diff options
Diffstat (limited to 'src/parse.y')
-rw-r--r-- | src/parse.y | 1928 |
1 files changed, 1928 insertions, 0 deletions
diff --git a/src/parse.y b/src/parse.y new file mode 100644 index 0000000..d627f22 --- /dev/null +++ b/src/parse.y @@ -0,0 +1,1928 @@ +%include { +/* +** 2001-09-15 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This file contains SQLite's SQL parser. +** +** The canonical source code to this file ("parse.y") is a Lemon grammar +** file that specifies the input grammar and actions to take while parsing. +** That input file is processed by Lemon to generate a C-language +** implementation of a parser for the given grammer. You might be reading +** this comment as part of the translated C-code. Edits should be made +** to the original parse.y sources. +*/ +} + +// All token codes are small integers with #defines that begin with "TK_" +%token_prefix TK_ + +// The type of the data attached to each token is Token. This is also the +// default type for non-terminals. +// +%token_type {Token} +%default_type {Token} + +// An extra argument to the constructor for the parser, which is available +// to all actions. +%extra_context {Parse *pParse} + +// This code runs whenever there is a syntax error +// +%syntax_error { + UNUSED_PARAMETER(yymajor); /* Silence some compiler warnings */ + if( TOKEN.z[0] ){ + sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN); + }else{ + sqlite3ErrorMsg(pParse, "incomplete input"); + } +} +%stack_overflow { + sqlite3ErrorMsg(pParse, "parser stack overflow"); +} + +// The name of the generated procedure that implements the parser +// is as follows: +%name sqlite3Parser + +// The following text is included near the beginning of the C source +// code file that implements the parser. +// +%include { +#include "sqliteInt.h" + +/* +** Disable all error recovery processing in the parser push-down +** automaton. +*/ +#define YYNOERRORRECOVERY 1 + +/* +** Make yytestcase() the same as testcase() +*/ +#define yytestcase(X) testcase(X) + +/* +** Indicate that sqlite3ParserFree() will never be called with a null +** pointer. +*/ +#define YYPARSEFREENEVERNULL 1 + +/* +** In the amalgamation, the parse.c file generated by lemon and the +** tokenize.c file are concatenated. In that case, sqlite3RunParser() +** has access to the the size of the yyParser object and so the parser +** engine can be allocated from stack. In that case, only the +** sqlite3ParserInit() and sqlite3ParserFinalize() routines are invoked +** and the sqlite3ParserAlloc() and sqlite3ParserFree() routines can be +** omitted. +*/ +#ifdef SQLITE_AMALGAMATION +# define sqlite3Parser_ENGINEALWAYSONSTACK 1 +#endif + +/* +** Alternative datatype for the argument to the malloc() routine passed +** into sqlite3ParserAlloc(). The default is size_t. +*/ +#define YYMALLOCARGTYPE u64 + +/* +** An instance of the following structure describes the event of a +** TRIGGER. "a" is the event type, one of TK_UPDATE, TK_INSERT, +** TK_DELETE, or TK_INSTEAD. If the event is of the form +** +** UPDATE ON (a,b,c) +** +** Then the "b" IdList records the list "a,b,c". +*/ +struct TrigEvent { int a; IdList * b; }; + +struct FrameBound { int eType; Expr *pExpr; }; + +/* +** Disable lookaside memory allocation for objects that might be +** shared across database connections. +*/ +static void disableLookaside(Parse *pParse){ + sqlite3 *db = pParse->db; + pParse->disableLookaside++; + DisableLookaside; +} + +#if !defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) \ + && defined(SQLITE_UDL_CAPABLE_PARSER) +/* +** Issue an error message if an ORDER BY or LIMIT clause occurs on an +** UPDATE or DELETE statement. +*/ +static void updateDeleteLimitError( + Parse *pParse, + ExprList *pOrderBy, + Expr *pLimit +){ + if( pOrderBy ){ + sqlite3ErrorMsg(pParse, "syntax error near \"ORDER BY\""); + }else{ + sqlite3ErrorMsg(pParse, "syntax error near \"LIMIT\""); + } + sqlite3ExprListDelete(pParse->db, pOrderBy); + sqlite3ExprDelete(pParse->db, pLimit); +} +#endif /* SQLITE_ENABLE_UPDATE_DELETE_LIMIT */ + +} // end %include + +// Input is a single SQL command +input ::= cmdlist. +cmdlist ::= cmdlist ecmd. +cmdlist ::= ecmd. +ecmd ::= SEMI. +ecmd ::= cmdx SEMI. +%ifndef SQLITE_OMIT_EXPLAIN +ecmd ::= explain cmdx SEMI. {NEVER-REDUCE} +explain ::= EXPLAIN. { pParse->explain = 1; } +explain ::= EXPLAIN QUERY PLAN. { pParse->explain = 2; } +%endif SQLITE_OMIT_EXPLAIN +cmdx ::= cmd. { sqlite3FinishCoding(pParse); } + +///////////////////// Begin and end transactions. //////////////////////////// +// + +cmd ::= BEGIN transtype(Y) trans_opt. {sqlite3BeginTransaction(pParse, Y);} +trans_opt ::= . +trans_opt ::= TRANSACTION. +trans_opt ::= TRANSACTION nm. +%type transtype {int} +transtype(A) ::= . {A = TK_DEFERRED;} +transtype(A) ::= DEFERRED(X). {A = @X; /*A-overwrites-X*/} +transtype(A) ::= IMMEDIATE(X). {A = @X; /*A-overwrites-X*/} +transtype(A) ::= EXCLUSIVE(X). {A = @X; /*A-overwrites-X*/} +cmd ::= COMMIT|END(X) trans_opt. {sqlite3EndTransaction(pParse,@X);} +cmd ::= ROLLBACK(X) trans_opt. {sqlite3EndTransaction(pParse,@X);} + +savepoint_opt ::= SAVEPOINT. +savepoint_opt ::= . +cmd ::= SAVEPOINT nm(X). { + sqlite3Savepoint(pParse, SAVEPOINT_BEGIN, &X); +} +cmd ::= RELEASE savepoint_opt nm(X). { + sqlite3Savepoint(pParse, SAVEPOINT_RELEASE, &X); +} +cmd ::= ROLLBACK trans_opt TO savepoint_opt nm(X). { + sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &X); +} + +///////////////////// The CREATE TABLE statement //////////////////////////// +// +cmd ::= create_table create_table_args. +create_table ::= createkw temp(T) TABLE ifnotexists(E) nm(Y) dbnm(Z). { + sqlite3StartTable(pParse,&Y,&Z,T,0,0,E); +} +createkw(A) ::= CREATE(A). {disableLookaside(pParse);} + +%type ifnotexists {int} +ifnotexists(A) ::= . {A = 0;} +ifnotexists(A) ::= IF NOT EXISTS. {A = 1;} +%type temp {int} +%ifndef SQLITE_OMIT_TEMPDB +temp(A) ::= TEMP. {A = pParse->db->init.busy==0;} +%endif SQLITE_OMIT_TEMPDB +temp(A) ::= . {A = 0;} +create_table_args ::= LP columnlist conslist_opt(X) RP(E) table_option_set(F). { + sqlite3EndTable(pParse,&X,&E,F,0); +} +create_table_args ::= AS select(S). { + sqlite3EndTable(pParse,0,0,0,S); + sqlite3SelectDelete(pParse->db, S); +} +%type table_option_set {u32} +%type table_option {u32} +table_option_set(A) ::= . {A = 0;} +table_option_set(A) ::= table_option(A). +table_option_set(A) ::= table_option_set(X) COMMA table_option(Y). {A = X|Y;} +table_option(A) ::= WITHOUT nm(X). { + if( X.n==5 && sqlite3_strnicmp(X.z,"rowid",5)==0 ){ + A = TF_WithoutRowid | TF_NoVisibleRowid; + }else{ + A = 0; + sqlite3ErrorMsg(pParse, "unknown table option: %.*s", X.n, X.z); + } +} +table_option(A) ::= nm(X). { + if( X.n==6 && sqlite3_strnicmp(X.z,"strict",6)==0 ){ + A = TF_Strict; + }else{ + A = 0; + sqlite3ErrorMsg(pParse, "unknown table option: %.*s", X.n, X.z); + } +} +columnlist ::= columnlist COMMA columnname carglist. +columnlist ::= columnname carglist. +columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,A,Y);} + +// Declare some tokens early in order to influence their values, to +// improve performance and reduce the executable size. The goal here is +// to get the "jump" operations in ISNULL through ESCAPE to have numeric +// values that are early enough so that all jump operations are clustered +// at the beginning. +// +%token ABORT ACTION AFTER ANALYZE ASC ATTACH BEFORE BEGIN BY CASCADE CAST. +%token CONFLICT DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL. +%token OR AND NOT IS MATCH LIKE_KW BETWEEN IN ISNULL NOTNULL NE EQ. +%token GT LE LT GE ESCAPE. + +// The following directive causes tokens ABORT, AFTER, ASC, etc. to +// fallback to ID if they will not parse as their original value. +// This obviates the need for the "id" nonterminal. +// +%fallback ID + ABORT ACTION AFTER ANALYZE ASC ATTACH BEFORE BEGIN BY CASCADE CAST COLUMNKW + CONFLICT DATABASE DEFERRED DESC DETACH DO + EACH END EXCLUSIVE EXPLAIN FAIL FOR + IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH NO PLAN + QUERY KEY OF OFFSET PRAGMA RAISE RECURSIVE RELEASE REPLACE RESTRICT ROW ROWS + ROLLBACK SAVEPOINT TEMP TRIGGER VACUUM VIEW VIRTUAL WITH WITHOUT + NULLS FIRST LAST +%ifdef SQLITE_OMIT_COMPOUND_SELECT + EXCEPT INTERSECT UNION +%endif SQLITE_OMIT_COMPOUND_SELECT +%ifndef SQLITE_OMIT_WINDOWFUNC + CURRENT FOLLOWING PARTITION PRECEDING RANGE UNBOUNDED + EXCLUDE GROUPS OTHERS TIES +%endif SQLITE_OMIT_WINDOWFUNC +%ifndef SQLITE_OMIT_GENERATED_COLUMNS + GENERATED ALWAYS +%endif + MATERIALIZED + REINDEX RENAME CTIME_KW IF + . +%wildcard ANY. + +// Define operator precedence early so that this is the first occurrence +// of the operator tokens in the grammer. Keeping the operators together +// causes them to be assigned integer values that are close together, +// which keeps parser tables smaller. +// +// The token values assigned to these symbols is determined by the order +// in which lemon first sees them. It must be the case that ISNULL/NOTNULL, +// NE/EQ, GT/LE, and GE/LT are separated by only a single value. See +// the sqlite3ExprIfFalse() routine for additional information on this +// constraint. +// +%left OR. +%left AND. +%right NOT. +%left IS MATCH LIKE_KW BETWEEN IN ISNULL NOTNULL NE EQ. +%left GT LE LT GE. +%right ESCAPE. +%left BITAND BITOR LSHIFT RSHIFT. +%left PLUS MINUS. +%left STAR SLASH REM. +%left CONCAT PTR. +%left COLLATE. +%right BITNOT. +%nonassoc ON. + +// An IDENTIFIER can be a generic identifier, or one of several +// keywords. Any non-standard keyword can also be an identifier. +// +%token_class id ID|INDEXED. + + +// And "ids" is an identifer-or-string. +// +%token_class ids ID|STRING. + +// The name of a column or table can be any of the following: +// +%type nm {Token} +nm(A) ::= id(A). +nm(A) ::= STRING(A). +nm(A) ::= JOIN_KW(A). + +// A typetoken is really zero or more tokens that form a type name such +// as can be found after the column name in a CREATE TABLE statement. +// Multiple tokens are concatenated to form the value of the typetoken. +// +%type typetoken {Token} +typetoken(A) ::= . {A.n = 0; A.z = 0;} +typetoken(A) ::= typename(A). +typetoken(A) ::= typename(A) LP signed RP(Y). { + A.n = (int)(&Y.z[Y.n] - A.z); +} +typetoken(A) ::= typename(A) LP signed COMMA signed RP(Y). { + A.n = (int)(&Y.z[Y.n] - A.z); +} +%type typename {Token} +typename(A) ::= ids(A). +typename(A) ::= typename(A) ids(Y). {A.n=Y.n+(int)(Y.z-A.z);} +signed ::= plus_num. +signed ::= minus_num. + +// The scanpt non-terminal takes a value which is a pointer to the +// input text just past the last token that has been shifted into +// the parser. By surrounding some phrase in the grammar with two +// scanpt non-terminals, we can capture the input text for that phrase. +// For example: +// +// something ::= .... scanpt(A) phrase scanpt(Z). +// +// The text that is parsed as "phrase" is a string starting at A +// and containing (int)(Z-A) characters. There might be some extra +// whitespace on either end of the text, but that can be removed in +// post-processing, if needed. +// +%type scanpt {const char*} +scanpt(A) ::= . { + assert( yyLookahead!=YYNOCODE ); + A = yyLookaheadToken.z; +} +scantok(A) ::= . { + assert( yyLookahead!=YYNOCODE ); + A = yyLookaheadToken; +} + +// "carglist" is a list of additional constraints that come after the +// column name and column type in a CREATE TABLE statement. +// +carglist ::= carglist ccons. +carglist ::= . +ccons ::= CONSTRAINT nm(X). {pParse->constraintName = X;} +ccons ::= DEFAULT scantok(A) term(X). + {sqlite3AddDefaultValue(pParse,X,A.z,&A.z[A.n]);} +ccons ::= DEFAULT LP(A) expr(X) RP(Z). + {sqlite3AddDefaultValue(pParse,X,A.z+1,Z.z);} +ccons ::= DEFAULT PLUS(A) scantok(Z) term(X). + {sqlite3AddDefaultValue(pParse,X,A.z,&Z.z[Z.n]);} +ccons ::= DEFAULT MINUS(A) scantok(Z) term(X). { + Expr *p = sqlite3PExpr(pParse, TK_UMINUS, X, 0); + sqlite3AddDefaultValue(pParse,p,A.z,&Z.z[Z.n]); +} +ccons ::= DEFAULT scantok id(X). { + Expr *p = tokenExpr(pParse, TK_STRING, X); + if( p ){ + sqlite3ExprIdToTrueFalse(p); + testcase( p->op==TK_TRUEFALSE && sqlite3ExprTruthValue(p) ); + } + sqlite3AddDefaultValue(pParse,p,X.z,X.z+X.n); +} + +// In addition to the type name, we also care about the primary key and +// UNIQUE constraints. +// +ccons ::= NULL onconf. +ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);} +ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I). + {sqlite3AddPrimaryKey(pParse,0,R,I,Z);} +ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0,0,0, + SQLITE_IDXTYPE_UNIQUE);} +ccons ::= CHECK LP(A) expr(X) RP(B). {sqlite3AddCheckConstraint(pParse,X,A.z,B.z);} +ccons ::= REFERENCES nm(T) eidlist_opt(TA) refargs(R). + {sqlite3CreateForeignKey(pParse,0,&T,TA,R);} +ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);} +ccons ::= COLLATE ids(C). {sqlite3AddCollateType(pParse, &C);} +ccons ::= GENERATED ALWAYS AS generated. +ccons ::= AS generated. +generated ::= LP expr(E) RP. {sqlite3AddGenerated(pParse,E,0);} +generated ::= LP expr(E) RP ID(TYPE). {sqlite3AddGenerated(pParse,E,&TYPE);} + +// The optional AUTOINCREMENT keyword +%type autoinc {int} +autoinc(X) ::= . {X = 0;} +autoinc(X) ::= AUTOINCR. {X = 1;} + +// The next group of rules parses the arguments to a REFERENCES clause +// that determine if the referential integrity checking is deferred or +// or immediate and which determine what action to take if a ref-integ +// check fails. +// +%type refargs {int} +refargs(A) ::= . { A = OE_None*0x0101; /* EV: R-19803-45884 */} +refargs(A) ::= refargs(A) refarg(Y). { A = (A & ~Y.mask) | Y.value; } +%type refarg {struct {int value; int mask;}} +refarg(A) ::= MATCH nm. { A.value = 0; A.mask = 0x000000; } +refarg(A) ::= ON INSERT refact. { A.value = 0; A.mask = 0x000000; } +refarg(A) ::= ON DELETE refact(X). { A.value = X; A.mask = 0x0000ff; } +refarg(A) ::= ON UPDATE refact(X). { A.value = X<<8; A.mask = 0x00ff00; } +%type refact {int} +refact(A) ::= SET NULL. { A = OE_SetNull; /* EV: R-33326-45252 */} +refact(A) ::= SET DEFAULT. { A = OE_SetDflt; /* EV: R-33326-45252 */} +refact(A) ::= CASCADE. { A = OE_Cascade; /* EV: R-33326-45252 */} +refact(A) ::= RESTRICT. { A = OE_Restrict; /* EV: R-33326-45252 */} +refact(A) ::= NO ACTION. { A = OE_None; /* EV: R-33326-45252 */} +%type defer_subclause {int} +defer_subclause(A) ::= NOT DEFERRABLE init_deferred_pred_opt. {A = 0;} +defer_subclause(A) ::= DEFERRABLE init_deferred_pred_opt(X). {A = X;} +%type init_deferred_pred_opt {int} +init_deferred_pred_opt(A) ::= . {A = 0;} +init_deferred_pred_opt(A) ::= INITIALLY DEFERRED. {A = 1;} +init_deferred_pred_opt(A) ::= INITIALLY IMMEDIATE. {A = 0;} + +conslist_opt(A) ::= . {A.n = 0; A.z = 0;} +conslist_opt(A) ::= COMMA(A) conslist. +conslist ::= conslist tconscomma tcons. +conslist ::= tcons. +tconscomma ::= COMMA. {pParse->constraintName.n = 0;} +tconscomma ::= . +tcons ::= CONSTRAINT nm(X). {pParse->constraintName = X;} +tcons ::= PRIMARY KEY LP sortlist(X) autoinc(I) RP onconf(R). + {sqlite3AddPrimaryKey(pParse,X,R,I,0);} +tcons ::= UNIQUE LP sortlist(X) RP onconf(R). + {sqlite3CreateIndex(pParse,0,0,0,X,R,0,0,0,0, + SQLITE_IDXTYPE_UNIQUE);} +tcons ::= CHECK LP(A) expr(E) RP(B) onconf. + {sqlite3AddCheckConstraint(pParse,E,A.z,B.z);} +tcons ::= FOREIGN KEY LP eidlist(FA) RP + REFERENCES nm(T) eidlist_opt(TA) refargs(R) defer_subclause_opt(D). { + sqlite3CreateForeignKey(pParse, FA, &T, TA, R); + sqlite3DeferForeignKey(pParse, D); +} +%type defer_subclause_opt {int} +defer_subclause_opt(A) ::= . {A = 0;} +defer_subclause_opt(A) ::= defer_subclause(A). + +// The following is a non-standard extension that allows us to declare the +// default behavior when there is a constraint conflict. +// +%type onconf {int} +%type orconf {int} +%type resolvetype {int} +onconf(A) ::= . {A = OE_Default;} +onconf(A) ::= ON CONFLICT resolvetype(X). {A = X;} +orconf(A) ::= . {A = OE_Default;} +orconf(A) ::= OR resolvetype(X). {A = X;} +resolvetype(A) ::= raisetype(A). +resolvetype(A) ::= IGNORE. {A = OE_Ignore;} +resolvetype(A) ::= REPLACE. {A = OE_Replace;} + +////////////////////////// The DROP TABLE ///////////////////////////////////// +// +cmd ::= DROP TABLE ifexists(E) fullname(X). { + sqlite3DropTable(pParse, X, 0, E); +} +%type ifexists {int} +ifexists(A) ::= IF EXISTS. {A = 1;} +ifexists(A) ::= . {A = 0;} + +///////////////////// The CREATE VIEW statement ///////////////////////////// +// +%ifndef SQLITE_OMIT_VIEW +cmd ::= createkw(X) temp(T) VIEW ifnotexists(E) nm(Y) dbnm(Z) eidlist_opt(C) + AS select(S). { + sqlite3CreateView(pParse, &X, &Y, &Z, C, S, T, E); +} +cmd ::= DROP VIEW ifexists(E) fullname(X). { + sqlite3DropTable(pParse, X, 1, E); +} +%endif SQLITE_OMIT_VIEW + +//////////////////////// The SELECT statement ///////////////////////////////// +// +cmd ::= select(X). { + SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0, 0}; + sqlite3Select(pParse, X, &dest); + sqlite3SelectDelete(pParse->db, X); +} + +%type select {Select*} +%destructor select {sqlite3SelectDelete(pParse->db, $$);} +%type selectnowith {Select*} +%destructor selectnowith {sqlite3SelectDelete(pParse->db, $$);} +%type oneselect {Select*} +%destructor oneselect {sqlite3SelectDelete(pParse->db, $$);} + +%include { + /* + ** For a compound SELECT statement, make sure p->pPrior->pNext==p for + ** all elements in the list. And make sure list length does not exceed + ** SQLITE_LIMIT_COMPOUND_SELECT. + */ + static void parserDoubleLinkSelect(Parse *pParse, Select *p){ + assert( p!=0 ); + if( p->pPrior ){ + Select *pNext = 0, *pLoop = p; + int mxSelect, cnt = 1; + while(1){ + pLoop->pNext = pNext; + pLoop->selFlags |= SF_Compound; + pNext = pLoop; + pLoop = pLoop->pPrior; + if( pLoop==0 ) break; + cnt++; + if( pLoop->pOrderBy || pLoop->pLimit ){ + sqlite3ErrorMsg(pParse,"%s clause should come after %s not before", + pLoop->pOrderBy!=0 ? "ORDER BY" : "LIMIT", + sqlite3SelectOpName(pNext->op)); + break; + } + } + if( (p->selFlags & SF_MultiValue)==0 && + (mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 && + cnt>mxSelect + ){ + sqlite3ErrorMsg(pParse, "too many terms in compound SELECT"); + } + } + } + + /* Attach a With object describing the WITH clause to a Select + ** object describing the query for which the WITH clause is a prefix. + */ + static Select *attachWithToSelect(Parse *pParse, Select *pSelect, With *pWith){ + if( pSelect ){ + pSelect->pWith = pWith; + parserDoubleLinkSelect(pParse, pSelect); + }else{ + sqlite3WithDelete(pParse->db, pWith); + } + return pSelect; + } +} + +%ifndef SQLITE_OMIT_CTE +select(A) ::= WITH wqlist(W) selectnowith(X). {A = attachWithToSelect(pParse,X,W);} +select(A) ::= WITH RECURSIVE wqlist(W) selectnowith(X). + {A = attachWithToSelect(pParse,X,W);} +%endif /* SQLITE_OMIT_CTE */ +select(A) ::= selectnowith(X). { + Select *p = X; + if( p ){ + parserDoubleLinkSelect(pParse, p); + } + A = p; /*A-overwrites-X*/ +} + +selectnowith(A) ::= oneselect(A). +%ifndef SQLITE_OMIT_COMPOUND_SELECT +selectnowith(A) ::= selectnowith(A) multiselect_op(Y) oneselect(Z). { + Select *pRhs = Z; + Select *pLhs = A; + if( pRhs && pRhs->pPrior ){ + SrcList *pFrom; + Token x; + x.n = 0; + parserDoubleLinkSelect(pParse, pRhs); + pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0); + pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0); + } + if( pRhs ){ + pRhs->op = (u8)Y; + pRhs->pPrior = pLhs; + if( ALWAYS(pLhs) ) pLhs->selFlags &= ~SF_MultiValue; + pRhs->selFlags &= ~SF_MultiValue; + if( Y!=TK_ALL ) pParse->hasCompound = 1; + }else{ + sqlite3SelectDelete(pParse->db, pLhs); + } + A = pRhs; +} +%type multiselect_op {int} +multiselect_op(A) ::= UNION(OP). {A = @OP; /*A-overwrites-OP*/} +multiselect_op(A) ::= UNION ALL. {A = TK_ALL;} +multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP; /*A-overwrites-OP*/} +%endif SQLITE_OMIT_COMPOUND_SELECT + +oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y) + groupby_opt(P) having_opt(Q) + orderby_opt(Z) limit_opt(L). { + A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L); +} +%ifndef SQLITE_OMIT_WINDOWFUNC +oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y) + groupby_opt(P) having_opt(Q) window_clause(R) + orderby_opt(Z) limit_opt(L). { + A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L); + if( A ){ + A->pWinDefn = R; + }else{ + sqlite3WindowListDelete(pParse->db, R); + } +} +%endif + + +oneselect(A) ::= values(A). + +%type values {Select*} +%destructor values {sqlite3SelectDelete(pParse->db, $$);} +values(A) ::= VALUES LP nexprlist(X) RP. { + A = sqlite3SelectNew(pParse,X,0,0,0,0,0,SF_Values,0); +} +values(A) ::= values(A) COMMA LP nexprlist(Y) RP. { + Select *pRight, *pLeft = A; + pRight = sqlite3SelectNew(pParse,Y,0,0,0,0,0,SF_Values|SF_MultiValue,0); + if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue; + if( pRight ){ + pRight->op = TK_ALL; + pRight->pPrior = pLeft; + A = pRight; + }else{ + A = pLeft; + } +} + +// The "distinct" nonterminal is true (1) if the DISTINCT keyword is +// present and false (0) if it is not. +// +%type distinct {int} +distinct(A) ::= DISTINCT. {A = SF_Distinct;} +distinct(A) ::= ALL. {A = SF_All;} +distinct(A) ::= . {A = 0;} + +// selcollist is a list of expressions that are to become the return +// values of the SELECT statement. The "*" in statements like +// "SELECT * FROM ..." is encoded as a special expression with an +// opcode of TK_ASTERISK. +// +%type selcollist {ExprList*} +%destructor selcollist {sqlite3ExprListDelete(pParse->db, $$);} +%type sclp {ExprList*} +%destructor sclp {sqlite3ExprListDelete(pParse->db, $$);} +sclp(A) ::= selcollist(A) COMMA. +sclp(A) ::= . {A = 0;} +selcollist(A) ::= sclp(A) scanpt(B) expr(X) scanpt(Z) as(Y). { + A = sqlite3ExprListAppend(pParse, A, X); + if( Y.n>0 ) sqlite3ExprListSetName(pParse, A, &Y, 1); + sqlite3ExprListSetSpan(pParse,A,B,Z); +} +selcollist(A) ::= sclp(A) scanpt STAR. { + Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); + A = sqlite3ExprListAppend(pParse, A, p); +} +selcollist(A) ::= sclp(A) scanpt nm(X) DOT STAR. { + Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0); + Expr *pLeft = tokenExpr(pParse, TK_ID, X); + Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight); + A = sqlite3ExprListAppend(pParse,A, pDot); +} + +// An option "AS <id>" phrase that can follow one of the expressions that +// define the result set, or one of the tables in the FROM clause. +// +%type as {Token} +as(X) ::= AS nm(Y). {X = Y;} +as(X) ::= ids(X). +as(X) ::= . {X.n = 0; X.z = 0;} + + +%type seltablist {SrcList*} +%destructor seltablist {sqlite3SrcListDelete(pParse->db, $$);} +%type stl_prefix {SrcList*} +%destructor stl_prefix {sqlite3SrcListDelete(pParse->db, $$);} +%type from {SrcList*} +%destructor from {sqlite3SrcListDelete(pParse->db, $$);} + +// A complete FROM clause. +// +from(A) ::= . {A = 0;} +from(A) ::= FROM seltablist(X). { + A = X; + sqlite3SrcListShiftJoinType(pParse,A); +} + +// "seltablist" is a "Select Table List" - the content of the FROM clause +// in a SELECT statement. "stl_prefix" is a prefix of this list. +// +stl_prefix(A) ::= seltablist(A) joinop(Y). { + if( ALWAYS(A && A->nSrc>0) ) A->a[A->nSrc-1].fg.jointype = (u8)Y; +} +stl_prefix(A) ::= . {A = 0;} +seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) as(Z) on_using(N). { + A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,&N); +} +seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) as(Z) indexed_by(I) on_using(N). { + A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,&N); + sqlite3SrcListIndexedBy(pParse, A, &I); +} +seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z) on_using(N). { + A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,&N); + sqlite3SrcListFuncArgs(pParse, A, E); +} +%ifndef SQLITE_OMIT_SUBQUERY + seltablist(A) ::= stl_prefix(A) LP select(S) RP as(Z) on_using(N). { + A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,S,&N); + } + seltablist(A) ::= stl_prefix(A) LP seltablist(F) RP as(Z) on_using(N). { + if( A==0 && Z.n==0 && N.pOn==0 && N.pUsing==0 ){ + A = F; + }else if( F->nSrc==1 ){ + A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,0,&N); + if( A ){ + SrcItem *pNew = &A->a[A->nSrc-1]; + SrcItem *pOld = F->a; + pNew->zName = pOld->zName; + pNew->zDatabase = pOld->zDatabase; + pNew->pSelect = pOld->pSelect; + if( pNew->pSelect && (pNew->pSelect->selFlags & SF_NestedFrom)!=0 ){ + pNew->fg.isNestedFrom = 1; + } + if( pOld->fg.isTabFunc ){ + pNew->u1.pFuncArg = pOld->u1.pFuncArg; + pOld->u1.pFuncArg = 0; + pOld->fg.isTabFunc = 0; + pNew->fg.isTabFunc = 1; + } + pOld->zName = pOld->zDatabase = 0; + pOld->pSelect = 0; + } + sqlite3SrcListDelete(pParse->db, F); + }else{ + Select *pSubquery; + sqlite3SrcListShiftJoinType(pParse,F); + pSubquery = sqlite3SelectNew(pParse,0,F,0,0,0,0,SF_NestedFrom,0); + A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,pSubquery,&N); + } + } +%endif SQLITE_OMIT_SUBQUERY + +%type dbnm {Token} +dbnm(A) ::= . {A.z=0; A.n=0;} +dbnm(A) ::= DOT nm(X). {A = X;} + +%type fullname {SrcList*} +%destructor fullname {sqlite3SrcListDelete(pParse->db, $$);} +fullname(A) ::= nm(X). { + A = sqlite3SrcListAppend(pParse,0,&X,0); + if( IN_RENAME_OBJECT && A ) sqlite3RenameTokenMap(pParse, A->a[0].zName, &X); +} +fullname(A) ::= nm(X) DOT nm(Y). { + A = sqlite3SrcListAppend(pParse,0,&X,&Y); + if( IN_RENAME_OBJECT && A ) sqlite3RenameTokenMap(pParse, A->a[0].zName, &Y); +} + +%type xfullname {SrcList*} +%destructor xfullname {sqlite3SrcListDelete(pParse->db, $$);} +xfullname(A) ::= nm(X). + {A = sqlite3SrcListAppend(pParse,0,&X,0); /*A-overwrites-X*/} +xfullname(A) ::= nm(X) DOT nm(Y). + {A = sqlite3SrcListAppend(pParse,0,&X,&Y); /*A-overwrites-X*/} +xfullname(A) ::= nm(X) DOT nm(Y) AS nm(Z). { + A = sqlite3SrcListAppend(pParse,0,&X,&Y); /*A-overwrites-X*/ + if( A ) A->a[0].zAlias = sqlite3NameFromToken(pParse->db, &Z); +} +xfullname(A) ::= nm(X) AS nm(Z). { + A = sqlite3SrcListAppend(pParse,0,&X,0); /*A-overwrites-X*/ + if( A ) A->a[0].zAlias = sqlite3NameFromToken(pParse->db, &Z); +} + +%type joinop {int} +joinop(X) ::= COMMA|JOIN. { X = JT_INNER; } +joinop(X) ::= JOIN_KW(A) JOIN. + {X = sqlite3JoinType(pParse,&A,0,0); /*X-overwrites-A*/} +joinop(X) ::= JOIN_KW(A) nm(B) JOIN. + {X = sqlite3JoinType(pParse,&A,&B,0); /*X-overwrites-A*/} +joinop(X) ::= JOIN_KW(A) nm(B) nm(C) JOIN. + {X = sqlite3JoinType(pParse,&A,&B,&C);/*X-overwrites-A*/} + +// There is a parsing abiguity in an upsert statement that uses a +// SELECT on the RHS of a the INSERT: +// +// INSERT INTO tab SELECT * FROM aaa JOIN bbb ON CONFLICT ... +// here ----^^ +// +// When the ON token is encountered, the parser does not know if it is +// the beginning of an ON CONFLICT clause, or the beginning of an ON +// clause associated with the JOIN. The conflict is resolved in favor +// of the JOIN. If an ON CONFLICT clause is intended, insert a dummy +// WHERE clause in between, like this: +// +// INSERT INTO tab SELECT * FROM aaa JOIN bbb WHERE true ON CONFLICT ... +// +// The [AND] and [OR] precedence marks in the rules for on_using cause the +// ON in this context to always be interpreted as belonging to the JOIN. +// +%type on_using {OnOrUsing} +//%destructor on_using {sqlite3ClearOnOrUsing(pParse->db, &$$);} +on_using(N) ::= ON expr(E). {N.pOn = E; N.pUsing = 0;} +on_using(N) ::= USING LP idlist(L) RP. {N.pOn = 0; N.pUsing = L;} +on_using(N) ::= . [OR] {N.pOn = 0; N.pUsing = 0;} + +// Note that this block abuses the Token type just a little. If there is +// no "INDEXED BY" clause, the returned token is empty (z==0 && n==0). If +// there is an INDEXED BY clause, then the token is populated as per normal, +// with z pointing to the token data and n containing the number of bytes +// in the token. +// +// If there is a "NOT INDEXED" clause, then (z==0 && n==1), which is +// normally illegal. The sqlite3SrcListIndexedBy() function +// recognizes and interprets this as a special case. +// +%type indexed_opt {Token} +%type indexed_by {Token} +indexed_opt(A) ::= . {A.z=0; A.n=0;} +indexed_opt(A) ::= indexed_by(A). +indexed_by(A) ::= INDEXED BY nm(X). {A = X;} +indexed_by(A) ::= NOT INDEXED. {A.z=0; A.n=1;} + +%type orderby_opt {ExprList*} +%destructor orderby_opt {sqlite3ExprListDelete(pParse->db, $$);} + +// the sortlist non-terminal stores a list of expression where each +// expression is optionally followed by ASC or DESC to indicate the +// sort order. +// +%type sortlist {ExprList*} +%destructor sortlist {sqlite3ExprListDelete(pParse->db, $$);} + +orderby_opt(A) ::= . {A = 0;} +orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;} +sortlist(A) ::= sortlist(A) COMMA expr(Y) sortorder(Z) nulls(X). { + A = sqlite3ExprListAppend(pParse,A,Y); + sqlite3ExprListSetSortOrder(A,Z,X); +} +sortlist(A) ::= expr(Y) sortorder(Z) nulls(X). { + A = sqlite3ExprListAppend(pParse,0,Y); /*A-overwrites-Y*/ + sqlite3ExprListSetSortOrder(A,Z,X); +} + +%type sortorder {int} + +sortorder(A) ::= ASC. {A = SQLITE_SO_ASC;} +sortorder(A) ::= DESC. {A = SQLITE_SO_DESC;} +sortorder(A) ::= . {A = SQLITE_SO_UNDEFINED;} + +%type nulls {int} +nulls(A) ::= NULLS FIRST. {A = SQLITE_SO_ASC;} +nulls(A) ::= NULLS LAST. {A = SQLITE_SO_DESC;} +nulls(A) ::= . {A = SQLITE_SO_UNDEFINED;} + +%type groupby_opt {ExprList*} +%destructor groupby_opt {sqlite3ExprListDelete(pParse->db, $$);} +groupby_opt(A) ::= . {A = 0;} +groupby_opt(A) ::= GROUP BY nexprlist(X). {A = X;} + +%type having_opt {Expr*} +%destructor having_opt {sqlite3ExprDelete(pParse->db, $$);} +having_opt(A) ::= . {A = 0;} +having_opt(A) ::= HAVING expr(X). {A = X;} + +%type limit_opt {Expr*} + +// The destructor for limit_opt will never fire in the current grammar. +// The limit_opt non-terminal only occurs at the end of a single production +// rule for SELECT statements. As soon as the rule that create the +// limit_opt non-terminal reduces, the SELECT statement rule will also +// reduce. So there is never a limit_opt non-terminal on the stack +// except as a transient. So there is never anything to destroy. +// +//%destructor limit_opt {sqlite3ExprDelete(pParse->db, $$);} +limit_opt(A) ::= . {A = 0;} +limit_opt(A) ::= LIMIT expr(X). + {A = sqlite3PExpr(pParse,TK_LIMIT,X,0);} +limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y). + {A = sqlite3PExpr(pParse,TK_LIMIT,X,Y);} +limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y). + {A = sqlite3PExpr(pParse,TK_LIMIT,Y,X);} + +/////////////////////////// The DELETE statement ///////////////////////////// +// +%if SQLITE_ENABLE_UPDATE_DELETE_LIMIT || SQLITE_UDL_CAPABLE_PARSER +cmd ::= with DELETE FROM xfullname(X) indexed_opt(I) where_opt_ret(W) + orderby_opt(O) limit_opt(L). { + sqlite3SrcListIndexedBy(pParse, X, &I); +#ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT + if( O || L ){ + updateDeleteLimitError(pParse,O,L); + O = 0; + L = 0; + } +#endif + sqlite3DeleteFrom(pParse,X,W,O,L); +} +%else +cmd ::= with DELETE FROM xfullname(X) indexed_opt(I) where_opt_ret(W). { + sqlite3SrcListIndexedBy(pParse, X, &I); + sqlite3DeleteFrom(pParse,X,W,0,0); +} +%endif + +%type where_opt {Expr*} +%destructor where_opt {sqlite3ExprDelete(pParse->db, $$);} +%type where_opt_ret {Expr*} +%destructor where_opt_ret {sqlite3ExprDelete(pParse->db, $$);} + +where_opt(A) ::= . {A = 0;} +where_opt(A) ::= WHERE expr(X). {A = X;} +where_opt_ret(A) ::= . {A = 0;} +where_opt_ret(A) ::= WHERE expr(X). {A = X;} +where_opt_ret(A) ::= RETURNING selcollist(X). + {sqlite3AddReturning(pParse,X); A = 0;} +where_opt_ret(A) ::= WHERE expr(X) RETURNING selcollist(Y). + {sqlite3AddReturning(pParse,Y); A = X;} + +////////////////////////// The UPDATE command //////////////////////////////// +// +%if SQLITE_ENABLE_UPDATE_DELETE_LIMIT || SQLITE_UDL_CAPABLE_PARSER +cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F) + where_opt_ret(W) orderby_opt(O) limit_opt(L). { + sqlite3SrcListIndexedBy(pParse, X, &I); + if( F ){ + SrcList *pFromClause = F; + if( pFromClause->nSrc>1 ){ + Select *pSubquery; + Token as; + pSubquery = sqlite3SelectNew(pParse,0,pFromClause,0,0,0,0,SF_NestedFrom,0); + as.n = 0; + as.z = 0; + pFromClause = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0); + } + X = sqlite3SrcListAppendList(pParse, X, pFromClause); + } + sqlite3ExprListCheckLength(pParse,Y,"set list"); +#ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT + if( O || L ){ + updateDeleteLimitError(pParse,O,L); + O = 0; + L = 0; + } +#endif + sqlite3Update(pParse,X,Y,W,R,O,L,0); +} +%else +cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y) from(F) + where_opt_ret(W). { + sqlite3SrcListIndexedBy(pParse, X, &I); + sqlite3ExprListCheckLength(pParse,Y,"set list"); + if( F ){ + SrcList *pFromClause = F; + if( pFromClause->nSrc>1 ){ + Select *pSubquery; + Token as; + pSubquery = sqlite3SelectNew(pParse,0,pFromClause,0,0,0,0,SF_NestedFrom,0); + as.n = 0; + as.z = 0; + pFromClause = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&as,pSubquery,0); + } + X = sqlite3SrcListAppendList(pParse, X, pFromClause); + } + sqlite3Update(pParse,X,Y,W,R,0,0,0); +} +%endif + + + +%type setlist {ExprList*} +%destructor setlist {sqlite3ExprListDelete(pParse->db, $$);} + +setlist(A) ::= setlist(A) COMMA nm(X) EQ expr(Y). { + A = sqlite3ExprListAppend(pParse, A, Y); + sqlite3ExprListSetName(pParse, A, &X, 1); +} +setlist(A) ::= setlist(A) COMMA LP idlist(X) RP EQ expr(Y). { + A = sqlite3ExprListAppendVector(pParse, A, X, Y); +} +setlist(A) ::= nm(X) EQ expr(Y). { + A = sqlite3ExprListAppend(pParse, 0, Y); + sqlite3ExprListSetName(pParse, A, &X, 1); +} +setlist(A) ::= LP idlist(X) RP EQ expr(Y). { + A = sqlite3ExprListAppendVector(pParse, 0, X, Y); +} + +////////////////////////// The INSERT command ///////////////////////////////// +// +cmd ::= with insert_cmd(R) INTO xfullname(X) idlist_opt(F) select(S) + upsert(U). { + sqlite3Insert(pParse, X, S, F, R, U); +} +cmd ::= with insert_cmd(R) INTO xfullname(X) idlist_opt(F) DEFAULT VALUES returning. +{ + sqlite3Insert(pParse, X, 0, F, R, 0); +} + +%type upsert {Upsert*} + +// Because upsert only occurs at the tip end of the INSERT rule for cmd, +// there is never a case where the value of the upsert pointer will not +// be destroyed by the cmd action. So comment-out the destructor to +// avoid unreachable code. +//%destructor upsert {sqlite3UpsertDelete(pParse->db,$$);} +upsert(A) ::= . { A = 0; } +upsert(A) ::= RETURNING selcollist(X). { A = 0; sqlite3AddReturning(pParse,X); } +upsert(A) ::= ON CONFLICT LP sortlist(T) RP where_opt(TW) + DO UPDATE SET setlist(Z) where_opt(W) upsert(N). + { A = sqlite3UpsertNew(pParse->db,T,TW,Z,W,N);} +upsert(A) ::= ON CONFLICT LP sortlist(T) RP where_opt(TW) DO NOTHING upsert(N). + { A = sqlite3UpsertNew(pParse->db,T,TW,0,0,N); } +upsert(A) ::= ON CONFLICT DO NOTHING returning. + { A = sqlite3UpsertNew(pParse->db,0,0,0,0,0); } +upsert(A) ::= ON CONFLICT DO UPDATE SET setlist(Z) where_opt(W) returning. + { A = sqlite3UpsertNew(pParse->db,0,0,Z,W,0);} + +returning ::= RETURNING selcollist(X). {sqlite3AddReturning(pParse,X);} +returning ::= . + +%type insert_cmd {int} +insert_cmd(A) ::= INSERT orconf(R). {A = R;} +insert_cmd(A) ::= REPLACE. {A = OE_Replace;} + +%type idlist_opt {IdList*} +%destructor idlist_opt {sqlite3IdListDelete(pParse->db, $$);} +%type idlist {IdList*} +%destructor idlist {sqlite3IdListDelete(pParse->db, $$);} + +idlist_opt(A) ::= . {A = 0;} +idlist_opt(A) ::= LP idlist(X) RP. {A = X;} +idlist(A) ::= idlist(A) COMMA nm(Y). + {A = sqlite3IdListAppend(pParse,A,&Y);} +idlist(A) ::= nm(Y). + {A = sqlite3IdListAppend(pParse,0,&Y); /*A-overwrites-Y*/} + +/////////////////////////// Expression Processing ///////////////////////////// +// + +%type expr {Expr*} +%destructor expr {sqlite3ExprDelete(pParse->db, $$);} +%type term {Expr*} +%destructor term {sqlite3ExprDelete(pParse->db, $$);} + +%include { + + /* Construct a new Expr object from a single token */ + static Expr *tokenExpr(Parse *pParse, int op, Token t){ + Expr *p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr)+t.n+1); + if( p ){ + /* memset(p, 0, sizeof(Expr)); */ + p->op = (u8)op; + p->affExpr = 0; + p->flags = EP_Leaf; + ExprClearVVAProperties(p); + /* p->iAgg = -1; // Not required */ + p->pLeft = p->pRight = 0; + p->pAggInfo = 0; + memset(&p->x, 0, sizeof(p->x)); + memset(&p->y, 0, sizeof(p->y)); + p->op2 = 0; + p->iTable = 0; + p->iColumn = 0; + p->u.zToken = (char*)&p[1]; + memcpy(p->u.zToken, t.z, t.n); + p->u.zToken[t.n] = 0; + p->w.iOfst = (int)(t.z - pParse->zTail); + if( sqlite3Isquote(p->u.zToken[0]) ){ + sqlite3DequoteExpr(p); + } +#if SQLITE_MAX_EXPR_DEPTH>0 + p->nHeight = 1; +#endif + if( IN_RENAME_OBJECT ){ + return (Expr*)sqlite3RenameTokenMap(pParse, (void*)p, &t); + } + } + return p; + } + +} + +expr(A) ::= term(A). +expr(A) ::= LP expr(X) RP. {A = X;} +expr(A) ::= id(X). {A=tokenExpr(pParse,TK_ID,X); /*A-overwrites-X*/} +expr(A) ::= JOIN_KW(X). {A=tokenExpr(pParse,TK_ID,X); /*A-overwrites-X*/} +expr(A) ::= nm(X) DOT nm(Y). { + Expr *temp1 = tokenExpr(pParse,TK_ID,X); + Expr *temp2 = tokenExpr(pParse,TK_ID,Y); + A = sqlite3PExpr(pParse, TK_DOT, temp1, temp2); +} +expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). { + Expr *temp1 = tokenExpr(pParse,TK_ID,X); + Expr *temp2 = tokenExpr(pParse,TK_ID,Y); + Expr *temp3 = tokenExpr(pParse,TK_ID,Z); + Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3); + if( IN_RENAME_OBJECT ){ + sqlite3RenameTokenRemap(pParse, 0, temp1); + } + A = sqlite3PExpr(pParse, TK_DOT, temp1, temp4); +} +term(A) ::= NULL|FLOAT|BLOB(X). {A=tokenExpr(pParse,@X,X); /*A-overwrites-X*/} +term(A) ::= STRING(X). {A=tokenExpr(pParse,@X,X); /*A-overwrites-X*/} +term(A) ::= INTEGER(X). { + A = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &X, 1); + if( A ) A->w.iOfst = (int)(X.z - pParse->zTail); +} +expr(A) ::= VARIABLE(X). { + if( !(X.z[0]=='#' && sqlite3Isdigit(X.z[1])) ){ + u32 n = X.n; + A = tokenExpr(pParse, TK_VARIABLE, X); + sqlite3ExprAssignVarNumber(pParse, A, n); + }else{ + /* When doing a nested parse, one can include terms in an expression + ** that look like this: #1 #2 ... These terms refer to registers + ** in the virtual machine. #N is the N-th register. */ + Token t = X; /*A-overwrites-X*/ + assert( t.n>=2 ); + if( pParse->nested==0 ){ + sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t); + A = 0; + }else{ + A = sqlite3PExpr(pParse, TK_REGISTER, 0, 0); + if( A ) sqlite3GetInt32(&t.z[1], &A->iTable); + } + } +} +expr(A) ::= expr(A) COLLATE ids(C). { + A = sqlite3ExprAddCollateToken(pParse, A, &C, 1); +} +%ifndef SQLITE_OMIT_CAST +expr(A) ::= CAST LP expr(E) AS typetoken(T) RP. { + A = sqlite3ExprAlloc(pParse->db, TK_CAST, &T, 1); + sqlite3ExprAttachSubtrees(pParse->db, A, E, 0); +} +%endif SQLITE_OMIT_CAST + + +expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP. { + A = sqlite3ExprFunction(pParse, Y, &X, D); +} +expr(A) ::= id(X) LP STAR RP. { + A = sqlite3ExprFunction(pParse, 0, &X, 0); +} + +%ifndef SQLITE_OMIT_WINDOWFUNC +expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP filter_over(Z). { + A = sqlite3ExprFunction(pParse, Y, &X, D); + sqlite3WindowAttach(pParse, A, Z); +} +expr(A) ::= id(X) LP STAR RP filter_over(Z). { + A = sqlite3ExprFunction(pParse, 0, &X, 0); + sqlite3WindowAttach(pParse, A, Z); +} +%endif + +term(A) ::= CTIME_KW(OP). { + A = sqlite3ExprFunction(pParse, 0, &OP, 0); +} + +expr(A) ::= LP nexprlist(X) COMMA expr(Y) RP. { + ExprList *pList = sqlite3ExprListAppend(pParse, X, Y); + A = sqlite3PExpr(pParse, TK_VECTOR, 0, 0); + if( A ){ + A->x.pList = pList; + if( ALWAYS(pList->nExpr) ){ + A->flags |= pList->a[0].pExpr->flags & EP_Propagate; + } + }else{ + sqlite3ExprListDelete(pParse->db, pList); + } +} + +expr(A) ::= expr(A) AND expr(Y). {A=sqlite3ExprAnd(pParse,A,Y);} +expr(A) ::= expr(A) OR(OP) expr(Y). {A=sqlite3PExpr(pParse,@OP,A,Y);} +expr(A) ::= expr(A) LT|GT|GE|LE(OP) expr(Y). + {A=sqlite3PExpr(pParse,@OP,A,Y);} +expr(A) ::= expr(A) EQ|NE(OP) expr(Y). {A=sqlite3PExpr(pParse,@OP,A,Y);} +expr(A) ::= expr(A) BITAND|BITOR|LSHIFT|RSHIFT(OP) expr(Y). + {A=sqlite3PExpr(pParse,@OP,A,Y);} +expr(A) ::= expr(A) PLUS|MINUS(OP) expr(Y). + {A=sqlite3PExpr(pParse,@OP,A,Y);} +expr(A) ::= expr(A) STAR|SLASH|REM(OP) expr(Y). + {A=sqlite3PExpr(pParse,@OP,A,Y);} +expr(A) ::= expr(A) CONCAT(OP) expr(Y). {A=sqlite3PExpr(pParse,@OP,A,Y);} +%type likeop {Token} +likeop(A) ::= LIKE_KW|MATCH(A). +likeop(A) ::= NOT LIKE_KW|MATCH(X). {A=X; A.n|=0x80000000; /*A-overwrite-X*/} +expr(A) ::= expr(A) likeop(OP) expr(Y). [LIKE_KW] { + ExprList *pList; + int bNot = OP.n & 0x80000000; + OP.n &= 0x7fffffff; + pList = sqlite3ExprListAppend(pParse,0, Y); + pList = sqlite3ExprListAppend(pParse,pList, A); + A = sqlite3ExprFunction(pParse, pList, &OP, 0); + if( bNot ) A = sqlite3PExpr(pParse, TK_NOT, A, 0); + if( A ) A->flags |= EP_InfixFunc; +} +expr(A) ::= expr(A) likeop(OP) expr(Y) ESCAPE expr(E). [LIKE_KW] { + ExprList *pList; + int bNot = OP.n & 0x80000000; + OP.n &= 0x7fffffff; + pList = sqlite3ExprListAppend(pParse,0, Y); + pList = sqlite3ExprListAppend(pParse,pList, A); + pList = sqlite3ExprListAppend(pParse,pList, E); + A = sqlite3ExprFunction(pParse, pList, &OP, 0); + if( bNot ) A = sqlite3PExpr(pParse, TK_NOT, A, 0); + if( A ) A->flags |= EP_InfixFunc; +} + +expr(A) ::= expr(A) ISNULL|NOTNULL(E). {A = sqlite3PExpr(pParse,@E,A,0);} +expr(A) ::= expr(A) NOT NULL. {A = sqlite3PExpr(pParse,TK_NOTNULL,A,0);} + +%include { + /* A routine to convert a binary TK_IS or TK_ISNOT expression into a + ** unary TK_ISNULL or TK_NOTNULL expression. */ + static void binaryToUnaryIfNull(Parse *pParse, Expr *pY, Expr *pA, int op){ + sqlite3 *db = pParse->db; + if( pA && pY && pY->op==TK_NULL && !IN_RENAME_OBJECT ){ + pA->op = (u8)op; + sqlite3ExprDelete(db, pA->pRight); + pA->pRight = 0; + } + } +} + +// expr1 IS expr2 +// expr1 IS NOT expr2 +// +// If expr2 is NULL then code as TK_ISNULL or TK_NOTNULL. If expr2 +// is any other expression, code as TK_IS or TK_ISNOT. +// +expr(A) ::= expr(A) IS expr(Y). { + A = sqlite3PExpr(pParse,TK_IS,A,Y); + binaryToUnaryIfNull(pParse, Y, A, TK_ISNULL); +} +expr(A) ::= expr(A) IS NOT expr(Y). { + A = sqlite3PExpr(pParse,TK_ISNOT,A,Y); + binaryToUnaryIfNull(pParse, Y, A, TK_NOTNULL); +} +expr(A) ::= expr(A) IS NOT DISTINCT FROM expr(Y). { + A = sqlite3PExpr(pParse,TK_IS,A,Y); + binaryToUnaryIfNull(pParse, Y, A, TK_ISNULL); +} +expr(A) ::= expr(A) IS DISTINCT FROM expr(Y). { + A = sqlite3PExpr(pParse,TK_ISNOT,A,Y); + binaryToUnaryIfNull(pParse, Y, A, TK_NOTNULL); +} + +expr(A) ::= NOT(B) expr(X). + {A = sqlite3PExpr(pParse, @B, X, 0);/*A-overwrites-B*/} +expr(A) ::= BITNOT(B) expr(X). + {A = sqlite3PExpr(pParse, @B, X, 0);/*A-overwrites-B*/} +expr(A) ::= PLUS|MINUS(B) expr(X). [BITNOT] { + A = sqlite3PExpr(pParse, @B==TK_PLUS ? TK_UPLUS : TK_UMINUS, X, 0); + /*A-overwrites-B*/ +} + +expr(A) ::= expr(B) PTR(C) expr(D). { + ExprList *pList = sqlite3ExprListAppend(pParse, 0, B); + pList = sqlite3ExprListAppend(pParse, pList, D); + A = sqlite3ExprFunction(pParse, pList, &C, 0); +} + +%type between_op {int} +between_op(A) ::= BETWEEN. {A = 0;} +between_op(A) ::= NOT BETWEEN. {A = 1;} +expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] { + ExprList *pList = sqlite3ExprListAppend(pParse,0, X); + pList = sqlite3ExprListAppend(pParse,pList, Y); + A = sqlite3PExpr(pParse, TK_BETWEEN, A, 0); + if( A ){ + A->x.pList = pList; + }else{ + sqlite3ExprListDelete(pParse->db, pList); + } + if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0); +} +%ifndef SQLITE_OMIT_SUBQUERY + %type in_op {int} + in_op(A) ::= IN. {A = 0;} + in_op(A) ::= NOT IN. {A = 1;} + expr(A) ::= expr(A) in_op(N) LP exprlist(Y) RP. [IN] { + if( Y==0 ){ + /* Expressions of the form + ** + ** expr1 IN () + ** expr1 NOT IN () + ** + ** simplify to constants 0 (false) and 1 (true), respectively, + ** regardless of the value of expr1. + */ + sqlite3ExprUnmapAndDelete(pParse, A); + A = sqlite3Expr(pParse->db, TK_STRING, N ? "true" : "false"); + if( A ) sqlite3ExprIdToTrueFalse(A); + }else{ + Expr *pRHS = Y->a[0].pExpr; + if( Y->nExpr==1 && sqlite3ExprIsConstant(pRHS) && A->op!=TK_VECTOR ){ + Y->a[0].pExpr = 0; + sqlite3ExprListDelete(pParse->db, Y); + pRHS = sqlite3PExpr(pParse, TK_UPLUS, pRHS, 0); + A = sqlite3PExpr(pParse, TK_EQ, A, pRHS); + }else{ + A = sqlite3PExpr(pParse, TK_IN, A, 0); + if( A==0 ){ + sqlite3ExprListDelete(pParse->db, Y); + }else if( A->pLeft->op==TK_VECTOR ){ + int nExpr = A->pLeft->x.pList->nExpr; + Select *pSelectRHS = sqlite3ExprListToValues(pParse, nExpr, Y); + if( pSelectRHS ){ + parserDoubleLinkSelect(pParse, pSelectRHS); + sqlite3PExprAddSelect(pParse, A, pSelectRHS); + } + }else{ + A->x.pList = Y; + sqlite3ExprSetHeightAndFlags(pParse, A); + } + } + if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0); + } + } + expr(A) ::= LP select(X) RP. { + A = sqlite3PExpr(pParse, TK_SELECT, 0, 0); + sqlite3PExprAddSelect(pParse, A, X); + } + expr(A) ::= expr(A) in_op(N) LP select(Y) RP. [IN] { + A = sqlite3PExpr(pParse, TK_IN, A, 0); + sqlite3PExprAddSelect(pParse, A, Y); + if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0); + } + expr(A) ::= expr(A) in_op(N) nm(Y) dbnm(Z) paren_exprlist(E). [IN] { + SrcList *pSrc = sqlite3SrcListAppend(pParse, 0,&Y,&Z); + Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0); + if( E ) sqlite3SrcListFuncArgs(pParse, pSelect ? pSrc : 0, E); + A = sqlite3PExpr(pParse, TK_IN, A, 0); + sqlite3PExprAddSelect(pParse, A, pSelect); + if( N ) A = sqlite3PExpr(pParse, TK_NOT, A, 0); + } + expr(A) ::= EXISTS LP select(Y) RP. { + Expr *p; + p = A = sqlite3PExpr(pParse, TK_EXISTS, 0, 0); + sqlite3PExprAddSelect(pParse, p, Y); + } +%endif SQLITE_OMIT_SUBQUERY + +/* CASE expressions */ +expr(A) ::= CASE case_operand(X) case_exprlist(Y) case_else(Z) END. { + A = sqlite3PExpr(pParse, TK_CASE, X, 0); + if( A ){ + A->x.pList = Z ? sqlite3ExprListAppend(pParse,Y,Z) : Y; + sqlite3ExprSetHeightAndFlags(pParse, A); + }else{ + sqlite3ExprListDelete(pParse->db, Y); + sqlite3ExprDelete(pParse->db, Z); + } +} +%type case_exprlist {ExprList*} +%destructor case_exprlist {sqlite3ExprListDelete(pParse->db, $$);} +case_exprlist(A) ::= case_exprlist(A) WHEN expr(Y) THEN expr(Z). { + A = sqlite3ExprListAppend(pParse,A, Y); + A = sqlite3ExprListAppend(pParse,A, Z); +} +case_exprlist(A) ::= WHEN expr(Y) THEN expr(Z). { + A = sqlite3ExprListAppend(pParse,0, Y); + A = sqlite3ExprListAppend(pParse,A, Z); +} +%type case_else {Expr*} +%destructor case_else {sqlite3ExprDelete(pParse->db, $$);} +case_else(A) ::= ELSE expr(X). {A = X;} +case_else(A) ::= . {A = 0;} +%type case_operand {Expr*} +%destructor case_operand {sqlite3ExprDelete(pParse->db, $$);} +case_operand(A) ::= expr(X). {A = X; /*A-overwrites-X*/} +case_operand(A) ::= . {A = 0;} + +%type exprlist {ExprList*} +%destructor exprlist {sqlite3ExprListDelete(pParse->db, $$);} +%type nexprlist {ExprList*} +%destructor nexprlist {sqlite3ExprListDelete(pParse->db, $$);} + +exprlist(A) ::= nexprlist(A). +exprlist(A) ::= . {A = 0;} +nexprlist(A) ::= nexprlist(A) COMMA expr(Y). + {A = sqlite3ExprListAppend(pParse,A,Y);} +nexprlist(A) ::= expr(Y). + {A = sqlite3ExprListAppend(pParse,0,Y); /*A-overwrites-Y*/} + +%ifndef SQLITE_OMIT_SUBQUERY +/* A paren_exprlist is an optional expression list contained inside +** of parenthesis */ +%type paren_exprlist {ExprList*} +%destructor paren_exprlist {sqlite3ExprListDelete(pParse->db, $$);} +paren_exprlist(A) ::= . {A = 0;} +paren_exprlist(A) ::= LP exprlist(X) RP. {A = X;} +%endif SQLITE_OMIT_SUBQUERY + + +///////////////////////////// The CREATE INDEX command /////////////////////// +// +cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D) + ON nm(Y) LP sortlist(Z) RP where_opt(W). { + sqlite3CreateIndex(pParse, &X, &D, + sqlite3SrcListAppend(pParse,0,&Y,0), Z, U, + &S, W, SQLITE_SO_ASC, NE, SQLITE_IDXTYPE_APPDEF); + if( IN_RENAME_OBJECT && pParse->pNewIndex ){ + sqlite3RenameTokenMap(pParse, pParse->pNewIndex->zName, &Y); + } +} + +%type uniqueflag {int} +uniqueflag(A) ::= UNIQUE. {A = OE_Abort;} +uniqueflag(A) ::= . {A = OE_None;} + + +// The eidlist non-terminal (Expression Id List) generates an ExprList +// from a list of identifiers. The identifier names are in ExprList.a[].zName. +// This list is stored in an ExprList rather than an IdList so that it +// can be easily sent to sqlite3ColumnsExprList(). +// +// eidlist is grouped with CREATE INDEX because it used to be the non-terminal +// used for the arguments to an index. That is just an historical accident. +// +// IMPORTANT COMPATIBILITY NOTE: Some prior versions of SQLite accepted +// COLLATE clauses and ASC or DESC keywords on ID lists in inappropriate +// places - places that might have been stored in the sqlite_schema table. +// Those extra features were ignored. But because they might be in some +// (busted) old databases, we need to continue parsing them when loading +// historical schemas. +// +%type eidlist {ExprList*} +%destructor eidlist {sqlite3ExprListDelete(pParse->db, $$);} +%type eidlist_opt {ExprList*} +%destructor eidlist_opt {sqlite3ExprListDelete(pParse->db, $$);} + +%include { + /* Add a single new term to an ExprList that is used to store a + ** list of identifiers. Report an error if the ID list contains + ** a COLLATE clause or an ASC or DESC keyword, except ignore the + ** error while parsing a legacy schema. + */ + static ExprList *parserAddExprIdListTerm( + Parse *pParse, + ExprList *pPrior, + Token *pIdToken, + int hasCollate, + int sortOrder + ){ + ExprList *p = sqlite3ExprListAppend(pParse, pPrior, 0); + if( (hasCollate || sortOrder!=SQLITE_SO_UNDEFINED) + && pParse->db->init.busy==0 + ){ + sqlite3ErrorMsg(pParse, "syntax error after column name \"%.*s\"", + pIdToken->n, pIdToken->z); + } + sqlite3ExprListSetName(pParse, p, pIdToken, 1); + return p; + } +} // end %include + +eidlist_opt(A) ::= . {A = 0;} +eidlist_opt(A) ::= LP eidlist(X) RP. {A = X;} +eidlist(A) ::= eidlist(A) COMMA nm(Y) collate(C) sortorder(Z). { + A = parserAddExprIdListTerm(pParse, A, &Y, C, Z); +} +eidlist(A) ::= nm(Y) collate(C) sortorder(Z). { + A = parserAddExprIdListTerm(pParse, 0, &Y, C, Z); /*A-overwrites-Y*/ +} + +%type collate {int} +collate(C) ::= . {C = 0;} +collate(C) ::= COLLATE ids. {C = 1;} + + +///////////////////////////// The DROP INDEX command ///////////////////////// +// +cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);} + +///////////////////////////// The VACUUM command ///////////////////////////// +// +%if !SQLITE_OMIT_VACUUM && !SQLITE_OMIT_ATTACH +%type vinto {Expr*} +%destructor vinto {sqlite3ExprDelete(pParse->db, $$);} +cmd ::= VACUUM vinto(Y). {sqlite3Vacuum(pParse,0,Y);} +cmd ::= VACUUM nm(X) vinto(Y). {sqlite3Vacuum(pParse,&X,Y);} +vinto(A) ::= INTO expr(X). {A = X;} +vinto(A) ::= . {A = 0;} +%endif + +///////////////////////////// The PRAGMA command ///////////////////////////// +// +%ifndef SQLITE_OMIT_PRAGMA +cmd ::= PRAGMA nm(X) dbnm(Z). {sqlite3Pragma(pParse,&X,&Z,0,0);} +cmd ::= PRAGMA nm(X) dbnm(Z) EQ nmnum(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);} +cmd ::= PRAGMA nm(X) dbnm(Z) LP nmnum(Y) RP. {sqlite3Pragma(pParse,&X,&Z,&Y,0);} +cmd ::= PRAGMA nm(X) dbnm(Z) EQ minus_num(Y). + {sqlite3Pragma(pParse,&X,&Z,&Y,1);} +cmd ::= PRAGMA nm(X) dbnm(Z) LP minus_num(Y) RP. + {sqlite3Pragma(pParse,&X,&Z,&Y,1);} + +nmnum(A) ::= plus_num(A). +nmnum(A) ::= nm(A). +nmnum(A) ::= ON(A). +nmnum(A) ::= DELETE(A). +nmnum(A) ::= DEFAULT(A). +%endif SQLITE_OMIT_PRAGMA +%token_class number INTEGER|FLOAT. +plus_num(A) ::= PLUS number(X). {A = X;} +plus_num(A) ::= number(A). +minus_num(A) ::= MINUS number(X). {A = X;} +//////////////////////////// The CREATE TRIGGER command ///////////////////// + +%ifndef SQLITE_OMIT_TRIGGER + +cmd ::= createkw trigger_decl(A) BEGIN trigger_cmd_list(S) END(Z). { + Token all; + all.z = A.z; + all.n = (int)(Z.z - A.z) + Z.n; + sqlite3FinishTrigger(pParse, S, &all); +} + +trigger_decl(A) ::= temp(T) TRIGGER ifnotexists(NOERR) nm(B) dbnm(Z) + trigger_time(C) trigger_event(D) + ON fullname(E) foreach_clause when_clause(G). { + sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, E, G, T, NOERR); + A = (Z.n==0?B:Z); /*A-overwrites-T*/ +} + +%type trigger_time {int} +trigger_time(A) ::= BEFORE|AFTER(X). { A = @X; /*A-overwrites-X*/ } +trigger_time(A) ::= INSTEAD OF. { A = TK_INSTEAD;} +trigger_time(A) ::= . { A = TK_BEFORE; } + +%type trigger_event {struct TrigEvent} +%destructor trigger_event {sqlite3IdListDelete(pParse->db, $$.b);} +trigger_event(A) ::= DELETE|INSERT(X). {A.a = @X; /*A-overwrites-X*/ A.b = 0;} +trigger_event(A) ::= UPDATE(X). {A.a = @X; /*A-overwrites-X*/ A.b = 0;} +trigger_event(A) ::= UPDATE OF idlist(X).{A.a = TK_UPDATE; A.b = X;} + +foreach_clause ::= . +foreach_clause ::= FOR EACH ROW. + +%type when_clause {Expr*} +%destructor when_clause {sqlite3ExprDelete(pParse->db, $$);} +when_clause(A) ::= . { A = 0; } +when_clause(A) ::= WHEN expr(X). { A = X; } + +%type trigger_cmd_list {TriggerStep*} +%destructor trigger_cmd_list {sqlite3DeleteTriggerStep(pParse->db, $$);} +trigger_cmd_list(A) ::= trigger_cmd_list(A) trigger_cmd(X) SEMI. { + assert( A!=0 ); + A->pLast->pNext = X; + A->pLast = X; +} +trigger_cmd_list(A) ::= trigger_cmd(A) SEMI. { + assert( A!=0 ); + A->pLast = A; +} + +// Disallow qualified table names on INSERT, UPDATE, and DELETE statements +// within a trigger. The table to INSERT, UPDATE, or DELETE is always in +// the same database as the table that the trigger fires on. +// +%type trnm {Token} +trnm(A) ::= nm(A). +trnm(A) ::= nm DOT nm(X). { + A = X; + sqlite3ErrorMsg(pParse, + "qualified table names are not allowed on INSERT, UPDATE, and DELETE " + "statements within triggers"); +} + +// Disallow the INDEX BY and NOT INDEXED clauses on UPDATE and DELETE +// statements within triggers. We make a specific error message for this +// since it is an exception to the default grammar rules. +// +tridxby ::= . +tridxby ::= INDEXED BY nm. { + sqlite3ErrorMsg(pParse, + "the INDEXED BY clause is not allowed on UPDATE or DELETE statements " + "within triggers"); +} +tridxby ::= NOT INDEXED. { + sqlite3ErrorMsg(pParse, + "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements " + "within triggers"); +} + + + +%type trigger_cmd {TriggerStep*} +%destructor trigger_cmd {sqlite3DeleteTriggerStep(pParse->db, $$);} +// UPDATE +trigger_cmd(A) ::= + UPDATE(B) orconf(R) trnm(X) tridxby SET setlist(Y) from(F) where_opt(Z) scanpt(E). + {A = sqlite3TriggerUpdateStep(pParse, &X, F, Y, Z, R, B.z, E);} + +// INSERT +trigger_cmd(A) ::= scanpt(B) insert_cmd(R) INTO + trnm(X) idlist_opt(F) select(S) upsert(U) scanpt(Z). { + A = sqlite3TriggerInsertStep(pParse,&X,F,S,R,U,B,Z);/*A-overwrites-R*/ +} +// DELETE +trigger_cmd(A) ::= DELETE(B) FROM trnm(X) tridxby where_opt(Y) scanpt(E). + {A = sqlite3TriggerDeleteStep(pParse, &X, Y, B.z, E);} + +// SELECT +trigger_cmd(A) ::= scanpt(B) select(X) scanpt(E). + {A = sqlite3TriggerSelectStep(pParse->db, X, B, E); /*A-overwrites-X*/} + +// The special RAISE expression that may occur in trigger programs +expr(A) ::= RAISE LP IGNORE RP. { + A = sqlite3PExpr(pParse, TK_RAISE, 0, 0); + if( A ){ + A->affExpr = OE_Ignore; + } +} +expr(A) ::= RAISE LP raisetype(T) COMMA nm(Z) RP. { + A = sqlite3ExprAlloc(pParse->db, TK_RAISE, &Z, 1); + if( A ) { + A->affExpr = (char)T; + } +} +%endif !SQLITE_OMIT_TRIGGER + +%type raisetype {int} +raisetype(A) ::= ROLLBACK. {A = OE_Rollback;} +raisetype(A) ::= ABORT. {A = OE_Abort;} +raisetype(A) ::= FAIL. {A = OE_Fail;} + + +//////////////////////// DROP TRIGGER statement ////////////////////////////// +%ifndef SQLITE_OMIT_TRIGGER +cmd ::= DROP TRIGGER ifexists(NOERR) fullname(X). { + sqlite3DropTrigger(pParse,X,NOERR); +} +%endif !SQLITE_OMIT_TRIGGER + +//////////////////////// ATTACH DATABASE file AS name ///////////////////////// +%ifndef SQLITE_OMIT_ATTACH +cmd ::= ATTACH database_kw_opt expr(F) AS expr(D) key_opt(K). { + sqlite3Attach(pParse, F, D, K); +} +cmd ::= DETACH database_kw_opt expr(D). { + sqlite3Detach(pParse, D); +} + +%type key_opt {Expr*} +%destructor key_opt {sqlite3ExprDelete(pParse->db, $$);} +key_opt(A) ::= . { A = 0; } +key_opt(A) ::= KEY expr(X). { A = X; } + +database_kw_opt ::= DATABASE. +database_kw_opt ::= . +%endif SQLITE_OMIT_ATTACH + +////////////////////////// REINDEX collation ////////////////////////////////// +%ifndef SQLITE_OMIT_REINDEX +cmd ::= REINDEX. {sqlite3Reindex(pParse, 0, 0);} +cmd ::= REINDEX nm(X) dbnm(Y). {sqlite3Reindex(pParse, &X, &Y);} +%endif SQLITE_OMIT_REINDEX + +/////////////////////////////////// ANALYZE /////////////////////////////////// +%ifndef SQLITE_OMIT_ANALYZE +cmd ::= ANALYZE. {sqlite3Analyze(pParse, 0, 0);} +cmd ::= ANALYZE nm(X) dbnm(Y). {sqlite3Analyze(pParse, &X, &Y);} +%endif + +//////////////////////// ALTER TABLE table ... //////////////////////////////// +%ifndef SQLITE_OMIT_ALTERTABLE +%ifndef SQLITE_OMIT_VIRTUALTABLE +cmd ::= ALTER TABLE fullname(X) RENAME TO nm(Z). { + sqlite3AlterRenameTable(pParse,X,&Z); +} +cmd ::= ALTER TABLE add_column_fullname + ADD kwcolumn_opt columnname(Y) carglist. { + Y.n = (int)(pParse->sLastToken.z-Y.z) + pParse->sLastToken.n; + sqlite3AlterFinishAddColumn(pParse, &Y); +} +cmd ::= ALTER TABLE fullname(X) DROP kwcolumn_opt nm(Y). { + sqlite3AlterDropColumn(pParse, X, &Y); +} + +add_column_fullname ::= fullname(X). { + disableLookaside(pParse); + sqlite3AlterBeginAddColumn(pParse, X); +} +cmd ::= ALTER TABLE fullname(X) RENAME kwcolumn_opt nm(Y) TO nm(Z). { + sqlite3AlterRenameColumn(pParse, X, &Y, &Z); +} + +kwcolumn_opt ::= . +kwcolumn_opt ::= COLUMNKW. + +%endif SQLITE_OMIT_VIRTUALTABLE +%endif SQLITE_OMIT_ALTERTABLE + +//////////////////////// CREATE VIRTUAL TABLE ... ///////////////////////////// +%ifndef SQLITE_OMIT_VIRTUALTABLE +cmd ::= create_vtab. {sqlite3VtabFinishParse(pParse,0);} +cmd ::= create_vtab LP vtabarglist RP(X). {sqlite3VtabFinishParse(pParse,&X);} +create_vtab ::= createkw VIRTUAL TABLE ifnotexists(E) + nm(X) dbnm(Y) USING nm(Z). { + sqlite3VtabBeginParse(pParse, &X, &Y, &Z, E); +} +vtabarglist ::= vtabarg. +vtabarglist ::= vtabarglist COMMA vtabarg. +vtabarg ::= . {sqlite3VtabArgInit(pParse);} +vtabarg ::= vtabarg vtabargtoken. +vtabargtoken ::= ANY(X). {sqlite3VtabArgExtend(pParse,&X);} +vtabargtoken ::= lp anylist RP(X). {sqlite3VtabArgExtend(pParse,&X);} +lp ::= LP(X). {sqlite3VtabArgExtend(pParse,&X);} +anylist ::= . +anylist ::= anylist LP anylist RP. +anylist ::= anylist ANY. +%endif SQLITE_OMIT_VIRTUALTABLE + + +//////////////////////// COMMON TABLE EXPRESSIONS //////////////////////////// +%type wqlist {With*} +%destructor wqlist {sqlite3WithDelete(pParse->db, $$);} +%type wqitem {Cte*} +// %destructor wqitem {sqlite3CteDelete(pParse->db, $$);} // not reachable + +with ::= . +%ifndef SQLITE_OMIT_CTE +with ::= WITH wqlist(W). { sqlite3WithPush(pParse, W, 1); } +with ::= WITH RECURSIVE wqlist(W). { sqlite3WithPush(pParse, W, 1); } + +%type wqas {u8} +wqas(A) ::= AS. {A = M10d_Any;} +wqas(A) ::= AS MATERIALIZED. {A = M10d_Yes;} +wqas(A) ::= AS NOT MATERIALIZED. {A = M10d_No;} +wqitem(A) ::= nm(X) eidlist_opt(Y) wqas(M) LP select(Z) RP. { + A = sqlite3CteNew(pParse, &X, Y, Z, M); /*A-overwrites-X*/ +} +wqlist(A) ::= wqitem(X). { + A = sqlite3WithAdd(pParse, 0, X); /*A-overwrites-X*/ +} +wqlist(A) ::= wqlist(A) COMMA wqitem(X). { + A = sqlite3WithAdd(pParse, A, X); +} +%endif SQLITE_OMIT_CTE + +//////////////////////// WINDOW FUNCTION EXPRESSIONS ///////////////////////// +// These must be at the end of this file. Specifically, the rules that +// introduce tokens WINDOW, OVER and FILTER must appear last. This causes +// the integer values assigned to these tokens to be larger than all other +// tokens that may be output by the tokenizer except TK_SPACE and TK_ILLEGAL. +// +%ifndef SQLITE_OMIT_WINDOWFUNC +%type windowdefn_list {Window*} +%destructor windowdefn_list {sqlite3WindowListDelete(pParse->db, $$);} +windowdefn_list(A) ::= windowdefn(Z). { A = Z; } +windowdefn_list(A) ::= windowdefn_list(Y) COMMA windowdefn(Z). { + assert( Z!=0 ); + sqlite3WindowChain(pParse, Z, Y); + Z->pNextWin = Y; + A = Z; +} + +%type windowdefn {Window*} +%destructor windowdefn {sqlite3WindowDelete(pParse->db, $$);} +windowdefn(A) ::= nm(X) AS LP window(Y) RP. { + if( ALWAYS(Y) ){ + Y->zName = sqlite3DbStrNDup(pParse->db, X.z, X.n); + } + A = Y; +} + +%type window {Window*} +%destructor window {sqlite3WindowDelete(pParse->db, $$);} + +%type frame_opt {Window*} +%destructor frame_opt {sqlite3WindowDelete(pParse->db, $$);} + +%type part_opt {ExprList*} +%destructor part_opt {sqlite3ExprListDelete(pParse->db, $$);} + +%type filter_clause {Expr*} +%destructor filter_clause {sqlite3ExprDelete(pParse->db, $$);} + +%type over_clause {Window*} +%destructor over_clause {sqlite3WindowDelete(pParse->db, $$);} + +%type filter_over {Window*} +%destructor filter_over {sqlite3WindowDelete(pParse->db, $$);} + +%type range_or_rows {int} + +%type frame_bound {struct FrameBound} +%destructor frame_bound {sqlite3ExprDelete(pParse->db, $$.pExpr);} +%type frame_bound_s {struct FrameBound} +%destructor frame_bound_s {sqlite3ExprDelete(pParse->db, $$.pExpr);} +%type frame_bound_e {struct FrameBound} +%destructor frame_bound_e {sqlite3ExprDelete(pParse->db, $$.pExpr);} + +window(A) ::= PARTITION BY nexprlist(X) orderby_opt(Y) frame_opt(Z). { + A = sqlite3WindowAssemble(pParse, Z, X, Y, 0); +} +window(A) ::= nm(W) PARTITION BY nexprlist(X) orderby_opt(Y) frame_opt(Z). { + A = sqlite3WindowAssemble(pParse, Z, X, Y, &W); +} +window(A) ::= ORDER BY sortlist(Y) frame_opt(Z). { + A = sqlite3WindowAssemble(pParse, Z, 0, Y, 0); +} +window(A) ::= nm(W) ORDER BY sortlist(Y) frame_opt(Z). { + A = sqlite3WindowAssemble(pParse, Z, 0, Y, &W); +} +window(A) ::= frame_opt(Z). { + A = Z; +} +window(A) ::= nm(W) frame_opt(Z). { + A = sqlite3WindowAssemble(pParse, Z, 0, 0, &W); +} + +frame_opt(A) ::= . { + A = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0); +} +frame_opt(A) ::= range_or_rows(X) frame_bound_s(Y) frame_exclude_opt(Z). { + A = sqlite3WindowAlloc(pParse, X, Y.eType, Y.pExpr, TK_CURRENT, 0, Z); +} +frame_opt(A) ::= range_or_rows(X) BETWEEN frame_bound_s(Y) AND + frame_bound_e(Z) frame_exclude_opt(W). { + A = sqlite3WindowAlloc(pParse, X, Y.eType, Y.pExpr, Z.eType, Z.pExpr, W); +} + +range_or_rows(A) ::= RANGE|ROWS|GROUPS(X). {A = @X; /*A-overwrites-X*/} + +frame_bound_s(A) ::= frame_bound(X). {A = X;} +frame_bound_s(A) ::= UNBOUNDED(X) PRECEDING. {A.eType = @X; A.pExpr = 0;} +frame_bound_e(A) ::= frame_bound(X). {A = X;} +frame_bound_e(A) ::= UNBOUNDED(X) FOLLOWING. {A.eType = @X; A.pExpr = 0;} + +frame_bound(A) ::= expr(X) PRECEDING|FOLLOWING(Y). + {A.eType = @Y; A.pExpr = X;} +frame_bound(A) ::= CURRENT(X) ROW. {A.eType = @X; A.pExpr = 0;} + +%type frame_exclude_opt {u8} +frame_exclude_opt(A) ::= . {A = 0;} +frame_exclude_opt(A) ::= EXCLUDE frame_exclude(X). {A = X;} + +%type frame_exclude {u8} +frame_exclude(A) ::= NO(X) OTHERS. {A = @X; /*A-overwrites-X*/} +frame_exclude(A) ::= CURRENT(X) ROW. {A = @X; /*A-overwrites-X*/} +frame_exclude(A) ::= GROUP|TIES(X). {A = @X; /*A-overwrites-X*/} + + +%type window_clause {Window*} +%destructor window_clause {sqlite3WindowListDelete(pParse->db, $$);} +window_clause(A) ::= WINDOW windowdefn_list(B). { A = B; } + +filter_over(A) ::= filter_clause(F) over_clause(O). { + if( O ){ + O->pFilter = F; + }else{ + sqlite3ExprDelete(pParse->db, F); + } + A = O; +} +filter_over(A) ::= over_clause(O). { + A = O; +} +filter_over(A) ::= filter_clause(F). { + A = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); + if( A ){ + A->eFrmType = TK_FILTER; + A->pFilter = F; + }else{ + sqlite3ExprDelete(pParse->db, F); + } +} + +over_clause(A) ::= OVER LP window(Z) RP. { + A = Z; + assert( A!=0 ); +} +over_clause(A) ::= OVER nm(Z). { + A = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window)); + if( A ){ + A->zName = sqlite3DbStrNDup(pParse->db, Z.z, Z.n); + } +} + +filter_clause(A) ::= FILTER LP WHERE expr(X) RP. { A = X; } +%endif /* SQLITE_OMIT_WINDOWFUNC */ + +/* +** The code generator needs some extra TK_ token values for tokens that +** are synthesized and do not actually appear in the grammar: +*/ +%token + COLUMN /* Reference to a table column */ + AGG_FUNCTION /* An aggregate function */ + AGG_COLUMN /* An aggregated column */ + TRUEFALSE /* True or false keyword */ + ISNOT /* Combination of IS and NOT */ + FUNCTION /* A function invocation */ + UMINUS /* Unary minus */ + UPLUS /* Unary plus */ + TRUTH /* IS TRUE or IS FALSE or IS NOT TRUE or IS NOT FALSE */ + REGISTER /* Reference to a VDBE register */ + VECTOR /* Vector */ + SELECT_COLUMN /* Choose a single column from a multi-column SELECT */ + IF_NULL_ROW /* the if-null-row operator */ + ASTERISK /* The "*" in count(*) and similar */ + SPAN /* The span operator */ + ERROR /* An expression containing an error */ +. +/* There must be no more than 255 tokens defined above. If this grammar +** is extended with new rules and tokens, they must either be so few in +** number that TK_SPAN is no more than 255, or else the new tokens must +** appear after this line. +*/ +%include { +#if TK_SPAN>255 +# error too many tokens in the grammar +#endif +} + +/* +** The TK_SPACE and TK_ILLEGAL tokens must be the last two tokens. The +** parser depends on this. Those tokens are not used in any grammar rule. +** They are only used by the tokenizer. Declare them last so that they +** are guaranteed to be the last two tokens +*/ +%token SPACE ILLEGAL. |