1
0
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:
drh 2014-08-06 01:25:47 +00:00
commit 58c4cbe152
30 changed files with 549 additions and 266 deletions

View File

@ -1,5 +1,5 @@
C Merge\sthe\sfix\sfor\sthe\sCREATE\sUNIQUE\sINDEX\sproblem\sinto\sthe\ssessions\sbranch. C Merge\sthe\slatest\s3.8.6\sbeta\schanges\sfrom\strunk.
D 2014-07-30T14:29:54.721 D 2014-08-06T01:25:47.611
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 639859a6f81bd15921ccd56ddbd6dfd335278377 F Makefile.in 639859a6f81bd15921ccd56ddbd6dfd335278377
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -175,30 +175,30 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 3d8b83c91651f53472ca17599dae3457b8b89494 F sqlite3.1 3d8b83c91651f53472ca17599dae3457b8b89494
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
F src/alter.c b00900877f766f116f9e16116f1ccacdc21d82f1 F src/alter.c b00900877f766f116f9e16116f1ccacdc21d82f1
F src/analyze.c de34a73b86db9dc3a16beef12cc5573c50223956 F src/analyze.c f98a351908da29f7b44741cfeb9eb20dda648ba0
F src/attach.c 3801129015ef59d76bf23c95ef9b0069d18a0c52 F src/attach.c 3801129015ef59d76bf23c95ef9b0069d18a0c52
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53 F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
F src/btree.c b5531339cd826af46b9621e4a9323971a9380e12 F src/btree.c 99d162e57af6e72ffd7db5bf79568a134cd87d5b
F src/btree.h 4245a349bfe09611d7ff887dbc3a80cee8b7955a F src/btree.h 4245a349bfe09611d7ff887dbc3a80cee8b7955a
F src/btreeInt.h cf180d86b2e9e418f638d65baa425c4c69c0e0e3 F src/btreeInt.h cf180d86b2e9e418f638d65baa425c4c69c0e0e3
F src/build.c 7ba21d8f0f5f1e8b5a0ed21aab9be2b39d1af516 F src/build.c 5abf794fe8a605f2005b422e98a3cedad9b9ef5b
F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98 F src/callback.c fcff28cf0df2403dd2f313bb8d1b8f31f6f3cd64
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a F src/ctime.c 0231df905e2c4abba4483ee18ffc05adc321df2a
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625 F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
F src/delete.c 50b74c1dde25d1ebcb4fa5c870762e6470ee46f1 F src/delete.c 50b74c1dde25d1ebcb4fa5c870762e6470ee46f1
F src/expr.c b989d07fc7c8780fff77365a4fc59881223e340c F src/expr.c f749009cf4a8534efb5e0d5cd7c9fb1fb0f2836c
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c a549cff9fe8b736cdae21650ea0af6de29b77619 F src/fkey.c 8545f3b36da47473e10800ea4fb0810fd4062514
F src/func.c 3bc223ea36cd29a91c481485343d0ee4257ab8dc F src/func.c 3bc223ea36cd29a91c481485343d0ee4257ab8dc
F src/global.c 1e4bd956dc2f608f87d2a929abc4a20db65f30e4 F src/global.c 1e4bd956dc2f608f87d2a929abc4a20db65f30e4
F src/hash.c d139319967164f139c8d1bb8a11b14db9c4ba3cd F src/hash.c d139319967164f139c8d1bb8a11b14db9c4ba3cd
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22 F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
F src/insert.c 3f5e6cb2cfea0c20a11d51da943395ac480122cb F src/insert.c b1f57e168d39fed8a0d3d891bf38091b104dd707
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12 F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
@ -211,18 +211,18 @@ F src/mem2.c dce31758da87ec2cfa52ba4c5df1aed6e07d8e8f
F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534 F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
F src/mem5.c 74670012946c4adc8a6ad84d03acc80959c3e529 F src/mem5.c 74670012946c4adc8a6ad84d03acc80959c3e529
F src/memjournal.c 0683aac6cab6ec2b5374c0db37c0deb2436a3785 F src/memjournal.c 0683aac6cab6ec2b5374c0db37c0deb2436a3785
F src/mutex.c d3b66a569368015e0fcb1ac15f81c119f504d3bc F src/mutex.c 84a073c9a23a8d7bdd2ea832522d1730df18812c
F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea
F src/mutex_noop.c 7682796b7d8d39bf1c138248858efcd10c9e1553 F src/mutex_noop.c f3f09fd7a2eb4287cfc799753ffc30380e7b71a1
F src/mutex_unix.c c3a4e00f96ba068a8dbef34084465979aaf369cc F src/mutex_unix.c 1b10d5413dfc794364a8adf3eb3a192926b43fa3
F src/mutex_w32.c 45020ed78735a202ff14efcf19415d29f556f16d F src/mutex_w32.c c50939b72368f1cfbddb58520372081a50558548
F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30 F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
F src/os.c 1b147e4cf7cc39e618115c14a086aed44bc91ace F src/os.c 1b147e4cf7cc39e618115c14a086aed44bc91ace
F src/os.h 60d419395e32a8029fa380a80a3da2e9030f635e F src/os.h 60d419395e32a8029fa380a80a3da2e9030f635e
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
F src/os_unix.c a7baf1b30f3c58ba20b813e01aab23b18ae44f85 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/os_win.h 057344a6720b4c8405d9bd98f58cb37a6ee46c25
F src/pager.c f6bb1fa6cdf2062f2d8aec3e64db302bca519ab8 F src/pager.c f6bb1fa6cdf2062f2d8aec3e64db302bca519ab8
F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428 F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428
@ -230,23 +230,23 @@ F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0
F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2 F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c
F src/pragma.c 30f3b2ac09fef58320375d78e0e18b976198fc69 F src/pragma.c d10ef67c4de79f78188b965b4b7988aff1d66f2e
F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337 F src/prepare.c 677521ab7132615a8a26107a1d1c3132f44ae337
F src/printf.c af06f66927919730f03479fed6ae9854f73419f4 F src/printf.c af06f66927919730f03479fed6ae9854f73419f4
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
F src/resolve.c 5fc110baeacf120a73fe34e103f052632ff11a02 F src/resolve.c 5fc110baeacf120a73fe34e103f052632ff11a02
F src/rowset.c a9c9aae3234b44a6d7c6f5a3cadf90dce1e627be F src/rowset.c a9c9aae3234b44a6d7c6f5a3cadf90dce1e627be
F src/select.c 6762c62e11b504aa014edceab8886495165e3a77 F src/select.c 1529c49075464c5a95fde77314073612b1b8d595
F src/shell.c 191129c3f7a9cf241aea90ff6a6be3e74d3767f0 F src/shell.c 191129c3f7a9cf241aea90ff6a6be3e74d3767f0
F src/sqlite.h.in c5940e8fdc6b2b046bb00a07edb1cc3fa342bd5d F src/sqlite.h.in 6b18f91758d1816f8cc2596d7a2c89c9db348ff5
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
F src/sqliteInt.h 56c7fe562722601d83a53bd8b5262a975851bf95 F src/sqliteInt.h d60dbbadfd64374a5a2f362fc6f45899540c2c8e
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/tclsqlite.c 7ada527ce7916adcabad7997c10f09680aac7c9b F src/tclsqlite.c 7ada527ce7916adcabad7997c10f09680aac7c9b
F src/test1.c 3c8bc491d2f8de5adbbf306533cefc343c733927 F src/test1.c 14409a611e9c27c6c522c610bbff5561f05c1558
F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712 F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
@ -271,8 +271,8 @@ F src/test_intarray.h 2ece66438cfd177b78d1bfda7a4180cd3a10844d
F src/test_journal.c f5c0a05b7b3d5930db769b5ee6c3766dc2221a64 F src/test_journal.c f5c0a05b7b3d5930db769b5ee6c3766dc2221a64
F src/test_loadext.c a5251f956ab6af21e138dc1f9c0399394a510cb4 F src/test_loadext.c a5251f956ab6af21e138dc1f9c0399394a510cb4
F src/test_malloc.c 1ff5b1243d96124c9a180f3b89424820a1f337f3 F src/test_malloc.c 1ff5b1243d96124c9a180f3b89424820a1f337f3
F src/test_multiplex.c 9f304bf04170c91c0318238d512df2da039eb1c8 F src/test_multiplex.c ca90057438b63bf0840ebb84d0ef050624519a76
F src/test_multiplex.h 110a8c4d356e0aa464ca8730375608a9a0b61ae1 F src/test_multiplex.h c08e4e8f8651f0c5e0509b138ff4d5b43ed1f5d3
F src/test_mutex.c 293042d623ebba969160f471a82aa1551626454f F src/test_mutex.c 293042d623ebba969160f471a82aa1551626454f
F src/test_onefile.c 0396f220561f3b4eedc450cef26d40c593c69a25 F src/test_onefile.c 0396f220561f3b4eedc450cef26d40c593c69a25
F src/test_osinst.c 3d0340bc31a9f3d8a3547e0272373e80f78dde25 F src/test_osinst.c 3d0340bc31a9f3d8a3547e0272373e80f78dde25
@ -293,11 +293,11 @@ F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/tokenize.c ae45399d6252b4d736af43bee1576ce7bff86aec F src/tokenize.c ae45399d6252b4d736af43bee1576ce7bff86aec
F src/trigger.c 66f3470b03b52b395e839155786966e3e037fddb F src/trigger.c 66f3470b03b52b395e839155786966e3e037fddb
F src/update.c 0f16e1d55d642a7ae3199bd0c2c1f51a7ef1b9d4 F src/update.c b0f38fda25d532343d54b7dc49f55ab73e92ca45
F src/utf.c a0314e637768a030e6e84a957d0c4f6ba910cc05 F src/utf.c a0314e637768a030e6e84a957d0c4f6ba910cc05
F src/util.c 3076bdd51cdbf60a6e2e57fada745be37133c73e F src/util.c 3076bdd51cdbf60a6e2e57fada745be37133c73e
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
F src/vdbe.c 79cd84435224f9f4edd420467f3a7bad29fffa8f F src/vdbe.c 54fa84fdd992886dcb1a4c0cec2ae686d2d18b2b
F src/vdbe.h ca3b6df299adce6e2f499c57e42ae54f142ae823 F src/vdbe.h ca3b6df299adce6e2f499c57e42ae54f142ae823
F src/vdbeInt.h 5eee1752eff410de9373196e2b327f7deefb3920 F src/vdbeInt.h 5eee1752eff410de9373196e2b327f7deefb3920
F src/vdbeapi.c 52335de5ff97bba93d6779d8df87feab5d53d7df F src/vdbeapi.c 52335de5ff97bba93d6779d8df87feab5d53d7df
@ -310,7 +310,7 @@ F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
F src/wal.c 264df50a1b33124130b23180ded2e2c5663c652a F src/wal.c 264df50a1b33124130b23180ded2e2c5663c652a
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45 F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
F src/where.c 4dfcd80380d154be434c4b51e890e17ce9754b3e F src/where.c ce1b9a3a2573033cd15e0882719db7f211f21cdd
F src/whereInt.h 929c1349b5355fd44f22cee5c14d72b3329c58a6 F src/whereInt.h 929c1349b5355fd44f22cee5c14d72b3329c58a6
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
@ -621,7 +621,7 @@ F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
F test/in.test 047c4671328e9032ab95666a67021adbbd36e98e F test/in.test 047c4671328e9032ab95666a67021adbbd36e98e
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75 F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0 F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
F test/in4.test 41c1c031aa46b1eb4411df2687ed2ed498da23b5 F test/in4.test d2b38cba404bc4320f4fe1b595b3d163f212c068
F test/in5.test 99f9a40af01711b06d2d614ecfe96129f334fba3 F test/in5.test 99f9a40af01711b06d2d614ecfe96129f334fba3
F test/incrblob.test e81846d214f3637622620fbde7cd526781cfe328 F test/incrblob.test e81846d214f3637622620fbde7cd526781cfe328
F test/incrblob2.test bf4d549aa4a466d7fbe3e3a3693d3861263d5600 F test/incrblob2.test bf4d549aa4a466d7fbe3e3a3693d3861263d5600
@ -733,7 +733,7 @@ F test/mmap1.test 93d167b328255cbe6679fe1e1a23be1b1197d07b
F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022 F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022
F test/mmap3.test c92273e16eb8d23c1d55c9815b446bb72ef0512e F test/mmap3.test c92273e16eb8d23c1d55c9815b446bb72ef0512e
F test/mmapfault.test d4c9eff9cd8c2dc14bc43e71e042f175b0a26fe3 F test/mmapfault.test d4c9eff9cd8c2dc14bc43e71e042f175b0a26fe3
F test/multiplex.test e08cc7177bd6d85990ee1d71100bb6c684c02256 F test/multiplex.test efd015ca0b5b4a57dc9535b8feb1273eebeadb60
F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a
F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101 F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101
F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41 F test/mutex1.test 78b2b9bb320e51d156c4efdb71b99b051e7a4b41
@ -768,7 +768,7 @@ F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54 F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54
F test/permutations.test bf568516e21758f2961a4612f29dc422d3ab75c1 F test/permutations.test bf568516e21758f2961a4612f29dc422d3ab75c1
F test/pragma.test adb21a90875bc54a880fa939c4d7c46598905aa0 F test/pragma.test 19d0241a007bcdd77fc2606ec60fc60357e7fc8b
F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13 F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
F test/printf2.test bed79b4c3e5da08ba88ad637c0bf62586843cfb1 F test/printf2.test bed79b4c3e5da08ba88ad637c0bf62586843cfb1
@ -871,14 +871,14 @@ F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2
F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85 F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85
F test/syscall.test d2fdaad713f103ac611fe7ef9b724c7b69f8149c F test/syscall.test d2fdaad713f103ac611fe7ef9b724c7b69f8149c
F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6 F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6
F test/table.test 580d23530187026d4502fae74a490f0408cf2cc7 F test/table.test 2a1d2fa52c531de5915f28023747d9a8c27b6f31
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126 F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930 F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
F test/tclsqlite.test a7308276aad2e6c0bfb5b0414424dd0d9cc0cad7 F test/tclsqlite.test a7308276aad2e6c0bfb5b0414424dd0d9cc0cad7
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30 F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1 F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1
F test/tester.tcl 8bab16cd983b4207203d82b7de229aa7b457f575 F test/tester.tcl eac48cc21d519ac33a4fbaa3b425d178861fe741
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5 F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@ -916,7 +916,7 @@ F test/tkt-78e04e52ea.test 813779f8888f3ca226df656c4eef078f9635f3c9
F test/tkt-7a31705a7e6.test e75a2bba4eec801b92c8040eb22096ac6d35e844 F test/tkt-7a31705a7e6.test e75a2bba4eec801b92c8040eb22096ac6d35e844
F test/tkt-7bbfb7d442.test 7b2cd79c7a17ae6750e75ec1a7846712a69c9d18 F test/tkt-7bbfb7d442.test 7b2cd79c7a17ae6750e75ec1a7846712a69c9d18
F test/tkt-80ba201079.test 105a721e6aad0ae3c5946d7615d1e4d03f6145b8 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-8454a207b9.test c583a9f814a82a2b5ba95207f55001c9f0cd816c
F test/tkt-868145d012.test a5f941107ece6a64410ca4755c6329b7eb57a356 F test/tkt-868145d012.test a5f941107ece6a64410ca4755c6329b7eb57a356
F test/tkt-8c63ff0ec.test 258b7fc8d7e4e1cb5362c7d65c143528b9c4cbed 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-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 8f1beeade0ddf802900c9d203a4fd678d1190394 6b785e92f279cb65746834d5cd25594fd3333342 P 43401ee624587ffa166c3cda7e5265ad0d81da5c 717245d48714c08156c9b7636aaa6c3a402bad66
R 4306541d4063ef0a1799e70c4c3d4ff7 R dc185340dec02c23864326e2a38aabfb
U drh U drh
Z 69e112d4dad31a7cb28801f346a66d8a Z 89e6d570704a9eb31c76806cdd19debb

