mirror of
https://github.com/tursodatabase/limbo.git
synced 2025-08-04 10:08:20 +00:00
Merge 'perf/prepare: box even more stuff to shrink the YYMINORTYPE enum further' from Jussi Saurio
the boxings will continue until morale improves <img width="621" alt="Screenshot 2025-02-09 at 14 16 21" src="https://github.com/user- attachments/assets/887d218d-3db7-4a64-ad81-b7431adb23bb" /> Closes #947
This commit is contained in:
commit
9e65d7ddea
9 changed files with 415 additions and 343 deletions
|
@ -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();
|
||||
|
|
|
@ -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"),
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ use crate::{bail_parse_error, Connection, LimboError, Result, SymbolTable};
|
|||
use insert::translate_insert;
|
||||
use select::translate_select;
|
||||
use sqlite3_parser::ast::{self, fmt::ToTokens};
|
||||
use sqlite3_parser::ast::{Delete, Insert};
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::Display;
|
||||
use std::rc::{Rc, Weak};
|
||||
|
@ -51,7 +52,7 @@ pub fn translate(
|
|||
let mut change_cnt_on = false;
|
||||
|
||||
let program = match stmt {
|
||||
ast::Stmt::AlterTable(_, _) => bail_parse_error!("ALTER TABLE not supported yet"),
|
||||
ast::Stmt::AlterTable(_) => bail_parse_error!("ALTER TABLE not supported yet"),
|
||||
ast::Stmt::Analyze(_) => bail_parse_error!("ANALYZE not supported yet"),
|
||||
ast::Stmt::Attach { .. } => bail_parse_error!("ATTACH not supported yet"),
|
||||
ast::Stmt::Begin(_, _) => bail_parse_error!("BEGIN not supported yet"),
|
||||
|
@ -67,19 +68,20 @@ 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"),
|
||||
ast::Stmt::CreateVirtualTable { .. } => {
|
||||
bail_parse_error!("CREATE VIRTUAL TABLE not supported yet")
|
||||
}
|
||||
ast::Stmt::Delete {
|
||||
tbl_name,
|
||||
where_clause,
|
||||
limit,
|
||||
..
|
||||
} => {
|
||||
ast::Stmt::Delete(delete) => {
|
||||
let Delete {
|
||||
tbl_name,
|
||||
where_clause,
|
||||
limit,
|
||||
..
|
||||
} = *delete;
|
||||
change_cnt_on = true;
|
||||
translate_delete(query_mode, schema, &tbl_name, where_clause, limit, syms)?
|
||||
}
|
||||
|
@ -92,7 +94,7 @@ pub fn translate(
|
|||
query_mode,
|
||||
&schema,
|
||||
&name,
|
||||
body,
|
||||
body.map(|b| *b),
|
||||
database_header.clone(),
|
||||
pager,
|
||||
)?,
|
||||
|
@ -103,14 +105,15 @@ pub fn translate(
|
|||
ast::Stmt::Select(select) => translate_select(query_mode, schema, *select, syms)?,
|
||||
ast::Stmt::Update { .. } => bail_parse_error!("UPDATE not supported yet"),
|
||||
ast::Stmt::Vacuum(_, _) => bail_parse_error!("VACUUM not supported yet"),
|
||||
ast::Stmt::Insert {
|
||||
with,
|
||||
or_conflict,
|
||||
tbl_name,
|
||||
columns,
|
||||
body,
|
||||
returning,
|
||||
} => {
|
||||
ast::Stmt::Insert(insert) => {
|
||||
let Insert {
|
||||
with,
|
||||
or_conflict,
|
||||
tbl_name,
|
||||
columns,
|
||||
body,
|
||||
returning,
|
||||
} = *insert;
|
||||
change_cnt_on = true;
|
||||
translate_insert(
|
||||
query_mode,
|
||||
|
|
|
@ -11,8 +11,8 @@ use crate::util::normalize_ident;
|
|||
use crate::vdbe::builder::{ProgramBuilderOpts, QueryMode};
|
||||
use crate::SymbolTable;
|
||||
use crate::{schema::Schema, vdbe::builder::ProgramBuilder, Result};
|
||||
use sqlite3_parser::ast::ResultColumn;
|
||||
use sqlite3_parser::ast::{self};
|
||||
use sqlite3_parser::ast::{ResultColumn, SelectInner};
|
||||
|
||||
pub fn translate_select(
|
||||
query_mode: QueryMode,
|
||||
|
@ -42,13 +42,14 @@ pub fn prepare_select_plan(
|
|||
syms: &SymbolTable,
|
||||
) -> Result<Plan> {
|
||||
match *select.body.select {
|
||||
ast::OneSelect::Select {
|
||||
mut columns,
|
||||
from,
|
||||
where_clause,
|
||||
group_by,
|
||||
..
|
||||
} => {
|
||||
ast::OneSelect::Select(select_inner) => {
|
||||
let SelectInner {
|
||||
mut columns,
|
||||
from,
|
||||
where_clause,
|
||||
group_by,
|
||||
..
|
||||
} = *select_inner;
|
||||
let col_count = columns.len();
|
||||
if col_count == 0 {
|
||||
crate::bail_parse_error!("SELECT without columns is not allowed");
|
||||
|
|
|
@ -3,7 +3,7 @@ use fallible_iterator::FallibleIterator;
|
|||
use super::{Error, Parser};
|
||||
use crate::parser::ast::fmt::ToTokens;
|
||||
use crate::parser::{
|
||||
ast::{Cmd, Name, ParameterInfo, QualifiedName, Stmt},
|
||||
ast::{Cmd, ParameterInfo, Stmt},
|
||||
ParserError,
|
||||
};
|
||||
|
||||
|
@ -73,20 +73,12 @@ fn vtab_args() -> Result<(), Error> {
|
|||
body TEXT CHECK(length(body)<10240)
|
||||
);";
|
||||
let r = parse_cmd(sql);
|
||||
let Cmd::Stmt(Stmt::CreateVirtualTable {
|
||||
tbl_name: QualifiedName {
|
||||
name: Name(tbl_name),
|
||||
..
|
||||
},
|
||||
module_name: Name(module_name),
|
||||
args: Some(args),
|
||||
..
|
||||
}) = r
|
||||
else {
|
||||
let Cmd::Stmt(Stmt::CreateVirtualTable(create_virtual_table)) = r else {
|
||||
panic!("unexpected AST")
|
||||
};
|
||||
assert_eq!(tbl_name, "mail");
|
||||
assert_eq!(module_name, "fts3");
|
||||
assert_eq!(create_virtual_table.tbl_name.name, "mail");
|
||||
assert_eq!(create_virtual_table.module_name.0, "fts3");
|
||||
let args = create_virtual_table.args.as_ref().unwrap();
|
||||
assert_eq!(args.len(), 2);
|
||||
assert_eq!(args[0], "subject VARCHAR(256) NOT NULL");
|
||||
assert_eq!(args[1], "body TEXT CHECK(length(body)<10240)");
|
||||
|
|
|
@ -56,20 +56,29 @@ impl Stmt {
|
|||
/// Like `sqlite3_column_count` but more limited
|
||||
pub fn column_count(&self) -> ColumnCount {
|
||||
match self {
|
||||
Self::Delete {
|
||||
returning: Some(returning),
|
||||
..
|
||||
} => column_count(returning),
|
||||
Self::Insert {
|
||||
returning: Some(returning),
|
||||
..
|
||||
} => column_count(returning),
|
||||
Self::Delete(delete) => {
|
||||
let Delete { returning, .. } = &**delete;
|
||||
match returning {
|
||||
Some(returning) => column_count(returning),
|
||||
None => ColumnCount::None,
|
||||
}
|
||||
}
|
||||
Self::Insert(insert) => {
|
||||
let Insert { returning, .. } = &**insert;
|
||||
match returning {
|
||||
Some(returning) => column_count(returning),
|
||||
None => ColumnCount::None,
|
||||
}
|
||||
}
|
||||
Self::Pragma(..) => ColumnCount::Dynamic,
|
||||
Self::Select(s) => s.column_count(),
|
||||
Self::Update {
|
||||
returning: Some(returning),
|
||||
..
|
||||
} => column_count(returning),
|
||||
Self::Update(update) => {
|
||||
let Update { returning, .. } = &**update;
|
||||
match returning {
|
||||
Some(returning) => column_count(returning),
|
||||
None => ColumnCount::None,
|
||||
}
|
||||
}
|
||||
_ => ColumnCount::None,
|
||||
}
|
||||
}
|
||||
|
@ -94,22 +103,28 @@ impl Stmt {
|
|||
/// check for extra rules
|
||||
pub fn check(&self) -> Result<(), ParserError> {
|
||||
match self {
|
||||
Self::AlterTable(old_name, AlterTableBody::RenameTo(new_name)) => {
|
||||
if *new_name == old_name.name {
|
||||
return Err(custom_err!(
|
||||
"there is already another table or index with this name: {}",
|
||||
new_name
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Self::AlterTable(.., AlterTableBody::AddColumn(cd)) => {
|
||||
for c in cd {
|
||||
if let ColumnConstraint::PrimaryKey { .. } = c {
|
||||
return Err(custom_err!("Cannot add a PRIMARY KEY column"));
|
||||
} else if let ColumnConstraint::Unique(..) = c {
|
||||
return Err(custom_err!("Cannot add a UNIQUE column"));
|
||||
Self::AlterTable(alter_table) => {
|
||||
let (old_name, body) = &**alter_table;
|
||||
match body {
|
||||
AlterTableBody::RenameTo(new_name) => {
|
||||
if *new_name == old_name.name {
|
||||
return Err(custom_err!(
|
||||
"there is already another table or index with this name: {}",
|
||||
new_name
|
||||
));
|
||||
}
|
||||
}
|
||||
AlterTableBody::AddColumn(cd) => {
|
||||
for c in cd {
|
||||
if let ColumnConstraint::PrimaryKey { .. } = c {
|
||||
return Err(custom_err!("Cannot add a PRIMARY KEY column"));
|
||||
}
|
||||
if let ColumnConstraint::Unique(..) = c {
|
||||
return Err(custom_err!("Cannot add a UNIQUE column"));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -153,31 +168,47 @@ impl Stmt {
|
|||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
Self::Delete {
|
||||
order_by: Some(_),
|
||||
limit: None,
|
||||
..
|
||||
} => Err(custom_err!("ORDER BY without LIMIT on DELETE")),
|
||||
Self::Insert {
|
||||
columns: Some(columns),
|
||||
body,
|
||||
..
|
||||
} => match &**body {
|
||||
InsertBody::Select(select, ..) => match select.body.select.column_count() {
|
||||
ColumnCount::Fixed(n) if n != columns.len() => {
|
||||
Err(custom_err!("{} values for {} columns", n, columns.len()))
|
||||
Self::Delete(delete) => {
|
||||
let Delete {
|
||||
order_by, limit, ..
|
||||
} = &**delete;
|
||||
if let Some(_) = order_by {
|
||||
if limit.is_none() {
|
||||
return Err(custom_err!("ORDER BY without LIMIT on DELETE"));
|
||||
}
|
||||
_ => Ok(()),
|
||||
},
|
||||
InsertBody::DefaultValues => {
|
||||
Err(custom_err!("0 values for {} columns", columns.len()))
|
||||
}
|
||||
},
|
||||
Self::Update {
|
||||
order_by: Some(_),
|
||||
limit: None,
|
||||
..
|
||||
} => Err(custom_err!("ORDER BY without LIMIT on UPDATE")),
|
||||
Ok(())
|
||||
}
|
||||
Self::Insert(insert) => {
|
||||
let Insert { columns, body, .. } = &**insert;
|
||||
if columns.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
let columns = columns.as_ref().unwrap();
|
||||
match &*body {
|
||||
InsertBody::Select(select, ..) => match select.body.select.column_count() {
|
||||
ColumnCount::Fixed(n) if n != columns.len() => {
|
||||
Err(custom_err!("{} values for {} columns", n, columns.len()))
|
||||
}
|
||||
_ => Ok(()),
|
||||
},
|
||||
InsertBody::DefaultValues => {
|
||||
Err(custom_err!("0 values for {} columns", columns.len()))
|
||||
}
|
||||
}
|
||||
}
|
||||
Self::Update(update) => {
|
||||
let Update {
|
||||
order_by, limit, ..
|
||||
} = &**update;
|
||||
if let Some(_) = order_by {
|
||||
if limit.is_none() {
|
||||
return Err(custom_err!("ORDER BY without LIMIT on UPDATE"));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
@ -295,7 +326,10 @@ impl OneSelect {
|
|||
/// Like `sqlite3_column_count` but more limited
|
||||
pub fn column_count(&self) -> ColumnCount {
|
||||
match self {
|
||||
Self::Select { columns, .. } => column_count(columns),
|
||||
Self::Select(select) => {
|
||||
let SelectInner { columns, .. } = &**select;
|
||||
column_count(columns)
|
||||
}
|
||||
Self::Values(values) => {
|
||||
assert!(!values.is_empty()); // TODO Validate
|
||||
ColumnCount::Fixed(values[0].len())
|
||||
|
|
|
@ -119,7 +119,8 @@ impl Display for Cmd {
|
|||
impl ToTokens for Stmt {
|
||||
fn to_tokens<S: TokenStream>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
match self {
|
||||
Self::AlterTable(tbl_name, body) => {
|
||||
Self::AlterTable(alter_table) => {
|
||||
let (tbl_name, body) = &**alter_table;
|
||||
s.append(TK_ALTER, None)?;
|
||||
s.append(TK_TABLE, None)?;
|
||||
tbl_name.to_tokens(s)?;
|
||||
|
@ -211,17 +212,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)?;
|
||||
|
@ -281,12 +283,13 @@ impl ToTokens for Stmt {
|
|||
s.append(TK_AS, None)?;
|
||||
select.to_tokens(s)
|
||||
}
|
||||
Self::CreateVirtualTable {
|
||||
if_not_exists,
|
||||
tbl_name,
|
||||
module_name,
|
||||
args,
|
||||
} => {
|
||||
Self::CreateVirtualTable(create_virtual_table) => {
|
||||
let CreateVirtualTable {
|
||||
if_not_exists,
|
||||
tbl_name,
|
||||
module_name,
|
||||
args,
|
||||
} = &**create_virtual_table;
|
||||
s.append(TK_CREATE, None)?;
|
||||
s.append(TK_VIRTUAL, None)?;
|
||||
s.append(TK_TABLE, None)?;
|
||||
|
@ -304,15 +307,16 @@ impl ToTokens for Stmt {
|
|||
}
|
||||
s.append(TK_RP, None)
|
||||
}
|
||||
Self::Delete {
|
||||
with,
|
||||
tbl_name,
|
||||
indexed,
|
||||
where_clause,
|
||||
returning,
|
||||
order_by,
|
||||
limit,
|
||||
} => {
|
||||
Self::Delete(delete) => {
|
||||
let Delete {
|
||||
with,
|
||||
tbl_name,
|
||||
indexed,
|
||||
where_clause,
|
||||
returning,
|
||||
order_by,
|
||||
limit,
|
||||
} = &**delete;
|
||||
if let Some(with) = with {
|
||||
with.to_tokens(s)?;
|
||||
}
|
||||
|
@ -392,14 +396,15 @@ impl ToTokens for Stmt {
|
|||
}
|
||||
view_name.to_tokens(s)
|
||||
}
|
||||
Self::Insert {
|
||||
with,
|
||||
or_conflict,
|
||||
tbl_name,
|
||||
columns,
|
||||
body,
|
||||
returning,
|
||||
} => {
|
||||
Self::Insert(insert) => {
|
||||
let Insert {
|
||||
with,
|
||||
or_conflict,
|
||||
tbl_name,
|
||||
columns,
|
||||
body,
|
||||
returning,
|
||||
} = &**insert;
|
||||
if let Some(with) = with {
|
||||
with.to_tokens(s)?;
|
||||
}
|
||||
|
@ -465,18 +470,19 @@ impl ToTokens for Stmt {
|
|||
name.to_tokens(s)
|
||||
}
|
||||
Self::Select(select) => select.to_tokens(s),
|
||||
Self::Update {
|
||||
with,
|
||||
or_conflict,
|
||||
tbl_name,
|
||||
indexed,
|
||||
sets,
|
||||
from,
|
||||
where_clause,
|
||||
returning,
|
||||
order_by,
|
||||
limit,
|
||||
} => {
|
||||
Self::Update(update) => {
|
||||
let Update {
|
||||
with,
|
||||
or_conflict,
|
||||
tbl_name,
|
||||
indexed,
|
||||
sets,
|
||||
from,
|
||||
where_clause,
|
||||
returning,
|
||||
order_by,
|
||||
limit,
|
||||
} = &**update;
|
||||
if let Some(with) = with {
|
||||
with.to_tokens(s)?;
|
||||
}
|
||||
|
@ -891,14 +897,15 @@ impl Display for CompoundOperator {
|
|||
impl ToTokens for OneSelect {
|
||||
fn to_tokens<S: TokenStream>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
match self {
|
||||
Self::Select {
|
||||
distinctness,
|
||||
columns,
|
||||
from,
|
||||
where_clause,
|
||||
group_by,
|
||||
window_clause,
|
||||
} => {
|
||||
Self::Select(select) => {
|
||||
let SelectInner {
|
||||
distinctness,
|
||||
columns,
|
||||
from,
|
||||
where_clause,
|
||||
group_by,
|
||||
window_clause,
|
||||
} = &**select;
|
||||
s.append(TK_SELECT, None)?;
|
||||
if let Some(ref distinctness) = distinctness {
|
||||
distinctness.to_tokens(s)?;
|
||||
|
@ -1649,13 +1656,14 @@ impl ToTokens for TriggerEvent {
|
|||
impl ToTokens for TriggerCmd {
|
||||
fn to_tokens<S: TokenStream>(&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)?;
|
||||
|
@ -1674,14 +1682,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 {
|
||||
|
@ -1708,14 +1717,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)?;
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ pub(crate) enum ExplainKind {
|
|||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Stmt {
|
||||
/// `ALTER TABLE`: table name, body
|
||||
AlterTable(QualifiedName, AlterTableBody),
|
||||
AlterTable(Box<(QualifiedName, AlterTableBody)>),
|
||||
/// `ANALYSE`: object name
|
||||
Analyze(Option<QualifiedName>),
|
||||
/// `ATTACH DATABASE`
|
||||
|
@ -95,13 +95,13 @@ pub enum Stmt {
|
|||
/// `IF NOT EXISTS`
|
||||
if_not_exists: bool,
|
||||
/// index name
|
||||
idx_name: QualifiedName,
|
||||
idx_name: Box<QualifiedName>,
|
||||
/// table name
|
||||
tbl_name: Name,
|
||||
/// indexed columns or expressions
|
||||
columns: Vec<SortedColumn>,
|
||||
/// partial index
|
||||
where_clause: Option<Expr>,
|
||||
where_clause: Option<Box<Expr>>,
|
||||
},
|
||||
/// `CREATE TABLE`
|
||||
CreateTable {
|
||||
|
@ -112,29 +112,10 @@ pub enum Stmt {
|
|||
/// table name
|
||||
tbl_name: QualifiedName,
|
||||
/// table body
|
||||
body: CreateTableBody,
|
||||
body: Box<CreateTableBody>,
|
||||
},
|
||||
/// `CREATE TRIGGER`
|
||||
CreateTrigger {
|
||||
/// `TEMPORARY`
|
||||
temporary: bool,
|
||||
/// `IF NOT EXISTS`
|
||||
if_not_exists: bool,
|
||||
/// trigger name
|
||||
trigger_name: QualifiedName,
|
||||
/// `BEFORE`/`AFTER`/`INSTEAD OF`
|
||||
time: Option<TriggerTime>,
|
||||
/// `DELETE`/`INSERT`/`UPDATE`
|
||||
event: Box<TriggerEvent>,
|
||||
/// table name
|
||||
tbl_name: QualifiedName,
|
||||
/// `FOR EACH ROW`
|
||||
for_each_row: bool,
|
||||
/// `WHEN`
|
||||
when_clause: Option<Box<Expr>>,
|
||||
/// statements
|
||||
commands: Vec<TriggerCmd>,
|
||||
},
|
||||
CreateTrigger(Box<CreateTrigger>),
|
||||
/// `CREATE VIEW`
|
||||
CreateView {
|
||||
/// `TEMPORARY`
|
||||
|
@ -149,35 +130,11 @@ pub enum Stmt {
|
|||
select: Box<Select>,
|
||||
},
|
||||
/// `CREATE VIRTUAL TABLE`
|
||||
CreateVirtualTable {
|
||||
/// `IF NOT EXISTS`
|
||||
if_not_exists: bool,
|
||||
/// table name
|
||||
tbl_name: QualifiedName,
|
||||
/// module
|
||||
module_name: Name,
|
||||
/// args
|
||||
args: Option<Vec<String>>, // TODO smol str
|
||||
},
|
||||
CreateVirtualTable(Box<CreateVirtualTable>),
|
||||
/// `DELETE`
|
||||
Delete {
|
||||
/// CTE
|
||||
with: Option<With>,
|
||||
/// `FROM` table name
|
||||
tbl_name: QualifiedName,
|
||||
/// `INDEXED`
|
||||
indexed: Option<Indexed>,
|
||||
/// `WHERE` clause
|
||||
where_clause: Option<Box<Expr>>,
|
||||
/// `RETURNING`
|
||||
returning: Option<Vec<ResultColumn>>,
|
||||
/// `ORDER BY`
|
||||
order_by: Option<Vec<SortedColumn>>,
|
||||
/// `LIMIT`
|
||||
limit: Option<Box<Limit>>,
|
||||
},
|
||||
Delete(Box<Delete>),
|
||||
/// `DETACH DATABASE`: db name
|
||||
Detach(Expr), // TODO distinction between DETACH and DETACH DATABASE
|
||||
Detach(Box<Expr>), // TODO distinction between DETACH and DETACH DATABASE
|
||||
/// `DROP INDEX`
|
||||
DropIndex {
|
||||
/// `IF EXISTS`
|
||||
|
@ -207,22 +164,9 @@ pub enum Stmt {
|
|||
view_name: QualifiedName,
|
||||
},
|
||||
/// `INSERT`
|
||||
Insert {
|
||||
/// CTE
|
||||
with: Option<With>,
|
||||
/// `OR`
|
||||
or_conflict: Option<ResolveType>, // TODO distinction between REPLACE and INSERT OR REPLACE
|
||||
/// table name
|
||||
tbl_name: QualifiedName,
|
||||
/// `COLUMNS`
|
||||
columns: Option<DistinctNames>,
|
||||
/// `VALUES` or `SELECT`
|
||||
body: Box<InsertBody>,
|
||||
/// `RETURNING`
|
||||
returning: Option<Vec<ResultColumn>>,
|
||||
},
|
||||
Insert(Box<Insert>),
|
||||
/// `PRAGMA`: pragma name, body
|
||||
Pragma(QualifiedName, Option<PragmaBody>),
|
||||
Pragma(Box<QualifiedName>, Option<Box<PragmaBody>>),
|
||||
/// `REINDEX`
|
||||
Reindex {
|
||||
/// collation or index or table name
|
||||
|
@ -242,30 +186,106 @@ pub enum Stmt {
|
|||
/// `SELECT`
|
||||
Select(Box<Select>),
|
||||
/// `UPDATE`
|
||||
Update {
|
||||
/// CTE
|
||||
with: Option<With>,
|
||||
/// `OR`
|
||||
or_conflict: Option<ResolveType>,
|
||||
/// table name
|
||||
tbl_name: QualifiedName,
|
||||
/// `INDEXED`
|
||||
indexed: Option<Indexed>,
|
||||
/// `SET` assignments
|
||||
sets: Vec<Set>,
|
||||
/// `FROM`
|
||||
from: Option<FromClause>,
|
||||
/// `WHERE` clause
|
||||
where_clause: Option<Box<Expr>>,
|
||||
/// `RETURNING`
|
||||
returning: Option<Vec<ResultColumn>>,
|
||||
/// `ORDER BY`
|
||||
order_by: Option<Vec<SortedColumn>>,
|
||||
/// `LIMIT`
|
||||
limit: Option<Box<Limit>>,
|
||||
},
|
||||
Update(Box<Update>),
|
||||
/// `VACUUM`: database name, into expr
|
||||
Vacuum(Option<Name>, Option<Expr>),
|
||||
Vacuum(Option<Name>, Option<Box<Expr>>),
|
||||
}
|
||||
|
||||
/// `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<Vec<String>>, // TODO smol str
|
||||
}
|
||||
|
||||
/// `CREATE TRIGGER
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct CreateTrigger {
|
||||
/// `TEMPORARY`
|
||||
pub temporary: bool,
|
||||
/// `IF NOT EXISTS`
|
||||
pub if_not_exists: bool,
|
||||
/// trigger name
|
||||
pub trigger_name: QualifiedName,
|
||||
/// `BEFORE`/`AFTER`/`INSTEAD OF`
|
||||
pub time: Option<TriggerTime>,
|
||||
/// `DELETE`/`INSERT`/`UPDATE`
|
||||
pub event: TriggerEvent,
|
||||
/// table name
|
||||
pub tbl_name: QualifiedName,
|
||||
/// `FOR EACH ROW`
|
||||
pub for_each_row: bool,
|
||||
/// `WHEN`
|
||||
pub when_clause: Option<Expr>,
|
||||
/// statements
|
||||
pub commands: Vec<TriggerCmd>,
|
||||
}
|
||||
|
||||
/// `INSERT`
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Insert {
|
||||
/// CTE
|
||||
pub with: Option<With>,
|
||||
/// `OR`
|
||||
pub or_conflict: Option<ResolveType>, // TODO distinction between REPLACE and INSERT OR REPLACE
|
||||
/// table name
|
||||
pub tbl_name: QualifiedName,
|
||||
/// `COLUMNS`
|
||||
pub columns: Option<DistinctNames>,
|
||||
/// `VALUES` or `SELECT`
|
||||
pub body: InsertBody,
|
||||
/// `RETURNING`
|
||||
pub returning: Option<Vec<ResultColumn>>,
|
||||
}
|
||||
|
||||
/// `UPDATE` clause
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Update {
|
||||
/// CTE
|
||||
pub with: Option<With>,
|
||||
/// `OR`
|
||||
pub or_conflict: Option<ResolveType>,
|
||||
/// table name
|
||||
pub tbl_name: QualifiedName,
|
||||
/// `INDEXED`
|
||||
pub indexed: Option<Indexed>,
|
||||
/// `SET` assignments
|
||||
pub sets: Vec<Set>,
|
||||
/// `FROM`
|
||||
pub from: Option<FromClause>,
|
||||
/// `WHERE` clause
|
||||
pub where_clause: Option<Box<Expr>>,
|
||||
/// `RETURNING`
|
||||
pub returning: Option<Vec<ResultColumn>>,
|
||||
/// `ORDER BY`
|
||||
pub order_by: Option<Vec<SortedColumn>>,
|
||||
/// `LIMIT`
|
||||
pub limit: Option<Box<Limit>>,
|
||||
}
|
||||
|
||||
/// `DELETE`
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Delete {
|
||||
/// CTE
|
||||
pub with: Option<With>,
|
||||
/// `FROM` table name
|
||||
pub tbl_name: QualifiedName,
|
||||
/// `INDEXED`
|
||||
pub indexed: Option<Indexed>,
|
||||
/// `WHERE` clause
|
||||
pub where_clause: Option<Box<Expr>>,
|
||||
/// `RETURNING`
|
||||
pub returning: Option<Vec<ResultColumn>>,
|
||||
/// `ORDER BY`
|
||||
pub order_by: Option<Vec<SortedColumn>>,
|
||||
/// `LIMIT`
|
||||
pub limit: Option<Box<Limit>>,
|
||||
}
|
||||
|
||||
/// SQL expression
|
||||
|
@ -771,24 +791,28 @@ pub enum CompoundOperator {
|
|||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum OneSelect {
|
||||
/// `SELECT`
|
||||
Select {
|
||||
/// `DISTINCT`
|
||||
distinctness: Option<Distinctness>,
|
||||
/// columns
|
||||
columns: Vec<ResultColumn>,
|
||||
/// `FROM` clause
|
||||
from: Option<FromClause>,
|
||||
/// `WHERE` clause
|
||||
where_clause: Option<Expr>,
|
||||
/// `GROUP BY`
|
||||
group_by: Option<GroupBy>,
|
||||
/// `WINDOW` definition
|
||||
window_clause: Option<Vec<WindowDef>>,
|
||||
},
|
||||
Select(Box<SelectInner>),
|
||||
/// `VALUES`
|
||||
Values(Vec<Vec<Expr>>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
/// `SELECT` core
|
||||
pub struct SelectInner {
|
||||
/// `DISTINCT`
|
||||
pub distinctness: Option<Distinctness>,
|
||||
/// columns
|
||||
pub columns: Vec<ResultColumn>,
|
||||
/// `FROM` clause
|
||||
pub from: Option<FromClause>,
|
||||
/// `WHERE` clause
|
||||
pub where_clause: Option<Expr>,
|
||||
/// `GROUP BY`
|
||||
pub group_by: Option<GroupBy>,
|
||||
/// `WINDOW` definition
|
||||
pub window_clause: Option<Vec<WindowDef>>,
|
||||
}
|
||||
|
||||
/// `SELECT` ... `FROM` clause
|
||||
// https://sqlite.org/syntax/join-clause.html
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -1632,44 +1656,56 @@ pub enum TriggerEvent {
|
|||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum TriggerCmd {
|
||||
/// `UPDATE`
|
||||
Update {
|
||||
/// `OR`
|
||||
or_conflict: Option<ResolveType>,
|
||||
/// table name
|
||||
tbl_name: Name,
|
||||
/// `SET` assignments
|
||||
sets: Vec<Set>,
|
||||
/// `FROM`
|
||||
from: Option<FromClause>,
|
||||
/// `WHERE` clause
|
||||
where_clause: Option<Expr>,
|
||||
},
|
||||
Update(Box<TriggerCmdUpdate>),
|
||||
/// `INSERT`
|
||||
Insert {
|
||||
/// `OR`
|
||||
or_conflict: Option<ResolveType>,
|
||||
/// table name
|
||||
tbl_name: Name,
|
||||
/// `COLUMNS`
|
||||
col_names: Option<DistinctNames>,
|
||||
/// `SELECT` or `VALUES`
|
||||
select: Box<Select>,
|
||||
/// `ON CONLICT` clause
|
||||
upsert: Option<Upsert>,
|
||||
/// `RETURNING`
|
||||
returning: Option<Vec<ResultColumn>>,
|
||||
},
|
||||
Insert(Box<TriggerCmdInsert>),
|
||||
/// `DELETE`
|
||||
Delete {
|
||||
/// table name
|
||||
tbl_name: Name,
|
||||
/// `WHERE` clause
|
||||
where_clause: Option<Expr>,
|
||||
},
|
||||
Delete(Box<TriggerCmdDelete>),
|
||||
/// `SELECT`
|
||||
Select(Box<Select>),
|
||||
}
|
||||
|
||||
/// `UPDATE` trigger command
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct TriggerCmdUpdate {
|
||||
/// `OR`
|
||||
pub or_conflict: Option<ResolveType>,
|
||||
/// table name
|
||||
pub tbl_name: Name,
|
||||
/// `SET` assignments
|
||||
pub sets: Vec<Set>,
|
||||
/// `FROM`
|
||||
pub from: Option<FromClause>,
|
||||
/// `WHERE` clause
|
||||
pub where_clause: Option<Expr>,
|
||||
}
|
||||
|
||||
/// `INSERT` trigger command
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct TriggerCmdInsert {
|
||||
/// `OR`
|
||||
pub or_conflict: Option<ResolveType>,
|
||||
/// table name
|
||||
pub tbl_name: Name,
|
||||
/// `COLUMNS`
|
||||
pub col_names: Option<DistinctNames>,
|
||||
/// `SELECT` or `VALUES`
|
||||
pub select: Box<Select>,
|
||||
/// `ON CONLICT` clause
|
||||
pub upsert: Option<Upsert>,
|
||||
/// `RETURNING`
|
||||
pub returning: Option<Vec<ResultColumn>>,
|
||||
}
|
||||
|
||||
/// `DELETE` trigger command
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct TriggerCmdDelete {
|
||||
/// table name
|
||||
pub tbl_name: Name,
|
||||
/// `WHERE` clause
|
||||
pub where_clause: Option<Expr>,
|
||||
}
|
||||
|
||||
/// Conflict resolution types
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum ResolveType {
|
||||
|
|
|
@ -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).
|
||||
|
||||
|
@ -525,14 +525,14 @@ multiselect_op(A) ::= INTERSECT. {A = CompoundOperator::Intersect;}
|
|||
|
||||
oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
|
||||
groupby_opt(P). {
|
||||
A = OneSelect::Select{ distinctness: D, columns: W, from: X, where_clause: Y,
|
||||
group_by: P, window_clause: None };
|
||||
A = OneSelect::Select(Box::new(SelectInner{ distinctness: D, columns: W, from: X, where_clause: Y,
|
||||
group_by: P, window_clause: None }));
|
||||
}
|
||||
%ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
|
||||
groupby_opt(P) window_clause(R). {
|
||||
A = OneSelect::Select{ distinctness: D, columns: W, from: X, where_clause: Y,
|
||||
group_by: P, window_clause: Some(R) };
|
||||
A = OneSelect::Select(Box::new(SelectInner{ distinctness: D, columns: W, from: X, where_clause: Y,
|
||||
group_by: P, window_clause: Some(R) }));
|
||||
}
|
||||
%endif
|
||||
|
||||
|
@ -761,14 +761,14 @@ limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y).
|
|||
cmd ::= with(C) DELETE FROM xfullname(X) indexed_opt(I) where_opt_ret(W)
|
||||
orderby_opt(O) limit_opt(L). {
|
||||
let (where_clause, returning) = W;
|
||||
self.ctx.stmt = Some(Stmt::Delete{ with: C, tbl_name: X, indexed: I, where_clause: where_clause.map(Box::new), returning,
|
||||
order_by: O, limit: L });
|
||||
self.ctx.stmt = Some(Stmt::Delete(Box::new(Delete{ with: C, tbl_name: X, indexed: I, where_clause: where_clause.map(Box::new), returning,
|
||||
order_by: O, limit: L })));
|
||||
}
|
||||
%else
|
||||
cmd ::= with(C) DELETE FROM xfullname(X) indexed_opt(I) where_opt_ret(W). {
|
||||
let (where_clause, returning) = W;
|
||||
self.ctx.stmt = Some(Stmt::Delete{ with: C, tbl_name: X, indexed: I, where_clause: where_clause.map(Box::new), returning,
|
||||
order_by: None, limit: None });
|
||||
self.ctx.stmt = Some(Stmt::Delete(Box::new(Delete{ with: C, tbl_name: X, indexed: I, where_clause: where_clause.map(Box::new), returning,
|
||||
order_by: None, limit: None })));
|
||||
}
|
||||
%endif
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -827,14 +827,14 @@ cmd ::= with(W) insert_cmd(R) INTO xfullname(X) idlist_opt(F) select(S)
|
|||
upsert(U). {
|
||||
let (upsert, returning) = U;
|
||||
let body = InsertBody::Select(Box::new(S), upsert);
|
||||
self.ctx.stmt = Some(Stmt::Insert{ with: W, or_conflict: R, tbl_name: X, columns: F,
|
||||
body: Box::new(body), returning });
|
||||
self.ctx.stmt = Some(Stmt::Insert(Box::new(Insert{ with: W, or_conflict: R, tbl_name: X, columns: F,
|
||||
body, returning })));
|
||||
}
|
||||
cmd ::= with(W) insert_cmd(R) INTO xfullname(X) idlist_opt(F) DEFAULT VALUES returning(Y).
|
||||
{
|
||||
let body = InsertBody::DefaultValues;
|
||||
self.ctx.stmt = Some(Stmt::Insert{ with: W, or_conflict: R, tbl_name: X, columns: F,
|
||||
body: Box::new(body), returning: Y });
|
||||
self.ctx.stmt = Some(Stmt::Insert(Box::new(Insert{ with: W, or_conflict: R, tbl_name: X, columns: F,
|
||||
body, returning: Y })));
|
||||
}
|
||||
|
||||
%type upsert {(Option<Upsert>, Option<Vec<ResultColumn>>)}
|
||||
|
@ -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}
|
||||
|
@ -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<Expr>}
|
||||
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
|
||||
|
@ -1139,13 +1139,13 @@ vinto(A) ::= . {A = None;}
|
|||
///////////////////////////// The PRAGMA command /////////////////////////////
|
||||
//
|
||||
%ifndef SQLITE_OMIT_PRAGMA
|
||||
cmd ::= PRAGMA fullname(X). {self.ctx.stmt = Some(Stmt::Pragma(X, None));}
|
||||
cmd ::= PRAGMA fullname(X) EQ nmnum(Y). {self.ctx.stmt = Some(Stmt::Pragma(X, Some(PragmaBody::Equals(Y))));}
|
||||
cmd ::= PRAGMA fullname(X) LP nmnum(Y) RP. {self.ctx.stmt = Some(Stmt::Pragma(X, Some(PragmaBody::Call(Y))));}
|
||||
cmd ::= PRAGMA fullname(X). {self.ctx.stmt = Some(Stmt::Pragma(Box::new(X), None));}
|
||||
cmd ::= PRAGMA fullname(X) EQ nmnum(Y). {self.ctx.stmt = Some(Stmt::Pragma(Box::new(X), Some(Box::new(PragmaBody::Equals(Y)))));}
|
||||
cmd ::= PRAGMA fullname(X) LP nmnum(Y) RP. {self.ctx.stmt = Some(Stmt::Pragma(Box::new(X), Some(Box::new(PragmaBody::Call(Y)))));}
|
||||
cmd ::= PRAGMA fullname(X) EQ minus_num(Y).
|
||||
{self.ctx.stmt = Some(Stmt::Pragma(X, Some(PragmaBody::Equals(Y))));}
|
||||
{self.ctx.stmt = Some(Stmt::Pragma(Box::new(X), Some(Box::new(PragmaBody::Equals(Y)))));}
|
||||
cmd ::= PRAGMA fullname(X) LP minus_num(Y) RP.
|
||||
{self.ctx.stmt = Some(Stmt::Pragma(X, Some(PragmaBody::Call(Y))));}
|
||||
{self.ctx.stmt = Some(Stmt::Pragma(Box::new(X), Some(Box::new(PragmaBody::Call(Y)))));}
|
||||
|
||||
%type nmnum {Expr}
|
||||
nmnum(A) ::= plus_num(A).
|
||||
|
@ -1166,10 +1166,10 @@ minus_num(A) ::= MINUS number(X). {A = Expr::unary(UnaryOperator::Negative,
|
|||
|
||||
cmd ::= createkw temp(T) TRIGGER ifnotexists(NOERR) fullname(B) trigger_time(C) trigger_event(D)
|
||||
ON fullname(E) foreach_clause(X) when_clause(G) BEGIN trigger_cmd_list(S) END. {
|
||||
self.ctx.stmt = Some(Stmt::CreateTrigger{
|
||||
temporary: T, if_not_exists: NOERR, trigger_name: B, time: C, event: Box::new(D), tbl_name: E,
|
||||
for_each_row: X, when_clause: G.map(Box::new), commands: S
|
||||
});
|
||||
self.ctx.stmt = Some(Stmt::CreateTrigger(Box::new(CreateTrigger{
|
||||
temporary: T, if_not_exists: NOERR, trigger_name: B, time: C, event: D, tbl_name: E,
|
||||
for_each_row: X, when_clause: G, commands: S
|
||||
})));
|
||||
}
|
||||
|
||||
%type trigger_time {Option<TriggerTime>}
|
||||
|
@ -1235,17 +1235,17 @@ tridxby ::= NOT INDEXED. {
|
|||
// UPDATE
|
||||
trigger_cmd(A) ::=
|
||||
UPDATE orconf(R) trnm(X) tridxby SET setlist(Y) from(F) where_opt(Z).
|
||||
{A = TriggerCmd::Update{ or_conflict: R, tbl_name: X, sets: Y, from: F, where_clause: Z };}
|
||||
{A = TriggerCmd::Update(Box::new(TriggerCmdUpdate{ or_conflict: R, tbl_name: X, sets: Y, from: F, where_clause: Z }));}
|
||||
|
||||
// INSERT
|
||||
trigger_cmd(A) ::= insert_cmd(R) INTO
|
||||
trnm(X) idlist_opt(F) select(S) upsert(U). {
|
||||
let (upsert, returning) = U;
|
||||
A = TriggerCmd::Insert{ or_conflict: R, tbl_name: X, col_names: F, select: Box::new(S), upsert, returning };/*A-overwrites-R*/
|
||||
A = TriggerCmd::Insert(Box::new(TriggerCmdInsert{ or_conflict: R, tbl_name: X, col_names: F, select: Box::new(S), upsert, returning }));/*A-overwrites-R*/
|
||||
}
|
||||
// DELETE
|
||||
trigger_cmd(A) ::= DELETE FROM trnm(X) tridxby where_opt(Y).
|
||||
{A = TriggerCmd::Delete{ tbl_name: X, where_clause: Y };}
|
||||
{A = TriggerCmd::Delete(Box::new(TriggerCmdDelete{ tbl_name: X, where_clause: Y }));}
|
||||
|
||||
// SELECT
|
||||
trigger_cmd(A) ::= select(X).
|
||||
|
@ -1279,7 +1279,7 @@ cmd ::= ATTACH database_kw_opt expr(F) AS expr(D) key_opt(K). {
|
|||
self.ctx.stmt = Some(Stmt::Attach{ expr: Box::new(F), db_name: Box::new(D), key: K.map(Box::new) });
|
||||
}
|
||||
cmd ::= DETACH database_kw_opt expr(D). {
|
||||
self.ctx.stmt = Some(Stmt::Detach(D));
|
||||
self.ctx.stmt = Some(Stmt::Detach(Box::new(D)));
|
||||
}
|
||||
|
||||
%type key_opt {Option<Expr>}
|
||||
|
@ -1305,19 +1305,19 @@ cmd ::= ANALYZE fullname(X). {self.ctx.stmt = Some(Stmt::Analyze(Some(X)));}
|
|||
//////////////////////// ALTER TABLE table ... ////////////////////////////////
|
||||
%ifndef SQLITE_OMIT_ALTERTABLE
|
||||
cmd ::= ALTER TABLE fullname(X) RENAME TO nm(Z). {
|
||||
self.ctx.stmt = Some(Stmt::AlterTable(X, AlterTableBody::RenameTo(Z)));
|
||||
self.ctx.stmt = Some(Stmt::AlterTable(Box::new((X, AlterTableBody::RenameTo(Z)))));
|
||||
}
|
||||
cmd ::= ALTER TABLE fullname(X)
|
||||
ADD kwcolumn_opt columnname(Y) carglist(C). {
|
||||
let (col_name, col_type) = Y;
|
||||
let cd = ColumnDefinition{ col_name, col_type, constraints: C };
|
||||
self.ctx.stmt = Some(Stmt::AlterTable(X, AlterTableBody::AddColumn(cd)));
|
||||
self.ctx.stmt = Some(Stmt::AlterTable(Box::new((X, AlterTableBody::AddColumn(cd)))));
|
||||
}
|
||||
cmd ::= ALTER TABLE fullname(X) RENAME kwcolumn_opt nm(Y) TO nm(Z). {
|
||||
self.ctx.stmt = Some(Stmt::AlterTable(X, AlterTableBody::RenameColumn{ old: Y, new: Z }));
|
||||
self.ctx.stmt = Some(Stmt::AlterTable(Box::new((X, AlterTableBody::RenameColumn{ old: Y, new: Z }))));
|
||||
}
|
||||
cmd ::= ALTER TABLE fullname(X) DROP kwcolumn_opt nm(Y). {
|
||||
self.ctx.stmt = Some(Stmt::AlterTable(X, AlterTableBody::DropColumn(Y)));
|
||||
self.ctx.stmt = Some(Stmt::AlterTable(Box::new((X, AlterTableBody::DropColumn(Y)))));
|
||||
}
|
||||
|
||||
kwcolumn_opt ::= .
|
||||
|
@ -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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue