1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Merge parser enhancements and other improvements and bug fixes from trunk.

FossilOrigin-Name: 9cf3e51bcce1268dbb22cc8fa77160db3cb72746
This commit is contained in:
drh
2015-09-07 20:22:22 +00:00
32 changed files with 986 additions and 420 deletions

View File

@@ -582,7 +582,7 @@ parse.h: parse.c
parse.c: $(TOP)/src/parse.y lemon $(TOP)/addopcodes.awk parse.c: $(TOP)/src/parse.y lemon $(TOP)/addopcodes.awk
cp $(TOP)/src/parse.y . cp $(TOP)/src/parse.y .
rm -f parse.h rm -f parse.h
./lemon $(OPTS) parse.y ./lemon -s $(OPTS) parse.y
mv parse.h parse.h.temp mv parse.h parse.h.temp
$(NAWK) -f $(TOP)/addopcodes.awk parse.h.temp >parse.h $(NAWK) -f $(TOP)/addopcodes.awk parse.h.temp >parse.h

View File

@@ -1,5 +1,5 @@
C Merge\sthe\slatest\strunk\schanges,\sand\sespecially\sthe\sfix\sfor\sallowing\nstrings\sas\sidentifiers\sin\sCREATE\sINDEX\sstatements. C Merge\sparser\senhancements\sand\sother\simprovements\sand\sbug\sfixes\sfrom\strunk.
D 2015-09-04T17:22:03.833 D 2015-09-07T20:22:22.153
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239 F Makefile.in f85066ce844a28b671aaeeff320921cd0ce36239
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -260,7 +260,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
F main.mk 61821e43596648bfacce2d6283377bee35986131 F main.mk 58eb74de702467c3b71cdf06f213cefe7f5ce544
F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
F mkopcodeh.awk 0e7f04a8eb90f92259e47d80110e4e98d7ce337a F mkopcodeh.awk 0e7f04a8eb90f92259e47d80110e4e98d7ce337a
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
@@ -275,7 +275,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F src/alter.c 4911e1f18fc11b60edbc6410643e938762969a6a F src/alter.c 4911e1f18fc11b60edbc6410643e938762969a6a
F src/analyze.c e4ad1495090d6b7bf58b927e1267fc211ad5e7da F src/analyze.c 4c308880cf53c558070cb8513bdff4ffb1a38a77
F src/attach.c e944d0052b577703b9b83aac1638452ff42a8395 F src/attach.c e944d0052b577703b9b83aac1638452ff42a8395
F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
F src/backup.c 4d9134dc988a87838c06056c89c0e8c4700a0452 F src/backup.c 4d9134dc988a87838c06056c89c0e8c4700a0452
@@ -284,25 +284,25 @@ F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79
F src/btree.c 7663d05467277379fd29ae44eb82bcbdee7f618f F src/btree.c 7663d05467277379fd29ae44eb82bcbdee7f618f
F src/btree.h 00d4cdb747c4172a5566faf037116985dbbc377e F src/btree.h 00d4cdb747c4172a5566faf037116985dbbc377e
F src/btreeInt.h df0e92901c6fbb01aa8fab3cfbcdaaba2654fd04 F src/btreeInt.h df0e92901c6fbb01aa8fab3cfbcdaaba2654fd04
F src/build.c 1f4fc82459d47ffb5a8ee3823fd648059b6508be F src/build.c 0620be86a9ad5acbeb3b3d757c06559d4fd26c27
F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f
F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b
F src/date.c 8ec787fed4929d8ccdf6b1bc360fccc3e1d2ca58 F src/date.c fb1c99172017dcc8e237339132c91a21a0788584
F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a
F src/delete.c 5b4835982c31f12b256dc4d814363a11e7ef34cf F src/delete.c 6792c80d7fb54c4df9f7680413952600e7439492
F src/expr.c af2c72f8938413c0c367554962b0d8761121f39d F src/expr.c 3a76afcdac925294c39903b7002ddb9e5fd29863
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 83e1baba999bed3144ea5a2143fc922edf51135f F src/fkey.c 83e1baba999bed3144ea5a2143fc922edf51135f
F src/func.c 824bea430d3a2b7dbc62806ad54da8fdb8ed9e3f F src/func.c ecdd69ec6a1e406f04cc73324be2ebbf6354197f
F src/global.c 508e4087f7b41d688e4762dcf4d4fe28cfbc87f9 F src/global.c 508e4087f7b41d688e4762dcf4d4fe28cfbc87f9
F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
F src/insert.c bcff4a416177ed90faa8dba65f0266ddad2aeb76 F src/insert.c 076dc5876e261a9908603d54cfc5344cd680166c
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e
F src/lempar.c 92bafa308607dd985ca389a788cd9e0a2b608712 F src/lempar.c d344a95d60c24e2f490ee59db9784b1b17439012
F src/loadext.c dfcee8c7c032cd0fd55af3e0fc1fcfb01e426df2 F src/loadext.c dfcee8c7c032cd0fd55af3e0fc1fcfb01e426df2
F src/main.c e17fcffae4306a9b8334faf3bac80d7396850b54 F src/main.c e17fcffae4306a9b8334faf3bac80d7396850b54
F src/malloc.c 021012e28a81ffdabf4c30ec3df6ce1f6cc93f1d F src/malloc.c 021012e28a81ffdabf4c30ec3df6ce1f6cc93f1d
@@ -313,11 +313,11 @@ F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
F src/mem5.c 61eeb90134f9a5be6c2e68d8daae7628b25953fb F src/mem5.c 61eeb90134f9a5be6c2e68d8daae7628b25953fb
F src/memjournal.c 3eb2c0b51adbd869cb6a44780323f05fa904dc85 F src/memjournal.c 3eb2c0b51adbd869cb6a44780323f05fa904dc85
F src/msvc.h d9ba56c6851227ab44b3f228a35f3f5772296495 F src/msvc.h d9ba56c6851227ab44b3f228a35f3f5772296495
F src/mutex.c 529e95739f815300a33c73fd8a7d6bdf0c24bd18 F src/mutex.c a39809c6c33f1ebc9cc781186c338ad90433e1e7
F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85 F src/mutex.h 012503b51ccfcf85b8b3846709a4c60a5839f16c
F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4 F src/mutex_noop.c 9d4309c075ba9cc7249e19412d3d62f7f94839c4
F src/mutex_unix.c b0d280089df0f49545f1318f45d61d07d2f674a8 F src/mutex_unix.c 7762c8ec907379204f2ed751a0e33663ab1c14d7
F src/mutex_w32.c b601f9e3073f7bd2c1f42a8c0ce59e42d6a08f85 F src/mutex_w32.c 2e025e6642eaf27597403690980f560d1a91f62c
F src/notify.c 9711a7575036f0d3040ba61bc6e217f13a9888e7 F src/notify.c 9711a7575036f0d3040ba61bc6e217f13a9888e7
F src/os.c 8fd25588eeba74068d41102d26810e216999b6c8 F src/os.c 8fd25588eeba74068d41102d26810e216999b6c8
F src/os.h 3e57a24e2794a94d3cf2342c6d9a884888cd96bf F src/os.h 3e57a24e2794a94d3cf2342c6d9a884888cd96bf
@@ -337,14 +337,14 @@ F src/pragma.h 631a91c8b0e6ca8f051a1d8a4a0da4150e04620a
F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1 F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1
F src/printf.c 0c4bcdd1c2e2521024f0a69cb5eb334f86b3652a F src/printf.c 0c4bcdd1c2e2521024f0a69cb5eb334f86b3652a
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
F src/resolve.c f2ef256786a6435efddd64a632fea89c8be62215 F src/resolve.c 3126f7694b8ce0f97282d7dd3a5198b8fa18dce9
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
F src/select.c c17613385bc6b095c421b1f30548814f5fd8a9b2 F src/select.c c17613385bc6b095c421b1f30548814f5fd8a9b2
F src/shell.c bbe2bab590b7dd04dd8f9119d4473cb8c52906e3 F src/shell.c 6332ef06db1390ef812cfdff1fc97b4fd76cdd42
F src/sqlite.h.in 378bebc8fe6a88bade25e5f23b7e6123fdc64b00 F src/sqlite.h.in 378bebc8fe6a88bade25e5f23b7e6123fdc64b00
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
F src/sqlite3ext.h f700e6a9dd1fdcccc9951ab022b366fb66b9e413 F src/sqlite3ext.h f700e6a9dd1fdcccc9951ab022b366fb66b9e413
F src/sqliteInt.h 8657f11e821b15500810020f529f452113fe6532 F src/sqliteInt.h 56a362369786fd1b49dbf6d49b6d7f8167af540d
F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46
F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179
F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e
@@ -395,10 +395,10 @@ F src/test_vfs.c 3b65d42e18b262805716bd96178c81da8f2d9283
F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698 F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 6bbcc9fe50c917864d48287b4792d46d6e873481 F src/threads.c 6bbcc9fe50c917864d48287b4792d46d6e873481
F src/tokenize.c 57cb3720f53f84d811def2069c2b169b6be539a5 F src/tokenize.c 83c6ed569423a3af83a83973b444cf7123be33a6
F src/treeview.c 46036cbbceada0836833531b2d963edbca3d9cfa F src/treeview.c 154f0acc622fa3514de8777dcedf4c8a8802b4ce
F src/trigger.c 322f23aad694e8f31d384dcfa386d52a48d3c52f F src/trigger.c 322f23aad694e8f31d384dcfa386d52a48d3c52f
F src/update.c 795fba8ebadeb194285b0a73a07f7ad5ae4d0410 F src/update.c 3c5bc9570df3bfafa0db36828406a8a14e4c426e
F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
F src/util.c fc612367108b74573c5fd13a85d0a23027f438bd F src/util.c fc612367108b74573c5fd13a85d0a23027f438bd
F src/vacuum.c 983cc3754718ef169a6ea9aef86798bd28106f21 F src/vacuum.c 983cc3754718ef169a6ea9aef86798bd28106f21
@@ -407,8 +407,8 @@ F src/vdbe.h 4bc88bd0e06f8046ee6ab7487c0015e85ad949ad
F src/vdbeInt.h 8b54e01ad0463590e7cffabce0bc36da9ee4f816 F src/vdbeInt.h 8b54e01ad0463590e7cffabce0bc36da9ee4f816
F src/vdbeapi.c bda74ef4b5103d7b4a4be36f936d3cf2b56a7d6f F src/vdbeapi.c bda74ef4b5103d7b4a4be36f936d3cf2b56a7d6f
F src/vdbeaux.c 4988b83d1e1989ee554b2fa4ca18f3606a78437c F src/vdbeaux.c 4988b83d1e1989ee554b2fa4ca18f3606a78437c
F src/vdbeblob.c 4f2e8e075d238392df98c5e03a64342465b03f90 F src/vdbeblob.c 1d7b97115e7bbac4c318db416d2ca83fc779544a
F src/vdbemem.c ae38a0d35ae71cf604381a887c170466ba518090 F src/vdbemem.c 19b3036aa4d676e7103b0fb5efd6327da455f915
F src/vdbesort.c f5009e7a35e3065635d8918b9a31f498a499976b F src/vdbesort.c f5009e7a35e3065635d8918b9a31f498a499976b
F src/vdbetrace.c 8befe829faff6d9e6f6e4dee5a7d3f85cc85f1a0 F src/vdbetrace.c 8befe829faff6d9e6f6e4dee5a7d3f85cc85f1a0
F src/vtab.c 2ecfe020c10e0a0c7b078203fdba2fae844744bc F src/vtab.c 2ecfe020c10e0a0c7b078203fdba2fae844744bc
@@ -416,10 +416,10 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb
F src/wal.c 5a86298540935981eea840050f66e516dbe536af F src/wal.c 5a86298540935981eea840050f66e516dbe536af
F src/wal.h 361b16891d2772294b138054c84f5a3bad6e9d05 F src/wal.h 361b16891d2772294b138054c84f5a3bad6e9d05
F src/walker.c 2e14d17f592d176b6dc879c33fbdec4fbccaa2ba F src/walker.c 2e14d17f592d176b6dc879c33fbdec4fbccaa2ba
F src/where.c f0e08e4f1f66ba1a0f5b70c5161cb031ce1fb858 F src/where.c ed1cd1cb0434bca9f4a5379582c637bf393b34ac
F src/whereInt.h 901c17c1e3c82745ad9b85b4471543fa59c980e9 F src/whereInt.h 292d3ac90da4eab1e03ac8452f1add746bcafaa1
F src/wherecode.c c0d9b1c7c7c827998016809851d2ddc529de0fee F src/wherecode.c 6ac8599523f4840d9efac335329f627ebf3f79fd
F src/whereexpr.c 1a308d1ee5144890d21ea9cf70d49bc96a83432b F src/whereexpr.c 2473e4350e30f9b55d1c6a8f66ca23c689f23f1d
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@@ -778,7 +778,7 @@ F test/incrvacuum.test d2a6ddf5e429720b5fe502766af747915ccf6c32
F test/incrvacuum2.test 676c41428765d58f1da7dbe659ef27726d3d30ac F test/incrvacuum2.test 676c41428765d58f1da7dbe659ef27726d3d30ac
F test/incrvacuum3.test 75256fb1377e7c39ef2de62bfc42bbff67be295a F test/incrvacuum3.test 75256fb1377e7c39ef2de62bfc42bbff67be295a
F test/incrvacuum_ioerr.test 6ae2f783424e47a0033304808fe27789cf93e635 F test/incrvacuum_ioerr.test 6ae2f783424e47a0033304808fe27789cf93e635
F test/index.test 4d990005a67a36984e4f1a5f1bdccea8d08da4ee F test/index.test fe3c7a1aad82af92623747e9c3f3aa94ccd51238
F test/index2.test f835d5e13ca163bd78c4459ca15fd2e4ed487407 F test/index2.test f835d5e13ca163bd78c4459ca15fd2e4ed487407
F test/index3.test fa3e49bbaa4f38091c9c742e36a1abe67c4ef1fc F test/index3.test fa3e49bbaa4f38091c9c742e36a1abe67c4ef1fc
F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6 F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6
@@ -786,6 +786,7 @@ F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7
F test/index6.test 7102ec371414c42dfb1d5ca37eb4519aa9edc23a F test/index6.test 7102ec371414c42dfb1d5ca37eb4519aa9edc23a
F test/index7.test 9c6765a74fc3fcde7aebc5b3bd40d98df14a527c F test/index7.test 9c6765a74fc3fcde7aebc5b3bd40d98df14a527c
F test/indexedby.test 5f527a78bae74c61b8046ae3037f9dfb0bf0c353 F test/indexedby.test 5f527a78bae74c61b8046ae3037f9dfb0bf0c353
F test/indexexpr1.test 4feec154aadacb033b41acc1760a18edc4c60470
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7 F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371 F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371
@@ -947,7 +948,7 @@ F test/rollback2.test fc14cf6d1a2b250d2735ef16124b971bce152f14
F test/rollbackfault.test 6a004f71087cc399296cffbb5429ea6da655ae65 F test/rollbackfault.test 6a004f71087cc399296cffbb5429ea6da655ae65
F test/rowallock.test 3f88ec6819489d0b2341c7a7528ae17c053ab7cc F test/rowallock.test 3f88ec6819489d0b2341c7a7528ae17c053ab7cc
F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81 F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
F test/rowid.test 742b5741584a8a44fd83e856cc2896688401d645 F test/rowid.test 5b7509f384f4f6fae1af3c8c104c8ca299fea18d
F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798 F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798
F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09 F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09
F test/savepoint.test c671fdbd34cd3bfe1518a777526ada595180cf8d F test/savepoint.test c671fdbd34cd3bfe1518a777526ada595180cf8d
@@ -1340,8 +1341,8 @@ F tool/fuzzershell.c f2fc86dd22df654b28851b85019d3bd007361751
F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4 F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4
F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5 F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
F tool/lemon.c b9109f59b57e7b6f101c4fe644c8361ba6dee969 F tool/lemon.c 0c455691cc1e59a8f782d51a83dd6bbd7c5c44e7
F tool/lempar.c 01ca97f87610d1dac6d8cd96ab109ab1130e76dc F tool/lempar.c 3617143ddb9b176c3605defe6a9c798793280120
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862 F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6 F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6
F tool/mkautoconfamal.sh d1a2da0e15b2ed33d60af35c7e9d483f13a8eb9f F tool/mkautoconfamal.sh d1a2da0e15b2ed33d60af35c7e9d483f13a8eb9f
@@ -1385,7 +1386,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P c0bf92eca4d3d4666e8a0476ef30fa8123de1cb0 3d3df79bfaf9dbc7aa711c08a19d2f6dbe744b32 P a9b84885aa572b7f92e5aafa246af328d13e3e6e 99b992fa840707711d99f8d05b62412f7008cd93
R ee966f158d53b77675f43896974b25d9 R 1f63598c79312b65d8d15c45f84006b8
U drh U drh
Z b1cc08beaad97d2b36ffef8ab5faa1b6 Z f300497e9766a2b3b13269e90f17caa1

