Merge in the latest trunk changes, including partial indexes, the MAX_PATH
fix in os_win.c, and the sqlite3_cancel_auto_extension() API. FossilOrigin-Name: 7e1acb390770d1bd189fac7a3a7f96106f96e3a4
This commit is contained in:
commit
7fb30bd0dd
@ -476,7 +476,7 @@ NAWK = gawk.exe
|
||||
|
||||
# Object files for the SQLite library (non-amalgamation).
|
||||
#
|
||||
LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
|
||||
LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.lo \
|
||||
backup.lo bitvec.lo btmutex.lo btree.lo build.lo \
|
||||
callback.lo complete.lo ctime.lo date.lo delete.lo \
|
||||
expr.lo fault.lo fkey.lo \
|
||||
@ -489,12 +489,12 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.lo \
|
||||
memjournal.lo \
|
||||
mutex.lo mutex_noop.lo mutex_unix.lo mutex_w32.lo \
|
||||
notify.lo opcodes.lo os.lo os_unix.lo os_win.lo \
|
||||
pager.lo parse.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
|
||||
pager.lo pcache.lo pcache1.lo pragma.lo prepare.lo printf.lo \
|
||||
random.lo resolve.lo rowset.lo rtree.lo \
|
||||
sqlite3session.lo select.lo status.lo \
|
||||
table.lo tokenize.lo trigger.lo \
|
||||
update.lo util.lo vacuum.lo \
|
||||
vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \
|
||||
vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo vdbesort.lo \
|
||||
vdbetrace.lo wal.lo walker.lo where.lo utf.lo vtab.lo
|
||||
|
||||
# Object files for the amalgamation.
|
||||
@ -1262,6 +1262,9 @@ soaktest: testfixture.exe sqlite3.exe
|
||||
fulltestonly: testfixture.exe sqlite3.exe
|
||||
.\testfixture.exe $(TOP)\test\full.test
|
||||
|
||||
queryplantest: testfixture.exe sqlite3.exe
|
||||
.\testfixture.exe $(TOP)\test\permutations.test queryplanner
|
||||
|
||||
test: testfixture.exe sqlite3.exe
|
||||
.\testfixture.exe $(TOP)\test\veryquick.test
|
||||
|
||||
|
@ -496,7 +496,7 @@ static const char *closureValueOfKey(const char *zKey, const char *zStr){
|
||||
/*
|
||||
** xConnect/xCreate method for the closure module. Arguments are:
|
||||
**
|
||||
** argv[0] -> module name ("approximate_match")
|
||||
** argv[0] -> module name ("transitive_closure")
|
||||
** argv[1] -> database name
|
||||
** argv[2] -> table name
|
||||
** argv[3...] -> arguments
|
||||
@ -907,7 +907,7 @@ static int closureBestIndex(
|
||||
}
|
||||
|
||||
/*
|
||||
** A virtual table module that implements the "approximate_match".
|
||||
** A virtual table module that implements the "transitive_closure".
|
||||
*/
|
||||
static sqlite3_module closureModule = {
|
||||
0, /* iVersion */
|
||||
|
@ -713,6 +713,7 @@ static void re_sql_func(
|
||||
const char *zPattern; /* The regular expression */
|
||||
const unsigned char *zStr;/* String being searched */
|
||||
const char *zErr; /* Compile error message */
|
||||
int setAux = 0; /* True to invoke sqlite3_set_auxdata() */
|
||||
|
||||
pRe = sqlite3_get_auxdata(context, 0);
|
||||
if( pRe==0 ){
|
||||
@ -728,12 +729,15 @@ static void re_sql_func(
|
||||
sqlite3_result_error_nomem(context);
|
||||
return;
|
||||
}
|
||||
sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free);
|
||||
setAux = 1;
|
||||
}
|
||||
zStr = (const unsigned char*)sqlite3_value_text(argv[1]);
|
||||
if( zStr!=0 ){
|
||||
sqlite3_result_int(context, re_match(pRe, zStr, -1));
|
||||
}
|
||||
if( setAux ){
|
||||
sqlite3_set_auxdata(context, 0, pRe, (void(*)(void*))re_free);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
7
main.mk
7
main.mk
@ -51,7 +51,8 @@ TCCX += -I$(TOP)/ext/session
|
||||
|
||||
# Object files for the SQLite library.
|
||||
#
|
||||
LIBOBJ+= alter.o analyze.o attach.o auth.o \
|
||||
LIBOBJ+= vdbe.o parse.o \
|
||||
alter.o analyze.o attach.o auth.o \
|
||||
backup.o bitvec.o btmutex.o btree.o build.o \
|
||||
callback.o complete.o ctime.o date.o delete.o expr.o fault.o fkey.o \
|
||||
fts3.o fts3_aux.o fts3_expr.o fts3_hash.o fts3_icu.o fts3_porter.o \
|
||||
@ -64,11 +65,11 @@ LIBOBJ+= alter.o analyze.o attach.o auth.o \
|
||||
memjournal.o \
|
||||
mutex.o mutex_noop.o mutex_unix.o mutex_w32.o \
|
||||
notify.o opcodes.o os.o os_unix.o os_win.o \
|
||||
pager.o parse.o pcache.o pcache1.o pragma.o prepare.o printf.o \
|
||||
pager.o pcache.o pcache1.o pragma.o prepare.o printf.o \
|
||||
random.o resolve.o rowset.o rtree.o select.o status.o \
|
||||
table.o tokenize.o trigger.o \
|
||||
update.o util.o vacuum.o \
|
||||
vdbe.o vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbesort.o \
|
||||
vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o vdbesort.o \
|
||||
vdbetrace.o wal.o walker.o where.o utf.o vtab.o
|
||||
|
||||
|
||||
|
88
manifest
88
manifest
@ -1,9 +1,9 @@
|
||||
C Merge\srecent\strunk\schanges\s(such\sas\sthe\squery_only\sPRAGMA,\sthe\ndefer_foreign_keys\sPRAGMA,\sand\sthe\sSQLITE_DBSTATUS_DEFERRED_FKS\sparameter\nto\ssqlite3_db_status())\sinto\sthe\ssessions\sbranch.
|
||||
D 2013-07-11T15:31:57.120
|
||||
C Merge\sin\sthe\slatest\strunk\schanges,\sincluding\spartial\sindexes,\sthe\sMAX_PATH\nfix\sin\sos_win.c,\sand\sthe\ssqlite3_cancel_auto_extension()\sAPI.
|
||||
D 2013-08-02T20:44:48.965
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in aff38bc64c582dd147f18739532198372587b0f0
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
F Makefile.msc ea294496193d9ed30137730b42ec2fc07ca5f544
|
||||
F Makefile.msc e5cc521bbc9fb09f032f7fef563542da7ac5544a
|
||||
F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315
|
||||
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
|
||||
F VERSION f135b651727f978b7191bd6fa12c7fc1e13e13ac
|
||||
@ -107,12 +107,12 @@ F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
|
||||
F ext/icu/icu.c d415ccf984defeb9df2c0e1afcfaa2f6dc05eacb
|
||||
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
F ext/misc/amatch.c eae8454cd9dcb287b2a3ec2e65a865a4ac5f0d06
|
||||
F ext/misc/closure.c 997c20ddf35f85ab399f4a02a557a9baa822ec32
|
||||
F ext/misc/closure.c 636024302cde41b2bf0c542f81c40c624cfb7012
|
||||
F ext/misc/fuzzer.c 136533c53cfce0957f0b48fa11dba27e21c5c01d
|
||||
F ext/misc/ieee754.c b0362167289170627659e84173f5d2e8fee8566e
|
||||
F ext/misc/nextchar.c 80ba262d23238efcfcb3d72d71aa4513098e26a6
|
||||
F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63
|
||||
F ext/misc/regexp.c c25c65fe775f5d9801fb8573e36ebe73f2c0c2e0
|
||||
F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc
|
||||
F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a
|
||||
F ext/misc/spellfix.c 5e1d547e9a2aed13897fa91bac924333f62fd2d9
|
||||
F ext/misc/vtshim.c 5fb6be7fe37659a8cbd1e16982d74cceacbc4543
|
||||
@ -152,7 +152,7 @@ F ext/session/test_session.c 12053e9190653164fa624427cf90d1f46ca7f179
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt f2b23a6bde8f1c6e86b957e4d94eab0add520b0d
|
||||
F main.mk f045701c66fec66208bc35d79de372340916e81e
|
||||
F main.mk 332db7908f776f4f31da6f83228b0703673eb394
|
||||
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
|
||||
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
|
||||
F mkextw.sh d2a981497b404d6498f5ff3e3b1f3816bdfcb338
|
||||
@ -170,7 +170,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc
|
||||
F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad
|
||||
F src/alter.c f8db986c03eb0bfb221523fc9bbb9d0b70de3168
|
||||
F src/analyze.c 27e541b9b5b48b41eb899b22a49ff42384899151
|
||||
F src/analyze.c a33fcb0b3a399d966951feb9f32115106b3ecc2e
|
||||
F src/attach.c 1816f5a9eea8d2010fc2b22b44f0f63eb3a62704
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c 43b348822db3e4cef48b2ae5a445fbeb6c73a165
|
||||
@ -179,13 +179,13 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c 3f7bbfd72efb1cbf6a49515c376a031767ec930a
|
||||
F src/btree.h 6fa8a3ff2483d0bb64a9f0105a8cedeac9e00cca
|
||||
F src/btreeInt.h eecc84f02375b2bb7a44abbcbbe3747dde73edb2
|
||||
F src/build.c 42239cfd95533e4aacf4d58b4724c8f858de5ced
|
||||
F src/build.c fc76e1cd014840781e175f57f6de38917986943b
|
||||
F src/callback.c d7e46f40c3cf53c43550b7da7a1d0479910b62cc
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 4262c227bc91cecc61ae37ed3a40f08069cfa267
|
||||
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
|
||||
F src/delete.c 39a770e9729b1acd2de347f8f614584841d0083e
|
||||
F src/expr.c 2b47ae9da6c9f34eff6736962ea2e102c6c4a755
|
||||
F src/delete.c 30ed4bc76a1a32c55bf17ac1528c5867aa5502c0
|
||||
F src/expr.c 2068a7c17e45f8bee6e44205b059aa30acbc71c5
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 914a6bbd987d857c41ac9d244efa6641f36faadb
|
||||
F src/func.c 5c50c1ea31fd864b0fe921fe1a8d4c55acd609ef
|
||||
@ -193,12 +193,12 @@ F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759
|
||||
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
|
||||
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c 02f8a1867088cb654eb756f98389f10441a65216
|
||||
F src/insert.c 54ec6fd4d3d08438f4d9a6b87ca422de94501d37
|
||||
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
|
||||
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
||||
F src/loadext.c c48f7f3f170e502fe0cc20748e03c6e0b5a016c2
|
||||
F src/main.c e974ea9db6214a5f7cb4c1765b49d3aba1e3409f
|
||||
F src/loadext.c 867c7b330b740c6c917af9956b13b81d0a048303
|
||||
F src/main.c e3ce4cb4a9d0634ce74b9711bd800405ae470954
|
||||
F src/malloc.c fe085aa851b666b7c375c1ff957643dc20a04bf6
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 437c7c4af964895d4650f29881df63535caaa1fa
|
||||
@ -216,25 +216,25 @@ F src/os.c b4ad71336fd96f97776f75587cd9e8218288f5be
|
||||
F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f
|
||||
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
|
||||
F src/os_unix.c 9eafa5458cf2ff684ddccff82c9bb113c7cad847
|
||||
F src/os_win.c 074cb2b9bca6a1c2bd72acf04666cdc554bfaa9b
|
||||
F src/os_win.c 1d84f2079d9b91f91a4b5dbfa5e08f1b1a0ed0ff
|
||||
F src/pager.c 5d2f7475260a8588f9c441bb309d2b7eaa7ded3b
|
||||
F src/pager.h 5cb78b8e1adfd5451e600be7719f5a99d87ac3b1
|
||||
F src/parse.y 9acfcc83ddbf0cf82f0ed9582ccf0ad6c366ff37
|
||||
F src/parse.y 599bc6338f3a6a7e1d656669a5667b9d77aea86b
|
||||
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
|
||||
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
|
||||
F src/pcache1.c d23d07716de96c7c0c2503ec5051a4384c3fb938
|
||||
F src/pragma.c 2790c5175bc3f95d2a0cf39283d144b9b012fec7
|
||||
F src/prepare.c 2306be166bbeddf454e18bf8b21dba8388d05328
|
||||
F src/pragma.c 590c75750d93ec5a1f903e4bb0dc6d2a0845bf8b
|
||||
F src/prepare.c fa6988589f39af8504a61731614cd4f6ae71554f
|
||||
F src/printf.c 41c49dac366a3a411190001a8ab495fa8887974e
|
||||
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
|
||||
F src/resolve.c 89f9003e8316ee3a172795459efc2a0274e1d5a8
|
||||
F src/resolve.c 17e670996729ac41aadf6a31f57b4e6f29b3d819
|
||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||
F src/select.c 91b62654caf8dfe292fb8882715e575d34ad3874
|
||||
F src/shell.c c8cd06e6b66250a3ea0149c4edec30de14f57b6f
|
||||
F src/sqlite.h.in 17c84f6a2296a33a16141f4cff4b176278f3d1cc
|
||||
F src/select.c 20369c82dc38eb4a77b458c8f6e353ef550580c9
|
||||
F src/shell.c 52f975eae87c8338c4dfbf4c2842d2a0971f01fd
|
||||
F src/sqlite.h.in 9dbc04c103f297d2bd26c7e323f0bdb9aaf0dc8a
|
||||
F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
|
||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||
F src/sqliteInt.h b25c57bb70c098aa05548ecde1948f4106cba472
|
||||
F src/sqliteInt.h 717511de3ce0129f9e02f98427b6a5991bbe64e4
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
@ -249,7 +249,7 @@ F src/test7.c 126b886b53f0358b92aba9b81d3fcbfbe9a93cd6
|
||||
F src/test8.c 7ee77ea522ae34aa691dfe407139dec80d4fc039
|
||||
F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
|
||||
F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8
|
||||
F src/test_autoext.c 5c95b5d435eaa09d6c0e7d90371c5ca8cd567701
|
||||
F src/test_autoext.c 32cff3d01cdd3202486e623c3f8103ed04cb57fa
|
||||
F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e
|
||||
F src/test_btree.c 5b89601dcb42a33ba8b820a6b763cc9cb48bac16
|
||||
F src/test_config.c 6b614c603cb4db1c996f1b192ca0a46ef0d152cd
|
||||
@ -281,29 +281,29 @@ F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
|
||||
F src/test_syscall.c 16dbe79fb320fadb5acd7a0a59f49e52ab2d2091
|
||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||
F src/test_thread.c 1e133a40b50e9c035b00174035b846e7eef481cb
|
||||
F src/test_vfs.c 12d9931f65acde64961523b6f420ba7cd057fbd7
|
||||
F src/test_vfs.c e72f555ef7a59080f898fcf1a233deb9eb704ea9
|
||||
F src/test_vfstrace.c 34b544e80ba7fb77be15395a609c669df2e660a2
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c e0e8fd3cb90a88451f6b6425726c84747b6b20d7
|
||||
F src/trigger.c 5c0ea9b8755e7c5e1a700f3e27ac4f8d92dd221e
|
||||
F src/update.c 19daebf6a0a67af5524913e93498d08388792128
|
||||
F src/update.c e3668141dd9701023681239265e001388f182236
|
||||
F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f
|
||||
F src/util.c f566b5138099a2df8533b190d0dcc74b7dfbe0c9
|
||||
F src/vacuum.c d9c5759f4c5a438bb43c2086f72c5d2edabc36c8
|
||||
F src/vdbe.c 4a9d00a91da42f6540203fc4e694235fd21347c9
|
||||
F src/vdbe.h 1223e2548e0970cf96f573ff6b99f804a36ad683
|
||||
F src/vdbeInt.h 11feb11eb49d8b312741011d30d91c9c50b59de0
|
||||
F src/vdbeapi.c bca51b6ea254af3a1bbfd2a58522f6d6db214334
|
||||
F src/vdbeaux.c 35846cedd64e90b83f498786775c69c2c6b6c8b1
|
||||
F src/vdbe.c 619306bc26158896392c84eb3c593e9bff35c49a
|
||||
F src/vdbe.h 7aa3ab6210a68471c8490dedfc9aa4ef5684b9a0
|
||||
F src/vdbeInt.h cc1974b94efa98ecaec6fa14a2584d7c1e82eadf
|
||||
F src/vdbeapi.c c8c433043d14b5e00e2ed6f7e44543bcc92d1594
|
||||
F src/vdbeaux.c ef37cae69147a3680f6b1927b99f79a89c8ff53c
|
||||
F src/vdbeblob.c 1268e0bcb8e21fa32520b0fc376e1bcdfaa0c642
|
||||
F src/vdbemem.c 833005f1cbbf447289f1973dba2a0c2228c7b8ab
|
||||
F src/vdbesort.c 3937e06b2a0e354500e17dc206ef4c35770a5017
|
||||
F src/vdbetrace.c e7ec40e1999ff3c6414424365d5941178966dcbc
|
||||
F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83
|
||||
F src/vtab.c 2e8b489db47e20ae36cd247932dc671c9ded0624
|
||||
F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73
|
||||
F src/where.c f5201334501cd23a39315cab479c0dcce0990701
|
||||
F src/where.c 30a9f5e4acd74e727b69a7f53a76863f9316b43b
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
|
||||
@ -315,7 +315,7 @@ F test/alter3.test 49c9d9fba2b8fcdce2dedeca97bbf1f369cc548d
|
||||
F test/alter4.test b2debc14d8cbe4c1d12ccd6a41eef88a8c1f15d5
|
||||
F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc
|
||||
F test/analyze.test f8ab7d15858b4093b06caf5e57e2a5ff7104bdae
|
||||
F test/analyze3.test 69863b446539f8849a996c2aa0b50461c9cecea4
|
||||
F test/analyze3.test 53cfd07625d110e70b92b57a6ff656ea844dfbee
|
||||
F test/analyze4.test eff2df19b8dd84529966420f29ea52edc6b56213
|
||||
F test/analyze5.test 3e57f192307be931f9ab2f6ff456f9063358ac77
|
||||
F test/analyze6.test cdbf9887d40ab41301f570fe85c6e1525dd3b1c9
|
||||
@ -375,7 +375,7 @@ F test/capi3c.test 93d24621c9ff84da9da060f30431e0453db1cdb0
|
||||
F test/capi3d.test 6d0fc0a86d73f42dd19a7d8b7761ab9bc02277d0
|
||||
F test/capi3e.test ad90088b18b0367125ff2d4b5400153fd2f99aab
|
||||
F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3
|
||||
F test/check.test 2eb93611139a7dfaed3be80067c7dc5ceb5fb287
|
||||
F test/check.test 1e9be446eb0bbd47a5f65955802e9632425096ab
|
||||
F test/close.test 340bd24cc58b16c6bc01967402755027c37eb815
|
||||
F test/closure01.test dbb28f1ea9eeaf0a53ec5bc0fed352e479def8c7
|
||||
F test/coalesce.test cee0dccb9fbd2d494b77234bccf9dc6c6786eb91
|
||||
@ -408,6 +408,7 @@ F test/corruptC.test 62a767fe64acb1975f58cc6171192839c783edbb
|
||||
F test/corruptD.test 3b09903a2e2fe07ecafe775fea94177f8a4bb34f
|
||||
F test/corruptE.test d3a3d7e864a95978195741744dda4abfd8286018
|
||||
F test/corruptF.test 1c7b6f77cf3f237fb7fbb5b61d6c921fd4c7b993
|
||||
F test/corruptG.test d18ee5169e10a76bccb7b115e551bc31087a525e
|
||||
F test/count.test 454e1ce985c94d13efeac405ce54439f49336163
|
||||
F test/coveridxscan.test cdb47d01acc4a634a34fd25abe85189e0d0f1e62
|
||||
F test/crash.test fb9dc4a02dcba30d4aa5c2c226f98b220b2b959f
|
||||
@ -569,7 +570,7 @@ F test/fts4merge4.test c19c85ca1faa7b6d536832b49c12e1867235f584
|
||||
F test/fts4noti.test aed33ba44808852dcb24bf70fa132e7bf530f057
|
||||
F test/fts4unicode.test c8ac44217bf6c17812b03eaafa6c06995ad304c2
|
||||
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
|
||||
F test/func.test b0fc34fdc36897769651975a2b0a606312753643
|
||||
F test/func.test cd25cf605c5a345d038dc7b84232204c6a901c84
|
||||
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
|
||||
F test/func3.test 001021e5b88bd02a3b365a5c5fd8f6f49d39744a
|
||||
F test/fuzz-oss1.test 4912e528ec9cf2f42134456933659d371c9e0d74
|
||||
@ -597,11 +598,12 @@ F test/incrvacuum.test d2a6ddf5e429720b5fe502766af747915ccf6c32
|
||||
F test/incrvacuum2.test 379eeb8740b0ef60c372c439ad4cbea20b34bb9b
|
||||
F test/incrvacuum3.test 75256fb1377e7c39ef2de62bfc42bbff67be295a
|
||||
F test/incrvacuum_ioerr.test 6ae2f783424e47a0033304808fe27789cf93e635
|
||||
F test/index.test b5429732b3b983fa810e3ac867d7ca85dae35097
|
||||
F test/index.test f2abacfb83d384ae36b8a919fbd94b1319333e55
|
||||
F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
|
||||
F test/index3.test 423a25c789fc8cc51aaf2a4370bbdde2d9e9eed7
|
||||
F test/index4.test 2983216eb8c86ee62d9ed7cb206b5cc3331c0026
|
||||
F test/index5.test fc07c14193c0430814e7a08b5da46888ee795c33
|
||||
F test/index6.test 0005b3093012c6d0f20cc54d9057210221216143
|
||||
F test/indexedby.test 0e959308707c808515c3a51363f7a9835027108c
|
||||
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
|
||||
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
|
||||
@ -640,7 +642,7 @@ F test/like.test 935fb4f608e3ea126891496a6e99b9468372bf5c
|
||||
F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da
|
||||
F test/limit.test cc0ab63385239b63c72452b0e93700bf5e8f0b99
|
||||
F test/loadext.test 92e6dfefd1229c3ef4aaabd87419efd8fa57a7a5
|
||||
F test/loadext2.test 0bcaeb4d81cd5b6e883fdfea3c1bdbe1f173cbca
|
||||
F test/loadext2.test 0408380b57adca04004247179837a18e866a74f7
|
||||
F test/lock.test 87af515b0c4cf928576d0f89946d67d7c265dfb4
|
||||
F test/lock2.test 5242d8ac4e2d59c403aebff606af449b455aceff
|
||||
F test/lock3.test f271375930711ae044080f4fe6d6eda930870d00
|
||||
@ -1051,13 +1053,13 @@ F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417
|
||||
F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a
|
||||
F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e
|
||||
F test/where.test da54153a4c1571ea1b95659e5bec8119edf786aa
|
||||
F test/where2.test d712de0ea9a2c3de7b34b0b1e75172556fef5b24
|
||||
F test/where2.test b1830f762f837153a4c9743adaab90a5761f73e7
|
||||
F test/where3.test a0682ba3dc8c8f46ffcc95a3d9f58c4327fc129f
|
||||
F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
|
||||
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
||||
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
|
||||
F test/where7.test 5a4b0abc207d71da4deecd734ad8579e8dd40aa8
|
||||
F test/where8.test f6b9559723564a042927ee0f22003ac9bed71b21
|
||||
F test/where8.test 6f95896633cf2d307b5263145b942b7d33e837c6
|
||||
F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739
|
||||
F test/where9.test 9a7fda4a4512abc26a855e8b2b6572b200f6019b
|
||||
F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a
|
||||
@ -1101,7 +1103,7 @@ F tool/showjournal.c b62cecaab86a4053d944c276bb5232e4d17ece02
|
||||
F tool/showwal.c 3f7f7da5ec0cba51b1449a75f700493377da57b5
|
||||
F tool/soak1.tcl 8d407956e1a45b485a8e072470a3e629a27037fe
|
||||
F tool/space_used.tcl f714c41a59e326b8b9042f415b628b561bafa06b
|
||||
F tool/spaceanal.tcl 76f583a246a0b027f423252339e711f13198932e
|
||||
F tool/spaceanal.tcl f87fc8e459e3e42255b52987fe0dda3f8a8c513d
|
||||
F tool/speedtest.tcl 06c76698485ccf597b9e7dbb1ac70706eb873355
|
||||
F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
|
||||
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
@ -1117,7 +1119,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||
F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae
|
||||
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
|
||||
P d39e65fe702a2e11477f2d996f77404f45763368 6557c407983b067449deb76bc4c5248de64e07dc
|
||||
R a7fbb947af42ffbd616de92443f86cbe
|
||||
P 8dfc0b78c38e519b64a796243ff7c0aff688ff36 c5c0a8ab6c222185d5f9d4321e64d9f93cd36b7d
|
||||
R 6bd6d033a187336743a83e4c58485278
|
||||
U drh
|
||||
Z a9673e579f51d102bcb297135146bef6
|
||||
Z 807175c2ca92264cb8fa0f2650b5caad
|
||||
|
@ -1 +1 @@
|
||||
8dfc0b78c38e519b64a796243ff7c0aff688ff36
|
||||
7e1acb390770d1bd189fac7a3a7f96106f96e3a4
|
@ -441,6 +441,7 @@ static void analyzeOneTable(
|
||||
int endOfLoop; /* The end of the loop */
|
||||
int jZeroRows = -1; /* Jump from here if number of rows is zero */
|
||||
int iDb; /* Index of database containing pTab */
|
||||
u8 needTableCnt = 1; /* True to count the table */
|
||||
int regTabname = iMem++; /* Register containing table name */
|
||||
int regIdxname = iMem++; /* Register containing index name */
|
||||
int regStat1 = iMem++; /* The stat column of sqlite_stat1 */
|
||||
@ -500,6 +501,7 @@ static void analyzeOneTable(
|
||||
int *aChngAddr; /* Array of jump instruction addresses */
|
||||
|
||||
if( pOnlyIdx && pOnlyIdx!=pIdx ) continue;
|
||||
if( pIdx->pPartIdxWhere==0 ) needTableCnt = 0;
|
||||
VdbeNoopComment((v, "Begin analysis of %s", pIdx->zName));
|
||||
nCol = pIdx->nColumn;
|
||||
aChngAddr = sqlite3DbMallocRaw(db, sizeof(int)*nCol);
|
||||
@ -659,9 +661,7 @@ static void analyzeOneTable(
|
||||
** is never possible.
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_SCopy, iMem, regStat1);
|
||||
if( jZeroRows<0 ){
|
||||
jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, iMem);
|
||||
}
|
||||
jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, iMem);
|
||||
for(i=0; i<nCol; i++){
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, regTemp, 0, " ", 0);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regStat1, regStat1);
|
||||
@ -671,32 +671,31 @@ static void analyzeOneTable(
|
||||
sqlite3VdbeAddOp1(v, OP_ToInt, regTemp);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regStat1, regStat1);
|
||||
}
|
||||
if( pIdx->pPartIdxWhere!=0 ) sqlite3VdbeJumpHere(v, jZeroRows);
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regNewRowid);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
||||
if( pIdx->pPartIdxWhere==0 ) sqlite3VdbeJumpHere(v, jZeroRows);
|
||||
}
|
||||
|
||||
/* If the table has no indices, create a single sqlite_stat1 entry
|
||||
** containing NULL as the index name and the row count as the content.
|
||||
/* Create a single sqlite_stat1 entry containing NULL as the index
|
||||
** name and the row count as the content.
|
||||
*/
|
||||
if( pTab->pIndex==0 ){
|
||||
if( pOnlyIdx==0 && needTableCnt ){
|
||||
sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pTab->tnum, iDb);
|
||||
VdbeComment((v, "%s", pTab->zName));
|
||||
sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat1);
|
||||
sqlite3VdbeAddOp1(v, OP_Close, iIdxCur);
|
||||
jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, regStat1);
|
||||
}else{
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname);
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regNewRowid);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
||||
sqlite3VdbeJumpHere(v, jZeroRows);
|
||||
jZeroRows = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname);
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regNewRowid);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
|
||||
if( pParse->nMem<regRec ) pParse->nMem = regRec;
|
||||
sqlite3VdbeJumpHere(v, jZeroRows);
|
||||
}
|
||||
|
||||
|
||||
@ -879,8 +878,10 @@ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){
|
||||
v = v*10 + c - '0';
|
||||
z++;
|
||||
}
|
||||
if( i==0 ) pTable->nRowEst = v;
|
||||
if( pIndex==0 ) break;
|
||||
if( i==0 && (pIndex==0 || pIndex->pPartIdxWhere==0) ){
|
||||
if( v>0 ) pTable->nRowEst = v;
|
||||
if( pIndex==0 ) break;
|
||||
}
|
||||
pIndex->aiRowEst[i] = v;
|
||||
if( *z==' ' ) z++;
|
||||
if( strcmp(z, "unordered")==0 ){
|
||||
|
59
src/build.c
59
src/build.c
@ -382,6 +382,7 @@ static void freeIndex(sqlite3 *db, Index *p){
|
||||
#ifndef SQLITE_OMIT_ANALYZE
|
||||
sqlite3DeleteIndexSamples(db, p);
|
||||
#endif
|
||||
sqlite3ExprDelete(db, p->pPartIdxWhere);
|
||||
sqlite3DbFree(db, p->zColAff);
|
||||
sqlite3DbFree(db, p);
|
||||
}
|
||||
@ -1225,7 +1226,8 @@ void sqlite3AddPrimaryKey(
|
||||
#endif
|
||||
}else{
|
||||
Index *p;
|
||||
p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0);
|
||||
p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0,
|
||||
0, sortOrder, 0);
|
||||
if( p ){
|
||||
p->autoIndex = 2;
|
||||
}
|
||||
@ -1520,26 +1522,7 @@ void sqlite3EndTable(
|
||||
/* Resolve names in all CHECK constraint expressions.
|
||||
*/
|
||||
if( p->pCheck ){
|
||||
SrcList sSrc; /* Fake SrcList for pParse->pNewTable */
|
||||
NameContext sNC; /* Name context for pParse->pNewTable */
|
||||
ExprList *pList; /* List of all CHECK constraints */
|
||||
int i; /* Loop counter */
|
||||
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
memset(&sSrc, 0, sizeof(sSrc));
|
||||
sSrc.nSrc = 1;
|
||||
sSrc.a[0].zName = p->zName;
|
||||
sSrc.a[0].pTab = p;
|
||||
sSrc.a[0].iCursor = -1;
|
||||
sNC.pParse = pParse;
|
||||
sNC.pSrcList = &sSrc;
|
||||
sNC.ncFlags = NC_IsCheck;
|
||||
pList = p->pCheck;
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
if( sqlite3ResolveExprNames(&sNC, pList->a[i].pExpr) ){
|
||||
return;
|
||||
}
|
||||
}
|
||||
sqlite3ResolveSelfReference(pParse, p, NC_IsCheck, 0, p->pCheck);
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_CHECK) */
|
||||
|
||||
@ -2391,6 +2374,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
int addr1; /* Address of top of loop */
|
||||
int addr2; /* Address to jump to for next iteration */
|
||||
int tnum; /* Root page of index */
|
||||
int iPartIdxLabel; /* Jump to this label to skip a row */
|
||||
Vdbe *v; /* Generate code into this virtual machine */
|
||||
KeyInfo *pKey; /* KeyInfo for index */
|
||||
int regRecord; /* Register holding assemblied index record */
|
||||
@ -2430,8 +2414,9 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0);
|
||||
regRecord = sqlite3GetTempReg(pParse);
|
||||
|
||||
sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1);
|
||||
sqlite3GenerateIndexKey(pParse, pIndex, iTab, regRecord, 1, &iPartIdxLabel);
|
||||
sqlite3VdbeAddOp2(v, OP_SorterInsert, iSorter, regRecord);
|
||||
sqlite3VdbeResolveLabel(v, iPartIdxLabel);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iTab, addr1+1);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0);
|
||||
@ -2482,7 +2467,7 @@ Index *sqlite3CreateIndex(
|
||||
ExprList *pList, /* A list of columns to be indexed */
|
||||
int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
|
||||
Token *pStart, /* The CREATE token that begins this statement */
|
||||
Token *pEnd, /* The ")" that closes the CREATE INDEX statement */
|
||||
Expr *pPIWhere, /* WHERE clause for partial indices */
|
||||
int sortOrder, /* Sort order of primary key when pList==NULL */
|
||||
int ifNotExist /* Omit error if index already exists */
|
||||
){
|
||||
@ -2504,7 +2489,6 @@ Index *sqlite3CreateIndex(
|
||||
int nExtra = 0;
|
||||
char *zExtra;
|
||||
|
||||
assert( pStart==0 || pEnd!=0 ); /* pEnd must be non-NULL if pStart is */
|
||||
assert( pParse->nErr==0 ); /* Never called with prior errors */
|
||||
if( db->mallocFailed || IN_DECLARE_VTAB ){
|
||||
goto exit_create_index;
|
||||
@ -2550,7 +2534,12 @@ Index *sqlite3CreateIndex(
|
||||
pTab = sqlite3LocateTableItem(pParse, 0, &pTblName->a[0]);
|
||||
assert( db->mallocFailed==0 || pTab==0 );
|
||||
if( pTab==0 ) goto exit_create_index;
|
||||
assert( db->aDb[iDb].pSchema==pTab->pSchema );
|
||||
if( iDb==1 && db->aDb[iDb].pSchema!=pTab->pSchema ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"cannot create a TEMP index on non-TEMP table \"%s\"",
|
||||
pTab->zName);
|
||||
goto exit_create_index;
|
||||
}
|
||||
}else{
|
||||
assert( pName==0 );
|
||||
assert( pStart==0 );
|
||||
@ -2699,6 +2688,11 @@ Index *sqlite3CreateIndex(
|
||||
pIndex->uniqNotNull = onError==OE_Abort;
|
||||
pIndex->autoIndex = (u8)(pName==0);
|
||||
pIndex->pSchema = db->aDb[iDb].pSchema;
|
||||
if( pPIWhere ){
|
||||
sqlite3ResolveSelfReference(pParse, pTab, NC_PartIdx, pPIWhere, 0);
|
||||
pIndex->pPartIdxWhere = pPIWhere;
|
||||
pPIWhere = 0;
|
||||
}
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
|
||||
/* Check to see if we should honor DESC requests on index columns
|
||||
@ -2854,7 +2848,7 @@ Index *sqlite3CreateIndex(
|
||||
** has just been created, it contains no data and the index initialization
|
||||
** step can be skipped.
|
||||
*/
|
||||
else{ /* if( db->init.busy==0 ) */
|
||||
else if( pParse->nErr==0 ){
|
||||
Vdbe *v;
|
||||
char *zStmt;
|
||||
int iMem = ++pParse->nMem;
|
||||
@ -2872,12 +2866,11 @@ Index *sqlite3CreateIndex(
|
||||
** the zStmt variable
|
||||
*/
|
||||
if( pStart ){
|
||||
assert( pEnd!=0 );
|
||||
int n = (pParse->sLastToken.z - pName->z) + pParse->sLastToken.n;
|
||||
if( pName->z[n-1]==';' ) n--;
|
||||
/* A named index with an explicit CREATE INDEX statement */
|
||||
zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s",
|
||||
onError==OE_None ? "" : " UNIQUE",
|
||||
(int)(pEnd->z - pName->z) + 1,
|
||||
pName->z);
|
||||
onError==OE_None ? "" : " UNIQUE", n, pName->z);
|
||||
}else{
|
||||
/* An automatic index created by a PRIMARY KEY or UNIQUE constraint */
|
||||
/* zStmt = sqlite3MPrintf(""); */
|
||||
@ -2933,10 +2926,8 @@ Index *sqlite3CreateIndex(
|
||||
|
||||
/* Clean up before exiting */
|
||||
exit_create_index:
|
||||
if( pIndex ){
|
||||
sqlite3DbFree(db, pIndex->zColAff);
|
||||
sqlite3DbFree(db, pIndex);
|
||||
}
|
||||
if( pIndex ) freeIndex(db, pIndex);
|
||||
sqlite3ExprDelete(db, pPIWhere);
|
||||
sqlite3ExprListDelete(db, pList);
|
||||
sqlite3SrcListDelete(db, pTblName);
|
||||
sqlite3DbFree(db, zName);
|
||||
|
35
src/delete.c
35
src/delete.c
@ -603,11 +603,14 @@ void sqlite3GenerateRowIndexDelete(
|
||||
int i;
|
||||
Index *pIdx;
|
||||
int r1;
|
||||
int iPartIdxLabel;
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
|
||||
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
|
||||
if( aRegIdx!=0 && aRegIdx[i-1]==0 ) continue;
|
||||
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iCur, 0, 0);
|
||||
sqlite3VdbeAddOp3(pParse->pVdbe, OP_IdxDelete, iCur+i, r1,pIdx->nColumn+1);
|
||||
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iCur, 0, 0, &iPartIdxLabel);
|
||||
sqlite3VdbeAddOp3(v, OP_IdxDelete, iCur+i, r1, pIdx->nColumn+1);
|
||||
sqlite3VdbeResolveLabel(v, iPartIdxLabel);
|
||||
}
|
||||
}
|
||||
|
||||
@ -621,13 +624,21 @@ void sqlite3GenerateRowIndexDelete(
|
||||
** registers that holds the elements of the index key. The
|
||||
** block of registers has already been deallocated by the time
|
||||
** this routine returns.
|
||||
**
|
||||
** If *piPartIdxLabel is not NULL, fill it in with a label and jump
|
||||
** to that label if pIdx is a partial index that should be skipped.
|
||||
** A partial index should be skipped if its WHERE clause evaluates
|
||||
** to false or null. If pIdx is not a partial index, *piPartIdxLabel
|
||||
** will be set to zero which is an empty label that is ignored by
|
||||
** sqlite3VdbeResolveLabel().
|
||||
*/
|
||||
int sqlite3GenerateIndexKey(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Index *pIdx, /* The index for which to generate a key */
|
||||
int iCur, /* Cursor number for the pIdx->pTable table */
|
||||
int regOut, /* Write the new index key to this register */
|
||||
int doMakeRec /* Run the OP_MakeRecord instruction if true */
|
||||
Parse *pParse, /* Parsing context */
|
||||
Index *pIdx, /* The index for which to generate a key */
|
||||
int iCur, /* Cursor number for the pIdx->pTable table */
|
||||
int regOut, /* Write the new index key to this register */
|
||||
int doMakeRec, /* Run the OP_MakeRecord instruction if true */
|
||||
int *piPartIdxLabel /* OUT: Jump to this label to skip partial index */
|
||||
){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
int j;
|
||||
@ -635,6 +646,16 @@ int sqlite3GenerateIndexKey(
|
||||
int regBase;
|
||||
int nCol;
|
||||
|
||||
if( piPartIdxLabel ){
|
||||
if( pIdx->pPartIdxWhere ){
|
||||
*piPartIdxLabel = sqlite3VdbeMakeLabel(v);
|
||||
pParse->iPartIdxTab = iCur;
|
||||
sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel,
|
||||
SQLITE_JUMPIFNULL);
|
||||
}else{
|
||||
*piPartIdxLabel = 0;
|
||||
}
|
||||
}
|
||||
nCol = pIdx->nColumn;
|
||||
regBase = sqlite3GetTempRange(pParse, nCol+1);
|
||||
sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regBase+nCol);
|
||||
|
94
src/expr.c
94
src/expr.c
@ -2362,15 +2362,20 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
/* Otherwise, fall thru into the TK_COLUMN case */
|
||||
}
|
||||
case TK_COLUMN: {
|
||||
if( pExpr->iTable<0 ){
|
||||
/* This only happens when coding check constraints */
|
||||
assert( pParse->ckBase>0 );
|
||||
inReg = pExpr->iColumn + pParse->ckBase;
|
||||
}else{
|
||||
inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
|
||||
pExpr->iColumn, pExpr->iTable, target,
|
||||
pExpr->op2);
|
||||
int iTab = pExpr->iTable;
|
||||
if( iTab<0 ){
|
||||
if( pParse->ckBase>0 ){
|
||||
/* Generating CHECK constraints or inserting into partial index */
|
||||
inReg = pExpr->iColumn + pParse->ckBase;
|
||||
break;
|
||||
}else{
|
||||
/* Deleting from a partial index */
|
||||
iTab = pParse->iPartIdxTab;
|
||||
}
|
||||
}
|
||||
inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
|
||||
pExpr->iColumn, iTab, target,
|
||||
pExpr->op2);
|
||||
break;
|
||||
}
|
||||
case TK_INTEGER: {
|
||||
@ -3793,6 +3798,12 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
** by a COLLATE operator at the top level. Return 2 if there are differences
|
||||
** other than the top-level COLLATE operator.
|
||||
**
|
||||
** If any subelement of pB has Expr.iTable==(-1) then it is allowed
|
||||
** to compare equal to an equivalent element in pA with Expr.iTable==iTab.
|
||||
**
|
||||
** The pA side might be using TK_REGISTER. If that is the case and pB is
|
||||
** not using TK_REGISTER but is otherwise equivalent, then still return 0.
|
||||
**
|
||||
** Sometimes this routine will return 2 even if the two expressions
|
||||
** really are equivalent. If we cannot prove that the expressions are
|
||||
** identical, we return 2 just to be safe. So if this routine
|
||||
@ -3803,7 +3814,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||
** just might result in some slightly slower code. But returning
|
||||
** an incorrect 0 or 1 could lead to a malfunction.
|
||||
*/
|
||||
int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
||||
int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){
|
||||
if( pA==0||pB==0 ){
|
||||
return pB==pA ? 0 : 2;
|
||||
}
|
||||
@ -3813,19 +3824,22 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
||||
return 2;
|
||||
}
|
||||
if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2;
|
||||
if( pA->op!=pB->op ){
|
||||
if( pA->op==TK_COLLATE && sqlite3ExprCompare(pA->pLeft, pB)<2 ){
|
||||
if( pA->op!=pB->op && (pA->op!=TK_REGISTER || pA->op2!=pB->op) ){
|
||||
if( pA->op==TK_COLLATE && sqlite3ExprCompare(pA->pLeft, pB, iTab)<2 ){
|
||||
return 1;
|
||||
}
|
||||
if( pB->op==TK_COLLATE && sqlite3ExprCompare(pA, pB->pLeft)<2 ){
|
||||
if( pB->op==TK_COLLATE && sqlite3ExprCompare(pA, pB->pLeft, iTab)<2 ){
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
if( sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 2;
|
||||
if( sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 2;
|
||||
if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList) ) return 2;
|
||||
if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 2;
|
||||
if( sqlite3ExprCompare(pA->pLeft, pB->pLeft, iTab) ) return 2;
|
||||
if( sqlite3ExprCompare(pA->pRight, pB->pRight, iTab) ) return 2;
|
||||
if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2;
|
||||
if( pA->iColumn!=pB->iColumn ) return 2;
|
||||
if( pA->iTable!=pB->iTable
|
||||
&& pA->op!=TK_REGISTER
|
||||
&& (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2;
|
||||
if( ExprHasProperty(pA, EP_IntValue) ){
|
||||
if( !ExprHasProperty(pB, EP_IntValue) || pA->u.iValue!=pB->u.iValue ){
|
||||
return 2;
|
||||
@ -3843,6 +3857,9 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
||||
** Compare two ExprList objects. Return 0 if they are identical and
|
||||
** non-zero if they differ in any way.
|
||||
**
|
||||
** If any subelement of pB has Expr.iTable==(-1) then it is allowed
|
||||
** to compare equal to an equivalent element in pA with Expr.iTable==iTab.
|
||||
**
|
||||
** This routine might return non-zero for equivalent ExprLists. The
|
||||
** only consequence will be disabled optimizations. But this routine
|
||||
** must never return 0 if the two ExprList objects are different, or
|
||||
@ -3851,7 +3868,7 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
||||
** Two NULL pointers are considered to be the same. But a NULL pointer
|
||||
** always differs from a non-NULL pointer.
|
||||
*/
|
||||
int sqlite3ExprListCompare(ExprList *pA, ExprList *pB){
|
||||
int sqlite3ExprListCompare(ExprList *pA, ExprList *pB, int iTab){
|
||||
int i;
|
||||
if( pA==0 && pB==0 ) return 0;
|
||||
if( pA==0 || pB==0 ) return 1;
|
||||
@ -3860,7 +3877,46 @@ int sqlite3ExprListCompare(ExprList *pA, ExprList *pB){
|
||||
Expr *pExprA = pA->a[i].pExpr;
|
||||
Expr *pExprB = pB->a[i].pExpr;
|
||||
if( pA->a[i].sortOrder!=pB->a[i].sortOrder ) return 1;
|
||||
if( sqlite3ExprCompare(pExprA, pExprB) ) return 1;
|
||||
if( sqlite3ExprCompare(pExprA, pExprB, iTab) ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return true if we can prove the pE2 will always be true if pE1 is
|
||||
** true. Return false if we cannot complete the proof or if pE2 might
|
||||
** be false. Examples:
|
||||
**
|
||||
** pE1: x==5 pE2: x==5 Result: true
|
||||
** pE1: x>0 pE2: x==5 Result: false
|
||||
** pE1: x=21 pE2: x=21 OR y=43 Result: true
|
||||
** pE1: x!=123 pE2: x IS NOT NULL Result: true
|
||||
** pE1: x!=?1 pE2: x IS NOT NULL Result: true
|
||||
** pE1: x IS NULL pE2: x IS NOT NULL Result: false
|
||||
** pE1: x IS ?2 pE2: x IS NOT NULL Reuslt: false
|
||||
**
|
||||
** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has
|
||||
** Expr.iTable<0 then assume a table number given by iTab.
|
||||
**
|
||||
** When in doubt, return false. Returning true might give a performance
|
||||
** improvement. Returning false might cause a performance reduction, but
|
||||
** it will always give the correct answer and is hence always safe.
|
||||
*/
|
||||
int sqlite3ExprImpliesExpr(Expr *pE1, Expr *pE2, int iTab){
|
||||
if( sqlite3ExprCompare(pE1, pE2, iTab)==0 ){
|
||||
return 1;
|
||||
}
|
||||
if( pE2->op==TK_OR
|
||||
&& (sqlite3ExprImpliesExpr(pE1, pE2->pLeft, iTab)
|
||||
|| sqlite3ExprImpliesExpr(pE1, pE2->pRight, iTab) )
|
||||
){
|
||||
return 1;
|
||||
}
|
||||
if( pE2->op==TK_NOTNULL
|
||||
&& sqlite3ExprCompare(pE1->pLeft, pE2->pLeft, iTab)==0
|
||||
&& (pE1->op!=TK_ISNULL && pE1->op!=TK_IS)
|
||||
){
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -4045,7 +4101,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
|
||||
*/
|
||||
struct AggInfo_func *pItem = pAggInfo->aFunc;
|
||||
for(i=0; i<pAggInfo->nFunc; i++, pItem++){
|
||||
if( sqlite3ExprCompare(pItem->pExpr, pExpr)==0 ){
|
||||
if( sqlite3ExprCompare(pItem->pExpr, pExpr, -1)==0 ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
25
src/insert.c
25
src/insert.c
@ -1389,9 +1389,19 @@ void sqlite3GenerateConstraintChecks(
|
||||
for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){
|
||||
int regIdx;
|
||||
int regR;
|
||||
int addrSkipRow = 0;
|
||||
|
||||
if( aRegIdx[iCur]==0 ) continue; /* Skip unused indices */
|
||||
|
||||
if( pIdx->pPartIdxWhere ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[iCur]);
|
||||
addrSkipRow = sqlite3VdbeMakeLabel(v);
|
||||
pParse->ckBase = regData;
|
||||
sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrSkipRow,
|
||||
SQLITE_JUMPIFNULL);
|
||||
pParse->ckBase = 0;
|
||||
}
|
||||
|
||||
/* Create a key for accessing the index entry */
|
||||
regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn+1);
|
||||
for(i=0; i<pIdx->nColumn; i++){
|
||||
@ -1411,6 +1421,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
onError = pIdx->onError;
|
||||
if( onError==OE_None ){
|
||||
sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1);
|
||||
sqlite3VdbeResolveLabel(v, addrSkipRow);
|
||||
continue; /* pIdx is not a UNIQUE index */
|
||||
}
|
||||
if( overrideError!=OE_Default ){
|
||||
@ -1480,6 +1491,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
}
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, j3);
|
||||
sqlite3VdbeResolveLabel(v, addrSkipRow);
|
||||
sqlite3ReleaseTempReg(pParse, regR);
|
||||
}
|
||||
|
||||
@ -1509,7 +1521,6 @@ void sqlite3CompleteInsertion(
|
||||
){
|
||||
int i;
|
||||
Vdbe *v;
|
||||
int nIdx;
|
||||
Index *pIdx;
|
||||
u8 pik_flags;
|
||||
int regData;
|
||||
@ -1518,9 +1529,11 @@ void sqlite3CompleteInsertion(
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
assert( v!=0 );
|
||||
assert( pTab->pSelect==0 ); /* This table is not a VIEW */
|
||||
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){}
|
||||
for(i=nIdx-1; i>=0; i--){
|
||||
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
|
||||
if( aRegIdx[i]==0 ) continue;
|
||||
if( pIdx->pPartIdxWhere ){
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, baseCur+i+1, aRegIdx[i]);
|
||||
if( useSeekResult ){
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
||||
@ -1622,6 +1635,7 @@ static int xferCompatibleCollation(const char *z1, const char *z2){
|
||||
** * The same DESC and ASC markings occurs on all columns
|
||||
** * The same onError processing (OE_Abort, OE_Ignore, etc)
|
||||
** * The same collating sequence on each column
|
||||
** * The index has the exact same WHERE clause
|
||||
*/
|
||||
static int xferCompatibleIndex(Index *pDest, Index *pSrc){
|
||||
int i;
|
||||
@ -1644,6 +1658,9 @@ static int xferCompatibleIndex(Index *pDest, Index *pSrc){
|
||||
return 0; /* Different collating sequences */
|
||||
}
|
||||
}
|
||||
if( sqlite3ExprCompare(pSrc->pPartIdxWhere, pDest->pPartIdxWhere, -1) ){
|
||||
return 0; /* Different WHERE clauses */
|
||||
}
|
||||
|
||||
/* If no test above fails then the indices must be compatible */
|
||||
return 1;
|
||||
@ -1799,7 +1816,7 @@ static int xferOptimization(
|
||||
}
|
||||
}
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck, pDest->pCheck) ){
|
||||
if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){
|
||||
return 0; /* Tables have different CHECK constraints. Ticket #2252 */
|
||||
}
|
||||
#endif
|
||||
|
@ -668,6 +668,35 @@ int sqlite3_auto_extension(void (*xInit)(void)){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Cancel a prior call to sqlite3_auto_extension. Remove xInit from the
|
||||
** set of routines that is invoked for each new database connection, if it
|
||||
** is currently on the list. If xInit is not on the list, then this
|
||||
** routine is a no-op.
|
||||
**
|
||||
** Return 1 if xInit was found on the list and removed. Return 0 if xInit
|
||||
** was not on the list.
|
||||
*/
|
||||
int sqlite3_cancel_auto_extension(void (*xInit)(void)){
|
||||
#if SQLITE_THREADSAFE
|
||||
sqlite3_mutex *mutex = sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER);
|
||||
#endif
|
||||
int i;
|
||||
int n = 0;
|
||||
wsdAutoextInit;
|
||||
sqlite3_mutex_enter(mutex);
|
||||
for(i=wsdAutoext.nExt-1; i>=0; i--){
|
||||
if( wsdAutoext.aExt[i]==xInit ){
|
||||
wsdAutoext.nExt--;
|
||||
wsdAutoext.aExt[i] = wsdAutoext.aExt[wsdAutoext.nExt];
|
||||
n++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sqlite3_mutex_leave(mutex);
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
** Reset the automatic extension loading mechanism.
|
||||
*/
|
||||
|
@ -1100,6 +1100,7 @@ const char *sqlite3ErrName(int rc){
|
||||
case SQLITE_IOERR_SEEK: zName = "SQLITE_IOERR_SEEK"; break;
|
||||
case SQLITE_IOERR_DELETE_NOENT: zName = "SQLITE_IOERR_DELETE_NOENT";break;
|
||||
case SQLITE_IOERR_MMAP: zName = "SQLITE_IOERR_MMAP"; break;
|
||||
case SQLITE_IOERR_GETTEMPPATH: zName = "SQLITE_IOERR_GETTEMPPATH"; break;
|
||||
case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
|
||||
case SQLITE_CORRUPT_VTAB: zName = "SQLITE_CORRUPT_VTAB"; break;
|
||||
case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break;
|
||||
@ -2476,7 +2477,7 @@ static int openDatabase(
|
||||
db->szMmap = sqlite3GlobalConfig.szMmap;
|
||||
db->nextPagesize = 0;
|
||||
db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger
|
||||
#if !defined(SQLITE_DEAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX
|
||||
#if !defined(SQLITE_DEFAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX
|
||||
| SQLITE_AutoIndex
|
||||
#endif
|
||||
#if SQLITE_DEFAULT_FILE_FORMAT<4
|
||||
|
86
src/os_win.c
86
src/os_win.c
@ -17,6 +17,7 @@
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
# include <sys/cygwin.h>
|
||||
# include <errno.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -230,6 +231,7 @@ struct winFile {
|
||||
# define SQLITE_WIN32_HEAP_FLAGS (0)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** The winMemData structure stores information required by the Win32-specific
|
||||
** sqlite3_mem_methods implementation.
|
||||
@ -3694,10 +3696,10 @@ static int winMapfile(winFile *pFd, sqlite3_int64 nByte){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
assert( (nMap % winSysInfo.dwPageSize)==0 );
|
||||
#if SQLITE_OS_WINRT
|
||||
pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, nMap);
|
||||
#else
|
||||
assert( sizeof(SIZE_T)==sizeof(sqlite3_int64) || nMap<=0xffffffff );
|
||||
#if SQLITE_OS_WINRT
|
||||
pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, (SIZE_T)nMap);
|
||||
#else
|
||||
pNew = osMapViewOfFile(pFd->hMap, flags, 0, 0, (SIZE_T)nMap);
|
||||
#endif
|
||||
if( pNew==NULL ){
|
||||
@ -3866,6 +3868,15 @@ static void *convertUtf8Filename(const char *zFilename){
|
||||
return zConverted;
|
||||
}
|
||||
|
||||
/*
|
||||
** Maximum pathname length (in bytes) for windows. The MAX_PATH macro is
|
||||
** in characters, so we allocate 3 bytes per character assuming worst-case
|
||||
** 3-bytes-per-character UTF8.
|
||||
*/
|
||||
#ifndef SQLITE_WIN32_MAX_PATH
|
||||
# define SQLITE_WIN32_MAX_PATH (MAX_PATH*3)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Create a temporary file name in zBuf. zBuf must be big enough to
|
||||
** hold at pVfs->mxPathname characters.
|
||||
@ -3877,7 +3888,7 @@ static int getTempname(int nBuf, char *zBuf){
|
||||
"0123456789";
|
||||
size_t i, j;
|
||||
int nTempPath;
|
||||
char zTempPath[MAX_PATH+2];
|
||||
char zTempPath[SQLITE_WIN32_MAX_PATH+2];
|
||||
|
||||
/* It's odd to simulate an io-error here, but really this is just
|
||||
** using the io-error infrastructure to test that SQLite handles this
|
||||
@ -3885,19 +3896,21 @@ static int getTempname(int nBuf, char *zBuf){
|
||||
*/
|
||||
SimulateIOError( return SQLITE_IOERR );
|
||||
|
||||
memset(zTempPath, 0, MAX_PATH+2);
|
||||
|
||||
if( sqlite3_temp_directory ){
|
||||
sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", sqlite3_temp_directory);
|
||||
sqlite3_snprintf(SQLITE_WIN32_MAX_PATH-30, zTempPath, "%s",
|
||||
sqlite3_temp_directory);
|
||||
}
|
||||
#if !SQLITE_OS_WINRT
|
||||
else if( isNT() ){
|
||||
char *zMulti;
|
||||
WCHAR zWidePath[MAX_PATH];
|
||||
osGetTempPathW(MAX_PATH-30, zWidePath);
|
||||
if( osGetTempPathW(MAX_PATH-30, zWidePath)==0 ){
|
||||
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_GETTEMPPATH\n"));
|
||||
return SQLITE_IOERR_GETTEMPPATH;
|
||||
}
|
||||
zMulti = unicodeToUtf8(zWidePath);
|
||||
if( zMulti ){
|
||||
sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zMulti);
|
||||
sqlite3_snprintf(SQLITE_WIN32_MAX_PATH-30, zTempPath, "%s", zMulti);
|
||||
sqlite3_free(zMulti);
|
||||
}else{
|
||||
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
|
||||
@ -3907,19 +3920,38 @@ static int getTempname(int nBuf, char *zBuf){
|
||||
#ifdef SQLITE_WIN32_HAS_ANSI
|
||||
else{
|
||||
char *zUtf8;
|
||||
char zMbcsPath[MAX_PATH];
|
||||
osGetTempPathA(MAX_PATH-30, zMbcsPath);
|
||||
char zMbcsPath[SQLITE_WIN32_MAX_PATH];
|
||||
if( osGetTempPathA(SQLITE_WIN32_MAX_PATH-30, zMbcsPath)==0 ){
|
||||
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_GETTEMPPATH\n"));
|
||||
return SQLITE_IOERR_GETTEMPPATH;
|
||||
}
|
||||
zUtf8 = sqlite3_win32_mbcs_to_utf8(zMbcsPath);
|
||||
if( zUtf8 ){
|
||||
sqlite3_snprintf(MAX_PATH-30, zTempPath, "%s", zUtf8);
|
||||
sqlite3_snprintf(SQLITE_WIN32_MAX_PATH-30, zTempPath, "%s", zUtf8);
|
||||
sqlite3_free(zUtf8);
|
||||
}else{
|
||||
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
|
||||
return SQLITE_IOERR_NOMEM;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
else{
|
||||
/*
|
||||
** Compiled without ANSI support and the current operating system
|
||||
** is not Windows NT; therefore, just zero the temporary buffer.
|
||||
*/
|
||||
memset(zTempPath, 0, SQLITE_WIN32_MAX_PATH+2);
|
||||
}
|
||||
#endif /* SQLITE_WIN32_HAS_ANSI */
|
||||
#else
|
||||
else{
|
||||
/*
|
||||
** Compiled for WinRT and the sqlite3_temp_directory is not set;
|
||||
** therefore, just zero the temporary buffer.
|
||||
*/
|
||||
memset(zTempPath, 0, SQLITE_WIN32_MAX_PATH+2);
|
||||
}
|
||||
#endif /* !SQLITE_OS_WINRT */
|
||||
|
||||
/* Check that the output buffer is large enough for the temporary file
|
||||
** name. If it is not, return SQLITE_ERROR.
|
||||
@ -4005,7 +4037,7 @@ static int winOpen(
|
||||
/* If argument zPath is a NULL pointer, this function is required to open
|
||||
** a temporary file. Use this buffer to store the file name in.
|
||||
*/
|
||||
char zTmpname[MAX_PATH+2]; /* Buffer used to create temp filename */
|
||||
char zTmpname[SQLITE_WIN32_MAX_PATH+2]; /* Buffer used to create temp filename */
|
||||
|
||||
int rc = SQLITE_OK; /* Function Return Code */
|
||||
#if !defined(NDEBUG) || SQLITE_OS_WINCE
|
||||
@ -4071,8 +4103,7 @@ static int winOpen(
|
||||
*/
|
||||
if( !zUtf8Name ){
|
||||
assert(isDelete && !isOpenJournal);
|
||||
memset(zTmpname, 0, MAX_PATH+2);
|
||||
rc = getTempname(MAX_PATH+2, zTmpname);
|
||||
rc = getTempname(SQLITE_WIN32_MAX_PATH+2, zTmpname);
|
||||
if( rc!=SQLITE_OK ){
|
||||
OSTRACE(("OPEN name=%s, rc=%s", zUtf8Name, sqlite3ErrName(rc)));
|
||||
return rc;
|
||||
@ -4503,7 +4534,7 @@ static int winFullPathname(
|
||||
#if defined(__CYGWIN__)
|
||||
SimulateIOError( return SQLITE_ERROR );
|
||||
UNUSED_PARAMETER(nFull);
|
||||
assert( pVfs->mxPathname>=MAX_PATH );
|
||||
assert( pVfs->mxPathname>=SQLITE_WIN32_MAX_PATH );
|
||||
assert( nFull>=pVfs->mxPathname );
|
||||
if ( sqlite3_data_directory && !winIsVerbatimPathname(zRelative) ){
|
||||
/*
|
||||
@ -4512,14 +4543,21 @@ static int winFullPathname(
|
||||
** for converting the relative path name to an absolute
|
||||
** one by prepending the data directory and a slash.
|
||||
*/
|
||||
char zOut[MAX_PATH+1];
|
||||
memset(zOut, 0, MAX_PATH+1);
|
||||
cygwin_conv_path(CCP_POSIX_TO_WIN_A|CCP_RELATIVE, zRelative, zOut,
|
||||
MAX_PATH+1);
|
||||
char zOut[SQLITE_WIN32_MAX_PATH+1];
|
||||
if( cygwin_conv_path(CCP_POSIX_TO_WIN_A|CCP_RELATIVE, zRelative, zOut,
|
||||
SQLITE_WIN32_MAX_PATH+1)<0 ){
|
||||
winLogError(SQLITE_CANTOPEN_FULLPATH, (DWORD)errno, "cygwin_conv_path",
|
||||
zRelative);
|
||||
return SQLITE_CANTOPEN_FULLPATH;
|
||||
}
|
||||
sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s\\%s",
|
||||
sqlite3_data_directory, zOut);
|
||||
}else{
|
||||
cygwin_conv_path(CCP_POSIX_TO_WIN_A, zRelative, zFull, nFull);
|
||||
if( cygwin_conv_path(CCP_POSIX_TO_WIN_A, zRelative, zFull, nFull)<0 ){
|
||||
winLogError(SQLITE_CANTOPEN_FULLPATH, (DWORD)errno, "cygwin_conv_path",
|
||||
zRelative);
|
||||
return SQLITE_CANTOPEN_FULLPATH;
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
#endif
|
||||
@ -4861,7 +4899,7 @@ int sqlite3_os_init(void){
|
||||
static sqlite3_vfs winVfs = {
|
||||
3, /* iVersion */
|
||||
sizeof(winFile), /* szOsFile */
|
||||
MAX_PATH, /* mxPathname */
|
||||
SQLITE_WIN32_MAX_PATH, /* mxPathname */
|
||||
0, /* pNext */
|
||||
"win32", /* zName */
|
||||
0, /* pAppData */
|
||||
|
@ -1125,10 +1125,10 @@ nexprlist(A) ::= expr(Y).
|
||||
///////////////////////////// The CREATE INDEX command ///////////////////////
|
||||
//
|
||||
cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D)
|
||||
ON nm(Y) LP idxlist(Z) RP(E). {
|
||||
ON nm(Y) LP idxlist(Z) RP where_opt(W). {
|
||||
sqlite3CreateIndex(pParse, &X, &D,
|
||||
sqlite3SrcListAppend(pParse->db,0,&Y,0), Z, U,
|
||||
&S, &E, SQLITE_SO_ASC, NE);
|
||||
&S, W, SQLITE_SO_ASC, NE);
|
||||
}
|
||||
|
||||
%type uniqueflag {int}
|
||||
|
60
src/pragma.c
60
src/pragma.c
@ -1400,9 +1400,7 @@ void sqlite3Pragma(
|
||||
}
|
||||
|
||||
/* Make sure sufficient number of registers have been allocated */
|
||||
if( pParse->nMem < cnt+4 ){
|
||||
pParse->nMem = cnt+4;
|
||||
}
|
||||
pParse->nMem = MAX( pParse->nMem, cnt+7 );
|
||||
|
||||
/* Do the b-tree integrity checks */
|
||||
sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1);
|
||||
@ -1427,12 +1425,15 @@ void sqlite3Pragma(
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1); /* Stop if out of errors */
|
||||
sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
sqlite3ExprCacheClear(pParse);
|
||||
sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, 2); /* reg(2) will count entries */
|
||||
loopTop = sqlite3VdbeAddOp2(v, OP_Rewind, 1, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 2, 1); /* increment entry count */
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
int jmp2;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, 7+j); /* index entries counter */
|
||||
}
|
||||
pParse->nMem = MAX(pParse->nMem, 7+j);
|
||||
loopTop = sqlite3VdbeAddOp2(v, OP_Rewind, 1, 0) + 1;
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
int jmp2, jmp3;
|
||||
int r1;
|
||||
static const VdbeOpList idxErr[] = {
|
||||
{ OP_AddImm, 1, -1, 0},
|
||||
@ -1447,7 +1448,8 @@ void sqlite3Pragma(
|
||||
{ OP_IfPos, 1, 0, 0}, /* 9 */
|
||||
{ OP_Halt, 0, 0, 0},
|
||||
};
|
||||
r1 = sqlite3GenerateIndexKey(pParse, pIdx, 1, 3, 0);
|
||||
r1 = sqlite3GenerateIndexKey(pParse, pIdx, 1, 3, 0, &jmp3);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 7+j, 1); /* increment entry count */
|
||||
jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, j+2, 0, r1, pIdx->nColumn+1);
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr);
|
||||
sqlite3VdbeChangeP4(v, addr+1, "rowid ", P4_STATIC);
|
||||
@ -1455,35 +1457,25 @@ void sqlite3Pragma(
|
||||
sqlite3VdbeChangeP4(v, addr+4, pIdx->zName, P4_TRANSIENT);
|
||||
sqlite3VdbeJumpHere(v, addr+9);
|
||||
sqlite3VdbeJumpHere(v, jmp2);
|
||||
sqlite3VdbeResolveLabel(v, jmp3);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Next, 1, loopTop+1);
|
||||
sqlite3VdbeJumpHere(v, loopTop);
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
static const VdbeOpList cntIdx[] = {
|
||||
{ OP_Integer, 0, 3, 0},
|
||||
{ OP_Rewind, 0, 0, 0}, /* 1 */
|
||||
{ OP_AddImm, 3, 1, 0},
|
||||
{ OP_Next, 0, 0, 0}, /* 3 */
|
||||
{ OP_Eq, 2, 0, 3}, /* 4 */
|
||||
{ OP_AddImm, 1, -1, 0},
|
||||
{ OP_String8, 0, 2, 0}, /* 6 */
|
||||
{ OP_String8, 0, 3, 0}, /* 7 */
|
||||
{ OP_Concat, 3, 2, 2},
|
||||
{ OP_ResultRow, 2, 1, 0},
|
||||
};
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
|
||||
sqlite3VdbeChangeP1(v, addr+1, j+2);
|
||||
sqlite3VdbeChangeP2(v, addr+1, addr+4);
|
||||
sqlite3VdbeChangeP1(v, addr+3, j+2);
|
||||
sqlite3VdbeChangeP2(v, addr+3, addr+2);
|
||||
sqlite3VdbeJumpHere(v, addr+4);
|
||||
sqlite3VdbeChangeP4(v, addr+6,
|
||||
sqlite3VdbeAddOp2(v, OP_Next, 1, loopTop);
|
||||
sqlite3VdbeJumpHere(v, loopTop-1);
|
||||
#ifndef SQLITE_OMIT_BTREECOUNT
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0,
|
||||
"wrong # of entries in index ", P4_STATIC);
|
||||
sqlite3VdbeChangeP4(v, addr+7, pIdx->zName, P4_TRANSIENT);
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
addr = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr+2);
|
||||
sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Count, j+2, 3);
|
||||
sqlite3VdbeAddOp3(v, OP_Eq, 7+j, addr+8, 3);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pIdx->zName, P4_TRANSIENT);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, 3, 2, 7);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 7, 1);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_BTREECOUNT */
|
||||
}
|
||||
}
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
|
||||
|
@ -810,6 +810,12 @@ static int sqlite3Prepare16(
|
||||
if( !sqlite3SafetyCheckOk(db) ){
|
||||
return SQLITE_MISUSE_BKPT;
|
||||
}
|
||||
if( nBytes>=0 ){
|
||||
int sz;
|
||||
const char *z = (const char*)zSql;
|
||||
for(sz=0; sz<nBytes && (z[sz]!=0 || z[sz+1]!=0); sz += 2){}
|
||||
nBytes = sz;
|
||||
}
|
||||
sqlite3_mutex_enter(db->mutex);
|
||||
zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE);
|
||||
if( zSql8 ){
|
||||
|
113
src/resolve.c
113
src/resolve.c
@ -240,11 +240,20 @@ static int lookupName(
|
||||
** resulting in an appropriate error message toward the end of this routine
|
||||
*/
|
||||
if( zDb ){
|
||||
for(i=0; i<db->nDb; i++){
|
||||
assert( db->aDb[i].zName );
|
||||
if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){
|
||||
pSchema = db->aDb[i].pSchema;
|
||||
break;
|
||||
testcase( pNC->ncFlags & NC_PartIdx );
|
||||
testcase( pNC->ncFlags & NC_IsCheck );
|
||||
if( (pNC->ncFlags & (NC_PartIdx|NC_IsCheck))!=0 ){
|
||||
/* Silently ignore database qualifiers inside CHECK constraints and partial
|
||||
** indices. Do not raise errors because that might break legacy and
|
||||
** because it does not hurt anything to just ignore the database name. */
|
||||
zDb = 0;
|
||||
}else{
|
||||
for(i=0; i<db->nDb; i++){
|
||||
assert( db->aDb[i].zName );
|
||||
if( sqlite3StrICmp(db->aDb[i].zName,zDb)==0 ){
|
||||
pSchema = db->aDb[i].pSchema;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -522,6 +531,39 @@ Expr *sqlite3CreateColumnExpr(sqlite3 *db, SrcList *pSrc, int iSrc, int iCol){
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Report an error that an expression is not valid for a partial index WHERE
|
||||
** clause.
|
||||
*/
|
||||
static void notValidPartIdxWhere(
|
||||
Parse *pParse, /* Leave error message here */
|
||||
NameContext *pNC, /* The name context */
|
||||
const char *zMsg /* Type of error */
|
||||
){
|
||||
if( (pNC->ncFlags & NC_PartIdx)!=0 ){
|
||||
sqlite3ErrorMsg(pParse, "%s prohibited in partial index WHERE clauses",
|
||||
zMsg);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
/*
|
||||
** Report an error that an expression is not valid for a CHECK constraint.
|
||||
*/
|
||||
static void notValidCheckConstraint(
|
||||
Parse *pParse, /* Leave error message here */
|
||||
NameContext *pNC, /* The name context */
|
||||
const char *zMsg /* Type of error */
|
||||
){
|
||||
if( (pNC->ncFlags & NC_IsCheck)!=0 ){
|
||||
sqlite3ErrorMsg(pParse,"%s prohibited in CHECK constraints", zMsg);
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define notValidCheckConstraint(P,N,M)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** This routine is callback for sqlite3WalkExpr().
|
||||
**
|
||||
@ -621,6 +663,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
|
||||
testcase( pExpr->op==TK_CONST_FUNC );
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
notValidPartIdxWhere(pParse, pNC, "functions");
|
||||
zId = pExpr->u.zToken;
|
||||
nId = sqlite3Strlen30(zId);
|
||||
pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0);
|
||||
@ -686,11 +729,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
testcase( pExpr->op==TK_IN );
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
int nRef = pNC->nRef;
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
if( (pNC->ncFlags & NC_IsCheck)!=0 ){
|
||||
sqlite3ErrorMsg(pParse,"subqueries prohibited in CHECK constraints");
|
||||
}
|
||||
#endif
|
||||
notValidCheckConstraint(pParse, pNC, "subqueries");
|
||||
notValidPartIdxWhere(pParse, pNC, "subqueries");
|
||||
sqlite3WalkSelect(pWalker, pExpr->x.pSelect);
|
||||
assert( pNC->nRef>=nRef );
|
||||
if( nRef!=pNC->nRef ){
|
||||
@ -699,14 +739,11 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_CHECK
|
||||
case TK_VARIABLE: {
|
||||
if( (pNC->ncFlags & NC_IsCheck)!=0 ){
|
||||
sqlite3ErrorMsg(pParse,"parameters prohibited in CHECK constraints");
|
||||
}
|
||||
notValidCheckConstraint(pParse, pNC, "parameters");
|
||||
notValidPartIdxWhere(pParse, pNC, "parameters");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return (pParse->nErr || pParse->db->mallocFailed) ? WRC_Abort : WRC_Continue;
|
||||
}
|
||||
@ -797,7 +834,7 @@ static int resolveOrderByTermToExprList(
|
||||
** result-set entry.
|
||||
*/
|
||||
for(i=0; i<pEList->nExpr; i++){
|
||||
if( sqlite3ExprCompare(pEList->a[i].pExpr, pE)<2 ){
|
||||
if( sqlite3ExprCompare(pEList->a[i].pExpr, pE, -1)<2 ){
|
||||
return i+1;
|
||||
}
|
||||
}
|
||||
@ -1025,7 +1062,7 @@ static int resolveOrderGroupBy(
|
||||
return 1;
|
||||
}
|
||||
for(j=0; j<pSelect->pEList->nExpr; j++){
|
||||
if( sqlite3ExprCompare(pE, pSelect->pEList->a[j].pExpr)==0 ){
|
||||
if( sqlite3ExprCompare(pE, pSelect->pEList->a[j].pExpr, -1)==0 ){
|
||||
pItem->iOrderByCol = j+1;
|
||||
}
|
||||
}
|
||||
@ -1331,3 +1368,45 @@ void sqlite3ResolveSelectNames(
|
||||
w.u.pNC = pOuterNC;
|
||||
sqlite3WalkSelect(&w, p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Resolve names in expressions that can only reference a single table:
|
||||
**
|
||||
** * CHECK constraints
|
||||
** * WHERE clauses on partial indices
|
||||
**
|
||||
** The Expr.iTable value for Expr.op==TK_COLUMN nodes of the expression
|
||||
** is set to -1 and the Expr.iColumn value is set to the column number.
|
||||
**
|
||||
** Any errors cause an error message to be set in pParse.
|
||||
*/
|
||||
void sqlite3ResolveSelfReference(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Table *pTab, /* The table being referenced */
|
||||
int type, /* NC_IsCheck or NC_PartIdx */
|
||||
Expr *pExpr, /* Expression to resolve. May be NULL. */
|
||||
ExprList *pList /* Expression list to resolve. May be NUL. */
|
||||
){
|
||||
SrcList sSrc; /* Fake SrcList for pParse->pNewTable */
|
||||
NameContext sNC; /* Name context for pParse->pNewTable */
|
||||
int i; /* Loop counter */
|
||||
|
||||
assert( type==NC_IsCheck || type==NC_PartIdx );
|
||||
memset(&sNC, 0, sizeof(sNC));
|
||||
memset(&sSrc, 0, sizeof(sSrc));
|
||||
sSrc.nSrc = 1;
|
||||
sSrc.a[0].zName = pTab->zName;
|
||||
sSrc.a[0].pTab = pTab;
|
||||
sSrc.a[0].iCursor = -1;
|
||||
sNC.pParse = pParse;
|
||||
sNC.pSrcList = &sSrc;
|
||||
sNC.ncFlags = type;
|
||||
if( sqlite3ResolveExprNames(&sNC, pExpr) ) return;
|
||||
if( pList ){
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
if( sqlite3ResolveExprNames(&sNC, pList->a[i].pExpr) ){
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4177,7 +4177,7 @@ int sqlite3Select(
|
||||
** Use the SQLITE_GroupByOrder flag with SQLITE_TESTCTRL_OPTIMIZER
|
||||
** to disable this optimization for testing purposes.
|
||||
*/
|
||||
if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy)==0
|
||||
if( sqlite3ExprListCompare(p->pGroupBy, pOrderBy, -1)==0
|
||||
&& OptimizationEnabled(db, SQLITE_GroupByOrder) ){
|
||||
pOrderBy = 0;
|
||||
}
|
||||
@ -4198,7 +4198,7 @@ int sqlite3Select(
|
||||
** BY and DISTINCT, and an index or separate temp-table for the other.
|
||||
*/
|
||||
if( (p->selFlags & (SF_Distinct|SF_Aggregate))==SF_Distinct
|
||||
&& sqlite3ExprListCompare(pOrderBy, p->pEList)==0
|
||||
&& sqlite3ExprListCompare(pOrderBy, p->pEList, -1)==0
|
||||
){
|
||||
p->selFlags &= ~SF_Distinct;
|
||||
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
|
||||
|
23
src/shell.c
23
src/shell.c
@ -65,7 +65,7 @@
|
||||
#define isatty(h) _isatty(h)
|
||||
#define access(f,m) _access((f),(m))
|
||||
#undef popen
|
||||
#define popen(a,b) _popen((a),(b))
|
||||
#define popen _popen
|
||||
#undef pclose
|
||||
#define pclose _pclose
|
||||
#else
|
||||
@ -74,6 +74,11 @@
|
||||
extern int isatty(int);
|
||||
#endif
|
||||
|
||||
/* popen and pclose are not C89 functions and so are sometimes omitted from
|
||||
** the <stdio.h> header */
|
||||
FILE *popen(const char*,const char*);
|
||||
int pclose(FILE*);
|
||||
|
||||
#if defined(_WIN32_WCE)
|
||||
/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
|
||||
* thus we always assume that we have a console. That can be
|
||||
@ -1721,7 +1726,6 @@ static char *csv_read_one_field(CSVReader *p){
|
||||
|| (c==EOF && pc==cQuote)
|
||||
){
|
||||
do{ p->n--; }while( p->z[p->n]!=cQuote );
|
||||
p->z[p->n] = 0;
|
||||
p->cTerm = c;
|
||||
break;
|
||||
}
|
||||
@ -1732,7 +1736,6 @@ static char *csv_read_one_field(CSVReader *p){
|
||||
if( c==EOF ){
|
||||
fprintf(stderr, "%s:%d: unterminated %c-quoted field\n",
|
||||
p->zFile, startLine, cQuote);
|
||||
p->z[p->n] = 0;
|
||||
p->cTerm = EOF;
|
||||
break;
|
||||
}
|
||||
@ -1748,9 +1751,9 @@ static char *csv_read_one_field(CSVReader *p){
|
||||
p->nLine++;
|
||||
if( p->n>1 && p->z[p->n-1]=='\r' ) p->n--;
|
||||
}
|
||||
p->z[p->n] = 0;
|
||||
p->cTerm = c;
|
||||
}
|
||||
if( p->z ) p->z[p->n] = 0;
|
||||
return p->z;
|
||||
}
|
||||
|
||||
@ -1799,7 +1802,6 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 ){
|
||||
const char *zDestFile = 0;
|
||||
const char *zDb = 0;
|
||||
const char *zKey = 0;
|
||||
sqlite3 *pDest;
|
||||
sqlite3_backup *pBackup;
|
||||
int j;
|
||||
@ -1807,9 +1809,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
const char *z = azArg[j];
|
||||
if( z[0]=='-' ){
|
||||
while( z[0]=='-' ) z++;
|
||||
if( strcmp(z,"key")==0 && j<nArg-1 ){
|
||||
zKey = azArg[++j];
|
||||
}else
|
||||
/* No options to process at this time */
|
||||
{
|
||||
fprintf(stderr, "unknown option: %s\n", azArg[j]);
|
||||
return 1;
|
||||
@ -1835,11 +1835,6 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
sqlite3_close(pDest);
|
||||
return 1;
|
||||
}
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
sqlite3_key(pDest, zKey, (int)strlen(zKey));
|
||||
#else
|
||||
(void)zKey;
|
||||
#endif
|
||||
open_db(p);
|
||||
pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
|
||||
if( pBackup==0 ){
|
||||
@ -2669,7 +2664,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
/* sqlite3_test_control(int, uint) */
|
||||
case SQLITE_TESTCTRL_PENDING_BYTE:
|
||||
if( nArg==3 ){
|
||||
unsigned int opt = (unsigned int)integerValue(azArg[2]);
|
||||
unsigned int opt = (unsigned int)integerValue(azArg[2]);
|
||||
rc = sqlite3_test_control(testctrl, opt);
|
||||
fprintf(p->out, "%d (0x%08x)\n", rc, rc);
|
||||
} else {
|
||||
|
@ -473,6 +473,7 @@ int sqlite3_exec(
|
||||
#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8))
|
||||
#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8))
|
||||
#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8))
|
||||
#define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25<<8))
|
||||
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
|
||||
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
|
||||
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
|
||||
@ -2554,9 +2555,10 @@ SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
|
||||
** interface is to keep a GUI updated during a large query.
|
||||
**
|
||||
** ^The parameter P is passed through as the only parameter to the
|
||||
** callback function X. ^The parameter N is the number of
|
||||
** callback function X. ^The parameter N is the approximate number of
|
||||
** [virtual machine instructions] that are evaluated between successive
|
||||
** invocations of the callback X.
|
||||
** invocations of the callback X. ^If N is less than one then the progress
|
||||
** handler is disabled.
|
||||
**
|
||||
** ^Only a single progress handler may be defined at one time per
|
||||
** [database connection]; setting a new progress handler cancels the
|
||||
@ -4176,41 +4178,49 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
|
||||
/*
|
||||
** CAPI3REF: Function Auxiliary Data
|
||||
**
|
||||
** The following two functions may be used by scalar SQL functions to
|
||||
** These functions may be used by (non-aggregate) SQL functions to
|
||||
** associate metadata with argument values. If the same value is passed to
|
||||
** multiple invocations of the same SQL function during query execution, under
|
||||
** some circumstances the associated metadata may be preserved. This may
|
||||
** be used, for example, to add a regular-expression matching scalar
|
||||
** function. The compiled version of the regular expression is stored as
|
||||
** metadata associated with the SQL value passed as the regular expression
|
||||
** pattern. The compiled regular expression can be reused on multiple
|
||||
** invocations of the same function so that the original pattern string
|
||||
** does not need to be recompiled on each invocation.
|
||||
** some circumstances the associated metadata may be preserved. An example
|
||||
** of where this might be useful is in a regular-expression matching
|
||||
** function. The compiled version of the regular expression can be stored as
|
||||
** metadata associated with the pattern string.
|
||||
** Then as long as the pattern string remains the same,
|
||||
** the compiled regular expression can be reused on multiple
|
||||
** invocations of the same function.
|
||||
**
|
||||
** ^The sqlite3_get_auxdata() interface returns a pointer to the metadata
|
||||
** associated by the sqlite3_set_auxdata() function with the Nth argument
|
||||
** value to the application-defined function. ^If no metadata has been ever
|
||||
** been set for the Nth argument of the function, or if the corresponding
|
||||
** function parameter has changed since the meta-data was set,
|
||||
** then sqlite3_get_auxdata() returns a NULL pointer.
|
||||
** value to the application-defined function. ^If there is no metadata
|
||||
** associated with the function argument, this sqlite3_get_auxdata() interface
|
||||
** returns a NULL pointer.
|
||||
**
|
||||
** ^The sqlite3_set_auxdata() interface saves the metadata
|
||||
** pointed to by its 3rd parameter as the metadata for the N-th
|
||||
** argument of the application-defined function. Subsequent
|
||||
** calls to sqlite3_get_auxdata() might return this data, if it has
|
||||
** not been destroyed.
|
||||
** ^If it is not NULL, SQLite will invoke the destructor
|
||||
** function given by the 4th parameter to sqlite3_set_auxdata() on
|
||||
** the metadata when the corresponding function parameter changes
|
||||
** or when the SQL statement completes, whichever comes first.
|
||||
** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
|
||||
** argument of the application-defined function. ^Subsequent
|
||||
** calls to sqlite3_get_auxdata(C,N) return P from the most recent
|
||||
** sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or
|
||||
** NULL if the metadata has been discarded.
|
||||
** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL,
|
||||
** SQLite will invoke the destructor function X with parameter P exactly
|
||||
** once, when the metadata is discarded.
|
||||
** SQLite is free to discard the metadata at any time, including: <ul>
|
||||
** <li> when the corresponding function parameter changes, or
|
||||
** <li> when [sqlite3_reset()] or [sqlite3_finalize()] is called for the
|
||||
** SQL statement, or
|
||||
** <li> when sqlite3_set_auxdata() is invoked again on the same parameter, or
|
||||
** <li> during the original sqlite3_set_auxdata() call when a memory
|
||||
** allocation error occurs. </ul>)^
|
||||
**
|
||||
** SQLite is free to call the destructor and drop metadata on any
|
||||
** parameter of any function at any time. ^The only guarantee is that
|
||||
** the destructor will be called before the metadata is dropped.
|
||||
** Note the last bullet in particular. The destructor X in
|
||||
** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the
|
||||
** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata()
|
||||
** should be called near the end of the function implementation and the
|
||||
** function implementation should not make any use of P after
|
||||
** sqlite3_set_auxdata() has been called.
|
||||
**
|
||||
** ^(In practice, metadata is preserved between function calls for
|
||||
** expressions that are constant at compile time. This includes literal
|
||||
** values and [parameters].)^
|
||||
** function parameters that are compile-time constants, including literal
|
||||
** values and [parameters] and expressions composed from the same.)^
|
||||
**
|
||||
** These routines must be called from the same thread in which
|
||||
** the SQL function is running.
|
||||
@ -5123,10 +5133,23 @@ int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
|
||||
** on the list of automatic extensions is a harmless no-op. ^No entry point
|
||||
** will be called more than once for each database connection that is opened.
|
||||
**
|
||||
** See also: [sqlite3_reset_auto_extension()].
|
||||
** See also: [sqlite3_reset_auto_extension()]
|
||||
** and [sqlite3_cancel_auto_extension()]
|
||||
*/
|
||||
int sqlite3_auto_extension(void (*xEntryPoint)(void));
|
||||
|
||||
/*
|
||||
** CAPI3REF: Cancel Automatic Extension Loading
|
||||
**
|
||||
** ^The [sqlite3_cancel_auto_extension(X)] interface unregisters the
|
||||
** initialization routine X that was registered using a prior call to
|
||||
** [sqlite3_auto_extension(X)]. ^The [sqlite3_cancel_auto_extension(X)]
|
||||
** routine returns 1 if initialization routine X was successfully
|
||||
** unregistered and it returns 0 if X was not on the list of initialization
|
||||
** routines.
|
||||
*/
|
||||
int sqlite3_cancel_auto_extension(void (*xEntryPoint)(void));
|
||||
|
||||
/*
|
||||
** CAPI3REF: Reset Automatic Extension Loading
|
||||
**
|
||||
@ -6241,9 +6264,9 @@ int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
|
||||
** </dd>
|
||||
**
|
||||
** [[SQLITE_DBSTATUS_DEFERRED_FKS]] ^(<dt>SQLITE_DBSTATUS_DEFERRED_FKS</dt>
|
||||
** <dd>This parameter returns the zero for the current value if and only if
|
||||
** there all foreign key constraints (deferred or immediate) have been
|
||||
** resolved. The highwater mark is always 0.
|
||||
** <dd>This parameter returns zero for the current value if and only if
|
||||
** all foreign key constraints (deferred or immediate) have been
|
||||
** resolved.)^ ^The highwater mark is always 0.
|
||||
** </dd>
|
||||
** </dl>
|
||||
*/
|
||||
|
@ -161,9 +161,6 @@
|
||||
** will cause HeapValidate to be called. If heap validation should fail, an
|
||||
** assertion will be triggered.
|
||||
**
|
||||
** (Historical note: There used to be several other options, but we've
|
||||
** pared it down to just these three.)
|
||||
**
|
||||
** If none of the above are defined, then set SQLITE_SYSTEM_MALLOC as
|
||||
** the default.
|
||||
*/
|
||||
@ -201,20 +198,13 @@
|
||||
# define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The TCL headers are only needed when compiling the TCL bindings.
|
||||
*/
|
||||
#if defined(SQLITE_TCL) || defined(TCLSH)
|
||||
# include <tcl.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
** NDEBUG and SQLITE_DEBUG are opposites. It should always be true that
|
||||
** defined(NDEBUG)==!defined(SQLITE_DEBUG). If this is not currently true,
|
||||
** make it true by defining or undefining NDEBUG.
|
||||
**
|
||||
** Setting NDEBUG makes the code smaller and run faster by disabling the
|
||||
** number assert() statements in the code. So we want the default action
|
||||
** Setting NDEBUG makes the code smaller and faster by disabling the
|
||||
** assert() statements in the code. So we want the default action
|
||||
** to be for NDEBUG to be set and NDEBUG to be undefined only if SQLITE_DEBUG
|
||||
** is set. Thus NDEBUG becomes an opt-in rather than an opt-out
|
||||
** feature.
|
||||
@ -284,7 +274,7 @@
|
||||
** In other words, ALWAYS and NEVER are added for defensive code.
|
||||
**
|
||||
** When doing coverage testing ALWAYS and NEVER are hard-coded to
|
||||
** be true and false so that the unreachable code then specify will
|
||||
** be true and false so that the unreachable code they specify will
|
||||
** not be counted as untested code.
|
||||
*/
|
||||
#if defined(SQLITE_COVERAGE_TEST)
|
||||
@ -308,16 +298,12 @@
|
||||
/*
|
||||
** The macro unlikely() is a hint that surrounds a boolean
|
||||
** expression that is usually false. Macro likely() surrounds
|
||||
** a boolean expression that is usually true. GCC is able to
|
||||
** use these hints to generate better code, sometimes.
|
||||
** a boolean expression that is usually true. These hints could,
|
||||
** in theory, be used by the compiler to generate better code, but
|
||||
** currently they are just comments for human readers.
|
||||
*/
|
||||
#if defined(__GNUC__) && 0
|
||||
# define likely(X) __builtin_expect((X),1)
|
||||
# define unlikely(X) __builtin_expect((X),0)
|
||||
#else
|
||||
# define likely(X) !!(X)
|
||||
# define unlikely(X) !!(X)
|
||||
#endif
|
||||
#define likely(X) (X)
|
||||
#define unlikely(X) (X)
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include "hash.h"
|
||||
@ -1560,6 +1546,7 @@ struct Index {
|
||||
Schema *pSchema; /* Schema containing this index */
|
||||
u8 *aSortOrder; /* for each column: True==DESC, False==ASC */
|
||||
char **azColl; /* Array of collation sequence names for index */
|
||||
Expr *pPartIdxWhere; /* WHERE clause for partial indices */
|
||||
int tnum; /* DB Page containing root of this index */
|
||||
u16 nColumn; /* Number of columns in table used by this index */
|
||||
u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */
|
||||
@ -2040,6 +2027,7 @@ struct NameContext {
|
||||
#define NC_InAggFunc 0x08 /* True if analyzing arguments to an agg func */
|
||||
#define NC_AsMaybe 0x10 /* Resolve to AS terms of the result set only
|
||||
** if no other resolution is available */
|
||||
#define NC_PartIdx 0x20 /* True if resolving a partial index WHERE */
|
||||
|
||||
/*
|
||||
** An instance of the following structure contains all information
|
||||
@ -2224,6 +2212,7 @@ struct Parse {
|
||||
int nSet; /* Number of sets used so far */
|
||||
int nOnce; /* Number of OP_Once instructions so far */
|
||||
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 */
|
||||
struct yColCache {
|
||||
@ -2809,7 +2798,7 @@ void sqlite3SrcListAssignCursors(Parse*, SrcList*);
|
||||
void sqlite3IdListDelete(sqlite3*, IdList*);
|
||||
void sqlite3SrcListDelete(sqlite3*, SrcList*);
|
||||
Index *sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*,
|
||||
Token*, int, int);
|
||||
Expr*, int, int);
|
||||
void sqlite3DropIndex(Parse*, SrcList*, int);
|
||||
int sqlite3Select(Parse*, Select*, SelectDest*);
|
||||
Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
|
||||
@ -2857,8 +2846,9 @@ void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
|
||||
void sqlite3Vacuum(Parse*);
|
||||
int sqlite3RunVacuum(char**, sqlite3*);
|
||||
char *sqlite3NameFromToken(sqlite3*, Token*);
|
||||
int sqlite3ExprCompare(Expr*, Expr*);
|
||||
int sqlite3ExprListCompare(ExprList*, ExprList*);
|
||||
int sqlite3ExprCompare(Expr*, Expr*, int);
|
||||
int sqlite3ExprListCompare(ExprList*, ExprList*, int);
|
||||
int sqlite3ExprImpliesExpr(Expr*, Expr*, int);
|
||||
void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
|
||||
void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
|
||||
int sqlite3FunctionUsesThisSrc(Expr*, SrcList*);
|
||||
@ -2885,7 +2875,7 @@ int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
|
||||
int sqlite3IsRowid(const char*);
|
||||
void sqlite3GenerateRowDelete(Parse*, Table*, int, int, int, Trigger *, int);
|
||||
void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int*);
|
||||
int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int);
|
||||
int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*);
|
||||
void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,
|
||||
int*,int,int,int,int,int*);
|
||||
void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int, int);
|
||||
@ -3088,6 +3078,7 @@ void sqlite3SelectPrep(Parse*, Select*, NameContext*);
|
||||
int sqlite3MatchSpanName(const char*, const char*, const char*, const char*);
|
||||
int sqlite3ResolveExprNames(NameContext*, Expr*);
|
||||
void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
|
||||
void sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*);
|
||||
int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
|
||||
void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
|
||||
void sqlite3AlterFinishAddColumn(Parse *, Token *);
|
||||
|
@ -98,6 +98,22 @@ static int autoExtSqrObjCmd(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_cancel_auto_extension_sqr
|
||||
**
|
||||
** Unregister the "sqr" extension.
|
||||
*/
|
||||
static int cancelAutoExtSqrObjCmd(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int rc = sqlite3_cancel_auto_extension((void*)sqr_init);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_auto_extension_cube
|
||||
**
|
||||
@ -114,6 +130,22 @@ static int autoExtCubeObjCmd(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_cancel_auto_extension_cube
|
||||
**
|
||||
** Unregister the "cube" extension.
|
||||
*/
|
||||
static int cancelAutoExtCubeObjCmd(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int rc = sqlite3_cancel_auto_extension((void*)cube_init);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_auto_extension_broken
|
||||
**
|
||||
@ -130,6 +162,22 @@ static int autoExtBrokenObjCmd(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite3_cancel_auto_extension_broken
|
||||
**
|
||||
** Unregister the broken extension.
|
||||
*/
|
||||
static int cancelAutoExtBrokenObjCmd(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int rc = sqlite3_cancel_auto_extension((void*)broken_init);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
|
||||
|
||||
|
||||
@ -161,6 +209,12 @@ int Sqlitetest_autoext_Init(Tcl_Interp *interp){
|
||||
Tcl_CreateObjCommand(interp, "sqlite3_auto_extension_broken",
|
||||
autoExtBrokenObjCmd, 0, 0);
|
||||
#endif
|
||||
Tcl_CreateObjCommand(interp, "sqlite3_cancel_auto_extension_sqr",
|
||||
cancelAutoExtSqrObjCmd, 0, 0);
|
||||
Tcl_CreateObjCommand(interp, "sqlite3_cancel_auto_extension_cube",
|
||||
cancelAutoExtCubeObjCmd, 0, 0);
|
||||
Tcl_CreateObjCommand(interp, "sqlite3_cancel_auto_extension_broken",
|
||||
cancelAutoExtBrokenObjCmd, 0, 0);
|
||||
Tcl_CreateObjCommand(interp, "sqlite3_reset_auto_extension",
|
||||
resetAutoExtObjCmd, 0, 0);
|
||||
return TCL_OK;
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include "sqliteInt.h"
|
||||
#include <tcl.h>
|
||||
|
||||
typedef struct Testvfs Testvfs;
|
||||
typedef struct TestvfsShm TestvfsShm;
|
||||
|
@ -246,7 +246,7 @@ void sqlite3Update(
|
||||
}
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
int reg;
|
||||
if( hasFK || chngRowid ){
|
||||
if( hasFK || chngRowid || pIdx->pPartIdxWhere ){
|
||||
reg = ++pParse->nMem;
|
||||
}else{
|
||||
reg = 0;
|
||||
|
38
src/vdbe.c
38
src/vdbe.c
@ -565,7 +565,7 @@ int sqlite3VdbeExec(
|
||||
int iCompare = 0; /* Result of last OP_Compare operation */
|
||||
unsigned nVmStep = 0; /* Number of virtual machine steps */
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
unsigned nProgressOps = 0; /* nVmStep at last progress callback. */
|
||||
unsigned nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */
|
||||
#endif
|
||||
Mem *aMem = p->aMem; /* Copy of p->aMem */
|
||||
Mem *pIn1 = 0; /* 1st input operand */
|
||||
@ -595,6 +595,17 @@ int sqlite3VdbeExec(
|
||||
db->busyHandler.nBusy = 0;
|
||||
CHECK_FOR_INTERRUPT;
|
||||
sqlite3VdbeIOTraceSql(p);
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
if( db->xProgress ){
|
||||
assert( 0 < db->nProgressOps );
|
||||
nProgressLimit = (unsigned)p->aCounter[SQLITE_STMTSTATUS_VM_STEP-1];
|
||||
if( nProgressLimit==0 ){
|
||||
nProgressLimit = db->nProgressOps;
|
||||
}else{
|
||||
nProgressLimit %= (unsigned)db->nProgressOps;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef SQLITE_DEBUG
|
||||
sqlite3BeginBenignMalloc();
|
||||
if( p->pc==0 && (p->db->flags & SQLITE_VdbeListing)!=0 ){
|
||||
@ -755,14 +766,16 @@ check_for_interrupt:
|
||||
** If the progress callback returns non-zero, exit the virtual machine with
|
||||
** a return code SQLITE_ABORT.
|
||||
*/
|
||||
if( db->xProgress!=0 && (nVmStep - nProgressOps)>=db->nProgressOps ){
|
||||
if( db->xProgress!=0 && nVmStep>=nProgressLimit ){
|
||||
int prc;
|
||||
prc = db->xProgress(db->pProgressArg);
|
||||
if( prc!=0 ){
|
||||
rc = SQLITE_INTERRUPT;
|
||||
goto vdbe_error_halt;
|
||||
}
|
||||
nProgressOps = nVmStep;
|
||||
if( db->xProgress!=0 ){
|
||||
nProgressLimit = nVmStep + db->nProgressOps - (nVmStep%db->nProgressOps);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1430,19 +1443,14 @@ case OP_Function: {
|
||||
REGISTER_TRACE(pOp->p2+i, pArg);
|
||||
}
|
||||
|
||||
assert( pOp->p4type==P4_FUNCDEF || pOp->p4type==P4_VDBEFUNC );
|
||||
if( pOp->p4type==P4_FUNCDEF ){
|
||||
ctx.pFunc = pOp->p4.pFunc;
|
||||
ctx.pVdbeFunc = 0;
|
||||
}else{
|
||||
ctx.pVdbeFunc = (VdbeFunc*)pOp->p4.pVdbeFunc;
|
||||
ctx.pFunc = ctx.pVdbeFunc->pFunc;
|
||||
}
|
||||
|
||||
assert( pOp->p4type==P4_FUNCDEF );
|
||||
ctx.pFunc = pOp->p4.pFunc;
|
||||
ctx.s.flags = MEM_Null;
|
||||
ctx.s.db = db;
|
||||
ctx.s.xDel = 0;
|
||||
ctx.s.zMalloc = 0;
|
||||
ctx.iOp = pc;
|
||||
ctx.pVdbe = p;
|
||||
|
||||
/* The output cell may already have a buffer allocated. Move
|
||||
** the pointer to ctx.s so in case the user-function can use
|
||||
@ -1465,11 +1473,7 @@ case OP_Function: {
|
||||
/* If any auxiliary data functions have been called by this user function,
|
||||
** immediately call the destructor for any non-static values.
|
||||
*/
|
||||
if( ctx.pVdbeFunc ){
|
||||
sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p1);
|
||||
pOp->p4.pVdbeFunc = ctx.pVdbeFunc;
|
||||
pOp->p4type = P4_VDBEFUNC;
|
||||
}
|
||||
sqlite3VdbeDeleteAuxData(p, pc, pOp->p1);
|
||||
|
||||
if( db->mallocFailed ){
|
||||
/* Even though a malloc() has failed, the implementation of the
|
||||
|
@ -30,7 +30,6 @@ typedef struct Vdbe Vdbe;
|
||||
** The names of the following types declared in vdbeInt.h are required
|
||||
** for the VdbeOp definition.
|
||||
*/
|
||||
typedef struct VdbeFunc VdbeFunc;
|
||||
typedef struct Mem Mem;
|
||||
typedef struct SubProgram SubProgram;
|
||||
|
||||
@ -54,7 +53,6 @@ struct VdbeOp {
|
||||
i64 *pI64; /* Used when p4type is P4_INT64 */
|
||||
double *pReal; /* Used when p4type is P4_REAL */
|
||||
FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */
|
||||
VdbeFunc *pVdbeFunc; /* Used when p4type is P4_VDBEFUNC */
|
||||
CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */
|
||||
Mem *pMem; /* Used when p4type is P4_MEM */
|
||||
VTable *pVtab; /* Used when p4type is P4_VTAB */
|
||||
@ -109,7 +107,6 @@ typedef struct VdbeOpList VdbeOpList;
|
||||
#define P4_COLLSEQ (-4) /* P4 is a pointer to a CollSeq structure */
|
||||
#define P4_FUNCDEF (-5) /* P4 is a pointer to a FuncDef structure */
|
||||
#define P4_KEYINFO (-6) /* P4 is a pointer to a KeyInfo structure */
|
||||
#define P4_VDBEFUNC (-7) /* P4 is a pointer to a VdbeFunc structure */
|
||||
#define P4_MEM (-8) /* P4 is a pointer to a Mem* structure */
|
||||
#define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */
|
||||
#define P4_VTAB (-10) /* P4 is a pointer to an sqlite3_vtab structure */
|
||||
@ -209,7 +206,7 @@ sqlite3 *sqlite3VdbeDb(Vdbe*);
|
||||
void sqlite3VdbeSetSql(Vdbe*, const char *z, int n, int);
|
||||
void sqlite3VdbeSwap(Vdbe*,Vdbe*);
|
||||
VdbeOp *sqlite3VdbeTakeOpArray(Vdbe*, int*, int*);
|
||||
sqlite3_value *sqlite3VdbeGetValue(Vdbe*, int, u8);
|
||||
sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe*, int, u8);
|
||||
void sqlite3VdbeSetVarmask(Vdbe*, int);
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
char *sqlite3VdbeExpandSql(Vdbe*, const char*);
|
||||
|
@ -44,6 +44,9 @@ typedef struct VdbeSorter VdbeSorter;
|
||||
/* Opaque type used by the explainer */
|
||||
typedef struct Explain Explain;
|
||||
|
||||
/* Elements of the linked list at Vdbe.pAuxData */
|
||||
typedef struct AuxData AuxData;
|
||||
|
||||
/*
|
||||
** A cursor is a pointer into a single BTree within a database file.
|
||||
** The cursor can seek to a BTree entry with a particular key, or
|
||||
@ -230,23 +233,19 @@ struct Mem {
|
||||
#define memIsValid(M) ((M)->flags & MEM_Invalid)==0
|
||||
#endif
|
||||
|
||||
|
||||
/* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains
|
||||
** additional information about auxiliary information bound to arguments
|
||||
** of the function. This is used to implement the sqlite3_get_auxdata()
|
||||
** and sqlite3_set_auxdata() APIs. The "auxdata" is some auxiliary data
|
||||
** that can be associated with a constant argument to a function. This
|
||||
** allows functions such as "regexp" to compile their constant regular
|
||||
** expression argument once and reused the compiled code for multiple
|
||||
** invocations.
|
||||
/*
|
||||
** Each auxilliary data pointer stored by a user defined function
|
||||
** implementation calling sqlite3_set_auxdata() is stored in an instance
|
||||
** of this structure. All such structures associated with a single VM
|
||||
** are stored in a linked list headed at Vdbe.pAuxData. All are destroyed
|
||||
** when the VM is halted (if not before).
|
||||
*/
|
||||
struct VdbeFunc {
|
||||
FuncDef *pFunc; /* The definition of the function */
|
||||
int nAux; /* Number of entries allocated for apAux[] */
|
||||
struct AuxData {
|
||||
void *pAux; /* Aux data for the i-th argument */
|
||||
void (*xDelete)(void *); /* Destructor for the aux data */
|
||||
} apAux[1]; /* One slot for each function argument */
|
||||
struct AuxData {
|
||||
int iOp; /* Instruction number of OP_Function opcode */
|
||||
int iArg; /* Index of function argument. */
|
||||
void *pAux; /* Aux data pointer */
|
||||
void (*xDelete)(void *); /* Destructor for the aux data */
|
||||
AuxData *pNext; /* Next element in list */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -264,12 +263,13 @@ struct VdbeFunc {
|
||||
*/
|
||||
struct sqlite3_context {
|
||||
FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
|
||||
VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */
|
||||
Mem s; /* The return value is stored here */
|
||||
Mem *pMem; /* Memory cell used to store aggregate context */
|
||||
CollSeq *pColl; /* Collating sequence */
|
||||
int isError; /* Error code returned by the function. */
|
||||
int skipFlag; /* Skip skip accumulator loading if true */
|
||||
int iOp; /* Instruction number of OP_Function */
|
||||
Vdbe *pVdbe; /* The VM that owns this context */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -368,6 +368,7 @@ struct Vdbe {
|
||||
SubProgram *pProgram; /* Linked list of all sub-programs used by VM */
|
||||
int nOnceFlag; /* Size of array aOnceFlag[] */
|
||||
u8 *aOnceFlag; /* Flags for OP_Once */
|
||||
AuxData *pAuxData; /* Linked list of auxdata allocations */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -410,7 +411,7 @@ u32 sqlite3VdbeSerialTypeLen(u32);
|
||||
u32 sqlite3VdbeSerialType(Mem*, int);
|
||||
u32 sqlite3VdbeSerialPut(unsigned char*, int, Mem*, int);
|
||||
u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
|
||||
void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);
|
||||
void sqlite3VdbeDeleteAuxData(Vdbe*, int, int);
|
||||
|
||||
int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
|
||||
int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int*);
|
||||
|
@ -584,14 +584,14 @@ void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
|
||||
** the user-function defined by pCtx.
|
||||
*/
|
||||
void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
|
||||
VdbeFunc *pVdbeFunc;
|
||||
AuxData *pAuxData;
|
||||
|
||||
assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
|
||||
pVdbeFunc = pCtx->pVdbeFunc;
|
||||
if( !pVdbeFunc || iArg>=pVdbeFunc->nAux || iArg<0 ){
|
||||
return 0;
|
||||
for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
|
||||
if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
|
||||
}
|
||||
return pVdbeFunc->apAux[iArg].pAux;
|
||||
|
||||
return (pAuxData ? pAuxData->pAux : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -605,29 +605,26 @@ void sqlite3_set_auxdata(
|
||||
void *pAux,
|
||||
void (*xDelete)(void*)
|
||||
){
|
||||
struct AuxData *pAuxData;
|
||||
VdbeFunc *pVdbeFunc;
|
||||
if( iArg<0 ) goto failed;
|
||||
AuxData *pAuxData;
|
||||
Vdbe *pVdbe = pCtx->pVdbe;
|
||||
|
||||
assert( sqlite3_mutex_held(pCtx->s.db->mutex) );
|
||||
pVdbeFunc = pCtx->pVdbeFunc;
|
||||
if( !pVdbeFunc || pVdbeFunc->nAux<=iArg ){
|
||||
int nAux = (pVdbeFunc ? pVdbeFunc->nAux : 0);
|
||||
int nMalloc = sizeof(VdbeFunc) + sizeof(struct AuxData)*iArg;
|
||||
pVdbeFunc = sqlite3DbRealloc(pCtx->s.db, pVdbeFunc, nMalloc);
|
||||
if( !pVdbeFunc ){
|
||||
goto failed;
|
||||
}
|
||||
pCtx->pVdbeFunc = pVdbeFunc;
|
||||
memset(&pVdbeFunc->apAux[nAux], 0, sizeof(struct AuxData)*(iArg+1-nAux));
|
||||
pVdbeFunc->nAux = iArg+1;
|
||||
pVdbeFunc->pFunc = pCtx->pFunc;
|
||||
}
|
||||
if( iArg<0 ) goto failed;
|
||||
|
||||
pAuxData = &pVdbeFunc->apAux[iArg];
|
||||
if( pAuxData->pAux && pAuxData->xDelete ){
|
||||
for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){
|
||||
if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break;
|
||||
}
|
||||
if( pAuxData==0 ){
|
||||
pAuxData = sqlite3DbMallocZero(pVdbe->db, sizeof(AuxData));
|
||||
if( !pAuxData ) goto failed;
|
||||
pAuxData->iOp = pCtx->iOp;
|
||||
pAuxData->iArg = iArg;
|
||||
pAuxData->pNext = pVdbe->pAuxData;
|
||||
pVdbe->pAuxData = pAuxData;
|
||||
}else if( pAuxData->xDelete ){
|
||||
pAuxData->xDelete(pAuxData->pAux);
|
||||
}
|
||||
|
||||
pAuxData->pAux = pAux;
|
||||
pAuxData->xDelete = xDelete;
|
||||
return;
|
||||
|
@ -251,8 +251,8 @@ int sqlite3VdbeMakeLabel(Vdbe *p){
|
||||
void sqlite3VdbeResolveLabel(Vdbe *p, int x){
|
||||
int j = -1-x;
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
assert( j>=0 && j<p->nLabel );
|
||||
if( p->aLabel ){
|
||||
assert( j<p->nLabel );
|
||||
if( j>=0 && p->aLabel ){
|
||||
p->aLabel[j] = p->nOp;
|
||||
}
|
||||
}
|
||||
@ -576,8 +576,7 @@ void sqlite3VdbeChangeP5(Vdbe *p, u8 val){
|
||||
** the address of the next instruction to be coded.
|
||||
*/
|
||||
void sqlite3VdbeJumpHere(Vdbe *p, int addr){
|
||||
assert( addr>=0 || p->db->mallocFailed );
|
||||
if( addr>=0 ) sqlite3VdbeChangeP2(p, addr, p->nOp);
|
||||
if( ALWAYS(addr>=0) ) sqlite3VdbeChangeP2(p, addr, p->nOp);
|
||||
}
|
||||
|
||||
|
||||
@ -613,13 +612,6 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
|
||||
if( db->pnBytesFreed==0 ) sqlite3_free(p4);
|
||||
break;
|
||||
}
|
||||
case P4_VDBEFUNC: {
|
||||
VdbeFunc *pVdbeFunc = (VdbeFunc *)p4;
|
||||
freeEphemeralFunction(db, pVdbeFunc->pFunc);
|
||||
if( db->pnBytesFreed==0 ) sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
|
||||
sqlite3DbFree(db, pVdbeFunc);
|
||||
break;
|
||||
}
|
||||
case P4_FUNCDEF: {
|
||||
freeEphemeralFunction(db, (FuncDef*)p4);
|
||||
break;
|
||||
@ -1649,6 +1641,10 @@ static void closeAllCursors(Vdbe *p){
|
||||
p->pDelFrame = pDel->pParent;
|
||||
sqlite3VdbeFrameDelete(pDel);
|
||||
}
|
||||
|
||||
/* Delete any auxdata allocations made by the VM */
|
||||
sqlite3VdbeDeleteAuxData(p, -1, 0);
|
||||
assert( p->pAuxData==0 );
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2447,20 +2443,35 @@ int sqlite3VdbeFinalize(Vdbe *p){
|
||||
}
|
||||
|
||||
/*
|
||||
** Call the destructor for each auxdata entry in pVdbeFunc for which
|
||||
** the corresponding bit in mask is clear. Auxdata entries beyond 31
|
||||
** are always destroyed. To destroy all auxdata entries, call this
|
||||
** routine with mask==0.
|
||||
** If parameter iOp is less than zero, then invoke the destructor for
|
||||
** all auxiliary data pointers currently cached by the VM passed as
|
||||
** the first argument.
|
||||
**
|
||||
** Or, if iOp is greater than or equal to zero, then the destructor is
|
||||
** only invoked for those auxiliary data pointers created by the user
|
||||
** function invoked by the OP_Function opcode at instruction iOp of
|
||||
** VM pVdbe, and only then if:
|
||||
**
|
||||
** * the associated function parameter is the 32nd or later (counting
|
||||
** from left to right), or
|
||||
**
|
||||
** * the corresponding bit in argument mask is clear (where the first
|
||||
** function parameter corrsponds to bit 0 etc.).
|
||||
*/
|
||||
void sqlite3VdbeDeleteAuxData(VdbeFunc *pVdbeFunc, int mask){
|
||||
int i;
|
||||
for(i=0; i<pVdbeFunc->nAux; i++){
|
||||
struct AuxData *pAux = &pVdbeFunc->apAux[i];
|
||||
if( (i>31 || !(mask&(((u32)1)<<i))) && pAux->pAux ){
|
||||
void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){
|
||||
AuxData **pp = &pVdbe->pAuxData;
|
||||
while( *pp ){
|
||||
AuxData *pAux = *pp;
|
||||
if( (iOp<0)
|
||||
|| (pAux->iOp==iOp && (pAux->iArg>31 || !(mask & ((u32)1<<pAux->iArg))))
|
||||
){
|
||||
if( pAux->xDelete ){
|
||||
pAux->xDelete(pAux->pAux);
|
||||
}
|
||||
pAux->pAux = 0;
|
||||
*pp = pAux->pNext;
|
||||
sqlite3DbFree(pVdbe->db, pAux);
|
||||
}else{
|
||||
pp= &pAux->pNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2980,7 +2991,7 @@ int sqlite3VdbeRecordCompare(
|
||||
int nKey1, const void *pKey1, /* Left key */
|
||||
UnpackedRecord *pPKey2 /* Right key */
|
||||
){
|
||||
int d1; /* Offset into aKey[] of next data element */
|
||||
u32 d1; /* Offset into aKey[] of next data element */
|
||||
u32 idx1; /* Offset into aKey[] of next header element */
|
||||
u32 szHdr1; /* Number of bytes in header */
|
||||
int i = 0;
|
||||
@ -3014,7 +3025,7 @@ int sqlite3VdbeRecordCompare(
|
||||
|
||||
/* Read the serial types for the next element in each key. */
|
||||
idx1 += getVarint32( aKey1+idx1, serial_type1 );
|
||||
if( d1>=nKey1 && sqlite3VdbeSerialTypeLen(serial_type1)>0 ) break;
|
||||
if( d1+sqlite3VdbeSerialTypeLen(serial_type1)>(u32)nKey1 ) break;
|
||||
|
||||
/* Extract the values to be compared.
|
||||
*/
|
||||
@ -3243,7 +3254,7 @@ sqlite3 *sqlite3VdbeDb(Vdbe *v){
|
||||
**
|
||||
** The returned value must be freed by the caller using sqlite3ValueFree().
|
||||
*/
|
||||
sqlite3_value *sqlite3VdbeGetValue(Vdbe *v, int iVar, u8 aff){
|
||||
sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff){
|
||||
assert( iVar>0 );
|
||||
if( v ){
|
||||
Mem *pMem = &v->aVar[iVar-1];
|
||||
|
@ -825,8 +825,8 @@ int sqlite3VtabSync(sqlite3 *db, char **pzErrmsg){
|
||||
if( pVtab && (x = pVtab->pModule->xSync)!=0 ){
|
||||
rc = x(pVtab);
|
||||
sqlite3DbFree(db, *pzErrmsg);
|
||||
*pzErrmsg = sqlite3DbStrDup(db, pVtab->zErrMsg);
|
||||
sqlite3_free(pVtab->zErrMsg);
|
||||
*pzErrmsg = pVtab->zErrMsg;
|
||||
pVtab->zErrMsg = 0;
|
||||
}
|
||||
}
|
||||
db->aVTrans = aVTrans;
|
||||
|
244
src/where.c
244
src/where.c
@ -45,6 +45,8 @@ typedef struct WherePath WherePath;
|
||||
typedef struct WhereTerm WhereTerm;
|
||||
typedef struct WhereLoopBuilder WhereLoopBuilder;
|
||||
typedef struct WhereScan WhereScan;
|
||||
typedef struct WhereOrCost WhereOrCost;
|
||||
typedef struct WhereOrSet WhereOrSet;
|
||||
|
||||
/*
|
||||
** Cost X is tracked as 10*log2(X) stored in a 16-bit integer. The
|
||||
@ -152,6 +154,27 @@ struct WhereLoop {
|
||||
WhereTerm *aLTermSpace[4]; /* Initial aLTerm[] space */
|
||||
};
|
||||
|
||||
/* This object holds the prerequisites and the cost of running a
|
||||
** subquery on one operand of an OR operator in the WHERE clause.
|
||||
** See WhereOrSet for additional information
|
||||
*/
|
||||
struct WhereOrCost {
|
||||
Bitmask prereq; /* Prerequisites */
|
||||
WhereCost rRun; /* Cost of running this subquery */
|
||||
WhereCost nOut; /* Number of outputs for this subquery */
|
||||
};
|
||||
|
||||
/* The WhereOrSet object holds a set of possible WhereOrCosts that
|
||||
** correspond to the subquery(s) of OR-clause processing. At most
|
||||
** favorable N_OR_COST elements are retained.
|
||||
*/
|
||||
#define N_OR_COST 3
|
||||
struct WhereOrSet {
|
||||
u16 n; /* Number of valid a[] entries */
|
||||
WhereOrCost a[N_OR_COST]; /* Set of best costs */
|
||||
};
|
||||
|
||||
|
||||
/* Forward declaration of methods */
|
||||
static int whereLoopResize(sqlite3*, WhereLoop*, int);
|
||||
|
||||
@ -366,7 +389,7 @@ struct WhereLoopBuilder {
|
||||
WhereClause *pWC; /* WHERE clause terms */
|
||||
ExprList *pOrderBy; /* ORDER BY clause */
|
||||
WhereLoop *pNew; /* Template WhereLoop */
|
||||
WhereLoop *pBest; /* If non-NULL, store single best loop here */
|
||||
WhereOrSet *pOrSet; /* Record best loops here, if not NULL */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -509,6 +532,54 @@ int sqlite3WhereOkOnePass(WhereInfo *pWInfo){
|
||||
return pWInfo->okOnePass;
|
||||
}
|
||||
|
||||
/*
|
||||
** Move the content of pSrc into pDest
|
||||
*/
|
||||
static void whereOrMove(WhereOrSet *pDest, WhereOrSet *pSrc){
|
||||
pDest->n = pSrc->n;
|
||||
memcpy(pDest->a, pSrc->a, pDest->n*sizeof(pDest->a[0]));
|
||||
}
|
||||
|
||||
/*
|
||||
** Try to insert a new prerequisite/cost entry into the WhereOrSet pSet.
|
||||
**
|
||||
** The new entry might overwrite an existing entry, or it might be
|
||||
** appended, or it might be discarded. Do whatever is the right thing
|
||||
** so that pSet keeps the N_OR_COST best entries seen so far.
|
||||
*/
|
||||
static int whereOrInsert(
|
||||
WhereOrSet *pSet, /* The WhereOrSet to be updated */
|
||||
Bitmask prereq, /* Prerequisites of the new entry */
|
||||
WhereCost rRun, /* Run-cost of the new entry */
|
||||
WhereCost nOut /* Number of outputs for the new entry */
|
||||
){
|
||||
u16 i;
|
||||
WhereOrCost *p;
|
||||
for(i=pSet->n, p=pSet->a; i>0; i--, p++){
|
||||
if( rRun<=p->rRun && (prereq & p->prereq)==prereq ){
|
||||
goto whereOrInsert_done;
|
||||
}
|
||||
if( p->rRun<=rRun && (p->prereq & prereq)==p->prereq ){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if( pSet->n<N_OR_COST ){
|
||||
p = &pSet->a[pSet->n++];
|
||||
p->nOut = nOut;
|
||||
}else{
|
||||
p = pSet->a;
|
||||
for(i=1; i<pSet->n; i++){
|
||||
if( p->rRun>pSet->a[i].rRun ) p = pSet->a + i;
|
||||
}
|
||||
if( p->rRun<=rRun ) return 0;
|
||||
}
|
||||
whereOrInsert_done:
|
||||
p->prereq = prereq;
|
||||
p->rRun = rRun;
|
||||
if( p->nOut>nOut ) p->nOut = nOut;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize a preallocated WhereClause structure.
|
||||
*/
|
||||
@ -1057,7 +1128,7 @@ static int isLikeOrGlob(
|
||||
if( op==TK_VARIABLE ){
|
||||
Vdbe *pReprepare = pParse->pReprepare;
|
||||
int iCol = pRight->iColumn;
|
||||
pVal = sqlite3VdbeGetValue(pReprepare, iCol, SQLITE_AFF_NONE);
|
||||
pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_NONE);
|
||||
if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){
|
||||
z = (char *)sqlite3_value_text(pVal);
|
||||
}
|
||||
@ -2164,7 +2235,7 @@ static void constructAutomaticIndex(
|
||||
/* Fill the automatic index with content */
|
||||
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur);
|
||||
regRecord = sqlite3GetTempReg(pParse);
|
||||
sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 1);
|
||||
sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 1, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
|
||||
sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1);
|
||||
@ -2521,7 +2592,7 @@ static int valueFromExpr(
|
||||
){
|
||||
int iVar = pExpr->iColumn;
|
||||
sqlite3VdbeSetVarmask(pParse->pVdbe, iVar);
|
||||
*pp = sqlite3VdbeGetValue(pParse->pReprepare, iVar, aff);
|
||||
*pp = sqlite3VdbeGetBoundValue(pParse->pReprepare, iVar, aff);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
return sqlite3ValueFromExpr(pParse->db, pExpr, SQLITE_UTF8, aff, pp);
|
||||
@ -3179,6 +3250,7 @@ static Bitmask codeOneLoopStart(
|
||||
WhereClause *pWC; /* Decomposition of the entire WHERE clause */
|
||||
WhereTerm *pTerm; /* A WHERE clause term */
|
||||
Parse *pParse; /* Parsing context */
|
||||
sqlite3 *db; /* Database connection */
|
||||
Vdbe *v; /* The prepared stmt under constructions */
|
||||
struct SrcList_item *pTabItem; /* FROM clause term being coded */
|
||||
int addrBrk; /* Jump here to break out of the loop */
|
||||
@ -3190,6 +3262,7 @@ static Bitmask codeOneLoopStart(
|
||||
pParse = pWInfo->pParse;
|
||||
v = pParse->pVdbe;
|
||||
pWC = &pWInfo->sWC;
|
||||
db = pParse->db;
|
||||
pLevel = &pWInfo->a[iLevel];
|
||||
pLoop = pLevel->pWLoop;
|
||||
pTabItem = &pWInfo->pTabList->a[pLevel->iFrom];
|
||||
@ -3480,7 +3553,7 @@ static Bitmask codeOneLoopStart(
|
||||
** starting at regBase.
|
||||
*/
|
||||
regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff);
|
||||
zEndAff = sqlite3DbStrDup(pParse->db, zStartAff);
|
||||
zEndAff = sqlite3DbStrDup(db, zStartAff);
|
||||
addrNxt = pLevel->addrNxt;
|
||||
|
||||
/* If we are doing a reverse order scan on an ascending index, or
|
||||
@ -3565,8 +3638,8 @@ static Bitmask codeOneLoopStart(
|
||||
nConstraint++;
|
||||
testcase( pRangeEnd->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
|
||||
}
|
||||
sqlite3DbFree(pParse->db, zStartAff);
|
||||
sqlite3DbFree(pParse->db, zEndAff);
|
||||
sqlite3DbFree(db, zStartAff);
|
||||
sqlite3DbFree(db, zEndAff);
|
||||
|
||||
/* Top of the loop body */
|
||||
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
|
||||
@ -3693,7 +3766,7 @@ static Bitmask codeOneLoopStart(
|
||||
int nNotReady; /* The number of notReady tables */
|
||||
struct SrcList_item *origSrc; /* Original list of tables */
|
||||
nNotReady = pWInfo->nLevel - iLevel - 1;
|
||||
pOrTab = sqlite3StackAllocRaw(pParse->db,
|
||||
pOrTab = sqlite3StackAllocRaw(db,
|
||||
sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0]));
|
||||
if( pOrTab==0 ) return notReady;
|
||||
pOrTab->nAlloc = (u8)(nNotReady + 1);
|
||||
@ -3743,11 +3816,12 @@ static Bitmask codeOneLoopStart(
|
||||
int iTerm;
|
||||
for(iTerm=0; iTerm<pWC->nTerm; iTerm++){
|
||||
Expr *pExpr = pWC->a[iTerm].pExpr;
|
||||
if( &pWC->a[iTerm] == pTerm ) continue;
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ) continue;
|
||||
if( pWC->a[iTerm].wtFlags & (TERM_VIRTUAL|TERM_ORINFO) ) continue;
|
||||
if( pWC->a[iTerm].wtFlags & (TERM_ORINFO) ) continue;
|
||||
if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
|
||||
pExpr = sqlite3ExprDup(pParse->db, pExpr, 0);
|
||||
pAndExpr = sqlite3ExprAnd(pParse->db, pAndExpr, pExpr);
|
||||
pExpr = sqlite3ExprDup(db, pExpr, 0);
|
||||
pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr);
|
||||
}
|
||||
if( pAndExpr ){
|
||||
pAndExpr = sqlite3PExpr(pParse, TK_AND, 0, pAndExpr, 0);
|
||||
@ -3767,7 +3841,7 @@ static Bitmask codeOneLoopStart(
|
||||
pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0,
|
||||
WHERE_OMIT_OPEN_CLOSE | WHERE_AND_ONLY |
|
||||
WHERE_FORCE_TABLE | WHERE_ONETABLE_ONLY, iCovCur);
|
||||
assert( pSubWInfo || pParse->nErr || pParse->db->mallocFailed );
|
||||
assert( pSubWInfo || pParse->nErr || db->mallocFailed );
|
||||
if( pSubWInfo ){
|
||||
WhereLoop *pSubLoop;
|
||||
explainOneScan(
|
||||
@ -3822,13 +3896,13 @@ static Bitmask codeOneLoopStart(
|
||||
if( pCov ) pLevel->iIdxCur = iCovCur;
|
||||
if( pAndExpr ){
|
||||
pAndExpr->pLeft = 0;
|
||||
sqlite3ExprDelete(pParse->db, pAndExpr);
|
||||
sqlite3ExprDelete(db, pAndExpr);
|
||||
}
|
||||
sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v));
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk);
|
||||
sqlite3VdbeResolveLabel(v, iLoopBody);
|
||||
|
||||
if( pWInfo->nLevel>1 ) sqlite3StackFree(pParse->db, pOrTab);
|
||||
if( pWInfo->nLevel>1 ) sqlite3StackFree(db, pOrTab);
|
||||
if( !untestedTerms ) disableTerm(pLevel, pTerm);
|
||||
}else
|
||||
#endif /* SQLITE_OMIT_OR_OPTIMIZATION */
|
||||
@ -3883,9 +3957,8 @@ static Bitmask codeOneLoopStart(
|
||||
** the implied "t1.a=123" constraint.
|
||||
*/
|
||||
for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){
|
||||
Expr *pE;
|
||||
Expr *pE, *pEAlt;
|
||||
WhereTerm *pAlt;
|
||||
Expr sEq;
|
||||
if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
||||
if( pTerm->eOperator!=(WO_EQUIV|WO_EQ) ) continue;
|
||||
if( pTerm->leftCursor!=iCur ) continue;
|
||||
@ -3899,9 +3972,13 @@ static Bitmask codeOneLoopStart(
|
||||
testcase( pAlt->eOperator & WO_EQ );
|
||||
testcase( pAlt->eOperator & WO_IN );
|
||||
VdbeNoopComment((v, "begin transitive constraint"));
|
||||
sEq = *pAlt->pExpr;
|
||||
sEq.pLeft = pE->pLeft;
|
||||
sqlite3ExprIfFalse(pParse, &sEq, addrCont, SQLITE_JUMPIFNULL);
|
||||
pEAlt = sqlite3StackAllocRaw(db, sizeof(*pEAlt));
|
||||
if( pEAlt ){
|
||||
*pEAlt = *pAlt->pExpr;
|
||||
pEAlt->pLeft = pE->pLeft;
|
||||
sqlite3ExprIfFalse(pParse, pEAlt, addrCont, SQLITE_JUMPIFNULL);
|
||||
sqlite3StackFree(db, pEAlt);
|
||||
}
|
||||
}
|
||||
|
||||
/* For a LEFT OUTER JOIN, generate code that will record the fact that
|
||||
@ -4072,12 +4149,12 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
|
||||
** fewer dependencies than the template. Otherwise a new WhereLoop is
|
||||
** added based on the template.
|
||||
**
|
||||
** If pBuilder->pBest is not NULL then we only care about the very
|
||||
** best template and that template should be stored in pBuilder->pBest.
|
||||
** If pBuilder->pBest is NULL then a list of the best templates are stored
|
||||
** in pBuilder->pWInfo->pLoops.
|
||||
** If pBuilder->pOrSet is not NULL then we only care about only the
|
||||
** prerequisites and rRun and nOut costs of the N best loops. That
|
||||
** information is gathered in the pBuilder->pOrSet object. This special
|
||||
** processing mode is used only for OR clause processing.
|
||||
**
|
||||
** When accumulating multiple loops (when pBuilder->pBest is NULL) we
|
||||
** When accumulating multiple loops (when pBuilder->pOrSet is NULL) we
|
||||
** still might overwrite similar loops with the new template if the
|
||||
** template is better. Loops may be overwritten if the following
|
||||
** conditions are met:
|
||||
@ -4094,30 +4171,22 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
|
||||
WhereInfo *pWInfo = pBuilder->pWInfo;
|
||||
sqlite3 *db = pWInfo->pParse->db;
|
||||
|
||||
/* If pBuilder->pBest is defined, then only keep track of the single
|
||||
** best WhereLoop. pBuilder->pBest->maskSelf==0 indicates that no
|
||||
** prior WhereLoops have been evaluated and that the current pTemplate
|
||||
** is therefore the first and hence the best and should be retained.
|
||||
/* If pBuilder->pOrSet is defined, then only keep track of the costs
|
||||
** and prereqs.
|
||||
*/
|
||||
if( (p = pBuilder->pBest)!=0 ){
|
||||
if( p->maskSelf!=0 ){
|
||||
WhereCost rCost = whereCostAdd(p->rRun,p->rSetup);
|
||||
WhereCost rTemplate = whereCostAdd(pTemplate->rRun,pTemplate->rSetup);
|
||||
if( rCost < rTemplate ){
|
||||
testcase( rCost==rTemplate-1 );
|
||||
goto whereLoopInsert_noop;
|
||||
}
|
||||
if( rCost==rTemplate && (p->prereq & pTemplate->prereq)==p->prereq ){
|
||||
goto whereLoopInsert_noop;
|
||||
}
|
||||
}
|
||||
if( pBuilder->pOrSet!=0 ){
|
||||
#if WHERETRACE_ENABLED
|
||||
u16 n = pBuilder->pOrSet->n;
|
||||
int x =
|
||||
#endif
|
||||
whereOrInsert(pBuilder->pOrSet, pTemplate->prereq, pTemplate->rRun,
|
||||
pTemplate->nOut);
|
||||
#if WHERETRACE_ENABLED
|
||||
if( sqlite3WhereTrace & 0x8 ){
|
||||
sqlite3DebugPrintf(p->maskSelf==0 ? "ins-init: " : "ins-best: ");
|
||||
sqlite3DebugPrintf(x?" or-%d: ":" or-X: ", n);
|
||||
whereLoopPrint(pTemplate, pWInfo->pTabList);
|
||||
}
|
||||
#endif
|
||||
whereLoopXfer(db, p, pTemplate);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@ -4211,7 +4280,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
|
||||
whereLoopInsert_noop:
|
||||
#if WHERETRACE_ENABLED
|
||||
if( sqlite3WhereTrace & 0x8 ){
|
||||
sqlite3DebugPrintf(pBuilder->pBest ? "ins-skip: " : "ins-noop: ");
|
||||
sqlite3DebugPrintf("ins-noop: ");
|
||||
whereLoopPrint(pTemplate, pWInfo->pTabList);
|
||||
}
|
||||
#endif
|
||||
@ -4362,7 +4431,8 @@ static int whereLoopAddBtreeIndex(
|
||||
&& !ExprHasProperty(pTerm->pExpr, EP_xIsSelect) ){
|
||||
rc = whereInScanEst(pParse, pProbe, pTerm->pExpr->x.pList, &nOut);
|
||||
}
|
||||
if( rc==SQLITE_OK ) pNew->nOut = whereCost(nOut);
|
||||
assert( nOut==0 || rc==SQLITE_OK );
|
||||
if( nOut ) pNew->nOut = whereCost(nOut);
|
||||
}
|
||||
#endif
|
||||
if( (pNew->wsFlags & (WHERE_IDX_ONLY|WHERE_IPK))==0 ){
|
||||
@ -4434,6 +4504,17 @@ static Bitmask columnsInIndex(Index *pIdx){
|
||||
return m;
|
||||
}
|
||||
|
||||
/* Check to see if a partial index with pPartIndexWhere can be used
|
||||
** in the current query. Return true if it can be and false if not.
|
||||
*/
|
||||
static int whereUsablePartialIndex(int iTab, WhereClause *pWC, Expr *pWhere){
|
||||
int i;
|
||||
WhereTerm *pTerm;
|
||||
for(i=0, pTerm=pWC->a; i<pWC->nTerm; i++, pTerm++){
|
||||
if( sqlite3ExprImpliesExpr(pTerm->pExpr, pWhere, iTab) ) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Add all WhereLoop objects for a single table of the join where the table
|
||||
@ -4457,11 +4538,13 @@ static int whereLoopAddBtree(
|
||||
int b; /* A boolean value */
|
||||
WhereCost rSize; /* number of rows in the table */
|
||||
WhereCost rLogSize; /* Logarithm of the number of rows in the table */
|
||||
WhereClause *pWC; /* The parsed WHERE clause */
|
||||
|
||||
pNew = pBuilder->pNew;
|
||||
pWInfo = pBuilder->pWInfo;
|
||||
pTabList = pWInfo->pTabList;
|
||||
pSrc = pTabList->a + pNew->iTab;
|
||||
pWC = pBuilder->pWC;
|
||||
assert( !IsVirtual(pSrc->pTab) );
|
||||
|
||||
if( pSrc->pIndex ){
|
||||
@ -4493,7 +4576,7 @@ static int whereLoopAddBtree(
|
||||
rLogSize = estLog(rSize);
|
||||
|
||||
/* Automatic indexes */
|
||||
if( !pBuilder->pBest
|
||||
if( !pBuilder->pOrSet
|
||||
&& (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0
|
||||
&& pSrc->pIndex==0
|
||||
&& !pSrc->viaCoroutine
|
||||
@ -4501,7 +4584,6 @@ static int whereLoopAddBtree(
|
||||
&& !pSrc->isCorrelated
|
||||
){
|
||||
/* Generate auto-index WhereLoops */
|
||||
WhereClause *pWC = pBuilder->pWC;
|
||||
WhereTerm *pTerm;
|
||||
WhereTerm *pWCEnd = pWC->a + pWC->nTerm;
|
||||
for(pTerm=pWC->a; rc==SQLITE_OK && pTerm<pWCEnd; pTerm++){
|
||||
@ -4531,6 +4613,10 @@ static int whereLoopAddBtree(
|
||||
/* Loop over all indices
|
||||
*/
|
||||
for(; rc==SQLITE_OK && pProbe; pProbe=pProbe->pNext, iSortIdx++){
|
||||
if( pProbe->pPartIdxWhere!=0
|
||||
&& !whereUsablePartialIndex(pNew->iTab, pWC, pProbe->pPartIdxWhere) ){
|
||||
continue; /* Partial index inappropriate for this query */
|
||||
}
|
||||
pNew->u.btree.nEq = 0;
|
||||
pNew->nLTerm = 0;
|
||||
pNew->iSortIdx = 0;
|
||||
@ -4779,7 +4865,7 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
|
||||
int iCur;
|
||||
WhereClause tempWC;
|
||||
WhereLoopBuilder sSubBuild;
|
||||
WhereLoop sBest;
|
||||
WhereOrSet sSum, sCur, sPrev;
|
||||
struct SrcList_item *pItem;
|
||||
|
||||
pWC = pBuilder->pWC;
|
||||
@ -4794,16 +4880,14 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
|
||||
WhereClause * const pOrWC = &pTerm->u.pOrInfo->wc;
|
||||
WhereTerm * const pOrWCEnd = &pOrWC->a[pOrWC->nTerm];
|
||||
WhereTerm *pOrTerm;
|
||||
WhereCost rTotal = 0;
|
||||
WhereCost nRow = 0;
|
||||
Bitmask prereq = mExtra;
|
||||
int once = 1;
|
||||
int i, j;
|
||||
|
||||
whereLoopInit(&sBest);
|
||||
pItem = pWInfo->pTabList->a + pNew->iTab;
|
||||
iCur = pItem->iCursor;
|
||||
sSubBuild = *pBuilder;
|
||||
sSubBuild.pOrderBy = 0;
|
||||
sSubBuild.pBest = &sBest;
|
||||
sSubBuild.pOrSet = &sCur;
|
||||
|
||||
for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
|
||||
if( (pOrTerm->eOperator & WO_AND)!=0 ){
|
||||
@ -4818,39 +4902,48 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){
|
||||
}else{
|
||||
continue;
|
||||
}
|
||||
sBest.maskSelf = 0;
|
||||
sBest.rSetup = 0;
|
||||
sBest.rRun = 0;
|
||||
sCur.n = 0;
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( IsVirtual(pItem->pTab) ){
|
||||
rc = whereLoopAddVirtual(&sSubBuild);
|
||||
for(i=0; i<sCur.n; i++) sCur.a[i].prereq |= mExtra;
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
rc = whereLoopAddBtree(&sSubBuild, mExtra);
|
||||
}
|
||||
/* sBest.maskSelf is always zero if an error occurs */
|
||||
assert( rc==SQLITE_OK || sBest.maskSelf==0 );
|
||||
if( sBest.maskSelf==0 ) break;
|
||||
assert( sBest.rSetup==0 );
|
||||
rTotal = whereCostAdd(rTotal, sBest.rRun);
|
||||
nRow = whereCostAdd(nRow, sBest.nOut);
|
||||
prereq |= sBest.prereq;
|
||||
assert( rc==SQLITE_OK || sCur.n==0 );
|
||||
if( sCur.n==0 ){
|
||||
sSum.n = 0;
|
||||
break;
|
||||
}else if( once ){
|
||||
whereOrMove(&sSum, &sCur);
|
||||
once = 0;
|
||||
}else{
|
||||
whereOrMove(&sPrev, &sSum);
|
||||
sSum.n = 0;
|
||||
for(i=0; i<sPrev.n; i++){
|
||||
for(j=0; j<sCur.n; j++){
|
||||
whereOrInsert(&sSum, sPrev.a[i].prereq | sCur.a[j].prereq,
|
||||
whereCostAdd(sPrev.a[i].rRun, sCur.a[j].rRun),
|
||||
whereCostAdd(sPrev.a[i].nOut, sCur.a[j].nOut));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assert( pNew->nLSlot>=1 );
|
||||
if( sBest.maskSelf ){
|
||||
pNew->nLTerm = 1;
|
||||
pNew->aLTerm[0] = pTerm;
|
||||
pNew->wsFlags = WHERE_MULTI_OR;
|
||||
pNew->rSetup = 0;
|
||||
pNew->nLTerm = 1;
|
||||
pNew->aLTerm[0] = pTerm;
|
||||
pNew->wsFlags = WHERE_MULTI_OR;
|
||||
pNew->rSetup = 0;
|
||||
pNew->iSortIdx = 0;
|
||||
memset(&pNew->u, 0, sizeof(pNew->u));
|
||||
for(i=0; rc==SQLITE_OK && i<sSum.n; i++){
|
||||
/* TUNING: Multiple by 3.5 for the secondary table lookup */
|
||||
pNew->rRun = rTotal + 18; assert( 18==whereCost(7)-whereCost(2) );
|
||||
pNew->nOut = nRow;
|
||||
pNew->prereq = prereq;
|
||||
memset(&pNew->u, 0, sizeof(pNew->u));
|
||||
pNew->rRun = sSum.a[i].rRun + 18;
|
||||
pNew->nOut = sSum.a[i].nOut;
|
||||
pNew->prereq = sSum.a[i].prereq;
|
||||
rc = whereLoopInsert(pBuilder, pNew);
|
||||
}
|
||||
whereLoopClear(pWInfo->pParse->db, &sBest);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
@ -5464,7 +5557,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
|
||||
pLoop->rRun = 33; /* 33==whereCost(10) */
|
||||
}else{
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( pIdx->onError==OE_None ) continue;
|
||||
if( pIdx->onError==OE_None || pIdx->pPartIdxWhere!=0 ) continue;
|
||||
for(j=0; j<pIdx->nColumn; j++){
|
||||
pTerm = findTerm(pWC, iCur, pIdx->aiColumn[j], 0, WO_EQ, pIdx);
|
||||
if( pTerm==0 ) break;
|
||||
@ -5657,7 +5750,8 @@ WhereInfo *sqlite3WhereBegin(
|
||||
pMaskSet = &pWInfo->sMaskSet;
|
||||
sWLB.pWInfo = pWInfo;
|
||||
sWLB.pWC = &pWInfo->sWC;
|
||||
sWLB.pNew = (WhereLoop*)&pWInfo->a[nTabList];
|
||||
sWLB.pNew = (WhereLoop*)(((char*)pWInfo)+nByteWInfo);
|
||||
assert( EIGHT_BYTE_ALIGNMENT(sWLB.pNew) );
|
||||
whereLoopInit(sWLB.pNew);
|
||||
#ifdef SQLITE_DEBUG
|
||||
sWLB.pNew->cId = '*';
|
||||
|
@ -43,6 +43,8 @@ ifcapable !stat3 {
|
||||
# analyze3-5.*: Check that the query plans of applicable statements are
|
||||
# invalidated if the values of SQL parameter are modified
|
||||
# using the clear_bindings() or transfer_bindings() APIs.
|
||||
#
|
||||
# analyze3-6.*: Test that the problem fixed by commit [127a5b776d] is fixed.
|
||||
#
|
||||
|
||||
proc getvar {varname} { uplevel #0 set $varname }
|
||||
@ -612,4 +614,29 @@ do_test analyze3-5.1.3 {
|
||||
sqlite3_finalize $S1
|
||||
} {SQLITE_OK}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
do_test analyze3-6.1 {
|
||||
execsql { DROP TABLE IF EXISTS t1 }
|
||||
execsql BEGIN
|
||||
execsql { CREATE TABLE t1(a, b, c) }
|
||||
for {set i 0} {$i < 1000} {incr i} {
|
||||
execsql "INSERT INTO t1 VALUES([expr $i/100], 'x', [expr $i/10])"
|
||||
}
|
||||
execsql {
|
||||
CREATE INDEX i1 ON t1(a, b);
|
||||
CREATE INDEX i2 ON t1(c);
|
||||
}
|
||||
execsql COMMIT
|
||||
execsql ANALYZE
|
||||
} {}
|
||||
|
||||
do_eqp_test analyze3-6-3 {
|
||||
SELECT * FROM t1 WHERE a = 5 AND c = 13;
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (c=?)}}
|
||||
|
||||
do_eqp_test analyze3-6-2 {
|
||||
SELECT * FROM t1 WHERE a = 5 AND b > 'w' AND c = 13;
|
||||
} {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (c=?)}}
|
||||
|
||||
finish_test
|
||||
|
@ -451,5 +451,11 @@ do_test 7.8 {
|
||||
catchsql { INSERT INTO t6 VALUES(12) } db2
|
||||
} {1 {constraint failed}}
|
||||
|
||||
# 2013-08-02: Silently ignore database name qualifiers in CHECK constraints.
|
||||
#
|
||||
do_execsql_test 8.1 {
|
||||
CREATE TABLE t810(a, CHECK( main.t810.a>0 ));
|
||||
CREATE TABLE t811(b, CHECK( xyzzy.t811.b BETWEEN 5 AND 10 ));
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
75
test/corruptG.test
Normal file
75
test/corruptG.test
Normal file
@ -0,0 +1,75 @@
|
||||
# 2013-08-01
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix corruptG
|
||||
|
||||
# Do not use a codec for tests in this file, as the database file is
|
||||
# manipulated directly using tcl scripts (using the [hexio_write] command).
|
||||
#
|
||||
do_not_use_codec
|
||||
|
||||
# Create a simple database with a single entry. Then corrupt the
|
||||
# header-size varint on the index payload so that it maps into a
|
||||
# negative number. Try to use the database.
|
||||
#
|
||||
|
||||
do_execsql_test 1.1 {
|
||||
PRAGMA page_size=512;
|
||||
CREATE TABLE t1(a,b,c);
|
||||
INSERT INTO t1(rowid,a,b,c) VALUES(52,'abc','xyz','123');
|
||||
CREATE INDEX t1abc ON t1(a,b,c);
|
||||
}
|
||||
|
||||
# Corrupt the file
|
||||
db close
|
||||
hexio_write test.db [expr {3*512 - 15}] 888080807f
|
||||
sqlite3 db test.db
|
||||
|
||||
# Try to use the file.
|
||||
do_test 1.2 {
|
||||
catchsql {
|
||||
SELECT c FROM t1 WHERE a>'abc';
|
||||
}
|
||||
} {0 {}}
|
||||
do_test 1.3 {
|
||||
catchsql {
|
||||
PRAGMA integrity_check
|
||||
}
|
||||
} {0 ok}
|
||||
do_test 1.4 {
|
||||
catchsql {
|
||||
SELECT c FROM t1 ORDER BY a;
|
||||
}
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
# Corrupt the same file in a slightly different way. Make the record header
|
||||
# sane, but corrupt one of the serial_type value to indicate a huge payload
|
||||
# such that the payload begins in allocated space but overflows the buffer.
|
||||
#
|
||||
db close
|
||||
hexio_write test.db [expr {3*512-15}] 0513ff7f01
|
||||
sqlite3 db test.db
|
||||
|
||||
do_test 2.1 {
|
||||
catchsql {
|
||||
SELECT rowid FROM t1 WHERE a='abc' and b='xyz123456789XYZ';
|
||||
}
|
||||
# The following test result is brittle. The point above is to try to
|
||||
# force a buffer overread by a corrupt database file. If we get an
|
||||
# incorrect answer from a corrupt database file, that is OK. If the
|
||||
# result below changes, that just means that "undefined behavior" has
|
||||
# changed.
|
||||
} {0 52}
|
||||
|
||||
finish_test
|
@ -14,6 +14,7 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix func
|
||||
|
||||
# Create a table to work with.
|
||||
#
|
||||
@ -682,6 +683,32 @@ do_test func-13.7 {
|
||||
lappend res [sqlite3_finalize $STMT]
|
||||
} {{0 0} {1 0} SQLITE_OK}
|
||||
|
||||
# Test that auxiliary data is discarded when a statement is reset.
|
||||
do_execsql_test 13.8.1 {
|
||||
SELECT test_auxdata('constant') FROM t4;
|
||||
} {0 1}
|
||||
do_execsql_test 13.8.2 {
|
||||
SELECT test_auxdata('constant') FROM t4;
|
||||
} {0 1}
|
||||
db cache flush
|
||||
do_execsql_test 13.8.3 {
|
||||
SELECT test_auxdata('constant') FROM t4;
|
||||
} {0 1}
|
||||
set V "one"
|
||||
do_execsql_test 13.8.4 {
|
||||
SELECT test_auxdata($V), $V FROM t4;
|
||||
} {0 one 1 one}
|
||||
set V "two"
|
||||
do_execsql_test 13.8.5 {
|
||||
SELECT test_auxdata($V), $V FROM t4;
|
||||
} {0 two 1 two}
|
||||
db cache flush
|
||||
set V "three"
|
||||
do_execsql_test 13.8.6 {
|
||||
SELECT test_auxdata($V), $V FROM t4;
|
||||
} {0 three 1 three}
|
||||
|
||||
|
||||
# Make sure that a function with a very long name is rejected
|
||||
do_test func-14.1 {
|
||||
catch {
|
||||
|
@ -715,6 +715,23 @@ do_test index-20.2 {
|
||||
DROP INDEX "t6i1";
|
||||
}
|
||||
} {}
|
||||
|
||||
# Try to create a TEMP index on a non-TEMP table. */
|
||||
#
|
||||
do_test index-21.1 {
|
||||
catchsql {
|
||||
CREATE INDEX temp.i21 ON t6(c);
|
||||
}
|
||||
} {1 {cannot create a TEMP index on non-TEMP table "t6"}}
|
||||
do_test index-21.2 {
|
||||
catchsql {
|
||||
CREATE TEMP TABLE t6(x);
|
||||
INSERT INTO temp.t6 values(1),(5),(9);
|
||||
CREATE INDEX temp.i21 ON t6(x);
|
||||
SELECT x FROM t6 ORDER BY x DESC;
|
||||
}
|
||||
} {0 {9 5 1}}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
230
test/index6.test
Normal file
230
test/index6.test
Normal file
@ -0,0 +1,230 @@
|
||||
# 2013-07-31
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test cases for partial indices
|
||||
#
|
||||
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
load_static_extension db wholenumber;
|
||||
do_test index6-1.1 {
|
||||
# Able to parse and manage partial indices
|
||||
execsql {
|
||||
CREATE TABLE t1(a,b,c);
|
||||
CREATE INDEX t1a ON t1(a) WHERE a IS NOT NULL;
|
||||
CREATE INDEX t1b ON t1(b) WHERE b>10;
|
||||
CREATE VIRTUAL TABLE nums USING wholenumber;
|
||||
INSERT INTO t1(a,b,c)
|
||||
SELECT CASE WHEN value%3!=0 THEN value END, value, value
|
||||
FROM nums WHERE value<=20;
|
||||
SELECT count(a), count(b) FROM t1;
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} {14 20 ok}
|
||||
|
||||
# Error conditions during parsing...
|
||||
#
|
||||
do_test index6-1.2 {
|
||||
catchsql {
|
||||
CREATE INDEX bad1 ON t1(a,b) WHERE x IS NOT NULL;
|
||||
}
|
||||
} {1 {no such column: x}}
|
||||
do_test index6-1.3 {
|
||||
catchsql {
|
||||
CREATE INDEX bad1 ON t1(a,b) WHERE EXISTS(SELECT * FROM t1);
|
||||
}
|
||||
} {1 {subqueries prohibited in partial index WHERE clauses}}
|
||||
do_test index6-1.4 {
|
||||
catchsql {
|
||||
CREATE INDEX bad1 ON t1(a,b) WHERE a!=?1;
|
||||
}
|
||||
} {1 {parameters prohibited in partial index WHERE clauses}}
|
||||
do_test index6-1.5 {
|
||||
catchsql {
|
||||
CREATE INDEX bad1 ON t1(a,b) WHERE a!=random();
|
||||
}
|
||||
} {1 {functions prohibited in partial index WHERE clauses}}
|
||||
do_test index6-1.6 {
|
||||
catchsql {
|
||||
CREATE INDEX bad1 ON t1(a,b) WHERE a NOT LIKE 'abc%';
|
||||
}
|
||||
} {1 {functions prohibited in partial index WHERE clauses}}
|
||||
|
||||
do_test index6-1.10 {
|
||||
execsql {
|
||||
ANALYZE;
|
||||
SELECT idx, stat FROM sqlite_stat1 ORDER BY idx;
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} {{} 20 t1a {14 1} t1b {10 1} ok}
|
||||
|
||||
# STAT1 shows the partial indices have a reduced number of
|
||||
# rows.
|
||||
#
|
||||
do_test index6-1.11 {
|
||||
execsql {
|
||||
UPDATE t1 SET a=b;
|
||||
ANALYZE;
|
||||
SELECT idx, stat FROM sqlite_stat1 ORDER BY idx;
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} {{} 20 t1a {20 1} t1b {10 1} ok}
|
||||
|
||||
do_test index6-1.11 {
|
||||
execsql {
|
||||
UPDATE t1 SET a=NULL WHERE b%3!=0;
|
||||
UPDATE t1 SET b=b+100;
|
||||
ANALYZE;
|
||||
SELECT idx, stat FROM sqlite_stat1 ORDER BY idx;
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} {{} 20 t1a {6 1} t1b {20 1} ok}
|
||||
|
||||
do_test index6-1.12 {
|
||||
execsql {
|
||||
UPDATE t1 SET a=CASE WHEN b%3!=0 THEN b END;
|
||||
UPDATE t1 SET b=b-100;
|
||||
ANALYZE;
|
||||
SELECT idx, stat FROM sqlite_stat1 ORDER BY idx;
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} {{} 20 t1a {13 1} t1b {10 1} ok}
|
||||
|
||||
do_test index6-1.13 {
|
||||
execsql {
|
||||
DELETE FROM t1 WHERE b BETWEEN 8 AND 12;
|
||||
ANALYZE;
|
||||
SELECT idx, stat FROM sqlite_stat1 ORDER BY idx;
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} {{} 15 t1a {10 1} t1b {8 1} ok}
|
||||
|
||||
do_test index6-1.14 {
|
||||
execsql {
|
||||
REINDEX;
|
||||
ANALYZE;
|
||||
SELECT idx, stat FROM sqlite_stat1 ORDER BY idx;
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} {{} 15 t1a {10 1} t1b {8 1} ok}
|
||||
|
||||
do_test index6-1.15 {
|
||||
execsql {
|
||||
CREATE INDEX t1c ON t1(c);
|
||||
ANALYZE;
|
||||
SELECT idx, stat FROM sqlite_stat1 ORDER BY idx;
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} {t1a {10 1} t1b {8 1} t1c {15 1} ok}
|
||||
|
||||
# Queries use partial indices as appropriate times.
|
||||
#
|
||||
do_test index6-2.1 {
|
||||
execsql {
|
||||
CREATE TABLE t2(a,b);
|
||||
INSERT INTO t2(a,b) SELECT value, value FROM nums WHERE value<1000;
|
||||
UPDATE t2 SET a=NULL WHERE b%5==0;
|
||||
CREATE INDEX t2a1 ON t2(a) WHERE a IS NOT NULL;
|
||||
SELECT count(*) FROM t2 WHERE a IS NOT NULL;
|
||||
}
|
||||
} {800}
|
||||
do_test index6-2.2 {
|
||||
execsql {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t2 WHERE a=5;
|
||||
}
|
||||
} {/.* TABLE t2 USING INDEX t2a1 .*/}
|
||||
do_test index6-2.3 {
|
||||
execsql {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t2 WHERE a IS NOT NULL;
|
||||
}
|
||||
} {/.* TABLE t2 USING INDEX t2a1 .*/}
|
||||
do_test index6-2.4 {
|
||||
execsql {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t2 WHERE a IS NULL;
|
||||
}
|
||||
} {~/.*INDEX t2a1.*/}
|
||||
|
||||
do_execsql_test index6-2.101 {
|
||||
DROP INDEX t2a1;
|
||||
UPDATE t2 SET a=b, b=b+10000;
|
||||
SELECT b FROM t2 WHERE a=15;
|
||||
} {10015}
|
||||
do_execsql_test index6-2.102 {
|
||||
CREATE INDEX t2a2 ON t2(a) WHERE a<100 OR a>200;
|
||||
SELECT b FROM t2 WHERE a=15;
|
||||
PRAGMA integrity_check;
|
||||
} {10015 ok}
|
||||
do_execsql_test index6-2.102eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT b FROM t2 WHERE a=15;
|
||||
} {~/.*INDEX t2a2.*/}
|
||||
do_execsql_test index6-2.103 {
|
||||
SELECT b FROM t2 WHERE a=15 AND a<100;
|
||||
} {10015}
|
||||
do_execsql_test index6-2.103eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT b FROM t2 WHERE a=15 AND a<100;
|
||||
} {/.*INDEX t2a2.*/}
|
||||
do_execsql_test index6-2.104 {
|
||||
SELECT b FROM t2 WHERE a=515 AND a>200;
|
||||
} {10515}
|
||||
do_execsql_test index6-2.104eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT b FROM t2 WHERE a=515 AND a>200;
|
||||
} {/.*INDEX t2a2.*/}
|
||||
|
||||
# Partial UNIQUE indices
|
||||
#
|
||||
do_execsql_test index6-3.1 {
|
||||
CREATE TABLE t3(a,b);
|
||||
INSERT INTO t3 SELECT value, value FROM nums WHERE value<200;
|
||||
UPDATE t3 SET a=999 WHERE b%5!=0;
|
||||
CREATE UNIQUE INDEX t3a ON t3(a) WHERE a<>999;
|
||||
} {}
|
||||
do_test index6-3.2 {
|
||||
# unable to insert a duplicate row a-value that is not 999.
|
||||
catchsql {
|
||||
INSERT INTO t3(a,b) VALUES(150, 'test1');
|
||||
}
|
||||
} {1 {column a is not unique}}
|
||||
do_test index6-3.3 {
|
||||
# can insert multiple rows with a==999 because such rows are not
|
||||
# part of the unique index.
|
||||
catchsql {
|
||||
INSERT INTO t3(a,b) VALUES(999, 'test1'), (999, 'test2');
|
||||
}
|
||||
} {0 {}}
|
||||
do_execsql_test index6-3.4 {
|
||||
SELECT count(*) FROM t3 WHERE a=999;
|
||||
} {162}
|
||||
integrity_check index6-3.5
|
||||
|
||||
do_execsql_test index6-4.0 {
|
||||
VACUUM;
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
|
||||
# Silently ignore database name qualifiers in partial indices.
|
||||
#
|
||||
do_execsql_test index6-5.0 {
|
||||
CREATE INDEX t3b ON t3(b) WHERE xyzzy.t3.b BETWEEN 5 AND 10;
|
||||
/* ^^^^^-- ignored */
|
||||
ANALYZE;
|
||||
SELECT count(*) FROM t3 WHERE t3.b BETWEEN 5 AND 10;
|
||||
SELECT stat+0 FROM sqlite_stat1 WHERE idx='t3b';
|
||||
} {6 6}
|
||||
|
||||
finish_test
|
@ -43,6 +43,19 @@ do_test loadext2-1.2 {
|
||||
}
|
||||
} {1 {no such function: cube}}
|
||||
|
||||
# Extensions loaders not currently registered
|
||||
#
|
||||
do_test loadext2-1.2.1 {
|
||||
sqlite3_cancel_auto_extension_sqr
|
||||
} {0}
|
||||
do_test loadext2-1.2.2 {
|
||||
sqlite3_cancel_auto_extension_sqr
|
||||
} {0}
|
||||
do_test loadext2-1.2.3 {
|
||||
sqlite3_cancel_auto_extension_sqr
|
||||
} {0}
|
||||
|
||||
|
||||
# Register auto-loaders. Still functions do not exist.
|
||||
#
|
||||
do_test loadext2-1.3 {
|
||||
@ -76,8 +89,19 @@ do_test loadext2-1.6 {
|
||||
|
||||
# Reset extension auto loading. Existing extensions still exist.
|
||||
#
|
||||
do_test loadext2-1.7 {
|
||||
sqlite3_reset_auto_extension
|
||||
do_test loadext2-1.7.1 {
|
||||
sqlite3_cancel_auto_extension_sqr
|
||||
} {1}
|
||||
do_test loadext2-1.7.2 {
|
||||
sqlite3_cancel_auto_extension_sqr
|
||||
} {0}
|
||||
do_test loadext2-1.7.3 {
|
||||
sqlite3_cancel_auto_extension_cube
|
||||
} {1}
|
||||
do_test loadext2-1.7.4 {
|
||||
sqlite3_cancel_auto_extension_cube
|
||||
} {0}
|
||||
do_test loadext2-1.7.5 {
|
||||
catchsql {
|
||||
SELECT sqr(2)
|
||||
}
|
||||
|
@ -699,5 +699,16 @@ do_test where2-11.4 {
|
||||
}
|
||||
} {4 8 10}
|
||||
|
||||
# Verify that the OR clause is used in an outer loop even when
|
||||
# the OR clause scores slightly better on an inner loop.
|
||||
do_execsql_test where2-12.1 {
|
||||
CREATE TABLE t12(x INTEGER PRIMARY KEY, y);
|
||||
CREATE INDEX t12y ON t12(y);
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT a.x, b.x
|
||||
FROM t12 AS a JOIN t12 AS b ON a.y=b.x
|
||||
WHERE (b.x=$abc OR b.y=$abc);
|
||||
} {/.*SEARCH TABLE t12 AS b .*SEARCH TABLE t12 AS b .*/}
|
||||
|
||||
|
||||
finish_test
|
||||
|
@ -212,8 +212,9 @@ 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')
|
||||
ORDER BY +a, +d;
|
||||
}
|
||||
} {2 2 2 4 3 3 3 4 0 0}
|
||||
} {2 2 2 4 3 3 3 4 0 1}
|
||||
|
||||
do_test where8-3.6 {
|
||||
# The first part of the WHERE clause in this query, (a=2 OR a=3) is
|
||||
@ -233,7 +234,7 @@ do_test where8-3.7 {
|
||||
WHERE a = 2 AND (d = a OR e = 'sixteen')
|
||||
ORDER BY t1.rowid
|
||||
}
|
||||
} {2 2 2 4 0 0}
|
||||
} {/2 2 2 4 0 [01]/}
|
||||
do_test where8-3.8 {
|
||||
execsql_status {
|
||||
SELECT a, d
|
||||
|
@ -246,8 +246,19 @@ mem function int integerify
|
||||
# [quote {hello world's}] == {'hello world''s'}
|
||||
#
|
||||
proc quote {txt} {
|
||||
regsub -all ' $txt '' q
|
||||
return '$q'
|
||||
return [string map {' ''} $txt]
|
||||
}
|
||||
|
||||
# Output a title line
|
||||
#
|
||||
proc titleline {title} {
|
||||
if {$title==""} {
|
||||
puts [string repeat * 79]
|
||||
} else {
|
||||
set len [string length $title]
|
||||
set stars [string repeat * [expr 79-$len-5]]
|
||||
puts "*** $title $stars"
|
||||
}
|
||||
}
|
||||
|
||||
# Generate a single line of output in the statistics section of the
|
||||
@ -255,7 +266,7 @@ proc quote {txt} {
|
||||
#
|
||||
proc statline {title value {extra {}}} {
|
||||
set len [string length $title]
|
||||
set dots [string range {......................................} $len end]
|
||||
set dots [string repeat . [expr 50-$len]]
|
||||
set len [string length $value]
|
||||
set sp2 [string range { } $len end]
|
||||
if {$extra ne ""} {
|
||||
@ -319,9 +330,7 @@ proc subreport {title where} {
|
||||
# Output the sub-report title, nicely decorated with * characters.
|
||||
#
|
||||
puts ""
|
||||
set len [string length $title]
|
||||
set stars [string repeat * [expr 65-$len]]
|
||||
puts "*** $title $stars"
|
||||
titleline $title
|
||||
puts ""
|
||||
|
||||
# Calculate statistics and store the results in TCL variables, as follows:
|
||||
@ -490,9 +499,6 @@ set user_percent [percent $user_payload $file_bytes]
|
||||
# Output the summary statistics calculated above.
|
||||
#
|
||||
puts "/** Disk-Space Utilization Report For $root_filename"
|
||||
catch {
|
||||
puts "*** As of [clock format [clock seconds] -format {%Y-%b-%d %H:%M:%S}]"
|
||||
}
|
||||
puts ""
|
||||
statline {Page size in bytes} $pageSize
|
||||
statline {Pages in the whole file (measured)} $file_pgcnt
|
||||
@ -517,16 +523,27 @@ statline {Bytes of user payload stored} $user_payload $user_percent
|
||||
# Output table rankings
|
||||
#
|
||||
puts ""
|
||||
puts "*** Page counts for all tables with their indices ********************"
|
||||
titleline "Page counts for all tables with their indices"
|
||||
puts ""
|
||||
mem eval {SELECT tblname, count(*) AS cnt,
|
||||
int(sum(int_pages+leaf_pages+ovfl_pages)) AS size
|
||||
FROM space_used GROUP BY tblname ORDER BY size+0 DESC, tblname} {} {
|
||||
statline [string toupper $tblname] $size [percent $size $file_pgcnt]
|
||||
}
|
||||
puts ""
|
||||
titleline "Page counts for all tables and indices separately"
|
||||
puts ""
|
||||
mem eval {
|
||||
SELECT
|
||||
upper(name) AS nm,
|
||||
int(int_pages+leaf_pages+ovfl_pages) AS size
|
||||
FROM space_used
|
||||
ORDER BY size+0 DESC, name} {} {
|
||||
statline $nm $size [percent $size $file_pgcnt]
|
||||
}
|
||||
if {$isCompressed} {
|
||||
puts ""
|
||||
puts "*** Bytes of disk space used after compression ***********************"
|
||||
titleline "Bytes of disk space used after compression"
|
||||
puts ""
|
||||
set csum 0
|
||||
mem eval {SELECT tblname,
|
||||
@ -554,13 +571,22 @@ if {$nindex>0} {
|
||||
}
|
||||
foreach tbl [mem eval {SELECT name FROM space_used WHERE NOT is_index
|
||||
ORDER BY name}] {
|
||||
regsub ' $tbl '' qn
|
||||
set qn [quote $tbl]
|
||||
set name [string toupper $tbl]
|
||||
set n [mem eval "SELECT count(*) FROM space_used WHERE tblname='$qn'"]
|
||||
set n [mem eval {SELECT count(*) FROM space_used WHERE tblname=$tbl}]
|
||||
if {$n>1} {
|
||||
set idxlist [mem eval "SELECT name FROM space_used
|
||||
WHERE tblname='$qn' AND is_index
|
||||
ORDER BY 1"]
|
||||
subreport "Table $name and all its indices" "tblname='$qn'"
|
||||
subreport "Table $name w/o any indices" "name='$qn'"
|
||||
subreport "Indices of table $name" "tblname='$qn' AND is_index"
|
||||
if {[llength $idxlist]>1} {
|
||||
subreport "Indices of table $name" "tblname='$qn' AND is_index"
|
||||
}
|
||||
foreach idx $idxlist {
|
||||
set qidx [quote $idx]
|
||||
subreport "Index [string toupper $idx] of table $name" "name='$qidx'"
|
||||
}
|
||||
} else {
|
||||
subreport "Table $name" "name='$qn'"
|
||||
}
|
||||
@ -568,9 +594,9 @@ foreach tbl [mem eval {SELECT name FROM space_used WHERE NOT is_index
|
||||
|
||||
# Output instructions on what the numbers above mean.
|
||||
#
|
||||
puts ""
|
||||
titleline Definitions
|
||||
puts {
|
||||
*** Definitions ******************************************************
|
||||
|
||||
Page size in bytes
|
||||
|
||||
The number of bytes in a single page of the database file.
|
||||
@ -722,7 +748,7 @@ Unused bytes on all pages
|
||||
# Output a dump of the in-memory database. This can be used for more
|
||||
# complex offline analysis.
|
||||
#
|
||||
puts "**********************************************************************"
|
||||
titleline {}
|
||||
puts "The entire text of this report can be sourced into any SQL database"
|
||||
puts "engine for further analysis. All of the text above is an SQL comment."
|
||||
puts "The data used to generate this report follows:"
|
||||
|
Loading…
Reference in New Issue
Block a user