Compare commits
103 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6f04b95f02 | |||
| 224f66fba3 | |||
| 47676fedf6 | |||
| 5fac42002a | |||
| 3f9cd2ae75 | |||
| 1fa85a15df | |||
| 7f59475fda | |||
| 7190e07fc0 | |||
| b5f68b0c8c | |||
| 1868cbc78c | |||
| 070865da8d | |||
| 9a01c16df8 | |||
| 89bc021850 | |||
| d5e4547084 | |||
| 47b927d2c3 | |||
| 2a702db1cf | |||
| d79e9c5802 | |||
| 290ea4053a | |||
| a256c1a4b3 | |||
| 094b7587fc | |||
| b202366509 | |||
| 09fe614372 | |||
| 1b4b334abb | |||
| 0d4a0cdf18 | |||
| 19be738b42 | |||
| 2c77be054a | |||
| 9338642ca6 | |||
| b87875ac40 | |||
| dcb5fa06e8 | |||
| ce00a83785 | |||
| ac68ced162 | |||
| c964c39fb0 | |||
| e1b62513e4 | |||
| 0f7e08e0e2 | |||
| 21236679d1 | |||
| ef1bd970ef | |||
| bbbb0e8053 | |||
| 2c7e9bfc50 | |||
| 1bcbc6a6d4 | |||
| aa1776f093 | |||
| 55fcab39be | |||
| 0425f18959 | |||
| dbb3c98ad1 | |||
| de1a8b8c69 | |||
| dad19c3204 | |||
| 202ca3e06b | |||
| 0b9dadacd8 | |||
| af8641bd45 | |||
| d16546da78 | |||
| fd8c88de9d | |||
| 9b2fc61d25 | |||
| ebf10b1fb4 | |||
| 17566ee243 | |||
| d2022b0118 | |||
| bb933ef6e7 | |||
| d793f44723 | |||
| ec3e6b10f4 | |||
| 5bbb7198d1 | |||
| 93307e9d06 | |||
| 0c2df17691 | |||
| 9948e95674 | |||
| 7b65ad31e1 | |||
| e19f8327f8 | |||
| c7c9f7110b | |||
| 1617577e77 | |||
| ad1ca9a792 | |||
| ac1f10458b | |||
| 20b859530b | |||
| f201496c6a | |||
| 0a30592c1e | |||
| cb4f870884 | |||
| 501932ca68 | |||
| 7a909855f2 | |||
| d673cddad6 | |||
| d9f158e7b2 | |||
| d2b637c2af | |||
| 2b53e00f73 | |||
| 66e810247e | |||
| d1a01edac9 | |||
| 10f468f37a | |||
| b1fba2868b | |||
| e09f43f8b7 | |||
| 76694c3ae5 | |||
| f93cd949a0 | |||
| 3630a408f2 | |||
| 5cc1023e1c | |||
| 1fd522ff49 | |||
| 14da87f8c5 | |||
| 380d685133 | |||
| c8606e416a | |||
| 399af1d2c2 | |||
| 79353dbd5f | |||
| 83b301b0af | |||
| 707f1c560a | |||
| c138dafe88 | |||
| 6bc69a2d4b | |||
| 5c82f4df9f | |||
| f37139f65b | |||
| 64ff26f741 | |||
| 2365bac1e2 | |||
| 2bea7cde6e | |||
| c4650bb33d | |||
| e73e067187 |
@@ -940,6 +940,9 @@ showdb$(TEXE): $(TOP)/tool/showdb.c sqlite3.c
|
||||
wordcount$(TEXE): $(TOP)/test/wordcount.c sqlite3.c
|
||||
$(LTLINK) -o $@ $(TOP)/test/wordcount.c sqlite3.c $(TLIBS)
|
||||
|
||||
speedtest1$(TEXE): $(TOP)/test/wordcount.c sqlite3.lo
|
||||
$(LTLINK) -o $@ $(TOP)/test/speedtest1.c sqlite3.lo $(TLIBS)
|
||||
|
||||
# Standard install and cleanup targets
|
||||
#
|
||||
lib_install: libsqlite3.la
|
||||
|
||||
+9
-5
@@ -162,7 +162,7 @@ RC = rc.exe
|
||||
!IFDEF NCC
|
||||
NCC = $(NCC:\\=\)
|
||||
!ELSEIF $(XCOMPILE)!=0
|
||||
NCC = "$(VCINSTALLDIR)\bin\cl.exe"
|
||||
NCC = "$(VCINSTALLDIR)\bin\$(CC)"
|
||||
NCC = $(NCC:\\=\)
|
||||
!ELSE
|
||||
NCC = $(CC)
|
||||
@@ -1334,13 +1334,17 @@ sqlite3_analyzer.exe: sqlite3_analyzer.c $(LIBRESOBJS)
|
||||
$(LTLINK) -DBUILD_sqlite -DTCLSH=2 -I$(TCLINCDIR) sqlite3_analyzer.c \
|
||||
/link $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS)
|
||||
|
||||
showdb.exe: $(TOP)/tool/showdb.c sqlite3.c
|
||||
showdb.exe: $(TOP)\tool\showdb.c sqlite3.c
|
||||
$(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o $@ \
|
||||
$(TOP)/tool/showdb.c sqlite3.c
|
||||
$(TOP)\tool\showdb.c sqlite3.c
|
||||
|
||||
wordcount.exe: $(TOP)/test/wordcount.c sqlite3.c
|
||||
wordcount.exe: $(TOP)\test\wordcount.c sqlite3.c
|
||||
$(LTLINK) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o $@ \
|
||||
$(TOP)/test/wordcount.c sqlite3.c
|
||||
$(TOP)\test\wordcount.c sqlite3.c
|
||||
|
||||
speedtest1.exe: $(TOP)\test\speedtest1.c sqlite3.c
|
||||
$(LTLINK) -DSQLITE_OMIT_LOAD_EXTENSION -o $@ \
|
||||
$(TOP)\test\speedtest1.c sqlite3.c
|
||||
|
||||
clean:
|
||||
del /Q *.lo *.ilk *.lib *.obj *.pdb sqlite3.exe libsqlite3.lib
|
||||
|
||||
@@ -28,7 +28,6 @@ END {
|
||||
printf "#define TK_%-29s %4d\n", "COLUMN", ++max
|
||||
printf "#define TK_%-29s %4d\n", "AGG_FUNCTION", ++max
|
||||
printf "#define TK_%-29s %4d\n", "AGG_COLUMN", ++max
|
||||
printf "#define TK_%-29s %4d\n", "CONST_FUNC", ++max
|
||||
printf "#define TK_%-29s %4d\n", "UMINUS", ++max
|
||||
printf "#define TK_%-29s %4d\n", "UPLUS", ++max
|
||||
}
|
||||
|
||||
+6
-3
@@ -333,6 +333,9 @@ int sqlite3Fts3PutVarint(char *p, sqlite_int64 v){
|
||||
#define GETVARINT_STEP(v, ptr, shift, mask1, mask2, var, ret) \
|
||||
v = (v & mask1) | ( (*ptr++) << shift ); \
|
||||
if( (v & mask2)==0 ){ var = v; return ret; }
|
||||
#define GETVARINT_INIT(v, ptr, shift, mask1, mask2, var, ret) \
|
||||
v = (*ptr++); \
|
||||
if( (v & mask2)==0 ){ var = v; return ret; }
|
||||
|
||||
/*
|
||||
** Read a 64-bit variable-length integer from memory starting at p[0].
|
||||
@@ -345,7 +348,7 @@ int sqlite3Fts3GetVarint(const char *p, sqlite_int64 *v){
|
||||
u64 b;
|
||||
int shift;
|
||||
|
||||
GETVARINT_STEP(a, p, 0, 0x00, 0x80, *v, 1);
|
||||
GETVARINT_INIT(a, p, 0, 0x00, 0x80, *v, 1);
|
||||
GETVARINT_STEP(a, p, 7, 0x7F, 0x4000, *v, 2);
|
||||
GETVARINT_STEP(a, p, 14, 0x3FFF, 0x200000, *v, 3);
|
||||
GETVARINT_STEP(a, p, 21, 0x1FFFFF, 0x10000000, *v, 4);
|
||||
@@ -357,7 +360,7 @@ int sqlite3Fts3GetVarint(const char *p, sqlite_int64 *v){
|
||||
if( (c & 0x80)==0 ) break;
|
||||
}
|
||||
*v = b;
|
||||
return p - pStart;
|
||||
return (int)(p - pStart);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -368,7 +371,7 @@ int sqlite3Fts3GetVarint32(const char *p, int *pi){
|
||||
u32 a;
|
||||
|
||||
#ifndef fts3GetVarint32
|
||||
GETVARINT_STEP(a, p, 0, 0x00, 0x80, *pi, 1);
|
||||
GETVARINT_INIT(a, p, 0, 0x00, 0x80, *pi, 1);
|
||||
#else
|
||||
a = (*p++);
|
||||
assert( a & 0x80 );
|
||||
|
||||
@@ -630,6 +630,9 @@ wordcount$(EXE): $(TOP)/test/wordcount.c sqlite3.c
|
||||
$(TCC) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -o wordcount$(EXE) \
|
||||
$(TOP)/test/wordcount.c sqlite3.c
|
||||
|
||||
speedtest1$(EXE): $(TOP)/test/speedtest1.c sqlite3.o
|
||||
$(TCC) -o speedtest1$(EXE) $(TOP)/test/speedtest1.c sqlite3.o $(THREADLIB)
|
||||
|
||||
# This target will fail if the SQLite amalgamation contains any exported
|
||||
# symbols that do not begin with "sqlite3_". It is run as part of the
|
||||
# releasetest.tcl script.
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
C Make\ssure\sone-pass\sDELETE\sfor\sWITHOUT\sROWID\stables\scorrectly\spositions\sthe\nPRIMARY\sKEY\scursor.\s\sMake\sthe\ssame\sfix\sfor\sUPDATE.
|
||||
D 2013-11-17T02:42:02.540
|
||||
C Version\s3.8.2
|
||||
D 2013-12-06T14:53:30.888
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 8a07bebafbfda0eb67728f4bd15a36201662d1a1
|
||||
F Makefile.in e1a9b4258bbde53f5636f4e238c65b7e11459e2b
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
F Makefile.msc 19243469fcd1073319ea5b7db97609c1cfb3b1c0
|
||||
F Makefile.msc bb1f271c8ee9773489c89be00f3f8ad7ed7ae8e0
|
||||
F Makefile.vxworks db21ed42a01d5740e656b16f92cb5d8d5e5dd315
|
||||
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
|
||||
F VERSION 52f7e22bfcec71a462e34194b4ae1671380fde59
|
||||
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
|
||||
F addopcodes.awk 17dc593f791f874d2c23a0f9360850ded0286531
|
||||
F addopcodes.awk 87ca612393d0f439550634bd2c156ea9ff6195ae
|
||||
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
|
||||
F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
|
||||
F art/sqlite370.jpg d512473dae7e378a67e28ff96a34da7cb331def2
|
||||
@@ -78,7 +78,7 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
|
||||
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
|
||||
F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314
|
||||
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
|
||||
F ext/fts3/fts3.c dceaa5079833caa2e7945433e1eb93bb22f623a3
|
||||
F ext/fts3/fts3.c 1e667eacb3fe4b4ad6f863920da4286f071f6e07
|
||||
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
|
||||
F ext/fts3/fts3Int.h eb5f8029589f3d8f1dc7fd50c773326a640388b1
|
||||
F ext/fts3/fts3_aux.c 5c211e17a64885faeb16b9ba7772f9d5445c2365
|
||||
@@ -142,12 +142,12 @@ F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt f439556c5ce01ced70987e5ee86549a45165d9ff
|
||||
F main.mk f57b51e64f50e9924b3f14df3c2e8b66893a8ce5
|
||||
F main.mk 82fd90375561d7b66287ae5a8b09e1e027394019
|
||||
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
|
||||
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
|
||||
F mkextw.sh d2a981497b404d6498f5ff3e3b1f3816bdfcb338
|
||||
F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
|
||||
F mkopcodeh.awk 987ee588ff3bb4043bed2185c1ee2bdc39b1e526
|
||||
F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||
@@ -166,20 +166,20 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
||||
F src/backup.c 1809a7caa2504233bdddd12f5018422421789537
|
||||
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
|
||||
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||
F src/btree.c 260dedc13119e6fb7930380bd3d294b98362bf5a
|
||||
F src/btree.h bfe0e8c5759b4ec77b0d18390064a6ef3cdffaaf
|
||||
F src/btree.c fe6c95c57fd14ed4b3329f4b5bb08132fe7c322d
|
||||
F src/btree.h a61ddebc78c66795a2b93181321a116746302cc9
|
||||
F src/btreeInt.h f038e818bfadf75afbd09819ed93c26a333d39e0
|
||||
F src/build.c 07054d45319953e54a89d726e589a423e9c1c590
|
||||
F src/build.c 1965c7b596ca6295b7ca59541ad186c57564b8f7
|
||||
F src/callback.c f99a8957ba2adf369645fac0db09ad8adcf1caa2
|
||||
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
|
||||
F src/ctime.c ea4b7f3623a0fcb1146e7f245d7410033e86859c
|
||||
F src/ctime.c 77779efbe78dd678d84bfb4fc2e87b6b6ad8dccd
|
||||
F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
|
||||
F src/delete.c d88e4fbfeca5a8cf48b7d358b9a68d5e81f314b7
|
||||
F src/expr.c 1a295d8b0a2ba08919ad9300ebf7b67988ff4030
|
||||
F src/delete.c b36db1f79ee50eaca979660c9dd36437f5410b93
|
||||
F src/expr.c 31a2b65339f6c3795d4cfa5e99798cd72f9fdfdf
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c 78364daed38e26269c53ddb94c515bceac1063c6
|
||||
F src/func.c 96caa9dfd1febf9a4b720de4c43ccfb392a52b73
|
||||
F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759
|
||||
F src/fkey.c 2ab0f5384b70594468ef3ac5c7ed8ca24bfd17d5
|
||||
F src/func.c ef30d26ae4d79bbc7300c74e77fd117a0ba30235
|
||||
F src/global.c 1d7bb7ea8254ae6a68ed9bfaf65fcb3d1690b486
|
||||
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
|
||||
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
@@ -188,13 +188,13 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
|
||||
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
|
||||
F src/loadext.c 867c7b330b740c6c917af9956b13b81d0a048303
|
||||
F src/main.c 32bf1e6e164a6fa0ddf1bf2616c6eafbefd6e9b0
|
||||
F src/main.c 74bdee8f574588868e67c25cd377df7cba80102e
|
||||
F src/malloc.c 543a8eb5508eaf4cadf55a9b503379eba2088128
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c c0c990fcaddff810ea277b4fb5d9138603dd5d4b
|
||||
F src/mem2.c dce31758da87ec2cfa52ba4c5df1aed6e07d8e8f
|
||||
F src/mem3.c 61c9d47b792908c532ca3a62b999cf21795c6534
|
||||
F src/mem5.c 0025308a93838022bd5696cf9627ff4e40b19918
|
||||
F src/mem5.c 19d9271cb936742707b6118ed44d779657c7c511
|
||||
F src/memjournal.c 0683aac6cab6ec2b5374c0db37c0deb2436a3785
|
||||
F src/mutex.c d3b66a569368015e0fcb1ac15f81c119f504d3bc
|
||||
F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea
|
||||
@@ -205,11 +205,11 @@ F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
|
||||
F src/os.c b4ad71336fd96f97776f75587cd9e8218288f5be
|
||||
F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f
|
||||
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
|
||||
F src/os_unix.c 143624d9eabb3b997c59cf594e0d06c56edd43e9
|
||||
F src/os_win.c ef091b347d682cb24fc575ac9a6290341af62e2b
|
||||
F src/os_unix.c f076587029285554a3a65d30d0e71d50cd61f41f
|
||||
F src/os_win.c 4323dd0bac4f7a7037fc4cf87fb4692d17f0b108
|
||||
F src/pager.c 2aa4444ffe86e9282d03bc349a4a5e49bd77c0e8
|
||||
F src/pager.h f094af9f6ececfaa8a1e93876905a4f34233fb0c
|
||||
F src/parse.y 073a8294e1826f1b1656e84806b77e4199f4bb57
|
||||
F src/parse.y acee1a9958539e21263362b194594c5255ad2fca
|
||||
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
|
||||
F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
|
||||
F src/pcache1.c a467393909a4ed7ca9de066d85ba5c5b04a5be63
|
||||
@@ -217,19 +217,19 @@ F src/pragma.c 5ab7279d132143feb77f773688a24ab05da75fd7
|
||||
F src/prepare.c 359d1a1e9c9bd4488e4dd3a1aaaf2d2ebb9bb768
|
||||
F src/printf.c da9119eb31a187a4b99f60aa4a225141c0ebb74b
|
||||
F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68
|
||||
F src/resolve.c 6fcceeb653a0020b14491975d567c989e794d408
|
||||
F src/resolve.c 7eda9097b29fcf3d2b42fdc17d1de672134e09b6
|
||||
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
|
||||
F src/select.c 253cb683e4a05b0b56b0f9c816f3c4a4e5575ebb
|
||||
F src/shell.c b98e74123d6c2e20369607c1da2d23c71db633d9
|
||||
F src/sqlite.h.in 4dedcab5b32358bf7a596badffe7363be1f1a82d
|
||||
F src/select.c d41381d80a22d3a83352aeca274cccf264ac277a
|
||||
F src/shell.c 936a72ff784efff3832cce274a96ed0b036e6758
|
||||
F src/sqlite.h.in baf55c31c4e15a4b626acfeaa792f2aaa566657f
|
||||
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
|
||||
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
|
||||
F src/sqliteInt.h 03b91c6bceccd7718473f3d790abcb8d5c2b1bf1
|
||||
F src/sqliteInt.h f3a5d663fe9c6c0b2ee7fc2e20a6204eaea5bc7c
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
|
||||
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
|
||||
F src/tclsqlite.c 3b5f3716e320480659239abe887164521c575d83
|
||||
F src/test1.c 5757066e503a8ed51313cb3a5d9bcdcced2991a9
|
||||
F src/tclsqlite.c 651b10698c87bbc3ae5772e2491e3444c5bbf153
|
||||
F src/test1.c 760e0419705f712d80595f47199568cd7e3b57a4
|
||||
F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35
|
||||
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
|
||||
F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
|
||||
@@ -242,7 +242,7 @@ F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8
|
||||
F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12
|
||||
F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e
|
||||
F src/test_btree.c 5b89601dcb42a33ba8b820a6b763cc9cb48bac16
|
||||
F src/test_config.c e825cd6a4a8f498be246fc5934fe5fd702b9441f
|
||||
F src/test_config.c 10d0e00dd6315879a6d9fac20bd063c7bbbfb8f8
|
||||
F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f
|
||||
@@ -253,7 +253,7 @@ F src/test_intarray.c 87847c71c3c36889c0bcc9c4baf9d31881665d61
|
||||
F src/test_intarray.h 2ece66438cfd177b78d1bfda7a4180cd3a10844d
|
||||
F src/test_journal.c f5c0a05b7b3d5930db769b5ee6c3766dc2221a64
|
||||
F src/test_loadext.c df586c27176e3c2cb2e099c78da67bf14379a56e
|
||||
F src/test_malloc.c eba4e1c5847cc98e7edc98f62265cd2abafba7a6
|
||||
F src/test_malloc.c 1ff5b1243d96124c9a180f3b89424820a1f337f3
|
||||
F src/test_multiplex.c 9f304bf04170c91c0318238d512df2da039eb1c8
|
||||
F src/test_multiplex.h 110a8c4d356e0aa464ca8730375608a9a0b61ae1
|
||||
F src/test_mutex.c 293042d623ebba969160f471a82aa1551626454f
|
||||
@@ -276,24 +276,24 @@ F src/test_vfstrace.c 34b544e80ba7fb77be15395a609c669df2e660a2
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c ec4c1a62b890bf1dbcdb966399e140b904c700a4
|
||||
F src/trigger.c d84e1f3669e9a217731a14a9d472b1c7b87c87ba
|
||||
F src/update.c cc3d826923f7b61566dedbb3cfce5f13964f35a4
|
||||
F src/update.c d1c2477dcf14d90999d1935af4efb4806553250b
|
||||
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
|
||||
F src/util.c 2fa6c821d28bbdbeec1b2a7b091a281c9ef8f918
|
||||
F src/util.c 76ed0519296e3f62e97e57dab1999e34184c8e49
|
||||
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
|
||||
F src/vdbe.c 5573893423aec2d64871e8d504fadbcdaad39fed
|
||||
F src/vdbe.c 54894fde8dc806d259e015ac7c9680145e725835
|
||||
F src/vdbe.h c06f0813f853566457ce9cfb1a4a4bc39a5da644
|
||||
F src/vdbeInt.h 62eb680327011f3a4b0336642b0ca9d6ecc6eb91
|
||||
F src/vdbeInt.h 05fbda0e061dbc4aaa2709a8cccf3515c245b263
|
||||
F src/vdbeapi.c 93a22a9ba2abe292d5c2cf304d7eb2e894dde0ed
|
||||
F src/vdbeaux.c dd0f6ab9dc159911facfc0a7a2164af44779bdda
|
||||
F src/vdbeblob.c d883398f7260725147dbf5b40c2b61332aee47f9
|
||||
F src/vdbemem.c cc529bbf4f13e4e181bdb446bf6e6962ab030b4b
|
||||
F src/vdbeaux.c 09b79d475f5af2b3b5068f639609d88e0ced9d95
|
||||
F src/vdbeblob.c 8cd05a5630e6d5563ad017bf82edaf812b28acde
|
||||
F src/vdbemem.c 20e349d2ca928802fc8f2d42a2cc488fd6981d3f
|
||||
F src/vdbesort.c 9d83601f9d6243fe70dd0169a2820c5ddfd48147
|
||||
F src/vdbetrace.c e7ec40e1999ff3c6414424365d5941178966dcbc
|
||||
F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
|
||||
F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c e9e593d5bb798c3e67fc3893dfe7055c9e7d8d74
|
||||
F src/where.c de64e326bb2a07e5591900b11a93d743df2a6919
|
||||
F src/where.c e6a4e713abe6f995495ea53dd6a5e48f88b53883
|
||||
F src/whereInt.h 96a75c61f1d2b9d4a8e4bb17d89deb0cf7cba358
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
@@ -313,7 +313,7 @@ F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4
|
||||
F test/analyze6.test d31defa011a561b938b4608d3538c1b4e0b5e92c
|
||||
F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f
|
||||
F test/analyze8.test 093d15c1c888eed5034304a98c992f7360130b88
|
||||
F test/analyze9.test 1b9b7e9a096d1536f03d9ad7b72f638ef5669347
|
||||
F test/analyze9.test 339e87723cd4dc158dc5e9095acd8df9e87faf79
|
||||
F test/analyzeA.test 1a5c40079894847976d983ca39c707aaa44b6944
|
||||
F test/analyzeB.test 8bf35ee0a548aea831bf56762cb8e7fdb1db083d
|
||||
F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b
|
||||
@@ -321,7 +321,7 @@ F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b
|
||||
F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7
|
||||
F test/async4.test 1787e3952128aa10238bf39945126de7ca23685a
|
||||
F test/async5.test 383ab533fdb9f7ad228cc99ee66e1acb34cc0dc0
|
||||
F test/atof1.test 9bf1d25180a2e05fc12ce3940cc8003033642f68
|
||||
F test/atof1.test 08a61df9365c341f334a65f4348897312d8f3db7
|
||||
F test/attach.test 0d112b7713611fdf0340260192749737135fda5f
|
||||
F test/attach2.test 0ec5defa340363de6cd50fd595046465e9aaba2d
|
||||
F test/attach3.test d89ccfe4fe6e2b5e368d480fcdfe4b496c54cf4e
|
||||
@@ -330,7 +330,7 @@ F test/attachmalloc.test 3a4bfca9545bfe906a8d2e622de10fbac5b711b0
|
||||
F test/auth.test 9bea29041871807d9f289ee679d05d3ed103642f
|
||||
F test/auth2.test c3b415b76c033bedb81292118fb7c01f5f10cbcd
|
||||
F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5
|
||||
F test/autoinc.test bd30d372d00045252f6c2e41b5f41455e1975acf
|
||||
F test/autoinc.test c58912526998a39e11f66b533e23cfabea7f25b7
|
||||
F test/autoindex1.test d4dfe14001dfcb74cfbd7107f45a79fc1ab6183e
|
||||
F test/autovacuum.test 941892505d2c0f410a0cb5970dfa1c7c4e5f6e74
|
||||
F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4
|
||||
@@ -387,25 +387,25 @@ F test/collateA.test b8218ab90d1fa5c59dcf156efabb1b2599c580d6
|
||||
F test/colmeta.test 087c42997754b8c648819832241daf724f813322
|
||||
F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b
|
||||
F test/conflict.test 841bcf7cabbfca39c577eb8411ea8601843b46a8
|
||||
F test/conflict2.test 3ed0b6ec3c2cb8acebbc89677ea0e58c01aaa1ff
|
||||
F test/conflict2.test 0d3af4fb534fa1bd020c79960bb56e4d52655f09
|
||||
F test/conflict3.test dec0634c0f31dec9a4b01c63063e939f0cd21b6b
|
||||
F test/contrib01.test 2a1cbc0f2f48955d7d073f725765da6fbceda6b4
|
||||
F test/corrupt.test 4aabd06cff3fe759e3e658bcc17b71789710665e
|
||||
F test/corrupt2.test 9c0ab4becd50e9050bc1ebb8675456a4e5587bf0
|
||||
F test/corrupt3.test 889d7cdb811800303aa722d7813fe8a4299cf726
|
||||
F test/corrupt4.test b963f9e01e0f92d15c76fb0747876fd4b96dc30a
|
||||
F test/corrupt5.test c23da7bfb20917cc7fdbb13ee25c7cc4e9fffeff
|
||||
F test/corrupt6.test 4e4161aef1f30b9f34582bb4142334b7f47eacae
|
||||
F test/corrupt7.test a90caf89c7d7cb7893ea4d92529bd0c129317ee4
|
||||
F test/corrupt8.test 48eb37ffb9a03bceada62219e2bd4c92f4b0cb75
|
||||
F test/corrupt9.test 959179e68dc0b7b99f424cf3e0381c86dcdd0112
|
||||
F test/corruptA.test fafa652aa585753be4f6b62ff0bb250266eaf7ce
|
||||
F test/corruptB.test 20d4a20cbed23958888c3e8995b424a47223d647
|
||||
F test/corruptC.test 62a767fe64acb1975f58cc6171192839c783edbb
|
||||
F test/corruptD.test 3b09903a2e2fe07ecafe775fea94177f8a4bb34f
|
||||
F test/corruptE.test d3a3d7e864a95978195741744dda4abfd8286018
|
||||
F test/corruptF.test 1c7b6f77cf3f237fb7fbb5b61d6c921fd4c7b993
|
||||
F test/corruptG.test c67fd860e9e3943bc90b856a3049c9a28827167e
|
||||
F test/corrupt.test 141c39ea650c1365e85a49e402fa05cb9617fb97
|
||||
F test/corrupt2.test f2064e0bf934124cc38868fd8badb8f0dd67b552
|
||||
F test/corrupt3.test 4b548d0bbe2933bc81d3f54099a05fc4d28aff18
|
||||
F test/corrupt4.test b99652079d542b21f4965f6248703b983e40fe80
|
||||
F test/corrupt5.test 8ead52af76006f3286e9396cb41898018ccea107
|
||||
F test/corrupt6.test 269548d19427ac554c830763b1c5ea54a0252f80
|
||||
F test/corrupt7.test 22cc644c2e76c9804bc844121267aa6f8f7c0ded
|
||||
F test/corrupt8.test 2399dfe40d2c0c63af86706e30f3e6302a8d0516
|
||||
F test/corrupt9.test 730a3db08d4ab9aa43392ea30d9c2b4879cbff85
|
||||
F test/corruptA.test 53e56dafd180addcdadb402244b8cb9771d2ba26
|
||||
F test/corruptB.test 73a8d6c0b9833697ecf16b63e3c5c05c945b5dec
|
||||
F test/corruptC.test 02405cf7ed0c1e989060e1aab6d02ffbc3906fbb
|
||||
F test/corruptD.test b3c205fac7952b1de645ce44bb02335cd9e3e040
|
||||
F test/corruptE.test 193b4ca4e927e77c1d5f4f56203ddc998432a7ee
|
||||
F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4
|
||||
F test/corruptG.test c150f156dace653c00a121ad0f5772a0568c41ba
|
||||
F test/count.test 42a251178e32f617eda33f76236a7f79825a50b5
|
||||
F test/coveridxscan.test cdb47d01acc4a634a34fd25abe85189e0d0f1e62
|
||||
F test/crash.test fb9dc4a02dcba30d4aa5c2c226f98b220b2b959f
|
||||
@@ -433,11 +433,11 @@ F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2
|
||||
F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
|
||||
F test/distinct.test 44028aaf161a5e80a2f229622b3a174d3b352810
|
||||
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
|
||||
F test/e_createtable.test 3b453432cd14a12732ee9467597d2274ca37ce36
|
||||
F test/e_createtable.test ee95d48664503d40f6cc9ef4a7d03216188e2ada
|
||||
F test/e_delete.test d5186e2f5478b659f16a2c8b66c09892823e542a
|
||||
F test/e_droptrigger.test 3cd080807622c13e5bbb61fc9a57bd7754da2412
|
||||
F test/e_dropview.test 0c9f7f60989164a70a67a9d9c26d1083bc808306
|
||||
F test/e_expr.test d5cdda0e4ffb17760858ed4c7c4ece07efc40f71
|
||||
F test/e_expr.test 5c71d183fbf519a4769fd2e2124afdc70b5b1f42
|
||||
F test/e_fkey.test d83a04478bb9c02d2c513518548a69f818869f41
|
||||
F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459
|
||||
F test/e_insert.test 1e44f84d2abe44d66e4fbf198be4b20e3cc724a0
|
||||
@@ -470,7 +470,7 @@ F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
|
||||
F test/fkey5.test 8a1fde4e7721ae00b05b3178888833726ca2df8d
|
||||
F test/fkey6.test abb59f866c1b44926fd02d1fdd217d831fe04f48
|
||||
F test/fkey7.test e31d0e71a41c1d29349a16448d6c420e2c53a8fc
|
||||
F test/fkey_malloc.test bb74c9cb8f8fceed03b58f8a7ef2df98520bbd51
|
||||
F test/fkey_malloc.test 594a7ea1fbab553c036c70813cd8bd9407d63749
|
||||
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
|
||||
F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c
|
||||
F test/fts1a.test 46090311f85da51bb33bd5ce84f7948359c6d8d7
|
||||
@@ -559,7 +559,7 @@ F test/fts3snippet.test d524af6bcef4714e059ef559113dbdc924cd33d1
|
||||
F test/fts3sort.test ed34c716a11cc2009a35210e84ad5f9c102362ca
|
||||
F test/fts3tok1.test b10d0a12a0ab5f905cea1200b745de233f37443f
|
||||
F test/fts3tok_err.test 52273cd193b9036282f7bacb43da78c6be87418d
|
||||
F test/fts3varint.test 23e79002ebebd6fbb1235504f7acb087b0fea741
|
||||
F test/fts3varint.test 752c08ed5d32c5d7dc211b056f4ed68a76b7e36e
|
||||
F test/fts4aa.test 0c3152322c7f0b548cc942ad763eaba0da87ccca
|
||||
F test/fts4check.test 66fa274cab2b615f2fb338b257713aba8fad88a8
|
||||
F test/fts4content.test 2e7252557d6d24afa101d9ba1de710d6140e6d06
|
||||
@@ -573,20 +573,21 @@ F test/fts4merge4.test c19c85ca1faa7b6d536832b49c12e1867235f584
|
||||
F test/fts4noti.test aed33ba44808852dcb24bf70fa132e7bf530f057
|
||||
F test/fts4unicode.test e28ba1a14181e709dcdf47455f207adf14c7cfe0
|
||||
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
|
||||
F test/func.test c7e80a44eebac8604397eb2ad83d0d5d9d541237
|
||||
F test/func.test 00667bbeac044d007f6f021af1b9f6150f0c7ff8
|
||||
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
|
||||
F test/func3.test dbccee9133cfef1473c59ec07b5f0262b9d72f9a
|
||||
F test/func4.test 6beacdfcb0e18c358e6c2dcacf1b65d1fa80955f
|
||||
F test/func5.test 1435dd313c0bae70d6af089c97a2a997fc5d0e53
|
||||
F test/fuzz-oss1.test 4912e528ec9cf2f42134456933659d371c9e0d74
|
||||
F test/fuzz.test 77fd50afc12847af50fcf1941679d90adebadde6
|
||||
F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167
|
||||
F test/fuzz3.test aec64345184d1662bd30e6a17851ff659d596dc5
|
||||
F test/fuzz3.test efd384b896c647b61a2c1848ba70d42aad60a7b3
|
||||
F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
|
||||
F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26
|
||||
F test/fuzzer1.test d4c52aaf3ef923da293a2653cfab33d02f718a36
|
||||
F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
|
||||
F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98
|
||||
F test/hook.test 45cb22b940c3cc0af616ba7430f666e245711a48
|
||||
F test/hook.test 162d7cef7a2d2b04839fe14402934e6a1b79442f
|
||||
F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
|
||||
F test/in.test 047c4671328e9032ab95666a67021adbbd36e98e
|
||||
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
||||
@@ -623,7 +624,7 @@ F test/intarray.test 066b7d7ac38d25bf96f87f1b017bfc687551cdd4
|
||||
F test/interrupt.test dfe9a67a94b0b2d8f70545ba1a6cca10780d71cc
|
||||
F test/intpkey.test 7506090fc08e028712a8bf47e5f54111947e3844
|
||||
F test/io.test 3a7abcef18727cc0f2399e04b0e8903eccae50f8
|
||||
F test/ioerr.test 40bb2cfcab63fb6aa7424cd97812a84bc16b5fb8
|
||||
F test/ioerr.test 2a24bd6ed5a8b062e64bfe1f6cf94fb25e92210d
|
||||
F test/ioerr2.test 9d71166f8466eda510f1af6137bdabaa82b5408d
|
||||
F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd
|
||||
F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
|
||||
@@ -642,7 +643,7 @@ F test/jrnlmode.test 9ee3a78f53d52cca737db69293d15dc41c0cbd36
|
||||
F test/jrnlmode2.test 81610545a4e6ed239ea8fa661891893385e23a1d
|
||||
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
|
||||
F test/keyword1.test a2400977a2e4fde43bf33754c2929fda34dbca05
|
||||
F test/lastinsert.test 474d519c68cb79d07ecae56a763aa7f322c72f51
|
||||
F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63
|
||||
F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200
|
||||
F test/like.test 935fb4f608e3ea126891496a6e99b9468372bf5c
|
||||
F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da
|
||||
@@ -755,9 +756,9 @@ F test/releasetest.tcl 06d289d8255794073a58d2850742f627924545ce
|
||||
F test/resolver01.test 33abf37ff8335e6bf98f2b45a0af3e06996ccd9a
|
||||
F test/rollback.test e9504a009a202c3ed711da2e6879ff60c5a4669c
|
||||
F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
|
||||
F test/rowid.test f777404492adb0e00868fd706a3721328fd3af48
|
||||
F test/rowid.test b78b30afb9537a73788ca1233a23a32190a3bb1f
|
||||
F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798
|
||||
F test/run-wordcount.bash 1c6a8b75738db8c53e5125be3d81ab63ef9eefd0
|
||||
F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09
|
||||
F test/savepoint.test 6c53f76dffe5df0dd87646efe3e7aa159c36e07b
|
||||
F test/savepoint2.test 9b8543940572a2f01a18298c3135ad0c9f4f67d7
|
||||
F test/savepoint3.test e328085853b14898d78ceea00dfe7db18bb6a9ec
|
||||
@@ -807,6 +808,7 @@ F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868
|
||||
F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
|
||||
F test/skipscan1.test 6bb4891c2cc5efd5690a9da9e7508e53d4a68e10
|
||||
F test/skipscan2.test 5a4db0799c338ddbacb154aaa5589c0254b36a8d
|
||||
F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
|
||||
F test/softheap1.test 40562fe6cac6d9827b7b42b86d45aedf12c15e24
|
||||
F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
|
||||
@@ -818,6 +820,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 4f1e34b6af9af0b59ca11b57d62c3cd851990fba
|
||||
F test/spellfix.test 8c40b169b104086d8795781f670ba3c786d6d8be
|
||||
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
|
||||
F test/stat.test c8eccfe8fcd3f3cfc864ce22d5b9e803a3c69940
|
||||
@@ -836,8 +839,8 @@ F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
|
||||
F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43
|
||||
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
|
||||
F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptrigger.test 0a48d94222d50e6e50d72ac103606c4f8e7cbb81
|
||||
F test/tester.tcl bce6b929932498383ce92431da6a96432c690bf7
|
||||
F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1
|
||||
F test/tester.tcl 2a7cce4abf404557c09323a84a2444b189835d0f
|
||||
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@@ -986,7 +989,7 @@ F test/tpch01.test 8f4ac52f62f3e9f6bce0889105aecdf0275e331b
|
||||
F test/trace.test 4b36a41a3e9c7842151af6da5998f5080cdad9e5
|
||||
F test/trace2.test e7a988fdd982cdec62f1f1f34b0360e6476d01a0
|
||||
F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6
|
||||
F test/trans2.test d5337e61de45e66b1fcbf9db833fa8c82e624b22
|
||||
F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76
|
||||
F test/trans3.test 373ac5183cc56be69f48ae44090e7f672939f732
|
||||
F test/transitive1.test 03f532954f46cdf5608f7766bff0b0c52bf2a7cd
|
||||
F test/trigger1.test dc47573ac79ffe0ee3eecaa517d70d8dacbccd03
|
||||
@@ -1082,16 +1085,18 @@ F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7
|
||||
F test/whereG.test 2a3d5181decc801b36600fa1c40b0dad2ccc267f
|
||||
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
|
||||
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
|
||||
F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
|
||||
F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
|
||||
F test/win32longpath.test e2aafc07e6990fe86c69be22a3d1a0e210cd329b
|
||||
F test/without_rowid1.test aaa26da19d543cd8d3d2d0e686dfa255556c15c8
|
||||
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
|
||||
F test/without_rowid3.test eac3d5c8a1924725b58503a368f2cbd24fd6c8a0
|
||||
F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a
|
||||
F test/wordcount.c c80f378f26fbf6ada602c4313ae88fc47439263e
|
||||
F test/without_rowid5.test b4a639a367f04d382d20e8f44fc1be4f2d57d107
|
||||
F test/wordcount.c 9915e06cb33d8ca8109b8700791afe80d305afda
|
||||
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
|
||||
F test/zerodamage.test 209d7ed441f44cc5299e4ebffbef06fd5aabfefd
|
||||
F tool/build-all-msvc.bat 1bac6adc3fdb4d9204f21d17b14be25778370e48 x
|
||||
F tool/build-all-msvc.bat e0917e787df675b020d250d60a00de8abaa4e30a x
|
||||
F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367
|
||||
F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2
|
||||
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
|
||||
@@ -1140,7 +1145,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
|
||||
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
|
||||
P a11243f840d35aaed8ee3b9901c3950bc584a417
|
||||
R f429117cda51c1a8c08160d9a3f515e6
|
||||
U drh
|
||||
Z 2718e457b564d6fbe8d10873d690a300
|
||||
P c632567063d81c4be404ce58cbac0eff7412f565
|
||||
R 39f74301df16683d1c19ab7ca83b6451
|
||||
T +bgcolor * #d0c0ff
|
||||
T +sym-release *
|
||||
T +sym-version-3.8.2 *
|
||||
U dan
|
||||
Z bddf39b758268961698f9899546a37dd
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
6bd5750b7d5da221b0689f6df6be5ed0dce61bec
|
||||
27392118af4c38c5203a04b8013e1afdb1cebd0d
|
||||
@@ -136,8 +136,10 @@ END {
|
||||
|| name=="OP_VUpdate" \
|
||||
|| name=="OP_VFilter" \
|
||||
|| name=="OP_Next" \
|
||||
|| name=="OP_NextIfOpen" \
|
||||
|| name=="OP_SorterNext" \
|
||||
|| name=="OP_Prev" \
|
||||
|| name=="OP_PrevIfOpen" \
|
||||
){
|
||||
cnt++
|
||||
while( used[cnt] ) cnt++
|
||||
|
||||
+66
-54
@@ -694,6 +694,10 @@ static int btreeMoveto(
|
||||
);
|
||||
if( pIdxKey==0 ) return SQLITE_NOMEM;
|
||||
sqlite3VdbeRecordUnpack(pCur->pKeyInfo, (int)nKey, pKey, pIdxKey);
|
||||
if( pIdxKey->nField==0 ){
|
||||
sqlite3DbFree(pCur->pKeyInfo->db, pFree);
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
}else{
|
||||
pIdxKey = 0;
|
||||
}
|
||||
@@ -4206,7 +4210,7 @@ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
|
||||
*/
|
||||
static const unsigned char *fetchPayload(
|
||||
BtCursor *pCur, /* Cursor pointing to entry to read from */
|
||||
int *pAmt, /* Write the number of available bytes here */
|
||||
u32 *pAmt, /* Write the number of available bytes here */
|
||||
int skipKey /* read beginning at data if this is true */
|
||||
){
|
||||
unsigned char *aPayload;
|
||||
@@ -4219,7 +4223,7 @@ static const unsigned char *fetchPayload(
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
pPage = pCur->apPage[pCur->iPage];
|
||||
assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
|
||||
if( NEVER(pCur->info.nSize==0) ){
|
||||
if( pCur->info.nSize==0 ){
|
||||
btreeParseCell(pCur->apPage[pCur->iPage], pCur->aiIdx[pCur->iPage],
|
||||
&pCur->info);
|
||||
}
|
||||
@@ -4256,7 +4260,7 @@ static const unsigned char *fetchPayload(
|
||||
** These routines is used to get quick access to key and data
|
||||
** in the common case where no overflow pages are used.
|
||||
*/
|
||||
const void *sqlite3BtreeKeyFetch(BtCursor *pCur, int *pAmt){
|
||||
const void *sqlite3BtreeKeyFetch(BtCursor *pCur, u32 *pAmt){
|
||||
const void *p = 0;
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
@@ -4265,7 +4269,7 @@ const void *sqlite3BtreeKeyFetch(BtCursor *pCur, int *pAmt){
|
||||
}
|
||||
return p;
|
||||
}
|
||||
const void *sqlite3BtreeDataFetch(BtCursor *pCur, int *pAmt){
|
||||
const void *sqlite3BtreeDataFetch(BtCursor *pCur, u32 *pAmt){
|
||||
const void *p = 0;
|
||||
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
@@ -4647,10 +4651,10 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
}
|
||||
assert( pCur->apPage[0]->intKey || pIdxKey );
|
||||
for(;;){
|
||||
int lwr, upr, idx;
|
||||
int lwr, upr, idx, c;
|
||||
Pgno chldPg;
|
||||
MemPage *pPage = pCur->apPage[pCur->iPage];
|
||||
int c;
|
||||
u8 *pCell; /* Pointer to current cell in pPage */
|
||||
|
||||
/* pPage->nCell must be greater than zero. If this is the root-page
|
||||
** the cursor would have been INVALID above and this for(;;) loop
|
||||
@@ -4662,35 +4666,47 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
assert( pPage->intKey==(pIdxKey==0) );
|
||||
lwr = 0;
|
||||
upr = pPage->nCell-1;
|
||||
if( biasRight ){
|
||||
pCur->aiIdx[pCur->iPage] = (u16)(idx = upr);
|
||||
}else{
|
||||
pCur->aiIdx[pCur->iPage] = (u16)(idx = (upr+lwr)/2);
|
||||
}
|
||||
for(;;){
|
||||
u8 *pCell; /* Pointer to current cell in pPage */
|
||||
|
||||
assert( idx==pCur->aiIdx[pCur->iPage] );
|
||||
pCur->info.nSize = 0;
|
||||
pCell = findCell(pPage, idx) + pPage->childPtrSize;
|
||||
if( pPage->intKey ){
|
||||
assert( biasRight==0 || biasRight==1 );
|
||||
idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
if( pPage->intKey ){
|
||||
for(;;){
|
||||
i64 nCellKey;
|
||||
pCell = findCell(pPage, idx) + pPage->childPtrSize;
|
||||
if( pPage->hasData ){
|
||||
u32 dummy;
|
||||
pCell += getVarint32(pCell, dummy);
|
||||
while( 0x80 <= *(pCell++) ){
|
||||
if( pCell>=pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
}
|
||||
getVarint(pCell, (u64*)&nCellKey);
|
||||
if( nCellKey==intKey ){
|
||||
c = 0;
|
||||
}else if( nCellKey<intKey ){
|
||||
c = -1;
|
||||
if( nCellKey<intKey ){
|
||||
lwr = idx+1;
|
||||
if( lwr>upr ){ c = -1; break; }
|
||||
}else if( nCellKey>intKey ){
|
||||
upr = idx-1;
|
||||
if( lwr>upr ){ c = +1; break; }
|
||||
}else{
|
||||
assert( nCellKey>intKey );
|
||||
c = +1;
|
||||
assert( nCellKey==intKey );
|
||||
pCur->validNKey = 1;
|
||||
pCur->info.nKey = nCellKey;
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
if( !pPage->leaf ){
|
||||
lwr = idx;
|
||||
goto moveto_next_layer;
|
||||
}else{
|
||||
*pRes = 0;
|
||||
rc = SQLITE_OK;
|
||||
goto moveto_finish;
|
||||
}
|
||||
}
|
||||
pCur->validNKey = 1;
|
||||
pCur->info.nKey = nCellKey;
|
||||
}else{
|
||||
assert( lwr+upr>=0 );
|
||||
idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2; */
|
||||
}
|
||||
}else{
|
||||
for(;;){
|
||||
int nCell;
|
||||
pCell = findCell(pPage, idx) + pPage->childPtrSize;
|
||||
|
||||
/* The maximum supported page-size is 65536 bytes. This means that
|
||||
** the maximum number of record bytes stored on an index B-Tree
|
||||
** page is less than 16384 bytes and may be stored as a 2-byte
|
||||
@@ -4699,7 +4715,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
** stored entirely within the b-tree page by inspecting the first
|
||||
** 2 bytes of the cell.
|
||||
*/
|
||||
int nCell = pCell[0];
|
||||
nCell = pCell[0];
|
||||
if( nCell<=pPage->max1bytePayload
|
||||
/* && (pCell+nCell)<pPage->aDataEnd */
|
||||
){
|
||||
@@ -4730,6 +4746,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
rc = SQLITE_NOMEM;
|
||||
goto moveto_finish;
|
||||
}
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
|
||||
if( rc ){
|
||||
sqlite3_free(pCellKey);
|
||||
@@ -4738,49 +4755,44 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey);
|
||||
sqlite3_free(pCellKey);
|
||||
}
|
||||
}
|
||||
if( c==0 ){
|
||||
if( pPage->intKey && !pPage->leaf ){
|
||||
lwr = idx;
|
||||
break;
|
||||
if( c<0 ){
|
||||
lwr = idx+1;
|
||||
}else if( c>0 ){
|
||||
upr = idx-1;
|
||||
}else{
|
||||
assert( c==0 );
|
||||
*pRes = 0;
|
||||
rc = SQLITE_OK;
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
goto moveto_finish;
|
||||
}
|
||||
if( lwr>upr ) break;
|
||||
assert( lwr+upr>=0 );
|
||||
idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2 */
|
||||
}
|
||||
if( c<0 ){
|
||||
lwr = idx+1;
|
||||
}else{
|
||||
upr = idx-1;
|
||||
}
|
||||
if( lwr>upr ){
|
||||
break;
|
||||
}
|
||||
pCur->aiIdx[pCur->iPage] = (u16)(idx = (lwr+upr)/2);
|
||||
}
|
||||
assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) );
|
||||
assert( pPage->isInit );
|
||||
if( pPage->leaf ){
|
||||
chldPg = 0;
|
||||
}else if( lwr>=pPage->nCell ){
|
||||
chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]);
|
||||
}else{
|
||||
chldPg = get4byte(findCell(pPage, lwr));
|
||||
}
|
||||
if( chldPg==0 ){
|
||||
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
|
||||
pCur->aiIdx[pCur->iPage] = (u16)idx;
|
||||
*pRes = c;
|
||||
rc = SQLITE_OK;
|
||||
goto moveto_finish;
|
||||
}
|
||||
moveto_next_layer:
|
||||
if( lwr>=pPage->nCell ){
|
||||
chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]);
|
||||
}else{
|
||||
chldPg = get4byte(findCell(pPage, lwr));
|
||||
}
|
||||
pCur->aiIdx[pCur->iPage] = (u16)lwr;
|
||||
pCur->info.nSize = 0;
|
||||
pCur->validNKey = 0;
|
||||
rc = moveToChild(pCur, chldPg);
|
||||
if( rc ) goto moveto_finish;
|
||||
if( rc ) break;
|
||||
}
|
||||
moveto_finish:
|
||||
pCur->info.nSize = 0;
|
||||
pCur->validNKey = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -178,8 +178,8 @@ int sqlite3BtreeEof(BtCursor*);
|
||||
int sqlite3BtreePrevious(BtCursor*, int *pRes);
|
||||
int sqlite3BtreeKeySize(BtCursor*, i64 *pSize);
|
||||
int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*);
|
||||
const void *sqlite3BtreeKeyFetch(BtCursor*, int *pAmt);
|
||||
const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt);
|
||||
const void *sqlite3BtreeKeyFetch(BtCursor*, u32 *pAmt);
|
||||
const void *sqlite3BtreeDataFetch(BtCursor*, u32 *pAmt);
|
||||
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
|
||||
int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
|
||||
void sqlite3BtreeSetCachedRowid(BtCursor*, sqlite3_int64);
|
||||
|
||||
+1
-1
@@ -2790,7 +2790,7 @@ Index *sqlite3CreateIndex(
|
||||
const Column *pTabCol; /* A column in the table */
|
||||
int nExtra = 0; /* Space allocated for zExtra[] */
|
||||
int nExtraCol; /* Number of extra columns needed */
|
||||
char *zExtra; /* Extra space after the Index object */
|
||||
char *zExtra = 0; /* Extra space after the Index object */
|
||||
Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */
|
||||
|
||||
assert( pParse->nErr==0 ); /* Never called with prior errors */
|
||||
|
||||
@@ -347,6 +347,9 @@ static const char * const azCompileOpt[] = {
|
||||
#ifdef SQLITE_SOUNDEX
|
||||
"SOUNDEX",
|
||||
#endif
|
||||
#ifdef SQLITE_SYSTEM_MALLOC
|
||||
"SYSTEM_MALLOC",
|
||||
#endif
|
||||
#ifdef SQLITE_TCL
|
||||
"TCL",
|
||||
#endif
|
||||
@@ -362,6 +365,9 @@ static const char * const azCompileOpt[] = {
|
||||
#ifdef SQLITE_USE_ALLOCA
|
||||
"USE_ALLOCA",
|
||||
#endif
|
||||
#ifdef SQLITE_WIN32_MALLOC
|
||||
"WIN32_MALLOC",
|
||||
#endif
|
||||
#ifdef SQLITE_ZERO_MALLOC
|
||||
"ZERO_MALLOC"
|
||||
#endif
|
||||
|
||||
+4
-5
@@ -244,10 +244,10 @@ void sqlite3DeleteFrom(
|
||||
int aiCurOnePass[2]; /* The write cursors opened by WHERE_ONEPASS */
|
||||
u8 *aToOpen = 0; /* Open cursor iTabCur+j if aToOpen[j] is true */
|
||||
Index *pPk; /* The PRIMARY KEY index on the table */
|
||||
int iPk; /* First of nPk registerss holding PRIMARY KEY value */
|
||||
i16 nPk = 1; /* Number of components of the PRIMARY KEY */
|
||||
int iKey; /* Memory cell holding row key of to be deleted */
|
||||
i16 nKey; /* Number of memory cells of row key */
|
||||
int iPk = 0; /* First of nPk registers holding PRIMARY KEY value */
|
||||
i16 nPk = 1; /* Number of columns in the PRIMARY KEY */
|
||||
int iKey; /* Memory cell holding key of row to be deleted */
|
||||
i16 nKey; /* Number of memory cells in the row key */
|
||||
int iEphCur = 0; /* Ephemeral table holding all primary key values */
|
||||
int iRowSet = 0; /* Register for rowset of rows to delete */
|
||||
int addrBypass = 0; /* Address of jump over the delete logic */
|
||||
@@ -420,7 +420,6 @@ void sqlite3DeleteFrom(
|
||||
pPk->aiColumn[i], iPk+i);
|
||||
}
|
||||
iKey = iPk;
|
||||
nKey = nPk;
|
||||
}else{
|
||||
iKey = pParse->nMem + 1;
|
||||
iKey = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iTabCur, iKey, 0);
|
||||
|
||||
+69
-32
@@ -1191,9 +1191,12 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
|
||||
|
||||
switch( pExpr->op ){
|
||||
/* Consider functions to be constant if all their arguments are constant
|
||||
** and pWalker->u.i==2 */
|
||||
** and either pWalker->u.i==2 or the function as the SQLITE_FUNC_CONST
|
||||
** flag. */
|
||||
case TK_FUNCTION:
|
||||
if( pWalker->u.i==2 ) return 0;
|
||||
if( pWalker->u.i==2 || ExprHasProperty(pExpr,EP_Constant) ){
|
||||
return WRC_Continue;
|
||||
}
|
||||
/* Fall through */
|
||||
case TK_ID:
|
||||
case TK_COLUMN:
|
||||
@@ -2623,7 +2626,6 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TK_CONST_FUNC:
|
||||
case TK_FUNCTION: {
|
||||
ExprList *pFarg; /* List of function arguments */
|
||||
int nFarg; /* Number of function arguments */
|
||||
@@ -2636,8 +2638,6 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
CollSeq *pColl = 0; /* A collating sequence */
|
||||
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
testcase( op==TK_CONST_FUNC );
|
||||
testcase( op==TK_FUNCTION );
|
||||
if( ExprHasProperty(pExpr, EP_TokenOnly) ){
|
||||
pFarg = 0;
|
||||
}else{
|
||||
@@ -2681,8 +2681,21 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
break;
|
||||
}
|
||||
|
||||
for(i=0; i<nFarg; i++){
|
||||
if( i<32 && sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){
|
||||
constMask |= (1<<i);
|
||||
}
|
||||
if( (pDef->funcFlags & SQLITE_FUNC_NEEDCOLL)!=0 && !pColl ){
|
||||
pColl = sqlite3ExprCollSeq(pParse, pFarg->a[i].pExpr);
|
||||
}
|
||||
}
|
||||
if( pFarg ){
|
||||
r1 = sqlite3GetTempRange(pParse, nFarg);
|
||||
if( constMask ){
|
||||
r1 = pParse->nMem+1;
|
||||
pParse->nMem += nFarg;
|
||||
}else{
|
||||
r1 = sqlite3GetTempRange(pParse, nFarg);
|
||||
}
|
||||
|
||||
/* For length() and typeof() functions with a column argument,
|
||||
** set the P5 parameter to the OP_Column opcode to OPFLAG_LENGTHARG
|
||||
@@ -2697,14 +2710,15 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
if( exprOp==TK_COLUMN || exprOp==TK_AGG_COLUMN ){
|
||||
assert( SQLITE_FUNC_LENGTH==OPFLAG_LENGTHARG );
|
||||
assert( SQLITE_FUNC_TYPEOF==OPFLAG_TYPEOFARG );
|
||||
testcase( (pDef->funcFlags&~SQLITE_FUNC_ENCMASK)
|
||||
==SQLITE_FUNC_LENGTH );
|
||||
pFarg->a[0].pExpr->op2 = pDef->funcFlags&~SQLITE_FUNC_ENCMASK;
|
||||
testcase( pDef->funcFlags & OPFLAG_LENGTHARG );
|
||||
pFarg->a[0].pExpr->op2 =
|
||||
pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG);
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */
|
||||
sqlite3ExprCodeExprList(pParse, pFarg, r1, 1);
|
||||
sqlite3ExprCodeExprList(pParse, pFarg, r1,
|
||||
SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
|
||||
sqlite3ExprCachePop(pParse, 1); /* Ticket 2ea2425d34be */
|
||||
}else{
|
||||
r1 = 0;
|
||||
@@ -2728,14 +2742,6 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[0].pExpr);
|
||||
}
|
||||
#endif
|
||||
for(i=0; i<nFarg; i++){
|
||||
if( i<32 && sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){
|
||||
constMask |= (1<<i);
|
||||
}
|
||||
if( (pDef->funcFlags & SQLITE_FUNC_NEEDCOLL)!=0 && !pColl ){
|
||||
pColl = sqlite3ExprCollSeq(pParse, pFarg->a[i].pExpr);
|
||||
}
|
||||
}
|
||||
if( pDef->funcFlags & SQLITE_FUNC_NEEDCOLL ){
|
||||
if( !pColl ) pColl = db->pDfltColl;
|
||||
sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ);
|
||||
@@ -2743,7 +2749,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
sqlite3VdbeAddOp4(v, OP_Function, constMask, r1, target,
|
||||
(char*)pDef, P4_FUNCDEF);
|
||||
sqlite3VdbeChangeP5(v, (u8)nFarg);
|
||||
if( nFarg ){
|
||||
if( nFarg && constMask==0 ){
|
||||
sqlite3ReleaseTempRange(pParse, r1, nFarg);
|
||||
}
|
||||
break;
|
||||
@@ -2980,6 +2986,28 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
return inReg;
|
||||
}
|
||||
|
||||
/*
|
||||
** Factor out the code of the given expression to initialization time.
|
||||
*/
|
||||
void sqlite3ExprCodeAtInit(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Expr *pExpr, /* The expression to code when the VDBE initializes */
|
||||
int regDest, /* Store the value in this register */
|
||||
u8 reusable /* True if this expression is reusable */
|
||||
){
|
||||
ExprList *p;
|
||||
assert( ConstFactorOk(pParse) );
|
||||
p = pParse->pConstExpr;
|
||||
pExpr = sqlite3ExprDup(pParse->db, pExpr, 0);
|
||||
p = sqlite3ExprListAppend(pParse, p, pExpr);
|
||||
if( p ){
|
||||
struct ExprList_item *pItem = &p->a[p->nExpr-1];
|
||||
pItem->u.iConstExprReg = regDest;
|
||||
pItem->reusable = reusable;
|
||||
}
|
||||
pParse->pConstExpr = p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Generate code to evaluate an expression and store the results
|
||||
** into a register. Return the register number where the results
|
||||
@@ -2996,7 +3024,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
|
||||
int r2;
|
||||
pExpr = sqlite3ExprSkipCollate(pExpr);
|
||||
if( pParse->cookieGoto>0
|
||||
if( ConstFactorOk(pParse)
|
||||
&& pExpr->op!=TK_REGISTER
|
||||
&& sqlite3ExprIsConstantNotJoin(pExpr)
|
||||
){
|
||||
@@ -3004,16 +3032,15 @@ int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
|
||||
int i;
|
||||
*pReg = 0;
|
||||
if( p ){
|
||||
for(i=0; i<p->nExpr; i++){
|
||||
if( sqlite3ExprCompare(p->a[i].pExpr, pExpr, -1)==0 ){
|
||||
return p->a[i].u.iConstExprReg;
|
||||
struct ExprList_item *pItem;
|
||||
for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){
|
||||
if( pItem->reusable && sqlite3ExprCompare(pItem->pExpr,pExpr,-1)==0 ){
|
||||
return pItem->u.iConstExprReg;
|
||||
}
|
||||
}
|
||||
}
|
||||
p = sqlite3ExprListAppend(pParse, p, sqlite3ExprDup(pParse->db, pExpr, 0));
|
||||
pParse->pConstExpr = p;
|
||||
r2 = ++pParse->nMem;
|
||||
if( p ) p->a[p->nExpr-1].u.iConstExprReg = r2;
|
||||
sqlite3ExprCodeAtInit(pParse, pExpr, r2, 1);
|
||||
}else{
|
||||
int r1 = sqlite3GetTempReg(pParse);
|
||||
r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
|
||||
@@ -3203,7 +3230,6 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){
|
||||
}
|
||||
|
||||
case TK_AGG_FUNCTION:
|
||||
case TK_CONST_FUNC:
|
||||
case TK_FUNCTION: {
|
||||
ExprList *pFarg; /* List of function arguments */
|
||||
if( ExprHasProperty(pExpr, EP_TokenOnly) ){
|
||||
@@ -3359,25 +3385,36 @@ void sqlite3ExplainExprList(Vdbe *pOut, ExprList *pList){
|
||||
** expression list into a sequence of registers beginning at target.
|
||||
**
|
||||
** Return the number of elements evaluated.
|
||||
**
|
||||
** The SQLITE_ECEL_DUP flag prevents the arguments from being
|
||||
** filled using OP_SCopy. OP_Copy must be used instead.
|
||||
**
|
||||
** The SQLITE_ECEL_FACTOR argument allows constant arguments to be
|
||||
** factored out into initialization code.
|
||||
*/
|
||||
int sqlite3ExprCodeExprList(
|
||||
Parse *pParse, /* Parsing context */
|
||||
ExprList *pList, /* The expression list to be coded */
|
||||
int target, /* Where to write results */
|
||||
int doHardCopy /* Make a hard copy of every element */
|
||||
u8 flags /* SQLITE_ECEL_* flags */
|
||||
){
|
||||
struct ExprList_item *pItem;
|
||||
int i, n;
|
||||
u8 copyOp = (flags & SQLITE_ECEL_DUP) ? OP_Copy : OP_SCopy;
|
||||
assert( pList!=0 );
|
||||
assert( target>0 );
|
||||
assert( pParse->pVdbe!=0 ); /* Never gets this far otherwise */
|
||||
n = pList->nExpr;
|
||||
if( !ConstFactorOk(pParse) ) flags &= ~SQLITE_ECEL_FACTOR;
|
||||
for(pItem=pList->a, i=0; i<n; i++, pItem++){
|
||||
Expr *pExpr = pItem->pExpr;
|
||||
int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
|
||||
if( inReg!=target+i ){
|
||||
sqlite3VdbeAddOp2(pParse->pVdbe, doHardCopy ? OP_Copy : OP_SCopy,
|
||||
inReg, target+i);
|
||||
if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){
|
||||
sqlite3ExprCodeAtInit(pParse, pExpr, target+i, 0);
|
||||
}else{
|
||||
int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
|
||||
if( inReg!=target+i ){
|
||||
sqlite3VdbeAddOp2(pParse->pVdbe, copyOp, inReg, target+i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return n;
|
||||
|
||||
@@ -548,6 +548,7 @@ static void fkScanChildren(
|
||||
assert( pIdx==0 || pIdx->pTable==pTab );
|
||||
assert( pIdx==0 || pIdx->nKeyCol==pFKey->nCol );
|
||||
assert( pIdx!=0 || pFKey->nCol==1 );
|
||||
assert( pIdx!=0 || HasRowid(pTab) );
|
||||
|
||||
if( nIncr<0 ){
|
||||
iFkIfZero = sqlite3VdbeAddOp2(v, OP_FkIfZero, pFKey->isDeferred, 0);
|
||||
@@ -600,6 +601,7 @@ static void fkScanChildren(
|
||||
}else{
|
||||
Expr *pEq, *pAll = 0;
|
||||
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
|
||||
assert( pIdx!=0 );
|
||||
for(i=0; i<pPk->nKeyCol; i++){
|
||||
i16 iCol = pIdx->aiColumn[i];
|
||||
pLeft = exprTableRegister(pParse, pTab, regData, iCol);
|
||||
|
||||
+5
-5
@@ -1664,8 +1664,8 @@ void sqlite3RegisterGlobalFunctions(void){
|
||||
FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
|
||||
FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
|
||||
FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
|
||||
FUNCTION(random, 0, 0, 0, randomFunc ),
|
||||
FUNCTION(randomblob, 1, 0, 0, randomBlob ),
|
||||
VFUNCTION(random, 0, 0, 0, randomFunc ),
|
||||
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
|
||||
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
|
||||
FUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
|
||||
FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
|
||||
@@ -1675,9 +1675,9 @@ void sqlite3RegisterGlobalFunctions(void){
|
||||
FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
|
||||
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
|
||||
FUNCTION(quote, 1, 0, 0, quoteFunc ),
|
||||
FUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
|
||||
FUNCTION(changes, 0, 0, 0, changes ),
|
||||
FUNCTION(total_changes, 0, 0, 0, total_changes ),
|
||||
VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
|
||||
VFUNCTION(changes, 0, 0, 0, changes ),
|
||||
VFUNCTION(total_changes, 0, 0, 0, total_changes ),
|
||||
FUNCTION(replace, 3, 0, 0, replaceFunc ),
|
||||
FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ),
|
||||
#ifdef SQLITE_SOUNDEX
|
||||
|
||||
+1
-1
@@ -148,6 +148,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
|
||||
SQLITE_USE_URI, /* bOpenUri */
|
||||
SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */
|
||||
0x7ffffffe, /* mxStrlen */
|
||||
0, /* neverCorrupt */
|
||||
128, /* szLookaside */
|
||||
500, /* nLookaside */
|
||||
{0,0,0,0,0,0,0,0}, /* m */
|
||||
@@ -183,7 +184,6 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** Hash table for global functions - functions common to all
|
||||
** database connections. After initialization, this table is
|
||||
|
||||
+20
@@ -515,6 +515,13 @@ int sqlite3_config(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
#if SQLITE_OS_WIN && defined(SQLITE_WIN32_MALLOC)
|
||||
case SQLITE_CONFIG_WIN32_HEAPSIZE: {
|
||||
sqlite3GlobalConfig.nHeap = va_arg(ap, int);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default: {
|
||||
rc = SQLITE_ERROR;
|
||||
break;
|
||||
@@ -3289,6 +3296,19 @@ int sqlite3_test_control(int op, ...){
|
||||
}
|
||||
#endif
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, int);
|
||||
**
|
||||
** Set or clear a flag that indicates that the database file is always well-
|
||||
** formed and never corrupt. This flag is clear by default, indicating that
|
||||
** database files might have arbitrary corruption. Setting the flag during
|
||||
** testing causes certain assert() statements in the code to be activated
|
||||
** that demonstrat invariants on well-formed database files.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_NEVER_CORRUPT: {
|
||||
sqlite3Config.neverCorrupt = va_arg(ap, int);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
va_end(ap);
|
||||
#endif /* SQLITE_OMIT_BUILTIN_TEST */
|
||||
|
||||
+4
-22
@@ -202,32 +202,13 @@ static void memsys5Leave(void){
|
||||
static int memsys5Size(void *p){
|
||||
int iSize = 0;
|
||||
if( p ){
|
||||
int i = ((u8 *)p-mem5.zPool)/mem5.szAtom;
|
||||
int i = (int)(((u8 *)p-mem5.zPool)/mem5.szAtom);
|
||||
assert( i>=0 && i<mem5.nBlock );
|
||||
iSize = mem5.szAtom * (1 << (mem5.aCtrl[i]&CTRL_LOGSIZE));
|
||||
}
|
||||
return iSize;
|
||||
}
|
||||
|
||||
/*
|
||||
** Find the first entry on the freelist iLogsize. Unlink that
|
||||
** entry and return its index.
|
||||
*/
|
||||
static int memsys5UnlinkFirst(int iLogsize){
|
||||
int i;
|
||||
int iFirst;
|
||||
|
||||
assert( iLogsize>=0 && iLogsize<=LOGMAX );
|
||||
i = iFirst = mem5.aiFreelist[iLogsize];
|
||||
assert( iFirst>=0 );
|
||||
while( i>0 ){
|
||||
if( i<iFirst ) iFirst = i;
|
||||
i = MEM5LINK(i)->next;
|
||||
}
|
||||
memsys5Unlink(iFirst, iLogsize);
|
||||
return iFirst;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return a block of memory of at least nBytes in size.
|
||||
** Return NULL if unable. Return NULL if nBytes==0.
|
||||
@@ -273,7 +254,8 @@ static void *memsys5MallocUnsafe(int nByte){
|
||||
sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes", nByte);
|
||||
return 0;
|
||||
}
|
||||
i = memsys5UnlinkFirst(iBin);
|
||||
i = mem5.aiFreelist[iBin];
|
||||
memsys5Unlink(i, iBin);
|
||||
while( iBin>iLogsize ){
|
||||
int newSize;
|
||||
|
||||
@@ -307,7 +289,7 @@ static void memsys5FreeUnsafe(void *pOld){
|
||||
/* Set iBlock to the index of the block pointed to by pOld in
|
||||
** the array of mem5.szAtom byte blocks pointed to by mem5.zPool.
|
||||
*/
|
||||
iBlock = ((u8 *)pOld-mem5.zPool)/mem5.szAtom;
|
||||
iBlock = (int)(((u8 *)pOld-mem5.zPool)/mem5.szAtom);
|
||||
|
||||
/* Check that the pointer pOld points to a valid, non-free block. */
|
||||
assert( iBlock>=0 && iBlock<mem5.nBlock );
|
||||
|
||||
+1
-1
@@ -4081,7 +4081,7 @@ static int unixShmSystemLock(
|
||||
#ifdef SQLITE_DEBUG
|
||||
{ u16 mask;
|
||||
OSTRACE(("SHM-LOCK "));
|
||||
mask = (1<<(ofst+n)) - (1<<ofst);
|
||||
mask = ofst>31 ? 0xffffffff : (1<<(ofst+n)) - (1<<ofst);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( lockType==F_UNLCK ){
|
||||
OSTRACE(("unlock %d ok", ofst));
|
||||
|
||||
+86
-33
@@ -59,6 +59,34 @@
|
||||
must be defined."
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Define the required Windows SDK version constants if they are not
|
||||
** already available.
|
||||
*/
|
||||
#ifndef NTDDI_WIN8
|
||||
# define NTDDI_WIN8 0x06020000
|
||||
#endif
|
||||
|
||||
#ifndef NTDDI_WINBLUE
|
||||
# define NTDDI_WINBLUE 0x06030000
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Check if the GetVersionEx[AW] functions should be considered deprecated
|
||||
** and avoid using them in that case. It should be noted here that if the
|
||||
** value of the SQLITE_WIN32_GETVERSIONEX pre-processor macro is zero
|
||||
** (whether via this block or via being manually specified), that implies
|
||||
** the underlying operating system will always be based on the Windows NT
|
||||
** Kernel.
|
||||
*/
|
||||
#ifndef SQLITE_WIN32_GETVERSIONEX
|
||||
# if defined(NTDDI_VERSION) && NTDDI_VERSION >= NTDDI_WINBLUE
|
||||
# define SQLITE_WIN32_GETVERSIONEX 0
|
||||
# else
|
||||
# define SQLITE_WIN32_GETVERSIONEX 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
** This constant should already be defined (in the "WinDef.h" SDK file).
|
||||
*/
|
||||
@@ -694,7 +722,8 @@ static struct win_syscall {
|
||||
|
||||
#define osGetTickCount ((DWORD(WINAPI*)(VOID))aSyscall[33].pCurrent)
|
||||
|
||||
#if defined(SQLITE_WIN32_HAS_ANSI)
|
||||
#if defined(SQLITE_WIN32_HAS_ANSI) && defined(SQLITE_WIN32_GETVERSIONEX) && \
|
||||
SQLITE_WIN32_GETVERSIONEX
|
||||
{ "GetVersionExA", (SYSCALL)GetVersionExA, 0 },
|
||||
#else
|
||||
{ "GetVersionExA", (SYSCALL)0, 0 },
|
||||
@@ -703,7 +732,8 @@ static struct win_syscall {
|
||||
#define osGetVersionExA ((BOOL(WINAPI*)( \
|
||||
LPOSVERSIONINFOA))aSyscall[34].pCurrent)
|
||||
|
||||
#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
|
||||
#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
|
||||
defined(SQLITE_WIN32_GETVERSIONEX) && SQLITE_WIN32_GETVERSIONEX
|
||||
{ "GetVersionExW", (SYSCALL)GetVersionExW, 0 },
|
||||
#else
|
||||
{ "GetVersionExW", (SYSCALL)0, 0 },
|
||||
@@ -1260,11 +1290,10 @@ void sqlite3_win32_sleep(DWORD milliseconds){
|
||||
** WinNT/2K/XP so that we will know whether or not we can safely call
|
||||
** the LockFileEx() API.
|
||||
*/
|
||||
#ifndef NTDDI_WIN8
|
||||
# define NTDDI_WIN8 0x06020000
|
||||
#endif
|
||||
|
||||
#if SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI)
|
||||
#if !defined(SQLITE_WIN32_GETVERSIONEX) || !SQLITE_WIN32_GETVERSIONEX
|
||||
# define osIsNT() (1)
|
||||
#elif SQLITE_OS_WINCE || SQLITE_OS_WINRT || !defined(SQLITE_WIN32_HAS_ANSI)
|
||||
# define osIsNT() (1)
|
||||
#elif !defined(SQLITE_WIN32_HAS_WIDE)
|
||||
# define osIsNT() (0)
|
||||
@@ -1401,14 +1430,20 @@ static int winMemInit(void *pAppData){
|
||||
|
||||
#if !SQLITE_OS_WINRT && SQLITE_WIN32_HEAP_CREATE
|
||||
if( !pWinMemData->hHeap ){
|
||||
DWORD dwInitialSize = SQLITE_WIN32_HEAP_INIT_SIZE;
|
||||
DWORD dwMaximumSize = (DWORD)sqlite3GlobalConfig.nHeap;
|
||||
if( dwMaximumSize==0 ){
|
||||
dwMaximumSize = SQLITE_WIN32_HEAP_MAX_SIZE;
|
||||
}else if( dwInitialSize>dwMaximumSize ){
|
||||
dwInitialSize = dwMaximumSize;
|
||||
}
|
||||
pWinMemData->hHeap = osHeapCreate(SQLITE_WIN32_HEAP_FLAGS,
|
||||
SQLITE_WIN32_HEAP_INIT_SIZE,
|
||||
SQLITE_WIN32_HEAP_MAX_SIZE);
|
||||
dwInitialSize, dwMaximumSize);
|
||||
if( !pWinMemData->hHeap ){
|
||||
sqlite3_log(SQLITE_NOMEM,
|
||||
"failed to HeapCreate (%lu), flags=%u, initSize=%u, maxSize=%u",
|
||||
osGetLastError(), SQLITE_WIN32_HEAP_FLAGS,
|
||||
SQLITE_WIN32_HEAP_INIT_SIZE, SQLITE_WIN32_HEAP_MAX_SIZE);
|
||||
"failed to HeapCreate (%lu), flags=%u, initSize=%lu, maxSize=%lu",
|
||||
osGetLastError(), SQLITE_WIN32_HEAP_FLAGS, dwInitialSize,
|
||||
dwMaximumSize);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pWinMemData->bOwned = TRUE;
|
||||
@@ -4068,7 +4103,7 @@ static const sqlite3_io_methods winIoMethod = {
|
||||
** sqlite3_vfs object.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#if defined(__CYGWIN__)
|
||||
/*
|
||||
** Convert a filename from whatever the underlying operating system
|
||||
** supports for filenames into UTF-8. Space to hold the result is
|
||||
@@ -4244,23 +4279,17 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
|
||||
** be used. However, we may need to convert the string containing
|
||||
** its name into UTF-8 (i.e. if it is UTF-16 right now).
|
||||
*/
|
||||
if( osIsNT() ){
|
||||
char *zUtf8 = winUnicodeToUtf8(zConverted);
|
||||
if( !zUtf8 ){
|
||||
sqlite3_free(zConverted);
|
||||
sqlite3_free(zBuf);
|
||||
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
|
||||
return SQLITE_IOERR_NOMEM;
|
||||
}
|
||||
sqlite3_snprintf(nMax, zBuf, "%s", zUtf8);
|
||||
sqlite3_free(zUtf8);
|
||||
char *zUtf8 = winConvertToUtf8Filename(zConverted);
|
||||
if( !zUtf8 ){
|
||||
sqlite3_free(zConverted);
|
||||
break;
|
||||
}else{
|
||||
sqlite3_snprintf(nMax, zBuf, "%s", zConverted);
|
||||
sqlite3_free(zConverted);
|
||||
break;
|
||||
sqlite3_free(zBuf);
|
||||
OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
|
||||
return SQLITE_IOERR_NOMEM;
|
||||
}
|
||||
sqlite3_snprintf(nMax, zBuf, "%s", zUtf8);
|
||||
sqlite3_free(zUtf8);
|
||||
sqlite3_free(zConverted);
|
||||
break;
|
||||
}
|
||||
sqlite3_free(zConverted);
|
||||
}
|
||||
@@ -4945,19 +4974,43 @@ static int winFullPathname(
|
||||
if( !zOut ){
|
||||
return SQLITE_IOERR_NOMEM;
|
||||
}
|
||||
if( cygwin_conv_path(CCP_POSIX_TO_WIN_A|CCP_RELATIVE, zRelative, zOut,
|
||||
pVfs->mxPathname+1)<0 ){
|
||||
if( cygwin_conv_path(
|
||||
(osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A) |
|
||||
CCP_RELATIVE, zRelative, zOut, pVfs->mxPathname+1)<0 ){
|
||||
sqlite3_free(zOut);
|
||||
return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno,
|
||||
"winFullPathname1", zRelative);
|
||||
}else{
|
||||
char *zUtf8 = winConvertToUtf8Filename(zOut);
|
||||
if( !zUtf8 ){
|
||||
sqlite3_free(zOut);
|
||||
return SQLITE_IOERR_NOMEM;
|
||||
}
|
||||
sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
|
||||
sqlite3_data_directory, winGetDirSep(), zUtf8);
|
||||
sqlite3_free(zUtf8);
|
||||
sqlite3_free(zOut);
|
||||
}
|
||||
sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
|
||||
sqlite3_data_directory, winGetDirSep(), zOut);
|
||||
sqlite3_free(zOut);
|
||||
}else{
|
||||
if( cygwin_conv_path(CCP_POSIX_TO_WIN_A, zRelative, zFull, nFull)<0 ){
|
||||
char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
|
||||
if( !zOut ){
|
||||
return SQLITE_IOERR_NOMEM;
|
||||
}
|
||||
if( cygwin_conv_path(
|
||||
(osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A),
|
||||
zRelative, zOut, pVfs->mxPathname+1)<0 ){
|
||||
sqlite3_free(zOut);
|
||||
return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno,
|
||||
"winFullPathname2", zRelative);
|
||||
}else{
|
||||
char *zUtf8 = winConvertToUtf8Filename(zOut);
|
||||
if( !zUtf8 ){
|
||||
sqlite3_free(zOut);
|
||||
return SQLITE_IOERR_NOMEM;
|
||||
}
|
||||
sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zUtf8);
|
||||
sqlite3_free(zUtf8);
|
||||
sqlite3_free(zOut);
|
||||
}
|
||||
}
|
||||
return SQLITE_OK;
|
||||
|
||||
+1
-6
@@ -854,12 +854,7 @@ expr(A) ::= ID(X) LP STAR RP(E). {
|
||||
spanSet(&A,&X,&E);
|
||||
}
|
||||
term(A) ::= CTIME_KW(OP). {
|
||||
/* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are
|
||||
** treated as functions that return constants */
|
||||
A.pExpr = sqlite3ExprFunction(pParse, 0,&OP);
|
||||
if( A.pExpr ){
|
||||
A.pExpr->op = TK_CONST_FUNC;
|
||||
}
|
||||
A.pExpr = sqlite3ExprFunction(pParse, 0, &OP);
|
||||
spanSet(&A, &OP, &OP);
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -352,7 +352,9 @@ static int lookupName(
|
||||
}
|
||||
}
|
||||
if( iCol>=pTab->nCol && sqlite3IsRowid(zCol) && HasRowid(pTab) ){
|
||||
iCol = -1; /* IMP: R-44911-55124 */
|
||||
/* IMP: R-24309-18625 */
|
||||
/* IMP: R-44911-55124 */
|
||||
iCol = -1;
|
||||
}
|
||||
if( iCol<pTab->nCol ){
|
||||
cnt++;
|
||||
@@ -667,7 +669,6 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
|
||||
/* Resolve function names
|
||||
*/
|
||||
case TK_CONST_FUNC:
|
||||
case TK_FUNCTION: {
|
||||
ExprList *pList = pExpr->x.pList; /* The argument list */
|
||||
int n = pList ? pList->nExpr : 0; /* Number of arguments */
|
||||
@@ -680,7 +681,6 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
FuncDef *pDef; /* Information about the function */
|
||||
u8 enc = ENC(pParse->db); /* The database encoding */
|
||||
|
||||
testcase( pExpr->op==TK_CONST_FUNC );
|
||||
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
|
||||
notValidPartIdxWhere(pParse, pNC, "functions");
|
||||
zId = pExpr->u.zToken;
|
||||
@@ -725,6 +725,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
pExpr->op = TK_NULL;
|
||||
return WRC_Prune;
|
||||
}
|
||||
if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ) ExprSetProperty(pExpr,EP_Constant);
|
||||
}
|
||||
#endif
|
||||
if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
|
||||
|
||||
+3
-2
@@ -599,7 +599,8 @@ static void selectInnerLoop(
|
||||
** values returned by the SELECT are not required.
|
||||
*/
|
||||
sqlite3ExprCacheClear(pParse);
|
||||
sqlite3ExprCodeExprList(pParse, pEList, regResult, eDest==SRT_Output);
|
||||
sqlite3ExprCodeExprList(pParse, pEList, regResult,
|
||||
(eDest==SRT_Output)?SQLITE_ECEL_DUP:0);
|
||||
}
|
||||
nColumn = nResultCol;
|
||||
|
||||
@@ -3885,7 +3886,7 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
||||
if( pList ){
|
||||
nArg = pList->nExpr;
|
||||
regAgg = sqlite3GetTempRange(pParse, nArg);
|
||||
sqlite3ExprCodeExprList(pParse, pList, regAgg, 1);
|
||||
sqlite3ExprCodeExprList(pParse, pList, regAgg, SQLITE_ECEL_DUP);
|
||||
}else{
|
||||
nArg = 0;
|
||||
regAgg = 0;
|
||||
|
||||
+20
-9
@@ -466,6 +466,7 @@ struct callback_data {
|
||||
FILE *pLog; /* Write log output here */
|
||||
int *aiIndent; /* Array of indents used in MODE_Explain */
|
||||
int nIndent; /* Size of array aiIndent[] */
|
||||
int iIndent; /* Index of current op in aiIndent[] */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -771,10 +772,10 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int
|
||||
w = strlen30(azArg[i]);
|
||||
}
|
||||
if( i==1 && p->aiIndent && p->pStmt ){
|
||||
int iOp = sqlite3_column_int(p->pStmt, 0);
|
||||
if( iOp<p->nIndent ){
|
||||
fprintf(p->out, "%*.s", p->aiIndent[iOp], "");
|
||||
if( p->iIndent<p->nIndent ){
|
||||
fprintf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
|
||||
}
|
||||
p->iIndent++;
|
||||
}
|
||||
if( w<0 ){
|
||||
fprintf(p->out,"%*.*s%s",-w,-w,
|
||||
@@ -1184,7 +1185,7 @@ static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
|
||||
const char *z; /* Used to check if this is an EXPLAIN */
|
||||
int *abYield = 0; /* True if op is an OP_Yield */
|
||||
int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */
|
||||
int iOp;
|
||||
int iOp; /* Index of operation in p->aiIndent[] */
|
||||
|
||||
const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 };
|
||||
const char *azYield[] = { "Yield", "SeekLt", "SeekGt", "RowSetRead", 0 };
|
||||
@@ -1199,8 +1200,16 @@ static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
|
||||
|
||||
for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){
|
||||
int i;
|
||||
int iAddr = sqlite3_column_int(pSql, 0);
|
||||
const char *zOp = (const char*)sqlite3_column_text(pSql, 1);
|
||||
|
||||
/* Set p2 to the P2 field of the current opcode. Then, assuming that
|
||||
** p2 is an instruction address, set variable p2op to the index of that
|
||||
** instruction in the aiIndent[] array. p2 and p2op may be different if
|
||||
** the current instruction is part of a sub-program generated by an
|
||||
** SQL trigger or foreign key. */
|
||||
int p2 = sqlite3_column_int(pSql, 3);
|
||||
int p2op = (p2 + (iOp-iAddr));
|
||||
|
||||
/* Grow the p->aiIndent array as required */
|
||||
if( iOp>=nAlloc ){
|
||||
@@ -1213,13 +1222,14 @@ static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
|
||||
p->nIndent = iOp+1;
|
||||
|
||||
if( str_in_array(zOp, azNext) ){
|
||||
for(i=p2; i<iOp; i++) p->aiIndent[i] += 2;
|
||||
for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
|
||||
}
|
||||
if( str_in_array(zOp, azGoto) && p2<p->nIndent && abYield[p2] ){
|
||||
for(i=p2+1; i<iOp; i++) p->aiIndent[i] += 2;
|
||||
if( str_in_array(zOp, azGoto) && p2op<p->nIndent && abYield[p2op] ){
|
||||
for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
|
||||
}
|
||||
}
|
||||
|
||||
p->iIndent = 0;
|
||||
sqlite3_free(abYield);
|
||||
sqlite3_reset(pSql);
|
||||
}
|
||||
@@ -1231,6 +1241,7 @@ static void explain_data_delete(struct callback_data *p){
|
||||
sqlite3_free(p->aiIndent);
|
||||
p->aiIndent = 0;
|
||||
p->nIndent = 0;
|
||||
p->iIndent = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1296,7 +1307,7 @@ static int shell_exec(
|
||||
|
||||
/* If the shell is currently in ".explain" mode, gather the extra
|
||||
** data required to add indents to the output.*/
|
||||
if( pArg->mode==MODE_Explain ){
|
||||
if( pArg && pArg->mode==MODE_Explain ){
|
||||
explain_data_prepare(pArg, pStmt);
|
||||
}
|
||||
|
||||
@@ -2085,7 +2096,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
*/
|
||||
p->mode = MODE_Explain;
|
||||
p->showHeader = 1;
|
||||
memset(p->colWidth,0,ArraySize(p->colWidth));
|
||||
memset(p->colWidth,0,sizeof(p->colWidth));
|
||||
p->colWidth[0] = 4; /* addr */
|
||||
p->colWidth[1] = 13; /* opcode */
|
||||
p->colWidth[2] = 4; /* P1 */
|
||||
|
||||
+24
-16
@@ -365,7 +365,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
|
||||
** <ul>
|
||||
** <li> The application must insure that the 1st parameter to sqlite3_exec()
|
||||
** is a valid and open [database connection].
|
||||
** <li> The application must not close [database connection] specified by
|
||||
** <li> The application must not close the [database connection] specified by
|
||||
** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
|
||||
** <li> The application must not modify the SQL statement text passed into
|
||||
** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
|
||||
@@ -442,7 +442,7 @@ int sqlite3_exec(
|
||||
** [sqlite3_extended_result_codes()] API.
|
||||
**
|
||||
** Some of the available extended result codes are listed here.
|
||||
** One may expect the number of extended result codes will be expand
|
||||
** One may expect the number of extended result codes will increase
|
||||
** over time. Software that uses extended result codes should expect
|
||||
** to see new result codes in future releases of SQLite.
|
||||
**
|
||||
@@ -1380,7 +1380,7 @@ int sqlite3_db_config(sqlite3*, int op, ...);
|
||||
** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0,
|
||||
** that causes the corresponding memory allocation to fail.
|
||||
**
|
||||
** The xInit method initializes the memory allocator. (For example,
|
||||
** The xInit method initializes the memory allocator. For example,
|
||||
** it might allocate any require mutexes or initialize internal data
|
||||
** structures. The xShutdown method is invoked (indirectly) by
|
||||
** [sqlite3_shutdown()] and should deallocate any resources acquired
|
||||
@@ -1682,6 +1682,13 @@ struct sqlite3_mem_methods {
|
||||
** [SQLITE_MAX_MMAP_SIZE] compile-time option.)^
|
||||
** ^If either argument to this option is negative, then that argument is
|
||||
** changed to its compile-time default.
|
||||
**
|
||||
** [[SQLITE_CONFIG_WIN32_HEAPSIZE]]
|
||||
** <dt>SQLITE_CONFIG_WIN32_HEAPSIZE
|
||||
** <dd>^This option is only available if SQLite is compiled for Windows
|
||||
** with the [SQLITE_WIN32_MALLOC] pre-processor macro defined.
|
||||
** SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value
|
||||
** that specifies the maximum size of the created heap.
|
||||
** </dl>
|
||||
*/
|
||||
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
|
||||
@@ -1706,6 +1713,7 @@ struct sqlite3_mem_methods {
|
||||
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
|
||||
#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
|
||||
#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
|
||||
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
|
||||
|
||||
/*
|
||||
** CAPI3REF: Database Connection Configuration Options
|
||||
@@ -3106,7 +3114,6 @@ int sqlite3_limit(sqlite3*, int id, int newVal);
|
||||
** choice of query plan if the parameter is the left-hand side of a [LIKE]
|
||||
** or [GLOB] operator or if the parameter is compared to an indexed column
|
||||
** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled.
|
||||
** the
|
||||
** </li>
|
||||
** </ol>
|
||||
*/
|
||||
@@ -3768,19 +3775,19 @@ int sqlite3_data_count(sqlite3_stmt *pStmt);
|
||||
**
|
||||
** <tr><td> NULL <td> INTEGER <td> Result is 0
|
||||
** <tr><td> NULL <td> FLOAT <td> Result is 0.0
|
||||
** <tr><td> NULL <td> TEXT <td> Result is NULL pointer
|
||||
** <tr><td> NULL <td> BLOB <td> Result is NULL pointer
|
||||
** <tr><td> NULL <td> TEXT <td> Result is a NULL pointer
|
||||
** <tr><td> NULL <td> BLOB <td> Result is a NULL pointer
|
||||
** <tr><td> INTEGER <td> FLOAT <td> Convert from integer to float
|
||||
** <tr><td> INTEGER <td> TEXT <td> ASCII rendering of the integer
|
||||
** <tr><td> INTEGER <td> BLOB <td> Same as INTEGER->TEXT
|
||||
** <tr><td> FLOAT <td> INTEGER <td> Convert from float to integer
|
||||
** <tr><td> FLOAT <td> INTEGER <td> [CAST] to INTEGER
|
||||
** <tr><td> FLOAT <td> TEXT <td> ASCII rendering of the float
|
||||
** <tr><td> FLOAT <td> BLOB <td> Same as FLOAT->TEXT
|
||||
** <tr><td> TEXT <td> INTEGER <td> Use atoi()
|
||||
** <tr><td> TEXT <td> FLOAT <td> Use atof()
|
||||
** <tr><td> FLOAT <td> BLOB <td> [CAST] to BLOB
|
||||
** <tr><td> TEXT <td> INTEGER <td> [CAST] to INTEGER
|
||||
** <tr><td> TEXT <td> FLOAT <td> [CAST] to REAL
|
||||
** <tr><td> TEXT <td> BLOB <td> No change
|
||||
** <tr><td> BLOB <td> INTEGER <td> Convert to TEXT then use atoi()
|
||||
** <tr><td> BLOB <td> FLOAT <td> Convert to TEXT then use atof()
|
||||
** <tr><td> BLOB <td> INTEGER <td> [CAST] to INTEGER
|
||||
** <tr><td> BLOB <td> FLOAT <td> [CAST] to REAL
|
||||
** <tr><td> BLOB <td> TEXT <td> Add a zero terminator if needed
|
||||
** </table>
|
||||
** </blockquote>)^
|
||||
@@ -3836,7 +3843,7 @@ int sqlite3_data_count(sqlite3_stmt *pStmt);
|
||||
** described above, or until [sqlite3_step()] or [sqlite3_reset()] or
|
||||
** [sqlite3_finalize()] is called. ^The memory space used to hold strings
|
||||
** and BLOBs is freed automatically. Do <b>not</b> pass the pointers returned
|
||||
** [sqlite3_column_blob()], [sqlite3_column_text()], etc. into
|
||||
** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into
|
||||
** [sqlite3_free()].
|
||||
**
|
||||
** ^(If a memory allocation error occurs during the evaluation of any
|
||||
@@ -4914,8 +4921,8 @@ int sqlite3_release_memory(int);
|
||||
**
|
||||
** ^The sqlite3_db_release_memory(D) interface attempts to free as much heap
|
||||
** memory as possible from database connection D. Unlike the
|
||||
** [sqlite3_release_memory()] interface, this interface is effect even
|
||||
** when then [SQLITE_ENABLE_MEMORY_MANAGEMENT] compile-time option is
|
||||
** [sqlite3_release_memory()] interface, this interface is in effect even
|
||||
** when the [SQLITE_ENABLE_MEMORY_MANAGEMENT] compile-time option is
|
||||
** omitted.
|
||||
**
|
||||
** See also: [sqlite3_release_memory()]
|
||||
@@ -6062,7 +6069,8 @@ int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
|
||||
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
|
||||
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19
|
||||
#define SQLITE_TESTCTRL_LAST 19
|
||||
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
|
||||
#define SQLITE_TESTCTRL_LAST 20
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQLite Runtime Status
|
||||
|
||||
+43
-4
@@ -1077,6 +1077,13 @@ struct sqlite3 {
|
||||
#define OptimizationEnabled(db, mask) 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** 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))
|
||||
|
||||
/*
|
||||
** Possible values for the sqlite.magic field.
|
||||
** The numbers are obtained at random and have no special meaning, other
|
||||
@@ -1143,6 +1150,7 @@ struct FuncDestructor {
|
||||
#define SQLITE_FUNC_COUNT 0x100 /* Built-in count(*) aggregate */
|
||||
#define SQLITE_FUNC_COALESCE 0x200 /* Built-in coalesce() or ifnull() */
|
||||
#define SQLITE_FUNC_UNLIKELY 0x400 /* Built-in unlikely() function */
|
||||
#define SQLITE_FUNC_CONSTANT 0x800 /* Constant inputs give a constant output */
|
||||
|
||||
/*
|
||||
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
|
||||
@@ -1155,6 +1163,9 @@ struct FuncDestructor {
|
||||
** as the user-data (sqlite3_user_data()) for the function. If
|
||||
** argument bNC is true, then the SQLITE_FUNC_NEEDCOLL flag is set.
|
||||
**
|
||||
** VFUNCTION(zName, nArg, iArg, bNC, xFunc)
|
||||
** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag.
|
||||
**
|
||||
** AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal)
|
||||
** Used to create an aggregate function definition implemented by
|
||||
** the C functions xStep and xFinal. The first four parameters
|
||||
@@ -1170,16 +1181,20 @@ struct FuncDestructor {
|
||||
** parameter.
|
||||
*/
|
||||
#define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
|
||||
{nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
|
||||
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
|
||||
#define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \
|
||||
{nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
|
||||
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
|
||||
#define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
|
||||
{nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
|
||||
{nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\
|
||||
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
|
||||
#define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
|
||||
{nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
|
||||
{nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
|
||||
pArg, 0, xFunc, 0, 0, #zName, 0, 0}
|
||||
#define LIKEFUNC(zName, nArg, arg, flags) \
|
||||
{nArg, SQLITE_UTF8|flags, (void *)arg, 0, likeFunc, 0, 0, #zName, 0, 0}
|
||||
{nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \
|
||||
(void *)arg, 0, likeFunc, 0, 0, #zName, 0, 0}
|
||||
#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
|
||||
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
|
||||
SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
|
||||
@@ -1839,6 +1854,7 @@ struct Expr {
|
||||
#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */
|
||||
#define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
|
||||
#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */
|
||||
#define EP_Constant 0x080000 /* Node is a constant */
|
||||
|
||||
/*
|
||||
** These macros can be used to test, set, or clear bits in the
|
||||
@@ -1900,6 +1916,7 @@ struct ExprList {
|
||||
u8 sortOrder; /* 1 for DESC or 0 for ASC */
|
||||
unsigned done :1; /* A flag to indicate when processing is finished */
|
||||
unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */
|
||||
unsigned reusable :1; /* Constant expression is reusable */
|
||||
union {
|
||||
struct {
|
||||
u16 iOrderByCol; /* For ORDER BY, column number in result set */
|
||||
@@ -2521,6 +2538,7 @@ struct Sqlite3Config {
|
||||
int bOpenUri; /* True to interpret filenames as URIs */
|
||||
int bUseCis; /* Use covering indices for full-scans */
|
||||
int mxStrlen; /* Maximum string length */
|
||||
int neverCorrupt; /* Database is always well-formed */
|
||||
int szLookaside; /* Default lookaside buffer size */
|
||||
int nLookaside; /* Default lookaside buffer count */
|
||||
sqlite3_mem_methods m; /* Low-level memory allocation interface */
|
||||
@@ -2557,6 +2575,24 @@ struct Sqlite3Config {
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
** This macro is used inside of assert() statements to indicate that
|
||||
** the assert is only valid on a well-formed database. Instead of:
|
||||
**
|
||||
** assert( X );
|
||||
**
|
||||
** One writes:
|
||||
**
|
||||
** assert( X || CORRUPT_DB );
|
||||
**
|
||||
** CORRUPT_DB is true during normal operation. CORRUPT_DB does not indicate
|
||||
** that the database is definitely corrupt, only that it might be corrupt.
|
||||
** For most test cases, CORRUPT_DB is set to false using a special
|
||||
** sqlite3_test_control(). This enables assert() statements to prove
|
||||
** things that are always true for well-formed databases.
|
||||
*/
|
||||
#define CORRUPT_DB (sqlite3Config.neverCorrupt==0)
|
||||
|
||||
/*
|
||||
** Context pointer passed down through the tree-walk.
|
||||
*/
|
||||
@@ -2894,10 +2930,13 @@ void sqlite3ExprCacheRemove(Parse*, int, int);
|
||||
void sqlite3ExprCacheClear(Parse*);
|
||||
void sqlite3ExprCacheAffinityChange(Parse*, int, int);
|
||||
int sqlite3ExprCode(Parse*, Expr*, int);
|
||||
void sqlite3ExprCodeAtInit(Parse*, Expr*, int, u8);
|
||||
int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
|
||||
int sqlite3ExprCodeTarget(Parse*, Expr*, int);
|
||||
int sqlite3ExprCodeAndCache(Parse*, Expr*, int);
|
||||
int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int);
|
||||
int sqlite3ExprCodeExprList(Parse*, ExprList*, int, u8);
|
||||
#define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */
|
||||
#define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */
|
||||
void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
|
||||
void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
|
||||
Table *sqlite3FindTable(sqlite3*,const char*, const char*);
|
||||
|
||||
+6
-6
@@ -424,13 +424,12 @@ static int safeToUseEvalObjv(Tcl_Interp *interp, Tcl_Obj *pCmd){
|
||||
*/
|
||||
static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){
|
||||
SqlFunc *p, *pNew;
|
||||
int i;
|
||||
pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + strlen30(zName) + 1 );
|
||||
int nName = strlen30(zName);
|
||||
pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + nName + 1 );
|
||||
pNew->zName = (char*)&pNew[1];
|
||||
for(i=0; zName[i]; i++){ pNew->zName[i] = tolower(zName[i]); }
|
||||
pNew->zName[i] = 0;
|
||||
memcpy(pNew->zName, zName, nName+1);
|
||||
for(p=pDb->pFunc; p; p=p->pNext){
|
||||
if( strcmp(p->zName, pNew->zName)==0 ){
|
||||
if( sqlite3_stricmp(p->zName, pNew->zName)==0 ){
|
||||
Tcl_Free((char*)pNew);
|
||||
return p;
|
||||
}
|
||||
@@ -1083,13 +1082,14 @@ static int dbPrepareAndBind(
|
||||
int nSql; /* Length of zSql in bytes */
|
||||
int nVar; /* Number of variables in statement */
|
||||
int iParm = 0; /* Next free entry in apParm */
|
||||
char c;
|
||||
int i;
|
||||
Tcl_Interp *interp = pDb->interp;
|
||||
|
||||
*ppPreStmt = 0;
|
||||
|
||||
/* Trim spaces from the start of zSql and calculate the remaining length. */
|
||||
while( isspace(zSql[0]) ){ zSql++; }
|
||||
while( (c = zSql[0])==' ' || c=='\t' || c=='\r' || c=='\n' ){ zSql++; }
|
||||
nSql = strlen30(zSql);
|
||||
|
||||
for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pPreStmt->pNext){
|
||||
|
||||
+33
@@ -5453,6 +5453,37 @@ static int reset_prng_state(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: database_may_be_corrupt
|
||||
**
|
||||
** Indicate that database files might be corrupt. In other words, set the normal
|
||||
** state of operation.
|
||||
*/
|
||||
static int database_may_be_corrupt(
|
||||
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, 0);
|
||||
return TCL_OK;
|
||||
}
|
||||
/*
|
||||
** tclcmd: database_never_corrupt
|
||||
**
|
||||
** Indicate that database files are always well-formed. This enables extra assert()
|
||||
** statements that test conditions that are always true for well-formed databases.
|
||||
*/
|
||||
static int database_never_corrupt(
|
||||
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, 1);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: pcache_stats
|
||||
*/
|
||||
@@ -6331,6 +6362,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "save_prng_state", save_prng_state, 0 },
|
||||
{ "restore_prng_state", restore_prng_state, 0 },
|
||||
{ "reset_prng_state", reset_prng_state, 0 },
|
||||
{ "database_never_corrupt", database_never_corrupt, 0},
|
||||
{ "database_may_be_corrupt", database_may_be_corrupt, 0},
|
||||
{ "optimization_control", optimization_control,0},
|
||||
#if SQLITE_OS_WIN
|
||||
{ "lock_win32_file", win32_file_lock, 0 },
|
||||
|
||||
@@ -63,6 +63,12 @@ static void set_options(Tcl_Interp *interp){
|
||||
Tcl_SetVar2(interp, "sqlite_options", "curdir", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_WIN32_MALLOC
|
||||
Tcl_SetVar2(interp, "sqlite_options", "win32malloc", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "win32malloc", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
Tcl_SetVar2(interp, "sqlite_options", "debug", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
||||
@@ -1130,6 +1130,33 @@ static int test_config_heap(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_config_heap_size NBYTE
|
||||
*/
|
||||
static int test_config_heap_size(
|
||||
void * clientData,
|
||||
Tcl_Interp *interp,
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int nByte; /* Size to pass to sqlite3_config() */
|
||||
int rc; /* Return code of sqlite3_config() */
|
||||
|
||||
Tcl_Obj * CONST *aArg = &objv[1];
|
||||
int nArg = objc-1;
|
||||
|
||||
if( nArg!=1 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "NBYTE");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;
|
||||
|
||||
rc = sqlite3_config(SQLITE_CONFIG_WIN32_HEAPSIZE, nByte);
|
||||
|
||||
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_config_error [DB]
|
||||
**
|
||||
@@ -1473,6 +1500,7 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_db_status", test_db_status ,0 },
|
||||
{ "install_malloc_faultsim", test_install_malloc_faultsim ,0 },
|
||||
{ "sqlite3_config_heap", test_config_heap ,0 },
|
||||
{ "sqlite3_config_heap_size", test_config_heap_size ,0 },
|
||||
{ "sqlite3_config_memstatus", test_config_memstatus ,0 },
|
||||
{ "sqlite3_config_lookaside", test_config_lookaside ,0 },
|
||||
{ "sqlite3_config_error", test_config_error ,0 },
|
||||
|
||||
+6
-5
@@ -263,6 +263,11 @@ void sqlite3Update(
|
||||
assert( chngPk==0 || chngPk==1 );
|
||||
chngKey = chngRowid + chngPk;
|
||||
|
||||
/* The SET expressions are not actually used inside the WHERE loop.
|
||||
** So reset the colUsed mask
|
||||
*/
|
||||
pTabList->a[0].colUsed = 0;
|
||||
|
||||
hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngKey);
|
||||
|
||||
/* There is one entry in the aRegIdx[] array for each index on the table
|
||||
@@ -574,11 +579,7 @@ void sqlite3Update(
|
||||
sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, 0);
|
||||
}
|
||||
if( bReplace || chngKey ){
|
||||
if( sqlite3VdbeCurrentAddr(v)==j1+1 ){
|
||||
sqlite3VdbeChangeToNoop(v, j1);
|
||||
}else{
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, j1);
|
||||
}
|
||||
|
||||
if( hasFK ){
|
||||
|
||||
+8
-7
@@ -465,12 +465,12 @@ static int compare2pow63(const char *zNum, int incr){
|
||||
** If the zNum value is representable as a 64-bit twos-complement
|
||||
** integer, then write that value into *pNum and return 0.
|
||||
**
|
||||
** If zNum is exactly 9223372036854665808, return 2. This special
|
||||
** case is broken out because while 9223372036854665808 cannot be a
|
||||
** signed 64-bit integer, its negative -9223372036854665808 can be.
|
||||
** If zNum is exactly 9223372036854775808, return 2. This special
|
||||
** case is broken out because while 9223372036854775808 cannot be a
|
||||
** signed 64-bit integer, its negative -9223372036854775808 can be.
|
||||
**
|
||||
** If zNum is too big for a 64-bit integer and is not
|
||||
** 9223372036854665808 or if zNum contains any non-numeric text,
|
||||
** 9223372036854775808 or if zNum contains any non-numeric text,
|
||||
** then return 1.
|
||||
**
|
||||
** length is the number of bytes in the string (bytes, not characters).
|
||||
@@ -512,7 +512,7 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
|
||||
u = u*10 + c - '0';
|
||||
}
|
||||
if( u>LARGEST_INT64 ){
|
||||
*pNum = SMALLEST_INT64;
|
||||
*pNum = neg ? SMALLEST_INT64 : LARGEST_INT64;
|
||||
}else if( neg ){
|
||||
*pNum = -(i64)u;
|
||||
}else{
|
||||
@@ -543,7 +543,6 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
|
||||
/* zNum is exactly 9223372036854775808. Fits if negative. The
|
||||
** special case 2 overflow if positive */
|
||||
assert( u-1==LARGEST_INT64 );
|
||||
assert( (*pNum)==SMALLEST_INT64 );
|
||||
return neg ? 0 : 2;
|
||||
}
|
||||
}
|
||||
@@ -1282,6 +1281,8 @@ u64 sqlite3LogEstToInt(LogEst x){
|
||||
x /= 10;
|
||||
if( n>=5 ) n -= 2;
|
||||
else if( n>=1 ) n -= 1;
|
||||
if( x>=3 ) return (n+8)<<(x-3);
|
||||
if( x>=3 ){
|
||||
return x>60 ? (u64)LARGEST_INT64 : (n+8)<<(x-3);
|
||||
}
|
||||
return (n+8)>>(3-x);
|
||||
}
|
||||
|
||||
+285
-343
@@ -212,9 +212,8 @@ static VdbeCursor *allocateCursor(
|
||||
int nByte;
|
||||
VdbeCursor *pCx = 0;
|
||||
nByte =
|
||||
ROUND8(sizeof(VdbeCursor)) +
|
||||
(isBtreeCursor?sqlite3BtreeCursorSize():0) +
|
||||
2*nField*sizeof(u32);
|
||||
ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
|
||||
(isBtreeCursor?sqlite3BtreeCursorSize():0);
|
||||
|
||||
assert( iCur<p->nCursor );
|
||||
if( p->apCsr[iCur] ){
|
||||
@@ -226,12 +225,9 @@ static VdbeCursor *allocateCursor(
|
||||
memset(pCx, 0, sizeof(VdbeCursor));
|
||||
pCx->iDb = iDb;
|
||||
pCx->nField = nField;
|
||||
if( nField ){
|
||||
pCx->aType = (u32 *)&pMem->z[ROUND8(sizeof(VdbeCursor))];
|
||||
}
|
||||
if( isBtreeCursor ){
|
||||
pCx->pCursor = (BtCursor*)
|
||||
&pMem->z[ROUND8(sizeof(VdbeCursor))+2*nField*sizeof(u32)];
|
||||
&pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField];
|
||||
sqlite3BtreeCursorZero(pCx->pCursor);
|
||||
}
|
||||
}
|
||||
@@ -1085,15 +1081,15 @@ case OP_Move: {
|
||||
int p1; /* Register to copy from */
|
||||
int p2; /* Register to copy to */
|
||||
|
||||
n = pOp->p3 + 1;
|
||||
n = pOp->p3;
|
||||
p1 = pOp->p1;
|
||||
p2 = pOp->p2;
|
||||
assert( n>0 && p1>0 && p2>0 );
|
||||
assert( n>=0 && p1>0 && p2>0 );
|
||||
assert( p1+n<=p2 || p2+n<=p1 );
|
||||
|
||||
pIn1 = &aMem[p1];
|
||||
pOut = &aMem[p2];
|
||||
while( n-- ){
|
||||
do{
|
||||
assert( pOut<=&aMem[(p->nMem-p->nCursor)] );
|
||||
assert( pIn1<=&aMem[(p->nMem-p->nCursor)] );
|
||||
assert( memIsValid(pIn1) );
|
||||
@@ -1110,7 +1106,7 @@ case OP_Move: {
|
||||
REGISTER_TRACE(p2++, pOut);
|
||||
pIn1++;
|
||||
pOut++;
|
||||
}
|
||||
}while( n-- );
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1491,10 +1487,6 @@ case OP_Function: {
|
||||
|
||||
assert( pOp->p4type==P4_FUNCDEF );
|
||||
ctx.pFunc = pOp->p4.pFunc;
|
||||
ctx.s.flags = MEM_Null;
|
||||
ctx.s.db = db;
|
||||
ctx.s.xDel = 0;
|
||||
ctx.s.zMalloc = 0;
|
||||
ctx.iOp = pc;
|
||||
ctx.pVdbe = p;
|
||||
|
||||
@@ -1502,7 +1494,10 @@ case OP_Function: {
|
||||
** the pointer to ctx.s so in case the user-function can use
|
||||
** the already allocated buffer instead of allocating a new one.
|
||||
*/
|
||||
sqlite3VdbeMemMove(&ctx.s, pOut);
|
||||
memcpy(&ctx.s, pOut, sizeof(Mem));
|
||||
pOut->flags = MEM_Null;
|
||||
pOut->xDel = 0;
|
||||
pOut->zMalloc = 0;
|
||||
MemSetTypeFlag(&ctx.s, MEM_Null);
|
||||
|
||||
ctx.fErrorOrAux = 0;
|
||||
@@ -1537,7 +1532,8 @@ case OP_Function: {
|
||||
|
||||
/* Copy the result of the function into register P3 */
|
||||
sqlite3VdbeChangeEncoding(&ctx.s, encoding);
|
||||
sqlite3VdbeMemMove(pOut, &ctx.s);
|
||||
assert( pOut->flags==MEM_Null );
|
||||
memcpy(pOut, &ctx.s, sizeof(Mem));
|
||||
if( sqlite3VdbeMemTooBig(pOut) ){
|
||||
goto too_big;
|
||||
}
|
||||
@@ -1662,17 +1658,19 @@ case OP_AddImm: { /* in1 */
|
||||
*/
|
||||
case OP_MustBeInt: { /* jump, in1 */
|
||||
pIn1 = &aMem[pOp->p1];
|
||||
applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding);
|
||||
if( (pIn1->flags & MEM_Int)==0 ){
|
||||
if( pOp->p2==0 ){
|
||||
rc = SQLITE_MISMATCH;
|
||||
goto abort_due_to_error;
|
||||
}else{
|
||||
pc = pOp->p2 - 1;
|
||||
applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding);
|
||||
if( (pIn1->flags & MEM_Int)==0 ){
|
||||
if( pOp->p2==0 ){
|
||||
rc = SQLITE_MISMATCH;
|
||||
goto abort_due_to_error;
|
||||
}else{
|
||||
pc = pOp->p2 - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
MemSetTypeFlag(pIn1, MEM_Int);
|
||||
}
|
||||
MemSetTypeFlag(pIn1, MEM_Int);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2251,151 +2249,103 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
|
||||
** skipped for length() and all content loading can be skipped for typeof().
|
||||
*/
|
||||
case OP_Column: {
|
||||
u32 payloadSize; /* Number of bytes in the record */
|
||||
i64 payloadSize64; /* Number of bytes in the record */
|
||||
int p1; /* P1 value of the opcode */
|
||||
int p2; /* column number to retrieve */
|
||||
VdbeCursor *pC; /* The VDBE cursor */
|
||||
char *zRec; /* Pointer to complete record-data */
|
||||
BtCursor *pCrsr; /* The BTree cursor */
|
||||
u32 *aType; /* aType[i] holds the numeric type of the i-th column */
|
||||
u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */
|
||||
int nField; /* number of fields in the record */
|
||||
int len; /* The length of the serialized data for the column */
|
||||
int i; /* Loop counter */
|
||||
char *zData; /* Part of the record being decoded */
|
||||
Mem *pDest; /* Where to write the extracted value */
|
||||
Mem sMem; /* For storing the record being decoded */
|
||||
u8 *zIdx; /* Index into header */
|
||||
u8 *zEndHdr; /* Pointer to first byte after the header */
|
||||
const u8 *zData; /* Part of the record being decoded */
|
||||
const u8 *zHdr; /* Next unparsed byte of the header */
|
||||
const u8 *zEndHdr; /* Pointer to first byte after the header */
|
||||
u32 offset; /* Offset into the data */
|
||||
u32 szField; /* Number of bytes in the content of a field */
|
||||
int szHdr; /* Size of the header size field at start of record */
|
||||
int avail; /* Number of bytes of available data */
|
||||
u32 avail; /* Number of bytes of available data */
|
||||
u32 t; /* A type code from the record header */
|
||||
Mem *pReg; /* PseudoTable input register */
|
||||
|
||||
|
||||
p1 = pOp->p1;
|
||||
p2 = pOp->p2;
|
||||
pC = 0;
|
||||
memset(&sMem, 0, sizeof(sMem));
|
||||
assert( p1<p->nCursor );
|
||||
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
|
||||
pDest = &aMem[pOp->p3];
|
||||
memAboutToChange(p, pDest);
|
||||
zRec = 0;
|
||||
|
||||
/* This block sets the variable payloadSize to be the total number of
|
||||
** bytes in the record.
|
||||
**
|
||||
** zRec is set to be the complete text of the record if it is available.
|
||||
** The complete record text is always available for pseudo-tables
|
||||
** If the record is stored in a cursor, the complete record text
|
||||
** might be available in the pC->aRow cache. Or it might not be.
|
||||
** If the data is unavailable, zRec is set to NULL.
|
||||
**
|
||||
** We also compute the number of columns in the record. For cursors,
|
||||
** the number of columns is stored in the VdbeCursor.nField element.
|
||||
*/
|
||||
pC = p->apCsr[p1];
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( p2<pC->nField );
|
||||
aType = pC->aType;
|
||||
aOffset = aType + pC->nField;
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
assert( pC->pVtabCursor==0 );
|
||||
assert( pC->pVtabCursor==0 ); /* OP_Column never called on virtual table */
|
||||
#endif
|
||||
pCrsr = pC->pCursor;
|
||||
if( pCrsr!=0 ){
|
||||
/* The record is stored in a B-Tree */
|
||||
rc = sqlite3VdbeCursorMoveto(pC);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
assert( pCrsr!=0 || pC->pseudoTableReg>0 ); /* pCrsr NULL on PseudoTables */
|
||||
assert( pCrsr!=0 || pC->nullRow ); /* pC->nullRow on PseudoTables */
|
||||
|
||||
/* If the cursor cache is stale, bring it up-to-date */
|
||||
rc = sqlite3VdbeCursorMoveto(pC);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
if( pC->cacheStatus!=p->cacheCtr || (pOp->p5&OPFLAG_CLEARCACHE)!=0 ){
|
||||
if( pC->nullRow ){
|
||||
payloadSize = 0;
|
||||
}else if( pC->cacheStatus==p->cacheCtr ){
|
||||
payloadSize = pC->payloadSize;
|
||||
zRec = (char*)pC->aRow;
|
||||
}else if( pC->isIndex ){
|
||||
assert( sqlite3BtreeCursorIsValid(pCrsr) );
|
||||
VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64);
|
||||
assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
|
||||
/* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the
|
||||
** payload size, so it is impossible for payloadSize64 to be
|
||||
** larger than 32 bits. */
|
||||
assert( (payloadSize64 & SQLITE_MAX_U32)==(u64)payloadSize64 );
|
||||
payloadSize = (u32)payloadSize64;
|
||||
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;
|
||||
pC->aRow = (u8*)pReg->z;
|
||||
}else{
|
||||
MemSetTypeFlag(pDest, MEM_Null);
|
||||
goto op_column_out;
|
||||
}
|
||||
}else{
|
||||
assert( sqlite3BtreeCursorIsValid(pCrsr) );
|
||||
VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &payloadSize);
|
||||
assert( rc==SQLITE_OK ); /* DataSize() cannot fail */
|
||||
assert( pCrsr );
|
||||
if( pC->isTable==0 ){
|
||||
assert( sqlite3BtreeCursorIsValid(pCrsr) );
|
||||
VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64);
|
||||
assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
|
||||
/* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the
|
||||
** payload size, so it is impossible for payloadSize64 to be
|
||||
** larger than 32 bits. */
|
||||
assert( (payloadSize64 & SQLITE_MAX_U32)==(u64)payloadSize64 );
|
||||
pC->aRow = sqlite3BtreeKeyFetch(pCrsr, &avail);
|
||||
pC->payloadSize = (u32)payloadSize64;
|
||||
}else{
|
||||
assert( sqlite3BtreeCursorIsValid(pCrsr) );
|
||||
VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &pC->payloadSize);
|
||||
assert( rc==SQLITE_OK ); /* DataSize() cannot fail */
|
||||
pC->aRow = sqlite3BtreeDataFetch(pCrsr, &avail);
|
||||
}
|
||||
assert( avail<=65536 ); /* Maximum page size is 64KiB */
|
||||
if( pC->payloadSize <= (u32)avail ){
|
||||
pC->szRow = pC->payloadSize;
|
||||
}else{
|
||||
pC->szRow = avail;
|
||||
}
|
||||
if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
||||
goto too_big;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
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) );
|
||||
payloadSize = pReg->n;
|
||||
zRec = pReg->z;
|
||||
pC->cacheStatus = (pOp->p5&OPFLAG_CLEARCACHE) ? CACHE_STALE : p->cacheCtr;
|
||||
assert( payloadSize==0 || zRec!=0 );
|
||||
}
|
||||
|
||||
/* If payloadSize is 0, then just store a NULL. This can happen because of
|
||||
** nullRow or because of a corrupt database. */
|
||||
if( payloadSize==0 ){
|
||||
MemSetTypeFlag(pDest, MEM_Null);
|
||||
goto op_column_out;
|
||||
}
|
||||
assert( db->aLimit[SQLITE_LIMIT_LENGTH]>=0 );
|
||||
if( payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
|
||||
goto too_big;
|
||||
}
|
||||
|
||||
nField = pC->nField;
|
||||
assert( p2<nField );
|
||||
|
||||
/* Read and parse the table header. Store the results of the parse
|
||||
** into the record header cache fields of the cursor.
|
||||
*/
|
||||
aType = pC->aType;
|
||||
if( pC->cacheStatus==p->cacheCtr ){
|
||||
aOffset = pC->aOffset;
|
||||
}else{
|
||||
assert(aType);
|
||||
avail = 0;
|
||||
pC->aOffset = aOffset = &aType[nField];
|
||||
pC->payloadSize = payloadSize;
|
||||
pC->cacheStatus = p->cacheCtr;
|
||||
|
||||
/* Figure out how many bytes are in the header */
|
||||
if( zRec ){
|
||||
zData = zRec;
|
||||
}else{
|
||||
if( pC->isIndex ){
|
||||
zData = (char*)sqlite3BtreeKeyFetch(pCrsr, &avail);
|
||||
}else{
|
||||
zData = (char*)sqlite3BtreeDataFetch(pCrsr, &avail);
|
||||
}
|
||||
/* If KeyFetch()/DataFetch() managed to get the entire payload,
|
||||
** save the payload in the pC->aRow cache. That will save us from
|
||||
** having to make additional calls to fetch the content portion of
|
||||
** the record.
|
||||
*/
|
||||
assert( avail>=0 );
|
||||
if( payloadSize <= (u32)avail ){
|
||||
zRec = zData;
|
||||
pC->aRow = (u8*)zData;
|
||||
}else{
|
||||
pC->aRow = 0;
|
||||
}
|
||||
pC->iHdrOffset = getVarint32(pC->aRow, offset);
|
||||
pC->nHdrParsed = 0;
|
||||
aOffset[0] = offset;
|
||||
if( avail<offset ){
|
||||
/* pC->aRow does not have to hold the entire row, but it does at least
|
||||
** need to cover the header of the record. If pC->aRow does not contain
|
||||
** the complete header, then set it to zero, forcing the header to be
|
||||
** dynamically allocated. */
|
||||
pC->aRow = 0;
|
||||
pC->szRow = 0;
|
||||
}
|
||||
/* The following assert is true in all cases except when
|
||||
** the database file has been corrupted externally.
|
||||
** assert( zRec!=0 || avail>=payloadSize || avail>=9 ); */
|
||||
szHdr = getVarint32((u8*)zData, offset);
|
||||
|
||||
/* Make sure a corrupt database has not given us an oversize header.
|
||||
** Do this now to avoid an oversize memory allocation.
|
||||
@@ -2406,155 +2356,148 @@ case OP_Column: {
|
||||
** 3-byte type for each of the maximum of 32768 columns plus three
|
||||
** extra bytes for the header length itself. 32768*3 + 3 = 98307.
|
||||
*/
|
||||
if( offset > 98307 ){
|
||||
if( offset > 98307 || offset > pC->payloadSize ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto op_column_out;
|
||||
goto op_column_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute in len the number of bytes of data we need to read in order
|
||||
** to get nField type values. offset is an upper bound on this. But
|
||||
** nField might be significantly less than the true number of columns
|
||||
** in the table, and in that case, 5*nField+3 might be smaller than offset.
|
||||
** We want to minimize len in order to limit the size of the memory
|
||||
** allocation, especially if a corrupt database file has caused offset
|
||||
** to be oversized. Offset is limited to 98307 above. But 98307 might
|
||||
** still exceed Robson memory allocation limits on some configurations.
|
||||
** On systems that cannot tolerate large memory allocations, nField*5+3
|
||||
** will likely be much smaller since nField will likely be less than
|
||||
** 20 or so. This insures that Robson memory allocation limits are
|
||||
** not exceeded even for corrupt database files.
|
||||
/* Make sure at least the first p2+1 entries of the header have been
|
||||
** parsed and valid information is in aOffset[] and aType[].
|
||||
*/
|
||||
if( pC->nHdrParsed<=p2 ){
|
||||
/* If there is more header available for parsing in the record, try
|
||||
** to extract additional fields up through the p2+1-th field
|
||||
*/
|
||||
len = nField*5 + 3;
|
||||
if( len > (int)offset ) len = (int)offset;
|
||||
|
||||
/* The KeyFetch() or DataFetch() above are fast and will get the entire
|
||||
** record header in most cases. But they will fail to get the complete
|
||||
** record header if the record header does not fit on a single page
|
||||
** in the B-Tree. When that happens, use sqlite3VdbeMemFromBtree() to
|
||||
** acquire the complete header text.
|
||||
*/
|
||||
if( !zRec && avail<len ){
|
||||
sMem.flags = 0;
|
||||
sMem.db = 0;
|
||||
rc = sqlite3VdbeMemFromBtree(pCrsr, 0, len, pC->isIndex, &sMem);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto op_column_out;
|
||||
if( pC->iHdrOffset<aOffset[0] ){
|
||||
/* Make sure zData points to enough of the record to cover the header. */
|
||||
if( pC->aRow==0 ){
|
||||
memset(&sMem, 0, sizeof(sMem));
|
||||
rc = sqlite3VdbeMemFromBtree(pCrsr, 0, aOffset[0],
|
||||
!pC->isTable, &sMem);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto op_column_error;
|
||||
}
|
||||
zData = (u8*)sMem.z;
|
||||
}else{
|
||||
zData = pC->aRow;
|
||||
}
|
||||
zData = sMem.z;
|
||||
}
|
||||
zEndHdr = (u8 *)&zData[len];
|
||||
zIdx = (u8 *)&zData[szHdr];
|
||||
|
||||
/* Scan the header and use it to fill in the aType[] and aOffset[]
|
||||
** arrays. aType[i] will contain the type integer for the i-th
|
||||
** column and aOffset[i] will contain the offset from the beginning
|
||||
** of the record to the start of the data for the i-th column
|
||||
*/
|
||||
for(i=0; i<nField; i++){
|
||||
if( zIdx<zEndHdr ){
|
||||
aOffset[i] = offset;
|
||||
if( zIdx[0]<0x80 ){
|
||||
t = zIdx[0];
|
||||
zIdx++;
|
||||
|
||||
/* Fill in aType[i] and aOffset[i] values through the p2-th field. */
|
||||
i = pC->nHdrParsed;
|
||||
offset = aOffset[i];
|
||||
zHdr = zData + pC->iHdrOffset;
|
||||
zEndHdr = zData + aOffset[0];
|
||||
assert( i<=p2 && zHdr<zEndHdr );
|
||||
do{
|
||||
if( zHdr[0]<0x80 ){
|
||||
t = zHdr[0];
|
||||
zHdr++;
|
||||
}else{
|
||||
zIdx += sqlite3GetVarint32(zIdx, &t);
|
||||
zHdr += sqlite3GetVarint32(zHdr, &t);
|
||||
}
|
||||
aType[i] = t;
|
||||
szField = sqlite3VdbeSerialTypeLen(t);
|
||||
offset += szField;
|
||||
if( offset<szField ){ /* True if offset overflows */
|
||||
zIdx = &zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */
|
||||
zHdr = &zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
/* If i is less that nField, then there are fewer fields in this
|
||||
** record than SetNumColumns indicated there are columns in the
|
||||
** table. Set the offset for any extra columns not present in
|
||||
** the record to 0. This tells code below to store the default value
|
||||
** for the column instead of deserializing a value from the record.
|
||||
*/
|
||||
aOffset[i] = 0;
|
||||
i++;
|
||||
aOffset[i] = offset;
|
||||
}while( i<=p2 && zHdr<zEndHdr );
|
||||
pC->nHdrParsed = i;
|
||||
pC->iHdrOffset = (u32)(zHdr - zData);
|
||||
if( pC->aRow==0 ){
|
||||
sqlite3VdbeMemRelease(&sMem);
|
||||
sMem.flags = MEM_Null;
|
||||
}
|
||||
|
||||
/* If we have read more header data than was contained in the header,
|
||||
** or if the end of the last field appears to be past the end of the
|
||||
** record, or if the end of the last field appears to be before the end
|
||||
** of the record (when all fields present), then we must be dealing
|
||||
** with a corrupt database.
|
||||
*/
|
||||
if( (zHdr > zEndHdr)
|
||||
|| (offset > pC->payloadSize)
|
||||
|| (zHdr==zEndHdr && offset!=pC->payloadSize)
|
||||
){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto op_column_error;
|
||||
}
|
||||
}
|
||||
sqlite3VdbeMemRelease(&sMem);
|
||||
sMem.flags = MEM_Null;
|
||||
|
||||
/* If we have read more header data than was contained in the header,
|
||||
** or if the end of the last field appears to be past the end of the
|
||||
** record, or if the end of the last field appears to be before the end
|
||||
** of the record (when all fields present), then we must be dealing
|
||||
** with a corrupt database.
|
||||
/* If after trying to extra new entries from the header, nHdrParsed is
|
||||
** still not up to p2, that means that the record has fewer than p2
|
||||
** columns. So the result will be either the default value or a NULL.
|
||||
*/
|
||||
if( (zIdx > zEndHdr) || (offset > payloadSize)
|
||||
|| (zIdx==zEndHdr && offset!=payloadSize) ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
if( pC->nHdrParsed<=p2 ){
|
||||
if( pOp->p4type==P4_MEM ){
|
||||
sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static);
|
||||
}else{
|
||||
MemSetTypeFlag(pDest, MEM_Null);
|
||||
}
|
||||
goto op_column_out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the column information. If aOffset[p2] is non-zero, then
|
||||
** deserialize the value from the record. If aOffset[p2] is zero,
|
||||
** then there are not enough fields in the record to satisfy the
|
||||
** request. In this case, set the value NULL or to P4 if P4 is
|
||||
** a pointer to a Mem object.
|
||||
/* Extract the content for the p2+1-th column. Control can only
|
||||
** reach this point if aOffset[p2], aOffset[p2+1], and aType[p2] are
|
||||
** all valid.
|
||||
*/
|
||||
if( aOffset[p2] ){
|
||||
assert( rc==SQLITE_OK );
|
||||
if( zRec ){
|
||||
/* This is the common case where the whole row fits on a single page */
|
||||
VdbeMemRelease(pDest);
|
||||
sqlite3VdbeSerialGet((u8 *)&zRec[aOffset[p2]], aType[p2], pDest);
|
||||
}else{
|
||||
/* This branch happens only when the row overflows onto multiple pages */
|
||||
t = aType[p2];
|
||||
if( (pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
|
||||
&& ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)
|
||||
){
|
||||
/* Content is irrelevant for the typeof() function and for
|
||||
** the length(X) function if X is a blob. So we might as well use
|
||||
** bogus content rather than reading content from disk. NULL works
|
||||
** for text and blob and whatever is in the payloadSize64 variable
|
||||
** will work for everything else. */
|
||||
zData = t<12 ? (char*)&payloadSize64 : 0;
|
||||
}else{
|
||||
len = sqlite3VdbeSerialTypeLen(t);
|
||||
sqlite3VdbeMemMove(&sMem, pDest);
|
||||
rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->isIndex,
|
||||
&sMem);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto op_column_out;
|
||||
}
|
||||
zData = sMem.z;
|
||||
}
|
||||
sqlite3VdbeSerialGet((u8*)zData, t, pDest);
|
||||
}
|
||||
pDest->enc = encoding;
|
||||
assert( p2<pC->nHdrParsed );
|
||||
assert( rc==SQLITE_OK );
|
||||
if( pC->szRow>=aOffset[p2+1] ){
|
||||
/* This is the common case where the desired content fits on the original
|
||||
** page - where the content is not on an overflow page */
|
||||
VdbeMemRelease(pDest);
|
||||
sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
|
||||
}else{
|
||||
if( pOp->p4type==P4_MEM ){
|
||||
sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static);
|
||||
/* This branch happens only when content is on overflow pages */
|
||||
t = aType[p2];
|
||||
if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
|
||||
&& ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
|
||||
|| (len = sqlite3VdbeSerialTypeLen(t))==0
|
||||
){
|
||||
/* Content is irrelevant for the typeof() function and for
|
||||
** the length(X) function if X is a blob. So we might as well use
|
||||
** bogus content rather than reading content from disk. NULL works
|
||||
** for text and blob and whatever is in the payloadSize64 variable
|
||||
** will work for everything else. Content is also irrelevant if
|
||||
** the content length is 0. */
|
||||
zData = t<=13 ? (u8*)&payloadSize64 : 0;
|
||||
sMem.zMalloc = 0;
|
||||
}else{
|
||||
MemSetTypeFlag(pDest, MEM_Null);
|
||||
memset(&sMem, 0, sizeof(sMem));
|
||||
sqlite3VdbeMemMove(&sMem, pDest);
|
||||
rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, !pC->isTable,
|
||||
&sMem);
|
||||
if( rc!=SQLITE_OK ){
|
||||
goto op_column_error;
|
||||
}
|
||||
zData = (u8*)sMem.z;
|
||||
}
|
||||
sqlite3VdbeSerialGet(zData, t, pDest);
|
||||
/* If we dynamically allocated space to hold the data (in the
|
||||
** sqlite3VdbeMemFromBtree() call above) then transfer control of that
|
||||
** dynamically allocated space over to the pDest structure.
|
||||
** This prevents a memory copy. */
|
||||
if( sMem.zMalloc ){
|
||||
assert( sMem.z==sMem.zMalloc );
|
||||
assert( !(pDest->flags & MEM_Dyn) );
|
||||
assert( !(pDest->flags & (MEM_Blob|MEM_Str)) || pDest->z==sMem.z );
|
||||
pDest->flags &= ~(MEM_Ephem|MEM_Static);
|
||||
pDest->flags |= MEM_Term;
|
||||
pDest->z = sMem.z;
|
||||
pDest->zMalloc = sMem.zMalloc;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we dynamically allocated space to hold the data (in the
|
||||
** sqlite3VdbeMemFromBtree() call above) then transfer control of that
|
||||
** dynamically allocated space over to the pDest structure.
|
||||
** This prevents a memory copy.
|
||||
*/
|
||||
if( sMem.zMalloc ){
|
||||
assert( sMem.z==sMem.zMalloc );
|
||||
assert( !(pDest->flags & MEM_Dyn) );
|
||||
assert( !(pDest->flags & (MEM_Blob|MEM_Str)) || pDest->z==sMem.z );
|
||||
pDest->flags &= ~(MEM_Ephem|MEM_Static);
|
||||
pDest->flags |= MEM_Term;
|
||||
pDest->z = sMem.z;
|
||||
pDest->zMalloc = sMem.zMalloc;
|
||||
}
|
||||
|
||||
rc = sqlite3VdbeMemMakeWriteable(pDest);
|
||||
pDest->enc = encoding;
|
||||
|
||||
op_column_out:
|
||||
rc = sqlite3VdbeMemMakeWriteable(pDest);
|
||||
op_column_error:
|
||||
UPDATE_MAX_BLOBSIZE(pDest);
|
||||
REGISTER_TRACE(pOp->p3, pDest);
|
||||
break;
|
||||
@@ -3310,6 +3253,8 @@ case OP_OpenWrite: {
|
||||
nField = pOp->p4.i;
|
||||
}
|
||||
assert( pOp->p1>=0 );
|
||||
assert( nField>=0 );
|
||||
testcase( nField==0 ); /* Table with INTEGER PRIMARY KEY and nothing else */
|
||||
pCur = allocateCursor(p, pOp->p1, nField, iDb, 1);
|
||||
if( pCur==0 ) goto no_mem;
|
||||
pCur->nullRow = 1;
|
||||
@@ -3323,12 +3268,11 @@ case OP_OpenWrite: {
|
||||
** sqlite3BtreeCursor() may return is SQLITE_OK. */
|
||||
assert( rc==SQLITE_OK );
|
||||
|
||||
/* Set the VdbeCursor.isTable and isIndex variables. Previous versions of
|
||||
/* Set the VdbeCursor.isTable variable. Previous versions of
|
||||
** SQLite used to check if the root-page flags were sane at this point
|
||||
** and report database corruption if they were not, but this check has
|
||||
** since moved into the btree layer. */
|
||||
pCur->isTable = pOp->p4type!=P4_KEYINFO;
|
||||
pCur->isIndex = !pCur->isTable;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3370,6 +3314,7 @@ case OP_OpenEphemeral: {
|
||||
SQLITE_OPEN_DELETEONCLOSE |
|
||||
SQLITE_OPEN_TRANSIENT_DB;
|
||||
assert( pOp->p1>=0 );
|
||||
assert( pOp->p2>=0 );
|
||||
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
|
||||
if( pCx==0 ) goto no_mem;
|
||||
pCx->nullRow = 1;
|
||||
@@ -3402,7 +3347,6 @@ case OP_OpenEphemeral: {
|
||||
}
|
||||
}
|
||||
pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
|
||||
pCx->isIndex = !pCx->isTable;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3415,12 +3359,13 @@ case OP_OpenEphemeral: {
|
||||
case OP_SorterOpen: {
|
||||
VdbeCursor *pCx;
|
||||
|
||||
assert( pOp->p1>=0 );
|
||||
assert( pOp->p2>=0 );
|
||||
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
|
||||
if( pCx==0 ) goto no_mem;
|
||||
pCx->pKeyInfo = pOp->p4.pKeyInfo;
|
||||
assert( pCx->pKeyInfo->db==db );
|
||||
assert( pCx->pKeyInfo->enc==ENC(db) );
|
||||
pCx->isSorter = 1;
|
||||
rc = sqlite3VdbeSorterInit(db, pCx);
|
||||
break;
|
||||
}
|
||||
@@ -3446,12 +3391,12 @@ case OP_OpenPseudo: {
|
||||
VdbeCursor *pCx;
|
||||
|
||||
assert( pOp->p1>=0 );
|
||||
assert( pOp->p3>=0 );
|
||||
pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0);
|
||||
if( pCx==0 ) goto no_mem;
|
||||
pCx->nullRow = 1;
|
||||
pCx->pseudoTableReg = pOp->p2;
|
||||
pCx->isTable = 1;
|
||||
pCx->isIndex = 0;
|
||||
pCx->multiPseudo = pOp->p5;
|
||||
break;
|
||||
}
|
||||
@@ -3565,36 +3510,28 @@ case OP_SeekGt: { /* jump, in3 */
|
||||
pc = pOp->p2 - 1;
|
||||
break;
|
||||
}
|
||||
/* If we reach this point, then the P3 value must be a floating
|
||||
** point number. */
|
||||
assert( (pIn3->flags & MEM_Real)!=0 );
|
||||
|
||||
if( iKey==SMALLEST_INT64 && (pIn3->r<(double)iKey || pIn3->r>0) ){
|
||||
/* The P3 value is too large in magnitude to be expressed as an
|
||||
** integer. */
|
||||
res = 1;
|
||||
if( pIn3->r<0 ){
|
||||
if( oc>=OP_SeekGe ){ assert( oc==OP_SeekGe || oc==OP_SeekGt );
|
||||
rc = sqlite3BtreeFirst(pC->pCursor, &res);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
}
|
||||
}else{
|
||||
if( oc<=OP_SeekLe ){ assert( oc==OP_SeekLt || oc==OP_SeekLe );
|
||||
rc = sqlite3BtreeLast(pC->pCursor, &res);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
}
|
||||
}
|
||||
if( res ){
|
||||
pc = pOp->p2 - 1;
|
||||
}
|
||||
break;
|
||||
}else if( oc==OP_SeekLt || oc==OP_SeekGe ){
|
||||
/* Use the ceiling() function to convert real->int */
|
||||
if( pIn3->r > (double)iKey ) iKey++;
|
||||
}else{
|
||||
/* Use the floor() function to convert real->int */
|
||||
assert( oc==OP_SeekLe || oc==OP_SeekGt );
|
||||
if( pIn3->r < (double)iKey ) iKey--;
|
||||
/* If the approximation iKey is larger than the actual real search
|
||||
** term, substitute >= for > and < for <=. e.g. if the search term
|
||||
** is 4.9 and the integer approximation 5:
|
||||
**
|
||||
** (x > 4.9) -> (x >= 5)
|
||||
** (x <= 4.9) -> (x < 5)
|
||||
*/
|
||||
if( pIn3->r<(double)iKey ){
|
||||
assert( OP_SeekGe==(OP_SeekGt-1) );
|
||||
assert( OP_SeekLt==(OP_SeekLe-1) );
|
||||
assert( (OP_SeekLe & 0x0001)==(OP_SeekGt & 0x0001) );
|
||||
if( (oc & 0x0001)==(OP_SeekGt & 0x0001) ) oc--;
|
||||
}
|
||||
|
||||
/* If the approximation iKey is smaller than the actual real search
|
||||
** term, substitute <= for < and > for >=. */
|
||||
else if( pIn3->r>(double)iKey ){
|
||||
assert( OP_SeekLe==(OP_SeekLt+1) );
|
||||
assert( OP_SeekGt==(OP_SeekGe+1) );
|
||||
assert( (OP_SeekLt & 0x0001)==(OP_SeekGe & 0x0001) );
|
||||
if( (oc & 0x0001)==(OP_SeekLt & 0x0001) ) oc++;
|
||||
}
|
||||
}
|
||||
rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, 0, (u64)iKey, 0, &res);
|
||||
@@ -4130,7 +4067,7 @@ case OP_InsertInt: {
|
||||
sqlite3BtreeSetCachedRowid(pC->pCursor, 0);
|
||||
rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey,
|
||||
pData->z, pData->n, nZero,
|
||||
pOp->p5 & OPFLAG_APPEND, seekResult
|
||||
(pOp->p5 & OPFLAG_APPEND)!=0, seekResult
|
||||
);
|
||||
pC->rowidIsValid = 0;
|
||||
pC->deferredMoveto = 0;
|
||||
@@ -4172,20 +4109,11 @@ case OP_Delete: {
|
||||
i64 iKey;
|
||||
VdbeCursor *pC;
|
||||
|
||||
iKey = 0;
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( pC->pCursor!=0 ); /* Only valid for real tables, no pseudotables */
|
||||
|
||||
/* If the update-hook will be invoked, set iKey to the rowid of the
|
||||
** row being deleted.
|
||||
*/
|
||||
if( db->xUpdateCallback && pOp->p4.z ){
|
||||
assert( pC->isTable );
|
||||
assert( pC->rowidIsValid ); /* lastRowid set by previous OP_NotFound */
|
||||
iKey = pC->lastRowid;
|
||||
}
|
||||
iKey = pC->lastRowid; /* Only used for the update hook */
|
||||
|
||||
/* The OP_Delete opcode always follows an OP_NotExists or OP_Last or
|
||||
** OP_Column on the same table without any intervening operations that
|
||||
@@ -4203,10 +4131,9 @@ case OP_Delete: {
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
|
||||
/* Invoke the update-hook if required. */
|
||||
if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z ){
|
||||
const char *zDb = db->aDb[pC->iDb].zName;
|
||||
const char *zTbl = pOp->p4.z;
|
||||
db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE, zDb, zTbl, iKey);
|
||||
if( rc==SQLITE_OK && db->xUpdateCallback && pOp->p4.z && pC->isTable ){
|
||||
db->xUpdateCallback(db->pUpdateArg, SQLITE_DELETE,
|
||||
db->aDb[pC->iDb].zName, pOp->p4.z, iKey);
|
||||
assert( pC->iDb>=0 );
|
||||
}
|
||||
if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
|
||||
@@ -4267,7 +4194,7 @@ case OP_SorterData: {
|
||||
|
||||
pOut = &aMem[pOp->p2];
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC->isSorter );
|
||||
assert( isSorter(pC) );
|
||||
rc = sqlite3VdbeSorterRowkey(pC, pOut);
|
||||
break;
|
||||
}
|
||||
@@ -4307,9 +4234,9 @@ case OP_RowData: {
|
||||
/* Note that RowKey and RowData are really exactly the same instruction */
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC->isSorter==0 );
|
||||
assert( isSorter(pC)==0 );
|
||||
assert( pC->isTable || pOp->opcode!=OP_RowData );
|
||||
assert( pC->isIndex || pOp->opcode==OP_RowData );
|
||||
assert( pC->isTable==0 || pOp->opcode==OP_RowData );
|
||||
assert( pC!=0 );
|
||||
assert( pC->nullRow==0 );
|
||||
assert( pC->pseudoTableReg==0 );
|
||||
@@ -4326,7 +4253,7 @@ case OP_RowData: {
|
||||
rc = sqlite3VdbeCursorMoveto(pC);
|
||||
if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
|
||||
|
||||
if( pC->isIndex ){
|
||||
if( pC->isTable==0 ){
|
||||
assert( !pC->isTable );
|
||||
VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &n64);
|
||||
assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
|
||||
@@ -4346,7 +4273,7 @@ case OP_RowData: {
|
||||
}
|
||||
pOut->n = n;
|
||||
MemSetTypeFlag(pOut, MEM_Blob);
|
||||
if( pC->isIndex ){
|
||||
if( pC->isTable==0 ){
|
||||
rc = sqlite3BtreeKey(pCrsr, 0, n, pOut->z);
|
||||
}else{
|
||||
rc = sqlite3BtreeData(pCrsr, 0, n, pOut->z);
|
||||
@@ -4419,6 +4346,7 @@ case OP_NullRow: {
|
||||
assert( pC!=0 );
|
||||
pC->nullRow = 1;
|
||||
pC->rowidIsValid = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
assert( pC->pCursor || pC->pVtabCursor );
|
||||
if( pC->pCursor ){
|
||||
sqlite3BtreeClearCursor(pC->pCursor);
|
||||
@@ -4494,7 +4422,7 @@ case OP_Rewind: { /* jump */
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( pC->isSorter==(pOp->opcode==OP_SorterSort) );
|
||||
assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) );
|
||||
res = 1;
|
||||
if( isSorter(pC) ){
|
||||
rc = sqlite3VdbeSorterRewind(db, pC, &res);
|
||||
@@ -4502,7 +4430,6 @@ case OP_Rewind: { /* jump */
|
||||
pCrsr = pC->pCursor;
|
||||
assert( pCrsr );
|
||||
rc = sqlite3BtreeFirst(pCrsr, &res);
|
||||
pC->atFirst = res==0 ?1:0;
|
||||
pC->deferredMoveto = 0;
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
pC->rowidIsValid = 0;
|
||||
@@ -4522,7 +4449,8 @@ case OP_Rewind: { /* jump */
|
||||
** to the following instruction. But if the cursor advance was successful,
|
||||
** jump immediately to P2.
|
||||
**
|
||||
** The P1 cursor must be for a real table, not a pseudo-table.
|
||||
** The P1 cursor must be for a real table, not a pseudo-table. P1 must have
|
||||
** been opened prior to this opcode or the program will segfault.
|
||||
**
|
||||
** P4 is always of type P4_ADVANCE. The function pointer points to
|
||||
** sqlite3BtreeNext().
|
||||
@@ -4530,7 +4458,12 @@ 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.
|
||||
**
|
||||
** See also: Prev
|
||||
** See also: Prev, NextIfOpen
|
||||
*/
|
||||
/* Opcode: NextIfOpen P1 P2 * * 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 * * P5
|
||||
**
|
||||
@@ -4539,7 +4472,8 @@ case OP_Rewind: { /* jump */
|
||||
** to the following instruction. But if the cursor backup was successful,
|
||||
** jump immediately to P2.
|
||||
**
|
||||
** The P1 cursor must be for a real table, not a pseudo-table.
|
||||
** The P1 cursor must be for a real table, not a pseudo-table. If P1 is
|
||||
** not open then the behavior is undefined.
|
||||
**
|
||||
** P4 is always of type P4_ADVANCE. The function pointer points to
|
||||
** sqlite3BtreePrevious().
|
||||
@@ -4547,38 +4481,47 @@ 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.
|
||||
*/
|
||||
case OP_SorterNext: /* jump */
|
||||
case OP_Prev: /* jump */
|
||||
case OP_Next: { /* jump */
|
||||
/* Opcode: PrevIfOpen P1 P2 * * P5
|
||||
**
|
||||
** This opcode works just like OP_Prev except that if cursor P1 is not
|
||||
** open it behaves a no-op.
|
||||
*/
|
||||
case OP_SorterNext: { /* jump */
|
||||
VdbeCursor *pC;
|
||||
int res;
|
||||
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( isSorter(pC) );
|
||||
rc = sqlite3VdbeSorterNext(db, pC, &res);
|
||||
goto next_tail;
|
||||
case OP_PrevIfOpen: /* jump */
|
||||
case OP_NextIfOpen: /* jump */
|
||||
if( p->apCsr[pOp->p1]==0 ) break;
|
||||
/* Fall through */
|
||||
case OP_Prev: /* jump */
|
||||
case OP_Next: /* jump */
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
assert( pOp->p5<ArraySize(p->aCounter) );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
if( pC==0 ){
|
||||
break; /* See ticket #2273 */
|
||||
}
|
||||
assert( pC->isSorter==(pOp->opcode==OP_SorterNext) );
|
||||
if( isSorter(pC) ){
|
||||
assert( pOp->opcode==OP_SorterNext );
|
||||
rc = sqlite3VdbeSorterNext(db, pC, &res);
|
||||
}else{
|
||||
/* res = 1; // Always initialized by the xAdvance() call */
|
||||
assert( pC->deferredMoveto==0 );
|
||||
assert( pC->pCursor );
|
||||
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
|
||||
assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
|
||||
rc = pOp->p4.xAdvance(pC->pCursor, &res);
|
||||
}
|
||||
pC->nullRow = (u8)res;
|
||||
assert( pC!=0 );
|
||||
assert( pC->deferredMoveto==0 );
|
||||
assert( pC->pCursor );
|
||||
assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
|
||||
assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
|
||||
assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext );
|
||||
assert( pOp->opcode!=OP_PrevIfOpen || pOp->p4.xAdvance==sqlite3BtreePrevious);
|
||||
rc = pOp->p4.xAdvance(pC->pCursor, &res);
|
||||
next_tail:
|
||||
pC->cacheStatus = CACHE_STALE;
|
||||
if( res==0 ){
|
||||
pC->nullRow = 0;
|
||||
pc = pOp->p2 - 1;
|
||||
p->aCounter[pOp->p5]++;
|
||||
#ifdef SQLITE_TEST
|
||||
sqlite3_search_count++;
|
||||
#endif
|
||||
}else{
|
||||
pC->nullRow = 1;
|
||||
}
|
||||
pC->rowidIsValid = 0;
|
||||
goto check_for_interrupt;
|
||||
@@ -4607,7 +4550,7 @@ case OP_IdxInsert: { /* in2 */
|
||||
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
|
||||
pC = p->apCsr[pOp->p1];
|
||||
assert( pC!=0 );
|
||||
assert( pC->isSorter==(pOp->opcode==OP_SorterInsert) );
|
||||
assert( isSorter(pC)==(pOp->opcode==OP_SorterInsert) );
|
||||
pIn2 = &aMem[pOp->p2];
|
||||
assert( pIn2->flags & MEM_Blob );
|
||||
pCrsr = pC->pCursor;
|
||||
@@ -5858,7 +5801,6 @@ case OP_VOpen: {
|
||||
pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
|
||||
if( pCur ){
|
||||
pCur->pVtabCursor = pVtabCursor;
|
||||
pCur->pModule = pVtabCursor->pVtab->pModule;
|
||||
}else{
|
||||
db->mallocFailed = 1;
|
||||
pModule->xClose(pVtabCursor);
|
||||
|
||||
+25
-24
@@ -36,7 +36,7 @@ typedef struct VdbeOp Op;
|
||||
/*
|
||||
** Boolean values
|
||||
*/
|
||||
typedef unsigned char Bool;
|
||||
typedef unsigned Bool;
|
||||
|
||||
/* Opaque type used by code in vdbesort.c */
|
||||
typedef struct VdbeSorter VdbeSorter;
|
||||
@@ -53,6 +53,9 @@ typedef struct AuxData AuxData;
|
||||
** loop over all entries of the Btree. You can also insert new BTree
|
||||
** entries or retrieve the key or data from the entry that the cursor
|
||||
** is currently pointing to.
|
||||
**
|
||||
** Cursors can also point to virtual tables, sorters, or "pseudo-tables".
|
||||
** A pseudo-table is a single-row table implemented by registers.
|
||||
**
|
||||
** Every cursor that the virtual machine has open is represented by an
|
||||
** instance of the following structure.
|
||||
@@ -61,30 +64,24 @@ struct VdbeCursor {
|
||||
BtCursor *pCursor; /* The cursor structure of the backend */
|
||||
Btree *pBt; /* Separate file holding temporary table */
|
||||
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
|
||||
int iDb; /* Index of cursor database in db->aDb[] (or -1) */
|
||||
int seekResult; /* Result of previous sqlite3BtreeMoveto() */
|
||||
int pseudoTableReg; /* Register holding pseudotable content. */
|
||||
int nField; /* Number of fields in the header */
|
||||
Bool zeroed; /* True if zeroed out and ready for reuse */
|
||||
Bool rowidIsValid; /* True if lastRowid is valid */
|
||||
Bool atFirst; /* True if pointing to first entry */
|
||||
Bool useRandomRowid; /* Generate new record numbers semi-randomly */
|
||||
Bool nullRow; /* True if pointing to a row with no data */
|
||||
Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
|
||||
Bool isTable; /* True if a table requiring integer keys */
|
||||
Bool isIndex; /* True if an index containing keys only - no data */
|
||||
Bool isOrdered; /* True if the underlying table is BTREE_UNORDERED */
|
||||
Bool isSorter; /* True if a new-style sorter */
|
||||
Bool multiPseudo; /* Multi-register pseudo-cursor */
|
||||
i16 nField; /* Number of fields in the header */
|
||||
u16 nHdrParsed; /* Number of header fields parsed so far */
|
||||
i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */
|
||||
u8 nullRow; /* True if pointing to a row with no data */
|
||||
u8 rowidIsValid; /* True if lastRowid is valid */
|
||||
u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
|
||||
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 */
|
||||
const sqlite3_module *pModule; /* Module for cursor pVtabCursor */
|
||||
i64 seqCount; /* Sequence counter */
|
||||
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
|
||||
i64 lastRowid; /* Last rowid from a Next or NextIdx operation */
|
||||
i64 lastRowid; /* Rowid being deleted by OP_Delete */
|
||||
VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */
|
||||
|
||||
/* Result of last sqlite3BtreeMoveto() done by an OP_NotExists */
|
||||
int seekResult;
|
||||
|
||||
/* Cached information about the header for the data record that the
|
||||
** cursor is currently pointing to. Only valid if cacheStatus matches
|
||||
** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of
|
||||
@@ -95,10 +92,14 @@ struct VdbeCursor {
|
||||
** be NULL.
|
||||
*/
|
||||
u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */
|
||||
int payloadSize; /* Total number of bytes in the record */
|
||||
u32 *aType; /* Type values for all entries in the record */
|
||||
u32 *aOffset; /* Cached offsets to the start of each columns data */
|
||||
u8 *aRow; /* Data for the current row, if all on one page */
|
||||
u32 payloadSize; /* Total number of bytes in the record */
|
||||
u32 szRow; /* Byte available in aRow */
|
||||
u32 iHdrOffset; /* Offset to next unparsed byte of the header */
|
||||
const u8 *aRow; /* Data for the current row, if all on one page */
|
||||
u32 aType[1]; /* Type values for all entries in the record */
|
||||
/* 2*nField extra array elements allocated for aType[], beyond the one
|
||||
** static element declared in the structure. nField total array slots for
|
||||
** aType[] and nField+1 array slots for aOffset[] */
|
||||
};
|
||||
typedef struct VdbeCursor VdbeCursor;
|
||||
|
||||
@@ -423,7 +424,7 @@ double sqlite3VdbeRealValue(Mem*);
|
||||
void sqlite3VdbeIntegerAffinity(Mem*);
|
||||
int sqlite3VdbeMemRealify(Mem*);
|
||||
int sqlite3VdbeMemNumerify(Mem*);
|
||||
int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
|
||||
int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*);
|
||||
void sqlite3VdbeMemRelease(Mem *p);
|
||||
void sqlite3VdbeMemReleaseExternal(Mem *p);
|
||||
#define VdbeMemRelease(X) \
|
||||
|
||||
+14
-13
@@ -453,12 +453,14 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
|
||||
}
|
||||
#endif
|
||||
case OP_Next:
|
||||
case OP_NextIfOpen:
|
||||
case OP_SorterNext: {
|
||||
pOp->p4.xAdvance = sqlite3BtreeNext;
|
||||
pOp->p4type = P4_ADVANCE;
|
||||
break;
|
||||
}
|
||||
case OP_Prev: {
|
||||
case OP_Prev:
|
||||
case OP_PrevIfOpen: {
|
||||
pOp->p4.xAdvance = sqlite3BtreePrevious;
|
||||
pOp->p4type = P4_ADVANCE;
|
||||
break;
|
||||
@@ -1674,7 +1676,7 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
|
||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||
if( pCx->pVtabCursor ){
|
||||
sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
|
||||
const sqlite3_module *pModule = pCx->pModule;
|
||||
const sqlite3_module *pModule = pVtabCursor->pVtab->pModule;
|
||||
p->inVtabMethod = 1;
|
||||
pModule->xClose(pVtabCursor);
|
||||
p->inVtabMethod = 0;
|
||||
@@ -2658,7 +2660,7 @@ int sqlite3VdbeCursorMoveto(VdbeCursor *p){
|
||||
#endif
|
||||
p->deferredMoveto = 0;
|
||||
p->cacheStatus = CACHE_STALE;
|
||||
}else if( ALWAYS(p->pCursor) ){
|
||||
}else if( p->pCursor ){
|
||||
int hasMoved;
|
||||
int rc = sqlite3BtreeCursorHasMoved(p->pCursor, &hasMoved);
|
||||
if( rc ) return rc;
|
||||
@@ -2966,15 +2968,12 @@ u32 sqlite3VdbeSerialGet(
|
||||
return 0;
|
||||
}
|
||||
default: {
|
||||
static const u16 aFlag[] = { MEM_Blob|MEM_Ephem, MEM_Str|MEM_Ephem };
|
||||
u32 len = (serial_type-12)/2;
|
||||
pMem->z = (char *)buf;
|
||||
pMem->n = len;
|
||||
pMem->xDel = 0;
|
||||
if( serial_type&0x01 ){
|
||||
pMem->flags = MEM_Str | MEM_Ephem;
|
||||
}else{
|
||||
pMem->flags = MEM_Blob | MEM_Ephem;
|
||||
}
|
||||
pMem->flags = aFlag[serial_type&1];
|
||||
return len;
|
||||
}
|
||||
}
|
||||
@@ -3113,9 +3112,11 @@ int sqlite3VdbeRecordCompare(
|
||||
|
||||
idx1 = getVarint32(aKey1, szHdr1);
|
||||
d1 = szHdr1;
|
||||
assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField );
|
||||
assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField || CORRUPT_DB );
|
||||
assert( pKeyInfo->aSortOrder!=0 );
|
||||
while( idx1<szHdr1 && i<pPKey2->nField ){
|
||||
assert( pKeyInfo->nField>0 );
|
||||
assert( idx1<=szHdr1 || CORRUPT_DB );
|
||||
do{
|
||||
u32 serial_type1;
|
||||
|
||||
/* Read the serial types for the next element in each key. */
|
||||
@@ -3148,7 +3149,7 @@ int sqlite3VdbeRecordCompare(
|
||||
return rc;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}while( idx1<szHdr1 && i<pPKey2->nField );
|
||||
|
||||
/* No memory allocation is ever used on mem1. Prove this using
|
||||
** the following assert(). If the assert() fails, it indicates a
|
||||
@@ -3206,7 +3207,7 @@ int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
|
||||
|
||||
/* Read in the complete content of the index entry */
|
||||
memset(&m, 0, sizeof(m));
|
||||
rc = sqlite3VdbeMemFromBtree(pCur, 0, (int)nCellKey, 1, &m);
|
||||
rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m);
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
@@ -3284,7 +3285,7 @@ int sqlite3VdbeIdxKeyCompare(
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
memset(&m, 0, sizeof(m));
|
||||
rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, (int)nCellKey, 1, &m);
|
||||
rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, (u32)nCellKey, 1, &m);
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
+4
-3
@@ -64,7 +64,8 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
|
||||
|
||||
rc = sqlite3_step(p->pStmt);
|
||||
if( rc==SQLITE_ROW ){
|
||||
u32 type = v->apCsr[0]->aType[p->iCol];
|
||||
VdbeCursor *pC = v->apCsr[0];
|
||||
u32 type = pC->aType[p->iCol];
|
||||
if( type<12 ){
|
||||
zErr = sqlite3MPrintf(p->db, "cannot open value of type %s",
|
||||
type==0?"null": type==7?"real": "integer"
|
||||
@@ -73,9 +74,9 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
|
||||
sqlite3_finalize(p->pStmt);
|
||||
p->pStmt = 0;
|
||||
}else{
|
||||
p->iOffset = v->apCsr[0]->aOffset[p->iCol];
|
||||
p->iOffset = pC->aType[p->iCol + pC->nField];
|
||||
p->nByte = sqlite3VdbeSerialTypeLen(type);
|
||||
p->pCsr = v->apCsr[0]->pCursor;
|
||||
p->pCsr = pC->pCursor;
|
||||
sqlite3BtreeEnterCursor(p->pCsr);
|
||||
sqlite3BtreeCacheOverflow(p->pCsr);
|
||||
sqlite3BtreeLeaveCursor(p->pCsr);
|
||||
|
||||
+15
-45
@@ -303,15 +303,8 @@ void sqlite3VdbeMemRelease(Mem *p){
|
||||
|
||||
/*
|
||||
** Convert a 64-bit IEEE double into a 64-bit signed integer.
|
||||
** If the double is too large, return 0x8000000000000000.
|
||||
**
|
||||
** Most systems appear to do this simply by assigning
|
||||
** variables and without the extra range tests. But
|
||||
** there are reports that windows throws an expection
|
||||
** if the floating point value is out of range. (See ticket #2880.)
|
||||
** Because we do not completely understand the problem, we will
|
||||
** take the conservative approach and always do range tests
|
||||
** before attempting the conversion.
|
||||
** If the double is out of range of a 64-bit signed integer then
|
||||
** return the closest available 64-bit signed integer.
|
||||
*/
|
||||
static i64 doubleToInt64(double r){
|
||||
#ifdef SQLITE_OMIT_FLOATING_POINT
|
||||
@@ -328,14 +321,10 @@ static i64 doubleToInt64(double r){
|
||||
static const i64 maxInt = LARGEST_INT64;
|
||||
static const i64 minInt = SMALLEST_INT64;
|
||||
|
||||
if( r<(double)minInt ){
|
||||
return minInt;
|
||||
}else if( r>(double)maxInt ){
|
||||
/* minInt is correct here - not maxInt. It turns out that assigning
|
||||
** a very large positive number to an integer results in a very large
|
||||
** negative integer. This makes no sense, but it is what x86 hardware
|
||||
** does so for compatibility we will do the same in software. */
|
||||
if( r<=(double)minInt ){
|
||||
return minInt;
|
||||
}else if( r>=(double)maxInt ){
|
||||
return maxInt;
|
||||
}else{
|
||||
return (i64)r;
|
||||
}
|
||||
@@ -417,17 +406,11 @@ void sqlite3VdbeIntegerAffinity(Mem *pMem){
|
||||
**
|
||||
** The second and third terms in the following conditional enforces
|
||||
** the second condition under the assumption that addition overflow causes
|
||||
** values to wrap around. On x86 hardware, the third term is always
|
||||
** true and could be omitted. But we leave it in because other
|
||||
** architectures might behave differently.
|
||||
** values to wrap around.
|
||||
*/
|
||||
if( pMem->r==(double)pMem->u.i
|
||||
&& pMem->u.i>SMALLEST_INT64
|
||||
#if defined(__i486__) || defined(__x86_64__)
|
||||
&& ALWAYS(pMem->u.i<LARGEST_INT64)
|
||||
#else
|
||||
&& pMem->u.i<LARGEST_INT64
|
||||
#endif
|
||||
){
|
||||
pMem->flags |= MEM_Int;
|
||||
}
|
||||
@@ -896,13 +879,13 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
|
||||
*/
|
||||
int sqlite3VdbeMemFromBtree(
|
||||
BtCursor *pCur, /* Cursor pointing at record to retrieve. */
|
||||
int offset, /* Offset from the start of data to return bytes from. */
|
||||
int amt, /* Number of bytes to return. */
|
||||
u32 offset, /* Offset from the start of data to return bytes from. */
|
||||
u32 amt, /* Number of bytes to return. */
|
||||
int key, /* If true, retrieve from the btree key, not data. */
|
||||
Mem *pMem /* OUT: Return data in this Mem structure. */
|
||||
){
|
||||
char *zData; /* Data from the btree layer */
|
||||
int available = 0; /* Number of bytes available on the local btree page */
|
||||
u32 available = 0; /* Number of bytes available on the local btree page */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
|
||||
assert( sqlite3BtreeCursorIsValid(pCur) );
|
||||
@@ -917,7 +900,7 @@ int sqlite3VdbeMemFromBtree(
|
||||
}
|
||||
assert( zData!=0 );
|
||||
|
||||
if( offset+amt<=available && (pMem->flags&MEM_Dyn)==0 ){
|
||||
if( offset+amt<=available ){
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
pMem->z = &zData[offset];
|
||||
pMem->flags = MEM_Blob|MEM_Ephem;
|
||||
@@ -936,7 +919,7 @@ int sqlite3VdbeMemFromBtree(
|
||||
sqlite3VdbeMemRelease(pMem);
|
||||
}
|
||||
}
|
||||
pMem->n = amt;
|
||||
pMem->n = (int)amt;
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -1033,7 +1016,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
|
||||
int i; /* Counter variable */
|
||||
int nCol = pIdx->nColumn; /* Number of index columns including rowid */
|
||||
|
||||
nByte = sizeof(Mem) * nCol + sizeof(UnpackedRecord);
|
||||
nByte = sizeof(Mem) * nCol + ROUND8(sizeof(UnpackedRecord));
|
||||
pRec = (UnpackedRecord*)sqlite3DbMallocZero(db, nByte);
|
||||
if( pRec ){
|
||||
pRec->pKeyInfo = sqlite3KeyInfoOfIndex(p->pParse, pIdx);
|
||||
@@ -1041,7 +1024,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
|
||||
assert( pRec->pKeyInfo->nField+pRec->pKeyInfo->nXField==nCol );
|
||||
assert( pRec->pKeyInfo->enc==ENC(db) );
|
||||
pRec->flags = UNPACKED_PREFIX_MATCH;
|
||||
pRec->aMem = (Mem *)&pRec[1];
|
||||
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;
|
||||
@@ -1095,16 +1078,7 @@ static int valueFromExpr(
|
||||
return SQLITE_OK;
|
||||
}
|
||||
op = pExpr->op;
|
||||
|
||||
/* op can only be TK_REGISTER if we have compiled with SQLITE_ENABLE_STAT4.
|
||||
** The ifdef here is to enable us to achieve 100% branch test coverage even
|
||||
** when SQLITE_ENABLE_STAT4 is omitted.
|
||||
*/
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
if( op==TK_REGISTER ) op = pExpr->op2;
|
||||
#else
|
||||
if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
|
||||
#endif
|
||||
|
||||
/* Handle negative integers in a single step. This is needed in the
|
||||
** case when the value is -9223372036854775808.
|
||||
@@ -1323,10 +1297,9 @@ int sqlite3Stat4ProbeSetValue(
|
||||
pVal = valueNew(db, &alloc);
|
||||
if( pVal ){
|
||||
sqlite3VdbeMemSetNull((Mem*)pVal);
|
||||
*pbOk = 1;
|
||||
}
|
||||
}else if( pExpr->op==TK_VARIABLE
|
||||
|| (pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE)
|
||||
|| NEVER(pExpr->op==TK_REGISTER && pExpr->op2==TK_VARIABLE)
|
||||
){
|
||||
Vdbe *v;
|
||||
int iBindVar = pExpr->iColumn;
|
||||
@@ -1339,16 +1312,13 @@ int sqlite3Stat4ProbeSetValue(
|
||||
sqlite3ValueApplyAffinity(pVal, affinity, ENC(db));
|
||||
}
|
||||
pVal->db = pParse->db;
|
||||
*pbOk = 1;
|
||||
sqlite3VdbeMemStoreType((Mem*)pVal);
|
||||
}
|
||||
}else{
|
||||
*pbOk = 0;
|
||||
}
|
||||
}else{
|
||||
rc = valueFromExpr(db, pExpr, ENC(db), affinity, &pVal, &alloc);
|
||||
*pbOk = (pVal!=0);
|
||||
}
|
||||
*pbOk = (pVal!=0);
|
||||
|
||||
assert( pVal==0 || pVal->db==db );
|
||||
return rc;
|
||||
|
||||
+15
-9
@@ -1905,8 +1905,7 @@ static void whereKeyStats(
|
||||
#ifndef SQLITE_DEBUG
|
||||
UNUSED_PARAMETER( pParse );
|
||||
#endif
|
||||
assert( pRec!=0 || pParse->db->mallocFailed );
|
||||
if( pRec==0 ) return;
|
||||
assert( pRec!=0 );
|
||||
iCol = pRec->nField - 1;
|
||||
assert( pIdx->nSample>0 );
|
||||
assert( pRec->nField>0 && iCol<pIdx->nSampleCol );
|
||||
@@ -2406,7 +2405,7 @@ static int codeEqualityTerm(
|
||||
}else{
|
||||
pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg);
|
||||
}
|
||||
pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next;
|
||||
pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen;
|
||||
sqlite3VdbeAddOp1(v, OP_IsNull, iReg);
|
||||
}else{
|
||||
pLevel->u.in.nIn = 0;
|
||||
@@ -2756,7 +2755,7 @@ static Bitmask codeOneLoopStart(
|
||||
bRev = (pWInfo->revMask>>iLevel)&1;
|
||||
omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0
|
||||
&& (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)==0;
|
||||
VdbeNoopComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
|
||||
VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
|
||||
|
||||
/* Create labels for the "break" and "continue" instructions
|
||||
** for the current loop. Jump to addrBrk to break out of a loop.
|
||||
@@ -3461,7 +3460,7 @@ static Bitmask codeOneLoopStart(
|
||||
if( pAlt->wtFlags & (TERM_CODED) ) continue;
|
||||
testcase( pAlt->eOperator & WO_EQ );
|
||||
testcase( pAlt->eOperator & WO_IN );
|
||||
VdbeNoopComment((v, "begin transitive constraint"));
|
||||
VdbeModuleComment((v, "begin transitive constraint"));
|
||||
pEAlt = sqlite3StackAllocRaw(db, sizeof(*pEAlt));
|
||||
if( pEAlt ){
|
||||
*pEAlt = *pAlt->pExpr;
|
||||
@@ -3918,10 +3917,17 @@ static int whereLoopAddBtreeIndex(
|
||||
saved_nOut = pNew->nOut;
|
||||
pNew->rSetup = 0;
|
||||
rLogSize = estLog(sqlite3LogEst(pProbe->aiRowEst[0]));
|
||||
|
||||
/* Consider using a skip-scan if there are no WHERE clause constraints
|
||||
** available for the left-most terms of the index, and if the average
|
||||
** number of repeats in the left-most terms is at least 18. The magic
|
||||
** number 18 was found by experimentation to be the payoff point where
|
||||
** skip-scan become faster than a full-scan.
|
||||
*/
|
||||
if( pTerm==0
|
||||
&& saved_nEq==saved_nSkip
|
||||
&& saved_nEq+1<pProbe->nKeyCol
|
||||
&& pProbe->aiRowEst[saved_nEq+1]>50
|
||||
&& pProbe->aiRowEst[saved_nEq+1]>=18 /* TUNING: Minimum for skip-scan */
|
||||
){
|
||||
LogEst nIter;
|
||||
pNew->u.btree.nEq++;
|
||||
@@ -5731,7 +5737,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
}
|
||||
|
||||
/* Done. */
|
||||
VdbeNoopComment((v, "Begin WHERE-core"));
|
||||
VdbeModuleComment((v, "Begin WHERE-core"));
|
||||
return pWInfo;
|
||||
|
||||
/* Jump here if malloc fails */
|
||||
@@ -5758,7 +5764,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
|
||||
/* Generate loop termination code.
|
||||
*/
|
||||
VdbeNoopComment((v, "End WHERE-core"));
|
||||
VdbeModuleComment((v, "End WHERE-core"));
|
||||
sqlite3ExprCacheClear(pParse);
|
||||
for(i=pWInfo->nLevel-1; i>=0; i--){
|
||||
int addr;
|
||||
@@ -5804,7 +5810,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
}
|
||||
sqlite3VdbeJumpHere(v, addr);
|
||||
}
|
||||
VdbeNoopComment((v, "End WHERE-loop%d: %s", i,
|
||||
VdbeModuleComment((v, "End WHERE-loop%d: %s", i,
|
||||
pWInfo->pTabList->a[pLevel->iFrom].pTab->zName));
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -805,8 +805,9 @@ do_test 16.1 {
|
||||
ANALYZE;
|
||||
}
|
||||
set nByte2 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1]
|
||||
puts -nonewline " (nByte=$nByte nByte2=$nByte2)"
|
||||
|
||||
expr {$nByte2 > $nByte+900 && $nByte2 < $nByte+1050}
|
||||
expr {$nByte2 > $nByte+900 && $nByte2 < $nByte+1100}
|
||||
} {1}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
if {![info exists __GNUC__]} {
|
||||
if {![info exists __GNUC__] || [regexp arm $tcl_platform(machine)]} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
+1
-1
@@ -216,7 +216,7 @@ do_test autoinc-2.27 {
|
||||
} {t1 1238}
|
||||
do_test autoinc-2.28 {
|
||||
execsql {
|
||||
UPDATE sqlite_sequence SET seq='12345678901234567890'
|
||||
UPDATE sqlite_sequence SET seq='-12345678901234567890'
|
||||
WHERE name='t1';
|
||||
INSERT INTO t1 VALUES(NULL,6);
|
||||
SELECT * FROM t1;
|
||||
|
||||
@@ -305,6 +305,11 @@ foreach {i conf1 cmd t0 t1 t2 t3 t4} {
|
||||
15 {} {UPDATE OR ABORT} 1 {1 2 3 4} 1 0 1
|
||||
16 {} {UPDATE OR ROLLBACK} 1 {1 2 3 4} 0 0 0
|
||||
} {
|
||||
|
||||
# When using in-memory journals, no temporary files are required for
|
||||
# statement journals.
|
||||
if {[permutation] == "inmemory_journal"} { set t4 0 }
|
||||
|
||||
if {$t0} {set t1 {UNIQUE constraint failed: t1.a}}
|
||||
if {[info exists TEMP_STORE] && $TEMP_STORE==3} {
|
||||
set t3 0
|
||||
|
||||
@@ -25,6 +25,10 @@ source $testdir/tester.tcl
|
||||
#
|
||||
do_not_use_codec
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
database_may_be_corrupt
|
||||
|
||||
# Construct a large database for testing.
|
||||
#
|
||||
do_test corrupt-1.1 {
|
||||
|
||||
@@ -23,6 +23,10 @@ source $testdir/tester.tcl
|
||||
#
|
||||
do_not_use_codec
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
database_may_be_corrupt
|
||||
|
||||
set presql ""
|
||||
catch { set presql "$::G(perm:presql);" }
|
||||
unset -nocomplain ::G(perm:presql)
|
||||
|
||||
@@ -23,6 +23,10 @@ source $testdir/tester.tcl
|
||||
#
|
||||
do_not_use_codec
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
database_may_be_corrupt
|
||||
|
||||
# We must have the page_size pragma for these tests to work.
|
||||
#
|
||||
ifcapable !pager_pragmas||direct_read {
|
||||
|
||||
@@ -23,6 +23,10 @@ source $testdir/tester.tcl
|
||||
#
|
||||
do_not_use_codec
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
database_may_be_corrupt
|
||||
|
||||
# We must have the page_size pragma for these tests to work.
|
||||
#
|
||||
ifcapable !pager_pragmas {
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
database_may_be_corrupt
|
||||
|
||||
# We must have the page_size pragma for these tests to work.
|
||||
#
|
||||
ifcapable !pager_pragmas {
|
||||
|
||||
@@ -24,6 +24,10 @@ source $testdir/tester.tcl
|
||||
#
|
||||
do_not_use_codec
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
database_may_be_corrupt
|
||||
|
||||
# We must have the page_size pragma for these tests to work.
|
||||
#
|
||||
ifcapable !pager_pragmas {
|
||||
|
||||
@@ -24,6 +24,10 @@ source $testdir/tester.tcl
|
||||
#
|
||||
do_not_use_codec
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
database_may_be_corrupt
|
||||
|
||||
# We must have the page_size pragma for these tests to work.
|
||||
#
|
||||
ifcapable !pager_pragmas {
|
||||
|
||||
@@ -24,6 +24,10 @@ source $testdir/tester.tcl
|
||||
#
|
||||
do_not_use_codec
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
database_may_be_corrupt
|
||||
|
||||
# We must have the page_size pragma for these tests to work.
|
||||
#
|
||||
ifcapable !pager_pragmas||!autovacuum {
|
||||
|
||||
@@ -24,6 +24,10 @@ source $testdir/tester.tcl
|
||||
#
|
||||
do_not_use_codec
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
database_may_be_corrupt
|
||||
|
||||
# We must have the page_size pragma for these tests to work.
|
||||
#
|
||||
ifcapable !pager_pragmas {
|
||||
|
||||
@@ -24,6 +24,10 @@ source $testdir/tester.tcl
|
||||
#
|
||||
do_not_use_codec
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
database_may_be_corrupt
|
||||
|
||||
|
||||
# Create a database to work with.
|
||||
#
|
||||
|
||||
@@ -30,6 +30,10 @@ source $testdir/tester.tcl
|
||||
#
|
||||
do_not_use_codec
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
database_may_be_corrupt
|
||||
|
||||
|
||||
do_test corruptB-1.1 {
|
||||
execsql {
|
||||
|
||||
+9
-1
@@ -27,6 +27,10 @@ source $testdir/tester.tcl
|
||||
#
|
||||
do_not_use_codec
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
database_may_be_corrupt
|
||||
|
||||
# Construct a compact, dense database for testing.
|
||||
#
|
||||
do_test corruptC-1.1 {
|
||||
@@ -202,6 +206,10 @@ do_test corruptC-2.8 {
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
# corruption (seed 170434)
|
||||
#
|
||||
# UPDATE: Prior to 3.8.2, this used to return SQLITE_CORRUPT. It no longer
|
||||
# does. That is Ok, the point of these tests is to verify that no buffer
|
||||
# overruns or overreads can be caused by corrupt databases.
|
||||
do_test corruptC-2.9 {
|
||||
db close
|
||||
forcecopy test.bu test.db
|
||||
@@ -211,7 +219,7 @@ do_test corruptC-2.9 {
|
||||
|
||||
sqlite3 db test.db
|
||||
catchsql {BEGIN; DELETE FROM t1 WHERE x>13; ROLLBACK;}
|
||||
} {1 {database disk image is malformed}}
|
||||
} {0 {}}
|
||||
|
||||
# corruption (seed 186504)
|
||||
do_test corruptC-2.10 {
|
||||
|
||||
@@ -19,6 +19,10 @@ source $testdir/tester.tcl
|
||||
#
|
||||
do_not_use_codec
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
database_may_be_corrupt
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# OVERVIEW
|
||||
#
|
||||
|
||||
@@ -24,6 +24,10 @@ source $testdir/tester.tcl
|
||||
#
|
||||
do_not_use_codec
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
database_may_be_corrupt
|
||||
|
||||
# Do not run the tests in this file if ENABLE_OVERSIZE_CELL_CHECK is on.
|
||||
#
|
||||
ifcapable oversize_cell_check {
|
||||
|
||||
@@ -19,6 +19,10 @@ set testprefix corruptF
|
||||
#
|
||||
do_not_use_codec
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
database_may_be_corrupt
|
||||
|
||||
proc str {i} { format %08d $i }
|
||||
|
||||
# Create a 6 page database containing a single table - t1. Table t1
|
||||
|
||||
@@ -19,6 +19,10 @@ set testprefix corruptG
|
||||
#
|
||||
do_not_use_codec
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
database_may_be_corrupt
|
||||
|
||||
# Create a simple database with a single entry. Then corrupt the
|
||||
# header-size varint on the index payload so that it maps into a
|
||||
# negative number. Try to use the database.
|
||||
|
||||
@@ -1103,7 +1103,7 @@ do_catchsql_test e_createtable-3.11.5 {
|
||||
# EVIDENCE-OF: R-52382-54248 Each table in SQLite may have at most one
|
||||
# PRIMARY KEY.
|
||||
#
|
||||
# EVIDENCE-OF: R-62315-57691 An error is rasied if more than one PRIMARY
|
||||
# EVIDENCE-OF: R-31826-01813 An error is raised if more than one PRIMARY
|
||||
# KEY clause appears in a CREATE TABLE statement.
|
||||
#
|
||||
# To test the two above, show that zero primary keys is Ok, one primary
|
||||
@@ -1654,6 +1654,10 @@ do_execsql_test 4.19.4 { SELECT * FROM t5 } {}
|
||||
# of the special case-independent names "rowid", "oid", or "_rowid_" in
|
||||
# place of a column name.
|
||||
#
|
||||
# EVIDENCE-OF: R-06726-07466 A column name can be any of the names
|
||||
# defined in the CREATE TABLE statement or one of the following special
|
||||
# identifiers: "ROWID", "OID", or "_ROWID_".
|
||||
#
|
||||
drop_all_tables
|
||||
do_execsql_test 5.1.0 {
|
||||
CREATE TABLE t1(x, y);
|
||||
@@ -1678,6 +1682,10 @@ do_createtable_tests 5.1 {
|
||||
# explicitly declared column and cannot be used to retrieve the integer
|
||||
# rowid value.
|
||||
#
|
||||
# EVIDENCE-OF: R-44615-33286 The special identifiers only refer to the
|
||||
# row key if the CREATE TABLE statement does not define a real column
|
||||
# with the same name.
|
||||
#
|
||||
do_execsql_test 5.2.0 {
|
||||
CREATE TABLE t2(oid, b);
|
||||
CREATE TABLE t3(a, _rowid_);
|
||||
|
||||
+57
-14
@@ -1081,9 +1081,9 @@ ifcapable !icu {
|
||||
# EVIDENCE-OF: R-33693-50180 The REGEXP operator is a special syntax for
|
||||
# the regexp() user function.
|
||||
#
|
||||
# EVIDENCE-OF: R-57289-13578 If a application-defined SQL function named
|
||||
# "regexp" is added at run-time, that function will be called in order
|
||||
# to implement the REGEXP operator.
|
||||
# EVIDENCE-OF: R-65524-61849 If an application-defined SQL function
|
||||
# named "regexp" is added at run-time, then the "X REGEXP Y" operator
|
||||
# will be implemented as a call to "regexp(Y,X)".
|
||||
#
|
||||
proc regexpfunc {args} {
|
||||
eval lappend ::regexpargs $args
|
||||
@@ -1407,10 +1407,12 @@ do_test e_expr-26.1.6 { set ::evalcount } {5}
|
||||
#-------------------------------------------------------------------------
|
||||
# Test statements related to CAST expressions.
|
||||
#
|
||||
# EVIDENCE-OF: R-65079-31758 Application of a CAST expression is
|
||||
# different to application of a column affinity, as with a CAST
|
||||
# expression the storage class conversion is forced even if it is lossy
|
||||
# and irrreversible.
|
||||
# EVIDENCE-OF: R-20854-17109 A CAST conversion is similar to the
|
||||
# conversion that takes place when a column affinity is applied to a
|
||||
# value except that with the CAST operator the conversion always takes
|
||||
# place even if the conversion lossy and irreversible, whereas column
|
||||
# affinity only changes the data type of a value if the change is
|
||||
# lossless and reversible.
|
||||
#
|
||||
do_execsql_test e_expr-27.1.1 {
|
||||
CREATE TABLE t3(a TEXT, b REAL, c INTEGER);
|
||||
@@ -1594,26 +1596,29 @@ do_expr_test e_expr-30.4.1 { CAST('' AS INTEGER) } integer 0
|
||||
do_expr_test e_expr-30.4.2 { CAST('not a number' AS INTEGER) } integer 0
|
||||
do_expr_test e_expr-30.4.3 { CAST('XXI' AS INTEGER) } integer 0
|
||||
|
||||
# EVIDENCE-OF: R-00741-38776 A cast of a REAL value into an INTEGER will
|
||||
# truncate the fractional part of the REAL.
|
||||
# EVIDENCE-OF: R-02752-50091 A cast of a REAL value into an INTEGER
|
||||
# results in the integer between the REAL value and zero that is closest
|
||||
# to the REAL value.
|
||||
#
|
||||
do_expr_test e_expr-31.1.1 { CAST(3.14159 AS INTEGER) } integer 3
|
||||
do_expr_test e_expr-31.1.2 { CAST(1.99999 AS INTEGER) } integer 1
|
||||
do_expr_test e_expr-31.1.3 { CAST(-1.99999 AS INTEGER) } integer -1
|
||||
do_expr_test e_expr-31.1.4 { CAST(-0.99999 AS INTEGER) } integer 0
|
||||
|
||||
# EVIDENCE-OF: R-49503-28105 If a REAL is too large to be represented as
|
||||
# an INTEGER then the result of the cast is the largest negative
|
||||
# integer: -9223372036854775808.
|
||||
# EVIDENCE-OF: R-51517-40824 If a REAL is greater than the greatest
|
||||
# possible signed integer (+9223372036854775807) then the result is the
|
||||
# greatest possible signed integer and if the REAL is less than the
|
||||
# least possible signed integer (-9223372036854775808) then the result
|
||||
# is the least possible signed integer.
|
||||
#
|
||||
do_expr_test e_expr-31.2.1 { CAST(2e+50 AS INT) } integer -9223372036854775808
|
||||
do_expr_test e_expr-31.2.1 { CAST(2e+50 AS INT) } integer 9223372036854775807
|
||||
do_expr_test e_expr-31.2.2 { CAST(-2e+50 AS INT) } integer -9223372036854775808
|
||||
do_expr_test e_expr-31.2.3 {
|
||||
CAST(-9223372036854775809.0 AS INT)
|
||||
} integer -9223372036854775808
|
||||
do_expr_test e_expr-31.2.4 {
|
||||
CAST(9223372036854775809.0 AS INT)
|
||||
} integer -9223372036854775808
|
||||
} integer 9223372036854775807
|
||||
|
||||
|
||||
# EVIDENCE-OF: R-09295-61337 Casting a TEXT or BLOB value into NUMERIC
|
||||
@@ -1847,5 +1852,43 @@ foreach {tn expr} {
|
||||
do_expr_test e_expr-36.4.$tn $expr null {}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-62477-06476 For example, the values NULL, 0.0, 0,
|
||||
# 'english' and '0' are all considered to be false.
|
||||
#
|
||||
do_execsql_test e_expr-37.1 {
|
||||
SELECT CASE WHEN NULL THEN 'true' ELSE 'false' END;
|
||||
} {false}
|
||||
do_execsql_test e_expr-37.2 {
|
||||
SELECT CASE WHEN 0.0 THEN 'true' ELSE 'false' END;
|
||||
} {false}
|
||||
do_execsql_test e_expr-37.3 {
|
||||
SELECT CASE WHEN 0 THEN 'true' ELSE 'false' END;
|
||||
} {false}
|
||||
do_execsql_test e_expr-37.4 {
|
||||
SELECT CASE WHEN 'engligh' THEN 'true' ELSE 'false' END;
|
||||
} {false}
|
||||
do_execsql_test e_expr-37.5 {
|
||||
SELECT CASE WHEN '0' THEN 'true' ELSE 'false' END;
|
||||
} {false}
|
||||
|
||||
# EVIDENCE-OF: R-55532-10108 Values 1, 1.0, 0.1, -0.1 and '1english' are
|
||||
# considered to be true.
|
||||
#
|
||||
do_execsql_test e_expr-37.6 {
|
||||
SELECT CASE WHEN 1 THEN 'true' ELSE 'false' END;
|
||||
} {true}
|
||||
do_execsql_test e_expr-37.7 {
|
||||
SELECT CASE WHEN 1.0 THEN 'true' ELSE 'false' END;
|
||||
} {true}
|
||||
do_execsql_test e_expr-37.8 {
|
||||
SELECT CASE WHEN 0.1 THEN 'true' ELSE 'false' END;
|
||||
} {true}
|
||||
do_execsql_test e_expr-37.9 {
|
||||
SELECT CASE WHEN -0.1 THEN 'true' ELSE 'false' END;
|
||||
} {true}
|
||||
do_execsql_test e_expr-37.10 {
|
||||
SELECT CASE WHEN '1english' THEN 'true' ELSE 'false' END;
|
||||
} {true}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -69,7 +69,10 @@ proc catch_fk_error {zSql} {
|
||||
if {[string match {*foreign key*} $msg]} {
|
||||
return ""
|
||||
}
|
||||
if {$msg eq "out of memory" || $msg eq "constraint failed"} {
|
||||
if {$msg eq "out of memory"
|
||||
|| $msg eq "FOREIGN KEY constraint failed"
|
||||
|| $msg eq "constraint failed"
|
||||
} {
|
||||
error 1
|
||||
}
|
||||
error $msg
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# $Id: fts3.test,v 1.2 2008/07/23 18:17:32 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/permutations.test
|
||||
source $testdir/tester.tcl
|
||||
set testprefix fts3varint
|
||||
|
||||
ifcapable !fts3 {
|
||||
|
||||
@@ -1319,6 +1319,24 @@ do_test func-29.6 {
|
||||
set x
|
||||
} {1}
|
||||
|
||||
# The OP_Column opcode has an optimization that avoids loading content
|
||||
# for fields with content-length=0 when the content offset is on an overflow
|
||||
# page. Make sure the optimization works.
|
||||
#
|
||||
do_execsql_test func-29.10 {
|
||||
CREATE TABLE t29b(a,b,c,d,e,f,g,h,i);
|
||||
INSERT INTO t29b
|
||||
VALUES(1, hex(randomblob(2000)), null, 0, 1, '', zeroblob(0),'x',x'01');
|
||||
SELECT typeof(c), typeof(d), typeof(e), typeof(f),
|
||||
typeof(g), typeof(h), typeof(i) FROM t29b;
|
||||
} {null integer integer text blob text blob}
|
||||
do_execsql_test func-29.11 {
|
||||
SELECT length(f), length(g), length(h), length(i) FROM t29b;
|
||||
} {0 0 1 1}
|
||||
do_execsql_test func-29.12 {
|
||||
SELECT quote(f), quote(g), quote(h), quote(i) FROM t29b;
|
||||
} {'' X'' 'x' X'01'}
|
||||
|
||||
# EVIDENCE-OF: R-29701-50711 The unicode(X) function returns the numeric
|
||||
# unicode code point corresponding to the first character of the string
|
||||
# X.
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# 2013-11-21
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#*************************************************************************
|
||||
#
|
||||
# Verify that constant string expressions that get factored into initializing
|
||||
# code are not reused between function parameters and other values in the
|
||||
# VDBE program, as the function might have changed the encoding.
|
||||
#
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
do_execsql_test func5-1.1 {
|
||||
PRAGMA encoding=UTF16le;
|
||||
CREATE TABLE t1(x,a,b,c);
|
||||
INSERT INTO t1 VALUES(1,'ab','cd',1);
|
||||
INSERT INTO t1 VALUES(2,'gh','ef',5);
|
||||
INSERT INTO t1 VALUES(3,'pqr','fuzzy',99);
|
||||
INSERT INTO t1 VALUES(4,'abcdefg','xy',22);
|
||||
INSERT INTO t1 VALUES(5,'shoe','mayer',2953);
|
||||
SELECT x FROM t1 WHERE c=instr('abcdefg',b) OR a='abcdefg' ORDER BY +x;
|
||||
} {2 4}
|
||||
do_execsql_test func5-1.2 {
|
||||
SELECT x FROM t1 WHERE a='abcdefg' OR c=instr('abcdefg',b) ORDER BY +x;
|
||||
} {2 4}
|
||||
|
||||
finish_test
|
||||
@@ -18,6 +18,9 @@
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# These tests deal with corrupt database files
|
||||
#
|
||||
database_may_be_corrupt
|
||||
|
||||
expr srand(123)
|
||||
|
||||
|
||||
+50
-2
@@ -127,21 +127,52 @@ db2 close
|
||||
# depopulation of indices, to make sure the update-hook is not
|
||||
# invoked incorrectly.
|
||||
#
|
||||
# EVIDENCE-OF: R-21999-45122 The sqlite3_update_hook() interface
|
||||
# registers a callback function with the database connection identified
|
||||
# by the first argument to be invoked whenever a row is updated,
|
||||
# inserted or deleted in a rowid table.
|
||||
|
||||
# Simple tests
|
||||
do_test hook-4.1.1 {
|
||||
do_test hook-4.1.1a {
|
||||
catchsql {
|
||||
DROP TABLE t1;
|
||||
}
|
||||
unset -nocomplain ::update_hook
|
||||
set ::update_hook {}
|
||||
db update_hook [list lappend ::update_hook]
|
||||
#
|
||||
# EVIDENCE-OF: R-52223-27275 The update hook is not invoked when
|
||||
# internal system tables are modified (i.e. sqlite_master and
|
||||
# sqlite_sequence).
|
||||
#
|
||||
execsql {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
CREATE TABLE t1w(a INT PRIMARY KEY, b) WITHOUT ROWID;
|
||||
}
|
||||
set ::update_hook
|
||||
} {}
|
||||
do_test hook-4.1.1b {
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES(1, 'one');
|
||||
INSERT INTO t1 VALUES(2, 'two');
|
||||
INSERT INTO t1 VALUES(3, 'three');
|
||||
INSERT INTO t1w SELECT * FROM t1;
|
||||
}
|
||||
db update_hook [list lappend ::update_hook]
|
||||
} {}
|
||||
|
||||
# EVIDENCE-OF: R-15506-57666 The second callback argument is one of
|
||||
# SQLITE_INSERT, SQLITE_DELETE, or SQLITE_UPDATE, depending on the
|
||||
# operation that caused the callback to be invoked.
|
||||
#
|
||||
# EVIDENCE-OF: R-29213-61195 The third and fourth arguments to the
|
||||
# callback contain pointers to the database and table name containing
|
||||
# the affected row.
|
||||
#
|
||||
# EVIDENCE-OF: R-30809-57812 The final callback parameter is the rowid
|
||||
# of the row.
|
||||
#
|
||||
do_test hook-4.1.2 {
|
||||
set ::update_hook {}
|
||||
execsql {
|
||||
INSERT INTO t1 VALUES(4, 'four');
|
||||
DELETE FROM t1 WHERE b = 'two';
|
||||
@@ -159,6 +190,23 @@ do_test hook-4.1.2 {
|
||||
DELETE main t1 4 \
|
||||
]
|
||||
|
||||
# EVIDENCE-OF: R-61808-14344 The sqlite3_update_hook() interface does
|
||||
# not fire callbacks for changes to a WITHOUT ROWID table.
|
||||
#
|
||||
# EVIDENCE-OF: R-33257-44249 The update hook is not invoked when WITHOUT
|
||||
# ROWID tables are modified.
|
||||
#
|
||||
do_test hook-4.1.2w {
|
||||
set ::update_hook {}
|
||||
execsql {
|
||||
INSERT INTO t1w VALUES(4, 'four');
|
||||
DELETE FROM t1w WHERE b = 'two';
|
||||
UPDATE t1w SET b = '' WHERE a = 1 OR a = 3;
|
||||
DELETE FROM t1w WHERE 1; -- Avoid the truncate optimization (for now)
|
||||
}
|
||||
set ::update_hook
|
||||
} {}
|
||||
|
||||
ifcapable trigger {
|
||||
# Update hook is not invoked for changes to sqlite_master
|
||||
#
|
||||
|
||||
+1
-1
@@ -258,7 +258,7 @@ do_ioerr_test ioerr-10 -ckrefcount true -tclprep {
|
||||
INSERT INTO t1 SELECT (a+500)%900, 'good string' FROM t1;
|
||||
}} msg
|
||||
|
||||
if {$msg != "column a is not unique"} {
|
||||
if {$msg != "UNIQUE constraint failed: t1.a"} {
|
||||
error $msg
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,17 @@ do_test lastinsert-1.1 {
|
||||
}
|
||||
} {0 3}
|
||||
|
||||
# EVIDENCE-OF: R-47220-63683 The sqlite3_last_insert_rowid() function
|
||||
# does not work for WITHOUT ROWID tables.
|
||||
#
|
||||
do_test lastinsert-1.1w {
|
||||
catchsql {
|
||||
create table t1w (k integer primary key) WITHOUT ROWID;
|
||||
insert into t1w values (123456);
|
||||
select last_insert_rowid(); -- returns 3 from above.
|
||||
}
|
||||
} {0 3}
|
||||
|
||||
# LIRID unchanged after an update on a table
|
||||
do_test lastinsert-1.2 {
|
||||
catchsql {
|
||||
|
||||
+3
-1
@@ -12,7 +12,9 @@
|
||||
# focus of this file is testing the magic ROWID column that is
|
||||
# found on all tables.
|
||||
#
|
||||
# $Id: rowid.test,v 1.21 2009/06/26 15:14:55 drh Exp $
|
||||
# EVIDENCE-OF: R-36924-43758 By default, every row in SQLite has a
|
||||
# special column, usually called the "rowid", that uniquely identifies
|
||||
# that row within the table.
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# This script runs the wordcount program in different ways, comparing
|
||||
# the output from each.
|
||||
#
|
||||
|
||||
|
||||
# Run the wordcount command with argument supplied and with --summary.
|
||||
# Store the results in wc-out.txt and report the run-time.
|
||||
#
|
||||
function time_wordcount {
|
||||
/usr/bin/time --format='%e %C' ./wordcount --summary $* >wc-out.txt
|
||||
}
|
||||
|
||||
# Compare wc-out.txt against wc-baseline.txt and report any differences.
|
||||
#
|
||||
function compare_results {
|
||||
if cmp -s wc-out.txt wc-baseline.txt;
|
||||
then echo hi >/dev/null;
|
||||
else echo ERROR:;
|
||||
diff -u wc-baseline.txt wc-out.txt;
|
||||
fi
|
||||
}
|
||||
|
||||
# Select the source text to be analyzed.
|
||||
#
|
||||
if test "x$1" = "x";
|
||||
then echo "Usage: $0 FILENAME [ARGS...]"; exit 1;
|
||||
fi
|
||||
|
||||
# Do test runs
|
||||
#
|
||||
rm -f wcdb1.db
|
||||
time_wordcount wcdb1.db $* --insert
|
||||
mv wc-out.txt wc-baseline.txt
|
||||
rm -f wcdb2.db
|
||||
time_wordcount wcdb2.db $* --insert --without-rowid
|
||||
compare_results
|
||||
|
||||
rm -f wcdb1.db
|
||||
time_wordcount wcdb1.db $* --replace
|
||||
compare_results
|
||||
rm -f wcdb2.db
|
||||
time_wordcount wcdb2.db $* --replace --without-rowid
|
||||
compare_results
|
||||
|
||||
rm -f wcdb1.db
|
||||
time_wordcount wcdb1.db $* --select
|
||||
compare_results
|
||||
rm -f wcdb2.db
|
||||
time_wordcount wcdb2.db $* --select --without-rowid
|
||||
compare_results
|
||||
|
||||
time_wordcount wcdb1.db $* --query
|
||||
mv wc-out.txt wc-baseline.txt
|
||||
time_wordcount wcdb2.db $* --query --without-rowid
|
||||
compare_results
|
||||
|
||||
time_wordcount wcdb1.db $* --delete
|
||||
mv wc-out.txt wc-baseline.txt
|
||||
time_wordcount wcdb2.db $* --delete --without-rowid
|
||||
compare_results
|
||||
|
||||
# Clean up temporary files created.
|
||||
#
|
||||
rm -rf wcdb1.db wcdb2.db wc-out.txt wc-baseline.txt
|
||||
@@ -0,0 +1,78 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# This script runs the wordcount program in different ways, comparing
|
||||
# the output from each.
|
||||
#
|
||||
|
||||
# Select the source text to be analyzed.
|
||||
#
|
||||
if test "x$1" = "x";
|
||||
then echo "Usage: $0 FILENAME [ARGS...]"; exit 1;
|
||||
fi
|
||||
|
||||
# Do test runs
|
||||
#
|
||||
rm -f wcdb1.db
|
||||
./wordcount --timer --summary wcdb1.db $* --insert >wc-out.txt
|
||||
mv wc-out.txt wc-baseline.txt
|
||||
rm -f wcdb2.db
|
||||
./wordcount --timer --summary wcdb2.db $* --insert --without-rowid >wc-out.txt
|
||||
if cmp -s wc-out.txt wc-baseline.txt;
|
||||
then echo hi >/dev/null;
|
||||
else echo ERROR:;
|
||||
diff -u wc-baseline.txt wc-out.txt;
|
||||
fi
|
||||
|
||||
rm -f wcdb1.db
|
||||
./wordcount --timer --summary wcdb1.db $* --replace >wc-out.txt
|
||||
if cmp -s wc-out.txt wc-baseline.txt;
|
||||
then echo hi >/dev/null;
|
||||
else echo ERROR:;
|
||||
diff -u wc-baseline.txt wc-out.txt;
|
||||
fi
|
||||
rm -f wcdb2.db
|
||||
./wordcount --timer --summary wcdb2.db $* --replace --without-rowid >wc-out.txt
|
||||
if cmp -s wc-out.txt wc-baseline.txt;
|
||||
then echo hi >/dev/null;
|
||||
else echo ERROR:;
|
||||
diff -u wc-baseline.txt wc-out.txt;
|
||||
fi
|
||||
|
||||
rm -f wcdb1.db
|
||||
./wordcount --timer --summary wcdb1.db $* --select >wc-out.txt
|
||||
if cmp -s wc-out.txt wc-baseline.txt;
|
||||
then echo hi >/dev/null;
|
||||
else echo ERROR:;
|
||||
diff -u wc-baseline.txt wc-out.txt;
|
||||
fi
|
||||
|
||||
rm -f wcdb2.db
|
||||
./wordcount --timer --summary wcdb2.db $* --select --without-rowid >wc-out.txt
|
||||
if cmp -s wc-out.txt wc-baseline.txt;
|
||||
then echo hi >/dev/null;
|
||||
else echo ERROR:;
|
||||
diff -u wc-baseline.txt wc-out.txt;
|
||||
fi
|
||||
|
||||
./wordcount --timer --summary wcdb1.db $* --query >wc-out.txt
|
||||
mv wc-out.txt wc-baseline.txt
|
||||
./wordcount --timer --summary wcdb2.db $* --query --without-rowid >wc-out.txt
|
||||
if cmp -s wc-out.txt wc-baseline.txt;
|
||||
then echo hi >/dev/null;
|
||||
else echo ERROR:;
|
||||
diff -u wc-baseline.txt wc-out.txt;
|
||||
fi
|
||||
|
||||
./wordcount --timer --summary wcdb1.db $* --delete >wc-out.txt
|
||||
mv wc-out.txt wc-baseline.txt
|
||||
./wordcount --timer --summary wcdb2.db $* --delete --without-rowid >wc-out.txt
|
||||
if cmp -s wc-out.txt wc-baseline.txt;
|
||||
then echo hi >/dev/null;
|
||||
else echo ERROR:;
|
||||
diff -u wc-baseline.txt wc-out.txt;
|
||||
fi
|
||||
|
||||
|
||||
# Clean up temporary files created.
|
||||
#
|
||||
rm -rf wcdb1.db wcdb2.db wc-out.txt wc-baseline.txt
|
||||
@@ -0,0 +1,190 @@
|
||||
# 2013-11-27
|
||||
#
|
||||
# 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 tests of the "skip-scan" query strategy.
|
||||
#
|
||||
# The test cases in this file are derived from the description of
|
||||
# the skip-scan query strategy in the "optoverview.html" document.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
do_execsql_test skipscan2-1.1 {
|
||||
CREATE TABLE people(
|
||||
name TEXT PRIMARY KEY,
|
||||
role TEXT NOT NULL,
|
||||
height INT NOT NULL, -- in cm
|
||||
CHECK( role IN ('student','teacher') )
|
||||
);
|
||||
CREATE INDEX people_idx1 ON people(role, height);
|
||||
} {}
|
||||
do_execsql_test skipscan2-1.2 {
|
||||
INSERT INTO people VALUES('Alice','student',156);
|
||||
INSERT INTO people VALUES('Bob','student',161);
|
||||
INSERT INTO people VALUES('Cindy','student',155);
|
||||
INSERT INTO people VALUES('David','student',181);
|
||||
INSERT INTO people VALUES('Emily','teacher',158);
|
||||
INSERT INTO people VALUES('Fred','student',163);
|
||||
INSERT INTO people VALUES('Ginny','student',169);
|
||||
INSERT INTO people VALUES('Harold','student',172);
|
||||
INSERT INTO people VALUES('Imma','student',179);
|
||||
INSERT INTO people VALUES('Jack','student',181);
|
||||
INSERT INTO people VALUES('Karen','student',163);
|
||||
INSERT INTO people VALUES('Logan','student',177);
|
||||
INSERT INTO people VALUES('Megan','teacher',159);
|
||||
INSERT INTO people VALUES('Nathan','student',163);
|
||||
INSERT INTO people VALUES('Olivia','student',161);
|
||||
INSERT INTO people VALUES('Patrick','teacher',180);
|
||||
INSERT INTO people VALUES('Quiana','student',182);
|
||||
INSERT INTO people VALUES('Robert','student',159);
|
||||
INSERT INTO people VALUES('Sally','student',166);
|
||||
INSERT INTO people VALUES('Tom','student',171);
|
||||
INSERT INTO people VALUES('Ursula','student',170);
|
||||
INSERT INTO people VALUES('Vance','student',179);
|
||||
INSERT INTO people VALUES('Willma','student',175);
|
||||
INSERT INTO people VALUES('Xavier','teacher',185);
|
||||
INSERT INTO people VALUES('Yvonne','student',149);
|
||||
INSERT INTO people VALUES('Zach','student',170);
|
||||
}
|
||||
|
||||
# Without ANALYZE, a skip-scan is not used
|
||||
#
|
||||
do_execsql_test skipscan2-1.3 {
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
do_execsql_test skipscan2-1.3eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {~/*INDEX people_idx1 */}
|
||||
|
||||
# Now do an ANALYZE. A skip-scan can be used after ANALYZE.
|
||||
#
|
||||
do_execsql_test skipscan2-1.4 {
|
||||
ANALYZE;
|
||||
-- We do not have enough people above to actually force the use
|
||||
-- of a skip-scan. So make a manual adjustment to the stat1 table
|
||||
-- to make it seem like there are many more.
|
||||
UPDATE sqlite_stat1 SET stat='10000 5000 20' WHERE idx='people_idx1';
|
||||
ANALYZE sqlite_master;
|
||||
}
|
||||
db cache flush
|
||||
do_execsql_test skipscan2-1.5 {
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
do_execsql_test skipscan2-1.5eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {/*INDEX people_idx1 */}
|
||||
|
||||
# Same answer with other formulations of the same query
|
||||
#
|
||||
do_execsql_test skipscan2-1.6 {
|
||||
SELECT name FROM people
|
||||
WHERE role IN (SELECT DISTINCT role FROM people)
|
||||
AND height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
do_execsql_test skipscan2-1.7 {
|
||||
SELECT name FROM people WHERE role='teacher' AND height>=180
|
||||
UNION ALL
|
||||
SELECT name FROM people WHERE role='student' AND height>=180
|
||||
ORDER BY 1;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
|
||||
# Add 8 more people, bringing the total to 34. Then the number of
|
||||
# duplicates in the left-column of the index will be 17 and
|
||||
# skip-scan should not be used after an (unfudged) ANALYZE.
|
||||
#
|
||||
do_execsql_test skipscan2-1.8 {
|
||||
INSERT INTO people VALUES('Angie','student',166);
|
||||
INSERT INTO people VALUES('Brad','student',176);
|
||||
INSERT INTO people VALUES('Claire','student',168);
|
||||
INSERT INTO people VALUES('Donald','student',162);
|
||||
INSERT INTO people VALUES('Elaine','student',177);
|
||||
INSERT INTO people VALUES('Frazier','student',159);
|
||||
INSERT INTO people VALUES('Grace','student',179);
|
||||
INSERT INTO people VALUES('Horace','student',166);
|
||||
ANALYZE;
|
||||
SELECT stat FROM sqlite_stat1 WHERE idx='people_idx1';
|
||||
} {{34 17 2}}
|
||||
db cache flush
|
||||
do_execsql_test skipscan2-1.9 {
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
do_execsql_test skipscan2-1.9eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {~/*INDEX people_idx1 */}
|
||||
|
||||
# Add 2 more people, bringing the total to 36. Then the number of
|
||||
# duplicates in the left-column of the index will be 18 and
|
||||
# skip-scan will be used after an (unfudged) ANALYZE.
|
||||
#
|
||||
do_execsql_test skipscan2-1.10 {
|
||||
INSERT INTO people VALUES('Ingrad','student',155);
|
||||
INSERT INTO people VALUES('Jacob','student',179);
|
||||
ANALYZE;
|
||||
SELECT stat FROM sqlite_stat1 WHERE idx='people_idx1';
|
||||
} {{36 18 2}}
|
||||
db cache flush
|
||||
do_execsql_test skipscan2-1.11 {
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
do_execsql_test skipscan2-1.11eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT name FROM people WHERE height>=180 ORDER BY +name;
|
||||
} {/*INDEX people_idx1 */}
|
||||
|
||||
|
||||
# Repeat using a WITHOUT ROWID table.
|
||||
#
|
||||
do_execsql_test skipscan2-2.1 {
|
||||
CREATE TABLE peoplew(
|
||||
name TEXT PRIMARY KEY,
|
||||
role TEXT NOT NULL,
|
||||
height INT NOT NULL, -- in cm
|
||||
CHECK( role IN ('student','teacher') )
|
||||
) WITHOUT ROWID;
|
||||
CREATE INDEX peoplew_idx1 ON peoplew(role, height);
|
||||
INSERT INTO peoplew(name,role,height)
|
||||
SELECT name, role, height FROM people;
|
||||
ALTER TABLE people RENAME TO old_people;
|
||||
SELECT name FROM peoplew WHERE height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
do_execsql_test skipscan2-2.2 {
|
||||
SELECT name FROM peoplew
|
||||
WHERE role IN (SELECT DISTINCT role FROM peoplew)
|
||||
AND height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
do_execsql_test skipscan2-2.2 {
|
||||
SELECT name FROM peoplew WHERE role='teacher' AND height>=180
|
||||
UNION ALL
|
||||
SELECT name FROM peoplew WHERE role='student' AND height>=180
|
||||
ORDER BY 1;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
|
||||
# Now do an ANALYZE. A skip-scan can be used after ANALYZE.
|
||||
#
|
||||
do_execsql_test skipscan2-2.4 {
|
||||
ANALYZE;
|
||||
}
|
||||
db cache flush
|
||||
do_execsql_test skipscan2-2.5 {
|
||||
SELECT name FROM peoplew WHERE height>=180 ORDER BY +name;
|
||||
} {David Jack Patrick Quiana Xavier}
|
||||
do_execsql_test skipscan2-2.5eqp {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT name FROM peoplew WHERE height>=180 ORDER BY +name;
|
||||
} {/*INDEX peoplew_idx1 */}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,966 @@
|
||||
/*
|
||||
** A program for performance testing.
|
||||
**
|
||||
** The available command-line options are described below:
|
||||
*/
|
||||
static const char zHelp[] =
|
||||
"Usage: %s [--options] DATABASE\n"
|
||||
"Options:\n"
|
||||
" --autovacuum Enable AUTOVACUUM mode\n"
|
||||
" --cachesize N Set the cache size to N\n"
|
||||
" --exclusive Enable locking_mode=EXCLUSIVE\n"
|
||||
" --heap SZ MIN Memory allocator uses SZ bytes & min allocation MIN\n"
|
||||
" --incrvacuum Enable incremenatal vacuum mode\n"
|
||||
" --journalmode M Set the journal_mode to MODE\n"
|
||||
" --key KEY Set the encryption key to KEY\n"
|
||||
" --lookaside N SZ Configure lookaside for N slots of SZ bytes each\n"
|
||||
" --nosync Set PRAGMA synchronous=OFF\n"
|
||||
" --notnull Add NOT NULL constraints to table columns\n"
|
||||
" --pagesize N Set the page size to N\n"
|
||||
" --pcache N SZ Configure N pages of pagecache each of size SZ bytes\n"
|
||||
" --primarykey Use PRIMARY KEY instead of UNIQUE where appropriate\n"
|
||||
" --reprepare Reprepare each statement upon every invocation\n"
|
||||
" --scratch N SZ Configure scratch memory for N slots of SZ bytes each\n"
|
||||
" --sqlonly No-op. Only show the SQL that would have been run.\n"
|
||||
" --size N Relative test size. Default=100\n"
|
||||
" --stats Show statistics at the end\n"
|
||||
" --testset T Run test-set T\n"
|
||||
" --trace Turn on SQL tracing\n"
|
||||
" --utf16be Set text encoding to UTF-16BE\n"
|
||||
" --utf16le Set text encoding to UTF-16LE\n"
|
||||
" --without-rowid Use WITHOUT ROWID where appropriate\n"
|
||||
;
|
||||
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* All global state is held in this structure */
|
||||
static struct Global {
|
||||
sqlite3 *db; /* The open database connection */
|
||||
sqlite3_stmt *pStmt; /* Current SQL statement */
|
||||
sqlite3_int64 iStart; /* Start-time for the current test */
|
||||
sqlite3_int64 iTotal; /* Total time */
|
||||
int bWithoutRowid; /* True for --without-rowid */
|
||||
int bReprepare; /* True to reprepare the SQL on each rerun */
|
||||
int bSqlOnly; /* True to print the SQL once only */
|
||||
int szTest; /* Scale factor for test iterations */
|
||||
const char *zWR; /* Might be WITHOUT ROWID */
|
||||
const char *zNN; /* Might be NOT NULL */
|
||||
const char *zPK; /* Might be UNIQUE or PRIMARY KEY */
|
||||
unsigned int x, y; /* Pseudo-random number generator state */
|
||||
int nResult; /* Size of the current result */
|
||||
char zResult[3000]; /* Text of the current result */
|
||||
} g;
|
||||
|
||||
|
||||
/* Print an error message and exit */
|
||||
static void fatal_error(const char *zMsg, ...){
|
||||
va_list ap;
|
||||
va_start(ap, zMsg);
|
||||
vfprintf(stderr, zMsg, ap);
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the value of a hexadecimal digit. Return -1 if the input
|
||||
** is not a hex digit.
|
||||
*/
|
||||
static int hexDigitValue(char c){
|
||||
if( c>='0' && c<='9' ) return c - '0';
|
||||
if( c>='a' && c<='f' ) return c - 'a' + 10;
|
||||
if( c>='A' && c<='F' ) return c - 'A' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Provide an alternative to sqlite3_stricmp() in older versions of
|
||||
** SQLite */
|
||||
#if SQLITE_VERSION_NUMBER<3007011
|
||||
# define sqlite3_stricmp strcmp
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Interpret zArg as an integer value, possibly with suffixes.
|
||||
*/
|
||||
static int integerValue(const char *zArg){
|
||||
sqlite3_int64 v = 0;
|
||||
static const struct { char *zSuffix; int iMult; } aMult[] = {
|
||||
{ "KiB", 1024 },
|
||||
{ "MiB", 1024*1024 },
|
||||
{ "GiB", 1024*1024*1024 },
|
||||
{ "KB", 1000 },
|
||||
{ "MB", 1000000 },
|
||||
{ "GB", 1000000000 },
|
||||
{ "K", 1000 },
|
||||
{ "M", 1000000 },
|
||||
{ "G", 1000000000 },
|
||||
};
|
||||
int i;
|
||||
int isNeg = 0;
|
||||
if( zArg[0]=='-' ){
|
||||
isNeg = 1;
|
||||
zArg++;
|
||||
}else if( zArg[0]=='+' ){
|
||||
zArg++;
|
||||
}
|
||||
if( zArg[0]=='0' && zArg[1]=='x' ){
|
||||
int x;
|
||||
zArg += 2;
|
||||
while( (x = hexDigitValue(zArg[0]))>=0 ){
|
||||
v = (v<<4) + x;
|
||||
zArg++;
|
||||
}
|
||||
}else{
|
||||
while( isdigit(zArg[0]) ){
|
||||
v = v*10 + zArg[0] - '0';
|
||||
zArg++;
|
||||
}
|
||||
}
|
||||
for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){
|
||||
if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
|
||||
v *= aMult[i].iMult;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( v>0x7fffffff ) fatal_error("parameter too large - max 2147483648");
|
||||
return (int)(isNeg? -v : v);
|
||||
}
|
||||
|
||||
/* Return the current wall-clock time, in milliseconds */
|
||||
sqlite3_int64 speedtest1_timestamp(void){
|
||||
static sqlite3_vfs *clockVfs = 0;
|
||||
sqlite3_int64 t;
|
||||
if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
|
||||
#if SQLITE_VERSION_NUMBER>=3007000
|
||||
if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){
|
||||
clockVfs->xCurrentTimeInt64(clockVfs, &t);
|
||||
}else
|
||||
#endif
|
||||
{
|
||||
double r;
|
||||
clockVfs->xCurrentTime(clockVfs, &r);
|
||||
t = (sqlite3_int64)(r*86400000.0);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Return a pseudo-random unsigned integer */
|
||||
unsigned int speedtest1_random(void){
|
||||
g.x = (g.x>>1) ^ ((1+~(g.x&1)) & 0xd0000001);
|
||||
g.y = g.y*1103515245 + 12345;
|
||||
return g.x ^ g.y;
|
||||
}
|
||||
|
||||
/* Map the value in within the range of 1...limit into another
|
||||
** number in a way that is chatic and invertable.
|
||||
*/
|
||||
unsigned swizzle(unsigned in, unsigned limit){
|
||||
unsigned out = 0;
|
||||
while( limit ){
|
||||
out = (out<<1) | (in&1);
|
||||
in >>= 1;
|
||||
limit >>= 1;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Round up a number so that it is a power of two minus one
|
||||
*/
|
||||
unsigned roundup_allones(unsigned limit){
|
||||
unsigned m = 1;
|
||||
while( m<limit ) m = (m<<1)+1;
|
||||
return m;
|
||||
}
|
||||
|
||||
/* The speedtest1_numbername procedure below converts its argment (an integer)
|
||||
** into a string which is the English-language name for that number.
|
||||
** The returned string should be freed with sqlite3_free().
|
||||
**
|
||||
** Example:
|
||||
**
|
||||
** speedtest1_numbername(123) -> "one hundred twenty three"
|
||||
*/
|
||||
int speedtest1_numbername(unsigned int n, char *zOut, int nOut){
|
||||
static const char *ones[] = { "zero", "one", "two", "three", "four", "five",
|
||||
"six", "seven", "eight", "nine", "ten", "eleven", "twelve",
|
||||
"thirteen", "fourteen", "fifteen", "sixteen", "seventeen",
|
||||
"eighteen", "nineteen" };
|
||||
static const char *tens[] = { "", "ten", "twenty", "thirty", "forty",
|
||||
"fifty", "sixty", "seventy", "eighty", "ninety" };
|
||||
int i = 0;
|
||||
|
||||
if( n>=1000000000 ){
|
||||
i += speedtest1_numbername(n/1000000000, zOut+i, nOut-i);
|
||||
sqlite3_snprintf(nOut-i, zOut+i, " billion");
|
||||
i += (int)strlen(zOut+i);
|
||||
n = n % 1000000000;
|
||||
}
|
||||
if( n>=1000000 ){
|
||||
if( i && i<nOut-1 ) zOut[i++] = ' ';
|
||||
i += speedtest1_numbername(n/1000000, zOut+i, nOut-i);
|
||||
sqlite3_snprintf(nOut-i, zOut+i, " million");
|
||||
i += (int)strlen(zOut+i);
|
||||
n = n % 1000000;
|
||||
}
|
||||
if( n>=1000 ){
|
||||
if( i && i<nOut-1 ) zOut[i++] = ' ';
|
||||
i += speedtest1_numbername(n/1000, zOut+i, nOut-i);
|
||||
sqlite3_snprintf(nOut-i, zOut+i, " thousand");
|
||||
i += (int)strlen(zOut+i);
|
||||
n = n % 1000;
|
||||
}
|
||||
if( n>=100 ){
|
||||
if( i && i<nOut-1 ) zOut[i++] = ' ';
|
||||
sqlite3_snprintf(nOut-i, zOut+i, "%s hundred", ones[n/100]);
|
||||
i += (int)strlen(zOut+i);
|
||||
n = n % 100;
|
||||
}
|
||||
if( n>=20 ){
|
||||
if( i && i<nOut-1 ) zOut[i++] = ' ';
|
||||
sqlite3_snprintf(nOut-i, zOut+i, "%s", tens[n/10]);
|
||||
i += (int)strlen(zOut+i);
|
||||
n = n % 10;
|
||||
}
|
||||
if( n>0 ){
|
||||
if( i && i<nOut-1 ) zOut[i++] = ' ';
|
||||
sqlite3_snprintf(nOut-i, zOut+i, "%s", ones[n]);
|
||||
i += (int)strlen(zOut+i);
|
||||
}
|
||||
if( i==0 ){
|
||||
sqlite3_snprintf(nOut-i, zOut+i, "zero");
|
||||
i += (int)strlen(zOut+i);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/* Start a new test case */
|
||||
#define NAMEWIDTH 60
|
||||
static const char zDots[] =
|
||||
".......................................................................";
|
||||
void speedtest1_begin_test(int iTestNum, const char *zTestName, ...){
|
||||
int n = (int)strlen(zTestName);
|
||||
char *zName;
|
||||
va_list ap;
|
||||
va_start(ap, zTestName);
|
||||
zName = sqlite3_vmprintf(zTestName, ap);
|
||||
va_end(ap);
|
||||
n = (int)strlen(zName);
|
||||
if( n>NAMEWIDTH ){
|
||||
zName[NAMEWIDTH] = 0;
|
||||
n = NAMEWIDTH;
|
||||
}
|
||||
if( g.bSqlOnly ){
|
||||
printf("/* %4d - %s%.*s */\n", iTestNum, zName, NAMEWIDTH-n, zDots);
|
||||
}else{
|
||||
printf("%4d - %s%.*s ", iTestNum, zName, NAMEWIDTH-n, zDots);
|
||||
fflush(stdout);
|
||||
}
|
||||
sqlite3_free(zName);
|
||||
g.nResult = 0;
|
||||
g.iStart = speedtest1_timestamp();
|
||||
g.x = 0xad131d0b;
|
||||
g.y = 0x44f9eac8;
|
||||
}
|
||||
|
||||
/* Complete a test case */
|
||||
void speedtest1_end_test(void){
|
||||
sqlite3_int64 iElapseTime = speedtest1_timestamp() - g.iStart;
|
||||
if( !g.bSqlOnly ){
|
||||
g.iTotal += iElapseTime;
|
||||
printf("%4d.%03ds\n", (int)(iElapseTime/1000), (int)(iElapseTime%1000));
|
||||
}
|
||||
if( g.pStmt ){
|
||||
sqlite3_finalize(g.pStmt);
|
||||
g.pStmt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Report end of testing */
|
||||
void speedtest1_final(void){
|
||||
if( !g.bSqlOnly ){
|
||||
printf(" TOTAL%.*s %4d.%03ds\n", NAMEWIDTH-5, zDots,
|
||||
(int)(g.iTotal/1000), (int)(g.iTotal%1000));
|
||||
}
|
||||
}
|
||||
|
||||
/* Run SQL */
|
||||
void speedtest1_exec(const char *zFormat, ...){
|
||||
va_list ap;
|
||||
char *zSql;
|
||||
va_start(ap, zFormat);
|
||||
zSql = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
if( g.bSqlOnly ){
|
||||
int n = (int)strlen(zSql);
|
||||
while( n>0 && (zSql[n-1]==';' || isspace(zSql[n-1])) ){ n--; }
|
||||
printf("%.*s;\n", n, zSql);
|
||||
}else{
|
||||
char *zErrMsg = 0;
|
||||
int rc = sqlite3_exec(g.db, zSql, 0, 0, &zErrMsg);
|
||||
if( zErrMsg ) fatal_error("SQL error: %s\n%s\n", zErrMsg, zSql);
|
||||
if( rc!=SQLITE_OK ) fatal_error("exec error: %s\n", sqlite3_errmsg(g.db));
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
|
||||
/* Prepare an SQL statement */
|
||||
void speedtest1_prepare(const char *zFormat, ...){
|
||||
va_list ap;
|
||||
char *zSql;
|
||||
va_start(ap, zFormat);
|
||||
zSql = sqlite3_vmprintf(zFormat, ap);
|
||||
va_end(ap);
|
||||
if( g.bSqlOnly ){
|
||||
int n = (int)strlen(zSql);
|
||||
while( n>0 && (zSql[n-1]==';' || isspace(zSql[n-1])) ){ n--; }
|
||||
printf("%.*s;\n", n, zSql);
|
||||
}else{
|
||||
int rc;
|
||||
if( g.pStmt ) sqlite3_finalize(g.pStmt);
|
||||
rc = sqlite3_prepare_v2(g.db, zSql, -1, &g.pStmt, 0);
|
||||
if( rc ){
|
||||
fatal_error("SQL error: %s\n", sqlite3_errmsg(g.db));
|
||||
}
|
||||
}
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
|
||||
/* Run an SQL statement previously prepared */
|
||||
void speedtest1_run(void){
|
||||
int i, n, len;
|
||||
if( g.bSqlOnly ) return;
|
||||
assert( g.pStmt );
|
||||
g.nResult = 0;
|
||||
while( sqlite3_step(g.pStmt)==SQLITE_ROW ){
|
||||
n = sqlite3_column_count(g.pStmt);
|
||||
for(i=0; i<n; i++){
|
||||
const char *z = (const char*)sqlite3_column_text(g.pStmt, i);
|
||||
if( z==0 ) z = "nil";
|
||||
len = (int)strlen(z);
|
||||
if( g.nResult+len<sizeof(g.zResult)-2 ){
|
||||
if( g.nResult>0 ) g.zResult[g.nResult++] = ' ';
|
||||
memcpy(g.zResult + g.nResult, z, len+1);
|
||||
g.nResult += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( g.bReprepare ){
|
||||
sqlite3_stmt *pNew;
|
||||
sqlite3_prepare_v2(g.db, sqlite3_sql(g.pStmt), -1, &pNew, 0);
|
||||
sqlite3_finalize(g.pStmt);
|
||||
g.pStmt = pNew;
|
||||
}else{
|
||||
sqlite3_reset(g.pStmt);
|
||||
}
|
||||
}
|
||||
|
||||
/* The sqlite3_trace() callback function */
|
||||
static void traceCallback(void *NotUsed, const char *zSql){
|
||||
int n = (int)strlen(zSql);
|
||||
while( n>0 && (zSql[n-1]==';' || isspace(zSql[n-1])) ) n--;
|
||||
fprintf(stderr,"%.*s;\n", n, zSql);
|
||||
}
|
||||
|
||||
/* Substitute random() function that gives the same random
|
||||
** sequence on each run, for repeatability. */
|
||||
static void randomFunc(
|
||||
sqlite3_context *context,
|
||||
int NotUsed,
|
||||
sqlite3_value **NotUsed2
|
||||
){
|
||||
sqlite3_result_int64(context, (sqlite3_int64)speedtest1_random());
|
||||
}
|
||||
|
||||
/*
|
||||
** The main and default testset
|
||||
*/
|
||||
void testset_main(void){
|
||||
int i; /* Loop counter */
|
||||
int n; /* iteration count */
|
||||
int sz; /* Size of the tables */
|
||||
int maxb; /* Maximum swizzled value */
|
||||
unsigned x1, x2; /* Parameters */
|
||||
int len; /* Length of the zNum[] string */
|
||||
char zNum[2000]; /* A number name */
|
||||
|
||||
sz = n = g.szTest*500;
|
||||
maxb = roundup_allones(sz);
|
||||
speedtest1_begin_test(100, "%d INSERTs into table with no index", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_exec("CREATE TABLE t1(a INTEGER %s, b INTEGER %s, c TEXT %s);",
|
||||
g.zNN, g.zNN, g.zNN);
|
||||
speedtest1_prepare("INSERT INTO t1 VALUES(?1,?2,?3); -- %d times", n);
|
||||
for(i=1; i<=n; i++){
|
||||
x1 = swizzle(i,maxb);
|
||||
speedtest1_numbername(x1, zNum, sizeof(zNum));
|
||||
sqlite3_bind_int64(g.pStmt, 1, (sqlite3_int64)x1);
|
||||
sqlite3_bind_int(g.pStmt, 2, i);
|
||||
sqlite3_bind_text(g.pStmt, 3, zNum, -1, SQLITE_STATIC);
|
||||
speedtest1_run();
|
||||
}
|
||||
speedtest1_exec("COMMIT");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
n = sz;
|
||||
speedtest1_begin_test(110, "%d ordered INSERTS with one index/PK", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_exec("CREATE TABLE t2(a INTEGER %s %s, b INTEGER %s, c TEXT %s) %s",
|
||||
g.zNN, g.zPK, g.zNN, g.zNN, g.zWR);
|
||||
speedtest1_prepare("INSERT INTO t2 VALUES(?1,?2,?3); -- %d times", n);
|
||||
for(i=1; i<=n; i++){
|
||||
x1 = swizzle(i,maxb);
|
||||
speedtest1_numbername(x1, zNum, sizeof(zNum));
|
||||
sqlite3_bind_int(g.pStmt, 1, i);
|
||||
sqlite3_bind_int64(g.pStmt, 2, (sqlite3_int64)x1);
|
||||
sqlite3_bind_text(g.pStmt, 3, zNum, -1, SQLITE_STATIC);
|
||||
speedtest1_run();
|
||||
}
|
||||
speedtest1_exec("COMMIT");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
n = sz;
|
||||
speedtest1_begin_test(120, "%d unordered INSERTS with one index/PK", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_exec("CREATE TABLE t3(a INTEGER %s %s, b INTEGER %s, c TEXT %s) %s",
|
||||
g.zNN, g.zPK, g.zNN, g.zNN, g.zWR);
|
||||
speedtest1_prepare("INSERT INTO t3 VALUES(?1,?2,?3); -- %d times", n);
|
||||
for(i=1; i<=n; i++){
|
||||
x1 = swizzle(i,maxb);
|
||||
speedtest1_numbername(x1, zNum, sizeof(zNum));
|
||||
sqlite3_bind_int(g.pStmt, 2, i);
|
||||
sqlite3_bind_int64(g.pStmt, 1, (sqlite3_int64)x1);
|
||||
sqlite3_bind_text(g.pStmt, 3, zNum, -1, SQLITE_STATIC);
|
||||
speedtest1_run();
|
||||
}
|
||||
speedtest1_exec("COMMIT");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
n = g.szTest/2;
|
||||
speedtest1_begin_test(130, "%d SELECTS, numeric BETWEEN, unindexed", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"SELECT count(*), avg(b), sum(length(c)) FROM t1\n"
|
||||
" WHERE b BETWEEN ?1 AND ?2; -- %d times", n
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
x1 = speedtest1_random()%maxb;
|
||||
x2 = speedtest1_random()%10 + sz/5000 + x1;
|
||||
sqlite3_bind_int(g.pStmt, 1, x1);
|
||||
sqlite3_bind_int(g.pStmt, 2, x2);
|
||||
speedtest1_run();
|
||||
}
|
||||
speedtest1_exec("COMMIT");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
n = g.szTest/5;
|
||||
speedtest1_begin_test(140, "%d SELECTS, LIKE, unindexed", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"SELECT count(*), avg(b), sum(length(c)) FROM t1\n"
|
||||
" WHERE c LIKE ?1; -- %d times", n
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
x1 = speedtest1_random()%maxb;
|
||||
zNum[0] = '%';
|
||||
len = speedtest1_numbername(i, zNum+1, sizeof(zNum)-2);
|
||||
zNum[len] = '%';
|
||||
zNum[len+1] = 0;
|
||||
sqlite3_bind_text(g.pStmt, 1, zNum, len, SQLITE_STATIC);
|
||||
speedtest1_run();
|
||||
}
|
||||
speedtest1_exec("COMMIT");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
speedtest1_begin_test(150, "CREATE INDEX five times");
|
||||
speedtest1_exec(
|
||||
"BEGIN;\n"
|
||||
"CREATE UNIQUE INDEX t1b ON t1(b);\n"
|
||||
"CREATE INDEX t1c ON t1(c);\n"
|
||||
"CREATE UNIQUE INDEX t2b ON t2(b);\n"
|
||||
"CREATE INDEX t2c ON t2(c DESC);\n"
|
||||
"CREATE INDEX t3bc ON t3(b,c);\n"
|
||||
"COMMIT;\n"
|
||||
);
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
n = sz/5;
|
||||
speedtest1_begin_test(160, "%d SELECTS, numeric BETWEEN, indexed", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"SELECT count(*), avg(b), sum(length(c)) FROM t1\n"
|
||||
" WHERE b BETWEEN ?1 AND ?2; -- %d times", n
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
x1 = speedtest1_random()%maxb;
|
||||
x2 = speedtest1_random()%10 + sz/5000 + x1;
|
||||
sqlite3_bind_int(g.pStmt, 1, x1);
|
||||
sqlite3_bind_int(g.pStmt, 2, x2);
|
||||
speedtest1_run();
|
||||
}
|
||||
speedtest1_exec("COMMIT");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
n = sz/5;
|
||||
speedtest1_begin_test(161, "%d SELECTS, numeric BETWEEN, PK", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"SELECT count(*), avg(b), sum(length(c)) FROM t2\n"
|
||||
" WHERE a BETWEEN ?1 AND ?2; -- %d times", n
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
x1 = speedtest1_random()%maxb;
|
||||
x2 = speedtest1_random()%10 + sz/5000 + x1;
|
||||
sqlite3_bind_int(g.pStmt, 1, x1);
|
||||
sqlite3_bind_int(g.pStmt, 2, x2);
|
||||
speedtest1_run();
|
||||
}
|
||||
speedtest1_exec("COMMIT");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
n = sz/5;
|
||||
speedtest1_begin_test(170, "%d SELECTS, text BETWEEN, indexed", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"SELECT count(*), avg(b), sum(length(c)) FROM t1\n"
|
||||
" WHERE c BETWEEN ?1 AND (?1||'~'); -- %d times", n
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
x1 = swizzle(i, maxb);
|
||||
len = speedtest1_numbername(x1, zNum, sizeof(zNum)-1);
|
||||
sqlite3_bind_text(g.pStmt, 1, zNum, len, SQLITE_STATIC);
|
||||
speedtest1_run();
|
||||
}
|
||||
speedtest1_exec("COMMIT");
|
||||
speedtest1_end_test();
|
||||
|
||||
n = sz;
|
||||
speedtest1_begin_test(180, "%d INSERTS with three indexes", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_exec(
|
||||
"CREATE TABLE t4(\n"
|
||||
" a INTEGER %s %s,\n"
|
||||
" b INTEGER %s,\n"
|
||||
" c TEXT %s\n"
|
||||
") %s",
|
||||
g.zNN, g.zPK, g.zNN, g.zNN, g.zWR);
|
||||
speedtest1_exec("CREATE INDEX t4b ON t4(b)");
|
||||
speedtest1_exec("CREATE INDEX t4c ON t4(c)");
|
||||
speedtest1_exec("INSERT INTO t4 SELECT * FROM t1");
|
||||
speedtest1_exec("COMMIT");
|
||||
speedtest1_end_test();
|
||||
|
||||
n = sz;
|
||||
speedtest1_begin_test(190, "DELETE and REFILL one table", n);
|
||||
speedtest1_exec(
|
||||
"DELETE FROM t2;"
|
||||
"INSERT INTO t2 SELECT * FROM t1;"
|
||||
);
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
speedtest1_begin_test(200, "VACUUM");
|
||||
speedtest1_exec("VACUUM");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
speedtest1_begin_test(210, "ALTER TABLE ADD COLUMN, and query");
|
||||
speedtest1_exec("ALTER TABLE t2 ADD COLUMN d DEFAULT 123");
|
||||
speedtest1_exec("SELECT sum(d) FROM t2");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
n = sz/5;
|
||||
speedtest1_begin_test(230, "%d UPDATES, numeric BETWEEN, indexed", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"UPDATE t2 SET d=b*2 WHERE b BETWEEN ?1 AND ?2; -- %d times", n
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
x1 = speedtest1_random()%maxb;
|
||||
x2 = speedtest1_random()%10 + sz/5000 + x1;
|
||||
sqlite3_bind_int(g.pStmt, 1, x1);
|
||||
sqlite3_bind_int(g.pStmt, 2, x2);
|
||||
speedtest1_run();
|
||||
}
|
||||
speedtest1_exec("COMMIT");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
n = sz;
|
||||
speedtest1_begin_test(240, "%d UPDATES of individual rows", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"UPDATE t2 SET d=b*3 WHERE a=?1; -- %d times", n
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
x1 = speedtest1_random()%sz + 1;
|
||||
sqlite3_bind_int(g.pStmt, 1, x1);
|
||||
speedtest1_run();
|
||||
}
|
||||
speedtest1_exec("COMMIT");
|
||||
speedtest1_end_test();
|
||||
|
||||
speedtest1_begin_test(250, "One big UPDATE of the whole %d-row table", sz);
|
||||
speedtest1_exec("UPDATE t2 SET d=b*4");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
speedtest1_begin_test(260, "Query added column after filling");
|
||||
speedtest1_exec("SELECT sum(d) FROM t2");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
|
||||
n = sz/5;
|
||||
speedtest1_begin_test(270, "%d DELETEs, numeric BETWEEN, indexed", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"DELETE FROM t2 WHERE b BETWEEN ?1 AND ?2; -- %d times", n
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
x1 = speedtest1_random()%maxb + 1;
|
||||
x2 = speedtest1_random()%10 + sz/5000 + x1;
|
||||
sqlite3_bind_int(g.pStmt, 1, x1);
|
||||
sqlite3_bind_int(g.pStmt, 2, x2);
|
||||
speedtest1_run();
|
||||
}
|
||||
speedtest1_exec("COMMIT");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
n = sz;
|
||||
speedtest1_begin_test(280, "%d DELETEs of individual rows", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"DELETE FROM t3 WHERE a=?1; -- %d times", n
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
x1 = speedtest1_random()%sz + 1;
|
||||
sqlite3_bind_int(g.pStmt, 1, x1);
|
||||
speedtest1_run();
|
||||
}
|
||||
speedtest1_exec("COMMIT");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
speedtest1_begin_test(290, "Refill two %d-row tables using REPLACE", sz);
|
||||
speedtest1_exec("REPLACE INTO t2(a,b,c) SELECT a,b,c FROM t1");
|
||||
speedtest1_exec("REPLACE INTO t3(a,b,c) SELECT a,b,c FROM t1");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
n = sz/5;
|
||||
speedtest1_begin_test(290, "%d four-ways joins", n);
|
||||
speedtest1_exec("BEGIN");
|
||||
speedtest1_prepare(
|
||||
"SELECT t1.c FROM t1, t2, t3, t4\n"
|
||||
" WHERE t4.a BETWEEN ?1 AND ?2\n"
|
||||
" AND t3.a=t4.b\n"
|
||||
" AND t2.a=t3.b\n"
|
||||
" AND t1.c=t2.c"
|
||||
);
|
||||
for(i=1; i<=n; i++){
|
||||
x1 = speedtest1_random()%sz + 1;
|
||||
x2 = speedtest1_random()%10 + x1 + 4;
|
||||
sqlite3_bind_int(g.pStmt, 1, x1);
|
||||
sqlite3_bind_int(g.pStmt, 2, x2);
|
||||
speedtest1_run();
|
||||
}
|
||||
speedtest1_exec("COMMIT");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
|
||||
speedtest1_begin_test(980, "PRAGMA integrity_check");
|
||||
speedtest1_exec("PRAGMA integrity_check");
|
||||
speedtest1_end_test();
|
||||
|
||||
|
||||
speedtest1_begin_test(990, "ANALYZE");
|
||||
speedtest1_exec("ANALYZE");
|
||||
speedtest1_end_test();
|
||||
}
|
||||
|
||||
/*
|
||||
** A testset used for debugging speedtest1 itself.
|
||||
*/
|
||||
void testset_debug1(void){
|
||||
unsigned i, n;
|
||||
unsigned x1, x2;
|
||||
char zNum[2000]; /* A number name */
|
||||
|
||||
n = g.szTest;
|
||||
for(i=1; i<=n; i++){
|
||||
x1 = swizzle(i, n);
|
||||
x2 = swizzle(x1, n);
|
||||
speedtest1_numbername(x1, zNum, sizeof(zNum));
|
||||
printf("%5d %5d %5d %s\n", i, x1, x2, zNum);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv){
|
||||
int doAutovac = 0; /* True for --autovacuum */
|
||||
int cacheSize = 0; /* Desired cache size. 0 means default */
|
||||
int doExclusive = 0; /* True for --exclusive */
|
||||
int nHeap = 0, mnHeap = 0; /* Heap size from --heap */
|
||||
int doIncrvac = 0; /* True for --incrvacuum */
|
||||
const char *zJMode = 0; /* Journal mode */
|
||||
const char *zKey = 0; /* Encryption key */
|
||||
int nLook = 0, szLook = 0; /* --lookaside configuration */
|
||||
int noSync = 0; /* True for --nosync */
|
||||
int pageSize = 0; /* Desired page size. 0 means default */
|
||||
int nPCache = 0, szPCache = 0;/* --pcache configuration */
|
||||
int nScratch = 0, szScratch=0;/* --scratch configuration */
|
||||
int showStats = 0; /* True for --stats */
|
||||
const char *zTSet = "main"; /* Which --testset torun */
|
||||
int doTrace = 0; /* True for --trace */
|
||||
const char *zEncoding = 0; /* --utf16be or --utf16le */
|
||||
const char *zDbName = 0; /* Name of the test database */
|
||||
|
||||
void *pHeap = 0; /* Allocated heap space */
|
||||
void *pLook = 0; /* Allocated lookaside space */
|
||||
void *pPCache = 0; /* Allocated storage for pcache */
|
||||
void *pScratch = 0; /* Allocated storage for scratch */
|
||||
int iCur, iHi; /* Stats values, current and "highwater" */
|
||||
int i; /* Loop counter */
|
||||
int rc; /* API return code */
|
||||
|
||||
/* Process command-line arguments */
|
||||
g.zWR = "";
|
||||
g.zNN = "";
|
||||
g.zPK = "UNIQUE";
|
||||
g.szTest = 100;
|
||||
for(i=1; i<argc; i++){
|
||||
const char *z = argv[i];
|
||||
if( z[0]=='-' ){
|
||||
do{ z++; }while( z[0]=='-' );
|
||||
if( strcmp(z,"autovacuum")==0 ){
|
||||
doAutovac = 1;
|
||||
}else if( strcmp(z,"cachesize")==0 ){
|
||||
if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]);
|
||||
i++;
|
||||
cacheSize = integerValue(argv[i]);
|
||||
}else if( strcmp(z,"exclusive")==0 ){
|
||||
doExclusive = 1;
|
||||
}else if( strcmp(z,"heap")==0 ){
|
||||
if( i>=argc-2 ) fatal_error("missing arguments on %s\n", argv[i]);
|
||||
nHeap = integerValue(argv[i+1]);
|
||||
mnHeap = integerValue(argv[i+2]);
|
||||
i += 2;
|
||||
}else if( strcmp(z,"incrvacuum")==0 ){
|
||||
doIncrvac = 1;
|
||||
}else if( strcmp(z,"journal")==0 ){
|
||||
if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]);
|
||||
zJMode = argv[++i];
|
||||
}else if( strcmp(z,"key")==0 ){
|
||||
if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]);
|
||||
zKey = argv[++i];
|
||||
}else if( strcmp(z,"lookaside")==0 ){
|
||||
if( i>=argc-2 ) fatal_error("missing arguments on %s\n", argv[i]);
|
||||
nLook = integerValue(argv[i+1]);
|
||||
szLook = integerValue(argv[i+2]);
|
||||
i += 2;
|
||||
}else if( strcmp(z,"nosync")==0 ){
|
||||
noSync = 1;
|
||||
}else if( strcmp(z,"notnull")==0 ){
|
||||
g.zNN = "NOT NULL";
|
||||
}else if( strcmp(z,"pagesize")==0 ){
|
||||
if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]);
|
||||
pageSize = integerValue(argv[++i]);
|
||||
}else if( strcmp(z,"pcache")==0 ){
|
||||
if( i>=argc-2 ) fatal_error("missing arguments on %s\n", argv[i]);
|
||||
nPCache = integerValue(argv[i+1]);
|
||||
szPCache = integerValue(argv[i+2]);
|
||||
i += 2;
|
||||
}else if( strcmp(z,"primarykey")==0 ){
|
||||
g.zPK = "PRIMARY KEY";
|
||||
}else if( strcmp(z,"reprepare")==0 ){
|
||||
g.bReprepare = 1;
|
||||
}else if( strcmp(z,"scratch")==0 ){
|
||||
if( i>=argc-2 ) fatal_error("missing arguments on %s\n", argv[i]);
|
||||
nScratch = integerValue(argv[i+1]);
|
||||
szScratch = integerValue(argv[i+2]);
|
||||
i += 2;
|
||||
}else if( strcmp(z,"sqlonly")==0 ){
|
||||
g.bSqlOnly = 1;
|
||||
}else if( strcmp(z,"size")==0 ){
|
||||
if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]);
|
||||
g.szTest = integerValue(argv[++i]);
|
||||
}else if( strcmp(z,"stats")==0 ){
|
||||
showStats = 1;
|
||||
}else if( strcmp(z,"testset")==0 ){
|
||||
if( i>=argc-1 ) fatal_error("missing argument on %s\n", argv[i]);
|
||||
zTSet = argv[++i];
|
||||
}else if( strcmp(z,"trace")==0 ){
|
||||
doTrace = 1;
|
||||
}else if( strcmp(z,"utf16le")==0 ){
|
||||
zEncoding = "utf16le";
|
||||
}else if( strcmp(z,"utf16be")==0 ){
|
||||
zEncoding = "utf16be";
|
||||
}else if( strcmp(z,"without-rowid")==0 ){
|
||||
g.zWR = "WITHOUT ROWID";
|
||||
g.zPK = "PRIMARY KEY";
|
||||
}else if( strcmp(z, "help")==0 || strcmp(z,"?")==0 ){
|
||||
printf(zHelp, argv[0]);
|
||||
exit(0);
|
||||
}else{
|
||||
fatal_error("unknown option: %s\nUse \"%s -?\" for help\n",
|
||||
argv[i], argv[0]);
|
||||
}
|
||||
}else if( zDbName==0 ){
|
||||
zDbName = argv[i];
|
||||
}else{
|
||||
fatal_error("surplus argument: %s\nUse \"%s -?\" for help\n",
|
||||
argv[i], argv[0]);
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
if( zDbName==0 ){
|
||||
fatal_error(zHelp, argv[0]);
|
||||
}
|
||||
#endif
|
||||
if( nHeap>0 ){
|
||||
pHeap = malloc( nHeap );
|
||||
if( pHeap==0 ) fatal_error("cannot allocate %d-byte heap\n", nHeap);
|
||||
rc = sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nHeap, mnHeap);
|
||||
if( rc ) fatal_error("heap configuration failed: %d\n", rc);
|
||||
}
|
||||
if( nPCache>0 && szPCache>0 ){
|
||||
pPCache = malloc( nPCache*(sqlite3_int64)szPCache );
|
||||
if( pPCache==0 ) fatal_error("cannot allocate %lld-byte pcache\n",
|
||||
nPCache*(sqlite3_int64)szPCache);
|
||||
rc = sqlite3_config(SQLITE_CONFIG_PAGECACHE, pPCache, szPCache, nPCache);
|
||||
if( rc ) fatal_error("pcache configuration failed: %d\n", rc);
|
||||
}
|
||||
if( nScratch>0 && szScratch>0 ){
|
||||
pScratch = malloc( nScratch*(sqlite3_int64)szScratch );
|
||||
if( pScratch==0 ) fatal_error("cannot allocate %lld-byte scratch\n",
|
||||
nScratch*(sqlite3_int64)szScratch);
|
||||
rc = sqlite3_config(SQLITE_CONFIG_SCRATCH, pScratch, szScratch, nScratch);
|
||||
if( rc ) fatal_error("scratch configuration failed: %d\n", rc);
|
||||
}
|
||||
if( nLook>0 ){
|
||||
sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0);
|
||||
}
|
||||
|
||||
/* Open the database and the input file */
|
||||
if( sqlite3_open(zDbName, &g.db) ){
|
||||
fatal_error("Cannot open database file: %s\n", zDbName);
|
||||
}
|
||||
if( nLook>0 && szLook>0 ){
|
||||
pLook = malloc( nLook*szLook );
|
||||
rc = sqlite3_db_config(g.db, SQLITE_DBCONFIG_LOOKASIDE, pLook, szLook,nLook);
|
||||
if( rc ) fatal_error("lookaside configuration failed: %d\n", rc);
|
||||
}
|
||||
|
||||
/* Set database connection options */
|
||||
sqlite3_create_function(g.db, "random", 0, SQLITE_UTF8, 0, randomFunc, 0, 0);
|
||||
if( doTrace ) sqlite3_trace(g.db, traceCallback, 0);
|
||||
if( zKey ){
|
||||
speedtest1_exec("PRAGMA key('%s')", zKey);
|
||||
}
|
||||
if( zEncoding ){
|
||||
speedtest1_exec("PRAGMA encoding=%s", zEncoding);
|
||||
}
|
||||
if( doAutovac ){
|
||||
speedtest1_exec("PRAGMA auto_vacuum=FULL");
|
||||
}else if( doIncrvac ){
|
||||
speedtest1_exec("PRAGMA auto_vacuum=INCREMENTAL");
|
||||
}
|
||||
if( pageSize ){
|
||||
speedtest1_exec("PRAGMA page_size=%d", pageSize);
|
||||
}
|
||||
if( cacheSize ){
|
||||
speedtest1_exec("PRAGMA cache_size=%d", cacheSize);
|
||||
}
|
||||
if( noSync ) speedtest1_exec("PRAGMA synchronous=OFF");
|
||||
if( doExclusive ){
|
||||
speedtest1_exec("PRAGMA locking_mode=EXCLUSIVE");
|
||||
}
|
||||
if( zJMode ){
|
||||
speedtest1_exec("PRAGMA journal_mode=%s", zJMode);
|
||||
}
|
||||
|
||||
if( strcmp(zTSet,"main")==0 ){
|
||||
testset_main();
|
||||
}else if( strcmp(zTSet,"debug1")==0 ){
|
||||
testset_debug1();
|
||||
}else{
|
||||
fatal_error("unknown testset: \"%s\"\n", zTSet);
|
||||
}
|
||||
speedtest1_final();
|
||||
|
||||
/* Database connection statistics printed after both prepared statements
|
||||
** have been finalized */
|
||||
#if SQLITE_VERSION_NUMBER>=3007009
|
||||
if( showStats ){
|
||||
sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHi, 0);
|
||||
printf("-- Lookaside Slots Used: %d (max %d)\n", iCur,iHi);
|
||||
sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHi, 0);
|
||||
printf("-- Successful lookasides: %d\n", iHi);
|
||||
sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur,&iHi,0);
|
||||
printf("-- Lookaside size faults: %d\n", iHi);
|
||||
sqlite3_db_status(g.db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur,&iHi,0);
|
||||
printf("-- Lookaside OOM faults: %d\n", iHi);
|
||||
sqlite3_db_status(g.db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHi, 0);
|
||||
printf("-- Pager Heap Usage: %d bytes\n", iCur);
|
||||
sqlite3_db_status(g.db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHi, 1);
|
||||
printf("-- Page cache hits: %d\n", iCur);
|
||||
sqlite3_db_status(g.db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHi, 1);
|
||||
printf("-- Page cache misses: %d\n", iCur);
|
||||
#if SQLITE_VERSION_NUMBER>=3007012
|
||||
sqlite3_db_status(g.db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHi, 1);
|
||||
printf("-- Page cache writes: %d\n", iCur);
|
||||
#endif
|
||||
sqlite3_db_status(g.db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHi, 0);
|
||||
printf("-- Schema Heap Usage: %d bytes\n", iCur);
|
||||
sqlite3_db_status(g.db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHi, 0);
|
||||
printf("-- Statement Heap Usage: %d bytes\n", iCur);
|
||||
}
|
||||
#endif
|
||||
|
||||
sqlite3_close(g.db);
|
||||
|
||||
/* Global memory usage statistics printed after the database connection
|
||||
** has closed. Memory usage should be zero at this point. */
|
||||
if( showStats ){
|
||||
sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHi, 0);
|
||||
printf("-- Memory Used (bytes): %d (max %d)\n", iCur,iHi);
|
||||
#if SQLITE_VERSION_NUMBER>=3007000
|
||||
sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHi, 0);
|
||||
printf("-- Outstanding Allocations: %d (max %d)\n", iCur,iHi);
|
||||
#endif
|
||||
sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHi, 0);
|
||||
printf("-- Pcache Overflow Bytes: %d (max %d)\n", iCur,iHi);
|
||||
sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHi, 0);
|
||||
printf("-- Scratch Overflow Bytes: %d (max %d)\n", iCur,iHi);
|
||||
sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHi, 0);
|
||||
printf("-- Largest Allocation: %d bytes\n",iHi);
|
||||
sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHi, 0);
|
||||
printf("-- Largest Pcache Allocation: %d bytes\n",iHi);
|
||||
sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHi, 0);
|
||||
printf("-- Largest Scratch Allocation: %d bytes\n", iHi);
|
||||
}
|
||||
|
||||
/* Release memory */
|
||||
free( pLook );
|
||||
free( pPCache );
|
||||
free( pScratch );
|
||||
free( pHeap );
|
||||
return 0;
|
||||
}
|
||||
@@ -265,10 +265,10 @@ do_test 6.1 {
|
||||
} {}
|
||||
|
||||
do_execsql_test 6.2 {
|
||||
SELECT * FROM aux.sqlite_master;
|
||||
SELECT type,name,tbl_name,sql FROM aux.sqlite_master;
|
||||
INSERT INTO aux.t1 VALUES(1,2,3);
|
||||
} {
|
||||
table t1 t1 2 {CREATE TABLE t1(a, b, c)}
|
||||
table t1 t1 {CREATE TABLE t1(a, b, c)}
|
||||
}
|
||||
|
||||
do_catchsql_test 6.3 {
|
||||
|
||||
@@ -1886,5 +1886,11 @@ set AUTOVACUUM $sqlite_options(default_autovacuum)
|
||||
# Make sure the FTS enhanced query syntax is disabled.
|
||||
set sqlite_fts3_enable_parentheses 0
|
||||
|
||||
# During testing, assume that all database files are well-formed. The
|
||||
# few test cases that deliberately corrupt database files should rescind
|
||||
# this setting by invoking "database_can_be_corrupt"
|
||||
#
|
||||
database_never_corrupt
|
||||
|
||||
source $testdir/thread_common.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
|
||||
+2
-2
@@ -161,7 +161,7 @@ for {set i 2} {$i<=30} {incr i} {
|
||||
z = CASE WHEN id<$max_rowid
|
||||
THEN zeroblob((random()&65535)%5000 + 1000) END;
|
||||
}
|
||||
} {1 {t1.z may not be NULL}}
|
||||
} {1 {NOT NULL constraint failed: t1.z}}
|
||||
do_test trans2-$i.11 {
|
||||
db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
|
||||
} $newres
|
||||
@@ -185,7 +185,7 @@ for {set i 2} {$i<=30} {incr i} {
|
||||
z = CASE WHEN id<$max1
|
||||
THEN zeroblob((random()&65535)%5000 + 1000) END;
|
||||
}
|
||||
} {1 {t1.z may not be NULL}}
|
||||
} {1 {NOT NULL constraint failed: t1.z}}
|
||||
do_test trans2-$i.31 {
|
||||
db eval {SELECT md5sum(u1), md5sum(u2) FROM t1 ORDER BY id}
|
||||
} $origres
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
# 2013 November 22
|
||||
#
|
||||
# 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. The
|
||||
# focus of this script is recovery from transient manditory locks
|
||||
# that sometimes appear on database files due to anti-virus software.
|
||||
#
|
||||
|
||||
if {$tcl_platform(platform)!="windows"} return
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
ifcapable !win32malloc {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
set testprefix win32heap
|
||||
|
||||
do_test 1.1 {
|
||||
catch {db close}
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_heap_size 1048576
|
||||
sqlite3_initialize
|
||||
} {SQLITE_OK}
|
||||
|
||||
do_test 1.2 {
|
||||
sqlite3 db test.db
|
||||
catchsql {
|
||||
CREATE TABLE t1(x);
|
||||
}
|
||||
} {0 {}}
|
||||
|
||||
do_test 1.3 {
|
||||
catchsql {
|
||||
INSERT INTO t1 (x) VALUES(RANDOMBLOB(1048576));
|
||||
}
|
||||
} {1 {out of memory}}
|
||||
|
||||
do_test 1.4 {
|
||||
catchsql {
|
||||
SELECT COUNT(*) FROM t1;
|
||||
}
|
||||
} {0 0}
|
||||
|
||||
do_test 1.5 {
|
||||
catch {db close}
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_heap_size 0
|
||||
sqlite3_initialize
|
||||
} {SQLITE_OK}
|
||||
|
||||
do_test 1.6 {
|
||||
sqlite3 db test.db
|
||||
catchsql {
|
||||
INSERT INTO t1 (x) VALUES(RANDOMBLOB(1048576));
|
||||
}
|
||||
} {0 {}}
|
||||
|
||||
do_test 1.7 {
|
||||
catchsql {
|
||||
SELECT COUNT(*) FROM t1;
|
||||
}
|
||||
} {0 1}
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,201 @@
|
||||
# 2013-11-26
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Requirements testing for WITHOUT ROWID tables.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
|
||||
# EVIDENCE-OF: R-36924-43758 By default, every row in SQLite has a
|
||||
# special column, usually called the "rowid", that uniquely identifies
|
||||
# that row within the table.
|
||||
#
|
||||
# EVIDENCE-OF: R-32341-39358 However if the phrase "WITHOUT ROWID" is
|
||||
# added to the end of a CREATE TABLE statement, then the special "rowid"
|
||||
# column is omitted.
|
||||
#
|
||||
do_execsql_test without_rowid5-1.1 {
|
||||
CREATE TABLE t1(a PRIMARY KEY,b,c);
|
||||
CREATE TABLE t1w(a PRIMARY KEY,b,c) WITHOUT ROWID;
|
||||
INSERT INTO t1 VALUES(1565,681,1148),(1429,1190,1619),(425,358,1306);
|
||||
INSERT INTO t1w SELECT a,b,c FROM t1;
|
||||
SELECT rowid, _rowid_, oid FROM t1 ORDER BY a DESC;
|
||||
} {1 1 1 2 2 2 3 3 3}
|
||||
do_catchsql_test without_rowid5-1.2 {
|
||||
SELECT rowid FROM t1w;
|
||||
} {1 {no such column: rowid}}
|
||||
do_catchsql_test without_rowid5-1.3 {
|
||||
SELECT _rowid_ FROM t1w;
|
||||
} {1 {no such column: _rowid_}}
|
||||
do_catchsql_test without_rowid5-1.4 {
|
||||
SELECT oid FROM t1w;
|
||||
} {1 {no such column: oid}}
|
||||
|
||||
# EVIDENCE-OF: R-00217-01605 To create a WITHOUT ROWID table, simply add
|
||||
# the keywords "WITHOUT ROWID" to the end of the CREATE TABLE statement.
|
||||
# For example: CREATE TABLE IF NOT EXISTS wordcount( word TEXT PRIMARY
|
||||
# KEY, cnt INTEGER ) WITHOUT ROWID;
|
||||
#
|
||||
do_execsql_test without_rowid5-2.1 {
|
||||
CREATE TABLE IF NOT EXISTS wordcount(
|
||||
word TEXT PRIMARY KEY,
|
||||
cnt INTEGER
|
||||
) WITHOUT ROWID;
|
||||
INSERT INTO wordcount VALUES('one',1);
|
||||
} {}
|
||||
do_catchsql_test without_rowid5-2.2 {
|
||||
SELECT rowid FROM wordcount;
|
||||
} {1 {no such column: rowid}}
|
||||
|
||||
# EVIDENCE-OF: R-24770-17719 As with all SQL syntax, the case of the
|
||||
# keywords does not matter. One can write "WITHOUT rowid" or "without
|
||||
# rowid" or "WiThOuT rOwId" and it will mean the same thing.
|
||||
#
|
||||
do_execsql_test without_rowid5-2.3 {
|
||||
CREATE TABLE IF NOT EXISTS wordcount_b(
|
||||
word TEXT PRIMARY KEY,
|
||||
cnt INTEGER
|
||||
) WITHOUT rowid;
|
||||
INSERT INTO wordcount_b VALUES('one',1);
|
||||
} {}
|
||||
do_catchsql_test without_rowid5-2.4 {
|
||||
SELECT rowid FROM wordcount_b;
|
||||
} {1 {no such column: rowid}}
|
||||
do_execsql_test without_rowid5-2.5 {
|
||||
CREATE TABLE IF NOT EXISTS wordcount_c(
|
||||
word TEXT PRIMARY KEY,
|
||||
cnt INTEGER
|
||||
) without rowid;
|
||||
INSERT INTO wordcount_c VALUES('one',1);
|
||||
} {}
|
||||
do_catchsql_test without_rowid5-2.6 {
|
||||
SELECT rowid FROM wordcount_c;
|
||||
} {1 {no such column: rowid}}
|
||||
do_execsql_test without_rowid5-2.7 {
|
||||
CREATE TABLE IF NOT EXISTS wordcount_d(
|
||||
word TEXT PRIMARY KEY,
|
||||
cnt INTEGER
|
||||
) WITHOUT rowid;
|
||||
INSERT INTO wordcount_d VALUES('one',1);
|
||||
} {}
|
||||
do_catchsql_test without_rowid5-2.8 {
|
||||
SELECT rowid FROM wordcount_d;
|
||||
} {1 {no such column: rowid}}
|
||||
|
||||
# EVIDENCE-OF: R-01418-51310 However, only "rowid" works as the keyword
|
||||
# in the CREATE TABLE statement.
|
||||
#
|
||||
do_catchsql_test without_rowid5-3.1 {
|
||||
CREATE TABLE IF NOT EXISTS error1(
|
||||
word TEXT PRIMARY KEY,
|
||||
cnt INTEGER
|
||||
) WITHOUT _rowid_;
|
||||
} {1 {unknown table option: _rowid_}}
|
||||
do_catchsql_test without_rowid5-3.2 {
|
||||
CREATE TABLE IF NOT EXISTS error2(
|
||||
word TEXT PRIMARY KEY,
|
||||
cnt INTEGER
|
||||
) WITHOUT oid;
|
||||
} {1 {unknown table option: oid}}
|
||||
|
||||
# EVIDENCE-OF: R-58033-17334 An error is raised if a CREATE TABLE
|
||||
# statement with the WITHOUT ROWID clause lacks a PRIMARY KEY.
|
||||
#
|
||||
# EVIDENCE-OF: R-63443-09418 Every WITHOUT ROWID table must have a
|
||||
# PRIMARY KEY.
|
||||
#
|
||||
# EVIDENCE-OF: R-27966-31616 An attempt to create a WITHOUT ROWID table
|
||||
# without a PRIMARY KEY results in an error.
|
||||
#
|
||||
do_catchsql_test without_rowid5-4.1 {
|
||||
CREATE TABLE IF NOT EXISTS error3(
|
||||
word TEXT UNIQUE,
|
||||
cnt INTEGER
|
||||
) WITHOUT ROWID;
|
||||
} {1 {PRIMARY KEY missing on table error3}}
|
||||
|
||||
# EVIDENCE-OF: R-48230-36247 The special behaviors associated "INTEGER
|
||||
# PRIMARY KEY" do not apply on WITHOUT ROWID tables.
|
||||
#
|
||||
do_execsql_test without_rowid5-5.1 {
|
||||
CREATE TABLE ipk(key INTEGER PRIMARY KEY, val TEXT) WITHOUT ROWID;
|
||||
INSERT INTO ipk VALUES('rival','bonus'); -- ok to insert non-integer key
|
||||
SELECT * FROM ipk;
|
||||
} {rival bonus}
|
||||
do_catchsql_test without_rowid5-5.2 {
|
||||
INSERT INTO ipk VALUES(NULL,'sample'); -- no automatic generation of keys
|
||||
} {1 {NOT NULL constraint failed: ipk.key}}
|
||||
|
||||
# EVIDENCE-OF: R-33142-02092 AUTOINCREMENT does not work on WITHOUT
|
||||
# ROWID tables.
|
||||
#
|
||||
# EVIDENCE-OF: R-53084-07740 An error is raised if the "AUTOINCREMENT"
|
||||
# keyword is used in the CREATE TABLE statement for a WITHOUT ROWID
|
||||
# table.
|
||||
#
|
||||
do_catchsql_test without_rowid5-5.3 {
|
||||
CREATE TABLE ipk2(key INTEGER PRIMARY KEY AUTOINCREMENT, val TEXT)WITHOUT ROWID;
|
||||
} {1 {AUTOINCREMENT not allowed on WITHOUT ROWID tables}}
|
||||
|
||||
# EVIDENCE-OF: R-27831-00579 NOT NULL is enforced on every column of the
|
||||
# PRIMARY KEY in a WITHOUT ROWID table.
|
||||
#
|
||||
# EVIDENCE-OF: R-29781-51289 So, ordinary rowid tables in SQLite violate
|
||||
# the SQL standard and allow NULL values in PRIMARY KEY fields.
|
||||
#
|
||||
# EVIDENCE-OF: R-27472-62612 But WITHOUT ROWID tables do follow the
|
||||
# standard and will throw an error on any attempt to insert a NULL into
|
||||
# a PRIMARY KEY column.
|
||||
#
|
||||
do_execsql_test without_rowid5-5.4 {
|
||||
CREATE TABLE nn(a, b, c, d, e, PRIMARY KEY(c,a,e));
|
||||
CREATE TABLE nnw(a, b, c, d, e, PRIMARY KEY(c,a,e)) WITHOUT ROWID;
|
||||
INSERT INTO nn VALUES(1,2,3,4,5);
|
||||
INSERT INTO nnw VALUES(1,2,3,4,5);
|
||||
} {}
|
||||
do_execsql_test without_rowid5-5.5 {
|
||||
INSERT INTO nn VALUES(NULL, 3,4,5,6);
|
||||
INSERT INTO nn VALUES(3,4,NULL,7,8);
|
||||
INSERT INTO nn VALUES(4,5,6,7,NULL);
|
||||
SELECT count(*) FROM nn;
|
||||
} {4}
|
||||
do_catchsql_test without_rowid5-5.6 {
|
||||
INSERT INTO nnw VALUES(NULL, 3,4,5,6);
|
||||
} {1 {NOT NULL constraint failed: nnw.a}}
|
||||
do_catchsql_test without_rowid5-5.7 {
|
||||
INSERT INTO nnw VALUES(3,4,NULL,7,8)
|
||||
} {1 {NOT NULL constraint failed: nnw.c}}
|
||||
do_catchsql_test without_rowid5-5.8 {
|
||||
INSERT INTO nnw VALUES(4,5,6,7,NULL)
|
||||
} {1 {NOT NULL constraint failed: nnw.e}}
|
||||
do_execsql_test without_rowid5-5.9 {
|
||||
SELECT count(*) FROM nnw;
|
||||
} {1}
|
||||
|
||||
# EVIDENCE-OF: R-12643-30541 The incremental blob I/O mechanism does not
|
||||
# work for WITHOUT ROWID tables.
|
||||
#
|
||||
# EVIDENCE-OF: R-25760-33257 The sqlite3_blob_open() interface will fail
|
||||
# for a WITHOUT ROWID table.
|
||||
#
|
||||
do_execsql_test without_rowid5-6.1 {
|
||||
CREATE TABLE b1(a INTEGER PRIMARY KEY, b BLOB) WITHOUT ROWID;
|
||||
INSERT INTO b1 VALUES(1,x'0102030405060708090a0b0c0d0e0f');
|
||||
} {}
|
||||
do_test without_rowid5-6.2 {
|
||||
set rc [catch {db incrblob b1 b 1} msg]
|
||||
lappend rc $msg
|
||||
} {1 {cannot open table without rowid: b1}}
|
||||
|
||||
|
||||
finish_test
|
||||
+31
-1
@@ -29,6 +29,7 @@
|
||||
** --commit NNN Commit after every NNN operations
|
||||
** --nosync Use PRAGMA synchronous=OFF
|
||||
** --journal MMMM Use PRAGMA journal_mode=MMMM
|
||||
** --timer Time the operation of this program
|
||||
**
|
||||
** Modes:
|
||||
**
|
||||
@@ -80,6 +81,21 @@
|
||||
#include <stdarg.h>
|
||||
#include "sqlite3.h"
|
||||
|
||||
/* Return the current wall-clock time */
|
||||
static sqlite3_int64 realTime(void){
|
||||
static sqlite3_vfs *clockVfs = 0;
|
||||
sqlite3_int64 t;
|
||||
if( clockVfs==0 ) clockVfs = sqlite3_vfs_find(0);
|
||||
if( clockVfs->iVersion>=1 && clockVfs->xCurrentTimeInt64!=0 ){
|
||||
clockVfs->xCurrentTimeInt64(clockVfs, &t);
|
||||
}else{
|
||||
double r;
|
||||
clockVfs->xCurrentTime(clockVfs, &r);
|
||||
t = (sqlite3_int64)(r*86400000.0);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Print an error message and exit */
|
||||
static void fatal_error(const char *zMsg, ...){
|
||||
va_list ap;
|
||||
@@ -100,7 +116,7 @@ static int printResult(void *NotUsed, int nArg, char **azArg, char **azNm){
|
||||
int i;
|
||||
printf("--");
|
||||
for(i=0; i<nArg; i++){
|
||||
printf(" %s", azArg[i]);
|
||||
printf(" %s", azArg[i] ? azArg[i] : "(null)");
|
||||
}
|
||||
printf("\n");
|
||||
return 0;
|
||||
@@ -186,6 +202,7 @@ int main(int argc, char **argv){
|
||||
int doTrace = 0; /* True for --trace */
|
||||
int showStats = 0; /* True for --stats */
|
||||
int showSummary = 0; /* True for --summary */
|
||||
int showTimer = 0; /* True for --timer */
|
||||
int cacheSize = 0; /* Desired cache size. 0 means default */
|
||||
int pageSize = 0; /* Desired page size. 0 means default */
|
||||
int commitInterval = 0; /* How often to commit. 0 means never */
|
||||
@@ -203,6 +220,7 @@ int main(int argc, char **argv){
|
||||
int rc; /* Return code from an SQLite interface */
|
||||
int iCur, iHiwtr; /* Statistics values, current and "highwater" */
|
||||
sqlite3_int64 sumCnt = 0; /* Sum in QUERY mode */
|
||||
sqlite3_int64 startTime;
|
||||
char zInput[2000]; /* A single line of input */
|
||||
|
||||
/* Process command-line arguments */
|
||||
@@ -234,6 +252,8 @@ int main(int argc, char **argv){
|
||||
showStats = 1;
|
||||
}else if( strcmp(z,"summary")==0 ){
|
||||
showSummary = 1;
|
||||
}else if( strcmp(z,"timer")==0 ){
|
||||
showTimer = i;
|
||||
}else if( strcmp(z,"cachesize")==0 && i<argc-1 ){
|
||||
i++;
|
||||
cacheSize = atoi(argv[i]);
|
||||
@@ -259,6 +279,7 @@ int main(int argc, char **argv){
|
||||
if( zDbName==0 ){
|
||||
fatal_error("Usage: %s [--options] DATABASE [INPUTFILE]\n", argv[0]);
|
||||
}
|
||||
startTime = realTime();
|
||||
|
||||
/* Open the database and the input file */
|
||||
if( sqlite3_open(zDbName, &db) ){
|
||||
@@ -449,6 +470,15 @@ int main(int argc, char **argv){
|
||||
sqlite3_finalize(pSelect);
|
||||
}
|
||||
|
||||
|
||||
if( showTimer ){
|
||||
sqlite3_int64 elapseTime = realTime() - startTime;
|
||||
fprintf(stderr, "%3d.%03d wordcount", (int)(elapseTime/1000),
|
||||
(int)(elapseTime%1000));
|
||||
for(i=1; i<argc; i++) if( i!=showTimer ) fprintf(stderr, " %s", argv[i]);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
if( showSummary ){
|
||||
sqlite3_create_function(db, "checksum", -1, SQLITE_UTF8, 0,
|
||||
0, checksumStep, checksumFinalize);
|
||||
|
||||
@@ -492,9 +492,9 @@ GOTO no_errors
|
||||
GOTO :EOF
|
||||
|
||||
:fn_CopyVariable
|
||||
SETLOCAL
|
||||
IF NOT DEFINED %1 GOTO :EOF
|
||||
IF "%2" == "" GOTO :EOF
|
||||
SETLOCAL
|
||||
SET __ECHO_CMD=ECHO %%%1%%
|
||||
FOR /F "delims=" %%V IN ('%__ECHO_CMD%') DO (
|
||||
SET VALUE=%%V
|
||||
|
||||
Reference in New Issue
Block a user