View File

@@ -1 +1 @@
a9b84885aa572b7f92e5aafa246af328d13e3e6e 9cf3e51bcce1268dbb22cc8fa77160db3cb72746

View File

@@ -1186,6 +1186,7 @@ static void analyzeOneTable(
regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol); regKey = sqlite3GetTempRange(pParse, pPk->nKeyCol);
for(j=0; j<pPk->nKeyCol; j++){ for(j=0; j<pPk->nKeyCol; j++){
k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]); k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]);
assert( k>=0 && k<pTab->nCol );
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, regKey+j);
VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName)); VdbeComment((v, "%s", pTab->aCol[pPk->aiColumn[j]].zName));
} }
@@ -1235,12 +1236,10 @@ static void analyzeOneTable(
** be taken */ ** be taken */
VdbeCoverageNeverTaken(v); VdbeCoverageNeverTaken(v);
#ifdef SQLITE_ENABLE_STAT3 #ifdef SQLITE_ENABLE_STAT3
sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, 0, regSample);
pIdx->aiColumn[0], regSample);
#else #else
for(i=0; i<nCol; i++){ for(i=0; i<nCol; i++){
i16 iCol = pIdx->aiColumn[i]; sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iTabCur, i, regCol+i);
sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regCol+i);
} }
sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol, regSample); sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol, regSample);
#endif #endif

View File