View File

@ -1 +1 @@
43401ee624587ffa166c3cda7e5265ad0d81da5c 68a6d5e2f43702c78057ae2f2a7345c981d24e17

View File

@ -1129,7 +1129,7 @@ static void analyzeOneTable(
*/ */
sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeAddOp0(v, OP_Goto);
addrNextRow = sqlite3VdbeCurrentAddr(v); 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 /* 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 ** row, we know that all the rest will be distinct, so skip
** subsequent distinctness tests. */ ** subsequent distinctness tests. */

View File

@ -162,7 +162,7 @@ static int hasSharedCacheTableLock(
** the correct locks are held. So do not bother - just return true. ** the correct locks are held. So do not bother - just return true.
** This case does not come up very often anyhow. ** 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; return 1;
} }

View File

@ -2130,7 +2130,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
pSelTab->aCol = 0; pSelTab->aCol = 0;
sqlite3DeleteTable(db, pSelTab); sqlite3DeleteTable(db, pSelTab);
assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) ); assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) );
pTable->pSchema->flags |= DB_UnresetViews; pTable->pSchema->schemaFlags |= DB_UnresetViews;
}else{ }else{
pTable->nCol = 0; pTable->nCol = 0;
nErr++; nErr++;
@ -2707,7 +2707,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v); addr1 = sqlite3VdbeAddOp2(v, OP_SorterSort, iSorter, 0); VdbeCoverage(v);
assert( pKey!=0 || db->mallocFailed || pParse->nErr ); assert( pKey!=0 || db->mallocFailed || pParse->nErr );
if( pIndex->onError!=OE_None && pKey!=0 ){ if( IsUniqueIndex(pIndex) && pKey!=0 ){
int j2 = sqlite3VdbeCurrentAddr(v) + 3; int j2 = sqlite3VdbeCurrentAddr(v) + 3;
sqlite3VdbeAddOp2(v, OP_Goto, 0, j2); sqlite3VdbeAddOp2(v, OP_Goto, 0, j2);
addr2 = sqlite3VdbeCurrentAddr(v); addr2 = sqlite3VdbeCurrentAddr(v);
@ -3104,9 +3104,9 @@ Index *sqlite3CreateIndex(
Index *pIdx; Index *pIdx;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
int k; int k;
assert( pIdx->onError!=OE_None ); assert( IsUniqueIndex(pIdx) );
assert( pIdx->idxType!=SQLITE_IDXTYPE_APPDEF ); assert( pIdx->idxType!=SQLITE_IDXTYPE_APPDEF );
assert( pIndex->onError!=OE_None ); assert( IsUniqueIndex(pIndex) );
if( pIdx->nKeyCol!=pIndex->nKeyCol ) continue; if( pIdx->nKeyCol!=pIndex->nKeyCol ) continue;
for(k=0; k<pIdx->nKeyCol; k++){ for(k=0; k<pIdx->nKeyCol; k++){
@ -3297,7 +3297,7 @@ void sqlite3DefaultRowEst(Index *pIdx){
} }
assert( 0==sqlite3LogEst(1) ); assert( 0==sqlite3LogEst(1) );
if( pIdx->onError!=OE_None ) a[pIdx->nKeyCol] = 0; if( IsUniqueIndex(pIdx) ) a[pIdx->nKeyCol] = 0;
} }
/* /*

View File

@ -447,9 +447,9 @@ void sqlite3SchemaClear(void *p){
sqlite3HashClear(&temp1); sqlite3HashClear(&temp1);
sqlite3HashClear(&pSchema->fkeyHash); sqlite3HashClear(&pSchema->fkeyHash);
pSchema->pSeqTab = 0; pSchema->pSeqTab = 0;
if( pSchema->flags & DB_SchemaLoaded ){ if( pSchema->schemaFlags & DB_SchemaLoaded ){
pSchema->iGeneration++; pSchema->iGeneration++;
pSchema->flags &= ~DB_SchemaLoaded; pSchema->schemaFlags &= ~DB_SchemaLoaded;
} }
} }

View File

@ -1368,6 +1368,9 @@ int sqlite3ExprCanBeNull(const Expr *p){
case TK_FLOAT: case TK_FLOAT:
case TK_BLOB: case TK_BLOB:
return 0; return 0;
case TK_COLUMN:
assert( p->pTab!=0 );
return p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0;
default: default:
return 1; return 1;
} }
@ -1475,6 +1478,40 @@ int sqlite3CodeOnce(Parse *pParse){
return sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++); 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. ** 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 ** 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 ** be used either to test for membership in the RHS set or to iterate through
** all members of the RHS set, skipping duplicates. ** 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. ** and pX->iTable is set to the index of that cursor.
** **
** The returned value of this function indicates the b-tree type, as follows: ** 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_INDEX_DESC - The cursor was opened on a descending index.
** IN_INDEX_EPH - The cursor was opened on a specially created and ** IN_INDEX_EPH - The cursor was opened on a specially created and
** populated epheremal table. ** 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 ** An existing b-tree might be used if the RHS expression pX is a simple
** subquery such as: ** 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 ** 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 ** 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 ** 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 ** The inFlags parameter must contain exactly one of the bits
** through the set members, skipping any duplicates. In this case an ** IN_INDEX_MEMBERSHIP or IN_INDEX_LOOP. If inFlags contains
** epheremal table must be used unless the selected <column> is guaranteed ** 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 ** to be unique - either because it is an INTEGER PRIMARY KEY or it
** has a UNIQUE constraint or UNIQUE index. ** has a UNIQUE constraint or UNIQUE index.
** **
** If the prNotFound parameter is not 0, then the b-tree will be used ** When IN_INDEX_MEMBERSHIP is used (and the b-tree will be used
** for fast set membership tests. In this case an epheremal table must ** for fast set membership tests) then an epheremal table must
** be used unless <column> is an INTEGER PRIMARY KEY or an index can ** be used unless <column> is an INTEGER PRIMARY KEY or an index can
** be found with <column> as its left-most column. ** 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 ** 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 ** might need to know whether or not the RHS side of the IN operator
** value in order to correctly evaluate expressions like "X IN (Y, Z)". ** contains a NULL. If prRhsHasNull is not a NULL pointer and
** If there is any chance that the (...) might contain a NULL value at ** if there is any chance that the (...) might contain a NULL value at
** runtime, then a register is allocated and the register number written ** runtime, then a register is allocated and the register number written
** to *prNotFound. If there is no chance that the (...) contains a ** to *prRhsHasNull. If there is no chance that the (...) contains a
** NULL value, then *prNotFound is left unchanged. ** NULL value, then *prRhsHasNull is left unchanged.
** **
** If a register is allocated and its location stored in *prNotFound, then ** If a register is allocated and its location stored in *prRhsHasNull, then
** its initial value is NULL. If the (...) does not remain constant ** the value in that register will be NULL if the b-tree contains one or more
** for the duration of the query (i.e. the SELECT within the (...) ** NULL values, and it will be some non-NULL value if the b-tree contains no
** is a correlated subquery) then the value of the allocated register is ** NULL values.
** 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.
*/ */
#ifndef SQLITE_OMIT_SUBQUERY #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 */ Select *p; /* SELECT to the right of IN operator */
int eType = 0; /* Type of RHS table. IN_INDEX_* */ int eType = 0; /* Type of RHS table. IN_INDEX_* */
int iTab = pParse->nTab++; /* Cursor of the RHS table */ 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 */ Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
assert( pX->op==TK_IN ); assert( pX->op==TK_IN );
mustBeUnique = (inFlags & IN_INDEX_LOOP)!=0;
/* Check to see if an existing table or index can be used to /* Check to see if an existing table or index can be used to
** satisfy the query. This is preferable to generating a new ** 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){ for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){
if( (pIdx->aiColumn[0]==iCol) if( (pIdx->aiColumn[0]==iCol)
&& sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq && 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); int iAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb); 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 ); assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0]; eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
if( prNotFound && !pTab->aCol[iCol].notNull ){ if( prRhsHasNull && !pTab->aCol[iCol].notNull ){
*prNotFound = ++pParse->nMem; *prRhsHasNull = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound); sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull);
} }
sqlite3VdbeJumpHere(v, iAddr); 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 ){ 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. ** We will have to generate an ephemeral table to do the job.
*/ */
u32 savedNQueryLoop = pParse->nQueryLoop; u32 savedNQueryLoop = pParse->nQueryLoop;
int rMayHaveNull = 0; int rMayHaveNull = 0;
eType = IN_INDEX_EPH; eType = IN_INDEX_EPH;
if( prNotFound ){ if( inFlags & IN_INDEX_LOOP ){
*prNotFound = rMayHaveNull = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Null, 0, *prNotFound);
}else{
pParse->nQueryLoop = 0; pParse->nQueryLoop = 0;
if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){ if( pX->pLeft->iColumn<0 && !ExprHasProperty(pX, EP_xIsSelect) ){
eType = IN_INDEX_ROWID; eType = IN_INDEX_ROWID;
} }
}else if( prRhsHasNull ){
*prRhsHasNull = rMayHaveNull = ++pParse->nMem;
} }
sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID); sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID);
pParse->nQueryLoop = savedNQueryLoop; 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 ** 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. ** (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 ** All this routine does is initialize the register given by rMayHaveNull
** to iterate over the RHS of the IN operator in order to quickly locate ** to NULL. Calling routines will take care of changing this register
** all corresponding LHS elements. All this routine does is initialize ** value to non-NULL if the RHS is NULL-free.
** 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.
** **
** For a SELECT or EXISTS operator, return the register that holds the ** 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. ** 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( int sqlite3CodeSubselect(
Parse *pParse, /* Parsing context */ Parse *pParse, /* Parsing context */
Expr *pExpr, /* The IN, SELECT, or EXISTS operator */ 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 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 */ int rReg = 0; /* Register storing resulting */
Vdbe *v = sqlite3GetVdbe(pParse); Vdbe *v = sqlite3GetVdbe(pParse);
if( NEVER(v==0) ) return 0; if( NEVER(v==0) ) return 0;
@ -1705,13 +1758,13 @@ int sqlite3CodeSubselect(
** save the results, and reuse the same result on subsequent invocations. ** save the results, and reuse the same result on subsequent invocations.
*/ */
if( !ExprHasProperty(pExpr, EP_VarSelect) ){ if( !ExprHasProperty(pExpr, EP_VarSelect) ){
testAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v); jmpIfDynamic = sqlite3CodeOnce(pParse); VdbeCoverage(v);
} }
#ifndef SQLITE_OMIT_EXPLAIN #ifndef SQLITE_OMIT_EXPLAIN
if( pParse->explain==2 ){ if( pParse->explain==2 ){
char *zMsg = sqlite3MPrintf( 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 pExpr->op==TK_IN?"LIST":"SCALAR", pParse->iNextSelectId
); );
sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC); 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 */ Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */
KeyInfo *pKeyInfo = 0; /* Key information */ KeyInfo *pKeyInfo = 0; /* Key information */
if( rMayHaveNull ){
sqlite3VdbeAddOp2(v, OP_Null, 0, rMayHaveNull);
}
affinity = sqlite3ExprAffinity(pLeft); affinity = sqlite3ExprAffinity(pLeft);
/* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)' /* 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 ** Generate code to write the results of the select into the temporary
** table allocated and opened above. ** table allocated and opened above.
*/ */
Select *pSelect = pExpr->x.pSelect;
SelectDest dest; SelectDest dest;
ExprList *pEList; ExprList *pEList;
@ -1761,13 +1811,15 @@ int sqlite3CodeSubselect(
sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable); sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
dest.affSdst = (u8)affinity; dest.affSdst = (u8)affinity;
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable ); 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() */ testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){ if( sqlite3Select(pParse, pSelect, &dest) ){
sqlite3KeyInfoUnref(pKeyInfo); sqlite3KeyInfoUnref(pKeyInfo);
return 0; return 0;
} }
pEList = pExpr->x.pSelect->pEList; pEList = pSelect->pEList;
assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */ assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */
assert( pEList!=0 ); assert( pEList!=0 );
assert( pEList->nExpr>0 ); assert( pEList->nExpr>0 );
@ -1798,7 +1850,7 @@ int sqlite3CodeSubselect(
/* Loop through each expression in <exprlist>. */ /* Loop through each expression in <exprlist>. */
r1 = sqlite3GetTempReg(pParse); r1 = sqlite3GetTempReg(pParse);
r2 = 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++){ for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){
Expr *pE2 = pItem->pExpr; Expr *pE2 = pItem->pExpr;
int iValToIns; int iValToIns;
@ -1808,9 +1860,9 @@ int sqlite3CodeSubselect(
** this code only executes once. Because for a non-constant ** this code only executes once. Because for a non-constant
** expression we need to rerun this code each time. ** expression we need to rerun this code each time.
*/ */
if( testAddr>=0 && !sqlite3ExprIsConstant(pE2) ){ if( jmpIfDynamic>=0 && !sqlite3ExprIsConstant(pE2) ){
sqlite3VdbeChangeToNoop(v, testAddr); sqlite3VdbeChangeToNoop(v, jmpIfDynamic);
testAddr = -1; jmpIfDynamic = -1;
} }
/* Evaluate the expression and insert it into the temp table */ /* Evaluate the expression and insert it into the temp table */
@ -1880,8 +1932,12 @@ int sqlite3CodeSubselect(
} }
} }
if( testAddr>=0 ){ if( rHasNullFlag ){
sqlite3VdbeJumpHere(v, testAddr); sqlite3SetHasNullFlag(v, pExpr->iTable, rHasNullFlag);
}
if( jmpIfDynamic>=0 ){
sqlite3VdbeJumpHere(v, jmpIfDynamic);
} }
sqlite3ExprCachePop(pParse); 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 ** if the LHS is NULL or if the LHS is not contained within the RHS and the
** RHS contains one or more NULL values. ** 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 ** 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 ** is contained in the RHS then jump to destIfNull. If the LHS is contained
** within the RHS then fall through. ** within the RHS then fall through.
@ -1925,7 +1981,9 @@ static void sqlite3ExprCodeIN(
v = pParse->pVdbe; v = pParse->pVdbe;
assert( v!=0 ); /* OOM detected prior to this routine */ assert( v!=0 ); /* OOM detected prior to this routine */
VdbeNoopComment((v, "begin IN expr")); 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 /* Figure out the affinity to use to create a key from the results
** of the expression. affinityStr stores a static string suitable for ** of the expression. affinityStr stores a static string suitable for
@ -1939,82 +1997,114 @@ static void sqlite3ExprCodeIN(
r1 = sqlite3GetTempReg(pParse); r1 = sqlite3GetTempReg(pParse);
sqlite3ExprCode(pParse, pExpr->pLeft, r1); sqlite3ExprCode(pParse, pExpr->pLeft, r1);
/* If the LHS is NULL, then the result is either false or NULL depending /* If sqlite3FindInIndex() did not find or create an index that is
** on whether the RHS is empty or not, respectively. ** suitable for evaluating the IN operator, then evaluate using a
** sequence of comparisons.
*/ */
if( destIfNull==destIfFalse ){ if( eType==IN_INDEX_NOOP ){
/* Shortcut for the common case where the false and NULL outcomes are ExprList *pList = pExpr->x.pList;
** the same. */ CollSeq *pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v); 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, &regToFree);
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{ }else{
int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse); /* If the LHS is NULL, then the result is either false or NULL depending
VdbeCoverage(v); ** on whether the RHS is empty or not, respectively.
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
*/ */
sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); VdbeCoverage(v); if( sqlite3ExprCanBeNull(pExpr->pLeft) ){
sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, destIfFalse, r1); if( destIfNull==destIfFalse ){
VdbeCoverage(v); /* Shortcut for the common case where the false and NULL outcomes are
}else{ ** the same. */
/* In this case, the RHS is an index b-tree. sqlite3VdbeAddOp2(v, OP_IsNull, r1, destIfNull); VdbeCoverage(v);
*/ }else{
sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1); int addr1 = sqlite3VdbeAddOp1(v, OP_NotNull, r1); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Rewind, pExpr->iTable, destIfFalse);
/* If the set membership test fails, then the result of the VdbeCoverage(v);
** "x IN (...)" expression must be either 0 or NULL. If the set sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
** contains no NULL values, then the result is 0. If the set sqlite3VdbeJumpHere(v, addr1);
** contains one or more NULL values, then the result of the }
** expression is also NULL. }
*/
if( rRhsHasNull==0 || destIfFalse==destIfNull ){ if( eType==IN_INDEX_ROWID ){
/* This branch runs if it is known at compile time that the RHS /* In this case, the RHS is the ROWID of table b-tree
** 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); sqlite3VdbeAddOp2(v, OP_MustBeInt, r1, destIfFalse); VdbeCoverage(v);
sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, destIfFalse, r1);
VdbeCoverage(v); VdbeCoverage(v);
}else{ }else{
/* In this branch, the RHS of the IN might contain a NULL and /* In this case, the RHS is an index b-tree.
** the presence of a NULL on the RHS makes a difference in the
** outcome.
*/ */
int j1, j2; sqlite3VdbeAddOp4(v, OP_Affinity, r1, 1, 0, &affinity, 1);
/* First check to see if the LHS is contained in the RHS. If so, /* If the set membership test fails, then the result of the
** then the presence of NULLs in the RHS does not matter, so jump ** "x IN (...)" expression must be either 0 or NULL. If the set
** over all of the code that follows. ** 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); assert( destIfFalse!=destIfNull || rRhsHasNull==0 );
VdbeCoverage(v); if( rRhsHasNull==0 ){
/* This branch runs if it is known at compile time that the RHS
/* Here we begin generating code that runs if the LHS is not ** cannot contain NULL values. This happens as the result
** contained within the RHS. Generate additional code that ** of a "NOT NULL" constraint in the database schema.
** tests the RHS for NULLs. If the RHS contains a NULL then **
** jump to destIfNull. If there are no NULLs in the RHS then ** Also run this branch if NULL is equivalent to FALSE
** jump to destIfFalse. ** for this particular IN operator.
*/ */
sqlite3VdbeAddOp2(v, OP_If, rRhsHasNull, destIfNull); VdbeCoverage(v); sqlite3VdbeAddOp4Int(v, OP_NotFound, pExpr->iTable, destIfFalse, r1, 1);
sqlite3VdbeAddOp2(v, OP_IfNot, rRhsHasNull, destIfFalse); VdbeCoverage(v); VdbeCoverage(v);
j2 = sqlite3VdbeAddOp4Int(v, OP_Found, pExpr->iTable, 0, rRhsHasNull, 1); }else{
VdbeCoverage(v); /* In this branch, the RHS of the IN might contain a NULL and
sqlite3VdbeAddOp2(v, OP_Integer, 0, rRhsHasNull); ** the presence of a NULL on the RHS makes a difference in the
sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfFalse); ** outcome.
sqlite3VdbeJumpHere(v, j2); */
sqlite3VdbeAddOp2(v, OP_Integer, 1, rRhsHasNull); int j1;
sqlite3VdbeAddOp2(v, OP_Goto, 0, destIfNull);
/* First check to see if the LHS is contained in the RHS. If so,
/* The OP_Found at the top of this branch jumps here when true, ** then the answer is TRUE the presence of NULLs in the RHS does
** causing the overall IN expression evaluation to fall through. ** 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
sqlite3VdbeJumpHere(v, j1); ** 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); sqlite3ReleaseTempReg(pParse, r1);
@ -2638,7 +2728,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
addr = sqlite3VdbeAddOp1(v, op, r1); addr = sqlite3VdbeAddOp1(v, op, r1);
VdbeCoverageIf(v, op==TK_ISNULL); VdbeCoverageIf(v, op==TK_ISNULL);
VdbeCoverageIf(v, op==TK_NOTNULL); VdbeCoverageIf(v, op==TK_NOTNULL);
sqlite3VdbeAddOp2(v, OP_AddImm, target, -1); sqlite3VdbeAddOp2(v, OP_Integer, 0, target);
sqlite3VdbeJumpHere(v, addr); sqlite3VdbeJumpHere(v, addr);
break; break;
} }
@ -2674,7 +2764,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
zId = pExpr->u.zToken; zId = pExpr->u.zToken;
nId = sqlite3Strlen30(zId); nId = sqlite3Strlen30(zId);
pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0); pDef = sqlite3FindFunction(db, zId, nId, nFarg, enc, 0);
if( pDef==0 ){ if( pDef==0 || pDef->xFunc==0 ){
sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId); sqlite3ErrorMsg(pParse, "unknown function: %.*s()", nId, zId);
break; break;
} }

View File

@ -225,7 +225,7 @@ int sqlite3FkLocateIndex(
} }
for(pIdx=pParent->pIndex; pIdx; pIdx=pIdx->pNext){ 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 /* 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 ** of columns. If each indexed column corresponds to a foreign key
** column of pFKey, then this index is a winner. */ ** column of pFKey, then this index is a winner. */

View File

@ -1898,7 +1898,7 @@ static int xferOptimization(
} }
} }
for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){ for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
if( pDestIdx->onError!=OE_None ){ if( IsUniqueIndex(pDestIdx) ){
destHasUniqueIdx = 1; destHasUniqueIdx = 1;
} }
for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){ for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){

View File

@ -81,7 +81,7 @@ int sqlite3MutexEnd(void){
*/ */
sqlite3_mutex *sqlite3_mutex_alloc(int id){ sqlite3_mutex *sqlite3_mutex_alloc(int id){
#ifndef SQLITE_OMIT_AUTOINIT #ifndef SQLITE_OMIT_AUTOINIT
if( sqlite3_initialize() ) return 0; if( id<=SQLITE_MUTEX_RECURSIVE && sqlite3_initialize() ) return 0;
#endif #endif
return sqlite3GlobalConfig.mutex.xMutexAlloc(id); return sqlite3GlobalConfig.mutex.xMutexAlloc(id);
} }

View File

@ -107,7 +107,7 @@ static int debugMutexEnd(void){ return SQLITE_OK; }
** that means that a mutex could not be allocated. ** that means that a mutex could not be allocated.
*/ */
static sqlite3_mutex *debugMutexAlloc(int id){ 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; sqlite3_debug_mutex *pNew = 0;
switch( id ){ switch( id ){
case SQLITE_MUTEX_FAST: case SQLITE_MUTEX_FAST:

View File

@ -96,10 +96,13 @@ static int pthreadMutexEnd(void){ return SQLITE_OK; }
** <li> SQLITE_MUTEX_RECURSIVE ** <li> SQLITE_MUTEX_RECURSIVE
** <li> SQLITE_MUTEX_STATIC_MASTER ** <li> SQLITE_MUTEX_STATIC_MASTER
** <li> SQLITE_MUTEX_STATIC_MEM ** <li> SQLITE_MUTEX_STATIC_MEM
** <li> SQLITE_MUTEX_STATIC_MEM2 ** <li> SQLITE_MUTEX_STATIC_OPEN
** <li> SQLITE_MUTEX_STATIC_PRNG ** <li> SQLITE_MUTEX_STATIC_PRNG
** <li> SQLITE_MUTEX_STATIC_LRU ** <li> SQLITE_MUTEX_STATIC_LRU
** <li> SQLITE_MUTEX_STATIC_PMEM ** <li> SQLITE_MUTEX_STATIC_PMEM
** <li> SQLITE_MUTEX_STATIC_APP1
** <li> SQLITE_MUTEX_STATIC_APP2
** <li> SQLITE_MUTEX_STATIC_APP3
** </ul> ** </ul>
** **
** The first two constants cause sqlite3_mutex_alloc() to create ** 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_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER,
SQLITE3_MUTEX_INITIALIZER SQLITE3_MUTEX_INITIALIZER
}; };
sqlite3_mutex *p; sqlite3_mutex *p;

View File

@ -80,7 +80,10 @@ static int winMutexNotheld(sqlite3_mutex *p){
/* /*
** Initialize and deinitialize the mutex subsystem. ** 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, 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_isInit = 0;
static int winMutex_isNt = -1; /* <0 means "need to query" */
/* As winMutexInit() and winMutexEnd() are called as part of the /* As the winMutexInit() and winMutexEnd() functions are called as part
** sqlite3_initialize() and sqlite3_shutdown() processing, the ** of the sqlite3_initialize() and sqlite3_shutdown() processing, the
** "interlocked" magic used in this section may not strictly ** "interlocked" magic used here is probably not strictly necessary.
** necessary.
*/ */
static LONG winMutex_lock = 0; static LONG volatile winMutex_lock = 0;
int sqlite3_win32_is_nt(void); /* os_win.c */ int sqlite3_win32_is_nt(void); /* os_win.c */
void sqlite3_win32_sleep(DWORD milliseconds); /* 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_RECURSIVE
** <li> SQLITE_MUTEX_STATIC_MASTER ** <li> SQLITE_MUTEX_STATIC_MASTER
** <li> SQLITE_MUTEX_STATIC_MEM ** <li> SQLITE_MUTEX_STATIC_MEM
** <li> SQLITE_MUTEX_STATIC_MEM2 ** <li> SQLITE_MUTEX_STATIC_OPEN
** <li> SQLITE_MUTEX_STATIC_PRNG ** <li> SQLITE_MUTEX_STATIC_PRNG
** <li> SQLITE_MUTEX_STATIC_LRU ** <li> SQLITE_MUTEX_STATIC_LRU
** <li> SQLITE_MUTEX_STATIC_PMEM ** <li> SQLITE_MUTEX_STATIC_PMEM
** <li> SQLITE_MUTEX_STATIC_APP1
** <li> SQLITE_MUTEX_STATIC_APP2
** <li> SQLITE_MUTEX_STATIC_APP3
** </ul> ** </ul>
** **
** The first two constants cause sqlite3_mutex_alloc() to create ** 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->nRef==0 && p->owner==0 );
assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE ); assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
#endif #endif
assert( winMutex_isInit==1 );
DeleteCriticalSection(&p->mutex); DeleteCriticalSection(&p->mutex);
sqlite3_free(p); sqlite3_free(p);
} }
@ -256,6 +263,7 @@ static void winMutexEnter(sqlite3_mutex *p){
#else #else
assert( p ); assert( p );
#endif #endif
assert( winMutex_isInit==1 );
EnterCriticalSection(&p->mutex); EnterCriticalSection(&p->mutex);
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
assert( p->nRef>0 || p->owner==0 ); assert( p->nRef>0 || p->owner==0 );
@ -287,7 +295,13 @@ static int winMutexTry(sqlite3_mutex *p){
** ticket #2685. ** ticket #2685.
*/ */
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400 #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 #ifdef SQLITE_DEBUG
p->owner = tid; p->owner = tid;
p->nRef++; p->nRef++;
@ -324,6 +338,7 @@ static void winMutexLeave(sqlite3_mutex *p){
if( p->nRef==0 ) p->owner = 0; if( p->nRef==0 ) p->owner = 0;
assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE ); assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
#endif #endif
assert( winMutex_isInit==1 );
LeaveCriticalSection(&p->mutex); LeaveCriticalSection(&p->mutex);
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
if( p->trace ){ if( p->trace ){

View File

@ -414,10 +414,9 @@ const sqlite3_mem_methods *sqlite3MemGetWin32(void);
** can manually set this value to 1 to emulate Win98 behavior. ** can manually set this value to 1 to emulate Win98 behavior.
*/ */
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
int sqlite3_os_type = 0; LONG volatile sqlite3_os_type = 0;
#elif !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && \ #else
defined(SQLITE_WIN32_HAS_ANSI) && defined(SQLITE_WIN32_HAS_WIDE) static LONG volatile sqlite3_os_type = 0;
static int sqlite3_os_type = 0;
#endif #endif
#ifndef SYSCALL #ifndef SYSCALL
@ -1048,6 +1047,11 @@ static struct win_syscall {
#define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \ #define osCreateFileMappingFromApp ((HANDLE(WINAPI*)(HANDLE, \
LPSECURITY_ATTRIBUTES,ULONG,ULONG64,LPCWSTR))aSyscall[75].pCurrent) 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 */ }; /* End of the overrideable system calls */
/* /*
@ -1298,7 +1302,7 @@ void sqlite3_win32_sleep(DWORD milliseconds){
#elif !defined(SQLITE_WIN32_HAS_WIDE) #elif !defined(SQLITE_WIN32_HAS_WIDE)
# define osIsNT() (0) # define osIsNT() (0)
#else #else
# define osIsNT() (sqlite3_win32_is_nt()) # define osIsNT() ((sqlite3_os_type==2) || sqlite3_win32_is_nt())
#endif #endif
/* /*
@ -1306,7 +1310,7 @@ void sqlite3_win32_sleep(DWORD milliseconds){
** based on the NT kernel. ** based on the NT kernel.
*/ */
int sqlite3_win32_is_nt(void){ 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 #if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WIN8
OSVERSIONINFOW sInfo; OSVERSIONINFOW sInfo;
sInfo.dwOSVersionInfoSize = sizeof(sInfo); sInfo.dwOSVersionInfoSize = sizeof(sInfo);
@ -1316,9 +1320,10 @@ int sqlite3_win32_is_nt(void){
sInfo.dwOSVersionInfoSize = sizeof(sInfo); sInfo.dwOSVersionInfoSize = sizeof(sInfo);
osGetVersionExA(&sInfo); osGetVersionExA(&sInfo);
#endif #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 #ifdef SQLITE_WIN32_MALLOC
@ -5475,7 +5480,7 @@ int sqlite3_os_init(void){
/* Double-check that the aSyscall[] array has been constructed /* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */ ** correctly. See ticket [bb3a86e890c8e96ab] */
assert( ArraySize(aSyscall)==76 ); assert( ArraySize(aSyscall)==77 );
/* get memory map allocation granularity */ /* get memory map allocation granularity */
memset(&winSysInfo, 0, sizeof(SYSTEM_INFO)); memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));

View File

@ -1544,7 +1544,7 @@ void sqlite3Pragma(
for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){ for(pIdx=pTab->pIndex, i=0; pIdx; pIdx=pIdx->pNext, i++){
sqlite3VdbeAddOp2(v, OP_Integer, i, 1); sqlite3VdbeAddOp2(v, OP_Integer, i, 1);
sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, pIdx->zName, 0); 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); sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 3);
} }
} }
@ -1794,9 +1794,8 @@ void sqlite3Pragma(
*/ */
static const int iLn = VDBE_OFFSET_LINENO(2); static const int iLn = VDBE_OFFSET_LINENO(2);
static const VdbeOpList endCode[] = { static const VdbeOpList endCode[] = {
{ OP_AddImm, 1, 0, 0}, /* 0 */ { OP_IfNeg, 1, 0, 0}, /* 0 */
{ OP_IfNeg, 1, 0, 0}, /* 1 */ { OP_String8, 0, 3, 0}, /* 1 */
{ OP_String8, 0, 3, 0}, /* 2 */
{ OP_ResultRow, 3, 1, 0}, { OP_ResultRow, 3, 1, 0},
}; };
@ -1908,28 +1907,76 @@ void sqlite3Pragma(
pParse->nMem = MAX(pParse->nMem, 8+j); pParse->nMem = MAX(pParse->nMem, 8+j);
sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0); VdbeCoverage(v);
loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1); 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++){ 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; if( pPk==pIdx ) continue;
r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3, r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3,
pPrior, r1); pPrior, r1);
pPrior = pIdx; pPrior = pIdx;
sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1); /* increment entry count */ 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); pIdx->nColumn); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */ sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, "row ", P4_STATIC); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, "row ", P4_STATIC);
sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3); sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, " missing from index ", sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0,
P4_STATIC); " missing from index ", P4_STATIC);
sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3); 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); sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 3);
sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1); sqlite3VdbeAddOp2(v, OP_ResultRow, 3, 1);
jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v); jmp4 = sqlite3VdbeAddOp1(v, OP_IfPos, 1); VdbeCoverage(v);
sqlite3VdbeAddOp0(v, OP_Halt); sqlite3VdbeAddOp0(v, OP_Halt);
sqlite3VdbeJumpHere(v, jmp4);
sqlite3VdbeJumpHere(v, jmp2); 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); sqlite3ResolvePartIdxLabel(pParse, jmp3);
} }
sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Next, iDataCur, loopTop); VdbeCoverage(v);
@ -1954,9 +2001,9 @@ void sqlite3Pragma(
} }
} }
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn); addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode, iLn);
sqlite3VdbeChangeP2(v, addr, -mxErr); sqlite3VdbeChangeP3(v, addr, -mxErr);
sqlite3VdbeJumpHere(v, addr+1); sqlite3VdbeJumpHere(v, addr);
sqlite3VdbeChangeP4(v, addr+2, "ok", P4_STATIC); sqlite3VdbeChangeP4(v, addr+1, "ok", P4_STATIC);
} }
break; break;
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */ #endif /* SQLITE_OMIT_INTEGRITY_CHECK */

