Skip to content

Commit

Permalink
implement the table_list pragma
Browse files Browse the repository at this point in the history
SQLite queries the schema tables to implement this, so that tables
can be printed out in order. For us, it would be quite cumbersome
to do this, so we will just add a timestamp to the table creation.
  • Loading branch information
glommer committed Feb 14, 2025
1 parent d9f4558 commit 300b82a
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 5 deletions.
2 changes: 1 addition & 1 deletion COMPAT.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ Limbo aims to be fully compatible with SQLite, with opt-in features not supporte
| PRAGMA stats | No | Used for testing in SQLite |
| PRAGMA synchronous | No | |
| PRAGMA table_info | Yes | |
| PRAGMA table_list | No | |
| PRAGMA table_list | Yes | |
| PRAGMA table_xinfo | No | |
| PRAGMA temp_store | No | |
| PRAGMA temp_store_directory | Not Needed | deprecated in SQLite |
Expand Down
4 changes: 4 additions & 0 deletions core/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use limbo_sqlite3_parser::{
};
use std::collections::HashMap;
use std::rc::Rc;
use std::time::Instant;
use tracing::trace;

pub struct Schema {
Expand Down Expand Up @@ -118,6 +119,7 @@ pub struct BTreeTable {
pub primary_key_column_names: Vec<String>,
pub columns: Vec<Column>,
pub has_rowid: bool,
pub created_at: Instant,
}

impl BTreeTable {
Expand Down Expand Up @@ -353,6 +355,7 @@ fn create_table(
has_rowid,
primary_key_column_names,
columns: cols,
created_at: Instant::now(),
})
}

Expand Down Expand Up @@ -416,6 +419,7 @@ pub fn sqlite_schema_table() -> BTreeTable {
name: "sqlite_schema".to_string(),
has_rowid: true,
primary_key_column_names: vec![],
created_at: Instant::now(),
columns: vec![
Column {
name: Some("type".to_string()),
Expand Down
51 changes: 48 additions & 3 deletions core/translate/pragma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ pub fn translate_pragma(
query_pragma(pragma, schema, None, database_header.clone(), &mut program)?;
}
Some(ast::PragmaBody::Equals(value)) => match pragma {
PragmaName::TableInfo => {
PragmaName::TableInfo | PragmaName::TableList => {
query_pragma(
pragma,
schema,
Expand All @@ -88,7 +88,7 @@ pub fn translate_pragma(
}
},
Some(ast::PragmaBody::Call(value)) => match pragma {
PragmaName::TableInfo => {
PragmaName::TableInfo | PragmaName::TableList => {
query_pragma(
pragma,
schema,
Expand Down Expand Up @@ -152,7 +152,7 @@ fn update_pragma(
// TODO: Implement updating user_version
todo!("updating user_version not yet implemented")
}
PragmaName::TableInfo => {
PragmaName::TableInfo | PragmaName::TableList => {
// because we need control over the write parameter for the transaction,
// this should be unreachable. We have to force-call query_pragma before
// getting here
Expand Down Expand Up @@ -245,6 +245,51 @@ fn query_pragma(
}
}
}
PragmaName::TableList => {
let table_name_filter = match value {
Some(ast::Expr::Name(name)) => Some(normalize_ident(&name.0)),
_ => None,
};

let base_reg = register;
program.alloc_register();
program.alloc_register();
program.alloc_register();
program.alloc_register();
program.alloc_register();

// SQLite just queries the schema table, and then ordering comes
// from the sequence numbers that we have there. But for us, querying
// something here is a harder, as we would need to have the IO context.
//
// So we keep a creation timestamp and iterate over that.
let mut sorted_tables: Vec<_> = schema
.tables
.iter()
.filter(|(tbl_name, _)| match &table_name_filter {
None => true,
Some(name) => *tbl_name == name,
})
.collect();

sorted_tables.sort_by(|(_, a), (_, b)| b.created_at.cmp(&a.created_at));

for (_, table) in sorted_tables {
// schema - currently we only support "main", not "temp"
program.emit_string8("main".to_string(), base_reg);
// name
program.emit_string8(table.name.clone(), base_reg + 1);
// type - always "table" for now since we don't support views
program.emit_string8("table".to_string(), base_reg + 2);
// ncol - number of columns
program.emit_int(table.columns.len() as i64, base_reg + 3);
// wr - without rowid flag
program.emit_int((!table.has_rowid) as i64, base_reg + 4);
// strict - we don't track this yet, so always 0
program.emit_int(0, base_reg + 5);
program.emit_result_row(base_reg, 6);
}
}
PragmaName::UserVersion => {
program.emit_transaction(false);
program.emit_insn(Insn::ReadCookie {
Expand Down
14 changes: 13 additions & 1 deletion testing/pragma.test
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,16 @@ do_execsql_test_on_specific_db "testing/testing_user_version_10.db" pragma-user-

do_execsql_test_on_specific_db ":memory:" pragma-user-version-default {
PRAGMA user_version
} {0}
} {0}

do_execsql_test_regex pragma-table-list {
PRAGMA table_list
} {^main\|products\|table\|3\|0\|0\nmain\|users\|table\|10\|0\|0\nmain\|sqlite_schema\|table\|5\|0\|0}

do_execsql_test pragma-table-list-equals {
PRAGMA table_list=products
} {main|products|table|3|0|0}

do_execsql_test pragma-table-list-calls {
PRAGMA table_list(users)
} {main|users|table|10|0|0}
2 changes: 2 additions & 0 deletions vendored/sqlite3-parser/src/parser/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1622,6 +1622,8 @@ pub enum PragmaName {
PageCount,
/// returns information about the columns of a table
TableInfo,
/// returns the list of all tables in the database
TableList,
/// Returns the user version of the database file.
UserVersion,
/// trigger a checkpoint to run on database(s) if WAL is enabled
Expand Down

0 comments on commit 300b82a

Please sign in to comment.