@@ -443,6 +443,7 @@ static void freeIndex(sqlite3 *db, Index *p){
sqlite3DeleteIndexSamples(db, p); sqlite3DeleteIndexSamples(db, p);
#endif #endif
sqlite3ExprDelete(db, p->pPartIdxWhere); sqlite3ExprDelete(db, p->pPartIdxWhere);
sqlite3ExprListDelete(db, p->aColExpr);
sqlite3DbFree(db, p->zColAff); sqlite3DbFree(db, p->zColAff);
if( p->isResized ) sqlite3DbFree(db, p->azColl); if( p->isResized ) sqlite3DbFree(db, p->azColl);
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
@@ -1309,7 +1310,8 @@ void sqlite3AddPrimaryKey(
nTerm = pList->nExpr; nTerm = pList->nExpr;
for(i=0; i<nTerm; i++){ for(i=0; i<nTerm; i++){
Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[i].pExpr); 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; const char *zCName = pCExpr->u.zToken;
for(iCol=0; iCol<pTab->nCol; iCol++){ for(iCol=0; iCol<pTab->nCol; iCol++){
if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){ if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){
@@ -2913,7 +2915,6 @@ Index *sqlite3CreateIndex(
int iDb; /* Index of the database that is being written */ int iDb; /* Index of the database that is being written */
Token *pName = 0; /* Unqualified name of the index to create */ Token *pName = 0; /* Unqualified name of the index to create */
struct ExprList_item *pListItem; /* For looping over pList */ struct ExprList_item *pListItem; /* For looping over pList */
const Column *pTabCol; /* A column in the table */
int nExtra = 0; /* Space allocated for zExtra[] */ int nExtra = 0; /* Space allocated for zExtra[] */
int nExtraCol; /* Number of extra columns needed */ int nExtraCol; /* Number of extra columns needed */
char *zExtra = 0; /* Extra space after the Index object */ char *zExtra = 0; /* Extra space after the Index object */
@@ -3085,7 +3086,8 @@ Index *sqlite3CreateIndex(
*/ */
for(i=0; i<pList->nExpr; i++){ for(i=0; i<pList->nExpr; i++){
Expr *pExpr = pList->a[i].pExpr; 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)); nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken));
} }
} }
@@ -3126,40 +3128,52 @@ Index *sqlite3CreateIndex(
sortOrderMask = 0; /* Ignore DESC */ sortOrderMask = 0; /* Ignore DESC */
} }
/* Scan the names of the columns of the table to be indexed and /* Analyze the list of expressions that form the terms of the index and
** load the column indices into the Index structure. Report an error ** report any errors. In the common case where the expression is exactly
** if any column is not found. ** 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 ** TODO: Issue a warning if two or more columns of the index are identical.
** more than once within the same index. Only the first instance of ** TODO: Issue a warning if the table primary key is used as part of the
** the column will ever be used by the optimizer. Note that using the ** index key.
** same column more than once cannot be an error because that would
** break backwards compatibility - it needs to be a warning.
*/ */
for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){ for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){
const char *zColName; Expr *pCExpr; /* The i-th index expression */
Expr *pCExpr; int requestedSortOrder; /* ASC or DESC on the i-th expression */
int requestedSortOrder;
char *zColl; /* Collation sequence name */ char *zColl; /* Collation sequence name */
sqlite3StringToId(pListItem->pExpr); sqlite3StringToId(pListItem->pExpr);
sqlite3ResolveSelfReference(pParse, pTab, NC_IdxExpr, pListItem->pExpr, 0);
if( pParse->nErr ) goto exit_create_index;
pCExpr = sqlite3ExprSkipCollate(pListItem->pExpr); pCExpr = sqlite3ExprSkipCollate(pListItem->pExpr);
if( pCExpr->op!=TK_ID ){ if( pCExpr->op!=TK_COLUMN ){
sqlite3ErrorMsg(pParse, "indexes on expressions not yet supported"); if( pTab==pParse->pNewTable ){
continue; sqlite3ErrorMsg(pParse, "expressions prohibited in PRIMARY KEY and "
} "UNIQUE constraints");
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; 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 ); assert( j<=0x7fff );
if( j<0 ){
j = pTab->iPKey;
}else if( pTab->aCol[j].notNull==0 ){
pIndex->uniqNotNull = 0;
}
pIndex->aiColumn[i] = (i16)j; pIndex->aiColumn[i] = (i16)j;
}
zColl = 0;
if( pListItem->pExpr->op==TK_COLLATE ){ if( pListItem->pExpr->op==TK_COLLATE ){
int nColl; int nColl;
zColl = pListItem->pExpr->u.zToken; zColl = pListItem->pExpr->u.zToken;
@@ -3169,21 +3183,26 @@ Index *sqlite3CreateIndex(
zColl = zExtra; zColl = zExtra;
zExtra += nColl; zExtra += nColl;
nExtra -= nColl; nExtra -= nColl;
}else{ }else if( j>=0 ){
zColl = pTab->aCol[j].zColl; zColl = pTab->aCol[j].zColl;
if( !zColl ) zColl = "BINARY";
} }
if( !zColl ) zColl = "BINARY";
if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){ if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){
goto exit_create_index; goto exit_create_index;
} }
pIndex->azColl[i] = zColl; pIndex->azColl[i] = zColl;
requestedSortOrder = pListItem->sortOrder & sortOrderMask; requestedSortOrder = pListItem->sortOrder & sortOrderMask;
pIndex->aSortOrder[i] = (u8)requestedSortOrder; 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 ){ if( pPk ){
for(j=0; j<pPk->nKeyCol; j++){ for(j=0; j<pPk->nKeyCol; j++){
int x = pPk->aiColumn[j]; int x = pPk->aiColumn[j];
assert( x>=0 );
if( hasColumn(pIndex->aiColumn, pIndex->nKeyCol, x) ){ if( hasColumn(pIndex->aiColumn, pIndex->nKeyCol, x) ){
pIndex->nColumn--; pIndex->nColumn--;
}else{ }else{
@@ -3234,6 +3253,7 @@ Index *sqlite3CreateIndex(
for(k=0; k<pIdx->nKeyCol; k++){ for(k=0; k<pIdx->nKeyCol; k++){
const char *z1; const char *z1;
const char *z2; const char *z2;
assert( pIdx->aiColumn[k]>=0 );
if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break; if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break;
z1 = pIdx->azColl[k]; z1 = pIdx->azColl[k];
z2 = pIndex->azColl[k]; z2 = pIndex->azColl[k];
@@ -3265,6 +3285,7 @@ Index *sqlite3CreateIndex(
/* Link the new Index structure to its table and to the other /* Link the new Index structure to its table and to the other
** in-memory database structures. ** in-memory database structures.
*/ */
assert( pParse->nErr==0 );
if( db->init.busy ){ if( db->init.busy ){
Index *p; Index *p;
assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) ); assert( sqlite3SchemaMutexHeld(db, 0, pIndex->pSchema) );
@@ -3294,7 +3315,7 @@ Index *sqlite3CreateIndex(
** has just been created, it contains no data and the index initialization ** has just been created, it contains no data and the index initialization
** step can be skipped. ** step can be skipped.
*/ */
else if( pParse->nErr==0 && (HasRowid(pTab) || pTblName!=0) ){ else if( HasRowid(pTab) || pTblName!=0 ){
Vdbe *v; Vdbe *v;
char *zStmt; char *zStmt;
int iMem = ++pParse->nMem; int iMem = ++pParse->nMem;
@@ -4124,12 +4145,16 @@ void sqlite3UniqueConstraint(
Table *pTab = pIdx->pTable; Table *pTab = pIdx->pTable;
sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200); sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200);
if( pIdx->aColExpr ){
sqlite3XPrintf(&errMsg, 0, "index '%q'", pIdx->zName);
}else{
for(j=0; j<pIdx->nKeyCol; j++){ for(j=0; j<pIdx->nKeyCol; j++){
char *zCol = pTab->aCol[pIdx->aiColumn[j]].zName; char *zCol;
assert( pIdx->aiColumn[j]>=0 );
zCol = pTab->aCol[pIdx->aiColumn[j]].zName;
if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2); if( j ) sqlite3StrAccumAppend(&errMsg, ", ", 2);
sqlite3StrAccumAppendAll(&errMsg, pTab->zName); sqlite3XPrintf(&errMsg, 0, "%s.%s", pTab->zName, zCol);
sqlite3StrAccumAppend(&errMsg, ".", 1); }
sqlite3StrAccumAppendAll(&errMsg, zCol);
} }
zErr = sqlite3StrAccumFinish(&errMsg); zErr = sqlite3StrAccumFinish(&errMsg);
sqlite3HaltConstraint(pParse, sqlite3HaltConstraint(pParse,

View File

@@ -1115,14 +1115,14 @@ static void currentTimeFunc(
void sqlite3RegisterDateTimeFunctions(void){ void sqlite3RegisterDateTimeFunctions(void){
static SQLITE_WSD FuncDef aDateTimeFuncs[] = { static SQLITE_WSD FuncDef aDateTimeFuncs[] = {
#ifndef SQLITE_OMIT_DATETIME_FUNCS #ifndef SQLITE_OMIT_DATETIME_FUNCS
FUNCTION(julianday, -1, 0, 0, juliandayFunc ), DFUNCTION(julianday, -1, 0, 0, juliandayFunc ),
FUNCTION(date, -1, 0, 0, dateFunc ), DFUNCTION(date, -1, 0, 0, dateFunc ),
FUNCTION(time, -1, 0, 0, timeFunc ), DFUNCTION(time, -1, 0, 0, timeFunc ),
FUNCTION(datetime, -1, 0, 0, datetimeFunc ), DFUNCTION(datetime, -1, 0, 0, datetimeFunc ),
FUNCTION(strftime, -1, 0, 0, strftimeFunc ), DFUNCTION(strftime, -1, 0, 0, strftimeFunc ),
FUNCTION(current_time, 0, 0, 0, ctimeFunc ), DFUNCTION(current_time, 0, 0, 0, ctimeFunc ),
FUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc), DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
FUNCTION(current_date, 0, 0, 0, cdateFunc ), DFUNCTION(current_date, 0, 0, 0, cdateFunc ),
#else #else
STR_FUNCTION(current_time, 0, "%H:%M:%S", 0, currentTimeFunc), STR_FUNCTION(current_time, 0, "%H:%M:%S", 0, currentTimeFunc),
STR_FUNCTION(current_date, 0, "%Y-%m-%d", 0, currentTimeFunc), STR_FUNCTION(current_date, 0, "%Y-%m-%d", 0, currentTimeFunc),

View File

@@ -411,6 +411,7 @@ void sqlite3DeleteFrom(
/* Extract the rowid or primary key for the current row */ /* Extract the rowid or primary key for the current row */
if( pPk ){ if( pPk ){
for(i=0; i<nPk; i++){ for(i=0; i<nPk; i++){
assert( pPk->aiColumn[i]>=(-1) );
sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur,
pPk->aiColumn[i], iPk+i); pPk->aiColumn[i], iPk+i);
} }
@@ -789,14 +790,13 @@ int sqlite3GenerateIndexKey(
){ ){
Vdbe *v = pParse->pVdbe; Vdbe *v = pParse->pVdbe;
int j; int j;
Table *pTab = pIdx->pTable;
int regBase; int regBase;
int nCol; int nCol;
if( piPartIdxLabel ){ if( piPartIdxLabel ){
if( pIdx->pPartIdxWhere ){ if( pIdx->pPartIdxWhere ){
*piPartIdxLabel = sqlite3VdbeMakeLabel(v); *piPartIdxLabel = sqlite3VdbeMakeLabel(v);
pParse->iPartIdxTab = iDataCur; pParse->iSelfTab = iDataCur;
sqlite3ExprCachePush(pParse); sqlite3ExprCachePush(pParse);
sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
SQLITE_JUMPIFNULL); SQLITE_JUMPIFNULL);
@@ -808,9 +808,14 @@ int sqlite3GenerateIndexKey(
regBase = sqlite3GetTempRange(pParse, nCol); regBase = sqlite3GetTempRange(pParse, nCol);
if( pPrior && (regBase!=regPrior || pPrior->pPartIdxWhere) ) pPrior = 0; if( pPrior && (regBase!=regPrior || pPrior->pPartIdxWhere) ) pPrior = 0;
for(j=0; j<nCol; j++){ for(j=0; j<nCol; j++){
if( pPrior && pPrior->aiColumn[j]==pIdx->aiColumn[j] ) continue; if( pPrior
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pIdx->aiColumn[j], && pPrior->aiColumn[j]==pIdx->aiColumn[j]
regBase+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 /* 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 ** might be stored in the table as an integer (using a compact
** representation) then converted to REAL by an OP_RealAffinity opcode. ** representation) then converted to REAL by an OP_RealAffinity opcode.

View File

@@ -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. ** or likelihood() function at the root of an expression.
*/ */
Expr *sqlite3ExprSkipCollate(Expr *pExpr){ Expr *sqlite3ExprSkipCollate(Expr *pExpr){
@@ -102,7 +102,7 @@ Expr *sqlite3ExprSkipCollate(Expr *pExpr){
assert( pExpr->op==TK_FUNCTION ); assert( pExpr->op==TK_FUNCTION );
pExpr = pExpr->x.pList->a[0].pExpr; pExpr = pExpr->x.pList->a[0].pExpr;
}else{ }else{
assert( pExpr->op==TK_COLLATE || pExpr->op==TK_AS ); assert( pExpr->op==TK_COLLATE );
pExpr = pExpr->pLeft; 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. ** 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; inReg = pExpr->iColumn + pParse->ckBase;
break; break;
}else{ }else{
/* Deleting from a partial index */ /* Coding an expression that is part of an index where column names
iTab = pParse->iPartIdxTab; ** in the index refer to the table to which the index belongs */
iTab = pParse->iSelfTab;
} }
} }
inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab, inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
@@ -2678,10 +2701,6 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
inReg = pExpr->iTable; inReg = pExpr->iTable;
break; break;
} }
case TK_AS: {
inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
break;
}
#ifndef SQLITE_OMIT_CAST #ifndef SQLITE_OMIT_CAST
case TK_CAST: { case TK_CAST: {
/* Expressions of the form: CAST(pLeft AS token) */ /* Expressions of the form: CAST(pLeft AS token) */
@@ -3765,7 +3784,9 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){
return 2; return 2;
} }
if( pA->op!=TK_COLUMN && ALWAYS(pA->op!=TK_AGG_COLUMN) && pA->u.zToken ){ 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; return pA->op==TK_COLLATE ? 1 : 2;
} }
} }

View File

@@ -1737,15 +1737,15 @@ void sqlite3RegisterGlobalFunctions(void){
VFUNCTION(random, 0, 0, 0, randomFunc ), VFUNCTION(random, 0, 0, 0, randomFunc ),
VFUNCTION(randomblob, 1, 0, 0, randomBlob ), VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
FUNCTION(nullif, 2, 0, 1, nullifFunc ), FUNCTION(nullif, 2, 0, 1, nullifFunc ),
FUNCTION(sqlite_version, 0, 0, 0, versionFunc ), DFUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), DFUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ), FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ),
#if SQLITE_USER_AUTHENTICATION #if SQLITE_USER_AUTHENTICATION
FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ), FUNCTION(sqlite_crypt, 2, 0, 0, sqlite3CryptFunc ),
#endif #endif
#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ), DFUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ),
FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ), DFUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
FUNCTION(quote, 1, 0, 0, quoteFunc ), FUNCTION(quote, 1, 0, 0, quoteFunc ),
VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid), VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
@@ -1757,8 +1757,8 @@ void sqlite3RegisterGlobalFunctions(void){
FUNCTION(soundex, 1, 0, 0, soundexFunc ), FUNCTION(soundex, 1, 0, 0, soundexFunc ),
#endif #endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION #ifndef SQLITE_OMIT_LOAD_EXTENSION
FUNCTION(load_extension, 1, 0, 0, loadExt ), VFUNCTION(load_extension, 1, 0, 0, loadExt ),
FUNCTION(load_extension, 2, 0, 0, loadExt ), VFUNCTION(load_extension, 2, 0, 0, loadExt ),
#endif #endif
AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ), AGGREGATE(sum, 1, 0, 0, sumStep, sumFinalize ),
AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ), AGGREGATE(total, 1, 0, 0, sumStep, totalFinalize ),

View File

@@ -88,7 +88,18 @@ const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
} }
for(n=0; n<pIdx->nColumn; n++){ for(n=0; n<pIdx->nColumn; n++){
i16 x = pIdx->aiColumn[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; pIdx->zColAff[n] = 0;
} }
@@ -1394,7 +1405,13 @@ void sqlite3GenerateConstraintChecks(
for(i=0; i<pIdx->nColumn; i++){ for(i=0; i<pIdx->nColumn; i++){
int iField = pIdx->aiColumn[i]; int iField = pIdx->aiColumn[i];
int x; int x;
if( iField<0 || iField==pTab->iPKey ){ 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{
if( iField==(-1) || iField==pTab->iPKey ){
if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */ if( regRowid==regIdx+i ) continue; /* ROWID already in regIdx+i */
x = regNewData; x = regNewData;
regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i; regRowid = pIdx->pPartIdxWhere ? -1 : regIdx+i;
@@ -1404,6 +1421,7 @@ void sqlite3GenerateConstraintChecks(
sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i); sqlite3VdbeAddOp2(v, OP_SCopy, x, regIdx+i);
VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName)); VdbeComment((v, "%s", iField<0 ? "rowid" : pTab->aCol[iField].zName));
} }
}
sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]); sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
VdbeComment((v, "for %s", pIdx->zName)); VdbeComment((v, "for %s", pIdx->zName));
sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn); sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn);
@@ -1723,6 +1741,13 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){
if( pSrc->aiColumn[i]!=pDest->aiColumn[i] ){ if( pSrc->aiColumn[i]!=pDest->aiColumn[i] ){
return 0; /* Different columns indexed */ 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] ){ if( pSrc->aSortOrder[i]!=pDest->aSortOrder[i] ){
return 0; /* Different sort orders */ return 0; /* Different sort orders */
} }

View File

@@ -56,15 +56,19 @@
** ParseARG_PDECL A parameter declaration for the %extra_argument ** ParseARG_PDECL A parameter declaration for the %extra_argument
** ParseARG_STORE Code to store %extra_argument into yypParser ** ParseARG_STORE Code to store %extra_argument into yypParser
** ParseARG_FETCH Code to extract %extra_argument from 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 ** YYERRORSYMBOL is the code number of the error symbol. If not
** defined, then do no error processing. ** 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 /* The yyzerominor constant is used to initialize instances of
** YYMINORTYPE objects to zero. */ ** 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 ** Suppose the action integer is N. Then the action is determined as
** follows ** 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. ** 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. ** slots in the yy_action[] table.
** **
** The action table is constructed as a single large table named yy_action[]. ** 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 semantic value stored at this level of the stack. This is
** the information used by the action routines in the grammar. ** the information used by the action routines in the grammar.
** It is sometimes called the "minor" token. ** 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 { 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 YYCODETYPE major; /* The major token value. This is the code
** number for the token at this stack level */ ** number for the token at this stack level */
YYMINORTYPE minor; /* The user-supplied minor token value. This YYMINORTYPE minor; /* The user-supplied minor token value. This
@@ -395,10 +407,10 @@ static int yy_find_shift_action(
int i; int i;
int stateno = pParser->yystack[pParser->yyidx].stateno; int stateno = pParser->yystack[pParser->yyidx].stateno;
if( stateno>YY_SHIFT_COUNT if( stateno>=YY_MIN_REDUCE ) return stateno;
|| (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){ assert( stateno <= YY_SHIFT_COUNT );
return yy_default[stateno]; i = yy_shift_ofst[stateno];
} if( i==YY_SHIFT_USE_DFLT ) return yy_default[stateno];
assert( iLookAhead!=YYNOCODE ); assert( iLookAhead!=YYNOCODE );
i += iLookAhead; i += iLookAhead;
if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[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( static void yy_shift(
yyParser *yypParser, /* The parser to be shifted */ yyParser *yypParser, /* The parser to be shifted */
@@ -532,16 +566,7 @@ static void yy_shift(
yytos->stateno = (YYACTIONTYPE)yyNewState; yytos->stateno = (YYACTIONTYPE)yyNewState;
yytos->major = (YYCODETYPE)yyMajor; yytos->major = (YYCODETYPE)yyMajor;
yytos->minor = *yypMinor; yytos->minor = *yypMinor;
#ifndef NDEBUG yyTraceShift(yypParser, yyNewState);
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
} }
/* The following table contains information about every rule that /* The following table contains information about every rule that
@@ -574,8 +599,9 @@ static void yy_reduce(
#ifndef NDEBUG #ifndef NDEBUG
if( yyTraceFILE && yyruleno>=0 if( yyTraceFILE && yyruleno>=0
&& yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt, yysize = yyRuleInfo[yyruleno].nrhs;
yyRuleName[yyruleno]); fprintf(yyTraceFILE, "%sReduce [%s] -> state %d.\n", yyTracePrompt,
yyRuleName[yyruleno], yymsp[-yysize].stateno);
} }
#endif /* NDEBUG */ #endif /* NDEBUG */
@@ -613,9 +639,9 @@ static void yy_reduce(
yysize = yyRuleInfo[yyruleno].nrhs; yysize = yyRuleInfo[yyruleno].nrhs;
yypParser->yyidx -= yysize; yypParser->yyidx -= yysize;
yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
if( yyact < YYNSTATE ){ if( yyact <= YY_MAX_SHIFTREDUCE ){
#ifdef NDEBUG if( yyact>YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
/* If we are not debugging and the reduce action popped at least /* If the reduce action popped at least
** one element off the stack, then we can push the new element back ** 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(). ** onto the stack here, and skip the stack overflow test in yy_shift().
** That gives a significant speed improvement. */ ** That gives a significant speed improvement. */
@@ -625,13 +651,12 @@ static void yy_reduce(
yymsp->stateno = (YYACTIONTYPE)yyact; yymsp->stateno = (YYACTIONTYPE)yyact;
yymsp->major = (YYCODETYPE)yygoto; yymsp->major = (YYCODETYPE)yygoto;
yymsp->minor = yygotominor; yymsp->minor = yygotominor;
}else yyTraceShift(yypParser, yyact);
#endif }else{
{
yy_shift(yypParser,yyact,yygoto,&yygotominor); yy_shift(yypParser,yyact,yygoto,&yygotominor);
} }
}else{ }else{
assert( yyact == YYNSTATE + YYNRULE + 1 ); assert( yyact == YY_ACCEPT_ACTION );
yy_accept(yypParser); yy_accept(yypParser);
} }
} }
@@ -755,12 +780,13 @@ void Parse(
do{ do{
yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); 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); yy_shift(yypParser,yyact,yymajor,&yyminorunion);
yypParser->yyerrcnt--; yypParser->yyerrcnt--;
yymajor = YYNOCODE; yymajor = YYNOCODE;
}else if( yyact < YYNSTATE + YYNRULE ){ }else if( yyact <= YY_MAX_REDUCE ){
yy_reduce(yypParser,yyact-YYNSTATE); yy_reduce(yypParser,yyact-YY_MIN_REDUCE);
}else{ }else{
assert( yyact == YY_ERROR_ACTION ); assert( yyact == YY_ERROR_ACTION );
#ifdef YYERRORSYMBOL #ifdef YYERRORSYMBOL
@@ -810,7 +836,7 @@ void Parse(
yymx != YYERRORSYMBOL && yymx != YYERRORSYMBOL &&
(yyact = yy_find_reduce_action( (yyact = yy_find_reduce_action(
yypParser->yystack[yypParser->yyidx].stateno, yypParser->yystack[yypParser->yyidx].stateno,
YYERRORSYMBOL)) >= YYNSTATE YYERRORSYMBOL)) >= YY_MIN_REDUCE
){ ){
yy_pop_parser_stack(yypParser); yy_pop_parser_stack(yypParser);
} }
@@ -860,5 +886,10 @@ void Parse(
#endif #endif
} }
}while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sReturn\n",yyTracePrompt);
}
#endif
return; return;
} }

View File

@@ -53,6 +53,7 @@ int sqlite3MutexInit(void){
pTo->xMutexLeave = pFrom->xMutexLeave; pTo->xMutexLeave = pFrom->xMutexLeave;
pTo->xMutexHeld = pFrom->xMutexHeld; pTo->xMutexHeld = pFrom->xMutexHeld;
pTo->xMutexNotheld = pFrom->xMutexNotheld; pTo->xMutexNotheld = pFrom->xMutexNotheld;
sqlite3MemoryBarrier();
pTo->xMutexAlloc = pFrom->xMutexAlloc; pTo->xMutexAlloc = pFrom->xMutexAlloc;
} }
rc = sqlite3GlobalConfig.mutex.xMutexInit(); rc = sqlite3GlobalConfig.mutex.xMutexInit();

View File

@@ -64,6 +64,7 @@
#define sqlite3MutexAlloc(X) ((sqlite3_mutex*)8) #define sqlite3MutexAlloc(X) ((sqlite3_mutex*)8)
#define sqlite3MutexInit() SQLITE_OK #define sqlite3MutexInit() SQLITE_OK
#define sqlite3MutexEnd() #define sqlite3MutexEnd()
#define sqlite3MemoryBarrier()
#define MUTEX_LOGIC(X) #define MUTEX_LOGIC(X)
#else #else
#define MUTEX_LOGIC(X) X #define MUTEX_LOGIC(X) X

View File

@@ -80,6 +80,17 @@ static int pthreadMutexNotheld(sqlite3_mutex *p){
} }
#endif #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. ** Initialize and deinitialize the mutex subsystem.
*/ */

