Files
MaxScale/query_classifier/qc_sqlite/sqlite-src-3110100/src/parse.y
Markus Mäkelä cddcc6d7d5 MXS-1896: Distinct LOAD DATA LOCAL INFILE from LOAD DATA INFILE
The two operations return different types of results and need to be
treated differently in order for them to be handled correctly in 2.2.

This fixes the unexpected internal state errors that happened in all 2.2
versions due to a wrong assumption made by readwritesplit. This fix is not
necessary for newer versions as the LOAD DATA LOCAL INFILE processing is
done with a simpler, and more robust, method.
2018-06-04 15:17:48 +03:00

3465 lines
107 KiB
Plaintext

/*
** 2001 September 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 grammar for SQL. Process this file
** using the lemon parser generator to generate C code that runs
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
*/
// 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}
// The generated parser function takes a 4th argument as follows:
%extra_argument {Parse *pParse}
// This code runs whenever there is a syntax error
//
%syntax_error {
UNUSED_PARAMETER(yymajor); /* Silence some compiler warnings */
assert( TOKEN.z[0] ); /* The tokenizer always gives us a token */
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
}
%stack_overflow {
UNUSED_PARAMETER(yypMinor); /* Silence some compiler warnings */
sqlite3ErrorMsg(pParse, "parser stack overflow");
}
// The name of the generated procedure that implements the parser
// is as follows:
%name sqlite3Parser
%ifdef MAXSCALE
%include {
#ifdef MAXSCALE
#ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
#error sqlite3 for MaxScale should be built with SQLITE_ENABLED_DELETE_LIMIT defined.
#endif
#endif
}
%endif
// The following text is included near the beginning of the C source
// code file that implements the parser.
//
%include {
#include "sqliteInt.h"
// Copied from query_classifier.h
enum
{
QUERY_TYPE_READ = 0x000002, /*< Read database data:any */
QUERY_TYPE_WRITE = 0x000004, /*< Master data will be modified:master */
QUERY_TYPE_USERVAR_READ = 0x000040, /*< Read a user variable:master or any */
};
typedef enum qc_field_usage
{
QC_USED_IN_SELECT = 0x01, /*< SELECT fld FROM... */
QC_USED_IN_SUBSELECT = 0x02, /*< SELECT 1 FROM ... SELECT fld ... */
QC_USED_IN_WHERE = 0x04, /*< SELECT ... FROM ... WHERE fld = ... */
QC_USED_IN_SET = 0x08, /*< UPDATE ... SET fld = ... */
QC_USED_IN_GROUP_BY = 0x10, /*< ... GROUP BY fld */
} qc_field_usage_t;
// MaxScale naming convention:
//
// - A function that "overloads" a sqlite3 function has the same name
// as the function it overloads, prefixed with "mxs_".
// - A function that is new for MaxScale has the name "maxscaleXYZ"
// where "XYZ" reflects the statement the function handles.
//
extern void mxs_sqlite3AlterFinishAddColumn(Parse *, Token *);
extern void mxs_sqlite3AlterBeginAddColumn(Parse *, SrcList *);
extern void mxs_sqlite3Analyze(Parse *, SrcList *);
extern void mxs_sqlite3BeginTransaction(Parse*, int token, int type);
extern void mxs_sqlite3CommitTransaction(Parse*);
extern void mxs_sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
Expr*, int, int);
extern void mxs_sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,SrcList*,
Expr*,int, int);
extern void mxs_sqlite3FinishTrigger(Parse*, TriggerStep*, Token*);
extern void mxs_sqlite3CreateView(Parse*,Token*,Token*,Token*,ExprList*,Select*,int,int);
extern void mxs_sqlite3DeleteFrom(Parse* pParse, SrcList* pTabList, Expr* pWhere, SrcList* pUsing);
extern void mxs_sqlite3DropIndex(Parse*, SrcList*, SrcList*,int);
extern void mxs_sqlite3DropTable(Parse*, SrcList*, int, int, int);
extern void mxs_sqlite3EndTable(Parse*, Token*, Token*, u8, Select*, SrcList*);
extern void mxs_sqlite3Insert(Parse*, SrcList*, Select*, IdList*, int,ExprList*);
extern void mxs_sqlite3RollbackTransaction(Parse*);
extern void mxs_sqlite3Savepoint(Parse *pParse, int op, Token *pName);
extern int mxs_sqlite3Select(Parse*, Select*, SelectDest*);
extern void mxs_sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int);
extern void mxs_sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
extern void maxscaleCollectInfoFromSelect(Parse*, Select*, int);
extern void maxscaleAlterTable(Parse*, mxs_alter_t command, SrcList*, Token*);
extern void maxscaleCall(Parse*, SrcList* pName, ExprList* pExprList);
extern void maxscaleCheckTable(Parse*, SrcList* pTables);
extern void maxscaleCreateSequence(Parse*, Token* pDatabase, Token* pTable);
extern void maxscaleDeclare(Parse* pParse);
extern void maxscaleDeallocate(Parse*, Token* pName);
extern void maxscaleDo(Parse*, ExprList* pEList);
extern void maxscaleDrop(Parse*, int what, Token* pDatabase, Token* pName);
extern void maxscaleExecute(Parse*, Token* pName, int type_mask);
extern void maxscaleExecuteImmediate(Parse*, Token* pName, ExprSpan* pExprSpan, int type_mask);
extern void maxscaleExplain(Parse*, Token* pNext);
extern void maxscaleFlush(Parse*, Token* pWhat);
extern void maxscaleHandler(Parse*, mxs_handler_t, SrcList* pFullName, Token* pName);
extern void maxscaleLoadData(Parse*, SrcList* pFullName, int local);
extern void maxscaleLock(Parse*, mxs_lock_t, SrcList*);
extern void maxscalePrepare(Parse*, Token* pName, Expr* pStmt);
extern void maxscalePrivileges(Parse*, int kind);
extern void maxscaleRenameTable(Parse*, SrcList* pTables);
extern void maxscaleSet(Parse*, int scope, mxs_set_t kind, ExprList*);
extern void maxscaleShow(Parse*, MxsShow* pShow);
extern void maxscaleTruncate(Parse*, Token* pDatabase, Token* pName);
extern void maxscaleUse(Parse*, Token*);
extern void maxscale_update_function_info(const char* name, const Expr* pExpr);
// Exposed utility functions
void exposed_sqlite3ExprDelete(sqlite3 *db, Expr *pExpr)
{
sqlite3ExprDelete(db, pExpr);
}
void exposed_sqlite3ExprListDelete(sqlite3 *db, ExprList *pList)
{
sqlite3ExprListDelete(db, pList);
}
void exposed_sqlite3IdListDelete(sqlite3 *db, IdList *pList)
{
sqlite3IdListDelete(db, pList);
}
void exposed_sqlite3SelectDelete(sqlite3 *db, Select *p)
{
sqlite3SelectDelete(db, p);
}
void exposed_sqlite3SrcListDelete(sqlite3 *db, SrcList *pList)
{
sqlite3SrcListDelete(db, pList);
}
// Exposed SQL functions.
void exposed_sqlite3BeginTrigger(Parse *pParse, /* The parse context of the CREATE TRIGGER statement */
Token *pName1, /* The name of the trigger */
Token *pName2, /* The name of the trigger */
int tr_tm, /* One of TK_BEFORE, TK_AFTER, TK_INSTEAD */
int op, /* One of TK_INSERT, TK_UPDATE, TK_DELETE */
IdList *pColumns, /* column list if this is an UPDATE OF trigger */
SrcList *pTableName,/* The name of the table/view the trigger applies to */
Expr *pWhen, /* WHEN clause */
int isTemp, /* True if the TEMPORARY keyword is present */
int noErr) /* Suppress errors if the trigger already exists */
{
sqlite3BeginTrigger(pParse, pName1, pName2, tr_tm, op, pColumns, pTableName, pWhen, isTemp, noErr);
}
void exposed_sqlite3FinishTrigger(Parse *pParse,
TriggerStep *pStepList,
Token *pAll)
{
sqlite3FinishTrigger(pParse, pStepList, pAll);
}
int exposed_sqlite3Dequote(char *z)
{
return sqlite3Dequote(z);
}
void exposed_sqlite3Insert(Parse* pParse,
SrcList* pTabList,
Select* pSelect,
IdList* pColumns,
int onError)
{
sqlite3Insert(pParse, pTabList, pSelect, pColumns, onError);
}
void exposed_sqlite3EndTable(Parse* pParse, Token* pCons, Token* pEnd, u8 tabOpts, Select* pSelect)
{
sqlite3EndTable(pParse, pCons, pEnd, tabOpts, pSelect);
}
int exposed_sqlite3Select(Parse* pParse, Select* p, SelectDest* pDest)
{
return sqlite3Select(pParse, p, pDest);
}
void exposed_sqlite3StartTable(Parse *pParse, /* Parser context */
Token *pName1, /* First part of the name of the table or view */
Token *pName2, /* Second part of the name of the table or view */
int isTemp, /* True if this is a TEMP table */
int isView, /* True if this is a VIEW */
int isVirtual, /* True if this is a VIRTUAL table */
int noErr) /* Do nothing if table already exists */
{
sqlite3StartTable(pParse, pName1, pName2, isTemp, isView, isVirtual, noErr);
}
void exposed_sqlite3Update(Parse* pParse, SrcList* pTabList, ExprList* pChanges, Expr* pWhere, int onError)
{
sqlite3Update(pParse, pTabList, pChanges, pWhere, onError);
}
/*
** 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
/*
** Alternative datatype for the argument to the malloc() routine passed
** into sqlite3ParserAlloc(). The default is size_t.
*/
#define YYMALLOCARGTYPE u64
/*
** An instance of this structure holds information about the
** LIMIT clause of a SELECT statement.
*/
struct LimitVal {
Expr *pLimit; /* The LIMIT expression. NULL if there is no limit */
Expr *pOffset; /* The OFFSET expression. NULL if there is none */
};
/*
** An instance of this structure is used to store the LIKE,
** GLOB, NOT LIKE, and NOT GLOB operators.
*/
struct LikeOp {
Token eOperator; /* "like" or "glob" or "regexp" */
int bNot; /* True if the NOT keyword is present */
};
/*
** 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; };
/*
** An instance of this structure holds the ATTACH key and the key type.
*/
struct AttachKey { int type; Token key; };
/*
** Disable lookaside memory allocation for objects that might be
** shared across database connections.
*/
static void disableLookaside(Parse *pParse){
pParse->disableLookaside++;
pParse->db->lookaside.bDisable++;
}
} // end %include
// Input is a single SQL command
input ::= cmdlist.
cmdlist ::= cmdlist ecmd.
cmdlist ::= ecmd.
ecmd ::= SEMI.
ecmd ::= explain SEMI.
ecmd ::= cmdx SEMI.
ecmd ::= oracle_assignment SEMI.
%ifdef MAXSCALE
explain_kw ::= EXPLAIN. // Also covers DESCRIBE
explain_kw ::= DESC.
explain ::= explain_kw. { pParse->explain = 1; }
// deferred_id is defined later, after the id token_class has been defined.
explain ::= explain_kw deferred_id(A). { maxscaleExplain(pParse, &A); }
explain ::= explain_kw deferred_id(A) DOT deferred_id. { maxscaleExplain(pParse, &A); }
ecmd ::= explain FOR(A) deferred_id INTEGER SEMI. { // FOR CONNECTION connection_id
pParse->explain = 1;
maxscaleExplain(pParse, &A);
}
%endif
%ifndef SQLITE_OMIT_EXPLAIN
%ifndef MAXSCALE
explain ::= EXPLAIN QUERY PLAN. { pParse->explain = 2; }
%endif
%endif SQLITE_OMIT_EXPLAIN
cmdx ::= cmd. { sqlite3FinishCoding(pParse); }
///////////////////// Begin and end transactions. ////////////////////////////
//
%ifdef MAXSCALE
work_opt ::= WORK.
work_opt ::= .
cmd ::= BEGIN work_opt. {mxs_sqlite3BeginTransaction(pParse, TK_BEGIN, 0);} // BEGIN [WORK]
%endif
%ifndef MAXSCALE
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;}
transtype(A) ::= IMMEDIATE(X). {A = @X;}
transtype(A) ::= EXCLUSIVE(X). {A = @X;}
%endif
%ifdef MAXSCALE
cmd ::= COMMIT work_opt. {mxs_sqlite3CommitTransaction(pParse);}
cmd ::= ROLLBACK work_opt. {mxs_sqlite3RollbackTransaction(pParse);}
%endif
%ifndef MAXSCALE
cmd ::= COMMIT trans_opt. {sqlite3CommitTransaction(pParse);}
cmd ::= END trans_opt. {sqlite3CommitTransaction(pParse);}
cmd ::= ROLLBACK trans_opt. {sqlite3RollbackTransaction(pParse);}
%endif
%ifdef MAXSCALE
savepoint_opt ::= SAVEPOINT.
savepoint_opt ::= .
cmd ::= SAVEPOINT nm(X). {
mxs_sqlite3Savepoint(pParse, SAVEPOINT_BEGIN, &X);
}
cmd ::= RELEASE savepoint_opt nm(X). {
mxs_sqlite3Savepoint(pParse, SAVEPOINT_RELEASE, &X);
}
cmd ::= ROLLBACK work_opt TO savepoint_opt nm(X). {
mxs_sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &X);
}
%endif
%ifndef MAXSCALE
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);
}
%endif
///////////////////// The CREATE TABLE statement ////////////////////////////
//
cmd ::= create_table create_table_args.
create_table ::= createkw temp(T) TABLE ifnotexists(E) nm(Y) dbnm(Z). {
#ifdef MAXSCALE
mxs_sqlite3StartTable(pParse,&Y,&Z,T,0,0,E);
#else
sqlite3StartTable(pParse,&Y,&Z,T,0,0,E);
#endif
}
%ifdef MAXSCALE
or_replace_opt ::= .
or_replace_opt ::= OR REPLACE.
createkw(A) ::= CREATE(X) or_replace_opt. {
disableLookaside(pParse);
A = X;
}
%endif
%ifndef MAXSCALE
createkw(A) ::= CREATE(X). {
disableLookaside(pParse);
A = X;
}
%endif
%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 = 1;}
%endif SQLITE_OMIT_TEMPDB
temp(A) ::= . {A = 0;}
create_table_args ::= LP columnlist conslist_opt(X) RP(E) table_options(F). {
#ifdef MAXSCALE
mxs_sqlite3EndTable(pParse,&X,&E,F,0,0);
#else
sqlite3EndTable(pParse,&X,&E,F,0);
#endif
}
%ifdef MAXSCALE
create_table_args ::= table_options(F) as_opt select(S). {
mxs_sqlite3EndTable(pParse,0,0,F,S,0);
sqlite3SelectDelete(pParse->db, S);
}
ignore_or_replace_opt ::= .
ignore_or_replace_opt ::= IGNORE.
ignore_or_replace_opt ::= REPLACE.
create_table_args ::= LP columnlist conslist_opt(X) RP(E) table_options(F)
ignore_or_replace_opt as_opt select(S). {
mxs_sqlite3EndTable(pParse,&X,&E,F,S,0);
sqlite3SelectDelete(pParse->db, S);
}
create_table_args ::= LIKE_KW fullname(X). {
mxs_sqlite3EndTable(pParse,0,0,0,0,X);
}
%endif
%ifndef MAXSCALE
create_table_args ::= AS select(S). {
sqlite3EndTable(pParse,0,0,0,S);
sqlite3SelectDelete(pParse->db, S);
}
%endif
%type table_option {int}
%type table_options {int}
table_options(A) ::= . {A = 0;}
%ifdef MAXSCALE
table_options(A) ::= table_options(B) table_option(C). {A = B|C;}
table_option(A) ::= ENGINE eq_opt nm. {A = 0;}
table_option(A) ::= AUTOINCR eq_opt INTEGER. {A = 0;}
table_option(A) ::= default_opt CHARSET eq_opt nm. {A = 0;}
table_option(A) ::= default_opt CHARACTER SET eq_opt nm. {A = 0;}
table_option(A) ::= COMMENT eq_opt STRING. {A = 0;}
table_option(A) ::= ID eq_opt DEFAULT. {A = 0;}
table_option(A) ::= ID eq_opt ID. {A = 0;}
table_option(A) ::= ID eq_opt INTEGER. {A = 0;}
table_option(A) ::= ID eq_opt STRING. {A = 0;}
table_option(A) ::= UNION eq LP fullnames(X) RP. {
sqlite3SrcListDelete(pParse->db, X);
A = 0;
}
%endif
%ifndef MAXSCALE
table_options(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);
}
}
%endif
columnlist ::= columnlist COMMA column.
columnlist ::= column.
// A "column" is a complete description of a single column in a
// CREATE TABLE statement. This includes the column name, its
// datatype, and other keywords such as PRIMARY KEY, UNIQUE, REFERENCES,
// NOT NULL and so forth.
//
%ifdef MAXSCALE
column(A) ::= columnid(X) type type_options carglist. {
%endif
%ifndef MAXSCALE
column(A) ::= columnid(X) type carglist. {
%endif
A.z = X.z;
A.n = (int)(pParse->sLastToken.z-X.z) + pParse->sLastToken.n;
}
%ifdef MAXSCALE
fulltext_or_spatial ::= FULLTEXT.
fulltext_or_spatial ::= SPATIAL.
index_or_key ::= INDEX.
index_or_key ::= KEY.
index_or_key_opt ::= .
index_or_key_opt ::= index_or_key.
index_name_opt ::= .
index_name_opt ::= index_name.
index_type ::= USING deferred_id. // USING {BTREE|HASH}
index_type_opt ::= .
index_type_opt ::= index_type.
index_option ::= deferred_id INTEGER. // KEY_BLOCK_SIZE valye
index_option ::= deferred_id eq INTEGER. // KEY_BLOCK_SIZE = value
index_option ::= index_type. // USING {BTREE|HASH}
index_option ::= WITH deferred_id deferred_id. // WITH PARSER parser_name.
index_option ::= COMMENT STRING. // COMMENT 'string'
index_option_opt ::= .
index_option_opt ::= index_option.
// PRIMARY KEY [index_option] (index_col_name, ...)
column(A) ::= PRIMARY KEY index_option_opt LP index_type_opt sortlist(X) RP index_option_opt. {
sqlite3ExprListDelete(pParse->db, X);
A.z = 0;
A.n = 0;
}
// {INDEX|KEY} [index_name] [index_type] (index_col_name, ...) [index_option]
column(A) ::= index_or_key index_name_opt index_type_opt LP sortlist(X) RP index_option_opt. {
sqlite3ExprListDelete(pParse->db, X);
A.z = 0;
A.n = 0;
}
// UNIQUE [INDEX|KEY] [index_name] (index_col_name, ...) [index_option]
column(A) ::= UNIQUE index_or_key_opt index_name_opt LP sortlist(X) RP index_option_opt. {
sqlite3ExprListDelete(pParse->db, X);
A.z = 0;
A.n = 0;
}
// {FULLTEXT|SPATIAL} [INDEX|KEY] [index_name] (index_col_name, ...) [index_option]
column(A) ::= fulltext_or_spatial index_or_key_opt index_name_opt LP sortlist(X) RP index_option_opt. {
sqlite3ExprListDelete(pParse->db, X);
A.z = 0;
A.n = 0;
}
// FOREIGN KEY [index_name] LP index_col_name, ... RP reference_definition
column(A) ::= 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);
A.z = 0;
A.n = 0;
}
// CHECK (expr)
column(A) ::= CHECK LP expr(X) RP. {
sqlite3AddCheckConstraint(pParse,X.pExpr);
A.z = 0;
A.n = 0;
}
%endif
%ifdef MAXSCALE
columnid(A) ::= nm(X). {
sqlite3AddColumn(pParse,&X);
A = X;
pParse->constraintName.n = 0;
}
columnid(A) ::= nm DOT nm(X). {
sqlite3AddColumn(pParse,&X);
A = X;
pParse->constraintName.n = 0;
}
columnid(A) ::= nm DOT nm DOT nm(X). {
sqlite3AddColumn(pParse,&X);
A = X;
pParse->constraintName.n = 0;
}
%endif
%ifndef MAXSCALE
columnid(A) ::= nm(X). {
sqlite3AddColumn(pParse,&X);
A = X;
pParse->constraintName.n = 0;
}
%endif
// 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.
// 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
%ifndef MAXSCALE
ABORT ACTION AFTER ANALYZE ASC ATTACH BEFORE BEGIN BY CASCADE CAST COLUMNKW
CONFLICT DATABASE DEFERRED DESC DETACH 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
ROLLBACK SAVEPOINT TEMP TRIGGER VACUUM VIEW VIRTUAL WITH WITHOUT
%ifdef SQLITE_OMIT_COMPOUND_SELECT
EXCEPT INTERSECT UNION
%endif SQLITE_OMIT_COMPOUND_SELECT
REINDEX RENAME CTIME_KW IF
%endif
%ifdef MAXSCALE
/*ABORT*/ ACTION AFTER ALGORITHM /*ANALYZE*/ /*ASC*/ /*ATTACH*/
/*BEFORE*/ /*BEGIN*/ BY
// TODO: BINARY is a reserved word and should not automatically convert into an identifer.
// TODO: However, if not here then rules such as CAST need to be modified.
BINARY
/*CASCADE*/ CAST CLOSE COLUMNKW COLUMNS COMMENT CONCURRENT /*CONFLICT*/
DATA /*DATABASE*/ DEALLOCATE DEFERRED /*DESC*/ /*DETACH*/ DUMPFILE
/*EACH*/ END ENGINE ENUM EXCLUSIVE /*EXPLAIN*/
FIRST FLUSH /*FOR*/ FORMAT
GLOBAL
// TODO: IF is a reserved word and should not automatically convert into an identifer.
IF IMMEDIATE INITIALLY INSTEAD
/*KEY*/
/*LIKE_KW*/
MASTER /*MATCH*/ MERGE
NAMES NEXT
NO
OF OFFSET OPEN
PREVIOUS
QUICK
RAISE RECURSIVE /*REINDEX*/ RELEASE /*RENAME*/ /*REPLACE*/ RESTRICT ROLLBACK ROLLUP ROW
SAVEPOINT SELECT_OPTIONS_KW /*SEQUENCE*/ SLAVE /*START*/ STATEMENT STATUS
TABLES TEMP TEMPTABLE /*TRIGGER*/
/*TRUNCATE*/
// TODO: UNSIGNED is a reserved word and should not automatically convert into an identifer.
// TODO: However, if not here then rules such as CAST need to be modified.
UNSIGNED
VALUE VIEW /*VIRTUAL*/
/*WITH*/
WORK
%endif
.
%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.
%left COLLATE.
%right BITNOT.
%ifdef MAXSCALE
// We need EQ in engine_opt up there, where CREATE is defined. However, as the
// value of a token is defined by the point the token is seen, EQ must not be
// used before the precedence is declared above where EQ and friends are
// declared in one go.
eq ::= EQ.
%endif
// 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(X). {A = X;}
nm(A) ::= STRING(X). {A = X;}
nm(A) ::= JOIN_KW(X). {A = X;}
nm(A) ::= START(X). {A = X;}
nm(A) ::= TRUNCATE(X). {A = X;}
nm(A) ::= BEGIN(X). {A = X;}
nm(A) ::= REPLACE(X). {A = X;}
// A typetoken is really one 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}
type ::= .
type ::= typetoken(X). {sqlite3AddColumnType(pParse,&X);}
%ifdef MAXSCALE
enumnames ::= STRING.
enumnames ::= enumnames COMMA STRING.
type ::= ENUM LP enumnames RP.
type ::= SET LP enumnames RP.
%endif
typetoken(A) ::= typename(X). {A = X;}
typetoken(A) ::= typename(X) LP signed RP(Y). {
A.z = X.z;
A.n = (int)(&Y.z[Y.n] - X.z);
}
typetoken(A) ::= typename(X) LP signed COMMA signed RP(Y). {
A.z = X.z;
A.n = (int)(&Y.z[Y.n] - X.z);
}
%type typename {Token}
typename(A) ::= ids(X). {A = X;}
typename(A) ::= typename(X) ids(Y). {A.z=X.z; A.n=Y.n+(int)(Y.z-X.z);}
signed ::= plus_num.
signed ::= minus_num.
// "carglist" is a list of additional constraints that come after the
// column name and column type in a CREATE TABLE statement.
//
%ifdef MAXSCALE
carglist ::= .
carglist ::= cconslist.
virtual_or_persistent ::= VIRTUAL.
virtual_or_persistent ::= PERSISTENT.
unique_key ::= .
unique_key ::= UNIQUE.
unique_key ::= UNIQUE KEY.
comment_string_opt ::= .
comment_string_opt ::= COMMENT STRING.
carglist ::= AS LP expr(X) RP virtual_or_persistent unique_key comment_string_opt. {
sqlite3ExprDelete(pParse->db, X.pExpr);
}
cconslist ::= ccons.
cconslist ::= cconslist ccons.
%endif
%ifndef MAXSCALE
carglist ::= carglist ccons.
carglist ::= .
%endif
%ifndef MAXSCALE
ccons ::= CONSTRAINT nm(X). {pParse->constraintName = X;}
%endif
ccons ::= DEFAULT term(X). {sqlite3AddDefaultValue(pParse,&X);}
ccons ::= DEFAULT LP expr(X) RP. {sqlite3AddDefaultValue(pParse,&X);}
ccons ::= DEFAULT PLUS term(X). {sqlite3AddDefaultValue(pParse,&X);}
ccons ::= DEFAULT MINUS(A) term(X). {
ExprSpan v;
v.pExpr = sqlite3PExpr(pParse, TK_UMINUS, X.pExpr, 0, 0);
v.zStart = A.z;
v.zEnd = X.zEnd;
sqlite3AddDefaultValue(pParse,&v);
}
ccons ::= DEFAULT id(X). {
ExprSpan v;
spanExpr(&v, pParse, TK_STRING, &X);
sqlite3AddDefaultValue(pParse,&v);
}
%ifdef MAXSCALE
ccons ::= DEFAULT id(X) LP RP. {
ExprSpan v;
spanExpr(&v, pParse, TK_STRING, &X);
sqlite3AddDefaultValue(pParse,&v);
}
%endif
// In addition to the type name, we also care about the primary key and
// UNIQUE constraints.
//
%ifdef MAXSCALE
ccons ::= AUTOINCR.
%endif
ccons ::= NULL onconf.
ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);}
%ifndef MAXSCALE
ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I).
{sqlite3AddPrimaryKey(pParse,0,R,I,Z);}
%endif
%ifdef MAXSCALE
// The addition of AUTOINCR above leads to conflicts if autoinc(I)
// follows onconf(R).
primary_opt ::= .
primary_opt ::= PRIMARY.
ccons ::= primary_opt KEY onconf(R).
{sqlite3AddPrimaryKey(pParse,0,R,0,0);}
%endif
ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0,0,0);}
%ifndef MAXSCALE
ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse,X.pExpr);}
// TODO: Following rule conflicts with "ccons ::= ON UPDATE ..." below.
ccons ::= REFERENCES nm(T) eidlist_opt(TA) refargs(R).
{sqlite3CreateForeignKey(pParse,0,&T,TA,R);}
%endif
ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);}
ccons ::= COLLATE ids(C). {sqlite3AddCollateType(pParse, &C);}
%ifdef MAXSCALE
reference_option ::= RESTRICT.
reference_option ::= CASCADE.
reference_option ::= SET NULL.
reference_option ::= NO ACTION.
reference_option ::= CTIME_KW.
// TODO: ccons ::= [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE]
ccons ::= ON DELETE reference_option.
ccons ::= ON UPDATE reference_option.
ccons ::= ON UPDATE id LP RP.
%endif
// The optional AUTOINCREMENT keyword
%ifndef MAXSCALE
%type autoinc {int}
autoinc(X) ::= . {X = 0;}
autoinc(X) ::= AUTOINCR. {X = 1;}
%endif
// 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(X) refarg(Y). { A = (X & ~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(X) conslist. {A = X;}
conslist ::= conslist tconscomma tcons.
conslist ::= tcons.
tconscomma ::= COMMA. {pParse->constraintName.n = 0;}
tconscomma ::= .
tcons ::= CONSTRAINT nm(X). {pParse->constraintName = X;}
%ifndef MAXSCALE
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);}
tcons ::= CHECK LP expr(E) RP onconf.
{sqlite3AddCheckConstraint(pParse,E.pExpr);}
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);
}
%endif
%type defer_subclause_opt {int}
defer_subclause_opt(A) ::= . {A = 0;}
defer_subclause_opt(A) ::= defer_subclause(X). {A = X;}
// 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}
%ifdef MAXSCALE
onconf ::= .
orconf ::= .
%endif
%ifndef MAXSCALE
%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(X). {A = X;}
resolvetype(A) ::= IGNORE. {A = OE_Ignore;}
resolvetype(A) ::= REPLACE. {A = OE_Replace;}
%endif
////////////////////////// The DROP TABLE /////////////////////////////////////
//
%ifdef MAXSCALE
table_or_tables ::= TABLE.
table_or_tables ::= TABLES.
cmd ::= DROP temp(T) table_or_tables ifexists(E) fullnames(X). {
mxs_sqlite3DropTable(pParse, X, 0, E, T);
}
%endif
%ifndef MAXSCALE
cmd ::= DROP TABLE ifexists(E) fullname(X). {
sqlite3DropTable(pParse, X, 0, E);
}
%endif
%type ifexists {int}
ifexists(A) ::= IF EXISTS. {A = 1;}
ifexists(A) ::= . {A = 0;}
///////////////////// The CREATE VIEW statement /////////////////////////////
//
%ifndef SQLITE_OMIT_VIEW
%ifdef MAXSCALE
%type algorithm {int}
algorithm(A) ::= UNDEFINED. {A=0;}
algorithm(A) ::= MERGE. {A=0;}
algorithm(A) ::= TEMPTABLE. {A=1;}
%type algorithm_opt {int}
algorithm_opt(A) ::= . {A=0;}
algorithm_opt(A) ::= ALGORITHM EQ algorithm(X). {A=X;}
cmd ::= createkw(X) algorithm_opt(T) VIEW ifnotexists(E) nm(Y) dbnm(Z) eidlist_opt(C)
AS select(S). {
mxs_sqlite3CreateView(pParse, &X, &Y, &Z, C, S, T, E);
sqlite3SelectDelete(pParse->db, S);
}
%endif
%ifndef MAXSCALE
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);
}
%endif
%ifdef MAXSCALE
cmd ::= DROP VIEW ifexists(E) fullnames(X). {
mxs_sqlite3DropTable(pParse, X, 1, E, 0);
}
%endif
%ifndef MAXSCALE
cmd ::= DROP VIEW ifexists(E) fullname(X). {
sqlite3DropTable(pParse, X, 1, E);
}
%endif
%endif SQLITE_OMIT_VIEW
//////////////////////// The SELECT statement /////////////////////////////////
//
cmd ::= select(X). {
SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0};
#ifdef MAXSCALE
mxs_sqlite3Select(pParse, X, &dest);
#else
sqlite3Select(pParse, X, &dest);
#endif
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){
if( p->pPrior ){
Select *pNext = 0, *pLoop;
int mxSelect, cnt = 0;
for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){
pLoop->pNext = pNext;
pLoop->selFlags |= SF_Compound;
}
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");
}
}
}
}
select(A) ::= with(W) selectnowith(X). {
Select *p = X;
if( p ){
p->pWith = W;
parserDoubleLinkSelect(pParse, p);
}else{
sqlite3WithDelete(pParse->db, W);
}
A = p;
}
selectnowith(A) ::= oneselect(X). {A = X;}
%ifndef SQLITE_OMIT_COMPOUND_SELECT
selectnowith(A) ::= selectnowith(X) multiselect_op(Y) oneselect(Z). {
Select *pRhs = Z;
Select *pLhs = X;
if( pRhs && pRhs->pPrior ){
SrcList *pFrom;
Token x;
x.n = 0;
parserDoubleLinkSelect(pParse, pRhs);
pFrom = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&x,pRhs,0,0);
#ifdef MAXSCALE
pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0,0,0);
#else
pRhs = sqlite3SelectNew(pParse,0,pFrom,0,0,0,0,0,0,0);
#endif
}
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;}
multiselect_op(A) ::= UNION ALL. {A = TK_ALL;}
multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP;}
%endif SQLITE_OMIT_COMPOUND_SELECT
%ifdef MAXSCALE
wf_window_name ::= id.
wf_window_ref_opt ::= .
wf_window_ref_opt ::= id.
wf_window_spec ::= LP wf_window_ref_opt wf_partition_by_opt wf_order_by_opt wf_frame_opt RP.
wf_window_def ::= wf_window_name AS wf_window_spec.
wf_window_def_list ::= wf_window_def_list COMMA wf_window_def.
wf_window_def_list ::= wf_window_def.
wf_window ::= WINDOW wf_window_def_list.
wf_window ::= WINDOW LP RP.
wf_window_opt ::= .
wf_window_opt ::= wf_window.
oneselect(A) ::= SELECT select_options(D) selcollist(W) select_into_opt(I1) from(X) where_opt(Y)
groupby_opt(P) having_opt(Q) wf_window_opt orderby_opt(Z) limit_opt(L)
select_into_opt(I2). {
if (!I1) {
I1=I2;
}
A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L.pLimit,L.pOffset,I1);
}
oneselect(A) ::= SELECT select_options(D) selcollist(W) select_into(I). {
A = sqlite3SelectNew(pParse,W,0,0,0,0,0,D,0,0,I);
}
oneselect(A) ::= SELECT select_options(D) selcollist(W) orderby_opt(Z) limit_opt(L). {
A = sqlite3SelectNew(pParse,W,0,0,0,0,Z,D,L.pLimit,L.pOffset,0);
}
%endif
%ifndef MAXSCALE
oneselect(A) ::= SELECT(S) 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.pLimit,L.pOffset);
#if SELECTTRACE_ENABLED
/* Populate the Select.zSelName[] string that is used to help with
** query planner debugging, to differentiate between multiple Select
** objects in a complex query.
**
** If the SELECT keyword is immediately followed by a C-style comment
** then extract the first few alphanumeric characters from within that
** comment to be the zSelName value. Otherwise, the label is #N where
** is an integer that is incremented with each SELECT statement seen.
*/
if( A!=0 ){
const char *z = S.z+6;
int i;
sqlite3_snprintf(sizeof(A->zSelName), A->zSelName, "#%d",
++pParse->nSelect);
while( z[0]==' ' ) z++;
if( z[0]=='/' && z[1]=='*' ){
z += 2;
while( z[0]==' ' ) z++;
for(i=0; sqlite3Isalnum(z[i]); i++){}
sqlite3_snprintf(sizeof(A->zSelName), A->zSelName, "%.*s", i, z);
}
}
#endif /* SELECTRACE_ENABLED */
}
%endif
oneselect(A) ::= values(X). {A = X;}
%type values {Select*}
%destructor values {sqlite3SelectDelete(pParse->db, $$);}
%ifdef MAXSCALE
value_or_values ::= VALUE.
value_or_values ::= VALUES.
values(A) ::= value_or_values LP exprlist(X) RP. {
A = sqlite3SelectNew(pParse,X,0,0,0,0,0,SF_Values,0,0,0);
}
%endif
%ifndef MAXSCALE
values(A) ::= VALUES LP nexprlist(X) RP. {
A = sqlite3SelectNew(pParse,X,0,0,0,0,0,SF_Values,0,0);
}
%endif
values(A) ::= values(X) COMMA LP exprlist(Y) RP. {
Select *pRight, *pLeft = X;
#ifdef MAXSCALE
pRight = sqlite3SelectNew(pParse,Y,0,0,0,0,0,SF_Values|SF_MultiValue,0,0,0);
#else
pRight = sqlite3SelectNew(pParse,Y,0,0,0,0,0,SF_Values|SF_MultiValue,0,0);
#endif
if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue;
if( pRight ){
pRight->op = TK_ALL;
pLeft = X;
pRight->pPrior = pLeft;
A = pRight;
}else{
A = pLeft;
}
}
%ifdef MAXSCALE
%type variables {ExprList*}
%destructor variables {sqlite3ExprListDelete(pParse->db, $$);}
variables(A) ::= VARIABLE(X). {
A = sqlite3ExprListAppend(pParse, NULL, 0);
sqlite3ExprListSetName(pParse, A, &X, 1);
}
variables(A) ::= variables(X) COMMA VARIABLE(Y). {
A = sqlite3ExprListAppend(pParse, X, 0);
sqlite3ExprListSetName(pParse, A, &Y, 1);
}
%type select_into_opt {ExprList*}
%destructor select_into_opt {sqlite3ExprListDelete(pParse->db, $$);}
select_into_opt(A) ::= . {A = 0;}
select_into_opt(A) ::= select_into(X). {A = X;}
%type select_into {ExprList*}
%destructor select_into {sqlite3ExprListDelete(pParse->db, $$);}
select_into(A) ::= INTO variables(X). {A = X;}
select_into(A) ::= INTO DUMPFILE STRING. {A = sqlite3ExprListAppend(pParse, 0, 0);}
select_into(A) ::= INTO OUTFILE STRING. {A = sqlite3ExprListAppend(pParse, 0, 0);}
%type select_options {int}
select_options(A) ::= . {A = 0;}
select_options(A) ::= select_options DISTINCT. {A = SF_Distinct;}
select_options(A) ::= select_options UNIQUE. {A = SF_Distinct;}
select_options(A) ::= select_options ALL. {A = SF_All;}
select_options(A) ::= select_options(X) HIGH_PRIORITY. {A = X;}
select_options(A) ::= select_options(X) SELECT_OPTIONS_KW. {A = X;}
select_options(A) ::= select_options(X) STRAIGHT_JOIN. {A = X;}
%endif
// The "distinct" nonterminal is true (1) if the DISTINCT keyword is
// present and false (0) if it is not.
//
%type distinct {int}
%ifdef MAXSCALE
distinct(A) ::= UNIQUE. {A = SF_Distinct;}
%endif
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(X) COMMA. {A = X;}
sclp(A) ::= . {A = 0;}
selcollist(A) ::= sclp(P) expr(X) as(Y). {
A = sqlite3ExprListAppend(pParse, P, X.pExpr);
if( Y.n>0 ) sqlite3ExprListSetName(pParse, A, &Y, 1);
sqlite3ExprListSetSpan(pParse,A,&X);
}
selcollist(A) ::= sclp(P) STAR. {
Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0);
A = sqlite3ExprListAppend(pParse, P, p);
}
selcollist(A) ::= sclp(P) nm(X) DOT STAR(Y). {
Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0, &Y);
Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
A = sqlite3ExprListAppend(pParse,P, pDot);
}
%ifdef MAXSCALE
next_or_previous(A) ::= NEXT(X). {A = X;}
next_or_previous(A) ::= PREVIOUS(X). {A = X;}
selcollist(A) ::= sclp(P) next_or_previous VALUE FOR nm(X) as(Y). {
Expr* pSeq = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
ExprList* pArgs = sqlite3ExprListAppend(pParse, NULL, pSeq);
Token nextval = { "nextval", 7 };
Expr* pFunc = sqlite3ExprFunction(pParse, pArgs, &nextval);
if( Y.n>0 ) sqlite3ExprListSetName(pParse, A, &Y, 1);
A = sqlite3ExprListAppend(pParse, P, pFunc);
}
selcollist(A) ::= sclp(P) DEFAULT LP nm RP as. {
A = P;
}
selcollist(A) ::= sclp(P) MATCH LP id(X) RP AGAINST LP expr(Y) RP. {
// Could be a subselect as well, but we just don't know it at this point.
sqlite3ExprDelete(pParse->db, Y.pExpr);
Expr *p = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
maxscale_update_function_info("match", p);
A = sqlite3ExprListAppend(pParse, P, p);
}
%endif
// 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(Y). {X = Y;}
as(X) ::= . {X.n = 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.
//
%ifndef MAXSCALE
from(A) ::= . {A = sqlite3DbMallocZero(pParse->db, sizeof(*A));}
%endif
from(A) ::= FROM seltablist(X). {
A = X;
sqlite3SrcListShiftJoinType(A);
}
%endif
// "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(X) joinop(Y). {
A = X;
if( ALWAYS(A && A->nSrc>0) ) A->a[A->nSrc-1].fg.jointype = (u8)Y;
}
stl_prefix(A) ::= . {A = 0;}
seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) indexed_opt(I)
on_opt(N) using_opt(U). {
A = sqlite3SrcListAppendFromTerm(pParse,X,&Y,&D,&Z,0,N,U);
sqlite3SrcListIndexedBy(pParse, A, &I);
}
%ifdef MAXSCALE
// as(X) above cannot be used, since it is used in other contexts as well.
seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) EQ nm(Z) indexed_opt(I)
on_opt(N) using_opt(U). {
A = sqlite3SrcListAppendFromTerm(pParse,X,&Y,&D,&Z,0,N,U);
sqlite3SrcListIndexedBy(pParse, A, &I);
}
%endif
seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) LP exprlist(E) RP as(Z)
on_opt(N) using_opt(U). {
A = sqlite3SrcListAppendFromTerm(pParse,X,&Y,&D,&Z,0,N,U);
sqlite3SrcListFuncArgs(pParse, A, E);
}
%ifndef SQLITE_OMIT_SUBQUERY
seltablist(A) ::= stl_prefix(X) LP select(S) RP
as(Z) on_opt(N) using_opt(U). {
A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,S,N,U);
}
seltablist(A) ::= stl_prefix(X) LP seltablist(F) RP
as(Z) on_opt(N) using_opt(U). {
if( X==0 && Z.n==0 && N==0 && U==0 ){
A = F;
}else if( F->nSrc==1 ){
A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,0,N,U);
if( A ){
struct SrcList_item *pNew = &A->a[A->nSrc-1];
struct SrcList_item *pOld = F->a;
pNew->zName = pOld->zName;
pNew->zDatabase = pOld->zDatabase;
pNew->pSelect = pOld->pSelect;
pOld->zName = pOld->zDatabase = 0;
pOld->pSelect = 0;
}
sqlite3SrcListDelete(pParse->db, F);
}else{
Select *pSubquery;
sqlite3SrcListShiftJoinType(F);
#ifdef MAXSCALE
pSubquery = sqlite3SelectNew(pParse,0,F,0,0,0,0,SF_NestedFrom,0,0,0);
#else
pSubquery = sqlite3SelectNew(pParse,0,F,0,0,0,0,SF_NestedFrom,0,0);
#endif
A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,pSubquery,N,U);
}
}
%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) dbnm(Y). {A = sqlite3SrcListAppend(pParse->db,0,&X,&Y);}
%ifdef MAXSCALE
%type fullnames {SrcList*}
%destructor fullnames {sqlite3SrcListDelete(pParse->db, $$);}
fullnames(A) ::= fullname(X). {A = X;}
fullnames(A) ::= fullnames(W) COMMA nm(X) dbnm(Y). {
A = sqlite3SrcListAppend(pParse->db, W, &X, &Y);
}
%endif
%type joinop {int}
joinop(X) ::= COMMA|JOIN. { X = JT_INNER; }
joinop(X) ::= JOIN_KW(A) JOIN. { X = sqlite3JoinType(pParse,&A,0,0); }
joinop(X) ::= JOIN_KW(A) nm(B) JOIN. { X = sqlite3JoinType(pParse,&A,&B,0); }
joinop(X) ::= JOIN_KW(A) nm(B) nm(C) JOIN.
{ X = sqlite3JoinType(pParse,&A,&B,&C); }
%ifdef MAXSCALE
joinop(X) ::= join_opt STRAIGHT_JOIN. { X = JT_INNER; }
%endif
%type on_opt {Expr*}
%destructor on_opt {sqlite3ExprDelete(pParse->db, $$);}
on_opt(N) ::= ON expr(E). {N = E.pExpr;}
on_opt(N) ::= . {N = 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}
indexed_opt(A) ::= . {A.z=0; A.n=0;}
%ifndef MAXSCALE
indexed_opt(A) ::= INDEXED BY nm(X). {A = X;}
indexed_opt(A) ::= NOT INDEXED. {A.z=0; A.n=1;}
%endif
%ifdef MAXSCALE
uif ::= USE|IGNORE|FORCE.
jog ::= JOIN|ORDER BY|GROUP BY.
for_jog ::= .
for_jog ::= FOR jog.
index_name ::= id.
index_name ::= PRIMARY.
index_list ::= index_name.
index_list ::= index_list COMMA index_name.
index_hint ::= uif index_or_key for_jog LP index_list RP.
index_hint_list ::= index_hint.
// TODO: index_hint_list ::= index_hint_list COMMA index_hint.
// TODO: Causes parsing conflict.
indexed_opt(A) ::= index_hint_list. {A.z=0; A.n=0;}
%endif
%type using_opt {IdList*}
%destructor using_opt {sqlite3IdListDelete(pParse->db, $$);}
using_opt(U) ::= USING LP idlist(L) RP. {U = L;}
using_opt(U) ::= . {U = 0;}
%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(X) COMMA expr(Y) sortorder(Z). {
A = sqlite3ExprListAppend(pParse,X,Y.pExpr);
sqlite3ExprListSetSortOrder(A,Z);
}
sortlist(A) ::= expr(Y) sortorder(Z). {
A = sqlite3ExprListAppend(pParse,0,Y.pExpr);
sqlite3ExprListSetSortOrder(A,Z);
}
%type sortorder {int}
sortorder(A) ::= ASC. {A = SQLITE_SO_ASC;}
sortorder(A) ::= DESC. {A = SQLITE_SO_DESC;}
sortorder(A) ::= . {A = SQLITE_SO_UNDEFINED;}
%type groupby_opt {ExprList*}
%destructor groupby_opt {sqlite3ExprListDelete(pParse->db, $$);}
groupby_opt(A) ::= . {A = 0;}
%ifndef MAXSCALE
groupby_opt(A) ::= GROUP BY nexprlist(X). {A = X;}
%endif
%ifdef MAXSCALE
with_rollup ::= WITH ROLLUP.
with_rollup ::= .
groupby_opt(A) ::= GROUP BY nexprlist(X) sortorder with_rollup. {A = X;}
%endif
%type having_opt {Expr*}
%destructor having_opt {sqlite3ExprDelete(pParse->db, $$);}
having_opt(A) ::= . {A = 0;}
having_opt(A) ::= HAVING expr(X). {A = X.pExpr;}
%type limit_opt {struct LimitVal}
// 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, $$.pLimit);
// sqlite3ExprDelete(pParse->db, $$.pOffset);
//}
limit_opt(A) ::= . {A.pLimit = 0; A.pOffset = 0;}
limit_opt(A) ::= LIMIT expr(X). {A.pLimit = X.pExpr; A.pOffset = 0;}
limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y).
{A.pLimit = X.pExpr; A.pOffset = Y.pExpr;}
limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y).
{A.pOffset = X.pExpr; A.pLimit = Y.pExpr;}
/////////////////////////// The DELETE statement /////////////////////////////
//
%ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
%ifdef MAXSCALE
low_priority_quick_ignore_opt ::= .
low_priority_quick_ignore_opt ::= LOW_PRIORITY.
low_priority_quick_ignore_opt ::= QUICK.
low_priority_quick_ignore_opt ::= IGNORE.
cmd ::= with(C) DELETE low_priority_quick_ignore_opt FROM fullname(X) indexed_opt(I) where_opt(W)
orderby_opt(O) limit_opt(L). {
%endif
%ifndef MAXSCALE
cmd ::= with(C) DELETE FROM fullname(X) indexed_opt(I) where_opt(W)
orderby_opt(O) limit_opt(L). {
%endif
sqlite3WithPush(pParse, C, 1);
sqlite3SrcListIndexedBy(pParse, X, &I);
#ifdef MAXSCALE
// We are not interested in the order by or limit information.
// Thus we simply delete it. sqlite also has some limitations, which
// will not bother us if we hide the information from it.
sqlite3ExprListDelete(pParse->db, O);
sqlite3ExprDelete(pParse->db, L.pLimit);
sqlite3ExprDelete(pParse->db, L.pOffset);
mxs_sqlite3DeleteFrom(pParse,X,W,0);
#else
W = sqlite3LimitWhere(pParse, X, W, O, L.pLimit, L.pOffset, "DELETE");
sqlite3DeleteFrom(pParse,X,W);
#endif
}
%endif
%ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
cmd ::= with(C) DELETE FROM fullname(X) indexed_opt(I) where_opt(W). {
sqlite3WithPush(pParse, C, 1);
sqlite3SrcListIndexedBy(pParse, X, &I);
sqlite3DeleteFrom(pParse,X,W);
}
%endif
%type where_opt {Expr*}
%destructor where_opt {sqlite3ExprDelete(pParse->db, $$);}
where_opt(A) ::= . {A = 0;}
where_opt(A) ::= WHERE expr(X). {A = X.pExpr;}
%ifdef MAXSCALE
%type table_factor {SrcList*}
%destructor table_factor {sqlite3SrcListDelete(pParse->db, $$);}
table_factor(A) ::= nm(X). {
A = sqlite3SrcListAppend(pParse->db, 0, &X, 0);
}
table_factor(A) ::= nm(X) as_opt id(Y). {
A = sqlite3SrcListAppendFromTerm(pParse, 0, &X, 0, &Y, 0, 0, 0);
}
table_factor(A) ::= nm(X) DOT nm(Y). {
A = sqlite3SrcListAppend(pParse->db, 0, &X, &Y);
}
table_factor(A) ::= nm(X) DOT nm(Y) as_opt id(Z). {
A = sqlite3SrcListAppendFromTerm(pParse, 0, &X, &Y, &Z, 0, 0, 0);
}
table_factor(A) ::= LP oneselect(S) RP as_opt id. {
maxscaleCollectInfoFromSelect(pParse, S, 1);
sqlite3SelectDelete(pParse->db, S);
A = 0;
}
%type table_reference {SrcList*}
%destructor table_reference {sqlite3SrcListDelete(pParse->db, $$);}
table_reference(A) ::= table_factor(X). {
A = X;
}
table_reference(A) ::= join_table(X). {
A = X;
}
%type join_table {SrcList*}
%destructor join_table {sqlite3SrcListDelete(pParse->db, $$);}
join_opt ::= .
join_opt ::= JOIN_KW.
join_table(A) ::= table_reference(X) join_opt JOIN table_reference(Y) join_condition. {
A = sqlite3SrcListCat(pParse->db, X, Y);
}
join_condition ::= ON expr(X). {
sqlite3ExprDelete(pParse->db, X.pExpr);
}
%type escaped_table_reference {SrcList*}
%destructor escaped_table_reference {sqlite3SrcListDelete(pParse->db, $$);}
escaped_table_reference(A) ::= table_reference(X). {
A = X;
}
%type table_references {SrcList*}
%destructor table_references {sqlite3SrcListDelete(pParse->db, $$);}
table_references(A) ::= escaped_table_reference(X). {
A = X;
}
table_references(A) ::= table_references(X) COMMA escaped_table_reference(Y). {
A = sqlite3SrcListCat(pParse->db, X, Y);
}
%type tbl_name {SrcList*}
%destructor tbl_name {sqlite3SrcListDelete(pParse->db, $$);}
tbl_name(A) ::= nm(X). { A = sqlite3SrcListAppend(pParse->db,0,&X,0); }
tbl_name(A) ::= nm(X) DOT STAR. { A = sqlite3SrcListAppend(pParse->db,0,&X,0); }
tbl_name(A) ::= nm(X) DOT nm(Y). { A = sqlite3SrcListAppend(pParse->db,0,&X,&Y); }
tbl_name(A) ::= nm(X) DOT nm(Y) DOT STAR. { A = sqlite3SrcListAppend(pParse->db,0,&X,&Y); }
%type tbl_names {SrcList*}
%destructor tbl_names {sqlite3SrcListDelete(pParse->db, $$);}
tbl_names(A) ::= tbl_name(X). { A = X; }
tbl_names(A) ::= tbl_names(X) COMMA tbl_name(Y). {
A = sqlite3SrcListCat(pParse->db, X, Y);
}
cmd ::= with(C) DELETE low_priority_quick_ignore_opt
tbl_names(X)
FROM table_references(U)
where_opt(W). {
sqlite3WithPush(pParse, C, 1);
mxs_sqlite3DeleteFrom(pParse, X, W, U);
}
cmd ::= with(C) DELETE low_priority_quick_ignore_opt
FROM tbl_names(X)
USING table_references(U)
where_opt(W). {
sqlite3WithPush(pParse, C, 1);
mxs_sqlite3DeleteFrom(pParse, X, W, U);
}
%endif
////////////////////////// The UPDATE command ////////////////////////////////
//
%ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
%ifdef MAXSCALE
low_priority_or_ignore_opt ::= .
low_priority_or_ignore_opt ::= low_priority_or_ignore_opt IGNORE.
low_priority_or_ignore_opt ::= low_priority_or_ignore_opt LOW_PRIORITY.
%type mxs_setlist {ExprList*}
%destructor mxs_setlist {sqlite3ExprListDelete(pParse->db, $$);}
mxs_setlist(A) ::= col_name(X) EQ expr(Y). {
Expr* pEq = sqlite3PExpr(pParse, TK_EQ, X.pExpr, Y.pExpr, 0);
A = sqlite3ExprListAppend(pParse, 0, pEq);
}
mxs_setlist(A) ::= mxs_setlist(Z) COMMA col_name(X) EQ expr(Y). {
Expr* pEq = sqlite3PExpr(pParse, TK_EQ, X.pExpr, Y.pExpr, 0);
A = sqlite3ExprListAppend(pParse, Z, pEq);
}
cmd ::= with(C) UPDATE low_priority_or_ignore_opt orconf(R) table_references(X) indexed_opt(I) SET mxs_setlist(Y)
where_opt(W) orderby_opt(O) limit_opt(L). {
%endif
%ifndef MAXSCALE
cmd ::= with(C) UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y)
where_opt(W) orderby_opt(O) limit_opt(L). {
%endif
sqlite3WithPush(pParse, C, 1);
sqlite3SrcListIndexedBy(pParse, X, &I);
sqlite3ExprListCheckLength(pParse,Y,"set list");
#ifdef MAXSCALE
// We are not interested in the order by or limit information.
// Thus we simply delete it. sqlite also has some limitations, which
// will not bother us if we hide the information from it.
sqlite3ExprListDelete(pParse->db, O);
sqlite3ExprDelete(pParse->db, L.pLimit);
sqlite3ExprDelete(pParse->db, L.pOffset);
mxs_sqlite3Update(pParse,X,Y,W,R);
#else
W = sqlite3LimitWhere(pParse, X, W, O, L.pLimit, L.pOffset, "UPDATE");
sqlite3Update(pParse,X,Y,W,R);
#endif
}
%endif
%ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
cmd ::= with(C) UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y)
where_opt(W). {
sqlite3WithPush(pParse, C, 1);
sqlite3SrcListIndexedBy(pParse, X, &I);
sqlite3ExprListCheckLength(pParse,Y,"set list");
sqlite3Update(pParse,X,Y,W,R);
}
%endif
%type setlist {ExprList*}
%destructor setlist {sqlite3ExprListDelete(pParse->db, $$);}
setlist(A) ::= setlist(Z) COMMA nm(X) EQ expr(Y). {
A = sqlite3ExprListAppend(pParse, Z, Y.pExpr);
sqlite3ExprListSetName(pParse, A, &X, 1);
}
setlist(A) ::= nm(X) EQ expr(Y). {
A = sqlite3ExprListAppend(pParse, 0, Y.pExpr);
sqlite3ExprListSetName(pParse, A, &X, 1);
}
////////////////////////// The INSERT command /////////////////////////////////
//
cmd ::= with(W) insert_cmd(R) INTO fullname(X) idlist_opt(F) select(S). {
sqlite3WithPush(pParse, W, 1);
#ifdef MAXSCALE
mxs_sqlite3Insert(pParse, X, S, F, R, 0);
#else
sqlite3Insert(pParse, X, S, F, R);
#endif
}
cmd ::= with(W) insert_cmd(R) INTO fullname(X) idlist_opt(F) DEFAULT VALUES.
{
sqlite3WithPush(pParse, W, 1);
#ifdef MAXSCALE
mxs_sqlite3Insert(pParse, X, 0, F, R, 0);
#else
sqlite3Insert(pParse, X, 0, F, R);
#endif
}
%ifdef MAXSCALE
cmd ::= with(W) insert_cmd(R) fullname(X) idlist_opt(F) DEFAULT VALUES.
{
sqlite3WithPush(pParse, W, 1);
mxs_sqlite3Insert(pParse, X, 0, F, R, 0);
}
cmd ::= with(W) insert_cmd(R) fullname(X) idlist_opt(F) select(S). {
sqlite3WithPush(pParse, W, 1);
mxs_sqlite3Insert(pParse, X, S, F, R, 0);
}
%type col_name {ExprSpan}
%destructor col_name {sqlite3ExprDelete(pParse->db, $$.pExpr);}
col_name(A) ::= nm(X). {
spanExpr(&A, pParse, TK_ID, &X);
}
col_name(A) ::= nm(X) DOT nm(Y). {
Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Y);
A.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0);
spanSet(&A,&X,&Y);
}
col_name(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Y);
Expr *temp3 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Z);
Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3, 0);
A.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0);
spanSet(&A,&X,&Z);
}
%type col_name_value {ExprSpan}
%destructor col_name_value {sqlite3ExprDelete(pParse->db, $$.pExpr);}
col_name_value(A) ::= col_name(X) EQ expr(Y). {
spanBinaryExpr(&A,pParse,TK_EQ,&X,&Y);
}
%type col_name_values {ExprList*}
%destructor col_name_values {sqlite3ExprListDelete(pParse->db, $$);}
col_name_values(A) ::= col_name_value(X). {
A = sqlite3ExprListAppend(pParse, 0, X.pExpr);
}
col_name_values(A) ::= col_name_values(X) COMMA col_name_value(Y). {
A = sqlite3ExprListAppend(pParse, X, Y.pExpr);
}
cmd ::= with(W) insert_cmd(R) fullname(X) SET col_name_values(Z).
{
sqlite3WithPush(pParse, W, 1);
mxs_sqlite3Insert(pParse, X, 0, 0, R, Z);
}
cmd ::= with(W) insert_cmd(R) INTO fullname(X) SET col_name_values(Z).
{
sqlite3WithPush(pParse, W, 1);
mxs_sqlite3Insert(pParse, X, 0, 0, R, Z);
}
%endif
%type insert_cmd {int}
%ifdef MAXSCALE
priority_opt ::= .
priority_opt ::= LOW_PRIORITY.
priority_opt ::= DELAYED.
priority_opt ::= HIGH_PRIORITY.
ignore_opt ::= .
ignore_opt ::= IGNORE.
insert_cmd(A) ::= INSERT priority_opt ignore_opt orconf(R). {A = R;}
%endif
%ifndef MAXSCALE
insert_cmd(A) ::= INSERT orconf(R). {A = R;}
%endif
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(X) COMMA nm(Y).
{A = sqlite3IdListAppend(pParse->db,X,&Y);}
idlist(A) ::= nm(Y).
{A = sqlite3IdListAppend(pParse->db,0,&Y);}
/////////////////////////// Expression Processing /////////////////////////////
//
%type expr {ExprSpan}
%destructor expr {sqlite3ExprDelete(pParse->db, $$.pExpr);}
%type term {ExprSpan}
%destructor term {sqlite3ExprDelete(pParse->db, $$.pExpr);}
%include {
/* This is a utility routine used to set the ExprSpan.zStart and
** ExprSpan.zEnd values of pOut so that the span covers the complete
** range of text beginning with pStart and going to the end of pEnd.
*/
static void spanSet(ExprSpan *pOut, Token *pStart, Token *pEnd){
pOut->zStart = pStart->z;
pOut->zEnd = &pEnd->z[pEnd->n];
}
/* Construct a new Expr object from a single identifier. Use the
** new Expr to populate pOut. Set the span of pOut to be the identifier
** that created the expression.
*/
static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token *pValue){
pOut->pExpr = sqlite3PExpr(pParse, op, 0, 0, pValue);
pOut->zStart = pValue->z;
pOut->zEnd = &pValue->z[pValue->n];
}
}
expr(A) ::= term(X). {A = X;}
expr(A) ::= LP(B) expr(X) RP(E). {A.pExpr = X.pExpr; spanSet(&A,&B,&E);}
%ifdef MAXSCALE
expr(A) ::= LP expr(X) COMMA(OP) expr(Y) RP. {spanBinaryExpr(&A,pParse,@OP,&X,&Y);}
term(A) ::= DEFAULT(X). {spanExpr(&A, pParse, @X, &X);}
%endif
term(A) ::= NULL(X). {spanExpr(&A, pParse, @X, &X);}
expr(A) ::= id(X). {spanExpr(&A, pParse, TK_ID, &X);}
expr(A) ::= nm(X) DOT nm(Y). {
Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Y);
A.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0);
spanSet(&A,&X,&Y);
}
expr(A) ::= DOT nm(X) DOT nm(Y). {
Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Y);
A.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0);
spanSet(&A,&X,&Y);
}
expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Y);
Expr *temp3 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Z);
Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3, 0);
A.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0);
spanSet(&A,&X,&Z);
}
term(A) ::= INTEGER|FLOAT|BLOB(X). {spanExpr(&A, pParse, @X, &X);}
term(A) ::= STRING(X). {spanExpr(&A, pParse, @X, &X);}
expr(A) ::= VARIABLE(X). {
if( X.n>=2 && X.z[0]=='#' && sqlite3Isdigit(X.z[1]) ){
/* 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. */
if( pParse->nested==0 ){
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &X);
A.pExpr = 0;
}else{
A.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, &X);
if( A.pExpr ) sqlite3GetInt32(&X.z[1], &A.pExpr->iTable);
}
}else{
spanExpr(&A, pParse, TK_VARIABLE, &X);
sqlite3ExprAssignVarNumber(pParse, A.pExpr);
}
spanSet(&A, &X, &X);
}
%ifdef MAXSCALE
expr(A) ::= VARIABLE(X) variable_tail(Y). {
// As we won't be executing any queries, we do not need to do
// the things that are done above.
ExprSpan v;
v.pExpr = sqlite3PExpr(pParse, TK_VARIABLE, 0, 0, &X);
spanSet(&v, &X, &X);
A.pExpr = sqlite3PExpr(pParse, TK_DOT, v.pExpr, Y.pExpr, 0);
A.zStart = v.zStart;
A.zEnd = Y.zEnd;
}
%endif
expr(A) ::= expr(E) COLLATE ids(C). {
A.pExpr = sqlite3ExprAddCollateToken(pParse, E.pExpr, &C, 1);
A.zStart = E.zStart;
A.zEnd = &C.z[C.n];
}
%ifndef SQLITE_OMIT_CAST
expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
A.pExpr = sqlite3PExpr(pParse, TK_CAST, E.pExpr, 0, &T);
spanSet(&A,&X,&Y);
}
%endif SQLITE_OMIT_CAST
%ifdef MAXSCALE
%type group_concat_colname {ExprSpan}
%destructor group_concat_colname {sqlite3ExprDelete(pParse->db, $$.pExpr);}
group_concat_colname(A) ::= nm(X). {
spanExpr(&A, pParse, TK_ID, &X);
}
group_concat_colname(A) ::= nm(X) DOT nm(Y). {
Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Y);
A.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0);
spanSet(&A,&X,&Y);
}
%type group_concat_colnames {ExprList*}
%destructor group_concat_colnames {sqlite3ExprListDelete(pParse->db, $$);}
group_concat_colnames(A) ::= group_concat_colname(Y). {
A = sqlite3ExprListAppend(pParse, 0, Y.pExpr);
}
group_concat_colnames(A) ::= group_concat_colnames(X) COMMA group_concat_colname(Y). {
A = sqlite3ExprListAppend(pParse, X, Y.pExpr);
}
%type group_concat_colnames_opt {ExprList*}
%destructor group_concat_colnames_opt {sqlite3ExprListDelete(pParse->db, $$);}
group_concat_colnames_opt(A) ::= . { A = NULL; }
group_concat_colnames_opt(A) ::= COMMA group_concat_colnames(X). { A = X; }
%type group_concat_order_by {ExprList*}
%destructor group_concat_order_by {sqlite3ExprListDelete(pParse->db, $$);}
group_concat_order_by(A) ::= ORDER BY INTEGER sortorder group_concat_colnames_opt(X). {
A = X;
}
group_concat_order_by(A) ::= ORDER BY col_name(X) sortorder group_concat_colnames_opt(Y). {
A = sqlite3ExprListAppend(pParse, Y, X.pExpr);
}
// TODO: The following causes conflicts.
//group_concat_order_by ::= ORDER BY expr(X) sortorder group_concat_colnames_opt. {
// sqlite3ExprDelete(pParse->db, X.pExpr);
//}
group_concat_separator ::= SEPARATOR STRING.
%type group_concat_tail {ExprList*}
%destructor group_concat_tail {sqlite3ExprListDelete(pParse->db, $$);}
group_concat_tail(A) ::= group_concat_order_by(X). { A = X; }
group_concat_tail(A) ::= group_concat_separator. { A = NULL; }
group_concat_tail(A) ::= group_concat_order_by(X) group_concat_separator. { A = X; }
convert_tail ::= USING id.
// Since we don't use the arguments for anything, any function can have these
// as trailing arguments. It's ok because if used incorrectly, the server will
// reject the statement
%type func_arg_tail_opt {ExprList*}
%destructor func_arg_tail_opt {sqlite3ExprListDelete(pParse->db, $$);}
func_arg_tail_opt(A) ::= . { A = NULL; }
func_arg_tail_opt(A) ::= group_concat_tail(X). { A = X; }
func_arg_tail_opt(A) ::= convert_tail. { A = NULL; }
wf_partition_by ::= PARTITION BY nexprlist(X). {
sqlite3ExprListDelete(pParse->db, X);
}
wf_partition_by_opt ::= .
wf_partition_by_opt ::= wf_partition_by.
wf_order_by ::= ORDER BY nexprlist(X) sortorder. {
sqlite3ExprListDelete(pParse->db, X);
}
wf_order_by_opt ::= .
wf_order_by_opt ::= wf_order_by.
wf_frame_units ::= RANGE.
wf_frame_units ::= ROWS.
wf_frame_start ::= UNBOUNDED PRECEDING.
wf_frame_start ::= CURRENT ROW.
wf_frame_start ::= term PRECEDING.
wf_frame_bound ::= wf_frame_start.
wf_frame_bound ::= UNBOUNDED FOLLOWING.
wf_frame_bound ::= term FOLLOWING.
wf_frame_extent ::= wf_frame_start.
wf_frame_extent ::= BETWEEN wf_frame_bound AND wf_frame_bound.
wf_frame_exclusion_opt ::= .
wf_frame_exclusion_opt ::= EXCLUDE CURRENT ROW.
wf_frame_exclusion_opt ::= EXCLUDE GROUP.
wf_frame_exclusion_opt ::= EXCLUDE TIES.
wf_frame_exclusion_opt ::= EXCLUDE NO OTHERS.
wf_frame_opt ::= .
wf_frame_opt ::= wf_frame_units wf_frame_extent wf_frame_exclusion_opt .
wf ::= OVER LP wf_window_ref_opt wf_partition_by_opt wf_order_by_opt wf_frame_opt RP.
wf ::= OVER id.
wf_opt ::= .
wf_opt ::= wf.
expr(A) ::= id(X) LP distinct(D) exprlist(Y) func_arg_tail_opt(Z) RP(E) wf_opt. {
// We just append Z on Y as we are only interested in what columns
// the function used.
Y = sqlite3ExprListAppendList(pParse, Y, Z);
%endif
%ifndef MAXSCALE
expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP(E). {
%endif
if( Y && Y->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
sqlite3ErrorMsg(pParse, "too many arguments on function %T", &X);
}
A.pExpr = sqlite3ExprFunction(pParse, Y, &X);
spanSet(&A,&X,&E);
if( D==SF_Distinct && A.pExpr ){
A.pExpr->flags |= EP_Distinct;
}
}
%ifdef MAXSCALE
expr(A) ::= nm DOT nm(X) LP distinct(D) exprlist(Y) func_arg_tail_opt(Z) RP(E) wf_opt. {
// We just append Z on Y as we are only interested in what columns
// the function used.
Y = sqlite3ExprListAppendList(pParse, Y, Z);
if( Y && Y->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
sqlite3ErrorMsg(pParse, "too many arguments on function %T", &X);
}
A.pExpr = sqlite3ExprFunction(pParse, Y, &X);
spanSet(&A,&X,&E);
if( D==SF_Distinct && A.pExpr ){
A.pExpr->flags |= EP_Distinct;
}
}
keyword_as_function(A) ::= JOIN_KW(X). {A = X;}
keyword_as_function(A) ::= INSERT(X). {A = X;}
keyword_as_function(A) ::= REPLACE(X). {A = X;}
expr(A) ::= keyword_as_function(X) LP distinct(D) exprlist(Y) RP(E). {
if( Y && Y->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
sqlite3ErrorMsg(pParse, "too many arguments on function %T", &X);
}
A.pExpr = sqlite3ExprFunction(pParse, Y, &X);
spanSet(&A,&X,&E);
if( D==SF_Distinct && A.pExpr ){
A.pExpr->flags |= EP_Distinct;
}
}
%endif
expr(A) ::= id(X) LP STAR RP(E) wf_opt. {
A.pExpr = sqlite3ExprFunction(pParse, 0, &X);
spanSet(&A,&X,&E);
}
term(A) ::= CTIME_KW(OP). {
A.pExpr = sqlite3ExprFunction(pParse, 0, &OP);
spanSet(&A, &OP, &OP);
}
%include {
/* This routine constructs a binary expression node out of two ExprSpan
** objects and uses the result to populate a new ExprSpan object.
*/
static void spanBinaryExpr(
ExprSpan *pOut, /* Write the result here */
Parse *pParse, /* The parsing context. Errors accumulate here */
int op, /* The binary operation */
ExprSpan *pLeft, /* The left operand */
ExprSpan *pRight /* The right operand */
){
pOut->pExpr = sqlite3PExpr(pParse, op, pLeft->pExpr, pRight->pExpr, 0);
pOut->zStart = pLeft->zStart;
pOut->zEnd = pRight->zEnd;
}
/* If doNot is true, then add a TK_NOT Expr-node wrapper around the
** outside of *ppExpr.
*/
static void exprNot(Parse *pParse, int doNot, Expr **ppExpr){
if( doNot ) *ppExpr = sqlite3PExpr(pParse, TK_NOT, *ppExpr, 0, 0);
}
}
expr(A) ::= expr(X) AND(OP) expr(Y). {spanBinaryExpr(&A,pParse,@OP,&X,&Y);}
expr(A) ::= expr(X) OR(OP) expr(Y). {spanBinaryExpr(&A,pParse,@OP,&X,&Y);}
expr(A) ::= expr(X) LT|GT|GE|LE(OP) expr(Y).
{spanBinaryExpr(&A,pParse,@OP,&X,&Y);}
expr(A) ::= expr(X) EQ|NE(OP) expr(Y). {spanBinaryExpr(&A,pParse,@OP,&X,&Y);}
expr(A) ::= expr(X) BITAND|BITOR|LSHIFT|RSHIFT(OP) expr(Y).
{spanBinaryExpr(&A,pParse,@OP,&X,&Y);}
expr(A) ::= expr(X) PLUS|MINUS(OP) expr(Y).
{spanBinaryExpr(&A,pParse,@OP,&X,&Y);}
%ifdef MAXSCALE
expr(A) ::= INTERVAL INTEGER(X) id. {
// Here we could check that id is one of MICROSECOND, SECOND, MINUTE
// HOUR, DAY, WEEK, etc.
spanExpr(&A, pParse, @X, &X);
}
%endif
expr(A) ::= expr(X) STAR|SLASH|REM(OP) expr(Y).
{spanBinaryExpr(&A,pParse,@OP,&X,&Y);}
expr(A) ::= expr(X) CONCAT(OP) expr(Y). {spanBinaryExpr(&A,pParse,@OP,&X,&Y);}
%type likeop {struct LikeOp}
likeop(A) ::= LIKE_KW|MATCH(X). {A.eOperator = X; A.bNot = 0;}
likeop(A) ::= NOT LIKE_KW|MATCH(X). {A.eOperator = X; A.bNot = 1;}
expr(A) ::= expr(X) likeop(OP) expr(Y). [LIKE_KW] {
ExprList *pList;
pList = sqlite3ExprListAppend(pParse,0, Y.pExpr);
pList = sqlite3ExprListAppend(pParse,pList, X.pExpr);
A.pExpr = sqlite3ExprFunction(pParse, pList, &OP.eOperator);
exprNot(pParse, OP.bNot, &A.pExpr);
A.zStart = X.zStart;
A.zEnd = Y.zEnd;
if( A.pExpr ) A.pExpr->flags |= EP_InfixFunc;
}
expr(A) ::= expr(X) likeop(OP) expr(Y) ESCAPE expr(E). [LIKE_KW] {
ExprList *pList;
pList = sqlite3ExprListAppend(pParse,0, Y.pExpr);
pList = sqlite3ExprListAppend(pParse,pList, X.pExpr);
pList = sqlite3ExprListAppend(pParse,pList, E.pExpr);
A.pExpr = sqlite3ExprFunction(pParse, pList, &OP.eOperator);
exprNot(pParse, OP.bNot, &A.pExpr);
A.zStart = X.zStart;
A.zEnd = E.zEnd;
if( A.pExpr ) A.pExpr->flags |= EP_InfixFunc;
}
%include {
/* Construct an expression node for a unary postfix operator
*/
static void spanUnaryPostfix(
ExprSpan *pOut, /* Write the new expression node here */
Parse *pParse, /* Parsing context to record errors */
int op, /* The operator */
ExprSpan *pOperand, /* The operand */
Token *pPostOp /* The operand token for setting the span */
){
pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0);
pOut->zStart = pOperand->zStart;
pOut->zEnd = &pPostOp->z[pPostOp->n];
}
}
expr(A) ::= expr(X) ISNULL|NOTNULL(E). {spanUnaryPostfix(&A,pParse,@E,&X,&E);}
expr(A) ::= expr(X) NOT NULL(E). {spanUnaryPostfix(&A,pParse,TK_NOTNULL,&X,&E);}
%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 ){
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(X) IS expr(Y). {
spanBinaryExpr(&A,pParse,TK_IS,&X,&Y);
binaryToUnaryIfNull(pParse, Y.pExpr, A.pExpr, TK_ISNULL);
}
expr(A) ::= expr(X) IS NOT expr(Y). {
spanBinaryExpr(&A,pParse,TK_ISNOT,&X,&Y);
binaryToUnaryIfNull(pParse, Y.pExpr, A.pExpr, TK_NOTNULL);
}
%include {
/* Construct an expression node for a unary prefix operator
*/
static void spanUnaryPrefix(
ExprSpan *pOut, /* Write the new expression node here */
Parse *pParse, /* Parsing context to record errors */
int op, /* The operator */
ExprSpan *pOperand, /* The operand */
Token *pPreOp /* The operand token for setting the span */
){
pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0);
pOut->zStart = pPreOp->z;
pOut->zEnd = pOperand->zEnd;
}
}
expr(A) ::= NOT(B) expr(X). {spanUnaryPrefix(&A,pParse,@B,&X,&B);}
expr(A) ::= BITNOT(B) expr(X). {spanUnaryPrefix(&A,pParse,@B,&X,&B);}
expr(A) ::= MINUS(B) expr(X). [BITNOT]
{spanUnaryPrefix(&A,pParse,TK_UMINUS,&X,&B);}
expr(A) ::= PLUS(B) expr(X). [BITNOT]
{spanUnaryPrefix(&A,pParse,TK_UPLUS,&X,&B);}
%type between_op {int}
between_op(A) ::= BETWEEN. {A = 0;}
between_op(A) ::= NOT BETWEEN. {A = 1;}
expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
ExprList *pList = sqlite3ExprListAppend(pParse,0, X.pExpr);
pList = sqlite3ExprListAppend(pParse,pList, Y.pExpr);
A.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, W.pExpr, 0, 0);
if( A.pExpr ){
A.pExpr->x.pList = pList;
}else{
sqlite3ExprListDelete(pParse->db, pList);
}
exprNot(pParse, N, &A.pExpr);
A.zStart = W.zStart;
A.zEnd = Y.zEnd;
}
%ifndef SQLITE_OMIT_SUBQUERY
%type in_op {int}
in_op(A) ::= IN. {A = 0;}
in_op(A) ::= NOT IN. {A = 1;}
expr(A) ::= expr(X) in_op(N) LP exprlist(Y) RP(E). [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.
*/
A.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[N]);
sqlite3ExprDelete(pParse->db, X.pExpr);
}else if( Y->nExpr==1 ){
/* Expressions of the form:
**
** expr1 IN (?1)
** expr1 NOT IN (?2)
**
** with exactly one value on the RHS can be simplified to something
** like this:
**
** expr1 == ?1
** expr1 <> ?2
**
** But, the RHS of the == or <> is marked with the EP_Generic flag
** so that it may not contribute to the computation of comparison
** affinity or the collating sequence to use for comparison. Otherwise,
** the semantics would be subtly different from IN or NOT IN.
*/
Expr *pRHS = Y->a[0].pExpr;
Y->a[0].pExpr = 0;
sqlite3ExprListDelete(pParse->db, Y);
/* pRHS cannot be NULL because a malloc error would have been detected
** before now and control would have never reached this point */
if( ALWAYS(pRHS) ){
pRHS->flags &= ~EP_Collate;
pRHS->flags |= EP_Generic;
}
A.pExpr = sqlite3PExpr(pParse, N ? TK_NE : TK_EQ, X.pExpr, pRHS, 0);
}else{
A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0);
if( A.pExpr ){
A.pExpr->x.pList = Y;
sqlite3ExprSetHeightAndFlags(pParse, A.pExpr);
}else{
sqlite3ExprListDelete(pParse->db, Y);
}
exprNot(pParse, N, &A.pExpr);
}
A.zStart = X.zStart;
A.zEnd = &E.z[E.n];
}
expr(A) ::= LP(B) select(X) RP(E). {
A.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
if( A.pExpr ){
A.pExpr->x.pSelect = X;
ExprSetProperty(A.pExpr, EP_xIsSelect|EP_Subquery);
sqlite3ExprSetHeightAndFlags(pParse, A.pExpr);
}else{
sqlite3SelectDelete(pParse->db, X);
}
A.zStart = B.z;
A.zEnd = &E.z[E.n];
}
expr(A) ::= expr(X) in_op(N) LP select(Y) RP(E). [IN] {
A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0);
if( A.pExpr ){
A.pExpr->x.pSelect = Y;
ExprSetProperty(A.pExpr, EP_xIsSelect|EP_Subquery);
sqlite3ExprSetHeightAndFlags(pParse, A.pExpr);
}else{
sqlite3SelectDelete(pParse->db, Y);
}
exprNot(pParse, N, &A.pExpr);
A.zStart = X.zStart;
A.zEnd = &E.z[E.n];
}
expr(A) ::= expr(X) in_op(N) nm(Y) dbnm(Z). [IN] {
SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&Y,&Z);
A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0);
if( A.pExpr ){
#ifdef MAXSCALE
A.pExpr->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0,0);
#else
A.pExpr->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
#endif
ExprSetProperty(A.pExpr, EP_xIsSelect|EP_Subquery);
sqlite3ExprSetHeightAndFlags(pParse, A.pExpr);
}else{
sqlite3SrcListDelete(pParse->db, pSrc);
}
exprNot(pParse, N, &A.pExpr);
A.zStart = X.zStart;
A.zEnd = Z.z ? &Z.z[Z.n] : &Y.z[Y.n];
}
expr(A) ::= EXISTS(B) LP select(Y) RP(E). {
Expr *p = A.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
if( p ){
p->x.pSelect = Y;
ExprSetProperty(p, EP_xIsSelect|EP_Subquery);
sqlite3ExprSetHeightAndFlags(pParse, p);
}else{
sqlite3SelectDelete(pParse->db, Y);
}
A.zStart = B.z;
A.zEnd = &E.z[E.n];
}
%endif SQLITE_OMIT_SUBQUERY
/* CASE expressions */
expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
A.pExpr = sqlite3PExpr(pParse, TK_CASE, X, 0, 0);
if( A.pExpr ){
A.pExpr->x.pList = Z ? sqlite3ExprListAppend(pParse,Y,Z) : Y;
sqlite3ExprSetHeightAndFlags(pParse, A.pExpr);
}else{
sqlite3ExprListDelete(pParse->db, Y);
sqlite3ExprDelete(pParse->db, Z);
}
A.zStart = C.z;
A.zEnd = &E.z[E.n];
}
%type case_exprlist {ExprList*}
%destructor case_exprlist {sqlite3ExprListDelete(pParse->db, $$);}
case_exprlist(A) ::= case_exprlist(X) WHEN expr(Y) THEN expr(Z). {
A = sqlite3ExprListAppend(pParse,X, Y.pExpr);
A = sqlite3ExprListAppend(pParse,A, Z.pExpr);
}
case_exprlist(A) ::= WHEN expr(Y) THEN expr(Z). {
A = sqlite3ExprListAppend(pParse,0, Y.pExpr);
A = sqlite3ExprListAppend(pParse,A, Z.pExpr);
}
%type case_else {Expr*}
%destructor case_else {sqlite3ExprDelete(pParse->db, $$);}
case_else(A) ::= ELSE expr(X). {A = X.pExpr;}
case_else(A) ::= . {A = 0;}
%type case_operand {Expr*}
%destructor case_operand {sqlite3ExprDelete(pParse->db, $$);}
case_operand(A) ::= expr(X). {A = X.pExpr;}
case_operand(A) ::= . {A = 0;}
%type exprlist {ExprList*}
%destructor exprlist {sqlite3ExprListDelete(pParse->db, $$);}
%type nexprlist {ExprList*}
%destructor nexprlist {sqlite3ExprListDelete(pParse->db, $$);}
exprlist(A) ::= nexprlist(X). {A = X;}
exprlist(A) ::= . {A = 0;}
nexprlist(A) ::= nexprlist(X) COMMA expr(Y).
{A = sqlite3ExprListAppend(pParse,X,Y.pExpr);}
nexprlist(A) ::= expr(Y).
{A = sqlite3ExprListAppend(pParse,0,Y.pExpr);}
%ifdef MAXSCALE
nexprlist(A) ::= expr(Y) AS typename.
{A = sqlite3ExprListAppend(pParse,0,Y.pExpr);}
nexprlist(A) ::= nexprlist(X) COMMA expr(Y) AS typename.
{A = sqlite3ExprListAppend(pParse,X,Y.pExpr);}
%endif
///////////////////////////// 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). {
#ifdef MAXSCALE
mxs_sqlite3CreateIndex(pParse, &X, &D,
sqlite3SrcListAppend(pParse->db,0,&Y,0), Z, U,
&S, W, SQLITE_SO_ASC, NE);
#else
sqlite3CreateIndex(pParse, &X, &D,
sqlite3SrcListAppend(pParse->db,0,&Y,0), Z, U,
&S, W, SQLITE_SO_ASC, NE);
#endif
}
%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_master schema.
// 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(X) COMMA nm(Y) collate(C) sortorder(Z). {
A = parserAddExprIdListTerm(pParse, X, &Y, C, Z);
}
eidlist(A) ::= nm(Y) collate(C) sortorder(Z). {
A = parserAddExprIdListTerm(pParse, 0, &Y, C, Z);
}
%type collate {int}
collate(C) ::= . {C = 0;}
collate(C) ::= COLLATE ids. {C = 1;}
///////////////////////////// The DROP INDEX command /////////////////////////
//
%ifdef MAXSCALE
%type drop_index_algorithm_option {int}
drop_index_algorithm_option(A) ::= DEFAULT. {A=0;}
drop_index_algorithm_option(A) ::= id. {
// Here we could verify that the id is "COPY" or "INPLACE"
A=1;
}
%type drop_index_algorithm {int}
drop_index_algorithm(A) ::= ALGORITHM drop_index_algorithm_option(X). {A=X;}
drop_index_algorithm(A) ::= ALGORITHM EQ drop_index_algorithm_option(X). {A=X;}
%type drop_index_lock_option {int}
drop_index_lock_option(A) ::= DEFAULT. {A=0;}
drop_index_lock_option(A) ::= id. {
// Here we could verify that the id is "EXCLUSIVE", "NONE" or "SHARED".
A=4;
}
%type drop_index_lock {int}
drop_index_lock(A) ::= LOCK drop_index_lock_option(X). {A=X;}
drop_index_lock(A) ::= LOCK EQ drop_index_lock_option(X). {A=X;}
%type drop_index_options {int}
drop_index_options(A) ::= . {A=0;}
drop_index_options(A) ::= drop_index_options(X) drop_index_algorithm(Y). {A=X|Y;}
drop_index_options(A) ::= drop_index_options(X) drop_index_lock(Y). {A=X|Y;}
cmd ::= DROP INDEX fullname(X) ON fullname(Y) drop_index_options(Z). {
mxs_sqlite3DropIndex(pParse, X, Y, Z);
}
%endif
%ifndef MAXSCALE
cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);}
%endif
///////////////////////////// The VACUUM command /////////////////////////////
//
%ifndef SQLITE_OMIT_VACUUM
%ifndef SQLITE_OMIT_ATTACH
cmd ::= VACUUM. {sqlite3Vacuum(pParse);}
cmd ::= VACUUM nm. {sqlite3Vacuum(pParse);}
%endif SQLITE_OMIT_ATTACH
%endif SQLITE_OMIT_VACUUM
///////////////////////////// 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(X). {A = X;}
nmnum(A) ::= nm(X). {A = X;}
nmnum(A) ::= ON(X). {A = X;}
nmnum(A) ::= DELETE(X). {A = X;}
nmnum(A) ::= DEFAULT(X). {A = X;}
%endif SQLITE_OMIT_PRAGMA
%token_class number INTEGER|FLOAT.
plus_num(A) ::= PLUS number(X). {A = X;}
plus_num(A) ::= number(X). {A = X;}
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;
#ifdef MAXSCALE
mxs_sqlite3FinishTrigger(pParse, S, &all);
#else
sqlite3FinishTrigger(pParse, S, &all);
#endif
}
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). {
#ifdef MAXSCALE
mxs_sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, E, G, T, NOERR);
#else
sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, E, G, T, NOERR);
#endif
A = (Z.n==0?B:Z);
}
%type trigger_time {int}
trigger_time(A) ::= BEFORE. { A = TK_BEFORE; }
trigger_time(A) ::= AFTER. { A = TK_AFTER; }
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(OP). {A.a = @OP; A.b = 0;}
trigger_event(A) ::= UPDATE(OP). {A.a = @OP; 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.pExpr; }
%type trigger_cmd_list {TriggerStep*}
%destructor trigger_cmd_list {sqlite3DeleteTriggerStep(pParse->db, $$);}
trigger_cmd_list(A) ::= trigger_cmd_list(Y) trigger_cmd(X) SEMI. {
assert( Y!=0 );
Y->pLast->pNext = X;
Y->pLast = X;
A = Y;
}
trigger_cmd_list(A) ::= trigger_cmd(X) SEMI. {
assert( X!=0 );
X->pLast = X;
A = X;
}
// 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(X). {A = X;}
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 orconf(R) trnm(X) tridxby SET setlist(Y) where_opt(Z).
{ A = sqlite3TriggerUpdateStep(pParse->db, &X, Y, Z, R); }
// INSERT
trigger_cmd(A) ::= insert_cmd(R) INTO trnm(X) idlist_opt(F) select(S).
{A = sqlite3TriggerInsertStep(pParse->db, &X, F, S, R);}
// DELETE
trigger_cmd(A) ::= DELETE FROM trnm(X) tridxby where_opt(Y).
{A = sqlite3TriggerDeleteStep(pParse->db, &X, Y);}
// SELECT
trigger_cmd(A) ::= select(X). {A = sqlite3TriggerSelectStep(pParse->db, X); }
// The special RAISE expression that may occur in trigger programs
expr(A) ::= RAISE(X) LP IGNORE RP(Y). {
A.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0);
if( A.pExpr ){
A.pExpr->affinity = OE_Ignore;
}
A.zStart = X.z;
A.zEnd = &Y.z[Y.n];
}
%ifndef MAXSCALE
expr(A) ::= RAISE(X) LP raisetype(T) COMMA nm(Z) RP(Y). {
A.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &Z);
if( A.pExpr ) {
A.pExpr->affinity = (char)T;
}
A.zStart = X.z;
A.zEnd = &Y.z[Y.n];
}
%endif
%endif !SQLITE_OMIT_TRIGGER
%ifndef MAXSCALE
%type raisetype {int}
raisetype(A) ::= ROLLBACK. {A = OE_Rollback;}
raisetype(A) ::= ABORT. {A = OE_Abort;}
raisetype(A) ::= FAIL. {A = OE_Fail;}
%endif
//////////////////////// 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.pExpr, D.pExpr, K);
}
cmd ::= DETACH database_kw_opt expr(D). {
sqlite3Detach(pParse, D.pExpr);
}
%type key_opt {Expr*}
%destructor key_opt {sqlite3ExprDelete(pParse->db, $$);}
key_opt(A) ::= . { A = 0; }
key_opt(A) ::= KEY expr(X). { A = X.pExpr; }
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
%ifdef MAXSCALE
analyze_options ::= .
analyze_options ::= NO_WRITE_TO_BINLOG.
analyze_options ::= LOCAL.
cmd ::= ANALYZE analyze_options TABLE fullnames(X). {mxs_sqlite3Analyze(pParse, X);}
%endif
%ifndef MAXSCALE
cmd ::= ANALYZE. {sqlite3Analyze(pParse, 0, 0);}
cmd ::= ANALYZE nm(X) dbnm(Y). {sqlite3Analyze(pParse, &X, &Y);}
%endif
%endif
//////////////////////// ALTER TABLE table ... ////////////////////////////////
%ifndef SQLITE_OMIT_ALTERTABLE
%ifndef MAXSCALE
cmd ::= ALTER TABLE fullname(X) RENAME TO nm(Z). {
sqlite3AlterRenameTable(pParse,X,&Z);
}
cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column(Y). {
sqlite3AlterFinishAddColumn(pParse, &Y);
}
%endif
%ifdef MAXSCALE
first_opt ::= .
first_opt ::= FIRST.
as_or_to_opt ::= .
as_or_to_opt ::= AS.
as_or_to_opt ::= TO.
cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column(Y) first_opt. {
mxs_sqlite3AlterFinishAddColumn(pParse, &Y);
}
cmd ::= ALTER TABLE fullname(X) ENABLE KEYS. {
maxscaleAlterTable(pParse,MXS_ALTER_ENABLE_KEYS,X,0);
}
cmd ::= ALTER TABLE fullname(X) DISABLE KEYS. {
maxscaleAlterTable(pParse,MXS_ALTER_DISABLE_KEYS,X,0);
}
cmd ::= ALTER TABLE fullname(X) RENAME as_or_to_opt nm(Z). {
maxscaleAlterTable(pParse,MXS_ALTER_RENAME,X,&Z);
}
%endif
add_column_fullname ::= fullname(X). {
disableLookaside(pParse);
#ifdef MAXSCALE
mxs_sqlite3AlterBeginAddColumn(pParse, X);
#else
sqlite3AlterBeginAddColumn(pParse, X);
#endif
}
kwcolumn_opt ::= .
kwcolumn_opt ::= COLUMNKW.
%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 with {With*}
%type wqlist {With*}
%destructor with {sqlite3WithDelete(pParse->db, $$);}
%destructor wqlist {sqlite3WithDelete(pParse->db, $$);}
with(A) ::= . {A = 0;}
%ifndef SQLITE_OMIT_CTE
with(A) ::= WITH wqlist(W). { A = W; }
with(A) ::= WITH RECURSIVE wqlist(W). { A = W; }
wqlist(A) ::= nm(X) eidlist_opt(Y) AS LP select(Z) RP. {
A = sqlite3WithAdd(pParse, 0, &X, Y, Z);
}
wqlist(A) ::= wqlist(W) COMMA nm(X) eidlist_opt(Y) AS LP select(Z) RP. {
A = sqlite3WithAdd(pParse, W, &X, Y, Z);
}
%endif SQLITE_OMIT_CTE
%ifdef MAXSCALE
/*
** MaxScale additions.
**
** New grammar rules made for MaxScale follow here.
**
*/
cmd ::= do.
do ::= DO nexprlist(X). {
maxscaleDo(pParse, X);
}
%type type_options {int}
type_options(A) ::= . {A=0;}
type_options(A) ::= type_options UNSIGNED. {A|=1;}
type_options(A) ::= type_options ZEROFILL. {A|=2;}
type_options(A) ::= type_options BINARY. {A|=4;}
type_options(A) ::= type_options CHARACTER SET ids. {A|=8;}
type_options(A) ::= type_options CHARSET ids. {A|=8;}
// deferred_id is used instead of id before the token_class id has been defined.
deferred_id(A) ::= id(X). {A=X;}
as_opt ::= .
as_opt ::= AS.
eq_opt ::= .
eq_opt ::= EQ.
default_opt ::= .
default_opt ::= DEFAULT.
//////////////////////// CALL statement ////////////////////////////////////
//
cmd ::= call.
%type call_args_opt {ExprList*}
call_args_opt(A) ::= . {A=0;}
call_args_opt(A) ::= LP exprlist(X) RP. {A=X;}
call ::= CALL fullname(X) call_args_opt(Y). {
maxscaleCall(pParse, X, Y);
}
//////////////////////// DROP FUNCTION statement ////////////////////////////////////
//
cmd ::= DROP FUNCTION_KW ifexists nm(X). {
maxscaleDrop(pParse, MXS_DROP_FUNCTION, NULL, &X);
}
//////////////////////// The CHECK TABLE statement ////////////////////////////////////
//
cmd ::= check.
// FOR UPGRADE | QUICK | FAST | MEDIUM | EXTENDED | CHANGED
check_option ::= FOR id.
check_option ::= QUICK.
check_option ::= id.
check_options ::= check_option.
check_options ::= check_options check_option.
check_options_opt ::= .
check_options_opt ::= check_options.
check ::= CHECK TABLE fullnames(X) check_options_opt. {
maxscaleCheckTable(pParse, X);
}
//////////////////////// The FLUSH statement ////////////////////////////////////
//
cmd ::= flush.
flush ::= FLUSH STATUS(X).
{
maxscaleFlush(pParse, &X);
}
flush ::= FLUSH nm(X).
{
maxscaleFlush(pParse, &X);
}
//////////////////////// The GRANT & REVOKE statements ////////////////////////////////////
//
cmd ::= grant.
grant ::= GRANT. {
maxscalePrivileges(pParse, TK_GRANT);
}
cmd ::= revoke.
revoke ::= REVOKE. {
maxscalePrivileges(pParse, TK_REVOKE);
}
//////////////////////// The HANDLER statement ////////////////////////////////////
//
cmd ::= handler.
handler ::= HANDLER fullname(X) OPEN as_opt nm(Y). {
maxscaleHandler(pParse, MXS_HANDLER_OPEN, X, &Y);
}
handler ::= HANDLER nm(X) CLOSE. {
maxscaleHandler(pParse, MXS_HANDLER_CLOSE, 0, &X);
}
// TODO: Rest of HANDLER commands.
//////////////////////// The LOAD DATA INFILE statement ////////////////////////////////////
//
%type ld_local_opt {int}
cmd ::= load_data.
ld_priority_opt ::= .
ld_priority_opt ::= LOW_PRIORITY.
ld_priority_opt ::= CONCURRENT.
ld_local_opt(A) ::= . {A = 0;}
ld_local_opt(A) ::= LOCAL. {A = 1;}
ld_charset_opt ::= .
ld_charset_opt ::= CHARACTER SET ids.
load_data ::= LOAD DATA ld_priority_opt ld_local_opt(Y)
INFILE STRING ignore_or_replace_opt
INTO TABLE fullname(X)
/* ld_partition_opt */
ld_charset_opt
/* ld_fields_opt */
/* ld_ignore_opt */
/* ld_col_name_or_user_var_opt */
/* ld_set */.
{
maxscaleLoadData(pParse, X, Y);
}
//////////////////////// The LOCK/UNLOCK statement ////////////////////////////////////
//
cmd ::= lock.
lock ::= LOCK table_or_tables lock_target(X).{
maxscaleLock(pParse, MXS_LOCK_LOCK, X);
}
%type lock_target {SrcList*}
%destructor lock_target {sqlite3SrcListDelete(pParse->db, $$);}
lock_target(A) ::= table_factor(X) lock_type. {
A = X;
}
lock_target(A) ::= lock_target(X) COMMA table_factor(Y). {
A = sqlite3SrcListCat(pParse->db, X, Y);
}
%type lock_type {int}
lock_type(A) ::= READ. { A = 1; }
lock_type(A) ::= READ LOCAL. { A = 3; }
lock_type(A) ::= WRITE. { A = 4; }
lock_type(A) ::= LOW_PRIORITY WRITE. { A = 12; }
cmd ::= unlock.
unlock ::= UNLOCK TABLES. {
maxscaleLock(pParse, MXS_LOCK_UNLOCK, 0);
}
//////////////////////// PREPARE and EXECUTE statements ////////////////////////////////////
//
cmd ::= prepare.
cmd ::= execute.
cmd ::= deallocate.
prepare ::= PREPARE nm(X) FROM expr(Y).
{
maxscalePrepare(pParse, &X, Y.pExpr);
}
%type execute_variable {int}
execute_variable(A) ::= INTEGER. {A=0;} // For Oracle
execute_variable(A) ::= VARIABLE. {A=QUERY_TYPE_USERVAR_READ;}
%type execute_variables {int}
execute_variables(A) ::= execute_variable(X). {A=X;}
execute_variables(A) ::= execute_variables(X) COMMA execute_variable(Y). {
A = X|Y;
}
%type execute_variables_opt {int}
execute_variables_opt(A) ::= . {A=0;}
execute_variables_opt(A) ::= USING execute_variables(X). {A=X;}
execute ::= EXECUTE nm(X) execute_variables_opt(Y). {
maxscaleExecute(pParse, &X, Y);
}
execute ::= EXECUTE id(X) expr(Y) execute_variables_opt(Z). {
maxscaleExecuteImmediate(pParse, &X, &Y, Z);
}
dod ::= DEALLOCATE.
dod ::= DROP.
deallocate ::= dod PREPARE nm(X). {
maxscaleDeallocate(pParse, &X);
}
//////////////////////// RENAME statement ////////////////////////////////////
//
cmd ::= rename.
%type table_to_rename {SrcList*}
%destructor table_to_rename {sqlite3SrcListDelete(pParse->db, $$);}
table_to_rename(A) ::= fullname(X) TO nm(Y). {
// The new name is passed in the alias field.
X->a[0].zAlias = sqlite3NameFromToken(pParse->db, &Y);
A = X;
}
%type tables_to_rename {SrcList*}
%destructor tables_to_rename {sqlite3SrcListDelete(pParse->db, $$);}
tables_to_rename(A) ::= table_to_rename(X). {
A = X;
}
tables_to_rename(A) ::= tables_to_rename(X) COMMA table_to_rename(Y).
{
A = sqlite3SrcListCat(pParse->db, X, Y);
}
rename ::= RENAME TABLE tables_to_rename(X). {
maxscaleRenameTable(pParse, X);
}
//////////////////////// The SET statement ////////////////////////////////////
//
%type set_scope {int}
set_scope(A) ::= . { A = 0; }
set_scope(A) ::= GLOBAL(X). { A = @X; }
set_scope(A) ::= SESSION(X). { A = @X; }
set_scope(A) ::= LOCAL. { A = TK_SESSION; }
%type variable {ExprSpan}
%destructor variable { sqlite3ExprDelete(pParse->db, $$.pExpr); }
%type variable_head {ExprSpan}
%destructor variable_head { sqlite3ExprDelete(pParse->db, $$.pExpr); }
%type variable_tail {ExprSpan}
%destructor variable_tail { sqlite3ExprDelete(pParse->db, $$.pExpr); }
variable_head(A) ::= VARIABLE(X). {
A.pExpr = sqlite3PExpr(pParse, TK_VARIABLE, 0, 0, &X);
spanSet(&A, &X, &X);
}
variable_head(A) ::= id(X). {
A.pExpr = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
spanSet(&A, &X, &X);
}
variable_tail(A) ::= DOT(D) id(X). {
Expr* pName = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
A.pExpr = sqlite3PExpr(pParse, TK_DOT, 0, pName, 0);
spanSet(&A, &D, &X);
}
variable_tail(A) ::= variable_tail(X) DOT id(Y). {
assert(!X.pExpr->pLeft);
X.pExpr->pLeft = X.pExpr->pRight;
Expr* pName = sqlite3PExpr(pParse, TK_ID, 0, 0, &Y);
X.pExpr->pRight = pName;
A = X;
A.zStart = X.zStart;
A.zEnd = X.zEnd;
}
variable(A) ::= variable_head(X). {
A = X;
}
variable(A) ::= variable_head(X) variable_tail(Y). {
A.pExpr = sqlite3PExpr(pParse, TK_DOT, X.pExpr, Y.pExpr, 0);
A.zStart = X.zStart;
A.zEnd = Y.zEnd;
}
%type variable_assignment {Expr*}
%destructor variable_assignment {sqlite3ExprDelete(pParse->db, $$);}
variable_assignment(A) ::= set_scope variable(X) EQ expr(Y). {
A = sqlite3PExpr(pParse, TK_EQ, X.pExpr, Y.pExpr, 0);
}
variable_assignment(A) ::= set_scope variable(X) EQ ON. {
Expr* pOn = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, 0);
pOn->u.iValue = 1;
A = sqlite3PExpr(pParse, TK_EQ, X.pExpr, pOn, 0);
}
variable_assignment(A) ::= set_scope variable(X) EQ ALL. {
Expr* pOn = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, 0);
pOn->u.iValue = 1;
A = sqlite3PExpr(pParse, TK_EQ, X.pExpr, pOn, 0);
}
set_names_arg ::= ids. // 'charset_name'
set_names_arg ::= ids COLLATE ids. // 'charset_name' COLLATE 'collation_name'
set_names_arg ::= DEFAULT.
variable_assignment(A) ::= NAMES set_names_arg. {
A = sqlite3PExpr(pParse, TK_NAMES, 0, 0, 0);
}
set_character_set_arg ::= ids.
set_character_set_arg ::= DEFAULT.
variable_assignment(A) ::= CHARACTER SET set_character_set_arg. {
A = sqlite3PExpr(pParse, TK_CHARACTER, 0, 0, 0);
}
%type variable_assignments {ExprList*}
%destructor variable_assignments {sqlite3ExprListDelete(pParse->db, $$);}
variable_assignments(A) ::= variable_assignment(X). {
A = sqlite3ExprListAppend(pParse, 0, X);
}
variable_assignments(A) ::= variable_assignments(X) COMMA variable_assignment(Y). {
A = sqlite3ExprListAppend(pParse, X, Y);
}
cmd ::= SET variable_assignments(Y). {
maxscaleSet(pParse, 0, MXS_SET_VARIABLES, Y);
}
transaction_characteristic ::= READ WRITE.
transaction_characteristic ::= READ id. // READ ONLY
transaction_characteristic ::= id id transaction_level. // ISOLATION LEVEL transaction_level
transaction_level ::= id READ. // REPEATABLE READ
transaction_level ::= READ id. // {READ COMMITTED|READ UNCOMMITTED}
transaction_level ::= id. // SERIALIZABLE
transaction_characteristics ::= transaction_characteristic.
transaction_characteristics ::= transaction_characteristics COMMA transaction_characteristic.
cmd ::= SET set_scope(X) TRANSACTION transaction_characteristics. {
maxscaleSet(pParse, X, MXS_SET_TRANSACTION, 0);
}
cmd ::= SET STATEMENT variable_assignments(X) FOR cmd. {
// The parsing of cmd will cause the relevant maxscale-callback to
// be called, so we neither need to call it here, nor free cmd (as
// it will be freed by that callback). The variable definitions we
// just throw away, as they are of no interest.
sqlite3ExprListDelete(pParse->db, X);
}
//////////////////////// The USE statement ////////////////////////////////////
//
cmd ::= use(X). {
maxscaleUse(pParse, &X);
}
%type use {Token}
use(A) ::= USE id(X). {A = X;}
//////////////////////// The SHOW statement ////////////////////////////////////
//
cmd ::= show(X). {
maxscaleShow(pParse, &X);
}
from_or_in ::= FROM.
from_or_in ::= IN.
from_or_in_db_opt(A) ::= . { A.z = 0; A.n = 0; }
from_or_in_db_opt(A) ::= FROM nm(X). { A = X; }
from_or_in_db_opt(A) ::= IN nm(X). { A = X; }
// sqlite returns FULL (as well as CROSS, INNER, LEFT,
// NATURAL, OUTER and RIGHT) as JOIN_KW.
%type full_opt {u32}
full_opt(A) ::= . { A = 0; }
full_opt(A) ::= JOIN_KW. { A = MXS_SHOW_COLUMNS_FULL; }
like_or_where_opt ::= .
like_or_where_opt ::= LIKE_KW ids.
like_or_where_opt ::= WHERE expr.
%type show {MxsShow}
show(A) ::= SHOW full_opt(X) COLUMNS from_or_in nm(Y) dbnm(Z) from_or_in_db_opt(W) like_or_where_opt . {
A.what = MXS_SHOW_COLUMNS;
A.data = X;
if (Z.z) {
A.pName = &Z;
A.pDatabase = &Y;
}
else if (W.z) {
A.pName = &Y;
A.pDatabase = &W;
}
else {
A.pName = &Y;
A.pDatabase = NULL;
}
}
show(A) ::= SHOW CREATE TABLE nm(X) dbnm(Y). {
A.what = MXS_SHOW_CREATE_TABLE;
A.data = 0;
if (Y.z) {
A.pName = &Y;
A.pDatabase = &X;
}
else {
A.pName = &X;
A.pDatabase = NULL;
}
}
show(A) ::= SHOW CREATE VIEW nm(X) dbnm(Y). {
A.what = MXS_SHOW_CREATE_VIEW;
A.data = 0;
if (Y.z) {
A.pName = &Y;
A.pDatabase = &X;
}
else {
A.pName = &X;
A.pDatabase = NULL;
}
}
show(A) ::= SHOW CREATE SEQUENCE nm(X) dbnm(Y). {
A.what = MXS_SHOW_CREATE_SEQUENCE;
A.data = 0;
if (Y.z) {
A.pName = &Y;
A.pDatabase = &X;
}
else {
A.pName = &X;
A.pDatabase = NULL;
}
}
show(A) ::= SHOW DATABASES_KW like_or_where_opt. {
A.what = MXS_SHOW_DATABASES;
A.data = 0;
A.pName = NULL;
A.pDatabase = NULL;
}
show(A) ::= SHOW ALL id STATUS. { // SHOW ALL SLAVES STATUS
A.what = MXS_SHOW_STATUS;
A.data = MXS_SHOW_STATUS_ALL_SLAVES;
A.pName = NULL;
A.pDatabase = NULL;
}
show(A) ::= SHOW MASTER STATUS. {
A.what = MXS_SHOW_STATUS;
A.data = MXS_SHOW_STATUS_MASTER;
A.pName = NULL;
A.pDatabase = NULL;
}
show(A) ::= SHOW SLAVE STATUS. {
A.what = MXS_SHOW_STATUS;
A.data = MXS_SHOW_STATUS_SLAVE;
A.pName = NULL;
A.pDatabase = NULL;
}
%type index_indexes_keys {int}
index_indexes_keys(A) ::= INDEX. {A = MXS_SHOW_INDEX;}
index_indexes_keys(A) ::= INDEXES. {A = MXS_SHOW_INDEXES;}
index_indexes_keys(A) ::= KEYS. {A = MXS_SHOW_KEYS;}
show(A) ::= SHOW index_indexes_keys(X) from_or_in nm(Y) dbnm(Z) from_or_in_db_opt where_opt . {
A.what = X;
A.data = 0;
if (Z.z) {
A.pName = &Z;
A.pDatabase = &Y;
}
else {
A.pName = &Y;
A.pDatabase = NULL;
}
}
%type global_session_local_opt {int}
global_session_local_opt(A) ::= . {A=MXS_SHOW_VARIABLES_UNSPECIFIED;}
global_session_local_opt(A) ::= GLOBAL. {A=MXS_SHOW_VARIABLES_GLOBAL;}
global_session_local_opt(A) ::= LOCAL. {A=MXS_SHOW_VARIABLES_SESSION;}
global_session_local_opt(A) ::= SESSION. {A=MXS_SHOW_VARIABLES_SESSION;}
show(A) ::= SHOW global_session_local_opt(X) STATUS like_or_where_opt. {
A.what = MXS_SHOW_STATUS;
A.data = X;
A.pName = NULL;
A.pDatabase = NULL;
}
show(A) ::= SHOW full_opt(X) TABLES from_or_in_db_opt(Y) like_or_where_opt. {
A.what = MXS_SHOW_TABLES;
A.data = X;
A.pDatabase = &Y;
A.pName = NULL;
}
show(A) ::= SHOW TABLE STATUS from_or_in_db_opt(X) like_or_where_opt. {
A.what = MXS_SHOW_TABLE_STATUS;
A.data = 0;
A.pDatabase = &X;
A.pName = NULL;
}
show(A) ::= SHOW global_session_local_opt(X) VARIABLES like_or_where_opt. {
A.what = MXS_SHOW_VARIABLES;
A.data = X;
A.pName = NULL;
A.pDatabase = NULL;
}
show_warnings_options ::= .
show_warnings_options ::= LIMIT INTEGER.
show_warnings_options ::= LIMIT INTEGER COMMA INTEGER.
show(A) ::= SHOW WARNINGS show_warnings_options. {
A.what = MXS_SHOW_WARNINGS;
A.data = 0;
A.pName = NULL;
A.pDatabase = NULL;
}
//////////////////////// The START TRANSACTION statement ////////////////////////////////////
//
%type start_transaction_characteristic {int}
start_transaction_characteristic(A) ::= READ WRITE. {
A = QUERY_TYPE_WRITE;
}
start_transaction_characteristic(A) ::= READ id. { // READ ONLY
A = QUERY_TYPE_READ;
}
start_transaction_characteristic(A) ::= WITH id id. { // WITH CONSISTENT SNAPSHOT
A = 0;
}
%type start_transaction_characteristics {int}
start_transaction_characteristics(A) ::= .
{
A = 0;
}
start_transaction_characteristics(A) ::= start_transaction_characteristic(X).
{
A = X;
}
start_transaction_characteristics(A) ::=
start_transaction_characteristics(X) COMMA start_transaction_characteristic(Y). {
A = X | Y;
}
cmd ::= START TRANSACTION start_transaction_characteristics(X). {
mxs_sqlite3BeginTransaction(pParse, TK_START, X);
}
//////////////////////// The TRUNCATE statement ////////////////////////////////////
//
table_opt ::= .
table_opt ::= TABLE.
cmd ::= TRUNCATE table_opt nm(X) dbnm(Y). {
Token* pName;
Token* pDatabase;
if (Y.z) {
pDatabase = &X;
pName = &Y;
}
else {
pDatabase = NULL;
pName = &X;
}
maxscaleTruncate(pParse, pDatabase, pName);
}
//////////////////////// ORACLE Assignment ////////////////////////////////////
//
oracle_assignment ::= id(X) EQ expr(Y). {
Expr* pX = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
Expr* pExpr = sqlite3PExpr(pParse, TK_EQ, pX, Y.pExpr, 0);
ExprList* pExprList = sqlite3ExprListAppend(pParse, 0, pExpr);
maxscaleSet(pParse, 0, MXS_SET_VARIABLES, pExprList);
}
//////////////////////// ORACLE CREATE SEQUENCE ////////////////////////////////////
//
cmd ::= CREATE SEQUENCE nm(X) dbnm(Y).{ // CREATE SEQUENCE db
Token* pDatabase;
Token* pTable;
if (Y.z)
{
pDatabase = &X;
pTable = &Y;
}
else
{
pDatabase = NULL;
pTable = &X;
}
maxscaleCreateSequence(pParse, pDatabase, pTable);
}
//////////////////////// ORACLE CREATE SEQUENCE ////////////////////////////////////
//
cmd ::= DROP SEQUENCE nm(X) dbnm(Y).{ // CREATE SEQUENCE db
Token* pDatabase;
Token* pTable;
if (Y.z)
{
pDatabase = &X;
pTable = &Y;
}
else
{
pDatabase = NULL;
pTable = &X;
}
maxscaleDrop(pParse, MXS_DROP_SEQUENCE, pDatabase, pTable);
}
//////////////////////// ORACLE DECLARE ////////////////////////////////////
//
cmd ::= DECLARE. {
maxscaleDeclare(pParse);
}
%endif