Merge parser enhancements and other improvements and bug fixes from trunk.
FossilOrigin-Name: 9cf3e51bcce1268dbb22cc8fa77160db3cb72746
This commit is contained in:
commit
9a5a469c7a
2
main.mk
2
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
|
||||
|
||||
|
69
manifest
69
manifest
@ -1,5 +1,5 @@
|
||||
C Merge\sthe\slatest\strunk\schanges,\sand\sespecially\sthe\sfix\sfor\sallowing\nstrings\sas\sidentifiers\sin\sCREATE\sINDEX\sstatements.
|
||||
D 2015-09-04T17:22:03.833
|
||||
C Merge\sparser\senhancements\sand\sother\simprovements\sand\sbug\sfixes\sfrom\strunk.
|
||||
D 2015-09-07T20:22:22.153
|
||||
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
|
||||
@ -275,7 +275,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 4911e1f18fc11b60edbc6410643e938762969a6a
|
||||
F src/analyze.c e4ad1495090d6b7bf58b927e1267fc211ad5e7da
|
||||
F src/analyze.c 4c308880cf53c558070cb8513bdff4ffb1a38a77
|
||||
F src/attach.c e944d0052b577703b9b83aac1638452ff42a8395
|
||||
F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
|
||||
F src/backup.c 4d9134dc988a87838c06056c89c0e8c4700a0452
|
||||
@ -284,25 +284,25 @@ F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79
|
||||
F src/btree.c 7663d05467277379fd29ae44eb82bcbdee7f618f
|
||||
F src/btree.h 00d4cdb747c4172a5566faf037116985dbbc377e
|
||||
F src/btreeInt.h df0e92901c6fbb01aa8fab3cfbcdaaba2654fd04
|
||||
F src/build.c 1f4fc82459d47ffb5a8ee3823fd648059b6508be
|
||||
F src/build.c 0620be86a9ad5acbeb3b3d757c06559d4fd26c27
|
||||
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 5b4835982c31f12b256dc4d814363a11e7ef34cf
|
||||
F src/expr.c af2c72f8938413c0c367554962b0d8761121f39d
|
||||
F src/delete.c 6792c80d7fb54c4df9f7680413952600e7439492
|
||||
F src/expr.c 3a76afcdac925294c39903b7002ddb9e5fd29863
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 83e1baba999bed3144ea5a2143fc922edf51135f
|
||||
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
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c bcff4a416177ed90faa8dba65f0266ddad2aeb76
|
||||
F src/insert.c 076dc5876e261a9908603d54cfc5344cd680166c
|
||||
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e
|
||||
F src/lempar.c 92bafa308607dd985ca389a788cd9e0a2b608712
|
||||
F src/lempar.c d344a95d60c24e2f490ee59db9784b1b17439012
|
||||
F src/loadext.c dfcee8c7c032cd0fd55af3e0fc1fcfb01e426df2
|
||||
F src/main.c e17fcffae4306a9b8334faf3bac80d7396850b54
|
||||
F src/malloc.c 021012e28a81ffdabf4c30ec3df6ce1f6cc93f1d
|
||||
@ -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 7762c8ec907379204f2ed751a0e33663ab1c14d7
|
||||
F src/mutex_w32.c 2e025e6642eaf27597403690980f560d1a91f62c
|
||||
F src/notify.c 9711a7575036f0d3040ba61bc6e217f13a9888e7
|
||||
F src/os.c 8fd25588eeba74068d41102d26810e216999b6c8
|
||||
F src/os.h 3e57a24e2794a94d3cf2342c6d9a884888cd96bf
|
||||
@ -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 f2ef256786a6435efddd64a632fea89c8be62215
|
||||
F src/resolve.c 3126f7694b8ce0f97282d7dd3a5198b8fa18dce9
|
||||
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
|
||||
F src/select.c c17613385bc6b095c421b1f30548814f5fd8a9b2
|
||||
F src/shell.c bbe2bab590b7dd04dd8f9119d4473cb8c52906e3
|
||||
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 8657f11e821b15500810020f529f452113fe6532
|
||||
F src/sqliteInt.h 56a362369786fd1b49dbf6d49b6d7f8167af540d
|
||||
F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46
|
||||
F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179
|
||||
F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e
|
||||
@ -395,10 +395,10 @@ 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/treeview.c 46036cbbceada0836833531b2d963edbca3d9cfa
|
||||
F src/tokenize.c 83c6ed569423a3af83a83973b444cf7123be33a6
|
||||
F src/treeview.c 154f0acc622fa3514de8777dcedf4c8a8802b4ce
|
||||
F src/trigger.c 322f23aad694e8f31d384dcfa386d52a48d3c52f
|
||||
F src/update.c 795fba8ebadeb194285b0a73a07f7ad5ae4d0410
|
||||
F src/update.c 3c5bc9570df3bfafa0db36828406a8a14e4c426e
|
||||
F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
|
||||
F src/util.c fc612367108b74573c5fd13a85d0a23027f438bd
|
||||
F src/vacuum.c 983cc3754718ef169a6ea9aef86798bd28106f21
|
||||
@ -407,8 +407,8 @@ F src/vdbe.h 4bc88bd0e06f8046ee6ab7487c0015e85ad949ad
|
||||
F src/vdbeInt.h 8b54e01ad0463590e7cffabce0bc36da9ee4f816
|
||||
F src/vdbeapi.c bda74ef4b5103d7b4a4be36f936d3cf2b56a7d6f
|
||||
F src/vdbeaux.c 4988b83d1e1989ee554b2fa4ca18f3606a78437c
|
||||
F src/vdbeblob.c 4f2e8e075d238392df98c5e03a64342465b03f90
|
||||
F src/vdbemem.c ae38a0d35ae71cf604381a887c170466ba518090
|
||||
F src/vdbeblob.c 1d7b97115e7bbac4c318db416d2ca83fc779544a
|
||||
F src/vdbemem.c 19b3036aa4d676e7103b0fb5efd6327da455f915
|
||||
F src/vdbesort.c f5009e7a35e3065635d8918b9a31f498a499976b
|
||||
F src/vdbetrace.c 8befe829faff6d9e6f6e4dee5a7d3f85cc85f1a0
|
||||
F src/vtab.c 2ecfe020c10e0a0c7b078203fdba2fae844744bc
|
||||
@ -416,10 +416,10 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb
|
||||
F src/wal.c 5a86298540935981eea840050f66e516dbe536af
|
||||
F src/wal.h 361b16891d2772294b138054c84f5a3bad6e9d05
|
||||
F src/walker.c 2e14d17f592d176b6dc879c33fbdec4fbccaa2ba
|
||||
F src/where.c f0e08e4f1f66ba1a0f5b70c5161cb031ce1fb858
|
||||
F src/whereInt.h 901c17c1e3c82745ad9b85b4471543fa59c980e9
|
||||
F src/wherecode.c c0d9b1c7c7c827998016809851d2ddc529de0fee
|
||||
F src/whereexpr.c 1a308d1ee5144890d21ea9cf70d49bc96a83432b
|
||||
F src/where.c ed1cd1cb0434bca9f4a5379582c637bf393b34ac
|
||||
F src/whereInt.h 292d3ac90da4eab1e03ac8452f1add746bcafaa1
|
||||
F src/wherecode.c 6ac8599523f4840d9efac335329f627ebf3f79fd
|
||||
F src/whereexpr.c 2473e4350e30f9b55d1c6a8f66ca23c689f23f1d
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
@ -778,7 +778,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 f835d5e13ca163bd78c4459ca15fd2e4ed487407
|
||||
F test/index3.test fa3e49bbaa4f38091c9c742e36a1abe67c4ef1fc
|
||||
F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6
|
||||
@ -786,6 +786,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 4feec154aadacb033b41acc1760a18edc4c60470
|
||||
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
|
||||
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
|
||||
F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371
|
||||
@ -947,7 +948,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 5b7509f384f4f6fae1af3c8c104c8ca299fea18d
|
||||
F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798
|
||||
F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09
|
||||
F test/savepoint.test c671fdbd34cd3bfe1518a777526ada595180cf8d
|
||||
@ -1340,8 +1341,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 b9109f59b57e7b6f101c4fe644c8361ba6dee969
|
||||
F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc
|
||||
F tool/lemon.c 0c455691cc1e59a8f782d51a83dd6bbd7c5c44e7
|
||||
F tool/lempar.c 3617143ddb9b176c3605defe6a9c798793280120
|
||||
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
|
||||
F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6
|
||||
F tool/mkautoconfamal.sh d1a2da0e15b2ed33d60af35c7e9d483f13a8eb9f
|
||||
@ -1385,7 +1386,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 c0bf92eca4d3d4666e8a0476ef30fa8123de1cb0 3d3df79bfaf9dbc7aa711c08a19d2f6dbe744b32
|
||||
R ee966f158d53b77675f43896974b25d9
|
||||
P a9b84885aa572b7f92e5aafa246af328d13e3e6e 99b992fa840707711d99f8d05b62412f7008cd93
|
||||
R 1f63598c79312b65d8d15c45f84006b8
|
||||
U drh
|
||||
Z b1cc08beaad97d2b36ffef8ab5faa1b6
|
||||
Z f300497e9766a2b3b13269e90f17caa1
|
||||
|
@ -1 +1 @@
|
||||
a9b84885aa572b7f92e5aafa246af328d13e3e6e
|
||||
9cf3e51bcce1268dbb22cc8fa77160db3cb72746
|
@ -1186,6 +1186,7 @@ static void analyzeOneTable(
|
||||
regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
|
||||
for(j=0; j<pPk->nKeyCol; j++){
|
||||
k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
|
||||
assert( k>=0 && k<pTab->nCol );
|
||||
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; i<nCol; i++){
|
||||
i16 iCol = pIdx->aiColumn[i];
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regCol+i);
|
||||
sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, i, regCol+i);
|
||||
}
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol, regSample);
|
||||
#endif
|
||||
|
103
src/build.c
103
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
|
||||
@ -1309,7 +1310,8 @@ void sqlite3AddPrimaryKey(
|
||||
nTerm = pList->nExpr;
|
||||
for(i=0; i<nTerm; i++){
|
||||
Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[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; iCol<pTab->nCol; iCol++){
|
||||
if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){
|
||||
@ -2913,7 +2915,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 */
|
||||
@ -3085,7 +3086,8 @@ Index *sqlite3CreateIndex(
|
||||
*/
|
||||
for(i=0; i<pList->nExpr; 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));
|
||||
}
|
||||
}
|
||||
@ -3126,40 +3128,52 @@ 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; i<pList->nExpr; i++, pListItem++){
|
||||
const char *zColName;
|
||||
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 */
|
||||
|
||||
sqlite3StringToId(pListItem->pExpr);
|
||||
sqlite3ResolveSelfReference(pParse, pTab, NC_IdxExpr, pListItem->pExpr, 0);
|
||||
if( pParse->nErr ) goto exit_create_index;
|
||||
pCExpr = sqlite3ExprSkipCollate(pListItem->pExpr);
|
||||
if( pCExpr->op!=TK_ID ){
|
||||
sqlite3ErrorMsg(pParse, "indexes on expressions not yet supported");
|
||||
continue;
|
||||
if( pCExpr->op!=TK_COLUMN ){
|
||||
if( pTab==pParse->pNewTable ){
|
||||
sqlite3ErrorMsg(pParse, "expressions prohibited in PRIMARY KEY and "
|
||||
"UNIQUE constraints");
|
||||
goto exit_create_index;
|
||||
}
|
||||
if( pIndex->aColExpr==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;
|
||||
pIndex->uniqNotNull = 0;
|
||||
}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;
|
||||
}
|
||||
zColName = pCExpr->u.zToken;
|
||||
for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; 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;
|
||||
}
|
||||
assert( j<=0x7fff );
|
||||
pIndex->aiColumn[i] = (i16)j;
|
||||
zColl = 0;
|
||||
if( pListItem->pExpr->op==TK_COLLATE ){
|
||||
int nColl;
|
||||
zColl = pListItem->pExpr->u.zToken;
|
||||
@ -3169,21 +3183,26 @@ 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;
|
||||
}
|
||||
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; j<pPk->nKeyCol; j++){
|
||||
int x = pPk->aiColumn[j];
|
||||
assert( x>=0 );
|
||||
if( hasColumn(pIndex->aiColumn, pIndex->nKeyCol, x) ){
|
||||
pIndex->nColumn--;
|
||||
}else{
|
||||
@ -3234,6 +3253,7 @@ Index *sqlite3CreateIndex(
|
||||
for(k=0; k<pIdx->nKeyCol; 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];
|
||||
@ -3265,6 +3285,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) );
|
||||
@ -3294,7 +3315,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;
|
||||
@ -4124,12 +4145,16 @@ void sqlite3UniqueConstraint(
|
||||
Table *pTab = pIdx->pTable;
|
||||
|
||||
sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200);
|
||||
for(j=0; j<pIdx->nKeyCol; j++){
|
||||
char *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; j<pIdx->nKeyCol; 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,
|
||||
|
16
src/date.c
16
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),
|
||||
|
15
src/delete.c
15
src/delete.c
@ -411,6 +411,7 @@ void sqlite3DeleteFrom(
|
||||
/* Extract the rowid or primary key for the current row */
|
||||
if( pPk ){
|
||||
for(i=0; i<nPk; i++){
|
||||
assert( pPk->aiColumn[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; j<nCol; j++){
|
||||
if( pPrior && pPrior->aiColumn[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.
|
||||
|
39
src/expr.c
39
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;
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
@ -2678,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) */
|
||||
@ -3765,7 +3784,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;
|
||||
}
|
||||
}
|
||||
|
12
src/func.c
12
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 ),
|
||||
|
41
src/insert.c
41
src/insert.c
@ -88,7 +88,18 @@ const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
|
||||
}
|
||||
for(n=0; n<pIdx->nColumn; 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{
|
||||
char aff;
|
||||
assert( x==(-2) );
|
||||
assert( pIdx->aColExpr!=0 );
|
||||
aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
|
||||
if( aff==0 ) aff = SQLITE_AFF_BLOB;
|
||||
pIdx->zColAff[n] = aff;
|
||||
}
|
||||
}
|
||||
pIdx->zColAff[n] = 0;
|
||||
}
|
||||
@ -1394,15 +1405,22 @@ void sqlite3GenerateConstraintChecks(
|
||||
for(i=0; i<pIdx->nColumn; 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));
|
||||
@ -1723,6 +1741,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 */
|
||||
}
|
||||
|
109
src/lempar.c
109
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[].
|
||||
@ -159,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
|
||||
@ -395,10 +407,10 @@ static int yy_find_shift_action(
|
||||
int i;
|
||||
int stateno = pParser->yystack[pParser->yyidx].stateno;
|
||||
|
||||
if( stateno>YY_SHIFT_COUNT
|
||||
|| (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){
|
||||
return yy_default[stateno];
|
||||
}
|
||||
if( stateno>=YY_MIN_REDUCE ) return 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 ){
|
||||
@ -499,7 +511,29 @@ static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
|
||||
}
|
||||
|
||||
/*
|
||||
** Perform a shift action.
|
||||
** Print tracing information for a SHIFT action
|
||||
*/
|
||||
#ifndef NDEBUG
|
||||
static void yyTraceShift(yyParser *yypParser, int yyNewState){
|
||||
if( yyTraceFILE ){
|
||||
int i;
|
||||
if( yyNewState<YYNSTATE ){
|
||||
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");
|
||||
}else{
|
||||
fprintf(yyTraceFILE,"%sShift *\n",yyTracePrompt);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define yyTraceShift(X,Y)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Perform a shift action. Return the number of errors.
|
||||
*/
|
||||
static void yy_shift(
|
||||
yyParser *yypParser, /* The parser to be shifted */
|
||||
@ -532,16 +566,7 @@ static void yy_shift(
|
||||
yytos->stateno = (YYACTIONTYPE)yyNewState;
|
||||
yytos->major = (YYCODETYPE)yyMajor;
|
||||
yytos->minor = *yypMinor;
|
||||
#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");
|
||||
}
|
||||
#endif
|
||||
yyTraceShift(yypParser, yyNewState);
|
||||
}
|
||||
|
||||
/* The following table contains information about every rule that
|
||||
@ -574,8 +599,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 +639,9 @@ 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( 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().
|
||||
** That gives a significant speed improvement. */
|
||||
@ -625,13 +651,12 @@ static void yy_reduce(
|
||||
yymsp->stateno = (YYACTIONTYPE)yyact;
|
||||
yymsp->major = (YYCODETYPE)yygoto;
|
||||
yymsp->minor = yygotominor;
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
yyTraceShift(yypParser, yyact);
|
||||
}else{
|
||||
yy_shift(yypParser,yyact,yygoto,&yygotominor);
|
||||
}
|
||||
}else{
|
||||
assert( yyact == YYNSTATE + YYNRULE + 1 );
|
||||
assert( yyact == YY_ACCEPT_ACTION );
|
||||
yy_accept(yypParser);
|
||||
}
|
||||
}
|
||||
@ -755,12 +780,13 @@ void Parse(
|
||||
|
||||
do{
|
||||
yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
|
||||
if( yyact<YYNSTATE ){
|
||||
if( yyact <= YY_MAX_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 < YYNSTATE + YYNRULE ){
|
||||
yy_reduce(yypParser,yyact-YYNSTATE);
|
||||
}else if( yyact <= YY_MAX_REDUCE ){
|
||||
yy_reduce(yypParser,yyact-YY_MIN_REDUCE);
|
||||
}else{
|
||||
assert( yyact == YY_ERROR_ACTION );
|
||||
#ifdef YYERRORSYMBOL
|
||||
@ -810,7 +836,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 +886,10 @@ void Parse(
|
||||
#endif
|
||||
}
|
||||
}while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
|
||||
#ifndef NDEBUG
|
||||
if( yyTraceFILE ){
|
||||
fprintf(yyTraceFILE,"%sReturn\n",yyTracePrompt);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -80,6 +80,17 @@ static int pthreadMutexNotheld(sqlite3_mutex *p){
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** 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();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize and deinitialize the mutex subsystem.
|
||||
*/
|
||||
|
@ -77,6 +77,19 @@ static int winMutexNotheld(sqlite3_mutex *p){
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** 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
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize and deinitialize the mutex subsystem.
|
||||
*/
|
||||
|
@ -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
|
||||
@ -547,36 +515,25 @@ 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.
|
||||
*/
|
||||
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 */
|
||||
){
|
||||
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 ){
|
||||
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 +618,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
Expr *pRight;
|
||||
|
||||
/* if( pSrcList==0 ) break; */
|
||||
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 ){
|
||||
zDb = 0;
|
||||
@ -690,7 +649,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);
|
||||
zId = pExpr->u.zToken;
|
||||
nId = sqlite3Strlen30(zId);
|
||||
pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
|
||||
@ -738,9 +697,18 @@ 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_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 ){
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
|
||||
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
|
||||
@ -786,8 +754,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);
|
||||
sqlite3WalkSelect(pWalker, pExpr->x.pSelect);
|
||||
assert( pNC->nRef>=nRef );
|
||||
if( nRef!=pNC->nRef ){
|
||||
@ -797,8 +764,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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1501,14 +1467,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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -1385,18 +1385,20 @@ 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_SLOCHNG 0x2000 /* "Slow Change". Value constant during a
|
||||
** single query - might change over time */
|
||||
|
||||
/*
|
||||
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
|
||||
@ -1412,6 +1414,12 @@ 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_SLOCHNG 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
|
||||
** the C functions xStep and xFinal. The first four parameters
|
||||
@ -1432,11 +1440,14 @@ 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_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_CONSTANT|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, \
|
||||
@ -1872,6 +1883,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 */
|
||||
@ -2121,9 +2133,10 @@ 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 _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
|
||||
@ -2392,6 +2405,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 */
|
||||
|
||||
/*
|
||||
@ -2661,7 +2675,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 */
|
||||
@ -3178,6 +3192,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);
|
||||
@ -3362,6 +3377,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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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; i<pIdx->nKeyCol; 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; i<nPk; i++){
|
||||
assert( pPk->aiColumn[i]>=(-1) );
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pPk->aiColumn[i],
|
||||
iPk+i);
|
||||
}
|
||||
|
@ -247,7 +247,8 @@ int sqlite3_blob_open(
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
int j;
|
||||
for(j=0; j<pIdx->nKeyCol; 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";
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
87
src/where.c
87
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; k<pWC->nTerm; 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,11 +276,14 @@ 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;
|
||||
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 +304,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=<expr> 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
|
||||
@ -373,6 +382,25 @@ 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 && iCol<pIdx->nColumn );
|
||||
j = pIdx->aiColumn[iCol];
|
||||
if( j>=0 ){
|
||||
return pIdx->pTable->aCol[j].notNull;
|
||||
}else if( j==(-1) ){
|
||||
return 1;
|
||||
}else{
|
||||
assert( j==(-2) );
|
||||
return 0; /* Assume an indexed expression can always yield a NULL */
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if the DISTINCT expression-list passed as the third argument
|
||||
** is redundant.
|
||||
@ -423,12 +451,9 @@ static int isDistinctRedundant(
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( !IsUniqueIndex(pIdx) ) continue;
|
||||
for(i=0; i<pIdx->nKeyCol; 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 ){
|
||||
@ -780,6 +805,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;
|
||||
assert( pTerm->u.leftColumn>=(-1) );
|
||||
nTerm++;
|
||||
}
|
||||
|
||||
@ -835,6 +861,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;
|
||||
assert( pTerm->u.leftColumn>=(-1) );
|
||||
pIdxCons[j].iColumn = pTerm->u.leftColumn;
|
||||
pIdxCons[j].iTermOffset = i;
|
||||
op = (u8)pTerm->eOperator & WO_ALL;
|
||||
@ -2126,7 +2153,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 +2173,15 @@ static int whereLoopAddBtreeIndex(
|
||||
if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
|
||||
|
||||
assert( pNew->u.btree.nEq<pProbe->nColumn );
|
||||
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 +2194,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 +2231,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) || (iCol>0 && nInMul==0 && saved_nEq==pProbe->nKeyCol-1) ){
|
||||
if( iCol>=0 && pProbe->uniqNotNull==0 ){
|
||||
pNew->wsFlags |= WHERE_UNQ_WANTED;
|
||||
}else{
|
||||
@ -2258,7 +2285,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 +3812,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
|
||||
) continue;
|
||||
opMask = pIdx->uniqNotNull ? (WO_EQ|WO_IS) : WO_EQ;
|
||||
for(j=0; j<pIdx->nKeyCol; 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;
|
||||
@ -4025,14 +4052,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<<N.
|
||||
**
|
||||
** The rule of the previous sentence ensures thta if X is the bitmask for
|
||||
** a table T, then X-1 is the bitmask for all other tables to the left of T.
|
||||
** Knowing the bitmask for all tables to the left of a left join is
|
||||
** important. Ticket #3015.
|
||||
**
|
||||
** Note that bitmasks are created for all pTabList->nSrc tables in
|
||||
** pTabList, not just the first nTabList tables. nTabList is normally
|
||||
@ -4043,14 +4068,10 @@ WhereInfo *sqlite3WhereBegin(
|
||||
createMask(pMaskSet, pTabList->a[ii].iCursor);
|
||||
sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC);
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
Bitmask toTheLeft = 0;
|
||||
for(ii=0; ii<pTabList->nSrc; ii++){
|
||||
Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor);
|
||||
assert( (m-1)==toTheLeft );
|
||||
toTheLeft |= m;
|
||||
}
|
||||
#ifdef SQLITE_DEBUG
|
||||
for(ii=0; ii<pTabList->nSrc; ii++){
|
||||
Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor);
|
||||
assert( m==MASKBIT(ii) );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -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[] */
|
||||
|
@ -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 "<expr>";
|
||||
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,24 +70,22 @@ 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<nEq; i++){
|
||||
char *z = aiColumn[i] < 0 ? "rowid" : aCol[aiColumn[i]].zName;
|
||||
const char *z = explainIndexColumnName(pIndex, i);
|
||||
if( i ) sqlite3StrAccumAppend(pStr, " AND ", 5);
|
||||
sqlite3XPrintf(pStr, 0, i>=nSkip ? "%s=?" : "ANY(%s)", z);
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -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; i<pIdx->nKeyCol; 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,16 +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;
|
||||
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 */
|
||||
@ -903,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;
|
||||
|
@ -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
|
||||
#
|
||||
|
222
test/indexexpr1.test
Normal file
222
test/indexexpr1.test
Normal file
@ -0,0 +1,222 @@
|
||||
# 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)
|
||||
/* 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),
|
||||
('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/}
|
||||
|
||||
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-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;
|
||||
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_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());
|
||||
} {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}}
|
||||
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}}
|
||||
|
||||
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'}}
|
||||
|
||||
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
|
@ -144,6 +144,8 @@ do_test rowid-2.8 {
|
||||
execsql {SELECT x FROM t1 ORDER BY x}
|
||||
} {1 3 5 7 9}
|
||||
|
||||
if 0 { # With the index-on-expressions enhancement, creating
|
||||
# an index on ROWID has become possible.
|
||||
# We cannot index by ROWID
|
||||
#
|
||||
do_test rowid-2.9 {
|
||||
@ -162,6 +164,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.
|
||||
|
289
tool/lemon.c
289
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.
|
||||
**
|
||||
@ -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 */
|
||||
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 */
|
||||
@ -385,7 +389,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 */
|
||||
@ -483,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 ){
|
||||
@ -1375,14 +1380,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;
|
||||
}
|
||||
@ -1480,6 +1487,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)
|
||||
{
|
||||
@ -1611,10 +1630,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.nxstate);
|
||||
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);
|
||||
@ -1873,7 +1897,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++;
|
||||
@ -2939,15 +2964,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 ){
|
||||
@ -2961,6 +2985,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 */
|
||||
@ -3000,15 +3030,30 @@ 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 */
|
||||
){
|
||||
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);
|
||||
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);
|
||||
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:
|
||||
fprintf(fp,"%*s accept",indent,ap->sp->name);
|
||||
break;
|
||||
@ -3017,16 +3062,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;
|
||||
@ -3034,7 +3079,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;
|
||||
@ -3047,7 +3092,7 @@ int PrintAction(struct action *ap, FILE *fp, int indent){
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Generate the "y.output" log file */
|
||||
/* Generate the "*.out" log file */
|
||||
void ReportOutput(struct lemon *lemp)
|
||||
{
|
||||
int i;
|
||||
@ -3058,7 +3103,7 @@ void ReportOutput(struct lemon *lemp)
|
||||
|
||||
fp = file_open(lemp,".out","wb");
|
||||
if( fp==0 ) return;
|
||||
for(i=0; i<lemp->nstate; i++){
|
||||
for(i=0; i<lemp->nxstate; i++){
|
||||
stp = lemp->sorted[i];
|
||||
fprintf(fp,"State %d:\n",stp->statenum);
|
||||
if( lemp->basisflag ) cfp=stp->bp;
|
||||
@ -3166,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;
|
||||
@ -3228,7 +3274,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 +3360,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 +3560,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;
|
||||
@ -3647,24 +3703,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;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3728,7 +3792,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;
|
||||
@ -3769,10 +3835,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*2+5,&szActionType)); lineno++;
|
||||
if( lemp->wildcard ){
|
||||
fprintf(out,"#define YYWILDCARD %d\n",
|
||||
lemp->wildcard->index); lineno++;
|
||||
@ -3808,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; i<lemp->nstate; i++){
|
||||
for(i=0; i<lemp->nxstate; i++){
|
||||
stp = lemp->sorted[i];
|
||||
ax[i*2].stp = stp;
|
||||
ax[i*2].isTkn = 1;
|
||||
@ -3848,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; i<lemp->nstate*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; i<lemp->nxstate*2; i++) ax[i].iOrder = i;
|
||||
qsort(ax, lemp->nxstate*2, sizeof(ax[0]), axset_compare);
|
||||
pActtab = acttab_alloc();
|
||||
for(i=0; i<lemp->nstate*2 && ax[i].nAction>0; i++){
|
||||
for(i=0; i<lemp->nxstate*2 && ax[i].nAction>0; i++){
|
||||
stp = ax[i].stp;
|
||||
if( ax[i].isTkn ){
|
||||
for(ap=stp->ap; ap; ap=ap->next){
|
||||
@ -3885,8 +3936,37 @@ 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 */
|
||||
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; i<n; i++){
|
||||
@ -3904,6 +3984,7 @@ void ReportTable(
|
||||
fprintf(out, "};\n"); lineno++;
|
||||
|
||||
/* Output the yy_lookahead table */
|
||||
lemp->tablesize += n*szCodeType;
|
||||
fprintf(out,"static const YYCODETYPE yy_lookahead[] = {\n"); lineno++;
|
||||
for(i=j=0; i<n; i++){
|
||||
int la = acttab_yylookahead(pActtab, i);
|
||||
@ -3921,13 +4002,14 @@ 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++;
|
||||
fprintf(out, "#define YY_SHIFT_MAX (%d)\n", mxTknOfst); lineno++;
|
||||
fprintf(out, "static const %s yy_shift_ofst[] = {\n",
|
||||
minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++;
|
||||
minimum_size_type(mnTknOfst-1, mxTknOfst, &sz)); lineno++;
|
||||
lemp->tablesize += n*sz;
|
||||
for(i=j=0; i<n; i++){
|
||||
int ofst;
|
||||
stp = lemp->sorted[i];
|
||||
@ -3946,13 +4028,14 @@ 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++;
|
||||
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; i<n; i++){
|
||||
int ofst;
|
||||
stp = lemp->sorted[i];
|
||||
@ -3971,11 +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; i<n; i++){
|
||||
stp = lemp->sorted[i];
|
||||
if( j==0 ) fprintf(out," /* %5d */ ", i);
|
||||
fprintf(out, " %4d,", stp->iDflt);
|
||||
fprintf(out, " %4d,", stp->iDfltReduce+lemp->nstate+lemp->nrule);
|
||||
if( j==9 || i==n-1 ){
|
||||
fprintf(out, "\n"); lineno++;
|
||||
j = 0;
|
||||
@ -3991,6 +4075,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 ){
|
||||
@ -4207,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;
|
||||
|
||||
@ -4255,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; i<lemp->nstate; 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4295,17 +4406,19 @@ void ResortStates(struct lemon *lemp)
|
||||
for(i=0; i<lemp->nstate; i++){
|
||||
stp = lemp->sorted[i];
|
||||
stp->nTknAct = stp->nNtAct = 0;
|
||||
stp->iDflt = lemp->nstate + 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->index<lemp->nterminal ){
|
||||
stp->nTknAct++;
|
||||
}else if( ap->sp->index<lemp->nsymbol ){
|
||||
stp->nNtAct++;
|
||||
}else{
|
||||
stp->iDflt = compute_action(lemp, ap);
|
||||
assert( stp->autoReduce==0 || stp->pDfltReduce==ap->x.rp );
|
||||
stp->iDfltReduce = iAction - lemp->nstate - lemp->nrule;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4315,6 +4428,10 @@ void ResortStates(struct lemon *lemp)
|
||||
for(i=0; i<lemp->nstate; i++){
|
||||
lemp->sorted[i]->statenum = i;
|
||||
}
|
||||
lemp->nxstate = lemp->nstate;
|
||||
while( lemp->nxstate>1 && lemp->sorted[lemp->nxstate-1]->autoReduce ){
|
||||
lemp->nxstate--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
112
tool/lempar.c
112
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[].
|
||||
@ -153,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
|
||||
@ -384,11 +396,11 @@ static int yy_find_shift_action(
|
||||
){
|
||||
int i;
|
||||
int stateno = pParser->yystack[pParser->yyidx].stateno;
|
||||
|
||||
if( stateno>YY_SHIFT_COUNT
|
||||
|| (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){
|
||||
return yy_default[stateno];
|
||||
}
|
||||
|
||||
if( stateno>=YY_MIN_REDUCE ) return 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 ){
|
||||
@ -489,7 +501,29 @@ static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
|
||||
}
|
||||
|
||||
/*
|
||||
** Perform a shift action.
|
||||
** Print tracing information for a SHIFT action
|
||||
*/
|
||||
#ifndef NDEBUG
|
||||
static void yyTraceShift(yyParser *yypParser, int yyNewState){
|
||||
if( yyTraceFILE ){
|
||||
int i;
|
||||
if( yyNewState<YYNSTATE ){
|
||||
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");
|
||||
}else{
|
||||
fprintf(yyTraceFILE,"%sShift *\n",yyTracePrompt);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define yyTraceShift(X,Y)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Perform a shift action. Return the number of errors.
|
||||
*/
|
||||
static void yy_shift(
|
||||
yyParser *yypParser, /* The parser to be shifted */
|
||||
@ -522,16 +556,7 @@ static void yy_shift(
|
||||
yytos->stateno = (YYACTIONTYPE)yyNewState;
|
||||
yytos->major = (YYCODETYPE)yyMajor;
|
||||
yytos->minor = *yypMinor;
|
||||
#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");
|
||||
}
|
||||
#endif
|
||||
yyTraceShift(yypParser, yyNewState);
|
||||
}
|
||||
|
||||
/* The following table contains information about every rule that
|
||||
@ -564,8 +589,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 +628,9 @@ 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( 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().
|
||||
** That gives a significant speed improvement. */
|
||||
@ -614,13 +640,12 @@ static void yy_reduce(
|
||||
yymsp->stateno = (YYACTIONTYPE)yyact;
|
||||
yymsp->major = (YYCODETYPE)yygoto;
|
||||
yymsp->minor = yygotominor;
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
yyTraceShift(yypParser, yyact);
|
||||
}else{
|
||||
yy_shift(yypParser,yyact,yygoto,&yygotominor);
|
||||
}
|
||||
}else{
|
||||
assert( yyact == YYNSTATE + YYNRULE + 1 );
|
||||
assert( yyact == YY_ACCEPT_ACTION );
|
||||
yy_accept(yypParser);
|
||||
}
|
||||
}
|
||||
@ -740,13 +765,13 @@ void Parse(
|
||||
|
||||
do{
|
||||
yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
|
||||
if( yyact<YYNSTATE ){
|
||||
assert( !yyendofinput ); /* Impossible to shift the $ token */
|
||||
if( yyact <= YY_MAX_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 < YYNSTATE + YYNRULE ){
|
||||
yy_reduce(yypParser,yyact-YYNSTATE);
|
||||
}else if( yyact <= YY_MAX_REDUCE ){
|
||||
yy_reduce(yypParser,yyact-YY_MIN_REDUCE);
|
||||
}else{
|
||||
assert( yyact == YY_ERROR_ACTION );
|
||||
#ifdef YYERRORSYMBOL
|
||||
@ -796,7 +821,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 +871,10 @@ void Parse(
|
||||
#endif
|
||||
}
|
||||
}while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
|
||||
#ifndef NDEBUG
|
||||
if( yyTraceFILE ){
|
||||
fprintf(yyTraceFILE,"%sReturn\n",yyTracePrompt);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user