mirror of
https://github.com/sqlite/sqlite.git
synced 2025-04-26 11:28:58 +03:00
Merge the latest 3.8.6 beta changes from trunk.
FossilOrigin-Name: 68a6d5e2f43702c78057ae2f2a7345c981d24e17
This commit is contained in:
commit
58c4cbe152
66
manifest
66
manifest
@ -1,5 +1,5 @@
|
||||
C Merge\sthe\sfix\sfor\sthe\sCREATE\sUNIQUE\sINDEX\sproblem\sinto\sthe\ssessions\sbranch.
|
||||
D 2014-07-30T14:29:54.721
|
||||
C Merge\sthe\slatest\s3.8.6\sbeta\schanges\sfrom\strunk.
|
||||
D 2014-08-06T01:25:47.611
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 639859a6f81bd15921ccd56ddbd6dfd335278377
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -175,30 +175,30 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 3d8b83c91651f53472ca17599dae3457b8b89494
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c b00900877f766f116f9e16116f1ccacdc21d82f1
|
||||
F src/analyze.c de34a73b86db9dc3a16beef12cc5573c50223956
|
||||
F src/analyze.c f98a351908da29f7b44741cfeb9eb20dda648ba0
|
||||
F src/attach.c 3801129015ef59d76bf23c95ef9b0069d18a0c52
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53
|
||||
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
|
||||
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c b5531339cd826af46b9621e4a9323971a9380e12
|
||||
F src/btree.c 99d162e57af6e72ffd7db5bf79568a134cd87d5b
|
||||
F src/btree.h 4245a349bfe09611d7ff887dbc3a80cee8b7955a
|
||||
F src/btreeInt.h cf180d86b2e9e418f638d65baa425c4c69c0e0e3
|
||||
F src/build.c 7ba21d8f0f5f1e8b5a0ed21aab9be2b39d1af516
|
||||
F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98
|
||||
F src/build.c 5abf794fe8a605f2005b422e98a3cedad9b9ef5b
|
||||
F src/callback.c fcff28cf0df2403dd2f313bb8d1b8f31f6f3cd64
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a
|
||||
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
|
||||
F src/delete.c 50b74c1dde25d1ebcb4fa5c870762e6470ee46f1
|
||||
F src/expr.c b989d07fc7c8780fff77365a4fc59881223e340c
|
||||
F src/expr.c f749009cf4a8534efb5e0d5cd7c9fb1fb0f2836c
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c a549cff9fe8b736cdae21650ea0af6de29b77619
|
||||
F src/fkey.c 8545f3b36da47473e10800ea4fb0810fd4062514
|
||||
F src/func.c 3bc223ea36cd29a91c481485343d0ee4257ab8dc
|
||||
F src/global.c 1e4bd956dc2f608f87d2a929abc4a20db65f30e4
|
||||
F src/hash.c d139319967164f139c8d1bb8a11b14db9c4ba3cd
|
||||
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c 3f5e6cb2cfea0c20a11d51da943395ac480122cb
|
||||
F src/insert.c b1f57e168d39fed8a0d3d891bf38091b104dd707
|
||||
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
|
||||
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
||||
@ -211,18 +211,18 @@ F src/mem2.c dce31758da87ec2cfa52ba4c5df1aed6e07d8e8f
|
||||
F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
|
||||
F src/mem5.c 74670012946c4adc8a6ad84d03acc80959c3e529
|
||||
F src/memjournal.c 0683aac6cab6ec2b5374c0db37c0deb2436a3785
|
||||
F src/mutex.c d3b66a569368015e0fcb1ac15f81c119f504d3bc
|
||||
F src/mutex.c 84a073c9a23a8d7bdd2ea832522d1730df18812c
|
||||
F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea
|
||||
F src/mutex_noop.c 7682796b7d8d39bf1c138248858efcd10c9e1553
|
||||
F src/mutex_unix.c c3a4e00f96ba068a8dbef34084465979aaf369cc
|
||||
F src/mutex_w32.c 45020ed78735a202ff14efcf19415d29f556f16d
|
||||
F src/mutex_noop.c f3f09fd7a2eb4287cfc799753ffc30380e7b71a1
|
||||
F src/mutex_unix.c 1b10d5413dfc794364a8adf3eb3a192926b43fa3
|
||||
F src/mutex_w32.c c50939b72368f1cfbddb58520372081a50558548
|
||||
F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
|
||||
F src/os.c 1b147e4cf7cc39e618115c14a086aed44bc91ace
|
||||
F src/os.h 60d419395e32a8029fa380a80a3da2e9030f635e
|
||||
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
|
||||
F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
|
||||
F src/os_unix.c a7baf1b30f3c58ba20b813e01aab23b18ae44f85
|
||||
F src/os_win.c c29e3a80b47ebdbabd61fc3d4015e52d2654d8c5
|
||||
F src/os_win.c e5f0fc446a682b70db3397d14cca9806d9a15d12
|
||||
F src/os_win.h 057344a6720b4c8405d9bd98f58cb37a6ee46c25
|
||||
F src/pager.c f6bb1fa6cdf2062f2d8aec3e64db302bca519ab8
|
||||
F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428
|
||||
@ -230,23 +230,23 @@ F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0
|
||||
F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2
|
||||
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
|
||||
F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c
|
||||
F src/pragma.c 30f3b2ac09fef58320375d78e0e18b976198fc69
|
||||
F src/pragma.c d10ef67c4de79f78188b965b4b7988aff1d66f2e
|
||||
F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337
|
||||
F src/printf.c af06f66927919730f03479fed6ae9854f73419f4
|
||||
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
|
||||
F src/resolve.c 5fc110baeacf120a73fe34e103f052632ff11a02
|
||||
F src/rowset.c a9c9aae3234b44a6d7c6f5a3cadf90dce1e627be
|
||||
F src/select.c 6762c62e11b504aa014edceab8886495165e3a77
|
||||
F src/select.c 1529c49075464c5a95fde77314073612b1b8d595
|
||||
F src/shell.c 191129c3f7a9cf241aea90ff6a6be3e74d3767f0
|
||||
F src/sqlite.h.in c5940e8fdc6b2b046bb00a07edb1cc3fa342bd5d
|
||||
F src/sqlite.h.in 6b18f91758d1816f8cc2596d7a2c89c9db348ff5
|
||||
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||
F src/sqliteInt.h 56c7fe562722601d83a53bd8b5262a975851bf95
|
||||
F src/sqliteInt.h d60dbbadfd64374a5a2f362fc6f45899540c2c8e
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c 7ada527ce7916adcabad7997c10f09680aac7c9b
|
||||
F src/test1.c 3c8bc491d2f8de5adbbf306533cefc343c733927
|
||||
F src/test1.c 14409a611e9c27c6c522c610bbff5561f05c1558
|
||||
F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712
|
||||
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
|
||||
F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
|
||||
@ -271,8 +271,8 @@ F src/test_intarray.h 2ece66438cfd177b78d1bfda7a4180cd3a10844d
|
||||
F src/test_journal.c f5c0a05b7b3d5930db769b5ee6c3766dc2221a64
|
||||
F src/test_loadext.c a5251f956ab6af21e138dc1f9c0399394a510cb4
|
||||
F src/test_malloc.c 1ff5b1243d96124c9a180f3b89424820a1f337f3
|
||||
F src/test_multiplex.c 9f304bf04170c91c0318238d512df2da039eb1c8
|
||||
F src/test_multiplex.h 110a8c4d356e0aa464ca8730375608a9a0b61ae1
|
||||
F src/test_multiplex.c ca90057438b63bf0840ebb84d0ef050624519a76
|
||||
F src/test_multiplex.h c08e4e8f8651f0c5e0509b138ff4d5b43ed1f5d3
|
||||
F src/test_mutex.c 293042d623ebba969160f471a82aa1551626454f
|
||||
F src/test_onefile.c 0396f220561f3b4eedc450cef26d40c593c69a25
|
||||
F src/test_osinst.c 3d0340bc31a9f3d8a3547e0272373e80f78dde25
|
||||
@ -293,11 +293,11 @@ F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c ae45399d6252b4d736af43bee1576ce7bff86aec
|
||||
F src/trigger.c 66f3470b03b52b395e839155786966e3e037fddb
|
||||
F src/update.c 0f16e1d55d642a7ae3199bd0c2c1f51a7ef1b9d4
|
||||
F src/update.c b0f38fda25d532343d54b7dc49f55ab73e92ca45
|
||||
F src/utf.c a0314e637768a030e6e84a957d0c4f6ba910cc05
|
||||
F src/util.c 3076bdd51cdbf60a6e2e57fada745be37133c73e
|
||||
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
||||
F src/vdbe.c 79cd84435224f9f4edd420467f3a7bad29fffa8f
|
||||
F src/vdbe.c 54fa84fdd992886dcb1a4c0cec2ae686d2d18b2b
|
||||
F src/vdbe.h ca3b6df299adce6e2f499c57e42ae54f142ae823
|
||||
F src/vdbeInt.h 5eee1752eff410de9373196e2b327f7deefb3920
|
||||
F src/vdbeapi.c 52335de5ff97bba93d6779d8df87feab5d53d7df
|
||||
@ -310,7 +310,7 @@ F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
|
||||
F src/wal.c 264df50a1b33124130b23180ded2e2c5663c652a
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
|
||||
F src/where.c 4dfcd80380d154be434c4b51e890e17ce9754b3e
|
||||
F src/where.c ce1b9a3a2573033cd15e0882719db7f211f21cdd
|
||||
F src/whereInt.h 929c1349b5355fd44f22cee5c14d72b3329c58a6
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
@ -621,7 +621,7 @@ F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
|
||||
F test/in.test 047c4671328e9032ab95666a67021adbbd36e98e
|
||||
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
||||
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
|
||||
F test/in4.test 41c1c031aa46b1eb4411df2687ed2ed498da23b5
|
||||
F test/in4.test d2b38cba404bc4320f4fe1b595b3d163f212c068
|
||||
F test/in5.test 99f9a40af01711b06d2d614ecfe96129f334fba3
|
||||
F test/incrblob.test e81846d214f3637622620fbde7cd526781cfe328
|
||||
F test/incrblob2.test bf4d549aa4a466d7fbe3e3a3693d3861263d5600
|
||||
@ -733,7 +733,7 @@ F test/mmap1.test 93d167b328255cbe6679fe1e1a23be1b1197d07b
|
||||
F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022
|
||||
F test/mmap3.test c92273e16eb8d23c1d55c9815b446bb72ef0512e
|
||||
F test/mmapfault.test d4c9eff9cd8c2dc14bc43e71e042f175b0a26fe3
|
||||
F test/multiplex.test e08cc7177bd6d85990ee1d71100bb6c684c02256
|
||||
F test/multiplex.test efd015ca0b5b4a57dc9535b8feb1273eebeadb60
|
||||
F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a
|
||||
F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101
|
||||
F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41
|
||||
@ -768,7 +768,7 @@ F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d
|
||||
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
|
||||
F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54
|
||||
F test/permutations.test bf568516e21758f2961a4612f29dc422d3ab75c1
|
||||
F test/pragma.test adb21a90875bc54a880fa939c4d7c46598905aa0
|
||||
F test/pragma.test 19d0241a007bcdd77fc2606ec60fc60357e7fc8b
|
||||
F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13
|
||||
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
|
||||
F test/printf2.test bed79b4c3e5da08ba88ad637c0bf62586843cfb1
|
||||
@ -871,14 +871,14 @@ F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2
|
||||
F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85
|
||||
F test/syscall.test d2fdaad713f103ac611fe7ef9b724c7b69f8149c
|
||||
F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6
|
||||
F test/table.test 580d23530187026d4502fae74a490f0408cf2cc7
|
||||
F test/table.test 2a1d2fa52c531de5915f28023747d9a8c27b6f31
|
||||
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
|
||||
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
|
||||
F test/tclsqlite.test a7308276aad2e6c0bfb5b0414424dd0d9cc0cad7
|
||||
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
|
||||
F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1
|
||||
F test/tester.tcl 8bab16cd983b4207203d82b7de229aa7b457f575
|
||||
F test/tester.tcl eac48cc21d519ac33a4fbaa3b425d178861fe741
|
||||
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@ -916,7 +916,7 @@ F test/tkt-78e04e52ea.test 813779f8888f3ca226df656c4eef078f9635f3c9
|
||||
F test/tkt-7a31705a7e6.test e75a2bba4eec801b92c8040eb22096ac6d35e844
|
||||
F test/tkt-7bbfb7d442.test 7b2cd79c7a17ae6750e75ec1a7846712a69c9d18
|
||||
F test/tkt-80ba201079.test 105a721e6aad0ae3c5946d7615d1e4d03f6145b8
|
||||
F test/tkt-80e031a00f.test 9a154173461a4dbe2de49cda73963e04842d52f7
|
||||
F test/tkt-80e031a00f.test f50046f474ecf67ad5c50cd9200da04ff887d7cd
|
||||
F test/tkt-8454a207b9.test c583a9f814a82a2b5ba95207f55001c9f0cd816c
|
||||
F test/tkt-868145d012.test a5f941107ece6a64410ca4755c6329b7eb57a356
|
||||
F test/tkt-8c63ff0ec.test 258b7fc8d7e4e1cb5362c7d65c143528b9c4cbed
|
||||
@ -1200,7 +1200,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 8f1beeade0ddf802900c9d203a4fd678d1190394 6b785e92f279cb65746834d5cd25594fd3333342
|
||||
R 4306541d4063ef0a1799e70c4c3d4ff7
|
||||
P 43401ee624587ffa166c3cda7e5265ad0d81da5c 717245d48714c08156c9b7636aaa6c3a402bad66
|
||||
R dc185340dec02c23864326e2a38aabfb
|
||||
U drh
|
||||
Z 69e112d4dad31a7cb28801f346a66d8a
|
||||
Z 89e6d570704a9eb31c76806cdd19debb
|
||||
|
@ -1 +1 @@
|
||||
43401ee624587ffa166c3cda7e5265ad0d81da5c
|
||||
68a6d5e2f43702c78057ae2f2a7345c981d24e17
|
@ -1129,7 +1129,7 @@ static void analyzeOneTable(
|
||||
*/
|
||||
sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
addrNextRow = sqlite3VdbeCurrentAddr(v);
|
||||
if( nColTest==1 && pIdx->nKeyCol==1 && pIdx->onError!=OE_None ){
|
||||
if( nColTest==1 && pIdx->nKeyCol==1 && IsUniqueIndex(pIdx) ){
|
||||
/* For a single-column UNIQUE index, once we have found a non-NULL
|
||||
** row, we know that all the rest will be distinct, so skip
|
||||
** subsequent distinctness tests. */
|
||||
|
@ -162,7 +162,7 @@ static int hasSharedCacheTableLock(
|
||||
** the correct locks are held. So do not bother - just return true.
|
||||
** This case does not come up very often anyhow.
|
||||
*/
|
||||
if( isIndex && (!pSchema || (pSchema->flags&DB_SchemaLoaded)==0) ){
|
||||
if( isIndex && (!pSchema || (pSchema->schemaFlags&DB_SchemaLoaded)==0) ){
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
10
src/build.c
10
src/build.c
@ -2130,7 +2130,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
|
||||
pSelTab->aCol = 0;
|
||||
sqlite3DeleteTable(db, pSelTab);
|
||||
assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
|
||||
pTable->pSchema->flags |= DB_UnresetViews;
|
||||
pTable->pSchema->schemaFlags |= DB_UnresetViews;
|
||||
}else{
|
||||
pTable->nCol = 0;
|
||||
nErr++;
|
||||
@ -2707,7 +2707,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||
|
||||
addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v);
|
||||
assert( pKey!=0 || db->mallocFailed || pParse->nErr );
|
||||
if( pIndex->onError!=OE_None && pKey!=0 ){
|
||||
if( IsUniqueIndex(pIndex) && pKey!=0 ){
|
||||
int j2 = sqlite3VdbeCurrentAddr(v) + 3;
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
|
||||
addr2 = sqlite3VdbeCurrentAddr(v);
|
||||
@ -3104,9 +3104,9 @@ Index *sqlite3CreateIndex(
|
||||
Index *pIdx;
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
int k;
|
||||
assert( pIdx->onError!=OE_None );
|
||||
assert( IsUniqueIndex(pIdx) );
|
||||
assert( pIdx->idxType!=SQLITE_IDXTYPE_APPDEF );
|
||||
assert( pIndex->onError!=OE_None );
|
||||
assert( IsUniqueIndex(pIndex) );
|
||||
|
||||
if( pIdx->nKeyCol!=pIndex->nKeyCol ) continue;
|
||||
for(k=0; k<pIdx->nKeyCol; k++){
|
||||
@ -3297,7 +3297,7 @@ void sqlite3DefaultRowEst(Index *pIdx){
|
||||
}
|
||||
|
||||
assert( 0==sqlite3LogEst(1) );
|
||||
if( pIdx->onError!=OE_None ) a[pIdx->nKeyCol] = 0;
|
||||
if( IsUniqueIndex(pIdx) ) a[pIdx->nKeyCol] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -447,9 +447,9 @@ void sqlite3SchemaClear(void *p){
|
||||
sqlite3HashClear(&temp1);
|
||||
sqlite3HashClear(&pSchema->fkeyHash);
|
||||
pSchema->pSeqTab = 0;
|
||||
if( pSchema->flags & DB_SchemaLoaded ){
|
||||
if( pSchema->schemaFlags & DB_SchemaLoaded ){
|
||||
pSchema->iGeneration++;
|
||||
pSchema->flags &= ~DB_SchemaLoaded;
|
||||
pSchema->schemaFlags &= ~DB_SchemaLoaded;
|
||||
}
|
||||
}
|
||||
|
||||
|
360
src/expr.c
360
src/expr.c
@ -1368,6 +1368,9 @@ int sqlite3ExprCanBeNull(const Expr *p){
|
||||
case TK_FLOAT:
|
||||
case TK_BLOB:
|
||||
return 0;
|
||||
case TK_COLUMN:
|
||||
assert( p->pTab!=0 );
|
||||
return p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
@ -1475,6 +1478,40 @@ int sqlite3CodeOnce(Parse *pParse){
|
||||
return sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that checks the left-most column of index table iCur to see if
|
||||
** it contains any NULL entries. Cause the register at regHasNull to be set
|
||||
** to a non-NULL value if iCur contains no NULLs. Cause register regHasNull
|
||||
** to be set to NULL if iCur contains one or more NULL values.
|
||||
*/
|
||||
static void sqlite3SetHasNullFlag(Vdbe *v, int iCur, int regHasNull){
|
||||
int j1;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regHasNull);
|
||||
j1 = sqlite3VdbeAddOp1(v, OP_Rewind, iCur); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_Column, iCur, 0, regHasNull);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
|
||||
VdbeComment((v, "first_entry_in(%d)", iCur));
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
}
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
/*
|
||||
** The argument is an IN operator with a list (not a subquery) on the
|
||||
** right-hand side. Return TRUE if that list is constant.
|
||||
*/
|
||||
static int sqlite3InRhsIsConstant(Expr *pIn){
|
||||
Expr *pLHS;
|
||||
int res;
|
||||
assert( !ExprHasProperty(pIn, EP_xIsSelect) );
|
||||
pLHS = pIn->pLeft;
|
||||
pIn->pLeft = 0;
|
||||
res = sqlite3ExprIsConstant(pIn);
|
||||
pIn->pLeft = pLHS;
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This function is used by the implementation of the IN (...) operator.
|
||||
** The pX parameter is the expression on the RHS of the IN operator, which
|
||||
@ -1484,7 +1521,7 @@ int sqlite3CodeOnce(Parse *pParse){
|
||||
** be used either to test for membership in the RHS set or to iterate through
|
||||
** all members of the RHS set, skipping duplicates.
|
||||
**
|
||||
** A cursor is opened on the b-tree object that the RHS of the IN operator
|
||||
** A cursor is opened on the b-tree object that is the RHS of the IN operator
|
||||
** and pX->iTable is set to the index of that cursor.
|
||||
**
|
||||
** The returned value of this function indicates the b-tree type, as follows:
|
||||
@ -1494,6 +1531,8 @@ int sqlite3CodeOnce(Parse *pParse){
|
||||
** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index.
|
||||
** IN_INDEX_EPH - The cursor was opened on a specially created and
|
||||
** populated epheremal table.
|
||||
** IN_INDEX_NOOP - No cursor was allocated. The IN operator must be
|
||||
** implemented as a sequence of comparisons.
|
||||
**
|
||||
** An existing b-tree might be used if the RHS expression pX is a simple
|
||||
** subquery such as:
|
||||
@ -1503,51 +1542,56 @@ int sqlite3CodeOnce(Parse *pParse){
|
||||
** If the RHS of the IN operator is a list or a more complex subquery, then
|
||||
** an ephemeral table might need to be generated from the RHS and then
|
||||
** pX->iTable made to point to the ephermeral table instead of an
|
||||
** existing table.
|
||||
** existing table.
|
||||
**
|
||||
** If the prNotFound parameter is 0, then the b-tree will be used to iterate
|
||||
** through the set members, skipping any duplicates. In this case an
|
||||
** epheremal table must be used unless the selected <column> is guaranteed
|
||||
** The inFlags parameter must contain exactly one of the bits
|
||||
** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP. If inFlags contains
|
||||
** IN_INDEX_MEMBERSHIP, then the generated table will be used for a
|
||||
** fast membership test. When the IN_INDEX_LOOP bit is set, the
|
||||
** IN index will be used to loop over all values of the RHS of the
|
||||
** IN operator.
|
||||
**
|
||||
** When IN_INDEX_LOOP is used (and the b-tree will be used to iterate
|
||||
** through the set members) then the b-tree must not contain duplicates.
|
||||
** An epheremal table must be used unless the selected <column> is guaranteed
|
||||
** to be unique - either because it is an INTEGER PRIMARY KEY or it
|
||||
** has a UNIQUE constraint or UNIQUE index.
|
||||
**
|
||||
** If the prNotFound parameter is not 0, then the b-tree will be used
|
||||
** for fast set membership tests. In this case an epheremal table must
|
||||
** When IN_INDEX_MEMBERSHIP is used (and the b-tree will be used
|
||||
** for fast set membership tests) then an epheremal table must
|
||||
** be used unless <column> is an INTEGER PRIMARY KEY or an index can
|
||||
** be found with <column> as its left-most column.
|
||||
**
|
||||
** If the IN_INDEX_NOOP_OK and IN_INDEX_MEMBERSHIP are both set and
|
||||
** if the RHS of the IN operator is a list (not a subquery) then this
|
||||
** routine might decide that creating an ephemeral b-tree for membership
|
||||
** testing is too expensive and return IN_INDEX_NOOP. In that case, the
|
||||
** calling routine should implement the IN operator using a sequence
|
||||
** of Eq or Ne comparison operations.
|
||||
**
|
||||
** When the b-tree is being used for membership tests, the calling function
|
||||
** needs to know whether or not the structure contains an SQL NULL
|
||||
** value in order to correctly evaluate expressions like "X IN (Y, Z)".
|
||||
** If there is any chance that the (...) might contain a NULL value at
|
||||
** might need to know whether or not the RHS side of the IN operator
|
||||
** contains a NULL. If prRhsHasNull is not a NULL pointer and
|
||||
** if there is any chance that the (...) might contain a NULL value at
|
||||
** runtime, then a register is allocated and the register number written
|
||||
** to *prNotFound. If there is no chance that the (...) contains a
|
||||
** NULL value, then *prNotFound is left unchanged.
|
||||
** to *prRhsHasNull. If there is no chance that the (...) contains a
|
||||
** NULL value, then *prRhsHasNull is left unchanged.
|
||||
**
|
||||
** If a register is allocated and its location stored in *prNotFound, then
|
||||
** its initial value is NULL. If the (...) does not remain constant
|
||||
** for the duration of the query (i.e. the SELECT within the (...)
|
||||
** is a correlated subquery) then the value of the allocated register is
|
||||
** reset to NULL each time the subquery is rerun. This allows the
|
||||
** caller to use vdbe code equivalent to the following:
|
||||
**
|
||||
** if( register==NULL ){
|
||||
** has_null = <test if data structure contains null>
|
||||
** register = 1
|
||||
** }
|
||||
**
|
||||
** in order to avoid running the <test if data structure contains null>
|
||||
** test more often than is necessary.
|
||||
** If a register is allocated and its location stored in *prRhsHasNull, then
|
||||
** the value in that register will be NULL if the b-tree contains one or more
|
||||
** NULL values, and it will be some non-NULL value if the b-tree contains no
|
||||
** NULL values.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
|
||||
Select *p; /* SELECT to the right of IN operator */
|
||||
int eType = 0; /* Type of RHS table. IN_INDEX_* */
|
||||
int iTab = pParse->nTab++; /* Cursor of the RHS table */
|
||||
int mustBeUnique = (prNotFound==0); /* True if RHS must be unique */
|
||||
int mustBeUnique; /* True if RHS must be unique */
|
||||
Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
|
||||
|
||||
assert( pX->op==TK_IN );
|
||||
mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0;
|
||||
|
||||
/* Check to see if an existing table or index can be used to
|
||||
** satisfy the query. This is preferable to generating a new
|
||||
@ -1604,7 +1648,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){
|
||||
if( (pIdx->aiColumn[0]==iCol)
|
||||
&& sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq
|
||||
&& (!mustBeUnique || (pIdx->nKeyCol==1 && pIdx->onError!=OE_None))
|
||||
&& (!mustBeUnique || (pIdx->nKeyCol==1 && IsUniqueIndex(pIdx)))
|
||||
){
|
||||
int iAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb);
|
||||
@ -1613,9 +1657,9 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
|
||||
eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
|
||||
|
||||
if( prNotFound && !pTab->aCol[iCol].notNull ){
|
||||
*prNotFound = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
|
||||
if( prRhsHasNull && !pTab->aCol[iCol].notNull ){
|
||||
*prRhsHasNull = ++pParse->nMem;
|
||||
sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull);
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, iAddr);
|
||||
}
|
||||
@ -1623,21 +1667,36 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
}
|
||||
}
|
||||
|
||||
/* If no preexisting index is available for the IN clause
|
||||
** and IN_INDEX_NOOP is an allowed reply
|
||||
** and the RHS of the IN operator is a list, not a subquery
|
||||
** and the RHS is not contant or has two or fewer terms,
|
||||
** then it is not worth creating an ephermeral table to evaluate
|
||||
** the IN operator so return IN_INDEX_NOOP.
|
||||
*/
|
||||
if( eType==0
|
||||
&& (inFlags & IN_INDEX_NOOP_OK)
|
||||
&& !ExprHasProperty(pX, EP_xIsSelect)
|
||||
&& (!sqlite3InRhsIsConstant(pX) || pX->x.pList->nExpr<=2)
|
||||
){
|
||||
eType = IN_INDEX_NOOP;
|
||||
}
|
||||
|
||||
|
||||
if( eType==0 ){
|
||||
/* Could not found an existing table or index to use as the RHS b-tree.
|
||||
/* Could not find an existing table or index to use as the RHS b-tree.
|
||||
** We will have to generate an ephemeral table to do the job.
|
||||
*/
|
||||
u32 savedNQueryLoop = pParse->nQueryLoop;
|
||||
int rMayHaveNull = 0;
|
||||
eType = IN_INDEX_EPH;
|
||||
if( prNotFound ){
|
||||
*prNotFound = rMayHaveNull = ++pParse->nMem;
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
|
||||
}else{
|
||||
if( inFlags & IN_INDEX_LOOP ){
|
||||
pParse->nQueryLoop = 0;
|
||||
if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){
|
||||
eType = IN_INDEX_ROWID;
|
||||
}
|
||||
}else if( prRhsHasNull ){
|
||||
*prRhsHasNull = rMayHaveNull = ++pParse->nMem;
|
||||
}
|
||||
sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID);
|
||||
pParse->nQueryLoop = savedNQueryLoop;
|
||||
@ -1668,15 +1727,9 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
**
|
||||
** If rMayHaveNull is non-zero, that means that the operation is an IN
|
||||
** (not a SELECT or EXISTS) and that the RHS might contains NULLs.
|
||||
** Furthermore, the IN is in a WHERE clause and that we really want
|
||||
** to iterate over the RHS of the IN operator in order to quickly locate
|
||||
** all corresponding LHS elements. All this routine does is initialize
|
||||
** the register given by rMayHaveNull to NULL. Calling routines will take
|
||||
** care of changing this register value to non-NULL if the RHS is NULL-free.
|
||||
**
|
||||
** If rMayHaveNull is zero, that means that the subquery is being used
|
||||
** for membership testing only. There is no need to initialize any
|
||||
** registers to indicate the presence or absence of NULLs on the RHS.
|
||||
** All this routine does is initialize the register given by rMayHaveNull
|
||||
** to NULL. Calling routines will take care of changing this register
|
||||
** value to non-NULL if the RHS is NULL-free.
|
||||
**
|
||||
** For a SELECT or EXISTS operator, return the register that holds the
|
||||
** result. For IN operators or if an error occurs, the return value is 0.
|
||||
@ -1685,10 +1738,10 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
int sqlite3CodeSubselect(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Expr *pExpr, /* The IN, SELECT, or EXISTS operator */
|
||||
int rMayHaveNull, /* Register that records whether NULLs exist in RHS */
|
||||
int rHasNullFlag, /* Register that records whether NULLs exist in RHS */
|
||||
int isRowid /* If true, LHS of IN operator is a rowid */
|
||||
){
|
||||
int testAddr = -1; /* One-time test address */
|
||||
int jmpIfDynamic = -1; /* One-time test address */
|
||||
int rReg = 0; /* Register storing resulting */
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
if( NEVER(v==0) ) return 0;
|
||||
@ -1705,13 +1758,13 @@ int sqlite3CodeSubselect(
|
||||
** save the results, and reuse the same result on subsequent invocations.
|
||||
*/
|
||||
if( !ExprHasProperty(pExpr, EP_VarSelect) ){
|
||||
testAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
|
||||
jmpIfDynamic = sqlite3CodeOnce(pParse); VdbeCoverage(v);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
if( pParse->explain==2 ){
|
||||
char *zMsg = sqlite3MPrintf(
|
||||
pParse->db, "EXECUTE %s%s SUBQUERY %d", testAddr>=0?"":"CORRELATED ",
|
||||
pParse->db, "EXECUTE %s%s SUBQUERY %d", jmpIfDynamic>=0?"":"CORRELATED ",
|
||||
pExpr->op==TK_IN?"LIST":"SCALAR", pParse->iNextSelectId
|
||||
);
|
||||
sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC);
|
||||
@ -1725,10 +1778,6 @@ int sqlite3CodeSubselect(
|
||||
Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */
|
||||
KeyInfo *pKeyInfo = 0; /* Key information */
|
||||
|
||||
if( rMayHaveNull ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, rMayHaveNull);
|
||||
}
|
||||
|
||||
affinity = sqlite3ExprAffinity(pLeft);
|
||||
|
||||
/* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)'
|
||||
@ -1754,6 +1803,7 @@ int sqlite3CodeSubselect(
|
||||
** Generate code to write the results of the select into the temporary
|
||||
** table allocated and opened above.
|
||||
*/
|
||||
Select *pSelect = pExpr->x.pSelect;
|
||||
SelectDest dest;
|
||||
ExprList *pEList;
|
||||
|
||||
@ -1761,13 +1811,15 @@ int sqlite3CodeSubselect(
|
||||
sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
|
||||
dest.affSdst = (u8)affinity;
|
||||
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
|
||||
pExpr->x.pSelect->iLimit = 0;
|
||||
pSelect->iLimit = 0;
|
||||
testcase( pSelect->selFlags & SF_Distinct );
|
||||
pSelect->selFlags &= ~SF_Distinct;
|
||||
testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
|
||||
if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){
|
||||
if( sqlite3Select(pParse, pSelect, &dest) ){
|
||||
sqlite3KeyInfoUnref(pKeyInfo);
|
||||
return 0;
|
||||
}
|
||||
pEList = pExpr->x.pSelect->pEList;
|
||||
pEList = pSelect->pEList;
|
||||
assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */
|
||||
assert( pEList!=0 );
|
||||
assert( pEList->nExpr>0 );
|
||||
@ -1798,7 +1850,7 @@ int sqlite3CodeSubselect(
|
||||
/* Loop through each expression in <exprlist>. */
|
||||
r1 = sqlite3GetTempReg(pParse);
|
||||
r2 = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, r2);
|
||||
if( isRowid ) sqlite3VdbeAddOp2(v, OP_Null, 0, r2);
|
||||
for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){
|
||||
Expr *pE2 = pItem->pExpr;
|
||||
int iValToIns;
|
||||
@ -1808,9 +1860,9 @@ int sqlite3CodeSubselect(
|
||||
** this code only executes once. Because for a non-constant
|
||||
** expression we need to rerun this code each time.
|
||||
*/
|
||||
if( testAddr>=0 && !sqlite3ExprIsConstant(pE2) ){
|
||||
sqlite3VdbeChangeToNoop(v, testAddr);
|
||||
testAddr = -1;
|
||||
if( jmpIfDynamic>=0 && !sqlite3ExprIsConstant(pE2) ){
|
||||
sqlite3VdbeChangeToNoop(v, jmpIfDynamic);
|
||||
jmpIfDynamic = -1;
|
||||
}
|
||||
|
||||
/* Evaluate the expression and insert it into the temp table */
|
||||
@ -1880,8 +1932,12 @@ int sqlite3CodeSubselect(
|
||||
}
|
||||
}
|
||||
|
||||
if( testAddr>=0 ){
|
||||
sqlite3VdbeJumpHere(v, testAddr);
|
||||
if( rHasNullFlag ){
|
||||
sqlite3SetHasNullFlag(v, pExpr->iTable, rHasNullFlag);
|
||||
}
|
||||
|
||||
if( jmpIfDynamic>=0 ){
|
||||
sqlite3VdbeJumpHere(v, jmpIfDynamic);
|
||||
}
|
||||
sqlite3ExprCachePop(pParse);
|
||||
|
||||
@ -1902,7 +1958,7 @@ int sqlite3CodeSubselect(
|
||||
** if the LHS is NULL or if the LHS is not contained within the RHS and the
|
||||
** RHS contains one or more NULL values.
|
||||
**
|
||||
** This routine generates code will jump to destIfFalse if the LHS is not
|
||||
** This routine generates code that jumps to destIfFalse if the LHS is not
|
||||
** contained within the RHS. If due to NULLs we cannot determine if the LHS
|
||||
** is contained in the RHS then jump to destIfNull. If the LHS is contained
|
||||
** within the RHS then fall through.
|
||||
@ -1925,7 +1981,9 @@ static void sqlite3ExprCodeIN(
|
||||
v = pParse->pVdbe;
|
||||
assert( v!=0 ); /* OOM detected prior to this routine */
|
||||
VdbeNoopComment((v, "begin IN expr"));
|
||||
eType = sqlite3FindInIndex(pParse, pExpr, &rRhsHasNull);
|
||||
eType = sqlite3FindInIndex(pParse, pExpr,
|
||||
IN_INDEX_MEMBERSHIP | IN_INDEX_NOOP_OK,
|
||||
destIfFalse==destIfNull ? 0 : &rRhsHasNull);
|
||||
|
||||
/* Figure out the affinity to use to create a key from the results
|
||||
** of the expression. affinityStr stores a static string suitable for
|
||||
@ -1939,82 +1997,114 @@ static void sqlite3ExprCodeIN(
|
||||
r1 = sqlite3GetTempReg(pParse);
|
||||
sqlite3ExprCode(pParse, pExpr->pLeft, r1);
|
||||
|
||||
/* If the LHS is NULL, then the result is either false or NULL depending
|
||||
** on whether the RHS is empty or not, respectively.
|
||||
/* If sqlite3FindInIndex() did not find or create an index that is
|
||||
** suitable for evaluating the IN operator, then evaluate using a
|
||||
** sequence of comparisons.
|
||||
*/
|
||||
if( destIfNull==destIfFalse ){
|
||||
/* Shortcut for the common case where the false and NULL outcomes are
|
||||
** the same. */
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v);
|
||||
if( eType==IN_INDEX_NOOP ){
|
||||
ExprList *pList = pExpr->x.pList;
|
||||
CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
|
||||
int labelOk = sqlite3VdbeMakeLabel(v);
|
||||
int r2, regToFree;
|
||||
int regCkNull = 0;
|
||||
int ii;
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
if( destIfNull!=destIfFalse ){
|
||||
regCkNull = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp3(v, OP_BitAnd, r1, r1, regCkNull);
|
||||
}
|
||||
for(ii=0; ii<pList->nExpr; ii++){
|
||||
r2 = sqlite3ExprCodeTemp(pParse, pList->a[ii].pExpr, ®ToFree);
|
||||
if( regCkNull && sqlite3ExprCanBeNull(pList->a[ii].pExpr) ){
|
||||
sqlite3VdbeAddOp3(v, OP_BitAnd, regCkNull, r2, regCkNull);
|
||||
}
|
||||
if( ii<pList->nExpr-1 || destIfNull!=destIfFalse ){
|
||||
sqlite3VdbeAddOp4(v, OP_Eq, r1, labelOk, r2,
|
||||
(void*)pColl, P4_COLLSEQ);
|
||||
VdbeCoverageIf(v, ii<pList->nExpr-1);
|
||||
VdbeCoverageIf(v, ii==pList->nExpr-1);
|
||||
sqlite3VdbeChangeP5(v, affinity);
|
||||
}else{
|
||||
assert( destIfNull==destIfFalse );
|
||||
sqlite3VdbeAddOp4(v, OP_Ne, r1, destIfFalse, r2,
|
||||
(void*)pColl, P4_COLLSEQ); VdbeCoverage(v);
|
||||
sqlite3VdbeChangeP5(v, affinity | SQLITE_JUMPIFNULL);
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, regToFree);
|
||||
}
|
||||
if( regCkNull ){
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, regCkNull, destIfNull); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse);
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, labelOk);
|
||||
sqlite3ReleaseTempReg(pParse, regCkNull);
|
||||
}else{
|
||||
int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
}
|
||||
|
||||
if( eType==IN_INDEX_ROWID ){
|
||||
/* In this case, the RHS is the ROWID of table b-tree
|
||||
|
||||
/* If the LHS is NULL, then the result is either false or NULL depending
|
||||
** on whether the RHS is empty or not, respectively.
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, destIfFalse, r1);
|
||||
VdbeCoverage(v);
|
||||
}else{
|
||||
/* In this case, the RHS is an index b-tree.
|
||||
*/
|
||||
sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1);
|
||||
|
||||
/* If the set membership test fails, then the result of the
|
||||
** "x IN (...)" expression must be either 0 or NULL. If the set
|
||||
** contains no NULL values, then the result is 0. If the set
|
||||
** contains one or more NULL values, then the result of the
|
||||
** expression is also NULL.
|
||||
*/
|
||||
if( rRhsHasNull==0 || destIfFalse==destIfNull ){
|
||||
/* This branch runs if it is known at compile time that the RHS
|
||||
** cannot contain NULL values. This happens as the result
|
||||
** of a "NOT NULL" constraint in the database schema.
|
||||
**
|
||||
** Also run this branch if NULL is equivalent to FALSE
|
||||
** for this particular IN operator.
|
||||
if( sqlite3ExprCanBeNull(pExpr->pLeft) ){
|
||||
if( destIfNull==destIfFalse ){
|
||||
/* Shortcut for the common case where the false and NULL outcomes are
|
||||
** the same. */
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v);
|
||||
}else{
|
||||
int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
|
||||
sqlite3VdbeJumpHere(v, addr1);
|
||||
}
|
||||
}
|
||||
|
||||
if( eType==IN_INDEX_ROWID ){
|
||||
/* In this case, the RHS is the ROWID of table b-tree
|
||||
*/
|
||||
sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, r1, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, destIfFalse, r1);
|
||||
VdbeCoverage(v);
|
||||
}else{
|
||||
/* In this branch, the RHS of the IN might contain a NULL and
|
||||
** the presence of a NULL on the RHS makes a difference in the
|
||||
** outcome.
|
||||
/* In this case, the RHS is an index b-tree.
|
||||
*/
|
||||
int j1, j2;
|
||||
|
||||
/* First check to see if the LHS is contained in the RHS. If so,
|
||||
** then the presence of NULLs in the RHS does not matter, so jump
|
||||
** over all of the code that follows.
|
||||
sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1);
|
||||
|
||||
/* If the set membership test fails, then the result of the
|
||||
** "x IN (...)" expression must be either 0 or NULL. If the set
|
||||
** contains no NULL values, then the result is 0. If the set
|
||||
** contains one or more NULL values, then the result of the
|
||||
** expression is also NULL.
|
||||
*/
|
||||
j1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1);
|
||||
VdbeCoverage(v);
|
||||
|
||||
/* Here we begin generating code that runs if the LHS is not
|
||||
** contained within the RHS. Generate additional code that
|
||||
** tests the RHS for NULLs. If the RHS contains a NULL then
|
||||
** jump to destIfNull. If there are no NULLs in the RHS then
|
||||
** jump to destIfFalse.
|
||||
*/
|
||||
sqlite3VdbeAddOp2(v, OP_If, rRhsHasNull, destIfNull); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_IfNot, rRhsHasNull, destIfFalse); VdbeCoverage(v);
|
||||
j2 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, rRhsHasNull, 1);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, rRhsHasNull);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse);
|
||||
sqlite3VdbeJumpHere(v, j2);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, rRhsHasNull);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
|
||||
|
||||
/* The OP_Found at the top of this branch jumps here when true,
|
||||
** causing the overall IN expression evaluation to fall through.
|
||||
*/
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
assert( destIfFalse!=destIfNull || rRhsHasNull==0 );
|
||||
if( rRhsHasNull==0 ){
|
||||
/* This branch runs if it is known at compile time that the RHS
|
||||
** cannot contain NULL values. This happens as the result
|
||||
** of a "NOT NULL" constraint in the database schema.
|
||||
**
|
||||
** Also run this branch if NULL is equivalent to FALSE
|
||||
** for this particular IN operator.
|
||||
*/
|
||||
sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, r1, 1);
|
||||
VdbeCoverage(v);
|
||||
}else{
|
||||
/* In this branch, the RHS of the IN might contain a NULL and
|
||||
** the presence of a NULL on the RHS makes a difference in the
|
||||
** outcome.
|
||||
*/
|
||||
int j1;
|
||||
|
||||
/* First check to see if the LHS is contained in the RHS. If so,
|
||||
** then the answer is TRUE the presence of NULLs in the RHS does
|
||||
** not matter. If the LHS is not contained in the RHS, then the
|
||||
** answer is NULL if the RHS contains NULLs and the answer is
|
||||
** FALSE if the RHS is NULL-free.
|
||||
*/
|
||||
j1 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, r1, 1);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, rRhsHasNull, destIfNull);
|
||||
VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse);
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
@ -2638,7 +2728,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
addr = sqlite3VdbeAddOp1(v, op, r1);
|
||||
VdbeCoverageIf(v, op==TK_ISNULL);
|
||||
VdbeCoverageIf(v, op==TK_NOTNULL);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, target, -1);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, target);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
break;
|
||||
}
|
||||
@ -2674,7 +2764,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
zId = pExpr->u.zToken;
|
||||
nId = sqlite3Strlen30(zId);
|
||||
pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0);
|
||||
if( pDef==0 ){
|
||||
if( pDef==0 || pDef->xFunc==0 ){
|
||||
sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId);
|
||||
break;
|
||||
}
|
||||
|
@ -225,7 +225,7 @@ int sqlite3FkLocateIndex(
|
||||
}
|
||||
|
||||
for(pIdx=pParent->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( pIdx->nKeyCol==nCol && pIdx->onError!=OE_None ){
|
||||
if( pIdx->nKeyCol==nCol && IsUniqueIndex(pIdx) ){
|
||||
/* pIdx is a UNIQUE index (or a PRIMARY KEY) and has the right number
|
||||
** of columns. If each indexed column corresponds to a foreign key
|
||||
** column of pFKey, then this index is a winner. */
|
||||
|
@ -1898,7 +1898,7 @@ static int xferOptimization(
|
||||
}
|
||||
}
|
||||
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
|
||||
if( pDestIdx->onError!=OE_None ){
|
||||
if( IsUniqueIndex(pDestIdx) ){
|
||||
destHasUniqueIdx = 1;
|
||||
}
|
||||
for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){
|
||||
|
@ -81,7 +81,7 @@ int sqlite3MutexEnd(void){
|
||||
*/
|
||||
sqlite3_mutex *sqlite3_mutex_alloc(int id){
|
||||
#ifndef SQLITE_OMIT_AUTOINIT
|
||||
if( sqlite3_initialize() ) return 0;
|
||||
if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0;
|
||||
#endif
|
||||
return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ static int debugMutexEnd(void){ return SQLITE_OK; }
|
||||
** that means that a mutex could not be allocated.
|
||||
*/
|
||||
static sqlite3_mutex *debugMutexAlloc(int id){
|
||||
static sqlite3_debug_mutex aStatic[6];
|
||||
static sqlite3_debug_mutex aStatic[SQLITE_MUTEX_STATIC_APP3 - 1];
|
||||
sqlite3_debug_mutex *pNew = 0;
|
||||
switch( id ){
|
||||
case SQLITE_MUTEX_FAST:
|
||||
|
@ -96,10 +96,13 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; }
|
||||
** <li> SQLITE_MUTEX_RECURSIVE
|
||||
** <li> SQLITE_MUTEX_STATIC_MASTER
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM2
|
||||
** <li> SQLITE_MUTEX_STATIC_OPEN
|
||||
** <li> SQLITE_MUTEX_STATIC_PRNG
|
||||
** <li> SQLITE_MUTEX_STATIC_LRU
|
||||
** <li> SQLITE_MUTEX_STATIC_PMEM
|
||||
** <li> SQLITE_MUTEX_STATIC_APP1
|
||||
** <li> SQLITE_MUTEX_STATIC_APP2
|
||||
** <li> SQLITE_MUTEX_STATIC_APP3
|
||||
** </ul>
|
||||
**
|
||||
** The first two constants cause sqlite3_mutex_alloc() to create
|
||||
@ -133,6 +136,9 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER
|
||||
};
|
||||
sqlite3_mutex *p;
|
||||
|
@ -80,7 +80,10 @@ static int winMutexNotheld(sqlite3_mutex *p){
|
||||
/*
|
||||
** Initialize and deinitialize the mutex subsystem.
|
||||
*/
|
||||
static sqlite3_mutex winMutex_staticMutexes[6] = {
|
||||
static sqlite3_mutex winMutex_staticMutexes[] = {
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
SQLITE3_MUTEX_INITIALIZER,
|
||||
@ -90,13 +93,13 @@ static sqlite3_mutex winMutex_staticMutexes[6] = {
|
||||
};
|
||||
|
||||
static int winMutex_isInit = 0;
|
||||
static int winMutex_isNt = -1; /* <0 means "need to query" */
|
||||
|
||||
/* As winMutexInit() and winMutexEnd() are called as part of the
|
||||
** sqlite3_initialize() and sqlite3_shutdown() processing, the
|
||||
** "interlocked" magic used in this section may not strictly
|
||||
** necessary.
|
||||
/* As the winMutexInit() and winMutexEnd() functions are called as part
|
||||
** of the sqlite3_initialize() and sqlite3_shutdown() processing, the
|
||||
** "interlocked" magic used here is probably not strictly necessary.
|
||||
*/
|
||||
static LONG winMutex_lock = 0;
|
||||
static LONG volatile winMutex_lock = 0;
|
||||
|
||||
int sqlite3_win32_is_nt(void); /* os_win.c */
|
||||
void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */
|
||||
@ -150,10 +153,13 @@ static int winMutexEnd(void){
|
||||
** <li> SQLITE_MUTEX_RECURSIVE
|
||||
** <li> SQLITE_MUTEX_STATIC_MASTER
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM2
|
||||
** <li> SQLITE_MUTEX_STATIC_OPEN
|
||||
** <li> SQLITE_MUTEX_STATIC_PRNG
|
||||
** <li> SQLITE_MUTEX_STATIC_LRU
|
||||
** <li> SQLITE_MUTEX_STATIC_PMEM
|
||||
** <li> SQLITE_MUTEX_STATIC_APP1
|
||||
** <li> SQLITE_MUTEX_STATIC_APP2
|
||||
** <li> SQLITE_MUTEX_STATIC_APP3
|
||||
** </ul>
|
||||
**
|
||||
** The first two constants cause sqlite3_mutex_alloc() to create
|
||||
@ -231,6 +237,7 @@ static void winMutexFree(sqlite3_mutex *p){
|
||||
assert( p->nRef==0 && p->owner==0 );
|
||||
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
|
||||
#endif
|
||||
assert( winMutex_isInit==1 );
|
||||
DeleteCriticalSection(&p->mutex);
|
||||
sqlite3_free(p);
|
||||
}
|
||||
@ -256,6 +263,7 @@ static void winMutexEnter(sqlite3_mutex *p){
|
||||
#else
|
||||
assert( p );
|
||||
#endif
|
||||
assert( winMutex_isInit==1 );
|
||||
EnterCriticalSection(&p->mutex);
|
||||
#ifdef SQLITE_DEBUG
|
||||
assert( p->nRef>0 || p->owner==0 );
|
||||
@ -287,7 +295,13 @@ static int winMutexTry(sqlite3_mutex *p){
|
||||
** ticket #2685.
|
||||
*/
|
||||
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400
|
||||
if( sqlite3_win32_is_nt() && TryEnterCriticalSection(&p->mutex) ){
|
||||
assert( winMutex_isInit==1 );
|
||||
assert( winMutex_isNt>=-1 && winMutex_isNt<=1 );
|
||||
if( winMutex_isNt<0 ){
|
||||
winMutex_isNt = sqlite3_win32_is_nt();
|
||||
}
|
||||
assert( winMutex_isNt==0 || winMutex_isNt==1 );
|
||||
if( winMutex_isNt && TryEnterCriticalSection(&p->mutex) ){
|
||||
#ifdef SQLITE_DEBUG
|
||||
p->owner = tid;
|
||||
p->nRef++;
|
||||
@ -324,6 +338,7 @@ static void winMutexLeave(sqlite3_mutex *p){
|
||||
if( p->nRef==0 ) p->owner = 0;
|
||||
assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
|
||||
#endif
|
||||
assert( winMutex_isInit==1 );
|
||||
LeaveCriticalSection(&p->mutex);
|
||||
#ifdef SQLITE_DEBUG
|
||||
if( p->trace ){
|
||||
|
23
src/os_win.c
23
src/os_win.c
@ -414,10 +414,9 @@ const sqlite3_mem_methods *sqlite3MemGetWin32(void);
|
||||
** can manually set this value to 1 to emulate Win98 behavior.
|
||||
*/
|
||||
#ifdef SQLITE_TEST
|
||||
int sqlite3_os_type = 0;
|
||||
#elif !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \
|
||||
defined(SQLITE_WIN32_HAS_ANSI) && defined(SQLITE_WIN32_HAS_WIDE)
|
||||
static int sqlite3_os_type = 0;
|
||||
LONG volatile sqlite3_os_type = 0;
|
||||
#else
|
||||
static LONG volatile sqlite3_os_type = 0;
|
||||
#endif
|
||||
|
||||
#ifndef SYSCALL
|
||||
@ -1048,6 +1047,11 @@ static struct win_syscall {
|
||||
#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \
|
||||
LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[75].pCurrent)
|
||||
|
||||
{ "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 },
|
||||
|
||||
#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG volatile*, \
|
||||
LONG,LONG))aSyscall[76].pCurrent)
|
||||
|
||||
}; /* End of the overrideable system calls */
|
||||
|
||||
/*
|
||||
@ -1298,7 +1302,7 @@ void sqlite3_win32_sleep(DWORD milliseconds){
|
||||
#elif !defined(SQLITE_WIN32_HAS_WIDE)
|
||||
# define osIsNT() (0)
|
||||
#else
|
||||
# define osIsNT() (sqlite3_win32_is_nt())
|
||||
# define osIsNT() ((sqlite3_os_type==2) || sqlite3_win32_is_nt())
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -1306,7 +1310,7 @@ void sqlite3_win32_sleep(DWORD milliseconds){
|
||||
** based on the NT kernel.
|
||||
*/
|
||||
int sqlite3_win32_is_nt(void){
|
||||
if( sqlite3_os_type==0 ){
|
||||
if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){
|
||||
#if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WIN8
|
||||
OSVERSIONINFOW sInfo;
|
||||
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
|
||||
@ -1316,9 +1320,10 @@ int sqlite3_win32_is_nt(void){
|
||||
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
|
||||
osGetVersionExA(&sInfo);
|
||||
#endif
|
||||
sqlite3_os_type = (sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1;
|
||||
osInterlockedCompareExchange(&sqlite3_os_type,
|
||||
(sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
|
||||
}
|
||||
return (sqlite3_os_type == 2);
|
||||
return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_WIN32_MALLOC
|
||||
@ -5475,7 +5480,7 @@ int sqlite3_os_init(void){
|
||||
|
||||
/* Double-check that the aSyscall[] array has been constructed
|
||||
** correctly. See ticket [bb3a86e890c8e96ab] */
|
||||
assert( ArraySize(aSyscall)==76 );
|
||||
assert( ArraySize(aSyscall)==77 );
|
||||
|
||||
/* get memory map allocation granularity */
|
||||
memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
|
||||
|
73
src/pragma.c
73
src/pragma.c
@ -1544,7 +1544,7 @@ void sqlite3Pragma(
|
||||
for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pIdx->onError!=OE_None, 3);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, IsUniqueIndex(pIdx), 3);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
|
||||
}
|
||||
}
|
||||
@ -1794,9 +1794,8 @@ void sqlite3Pragma(
|
||||
*/
|
||||
static const int iLn = VDBE_OFFSET_LINENO(2);
|
||||
static const VdbeOpList endCode[] = {
|
||||
{ OP_AddImm, 1, 0, 0}, /* 0 */
|
||||
{ OP_IfNeg, 1, 0, 0}, /* 1 */
|
||||
{ OP_String8, 0, 3, 0}, /* 2 */
|
||||
{ OP_IfNeg, 1, 0, 0}, /* 0 */
|
||||
{ OP_String8, 0, 3, 0}, /* 1 */
|
||||
{ OP_ResultRow, 3, 1, 0},
|
||||
};
|
||||
|
||||
@ -1908,28 +1907,76 @@ void sqlite3Pragma(
|
||||
pParse->nMem = MAX(pParse->nMem, 8+j);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
|
||||
loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
|
||||
/* Verify that all NOT NULL columns really are NOT NULL */
|
||||
for(j=0; j<pTab->nCol; j++){
|
||||
char *zErr;
|
||||
int jmp2, jmp3;
|
||||
if( j==pTab->iPKey ) continue;
|
||||
if( pTab->aCol[j].notNull==0 ) continue;
|
||||
sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3);
|
||||
sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG);
|
||||
jmp2 = sqlite3VdbeAddOp1(v, OP_NotNull, 3); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
|
||||
zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
|
||||
pTab->aCol[j].zName);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
|
||||
jmp3 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp0(v, OP_Halt);
|
||||
sqlite3VdbeJumpHere(v, jmp2);
|
||||
sqlite3VdbeJumpHere(v, jmp3);
|
||||
}
|
||||
/* Validate index entries for the current row */
|
||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||
int jmp2, jmp3, jmp4;
|
||||
int jmp2, jmp3, jmp4, jmp5;
|
||||
int ckUniq = sqlite3VdbeMakeLabel(v);
|
||||
if( pPk==pIdx ) continue;
|
||||
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3,
|
||||
pPrior, r1);
|
||||
pPrior = pIdx;
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1); /* increment entry count */
|
||||
jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, 0, r1,
|
||||
/* Verify that an index entry exists for the current table row */
|
||||
jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, ckUniq, r1,
|
||||
pIdx->nColumn); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, "row ", P4_STATIC);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, " missing from index ",
|
||||
P4_STATIC);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0,
|
||||
" missing from index ", P4_STATIC);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, pIdx->zName, P4_TRANSIENT);
|
||||
jmp5 = sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0,
|
||||
pIdx->zName, P4_TRANSIENT);
|
||||
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
|
||||
sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
|
||||
jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp0(v, OP_Halt);
|
||||
sqlite3VdbeJumpHere(v, jmp4);
|
||||
sqlite3VdbeJumpHere(v, jmp2);
|
||||
/* For UNIQUE indexes, verify that only one entry exists with the
|
||||
** current key. The entry is unique if (1) any column is NULL
|
||||
** or (2) the next entry has a different key */
|
||||
if( IsUniqueIndex(pIdx) ){
|
||||
int uniqOk = sqlite3VdbeMakeLabel(v);
|
||||
int jmp6;
|
||||
int kk;
|
||||
for(kk=0; kk<pIdx->nKeyCol; kk++){
|
||||
int iCol = pIdx->aiColumn[kk];
|
||||
assert( iCol>=0 && iCol<pTab->nCol );
|
||||
if( pTab->aCol[iCol].notNull ) continue;
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, r1+kk, uniqOk);
|
||||
VdbeCoverage(v);
|
||||
}
|
||||
jmp6 = sqlite3VdbeAddOp1(v, OP_Next, iIdxCur+j); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, uniqOk);
|
||||
sqlite3VdbeJumpHere(v, jmp6);
|
||||
sqlite3VdbeAddOp4Int(v, OP_IdxGT, iIdxCur+j, uniqOk, r1,
|
||||
pIdx->nKeyCol); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
|
||||
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0,
|
||||
"non-unique entry in index ", P4_STATIC);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, jmp5);
|
||||
sqlite3VdbeResolveLabel(v, uniqOk);
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, jmp4);
|
||||
sqlite3ResolvePartIdxLabel(pParse, jmp3);
|
||||
}
|
||||
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
|
||||
@ -1954,9 +2001,9 @@ void sqlite3Pragma(
|
||||
}
|
||||
}
|
||||
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
|
||||
sqlite3VdbeChangeP2(v, addr, -mxErr);
|
||||
sqlite3VdbeJumpHere(v, addr+1);
|
||||
sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC);
|
||||
sqlite3VdbeChangeP3(v, addr, -mxErr);
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
sqlite3VdbeChangeP4(v, addr+1, "ok", P4_STATIC);
|
||||
}
|
||||
break;
|
||||
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
|
||||
|
@ -541,8 +541,7 @@ static void codeOffset(
|
||||
){
|
||||
if( iOffset>0 ){
|
||||
int addr;
|
||||
sqlite3VdbeAddOp2(v, OP_AddImm, iOffset, -1);
|
||||
addr = sqlite3VdbeAddOp1(v, OP_IfNeg, iOffset); VdbeCoverage(v);
|
||||
addr = sqlite3VdbeAddOp3(v, OP_IfNeg, iOffset, 0, -1); VdbeCoverage(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, iContinue);
|
||||
VdbeComment((v, "skip OFFSET records"));
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
|
@ -5875,10 +5875,12 @@ int sqlite3_vfs_unregister(sqlite3_vfs*);
|
||||
** <li> SQLITE_MUTEX_RECURSIVE
|
||||
** <li> SQLITE_MUTEX_STATIC_MASTER
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM
|
||||
** <li> SQLITE_MUTEX_STATIC_MEM2
|
||||
** <li> SQLITE_MUTEX_STATIC_OPEN
|
||||
** <li> SQLITE_MUTEX_STATIC_PRNG
|
||||
** <li> SQLITE_MUTEX_STATIC_LRU
|
||||
** <li> SQLITE_MUTEX_STATIC_LRU2
|
||||
** <li> SQLITE_MUTEX_STATIC_PMEM
|
||||
** <li> SQLITE_MUTEX_STATIC_APP1
|
||||
** <li> SQLITE_MUTEX_STATIC_APP2
|
||||
** </ul>)^
|
||||
**
|
||||
** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
|
||||
@ -6082,6 +6084,9 @@ int sqlite3_mutex_notheld(sqlite3_mutex*);
|
||||
#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */
|
||||
#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
|
||||
#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */
|
||||
#define SQLITE_MUTEX_STATIC_APP1 8 /* For use by application */
|
||||
#define SQLITE_MUTEX_STATIC_APP2 9 /* For use by application */
|
||||
#define SQLITE_MUTEX_STATIC_APP3 10 /* For use by application */
|
||||
|
||||
/*
|
||||
** CAPI3REF: Retrieve the mutex for a database connection
|
||||
|
@ -877,7 +877,7 @@ struct Schema {
|
||||
Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */
|
||||
u8 file_format; /* Schema format version for this file */
|
||||
u8 enc; /* Text encoding used by this database */
|
||||
u16 flags; /* Flags associated with this schema */
|
||||
u16 schemaFlags; /* Flags associated with this schema */
|
||||
int cache_size; /* Number of pages to use in the cache */
|
||||
};
|
||||
|
||||
@ -885,10 +885,10 @@ struct Schema {
|
||||
** These macros can be used to test, set, or clear bits in the
|
||||
** Db.pSchema->flags field.
|
||||
*/
|
||||
#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))==(P))
|
||||
#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))!=0)
|
||||
#define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->flags|=(P)
|
||||
#define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->flags&=~(P)
|
||||
#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))==(P))
|
||||
#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))!=0)
|
||||
#define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->schemaFlags|=(P)
|
||||
#define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->schemaFlags&=~(P)
|
||||
|
||||
/*
|
||||
** Allowed values for the DB.pSchema->flags field.
|
||||
@ -1728,6 +1728,9 @@ struct Index {
|
||||
/* Return true if index X is a PRIMARY KEY index */
|
||||
#define IsPrimaryKeyIndex(X) ((X)->idxType==SQLITE_IDXTYPE_PRIMARYKEY)
|
||||
|
||||
/* Return true if index X is a UNIQUE index */
|
||||
#define IsUniqueIndex(X) ((X)->onError!=OE_None)
|
||||
|
||||
/*
|
||||
** Each sample stored in the sqlite_stat3 table is represented in memory
|
||||
** using a structure of this type. See documentation at the top of the
|
||||
@ -3600,11 +3603,21 @@ const char *sqlite3JournalModename(int);
|
||||
#define sqlite3EndBenignMalloc()
|
||||
#endif
|
||||
|
||||
#define IN_INDEX_ROWID 1
|
||||
#define IN_INDEX_EPH 2
|
||||
#define IN_INDEX_INDEX_ASC 3
|
||||
#define IN_INDEX_INDEX_DESC 4
|
||||
int sqlite3FindInIndex(Parse *, Expr *, int*);
|
||||
/*
|
||||
** Allowed return values from sqlite3FindInIndex()
|
||||
*/
|
||||
#define IN_INDEX_ROWID 1 /* Search the rowid of the table */
|
||||
#define IN_INDEX_EPH 2 /* Search an ephemeral b-tree */
|
||||
#define IN_INDEX_INDEX_ASC 3 /* Existing index ASCENDING */
|
||||
#define IN_INDEX_INDEX_DESC 4 /* Existing index DESCENDING */
|
||||
#define IN_INDEX_NOOP 5 /* No table available. Use comparisons */
|
||||
/*
|
||||
** Allowed flags for the 3rd parameter to sqlite3FindInIndex().
|
||||
*/
|
||||
#define IN_INDEX_NOOP_OK 0x0001 /* OK to return IN_INDEX_NOOP */
|
||||
#define IN_INDEX_MEMBERSHIP 0x0002 /* IN operator used for membership test */
|
||||
#define IN_INDEX_LOOP 0x0004 /* IN operator used as a loop */
|
||||
int sqlite3FindInIndex(Parse *, Expr *, u32, int*);
|
||||
|
||||
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
||||
int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
|
||||
|
@ -6581,7 +6581,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
extern int sqlite3_pager_writedb_count;
|
||||
extern int sqlite3_pager_writej_count;
|
||||
#if SQLITE_OS_WIN
|
||||
extern int sqlite3_os_type;
|
||||
extern LONG volatile sqlite3_os_type;
|
||||
#endif
|
||||
#ifdef SQLITE_DEBUG
|
||||
extern int sqlite3WhereTrace;
|
||||
@ -6639,7 +6639,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
#endif
|
||||
#if SQLITE_OS_WIN
|
||||
Tcl_LinkVar(interp, "sqlite_os_type",
|
||||
(char*)&sqlite3_os_type, TCL_LINK_INT);
|
||||
(char*)&sqlite3_os_type, TCL_LINK_LONG);
|
||||
#endif
|
||||
#ifdef SQLITE_TEST
|
||||
{
|
||||
|
@ -1176,14 +1176,20 @@ int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefault){
|
||||
** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once while
|
||||
** shutting down in order to free all remaining multiplex groups.
|
||||
*/
|
||||
int sqlite3_multiplex_shutdown(void){
|
||||
int sqlite3_multiplex_shutdown(int eForce){
|
||||
int rc = SQLITE_OK;
|
||||
if( gMultiplex.isInitialized==0 ) return SQLITE_MISUSE;
|
||||
if( gMultiplex.pGroups ) return SQLITE_MISUSE;
|
||||
if( gMultiplex.pGroups ){
|
||||
sqlite3_log(SQLITE_MISUSE, "sqlite3_multiplex_shutdown() called "
|
||||
"while database connections are still open");
|
||||
if( !eForce ) return SQLITE_MISUSE;
|
||||
rc = SQLITE_MISUSE;
|
||||
}
|
||||
gMultiplex.isInitialized = 0;
|
||||
sqlite3_mutex_free(gMultiplex.pMutex);
|
||||
sqlite3_vfs_unregister(&gMultiplex.sThisVfs);
|
||||
memset(&gMultiplex, 0, sizeof(gMultiplex));
|
||||
return SQLITE_OK;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/***************************** Test Code ***********************************/
|
||||
@ -1236,13 +1242,16 @@ static int test_multiplex_shutdown(
|
||||
|
||||
UNUSED_PARAMETER(clientData);
|
||||
|
||||
if( objc!=1 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "");
|
||||
if( objc==2 && strcmp(Tcl_GetString(objv[1]),"-force")!=0 ){
|
||||
objc = 3;
|
||||
}
|
||||
if( (objc!=1 && objc!=2) ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "?-force?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/* Call sqlite3_multiplex_shutdown() */
|
||||
rc = sqlite3_multiplex_shutdown();
|
||||
rc = sqlite3_multiplex_shutdown(objc==2);
|
||||
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
|
||||
|
||||
return TCL_OK;
|
||||
|
@ -90,7 +90,7 @@ extern int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefaul
|
||||
** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once while
|
||||
** shutting down in order to free all remaining multiplex groups.
|
||||
*/
|
||||
extern int sqlite3_multiplex_shutdown(void);
|
||||
extern int sqlite3_multiplex_shutdown(int eForce);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* End of the 'extern "C"' block */
|
||||
|
@ -438,7 +438,8 @@ void sqlite3Update(
|
||||
}
|
||||
labelContinue = labelBreak;
|
||||
sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak);
|
||||
VdbeCoverage(v);
|
||||
VdbeCoverageIf(v, pPk==0);
|
||||
VdbeCoverageIf(v, pPk!=0);
|
||||
}else if( pPk ){
|
||||
labelContinue = sqlite3VdbeMakeLabel(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v);
|
||||
|
44
src/vdbe.c
44
src/vdbe.c
@ -126,6 +126,12 @@ int sqlite3_found_count = 0;
|
||||
** branch can go. It is usually 2. "I" is the direction the branch
|
||||
** goes. 0 means falls through. 1 means branch is taken. 2 means the
|
||||
** second alternative branch is taken.
|
||||
**
|
||||
** iSrcLine is the source code line (from the __LINE__ macro) that
|
||||
** generated the VDBE instruction. This instrumentation assumes that all
|
||||
** source code is in a single file (the amalgamation). Special values 1
|
||||
** and 2 for the iSrcLine parameter mean that this particular branch is
|
||||
** always taken or never taken, respectively.
|
||||
*/
|
||||
#if !defined(SQLITE_VDBE_COVERAGE)
|
||||
# define VdbeBranchTaken(I,M)
|
||||
@ -800,7 +806,7 @@ case OP_InitCoroutine: { /* jump */
|
||||
|
||||
/* Opcode: EndCoroutine P1 * * * *
|
||||
**
|
||||
** The instruction at the address in register P1 is an Yield.
|
||||
** The instruction at the address in register P1 is a Yield.
|
||||
** Jump to the P2 parameter of that Yield.
|
||||
** After the jump, register P1 becomes undefined.
|
||||
**
|
||||
@ -993,7 +999,7 @@ case OP_Real: { /* same as TK_FLOAT, out2-prerelease */
|
||||
** Synopsis: r[P2]='P4'
|
||||
**
|
||||
** P4 points to a nul terminated UTF-8 string. This opcode is transformed
|
||||
** into an OP_String before it is executed for the first time. During
|
||||
** into a String before it is executed for the first time. During
|
||||
** this transformation, the length of string P4 is computed and stored
|
||||
** as the P1 parameter.
|
||||
*/
|
||||
@ -2239,13 +2245,13 @@ case OP_Once: { /* jump */
|
||||
**
|
||||
** Jump to P2 if the value in register P1 is true. The value
|
||||
** is considered true if it is numeric and non-zero. If the value
|
||||
** in P1 is NULL then take the jump if P3 is non-zero.
|
||||
** in P1 is NULL then take the jump if and only if P3 is non-zero.
|
||||
*/
|
||||
/* Opcode: IfNot P1 P2 P3 * *
|
||||
**
|
||||
** Jump to P2 if the value in register P1 is False. The value
|
||||
** is considered false if it has a numeric value of zero. If the value
|
||||
** in P1 is NULL then take the jump if P3 is zero.
|
||||
** in P1 is NULL then take the jump if and only if P3 is non-zero.
|
||||
*/
|
||||
case OP_If: /* jump, in1 */
|
||||
case OP_IfNot: { /* jump, in1 */
|
||||
@ -3517,7 +3523,7 @@ case OP_Close: {
|
||||
** greater than or equal to the key and P2 is not zero, then jump to P2.
|
||||
**
|
||||
** This opcode leaves the cursor configured to move in forward order,
|
||||
** from the begining toward the end. In other words, the cursor is
|
||||
** from the beginning toward the end. In other words, the cursor is
|
||||
** configured to use Next, not Prev.
|
||||
**
|
||||
** See also: Found, NotFound, SeekLt, SeekGt, SeekLe
|
||||
@ -3757,9 +3763,9 @@ case OP_Seek: { /* in2 */
|
||||
** is a prefix of any entry in P1 then a jump is made to P2 and
|
||||
** P1 is left pointing at the matching entry.
|
||||
**
|
||||
** This operation leaves the cursor in a state where it cannot be
|
||||
** advanced in either direction. In other words, the Next and Prev
|
||||
** opcodes do not work after this operation.
|
||||
** This operation leaves the cursor in a state where it can be
|
||||
** advanced in the forward direction. The Next instruction will work,
|
||||
** but not the Prev instruction.
|
||||
**
|
||||
** See also: NotFound, NoConflict, NotExists. SeekGe
|
||||
*/
|
||||
@ -3826,7 +3832,7 @@ case OP_Found: { /* jump, in3 */
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
#ifdef SQLITE_DEBUG
|
||||
pC->seekOp = 0;
|
||||
pC->seekOp = pOp->opcode;
|
||||
#endif
|
||||
pIn3 = &aMem[pOp->p3];
|
||||
assert( pC->pCursor!=0 );
|
||||
@ -4236,7 +4242,7 @@ case OP_InsertInt: {
|
||||
** The cursor will be left pointing at either the next or the previous
|
||||
** record in the table. If it is left pointing at the next record, then
|
||||
** the next Next instruction will be a no-op. Hence it is OK to delete
|
||||
** a record from within an Next loop.
|
||||
** a record from within a Next loop.
|
||||
**
|
||||
** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
|
||||
** incremented (otherwise not).
|
||||
@ -4335,7 +4341,7 @@ case OP_ResetCount: {
|
||||
** Synopsis: if key(P1)!=trim(r[P3],P4) goto P2
|
||||
**
|
||||
** P1 is a sorter cursor. This instruction compares a prefix of the
|
||||
** the record blob in register P3 against a prefix of the entry that
|
||||
** record blob in register P3 against a prefix of the entry that
|
||||
** the sorter cursor currently points to. Only the first P4 fields
|
||||
** of r[P3] and the sorter record are compared.
|
||||
**
|
||||
@ -4734,7 +4740,7 @@ case OP_Next: /* jump */
|
||||
** The Prev opcode is only used after SeekLT, SeekLE, and Last. */
|
||||
assert( pOp->opcode!=OP_Next || pOp->opcode!=OP_NextIfOpen
|
||||
|| pC->seekOp==OP_SeekGT || pC->seekOp==OP_SeekGE
|
||||
|| pC->seekOp==OP_Rewind );
|
||||
|| pC->seekOp==OP_Rewind || pC->seekOp==OP_Found);
|
||||
assert( pOp->opcode!=OP_Prev || pOp->opcode!=OP_PrevIfOpen
|
||||
|| pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE
|
||||
|| pC->seekOp==OP_Last );
|
||||
@ -5661,17 +5667,16 @@ case OP_IfPos: { /* jump, in1 */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: IfNeg P1 P2 * * *
|
||||
** Synopsis: if r[P1]<0 goto P2
|
||||
/* Opcode: IfNeg P1 P2 P3 * *
|
||||
** Synopsis: r[P1]+=P3, if r[P1]<0 goto P2
|
||||
**
|
||||
** If the value of register P1 is less than zero, jump to P2.
|
||||
**
|
||||
** It is illegal to use this instruction on a register that does
|
||||
** not contain an integer. An assertion fault will result if you try.
|
||||
** Register P1 must contain an integer. Add literal P3 to the value in
|
||||
** register P1 then if the value of register P1 is less than zero, jump to P2.
|
||||
*/
|
||||
case OP_IfNeg: { /* jump, in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( pIn1->flags&MEM_Int );
|
||||
pIn1->u.i += pOp->p3;
|
||||
VdbeBranchTaken(pIn1->u.i<0, 2);
|
||||
if( pIn1->u.i<0 ){
|
||||
pc = pOp->p2 - 1;
|
||||
@ -5684,9 +5689,6 @@ case OP_IfNeg: { /* jump, in1 */
|
||||
**
|
||||
** The register P1 must contain an integer. Add literal P3 to the
|
||||
** value in register P1. If the result is exactly 0, jump to P2.
|
||||
**
|
||||
** It is illegal to use this instruction on a register that does
|
||||
** not contain an integer. An assertion fault will result if you try.
|
||||
*/
|
||||
case OP_IfZero: { /* jump, in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
|
10
src/where.c
10
src/where.c
@ -1470,7 +1470,7 @@ static int isDistinctRedundant(
|
||||
** contain a "col=X" term are subject to a NOT NULL constraint.
|
||||
*/
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
if( pIdx->onError==OE_None ) continue;
|
||||
if( !IsUniqueIndex(pIdx) ) continue;
|
||||
for(i=0; i<pIdx->nKeyCol; i++){
|
||||
i16 iCol = pIdx->aiColumn[i];
|
||||
if( 0==findTerm(pWC, iBase, iCol, ~(Bitmask)0, WO_EQ, pIdx) ){
|
||||
@ -2522,7 +2522,7 @@ static int codeEqualityTerm(
|
||||
}
|
||||
assert( pX->op==TK_IN );
|
||||
iReg = iTarget;
|
||||
eType = sqlite3FindInIndex(pParse, pX, 0);
|
||||
eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0);
|
||||
if( eType==IN_INDEX_INDEX_DESC ){
|
||||
testcase( bRev );
|
||||
bRev = !bRev;
|
||||
@ -4376,7 +4376,7 @@ static int whereLoopAddBtreeIndex(
|
||||
}else if( eOp & (WO_EQ) ){
|
||||
pNew->wsFlags |= WHERE_COLUMN_EQ;
|
||||
if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1) ){
|
||||
if( iCol>=0 && pProbe->onError==OE_None ){
|
||||
if( iCol>=0 && !IsUniqueIndex(pProbe) ){
|
||||
pNew->wsFlags |= WHERE_UNQ_WANTED;
|
||||
}else{
|
||||
pNew->wsFlags |= WHERE_ONEROW;
|
||||
@ -5231,7 +5231,7 @@ static i8 wherePathSatisfiesOrderBy(
|
||||
nColumn = pIndex->nColumn;
|
||||
assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) );
|
||||
assert( pIndex->aiColumn[nColumn-1]==(-1) || !HasRowid(pIndex->pTable));
|
||||
isOrderDistinct = pIndex->onError!=OE_None;
|
||||
isOrderDistinct = IsUniqueIndex(pIndex);
|
||||
}
|
||||
|
||||
/* Loop through all columns of the index and deal with the ones
|
||||
@ -5746,7 +5746,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){
|
||||
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
assert( pLoop->aLTermSpace==pLoop->aLTerm );
|
||||
assert( ArraySize(pLoop->aLTermSpace)==4 );
|
||||
if( pIdx->onError==OE_None
|
||||
if( !IsUniqueIndex(pIdx)
|
||||
|| pIdx->pPartIdxWhere!=0
|
||||
|| pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace)
|
||||
) continue;
|
||||
|
@ -231,11 +231,11 @@ do_execsql_test in4-3.44 {
|
||||
SELECT * FROM t3 WHERE x IN (10);
|
||||
} {~/OpenEphemeral/}
|
||||
do_execsql_test in4-3.45 {
|
||||
SELECT * FROM t3 WHERE x NOT IN (10,11);
|
||||
SELECT * FROM t3 WHERE x NOT IN (10,11,99999);
|
||||
} {1 1 1}
|
||||
do_execsql_test in4-3.46 {
|
||||
EXPLAIN
|
||||
SELECT * FROM t3 WHERE x NOT IN (10,11);
|
||||
SELECT * FROM t3 WHERE x NOT IN (10,11,99999);
|
||||
} {/OpenEphemeral/}
|
||||
do_execsql_test in4-3.47 {
|
||||
SELECT * FROM t3 WHERE x NOT IN (10);
|
||||
|
@ -68,6 +68,12 @@ proc multiplex_delete {name} {
|
||||
}
|
||||
|
||||
db close
|
||||
sqlite3_shutdown
|
||||
test_sqlite3_log xLog
|
||||
proc xLog {error_code msg} {
|
||||
lappend ::log $error_code $msg
|
||||
}
|
||||
unset -nocomplain log
|
||||
|
||||
multiplex_delete test.db
|
||||
multiplex_delete test2.db
|
||||
@ -188,12 +194,16 @@ do_test multiplex-2.3.1 {
|
||||
} {}
|
||||
|
||||
|
||||
unset -nocomplain ::log
|
||||
do_test multiplex-2.4.1 {
|
||||
sqlite3_multiplex_shutdown
|
||||
} {SQLITE_MISUSE}
|
||||
do_test multiplex-2.4.2 {
|
||||
execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
|
||||
} {}
|
||||
do_test multiplex-2.4.3 {
|
||||
set ::log
|
||||
} {SQLITE_MISUSE {sqlite3_multiplex_shutdown() called while database connections are still open}}
|
||||
do_test multiplex-2.4.4 { file size [multiplex_name test.x 0] } {7168}
|
||||
do_test multiplex-2.4.5 {
|
||||
db close
|
||||
@ -583,5 +593,9 @@ do_test multiplex-6.99 {
|
||||
}
|
||||
|
||||
|
||||
catch { db close }
|
||||
catch { sqlite3_multiplex_shutdown }
|
||||
sqlite3_shutdown
|
||||
test_sqlite3_log
|
||||
sqlite3_initialize
|
||||
finish_test
|
||||
|
@ -431,7 +431,32 @@ Page 6 is never used} {row 1 missing from index i2}}
|
||||
db eval {PRAGMA integrity_check}
|
||||
} {ok}
|
||||
}
|
||||
#exit
|
||||
|
||||
# Verify that PRAGMA integrity_check catches UNIQUE and NOT NULL
|
||||
# constraint violations.
|
||||
#
|
||||
do_execsql_test pragma-3.20 {
|
||||
CREATE TABLE t1(a,b);
|
||||
CREATE INDEX t1a ON t1(a);
|
||||
INSERT INTO t1 VALUES(1,1),(2,2),(3,3),(2,4),(NULL,5),(NULL,6);
|
||||
PRAGMA writable_schema=ON;
|
||||
UPDATE sqlite_master SET sql='CREATE UNIQUE INDEX t1a ON t1(a)'
|
||||
WHERE name='t1a';
|
||||
UPDATE sqlite_master SET sql='CREATE TABLE t1(a NOT NULL,b)'
|
||||
WHERE name='t1';
|
||||
PRAGMA writable_schema=OFF;
|
||||
ALTER TABLE t1 RENAME TO t1x;
|
||||
PRAGMA integrity_check;
|
||||
} {{non-unique entry in index t1a} {NULL value in t1x.a} {non-unique entry in index t1a} {NULL value in t1x.a}}
|
||||
do_execsql_test pragma-3.21 {
|
||||
PRAGMA integrity_check(3);
|
||||
} {{non-unique entry in index t1a} {NULL value in t1x.a} {non-unique entry in index t1a}}
|
||||
do_execsql_test pragma-3.22 {
|
||||
PRAGMA integrity_check(2);
|
||||
} {{non-unique entry in index t1a} {NULL value in t1x.a}}
|
||||
do_execsql_test pragma-3.21 {
|
||||
PRAGMA integrity_check(1);
|
||||
} {{non-unique entry in index t1a}}
|
||||
|
||||
# Test modifying the cache_size of an attached database.
|
||||
ifcapable pager_pragmas&&attach {
|
||||
|
@ -726,4 +726,51 @@ do_test table-15.2 {
|
||||
execsql {COMMIT}
|
||||
} {}
|
||||
|
||||
# Ticket 3a88d85f36704eebe134f7f48aebf00cd6438c1a (2014-08-05)
|
||||
# The following SQL script segfaults while running the INSERT statement:
|
||||
#
|
||||
# CREATE TABLE t1(x DEFAULT(max(1)));
|
||||
# INSERT INTO t1(rowid) VALUES(1);
|
||||
#
|
||||
# The problem appears to be the use of an aggregate function as part of
|
||||
# the default value for a column. This problem has been in the code since
|
||||
# at least 2006-01-01 and probably before that. This problem was detected
|
||||
# and reported on the sqlite-users@sqlite.org mailing list by Zsbán Ambrus.
|
||||
#
|
||||
do_execsql_test table-16.1 {
|
||||
CREATE TABLE t16(x DEFAULT(max(1)));
|
||||
INSERT INTO t16(x) VALUES(123);
|
||||
SELECT rowid, x FROM t16;
|
||||
} {1 123}
|
||||
do_catchsql_test table-16.2 {
|
||||
INSERT INTO t16(rowid) VALUES(4);
|
||||
} {1 {unknown function: max()}}
|
||||
do_execsql_test table-16.3 {
|
||||
DROP TABLE t16;
|
||||
CREATE TABLE t16(x DEFAULT(abs(1)));
|
||||
INSERT INTO t16(rowid) VALUES(4);
|
||||
SELECT rowid, x FROM t16;
|
||||
} {4 1}
|
||||
do_catchsql_test table-16.4 {
|
||||
DROP TABLE t16;
|
||||
CREATE TABLE t16(x DEFAULT(avg(1)));
|
||||
INSERT INTO t16(rowid) VALUES(123);
|
||||
SELECT rowid, x FROM t16;
|
||||
} {1 {unknown function: avg()}}
|
||||
do_catchsql_test table-16.5 {
|
||||
DROP TABLE t16;
|
||||
CREATE TABLE t16(x DEFAULT(count()));
|
||||
INSERT INTO t16(rowid) VALUES(123);
|
||||
SELECT rowid, x FROM t16;
|
||||
} {1 {unknown function: count()}}
|
||||
do_catchsql_test table-16.6 {
|
||||
DROP TABLE t16;
|
||||
CREATE TABLE t16(x DEFAULT(group_concat('x',',')));
|
||||
INSERT INTO t16(rowid) VALUES(123);
|
||||
SELECT rowid, x FROM t16;
|
||||
} {1 {unknown function: group_concat()}}
|
||||
do_catchsql_test table-16.7 {
|
||||
INSERT INTO t16 DEFAULT VALUES;
|
||||
} {1 {unknown function: group_concat()}}
|
||||
|
||||
finish_test
|
||||
|
@ -869,6 +869,7 @@ proc speed_trial_summary {name} {
|
||||
#
|
||||
proc finish_test {} {
|
||||
catch {db close}
|
||||
catch {db1 close}
|
||||
catch {db2 close}
|
||||
catch {db3 close}
|
||||
if {0==[info exists ::SLAVE]} { finalize_testing }
|
||||
|
@ -160,6 +160,10 @@ do_execsql_test tkt-80e031a00f.322 {SELECT 'b' IN t8} 1
|
||||
do_execsql_test tkt-80e031a00f.323 {SELECT 'c' NOT IN t8} 0
|
||||
do_execsql_test tkt-80e031a00f.324 {SELECT 'c' IN t8n} 1
|
||||
do_execsql_test tkt-80e031a00f.325 {SELECT 'd' NOT IN t8n} 0
|
||||
do_execsql_test tkt-80e031a00f.326 {SELECT 'a' IN (NULL,'a')} 1
|
||||
do_execsql_test tkt-80e031a00f.327 {SELECT 'a' IN (NULL,'b')} {{}}
|
||||
do_execsql_test tkt-80e031a00f.328 {SELECT 'a' NOT IN (NULL,'a')} 0
|
||||
do_execsql_test tkt-80e031a00f.329 {SELECT 'a' NOT IN (NULL,'b')} {{}}
|
||||
#
|
||||
# Row 4:
|
||||
do_execsql_test tkt-80e031a00f.400 {SELECT 1 IN (2,3,4,null)} {{}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user