View File

@@ -77,6 +77,19 @@ static int winMutexNotheld(sqlite3_mutex *p){
} }
#endif #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. ** Initialize and deinitialize the mutex subsystem.
*/ */

View File

@@ -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 ** Turn the pExpr expression into an alias for the iCol-th column of the
** result set in pEList. ** 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 ** If the reference is followed by a COLLATE operator, then make sure
** the COLLATE operator is preserved. For example: ** the COLLATE operator is preserved. For example:
** **
@@ -102,19 +78,11 @@ static void resolveAlias(
db = pParse->db; db = pParse->db;
pDup = sqlite3ExprDup(db, pOrig, 0); pDup = sqlite3ExprDup(db, pOrig, 0);
if( pDup==0 ) return; if( pDup==0 ) return;
if( pOrig->op!=TK_COLUMN && zType[0]!='G' ){ if( zType[0]!='G' ) incrAggFunctionDepth(pDup, nSubquery);
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( pExpr->op==TK_COLLATE ){ if( pExpr->op==TK_COLLATE ){
pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken); pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken);
} }
ExprSetProperty(pDup, EP_Alias);
/* Before calling sqlite3ExprDelete(), set the EP_Static flag. This /* Before calling sqlite3ExprDelete(), set the EP_Static flag. This
** prevents ExprDelete() from deleting the Expr structure itself, ** prevents ExprDelete() from deleting the Expr structure itself,
@@ -506,7 +474,7 @@ static int lookupName(
lookupname_end: lookupname_end:
if( cnt==1 ){ if( cnt==1 ){
assert( pNC!=0 ); assert( pNC!=0 );
if( pExpr->op!=TK_AS ){ if( !ExprHasProperty(pExpr, EP_Alias) ){
sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList); sqlite3AuthRead(pParse, pExpr, pSchema, pNC->pSrcList);
} }
/* Increment the nRef value on all name contexts from TopNC up to /* 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 ** Report an error that an expression is not valid for some set of
** clause. ** pNC->ncFlags values determined by validMask.
*/ */
static void notValidPartIdxWhere( static void notValid(
Parse *pParse, /* Leave error message here */ Parse *pParse, /* Leave error message here */
NameContext *pNC, /* The name context */ 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 ){ assert( (validMask&~(NC_IsCheck|NC_PartIdx|NC_IdxExpr))==0 );
sqlite3ErrorMsg(pParse, "%s prohibited in partial index WHERE clauses", if( (pNC->ncFlags & validMask)!=0 ){
zMsg); const char *zIn = "partial index WHERE clauses";
} if( pNC->ncFlags & NC_IdxExpr ) zIn = "index expressions";
}
#ifndef SQLITE_OMIT_CHECK #ifndef SQLITE_OMIT_CHECK
/* else if( pNC->ncFlags & NC_IsCheck ) zIn = "CHECK constraints";
** Report an error that an expression is not valid for a CHECK constraint. #endif
*/ sqlite3ErrorMsg(pParse, "%s prohibited in %s", zMsg, zIn);
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
# define notValidCheckConstraint(P,N,M)
#endif
/* /*
** Expression p should encode a floating point value between 1.0 and 0.0. ** 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; Expr *pRight;
/* if( pSrcList==0 ) break; */ /* if( pSrcList==0 ) break; */
notValid(pParse, pNC, "the \".\" operator", NC_IdxExpr);
/*notValid(pParse, pNC, "the \".\" operator", NC_PartIdx|NC_IsCheck, 1);*/
pRight = pExpr->pRight; pRight = pExpr->pRight;
if( pRight->op==TK_ID ){ if( pRight->op==TK_ID ){
zDb = 0; zDb = 0;
@@ -690,7 +649,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
u8 enc = ENC(pParse->db); /* The database encoding */ u8 enc = ENC(pParse->db); /* The database encoding */
assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
notValidPartIdxWhere(pParse, pNC, "functions"); notValid(pParse, pNC, "functions", NC_PartIdx);
zId = pExpr->u.zToken; zId = pExpr->u.zToken;
nId = sqlite3Strlen30(zId); nId = sqlite3Strlen30(zId);
pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0); pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
@@ -738,9 +697,18 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
return WRC_Prune; return WRC_Prune;
} }
#endif #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); 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 ){ if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId); 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 ); testcase( pExpr->op==TK_IN );
if( ExprHasProperty(pExpr, EP_xIsSelect) ){ if( ExprHasProperty(pExpr, EP_xIsSelect) ){
int nRef = pNC->nRef; int nRef = pNC->nRef;
notValidCheckConstraint(pParse, pNC, "subqueries"); notValid(pParse, pNC, "subqueries", NC_IsCheck|NC_PartIdx|NC_IdxExpr);
notValidPartIdxWhere(pParse, pNC, "subqueries");
sqlite3WalkSelect(pWalker, pExpr->x.pSelect); sqlite3WalkSelect(pWalker, pExpr->x.pSelect);
assert( pNC->nRef>=nRef ); assert( pNC->nRef>=nRef );
if( nRef!=pNC->nRef ){ if( nRef!=pNC->nRef ){
@@ -797,8 +764,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
break; break;
} }
case TK_VARIABLE: { case TK_VARIABLE: {
notValidCheckConstraint(pParse, pNC, "parameters"); notValid(pParse, pNC, "parameters", NC_IsCheck|NC_PartIdx|NC_IdxExpr);
notValidPartIdxWhere(pParse, pNC, "parameters");
break; break;
} }
} }
@@ -1501,14 +1467,14 @@ void sqlite3ResolveSelectNames(
void sqlite3ResolveSelfReference( void sqlite3ResolveSelfReference(
Parse *pParse, /* Parsing context */ Parse *pParse, /* Parsing context */
Table *pTab, /* The table being referenced */ 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. */ Expr *pExpr, /* Expression to resolve. May be NULL. */
ExprList *pList /* Expression list to resolve. May be NUL. */ ExprList *pList /* Expression list to resolve. May be NUL. */
){ ){
SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ SrcList sSrc; /* Fake SrcList for pParse->pNewTable */
NameContext sNC; /* Name context 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(&sNC, 0, sizeof(sNC));
memset(&sSrc, 0, sizeof(sSrc)); memset(&sSrc, 0, sizeof(sSrc));
sSrc.nSrc = 1; sSrc.nSrc = 1;

View File

@@ -4252,8 +4252,8 @@ static int process_input(ShellState *p, FILE *in){
fprintf(stderr, "Error: incomplete SQL: %s\n", zSql); fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
errCnt++; errCnt++;
} }
free(zSql);
} }
free(zSql);
free(zLine); free(zLine);
return errCnt>0; return errCnt>0;
} }

View File

@@ -1385,18 +1385,20 @@ struct FuncDestructor {
** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG. There ** values must correspond to OPFLAG_LENGTHARG and OPFLAG_TYPEOFARG. There
** are assert() statements in the code to verify this. ** are assert() statements in the code to verify this.
*/ */
#define SQLITE_FUNC_ENCMASK 0x003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */ #define SQLITE_FUNC_ENCMASK 0x0003 /* SQLITE_UTF8, SQLITE_UTF16BE or UTF16LE */
#define SQLITE_FUNC_LIKE 0x004 /* Candidate for the LIKE optimization */ #define SQLITE_FUNC_LIKE 0x0004 /* Candidate for the LIKE optimization */
#define SQLITE_FUNC_CASE 0x008 /* Case-sensitive LIKE-type function */ #define SQLITE_FUNC_CASE 0x0008 /* Case-sensitive LIKE-type function */
#define SQLITE_FUNC_EPHEM 0x010 /* Ephemeral. Delete with VDBE */ #define SQLITE_FUNC_EPHEM 0x0010 /* Ephemeral. Delete with VDBE */
#define SQLITE_FUNC_NEEDCOLL 0x020 /* sqlite3GetFuncCollSeq() might be called */ #define SQLITE_FUNC_NEEDCOLL 0x0020 /* sqlite3GetFuncCollSeq() might be called*/
#define SQLITE_FUNC_LENGTH 0x040 /* Built-in length() function */ #define SQLITE_FUNC_LENGTH 0x0040 /* Built-in length() function */
#define SQLITE_FUNC_TYPEOF 0x080 /* Built-in typeof() function */ #define SQLITE_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */
#define SQLITE_FUNC_COUNT 0x100 /* Built-in count(*) aggregate */ #define SQLITE_FUNC_COUNT 0x0100 /* Built-in count(*) aggregate */
#define SQLITE_FUNC_COALESCE 0x200 /* Built-in coalesce() or ifnull() */ #define SQLITE_FUNC_COALESCE 0x0200 /* Built-in coalesce() or ifnull() */
#define SQLITE_FUNC_UNLIKELY 0x400 /* Built-in unlikely() function */ #define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */
#define SQLITE_FUNC_CONSTANT 0x800 /* Constant inputs give a constant output */ #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_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 ** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
@@ -1412,6 +1414,12 @@ struct FuncDestructor {
** VFUNCTION(zName, nArg, iArg, bNC, xFunc) ** VFUNCTION(zName, nArg, iArg, bNC, xFunc)
** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag. ** 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) ** AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal)
** Used to create an aggregate function definition implemented by ** Used to create an aggregate function definition implemented by
** the C functions xStep and xFinal. The first four parameters ** the C functions xStep and xFinal. The first four parameters
@@ -1432,11 +1440,14 @@ struct FuncDestructor {
#define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \ #define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \
{nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \ {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0} 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) \ #define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
{nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\ {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0} SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
#define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \ #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} pArg, 0, xFunc, 0, 0, #zName, 0, 0}
#define LIKEFUNC(zName, nArg, arg, flags) \ #define LIKEFUNC(zName, nArg, arg, flags) \
{nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \ {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \
@@ -1872,6 +1883,7 @@ struct Index {
u8 *aSortOrder; /* for each column: True==DESC, False==ASC */ u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
char **azColl; /* Array of collation sequence names for index */ char **azColl; /* Array of collation sequence names for index */
Expr *pPartIdxWhere; /* WHERE clause for partial indices */ Expr *pPartIdxWhere; /* WHERE clause for partial indices */
ExprList *aColExpr; /* Column expressions */
int tnum; /* DB Page containing root of this index */ int tnum; /* DB Page containing root of this index */
LogEst szIdxRow; /* Estimated average row size in bytes */ LogEst szIdxRow; /* Estimated average row size in bytes */
u16 nKeyCol; /* Number of columns forming the key */ 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_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */
#define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */ #define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */ #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_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
#define EP_Subquery 0x200000 /* Tree contains a TK_SELECT operator */ #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 ** 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_IsCheck 0x0004 /* True if resolving names in a CHECK constraint */
#define NC_InAggFunc 0x0008 /* True if analyzing arguments to an agg func */ #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_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 */ #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 nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */
int iFixedOp; /* Never back out opcodes iFixedOp-1 or earlier */ int iFixedOp; /* Never back out opcodes iFixedOp-1 or earlier */
int ckBase; /* Base register of data during check constraints */ 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 iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
int iCacheCnt; /* Counter used to generate aColCache[].lru values */ int iCacheCnt; /* Counter used to generate aColCache[].lru values */
int nLabel; /* Number of labels used */ int nLabel; /* Number of labels used */
@@ -3178,6 +3192,7 @@ const sqlite3_mem_methods *sqlite3MemGetMemsys5(void);
sqlite3_mutex *sqlite3MutexAlloc(int); sqlite3_mutex *sqlite3MutexAlloc(int);
int sqlite3MutexInit(void); int sqlite3MutexInit(void);
int sqlite3MutexEnd(void); int sqlite3MutexEnd(void);
void sqlite3MemoryBarrier(void);
#endif #endif
sqlite3_int64 sqlite3StatusValue(int); sqlite3_int64 sqlite3StatusValue(int);
@@ -3362,6 +3377,7 @@ int sqlite3WhereIsSorted(WhereInfo*);
int sqlite3WhereContinueLabel(WhereInfo*); int sqlite3WhereContinueLabel(WhereInfo*);
int sqlite3WhereBreakLabel(WhereInfo*); int sqlite3WhereBreakLabel(WhereInfo*);
int sqlite3WhereOkOnePass(WhereInfo*, int*); int sqlite3WhereOkOnePass(WhereInfo*, int*);
void sqlite3ExprCodeLoadIndexColumn(Parse*, Index*, int, int, int);
int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8); int sqlite3ExprCodeGetColumn(Parse*, Table*, int, int, int, u8);
void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int); void sqlite3ExprCodeGetColumnOfTable(Vdbe*, Table*, int, int, int);
void sqlite3ExprCodeMove(Parse*, int, int, int); void sqlite3ExprCodeMove(Parse*, int, int, int);

View File

@@ -403,6 +403,7 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
pParse->zTail = zSql; pParse->zTail = zSql;
i = 0; i = 0;
assert( pzErrMsg!=0 ); assert( pzErrMsg!=0 );
/* sqlite3ParserTrace(stdout, "parser: "); */
pEngine = sqlite3ParserAlloc(sqlite3Malloc); pEngine = sqlite3ParserAlloc(sqlite3Malloc);
if( pEngine==0 ){ if( pEngine==0 ){
db->mallocFailed = 1; db->mallocFailed = 1;

View File

@@ -253,11 +253,6 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){
sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable); sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable);
break; break;
} }
case TK_AS: {
sqlite3TreeViewLine(pView,"AS %Q", pExpr->u.zToken);
sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
break;
}
case TK_ID: { case TK_ID: {
sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken); sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken);
break; break;

View File

@@ -273,6 +273,8 @@ void sqlite3Update(
/* There is one entry in the aRegIdx[] array for each index on the table /* 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 ** 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++){ for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
int reg; int reg;
@@ -281,7 +283,8 @@ void sqlite3Update(
}else{ }else{
reg = 0; reg = 0;
for(i=0; i<pIdx->nKeyCol; i++){ 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; reg = ++pParse->nMem;
break; break;
} }
@@ -381,6 +384,7 @@ void sqlite3Update(
if( pWInfo==0 ) goto update_cleanup; if( pWInfo==0 ) goto update_cleanup;
okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass); okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
for(i=0; i<nPk; i++){ for(i=0; i<nPk; i++){
assert( pPk->aiColumn[i]>=(-1) );
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pPk->aiColumn[i], sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, pPk->aiColumn[i],
iPk+i); iPk+i);
} }

View File

@@ -247,7 +247,8 @@ int sqlite3_blob_open(
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int j; int j;
for(j=0; j<pIdx->nKeyCol; 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"; zFault = "indexed";
} }
} }

View File

@@ -1155,7 +1155,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
** to be a scalar SQL function. If ** to be a scalar SQL function. If
** **
** * all function arguments are SQL literals, ** * 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, ** * the SQLITE_FUNC_NEEDCOLL function flag is not set,
** **
** then this routine attempts to invoke the SQL function. Assuming no ** then this routine attempts to invoke the SQL function. Assuming no
@@ -1196,7 +1196,7 @@ static int valueFromFunction(
nName = sqlite3Strlen30(p->u.zToken); nName = sqlite3Strlen30(p->u.zToken);
pFunc = sqlite3FindFunction(db, p->u.zToken, nName, nVal, enc, 0); pFunc = sqlite3FindFunction(db, p->u.zToken, nName, nVal, enc, 0);
assert( pFunc ); assert( pFunc );
if( (pFunc->funcFlags & SQLITE_FUNC_CONSTANT)==0 if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
|| (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL) || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
){ ){
return SQLITE_OK; return SQLITE_OK;

View File

@@ -180,10 +180,13 @@ static WhereTerm *whereScanNext(WhereScan *pScan){
while( pScan->iEquiv<=pScan->nEquiv ){ while( pScan->iEquiv<=pScan->nEquiv ){
iCur = pScan->aiCur[pScan->iEquiv-1]; iCur = pScan->aiCur[pScan->iEquiv-1];
iColumn = pScan->aiColumn[pScan->iEquiv-1]; iColumn = pScan->aiColumn[pScan->iEquiv-1];
assert( iColumn!=(-2) || pScan->pIdxExpr!=0 );
while( (pWC = pScan->pWC)!=0 ){ while( (pWC = pScan->pWC)!=0 ){
for(pTerm=pWC->a+k; k<pWC->nTerm; k++, pTerm++){ for(pTerm=pWC->a+k; k<pWC->nTerm; k++, pTerm++){
if( pTerm->leftCursor==iCur if( pTerm->leftCursor==iCur
&& pTerm->u.leftColumn==iColumn && pTerm->u.leftColumn==iColumn
&& (iColumn!=(-2)
|| sqlite3ExprCompare(pTerm->pExpr->pLeft,pScan->pIdxExpr,iCur)==0)
&& (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin)) && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin))
){ ){
if( (pTerm->eOperator & WO_EQUIV)!=0 if( (pTerm->eOperator & WO_EQUIV)!=0
@@ -273,11 +276,14 @@ static WhereTerm *whereScanInit(
/* memset(pScan, 0, sizeof(*pScan)); */ /* memset(pScan, 0, sizeof(*pScan)); */
pScan->pOrigWC = pWC; pScan->pOrigWC = pWC;
pScan->pWC = 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 ){ if( pIdx && iColumn>=0 ){
pScan->idxaff = pIdx->pTable->aCol[iColumn].affinity; 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]; pScan->zCollName = pIdx->azColl[j];
}else{ }else{
pScan->idxaff = 0; pScan->idxaff = 0;
@@ -298,6 +304,9 @@ static WhereTerm *whereScanInit(
** the WO_xx operator codes specified by the op parameter. ** the WO_xx operator codes specified by the op parameter.
** Return a pointer to the term. Return 0 if not found. ** 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 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 ** 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 ** identified by the WO_EQUIV bit in the pTerm->eOperator field. The
@@ -373,6 +382,25 @@ static int findIndexCol(
return -1; 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 ** Return true if the DISTINCT expression-list passed as the third argument
** is redundant. ** is redundant.
@@ -423,12 +451,9 @@ static int isDistinctRedundant(
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( !IsUniqueIndex(pIdx) ) continue; if( !IsUniqueIndex(pIdx) ) continue;
for(i=0; i<pIdx->nKeyCol; i++){ for(i=0; i<pIdx->nKeyCol; i++){
i16 iCol = pIdx->aiColumn[i]; if( 0==sqlite3WhereFindTerm(pWC, iBase, i, ~(Bitmask)0, WO_EQ, pIdx) ){
if( 0==sqlite3WhereFindTerm(pWC, iBase, iCol, ~(Bitmask)0, WO_EQ, pIdx) ){ if( findIndexCol(pParse, pDistinct, iBase, pIdx, i)<0 ) break;
int iIdxCol = findIndexCol(pParse, pDistinct, iBase, pIdx, i); if( indexColumnNotNull(pIdx, i)==0 ) break;
if( iIdxCol<0 || pTab->aCol[iCol].notNull==0 ){
break;
}
} }
} }
if( i==pIdx->nKeyCol ){ if( i==pIdx->nKeyCol ){
@@ -780,6 +805,7 @@ static sqlite3_index_info *allocateIndexInfo(
testcase( pTerm->eOperator & WO_ALL ); testcase( pTerm->eOperator & WO_ALL );
if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue; if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue;
if( pTerm->wtFlags & TERM_VNULL ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue;
assert( pTerm->u.leftColumn>=(-1) );
nTerm++; nTerm++;
} }
@@ -835,6 +861,7 @@ static sqlite3_index_info *allocateIndexInfo(
testcase( pTerm->eOperator & WO_ALL ); testcase( pTerm->eOperator & WO_ALL );
if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue; if( (pTerm->eOperator & ~(WO_ISNULL|WO_EQUIV|WO_IS))==0 ) continue;
if( pTerm->wtFlags & TERM_VNULL ) continue; if( pTerm->wtFlags & TERM_VNULL ) continue;
assert( pTerm->u.leftColumn>=(-1) );
pIdxCons[j].iColumn = pTerm->u.leftColumn; pIdxCons[j].iColumn = pTerm->u.leftColumn;
pIdxCons[j].iTermOffset = i; pIdxCons[j].iTermOffset = i;
op = (u8)pTerm->eOperator & WO_ALL; op = (u8)pTerm->eOperator & WO_ALL;
@@ -2126,7 +2153,6 @@ static int whereLoopAddBtreeIndex(
u16 saved_nSkip; /* Original value of pNew->nSkip */ u16 saved_nSkip; /* Original value of pNew->nSkip */
u32 saved_wsFlags; /* Original value of pNew->wsFlags */ u32 saved_wsFlags; /* Original value of pNew->wsFlags */
LogEst saved_nOut; /* Original value of pNew->nOut */ LogEst saved_nOut; /* Original value of pNew->nOut */
int iCol; /* Index of the column in the table */
int rc = SQLITE_OK; /* Return code */ int rc = SQLITE_OK; /* Return code */
LogEst rSize; /* Number of rows in the table */ LogEst rSize; /* Number of rows in the table */
LogEst rLogSize; /* Logarithm of table size */ 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); if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
assert( pNew->u.btree.nEq<pProbe->nColumn ); 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_nEq = pNew->u.btree.nEq;
saved_nSkip = pNew->nSkip; saved_nSkip = pNew->nSkip;
saved_nLTerm = pNew->nLTerm; saved_nLTerm = pNew->nLTerm;
saved_wsFlags = pNew->wsFlags; saved_wsFlags = pNew->wsFlags;
saved_prereq = pNew->prereq; saved_prereq = pNew->prereq;
saved_nOut = pNew->nOut; saved_nOut = pNew->nOut;
pTerm = whereScanInit(&scan, pBuilder->pWC, pSrc->iCursor, saved_nEq,
opMask, pProbe);
pNew->rSetup = 0; pNew->rSetup = 0;
rSize = pProbe->aiRowLogEst[0]; rSize = pProbe->aiRowLogEst[0];
rLogSize = estLog(rSize); rLogSize = estLog(rSize);
@@ -2169,7 +2194,7 @@ static int whereLoopAddBtreeIndex(
int nRecValid = pBuilder->nRecValid; int nRecValid = pBuilder->nRecValid;
#endif #endif
if( (eOp==WO_ISNULL || (pTerm->wtFlags&TERM_VNULL)!=0) 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 */ continue; /* ignore IS [NOT] NULL constraints on NOT NULL columns */
} }
@@ -2206,8 +2231,10 @@ static int whereLoopAddBtreeIndex(
** changes "x IN (?)" into "x=?". */ ** changes "x IN (?)" into "x=?". */
}else if( eOp & (WO_EQ|WO_IS) ){ }else if( eOp & (WO_EQ|WO_IS) ){
int iCol = pProbe->aiColumn[saved_nEq];
pNew->wsFlags |= WHERE_COLUMN_EQ; 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 ){ if( iCol>=0 && pProbe->uniqNotNull==0 ){
pNew->wsFlags |= WHERE_UNQ_WANTED; pNew->wsFlags |= WHERE_UNQ_WANTED;
}else{ }else{
@@ -2258,7 +2285,7 @@ static int whereLoopAddBtreeIndex(
assert( eOp & (WO_ISNULL|WO_EQ|WO_IN|WO_IS) ); assert( eOp & (WO_ISNULL|WO_EQ|WO_IN|WO_IS) );
assert( pNew->nOut==saved_nOut ); 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 ); assert( (eOp & WO_IN) || nIn==0 );
testcase( eOp & WO_IN ); testcase( eOp & WO_IN );
pNew->nOut += pTerm->truthProb; pNew->nOut += pTerm->truthProb;
@@ -3785,7 +3812,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
) continue; ) continue;
opMask = pIdx->uniqNotNull ? (WO_EQ|WO_IS) : WO_EQ; opMask = pIdx->uniqNotNull ? (WO_EQ|WO_IS) : WO_EQ;
for(j=0; j<pIdx->nKeyCol; j++){ 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; if( pTerm==0 ) break;
testcase( pTerm->eOperator & WO_IS ); testcase( pTerm->eOperator & WO_IS );
pLoop->aLTerm[j] = pTerm; pLoop->aLTerm[j] = pTerm;
@@ -4025,14 +4052,12 @@ WhereInfo *sqlite3WhereBegin(
/* Assign a bit from the bitmask to every term in the FROM clause. /* 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 N-th term of the FROM clause is assigned a bitmask of 1<<N.
** 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 ** The rule of the previous sentence ensures thta if X is the bitmask for
** is (X-1). An expression from the ON clause of a LEFT JOIN can use ** a table T, then X-1 is the bitmask for all other tables to the left of T.
** its Expr.iRightJoinTable value to find the bitmask of the right table ** Knowing the bitmask for all tables to the left of a left join is
** of the join. Subtracting one from the right table bitmask gives a ** important. Ticket #3015.
** 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.
** **
** Note that bitmasks are created for all pTabList->nSrc tables in ** Note that bitmasks are created for all pTabList->nSrc tables in
** pTabList, not just the first nTabList tables. nTabList is normally ** pTabList, not just the first nTabList tables. nTabList is normally
@@ -4043,14 +4068,10 @@ WhereInfo *sqlite3WhereBegin(
createMask(pMaskSet, pTabList->a[ii].iCursor); createMask(pMaskSet, pTabList->a[ii].iCursor);
sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC); sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC);
} }
#ifndef NDEBUG #ifdef SQLITE_DEBUG
{
Bitmask toTheLeft = 0;
for(ii=0; ii<pTabList->nSrc; ii++){ for(ii=0; ii<pTabList->nSrc; ii++){
Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor); Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor);
assert( (m-1)==toTheLeft ); assert( m==MASKBIT(ii) );
toTheLeft |= m;
}
} }
#endif #endif

View File

@@ -286,6 +286,7 @@ struct WhereScan {
WhereClause *pOrigWC; /* Original, innermost WhereClause */ WhereClause *pOrigWC; /* Original, innermost WhereClause */
WhereClause *pWC; /* WhereClause currently being scanned */ WhereClause *pWC; /* WhereClause currently being scanned */
char *zCollName; /* Required collating sequence, if not NULL */ char *zCollName; /* Required collating sequence, if not NULL */
Expr *pIdxExpr; /* Search for this index expression */
char idxaff; /* Must match this affinity, if zCollName!=NULL */ char idxaff; /* Must match this affinity, if zCollName!=NULL */
unsigned char nEquiv; /* Number of entries in aEquiv[] */ unsigned char nEquiv; /* Number of entries in aEquiv[] */
unsigned char iEquiv; /* Next unused slot in aEquiv[] */ unsigned char iEquiv; /* Next unused slot in aEquiv[] */

View File

@@ -41,6 +41,16 @@ static void explainAppendTerm(
sqlite3StrAccumAppend(pStr, "?", 1); 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 ** Argument pLevel describes a strategy for scanning table pTab. This
** function appends text to pStr that describes the subset of table ** 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 nEq = pLoop->u.btree.nEq;
u16 nSkip = pLoop->nSkip; u16 nSkip = pLoop->nSkip;
int i, j; int i, j;
Column *aCol = pTab->aCol;
i16 *aiColumn = pIndex->aiColumn;
if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return; if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return;
sqlite3StrAccumAppend(pStr, " (", 2); sqlite3StrAccumAppend(pStr, " (", 2);
for(i=0; i<nEq; i++){ 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); if( i ) sqlite3StrAccumAppend(pStr, " AND ", 5);
sqlite3XPrintf(pStr, 0, i>=nSkip ? "%s=?" : "ANY(%s)", z); sqlite3XPrintf(pStr, 0, i>=nSkip ? "%s=?" : "ANY(%s)", z);
} }
j = i; j = i;
if( pLoop->wsFlags&WHERE_BTM_LIMIT ){ 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, ">"); explainAppendTerm(pStr, i++, z, ">");
} }
if( pLoop->wsFlags&WHERE_TOP_LIMIT ){ 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, "<"); explainAppendTerm(pStr, i, z, "<");
} }
sqlite3StrAccumAppend(pStr, ")", 1); sqlite3StrAccumAppend(pStr, ")", 1);

View File

@@ -795,6 +795,51 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
return mask; 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 ** 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 ** "pExpr" field filled in. The job of this routine is to analyze the
@@ -865,16 +910,19 @@ static void exprAnalyze(
pTerm->iParent = -1; pTerm->iParent = -1;
pTerm->eOperator = 0; pTerm->eOperator = 0;
if( allowedOp(op) ){ if( allowedOp(op) ){
int iCur, iColumn;
Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft); Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight); Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV; u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
if( pLeft->op==TK_COLUMN ){ if( exprMightBeIndexed(pSrc, prereqLeft, pLeft, &iCur, &iColumn) ){
pTerm->leftCursor = pLeft->iTable; pTerm->leftCursor = iCur;
pTerm->u.leftColumn = pLeft->iColumn; pTerm->u.leftColumn = iColumn;
pTerm->eOperator = operatorMask(op) & opMask; pTerm->eOperator = operatorMask(op) & opMask;
} }
if( op==TK_IS ) pTerm->wtFlags |= TERM_IS; 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; WhereTerm *pNew;
Expr *pDup; Expr *pDup;
u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */ u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */
@@ -903,8 +951,8 @@ static void exprAnalyze(
} }
exprCommute(pParse, pDup); exprCommute(pParse, pDup);
pLeft = sqlite3ExprSkipCollate(pDup->pLeft); pLeft = sqlite3ExprSkipCollate(pDup->pLeft);
pNew->leftCursor = pLeft->iTable; pNew->leftCursor = iCur;
pNew->u.leftColumn = pLeft->iColumn; pNew->u.leftColumn = iColumn;
testcase( (prereqLeft | extraRight) != prereqLeft ); testcase( (prereqLeft | extraRight) != prereqLeft );
pNew->prereqRight = prereqLeft | extraRight; pNew->prereqRight = prereqLeft | extraRight;
pNew->prereqAll = prereqAll; pNew->prereqAll = prereqAll;

View File

@@ -56,11 +56,11 @@ do_test index-2.1 {
# Try adding an index on a column of a table where the table # Try adding an index on a column of a table where the table
# exists but the column does not. # 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)} execsql {CREATE TABLE test1(f1 int, f2 int, f3 int)}
set v [catch {execsql {CREATE INDEX index1 ON test1(f4)}} msg] set v [catch {execsql {CREATE INDEX index1 ON test1(f4)}} msg]
lappend v $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. # 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] set v [catch {execsql {CREATE INDEX index1 ON test1(f1, f2, f4, f3)}} msg]
execsql {DROP TABLE test1} execsql {DROP TABLE test1}
lappend v $msg 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 # Try creating a bunch of indices on the same table
# #

222
test/indexexpr1.test Normal file
View 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

View File

@@ -144,6 +144,8 @@ do_test rowid-2.8 {
execsql {SELECT x FROM t1 ORDER BY x} execsql {SELECT x FROM t1 ORDER BY x}
} {1 3 5 7 9} } {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 # We cannot index by ROWID
# #
do_test rowid-2.9 { 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] set v [catch {execsql {CREATE INDEX idxt1 ON t1(x, rowid)}} msg]
lappend v $msg lappend v $msg
} {1 {table t1 has no column named rowid}} } {1 {table t1 has no column named rowid}}
}
# Columns defined in the CREATE statement override the buildin ROWID # Columns defined in the CREATE statement override the buildin ROWID
# column names. # column names.

View File

@@ -316,7 +316,8 @@ enum e_action {
RRCONFLICT, /* Was a reduce, but part of a conflict */ RRCONFLICT, /* Was a reduce, but part of a conflict */
SH_RESOLVED, /* Was a shift. Precedence resolved conflict */ SH_RESOLVED, /* Was a shift. Precedence resolved conflict */
RD_RESOLVED, /* Was reduce. 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 */ /* 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 */ struct action *ap; /* Array of actions for this state */
int nTknAct, nNtAct; /* Number of actions on terminals and nonterminals */ int nTknAct, nNtAct; /* Number of actions on terminals and nonterminals */
int iTknOfst, iNtOfst; /* yy_action[] offset for terminals and nonterms */ 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) #define NO_OFFSET (-2147483647)
@@ -360,6 +363,7 @@ struct lemon {
struct state **sorted; /* Table of states sorted by state number */ struct state **sorted; /* Table of states sorted by state number */
struct rule *rule; /* List of all rules */ struct rule *rule; /* List of all rules */
int nstate; /* Number of states */ int nstate; /* Number of states */
int nxstate; /* nstate with tail degenerate states removed */
int nrule; /* Number of rules */ int nrule; /* Number of rules */
int nsymbol; /* Number of terminal and nonterminal symbols */ int nsymbol; /* Number of terminal and nonterminal symbols */
int nterminal; /* Number of terminal symbols */ int nterminal; /* Number of terminal symbols */
@@ -385,7 +389,8 @@ struct lemon {
char *outname; /* Name of the current output file */ char *outname; /* Name of the current output file */
char *tokenprefix; /* A prefix added to token names in the .h file */ char *tokenprefix; /* A prefix added to token names in the .h file */
int nconflict; /* Number of parsing conflicts */ 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 basisflag; /* Print only basis configurations */
int has_fallback; /* True if any %fallback is seen in the grammar */ int has_fallback; /* True if any %fallback is seen in the grammar */
int nolinenosflag; /* True if #line statements should not be printed */ int nolinenosflag; /* True if #line statements should not be printed */
@@ -483,7 +488,7 @@ static int actioncmp(
if( rc==0 ){ if( rc==0 ){
rc = (int)ap1->type - (int)ap2->type; 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; rc = ap1->x.rp->index - ap2->x.rp->index;
} }
if( rc==0 ){ if( rc==0 ){
@@ -1375,14 +1380,16 @@ void Configlist_closure(struct lemon *lemp)
/* Sort the configuration list */ /* Sort the configuration list */
void Configlist_sort(){ 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; currentend = 0;
return; return;
} }
/* Sort the basis configuration list */ /* Sort the basis configuration list */
void Configlist_sortbasis(){ 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; basisend = 0;
return; return;
} }
@@ -1480,6 +1487,18 @@ static void handle_T_option(char *z){
lemon_strcpy(user_templatename, 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... */ /* The main program. Parse the command line and do it... */
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
@@ -1611,10 +1630,15 @@ int main(int argc, char **argv)
if( !mhflag ) ReportHeader(&lem); if( !mhflag ) ReportHeader(&lem);
} }
if( statistics ){ if( statistics ){
printf("Parser statistics: %d terminals, %d nonterminals, %d rules\n", printf("Parser statistics:\n");
lem.nterminal, lem.nsymbol - lem.nterminal, lem.nrule); stats_line("terminal symbols", lem.nterminal);
printf(" %d states, %d parser table entries, %d conflicts\n", stats_line("non-terminal symbols", lem.nsymbol - lem.nterminal);
lem.nstate, lem.tablesize, lem.nconflict); 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 ){ if( lem.nconflict > 0 ){
fprintf(stderr,"%d parsing conflicts.\n",lem.nconflict); fprintf(stderr,"%d parsing conflicts.\n",lem.nconflict);
@@ -1873,7 +1897,8 @@ static int handleswitch(int i, FILE *err)
dv = strtod(cp,&end); dv = strtod(cp,&end);
if( *end ){ if( *end ){
if( err ){ 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); errline(i,(int)((char*)end-(char*)argv[i]),err);
} }
errcnt++; errcnt++;
@@ -2939,15 +2964,14 @@ void Reprint(struct lemon *lemp)
} }
} }
void ConfigPrint(FILE *fp, struct config *cfp) /* Print a single rule.
{ */
struct rule *rp; void RulePrint(FILE *fp, struct rule *rp, int iCursor){
struct symbol *sp; struct symbol *sp;
int i, j; int i, j;
rp = cfp->rp;
fprintf(fp,"%s ::=",rp->lhs->name); fprintf(fp,"%s ::=",rp->lhs->name);
for(i=0; i<=rp->nrhs; i++){ for(i=0; i<=rp->nrhs; i++){
if( i==cfp->dot ) fprintf(fp," *"); if( i==iCursor ) fprintf(fp," *");
if( i==rp->nrhs ) break; if( i==rp->nrhs ) break;
sp = rp->rhs[i]; sp = rp->rhs[i];
if( sp->type==MULTITERMINAL ){ 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 */ /* #define TEST */
#if 0 #if 0
/* Print a set */ /* Print a set */
@@ -3000,15 +3030,30 @@ char *tag;
/* Print an action to the given file descriptor. Return FALSE if /* Print an action to the given file descriptor. Return FALSE if
** nothing was actually printed. ** 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; int result = 1;
switch( ap->type ){ switch( ap->type ){
case SHIFT: case SHIFT: {
fprintf(fp,"%*s shift %d",indent,ap->sp->name,ap->x.stp->statenum); struct state *stp = ap->x.stp;
fprintf(fp,"%*s shift %-7d",indent,ap->sp->name,stp->statenum);
break; 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; 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: case ACCEPT:
fprintf(fp,"%*s accept",indent,ap->sp->name); fprintf(fp,"%*s accept",indent,ap->sp->name);
break; break;
@@ -3017,16 +3062,16 @@ int PrintAction(struct action *ap, FILE *fp, int indent){
break; break;
case SRCONFLICT: case SRCONFLICT:
case RRCONFLICT: case RRCONFLICT:
fprintf(fp,"%*s reduce %-3d ** Parsing conflict **", fprintf(fp,"%*s reduce %-7d ** Parsing conflict **",
indent,ap->sp->name,ap->x.rp->index); indent,ap->sp->name,ap->x.rp->index);
break; break;
case SSCONFLICT: case SSCONFLICT:
fprintf(fp,"%*s shift %-3d ** Parsing conflict **", fprintf(fp,"%*s shift %-7d ** Parsing conflict **",
indent,ap->sp->name,ap->x.stp->statenum); indent,ap->sp->name,ap->x.stp->statenum);
break; break;
case SH_RESOLVED: case SH_RESOLVED:
if( showPrecedenceConflict ){ 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); indent,ap->sp->name,ap->x.stp->statenum);
}else{ }else{
result = 0; result = 0;
@@ -3034,7 +3079,7 @@ int PrintAction(struct action *ap, FILE *fp, int indent){
break; break;
case RD_RESOLVED: case RD_RESOLVED:
if( showPrecedenceConflict ){ 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); indent,ap->sp->name,ap->x.rp->index);
}else{ }else{
result = 0; result = 0;
@@ -3047,7 +3092,7 @@ int PrintAction(struct action *ap, FILE *fp, int indent){
return result; return result;
} }
/* Generate the "y.output" log file */ /* Generate the "*.out" log file */
void ReportOutput(struct lemon *lemp) void ReportOutput(struct lemon *lemp)
{ {
int i; int i;
@@ -3058,7 +3103,7 @@ void ReportOutput(struct lemon *lemp)
fp = file_open(lemp,".out","wb"); fp = file_open(lemp,".out","wb");
if( fp==0 ) return; if( fp==0 ) return;
for(i=0; i<lemp->nstate; i++){ for(i=0; i<lemp->nxstate; i++){
stp = lemp->sorted[i]; stp = lemp->sorted[i];
fprintf(fp,"State %d:\n",stp->statenum); fprintf(fp,"State %d:\n",stp->statenum);
if( lemp->basisflag ) cfp=stp->bp; if( lemp->basisflag ) cfp=stp->bp;
@@ -3167,9 +3212,10 @@ PRIVATE int compute_action(struct lemon *lemp, struct action *ap)
int act; int act;
switch( ap->type ){ switch( ap->type ){
case SHIFT: act = ap->x.stp->statenum; break; case SHIFT: act = ap->x.stp->statenum; break;
case REDUCE: act = ap->x.rp->index + lemp->nstate; break; case SHIFTREDUCE: act = ap->x.rp->index + lemp->nstate; break;
case ERROR: act = lemp->nstate + lemp->nrule; break; case REDUCE: act = ap->x.rp->index + lemp->nstate+lemp->nrule; break;
case ACCEPT: act = lemp->nstate + lemp->nrule + 1; break; case ERROR: act = lemp->nstate + lemp->nrule*2; break;
case ACCEPT: act = lemp->nstate + lemp->nrule*2 + 1; break;
default: act = -1; break; default: act = -1; break;
} }
return act; return act;
@@ -3228,7 +3274,8 @@ PRIVATE FILE *tplt_open(struct lemon *lemp)
} }
in = fopen(user_templatename,"rb"); in = fopen(user_templatename,"rb");
if( in==0 ){ 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++; lemp->errorcnt++;
return 0; return 0;
} }
@@ -3313,7 +3360,10 @@ void emit_destructor_code(
}else if( sp->destructor ){ }else if( sp->destructor ){
cp = sp->destructor; cp = sp->destructor;
fprintf(out,"{\n"); (*lineno)++; 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 ){ }else if( lemp->vardest ){
cp = lemp->vardest; cp = lemp->vardest;
if( cp==0 ) return; if( cp==0 ) return;
@@ -3510,13 +3560,19 @@ PRIVATE void emit_code(
/* Generate code to do the reduce action */ /* Generate code to do the reduce action */
if( rp->code ){ 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); fprintf(out,"{%s",rp->code);
for(cp=rp->code; *cp; cp++){ for(cp=rp->code; *cp; cp++){
if( *cp=='\n' ) (*lineno)++; if( *cp=='\n' ) (*lineno)++;
} /* End loop */ } /* End loop */
fprintf(out,"}\n"); (*lineno)++; 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 ) */ } /* End if( rp->code ) */
return; return;
@@ -3647,24 +3703,32 @@ void print_stack_union(
/* /*
** Return the name of a C datatype able to represent values between ** 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( lwr>=0 ){
if( upr<=255 ){ if( upr<=255 ){
return "unsigned char"; zType = "unsigned char";
nByte = 1;
}else if( upr<65535 ){ }else if( upr<65535 ){
return "unsigned short int"; zType = "unsigned short int";
nByte = 2;
}else{ }else{
return "unsigned int"; zType = "unsigned int";
nByte = 4;
} }
}else if( lwr>=-127 && upr<=127 ){ }else if( lwr>=-127 && upr<=127 ){
return "signed char"; zType = "signed char";
nByte = 1;
}else if( lwr>=-32767 && upr<32767 ){ }else if( lwr>=-32767 && upr<32767 ){
return "short"; zType = "short";
}else{ nByte = 2;
return "int";
} }
if( pnByte ) *pnByte = nByte;
return zType;
} }
/* /*
@@ -3728,7 +3792,9 @@ void ReportTable(
struct action *ap; struct action *ap;
struct rule *rp; struct rule *rp;
struct acttab *pActtab; struct acttab *pActtab;
int i, j, n; int i, j, n, sz;
int szActionType; /* sizeof(YYACTIONTYPE) */
int szCodeType; /* sizeof(YYCODETYPE) */
const char *name; const char *name;
int mnTknOfst, mxTknOfst; int mnTknOfst, mxTknOfst;
int mnNtOfst, mxNtOfst; int mnNtOfst, mxNtOfst;
@@ -3769,10 +3835,10 @@ void ReportTable(
/* Generate the defines */ /* Generate the defines */
fprintf(out,"#define YYCODETYPE %s\n", 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 YYNOCODE %d\n",lemp->nsymbol+1); lineno++;
fprintf(out,"#define YYACTIONTYPE %s\n", 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 ){ if( lemp->wildcard ){
fprintf(out,"#define YYWILDCARD %d\n", fprintf(out,"#define YYWILDCARD %d\n",
lemp->wildcard->index); lineno++; lemp->wildcard->index); lineno++;
@@ -3808,8 +3874,6 @@ void ReportTable(
if( mhflag ){ if( mhflag ){
fprintf(out,"#endif\n"); lineno++; 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 ){ if( lemp->errsym->useCnt ){
fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++; fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++;
fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++; fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++;
@@ -3817,27 +3881,17 @@ void ReportTable(
if( lemp->has_fallback ){ if( lemp->has_fallback ){
fprintf(out,"#define YYFALLBACK 1\n"); lineno++; fprintf(out,"#define YYFALLBACK 1\n"); lineno++;
} }
tplt_xfer(lemp->name,in,out,&lineno);
/* Generate the action table and its associates: /* Compute the action table, but do not output it yet. The action
** ** table must be computed before generating the YYNSTATE macro because
** yy_action[] A single table containing all actions. ** we need to know how many states can be eliminated.
** 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.
*/ */
ax = (struct axset *) calloc(lemp->nxstate*2, sizeof(ax[0]));
/* Compute the actions on all states and count them up */
ax = (struct axset *) calloc(lemp->nstate*2, sizeof(ax[0]));
if( ax==0 ){ if( ax==0 ){
fprintf(stderr,"malloc failed\n"); fprintf(stderr,"malloc failed\n");
exit(1); exit(1);
} }
for(i=0; i<lemp->nstate; i++){ for(i=0; i<lemp->nxstate; i++){
stp = lemp->sorted[i]; stp = lemp->sorted[i];
ax[i*2].stp = stp; ax[i*2].stp = stp;
ax[i*2].isTkn = 1; ax[i*2].isTkn = 1;
@@ -3848,15 +3902,12 @@ void ReportTable(
} }
mxTknOfst = mnTknOfst = 0; mxTknOfst = mnTknOfst = 0;
mxNtOfst = mnNtOfst = 0; mxNtOfst = mnNtOfst = 0;
/* In an effort to minimize the action table size, use the heuristic
/* Compute the action table. In order to try to keep the size of the ** of placing the largest action sets first */
** action table to a minimum, the heuristic of placing the largest action for(i=0; i<lemp->nxstate*2; i++) ax[i].iOrder = i;
** sets first is used. qsort(ax, lemp->nxstate*2, sizeof(ax[0]), axset_compare);
*/
for(i=0; i<lemp->nstate*2; i++) ax[i].iOrder = i;
qsort(ax, lemp->nstate*2, sizeof(ax[0]), axset_compare);
pActtab = acttab_alloc(); 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; stp = ax[i].stp;
if( ax[i].isTkn ){ if( ax[i].isTkn ){
for(ap=stp->ap; ap; ap=ap->next){ for(ap=stp->ap; ap; ap=ap->next){
@@ -3885,8 +3936,37 @@ void ReportTable(
} }
free(ax); 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 */ /* 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,"#define YY_ACTTAB_COUNT (%d)\n", n); lineno++;
fprintf(out,"static const YYACTIONTYPE yy_action[] = {\n"); lineno++; fprintf(out,"static const YYACTIONTYPE yy_action[] = {\n"); lineno++;
for(i=j=0; i<n; i++){ for(i=j=0; i<n; i++){
@@ -3904,6 +3984,7 @@ void ReportTable(
fprintf(out, "};\n"); lineno++; fprintf(out, "};\n"); lineno++;
/* Output the yy_lookahead table */ /* Output the yy_lookahead table */
lemp->tablesize += n*szCodeType;
fprintf(out,"static const YYCODETYPE yy_lookahead[] = {\n"); lineno++; fprintf(out,"static const YYCODETYPE yy_lookahead[] = {\n"); lineno++;
for(i=j=0; i<n; i++){ for(i=j=0; i<n; i++){
int la = acttab_yylookahead(pActtab, i); int la = acttab_yylookahead(pActtab, i);
@@ -3921,13 +4002,14 @@ void ReportTable(
/* Output the yy_shift_ofst[] table */ /* Output the yy_shift_ofst[] table */
fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++; 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--; 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_COUNT (%d)\n", n-1); lineno++;
fprintf(out, "#define YY_SHIFT_MIN (%d)\n", mnTknOfst); lineno++; fprintf(out, "#define YY_SHIFT_MIN (%d)\n", mnTknOfst); lineno++;
fprintf(out, "#define YY_SHIFT_MAX (%d)\n", mxTknOfst); lineno++; fprintf(out, "#define YY_SHIFT_MAX (%d)\n", mxTknOfst); lineno++;
fprintf(out, "static const %s yy_shift_ofst[] = {\n", 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++){ for(i=j=0; i<n; i++){
int ofst; int ofst;
stp = lemp->sorted[i]; stp = lemp->sorted[i];
@@ -3946,13 +4028,14 @@ void ReportTable(
/* Output the yy_reduce_ofst[] table */ /* Output the yy_reduce_ofst[] table */
fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++; 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--; 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_COUNT (%d)\n", n-1); lineno++;
fprintf(out, "#define YY_REDUCE_MIN (%d)\n", mnNtOfst); lineno++; fprintf(out, "#define YY_REDUCE_MIN (%d)\n", mnNtOfst); lineno++;
fprintf(out, "#define YY_REDUCE_MAX (%d)\n", mxNtOfst); lineno++; fprintf(out, "#define YY_REDUCE_MAX (%d)\n", mxNtOfst); lineno++;
fprintf(out, "static const %s yy_reduce_ofst[] = {\n", 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++){ for(i=j=0; i<n; i++){
int ofst; int ofst;
stp = lemp->sorted[i]; stp = lemp->sorted[i];
@@ -3971,11 +4054,12 @@ void ReportTable(
/* Output the default action table */ /* Output the default action table */
fprintf(out, "static const YYACTIONTYPE yy_default[] = {\n"); lineno++; 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++){ for(i=j=0; i<n; i++){
stp = lemp->sorted[i]; stp = lemp->sorted[i];
if( j==0 ) fprintf(out," /* %5d */ ", 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 ){ if( j==9 || i==n-1 ){
fprintf(out, "\n"); lineno++; fprintf(out, "\n"); lineno++;
j = 0; j = 0;
@@ -3991,6 +4075,7 @@ void ReportTable(
if( lemp->has_fallback ){ if( lemp->has_fallback ){
int mx = lemp->nterminal - 1; int mx = lemp->nterminal - 1;
while( mx>0 && lemp->symbols[mx]->fallback==0 ){ mx--; } while( mx>0 && lemp->symbols[mx]->fallback==0 ){ mx--; }
lemp->tablesize += (mx+1)*szCodeType;
for(i=0; i<=mx; i++){ for(i=0; i<=mx; i++){
struct symbol *p = lemp->symbols[i]; struct symbol *p = lemp->symbols[i];
if( p->fallback==0 ){ if( p->fallback==0 ){
@@ -4207,7 +4292,7 @@ void CompressTables(struct lemon *lemp)
struct state *stp; struct state *stp;
struct action *ap, *ap2; struct action *ap, *ap2;
struct rule *rp, *rp2, *rbest; struct rule *rp, *rp2, *rbest;
int nbest, n; int nbest, n, nshift;
int i; int i;
int usesWildcard; int usesWildcard;
@@ -4255,6 +4340,32 @@ void CompressTables(struct lemon *lemp)
if( ap->type==REDUCE && ap->x.rp==rbest ) ap->type = NOT_USED; if( ap->type==REDUCE && ap->x.rp==rbest ) ap->type = NOT_USED;
} }
stp->ap = Action_sort(stp->ap); 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++){ for(i=0; i<lemp->nstate; i++){
stp = lemp->sorted[i]; stp = lemp->sorted[i];
stp->nTknAct = stp->nNtAct = 0; 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->iTknOfst = NO_OFFSET;
stp->iNtOfst = NO_OFFSET; stp->iNtOfst = NO_OFFSET;
for(ap=stp->ap; ap; ap=ap->next){ 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 ){ if( ap->sp->index<lemp->nterminal ){
stp->nTknAct++; stp->nTknAct++;
}else if( ap->sp->index<lemp->nsymbol ){ }else if( ap->sp->index<lemp->nsymbol ){
stp->nNtAct++; stp->nNtAct++;
}else{ }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++){ for(i=0; i<lemp->nstate; i++){
lemp->sorted[i]->statenum = i; lemp->sorted[i]->statenum = i;
} }
lemp->nxstate = lemp->nstate;
while( lemp->nxstate>1 && lemp->sorted[lemp->nxstate-1]->autoReduce ){
lemp->nxstate--;
}
} }

View File

@@ -50,15 +50,19 @@
** ParseARG_PDECL A parameter declaration for the %extra_argument ** ParseARG_PDECL A parameter declaration for the %extra_argument
** ParseARG_STORE Code to store %extra_argument into yypParser ** ParseARG_STORE Code to store %extra_argument into yypParser
** ParseARG_FETCH Code to extract %extra_argument from 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 ** YYERRORSYMBOL is the code number of the error symbol. If not
** defined, then do no error processing. ** 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 /* The yyzerominor constant is used to initialize instances of
** YYMINORTYPE objects to zero. */ ** 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 ** Suppose the action integer is N. Then the action is determined as
** follows ** 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. ** 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. ** slots in the yy_action[] table.
** **
** The action table is constructed as a single large table named yy_action[]. ** 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 semantic value stored at this level of the stack. This is
** the information used by the action routines in the grammar. ** the information used by the action routines in the grammar.
** It is sometimes called the "minor" token. ** 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 { 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 YYCODETYPE major; /* The major token value. This is the code
** number for the token at this stack level */ ** number for the token at this stack level */
YYMINORTYPE minor; /* The user-supplied minor token value. This YYMINORTYPE minor; /* The user-supplied minor token value. This
@@ -385,10 +397,10 @@ static int yy_find_shift_action(
int i; int i;
int stateno = pParser->yystack[pParser->yyidx].stateno; int stateno = pParser->yystack[pParser->yyidx].stateno;
if( stateno>YY_SHIFT_COUNT if( stateno>=YY_MIN_REDUCE ) return stateno;
|| (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){ assert( stateno <= YY_SHIFT_COUNT );
return yy_default[stateno]; i = yy_shift_ofst[stateno];
} if( i==YY_SHIFT_USE_DFLT ) return yy_default[stateno];
assert( iLookAhead!=YYNOCODE ); assert( iLookAhead!=YYNOCODE );
i += iLookAhead; i += iLookAhead;
if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[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( static void yy_shift(
yyParser *yypParser, /* The parser to be shifted */ yyParser *yypParser, /* The parser to be shifted */
@@ -522,16 +556,7 @@ static void yy_shift(
yytos->stateno = (YYACTIONTYPE)yyNewState; yytos->stateno = (YYACTIONTYPE)yyNewState;
yytos->major = (YYCODETYPE)yyMajor; yytos->major = (YYCODETYPE)yyMajor;
yytos->minor = *yypMinor; yytos->minor = *yypMinor;
#ifndef NDEBUG yyTraceShift(yypParser, yyNewState);
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
} }
/* The following table contains information about every rule that /* The following table contains information about every rule that
@@ -564,8 +589,9 @@ static void yy_reduce(
#ifndef NDEBUG #ifndef NDEBUG
if( yyTraceFILE && yyruleno>=0 if( yyTraceFILE && yyruleno>=0
&& yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt, yysize = yyRuleInfo[yyruleno].nrhs;
yyRuleName[yyruleno]); fprintf(yyTraceFILE, "%sReduce [%s] -> state %d.\n", yyTracePrompt,
yyRuleName[yyruleno], yymsp[-yysize].stateno);
} }
#endif /* NDEBUG */ #endif /* NDEBUG */
@@ -602,9 +628,9 @@ static void yy_reduce(
yysize = yyRuleInfo[yyruleno].nrhs; yysize = yyRuleInfo[yyruleno].nrhs;
yypParser->yyidx -= yysize; yypParser->yyidx -= yysize;
yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
if( yyact < YYNSTATE ){ if( yyact <= YY_MAX_SHIFTREDUCE ){
#ifdef NDEBUG if( yyact>YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
/* If we are not debugging and the reduce action popped at least /* If the reduce action popped at least
** one element off the stack, then we can push the new element back ** 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(). ** onto the stack here, and skip the stack overflow test in yy_shift().
** That gives a significant speed improvement. */ ** That gives a significant speed improvement. */
@@ -614,13 +640,12 @@ static void yy_reduce(
yymsp->stateno = (YYACTIONTYPE)yyact; yymsp->stateno = (YYACTIONTYPE)yyact;
yymsp->major = (YYCODETYPE)yygoto; yymsp->major = (YYCODETYPE)yygoto;
yymsp->minor = yygotominor; yymsp->minor = yygotominor;
}else yyTraceShift(yypParser, yyact);
#endif }else{
{
yy_shift(yypParser,yyact,yygoto,&yygotominor); yy_shift(yypParser,yyact,yygoto,&yygotominor);
} }
}else{ }else{
assert( yyact == YYNSTATE + YYNRULE + 1 ); assert( yyact == YY_ACCEPT_ACTION );
yy_accept(yypParser); yy_accept(yypParser);
} }
} }
@@ -740,13 +765,13 @@ void Parse(
do{ do{
yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
if( yyact<YYNSTATE ){ if( yyact <= YY_MAX_SHIFTREDUCE ){
assert( !yyendofinput ); /* Impossible to shift the $ token */ if( yyact > YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
yy_shift(yypParser,yyact,yymajor,&yyminorunion); yy_shift(yypParser,yyact,yymajor,&yyminorunion);
yypParser->yyerrcnt--; yypParser->yyerrcnt--;
yymajor = YYNOCODE; yymajor = YYNOCODE;
}else if( yyact < YYNSTATE + YYNRULE ){ }else if( yyact <= YY_MAX_REDUCE ){
yy_reduce(yypParser,yyact-YYNSTATE); yy_reduce(yypParser,yyact-YY_MIN_REDUCE);
}else{ }else{
assert( yyact == YY_ERROR_ACTION ); assert( yyact == YY_ERROR_ACTION );
#ifdef YYERRORSYMBOL #ifdef YYERRORSYMBOL
@@ -796,7 +821,7 @@ void Parse(
yymx != YYERRORSYMBOL && yymx != YYERRORSYMBOL &&
(yyact = yy_find_reduce_action( (yyact = yy_find_reduce_action(
yypParser->yystack[yypParser->yyidx].stateno, yypParser->yystack[yypParser->yyidx].stateno,
YYERRORSYMBOL)) >= YYNSTATE YYERRORSYMBOL)) >= YY_MIN_REDUCE
){ ){
yy_pop_parser_stack(yypParser); yy_pop_parser_stack(yypParser);
} }
@@ -846,5 +871,10 @@ void Parse(
#endif #endif
} }
}while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
#ifndef NDEBUG
if( yyTraceFILE ){
fprintf(yyTraceFILE,"%sReturn\n",yyTracePrompt);
}
#endif
return; return;
} }