View File

@ -541,8 +541,7 @@ static void codeOffset(
){ ){
if( iOffset>0 ){ if( iOffset>0 ){
int addr; int addr;
sqlite3VdbeAddOp2(v, OP_AddImm, iOffset, -1); addr = sqlite3VdbeAddOp3(v, OP_IfNeg, iOffset, 0, -1); VdbeCoverage(v);
addr = sqlite3VdbeAddOp1(v, OP_IfNeg, iOffset); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_Goto, 0, iContinue); sqlite3VdbeAddOp2(v, OP_Goto, 0, iContinue);
VdbeComment((v, "skip OFFSET records")); VdbeComment((v, "skip OFFSET records"));
sqlite3VdbeJumpHere(v, addr); sqlite3VdbeJumpHere(v, addr);

View File

@ -5875,10 +5875,12 @@ int sqlite3_vfs_unregister(sqlite3_vfs*);
** <li> SQLITE_MUTEX_RECURSIVE ** <li> SQLITE_MUTEX_RECURSIVE
** <li> SQLITE_MUTEX_STATIC_MASTER ** <li> SQLITE_MUTEX_STATIC_MASTER
** <li> SQLITE_MUTEX_STATIC_MEM ** <li> SQLITE_MUTEX_STATIC_MEM
** <li> SQLITE_MUTEX_STATIC_MEM2 ** <li> SQLITE_MUTEX_STATIC_OPEN
** <li> SQLITE_MUTEX_STATIC_PRNG ** <li> SQLITE_MUTEX_STATIC_PRNG
** <li> SQLITE_MUTEX_STATIC_LRU ** <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>)^ ** </ul>)^
** **
** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) ** ^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_LRU 6 /* lru page list */
#define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */ #define SQLITE_MUTEX_STATIC_LRU2 7 /* NOT USED */
#define SQLITE_MUTEX_STATIC_PMEM 7 /* sqlite3PageMalloc() */ #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 ** CAPI3REF: Retrieve the mutex for a database connection

