Files
turso/parser/src/parser.rs
2025-08-13 15:11:32 +07:00

11270 lines
484 KiB
Rust
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use crate::ast::{
AlterTableBody, As, Cmd, ColumnConstraint, ColumnDefinition, CommonTableExpr, CompoundOperator,
CompoundSelect, CreateTableBody, DeferSubclause, Distinctness, Expr, ForeignKeyClause,
FrameBound, FrameClause, FrameExclude, FrameMode, FromClause, FunctionTail, GroupBy, Indexed,
IndexedColumn, InitDeferredPred, InsertBody, JoinConstraint, JoinOperator, JoinType,
JoinedSelectTable, LikeOperator, Limit, Literal, Materialized, Name, NamedColumnConstraint,
NamedTableConstraint, NullsOrder, OneSelect, Operator, Over, PragmaBody, PragmaValue,
QualifiedName, RefAct, RefArg, ResolveType, ResultColumn, Select, SelectBody, SelectTable, Set,
SortOrder, SortedColumn, Stmt, TableConstraint, TableOptions, TransactionType, TriggerCmd,
TriggerEvent, TriggerTime, Type, TypeSize, UnaryOperator, Upsert, UpsertDo, UpsertIndex,
Window, WindowDef, With,
};
use crate::error::Error;
use crate::lexer::{Lexer, Token};
use crate::token::TokenType;
#[inline(always)]
fn from_bytes_as_str(bytes: &[u8]) -> &str {
unsafe { str::from_utf8_unchecked(bytes) }
}
#[inline(always)]
fn from_bytes(bytes: &[u8]) -> String {
unsafe { str::from_utf8_unchecked(bytes).to_owned() }
}
#[inline(always)]
fn join_type_from_bytes(s: &[u8]) -> Result<JoinType, Error> {
if b"CROSS".eq_ignore_ascii_case(s) {
Ok(JoinType::INNER | JoinType::CROSS)
} else if b"FULL".eq_ignore_ascii_case(s) {
Ok(JoinType::LEFT | JoinType::RIGHT | JoinType::OUTER)
} else if b"INNER".eq_ignore_ascii_case(s) {
Ok(JoinType::INNER)
} else if b"LEFT".eq_ignore_ascii_case(s) {
Ok(JoinType::LEFT | JoinType::OUTER)
} else if b"NATURAL".eq_ignore_ascii_case(s) {
Ok(JoinType::NATURAL)
} else if b"RIGHT".eq_ignore_ascii_case(s) {
Ok(JoinType::RIGHT | JoinType::OUTER)
} else if b"OUTER".eq_ignore_ascii_case(s) {
Ok(JoinType::OUTER)
} else {
Err(Error::Custom(format!(
"unsupported JOIN type: {:?}",
str::from_utf8(s)
)))
}
}
#[inline(always)]
fn new_join_type(n0: &[u8], n1: Option<&[u8]>, n2: Option<&[u8]>) -> Result<JoinType, Error> {
let mut jt = join_type_from_bytes(n0)?;
if let Some(n1) = n1 {
jt |= join_type_from_bytes(n1)?;
}
if let Some(n2) = n2 {
jt |= join_type_from_bytes(n2)?;
}
if (jt & (JoinType::INNER | JoinType::OUTER)) == (JoinType::INNER | JoinType::OUTER)
|| (jt & (JoinType::OUTER | JoinType::LEFT | JoinType::RIGHT)) == JoinType::OUTER
{
return Err(Error::Custom(format!(
"unsupported JOIN type: {:?} {:?} {:?}",
from_bytes_as_str(n0),
from_bytes_as_str(n1.unwrap_or(&[])),
from_bytes_as_str(n2.unwrap_or(&[])),
)));
}
Ok(jt)
}
pub struct Parser<'a> {
lexer: Lexer<'a>,
/// The current token being processed
current_token: Token<'a>,
peekable: bool,
}
impl<'a> Iterator for Parser<'a> {
type Item = Result<Cmd, Error>;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
match self.mark(|p| p.next_cmd()) {
Ok(None) => None, // EOF
Ok(Some(cmd)) => Some(Ok(cmd)),
Err(err) => Some(Err(err)),
}
}
}
impl<'a> Parser<'a> {
#[inline(always)]
pub fn new(input: &'a [u8]) -> Self {
Self {
lexer: Lexer::new(input),
peekable: false,
current_token: Token {
value: b"",
token_type: None,
},
}
}
// entrypoint of parsing
fn next_cmd(&mut self) -> Result<Option<Cmd>, Error> {
// consumes prefix SEMI
while let Some(token) = self.peek()? {
if token.token_type == Some(TokenType::TK_SEMI) {
self.eat_assert(&[TokenType::TK_SEMI]);
} else {
break;
}
}
let result = match self.peek()? {
None => None, // EOF
Some(token) => match token.token_type.unwrap() {
TokenType::TK_EXPLAIN => {
self.eat_assert(&[TokenType::TK_EXPLAIN]);
let mut is_query_plan = false;
if self.peek_no_eof()?.token_type == Some(TokenType::TK_QUERY) {
self.eat_assert(&[TokenType::TK_QUERY]);
self.eat_expect(&[TokenType::TK_PLAN])?;
is_query_plan = true;
}
let stmt = self.parse_stmt()?;
if is_query_plan {
Some(Cmd::ExplainQueryPlan(stmt))
} else {
Some(Cmd::Explain(stmt))
}
}
_ => {
let stmt = self.parse_stmt()?;
Some(Cmd::Stmt(stmt))
}
},
};
let mut found_semi = false;
loop {
match self.peek()? {
None => break,
Some(token) if token.token_type == Some(TokenType::TK_SEMI) => {
found_semi = true;
self.eat_assert(&[TokenType::TK_SEMI]);
}
Some(token) => {
if !found_semi {
return Err(Error::ParseUnexpectedToken {
parsed_offset: (self.lexer.offset, 1).into(),
expected: &[TokenType::TK_SEMI],
got: token.token_type.unwrap(),
});
}
break;
}
}
}
Ok(result)
}
#[inline(always)]
fn consume_lexer_without_whitespaces_or_comments(
&mut self,
) -> Option<Result<Token<'a>, Error>> {
debug_assert!(!self.peekable);
loop {
let tok = self.lexer.next();
if let Some(Ok(ref token)) = tok {
if token.token_type.is_none() {
continue; // white space or comment
}
}
return tok;
}
}
fn next_token(&mut self) -> Result<Option<Token<'a>>, Error> {
debug_assert!(!self.peekable);
let mut next = self.consume_lexer_without_whitespaces_or_comments();
fn get_token(tt: TokenType) -> TokenType {
match tt {
TokenType::TK_ID
| TokenType::TK_STRING
| TokenType::TK_JOIN_KW
| TokenType::TK_UNION
| TokenType::TK_EXCEPT
| TokenType::TK_INTERSECT
| TokenType::TK_GENERATED
| TokenType::TK_WITHOUT
| TokenType::TK_COLUMNKW
| TokenType::TK_WINDOW
| TokenType::TK_FILTER
| TokenType::TK_OVER => TokenType::TK_ID,
_ => tt.fallback_id_if_ok(),
}
}
if let Some(Ok(ref mut tok)) = next {
/*
** The following three functions are called immediately after the tokenizer
** reads the keywords WINDOW, OVER and FILTER, respectively, to determine
** whether the token should be treated as a keyword or an SQL identifier.
** This cannot be handled by the usual lemon %fallback method, due to
** the ambiguity in some constructions. e.g.
**
** SELECT sum(x) OVER ...
**
** In the above, "OVER" might be a keyword, or it might be an alias for the
** sum(x) expression. If a "%fallback ID OVER" directive were added to
** grammar, then SQLite would always treat "OVER" as an alias, making it
** impossible to call a window-function without a FILTER clause.
**
** WINDOW is treated as a keyword if:
**
** * the following token is an identifier, or a keyword that can fallback
** to being an identifier, and
** * the token after than one is TK_AS.
**
** OVER is a keyword if:
**
** * the previous token was TK_RP, and
** * the next token is either TK_LP or an identifier.
**
** FILTER is a keyword if:
**
** * the previous token was TK_RP, and
** * the next token is TK_LP.
**
** UNION is a keyword if:
**
** * the next token is TK_ALL|TK_SELECT|TK_VALUES.
**
** EXCEPT is a keyword if:
**
** * the next token is TK_SELECT|TK_VALUES.
**
** INTERSECT is a keyword if:
**
** * the next token is TK_SELECT|TK_VALUES.
**
** COLUMNKW is a keyword if:
**
** * the previous token is TK_ADD|TK_RENAME|TK_DROP.
**
** GENERATED is a keyword if:
**
** * the next token is TK_ALWAYS.
** * the token after than one is TK_AS.
**
** WITHOUT is a keyword if:
**
** * the previous token is TK_RP|TK_COMMA.
** * the next token is TK_ID.
*/
match tok.token_type.unwrap() {
TokenType::TK_WINDOW => {
let can_be_window = self.try_parse(|p| {
match p.consume_lexer_without_whitespaces_or_comments() {
None => return Ok(false),
Some(tok) => match get_token(tok?.token_type.unwrap()) {
TokenType::TK_ID => {}
_ => return Ok(false),
},
}
match p.consume_lexer_without_whitespaces_or_comments() {
None => return Ok(false),
Some(tok) => match tok?.token_type.unwrap() {
TokenType::TK_AS => Ok(true),
_ => Ok(false),
},
}
})?;
if !can_be_window {
tok.token_type = Some(TokenType::TK_ID);
}
}
TokenType::TK_OVER => {
let prev_tt = self.current_token.token_type.unwrap_or(TokenType::TK_EOF);
let can_be_over = {
if prev_tt == TokenType::TK_RP {
self.try_parse(|p| {
match p.consume_lexer_without_whitespaces_or_comments() {
None => return Ok(false),
Some(tok) => match get_token(tok?.token_type.unwrap()) {
TokenType::TK_LP | TokenType::TK_ID => Ok(true),
_ => Ok(false),
},
}
})?
} else {
false
}
};
if !can_be_over {
tok.token_type = Some(TokenType::TK_ID);
}
}
TokenType::TK_FILTER => {
let prev_tt = self.current_token.token_type.unwrap_or(TokenType::TK_EOF);
let can_be_filter = {
if prev_tt == TokenType::TK_RP {
self.try_parse(|p| {
match p.consume_lexer_without_whitespaces_or_comments() {
None => return Ok(false),
Some(tok) => match tok?.token_type.unwrap() {
TokenType::TK_LP => Ok(true),
_ => Ok(false),
},
}
})?
} else {
false
}
};
if !can_be_filter {
tok.token_type = Some(TokenType::TK_ID);
}
}
TokenType::TK_UNION => {
let can_be_union = self.try_parse(|p| {
match p.consume_lexer_without_whitespaces_or_comments() {
None => return Ok(false),
Some(tok) => match tok?.token_type.unwrap() {
TokenType::TK_ALL | TokenType::TK_SELECT | TokenType::TK_VALUES => {
Ok(true)
}
_ => Ok(false),
},
}
})?;
if !can_be_union {
tok.token_type = Some(TokenType::TK_ID);
}
}
TokenType::TK_EXCEPT | TokenType::TK_INTERSECT => {
let can_be_except = self.try_parse(|p| {
match p.consume_lexer_without_whitespaces_or_comments() {
None => return Ok(false),
Some(tok) => match tok?.token_type.unwrap() {
TokenType::TK_SELECT | TokenType::TK_VALUES => Ok(true),
_ => Ok(false),
},
}
})?;
if !can_be_except {
tok.token_type = Some(TokenType::TK_ID);
}
}
TokenType::TK_COLUMNKW => {
let prev_tt = self.current_token.token_type.unwrap_or(TokenType::TK_EOF);
let can_be_columnkw = match prev_tt {
TokenType::TK_ADD | TokenType::TK_RENAME | TokenType::TK_DROP => true,
_ => false,
};
if !can_be_columnkw {
tok.token_type = Some(TokenType::TK_ID);
}
}
TokenType::TK_GENERATED => {
let can_be_generated = self.try_parse(|p| {
match p.consume_lexer_without_whitespaces_or_comments() {
None => return Ok(false),
Some(tok) => match tok?.token_type.unwrap() {
TokenType::TK_ALWAYS => {}
_ => return Ok(false),
},
}
match p.consume_lexer_without_whitespaces_or_comments() {
None => return Ok(false),
Some(tok) => match tok?.token_type.unwrap() {
TokenType::TK_AS => Ok(true),
_ => Ok(false),
},
}
})?;
if !can_be_generated {
tok.token_type = Some(TokenType::TK_ID);
}
}
TokenType::TK_WITHOUT => {
let prev_tt = self.current_token.token_type.unwrap_or(TokenType::TK_EOF);
let can_be_without = match prev_tt {
TokenType::TK_RP | TokenType::TK_COMMA => self.try_parse(|p| {
match p.consume_lexer_without_whitespaces_or_comments() {
None => return Ok(false),
Some(tok) => match get_token(tok?.token_type.unwrap()) {
TokenType::TK_ID => Ok(true),
_ => Ok(false),
},
}
})?,
_ => false,
};
if !can_be_without {
tok.token_type = Some(TokenType::TK_ID);
}
}
_ => {}
}
}
match next {
None => Ok(None), // EOF
Some(Ok(tok)) => {
self.current_token = tok.clone();
self.peekable = true;
Ok(Some(tok))
}
Some(Err(err)) => Err(err),
}
}
#[inline(always)]
fn mark<F, R>(&mut self, exc: F) -> Result<R, Error>
where
F: FnOnce(&mut Self) -> Result<R, Error>,
{
let old_peekable = self.peekable;
let old_current_token = self.current_token.clone();
let start_offset = self.lexer.offset;
let result = exc(self);
if result.is_err() {
self.peekable = old_peekable;
self.current_token = old_current_token;
self.lexer.offset = start_offset;
}
result
}
#[inline(always)]
fn try_parse<F, R>(&mut self, exc: F) -> R
where
F: FnOnce(&mut Self) -> R,
{
debug_assert!(!self.peekable);
let start_offset = self.lexer.offset;
let result = exc(self);
self.peekable = false;
self.lexer.offset = start_offset;
result
}
/// Get the next token from the lexer
#[inline(always)]
fn eat(&mut self) -> Result<Option<Token<'a>>, Error> {
let result = self.peek()?;
self.peekable = false; // Clear the peek mark after consuming
Ok(result)
}
/// Peek at the next token without consuming it
#[inline(always)]
fn peek(&mut self) -> Result<Option<Token<'a>>, Error> {
if self.peekable {
return Ok(Some(self.current_token.clone()));
}
self.next_token()
}
#[inline(always)]
fn eat_no_eof(&mut self) -> Result<Token<'a>, Error> {
match self.eat()? {
None => Err(Error::ParseUnexpectedEOF),
Some(token) => Ok(token),
}
}
#[inline(always)]
fn eat_expect(&mut self, expected: &'static [TokenType]) -> Result<Token<'a>, Error> {
self.peek_expect(expected)?;
Ok(self.eat_assert(expected))
}
// this function expected to be called after checking the token type (peek)
#[inline(always)]
fn eat_assert(&mut self, _expected: &'static [TokenType]) -> Token<'a> {
let token = self.eat_no_eof().unwrap();
#[cfg(debug_assertions)]
{
for expected in _expected {
if token.token_type == Some(*expected) {
return token;
}
if *expected == TokenType::TK_ID
&& token.token_type.unwrap().fallback_id_if_ok() == TokenType::TK_ID
{
return token;
}
}
panic!(
"Expected token {:?}, got {:?}",
_expected,
token.token_type.unwrap()
);
}
#[cfg(not(debug_assertions))]
token // in release mode, we assume the caller has checked the token type
}
#[inline(always)]
fn peek_no_eof(&mut self) -> Result<Token<'a>, Error> {
match self.peek()? {
None => Err(Error::ParseUnexpectedEOF),
Some(token) => Ok(token),
}
}
#[inline(always)]
fn peek_expect(&mut self, expected: &'static [TokenType]) -> Result<Token<'a>, Error> {
let token = self.peek_no_eof()?;
for expected in expected {
if token.token_type == Some(*expected) {
return Ok(token);
}
if *expected == TokenType::TK_ID
&& token.token_type.unwrap().fallback_id_if_ok() == TokenType::TK_ID
{
return Ok(token);
}
}
Err(Error::ParseUnexpectedToken {
parsed_offset: (self.lexer.offset, 1).into(),
expected: expected,
got: token.token_type.unwrap(), // no whitespace or comment tokens here
})
}
#[inline(always)]
fn parse_stmt(&mut self) -> Result<Stmt, Error> {
let tok = self.peek_expect(&[
TokenType::TK_BEGIN,
TokenType::TK_COMMIT,
TokenType::TK_END,
TokenType::TK_ROLLBACK,
TokenType::TK_SAVEPOINT,
TokenType::TK_RELEASE,
TokenType::TK_CREATE,
TokenType::TK_SELECT,
TokenType::TK_VALUES,
TokenType::TK_WITH,
TokenType::TK_ANALYZE,
TokenType::TK_ATTACH,
TokenType::TK_DETACH,
TokenType::TK_PRAGMA,
TokenType::TK_VACUUM,
TokenType::TK_ALTER,
TokenType::TK_DELETE,
TokenType::TK_DROP,
TokenType::TK_INSERT,
TokenType::TK_REPLACE,
TokenType::TK_UPDATE,
])?;
match tok.token_type.unwrap() {
TokenType::TK_BEGIN => self.parse_begin(),
TokenType::TK_COMMIT | TokenType::TK_END => self.parse_commit(),
TokenType::TK_ROLLBACK => self.parse_rollback(),
TokenType::TK_SAVEPOINT => self.parse_savepoint(),
TokenType::TK_RELEASE => self.parse_release(),
TokenType::TK_CREATE => self.parse_create_stmt(),
TokenType::TK_SELECT | TokenType::TK_VALUES => Ok(Stmt::Select(self.parse_select()?)),
TokenType::TK_WITH => self.parse_with_stmt(),
TokenType::TK_ANALYZE => self.parse_analyze(),
TokenType::TK_ATTACH => self.parse_attach(),
TokenType::TK_DETACH => self.parse_detach(),
TokenType::TK_PRAGMA => self.parse_pragma(),
TokenType::TK_VACUUM => self.parse_vacuum(),
TokenType::TK_ALTER => self.parse_alter(),
TokenType::TK_DELETE => self.parse_delete(),
TokenType::TK_DROP => self.parse_drop_stmt(),
TokenType::TK_INSERT | TokenType::TK_REPLACE => self.parse_insert(),
TokenType::TK_UPDATE => self.parse_update(),
_ => unreachable!(),
}
}
fn parse_nm(&mut self) -> Result<Name, Error> {
let tok = self.eat_expect(&[
TokenType::TK_ID,
TokenType::TK_STRING,
TokenType::TK_INDEXED,
TokenType::TK_JOIN_KW,
])?;
let first_char = tok.value[0]; // no need to check empty
match first_char {
b'[' | b'\'' | b'`' | b'"' => Ok(Name::Quoted(from_bytes(tok.value))),
_ => Ok(Name::Ident(from_bytes(tok.value))),
}
}
fn parse_transopt(&mut self) -> Result<Option<Name>, Error> {
match self.peek()? {
None => Ok(None),
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_TRANSACTION => {
self.eat_assert(&[TokenType::TK_TRANSACTION]);
match self.peek()? {
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_ID
| TokenType::TK_STRING
| TokenType::TK_INDEXED
| TokenType::TK_JOIN_KW => Ok(Some(self.parse_nm()?)),
_ => Ok(None),
},
_ => Ok(None),
}
}
_ => Ok(None),
},
}
}
fn parse_begin(&mut self) -> Result<Stmt, Error> {
self.eat_assert(&[TokenType::TK_BEGIN]);
let transtype = match self.peek()? {
None => None,
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_DEFERRED => {
self.eat_assert(&[TokenType::TK_DEFERRED]);
Some(TransactionType::Deferred)
}
TokenType::TK_IMMEDIATE => {
self.eat_assert(&[TokenType::TK_IMMEDIATE]);
Some(TransactionType::Immediate)
}
TokenType::TK_EXCLUSIVE => {
self.eat_assert(&[TokenType::TK_EXCLUSIVE]);
Some(TransactionType::Exclusive)
}
_ => None,
},
};
Ok(Stmt::Begin {
typ: transtype,
name: self.parse_transopt()?,
})
}
fn parse_commit(&mut self) -> Result<Stmt, Error> {
self.eat_assert(&[TokenType::TK_COMMIT, TokenType::TK_END]);
Ok(Stmt::Commit {
name: self.parse_transopt()?,
})
}
fn parse_rollback(&mut self) -> Result<Stmt, Error> {
self.eat_assert(&[TokenType::TK_ROLLBACK]);
let tx_name = self.parse_transopt()?;
let savepoint_name = match self.peek()? {
None => None,
Some(tok) => {
if tok.token_type == Some(TokenType::TK_TO) {
self.eat_assert(&[TokenType::TK_TO]);
if self.peek_no_eof()?.token_type == Some(TokenType::TK_SAVEPOINT) {
self.eat_assert(&[TokenType::TK_SAVEPOINT]);
}
Some(self.parse_nm()?)
} else {
None
}
}
};
Ok(Stmt::Rollback {
tx_name,
savepoint_name,
})
}
fn parse_savepoint(&mut self) -> Result<Stmt, Error> {
self.eat_assert(&[TokenType::TK_SAVEPOINT]);
Ok(Stmt::Savepoint {
name: self.parse_nm()?,
})
}
fn parse_release(&mut self) -> Result<Stmt, Error> {
self.eat_assert(&[TokenType::TK_RELEASE]);
if self.peek_no_eof()?.token_type == Some(TokenType::TK_SAVEPOINT) {
self.eat_assert(&[TokenType::TK_SAVEPOINT]);
}
Ok(Stmt::Release {
name: self.parse_nm()?,
})
}
fn parse_create_view(&mut self, temporary: bool) -> Result<Stmt, Error> {
self.eat_assert(&[TokenType::TK_VIEW]);
let if_not_exists = self.parse_if_not_exists()?;
let view_name = self.parse_fullname(false)?;
let columns = self.parse_eid_list()?;
self.eat_expect(&[TokenType::TK_AS])?;
let select = self.parse_select()?;
Ok(Stmt::CreateView {
temporary,
if_not_exists,
view_name,
columns,
select,
})
}
fn parse_vtab_arg(&mut self) -> Result<String, Error> {
let tok = self.peek_no_eof()?;
// minus len() because lexer already consumed the token
let start_idx = self.lexer.offset - tok.value.len();
loop {
match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_LP => {
let mut lp_count: usize = 0;
loop {
let tok = self.eat_no_eof()?;
match tok.token_type.unwrap() {
TokenType::TK_LP => {
lp_count += 1;
}
TokenType::TK_RP => {
lp_count -= 1; // FIXME: no need to check underflow
if lp_count == 0 {
break;
}
}
_ => {}
}
}
}
TokenType::TK_COMMA | TokenType::TK_RP => break,
_ => {
self.eat_no_eof()?;
}
}
}
// minus 1 because lexer already consumed TK_COMMA or TK_RP
let end_idx = self.lexer.offset - 1;
if start_idx == end_idx {
return Err(Error::Custom("unexpected COMMA in vtab args".to_owned()));
}
Ok(from_bytes(&self.lexer.input[start_idx..end_idx]))
}
fn parse_create_virtual(&mut self) -> Result<Stmt, Error> {
self.eat_assert(&[TokenType::TK_VIRTUAL]);
self.eat_expect(&[TokenType::TK_TABLE])?;
let if_not_exists = self.parse_if_not_exists()?;
let tbl_name = self.parse_fullname(false)?;
self.eat_expect(&[TokenType::TK_USING])?;
let module_name = self.parse_nm()?;
let args = match self.peek()? {
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_LP => {
self.eat_assert(&[TokenType::TK_LP]);
let mut result = vec![];
loop {
match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_RP => break, // handle empty args case
_ => {}
}
result.push(self.parse_vtab_arg()?);
let tok = self.peek_expect(&[TokenType::TK_COMMA, TokenType::TK_RP])?;
match tok.token_type.unwrap() {
TokenType::TK_COMMA => {
self.eat_assert(&[TokenType::TK_COMMA]);
}
TokenType::TK_RP => break,
_ => unreachable!(),
}
}
self.eat_assert(&[TokenType::TK_RP]);
result
}
_ => vec![],
},
_ => vec![],
};
Ok(Stmt::CreateVirtualTable {
if_not_exists,
tbl_name,
module_name,
args,
})
}
fn parse_create_stmt(&mut self) -> Result<Stmt, Error> {
self.eat_assert(&[TokenType::TK_CREATE]);
let mut first_tok = self.peek_expect(&[
TokenType::TK_TEMP,
TokenType::TK_TABLE,
TokenType::TK_VIRTUAL,
TokenType::TK_VIEW,
TokenType::TK_INDEX,
TokenType::TK_UNIQUE,
TokenType::TK_TRIGGER,
])?;
let mut temp = false;
if first_tok.token_type == Some(TokenType::TK_TEMP) {
self.eat_assert(&[TokenType::TK_TEMP]);
temp = true;
first_tok = self.peek_expect(&[
TokenType::TK_TABLE,
TokenType::TK_VIEW,
TokenType::TK_TRIGGER,
])?;
}
match first_tok.token_type.unwrap() {
TokenType::TK_TABLE => self.parse_create_table(temp),
TokenType::TK_VIEW => self.parse_create_view(temp),
TokenType::TK_TRIGGER => self.parse_create_trigger(temp),
TokenType::TK_VIRTUAL => self.parse_create_virtual(),
TokenType::TK_INDEX | TokenType::TK_UNIQUE => self.parse_create_index(),
_ => unreachable!(),
}
}
fn parse_with_stmt(&mut self) -> Result<Stmt, Error> {
let with = self.parse_with()?;
debug_assert!(with.is_some());
let first_tok = self.peek_expect(&[
TokenType::TK_SELECT,
TokenType::TK_VALUES,
TokenType::TK_UPDATE,
TokenType::TK_DELETE,
TokenType::TK_INSERT,
TokenType::TK_REPLACE,
])?;
match first_tok.token_type.unwrap() {
TokenType::TK_SELECT | TokenType::TK_VALUES => {
Ok(Stmt::Select(self.parse_select_without_cte(with)?))
}
TokenType::TK_UPDATE => self.parse_update_without_cte(with),
TokenType::TK_DELETE => self.parse_delete_without_cte(with),
TokenType::TK_INSERT | TokenType::TK_REPLACE => self.parse_insert_without_cte(with),
_ => unreachable!(),
}
}
fn parse_if_not_exists(&mut self) -> Result<bool, Error> {
if let Some(tok) = self.peek()? {
if tok.token_type == Some(TokenType::TK_IF) {
self.eat_assert(&[TokenType::TK_IF]);
} else {
return Ok(false);
}
} else {
return Ok(false);
}
self.eat_expect(&[TokenType::TK_NOT])?;
self.eat_expect(&[TokenType::TK_EXISTS])?;
Ok(true)
}
fn parse_fullname(&mut self, allow_alias: bool) -> Result<QualifiedName, Error> {
let first_name = self.parse_nm()?;
let secone_name = if let Some(tok) = self.peek()? {
if tok.token_type == Some(TokenType::TK_DOT) {
self.eat_assert(&[TokenType::TK_DOT]);
Some(self.parse_nm()?)
} else {
None
}
} else {
None
};
let alias_name = if allow_alias {
if let Some(tok) = self.peek()? {
if tok.token_type == Some(TokenType::TK_AS) {
self.eat_assert(&[TokenType::TK_AS]);
Some(self.parse_nm()?)
} else {
None
}
} else {
None
}
} else {
None
};
if secone_name.is_some() {
Ok(QualifiedName {
db_name: Some(first_name),
name: secone_name.unwrap(),
alias: alias_name,
})
} else {
Ok(QualifiedName {
db_name: None,
name: first_name,
alias: alias_name,
})
}
}
fn parse_signed(&mut self) -> Result<Box<Expr>, Error> {
self.peek_expect(&[
TokenType::TK_FLOAT,
TokenType::TK_INTEGER,
TokenType::TK_PLUS,
TokenType::TK_MINUS,
])?;
let expr = self.parse_expr_operand()?;
match expr.as_ref() {
Expr::Unary(_, inner) => match inner.as_ref() {
Expr::Literal(Literal::Numeric(_)) => Ok(expr),
_ => Err(Error::Custom(
"Expected a numeric literal after unary operator".to_string(),
)),
},
_ => Ok(expr),
}
}
fn parse_type(&mut self) -> Result<Option<Type>, Error> {
let mut type_name = if let Some(tok) = self.peek()? {
match tok.token_type.unwrap().fallback_id_if_ok() {
TokenType::TK_ID | TokenType::TK_STRING => {
self.eat_assert(&[TokenType::TK_ID, TokenType::TK_STRING]);
from_bytes(tok.value)
}
_ => return Ok(None),
}
} else {
return Ok(None);
};
loop {
if let Some(tok) = self.peek()? {
match tok.token_type.unwrap().fallback_id_if_ok() {
TokenType::TK_ID | TokenType::TK_STRING => {
self.eat_assert(&[TokenType::TK_ID, TokenType::TK_STRING]);
type_name.push_str(" ");
type_name.push_str(from_bytes_as_str(tok.value));
}
_ => break,
}
} else {
break;
}
}
let size = if let Some(tok) = self.peek()? {
if tok.token_type == Some(TokenType::TK_LP) {
self.eat_assert(&[TokenType::TK_LP]);
let first_size = self.parse_signed()?;
let tok = self.eat_expect(&[TokenType::TK_RP, TokenType::TK_COMMA])?;
match tok.token_type.unwrap() {
TokenType::TK_RP => Some(TypeSize::MaxSize(first_size)),
TokenType::TK_COMMA => {
let second_size = self.parse_signed()?;
self.eat_expect(&[TokenType::TK_RP])?;
Some(TypeSize::TypeSize(first_size, second_size))
}
_ => unreachable!(),
}
} else {
None
}
} else {
None
};
Ok(Some(Type {
name: type_name,
size,
}))
}
/// SQLite understands these operators, listed in precedence1 order
/// (top to bottom / highest to lowest):
///
/// Operators 2
/// 11 -> ~ [expr] + [expr] - [expr]
/// 10 -> [expr] COLLATE (collation-name) 3
/// 9 -> || -> ->>
/// 8 -> * / %
/// 7 -> + -
/// 6 -> & | << >>
/// 5 -> [expr] ESCAPE [escape-character-expr] 4
/// 4 -> < > <= >=
/// 3 -> = == <> != IS IS NOT
/// IS DISTINCT FROM IS NOT DISTINCT FROM
/// [expr] BETWEEN5 [expr] AND [expr]
/// IN5 MATCH5 LIKE5 REGEXP5 GLOB5
/// [expr] ISNULL [expr] NOTNULL [expr] NOT NULL
/// 2 NOT [expr]
/// 1 -> AND
/// 0 -> OR
///
/// this function detect precedence by peeking first token of operator
/// after parsing a operand (binary operator)
fn current_token_precedence(&mut self) -> Result<Option<u8>, Error> {
let tok = self.peek()?;
if tok.is_none() {
return Ok(None);
}
match tok.unwrap().token_type.unwrap() {
TokenType::TK_OR => Ok(Some(0)),
TokenType::TK_AND => Ok(Some(1)),
TokenType::TK_NOT => Ok(Some(3)), // NOT is 3 because of binary operator
TokenType::TK_EQ
| TokenType::TK_NE
| TokenType::TK_IS
| TokenType::TK_BETWEEN
| TokenType::TK_IN
| TokenType::TK_MATCH
| TokenType::TK_LIKE_KW
| TokenType::TK_ISNULL
| TokenType::TK_NOTNULL => Ok(Some(3)),
TokenType::TK_LT | TokenType::TK_GT | TokenType::TK_LE | TokenType::TK_GE => {
Ok(Some(4))
}
TokenType::TK_ESCAPE => Ok(None), // ESCAPE will be consumed after parsing
// MATCH|LIKE_KW
TokenType::TK_BITAND
| TokenType::TK_BITOR
| TokenType::TK_LSHIFT
| TokenType::TK_RSHIFT => Ok(Some(6)),
TokenType::TK_PLUS | TokenType::TK_MINUS => Ok(Some(7)),
TokenType::TK_STAR | TokenType::TK_SLASH | TokenType::TK_REM => Ok(Some(8)),
TokenType::TK_CONCAT | TokenType::TK_PTR => Ok(Some(9)),
TokenType::TK_COLLATE => Ok(Some(10)),
// no need 11 because its for unary operators
_ => Ok(None),
}
}
fn parse_distinct(&mut self) -> Result<Option<Distinctness>, Error> {
match self.peek()? {
None => Ok(None),
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_DISTINCT => {
self.eat_assert(&[TokenType::TK_DISTINCT]);
Ok(Some(Distinctness::Distinct))
}
TokenType::TK_ALL => {
self.eat_assert(&[TokenType::TK_ALL]);
Ok(Some(Distinctness::All))
}
_ => Ok(None),
},
}
}
fn parse_filter_clause(&mut self) -> Result<Option<Box<Expr>>, Error> {
match self.peek()? {
None => return Ok(None),
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_FILTER => {
self.eat_assert(&[TokenType::TK_FILTER]);
}
_ => return Ok(None),
},
}
self.eat_expect(&[TokenType::TK_LP])?;
self.eat_expect(&[TokenType::TK_WHERE])?;
let expr = self.parse_expr(0)?;
self.eat_expect(&[TokenType::TK_RP])?;
Ok(Some(expr))
}
fn parse_frame_opt(&mut self) -> Result<Option<FrameClause>, Error> {
let range_or_rows = match self.peek()? {
None => return Ok(None),
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_RANGE => {
self.eat_assert(&[TokenType::TK_RANGE]);
FrameMode::Range
}
TokenType::TK_ROWS => {
self.eat_assert(&[TokenType::TK_ROWS]);
FrameMode::Rows
}
TokenType::TK_GROUPS => {
self.eat_assert(&[TokenType::TK_GROUPS]);
FrameMode::Groups
}
_ => return Ok(None),
},
};
let has_end = match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_BETWEEN => {
self.eat_assert(&[TokenType::TK_BETWEEN]);
true
}
_ => false,
};
let start = match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_UNBOUNDED => {
self.eat_assert(&[TokenType::TK_UNBOUNDED]);
self.eat_expect(&[TokenType::TK_PRECEDING])?;
FrameBound::UnboundedPreceding
}
TokenType::TK_CURRENT => {
self.eat_assert(&[TokenType::TK_CURRENT]);
self.eat_expect(&[TokenType::TK_ROW])?;
FrameBound::CurrentRow
}
_ => {
let expr = self.parse_expr(0)?;
let tok = self.eat_expect(&[TokenType::TK_PRECEDING, TokenType::TK_FOLLOWING])?;
match tok.token_type.unwrap() {
TokenType::TK_PRECEDING => FrameBound::Preceding(expr),
TokenType::TK_FOLLOWING => FrameBound::Following(expr),
_ => unreachable!(),
}
}
};
let end = if has_end {
self.eat_expect(&[TokenType::TK_AND])?;
Some(match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_UNBOUNDED => {
self.eat_assert(&[TokenType::TK_UNBOUNDED]);
self.eat_expect(&[TokenType::TK_FOLLOWING])?;
FrameBound::UnboundedFollowing
}
TokenType::TK_CURRENT => {
self.eat_assert(&[TokenType::TK_CURRENT]);
self.eat_expect(&[TokenType::TK_ROW])?;
FrameBound::CurrentRow
}
_ => {
let expr = self.parse_expr(0)?;
let tok =
self.eat_expect(&[TokenType::TK_PRECEDING, TokenType::TK_FOLLOWING])?;
match tok.token_type.unwrap() {
TokenType::TK_PRECEDING => FrameBound::Preceding(expr),
TokenType::TK_FOLLOWING => FrameBound::Following(expr),
_ => unreachable!(),
}
}
})
} else {
None
};
let exclude = match self.peek()? {
None => None,
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_EXCLUDE => {
self.eat_assert(&[TokenType::TK_EXCLUDE]);
let tok = self.eat_expect(&[
TokenType::TK_NO,
TokenType::TK_CURRENT,
TokenType::TK_GROUP,
TokenType::TK_TIES,
])?;
match tok.token_type.unwrap() {
TokenType::TK_NO => {
self.eat_expect(&[TokenType::TK_OTHERS])?;
Some(FrameExclude::NoOthers)
}
TokenType::TK_CURRENT => {
self.eat_expect(&[TokenType::TK_ROW])?;
Some(FrameExclude::CurrentRow)
}
TokenType::TK_GROUP => Some(FrameExclude::Group),
TokenType::TK_TIES => Some(FrameExclude::Ties),
_ => unreachable!(),
}
}
_ => None,
},
};
Ok(Some(FrameClause {
mode: range_or_rows,
start,
end,
exclude,
}))
}
fn parse_window(&mut self) -> Result<Window, Error> {
let name = match self.peek()? {
None => None,
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_PARTITION
| TokenType::TK_ORDER
| TokenType::TK_RANGE
| TokenType::TK_ROWS
| TokenType::TK_GROUPS => None,
tt => match tt.fallback_id_if_ok() {
TokenType::TK_ID
| TokenType::TK_STRING
| TokenType::TK_INDEXED
| TokenType::TK_JOIN_KW => Some(self.parse_nm()?),
_ => None,
},
},
};
let partition_by = match self.peek()? {
Some(tok) if tok.token_type == Some(TokenType::TK_PARTITION) => {
self.eat_assert(&[TokenType::TK_PARTITION]);
self.eat_expect(&[TokenType::TK_BY])?;
self.parse_nexpr_list()?
}
_ => vec![],
};
let order_by = self.parse_order_by()?;
let frame_clause = self.parse_frame_opt()?;
Ok(Window {
base: name,
partition_by,
order_by,
frame_clause,
})
}
fn parse_over_clause(&mut self) -> Result<Option<Over>, Error> {
match self.peek()? {
None => return Ok(None),
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_OVER => {
self.eat_assert(&[TokenType::TK_OVER]);
}
_ => return Ok(None),
},
}
let tok = self.peek_expect(&[
TokenType::TK_LP,
TokenType::TK_ID,
TokenType::TK_STRING,
TokenType::TK_INDEXED,
TokenType::TK_JOIN_KW,
])?;
match tok.token_type.unwrap() {
TokenType::TK_LP => {
self.eat_assert(&[TokenType::TK_LP]);
let window = self.parse_window()?;
self.eat_expect(&[TokenType::TK_RP])?;
Ok(Some(Over::Window(window)))
}
_ => Ok(Some(Over::Name(self.parse_nm()?))),
}
}
fn parse_filter_over(&mut self) -> Result<FunctionTail, Error> {
let filter_clause = self.parse_filter_clause()?;
let over_clause = self.parse_over_clause()?;
Ok(FunctionTail {
filter_clause,
over_clause,
})
}
fn parse_raise_type(&mut self) -> Result<ResolveType, Error> {
let tok = self.eat_expect(&[
TokenType::TK_ROLLBACK,
TokenType::TK_ABORT,
TokenType::TK_FAIL,
])?;
match tok.token_type.unwrap() {
TokenType::TK_ROLLBACK => Ok(ResolveType::Rollback),
TokenType::TK_ABORT => Ok(ResolveType::Abort),
TokenType::TK_FAIL => Ok(ResolveType::Fail),
_ => unreachable!(),
}
}
fn parse_expr_operand(&mut self) -> Result<Box<Expr>, Error> {
let tok = self.peek_expect(&[
TokenType::TK_LP,
TokenType::TK_CAST,
TokenType::TK_CTIME_KW,
TokenType::TK_RAISE,
TokenType::TK_ID,
TokenType::TK_STRING,
TokenType::TK_INDEXED,
TokenType::TK_JOIN_KW,
TokenType::TK_NULL,
TokenType::TK_BLOB,
TokenType::TK_FLOAT,
TokenType::TK_INTEGER,
TokenType::TK_VARIABLE,
TokenType::TK_NOT,
TokenType::TK_BITNOT,
TokenType::TK_PLUS,
TokenType::TK_MINUS,
TokenType::TK_EXISTS,
TokenType::TK_CASE,
])?;
match tok.token_type.unwrap() {
TokenType::TK_LP => {
self.eat_assert(&[TokenType::TK_LP]);
match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_WITH | TokenType::TK_SELECT | TokenType::TK_VALUES => {
let select = self.parse_select()?;
self.eat_expect(&[TokenType::TK_RP])?;
Ok(Box::new(Expr::Subquery(select)))
}
_ => {
let exprs = self.parse_nexpr_list()?;
self.eat_expect(&[TokenType::TK_RP])?;
Ok(Box::new(Expr::Parenthesized(exprs)))
}
}
}
TokenType::TK_NULL => {
self.eat_assert(&[TokenType::TK_NULL]);
Ok(Box::new(Expr::Literal(Literal::Null)))
}
TokenType::TK_BLOB => {
self.eat_assert(&[TokenType::TK_BLOB]);
Ok(Box::new(Expr::Literal(Literal::Blob(from_bytes(
tok.value,
)))))
}
TokenType::TK_FLOAT => {
self.eat_assert(&[TokenType::TK_FLOAT]);
Ok(Box::new(Expr::Literal(Literal::Numeric(from_bytes(
tok.value,
)))))
}
TokenType::TK_INTEGER => {
self.eat_assert(&[TokenType::TK_INTEGER]);
Ok(Box::new(Expr::Literal(Literal::Numeric(from_bytes(
tok.value,
)))))
}
TokenType::TK_VARIABLE => {
self.eat_assert(&[TokenType::TK_VARIABLE]);
Ok(Box::new(Expr::Variable(from_bytes(tok.value))))
}
TokenType::TK_CAST => {
self.eat_assert(&[TokenType::TK_CAST]);
self.eat_expect(&[TokenType::TK_LP])?;
let expr = self.parse_expr(0)?;
self.eat_expect(&[TokenType::TK_AS])?;
let typ = self.parse_type()?;
self.eat_expect(&[TokenType::TK_RP])?;
return Ok(Box::new(Expr::Cast {
expr,
type_name: typ,
}));
}
TokenType::TK_CTIME_KW => {
let tok = self.eat_assert(&[TokenType::TK_CTIME_KW]);
if b"CURRENT_DATE".eq_ignore_ascii_case(&tok.value) {
Ok(Box::new(Expr::Literal(Literal::CurrentDate)))
} else if b"CURRENT_TIME".eq_ignore_ascii_case(&tok.value) {
Ok(Box::new(Expr::Literal(Literal::CurrentTime)))
} else if b"CURRENT_TIMESTAMP".eq_ignore_ascii_case(&tok.value) {
Ok(Box::new(Expr::Literal(Literal::CurrentTimestamp)))
} else {
unreachable!()
}
}
TokenType::TK_NOT => {
self.eat_assert(&[TokenType::TK_NOT]);
let expr = self.parse_expr(2)?; // NOT precedence is 2
Ok(Box::new(Expr::Unary(UnaryOperator::Not, expr)))
}
TokenType::TK_BITNOT => {
self.eat_assert(&[TokenType::TK_BITNOT]);
let expr = self.parse_expr(11)?; // BITNOT precedence is 11
Ok(Box::new(Expr::Unary(UnaryOperator::BitwiseNot, expr)))
}
TokenType::TK_PLUS => {
self.eat_assert(&[TokenType::TK_PLUS]);
let expr = self.parse_expr(11)?; // PLUS precedence is 11
Ok(Box::new(Expr::Unary(UnaryOperator::Positive, expr)))
}
TokenType::TK_MINUS => {
self.eat_assert(&[TokenType::TK_MINUS]);
let expr = self.parse_expr(11)?; // MINUS precedence is 11
Ok(Box::new(Expr::Unary(UnaryOperator::Negative, expr)))
}
TokenType::TK_EXISTS => {
self.eat_assert(&[TokenType::TK_EXISTS]);
self.eat_expect(&[TokenType::TK_LP])?;
let select = self.parse_select()?;
self.eat_expect(&[TokenType::TK_RP])?;
Ok(Box::new(Expr::Exists(select)))
}
TokenType::TK_CASE => {
self.eat_assert(&[TokenType::TK_CASE]);
let base = if self.peek_no_eof()?.token_type.unwrap() != TokenType::TK_WHEN {
Some(self.parse_expr(0)?)
} else {
None
};
self.eat_expect(&[TokenType::TK_WHEN])?;
let first_when = self.parse_expr(0)?;
self.eat_expect(&[TokenType::TK_THEN])?;
let mut when_then_pairs = vec![(first_when, self.parse_expr(0)?)];
loop {
if let Some(tok) = self.peek()? {
if tok.token_type.unwrap() != TokenType::TK_WHEN {
break;
}
} else {
break;
}
self.eat_assert(&[TokenType::TK_WHEN]);
let when = self.parse_expr(0)?;
self.eat_expect(&[TokenType::TK_THEN])?;
let then = self.parse_expr(0)?;
when_then_pairs.push((when, then));
}
let else_expr = if let Some(ok) = self.peek()? {
if ok.token_type == Some(TokenType::TK_ELSE) {
self.eat_assert(&[TokenType::TK_ELSE]);
Some(self.parse_expr(0)?)
} else {
None
}
} else {
None
};
self.eat_expect(&[TokenType::TK_END])?;
Ok(Box::new(Expr::Case {
base,
when_then_pairs,
else_expr,
}))
}
TokenType::TK_RAISE => {
self.eat_assert(&[TokenType::TK_RAISE]);
self.eat_expect(&[TokenType::TK_LP])?;
let resolve = match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_IGNORE => {
self.eat_assert(&[TokenType::TK_IGNORE]);
ResolveType::Ignore
}
_ => self.parse_raise_type()?,
};
let expr = if resolve != ResolveType::Ignore {
self.eat_expect(&[TokenType::TK_COMMA])?;
Some(self.parse_expr(0)?)
} else {
None
};
self.eat_expect(&[TokenType::TK_RP])?;
Ok(Box::new(Expr::Raise(resolve, expr)))
}
_ => {
let can_be_lit_str = tok.token_type == Some(TokenType::TK_STRING);
let name = self.parse_nm()?;
let second_name = if let Some(tok) = self.peek()? {
if tok.token_type == Some(TokenType::TK_DOT) {
self.eat_assert(&[TokenType::TK_DOT]);
Some(self.parse_nm()?)
} else if tok.token_type == Some(TokenType::TK_LP) {
if can_be_lit_str {
return Err(Error::ParseUnexpectedToken {
parsed_offset: (self.lexer.offset, 1).into(),
got: TokenType::TK_STRING,
expected: &[
TokenType::TK_ID,
TokenType::TK_INDEXED,
TokenType::TK_JOIN_KW,
],
});
} // can not be literal string in function name
self.eat_assert(&[TokenType::TK_LP]);
let tok = self.peek_no_eof()?;
match tok.token_type.unwrap() {
TokenType::TK_STAR => {
self.eat_assert(&[TokenType::TK_STAR]);
self.eat_expect(&[TokenType::TK_RP])?;
return Ok(Box::new(Expr::FunctionCallStar {
name: name,
filter_over: self.parse_filter_over()?,
}));
}
_ => {
let distinct = self.parse_distinct()?;
let exprs = self.parse_expr_list()?;
self.eat_expect(&[TokenType::TK_RP])?;
let order_by = self.parse_order_by()?;
let filter_over = self.parse_filter_over()?;
return Ok(Box::new(Expr::FunctionCall {
name,
distinctness: distinct,
args: exprs,
order_by,
filter_over,
}));
}
}
} else {
None
}
} else {
None
};
let third_name = if let Some(tok) = self.peek()? {
if tok.token_type == Some(TokenType::TK_DOT) {
debug_assert!(second_name.is_some());
self.eat_assert(&[TokenType::TK_DOT]);
Some(self.parse_nm()?)
} else {
None
}
} else {
None
};
if second_name.is_some() && third_name.is_some() {
Ok(Box::new(Expr::DoublyQualified(
name,
second_name.unwrap(),
third_name.unwrap(),
)))
} else if second_name.is_some() {
Ok(Box::new(Expr::Qualified(name, second_name.unwrap())))
} else if can_be_lit_str {
Ok(Box::new(Expr::Literal(match name {
Name::Quoted(s) => Literal::String(s),
Name::Ident(s) => Literal::String(s),
})))
} else {
Ok(Box::new(Expr::Id(name)))
}
}
}
}
fn parse_expr_list(&mut self) -> Result<Vec<Box<Expr>>, Error> {
let mut exprs = vec![];
loop {
match self.peek()? {
Some(tok) => match tok.token_type.unwrap().fallback_id_if_ok() {
TokenType::TK_LP
| TokenType::TK_CAST
| TokenType::TK_ID
| TokenType::TK_STRING
| TokenType::TK_INDEXED
| TokenType::TK_JOIN_KW
| TokenType::TK_NULL
| TokenType::TK_BLOB
| TokenType::TK_FLOAT
| TokenType::TK_INTEGER
| TokenType::TK_VARIABLE
| TokenType::TK_CTIME_KW
| TokenType::TK_NOT
| TokenType::TK_BITNOT
| TokenType::TK_PLUS
| TokenType::TK_MINUS
| TokenType::TK_EXISTS
| TokenType::TK_CASE => {}
_ => break,
},
None => break,
}
exprs.push(self.parse_expr(0)?);
match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_COMMA => {
self.eat_assert(&[TokenType::TK_COMMA]);
}
_ => break,
}
}
Ok(exprs)
}
fn parse_expr(&mut self, precedence: u8) -> Result<Box<Expr>, Error> {
let mut result = self.parse_expr_operand()?;
loop {
let pre = match self.current_token_precedence()? {
Some(pre) if pre < precedence => break,
None => break, // no more ops
Some(pre) => pre,
};
let mut tok = self.peek_no_eof()?;
let mut not = false;
if tok.token_type.unwrap() == TokenType::TK_NOT {
self.eat_assert(&[TokenType::TK_NOT]);
tok = self.peek_expect(&[
TokenType::TK_BETWEEN,
TokenType::TK_IN,
TokenType::TK_MATCH,
TokenType::TK_LIKE_KW,
])?;
not = true;
}
result = match tok.token_type.unwrap() {
TokenType::TK_OR => {
self.eat_assert(&[TokenType::TK_OR]);
Box::new(Expr::Binary(result, Operator::Or, self.parse_expr(pre)?))
}
TokenType::TK_AND => {
self.eat_assert(&[TokenType::TK_AND]);
Box::new(Expr::Binary(result, Operator::And, self.parse_expr(pre)?))
}
TokenType::TK_EQ => {
self.eat_assert(&[TokenType::TK_EQ]);
Box::new(Expr::Binary(
result,
Operator::Equals,
self.parse_expr(pre)?,
))
}
TokenType::TK_NE => {
self.eat_assert(&[TokenType::TK_NE]);
Box::new(Expr::Binary(
result,
Operator::NotEquals,
self.parse_expr(pre)?,
))
}
TokenType::TK_BETWEEN => {
self.eat_assert(&[TokenType::TK_BETWEEN]);
let start = self.parse_expr(pre)?;
self.eat_expect(&[TokenType::TK_AND])?;
let end = self.parse_expr(pre)?;
Box::new(Expr::Between {
lhs: result,
not,
start,
end,
})
}
TokenType::TK_IN => {
self.eat_assert(&[TokenType::TK_IN]);
let tok = self.peek_no_eof()?;
match tok.token_type.unwrap() {
TokenType::TK_LP => {
self.eat_assert(&[TokenType::TK_LP]);
let tok = self.peek_no_eof()?;
match tok.token_type.unwrap() {
TokenType::TK_SELECT
| TokenType::TK_WITH
| TokenType::TK_VALUES => {
let select = self.parse_select()?;
self.eat_expect(&[TokenType::TK_RP])?;
Box::new(Expr::InSelect {
lhs: result,
not,
rhs: select,
})
}
_ => {
let exprs = self.parse_expr_list()?;
self.eat_expect(&[TokenType::TK_RP])?;
Box::new(Expr::InList {
lhs: result,
not,
rhs: exprs,
})
}
}
}
_ => {
let name = self.parse_fullname(false)?;
let mut exprs = vec![];
if let Some(tok) = self.peek()? {
if tok.token_type == Some(TokenType::TK_LP) {
self.eat_assert(&[TokenType::TK_LP]);
exprs = self.parse_expr_list()?;
self.eat_expect(&[TokenType::TK_RP])?;
}
}
Box::new(Expr::InTable {
lhs: result,
not,
rhs: name,
args: exprs,
})
}
}
}
TokenType::TK_MATCH | TokenType::TK_LIKE_KW => {
let tok = self.eat_assert(&[TokenType::TK_MATCH, TokenType::TK_LIKE_KW]);
let op = match tok.token_type.unwrap() {
TokenType::TK_MATCH => LikeOperator::Match,
TokenType::TK_LIKE_KW => {
if b"LIKE".eq_ignore_ascii_case(tok.value) {
LikeOperator::Like
} else if b"GLOB".eq_ignore_ascii_case(tok.value) {
LikeOperator::Glob
} else if b"REGEXP".eq_ignore_ascii_case(tok.value) {
LikeOperator::Regexp
} else {
unreachable!()
}
}
_ => unreachable!(),
};
let expr = self.parse_expr(pre)?;
let escape = if let Some(tok) = self.peek()? {
if tok.token_type == Some(TokenType::TK_ESCAPE) {
self.eat_assert(&[TokenType::TK_ESCAPE]);
Some(self.parse_expr(pre)?)
} else {
None
}
} else {
None
};
Box::new(Expr::Like {
lhs: result,
not,
op,
rhs: expr,
escape,
})
}
TokenType::TK_ISNULL => {
self.eat_assert(&[TokenType::TK_ISNULL]);
Box::new(Expr::IsNull(result))
}
TokenType::TK_NOTNULL => {
self.eat_assert(&[TokenType::TK_NOTNULL]);
Box::new(Expr::NotNull(result))
}
TokenType::TK_LT => {
self.eat_assert(&[TokenType::TK_LT]);
Box::new(Expr::Binary(result, Operator::Less, self.parse_expr(pre)?))
}
TokenType::TK_GT => {
self.eat_assert(&[TokenType::TK_GT]);
Box::new(Expr::Binary(
result,
Operator::Greater,
self.parse_expr(pre)?,
))
}
TokenType::TK_LE => {
self.eat_assert(&[TokenType::TK_LE]);
Box::new(Expr::Binary(
result,
Operator::LessEquals,
self.parse_expr(pre)?,
))
}
TokenType::TK_GE => {
self.eat_assert(&[TokenType::TK_GE]);
Box::new(Expr::Binary(
result,
Operator::GreaterEquals,
self.parse_expr(pre)?,
))
}
TokenType::TK_ESCAPE => unreachable!(),
TokenType::TK_BITAND => {
self.eat_assert(&[TokenType::TK_BITAND]);
Box::new(Expr::Binary(
result,
Operator::BitwiseAnd,
self.parse_expr(pre)?,
))
}
TokenType::TK_BITOR => {
self.eat_assert(&[TokenType::TK_BITOR]);
Box::new(Expr::Binary(
result,
Operator::BitwiseOr,
self.parse_expr(pre)?,
))
}
TokenType::TK_LSHIFT => {
self.eat_assert(&[TokenType::TK_LSHIFT]);
Box::new(Expr::Binary(
result,
Operator::LeftShift,
self.parse_expr(pre)?,
))
}
TokenType::TK_RSHIFT => {
self.eat_assert(&[TokenType::TK_RSHIFT]);
Box::new(Expr::Binary(
result,
Operator::RightShift,
self.parse_expr(pre)?,
))
}
TokenType::TK_PLUS => {
self.eat_assert(&[TokenType::TK_PLUS]);
Box::new(Expr::Binary(result, Operator::Add, self.parse_expr(pre)?))
}
TokenType::TK_MINUS => {
self.eat_assert(&[TokenType::TK_MINUS]);
Box::new(Expr::Binary(
result,
Operator::Subtract,
self.parse_expr(pre)?,
))
}
TokenType::TK_STAR => {
self.eat_assert(&[TokenType::TK_STAR]);
Box::new(Expr::Binary(
result,
Operator::Multiply,
self.parse_expr(pre)?,
))
}
TokenType::TK_SLASH => {
self.eat_assert(&[TokenType::TK_SLASH]);
Box::new(Expr::Binary(
result,
Operator::Divide,
self.parse_expr(pre)?,
))
}
TokenType::TK_REM => {
self.eat_assert(&[TokenType::TK_REM]);
Box::new(Expr::Binary(
result,
Operator::Modulus,
self.parse_expr(pre)?,
))
}
TokenType::TK_CONCAT => {
self.eat_assert(&[TokenType::TK_CONCAT]);
Box::new(Expr::Binary(
result,
Operator::Concat,
self.parse_expr(pre)?,
))
}
TokenType::TK_PTR => {
let tok = self.eat_assert(&[TokenType::TK_PTR]);
let op = if tok.value.len() == 2 {
Operator::ArrowRight
} else {
Operator::ArrowRightShift
};
Box::new(Expr::Binary(result, op, self.parse_expr(pre)?))
}
TokenType::TK_COLLATE => {
Box::new(Expr::Collate(result, self.parse_collate()?.unwrap()))
}
_ => unreachable!(),
}
}
Ok(result)
}
fn parse_collate(&mut self) -> Result<Option<Name>, Error> {
if let Some(tok) = self.peek()? {
if tok.token_type == Some(TokenType::TK_COLLATE) {
self.eat_assert(&[TokenType::TK_COLLATE]);
} else {
return Ok(None);
}
} else {
return Ok(None);
}
let tok = self.eat_expect(&[TokenType::TK_ID, TokenType::TK_STRING])?;
let first_char = tok.value[0]; // no need to check empty
match first_char {
b'[' | b'\'' | b'`' | b'"' => Ok(Some(Name::Quoted(from_bytes(tok.value)))),
_ => Ok(Some(Name::Ident(from_bytes(tok.value)))),
}
}
fn parse_sort_order(&mut self) -> Result<Option<SortOrder>, Error> {
match self.peek()? {
Some(tok) if tok.token_type == Some(TokenType::TK_ASC) => {
self.eat_assert(&[TokenType::TK_ASC]);
Ok(Some(SortOrder::Asc))
}
Some(tok) if tok.token_type == Some(TokenType::TK_DESC) => {
self.eat_assert(&[TokenType::TK_DESC]);
Ok(Some(SortOrder::Desc))
}
_ => Ok(None),
}
}
fn parse_eid(&mut self) -> Result<IndexedColumn, Error> {
let nm = self.parse_nm()?;
let collate = self.parse_collate()?;
let sort_order = self.parse_sort_order()?;
Ok(IndexedColumn {
col_name: nm,
collation_name: collate,
order: sort_order,
})
}
fn parse_eid_list(&mut self) -> Result<Vec<IndexedColumn>, Error> {
if let Some(tok) = self.peek()? {
if tok.token_type == Some(TokenType::TK_LP) {
self.eat_assert(&[TokenType::TK_LP]);
} else {
return Ok(vec![]);
}
} else {
return Ok(vec![]);
}
let mut columns = vec![self.parse_eid()?];
loop {
match self.peek()? {
Some(tok) if tok.token_type == Some(TokenType::TK_COMMA) => {
self.eat_assert(&[TokenType::TK_COMMA]);
columns.push(self.parse_eid()?);
}
_ => break,
}
}
self.eat_expect(&[TokenType::TK_RP])?;
Ok(columns)
}
fn parse_common_table_expr(&mut self) -> Result<CommonTableExpr, Error> {
let nm = self.parse_nm()?;
let eid_list = self.parse_eid_list()?;
self.eat_expect(&[TokenType::TK_AS])?;
let wqas = match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_MATERIALIZED => {
self.eat_assert(&[TokenType::TK_MATERIALIZED]);
Materialized::Yes
}
TokenType::TK_NOT => {
self.eat_assert(&[TokenType::TK_NOT]);
self.eat_expect(&[TokenType::TK_MATERIALIZED])?;
Materialized::No
}
_ => Materialized::Any,
};
self.eat_expect(&[TokenType::TK_LP])?;
let select = self.parse_select()?;
self.eat_expect(&[TokenType::TK_RP])?;
Ok(CommonTableExpr {
tbl_name: nm,
columns: eid_list,
materialized: wqas,
select,
})
}
fn parse_with(&mut self) -> Result<Option<With>, Error> {
if let Some(tok) = self.peek()? {
if tok.token_type == Some(TokenType::TK_WITH) {
self.eat_assert(&[TokenType::TK_WITH]);
} else {
return Ok(None);
}
} else {
return Ok(None);
}
let recursive = if self.peek_no_eof()?.token_type == Some(TokenType::TK_RECURSIVE) {
self.eat_assert(&[TokenType::TK_RECURSIVE]);
true
} else {
false
};
let mut ctes = vec![self.parse_common_table_expr()?];
loop {
match self.peek()? {
Some(tok) if tok.token_type == Some(TokenType::TK_COMMA) => {
self.eat_assert(&[TokenType::TK_COMMA]);
ctes.push(self.parse_common_table_expr()?);
}
_ => break,
}
}
Ok(Some(With { recursive, ctes }))
}
fn parse_as(&mut self) -> Result<Option<As>, Error> {
match self.peek()? {
None => Ok(None),
Some(tok) => match tok.token_type.unwrap().fallback_id_if_ok() {
TokenType::TK_AS => {
self.eat_assert(&[TokenType::TK_AS]);
Ok(Some(As::As(self.parse_nm()?)))
}
TokenType::TK_STRING | TokenType::TK_ID => Ok(Some(As::Elided(self.parse_nm()?))),
_ => Ok(None),
},
}
}
fn parse_window_defn(&mut self) -> Result<WindowDef, Error> {
let name = self.parse_nm()?;
self.eat_expect(&[TokenType::TK_AS])?;
self.eat_expect(&[TokenType::TK_LP])?;
let window = self.parse_window()?;
self.eat_expect(&[TokenType::TK_RP])?;
Ok(WindowDef { name, window })
}
fn parse_window_clause(&mut self) -> Result<Vec<WindowDef>, Error> {
match self.peek()? {
None => return Ok(vec![]),
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_WINDOW => {
self.eat_assert(&[TokenType::TK_WINDOW]);
}
_ => return Ok(vec![]),
},
}
let mut result = vec![self.parse_window_defn()?];
loop {
match self.peek()? {
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_COMMA => {
self.eat_assert(&[TokenType::TK_COMMA]);
result.push(self.parse_window_defn()?);
}
_ => break,
},
_ => break,
}
}
Ok(result)
}
fn parse_group_by(&mut self) -> Result<Option<GroupBy>, Error> {
match self.peek()? {
None => return Ok(None),
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_GROUP => {
self.eat_assert(&[TokenType::TK_GROUP]);
self.eat_expect(&[TokenType::TK_BY])?;
}
_ => return Ok(None),
},
}
let exprs = self.parse_nexpr_list()?;
let having = match self.peek()? {
Some(tok) if tok.token_type == Some(TokenType::TK_HAVING) => {
self.eat_assert(&[TokenType::TK_HAVING]);
Some(self.parse_expr(0)?)
}
_ => None,
};
Ok(Some(GroupBy { exprs, having }))
}
fn parse_where(&mut self) -> Result<Option<Box<Expr>>, Error> {
match self.peek()? {
None => Ok(None),
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_WHERE => {
self.eat_assert(&[TokenType::TK_WHERE]);
let expr = self.parse_expr(0)?;
Ok(Some(expr))
}
_ => Ok(None),
},
}
}
fn parse_indexed(&mut self) -> Result<Option<Indexed>, Error> {
match self.peek()? {
None => Ok(None),
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_INDEXED => {
self.eat_assert(&[TokenType::TK_INDEXED]);
self.eat_expect(&[TokenType::TK_BY])?;
Ok(Some(Indexed::IndexedBy(self.parse_nm()?)))
}
TokenType::TK_NOT => {
self.eat_assert(&[TokenType::TK_NOT]);
self.eat_expect(&[TokenType::TK_INDEXED])?;
Ok(Some(Indexed::NotIndexed))
}
_ => Ok(None),
},
}
}
fn parse_nm_list(&mut self) -> Result<Vec<Name>, Error> {
let mut names = vec![self.parse_nm()?];
loop {
match self.peek()? {
Some(tok) if tok.token_type == Some(TokenType::TK_COMMA) => {
self.eat_assert(&[TokenType::TK_COMMA]);
names.push(self.parse_nm()?);
}
_ => break,
}
}
Ok(names)
}
fn parse_nm_list_opt(&mut self) -> Result<Vec<Name>, Error> {
match self.peek()? {
Some(tok) if tok.token_type == Some(TokenType::TK_LP) => {
self.eat_assert(&[TokenType::TK_LP]);
}
_ => return Ok(vec![]),
}
let result = self.parse_nm_list()?;
self.eat_expect(&[TokenType::TK_RP])?;
Ok(result)
}
fn parse_on_using(&mut self) -> Result<Option<JoinConstraint>, Error> {
match self.peek()? {
None => Ok(None),
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_ON => {
self.eat_assert(&[TokenType::TK_ON]);
let expr = self.parse_expr(0)?;
Ok(Some(JoinConstraint::On(expr)))
}
TokenType::TK_USING => {
self.eat_assert(&[TokenType::TK_USING]);
self.eat_expect(&[TokenType::TK_LP])?;
let names = self.parse_nm_list()?;
self.eat_expect(&[TokenType::TK_RP])?;
Ok(Some(JoinConstraint::Using(names)))
}
_ => Ok(None),
},
}
}
fn parse_joined_tables(&mut self) -> Result<Vec<JoinedSelectTable>, Error> {
let mut result = vec![];
loop {
let op = match self.peek()? {
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_COMMA => {
self.eat_assert(&[TokenType::TK_COMMA]);
JoinOperator::Comma
}
TokenType::TK_JOIN => {
self.eat_assert(&[TokenType::TK_JOIN]);
JoinOperator::TypedJoin(None)
}
TokenType::TK_JOIN_KW => {
let jkw = self.eat_assert(&[TokenType::TK_JOIN_KW]);
let tok = self.eat_expect(&[
TokenType::TK_JOIN,
TokenType::TK_ID,
TokenType::TK_STRING,
TokenType::TK_INDEXED,
TokenType::TK_JOIN_KW,
])?;
match tok.token_type.unwrap() {
TokenType::TK_JOIN => {
JoinOperator::TypedJoin(Some(new_join_type(jkw.value, None, None)?))
}
_ => {
let name_1 = tok.value;
let tok = self.eat_expect(&[
TokenType::TK_JOIN,
TokenType::TK_ID,
TokenType::TK_STRING,
TokenType::TK_INDEXED,
TokenType::TK_JOIN_KW,
])?;
match tok.token_type.unwrap() {
TokenType::TK_JOIN => JoinOperator::TypedJoin(Some(
new_join_type(jkw.value, Some(name_1), None)?,
)),
_ => {
let name_2 = tok.value;
self.eat_expect(&[TokenType::TK_JOIN])?;
JoinOperator::TypedJoin(Some(new_join_type(
jkw.value,
Some(name_1),
Some(name_2),
)?))
}
}
}
}
}
_ => break,
},
None => break,
};
let tok = self.peek_expect(&[
TokenType::TK_ID,
TokenType::TK_STRING,
TokenType::TK_INDEXED,
TokenType::TK_JOIN_KW,
TokenType::TK_LP,
])?;
match tok.token_type.unwrap().fallback_id_if_ok() {
TokenType::TK_ID
| TokenType::TK_STRING
| TokenType::TK_INDEXED
| TokenType::TK_JOIN_KW => {
let name = self.parse_fullname(false)?;
match self.peek()? {
None => {
result.push(JoinedSelectTable {
operator: op,
table: Box::new(SelectTable::Table(name, None, None)),
constraint: None,
});
}
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_LP => {
self.eat_assert(&[TokenType::TK_LP]);
let exprs = self.parse_expr_list()?;
self.eat_assert(&[TokenType::TK_RP]);
let alias = self.parse_as()?;
let on_using = self.parse_on_using()?;
result.push(JoinedSelectTable {
operator: op,
table: Box::new(SelectTable::TableCall(name, exprs, alias)),
constraint: on_using,
});
}
_ => {
let alias = self.parse_as()?;
let indexed = self.parse_indexed()?;
let on_using = self.parse_on_using()?;
result.push(JoinedSelectTable {
operator: op,
table: Box::new(SelectTable::Table(name, alias, indexed)),
constraint: on_using,
});
}
},
}
}
TokenType::TK_LP => {
self.eat_assert(&[TokenType::TK_LP]);
match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_SELECT | TokenType::TK_WITH | TokenType::TK_VALUES => {
let select = self.parse_select()?;
self.eat_expect(&[TokenType::TK_RP])?;
let alias = self.parse_as()?;
let on_using = self.parse_on_using()?;
result.push(JoinedSelectTable {
operator: op,
table: Box::new(SelectTable::Select(select, alias)),
constraint: on_using,
});
}
_ => {
let fr = self.parse_from_clause()?;
self.eat_expect(&[TokenType::TK_RP])?;
let alias = self.parse_as()?;
let on_using = self.parse_on_using()?;
result.push(JoinedSelectTable {
operator: op,
table: Box::new(SelectTable::Sub(fr, alias)),
constraint: on_using,
});
}
}
}
_ => unreachable!(),
}
}
Ok(result)
}
fn parse_from_clause(&mut self) -> Result<FromClause, Error> {
let tok = self.peek_expect(&[
TokenType::TK_ID,
TokenType::TK_STRING,
TokenType::TK_INDEXED,
TokenType::TK_JOIN_KW,
TokenType::TK_LP,
])?;
match tok.token_type.unwrap().fallback_id_if_ok() {
TokenType::TK_ID
| TokenType::TK_STRING
| TokenType::TK_INDEXED
| TokenType::TK_JOIN_KW => {
let name = self.parse_fullname(false)?;
match self.peek()? {
None => Ok(FromClause {
select: Box::new(SelectTable::Table(name, None, None)),
joins: vec![],
}),
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_LP => {
self.eat_assert(&[TokenType::TK_LP]);
let exprs = self.parse_expr_list()?;
self.eat_assert(&[TokenType::TK_RP]);
let alias = self.parse_as()?;
Ok(FromClause {
select: Box::new(SelectTable::TableCall(name, exprs, alias)),
joins: self.parse_joined_tables()?,
})
}
_ => {
let alias = self.parse_as()?;
let indexed = self.parse_indexed()?;
Ok(FromClause {
select: Box::new(SelectTable::Table(name, alias, indexed)),
joins: self.parse_joined_tables()?,
})
}
},
}
}
TokenType::TK_LP => {
self.eat_assert(&[TokenType::TK_LP]);
match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_SELECT | TokenType::TK_WITH | TokenType::TK_VALUES => {
let select = self.parse_select()?;
self.eat_expect(&[TokenType::TK_RP])?;
let alias = self.parse_as()?;
Ok(FromClause {
select: Box::new(SelectTable::Select(select, alias)),
joins: self.parse_joined_tables()?,
})
}
_ => {
let fr = self.parse_from_clause()?;
self.eat_expect(&[TokenType::TK_RP])?;
let alias = self.parse_as()?;
Ok(FromClause {
select: Box::new(SelectTable::Sub(fr, alias)),
joins: self.parse_joined_tables()?,
})
}
}
}
_ => unreachable!(),
}
}
fn parse_from_clause_opt(&mut self) -> Result<Option<FromClause>, Error> {
match self.peek()? {
None => return Ok(None),
Some(tok) if tok.token_type == Some(TokenType::TK_FROM) => {
self.eat_assert(&[TokenType::TK_FROM]);
}
_ => return Ok(None),
}
Ok(Some(self.parse_from_clause()?))
}
fn parse_select_column(&mut self) -> Result<ResultColumn, Error> {
match self.peek_no_eof()?.token_type.unwrap().fallback_id_if_ok() {
TokenType::TK_STAR => {
self.eat_assert(&[TokenType::TK_STAR]);
Ok(ResultColumn::Star)
}
tt => {
// dot STAR case
if tt == TokenType::TK_ID
|| tt == TokenType::TK_STRING
|| tt == TokenType::TK_INDEXED
|| tt == TokenType::TK_JOIN_KW
{
if let Ok(res) = self.mark(|p| -> Result<ResultColumn, Error> {
let name = p.parse_nm()?;
p.eat_expect(&[TokenType::TK_DOT])?;
p.eat_expect(&[TokenType::TK_STAR])?;
Ok(ResultColumn::TableStar(name))
}) {
return Ok(res);
}
}
let expr = self.parse_expr(0)?;
let alias = self.parse_as()?;
Ok(ResultColumn::Expr(expr, alias))
}
}
}
fn parse_select_columns(&mut self) -> Result<Vec<ResultColumn>, Error> {
let mut result = vec![self.parse_select_column()?];
loop {
if let Some(tok) = self.peek()? {
if tok.token_type == Some(TokenType::TK_COMMA) {
self.eat_assert(&[TokenType::TK_COMMA]);
} else {
break;
}
} else {
break;
}
result.push(self.parse_select_column()?);
}
Ok(result)
}
fn parse_nexpr_list(&mut self) -> Result<Vec<Box<Expr>>, Error> {
let mut result = vec![self.parse_expr(0)?];
loop {
if let Some(tok) = self.peek()? {
if tok.token_type == Some(TokenType::TK_COMMA) {
self.eat_assert(&[TokenType::TK_COMMA]);
} else {
break;
}
} else {
break;
}
result.push(self.parse_expr(0)?);
}
Ok(result)
}
fn parse_one_select(&mut self) -> Result<OneSelect, Error> {
let tok = self.eat_expect(&[TokenType::TK_SELECT, TokenType::TK_VALUES])?;
match tok.token_type.unwrap() {
TokenType::TK_SELECT => {
let distinct = self.parse_distinct()?;
let collist = self.parse_select_columns()?;
let from = self.parse_from_clause_opt()?;
let where_clause = self.parse_where()?;
let group_by = self.parse_group_by()?;
let window_clause = self.parse_window_clause()?;
Ok(OneSelect::Select {
distinctness: distinct,
columns: collist,
from,
where_clause,
group_by,
window_clause,
})
}
TokenType::TK_VALUES => {
self.eat_expect(&[TokenType::TK_LP])?;
let mut values = vec![self.parse_nexpr_list()?];
self.eat_expect(&[TokenType::TK_RP])?;
loop {
if let Some(tok) = self.peek()? {
if tok.token_type == Some(TokenType::TK_COMMA) {
self.eat_assert(&[TokenType::TK_COMMA]);
} else {
break;
}
} else {
break;
}
self.eat_expect(&[TokenType::TK_LP])?;
values.push(self.parse_nexpr_list()?);
self.eat_expect(&[TokenType::TK_RP])?;
}
Ok(OneSelect::Values(values))
}
_ => unreachable!(),
}
}
fn parse_select_body(&mut self) -> Result<SelectBody, Error> {
let select = self.parse_one_select()?;
let mut compounds = vec![];
loop {
let op = match self.peek()? {
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_UNION => {
self.eat_assert(&[TokenType::TK_UNION]);
if self.peek_no_eof()?.token_type == Some(TokenType::TK_ALL) {
self.eat_assert(&[TokenType::TK_ALL]);
CompoundOperator::UnionAll
} else {
CompoundOperator::Union
}
}
TokenType::TK_EXCEPT => {
self.eat_assert(&[TokenType::TK_EXCEPT]);
CompoundOperator::Except
}
TokenType::TK_INTERSECT => {
self.eat_assert(&[TokenType::TK_INTERSECT]);
CompoundOperator::Intersect
}
_ => break,
},
None => break,
};
compounds.push(CompoundSelect {
operator: op,
select: self.parse_one_select()?,
});
}
Ok(SelectBody { select, compounds })
}
fn parse_sorted_column(&mut self) -> Result<SortedColumn, Error> {
let expr = self.parse_expr(0)?;
let sort_order = self.parse_sort_order()?;
let nulls = match self.peek()? {
Some(tok) if tok.token_type == Some(TokenType::TK_NULLS) => {
self.eat_assert(&[TokenType::TK_NULLS]);
let tok = self.eat_expect(&[TokenType::TK_FIRST, TokenType::TK_LAST])?;
match tok.token_type.unwrap() {
TokenType::TK_FIRST => Some(NullsOrder::First),
TokenType::TK_LAST => Some(NullsOrder::Last),
_ => unreachable!(),
}
}
_ => None,
};
Ok(SortedColumn {
expr,
order: sort_order,
nulls,
})
}
fn parse_sort_list(&mut self) -> Result<Vec<SortedColumn>, Error> {
let mut columns = vec![self.parse_sorted_column()?];
loop {
match self.peek()? {
Some(tok) if tok.token_type == Some(TokenType::TK_COMMA) => {
self.eat_assert(&[TokenType::TK_COMMA]);
columns.push(self.parse_sorted_column()?);
}
_ => break,
}
}
Ok(columns)
}
fn parse_order_by(&mut self) -> Result<Vec<SortedColumn>, Error> {
if let Some(tok) = self.peek()? {
if tok.token_type == Some(TokenType::TK_ORDER) {
self.eat_assert(&[TokenType::TK_ORDER]);
} else {
return Ok(vec![]);
}
} else {
return Ok(vec![]);
}
self.eat_expect(&[TokenType::TK_BY])?;
Ok(self.parse_sort_list()?)
}
fn parse_limit(&mut self) -> Result<Option<Limit>, Error> {
if let Some(tok) = self.peek()? {
if tok.token_type == Some(TokenType::TK_LIMIT) {
self.eat_assert(&[TokenType::TK_LIMIT]);
} else {
return Ok(None);
}
} else {
return Ok(None);
}
let limit = self.parse_expr(0)?;
let offset = match self.peek()? {
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_OFFSET | TokenType::TK_COMMA => {
self.eat_assert(&[TokenType::TK_OFFSET, TokenType::TK_COMMA]);
Some(self.parse_expr(0)?)
}
_ => None,
},
_ => None,
};
Ok(Some(Limit {
expr: limit,
offset,
}))
}
fn parse_select_without_cte(&mut self, with: Option<With>) -> Result<Select, Error> {
let body = self.parse_select_body()?;
let order_by = self.parse_order_by()?;
let limit = self.parse_limit()?;
Ok(Select {
with,
body,
order_by,
limit,
})
}
fn parse_select(&mut self) -> Result<Select, Error> {
let with = self.parse_with()?;
self.parse_select_without_cte(with)
}
fn parse_primary_table_constraint(&mut self) -> Result<TableConstraint, Error> {
self.eat_assert(&[TokenType::TK_PRIMARY]);
self.eat_expect(&[TokenType::TK_KEY])?;
self.eat_expect(&[TokenType::TK_LP])?;
let columns = self.parse_sort_list()?;
let auto_increment = self.parse_auto_increment()?;
self.eat_expect(&[TokenType::TK_RP])?;
let conflict_clause = self.parse_on_conflict()?;
Ok(TableConstraint::PrimaryKey {
columns,
auto_increment,
conflict_clause,
})
}
fn parse_unique_table_constraint(&mut self) -> Result<TableConstraint, Error> {
self.eat_assert(&[TokenType::TK_UNIQUE]);
self.eat_expect(&[TokenType::TK_LP])?;
let columns = self.parse_sort_list()?;
self.eat_expect(&[TokenType::TK_RP])?;
let conflict_clause = self.parse_on_conflict()?;
Ok(TableConstraint::Unique {
columns,
conflict_clause,
})
}
fn parse_check_table_constraint(&mut self) -> Result<TableConstraint, Error> {
self.eat_assert(&[TokenType::TK_CHECK]);
self.eat_expect(&[TokenType::TK_LP])?;
let expr = self.parse_expr(0)?;
self.eat_expect(&[TokenType::TK_RP])?;
Ok(TableConstraint::Check(expr))
}
fn parse_foreign_key_table_constraint(&mut self) -> Result<TableConstraint, Error> {
self.eat_assert(&[TokenType::TK_FOREIGN]);
self.eat_expect(&[TokenType::TK_KEY])?;
self.peek_expect(&[TokenType::TK_LP])?; // make sure we have columns
let columns = self.parse_eid_list()?;
self.peek_expect(&[TokenType::TK_REFERENCES])?;
let clause = self.parse_foreign_key_clause()?;
let deref_clause = self.parse_defer_subclause()?;
Ok(TableConstraint::ForeignKey {
columns,
clause,
deref_clause,
})
}
fn parse_named_table_constraints(&mut self) -> Result<Vec<NamedTableConstraint>, Error> {
let mut result = vec![];
loop {
match self.peek()? {
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_COMMA => {
self.eat_assert(&[TokenType::TK_COMMA]);
}
TokenType::TK_CONSTRAINT
| TokenType::TK_PRIMARY
| TokenType::TK_UNIQUE
| TokenType::TK_CHECK
| TokenType::TK_FOREIGN => {}
_ => break,
},
_ => break,
}
let name = match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_CONSTRAINT => {
self.eat_assert(&[TokenType::TK_CONSTRAINT]);
Some(self.parse_nm()?)
}
_ => None,
};
let tok = self.peek_expect(&[
TokenType::TK_PRIMARY,
TokenType::TK_UNIQUE,
TokenType::TK_CHECK,
TokenType::TK_FOREIGN,
])?;
match tok.token_type.unwrap() {
TokenType::TK_PRIMARY => {
result.push(NamedTableConstraint {
name,
constraint: self.parse_primary_table_constraint()?,
});
}
TokenType::TK_UNIQUE => {
result.push(NamedTableConstraint {
name,
constraint: self.parse_unique_table_constraint()?,
});
}
TokenType::TK_CHECK => {
result.push(NamedTableConstraint {
name,
constraint: self.parse_check_table_constraint()?,
});
}
TokenType::TK_FOREIGN => {
result.push(NamedTableConstraint {
name,
constraint: self.parse_foreign_key_table_constraint()?,
});
}
_ => unreachable!(),
}
}
Ok(result)
}
fn parse_table_option(&mut self) -> Result<TableOptions, Error> {
match self.peek()? {
Some(tok) => match tok.token_type.unwrap().fallback_id_if_ok() {
TokenType::TK_WITHOUT => {
self.eat_assert(&[TokenType::TK_WITHOUT]);
let tok = self.eat_expect(&[TokenType::TK_ID])?;
if b"ROWID".eq_ignore_ascii_case(tok.value) {
Ok(TableOptions::WITHOUT_ROWID)
} else {
Err(Error::Custom(format!(
"unknown table option: {}",
from_bytes(tok.value)
)))
}
}
TokenType::TK_ID => {
let tok = self.eat_assert(&[TokenType::TK_ID]);
if b"STRICT".eq_ignore_ascii_case(tok.value) {
Ok(TableOptions::STRICT)
} else {
Err(Error::Custom(format!(
"unknown table option: {}",
from_bytes(tok.value)
)))
}
}
_ => Ok(TableOptions::NONE),
},
_ => Ok(TableOptions::NONE),
}
}
fn parse_table_options(&mut self) -> Result<TableOptions, Error> {
let mut result = self.parse_table_option()?;
loop {
match self.peek()? {
Some(tok) if tok.token_type == Some(TokenType::TK_COMMA) => {
self.eat_assert(&[TokenType::TK_COMMA]);
result = result | self.parse_table_option()?;
}
_ => break,
}
}
Ok(result)
}
fn parse_create_table_args(&mut self) -> Result<CreateTableBody, Error> {
let tok = self.eat_expect(&[TokenType::TK_LP, TokenType::TK_AS])?;
match tok.token_type.unwrap() {
TokenType::TK_AS => Ok(CreateTableBody::AsSelect(self.parse_select()?)),
TokenType::TK_LP => {
let mut columns = vec![self.parse_column_definition()?];
let mut constraints = vec![];
loop {
match self.peek()? {
Some(tok) if tok.token_type == Some(TokenType::TK_COMMA) => {
self.eat_assert(&[TokenType::TK_COMMA]);
match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_CONSTRAINT
| TokenType::TK_PRIMARY
| TokenType::TK_UNIQUE
| TokenType::TK_CHECK
| TokenType::TK_FOREIGN => {
constraints = self.parse_named_table_constraints()?;
break;
}
_ => {
columns.push(self.parse_column_definition()?);
}
}
}
_ => break,
}
}
self.eat_expect(&[TokenType::TK_RP])?;
let options = self.parse_table_options()?;
Ok(CreateTableBody::ColumnsAndConstraints {
columns,
constraints,
options,
})
}
_ => unreachable!(),
}
}
fn parse_create_table(&mut self, temporary: bool) -> Result<Stmt, Error> {
self.eat_assert(&[TokenType::TK_TABLE]);
let if_not_exists = self.parse_if_not_exists()?;
let tbl_name = self.parse_fullname(false)?;
let body = self.parse_create_table_args()?;
Ok(Stmt::CreateTable {
temporary,
if_not_exists,
tbl_name,
body,
})
}
fn parse_analyze(&mut self) -> Result<Stmt, Error> {
self.eat_assert(&[TokenType::TK_ANALYZE]);
let name = match self.peek()? {
Some(tok) => match tok.token_type.unwrap().fallback_id_if_ok() {
TokenType::TK_ID
| TokenType::TK_STRING
| TokenType::TK_INDEXED
| TokenType::TK_JOIN_KW => Some(self.parse_fullname(false)?),
_ => None,
},
_ => None,
};
Ok(Stmt::Analyze { name: name })
}
fn parse_attach(&mut self) -> Result<Stmt, Error> {
self.eat_assert(&[TokenType::TK_ATTACH]);
match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_DATABASE => {
self.eat_assert(&[TokenType::TK_DATABASE]);
}
_ => {}
}
let expr = self.parse_expr(0)?;
self.eat_expect(&[TokenType::TK_AS])?;
let db_name = self.parse_expr(0)?;
let key = match self.peek()? {
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_KEY => {
self.eat_assert(&[TokenType::TK_KEY]);
Some(self.parse_expr(0)?)
}
_ => None,
},
_ => None,
};
Ok(Stmt::Attach { expr, db_name, key })
}
fn parse_detach(&mut self) -> Result<Stmt, Error> {
self.eat_assert(&[TokenType::TK_DETACH]);
match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_DATABASE => {
self.eat_assert(&[TokenType::TK_DATABASE]);
}
_ => {}
}
Ok(Stmt::Detach {
name: self.parse_expr(0)?,
})
}
fn parse_pragma_value(&mut self) -> Result<PragmaValue, Error> {
match self.peek_no_eof()?.token_type.unwrap().fallback_id_if_ok() {
TokenType::TK_ON | TokenType::TK_DELETE | TokenType::TK_DEFAULT => {
let tok = self.eat_assert(&[
TokenType::TK_ON,
TokenType::TK_DELETE,
TokenType::TK_DEFAULT,
]);
Ok(Box::new(Expr::Literal(Literal::Keyword(from_bytes(
tok.value,
)))))
}
TokenType::TK_ID
| TokenType::TK_STRING
| TokenType::TK_INDEXED
| TokenType::TK_JOIN_KW => Ok(Box::new(Expr::Name(self.parse_nm()?))),
_ => self.parse_signed(),
}
}
fn parse_pragma(&mut self) -> Result<Stmt, Error> {
self.eat_assert(&[TokenType::TK_PRAGMA]);
let name = self.parse_fullname(false)?;
match self.peek()? {
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_EQ => {
self.eat_assert(&[TokenType::TK_EQ]);
Ok(Stmt::Pragma {
name: name,
body: Some(PragmaBody::Equals(self.parse_pragma_value()?)),
})
}
TokenType::TK_LP => {
self.eat_assert(&[TokenType::TK_LP]);
let value = self.parse_pragma_value()?;
self.eat_expect(&[TokenType::TK_RP])?;
Ok(Stmt::Pragma {
name: name,
body: Some(PragmaBody::Call(value)),
})
}
_ => Ok(Stmt::Pragma {
name: name,
body: None,
}),
},
_ => Ok(Stmt::Pragma {
name: name,
body: None,
}),
}
}
fn parse_vacuum(&mut self) -> Result<Stmt, Error> {
self.eat_assert(&[TokenType::TK_VACUUM]);
let name = match self.peek()? {
Some(tok) => match tok.token_type.unwrap().fallback_id_if_ok() {
TokenType::TK_ID
| TokenType::TK_STRING
| TokenType::TK_INDEXED
| TokenType::TK_JOIN_KW => Some(self.parse_nm()?),
_ => None,
},
_ => None,
};
let into = match self.peek()? {
Some(tok) if tok.token_type == Some(TokenType::TK_INTO) => {
self.eat_assert(&[TokenType::TK_INTO]);
Some(self.parse_expr(0)?)
}
_ => None,
};
Ok(Stmt::Vacuum { name, into })
}
fn parse_term(&mut self) -> Result<Box<Expr>, Error> {
self.peek_expect(&[
TokenType::TK_NULL,
TokenType::TK_BLOB,
TokenType::TK_STRING,
TokenType::TK_FLOAT,
TokenType::TK_INTEGER,
TokenType::TK_CTIME_KW,
])?;
self.parse_expr_operand()
}
fn parse_default_column_constraint(&mut self) -> Result<ColumnConstraint, Error> {
self.eat_assert(&[TokenType::TK_DEFAULT]);
match self.peek_no_eof()?.token_type.unwrap().fallback_id_if_ok() {
TokenType::TK_LP => {
self.eat_assert(&[TokenType::TK_LP]);
let expr = self.parse_expr(0)?;
self.eat_expect(&[TokenType::TK_RP])?;
Ok(ColumnConstraint::Default(Box::new(Expr::Parenthesized(
vec![expr],
))))
}
TokenType::TK_PLUS => {
self.eat_assert(&[TokenType::TK_PLUS]);
Ok(ColumnConstraint::Default(Box::new(Expr::Unary(
UnaryOperator::Positive,
self.parse_term()?,
))))
}
TokenType::TK_MINUS => {
self.eat_assert(&[TokenType::TK_MINUS]);
Ok(ColumnConstraint::Default(Box::new(Expr::Unary(
UnaryOperator::Negative,
self.parse_term()?,
))))
}
TokenType::TK_ID | TokenType::TK_INDEXED => Ok(ColumnConstraint::Default(Box::new(
Expr::Id(self.parse_nm()?),
))),
_ => Ok(ColumnConstraint::Default(self.parse_term()?)),
}
}
fn parse_resolve_type(&mut self) -> Result<ResolveType, Error> {
match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_IGNORE => {
self.eat_assert(&[TokenType::TK_IGNORE]);
Ok(ResolveType::Ignore)
}
TokenType::TK_REPLACE => {
self.eat_assert(&[TokenType::TK_REPLACE]);
Ok(ResolveType::Replace)
}
_ => Ok(self.parse_raise_type()?),
}
}
fn parse_on_conflict(&mut self) -> Result<Option<ResolveType>, Error> {
match self.peek()? {
None => return Ok(None),
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_ON => {
self.eat_assert(&[TokenType::TK_ON]);
self.eat_expect(&[TokenType::TK_CONFLICT])?;
}
_ => return Ok(None),
},
}
Ok(Some(self.parse_resolve_type()?))
}
fn parse_or_conflict(&mut self) -> Result<Option<ResolveType>, Error> {
match self.peek()? {
None => return Ok(None),
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_OR => {
self.eat_assert(&[TokenType::TK_OR]);
}
_ => return Ok(None),
},
}
Ok(Some(self.parse_resolve_type()?))
}
fn parse_auto_increment(&mut self) -> Result<bool, Error> {
match self.peek()? {
None => Ok(false),
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_AUTOINCR => {
self.eat_assert(&[TokenType::TK_AUTOINCR]);
Ok(true)
}
_ => Ok(false),
},
}
}
fn parse_not_null_column_constraint(&mut self) -> Result<ColumnConstraint, Error> {
let has_not = match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_NOT => {
self.eat_assert(&[TokenType::TK_NOT]);
true
}
_ => false,
};
self.eat_expect(&[TokenType::TK_NULL])?;
Ok(ColumnConstraint::NotNull {
nullable: !has_not,
conflict_clause: self.parse_on_conflict()?,
})
}
fn parse_primary_column_constraint(&mut self) -> Result<ColumnConstraint, Error> {
self.eat_assert(&[TokenType::TK_PRIMARY]);
self.eat_expect(&[TokenType::TK_KEY])?;
let sort_order = self.parse_sort_order()?;
let conflict_clause = self.parse_on_conflict()?;
let autoincr = self.parse_auto_increment()?;
Ok(ColumnConstraint::PrimaryKey {
order: sort_order,
conflict_clause,
auto_increment: autoincr,
})
}
fn parse_unique_column_constraint(&mut self) -> Result<ColumnConstraint, Error> {
self.eat_assert(&[TokenType::TK_UNIQUE]);
Ok(ColumnConstraint::Unique(self.parse_on_conflict()?))
}
fn parse_check_column_constraint(&mut self) -> Result<ColumnConstraint, Error> {
self.eat_assert(&[TokenType::TK_CHECK]);
self.eat_expect(&[TokenType::TK_LP])?;
let expr = self.parse_expr(0)?;
self.eat_expect(&[TokenType::TK_RP])?;
Ok(ColumnConstraint::Check(expr))
}
fn parse_ref_act(&mut self) -> Result<RefAct, Error> {
let tok = self.eat_expect(&[
TokenType::TK_SET,
TokenType::TK_CASCADE,
TokenType::TK_RESTRICT,
TokenType::TK_NO,
])?;
match tok.token_type.unwrap() {
TokenType::TK_SET => {
let tok = self.eat_expect(&[TokenType::TK_NULL, TokenType::TK_DEFAULT])?;
match tok.token_type.unwrap() {
TokenType::TK_NULL => Ok(RefAct::SetNull),
TokenType::TK_DEFAULT => Ok(RefAct::SetDefault),
_ => unreachable!(),
}
}
TokenType::TK_CASCADE => Ok(RefAct::Cascade),
TokenType::TK_RESTRICT => Ok(RefAct::Restrict),
TokenType::TK_NO => {
self.eat_expect(&[TokenType::TK_ACTION])?;
Ok(RefAct::NoAction)
}
_ => unreachable!(),
}
}
fn parse_ref_args(&mut self) -> Result<Vec<RefArg>, Error> {
let mut result = vec![];
loop {
match self.peek()? {
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_MATCH => {
self.eat_assert(&[TokenType::TK_MATCH]);
result.push(RefArg::Match(self.parse_nm()?));
}
TokenType::TK_ON => {
self.eat_assert(&[TokenType::TK_ON]);
let tok = self.eat_expect(&[
TokenType::TK_INSERT,
TokenType::TK_DELETE,
TokenType::TK_UPDATE,
])?;
match tok.token_type.unwrap() {
TokenType::TK_INSERT => {
result.push(RefArg::OnInsert(self.parse_ref_act()?))
}
TokenType::TK_DELETE => {
result.push(RefArg::OnDelete(self.parse_ref_act()?))
}
TokenType::TK_UPDATE => {
result.push(RefArg::OnUpdate(self.parse_ref_act()?))
}
_ => unreachable!(),
}
}
_ => break,
},
_ => break,
}
}
Ok(result)
}
fn parse_foreign_key_clause(&mut self) -> Result<ForeignKeyClause, Error> {
self.eat_assert(&[TokenType::TK_REFERENCES]);
let name = self.parse_nm()?;
let eid_list = self.parse_eid_list()?;
let ref_args = self.parse_ref_args()?;
Ok(ForeignKeyClause {
tbl_name: name,
columns: eid_list,
args: ref_args,
})
}
fn parse_defer_subclause(&mut self) -> Result<Option<DeferSubclause>, Error> {
let has_not = match self.peek()? {
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_DEFERRABLE => false,
TokenType::TK_NOT => {
self.eat_assert(&[TokenType::TK_NOT]);
true
}
_ => return Ok(None),
},
_ => return Ok(None),
};
self.eat_expect(&[TokenType::TK_DEFERRABLE])?;
let init = match self.peek()? {
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_INITIALLY => {
self.eat_assert(&[TokenType::TK_INITIALLY]);
let tok =
self.eat_expect(&[TokenType::TK_DEFERRED, TokenType::TK_IMMEDIATE])?;
match tok.token_type.unwrap() {
TokenType::TK_DEFERRED => Some(InitDeferredPred::InitiallyDeferred),
TokenType::TK_IMMEDIATE => Some(InitDeferredPred::InitiallyImmediate),
_ => unreachable!(),
}
}
_ => None,
},
_ => None,
};
Ok(Some(DeferSubclause {
deferrable: !has_not,
init_deferred: init,
}))
}
fn parse_reference_column_constraint(&mut self) -> Result<ColumnConstraint, Error> {
let clause = self.parse_foreign_key_clause()?;
let deref_clause = self.parse_defer_subclause()?;
Ok(ColumnConstraint::ForeignKey {
clause,
deref_clause,
})
}
fn parse_generated_column_constraint(&mut self) -> Result<ColumnConstraint, Error> {
let tok = self.eat_assert(&[TokenType::TK_GENERATED, TokenType::TK_AS]);
match tok.token_type.unwrap() {
TokenType::TK_GENERATED => {
self.eat_expect(&[TokenType::TK_ALWAYS])?;
self.eat_expect(&[TokenType::TK_AS])?;
}
TokenType::TK_AS => {}
_ => unreachable!(),
}
self.eat_expect(&[TokenType::TK_LP])?;
let expr = self.parse_expr(0)?;
self.eat_expect(&[TokenType::TK_RP])?;
let typ = match self.peek()? {
Some(tok) => match tok.token_type.unwrap().fallback_id_if_ok() {
TokenType::TK_ID => {
let tok = self.eat_assert(&[TokenType::TK_ID]);
Some(Name::Ident(from_bytes(tok.value)))
}
_ => None,
},
_ => None,
};
Ok(ColumnConstraint::Generated { expr, typ })
}
fn parse_named_column_constraints(&mut self) -> Result<Vec<NamedColumnConstraint>, Error> {
let mut result = vec![];
loop {
let name = match self.peek()? {
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_CONSTRAINT => {
self.eat_assert(&[TokenType::TK_CONSTRAINT]);
Some(self.parse_nm()?)
}
_ => None,
},
_ => None,
};
if name.is_some() {
self.peek_expect(&[
TokenType::TK_DEFAULT,
TokenType::TK_NOT,
TokenType::TK_NULL,
TokenType::TK_PRIMARY,
TokenType::TK_UNIQUE,
TokenType::TK_CHECK,
TokenType::TK_REFERENCES,
TokenType::TK_COLLATE,
TokenType::TK_GENERATED,
TokenType::TK_AS,
])?;
}
match self.peek()? {
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_DEFAULT => {
result.push(NamedColumnConstraint {
name,
constraint: self.parse_default_column_constraint()?,
});
}
TokenType::TK_NOT | TokenType::TK_NULL => {
result.push(NamedColumnConstraint {
name,
constraint: self.parse_not_null_column_constraint()?,
});
}
TokenType::TK_PRIMARY => {
result.push(NamedColumnConstraint {
name,
constraint: self.parse_primary_column_constraint()?,
});
}
TokenType::TK_UNIQUE => {
result.push(NamedColumnConstraint {
name,
constraint: self.parse_unique_column_constraint()?,
});
}
TokenType::TK_CHECK => {
result.push(NamedColumnConstraint {
name,
constraint: self.parse_check_column_constraint()?,
});
}
TokenType::TK_REFERENCES => {
result.push(NamedColumnConstraint {
name,
constraint: self.parse_reference_column_constraint()?,
});
}
TokenType::TK_COLLATE => {
result.push(NamedColumnConstraint {
name,
constraint: ColumnConstraint::Collate {
collation_name: self.parse_collate()?.unwrap(),
},
});
}
TokenType::TK_GENERATED | TokenType::TK_AS => {
result.push(NamedColumnConstraint {
name,
constraint: self.parse_generated_column_constraint()?,
});
}
_ => break,
},
_ => break,
}
}
Ok(result)
}
fn parse_column_definition(&mut self) -> Result<ColumnDefinition, Error> {
let col_name = self.parse_nm()?;
let col_type = self.parse_type()?;
let constraints = self.parse_named_column_constraints()?;
Ok(ColumnDefinition {
col_name,
col_type,
constraints,
})
}
fn parse_alter(&mut self) -> Result<Stmt, Error> {
self.eat_assert(&[TokenType::TK_ALTER]);
self.eat_expect(&[TokenType::TK_TABLE])?;
let tbl_name = self.parse_fullname(false)?;
let tok =
self.eat_expect(&[TokenType::TK_ADD, TokenType::TK_DROP, TokenType::TK_RENAME])?;
match tok.token_type.unwrap() {
TokenType::TK_ADD => {
match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_COLUMNKW => {
self.eat_assert(&[TokenType::TK_COLUMNKW]);
}
_ => {}
}
Ok(Stmt::AlterTable {
name: tbl_name,
body: AlterTableBody::AddColumn(self.parse_column_definition()?),
})
}
TokenType::TK_DROP => {
match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_COLUMNKW => {
self.eat_assert(&[TokenType::TK_COLUMNKW]);
}
_ => {}
}
Ok(Stmt::AlterTable {
name: tbl_name,
body: AlterTableBody::DropColumn(self.parse_nm()?),
})
}
TokenType::TK_RENAME => {
let col_name = match self.peek_no_eof()?.token_type.unwrap().fallback_id_if_ok() {
TokenType::TK_COLUMNKW => {
self.eat_assert(&[TokenType::TK_COLUMNKW]);
Some(self.parse_nm()?)
}
TokenType::TK_ID
| TokenType::TK_STRING
| TokenType::TK_INDEXED
| TokenType::TK_JOIN_KW => Some(self.parse_nm()?),
_ => None,
};
self.eat_expect(&[TokenType::TK_TO])?;
let to_name = self.parse_nm()?;
if col_name.is_some() {
Ok(Stmt::AlterTable {
name: tbl_name,
body: AlterTableBody::RenameColumn {
old: col_name.unwrap(),
new: to_name,
},
})
} else {
Ok(Stmt::AlterTable {
name: tbl_name,
body: AlterTableBody::RenameTo(to_name),
})
}
}
_ => unreachable!(),
}
}
fn parse_create_index(&mut self) -> Result<Stmt, Error> {
let tok = self.eat_assert(&[TokenType::TK_INDEX, TokenType::TK_UNIQUE]);
let has_unique = tok.token_type == Some(TokenType::TK_UNIQUE);
if has_unique {
self.eat_expect(&[TokenType::TK_INDEX])?;
}
let if_not_exists = self.parse_if_not_exists()?;
let idx_name = self.parse_fullname(false)?;
self.eat_expect(&[TokenType::TK_ON])?;
let tbl_name = self.parse_nm()?;
self.eat_expect(&[TokenType::TK_LP])?;
let columns = self.parse_sort_list()?;
self.eat_expect(&[TokenType::TK_RP])?;
let where_clause = self.parse_where()?;
Ok(Stmt::CreateIndex {
if_not_exists,
idx_name,
tbl_name,
columns,
where_clause,
unique: has_unique,
})
}
fn parse_set(&mut self) -> Result<Set, Error> {
let tok = self.peek_expect(&[
TokenType::TK_LP,
TokenType::TK_ID,
TokenType::TK_STRING,
TokenType::TK_JOIN_KW,
TokenType::TK_INDEXED,
])?;
match tok.token_type.unwrap() {
TokenType::TK_LP => {
self.eat_assert(&[TokenType::TK_LP]);
let names = self.parse_nm_list()?;
self.eat_expect(&[TokenType::TK_RP])?;
self.eat_expect(&[TokenType::TK_EQ])?;
Ok(Set {
col_names: names,
expr: self.parse_expr(0)?,
})
}
_ => {
let name = self.parse_nm()?;
self.eat_expect(&[TokenType::TK_EQ])?;
Ok(Set {
col_names: vec![name],
expr: self.parse_expr(0)?,
})
}
}
}
fn parse_set_list(&mut self) -> Result<Vec<Set>, Error> {
let mut results = vec![self.parse_set()?];
loop {
match self.peek()? {
Some(tok) if tok.token_type == Some(TokenType::TK_COMMA) => {
self.eat_assert(&[TokenType::TK_COMMA]);
results.push(self.parse_set()?);
}
_ => break,
}
}
Ok(results)
}
fn parse_returning(&mut self) -> Result<Vec<ResultColumn>, Error> {
match self.peek()? {
Some(tok) if tok.token_type == Some(TokenType::TK_RETURNING) => {
self.eat_assert(&[TokenType::TK_RETURNING]);
}
_ => return Ok(vec![]),
}
self.parse_select_columns()
}
fn parse_upsert(&mut self) -> Result<(Option<Box<Upsert>>, Vec<ResultColumn>), Error> {
match self.peek()? {
Some(tok) => match tok.token_type.unwrap() {
TokenType::TK_ON => {
self.eat_assert(&[TokenType::TK_ON]);
}
TokenType::TK_RETURNING => {
return Ok((None, self.parse_returning()?));
}
_ => return Ok((None, vec![])),
},
_ => return Ok((None, vec![])),
}
self.eat_expect(&[TokenType::TK_CONFLICT])?;
let targets = match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_LP => {
self.eat_assert(&[TokenType::TK_LP]);
let result = self.parse_sort_list()?;
self.eat_expect(&[TokenType::TK_RP])?;
result
}
_ => vec![],
};
let where_clause = if !targets.is_empty() {
self.parse_where()?
} else {
None
};
self.eat_expect(&[TokenType::TK_DO])?;
let tok = self.eat_expect(&[TokenType::TK_NOTHING, TokenType::TK_UPDATE])?;
let do_clause = match tok.token_type.unwrap() {
TokenType::TK_NOTHING => UpsertDo::Nothing,
TokenType::TK_UPDATE => {
self.eat_expect(&[TokenType::TK_SET])?;
let set_list = self.parse_set_list()?;
let update_where_clause = self.parse_where()?;
UpsertDo::Set {
sets: set_list,
where_clause: update_where_clause,
}
}
_ => unreachable!(),
};
if !targets.is_empty() {
let (next, returning) = self.parse_upsert()?;
Ok((
Some(Box::new(Upsert {
index: Some(UpsertIndex {
targets,
where_clause,
}),
do_clause,
next,
})),
returning,
))
} else {
Ok((
Some(Box::new(Upsert {
index: None,
do_clause,
next: None,
})),
self.parse_returning()?,
))
}
}
fn parse_trigger_insert_cmd(&mut self) -> Result<TriggerCmd, Error> {
let tok = self.eat_assert(&[TokenType::TK_INSERT, TokenType::TK_REPLACE]);
let resolve_type = match tok.token_type.unwrap() {
TokenType::TK_INSERT => self.parse_or_conflict()?,
TokenType::TK_REPLACE => Some(ResolveType::Replace),
_ => unreachable!(),
};
self.eat_expect(&[TokenType::TK_INTO])?;
let tbl_name = self.parse_nm()?;
let col_names = self.parse_nm_list_opt()?;
let select = self.parse_select()?;
let (upsert, returning) = self.parse_upsert()?;
Ok(TriggerCmd::Insert {
or_conflict: resolve_type,
tbl_name,
col_names,
select,
upsert,
returning,
})
}
fn parse_trigger_update_cmd(&mut self) -> Result<TriggerCmd, Error> {
self.eat_assert(&[TokenType::TK_UPDATE]);
let or_conflict = self.parse_or_conflict()?;
let tbl_name = self.parse_nm()?;
self.eat_expect(&[TokenType::TK_SET])?;
let sets = self.parse_set_list()?;
let from = self.parse_from_clause_opt()?;
let where_clause = self.parse_where()?;
Ok(TriggerCmd::Update {
or_conflict,
tbl_name,
sets,
from,
where_clause,
})
}
fn parse_trigger_delete_cmd(&mut self) -> Result<TriggerCmd, Error> {
self.eat_assert(&[TokenType::TK_DELETE]);
self.eat_expect(&[TokenType::TK_FROM])?;
let tbl_name = self.parse_nm()?;
let where_clause = self.parse_where()?;
Ok(TriggerCmd::Delete {
tbl_name,
where_clause,
})
}
fn parse_trigger_cmd(&mut self) -> Result<TriggerCmd, Error> {
let tok = self.peek_expect(&[
TokenType::TK_INSERT,
TokenType::TK_REPLACE,
TokenType::TK_UPDATE,
TokenType::TK_DELETE,
TokenType::TK_WITH,
TokenType::TK_SELECT,
TokenType::TK_VALUES,
])?;
let result = match tok.token_type.unwrap() {
TokenType::TK_WITH | TokenType::TK_SELECT | TokenType::TK_VALUES => {
TriggerCmd::Select(self.parse_select()?)
}
TokenType::TK_INSERT | TokenType::TK_REPLACE => self.parse_trigger_insert_cmd()?,
TokenType::TK_UPDATE => self.parse_trigger_update_cmd()?,
TokenType::TK_DELETE => self.parse_trigger_delete_cmd()?,
_ => unreachable!(),
};
self.eat_expect(&[TokenType::TK_SEMI])?;
Ok(result)
}
fn parse_create_trigger(&mut self, temporary: bool) -> Result<Stmt, Error> {
self.eat_assert(&[TokenType::TK_TRIGGER]);
let if_not_exists = self.parse_if_not_exists()?;
let trigger_name = self.parse_fullname(false)?;
let trigger_time = match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_BEFORE => {
self.eat_assert(&[TokenType::TK_BEFORE]);
Some(TriggerTime::Before)
}
TokenType::TK_AFTER => {
self.eat_assert(&[TokenType::TK_AFTER]);
Some(TriggerTime::After)
}
TokenType::TK_INSTEAD => {
self.eat_assert(&[TokenType::TK_INSTEAD]);
self.eat_expect(&[TokenType::TK_OF])?;
Some(TriggerTime::InsteadOf)
}
_ => None,
};
let tok = self.eat_expect(&[
TokenType::TK_INSERT,
TokenType::TK_UPDATE,
TokenType::TK_DELETE,
])?;
let trigger_event = match tok.token_type.unwrap() {
TokenType::TK_INSERT => TriggerEvent::Insert,
TokenType::TK_DELETE => TriggerEvent::Delete,
TokenType::TK_UPDATE => match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_OF => {
self.eat_assert(&[TokenType::TK_OF]);
TriggerEvent::UpdateOf(self.parse_nm_list()?)
}
_ => TriggerEvent::Update,
},
_ => unreachable!(),
};
self.eat_expect(&[TokenType::TK_ON])?;
let tbl_name = self.parse_fullname(false)?;
let foreach_clause = match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_FOR => {
self.eat_assert(&[TokenType::TK_FOR]);
self.eat_expect(&[TokenType::TK_EACH])?;
self.eat_expect(&[TokenType::TK_ROW])?;
true
}
_ => false,
};
let when_clause = match self.peek()? {
Some(tok) if tok.token_type == Some(TokenType::TK_WHEN) => {
self.eat_assert(&[TokenType::TK_WHEN]);
Some(self.parse_expr(0)?)
}
_ => None,
};
self.eat_expect(&[TokenType::TK_BEGIN])?;
let mut cmds = vec![self.parse_trigger_cmd()?];
loop {
match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_UPDATE
| TokenType::TK_REPLACE
| TokenType::TK_INSERT
| TokenType::TK_DELETE
| TokenType::TK_WITH
| TokenType::TK_SELECT
| TokenType::TK_VALUES => {}
_ => break,
}
cmds.push(self.parse_trigger_cmd()?);
}
self.eat_expect(&[TokenType::TK_END])?;
Ok(Stmt::CreateTrigger {
temporary,
if_not_exists,
trigger_name,
time: trigger_time,
event: trigger_event,
tbl_name,
for_each_row: foreach_clause,
when_clause,
commands: cmds,
})
}
fn parse_delete_without_cte(&mut self, with: Option<With>) -> Result<Stmt, Error> {
self.eat_assert(&[TokenType::TK_DELETE]);
self.eat_expect(&[TokenType::TK_FROM])?;
let tbl_name = self.parse_fullname(true)?;
let indexed = self.parse_indexed()?;
let where_clause = self.parse_where()?;
let returning = self.parse_returning()?;
let order_by = self.parse_order_by()?;
let limit = self.parse_limit()?;
Ok(Stmt::Delete {
with,
tbl_name,
indexed,
where_clause,
returning,
order_by,
limit,
})
}
fn parse_delete(&mut self) -> Result<Stmt, Error> {
let with = self.parse_with()?;
self.parse_delete_without_cte(with)
}
fn parse_if_exists(&mut self) -> Result<bool, Error> {
match self.peek()? {
Some(tok) if tok.token_type == Some(TokenType::TK_IF) => {
self.eat_assert(&[TokenType::TK_IF]);
self.eat_expect(&[TokenType::TK_EXISTS])?;
Ok(true)
}
_ => Ok(false),
}
}
fn parse_drop_stmt(&mut self) -> Result<Stmt, Error> {
self.eat_assert(&[TokenType::TK_DROP]);
let tok = self.peek_expect(&[
TokenType::TK_TABLE,
TokenType::TK_INDEX,
TokenType::TK_TRIGGER,
TokenType::TK_VIEW,
])?;
match tok.token_type.unwrap() {
TokenType::TK_TABLE => {
self.eat_expect(&[TokenType::TK_TABLE])?;
let if_exists = self.parse_if_exists()?;
let tbl_name = self.parse_fullname(false)?;
Ok(Stmt::DropTable {
if_exists,
tbl_name,
})
}
TokenType::TK_INDEX => {
self.eat_expect(&[TokenType::TK_INDEX])?;
let if_exists = self.parse_if_exists()?;
let idx_name = self.parse_fullname(false)?;
Ok(Stmt::DropIndex {
if_exists,
idx_name,
})
}
TokenType::TK_TRIGGER => {
self.eat_expect(&[TokenType::TK_TRIGGER])?;
let if_exists = self.parse_if_exists()?;
let trigger_name = self.parse_fullname(false)?;
Ok(Stmt::DropTrigger {
if_exists,
trigger_name,
})
}
TokenType::TK_VIEW => {
self.eat_expect(&[TokenType::TK_VIEW])?;
let if_exists = self.parse_if_exists()?;
let view_name = self.parse_fullname(false)?;
Ok(Stmt::DropView {
if_exists,
view_name,
})
}
_ => unreachable!(),
}
}
fn parse_insert_without_cte(&mut self, with: Option<With>) -> Result<Stmt, Error> {
let tok = self.eat_assert(&[TokenType::TK_INSERT, TokenType::TK_REPLACE]);
let resolve_type = match tok.token_type.unwrap() {
TokenType::TK_INSERT => self.parse_or_conflict()?,
TokenType::TK_REPLACE => Some(ResolveType::Replace),
_ => unreachable!(),
};
self.eat_expect(&[TokenType::TK_INTO])?;
let tbl_name = self.parse_fullname(true)?;
let columns = self.parse_nm_list_opt()?;
let (body, returning) = match self.peek_no_eof()?.token_type.unwrap() {
TokenType::TK_DEFAULT => {
self.eat_assert(&[TokenType::TK_DEFAULT]);
self.eat_expect(&[TokenType::TK_VALUES])?;
(InsertBody::DefaultValues, self.parse_returning()?)
}
_ => {
let select = self.parse_select()?;
let (upsert, returning) = self.parse_upsert()?;
(InsertBody::Select(select, upsert), returning)
}
};
Ok(Stmt::Insert {
with,
or_conflict: resolve_type,
tbl_name,
columns,
body,
returning,
})
}
fn parse_insert(&mut self) -> Result<Stmt, Error> {
let with = self.parse_with()?;
self.parse_insert_without_cte(with)
}
fn parse_update_without_cte(&mut self, with: Option<With>) -> Result<Stmt, Error> {
self.eat_assert(&[TokenType::TK_UPDATE]);
let resolve_type = self.parse_or_conflict()?;
let tbl_name = self.parse_fullname(true)?;
let indexed = self.parse_indexed()?;
self.eat_expect(&[TokenType::TK_SET])?;
let sets = self.parse_set_list()?;
let from = self.parse_from_clause_opt()?;
let where_clause = self.parse_where()?;
let returning = self.parse_returning()?;
let order_by = self.parse_order_by()?;
let limit = self.parse_limit()?;
Ok(Stmt::Update {
with,
or_conflict: resolve_type,
tbl_name,
indexed,
sets,
from,
where_clause,
returning,
order_by,
limit,
})
}
fn parse_update(&mut self) -> Result<Stmt, Error> {
let with = self.parse_with()?;
self.parse_update_without_cte(with)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parser() {
let test_cases = vec![
// begin
(
b"BEGIN".as_slice(),
vec![Cmd::Stmt(Stmt::Begin {
typ: None,
name: None,
})],
),
(
b"EXPLAIN BEGIN".as_slice(),
vec![Cmd::Explain(Stmt::Begin {
typ: None,
name: None,
})],
),
(
b"EXPLAIN QUERY PLAN BEGIN".as_slice(),
vec![Cmd::ExplainQueryPlan(Stmt::Begin {
typ: None,
name: None,
})],
),
(
b"BEGIN TRANSACTION".as_slice(),
vec![Cmd::Stmt(Stmt::Begin {
typ: None,
name: None,
})],
),
(
b"BEGIN DEFERRED TRANSACTION".as_slice(),
vec![Cmd::Stmt(Stmt::Begin {
typ: Some(TransactionType::Deferred),
name: None,
})],
),
(
b"BEGIN IMMEDIATE TRANSACTION".as_slice(),
vec![Cmd::Stmt(Stmt::Begin {
typ: Some(TransactionType::Immediate),
name: None,
})],
),
(
b"BEGIN EXCLUSIVE TRANSACTION".as_slice(),
vec![Cmd::Stmt(Stmt::Begin {
typ: Some(TransactionType::Exclusive),
name: None,
})],
),
(
b"BEGIN DEFERRED TRANSACTION my_transaction".as_slice(),
vec![Cmd::Stmt(Stmt::Begin {
typ: Some(TransactionType::Deferred),
name: Some(Name::Ident("my_transaction".to_string())),
})],
),
(
b"BEGIN IMMEDIATE TRANSACTION my_transaction".as_slice(),
vec![Cmd::Stmt(Stmt::Begin {
typ: Some(TransactionType::Immediate),
name: Some(Name::Ident("my_transaction".to_string())),
})],
),
(
b"BEGIN EXCLUSIVE TRANSACTION my_transaction".as_slice(),
vec![Cmd::Stmt(Stmt::Begin {
typ: Some(TransactionType::Exclusive),
name: Some(Name::Ident("my_transaction".to_string())),
})],
),
(
b"BEGIN EXCLUSIVE TRANSACTION 'my_transaction'".as_slice(),
vec![Cmd::Stmt(Stmt::Begin {
typ: Some(TransactionType::Exclusive),
name: Some(Name::Quoted("'my_transaction'".to_string())),
})],
),
(
";;;BEGIN;BEGIN;;;;;;BEGIN".as_bytes(),
vec![
Cmd::Stmt(Stmt::Begin {
typ: None,
name: None,
}),
Cmd::Stmt(Stmt::Begin {
typ: None,
name: None,
}),
Cmd::Stmt(Stmt::Begin {
typ: None,
name: None,
}),
],
),
// commit
(
b"COMMIT".as_slice(),
vec![Cmd::Stmt(Stmt::Commit { name: None })],
),
(
b"END".as_slice(),
vec![Cmd::Stmt(Stmt::Commit { name: None })],
),
(
b"COMMIT TRANSACTION".as_slice(),
vec![Cmd::Stmt(Stmt::Commit { name: None })],
),
(
b"END TRANSACTION".as_slice(),
vec![Cmd::Stmt(Stmt::Commit { name: None })],
),
(
b"COMMIT TRANSACTION my_transaction".as_slice(),
vec![Cmd::Stmt(Stmt::Commit {
name: Some(Name::Ident("my_transaction".to_string())),
})],
),
(
b"END TRANSACTION my_transaction".as_slice(),
vec![Cmd::Stmt(Stmt::Commit {
name: Some(Name::Ident("my_transaction".to_string())),
})],
),
// Rollback
(
b"ROLLBACK".as_slice(),
vec![Cmd::Stmt(Stmt::Rollback {
tx_name: None,
savepoint_name: None,
})],
),
(
b"ROLLBACK TO SAVEPOINT my_savepoint".as_slice(),
vec![Cmd::Stmt(Stmt::Rollback {
tx_name: None,
savepoint_name: Some(Name::Ident("my_savepoint".to_string())),
})],
),
(
b"ROLLBACK TO my_savepoint".as_slice(),
vec![Cmd::Stmt(Stmt::Rollback {
tx_name: None,
savepoint_name: Some(Name::Ident("my_savepoint".to_string())),
})],
),
(
b"ROLLBACK TRANSACTION my_transaction".as_slice(),
vec![Cmd::Stmt(Stmt::Rollback {
tx_name: Some(Name::Ident("my_transaction".to_string())),
savepoint_name: None,
})],
),
(
b"ROLLBACK TRANSACTION my_transaction TO my_savepoint".as_slice(),
vec![Cmd::Stmt(Stmt::Rollback {
tx_name: Some(Name::Ident("my_transaction".to_string())),
savepoint_name: Some(Name::Ident("my_savepoint".to_string())),
})],
),
// savepoint
(
b"SAVEPOINT my_savepoint".as_slice(),
vec![Cmd::Stmt(Stmt::Savepoint {
name: Name::Ident("my_savepoint".to_string()),
})],
),
(
b"SAVEPOINT 'my_savepoint'".as_slice(),
vec![Cmd::Stmt(Stmt::Savepoint {
name: Name::Quoted("'my_savepoint'".to_string()),
})],
),
// release
(
b"RELEASE my_savepoint".as_slice(),
vec![Cmd::Stmt(Stmt::Release {
name: Name::Ident("my_savepoint".to_string()),
})],
),
(
b"RELEASE SAVEPOINT my_savepoint".as_slice(),
vec![Cmd::Stmt(Stmt::Release {
name: Name::Ident("my_savepoint".to_string()),
})],
),
(
b"RELEASE SAVEPOINT 'my_savepoint'".as_slice(),
vec![Cmd::Stmt(Stmt::Release {
name: Name::Quoted("'my_savepoint'".to_string()),
})],
),
(
b"RELEASE SAVEPOINT ABORT".as_slice(),
vec![Cmd::Stmt(Stmt::Release {
name: Name::Ident("ABORT".to_string()),
})],
),
// test expr operand
(
b"SELECT 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT (1)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Parenthesized(vec![Box::new(Expr::Literal(
Literal::Numeric("1".to_owned()),
))])),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT NULL".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Null)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT X'ab'".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Blob("ab".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 3.333".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("3.333".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT ?1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Variable("1".to_owned())),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT CAST(1 AS INTEGER)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Cast {
expr: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
type_name: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT CAST(1 AS VARCHAR(255))".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Cast {
expr: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
type_name: Some(Type {
name: "VARCHAR".to_owned(),
size: Some(TypeSize::MaxSize(Box::new(Expr::Literal(
Literal::Numeric("255".to_owned()),
)))),
}),
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT CAST(1 AS DECIMAL(10, 5))".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Cast {
expr: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
type_name: Some(Type {
name: "DECIMAL".to_owned(),
size: Some(TypeSize::TypeSize(
Box::new(Expr::Literal(Literal::Numeric(
"10".to_owned(),
))),
Box::new(Expr::Literal(Literal::Numeric(
"5".to_owned(),
))),
)),
}),
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT CURRENT_DATE".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::CurrentDate)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT CURRENT_TIME".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::CurrentTime)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT CURRENT_TIMESTAMP".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::CurrentTimestamp)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT NOT 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Unary(
UnaryOperator::Not,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT NOT 1 + 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Unary(
UnaryOperator::Not,
Box::new(Expr::Binary(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::Add,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT ~1 + 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary(
Box::new(Expr::Unary(
UnaryOperator::BitwiseNot,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
Operator::Add,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT +1 + 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary(
Box::new(Expr::Unary(
UnaryOperator::Positive,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
Operator::Add,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT -1 + 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary(
Box::new(Expr::Unary(
UnaryOperator::Negative,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
Operator::Add,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT EXISTS (SELECT 1)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Exists(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric(
"1".to_owned(),
))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
})),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT CASE WHEN 1 THEN 2 ELSE 3 END".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Case {
base: None,
when_then_pairs: vec![(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
)],
else_expr: Some(Box::new(Expr::Literal(Literal::Numeric(
"3".to_owned(),
)))),
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT CASE 4 WHEN 1 THEN 2 ELSE 3 END".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Case {
base: Some(Box::new(Expr::Literal(Literal::Numeric(
"4".to_owned(),
)))),
when_then_pairs: vec![(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
)],
else_expr: Some(Box::new(Expr::Literal(Literal::Numeric(
"3".to_owned(),
)))),
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT CASE 4 WHEN 1 THEN 2 END".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Case {
base: Some(Box::new(Expr::Literal(Literal::Numeric(
"4".to_owned(),
)))),
when_then_pairs: vec![(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
)],
else_expr: None,
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT (SELECT 1)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Subquery(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric(
"1".to_owned(),
))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
})),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT RAISE (Ignore)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Raise(ResolveType::Ignore, None)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT RAISE (FAIL, 'error')".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Raise(
ResolveType::Fail,
Some(Box::new(Expr::Literal(Literal::String(
"'error'".to_owned(),
)))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT RAISE (ROLLBACK, 'error')".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Raise(
ResolveType::Rollback,
Some(Box::new(Expr::Literal(Literal::String(
"'error'".to_owned(),
)))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT RAISE (ABORT, 'error')".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Raise(
ResolveType::Abort,
Some(Box::new(Expr::Literal(Literal::String(
"'error'".to_owned(),
)))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT RAISE (ABORT, 'error')".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Raise(
ResolveType::Abort,
Some(Box::new(Expr::Literal(Literal::String(
"'error'".to_owned(),
)))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT col_1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Id(Name::Ident("col_1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 'col_1'".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::String("'col_1'".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT tbl_name.col_1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Qualified(
Name::Ident("tbl_name".to_owned()),
Name::Ident("col_1".to_owned()),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT schema_name.tbl_name.col_1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::DoublyQualified(
Name::Ident("schema_name".to_owned()),
Name::Ident("tbl_name".to_owned()),
Name::Ident("col_1".to_owned()),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT func_name()".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::FunctionCall {
name: Name::Ident("func_name".to_owned()),
distinctness: None,
args: vec![],
order_by: vec![],
filter_over: FunctionTail {
filter_clause: None,
over_clause: None,
},
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT func_name(DISTINCT 1, 2) FILTER (WHERE x) OVER window_name".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::FunctionCall {
name: Name::Ident("func_name".to_owned()),
distinctness: Some(Distinctness::Distinct),
args: vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
order_by: vec![],
filter_over: FunctionTail {
filter_clause: Some(Box::new(Expr::Id(Name::Ident(
"x".to_owned(),
)))),
over_clause: Some(Over::Name(Name::Ident(
"window_name".to_owned(),
))),
},
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT func_name(DISTINCT 1, 2) OVER (PARTITION BY product)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::FunctionCall {
name: Name::Ident("func_name".to_owned()),
distinctness: Some(Distinctness::Distinct),
args: vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
order_by: vec![],
filter_over: FunctionTail {
filter_clause: None,
over_clause: Some(Over::Window(Window {
base: None,
partition_by: vec![Box::new(Expr::Id(Name::Ident(
"product".to_owned(),
)))],
order_by: vec![],
frame_clause: None,
})),
},
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT func_name(DISTINCT 1, 2) OVER (test PARTITION BY product)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::FunctionCall {
name: Name::Ident("func_name".to_owned()),
distinctness: Some(Distinctness::Distinct),
args: vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
order_by: vec![],
filter_over: FunctionTail {
filter_clause: None,
over_clause: Some(Over::Window(Window {
base: Some(Name::Ident("test".to_owned())),
partition_by: vec![Box::new(Expr::Id(Name::Ident(
"product".to_owned(),
)))],
order_by: vec![],
frame_clause: None,
})),
},
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT func_name(DISTINCT 1, 2) OVER (test PARTITION BY product ORDER BY test ASC NULLS LAST)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::FunctionCall {
name: Name::Ident("func_name".to_owned()),
distinctness: Some(Distinctness::Distinct),
args: vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
order_by: vec![],
filter_over: FunctionTail {
filter_clause: None,
over_clause: Some(Over::Window(Window {
base: Some(Name::Ident("test".to_owned())),
partition_by: vec![Box::new(Expr::Id(Name::Ident(
"product".to_owned(),
)))],
order_by: vec![
SortedColumn {
expr: Box::new(Expr::Id(Name::Ident("test".to_owned()))),
order: Some(SortOrder::Asc),
nulls: Some(NullsOrder::Last),
}
],
frame_clause: None,
})),
},
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT func_name(DISTINCT 1, 2) OVER (test PARTITION BY product ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::FunctionCall {
name: Name::Ident("func_name".to_owned()),
distinctness: Some(Distinctness::Distinct),
args: vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
order_by: vec![],
filter_over: FunctionTail {
filter_clause: None,
over_clause: Some(Over::Window(Window {
base: Some(Name::Ident("test".to_owned())),
partition_by: vec![Box::new(Expr::Id(Name::Ident(
"product".to_owned(),
)))],
order_by: vec![],
frame_clause: Some(FrameClause{
mode: FrameMode::Rows,
start: FrameBound::Preceding(Box::new(Expr::Literal(Literal::Numeric("2".to_owned())))),
end: Some(FrameBound::CurrentRow),
exclude: None
}),
})),
},
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT func_name(DISTINCT 1, 2) OVER (test PARTITION BY product RANGE BETWEEN 2 PRECEDING AND CURRENT ROW)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::FunctionCall {
name: Name::Ident("func_name".to_owned()),
distinctness: Some(Distinctness::Distinct),
args: vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
order_by: vec![],
filter_over: FunctionTail {
filter_clause: None,
over_clause: Some(Over::Window(Window {
base: Some(Name::Ident("test".to_owned())),
partition_by: vec![Box::new(Expr::Id(Name::Ident(
"product".to_owned(),
)))],
order_by: vec![],
frame_clause: Some(FrameClause{
mode: FrameMode::Range,
start: FrameBound::Preceding(Box::new(Expr::Literal(Literal::Numeric("2".to_owned())))),
end: Some(FrameBound::CurrentRow),
exclude: None
}),
})),
},
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT func_name(DISTINCT 1, 2) OVER (test PARTITION BY product GROUPS BETWEEN 2 PRECEDING AND CURRENT ROW)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::FunctionCall {
name: Name::Ident("func_name".to_owned()),
distinctness: Some(Distinctness::Distinct),
args: vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
order_by: vec![],
filter_over: FunctionTail {
filter_clause: None,
over_clause: Some(Over::Window(Window {
base: Some(Name::Ident("test".to_owned())),
partition_by: vec![Box::new(Expr::Id(Name::Ident(
"product".to_owned(),
)))],
order_by: vec![],
frame_clause: Some(FrameClause{
mode: FrameMode::Groups,
start: FrameBound::Preceding(Box::new(Expr::Literal(Literal::Numeric("2".to_owned())))),
end: Some(FrameBound::CurrentRow),
exclude: None
}),
})),
},
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT func_name(DISTINCT 1, 2) OVER (test PARTITION BY product GROUPS BETWEEN 2 FOLLOWING AND CURRENT ROW)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::FunctionCall {
name: Name::Ident("func_name".to_owned()),
distinctness: Some(Distinctness::Distinct),
args: vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
order_by: vec![],
filter_over: FunctionTail {
filter_clause: None,
over_clause: Some(Over::Window(Window {
base: Some(Name::Ident("test".to_owned())),
partition_by: vec![Box::new(Expr::Id(Name::Ident(
"product".to_owned(),
)))],
order_by: vec![],
frame_clause: Some(FrameClause{
mode: FrameMode::Groups,
start: FrameBound::Following(Box::new(Expr::Literal(Literal::Numeric("2".to_owned())))),
end: Some(FrameBound::CurrentRow),
exclude: None
}),
})),
},
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT func_name(DISTINCT 1, 2) OVER (test PARTITION BY product GROUPS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::FunctionCall {
name: Name::Ident("func_name".to_owned()),
distinctness: Some(Distinctness::Distinct),
args: vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
order_by: vec![],
filter_over: FunctionTail {
filter_clause: None,
over_clause: Some(Over::Window(Window {
base: Some(Name::Ident("test".to_owned())),
partition_by: vec![Box::new(Expr::Id(Name::Ident(
"product".to_owned(),
)))],
order_by: vec![],
frame_clause: Some(FrameClause{
mode: FrameMode::Groups,
start: FrameBound::UnboundedPreceding,
end: Some(FrameBound::CurrentRow),
exclude: None
}),
})),
},
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT func_name(DISTINCT 1, 2) OVER (test PARTITION BY product GROUPS BETWEEN CURRENT ROW AND CURRENT ROW)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::FunctionCall {
name: Name::Ident("func_name".to_owned()),
distinctness: Some(Distinctness::Distinct),
args: vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
order_by: vec![],
filter_over: FunctionTail {
filter_clause: None,
over_clause: Some(Over::Window(Window {
base: Some(Name::Ident("test".to_owned())),
partition_by: vec![Box::new(Expr::Id(Name::Ident(
"product".to_owned(),
)))],
order_by: vec![],
frame_clause: Some(FrameClause{
mode: FrameMode::Groups,
start: FrameBound::CurrentRow,
end: Some(FrameBound::CurrentRow),
exclude: None
}),
})),
},
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT func_name(DISTINCT 1, 2) OVER (test PARTITION BY product GROUPS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::FunctionCall {
name: Name::Ident("func_name".to_owned()),
distinctness: Some(Distinctness::Distinct),
args: vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
order_by: vec![],
filter_over: FunctionTail {
filter_clause: None,
over_clause: Some(Over::Window(Window {
base: Some(Name::Ident("test".to_owned())),
partition_by: vec![Box::new(Expr::Id(Name::Ident(
"product".to_owned(),
)))],
order_by: vec![],
frame_clause: Some(FrameClause{
mode: FrameMode::Groups,
start: FrameBound::CurrentRow,
end: Some(FrameBound::UnboundedFollowing),
exclude: None
}),
})),
},
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT func_name(DISTINCT 1, 2) OVER (test PARTITION BY product GROUPS BETWEEN CURRENT ROW AND 1 PRECEDING)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::FunctionCall {
name: Name::Ident("func_name".to_owned()),
distinctness: Some(Distinctness::Distinct),
args: vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
order_by: vec![],
filter_over: FunctionTail {
filter_clause: None,
over_clause: Some(Over::Window(Window {
base: Some(Name::Ident("test".to_owned())),
partition_by: vec![Box::new(Expr::Id(Name::Ident(
"product".to_owned(),
)))],
order_by: vec![],
frame_clause: Some(FrameClause{
mode: FrameMode::Groups,
start: FrameBound::CurrentRow,
end: Some(FrameBound::Preceding(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned())))
)),
exclude: None
}),
})),
},
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT func_name(DISTINCT 1, 2) OVER (test PARTITION BY product GROUPS BETWEEN CURRENT ROW AND 1 FOLLOWING)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::FunctionCall {
name: Name::Ident("func_name".to_owned()),
distinctness: Some(Distinctness::Distinct),
args: vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
order_by: vec![],
filter_over: FunctionTail {
filter_clause: None,
over_clause: Some(Over::Window(Window {
base: Some(Name::Ident("test".to_owned())),
partition_by: vec![Box::new(Expr::Id(Name::Ident(
"product".to_owned(),
)))],
order_by: vec![],
frame_clause: Some(FrameClause{
mode: FrameMode::Groups,
start: FrameBound::CurrentRow,
end: Some(FrameBound::Following(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned())))
)),
exclude: None
}),
})),
},
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT func_name(DISTINCT 1, 2) OVER (test PARTITION BY product GROUPS CURRENT ROW EXCLUDE NO OTHERS)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::FunctionCall {
name: Name::Ident("func_name".to_owned()),
distinctness: Some(Distinctness::Distinct),
args: vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
order_by: vec![],
filter_over: FunctionTail {
filter_clause: None,
over_clause: Some(Over::Window(Window {
base: Some(Name::Ident("test".to_owned())),
partition_by: vec![Box::new(Expr::Id(Name::Ident(
"product".to_owned(),
)))],
order_by: vec![],
frame_clause: Some(FrameClause{
mode: FrameMode::Groups,
start: FrameBound::CurrentRow,
end: None,
exclude: Some(FrameExclude::NoOthers)
}),
})),
},
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT func_name(DISTINCT 1, 2) OVER (test PARTITION BY product GROUPS CURRENT ROW EXCLUDE CURRENT ROW)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::FunctionCall {
name: Name::Ident("func_name".to_owned()),
distinctness: Some(Distinctness::Distinct),
args: vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
order_by: vec![],
filter_over: FunctionTail {
filter_clause: None,
over_clause: Some(Over::Window(Window {
base: Some(Name::Ident("test".to_owned())),
partition_by: vec![Box::new(Expr::Id(Name::Ident(
"product".to_owned(),
)))],
order_by: vec![],
frame_clause: Some(FrameClause{
mode: FrameMode::Groups,
start: FrameBound::CurrentRow,
end: None,
exclude: Some(FrameExclude::CurrentRow)
}),
})),
},
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT func_name(DISTINCT 1, 2) OVER (test PARTITION BY product GROUPS CURRENT ROW EXCLUDE GROUP)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::FunctionCall {
name: Name::Ident("func_name".to_owned()),
distinctness: Some(Distinctness::Distinct),
args: vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
order_by: vec![],
filter_over: FunctionTail {
filter_clause: None,
over_clause: Some(Over::Window(Window {
base: Some(Name::Ident("test".to_owned())),
partition_by: vec![Box::new(Expr::Id(Name::Ident(
"product".to_owned(),
)))],
order_by: vec![],
frame_clause: Some(FrameClause{
mode: FrameMode::Groups,
start: FrameBound::CurrentRow,
end: None,
exclude: Some(FrameExclude::Group)
}),
})),
},
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT func_name(DISTINCT 1, 2) OVER (test PARTITION BY product GROUPS CURRENT ROW EXCLUDE TIES)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::FunctionCall {
name: Name::Ident("func_name".to_owned()),
distinctness: Some(Distinctness::Distinct),
args: vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
order_by: vec![],
filter_over: FunctionTail {
filter_clause: None,
over_clause: Some(Over::Window(Window {
base: Some(Name::Ident("test".to_owned())),
partition_by: vec![Box::new(Expr::Id(Name::Ident(
"product".to_owned(),
)))],
order_by: vec![],
frame_clause: Some(FrameClause{
mode: FrameMode::Groups,
start: FrameBound::CurrentRow,
end: None,
exclude: Some(FrameExclude::Ties)
}),
})),
},
}),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
// parse expr
(
b"SELECT 1 + 2 * 3".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::Add,
Box::new(Expr::Binary (
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
Operator::Multiply,
Box::new(Expr::Literal(Literal::Numeric("3".to_owned())))
))
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 AND 2 OR 3".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Binary (
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("2".to_owned())))
)),
Operator::Or,
Box::new(Expr::Literal(Literal::Numeric("3".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 = 0 AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Binary (
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::Equals,
Box::new(Expr::Literal(Literal::Numeric("0".to_owned())))
)),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 != 0 AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Binary (
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::NotEquals,
Box::new(Expr::Literal(Literal::Numeric("0".to_owned())))
)),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 BETWEEN 2 AND 3 AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Between {
lhs: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
not: false,
start: Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
end: Box::new(Expr::Literal(Literal::Numeric("3".to_owned()))),
}),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 NOT BETWEEN 2 AND 3 AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Between {
lhs: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
not: true,
start: Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
end: Box::new(Expr::Literal(Literal::Numeric("3".to_owned()))),
}),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 IN (SELECT 1) AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::InSelect {
lhs: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
not: false,
rhs: Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None
},
}),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 NOT IN (SELECT 1) AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::InSelect {
lhs: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
not: true,
rhs: Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None
},
}),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 IN (1, 2, 3) AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::InList {
lhs: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
not: false,
rhs: vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("3".to_owned()))),
],
}),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 IN test(1, 2, 3) AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::InTable {
lhs: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
not: false,
rhs: QualifiedName {
db_name: None,
name: Name::Ident("test".to_owned()),
alias: None,
},
args: vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("3".to_owned()))),
],
}),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 'test' MATCH 'foo' AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Like {
lhs: Box::new(Expr::Literal(Literal::String("'test'".to_owned()))),
not: false,
op: LikeOperator::Match,
rhs: Box::new(Expr::Literal(Literal::String("'foo'".to_owned()))),
escape: None,
}),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 'test' NOT MATCH 'foo' AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Like {
lhs: Box::new(Expr::Literal(Literal::String("'test'".to_owned()))),
not: true,
op: LikeOperator::Match,
rhs: Box::new(Expr::Literal(Literal::String("'foo'".to_owned()))),
escape: None,
}),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 'test' NOT MATCH 'foo' ESCAPE 'bar' AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Like {
lhs: Box::new(Expr::Literal(Literal::String("'test'".to_owned()))),
not: true,
op: LikeOperator::Match,
rhs: Box::new(Expr::Literal(Literal::String("'foo'".to_owned()))),
escape: Some(Box::new(Expr::Literal(Literal::String("'bar'".to_owned())))),
}),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 'test' NOT LIKE 'foo' ESCAPE 'bar' AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Like {
lhs: Box::new(Expr::Literal(Literal::String("'test'".to_owned()))),
not: true,
op: LikeOperator::Like,
rhs: Box::new(Expr::Literal(Literal::String("'foo'".to_owned()))),
escape: Some(Box::new(Expr::Literal(Literal::String("'bar'".to_owned())))),
}),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 'test' NOT GLOB 'foo' ESCAPE 'bar' AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Like {
lhs: Box::new(Expr::Literal(Literal::String("'test'".to_owned()))),
not: true,
op: LikeOperator::Glob,
rhs: Box::new(Expr::Literal(Literal::String("'foo'".to_owned()))),
escape: Some(Box::new(Expr::Literal(Literal::String("'bar'".to_owned())))),
}),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 'test' NOT REGEXP 'foo' ESCAPE 'bar' AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Like {
lhs: Box::new(Expr::Literal(Literal::String("'test'".to_owned()))),
not: true,
op: LikeOperator::Regexp,
rhs: Box::new(Expr::Literal(Literal::String("'foo'".to_owned()))),
escape: Some(Box::new(Expr::Literal(Literal::String("'bar'".to_owned())))),
}),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 ISNULL AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::IsNull (
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 NOTNULL AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::NotNull(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 < 2 AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Binary (
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::Less,
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
)),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 > 2 AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Binary (
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::Greater,
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
)),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 <= 2 AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Binary (
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::LessEquals,
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
)),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 >= 2 AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Binary (
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::GreaterEquals,
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
)),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 & 2 AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Binary (
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::BitwiseAnd,
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
)),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 | 2 AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Binary (
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::BitwiseOr,
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
)),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 << 2 AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Binary (
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::LeftShift,
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
)),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 >> 2 AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Binary (
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::RightShift,
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
)),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 / 2 AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Binary (
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::Divide,
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
)),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 % 2 AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Binary (
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::Modulus,
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
)),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 || 2 AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Binary (
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::Concat,
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
)),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 -> 2 AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Binary (
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::ArrowRight,
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
)),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 ->> 2 AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Binary (
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::ArrowRightShift,
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
)),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 'foo' COLLATE bar AND 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Binary (
Box::new(Expr::Collate (
Box::new(Expr::Literal(Literal::String("'foo'".to_owned()))),
Name::Ident("bar".to_owned()),
)),
Operator::And,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
// test select
(
b"VALUES (1, 2), (3, 4), (5, 6)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Values(vec![
vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
vec![
Box::new(Expr::Literal(Literal::Numeric("3".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("4".to_owned()))),
],
vec![
Box::new(Expr::Literal(Literal::Numeric("5".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("6".to_owned()))),
],
]),
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT *".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Star],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT tbl_name.*".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::TableStar(
Name::Ident("tbl_name".to_owned()),
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT col_1 OVER".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Id(Name::Ident("col_1".to_owned()))),
Some(As::Elided(Name::Ident("OVER".to_owned()))),
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT col_1 AS OVER".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Id(Name::Ident("col_1".to_owned()))),
Some(As::As(Name::Ident("OVER".to_owned()))),
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"WITH test AS (SELECT 1) SELECT 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: Some(With {
recursive: false,
ctes: vec![
CommonTableExpr {
tbl_name: Name::Ident("test".to_owned()),
columns: vec![],
materialized: Materialized::Any,
select: Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}
},
]
}),
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"WITH test(col_1) AS MATERIALIZED (SELECT 1 AS col_1) SELECT 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: Some(With {
recursive: false,
ctes: vec![
CommonTableExpr {
tbl_name: Name::Ident("test".to_owned()),
columns: vec![
IndexedColumn {
col_name: Name::Ident("col_1".to_owned()),
collation_name: None,
order: None,
},
],
materialized: Materialized::Yes,
select: Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Some(As::As(Name::Ident("col_1".to_owned()))),
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}
},
]
}),
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"WITH test(col_1) AS NOT MATERIALIZED (SELECT 1 AS col_1) SELECT 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: Some(With {
recursive: false,
ctes: vec![
CommonTableExpr {
tbl_name: Name::Ident("test".to_owned()),
columns: vec![
IndexedColumn {
col_name: Name::Ident("col_1".to_owned()),
collation_name: None,
order: None,
},
],
materialized: Materialized::No,
select: Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Some(As::As(Name::Ident("col_1".to_owned()))),
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}
},
]
}),
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"WITH test AS (SELECT 1), test_2 AS (SELECT 1) SELECT 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: Some(With {
recursive: false,
ctes: vec![
CommonTableExpr {
tbl_name: Name::Ident("test".to_owned()),
columns: vec![],
materialized: Materialized::Any,
select: Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}
},
CommonTableExpr {
tbl_name: Name::Ident("test_2".to_owned()),
columns: vec![],
materialized: Materialized::Any,
select: Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}
},
]
}),
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 ORDER BY 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![
SortedColumn {
expr: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
order: None,
nulls: None,
},
],
limit: None,
}))],
),
(
b"SELECT 1 ORDER BY 1 DESC NULLS FIRST".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![
SortedColumn {
expr: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
order: Some(SortOrder::Desc),
nulls: Some(NullsOrder::First),
},
],
limit: None,
}))],
),
(
b"SELECT 1 ORDER BY 1 ASC NULLS LAST".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![
SortedColumn {
expr: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
order: Some(SortOrder::Asc),
nulls: Some(NullsOrder::Last),
},
],
limit: None,
}))],
),
(
b"SELECT 1 LIMIT 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: Some(Limit {
expr: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
offset: None,
}),
}))],
),
(
b"SELECT 1 LIMIT 1,2".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: Some(Limit {
expr: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
offset: Some(Box::new(Expr::Literal(Literal::Numeric("2".to_owned())))),
}),
}))],
),
(
b"SELECT 1 LIMIT 1 OFFSET 2".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: Some(Limit {
expr: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
offset: Some(Box::new(Expr::Literal(Literal::Numeric("2".to_owned())))),
}),
}))],
),
(
b"SELECT 1 UNION SELECT 2".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![
CompoundSelect {
operator: CompoundOperator::Union,
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
}
}
],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 UNION ALL SELECT 2".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![
CompoundSelect {
operator: CompoundOperator::UnionAll,
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
}
}
],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 EXCEPT SELECT 2".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![
CompoundSelect {
operator: CompoundOperator::Except,
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
}
}
],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 INTERSECT SELECT 2".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![
CompoundSelect {
operator: CompoundOperator::Intersect,
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
}
}
],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo(1, 2)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::TableCall(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
None,
)),
joins: vec![]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM (SELECT 1)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Select(
Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
},
None,
)),
joins: vec![]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM (tbl_name)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Sub(
FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("tbl_name".to_owned()), alias: None },
None,
None
)),
joins: vec![]
},
None,
)),
joins: vec![]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo INDEXED BY bar".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
Some(Indexed::IndexedBy(Name::Ident("bar".to_owned()))),
)),
joins: vec![]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo NOT INDEXED".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
Some(Indexed::NotIndexed),
)),
joins: vec![]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo, bar".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![
JoinedSelectTable {
operator: JoinOperator::Comma,
table: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("bar".to_owned()), alias: None },
None,
None,
)),
constraint: None,
}
]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo, bar".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![
JoinedSelectTable {
operator: JoinOperator::Comma,
table: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("bar".to_owned()), alias: None },
None,
None,
)),
constraint: None,
}
]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo JOIN bar".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![
JoinedSelectTable {
operator: JoinOperator::TypedJoin(None),
table: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("bar".to_owned()), alias: None },
None,
None,
)),
constraint: None,
}
]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo NATURAL JOIN bar".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![
JoinedSelectTable {
operator: JoinOperator::TypedJoin(Some(JoinType::NATURAL)),
table: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("bar".to_owned()), alias: None },
None,
None,
)),
constraint: None,
}
]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo CROSS JOIN bar".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![
JoinedSelectTable {
operator: JoinOperator::TypedJoin(Some(JoinType::INNER|JoinType::CROSS)),
table: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("bar".to_owned()), alias: None },
None,
None,
)),
constraint: None,
}
]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo LEFT JOIN bar".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![
JoinedSelectTable {
operator: JoinOperator::TypedJoin(Some(JoinType::LEFT|JoinType::OUTER)),
table: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("bar".to_owned()), alias: None },
None,
None,
)),
constraint: None,
}
]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo RIGHT JOIN bar".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![
JoinedSelectTable {
operator: JoinOperator::TypedJoin(Some(JoinType::RIGHT|JoinType::OUTER)),
table: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("bar".to_owned()), alias: None },
None,
None,
)),
constraint: None,
}
]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo FULL JOIN bar".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![
JoinedSelectTable {
operator: JoinOperator::TypedJoin(Some(JoinType::LEFT | JoinType::RIGHT | JoinType::OUTER)),
table: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("bar".to_owned()), alias: None },
None,
None,
)),
constraint: None,
}
]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo INNER JOIN bar".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![
JoinedSelectTable {
operator: JoinOperator::TypedJoin(Some(JoinType::INNER)),
table: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("bar".to_owned()), alias: None },
None,
None,
)),
constraint: None,
}
]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo NATURAL INNER JOIN bar".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![
JoinedSelectTable {
operator: JoinOperator::TypedJoin(Some(JoinType::NATURAL | JoinType::INNER)),
table: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("bar".to_owned()), alias: None },
None,
None,
)),
constraint: None,
}
]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo NATURAL LEFT OUTER JOIN bar".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![
JoinedSelectTable {
operator: JoinOperator::TypedJoin(Some(JoinType::NATURAL | JoinType::LEFT | JoinType::OUTER)),
table: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("bar".to_owned()), alias: None },
None,
None,
)),
constraint: None,
}
]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo JOIN bar ON 1 = 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![
JoinedSelectTable {
operator: JoinOperator::TypedJoin(None),
table: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("bar".to_owned()), alias: None },
None,
None,
)),
constraint: Some(JoinConstraint::On(Box::new(Expr::Binary(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::Equals,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)))),
}
]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo JOIN bar USING (col_1)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![
JoinedSelectTable {
operator: JoinOperator::TypedJoin(None),
table: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("bar".to_owned()), alias: None },
None,
None,
)),
constraint: Some(JoinConstraint::Using(vec![
Name::Ident("col_1".to_owned()),
])),
}
]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo JOIN bar bar_alias USING (col_1)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![
JoinedSelectTable {
operator: JoinOperator::TypedJoin(None),
table: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("bar".to_owned()), alias: None },
Some(As::Elided(Name::Ident("bar_alias".to_owned()))),
None,
)),
constraint: Some(JoinConstraint::Using(vec![
Name::Ident("col_1".to_owned()),
])),
}
]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo JOIN bar(1, 2)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![
JoinedSelectTable {
operator: JoinOperator::TypedJoin(None),
table: Box::new(SelectTable::TableCall(
QualifiedName { db_name: None, name: Name::Ident("bar".to_owned()), alias: None },
vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
None,
)),
constraint: None,
}
]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo JOIN (VALUES (1,2), (3, 4))".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![
JoinedSelectTable {
operator: JoinOperator::TypedJoin(None),
table: Box::new(SelectTable::Select(
Select {
with: None,
body: SelectBody {
select: OneSelect::Values(vec![
vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned())))
],
vec![
Box::new(Expr::Literal(Literal::Numeric("3".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("4".to_owned())))
],
]),
compounds: vec![],
},
order_by: vec![],
limit: None,
},
None,
)),
constraint: None,
}
]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo JOIN (bar)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![
JoinedSelectTable {
operator: JoinOperator::TypedJoin(None),
table: Box::new(SelectTable::Sub(
FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("bar".to_owned()), alias: None },
None,
None,
)),
joins: vec![]
},
None,
)),
constraint: None,
}
]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo WHERE 1 = 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![]
}),
where_clause: Some(Box::new(Expr::Binary(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::Equals,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
))),
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo GROUP BY 1 = 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![]
}),
where_clause: None,
group_by: Some(GroupBy {
exprs: vec![
Box::new(Expr::Binary(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::Equals,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
],
having: None,
}),
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo GROUP BY 1 = 1 HAVING 1 = 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![]
}),
where_clause: None,
group_by: Some(GroupBy {
exprs: vec![
Box::new(Expr::Binary(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::Equals,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
],
having: Some(Box::new(Expr::Binary(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::Equals,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
))),
}),
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT 1 FROM foo GROUP BY 1 = 1 HAVING 1 = 1".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
None,
None,
)),
joins: vec![]
}),
where_clause: None,
group_by: Some(GroupBy {
exprs: vec![
Box::new(Expr::Binary(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::Equals,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
)),
],
having: Some(Box::new(Expr::Binary(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Operator::Equals,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
))),
}),
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT * FROM t0 WINDOW JOIN t0;".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Star],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("t0".to_owned()), alias: None },
Some(As::Elided(Name::Ident("WINDOW".to_owned()))),
None,
)),
joins: vec![
JoinedSelectTable {
operator: JoinOperator::TypedJoin(None),
table: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("t0".to_owned()), alias: None },
None,
None,
)),
constraint: None,
}
]
}),
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT * FROM t0 WINDOW window_1 AS (PARTITION BY product)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Star],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("t0".to_owned()), alias: None },
None,
None,
)),
joins: vec![]
}),
where_clause: None,
group_by: None,
window_clause: vec![
WindowDef {
name: Name::Ident("window_1".to_owned()),
window: Window {
base: None,
partition_by: vec![
Box::new(Expr::Id(Name::Ident("product".to_owned()))),
],
order_by: vec![],
frame_clause: None,
},
}
],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
(
b"SELECT * FROM t0 WINDOW window_1 AS (PARTITION BY product), window_2 AS (PARTITION BY product_2)".as_slice(),
vec![Cmd::Stmt(Stmt::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Star],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName { db_name: None, name: Name::Ident("t0".to_owned()), alias: None },
None,
None,
)),
joins: vec![]
}),
where_clause: None,
group_by: None,
window_clause: vec![
WindowDef {
name: Name::Ident("window_1".to_owned()),
window: Window {
base: None,
partition_by: vec![
Box::new(Expr::Id(Name::Ident("product".to_owned()))),
],
order_by: vec![],
frame_clause: None,
},
},
WindowDef {
name: Name::Ident("window_2".to_owned()),
window: Window {
base: None,
partition_by: vec![
Box::new(Expr::Id(Name::Ident("product_2".to_owned()))),
],
order_by: vec![],
frame_clause: None,
},
}
],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}))],
),
// parse Analyze
(
b"ANALYZE".as_slice(),
vec![Cmd::Stmt(Stmt::Analyze {
name: None,
})],
),
(
b"ANALYZE foo".as_slice(),
vec![Cmd::Stmt(Stmt::Analyze {
name: Some(QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None }),
})],
),
// parse attach
(
b"ATTACH DATABASE 'foo' AS bar".as_slice(),
vec![Cmd::Stmt(Stmt::Attach {
expr: Box::new(Expr::Literal(Literal::String("'foo'".to_owned()))),
db_name: Box::new(Expr::Id(Name::Ident("bar".to_owned()))),
key: None,
})],
),
(
b"ATTACH 'foo' AS bar".as_slice(),
vec![Cmd::Stmt(Stmt::Attach {
expr: Box::new(Expr::Literal(Literal::String("'foo'".to_owned()))),
db_name: Box::new(Expr::Id(Name::Ident("bar".to_owned()))),
key: None,
})],
),
(
b"ATTACH 'foo' AS bar key baz".as_slice(),
vec![Cmd::Stmt(Stmt::Attach {
expr: Box::new(Expr::Literal(Literal::String("'foo'".to_owned()))),
db_name: Box::new(Expr::Id(Name::Ident("bar".to_owned()))),
key: Some(Box::new(Expr::Id(Name::Ident("baz".to_owned())))),
})],
),
// parse detach
(
b"DETACH DATABASE bar".as_slice(),
vec![Cmd::Stmt(Stmt::Detach {
name: Box::new(Expr::Id(Name::Ident("bar".to_owned()))),
})],
),
(
b"DETACH bar".as_slice(),
vec![Cmd::Stmt(Stmt::Detach {
name: Box::new(Expr::Id(Name::Ident("bar".to_owned()))),
})],
),
// parse pragma
(
b"PRAGMA foreign_keys = ON".as_slice(),
vec![Cmd::Stmt(Stmt::Pragma {
name: QualifiedName { db_name: None, name: Name::Ident("foreign_keys".to_owned()), alias: None },
body: Some(PragmaBody::Equals(Box::new(Expr::Literal(Literal::Keyword("ON".to_owned()))))),
})],
),
(
b"PRAGMA foreign_keys = DELETE".as_slice(),
vec![Cmd::Stmt(Stmt::Pragma {
name: QualifiedName { db_name: None, name: Name::Ident("foreign_keys".to_owned()), alias: None },
body: Some(PragmaBody::Equals(Box::new(Expr::Literal(Literal::Keyword("DELETE".to_owned()))))),
})],
),
(
b"PRAGMA foreign_keys = DEFAULT".as_slice(),
vec![Cmd::Stmt(Stmt::Pragma {
name: QualifiedName { db_name: None, name: Name::Ident("foreign_keys".to_owned()), alias: None },
body: Some(PragmaBody::Equals(Box::new(Expr::Literal(Literal::Keyword("DEFAULT".to_owned()))))),
})],
),
(
b"PRAGMA foreign_keys".as_slice(),
vec![Cmd::Stmt(Stmt::Pragma {
name: QualifiedName { db_name: None, name: Name::Ident("foreign_keys".to_owned()), alias: None },
body: None,
})],
),
(
b"PRAGMA foreign_keys = 1".as_slice(),
vec![Cmd::Stmt(Stmt::Pragma {
name: QualifiedName { db_name: None, name: Name::Ident("foreign_keys".to_owned()), alias: None },
body: Some(PragmaBody::Equals(Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))))),
})],
),
(
b"PRAGMA foreign_keys = test".as_slice(),
vec![Cmd::Stmt(Stmt::Pragma {
name: QualifiedName { db_name: None, name: Name::Ident("foreign_keys".to_owned()), alias: None },
body: Some(PragmaBody::Equals(Box::new(Expr::Name(Name::Ident("test".to_owned()))))),
})],
),
(
b"PRAGMA foreign_keys".as_slice(),
vec![Cmd::Stmt(Stmt::Pragma {
name: QualifiedName { db_name: None, name: Name::Ident("foreign_keys".to_owned()), alias: None },
body: None,
})],
),
// parse vacuum
(
b"VACUUM".as_slice(),
vec![Cmd::Stmt(Stmt::Vacuum {
name: None,
into: None,
})],
),
(
b"VACUUM INTO 'foo'".as_slice(),
vec![Cmd::Stmt(Stmt::Vacuum {
name: None,
into: Some(Box::new(Expr::Literal(Literal::String("'foo'".to_owned())))),
})],
),
(
b"VACUUM INTO foo".as_slice(),
vec![Cmd::Stmt(Stmt::Vacuum {
name: None,
into: Some(Box::new(Expr::Id(Name::Ident("foo".to_owned())))),
})],
),
(
b"VACUUM foo".as_slice(),
vec![Cmd::Stmt(Stmt::Vacuum {
name: Some(Name::Ident("foo".to_owned())),
into: None,
})],
),
(
b"VACUUM foo INTO 'bar'".as_slice(),
vec![Cmd::Stmt(Stmt::Vacuum {
name: Some(Name::Ident("foo".to_owned())),
into: Some(Box::new(Expr::Literal(Literal::String("'bar'".to_owned())))),
})],
),
// parse alter
(
b"ALTER TABLE foo RENAME TO bar".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::RenameTo(Name::Ident("bar".to_owned())),
})],
),
(
b"ALTER TABLE foo RENAME baz TO bar".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::RenameColumn {
old: Name::Ident("baz".to_owned()),
new: Name::Ident("bar".to_owned())
},
})],
),
(
b"ALTER TABLE foo RENAME COLUMN baz TO bar".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::RenameColumn {
old: Name::Ident("baz".to_owned()),
new: Name::Ident("bar".to_owned())
},
})],
),
(
b"ALTER TABLE foo DROP baz".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::DropColumn(Name::Ident("baz".to_owned())),
})],
),
(
b"ALTER TABLE foo DROP COLUMN baz".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::DropColumn(Name::Ident("baz".to_owned())),
})],
),
(
b"ALTER TABLE foo ADD baz".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: None,
constraints: vec![],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER DEFAULT 1".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::Default(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned())))
),
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER DEFAULT (1)".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::Default(
Box::new(Expr::Parenthesized(vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
]))
),
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER DEFAULT +1".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::Default(
Box::new(Expr::Unary(
UnaryOperator::Positive,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
))
),
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER DEFAULT -1".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::Default(
Box::new(Expr::Unary(
UnaryOperator::Negative,
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
))
),
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER DEFAULT hello".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::Default(
Box::new(Expr::Id(Name::Ident("hello".to_owned())))
),
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER NULL".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::NotNull {
nullable: true,
conflict_clause: None,
},
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER NOT NULL ON CONFLICT IGNORE".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::NotNull {
nullable: false,
conflict_clause: Some(ResolveType::Ignore),
},
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER NOT NULL ON CONFLICT REPLACE".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::NotNull {
nullable: false,
conflict_clause: Some(ResolveType::Replace),
},
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER NOT NULL ON CONFLICT ROLLBACK".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::NotNull {
nullable: false,
conflict_clause: Some(ResolveType::Rollback),
},
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER NOT NULL ON CONFLICT ROLLBACK".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::NotNull {
nullable: false,
conflict_clause: Some(ResolveType::Rollback),
},
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER PRIMARY KEY".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::PrimaryKey {
order: None,
conflict_clause: None,
auto_increment: false,
}
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER PRIMARY KEY ASC ON CONFLICT ROLLBACK AUTOINCREMENT".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::PrimaryKey {
order: Some(SortOrder::Asc),
conflict_clause: Some(ResolveType::Rollback),
auto_increment: true,
}
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER UNIQUE".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::Unique(None),
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER UNIQUE ON CONFLICT ROLLBACK".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::Unique(Some(ResolveType::Rollback)),
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER CHECK (1)".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::Check(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
),
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER CHECK (1)".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::Check(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
),
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER REFERENCES bar".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::ForeignKey {
clause: ForeignKeyClause {
tbl_name: Name::Ident("bar".to_owned()),
columns: vec![],
args: vec![]
},
deref_clause: None
},
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER REFERENCES bar(test, test_2) MATCH test_3 ON INSERT SET NULL".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::ForeignKey {
clause: ForeignKeyClause {
tbl_name: Name::Ident("bar".to_owned()),
columns: vec![
IndexedColumn {
col_name: Name::Ident("test".to_owned()),
collation_name: None,
order: None,
},
IndexedColumn {
col_name: Name::Ident("test_2".to_owned()),
collation_name: None,
order: None,
},
],
args: vec![
RefArg::Match(Name::Ident("test_3".to_owned())),
RefArg::OnInsert(RefAct::SetNull),
]
},
deref_clause: None
},
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER REFERENCES bar(test, test_2) MATCH test_3 ON UPDATE SET NULL".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::ForeignKey {
clause: ForeignKeyClause {
tbl_name: Name::Ident("bar".to_owned()),
columns: vec![
IndexedColumn {
col_name: Name::Ident("test".to_owned()),
collation_name: None,
order: None,
},
IndexedColumn {
col_name: Name::Ident("test_2".to_owned()),
collation_name: None,
order: None,
},
],
args: vec![
RefArg::Match(Name::Ident("test_3".to_owned())),
RefArg::OnUpdate(RefAct::SetNull),
]
},
deref_clause: None
},
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER REFERENCES bar(test, test_2) MATCH test_3 ON DELETE SET NULL".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::ForeignKey {
clause: ForeignKeyClause {
tbl_name: Name::Ident("bar".to_owned()),
columns: vec![
IndexedColumn {
col_name: Name::Ident("test".to_owned()),
collation_name: None,
order: None,
},
IndexedColumn {
col_name: Name::Ident("test_2".to_owned()),
collation_name: None,
order: None,
},
],
args: vec![
RefArg::Match(Name::Ident("test_3".to_owned())),
RefArg::OnDelete(RefAct::SetNull),
]
},
deref_clause: None
},
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER REFERENCES bar(test, test_2) MATCH test_3 ON DELETE SET DEFAULT".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::ForeignKey {
clause: ForeignKeyClause {
tbl_name: Name::Ident("bar".to_owned()),
columns: vec![
IndexedColumn {
col_name: Name::Ident("test".to_owned()),
collation_name: None,
order: None,
},
IndexedColumn {
col_name: Name::Ident("test_2".to_owned()),
collation_name: None,
order: None,
},
],
args: vec![
RefArg::Match(Name::Ident("test_3".to_owned())),
RefArg::OnDelete(RefAct::SetDefault),
]
},
deref_clause: None
},
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER REFERENCES bar(test, test_2) MATCH test_3 ON DELETE CASCADE".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::ForeignKey {
clause: ForeignKeyClause {
tbl_name: Name::Ident("bar".to_owned()),
columns: vec![
IndexedColumn {
col_name: Name::Ident("test".to_owned()),
collation_name: None,
order: None,
},
IndexedColumn {
col_name: Name::Ident("test_2".to_owned()),
collation_name: None,
order: None,
},
],
args: vec![
RefArg::Match(Name::Ident("test_3".to_owned())),
RefArg::OnDelete(RefAct::Cascade),
]
},
deref_clause: None
},
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER REFERENCES bar(test, test_2) MATCH test_3 ON DELETE RESTRICT".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::ForeignKey {
clause: ForeignKeyClause {
tbl_name: Name::Ident("bar".to_owned()),
columns: vec![
IndexedColumn {
col_name: Name::Ident("test".to_owned()),
collation_name: None,
order: None,
},
IndexedColumn {
col_name: Name::Ident("test_2".to_owned()),
collation_name: None,
order: None,
},
],
args: vec![
RefArg::Match(Name::Ident("test_3".to_owned())),
RefArg::OnDelete(RefAct::Restrict),
]
},
deref_clause: None
},
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER REFERENCES bar(test, test_2) MATCH test_3 ON DELETE NO ACTION".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::ForeignKey {
clause: ForeignKeyClause {
tbl_name: Name::Ident("bar".to_owned()),
columns: vec![
IndexedColumn {
col_name: Name::Ident("test".to_owned()),
collation_name: None,
order: None,
},
IndexedColumn {
col_name: Name::Ident("test_2".to_owned()),
collation_name: None,
order: None,
},
],
args: vec![
RefArg::Match(Name::Ident("test_3".to_owned())),
RefArg::OnDelete(RefAct::NoAction),
]
},
deref_clause: None
},
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER REFERENCES bar DEFERRABLE".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::ForeignKey {
clause: ForeignKeyClause {
tbl_name: Name::Ident("bar".to_owned()),
columns: vec![],
args: vec![]
},
deref_clause: Some(DeferSubclause {
deferrable: true,
init_deferred: None,
})
},
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER REFERENCES bar NOT DEFERRABLE INITIALLY IMMEDIATE".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::ForeignKey {
clause: ForeignKeyClause {
tbl_name: Name::Ident("bar".to_owned()),
columns: vec![],
args: vec![]
},
deref_clause: Some(DeferSubclause {
deferrable: false,
init_deferred: Some(InitDeferredPred::InitiallyImmediate),
})
},
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER REFERENCES bar NOT DEFERRABLE INITIALLY DEFERRED".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::ForeignKey {
clause: ForeignKeyClause {
tbl_name: Name::Ident("bar".to_owned()),
columns: vec![],
args: vec![]
},
deref_clause: Some(DeferSubclause {
deferrable: false,
init_deferred: Some(InitDeferredPred::InitiallyDeferred),
})
},
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER REFERENCES bar NOT DEFERRABLE INITIALLY DEFERRED".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::ForeignKey {
clause: ForeignKeyClause {
tbl_name: Name::Ident("bar".to_owned()),
columns: vec![],
args: vec![]
},
deref_clause: Some(DeferSubclause {
deferrable: false,
init_deferred: Some(InitDeferredPred::InitiallyDeferred),
})
},
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER COLLATE bar".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::Collate {
collation_name: Name::Ident("bar".to_owned()),
},
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER GENERATED ALWAYS AS (1)".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::Generated {
expr: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
typ: None,
},
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER AS (1)".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::Generated {
expr: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
typ: None,
},
},
],
}),
})],
),
(
b"ALTER TABLE foo ADD COLUMN baz INTEGER AS (1) STORED".as_slice(),
vec![Cmd::Stmt(Stmt::AlterTable {
name: QualifiedName { db_name: None, name: Name::Ident("foo".to_owned()), alias: None },
body: AlterTableBody::AddColumn(ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![
NamedColumnConstraint {
name: None,
constraint: ColumnConstraint::Generated {
expr: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
typ: Some(Name::Ident("STORED".to_owned())),
},
},
],
}),
})],
),
// parse create index
(
b"CREATE INDEX idx_foo ON foo (bar)".as_slice(),
vec![Cmd::Stmt(Stmt::CreateIndex {
unique: false,
if_not_exists: false,
idx_name: QualifiedName {
db_name: None,
name: Name::Ident("idx_foo".to_owned()),
alias: None,
},
tbl_name: Name::Ident("foo".to_owned()),
columns: vec![SortedColumn {
expr: Box::new(Expr::Id(Name::Ident("bar".to_owned()))),
order: None,
nulls: None,
}],
where_clause: None,
})],
),
(
b"CREATE UNIQUE INDEX IF NOT EXISTS idx_foo ON foo (bar) WHERE 1".as_slice(),
vec![Cmd::Stmt(Stmt::CreateIndex {
unique: true,
if_not_exists: true,
idx_name: QualifiedName {
db_name: None,
name: Name::Ident("idx_foo".to_owned()),
alias: None,
},
tbl_name: Name::Ident("foo".to_owned()),
columns: vec![SortedColumn {
expr: Box::new(Expr::Id(Name::Ident("bar".to_owned()))),
order: None,
nulls: None,
}],
where_clause: Some(Box::new(
Expr::Literal(Literal::Numeric("1".to_owned()))
)),
})],
),
// parse create table
(
b"CREATE TABLE foo (column)".as_slice(),
vec![Cmd::Stmt(Stmt::CreateTable {
temporary: false,
if_not_exists: false,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
body: CreateTableBody::ColumnsAndConstraints {
columns: vec![
ColumnDefinition {
col_name: Name::Ident("column".to_owned()),
col_type: None,
constraints: vec![],
},
],
constraints: vec![],
options: TableOptions::NONE,
},
})],
),
(
b"CREATE TABLE foo AS SELECT 1".as_slice(),
vec![Cmd::Stmt(Stmt::CreateTable {
temporary: false,
if_not_exists: false,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
body: CreateTableBody::AsSelect(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![
ResultColumn::Expr(Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))), None)
],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![]
},
order_by: vec![],
limit: None,
}),
})],
),
(
b"CREATE TEMP TABLE IF NOT EXISTS foo (bar, baz INTEGER, CONSTRAINT tbl_cons PRIMARY KEY (bar AUTOINCREMENT) ON CONFLICT ROLLBACK) STRICT".as_slice(),
vec![Cmd::Stmt(Stmt::CreateTable {
temporary: true,
if_not_exists: true,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
body: CreateTableBody::ColumnsAndConstraints {
columns: vec![
ColumnDefinition {
col_name: Name::Ident("bar".to_owned()),
col_type: None,
constraints: vec![],
},
ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![],
},
],
constraints: vec![
NamedTableConstraint {
name: Some(Name::Ident("tbl_cons".to_owned())),
constraint: TableConstraint::PrimaryKey {
columns: vec![
SortedColumn {
expr: Box::new(Expr::Id(Name::Ident("bar".to_owned()))),
order: None,
nulls: None,
},
],
auto_increment: true,
conflict_clause: Some(ResolveType::Rollback)
}
},
],
options: TableOptions::STRICT,
},
})],
),
(
b"CREATE TEMP TABLE IF NOT EXISTS foo (bar, baz INTEGER, UNIQUE (bar) ON CONFLICT ROLLBACK) WITHOUT ROWID".as_slice(),
vec![Cmd::Stmt(Stmt::CreateTable {
temporary: true,
if_not_exists: true,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
body: CreateTableBody::ColumnsAndConstraints {
columns: vec![
ColumnDefinition {
col_name: Name::Ident("bar".to_owned()),
col_type: None,
constraints: vec![],
},
ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![],
},
],
constraints: vec![
NamedTableConstraint {
name: None,
constraint: TableConstraint::Unique {
columns: vec![
SortedColumn {
expr: Box::new(Expr::Id(Name::Ident("bar".to_owned()))),
order: None,
nulls: None,
},
],
conflict_clause: Some(ResolveType::Rollback)
}
},
],
options: TableOptions::WITHOUT_ROWID,
},
})],
),
(
b"CREATE TEMP TABLE IF NOT EXISTS foo (bar, baz INTEGER, CHECK (1))".as_slice(),
vec![Cmd::Stmt(Stmt::CreateTable {
temporary: true,
if_not_exists: true,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
body: CreateTableBody::ColumnsAndConstraints {
columns: vec![
ColumnDefinition {
col_name: Name::Ident("bar".to_owned()),
col_type: None,
constraints: vec![],
},
ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![],
},
],
constraints: vec![
NamedTableConstraint {
name: None,
constraint: TableConstraint::Check(Box::new(
Expr::Literal(Literal::Numeric("1".to_owned()))
)),
},
],
options: TableOptions::NONE,
},
})],
),
(
b"CREATE TEMP TABLE IF NOT EXISTS foo (bar, baz INTEGER, FOREIGN KEY (bar) REFERENCES foo_2(bar_2), CHECK (1))".as_slice(),
vec![Cmd::Stmt(Stmt::CreateTable {
temporary: true,
if_not_exists: true,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
body: CreateTableBody::ColumnsAndConstraints {
columns: vec![
ColumnDefinition {
col_name: Name::Ident("bar".to_owned()),
col_type: None,
constraints: vec![],
},
ColumnDefinition {
col_name: Name::Ident("baz".to_owned()),
col_type: Some(Type {
name: "INTEGER".to_owned(),
size: None,
}),
constraints: vec![],
},
],
constraints: vec![
NamedTableConstraint {
name: None,
constraint: TableConstraint::ForeignKey {
columns: vec![
IndexedColumn {
col_name: Name::Ident("bar".to_owned()),
collation_name: None,
order: None,
},
],
clause: ForeignKeyClause {
tbl_name: Name::Ident("foo_2".to_owned()),
columns: vec![
IndexedColumn {
col_name: Name::Ident("bar_2".to_owned()),
collation_name: None,
order: None,
},
],
args: vec![],
},
deref_clause: None,
},
},
NamedTableConstraint {
name: None,
constraint: TableConstraint::Check(Box::new(
Expr::Literal(Literal::Numeric("1".to_owned()))
)),
},
],
options: TableOptions::NONE,
},
})],
),
// parse create trigger
(
b"CREATE TRIGGER foo INSERT ON bar BEGIN SELECT 1; END".as_slice(),
vec![Cmd::Stmt(Stmt::CreateTrigger {
temporary: false,
if_not_exists: false,
trigger_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
time: None,
event: TriggerEvent::Insert,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("bar".to_owned()),
alias: None,
},
for_each_row: false,
when_clause: None,
commands: vec![
TriggerCmd::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
})
],
})],
),
(
b"CREATE TEMP TRIGGER IF NOT EXISTS foo AFTER UPDATE ON bar FOR EACH ROW WHEN 1 BEGIN SELECT 1; END".as_slice(),
vec![Cmd::Stmt(Stmt::CreateTrigger {
temporary: true,
if_not_exists: true,
trigger_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
time: Some(TriggerTime::After),
event: TriggerEvent::Update,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("bar".to_owned()),
alias: None,
},
for_each_row: true,
when_clause: Some(Box::new(Expr::Literal(Literal::Numeric("1".to_owned())))),
commands: vec![
TriggerCmd::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
})
],
})],
),
(
b"CREATE TEMP TRIGGER IF NOT EXISTS foo BEFORE DELETE ON bar FOR EACH ROW WHEN 1 BEGIN SELECT 1; END".as_slice(),
vec![Cmd::Stmt(Stmt::CreateTrigger {
temporary: true,
if_not_exists: true,
trigger_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
time: Some(TriggerTime::Before),
event: TriggerEvent::Delete,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("bar".to_owned()),
alias: None,
},
for_each_row: true,
when_clause: Some(Box::new(Expr::Literal(Literal::Numeric("1".to_owned())))),
commands: vec![
TriggerCmd::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
})
],
})],
),
(
b"CREATE TEMP TRIGGER IF NOT EXISTS foo INSTEAD OF UPDATE OF baz, bar ON bar FOR EACH ROW WHEN 1 BEGIN SELECT 1; END".as_slice(),
vec![Cmd::Stmt(Stmt::CreateTrigger {
temporary: true,
if_not_exists: true,
trigger_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
time: Some(TriggerTime::InsteadOf),
event: TriggerEvent::UpdateOf(vec![
Name::Ident("baz".to_owned()),
Name::Ident("bar".to_owned()),
]),
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("bar".to_owned()),
alias: None,
},
for_each_row: true,
when_clause: Some(Box::new(Expr::Literal(Literal::Numeric("1".to_owned())))),
commands: vec![
TriggerCmd::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
})
],
})],
),
(
b"CREATE TRIGGER foo INSERT ON bar BEGIN INSERT INTO foo VALUES (1, 2); END".as_slice(),
vec![Cmd::Stmt(Stmt::CreateTrigger {
temporary: false,
if_not_exists: false,
trigger_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
time: None,
event: TriggerEvent::Insert,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("bar".to_owned()),
alias: None,
},
for_each_row: false,
when_clause: None,
commands: vec![
TriggerCmd::Insert {
or_conflict: None,
tbl_name: Name::Ident("foo".to_owned()),
col_names: vec![],
select: Select {
with: None,
body: SelectBody {
select: OneSelect::Values(vec![
vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
]),
compounds: vec![],
},
order_by: vec![],
limit: None,
},
upsert: None,
returning: vec![],
},
],
})],
),
(
b"CREATE TRIGGER foo INSERT ON bar BEGIN INSERT OR ROLLBACK INTO foo(bar, baz) VALUES (1, 2); END".as_slice(),
vec![Cmd::Stmt(Stmt::CreateTrigger {
temporary: false,
if_not_exists: false,
trigger_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
time: None,
event: TriggerEvent::Insert,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("bar".to_owned()),
alias: None,
},
for_each_row: false,
when_clause: None,
commands: vec![
TriggerCmd::Insert {
or_conflict: Some(ResolveType::Rollback),
tbl_name: Name::Ident("foo".to_owned()),
col_names: vec![
Name::Ident("bar".to_owned()),
Name::Ident("baz".to_owned()),
],
select: Select {
with: None,
body: SelectBody {
select: OneSelect::Values(vec![
vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
]),
compounds: vec![],
},
order_by: vec![],
limit: None,
},
upsert: None,
returning: vec![],
},
],
})],
),
(
b"CREATE TRIGGER foo INSERT ON bar BEGIN INSERT INTO foo VALUES (1, 2) RETURNING bar, baz; END".as_slice(),
vec![Cmd::Stmt(Stmt::CreateTrigger {
temporary: false,
if_not_exists: false,
trigger_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
time: None,
event: TriggerEvent::Insert,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("bar".to_owned()),
alias: None,
},
for_each_row: false,
when_clause: None,
commands: vec![
TriggerCmd::Insert {
or_conflict: None,
tbl_name: Name::Ident("foo".to_owned()),
col_names: vec![],
select: Select {
with: None,
body: SelectBody {
select: OneSelect::Values(vec![
vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
]),
compounds: vec![],
},
order_by: vec![],
limit: None,
},
upsert: None,
returning: vec![
ResultColumn::Expr(
Box::new(Expr::Id(Name::Ident("bar".to_owned()))),
None,
),
ResultColumn::Expr(
Box::new(Expr::Id(Name::Ident("baz".to_owned()))),
None,
),
],
},
],
})],
),
(
b"CREATE TRIGGER foo INSERT ON bar BEGIN INSERT INTO foo VALUES (1, 2) ON CONFLICT (bar, baz) WHERE 1 DO NOTHING RETURNING bar, baz; END".as_slice(),
vec![Cmd::Stmt(Stmt::CreateTrigger {
temporary: false,
if_not_exists: false,
trigger_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
time: None,
event: TriggerEvent::Insert,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("bar".to_owned()),
alias: None,
},
for_each_row: false,
when_clause: None,
commands: vec![
TriggerCmd::Insert {
or_conflict: None,
tbl_name: Name::Ident("foo".to_owned()),
col_names: vec![],
select: Select {
with: None,
body: SelectBody {
select: OneSelect::Values(vec![
vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
]),
compounds: vec![],
},
order_by: vec![],
limit: None,
},
upsert: Some(Box::new(Upsert {
index: Some(UpsertIndex {
targets: vec![
SortedColumn {
expr: Box::new(Expr::Id(Name::Ident("bar".to_owned()))),
order: None,
nulls: None
},
SortedColumn {
expr: Box::new(Expr::Id(Name::Ident("baz".to_owned()))),
order: None,
nulls: None
},
],
where_clause: Some(Box::new(Expr::Literal(Literal::Numeric("1".to_owned())))),
}),
do_clause: UpsertDo::Nothing,
next: None
})),
returning: vec![
ResultColumn::Expr(
Box::new(Expr::Id(Name::Ident("bar".to_owned()))),
None,
),
ResultColumn::Expr(
Box::new(Expr::Id(Name::Ident("baz".to_owned()))),
None,
),
],
},
],
})],
),
(
b"CREATE TRIGGER foo INSERT ON bar BEGIN INSERT INTO foo VALUES (1, 2) ON CONFLICT DO UPDATE SET (bar, baz) = 1 WHERE 1 RETURNING bar, baz; END".as_slice(),
vec![Cmd::Stmt(Stmt::CreateTrigger {
temporary: false,
if_not_exists: false,
trigger_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
time: None,
event: TriggerEvent::Insert,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("bar".to_owned()),
alias: None,
},
for_each_row: false,
when_clause: None,
commands: vec![
TriggerCmd::Insert {
or_conflict: None,
tbl_name: Name::Ident("foo".to_owned()),
col_names: vec![],
select: Select {
with: None,
body: SelectBody {
select: OneSelect::Values(vec![
vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
]),
compounds: vec![],
},
order_by: vec![],
limit: None,
},
upsert: Some(Box::new(Upsert {
index: None,
do_clause: UpsertDo::Set {
sets: vec![
Set {
col_names: vec![
Name::Ident("bar".to_owned()),
Name::Ident("baz".to_owned()),
],
expr: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
}
],
where_clause: Some(Box::new(Expr::Literal(Literal::Numeric("1".to_owned())))),
},
next: None
})),
returning: vec![
ResultColumn::Expr(
Box::new(Expr::Id(Name::Ident("bar".to_owned()))),
None,
),
ResultColumn::Expr(
Box::new(Expr::Id(Name::Ident("baz".to_owned()))),
None,
),
],
},
],
})],
),
(
b"CREATE TRIGGER foo INSERT ON bar BEGIN INSERT INTO foo VALUES (1, 2) ON CONFLICT (bar, baz) DO NOTHING ON CONFLICT DO NOTHING; END".as_slice(),
vec![Cmd::Stmt(Stmt::CreateTrigger {
temporary: false,
if_not_exists: false,
trigger_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
time: None,
event: TriggerEvent::Insert,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("bar".to_owned()),
alias: None,
},
for_each_row: false,
when_clause: None,
commands: vec![
TriggerCmd::Insert {
or_conflict: None,
tbl_name: Name::Ident("foo".to_owned()),
col_names: vec![],
select: Select {
with: None,
body: SelectBody {
select: OneSelect::Values(vec![
vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
]),
compounds: vec![],
},
order_by: vec![],
limit: None,
},
upsert: Some(Box::new(Upsert {
index: Some(UpsertIndex {
targets: vec![
SortedColumn {
expr: Box::new(Expr::Id(Name::Ident("bar".to_owned()))),
order: None,
nulls: None
},
SortedColumn {
expr: Box::new(Expr::Id(Name::Ident("baz".to_owned()))),
order: None,
nulls: None
},
],
where_clause: None,
}),
do_clause: UpsertDo::Nothing,
next: Some(Box::new(Upsert {
index: None,
do_clause: UpsertDo::Nothing,
next: None,
})),
})),
returning: vec![],
},
],
})],
),
(
b"CREATE TRIGGER foo INSERT ON bar BEGIN UPDATE foo SET bar = 1; END".as_slice(),
vec![Cmd::Stmt(Stmt::CreateTrigger {
temporary: false,
if_not_exists: false,
trigger_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
time: None,
event: TriggerEvent::Insert,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("bar".to_owned()),
alias: None,
},
for_each_row: false,
when_clause: None,
commands: vec![
TriggerCmd::Update {
or_conflict: None,
tbl_name: Name::Ident("foo".to_owned()),
sets: vec![
Set {
col_names: vec![Name::Ident("bar".to_owned())],
expr: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
},
],
from: None,
where_clause: None,
},
],
})],
),
(
b"CREATE TRIGGER foo INSERT ON bar BEGIN DELETE FROM foo; END".as_slice(),
vec![Cmd::Stmt(Stmt::CreateTrigger {
temporary: false,
if_not_exists: false,
trigger_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
time: None,
event: TriggerEvent::Insert,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("bar".to_owned()),
alias: None,
},
for_each_row: false,
when_clause: None,
commands: vec![
TriggerCmd::Delete {
tbl_name: Name::Ident("foo".to_owned()),
where_clause: None,
},
],
})],
),
(
b"CREATE TRIGGER foo INSERT ON bar BEGIN DELETE FROM foo WHERE 1; END".as_slice(),
vec![Cmd::Stmt(Stmt::CreateTrigger {
temporary: false,
if_not_exists: false,
trigger_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
time: None,
event: TriggerEvent::Insert,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("bar".to_owned()),
alias: None,
},
for_each_row: false,
when_clause: None,
commands: vec![
TriggerCmd::Delete {
tbl_name: Name::Ident("foo".to_owned()),
where_clause: Some(Box::new(Expr::Literal(Literal::Numeric("1".to_owned())))),
},
],
})],
),
(
b"CREATE TRIGGER foo INSERT ON bar BEGIN SELECT 1; SELECT 1; END".as_slice(),
vec![Cmd::Stmt(Stmt::CreateTrigger {
temporary: false,
if_not_exists: false,
trigger_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
time: None,
event: TriggerEvent::Insert,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("bar".to_owned()),
alias: None,
},
for_each_row: false,
when_clause: None,
commands: vec![
TriggerCmd::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
}),
TriggerCmd::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
})
],
})],
),
// parse create view
(
b"CREATE VIEW foo AS SELECT 1".as_slice(),
vec![Cmd::Stmt(Stmt::CreateView {
temporary: false,
if_not_exists: false,
view_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
columns: vec![],
select: Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
},
})],
),
(
b"CREATE TEMP VIEW IF NOT EXISTS foo(bar) AS SELECT 1".as_slice(),
vec![Cmd::Stmt(Stmt::CreateView {
temporary: true,
if_not_exists: true,
view_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
columns: vec![
IndexedColumn {
col_name: Name::Ident("bar".to_owned()),
collation_name: None,
order: None,
}
],
select: Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
},
})],
),
// parse CREATE VIRTUAL TABLE
(
b"CREATE VIRTUAL TABLE foo USING bar".as_slice(),
vec![Cmd::Stmt(Stmt::CreateVirtualTable {
if_not_exists: false,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
module_name: Name::Ident("bar".to_owned()),
args: vec![],
})],
),
(
b"CREATE VIRTUAL TABLE foo USING bar()".as_slice(),
vec![Cmd::Stmt(Stmt::CreateVirtualTable {
if_not_exists: false,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
module_name: Name::Ident("bar".to_owned()),
args: vec![],
})],
),
(
b"CREATE VIRTUAL TABLE IF NOT EXISTS foo USING bar(1, 2, ('hello', (3.333), 'world', (1, 2)))".as_slice(),
vec![Cmd::Stmt(Stmt::CreateVirtualTable {
if_not_exists: true,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
module_name: Name::Ident("bar".to_owned()),
args: vec![
"1".to_owned(),
"2".to_owned(),
"('hello', (3.333), 'world', (1, 2))".to_owned(),
],
})],
),
(
b"CREATE VIRTUAL TABLE ft USING fts5(x, tokenize = '''porter'' ''ascii''')".as_slice(),
vec![Cmd::Stmt(Stmt::CreateVirtualTable {
if_not_exists: false,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("ft".to_owned()),
alias: None,
},
module_name: Name::Ident("fts5".to_owned()),
args: vec![
"x".to_owned(),
"tokenize = '''porter'' ''ascii'''".to_owned(),
],
})],
),
// parse delete
(
b"DELETE FROM foo".as_slice(),
vec![Cmd::Stmt(Stmt::Delete {
with: None,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None
},
indexed: None,
where_clause: None,
returning: vec![],
order_by: vec![],
limit: None,
})],
),
(
b"WITH test AS (SELECT 1) DELETE FROM foo NOT INDEXED WHERE 1 RETURNING bar ORDER BY bar LIMIT 1".as_slice(),
vec![Cmd::Stmt(Stmt::Delete {
with: Some(With {
recursive: false,
ctes: vec![
CommonTableExpr {
tbl_name: Name::Ident("test".to_owned()),
columns: vec![],
materialized: Materialized::Any,
select: Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
},
}
],
}),
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None
},
indexed: Some(Indexed::NotIndexed),
where_clause: Some(Box::new(Expr::Literal(Literal::Numeric("1".to_owned())))),
returning: vec![
ResultColumn::Expr(
Box::new(Expr::Id(Name::Ident("bar".to_owned()))),
None,
),
],
order_by: vec![
SortedColumn {
expr: Box::new(Expr::Id(Name::Ident("bar".to_owned()))),
order: None,
nulls: None,
}
],
limit: Some(Limit {
expr: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
offset: None,
}),
})],
),
// parse drop index
(
b"DROP INDEX foo".as_slice(),
vec![Cmd::Stmt(Stmt::DropIndex {
if_exists: false,
idx_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
})],
),
(
b"DROP INDEX IF EXISTS foo".as_slice(),
vec![Cmd::Stmt(Stmt::DropIndex {
if_exists: true,
idx_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
})],
),
// parse drop table
(
b"DROP TABLE foo".as_slice(),
vec![Cmd::Stmt(Stmt::DropTable {
if_exists: false,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
})],
),
(
b"DROP TABLE IF EXISTS foo".as_slice(),
vec![Cmd::Stmt(Stmt::DropTable {
if_exists: true,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
})],
),
// parse drop trigger
(
b"DROP TRIGGER foo".as_slice(),
vec![Cmd::Stmt(Stmt::DropTrigger {
if_exists: false,
trigger_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
})],
),
(
b"DROP TRIGGER IF EXISTS foo".as_slice(),
vec![Cmd::Stmt(Stmt::DropTrigger {
if_exists: true,
trigger_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
})],
),
// parse drop view
(
b"DROP VIEW foo".as_slice(),
vec![Cmd::Stmt(Stmt::DropView {
if_exists: false,
view_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
})],
),
(
b"DROP VIEW IF EXISTS foo".as_slice(),
vec![Cmd::Stmt(Stmt::DropView {
if_exists: true,
view_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
})],
),
// parse insert
(
b"INSERT INTO foo VALUES (1, 2)".as_slice(),
vec![Cmd::Stmt(Stmt::Insert {
with: None,
or_conflict: None,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
columns: vec![],
body: InsertBody::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Values(vec![
vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
]),
compounds: vec![],
},
order_by: vec![],
limit: None,
}, None),
returning: vec![],
})],
),
(
b"REPLACE INTO foo VALUES (1, 2)".as_slice(),
vec![Cmd::Stmt(Stmt::Insert {
with: None,
or_conflict: Some(ResolveType::Replace),
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
columns: vec![],
body: InsertBody::Select(Select {
with: None,
body: SelectBody {
select: OneSelect::Values(vec![
vec![
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
Box::new(Expr::Literal(Literal::Numeric("2".to_owned()))),
],
]),
compounds: vec![],
},
order_by: vec![],
limit: None,
}, None),
returning: vec![],
})],
),
(
b"WITH test AS (SELECT 1) INSERT INTO foo(bar, baz) DEFAULT VALUES RETURNING bar".as_slice(),
vec![Cmd::Stmt(Stmt::Insert {
with: Some(With {
recursive: false,
ctes: vec![
CommonTableExpr {
tbl_name: Name::Ident("test".to_owned()),
columns: vec![],
materialized: Materialized::Any,
select: Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
},
}
],
}),
or_conflict: None,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
columns: vec![
Name::Ident("bar".to_owned()),
Name::Ident("baz".to_owned()),
],
body: InsertBody::DefaultValues,
returning: vec![
ResultColumn::Expr(
Box::new(Expr::Id(Name::Ident("bar".to_owned()))),
None,
),
],
})],
),
(
b"WITH test AS (SELECT 1) REPLACE INTO foo(bar, baz) DEFAULT VALUES RETURNING bar".as_slice(),
vec![Cmd::Stmt(Stmt::Insert {
with: Some(With {
recursive: false,
ctes: vec![
CommonTableExpr {
tbl_name: Name::Ident("test".to_owned()),
columns: vec![],
materialized: Materialized::Any,
select: Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
},
}
],
}),
or_conflict: Some(ResolveType::Replace),
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
columns: vec![
Name::Ident("bar".to_owned()),
Name::Ident("baz".to_owned()),
],
body: InsertBody::DefaultValues,
returning: vec![
ResultColumn::Expr(
Box::new(Expr::Id(Name::Ident("bar".to_owned()))),
None,
),
],
})],
),
// parse update
(
b"UPDATE foo SET bar = 1".as_slice(),
vec![Cmd::Stmt(Stmt::Update {
with: None,
or_conflict: None,
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
indexed: None,
sets: vec![
Set {
col_names: vec![
Name::Ident("bar".to_owned()),
],
expr: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
}
],
from: None,
where_clause: None,
returning: vec![],
order_by: vec![],
limit: None,
})],
),
(
b"WITH test AS (SELECT 1) UPDATE OR REPLACE foo NOT INDEXED SET bar = 1 FROM foo_2 WHERE 1 RETURNING bar ORDER By bar LIMIT 1".as_slice(),
vec![Cmd::Stmt(Stmt::Update {
with: Some(With {
recursive: false,
ctes: vec![
CommonTableExpr {
tbl_name: Name::Ident("test".to_owned()),
columns: vec![],
materialized: Materialized::Any,
select: Select {
with: None,
body: SelectBody {
select: OneSelect::Select {
distinctness: None,
columns: vec![ResultColumn::Expr(
Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
None,
)],
from: None,
where_clause: None,
group_by: None,
window_clause: vec![],
},
compounds: vec![],
},
order_by: vec![],
limit: None,
},
}
],
}),
or_conflict: Some(ResolveType::Replace),
tbl_name: QualifiedName {
db_name: None,
name: Name::Ident("foo".to_owned()),
alias: None,
},
indexed: Some(Indexed::NotIndexed),
sets: vec![
Set {
col_names: vec![
Name::Ident("bar".to_owned()),
],
expr: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
}
],
from: Some(FromClause {
select: Box::new(SelectTable::Table(
QualifiedName {
db_name: None,
name: Name::Ident("foo_2".to_owned()),
alias: None,
},
None,
None,
)),
joins: vec![]
}),
where_clause: Some(Box::new(Expr::Literal(Literal::Numeric("1".to_owned())))),
returning: vec![
ResultColumn::Expr(
Box::new(Expr::Id(Name::Ident("bar".to_owned()))),
None,
),
],
order_by: vec![
SortedColumn {
expr: Box::new(Expr::Id(Name::Ident("bar".to_owned()))),
order: None,
nulls: None,
}
],
limit: Some(Limit {
expr: Box::new(Expr::Literal(Literal::Numeric("1".to_owned()))),
offset: None,
}),
})],
),
];
for (input, expected) in test_cases {
println!("Testing input: {:?}", from_bytes(input));
let mut parser = Parser::new(input);
let mut results = Vec::new();
while let Some(cmd) = parser.next() {
match cmd {
Ok(cmd) => results.push(cmd),
Err(err) => panic!("Parse error: {}", err),
}
}
assert_eq!(results, expected, "Input: {:?}", input);
}
}
}