mirror of https://github.com/sqlite/sqlite
Sync the latest trunk changes, and in particular the STAT4 IS NOT NULL fix.
FossilOrigin-Name: b006792695d23980e1923b21915d5c1138ecf29d
This commit is contained in:
commit
5671ef69ec
|
@ -1933,7 +1933,6 @@ static int spellfix1Init(
|
|||
#define SPELLFIX_COL_COMMAND 11
|
||||
}
|
||||
if( rc==SQLITE_OK && isCreate ){
|
||||
sqlite3_uint64 r;
|
||||
spellfix1DbExec(&rc, db,
|
||||
"CREATE TABLE IF NOT EXISTS \"%w\".\"%w_vocab\"(\n"
|
||||
" id INTEGER PRIMARY KEY,\n"
|
||||
|
@ -1945,11 +1944,10 @@ static int spellfix1Init(
|
|||
");\n",
|
||||
zDbName, zTableName
|
||||
);
|
||||
sqlite3_randomness(sizeof(r), &r);
|
||||
spellfix1DbExec(&rc, db,
|
||||
"CREATE INDEX IF NOT EXISTS \"%w\".\"%w_index_%llx\" "
|
||||
"CREATE INDEX IF NOT EXISTS \"%w\".\"%w_vocab_index_langid_k2\" "
|
||||
"ON \"%w_vocab\"(langid,k2);",
|
||||
zDbName, zModule, r, zTableName
|
||||
zDbName, zModule, zTableName
|
||||
);
|
||||
}
|
||||
for(i=3; rc==SQLITE_OK && i<argc; i++){
|
||||
|
|
|
@ -2547,7 +2547,8 @@ static int sessionBindValue(
|
|||
int i, /* Parameter number to bind to */
|
||||
sqlite3_value *pVal /* Value to bind */
|
||||
){
|
||||
if( (pVal->type==SQLITE_TEXT || pVal->type==SQLITE_BLOB) && pVal->z==0 ){
|
||||
int eType = sqlite3_value_type(pVal);
|
||||
if( (eType==SQLITE_TEXT || eType==SQLITE_BLOB) && pVal->z==0 ){
|
||||
/* This condition occurs when an earlier OOM in a call to
|
||||
** sqlite3_value_text() or sqlite3_value_blob() (perhaps from within
|
||||
** a conflict-hanler) has zeroed the pVal->z pointer. Return NOMEM. */
|
||||
|
|
77
manifest
77
manifest
|
@ -1,5 +1,5 @@
|
|||
C Sync\swith\sversion\s3.8.3.
|
||||
D 2014-02-03T13:58:42.546
|
||||
C Sync\sthe\slatest\strunk\schanges,\sand\sin\sparticular\sthe\sSTAT4\sIS\sNOT\sNULL\sfix.
|
||||
D 2014-02-11T04:30:29.995
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in e4ee6d36cdf6136aee0158675a3b24dd3bf31a5a
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
|
@ -114,7 +114,7 @@ F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
|
|||
F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63
|
||||
F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc
|
||||
F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a
|
||||
F ext/misc/spellfix.c adfc569fafef7a1eb8f21528e5277686b358c3ce
|
||||
F ext/misc/spellfix.c 3548c433f473c2054e080b6382771636fcaa2c4c
|
||||
F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
|
||||
F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
|
||||
F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
|
||||
|
@ -150,7 +150,7 @@ F ext/session/session9.test 776e46785c29c11cda01f5205d0f1e8f8f9a46bf
|
|||
F ext/session/sessionA.test eb05c13e4ef1ca8046a3a6dbf2d5f6f5b04a11d4
|
||||
F ext/session/session_common.tcl 1539d8973b2aea0025c133eb0cc4c89fcef541a5
|
||||
F ext/session/sessionfault.test 496291b287ba3c0b14ca2e074425e29cc92a64a6
|
||||
F ext/session/sqlite3session.c 63eea3741e8ac1574d4c183fd92a6a50b1415357
|
||||
F ext/session/sqlite3session.c 34e19186d05d534e5a37a4f5a8a3c3e24e3fa88a
|
||||
F ext/session/sqlite3session.h 6c35057241567ed6319f750ee504a81c459225e1
|
||||
F ext/session/test_session.c d38968307c05229cc8cd603722cf305d6f768832
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
|
@ -173,23 +173,23 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
|||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 3d8b83c91651f53472ca17599dae3457b8b89494
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 2af0330bb1b601af7a7789bf7229675fd772a083
|
||||
F src/alter.c d5348d0f86a5fc8fb3987727402f023953c021cf
|
||||
F src/analyze.c 581d5c18ce89c6f45d4dca65914d0de5b4dad41f
|
||||
F src/attach.c 3801129015ef59d76bf23c95ef9b0069d18a0c52
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53
|
||||
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
|
||||
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c 02e1a4e71d8fc37e9fd5216c15d989d148a77c87
|
||||
F src/btree.c 7b2c3cd16deedff7f4904f2e871e7b77328b9872
|
||||
F src/btree.h a61ddebc78c66795a2b93181321a116746302cc9
|
||||
F src/btreeInt.h f038e818bfadf75afbd09819ed93c26a333d39e0
|
||||
F src/build.c 7e6c275ab1731510d6f793d0f88373ab3e858e69
|
||||
F src/build.c 13b9d82181d95af7b00ec8a8e1304bac096432d4
|
||||
F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 77779efbe78dd678d84bfb4fc2e87b6b6ad8dccd
|
||||
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
|
||||
F src/delete.c a3f2007baa239c6e1fc3246cf366febd24c1a12e
|
||||
F src/expr.c e3e09af908b968305d4efeda8dc3499a087ee7d2
|
||||
F src/delete.c 2017d2913f760d581378259064d8be67882771d1
|
||||
F src/expr.c 9bea427f95665c1aa8fdc87b7678546eef50c296
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 2ab0f5384b70594468ef3ac5c7ed8ca24bfd17d5
|
||||
F src/func.c f4499b39d66b71825514334ce67b32ff14bd19f5
|
||||
|
@ -197,7 +197,7 @@ F src/global.c 1d7bb7ea8254ae6a68ed9bfaf65fcb3d1690b486
|
|||
F src/hash.c d139319967164f139c8d1bb8a11b14db9c4ba3cd
|
||||
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c a8a987ba42e7172b144052db79e7246da6ae2ccf
|
||||
F src/insert.c 985b61befb66ae35d629f10c3601ce9fa1bd8ef3
|
||||
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
|
||||
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
||||
|
@ -219,12 +219,12 @@ F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
|
|||
F src/os.c 1b147e4cf7cc39e618115c14a086aed44bc91ace
|
||||
F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f
|
||||
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
|
||||
F src/os_unix.c f3ed0e406cbf9c820565b2118232d0796346130f
|
||||
F src/os_win.c 1b21af72c5fa6f9e519a5fcab33e80d182b1aedb
|
||||
F src/pager.c efa923693e958696eee69b205a20bfbc402c8480
|
||||
F src/os_unix.c 18f7f95dc6bcb9cf4d4a238d8e2de96611bc2ae5
|
||||
F src/os_win.c d4284f003445054a26689f1264b1b9bf7261bd1b
|
||||
F src/pager.c 0ffa313a30ed6d061d9c6601b7b175cc50a1cab7
|
||||
F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428
|
||||
F src/parse.y bd51bc17cbfe7549adb4ca3747b1c3d384645065
|
||||
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
|
||||
F src/parse.y cce844ccb80b5f969b04c25100c8d94338488efb
|
||||
F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2
|
||||
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
|
||||
F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c
|
||||
F src/pragma.c ed409ce4104cf4d9de6ead40ace70974f124853b
|
||||
|
@ -233,21 +233,21 @@ F src/printf.c 85d07756e45d7496d19439dcae3e6e9e0090f269
|
|||
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
|
||||
F src/resolve.c 7eda9097b29fcf3d2b42fdc17d1de672134e09b6
|
||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||
F src/select.c a421f3fb7f52a3c0b37f5caeabd27799e8a9ae58
|
||||
F src/shell.c 24722d24d4ea8ca93db35e44db7308de786767ca
|
||||
F src/select.c 50961f0d0ab8f2d45ff29ec5f91d8db221330ca7
|
||||
F src/shell.c 7dedf7367ee49050b0366bf8dbc8ec2bd15b42c7
|
||||
F src/sqlite.h.in a92d7fcdcb1a8003a62e916ec49025f27ccb56b8
|
||||
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||
F src/sqliteInt.h 5bec5e943c184f137e5f0895886346c82618728d
|
||||
F src/sqliteInt.h 2c9a421de05893c798b851004658b12e9843c0f7
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c 97a7cb53646107433f463592ed785f6e177b93b5
|
||||
F src/tclsqlite.c 52c628d5ac76a13d9c633e6bf384595ac18662b7
|
||||
F src/test1.c 2401eee14a4309a7cfe2aeb2f30ad517a1d9c299
|
||||
F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35
|
||||
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
|
||||
F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
|
||||
F src/test5.c a6d1ac55ac054d0b2b8f37b5e655b6c92645a013
|
||||
F src/test5.c 41e6e732f14a54c7b47f753e364700760f6521b0
|
||||
F src/test6.c 41cacf3b0dd180823919bf9e1fbab287c9266723
|
||||
F src/test7.c 72b732baa5642f795655ba1126ea032af46ecfd2
|
||||
F src/test8.c 54ccd7b1df5062f0ecbf50a8f7b618f8b1f13b20
|
||||
|
@ -289,26 +289,26 @@ F src/test_vfs.c e72f555ef7a59080f898fcf1a233deb9eb704ea9
|
|||
F src/test_vfstrace.c 3a0ab304682fecbceb689e7d9b904211fde11d78
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 6da2de6e12218ccb0aea5184b56727d011f4bee7
|
||||
F src/trigger.c 5c1c0b899ac0ce284763dcb8fdbaa38ecf15ef98
|
||||
F src/trigger.c a417d386e214f0abd2e0f756b834b4d9f4d3368a
|
||||
F src/update.c 437c130e7d16230e182782baffa8290a349cdf7d
|
||||
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
|
||||
F src/util.c 15ac2627f548f5481d0d7e6c4eb67be673027695
|
||||
F src/util.c c46c90459ef9bdc0c6c73803cf4c55425b4771cf
|
||||
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
||||
F src/vdbe.c 7b5d45ba9be3cb2e27ff52e0ce452a58fd3bc282
|
||||
F src/vdbe.c 8b389fc56e63664e168c84989c645905eec650f4
|
||||
F src/vdbe.h 06016671144c70373331e348fd7edf2b2535ac97
|
||||
F src/vdbeInt.h 08d79db15519f98d6d2c2dedaebfbb7f3d69a6d8
|
||||
F src/vdbeapi.c 647d65813a5595c7f667b9f43d119ecd8d70be08
|
||||
F src/vdbeaux.c 25e8ee3c8fdb3951ee46616f09c62cce217df855
|
||||
F src/vdbeblob.c 6e791541114d482074e031ef8dbc3d5e5c180e23
|
||||
F src/vdbemem.c 23cdc14ed43e0aafa57bd72b9bf3d5b1641afa91
|
||||
F src/vdbeInt.h 9ad4950c4af3531253a7b86cfc88f9ec3c38834c
|
||||
F src/vdbeapi.c a130692dd1016cd2becdae323391437f580b2417
|
||||
F src/vdbeaux.c b02637a5c0369c2206ed883a3f24c4f71a85b71c
|
||||
F src/vdbeblob.c c8c547cc9d5dd2d5a3d355128bb4a02e1889f423
|
||||
F src/vdbemem.c 06603e8e9d2f3247b68c6bbe4bd37fb6721b5bda
|
||||
F src/vdbesort.c 9d83601f9d6243fe70dd0169a2820c5ddfd48147
|
||||
F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
|
||||
F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
|
||||
F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
|
||||
F src/where.c 67ae3b5e97ecff36c70cb61ccc7d74cf228f1596
|
||||
F src/whereInt.h 96a75c61f1d2b9d4a8e4bb17d89deb0cf7cba358
|
||||
F src/where.c b0436385f40e86f0f4cc60355cd018bde2c89d4b
|
||||
F src/whereInt.h 921f935af8b684ffb49705610bda7284db1db138
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
|
||||
|
@ -446,7 +446,7 @@ F test/descidx1.test 6d03b44c8538fe0eb4924e19fba10cdd8f3c9240
|
|||
F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
|
||||
F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2
|
||||
F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
|
||||
F test/distinct.test 44028aaf161a5e80a2f229622b3a174d3b352810
|
||||
F test/distinct.test c7b194ef95dbddb32d77acbbab2e023c6eed0cb2
|
||||
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
|
||||
F test/e_createtable.test ee95d48664503d40f6cc9ef4a7d03216188e2ada
|
||||
F test/e_delete.test d5186e2f5478b659f16a2c8b66c09892823e542a
|
||||
|
@ -800,7 +800,7 @@ F test/select6.test e76bd10a56988f15726c097a5d5a7966fe82d3b2
|
|||
F test/select7.test 7fd2ef598cfabb6b9ff6ac13973b91d0527df49d
|
||||
F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d
|
||||
F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95
|
||||
F test/selectA.test 99cf21df033b93033ea4f34aba14a500f48f04fe
|
||||
F test/selectA.test 77adaffe9704cb80e301ebaeff4b107b58d435c5
|
||||
F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25
|
||||
F test/selectC.test 871fb55d884d3de5943c4057ebd22c2459e71977
|
||||
F test/selectD.test b0f02a04ef7737decb24e08be2c39b9664b43394
|
||||
|
@ -839,7 +839,7 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523
|
|||
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
|
||||
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
|
||||
F test/speedtest1.c 7130d2cb6db45baa553a4ab2f715116c71c2d9f4
|
||||
F test/speedtest1.c 1603da7b4897716f9df15bd71b0310f56ec3181e
|
||||
F test/spellfix.test 61309f5efbec53603b3f86457d34a504f80abafe
|
||||
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
|
||||
F test/stat.test 76fd746b85459e812a0193410fb599f0531f22de
|
||||
|
@ -884,6 +884,7 @@ F test/tkt-3998683a16.test 6d1d04d551ed1704eb3396ca87bb9ccc8c5c1eb7
|
|||
F test/tkt-3a77c9714e.test b08bca26de1140bdf004a37716582a43d7bd8be8
|
||||
F test/tkt-3fe897352e.test 27e26eb0f1811aeba4d65aba43a4c52e99da5e70
|
||||
F test/tkt-4a03edc4c8.test 91c0e135888cdc3d4eea82406a44b05c8c1648d0
|
||||
F test/tkt-4c86b126f2.test cbcc611becd0396890169ab23102dd70048bbc9a
|
||||
F test/tkt-4dd95f6943.test 3d0ce415d2ee15d3d564121960016b9c7be79407
|
||||
F test/tkt-54844eea3f.test a12b851128f46a695e4e378cca67409b9b8f5894
|
||||
F test/tkt-5d863f876e.test c9f36ca503fa154a3655f92a69d2c30da1747bfa
|
||||
|
@ -1092,7 +1093,7 @@ F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
|
|||
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
||||
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
|
||||
F test/where7.test 5a4b0abc207d71da4deecd734ad8579e8dd40aa8
|
||||
F test/where8.test d2b4fd6d7b7c5d44f590182a05033d78a14c00a1
|
||||
F test/where8.test 84033c4da466d90fe7ef0152661ff67fd218105f
|
||||
F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739
|
||||
F test/where9.test 4f3eab951353a3ae164befc521c777dfa903e46c
|
||||
F test/whereA.test 4d253178d135ec46d1671e440cd8f2b916aa6e6b
|
||||
|
@ -1107,7 +1108,7 @@ F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
|
|||
F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
|
||||
F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
|
||||
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
|
||||
F test/with1.test ce15d69d34a2576b0e47d78c244d1ba2a31679d1
|
||||
F test/with1.test 268081a6b14817a262ced4d0ee34d4d2a1dd2068
|
||||
F test/with2.test 2fe78fcd8deef2a0f9cfc49bfc755911d0b3fd64
|
||||
F test/withM.test e97f2a8c506ab3ea9eab94e6f6072f6cc924c991
|
||||
F test/without_rowid1.test aaa26da19d543cd8d3d2d0e686dfa255556c15c8
|
||||
|
@ -1167,7 +1168,7 @@ F tool/vdbe-compress.tcl 0cf56e9263a152b84da86e75a5c0cdcdb7a47891
|
|||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
||||
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
||||
P 6b6dcd4cc75317628072abac7c58b41361cc72b4 e816dd924619db5f766de6df74ea2194f3e3b538
|
||||
R 346d101c294d20bde7ae1f470938d788
|
||||
P a704b65b9476d60c88b5bc82f2743faa2bce5ac2 c950d6c4117d076f871518e738cdf9e8c46a19fc
|
||||
R 938a4c92585daead803d3d317e7d6a12
|
||||
U drh
|
||||
Z 539f6826e36788b480b45411fb5563b3
|
||||
Z d6bfa33b9fae0786f865ca76b023abf9
|
||||
|
|
|
@ -1 +1 @@
|
|||
a704b65b9476d60c88b5bc82f2743faa2bce5ac2
|
||||
b006792695d23980e1923b21915d5c1138ecf29d
|
|
@ -469,7 +469,7 @@ void sqlite3AlterRenameTable(
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Begin a transaction and code the VerifyCookie for database iDb.
|
||||
/* Begin a transaction for database iDb.
|
||||
** Then modify the schema cookie (since the ALTER TABLE modifies the
|
||||
** schema). Open a statement transaction if the table is a virtual
|
||||
** table.
|
||||
|
|
22
src/btree.c
22
src/btree.c
|
@ -4777,6 +4777,15 @@ int sqlite3BtreeEof(BtCursor *pCur){
|
|||
** successful then set *pRes=0. If the cursor
|
||||
** was already pointing to the last entry in the database before
|
||||
** this routine was called, then set *pRes=1.
|
||||
**
|
||||
** The calling function will set *pRes to 0 or 1. The initial *pRes value
|
||||
** will be 1 if the cursor being stepped corresponds to an SQL index and
|
||||
** if this routine could have been skipped if that SQL index had been
|
||||
** a unique index. Otherwise the caller will have set *pRes to zero.
|
||||
** Zero is the common case. The btree implementation is free to use the
|
||||
** initial *pRes value as a hint to improve performance, but the current
|
||||
** SQLite btree implementation does not. (Note that the comdb2 btree
|
||||
** implementation does use this hint, however.)
|
||||
*/
|
||||
int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
||||
int rc;
|
||||
|
@ -4785,6 +4794,7 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
|||
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( pRes!=0 );
|
||||
assert( *pRes==0 || *pRes==1 );
|
||||
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
|
||||
if( pCur->eState!=CURSOR_VALID ){
|
||||
rc = restoreCursorPosition(pCur);
|
||||
|
@ -4863,6 +4873,15 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
|
|||
** successful then set *pRes=0. If the cursor
|
||||
** was already pointing to the first entry in the database before
|
||||
** this routine was called, then set *pRes=1.
|
||||
**
|
||||
** The calling function will set *pRes to 0 or 1. The initial *pRes value
|
||||
** will be 1 if the cursor being stepped corresponds to an SQL index and
|
||||
** if this routine could have been skipped if that SQL index had been
|
||||
** a unique index. Otherwise the caller will have set *pRes to zero.
|
||||
** Zero is the common case. The btree implementation is free to use the
|
||||
** initial *pRes value as a hint to improve performance, but the current
|
||||
** SQLite btree implementation does not. (Note that the comdb2 btree
|
||||
** implementation does use this hint, however.)
|
||||
*/
|
||||
int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
|
||||
int rc;
|
||||
|
@ -4870,6 +4889,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
|
|||
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( pRes!=0 );
|
||||
assert( *pRes==0 || *pRes==1 );
|
||||
assert( pCur->skipNext==0 || pCur->eState!=CURSOR_VALID );
|
||||
pCur->atLast = 0;
|
||||
if( pCur->eState!=CURSOR_VALID ){
|
||||
|
@ -7096,7 +7116,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
|||
** sub-tree headed by the child page of the cell being deleted. This makes
|
||||
** balancing the tree following the delete operation easier. */
|
||||
if( !pPage->leaf ){
|
||||
int notUsed;
|
||||
int notUsed = 0;
|
||||
rc = sqlite3BtreePrevious(pCur, ¬Used);
|
||||
if( rc ) return rc;
|
||||
}
|
||||
|
|
93
src/build.c
93
src/build.c
|
@ -149,20 +149,22 @@ void sqlite3FinishCoding(Parse *pParse){
|
|||
** transaction on each used database and to verify the schema cookie
|
||||
** on each used database.
|
||||
*/
|
||||
if( pParse->cookieGoto>0 ){
|
||||
if( db->mallocFailed==0 && (pParse->cookieMask || pParse->pConstExpr) ){
|
||||
yDbMask mask;
|
||||
int iDb, i, addr;
|
||||
sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
|
||||
int iDb, i;
|
||||
assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
|
||||
sqlite3VdbeJumpHere(v, 0);
|
||||
for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
|
||||
if( (mask & pParse->cookieMask)==0 ) continue;
|
||||
sqlite3VdbeUsesBtree(v, iDb);
|
||||
sqlite3VdbeAddOp2(v,OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
|
||||
if( db->init.busy==0 ){
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
sqlite3VdbeAddOp3(v, OP_VerifyCookie,
|
||||
iDb, pParse->cookieValue[iDb],
|
||||
db->aDb[iDb].pSchema->iGeneration);
|
||||
}
|
||||
sqlite3VdbeAddOp4Int(v,
|
||||
OP_Transaction, /* Opcode */
|
||||
iDb, /* P1 */
|
||||
(mask & pParse->writeMask)!=0, /* P2 */
|
||||
pParse->cookieValue[iDb], /* P3 */
|
||||
db->aDb[iDb].pSchema->iGeneration /* P4 */
|
||||
);
|
||||
if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
for(i=0; i<pParse->nVtabLock; i++){
|
||||
|
@ -183,17 +185,16 @@ void sqlite3FinishCoding(Parse *pParse){
|
|||
sqlite3AutoincrementBegin(pParse);
|
||||
|
||||
/* Code constant expressions that where factored out of inner loops */
|
||||
addr = pParse->cookieGoto;
|
||||
if( pParse->pConstExpr ){
|
||||
ExprList *pEL = pParse->pConstExpr;
|
||||
pParse->cookieGoto = 0;
|
||||
pParse->okConstFactor = 0;
|
||||
for(i=0; i<pEL->nExpr; i++){
|
||||
sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Finally, jump back to the beginning of the executable code. */
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -216,7 +217,6 @@ void sqlite3FinishCoding(Parse *pParse){
|
|||
pParse->nSet = 0;
|
||||
pParse->nVar = 0;
|
||||
pParse->cookieMask = 0;
|
||||
pParse->cookieGoto = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3825,59 +3825,26 @@ int sqlite3OpenTempDatabase(Parse *pParse){
|
|||
}
|
||||
|
||||
/*
|
||||
** Generate VDBE code that will verify the schema cookie and start
|
||||
** a read-transaction for all named database files.
|
||||
**
|
||||
** It is important that all schema cookies be verified and all
|
||||
** read transactions be started before anything else happens in
|
||||
** the VDBE program. But this routine can be called after much other
|
||||
** code has been generated. So here is what we do:
|
||||
**
|
||||
** The first time this routine is called, we code an OP_Goto that
|
||||
** will jump to a subroutine at the end of the program. Then we
|
||||
** record every database that needs its schema verified in the
|
||||
** pParse->cookieMask field. Later, after all other code has been
|
||||
** generated, the subroutine that does the cookie verifications and
|
||||
** starts the transactions will be coded and the OP_Goto P2 value
|
||||
** will be made to point to that subroutine. The generation of the
|
||||
** cookie verification subroutine code happens in sqlite3FinishCoding().
|
||||
**
|
||||
** If iDb<0 then code the OP_Goto only - don't set flag to verify the
|
||||
** schema on any databases. This can be used to position the OP_Goto
|
||||
** early in the code, before we know if any database tables will be used.
|
||||
** Record the fact that the schema cookie will need to be verified
|
||||
** for database iDb. The code to actually verify the schema cookie
|
||||
** will occur at the end of the top-level VDBE and will be generated
|
||||
** later, by sqlite3FinishCoding().
|
||||
*/
|
||||
void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
|
||||
Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
||||
sqlite3 *db = pToplevel->db;
|
||||
yDbMask mask;
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
if( pToplevel!=pParse ){
|
||||
/* This branch is taken if a trigger is currently being coded. In this
|
||||
** case, set cookieGoto to a non-zero value to show that this function
|
||||
** has been called. This is used by the sqlite3ExprCodeConstants()
|
||||
** function. */
|
||||
pParse->cookieGoto = -1;
|
||||
}
|
||||
#endif
|
||||
if( pToplevel->cookieGoto==0 ){
|
||||
Vdbe *v = sqlite3GetVdbe(pToplevel);
|
||||
if( v==0 ) return; /* This only happens if there was a prior error */
|
||||
pToplevel->cookieGoto = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0)+1;
|
||||
}
|
||||
if( iDb>=0 ){
|
||||
sqlite3 *db = pToplevel->db;
|
||||
yDbMask mask;
|
||||
|
||||
assert( iDb<db->nDb );
|
||||
assert( db->aDb[iDb].pBt!=0 || iDb==1 );
|
||||
assert( iDb<SQLITE_MAX_ATTACHED+2 );
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
mask = ((yDbMask)1)<<iDb;
|
||||
if( (pToplevel->cookieMask & mask)==0 ){
|
||||
pToplevel->cookieMask |= mask;
|
||||
pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
|
||||
if( !OMIT_TEMPDB && iDb==1 ){
|
||||
sqlite3OpenTempDatabase(pToplevel);
|
||||
}
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
assert( db->aDb[iDb].pBt!=0 || iDb==1 );
|
||||
assert( iDb<SQLITE_MAX_ATTACHED+2 );
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
mask = ((yDbMask)1)<<iDb;
|
||||
if( (pToplevel->cookieMask & mask)==0 ){
|
||||
pToplevel->cookieMask |= mask;
|
||||
pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
|
||||
if( !OMIT_TEMPDB && iDb==1 ){
|
||||
sqlite3OpenTempDatabase(pToplevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,10 +97,8 @@ void sqlite3MaterializeView(
|
|||
SrcList *pFrom;
|
||||
sqlite3 *db = pParse->db;
|
||||
int iDb = sqlite3SchemaToIndex(db, pView->pSchema);
|
||||
|
||||
pWhere = sqlite3ExprDup(db, pWhere, 0);
|
||||
pFrom = sqlite3SrcListAppend(db, 0, 0, 0);
|
||||
|
||||
if( pFrom ){
|
||||
assert( pFrom->nSrc==1 );
|
||||
pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
|
||||
|
@ -108,10 +106,7 @@ void sqlite3MaterializeView(
|
|||
assert( pFrom->a[0].pOn==0 );
|
||||
assert( pFrom->a[0].pUsing==0 );
|
||||
}
|
||||
|
||||
pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0);
|
||||
if( pSel ) pSel->selFlags |= SF_Materialize;
|
||||
|
||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
|
||||
sqlite3Select(pParse, pSel, &dest);
|
||||
sqlite3SelectDelete(db, pSel);
|
||||
|
|
|
@ -1060,7 +1060,6 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
|
|||
pNew->iLimit = 0;
|
||||
pNew->iOffset = 0;
|
||||
pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
|
||||
pNew->pRightmost = 0;
|
||||
pNew->addrOpenEphm[0] = -1;
|
||||
pNew->addrOpenEphm[1] = -1;
|
||||
pNew->addrOpenEphm[2] = -1;
|
||||
|
@ -1584,7 +1583,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
|||
pExpr = p->pEList->a[0].pExpr;
|
||||
iCol = (i16)pExpr->iColumn;
|
||||
|
||||
/* Code an OP_VerifyCookie and OP_TableLock for <table>. */
|
||||
/* Code an OP_Transaction and OP_TableLock for <table>. */
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
||||
|
@ -1763,7 +1762,6 @@ int sqlite3CodeSubselect(
|
|||
*/
|
||||
pExpr->iTable = pParse->nTab++;
|
||||
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, !isRowid);
|
||||
if( rMayHaveNull==0 ) sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
|
||||
pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, 1, 1);
|
||||
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
|
|
71
src/insert.c
71
src/insert.c
|
@ -349,17 +349,13 @@ void sqlite3AutoincrementEnd(Parse *pParse){
|
|||
** co-routine. Run the co-routine to its next breakpoint
|
||||
** by calling "OP_Yield $X" where $X is pDest->iSDParm.
|
||||
**
|
||||
** pDest->iSDParm+1 The register holding the "completed" flag for the
|
||||
** co-routine. This register is 0 if the previous Yield
|
||||
** generated a new result row, or 1 if the subquery
|
||||
** has completed. If the Yield is called again
|
||||
** after this register becomes 1, then the VDBE will
|
||||
** halt with an SQLITE_INTERNAL error.
|
||||
**
|
||||
** pDest->iSdst First result register.
|
||||
**
|
||||
** pDest->nSdst Number of result registers.
|
||||
**
|
||||
** At EOF the first result register will be marked as "undefined" so that
|
||||
** the caller can know when to stop reading results.
|
||||
**
|
||||
** This routine handles all of the register allocation and fills in the
|
||||
** pDest structure appropriately.
|
||||
**
|
||||
|
@ -370,7 +366,6 @@ void sqlite3AutoincrementEnd(Parse *pParse){
|
|||
** reg[pDest->iSdst+pDest->nSdst-1]:
|
||||
**
|
||||
** X <- A
|
||||
** EOF <- 0
|
||||
** goto B
|
||||
** A: setup for the SELECT
|
||||
** loop rows in the SELECT
|
||||
|
@ -378,16 +373,13 @@ void sqlite3AutoincrementEnd(Parse *pParse){
|
|||
** yield X
|
||||
** end loop
|
||||
** cleanup after the SELECT
|
||||
** EOF <- 1
|
||||
** yield X
|
||||
** halt-error
|
||||
** end co-routine R
|
||||
** B:
|
||||
**
|
||||
** To use this subroutine, the caller generates code as follows:
|
||||
**
|
||||
** [ Co-routine generated by this subroutine, shown above ]
|
||||
** S: yield X
|
||||
** if EOF goto E
|
||||
** S: yield X, at EOF goto E
|
||||
** if skip this row, goto C
|
||||
** if terminate loop, goto E
|
||||
** deal with this row
|
||||
|
@ -396,31 +388,21 @@ void sqlite3AutoincrementEnd(Parse *pParse){
|
|||
*/
|
||||
int sqlite3CodeCoroutine(Parse *pParse, Select *pSelect, SelectDest *pDest){
|
||||
int regYield; /* Register holding co-routine entry-point */
|
||||
int regEof; /* Register holding co-routine completion flag */
|
||||
int addrTop; /* Top of the co-routine */
|
||||
int j1; /* Jump instruction */
|
||||
int rc; /* Result code */
|
||||
Vdbe *v; /* VDBE under construction */
|
||||
|
||||
regYield = ++pParse->nMem;
|
||||
regEof = ++pParse->nMem;
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
addrTop = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, addrTop+2, regYield); /* X <- A */
|
||||
VdbeComment((v, "Co-routine entry point"));
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regEof); /* EOF <- 0 */
|
||||
VdbeComment((v, "Co-routine completion flag"));
|
||||
addrTop = sqlite3VdbeCurrentAddr(v) + 1;
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
|
||||
sqlite3SelectDestInit(pDest, SRT_Coroutine, regYield);
|
||||
j1 = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
|
||||
rc = sqlite3Select(pParse, pSelect, pDest);
|
||||
assert( pParse->nErr==0 || rc );
|
||||
if( pParse->db->mallocFailed && rc==SQLITE_OK ) rc = SQLITE_NOMEM;
|
||||
if( rc ) return rc;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEof); /* EOF <- 1 */
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regYield); /* yield X */
|
||||
sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_INTERNAL, OE_Abort);
|
||||
VdbeComment((v, "End of coroutine"));
|
||||
sqlite3VdbeJumpHere(v, j1); /* label B: */
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
|
||||
sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -488,7 +470,6 @@ static int xferOptimization(
|
|||
** and the SELECT clause does not read from <table> at any time.
|
||||
** The generated code follows this template:
|
||||
**
|
||||
** EOF <- 0
|
||||
** X <- A
|
||||
** goto B
|
||||
** A: setup for the SELECT
|
||||
|
@ -497,12 +478,9 @@ static int xferOptimization(
|
|||
** yield X
|
||||
** end loop
|
||||
** cleanup after the SELECT
|
||||
** EOF <- 1
|
||||
** yield X
|
||||
** goto A
|
||||
** end-coroutine X
|
||||
** B: open write cursor to <table> and its indices
|
||||
** C: yield X
|
||||
** if EOF goto D
|
||||
** C: yield X, at EOF goto D
|
||||
** insert the select result into <table> from R..R+n
|
||||
** goto C
|
||||
** D: cleanup
|
||||
|
@ -513,7 +491,6 @@ static int xferOptimization(
|
|||
** we have to use a intermediate table to store the results of
|
||||
** the select. The template is like this:
|
||||
**
|
||||
** EOF <- 0
|
||||
** X <- A
|
||||
** goto B
|
||||
** A: setup for the SELECT
|
||||
|
@ -522,12 +499,9 @@ static int xferOptimization(
|
|||
** yield X
|
||||
** end loop
|
||||
** cleanup after the SELECT
|
||||
** EOF <- 1
|
||||
** yield X
|
||||
** halt-error
|
||||
** end co-routine R
|
||||
** B: open temp table
|
||||
** L: yield X
|
||||
** if EOF goto M
|
||||
** L: yield X, at EOF goto M
|
||||
** insert row from R..R+n into temp table
|
||||
** goto L
|
||||
** M: open write cursor to <table> and its indices
|
||||
|
@ -576,7 +550,6 @@ void sqlite3Insert(
|
|||
int regIns; /* Block of regs holding rowid+data being inserted */
|
||||
int regRowid; /* registers holding insert rowid */
|
||||
int regData; /* register holding first column to insert */
|
||||
int regEof = 0; /* Register recording end of SELECT data */
|
||||
int *aRegIdx = 0; /* One register allocated to each index */
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
|
@ -689,7 +662,6 @@ void sqlite3Insert(
|
|||
int rc = sqlite3CodeCoroutine(pParse, pSelect, &dest);
|
||||
if( rc ) goto insert_cleanup;
|
||||
|
||||
regEof = dest.iSDParm + 1;
|
||||
regFromSelect = dest.iSdst;
|
||||
assert( pSelect->pEList );
|
||||
nColumn = pSelect->pEList->nExpr;
|
||||
|
@ -714,8 +686,7 @@ void sqlite3Insert(
|
|||
** here is from the 4th template:
|
||||
**
|
||||
** B: open temp table
|
||||
** L: yield X
|
||||
** if EOF goto M
|
||||
** L: yield X, goto M at EOF
|
||||
** insert row from R..R+n into temp table
|
||||
** goto L
|
||||
** M: ...
|
||||
|
@ -723,19 +694,17 @@ void sqlite3Insert(
|
|||
int regRec; /* Register to hold packed record */
|
||||
int regTempRowid; /* Register to hold temp table ROWID */
|
||||
int addrTop; /* Label "L" */
|
||||
int addrIf; /* Address of jump to M */
|
||||
|
||||
srcTab = pParse->nTab++;
|
||||
regRec = sqlite3GetTempReg(pParse);
|
||||
regTempRowid = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, nColumn);
|
||||
addrTop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
|
||||
addrIf = sqlite3VdbeAddOp1(v, OP_If, regEof);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regTempRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regTempRowid);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
|
||||
sqlite3VdbeJumpHere(v, addrIf);
|
||||
sqlite3VdbeJumpHere(v, addrTop);
|
||||
sqlite3ReleaseTempReg(pParse, regRec);
|
||||
sqlite3ReleaseTempReg(pParse, regTempRowid);
|
||||
}
|
||||
|
@ -847,7 +816,7 @@ void sqlite3Insert(
|
|||
/* This block codes the top of loop only. The complete loop is the
|
||||
** following pseudocode (template 4):
|
||||
**
|
||||
** rewind temp table
|
||||
** rewind temp table, if empty goto D
|
||||
** C: loop over rows of intermediate table
|
||||
** transfer values form intermediate table into <table>
|
||||
** end loop
|
||||
|
@ -859,14 +828,12 @@ void sqlite3Insert(
|
|||
/* This block codes the top of loop only. The complete loop is the
|
||||
** following pseudocode (template 3):
|
||||
**
|
||||
** C: yield X
|
||||
** if EOF goto D
|
||||
** C: yield X, at EOF goto D
|
||||
** insert the select result into <table> from R..R+n
|
||||
** goto C
|
||||
** D: ...
|
||||
*/
|
||||
addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
|
||||
addrInsTop = sqlite3VdbeAddOp1(v, OP_If, regEof);
|
||||
addrInsTop = addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
|
||||
}
|
||||
|
||||
/* Allocate registers for holding the rowid of the new row,
|
||||
|
@ -2083,7 +2050,7 @@ static int xferOptimization(
|
|||
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, emptySrcTest);
|
||||
if( emptySrcTest ) sqlite3VdbeJumpHere(v, emptySrcTest);
|
||||
sqlite3ReleaseTempReg(pParse, regRowid);
|
||||
sqlite3ReleaseTempReg(pParse, regData);
|
||||
if( emptyDestTest ){
|
||||
|
|
|
@ -83,32 +83,6 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** These #defines should enable >2GB file support on Posix if the
|
||||
** underlying operating system supports it. If the OS lacks
|
||||
** large file support, these should be no-ops.
|
||||
**
|
||||
** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch
|
||||
** on the compiler command line. This is necessary if you are compiling
|
||||
** on a recent machine (ex: RedHat 7.2) but you want your code to work
|
||||
** on an older machine (ex: RedHat 6.0). If you compile on RedHat 7.2
|
||||
** without this option, LFS is enable. But LFS does not exist in the kernel
|
||||
** in RedHat 6.0, so the code won't work. Hence, for maximum binary
|
||||
** portability you should omit LFS.
|
||||
**
|
||||
** The previous paragraph was written in 2005. (This paragraph is written
|
||||
** on 2008-11-28.) These days, all Linux kernels support large files, so
|
||||
** you should probably leave LFS enabled. But some embedded platforms might
|
||||
** lack LFS in which case the SQLITE_DISABLE_LFS macro might still be useful.
|
||||
*/
|
||||
#ifndef SQLITE_DISABLE_LFS
|
||||
# define _LARGE_FILE 1
|
||||
# ifndef _FILE_OFFSET_BITS
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
# endif
|
||||
# define _LARGEFILE_SOURCE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** standard include files.
|
||||
*/
|
||||
|
|
|
@ -3201,7 +3201,7 @@ static int winDeviceCharacteristics(sqlite3_file *id){
|
|||
** During sqlite3_os_init() we do a GetSystemInfo()
|
||||
** to get the granularity size.
|
||||
*/
|
||||
SYSTEM_INFO winSysInfo;
|
||||
static SYSTEM_INFO winSysInfo;
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
|
||||
|
|
|
@ -1683,7 +1683,7 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
|
|||
** already in memory.
|
||||
*/
|
||||
static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
|
||||
PgHdr *p; /* Return value */
|
||||
PgHdr *p = 0; /* Return value */
|
||||
|
||||
/* It is not possible for a call to PcacheFetch() with createFlag==0 to
|
||||
** fail, since no attempt to allocate dynamic memory will be made.
|
||||
|
|
21
src/parse.y
21
src/parse.y
|
@ -412,13 +412,26 @@ cmd ::= select(X). {
|
|||
%type oneselect {Select*}
|
||||
%destructor oneselect {sqlite3SelectDelete(pParse->db, $$);}
|
||||
|
||||
select(A) ::= with(W) selectnowith(X). {
|
||||
if( X ){
|
||||
X->pWith = W;
|
||||
select(A) ::= with(W) selectnowith(X). {
|
||||
Select *p = X, *pNext, *pLoop;
|
||||
if( p ){
|
||||
int cnt = 0, mxSelect;
|
||||
p->pWith = W;
|
||||
if( p->pPrior ){
|
||||
pNext = 0;
|
||||
for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){
|
||||
pLoop->pNext = pNext;
|
||||
pLoop->selFlags |= SF_Compound;
|
||||
}
|
||||
mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT];
|
||||
if( mxSelect && cnt>mxSelect ){
|
||||
sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
|
||||
}
|
||||
}
|
||||
}else{
|
||||
sqlite3WithDelete(pParse->db, W);
|
||||
}
|
||||
A = X;
|
||||
A = p;
|
||||
}
|
||||
|
||||
selectnowith(A) ::= oneselect(X). {A = X;}
|
||||
|
|
34
src/pcache.c
34
src/pcache.c
|
@ -23,7 +23,8 @@ struct PCache {
|
|||
int szCache; /* Configured cache size */
|
||||
int szPage; /* Size of every page in this cache */
|
||||
int szExtra; /* Size of extra space for each page */
|
||||
int bPurgeable; /* True if pages are on backing store */
|
||||
u8 bPurgeable; /* True if pages are on backing store */
|
||||
u8 eCreate; /* eCreate value for for xFetch() */
|
||||
int (*xStress)(void*,PgHdr*); /* Call to try make a page clean */
|
||||
void *pStress; /* Argument to xStress */
|
||||
sqlite3_pcache *pCache; /* Pluggable cache module */
|
||||
|
@ -90,6 +91,10 @@ static void pcacheRemoveFromDirtyList(PgHdr *pPage){
|
|||
}else{
|
||||
assert( pPage==p->pDirty );
|
||||
p->pDirty = pPage->pDirtyNext;
|
||||
if( p->pDirty==0 && p->bPurgeable ){
|
||||
assert( p->eCreate==1 );
|
||||
p->eCreate = 2;
|
||||
}
|
||||
}
|
||||
pPage->pDirtyNext = 0;
|
||||
pPage->pDirtyPrev = 0;
|
||||
|
@ -110,6 +115,9 @@ static void pcacheAddToDirtyList(PgHdr *pPage){
|
|||
if( pPage->pDirtyNext ){
|
||||
assert( pPage->pDirtyNext->pDirtyPrev==0 );
|
||||
pPage->pDirtyNext->pDirtyPrev = pPage;
|
||||
}else if( p->bPurgeable ){
|
||||
assert( p->eCreate==2 );
|
||||
p->eCreate = 1;
|
||||
}
|
||||
p->pDirty = pPage;
|
||||
if( !p->pDirtyTail ){
|
||||
|
@ -179,6 +187,7 @@ void sqlite3PcacheOpen(
|
|||
p->szPage = szPage;
|
||||
p->szExtra = szExtra;
|
||||
p->bPurgeable = bPurgeable;
|
||||
p->eCreate = 2;
|
||||
p->xStress = xStress;
|
||||
p->pStress = pStress;
|
||||
p->szCache = 100;
|
||||
|
@ -218,7 +227,7 @@ int sqlite3PcacheFetch(
|
|||
int createFlag, /* If true, create page if it does not exist already */
|
||||
PgHdr **ppPage /* Write the page here */
|
||||
){
|
||||
sqlite3_pcache_page *pPage = 0;
|
||||
sqlite3_pcache_page *pPage;
|
||||
PgHdr *pPgHdr = 0;
|
||||
int eCreate;
|
||||
|
||||
|
@ -229,8 +238,12 @@ int sqlite3PcacheFetch(
|
|||
/* If the pluggable cache (sqlite3_pcache*) has not been allocated,
|
||||
** allocate it now.
|
||||
*/
|
||||
if( !pCache->pCache && createFlag ){
|
||||
if( !pCache->pCache ){
|
||||
sqlite3_pcache *p;
|
||||
if( !createFlag ){
|
||||
*ppPage = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
p = sqlite3GlobalConfig.pcache2.xCreate(
|
||||
pCache->szPage, pCache->szExtra + sizeof(PgHdr), pCache->bPurgeable
|
||||
);
|
||||
|
@ -241,11 +254,16 @@ int sqlite3PcacheFetch(
|
|||
pCache->pCache = p;
|
||||
}
|
||||
|
||||
eCreate = createFlag * (1 + (!pCache->bPurgeable || !pCache->pDirty));
|
||||
if( pCache->pCache ){
|
||||
pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
|
||||
}
|
||||
|
||||
/* eCreate defines what to do if the page does not exist.
|
||||
** 0 Do not allocate a new page. (createFlag==0)
|
||||
** 1 Allocate a new page if doing so is inexpensive.
|
||||
** (createFlag==1 AND bPurgeable AND pDirty)
|
||||
** 2 Allocate a new page even it doing so is difficult.
|
||||
** (createFlag==1 AND !(bPurgeable AND pDirty)
|
||||
*/
|
||||
eCreate = createFlag==0 ? 0 : pCache->eCreate;
|
||||
assert( (createFlag*(1+(!pCache->bPurgeable||!pCache->pDirty)))==eCreate );
|
||||
pPage = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, pgno, eCreate);
|
||||
if( !pPage && eCreate==1 ){
|
||||
PgHdr *pPg;
|
||||
|
||||
|
|
181
src/select.c
181
src/select.c
|
@ -109,6 +109,14 @@ void sqlite3SelectDelete(sqlite3 *db, Select *p){
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to the right-most SELECT statement in a compound.
|
||||
*/
|
||||
static Select *findRightmost(Select *p){
|
||||
while( p->pNext ) p = p->pNext;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Given 1 to 3 identifiers preceding the JOIN keyword, determine the
|
||||
** type of join. Return an integer constant that expresses that type
|
||||
|
@ -765,12 +773,8 @@ static void selectInnerLoop(
|
|||
}
|
||||
#endif /* #ifndef SQLITE_OMIT_SUBQUERY */
|
||||
|
||||
/* Send the data to the callback function or to a subroutine. In the
|
||||
** case of a subroutine, the subroutine itself is responsible for
|
||||
** popping the data from the stack.
|
||||
*/
|
||||
case SRT_Coroutine:
|
||||
case SRT_Output: {
|
||||
case SRT_Coroutine: /* Send data to a co-routine */
|
||||
case SRT_Output: { /* Return the results */
|
||||
testcase( eDest==SRT_Coroutine );
|
||||
testcase( eDest==SRT_Output );
|
||||
if( pOrderBy ){
|
||||
|
@ -1619,11 +1623,13 @@ Vdbe *sqlite3GetVdbe(Parse *pParse){
|
|||
Vdbe *v = pParse->pVdbe;
|
||||
if( v==0 ){
|
||||
v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
if( v ){
|
||||
sqlite3VdbeAddOp0(v, OP_Trace);
|
||||
if( v ) sqlite3VdbeAddOp0(v, OP_Init);
|
||||
if( pParse->pToplevel==0
|
||||
&& OptimizationEnabled(pParse->db,SQLITE_FactorOutConst)
|
||||
){
|
||||
pParse->okConstFactor = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
@ -1879,7 +1885,9 @@ static void generateWithRecursiveQuery(
|
|||
p->pOrderBy = 0;
|
||||
|
||||
/* Store the results of the setup-query in Queue. */
|
||||
pSetup->pNext = 0;
|
||||
rc = sqlite3Select(pParse, pSetup, &destQueue);
|
||||
pSetup->pNext = p;
|
||||
if( rc ) goto end_of_recursive_query;
|
||||
|
||||
/* Find the next row in the Queue and output that row */
|
||||
|
@ -1984,8 +1992,6 @@ static int multiSelect(
|
|||
assert( (p->selFlags & SF_Recursive)==0 || p->op==TK_ALL || p->op==TK_UNION );
|
||||
db = pParse->db;
|
||||
pPrior = p->pPrior;
|
||||
assert( pPrior->pRightmost!=pPrior );
|
||||
assert( pPrior->pRightmost==p->pRightmost );
|
||||
dest = *pDest;
|
||||
if( pPrior->pOrderBy ){
|
||||
sqlite3ErrorMsg(pParse,"ORDER BY clause should come after %s not before",
|
||||
|
@ -2093,12 +2099,10 @@ static int multiSelect(
|
|||
testcase( p->op==TK_EXCEPT );
|
||||
testcase( p->op==TK_UNION );
|
||||
priorOp = SRT_Union;
|
||||
if( dest.eDest==priorOp && ALWAYS(!p->pLimit &&!p->pOffset) ){
|
||||
if( dest.eDest==priorOp ){
|
||||
/* We can reuse a temporary table generated by a SELECT to our
|
||||
** right.
|
||||
*/
|
||||
assert( p->pRightmost!=p ); /* Can only happen for leftward elements
|
||||
** of a 3-way or more compound */
|
||||
assert( p->pLimit==0 ); /* Not allowed on leftward elements */
|
||||
assert( p->pOffset==0 ); /* Not allowed on leftward elements */
|
||||
unionTab = dest.iSDParm;
|
||||
|
@ -2111,7 +2115,7 @@ static int multiSelect(
|
|||
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0);
|
||||
assert( p->addrOpenEphm[0] == -1 );
|
||||
p->addrOpenEphm[0] = addr;
|
||||
p->pRightmost->selFlags |= SF_UsesEphemeral;
|
||||
findRightmost(p)->selFlags |= SF_UsesEphemeral;
|
||||
assert( p->pEList );
|
||||
}
|
||||
|
||||
|
@ -2200,7 +2204,7 @@ static int multiSelect(
|
|||
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0);
|
||||
assert( p->addrOpenEphm[0] == -1 );
|
||||
p->addrOpenEphm[0] = addr;
|
||||
p->pRightmost->selFlags |= SF_UsesEphemeral;
|
||||
findRightmost(p)->selFlags |= SF_UsesEphemeral;
|
||||
assert( p->pEList );
|
||||
|
||||
/* Code the SELECTs to our left into temporary table "tab1".
|
||||
|
@ -2279,7 +2283,7 @@ static int multiSelect(
|
|||
CollSeq **apColl; /* For looping through pKeyInfo->aColl[] */
|
||||
int nCol; /* Number of columns in result set */
|
||||
|
||||
assert( p->pRightmost==p );
|
||||
assert( p->pNext==0 );
|
||||
nCol = p->pEList->nExpr;
|
||||
pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1);
|
||||
if( !pKeyInfo ){
|
||||
|
@ -2572,9 +2576,7 @@ static int multiSelectOrderBy(
|
|||
SelectDest destA; /* Destination for coroutine A */
|
||||
SelectDest destB; /* Destination for coroutine B */
|
||||
int regAddrA; /* Address register for select-A coroutine */
|
||||
int regEofA; /* Flag to indicate when select-A is complete */
|
||||
int regAddrB; /* Address register for select-B coroutine */
|
||||
int regEofB; /* Flag to indicate when select-B is complete */
|
||||
int addrSelectA; /* Address of the select-A coroutine */
|
||||
int addrSelectB; /* Address of the select-B coroutine */
|
||||
int regOutA; /* Address register for the output-A subroutine */
|
||||
|
@ -2582,6 +2584,7 @@ static int multiSelectOrderBy(
|
|||
int addrOutA; /* Address of the output-A subroutine */
|
||||
int addrOutB = 0; /* Address of the output-B subroutine */
|
||||
int addrEofA; /* Address of the select-A-exhausted subroutine */
|
||||
int addrEofA_noB; /* Alternate addrEofA if B is uninitialized */
|
||||
int addrEofB; /* Address of the select-B-exhausted subroutine */
|
||||
int addrAltB; /* Address of the A<B subroutine */
|
||||
int addrAeqB; /* Address of the A==B subroutine */
|
||||
|
@ -2696,6 +2699,7 @@ static int multiSelectOrderBy(
|
|||
/* Separate the left and the right query from one another
|
||||
*/
|
||||
p->pPrior = 0;
|
||||
pPrior->pNext = 0;
|
||||
sqlite3ResolveOrderGroupBy(pParse, p, p->pOrderBy, "ORDER");
|
||||
if( pPrior->pPrior==0 ){
|
||||
sqlite3ResolveOrderGroupBy(pParse, pPrior, pPrior->pOrderBy, "ORDER");
|
||||
|
@ -2718,37 +2722,30 @@ static int multiSelectOrderBy(
|
|||
p->pOffset = 0;
|
||||
|
||||
regAddrA = ++pParse->nMem;
|
||||
regEofA = ++pParse->nMem;
|
||||
regAddrB = ++pParse->nMem;
|
||||
regEofB = ++pParse->nMem;
|
||||
regOutA = ++pParse->nMem;
|
||||
regOutB = ++pParse->nMem;
|
||||
sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA);
|
||||
sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB);
|
||||
|
||||
/* Jump past the various subroutines and coroutines to the main
|
||||
** merge loop
|
||||
*/
|
||||
j1 = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
addrSelectA = sqlite3VdbeCurrentAddr(v);
|
||||
|
||||
|
||||
/* Generate a coroutine to evaluate the SELECT statement to the
|
||||
** left of the compound operator - the "A" select.
|
||||
*/
|
||||
VdbeNoopComment((v, "Begin coroutine for left SELECT"));
|
||||
addrSelectA = sqlite3VdbeCurrentAddr(v) + 1;
|
||||
j1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA);
|
||||
VdbeComment((v, "left SELECT"));
|
||||
pPrior->iLimit = regLimitA;
|
||||
explainSetInteger(iSub1, pParse->iNextSelectId);
|
||||
sqlite3Select(pParse, pPrior, &destA);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofA);
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
||||
VdbeNoopComment((v, "End coroutine for left SELECT"));
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrA);
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
|
||||
/* Generate a coroutine to evaluate the SELECT statement on
|
||||
** the right - the "B" select
|
||||
*/
|
||||
addrSelectB = sqlite3VdbeCurrentAddr(v);
|
||||
VdbeNoopComment((v, "Begin coroutine for right SELECT"));
|
||||
addrSelectB = sqlite3VdbeCurrentAddr(v) + 1;
|
||||
j1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB);
|
||||
VdbeComment((v, "right SELECT"));
|
||||
savedLimit = p->iLimit;
|
||||
savedOffset = p->iOffset;
|
||||
p->iLimit = regLimitB;
|
||||
|
@ -2757,9 +2754,7 @@ static int multiSelectOrderBy(
|
|||
sqlite3Select(pParse, p, &destB);
|
||||
p->iLimit = savedLimit;
|
||||
p->iOffset = savedOffset;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofB);
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
|
||||
VdbeNoopComment((v, "End coroutine for right SELECT"));
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrB);
|
||||
|
||||
/* Generate a subroutine that outputs the current row of the A
|
||||
** select as the next output row of the compound select.
|
||||
|
@ -2783,13 +2778,12 @@ static int multiSelectOrderBy(
|
|||
/* Generate a subroutine to run when the results from select A
|
||||
** are exhausted and only data in select B remains.
|
||||
*/
|
||||
VdbeNoopComment((v, "eof-A subroutine"));
|
||||
if( op==TK_EXCEPT || op==TK_INTERSECT ){
|
||||
addrEofA = sqlite3VdbeAddOp2(v, OP_Goto, 0, labelEnd);
|
||||
addrEofA_noB = addrEofA = labelEnd;
|
||||
}else{
|
||||
addrEofA = sqlite3VdbeAddOp2(v, OP_If, regEofB, labelEnd);
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
|
||||
VdbeNoopComment((v, "eof-A subroutine"));
|
||||
addrEofA = sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
|
||||
addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEofA);
|
||||
p->nSelectRow += pPrior->nSelectRow;
|
||||
}
|
||||
|
@ -2802,9 +2796,8 @@ static int multiSelectOrderBy(
|
|||
if( p->nSelectRow > pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow;
|
||||
}else{
|
||||
VdbeNoopComment((v, "eof-B subroutine"));
|
||||
addrEofB = sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd);
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
||||
addrEofB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
|
||||
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, labelEnd);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEofB);
|
||||
}
|
||||
|
||||
|
@ -2812,8 +2805,7 @@ static int multiSelectOrderBy(
|
|||
*/
|
||||
VdbeNoopComment((v, "A-lt-B subroutine"));
|
||||
addrAltB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
||||
sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
|
||||
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
|
||||
|
||||
/* Generate code to handle the case of A==B
|
||||
|
@ -2826,8 +2818,7 @@ static int multiSelectOrderBy(
|
|||
}else{
|
||||
VdbeNoopComment((v, "A-eq-B subroutine"));
|
||||
addrAeqB =
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
||||
sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
|
||||
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
|
||||
}
|
||||
|
||||
|
@ -2838,19 +2829,14 @@ static int multiSelectOrderBy(
|
|||
if( op==TK_ALL || op==TK_UNION ){
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
|
||||
}
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
|
||||
sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB);
|
||||
sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
|
||||
|
||||
/* This code runs once to initialize everything.
|
||||
*/
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regEofA);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regEofB);
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regAddrA, addrSelectA);
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regAddrB, addrSelectB);
|
||||
sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
|
||||
sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB);
|
||||
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA_noB);
|
||||
sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB);
|
||||
|
||||
/* Implement the main merge loop
|
||||
*/
|
||||
|
@ -2879,6 +2865,7 @@ static int multiSelectOrderBy(
|
|||
sqlite3SelectDelete(db, p->pPrior);
|
||||
}
|
||||
p->pPrior = pPrior;
|
||||
pPrior->pNext = p;
|
||||
|
||||
/*** TBD: Insert subroutine calls to close cursors on incomplete
|
||||
**** subqueries ****/
|
||||
|
@ -3144,7 +3131,7 @@ static int flattenSubquery(
|
|||
** and (14). */
|
||||
if( pSub->pLimit && p->pLimit ) return 0; /* Restriction (13) */
|
||||
if( pSub->pOffset ) return 0; /* Restriction (14) */
|
||||
if( p->pRightmost && pSub->pLimit ){
|
||||
if( (p->selFlags & SF_Compound)!=0 && pSub->pLimit ){
|
||||
return 0; /* Restriction (15) */
|
||||
}
|
||||
if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */
|
||||
|
@ -3295,14 +3282,14 @@ static int flattenSubquery(
|
|||
p->pOrderBy = pOrderBy;
|
||||
p->pSrc = pSrc;
|
||||
p->op = TK_ALL;
|
||||
p->pRightmost = 0;
|
||||
if( pNew==0 ){
|
||||
pNew = pPrior;
|
||||
p->pPrior = pPrior;
|
||||
}else{
|
||||
pNew->pPrior = pPrior;
|
||||
pNew->pRightmost = 0;
|
||||
if( pPrior ) pPrior->pNext = pNew;
|
||||
pNew->pNext = p;
|
||||
p->pPrior = pNew;
|
||||
}
|
||||
p->pPrior = pNew;
|
||||
if( db->mallocFailed ) return 1;
|
||||
}
|
||||
|
||||
|
@ -3641,6 +3628,10 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
|
|||
pNew->pHaving = 0;
|
||||
pNew->pOrderBy = 0;
|
||||
p->pPrior = 0;
|
||||
p->pNext = 0;
|
||||
p->selFlags &= ~SF_Compound;
|
||||
assert( pNew->pPrior!=0 );
|
||||
pNew->pPrior->pNext = pNew;
|
||||
pNew->pLimit = 0;
|
||||
pNew->pOffset = 0;
|
||||
return WRC_Continue;
|
||||
|
@ -3828,9 +3819,10 @@ static int withExpand(
|
|||
*/
|
||||
static void selectPopWith(Walker *pWalker, Select *p){
|
||||
Parse *pParse = pWalker->pParse;
|
||||
if( p->pWith ){
|
||||
assert( pParse->pWith==p->pWith );
|
||||
pParse->pWith = p->pWith->pOuter;
|
||||
With *pWith = findRightmost(p)->pWith;
|
||||
if( pWith!=0 ){
|
||||
assert( pParse->pWith==pWith );
|
||||
pParse->pWith = pWith->pOuter;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
@ -3880,7 +3872,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
|||
}
|
||||
pTabList = p->pSrc;
|
||||
pEList = p->pEList;
|
||||
sqlite3WithPush(pParse, p->pWith, 0);
|
||||
sqlite3WithPush(pParse, findRightmost(p)->pWith, 0);
|
||||
|
||||
/* Make sure cursor numbers have been assigned to all entries in
|
||||
** the FROM clause of the SELECT statement.
|
||||
|
@ -4552,42 +4544,24 @@ int sqlite3Select(
|
|||
p->selFlags |= SF_Aggregate;
|
||||
}
|
||||
i = -1;
|
||||
}else if( pTabList->nSrc==1 && (p->selFlags & SF_Materialize)==0
|
||||
&& OptimizationEnabled(db, SQLITE_SubqCoroutine)
|
||||
}else if( pTabList->nSrc==1
|
||||
&& OptimizationEnabled(db, SQLITE_SubqCoroutine)
|
||||
){
|
||||
/* Implement a co-routine that will return a single row of the result
|
||||
** set on each invocation.
|
||||
*/
|
||||
int addrTop;
|
||||
int addrEof;
|
||||
int addrTop = sqlite3VdbeCurrentAddr(v)+1;
|
||||
pItem->regReturn = ++pParse->nMem;
|
||||
addrEof = ++pParse->nMem;
|
||||
/* Before coding the OP_Goto to jump to the start of the main routine,
|
||||
** ensure that the jump to the verify-schema routine has already
|
||||
** been coded. Otherwise, the verify-schema would likely be coded as
|
||||
** part of the co-routine. If the main routine then accessed the
|
||||
** database before invoking the co-routine for the first time (for
|
||||
** example to initialize a LIMIT register from a sub-select), it would
|
||||
** be doing so without having verified the schema version and obtained
|
||||
** the required db locks. See ticket d6b36be38. */
|
||||
sqlite3CodeVerifySchema(pParse, -1);
|
||||
sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
addrTop = sqlite3VdbeAddOp1(v, OP_OpenPseudo, pItem->iCursor);
|
||||
sqlite3VdbeChangeP5(v, 1);
|
||||
VdbeComment((v, "coroutine for %s", pItem->pTab->zName));
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop);
|
||||
VdbeComment((v, "%s", pItem->pTab->zName));
|
||||
pItem->addrFillSub = addrTop;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, addrEof);
|
||||
sqlite3VdbeChangeP5(v, 1);
|
||||
sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
|
||||
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
|
||||
pItem->viaCoroutine = 1;
|
||||
sqlite3VdbeChangeP2(v, addrTop, dest.iSdst);
|
||||
sqlite3VdbeChangeP3(v, addrTop, dest.nSdst);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, addrEof);
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, pItem->regReturn);
|
||||
VdbeComment((v, "end %s", pItem->pTab->zName));
|
||||
pItem->regResult = dest.iSdst;
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn);
|
||||
sqlite3VdbeJumpHere(v, addrTop-1);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
}else{
|
||||
|
@ -4603,12 +4577,14 @@ int sqlite3Select(
|
|||
pItem->regReturn = ++pParse->nMem;
|
||||
topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
|
||||
pItem->addrFillSub = topAddr+1;
|
||||
VdbeNoopComment((v, "materialize %s", pItem->pTab->zName));
|
||||
if( pItem->isCorrelated==0 ){
|
||||
/* If the subquery is not correlated and if we are not inside of
|
||||
** a trigger, then we only need to compute the value of the subquery
|
||||
** once. */
|
||||
onceAddr = sqlite3CodeOnce(pParse);
|
||||
VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName));
|
||||
}else{
|
||||
VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
|
||||
}
|
||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
||||
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
||||
|
@ -4640,21 +4616,6 @@ int sqlite3Select(
|
|||
/* If there is are a sequence of queries, do the earlier ones first.
|
||||
*/
|
||||
if( p->pPrior ){
|
||||
if( p->pRightmost==0 ){
|
||||
Select *pLoop, *pRight = 0;
|
||||
int cnt = 0;
|
||||
int mxSelect;
|
||||
for(pLoop=p; pLoop; pLoop=pLoop->pPrior, cnt++){
|
||||
pLoop->pRightmost = p;
|
||||
pLoop->pNext = pRight;
|
||||
pRight = pLoop;
|
||||
}
|
||||
mxSelect = db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT];
|
||||
if( mxSelect && cnt>mxSelect ){
|
||||
sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
|
||||
goto select_end;
|
||||
}
|
||||
}
|
||||
rc = multiSelect(pParse, p, pDest);
|
||||
explainSetInteger(pParse->iSelectId, iRestoreSelectId);
|
||||
return rc;
|
||||
|
@ -5316,10 +5277,6 @@ void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){
|
|||
sqlite3ExplainPrintf(pVdbe, "(null-select)");
|
||||
return;
|
||||
}
|
||||
while( p->pPrior ){
|
||||
p->pPrior->pNext = p;
|
||||
p = p->pPrior;
|
||||
}
|
||||
sqlite3ExplainPush(pVdbe);
|
||||
while( p ){
|
||||
explainOneSelect(pVdbe, p);
|
||||
|
|
218
src/shell.c
218
src/shell.c
|
@ -1543,6 +1543,7 @@ static int run_schema_dump_query(
|
|||
static char zHelp[] =
|
||||
".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
|
||||
".bail ON|OFF Stop after hitting an error. Default OFF\n"
|
||||
".clone NEWDB Clone data into NEWDB from the existing database\n"
|
||||
".databases List names and files of attached databases\n"
|
||||
".dump ?TABLE? ... Dump the database in an SQL text format\n"
|
||||
" If TABLE specified, only dump tables matching\n"
|
||||
|
@ -1896,6 +1897,219 @@ static char *csv_read_one_field(CSVReader *p){
|
|||
return p->z;
|
||||
}
|
||||
|
||||
/*
|
||||
** Try to transfer data for table zTable. If an error is seen while
|
||||
** moving forward, try to go backwards. The backwards movement won't
|
||||
** work for WITHOUT ROWID tables.
|
||||
*/
|
||||
static void tryToCloneData(
|
||||
struct callback_data *p,
|
||||
sqlite3 *newDb,
|
||||
const char *zTable
|
||||
){
|
||||
sqlite3_stmt *pQuery = 0;
|
||||
sqlite3_stmt *pInsert = 0;
|
||||
char *zQuery = 0;
|
||||
char *zInsert = 0;
|
||||
int rc;
|
||||
int i, j, n;
|
||||
int nTable = (int)strlen(zTable);
|
||||
int k = 0;
|
||||
int cnt = 0;
|
||||
const int spinRate = 10000;
|
||||
|
||||
zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
|
||||
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Error %d: %s on [%s]\n",
|
||||
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
|
||||
zQuery);
|
||||
goto end_data_xfer;
|
||||
}
|
||||
n = sqlite3_column_count(pQuery);
|
||||
zInsert = sqlite3_malloc(200 + nTable + n*3);
|
||||
if( zInsert==0 ){
|
||||
fprintf(stderr, "out of memory\n");
|
||||
goto end_data_xfer;
|
||||
}
|
||||
sqlite3_snprintf(200+nTable,zInsert,
|
||||
"INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
|
||||
i = (int)strlen(zInsert);
|
||||
for(j=1; j<n; j++){
|
||||
memcpy(zInsert+i, ",?", 2);
|
||||
i += 2;
|
||||
}
|
||||
memcpy(zInsert+i, ");", 3);
|
||||
rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Error %d: %s on [%s]\n",
|
||||
sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb),
|
||||
zQuery);
|
||||
goto end_data_xfer;
|
||||
}
|
||||
for(k=0; k<2; k++){
|
||||
while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
|
||||
for(i=0; i<n; i++){
|
||||
switch( sqlite3_column_type(pQuery, i) ){
|
||||
case SQLITE_NULL: {
|
||||
sqlite3_bind_null(pInsert, i+1);
|
||||
break;
|
||||
}
|
||||
case SQLITE_INTEGER: {
|
||||
sqlite3_bind_int64(pInsert, i+1, sqlite3_column_int64(pQuery,i));
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT: {
|
||||
sqlite3_bind_double(pInsert, i+1, sqlite3_column_double(pQuery,i));
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
sqlite3_bind_text(pInsert, i+1,
|
||||
(const char*)sqlite3_column_text(pQuery,i),
|
||||
-1, SQLITE_STATIC);
|
||||
break;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
sqlite3_bind_blob(pInsert, i+1, sqlite3_column_blob(pQuery,i),
|
||||
sqlite3_column_bytes(pQuery,i),
|
||||
SQLITE_STATIC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} /* End for */
|
||||
rc = sqlite3_step(pInsert);
|
||||
if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
|
||||
fprintf(stderr, "Error %d: %s\n", sqlite3_extended_errcode(newDb),
|
||||
sqlite3_errmsg(newDb));
|
||||
}
|
||||
sqlite3_reset(pInsert);
|
||||
cnt++;
|
||||
if( (cnt%spinRate)==0 ){
|
||||
printf("%c\b", "|/-\\"[(cnt/spinRate)%4]);
|
||||
fflush(stdout);
|
||||
}
|
||||
} /* End while */
|
||||
if( rc==SQLITE_DONE ) break;
|
||||
sqlite3_finalize(pQuery);
|
||||
sqlite3_free(zQuery);
|
||||
zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
|
||||
zTable);
|
||||
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Warning: cannot step \"%s\" backwards", zTable);
|
||||
break;
|
||||
}
|
||||
} /* End for(k=0...) */
|
||||
|
||||
end_data_xfer:
|
||||
sqlite3_finalize(pQuery);
|
||||
sqlite3_finalize(pInsert);
|
||||
sqlite3_free(zQuery);
|
||||
sqlite3_free(zInsert);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Try to transfer all rows of the schema that match zWhere. For
|
||||
** each row, invoke xForEach() on the object defined by that row.
|
||||
** If an error is encountered while moving forward through the
|
||||
** sqlite_master table, try again moving backwards.
|
||||
*/
|
||||
static void tryToCloneSchema(
|
||||
struct callback_data *p,
|
||||
sqlite3 *newDb,
|
||||
const char *zWhere,
|
||||
void (*xForEach)(struct callback_data*,sqlite3*,const char*)
|
||||
){
|
||||
sqlite3_stmt *pQuery = 0;
|
||||
char *zQuery = 0;
|
||||
int rc;
|
||||
const unsigned char *zName;
|
||||
const unsigned char *zSql;
|
||||
char *zErrMsg = 0;
|
||||
|
||||
zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
|
||||
" WHERE %s", zWhere);
|
||||
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Error: (%d) %s on [%s]\n",
|
||||
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
|
||||
zQuery);
|
||||
goto end_schema_xfer;
|
||||
}
|
||||
while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
|
||||
zName = sqlite3_column_text(pQuery, 0);
|
||||
zSql = sqlite3_column_text(pQuery, 1);
|
||||
printf("%s... ", zName); fflush(stdout);
|
||||
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
|
||||
if( zErrMsg ){
|
||||
fprintf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
|
||||
sqlite3_free(zErrMsg);
|
||||
zErrMsg = 0;
|
||||
}
|
||||
if( xForEach ){
|
||||
xForEach(p, newDb, (const char*)zName);
|
||||
}
|
||||
printf("done\n");
|
||||
}
|
||||
if( rc!=SQLITE_DONE ){
|
||||
sqlite3_finalize(pQuery);
|
||||
sqlite3_free(zQuery);
|
||||
zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
|
||||
" WHERE %s ORDER BY rowid DESC", zWhere);
|
||||
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Error: (%d) %s on [%s]\n",
|
||||
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
|
||||
zQuery);
|
||||
goto end_schema_xfer;
|
||||
}
|
||||
while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
|
||||
zName = sqlite3_column_text(pQuery, 0);
|
||||
zSql = sqlite3_column_text(pQuery, 1);
|
||||
printf("%s... ", zName); fflush(stdout);
|
||||
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
|
||||
if( zErrMsg ){
|
||||
fprintf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
|
||||
sqlite3_free(zErrMsg);
|
||||
zErrMsg = 0;
|
||||
}
|
||||
if( xForEach ){
|
||||
xForEach(p, newDb, (const char*)zName);
|
||||
}
|
||||
printf("done\n");
|
||||
}
|
||||
}
|
||||
end_schema_xfer:
|
||||
sqlite3_finalize(pQuery);
|
||||
sqlite3_free(zQuery);
|
||||
}
|
||||
|
||||
/*
|
||||
** Open a new database file named "zNewDb". Try to recover as much information
|
||||
** as possible out of the main database (which might be corrupt) and write it
|
||||
** into zNewDb.
|
||||
*/
|
||||
static void tryToClone(struct callback_data *p, const char *zNewDb){
|
||||
int rc;
|
||||
sqlite3 *newDb = 0;
|
||||
if( access(zNewDb,0)==0 ){
|
||||
fprintf(stderr, "File \"%s\" already exists.\n", zNewDb);
|
||||
return;
|
||||
}
|
||||
rc = sqlite3_open(zNewDb, &newDb);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Cannot create output database: %s\n",
|
||||
sqlite3_errmsg(newDb));
|
||||
}else{
|
||||
sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
|
||||
tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
|
||||
tryToCloneSchema(p, newDb, "type!='table'", 0);
|
||||
sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
|
||||
}
|
||||
sqlite3_close(newDb);
|
||||
}
|
||||
|
||||
/*
|
||||
** If an input line begins with "." then invoke this routine to
|
||||
** process that line.
|
||||
|
@ -2003,6 +2217,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
|||
test_breakpoint();
|
||||
}else
|
||||
|
||||
if( c=='c' && strncmp(azArg[0], "clone", n)==0 && nArg>1 && nArg<3 ){
|
||||
tryToClone(p, azArg[1]);
|
||||
}else
|
||||
|
||||
if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){
|
||||
struct callback_data data;
|
||||
char *zErrMsg = 0;
|
||||
|
|
|
@ -33,6 +33,11 @@
|
|||
** in Red Hat 6.0, so the code won't work. Hence, for maximum binary
|
||||
** portability you should omit LFS.
|
||||
**
|
||||
** The previous paragraph was written in 2005. (This paragraph is written
|
||||
** on 2008-11-28.) These days, all Linux kernels support large files, so
|
||||
** you should probably leave LFS enabled. But some embedded platforms might
|
||||
** lack LFS in which case the SQLITE_DISABLE_LFS macro might still be useful.
|
||||
**
|
||||
** Similar is true for Mac OS X. LFS is only supported on Mac OS X 9 and later.
|
||||
*/
|
||||
#ifndef SQLITE_DISABLE_LFS
|
||||
|
@ -1091,8 +1096,7 @@ struct sqlite3 {
|
|||
** Return true if it OK to factor constant expressions into the initialization
|
||||
** code. The argument is a Parse object for the code generator.
|
||||
*/
|
||||
#define ConstFactorOk(P) \
|
||||
((P)->cookieGoto>0 && OptimizationEnabled((P)->db,SQLITE_FactorOutConst))
|
||||
#define ConstFactorOk(P) ((P)->okConstFactor)
|
||||
|
||||
/*
|
||||
** Possible values for the sqlite.magic field.
|
||||
|
@ -2023,6 +2027,7 @@ struct SrcList {
|
|||
Select *pSelect; /* A SELECT statement used in place of a table name */
|
||||
int addrFillSub; /* Address of subroutine to manifest a subquery */
|
||||
int regReturn; /* Register holding return address of addrFillSub */
|
||||
int regResult; /* Registers holding results of a co-routine */
|
||||
u8 jointype; /* Type of join between this able and the previous */
|
||||
unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */
|
||||
unsigned isCorrelated :1; /* True if sub-query is correlated */
|
||||
|
@ -2151,7 +2156,6 @@ struct Select {
|
|||
ExprList *pOrderBy; /* The ORDER BY clause */
|
||||
Select *pPrior; /* Prior select in a compound select statement */
|
||||
Select *pNext; /* Next select to the left in a compound */
|
||||
Select *pRightmost; /* Right-most select in a compound select statement */
|
||||
Expr *pLimit; /* LIMIT expression. NULL means not used. */
|
||||
Expr *pOffset; /* OFFSET expression. NULL means not used. */
|
||||
With *pWith; /* WITH clause attached to this select. Or NULL. */
|
||||
|
@ -2169,10 +2173,11 @@ struct Select {
|
|||
#define SF_HasTypeInfo 0x0020 /* FROM subqueries have Table metadata */
|
||||
#define SF_UseSorter 0x0040 /* Sort using a sorter */
|
||||
#define SF_Values 0x0080 /* Synthesized from VALUES clause */
|
||||
#define SF_Materialize 0x0100 /* Force materialization of views */
|
||||
#define SF_Materialize 0x0100 /* NOT USED */
|
||||
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
|
||||
#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
|
||||
#define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
|
||||
#define SF_Compound 0x1000 /* Part of a compound query */
|
||||
|
||||
|
||||
/*
|
||||
|
@ -2357,6 +2362,7 @@ struct Parse {
|
|||
u8 isMultiWrite; /* True if statement may modify/insert multiple rows */
|
||||
u8 mayAbort; /* True if statement may throw an ABORT exception */
|
||||
u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
|
||||
u8 okConstFactor; /* OK to factor out constants */
|
||||
int aTempReg[8]; /* Holding area for temporary registers */
|
||||
int nRangeReg; /* Size of the temporary register block */
|
||||
int iRangeReg; /* First register in temporary register block */
|
||||
|
@ -2366,30 +2372,29 @@ struct Parse {
|
|||
int nSet; /* Number of sets used so far */
|
||||
int nOnce; /* Number of OP_Once instructions so far */
|
||||
int nOpAlloc; /* Number of slots allocated for Vdbe.aOp[] */
|
||||
int nLabel; /* Number of labels used */
|
||||
int *aLabel; /* Space to hold the labels */
|
||||
int iFixedOp; /* Never back out opcodes iFixedOp-1 or earlier */
|
||||
int ckBase; /* Base register of data during check constraints */
|
||||
int iPartIdxTab; /* Table corresponding to a partial index */
|
||||
int iCacheLevel; /* ColCache valid when aColCache[].iLevel<=iCacheLevel */
|
||||
int iCacheCnt; /* Counter used to generate aColCache[].lru values */
|
||||
int nLabel; /* Number of labels used */
|
||||
int *aLabel; /* Space to hold the labels */
|
||||
struct yColCache {
|
||||
int iTable; /* Table cursor number */
|
||||
int iColumn; /* Table column number */
|
||||
i16 iColumn; /* Table column number */
|
||||
u8 tempReg; /* iReg is a temp register that needs to be freed */
|
||||
int iLevel; /* Nesting level */
|
||||
int iReg; /* Reg with value of this column. 0 means none. */
|
||||
int lru; /* Least recently used entry has the smallest value */
|
||||
} aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */
|
||||
ExprList *pConstExpr;/* Constant expressions */
|
||||
Token constraintName;/* Name of the constraint currently being parsed */
|
||||
yDbMask writeMask; /* Start a write transaction on these databases */
|
||||
yDbMask cookieMask; /* Bitmask of schema verified databases */
|
||||
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
|
||||
int cookieValue[SQLITE_MAX_ATTACHED+2]; /* Values of cookies to verify */
|
||||
int regRowid; /* Register holding rowid of CREATE TABLE entry */
|
||||
int regRoot; /* Register holding root page number for new objects */
|
||||
int nMaxArg; /* Max args passed to user function by sub-program */
|
||||
Token constraintName;/* Name of the constraint currently being parsed */
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
int nTableLock; /* Number of locks in aTableLock */
|
||||
TableLock *aTableLock; /* Required table locks for shared-cache mode */
|
||||
|
@ -2408,12 +2413,17 @@ struct Parse {
|
|||
u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
|
||||
u8 disableTriggers; /* True to disable triggers */
|
||||
|
||||
/* Above is constant between recursions. Below is reset before and after
|
||||
** each recursion */
|
||||
/************************************************************************
|
||||
** Above is constant between recursions. Below is reset before and after
|
||||
** each recursion. The boundary between these two regions is determined
|
||||
** using offsetof(Parse,nVar) so the nVar field must be the first field
|
||||
** in the recursive region.
|
||||
************************************************************************/
|
||||
|
||||
int nVar; /* Number of '?' variables seen in the SQL so far */
|
||||
int nzVar; /* Number of available slots in azVar[] */
|
||||
u8 iPkSortOrder; /* ASC or DESC for INTEGER PRIMARY KEY */
|
||||
u8 bFreeWith; /* True if pWith should be freed with parser */
|
||||
u8 explain; /* True if the EXPLAIN flag is found on the query */
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
u8 declareVtab; /* True if inside sqlite3_declare_vtab() */
|
||||
|
@ -2440,7 +2450,6 @@ struct Parse {
|
|||
Table *pZombieTab; /* List of Table objects to delete after code gen */
|
||||
TriggerPrg *pTriggerPrg; /* Linked list of coded triggers */
|
||||
With *pWith; /* Current WITH clause, or NULL */
|
||||
u8 bFreeWith; /* True if pWith should be freed with parser */
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -1069,7 +1069,7 @@ static int DbTransPostCmd(
|
|||
** this method's logic. Not clear how this would be best handled.
|
||||
*/
|
||||
if( rc!=TCL_ERROR ){
|
||||
Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0);
|
||||
Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0);
|
||||
rc = TCL_ERROR;
|
||||
}
|
||||
sqlite3_exec(pDb->db, "ROLLBACK", 0, 0, 0);
|
||||
|
@ -1760,7 +1760,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
*/
|
||||
case DB_AUTHORIZER: {
|
||||
#ifdef SQLITE_OMIT_AUTHORIZATION
|
||||
Tcl_AppendResult(interp, "authorization not available in this build", 0);
|
||||
Tcl_AppendResult(interp, "authorization not available in this build",
|
||||
(char*)0);
|
||||
return TCL_ERROR;
|
||||
#else
|
||||
if( objc>3 ){
|
||||
|
@ -1768,7 +1769,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
return TCL_ERROR;
|
||||
}else if( objc==2 ){
|
||||
if( pDb->zAuth ){
|
||||
Tcl_AppendResult(interp, pDb->zAuth, 0);
|
||||
Tcl_AppendResult(interp, pDb->zAuth, (char*)0);
|
||||
}
|
||||
}else{
|
||||
char *zAuth;
|
||||
|
@ -1854,7 +1855,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
return TCL_ERROR;
|
||||
}else if( objc==2 ){
|
||||
if( pDb->zBusy ){
|
||||
Tcl_AppendResult(interp, pDb->zBusy, 0);
|
||||
Tcl_AppendResult(interp, pDb->zBusy, (char*)0);
|
||||
}
|
||||
}else{
|
||||
char *zBusy;
|
||||
|
@ -1908,7 +1909,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
}else{
|
||||
if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){
|
||||
Tcl_AppendResult( interp, "cannot convert \"",
|
||||
Tcl_GetStringFromObj(objv[3],0), "\" to integer", 0);
|
||||
Tcl_GetStringFromObj(objv[3],0), "\" to integer", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}else{
|
||||
if( n<0 ){
|
||||
|
@ -1922,7 +1923,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
}
|
||||
}else{
|
||||
Tcl_AppendResult( interp, "bad option \"",
|
||||
Tcl_GetStringFromObj(objv[2],0), "\": must be flush or size", 0);
|
||||
Tcl_GetStringFromObj(objv[2],0), "\": must be flush or size",
|
||||
(char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
break;
|
||||
|
@ -2019,7 +2021,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
return TCL_ERROR;
|
||||
}else if( objc==2 ){
|
||||
if( pDb->zCommit ){
|
||||
Tcl_AppendResult(interp, pDb->zCommit, 0);
|
||||
Tcl_AppendResult(interp, pDb->zCommit, (char*)0);
|
||||
}
|
||||
}else{
|
||||
const char *zCommit;
|
||||
|
@ -2124,7 +2126,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
nSep = strlen30(zSep);
|
||||
nNull = strlen30(zNull);
|
||||
if( nSep==0 ){
|
||||
Tcl_AppendResult(interp,"Error: non-null separator required for copy",0);
|
||||
Tcl_AppendResult(interp,"Error: non-null separator required for copy",
|
||||
(char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if(strcmp(zConflict, "rollback") != 0 &&
|
||||
|
@ -2134,19 +2137,19 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
strcmp(zConflict, "replace" ) != 0 ) {
|
||||
Tcl_AppendResult(interp, "Error: \"", zConflict,
|
||||
"\", conflict-algorithm must be one of: rollback, "
|
||||
"abort, fail, ignore, or replace", 0);
|
||||
"abort, fail, ignore, or replace", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable);
|
||||
if( zSql==0 ){
|
||||
Tcl_AppendResult(interp, "Error: no such table: ", zTable, 0);
|
||||
Tcl_AppendResult(interp, "Error: no such table: ", zTable, (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
nByte = strlen30(zSql);
|
||||
rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
|
||||
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), (char*)0);
|
||||
nCol = 0;
|
||||
}else{
|
||||
nCol = sqlite3_column_count(pStmt);
|
||||
|
@ -2157,7 +2160,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
}
|
||||
zSql = malloc( nByte + 50 + nCol*2 );
|
||||
if( zSql==0 ) {
|
||||
Tcl_AppendResult(interp, "Error: can't malloc()", 0);
|
||||
Tcl_AppendResult(interp, "Error: can't malloc()", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
sqlite3_snprintf(nByte+50, zSql, "INSERT OR %q INTO '%q' VALUES(?",
|
||||
|
@ -2172,7 +2175,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0);
|
||||
free(zSql);
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
|
||||
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), (char*)0);
|
||||
sqlite3_finalize(pStmt);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
@ -2184,7 +2187,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
}
|
||||
azCol = malloc( sizeof(azCol[0])*(nCol+1) );
|
||||
if( azCol==0 ) {
|
||||
Tcl_AppendResult(interp, "Error: can't malloc()", 0);
|
||||
Tcl_AppendResult(interp, "Error: can't malloc()", (char*)0);
|
||||
fclose(in);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
@ -2212,7 +2215,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
sqlite3_snprintf(nErr, zErr,
|
||||
"Error: %s line %d: expected %d columns of data but found %d",
|
||||
zFile, lineno, nCol, i+1);
|
||||
Tcl_AppendResult(interp, zErr, 0);
|
||||
Tcl_AppendResult(interp, zErr, (char*)0);
|
||||
free(zErr);
|
||||
}
|
||||
zCommit = "ROLLBACK";
|
||||
|
@ -2232,7 +2235,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
rc = sqlite3_reset(pStmt);
|
||||
free(zLine);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), 0);
|
||||
Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), (char*)0);
|
||||
zCommit = "ROLLBACK";
|
||||
break;
|
||||
}
|
||||
|
@ -2250,7 +2253,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
}else{
|
||||
/* failure, append lineno where failed */
|
||||
sqlite3_snprintf(sizeof(zLineNum), zLineNum,"%d",lineno);
|
||||
Tcl_AppendResult(interp,", failed while processing line: ",zLineNum,0);
|
||||
Tcl_AppendResult(interp,", failed while processing line: ",zLineNum,
|
||||
(char*)0);
|
||||
rc = TCL_ERROR;
|
||||
}
|
||||
break;
|
||||
|
@ -2276,7 +2280,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
break;
|
||||
#else
|
||||
Tcl_AppendResult(interp, "extension loading is turned off at compile-time",
|
||||
0);
|
||||
(char*)0);
|
||||
return TCL_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
@ -2434,7 +2438,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
*/
|
||||
case DB_INCRBLOB: {
|
||||
#ifdef SQLITE_OMIT_INCRBLOB
|
||||
Tcl_AppendResult(interp, "incrblob not available in this build", 0);
|
||||
Tcl_AppendResult(interp, "incrblob not available in this build", (char*)0);
|
||||
return TCL_ERROR;
|
||||
#else
|
||||
int isReadonly = 0;
|
||||
|
@ -2541,7 +2545,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
case DB_PROGRESS: {
|
||||
if( objc==2 ){
|
||||
if( pDb->zProgress ){
|
||||
Tcl_AppendResult(interp, pDb->zProgress, 0);
|
||||
Tcl_AppendResult(interp, pDb->zProgress, (char*)0);
|
||||
}
|
||||
}else if( objc==4 ){
|
||||
char *zProgress;
|
||||
|
@ -2587,7 +2591,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
return TCL_ERROR;
|
||||
}else if( objc==2 ){
|
||||
if( pDb->zProfile ){
|
||||
Tcl_AppendResult(interp, pDb->zProfile, 0);
|
||||
Tcl_AppendResult(interp, pDb->zProfile, (char*)0);
|
||||
}
|
||||
}else{
|
||||
char *zProfile;
|
||||
|
@ -2632,7 +2636,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey);
|
||||
rc = sqlite3_rekey(pDb->db, pKey, nKey);
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, sqlite3_errstr(rc), 0);
|
||||
Tcl_AppendResult(interp, sqlite3_errstr(rc), (char*)0);
|
||||
rc = TCL_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
@ -2773,7 +2777,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
return TCL_ERROR;
|
||||
}else if( objc==2 ){
|
||||
if( pDb->zTrace ){
|
||||
Tcl_AppendResult(interp, pDb->zTrace, 0);
|
||||
Tcl_AppendResult(interp, pDb->zTrace, (char*)0);
|
||||
}
|
||||
}else{
|
||||
char *zTrace;
|
||||
|
@ -2844,7 +2848,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
rc = sqlite3_exec(pDb->db, zBegin, 0, 0, 0);
|
||||
pDb->disableAuth--;
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0);
|
||||
Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pDb->nTransaction++;
|
||||
|
@ -2868,7 +2872,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
*/
|
||||
case DB_UNLOCK_NOTIFY: {
|
||||
#ifndef SQLITE_ENABLE_UNLOCK_NOTIFY
|
||||
Tcl_AppendResult(interp, "unlock_notify not available in this build", 0);
|
||||
Tcl_AppendResult(interp, "unlock_notify not available in this build",
|
||||
(char*)0);
|
||||
rc = TCL_ERROR;
|
||||
#else
|
||||
if( objc!=2 && objc!=3 ){
|
||||
|
@ -2891,7 +2896,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
}
|
||||
|
||||
if( sqlite3_unlock_notify(pDb->db, xNotify, pNotifyArg) ){
|
||||
Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0);
|
||||
Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0);
|
||||
rc = TCL_ERROR;
|
||||
}
|
||||
}
|
||||
|
@ -3081,14 +3086,14 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
if( objc==2 ){
|
||||
zArg = Tcl_GetStringFromObj(objv[1], 0);
|
||||
if( strcmp(zArg,"-version")==0 ){
|
||||
Tcl_AppendResult(interp,sqlite3_libversion(),0);
|
||||
Tcl_AppendResult(interp,sqlite3_libversion(), (char*)0);
|
||||
return TCL_OK;
|
||||
}
|
||||
if( strcmp(zArg,"-has-codec")==0 ){
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
Tcl_AppendResult(interp,"1",0);
|
||||
Tcl_AppendResult(interp,"1",(char*)0);
|
||||
#else
|
||||
Tcl_AppendResult(interp,"0",0);
|
||||
Tcl_AppendResult(interp,"0",(char*)0);
|
||||
#endif
|
||||
return TCL_OK;
|
||||
}
|
||||
|
@ -3570,7 +3575,7 @@ static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){
|
|||
|
||||
if( argc!=2 ){
|
||||
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
||||
" TEXT\"", 0);
|
||||
" TEXT\"", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
MD5Init(&ctx);
|
||||
|
@ -3595,13 +3600,13 @@ static int md5file_cmd(void*cd, Tcl_Interp*interp, int argc, const char **argv){
|
|||
|
||||
if( argc!=2 ){
|
||||
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
||||
" FILENAME\"", 0);
|
||||
" FILENAME\"", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
in = fopen(argv[1],"rb");
|
||||
if( in==0 ){
|
||||
Tcl_AppendResult(interp,"unable to open file \"", argv[1],
|
||||
"\" for reading", 0);
|
||||
"\" for reading", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
MD5Init(&ctx);
|
||||
|
|
|
@ -76,7 +76,7 @@ static int test_value_overhead(
|
|||
|
||||
val.flags = MEM_Str|MEM_Term|MEM_Static;
|
||||
val.z = "hello world";
|
||||
val.type = SQLITE_TEXT;
|
||||
val.memType = MEM_Str;
|
||||
val.enc = SQLITE_UTF8;
|
||||
|
||||
for(i=0; i<repeat_count; i++){
|
||||
|
|
|
@ -726,15 +726,7 @@ static int codeTriggerProgram(
|
|||
** INSERT OR IGNORE INTO t1 ... ; -- insert into t2 uses IGNORE policy
|
||||
*/
|
||||
pParse->eOrconf = (orconf==OE_Default)?pStep->orconf:(u8)orconf;
|
||||
|
||||
/* Clear the cookieGoto flag. When coding triggers, the cookieGoto
|
||||
** variable is used as a flag to indicate to sqlite3ExprCodeConstants()
|
||||
** that it is not safe to refactor constants (this happens after the
|
||||
** start of the first loop in the SQL statement is coded - at that
|
||||
** point code may be conditionally executed, so it is no longer safe to
|
||||
** initialize constant register values). */
|
||||
assert( pParse->cookieGoto==0 || pParse->cookieGoto==-1 );
|
||||
pParse->cookieGoto = 0;
|
||||
assert( pParse->okConstFactor==0 );
|
||||
|
||||
switch( pStep->op ){
|
||||
case TK_UPDATE: {
|
||||
|
|
18
src/util.c
18
src/util.c
|
@ -1123,13 +1123,12 @@ int sqlite3AddInt64(i64 *pA, i64 iB){
|
|||
testcase( iA>0 && LARGEST_INT64 - iA == iB );
|
||||
testcase( iA>0 && LARGEST_INT64 - iA == iB - 1 );
|
||||
if( iA>0 && LARGEST_INT64 - iA < iB ) return 1;
|
||||
*pA += iB;
|
||||
}else{
|
||||
testcase( iA<0 && -(iA + LARGEST_INT64) == iB + 1 );
|
||||
testcase( iA<0 && -(iA + LARGEST_INT64) == iB + 2 );
|
||||
if( iA<0 && -(iA + LARGEST_INT64) > iB + 1 ) return 1;
|
||||
*pA += iB;
|
||||
}
|
||||
*pA += iB;
|
||||
return 0;
|
||||
}
|
||||
int sqlite3SubInt64(i64 *pA, i64 iB){
|
||||
|
@ -1153,9 +1152,18 @@ int sqlite3MulInt64(i64 *pA, i64 iB){
|
|||
iA0 = iA % TWOPOWER32;
|
||||
iB1 = iB/TWOPOWER32;
|
||||
iB0 = iB % TWOPOWER32;
|
||||
if( iA1*iB1 != 0 ) return 1;
|
||||
assert( iA1*iB0==0 || iA0*iB1==0 );
|
||||
r = iA1*iB0 + iA0*iB1;
|
||||
if( iA1==0 ){
|
||||
if( iB1==0 ){
|
||||
*pA *= iB;
|
||||
return 0;
|
||||
}
|
||||
r = iA0*iB1;
|
||||
}else if( iB1==0 ){
|
||||
r = iA1*iB0;
|
||||
}else{
|
||||
/* If both iA1 and iB1 are non-zero, overflow will result */
|
||||
return 1;
|
||||
}
|
||||
testcase( r==(-TWOPOWER31)-1 );
|
||||
testcase( r==(-TWOPOWER31) );
|
||||
testcase( r==TWOPOWER31 );
|
||||
|
|
391
src/vdbe.c
391
src/vdbe.c
|
@ -9,33 +9,8 @@
|
|||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** The code in this file implements execution method of the
|
||||
** Virtual Database Engine (VDBE). A separate file ("vdbeaux.c")
|
||||
** handles housekeeping details such as creating and deleting
|
||||
** VDBE instances. This file is solely interested in executing
|
||||
** the VDBE program.
|
||||
**
|
||||
** In the external interface, an "sqlite3_stmt*" is an opaque pointer
|
||||
** to a VDBE.
|
||||
**
|
||||
** The SQL parser generates a program which is then executed by
|
||||
** the VDBE to do the work of the SQL statement. VDBE programs are
|
||||
** similar in form to assembly language. The program consists of
|
||||
** a linear sequence of operations. Each operation has an opcode
|
||||
** and 5 operands. Operands P1, P2, and P3 are integers. Operand P4
|
||||
** is a null-terminated string. Operand P5 is an unsigned character.
|
||||
** Few opcodes use all 5 operands.
|
||||
**
|
||||
** Computation results are stored on a set of registers numbered beginning
|
||||
** with 1 and going up to Vdbe.nMem. Each register can store
|
||||
** either an integer, a null-terminated string, a floating point
|
||||
** number, or the SQL "NULL" value. An implicit conversion from one
|
||||
** type to the other occurs as necessary.
|
||||
**
|
||||
** Most of the code in this file is taken up by the sqlite3VdbeExec()
|
||||
** function which does the work of interpreting a VDBE program.
|
||||
** But other routines are also provided to help in building up
|
||||
** a program instruction by instruction.
|
||||
** The code in this file implements the function that runs the
|
||||
** bytecode of a prepared statement.
|
||||
**
|
||||
** Various scripts scan this source file in order to generate HTML
|
||||
** documentation, headers files, or other derived files. The formatting
|
||||
|
@ -49,7 +24,11 @@
|
|||
/*
|
||||
** Invoke this macro on memory cells just prior to changing the
|
||||
** value of the cell. This macro verifies that shallow copies are
|
||||
** not misused.
|
||||
** not misused. A shallow copy of a string or blob just copies a
|
||||
** pointer to the string or blob, not the content. If the original
|
||||
** is changed while the copy is still in use, the string or blob might
|
||||
** be changed out from under the copy. This macro verifies that nothing
|
||||
** like that every happens.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
# define memAboutToChange(P,M) sqlite3VdbeMemAboutToChange(P,M)
|
||||
|
@ -118,7 +97,7 @@ static void updateMaxBlobsize(Mem *p){
|
|||
#endif
|
||||
|
||||
/*
|
||||
** The next global variable is incremented each type the OP_Found opcode
|
||||
** The next global variable is incremented each time the OP_Found opcode
|
||||
** is executed. This is used to test whether or not the foreign key
|
||||
** operation implemented using OP_FkIsZero is working. This variable
|
||||
** has no function other than to help verify the correct operation of the
|
||||
|
@ -162,31 +141,7 @@ int sqlite3_found_count = 0;
|
|||
&& sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;}
|
||||
|
||||
/* Return true if the cursor was opened using the OP_OpenSorter opcode. */
|
||||
# define isSorter(x) ((x)->pSorter!=0)
|
||||
|
||||
/*
|
||||
** Argument pMem points at a register that will be passed to a
|
||||
** user-defined function or returned to the user as the result of a query.
|
||||
** This routine sets the pMem->type variable used by the sqlite3_value_*()
|
||||
** routines.
|
||||
*/
|
||||
void sqlite3VdbeMemStoreType(Mem *pMem){
|
||||
int flags = pMem->flags;
|
||||
if( flags & MEM_Null ){
|
||||
pMem->type = SQLITE_NULL;
|
||||
}
|
||||
else if( flags & MEM_Int ){
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
}
|
||||
else if( flags & MEM_Real ){
|
||||
pMem->type = SQLITE_FLOAT;
|
||||
}
|
||||
else if( flags & MEM_Str ){
|
||||
pMem->type = SQLITE_TEXT;
|
||||
}else{
|
||||
pMem->type = SQLITE_BLOB;
|
||||
}
|
||||
}
|
||||
#define isSorter(x) ((x)->pSorter!=0)
|
||||
|
||||
/*
|
||||
** Allocate VdbeCursor number iCur. Return a pointer to it. Return NULL
|
||||
|
@ -316,12 +271,14 @@ static void applyAffinity(
|
|||
** loss of information and return the revised type of the argument.
|
||||
*/
|
||||
int sqlite3_value_numeric_type(sqlite3_value *pVal){
|
||||
Mem *pMem = (Mem*)pVal;
|
||||
if( pMem->type==SQLITE_TEXT ){
|
||||
int eType = sqlite3_value_type(pVal);
|
||||
if( eType==SQLITE_TEXT ){
|
||||
Mem *pMem = (Mem*)pVal;
|
||||
applyNumericAffinity(pMem);
|
||||
sqlite3VdbeMemStoreType(pMem);
|
||||
eType = sqlite3_value_type(pVal);
|
||||
}
|
||||
return pMem->type;
|
||||
return eType;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -424,7 +381,7 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
|
|||
** Print the value of a register for tracing purposes:
|
||||
*/
|
||||
static void memTracePrint(Mem *p){
|
||||
if( p->flags & MEM_Invalid ){
|
||||
if( p->flags & MEM_Undefined ){
|
||||
printf(" undefined");
|
||||
}else if( p->flags & MEM_Null ){
|
||||
printf(" NULL");
|
||||
|
@ -468,20 +425,6 @@ static void registerTrace(int iReg, Mem *p){
|
|||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The CHECK_FOR_INTERRUPT macro defined here looks to see if the
|
||||
** sqlite3_interrupt() routine has been called. If it has been, then
|
||||
** processing of the VDBE program is interrupted.
|
||||
**
|
||||
** This macro added to every instruction that does a jump in order to
|
||||
** implement a loop. This test used to be on every single instruction,
|
||||
** but that meant we more testing than we needed. By only testing the
|
||||
** flag on jump instructions, we get a (small) speed improvement.
|
||||
*/
|
||||
#define CHECK_FOR_INTERRUPT \
|
||||
if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
/*
|
||||
** This function is only called from within an assert() expression. It
|
||||
|
@ -504,35 +447,8 @@ static int checkSavepointCount(sqlite3 *db){
|
|||
|
||||
|
||||
/*
|
||||
** Execute as much of a VDBE program as we can then return.
|
||||
**
|
||||
** sqlite3VdbeMakeReady() must be called before this routine in order to
|
||||
** close the program with a final OP_Halt and to set up the callbacks
|
||||
** and the error message pointer.
|
||||
**
|
||||
** Whenever a row or result data is available, this routine will either
|
||||
** invoke the result callback (if there is one) or return with
|
||||
** SQLITE_ROW.
|
||||
**
|
||||
** If an attempt is made to open a locked database, then this routine
|
||||
** will either invoke the busy callback (if there is one) or it will
|
||||
** return SQLITE_BUSY.
|
||||
**
|
||||
** If an error occurs, an error message is written to memory obtained
|
||||
** from sqlite3_malloc() and p->zErrMsg is made to point to that memory.
|
||||
** The error code is stored in p->rc and this routine returns SQLITE_ERROR.
|
||||
**
|
||||
** If the callback ever returns non-zero, then the program exits
|
||||
** immediately. There will be no error message but the p->rc field is
|
||||
** set to SQLITE_ABORT and this routine will return SQLITE_ERROR.
|
||||
**
|
||||
** A memory allocation error causes p->rc to be set to SQLITE_NOMEM and this
|
||||
** routine to return SQLITE_ERROR.
|
||||
**
|
||||
** Other fatal errors return SQLITE_ERROR.
|
||||
**
|
||||
** After this routine has finished, sqlite3VdbeFinalize() should be
|
||||
** used to clean up the mess that was left behind.
|
||||
** Execute as much of a VDBE program as we can.
|
||||
** This is the core of sqlite3_step().
|
||||
*/
|
||||
int sqlite3VdbeExec(
|
||||
Vdbe *p /* The VDBE */
|
||||
|
@ -576,7 +492,7 @@ int sqlite3VdbeExec(
|
|||
assert( p->explain==0 );
|
||||
p->pResultSet = 0;
|
||||
db->busyHandler.nBusy = 0;
|
||||
CHECK_FOR_INTERRUPT;
|
||||
if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
|
||||
sqlite3VdbeIOTraceSql(p);
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
if( db->xProgress ){
|
||||
|
@ -752,7 +668,7 @@ case OP_Goto: { /* jump */
|
|||
** checks on every opcode. This helps sqlite3_step() to run about 1.5%
|
||||
** faster according to "valgrind --tool=cachegrind" */
|
||||
check_for_interrupt:
|
||||
CHECK_FOR_INTERRUPT;
|
||||
if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
/* Call the progress callback if it is configured and the required number
|
||||
** of VDBE ops have been executed (either since this invocation of
|
||||
|
@ -792,20 +708,66 @@ case OP_Gosub: { /* jump */
|
|||
|
||||
/* Opcode: Return P1 * * * *
|
||||
**
|
||||
** Jump to the next instruction after the address in register P1.
|
||||
** Jump to the next instruction after the address in register P1. After
|
||||
** the jump, register P1 becomes undefined.
|
||||
*/
|
||||
case OP_Return: { /* in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( pIn1->flags & MEM_Int );
|
||||
assert( pIn1->flags==MEM_Int );
|
||||
pc = (int)pIn1->u.i;
|
||||
pIn1->flags = MEM_Undefined;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Yield P1 * * * *
|
||||
/* Opcode: InitCoroutine P1 P2 P3 * *
|
||||
**
|
||||
** Set up register P1 so that it will OP_Yield to the co-routine
|
||||
** located at address P3.
|
||||
**
|
||||
** If P2!=0 then the co-routine implementation immediately follows
|
||||
** this opcode. So jump over the co-routine implementation to
|
||||
** address P2.
|
||||
*/
|
||||
case OP_InitCoroutine: { /* jump */
|
||||
assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
|
||||
assert( pOp->p2>=0 && pOp->p2<p->nOp );
|
||||
assert( pOp->p3>=0 && pOp->p3<p->nOp );
|
||||
pOut = &aMem[pOp->p1];
|
||||
assert( !VdbeMemDynamic(pOut) );
|
||||
pOut->u.i = pOp->p3 - 1;
|
||||
pOut->flags = MEM_Int;
|
||||
if( pOp->p2 ) pc = pOp->p2 - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: EndCoroutine P1 * * * *
|
||||
**
|
||||
** The instruction at the address in register P1 is an OP_Yield.
|
||||
** Jump to the P2 parameter of that OP_Yield.
|
||||
** After the jump, register P1 becomes undefined.
|
||||
*/
|
||||
case OP_EndCoroutine: { /* in1 */
|
||||
VdbeOp *pCaller;
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( pIn1->flags==MEM_Int );
|
||||
assert( pIn1->u.i>=0 && pIn1->u.i<p->nOp );
|
||||
pCaller = &aOp[pIn1->u.i];
|
||||
assert( pCaller->opcode==OP_Yield );
|
||||
assert( pCaller->p2>=0 && pCaller->p2<p->nOp );
|
||||
pc = pCaller->p2 - 1;
|
||||
pIn1->flags = MEM_Undefined;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Yield P1 P2 * * *
|
||||
**
|
||||
** Swap the program counter with the value in register P1.
|
||||
**
|
||||
** If the co-routine ends with OP_Yield or OP_Return then continue
|
||||
** to the next instruction. But if the co-routine ends with
|
||||
** OP_EndCoroutine, jump immediately to P2.
|
||||
*/
|
||||
case OP_Yield: { /* in1 */
|
||||
case OP_Yield: { /* in1, jump */
|
||||
int pcDest;
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( (pIn1->flags & MEM_Dyn)==0 );
|
||||
|
@ -818,7 +780,7 @@ case OP_Yield: { /* in1 */
|
|||
}
|
||||
|
||||
/* Opcode: HaltIfNull P1 P2 P3 P4 P5
|
||||
** Synopsis: if r[P3] null then halt
|
||||
** Synopsis: if r[P3]=null halt
|
||||
**
|
||||
** Check the value in register P3. If it is NULL then Halt using
|
||||
** parameter P1, P2, and P4 as if this were a Halt instruction. If the
|
||||
|
@ -966,7 +928,9 @@ case OP_Real: { /* same as TK_FLOAT, out2-prerelease */
|
|||
** Synopsis: r[P2]='P4'
|
||||
**
|
||||
** P4 points to a nul terminated UTF-8 string. This opcode is transformed
|
||||
** into an OP_String before it is executed for the first time.
|
||||
** into an OP_String before it is executed for the first time. During
|
||||
** this transformation, the length of string P4 is computed and stored
|
||||
** as the P1 parameter.
|
||||
*/
|
||||
case OP_String8: { /* same as TK_STRING, out2-prerelease */
|
||||
assert( pOp->p4.z!=0 );
|
||||
|
@ -1041,7 +1005,7 @@ case OP_Null: { /* out2-prerelease */
|
|||
}
|
||||
|
||||
|
||||
/* Opcode: Blob P1 P2 * P4
|
||||
/* Opcode: Blob P1 P2 * P4 *
|
||||
** Synopsis: r[P2]=P4 (len=P1)
|
||||
**
|
||||
** P4 points to a blob of data P1 bytes long. Store this
|
||||
|
@ -1060,7 +1024,7 @@ case OP_Blob: { /* out2-prerelease */
|
|||
**
|
||||
** Transfer the values of bound parameter P1 into register P2
|
||||
**
|
||||
** If the parameter is named, then its name appears in P4 and P3==1.
|
||||
** If the parameter is named, then its name appears in P4.
|
||||
** The P4 value is used by sqlite3_bind_parameter_name().
|
||||
*/
|
||||
case OP_Variable: { /* out2-prerelease */
|
||||
|
@ -1179,8 +1143,8 @@ case OP_SCopy: { /* out2 */
|
|||
** The registers P1 through P1+P2-1 contain a single row of
|
||||
** results. This opcode causes the sqlite3_step() call to terminate
|
||||
** with an SQLITE_ROW return code and it sets up the sqlite3_stmt
|
||||
** structure to provide access to the top P1 values as the result
|
||||
** row.
|
||||
** structure to provide access to the r[P1]..r[P1+P2-1] values as
|
||||
** the result row.
|
||||
*/
|
||||
case OP_ResultRow: {
|
||||
Mem *pMem;
|
||||
|
@ -1708,7 +1672,7 @@ case OP_RealAffinity: { /* in1 */
|
|||
**
|
||||
** Force the value in register P1 to be text.
|
||||
** If the value is numeric, convert it to a string using the
|
||||
** equivalent of printf(). Blob values are unchanged and
|
||||
** equivalent of sprintf(). Blob values are unchanged and
|
||||
** are afterwards simply interpreted as text.
|
||||
**
|
||||
** A NULL value is not changed by this routine. It remains NULL.
|
||||
|
@ -2163,7 +2127,9 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
|
|||
/* Opcode: Once P1 P2 * * *
|
||||
**
|
||||
** Check if OP_Once flag P1 is set. If so, jump to instruction P2. Otherwise,
|
||||
** set the flag and fall through to the next instruction.
|
||||
** set the flag and fall through to the next instruction. In other words,
|
||||
** this opcode causes all following up codes up through P2 (but not including
|
||||
** P2) to run just once and skipped on subsequent times through the loop.
|
||||
*/
|
||||
case OP_Once: { /* jump */
|
||||
assert( pOp->p1<p->nOnceFlag );
|
||||
|
@ -2303,11 +2269,6 @@ case OP_Column: {
|
|||
if( pCrsr==0 ){
|
||||
assert( pC->pseudoTableReg>0 );
|
||||
pReg = &aMem[pC->pseudoTableReg];
|
||||
if( pC->multiPseudo ){
|
||||
sqlite3VdbeMemShallowCopy(pDest, pReg+p2, MEM_Ephem);
|
||||
Deephemeralize(pDest);
|
||||
goto op_column_out;
|
||||
}
|
||||
assert( pReg->flags & MEM_Blob );
|
||||
assert( memIsValid(pReg) );
|
||||
pC->payloadSize = pC->szRow = avail = pReg->n;
|
||||
|
@ -2956,7 +2917,7 @@ case OP_AutoCommit: {
|
|||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Transaction P1 P2 * * *
|
||||
/* Opcode: Transaction P1 P2 P3 P4 P5
|
||||
**
|
||||
** Begin a transaction. The transaction ends when a Commit or Rollback
|
||||
** opcode is encountered. Depending on the ON CONFLICT setting, the
|
||||
|
@ -2986,9 +2947,17 @@ case OP_AutoCommit: {
|
|||
** will automatically commit when the VDBE halts.
|
||||
**
|
||||
** If P2 is zero, then a read-lock is obtained on the database file.
|
||||
**
|
||||
** If P5!=0 then this opcode also checks the schema cookie against P3
|
||||
** and the schema generation counter against P4.
|
||||
** The cookie changes its value whenever the database schema changes.
|
||||
** This operation is used to detect when that the cookie has changed
|
||||
** and that the current process needs to reread the schema.
|
||||
*/
|
||||
case OP_Transaction: {
|
||||
Btree *pBt;
|
||||
int iMeta;
|
||||
int iGen;
|
||||
|
||||
assert( p->bIsReader );
|
||||
assert( p->readOnly==0 || pOp->p2==0 );
|
||||
|
@ -3032,6 +3001,35 @@ case OP_Transaction: {
|
|||
p->nStmtDefCons = db->nDeferredCons;
|
||||
p->nStmtDefImmCons = db->nDeferredImmCons;
|
||||
}
|
||||
|
||||
/* Gather the schema version number for checking */
|
||||
sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta);
|
||||
iGen = db->aDb[pOp->p1].pSchema->iGeneration;
|
||||
}else{
|
||||
iGen = iMeta = 0;
|
||||
}
|
||||
assert( pOp->p5==0 || pOp->p4type==P4_INT32 );
|
||||
if( pOp->p5 && (iMeta!=pOp->p3 || iGen!=pOp->p4.i) ){
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
|
||||
/* If the schema-cookie from the database file matches the cookie
|
||||
** stored with the in-memory representation of the schema, do
|
||||
** not reload the schema from the database file.
|
||||
**
|
||||
** If virtual-tables are in use, this is not just an optimization.
|
||||
** Often, v-tables store their data in other SQLite tables, which
|
||||
** are queried from within xNext() and other v-table methods using
|
||||
** prepared queries. If such a query is out-of-date, we do not want to
|
||||
** discard the database schema, as the user code implementing the
|
||||
** v-table would have to be ready for the sqlite3_vtab structure itself
|
||||
** to be invalidated whenever sqlite3_step() is called from within
|
||||
** a v-table method.
|
||||
*/
|
||||
if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){
|
||||
sqlite3ResetOneSchema(db, pOp->p1);
|
||||
}
|
||||
p->expired = 1;
|
||||
rc = SQLITE_SCHEMA;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -3106,66 +3104,6 @@ case OP_SetCookie: { /* in3 */
|
|||
break;
|
||||
}
|
||||
|
||||
/* Opcode: VerifyCookie P1 P2 P3 * *
|
||||
**
|
||||
** Check the value of global database parameter number 0 (the
|
||||
** schema version) and make sure it is equal to P2 and that the
|
||||
** generation counter on the local schema parse equals P3.
|
||||
**
|
||||
** P1 is the database number which is 0 for the main database file
|
||||
** and 1 for the file holding temporary tables and some higher number
|
||||
** for auxiliary databases.
|
||||
**
|
||||
** The cookie changes its value whenever the database schema changes.
|
||||
** This operation is used to detect when that the cookie has changed
|
||||
** and that the current process needs to reread the schema.
|
||||
**
|
||||
** Either a transaction needs to have been started or an OP_Open needs
|
||||
** to be executed (to establish a read lock) before this opcode is
|
||||
** invoked.
|
||||
*/
|
||||
case OP_VerifyCookie: {
|
||||
int iMeta;
|
||||
int iGen;
|
||||
Btree *pBt;
|
||||
|
||||
assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
||||
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
|
||||
assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) );
|
||||
assert( p->bIsReader );
|
||||
pBt = db->aDb[pOp->p1].pBt;
|
||||
if( pBt ){
|
||||
sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta);
|
||||
iGen = db->aDb[pOp->p1].pSchema->iGeneration;
|
||||
}else{
|
||||
iGen = iMeta = 0;
|
||||
}
|
||||
if( iMeta!=pOp->p2 || iGen!=pOp->p3 ){
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
|
||||
/* If the schema-cookie from the database file matches the cookie
|
||||
** stored with the in-memory representation of the schema, do
|
||||
** not reload the schema from the database file.
|
||||
**
|
||||
** If virtual-tables are in use, this is not just an optimization.
|
||||
** Often, v-tables store their data in other SQLite tables, which
|
||||
** are queried from within xNext() and other v-table methods using
|
||||
** prepared queries. If such a query is out-of-date, we do not want to
|
||||
** discard the database schema, as the user code implementing the
|
||||
** v-table would have to be ready for the sqlite3_vtab structure itself
|
||||
** to be invalidated whenever sqlite3_step() is called from within
|
||||
** a v-table method.
|
||||
*/
|
||||
if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){
|
||||
sqlite3ResetOneSchema(db, pOp->p1);
|
||||
}
|
||||
|
||||
p->expired = 1;
|
||||
rc = SQLITE_SCHEMA;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: OpenRead P1 P2 P3 P4 P5
|
||||
** Synopsis: root=P2 iDb=P3
|
||||
**
|
||||
|
@ -3379,7 +3317,7 @@ case OP_OpenEphemeral: {
|
|||
break;
|
||||
}
|
||||
|
||||
/* Opcode: SorterOpen P1 * * P4 *
|
||||
/* Opcode: SorterOpen P1 P2 * P4 *
|
||||
**
|
||||
** This opcode works like OP_OpenEphemeral except that it opens
|
||||
** a transient index that is specifically designed to sort large
|
||||
|
@ -3399,14 +3337,13 @@ case OP_SorterOpen: {
|
|||
break;
|
||||
}
|
||||
|
||||
/* Opcode: OpenPseudo P1 P2 P3 * P5
|
||||
** Synopsis: content in r[P2@P3]
|
||||
/* Opcode: OpenPseudo P1 P2 P3 * *
|
||||
** Synopsis: P3 columns in r[P2]
|
||||
**
|
||||
** Open a new cursor that points to a fake table that contains a single
|
||||
** row of data. The content of that one row in the content of memory
|
||||
** register P2 when P5==0. In other words, cursor P1 becomes an alias for the
|
||||
** MEM_Blob content contained in register P2. When P5==1, then the
|
||||
** row is represented by P3 consecutive registers beginning with P2.
|
||||
** row of data. The content of that one row is the content of memory
|
||||
** register P2. In other words, cursor P1 becomes an alias for the
|
||||
** MEM_Blob content contained in register P2.
|
||||
**
|
||||
** A pseudo-table created by this opcode is used to hold a single
|
||||
** row output from the sorter so that the row can be decomposed into
|
||||
|
@ -3426,7 +3363,7 @@ case OP_OpenPseudo: {
|
|||
pCx->nullRow = 1;
|
||||
pCx->pseudoTableReg = pOp->p2;
|
||||
pCx->isTable = 1;
|
||||
pCx->multiPseudo = pOp->p5;
|
||||
assert( pOp->p5==0 );
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3609,6 +3546,7 @@ case OP_SeekGt: { /* jump, in3 */
|
|||
#endif
|
||||
if( oc>=OP_SeekGe ){ assert( oc==OP_SeekGe || oc==OP_SeekGt );
|
||||
if( res<0 || (res==0 && oc==OP_SeekGt) ){
|
||||
res = 0;
|
||||
rc = sqlite3BtreeNext(pC->pCursor, &res);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
pC->rowidIsValid = 0;
|
||||
|
@ -3618,6 +3556,7 @@ case OP_SeekGt: { /* jump, in3 */
|
|||
}else{
|
||||
assert( oc==OP_SeekLt || oc==OP_SeekLe );
|
||||
if( res>0 || (res==0 && oc==OP_SeekLt) ){
|
||||
res = 0;
|
||||
rc = sqlite3BtreePrevious(pC->pCursor, &res);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
pC->rowidIsValid = 0;
|
||||
|
@ -3737,15 +3676,13 @@ case OP_Found: { /* jump, in3 */
|
|||
r.pKeyInfo = pC->pKeyInfo;
|
||||
r.nField = (u16)pOp->p4.i;
|
||||
r.aMem = pIn3;
|
||||
for(ii=0; ii<r.nField; ii++){
|
||||
assert( memIsValid(&r.aMem[ii]) );
|
||||
ExpandBlob(&r.aMem[ii]);
|
||||
#ifdef SQLITE_DEBUG
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<r.nField; i++){
|
||||
assert( memIsValid(&r.aMem[i]) );
|
||||
if( i ) REGISTER_TRACE(pOp->p3+i, &r.aMem[i]);
|
||||
}
|
||||
}
|
||||
if( ii ) REGISTER_TRACE(pOp->p3+ii, &r.aMem[ii]);
|
||||
#endif
|
||||
}
|
||||
r.flags = UNPACKED_PREFIX_MATCH;
|
||||
pIdxKey = &r;
|
||||
}else{
|
||||
|
@ -4295,7 +4232,7 @@ case OP_SorterData: {
|
|||
**
|
||||
** Write into register P2 the complete row key for cursor P1.
|
||||
** There is no interpretation of the data.
|
||||
** The key is copied onto the P3 register exactly as
|
||||
** The key is copied onto the P2 register exactly as
|
||||
** it is found in the database file.
|
||||
**
|
||||
** If the P1 cursor must be pointing to a valid row (not a NULL row)
|
||||
|
@ -4521,7 +4458,7 @@ case OP_Rewind: { /* jump */
|
|||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Next P1 P2 * * P5
|
||||
/* Opcode: Next P1 P2 P3 P4 P5
|
||||
**
|
||||
** Advance cursor P1 so that it points to the next key/data pair in its
|
||||
** table or index. If there are no more key/value pairs then fall through
|
||||
|
@ -4531,6 +4468,11 @@ case OP_Rewind: { /* jump */
|
|||
** The P1 cursor must be for a real table, not a pseudo-table. P1 must have
|
||||
** been opened prior to this opcode or the program will segfault.
|
||||
**
|
||||
** The P3 value is a hint to the btree implementation. If P3==1, that
|
||||
** means P1 is an SQL index and that this instruction could have been
|
||||
** omitted if that index had been unique. P3 is usually 0. P3 is
|
||||
** always either 0 or 1.
|
||||
**
|
||||
** P4 is always of type P4_ADVANCE. The function pointer points to
|
||||
** sqlite3BtreeNext().
|
||||
**
|
||||
|
@ -4539,12 +4481,12 @@ case OP_Rewind: { /* jump */
|
|||
**
|
||||
** See also: Prev, NextIfOpen
|
||||
*/
|
||||
/* Opcode: NextIfOpen P1 P2 * * P5
|
||||
/* Opcode: NextIfOpen P1 P2 P3 P4 P5
|
||||
**
|
||||
** This opcode works just like OP_Next except that if cursor P1 is not
|
||||
** open it behaves a no-op.
|
||||
*/
|
||||
/* Opcode: Prev P1 P2 * * P5
|
||||
/* Opcode: Prev P1 P2 P3 P4 P5
|
||||
**
|
||||
** Back up cursor P1 so that it points to the previous key/data pair in its
|
||||
** table or index. If there is no previous key/value pairs then fall through
|
||||
|
@ -4554,13 +4496,18 @@ case OP_Rewind: { /* jump */
|
|||
** The P1 cursor must be for a real table, not a pseudo-table. If P1 is
|
||||
** not open then the behavior is undefined.
|
||||
**
|
||||
** The P3 value is a hint to the btree implementation. If P3==1, that
|
||||
** means P1 is an SQL index and that this instruction could have been
|
||||
** omitted if that index had been unique. P3 is usually 0. P3 is
|
||||
** always either 0 or 1.
|
||||
**
|
||||
** P4 is always of type P4_ADVANCE. The function pointer points to
|
||||
** sqlite3BtreePrevious().
|
||||
**
|
||||
** If P5 is positive and the jump is taken, then event counter
|
||||
** number P5-1 in the prepared statement is incremented.
|
||||
*/
|
||||
/* Opcode: PrevIfOpen P1 P2 * * P5
|
||||
/* Opcode: PrevIfOpen P1 P2 P3 P4 P5
|
||||
**
|
||||
** This opcode works just like OP_Prev except that if cursor P1 is not
|
||||
** open it behaves a no-op.
|
||||
|
@ -4582,9 +4529,12 @@ case OP_Next: /* jump */
|
|||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
assert( pOp->p5<ArraySize(p->aCounter) );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
res = pOp->p3;
|
||||
assert( pC!=0 );
|
||||
assert( pC->deferredMoveto==0 );
|
||||
assert( pC->pCursor );
|
||||
assert( res==0 || (res==1 && pC->isTable==0) );
|
||||
testcase( res==1 );
|
||||
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
|
||||
assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
|
||||
assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext );
|
||||
|
@ -4616,6 +4566,14 @@ next_tail:
|
|||
** P3 is a flag that provides a hint to the b-tree layer that this
|
||||
** insert is likely to be an append.
|
||||
**
|
||||
** If P5 has the OPFLAG_NCHANGE bit set, then the change counter is
|
||||
** incremented by this instruction. If the OPFLAG_NCHANGE bit is clear,
|
||||
** then the change counter is unchanged.
|
||||
**
|
||||
** If P5 has the OPFLAG_USESEEKRESULT bit set, then the cursor must have
|
||||
** just done a seek to the spot where the new entry is to be inserted.
|
||||
** This flag avoids doing an extra seek.
|
||||
**
|
||||
** This instruction only works for indices. The equivalent instruction
|
||||
** for tables is OP_Insert.
|
||||
*/
|
||||
|
@ -5216,7 +5174,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */
|
|||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
|
||||
/* Opcode: Program P1 P2 P3 P4 *
|
||||
/* Opcode: Program P1 P2 P3 P4 P5
|
||||
**
|
||||
** Execute the trigger program passed as P4 (type P4_SUBPROGRAM).
|
||||
**
|
||||
|
@ -5228,6 +5186,8 @@ case OP_RowSetTest: { /* jump, in1, in3 */
|
|||
** memory required by the sub-vdbe at runtime.
|
||||
**
|
||||
** P4 is a pointer to the VM containing the trigger program.
|
||||
**
|
||||
** If P5 is non-zero, then recursive program invocation is enabled.
|
||||
*/
|
||||
case OP_Program: { /* jump */
|
||||
int nMem; /* Number of memory registers for sub-program */
|
||||
|
@ -5305,7 +5265,7 @@ case OP_Program: { /* jump */
|
|||
|
||||
pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem];
|
||||
for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){
|
||||
pMem->flags = MEM_Invalid;
|
||||
pMem->flags = MEM_Undefined;
|
||||
pMem->db = db;
|
||||
}
|
||||
}else{
|
||||
|
@ -5615,7 +5575,7 @@ case OP_Checkpoint: {
|
|||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_PRAGMA
|
||||
/* Opcode: JournalMode P1 P2 P3 * P5
|
||||
/* Opcode: JournalMode P1 P2 P3 * *
|
||||
**
|
||||
** Change the journal mode of database P1 to P3. P3 must be one of the
|
||||
** PAGER_JOURNALMODE_XXX values. If changing between the various rollback
|
||||
|
@ -6101,7 +6061,7 @@ case OP_VRename: {
|
|||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/* Opcode: VUpdate P1 P2 P3 P4 *
|
||||
/* Opcode: VUpdate P1 P2 P3 P4 P5
|
||||
** Synopsis: data=r[P3@P2]
|
||||
**
|
||||
** P4 is a pointer to a virtual table object, an sqlite3_vtab structure.
|
||||
|
@ -6124,6 +6084,9 @@ case OP_VRename: {
|
|||
** P1 is a boolean flag. If it is set to true and the xUpdate call
|
||||
** is successful, then the value returned by sqlite3_last_insert_rowid()
|
||||
** is set to the value of the rowid for the row just inserted.
|
||||
**
|
||||
** P5 is the error actions (OE_Replace, OE_Fail, OE_Ignore, etc) to
|
||||
** apply in the case of a constraint failure on an insert or update.
|
||||
*/
|
||||
case OP_VUpdate: {
|
||||
sqlite3_vtab *pVtab;
|
||||
|
@ -6212,16 +6175,26 @@ case OP_MaxPgcnt: { /* out2-prerelease */
|
|||
#endif
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
/* Opcode: Trace * * * P4 *
|
||||
/* Opcode: Init * P2 * P4 *
|
||||
** Synopsis: Start at P2
|
||||
**
|
||||
** Programs contain a single instance of this opcode as the very first
|
||||
** opcode.
|
||||
**
|
||||
** If tracing is enabled (by the sqlite3_trace()) interface, then
|
||||
** the UTF-8 string contained in P4 is emitted on the trace callback.
|
||||
** Or if P4 is blank, use the string returned by sqlite3_sql().
|
||||
**
|
||||
** If P2 is not zero, jump to instruction P2.
|
||||
*/
|
||||
case OP_Trace: {
|
||||
case OP_Init: { /* jump */
|
||||
char *zTrace;
|
||||
char *z;
|
||||
|
||||
if( pOp->p2 ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
if( db->xTrace
|
||||
&& !p->doingRerun
|
||||
&& (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
|
||||
|
@ -6247,9 +6220,9 @@ case OP_Trace: {
|
|||
sqlite3DebugPrintf("SQL-trace: %s\n", zTrace);
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
#endif /* SQLITE_OMIT_TRACE */
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Opcode: Noop * * * * *
|
||||
|
|
|
@ -75,7 +75,6 @@ struct VdbeCursor {
|
|||
Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
|
||||
Bool isTable:1; /* True if a table requiring integer keys */
|
||||
Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */
|
||||
Bool multiPseudo:1; /* Multi-register pseudo-cursor */
|
||||
sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
|
||||
i64 seqCount; /* Sequence counter */
|
||||
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
|
||||
|
@ -169,7 +168,7 @@ struct Mem {
|
|||
} u;
|
||||
int n; /* Number of characters in string value, excluding '\0' */
|
||||
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
|
||||
u8 type; /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */
|
||||
u8 memType; /* Lower 5 bits of flags */
|
||||
u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
|
||||
#ifdef SQLITE_DEBUG
|
||||
Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */
|
||||
|
@ -198,7 +197,7 @@ struct Mem {
|
|||
#define MEM_Blob 0x0010 /* Value is a BLOB */
|
||||
#define MEM_RowSet 0x0020 /* Value is a RowSet object */
|
||||
#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */
|
||||
#define MEM_Invalid 0x0080 /* Value is undefined */
|
||||
#define MEM_Undefined 0x0080 /* Value is undefined */
|
||||
#define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */
|
||||
#define MEM_TypeMask 0x01ff /* Mask of type bits */
|
||||
|
||||
|
@ -230,7 +229,7 @@ struct Mem {
|
|||
** is for use inside assert() statements only.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
#define memIsValid(M) ((M)->flags & MEM_Invalid)==0
|
||||
#define memIsValid(M) ((M)->flags & MEM_Undefined)==0
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -444,16 +443,18 @@ int sqlite3VdbeMemNumerify(Mem*);
|
|||
int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*);
|
||||
void sqlite3VdbeMemRelease(Mem *p);
|
||||
void sqlite3VdbeMemReleaseExternal(Mem *p);
|
||||
#define VdbeMemDynamic(X) \
|
||||
(((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0)
|
||||
#define VdbeMemRelease(X) \
|
||||
if((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame)) \
|
||||
sqlite3VdbeMemReleaseExternal(X);
|
||||
if( VdbeMemDynamic(X) ) sqlite3VdbeMemReleaseExternal(X);
|
||||
int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
|
||||
const char *sqlite3OpcodeName(int);
|
||||
int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
|
||||
int sqlite3VdbeCloseStatement(Vdbe *, int);
|
||||
void sqlite3VdbeFrameDelete(VdbeFrame*);
|
||||
int sqlite3VdbeFrameRestore(VdbeFrame *);
|
||||
void sqlite3VdbeMemStoreType(Mem *pMem);
|
||||
#define sqlite3VdbeMemStoreType(X) (X)->memType = (u8)((X)->flags&0x1f)
|
||||
/* void sqlite3VdbeMemStoreType(Mem *pMem); */
|
||||
void sqlite3VdbePreUpdateHook(
|
||||
Vdbe *, VdbeCursor *, int, const char*, Table *, i64, int);
|
||||
int sqlite3VdbeTransferError(Vdbe *p);
|
||||
|
|
|
@ -172,7 +172,41 @@ const void *sqlite3_value_text16le(sqlite3_value *pVal){
|
|||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
int sqlite3_value_type(sqlite3_value* pVal){
|
||||
return pVal->type;
|
||||
static const u8 aType[] = {
|
||||
SQLITE_BLOB, /* 0x00 */
|
||||
SQLITE_NULL, /* 0x01 */
|
||||
SQLITE_TEXT, /* 0x02 */
|
||||
SQLITE_NULL, /* 0x03 */
|
||||
SQLITE_INTEGER, /* 0x04 */
|
||||
SQLITE_NULL, /* 0x05 */
|
||||
SQLITE_INTEGER, /* 0x06 */
|
||||
SQLITE_NULL, /* 0x07 */
|
||||
SQLITE_FLOAT, /* 0x08 */
|
||||
SQLITE_NULL, /* 0x09 */
|
||||
SQLITE_FLOAT, /* 0x0a */
|
||||
SQLITE_NULL, /* 0x0b */
|
||||
SQLITE_INTEGER, /* 0x0c */
|
||||
SQLITE_NULL, /* 0x0d */
|
||||
SQLITE_INTEGER, /* 0x0e */
|
||||
SQLITE_NULL, /* 0x0f */
|
||||
SQLITE_BLOB, /* 0x10 */
|
||||
SQLITE_NULL, /* 0x11 */
|
||||
SQLITE_TEXT, /* 0x12 */
|
||||
SQLITE_NULL, /* 0x13 */
|
||||
SQLITE_INTEGER, /* 0x14 */
|
||||
SQLITE_NULL, /* 0x15 */
|
||||
SQLITE_INTEGER, /* 0x16 */
|
||||
SQLITE_NULL, /* 0x17 */
|
||||
SQLITE_FLOAT, /* 0x18 */
|
||||
SQLITE_NULL, /* 0x19 */
|
||||
SQLITE_FLOAT, /* 0x1a */
|
||||
SQLITE_NULL, /* 0x1b */
|
||||
SQLITE_INTEGER, /* 0x1c */
|
||||
SQLITE_NULL, /* 0x1d */
|
||||
SQLITE_INTEGER, /* 0x1e */
|
||||
SQLITE_NULL, /* 0x1f */
|
||||
};
|
||||
return aType[pVal->memType&0x1f];
|
||||
}
|
||||
|
||||
/**************************** sqlite3_result_ *******************************
|
||||
|
@ -1130,7 +1164,7 @@ int sqlite3_bind_text16(
|
|||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
|
||||
int rc;
|
||||
switch( pValue->type ){
|
||||
switch( sqlite3_value_type((sqlite3_value*)pValue) ){
|
||||
case SQLITE_INTEGER: {
|
||||
rc = sqlite3_bind_int64(pStmt, i, pValue->u.i);
|
||||
break;
|
||||
|
|
|
@ -864,14 +864,6 @@ void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){
|
|||
** this routine is a valid pointer. But because the dummy.opcode is 0,
|
||||
** dummy will never be written to. This is verified by code inspection and
|
||||
** by running with Valgrind.
|
||||
**
|
||||
** About the #ifdef SQLITE_OMIT_TRACE: Normally, this routine is never called
|
||||
** unless p->nOp>0. This is because in the absense of SQLITE_OMIT_TRACE,
|
||||
** an OP_Trace instruction is always inserted by sqlite3VdbeGet() as soon as
|
||||
** a new VDBE is created. So we are free to set addr to p->nOp-1 without
|
||||
** having to double-check to make sure that the result is non-negative. But
|
||||
** if SQLITE_OMIT_TRACE is defined, the OP_Trace is omitted and we do need to
|
||||
** check the value of p->nOp-1 before continuing.
|
||||
*/
|
||||
VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
|
||||
/* C89 specifies that the constant "dummy" will be initialized to all
|
||||
|
@ -879,9 +871,6 @@ VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
|
|||
static VdbeOp dummy; /* Ignore the MSVC warning about no initializer */
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
if( addr<0 ){
|
||||
#ifdef SQLITE_OMIT_TRACE
|
||||
if( p->nOp==0 ) return (VdbeOp*)&dummy;
|
||||
#endif
|
||||
addr = p->nOp - 1;
|
||||
}
|
||||
assert( (addr>=0 && addr<p->nOp) || p->db->mallocFailed );
|
||||
|
@ -1235,7 +1224,7 @@ static void releaseMemArray(Mem *p, int N){
|
|||
p->zMalloc = 0;
|
||||
}
|
||||
|
||||
p->flags = MEM_Invalid;
|
||||
p->flags = MEM_Undefined;
|
||||
}
|
||||
db->mallocFailed = malloc_failed;
|
||||
}
|
||||
|
@ -1357,7 +1346,7 @@ int sqlite3VdbeList(
|
|||
}
|
||||
if( p->explain==1 ){
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
pMem->memType = MEM_Int;
|
||||
pMem->u.i = i; /* Program counter */
|
||||
pMem++;
|
||||
|
||||
|
@ -1365,7 +1354,7 @@ int sqlite3VdbeList(
|
|||
pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */
|
||||
assert( pMem->z!=0 );
|
||||
pMem->n = sqlite3Strlen30(pMem->z);
|
||||
pMem->type = SQLITE_TEXT;
|
||||
pMem->memType = MEM_Str;
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
pMem++;
|
||||
|
||||
|
@ -1391,17 +1380,17 @@ int sqlite3VdbeList(
|
|||
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->u.i = pOp->p1; /* P1 */
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
pMem->memType = MEM_Int;
|
||||
pMem++;
|
||||
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->u.i = pOp->p2; /* P2 */
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
pMem->memType = MEM_Int;
|
||||
pMem++;
|
||||
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->u.i = pOp->p3; /* P3 */
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
pMem->memType = MEM_Int;
|
||||
pMem++;
|
||||
|
||||
if( sqlite3VdbeMemGrow(pMem, 32, 0) ){ /* P4 */
|
||||
|
@ -1417,7 +1406,7 @@ int sqlite3VdbeList(
|
|||
pMem->n = sqlite3Strlen30(pMem->z);
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
}
|
||||
pMem->type = SQLITE_TEXT;
|
||||
pMem->memType = MEM_Str;
|
||||
pMem++;
|
||||
|
||||
if( p->explain==1 ){
|
||||
|
@ -1428,7 +1417,7 @@ int sqlite3VdbeList(
|
|||
pMem->flags = MEM_Dyn|MEM_Str|MEM_Term;
|
||||
pMem->n = 2;
|
||||
sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5); /* P5 */
|
||||
pMem->type = SQLITE_TEXT;
|
||||
pMem->memType = MEM_Str;
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
pMem++;
|
||||
|
||||
|
@ -1439,11 +1428,11 @@ int sqlite3VdbeList(
|
|||
}
|
||||
pMem->flags = MEM_Dyn|MEM_Str|MEM_Term;
|
||||
pMem->n = displayComment(pOp, zP4, pMem->z, 500);
|
||||
pMem->type = SQLITE_TEXT;
|
||||
pMem->memType = MEM_Str;
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
#else
|
||||
pMem->flags = MEM_Null; /* Comment */
|
||||
pMem->type = SQLITE_NULL;
|
||||
pMem->memType = MEM_Null;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1466,7 +1455,7 @@ void sqlite3VdbePrintSql(Vdbe *p){
|
|||
z = p->zSql;
|
||||
}else if( p->nOp>=1 ){
|
||||
const VdbeOp *pOp = &p->aOp[0];
|
||||
if( pOp->opcode==OP_Trace && pOp->p4.z!=0 ){
|
||||
if( pOp->opcode==OP_Init && pOp->p4.z!=0 ){
|
||||
z = pOp->p4.z;
|
||||
while( sqlite3Isspace(*z) ) z++;
|
||||
}
|
||||
|
@ -1485,7 +1474,7 @@ void sqlite3VdbeIOTraceSql(Vdbe *p){
|
|||
if( sqlite3IoTrace==0 ) return;
|
||||
if( nOp<1 ) return;
|
||||
pOp = &p->aOp[0];
|
||||
if( pOp->opcode==OP_Trace && pOp->p4.z!=0 ){
|
||||
if( pOp->opcode==OP_Init && pOp->p4.z!=0 ){
|
||||
int i, j;
|
||||
char z[1000];
|
||||
sqlite3_snprintf(sizeof(z), z, "%s", pOp->p4.z);
|
||||
|
@ -1703,7 +1692,7 @@ void sqlite3VdbeMakeReady(
|
|||
p->aMem--; /* aMem[] goes from 1..nMem */
|
||||
p->nMem = nMem; /* not from 0..nMem-1 */
|
||||
for(n=1; n<=nMem; n++){
|
||||
p->aMem[n].flags = MEM_Invalid;
|
||||
p->aMem[n].flags = MEM_Undefined;
|
||||
p->aMem[n].db = db;
|
||||
}
|
||||
}
|
||||
|
@ -1815,7 +1804,7 @@ static void Cleanup(Vdbe *p){
|
|||
int i;
|
||||
if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 );
|
||||
if( p->aMem ){
|
||||
for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Invalid );
|
||||
for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -136,21 +136,20 @@ int sqlite3_blob_open(
|
|||
** transaction.
|
||||
*/
|
||||
static const VdbeOpList openBlob[] = {
|
||||
{OP_Transaction, 0, 0, 0}, /* 0: Start a transaction */
|
||||
{OP_VerifyCookie, 0, 0, 0}, /* 1: Check the schema cookie */
|
||||
{OP_TableLock, 0, 0, 0}, /* 2: Acquire a read or write lock */
|
||||
/* {OP_Transaction, 0, 0, 0}, // 0: Inserted separately */
|
||||
{OP_TableLock, 0, 0, 0}, /* 1: Acquire a read or write lock */
|
||||
|
||||
/* One of the following two instructions is replaced by an OP_Noop. */
|
||||
{OP_OpenRead, 0, 0, 0}, /* 3: Open cursor 0 for reading */
|
||||
{OP_OpenWrite, 0, 0, 0}, /* 4: Open cursor 0 for read/write */
|
||||
{OP_OpenRead, 0, 0, 0}, /* 2: Open cursor 0 for reading */
|
||||
{OP_OpenWrite, 0, 0, 0}, /* 3: Open cursor 0 for read/write */
|
||||
|
||||
{OP_Variable, 1, 1, 1}, /* 5: Push the rowid to the stack */
|
||||
{OP_NotExists, 0, 10, 1}, /* 6: Seek the cursor */
|
||||
{OP_Column, 0, 0, 1}, /* 7 */
|
||||
{OP_ResultRow, 1, 0, 0}, /* 8 */
|
||||
{OP_Goto, 0, 5, 0}, /* 9 */
|
||||
{OP_Close, 0, 0, 0}, /* 10 */
|
||||
{OP_Halt, 0, 0, 0}, /* 11 */
|
||||
{OP_Variable, 1, 1, 1}, /* 4: Push the rowid to the stack */
|
||||
{OP_NotExists, 0, 10, 1}, /* 5: Seek the cursor */
|
||||
{OP_Column, 0, 0, 1}, /* 6 */
|
||||
{OP_ResultRow, 1, 0, 0}, /* 7 */
|
||||
{OP_Goto, 0, 4, 0}, /* 8 */
|
||||
{OP_Close, 0, 0, 0}, /* 9 */
|
||||
{OP_Halt, 0, 0, 0}, /* 10 */
|
||||
};
|
||||
|
||||
int rc = SQLITE_OK;
|
||||
|
@ -265,36 +264,31 @@ int sqlite3_blob_open(
|
|||
Vdbe *v = (Vdbe *)pBlob->pStmt;
|
||||
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
|
||||
|
||||
sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, flags,
|
||||
pTab->pSchema->schema_cookie,
|
||||
pTab->pSchema->iGeneration);
|
||||
sqlite3VdbeChangeP5(v, 1);
|
||||
sqlite3VdbeAddOpList(v, sizeof(openBlob)/sizeof(VdbeOpList), openBlob);
|
||||
|
||||
|
||||
/* Configure the OP_Transaction */
|
||||
sqlite3VdbeChangeP1(v, 0, iDb);
|
||||
sqlite3VdbeChangeP2(v, 0, flags);
|
||||
|
||||
/* Configure the OP_VerifyCookie */
|
||||
sqlite3VdbeChangeP1(v, 1, iDb);
|
||||
sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie);
|
||||
sqlite3VdbeChangeP3(v, 1, pTab->pSchema->iGeneration);
|
||||
|
||||
/* Make sure a mutex is held on the table to be accessed */
|
||||
sqlite3VdbeUsesBtree(v, iDb);
|
||||
|
||||
/* Configure the OP_TableLock instruction */
|
||||
#ifdef SQLITE_OMIT_SHARED_CACHE
|
||||
sqlite3VdbeChangeToNoop(v, 2);
|
||||
sqlite3VdbeChangeToNoop(v, 1);
|
||||
#else
|
||||
sqlite3VdbeChangeP1(v, 2, iDb);
|
||||
sqlite3VdbeChangeP2(v, 2, pTab->tnum);
|
||||
sqlite3VdbeChangeP3(v, 2, flags);
|
||||
sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);
|
||||
sqlite3VdbeChangeP1(v, 1, iDb);
|
||||
sqlite3VdbeChangeP2(v, 1, pTab->tnum);
|
||||
sqlite3VdbeChangeP3(v, 1, flags);
|
||||
sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT);
|
||||
#endif
|
||||
|
||||
/* Remove either the OP_OpenWrite or OpenRead. Set the P2
|
||||
** parameter of the other to pTab->tnum. */
|
||||
sqlite3VdbeChangeToNoop(v, 4 - flags);
|
||||
sqlite3VdbeChangeP2(v, 3 + flags, pTab->tnum);
|
||||
sqlite3VdbeChangeP3(v, 3 + flags, iDb);
|
||||
sqlite3VdbeChangeToNoop(v, 3 - flags);
|
||||
sqlite3VdbeChangeP2(v, 2 + flags, pTab->tnum);
|
||||
sqlite3VdbeChangeP3(v, 2 + flags, iDb);
|
||||
|
||||
/* Configure the number of columns. Configure the cursor to
|
||||
** think that the table has one more column than it really
|
||||
|
@ -303,8 +297,8 @@ int sqlite3_blob_open(
|
|||
** we can invoke OP_Column to fill in the vdbe cursors type
|
||||
** and offset cache without causing any IO.
|
||||
*/
|
||||
sqlite3VdbeChangeP4(v, 3+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32);
|
||||
sqlite3VdbeChangeP2(v, 7, pTab->nCol);
|
||||
sqlite3VdbeChangeP4(v, 2+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32);
|
||||
sqlite3VdbeChangeP2(v, 6, pTab->nCol);
|
||||
if( !db->mallocFailed ){
|
||||
pParse->nVar = 1;
|
||||
pParse->nMem = 1;
|
||||
|
|
|
@ -289,7 +289,7 @@ void sqlite3VdbeMemReleaseExternal(Mem *p){
|
|||
/*
|
||||
** Release any memory held by the Mem. This may leave the Mem in an
|
||||
** inconsistent state, for example with (Mem.z==0) and
|
||||
** (Mem.type==SQLITE_TEXT).
|
||||
** (Mem.memType==MEM_Str).
|
||||
*/
|
||||
void sqlite3VdbeMemRelease(Mem *p){
|
||||
VdbeMemRelease(p);
|
||||
|
@ -480,7 +480,7 @@ void sqlite3VdbeMemSetNull(Mem *pMem){
|
|||
sqlite3RowSetClear(pMem->u.pRowSet);
|
||||
}
|
||||
MemSetTypeFlag(pMem, MEM_Null);
|
||||
pMem->type = SQLITE_NULL;
|
||||
pMem->memType = MEM_Null;
|
||||
}
|
||||
void sqlite3ValueSetNull(sqlite3_value *p){
|
||||
sqlite3VdbeMemSetNull((Mem*)p);
|
||||
|
@ -493,7 +493,7 @@ void sqlite3ValueSetNull(sqlite3_value *p){
|
|||
void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->flags = MEM_Blob|MEM_Zero;
|
||||
pMem->type = SQLITE_BLOB;
|
||||
pMem->memType = MEM_Blob;
|
||||
pMem->n = 0;
|
||||
if( n<0 ) n = 0;
|
||||
pMem->u.nZero = n;
|
||||
|
@ -516,7 +516,7 @@ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
|
|||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->u.i = val;
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
pMem->memType = MEM_Int;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
|
@ -531,7 +531,7 @@ void sqlite3VdbeMemSetDouble(Mem *pMem, double val){
|
|||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->r = val;
|
||||
pMem->flags = MEM_Real;
|
||||
pMem->type = SQLITE_FLOAT;
|
||||
pMem->memType = MEM_Real;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -587,7 +587,7 @@ void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
|
|||
Mem *pX;
|
||||
for(i=1, pX=&pVdbe->aMem[1]; i<=pVdbe->nMem; i++, pX++){
|
||||
if( pX->pScopyFrom==pMem ){
|
||||
pX->flags |= MEM_Invalid;
|
||||
pX->flags |= MEM_Undefined;
|
||||
pX->pScopyFrom = 0;
|
||||
}
|
||||
}
|
||||
|
@ -739,7 +739,7 @@ int sqlite3VdbeMemSetStr(
|
|||
pMem->n = nByte;
|
||||
pMem->flags = flags;
|
||||
pMem->enc = (enc==0 ? SQLITE_UTF8 : enc);
|
||||
pMem->type = (enc==0 ? SQLITE_BLOB : SQLITE_TEXT);
|
||||
pMem->memType = flags&0x1f;
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
if( pMem->enc!=SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){
|
||||
|
@ -910,7 +910,7 @@ int sqlite3VdbeMemFromBtree(
|
|||
}else if( SQLITE_OK==(rc = sqlite3VdbeMemGrow(pMem, amt+2, 0)) ){
|
||||
pMem->flags = MEM_Blob|MEM_Dyn|MEM_Term;
|
||||
pMem->enc = 0;
|
||||
pMem->type = SQLITE_BLOB;
|
||||
pMem->memType = MEM_Blob;
|
||||
if( key ){
|
||||
rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z);
|
||||
}else{
|
||||
|
@ -980,7 +980,7 @@ sqlite3_value *sqlite3ValueNew(sqlite3 *db){
|
|||
Mem *p = sqlite3DbMallocZero(db, sizeof(*p));
|
||||
if( p ){
|
||||
p->flags = MEM_Null;
|
||||
p->type = SQLITE_NULL;
|
||||
p->memType = MEM_Null;
|
||||
p->db = db;
|
||||
}
|
||||
return p;
|
||||
|
@ -1030,7 +1030,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
|
|||
pRec->aMem = (Mem *)((u8*)pRec + ROUND8(sizeof(UnpackedRecord)));
|
||||
for(i=0; i<nCol; i++){
|
||||
pRec->aMem[i].flags = MEM_Null;
|
||||
pRec->aMem[i].type = SQLITE_NULL;
|
||||
pRec->aMem[i].memType = MEM_Null;
|
||||
pRec->aMem[i].db = db;
|
||||
}
|
||||
}else{
|
||||
|
@ -1103,7 +1103,7 @@ static int valueFromExpr(
|
|||
zVal = sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken);
|
||||
if( zVal==0 ) goto no_mem;
|
||||
sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
|
||||
if( op==TK_FLOAT ) pVal->type = SQLITE_FLOAT;
|
||||
if( op==TK_FLOAT ) pVal->memType = MEM_Real;
|
||||
}
|
||||
if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){
|
||||
sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8);
|
||||
|
|
58
src/where.c
58
src/where.c
|
@ -2785,10 +2785,9 @@ static Bitmask codeOneLoopStart(
|
|||
/* Special case of a FROM clause subquery implemented as a co-routine */
|
||||
if( pTabItem->viaCoroutine ){
|
||||
int regYield = pTabItem->regReturn;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pTabItem->addrFillSub-1, regYield);
|
||||
pLevel->p2 = sqlite3VdbeAddOp1(v, OP_Yield, regYield);
|
||||
VdbeComment((v, "next row of co-routine %s", pTabItem->pTab->zName));
|
||||
sqlite3VdbeAddOp2(v, OP_If, regYield+1, addrBrk);
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
|
||||
pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk);
|
||||
VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName));
|
||||
pLevel->op = OP_Goto;
|
||||
}else
|
||||
|
||||
|
@ -3184,6 +3183,8 @@ static Bitmask codeOneLoopStart(
|
|||
pLevel->op = OP_Next;
|
||||
}
|
||||
pLevel->p1 = iIdxCur;
|
||||
assert( (WHERE_UNQ_WANTED>>16)==1 );
|
||||
pLevel->p3 = (pLoop->wsFlags>>16)&1;
|
||||
if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){
|
||||
pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP;
|
||||
}else{
|
||||
|
@ -3314,7 +3315,9 @@ static Bitmask codeOneLoopStart(
|
|||
Expr *pExpr = pWC->a[iTerm].pExpr;
|
||||
if( &pWC->a[iTerm] == pTerm ) continue;
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ) continue;
|
||||
if( pWC->a[iTerm].wtFlags & (TERM_ORINFO) ) continue;
|
||||
testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO );
|
||||
testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL );
|
||||
if( pWC->a[iTerm].wtFlags & (TERM_ORINFO|TERM_VIRTUAL) ) continue;
|
||||
if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
|
||||
pExpr = sqlite3ExprDup(db, pExpr, 0);
|
||||
pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr);
|
||||
|
@ -3986,12 +3989,13 @@ static int whereLoopAddBtreeIndex(
|
|||
|| nInMul==0
|
||||
);
|
||||
pNew->wsFlags |= WHERE_COLUMN_EQ;
|
||||
if( iCol<0
|
||||
|| (pProbe->onError!=OE_None && nInMul==0
|
||||
&& pNew->u.btree.nEq==pProbe->nKeyCol-1)
|
||||
){
|
||||
if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1)){
|
||||
assert( (pNew->wsFlags & WHERE_COLUMN_IN)==0 || iCol<0 );
|
||||
pNew->wsFlags |= WHERE_ONEROW;
|
||||
if( iCol>=0 && pProbe->onError==OE_None ){
|
||||
pNew->wsFlags |= WHERE_UNQ_WANTED;
|
||||
}else{
|
||||
pNew->wsFlags |= WHERE_ONEROW;
|
||||
}
|
||||
}
|
||||
pNew->u.btree.nEq++;
|
||||
pNew->nOut = nRowEst + nInMul;
|
||||
|
@ -5434,7 +5438,6 @@ WhereInfo *sqlite3WhereBegin(
|
|||
initMaskSet(pMaskSet);
|
||||
whereClauseInit(&pWInfo->sWC, pWInfo);
|
||||
whereSplit(&pWInfo->sWC, pWhere, TK_AND);
|
||||
sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
|
||||
|
||||
/* Special case: a WHERE clause that is constant. Evaluate the
|
||||
** expression and either jump over all of the code or fall thru.
|
||||
|
@ -5723,7 +5726,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
sqlite3VdbeSetP4KeyInfo(pParse, pIx);
|
||||
VdbeComment((v, "%s", pIx->zName));
|
||||
}
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
if( iDb>=0 ) sqlite3CodeVerifySchema(pParse, iDb);
|
||||
notReady &= ~getMask(&pWInfo->sMaskSet, pTabItem->iCursor);
|
||||
}
|
||||
pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
|
||||
|
@ -5785,7 +5788,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|||
pLoop = pLevel->pWLoop;
|
||||
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
|
||||
if( pLevel->op!=OP_Noop ){
|
||||
sqlite3VdbeAddOp2(v, pLevel->op, pLevel->p1, pLevel->p2);
|
||||
sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3);
|
||||
sqlite3VdbeChangeP5(v, pLevel->p5);
|
||||
}
|
||||
if( pLoop->wsFlags & WHERE_IN_ABLE && pLevel->u.in.nIn>0 ){
|
||||
|
@ -5834,12 +5837,38 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|||
|
||||
assert( pWInfo->nLevel<=pTabList->nSrc );
|
||||
for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
|
||||
int k, last;
|
||||
VdbeOp *pOp;
|
||||
Index *pIdx = 0;
|
||||
struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom];
|
||||
Table *pTab = pTabItem->pTab;
|
||||
assert( pTab!=0 );
|
||||
pLoop = pLevel->pWLoop;
|
||||
|
||||
/* For a co-routine, change all OP_Column references to the table of
|
||||
** the co-routine into OP_SCopy of result contained in a register.
|
||||
** OP_Rowid becomes OP_Null.
|
||||
*/
|
||||
if( pTabItem->viaCoroutine ){
|
||||
last = sqlite3VdbeCurrentAddr(v);
|
||||
k = pLevel->addrBody;
|
||||
pOp = sqlite3VdbeGetOp(v, k);
|
||||
for(; k<last; k++, pOp++){
|
||||
if( pOp->p1!=pLevel->iTabCur ) continue;
|
||||
if( pOp->opcode==OP_Column ){
|
||||
pOp->opcode = OP_SCopy;
|
||||
pOp->p1 = pOp->p2 + pTabItem->regResult;
|
||||
pOp->p2 = pOp->p3;
|
||||
pOp->p3 = 0;
|
||||
}else if( pOp->opcode==OP_Rowid ){
|
||||
pOp->opcode = OP_Null;
|
||||
pOp->p1 = 0;
|
||||
pOp->p3 = 0;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Close all of the cursors that were opened by sqlite3WhereBegin.
|
||||
** Except, do not close cursors that will be reused by the OR optimization
|
||||
** (WHERE_OMIT_OPEN_CLOSE). And do not close the OP_OpenWrite cursors
|
||||
|
@ -5878,9 +5907,6 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
|||
pIdx = pLevel->u.pCovidx;
|
||||
}
|
||||
if( pIdx && !db->mallocFailed ){
|
||||
int k, last;
|
||||
VdbeOp *pOp;
|
||||
|
||||
last = sqlite3VdbeCurrentAddr(v);
|
||||
k = pLevel->addrBody;
|
||||
pOp = sqlite3VdbeGetOp(v, k);
|
||||
|
|
|
@ -70,7 +70,7 @@ struct WhereLevel {
|
|||
int addrFirst; /* First instruction of interior of the loop */
|
||||
int addrBody; /* Beginning of the body of this loop */
|
||||
u8 iFrom; /* Which entry in the FROM clause */
|
||||
u8 op, p5; /* Opcode and P5 of the opcode that ends the loop */
|
||||
u8 op, p3, p5; /* Opcode, P3 & P5 of the opcode that ends the loop */
|
||||
int p1, p2; /* Operands of the opcode used to ends the loop */
|
||||
union { /* Information that depends on pWLoop->wsFlags */
|
||||
struct {
|
||||
|
@ -457,3 +457,4 @@ struct WhereInfo {
|
|||
#define WHERE_MULTI_OR 0x00002000 /* OR using multiple indices */
|
||||
#define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */
|
||||
#define WHERE_SKIPSCAN 0x00008000 /* Uses the skip-scan algorithm */
|
||||
#define WHERE_UNQ_WANTED 0x00010000 /* WHERE_ONEROW would have been helpful*/
|
||||
|
|
|
@ -197,4 +197,29 @@ do_test 3.1 {
|
|||
}]
|
||||
} {0}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Ticket [fccbde530a6583bf2748400919f1603d5425995c] (2014-01-08)
|
||||
# The logic that computes DISTINCT sometimes thinks that a zeroblob()
|
||||
# and a blob of all zeros are different when they should be the same.
|
||||
#
|
||||
do_execsql_test 4.1 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t2;
|
||||
CREATE TABLE t1(a INTEGER);
|
||||
INSERT INTO t1 VALUES(3);
|
||||
INSERT INTO t1 VALUES(2);
|
||||
INSERT INTO t1 VALUES(1);
|
||||
INSERT INTO t1 VALUES(2);
|
||||
INSERT INTO t1 VALUES(3);
|
||||
INSERT INTO t1 VALUES(1);
|
||||
CREATE TABLE t2(x);
|
||||
INSERT INTO t2
|
||||
SELECT DISTINCT
|
||||
CASE a WHEN 1 THEN x'0000000000'
|
||||
WHEN 2 THEN zeroblob(5)
|
||||
ELSE 'xyzzy' END
|
||||
FROM t1;
|
||||
SELECT quote(x) FROM t2 ORDER BY 1;
|
||||
} {'xyzzy' X'0000000000'}
|
||||
|
||||
finish_test
|
||||
|
|
|
@ -1292,5 +1292,22 @@ do_test selectA-3.97 {
|
|||
ORDER BY y COLLATE NOCASE DESC,x,z)))
|
||||
}
|
||||
} {MAD}
|
||||
do_execsql_test selectA-3.98 {
|
||||
WITH RECURSIVE
|
||||
xyz(n) AS (
|
||||
SELECT upper((SELECT x FROM (
|
||||
SELECT x,y,z FROM t2
|
||||
INTERSECT SELECT a,b,c FROM t3
|
||||
EXCEPT SELECT c,b,a FROM t1
|
||||
UNION SELECT a,b,c FROM t3
|
||||
INTERSECT SELECT a,b,c FROM t3
|
||||
EXCEPT SELECT c,b,a FROM t1
|
||||
UNION SELECT a,b,c FROM t3
|
||||
ORDER BY y COLLATE NOCASE DESC,x,z)))
|
||||
UNION ALL
|
||||
SELECT n || '+' FROM xyz WHERE length(n)<5
|
||||
)
|
||||
SELECT n FROM xyz ORDER BY +n;
|
||||
} {MAD MAD+ MAD++}
|
||||
|
||||
finish_test
|
||||
|
|
|
@ -737,6 +737,161 @@ void testset_main(void){
|
|||
speedtest1_end_test();
|
||||
}
|
||||
|
||||
/*
|
||||
** A testset for common table expressions. This exercises code
|
||||
** for views, subqueries, co-routines, etc.
|
||||
*/
|
||||
void testset_cte(void){
|
||||
static const char *azPuzzle[] = {
|
||||
/* Easy */
|
||||
"534...9.."
|
||||
"67.195..."
|
||||
".98....6."
|
||||
"8...6...3"
|
||||
"4..8.3..1"
|
||||
"....2...6"
|
||||
".6....28."
|
||||
"...419..5"
|
||||
"...28..79",
|
||||
|
||||
/* Medium */
|
||||
"53....9.."
|
||||
"6..195..."
|
||||
".98....6."
|
||||
"8...6...3"
|
||||
"4..8.3..1"
|
||||
"....2...6"
|
||||
".6....28."
|
||||
"...419..5"
|
||||
"....8..79",
|
||||
|
||||
/* Hard */
|
||||
"53......."
|
||||
"6..195..."
|
||||
".98....6."
|
||||
"8...6...3"
|
||||
"4..8.3..1"
|
||||
"....2...6"
|
||||
".6....28."
|
||||
"...419..5"
|
||||
"....8..79",
|
||||
};
|
||||
const char *zPuz;
|
||||
double rSpacing;
|
||||
int nElem;
|
||||
|
||||
if( g.szTest<25 ){
|
||||
zPuz = azPuzzle[0];
|
||||
}else if( g.szTest<70 ){
|
||||
zPuz = azPuzzle[1];
|
||||
}else{
|
||||
zPuz = azPuzzle[2];
|
||||
}
|
||||
speedtest1_begin_test(100, "Sudoku with recursive 'digits'");
|
||||
speedtest1_prepare(
|
||||
"WITH RECURSIVE\n"
|
||||
" input(sud) AS (VALUES(?1)),\n"
|
||||
" digits(z,lp) AS (\n"
|
||||
" VALUES('1', 1)\n"
|
||||
" UNION ALL\n"
|
||||
" SELECT CAST(lp+1 AS TEXT), lp+1 FROM digits WHERE lp<9\n"
|
||||
" ),\n"
|
||||
" x(s, ind) AS (\n"
|
||||
" SELECT sud, instr(sud, '.') FROM input\n"
|
||||
" UNION ALL\n"
|
||||
" SELECT\n"
|
||||
" substr(s, 1, ind-1) || z || substr(s, ind+1),\n"
|
||||
" instr( substr(s, 1, ind-1) || z || substr(s, ind+1), '.' )\n"
|
||||
" FROM x, digits AS z\n"
|
||||
" WHERE ind>0\n"
|
||||
" AND NOT EXISTS (\n"
|
||||
" SELECT 1\n"
|
||||
" FROM digits AS lp\n"
|
||||
" WHERE z.z = substr(s, ((ind-1)/9)*9 + lp, 1)\n"
|
||||
" OR z.z = substr(s, ((ind-1)%%9) + (lp-1)*9 + 1, 1)\n"
|
||||
" OR z.z = substr(s, (((ind-1)/3) %% 3) * 3\n"
|
||||
" + ((ind-1)/27) * 27 + lp\n"
|
||||
" + ((lp-1) / 3) * 6, 1)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
"SELECT s FROM x WHERE ind=0;"
|
||||
);
|
||||
sqlite3_bind_text(g.pStmt, 1, zPuz, -1, SQLITE_STATIC);
|
||||
speedtest1_run();
|
||||
speedtest1_end_test();
|
||||
|
||||
speedtest1_begin_test(200, "Sudoku with VALUES 'digits'");
|
||||
speedtest1_prepare(
|
||||
"WITH RECURSIVE\n"
|
||||
" input(sud) AS (VALUES(?1)),\n"
|
||||
" digits(z,lp) AS (VALUES('1',1),('2',2),('3',3),('4',4),('5',5),\n"
|
||||
" ('6',6),('7',7),('8',8),('9',9)),\n"
|
||||
" x(s, ind) AS (\n"
|
||||
" SELECT sud, instr(sud, '.') FROM input\n"
|
||||
" UNION ALL\n"
|
||||
" SELECT\n"
|
||||
" substr(s, 1, ind-1) || z || substr(s, ind+1),\n"
|
||||
" instr( substr(s, 1, ind-1) || z || substr(s, ind+1), '.' )\n"
|
||||
" FROM x, digits AS z\n"
|
||||
" WHERE ind>0\n"
|
||||
" AND NOT EXISTS (\n"
|
||||
" SELECT 1\n"
|
||||
" FROM digits AS lp\n"
|
||||
" WHERE z.z = substr(s, ((ind-1)/9)*9 + lp, 1)\n"
|
||||
" OR z.z = substr(s, ((ind-1)%%9) + (lp-1)*9 + 1, 1)\n"
|
||||
" OR z.z = substr(s, (((ind-1)/3) %% 3) * 3\n"
|
||||
" + ((ind-1)/27) * 27 + lp\n"
|
||||
" + ((lp-1) / 3) * 6, 1)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
"SELECT s FROM x WHERE ind=0;"
|
||||
);
|
||||
sqlite3_bind_text(g.pStmt, 1, zPuz, -1, SQLITE_STATIC);
|
||||
speedtest1_run();
|
||||
speedtest1_end_test();
|
||||
|
||||
rSpacing = 5.0/g.szTest;
|
||||
speedtest1_begin_test(300, "Mandelbrot Set with spacing=%f", rSpacing);
|
||||
speedtest1_prepare(
|
||||
"WITH RECURSIVE \n"
|
||||
" xaxis(x) AS (VALUES(-2.0) UNION ALL SELECT x+?1 FROM xaxis WHERE x<1.2),\n"
|
||||
" yaxis(y) AS (VALUES(-1.0) UNION ALL SELECT y+?2 FROM yaxis WHERE y<1.0),\n"
|
||||
" m(iter, cx, cy, x, y) AS (\n"
|
||||
" SELECT 0, x, y, 0.0, 0.0 FROM xaxis, yaxis\n"
|
||||
" UNION ALL\n"
|
||||
" SELECT iter+1, cx, cy, x*x-y*y + cx, 2.0*x*y + cy FROM m \n"
|
||||
" WHERE (x*x + y*y) < 4.0 AND iter<28\n"
|
||||
" ),\n"
|
||||
" m2(iter, cx, cy) AS (\n"
|
||||
" SELECT max(iter), cx, cy FROM m GROUP BY cx, cy\n"
|
||||
" ),\n"
|
||||
" a(t) AS (\n"
|
||||
" SELECT group_concat( substr(' .+*#', 1+min(iter/7,4), 1), '') \n"
|
||||
" FROM m2 GROUP BY cy\n"
|
||||
" )\n"
|
||||
"SELECT group_concat(rtrim(t),x'0a') FROM a;"
|
||||
);
|
||||
sqlite3_bind_double(g.pStmt, 1, rSpacing*.05);
|
||||
sqlite3_bind_double(g.pStmt, 2, rSpacing);
|
||||
speedtest1_run();
|
||||
speedtest1_end_test();
|
||||
|
||||
nElem = 10000*g.szTest;
|
||||
speedtest1_begin_test(400, "EXCEPT operator on %d-element tables", nElem);
|
||||
speedtest1_prepare(
|
||||
"WITH RECURSIVE \n"
|
||||
" t1(x) AS (VALUES(2) UNION ALL SELECT x+2 FROM t1 WHERE x<%d),\n"
|
||||
" t2(y) AS (VALUES(3) UNION ALL SELECT y+3 FROM t2 WHERE y<%d)\n"
|
||||
"SELECT count(x), avg(x) FROM (\n"
|
||||
" SELECT x FROM t1 EXCEPT SELECT y FROM t2 ORDER BY 1\n"
|
||||
");",
|
||||
nElem, nElem
|
||||
);
|
||||
speedtest1_run();
|
||||
speedtest1_end_test();
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
** A testset used for debugging speedtest1 itself.
|
||||
*/
|
||||
|
@ -945,6 +1100,8 @@ int main(int argc, char **argv){
|
|||
testset_main();
|
||||
}else if( strcmp(zTSet,"debug1")==0 ){
|
||||
testset_debug1();
|
||||
}else if( strcmp(zTSet,"cte")==0 ){
|
||||
testset_cte();
|
||||
}else{
|
||||
fatal_error("unknown testset: \"%s\"\n", zTSet);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
# 2014-02-11
|
||||
#
|
||||
# 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. Specifically,
|
||||
# it tests that ticket [4c86b126f22ad548fee0125337bdc9366912d9ac].
|
||||
#
|
||||
# When SQLite is compiled using SQLITE_ENABLE_STAT3 or SQLITE_ENABLE_STAT4,
|
||||
# it gets the wrong answer...
|
||||
#
|
||||
# The problem was introduced in SQLite 3.8.1.
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
do_execsql_test tkt-4c86b126f2-1.1 {
|
||||
CREATE TABLE nodes(
|
||||
local_relpath TEXT PRIMARY KEY,
|
||||
moved_to TEXT
|
||||
);
|
||||
INSERT INTO nodes VALUES('A',NULL);
|
||||
INSERT INTO nodes VALUES('A/B',NULL);
|
||||
INSERT INTO nodes VALUES('',NULL);
|
||||
INSERT INTO nodes VALUES('A/B/C-move',NULL);
|
||||
INSERT INTO nodes VALUES('A/B/C','A/B/C-move');
|
||||
INSERT INTO nodes VALUES('A/B-move',NULL);
|
||||
INSERT INTO nodes VALUES('A/B-move/C-move',NULL);
|
||||
INSERT INTO nodes VALUES('A/B-move/C','x');
|
||||
SELECT local_relpath, moved_to
|
||||
FROM nodes
|
||||
WHERE (local_relpath = 'A/B' OR
|
||||
((local_relpath > 'A/B/') AND (local_relpath < 'A/B0')))
|
||||
AND moved_to IS NOT NULL;
|
||||
} {A/B/C A/B/C-move}
|
||||
|
||||
do_execsql_test tkt-4c86b126f2-2.1 {
|
||||
CREATE TABLE t1(x TEXT UNIQUE, y TEXT UNIQUE, z);
|
||||
INSERT INTO t1 VALUES('ghi','jkl','y');
|
||||
SELECT * FROM t1 WHERE (x='ghi' OR y='jkl') AND z IS NOT NULL;
|
||||
} {ghi jkl y}
|
||||
|
||||
|
||||
finish_test
|
|
@ -210,7 +210,7 @@ do_test where8-3.4 {
|
|||
|
||||
do_test where8-3.5 {
|
||||
execsql_status {
|
||||
SELECT a, d FROM t1, t2 WHERE (a = 2 OR a = 3) AND (d = a OR e = 'sixteen')
|
||||
SELECT a, d FROM t1, t2 WHERE (a = 2 OR a = 3) AND (d = +a OR e = 'sixteen')
|
||||
ORDER BY +a, +d;
|
||||
}
|
||||
} {2 2 2 4 3 3 3 4 0 1}
|
||||
|
@ -222,7 +222,7 @@ do_test where8-3.6 {
|
|||
execsql_status {
|
||||
SELECT a, d
|
||||
FROM t1, t2
|
||||
WHERE (a = 2 OR a = 3) AND (d = a OR e = 'sixteen')
|
||||
WHERE (a = 2 OR a = 3) AND (d = +a OR e = 'sixteen')
|
||||
ORDER BY t1.rowid
|
||||
}
|
||||
} {2 2 2 4 3 3 3 4 0 1}
|
||||
|
|
|
@ -816,5 +816,16 @@ do_execsql_test 11.3 {
|
|||
.........Noland
|
||||
.........Olivia}}
|
||||
|
||||
finish_test
|
||||
#--------------------------------------------------------------------------
|
||||
# Ticket [31a19d11b97088296ac104aaff113a9790394927] (2014-02-09)
|
||||
# Name resolution issue with compound SELECTs and Common Table Expressions
|
||||
#
|
||||
do_execsql_test 12.1 {
|
||||
WITH RECURSIVE
|
||||
t1(x) AS (VALUES(2) UNION ALL SELECT x+2 FROM t1 WHERE x<20),
|
||||
t2(y) AS (VALUES(3) UNION ALL SELECT y+3 FROM t2 WHERE y<20)
|
||||
SELECT x FROM t1 EXCEPT SELECT y FROM t2 ORDER BY 1;
|
||||
} {2 4 8 10 14 16 20}
|
||||
|
||||
|
||||
finish_test
|
||||
|
|
Loading…
Reference in New Issue