View File

@ -877,7 +877,7 @@ struct Schema {
Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */ Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */
u8 file_format; /* Schema format version for this file */ u8 file_format; /* Schema format version for this file */
u8 enc; /* Text encoding used by this database */ 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 */ 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 ** These macros can be used to test, set, or clear bits in the
** Db.pSchema->flags field. ** Db.pSchema->flags field.
*/ */
#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))==(P)) #define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))==(P))
#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))!=0) #define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->schemaFlags&(P))!=0)
#define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->flags|=(P) #define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->schemaFlags|=(P)
#define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->flags&=~(P) #define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->schemaFlags&=~(P)
/* /*
** Allowed values for the DB.pSchema->flags field. ** Allowed values for the DB.pSchema->flags field.
@ -1728,6 +1728,9 @@ struct Index {
/* Return true if index X is a PRIMARY KEY index */ /* Return true if index X is a PRIMARY KEY index */
#define IsPrimaryKeyIndex(X) ((X)->idxType==SQLITE_IDXTYPE_PRIMARYKEY) #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 ** 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 ** using a structure of this type. See documentation at the top of the
@ -3600,11 +3603,21 @@ const char *sqlite3JournalModename(int);
#define sqlite3EndBenignMalloc() #define sqlite3EndBenignMalloc()
#endif #endif
#define IN_INDEX_ROWID 1 /*
#define IN_INDEX_EPH 2 ** Allowed return values from sqlite3FindInIndex()
#define IN_INDEX_INDEX_ASC 3 */
#define IN_INDEX_INDEX_DESC 4 #define IN_INDEX_ROWID 1 /* Search the rowid of the table */
int sqlite3FindInIndex(Parse *, Expr *, int*); #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 #ifdef SQLITE_ENABLE_ATOMIC_WRITE
int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int); int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);

