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:
drh 2013-08-02 20:44:48 +00:00
commit 7fb30bd0dd
42 changed files with 1323 additions and 470 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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);
}
}
/*

View File

@ -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

View File

@ -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

View File

@ -1 +1 @@
8dfc0b78c38e519b64a796243ff7c0aff688ff36
7e1acb390770d1bd189fac7a3a7f96106f96e3a4

View File

@ -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);
}
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{
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);
}
if( pParse->nMem<regRec ) pParse->nMem = regRec;
}
@ -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( 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 ){

View File

@ -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);

View File

@ -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 */
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);

View File

@ -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 );
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{
inReg = sqlite3ExprCodeGetColumn(pParse, pExpr->pTab,
pExpr->iColumn, pExpr->iTable, target,
pExpr->op2);
/* 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;
}
}

View File

@ -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

View File

@ -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.
*/

View File

@ -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

View File

@ -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 */

View File

@ -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}

View File

@ -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);

View File

@ -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 ){

View File

@ -240,6 +240,14 @@ static int lookupName(
** resulting in an appropriate error message toward the end of this routine
*/
if( zDb ){
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 ){
@ -248,6 +256,7 @@ static int lookupName(
}
}
}
}
/* Start at the inner-most context and move outward until a match is found */
while( pNC && cnt==0 ){
@ -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;
}
}
}
}

View File

@ -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);

View File

@ -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 ){

View File

@ -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>
*/

View File

@ -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 *);

View File

@ -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;

View File

@ -28,6 +28,7 @@
#include "sqlite3.h"
#include "sqliteInt.h"
#include <tcl.h>
typedef struct Testvfs Testvfs;
typedef struct TestvfsShm TestvfsShm;

View File

@ -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;

View File

@ -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 ){
assert( pOp->p4type==P4_FUNCDEF );
ctx.pFunc = pOp->p4.pFunc;
ctx.pVdbeFunc = 0;
}else{
ctx.pVdbeFunc = (VdbeFunc*)pOp->p4.pVdbeFunc;
ctx.pFunc = ctx.pVdbeFunc->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

View File

@ -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*);

View File

@ -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 */
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 */
} apAux[1]; /* One slot for each function argument */
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*);

View File

@ -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;

View File

@ -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];

View File

@ -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;

View File

@ -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;
/* 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;
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 = 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 = '*';

View File

@ -44,6 +44,8 @@ ifcapable !stat3 {
# 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 }
db function var getvar
@ -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

View File

@ -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
View 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

View File

@ -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 {

View File

@ -716,5 +716,22 @@ do_test index-20.2 {
}
} {}
# 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
View 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

View File

@ -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)
}

View File

@ -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

View File

@ -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

View File

@ -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'"
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:"