From a514b8eb0cc9c6773171381a1dfe5b456d963a97 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 25 Aug 2015 00:27:06 +0000 Subject: [PATCH 01/25] Changes toward being abld to process indexes on expressions. Not there yet - this check-in is just movement in that direction. Some tests are failing. FossilOrigin-Name: 0ad0f8d77d8f95ca2ffb7745d18219f5e87dc89c --- manifest | 19 +++++++++-------- manifest.uuid | 2 +- src/build.c | 25 ++++++++--------------- src/resolve.c | 54 ++++++++++++++++++++++--------------------------- src/sqliteInt.h | 1 + 5 files changed, 45 insertions(+), 56 deletions(-) diff --git a/manifest b/manifest index 9efff535b2..34496b20c1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\ssome\sredundant\scode:\s\sCall\ssqlite3ResolveExprListNames()\srather\sthan\ncalling\ssqlite3ResolveExprNames()\sin\sa\sloop\s-\sin\stwo\splaces. -D 2015-08-24T20:54:06.120 +C Changes\stoward\sbeing\sabld\sto\sprocess\sindexes\son\sexpressions.\s\sNot\sthere\syet\s-\s\nthis\scheck-in\sis\sjust\smovement\sin\sthat\sdirection.\s\sSome\stests\sare\sfailing. +D 2015-08-25T00:27:06.624 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in e2218eb228374422969de7b1680eda6864affcef F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -282,7 +282,7 @@ F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79 F src/btree.c f48b3ef91676c06a90a8832987ecef6b94c931ee F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1 F src/btreeInt.h 8177c9ab90d772d6d2c6c517e05bed774b7c92c0 -F src/build.c 789e75f3478ac63c0f398a131c49a0802c356c2b +F src/build.c d9d53c7318117e04cfb79bc498b45f4982092f0c F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b @@ -335,14 +335,14 @@ F src/pragma.h 631a91c8b0e6ca8f051a1d8a4a0da4150e04620a F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1 F src/printf.c 2bc439ff20a4aad0e0ad50a37a67b5eae7d20edc F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 -F src/resolve.c 66b2740075fdb8baf90155180d33d9850cbcc976 +F src/resolve.c ad9404cfa6f698aa530cca1c86570fa92cb65a12 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c da6d1e7a4f1c8d713ed5415b5ed21d82ef465c0f F src/shell.c b1f91e60918df3a68efad1e3a11696b9a7e23d23 F src/sqlite.h.in 378bebc8fe6a88bade25e5f23b7e6123fdc64b00 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h f700e6a9dd1fdcccc9951ab022b366fb66b9e413 -F src/sqliteInt.h edbcd0c0787541a636a25ab1d1eaf847dbd043f1 +F src/sqliteInt.h 5e2ce12324eb03b75d5b8a37084550eb66dbef78 F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e @@ -1379,7 +1379,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P bed42116addabcf3dfdc2e2d51ae183965704988 -R 455d327d4502b1aadc3594ff31ef63f2 +P bdaf66465b6b1bdad10c08d9527b98e7000a41e4 +R 3888db9ab5ffaaee9ce833f48e49ed84 +T *branch * index-expr +T *sym-index-expr * +T -sym-trunk * U drh -Z 983b791d1ba8013f2148572b484fe05d +Z 80441a5a4abd6f0065befff78e2e1eff diff --git a/manifest.uuid b/manifest.uuid index 96012b923f..712ea9a3fd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -bdaf66465b6b1bdad10c08d9527b98e7000a41e4 \ No newline at end of file +0ad0f8d77d8f95ca2ffb7745d18219f5e87dc89c \ No newline at end of file diff --git a/src/build.c b/src/build.c index 8a7dda89c1..64bfe1b061 100644 --- a/src/build.c +++ b/src/build.c @@ -640,9 +640,7 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ sqlite3DbFree(db, pTable->zName); sqlite3DbFree(db, pTable->zColAff); sqlite3SelectDelete(db, pTable->pSelect); -#ifndef SQLITE_OMIT_CHECK sqlite3ExprListDelete(db, pTable->pCheck); -#endif #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3VtabClear(db, pTable); #endif @@ -2891,7 +2889,6 @@ Index *sqlite3CreateIndex( int iDb; /* Index of the database that is being written */ Token *pName = 0; /* Unqualified name of the index to create */ struct ExprList_item *pListItem; /* For looping over pList */ - const Column *pTabCol; /* A column in the table */ int nExtra = 0; /* Space allocated for zExtra[] */ int nExtraCol; /* Number of extra columns needed */ char *zExtra = 0; /* Extra space after the Index object */ @@ -3115,28 +3112,22 @@ Index *sqlite3CreateIndex( ** break backwards compatibility - it needs to be a warning. */ for(i=0, pListItem=pList->a; inExpr; i++, pListItem++){ - const char *zColName; Expr *pCExpr; int requestedSortOrder; char *zColl; /* Collation sequence name */ + sqlite3ResolveSelfReference(pParse, pTab, NC_IdxExpr, pListItem->pExpr, 0); + if( pParse->nErr ) goto exit_create_index; pCExpr = sqlite3ExprSkipCollate(pListItem->pExpr); - if( pCExpr->op!=TK_ID ){ + if( pCExpr->op!=TK_COLUMN ){ sqlite3ErrorMsg(pParse, "indexes on expressions not yet supported"); continue; } - zColName = pCExpr->u.zToken; - for(j=0, pTabCol=pTab->aCol; jnCol; j++, pTabCol++){ - if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break; - } - if( j>=pTab->nCol ){ - sqlite3ErrorMsg(pParse, "table %s has no column named %s", - pTab->zName, zColName); - pParse->checkSchema = 1; - goto exit_create_index; - } + j = pCExpr->iColumn; assert( j<=0x7fff ); + if( j<0 ) j = pTab->iPKey; pIndex->aiColumn[i] = (i16)j; + zColl = 0; if( pListItem->pExpr->op==TK_COLLATE ){ int nColl; zColl = pListItem->pExpr->u.zToken; @@ -3146,10 +3137,10 @@ Index *sqlite3CreateIndex( zColl = zExtra; zExtra += nColl; nExtra -= nColl; - }else{ + }else if( j>=0 ){ zColl = pTab->aCol[j].zColl; - if( !zColl ) zColl = "BINARY"; } + if( !zColl ) zColl = "BINARY"; if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){ goto exit_create_index; } diff --git a/src/resolve.c b/src/resolve.c index 4ef8fe051b..979596941d 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -547,36 +547,28 @@ Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){ } /* -** Report an error that an expression is not valid for a partial index WHERE -** clause. +** Report an error that an expression is not valid for some set of +** pNC->ncFlags values determined by validMask. If */ -static void notValidPartIdxWhere( +static void notValid( Parse *pParse, /* Leave error message here */ NameContext *pNC, /* The name context */ - const char *zMsg /* Type of error */ + const char *zMsg, /* Type of error */ + int validMask, /* Set of contexts for which prohibited */ + int okForInit /* No error if pParse->db->init.busy is true */ ){ - if( (pNC->ncFlags & NC_PartIdx)!=0 ){ - sqlite3ErrorMsg(pParse, "%s prohibited in partial index WHERE clauses", - zMsg); - } -} - + assert( (validMask&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr))==0 ); + if( (pNC->ncFlags & validMask)!=0 + && (pParse->db->init.busy==0 || !okForInit) + ){ + const char *zIn = "partial index WHERE clauses"; + if( pNC->ncFlags & NC_IdxExpr ) zIn = "index expressions"; #ifndef SQLITE_OMIT_CHECK -/* -** Report an error that an expression is not valid for a CHECK constraint. -*/ -static void notValidCheckConstraint( - Parse *pParse, /* Leave error message here */ - NameContext *pNC, /* The name context */ - const char *zMsg /* Type of error */ -){ - if( (pNC->ncFlags & NC_IsCheck)!=0 ){ - sqlite3ErrorMsg(pParse,"%s prohibited in CHECK constraints", zMsg); + else if( pNC->ncFlags & NC_IsCheck ) zIn = "CHECK constraints"; +#endif + sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn); } } -#else -# define notValidCheckConstraint(P,N,M) -#endif /* ** Expression p should encode a floating point value between 1.0 and 0.0. @@ -661,6 +653,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ Expr *pRight; /* if( pSrcList==0 ) break; */ + notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr, 0); + notValid(pParse, pNC, "the \".\" operator", NC_PartIdx|NC_IsCheck, 1); pRight = pExpr->pRight; if( pRight->op==TK_ID ){ zDb = 0; @@ -690,7 +684,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ u8 enc = ENC(pParse->db); /* The database encoding */ assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); - notValidPartIdxWhere(pParse, pNC, "functions"); + notValid(pParse, pNC, "functions", NC_PartIdx, 0); zId = pExpr->u.zToken; nId = sqlite3Strlen30(zId); pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0); @@ -740,6 +734,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ #endif if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ){ ExprSetProperty(pExpr,EP_ConstFunc); + }else{ + notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr, 0); } } if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){ @@ -786,8 +782,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_IN ); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ int nRef = pNC->nRef; - notValidCheckConstraint(pParse, pNC, "subqueries"); - notValidPartIdxWhere(pParse, pNC, "subqueries"); + notValid(pParse, pNC, "subqueries", NC_IsCheck|NC_PartIdx|NC_IdxExpr,0); sqlite3WalkSelect(pWalker, pExpr->x.pSelect); assert( pNC->nRef>=nRef ); if( nRef!=pNC->nRef ){ @@ -797,8 +792,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ break; } case TK_VARIABLE: { - notValidCheckConstraint(pParse, pNC, "parameters"); - notValidPartIdxWhere(pParse, pNC, "parameters"); + notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr, 0); break; } } @@ -1501,14 +1495,14 @@ void sqlite3ResolveSelectNames( void sqlite3ResolveSelfReference( Parse *pParse, /* Parsing context */ Table *pTab, /* The table being referenced */ - int type, /* NC_IsCheck or NC_PartIdx */ + int type, /* NC_IsCheck or NC_PartIdx or NC_IdxExpr */ Expr *pExpr, /* Expression to resolve. May be NULL. */ ExprList *pList /* Expression list to resolve. May be NUL. */ ){ SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ NameContext sNC; /* Name context for pParse->pNewTable */ - assert( type==NC_IsCheck || type==NC_PartIdx ); + assert( type==NC_IsCheck || type==NC_PartIdx || type==NC_IdxExpr ); memset(&sNC, 0, sizeof(sNC)); memset(&sSrc, 0, sizeof(sSrc)); sSrc.nSrc = 1; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 4c17904ff8..2358795148 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2391,6 +2391,7 @@ struct NameContext { #define NC_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */ #define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */ #define NC_PartIdx 0x0010 /* True if resolving a partial index WHERE */ +#define NC_IdxExpr 0x0020 /* True if resolving columns of CREATE INDEX */ #define NC_MinMaxAgg 0x1000 /* min/max aggregates seen. See note above */ /* From 1f9ca2c84ca1601fde33eab74d376ac1b1c9d3b0 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 25 Aug 2015 16:57:52 +0000 Subject: [PATCH 02/25] Add code to maintain indexes with expression arguments across DELETE, INSERT, and UPDATE statements. Legacy tests pass, but the new code paths are still largely untested. The query planner currently makes no effort to use expression indexes. FossilOrigin-Name: efaabdb71626bdc03768e87e186c72f6f3da75b2 --- manifest | 37 ++++++++++++++---------------- manifest.uuid | 2 +- src/analyze.c | 7 +++--- src/build.c | 60 ++++++++++++++++++++++++++++++++++--------------- src/delete.c | 15 ++++++++----- src/expr.c | 27 ++++++++++++++++++++-- src/insert.c | 38 ++++++++++++++++++++++++------- src/resolve.c | 2 +- src/shell.c | 2 +- src/sqliteInt.h | 4 +++- src/update.c | 8 +++++-- src/vdbeblob.c | 3 ++- test/index.test | 6 ++--- test/rowid.test | 2 ++ 14 files changed, 146 insertions(+), 67 deletions(-) diff --git a/manifest b/manifest index 34496b20c1..b9e43c21d7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Changes\stoward\sbeing\sabld\sto\sprocess\sindexes\son\sexpressions.\s\sNot\sthere\syet\s-\s\nthis\scheck-in\sis\sjust\smovement\sin\sthat\sdirection.\s\sSome\stests\sare\sfailing. -D 2015-08-25T00:27:06.624 +C Add\scode\sto\smaintain\sindexes\swith\sexpression\sarguments\sacross\sDELETE,\sINSERT,\nand\sUPDATE\sstatements.\s\sLegacy\stests\spass,\sbut\sthe\snew\scode\spaths\sare\sstill\nlargely\suntested.\s\sThe\squery\splanner\scurrently\smakes\sno\seffort\sto\suse\nexpression\sindexes. +D 2015-08-25T16:57:52.554 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in e2218eb228374422969de7b1680eda6864affcef F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -273,7 +273,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F src/alter.c 48e14b8aea28dc58baafe3cfcb8889c086b7744a -F src/analyze.c f89727c36f997bd2bf6c5e546c2f51dc94e6f2a4 +F src/analyze.c 3ec61c5142e5fd6f66faf83de93d86d9810d1728 F src/attach.c e944d0052b577703b9b83aac1638452ff42a8395 F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/backup.c 4d9134dc988a87838c06056c89c0e8c4700a0452 @@ -282,14 +282,14 @@ F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79 F src/btree.c f48b3ef91676c06a90a8832987ecef6b94c931ee F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1 F src/btreeInt.h 8177c9ab90d772d6d2c6c517e05bed774b7c92c0 -F src/build.c d9d53c7318117e04cfb79bc498b45f4982092f0c +F src/build.c c249a192b2395363e9ec89ec7060312ea6a0b2ca F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b F src/date.c 8ec787fed4929d8ccdf6b1bc360fccc3e1d2ca58 F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a -F src/delete.c 8857a6f27560718f65d43bdbec86c967ae1f8dfa -F src/expr.c 650ac7c4f659980a3315e2aaa02a0d71e87f14a5 +F src/delete.c 07ba8cc1def3ed9a316c0073217c48ebff59062b +F src/expr.c 4a52fd29145d94c6f2e355ec67489dc8d309f05e F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c c9b63a217d86582c22121699a47f22f524608869 F src/func.c 824bea430d3a2b7dbc62806ad54da8fdb8ed9e3f @@ -297,7 +297,7 @@ F src/global.c 508e4087f7b41d688e4762dcf4d4fe28cfbc87f9 F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c ad9ebaafdc4438bb0de58cd7d6bc199fb5b6917a +F src/insert.c 602809df9668a8418ea488a59a0bef787f0aec6f F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 92bafa308607dd985ca389a788cd9e0a2b608712 @@ -335,14 +335,14 @@ F src/pragma.h 631a91c8b0e6ca8f051a1d8a4a0da4150e04620a F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1 F src/printf.c 2bc439ff20a4aad0e0ad50a37a67b5eae7d20edc F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 -F src/resolve.c ad9404cfa6f698aa530cca1c86570fa92cb65a12 +F src/resolve.c c4691acf9dca466799a0b07cf7f82d18d557f799 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c da6d1e7a4f1c8d713ed5415b5ed21d82ef465c0f -F src/shell.c b1f91e60918df3a68efad1e3a11696b9a7e23d23 +F src/shell.c 5a08835e85c502978bde35a89d4045833f772876 F src/sqlite.h.in 378bebc8fe6a88bade25e5f23b7e6123fdc64b00 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h f700e6a9dd1fdcccc9951ab022b366fb66b9e413 -F src/sqliteInt.h 5e2ce12324eb03b75d5b8a37084550eb66dbef78 +F src/sqliteInt.h 5fe814323e6ea95685206f8764db29dba680c8e8 F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e @@ -396,7 +396,7 @@ F src/threads.c 6bbcc9fe50c917864d48287b4792d46d6e873481 F src/tokenize.c 57cb3720f53f84d811def2069c2b169b6be539a5 F src/treeview.c c15df00728034549ff92d78ae851b44952736d3b F src/trigger.c 322f23aad694e8f31d384dcfa386d52a48d3c52f -F src/update.c 487747b328b7216bb7f6af0695d6937d5c9e605f +F src/update.c 798196d7693277d359846df7587fc15ee58a563f F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c bc9dd64b5db544218b871b66243871c202b2781f F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701 @@ -405,7 +405,7 @@ F src/vdbe.h 7a75045d879118b9d3af7e8b3c108f2f27c51473 F src/vdbeInt.h 8b54e01ad0463590e7cffabce0bc36da9ee4f816 F src/vdbeapi.c bda74ef4b5103d7b4a4be36f936d3cf2b56a7d6f F src/vdbeaux.c af2d86b2b114a106c94fc656503fc5c89594f5af -F src/vdbeblob.c 4f2e8e075d238392df98c5e03a64342465b03f90 +F src/vdbeblob.c 1d7b97115e7bbac4c318db416d2ca83fc779544a F src/vdbemem.c ae38a0d35ae71cf604381a887c170466ba518090 F src/vdbesort.c f5009e7a35e3065635d8918b9a31f498a499976b F src/vdbetrace.c 8befe829faff6d9e6f6e4dee5a7d3f85cc85f1a0 @@ -772,7 +772,7 @@ F test/incrvacuum.test d2a6ddf5e429720b5fe502766af747915ccf6c32 F test/incrvacuum2.test 676c41428765d58f1da7dbe659ef27726d3d30ac F test/incrvacuum3.test 75256fb1377e7c39ef2de62bfc42bbff67be295a F test/incrvacuum_ioerr.test 6ae2f783424e47a0033304808fe27789cf93e635 -F test/index.test 4d990005a67a36984e4f1a5f1bdccea8d08da4ee +F test/index.test fe3c7a1aad82af92623747e9c3f3aa94ccd51238 F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6 F test/index3.test b6ec456cf3b81d9a32123fe7e449bde434db338b F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6 @@ -941,7 +941,7 @@ F test/rollback2.test fc14cf6d1a2b250d2735ef16124b971bce152f14 F test/rollbackfault.test 6a004f71087cc399296cffbb5429ea6da655ae65 F test/rowallock.test 3f88ec6819489d0b2341c7a7528ae17c053ab7cc F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81 -F test/rowid.test 742b5741584a8a44fd83e856cc2896688401d645 +F test/rowid.test 09fcded0c96fbc0ed11fb75faa3b0bad32cb011a F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798 F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09 F test/savepoint.test c671fdbd34cd3bfe1518a777526ada595180cf8d @@ -1379,10 +1379,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P bdaf66465b6b1bdad10c08d9527b98e7000a41e4 -R 3888db9ab5ffaaee9ce833f48e49ed84 -T *branch * index-expr -T *sym-index-expr * -T -sym-trunk * +P 0ad0f8d77d8f95ca2ffb7745d18219f5e87dc89c +R 457a1c92538887efc6aebf70344c3622 U drh -Z 80441a5a4abd6f0065befff78e2e1eff +Z d2f3b8f04887de8a5bca7c4f4441bcbc diff --git a/manifest.uuid b/manifest.uuid index 712ea9a3fd..a43b7e84ea 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0ad0f8d77d8f95ca2ffb7745d18219f5e87dc89c \ No newline at end of file +efaabdb71626bdc03768e87e186c72f6f3da75b2 \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index 59518cdc3f..3e531bd722 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -1186,6 +1186,7 @@ static void analyzeOneTable( regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol); for(j=0; jnKeyCol; j++){ k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]); + assert( k>=0 && knCol ); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j); VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName)); } @@ -1235,12 +1236,10 @@ static void analyzeOneTable( ** be taken */ VdbeCoverageNeverTaken(v); #ifdef SQLITE_ENABLE_STAT3 - sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, - pIdx->aiColumn[0], regSample); + sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, 0, regSample); #else for(i=0; iaiColumn[i]; - sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regCol+i); + sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, i, regCol+i); } sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol, regSample); #endif diff --git a/src/build.c b/src/build.c index 64bfe1b061..fc50fdd822 100644 --- a/src/build.c +++ b/src/build.c @@ -443,6 +443,7 @@ static void freeIndex(sqlite3 *db, Index *p){ sqlite3DeleteIndexSamples(db, p); #endif sqlite3ExprDelete(db, p->pPartIdxWhere); + sqlite3ExprListDelete(db, p->aColExpr); sqlite3DbFree(db, p->zColAff); if( p->isResized ) sqlite3DbFree(db, p->azColl); #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 @@ -3101,32 +3102,47 @@ Index *sqlite3CreateIndex( sortOrderMask = 0; /* Ignore DESC */ } - /* Scan the names of the columns of the table to be indexed and - ** load the column indices into the Index structure. Report an error - ** if any column is not found. + /* Analyze the list of expressions that form the terms of the index and + ** report any errors. In the common case where the expression is exactly + ** a table column, store that column in aiColumn[]. For general expressions, + ** populate pIndex->aColExpr and store -2 in aiColumn[]. ** - ** TODO: Add a test to make sure that the same column is not named - ** more than once within the same index. Only the first instance of - ** the column will ever be used by the optimizer. Note that using the - ** same column more than once cannot be an error because that would - ** break backwards compatibility - it needs to be a warning. + ** TODO: Issue a warning if two or more columns of the index are identical. + ** TODO: Issue a warning if the table primary key is used as part of the + ** index key. */ for(i=0, pListItem=pList->a; inExpr; i++, pListItem++){ - Expr *pCExpr; - int requestedSortOrder; + Expr *pCExpr; /* The i-th index expression */ + int requestedSortOrder; /* ASC or DESC on the i-th expression */ char *zColl; /* Collation sequence name */ sqlite3ResolveSelfReference(pParse, pTab, NC_IdxExpr, pListItem->pExpr, 0); if( pParse->nErr ) goto exit_create_index; pCExpr = sqlite3ExprSkipCollate(pListItem->pExpr); if( pCExpr->op!=TK_COLUMN ){ - sqlite3ErrorMsg(pParse, "indexes on expressions not yet supported"); - continue; + if( pTab==pParse->pNewTable ){ + sqlite3ErrorMsg(pParse, "expressions prohibited in PRIMARY KEY and " + "UNIQUE constraints"); + goto exit_create_index; + } + if( pIndex->aColExpr==0 ){ + pIndex->aColExpr = sqlite3ExprListDup(db, pList, 0); + } + j = -2; + pIndex->aiColumn[i] = -2; + if( sqlite3ExprCanBeNull(pList->a[i].pExpr) ){ + pIndex->uniqNotNull = 1; + } + }else{ + j = pCExpr->iColumn; + assert( j<=0x7fff ); + if( j<0 ){ + j = pTab->iPKey; + }else if( pTab->aCol[j].notNull==0 ){ + pIndex->uniqNotNull = 0; + } + pIndex->aiColumn[i] = (i16)j; } - j = pCExpr->iColumn; - assert( j<=0x7fff ); - if( j<0 ) j = pTab->iPKey; - pIndex->aiColumn[i] = (i16)j; zColl = 0; if( pListItem->pExpr->op==TK_COLLATE ){ int nColl; @@ -3147,11 +3163,16 @@ Index *sqlite3CreateIndex( pIndex->azColl[i] = zColl; requestedSortOrder = pListItem->sortOrder & sortOrderMask; pIndex->aSortOrder[i] = (u8)requestedSortOrder; - if( pTab->aCol[j].notNull==0 ) pIndex->uniqNotNull = 0; } + + /* Append the table key to the end of the index. For WITHOUT ROWID + ** tables (when pPk!=0) this will be the declared PRIMARY KEY. For + ** normal tables (when pPk==0) this will be the rowid. + */ if( pPk ){ for(j=0; jnKeyCol; j++){ int x = pPk->aiColumn[j]; + assert( x>=0 ); if( hasColumn(pIndex->aiColumn, pIndex->nKeyCol, x) ){ pIndex->nColumn--; }else{ @@ -3202,6 +3223,7 @@ Index *sqlite3CreateIndex( for(k=0; knKeyCol; k++){ const char *z1; const char *z2; + assert( pIdx->aiColumn[k]>=0 ); if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break; z1 = pIdx->azColl[k]; z2 = pIndex->azColl[k]; @@ -4093,7 +4115,9 @@ void sqlite3UniqueConstraint( sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200); for(j=0; jnKeyCol; j++){ - char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName; + char *zCol; + assert( pIdx->aiColumn[j]>=0 ); + zCol = pTab->aCol[pIdx->aiColumn[j]].zName; if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2); sqlite3StrAccumAppendAll(&errMsg, pTab->zName); sqlite3StrAccumAppend(&errMsg, ".", 1); diff --git a/src/delete.c b/src/delete.c index 369cdaf6fe..cff922cbb3 100644 --- a/src/delete.c +++ b/src/delete.c @@ -411,6 +411,7 @@ void sqlite3DeleteFrom( /* Extract the rowid or primary key for the current row */ if( pPk ){ for(i=0; iaiColumn[i]>=(-1) ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, pPk->aiColumn[i], iPk+i); } @@ -789,14 +790,13 @@ int sqlite3GenerateIndexKey( ){ Vdbe *v = pParse->pVdbe; int j; - Table *pTab = pIdx->pTable; int regBase; int nCol; if( piPartIdxLabel ){ if( pIdx->pPartIdxWhere ){ *piPartIdxLabel = sqlite3VdbeMakeLabel(v); - pParse->iPartIdxTab = iDataCur; + pParse->iSelfTab = iDataCur; sqlite3ExprCachePush(pParse); sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, SQLITE_JUMPIFNULL); @@ -808,9 +808,14 @@ int sqlite3GenerateIndexKey( regBase = sqlite3GetTempRange(pParse, nCol); if( pPrior && (regBase!=regPrior || pPrior->pPartIdxWhere) ) pPrior = 0; for(j=0; jaiColumn[j]==pIdx->aiColumn[j] ) continue; - sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pIdx->aiColumn[j], - regBase+j); + if( pPrior + && pPrior->aiColumn[j]==pIdx->aiColumn[j] + && pPrior->aiColumn[j]>=(-1) + ){ + /* This column was already computed by the previous index */ + continue; + } + sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iDataCur, j, regBase+j); /* If the column affinity is REAL but the number is an integer, then it ** might be stored in the table as an integer (using a compact ** representation) then converted to REAL by an OP_RealAffinity opcode. diff --git a/src/expr.c b/src/expr.c index 1aebef6b16..34c382a192 100644 --- a/src/expr.c +++ b/src/expr.c @@ -2432,6 +2432,28 @@ static void sqlite3ExprCachePinRegister(Parse *pParse, int iReg){ } } +/* Generate code that will load into register regOut a value that is +** appropriate for the iIdxCol-th column of index pIdx. +*/ +void sqlite3ExprCodeLoadIndexColumn( + Parse *pParse, /* The parsing context */ + Index *pIdx, /* The index whose column is to be loaded */ + int iTabCur, /* Cursor pointing to a table row */ + int iIdxCol, /* The column of the index to be loaded */ + int regOut /* Store the index column value in this register */ +){ + i16 iTabCol = pIdx->aiColumn[iIdxCol]; + if( iTabCol>=(-1) ){ + sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pIdx->pTable, iTabCur, + iTabCol, regOut); + return; + } + assert( pIdx->aColExpr ); + assert( pIdx->aColExpr->nExpr>iIdxCol ); + pParse->iSelfTab = iTabCur; + sqlite3ExprCode(pParse, pIdx->aColExpr->a[iIdxCol].pExpr, regOut); +} + /* ** Generate code to extract the value of the iCol-th column of a table. */ @@ -2617,8 +2639,9 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ inReg = pExpr->iColumn + pParse->ckBase; break; }else{ - /* Deleting from a partial index */ - iTab = pParse->iPartIdxTab; + /* Coding an expression that is part of an index where column names + ** in the index refer to the table to which the index belongs */ + iTab = pParse->iSelfTab; } } inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab, diff --git a/src/insert.c b/src/insert.c index 839599438c..ae24991301 100644 --- a/src/insert.c +++ b/src/insert.c @@ -89,7 +89,15 @@ const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){ } for(n=0; nnColumn; n++){ i16 x = pIdx->aiColumn[n]; - pIdx->zColAff[n] = x<0 ? SQLITE_AFF_INTEGER : pTab->aCol[x].affinity; + if( x>=0 ){ + pIdx->zColAff[n] = pTab->aCol[x].affinity; + }else if( x==(-1) ){ + pIdx->zColAff[n] = SQLITE_AFF_INTEGER; + }else{ + assert( x==(-2) ); + assert( pIdx->aColExpr!=0 ); + pIdx->zColAff[n] = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr); + } } pIdx->zColAff[n] = 0; } @@ -1395,15 +1403,22 @@ void sqlite3GenerateConstraintChecks( for(i=0; inColumn; i++){ int iField = pIdx->aiColumn[i]; int x; - if( iField<0 || iField==pTab->iPKey ){ - if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */ - x = regNewData; - regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i; + if( iField==(-2) ){ + pParse->ckBase = regNewData+1; + sqlite3ExprCode(pParse, pIdx->aColExpr->a[i].pExpr, regIdx+i); + pParse->ckBase = 0; + VdbeComment((v, "%s column %d", pIdx->zName, i)); }else{ - x = iField + regNewData + 1; + if( iField==(-1) || iField==pTab->iPKey ){ + if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */ + x = regNewData; + regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i; + }else{ + x = iField + regNewData + 1; + } + sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i); + VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName)); } - sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i); - VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName)); } sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]); VdbeComment((v, "for %s", pIdx->zName)); @@ -1724,6 +1739,13 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){ if( pSrc->aiColumn[i]!=pDest->aiColumn[i] ){ return 0; /* Different columns indexed */ } + if( pSrc->aiColumn[i]==(-2) ){ + assert( pSrc->aColExpr!=0 && pDest->aColExpr!=0 ); + if( sqlite3ExprCompare(pSrc->aColExpr->a[i].pExpr, + pDest->aColExpr->a[i].pExpr, -1)!=0 ){ + return 0; /* Different expressions in the index */ + } + } if( pSrc->aSortOrder[i]!=pDest->aSortOrder[i] ){ return 0; /* Different sort orders */ } diff --git a/src/resolve.c b/src/resolve.c index 979596941d..a85543f09e 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -654,7 +654,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ /* if( pSrcList==0 ) break; */ notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr, 0); - notValid(pParse, pNC, "the \".\" operator", NC_PartIdx|NC_IsCheck, 1); + /*notValid(pParse, pNC, "the \".\" operator", NC_PartIdx|NC_IsCheck, 1);*/ pRight = pExpr->pRight; if( pRight->op==TK_ID ){ zDb = 0; diff --git a/src/shell.c b/src/shell.c index c289998a7b..da7f78e10d 100644 --- a/src/shell.c +++ b/src/shell.c @@ -4252,8 +4252,8 @@ static int process_input(ShellState *p, FILE *in){ fprintf(stderr, "Error: incomplete SQL: %s\n", zSql); errCnt++; } - free(zSql); } + free(zSql); free(zLine); return errCnt>0; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 2358795148..73bf83d3de 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1871,6 +1871,7 @@ struct Index { u8 *aSortOrder; /* for each column: True==DESC, False==ASC */ char **azColl; /* Array of collation sequence names for index */ Expr *pPartIdxWhere; /* WHERE clause for partial indices */ + ExprList *aColExpr; /* Column expressions */ int tnum; /* DB Page containing root of this index */ LogEst szIdxRow; /* Estimated average row size in bytes */ u16 nKeyCol; /* Number of columns forming the key */ @@ -2661,7 +2662,7 @@ struct Parse { int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */ int iFixedOp; /* Never back out opcodes iFixedOp-1 or earlier */ int ckBase; /* Base register of data during check constraints */ - int iPartIdxTab; /* Table corresponding to a partial index */ + int iSelfTab; /* Table of an index whose exprs are being coded */ int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */ int iCacheCnt; /* Counter used to generate aColCache[].lru values */ int nLabel; /* Number of labels used */ @@ -3362,6 +3363,7 @@ int sqlite3WhereIsSorted(WhereInfo*); int sqlite3WhereContinueLabel(WhereInfo*); int sqlite3WhereBreakLabel(WhereInfo*); int sqlite3WhereOkOnePass(WhereInfo*, int*); +void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int); int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); void sqlite3ExprCodeMove(Parse*, int, int, int); diff --git a/src/update.c b/src/update.c index f8347448a1..cc9b690779 100644 --- a/src/update.c +++ b/src/update.c @@ -272,7 +272,9 @@ void sqlite3Update( /* There is one entry in the aRegIdx[] array for each index on the table ** being updated. Fill in aRegIdx[] with a register number that will hold - ** the key for accessing each index. + ** the key for accessing each index. + ** + ** FIXME: Be smarter about omitting indexes that use expressions. */ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int reg; @@ -281,7 +283,8 @@ void sqlite3Update( }else{ reg = 0; for(i=0; inKeyCol; i++){ - if( aXRef[pIdx->aiColumn[i]]>=0 ){ + i16 iIdxCol = pIdx->aiColumn[i]; + if( iIdxCol<0 || aXRef[iIdxCol]>=0 ){ reg = ++pParse->nMem; break; } @@ -381,6 +384,7 @@ void sqlite3Update( if( pWInfo==0 ) goto update_cleanup; okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); for(i=0; iaiColumn[i]>=(-1) ); sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pPk->aiColumn[i], iPk+i); } diff --git a/src/vdbeblob.c b/src/vdbeblob.c index ea01f5ce80..2cdc3edb00 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -247,7 +247,8 @@ int sqlite3_blob_open( for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int j; for(j=0; jnKeyCol; j++){ - if( pIdx->aiColumn[j]==iCol ){ + /* FIXME: Be smarter about indexes that use expressions */ + if( pIdx->aiColumn[j]==iCol || pIdx->aiColumn[j]==(-2) ){ zFault = "indexed"; } } diff --git a/test/index.test b/test/index.test index 59c0ea6f90..712f42c3a4 100644 --- a/test/index.test +++ b/test/index.test @@ -56,11 +56,11 @@ do_test index-2.1 { # Try adding an index on a column of a table where the table # exists but the column does not. # -do_test index-2.1 { +do_test index-2.1b { execsql {CREATE TABLE test1(f1 int, f2 int, f3 int)} set v [catch {execsql {CREATE INDEX index1 ON test1(f4)}} msg] lappend v $msg -} {1 {table test1 has no column named f4}} +} {1 {no such column: f4}} # Try an index with some columns that match and others that do now. # @@ -68,7 +68,7 @@ do_test index-2.2 { set v [catch {execsql {CREATE INDEX index1 ON test1(f1, f2, f4, f3)}} msg] execsql {DROP TABLE test1} lappend v $msg -} {1 {table test1 has no column named f4}} +} {1 {no such column: f4}} # Try creating a bunch of indices on the same table # diff --git a/test/rowid.test b/test/rowid.test index b00b5287fd..21696f6839 100644 --- a/test/rowid.test +++ b/test/rowid.test @@ -144,6 +144,7 @@ do_test rowid-2.8 { execsql {SELECT x FROM t1 ORDER BY x} } {1 3 5 7 9} +if 0 { # we can now.... # We cannot index by ROWID # do_test rowid-2.9 { @@ -162,6 +163,7 @@ do_test rowid-2.12 { set v [catch {execsql {CREATE INDEX idxt1 ON t1(x, rowid)}} msg] lappend v $msg } {1 {table t1 has no column named rowid}} +} # Columns defined in the CREATE statement override the buildin ROWID # column names. From bb52308f3d53949407c13e7cc624b1983b0d4034 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 27 Aug 2015 15:58:51 +0000 Subject: [PATCH 03/25] Adjustments to the WHERE term scanning, to better handle scanning terms of an index. FossilOrigin-Name: 5611130a595e7f0b6d5f21d76f2755e9c09c7810 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 53 ++++++++++++++++++++++++++++++++++----------------- 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/manifest b/manifest index cc1cce44df..8a7ec7eaf1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\senhancements\sfrom\strunk. -D 2015-08-26T18:04:23.442 +C Adjustments\sto\sthe\sWHERE\sterm\sscanning,\sto\sbetter\shandle\sscanning\sterms\sof\nan\sindex. +D 2015-08-27T15:58:51.073 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in e2218eb228374422969de7b1680eda6864affcef F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -414,7 +414,7 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c 6fb6b68969e4692593c2552c4e7bff5882de2cb8 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 2e14d17f592d176b6dc879c33fbdec4fbccaa2ba -F src/where.c fb8546b8053433bfb39f6c39fdc99c111a6f97c5 +F src/where.c 0709bbc33117a21db57a031b1452a35de14bf86b F src/whereInt.h 880a8599226ac1c00203490d934f3ed79b292572 F src/wherecode.c 3d9113cc307ffeed58db41fe9f2d807c94787ab5 F src/whereexpr.c 1a308d1ee5144890d21ea9cf70d49bc96a83432b @@ -1380,7 +1380,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P e8b02902c48f3668dcff7b1767347ac7ef3c971e c2f3bbad778504681b39ab9399a1eb3c1a35ab3f -R 81693495b2084fce0fa08431d5ef28b1 +P ec6ddb3d481d005c304a26c948c9c808586750e9 +R e5ffdfd8fde6c8b7686cb0a9ca3923f7 U drh -Z bec0cbafd7b79403eeb50b2f9a3289c8 +Z 4ee413196597973385c2eb895ecb052b diff --git a/manifest.uuid b/manifest.uuid index c6150c8ad4..5b29dbd27d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ec6ddb3d481d005c304a26c948c9c808586750e9 \ No newline at end of file +5611130a595e7f0b6d5f21d76f2755e9c09c7810 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 9789b0848d..f3454c0fd0 100644 --- a/src/where.c +++ b/src/where.c @@ -273,11 +273,12 @@ static WhereTerm *whereScanInit( /* memset(pScan, 0, sizeof(*pScan)); */ pScan->pOrigWC = pWC; pScan->pWC = pWC; + if( pIdx ){ + j = iColumn; + iColumn = pIdx->aiColumn[j]; + } if( pIdx && iColumn>=0 ){ pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity; - for(j=0; pIdx->aiColumn[j]!=iColumn; j++){ - if( NEVER(j>pIdx->nColumn) ) return 0; - } pScan->zCollName = pIdx->azColl[j]; }else{ pScan->idxaff = 0; @@ -298,6 +299,9 @@ static WhereTerm *whereScanInit( ** the WO_xx operator codes specified by the op parameter. ** Return a pointer to the term. Return 0 if not found. ** +** If pIdx!=0 then search for terms matching the iColumn-th column of pIdx +** rather than the iColumn-th column of table iCur. +** ** The term returned might by Y= if there is another constraint in ** the WHERE clause that specifies that X=Y. Any such constraints will be ** identified by the WO_EQUIV bit in the pTerm->eOperator field. The @@ -375,6 +379,24 @@ static int findIndexCol( return -1; } +/* +** Return TRUE if the iCol-th column of index pIdx is NOT NULL +*/ +static int indexColumnNotNull(Index *pIdx, int iCol){ + int j; + assert( pIdx!=0 ); + assert( iCol>=0 && iColnColumn ); + j = pIdx->aiColumn[iCol]; + if( j>=0 ){ + return pIdx->pTable->aCol[j].notNull; + }else if( j==(-1) ){ + return 1; + }else{ + assert( j==(-2) ); + return !sqlite3ExprCanBeNull(pIdx->aColExpr->a[iCol].pExpr); + } +} + /* ** Return true if the DISTINCT expression-list passed as the third argument ** is redundant. @@ -425,12 +447,9 @@ static int isDistinctRedundant( for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( !IsUniqueIndex(pIdx) ) continue; for(i=0; inKeyCol; i++){ - i16 iCol = pIdx->aiColumn[i]; - if( 0==sqlite3WhereFindTerm(pWC, iBase, iCol, ~(Bitmask)0, WO_EQ, pIdx) ){ - int iIdxCol = findIndexCol(pParse, pDistinct, iBase, pIdx, i); - if( iIdxCol<0 || pTab->aCol[iCol].notNull==0 ){ - break; - } + if( 0==sqlite3WhereFindTerm(pWC, iBase, i, ~(Bitmask)0, WO_EQ, pIdx) ){ + if( findIndexCol(pParse, pDistinct, iBase, pIdx, i)<0 ) break; + if( indexColumnNotNull(pIdx, i)==0 ) break; } } if( i==pIdx->nKeyCol ){ @@ -2126,7 +2145,6 @@ static int whereLoopAddBtreeIndex( u16 saved_nSkip; /* Original value of pNew->nSkip */ u32 saved_wsFlags; /* Original value of pNew->wsFlags */ LogEst saved_nOut; /* Original value of pNew->nOut */ - int iCol; /* Index of the column in the table */ int rc = SQLITE_OK; /* Return code */ LogEst rSize; /* Number of rows in the table */ LogEst rLogSize; /* Logarithm of table size */ @@ -2147,16 +2165,15 @@ static int whereLoopAddBtreeIndex( if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); assert( pNew->u.btree.nEqnColumn ); - iCol = pProbe->aiColumn[pNew->u.btree.nEq]; - pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, iCol, - opMask, pProbe); saved_nEq = pNew->u.btree.nEq; saved_nSkip = pNew->nSkip; saved_nLTerm = pNew->nLTerm; saved_wsFlags = pNew->wsFlags; saved_prereq = pNew->prereq; saved_nOut = pNew->nOut; + pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, saved_nEq, + opMask, pProbe); pNew->rSetup = 0; rSize = pProbe->aiRowLogEst[0]; rLogSize = estLog(rSize); @@ -2169,7 +2186,7 @@ static int whereLoopAddBtreeIndex( int nRecValid = pBuilder->nRecValid; #endif if( (eOp==WO_ISNULL || (pTerm->wtFlags&TERM_VNULL)!=0) - && (iCol<0 || pSrc->pTab->aCol[iCol].notNull) + && indexColumnNotNull(pProbe, saved_nEq) ){ continue; /* ignore IS [NOT] NULL constraints on NOT NULL columns */ } @@ -2206,8 +2223,10 @@ static int whereLoopAddBtreeIndex( ** changes "x IN (?)" into "x=?". */ }else if( eOp & (WO_EQ|WO_IS) ){ + int iCol = pProbe->aiColumn[saved_nEq]; pNew->wsFlags |= WHERE_COLUMN_EQ; - if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1) ){ + assert( saved_nEq==pNew->u.btree.nEq ); + if( iCol==(-1) || (nInMul==0 && saved_nEq==pProbe->nKeyCol-1) ){ if( iCol>=0 && pProbe->uniqNotNull==0 ){ pNew->wsFlags |= WHERE_UNQ_WANTED; }else{ @@ -2258,7 +2277,7 @@ static int whereLoopAddBtreeIndex( assert( eOp & (WO_ISNULL|WO_EQ|WO_IN|WO_IS) ); assert( pNew->nOut==saved_nOut ); - if( pTerm->truthProb<=0 && iCol>=0 ){ + if( pTerm->truthProb<=0 && pProbe->aiColumn[saved_nEq]>=0 ){ assert( (eOp & WO_IN) || nIn==0 ); testcase( eOp & WO_IN ); pNew->nOut += pTerm->truthProb; @@ -3785,7 +3804,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ ) continue; opMask = pIdx->uniqNotNull ? (WO_EQ|WO_IS) : WO_EQ; for(j=0; jnKeyCol; j++){ - pTerm = sqlite3WhereFindTerm(pWC, iCur, pIdx->aiColumn[j], 0, opMask, pIdx); + pTerm = sqlite3WhereFindTerm(pWC, iCur, j, 0, opMask, pIdx); if( pTerm==0 ) break; testcase( pTerm->eOperator & WO_IS ); pLoop->aLTerm[j] = pTerm; From 6860e6fa6fec87334b5c9fe1bc3d0be45cf5ef49 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 27 Aug 2015 18:24:02 +0000 Subject: [PATCH 04/25] Activate the ability to use expressions in indexes in a query. There are some test failures, but mostly this seems to work. FossilOrigin-Name: 42f93f582eccd8a778189aa6c113874f995ab751 --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/insert.c | 5 ++++- src/where.c | 7 ++++++- src/whereInt.h | 1 + src/whereexpr.c | 6 ++++++ 6 files changed, 27 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index 1f899d463c..2b7ae5a002 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\schanges\sfrom\strunk. -D 2015-08-27T16:07:02.026 +C Activate\sthe\sability\sto\suse\sexpressions\sin\sindexes\sin\sa\squery.\s\sThere\sare\ssome\ntest\sfailures,\sbut\smostly\sthis\sseems\sto\swork. +D 2015-08-27T18:24:02.056 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in e2218eb228374422969de7b1680eda6864affcef F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -297,7 +297,7 @@ F src/global.c 508e4087f7b41d688e4762dcf4d4fe28cfbc87f9 F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c b459da1440fd10cb839c716685701f619e3d86a5 +F src/insert.c ef4da9af15ed852509fe49ff9570da6bf4819db6 F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 92bafa308607dd985ca389a788cd9e0a2b608712 @@ -414,10 +414,10 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c 6fb6b68969e4692593c2552c4e7bff5882de2cb8 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 2e14d17f592d176b6dc879c33fbdec4fbccaa2ba -F src/where.c 7b62bfb9a6d98cbba33bfc7914f823a9ad854b33 -F src/whereInt.h 901c17c1e3c82745ad9b85b4471543fa59c980e9 +F src/where.c 29851b4a1a93934fef1bde3d0a1e7407efd57543 +F src/whereInt.h 292d3ac90da4eab1e03ac8452f1add746bcafaa1 F src/wherecode.c 3d9113cc307ffeed58db41fe9f2d807c94787ab5 -F src/whereexpr.c 1a308d1ee5144890d21ea9cf70d49bc96a83432b +F src/whereexpr.c 990ed42b5940d4000e7e61887a4bbed412c80488 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -1380,7 +1380,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 5611130a595e7f0b6d5f21d76f2755e9c09c7810 cbc3c9a8bf169ae0b21f26855038502c6cc25cfe -R 5eb2cbc19058900f308a8789aae8ba36 +P c80e9e8e8cc1e7676d7c782ee0827726875db79e +R ff3e8c131dda72b26dbe6f001a80b515 U drh -Z a8340d48ea4d99e733a68ecfeafbe44a +Z 3e34cddbe64a99afb651902a91a49bea diff --git a/manifest.uuid b/manifest.uuid index f9a3e724f5..62cf69b6e4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c80e9e8e8cc1e7676d7c782ee0827726875db79e \ No newline at end of file +42f93f582eccd8a778189aa6c113874f995ab751 \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index 149096c045..73879303de 100644 --- a/src/insert.c +++ b/src/insert.c @@ -93,9 +93,12 @@ const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){ }else if( x==(-1) ){ pIdx->zColAff[n] = SQLITE_AFF_INTEGER; }else{ + char aff; assert( x==(-2) ); assert( pIdx->aColExpr!=0 ); - pIdx->zColAff[n] = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr); + aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr); + if( aff==0 ) aff = SQLITE_AFF_BLOB; + pIdx->zColAff[n] = aff; } } pIdx->zColAff[n] = 0; diff --git a/src/where.c b/src/where.c index 62a90cade1..ad1eecd920 100644 --- a/src/where.c +++ b/src/where.c @@ -180,10 +180,13 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ while( pScan->iEquiv<=pScan->nEquiv ){ iCur = pScan->aiCur[pScan->iEquiv-1]; iColumn = pScan->aiColumn[pScan->iEquiv-1]; + assert( iColumn!=(-2) || pScan->pIdxExpr!=0 ); while( (pWC = pScan->pWC)!=0 ){ for(pTerm=pWC->a+k; knTerm; k++, pTerm++){ if( pTerm->leftCursor==iCur && pTerm->u.leftColumn==iColumn + && (iColumn!=(-2) + || sqlite3ExprCompare(pTerm->pExpr->pLeft,pScan->pIdxExpr,iCur)==0) && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin)) ){ if( (pTerm->eOperator & WO_EQUIV)!=0 @@ -273,9 +276,11 @@ static WhereTerm *whereScanInit( /* memset(pScan, 0, sizeof(*pScan)); */ pScan->pOrigWC = pWC; pScan->pWC = pWC; + pScan->pIdxExpr = 0; if( pIdx ){ j = iColumn; iColumn = pIdx->aiColumn[j]; + if( iColumn==(-2) ) pScan->pIdxExpr = pIdx->aColExpr->a[j].pExpr; } if( pIdx && iColumn>=0 ){ pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity; @@ -2224,7 +2229,7 @@ static int whereLoopAddBtreeIndex( int iCol = pProbe->aiColumn[saved_nEq]; pNew->wsFlags |= WHERE_COLUMN_EQ; assert( saved_nEq==pNew->u.btree.nEq ); - if( iCol==(-1) || (nInMul==0 && saved_nEq==pProbe->nKeyCol-1) ){ + if( iCol==(-1) || (iCol>0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1) ){ if( iCol>=0 && pProbe->uniqNotNull==0 ){ pNew->wsFlags |= WHERE_UNQ_WANTED; }else{ diff --git a/src/whereInt.h b/src/whereInt.h index 7138b85b25..65c1180048 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -286,6 +286,7 @@ struct WhereScan { WhereClause *pOrigWC; /* Original, innermost WhereClause */ WhereClause *pWC; /* WhereClause currently being scanned */ char *zCollName; /* Required collating sequence, if not NULL */ + Expr *pIdxExpr; /* Search for this index expression */ char idxaff; /* Must match this affinity, if zCollName!=NULL */ unsigned char nEquiv; /* Number of entries in aEquiv[] */ unsigned char iEquiv; /* Next unused slot in aEquiv[] */ diff --git a/src/whereexpr.c b/src/whereexpr.c index 88eb5b70aa..631a7e0dce 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -872,6 +872,12 @@ static void exprAnalyze( pTerm->leftCursor = pLeft->iTable; pTerm->u.leftColumn = pLeft->iColumn; pTerm->eOperator = operatorMask(op) & opMask; + }else if( prereqLeft!=0 && (prereqLeft&(prereqLeft-1))==0 ){ + int i; + for(i=0; (prereqLeft>>i)<1; i++){} + pTerm->leftCursor = pMaskSet->ix[i]; + pTerm->u.leftColumn = -2; + pTerm->eOperator = operatorMask(op) & opMask; } if( op==TK_IS ) pTerm->wtFlags |= TERM_IS; if( pRight && pRight->op==TK_COLUMN ){ From 29d03f6517918b1e67f630e9984d1f8d726df401 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 27 Aug 2015 19:56:49 +0000 Subject: [PATCH 05/25] Fix problems in the indexed-expression handling in the optimizer. FossilOrigin-Name: 03375017691d5b480e73d712c4318632e835060c --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 4 +++- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 2b7ae5a002..2a88bdcb4d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Activate\sthe\sability\sto\suse\sexpressions\sin\sindexes\sin\sa\squery.\s\sThere\sare\ssome\ntest\sfailures,\sbut\smostly\sthis\sseems\sto\swork. -D 2015-08-27T18:24:02.056 +C Fix\sproblems\sin\sthe\sindexed-expression\shandling\sin\sthe\soptimizer. +D 2015-08-27T19:56:49.408 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in e2218eb228374422969de7b1680eda6864affcef F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -414,7 +414,7 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c 6fb6b68969e4692593c2552c4e7bff5882de2cb8 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 2e14d17f592d176b6dc879c33fbdec4fbccaa2ba -F src/where.c 29851b4a1a93934fef1bde3d0a1e7407efd57543 +F src/where.c fcdded4bf274bf527020436e8895b33d575f18f6 F src/whereInt.h 292d3ac90da4eab1e03ac8452f1add746bcafaa1 F src/wherecode.c 3d9113cc307ffeed58db41fe9f2d807c94787ab5 F src/whereexpr.c 990ed42b5940d4000e7e61887a4bbed412c80488 @@ -1380,7 +1380,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P c80e9e8e8cc1e7676d7c782ee0827726875db79e -R ff3e8c131dda72b26dbe6f001a80b515 +P 42f93f582eccd8a778189aa6c113874f995ab751 +R 475d6e7258921a9c57642e7cd0e82c9c U drh -Z 3e34cddbe64a99afb651902a91a49bea +Z 29a0c57d5a3080634424e9023a9fd1e9 diff --git a/manifest.uuid b/manifest.uuid index 62cf69b6e4..d483132b90 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -42f93f582eccd8a778189aa6c113874f995ab751 \ No newline at end of file +03375017691d5b480e73d712c4318632e835060c \ No newline at end of file diff --git a/src/where.c b/src/where.c index ad1eecd920..c78563f1c5 100644 --- a/src/where.c +++ b/src/where.c @@ -180,7 +180,7 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ while( pScan->iEquiv<=pScan->nEquiv ){ iCur = pScan->aiCur[pScan->iEquiv-1]; iColumn = pScan->aiColumn[pScan->iEquiv-1]; - assert( iColumn!=(-2) || pScan->pIdxExpr!=0 ); + if( iColumn==(-2) && pScan->pIdxExpr==0 ) return 0; while( (pWC = pScan->pWC)!=0 ){ for(pTerm=pWC->a+k; knTerm; k++, pTerm++){ if( pTerm->leftCursor==iCur @@ -804,6 +804,7 @@ static sqlite3_index_info *allocateIndexInfo( testcase( pTerm->eOperator & WO_ALL ); if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; + if( pTerm->u.leftColumn<(-1) ) continue; nTerm++; } @@ -859,6 +860,7 @@ static sqlite3_index_info *allocateIndexInfo( testcase( pTerm->eOperator & WO_ALL ); if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; + if( pTerm->u.leftColumn<(-1) ) continue; pIdxCons[j].iColumn = pTerm->u.leftColumn; pIdxCons[j].iTermOffset = i; op = (u8)pTerm->eOperator & WO_ALL; From c7c4680ffd727443c81c4b926e518b2552275d3f Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 27 Aug 2015 20:33:38 +0000 Subject: [PATCH 06/25] Fix EXPLAIN QUERY PLAN output for indexed-expressions. Fix another obscure fault in the WHERE term scanner. FossilOrigin-Name: 73d361ce9e4d72c943def8b0b3caa227f9199aed --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/where.c | 3 +-- src/wherecode.c | 18 +++++++++++++----- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/manifest b/manifest index 2a88bdcb4d..901fd70006 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sproblems\sin\sthe\sindexed-expression\shandling\sin\sthe\soptimizer. -D 2015-08-27T19:56:49.408 +C Fix\sEXPLAIN\sQUERY\sPLAN\soutput\sfor\sindexed-expressions.\s\sFix\sanother\nobscure\sfault\sin\sthe\sWHERE\sterm\sscanner. +D 2015-08-27T20:33:38.975 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in e2218eb228374422969de7b1680eda6864affcef F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -414,9 +414,9 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c 6fb6b68969e4692593c2552c4e7bff5882de2cb8 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 2e14d17f592d176b6dc879c33fbdec4fbccaa2ba -F src/where.c fcdded4bf274bf527020436e8895b33d575f18f6 +F src/where.c b22b416694905555a0cbbd7d8881179392a56aba F src/whereInt.h 292d3ac90da4eab1e03ac8452f1add746bcafaa1 -F src/wherecode.c 3d9113cc307ffeed58db41fe9f2d807c94787ab5 +F src/wherecode.c b0bf45ca49e62fde68ba2e2ad2939d9cdeb4e409 F src/whereexpr.c 990ed42b5940d4000e7e61887a4bbed412c80488 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd @@ -1380,7 +1380,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 42f93f582eccd8a778189aa6c113874f995ab751 -R 475d6e7258921a9c57642e7cd0e82c9c +P 03375017691d5b480e73d712c4318632e835060c +R 8aa1e38f792c255d32b6cb36a0f80565 U drh -Z 29a0c57d5a3080634424e9023a9fd1e9 +Z dc558ff8656aec58d6de7d38d850c48a diff --git a/manifest.uuid b/manifest.uuid index d483132b90..77236f721d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -03375017691d5b480e73d712c4318632e835060c \ No newline at end of file +73d361ce9e4d72c943def8b0b3caa227f9199aed \ No newline at end of file diff --git a/src/where.c b/src/where.c index c78563f1c5..8d26cd4b4d 100644 --- a/src/where.c +++ b/src/where.c @@ -191,10 +191,9 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ ){ if( (pTerm->eOperator & WO_EQUIV)!=0 && pScan->nEquivaiCur) + && (pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight))->op==TK_COLUMN ){ int j; - pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight); - assert( pX->op==TK_COLUMN ); for(j=0; jnEquiv; j++){ if( pScan->aiCur[j]==pX->iTable && pScan->aiColumn[j]==pX->iColumn ){ diff --git a/src/wherecode.c b/src/wherecode.c index e5c0b40b1a..0a9d7b35be 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -41,6 +41,16 @@ static void explainAppendTerm( sqlite3StrAccumAppend(pStr, "?", 1); } +/* +** Return the name of the i-th column of the pIdx index. +*/ +static const char *explainIndexColumnName(Index *pIdx, int i){ + i = pIdx->aiColumn[i]; + if( i==(-2) ) return ""; + if( i==(-1) ) return "rowid"; + return pIdx->pTable->aCol[i].zName; +} + /* ** Argument pLevel describes a strategy for scanning table pTab. This ** function appends text to pStr that describes the subset of table @@ -60,13 +70,11 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){ u16 nEq = pLoop->u.btree.nEq; u16 nSkip = pLoop->nSkip; int i, j; - Column *aCol = pTab->aCol; - i16 *aiColumn = pIndex->aiColumn; if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return; sqlite3StrAccumAppend(pStr, " (", 2); for(i=0; i=nSkip ){ explainAppendTerm(pStr, i, z, "="); }else{ @@ -77,11 +85,11 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){ j = i; if( pLoop->wsFlags&WHERE_BTM_LIMIT ){ - char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName; + const char *z = explainIndexColumnName(pIndex, i); explainAppendTerm(pStr, i++, z, ">"); } if( pLoop->wsFlags&WHERE_TOP_LIMIT ){ - char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName; + const char *z = explainIndexColumnName(pIndex, j); explainAppendTerm(pStr, i, z, "<"); } sqlite3StrAccumAppend(pStr, ")", 1); From 47991425cb67375e341d5c8179f14a47e2c1188d Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 31 Aug 2015 15:58:06 +0000 Subject: [PATCH 07/25] Improved analysis and usage of indexed expressions in the query planner. FossilOrigin-Name: f8893696387cba9d293a05a68dc38228077b3dc5 --- manifest | 15 +++++----- manifest.uuid | 2 +- src/where.c | 26 +++++++---------- src/whereexpr.c | 66 ++++++++++++++++++++++++++++++++++++-------- test/indexexpr1.test | 45 ++++++++++++++++++++++++++++++ 5 files changed, 118 insertions(+), 36 deletions(-) create mode 100644 test/indexexpr1.test diff --git a/manifest b/manifest index 5612003055..64b3dc444a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sthe\slatest\senhancements\sfrom\strunk. -D 2015-08-31T14:27:29.928 +C Improved\sanalysis\sand\susage\sof\sindexed\sexpressions\sin\sthe\squery\splanner. +D 2015-08-31T15:58:06.350 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -414,10 +414,10 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c 8cd07f1f99e1a81346db1c9da879bef6c6f97cf6 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 2e14d17f592d176b6dc879c33fbdec4fbccaa2ba -F src/where.c acec45dc602a4f58e80e6fa088b9379ccfffd3a4 +F src/where.c 385f927f06a89d06de6a4ce7627fbd1684f157bb F src/whereInt.h 292d3ac90da4eab1e03ac8452f1add746bcafaa1 F src/wherecode.c b0bf45ca49e62fde68ba2e2ad2939d9cdeb4e409 -F src/whereexpr.c 990ed42b5940d4000e7e61887a4bbed412c80488 +F src/whereexpr.c 2473e4350e30f9b55d1c6a8f66ca23c689f23f1d F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -780,6 +780,7 @@ F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7 F test/index6.test 7102ec371414c42dfb1d5ca37eb4519aa9edc23a F test/index7.test 9c6765a74fc3fcde7aebc5b3bd40d98df14a527c F test/indexedby.test 5f527a78bae74c61b8046ae3037f9dfb0bf0c353 +F test/indexexpr1.test 36b7aab1fdb03710b99ee876ff764b92c7b96e3e F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7 F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371 @@ -1380,7 +1381,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P cf452028d1be2c5578a07f6e21b4d8b613373eb8 1da60c3dda4254620052a83c853c2d2b6dd5009f -R 64522485917d5b93eb19dc63143d2895 +P 7bde6d4d8cf05e1beb9bdf20b85760dc3e7a76c9 +R b7744e5a00368fcccd1913a83a0521e8 U drh -Z 590b51e0f03c976eccd82950be2fb3fc +Z 32945199df036dc2360847bdab3537ac diff --git a/manifest.uuid b/manifest.uuid index a7185b1794..327673b19f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7bde6d4d8cf05e1beb9bdf20b85760dc3e7a76c9 \ No newline at end of file +f8893696387cba9d293a05a68dc38228077b3dc5 \ No newline at end of file diff --git a/src/where.c b/src/where.c index ef92523a44..f39afb7e3a 100644 --- a/src/where.c +++ b/src/where.c @@ -4050,14 +4050,12 @@ WhereInfo *sqlite3WhereBegin( /* Assign a bit from the bitmask to every term in the FROM clause. ** - ** When assigning bitmask values to FROM clause cursors, it must be - ** the case that if X is the bitmask for the N-th FROM clause term then - ** the bitmask for all FROM clause terms to the left of the N-th term - ** is (X-1). An expression from the ON clause of a LEFT JOIN can use - ** its Expr.iRightJoinTable value to find the bitmask of the right table - ** of the join. Subtracting one from the right table bitmask gives a - ** bitmask for all tables to the left of the join. Knowing the bitmask - ** for all tables to the left of a left join is important. Ticket #3015. + ** The N-th term of the FROM clause is assigned a bitmask of 1<nSrc tables in ** pTabList, not just the first nTabList tables. nTabList is normally @@ -4068,14 +4066,10 @@ WhereInfo *sqlite3WhereBegin( createMask(pMaskSet, pTabList->a[ii].iCursor); sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC); } -#ifndef NDEBUG - { - Bitmask toTheLeft = 0; - for(ii=0; iinSrc; ii++){ - Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor); - assert( (m-1)==toTheLeft ); - toTheLeft |= m; - } +#ifdef SQLITE_DEBUG + for(ii=0; iinSrc; ii++){ + Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor); + assert( m==MASKBIT(ii) ); } #endif diff --git a/src/whereexpr.c b/src/whereexpr.c index 631a7e0dce..dff425d0ea 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -795,6 +795,51 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){ return mask; } +/* +** Expression pExpr is one operand of a comparison operator that might +** be useful for indexing. This routine checks to see if pExpr appears +** in any index. Return TRUE (1) if pExpr is an indexed term and return +** FALSE (0) if not. If TRUE is returned, also set *piCur to the cursor +** number of the table that is indexed and *piColumn to the column number +** of the column that is indexed, or -2 if an expression is being indexed. +** +** If pExpr is a TK_COLUMN column reference, then this routine always returns +** true even if that particular column is not indexed, because the column +** might be added to an automatic index later. +*/ +static int exprMightBeIndexed( + SrcList *pFrom, /* The FROM clause */ + Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */ + Expr *pExpr, /* An operand of a comparison operator */ + int *piCur, /* Write the referenced table cursor number here */ + int *piColumn /* Write the referenced table column number here */ +){ + Index *pIdx; + int i; + int iCur; + if( pExpr->op==TK_COLUMN ){ + *piCur = pExpr->iTable; + *piColumn = pExpr->iColumn; + return 1; + } + if( mPrereq==0 ) return 0; /* No table references */ + if( (mPrereq&(mPrereq-1))!=0 ) return 0; /* Refs more than one table */ + for(i=0; mPrereq>1; i++, mPrereq>>=1){} + iCur = pFrom->a[i].iCursor; + for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + if( pIdx->aColExpr==0 ) continue; + for(i=0; inKeyCol; i++){ + if( pIdx->aiColumn[i]!=(-2) ) continue; + if( sqlite3ExprCompare(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){ + *piCur = iCur; + *piColumn = -2; + return 1; + } + } + } + return 0; +} + /* ** The input to this routine is an WhereTerm structure with only the ** "pExpr" field filled in. The job of this routine is to analyze the @@ -865,22 +910,19 @@ static void exprAnalyze( pTerm->iParent = -1; pTerm->eOperator = 0; if( allowedOp(op) ){ + int iCur, iColumn; Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft); Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight); u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV; - if( pLeft->op==TK_COLUMN ){ - pTerm->leftCursor = pLeft->iTable; - pTerm->u.leftColumn = pLeft->iColumn; - pTerm->eOperator = operatorMask(op) & opMask; - }else if( prereqLeft!=0 && (prereqLeft&(prereqLeft-1))==0 ){ - int i; - for(i=0; (prereqLeft>>i)<1; i++){} - pTerm->leftCursor = pMaskSet->ix[i]; - pTerm->u.leftColumn = -2; + if( exprMightBeIndexed(pSrc, prereqLeft, pLeft, &iCur, &iColumn) ){ + pTerm->leftCursor = iCur; + pTerm->u.leftColumn = iColumn; pTerm->eOperator = operatorMask(op) & opMask; } if( op==TK_IS ) pTerm->wtFlags |= TERM_IS; - if( pRight && pRight->op==TK_COLUMN ){ + if( pRight + && exprMightBeIndexed(pSrc, pTerm->prereqRight, pRight, &iCur, &iColumn) + ){ WhereTerm *pNew; Expr *pDup; u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */ @@ -909,8 +951,8 @@ static void exprAnalyze( } exprCommute(pParse, pDup); pLeft = sqlite3ExprSkipCollate(pDup->pLeft); - pNew->leftCursor = pLeft->iTable; - pNew->u.leftColumn = pLeft->iColumn; + pNew->leftCursor = iCur; + pNew->u.leftColumn = iColumn; testcase( (prereqLeft | extraRight) != prereqLeft ); pNew->prereqRight = prereqLeft | extraRight; pNew->prereqAll = prereqAll; diff --git a/test/indexexpr1.test b/test/indexexpr1.test new file mode 100644 index 0000000000..c912226ce5 --- /dev/null +++ b/test/indexexpr1.test @@ -0,0 +1,45 @@ +# 2015-08-31 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing indexes on expressions. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_execsql_test indexexpr1-100 { + CREATE TABLE t1(a,b,c); + INSERT INTO t1(a,b,c) + VALUES('In the beginning was the Word',1,1), + ('and the Word was with God',1,2), + ('and the Word was God',1,3), + ('The same was in the beginning with God',2,1), + ('All things were made by him',3,1), + ('and without him was not any thing made that was made',3,2); + CREATE INDEX t1a1 ON t1(substr(a,1,12)); +} {} +do_execsql_test indexexpr1-110 { + SELECT b, c, '|' FROM t1 WHERE substr(a,1,12)=='and the Word' ORDER BY b, c; +} {1 2 | 1 3 |} +do_execsql_test indexexpr1-110eqp { + EXPLAIN QUERY PLAN + SELECT b, c, '|' FROM t1 WHERE substr(a,1,12)=='and the Word' ORDER BY b, c; +} {/USING INDEX t1a1/} +do_execsql_test indexexpr1-120 { + SELECT b, c, '|' FROM t1 WHERE 'and the Word'==substr(a,1,12) ORDER BY b, c; +} {1 2 | 1 3 |} +do_execsql_test indexexpr1-120eqp { + EXPLAIN QUERY PLAN + SELECT b, c, '|' FROM t1 WHERE 'and the Word'==substr(a,1,12) ORDER BY b, c; +} {/USING INDEX t1a1/} + + +finish_test From 1d85e405e6c7674d0df4d4a720ceaeb47273b9ba Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 31 Aug 2015 17:34:41 +0000 Subject: [PATCH 08/25] Make the distinction between truly deterministic functions and date/time functions which only return the same answer for a single query. Only truly deterministic functions are allowed in indexes. Add new expression index test cases. FossilOrigin-Name: c77554b5c42327106a7b90334e9cc3c07b007c76 --- manifest | 18 +++---- manifest.uuid | 2 +- src/date.c | 16 +++--- src/resolve.c | 10 +++- src/sqliteInt.h | 34 +++++++----- test/indexexpr1.test | 123 +++++++++++++++++++++++++++++++++++++++---- 6 files changed, 160 insertions(+), 43 deletions(-) diff --git a/manifest b/manifest index 64b3dc444a..bcc1d9de6b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\sanalysis\sand\susage\sof\sindexed\sexpressions\sin\sthe\squery\splanner. -D 2015-08-31T15:58:06.350 +C Make\sthe\sdistinction\sbetween\struly\sdeterministic\sfunctions\sand\sdate/time\nfunctions\swhich\sonly\sreturn\sthe\ssame\sanswer\sfor\sa\ssingle\squery.\s\sOnly\struly\ndeterministic\sfunctions\sare\sallowed\sin\sindexes.\s\sAdd\snew\sexpression\sindex\ntest\scases. +D 2015-08-31T17:34:41.308 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -286,7 +286,7 @@ F src/build.c e0902658fc86dbd60a5c6772ca45429c69ee81fe F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b -F src/date.c 8ec787fed4929d8ccdf6b1bc360fccc3e1d2ca58 +F src/date.c fb1c99172017dcc8e237339132c91a21a0788584 F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a F src/delete.c 224e5c9a0eae7fbdd3b461ca971465c992851354 F src/expr.c cf0c5ef6467d3eb65e3ff5c88eb2f602ba3b5163 @@ -335,14 +335,14 @@ F src/pragma.h 631a91c8b0e6ca8f051a1d8a4a0da4150e04620a F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1 F src/printf.c 2bc439ff20a4aad0e0ad50a37a67b5eae7d20edc F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 -F src/resolve.c e6dc5a5490cf93afc1cc2cb58280c98da56acb3c +F src/resolve.c 3ec6456a534bcbf0f3fc11ad83c6208301db60a2 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c b52c80f2b1bdb62491f9ce40eea0c5f80c78d105 F src/shell.c 6332ef06db1390ef812cfdff1fc97b4fd76cdd42 F src/sqlite.h.in 378bebc8fe6a88bade25e5f23b7e6123fdc64b00 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h f700e6a9dd1fdcccc9951ab022b366fb66b9e413 -F src/sqliteInt.h 340fc115a707838ad365b52057f126b143f6aa60 +F src/sqliteInt.h 332ae4f753d91c92421a2c4227c195298d5b154c F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e @@ -780,7 +780,7 @@ F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7 F test/index6.test 7102ec371414c42dfb1d5ca37eb4519aa9edc23a F test/index7.test 9c6765a74fc3fcde7aebc5b3bd40d98df14a527c F test/indexedby.test 5f527a78bae74c61b8046ae3037f9dfb0bf0c353 -F test/indexexpr1.test 36b7aab1fdb03710b99ee876ff764b92c7b96e3e +F test/indexexpr1.test 1e57b4bb93b65a451803e7547a51f685af1c35db F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7 F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371 @@ -1381,7 +1381,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 7bde6d4d8cf05e1beb9bdf20b85760dc3e7a76c9 -R b7744e5a00368fcccd1913a83a0521e8 +P f8893696387cba9d293a05a68dc38228077b3dc5 +R 73b6719fd207957d3d30c3e1b6c218bc U drh -Z 32945199df036dc2360847bdab3537ac +Z fe2263cb4a747333f78b4cc6eb661f66 diff --git a/manifest.uuid b/manifest.uuid index 327673b19f..3dc8f017b9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f8893696387cba9d293a05a68dc38228077b3dc5 \ No newline at end of file +c77554b5c42327106a7b90334e9cc3c07b007c76 \ No newline at end of file diff --git a/src/date.c b/src/date.c index 6b11d9904a..8a66eae900 100644 --- a/src/date.c +++ b/src/date.c @@ -1115,14 +1115,14 @@ static void currentTimeFunc( void sqlite3RegisterDateTimeFunctions(void){ static SQLITE_WSD FuncDef aDateTimeFuncs[] = { #ifndef SQLITE_OMIT_DATETIME_FUNCS - FUNCTION(julianday, -1, 0, 0, juliandayFunc ), - FUNCTION(date, -1, 0, 0, dateFunc ), - FUNCTION(time, -1, 0, 0, timeFunc ), - FUNCTION(datetime, -1, 0, 0, datetimeFunc ), - FUNCTION(strftime, -1, 0, 0, strftimeFunc ), - FUNCTION(current_time, 0, 0, 0, ctimeFunc ), - FUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc), - FUNCTION(current_date, 0, 0, 0, cdateFunc ), + DFUNCTION(julianday, -1, 0, 0, juliandayFunc ), + DFUNCTION(date, -1, 0, 0, dateFunc ), + DFUNCTION(time, -1, 0, 0, timeFunc ), + DFUNCTION(datetime, -1, 0, 0, datetimeFunc ), + DFUNCTION(strftime, -1, 0, 0, strftimeFunc ), + DFUNCTION(current_time, 0, 0, 0, ctimeFunc ), + DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc), + DFUNCTION(current_date, 0, 0, 0, cdateFunc ), #else STR_FUNCTION(current_time, 0, "%H:%M:%S", 0, currentTimeFunc), STR_FUNCTION(current_date, 0, "%Y-%m-%d", 0, currentTimeFunc), diff --git a/src/resolve.c b/src/resolve.c index eb43396454..0b8dde7cc6 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -732,9 +732,15 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ return WRC_Prune; } #endif - if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ){ + if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_DATETIME) ){ + /* For the purposes of the EP_ConstFunc flag, date and time + ** functions are considered constant because the the time does + ** not change for the duration of a query. */ ExprSetProperty(pExpr,EP_ConstFunc); - }else{ + } + if( (pDef->funcFlags & SQLITE_FUNC_CONSTANT)==0 ){ + /* DATETIME functions are considered non-deterministic because of + ** the 'now' capability */ notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr, 0); } } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 69f98da26d..613f351aa5 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1384,18 +1384,19 @@ struct FuncDestructor { ** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG. There ** are assert() statements in the code to verify this. */ -#define SQLITE_FUNC_ENCMASK 0x003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */ -#define SQLITE_FUNC_LIKE 0x004 /* Candidate for the LIKE optimization */ -#define SQLITE_FUNC_CASE 0x008 /* Case-sensitive LIKE-type function */ -#define SQLITE_FUNC_EPHEM 0x010 /* Ephemeral. Delete with VDBE */ -#define SQLITE_FUNC_NEEDCOLL 0x020 /* sqlite3GetFuncCollSeq() might be called */ -#define SQLITE_FUNC_LENGTH 0x040 /* Built-in length() function */ -#define SQLITE_FUNC_TYPEOF 0x080 /* Built-in typeof() function */ -#define SQLITE_FUNC_COUNT 0x100 /* Built-in count(*) aggregate */ -#define SQLITE_FUNC_COALESCE 0x200 /* Built-in coalesce() or ifnull() */ -#define SQLITE_FUNC_UNLIKELY 0x400 /* Built-in unlikely() function */ -#define SQLITE_FUNC_CONSTANT 0x800 /* Constant inputs give a constant output */ -#define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */ +#define SQLITE_FUNC_ENCMASK 0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */ +#define SQLITE_FUNC_LIKE 0x0004 /* Candidate for the LIKE optimization */ +#define SQLITE_FUNC_CASE 0x0008 /* Case-sensitive LIKE-type function */ +#define SQLITE_FUNC_EPHEM 0x0010 /* Ephemeral. Delete with VDBE */ +#define SQLITE_FUNC_NEEDCOLL 0x0020 /* sqlite3GetFuncCollSeq() might be called*/ +#define SQLITE_FUNC_LENGTH 0x0040 /* Built-in length() function */ +#define SQLITE_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */ +#define SQLITE_FUNC_COUNT 0x0100 /* Built-in count(*) aggregate */ +#define SQLITE_FUNC_COALESCE 0x0200 /* Built-in coalesce() or ifnull() */ +#define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */ +#define SQLITE_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */ +#define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */ +#define SQLITE_FUNC_DATETIME 0x2000 /* Function returns a date and/or time */ /* ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are @@ -1411,6 +1412,10 @@ struct FuncDestructor { ** VFUNCTION(zName, nArg, iArg, bNC, xFunc) ** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag. ** +** DFUNCTION(zName, nArg, iArg, bNC, xFunc) +** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and +** adds the SQLITE_FUNC_DATETIME flag. Used for date & time functions. +** ** AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal) ** Used to create an aggregate function definition implemented by ** the C functions xStep and xFinal. The first four parameters @@ -1431,6 +1436,9 @@ struct FuncDestructor { #define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \ {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0} +#define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \ + {nArg, SQLITE_FUNC_DATETIME|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ + SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0} #define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \ {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0} @@ -2121,7 +2129,7 @@ struct Expr { #define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */ #define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */ #define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */ -#define EP_ConstFunc 0x080000 /* Node is a SQLITE_FUNC_CONSTANT function */ +#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _DATETIME function */ #define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */ #define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */ diff --git a/test/indexexpr1.test b/test/indexexpr1.test index c912226ce5..0b3e7c6603 100644 --- a/test/indexexpr1.test +++ b/test/indexexpr1.test @@ -18,28 +18,131 @@ source $testdir/tester.tcl do_execsql_test indexexpr1-100 { CREATE TABLE t1(a,b,c); INSERT INTO t1(a,b,c) - VALUES('In the beginning was the Word',1,1), - ('and the Word was with God',1,2), - ('and the Word was God',1,3), - ('The same was in the beginning with God',2,1), - ('All things were made by him',3,1), - ('and without him was not any thing made that was made',3,2); + VALUES('In_the_beginning_was_the_Word',1,1), + ('and_the_Word_was_with_God',1,2), + ('and_the_Word_was_God',1,3), + ('The_same_was_in_the_beginning_with_God',2,1), + ('All_things_were_made_by_him',3,1), + ('and_without_him_was_not_any_thing_made_that_was_made',3,2); CREATE INDEX t1a1 ON t1(substr(a,1,12)); } {} do_execsql_test indexexpr1-110 { - SELECT b, c, '|' FROM t1 WHERE substr(a,1,12)=='and the Word' ORDER BY b, c; + SELECT b, c, '|' FROM t1 WHERE substr(a,1,12)=='and_the_Word' ORDER BY b, c; } {1 2 | 1 3 |} do_execsql_test indexexpr1-110eqp { EXPLAIN QUERY PLAN - SELECT b, c, '|' FROM t1 WHERE substr(a,1,12)=='and the Word' ORDER BY b, c; + SELECT b, c, '|' FROM t1 WHERE substr(a,1,12)=='and_the_Word' ORDER BY b, c; } {/USING INDEX t1a1/} do_execsql_test indexexpr1-120 { - SELECT b, c, '|' FROM t1 WHERE 'and the Word'==substr(a,1,12) ORDER BY b, c; + SELECT b, c, '|' FROM t1 WHERE 'and_the_Word'==substr(a,1,12) ORDER BY b, c; } {1 2 | 1 3 |} do_execsql_test indexexpr1-120eqp { EXPLAIN QUERY PLAN - SELECT b, c, '|' FROM t1 WHERE 'and the Word'==substr(a,1,12) ORDER BY b, c; + SELECT b, c, '|' FROM t1 WHERE 'and_the_Word'==substr(a,1,12) ORDER BY b, c; } {/USING INDEX t1a1/} +do_execsql_test indexexpr1-130 { + CREATE INDEX t1ba ON t1(b,substr(a,2,3),c); + SELECT c FROM t1 WHERE b=1 AND substr(a,2,3)='nd_' ORDER BY c; +} {2 3} +do_execsql_test indexexpr1-130eqp { + EXPLAIN QUERY PLAN + SELECT c FROM t1 WHERE b=1 AND substr(a,2,3)='nd_' ORDER BY c; +} {/USING INDEX t1ba/} + +do_execsql_test indexexpr1-140 { + SELECT rowid, substr(a,b,3), '|' FROM t1 ORDER BY 2; +} {1 In_ | 2 and | 3 and | 6 d_w | 4 he_ | 5 l_t |} +do_execsql_test indexexpr1-141 { + CREATE INDEX t1abx ON t1(substr(a,b,3)); + SELECT rowid FROM t1 WHERE substr(a,b,3)<='and' ORDER BY +rowid; +} {1 2 3} +do_execsql_test indexexpr1-141eqp { + EXPLAIN QUERY PLAN + SELECT rowid FROM t1 WHERE substr(a,b,3)<='and' ORDER BY +rowid; +} {/USING INDEX t1abx/} +do_execsql_test indexexpr1-142 { + SELECT rowid FROM t1 WHERE +substr(a,b,3)<='and' ORDER BY +rowid; +} {1 2 3} +do_execsql_test indexexpr1-150 { + SELECT rowid FROM t1 WHERE substr(a,b,3) IN ('and','l_t','xyz') + ORDER BY +rowid; +} {2 3 5} +do_execsql_test indexexpr1-150eqp { + EXPLAIN QUERY PLAN + SELECT rowid FROM t1 WHERE substr(a,b,3) IN ('and','l_t','xyz') + ORDER BY +rowid; +} {/USING INDEX t1abx/} + +do_execsql_test indexexpr1-200 { + DROP TABLE t1; + CREATE TABLE t1(id ANY PRIMARY KEY, a,b,c) WITHOUT ROWID; + INSERT INTO t1(id,a,b,c) + VALUES(1,'In_the_beginning_was_the_Word',1,1), + (2,'and_the_Word_was_with_God',1,2), + (3,'and_the_Word_was_God',1,3), + (4,'The_same_was_in_the_beginning_with_God',2,1), + (5,'All_things_were_made_by_him',3,1), + (6,'and_without_him_was_not_any_thing_made_that_was_made',3,2); + CREATE INDEX t1a1 ON t1(substr(a,1,12)); +} {} +do_execsql_test indexexpr1-210 { + SELECT b, c, '|' FROM t1 WHERE substr(a,1,12)=='and_the_Word' ORDER BY b, c; +} {1 2 | 1 3 |} +do_execsql_test indexexpr1-210eqp { + EXPLAIN QUERY PLAN + SELECT b, c, '|' FROM t1 WHERE substr(a,1,12)=='and_the_Word' ORDER BY b, c; +} {/USING INDEX t1a1/} +do_execsql_test indexexpr1-220 { + SELECT b, c, '|' FROM t1 WHERE 'and_the_Word'==substr(a,1,12) ORDER BY b, c; +} {1 2 | 1 3 |} +do_execsql_test indexexpr1-220eqp { + EXPLAIN QUERY PLAN + SELECT b, c, '|' FROM t1 WHERE 'and_the_Word'==substr(a,1,12) ORDER BY b, c; +} {/USING INDEX t1a1/} + +do_execsql_test indexexpr1-230 { + CREATE INDEX t1ba ON t1(b,substr(a,2,3),c); + SELECT c FROM t1 WHERE b=1 AND substr(a,2,3)='nd_' ORDER BY c; +} {2 3} +do_execsql_test indexexpr1-230eqp { + EXPLAIN QUERY PLAN + SELECT c FROM t1 WHERE b=1 AND substr(a,2,3)='nd_' ORDER BY c; +} {/USING INDEX t1ba/} + +do_execsql_test indexexpr1-240 { + SELECT id, substr(a,b,3), '|' FROM t1 ORDER BY 2; +} {1 In_ | 2 and | 3 and | 6 d_w | 4 he_ | 5 l_t |} +do_execsql_test indexexpr1-241 { + CREATE INDEX t1abx ON t1(substr(a,b,3)); + SELECT id FROM t1 WHERE substr(a,b,3)<='and' ORDER BY +id; +} {1 2 3} +do_execsql_test indexexpr1-241eqp { + EXPLAIN QUERY PLAN + SELECT id FROM t1 WHERE substr(a,b,3)<='and' ORDER BY +id; +} {/USING INDEX t1abx/} +do_execsql_test indexexpr1-242 { + SELECT id FROM t1 WHERE +substr(a,b,3)<='and' ORDER BY +id; +} {1 2 3} +do_execsql_test indexexpr1-250 { + SELECT id FROM t1 WHERE substr(a,b,3) IN ('and','l_t','xyz') + ORDER BY +id; +} {2 3 5} +do_execsql_test indexexpr1-250eqp { + EXPLAIN QUERY PLAN + SELECT id FROM t1 WHERE substr(a,b,3) IN ('and','l_t','xyz') + ORDER BY +id; +} {/USING INDEX t1abx/} + +do_catchsql_test indexexpr1-300 { + CREATE TABLE t2(a,b,c); + CREATE INDEX t2x1 ON t2(a,b+random()); +} {1 {non-deterministic functions prohibited in index expressions}} +do_catchsql_test indexexpr1-301 { + CREATE INDEX t2x1 ON t2(a+julianday('now')); +} {1 {non-deterministic functions prohibited in index expressions}} +do_catchsql_test indexexpr1-310 { + CREATE INDEX t2x2 ON t2(a,b+(SELECT 15)); +} {1 {subqueries prohibited in index expressions}} finish_test From 390b88a448d219a25498a2cdb379f45a914b006d Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 31 Aug 2015 18:13:01 +0000 Subject: [PATCH 09/25] Case should not be significant when comparing function names. FossilOrigin-Name: e2f1caf117b0a9632d52246717ab202852982339 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/expr.c | 4 +++- test/indexexpr1.test | 41 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index bcc1d9de6b..3215993778 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Make\sthe\sdistinction\sbetween\struly\sdeterministic\sfunctions\sand\sdate/time\nfunctions\swhich\sonly\sreturn\sthe\ssame\sanswer\sfor\sa\ssingle\squery.\s\sOnly\struly\ndeterministic\sfunctions\sare\sallowed\sin\sindexes.\s\sAdd\snew\sexpression\sindex\ntest\scases. -D 2015-08-31T17:34:41.308 +C Case\sshould\snot\sbe\ssignificant\swhen\scomparing\sfunction\snames. +D 2015-08-31T18:13:01.161 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -289,7 +289,7 @@ F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b F src/date.c fb1c99172017dcc8e237339132c91a21a0788584 F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a F src/delete.c 224e5c9a0eae7fbdd3b461ca971465c992851354 -F src/expr.c cf0c5ef6467d3eb65e3ff5c88eb2f602ba3b5163 +F src/expr.c 500c0ee6ac2e5d60c10df62b8c9b96dc75c2cbb1 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 3ce33dd49f12c72376cec9adc7a4d8e7111cedcc F src/func.c 824bea430d3a2b7dbc62806ad54da8fdb8ed9e3f @@ -780,7 +780,7 @@ F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7 F test/index6.test 7102ec371414c42dfb1d5ca37eb4519aa9edc23a F test/index7.test 9c6765a74fc3fcde7aebc5b3bd40d98df14a527c F test/indexedby.test 5f527a78bae74c61b8046ae3037f9dfb0bf0c353 -F test/indexexpr1.test 1e57b4bb93b65a451803e7547a51f685af1c35db +F test/indexexpr1.test d04a3905275fb9a0fb82447e7d43773f98fad282 F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7 F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371 @@ -1381,7 +1381,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P f8893696387cba9d293a05a68dc38228077b3dc5 -R 73b6719fd207957d3d30c3e1b6c218bc +P c77554b5c42327106a7b90334e9cc3c07b007c76 +R 0c8c1c66a00ef8c41547d29bee27b359 U drh -Z fe2263cb4a747333f78b4cc6eb661f66 +Z 0525f466a18434624bccbe0dbed916be diff --git a/manifest.uuid b/manifest.uuid index 3dc8f017b9..51f3249ab6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c77554b5c42327106a7b90334e9cc3c07b007c76 \ No newline at end of file +e2f1caf117b0a9632d52246717ab202852982339 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 9ae611ba7c..ee3fb1a940 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3788,7 +3788,9 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){ return 2; } if( pA->op!=TK_COLUMN && ALWAYS(pA->op!=TK_AGG_COLUMN) && pA->u.zToken ){ - if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ + if( pA->op==TK_FUNCTION ){ + if( sqlite3StrICmp(pA->u.zToken,pB->u.zToken)!=0 ) return 2; + }else if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){ return pA->op==TK_COLLATE ? 1 : 2; } } diff --git a/test/indexexpr1.test b/test/indexexpr1.test index 0b3e7c6603..aa056e55d4 100644 --- a/test/indexexpr1.test +++ b/test/indexexpr1.test @@ -18,6 +18,7 @@ source $testdir/tester.tcl do_execsql_test indexexpr1-100 { CREATE TABLE t1(a,b,c); INSERT INTO t1(a,b,c) + /* 123456789 123456789 123456789 123456789 123456789 123456789 */ VALUES('In_the_beginning_was_the_Word',1,1), ('and_the_Word_was_with_God',1,2), ('and_the_Word_was_God',1,3), @@ -74,6 +75,20 @@ do_execsql_test indexexpr1-150eqp { ORDER BY +rowid; } {/USING INDEX t1abx/} +do_execsql_test indexexpr1-160 { + ALTER TABLE t1 ADD COLUMN d; + UPDATE t1 SET d=length(a); + CREATE INDEX t1a2 ON t1(SUBSTR(a, 27, 3)) WHERE d>=29; + SELECT rowid, b, c FROM t1 + WHERE substr(a,27,3)=='ord' AND d>=29; +} {1 1 1} +do_execsql_test indexexpr1-160eqp { + EXPLAIN QUERY PLAN + SELECT rowid, b, c FROM t1 + WHERE substr(a,27,3)=='ord' AND d>=29; +} {/USING INDEX t1a2/} + + do_execsql_test indexexpr1-200 { DROP TABLE t1; CREATE TABLE t1(id ANY PRIMARY KEY, a,b,c) WITHOUT ROWID; @@ -134,6 +149,20 @@ do_execsql_test indexexpr1-250eqp { ORDER BY +id; } {/USING INDEX t1abx/} +do_execsql_test indexexpr1-260 { + ALTER TABLE t1 ADD COLUMN d; + UPDATE t1 SET d=length(a); + CREATE INDEX t1a2 ON t1(SUBSTR(a, 27, 3)) WHERE d>=29; + SELECT id, b, c FROM t1 + WHERE substr(a,27,3)=='ord' AND d>=29; +} {1 1 1} +do_execsql_test indexexpr1-260eqp { + EXPLAIN QUERY PLAN + SELECT id, b, c FROM t1 + WHERE substr(a,27,3)=='ord' AND d>=29; +} {/USING INDEX t1a2/} + + do_catchsql_test indexexpr1-300 { CREATE TABLE t2(a,b,c); CREATE INDEX t2x1 ON t2(a,b+random()); @@ -144,5 +173,17 @@ do_catchsql_test indexexpr1-301 { do_catchsql_test indexexpr1-310 { CREATE INDEX t2x2 ON t2(a,b+(SELECT 15)); } {1 {subqueries prohibited in index expressions}} +do_catchsql_test indexexpr1-320 { + CREATE TABLE e1(x,y,UNIQUE(y,substr(x,1,5))); +} {1 {expressions prohibited in PRIMARY KEY and UNIQUE constraints}} +do_catchsql_test indexexpr1-330 { + CREATE TABLE e1(x,y,PRIMARY KEY(y,substr(x,1,5))); +} {1 {expressions prohibited in PRIMARY KEY and UNIQUE constraints}} +do_catchsql_test indexexpr1-331 { + CREATE TABLE e1(x,y,PRIMARY KEY(y,substr(x,1,5))) WITHOUT ROWID; +} {1 {expressions prohibited in PRIMARY KEY and UNIQUE constraints}} +do_catchsql_test indexexpr1-340 { + CREATE TABLE e1(x,y,FOREIGN KEY(substr(y,1,5)) REFERENCES t1); +} {1 {near "(": syntax error}} finish_test From 8492653c37795ec45673d22ee8bb5e8b3e848653 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 31 Aug 2015 19:38:42 +0000 Subject: [PATCH 10/25] Always assume that indexed expressions can generate a NULL. Get indexed expressions working for the case of two or more expressions in the same index. FossilOrigin-Name: cc60321a67bf9f169c090b47afb505f589a6925e --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/build.c | 11 +++++++---- src/where.c | 2 +- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index 3215993778..392a86929f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Case\sshould\snot\sbe\ssignificant\swhen\scomparing\sfunction\snames. -D 2015-08-31T18:13:01.161 +C Always\sassume\sthat\sindexed\sexpressions\scan\sgenerate\sa\sNULL.\s\sGet\nindexed\sexpressions\sworking\sfor\sthe\scase\sof\stwo\sor\smore\sexpressions\sin\nthe\ssame\sindex. +D 2015-08-31T19:38:42.715 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -282,7 +282,7 @@ F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79 F src/btree.c f48b3ef91676c06a90a8832987ecef6b94c931ee F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1 F src/btreeInt.h 8177c9ab90d772d6d2c6c517e05bed774b7c92c0 -F src/build.c e0902658fc86dbd60a5c6772ca45429c69ee81fe +F src/build.c 9e7216acaf612d371c1b4a6bf9711886472f7ac6 F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b @@ -414,7 +414,7 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c 8cd07f1f99e1a81346db1c9da879bef6c6f97cf6 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 2e14d17f592d176b6dc879c33fbdec4fbccaa2ba -F src/where.c 385f927f06a89d06de6a4ce7627fbd1684f157bb +F src/where.c 04e0f87e4d82a85c283176958465bed6ea5434e0 F src/whereInt.h 292d3ac90da4eab1e03ac8452f1add746bcafaa1 F src/wherecode.c b0bf45ca49e62fde68ba2e2ad2939d9cdeb4e409 F src/whereexpr.c 2473e4350e30f9b55d1c6a8f66ca23c689f23f1d @@ -1381,7 +1381,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P c77554b5c42327106a7b90334e9cc3c07b007c76 -R 0c8c1c66a00ef8c41547d29bee27b359 +P e2f1caf117b0a9632d52246717ab202852982339 +R 9a8972907f2a35dc9161585e1e0d88b8 U drh -Z 0525f466a18434624bccbe0dbed916be +Z 7baf4f251bc37ea5f508ac4ed0b603b4 diff --git a/manifest.uuid b/manifest.uuid index 51f3249ab6..693f9f59dd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e2f1caf117b0a9632d52246717ab202852982339 \ No newline at end of file +cc60321a67bf9f169c090b47afb505f589a6925e \ No newline at end of file diff --git a/src/build.c b/src/build.c index 59c2a73021..f217ab251a 100644 --- a/src/build.c +++ b/src/build.c @@ -3126,13 +3126,16 @@ Index *sqlite3CreateIndex( goto exit_create_index; } if( pIndex->aColExpr==0 ){ - pIndex->aColExpr = sqlite3ExprListDup(db, pList, 0); + ExprList *pCopy = sqlite3ExprListDup(db, pList, 0); + pIndex->aColExpr = pCopy; + if( !db->mallocFailed ){ + assert( pCopy!=0 ); + pListItem = &pCopy->a[i]; + } } j = -2; pIndex->aiColumn[i] = -2; - if( sqlite3ExprCanBeNull(pList->a[i].pExpr) ){ - pIndex->uniqNotNull = 1; - } + pIndex->uniqNotNull = 0; }else{ j = pCExpr->iColumn; assert( j<=0x7fff ); diff --git a/src/where.c b/src/where.c index f39afb7e3a..6dc326be0d 100644 --- a/src/where.c +++ b/src/where.c @@ -395,7 +395,7 @@ static int indexColumnNotNull(Index *pIdx, int iCol){ return 1; }else{ assert( j==(-2) ); - return !sqlite3ExprCanBeNull(pIdx->aColExpr->a[iCol].pExpr); + return 0; /* Assume an indexed expression can always yield a NULL */ } } From 03bf26d90dedaf774c0afbdb54fbf1904234c09e Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 31 Aug 2015 21:16:36 +0000 Subject: [PATCH 11/25] Not only date/time functions, but also functions like sqlite_version() and changes() need to be prohibited from use inside of indexes. FossilOrigin-Name: 487131303980f15dd5e1b6695b4f29efda229eb8 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/func.c | 12 ++++++------ src/resolve.c | 25 +++++++++++-------------- src/sqliteInt.h | 12 +++++++----- 5 files changed, 33 insertions(+), 34 deletions(-) diff --git a/manifest b/manifest index 392a86929f..b244252bcb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Always\sassume\sthat\sindexed\sexpressions\scan\sgenerate\sa\sNULL.\s\sGet\nindexed\sexpressions\sworking\sfor\sthe\scase\sof\stwo\sor\smore\sexpressions\sin\nthe\ssame\sindex. -D 2015-08-31T19:38:42.715 +C Not\sonly\sdate/time\sfunctions,\sbut\salso\sfunctions\slike\ssqlite_version()\sand\nchanges()\sneed\sto\sbe\sprohibited\sfrom\suse\sinside\sof\sindexes. +D 2015-08-31T21:16:36.552 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -292,7 +292,7 @@ F src/delete.c 224e5c9a0eae7fbdd3b461ca971465c992851354 F src/expr.c 500c0ee6ac2e5d60c10df62b8c9b96dc75c2cbb1 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 3ce33dd49f12c72376cec9adc7a4d8e7111cedcc -F src/func.c 824bea430d3a2b7dbc62806ad54da8fdb8ed9e3f +F src/func.c ecdd69ec6a1e406f04cc73324be2ebbf6354197f F src/global.c 508e4087f7b41d688e4762dcf4d4fe28cfbc87f9 F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 @@ -335,14 +335,14 @@ F src/pragma.h 631a91c8b0e6ca8f051a1d8a4a0da4150e04620a F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1 F src/printf.c 2bc439ff20a4aad0e0ad50a37a67b5eae7d20edc F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 -F src/resolve.c 3ec6456a534bcbf0f3fc11ad83c6208301db60a2 +F src/resolve.c 203146a9adfed08c94cdb4bd59421b066a00e03f F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c b52c80f2b1bdb62491f9ce40eea0c5f80c78d105 F src/shell.c 6332ef06db1390ef812cfdff1fc97b4fd76cdd42 F src/sqlite.h.in 378bebc8fe6a88bade25e5f23b7e6123fdc64b00 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h f700e6a9dd1fdcccc9951ab022b366fb66b9e413 -F src/sqliteInt.h 332ae4f753d91c92421a2c4227c195298d5b154c +F src/sqliteInt.h fde5d96c3d547084f7c9ba85b87bad3e4a9a613f F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e @@ -1381,7 +1381,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P e2f1caf117b0a9632d52246717ab202852982339 -R 9a8972907f2a35dc9161585e1e0d88b8 +P cc60321a67bf9f169c090b47afb505f589a6925e +R d6937d2b3277ce224a948b2dc07646a7 U drh -Z 7baf4f251bc37ea5f508ac4ed0b603b4 +Z c474b9a8c6f81c985226d970f2d27c66 diff --git a/manifest.uuid b/manifest.uuid index 693f9f59dd..79cdf18fae 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cc60321a67bf9f169c090b47afb505f589a6925e \ No newline at end of file +487131303980f15dd5e1b6695b4f29efda229eb8 \ No newline at end of file diff --git a/src/func.c b/src/func.c index 6ecd743969..8ea1169327 100644 --- a/src/func.c +++ b/src/func.c @@ -1737,15 +1737,15 @@ void sqlite3RegisterGlobalFunctions(void){ VFUNCTION(random, 0, 0, 0, randomFunc ), VFUNCTION(randomblob, 1, 0, 0, randomBlob ), FUNCTION(nullif, 2, 0, 1, nullifFunc ), - FUNCTION(sqlite_version, 0, 0, 0, versionFunc ), - FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), + DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ), + DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ), #if SQLITE_USER_AUTHENTICATION FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ), #endif #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS - FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ), - FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ), + DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ), + DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ), #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ FUNCTION(quote, 1, 0, 0, quoteFunc ), VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid), @@ -1757,8 +1757,8 @@ void sqlite3RegisterGlobalFunctions(void){ FUNCTION(soundex, 1, 0, 0, soundexFunc ), #endif #ifndef SQLITE_OMIT_LOAD_EXTENSION - FUNCTION(load_extension, 1, 0, 0, loadExt ), - FUNCTION(load_extension, 2, 0, 0, loadExt ), + VFUNCTION(load_extension, 1, 0, 0, loadExt ), + VFUNCTION(load_extension, 2, 0, 0, loadExt ), #endif AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ), AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ), diff --git a/src/resolve.c b/src/resolve.c index 0b8dde7cc6..9522f63cea 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -548,19 +548,16 @@ Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){ /* ** Report an error that an expression is not valid for some set of -** pNC->ncFlags values determined by validMask. If +** pNC->ncFlags values determined by validMask. */ static void notValid( Parse *pParse, /* Leave error message here */ NameContext *pNC, /* The name context */ const char *zMsg, /* Type of error */ - int validMask, /* Set of contexts for which prohibited */ - int okForInit /* No error if pParse->db->init.busy is true */ + int validMask /* Set of contexts for which prohibited */ ){ assert( (validMask&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr))==0 ); - if( (pNC->ncFlags & validMask)!=0 - && (pParse->db->init.busy==0 || !okForInit) - ){ + if( (pNC->ncFlags & validMask)!=0 ){ const char *zIn = "partial index WHERE clauses"; if( pNC->ncFlags & NC_IdxExpr ) zIn = "index expressions"; #ifndef SQLITE_OMIT_CHECK @@ -653,7 +650,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ Expr *pRight; /* if( pSrcList==0 ) break; */ - notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr, 0); + notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr); /*notValid(pParse, pNC, "the \".\" operator", NC_PartIdx|NC_IsCheck, 1);*/ pRight = pExpr->pRight; if( pRight->op==TK_ID ){ @@ -684,7 +681,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ u8 enc = ENC(pParse->db); /* The database encoding */ assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); - notValid(pParse, pNC, "functions", NC_PartIdx, 0); + notValid(pParse, pNC, "functions", NC_PartIdx); zId = pExpr->u.zToken; nId = sqlite3Strlen30(zId); pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0); @@ -732,16 +729,16 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ return WRC_Prune; } #endif - if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_DATETIME) ){ + if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_VARYING) ){ /* For the purposes of the EP_ConstFunc flag, date and time - ** functions are considered constant because the the time does - ** not change for the duration of a query. */ + ** functions and other functions that change slowly are considered + ** constant because they are constant for the duration of one query */ ExprSetProperty(pExpr,EP_ConstFunc); } if( (pDef->funcFlags & SQLITE_FUNC_CONSTANT)==0 ){ /* DATETIME functions are considered non-deterministic because of ** the 'now' capability */ - notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr, 0); + notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr); } } if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){ @@ -788,7 +785,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ testcase( pExpr->op==TK_IN ); if( ExprHasProperty(pExpr, EP_xIsSelect) ){ int nRef = pNC->nRef; - notValid(pParse, pNC, "subqueries", NC_IsCheck|NC_PartIdx|NC_IdxExpr,0); + notValid(pParse, pNC, "subqueries", NC_IsCheck|NC_PartIdx|NC_IdxExpr); sqlite3WalkSelect(pWalker, pExpr->x.pSelect); assert( pNC->nRef>=nRef ); if( nRef!=pNC->nRef ){ @@ -798,7 +795,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ break; } case TK_VARIABLE: { - notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr, 0); + notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr); break; } } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 613f351aa5..8bbb913325 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1396,7 +1396,7 @@ struct FuncDestructor { #define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */ #define SQLITE_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */ #define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */ -#define SQLITE_FUNC_DATETIME 0x2000 /* Function returns a date and/or time */ +#define SQLITE_FUNC_VARYING 0x2000 /* Function that change in the long term */ /* ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are @@ -1414,7 +1414,9 @@ struct FuncDestructor { ** ** DFUNCTION(zName, nArg, iArg, bNC, xFunc) ** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and -** adds the SQLITE_FUNC_DATETIME flag. Used for date & time functions. +** adds the SQLITE_FUNC_VARYING flag. Used for date & time functions +** and functions like sqlite_version() that can change, but not during +** a single query. ** ** AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal) ** Used to create an aggregate function definition implemented by @@ -1437,13 +1439,13 @@ struct FuncDestructor { {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0} #define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \ - {nArg, SQLITE_FUNC_DATETIME|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ + {nArg, SQLITE_FUNC_VARYING|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0} #define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \ {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0} #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \ - {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ + {nArg, SQLITE_FUNC_VARYING|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ pArg, 0, xFunc, 0, 0, #zName, 0, 0} #define LIKEFUNC(zName, nArg, arg, flags) \ {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \ @@ -2129,7 +2131,7 @@ struct Expr { #define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */ #define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */ #define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */ -#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _DATETIME function */ +#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _VARYING function */ #define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */ #define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */ From 8b576422592d9845240cc3b9e923d1ba2dbff4f1 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 31 Aug 2015 23:09:42 +0000 Subject: [PATCH 12/25] Fix a bug in error reporting when a UNIQUE index on expressions fails its uniqueness test. FossilOrigin-Name: 5a2c0e90a1933545b4768d91d8f7c42c8f391019 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/build.c | 18 ++++++++++-------- test/indexexpr1.test | 12 ++++++++++++ 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index b244252bcb..ab89121f74 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Not\sonly\sdate/time\sfunctions,\sbut\salso\sfunctions\slike\ssqlite_version()\sand\nchanges()\sneed\sto\sbe\sprohibited\sfrom\suse\sinside\sof\sindexes. -D 2015-08-31T21:16:36.552 +C Fix\sa\sbug\sin\serror\sreporting\swhen\sa\sUNIQUE\sindex\son\sexpressions\sfails\sits\nuniqueness\stest. +D 2015-08-31T23:09:42.268 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -282,7 +282,7 @@ F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79 F src/btree.c f48b3ef91676c06a90a8832987ecef6b94c931ee F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1 F src/btreeInt.h 8177c9ab90d772d6d2c6c517e05bed774b7c92c0 -F src/build.c 9e7216acaf612d371c1b4a6bf9711886472f7ac6 +F src/build.c f85ede9d6dbf833f8f8d43bd78619c2a112ab161 F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b @@ -780,7 +780,7 @@ F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7 F test/index6.test 7102ec371414c42dfb1d5ca37eb4519aa9edc23a F test/index7.test 9c6765a74fc3fcde7aebc5b3bd40d98df14a527c F test/indexedby.test 5f527a78bae74c61b8046ae3037f9dfb0bf0c353 -F test/indexexpr1.test d04a3905275fb9a0fb82447e7d43773f98fad282 +F test/indexexpr1.test 3c5033412f851f225e3a37d6795709df71bea638 F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7 F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371 @@ -1381,7 +1381,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P cc60321a67bf9f169c090b47afb505f589a6925e -R d6937d2b3277ce224a948b2dc07646a7 +P 487131303980f15dd5e1b6695b4f29efda229eb8 +R 9ef09a7ae54b897d1ff4fd4dfc1065a6 U drh -Z c474b9a8c6f81c985226d970f2d27c66 +Z 8fa9de950d104f084061f9372f8e6439 diff --git a/manifest.uuid b/manifest.uuid index 79cdf18fae..145029b629 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -487131303980f15dd5e1b6695b4f29efda229eb8 \ No newline at end of file +5a2c0e90a1933545b4768d91d8f7c42c8f391019 \ No newline at end of file diff --git a/src/build.c b/src/build.c index f217ab251a..0d5aa34fd1 100644 --- a/src/build.c +++ b/src/build.c @@ -4117,14 +4117,16 @@ void sqlite3UniqueConstraint( Table *pTab = pIdx->pTable; sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200); - for(j=0; jnKeyCol; j++){ - char *zCol; - assert( pIdx->aiColumn[j]>=0 ); - zCol = pTab->aCol[pIdx->aiColumn[j]].zName; - if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2); - sqlite3StrAccumAppendAll(&errMsg, pTab->zName); - sqlite3StrAccumAppend(&errMsg, ".", 1); - sqlite3StrAccumAppendAll(&errMsg, zCol); + if( pIdx->aColExpr ){ + sqlite3XPrintf(&errMsg, 0, "index '%q'", pIdx->zName); + }else{ + for(j=0; jnKeyCol; j++){ + char *zCol; + assert( pIdx->aiColumn[j]>=0 ); + zCol = pTab->aCol[pIdx->aiColumn[j]].zName; + if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2); + sqlite3XPrintf(&errMsg, 0, "%s.%s", pTab->zName, zCol); + } } zErr = sqlite3StrAccumFinish(&errMsg); sqlite3HaltConstraint(pParse, diff --git a/test/indexexpr1.test b/test/indexexpr1.test index aa056e55d4..faaf292de5 100644 --- a/test/indexexpr1.test +++ b/test/indexexpr1.test @@ -186,4 +186,16 @@ do_catchsql_test indexexpr1-340 { CREATE TABLE e1(x,y,FOREIGN KEY(substr(y,1,5)) REFERENCES t1); } {1 {near "(": syntax error}} +do_execsql_test indexexpr1-400 { + CREATE TABLE t3(a,b,c); + WITH RECURSIVE c(x) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<30) + INSERT INTO t3(a,b,c) + SELECT x, printf('ab%04xyz',x), random() FROM c; + CREATE UNIQUE INDEX t3abc ON t3(CAST(a AS text), b, substr(c,1,3)); + SELECT a FROM t3 WHERE CAST(a AS text)<='10' ORDER BY +a; +} {1 10} +do_catchsql_test indexexpr1-410 { + INSERT INTO t3 SELECT * FROM t3 WHERE rowid=10; +} {1 {UNIQUE constraint failed: index 't3abc'}} + finish_test From 7d3d9daea2f94d1265ec97f1d1dfbc6cc36edefd Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 1 Sep 2015 00:42:52 +0000 Subject: [PATCH 13/25] Remove unreachable branches. FossilOrigin-Name: fd4da2318cc032d7c355376e440d4a05d7ab8793 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/build.c | 9 ++++++--- src/where.c | 7 ++++--- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index ab89121f74..a1b5d3fc23 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sbug\sin\serror\sreporting\swhen\sa\sUNIQUE\sindex\son\sexpressions\sfails\sits\nuniqueness\stest. -D 2015-08-31T23:09:42.268 +C Remove\sunreachable\sbranches. +D 2015-09-01T00:42:52.453 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -282,7 +282,7 @@ F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79 F src/btree.c f48b3ef91676c06a90a8832987ecef6b94c931ee F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1 F src/btreeInt.h 8177c9ab90d772d6d2c6c517e05bed774b7c92c0 -F src/build.c f85ede9d6dbf833f8f8d43bd78619c2a112ab161 +F src/build.c c6926497c50c8005c75d4ca476b254978d195a0d F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b @@ -414,7 +414,7 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c 8cd07f1f99e1a81346db1c9da879bef6c6f97cf6 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 2e14d17f592d176b6dc879c33fbdec4fbccaa2ba -F src/where.c 04e0f87e4d82a85c283176958465bed6ea5434e0 +F src/where.c 567b96aa00e7a13ae379a48e10c2911087159e7d F src/whereInt.h 292d3ac90da4eab1e03ac8452f1add746bcafaa1 F src/wherecode.c b0bf45ca49e62fde68ba2e2ad2939d9cdeb4e409 F src/whereexpr.c 2473e4350e30f9b55d1c6a8f66ca23c689f23f1d @@ -1381,7 +1381,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 487131303980f15dd5e1b6695b4f29efda229eb8 -R 9ef09a7ae54b897d1ff4fd4dfc1065a6 +P 5a2c0e90a1933545b4768d91d8f7c42c8f391019 +R 43c7fa01f20234523219b9eb18641ef8 U drh -Z 8fa9de950d104f084061f9372f8e6439 +Z e43aaed9b864f00cd6aff5655ab5ae6d diff --git a/manifest.uuid b/manifest.uuid index 145029b629..8be0526e03 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5a2c0e90a1933545b4768d91d8f7c42c8f391019 \ No newline at end of file +fd4da2318cc032d7c355376e440d4a05d7ab8793 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 0d5aa34fd1..e05b17b68e 100644 --- a/src/build.c +++ b/src/build.c @@ -1310,7 +1310,8 @@ void sqlite3AddPrimaryKey( nTerm = pList->nExpr; for(i=0; ia[i].pExpr); - if( pCExpr && pCExpr->op==TK_ID ){ + assert( pCExpr!=0 ); + if( pCExpr->op==TK_ID ){ const char *zCName = pCExpr->u.zToken; for(iCol=0; iColnCol; iCol++){ if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){ @@ -3061,7 +3062,8 @@ Index *sqlite3CreateIndex( */ for(i=0; inExpr; i++){ Expr *pExpr = pList->a[i].pExpr; - if( pExpr && pExpr->op==TK_COLLATE ){ + assert( pExpr!=0 ); + if( pExpr->op==TK_COLLATE ){ nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken)); } } @@ -3258,6 +3260,7 @@ Index *sqlite3CreateIndex( /* Link the new Index structure to its table and to the other ** in-memory database structures. */ + assert( pParse->nErr==0 ); if( db->init.busy ){ Index *p; assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); @@ -3287,7 +3290,7 @@ Index *sqlite3CreateIndex( ** has just been created, it contains no data and the index initialization ** step can be skipped. */ - else if( pParse->nErr==0 && (HasRowid(pTab) || pTblName!=0) ){ + else if( HasRowid(pTab) || pTblName!=0 ){ Vdbe *v; char *zStmt; int iMem = ++pParse->nMem; diff --git a/src/where.c b/src/where.c index 6dc326be0d..68abfdfe1c 100644 --- a/src/where.c +++ b/src/where.c @@ -180,7 +180,7 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ while( pScan->iEquiv<=pScan->nEquiv ){ iCur = pScan->aiCur[pScan->iEquiv-1]; iColumn = pScan->aiColumn[pScan->iEquiv-1]; - if( iColumn==(-2) && pScan->pIdxExpr==0 ) return 0; + assert( iColumn!=(-2) || pScan->pIdxExpr!=0 ); while( (pWC = pScan->pWC)!=0 ){ for(pTerm=pWC->a+k; knTerm; k++, pTerm++){ if( pTerm->leftCursor==iCur @@ -396,6 +396,7 @@ static int indexColumnNotNull(Index *pIdx, int iCol){ }else{ assert( j==(-2) ); return 0; /* Assume an indexed expression can always yield a NULL */ + } } @@ -803,7 +804,7 @@ static sqlite3_index_info *allocateIndexInfo( testcase( pTerm->eOperator & WO_ALL ); if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; - if( pTerm->u.leftColumn<(-1) ) continue; + assert( pTerm->u.leftColumn>=(-1) ); nTerm++; } @@ -859,7 +860,7 @@ static sqlite3_index_info *allocateIndexInfo( testcase( pTerm->eOperator & WO_ALL ); if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue; - if( pTerm->u.leftColumn<(-1) ) continue; + assert( pTerm->u.leftColumn>=(-1) ); pIdxCons[j].iColumn = pTerm->u.leftColumn; pIdxCons[j].iTermOffset = i; op = (u8)pTerm->eOperator & WO_ALL; From a7f910b549e305306165fe99b431891e66c84223 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 1 Sep 2015 13:17:17 +0000 Subject: [PATCH 14/25] Rename SQLITE_FUNC_VARYING to SQLITE_FUNC_SLOCHNG - a more descriptive name for what that bit means. FossilOrigin-Name: ff5137a6dd8cb2a9b629b3a244f52665e9c9ebce --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/resolve.c | 7 ++++--- src/sqliteInt.h | 11 ++++++----- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index a1b5d3fc23..c69f4462c2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sunreachable\sbranches. -D 2015-09-01T00:42:52.453 +C Rename\sSQLITE_FUNC_VARYING\sto\sSQLITE_FUNC_SLOCHNG\s-\sa\smore\sdescriptive\sname\nfor\swhat\sthat\sbit\smeans. +D 2015-09-01T13:17:17.375 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -335,14 +335,14 @@ F src/pragma.h 631a91c8b0e6ca8f051a1d8a4a0da4150e04620a F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1 F src/printf.c 2bc439ff20a4aad0e0ad50a37a67b5eae7d20edc F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 -F src/resolve.c 203146a9adfed08c94cdb4bd59421b066a00e03f +F src/resolve.c 47c00ca0ab24d4b8113c6c05aa07bc6cf6eac9af F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c b52c80f2b1bdb62491f9ce40eea0c5f80c78d105 F src/shell.c 6332ef06db1390ef812cfdff1fc97b4fd76cdd42 F src/sqlite.h.in 378bebc8fe6a88bade25e5f23b7e6123fdc64b00 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h f700e6a9dd1fdcccc9951ab022b366fb66b9e413 -F src/sqliteInt.h fde5d96c3d547084f7c9ba85b87bad3e4a9a613f +F src/sqliteInt.h e7e92112a71aeb214c66ebdea1366560535614d1 F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e @@ -1381,7 +1381,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 5a2c0e90a1933545b4768d91d8f7c42c8f391019 -R 43c7fa01f20234523219b9eb18641ef8 +P fd4da2318cc032d7c355376e440d4a05d7ab8793 +R 56bc6d7502c6fcf5fea0759746df8b8f U drh -Z e43aaed9b864f00cd6aff5655ab5ae6d +Z 5fd0e1fb2f0e68b5cb95600541b3c11a diff --git a/manifest.uuid b/manifest.uuid index 8be0526e03..5b8d71a036 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fd4da2318cc032d7c355376e440d4a05d7ab8793 \ No newline at end of file +ff5137a6dd8cb2a9b629b3a244f52665e9c9ebce \ No newline at end of file diff --git a/src/resolve.c b/src/resolve.c index 9522f63cea..22df223948 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -729,15 +729,16 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ return WRC_Prune; } #endif - if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_VARYING) ){ + if( pDef->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG) ){ /* For the purposes of the EP_ConstFunc flag, date and time ** functions and other functions that change slowly are considered ** constant because they are constant for the duration of one query */ ExprSetProperty(pExpr,EP_ConstFunc); } if( (pDef->funcFlags & SQLITE_FUNC_CONSTANT)==0 ){ - /* DATETIME functions are considered non-deterministic because of - ** the 'now' capability */ + /* Date/time functions that use 'now', and other functions like + ** sqlite_version() that might change over time cannot be used + ** in an index. */ notValid(pParse, pNC, "non-deterministic functions", NC_IdxExpr); } } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 8bbb913325..69315ed466 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1396,7 +1396,8 @@ struct FuncDestructor { #define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */ #define SQLITE_FUNC_CONSTANT 0x0800 /* Constant inputs give a constant output */ #define SQLITE_FUNC_MINMAX 0x1000 /* True for min() and max() aggregates */ -#define SQLITE_FUNC_VARYING 0x2000 /* Function that change in the long term */ +#define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a + ** single query - might change over time */ /* ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are @@ -1414,7 +1415,7 @@ struct FuncDestructor { ** ** DFUNCTION(zName, nArg, iArg, bNC, xFunc) ** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag and -** adds the SQLITE_FUNC_VARYING flag. Used for date & time functions +** adds the SQLITE_FUNC_SLOCHNG flag. Used for date & time functions ** and functions like sqlite_version() that can change, but not during ** a single query. ** @@ -1439,13 +1440,13 @@ struct FuncDestructor { {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0} #define DFUNCTION(zName, nArg, iArg, bNC, xFunc) \ - {nArg, SQLITE_FUNC_VARYING|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ + {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0} #define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \ {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0} #define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \ - {nArg, SQLITE_FUNC_VARYING|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ + {nArg, SQLITE_FUNC_SLOCHNG|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ pArg, 0, xFunc, 0, 0, #zName, 0, 0} #define LIKEFUNC(zName, nArg, arg, flags) \ {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \ @@ -2131,7 +2132,7 @@ struct Expr { #define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */ #define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */ #define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */ -#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _VARYING function */ +#define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */ #define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */ #define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */ From 2547336dadb65cb5e67dd13f35ab893ed366a40b Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 4 Sep 2015 18:03:45 +0000 Subject: [PATCH 15/25] Fix over-length source code lines in Lemon. FossilOrigin-Name: 1efece95ff8777b89558be59277732ba2a68d5ab --- manifest | 13 ++++++------- manifest.uuid | 2 +- tool/lemon.c | 32 +++++++++++++++++++++++--------- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/manifest b/manifest index 2fb2749921..a7ab65d3ef 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\ssupport\sfor\sCREATE\sINDEX\sstatements\sthat\suse\sdeterministic\sexpressions\nrather\sthan\sonly\scolumn\snames. -D 2015-09-04T17:32:19.351 +C Fix\sover-length\ssource\scode\slines\sin\sLemon. +D 2015-09-04T18:03:45.061 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -1338,7 +1338,7 @@ F tool/fuzzershell.c f2fc86dd22df654b28851b85019d3bd007361751 F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4 F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5 F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce -F tool/lemon.c b9109f59b57e7b6f101c4fe644c8361ba6dee969 +F tool/lemon.c b12cb605725dabfa3a8607ec6bd9e978973c7af9 F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862 F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6 @@ -1383,8 +1383,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 3d3df79bfaf9dbc7aa711c08a19d2f6dbe744b32 5ff855293865c244ac632c630e8e7e8d7c05a5f6 -R 46fafd1e16150312779d43bb23b81793 -T +closed 5ff855293865c244ac632c630e8e7e8d7c05a5f6 +P 2131a5ca53f0e9b0b98a9dd9a20e495d54d146a7 +R c504fcfc7ca364ef5b7aec55028c181c U drh -Z 4941f6208637da2261b21635bf7704d1 +Z 31da7673766f0dcc42d3887f78dbee2d diff --git a/manifest.uuid b/manifest.uuid index 8d3663c4f3..6ca3648ba2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2131a5ca53f0e9b0b98a9dd9a20e495d54d146a7 \ No newline at end of file +1efece95ff8777b89558be59277732ba2a68d5ab \ No newline at end of file diff --git a/tool/lemon.c b/tool/lemon.c index 89d992c37e..5967885021 100644 --- a/tool/lemon.c +++ b/tool/lemon.c @@ -55,7 +55,7 @@ static char *msort(char*,char**,int(*)(const char*,const char*)); ** saying they are unsafe. So we define our own versions of those routines too. ** ** There are three routines here: lemon_sprintf(), lemon_vsprintf(), and -** lemon_addtext(). The first two are replacements for sprintf() and vsprintf(). +** lemon_addtext(). The first two are replacements for sprintf() and vsprintf(). ** The third is a helper routine for vsnprintf() that adds texts to the end of a ** buffer, making sure the buffer is always zero-terminated. ** @@ -1375,14 +1375,16 @@ void Configlist_closure(struct lemon *lemp) /* Sort the configuration list */ void Configlist_sort(){ - current = (struct config *)msort((char *)current,(char **)&(current->next),Configcmp); + current = (struct config*)msort((char*)current,(char**)&(current->next), + Configcmp); currentend = 0; return; } /* Sort the basis configuration list */ void Configlist_sortbasis(){ - basis = (struct config *)msort((char *)current,(char **)&(current->bp),Configcmp); + basis = (struct config*)msort((char*)current,(char**)&(current->bp), + Configcmp); basisend = 0; return; } @@ -1613,7 +1615,8 @@ int main(int argc, char **argv) if( statistics ){ printf("Parser statistics: %d terminals, %d nonterminals, %d rules\n", lem.nterminal, lem.nsymbol - lem.nterminal, lem.nrule); - printf(" %d states, %d parser table entries, %d conflicts\n", + printf(" %d states, %d parser table entries," + " %d conflicts\n", lem.nstate, lem.tablesize, lem.nconflict); } if( lem.nconflict > 0 ){ @@ -1873,7 +1876,8 @@ static int handleswitch(int i, FILE *err) dv = strtod(cp,&end); if( *end ){ if( err ){ - fprintf(err,"%sillegal character in floating-point argument.\n",emsg); + fprintf(err, + "%sillegal character in floating-point argument.\n",emsg); errline(i,(int)((char*)end-(char*)argv[i]),err); } errcnt++; @@ -3228,7 +3232,8 @@ PRIVATE FILE *tplt_open(struct lemon *lemp) } in = fopen(user_templatename,"rb"); if( in==0 ){ - fprintf(stderr,"Can't open the template file \"%s\".\n",user_templatename); + fprintf(stderr,"Can't open the template file \"%s\".\n", + user_templatename); lemp->errorcnt++; return 0; } @@ -3313,7 +3318,10 @@ void emit_destructor_code( }else if( sp->destructor ){ cp = sp->destructor; fprintf(out,"{\n"); (*lineno)++; - if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,sp->destLineno,lemp->filename); } + if( !lemp->nolinenosflag ){ + (*lineno)++; + tplt_linedir(out,sp->destLineno,lemp->filename); + } }else if( lemp->vardest ){ cp = lemp->vardest; if( cp==0 ) return; @@ -3510,13 +3518,19 @@ PRIVATE void emit_code( /* Generate code to do the reduce action */ if( rp->code ){ - if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,rp->line,lemp->filename); } + if( !lemp->nolinenosflag ){ + (*lineno)++; + tplt_linedir(out,rp->line,lemp->filename); + } fprintf(out,"{%s",rp->code); for(cp=rp->code; *cp; cp++){ if( *cp=='\n' ) (*lineno)++; } /* End loop */ fprintf(out,"}\n"); (*lineno)++; - if (!lemp->nolinenosflag) { (*lineno)++; tplt_linedir(out,*lineno,lemp->outname); } + if( !lemp->nolinenosflag ){ + (*lineno)++; + tplt_linedir(out,*lineno,lemp->outname); + } } /* End if( rp->code ) */ return; From e3a7307e2dd806033b5f3959c7f2a3fd6c965f97 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 5 Sep 2015 19:07:08 +0000 Subject: [PATCH 16/25] Get STAT4 range scan estimates work again when the bounds are determined by date/time functions. FossilOrigin-Name: d2761357a0496ec1e590c7c9e397c5b5c904f91a --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/vdbemem.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index a7ab65d3ef..434d78ec41 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sover-length\ssource\scode\slines\sin\sLemon. -D 2015-09-04T18:03:45.061 +C Get\sSTAT4\srange\sscan\sestimates\swork\sagain\swhen\sthe\sbounds\sare\sdetermined\nby\sdate/time\sfunctions. +D 2015-09-05T19:07:08.860 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -408,7 +408,7 @@ F src/vdbeInt.h 8b54e01ad0463590e7cffabce0bc36da9ee4f816 F src/vdbeapi.c bda74ef4b5103d7b4a4be36f936d3cf2b56a7d6f F src/vdbeaux.c fd00b489ab3f44f2dca1e4344faf289b7bfcf649 F src/vdbeblob.c 1d7b97115e7bbac4c318db416d2ca83fc779544a -F src/vdbemem.c ae38a0d35ae71cf604381a887c170466ba518090 +F src/vdbemem.c 19b3036aa4d676e7103b0fb5efd6327da455f915 F src/vdbesort.c f5009e7a35e3065635d8918b9a31f498a499976b F src/vdbetrace.c 8befe829faff6d9e6f6e4dee5a7d3f85cc85f1a0 F src/vtab.c 2ecfe020c10e0a0c7b078203fdba2fae844744bc @@ -1383,7 +1383,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 2131a5ca53f0e9b0b98a9dd9a20e495d54d146a7 -R c504fcfc7ca364ef5b7aec55028c181c +P 1efece95ff8777b89558be59277732ba2a68d5ab +R 33b468f201c817bccc2bf5f080039adb U drh -Z 31da7673766f0dcc42d3887f78dbee2d +Z 535e2ce68f49a8491abd9f8ccc62b768 diff --git a/manifest.uuid b/manifest.uuid index 6ca3648ba2..3ddd4c577d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1efece95ff8777b89558be59277732ba2a68d5ab \ No newline at end of file +d2761357a0496ec1e590c7c9e397c5b5c904f91a \ No newline at end of file diff --git a/src/vdbemem.c b/src/vdbemem.c index 648a53d2a3..28dd5d9572 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -1155,7 +1155,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ ** to be a scalar SQL function. If ** ** * all function arguments are SQL literals, -** * the SQLITE_FUNC_CONSTANT function flag is set, and +** * one of the SQLITE_FUNC_CONSTANT or _SLOCHNG function flags is set, and ** * the SQLITE_FUNC_NEEDCOLL function flag is not set, ** ** then this routine attempts to invoke the SQL function. Assuming no @@ -1196,7 +1196,7 @@ static int valueFromFunction( nName = sqlite3Strlen30(p->u.zToken); pFunc = sqlite3FindFunction(db, p->u.zToken, nName, nVal, enc, 0); assert( pFunc ); - if( (pFunc->funcFlags & SQLITE_FUNC_CONSTANT)==0 + if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0 || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL) ){ return SQLITE_OK; From 28b9e0fc058c5e6c212109b58162fbe7d9f5a651 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 5 Sep 2015 19:21:00 +0000 Subject: [PATCH 17/25] Fix an unreachable conditional in the WHERE clause analysis logic. FossilOrigin-Name: 24924a58197e558a9e8800cc5c91dc8fb32f3557 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 3 ++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 434d78ec41..f9b770eebc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Get\sSTAT4\srange\sscan\sestimates\swork\sagain\swhen\sthe\sbounds\sare\sdetermined\nby\sdate/time\sfunctions. -D 2015-09-05T19:07:08.860 +C Fix\san\sunreachable\sconditional\sin\sthe\sWHERE\sclause\sanalysis\slogic. +D 2015-09-05T19:21:00.671 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -416,7 +416,7 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c 8cd07f1f99e1a81346db1c9da879bef6c6f97cf6 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 2e14d17f592d176b6dc879c33fbdec4fbccaa2ba -F src/where.c e6efbb9e5f0c20943cd03909b3894ad5b105dedf +F src/where.c ed1cd1cb0434bca9f4a5379582c637bf393b34ac F src/whereInt.h 292d3ac90da4eab1e03ac8452f1add746bcafaa1 F src/wherecode.c 6ac8599523f4840d9efac335329f627ebf3f79fd F src/whereexpr.c 2473e4350e30f9b55d1c6a8f66ca23c689f23f1d @@ -1383,7 +1383,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 1efece95ff8777b89558be59277732ba2a68d5ab -R 33b468f201c817bccc2bf5f080039adb +P d2761357a0496ec1e590c7c9e397c5b5c904f91a +R 9921ff0c69ded6987711a9a840df906d U drh -Z 535e2ce68f49a8491abd9f8ccc62b768 +Z 612add4179403f74341dc4eb50c9c3d3 diff --git a/manifest.uuid b/manifest.uuid index 3ddd4c577d..4767aec925 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d2761357a0496ec1e590c7c9e397c5b5c904f91a \ No newline at end of file +24924a58197e558a9e8800cc5c91dc8fb32f3557 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 1ee31fef3b..a29988a8e0 100644 --- a/src/where.c +++ b/src/where.c @@ -191,9 +191,10 @@ static WhereTerm *whereScanNext(WhereScan *pScan){ ){ if( (pTerm->eOperator & WO_EQUIV)!=0 && pScan->nEquivaiCur) - && (pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight))->op==TK_COLUMN ){ int j; + pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight); + assert( pX->op==TK_COLUMN ); for(j=0; jnEquiv; j++){ if( pScan->aiCur[j]==pX->iTable && pScan->aiColumn[j]==pX->iColumn ){ From 0b8d255c37ea9830cecabb57f1c2ba6305eacc44 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 5 Sep 2015 22:36:07 +0000 Subject: [PATCH 18/25] Omit all use of Expr nodes for TK_AS, as those nodes no longer served a useful purpose and in fact interferred with the query planner. FossilOrigin-Name: 7ab0b258eabfcfb7f1b0bd1b12e166d2f267823d --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/expr.c | 8 ++------ src/resolve.c | 38 +++----------------------------------- src/sqliteInt.h | 1 + src/treeview.c | 5 ----- test/indexexpr1.test | 21 +++++++++++++++++++++ 7 files changed, 38 insertions(+), 57 deletions(-) diff --git a/manifest b/manifest index f9b770eebc..bcf650cd13 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\san\sunreachable\sconditional\sin\sthe\sWHERE\sclause\sanalysis\slogic. -D 2015-09-05T19:21:00.671 +C Omit\sall\suse\sof\sExpr\snodes\sfor\sTK_AS,\sas\sthose\snodes\sno\slonger\sserved\sa\suseful\npurpose\sand\sin\sfact\sinterferred\swith\sthe\squery\splanner. +D 2015-09-05T22:36:07.095 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -291,7 +291,7 @@ F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b F src/date.c fb1c99172017dcc8e237339132c91a21a0788584 F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a F src/delete.c 6792c80d7fb54c4df9f7680413952600e7439492 -F src/expr.c f3c4d165dea72b268a7b922d00035af1d510dd78 +F src/expr.c 3a76afcdac925294c39903b7002ddb9e5fd29863 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 83e1baba999bed3144ea5a2143fc922edf51135f F src/func.c ecdd69ec6a1e406f04cc73324be2ebbf6354197f @@ -337,14 +337,14 @@ F src/pragma.h 631a91c8b0e6ca8f051a1d8a4a0da4150e04620a F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1 F src/printf.c 0c4bcdd1c2e2521024f0a69cb5eb334f86b3652a F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 -F src/resolve.c 47c00ca0ab24d4b8113c6c05aa07bc6cf6eac9af +F src/resolve.c 3126f7694b8ce0f97282d7dd3a5198b8fa18dce9 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c c17613385bc6b095c421b1f30548814f5fd8a9b2 F src/shell.c 6332ef06db1390ef812cfdff1fc97b4fd76cdd42 F src/sqlite.h.in 378bebc8fe6a88bade25e5f23b7e6123fdc64b00 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h f700e6a9dd1fdcccc9951ab022b366fb66b9e413 -F src/sqliteInt.h e7e92112a71aeb214c66ebdea1366560535614d1 +F src/sqliteInt.h ad5504745ef37aca44365a2b91173bc399d71e7e F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e @@ -396,7 +396,7 @@ F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 6bbcc9fe50c917864d48287b4792d46d6e873481 F src/tokenize.c 57cb3720f53f84d811def2069c2b169b6be539a5 -F src/treeview.c 46036cbbceada0836833531b2d963edbca3d9cfa +F src/treeview.c 154f0acc622fa3514de8777dcedf4c8a8802b4ce F src/trigger.c 322f23aad694e8f31d384dcfa386d52a48d3c52f F src/update.c 3c5bc9570df3bfafa0db36828406a8a14e4c426e F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c @@ -782,7 +782,7 @@ F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7 F test/index6.test 7102ec371414c42dfb1d5ca37eb4519aa9edc23a F test/index7.test 9c6765a74fc3fcde7aebc5b3bd40d98df14a527c F test/indexedby.test 5f527a78bae74c61b8046ae3037f9dfb0bf0c353 -F test/indexexpr1.test 3c5033412f851f225e3a37d6795709df71bea638 +F test/indexexpr1.test 4feec154aadacb033b41acc1760a18edc4c60470 F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7 F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371 @@ -1383,7 +1383,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P d2761357a0496ec1e590c7c9e397c5b5c904f91a -R 9921ff0c69ded6987711a9a840df906d +P 24924a58197e558a9e8800cc5c91dc8fb32f3557 +R 7e67010ff7c10ab44fd6cfd6cc975796 U drh -Z 612add4179403f74341dc4eb50c9c3d3 +Z 8a5f85b9c3f71859f18b9284198b5fad diff --git a/manifest.uuid b/manifest.uuid index 4767aec925..86f4bfaeac 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -24924a58197e558a9e8800cc5c91dc8fb32f3557 \ No newline at end of file +7ab0b258eabfcfb7f1b0bd1b12e166d2f267823d \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 00228d9a3f..3141cd9dbd 100644 --- a/src/expr.c +++ b/src/expr.c @@ -91,7 +91,7 @@ Expr *sqlite3ExprAddCollateString(Parse *pParse, Expr *pExpr, const char *zC){ } /* -** Skip over any TK_COLLATE or TK_AS operators and any unlikely() +** Skip over any TK_COLLATE operators and any unlikely() ** or likelihood() function at the root of an expression. */ Expr *sqlite3ExprSkipCollate(Expr *pExpr){ @@ -102,7 +102,7 @@ Expr *sqlite3ExprSkipCollate(Expr *pExpr){ assert( pExpr->op==TK_FUNCTION ); pExpr = pExpr->x.pList->a[0].pExpr; }else{ - assert( pExpr->op==TK_COLLATE || pExpr->op==TK_AS ); + assert( pExpr->op==TK_COLLATE ); pExpr = pExpr->pLeft; } } @@ -2701,10 +2701,6 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ inReg = pExpr->iTable; break; } - case TK_AS: { - inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target); - break; - } #ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ diff --git a/src/resolve.c b/src/resolve.c index 22df223948..2c4212ba7d 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -45,30 +45,6 @@ static void incrAggFunctionDepth(Expr *pExpr, int N){ ** Turn the pExpr expression into an alias for the iCol-th column of the ** result set in pEList. ** -** If the result set column is a simple column reference, then this routine -** makes an exact copy. But for any other kind of expression, this -** routine make a copy of the result set column as the argument to the -** TK_AS operator. The TK_AS operator causes the expression to be -** evaluated just once and then reused for each alias. -** -** The reason for suppressing the TK_AS term when the expression is a simple -** column reference is so that the column reference will be recognized as -** usable by indices within the WHERE clause processing logic. -** -** The TK_AS operator is inhibited if zType[0]=='G'. This means -** that in a GROUP BY clause, the expression is evaluated twice. Hence: -** -** SELECT random()%5 AS x, count(*) FROM tab GROUP BY x -** -** Is equivalent to: -** -** SELECT random()%5 AS x, count(*) FROM tab GROUP BY random()%5 -** -** The result of random()%5 in the GROUP BY clause is probably different -** from the result in the result-set. On the other hand Standard SQL does -** not allow the GROUP BY clause to contain references to result-set columns. -** So this should never come up in well-formed queries. -** ** If the reference is followed by a COLLATE operator, then make sure ** the COLLATE operator is preserved. For example: ** @@ -102,19 +78,11 @@ static void resolveAlias( db = pParse->db; pDup = sqlite3ExprDup(db, pOrig, 0); if( pDup==0 ) return; - if( pOrig->op!=TK_COLUMN && zType[0]!='G' ){ - incrAggFunctionDepth(pDup, nSubquery); - pDup = sqlite3PExpr(pParse, TK_AS, pDup, 0, 0); - if( pDup==0 ) return; - ExprSetProperty(pDup, EP_Skip); - if( pEList->a[iCol].u.x.iAlias==0 ){ - pEList->a[iCol].u.x.iAlias = (u16)(++pParse->nAlias); - } - pDup->iTable = pEList->a[iCol].u.x.iAlias; - } + if( zType[0]!='G' ) incrAggFunctionDepth(pDup, nSubquery); if( pExpr->op==TK_COLLATE ){ pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken); } + ExprSetProperty(pDup, EP_Alias); /* Before calling sqlite3ExprDelete(), set the EP_Static flag. This ** prevents ExprDelete() from deleting the Expr structure itself, @@ -506,7 +474,7 @@ static int lookupName( lookupname_end: if( cnt==1 ){ assert( pNC!=0 ); - if( pExpr->op!=TK_AS ){ + if( !ExprHasProperty(pExpr, EP_Alias) ){ sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList); } /* Increment the nRef value on all name contexts from TopNC up to diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 69315ed466..89b3d798f1 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2135,6 +2135,7 @@ struct Expr { #define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */ #define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */ #define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */ +#define EP_Alias 0x400000 /* Is an alias for a result set column */ /* ** Combinations of two or more EP_* flags diff --git a/src/treeview.c b/src/treeview.c index 59c07e4742..971de4e8bc 100644 --- a/src/treeview.c +++ b/src/treeview.c @@ -253,11 +253,6 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable); break; } - case TK_AS: { - sqlite3TreeViewLine(pView,"AS %Q", pExpr->u.zToken); - sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); - break; - } case TK_ID: { sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken); break; diff --git a/test/indexexpr1.test b/test/indexexpr1.test index faaf292de5..0c925c9f92 100644 --- a/test/indexexpr1.test +++ b/test/indexexpr1.test @@ -198,4 +198,25 @@ do_catchsql_test indexexpr1-410 { INSERT INTO t3 SELECT * FROM t3 WHERE rowid=10; } {1 {UNIQUE constraint failed: index 't3abc'}} +do_execsql_test indexexpr1-500 { + CREATE TABLE t5(a); + CREATE TABLE cnt(x); + WITH RECURSIVE + c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<5) + INSERT INTO cnt(x) SELECT x FROM c; + INSERT INTO t5(a) SELECT printf('abc%03dxyz',x) FROM cnt; + CREATE INDEX t5ax ON t5( substr(a,4,3) ); +} {} +do_execsql_test indexexpr1-510 { + -- The use of the "k" alias in the WHERE clause is technically + -- illegal, but SQLite allows it for historical reasons. In this + -- test and the next, verify that "k" can be used by the t5ax index + SELECT substr(a,4,3) AS k FROM cnt, t5 WHERE k=printf('%03d',x); +} {001 002 003 004 005} +do_execsql_test indexexpr1-510eqp { + EXPLAIN QUERY PLAN + SELECT substr(a,4,3) AS k FROM cnt, t5 WHERE k=printf('%03d',x); +} {/USING INDEX t5ax/} + + finish_test From 6081c1dbdf7730752bbde89ebb17d01bb30bf8f0 Mon Sep 17 00:00:00 2001 From: drh Date: Sun, 6 Sep 2015 02:51:04 +0000 Subject: [PATCH 19/25] Add a memory barrier to the mutex initialization logic, try to work around an issue reported by WebKit. FossilOrigin-Name: 11a9a786ec06403addb47f5c6fb142b382fae522 --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/mutex.c | 1 + src/mutex.h | 1 + src/mutex_unix.c | 12 ++++++++++++ src/mutex_w32.c | 7 +++++++ src/sqliteInt.h | 1 + 7 files changed, 33 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index bcf650cd13..6ceaeb6515 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Omit\sall\suse\sof\sExpr\snodes\sfor\sTK_AS,\sas\sthose\snodes\sno\slonger\sserved\sa\suseful\npurpose\sand\sin\sfact\sinterferred\swith\sthe\squery\splanner. -D 2015-09-05T22:36:07.095 +C Add\sa\smemory\sbarrier\sto\sthe\smutex\sinitialization\slogic,\stry\sto\swork\saround\nan\sissue\sreported\sby\sWebKit. +D 2015-09-06T02:51:04.140 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -313,11 +313,11 @@ F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534 F src/mem5.c 61eeb90134f9a5be6c2e68d8daae7628b25953fb F src/memjournal.c 3eb2c0b51adbd869cb6a44780323f05fa904dc85 F src/msvc.h d9ba56c6851227ab44b3f228a35f3f5772296495 -F src/mutex.c 529e95739f815300a33c73fd8a7d6bdf0c24bd18 -F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85 +F src/mutex.c a39809c6c33f1ebc9cc781186c338ad90433e1e7 +F src/mutex.h 012503b51ccfcf85b8b3846709a4c60a5839f16c F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4 -F src/mutex_unix.c b0d280089df0f49545f1318f45d61d07d2f674a8 -F src/mutex_w32.c b601f9e3073f7bd2c1f42a8c0ce59e42d6a08f85 +F src/mutex_unix.c c3f415ebd3c1a7952d24f46f748aef796beabdcc +F src/mutex_w32.c 0f323eb53f092393be9d1fa91c9730baf56c4718 F src/notify.c 9711a7575036f0d3040ba61bc6e217f13a9888e7 F src/os.c 8fd25588eeba74068d41102d26810e216999b6c8 F src/os.h 3e57a24e2794a94d3cf2342c6d9a884888cd96bf @@ -344,7 +344,7 @@ F src/shell.c 6332ef06db1390ef812cfdff1fc97b4fd76cdd42 F src/sqlite.h.in 378bebc8fe6a88bade25e5f23b7e6123fdc64b00 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h f700e6a9dd1fdcccc9951ab022b366fb66b9e413 -F src/sqliteInt.h ad5504745ef37aca44365a2b91173bc399d71e7e +F src/sqliteInt.h dba8add0b95fcea1047af7a6875a1e305fcb96d7 F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e @@ -1383,7 +1383,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 24924a58197e558a9e8800cc5c91dc8fb32f3557 -R 7e67010ff7c10ab44fd6cfd6cc975796 +P 7ab0b258eabfcfb7f1b0bd1b12e166d2f267823d +R b2a67150d05e13e20516640b31b0c7ad U drh -Z 8a5f85b9c3f71859f18b9284198b5fad +Z b9d369a816ef742a733a926cd28b24f3 diff --git a/manifest.uuid b/manifest.uuid index 86f4bfaeac..7aaeaf8ce5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7ab0b258eabfcfb7f1b0bd1b12e166d2f267823d \ No newline at end of file +11a9a786ec06403addb47f5c6fb142b382fae522 \ No newline at end of file diff --git a/src/mutex.c b/src/mutex.c index 64efd3b05e..a2e4e6387a 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -53,6 +53,7 @@ int sqlite3MutexInit(void){ pTo->xMutexLeave = pFrom->xMutexLeave; pTo->xMutexHeld = pFrom->xMutexHeld; pTo->xMutexNotheld = pFrom->xMutexNotheld; + sqlite3MemoryBarrier(); pTo->xMutexAlloc = pFrom->xMutexAlloc; } rc = sqlite3GlobalConfig.mutex.xMutexInit(); diff --git a/src/mutex.h b/src/mutex.h index 03eb1faadb..8bcf2353f7 100644 --- a/src/mutex.h +++ b/src/mutex.h @@ -64,6 +64,7 @@ #define sqlite3MutexAlloc(X) ((sqlite3_mutex*)8) #define sqlite3MutexInit() SQLITE_OK #define sqlite3MutexEnd() +#define sqlite3MemoryBarrier() #define MUTEX_LOGIC(X) #else #define MUTEX_LOGIC(X) X diff --git a/src/mutex_unix.c b/src/mutex_unix.c index 0a493fa6a7..e181ba5bd1 100644 --- a/src/mutex_unix.c +++ b/src/mutex_unix.c @@ -80,6 +80,18 @@ static int pthreadMutexNotheld(sqlite3_mutex *p){ } #endif +/* +** Try to provide a memory barrier operation, needed for initialization only. +*/ +void sqlite3MemoryBarrier(void){ +#if defined(__GNUC__) + __sync_synchronize(); +#endif +#ifdef SQLITE_MEMORY_BARRIER + SQLITE_MEMORY_BARRIER; +#endif +} + /* ** Initialize and deinitialize the mutex subsystem. */ diff --git a/src/mutex_w32.c b/src/mutex_w32.c index fc943acaa0..9f2fb048fd 100644 --- a/src/mutex_w32.c +++ b/src/mutex_w32.c @@ -77,6 +77,13 @@ static int winMutexNotheld(sqlite3_mutex *p){ } #endif +/* +** Try to provide a memory barrier operation, needed for initialization only. +*/ +void sqlite3MemoryBarrier(void){ + MemoryBarrier(); +} + /* ** Initialize and deinitialize the mutex subsystem. */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 89b3d798f1..eeb0b9950c 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3191,6 +3191,7 @@ const sqlite3_mem_methods *sqlite3MemGetMemsys5(void); sqlite3_mutex *sqlite3MutexAlloc(int); int sqlite3MutexInit(void); int sqlite3MutexEnd(void); + void sqlite3MemoryBarrier(void); #endif sqlite3_int64 sqlite3StatusValue(int); From 2d64034bc2b1d61eea4c75e11af5c5ef15576352 Mon Sep 17 00:00:00 2001 From: drh Date: Sun, 6 Sep 2015 10:31:37 +0000 Subject: [PATCH 20/25] Improved memory barrier that should work with MinGW on older versions of Windows. FossilOrigin-Name: 47dc24bd1e8f76eb17ba53a883b8984b3e1b2934 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/mutex_unix.c | 7 +++---- src/mutex_w32.c | 6 ++++++ 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index 6ceaeb6515..54933846aa 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\smemory\sbarrier\sto\sthe\smutex\sinitialization\slogic,\stry\sto\swork\saround\nan\sissue\sreported\sby\sWebKit. -D 2015-09-06T02:51:04.140 +C Improved\smemory\sbarrier\sthat\sshould\swork\swith\sMinGW\son\solder\sversions\sof\nWindows. +D 2015-09-06T10:31:37.987 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -316,8 +316,8 @@ F src/msvc.h d9ba56c6851227ab44b3f228a35f3f5772296495 F src/mutex.c a39809c6c33f1ebc9cc781186c338ad90433e1e7 F src/mutex.h 012503b51ccfcf85b8b3846709a4c60a5839f16c F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4 -F src/mutex_unix.c c3f415ebd3c1a7952d24f46f748aef796beabdcc -F src/mutex_w32.c 0f323eb53f092393be9d1fa91c9730baf56c4718 +F src/mutex_unix.c 7762c8ec907379204f2ed751a0e33663ab1c14d7 +F src/mutex_w32.c 2e025e6642eaf27597403690980f560d1a91f62c F src/notify.c 9711a7575036f0d3040ba61bc6e217f13a9888e7 F src/os.c 8fd25588eeba74068d41102d26810e216999b6c8 F src/os.h 3e57a24e2794a94d3cf2342c6d9a884888cd96bf @@ -1383,7 +1383,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 7ab0b258eabfcfb7f1b0bd1b12e166d2f267823d -R b2a67150d05e13e20516640b31b0c7ad +P 11a9a786ec06403addb47f5c6fb142b382fae522 +R ddcc46edb79b17bfa61348716fbd1950 U drh -Z b9d369a816ef742a733a926cd28b24f3 +Z 19a2121ad81300b8c56d01dcfbdbe0e2 diff --git a/manifest.uuid b/manifest.uuid index 7aaeaf8ce5..5d01533397 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -11a9a786ec06403addb47f5c6fb142b382fae522 \ No newline at end of file +47dc24bd1e8f76eb17ba53a883b8984b3e1b2934 \ No newline at end of file diff --git a/src/mutex_unix.c b/src/mutex_unix.c index e181ba5bd1..78fba1d81f 100644 --- a/src/mutex_unix.c +++ b/src/mutex_unix.c @@ -84,11 +84,10 @@ static int pthreadMutexNotheld(sqlite3_mutex *p){ ** Try to provide a memory barrier operation, needed for initialization only. */ void sqlite3MemoryBarrier(void){ -#if defined(__GNUC__) - __sync_synchronize(); -#endif -#ifdef SQLITE_MEMORY_BARRIER +#if defined(SQLITE_MEMORY_BARRIER) SQLITE_MEMORY_BARRIER; +#elif defined(__GNUC__) + __sync_synchronize(); #endif } diff --git a/src/mutex_w32.c b/src/mutex_w32.c index 9f2fb048fd..90be07db2d 100644 --- a/src/mutex_w32.c +++ b/src/mutex_w32.c @@ -81,7 +81,13 @@ static int winMutexNotheld(sqlite3_mutex *p){ ** Try to provide a memory barrier operation, needed for initialization only. */ void sqlite3MemoryBarrier(void){ +#if defined(SQLITE_MEMORY_BARRIER) + SQLITE_MEMORY_BARRIER; +#elif defined(__GNUC__) + __sync_synchronize(); +#else MemoryBarrier(); +#endif } /* From c75e0166f08b72417ca617c85f8c8d627c880d46 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 7 Sep 2015 02:23:02 +0000 Subject: [PATCH 21/25] Improved "Parser Statistics" output (the -s option) for the Lemon parser generator. FossilOrigin-Name: 809503e4efcdb498d176e8c0794a5ba0882adef2 --- manifest | 12 ++++----- manifest.uuid | 2 +- tool/lemon.c | 75 ++++++++++++++++++++++++++++++++++++--------------- 3 files changed, 61 insertions(+), 28 deletions(-) diff --git a/manifest b/manifest index 54933846aa..f8137c54e5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\smemory\sbarrier\sthat\sshould\swork\swith\sMinGW\son\solder\sversions\sof\nWindows. -D 2015-09-06T10:31:37.987 +C Improved\s"Parser\sStatistics"\soutput\s(the\s-s\soption)\sfor\sthe\sLemon\sparser\ngenerator. +D 2015-09-07T02:23:02.396 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -1338,7 +1338,7 @@ F tool/fuzzershell.c f2fc86dd22df654b28851b85019d3bd007361751 F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4 F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5 F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce -F tool/lemon.c b12cb605725dabfa3a8607ec6bd9e978973c7af9 +F tool/lemon.c cc515b02a6610ed76c93d49bd01fdb219356d7ac F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862 F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6 @@ -1383,7 +1383,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 11a9a786ec06403addb47f5c6fb142b382fae522 -R ddcc46edb79b17bfa61348716fbd1950 +P 47dc24bd1e8f76eb17ba53a883b8984b3e1b2934 +R d6df305b5709e894bdfc542577063f51 U drh -Z 19a2121ad81300b8c56d01dcfbdbe0e2 +Z 643bd9ba035c2e0820f3e9522cf3c1e3 diff --git a/manifest.uuid b/manifest.uuid index 5d01533397..f1edfd5794 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -47dc24bd1e8f76eb17ba53a883b8984b3e1b2934 \ No newline at end of file +809503e4efcdb498d176e8c0794a5ba0882adef2 \ No newline at end of file diff --git a/tool/lemon.c b/tool/lemon.c index 5967885021..f27fe4d24a 100644 --- a/tool/lemon.c +++ b/tool/lemon.c @@ -385,7 +385,8 @@ struct lemon { char *outname; /* Name of the current output file */ char *tokenprefix; /* A prefix added to token names in the .h file */ int nconflict; /* Number of parsing conflicts */ - int tablesize; /* Size of the parse tables */ + int nactiontab; /* Number of entries in the yy_action[] table */ + int tablesize; /* Total table size of all tables in bytes */ int basisflag; /* Print only basis configurations */ int has_fallback; /* True if any %fallback is seen in the grammar */ int nolinenosflag; /* True if #line statements should not be printed */ @@ -1482,6 +1483,18 @@ static void handle_T_option(char *z){ lemon_strcpy(user_templatename, z); } +/* forward reference */ +static const char *minimum_size_type(int lwr, int upr, int *pnByte); + +/* Print a single line of the "Parser Stats" output +*/ +static void stats_line(const char *zLabel, int iValue){ + int nLabel = lemonStrlen(zLabel); + printf(" %s%.*s %5d\n", zLabel, + 35-nLabel, "................................", + iValue); +} + /* The main program. Parse the command line and do it... */ int main(int argc, char **argv) { @@ -1613,11 +1626,15 @@ int main(int argc, char **argv) if( !mhflag ) ReportHeader(&lem); } if( statistics ){ - printf("Parser statistics: %d terminals, %d nonterminals, %d rules\n", - lem.nterminal, lem.nsymbol - lem.nterminal, lem.nrule); - printf(" %d states, %d parser table entries," - " %d conflicts\n", - lem.nstate, lem.tablesize, lem.nconflict); + printf("Parser statistics:\n"); + stats_line("terminal symbols", lem.nterminal); + stats_line("non-terminal symbols", lem.nsymbol - lem.nterminal); + stats_line("total symbols", lem.nsymbol); + stats_line("rules", lem.nrule); + stats_line("states", lem.nstate); + stats_line("conflicts", lem.nconflict); + stats_line("action table entries", lem.nactiontab); + stats_line("total table size (bytes)", lem.tablesize); } if( lem.nconflict > 0 ){ fprintf(stderr,"%d parsing conflicts.\n",lem.nconflict); @@ -3661,24 +3678,32 @@ void print_stack_union( /* ** Return the name of a C datatype able to represent values between -** lwr and upr, inclusive. +** lwr and upr, inclusive. If pnByte!=NULL then also write the sizeof +** for that type (1, 2, or 4) into *pnByte. */ -static const char *minimum_size_type(int lwr, int upr){ +static const char *minimum_size_type(int lwr, int upr, int *pnByte){ + const char *zType = "int"; + int nByte = 4; if( lwr>=0 ){ if( upr<=255 ){ - return "unsigned char"; + zType = "unsigned char"; + nByte = 1; }else if( upr<65535 ){ - return "unsigned short int"; + zType = "unsigned short int"; + nByte = 2; }else{ - return "unsigned int"; + zType = "unsigned int"; + nByte = 4; } }else if( lwr>=-127 && upr<=127 ){ - return "signed char"; + zType = "signed char"; + nByte = 1; }else if( lwr>=-32767 && upr<32767 ){ - return "short"; - }else{ - return "int"; + zType = "short"; + nByte = 2; } + if( pnByte ) *pnByte = nByte; + return zType; } /* @@ -3742,7 +3767,9 @@ void ReportTable( struct action *ap; struct rule *rp; struct acttab *pActtab; - int i, j, n; + int i, j, n, sz; + int szActionType; /* sizeof(YYACTIONTYPE) */ + int szCodeType; /* sizeof(YYCODETYPE) */ const char *name; int mnTknOfst, mxTknOfst; int mnNtOfst, mxNtOfst; @@ -3783,10 +3810,10 @@ void ReportTable( /* Generate the defines */ fprintf(out,"#define YYCODETYPE %s\n", - minimum_size_type(0, lemp->nsymbol+1)); lineno++; + minimum_size_type(0, lemp->nsymbol+1, &szCodeType)); lineno++; fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol+1); lineno++; fprintf(out,"#define YYACTIONTYPE %s\n", - minimum_size_type(0, lemp->nstate+lemp->nrule+5)); lineno++; + minimum_size_type(0, lemp->nstate+lemp->nrule+5, &szActionType)); lineno++; if( lemp->wildcard ){ fprintf(out,"#define YYWILDCARD %d\n", lemp->wildcard->index); lineno++; @@ -3900,7 +3927,8 @@ void ReportTable( free(ax); /* Output the yy_action table */ - n = acttab_size(pActtab); + lemp->nactiontab = n = acttab_size(pActtab); + lemp->tablesize += n*szActionType; fprintf(out,"#define YY_ACTTAB_COUNT (%d)\n", n); lineno++; fprintf(out,"static const YYACTIONTYPE yy_action[] = {\n"); lineno++; for(i=j=0; itablesize += n*szCodeType; fprintf(out,"static const YYCODETYPE yy_lookahead[] = {\n"); lineno++; for(i=j=0; itablesize += n*sz; for(i=j=0; isorted[i]; @@ -3966,7 +3996,8 @@ void ReportTable( fprintf(out, "#define YY_REDUCE_MIN (%d)\n", mnNtOfst); lineno++; fprintf(out, "#define YY_REDUCE_MAX (%d)\n", mxNtOfst); lineno++; fprintf(out, "static const %s yy_reduce_ofst[] = {\n", - minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++; + minimum_size_type(mnNtOfst-1, mxNtOfst, &sz)); lineno++; + lemp->tablesize += n*sz; for(i=j=0; isorted[i]; @@ -3986,6 +4017,7 @@ void ReportTable( /* Output the default action table */ fprintf(out, "static const YYACTIONTYPE yy_default[] = {\n"); lineno++; n = lemp->nstate; + lemp->tablesize += n*szActionType; for(i=j=0; isorted[i]; if( j==0 ) fprintf(out," /* %5d */ ", i); @@ -4005,6 +4037,7 @@ void ReportTable( if( lemp->has_fallback ){ int mx = lemp->nterminal - 1; while( mx>0 && lemp->symbols[mx]->fallback==0 ){ mx--; } + lemp->tablesize += (mx+1)*szCodeType; for(i=0; i<=mx; i++){ struct symbol *p = lemp->symbols[i]; if( p->fallback==0 ){ From 7e698e9d71606c5f3d4364db26a0f72b2e7ceb4e Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 7 Sep 2015 14:22:24 +0000 Subject: [PATCH 22/25] In the "parse.out" output file from Lemon, show addition the complete text of rules on reduce actions. FossilOrigin-Name: b6ffb7e471e51ff69668154ad2c8790e466c9d37 --- main.mk | 2 +- manifest | 14 +++++------ manifest.uuid | 2 +- tool/lemon.c | 68 +++++++++++++++++++++++++++++++++++++-------------- 4 files changed, 58 insertions(+), 28 deletions(-) diff --git a/main.mk b/main.mk index d07e473be6..3668c84321 100644 --- a/main.mk +++ b/main.mk @@ -582,7 +582,7 @@ parse.h: parse.c parse.c: $(TOP)/src/parse.y lemon $(TOP)/addopcodes.awk cp $(TOP)/src/parse.y . rm -f parse.h - ./lemon $(OPTS) parse.y + ./lemon -s $(OPTS) parse.y mv parse.h parse.h.temp $(NAWK) -f $(TOP)/addopcodes.awk parse.h.temp >parse.h diff --git a/manifest b/manifest index f8137c54e5..28359665c7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\s"Parser\sStatistics"\soutput\s(the\s-s\soption)\sfor\sthe\sLemon\sparser\ngenerator. -D 2015-09-07T02:23:02.396 +C In\sthe\s"parse.out"\soutput\sfile\sfrom\sLemon,\sshow\saddition\sthe\scomplete\stext\nof\srules\son\sreduce\sactions. +D 2015-09-07T14:22:24.531 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -260,7 +260,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk 61821e43596648bfacce2d6283377bee35986131 +F main.mk 58eb74de702467c3b71cdf06f213cefe7f5ce544 F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea F mkopcodeh.awk 0e7f04a8eb90f92259e47d80110e4e98d7ce337a F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 @@ -1338,7 +1338,7 @@ F tool/fuzzershell.c f2fc86dd22df654b28851b85019d3bd007361751 F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4 F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5 F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce -F tool/lemon.c cc515b02a6610ed76c93d49bd01fdb219356d7ac +F tool/lemon.c a110c3850af6b91a553e153141186c32dee58f0d F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862 F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6 @@ -1383,7 +1383,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 47dc24bd1e8f76eb17ba53a883b8984b3e1b2934 -R d6df305b5709e894bdfc542577063f51 +P 809503e4efcdb498d176e8c0794a5ba0882adef2 +R fba651a02e6066be297178ded140cace U drh -Z 643bd9ba035c2e0820f3e9522cf3c1e3 +Z 5f03c60d31dd0f570ea326a36f822715 diff --git a/manifest.uuid b/manifest.uuid index f1edfd5794..31a7538355 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -809503e4efcdb498d176e8c0794a5ba0882adef2 \ No newline at end of file +b6ffb7e471e51ff69668154ad2c8790e466c9d37 \ No newline at end of file diff --git a/tool/lemon.c b/tool/lemon.c index f27fe4d24a..1f9ef7b84d 100644 --- a/tool/lemon.c +++ b/tool/lemon.c @@ -340,7 +340,7 @@ struct state { struct action *ap; /* Array of actions for this state */ int nTknAct, nNtAct; /* Number of actions on terminals and nonterminals */ int iTknOfst, iNtOfst; /* yy_action[] offset for terminals and nonterms */ - int iDflt; /* Default action */ + int iDflt; /* Default action is reduce by this rule */ }; #define NO_OFFSET (-2147483647) @@ -2960,15 +2960,14 @@ void Reprint(struct lemon *lemp) } } -void ConfigPrint(FILE *fp, struct config *cfp) -{ - struct rule *rp; +/* Print a single rule. +*/ +void RulePrint(FILE *fp, struct rule *rp, int iCursor){ struct symbol *sp; int i, j; - rp = cfp->rp; fprintf(fp,"%s ::=",rp->lhs->name); for(i=0; i<=rp->nrhs; i++){ - if( i==cfp->dot ) fprintf(fp," *"); + if( i==iCursor ) fprintf(fp," *"); if( i==rp->nrhs ) break; sp = rp->rhs[i]; if( sp->type==MULTITERMINAL ){ @@ -2982,6 +2981,12 @@ void ConfigPrint(FILE *fp, struct config *cfp) } } +/* Print the rule for a configuration. +*/ +void ConfigPrint(FILE *fp, struct config *cfp){ + RulePrint(fp, cfp->rp, cfp->dot); +} + /* #define TEST */ #if 0 /* Print a set */ @@ -3021,15 +3026,29 @@ char *tag; /* Print an action to the given file descriptor. Return FALSE if ** nothing was actually printed. */ -int PrintAction(struct action *ap, FILE *fp, int indent){ +int PrintAction( + struct action *ap, /* The action to print */ + FILE *fp, /* Print the action here */ + int indent, /* Indent by this amount */ + struct rule **apRule /* All rules by index */ +){ int result = 1; switch( ap->type ){ - case SHIFT: - fprintf(fp,"%*s shift %d",indent,ap->sp->name,ap->x.stp->statenum); + case SHIFT: { + struct state *stp = ap->x.stp; + fprintf(fp,"%*s shift %-7d",indent,ap->sp->name,stp->statenum); + if( stp->nTknAct==0 && stp->nNtAct==0 && apRule ){ + fprintf(fp,"then reduce %d: ", stp->iDflt); + RulePrint(fp, apRule[stp->iDflt], -1); + } break; - case REDUCE: - fprintf(fp,"%*s reduce %d",indent,ap->sp->name,ap->x.rp->index); + } + case REDUCE: { + struct rule *rp = ap->x.rp; + fprintf(fp,"%*s reduce %-7d",indent,ap->sp->name,rp->index); + if( apRule ) RulePrint(fp, apRule[rp->index], -1); break; + } case ACCEPT: fprintf(fp,"%*s accept",indent,ap->sp->name); break; @@ -3038,16 +3057,16 @@ int PrintAction(struct action *ap, FILE *fp, int indent){ break; case SRCONFLICT: case RRCONFLICT: - fprintf(fp,"%*s reduce %-3d ** Parsing conflict **", + fprintf(fp,"%*s reduce %-7d ** Parsing conflict **", indent,ap->sp->name,ap->x.rp->index); break; case SSCONFLICT: - fprintf(fp,"%*s shift %-3d ** Parsing conflict **", + fprintf(fp,"%*s shift %-7d ** Parsing conflict **", indent,ap->sp->name,ap->x.stp->statenum); break; case SH_RESOLVED: if( showPrecedenceConflict ){ - fprintf(fp,"%*s shift %-3d -- dropped by precedence", + fprintf(fp,"%*s shift %-7d -- dropped by precedence", indent,ap->sp->name,ap->x.stp->statenum); }else{ result = 0; @@ -3055,7 +3074,7 @@ int PrintAction(struct action *ap, FILE *fp, int indent){ break; case RD_RESOLVED: if( showPrecedenceConflict ){ - fprintf(fp,"%*s reduce %-3d -- dropped by precedence", + fprintf(fp,"%*s reduce %-7d -- dropped by precedence", indent,ap->sp->name,ap->x.rp->index); }else{ result = 0; @@ -3076,7 +3095,17 @@ void ReportOutput(struct lemon *lemp) struct config *cfp; struct action *ap; FILE *fp; + struct rule **apRule; + apRule = malloc( sizeof(apRule[0])*(lemp->nrule+1) ); + if( apRule ){ + struct rule *x; + memset(apRule, 0, sizeof(apRule[0])*(lemp->nrule+1) ); + for(x=lemp->rule; x; x=x->next){ + assert( x->index>=0 && x->index<(lemp->nrule+1) ); + apRule[x->index] = x; + } + } fp = file_open(lemp,".out","wb"); if( fp==0 ) return; for(i=0; instate; i++){ @@ -3104,7 +3133,7 @@ void ReportOutput(struct lemon *lemp) } fprintf(fp,"\n"); for(ap=stp->ap; ap; ap=ap->next){ - if( PrintAction(ap,fp,30) ) fprintf(fp,"\n"); + if( PrintAction(ap,fp,30,apRule) ) fprintf(fp,"\n"); } fprintf(fp,"\n"); } @@ -3130,6 +3159,7 @@ void ReportOutput(struct lemon *lemp) fprintf(fp, "\n"); } fclose(fp); + free(apRule); return; } @@ -4021,7 +4051,7 @@ void ReportTable( for(i=j=0; isorted[i]; if( j==0 ) fprintf(out," /* %5d */ ", i); - fprintf(out, " %4d,", stp->iDflt); + fprintf(out, " %4d,", stp->iDflt+n); if( j==9 || i==n-1 ){ fprintf(out, "\n"); lineno++; j = 0; @@ -4342,7 +4372,7 @@ void ResortStates(struct lemon *lemp) for(i=0; instate; i++){ stp = lemp->sorted[i]; stp->nTknAct = stp->nNtAct = 0; - stp->iDflt = lemp->nstate + lemp->nrule; + stp->iDflt = lemp->nrule; stp->iTknOfst = NO_OFFSET; stp->iNtOfst = NO_OFFSET; for(ap=stp->ap; ap; ap=ap->next){ @@ -4352,7 +4382,7 @@ void ResortStates(struct lemon *lemp) }else if( ap->sp->indexnsymbol ){ stp->nNtAct++; }else{ - stp->iDflt = compute_action(lemp, ap); + stp->iDflt = compute_action(lemp, ap) - lemp->nstate; } } } From 3bd48ab213bdfd776d04b4e9be4641bc0d0583e4 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 7 Sep 2015 18:23:37 +0000 Subject: [PATCH 23/25] For the Lemon-generated parser, add a new action type SHIFTREDUCE and use it to further compress the parser tables and improve parser performance. FossilOrigin-Name: 531c3974b3d586c1989cde905b2fb4681239a570 --- manifest | 22 +++--- manifest.uuid | 2 +- src/lempar.c | 98 ++++++++++++++++---------- src/parse.y | 2 +- src/tokenize.c | 3 +- test/misc1.test | 2 +- tool/lemon.c | 180 +++++++++++++++++++++++++++++------------------- tool/lempar.c | 99 ++++++++++++++++---------- 8 files changed, 252 insertions(+), 156 deletions(-) diff --git a/manifest b/manifest index 28359665c7..a6e735d796 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sthe\s"parse.out"\soutput\sfile\sfrom\sLemon,\sshow\saddition\sthe\scomplete\stext\nof\srules\son\sreduce\sactions. -D 2015-09-07T14:22:24.531 +C For\sthe\sLemon-generated\sparser,\sadd\sa\snew\saction\stype\sSHIFTREDUCE\sand\suse\sit\nto\sfurther\scompress\sthe\sparser\stables\sand\simprove\sparser\sperformance. +D 2015-09-07T18:23:37.162 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -302,7 +302,7 @@ F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 F src/insert.c 076dc5876e261a9908603d54cfc5344cd680166c F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e -F src/lempar.c 92bafa308607dd985ca389a788cd9e0a2b608712 +F src/lempar.c 406f2e85d2552d88bd4b994cc9c567c0fbc9f483 F src/loadext.c dfcee8c7c032cd0fd55af3e0fc1fcfb01e426df2 F src/main.c e17fcffae4306a9b8334faf3bac80d7396850b54 F src/malloc.c 021012e28a81ffdabf4c30ec3df6ce1f6cc93f1d @@ -328,7 +328,7 @@ F src/os_win.c 40b3af7a47eb1107d0d69e592bec345a3b7b798a F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca F src/pager.c 4784012f80b2197c61ff6eaf4f5c7026d93253fd F src/pager.h 6d435f563b3f7fcae4b84433b76a6ac2730036e2 -F src/parse.y f599aa5e871a493330d567ced93de696f61f48f7 +F src/parse.y 9e1777c68d5bb483d7217327e524dcfe5263b01c F src/pcache.c 24be750c79272e0ca7b6e007bc94999700f3e5ef F src/pcache.h 9968603796240cdf83da7e7bef76edf90619cea9 F src/pcache1.c bf2afe64a3dedb8643c8dcbd94a145cc80ab2a67 @@ -395,7 +395,7 @@ F src/test_vfs.c 3b65d42e18b262805716bd96178c81da8f2d9283 F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 6bbcc9fe50c917864d48287b4792d46d6e873481 -F src/tokenize.c 57cb3720f53f84d811def2069c2b169b6be539a5 +F src/tokenize.c 9655e20ade774e5c8e580634f1359288eba3fada F src/treeview.c 154f0acc622fa3514de8777dcedf4c8a8802b4ce F src/trigger.c 322f23aad694e8f31d384dcfa386d52a48d3c52f F src/update.c 3c5bc9570df3bfafa0db36828406a8a14e4c426e @@ -866,7 +866,7 @@ F test/minmax.test 42fbad0e81afaa6e0de41c960329f2b2c3526efd F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354 F test/minmax4.test 936941484ebdceb8adec7c86b6cd9b6e5e897c1f -F test/misc1.test 3f1c479c5a093a6280f378c0fbff1c2701486660 +F test/misc1.test 0be38a2944dd3e63dfb2899f24446339487d17c7 F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d F test/misc4.test 0d8be3466adf123a7791a66ba2bc8e8d229e87f3 @@ -1338,8 +1338,8 @@ F tool/fuzzershell.c f2fc86dd22df654b28851b85019d3bd007361751 F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4 F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5 F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce -F tool/lemon.c a110c3850af6b91a553e153141186c32dee58f0d -F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc +F tool/lemon.c 0c455691cc1e59a8f782d51a83dd6bbd7c5c44e7 +F tool/lempar.c 1522366692ef87584d4eacdbb1e95bdd0bc7f3b6 F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862 F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6 F tool/mkautoconfamal.sh d1a2da0e15b2ed33d60af35c7e9d483f13a8eb9f @@ -1383,7 +1383,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 809503e4efcdb498d176e8c0794a5ba0882adef2 -R fba651a02e6066be297178ded140cace +P b6ffb7e471e51ff69668154ad2c8790e466c9d37 +R 90541ca0731ebb2fb0e53dfdeffae5a4 U drh -Z 5f03c60d31dd0f570ea326a36f822715 +Z 08f2caec8f48c0982df46628b104ff5c diff --git a/manifest.uuid b/manifest.uuid index 31a7538355..1eb95138eb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b6ffb7e471e51ff69668154ad2c8790e466c9d37 \ No newline at end of file +531c3974b3d586c1989cde905b2fb4681239a570 \ No newline at end of file diff --git a/src/lempar.c b/src/lempar.c index b6c60a25b6..d014ebcc75 100644 --- a/src/lempar.c +++ b/src/lempar.c @@ -56,15 +56,19 @@ ** ParseARG_PDECL A parameter declaration for the %extra_argument ** ParseARG_STORE Code to store %extra_argument into yypParser ** ParseARG_FETCH Code to extract %extra_argument from yypParser -** YYNSTATE the combined number of states. -** YYNRULE the number of rules in the grammar ** YYERRORSYMBOL is the code number of the error symbol. If not ** defined, then do no error processing. +** YYNSTATE the combined number of states. +** YYNRULE the number of rules in the grammar +** YY_MAX_SHIFT Maximum value for shift actions +** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions +** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions +** YY_MIN_REDUCE Maximum value for reduce actions +** YY_ERROR_ACTION The yy_action[] code for syntax error +** YY_ACCEPT_ACTION The yy_action[] code for accept +** YY_NO_ACTION The yy_action[] code for no-op */ %% -#define YY_NO_ACTION (YYNSTATE+YYNRULE+2) -#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1) -#define YY_ERROR_ACTION (YYNSTATE+YYNRULE) /* The yyzerominor constant is used to initialize instances of ** YYMINORTYPE objects to zero. */ @@ -91,16 +95,20 @@ static const YYMINORTYPE yyzerominor = { 0 }; ** Suppose the action integer is N. Then the action is determined as ** follows ** -** 0 <= N < YYNSTATE Shift N. That is, push the lookahead +** 0 <= N <= YY_MAX_SHIFT Shift N. That is, push the lookahead ** token onto the stack and goto state N. ** -** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE. +** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then +** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. ** -** N == YYNSTATE+YYNRULE A syntax error has occurred. +** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE +** and YY_MAX_REDUCE + +** N == YY_ERROR_ACTION A syntax error has occurred. ** -** N == YYNSTATE+YYNRULE+1 The parser accepts its input. +** N == YY_ACCEPT_ACTION The parser accepts its input. ** -** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused +** N == YY_NO_ACTION No such action. Denotes unused ** slots in the yy_action[] table. ** ** The action table is constructed as a single large table named yy_action[]. @@ -499,9 +507,9 @@ static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){ } /* -** Perform a shift action. +** Perform a shift action. Return the number of errors. */ -static void yy_shift( +static int yy_shift( yyParser *yypParser, /* The parser to be shifted */ int yyNewState, /* The new state to shift in */ int yyMajor, /* The major token to shift in */ @@ -517,14 +525,14 @@ static void yy_shift( #if YYSTACKDEPTH>0 if( yypParser->yyidx>=YYSTACKDEPTH ){ yyStackOverflow(yypParser, yypMinor); - return; + return 1; } #else if( yypParser->yyidx>=yypParser->yystksz ){ yyGrowStack(yypParser); if( yypParser->yyidx>=yypParser->yystksz ){ yyStackOverflow(yypParser, yypMinor); - return; + return 1; } } #endif @@ -535,13 +543,18 @@ static void yy_shift( #ifndef NDEBUG if( yyTraceFILE && yypParser->yyidx>0 ){ int i; - fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState); - fprintf(yyTraceFILE,"%sStack:",yyTracePrompt); - for(i=1; i<=yypParser->yyidx; i++) - fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]); - fprintf(yyTraceFILE,"\n"); + if( yyNewStateyyidx; i++) + fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]); + fprintf(yyTraceFILE,"\n"); + }else{ + fprintf(yyTraceFILE,"%sShift *\n",yyTracePrompt); + } } #endif + return 0; } /* The following table contains information about every rule that @@ -574,8 +587,9 @@ static void yy_reduce( #ifndef NDEBUG if( yyTraceFILE && yyruleno>=0 && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ - fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt, - yyRuleName[yyruleno]); + yysize = yyRuleInfo[yyruleno].nrhs; + fprintf(yyTraceFILE, "%sReduce [%s] -> state %d.\n", yyTracePrompt, + yyRuleName[yyruleno], yymsp[-yysize].stateno); } #endif /* NDEBUG */ @@ -613,9 +627,8 @@ static void yy_reduce( yysize = yyRuleInfo[yyruleno].nrhs; yypParser->yyidx -= yysize; yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); - if( yyact < YYNSTATE ){ -#ifdef NDEBUG - /* If we are not debugging and the reduce action popped at least + if( yyact <= YY_MAX_SHIFTREDUCE ){ + /* If the reduce action popped at least ** one element off the stack, then we can push the new element back ** onto the stack here, and skip the stack overflow test in yy_shift(). ** That gives a significant speed improvement. */ @@ -625,13 +638,19 @@ static void yy_reduce( yymsp->stateno = (YYACTIONTYPE)yyact; yymsp->major = (YYCODETYPE)yygoto; yymsp->minor = yygotominor; - }else +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyact); + } #endif - { - yy_shift(yypParser,yyact,yygoto,&yygotominor); + }else{ + if( yy_shift(yypParser,yyact,yygoto,&yygotominor) ) yyact = 0; + } + if( yyact>=YY_MIN_SHIFTREDUCE ){ + yy_reduce(yypParser, yyact - YY_MIN_SHIFTREDUCE); } }else{ - assert( yyact == YYNSTATE + YYNRULE + 1 ); + assert( yyact == YY_ACCEPT_ACTION ); yy_accept(yypParser); } } @@ -755,12 +774,16 @@ void Parse( do{ yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); - if( yyactyyerrcnt--; - yymajor = YYNOCODE; - }else if( yyact < YYNSTATE + YYNRULE ){ - yy_reduce(yypParser,yyact-YYNSTATE); + if( yyact <= YY_MAX_SHIFTREDUCE ){ + if( yy_shift(yypParser,yyact,yymajor,&yyminorunion)==0 ){ + yypParser->yyerrcnt--; + yymajor = YYNOCODE; + if( yyact > YY_MAX_SHIFT ){ + yy_reduce(yypParser, yyact-YY_MIN_SHIFTREDUCE); + } + } + }else if( yyact <= YY_MAX_REDUCE ){ + yy_reduce(yypParser,yyact-YY_MIN_REDUCE); }else{ assert( yyact == YY_ERROR_ACTION ); #ifdef YYERRORSYMBOL @@ -810,7 +833,7 @@ void Parse( yymx != YYERRORSYMBOL && (yyact = yy_find_reduce_action( yypParser->yystack[yypParser->yyidx].stateno, - YYERRORSYMBOL)) >= YYNSTATE + YYERRORSYMBOL)) >= YY_MIN_REDUCE ){ yy_pop_parser_stack(yypParser); } @@ -860,5 +883,10 @@ void Parse( #endif } }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); +#ifdef SQLITE_DEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sReturn\n",yyTracePrompt); + } +#endif return; } diff --git a/src/parse.y b/src/parse.y index e99feeefc1..cdfef7bd3b 100644 --- a/src/parse.y +++ b/src/parse.y @@ -587,7 +587,7 @@ from(A) ::= FROM seltablist(X). { // stl_prefix(A) ::= seltablist(X) joinop(Y). { A = X; - if( ALWAYS(A && A->nSrc>0) ) A->a[A->nSrc-1].fg.jointype = (u8)Y; + if( A && A->nSrc>0 ) A->a[A->nSrc-1].fg.jointype = (u8)Y; } stl_prefix(A) ::= . {A = 0;} seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) indexed_opt(I) diff --git a/src/tokenize.c b/src/tokenize.c index 3d08f75a2a..30a8ad06d0 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -403,6 +403,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ pParse->zTail = zSql; i = 0; assert( pzErrMsg!=0 ); + /* sqlite3ParserTrace(stdout, "parser: "); */ pEngine = sqlite3ParserAlloc(sqlite3Malloc); if( pEngine==0 ){ db->mallocFailed = 1; @@ -458,12 +459,12 @@ abort_parse: assert( zSql[i]==0 ); if( lastTokenParsed!=TK_SEMI ){ sqlite3Parser(pEngine, TK_SEMI, pParse->sLastToken, pParse); - pParse->zTail = &zSql[i]; } if( pParse->rc==SQLITE_OK && db->mallocFailed==0 ){ sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse); } } + pParse->zTail = &zSql[i]; #ifdef YYTRACKMAXSTACKDEPTH sqlite3_mutex_enter(sqlite3MallocMutex()); sqlite3StatusSet(SQLITE_STATUS_PARSER_STACK, diff --git a/test/misc1.test b/test/misc1.test index 25e9bd813e..be4ab8646d 100644 --- a/test/misc1.test +++ b/test/misc1.test @@ -646,7 +646,7 @@ do_catchsql_test misc1-21.1 { } {1 {near "#0": syntax error}} do_catchsql_test misc1-21.2 { VALUES(0,0x0MATCH#0; -} {1 {near ";": syntax error}} +} {1 {near "#0": syntax error}} # 2015-04-15 do_execsql_test misc1-22.1 { diff --git a/tool/lemon.c b/tool/lemon.c index 1f9ef7b84d..2bb3d5ef58 100644 --- a/tool/lemon.c +++ b/tool/lemon.c @@ -316,7 +316,8 @@ enum e_action { RRCONFLICT, /* Was a reduce, but part of a conflict */ SH_RESOLVED, /* Was a shift. Precedence resolved conflict */ RD_RESOLVED, /* Was reduce. Precedence resolved conflict */ - NOT_USED /* Deleted by compression */ + NOT_USED, /* Deleted by compression */ + SHIFTREDUCE /* Shift first, then reduce */ }; /* Every shift or reduce operation is stored as one of the following */ @@ -340,7 +341,9 @@ struct state { struct action *ap; /* Array of actions for this state */ int nTknAct, nNtAct; /* Number of actions on terminals and nonterminals */ int iTknOfst, iNtOfst; /* yy_action[] offset for terminals and nonterms */ - int iDflt; /* Default action is reduce by this rule */ + int iDfltReduce; /* Default action is to REDUCE by this rule */ + struct rule *pDfltReduce;/* The default REDUCE rule. */ + int autoReduce; /* True if this is an auto-reduce state */ }; #define NO_OFFSET (-2147483647) @@ -360,6 +363,7 @@ struct lemon { struct state **sorted; /* Table of states sorted by state number */ struct rule *rule; /* List of all rules */ int nstate; /* Number of states */ + int nxstate; /* nstate with tail degenerate states removed */ int nrule; /* Number of rules */ int nsymbol; /* Number of terminal and nonterminal symbols */ int nterminal; /* Number of terminal symbols */ @@ -484,7 +488,7 @@ static int actioncmp( if( rc==0 ){ rc = (int)ap1->type - (int)ap2->type; } - if( rc==0 && ap1->type==REDUCE ){ + if( rc==0 && (ap1->type==REDUCE || ap1->type==SHIFTREDUCE) ){ rc = ap1->x.rp->index - ap2->x.rp->index; } if( rc==0 ){ @@ -1631,7 +1635,7 @@ int main(int argc, char **argv) stats_line("non-terminal symbols", lem.nsymbol - lem.nterminal); stats_line("total symbols", lem.nsymbol); stats_line("rules", lem.nrule); - stats_line("states", lem.nstate); + stats_line("states", lem.nxstate); stats_line("conflicts", lem.nconflict); stats_line("action table entries", lem.nactiontab); stats_line("total table size (bytes)", lem.tablesize); @@ -3029,24 +3033,25 @@ char *tag; int PrintAction( struct action *ap, /* The action to print */ FILE *fp, /* Print the action here */ - int indent, /* Indent by this amount */ - struct rule **apRule /* All rules by index */ + int indent /* Indent by this amount */ ){ int result = 1; switch( ap->type ){ case SHIFT: { struct state *stp = ap->x.stp; - fprintf(fp,"%*s shift %-7d",indent,ap->sp->name,stp->statenum); - if( stp->nTknAct==0 && stp->nNtAct==0 && apRule ){ - fprintf(fp,"then reduce %d: ", stp->iDflt); - RulePrint(fp, apRule[stp->iDflt], -1); - } + fprintf(fp,"%*s shift %-7d",indent,ap->sp->name,stp->statenum); break; } case REDUCE: { struct rule *rp = ap->x.rp; - fprintf(fp,"%*s reduce %-7d",indent,ap->sp->name,rp->index); - if( apRule ) RulePrint(fp, apRule[rp->index], -1); + fprintf(fp,"%*s reduce %-7d",indent,ap->sp->name,rp->index); + RulePrint(fp, rp, -1); + break; + } + case SHIFTREDUCE: { + struct rule *rp = ap->x.rp; + fprintf(fp,"%*s shift-reduce %-7d",indent,ap->sp->name,rp->index); + RulePrint(fp, rp, -1); break; } case ACCEPT: @@ -3057,16 +3062,16 @@ int PrintAction( break; case SRCONFLICT: case RRCONFLICT: - fprintf(fp,"%*s reduce %-7d ** Parsing conflict **", + fprintf(fp,"%*s reduce %-7d ** Parsing conflict **", indent,ap->sp->name,ap->x.rp->index); break; case SSCONFLICT: - fprintf(fp,"%*s shift %-7d ** Parsing conflict **", + fprintf(fp,"%*s shift %-7d ** Parsing conflict **", indent,ap->sp->name,ap->x.stp->statenum); break; case SH_RESOLVED: if( showPrecedenceConflict ){ - fprintf(fp,"%*s shift %-7d -- dropped by precedence", + fprintf(fp,"%*s shift %-7d -- dropped by precedence", indent,ap->sp->name,ap->x.stp->statenum); }else{ result = 0; @@ -3087,7 +3092,7 @@ int PrintAction( return result; } -/* Generate the "y.output" log file */ +/* Generate the "*.out" log file */ void ReportOutput(struct lemon *lemp) { int i; @@ -3095,20 +3100,10 @@ void ReportOutput(struct lemon *lemp) struct config *cfp; struct action *ap; FILE *fp; - struct rule **apRule; - apRule = malloc( sizeof(apRule[0])*(lemp->nrule+1) ); - if( apRule ){ - struct rule *x; - memset(apRule, 0, sizeof(apRule[0])*(lemp->nrule+1) ); - for(x=lemp->rule; x; x=x->next){ - assert( x->index>=0 && x->index<(lemp->nrule+1) ); - apRule[x->index] = x; - } - } fp = file_open(lemp,".out","wb"); if( fp==0 ) return; - for(i=0; instate; i++){ + for(i=0; inxstate; i++){ stp = lemp->sorted[i]; fprintf(fp,"State %d:\n",stp->statenum); if( lemp->basisflag ) cfp=stp->bp; @@ -3133,7 +3128,7 @@ void ReportOutput(struct lemon *lemp) } fprintf(fp,"\n"); for(ap=stp->ap; ap; ap=ap->next){ - if( PrintAction(ap,fp,30,apRule) ) fprintf(fp,"\n"); + if( PrintAction(ap,fp,30) ) fprintf(fp,"\n"); } fprintf(fp,"\n"); } @@ -3159,7 +3154,6 @@ void ReportOutput(struct lemon *lemp) fprintf(fp, "\n"); } fclose(fp); - free(apRule); return; } @@ -3217,10 +3211,11 @@ PRIVATE int compute_action(struct lemon *lemp, struct action *ap) { int act; switch( ap->type ){ - case SHIFT: act = ap->x.stp->statenum; break; - case REDUCE: act = ap->x.rp->index + lemp->nstate; break; - case ERROR: act = lemp->nstate + lemp->nrule; break; - case ACCEPT: act = lemp->nstate + lemp->nrule + 1; break; + case SHIFT: act = ap->x.stp->statenum; break; + case SHIFTREDUCE: act = ap->x.rp->index + lemp->nstate; break; + case REDUCE: act = ap->x.rp->index + lemp->nstate+lemp->nrule; break; + case ERROR: act = lemp->nstate + lemp->nrule*2; break; + case ACCEPT: act = lemp->nstate + lemp->nrule*2 + 1; break; default: act = -1; break; } return act; @@ -3843,7 +3838,7 @@ void ReportTable( minimum_size_type(0, lemp->nsymbol+1, &szCodeType)); lineno++; fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol+1); lineno++; fprintf(out,"#define YYACTIONTYPE %s\n", - minimum_size_type(0, lemp->nstate+lemp->nrule+5, &szActionType)); lineno++; + minimum_size_type(0,lemp->nstate+lemp->nrule*2+5,&szActionType)); lineno++; if( lemp->wildcard ){ fprintf(out,"#define YYWILDCARD %d\n", lemp->wildcard->index); lineno++; @@ -3879,36 +3874,24 @@ void ReportTable( if( mhflag ){ fprintf(out,"#endif\n"); lineno++; } - fprintf(out,"#define YYNSTATE %d\n",lemp->nstate); lineno++; - fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++; if( lemp->errsym->useCnt ){ - fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++; - fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++; + fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++; + fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++; } if( lemp->has_fallback ){ fprintf(out,"#define YYFALLBACK 1\n"); lineno++; } - tplt_xfer(lemp->name,in,out,&lineno); - /* Generate the action table and its associates: - ** - ** yy_action[] A single table containing all actions. - ** yy_lookahead[] A table containing the lookahead for each entry in - ** yy_action. Used to detect hash collisions. - ** yy_shift_ofst[] For each state, the offset into yy_action for - ** shifting terminals. - ** yy_reduce_ofst[] For each state, the offset into yy_action for - ** shifting non-terminals after a reduce. - ** yy_default[] Default action for each state. + /* Compute the action table, but do not output it yet. The action + ** table must be computed before generating the YYNSTATE macro because + ** we need to know how many states can be eliminated. */ - - /* Compute the actions on all states and count them up */ - ax = (struct axset *) calloc(lemp->nstate*2, sizeof(ax[0])); + ax = (struct axset *) calloc(lemp->nxstate*2, sizeof(ax[0])); if( ax==0 ){ fprintf(stderr,"malloc failed\n"); exit(1); } - for(i=0; instate; i++){ + for(i=0; inxstate; i++){ stp = lemp->sorted[i]; ax[i*2].stp = stp; ax[i*2].isTkn = 1; @@ -3919,15 +3902,12 @@ void ReportTable( } mxTknOfst = mnTknOfst = 0; mxNtOfst = mnNtOfst = 0; - - /* Compute the action table. In order to try to keep the size of the - ** action table to a minimum, the heuristic of placing the largest action - ** sets first is used. - */ - for(i=0; instate*2; i++) ax[i].iOrder = i; - qsort(ax, lemp->nstate*2, sizeof(ax[0]), axset_compare); + /* In an effort to minimize the action table size, use the heuristic + ** of placing the largest action sets first */ + for(i=0; inxstate*2; i++) ax[i].iOrder = i; + qsort(ax, lemp->nxstate*2, sizeof(ax[0]), axset_compare); pActtab = acttab_alloc(); - for(i=0; instate*2 && ax[i].nAction>0; i++){ + for(i=0; inxstate*2 && ax[i].nAction>0; i++){ stp = ax[i].stp; if( ax[i].isTkn ){ for(ap=stp->ap; ap; ap=ap->next){ @@ -3956,6 +3936,34 @@ void ReportTable( } free(ax); + /* Finish rendering the constants now that the action table has + ** been computed */ + fprintf(out,"#define YYNSTATE %d\n",lemp->nxstate); lineno++; + fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++; + fprintf(out,"#define YY_MAX_SHIFT %d\n",lemp->nstate-1); lineno++; + fprintf(out,"#define YY_MIN_SHIFTREDUCE %d\n",lemp->nstate); lineno++; + i = lemp->nstate + lemp->nrule; + fprintf(out,"#define YY_MAX_SHIFTREDUCE %d\n", i-1); lineno++; + fprintf(out,"#define YY_MIN_REDUCE %d\n", i); lineno++; + i = lemp->nstate + lemp->nrule*2; + fprintf(out,"#define YY_MAX_REDUCE %d\n", i-1); lineno++; + fprintf(out,"#define YY_ERROR_ACTION %d\n", i); lineno++; + fprintf(out,"#define YY_ACCEPT_ACTION %d\n", i+1); lineno++; + fprintf(out,"#define YY_NO_ACTION %d\n", i+2); lineno++; + tplt_xfer(lemp->name,in,out,&lineno); + + /* Now output the action table and its associates: + ** + ** yy_action[] A single table containing all actions. + ** yy_lookahead[] A table containing the lookahead for each entry in + ** yy_action. Used to detect hash collisions. + ** yy_shift_ofst[] For each state, the offset into yy_action for + ** shifting terminals. + ** yy_reduce_ofst[] For each state, the offset into yy_action for + ** shifting non-terminals after a reduce. + ** yy_default[] Default action for each state. + */ + /* Output the yy_action table */ lemp->nactiontab = n = acttab_size(pActtab); lemp->tablesize += n*szActionType; @@ -3994,7 +4002,7 @@ void ReportTable( /* Output the yy_shift_ofst[] table */ fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++; - n = lemp->nstate; + n = lemp->nxstate; while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--; fprintf(out, "#define YY_SHIFT_COUNT (%d)\n", n-1); lineno++; fprintf(out, "#define YY_SHIFT_MIN (%d)\n", mnTknOfst); lineno++; @@ -4020,7 +4028,7 @@ void ReportTable( /* Output the yy_reduce_ofst[] table */ fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++; - n = lemp->nstate; + n = lemp->nxstate; while( n>0 && lemp->sorted[n-1]->iNtOfst==NO_OFFSET ) n--; fprintf(out, "#define YY_REDUCE_COUNT (%d)\n", n-1); lineno++; fprintf(out, "#define YY_REDUCE_MIN (%d)\n", mnNtOfst); lineno++; @@ -4046,12 +4054,12 @@ void ReportTable( /* Output the default action table */ fprintf(out, "static const YYACTIONTYPE yy_default[] = {\n"); lineno++; - n = lemp->nstate; + n = lemp->nxstate; lemp->tablesize += n*szActionType; for(i=j=0; isorted[i]; if( j==0 ) fprintf(out," /* %5d */ ", i); - fprintf(out, " %4d,", stp->iDflt+n); + fprintf(out, " %4d,", stp->iDfltReduce+lemp->nstate+lemp->nrule); if( j==9 || i==n-1 ){ fprintf(out, "\n"); lineno++; j = 0; @@ -4284,7 +4292,7 @@ void CompressTables(struct lemon *lemp) struct state *stp; struct action *ap, *ap2; struct rule *rp, *rp2, *rbest; - int nbest, n; + int nbest, n, nshift; int i; int usesWildcard; @@ -4332,6 +4340,32 @@ void CompressTables(struct lemon *lemp) if( ap->type==REDUCE && ap->x.rp==rbest ) ap->type = NOT_USED; } stp->ap = Action_sort(stp->ap); + + for(ap=stp->ap; ap; ap=ap->next){ + if( ap->type==SHIFT ) break; + if( ap->type==REDUCE && ap->x.rp!=rbest ) break; + } + if( ap==0 ){ + stp->autoReduce = 1; + stp->pDfltReduce = rbest; + } + } + + /* Make a second pass over all states and actions. Convert + ** every action that is a SHIFT to an autoReduce state into + ** a SHIFTREDUCE action. + */ + for(i=0; instate; i++){ + stp = lemp->sorted[i]; + for(ap=stp->ap; ap; ap=ap->next){ + struct state *pNextState; + if( ap->type!=SHIFT ) continue; + pNextState = ap->x.stp; + if( pNextState->autoReduce && pNextState->pDfltReduce!=0 ){ + ap->type = SHIFTREDUCE; + ap->x.rp = pNextState->pDfltReduce; + } + } } } @@ -4372,17 +4406,19 @@ void ResortStates(struct lemon *lemp) for(i=0; instate; i++){ stp = lemp->sorted[i]; stp->nTknAct = stp->nNtAct = 0; - stp->iDflt = lemp->nrule; + stp->iDfltReduce = lemp->nrule; /* Init dflt action to "syntax error" */ stp->iTknOfst = NO_OFFSET; stp->iNtOfst = NO_OFFSET; for(ap=stp->ap; ap; ap=ap->next){ - if( compute_action(lemp,ap)>=0 ){ + int iAction = compute_action(lemp,ap); + if( iAction>=0 ){ if( ap->sp->indexnterminal ){ stp->nTknAct++; }else if( ap->sp->indexnsymbol ){ stp->nNtAct++; }else{ - stp->iDflt = compute_action(lemp, ap) - lemp->nstate; + assert( stp->autoReduce==0 || stp->pDfltReduce==ap->x.rp ); + stp->iDfltReduce = iAction - lemp->nstate - lemp->nrule; } } } @@ -4392,6 +4428,10 @@ void ResortStates(struct lemon *lemp) for(i=0; instate; i++){ lemp->sorted[i]->statenum = i; } + lemp->nxstate = lemp->nstate; + while( lemp->nxstate>1 && lemp->sorted[lemp->nxstate-1]->autoReduce ){ + lemp->nxstate--; + } } diff --git a/tool/lempar.c b/tool/lempar.c index fe56d2dc16..ddace228f6 100644 --- a/tool/lempar.c +++ b/tool/lempar.c @@ -50,15 +50,19 @@ ** ParseARG_PDECL A parameter declaration for the %extra_argument ** ParseARG_STORE Code to store %extra_argument into yypParser ** ParseARG_FETCH Code to extract %extra_argument from yypParser -** YYNSTATE the combined number of states. -** YYNRULE the number of rules in the grammar ** YYERRORSYMBOL is the code number of the error symbol. If not ** defined, then do no error processing. +** YYNSTATE the combined number of states. +** YYNRULE the number of rules in the grammar +** YY_MAX_SHIFT Maximum value for shift actions +** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions +** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions +** YY_MIN_REDUCE Maximum value for reduce actions +** YY_ERROR_ACTION The yy_action[] code for syntax error +** YY_ACCEPT_ACTION The yy_action[] code for accept +** YY_NO_ACTION The yy_action[] code for no-op */ %% -#define YY_NO_ACTION (YYNSTATE+YYNRULE+2) -#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1) -#define YY_ERROR_ACTION (YYNSTATE+YYNRULE) /* The yyzerominor constant is used to initialize instances of ** YYMINORTYPE objects to zero. */ @@ -85,16 +89,20 @@ static const YYMINORTYPE yyzerominor = { 0 }; ** Suppose the action integer is N. Then the action is determined as ** follows ** -** 0 <= N < YYNSTATE Shift N. That is, push the lookahead +** 0 <= N <= YY_MAX_SHIFT Shift N. That is, push the lookahead ** token onto the stack and goto state N. ** -** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE. +** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then +** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. ** -** N == YYNSTATE+YYNRULE A syntax error has occurred. +** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE +** and YY_MAX_REDUCE + +** N == YY_ERROR_ACTION A syntax error has occurred. ** -** N == YYNSTATE+YYNRULE+1 The parser accepts its input. +** N == YY_ACCEPT_ACTION The parser accepts its input. ** -** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused +** N == YY_NO_ACTION No such action. Denotes unused ** slots in the yy_action[] table. ** ** The action table is constructed as a single large table named yy_action[]. @@ -489,9 +497,9 @@ static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){ } /* -** Perform a shift action. +** Perform a shift action. Return the number of errors. */ -static void yy_shift( +static int yy_shift( yyParser *yypParser, /* The parser to be shifted */ int yyNewState, /* The new state to shift in */ int yyMajor, /* The major token to shift in */ @@ -507,14 +515,14 @@ static void yy_shift( #if YYSTACKDEPTH>0 if( yypParser->yyidx>=YYSTACKDEPTH ){ yyStackOverflow(yypParser, yypMinor); - return; + return 1; } #else if( yypParser->yyidx>=yypParser->yystksz ){ yyGrowStack(yypParser); if( yypParser->yyidx>=yypParser->yystksz ){ yyStackOverflow(yypParser, yypMinor); - return; + return 1; } } #endif @@ -525,13 +533,18 @@ static void yy_shift( #ifndef NDEBUG if( yyTraceFILE && yypParser->yyidx>0 ){ int i; - fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState); - fprintf(yyTraceFILE,"%sStack:",yyTracePrompt); - for(i=1; i<=yypParser->yyidx; i++) - fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]); - fprintf(yyTraceFILE,"\n"); + if( yyNewStateyyidx; i++) + fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]); + fprintf(yyTraceFILE,"\n"); + }else{ + fprintf(yyTraceFILE,"%sShift *\n",yyTracePrompt); + } } #endif + return 0; } /* The following table contains information about every rule that @@ -564,8 +577,9 @@ static void yy_reduce( #ifndef NDEBUG if( yyTraceFILE && yyruleno>=0 && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ - fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt, - yyRuleName[yyruleno]); + yysize = yyRuleInfo[yyruleno].nrhs; + fprintf(yyTraceFILE, "%sReduce [%s] -> state %d.\n", yyTracePrompt, + yyRuleName[yyruleno], yymsp[-yysize].stateno); } #endif /* NDEBUG */ @@ -602,9 +616,8 @@ static void yy_reduce( yysize = yyRuleInfo[yyruleno].nrhs; yypParser->yyidx -= yysize; yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); - if( yyact < YYNSTATE ){ -#ifdef NDEBUG - /* If we are not debugging and the reduce action popped at least + if( yyact < YY_MAX_SHIFTREDUCE ){ + /* If the reduce action popped at least ** one element off the stack, then we can push the new element back ** onto the stack here, and skip the stack overflow test in yy_shift(). ** That gives a significant speed improvement. */ @@ -614,13 +627,19 @@ static void yy_reduce( yymsp->stateno = (YYACTIONTYPE)yyact; yymsp->major = (YYCODETYPE)yygoto; yymsp->minor = yygotominor; - }else +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyact); + } #endif - { - yy_shift(yypParser,yyact,yygoto,&yygotominor); + }else{ + if( yy_shift(yypParser,yyact,yygoto,&yygotominor) ) yyact = 0; + } + if( yyact>=YY_MIN_SHIFTREDUCE ){ + yy_reduce(yypParser, yyact - YY_MIN_SHIFTREDUCE); } }else{ - assert( yyact == YYNSTATE + YYNRULE + 1 ); + assert( yyact == YY_ACCEPT_ACTION ); yy_accept(yypParser); } } @@ -740,13 +759,16 @@ void Parse( do{ yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); - if( yyactyyerrcnt--; - yymajor = YYNOCODE; - }else if( yyact < YYNSTATE + YYNRULE ){ - yy_reduce(yypParser,yyact-YYNSTATE); + if( yyact <= YY_MAX_SHIFTREDUCE ){ + if( yy_shift(yypParser,yyact,yymajor,&yyminorunion)==0 ){ + yypParser->yyerrcnt--; + yymajor = YYNOCODE; + if( yyact > YY_MAX_SHIFT ){ + yy_reduce(yypParser, yyact-YY_MIN_SHIFTREDUCE); + } + } + }else if( yyact <= YY_MAX_REDUCE ){ + yy_reduce(yypParser,yyact-YY_MIN_REDUCE); }else{ assert( yyact == YY_ERROR_ACTION ); #ifdef YYERRORSYMBOL @@ -796,7 +818,7 @@ void Parse( yymx != YYERRORSYMBOL && (yyact = yy_find_reduce_action( yypParser->yystack[yypParser->yyidx].stateno, - YYERRORSYMBOL)) >= YYNSTATE + YYERRORSYMBOL)) >= YY_MIN_REDUCE ){ yy_pop_parser_stack(yypParser); } @@ -846,5 +868,10 @@ void Parse( #endif } }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sReturn\n",yyTracePrompt); + } +#endif return; } From a248a722cf721cf294bd591ccb2e7398aeb6ecdf Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 7 Sep 2015 19:52:55 +0000 Subject: [PATCH 24/25] Change the parser engine so that it (once again) waits for a lookahead token before reducing, even in a SHIFTREDUCE action. FossilOrigin-Name: 2c17a1358353a0845b039283be79353f033e2491 --- manifest | 20 ++++++------- manifest.uuid | 2 +- src/lempar.c | 76 ++++++++++++++++++++++++----------------------- src/parse.y | 2 +- src/tokenize.c | 2 +- test/misc1.test | 2 +- tool/lempar.c | 78 ++++++++++++++++++++++++++----------------------- 7 files changed, 95 insertions(+), 87 deletions(-) diff --git a/manifest b/manifest index a6e735d796..c4c835e219 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C For\sthe\sLemon-generated\sparser,\sadd\sa\snew\saction\stype\sSHIFTREDUCE\sand\suse\sit\nto\sfurther\scompress\sthe\sparser\stables\sand\simprove\sparser\sperformance. -D 2015-09-07T18:23:37.162 +C Change\sthe\sparser\sengine\sso\sthat\sit\s(once\sagain)\swaits\sfor\sa\slookahead\stoken\nbefore\sreducing,\seven\sin\sa\sSHIFTREDUCE\saction. +D 2015-09-07T19:52:55.484 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -302,7 +302,7 @@ F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 F src/insert.c 076dc5876e261a9908603d54cfc5344cd680166c F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e -F src/lempar.c 406f2e85d2552d88bd4b994cc9c567c0fbc9f483 +F src/lempar.c d98d6c2229d5ed5e628a63819fc53ed5b292d4bd F src/loadext.c dfcee8c7c032cd0fd55af3e0fc1fcfb01e426df2 F src/main.c e17fcffae4306a9b8334faf3bac80d7396850b54 F src/malloc.c 021012e28a81ffdabf4c30ec3df6ce1f6cc93f1d @@ -328,7 +328,7 @@ F src/os_win.c 40b3af7a47eb1107d0d69e592bec345a3b7b798a F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca F src/pager.c 4784012f80b2197c61ff6eaf4f5c7026d93253fd F src/pager.h 6d435f563b3f7fcae4b84433b76a6ac2730036e2 -F src/parse.y 9e1777c68d5bb483d7217327e524dcfe5263b01c +F src/parse.y f599aa5e871a493330d567ced93de696f61f48f7 F src/pcache.c 24be750c79272e0ca7b6e007bc94999700f3e5ef F src/pcache.h 9968603796240cdf83da7e7bef76edf90619cea9 F src/pcache1.c bf2afe64a3dedb8643c8dcbd94a145cc80ab2a67 @@ -395,7 +395,7 @@ F src/test_vfs.c 3b65d42e18b262805716bd96178c81da8f2d9283 F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 6bbcc9fe50c917864d48287b4792d46d6e873481 -F src/tokenize.c 9655e20ade774e5c8e580634f1359288eba3fada +F src/tokenize.c 83c6ed569423a3af83a83973b444cf7123be33a6 F src/treeview.c 154f0acc622fa3514de8777dcedf4c8a8802b4ce F src/trigger.c 322f23aad694e8f31d384dcfa386d52a48d3c52f F src/update.c 3c5bc9570df3bfafa0db36828406a8a14e4c426e @@ -866,7 +866,7 @@ F test/minmax.test 42fbad0e81afaa6e0de41c960329f2b2c3526efd F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354 F test/minmax4.test 936941484ebdceb8adec7c86b6cd9b6e5e897c1f -F test/misc1.test 0be38a2944dd3e63dfb2899f24446339487d17c7 +F test/misc1.test 3f1c479c5a093a6280f378c0fbff1c2701486660 F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d F test/misc4.test 0d8be3466adf123a7791a66ba2bc8e8d229e87f3 @@ -1339,7 +1339,7 @@ F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4 F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5 F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce F tool/lemon.c 0c455691cc1e59a8f782d51a83dd6bbd7c5c44e7 -F tool/lempar.c 1522366692ef87584d4eacdbb1e95bdd0bc7f3b6 +F tool/lempar.c 9bec5f85673746e5ed92084e79931afae443a6be F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862 F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6 F tool/mkautoconfamal.sh d1a2da0e15b2ed33d60af35c7e9d483f13a8eb9f @@ -1383,7 +1383,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P b6ffb7e471e51ff69668154ad2c8790e466c9d37 -R 90541ca0731ebb2fb0e53dfdeffae5a4 +P 531c3974b3d586c1989cde905b2fb4681239a570 +R 9764b1afa291a8128703e02e85f419ca U drh -Z 08f2caec8f48c0982df46628b104ff5c +Z 7cd6903444e24935012e1ca631512fff diff --git a/manifest.uuid b/manifest.uuid index 1eb95138eb..5557c822f6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -531c3974b3d586c1989cde905b2fb4681239a570 \ No newline at end of file +2c17a1358353a0845b039283be79353f033e2491 \ No newline at end of file diff --git a/src/lempar.c b/src/lempar.c index d014ebcc75..f983ff752f 100644 --- a/src/lempar.c +++ b/src/lempar.c @@ -167,9 +167,13 @@ static const YYCODETYPE yyFallback[] = { ** + The semantic value stored at this level of the stack. This is ** the information used by the action routines in the grammar. ** It is sometimes called the "minor" token. +** +** After the "shift" half of a SHIFTREDUCE action, the stateno field +** actually contains the reduce action for the second half of the +** SHIFTREDUCE. */ struct yyStackEntry { - YYACTIONTYPE stateno; /* The state-number */ + YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */ YYCODETYPE major; /* The major token value. This is the code ** number for the token at this stack level */ YYMINORTYPE minor; /* The user-supplied minor token value. This @@ -403,6 +407,7 @@ static int yy_find_shift_action( int i; int stateno = pParser->yystack[pParser->yyidx].stateno; + if( stateno>=YY_MIN_REDUCE ) return stateno; if( stateno>YY_SHIFT_COUNT || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){ return yy_default[stateno]; @@ -506,10 +511,32 @@ static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){ ParseARG_STORE; /* Suppress warning about unused %extra_argument var */ } +/* +** Print tracing information for a SHIFT action +*/ +#ifndef NDEBUG +static void yyTraceShift(yyParser *yypParser, int yyNewState){ + if( yyTraceFILE ){ + int i; + if( yyNewStateyyidx; i++) + fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]); + fprintf(yyTraceFILE,"\n"); + }else{ + fprintf(yyTraceFILE,"%sShift *\n",yyTracePrompt); + } + } +} +#else +# define yyTraceShift(X,Y) +#endif + /* ** Perform a shift action. Return the number of errors. */ -static int yy_shift( +static void yy_shift( yyParser *yypParser, /* The parser to be shifted */ int yyNewState, /* The new state to shift in */ int yyMajor, /* The major token to shift in */ @@ -525,14 +552,14 @@ static int yy_shift( #if YYSTACKDEPTH>0 if( yypParser->yyidx>=YYSTACKDEPTH ){ yyStackOverflow(yypParser, yypMinor); - return 1; + return; } #else if( yypParser->yyidx>=yypParser->yystksz ){ yyGrowStack(yypParser); if( yypParser->yyidx>=yypParser->yystksz ){ yyStackOverflow(yypParser, yypMinor); - return 1; + return; } } #endif @@ -540,21 +567,7 @@ static int yy_shift( yytos->stateno = (YYACTIONTYPE)yyNewState; yytos->major = (YYCODETYPE)yyMajor; yytos->minor = *yypMinor; -#ifndef NDEBUG - if( yyTraceFILE && yypParser->yyidx>0 ){ - int i; - if( yyNewStateyyidx; i++) - fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]); - fprintf(yyTraceFILE,"\n"); - }else{ - fprintf(yyTraceFILE,"%sShift *\n",yyTracePrompt); - } - } -#endif - return 0; + yyTraceShift(yypParser, yyNewState); } /* The following table contains information about every rule that @@ -628,6 +641,7 @@ static void yy_reduce( yypParser->yyidx -= yysize; yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); if( yyact <= YY_MAX_SHIFTREDUCE ){ + if( yyact>YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; /* If the reduce action popped at least ** one element off the stack, then we can push the new element back ** onto the stack here, and skip the stack overflow test in yy_shift(). @@ -638,16 +652,9 @@ static void yy_reduce( yymsp->stateno = (YYACTIONTYPE)yyact; yymsp->major = (YYCODETYPE)yygoto; yymsp->minor = yygotominor; -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyact); - } -#endif + yyTraceShift(yypParser, yyact); }else{ - if( yy_shift(yypParser,yyact,yygoto,&yygotominor) ) yyact = 0; - } - if( yyact>=YY_MIN_SHIFTREDUCE ){ - yy_reduce(yypParser, yyact - YY_MIN_SHIFTREDUCE); + yy_shift(yypParser,yyact,yygoto,&yygotominor); } }else{ assert( yyact == YY_ACCEPT_ACTION ); @@ -775,13 +782,10 @@ void Parse( do{ yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); if( yyact <= YY_MAX_SHIFTREDUCE ){ - if( yy_shift(yypParser,yyact,yymajor,&yyminorunion)==0 ){ - yypParser->yyerrcnt--; - yymajor = YYNOCODE; - if( yyact > YY_MAX_SHIFT ){ - yy_reduce(yypParser, yyact-YY_MIN_SHIFTREDUCE); - } - } + if( yyact > YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; + yy_shift(yypParser,yyact,yymajor,&yyminorunion); + yypParser->yyerrcnt--; + yymajor = YYNOCODE; }else if( yyact <= YY_MAX_REDUCE ){ yy_reduce(yypParser,yyact-YY_MIN_REDUCE); }else{ @@ -883,7 +887,7 @@ void Parse( #endif } }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); -#ifdef SQLITE_DEBUG +#ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sReturn\n",yyTracePrompt); } diff --git a/src/parse.y b/src/parse.y index cdfef7bd3b..e99feeefc1 100644 --- a/src/parse.y +++ b/src/parse.y @@ -587,7 +587,7 @@ from(A) ::= FROM seltablist(X). { // stl_prefix(A) ::= seltablist(X) joinop(Y). { A = X; - if( A && A->nSrc>0 ) A->a[A->nSrc-1].fg.jointype = (u8)Y; + if( ALWAYS(A && A->nSrc>0) ) A->a[A->nSrc-1].fg.jointype = (u8)Y; } stl_prefix(A) ::= . {A = 0;} seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) indexed_opt(I) diff --git a/src/tokenize.c b/src/tokenize.c index 30a8ad06d0..6b5ad27901 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -459,12 +459,12 @@ abort_parse: assert( zSql[i]==0 ); if( lastTokenParsed!=TK_SEMI ){ sqlite3Parser(pEngine, TK_SEMI, pParse->sLastToken, pParse); + pParse->zTail = &zSql[i]; } if( pParse->rc==SQLITE_OK && db->mallocFailed==0 ){ sqlite3Parser(pEngine, 0, pParse->sLastToken, pParse); } } - pParse->zTail = &zSql[i]; #ifdef YYTRACKMAXSTACKDEPTH sqlite3_mutex_enter(sqlite3MallocMutex()); sqlite3StatusSet(SQLITE_STATUS_PARSER_STACK, diff --git a/test/misc1.test b/test/misc1.test index be4ab8646d..25e9bd813e 100644 --- a/test/misc1.test +++ b/test/misc1.test @@ -646,7 +646,7 @@ do_catchsql_test misc1-21.1 { } {1 {near "#0": syntax error}} do_catchsql_test misc1-21.2 { VALUES(0,0x0MATCH#0; -} {1 {near "#0": syntax error}} +} {1 {near ";": syntax error}} # 2015-04-15 do_execsql_test misc1-22.1 { diff --git a/tool/lempar.c b/tool/lempar.c index ddace228f6..161632a6c7 100644 --- a/tool/lempar.c +++ b/tool/lempar.c @@ -161,9 +161,13 @@ static const YYCODETYPE yyFallback[] = { ** + The semantic value stored at this level of the stack. This is ** the information used by the action routines in the grammar. ** It is sometimes called the "minor" token. +** +** After the "shift" half of a SHIFTREDUCE action, the stateno field +** actually contains the reduce action for the second half of the +** SHIFTREDUCE. */ struct yyStackEntry { - YYACTIONTYPE stateno; /* The state-number */ + YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */ YYCODETYPE major; /* The major token value. This is the code ** number for the token at this stack level */ YYMINORTYPE minor; /* The user-supplied minor token value. This @@ -392,7 +396,8 @@ static int yy_find_shift_action( ){ int i; int stateno = pParser->yystack[pParser->yyidx].stateno; - + + if( stateno>=YY_MIN_REDUCE ) return stateno; if( stateno>YY_SHIFT_COUNT || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){ return yy_default[stateno]; @@ -496,10 +501,32 @@ static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){ ParseARG_STORE; /* Suppress warning about unused %extra_argument var */ } +/* +** Print tracing information for a SHIFT action +*/ +#ifndef NDEBUG +static void yyTraceShift(yyParser *yypParser, int yyNewState){ + if( yyTraceFILE ){ + int i; + if( yyNewStateyyidx; i++) + fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]); + fprintf(yyTraceFILE,"\n"); + }else{ + fprintf(yyTraceFILE,"%sShift *\n",yyTracePrompt); + } + } +} +#else +# define yyTraceShift(X,Y) +#endif + /* ** Perform a shift action. Return the number of errors. */ -static int yy_shift( +static void yy_shift( yyParser *yypParser, /* The parser to be shifted */ int yyNewState, /* The new state to shift in */ int yyMajor, /* The major token to shift in */ @@ -515,14 +542,14 @@ static int yy_shift( #if YYSTACKDEPTH>0 if( yypParser->yyidx>=YYSTACKDEPTH ){ yyStackOverflow(yypParser, yypMinor); - return 1; + return; } #else if( yypParser->yyidx>=yypParser->yystksz ){ yyGrowStack(yypParser); if( yypParser->yyidx>=yypParser->yystksz ){ yyStackOverflow(yypParser, yypMinor); - return 1; + return; } } #endif @@ -530,21 +557,7 @@ static int yy_shift( yytos->stateno = (YYACTIONTYPE)yyNewState; yytos->major = (YYCODETYPE)yyMajor; yytos->minor = *yypMinor; -#ifndef NDEBUG - if( yyTraceFILE && yypParser->yyidx>0 ){ - int i; - if( yyNewStateyyidx; i++) - fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]); - fprintf(yyTraceFILE,"\n"); - }else{ - fprintf(yyTraceFILE,"%sShift *\n",yyTracePrompt); - } - } -#endif - return 0; + yyTraceShift(yypParser, yyNewState); } /* The following table contains information about every rule that @@ -616,7 +629,8 @@ static void yy_reduce( yysize = yyRuleInfo[yyruleno].nrhs; yypParser->yyidx -= yysize; yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); - if( yyact < YY_MAX_SHIFTREDUCE ){ + if( yyact <= YY_MAX_SHIFTREDUCE ){ + if( yyact>YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; /* If the reduce action popped at least ** one element off the stack, then we can push the new element back ** onto the stack here, and skip the stack overflow test in yy_shift(). @@ -627,16 +641,9 @@ static void yy_reduce( yymsp->stateno = (YYACTIONTYPE)yyact; yymsp->major = (YYCODETYPE)yygoto; yymsp->minor = yygotominor; -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyact); - } -#endif + yyTraceShift(yypParser, yyact); }else{ - if( yy_shift(yypParser,yyact,yygoto,&yygotominor) ) yyact = 0; - } - if( yyact>=YY_MIN_SHIFTREDUCE ){ - yy_reduce(yypParser, yyact - YY_MIN_SHIFTREDUCE); + yy_shift(yypParser,yyact,yygoto,&yygotominor); } }else{ assert( yyact == YY_ACCEPT_ACTION ); @@ -760,13 +767,10 @@ void Parse( do{ yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); if( yyact <= YY_MAX_SHIFTREDUCE ){ - if( yy_shift(yypParser,yyact,yymajor,&yyminorunion)==0 ){ - yypParser->yyerrcnt--; - yymajor = YYNOCODE; - if( yyact > YY_MAX_SHIFT ){ - yy_reduce(yypParser, yyact-YY_MIN_SHIFTREDUCE); - } - } + if( yyact > YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; + yy_shift(yypParser,yyact,yymajor,&yyminorunion); + yypParser->yyerrcnt--; + yymajor = YYNOCODE; }else if( yyact <= YY_MAX_REDUCE ){ yy_reduce(yypParser,yyact-YY_MIN_REDUCE); }else{ From ae2a4084a238ade6c977f04906983c74b5e9fa60 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 7 Sep 2015 20:02:39 +0000 Subject: [PATCH 25/25] Fix an unreachable branch in the new parse automaton. FossilOrigin-Name: e9d604b4306a86faae315ac3cba59bf07d1b665c --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/lempar.c | 7 +++---- tool/lempar.c | 7 +++---- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index c4c835e219..41384f854b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\sthe\sparser\sengine\sso\sthat\sit\s(once\sagain)\swaits\sfor\sa\slookahead\stoken\nbefore\sreducing,\seven\sin\sa\sSHIFTREDUCE\saction. -D 2015-09-07T19:52:55.484 +C Fix\san\sunreachable\sbranch\sin\sthe\snew\sparse\sautomaton. +D 2015-09-07T20:02:39.726 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -302,7 +302,7 @@ F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 F src/insert.c 076dc5876e261a9908603d54cfc5344cd680166c F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e -F src/lempar.c d98d6c2229d5ed5e628a63819fc53ed5b292d4bd +F src/lempar.c d344a95d60c24e2f490ee59db9784b1b17439012 F src/loadext.c dfcee8c7c032cd0fd55af3e0fc1fcfb01e426df2 F src/main.c e17fcffae4306a9b8334faf3bac80d7396850b54 F src/malloc.c 021012e28a81ffdabf4c30ec3df6ce1f6cc93f1d @@ -1339,7 +1339,7 @@ F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4 F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5 F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce F tool/lemon.c 0c455691cc1e59a8f782d51a83dd6bbd7c5c44e7 -F tool/lempar.c 9bec5f85673746e5ed92084e79931afae443a6be +F tool/lempar.c 3617143ddb9b176c3605defe6a9c798793280120 F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862 F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6 F tool/mkautoconfamal.sh d1a2da0e15b2ed33d60af35c7e9d483f13a8eb9f @@ -1383,7 +1383,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 531c3974b3d586c1989cde905b2fb4681239a570 -R 9764b1afa291a8128703e02e85f419ca +P 2c17a1358353a0845b039283be79353f033e2491 +R c7dbe034ff98374fe795187c44f7caee U drh -Z 7cd6903444e24935012e1ca631512fff +Z f008d623d9e778806c4a18c7c6cec2d4 diff --git a/manifest.uuid b/manifest.uuid index 5557c822f6..0b0630a9a0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2c17a1358353a0845b039283be79353f033e2491 \ No newline at end of file +e9d604b4306a86faae315ac3cba59bf07d1b665c \ No newline at end of file diff --git a/src/lempar.c b/src/lempar.c index f983ff752f..5e5a11aeaa 100644 --- a/src/lempar.c +++ b/src/lempar.c @@ -408,10 +408,9 @@ static int yy_find_shift_action( int stateno = pParser->yystack[pParser->yyidx].stateno; if( stateno>=YY_MIN_REDUCE ) return stateno; - if( stateno>YY_SHIFT_COUNT - || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){ - return yy_default[stateno]; - } + assert( stateno <= YY_SHIFT_COUNT ); + i = yy_shift_ofst[stateno]; + if( i==YY_SHIFT_USE_DFLT ) return yy_default[stateno]; assert( iLookAhead!=YYNOCODE ); i += iLookAhead; if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ diff --git a/tool/lempar.c b/tool/lempar.c index 161632a6c7..cdf4ca5a1a 100644 --- a/tool/lempar.c +++ b/tool/lempar.c @@ -398,10 +398,9 @@ static int yy_find_shift_action( int stateno = pParser->yystack[pParser->yyidx].stateno; if( stateno>=YY_MIN_REDUCE ) return stateno; - if( stateno>YY_SHIFT_COUNT - || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){ - return yy_default[stateno]; - } + assert( stateno <= YY_SHIFT_COUNT ); + i = yy_shift_ofst[stateno]; + if( i==YY_SHIFT_USE_DFLT ) return yy_default[stateno]; assert( iLookAhead!=YYNOCODE ); i += iLookAhead; if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){