mirror of
https://github.com/tursodatabase/libsql.git
synced 2025-06-08 09:34:12 +00:00
1985 lines
69 KiB
Plaintext
1985 lines
69 KiB
Plaintext
%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 grammar. 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. { if( pParse->pReprepare==0 ) pParse->explain = 1; }
|
|
explain ::= EXPLAIN QUERY PLAN. { if( pParse->pReprepare==0 ) 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*/}
|
|
// FIXME: READONLY transactions map directly to DEFERRED transactions
|
|
// as currently the syntax is only used by libsql's rust library to
|
|
// force the connection to be in an interactive read local mode. In the
|
|
// future we should extend this by impmenting readonly features within
|
|
// the database impl of libsql.
|
|
transtype(A) ::= READONLY. {A = TK_DEFERRED; /*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) ::= RANDOM nm(X). {
|
|
if( X.n==5 && sqlite3_strnicmp(X.z,"rowid",5)==0 ){
|
|
A = TF_RandomRowid;
|
|
}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 FUNCTION LANGUAGE.
|
|
%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 FUNCTION
|
|
IGNORE IMMEDIATE INITIALLY INSTEAD LANGUAGE LIKE_KW MATCH NO PLAN
|
|
QUERY KEY OF OFFSET PRAGMA RAISE RANDOM READONLY 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 grammar. 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.
|
|
|
|
// An identifier or a join-keyword
|
|
//
|
|
%token_class idj ID|INDEXED|JOIN_KW.
|
|
|
|
// The name of a column or table can be any of the following:
|
|
//
|
|
%type nm {Token}
|
|
nm(A) ::= idj(A).
|
|
nm(A) ::= STRING(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,0);}
|
|
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,0);}
|
|
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 CREATE FUNCTION statement /////////////////////////
|
|
//
|
|
|
|
cmd ::= createkw FUNCTION ifnotexists(E) nm(N) LANGUAGE nm(L) AS STRING(B). {
|
|
libsql_create_function(pParse, &N, &L, &B, 0, E);
|
|
}
|
|
|
|
cmd ::= createkw FUNCTION ifnotexists(E) nm(N) LANGUAGE nm(L) AS BLOB(B). {
|
|
libsql_create_function(pParse, &N, &L, &B, 1, E);
|
|
}
|
|
|
|
///////////////////// The DROP FUNCTION statement ///////////////////////////
|
|
//
|
|
|
|
cmd ::= DROP FUNCTION ifexists(E) nm(N). {
|
|
libsql_drop_function(pParse, &N, E);
|
|
}
|
|
|
|
//////////////////////// 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(A). {
|
|
Select *p = A;
|
|
if( p ){
|
|
parserDoubleLinkSelect(pParse, p);
|
|
}
|
|
}
|
|
|
|
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(X). {
|
|
Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0);
|
|
sqlite3ExprSetErrorOffset(p, (int)(X.z - pParse->zTail));
|
|
A = sqlite3ExprListAppend(pParse, A, p);
|
|
}
|
|
selcollist(A) ::= sclp(A) scanpt nm(X) DOT STAR(Y). {
|
|
Expr *pRight, *pLeft, *pDot;
|
|
pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
|
|
sqlite3ExprSetErrorOffset(pRight, (int)(Y.z - pParse->zTail));
|
|
pLeft = tokenExpr(pParse, TK_ID, X);
|
|
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( ALWAYS(F!=0) && 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) ::= idj(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) ::= idj(X) LP distinct(D) exprlist(Y) RP. {
|
|
A = sqlite3ExprFunction(pParse, Y, &X, D);
|
|
}
|
|
expr(A) ::= idj(X) LP distinct(D) exprlist(Y) ORDER BY sortlist(O) RP. {
|
|
A = sqlite3ExprFunction(pParse, Y, &X, D);
|
|
sqlite3ExprAddFunctionOrderBy(pParse, A, O);
|
|
}
|
|
expr(A) ::= idj(X) LP STAR RP. {
|
|
A = sqlite3ExprFunction(pParse, 0, &X, 0);
|
|
}
|
|
|
|
%ifndef SQLITE_OMIT_WINDOWFUNC
|
|
expr(A) ::= idj(X) LP distinct(D) exprlist(Y) RP filter_over(Z). {
|
|
A = sqlite3ExprFunction(pParse, Y, &X, D);
|
|
sqlite3WindowAttach(pParse, A, Z);
|
|
}
|
|
expr(A) ::= idj(X) LP distinct(D) exprlist(Y) ORDER BY sortlist(O) RP filter_over(Z). {
|
|
A = sqlite3ExprFunction(pParse, Y, &X, D);
|
|
sqlite3WindowAttach(pParse, A, Z);
|
|
sqlite3ExprAddFunctionOrderBy(pParse, A, O);
|
|
}
|
|
expr(A) ::= idj(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 if( Y->nExpr==1 && pRHS->op==TK_SELECT ){
|
|
A = sqlite3PExpr(pParse, TK_IN, A, 0);
|
|
sqlite3PExprAddSelect(pParse, A, pRHS->x.pSelect);
|
|
pRHS->x.pSelect = 0;
|
|
sqlite3ExprListDelete(pParse->db, Y);
|
|
}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(A).
|
|
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) indextype(T)
|
|
ON nm(Y) LP sortlist(Z) RP where_opt(W). {
|
|
u8 idxType = SQLITE_IDXTYPE_APPDEF;
|
|
sqlite3CreateIndex(pParse, &X, &D,
|
|
sqlite3SrcListAppend(pParse,0,&Y,0), Z, U,
|
|
&S, W, SQLITE_SO_ASC, NE, idxType, T.pUsing);
|
|
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;}
|
|
|
|
%type indextype {OnOrUsing}
|
|
indextype(T) ::= USING idlist(L). {T.pOn = 0; T.pUsing = L;}
|
|
indextype(T) ::= . {T.pOn = 0; T.pUsing = 0;}
|
|
|
|
// 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);
|
|
}
|
|
|
|
cmd ::= ALTER TABLE fullname(X) ALTER COLUMNKW columnname(Y) TO columnname(Z) carglist. {
|
|
int definitionLength = (int)(pParse->sLastToken.z-Z.z) + pParse->sLastToken.n;
|
|
libsqlAlterAlterColumn(pParse, X, &Y, &Z, definitionLength);
|
|
}
|
|
|
|
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(A).
|
|
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(A).
|
|
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.
|