diff --git a/query_classifier/qc_sqlite/sqlite-src-3110100/configure b/query_classifier/qc_sqlite/sqlite-src-3110100/configure index 8fdbb45ec..69a2d50d3 100755 --- a/query_classifier/qc_sqlite/sqlite-src-3110100/configure +++ b/query_classifier/qc_sqlite/sqlite-src-3110100/configure @@ -908,6 +908,7 @@ enable_fts4 enable_fts5 enable_json1 enable_rtree +enable_maxscale enable_gcov ' ac_precious_vars='build_alias @@ -1556,6 +1557,7 @@ Optional Features: --enable-fts5 Enable the FTS5 extension --enable-json1 Enable the JSON1 extension --enable-rtree Enable the RTREE extension + --enable-maxscale Enable MaxScale extensions --enable-gcov Enable coverage testing using gcov Optional Packages: @@ -3923,13 +3925,13 @@ if ${lt_cv_nm_interface+:} false; then : else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:3926: $ac_compile\"" >&5) + (eval echo "\"\$as_me:3928: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 - (eval echo "\"\$as_me:3929: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval echo "\"\$as_me:3931: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 - (eval echo "\"\$as_me:3932: output\"" >&5) + (eval echo "\"\$as_me:3934: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" @@ -5135,7 +5137,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 5138 "configure"' > conftest.$ac_ext + echo '#line 5140 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -6660,11 +6662,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:6663: $lt_compile\"" >&5) + (eval echo "\"\$as_me:6665: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:6667: \$? = $ac_status" >&5 + echo "$as_me:6669: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -6999,11 +7001,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7002: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7004: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7006: \$? = $ac_status" >&5 + echo "$as_me:7008: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7104,11 +7106,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7107: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7109: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7111: \$? = $ac_status" >&5 + echo "$as_me:7113: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -7159,11 +7161,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7162: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7164: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7166: \$? = $ac_status" >&5 + echo "$as_me:7168: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -9539,7 +9541,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 9542 "configure" +#line 9544 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -9635,7 +9637,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 9638 "configure" +#line 9640 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11494,6 +11496,21 @@ if test "${enable_rtree}" = "yes" ; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_RTREE" fi +######### +# See whether we should enable MaxScale +# Check whether --enable-maxscale was given. +if test "${enable_maxscale+set}" = set; then : + enableval=$enable_maxscale; enable_maxscale=yes +else + enable_maxscale=no +fi + +if test "${enable_maxscale}" = "yes" ; then + # If something is added here, check the obvious 'add_definitions' + # in ../CMakeLists.txt + OPT_FEATURE_FLAGS="$OPT_FEATURE_FLAGS -DMAXSCALE -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT -DSQLITE_OMIT_ATTACH -DSQLITE_OMIT_REINDEX -DSQLITE_OMIT_AUTOVACUUM -DSQLITE_OMIT_PRAGMA -DSQLITE_OMIT_VIRTUALTABLE" +fi + ######### # attempt to duplicate any OMITS and ENABLES into the $(OPT_FEATURE_FLAGS) parameter for option in $CFLAGS $CPPFLAGS diff --git a/query_classifier/qc_sqlite/sqlite-src-3110100/configure.ac b/query_classifier/qc_sqlite/sqlite-src-3110100/configure.ac index 19f85dc87..5c2c8774f 100644 --- a/query_classifier/qc_sqlite/sqlite-src-3110100/configure.ac +++ b/query_classifier/qc_sqlite/sqlite-src-3110100/configure.ac @@ -615,6 +615,15 @@ if test "${enable_rtree}" = "yes" ; then OPT_FEATURE_FLAGS+=" -DSQLITE_ENABLE_RTREE" fi +######### +# See whether we should enable MaxScale +AC_ARG_ENABLE(maxscale, AC_HELP_STRING([--enable-maxscale], + [Enable MaxScale extensions]), + [enable_maxscale=yes],[enable_maxscale=no]) +if test "${enable_maxscale}" = "yes" ; then + OPT_FEATURE_FLAGS+=" -DMAXSCALE -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT -DSQLITE_OMIT_ATTACH -DSQLITE_OMIT_REINDEX -DSQLITE_OMIT_AUTOVACUUM -DSQLITE_OMIT_PRAGMA" +fi + ######### # attempt to duplicate any OMITS and ENABLES into the $(OPT_FEATURE_FLAGS) parameter for option in $CFLAGS $CPPFLAGS diff --git a/query_classifier/qc_sqlite/sqlite-src-3110100/src/alter.c b/query_classifier/qc_sqlite/sqlite-src-3110100/src/alter.c index 34221777a..0acc31d74 100644 --- a/query_classifier/qc_sqlite/sqlite-src-3110100/src/alter.c +++ b/query_classifier/qc_sqlite/sqlite-src-3110100/src/alter.c @@ -72,7 +72,11 @@ static void renameTableFunc( */ do { zCsr += len; +#ifdef MAXSCALE + len = sqlite3GetToken(0, zCsr, &token); +#else len = sqlite3GetToken(zCsr, &token); +#endif } while( token==TK_SPACE ); assert( len>0 ); } while( token!=TK_LP && token!=TK_USING ); @@ -118,12 +122,20 @@ static void renameParentFunc( UNUSED_PARAMETER(NotUsed); if( zInput==0 || zOld==0 ) return; for(z=zInput; *z; z=z+n){ +#ifdef MAXSCALE + n = sqlite3GetToken(0, z, &token); +#else n = sqlite3GetToken(z, &token); +#endif if( token==TK_REFERENCES ){ char *zParent; do { z += n; +#ifdef MAXSCALE + n = sqlite3GetToken(0, z, &token); +#else n = sqlite3GetToken(z, &token); +#endif }while( token==TK_SPACE ); if( token==TK_ILLEGAL ) break; @@ -196,7 +208,11 @@ static void renameTriggerFunc( */ do { zCsr += len; +#ifdef MAXSCALE + len = sqlite3GetToken(0, zCsr, &token); +#else len = sqlite3GetToken(zCsr, &token); +#endif }while( token==TK_SPACE ); assert( len>0 ); diff --git a/query_classifier/qc_sqlite/sqlite-src-3110100/src/build.c b/query_classifier/qc_sqlite/sqlite-src-3110100/src/build.c index 250dc20d2..477d6094c 100644 --- a/query_classifier/qc_sqlite/sqlite-src-3110100/src/build.c +++ b/query_classifier/qc_sqlite/sqlite-src-3110100/src/build.c @@ -3728,6 +3728,43 @@ SrcList *sqlite3SrcListAppend( return pList; } +#ifdef MAXSCALE +/* +** Catenate the items of one SrcList object to the end of another +** SrcList object. +** +** If either of the provided lists is NULL, then the other list +** is returned as such. If both are NULL, then NULL is returned. +** If the operation is performed successfully, then the returned +** list will contain the items of both lists. In that case, pTail +** has been deleted. +** +** If a memory allocation fails, both lists are unchanged. The +** db->mallocFailed flag will be set to true. +*/ +SrcList* sqlite3SrcListCat(sqlite3 *db, SrcList *pHead, SrcList *pTail) +{ + SrcList *pNew; + if ( pTail==0 ){ + return pHead; + } + if ( pHead==0 ){ + return pTail; + } + pNew = sqlite3SrcListEnlarge(db, pHead, pTail->nSrc, pHead->nSrc); + if (!db->mallocFailed){ + int i; + for(i=0; inSrc; i++){ + pNew->a[pNew->nSrc - 1 + i] = pTail->a[i]; + memset(&pTail->a[i], 0, sizeof(pTail->a[0])); + } + pTail->nSrc = 0; + sqlite3SrcListDelete(db, pTail); + } + return pNew; +} +#endif + /* ** Assign VdbeCursor index numbers to all tables in a SrcList */ diff --git a/query_classifier/qc_sqlite/sqlite-src-3110100/src/delete.c b/query_classifier/qc_sqlite/sqlite-src-3110100/src/delete.c index 0fe064bc4..63e827b85 100644 --- a/query_classifier/qc_sqlite/sqlite-src-3110100/src/delete.c +++ b/query_classifier/qc_sqlite/sqlite-src-3110100/src/delete.c @@ -106,8 +106,13 @@ void sqlite3MaterializeView( assert( pFrom->a[0].pOn==0 ); assert( pFrom->a[0].pUsing==0 ); } +#ifdef MAXSCALE + pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, + SF_IncludeHidden, 0, 0, 0); +#else pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, SF_IncludeHidden, 0, 0); +#endif sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur); sqlite3Select(pParse, pSel, &dest); sqlite3SelectDelete(db, pSel); @@ -178,8 +183,13 @@ Expr *sqlite3LimitWhere( } /* generate the SELECT expression tree. */ +#ifdef MAXSCALE + pSelect = sqlite3SelectNew(pParse,pEList,pSelectSrc,pWhere,0,0, + pOrderBy,0,pLimit,pOffset,0); +#else pSelect = sqlite3SelectNew(pParse,pEList,pSelectSrc,pWhere,0,0, pOrderBy,0,pLimit,pOffset); +#endif if( pSelect == 0 ) return 0; /* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */ diff --git a/query_classifier/qc_sqlite/sqlite-src-3110100/src/expr.c b/query_classifier/qc_sqlite/sqlite-src-3110100/src/expr.c index 8d96ba10c..3d2fe78d0 100644 --- a/query_classifier/qc_sqlite/sqlite-src-3110100/src/expr.c +++ b/query_classifier/qc_sqlite/sqlite-src-3110100/src/expr.c @@ -1117,6 +1117,9 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){ pNew->addrOpenEphm[1] = -1; pNew->nSelectRow = p->nSelectRow; pNew->pWith = withDup(db, p->pWith); +#ifdef MAXSCALE + pNew->pInto = sqlite3ExprListDup(db, p->pInto, flags); +#endif sqlite3SelectSetName(pNew, p->zSelName); return pNew; } @@ -1175,6 +1178,49 @@ no_mem: return 0; } +#ifdef MAXSCALE +/* +** Add an expression list to the end of an expression list. If pList +** is initially NULL, then create a new expression list. +** +** If a memory allocation error occurs, the entire list is freed and +** NULL is returned. If non-NULL is returned, then it is guaranteed +** that the list was successfully appended. +*/ +ExprList *sqlite3ExprListAppendList( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* List to which to append. Might be NULL */ + ExprList *pAppend /* List to be appended. Might be NULL */ +){ + sqlite3 *db = pParse->db; + int i; + assert( db!=0 ); + if (!pAppend) { + return pList; + } + if (!pList) { + return pAppend; + } + + for (i = 0; i < pAppend->nExpr; ++i) { + pList = sqlite3ExprListAppend(pParse, pList, pAppend->a[i].pExpr); + if (pList) { + pAppend->a[i].pExpr = NULL; + } + else { + goto no_mem; + } + } + sqlite3ExprListDelete(db, pAppend); + return pList; + +no_mem: + sqlite3ExprListDelete(db, pList); + sqlite3ExprListDelete(db, pAppend); + return 0; +} + +#endif /* ** Set the sort order for the last element on the given ExprList. */ diff --git a/query_classifier/qc_sqlite/sqlite-src-3110100/src/fkey.c b/query_classifier/qc_sqlite/sqlite-src-3110100/src/fkey.c index 38fd4f756..03e907bd5 100644 --- a/query_classifier/qc_sqlite/sqlite-src-3110100/src/fkey.c +++ b/query_classifier/qc_sqlite/sqlite-src-3110100/src/fkey.c @@ -1268,6 +1268,9 @@ static Trigger *fkActionTrigger( sqlite3SrcListAppend(db, 0, &tFrom, 0), pWhere, 0, 0, 0, 0, 0, 0 +#ifdef MAXSCALE + , 0 +#endif ); pWhere = 0; } diff --git a/query_classifier/qc_sqlite/sqlite-src-3110100/src/parse.y b/query_classifier/qc_sqlite/sqlite-src-3110100/src/parse.y index 0bfe4e473..755ee9d5f 100644 --- a/query_classifier/qc_sqlite/sqlite-src-3110100/src/parse.y +++ b/query_classifier/qc_sqlite/sqlite-src-3110100/src/parse.y @@ -43,12 +43,188 @@ // 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 maxscaleExplainTable(Parse*, SrcList* pList); +extern void maxscaleExplain(Parse*); +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); +extern void maxscale_set_type_mask(unsigned int type_mask); + +static Expr* maxscale_create_pseudo_limit(Parse* pParse, Token* pToken, ExprSpan* pLimit); + +// 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. @@ -122,17 +298,41 @@ input ::= cmdlist. cmdlist ::= cmdlist ecmd. cmdlist ::= ecmd. ecmd ::= SEMI. -ecmd ::= explain cmdx SEMI. -explain ::= . +ecmd ::= explain SEMI. +ecmd ::= cmdx SEMI. +ecmd ::= oracle_assignment SEMI. +%ifdef MAXSCALE +explain_kw ::= EXPLAIN. // Also covers DESCRIBE +explain_kw ::= DESC. + +explain ::= explain_kw tbl_name(A). { pParse->explain = 1; maxscaleExplainTable(pParse, A); } +explain_type ::= . +explain_type ::= EXTENDED. +explain_type ::= PARTITIONS. +// deferred_id is defined later, after the id token_class has been defined. +explain_type ::= FORMAT TK_EQ deferred_id. // FORMAT = {TRADITIONAL|JSON} + +explain ::= explain_kw explain_type FOR CONNECTION INTEGER. { // FOR CONNECTION connection_id + pParse->explain = 1; + maxscaleExplain(pParse); +} +%endif %ifndef SQLITE_OMIT_EXPLAIN -explain ::= EXPLAIN. { pParse->explain = 1; } +%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. @@ -142,10 +342,32 @@ 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). { @@ -157,17 +379,33 @@ cmd ::= RELEASE savepoint_opt nm(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;} @@ -177,14 +415,59 @@ 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; @@ -193,6 +476,7 @@ table_options(A) ::= WITHOUT nm(X). { sqlite3ErrorMsg(pParse, "unknown table option: %.*s", X.n, X.z); } } +%endif columnlist ::= columnlist COMMA column. columnlist ::= column. @@ -201,16 +485,113 @@ columnlist ::= column. // 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. @@ -222,6 +603,7 @@ columnid(A) ::= nm(X). { // 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 @@ -231,6 +613,40 @@ columnid(A) ::= nm(X). { 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*/ CONNECTION + DATA DATABASE DEALLOCATE DEFERRED /*DESC*/ /*DETACH*/ DUMPFILE + /*EACH*/ END ENGINE ENUM EXCLUSIVE /*EXPLAIN*/ EXTENDED + FIELDS 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 + PARTITIONS PASSWORD 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 + XA +%endif . %wildcard ANY. @@ -258,6 +674,14 @@ columnid(A) ::= nm(X). { %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. @@ -268,6 +692,10 @@ columnid(A) ::= nm(X). { 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. @@ -276,6 +704,13 @@ nm(A) ::= JOIN_KW(X). {A = X;} %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; @@ -294,9 +729,34 @@ 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);} @@ -312,25 +772,63 @@ ccons ::= DEFAULT id(X). { 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 @@ -366,6 +864,7 @@ 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). @@ -377,6 +876,7 @@ tcons ::= FOREIGN KEY LP eidlist(FA) RP 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;} @@ -386,6 +886,11 @@ defer_subclause_opt(A) ::= defer_subclause(X). {A = X;} // %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;} @@ -394,12 +899,23 @@ 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;} @@ -407,20 +923,61 @@ 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 ///////////////////////////////// // +%ifdef MAXSCALE +%type pselect {Select*} +%destructor pselect {sqlite3SelectDelete(pParse->db, $$);} + +pselect(A) ::= LP pselect(X) RP. { A = X; } +pselect(A) ::= select(X). { A = X; } + +cmd ::= pselect(X). { +%endif +%ifndef MAXSCALE cmd ::= select(X). { +%endif 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); } @@ -428,6 +985,10 @@ cmd ::= select(X). { %destructor select {sqlite3SelectDelete(pParse->db, $$);} %type selectnowith {Select*} %destructor selectnowith {sqlite3SelectDelete(pParse->db, $$);} +%ifdef MAXSCALE +%type selectnowithsuffix {Select*} +%destructor selectnowithsuffix {sqlite3SelectDelete(pParse->db, $$);} +%endif %type oneselect {Select*} %destructor oneselect {sqlite3SelectDelete(pParse->db, $$);} @@ -455,7 +1016,12 @@ cmd ::= select(X). { } } +%ifdef MAXSCALE +select(A) ::= with(W) selectnowithsuffix(X). { +%endif +%ifndef MAXSCALE select(A) ::= with(W) selectnowith(X). { +%endif Select *p = X; if( p ){ p->pWith = W; @@ -466,6 +1032,15 @@ select(A) ::= with(W) selectnowith(X). { A = p; } +%ifdef MAXSCALE +selectnowithsuffix(A) ::= selectnowith(X). {A = X;} + +selectnowithsuffix(A) ::= selectnowith(X) FOR UPDATE. { + A = X; + maxscale_set_type_mask(QUERY_TYPE_WRITE); +} +%endif + selectnowith(A) ::= oneselect(X). {A = X;} %ifndef SQLITE_OMIT_COMPOUND_SELECT selectnowith(A) ::= selectnowith(X) multiselect_op(Y) oneselect(Z). { @@ -477,7 +1052,11 @@ selectnowith(A) ::= selectnowith(X) multiselect_op(Y) oneselect(Z). { 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; @@ -495,6 +1074,42 @@ 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); @@ -523,16 +1138,31 @@ oneselect(A) ::= SELECT(S) distinct(D) selcollist(W) from(X) where_opt(Y) } #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; @@ -544,10 +1174,58 @@ values(A) ::= values(X) COMMA LP exprlist(Y) RP. { } } +%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;} +// In order to allow us to distinguish between "INTO @var" and +// "INTO OUTFILE" or "INTO DUMPFILE", we give the expression list +// a name that cannot be a variable and look for that in +// maxscaleCollectInfoFromSelect(). +select_into(A) ::= INTO DUMPFILE STRING. { + static Token dumpfile = { ":DUMPFILE:", 10 }; + A = sqlite3ExprListAppend(pParse, 0, 0); + sqlite3ExprListSetName(pParse, A, &dumpfile, 1); +} +select_into(A) ::= INTO OUTFILE STRING. { + static Token outfile = { ":OUTFILE:", 9 }; + A = sqlite3ExprListAppend(pParse, 0, 0); + sqlite3ExprListSetName(pParse, A, &outfile, 1); +} + +%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;} @@ -578,6 +1256,30 @@ selcollist(A) ::= sclp(P) nm(X) DOT STAR(Y). { 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 " phrase that can follow one of the expressions that // define the result set, or one of the tables in the FROM clause. @@ -597,11 +1299,14 @@ as(X) ::= . {X.n = 0;} // 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. @@ -616,6 +1321,14 @@ seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) indexed_opt(I) 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); @@ -645,7 +1358,11 @@ seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) LP exprlist(E) RP as(Z) }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); } } @@ -659,12 +1376,24 @@ dbnm(A) ::= DOT nm(X). {A = X;} %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, $$);} @@ -683,8 +1412,32 @@ on_opt(N) ::= . {N = 0;} // %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, $$);} @@ -722,7 +1475,15 @@ 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, $$);} @@ -752,12 +1513,35 @@ limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y). /////////////////////////// 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 + Token token; + ExprSpan limit; + if (O && !L.pLimit) { + L.pLimit = maxscale_create_pseudo_limit(pParse, &token, &limit); + sqlite3ExprDelete(pParse->db, L.pOffset); + L.pOffset = 0; + } + W = sqlite3LimitWhere(pParse, X, W, O, L.pLimit, L.pOffset, "DELETE"); + 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 @@ -774,16 +1558,155 @@ cmd ::= with(C) DELETE FROM fullname(X) indexed_opt(I) where_opt(W). { 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 + Token token; + ExprSpan limit; + if (O && !L.pLimit) { + L.pLimit = maxscale_create_pseudo_limit(pParse, &token, &limit); + sqlite3ExprDelete(pParse->db, L.pOffset); + L.pOffset = 0; + } + + W = sqlite3LimitWhere(pParse, X, W, O, L.pLimit, L.pOffset, "UPDATE"); + 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 @@ -812,20 +1735,104 @@ setlist(A) ::= nm(X) EQ expr(Y). { // 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 } -%type insert_cmd {int} -insert_cmd(A) ::= INSERT orconf(R). {A = R;} -insert_cmd(A) ::= REPLACE. {A = OE_Replace;} +%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, $$);} @@ -866,16 +1873,30 @@ idlist(A) ::= nm(Y). } expr(A) ::= term(X). {A = X;} +%ifndef MAXSCALE expr(A) ::= LP(B) expr(X) RP(E). {A.pExpr = X.pExpr; spanSet(&A,&B,&E);} +%endif +%ifdef MAXSCALE +%type exprs {ExprSpan} +exprs(A) ::= expr(X). { A = X; } +exprs(A) ::= exprs(X) COMMA(OP) expr(Y). {spanBinaryExpr(&A,pParse,@OP,&X,&Y);} +expr(A) ::= LP(B) exprs(X) RP(E). {A.pExpr = X.pExpr; spanSet(&A,&B,&E);} +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) ::= JOIN_KW(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); @@ -904,6 +1925,25 @@ expr(A) ::= VARIABLE(X). { } spanSet(&A, &X, &X); } +%ifdef MAXSCALE +expr(A) ::= id(X) INTEGER(Y). { + // The sole purpose of this is to interpret something like '_utf8mb4 0xD091D092D093' + // as a string. It does not matter that any identifier followed by an integer will + // be interpreted as a string, as invalid usage will be caught by the server. + A.pExpr = sqlite3PExpr(pParse, TK_STRING, 0, 0, &Y); + spanSet(&A, &X, &Y); +} +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; @@ -915,7 +1955,126 @@ expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). { 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); } @@ -925,7 +2084,37 @@ expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP(E). { A.pExpr->flags |= EP_Distinct; } } -expr(A) ::= id(X) LP STAR RP(E). { +%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); } @@ -967,6 +2156,13 @@ 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 expr(X) id. { + // Here we could check that id is one of MICROSECOND, SECOND, MINUTE + // HOUR, DAY, WEEK, etc. + A=X; // We simply ignore 'INTERVAL' +} +%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);} @@ -1168,7 +2364,11 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] { 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{ @@ -1235,15 +2435,26 @@ 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} @@ -1312,7 +2523,43 @@ 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 ///////////////////////////// // @@ -1352,13 +2599,21 @@ 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); } @@ -1454,6 +2709,7 @@ expr(A) ::= RAISE(X) LP IGNORE RP(Y). { 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 ) { @@ -1462,12 +2718,15 @@ expr(A) ::= RAISE(X) LP raisetype(T) COMMA nm(Z) RP(Y). { 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 ////////////////////////////// @@ -1503,21 +2762,61 @@ cmd ::= REINDEX nm(X) dbnm(Y). {sqlite3Reindex(pParse, &X, &Y);} /////////////////////////////////// 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. @@ -1562,3 +2861,697 @@ 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. + +////////////////////////// DROP DATABASE statement ///////////////////////////////////// +// +cmd ::= DROP DATABASE ifexists id(X). { + maxscaleDrop(pParse, MXS_DROP_DATABASE, &X, NULL); +} + +//////////////////////// 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} + +columns_or_fields ::= COLUMNS. +columns_or_fields ::= FIELDS. + +show(A) ::= SHOW full_opt(X) columns_or_fields 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 + +%include { + +static Expr* maxscale_create_pseudo_limit(Parse* pParse, Token* pToken, ExprSpan* pLimit) +{ + // sqlite3 does not accept a ORDER BY without LIMIT, but MariaDB + // does. Thus, to make sqlite3LimitWhere return non-NULL we need + // to inject a LIMIT if there is none. We use a value of -1 to + // tell update_field_infos_from_select() that this LIMIT should + // not be counted as a limiting clause. + static char one[] = "-1"; + pToken->z = one; + pToken->n = 1; + spanExpr(pLimit, pParse, TK_INTEGER, pToken); + return pLimit->pExpr; +} + +} diff --git a/query_classifier/qc_sqlite/sqlite-src-3110100/src/select.c b/query_classifier/qc_sqlite/sqlite-src-3110100/src/select.c index c3132c232..cf0fafd66 100644 --- a/query_classifier/qc_sqlite/sqlite-src-3110100/src/select.c +++ b/query_classifier/qc_sqlite/sqlite-src-3110100/src/select.c @@ -75,6 +75,9 @@ static void clearSelect(sqlite3 *db, Select *p, int bFree){ sqlite3ExprDelete(db, p->pLimit); sqlite3ExprDelete(db, p->pOffset); sqlite3WithDelete(db, p->pWith); +#ifdef MAXSCALE + sqlite3ExprListDelete(db, p->pInto); +#endif if( bFree ) sqlite3DbFree(db, p); p = pPrior; bFree = 1; @@ -108,6 +111,10 @@ Select *sqlite3SelectNew( u16 selFlags, /* Flag parameters, such as SF_Distinct */ Expr *pLimit, /* LIMIT value. NULL means not used */ Expr *pOffset /* OFFSET value. NULL means no offset */ +#ifdef MAXSCALE + , + ExprList *pInto /* the INTO clause */ +#endif ){ Select *pNew; Select standin; @@ -118,7 +125,9 @@ Select *sqlite3SelectNew( pNew = &standin; } if( pEList==0 ){ +#ifndef MAXSCALE pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ASTERISK,0)); +#endif } pNew->pEList = pEList; pNew->op = TK_SELECT; @@ -142,6 +151,9 @@ Select *sqlite3SelectNew( pNew->pLimit = pLimit; pNew->pOffset = pOffset; pNew->pWith = 0; +#ifdef MAXSCALE + pNew->pInto = pInto; +#endif assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 ); if( db->mallocFailed ) { clearSelect(db, pNew, pNew!=&standin); @@ -247,8 +259,10 @@ int sqlite3JoinType(Parse *pParse, Token *pA, Token *pB, Token *pC){ jointype = JT_INNER; }else if( (jointype & JT_OUTER)!=0 && (jointype & (JT_LEFT|JT_RIGHT))!=JT_LEFT ){ +#ifndef MAXSCALE sqlite3ErrorMsg(pParse, "RIGHT and FULL OUTER JOINs are not currently supported"); +#endif jointype = JT_INNER; } return jointype; diff --git a/query_classifier/qc_sqlite/sqlite-src-3110100/src/sqliteInt.h b/query_classifier/qc_sqlite/sqlite-src-3110100/src/sqliteInt.h index f04aebe79..fdc3217a6 100644 --- a/query_classifier/qc_sqlite/sqlite-src-3110100/src/sqliteInt.h +++ b/query_classifier/qc_sqlite/sqlite-src-3110100/src/sqliteInt.h @@ -2517,6 +2517,9 @@ struct Select { Expr *pLimit; /* LIMIT expression. NULL means not used. */ Expr *pOffset; /* OFFSET expression. NULL means not used. */ With *pWith; /* WITH clause attached to this select. Or NULL. */ +#ifdef MAXSCALE + ExprList* pInto; /* The INTO clause */ +#endif }; /* @@ -3358,6 +3361,9 @@ Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*); void sqlite3ExprAssignVarNumber(Parse*, Expr*); void sqlite3ExprDelete(sqlite3*, Expr*); ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); +#ifdef MAXSCALE +ExprList *sqlite3ExprListAppendList(Parse*,ExprList*,ExprList*); +#endif void sqlite3ExprListSetSortOrder(ExprList*,int); void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int); void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*); @@ -3445,6 +3451,9 @@ IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*); int sqlite3IdListIndex(IdList*,const char*); SrcList *sqlite3SrcListEnlarge(sqlite3*, SrcList*, int, int); SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*); +#ifdef MAXSCALE +SrcList* sqlite3SrcListCat(sqlite3*, SrcList*, SrcList*); +#endif SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, Token*, Select*, Expr*, IdList*); void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *); @@ -3459,8 +3468,13 @@ Index *sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, Expr*, int, int); void sqlite3DropIndex(Parse*, SrcList*, int); int sqlite3Select(Parse*, Select*, SelectDest*); +#ifdef MAXSCALE +Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, + Expr*,ExprList*,u16,Expr*,Expr*,ExprList*); +#else Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*, Expr*,ExprList*,u16,Expr*,Expr*); +#endif void sqlite3SelectDelete(sqlite3*, Select*); Table *sqlite3SrcListLookup(Parse*, SrcList*); int sqlite3IsReadOnly(Parse*, Table*, int); @@ -3746,7 +3760,11 @@ void sqlite3RootPageMoved(sqlite3*, int, int, int); void sqlite3Reindex(Parse*, Token*, Token*); void sqlite3AlterFunctions(void); void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); +#ifdef MAXSCALE +int sqlite3GetToken(Parse*, const unsigned char *, int *); +#else int sqlite3GetToken(const unsigned char *, int *); +#endif void sqlite3NestedParse(Parse*, const char*, ...); void sqlite3ExpirePreparedStatements(sqlite3*); int sqlite3CodeSubselect(Parse *, Expr *, int, int); @@ -4072,4 +4090,78 @@ int sqlite3ThreadJoin(SQLiteThread*, void**); int sqlite3DbstatRegister(sqlite3*); #endif +#ifdef MAXSCALE + +typedef enum mxs_drop +{ + MXS_DROP_DATABASE, + MXS_DROP_FUNCTION, + MXS_DROP_SEQUENCE, +} mxs_drop_t; + +typedef enum mxs_set +{ + MXS_SET_VARIABLES, + MXS_SET_TRANSACTION +} mxs_set_t; + +typedef enum mxs_show +{ + MXS_SHOW_COLUMNS, + MXS_SHOW_CREATE_SEQUENCE, + MXS_SHOW_CREATE_TABLE, + MXS_SHOW_CREATE_VIEW, + MXS_SHOW_DATABASES, + MXS_SHOW_INDEX, + MXS_SHOW_INDEXES, + MXS_SHOW_KEYS, + MXS_SHOW_STATUS, + MXS_SHOW_TABLE_STATUS, + MXS_SHOW_TABLES, + MXS_SHOW_VARIABLES, + MXS_SHOW_WARNINGS, +} mxs_show_t; + +enum mxs_show_data +{ + MXS_SHOW_COLUMNS_FULL = 1, + + // NOTE: The following are used both in MXS_SHOW_VARIABLES and MXS_SHOW_STATUS + MXS_SHOW_VARIABLES_GLOBAL, + MXS_SHOW_VARIABLES_SESSION, + MXS_SHOW_VARIABLES_UNSPECIFIED, + MXS_SHOW_STATUS_MASTER, + MXS_SHOW_STATUS_SLAVE, + MXS_SHOW_STATUS_ALL_SLAVES, +}; + +typedef struct MxsShow +{ + mxs_show_t what; + u32 data; + Token* pName; + Token* pDatabase; +} MxsShow; + +typedef enum mxs_alter +{ + MXS_ALTER_DISABLE_KEYS, + MXS_ALTER_ENABLE_KEYS, + MXS_ALTER_RENAME, +} mxs_alter_t; + +typedef enum mxs_lock +{ + MXS_LOCK_LOCK, + MXS_LOCK_UNLOCK, +} mxs_lock_t; + +typedef enum mxs_handler +{ + MXS_HANDLER_OPEN, + MXS_HANDLER_CLOSE +} mxs_handler_t; + +#endif /* MAXSCALE */ + #endif /* _SQLITEINT_H_ */ diff --git a/query_classifier/qc_sqlite/sqlite-src-3110100/src/tokenize.c b/query_classifier/qc_sqlite/sqlite-src-3110100/src/tokenize.c index 9b3444ac8..a698d29ba 100644 --- a/query_classifier/qc_sqlite/sqlite-src-3110100/src/tokenize.c +++ b/query_classifier/qc_sqlite/sqlite-src-3110100/src/tokenize.c @@ -60,7 +60,11 @@ static const unsigned char aiClass[] = { /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xa xb xc xd xe xf */ /* 0x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 7, 7, 27, 7, 7, 27, 27, /* 1x */ 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +#ifdef MAXSCALE +/* 2x */ 7, 15, 8, 5, 2, 22, 24, 8, 17, 18, 21, 20, 23, 11, 26, 16, +#else /* 2x */ 7, 15, 8, 5, 4, 22, 24, 8, 17, 18, 21, 20, 23, 11, 26, 16, +#endif /* 3x */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 19, 12, 14, 13, 6, /* 4x */ 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 5x */ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 9, 27, 27, 27, 1, @@ -193,7 +197,12 @@ int sqlite3IsIdChar(u8 c){ return IdChar(c); } ** Return the length (in bytes) of the token that begins at z[0]. ** Store the token type in *tokenType before returning. */ +#ifdef MAXSCALE +extern int maxscaleComment(); +int sqlite3GetToken(Parse* pParse, const unsigned char *z, int *tokenType){ +#else int sqlite3GetToken(const unsigned char *z, int *tokenType){ +#endif int i, c; switch( aiClass[*z] ){ /* Switch on the character-class of the first byte ** of the token. See the comment on the CC_ defines @@ -210,6 +219,9 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){ } case CC_MINUS: { if( z[1]=='-' ){ +#ifdef MAXSCALE + maxscaleComment(); +#endif for(i=2; (c=z[i])!=0 && c!='\n'; i++){} *tokenType = TK_SPACE; /* IMP: R-22934-25134 */ return i; @@ -242,8 +254,39 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){ *tokenType = TK_SLASH; return 1; } +#ifdef MAXSCALE + if ( z[2]=='!' || (z[2]=='M' && z[3]=='!')){ + int j = (z[2]=='M' ? 4 : 3); + // MySQL-specific code + for (i=j, c=z[j-1]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){} + if (c=='*' && z[i]=='/'){ + if (sqlite3Isdigit(z[j])) { + // A version specific executable comment, + // e.g. "/*!99999 ..." or "/*M!99999 ..." => never parsed. + extern void maxscaleSetStatusCap(int); + maxscaleSetStatusCap(2); // QC_QUERY_PARTIALLY_PARSED, see query_classifier.h:qc_parse_result + ++i; // Next after the trailing '/' + } + else { + // A non-version specific executable comment, + // e.g."/*! select 1 */ or "/*M! select 1 */ => always parsed. + char* znc = (char*) z; + znc[0]=znc[1]=znc[2]=znc[i-1]=znc[i]=' '; // Remove comment chars, i.e. "/*!" and "*/". + if (j==4){ + znc[3]=0; // It wasn't "/*!" but "/*M!". + } + for (i=j; sqlite3Isspace(z[i]); ++i){} // Jump over any space. + } + } + } else { + for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){} + + if( c ) i++; + } +#else for(i=3, c=z[2]; (c!='*' || z[i]!='/') && (c=z[i])!=0; i++){} if( c ) i++; +#endif *tokenType = TK_SPACE; /* IMP: R-22934-25134 */ return i; } @@ -257,6 +300,13 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){ } case CC_LT: { if( (c=z[1])=='=' ){ +#ifdef MAXSCALE + if ( z[2]=='>' ){ + // "<=>" + *tokenType = TK_EQ; + return 3; + } +#endif *tokenType = TK_LE; return 2; }else if( c=='>' ){ @@ -324,9 +374,19 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){ }else{ break; } +#ifdef MAXSCALE + }else if (c == '\\' ){ + if ( z[i+1] ){ + i++; + } +#endif } } +#ifdef MAXSCALE + if( c=='\'' || c=='"' ){ +#else if( c=='\'' ){ +#endif *tokenType = TK_STRING; return i+1; }else if( c!=0 ){ @@ -345,6 +405,23 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){ *tokenType = TK_DOT; return 1; } +#ifdef MAXSCALE + /* Next char is a digit, we need to sniff further to find out whether it + ** is an identifer that starts with a digit. + */ + int j=1; + int nondigitChars=0; + while ( IdChar(z[j]) ){ + if ( !sqlite3Isdigit(z[j++]) ){ + ++nondigitChars; + } + } + if ( nondigitChars ){ + // At least one char that is not a digit => an id (and not a float) coming. + *tokenType = TK_DOT; + return 1; + } +#endif /* If the next character is a digit, this is a floating point ** number that begins with ".". Fall thru into the next case */ } @@ -378,7 +455,11 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){ } #endif while( IdChar(z[i]) ){ +#ifdef MAXSCALE + *tokenType = TK_ID; +#else *tokenType = TK_ILLEGAL; +#endif i++; } return i; @@ -398,9 +479,30 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){ int n = 0; testcase( z[0]=='$' ); testcase( z[0]=='@' ); testcase( z[0]==':' ); testcase( z[0]=='#' ); +#ifdef MAXSCALE + if (z[0]=='#') { + if (maxscaleComment()) { + for(i=1; (c=z[i])!=0 && c!='\n'; i++){} + *tokenType = TK_SPACE; + return i; + } + } + if (z[0]==':' && z[1]=='=') { + *tokenType = TK_EQ; + return 2; + } +#endif *tokenType = TK_VARIABLE; for(i=1; (c=z[i])!=0; i++){ +#ifdef MAXSCALE + if ( (i == 1) && (z[0] == '@') && (c == '@') ) { + // If the first char is '@' then if the second char is a '@' + // it is a system variable (@@xyz). + continue; + }else if( IdChar(c) ){ +#else if( IdChar(c) ){ +#endif n++; #ifndef SQLITE_OMIT_TCL_VARIABLE }else if( c=='(' && n>0 ){ @@ -415,6 +517,20 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){ break; }else if( c==':' && z[i+1]==':' ){ i++; +#endif +#ifdef MAXSCALE + }else if ( c=='\'' || c=='"' || c=='`' ){ + int q=c; + ++i; + while ( IdChar(z[i]) ) { + ++i; + ++n; + } + if ( z[i]==q ) + { + ++i; + break; + } #endif }else{ break; @@ -424,6 +540,23 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){ return i; } case CC_KYWD: { +#ifdef MAXSCALE + // This is for bit fields, e.g. b'10110111'. + if ( z[0]=='b' || z[0]=='B' ) { + if ( z[1]=='\'' ){ + // We return it as an integer. We are not interested in the value + *tokenType = TK_INTEGER; + for(i=2; (z[i]=='0'||z[i]=='1'); i++){} + if ( z[i]!='\'' ){ + *tokenType = TK_ILLEGAL; + while ( z[i] && z[i]!='\'' ){ i++; } + } + if ( z[i] ) i++; + return i; + } + } + /* Not a bit field. It may be a keyword so we flow through */ +#endif for(i=1; aiClass[z[i]]<=CC_KYWD; i++){} if( IdChar(z[i]) ){ /* This token started out using characters that can appear in keywords, @@ -433,7 +566,49 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){ break; } *tokenType = TK_ID; +#ifdef MAXSCALE + i = keywordCode((char*)z, i, tokenType); + if (*tokenType != TK_ID) + { + if (pParse) { + if (z != (const unsigned char *)pParse->zTail) { + const char *p = (const char*)z - 1; + while ((p != pParse->zTail) && sqlite3Isspace(*p)) { + --p; + } + + if (*p == '.') { + /* If the last character before the keyword is '.' then + ** we assume this token is the second part of a qualified + ** name, e.g. "tbl1.index" in which case we return the + ** keyword as an id. + */ + *tokenType = TK_ID; + } + } + } + + if (*tokenType != TK_ID) { + extern int maxscaleKeyword(int); + extern int maxscaleTranslateKeyword(int); + + *tokenType = maxscaleTranslateKeyword(*tokenType); + + if (*tokenType != TK_ID) { + if (maxscaleKeyword(*tokenType) != 0) + { + /* Consume the entire string. */ + while ( z[i] ) { + ++i; + } + } + } + } + } + return i; +#else return keywordCode((char*)z, i, tokenType); +#endif } #ifndef SQLITE_OMIT_BLOB_LITERAL case CC_X: { @@ -451,6 +626,22 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){ /* If it is not a BLOB literal, then it must be an ID, since no ** SQL keywords start with the letter 'x'. Fall through */ } +#endif +#ifdef MAXSCALE + // It may be the "XA" keyword. + // If the next character is 'a' or 'A', followed by whitespace or a + // comment, then we are indeed dealing with the "XA" keyword. + if (( z[1]=='a' || z[1]=='A' ) && + (sqlite3Isspace(z[2]) || // Whitespace + (z[2]=='/' && z[3]=='*') || // Beginning of /* comment + (z[2]=='#') || // # eol comment + (z[2]=='-' && z[3]=='-' && sqlite3Isspace(z[4])))) { // -- eol comment + extern int maxscaleKeyword(int); + + *tokenType = TK_XA; + maxscaleKeyword(*tokenType); + return 2; + } #endif case CC_ID: { i = 1; @@ -505,7 +696,11 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ while( zSql[i]!=0 ){ assert( i>=0 ); pParse->sLastToken.z = &zSql[i]; +#ifdef MAXSCALE + pParse->sLastToken.n = sqlite3GetToken(pParse,(unsigned char*)&zSql[i],&tokenType); +#else pParse->sLastToken.n = sqlite3GetToken((unsigned char*)&zSql[i],&tokenType); +#endif i += pParse->sLastToken.n; if( i>mxSqlLen ){ pParse->rc = SQLITE_TOOBIG; diff --git a/query_classifier/qc_sqlite/sqlite-src-3110100/src/util.c b/query_classifier/qc_sqlite/sqlite-src-3110100/src/util.c index 37b585b2e..c9ce17de8 100644 --- a/query_classifier/qc_sqlite/sqlite-src-3110100/src/util.c +++ b/query_classifier/qc_sqlite/sqlite-src-3110100/src/util.c @@ -219,6 +219,23 @@ int sqlite3Dequote(char *z){ } for(i=1, j=0;; i++){ assert( z[i] ); +#ifdef MAXSCALE + if ( z[i]==0 ){ + // TODO: This is needed only because exposed_sqlite3Dequote() is called + // TODO: in qc_sqlite.c:update_names(). That call probably is not needed + // TODO: and should be removed, in which case this check could also be + // TODO: removed. + break; + }else if ( z[i]=='\\' ){ + // If we want to dequote properly, a few more characters would have to be + // handled explicitly. That would not affect the classification, however, + // so we won't do that. + if ( z[i+1]==quote || z[i+1]=='\\' ){ + z[j++] = z[i+1]; + i++; + } + } else +#endif if( z[i]==quote ){ if( z[i+1]==quote ){ z[j++] = quote; diff --git a/query_classifier/qc_sqlite/sqlite-src-3110100/src/vdbetrace.c b/query_classifier/qc_sqlite/sqlite-src-3110100/src/vdbetrace.c index 07235c931..4146d3d23 100644 --- a/query_classifier/qc_sqlite/sqlite-src-3110100/src/vdbetrace.c +++ b/query_classifier/qc_sqlite/sqlite-src-3110100/src/vdbetrace.c @@ -33,7 +33,11 @@ static int findNextHostParameter(const char *zSql, int *pnToken){ *pnToken = 0; while( zSql[0] ){ +#ifdef MAXSCALE + n = sqlite3GetToken(0, (u8*)zSql, &tokenType); +#else n = sqlite3GetToken((u8*)zSql, &tokenType); +#endif assert( n>0 && tokenType!=TK_ILLEGAL ); if( tokenType==TK_VARIABLE ){ *pnToken = n; diff --git a/query_classifier/qc_sqlite/sqlite-src-3110100/tool/mkkeywordhash.c b/query_classifier/qc_sqlite/sqlite-src-3110100/tool/mkkeywordhash.c index 7e5287ea5..fb224da7a 100644 --- a/query_classifier/qc_sqlite/sqlite-src-3110100/tool/mkkeywordhash.c +++ b/query_classifier/qc_sqlite/sqlite-src-3110100/tool/mkkeywordhash.c @@ -148,97 +148,265 @@ struct Keyword { ** These are the keywords */ static Keyword aKeywordTable[] = { +#ifndef MAXSCALE { "ABORT", "TK_ABORT", CONFLICT|TRIGGER }, +#endif { "ACTION", "TK_ACTION", FKEY }, { "ADD", "TK_ADD", ALTER }, { "AFTER", "TK_AFTER", TRIGGER }, +#ifdef MAXSCALE + { "AGAINST", "TK_AGAINST", ALWAYS }, +#endif { "ALL", "TK_ALL", ALWAYS }, { "ALTER", "TK_ALTER", ALTER }, +#ifdef MAXSCALE + { "ALGORITHM", "TK_ALGORITHM", ANALYZE }, +#endif { "ANALYZE", "TK_ANALYZE", ANALYZE }, { "AND", "TK_AND", ALWAYS }, { "AS", "TK_AS", ALWAYS }, { "ASC", "TK_ASC", ALWAYS }, { "ATTACH", "TK_ATTACH", ATTACH }, { "AUTOINCREMENT", "TK_AUTOINCR", AUTOINCR }, +#ifdef MAXSCALE + { "AUTO_INCREMENT", "TK_AUTOINCR", AUTOINCR }, +#endif { "BEFORE", "TK_BEFORE", TRIGGER }, { "BEGIN", "TK_BEGIN", ALWAYS }, { "BETWEEN", "TK_BETWEEN", ALWAYS }, +#ifdef MAXSCALE + { "BINARY", "TK_BINARY", ALWAYS }, +#endif { "BY", "TK_BY", ALWAYS }, +#ifdef MAXSCALE + { "CALL", "TK_CALL", ALWAYS }, +#endif { "CASCADE", "TK_CASCADE", FKEY }, { "CASE", "TK_CASE", ALWAYS }, { "CAST", "TK_CAST", CAST }, +#ifdef MAXSCALE + { "CHARACTER", "TK_CHARACTER", ALWAYS }, + { "CHARSET", "TK_CHARSET", ALWAYS }, +#endif { "CHECK", "TK_CHECK", ALWAYS }, +#ifdef MAXSCALE + { "CLOSE", "TK_CLOSE", ALWAYS }, +#endif { "COLLATE", "TK_COLLATE", ALWAYS }, { "COLUMN", "TK_COLUMNKW", ALTER }, +#ifdef MAXSCALE + { "COLUMNS", "TK_COLUMNS", ALWAYS }, + { "COMMENT", "TK_COMMENT", ALWAYS }, +#endif { "COMMIT", "TK_COMMIT", ALWAYS }, +#ifndef MAXSCALE { "CONFLICT", "TK_CONFLICT", CONFLICT }, +#endif +#ifdef MAXSCALE + { "CONNECTION", "TK_CONNECTION", ALWAYS }, + { "CONCURRENT", "TK_CONCURRENT", ALWAYS }, +#endif { "CONSTRAINT", "TK_CONSTRAINT", ALWAYS }, { "CREATE", "TK_CREATE", ALWAYS }, { "CROSS", "TK_JOIN_KW", ALWAYS }, +#ifdef MAXSCALE + { "CURRENT", "TK_CURRENT", ALWAYS }, +#endif { "CURRENT_DATE", "TK_CTIME_KW", ALWAYS }, { "CURRENT_TIME", "TK_CTIME_KW", ALWAYS }, { "CURRENT_TIMESTAMP","TK_CTIME_KW", ALWAYS }, +#ifdef MAXSCALE + { "DATA", "TK_DATA", ALWAYS }, + { "DATABASE", "TK_DATABASE", ALWAYS }, +#else { "DATABASE", "TK_DATABASE", ATTACH }, +#endif +#ifdef MAXSCALE + { "DATABASES", "TK_DATABASES_KW", ALWAYS }, + { "DEALLOCATE", "TK_DEALLOCATE", ALWAYS }, + { "DECLARE", "TK_DECLARE", ALWAYS }, +#endif { "DEFAULT", "TK_DEFAULT", ALWAYS }, { "DEFERRED", "TK_DEFERRED", ALWAYS }, { "DEFERRABLE", "TK_DEFERRABLE", FKEY }, +#ifdef MAXSCALE + { "DELAYED", "TK_DELAYED", ALWAYS }, +#endif { "DELETE", "TK_DELETE", ALWAYS }, { "DESC", "TK_DESC", ALWAYS }, +#ifdef MAXSCALE + { "DESCRIBE", "TK_EXPLAIN" , ALWAYS }, +#endif { "DETACH", "TK_DETACH", ATTACH }, { "DISTINCT", "TK_DISTINCT", ALWAYS }, +#ifdef MAXSCALE + { "DISTINCTROW", "TK_DISTINCT", ALWAYS }, + { "DO", "TK_DO", ALWAYS }, +#endif { "DROP", "TK_DROP", ALWAYS }, +#ifdef MAXSCALE + { "DUMPFILE", "TK_DUMPFILE", ALWAYS }, +#endif { "END", "TK_END", ALWAYS }, { "EACH", "TK_EACH", TRIGGER }, +#ifdef MAXSCALE + { "ENABLE", "TK_ENABLE", ALWAYS }, + { "ENGINE", "TK_ENGINE", ALWAYS }, + { "ENUM", "TK_ENUM", ALWAYS }, +#endif { "ELSE", "TK_ELSE", ALWAYS }, { "ESCAPE", "TK_ESCAPE", ALWAYS }, { "EXCEPT", "TK_EXCEPT", COMPOUND }, { "EXCLUSIVE", "TK_EXCLUSIVE", ALWAYS }, +#ifdef MAXSCALE + { "EXECUTE", "TK_EXECUTE", ALWAYS }, + { "EXCLUDE", "TK_EXCLUDE", ALWAYS }, + { "EXTENDED", "TK_EXTENDED", ALWAYS }, +#endif { "EXISTS", "TK_EXISTS", ALWAYS }, { "EXPLAIN", "TK_EXPLAIN", EXPLAIN }, +#ifndef MAXSCALE { "FAIL", "TK_FAIL", CONFLICT|TRIGGER }, +#endif +#ifdef MAXSCALE + { "FIELDS", "TK_FIELDS", ALWAYS }, + { "FIRST", "TK_FIRST", ALWAYS }, + { "FLUSH", "TK_FLUSH", ALWAYS }, + { "FOLLOWING", "TK_FOLLOWING", ALWAYS }, +#endif +#ifdef MAXSCALE + { "FOR", "TK_FOR", ALWAYS }, +#else { "FOR", "TK_FOR", TRIGGER }, +#endif +#ifdef MAXSCALE + { "FORCE", "TK_FORCE", ALWAYS }, +#endif { "FOREIGN", "TK_FOREIGN", FKEY }, +#ifdef MAXSCALE + { "FORMAT", "TK_FORMAT", ALWAYS }, +#endif { "FROM", "TK_FROM", ALWAYS }, { "FULL", "TK_JOIN_KW", ALWAYS }, +#ifdef MAXSCALE + { "FULLTEXT", "TK_FULLTEXT", ALWAYS }, + { "FUNCTION", "TK_FUNCTION_KW", ALWAYS }, +#endif { "GLOB", "TK_LIKE_KW", ALWAYS }, +#ifdef MAXSCALE + { "GLOBAL", "TK_GLOBAL", ALWAYS }, + { "GRANT", "TK_GRANT", ALWAYS }, +#endif { "GROUP", "TK_GROUP", ALWAYS }, +#ifdef MAXSCALE + { "HANDLER", "TK_HANDLER", ALWAYS }, +#endif { "HAVING", "TK_HAVING", ALWAYS }, +#ifdef MAXSCALE + { "HIGH_PRIORITY", "TK_HIGH_PRIORITY",ALWAYS }, +#endif { "IF", "TK_IF", ALWAYS }, +#ifdef MAXSCALE + { "IGNORE", "TK_IGNORE", ALWAYS }, +#else { "IGNORE", "TK_IGNORE", CONFLICT|TRIGGER }, +#endif { "IMMEDIATE", "TK_IMMEDIATE", ALWAYS }, { "IN", "TK_IN", ALWAYS }, { "INDEX", "TK_INDEX", ALWAYS }, { "INDEXED", "TK_INDEXED", ALWAYS }, +#ifdef MAXSCALE + { "INDEXES", "TK_INDEXES", ALWAYS }, + { "INFILE", "TK_INFILE", ALWAYS }, +#endif { "INITIALLY", "TK_INITIALLY", FKEY }, { "INNER", "TK_JOIN_KW", ALWAYS }, { "INSERT", "TK_INSERT", ALWAYS }, { "INSTEAD", "TK_INSTEAD", TRIGGER }, { "INTERSECT", "TK_INTERSECT", COMPOUND }, +#ifdef MAXSCALE + { "INTERVAL", "TK_INTERVAL", ALWAYS }, +#endif { "INTO", "TK_INTO", ALWAYS }, { "IS", "TK_IS", ALWAYS }, { "ISNULL", "TK_ISNULL", ALWAYS }, { "JOIN", "TK_JOIN", ALWAYS }, { "KEY", "TK_KEY", ALWAYS }, +#ifdef MAXSCALE + { "KEYS", "TK_KEYS", ALWAYS }, +#endif { "LEFT", "TK_JOIN_KW", ALWAYS }, { "LIKE", "TK_LIKE_KW", ALWAYS }, { "LIMIT", "TK_LIMIT", ALWAYS }, +#ifdef MAXSCALE + { "LOAD", "TK_LOAD", ALWAYS }, + { "LOCAL", "TK_LOCAL", ALWAYS }, + { "LOCK", "TK_LOCK", ALWAYS }, + { "LOW_PRIORITY", "TK_LOW_PRIORITY", ALWAYS }, +#endif { "MATCH", "TK_MATCH", ALWAYS }, +#ifdef MAXSCALE + { "MASTER", "TK_MASTER", ALWAYS }, + { "MERGE", "TK_MERGE", ALWAYS }, + { "NAMES", "TK_NAMES", ALWAYS }, +#endif { "NATURAL", "TK_JOIN_KW", ALWAYS }, +#ifdef MAXSCALE + { "NEXT", "TK_NEXT", ALWAYS }, +#endif { "NO", "TK_NO", FKEY }, { "NOT", "TK_NOT", ALWAYS }, { "NOTNULL", "TK_NOTNULL", ALWAYS }, +#ifdef MAXSCALE + { "NO_WRITE_TO_BINLOG","TK_NO_WRITE_TO_BINLOG",ALWAYS }, +#endif { "NULL", "TK_NULL", ALWAYS }, { "OF", "TK_OF", ALWAYS }, { "OFFSET", "TK_OFFSET", ALWAYS }, { "ON", "TK_ON", ALWAYS }, +#ifdef MAXSCALE + { "OPEN", "TK_OPEN", ALWAYS }, +#endif { "OR", "TK_OR", ALWAYS }, { "ORDER", "TK_ORDER", ALWAYS }, +#ifdef MAXSCALE + { "OTHERS", "TK_OTHERS", ALWAYS }, +#endif { "OUTER", "TK_JOIN_KW", ALWAYS }, +#ifdef MAXSCALE + { "OUTFILE", "TK_OUTFILE", ALWAYS }, + { "OVER", "TK_OVER", ALWAYS }, +#endif +#ifdef MAXSCALE + { "PARTITION", "TK_PARTITION", ALWAYS }, + { "PARTITIONS", "TK_PARTITIONS", ALWAYS }, + { "PASSWORD", "TK_PASSWORD", ALWAYS }, + { "PERSISTENT", "TK_PERSISTENT", ALWAYS }, +#endif +#ifndef MAXSCALE { "PLAN", "TK_PLAN", EXPLAIN }, +#endif { "PRAGMA", "TK_PRAGMA", PRAGMA }, +#ifdef MAXSCALE + { "PRECEDING", "TK_PRECEDING", ALWAYS }, + { "PREPARE", "TK_PREPARE", ALWAYS }, + { "PREVIOUS", "TK_PREVIOUS", ALWAYS }, +#endif { "PRIMARY", "TK_PRIMARY", ALWAYS }, +#ifdef MAXSCALE + { "PROCEDURE", "TK_FUNCTION_KW", ALWAYS }, +#endif +#ifndef MAXSCALE { "QUERY", "TK_QUERY", EXPLAIN }, +#endif +#ifdef MAXSCALE + { "QUICK", "TK_QUICK", ALWAYS }, +#endif { "RAISE", "TK_RAISE", TRIGGER }, +#ifdef MAXSCALE + { "RANGE", "TK_RANGE", ALWAYS }, + { "READ", "TK_READ", ALWAYS }, +#endif { "RECURSIVE", "TK_RECURSIVE", CTE }, { "REFERENCES", "TK_REFERENCES", FKEY }, { "REGEXP", "TK_LIKE_KW", ALWAYS }, @@ -247,31 +415,99 @@ static Keyword aKeywordTable[] = { { "RENAME", "TK_RENAME", ALTER }, { "REPLACE", "TK_REPLACE", CONFLICT }, { "RESTRICT", "TK_RESTRICT", FKEY }, +#ifdef MAXSCALE + { "REVOKE", "TK_REVOKE", ALWAYS }, +#endif { "RIGHT", "TK_JOIN_KW", ALWAYS }, { "ROLLBACK", "TK_ROLLBACK", ALWAYS }, +#ifdef MAXSCALE + { "ROLLUP", "TK_ROLLUP", ALWAYS }, +#endif { "ROW", "TK_ROW", TRIGGER }, +#ifdef MAXSCALE + { "ROWS", "TK_ROWS", ALWAYS }, +#endif { "SAVEPOINT", "TK_SAVEPOINT", ALWAYS }, +#ifdef MAXSCALE + { "SCHEMAS", "TK_DATABASES_KW", ALWAYS }, + { "SEQUENCE", "TK_SEQUENCE", ALWAYS }, +#endif { "SELECT", "TK_SELECT", ALWAYS }, +#ifdef MAXSCALE + { "SESSION", "TK_SESSION", ALWAYS }, + { "SEPARATOR", "TK_SEPARATOR", ALWAYS }, + { "SHOW", "TK_SHOW", ALWAYS }, + { "SLAVE", "TK_SLAVE", ALWAYS }, + { "SPATIAL", "TK_SPATIAL", ALWAYS }, + { "SQL_BIG_RESULT", "TK_SELECT_OPTIONS_KW", ALWAYS }, + { "SQL_BUFFER_RESULT","TK_SELECT_OPTIONS_KW", ALWAYS }, + { "SQL_CACHE", "TK_SELECT_OPTIONS_KW", ALWAYS }, + { "SQL_CALC_FOUND_ROWS","TK_SELECT_OPTIONS_KW", ALWAYS }, + { "SQL_NO_CACHE", "TK_SELECT_OPTIONS_KW", ALWAYS }, + { "SQL_SMALL_RESULT", "TK_SELECT_OPTIONS_KW", ALWAYS }, +#endif { "SET", "TK_SET", ALWAYS }, +#ifdef MAXSCALE + { "START", "TK_START", ALWAYS }, + { "STATEMENT", "TK_STATEMENT", ALWAYS }, + { "STATUS", "TK_STATUS", ALWAYS }, + { "STRAIGHT_JOIN", "TK_STRAIGHT_JOIN",ALWAYS }, +#endif { "TABLE", "TK_TABLE", ALWAYS }, +#ifdef MAXSCALE + { "TABLES", "TK_TABLES", ALWAYS }, +#endif { "TEMP", "TK_TEMP", ALWAYS }, { "TEMPORARY", "TK_TEMP", ALWAYS }, +#ifdef MAXSCALE + { "TEMPTABLE", "TK_TEMPTABLE", ANALYZE }, +#endif { "THEN", "TK_THEN", ALWAYS }, +#ifdef MAXSCALE + { "TIES", "TK_TIES", ANALYZE }, +#endif { "TO", "TK_TO", ALWAYS }, { "TRANSACTION", "TK_TRANSACTION", ALWAYS }, { "TRIGGER", "TK_TRIGGER", TRIGGER }, +#ifdef MAXSCALE + { "TRUNCATE", "TK_TRUNCATE", ALWAYS }, + { "UNBOUNDED", "TK_UNBOUNDED", ALWAYS }, +#endif { "UNION", "TK_UNION", COMPOUND }, + { "UNSIGNED", "TK_UNSIGNED", ALWAYS }, { "UNIQUE", "TK_UNIQUE", ALWAYS }, +#ifdef MAXSCALE + { "UNLOCK", "TK_UNLOCK", ALWAYS }, +#endif { "UPDATE", "TK_UPDATE", ALWAYS }, + { "USE", "TK_USE", ALWAYS }, { "USING", "TK_USING", ALWAYS }, { "VACUUM", "TK_VACUUM", VACUUM }, +#ifdef MAXSCALE + { "VALUE", "TK_VALUE", ALWAYS }, +#endif { "VALUES", "TK_VALUES", ALWAYS }, +#ifdef MAXSCALE + { "VARIABLES", "TK_VARIABLES", ALWAYS }, +#endif { "VIEW", "TK_VIEW", VIEW }, { "VIRTUAL", "TK_VIRTUAL", VTAB }, +#ifdef MAXSCALE + { "WARNINGS", "TK_WARNINGS", ALWAYS }, + { "WINDOW", "TK_WINDOW", ALWAYS }, +#endif { "WITH", "TK_WITH", CTE }, +#ifndef MAXSCALE { "WITHOUT", "TK_WITHOUT", ALWAYS }, +#endif { "WHEN", "TK_WHEN", ALWAYS }, { "WHERE", "TK_WHERE", ALWAYS }, +#ifdef MAXSCALE + { "WORK", "TK_WORK", ALWAYS }, + { "WRITE", "TK_WRITE", ALWAYS }, + { "XA", "TK_XA", ALWAYS }, +#endif + { "ZEROFILL", "TK_ZEROFILL", ALWAYS }, }; /* Number of keywords */