View File

@ -6581,7 +6581,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
extern int sqlite3_pager_writedb_count; extern int sqlite3_pager_writedb_count;
extern int sqlite3_pager_writej_count; extern int sqlite3_pager_writej_count;
#if SQLITE_OS_WIN #if SQLITE_OS_WIN
extern int sqlite3_os_type; extern LONG volatile sqlite3_os_type;
#endif #endif
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
extern int sqlite3WhereTrace; extern int sqlite3WhereTrace;
@ -6639,7 +6639,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
#endif #endif
#if SQLITE_OS_WIN #if SQLITE_OS_WIN
Tcl_LinkVar(interp, "sqlite_os_type", Tcl_LinkVar(interp, "sqlite_os_type",
(char*)&sqlite3_os_type, TCL_LINK_INT); (char*)&sqlite3_os_type, TCL_LINK_LONG);
#endif #endif
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
{ {

View File

@ -1176,14 +1176,20 @@ int sqlite3_multiplex_initialize(const char *zOrigVfsName, int makeDefault){
** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once while ** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once while
** shutting down in order to free all remaining multiplex groups. ** 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.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; gMultiplex.isInitialized = 0;
sqlite3_mutex_free(gMultiplex.pMutex); sqlite3_mutex_free(gMultiplex.pMutex);
sqlite3_vfs_unregister(&gMultiplex.sThisVfs); sqlite3_vfs_unregister(&gMultiplex.sThisVfs);
memset(&gMultiplex, 0, sizeof(gMultiplex)); memset(&gMultiplex, 0, sizeof(gMultiplex));
return SQLITE_OK; return rc;
} }
/***************************** Test Code ***********************************/ /***************************** Test Code ***********************************/
@ -1236,13 +1242,16 @@ static int test_multiplex_shutdown(
UNUSED_PARAMETER(clientData); UNUSED_PARAMETER(clientData);
if( objc!=1 ){ if( objc==2 && strcmp(Tcl_GetString(objv[1]),"-force")!=0 ){
Tcl_WrongNumArgs(interp, 1, objv, ""); objc = 3;
}
if( (objc!=1 && objc!=2) ){
Tcl_WrongNumArgs(interp, 1, objv, "?-force?");
return TCL_ERROR; return TCL_ERROR;
} }
/* Call sqlite3_multiplex_shutdown() */ /* Call sqlite3_multiplex_shutdown() */
rc = sqlite3_multiplex_shutdown(); rc = sqlite3_multiplex_shutdown(objc==2);
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
return TCL_OK; return TCL_OK;

View File

@ -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 ** THIS ROUTINE IS NOT THREADSAFE. Call this routine exactly once while
** shutting down in order to free all remaining multiplex groups. ** 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 #ifdef __cplusplus
} /* End of the 'extern "C"' block */ } /* End of the 'extern "C"' block */

