From d177f6195bfdeb1e7bf0c43cce6b68fbd3a60f0d Mon Sep 17 00:00:00 2001 From: Jussi Saurio Date: Sun, 9 Feb 2025 12:34:53 +0200 Subject: [PATCH 01/13] sqlite3-parser: box big members of createindex --- vendored/sqlite3-parser/src/parser/ast/mod.rs | 4 ++-- vendored/sqlite3-parser/src/parser/parse.y | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/vendored/sqlite3-parser/src/parser/ast/mod.rs b/vendored/sqlite3-parser/src/parser/ast/mod.rs index 8cf4f805d..780af728f 100644 --- a/vendored/sqlite3-parser/src/parser/ast/mod.rs +++ b/vendored/sqlite3-parser/src/parser/ast/mod.rs @@ -95,13 +95,13 @@ pub enum Stmt { /// `IF NOT EXISTS` if_not_exists: bool, /// index name - idx_name: QualifiedName, + idx_name: Box, /// table name tbl_name: Name, /// indexed columns or expressions columns: Vec, /// partial index - where_clause: Option, + where_clause: Option>, }, /// `CREATE TABLE` CreateTable { diff --git a/vendored/sqlite3-parser/src/parser/parse.y b/vendored/sqlite3-parser/src/parser/parse.y index bb3c80e91..38fb47fda 100644 --- a/vendored/sqlite3-parser/src/parser/parse.y +++ b/vendored/sqlite3-parser/src/parser/parse.y @@ -1077,8 +1077,8 @@ paren_exprlist(A) ::= LP exprlist(X) RP. {A = X;} // cmd ::= createkw uniqueflag(U) INDEX ifnotexists(NE) fullname(X) ON nm(Y) LP sortlist(Z) RP where_opt(W). { - self.ctx.stmt = Some(Stmt::CreateIndex { unique: U, if_not_exists: NE, idx_name: X, - tbl_name: Y, columns: Z, where_clause: W }); + self.ctx.stmt = Some(Stmt::CreateIndex { unique: U, if_not_exists: NE, idx_name: Box::new(X), + tbl_name: Y, columns: Z, where_clause: W.map(Box::new) }); } %type uniqueflag {bool} From 358fda2ec74c6ae1b33dff8b14519b8101f99909 Mon Sep 17 00:00:00 2001 From: Jussi Saurio Date: Sun, 9 Feb 2025 12:42:53 +0200 Subject: [PATCH 02/13] sqlite3-parser: box the create table body --- core/ext/mod.rs | 2 +- core/schema.rs | 2 +- core/translate/mod.rs | 2 +- vendored/sqlite3-parser/src/parser/ast/mod.rs | 2 +- vendored/sqlite3-parser/src/parser/parse.y | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/ext/mod.rs b/core/ext/mod.rs index 67fd78491..344b8f4a4 100644 --- a/core/ext/mod.rs +++ b/core/ext/mod.rs @@ -127,7 +127,7 @@ impl Database { let Stmt::CreateTable { body, .. } = stmt else { return ResultCode::Error; }; - let Ok(columns) = columns_from_create_table_body(body) else { + let Ok(columns) = columns_from_create_table_body(*body) else { return ResultCode::Error; }; let vtab_module = self.vtab_modules.get(name).unwrap().clone(); diff --git a/core/schema.rs b/core/schema.rs index f4a6aee2b..aa38cd191 100644 --- a/core/schema.rs +++ b/core/schema.rs @@ -150,7 +150,7 @@ impl BTreeTable { let cmd = parser.next()?; match cmd { Some(Cmd::Stmt(Stmt::CreateTable { tbl_name, body, .. })) => { - create_table(tbl_name, body, root_page) + create_table(tbl_name, *body, root_page) } _ => todo!("Expected CREATE TABLE statement"), } diff --git a/core/translate/mod.rs b/core/translate/mod.rs index 79791866b..d9c3f7421 100644 --- a/core/translate/mod.rs +++ b/core/translate/mod.rs @@ -67,7 +67,7 @@ pub fn translate( bail_parse_error!("TEMPORARY table not supported yet"); } - translate_create_table(query_mode, tbl_name, body, if_not_exists, schema)? + translate_create_table(query_mode, tbl_name, *body, if_not_exists, schema)? } ast::Stmt::CreateTrigger { .. } => bail_parse_error!("CREATE TRIGGER not supported yet"), ast::Stmt::CreateView { .. } => bail_parse_error!("CREATE VIEW not supported yet"), diff --git a/vendored/sqlite3-parser/src/parser/ast/mod.rs b/vendored/sqlite3-parser/src/parser/ast/mod.rs index 780af728f..049084bd5 100644 --- a/vendored/sqlite3-parser/src/parser/ast/mod.rs +++ b/vendored/sqlite3-parser/src/parser/ast/mod.rs @@ -112,7 +112,7 @@ pub enum Stmt { /// table name tbl_name: QualifiedName, /// table body - body: CreateTableBody, + body: Box, }, /// `CREATE TRIGGER` CreateTrigger { diff --git a/vendored/sqlite3-parser/src/parser/parse.y b/vendored/sqlite3-parser/src/parser/parse.y index 38fb47fda..511c83c3b 100644 --- a/vendored/sqlite3-parser/src/parser/parse.y +++ b/vendored/sqlite3-parser/src/parser/parse.y @@ -109,7 +109,7 @@ cmd ::= ROLLBACK trans_opt(Y) TO savepoint_opt nm(X). { ///////////////////// The CREATE TABLE statement //////////////////////////// // cmd ::= createkw temp(T) TABLE ifnotexists(E) fullname(Y) create_table_args(X). { - self.ctx.stmt = Some(Stmt::CreateTable{ temporary: T, if_not_exists: E, tbl_name: Y, body: X }); + self.ctx.stmt = Some(Stmt::CreateTable{ temporary: T, if_not_exists: E, tbl_name: Y, body: Box::new(X) }); } createkw(A) ::= CREATE(A). From 575b48474065e8c2720de5ccfec2889f73b105b0 Mon Sep 17 00:00:00 2001 From: Jussi Saurio Date: Sun, 9 Feb 2025 12:50:00 +0200 Subject: [PATCH 03/13] sqlite3-parser: separate boxed CreateTrigger struct --- vendored/sqlite3-parser/src/parser/ast/fmt.rs | 23 ++++--- vendored/sqlite3-parser/src/parser/ast/mod.rs | 67 +++++++------------ vendored/sqlite3-parser/src/parser/parse.y | 8 +-- 3 files changed, 39 insertions(+), 59 deletions(-) diff --git a/vendored/sqlite3-parser/src/parser/ast/fmt.rs b/vendored/sqlite3-parser/src/parser/ast/fmt.rs index 34a7fa3f0..10e7c1ad9 100644 --- a/vendored/sqlite3-parser/src/parser/ast/fmt.rs +++ b/vendored/sqlite3-parser/src/parser/ast/fmt.rs @@ -211,17 +211,18 @@ impl ToTokens for Stmt { tbl_name.to_tokens(s)?; body.to_tokens(s) } - Self::CreateTrigger { - temporary, - if_not_exists, - trigger_name, - time, - event, - tbl_name, - for_each_row, - when_clause, - commands, - } => { + Self::CreateTrigger(trigger) => { + let CreateTrigger { + temporary, + if_not_exists, + trigger_name, + time, + event, + tbl_name, + for_each_row, + when_clause, + commands, + } = &**trigger; s.append(TK_CREATE, None)?; if *temporary { s.append(TK_TEMP, None)?; diff --git a/vendored/sqlite3-parser/src/parser/ast/mod.rs b/vendored/sqlite3-parser/src/parser/ast/mod.rs index 049084bd5..814aacdb1 100644 --- a/vendored/sqlite3-parser/src/parser/ast/mod.rs +++ b/vendored/sqlite3-parser/src/parser/ast/mod.rs @@ -115,26 +115,7 @@ pub enum Stmt { body: Box, }, /// `CREATE TRIGGER` - CreateTrigger { - /// `TEMPORARY` - temporary: bool, - /// `IF NOT EXISTS` - if_not_exists: bool, - /// trigger name - trigger_name: QualifiedName, - /// `BEFORE`/`AFTER`/`INSTEAD OF` - time: Option, - /// `DELETE`/`INSERT`/`UPDATE` - event: Box, - /// table name - tbl_name: QualifiedName, - /// `FOR EACH ROW` - for_each_row: bool, - /// `WHEN` - when_clause: Option>, - /// statements - commands: Vec, - }, + CreateTrigger(Box), /// `CREATE VIEW` CreateView { /// `TEMPORARY` @@ -242,30 +223,28 @@ pub enum Stmt { /// `SELECT` Select(Box), /// `UPDATE` + Update(Box), + /// `VACUUM`: database name, into expr + Vacuum(Option, Option), +} + /// `CREATE TRIGGER #[derive(Clone, Debug, PartialEq, Eq)] pub struct CreateTrigger { @@ -245,6 +250,30 @@ pub struct CreateTrigger { /// statements pub commands: Vec, } + +/// `UPDATE` clause +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Update { + /// CTE + pub with: Option, + /// `OR` + pub or_conflict: Option, + /// table name + pub tbl_name: QualifiedName, + /// `INDEXED` + pub indexed: Option, + /// `SET` assignments + pub sets: Vec, + /// `FROM` + pub from: Option, + /// `WHERE` clause + pub where_clause: Option>, + /// `RETURNING` + pub returning: Option>, + /// `ORDER BY` + pub order_by: Option>, + /// `LIMIT` + pub limit: Option>, } /// SQL expression diff --git a/vendored/sqlite3-parser/src/parser/parse.y b/vendored/sqlite3-parser/src/parser/parse.y index b24c9b708..2e298aa9e 100644 --- a/vendored/sqlite3-parser/src/parser/parse.y +++ b/vendored/sqlite3-parser/src/parser/parse.y @@ -790,15 +790,15 @@ where_opt_ret(A) ::= WHERE expr(X) RETURNING selcollist(Y). cmd ::= with(C) UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F) where_opt_ret(W) orderby_opt(O) limit_opt(L). { let (where_clause, returning) = W; - self.ctx.stmt = Some(Stmt::Update { with: C, or_conflict: R, tbl_name: X, indexed: I, sets: Y, from: F, - where_clause: where_clause.map(Box::new), returning, order_by: O, limit: L }); + self.ctx.stmt = Some(Stmt::Update(Box::new(Update{ with: C, or_conflict: R, tbl_name: X, indexed: I, sets: Y, from: F, + where_clause: where_clause.map(Box::new), returning, order_by: O, limit: L }))); } %else cmd ::= with(C) UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F) where_opt_ret(W). { let (where_clause, returning) = W; - self.ctx.stmt = Some(Stmt::Update { with: C, or_conflict: R, tbl_name: X, indexed: I, sets: Y, from: F, - where_clause: where_clause.map(Box::new), returning, order_by: None, limit: None }); + self.ctx.stmt = Some(Stmt::Update(Box::new(Update{ with: C, or_conflict: R, tbl_name: X, indexed: I, sets: Y, from: F, + where_clause: where_clause.map(Box::new), returning, order_by: None, limit: None }))); } %endif From f75aca67bb00124008b1081be5e6ae0ad18031e9 Mon Sep 17 00:00:00 2001 From: Jussi Saurio Date: Sun, 9 Feb 2025 12:52:30 +0200 Subject: [PATCH 05/13] sqlite3-parser: separate boxed TriggerCmd struct variants --- vendored/sqlite3-parser/src/parser/ast/fmt.rs | 41 +++++----- vendored/sqlite3-parser/src/parser/ast/mod.rs | 76 +++++++++++-------- vendored/sqlite3-parser/src/parser/parse.y | 6 +- 3 files changed, 67 insertions(+), 56 deletions(-) diff --git a/vendored/sqlite3-parser/src/parser/ast/fmt.rs b/vendored/sqlite3-parser/src/parser/ast/fmt.rs index 2d44f5255..313177a39 100644 --- a/vendored/sqlite3-parser/src/parser/ast/fmt.rs +++ b/vendored/sqlite3-parser/src/parser/ast/fmt.rs @@ -1651,13 +1651,14 @@ impl ToTokens for TriggerEvent { impl ToTokens for TriggerCmd { fn to_tokens(&self, s: &mut S) -> Result<(), S::Error> { match self { - Self::Update { - or_conflict, - tbl_name, - sets, - from, - where_clause, - } => { + Self::Update(update) => { + let TriggerCmdUpdate { + or_conflict, + tbl_name, + sets, + from, + where_clause, + } = &**update; s.append(TK_UPDATE, None)?; if let Some(or_conflict) = or_conflict { s.append(TK_OR, None)?; @@ -1676,14 +1677,15 @@ impl ToTokens for TriggerCmd { } Ok(()) } - Self::Insert { - or_conflict, - tbl_name, - col_names, - select, - upsert, - returning, - } => { + Self::Insert(insert) => { + let TriggerCmdInsert { + or_conflict, + tbl_name, + col_names, + select, + upsert, + returning, + } = &**insert; if let Some(ResolveType::Replace) = or_conflict { s.append(TK_REPLACE, None)?; } else { @@ -1710,14 +1712,11 @@ impl ToTokens for TriggerCmd { } Ok(()) } - Self::Delete { - tbl_name, - where_clause, - } => { + Self::Delete(delete) => { s.append(TK_DELETE, None)?; s.append(TK_FROM, None)?; - tbl_name.to_tokens(s)?; - if let Some(where_clause) = where_clause { + delete.tbl_name.to_tokens(s)?; + if let Some(where_clause) = &delete.where_clause { s.append(TK_WHERE, None)?; where_clause.to_tokens(s)?; } diff --git a/vendored/sqlite3-parser/src/parser/ast/mod.rs b/vendored/sqlite3-parser/src/parser/ast/mod.rs index 3c729ea70..6b0ac88df 100644 --- a/vendored/sqlite3-parser/src/parser/ast/mod.rs +++ b/vendored/sqlite3-parser/src/parser/ast/mod.rs @@ -1640,44 +1640,56 @@ pub enum TriggerEvent { #[derive(Clone, Debug, PartialEq, Eq)] pub enum TriggerCmd { /// `UPDATE` - Update { - /// `OR` - or_conflict: Option, - /// table name - tbl_name: Name, - /// `SET` assignments - sets: Vec, - /// `FROM` - from: Option, - /// `WHERE` clause - where_clause: Option, - }, + Update(Box), /// `INSERT` - Insert { - /// `OR` - or_conflict: Option, - /// table name - tbl_name: Name, - /// `COLUMNS` - col_names: Option, - /// `SELECT` or `VALUES` - select: Box), } +/// `UPDATE` trigger command +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct TriggerCmdUpdate { + /// `OR` + pub or_conflict: Option, + /// table name + pub tbl_name: Name, + /// `SET` assignments + pub sets: Vec, + /// `FROM` + pub from: Option, + /// `WHERE` clause + pub where_clause: Option, +} + +/// `INSERT` trigger command +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct TriggerCmdInsert { + /// `OR` + pub or_conflict: Option, + /// table name + pub tbl_name: Name, + /// `COLUMNS` + pub col_names: Option, + /// `SELECT` or `VALUES` + pub select: Box, }, /// `CREATE VIRTUAL TABLE` - CreateVirtualTable { - /// `IF NOT EXISTS` - if_not_exists: bool, - /// table name - tbl_name: QualifiedName, - /// module - module_name: Name, - /// args - args: Option>, // TODO smol str - }, + CreateVirtualTable(Box), /// `DELETE` Delete(Box), /// `DETACH DATABASE`: db name @@ -197,7 +188,17 @@ pub enum Stmt { /// `UPDATE` Update(Box), /// `VACUUM`: database name, into expr - Vacuum(Option, Option), +/// `CREATE VIRTUAL TABLE` +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CreateVirtualTable { + /// `IF NOT EXISTS` + pub if_not_exists: bool, + /// table name + pub tbl_name: QualifiedName, + /// module name + pub module_name: Name, + /// args + pub args: Option>, // TODO smol str } /// `CREATE TRIGGER diff --git a/vendored/sqlite3-parser/src/parser/parse.y b/vendored/sqlite3-parser/src/parser/parse.y index 16c8b9f00..6ff139835 100644 --- a/vendored/sqlite3-parser/src/parser/parse.y +++ b/vendored/sqlite3-parser/src/parser/parse.y @@ -1329,15 +1329,15 @@ kwcolumn_opt ::= COLUMNKW. cmd ::= create_vtab(X). {self.ctx.stmt = Some(X);} cmd ::= create_vtab(X) LP vtabarglist RP. { let mut stmt = X; - if let Stmt::CreateVirtualTable{ ref mut args, .. } = stmt { - *args = self.ctx.module_args(); + if let Stmt::CreateVirtualTable(ref mut create_virtual_table) = stmt { + create_virtual_table.args = self.ctx.module_args(); } self.ctx.stmt = Some(stmt); } %type create_vtab {Stmt} create_vtab(A) ::= createkw VIRTUAL TABLE ifnotexists(E) fullname(X) USING nm(Z). { - A = Stmt::CreateVirtualTable{ if_not_exists: E, tbl_name: X, module_name: Z, args: None }; + A = Stmt::CreateVirtualTable(Box::new(CreateVirtualTable{ if_not_exists: E, tbl_name: X, module_name: Z, args: None })); } vtabarglist ::= vtabarg. vtabarglist ::= vtabarglist COMMA vtabarg. From a8685c80862f994f20965f825864474076b56898 Mon Sep 17 00:00:00 2001 From: Jussi Saurio Date: Sun, 9 Feb 2025 14:11:57 +0200 Subject: [PATCH 13/13] sqlite3-parser: box the Expr in Vacuum --- vendored/sqlite3-parser/src/parser/ast/mod.rs | 3 +++ vendored/sqlite3-parser/src/parser/parse.y | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/vendored/sqlite3-parser/src/parser/ast/mod.rs b/vendored/sqlite3-parser/src/parser/ast/mod.rs index f942d1090..3ea9d5992 100644 --- a/vendored/sqlite3-parser/src/parser/ast/mod.rs +++ b/vendored/sqlite3-parser/src/parser/ast/mod.rs @@ -188,6 +188,9 @@ pub enum Stmt { /// `UPDATE` Update(Box), /// `VACUUM`: database name, into expr + Vacuum(Option, Option>), +} + /// `CREATE VIRTUAL TABLE` #[derive(Clone, Debug, PartialEq, Eq)] pub struct CreateVirtualTable { diff --git a/vendored/sqlite3-parser/src/parser/parse.y b/vendored/sqlite3-parser/src/parser/parse.y index 6ff139835..aeb6c689f 100644 --- a/vendored/sqlite3-parser/src/parser/parse.y +++ b/vendored/sqlite3-parser/src/parser/parse.y @@ -1130,8 +1130,8 @@ cmd ::= DROP INDEX ifexists(E) fullname(X). {self.ctx.stmt = Some(Stmt::DropIn // %if !SQLITE_OMIT_VACUUM && !SQLITE_OMIT_ATTACH %type vinto {Option} -cmd ::= VACUUM vinto(Y). {self.ctx.stmt = Some(Stmt::Vacuum(None, Y));} -cmd ::= VACUUM nm(X) vinto(Y). {self.ctx.stmt = Some(Stmt::Vacuum(Some(X), Y));} +cmd ::= VACUUM vinto(Y). {self.ctx.stmt = Some(Stmt::Vacuum(None, Y.map(Box::new)));} +cmd ::= VACUUM nm(X) vinto(Y). {self.ctx.stmt = Some(Stmt::Vacuum(Some(X), Y.map(Box::new)));} vinto(A) ::= INTO expr(X). {A = Some(X);} vinto(A) ::= . {A = None;} %endif