Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 95b54f8816 | |||
| a52cbdb416 | |||
| e5c544e0ab | |||
| c5185cd845 | |||
| 39a3088dc4 | |||
| aaa21b41e8 | |||
| 3612639a6f | |||
| 7c3280649a | |||
| 35b85b4855 | |||
| a6e3a8c9d5 | |||
| 5c7976fe86 | |||
| c913126272 | |||
| ba47ba76a5 | |||
| 1247aa4e4a | |||
| 8af9ad951d | |||
| b373591c5e | |||
| 60830e3c53 | |||
| 53a6eb3f3c | |||
| 1b27b8c0a0 | |||
| 5574e3f456 | |||
| d227a291b2 | |||
| fa46bfbbc5 | |||
| c47548057d | |||
| 5f61229504 | |||
| 826af37865 | |||
| c0740cebeb | |||
| 04d0bcd533 | |||
| 725de29a2d | |||
| e0e261a473 | |||
| aceb31b120 | |||
| 642364a48b | |||
| dddf6978d2 | |||
| a198f2b55d | |||
| ed71a839fd | |||
| 81cf13ec7b | |||
| a5750cfe01 | |||
| 21a919f630 | |||
| 0fd613542c | |||
| b22f7c831f | |||
| 0211d8bca4 | |||
| 4bbcf10617 | |||
| e31ae90100 | |||
| 3350ce95f7 |
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.62 for sqlite 3.8.3.
|
||||
# Generated by GNU Autoconf 2.62 for sqlite 3.8.4.
|
||||
#
|
||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
|
||||
@@ -743,8 +743,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
|
||||
# Identity of this package.
|
||||
PACKAGE_NAME='sqlite'
|
||||
PACKAGE_TARNAME='sqlite'
|
||||
PACKAGE_VERSION='3.8.3'
|
||||
PACKAGE_STRING='sqlite 3.8.3'
|
||||
PACKAGE_VERSION='3.8.4'
|
||||
PACKAGE_STRING='sqlite 3.8.4'
|
||||
PACKAGE_BUGREPORT=''
|
||||
|
||||
# Factoring default headers for most tests.
|
||||
@@ -1483,7 +1483,7 @@ if test "$ac_init_help" = "long"; then
|
||||
# Omit some internal or obsolete options to make the list less imposing.
|
||||
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||
cat <<_ACEOF
|
||||
\`configure' configures sqlite 3.8.3 to adapt to many kinds of systems.
|
||||
\`configure' configures sqlite 3.8.4 to adapt to many kinds of systems.
|
||||
|
||||
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -1548,7 +1548,7 @@ fi
|
||||
|
||||
if test -n "$ac_init_help"; then
|
||||
case $ac_init_help in
|
||||
short | recursive ) echo "Configuration of sqlite 3.8.3:";;
|
||||
short | recursive ) echo "Configuration of sqlite 3.8.4:";;
|
||||
esac
|
||||
cat <<\_ACEOF
|
||||
|
||||
@@ -1664,7 +1664,7 @@ fi
|
||||
test -n "$ac_init_help" && exit $ac_status
|
||||
if $ac_init_version; then
|
||||
cat <<\_ACEOF
|
||||
sqlite configure 3.8.3
|
||||
sqlite configure 3.8.4
|
||||
generated by GNU Autoconf 2.62
|
||||
|
||||
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
|
||||
@@ -1678,7 +1678,7 @@ cat >config.log <<_ACEOF
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by sqlite $as_me 3.8.3, which was
|
||||
It was created by sqlite $as_me 3.8.4, which was
|
||||
generated by GNU Autoconf 2.62. Invocation command line was
|
||||
|
||||
$ $0 $@
|
||||
@@ -14021,7 +14021,7 @@ exec 6>&1
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling.
|
||||
ac_log="
|
||||
This file was extended by sqlite $as_me 3.8.3, which was
|
||||
This file was extended by sqlite $as_me 3.8.4, which was
|
||||
generated by GNU Autoconf 2.62. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -14074,7 +14074,7 @@ Report bugs to <bug-autoconf@gnu.org>."
|
||||
_ACEOF
|
||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||
ac_cs_version="\\
|
||||
sqlite config.status 3.8.3
|
||||
sqlite config.status 3.8.4
|
||||
configured by $0, generated by GNU Autoconf 2.62,
|
||||
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
|
||||
|
||||
|
||||
+2
-4
@@ -1933,7 +1933,6 @@ static int spellfix1Init(
|
||||
#define SPELLFIX_COL_COMMAND 11
|
||||
}
|
||||
if( rc==SQLITE_OK && isCreate ){
|
||||
sqlite3_uint64 r;
|
||||
spellfix1DbExec(&rc, db,
|
||||
"CREATE TABLE IF NOT EXISTS \"%w\".\"%w_vocab\"(\n"
|
||||
" id INTEGER PRIMARY KEY,\n"
|
||||
@@ -1945,11 +1944,10 @@ static int spellfix1Init(
|
||||
");\n",
|
||||
zDbName, zTableName
|
||||
);
|
||||
sqlite3_randomness(sizeof(r), &r);
|
||||
spellfix1DbExec(&rc, db,
|
||||
"CREATE INDEX IF NOT EXISTS \"%w\".\"%w_index_%llx\" "
|
||||
"CREATE INDEX IF NOT EXISTS \"%w\".\"%w_vocab_index_langid_k2\" "
|
||||
"ON \"%w_vocab\"(langid,k2);",
|
||||
zDbName, zModule, r, zTableName
|
||||
zDbName, zModule, zTableName
|
||||
);
|
||||
}
|
||||
for(i=3; rc==SQLITE_OK && i<argc; i++){
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
C Change\smore\sOP_OpenEphemeral\soperations\sto\sOP_OpenHash.
|
||||
D 2014-02-06T14:59:47.807
|
||||
C Various\sfixes\sand\stest\scase\supdates\sso\sthat\sveryquick.test\spasses\sagain.
|
||||
D 2014-02-12T15:05:05.674
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
F Makefile.msc 6ff3ff2eef45c7dd309a8626ff7947b20bd387e7
|
||||
F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315
|
||||
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
|
||||
F VERSION 8ed548d87d0a27fd7d7620476f9e25f9fa742d73
|
||||
F VERSION 0dc30ad5cf90736d5fd9e540c9f05c542658abe7
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F addopcodes.awk 9eb448a552d5c0185cf62c463f9c173cedae3811
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
@@ -38,7 +38,7 @@ F autoconf/tea/win/rules.vc c511f222b80064096b705dbeb97060ee1d6b6d63
|
||||
F config.guess 226d9a188c6196f3033ffc651cbc9dcee1a42977
|
||||
F config.h.in 0921066a13130082764ab4ab6456f7b5bebe56de
|
||||
F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
|
||||
F configure 1673bc402f8fc95015f72c279adc5a9a668ee237 x
|
||||
F configure e12e1a4f031354f9af735bcb377941a72dc2cca5 x
|
||||
F configure.ac 4cf9f60785143fa141b10962ccc885d973792e9a
|
||||
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
|
||||
F doc/lemon.html 334dbf6621b8fb8790297ec1abf3cfa4621709d1
|
||||
@@ -114,7 +114,7 @@ F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
|
||||
F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63
|
||||
F ext/misc/regexp.c af92cdaa5058fcec1451e49becc7ba44dba023dc
|
||||
F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a
|
||||
F ext/misc/spellfix.c adfc569fafef7a1eb8f21528e5277686b358c3ce
|
||||
F ext/misc/spellfix.c 3548c433f473c2054e080b6382771636fcaa2c4c
|
||||
F ext/misc/totype.c 4a167594e791abeed95e0a8db028822b5e8fe512
|
||||
F ext/misc/vfslog.c fe40fab5c077a40477f7e5eba994309ecac6cc95
|
||||
F ext/misc/vtshim.c babb0dc2bf116029e3e7c9a618b8a1377045303e
|
||||
@@ -159,23 +159,23 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca
|
||||
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 3d8b83c91651f53472ca17599dae3457b8b89494
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c 2af0330bb1b601af7a7789bf7229675fd772a083
|
||||
F src/alter.c d5348d0f86a5fc8fb3987727402f023953c021cf
|
||||
F src/analyze.c 581d5c18ce89c6f45d4dca65914d0de5b4dad41f
|
||||
F src/attach.c 3801129015ef59d76bf23c95ef9b0069d18a0c52
|
||||
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c a729e63cf5cd1829507cb7b8e89f99b95141bb53
|
||||
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
|
||||
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c ae408b77caf025df8c1baab52aad8a5a393bed35
|
||||
F src/btree.h f1c65e0511d7a228fd1a7c7463ef842525364348
|
||||
F src/btree.c 7b2c3cd16deedff7f4904f2e871e7b77328b9872
|
||||
F src/btree.h a61ddebc78c66795a2b93181321a116746302cc9
|
||||
F src/btreeInt.h f038e818bfadf75afbd09819ed93c26a333d39e0
|
||||
F src/build.c 7e6c275ab1731510d6f793d0f88373ab3e858e69
|
||||
F src/build.c 13b9d82181d95af7b00ec8a8e1304bac096432d4
|
||||
F src/callback.c 174e3c8656bc29f91d710ab61550d16eea34be98
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c 77779efbe78dd678d84bfb4fc2e87b6b6ad8dccd
|
||||
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
|
||||
F src/delete.c 3987ac3e32f6a447b1f3ca0268d67bdaf0a8b97f
|
||||
F src/expr.c fa9cd9b4bdc8989efce99d49c7e46484e17f41f4
|
||||
F src/delete.c 6765a421f08adbedc5d52d21760ec6dbe5123fd3
|
||||
F src/expr.c 9bea427f95665c1aa8fdc87b7678546eef50c296
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 2ab0f5384b70594468ef3ac5c7ed8ca24bfd17d5
|
||||
F src/func.c f4499b39d66b71825514334ce67b32ff14bd19f5
|
||||
@@ -183,7 +183,7 @@ F src/global.c 1d7bb7ea8254ae6a68ed9bfaf65fcb3d1690b486
|
||||
F src/hash.c d139319967164f139c8d1bb8a11b14db9c4ba3cd
|
||||
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
F src/insert.c c6b4ba486e62d0b600632fdfce4bca76213158cb
|
||||
F src/insert.c 89526b031cf8f0e2306f02099a73cee56110c580
|
||||
F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
|
||||
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
||||
@@ -205,11 +205,11 @@ F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
|
||||
F src/os.c 1b147e4cf7cc39e618115c14a086aed44bc91ace
|
||||
F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f
|
||||
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
|
||||
F src/os_unix.c f3ed0e406cbf9c820565b2118232d0796346130f
|
||||
F src/os_unix.c c53e2683d8cc23d08f28dbecf0e3c2bcf1d1acca
|
||||
F src/os_win.c d4284f003445054a26689f1264b1b9bf7261bd1b
|
||||
F src/pager.c efa923693e958696eee69b205a20bfbc402c8480
|
||||
F src/pager.c 0ffa313a30ed6d061d9c6601b7b175cc50a1cab7
|
||||
F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428
|
||||
F src/parse.y bd51bc17cbfe7549adb4ca3747b1c3d384645065
|
||||
F src/parse.y cce844ccb80b5f969b04c25100c8d94338488efb
|
||||
F src/pcache.c d8eafac28290d4bb80332005435db44991d07fc2
|
||||
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
|
||||
F src/pcache1.c 102e6f5a2fbc646154463eb856d1fd716867b64c
|
||||
@@ -219,21 +219,21 @@ F src/printf.c 85d07756e45d7496d19439dcae3e6e9e0090f269
|
||||
F src/random.c d10c1f85b6709ca97278428fd5db5bbb9c74eece
|
||||
F src/resolve.c 7eda9097b29fcf3d2b42fdc17d1de672134e09b6
|
||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||
F src/select.c d1acf45637f70d71a76cb8312507550e3aee6caa
|
||||
F src/shell.c 24722d24d4ea8ca93db35e44db7308de786767ca
|
||||
F src/select.c 50961f0d0ab8f2d45ff29ec5f91d8db221330ca7
|
||||
F src/shell.c 3dd86bf73ccd079f0e32ef5069600586085e8239
|
||||
F src/sqlite.h.in eed7f7d66a60daaa7b4a597dcd9bad87aad9611b
|
||||
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||
F src/sqliteInt.h 29b97acb02309ad07de107a81c381512066fc2e4
|
||||
F src/sqliteInt.h 5b1f4e30c8332270e4c14254ef1fbcbd92a4a4c7
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c 21ca0043d7c48cde5dabed5c1116eee1be692f62
|
||||
F src/tclsqlite.c 649d373f2a3cfbefe8e935a8dec83686616f9a85
|
||||
F src/test1.c 2401eee14a4309a7cfe2aeb2f30ad517a1d9c299
|
||||
F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35
|
||||
F src/test2.c 0f8bd858c127fd5236dd965d534622422fbe0b2f
|
||||
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
|
||||
F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
|
||||
F src/test5.c a6d1ac55ac054d0b2b8f37b5e655b6c92645a013
|
||||
F src/test5.c 41e6e732f14a54c7b47f753e364700760f6521b0
|
||||
F src/test6.c 41cacf3b0dd180823919bf9e1fbab287c9266723
|
||||
F src/test7.c 72b732baa5642f795655ba1126ea032af46ecfd2
|
||||
F src/test8.c 54ccd7b1df5062f0ecbf50a8f7b618f8b1f13b20
|
||||
@@ -275,25 +275,25 @@ F src/test_vfs.c e72f555ef7a59080f898fcf1a233deb9eb704ea9
|
||||
F src/test_vfstrace.c 3a0ab304682fecbceb689e7d9b904211fde11d78
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 6da2de6e12218ccb0aea5184b56727d011f4bee7
|
||||
F src/trigger.c 5c1c0b899ac0ce284763dcb8fdbaa38ecf15ef98
|
||||
F src/update.c 3d2bdfe24d78303cf7fd3017aaa2d848d47a1020
|
||||
F src/trigger.c a417d386e214f0abd2e0f756b834b4d9f4d3368a
|
||||
F src/update.c a7df6fffce6bfedc578fda6136dd33e34a63f8ee
|
||||
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
|
||||
F src/util.c 15ac2627f548f5481d0d7e6c4eb67be673027695
|
||||
F src/util.c c46c90459ef9bdc0c6c73803cf4c55425b4771cf
|
||||
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
||||
F src/vdbe.c 2e46c464e910cf0f11acf6690e8f72d7239a5f63
|
||||
F src/vdbe.c e5c87476d717aebef5dafceab11417ebf2730554
|
||||
F src/vdbe.h e6c4c610fcabad4fa80ebb1efc6822a9367e2b26
|
||||
F src/vdbeInt.h 42db251e9f863401ff847b90d5fe1614c89a6a56
|
||||
F src/vdbeapi.c ce4e68ea4842cc6081046f533d088dcf01d247ad
|
||||
F src/vdbeaux.c a3327afa8cfcc5bb3d38f2b2a599bac5fb63c6be
|
||||
F src/vdbeblob.c bc40f98f256f0b34116d6a44b114da4a81a15d33
|
||||
F src/vdbemem.c 23cdc14ed43e0aafa57bd72b9bf3d5b1641afa91
|
||||
F src/vdbeInt.h 5286af9067cabdb8ba57b87c0c988a931be6c6c8
|
||||
F src/vdbeapi.c 5bc41aaea448a7fc250902c418f1795859be3820
|
||||
F src/vdbeaux.c dac6e571262a322b2f889752a8dd36549bdacd2b
|
||||
F src/vdbeblob.c 9542e116c1db5ed813977581d506c176e117c0ec
|
||||
F src/vdbemem.c 06603e8e9d2f3247b68c6bbe4bd37fb6721b5bda
|
||||
F src/vdbesort.c 9d83601f9d6243fe70dd0169a2820c5ddfd48147
|
||||
F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
|
||||
F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
|
||||
F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45
|
||||
F src/where.c 087307272e374c35c7eb1eb722f0ab7db09317f2
|
||||
F src/where.c b0436385f40e86f0f4cc60355cd018bde2c89d4b
|
||||
F src/whereInt.h 921f935af8b684ffb49705610bda7284db1db138
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
@@ -336,9 +336,9 @@ F test/autovacuum.test 941892505d2c0f410a0cb5970dfa1c7c4e5f6e74
|
||||
F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4
|
||||
F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85
|
||||
F test/backcompat.test 5f8ad58b3eaebc78cd2c66c65476a42e6f32b2ad
|
||||
F test/backup.test c9cdd23a495864b9edf75a9fa66f5cb7e10fcf62
|
||||
F test/backup.test 3b072335eadafa32ab940fceed5852fb48c30655
|
||||
F test/backup2.test 34986ef926ea522911a51dfdb2f8e99b7b75ebcf
|
||||
F test/backup4.test 2a2e4a64388090b152de753fd9e123f28f6a3bd4
|
||||
F test/backup4.test 139a465f76d43259123d6e09281d080fccc59f8a
|
||||
F test/backup_ioerr.test 4c3c7147cee85b024ecf6e150e090c32fdbb5135
|
||||
F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450
|
||||
F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f
|
||||
@@ -368,7 +368,7 @@ F test/capi3.test 6cdd49656bd62a296924f4d2fcfd05cd2a298369
|
||||
F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
|
||||
F test/capi3c.test a21869e4d50d5dbb7e566e328fc0bc7c2efa6a32
|
||||
F test/capi3d.test 6d0fc0a86d73f42dd19a7d8b7761ab9bc02277d0
|
||||
F test/capi3e.test ad90088b18b0367125ff2d4b5400153fd2f99aab
|
||||
F test/capi3e.test 1ecb23b79a6f2a50ba336142e795d6e677d1d2d4
|
||||
F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3
|
||||
F test/check.test 5831ddb6f2c687782eaf2e1a07b6e17f24c4f763
|
||||
F test/close.test 340bd24cc58b16c6bc01967402755027c37eb815
|
||||
@@ -432,7 +432,7 @@ F test/descidx1.test 6d03b44c8538fe0eb4924e19fba10cdd8f3c9240
|
||||
F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
|
||||
F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2
|
||||
F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
|
||||
F test/distinct.test b9f34f3827a67baf5b5bcb1cdf5185963d629d49
|
||||
F test/distinct.test c7b194ef95dbddb32d77acbbab2e023c6eed0cb2
|
||||
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
|
||||
F test/e_createtable.test ee95d48664503d40f6cc9ef4a7d03216188e2ada
|
||||
F test/e_delete.test d5186e2f5478b659f16a2c8b66c09892823e542a
|
||||
@@ -447,7 +447,7 @@ F test/e_resolve.test dcce9308fb13b934ce29591105d031d3e14fbba6
|
||||
F test/e_select.test 52692ff3849541e828ad4661fe3773a9b8711763
|
||||
F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f
|
||||
F test/e_update.test 312cb8f5ccfe41515a6bb092f8ea562a9bd54d52
|
||||
F test/e_uri.test a2c92d80093a7efdcfbb11093651cbea87097b6b
|
||||
F test/e_uri.test bfa56d624d693a81bb29ac2a9a999e35c2c8d9bf
|
||||
F test/e_vacuum.test 5bfbdc21b65c0abf24398d0ba31dc88d93ca77a9
|
||||
F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea
|
||||
F test/enc2.test 83437a79ba1545a55fb549309175c683fb334473
|
||||
@@ -457,7 +457,7 @@ F test/eqp.test 57c6c604c2807fb5531731c5323133453c24afac
|
||||
F test/errmsg.test f31592a594b44ee121371d25ddd5d63497bb3401
|
||||
F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3
|
||||
F test/exclusive.test c7ebbc756eacf544c108b15eed64d7d4e5f86b75
|
||||
F test/exclusive2.test 32798111aae78a5deec980eee383213f189df308
|
||||
F test/exclusive2.test a3bfa5d21268d2d1f4dd1c094ad9cd583914ca73
|
||||
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
|
||||
F test/exists.test 8f7b27b61c2fbe5822f0a1f899c715d14e416e30
|
||||
F test/expr.test 67c9fd6f8f829e239dc8b0f4a08a73c08b09196d
|
||||
@@ -593,16 +593,16 @@ F test/hook.test 162d7cef7a2d2b04839fe14402934e6a1b79442f
|
||||
F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
|
||||
F test/in.test 047c4671328e9032ab95666a67021adbbd36e98e
|
||||
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
||||
F test/in3.test dbf41c0c073c10a8c0fee280cba3e9dddbd4a9c6
|
||||
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
|
||||
F test/in4.test 64f3cc1acde1b9161ccdd8e5bde3daefdb5b2617
|
||||
F test/in5.test 9d8c15bfc9a06da5b354d4d4ecfea9f928769641
|
||||
F test/in5.test 99f9a40af01711b06d2d614ecfe96129f334fba3
|
||||
F test/incrblob.test e81846d214f3637622620fbde7cd526781cfe328
|
||||
F test/incrblob2.test bf4d549aa4a466d7fbe3e3a3693d3861263d5600
|
||||
F test/incrblob3.test d8d036fde015d4a159cd3cbae9d29003b37227a4
|
||||
F test/incrblob4.test f26502a5697893e5acea268c910f16478c2f0fab
|
||||
F test/incrblob_err.test d2562d2771ebffd4b3af89ef64c140dd44371597
|
||||
F test/incrblobfault.test 280474078f6da9e732cd2a215d3d854969014b6e
|
||||
F test/incrvacuum.test d2a6ddf5e429720b5fe502766af747915ccf6c32
|
||||
F test/incrvacuum.test 0e0f03c3c4956de4f3b1d47fe03ea762bc9aaa83
|
||||
F test/incrvacuum2.test 379eeb8740b0ef60c372c439ad4cbea20b34bb9b
|
||||
F test/incrvacuum3.test 75256fb1377e7c39ef2de62bfc42bbff67be295a
|
||||
F test/incrvacuum_ioerr.test 6ae2f783424e47a0033304808fe27789cf93e635
|
||||
@@ -625,7 +625,7 @@ F test/instr.test 737bbf80685232033f3abedc6ae92f75860b5dd2
|
||||
F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4
|
||||
F test/interrupt.test dfe9a67a94b0b2d8f70545ba1a6cca10780d71cc
|
||||
F test/intpkey.test 7506090fc08e028712a8bf47e5f54111947e3844
|
||||
F test/io.test 3a7abcef18727cc0f2399e04b0e8903eccae50f8
|
||||
F test/io.test 148556665d0f5181f510d072f434855bd40be1be
|
||||
F test/ioerr.test 2a24bd6ed5a8b062e64bfe1f6cf94fb25e92210d
|
||||
F test/ioerr2.test 9d71166f8466eda510f1af6137bdabaa82b5408d
|
||||
F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd
|
||||
@@ -725,7 +725,7 @@ F test/orderby3.test 8619d06a3debdcd80a27c0fdea5c40b468854b99
|
||||
F test/orderby4.test 4d39bfbaaa3ae64d026ca2ff166353d2edca4ba4
|
||||
F test/orderby5.test 0eb82d5890c3f3d0563966560cfdc984ea69e30c
|
||||
F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3
|
||||
F test/pager1.test 1acbdb14c5952a72dd43129cabdbf69aaa3ed1fa
|
||||
F test/pager1.test c609ea28a3692d8983e945a253ebae25ad385977
|
||||
F test/pager2.test 67b8f40ae98112bcdba1f2b2d03ea83266418c71
|
||||
F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f
|
||||
F test/pager4.test a122e9e6925d5b23b31e3dfef8c6a44bbf19590e
|
||||
@@ -737,7 +737,7 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
|
||||
F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d
|
||||
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
|
||||
F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54
|
||||
F test/permutations.test 40add071ba71aefe1c04f5845308cf46f7de8d04
|
||||
F test/permutations.test deb0e98ed7e2849fd896a39e3443b342b7feda2a
|
||||
F test/pragma.test e882183ecd21d064cec5c7aaea174fbd36293429
|
||||
F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13
|
||||
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
|
||||
@@ -786,7 +786,7 @@ F test/select6.test e76bd10a56988f15726c097a5d5a7966fe82d3b2
|
||||
F test/select7.test 7fd2ef598cfabb6b9ff6ac13973b91d0527df49d
|
||||
F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d
|
||||
F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95
|
||||
F test/selectA.test 99cf21df033b93033ea4f34aba14a500f48f04fe
|
||||
F test/selectA.test 77adaffe9704cb80e301ebaeff4b107b58d435c5
|
||||
F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25
|
||||
F test/selectC.test 871fb55d884d3de5943c4057ebd22c2459e71977
|
||||
F test/selectD.test b0f02a04ef7737decb24e08be2c39b9664b43394
|
||||
@@ -803,7 +803,7 @@ F test/shared9.test 5f2a8f79b4d6c7d107a01ffa1ed05ae7e6333e21
|
||||
F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5
|
||||
F test/shared_err.test 0079c05c97d88cfa03989b7c20a8b266983087aa
|
||||
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
|
||||
F test/shell1.test e7c0b9ebda25d5e78f0a3ea0dc4e31bb6d8098c0
|
||||
F test/shell1.test f2a1d471e5cd2b42f7a65b166dc1ace2b8d11583
|
||||
F test/shell2.test c57da3a381c099b02c813ba156298d5c2f5c93a3
|
||||
F test/shell3.test 5e8545ec72c4413a0e8d4c6be56496e3c257ca29
|
||||
F test/shell4.test aa4eef8118b412d1a01477a53426ece169ea86a9
|
||||
@@ -824,7 +824,7 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523
|
||||
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
|
||||
F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa
|
||||
F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b
|
||||
F test/speedtest1.c 7130d2cb6db45baa553a4ab2f715116c71c2d9f4
|
||||
F test/speedtest1.c 1603da7b4897716f9df15bd71b0310f56ec3181e
|
||||
F test/spellfix.test 61309f5efbec53603b3f86457d34a504f80abafe
|
||||
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
|
||||
F test/stat.test 76fd746b85459e812a0193410fb599f0531f22de
|
||||
@@ -835,7 +835,7 @@ F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
|
||||
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
|
||||
F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2
|
||||
F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85
|
||||
F test/syscall.test a653783d985108c4912cc64d341ffbbb55ad2806
|
||||
F test/syscall.test 8e96912cf2e41b572d00c537ac71b9f5bb72477e
|
||||
F test/sysfault.test fa776e60bf46bdd3ae69f0b73e46ee3977a58ae6
|
||||
F test/table.test 580d23530187026d4502fae74a490f0408cf2cc7
|
||||
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
|
||||
@@ -844,7 +844,7 @@ F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43
|
||||
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
|
||||
F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1
|
||||
F test/tester.tcl 9bd04481b8b0ef1f2049ad01f28e175ee9a14f7b
|
||||
F test/tester.tcl cc5fc5ecfbbd90f4c100d3aaea65eb5d3b3de988
|
||||
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@@ -869,6 +869,7 @@ F test/tkt-3998683a16.test 6d1d04d551ed1704eb3396ca87bb9ccc8c5c1eb7
|
||||
F test/tkt-3a77c9714e.test b08bca26de1140bdf004a37716582a43d7bd8be8
|
||||
F test/tkt-3fe897352e.test 27e26eb0f1811aeba4d65aba43a4c52e99da5e70
|
||||
F test/tkt-4a03edc4c8.test 91c0e135888cdc3d4eea82406a44b05c8c1648d0
|
||||
F test/tkt-4c86b126f2.test cbcc611becd0396890169ab23102dd70048bbc9a
|
||||
F test/tkt-4dd95f6943.test 3d0ce415d2ee15d3d564121960016b9c7be79407
|
||||
F test/tkt-54844eea3f.test a12b851128f46a695e4e378cca67409b9b8f5894
|
||||
F test/tkt-5d863f876e.test c9f36ca503fa154a3655f92a69d2c30da1747bfa
|
||||
@@ -987,7 +988,7 @@ F test/tkt3929.test cdf67acf5aa936ec4ffead81db87f8a71fe40e59
|
||||
F test/tkt3935.test e15261fedb9e30a4305a311da614a5d8e693c767
|
||||
F test/tkt3992.test f3e7d548ac26f763b47bc0f750da3d03c81071da
|
||||
F test/tkt3997.test a335fa41ca3985660a139df7b734a26ef53284bd
|
||||
F test/tkt4018.test 7c2c9ba4df489c676a0a7a0e809a1fb9b2185bd1
|
||||
F test/tkt4018.test 04115ae33ee39988a076bd78decef7cec820ebe0
|
||||
F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7
|
||||
F test/tpch01.test 8f4ac52f62f3e9f6bce0889105aecdf0275e331b
|
||||
F test/trace.test 4b36a41a3e9c7842151af6da5998f5080cdad9e5
|
||||
@@ -1018,7 +1019,7 @@ F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264
|
||||
F test/unixexcl.test a9870e46cc6f8390a494513d4f2bf55b5a8b3e46
|
||||
F test/unordered.test ef85ac8f2f3c93ed2b9e811b684de73175fc464c
|
||||
F test/update.test 1b6c488a8f993d090b7ee9ad0e234faa161b3aeb
|
||||
F test/uri.test 63e03df051620a18f794b4f4adcdefb3c23b6751
|
||||
F test/uri.test 6aad91f02090012a03d0545a30c7cea02c70947a
|
||||
F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
|
||||
F test/vacuum.test ce91c39f7f91a4273bf620efad21086b5aa6ef1d
|
||||
F test/vacuum2.test af432e6e3bfc0ea20a80cb86a03c7d9876d38324
|
||||
@@ -1048,7 +1049,7 @@ F test/vtab_shared.test 6acafaae7126c9f49be72c2f57eb8bef3024f1cb
|
||||
F test/wal.test 40073e54359d43354925b2b700b7eebd5e207285
|
||||
F test/wal2.test a8e3963abf6b232cf0b852b09b53665ef34007af
|
||||
F test/wal3.test b22eb662bcbc148c5f6d956eaf94b047f7afe9c0
|
||||
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
|
||||
F test/wal4.test fc104ae9670221a5326c611789c205889aebe9fa
|
||||
F test/wal5.test 8f888b50f66b78821e61ed0e233ded5de378224b
|
||||
F test/wal6.test 527581f5527bf9c24394991e2be83000aace5f9e
|
||||
F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd
|
||||
@@ -1077,7 +1078,7 @@ F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2
|
||||
F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2
|
||||
F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b
|
||||
F test/where7.test 5a4b0abc207d71da4deecd734ad8579e8dd40aa8
|
||||
F test/where8.test d2b4fd6d7b7c5d44f590182a05033d78a14c00a1
|
||||
F test/where8.test 84033c4da466d90fe7ef0152661ff67fd218105f
|
||||
F test/where8m.test da346596e19d54f0aba35ebade032a7c47d79739
|
||||
F test/where9.test 4f3eab951353a3ae164befc521c777dfa903e46c
|
||||
F test/whereA.test 4d253178d135ec46d1671e440cd8f2b916aa6e6b
|
||||
@@ -1092,7 +1093,7 @@ F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
|
||||
F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
|
||||
F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
|
||||
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
|
||||
F test/with1.test ce15d69d34a2576b0e47d78c244d1ba2a31679d1
|
||||
F test/with1.test 268081a6b14817a262ced4d0ee34d4d2a1dd2068
|
||||
F test/with2.test 2fe78fcd8deef2a0f9cfc49bfc755911d0b3fd64
|
||||
F test/withM.test e97f2a8c506ab3ea9eab94e6f6072f6cc924c991
|
||||
F test/without_rowid1.test aaa26da19d543cd8d3d2d0e686dfa255556c15c8
|
||||
@@ -1152,7 +1153,7 @@ F tool/vdbe-compress.tcl 0cf56e9263a152b84da86e75a5c0cdcdb7a47891
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
||||
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
||||
P 715fac7749a6b1523fe9f7de8263f0c4d1571d07
|
||||
R f507eae713e5b72113d4535fdf641347
|
||||
U drh
|
||||
Z 759564bb3627cf7a97644b4104ef33de
|
||||
P 4d7057c4942464b4302031a1ee9f195700c5e66d 0a8bcbbd4e11a60923736b2be9b1ce83ea2263fb
|
||||
R 4a7f56d4353f8f673e4fcc636c77fc4f
|
||||
U dan
|
||||
Z be45f6e8774a4940e329c99165e0e8a7
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
881164cf6e5c987ae0e40804267715d878135198
|
||||
f352ef57e39a9443b4bdf47fc2c9b01006fe3c10
|
||||
+1
-1
@@ -469,7 +469,7 @@ void sqlite3AlterRenameTable(
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Begin a transaction and code the VerifyCookie for database iDb.
|
||||
/* Begin a transaction for database iDb.
|
||||
** Then modify the schema cookie (since the ALTER TABLE modifies the
|
||||
** schema). Open a statement transaction if the table is a virtual
|
||||
** table.
|
||||
|
||||
+4
-7
@@ -1527,7 +1527,7 @@ static int btreeInitPage(MemPage *pPage){
|
||||
** Set up a raw page so that it looks like a database page holding
|
||||
** no entries.
|
||||
*/
|
||||
static void zeroPage(MemPage *pPage, u8 flags){
|
||||
static void zeroPage(MemPage *pPage, int flags){
|
||||
unsigned char *data = pPage->aData;
|
||||
BtShared *pBt = pPage->pBt;
|
||||
u8 hdr = pPage->hdrOffset;
|
||||
@@ -2585,7 +2585,6 @@ static int newDatabase(BtShared *pBt){
|
||||
MemPage *pP1;
|
||||
unsigned char *data;
|
||||
int rc;
|
||||
u8 flags;
|
||||
|
||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
||||
if( pBt->nPage>0 ){
|
||||
@@ -2608,9 +2607,7 @@ static int newDatabase(BtShared *pBt){
|
||||
data[22] = 32;
|
||||
data[23] = 32;
|
||||
memset(&data[24], 0, 100-24);
|
||||
flags = (pBt->openFlags&BTREE_SINGLE_INDEX) ? PTF_ZERODATA|PTF_LEAF
|
||||
: PTF_INTKEY|PTF_LEAFDATA|PTF_LEAF;
|
||||
zeroPage(pP1, flags);
|
||||
zeroPage(pP1, PTF_INTKEY|PTF_LEAF|PTF_LEAFDATA );
|
||||
pBt->btsFlags |= BTS_PAGESIZE_FIXED;
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
assert( pBt->autoVacuum==1 || pBt->autoVacuum==0 );
|
||||
@@ -6112,7 +6109,7 @@ static int balance_nonroot(
|
||||
u16 leafCorrection; /* 4 if pPage is a leaf. 0 if not */
|
||||
int leafData; /* True if pPage is a leaf of a LEAFDATA tree */
|
||||
int usableSpace; /* Bytes in pPage beyond the header */
|
||||
u8 pageFlags; /* Value of pPage->aData[0] */
|
||||
int pageFlags; /* Value of pPage->aData[0] */
|
||||
int subtotal; /* Subtotal of bytes in cells on one page */
|
||||
int iSpace1 = 0; /* First unused byte of aSpace1[] */
|
||||
int iOvflSpace = 0; /* First unused byte of aOvflSpace[] */
|
||||
@@ -7213,7 +7210,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
|
||||
MemPage *pRoot;
|
||||
Pgno pgnoRoot;
|
||||
int rc;
|
||||
u8 ptfFlags; /* Page-type flage for the root page of new table */
|
||||
int ptfFlags; /* Page-type flage for the root page of new table */
|
||||
|
||||
assert( sqlite3BtreeHoldsMutex(p) );
|
||||
assert( pBt->inTransaction==TRANS_WRITE );
|
||||
|
||||
+4
-5
@@ -56,11 +56,10 @@ int sqlite3BtreeOpen(
|
||||
** NOTE: These values must match the corresponding PAGER_ values in
|
||||
** pager.h.
|
||||
*/
|
||||
#define BTREE_OMIT_JOURNAL 0x01 /* Do not create or use a rollback journal */
|
||||
#define BTREE_MEMORY 0x02 /* This is an in-memory DB */
|
||||
#define BTREE_SINGLE 0x04 /* The file contains at most 1 b-tree */
|
||||
#define BTREE_UNORDERED 0x08 /* Use of a hash implementation is OK */
|
||||
#define BTREE_SINGLE_INDEX 0x10 /* File contains one index btree */
|
||||
#define BTREE_OMIT_JOURNAL 1 /* Do not create or use a rollback journal */
|
||||
#define BTREE_MEMORY 2 /* This is an in-memory DB */
|
||||
#define BTREE_SINGLE 4 /* The file contains at most 1 b-tree */
|
||||
#define BTREE_UNORDERED 8 /* Use of a hash implementation is OK */
|
||||
|
||||
int sqlite3BtreeClose(Btree*);
|
||||
int sqlite3BtreeSetCacheSize(Btree*,int);
|
||||
|
||||
+30
-63
@@ -149,20 +149,22 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
** transaction on each used database and to verify the schema cookie
|
||||
** on each used database.
|
||||
*/
|
||||
if( pParse->cookieGoto>0 ){
|
||||
if( db->mallocFailed==0 && (pParse->cookieMask || pParse->pConstExpr) ){
|
||||
yDbMask mask;
|
||||
int iDb, i, addr;
|
||||
sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
|
||||
int iDb, i;
|
||||
assert( sqlite3VdbeGetOp(v, 0)->opcode==OP_Init );
|
||||
sqlite3VdbeJumpHere(v, 0);
|
||||
for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
|
||||
if( (mask & pParse->cookieMask)==0 ) continue;
|
||||
sqlite3VdbeUsesBtree(v, iDb);
|
||||
sqlite3VdbeAddOp2(v,OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
|
||||
if( db->init.busy==0 ){
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
sqlite3VdbeAddOp3(v, OP_VerifyCookie,
|
||||
iDb, pParse->cookieValue[iDb],
|
||||
db->aDb[iDb].pSchema->iGeneration);
|
||||
}
|
||||
sqlite3VdbeAddOp4Int(v,
|
||||
OP_Transaction, /* Opcode */
|
||||
iDb, /* P1 */
|
||||
(mask & pParse->writeMask)!=0, /* P2 */
|
||||
pParse->cookieValue[iDb], /* P3 */
|
||||
db->aDb[iDb].pSchema->iGeneration /* P4 */
|
||||
);
|
||||
if( db->init.busy==0 ) sqlite3VdbeChangeP5(v, 1);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
for(i=0; i<pParse->nVtabLock; i++){
|
||||
@@ -183,17 +185,16 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
sqlite3AutoincrementBegin(pParse);
|
||||
|
||||
/* Code constant expressions that where factored out of inner loops */
|
||||
addr = pParse->cookieGoto;
|
||||
if( pParse->pConstExpr ){
|
||||
ExprList *pEL = pParse->pConstExpr;
|
||||
pParse->cookieGoto = 0;
|
||||
pParse->okConstFactor = 0;
|
||||
for(i=0; i<pEL->nExpr; i++){
|
||||
sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Finally, jump back to the beginning of the executable code. */
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,7 +217,6 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||
pParse->nSet = 0;
|
||||
pParse->nVar = 0;
|
||||
pParse->cookieMask = 0;
|
||||
pParse->cookieGoto = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3825,59 +3825,26 @@ int sqlite3OpenTempDatabase(Parse *pParse){
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate VDBE code that will verify the schema cookie and start
|
||||
** a read-transaction for all named database files.
|
||||
**
|
||||
** It is important that all schema cookies be verified and all
|
||||
** read transactions be started before anything else happens in
|
||||
** the VDBE program. But this routine can be called after much other
|
||||
** code has been generated. So here is what we do:
|
||||
**
|
||||
** The first time this routine is called, we code an OP_Goto that
|
||||
** will jump to a subroutine at the end of the program. Then we
|
||||
** record every database that needs its schema verified in the
|
||||
** pParse->cookieMask field. Later, after all other code has been
|
||||
** generated, the subroutine that does the cookie verifications and
|
||||
** starts the transactions will be coded and the OP_Goto P2 value
|
||||
** will be made to point to that subroutine. The generation of the
|
||||
** cookie verification subroutine code happens in sqlite3FinishCoding().
|
||||
**
|
||||
** If iDb<0 then code the OP_Goto only - don't set flag to verify the
|
||||
** schema on any databases. This can be used to position the OP_Goto
|
||||
** early in the code, before we know if any database tables will be used.
|
||||
** Record the fact that the schema cookie will need to be verified
|
||||
** for database iDb. The code to actually verify the schema cookie
|
||||
** will occur at the end of the top-level VDBE and will be generated
|
||||
** later, by sqlite3FinishCoding().
|
||||
*/
|
||||
void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
|
||||
Parse *pToplevel = sqlite3ParseToplevel(pParse);
|
||||
sqlite3 *db = pToplevel->db;
|
||||
yDbMask mask;
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
if( pToplevel!=pParse ){
|
||||
/* This branch is taken if a trigger is currently being coded. In this
|
||||
** case, set cookieGoto to a non-zero value to show that this function
|
||||
** has been called. This is used by the sqlite3ExprCodeConstants()
|
||||
** function. */
|
||||
pParse->cookieGoto = -1;
|
||||
}
|
||||
#endif
|
||||
if( pToplevel->cookieGoto==0 ){
|
||||
Vdbe *v = sqlite3GetVdbe(pToplevel);
|
||||
if( v==0 ) return; /* This only happens if there was a prior error */
|
||||
pToplevel->cookieGoto = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0)+1;
|
||||
}
|
||||
if( iDb>=0 ){
|
||||
sqlite3 *db = pToplevel->db;
|
||||
yDbMask mask;
|
||||
|
||||
assert( iDb<db->nDb );
|
||||
assert( db->aDb[iDb].pBt!=0 || iDb==1 );
|
||||
assert( iDb<SQLITE_MAX_ATTACHED+2 );
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
mask = ((yDbMask)1)<<iDb;
|
||||
if( (pToplevel->cookieMask & mask)==0 ){
|
||||
pToplevel->cookieMask |= mask;
|
||||
pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
|
||||
if( !OMIT_TEMPDB && iDb==1 ){
|
||||
sqlite3OpenTempDatabase(pToplevel);
|
||||
}
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
assert( db->aDb[iDb].pBt!=0 || iDb==1 );
|
||||
assert( iDb<SQLITE_MAX_ATTACHED+2 );
|
||||
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
|
||||
mask = ((yDbMask)1)<<iDb;
|
||||
if( (pToplevel->cookieMask & mask)==0 ){
|
||||
pToplevel->cookieMask |= mask;
|
||||
pToplevel->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie;
|
||||
if( !OMIT_TEMPDB && iDb==1 ){
|
||||
sqlite3OpenTempDatabase(pToplevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -383,9 +383,7 @@ void sqlite3DeleteFrom(
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
|
||||
}else{
|
||||
/* For a WITHOUT ROWID table, create an ephermeral table used to
|
||||
** hold all primary keys for rows to be deleted. Use OP_OpenEphemeral
|
||||
** rather than OP_OpenHash since for efficiency reasons it is good to
|
||||
** process the primary keys in order. */
|
||||
** hold all primary keys for rows to be deleted. */
|
||||
pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
assert( pPk!=0 );
|
||||
nPk = pPk->nKeyCol;
|
||||
|
||||
+213
-221
@@ -1060,7 +1060,6 @@ Select *sqlite3SelectDup(sqlite3 *db, Select *p, int flags){
|
||||
pNew->iLimit = 0;
|
||||
pNew->iOffset = 0;
|
||||
pNew->selFlags = p->selFlags & ~SF_UsesEphemeral;
|
||||
pNew->pRightmost = 0;
|
||||
pNew->addrOpenEphm[0] = -1;
|
||||
pNew->addrOpenEphm[1] = -1;
|
||||
pNew->addrOpenEphm[2] = -1;
|
||||
@@ -1490,177 +1489,6 @@ int sqlite3CodeOnce(Parse *pParse){
|
||||
return sqlite3VdbeAddOp1(v, OP_Once, pParse->nOnce++);
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code that constructs a transient table for the RHS of an IN
|
||||
** operator:
|
||||
**
|
||||
** x IN (4,5,11) -- IN operator with list on right-hand side
|
||||
** x IN (SELECT a FROM b) -- IN operator with subquery on the right
|
||||
**
|
||||
** The pExpr parameter is the IN expression.
|
||||
**
|
||||
** If parameter isRowid is non-zero, then expression pExpr is guaranteed
|
||||
** to be of the form "<rowid> IN (?, ?, ?)", where <rowid> is a reference
|
||||
** to some integer key column of a table B-Tree. In this case, use an
|
||||
** intkey B-Tree to store the set of IN(...) values instead of the usual
|
||||
** (slower) variable length keys B-Tree.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
static void sqlite3CreateInOperatorRhsTable(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Expr *pExpr, /* The IN, SELECT, or EXISTS operator */
|
||||
int isRowid, /* If true, LHS of IN operator is a rowid */
|
||||
int bOrdered /* If true, must use btree, not a hash */
|
||||
){
|
||||
int testAddr = -1; /* One-time test address */
|
||||
Vdbe *v = sqlite3GetVdbe(pParse); /* prepared stmt under construction */
|
||||
char affinity; /* Affinity of the LHS of the IN */
|
||||
int addr; /* Address of OP_Open.. instruction */
|
||||
Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */
|
||||
KeyInfo *pKeyInfo = 0; /* Key information */
|
||||
|
||||
assert( v!=0 );
|
||||
assert( pExpr->op==TK_IN );
|
||||
sqlite3ExprCachePush(pParse);
|
||||
|
||||
/* This code must be run in its entirety every time it is encountered
|
||||
** if any of the following is true:
|
||||
**
|
||||
** * The right-hand side is a correlated subquery
|
||||
** * We are inside a trigger
|
||||
**
|
||||
** If all of the above are false, then we can run this code just once
|
||||
** save the results, and reuse the same result on subsequent invocations.
|
||||
*/
|
||||
if( !ExprHasProperty(pExpr, EP_VarSelect) ){
|
||||
testAddr = sqlite3CodeOnce(pParse);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
if( pParse->explain==2 ){
|
||||
char *zMsg = sqlite3MPrintf(
|
||||
pParse->db, "EXECUTE %sLIST SUBQUERY %d", testAddr>=0?"":"CORRELATED ",
|
||||
pParse->iNextSelectId
|
||||
);
|
||||
sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC);
|
||||
}
|
||||
#endif
|
||||
|
||||
affinity = sqlite3ExprAffinity(pLeft);
|
||||
|
||||
/* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)'
|
||||
** expression it is handled the same way. An ephemeral table is
|
||||
** filled with single-field index keys representing the results
|
||||
** from the SELECT or the <exprlist>.
|
||||
**
|
||||
** If the 'x' expression is a column value, or the SELECT...
|
||||
** statement returns a column value, then the affinity of that
|
||||
** column is used to build the index keys. If both 'x' and the
|
||||
** SELECT... statement are columns, then numeric affinity is used
|
||||
** if either column has NUMERIC or INTEGER affinity. If neither
|
||||
** 'x' nor the SELECT... statement are columns, then numeric affinity
|
||||
** is used.
|
||||
*/
|
||||
pExpr->iTable = pParse->nTab++;
|
||||
addr = sqlite3VdbeAddOp2(v, bOrdered ? OP_OpenEphemeral : OP_OpenHash,
|
||||
pExpr->iTable, !isRowid);
|
||||
pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, 1, 1);
|
||||
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
/* Case 1: expr IN (SELECT ...)
|
||||
**
|
||||
** Generate code to write the results of the select into the temporary
|
||||
** table allocated and opened above.
|
||||
*/
|
||||
SelectDest dest;
|
||||
ExprList *pEList;
|
||||
|
||||
assert( !isRowid );
|
||||
sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
|
||||
dest.affSdst = (u8)affinity;
|
||||
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
|
||||
pExpr->x.pSelect->iLimit = 0;
|
||||
testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
|
||||
if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){
|
||||
sqlite3KeyInfoUnref(pKeyInfo);
|
||||
return;
|
||||
}
|
||||
pEList = pExpr->x.pSelect->pEList;
|
||||
assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */
|
||||
assert( pEList!=0 );
|
||||
assert( pEList->nExpr>0 );
|
||||
assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
|
||||
pKeyInfo->aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
|
||||
pEList->a[0].pExpr);
|
||||
}else if( ALWAYS(pExpr->x.pList!=0) ){
|
||||
/* Case 2: expr IN (exprlist)
|
||||
**
|
||||
** For each expression, build an index key from the evaluation and
|
||||
** store it in the temporary table. If <expr> is a column, then use
|
||||
** that columns affinity when building index keys. If <expr> is not
|
||||
** a column, use numeric affinity.
|
||||
*/
|
||||
int i;
|
||||
ExprList *pList = pExpr->x.pList;
|
||||
struct ExprList_item *pItem;
|
||||
int r1, r2, r3;
|
||||
|
||||
if( !affinity ){
|
||||
affinity = SQLITE_AFF_NONE;
|
||||
}
|
||||
if( pKeyInfo ){
|
||||
assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
|
||||
pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
|
||||
}
|
||||
|
||||
/* Loop through each expression in <exprlist>. */
|
||||
r1 = sqlite3GetTempReg(pParse);
|
||||
r2 = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, r2);
|
||||
for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){
|
||||
Expr *pE2 = pItem->pExpr;
|
||||
int iValToIns;
|
||||
|
||||
/* If the expression is not constant then we will need to
|
||||
** disable the test that was generated above that makes sure
|
||||
** this code only executes once. Because for a non-constant
|
||||
** expression we need to rerun this code each time.
|
||||
*/
|
||||
if( testAddr>=0 && !sqlite3ExprIsConstant(pE2) ){
|
||||
sqlite3VdbeChangeToNoop(v, testAddr);
|
||||
testAddr = -1;
|
||||
}
|
||||
|
||||
/* Evaluate the expression and insert it into the temp table */
|
||||
if( isRowid && sqlite3ExprIsInteger(pE2, &iValToIns) ){
|
||||
sqlite3VdbeAddOp3(v, OP_InsertInt, pExpr->iTable, r2, iValToIns);
|
||||
}else{
|
||||
r3 = sqlite3ExprCodeTarget(pParse, pE2, r1);
|
||||
if( isRowid ){
|
||||
sqlite3VdbeAddOp2(v, OP_MustBeInt, r3,
|
||||
sqlite3VdbeCurrentAddr(v)+2);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, pExpr->iTable, r2, r3);
|
||||
}else{
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1);
|
||||
sqlite3ExprCacheAffinityChange(pParse, r3, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2);
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
sqlite3ReleaseTempReg(pParse, r2);
|
||||
}
|
||||
if( pKeyInfo ){
|
||||
sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO);
|
||||
}
|
||||
|
||||
if( testAddr>=0 ){
|
||||
sqlite3VdbeJumpHere(v, testAddr);
|
||||
}
|
||||
sqlite3ExprCachePop(pParse, 1);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_SUBQUERY */
|
||||
|
||||
/*
|
||||
** 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
|
||||
@@ -1724,19 +1552,15 @@ static void sqlite3CreateInOperatorRhsTable(
|
||||
**
|
||||
** in order to avoid running the <test if data structure contains null>
|
||||
** test more often than is necessary.
|
||||
**
|
||||
** IN_INDEX_EPH ephemeral tables must be in key order if the bOrdered flag
|
||||
** is true. If bOrdered is false, the generated table can be a hash.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound, int bOrdered){
|
||||
int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
||||
Select *p; /* SELECT to the right of IN operator */
|
||||
int eType = 0; /* Type of RHS table. IN_INDEX_* */
|
||||
int iTab = pParse->nTab++; /* Cursor of the RHS table */
|
||||
int mustBeUnique = (prNotFound==0); /* True if RHS must be unique */
|
||||
Vdbe *v = sqlite3GetVdbe(pParse); /* Virtual machine being coded */
|
||||
|
||||
assert( v!=0 );
|
||||
assert( pX->op==TK_IN );
|
||||
|
||||
/* Check to see if an existing table or index can be used to
|
||||
@@ -1745,11 +1569,11 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound, int bOrdered){
|
||||
*/
|
||||
p = (ExprHasProperty(pX, EP_xIsSelect) ? pX->x.pSelect : 0);
|
||||
if( ALWAYS(pParse->nErr==0) && isCandidateForInOpt(p) ){
|
||||
sqlite3 *db = pParse->db; /* Database connection */
|
||||
Table *pTab; /* Table <table>. */
|
||||
Expr *pExpr; /* Expression <column> */
|
||||
i16 iCol; /* Index of column <column> */
|
||||
i16 iDb; /* Database idx for pTab */
|
||||
sqlite3 *db = pParse->db; /* Database connection */
|
||||
Table *pTab; /* Table <table>. */
|
||||
Expr *pExpr; /* Expression <column> */
|
||||
i16 iCol; /* Index of column <column> */
|
||||
i16 iDb; /* Database idx for pTab */
|
||||
|
||||
assert( p ); /* Because of isCandidateForInOpt(p) */
|
||||
assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */
|
||||
@@ -1759,15 +1583,24 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound, int bOrdered){
|
||||
pExpr = p->pEList->a[0].pExpr;
|
||||
iCol = (i16)pExpr->iColumn;
|
||||
|
||||
/* Code an OP_VerifyCookie and OP_TableLock for <table>. */
|
||||
/* Code an OP_Transaction and OP_TableLock for <table>. */
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
|
||||
|
||||
/* This function is only called from two places. In both cases the vdbe
|
||||
** has already been allocated. So assume sqlite3GetVdbe() is always
|
||||
** successful here.
|
||||
*/
|
||||
assert(v);
|
||||
if( iCol<0 ){
|
||||
int iAddr = sqlite3CodeOnce(pParse);
|
||||
int iAddr;
|
||||
|
||||
iAddr = sqlite3CodeOnce(pParse);
|
||||
|
||||
sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead);
|
||||
eType = IN_INDEX_ROWID;
|
||||
|
||||
sqlite3VdbeJumpHere(v, iAddr);
|
||||
}else{
|
||||
Index *pIdx; /* Iterator variable */
|
||||
@@ -1822,7 +1655,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound, int bOrdered){
|
||||
eType = IN_INDEX_ROWID;
|
||||
}
|
||||
}
|
||||
sqlite3CreateInOperatorRhsTable(pParse, pX, eType==IN_INDEX_ROWID,bOrdered);
|
||||
sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID);
|
||||
pParse->nQueryLoop = savedNQueryLoop;
|
||||
}else{
|
||||
pX->iTable = iTab;
|
||||
@@ -1832,37 +1665,56 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound, int bOrdered){
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Generate code for scalar subqueries used as a subquery expression:
|
||||
** Generate code for scalar subqueries used as a subquery expression, EXISTS,
|
||||
** or IN operators. Examples:
|
||||
**
|
||||
** (SELECT a FROM b) -- subquery
|
||||
** EXISTS (SELECT a FROM b) -- EXISTS subquery
|
||||
** x IN (4,5,11) -- IN operator with list on right-hand side
|
||||
** x IN (SELECT a FROM b) -- IN operator with subquery on the right
|
||||
**
|
||||
** The pExpr parameter describes the expression that contains the subquery.
|
||||
** The pExpr parameter describes the expression that contains the IN
|
||||
** operator or subquery.
|
||||
**
|
||||
** Return the register that holds the result.
|
||||
** If parameter isRowid is non-zero, then expression pExpr is guaranteed
|
||||
** to be of the form "<rowid> IN (?, ?, ?)", where <rowid> is a reference
|
||||
** to some integer key column of a table B-Tree. In this case, use an
|
||||
** intkey B-Tree to store the set of IN(...) values instead of the usual
|
||||
** (slower) variable length keys B-Tree.
|
||||
**
|
||||
** If rMayHaveNull is non-zero, that means that the operation is an IN
|
||||
** (not a SELECT or EXISTS) and that the RHS might contains NULLs.
|
||||
** Furthermore, the IN is in a WHERE clause and that we really want
|
||||
** to iterate over the RHS of the IN operator in order to quickly locate
|
||||
** all corresponding LHS elements. All this routine does is initialize
|
||||
** the register given by rMayHaveNull to NULL. Calling routines will take
|
||||
** care of changing this register value to non-NULL if the RHS is NULL-free.
|
||||
**
|
||||
** If rMayHaveNull is zero, that means that the subquery is being used
|
||||
** for membership testing only. There is no need to initialize any
|
||||
** registers to indicate the presence or absence of NULLs on the RHS.
|
||||
**
|
||||
** 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.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
static int sqlite3CodeScalarSubquery(
|
||||
int sqlite3CodeSubselect(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Expr *pExpr /* The SELECT or EXISTS operator */
|
||||
Expr *pExpr, /* The IN, SELECT, or EXISTS operator */
|
||||
int rMayHaveNull, /* Register that records whether NULLs exist in RHS */
|
||||
int isRowid /* If true, LHS of IN operator is a rowid */
|
||||
){
|
||||
int testAddr = -1; /* One-time test address */
|
||||
int rReg = 0; /* Register storing resulting */
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
Select *pSel; /* SELECT statement to encode */
|
||||
SelectDest dest; /* How to deal with SELECt result */
|
||||
|
||||
if( NEVER(v==0) ) return 0;
|
||||
testcase( pExpr->op==TK_EXISTS );
|
||||
testcase( pExpr->op==TK_SELECT );
|
||||
assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT );
|
||||
assert( ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
sqlite3ExprCachePush(pParse);
|
||||
|
||||
/* This code must be run in its entirety every time it is encountered
|
||||
** if any of the following is true:
|
||||
**
|
||||
** * pExpr is a correlated subquery
|
||||
** * The right-hand side is a correlated subquery
|
||||
** * The right-hand side is an expression list containing variables
|
||||
** * We are inside a trigger
|
||||
**
|
||||
** If all of the above are false, then we can run this code just once
|
||||
@@ -1875,33 +1727,173 @@ static int sqlite3CodeScalarSubquery(
|
||||
#ifndef SQLITE_OMIT_EXPLAIN
|
||||
if( pParse->explain==2 ){
|
||||
char *zMsg = sqlite3MPrintf(
|
||||
pParse->db, "EXECUTE %sSCALAR SUBQUERY %d",
|
||||
testAddr>=0?"":"CORRELATED ", pParse->iNextSelectId
|
||||
pParse->db, "EXECUTE %s%s SUBQUERY %d", testAddr>=0?"":"CORRELATED ",
|
||||
pExpr->op==TK_IN?"LIST":"SCALAR", pParse->iNextSelectId
|
||||
);
|
||||
sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC);
|
||||
}
|
||||
#endif
|
||||
|
||||
pSel = pExpr->x.pSelect;
|
||||
sqlite3SelectDestInit(&dest, 0, ++pParse->nMem);
|
||||
if( pExpr->op==TK_SELECT ){
|
||||
dest.eDest = SRT_Mem;
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, dest.iSDParm);
|
||||
VdbeComment((v, "Init subquery result"));
|
||||
}else{
|
||||
dest.eDest = SRT_Exists;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iSDParm);
|
||||
VdbeComment((v, "Init EXISTS result"));
|
||||
switch( pExpr->op ){
|
||||
case TK_IN: {
|
||||
char affinity; /* Affinity of the LHS of the IN */
|
||||
int addr; /* Address of OP_OpenEphemeral instruction */
|
||||
Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */
|
||||
KeyInfo *pKeyInfo = 0; /* Key information */
|
||||
|
||||
if( rMayHaveNull ){
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, rMayHaveNull);
|
||||
}
|
||||
|
||||
affinity = sqlite3ExprAffinity(pLeft);
|
||||
|
||||
/* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)'
|
||||
** expression it is handled the same way. An ephemeral table is
|
||||
** filled with single-field index keys representing the results
|
||||
** from the SELECT or the <exprlist>.
|
||||
**
|
||||
** If the 'x' expression is a column value, or the SELECT...
|
||||
** statement returns a column value, then the affinity of that
|
||||
** column is used to build the index keys. If both 'x' and the
|
||||
** SELECT... statement are columns, then numeric affinity is used
|
||||
** if either column has NUMERIC or INTEGER affinity. If neither
|
||||
** 'x' nor the SELECT... statement are columns, then numeric affinity
|
||||
** is used.
|
||||
*/
|
||||
pExpr->iTable = pParse->nTab++;
|
||||
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, !isRowid);
|
||||
pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, 1, 1);
|
||||
|
||||
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
|
||||
/* Case 1: expr IN (SELECT ...)
|
||||
**
|
||||
** Generate code to write the results of the select into the temporary
|
||||
** table allocated and opened above.
|
||||
*/
|
||||
SelectDest dest;
|
||||
ExprList *pEList;
|
||||
|
||||
assert( !isRowid );
|
||||
sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
|
||||
dest.affSdst = (u8)affinity;
|
||||
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
|
||||
pExpr->x.pSelect->iLimit = 0;
|
||||
testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
|
||||
if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){
|
||||
sqlite3KeyInfoUnref(pKeyInfo);
|
||||
return 0;
|
||||
}
|
||||
pEList = pExpr->x.pSelect->pEList;
|
||||
assert( pKeyInfo!=0 ); /* OOM will cause exit after sqlite3Select() */
|
||||
assert( pEList!=0 );
|
||||
assert( pEList->nExpr>0 );
|
||||
assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
|
||||
pKeyInfo->aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
|
||||
pEList->a[0].pExpr);
|
||||
}else if( ALWAYS(pExpr->x.pList!=0) ){
|
||||
/* Case 2: expr IN (exprlist)
|
||||
**
|
||||
** For each expression, build an index key from the evaluation and
|
||||
** store it in the temporary table. If <expr> is a column, then use
|
||||
** that columns affinity when building index keys. If <expr> is not
|
||||
** a column, use numeric affinity.
|
||||
*/
|
||||
int i;
|
||||
ExprList *pList = pExpr->x.pList;
|
||||
struct ExprList_item *pItem;
|
||||
int r1, r2, r3;
|
||||
|
||||
if( !affinity ){
|
||||
affinity = SQLITE_AFF_NONE;
|
||||
}
|
||||
if( pKeyInfo ){
|
||||
assert( sqlite3KeyInfoIsWriteable(pKeyInfo) );
|
||||
pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
|
||||
}
|
||||
|
||||
/* Loop through each expression in <exprlist>. */
|
||||
r1 = sqlite3GetTempReg(pParse);
|
||||
r2 = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, r2);
|
||||
for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){
|
||||
Expr *pE2 = pItem->pExpr;
|
||||
int iValToIns;
|
||||
|
||||
/* If the expression is not constant then we will need to
|
||||
** disable the test that was generated above that makes sure
|
||||
** this code only executes once. Because for a non-constant
|
||||
** expression we need to rerun this code each time.
|
||||
*/
|
||||
if( testAddr>=0 && !sqlite3ExprIsConstant(pE2) ){
|
||||
sqlite3VdbeChangeToNoop(v, testAddr);
|
||||
testAddr = -1;
|
||||
}
|
||||
|
||||
/* Evaluate the expression and insert it into the temp table */
|
||||
if( isRowid && sqlite3ExprIsInteger(pE2, &iValToIns) ){
|
||||
sqlite3VdbeAddOp3(v, OP_InsertInt, pExpr->iTable, r2, iValToIns);
|
||||
}else{
|
||||
r3 = sqlite3ExprCodeTarget(pParse, pE2, r1);
|
||||
if( isRowid ){
|
||||
sqlite3VdbeAddOp2(v, OP_MustBeInt, r3,
|
||||
sqlite3VdbeCurrentAddr(v)+2);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, pExpr->iTable, r2, r3);
|
||||
}else{
|
||||
sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1);
|
||||
sqlite3ExprCacheAffinityChange(pParse, r3, 1);
|
||||
sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2);
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3ReleaseTempReg(pParse, r1);
|
||||
sqlite3ReleaseTempReg(pParse, r2);
|
||||
}
|
||||
if( pKeyInfo ){
|
||||
sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TK_EXISTS:
|
||||
case TK_SELECT:
|
||||
default: {
|
||||
/* If this has to be a scalar SELECT. Generate code to put the
|
||||
** value of this select in a memory cell and record the number
|
||||
** of the memory cell in iColumn. If this is an EXISTS, write
|
||||
** an integer 0 (not exists) or 1 (exists) into a memory cell
|
||||
** and record that memory cell in iColumn.
|
||||
*/
|
||||
Select *pSel; /* SELECT statement to encode */
|
||||
SelectDest dest; /* How to deal with SELECt result */
|
||||
|
||||
testcase( pExpr->op==TK_EXISTS );
|
||||
testcase( pExpr->op==TK_SELECT );
|
||||
assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT );
|
||||
|
||||
assert( ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
pSel = pExpr->x.pSelect;
|
||||
sqlite3SelectDestInit(&dest, 0, ++pParse->nMem);
|
||||
if( pExpr->op==TK_SELECT ){
|
||||
dest.eDest = SRT_Mem;
|
||||
sqlite3VdbeAddOp2(v, OP_Null, 0, dest.iSDParm);
|
||||
VdbeComment((v, "Init subquery result"));
|
||||
}else{
|
||||
dest.eDest = SRT_Exists;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iSDParm);
|
||||
VdbeComment((v, "Init EXISTS result"));
|
||||
}
|
||||
sqlite3ExprDelete(pParse->db, pSel->pLimit);
|
||||
pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0,
|
||||
&sqlite3IntTokens[1]);
|
||||
pSel->iLimit = 0;
|
||||
if( sqlite3Select(pParse, pSel, &dest) ){
|
||||
return 0;
|
||||
}
|
||||
rReg = dest.iSDParm;
|
||||
ExprSetVVAProperty(pExpr, EP_NoReduce);
|
||||
break;
|
||||
}
|
||||
}
|
||||
sqlite3ExprDelete(pParse->db, pSel->pLimit);
|
||||
pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0,
|
||||
&sqlite3IntTokens[1]);
|
||||
pSel->iLimit = 0;
|
||||
if( sqlite3Select(pParse, pSel, &dest) ){
|
||||
return 0;
|
||||
}
|
||||
rReg = dest.iSDParm;
|
||||
ExprSetVVAProperty(pExpr, EP_NoReduce);
|
||||
|
||||
if( testAddr>=0 ){
|
||||
sqlite3VdbeJumpHere(v, testAddr);
|
||||
@@ -1948,7 +1940,7 @@ static void sqlite3ExprCodeIN(
|
||||
v = pParse->pVdbe;
|
||||
assert( v!=0 ); /* OOM detected prior to this routine */
|
||||
VdbeNoopComment((v, "begin IN expr"));
|
||||
eType = sqlite3FindInIndex(pParse, pExpr, &rRhsHasNull, 0);
|
||||
eType = sqlite3FindInIndex(pParse, pExpr, &rRhsHasNull);
|
||||
|
||||
/* Figure out the affinity to use to create a key from the results
|
||||
** of the expression. affinityStr stores a static string suitable for
|
||||
@@ -2820,7 +2812,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
case TK_SELECT: {
|
||||
testcase( op==TK_EXISTS );
|
||||
testcase( op==TK_SELECT );
|
||||
inReg = sqlite3CodeScalarSubquery(pParse, pExpr);
|
||||
inReg = sqlite3CodeSubselect(pParse, pExpr, 0, 0);
|
||||
break;
|
||||
}
|
||||
case TK_IN: {
|
||||
|
||||
+19
-55
@@ -349,17 +349,13 @@ void sqlite3AutoincrementEnd(Parse *pParse){
|
||||
** co-routine. Run the co-routine to its next breakpoint
|
||||
** by calling "OP_Yield $X" where $X is pDest->iSDParm.
|
||||
**
|
||||
** pDest->iSDParm+1 The register holding the "completed" flag for the
|
||||
** co-routine. This register is 0 if the previous Yield
|
||||
** generated a new result row, or 1 if the subquery
|
||||
** has completed. If the Yield is called again
|
||||
** after this register becomes 1, then the VDBE will
|
||||
** halt with an SQLITE_INTERNAL error.
|
||||
**
|
||||
** pDest->iSdst First result register.
|
||||
**
|
||||
** pDest->nSdst Number of result registers.
|
||||
**
|
||||
** At EOF the first result register will be marked as "undefined" so that
|
||||
** the caller can know when to stop reading results.
|
||||
**
|
||||
** This routine handles all of the register allocation and fills in the
|
||||
** pDest structure appropriately.
|
||||
**
|
||||
@@ -370,7 +366,6 @@ void sqlite3AutoincrementEnd(Parse *pParse){
|
||||
** reg[pDest->iSdst+pDest->nSdst-1]:
|
||||
**
|
||||
** X <- A
|
||||
** EOF <- 0
|
||||
** goto B
|
||||
** A: setup for the SELECT
|
||||
** loop rows in the SELECT
|
||||
@@ -378,16 +373,13 @@ void sqlite3AutoincrementEnd(Parse *pParse){
|
||||
** yield X
|
||||
** end loop
|
||||
** cleanup after the SELECT
|
||||
** EOF <- 1
|
||||
** yield X
|
||||
** halt-error
|
||||
** end co-routine R
|
||||
** B:
|
||||
**
|
||||
** To use this subroutine, the caller generates code as follows:
|
||||
**
|
||||
** [ Co-routine generated by this subroutine, shown above ]
|
||||
** S: yield X
|
||||
** if EOF goto E
|
||||
** S: yield X, at EOF goto E
|
||||
** if skip this row, goto C
|
||||
** if terminate loop, goto E
|
||||
** deal with this row
|
||||
@@ -396,31 +388,21 @@ void sqlite3AutoincrementEnd(Parse *pParse){
|
||||
*/
|
||||
int sqlite3CodeCoroutine(Parse *pParse, Select *pSelect, SelectDest *pDest){
|
||||
int regYield; /* Register holding co-routine entry-point */
|
||||
int regEof; /* Register holding co-routine completion flag */
|
||||
int addrTop; /* Top of the co-routine */
|
||||
int j1; /* Jump instruction */
|
||||
int rc; /* Result code */
|
||||
Vdbe *v; /* VDBE under construction */
|
||||
|
||||
regYield = ++pParse->nMem;
|
||||
regEof = ++pParse->nMem;
|
||||
v = sqlite3GetVdbe(pParse);
|
||||
addrTop = sqlite3VdbeCurrentAddr(v);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, addrTop+2, regYield); /* X <- A */
|
||||
VdbeComment((v, "Co-routine entry point"));
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regEof); /* EOF <- 0 */
|
||||
VdbeComment((v, "Co-routine completion flag"));
|
||||
addrTop = sqlite3VdbeCurrentAddr(v) + 1;
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
|
||||
sqlite3SelectDestInit(pDest, SRT_Coroutine, regYield);
|
||||
j1 = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0);
|
||||
rc = sqlite3Select(pParse, pSelect, pDest);
|
||||
assert( pParse->nErr==0 || rc );
|
||||
if( pParse->db->mallocFailed && rc==SQLITE_OK ) rc = SQLITE_NOMEM;
|
||||
if( rc ) return rc;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEof); /* EOF <- 1 */
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regYield); /* yield X */
|
||||
sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_INTERNAL, OE_Abort);
|
||||
VdbeComment((v, "End of coroutine"));
|
||||
sqlite3VdbeJumpHere(v, j1); /* label B: */
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regYield);
|
||||
sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -488,7 +470,6 @@ static int xferOptimization(
|
||||
** and the SELECT clause does not read from <table> at any time.
|
||||
** The generated code follows this template:
|
||||
**
|
||||
** EOF <- 0
|
||||
** X <- A
|
||||
** goto B
|
||||
** A: setup for the SELECT
|
||||
@@ -497,12 +478,9 @@ static int xferOptimization(
|
||||
** yield X
|
||||
** end loop
|
||||
** cleanup after the SELECT
|
||||
** EOF <- 1
|
||||
** yield X
|
||||
** goto A
|
||||
** end-coroutine X
|
||||
** B: open write cursor to <table> and its indices
|
||||
** C: yield X
|
||||
** if EOF goto D
|
||||
** C: yield X, at EOF goto D
|
||||
** insert the select result into <table> from R..R+n
|
||||
** goto C
|
||||
** D: cleanup
|
||||
@@ -513,7 +491,6 @@ static int xferOptimization(
|
||||
** we have to use a intermediate table to store the results of
|
||||
** the select. The template is like this:
|
||||
**
|
||||
** EOF <- 0
|
||||
** X <- A
|
||||
** goto B
|
||||
** A: setup for the SELECT
|
||||
@@ -522,12 +499,9 @@ static int xferOptimization(
|
||||
** yield X
|
||||
** end loop
|
||||
** cleanup after the SELECT
|
||||
** EOF <- 1
|
||||
** yield X
|
||||
** halt-error
|
||||
** end co-routine R
|
||||
** B: open temp table
|
||||
** L: yield X
|
||||
** if EOF goto M
|
||||
** L: yield X, at EOF goto M
|
||||
** insert row from R..R+n into temp table
|
||||
** goto L
|
||||
** M: open write cursor to <table> and its indices
|
||||
@@ -576,7 +550,6 @@ void sqlite3Insert(
|
||||
int regIns; /* Block of regs holding rowid+data being inserted */
|
||||
int regRowid; /* registers holding insert rowid */
|
||||
int regData; /* register holding first column to insert */
|
||||
int regEof = 0; /* Register recording end of SELECT data */
|
||||
int *aRegIdx = 0; /* One register allocated to each index */
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
@@ -689,7 +662,6 @@ void sqlite3Insert(
|
||||
int rc = sqlite3CodeCoroutine(pParse, pSelect, &dest);
|
||||
if( rc ) goto insert_cleanup;
|
||||
|
||||
regEof = dest.iSDParm + 1;
|
||||
regFromSelect = dest.iSdst;
|
||||
assert( pSelect->pEList );
|
||||
nColumn = pSelect->pEList->nExpr;
|
||||
@@ -714,31 +686,25 @@ void sqlite3Insert(
|
||||
** here is from the 4th template:
|
||||
**
|
||||
** B: open temp table
|
||||
** L: yield X
|
||||
** if EOF goto M
|
||||
** L: yield X, goto M at EOF
|
||||
** insert row from R..R+n into temp table
|
||||
** goto L
|
||||
** M: ...
|
||||
**
|
||||
** Use OP_OpenEphemeral, not OP_OpenHash, so that srcTab behaves as
|
||||
** a FIFO.
|
||||
*/
|
||||
int regRec; /* Register to hold packed record */
|
||||
int regTempRowid; /* Register to hold temp table ROWID */
|
||||
int addrTop; /* Label "L" */
|
||||
int addrIf; /* Address of jump to M */
|
||||
|
||||
srcTab = pParse->nTab++;
|
||||
regRec = sqlite3GetTempReg(pParse);
|
||||
regTempRowid = sqlite3GetTempReg(pParse);
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, srcTab, nColumn);
|
||||
addrTop = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
|
||||
addrIf = sqlite3VdbeAddOp1(v, OP_If, regEof);
|
||||
sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec);
|
||||
sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regTempRowid);
|
||||
sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regTempRowid);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop);
|
||||
sqlite3VdbeJumpHere(v, addrIf);
|
||||
sqlite3VdbeJumpHere(v, addrTop);
|
||||
sqlite3ReleaseTempReg(pParse, regRec);
|
||||
sqlite3ReleaseTempReg(pParse, regTempRowid);
|
||||
}
|
||||
@@ -850,7 +816,7 @@ void sqlite3Insert(
|
||||
/* This block codes the top of loop only. The complete loop is the
|
||||
** following pseudocode (template 4):
|
||||
**
|
||||
** rewind temp table
|
||||
** rewind temp table, if empty goto D
|
||||
** C: loop over rows of intermediate table
|
||||
** transfer values form intermediate table into <table>
|
||||
** end loop
|
||||
@@ -862,14 +828,12 @@ void sqlite3Insert(
|
||||
/* This block codes the top of loop only. The complete loop is the
|
||||
** following pseudocode (template 3):
|
||||
**
|
||||
** C: yield X
|
||||
** if EOF goto D
|
||||
** C: yield X, at EOF goto D
|
||||
** insert the select result into <table> from R..R+n
|
||||
** goto C
|
||||
** D: ...
|
||||
*/
|
||||
addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
|
||||
addrInsTop = sqlite3VdbeAddOp1(v, OP_If, regEof);
|
||||
addrInsTop = addrCont = sqlite3VdbeAddOp1(v, OP_Yield, dest.iSDParm);
|
||||
}
|
||||
|
||||
/* Allocate registers for holding the rowid of the new row,
|
||||
@@ -2074,7 +2038,7 @@ static int xferOptimization(
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0);
|
||||
sqlite3VdbeAddOp2(v, OP_Close, iDest, 0);
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, emptySrcTest);
|
||||
if( emptySrcTest ) sqlite3VdbeJumpHere(v, emptySrcTest);
|
||||
sqlite3ReleaseTempReg(pParse, regRowid);
|
||||
sqlite3ReleaseTempReg(pParse, regData);
|
||||
if( emptyDestTest ){
|
||||
|
||||
+160
-56
@@ -83,32 +83,6 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** These #defines should enable >2GB file support on Posix if the
|
||||
** underlying operating system supports it. If the OS lacks
|
||||
** large file support, these should be no-ops.
|
||||
**
|
||||
** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch
|
||||
** on the compiler command line. This is necessary if you are compiling
|
||||
** on a recent machine (ex: RedHat 7.2) but you want your code to work
|
||||
** on an older machine (ex: RedHat 6.0). If you compile on RedHat 7.2
|
||||
** without this option, LFS is enable. But LFS does not exist in the kernel
|
||||
** in RedHat 6.0, so the code won't work. Hence, for maximum binary
|
||||
** portability you should omit LFS.
|
||||
**
|
||||
** The previous paragraph was written in 2005. (This paragraph is written
|
||||
** on 2008-11-28.) These days, all Linux kernels support large files, so
|
||||
** you should probably leave LFS enabled. But some embedded platforms might
|
||||
** lack LFS in which case the SQLITE_DISABLE_LFS macro might still be useful.
|
||||
*/
|
||||
#ifndef SQLITE_DISABLE_LFS
|
||||
# define _LARGE_FILE 1
|
||||
# ifndef _FILE_OFFSET_BITS
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
# endif
|
||||
# define _LARGEFILE_SOURCE 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** standard include files.
|
||||
*/
|
||||
@@ -229,9 +203,7 @@ struct unixFile {
|
||||
int sectorSize; /* Device sector size */
|
||||
int deviceCharacteristics; /* Precomputed device characteristics */
|
||||
#endif
|
||||
#if SQLITE_ENABLE_LOCKING_STYLE
|
||||
int openFlags; /* The flags specified at open() */
|
||||
#endif
|
||||
#if SQLITE_ENABLE_LOCKING_STYLE || defined(__APPLE__)
|
||||
unsigned fsFlags; /* cached details from statfs() */
|
||||
#endif
|
||||
@@ -281,7 +253,8 @@ static int randomnessPid = 0;
|
||||
#define UNIXFILE_DELETE 0x20 /* Delete on close */
|
||||
#define UNIXFILE_URI 0x40 /* Filename might have query parameters */
|
||||
#define UNIXFILE_NOLOCK 0x80 /* Do no file locking */
|
||||
#define UNIXFILE_WARNED 0x0100 /* verifyDbFile() warnings have been issued */
|
||||
#define UNIXFILE_WARNED 0x0100 /* verifyDbFile() has issued warnings */
|
||||
#define UNIXFILE_DEFERRED 0x0200 /* File has not yet been opened */
|
||||
|
||||
/*
|
||||
** Include code that is common to all os_*.c files
|
||||
@@ -1383,9 +1356,14 @@ static int unixCheckReservedLock(sqlite3_file *id, int *pResOut){
|
||||
int reserved = 0;
|
||||
unixFile *pFile = (unixFile*)id;
|
||||
|
||||
assert( pFile );
|
||||
SimulateIOError( return SQLITE_IOERR_CHECKRESERVEDLOCK; );
|
||||
|
||||
assert( pFile );
|
||||
if( pFile->ctrlFlags & UNIXFILE_DEFERRED ){
|
||||
*pResOut = 0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
unixEnterMutex(); /* Because pFile->pInode is shared across threads */
|
||||
|
||||
/* Check if a thread in this process holds such a lock */
|
||||
@@ -1465,6 +1443,21 @@ static int unixFileLock(unixFile *pFile, struct flock *pLock){
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int unixOpen(sqlite3_vfs*, const char*, sqlite3_file*, int, int *);
|
||||
|
||||
static int unixOpenAndLock(unixFile *pFile){
|
||||
sqlite3_file *id = (sqlite3_file*)pFile;
|
||||
int eOrigLock = pFile->eFileLock;
|
||||
int rc;
|
||||
|
||||
assert( pFile->ctrlFlags & UNIXFILE_DEFERRED );
|
||||
rc = unixOpen(pFile->pVfs, pFile->zPath, id, pFile->openFlags, 0);
|
||||
if( rc==SQLITE_OK && eOrigLock ){
|
||||
rc = id->pMethods->xLock(id, eOrigLock);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Lock the file with the lock specified by parameter eFileLock - one
|
||||
** of the following:
|
||||
@@ -1549,9 +1542,29 @@ static int unixLock(sqlite3_file *id, int eFileLock){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
if( pFile->ctrlFlags & UNIXFILE_DEFERRED ){
|
||||
const char *zPath = pFile->zPath; /* Full-path to database file */
|
||||
int eOrigLock; /* Current lock held on pFile */
|
||||
|
||||
assert( pFile->eFileLock==SHARED_LOCK || pFile->eFileLock==NO_LOCK );
|
||||
|
||||
/* If SQLite is requesting a SHARED lock and the database file does
|
||||
** not exist, return early without opening the file. */
|
||||
if( eFileLock==SHARED_LOCK && osAccess(zPath, F_OK) && errno==ENOENT ){
|
||||
pFile->eFileLock = SHARED_LOCK;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/* Or, if the database file has been created or a write lock is
|
||||
** requested, open the database file now. */
|
||||
rc = unixOpenAndLock(pFile);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
assert( (pFile->ctrlFlags & UNIXFILE_DEFERRED)==0 );
|
||||
|
||||
/* Make sure the locking sequence is correct.
|
||||
** (1) We never move from unlocked to anything higher than shared lock.
|
||||
** (2) SQLite never explicitly requests a pendig lock.
|
||||
** (2) SQLite never explicitly requests a pending lock.
|
||||
** (3) A shared lock is always held when a reserve lock is requested.
|
||||
*/
|
||||
assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK );
|
||||
@@ -1752,6 +1765,7 @@ static int posixUnlock(sqlite3_file *id, int eFileLock, int handleNFSUnlock){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
unixEnterMutex();
|
||||
if( pFile->ctrlFlags & UNIXFILE_DEFERRED ) goto end_unlock;
|
||||
pInode = pFile->pInode;
|
||||
assert( pInode->nShared!=0 );
|
||||
if( pFile->eFileLock>SHARED_LOCK ){
|
||||
@@ -1958,19 +1972,23 @@ static int unixClose(sqlite3_file *id){
|
||||
unixUnlock(id, NO_LOCK);
|
||||
unixEnterMutex();
|
||||
|
||||
/* unixFile.pInode is always valid here. Otherwise, a different close
|
||||
** routine (e.g. nolockClose()) would be called instead.
|
||||
/* unixFile.pInode may be NULL here if the file was never opened.
|
||||
*/
|
||||
assert( pFile->pInode->nLock>0 || pFile->pInode->bProcessLock==0 );
|
||||
if( ALWAYS(pFile->pInode) && pFile->pInode->nLock ){
|
||||
/* If there are outstanding locks, do not actually close the file just
|
||||
** yet because that would clear those locks. Instead, add the file
|
||||
** descriptor to pInode->pUnused list. It will be automatically closed
|
||||
** when the last lock is cleared.
|
||||
*/
|
||||
setPendingFd(pFile);
|
||||
assert( pFile->pInode==0
|
||||
|| pFile->pInode->nLock>0
|
||||
|| pFile->pInode->bProcessLock==0
|
||||
);
|
||||
if( pFile->pInode ){
|
||||
if( pFile->pInode->nLock ){
|
||||
/* If there are outstanding locks, do not actually close the file just
|
||||
** yet because that would clear those locks. Instead, add the file
|
||||
** descriptor to pInode->pUnused list. It will be automatically closed
|
||||
** when the last lock is cleared.
|
||||
*/
|
||||
setPendingFd(pFile);
|
||||
}
|
||||
releaseInodeInfo(pFile);
|
||||
}
|
||||
releaseInodeInfo(pFile);
|
||||
rc = closeUnixFile(id);
|
||||
unixLeaveMutex();
|
||||
return rc;
|
||||
@@ -3199,6 +3217,20 @@ static int unixRead(
|
||||
);
|
||||
#endif
|
||||
|
||||
if( pFile->ctrlFlags & UNIXFILE_DEFERRED ){
|
||||
int rc;
|
||||
if( osAccess(pFile->zPath, F_OK) && errno==ENOENT ){
|
||||
memset(pBuf, 0, amt);
|
||||
rc = SQLITE_IOERR_SHORT_READ;
|
||||
}else{
|
||||
rc = unixOpen(pFile->pVfs, pFile->zPath, id, pFile->openFlags, 0);
|
||||
}
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
assert( (pFile->ctrlFlags & UNIXFILE_DEFERRED)==0 );
|
||||
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
/* Deal with as much of this read request as possible by transfering
|
||||
** data from the memory mapping using memcpy(). */
|
||||
@@ -3303,6 +3335,15 @@ static int unixWrite(
|
||||
assert( id );
|
||||
assert( amt>0 );
|
||||
|
||||
/* SQLite never actually calls xWrite on an empty file before obtaining
|
||||
** a RESERVED lock on it. So the following condition is never true if
|
||||
** the VFS is being used directly by SQLite. But it may be if this module
|
||||
** is being used in some other way. By the multiplexor VFS, for example. */
|
||||
if( pFile->ctrlFlags & UNIXFILE_DEFERRED ){
|
||||
int rc = unixOpenAndLock(pFile);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
}
|
||||
|
||||
/* If this is a database file (not a journal, master-journal or temp
|
||||
** file), the bytes in the locking range should never be read or written. */
|
||||
#if 0
|
||||
@@ -3651,10 +3692,19 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
|
||||
** Determine the current size of a file in bytes
|
||||
*/
|
||||
static int unixFileSize(sqlite3_file *id, i64 *pSize){
|
||||
unixFile *pFile = (unixFile*)id;
|
||||
int rc;
|
||||
struct stat buf;
|
||||
assert( id );
|
||||
rc = osFstat(((unixFile*)id)->h, &buf);
|
||||
if( pFile->ctrlFlags & UNIXFILE_DEFERRED ){
|
||||
rc = osStat(pFile->zPath, &buf);
|
||||
if( rc && errno==ENOENT ){
|
||||
rc = 0;
|
||||
buf.st_size = 0;
|
||||
}
|
||||
}else{
|
||||
rc = osFstat(pFile->h, &buf);
|
||||
}
|
||||
SimulateIOError( rc=1 );
|
||||
if( rc!=0 ){
|
||||
((unixFile*)id)->lastErrno = errno;
|
||||
@@ -3670,7 +3720,6 @@ static int unixFileSize(sqlite3_file *id, i64 *pSize){
|
||||
*/
|
||||
if( *pSize==1 ) *pSize = 0;
|
||||
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -5202,14 +5251,7 @@ static int fillInUnixFile(
|
||||
pNew->h = h;
|
||||
pNew->pVfs = pVfs;
|
||||
pNew->zPath = zFilename;
|
||||
pNew->ctrlFlags = (u8)ctrlFlags;
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
pNew->mmapSizeMax = sqlite3GlobalConfig.szMmap;
|
||||
#endif
|
||||
if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0),
|
||||
"psow", SQLITE_POWERSAFE_OVERWRITE) ){
|
||||
pNew->ctrlFlags |= UNIXFILE_PSOW;
|
||||
}
|
||||
pNew->ctrlFlags = (unsigned short)ctrlFlags;
|
||||
if( strcmp(pVfs->zName,"unix-excl")==0 ){
|
||||
pNew->ctrlFlags |= UNIXFILE_EXCL;
|
||||
}
|
||||
@@ -5348,7 +5390,6 @@ static int fillInUnixFile(
|
||||
if( h>=0 ) robust_close(pNew, h, __LINE__);
|
||||
}else{
|
||||
pNew->pMethod = pLockingStyle;
|
||||
OpenCounter(+1);
|
||||
verifyDbFile(pNew);
|
||||
}
|
||||
return rc;
|
||||
@@ -5605,7 +5646,7 @@ static int unixOpen(
|
||||
int eType = flags&0xFFFFFF00; /* Type of file to open */
|
||||
int noLock; /* True to omit locking primitives */
|
||||
int rc = SQLITE_OK; /* Function Return Code */
|
||||
int ctrlFlags = 0; /* UNIXFILE_* flags */
|
||||
int ctrlFlags; /* UNIXFILE_* flags */
|
||||
|
||||
int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
|
||||
int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
|
||||
@@ -5635,6 +5676,11 @@ static int unixOpen(
|
||||
char zTmpname[MAX_PATHNAME+2];
|
||||
const char *zName = zPath;
|
||||
|
||||
assert( p->pInode==0 && (p->h==-1 || p->h==0) );
|
||||
p->ctrlFlags &= ~UNIXFILE_DEFERRED;
|
||||
p->eFileLock = NO_LOCK;
|
||||
ctrlFlags = p->ctrlFlags;
|
||||
|
||||
/* Check the following statements are true:
|
||||
**
|
||||
** (a) Exactly one of the READWRITE and READONLY flags must be set, and
|
||||
@@ -5671,7 +5717,6 @@ static int unixOpen(
|
||||
sqlite3_randomness(0,0);
|
||||
}
|
||||
|
||||
memset(p, 0, sizeof(unixFile));
|
||||
|
||||
if( eType==SQLITE_OPEN_MAIN_DB ){
|
||||
UnixUnusedFd *pUnused;
|
||||
@@ -5844,10 +5889,69 @@ static int unixOpen(
|
||||
open_finished:
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_free(p->pUnused);
|
||||
p->pUnused = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int unixOpenDeferred(
|
||||
sqlite3_vfs *pVfs, /* The VFS for which this is the xOpen method */
|
||||
const char *zPath, /* Pathname of file to be opened */
|
||||
sqlite3_file *pFile, /* The file descriptor to be filled in */
|
||||
int flags, /* Input flags to control the opening */
|
||||
int *pOutFlags /* Output flags returned to SQLite core */
|
||||
){
|
||||
const int mask1 = SQLITE_OPEN_MAIN_DB | SQLITE_OPEN_READWRITE
|
||||
| SQLITE_OPEN_CREATE;
|
||||
const int mask2 = SQLITE_OPEN_READONLY | SQLITE_OPEN_DELETEONCLOSE
|
||||
| SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_AUTOPROXY;
|
||||
|
||||
int rc; /* Return code */
|
||||
unixFile *p = (unixFile*)pFile; /* File object to populate */
|
||||
const char *zUri = (flags & UNIXFILE_URI) ? zPath : 0;
|
||||
|
||||
/* Zero the file object */
|
||||
memset(p, 0, sizeof(unixFile));
|
||||
if( sqlite3_uri_boolean(zUri, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
|
||||
p->ctrlFlags |= UNIXFILE_PSOW;
|
||||
}
|
||||
#if SQLITE_MAX_MMAP_SIZE>0
|
||||
p->mmapSizeMax = sqlite3GlobalConfig.szMmap;
|
||||
#endif
|
||||
|
||||
/* If all the flags in mask1 are set, and all the flags in mask2 are
|
||||
** clear, the file does not exist but the directory does and is
|
||||
** writable, then this is a deferred open. */
|
||||
if( zPath && (flags & (mask1 | mask2))==mask1 ){
|
||||
int posixrc;
|
||||
posixrc = osAccess(zPath, F_OK);
|
||||
if( posixrc && errno==ENOENT ){
|
||||
char zDirname[MAX_PATHNAME+1];
|
||||
int i;
|
||||
for(i=(int)strlen(zPath); i>1 && zPath[i]!='/'; i--);
|
||||
memcpy(zDirname, zPath, i);
|
||||
zDirname[i] = '\0';
|
||||
posixrc = osAccess(zDirname, W_OK);
|
||||
if( posixrc==0 ){
|
||||
p->pMethod = (**(finder_type*)pVfs->pAppData)(0, 0);
|
||||
if( p->pMethod->xLock==unixLock ){
|
||||
p->pVfs = pVfs;
|
||||
p->h = -1;
|
||||
p->ctrlFlags |= UNIXFILE_DEFERRED;
|
||||
p->openFlags = flags;
|
||||
p->zPath = zPath;
|
||||
if( pOutFlags ) *pOutFlags = flags;
|
||||
OpenCounter(+1);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rc = unixOpen(pVfs, zPath, pFile, flags, pOutFlags);
|
||||
OpenCounter( rc==SQLITE_OK );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete the file at zPath. If the dirSync argument is true, fsync()
|
||||
@@ -7402,7 +7506,7 @@ int sqlite3_os_init(void){
|
||||
0, /* pNext */ \
|
||||
VFSNAME, /* zName */ \
|
||||
(void*)&FINDER, /* pAppData */ \
|
||||
unixOpen, /* xOpen */ \
|
||||
unixOpenDeferred, /* xOpen */ \
|
||||
unixDelete, /* xDelete */ \
|
||||
unixAccess, /* xAccess */ \
|
||||
unixFullPathname, /* xFullPathname */ \
|
||||
|
||||
+1
-1
@@ -1683,7 +1683,7 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
|
||||
** already in memory.
|
||||
*/
|
||||
static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
|
||||
PgHdr *p; /* Return value */
|
||||
PgHdr *p = 0; /* Return value */
|
||||
|
||||
/* It is not possible for a call to PcacheFetch() with createFlag==0 to
|
||||
** fail, since no attempt to allocate dynamic memory will be made.
|
||||
|
||||
+17
-4
@@ -412,13 +412,26 @@ cmd ::= select(X). {
|
||||
%type oneselect {Select*}
|
||||
%destructor oneselect {sqlite3SelectDelete(pParse->db, $$);}
|
||||
|
||||
select(A) ::= with(W) selectnowith(X). {
|
||||
if( X ){
|
||||
X->pWith = W;
|
||||
select(A) ::= with(W) selectnowith(X). {
|
||||
Select *p = X, *pNext, *pLoop;
|
||||
if( p ){
|
||||
int cnt = 0, mxSelect;
|
||||
p->pWith = W;
|
||||
if( p->pPrior ){
|
||||
pNext = 0;
|
||||
for(pLoop=p; pLoop; pNext=pLoop, pLoop=pLoop->pPrior, cnt++){
|
||||
pLoop->pNext = pNext;
|
||||
pLoop->selFlags |= SF_Compound;
|
||||
}
|
||||
mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT];
|
||||
if( mxSelect && cnt>mxSelect ){
|
||||
sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
|
||||
}
|
||||
}
|
||||
}else{
|
||||
sqlite3WithDelete(pParse->db, W);
|
||||
}
|
||||
A = X;
|
||||
A = p;
|
||||
}
|
||||
|
||||
selectnowith(A) ::= oneselect(X). {A = X;}
|
||||
|
||||
+77
-121
@@ -109,6 +109,14 @@ void sqlite3SelectDelete(sqlite3 *db, Select *p){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a pointer to the right-most SELECT statement in a compound.
|
||||
*/
|
||||
static Select *findRightmost(Select *p){
|
||||
while( p->pNext ) p = p->pNext;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Given 1 to 3 identifiers preceding the JOIN keyword, determine the
|
||||
** type of join. Return an integer constant that expresses that type
|
||||
@@ -535,8 +543,8 @@ typedef struct DistinctCtx DistinctCtx;
|
||||
struct DistinctCtx {
|
||||
u8 isTnct; /* True if the DISTINCT keyword is present */
|
||||
u8 eTnctType; /* One of the WHERE_DISTINCT_* operators */
|
||||
int tabTnct; /* Table containing previously seen values */
|
||||
int addrTnct; /* Address of OpenEphemeral/OpenHash opcode for tabTnct */
|
||||
int tabTnct; /* Ephemeral table used for DISTINCT processing */
|
||||
int addrTnct; /* Address of OP_OpenEphemeral opcode for tabTnct */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -765,12 +773,8 @@ static void selectInnerLoop(
|
||||
}
|
||||
#endif /* #ifndef SQLITE_OMIT_SUBQUERY */
|
||||
|
||||
/* Send the data to the callback function or to a subroutine. In the
|
||||
** case of a subroutine, the subroutine itself is responsible for
|
||||
** popping the data from the stack.
|
||||
*/
|
||||
case SRT_Coroutine:
|
||||
case SRT_Output: {
|
||||
case SRT_Coroutine: /* Send data to a co-routine */
|
||||
case SRT_Output: { /* Return the results */
|
||||
testcase( eDest==SRT_Coroutine );
|
||||
testcase( eDest==SRT_Output );
|
||||
if( pOrderBy ){
|
||||
@@ -1619,11 +1623,13 @@ Vdbe *sqlite3GetVdbe(Parse *pParse){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
if( v==0 ){
|
||||
v = pParse->pVdbe = sqlite3VdbeCreate(pParse);
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
if( v ){
|
||||
sqlite3VdbeAddOp0(v, OP_Trace);
|
||||
if( v ) sqlite3VdbeAddOp0(v, OP_Init);
|
||||
if( pParse->pToplevel==0
|
||||
&& OptimizationEnabled(pParse->db,SQLITE_FactorOutConst)
|
||||
){
|
||||
pParse->okConstFactor = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
return v;
|
||||
}
|
||||
@@ -1871,7 +1877,7 @@ static void generateWithRecursiveQuery(
|
||||
}
|
||||
VdbeComment((v, "Queue table"));
|
||||
if( iDistinct ){
|
||||
p->addrOpenEphm[0] = sqlite3VdbeAddOp2(v, OP_OpenHash, iDistinct, 0);
|
||||
p->addrOpenEphm[0] = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iDistinct, 0);
|
||||
p->selFlags |= SF_UsesEphemeral;
|
||||
}
|
||||
|
||||
@@ -1879,7 +1885,9 @@ static void generateWithRecursiveQuery(
|
||||
p->pOrderBy = 0;
|
||||
|
||||
/* Store the results of the setup-query in Queue. */
|
||||
pSetup->pNext = 0;
|
||||
rc = sqlite3Select(pParse, pSetup, &destQueue);
|
||||
pSetup->pNext = p;
|
||||
if( rc ) goto end_of_recursive_query;
|
||||
|
||||
/* Find the next row in the Queue and output that row */
|
||||
@@ -1984,8 +1992,6 @@ static int multiSelect(
|
||||
assert( (p->selFlags & SF_Recursive)==0 || p->op==TK_ALL || p->op==TK_UNION );
|
||||
db = pParse->db;
|
||||
pPrior = p->pPrior;
|
||||
assert( pPrior->pRightmost!=pPrior );
|
||||
assert( pPrior->pRightmost==p->pRightmost );
|
||||
dest = *pDest;
|
||||
if( pPrior->pOrderBy ){
|
||||
sqlite3ErrorMsg(pParse,"ORDER BY clause should come after %s not before",
|
||||
@@ -2007,7 +2013,8 @@ static int multiSelect(
|
||||
*/
|
||||
if( dest.eDest==SRT_EphemTab ){
|
||||
assert( p->pEList );
|
||||
sqlite3VdbeAddOp2(v, OP_OpenHash, dest.iSDParm, p->pEList->nExpr);
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, dest.iSDParm, p->pEList->nExpr);
|
||||
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
|
||||
dest.eDest = SRT_Table;
|
||||
}
|
||||
|
||||
@@ -2092,12 +2099,10 @@ static int multiSelect(
|
||||
testcase( p->op==TK_EXCEPT );
|
||||
testcase( p->op==TK_UNION );
|
||||
priorOp = SRT_Union;
|
||||
if( dest.eDest==priorOp && ALWAYS(!p->pLimit &&!p->pOffset) ){
|
||||
if( dest.eDest==priorOp ){
|
||||
/* We can reuse a temporary table generated by a SELECT to our
|
||||
** right.
|
||||
*/
|
||||
assert( p->pRightmost!=p ); /* Can only happen for leftward elements
|
||||
** of a 3-way or more compound */
|
||||
assert( p->pLimit==0 ); /* Not allowed on leftward elements */
|
||||
assert( p->pOffset==0 ); /* Not allowed on leftward elements */
|
||||
unionTab = dest.iSDParm;
|
||||
@@ -2107,10 +2112,10 @@ static int multiSelect(
|
||||
*/
|
||||
unionTab = pParse->nTab++;
|
||||
assert( p->pOrderBy==0 );
|
||||
addr = sqlite3VdbeAddOp2(v, OP_OpenHash, unionTab, 0);
|
||||
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0);
|
||||
assert( p->addrOpenEphm[0] == -1 );
|
||||
p->addrOpenEphm[0] = addr;
|
||||
p->pRightmost->selFlags |= SF_UsesEphemeral;
|
||||
findRightmost(p)->selFlags |= SF_UsesEphemeral;
|
||||
assert( p->pEList );
|
||||
}
|
||||
|
||||
@@ -2190,8 +2195,7 @@ static int multiSelect(
|
||||
|
||||
/* INTERSECT is different from the others since it requires
|
||||
** two temporary tables. Hence it has its own case. Begin
|
||||
** by allocating the tables we will need. The tables must be
|
||||
** ordered: Use OP_OpenEphermeral, not OP_OpenHash.
|
||||
** by allocating the tables we will need.
|
||||
*/
|
||||
tab1 = pParse->nTab++;
|
||||
tab2 = pParse->nTab++;
|
||||
@@ -2200,7 +2204,7 @@ static int multiSelect(
|
||||
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0);
|
||||
assert( p->addrOpenEphm[0] == -1 );
|
||||
p->addrOpenEphm[0] = addr;
|
||||
p->pRightmost->selFlags |= SF_UsesEphemeral;
|
||||
findRightmost(p)->selFlags |= SF_UsesEphemeral;
|
||||
assert( p->pEList );
|
||||
|
||||
/* Code the SELECTs to our left into temporary table "tab1".
|
||||
@@ -2279,7 +2283,7 @@ static int multiSelect(
|
||||
CollSeq **apColl; /* For looping through pKeyInfo->aColl[] */
|
||||
int nCol; /* Number of columns in result set */
|
||||
|
||||
assert( p->pRightmost==p );
|
||||
assert( p->pNext==0 );
|
||||
nCol = p->pEList->nExpr;
|
||||
pKeyInfo = sqlite3KeyInfoAlloc(db, nCol, 1);
|
||||
if( !pKeyInfo ){
|
||||
@@ -2572,9 +2576,7 @@ static int multiSelectOrderBy(
|
||||
SelectDest destA; /* Destination for coroutine A */
|
||||
SelectDest destB; /* Destination for coroutine B */
|
||||
int regAddrA; /* Address register for select-A coroutine */
|
||||
int regEofA; /* Flag to indicate when select-A is complete */
|
||||
int regAddrB; /* Address register for select-B coroutine */
|
||||
int regEofB; /* Flag to indicate when select-B is complete */
|
||||
int addrSelectA; /* Address of the select-A coroutine */
|
||||
int addrSelectB; /* Address of the select-B coroutine */
|
||||
int regOutA; /* Address register for the output-A subroutine */
|
||||
@@ -2582,6 +2584,7 @@ static int multiSelectOrderBy(
|
||||
int addrOutA; /* Address of the output-A subroutine */
|
||||
int addrOutB = 0; /* Address of the output-B subroutine */
|
||||
int addrEofA; /* Address of the select-A-exhausted subroutine */
|
||||
int addrEofA_noB; /* Alternate addrEofA if B is uninitialized */
|
||||
int addrEofB; /* Address of the select-B-exhausted subroutine */
|
||||
int addrAltB; /* Address of the A<B subroutine */
|
||||
int addrAeqB; /* Address of the A==B subroutine */
|
||||
@@ -2696,6 +2699,7 @@ static int multiSelectOrderBy(
|
||||
/* Separate the left and the right query from one another
|
||||
*/
|
||||
p->pPrior = 0;
|
||||
pPrior->pNext = 0;
|
||||
sqlite3ResolveOrderGroupBy(pParse, p, p->pOrderBy, "ORDER");
|
||||
if( pPrior->pPrior==0 ){
|
||||
sqlite3ResolveOrderGroupBy(pParse, pPrior, pPrior->pOrderBy, "ORDER");
|
||||
@@ -2718,37 +2722,30 @@ static int multiSelectOrderBy(
|
||||
p->pOffset = 0;
|
||||
|
||||
regAddrA = ++pParse->nMem;
|
||||
regEofA = ++pParse->nMem;
|
||||
regAddrB = ++pParse->nMem;
|
||||
regEofB = ++pParse->nMem;
|
||||
regOutA = ++pParse->nMem;
|
||||
regOutB = ++pParse->nMem;
|
||||
sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA);
|
||||
sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB);
|
||||
|
||||
/* Jump past the various subroutines and coroutines to the main
|
||||
** merge loop
|
||||
*/
|
||||
j1 = sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
addrSelectA = sqlite3VdbeCurrentAddr(v);
|
||||
|
||||
|
||||
/* Generate a coroutine to evaluate the SELECT statement to the
|
||||
** left of the compound operator - the "A" select.
|
||||
*/
|
||||
VdbeNoopComment((v, "Begin coroutine for left SELECT"));
|
||||
addrSelectA = sqlite3VdbeCurrentAddr(v) + 1;
|
||||
j1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA);
|
||||
VdbeComment((v, "left SELECT"));
|
||||
pPrior->iLimit = regLimitA;
|
||||
explainSetInteger(iSub1, pParse->iNextSelectId);
|
||||
sqlite3Select(pParse, pPrior, &destA);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofA);
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
||||
VdbeNoopComment((v, "End coroutine for left SELECT"));
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrA);
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
|
||||
/* Generate a coroutine to evaluate the SELECT statement on
|
||||
** the right - the "B" select
|
||||
*/
|
||||
addrSelectB = sqlite3VdbeCurrentAddr(v);
|
||||
VdbeNoopComment((v, "Begin coroutine for right SELECT"));
|
||||
addrSelectB = sqlite3VdbeCurrentAddr(v) + 1;
|
||||
j1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB);
|
||||
VdbeComment((v, "right SELECT"));
|
||||
savedLimit = p->iLimit;
|
||||
savedOffset = p->iOffset;
|
||||
p->iLimit = regLimitB;
|
||||
@@ -2757,9 +2754,7 @@ static int multiSelectOrderBy(
|
||||
sqlite3Select(pParse, p, &destB);
|
||||
p->iLimit = savedLimit;
|
||||
p->iOffset = savedOffset;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, regEofB);
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
|
||||
VdbeNoopComment((v, "End coroutine for right SELECT"));
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, regAddrB);
|
||||
|
||||
/* Generate a subroutine that outputs the current row of the A
|
||||
** select as the next output row of the compound select.
|
||||
@@ -2783,13 +2778,12 @@ static int multiSelectOrderBy(
|
||||
/* Generate a subroutine to run when the results from select A
|
||||
** are exhausted and only data in select B remains.
|
||||
*/
|
||||
VdbeNoopComment((v, "eof-A subroutine"));
|
||||
if( op==TK_EXCEPT || op==TK_INTERSECT ){
|
||||
addrEofA = sqlite3VdbeAddOp2(v, OP_Goto, 0, labelEnd);
|
||||
addrEofA_noB = addrEofA = labelEnd;
|
||||
}else{
|
||||
addrEofA = sqlite3VdbeAddOp2(v, OP_If, regEofB, labelEnd);
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
|
||||
VdbeNoopComment((v, "eof-A subroutine"));
|
||||
addrEofA = sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
|
||||
addrEofA_noB = sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, labelEnd);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEofA);
|
||||
p->nSelectRow += pPrior->nSelectRow;
|
||||
}
|
||||
@@ -2802,9 +2796,8 @@ static int multiSelectOrderBy(
|
||||
if( p->nSelectRow > pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow;
|
||||
}else{
|
||||
VdbeNoopComment((v, "eof-B subroutine"));
|
||||
addrEofB = sqlite3VdbeAddOp2(v, OP_If, regEofA, labelEnd);
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
||||
addrEofB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
|
||||
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, labelEnd);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, addrEofB);
|
||||
}
|
||||
|
||||
@@ -2812,8 +2805,7 @@ static int multiSelectOrderBy(
|
||||
*/
|
||||
VdbeNoopComment((v, "A-lt-B subroutine"));
|
||||
addrAltB = sqlite3VdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
||||
sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
|
||||
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
|
||||
|
||||
/* Generate code to handle the case of A==B
|
||||
@@ -2826,8 +2818,7 @@ static int multiSelectOrderBy(
|
||||
}else{
|
||||
VdbeNoopComment((v, "A-eq-B subroutine"));
|
||||
addrAeqB =
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrA);
|
||||
sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
|
||||
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
|
||||
}
|
||||
|
||||
@@ -2838,19 +2829,14 @@ static int multiSelectOrderBy(
|
||||
if( op==TK_ALL || op==TK_UNION ){
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
|
||||
}
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, regAddrB);
|
||||
sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB);
|
||||
sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB);
|
||||
sqlite3VdbeAddOp2(v, OP_Goto, 0, labelCmpr);
|
||||
|
||||
/* This code runs once to initialize everything.
|
||||
*/
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regEofA);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, regEofB);
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regAddrA, addrSelectA);
|
||||
sqlite3VdbeAddOp2(v, OP_Gosub, regAddrB, addrSelectB);
|
||||
sqlite3VdbeAddOp2(v, OP_If, regEofA, addrEofA);
|
||||
sqlite3VdbeAddOp2(v, OP_If, regEofB, addrEofB);
|
||||
sqlite3VdbeAddOp2(v, OP_Yield, regAddrA, addrEofA_noB);
|
||||
sqlite3VdbeAddOp2(v, OP_Yield, regAddrB, addrEofB);
|
||||
|
||||
/* Implement the main merge loop
|
||||
*/
|
||||
@@ -2879,6 +2865,7 @@ static int multiSelectOrderBy(
|
||||
sqlite3SelectDelete(db, p->pPrior);
|
||||
}
|
||||
p->pPrior = pPrior;
|
||||
pPrior->pNext = p;
|
||||
|
||||
/*** TBD: Insert subroutine calls to close cursors on incomplete
|
||||
**** subqueries ****/
|
||||
@@ -3144,7 +3131,7 @@ static int flattenSubquery(
|
||||
** and (14). */
|
||||
if( pSub->pLimit && p->pLimit ) return 0; /* Restriction (13) */
|
||||
if( pSub->pOffset ) return 0; /* Restriction (14) */
|
||||
if( p->pRightmost && pSub->pLimit ){
|
||||
if( (p->selFlags & SF_Compound)!=0 && pSub->pLimit ){
|
||||
return 0; /* Restriction (15) */
|
||||
}
|
||||
if( pSubSrc->nSrc==0 ) return 0; /* Restriction (7) */
|
||||
@@ -3295,14 +3282,14 @@ static int flattenSubquery(
|
||||
p->pOrderBy = pOrderBy;
|
||||
p->pSrc = pSrc;
|
||||
p->op = TK_ALL;
|
||||
p->pRightmost = 0;
|
||||
if( pNew==0 ){
|
||||
pNew = pPrior;
|
||||
p->pPrior = pPrior;
|
||||
}else{
|
||||
pNew->pPrior = pPrior;
|
||||
pNew->pRightmost = 0;
|
||||
if( pPrior ) pPrior->pNext = pNew;
|
||||
pNew->pNext = p;
|
||||
p->pPrior = pNew;
|
||||
}
|
||||
p->pPrior = pNew;
|
||||
if( db->mallocFailed ) return 1;
|
||||
}
|
||||
|
||||
@@ -3641,6 +3628,10 @@ static int convertCompoundSelectToSubquery(Walker *pWalker, Select *p){
|
||||
pNew->pHaving = 0;
|
||||
pNew->pOrderBy = 0;
|
||||
p->pPrior = 0;
|
||||
p->pNext = 0;
|
||||
p->selFlags &= ~SF_Compound;
|
||||
assert( pNew->pPrior!=0 );
|
||||
pNew->pPrior->pNext = pNew;
|
||||
pNew->pLimit = 0;
|
||||
pNew->pOffset = 0;
|
||||
return WRC_Continue;
|
||||
@@ -3828,9 +3819,10 @@ static int withExpand(
|
||||
*/
|
||||
static void selectPopWith(Walker *pWalker, Select *p){
|
||||
Parse *pParse = pWalker->pParse;
|
||||
if( p->pWith ){
|
||||
assert( pParse->pWith==p->pWith );
|
||||
pParse->pWith = p->pWith->pOuter;
|
||||
With *pWith = findRightmost(p)->pWith;
|
||||
if( pWith!=0 ){
|
||||
assert( pParse->pWith==pWith );
|
||||
pParse->pWith = pWith->pOuter;
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -3880,7 +3872,7 @@ static int selectExpander(Walker *pWalker, Select *p){
|
||||
}
|
||||
pTabList = p->pSrc;
|
||||
pEList = p->pEList;
|
||||
sqlite3WithPush(pParse, p->pWith, 0);
|
||||
sqlite3WithPush(pParse, findRightmost(p)->pWith, 0);
|
||||
|
||||
/* Make sure cursor numbers have been assigned to all entries in
|
||||
** the FROM clause of the SELECT statement.
|
||||
@@ -4302,7 +4294,7 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
||||
pFunc->iDistinct = -1;
|
||||
}else{
|
||||
KeyInfo *pKeyInfo = keyInfoFromExprList(pParse, pE->x.pList, 0);
|
||||
sqlite3VdbeAddOp4(v, OP_OpenHash, pFunc->iDistinct, 0, 0,
|
||||
sqlite3VdbeAddOp4(v, OP_OpenEphemeral, pFunc->iDistinct, 0, 0,
|
||||
(char*)pKeyInfo, P4_KEYINFO);
|
||||
}
|
||||
}
|
||||
@@ -4558,36 +4550,18 @@ int sqlite3Select(
|
||||
/* Implement a co-routine that will return a single row of the result
|
||||
** set on each invocation.
|
||||
*/
|
||||
int addrTop;
|
||||
int addrEof;
|
||||
int addrTop = sqlite3VdbeCurrentAddr(v)+1;
|
||||
pItem->regReturn = ++pParse->nMem;
|
||||
addrEof = ++pParse->nMem;
|
||||
/* Before coding the OP_Goto to jump to the start of the main routine,
|
||||
** ensure that the jump to the verify-schema routine has already
|
||||
** been coded. Otherwise, the verify-schema would likely be coded as
|
||||
** part of the co-routine. If the main routine then accessed the
|
||||
** database before invoking the co-routine for the first time (for
|
||||
** example to initialize a LIMIT register from a sub-select), it would
|
||||
** be doing so without having verified the schema version and obtained
|
||||
** the required db locks. See ticket d6b36be38. */
|
||||
sqlite3CodeVerifySchema(pParse, -1);
|
||||
sqlite3VdbeAddOp0(v, OP_Goto);
|
||||
addrTop = sqlite3VdbeAddOp1(v, OP_OpenPseudo, pItem->iCursor);
|
||||
sqlite3VdbeChangeP5(v, 1);
|
||||
VdbeComment((v, "coroutine for %s", pItem->pTab->zName));
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop);
|
||||
VdbeComment((v, "%s", pItem->pTab->zName));
|
||||
pItem->addrFillSub = addrTop;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 0, addrEof);
|
||||
sqlite3VdbeChangeP5(v, 1);
|
||||
sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn);
|
||||
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
||||
sqlite3Select(pParse, pSub, &dest);
|
||||
pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
|
||||
pItem->viaCoroutine = 1;
|
||||
sqlite3VdbeChangeP2(v, addrTop, dest.iSdst);
|
||||
sqlite3VdbeChangeP3(v, addrTop, dest.nSdst);
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, 1, addrEof);
|
||||
sqlite3VdbeAddOp1(v, OP_Yield, pItem->regReturn);
|
||||
VdbeComment((v, "end %s", pItem->pTab->zName));
|
||||
pItem->regResult = dest.iSdst;
|
||||
sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn);
|
||||
sqlite3VdbeJumpHere(v, addrTop-1);
|
||||
sqlite3ClearTempRegCache(pParse);
|
||||
}else{
|
||||
@@ -4603,12 +4577,14 @@ int sqlite3Select(
|
||||
pItem->regReturn = ++pParse->nMem;
|
||||
topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn);
|
||||
pItem->addrFillSub = topAddr+1;
|
||||
VdbeNoopComment((v, "materialize %s", pItem->pTab->zName));
|
||||
if( pItem->isCorrelated==0 ){
|
||||
/* If the subquery is not correlated and if we are not inside of
|
||||
** a trigger, then we only need to compute the value of the subquery
|
||||
** once. */
|
||||
onceAddr = sqlite3CodeOnce(pParse);
|
||||
VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName));
|
||||
}else{
|
||||
VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName));
|
||||
}
|
||||
sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
|
||||
explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
|
||||
@@ -4640,21 +4616,6 @@ int sqlite3Select(
|
||||
/* If there is are a sequence of queries, do the earlier ones first.
|
||||
*/
|
||||
if( p->pPrior ){
|
||||
if( p->pRightmost==0 ){
|
||||
Select *pLoop, *pRight = 0;
|
||||
int cnt = 0;
|
||||
int mxSelect;
|
||||
for(pLoop=p; pLoop; pLoop=pLoop->pPrior, cnt++){
|
||||
pLoop->pRightmost = p;
|
||||
pLoop->pNext = pRight;
|
||||
pRight = pLoop;
|
||||
}
|
||||
mxSelect = db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT];
|
||||
if( mxSelect && cnt>mxSelect ){
|
||||
sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
|
||||
goto select_end;
|
||||
}
|
||||
}
|
||||
rc = multiSelect(pParse, p, pDest);
|
||||
explainSetInteger(pParse->iSelectId, iRestoreSelectId);
|
||||
return rc;
|
||||
@@ -4721,8 +4682,6 @@ int sqlite3Select(
|
||||
}
|
||||
|
||||
/* If the output is destined for a temporary table, open that table.
|
||||
** Use OP_OpenEphemeral rather than OP_OpenHash to keep the rows in
|
||||
** their original order.
|
||||
*/
|
||||
if( pDest->eDest==SRT_EphemTab ){
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iSDParm, pEList->nExpr);
|
||||
@@ -4742,10 +4701,11 @@ int sqlite3Select(
|
||||
*/
|
||||
if( p->selFlags & SF_Distinct ){
|
||||
sDistinct.tabTnct = pParse->nTab++;
|
||||
sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenHash,
|
||||
sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
|
||||
sDistinct.tabTnct, 0, 0,
|
||||
(char*)keyInfoFromExprList(pParse, p->pEList, 0),
|
||||
P4_KEYINFO);
|
||||
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
|
||||
sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED;
|
||||
}else{
|
||||
sDistinct.eTnctType = WHERE_DISTINCT_NOOP;
|
||||
@@ -5317,10 +5277,6 @@ void sqlite3ExplainSelect(Vdbe *pVdbe, Select *p){
|
||||
sqlite3ExplainPrintf(pVdbe, "(null-select)");
|
||||
return;
|
||||
}
|
||||
while( p->pPrior ){
|
||||
p->pPrior->pNext = p;
|
||||
p = p->pPrior;
|
||||
}
|
||||
sqlite3ExplainPush(pVdbe);
|
||||
while( p ){
|
||||
explainOneSelect(pVdbe, p);
|
||||
|
||||
+261
-10
@@ -45,14 +45,17 @@
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_EDITLINE
|
||||
# include <editline/editline.h>
|
||||
#endif
|
||||
#if defined(HAVE_READLINE) && HAVE_READLINE==1
|
||||
#if defined(HAVE_READLINE) && HAVE_READLINE!=0
|
||||
# include <readline/readline.h>
|
||||
# include <readline/history.h>
|
||||
#else
|
||||
# undef HAVE_READLINE
|
||||
#endif
|
||||
#if !defined(HAVE_EDITLINE) && (!defined(HAVE_READLINE) || HAVE_READLINE!=1)
|
||||
#if defined(HAVE_EDITLINE) && !defined(HAVE_READLINE)
|
||||
# define HAVE_READLINE 1
|
||||
# include <editline/readline.h>
|
||||
#endif
|
||||
#if !defined(HAVE_READLINE)
|
||||
# define add_history(X)
|
||||
# define read_history(X)
|
||||
# define write_history(X)
|
||||
@@ -413,7 +416,7 @@ static char *one_input_line(FILE *in, char *zPrior, int isContinuation){
|
||||
zResult = local_getline(zPrior, in);
|
||||
}else{
|
||||
zPrompt = isContinuation ? continuePrompt : mainPrompt;
|
||||
#if defined(HAVE_READLINE) && HAVE_READLINE==1
|
||||
#if defined(HAVE_READLINE)
|
||||
free(zPrior);
|
||||
zResult = readline(zPrompt);
|
||||
if( zResult && *zResult ) add_history(zResult);
|
||||
@@ -1543,6 +1546,7 @@ static int run_schema_dump_query(
|
||||
static char zHelp[] =
|
||||
".backup ?DB? FILE Backup DB (default \"main\") to FILE\n"
|
||||
".bail ON|OFF Stop after hitting an error. Default OFF\n"
|
||||
".clone NEWDB Clone data into NEWDB from the existing database\n"
|
||||
".databases List names and files of attached databases\n"
|
||||
".dump ?TABLE? ... Dump the database in an SQL text format\n"
|
||||
" If TABLE specified, only dump tables matching\n"
|
||||
@@ -1582,6 +1586,7 @@ static char zHelp[] =
|
||||
".quit Exit this program\n"
|
||||
".read FILENAME Execute SQL in FILENAME\n"
|
||||
".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n"
|
||||
".save FILE Write in-memory database into FILE\n"
|
||||
".schema ?TABLE? Show the CREATE statements\n"
|
||||
" If TABLE specified, only show tables matching\n"
|
||||
" LIKE pattern TABLE.\n"
|
||||
@@ -1896,6 +1901,219 @@ static char *csv_read_one_field(CSVReader *p){
|
||||
return p->z;
|
||||
}
|
||||
|
||||
/*
|
||||
** Try to transfer data for table zTable. If an error is seen while
|
||||
** moving forward, try to go backwards. The backwards movement won't
|
||||
** work for WITHOUT ROWID tables.
|
||||
*/
|
||||
static void tryToCloneData(
|
||||
struct callback_data *p,
|
||||
sqlite3 *newDb,
|
||||
const char *zTable
|
||||
){
|
||||
sqlite3_stmt *pQuery = 0;
|
||||
sqlite3_stmt *pInsert = 0;
|
||||
char *zQuery = 0;
|
||||
char *zInsert = 0;
|
||||
int rc;
|
||||
int i, j, n;
|
||||
int nTable = (int)strlen(zTable);
|
||||
int k = 0;
|
||||
int cnt = 0;
|
||||
const int spinRate = 10000;
|
||||
|
||||
zQuery = sqlite3_mprintf("SELECT * FROM \"%w\"", zTable);
|
||||
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Error %d: %s on [%s]\n",
|
||||
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
|
||||
zQuery);
|
||||
goto end_data_xfer;
|
||||
}
|
||||
n = sqlite3_column_count(pQuery);
|
||||
zInsert = sqlite3_malloc(200 + nTable + n*3);
|
||||
if( zInsert==0 ){
|
||||
fprintf(stderr, "out of memory\n");
|
||||
goto end_data_xfer;
|
||||
}
|
||||
sqlite3_snprintf(200+nTable,zInsert,
|
||||
"INSERT OR IGNORE INTO \"%s\" VALUES(?", zTable);
|
||||
i = (int)strlen(zInsert);
|
||||
for(j=1; j<n; j++){
|
||||
memcpy(zInsert+i, ",?", 2);
|
||||
i += 2;
|
||||
}
|
||||
memcpy(zInsert+i, ");", 3);
|
||||
rc = sqlite3_prepare_v2(newDb, zInsert, -1, &pInsert, 0);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Error %d: %s on [%s]\n",
|
||||
sqlite3_extended_errcode(newDb), sqlite3_errmsg(newDb),
|
||||
zQuery);
|
||||
goto end_data_xfer;
|
||||
}
|
||||
for(k=0; k<2; k++){
|
||||
while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
|
||||
for(i=0; i<n; i++){
|
||||
switch( sqlite3_column_type(pQuery, i) ){
|
||||
case SQLITE_NULL: {
|
||||
sqlite3_bind_null(pInsert, i+1);
|
||||
break;
|
||||
}
|
||||
case SQLITE_INTEGER: {
|
||||
sqlite3_bind_int64(pInsert, i+1, sqlite3_column_int64(pQuery,i));
|
||||
break;
|
||||
}
|
||||
case SQLITE_FLOAT: {
|
||||
sqlite3_bind_double(pInsert, i+1, sqlite3_column_double(pQuery,i));
|
||||
break;
|
||||
}
|
||||
case SQLITE_TEXT: {
|
||||
sqlite3_bind_text(pInsert, i+1,
|
||||
(const char*)sqlite3_column_text(pQuery,i),
|
||||
-1, SQLITE_STATIC);
|
||||
break;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
sqlite3_bind_blob(pInsert, i+1, sqlite3_column_blob(pQuery,i),
|
||||
sqlite3_column_bytes(pQuery,i),
|
||||
SQLITE_STATIC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} /* End for */
|
||||
rc = sqlite3_step(pInsert);
|
||||
if( rc!=SQLITE_OK && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){
|
||||
fprintf(stderr, "Error %d: %s\n", sqlite3_extended_errcode(newDb),
|
||||
sqlite3_errmsg(newDb));
|
||||
}
|
||||
sqlite3_reset(pInsert);
|
||||
cnt++;
|
||||
if( (cnt%spinRate)==0 ){
|
||||
printf("%c\b", "|/-\\"[(cnt/spinRate)%4]);
|
||||
fflush(stdout);
|
||||
}
|
||||
} /* End while */
|
||||
if( rc==SQLITE_DONE ) break;
|
||||
sqlite3_finalize(pQuery);
|
||||
sqlite3_free(zQuery);
|
||||
zQuery = sqlite3_mprintf("SELECT * FROM \"%w\" ORDER BY rowid DESC;",
|
||||
zTable);
|
||||
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Warning: cannot step \"%s\" backwards", zTable);
|
||||
break;
|
||||
}
|
||||
} /* End for(k=0...) */
|
||||
|
||||
end_data_xfer:
|
||||
sqlite3_finalize(pQuery);
|
||||
sqlite3_finalize(pInsert);
|
||||
sqlite3_free(zQuery);
|
||||
sqlite3_free(zInsert);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Try to transfer all rows of the schema that match zWhere. For
|
||||
** each row, invoke xForEach() on the object defined by that row.
|
||||
** If an error is encountered while moving forward through the
|
||||
** sqlite_master table, try again moving backwards.
|
||||
*/
|
||||
static void tryToCloneSchema(
|
||||
struct callback_data *p,
|
||||
sqlite3 *newDb,
|
||||
const char *zWhere,
|
||||
void (*xForEach)(struct callback_data*,sqlite3*,const char*)
|
||||
){
|
||||
sqlite3_stmt *pQuery = 0;
|
||||
char *zQuery = 0;
|
||||
int rc;
|
||||
const unsigned char *zName;
|
||||
const unsigned char *zSql;
|
||||
char *zErrMsg = 0;
|
||||
|
||||
zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
|
||||
" WHERE %s", zWhere);
|
||||
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Error: (%d) %s on [%s]\n",
|
||||
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
|
||||
zQuery);
|
||||
goto end_schema_xfer;
|
||||
}
|
||||
while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
|
||||
zName = sqlite3_column_text(pQuery, 0);
|
||||
zSql = sqlite3_column_text(pQuery, 1);
|
||||
printf("%s... ", zName); fflush(stdout);
|
||||
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
|
||||
if( zErrMsg ){
|
||||
fprintf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
|
||||
sqlite3_free(zErrMsg);
|
||||
zErrMsg = 0;
|
||||
}
|
||||
if( xForEach ){
|
||||
xForEach(p, newDb, (const char*)zName);
|
||||
}
|
||||
printf("done\n");
|
||||
}
|
||||
if( rc!=SQLITE_DONE ){
|
||||
sqlite3_finalize(pQuery);
|
||||
sqlite3_free(zQuery);
|
||||
zQuery = sqlite3_mprintf("SELECT name, sql FROM sqlite_master"
|
||||
" WHERE %s ORDER BY rowid DESC", zWhere);
|
||||
rc = sqlite3_prepare_v2(p->db, zQuery, -1, &pQuery, 0);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Error: (%d) %s on [%s]\n",
|
||||
sqlite3_extended_errcode(p->db), sqlite3_errmsg(p->db),
|
||||
zQuery);
|
||||
goto end_schema_xfer;
|
||||
}
|
||||
while( (rc = sqlite3_step(pQuery))==SQLITE_ROW ){
|
||||
zName = sqlite3_column_text(pQuery, 0);
|
||||
zSql = sqlite3_column_text(pQuery, 1);
|
||||
printf("%s... ", zName); fflush(stdout);
|
||||
sqlite3_exec(newDb, (const char*)zSql, 0, 0, &zErrMsg);
|
||||
if( zErrMsg ){
|
||||
fprintf(stderr, "Error: %s\nSQL: [%s]\n", zErrMsg, zSql);
|
||||
sqlite3_free(zErrMsg);
|
||||
zErrMsg = 0;
|
||||
}
|
||||
if( xForEach ){
|
||||
xForEach(p, newDb, (const char*)zName);
|
||||
}
|
||||
printf("done\n");
|
||||
}
|
||||
}
|
||||
end_schema_xfer:
|
||||
sqlite3_finalize(pQuery);
|
||||
sqlite3_free(zQuery);
|
||||
}
|
||||
|
||||
/*
|
||||
** Open a new database file named "zNewDb". Try to recover as much information
|
||||
** as possible out of the main database (which might be corrupt) and write it
|
||||
** into zNewDb.
|
||||
*/
|
||||
static void tryToClone(struct callback_data *p, const char *zNewDb){
|
||||
int rc;
|
||||
sqlite3 *newDb = 0;
|
||||
if( access(zNewDb,0)==0 ){
|
||||
fprintf(stderr, "File \"%s\" already exists.\n", zNewDb);
|
||||
return;
|
||||
}
|
||||
rc = sqlite3_open(zNewDb, &newDb);
|
||||
if( rc ){
|
||||
fprintf(stderr, "Cannot create output database: %s\n",
|
||||
sqlite3_errmsg(newDb));
|
||||
}else{
|
||||
sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0);
|
||||
tryToCloneSchema(p, newDb, "type='table'", tryToCloneData);
|
||||
tryToCloneSchema(p, newDb, "type!='table'", 0);
|
||||
sqlite3_exec(newDb, "COMMIT;", 0, 0, 0);
|
||||
}
|
||||
sqlite3_close(newDb);
|
||||
}
|
||||
|
||||
/*
|
||||
** If an input line begins with "." then invoke this routine to
|
||||
** process that line.
|
||||
@@ -1938,7 +2156,9 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
if( nArg==0 ) return 0; /* no tokens, no error */
|
||||
n = strlen30(azArg[0]);
|
||||
c = azArg[0][0];
|
||||
if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 ){
|
||||
if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0)
|
||||
|| (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0)
|
||||
){
|
||||
const char *zDestFile = 0;
|
||||
const char *zDb = 0;
|
||||
sqlite3 *pDest;
|
||||
@@ -2003,6 +2223,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
test_breakpoint();
|
||||
}else
|
||||
|
||||
if( c=='c' && strncmp(azArg[0], "clone", n)==0 && nArg>1 && nArg<3 ){
|
||||
tryToClone(p, azArg[1]);
|
||||
}else
|
||||
|
||||
if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){
|
||||
struct callback_data data;
|
||||
char *zErrMsg = 0;
|
||||
@@ -3282,6 +3506,26 @@ static void main_init(struct callback_data *data) {
|
||||
sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
|
||||
}
|
||||
|
||||
/*
|
||||
** Output text to the console in a font that attracts extra attention.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
static void printBold(const char *zText){
|
||||
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
CONSOLE_SCREEN_BUFFER_INFO defaultScreenInfo;
|
||||
GetConsoleScreenBufferInfo(out, &defaultScreenInfo);
|
||||
SetConsoleTextAttribute(out,
|
||||
FOREGROUND_RED|FOREGROUND_INTENSITY
|
||||
);
|
||||
printf("%s", zText);
|
||||
SetConsoleTextAttribute(out, defaultScreenInfo.wAttributes);
|
||||
}
|
||||
#else
|
||||
static void printBold(const char *zText){
|
||||
printf("\033[1m%s\033[0m", zText);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Get the argument to an --option. Throw an error and die if no argument
|
||||
** is available.
|
||||
@@ -3302,6 +3546,7 @@ int main(int argc, char **argv){
|
||||
char *zFirstCmd = 0;
|
||||
int i;
|
||||
int rc = 0;
|
||||
int warnInmemoryDb = 0;
|
||||
|
||||
if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){
|
||||
fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
|
||||
@@ -3396,6 +3641,7 @@ int main(int argc, char **argv){
|
||||
if( data.zDbFilename==0 ){
|
||||
#ifndef SQLITE_OMIT_MEMORYDB
|
||||
data.zDbFilename = ":memory:";
|
||||
warnInmemoryDb = argc==1;
|
||||
#else
|
||||
fprintf(stderr,"%s: Error: no database filename specified\n", Argv0);
|
||||
return 1;
|
||||
@@ -3532,10 +3778,15 @@ int main(int argc, char **argv){
|
||||
int nHistory;
|
||||
printf(
|
||||
"SQLite version %s %.19s\n" /*extra-version-info*/
|
||||
"Enter \".help\" for instructions\n"
|
||||
"Enter SQL statements terminated with a \";\"\n",
|
||||
"Enter \".help\" for usage hints.\n",
|
||||
sqlite3_libversion(), sqlite3_sourceid()
|
||||
);
|
||||
if( warnInmemoryDb ){
|
||||
printf("Connected to a ");
|
||||
printBold("transient in-memory database.");
|
||||
printf("\nUse \".open FILENAME\" to reopen on a "
|
||||
"persistent database.\n");
|
||||
}
|
||||
zHome = find_home_dir();
|
||||
if( zHome ){
|
||||
nHistory = strlen30(zHome) + 20;
|
||||
@@ -3543,7 +3794,7 @@ int main(int argc, char **argv){
|
||||
sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
|
||||
}
|
||||
}
|
||||
#if defined(HAVE_READLINE) && HAVE_READLINE==1
|
||||
#if defined(HAVE_READLINE)
|
||||
if( zHistory ) read_history(zHistory);
|
||||
#endif
|
||||
rc = process_input(&data, 0);
|
||||
|
||||
+11
-5
@@ -33,6 +33,11 @@
|
||||
** in Red Hat 6.0, so the code won't work. Hence, for maximum binary
|
||||
** portability you should omit LFS.
|
||||
**
|
||||
** The previous paragraph was written in 2005. (This paragraph is written
|
||||
** on 2008-11-28.) These days, all Linux kernels support large files, so
|
||||
** you should probably leave LFS enabled. But some embedded platforms might
|
||||
** lack LFS in which case the SQLITE_DISABLE_LFS macro might still be useful.
|
||||
**
|
||||
** Similar is true for Mac OS X. LFS is only supported on Mac OS X 9 and later.
|
||||
*/
|
||||
#ifndef SQLITE_DISABLE_LFS
|
||||
@@ -1083,8 +1088,7 @@ struct sqlite3 {
|
||||
** Return true if it OK to factor constant expressions into the initialization
|
||||
** code. The argument is a Parse object for the code generator.
|
||||
*/
|
||||
#define ConstFactorOk(P) \
|
||||
((P)->cookieGoto>0 && OptimizationEnabled((P)->db,SQLITE_FactorOutConst))
|
||||
#define ConstFactorOk(P) ((P)->okConstFactor)
|
||||
|
||||
/*
|
||||
** Possible values for the sqlite.magic field.
|
||||
@@ -2015,6 +2019,7 @@ struct SrcList {
|
||||
Select *pSelect; /* A SELECT statement used in place of a table name */
|
||||
int addrFillSub; /* Address of subroutine to manifest a subquery */
|
||||
int regReturn; /* Register holding return address of addrFillSub */
|
||||
int regResult; /* Registers holding results of a co-routine */
|
||||
u8 jointype; /* Type of join between this able and the previous */
|
||||
unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */
|
||||
unsigned isCorrelated :1; /* True if sub-query is correlated */
|
||||
@@ -2143,7 +2148,6 @@ struct Select {
|
||||
ExprList *pOrderBy; /* The ORDER BY clause */
|
||||
Select *pPrior; /* Prior select in a compound select statement */
|
||||
Select *pNext; /* Next select to the left in a compound */
|
||||
Select *pRightmost; /* Right-most select in a compound select statement */
|
||||
Expr *pLimit; /* LIMIT expression. NULL means not used. */
|
||||
Expr *pOffset; /* OFFSET expression. NULL means not used. */
|
||||
With *pWith; /* WITH clause attached to this select. Or NULL. */
|
||||
@@ -2165,6 +2169,7 @@ struct Select {
|
||||
#define SF_NestedFrom 0x0200 /* Part of a parenthesized FROM clause */
|
||||
#define SF_MaybeConvert 0x0400 /* Need convertCompoundSelectToSubquery() */
|
||||
#define SF_Recursive 0x0800 /* The recursive part of a recursive CTE */
|
||||
#define SF_Compound 0x1000 /* Part of a compound query */
|
||||
|
||||
|
||||
/*
|
||||
@@ -2349,6 +2354,7 @@ struct Parse {
|
||||
u8 isMultiWrite; /* True if statement may modify/insert multiple rows */
|
||||
u8 mayAbort; /* True if statement may throw an ABORT exception */
|
||||
u8 hasCompound; /* Need to invoke convertCompoundSelectToSubquery() */
|
||||
u8 okConstFactor; /* OK to factor out constants */
|
||||
int aTempReg[8]; /* Holding area for temporary registers */
|
||||
int nRangeReg; /* Size of the temporary register block */
|
||||
int iRangeReg; /* First register in temporary register block */
|
||||
@@ -2377,7 +2383,6 @@ struct Parse {
|
||||
Token constraintName;/* Name of the constraint currently being parsed */
|
||||
yDbMask writeMask; /* Start a write transaction on these databases */
|
||||
yDbMask cookieMask; /* Bitmask of schema verified databases */
|
||||
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
|
||||
int cookieValue[SQLITE_MAX_ATTACHED+2]; /* Values of cookies to verify */
|
||||
int regRowid; /* Register holding rowid of CREATE TABLE entry */
|
||||
int regRoot; /* Register holding root page number for new objects */
|
||||
@@ -3283,6 +3288,7 @@ void sqlite3AlterRenameTable(Parse*, SrcList*, Token*);
|
||||
int sqlite3GetToken(const unsigned char *, int *);
|
||||
void sqlite3NestedParse(Parse*, const char*, ...);
|
||||
void sqlite3ExpirePreparedStatements(sqlite3*);
|
||||
int sqlite3CodeSubselect(Parse *, Expr *, int, int);
|
||||
void sqlite3SelectPrep(Parse*, Select*, NameContext*);
|
||||
int sqlite3MatchSpanName(const char*, const char*, const char*, const char*);
|
||||
int sqlite3ResolveExprNames(NameContext*, Expr*);
|
||||
@@ -3478,7 +3484,7 @@ const char *sqlite3JournalModename(int);
|
||||
#define IN_INDEX_EPH 2
|
||||
#define IN_INDEX_INDEX_ASC 3
|
||||
#define IN_INDEX_INDEX_DESC 4
|
||||
int sqlite3FindInIndex(Parse *, Expr *, int*, int);
|
||||
int sqlite3FindInIndex(Parse *, Expr *, int*);
|
||||
|
||||
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
||||
int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
|
||||
|
||||
+37
-32
@@ -1025,7 +1025,7 @@ static int DbTransPostCmd(
|
||||
** this method's logic. Not clear how this would be best handled.
|
||||
*/
|
||||
if( rc!=TCL_ERROR ){
|
||||
Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0);
|
||||
Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0);
|
||||
rc = TCL_ERROR;
|
||||
}
|
||||
sqlite3_exec(pDb->db, "ROLLBACK", 0, 0, 0);
|
||||
@@ -1675,7 +1675,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
*/
|
||||
case DB_AUTHORIZER: {
|
||||
#ifdef SQLITE_OMIT_AUTHORIZATION
|
||||
Tcl_AppendResult(interp, "authorization not available in this build", 0);
|
||||
Tcl_AppendResult(interp, "authorization not available in this build",
|
||||
(char*)0);
|
||||
return TCL_ERROR;
|
||||
#else
|
||||
if( objc>3 ){
|
||||
@@ -1683,7 +1684,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
return TCL_ERROR;
|
||||
}else if( objc==2 ){
|
||||
if( pDb->zAuth ){
|
||||
Tcl_AppendResult(interp, pDb->zAuth, 0);
|
||||
Tcl_AppendResult(interp, pDb->zAuth, (char*)0);
|
||||
}
|
||||
}else{
|
||||
char *zAuth;
|
||||
@@ -1769,7 +1770,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
return TCL_ERROR;
|
||||
}else if( objc==2 ){
|
||||
if( pDb->zBusy ){
|
||||
Tcl_AppendResult(interp, pDb->zBusy, 0);
|
||||
Tcl_AppendResult(interp, pDb->zBusy, (char*)0);
|
||||
}
|
||||
}else{
|
||||
char *zBusy;
|
||||
@@ -1823,7 +1824,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
}else{
|
||||
if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){
|
||||
Tcl_AppendResult( interp, "cannot convert \"",
|
||||
Tcl_GetStringFromObj(objv[3],0), "\" to integer", 0);
|
||||
Tcl_GetStringFromObj(objv[3],0), "\" to integer", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}else{
|
||||
if( n<0 ){
|
||||
@@ -1837,7 +1838,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
}
|
||||
}else{
|
||||
Tcl_AppendResult( interp, "bad option \"",
|
||||
Tcl_GetStringFromObj(objv[2],0), "\": must be flush or size", 0);
|
||||
Tcl_GetStringFromObj(objv[2],0), "\": must be flush or size",
|
||||
(char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
break;
|
||||
@@ -1934,7 +1936,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
return TCL_ERROR;
|
||||
}else if( objc==2 ){
|
||||
if( pDb->zCommit ){
|
||||
Tcl_AppendResult(interp, pDb->zCommit, 0);
|
||||
Tcl_AppendResult(interp, pDb->zCommit, (char*)0);
|
||||
}
|
||||
}else{
|
||||
const char *zCommit;
|
||||
@@ -2039,7 +2041,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
nSep = strlen30(zSep);
|
||||
nNull = strlen30(zNull);
|
||||
if( nSep==0 ){
|
||||
Tcl_AppendResult(interp,"Error: non-null separator required for copy",0);
|
||||
Tcl_AppendResult(interp,"Error: non-null separator required for copy",
|
||||
(char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if(strcmp(zConflict, "rollback") != 0 &&
|
||||
@@ -2049,19 +2052,19 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
strcmp(zConflict, "replace" ) != 0 ) {
|
||||
Tcl_AppendResult(interp, "Error: \"", zConflict,
|
||||
"\", conflict-algorithm must be one of: rollback, "
|
||||
"abort, fail, ignore, or replace", 0);
|
||||
"abort, fail, ignore, or replace", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable);
|
||||
if( zSql==0 ){
|
||||
Tcl_AppendResult(interp, "Error: no such table: ", zTable, 0);
|
||||
Tcl_AppendResult(interp, "Error: no such table: ", zTable, (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
nByte = strlen30(zSql);
|
||||
rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
|
||||
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), (char*)0);
|
||||
nCol = 0;
|
||||
}else{
|
||||
nCol = sqlite3_column_count(pStmt);
|
||||
@@ -2072,7 +2075,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
}
|
||||
zSql = malloc( nByte + 50 + nCol*2 );
|
||||
if( zSql==0 ) {
|
||||
Tcl_AppendResult(interp, "Error: can't malloc()", 0);
|
||||
Tcl_AppendResult(interp, "Error: can't malloc()", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
sqlite3_snprintf(nByte+50, zSql, "INSERT OR %q INTO '%q' VALUES(?",
|
||||
@@ -2087,7 +2090,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0);
|
||||
free(zSql);
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
|
||||
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), (char*)0);
|
||||
sqlite3_finalize(pStmt);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
@@ -2099,7 +2102,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
}
|
||||
azCol = malloc( sizeof(azCol[0])*(nCol+1) );
|
||||
if( azCol==0 ) {
|
||||
Tcl_AppendResult(interp, "Error: can't malloc()", 0);
|
||||
Tcl_AppendResult(interp, "Error: can't malloc()", (char*)0);
|
||||
fclose(in);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
@@ -2127,7 +2130,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
sqlite3_snprintf(nErr, zErr,
|
||||
"Error: %s line %d: expected %d columns of data but found %d",
|
||||
zFile, lineno, nCol, i+1);
|
||||
Tcl_AppendResult(interp, zErr, 0);
|
||||
Tcl_AppendResult(interp, zErr, (char*)0);
|
||||
free(zErr);
|
||||
}
|
||||
zCommit = "ROLLBACK";
|
||||
@@ -2147,7 +2150,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
rc = sqlite3_reset(pStmt);
|
||||
free(zLine);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), 0);
|
||||
Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), (char*)0);
|
||||
zCommit = "ROLLBACK";
|
||||
break;
|
||||
}
|
||||
@@ -2165,7 +2168,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
}else{
|
||||
/* failure, append lineno where failed */
|
||||
sqlite3_snprintf(sizeof(zLineNum), zLineNum,"%d",lineno);
|
||||
Tcl_AppendResult(interp,", failed while processing line: ",zLineNum,0);
|
||||
Tcl_AppendResult(interp,", failed while processing line: ",zLineNum,
|
||||
(char*)0);
|
||||
rc = TCL_ERROR;
|
||||
}
|
||||
break;
|
||||
@@ -2191,7 +2195,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
break;
|
||||
#else
|
||||
Tcl_AppendResult(interp, "extension loading is turned off at compile-time",
|
||||
0);
|
||||
(char*)0);
|
||||
return TCL_ERROR;
|
||||
#endif
|
||||
}
|
||||
@@ -2349,7 +2353,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
*/
|
||||
case DB_INCRBLOB: {
|
||||
#ifdef SQLITE_OMIT_INCRBLOB
|
||||
Tcl_AppendResult(interp, "incrblob not available in this build", 0);
|
||||
Tcl_AppendResult(interp, "incrblob not available in this build", (char*)0);
|
||||
return TCL_ERROR;
|
||||
#else
|
||||
int isReadonly = 0;
|
||||
@@ -2456,7 +2460,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
case DB_PROGRESS: {
|
||||
if( objc==2 ){
|
||||
if( pDb->zProgress ){
|
||||
Tcl_AppendResult(interp, pDb->zProgress, 0);
|
||||
Tcl_AppendResult(interp, pDb->zProgress, (char*)0);
|
||||
}
|
||||
}else if( objc==4 ){
|
||||
char *zProgress;
|
||||
@@ -2502,7 +2506,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
return TCL_ERROR;
|
||||
}else if( objc==2 ){
|
||||
if( pDb->zProfile ){
|
||||
Tcl_AppendResult(interp, pDb->zProfile, 0);
|
||||
Tcl_AppendResult(interp, pDb->zProfile, (char*)0);
|
||||
}
|
||||
}else{
|
||||
char *zProfile;
|
||||
@@ -2547,7 +2551,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey);
|
||||
rc = sqlite3_rekey(pDb->db, pKey, nKey);
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, sqlite3_errstr(rc), 0);
|
||||
Tcl_AppendResult(interp, sqlite3_errstr(rc), (char*)0);
|
||||
rc = TCL_ERROR;
|
||||
}
|
||||
#endif
|
||||
@@ -2688,7 +2692,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
return TCL_ERROR;
|
||||
}else if( objc==2 ){
|
||||
if( pDb->zTrace ){
|
||||
Tcl_AppendResult(interp, pDb->zTrace, 0);
|
||||
Tcl_AppendResult(interp, pDb->zTrace, (char*)0);
|
||||
}
|
||||
}else{
|
||||
char *zTrace;
|
||||
@@ -2759,7 +2763,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
rc = sqlite3_exec(pDb->db, zBegin, 0, 0, 0);
|
||||
pDb->disableAuth--;
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0);
|
||||
Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pDb->nTransaction++;
|
||||
@@ -2783,7 +2787,8 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
*/
|
||||
case DB_UNLOCK_NOTIFY: {
|
||||
#ifndef SQLITE_ENABLE_UNLOCK_NOTIFY
|
||||
Tcl_AppendResult(interp, "unlock_notify not available in this build", 0);
|
||||
Tcl_AppendResult(interp, "unlock_notify not available in this build",
|
||||
(char*)0);
|
||||
rc = TCL_ERROR;
|
||||
#else
|
||||
if( objc!=2 && objc!=3 ){
|
||||
@@ -2806,7 +2811,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
}
|
||||
|
||||
if( sqlite3_unlock_notify(pDb->db, xNotify, pNotifyArg) ){
|
||||
Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0);
|
||||
Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0);
|
||||
rc = TCL_ERROR;
|
||||
}
|
||||
}
|
||||
@@ -2935,14 +2940,14 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
if( objc==2 ){
|
||||
zArg = Tcl_GetStringFromObj(objv[1], 0);
|
||||
if( strcmp(zArg,"-version")==0 ){
|
||||
Tcl_AppendResult(interp,sqlite3_libversion(),0);
|
||||
Tcl_AppendResult(interp,sqlite3_libversion(), (char*)0);
|
||||
return TCL_OK;
|
||||
}
|
||||
if( strcmp(zArg,"-has-codec")==0 ){
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
Tcl_AppendResult(interp,"1",0);
|
||||
Tcl_AppendResult(interp,"1",(char*)0);
|
||||
#else
|
||||
Tcl_AppendResult(interp,"0",0);
|
||||
Tcl_AppendResult(interp,"0",(char*)0);
|
||||
#endif
|
||||
return TCL_OK;
|
||||
}
|
||||
@@ -3424,7 +3429,7 @@ static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){
|
||||
|
||||
if( argc!=2 ){
|
||||
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
||||
" TEXT\"", 0);
|
||||
" TEXT\"", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
MD5Init(&ctx);
|
||||
@@ -3449,13 +3454,13 @@ static int md5file_cmd(void*cd, Tcl_Interp*interp, int argc, const char **argv){
|
||||
|
||||
if( argc!=2 ){
|
||||
Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
|
||||
" FILENAME\"", 0);
|
||||
" FILENAME\"", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
in = fopen(argv[1],"rb");
|
||||
if( in==0 ){
|
||||
Tcl_AppendResult(interp,"unable to open file \"", argv[1],
|
||||
"\" for reading", 0);
|
||||
"\" for reading", (char*)0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
MD5Init(&ctx);
|
||||
|
||||
@@ -534,7 +534,10 @@ static int fake_big_file(
|
||||
}
|
||||
offset = n;
|
||||
offset *= 1024*1024;
|
||||
sqlite3OsLock(fd, SHARED_LOCK);
|
||||
sqlite3OsLock(fd, EXCLUSIVE_LOCK);
|
||||
rc = sqlite3OsWrite(fd, "Hello, World!", 14, offset);
|
||||
sqlite3OsUnlock(fd, NO_LOCK);
|
||||
sqlite3OsCloseFree(fd);
|
||||
sqlite3_free(zFile);
|
||||
if( rc ){
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ static int test_value_overhead(
|
||||
|
||||
val.flags = MEM_Str|MEM_Term|MEM_Static;
|
||||
val.z = "hello world";
|
||||
val.type = SQLITE_TEXT;
|
||||
val.memType = MEM_Str;
|
||||
val.enc = SQLITE_UTF8;
|
||||
|
||||
for(i=0; i<repeat_count; i++){
|
||||
|
||||
+1
-9
@@ -726,15 +726,7 @@ static int codeTriggerProgram(
|
||||
** INSERT OR IGNORE INTO t1 ... ; -- insert into t2 uses IGNORE policy
|
||||
*/
|
||||
pParse->eOrconf = (orconf==OE_Default)?pStep->orconf:(u8)orconf;
|
||||
|
||||
/* Clear the cookieGoto flag. When coding triggers, the cookieGoto
|
||||
** variable is used as a flag to indicate to sqlite3ExprCodeConstants()
|
||||
** that it is not safe to refactor constants (this happens after the
|
||||
** start of the first loop in the SQL statement is coded - at that
|
||||
** point code may be conditionally executed, so it is no longer safe to
|
||||
** initialize constant register values). */
|
||||
assert( pParse->cookieGoto==0 || pParse->cookieGoto==-1 );
|
||||
pParse->cookieGoto = 0;
|
||||
assert( pParse->okConstFactor==0 );
|
||||
|
||||
switch( pStep->op ){
|
||||
case TK_UPDATE: {
|
||||
|
||||
+2
-1
@@ -735,7 +735,8 @@ static void updateVirtualTable(
|
||||
*/
|
||||
assert( v );
|
||||
ephemTab = pParse->nTab++;
|
||||
sqlite3VdbeAddOp2(v, OP_OpenHash, ephemTab, pTab->nCol+1+(pRowid!=0));
|
||||
sqlite3VdbeAddOp2(v, OP_OpenEphemeral, ephemTab, pTab->nCol+1+(pRowid!=0));
|
||||
sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
|
||||
|
||||
/* fill the ephemeral table
|
||||
*/
|
||||
|
||||
+13
-5
@@ -1123,13 +1123,12 @@ int sqlite3AddInt64(i64 *pA, i64 iB){
|
||||
testcase( iA>0 && LARGEST_INT64 - iA == iB );
|
||||
testcase( iA>0 && LARGEST_INT64 - iA == iB - 1 );
|
||||
if( iA>0 && LARGEST_INT64 - iA < iB ) return 1;
|
||||
*pA += iB;
|
||||
}else{
|
||||
testcase( iA<0 && -(iA + LARGEST_INT64) == iB + 1 );
|
||||
testcase( iA<0 && -(iA + LARGEST_INT64) == iB + 2 );
|
||||
if( iA<0 && -(iA + LARGEST_INT64) > iB + 1 ) return 1;
|
||||
*pA += iB;
|
||||
}
|
||||
*pA += iB;
|
||||
return 0;
|
||||
}
|
||||
int sqlite3SubInt64(i64 *pA, i64 iB){
|
||||
@@ -1153,9 +1152,18 @@ int sqlite3MulInt64(i64 *pA, i64 iB){
|
||||
iA0 = iA % TWOPOWER32;
|
||||
iB1 = iB/TWOPOWER32;
|
||||
iB0 = iB % TWOPOWER32;
|
||||
if( iA1*iB1 != 0 ) return 1;
|
||||
assert( iA1*iB0==0 || iA0*iB1==0 );
|
||||
r = iA1*iB0 + iA0*iB1;
|
||||
if( iA1==0 ){
|
||||
if( iB1==0 ){
|
||||
*pA *= iB;
|
||||
return 0;
|
||||
}
|
||||
r = iA0*iB1;
|
||||
}else if( iB1==0 ){
|
||||
r = iA1*iB0;
|
||||
}else{
|
||||
/* If both iA1 and iB1 are non-zero, overflow will result */
|
||||
return 1;
|
||||
}
|
||||
testcase( r==(-TWOPOWER31)-1 );
|
||||
testcase( r==(-TWOPOWER31) );
|
||||
testcase( r==TWOPOWER31 );
|
||||
|
||||
+197
-244
@@ -9,33 +9,8 @@
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** The code in this file implements execution method of the
|
||||
** Virtual Database Engine (VDBE). A separate file ("vdbeaux.c")
|
||||
** handles housekeeping details such as creating and deleting
|
||||
** VDBE instances. This file is solely interested in executing
|
||||
** the VDBE program.
|
||||
**
|
||||
** In the external interface, an "sqlite3_stmt*" is an opaque pointer
|
||||
** to a VDBE.
|
||||
**
|
||||
** The SQL parser generates a program which is then executed by
|
||||
** the VDBE to do the work of the SQL statement. VDBE programs are
|
||||
** similar in form to assembly language. The program consists of
|
||||
** a linear sequence of operations. Each operation has an opcode
|
||||
** and 5 operands. Operands P1, P2, and P3 are integers. Operand P4
|
||||
** is a null-terminated string. Operand P5 is an unsigned character.
|
||||
** Few opcodes use all 5 operands.
|
||||
**
|
||||
** Computation results are stored on a set of registers numbered beginning
|
||||
** with 1 and going up to Vdbe.nMem. Each register can store
|
||||
** either an integer, a null-terminated string, a floating point
|
||||
** number, or the SQL "NULL" value. An implicit conversion from one
|
||||
** type to the other occurs as necessary.
|
||||
**
|
||||
** Most of the code in this file is taken up by the sqlite3VdbeExec()
|
||||
** function which does the work of interpreting a VDBE program.
|
||||
** But other routines are also provided to help in building up
|
||||
** a program instruction by instruction.
|
||||
** The code in this file implements the function that runs the
|
||||
** bytecode of a prepared statement.
|
||||
**
|
||||
** Various scripts scan this source file in order to generate HTML
|
||||
** documentation, headers files, or other derived files. The formatting
|
||||
@@ -49,7 +24,11 @@
|
||||
/*
|
||||
** Invoke this macro on memory cells just prior to changing the
|
||||
** value of the cell. This macro verifies that shallow copies are
|
||||
** not misused.
|
||||
** not misused. A shallow copy of a string or blob just copies a
|
||||
** pointer to the string or blob, not the content. If the original
|
||||
** is changed while the copy is still in use, the string or blob might
|
||||
** be changed out from under the copy. This macro verifies that nothing
|
||||
** like that every happens.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
# define memAboutToChange(P,M) sqlite3VdbeMemAboutToChange(P,M)
|
||||
@@ -108,7 +87,7 @@ static void updateMaxBlobsize(Mem *p){
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The next global variable is incremented each type the OP_Found opcode
|
||||
** The next global variable is incremented each time the OP_Found opcode
|
||||
** is executed. This is used to test whether or not the foreign key
|
||||
** operation implemented using OP_FkIsZero is working. This variable
|
||||
** has no function other than to help verify the correct operation of the
|
||||
@@ -152,31 +131,7 @@ int sqlite3_found_count = 0;
|
||||
&& sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;}
|
||||
|
||||
/* Return true if the cursor was opened using the OP_OpenSorter opcode. */
|
||||
# define isSorter(x) ((x)->pSorter!=0)
|
||||
|
||||
/*
|
||||
** Argument pMem points at a register that will be passed to a
|
||||
** user-defined function or returned to the user as the result of a query.
|
||||
** This routine sets the pMem->type variable used by the sqlite3_value_*()
|
||||
** routines.
|
||||
*/
|
||||
void sqlite3VdbeMemStoreType(Mem *pMem){
|
||||
int flags = pMem->flags;
|
||||
if( flags & MEM_Null ){
|
||||
pMem->type = SQLITE_NULL;
|
||||
}
|
||||
else if( flags & MEM_Int ){
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
}
|
||||
else if( flags & MEM_Real ){
|
||||
pMem->type = SQLITE_FLOAT;
|
||||
}
|
||||
else if( flags & MEM_Str ){
|
||||
pMem->type = SQLITE_TEXT;
|
||||
}else{
|
||||
pMem->type = SQLITE_BLOB;
|
||||
}
|
||||
}
|
||||
#define isSorter(x) ((x)->pSorter!=0)
|
||||
|
||||
/*
|
||||
** Allocate VdbeCursor number iCur. Return a pointer to it. Return NULL
|
||||
@@ -306,12 +261,14 @@ static void applyAffinity(
|
||||
** loss of information and return the revised type of the argument.
|
||||
*/
|
||||
int sqlite3_value_numeric_type(sqlite3_value *pVal){
|
||||
Mem *pMem = (Mem*)pVal;
|
||||
if( pMem->type==SQLITE_TEXT ){
|
||||
int eType = sqlite3_value_type(pVal);
|
||||
if( eType==SQLITE_TEXT ){
|
||||
Mem *pMem = (Mem*)pVal;
|
||||
applyNumericAffinity(pMem);
|
||||
sqlite3VdbeMemStoreType(pMem);
|
||||
eType = sqlite3_value_type(pVal);
|
||||
}
|
||||
return pMem->type;
|
||||
return eType;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -414,7 +371,7 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
|
||||
** Print the value of a register for tracing purposes:
|
||||
*/
|
||||
static void memTracePrint(Mem *p){
|
||||
if( p->flags & MEM_Invalid ){
|
||||
if( p->flags & MEM_Undefined ){
|
||||
printf(" undefined");
|
||||
}else if( p->flags & MEM_Null ){
|
||||
printf(" NULL");
|
||||
@@ -458,20 +415,6 @@ static void registerTrace(int iReg, Mem *p){
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The CHECK_FOR_INTERRUPT macro defined here looks to see if the
|
||||
** sqlite3_interrupt() routine has been called. If it has been, then
|
||||
** processing of the VDBE program is interrupted.
|
||||
**
|
||||
** This macro added to every instruction that does a jump in order to
|
||||
** implement a loop. This test used to be on every single instruction,
|
||||
** but that meant we more testing than we needed. By only testing the
|
||||
** flag on jump instructions, we get a (small) speed improvement.
|
||||
*/
|
||||
#define CHECK_FOR_INTERRUPT \
|
||||
if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
/*
|
||||
** This function is only called from within an assert() expression. It
|
||||
@@ -494,35 +437,8 @@ static int checkSavepointCount(sqlite3 *db){
|
||||
|
||||
|
||||
/*
|
||||
** Execute as much of a VDBE program as we can then return.
|
||||
**
|
||||
** sqlite3VdbeMakeReady() must be called before this routine in order to
|
||||
** close the program with a final OP_Halt and to set up the callbacks
|
||||
** and the error message pointer.
|
||||
**
|
||||
** Whenever a row or result data is available, this routine will either
|
||||
** invoke the result callback (if there is one) or return with
|
||||
** SQLITE_ROW.
|
||||
**
|
||||
** If an attempt is made to open a locked database, then this routine
|
||||
** will either invoke the busy callback (if there is one) or it will
|
||||
** return SQLITE_BUSY.
|
||||
**
|
||||
** If an error occurs, an error message is written to memory obtained
|
||||
** from sqlite3_malloc() and p->zErrMsg is made to point to that memory.
|
||||
** The error code is stored in p->rc and this routine returns SQLITE_ERROR.
|
||||
**
|
||||
** If the callback ever returns non-zero, then the program exits
|
||||
** immediately. There will be no error message but the p->rc field is
|
||||
** set to SQLITE_ABORT and this routine will return SQLITE_ERROR.
|
||||
**
|
||||
** A memory allocation error causes p->rc to be set to SQLITE_NOMEM and this
|
||||
** routine to return SQLITE_ERROR.
|
||||
**
|
||||
** Other fatal errors return SQLITE_ERROR.
|
||||
**
|
||||
** After this routine has finished, sqlite3VdbeFinalize() should be
|
||||
** used to clean up the mess that was left behind.
|
||||
** Execute as much of a VDBE program as we can.
|
||||
** This is the core of sqlite3_step().
|
||||
*/
|
||||
int sqlite3VdbeExec(
|
||||
Vdbe *p /* The VDBE */
|
||||
@@ -566,7 +482,7 @@ int sqlite3VdbeExec(
|
||||
assert( p->explain==0 );
|
||||
p->pResultSet = 0;
|
||||
db->busyHandler.nBusy = 0;
|
||||
CHECK_FOR_INTERRUPT;
|
||||
if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
|
||||
sqlite3VdbeIOTraceSql(p);
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
if( db->xProgress ){
|
||||
@@ -742,7 +658,7 @@ case OP_Goto: { /* jump */
|
||||
** checks on every opcode. This helps sqlite3_step() to run about 1.5%
|
||||
** faster according to "valgrind --tool=cachegrind" */
|
||||
check_for_interrupt:
|
||||
CHECK_FOR_INTERRUPT;
|
||||
if( db->u1.isInterrupted ) goto abort_due_to_interrupt;
|
||||
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
|
||||
/* Call the progress callback if it is configured and the required number
|
||||
** of VDBE ops have been executed (either since this invocation of
|
||||
@@ -782,20 +698,66 @@ case OP_Gosub: { /* jump */
|
||||
|
||||
/* Opcode: Return P1 * * * *
|
||||
**
|
||||
** Jump to the next instruction after the address in register P1.
|
||||
** Jump to the next instruction after the address in register P1. After
|
||||
** the jump, register P1 becomes undefined.
|
||||
*/
|
||||
case OP_Return: { /* in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( pIn1->flags & MEM_Int );
|
||||
assert( pIn1->flags==MEM_Int );
|
||||
pc = (int)pIn1->u.i;
|
||||
pIn1->flags = MEM_Undefined;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Yield P1 * * * *
|
||||
/* Opcode: InitCoroutine P1 P2 P3 * *
|
||||
**
|
||||
** Set up register P1 so that it will OP_Yield to the co-routine
|
||||
** located at address P3.
|
||||
**
|
||||
** If P2!=0 then the co-routine implementation immediately follows
|
||||
** this opcode. So jump over the co-routine implementation to
|
||||
** address P2.
|
||||
*/
|
||||
case OP_InitCoroutine: { /* jump */
|
||||
assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
|
||||
assert( pOp->p2>=0 && pOp->p2<p->nOp );
|
||||
assert( pOp->p3>=0 && pOp->p3<p->nOp );
|
||||
pOut = &aMem[pOp->p1];
|
||||
assert( !VdbeMemDynamic(pOut) );
|
||||
pOut->u.i = pOp->p3 - 1;
|
||||
pOut->flags = MEM_Int;
|
||||
if( pOp->p2 ) pc = pOp->p2 - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: EndCoroutine P1 * * * *
|
||||
**
|
||||
** The instruction at the address in register P1 is an OP_Yield.
|
||||
** Jump to the P2 parameter of that OP_Yield.
|
||||
** After the jump, register P1 becomes undefined.
|
||||
*/
|
||||
case OP_EndCoroutine: { /* in1 */
|
||||
VdbeOp *pCaller;
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( pIn1->flags==MEM_Int );
|
||||
assert( pIn1->u.i>=0 && pIn1->u.i<p->nOp );
|
||||
pCaller = &aOp[pIn1->u.i];
|
||||
assert( pCaller->opcode==OP_Yield );
|
||||
assert( pCaller->p2>=0 && pCaller->p2<p->nOp );
|
||||
pc = pCaller->p2 - 1;
|
||||
pIn1->flags = MEM_Undefined;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Yield P1 P2 * * *
|
||||
**
|
||||
** Swap the program counter with the value in register P1.
|
||||
**
|
||||
** If the co-routine ends with OP_Yield or OP_Return then continue
|
||||
** to the next instruction. But if the co-routine ends with
|
||||
** OP_EndCoroutine, jump immediately to P2.
|
||||
*/
|
||||
case OP_Yield: { /* in1 */
|
||||
case OP_Yield: { /* in1, jump */
|
||||
int pcDest;
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
assert( (pIn1->flags & MEM_Dyn)==0 );
|
||||
@@ -808,7 +770,7 @@ case OP_Yield: { /* in1 */
|
||||
}
|
||||
|
||||
/* Opcode: HaltIfNull P1 P2 P3 P4 P5
|
||||
** Synopsis: if r[P3] null then halt
|
||||
** Synopsis: if r[P3]=null halt
|
||||
**
|
||||
** Check the value in register P3. If it is NULL then Halt using
|
||||
** parameter P1, P2, and P4 as if this were a Halt instruction. If the
|
||||
@@ -956,7 +918,9 @@ case OP_Real: { /* same as TK_FLOAT, out2-prerelease */
|
||||
** Synopsis: r[P2]='P4'
|
||||
**
|
||||
** P4 points to a nul terminated UTF-8 string. This opcode is transformed
|
||||
** into an OP_String before it is executed for the first time.
|
||||
** into an OP_String before it is executed for the first time. During
|
||||
** this transformation, the length of string P4 is computed and stored
|
||||
** as the P1 parameter.
|
||||
*/
|
||||
case OP_String8: { /* same as TK_STRING, out2-prerelease */
|
||||
assert( pOp->p4.z!=0 );
|
||||
@@ -1031,7 +995,7 @@ case OP_Null: { /* out2-prerelease */
|
||||
}
|
||||
|
||||
|
||||
/* Opcode: Blob P1 P2 * P4
|
||||
/* Opcode: Blob P1 P2 * P4 *
|
||||
** Synopsis: r[P2]=P4 (len=P1)
|
||||
**
|
||||
** P4 points to a blob of data P1 bytes long. Store this
|
||||
@@ -1050,7 +1014,7 @@ case OP_Blob: { /* out2-prerelease */
|
||||
**
|
||||
** Transfer the values of bound parameter P1 into register P2
|
||||
**
|
||||
** If the parameter is named, then its name appears in P4 and P3==1.
|
||||
** If the parameter is named, then its name appears in P4.
|
||||
** The P4 value is used by sqlite3_bind_parameter_name().
|
||||
*/
|
||||
case OP_Variable: { /* out2-prerelease */
|
||||
@@ -1169,8 +1133,8 @@ case OP_SCopy: { /* out2 */
|
||||
** The registers P1 through P1+P2-1 contain a single row of
|
||||
** results. This opcode causes the sqlite3_step() call to terminate
|
||||
** with an SQLITE_ROW return code and it sets up the sqlite3_stmt
|
||||
** structure to provide access to the top P1 values as the result
|
||||
** row.
|
||||
** structure to provide access to the r[P1]..r[P1+P2-1] values as
|
||||
** the result row.
|
||||
*/
|
||||
case OP_ResultRow: {
|
||||
Mem *pMem;
|
||||
@@ -1698,7 +1662,7 @@ case OP_RealAffinity: { /* in1 */
|
||||
**
|
||||
** Force the value in register P1 to be text.
|
||||
** If the value is numeric, convert it to a string using the
|
||||
** equivalent of printf(). Blob values are unchanged and
|
||||
** equivalent of sprintf(). Blob values are unchanged and
|
||||
** are afterwards simply interpreted as text.
|
||||
**
|
||||
** A NULL value is not changed by this routine. It remains NULL.
|
||||
@@ -2153,7 +2117,9 @@ case OP_BitNot: { /* same as TK_BITNOT, in1, out2 */
|
||||
/* Opcode: Once P1 P2 * * *
|
||||
**
|
||||
** Check if OP_Once flag P1 is set. If so, jump to instruction P2. Otherwise,
|
||||
** set the flag and fall through to the next instruction.
|
||||
** set the flag and fall through to the next instruction. In other words,
|
||||
** this opcode causes all following up codes up through P2 (but not including
|
||||
** P2) to run just once and skipped on subsequent times through the loop.
|
||||
*/
|
||||
case OP_Once: { /* jump */
|
||||
assert( pOp->p1<p->nOnceFlag );
|
||||
@@ -2293,11 +2259,6 @@ case OP_Column: {
|
||||
if( pCrsr==0 ){
|
||||
assert( pC->pseudoTableReg>0 );
|
||||
pReg = &aMem[pC->pseudoTableReg];
|
||||
if( pC->multiPseudo ){
|
||||
sqlite3VdbeMemShallowCopy(pDest, pReg+p2, MEM_Ephem);
|
||||
Deephemeralize(pDest);
|
||||
goto op_column_out;
|
||||
}
|
||||
assert( pReg->flags & MEM_Blob );
|
||||
assert( memIsValid(pReg) );
|
||||
pC->payloadSize = pC->szRow = avail = pReg->n;
|
||||
@@ -2946,7 +2907,7 @@ case OP_AutoCommit: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Transaction P1 P2 * * *
|
||||
/* Opcode: Transaction P1 P2 P3 P4 P5
|
||||
**
|
||||
** Begin a transaction. The transaction ends when a Commit or Rollback
|
||||
** opcode is encountered. Depending on the ON CONFLICT setting, the
|
||||
@@ -2976,9 +2937,17 @@ case OP_AutoCommit: {
|
||||
** will automatically commit when the VDBE halts.
|
||||
**
|
||||
** If P2 is zero, then a read-lock is obtained on the database file.
|
||||
**
|
||||
** If P5!=0 then this opcode also checks the schema cookie against P3
|
||||
** and the schema generation counter against P4.
|
||||
** The cookie changes its value whenever the database schema changes.
|
||||
** This operation is used to detect when that the cookie has changed
|
||||
** and that the current process needs to reread the schema.
|
||||
*/
|
||||
case OP_Transaction: {
|
||||
Btree *pBt;
|
||||
int iMeta;
|
||||
int iGen;
|
||||
|
||||
assert( p->bIsReader );
|
||||
assert( p->readOnly==0 || pOp->p2==0 );
|
||||
@@ -3022,6 +2991,35 @@ case OP_Transaction: {
|
||||
p->nStmtDefCons = db->nDeferredCons;
|
||||
p->nStmtDefImmCons = db->nDeferredImmCons;
|
||||
}
|
||||
|
||||
/* Gather the schema version number for checking */
|
||||
sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta);
|
||||
iGen = db->aDb[pOp->p1].pSchema->iGeneration;
|
||||
}else{
|
||||
iGen = iMeta = 0;
|
||||
}
|
||||
assert( pOp->p5==0 || pOp->p4type==P4_INT32 );
|
||||
if( pOp->p5 && (iMeta!=pOp->p3 || iGen!=pOp->p4.i) ){
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
|
||||
/* If the schema-cookie from the database file matches the cookie
|
||||
** stored with the in-memory representation of the schema, do
|
||||
** not reload the schema from the database file.
|
||||
**
|
||||
** If virtual-tables are in use, this is not just an optimization.
|
||||
** Often, v-tables store their data in other SQLite tables, which
|
||||
** are queried from within xNext() and other v-table methods using
|
||||
** prepared queries. If such a query is out-of-date, we do not want to
|
||||
** discard the database schema, as the user code implementing the
|
||||
** v-table would have to be ready for the sqlite3_vtab structure itself
|
||||
** to be invalidated whenever sqlite3_step() is called from within
|
||||
** a v-table method.
|
||||
*/
|
||||
if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){
|
||||
sqlite3ResetOneSchema(db, pOp->p1);
|
||||
}
|
||||
p->expired = 1;
|
||||
rc = SQLITE_SCHEMA;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3096,66 +3094,6 @@ case OP_SetCookie: { /* in3 */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: VerifyCookie P1 P2 P3 * *
|
||||
**
|
||||
** Check the value of global database parameter number 0 (the
|
||||
** schema version) and make sure it is equal to P2 and that the
|
||||
** generation counter on the local schema parse equals P3.
|
||||
**
|
||||
** P1 is the database number which is 0 for the main database file
|
||||
** and 1 for the file holding temporary tables and some higher number
|
||||
** for auxiliary databases.
|
||||
**
|
||||
** The cookie changes its value whenever the database schema changes.
|
||||
** This operation is used to detect when that the cookie has changed
|
||||
** and that the current process needs to reread the schema.
|
||||
**
|
||||
** Either a transaction needs to have been started or an OP_Open needs
|
||||
** to be executed (to establish a read lock) before this opcode is
|
||||
** invoked.
|
||||
*/
|
||||
case OP_VerifyCookie: {
|
||||
int iMeta;
|
||||
int iGen;
|
||||
Btree *pBt;
|
||||
|
||||
assert( pOp->p1>=0 && pOp->p1<db->nDb );
|
||||
assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
|
||||
assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) );
|
||||
assert( p->bIsReader );
|
||||
pBt = db->aDb[pOp->p1].pBt;
|
||||
if( pBt ){
|
||||
sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta);
|
||||
iGen = db->aDb[pOp->p1].pSchema->iGeneration;
|
||||
}else{
|
||||
iGen = iMeta = 0;
|
||||
}
|
||||
if( iMeta!=pOp->p2 || iGen!=pOp->p3 ){
|
||||
sqlite3DbFree(db, p->zErrMsg);
|
||||
p->zErrMsg = sqlite3DbStrDup(db, "database schema has changed");
|
||||
/* If the schema-cookie from the database file matches the cookie
|
||||
** stored with the in-memory representation of the schema, do
|
||||
** not reload the schema from the database file.
|
||||
**
|
||||
** If virtual-tables are in use, this is not just an optimization.
|
||||
** Often, v-tables store their data in other SQLite tables, which
|
||||
** are queried from within xNext() and other v-table methods using
|
||||
** prepared queries. If such a query is out-of-date, we do not want to
|
||||
** discard the database schema, as the user code implementing the
|
||||
** v-table would have to be ready for the sqlite3_vtab structure itself
|
||||
** to be invalidated whenever sqlite3_step() is called from within
|
||||
** a v-table method.
|
||||
*/
|
||||
if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){
|
||||
sqlite3ResetOneSchema(db, pOp->p1);
|
||||
}
|
||||
|
||||
p->expired = 1;
|
||||
rc = SQLITE_SCHEMA;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: OpenRead P1 P2 P3 P4 P5
|
||||
** Synopsis: root=P2 iDb=P3
|
||||
**
|
||||
@@ -3295,7 +3233,7 @@ case OP_OpenWrite: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: OpenEphemeral P1 P2 * P4 *
|
||||
/* Opcode: OpenEphemeral P1 P2 * P4 P5
|
||||
** Synopsis: nColumn=P2
|
||||
**
|
||||
** Open a new cursor P1 to a transient table.
|
||||
@@ -3307,18 +3245,11 @@ case OP_OpenWrite: {
|
||||
** The cursor points to a BTree table if P4==0 and to a BTree index
|
||||
** if P4 is not 0. If P4 is not NULL, it points to a KeyInfo structure
|
||||
** that defines the format of keys in the index.
|
||||
*/
|
||||
/* Opcode: OpenHash P1 P2 * P4 *
|
||||
** Synopsis: nColumn=P2
|
||||
**
|
||||
** Open a new cursor P1 to a transient table.
|
||||
** P2 is the number of columns in the ephemeral table.
|
||||
** The cursor points to a BTree table if P4==0 and to a BTree index
|
||||
** if P4 is a KeyInfo structure.
|
||||
**
|
||||
** This opcode is identical to OP_OpenEphemeral except that it
|
||||
** adds the BTREE_UNORDERED parameter to the sqlite3BtreeOpen() call,
|
||||
** thus causing the underlying table to unordered.
|
||||
** The P5 parameter can be a mask of the BTREE_* flags defined
|
||||
** in btree.h. These flags control aspects of the operation of
|
||||
** the btree. The BTREE_OMIT_JOURNAL and BTREE_SINGLE flags are
|
||||
** added automatically.
|
||||
*/
|
||||
/* Opcode: OpenAutoindex P1 P2 * P4 *
|
||||
** Synopsis: nColumn=P2
|
||||
@@ -3329,10 +3260,9 @@ case OP_OpenWrite: {
|
||||
** indices in joins.
|
||||
*/
|
||||
case OP_OpenAutoindex:
|
||||
case OP_OpenHash:
|
||||
case OP_OpenEphemeral: {
|
||||
VdbeCursor *pCx;
|
||||
int btreeFlags;
|
||||
KeyInfo *pKeyInfo;
|
||||
|
||||
static const int vfsFlags =
|
||||
SQLITE_OPEN_READWRITE |
|
||||
@@ -3342,39 +3272,42 @@ case OP_OpenEphemeral: {
|
||||
SQLITE_OPEN_TRANSIENT_DB;
|
||||
assert( pOp->p1>=0 );
|
||||
assert( pOp->p2>=0 );
|
||||
assert( pOp->p5==0 );
|
||||
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
|
||||
if( pCx==0 ) goto no_mem;
|
||||
pCx->nullRow = 1;
|
||||
btreeFlags = BTREE_OMIT_JOURNAL | BTREE_SINGLE;
|
||||
if( pOp->opcode==OP_OpenHash ){
|
||||
btreeFlags |= BTREE_UNORDERED;
|
||||
pCx->isOrdered = 0;
|
||||
}else{
|
||||
pCx->isOrdered = 1;
|
||||
}
|
||||
if( pOp->p4.pKeyInfo ){
|
||||
assert( pOp->p4type==P4_KEYINFO );
|
||||
assert( pOp->p4.pKeyInfo->db==db );
|
||||
assert( pOp->p4.pKeyInfo->enc==ENC(db) );
|
||||
btreeFlags |= BTREE_SINGLE_INDEX;
|
||||
pCx->isTable = 0;
|
||||
}else{
|
||||
pCx->isTable = 1;
|
||||
}
|
||||
rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt, btreeFlags, vfsFlags);
|
||||
rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pCx->pBt,
|
||||
BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3BtreeBeginTrans(pCx->pBt, 1);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, pOp->p4.pKeyInfo,
|
||||
pCx->pCursor);
|
||||
/* If a transient index is required, create it by calling
|
||||
** sqlite3BtreeCreateTable() with the BTREE_BLOBKEY flag before
|
||||
** opening it. If a transient table is required, just use the
|
||||
** automatically created table with root-page 1 (an BLOB_INTKEY table).
|
||||
*/
|
||||
if( (pKeyInfo = pOp->p4.pKeyInfo)!=0 ){
|
||||
int pgno;
|
||||
assert( pOp->p4type==P4_KEYINFO );
|
||||
rc = sqlite3BtreeCreateTable(pCx->pBt, &pgno, BTREE_BLOBKEY | pOp->p5);
|
||||
if( rc==SQLITE_OK ){
|
||||
assert( pgno==MASTER_ROOT+1 );
|
||||
assert( pKeyInfo->db==db );
|
||||
assert( pKeyInfo->enc==ENC(db) );
|
||||
pCx->pKeyInfo = pKeyInfo;
|
||||
rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, pKeyInfo, pCx->pCursor);
|
||||
}
|
||||
pCx->isTable = 0;
|
||||
}else{
|
||||
rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, 0, pCx->pCursor);
|
||||
pCx->isTable = 1;
|
||||
}
|
||||
}
|
||||
pCx->pKeyInfo = pOp->p4.pKeyInfo;
|
||||
pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: SorterOpen P1 * * P4 *
|
||||
/* Opcode: SorterOpen P1 P2 * P4 *
|
||||
**
|
||||
** This opcode works like OP_OpenEphemeral except that it opens
|
||||
** a transient index that is specifically designed to sort large
|
||||
@@ -3394,14 +3327,13 @@ case OP_SorterOpen: {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: OpenPseudo P1 P2 P3 * P5
|
||||
** Synopsis: content in r[P2@P3]
|
||||
/* Opcode: OpenPseudo P1 P2 P3 * *
|
||||
** Synopsis: P3 columns in r[P2]
|
||||
**
|
||||
** Open a new cursor that points to a fake table that contains a single
|
||||
** row of data. The content of that one row in the content of memory
|
||||
** register P2 when P5==0. In other words, cursor P1 becomes an alias for the
|
||||
** MEM_Blob content contained in register P2. When P5==1, then the
|
||||
** row is represented by P3 consecutive registers beginning with P2.
|
||||
** row of data. The content of that one row is the content of memory
|
||||
** register P2. In other words, cursor P1 becomes an alias for the
|
||||
** MEM_Blob content contained in register P2.
|
||||
**
|
||||
** A pseudo-table created by this opcode is used to hold a single
|
||||
** row output from the sorter so that the row can be decomposed into
|
||||
@@ -3421,7 +3353,7 @@ case OP_OpenPseudo: {
|
||||
pCx->nullRow = 1;
|
||||
pCx->pseudoTableReg = pOp->p2;
|
||||
pCx->isTable = 1;
|
||||
pCx->multiPseudo = pOp->p5;
|
||||
assert( pOp->p5==0 );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3734,15 +3666,13 @@ case OP_Found: { /* jump, in3 */
|
||||
r.pKeyInfo = pC->pKeyInfo;
|
||||
r.nField = (u16)pOp->p4.i;
|
||||
r.aMem = pIn3;
|
||||
for(ii=0; ii<r.nField; ii++){
|
||||
assert( memIsValid(&r.aMem[ii]) );
|
||||
ExpandBlob(&r.aMem[ii]);
|
||||
#ifdef SQLITE_DEBUG
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<r.nField; i++){
|
||||
assert( memIsValid(&r.aMem[i]) );
|
||||
if( i ) REGISTER_TRACE(pOp->p3+i, &r.aMem[i]);
|
||||
}
|
||||
}
|
||||
if( ii ) REGISTER_TRACE(pOp->p3+ii, &r.aMem[ii]);
|
||||
#endif
|
||||
}
|
||||
r.flags = UNPACKED_PREFIX_MATCH;
|
||||
pIdxKey = &r;
|
||||
}else{
|
||||
@@ -4241,7 +4171,7 @@ case OP_SorterData: {
|
||||
**
|
||||
** Write into register P2 the complete row key for cursor P1.
|
||||
** There is no interpretation of the data.
|
||||
** The key is copied onto the P3 register exactly as
|
||||
** The key is copied onto the P2 register exactly as
|
||||
** it is found in the database file.
|
||||
**
|
||||
** If the P1 cursor must be pointing to a valid row (not a NULL row)
|
||||
@@ -4467,7 +4397,7 @@ case OP_Rewind: { /* jump */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Opcode: Next P1 P2 P3 * P5
|
||||
/* Opcode: Next P1 P2 P3 P4 P5
|
||||
**
|
||||
** Advance cursor P1 so that it points to the next key/data pair in its
|
||||
** table or index. If there are no more key/value pairs then fall through
|
||||
@@ -4490,12 +4420,12 @@ case OP_Rewind: { /* jump */
|
||||
**
|
||||
** See also: Prev, NextIfOpen
|
||||
*/
|
||||
/* Opcode: NextIfOpen P1 P2 P3 * P5
|
||||
/* Opcode: NextIfOpen P1 P2 P3 P4 P5
|
||||
**
|
||||
** This opcode works just like OP_Next except that if cursor P1 is not
|
||||
** open it behaves a no-op.
|
||||
*/
|
||||
/* Opcode: Prev P1 P2 P3 * P5
|
||||
/* Opcode: Prev P1 P2 P3 P4 P5
|
||||
**
|
||||
** Back up cursor P1 so that it points to the previous key/data pair in its
|
||||
** table or index. If there is no previous key/value pairs then fall through
|
||||
@@ -4516,7 +4446,7 @@ case OP_Rewind: { /* jump */
|
||||
** If P5 is positive and the jump is taken, then event counter
|
||||
** number P5-1 in the prepared statement is incremented.
|
||||
*/
|
||||
/* Opcode: PrevIfOpen P1 P2 P3 * P5
|
||||
/* Opcode: PrevIfOpen P1 P2 P3 P4 P5
|
||||
**
|
||||
** This opcode works just like OP_Prev except that if cursor P1 is not
|
||||
** open it behaves a no-op.
|
||||
@@ -4575,6 +4505,14 @@ next_tail:
|
||||
** P3 is a flag that provides a hint to the b-tree layer that this
|
||||
** insert is likely to be an append.
|
||||
**
|
||||
** If P5 has the OPFLAG_NCHANGE bit set, then the change counter is
|
||||
** incremented by this instruction. If the OPFLAG_NCHANGE bit is clear,
|
||||
** then the change counter is unchanged.
|
||||
**
|
||||
** If P5 has the OPFLAG_USESEEKRESULT bit set, then the cursor must have
|
||||
** just done a seek to the spot where the new entry is to be inserted.
|
||||
** This flag avoids doing an extra seek.
|
||||
**
|
||||
** This instruction only works for indices. The equivalent instruction
|
||||
** for tables is OP_Insert.
|
||||
*/
|
||||
@@ -5175,7 +5113,7 @@ case OP_RowSetTest: { /* jump, in1, in3 */
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
|
||||
/* Opcode: Program P1 P2 P3 P4 *
|
||||
/* Opcode: Program P1 P2 P3 P4 P5
|
||||
**
|
||||
** Execute the trigger program passed as P4 (type P4_SUBPROGRAM).
|
||||
**
|
||||
@@ -5187,6 +5125,8 @@ case OP_RowSetTest: { /* jump, in1, in3 */
|
||||
** memory required by the sub-vdbe at runtime.
|
||||
**
|
||||
** P4 is a pointer to the VM containing the trigger program.
|
||||
**
|
||||
** If P5 is non-zero, then recursive program invocation is enabled.
|
||||
*/
|
||||
case OP_Program: { /* jump */
|
||||
int nMem; /* Number of memory registers for sub-program */
|
||||
@@ -5264,7 +5204,7 @@ case OP_Program: { /* jump */
|
||||
|
||||
pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem];
|
||||
for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){
|
||||
pMem->flags = MEM_Invalid;
|
||||
pMem->flags = MEM_Undefined;
|
||||
pMem->db = db;
|
||||
}
|
||||
}else{
|
||||
@@ -5574,7 +5514,7 @@ case OP_Checkpoint: {
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_PRAGMA
|
||||
/* Opcode: JournalMode P1 P2 P3 * P5
|
||||
/* Opcode: JournalMode P1 P2 P3 * *
|
||||
**
|
||||
** Change the journal mode of database P1 to P3. P3 must be one of the
|
||||
** PAGER_JOURNALMODE_XXX values. If changing between the various rollback
|
||||
@@ -6060,7 +6000,7 @@ case OP_VRename: {
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
/* Opcode: VUpdate P1 P2 P3 P4 *
|
||||
/* Opcode: VUpdate P1 P2 P3 P4 P5
|
||||
** Synopsis: data=r[P3@P2]
|
||||
**
|
||||
** P4 is a pointer to a virtual table object, an sqlite3_vtab structure.
|
||||
@@ -6083,6 +6023,9 @@ case OP_VRename: {
|
||||
** P1 is a boolean flag. If it is set to true and the xUpdate call
|
||||
** is successful, then the value returned by sqlite3_last_insert_rowid()
|
||||
** is set to the value of the rowid for the row just inserted.
|
||||
**
|
||||
** P5 is the error actions (OE_Replace, OE_Fail, OE_Ignore, etc) to
|
||||
** apply in the case of a constraint failure on an insert or update.
|
||||
*/
|
||||
case OP_VUpdate: {
|
||||
sqlite3_vtab *pVtab;
|
||||
@@ -6171,16 +6114,26 @@ case OP_MaxPgcnt: { /* out2-prerelease */
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
/* Opcode: Trace * * * P4 *
|
||||
/* Opcode: Init * P2 * P4 *
|
||||
** Synopsis: Start at P2
|
||||
**
|
||||
** Programs contain a single instance of this opcode as the very first
|
||||
** opcode.
|
||||
**
|
||||
** If tracing is enabled (by the sqlite3_trace()) interface, then
|
||||
** the UTF-8 string contained in P4 is emitted on the trace callback.
|
||||
** Or if P4 is blank, use the string returned by sqlite3_sql().
|
||||
**
|
||||
** If P2 is not zero, jump to instruction P2.
|
||||
*/
|
||||
case OP_Trace: {
|
||||
case OP_Init: { /* jump */
|
||||
char *zTrace;
|
||||
char *z;
|
||||
|
||||
if( pOp->p2 ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_TRACE
|
||||
if( db->xTrace
|
||||
&& !p->doingRerun
|
||||
&& (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
|
||||
@@ -6206,9 +6159,9 @@ case OP_Trace: {
|
||||
sqlite3DebugPrintf("SQL-trace: %s\n", zTrace);
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
#endif /* SQLITE_OMIT_TRACE */
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Opcode: Noop * * * * *
|
||||
|
||||
+8
-7
@@ -75,7 +75,6 @@ struct VdbeCursor {
|
||||
Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
|
||||
Bool isTable:1; /* True if a table requiring integer keys */
|
||||
Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */
|
||||
Bool multiPseudo:1; /* Multi-register pseudo-cursor */
|
||||
sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
|
||||
i64 seqCount; /* Sequence counter */
|
||||
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
|
||||
@@ -169,7 +168,7 @@ struct Mem {
|
||||
} u;
|
||||
int n; /* Number of characters in string value, excluding '\0' */
|
||||
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
|
||||
u8 type; /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */
|
||||
u8 memType; /* Lower 5 bits of flags */
|
||||
u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
|
||||
#ifdef SQLITE_DEBUG
|
||||
Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */
|
||||
@@ -198,7 +197,7 @@ struct Mem {
|
||||
#define MEM_Blob 0x0010 /* Value is a BLOB */
|
||||
#define MEM_RowSet 0x0020 /* Value is a RowSet object */
|
||||
#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */
|
||||
#define MEM_Invalid 0x0080 /* Value is undefined */
|
||||
#define MEM_Undefined 0x0080 /* Value is undefined */
|
||||
#define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */
|
||||
#define MEM_TypeMask 0x01ff /* Mask of type bits */
|
||||
|
||||
@@ -230,7 +229,7 @@ struct Mem {
|
||||
** is for use inside assert() statements only.
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
#define memIsValid(M) ((M)->flags & MEM_Invalid)==0
|
||||
#define memIsValid(M) ((M)->flags & MEM_Undefined)==0
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -425,16 +424,18 @@ int sqlite3VdbeMemNumerify(Mem*);
|
||||
int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*);
|
||||
void sqlite3VdbeMemRelease(Mem *p);
|
||||
void sqlite3VdbeMemReleaseExternal(Mem *p);
|
||||
#define VdbeMemDynamic(X) \
|
||||
(((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0)
|
||||
#define VdbeMemRelease(X) \
|
||||
if((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame)) \
|
||||
sqlite3VdbeMemReleaseExternal(X);
|
||||
if( VdbeMemDynamic(X) ) sqlite3VdbeMemReleaseExternal(X);
|
||||
int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
|
||||
const char *sqlite3OpcodeName(int);
|
||||
int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve);
|
||||
int sqlite3VdbeCloseStatement(Vdbe *, int);
|
||||
void sqlite3VdbeFrameDelete(VdbeFrame*);
|
||||
int sqlite3VdbeFrameRestore(VdbeFrame *);
|
||||
void sqlite3VdbeMemStoreType(Mem *pMem);
|
||||
#define sqlite3VdbeMemStoreType(X) (X)->memType = (u8)((X)->flags&0x1f)
|
||||
/* void sqlite3VdbeMemStoreType(Mem *pMem); */
|
||||
int sqlite3VdbeTransferError(Vdbe *p);
|
||||
|
||||
int sqlite3VdbeSorterInit(sqlite3 *, VdbeCursor *);
|
||||
|
||||
+36
-2
@@ -172,7 +172,41 @@ const void *sqlite3_value_text16le(sqlite3_value *pVal){
|
||||
}
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
int sqlite3_value_type(sqlite3_value* pVal){
|
||||
return pVal->type;
|
||||
static const u8 aType[] = {
|
||||
SQLITE_BLOB, /* 0x00 */
|
||||
SQLITE_NULL, /* 0x01 */
|
||||
SQLITE_TEXT, /* 0x02 */
|
||||
SQLITE_NULL, /* 0x03 */
|
||||
SQLITE_INTEGER, /* 0x04 */
|
||||
SQLITE_NULL, /* 0x05 */
|
||||
SQLITE_INTEGER, /* 0x06 */
|
||||
SQLITE_NULL, /* 0x07 */
|
||||
SQLITE_FLOAT, /* 0x08 */
|
||||
SQLITE_NULL, /* 0x09 */
|
||||
SQLITE_FLOAT, /* 0x0a */
|
||||
SQLITE_NULL, /* 0x0b */
|
||||
SQLITE_INTEGER, /* 0x0c */
|
||||
SQLITE_NULL, /* 0x0d */
|
||||
SQLITE_INTEGER, /* 0x0e */
|
||||
SQLITE_NULL, /* 0x0f */
|
||||
SQLITE_BLOB, /* 0x10 */
|
||||
SQLITE_NULL, /* 0x11 */
|
||||
SQLITE_TEXT, /* 0x12 */
|
||||
SQLITE_NULL, /* 0x13 */
|
||||
SQLITE_INTEGER, /* 0x14 */
|
||||
SQLITE_NULL, /* 0x15 */
|
||||
SQLITE_INTEGER, /* 0x16 */
|
||||
SQLITE_NULL, /* 0x17 */
|
||||
SQLITE_FLOAT, /* 0x18 */
|
||||
SQLITE_NULL, /* 0x19 */
|
||||
SQLITE_FLOAT, /* 0x1a */
|
||||
SQLITE_NULL, /* 0x1b */
|
||||
SQLITE_INTEGER, /* 0x1c */
|
||||
SQLITE_NULL, /* 0x1d */
|
||||
SQLITE_INTEGER, /* 0x1e */
|
||||
SQLITE_NULL, /* 0x1f */
|
||||
};
|
||||
return aType[pVal->memType&0x1f];
|
||||
}
|
||||
|
||||
/**************************** sqlite3_result_ *******************************
|
||||
@@ -1131,7 +1165,7 @@ int sqlite3_bind_text16(
|
||||
#endif /* SQLITE_OMIT_UTF16 */
|
||||
int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){
|
||||
int rc;
|
||||
switch( pValue->type ){
|
||||
switch( sqlite3_value_type((sqlite3_value*)pValue) ){
|
||||
case SQLITE_INTEGER: {
|
||||
rc = sqlite3_bind_int64(pStmt, i, pValue->u.i);
|
||||
break;
|
||||
|
||||
+14
-25
@@ -863,14 +863,6 @@ void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){
|
||||
** this routine is a valid pointer. But because the dummy.opcode is 0,
|
||||
** dummy will never be written to. This is verified by code inspection and
|
||||
** by running with Valgrind.
|
||||
**
|
||||
** About the #ifdef SQLITE_OMIT_TRACE: Normally, this routine is never called
|
||||
** unless p->nOp>0. This is because in the absense of SQLITE_OMIT_TRACE,
|
||||
** an OP_Trace instruction is always inserted by sqlite3VdbeGet() as soon as
|
||||
** a new VDBE is created. So we are free to set addr to p->nOp-1 without
|
||||
** having to double-check to make sure that the result is non-negative. But
|
||||
** if SQLITE_OMIT_TRACE is defined, the OP_Trace is omitted and we do need to
|
||||
** check the value of p->nOp-1 before continuing.
|
||||
*/
|
||||
VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
|
||||
/* C89 specifies that the constant "dummy" will be initialized to all
|
||||
@@ -878,9 +870,6 @@ VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
|
||||
static VdbeOp dummy; /* Ignore the MSVC warning about no initializer */
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
if( addr<0 ){
|
||||
#ifdef SQLITE_OMIT_TRACE
|
||||
if( p->nOp==0 ) return (VdbeOp*)&dummy;
|
||||
#endif
|
||||
addr = p->nOp - 1;
|
||||
}
|
||||
assert( (addr>=0 && addr<p->nOp) || p->db->mallocFailed );
|
||||
@@ -1234,7 +1223,7 @@ static void releaseMemArray(Mem *p, int N){
|
||||
p->zMalloc = 0;
|
||||
}
|
||||
|
||||
p->flags = MEM_Invalid;
|
||||
p->flags = MEM_Undefined;
|
||||
}
|
||||
db->mallocFailed = malloc_failed;
|
||||
}
|
||||
@@ -1356,7 +1345,7 @@ int sqlite3VdbeList(
|
||||
}
|
||||
if( p->explain==1 ){
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
pMem->memType = MEM_Int;
|
||||
pMem->u.i = i; /* Program counter */
|
||||
pMem++;
|
||||
|
||||
@@ -1364,7 +1353,7 @@ int sqlite3VdbeList(
|
||||
pMem->z = (char*)sqlite3OpcodeName(pOp->opcode); /* Opcode */
|
||||
assert( pMem->z!=0 );
|
||||
pMem->n = sqlite3Strlen30(pMem->z);
|
||||
pMem->type = SQLITE_TEXT;
|
||||
pMem->memType = MEM_Str;
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
pMem++;
|
||||
|
||||
@@ -1390,17 +1379,17 @@ int sqlite3VdbeList(
|
||||
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->u.i = pOp->p1; /* P1 */
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
pMem->memType = MEM_Int;
|
||||
pMem++;
|
||||
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->u.i = pOp->p2; /* P2 */
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
pMem->memType = MEM_Int;
|
||||
pMem++;
|
||||
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->u.i = pOp->p3; /* P3 */
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
pMem->memType = MEM_Int;
|
||||
pMem++;
|
||||
|
||||
if( sqlite3VdbeMemGrow(pMem, 32, 0) ){ /* P4 */
|
||||
@@ -1416,7 +1405,7 @@ int sqlite3VdbeList(
|
||||
pMem->n = sqlite3Strlen30(pMem->z);
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
}
|
||||
pMem->type = SQLITE_TEXT;
|
||||
pMem->memType = MEM_Str;
|
||||
pMem++;
|
||||
|
||||
if( p->explain==1 ){
|
||||
@@ -1427,7 +1416,7 @@ int sqlite3VdbeList(
|
||||
pMem->flags = MEM_Dyn|MEM_Str|MEM_Term;
|
||||
pMem->n = 2;
|
||||
sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5); /* P5 */
|
||||
pMem->type = SQLITE_TEXT;
|
||||
pMem->memType = MEM_Str;
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
pMem++;
|
||||
|
||||
@@ -1438,11 +1427,11 @@ int sqlite3VdbeList(
|
||||
}
|
||||
pMem->flags = MEM_Dyn|MEM_Str|MEM_Term;
|
||||
pMem->n = displayComment(pOp, zP4, pMem->z, 500);
|
||||
pMem->type = SQLITE_TEXT;
|
||||
pMem->memType = MEM_Str;
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
#else
|
||||
pMem->flags = MEM_Null; /* Comment */
|
||||
pMem->type = SQLITE_NULL;
|
||||
pMem->memType = MEM_Null;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1465,7 +1454,7 @@ void sqlite3VdbePrintSql(Vdbe *p){
|
||||
z = p->zSql;
|
||||
}else if( p->nOp>=1 ){
|
||||
const VdbeOp *pOp = &p->aOp[0];
|
||||
if( pOp->opcode==OP_Trace && pOp->p4.z!=0 ){
|
||||
if( pOp->opcode==OP_Init && pOp->p4.z!=0 ){
|
||||
z = pOp->p4.z;
|
||||
while( sqlite3Isspace(*z) ) z++;
|
||||
}
|
||||
@@ -1484,7 +1473,7 @@ void sqlite3VdbeIOTraceSql(Vdbe *p){
|
||||
if( sqlite3IoTrace==0 ) return;
|
||||
if( nOp<1 ) return;
|
||||
pOp = &p->aOp[0];
|
||||
if( pOp->opcode==OP_Trace && pOp->p4.z!=0 ){
|
||||
if( pOp->opcode==OP_Init && pOp->p4.z!=0 ){
|
||||
int i, j;
|
||||
char z[1000];
|
||||
sqlite3_snprintf(sizeof(z), z, "%s", pOp->p4.z);
|
||||
@@ -1702,7 +1691,7 @@ void sqlite3VdbeMakeReady(
|
||||
p->aMem--; /* aMem[] goes from 1..nMem */
|
||||
p->nMem = nMem; /* not from 0..nMem-1 */
|
||||
for(n=1; n<=nMem; n++){
|
||||
p->aMem[n].flags = MEM_Invalid;
|
||||
p->aMem[n].flags = MEM_Undefined;
|
||||
p->aMem[n].db = db;
|
||||
}
|
||||
}
|
||||
@@ -1814,7 +1803,7 @@ static void Cleanup(Vdbe *p){
|
||||
int i;
|
||||
if( p->apCsr ) for(i=0; i<p->nCursor; i++) assert( p->apCsr[i]==0 );
|
||||
if( p->aMem ){
|
||||
for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Invalid );
|
||||
for(i=1; i<=p->nMem; i++) assert( p->aMem[i].flags==MEM_Undefined );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+26
-32
@@ -134,21 +134,20 @@ int sqlite3_blob_open(
|
||||
** transaction.
|
||||
*/
|
||||
static const VdbeOpList openBlob[] = {
|
||||
{OP_Transaction, 0, 0, 0}, /* 0: Start a transaction */
|
||||
{OP_VerifyCookie, 0, 0, 0}, /* 1: Check the schema cookie */
|
||||
{OP_TableLock, 0, 0, 0}, /* 2: Acquire a read or write lock */
|
||||
/* {OP_Transaction, 0, 0, 0}, // 0: Inserted separately */
|
||||
{OP_TableLock, 0, 0, 0}, /* 1: Acquire a read or write lock */
|
||||
|
||||
/* One of the following two instructions is replaced by an OP_Noop. */
|
||||
{OP_OpenRead, 0, 0, 0}, /* 3: Open cursor 0 for reading */
|
||||
{OP_OpenWrite, 0, 0, 0}, /* 4: Open cursor 0 for read/write */
|
||||
{OP_OpenRead, 0, 0, 0}, /* 2: Open cursor 0 for reading */
|
||||
{OP_OpenWrite, 0, 0, 0}, /* 3: Open cursor 0 for read/write */
|
||||
|
||||
{OP_Variable, 1, 1, 1}, /* 5: Push the rowid to the stack */
|
||||
{OP_NotExists, 0, 10, 1}, /* 6: Seek the cursor */
|
||||
{OP_Column, 0, 0, 1}, /* 7 */
|
||||
{OP_ResultRow, 1, 0, 0}, /* 8 */
|
||||
{OP_Goto, 0, 5, 0}, /* 9 */
|
||||
{OP_Close, 0, 0, 0}, /* 10 */
|
||||
{OP_Halt, 0, 0, 0}, /* 11 */
|
||||
{OP_Variable, 1, 1, 1}, /* 4: Push the rowid to the stack */
|
||||
{OP_NotExists, 0, 10, 1}, /* 5: Seek the cursor */
|
||||
{OP_Column, 0, 0, 1}, /* 6 */
|
||||
{OP_ResultRow, 1, 0, 0}, /* 7 */
|
||||
{OP_Goto, 0, 4, 0}, /* 8 */
|
||||
{OP_Close, 0, 0, 0}, /* 9 */
|
||||
{OP_Halt, 0, 0, 0}, /* 10 */
|
||||
};
|
||||
|
||||
int rc = SQLITE_OK;
|
||||
@@ -261,36 +260,31 @@ int sqlite3_blob_open(
|
||||
Vdbe *v = (Vdbe *)pBlob->pStmt;
|
||||
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
|
||||
|
||||
sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, flags,
|
||||
pTab->pSchema->schema_cookie,
|
||||
pTab->pSchema->iGeneration);
|
||||
sqlite3VdbeChangeP5(v, 1);
|
||||
sqlite3VdbeAddOpList(v, sizeof(openBlob)/sizeof(VdbeOpList), openBlob);
|
||||
|
||||
|
||||
/* Configure the OP_Transaction */
|
||||
sqlite3VdbeChangeP1(v, 0, iDb);
|
||||
sqlite3VdbeChangeP2(v, 0, flags);
|
||||
|
||||
/* Configure the OP_VerifyCookie */
|
||||
sqlite3VdbeChangeP1(v, 1, iDb);
|
||||
sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie);
|
||||
sqlite3VdbeChangeP3(v, 1, pTab->pSchema->iGeneration);
|
||||
|
||||
/* Make sure a mutex is held on the table to be accessed */
|
||||
sqlite3VdbeUsesBtree(v, iDb);
|
||||
|
||||
/* Configure the OP_TableLock instruction */
|
||||
#ifdef SQLITE_OMIT_SHARED_CACHE
|
||||
sqlite3VdbeChangeToNoop(v, 2);
|
||||
sqlite3VdbeChangeToNoop(v, 1);
|
||||
#else
|
||||
sqlite3VdbeChangeP1(v, 2, iDb);
|
||||
sqlite3VdbeChangeP2(v, 2, pTab->tnum);
|
||||
sqlite3VdbeChangeP3(v, 2, flags);
|
||||
sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);
|
||||
sqlite3VdbeChangeP1(v, 1, iDb);
|
||||
sqlite3VdbeChangeP2(v, 1, pTab->tnum);
|
||||
sqlite3VdbeChangeP3(v, 1, flags);
|
||||
sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT);
|
||||
#endif
|
||||
|
||||
/* Remove either the OP_OpenWrite or OpenRead. Set the P2
|
||||
** parameter of the other to pTab->tnum. */
|
||||
sqlite3VdbeChangeToNoop(v, 4 - flags);
|
||||
sqlite3VdbeChangeP2(v, 3 + flags, pTab->tnum);
|
||||
sqlite3VdbeChangeP3(v, 3 + flags, iDb);
|
||||
sqlite3VdbeChangeToNoop(v, 3 - flags);
|
||||
sqlite3VdbeChangeP2(v, 2 + flags, pTab->tnum);
|
||||
sqlite3VdbeChangeP3(v, 2 + flags, iDb);
|
||||
|
||||
/* Configure the number of columns. Configure the cursor to
|
||||
** think that the table has one more column than it really
|
||||
@@ -299,8 +293,8 @@ int sqlite3_blob_open(
|
||||
** we can invoke OP_Column to fill in the vdbe cursors type
|
||||
** and offset cache without causing any IO.
|
||||
*/
|
||||
sqlite3VdbeChangeP4(v, 3+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32);
|
||||
sqlite3VdbeChangeP2(v, 7, pTab->nCol);
|
||||
sqlite3VdbeChangeP4(v, 2+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32);
|
||||
sqlite3VdbeChangeP2(v, 6, pTab->nCol);
|
||||
if( !db->mallocFailed ){
|
||||
pParse->nVar = 1;
|
||||
pParse->nMem = 1;
|
||||
|
||||
+11
-11
@@ -289,7 +289,7 @@ void sqlite3VdbeMemReleaseExternal(Mem *p){
|
||||
/*
|
||||
** Release any memory held by the Mem. This may leave the Mem in an
|
||||
** inconsistent state, for example with (Mem.z==0) and
|
||||
** (Mem.type==SQLITE_TEXT).
|
||||
** (Mem.memType==MEM_Str).
|
||||
*/
|
||||
void sqlite3VdbeMemRelease(Mem *p){
|
||||
VdbeMemRelease(p);
|
||||
@@ -480,7 +480,7 @@ void sqlite3VdbeMemSetNull(Mem *pMem){
|
||||
sqlite3RowSetClear(pMem->u.pRowSet);
|
||||
}
|
||||
MemSetTypeFlag(pMem, MEM_Null);
|
||||
pMem->type = SQLITE_NULL;
|
||||
pMem->memType = MEM_Null;
|
||||
}
|
||||
void sqlite3ValueSetNull(sqlite3_value *p){
|
||||
sqlite3VdbeMemSetNull((Mem*)p);
|
||||
@@ -493,7 +493,7 @@ void sqlite3ValueSetNull(sqlite3_value *p){
|
||||
void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->flags = MEM_Blob|MEM_Zero;
|
||||
pMem->type = SQLITE_BLOB;
|
||||
pMem->memType = MEM_Blob;
|
||||
pMem->n = 0;
|
||||
if( n<0 ) n = 0;
|
||||
pMem->u.nZero = n;
|
||||
@@ -516,7 +516,7 @@ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->u.i = val;
|
||||
pMem->flags = MEM_Int;
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
pMem->memType = MEM_Int;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
@@ -531,7 +531,7 @@ void sqlite3VdbeMemSetDouble(Mem *pMem, double val){
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->r = val;
|
||||
pMem->flags = MEM_Real;
|
||||
pMem->type = SQLITE_FLOAT;
|
||||
pMem->memType = MEM_Real;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -587,7 +587,7 @@ void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
|
||||
Mem *pX;
|
||||
for(i=1, pX=&pVdbe->aMem[1]; i<=pVdbe->nMem; i++, pX++){
|
||||
if( pX->pScopyFrom==pMem ){
|
||||
pX->flags |= MEM_Invalid;
|
||||
pX->flags |= MEM_Undefined;
|
||||
pX->pScopyFrom = 0;
|
||||
}
|
||||
}
|
||||
@@ -739,7 +739,7 @@ int sqlite3VdbeMemSetStr(
|
||||
pMem->n = nByte;
|
||||
pMem->flags = flags;
|
||||
pMem->enc = (enc==0 ? SQLITE_UTF8 : enc);
|
||||
pMem->type = (enc==0 ? SQLITE_BLOB : SQLITE_TEXT);
|
||||
pMem->memType = flags&0x1f;
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
if( pMem->enc!=SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){
|
||||
@@ -910,7 +910,7 @@ int sqlite3VdbeMemFromBtree(
|
||||
}else if( SQLITE_OK==(rc = sqlite3VdbeMemGrow(pMem, amt+2, 0)) ){
|
||||
pMem->flags = MEM_Blob|MEM_Dyn|MEM_Term;
|
||||
pMem->enc = 0;
|
||||
pMem->type = SQLITE_BLOB;
|
||||
pMem->memType = MEM_Blob;
|
||||
if( key ){
|
||||
rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z);
|
||||
}else{
|
||||
@@ -980,7 +980,7 @@ sqlite3_value *sqlite3ValueNew(sqlite3 *db){
|
||||
Mem *p = sqlite3DbMallocZero(db, sizeof(*p));
|
||||
if( p ){
|
||||
p->flags = MEM_Null;
|
||||
p->type = SQLITE_NULL;
|
||||
p->memType = MEM_Null;
|
||||
p->db = db;
|
||||
}
|
||||
return p;
|
||||
@@ -1030,7 +1030,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
|
||||
pRec->aMem = (Mem *)((u8*)pRec + ROUND8(sizeof(UnpackedRecord)));
|
||||
for(i=0; i<nCol; i++){
|
||||
pRec->aMem[i].flags = MEM_Null;
|
||||
pRec->aMem[i].type = SQLITE_NULL;
|
||||
pRec->aMem[i].memType = MEM_Null;
|
||||
pRec->aMem[i].db = db;
|
||||
}
|
||||
}else{
|
||||
@@ -1103,7 +1103,7 @@ static int valueFromExpr(
|
||||
zVal = sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken);
|
||||
if( zVal==0 ) goto no_mem;
|
||||
sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
|
||||
if( op==TK_FLOAT ) pVal->type = SQLITE_FLOAT;
|
||||
if( op==TK_FLOAT ) pVal->memType = MEM_Real;
|
||||
}
|
||||
if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){
|
||||
sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8);
|
||||
|
||||
+43
-22
@@ -2348,17 +2348,16 @@ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){
|
||||
** this routine sets up a loop that will iterate over all values of X.
|
||||
*/
|
||||
static int codeEqualityTerm(
|
||||
WhereInfo *pWInfo, /* WHERE clause */
|
||||
Parse *pParse, /* The parsing context */
|
||||
WhereTerm *pTerm, /* The term of the WHERE clause to be coded */
|
||||
WhereLevel *pLevel, /* The level of the FROM clause we are working on */
|
||||
int iEq, /* Index of the equality term within this level */
|
||||
int bRev, /* True for reverse-order IN operations */
|
||||
int iTarget /* Attempt to leave results in this register */
|
||||
){
|
||||
Expr *pX = pTerm->pExpr; /* Expression to be coded */
|
||||
Parse *pParse = pWInfo->pParse; /* Parsing context */
|
||||
Vdbe *v = pParse->pVdbe; /* Prepared stmt under construction */
|
||||
int iReg; /* Register holding results */
|
||||
Expr *pX = pTerm->pExpr;
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
int iReg; /* Register holding results */
|
||||
|
||||
assert( iTarget>0 );
|
||||
if( pX->op==TK_EQ ){
|
||||
@@ -2383,7 +2382,7 @@ static int codeEqualityTerm(
|
||||
}
|
||||
assert( pX->op==TK_IN );
|
||||
iReg = iTarget;
|
||||
eType = sqlite3FindInIndex(pParse, pX, 0, pWInfo->bOBSat);
|
||||
eType = sqlite3FindInIndex(pParse, pX, 0);
|
||||
if( eType==IN_INDEX_INDEX_DESC ){
|
||||
testcase( bRev );
|
||||
bRev = !bRev;
|
||||
@@ -2465,7 +2464,7 @@ static int codeEqualityTerm(
|
||||
** string in this example would be set to SQLITE_AFF_NONE.
|
||||
*/
|
||||
static int codeAllEqualityTerms(
|
||||
WhereInfo *pWInfo, /* WHERE clause */
|
||||
Parse *pParse, /* Parsing context */
|
||||
WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */
|
||||
int bRev, /* Reverse the order of IN operators */
|
||||
int nExtraReg, /* Number of extra registers to allocate */
|
||||
@@ -2473,7 +2472,6 @@ static int codeAllEqualityTerms(
|
||||
){
|
||||
u16 nEq; /* The number of == or IN constraints to code */
|
||||
u16 nSkip; /* Number of left-most columns to skip */
|
||||
Parse *pParse = pWInfo->pParse; /* Parsing context */
|
||||
Vdbe *v = pParse->pVdbe; /* The vm under construction */
|
||||
Index *pIdx; /* The index being used for this loop */
|
||||
WhereTerm *pTerm; /* A single constraint term */
|
||||
@@ -2528,7 +2526,7 @@ static int codeAllEqualityTerms(
|
||||
** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
|
||||
testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
|
||||
testcase( pTerm->wtFlags & TERM_VIRTUAL );
|
||||
r1 = codeEqualityTerm(pWInfo, pTerm, pLevel, j, bRev, regBase+j);
|
||||
r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, regBase+j);
|
||||
if( r1!=regBase+j ){
|
||||
if( nReg==1 ){
|
||||
sqlite3ReleaseTempReg(pParse, regBase);
|
||||
@@ -2787,10 +2785,9 @@ static Bitmask codeOneLoopStart(
|
||||
/* Special case of a FROM clause subquery implemented as a co-routine */
|
||||
if( pTabItem->viaCoroutine ){
|
||||
int regYield = pTabItem->regReturn;
|
||||
sqlite3VdbeAddOp2(v, OP_Integer, pTabItem->addrFillSub-1, regYield);
|
||||
pLevel->p2 = sqlite3VdbeAddOp1(v, OP_Yield, regYield);
|
||||
VdbeComment((v, "next row of co-routine %s", pTabItem->pTab->zName));
|
||||
sqlite3VdbeAddOp2(v, OP_If, regYield+1, addrBrk);
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
|
||||
pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk);
|
||||
VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName));
|
||||
pLevel->op = OP_Goto;
|
||||
}else
|
||||
|
||||
@@ -2811,7 +2808,7 @@ static Bitmask codeOneLoopStart(
|
||||
pTerm = pLoop->aLTerm[j];
|
||||
if( pTerm==0 ) continue;
|
||||
if( pTerm->eOperator & WO_IN ){
|
||||
codeEqualityTerm(pWInfo, pTerm, pLevel, j, bRev, iTarget);
|
||||
codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget);
|
||||
addrNotFound = pLevel->addrNxt;
|
||||
}else{
|
||||
sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget);
|
||||
@@ -2851,7 +2848,7 @@ static Bitmask codeOneLoopStart(
|
||||
assert( pTerm->pExpr!=0 );
|
||||
assert( omitTable==0 );
|
||||
testcase( pTerm->wtFlags & TERM_VIRTUAL );
|
||||
iRowidReg = codeEqualityTerm(pWInfo, pTerm, pLevel, 0, bRev, iReleaseReg);
|
||||
iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg);
|
||||
addrNxt = pLevel->addrNxt;
|
||||
sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
|
||||
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg);
|
||||
@@ -3041,7 +3038,7 @@ static Bitmask codeOneLoopStart(
|
||||
** and store the values of those terms in an array of registers
|
||||
** starting at regBase.
|
||||
*/
|
||||
regBase = codeAllEqualityTerms(pWInfo,pLevel,bRev,nExtraReg,&zStartAff);
|
||||
regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff);
|
||||
assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq );
|
||||
if( zStartAff ) cEndAff = zStartAff[nEq];
|
||||
addrNxt = pLevel->addrNxt;
|
||||
@@ -3318,7 +3315,9 @@ static Bitmask codeOneLoopStart(
|
||||
Expr *pExpr = pWC->a[iTerm].pExpr;
|
||||
if( &pWC->a[iTerm] == pTerm ) continue;
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ) continue;
|
||||
if( pWC->a[iTerm].wtFlags & (TERM_ORINFO) ) continue;
|
||||
testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO );
|
||||
testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL );
|
||||
if( pWC->a[iTerm].wtFlags & (TERM_ORINFO|TERM_VIRTUAL) ) continue;
|
||||
if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
|
||||
pExpr = sqlite3ExprDup(db, pExpr, 0);
|
||||
pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr);
|
||||
@@ -5439,7 +5438,6 @@ WhereInfo *sqlite3WhereBegin(
|
||||
initMaskSet(pMaskSet);
|
||||
whereClauseInit(&pWInfo->sWC, pWInfo);
|
||||
whereSplit(&pWInfo->sWC, pWhere, TK_AND);
|
||||
sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
|
||||
|
||||
/* Special case: a WHERE clause that is constant. Evaluate the
|
||||
** expression and either jump over all of the code or fall thru.
|
||||
@@ -5728,7 +5726,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
sqlite3VdbeSetP4KeyInfo(pParse, pIx);
|
||||
VdbeComment((v, "%s", pIx->zName));
|
||||
}
|
||||
sqlite3CodeVerifySchema(pParse, iDb);
|
||||
if( iDb>=0 ) sqlite3CodeVerifySchema(pParse, iDb);
|
||||
notReady &= ~getMask(&pWInfo->sMaskSet, pTabItem->iCursor);
|
||||
}
|
||||
pWInfo->iTop = sqlite3VdbeCurrentAddr(v);
|
||||
@@ -5839,12 +5837,38 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
|
||||
assert( pWInfo->nLevel<=pTabList->nSrc );
|
||||
for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){
|
||||
int k, last;
|
||||
VdbeOp *pOp;
|
||||
Index *pIdx = 0;
|
||||
struct SrcList_item *pTabItem = &pTabList->a[pLevel->iFrom];
|
||||
Table *pTab = pTabItem->pTab;
|
||||
assert( pTab!=0 );
|
||||
pLoop = pLevel->pWLoop;
|
||||
|
||||
/* For a co-routine, change all OP_Column references to the table of
|
||||
** the co-routine into OP_SCopy of result contained in a register.
|
||||
** OP_Rowid becomes OP_Null.
|
||||
*/
|
||||
if( pTabItem->viaCoroutine ){
|
||||
last = sqlite3VdbeCurrentAddr(v);
|
||||
k = pLevel->addrBody;
|
||||
pOp = sqlite3VdbeGetOp(v, k);
|
||||
for(; k<last; k++, pOp++){
|
||||
if( pOp->p1!=pLevel->iTabCur ) continue;
|
||||
if( pOp->opcode==OP_Column ){
|
||||
pOp->opcode = OP_SCopy;
|
||||
pOp->p1 = pOp->p2 + pTabItem->regResult;
|
||||
pOp->p2 = pOp->p3;
|
||||
pOp->p3 = 0;
|
||||
}else if( pOp->opcode==OP_Rowid ){
|
||||
pOp->opcode = OP_Null;
|
||||
pOp->p1 = 0;
|
||||
pOp->p3 = 0;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Close all of the cursors that were opened by sqlite3WhereBegin.
|
||||
** Except, do not close cursors that will be reused by the OR optimization
|
||||
** (WHERE_OMIT_OPEN_CLOSE). And do not close the OP_OpenWrite cursors
|
||||
@@ -5883,9 +5907,6 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
pIdx = pLevel->u.pCovidx;
|
||||
}
|
||||
if( pIdx && !db->mallocFailed ){
|
||||
int k, last;
|
||||
VdbeOp *pOp;
|
||||
|
||||
last = sqlite3VdbeCurrentAddr(v);
|
||||
k = pLevel->addrBody;
|
||||
pOp = sqlite3VdbeGetOp(v, k);
|
||||
|
||||
+2
-2
@@ -333,14 +333,14 @@ do_test backup-3.$iTest.1 {
|
||||
set iTab 1
|
||||
|
||||
db eval { PRAGMA page_size = 512 }
|
||||
while {[file size test.db] <= $::sqlite_pending_byte} {
|
||||
while {[file_size test.db] <= $::sqlite_pending_byte} {
|
||||
db eval "CREATE TABLE t${iTab}(a, b, c)"
|
||||
incr iTab
|
||||
}
|
||||
|
||||
sqlite3 db2 test2.db
|
||||
db2 eval { PRAGMA page_size = 4096 }
|
||||
while {[file size test2.db] < $::sqlite_pending_byte} {
|
||||
while {[file_size test2.db] < $::sqlite_pending_byte} {
|
||||
db2 eval "CREATE TABLE t${iTab}(a, b, c)"
|
||||
incr iTab
|
||||
}
|
||||
|
||||
+2
-2
@@ -72,7 +72,7 @@ do_test 2.3 {
|
||||
file size test.db
|
||||
} {1024}
|
||||
|
||||
do_test 2.4 { file size test.db2 } 0
|
||||
do_test 2.4 { file_size test.db2 } 0
|
||||
|
||||
db close
|
||||
forcedelete test.db
|
||||
@@ -98,6 +98,6 @@ do_test 3.3 {
|
||||
file size test.db
|
||||
} {1024}
|
||||
|
||||
do_test 3.4 { file size test.db2 } 0
|
||||
do_test 3.4 { file_size test.db2 } 0
|
||||
|
||||
finish_test
|
||||
|
||||
+4
-1
@@ -70,9 +70,12 @@ foreach name $names {
|
||||
sqlite3_errcode $db2
|
||||
} {SQLITE_OK}
|
||||
do_test capi3e-1.2.$i {
|
||||
sqlite3_exec $db2 { CREATE TABLE t1(x) }
|
||||
} {0 {}}
|
||||
do_test capi3e-1.3.$i {
|
||||
sqlite3_close $db2
|
||||
} {SQLITE_OK}
|
||||
do_test capi3e-1.3.$i {
|
||||
do_test capi3e-1.4.$i {
|
||||
file isfile $name
|
||||
} {1}
|
||||
}
|
||||
|
||||
+31
-3
@@ -51,9 +51,12 @@ proc do_temptables_test {tn sql temptables} {
|
||||
set ret ""
|
||||
db eval "EXPLAIN [set sql]" {
|
||||
if {$opcode == "OpenEphemeral" || $opcode == "SorterOpen"} {
|
||||
lappend ret btree
|
||||
} elseif {$opcode == "OpenHash"} {
|
||||
lappend ret hash
|
||||
if {$p5 != "08" && $p5!="00"} { error "p5 = $p5" }
|
||||
if {$p5 == "08"} {
|
||||
lappend ret hash
|
||||
} else {
|
||||
lappend ret btree
|
||||
}
|
||||
}
|
||||
}
|
||||
set ret
|
||||
@@ -194,4 +197,29 @@ do_test 3.1 {
|
||||
}]
|
||||
} {0}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Ticket [fccbde530a6583bf2748400919f1603d5425995c] (2014-01-08)
|
||||
# The logic that computes DISTINCT sometimes thinks that a zeroblob()
|
||||
# and a blob of all zeros are different when they should be the same.
|
||||
#
|
||||
do_execsql_test 4.1 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t2;
|
||||
CREATE TABLE t1(a INTEGER);
|
||||
INSERT INTO t1 VALUES(3);
|
||||
INSERT INTO t1 VALUES(2);
|
||||
INSERT INTO t1 VALUES(1);
|
||||
INSERT INTO t1 VALUES(2);
|
||||
INSERT INTO t1 VALUES(3);
|
||||
INSERT INTO t1 VALUES(1);
|
||||
CREATE TABLE t2(x);
|
||||
INSERT INTO t2
|
||||
SELECT DISTINCT
|
||||
CASE a WHEN 1 THEN x'0000000000'
|
||||
WHEN 2 THEN zeroblob(5)
|
||||
ELSE 'xyzzy' END
|
||||
FROM t1;
|
||||
SELECT quote(x) FROM t2 ORDER BY 1;
|
||||
} {'xyzzy' X'0000000000'}
|
||||
|
||||
finish_test
|
||||
|
||||
+10
-1
@@ -64,6 +64,7 @@ if {$tcl_platform(platform) == "unix"} {
|
||||
do_test 1.1 {
|
||||
forcedelete file:test.db test.db
|
||||
set DB [sqlite3_open_v2 file:test.db [concat $flags SQLITE_OPEN_URI] ""]
|
||||
sqlite3_exec $DB {CREATE TABLE t1(x)}
|
||||
list [file exists file:test.db] [file exists test.db]
|
||||
} {0 1}
|
||||
do_test 1.2 {
|
||||
@@ -71,12 +72,14 @@ if {$tcl_platform(platform) == "unix"} {
|
||||
set STMT [sqlite3_prepare $DB "ATTACH 'file:test.db2' AS aux" -1 dummy]
|
||||
sqlite3_step $STMT
|
||||
sqlite3_finalize $STMT
|
||||
sqlite3_exec $DB {CREATE TABLE aux.t1(x)}
|
||||
list [file exists file:test.db2] [file exists test.db2]
|
||||
} {0 1}
|
||||
sqlite3_close $DB
|
||||
do_test 1.3 {
|
||||
forcedelete file:test.db test.db
|
||||
set DB [sqlite3_open_v2 file:test.db [concat $flags] ""]
|
||||
sqlite3_exec $DB {CREATE TABLE t1(x)}
|
||||
list [file exists file:test.db] [file exists test.db]
|
||||
} {1 0}
|
||||
do_test 1.4 {
|
||||
@@ -84,6 +87,7 @@ if {$tcl_platform(platform) == "unix"} {
|
||||
set STMT [sqlite3_prepare $DB "ATTACH 'file:test.db2' AS aux" -1 dummy]
|
||||
sqlite3_step $STMT
|
||||
sqlite3_finalize $STMT
|
||||
sqlite3_exec $DB {CREATE TABLE aux.t1(x)}
|
||||
list [file exists file:test.db2] [file exists test.db2]
|
||||
} {1 0}
|
||||
sqlite3_close $DB
|
||||
@@ -96,6 +100,7 @@ if {$tcl_platform(platform) == "unix"} {
|
||||
do_test 1.5 {
|
||||
forcedelete file:test.db test.db
|
||||
set DB [sqlite3_open_v2 file:test.db [concat $flags SQLITE_OPEN_URI] ""]
|
||||
sqlite3_exec $DB {CREATE TABLE t1(x)}
|
||||
list [file exists file:test.db] [file exists test.db]
|
||||
} {0 1}
|
||||
do_test 1.6 {
|
||||
@@ -103,12 +108,14 @@ if {$tcl_platform(platform) == "unix"} {
|
||||
set STMT [sqlite3_prepare $DB "ATTACH 'file:test.db2' AS aux" -1 dummy]
|
||||
sqlite3_step $STMT
|
||||
sqlite3_finalize $STMT
|
||||
sqlite3_exec $DB {CREATE TABLE aux.t1(x)}
|
||||
list [file exists file:test.db2] [file exists test.db2]
|
||||
} {0 1}
|
||||
sqlite3_close $DB
|
||||
do_test 1.7 {
|
||||
forcedelete file:test.db test.db
|
||||
set DB [sqlite3_open_v2 file:test.db [concat $flags] ""]
|
||||
sqlite3_exec $DB {CREATE TABLE t1(x)}
|
||||
list [file exists file:test.db] [file exists test.db]
|
||||
} {0 1}
|
||||
do_test 1.8 {
|
||||
@@ -116,6 +123,7 @@ if {$tcl_platform(platform) == "unix"} {
|
||||
set STMT [sqlite3_prepare $DB "ATTACH 'file:test.db2' AS aux" -1 dummy]
|
||||
sqlite3_step $STMT
|
||||
sqlite3_finalize $STMT
|
||||
sqlite3_exec $DB {CREATE TABLE aux.t1(x)}
|
||||
list [file exists file:test.db2] [file exists test.db2]
|
||||
} {0 1}
|
||||
sqlite3_close $DB
|
||||
@@ -314,6 +322,7 @@ foreach {tn uri read write create} {
|
||||
#
|
||||
forcedelete test.db
|
||||
sqlite3 db test.db
|
||||
db eval {CREATE TABLE t1(x)}
|
||||
db close
|
||||
foreach {tn uri flags error} {
|
||||
1 {file:test.db?mode=ro} ro {not an error}
|
||||
@@ -331,7 +340,7 @@ foreach {tn uri flags error} {
|
||||
set f(ro) [list SQLITE_OPEN_READONLY SQLITE_OPEN_URI]
|
||||
set f(rw) [list SQLITE_OPEN_READWRITE SQLITE_OPEN_URI]
|
||||
set f(rwc) [list SQLITE_OPEN_READWRITE SQLITE_OPEN_CREATE SQLITE_OPEN_URI]
|
||||
|
||||
breakpoint
|
||||
set DB [sqlite3_open_v2 $uri $f($flags) ""]
|
||||
set e [sqlite3_errmsg $DB]
|
||||
sqlite3_close $DB
|
||||
|
||||
+14
-12
@@ -69,18 +69,20 @@ proc pagerChangeCounter {filename new {fd ""}} {
|
||||
}
|
||||
|
||||
proc readPagerChangeCounter {filename} {
|
||||
set fd [open $filename RDONLY]
|
||||
fconfigure $fd -translation binary -encoding binary
|
||||
|
||||
seek $fd 24
|
||||
foreach {a b c d} [list 0 0 0 0] {}
|
||||
binary scan [read $fd 4] cccc a b c d
|
||||
set ret [expr ($a&0x000000FF)<<24]
|
||||
incr ret [expr ($b&0x000000FF)<<16]
|
||||
incr ret [expr ($c&0x000000FF)<<8]
|
||||
incr ret [expr ($d&0x000000FF)<<0]
|
||||
|
||||
close $fd
|
||||
if {[file exists $filename]} {
|
||||
set fd [open $filename RDONLY]
|
||||
fconfigure $fd -translation binary -encoding binary
|
||||
seek $fd 24
|
||||
foreach {a b c d} [list 0 0 0 0] {}
|
||||
binary scan [read $fd 4] cccc a b c d
|
||||
set ret [expr ($a&0x000000FF)<<24]
|
||||
incr ret [expr ($b&0x000000FF)<<16]
|
||||
incr ret [expr ($c&0x000000FF)<<8]
|
||||
incr ret [expr ($d&0x000000FF)<<0]
|
||||
close $fd
|
||||
} else {
|
||||
set ret 0
|
||||
}
|
||||
return $ret
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ ifcapable !subquery {
|
||||
proc nEphemeral {sql} {
|
||||
set nEph 0
|
||||
foreach op [execsql "EXPLAIN $sql"] {
|
||||
if {$op eq "OpenEphemeral" || $op eq "OpenHash"} {incr nEph}
|
||||
if {$op eq "OpenEphemeral"} {incr nEph}
|
||||
}
|
||||
set nEph
|
||||
}
|
||||
|
||||
+3
-3
@@ -65,17 +65,17 @@ do_test in5-2.4 {
|
||||
}
|
||||
} {12a 56e}
|
||||
do_test in5-2.5.1 {
|
||||
regexp {Open(Ephemeral|Hash)} [db eval {
|
||||
regexp {OpenEphemeral} [db eval {
|
||||
EXPLAIN SELECT d FROM t2 WHERE a IN t3x AND b IN t1y AND c IN t1z
|
||||
}]
|
||||
} {1}
|
||||
do_test in5-2.5.2 {
|
||||
regexp {Open(Ephemeral|Hash)} [db eval {
|
||||
regexp {OpenEphemeral} [db eval {
|
||||
EXPLAIN SELECT d FROM t2 WHERE a IN t1x AND b IN t3y AND c IN t1z
|
||||
}]
|
||||
} {1}
|
||||
do_test in5-2.5.3 {
|
||||
regexp {Open(Ephemeral|Hash)} [db eval {
|
||||
regexp {OpenEphemeral} [db eval {
|
||||
EXPLAIN SELECT d FROM t2 WHERE a IN t1x AND b IN t1y AND c IN t3z
|
||||
}]
|
||||
} {1}
|
||||
|
||||
@@ -38,7 +38,7 @@ do_test incrvacuum-1.2.0 {
|
||||
# File size is sometimes 1 instead of 0 due to the hack we put in
|
||||
# to work around ticket #3260. Search for comments on #3260 in
|
||||
# os_unix.c.
|
||||
expr {[file size test.db] > 1}
|
||||
expr {[file_size test.db] > 1}
|
||||
} {0}
|
||||
do_test incrvacuum-1.2 {
|
||||
# This command will create the database.
|
||||
@@ -700,7 +700,7 @@ do_test incrvacuum-13.1 {
|
||||
# File size is sometimes 1 instead of 0 due to the hack we put in
|
||||
# to work around ticket #3260. Search for comments on #3260 in
|
||||
# os_unix.c.
|
||||
expr {[file size test.db]>1}
|
||||
expr {[file_size test.db]>1}
|
||||
} {0}
|
||||
do_test incrvacuum-13.2 {
|
||||
set ::STMT [sqlite3_prepare $::DB {PRAGMA auto_vacuum = 2} -1 DUMMY]
|
||||
|
||||
+1
-1
@@ -391,7 +391,7 @@ ifcapable pager_pragmas {
|
||||
}
|
||||
# File size might be 1 due to the hack to work around ticket #3260.
|
||||
# Search for #3260 in os_unix.c for additional information.
|
||||
expr {[file size test.db]>1}
|
||||
expr {[file_size test.db]>1}
|
||||
} {0}
|
||||
do_test io-3.2 {
|
||||
execsql { CREATE TABLE abc(a, b) }
|
||||
|
||||
+1
-1
@@ -1373,7 +1373,7 @@ do_test pager1-9.4.1 {
|
||||
list [B step 10000] [B finish]
|
||||
} {SQLITE_DONE SQLITE_OK}
|
||||
do_test pager1-9.4.2 {
|
||||
list [file size test.db2] [file size test.db]
|
||||
list [file_size test.db2] [file_size test.db]
|
||||
} {1024 0}
|
||||
db2 close
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ test_suite "veryquick" -prefix "" -description {
|
||||
This test suite is the same as the "quick" tests, except that some files
|
||||
that test malloc and IO errors are omitted.
|
||||
} -files [
|
||||
test_set $allquicktests -exclude *malloc* *ioerr* *fault*
|
||||
test_set $allquicktests -exclude *malloc* *ioerr* *fault*
|
||||
]
|
||||
|
||||
test_suite "mmap" -prefix "mm-" -description {
|
||||
|
||||
@@ -1292,5 +1292,22 @@ do_test selectA-3.97 {
|
||||
ORDER BY y COLLATE NOCASE DESC,x,z)))
|
||||
}
|
||||
} {MAD}
|
||||
do_execsql_test selectA-3.98 {
|
||||
WITH RECURSIVE
|
||||
xyz(n) AS (
|
||||
SELECT upper((SELECT x FROM (
|
||||
SELECT x,y,z FROM t2
|
||||
INTERSECT SELECT a,b,c FROM t3
|
||||
EXCEPT SELECT c,b,a FROM t1
|
||||
UNION SELECT a,b,c FROM t3
|
||||
INTERSECT SELECT a,b,c FROM t3
|
||||
EXCEPT SELECT c,b,a FROM t1
|
||||
UNION SELECT a,b,c FROM t3
|
||||
ORDER BY y COLLATE NOCASE DESC,x,z)))
|
||||
UNION ALL
|
||||
SELECT n || '+' FROM xyz WHERE length(n)<5
|
||||
)
|
||||
SELECT n FROM xyz ORDER BY +n;
|
||||
} {MAD MAD+ MAD++}
|
||||
|
||||
finish_test
|
||||
|
||||
+1
-1
@@ -105,7 +105,7 @@ do_test shell1-1.7.1 {
|
||||
set rc [lindex $res 0]
|
||||
list $rc \
|
||||
[regexp {SQLite version} $res] \
|
||||
[regexp {Enter SQL statements} $res]
|
||||
[regexp {Enter ".help" for usage hints} $res]
|
||||
} {0 1 1}
|
||||
|
||||
# -batch force batch I/O
|
||||
|
||||
@@ -737,6 +737,161 @@ void testset_main(void){
|
||||
speedtest1_end_test();
|
||||
}
|
||||
|
||||
/*
|
||||
** A testset for common table expressions. This exercises code
|
||||
** for views, subqueries, co-routines, etc.
|
||||
*/
|
||||
void testset_cte(void){
|
||||
static const char *azPuzzle[] = {
|
||||
/* Easy */
|
||||
"534...9.."
|
||||
"67.195..."
|
||||
".98....6."
|
||||
"8...6...3"
|
||||
"4..8.3..1"
|
||||
"....2...6"
|
||||
".6....28."
|
||||
"...419..5"
|
||||
"...28..79",
|
||||
|
||||
/* Medium */
|
||||
"53....9.."
|
||||
"6..195..."
|
||||
".98....6."
|
||||
"8...6...3"
|
||||
"4..8.3..1"
|
||||
"....2...6"
|
||||
".6....28."
|
||||
"...419..5"
|
||||
"....8..79",
|
||||
|
||||
/* Hard */
|
||||
"53......."
|
||||
"6..195..."
|
||||
".98....6."
|
||||
"8...6...3"
|
||||
"4..8.3..1"
|
||||
"....2...6"
|
||||
".6....28."
|
||||
"...419..5"
|
||||
"....8..79",
|
||||
};
|
||||
const char *zPuz;
|
||||
double rSpacing;
|
||||
int nElem;
|
||||
|
||||
if( g.szTest<25 ){
|
||||
zPuz = azPuzzle[0];
|
||||
}else if( g.szTest<70 ){
|
||||
zPuz = azPuzzle[1];
|
||||
}else{
|
||||
zPuz = azPuzzle[2];
|
||||
}
|
||||
speedtest1_begin_test(100, "Sudoku with recursive 'digits'");
|
||||
speedtest1_prepare(
|
||||
"WITH RECURSIVE\n"
|
||||
" input(sud) AS (VALUES(?1)),\n"
|
||||
" digits(z,lp) AS (\n"
|
||||
" VALUES('1', 1)\n"
|
||||
" UNION ALL\n"
|
||||
" SELECT CAST(lp+1 AS TEXT), lp+1 FROM digits WHERE lp<9\n"
|
||||
" ),\n"
|
||||
" x(s, ind) AS (\n"
|
||||
" SELECT sud, instr(sud, '.') FROM input\n"
|
||||
" UNION ALL\n"
|
||||
" SELECT\n"
|
||||
" substr(s, 1, ind-1) || z || substr(s, ind+1),\n"
|
||||
" instr( substr(s, 1, ind-1) || z || substr(s, ind+1), '.' )\n"
|
||||
" FROM x, digits AS z\n"
|
||||
" WHERE ind>0\n"
|
||||
" AND NOT EXISTS (\n"
|
||||
" SELECT 1\n"
|
||||
" FROM digits AS lp\n"
|
||||
" WHERE z.z = substr(s, ((ind-1)/9)*9 + lp, 1)\n"
|
||||
" OR z.z = substr(s, ((ind-1)%%9) + (lp-1)*9 + 1, 1)\n"
|
||||
" OR z.z = substr(s, (((ind-1)/3) %% 3) * 3\n"
|
||||
" + ((ind-1)/27) * 27 + lp\n"
|
||||
" + ((lp-1) / 3) * 6, 1)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
"SELECT s FROM x WHERE ind=0;"
|
||||
);
|
||||
sqlite3_bind_text(g.pStmt, 1, zPuz, -1, SQLITE_STATIC);
|
||||
speedtest1_run();
|
||||
speedtest1_end_test();
|
||||
|
||||
speedtest1_begin_test(200, "Sudoku with VALUES 'digits'");
|
||||
speedtest1_prepare(
|
||||
"WITH RECURSIVE\n"
|
||||
" input(sud) AS (VALUES(?1)),\n"
|
||||
" digits(z,lp) AS (VALUES('1',1),('2',2),('3',3),('4',4),('5',5),\n"
|
||||
" ('6',6),('7',7),('8',8),('9',9)),\n"
|
||||
" x(s, ind) AS (\n"
|
||||
" SELECT sud, instr(sud, '.') FROM input\n"
|
||||
" UNION ALL\n"
|
||||
" SELECT\n"
|
||||
" substr(s, 1, ind-1) || z || substr(s, ind+1),\n"
|
||||
" instr( substr(s, 1, ind-1) || z || substr(s, ind+1), '.' )\n"
|
||||
" FROM x, digits AS z\n"
|
||||
" WHERE ind>0\n"
|
||||
" AND NOT EXISTS (\n"
|
||||
" SELECT 1\n"
|
||||
" FROM digits AS lp\n"
|
||||
" WHERE z.z = substr(s, ((ind-1)/9)*9 + lp, 1)\n"
|
||||
" OR z.z = substr(s, ((ind-1)%%9) + (lp-1)*9 + 1, 1)\n"
|
||||
" OR z.z = substr(s, (((ind-1)/3) %% 3) * 3\n"
|
||||
" + ((ind-1)/27) * 27 + lp\n"
|
||||
" + ((lp-1) / 3) * 6, 1)\n"
|
||||
" )\n"
|
||||
" )\n"
|
||||
"SELECT s FROM x WHERE ind=0;"
|
||||
);
|
||||
sqlite3_bind_text(g.pStmt, 1, zPuz, -1, SQLITE_STATIC);
|
||||
speedtest1_run();
|
||||
speedtest1_end_test();
|
||||
|
||||
rSpacing = 5.0/g.szTest;
|
||||
speedtest1_begin_test(300, "Mandelbrot Set with spacing=%f", rSpacing);
|
||||
speedtest1_prepare(
|
||||
"WITH RECURSIVE \n"
|
||||
" xaxis(x) AS (VALUES(-2.0) UNION ALL SELECT x+?1 FROM xaxis WHERE x<1.2),\n"
|
||||
" yaxis(y) AS (VALUES(-1.0) UNION ALL SELECT y+?2 FROM yaxis WHERE y<1.0),\n"
|
||||
" m(iter, cx, cy, x, y) AS (\n"
|
||||
" SELECT 0, x, y, 0.0, 0.0 FROM xaxis, yaxis\n"
|
||||
" UNION ALL\n"
|
||||
" SELECT iter+1, cx, cy, x*x-y*y + cx, 2.0*x*y + cy FROM m \n"
|
||||
" WHERE (x*x + y*y) < 4.0 AND iter<28\n"
|
||||
" ),\n"
|
||||
" m2(iter, cx, cy) AS (\n"
|
||||
" SELECT max(iter), cx, cy FROM m GROUP BY cx, cy\n"
|
||||
" ),\n"
|
||||
" a(t) AS (\n"
|
||||
" SELECT group_concat( substr(' .+*#', 1+min(iter/7,4), 1), '') \n"
|
||||
" FROM m2 GROUP BY cy\n"
|
||||
" )\n"
|
||||
"SELECT group_concat(rtrim(t),x'0a') FROM a;"
|
||||
);
|
||||
sqlite3_bind_double(g.pStmt, 1, rSpacing*.05);
|
||||
sqlite3_bind_double(g.pStmt, 2, rSpacing);
|
||||
speedtest1_run();
|
||||
speedtest1_end_test();
|
||||
|
||||
nElem = 10000*g.szTest;
|
||||
speedtest1_begin_test(400, "EXCEPT operator on %d-element tables", nElem);
|
||||
speedtest1_prepare(
|
||||
"WITH RECURSIVE \n"
|
||||
" t1(x) AS (VALUES(2) UNION ALL SELECT x+2 FROM t1 WHERE x<%d),\n"
|
||||
" t2(y) AS (VALUES(3) UNION ALL SELECT y+3 FROM t2 WHERE y<%d)\n"
|
||||
"SELECT count(x), avg(x) FROM (\n"
|
||||
" SELECT x FROM t1 EXCEPT SELECT y FROM t2 ORDER BY 1\n"
|
||||
");",
|
||||
nElem, nElem
|
||||
);
|
||||
speedtest1_run();
|
||||
speedtest1_end_test();
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
** A testset used for debugging speedtest1 itself.
|
||||
*/
|
||||
@@ -945,6 +1100,8 @@ int main(int argc, char **argv){
|
||||
testset_main();
|
||||
}else if( strcmp(zTSet,"debug1")==0 ){
|
||||
testset_debug1();
|
||||
}else if( strcmp(zTSet,"cte")==0 ){
|
||||
testset_cte();
|
||||
}else{
|
||||
fatal_error("unknown testset: \"%s\"\n", zTSet);
|
||||
}
|
||||
|
||||
+4
-2
@@ -236,9 +236,10 @@ catch { db close }
|
||||
forcedelete test.db test.db2
|
||||
|
||||
do_test 8.1 {
|
||||
close [open test.db w]
|
||||
sqlite3 db test.db
|
||||
file_control_chunksize_test db main 4096
|
||||
file size test.db
|
||||
file_size test.db
|
||||
} {0}
|
||||
foreach {tn hint size} {
|
||||
1 1000 4096
|
||||
@@ -249,13 +250,14 @@ foreach {tn hint size} {
|
||||
} {
|
||||
do_test 8.2.$tn {
|
||||
file_control_sizehint_test db main $hint
|
||||
file size test.db
|
||||
file_size test.db
|
||||
} $size
|
||||
}
|
||||
|
||||
do_test 8.3 {
|
||||
db close
|
||||
forcedelete test.db test.db2
|
||||
close [open test.db w]
|
||||
sqlite3 db test.db
|
||||
file_control_chunksize_test db main 16
|
||||
file size test.db
|
||||
|
||||
@@ -185,6 +185,16 @@ proc forcecopy {from to} {
|
||||
do_copy_file true $from $to
|
||||
}
|
||||
|
||||
# If file $zFile exists in the file system, return its size in bytes.
|
||||
# Otherwise, return zero.
|
||||
proc file_size {zFile} {
|
||||
if {[file exists $zFile]} {
|
||||
return [file size $zFile]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
proc do_copy_file {force from to} {
|
||||
set nRetry [getFileRetries] ;# Maximum number of retries.
|
||||
set nDelay [getFileRetryDelay] ;# Delay in ms before retrying.
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# 2014-02-11
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library. Specifically,
|
||||
# it tests that ticket [4c86b126f22ad548fee0125337bdc9366912d9ac].
|
||||
#
|
||||
# When SQLite is compiled using SQLITE_ENABLE_STAT3 or SQLITE_ENABLE_STAT4,
|
||||
# it gets the wrong answer...
|
||||
#
|
||||
# The problem was introduced in SQLite 3.8.1.
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
do_execsql_test tkt-4c86b126f2-1.1 {
|
||||
CREATE TABLE nodes(
|
||||
local_relpath TEXT PRIMARY KEY,
|
||||
moved_to TEXT
|
||||
);
|
||||
INSERT INTO nodes VALUES('A',NULL);
|
||||
INSERT INTO nodes VALUES('A/B',NULL);
|
||||
INSERT INTO nodes VALUES('',NULL);
|
||||
INSERT INTO nodes VALUES('A/B/C-move',NULL);
|
||||
INSERT INTO nodes VALUES('A/B/C','A/B/C-move');
|
||||
INSERT INTO nodes VALUES('A/B-move',NULL);
|
||||
INSERT INTO nodes VALUES('A/B-move/C-move',NULL);
|
||||
INSERT INTO nodes VALUES('A/B-move/C','x');
|
||||
SELECT local_relpath, moved_to
|
||||
FROM nodes
|
||||
WHERE (local_relpath = 'A/B' OR
|
||||
((local_relpath > 'A/B/') AND (local_relpath < 'A/B0')))
|
||||
AND moved_to IS NOT NULL;
|
||||
} {A/B/C A/B/C-move}
|
||||
|
||||
do_execsql_test tkt-4c86b126f2-2.1 {
|
||||
CREATE TABLE t1(x TEXT UNIQUE, y TEXT UNIQUE, z);
|
||||
INSERT INTO t1 VALUES('ghi','jkl','y');
|
||||
SELECT * FROM t1 WHERE (x='ghi' OR y='jkl') AND z IS NOT NULL;
|
||||
} {ghi jkl y}
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -46,6 +46,7 @@ do_test tkt4018-1.1 {
|
||||
# connection to test.db 10000 times. If file-descriptors are not being
|
||||
# reused, then the process will quickly exceed its maximum number of
|
||||
# file descriptors (1024 by default on linux).
|
||||
breakpoint
|
||||
do_test tkt4018-1.2 {
|
||||
for {set i 0} {$i < 10000} {incr i} {
|
||||
sqlite3 db2 test.db
|
||||
|
||||
@@ -76,6 +76,7 @@ foreach {tn uri file} {
|
||||
forcedelete $file
|
||||
do_test 1.$tn.1 { file exists $file } 0
|
||||
set DB [sqlite3_open $uri]
|
||||
sqlite3_exec $DB {CREATE TABLE t1(x)}
|
||||
do_test 1.$tn.2 { file exists $file } 1
|
||||
sqlite3_close $DB
|
||||
forcedelete $file
|
||||
@@ -83,6 +84,7 @@ foreach {tn uri file} {
|
||||
do_test 1.$tn.3 { file exists $file } 0
|
||||
sqlite3 db xxx.db
|
||||
catchsql { ATTACH $uri AS aux }
|
||||
db eval {CREATE TABLE aux.t1(x)}
|
||||
do_test 1.$tn.4 { file exists $file } 1
|
||||
db close
|
||||
}
|
||||
|
||||
+2
-2
@@ -56,8 +56,8 @@ do_faultsim_test wal4-2 -prep {
|
||||
if { $testrc==0 && [file exists test.db-wal] } {
|
||||
error "Wal file was not deleted"
|
||||
}
|
||||
if { [file size test.db]!=0 } {
|
||||
error "Db file grew to [file size test.db] bytes"
|
||||
if { [file_size test.db]!=0 } {
|
||||
error "Db file grew to [file_size test.db] bytes"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -210,7 +210,7 @@ do_test where8-3.4 {
|
||||
|
||||
do_test where8-3.5 {
|
||||
execsql_status {
|
||||
SELECT a, d FROM t1, t2 WHERE (a = 2 OR a = 3) AND (d = a OR e = 'sixteen')
|
||||
SELECT a, d FROM t1, t2 WHERE (a = 2 OR a = 3) AND (d = +a OR e = 'sixteen')
|
||||
ORDER BY +a, +d;
|
||||
}
|
||||
} {2 2 2 4 3 3 3 4 0 1}
|
||||
@@ -222,7 +222,7 @@ do_test where8-3.6 {
|
||||
execsql_status {
|
||||
SELECT a, d
|
||||
FROM t1, t2
|
||||
WHERE (a = 2 OR a = 3) AND (d = a OR e = 'sixteen')
|
||||
WHERE (a = 2 OR a = 3) AND (d = +a OR e = 'sixteen')
|
||||
ORDER BY t1.rowid
|
||||
}
|
||||
} {2 2 2 4 3 3 3 4 0 1}
|
||||
|
||||
+12
-1
@@ -816,5 +816,16 @@ do_execsql_test 11.3 {
|
||||
.........Noland
|
||||
.........Olivia}}
|
||||
|
||||
finish_test
|
||||
#--------------------------------------------------------------------------
|
||||
# Ticket [31a19d11b97088296ac104aaff113a9790394927] (2014-02-09)
|
||||
# Name resolution issue with compound SELECTs and Common Table Expressions
|
||||
#
|
||||
do_execsql_test 12.1 {
|
||||
WITH RECURSIVE
|
||||
t1(x) AS (VALUES(2) UNION ALL SELECT x+2 FROM t1 WHERE x<20),
|
||||
t2(y) AS (VALUES(3) UNION ALL SELECT y+3 FROM t2 WHERE y<20)
|
||||
SELECT x FROM t1 EXCEPT SELECT y FROM t2 ORDER BY 1;
|
||||
} {2 4 8 10 14 16 20}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
Reference in New Issue
Block a user