View File

@ -438,7 +438,8 @@ void sqlite3Update(
} }
labelContinue = labelBreak; labelContinue = labelBreak;
sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak); sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak);
VdbeCoverage(v); VdbeCoverageIf(v, pPk==0);
VdbeCoverageIf(v, pPk!=0);
}else if( pPk ){ }else if( pPk ){
labelContinue = sqlite3VdbeMakeLabel(v); labelContinue = sqlite3VdbeMakeLabel(v);
sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v);

View File

@ -126,6 +126,12 @@ int sqlite3_found_count = 0;
** branch can go. It is usually 2. "I" is the direction the branch ** 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 ** goes. 0 means falls through. 1 means branch is taken. 2 means the
** second alternative branch is taken. ** 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) #if !defined(SQLITE_VDBE_COVERAGE)
# define VdbeBranchTaken(I,M) # define VdbeBranchTaken(I,M)
@ -800,7 +806,7 @@ case OP_InitCoroutine: { /* jump */
/* Opcode: EndCoroutine P1 * * * * /* 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. ** Jump to the P2 parameter of that Yield.
** After the jump, register P1 becomes undefined. ** After the jump, register P1 becomes undefined.
** **
@ -993,7 +999,7 @@ case OP_Real: { /* same as TK_FLOAT, out2-prerelease */
** Synopsis: r[P2]='P4' ** Synopsis: r[P2]='P4'
** **
** P4 points to a nul terminated UTF-8 string. This opcode is transformed ** 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 ** this transformation, the length of string P4 is computed and stored
** as the P1 parameter. ** 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 ** 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 ** 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 * * /* Opcode: IfNot P1 P2 P3 * *
** **
** Jump to P2 if the value in register P1 is False. The value ** 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 ** 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_If: /* jump, in1 */
case OP_IfNot: { /* 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. ** 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, ** 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. ** configured to use Next, not Prev.
** **
** See also: Found, NotFound, SeekLt, SeekGt, SeekLe ** 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 ** is a prefix of any entry in P1 then a jump is made to P2 and
** P1 is left pointing at the matching entry. ** P1 is left pointing at the matching entry.
** **
** This operation leaves the cursor in a state where it cannot be ** This operation leaves the cursor in a state where it can be
** advanced in either direction. In other words, the Next and Prev ** advanced in the forward direction. The Next instruction will work,
** opcodes do not work after this operation. ** but not the Prev instruction.
** **
** See also: NotFound, NoConflict, NotExists. SeekGe ** See also: NotFound, NoConflict, NotExists. SeekGe
*/ */
@ -3826,7 +3832,7 @@ case OP_Found: { /* jump, in3 */
pC = p->apCsr[pOp->p1]; pC = p->apCsr[pOp->p1];
assert( pC!=0 ); assert( pC!=0 );
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
pC->seekOp = 0; pC->seekOp = pOp->opcode;
#endif #endif
pIn3 = &aMem[pOp->p3]; pIn3 = &aMem[pOp->p3];
assert( pC->pCursor!=0 ); assert( pC->pCursor!=0 );
@ -4236,7 +4242,7 @@ case OP_InsertInt: {
** The cursor will be left pointing at either the next or the previous ** 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 ** 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 ** 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 ** If the OPFLAG_NCHANGE flag of P2 is set, then the row change count is
** incremented (otherwise not). ** incremented (otherwise not).
@ -4335,7 +4341,7 @@ case OP_ResetCount: {
** Synopsis: if key(P1)!=trim(r[P3],P4) goto P2 ** Synopsis: if key(P1)!=trim(r[P3],P4) goto P2
** **
** P1 is a sorter cursor. This instruction compares a prefix of the ** 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 ** the sorter cursor currently points to. Only the first P4 fields
** of r[P3] and the sorter record are compared. ** 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. */ ** The Prev opcode is only used after SeekLT, SeekLE, and Last. */
assert( pOp->opcode!=OP_Next || pOp->opcode!=OP_NextIfOpen assert( pOp->opcode!=OP_Next || pOp->opcode!=OP_NextIfOpen
|| pC->seekOp==OP_SeekGT || pC->seekOp==OP_SeekGE || 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 assert( pOp->opcode!=OP_Prev || pOp->opcode!=OP_PrevIfOpen
|| pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE || pC->seekOp==OP_SeekLT || pC->seekOp==OP_SeekLE
|| pC->seekOp==OP_Last ); || pC->seekOp==OP_Last );
@ -5661,17 +5667,16 @@ case OP_IfPos: { /* jump, in1 */
break; break;
} }
/* Opcode: IfNeg P1 P2 * * * /* Opcode: IfNeg P1 P2 P3 * *
** Synopsis: if r[P1]<0 goto P2 ** Synopsis: r[P1]+=P3, if r[P1]<0 goto P2
** **
** If the value of register P1 is less than zero, jump to P2. ** 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.
** 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_IfNeg: { /* jump, in1 */ case OP_IfNeg: { /* jump, in1 */
pIn1 = &aMem[pOp->p1]; pIn1 = &aMem[pOp->p1];
assert( pIn1->flags&MEM_Int ); assert( pIn1->flags&MEM_Int );
pIn1->u.i += pOp->p3;
VdbeBranchTaken(pIn1->u.i<0, 2); VdbeBranchTaken(pIn1->u.i<0, 2);
if( pIn1->u.i<0 ){ if( pIn1->u.i<0 ){
pc = pOp->p2 - 1; 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 ** 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. ** 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 */ case OP_IfZero: { /* jump, in1 */
pIn1 = &aMem[pOp->p1]; pIn1 = &aMem[pOp->p1];

View File

@ -1470,7 +1470,7 @@ static int isDistinctRedundant(
** contain a "col=X" term are subject to a NOT NULL constraint. ** contain a "col=X" term are subject to a NOT NULL constraint.
*/ */
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ 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++){ for(i=0; i<pIdx->nKeyCol; i++){
i16 iCol = pIdx->aiColumn[i]; i16 iCol = pIdx->aiColumn[i];
if( 0==findTerm(pWC, iBase, iCol, ~(Bitmask)0, WO_EQ, pIdx) ){ if( 0==findTerm(pWC, iBase, iCol, ~(Bitmask)0, WO_EQ, pIdx) ){
@ -2522,7 +2522,7 @@ static int codeEqualityTerm(
} }
assert( pX->op==TK_IN ); assert( pX->op==TK_IN );
iReg = iTarget; iReg = iTarget;
eType = sqlite3FindInIndex(pParse, pX, 0); eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0);
if( eType==IN_INDEX_INDEX_DESC ){ if( eType==IN_INDEX_INDEX_DESC ){
testcase( bRev ); testcase( bRev );
bRev = !bRev; bRev = !bRev;
@ -4376,7 +4376,7 @@ static int whereLoopAddBtreeIndex(
}else if( eOp & (WO_EQ) ){ }else if( eOp & (WO_EQ) ){
pNew->wsFlags |= WHERE_COLUMN_EQ; pNew->wsFlags |= WHERE_COLUMN_EQ;
if( iCol<0 || (nInMul==0 && pNew->u.btree.nEq==pProbe->nKeyCol-1) ){ 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; pNew->wsFlags |= WHERE_UNQ_WANTED;
}else{ }else{
pNew->wsFlags |= WHERE_ONEROW; pNew->wsFlags |= WHERE_ONEROW;
@ -5231,7 +5231,7 @@ static i8 wherePathSatisfiesOrderBy(
nColumn = pIndex->nColumn; nColumn = pIndex->nColumn;
assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) ); assert( nColumn==nKeyCol+1 || !HasRowid(pIndex->pTable) );
assert( pIndex->aiColumn[nColumn-1]==(-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 /* 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){ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
assert( pLoop->aLTermSpace==pLoop->aLTerm ); assert( pLoop->aLTermSpace==pLoop->aLTerm );
assert( ArraySize(pLoop->aLTermSpace)==4 ); assert( ArraySize(pLoop->aLTermSpace)==4 );
if( pIdx->onError==OE_None if( !IsUniqueIndex(pIdx)
|| pIdx->pPartIdxWhere!=0 || pIdx->pPartIdxWhere!=0
|| pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace) || pIdx->nKeyCol>ArraySize(pLoop->aLTermSpace)
) continue; ) continue;

View File

@ -231,11 +231,11 @@ do_execsql_test in4-3.44 {
SELECT * FROM t3 WHERE x IN (10); SELECT * FROM t3 WHERE x IN (10);
} {~/OpenEphemeral/} } {~/OpenEphemeral/}
do_execsql_test in4-3.45 { 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} } {1 1 1}
do_execsql_test in4-3.46 { do_execsql_test in4-3.46 {
EXPLAIN EXPLAIN
SELECT * FROM t3 WHERE x NOT IN (10,11); SELECT * FROM t3 WHERE x NOT IN (10,11,99999);
} {/OpenEphemeral/} } {/OpenEphemeral/}
do_execsql_test in4-3.47 { do_execsql_test in4-3.47 {
SELECT * FROM t3 WHERE x NOT IN (10); SELECT * FROM t3 WHERE x NOT IN (10);

View File

@ -68,6 +68,12 @@ proc multiplex_delete {name} {
} }
db close 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 test.db
multiplex_delete test2.db multiplex_delete test2.db
@ -188,12 +194,16 @@ do_test multiplex-2.3.1 {
} {} } {}
unset -nocomplain ::log
do_test multiplex-2.4.1 { do_test multiplex-2.4.1 {
sqlite3_multiplex_shutdown sqlite3_multiplex_shutdown
} {SQLITE_MISUSE} } {SQLITE_MISUSE}
do_test multiplex-2.4.2 { do_test multiplex-2.4.2 {
execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) } 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.4 { file size [multiplex_name test.x 0] } {7168}
do_test multiplex-2.4.5 { do_test multiplex-2.4.5 {
db close db close
@ -583,5 +593,9 @@ do_test multiplex-6.99 {
} }
catch { db close }
catch { sqlite3_multiplex_shutdown } catch { sqlite3_multiplex_shutdown }
sqlite3_shutdown
test_sqlite3_log
sqlite3_initialize
finish_test finish_test

View File

@ -431,7 +431,32 @@ Page 6 is never used} {row 1 missing from index i2}}
db eval {PRAGMA integrity_check} db eval {PRAGMA integrity_check}
} {ok} } {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. # Test modifying the cache_size of an attached database.
ifcapable pager_pragmas&&attach { ifcapable pager_pragmas&&attach {

View File

@ -726,4 +726,51 @@ do_test table-15.2 {
execsql {COMMIT} 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 finish_test

View File

@ -869,6 +869,7 @@ proc speed_trial_summary {name} {
# #
proc finish_test {} { proc finish_test {} {
catch {db close} catch {db close}
catch {db1 close}
catch {db2 close} catch {db2 close}
catch {db3 close} catch {db3 close}
if {0==[info exists ::SLAVE]} { finalize_testing } if {0==[info exists ::SLAVE]} { finalize_testing }

View File

@ -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.323 {SELECT 'c' NOT IN t8} 0
do_execsql_test tkt-80e031a00f.324 {SELECT 'c' IN t8n} 1 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.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: # Row 4:
do_execsql_test tkt-80e031a00f.400 {SELECT 1 IN (2,3,4,null)} {{}} do_execsql_test tkt-80e031a00f.400 {SELECT 1 IN (2,3,4,null)} {{}}