Compare commits

..

51 Commits

Author SHA1 Message Date
drh 9b2fc61d25 Return an SQLITE_CORRUPT error if the content size field of a table record
extends off the end of a page.

FossilOrigin-Name: b48c4e402125fb8d2208d358f6e9bbc351f3a49d
2013-11-25 20:14:13 +00:00
drh ebf10b1fb4 Uses shifts rather than division for arithmetic on the cell indices, since
those indices are always non-negative.

FossilOrigin-Name: 5bf2a3feeb2c83671bf3edeb20a549239e6873bf
2013-11-25 17:38:26 +00:00
drh 17566ee243 Optimize the skipping of the payload size field when doing a binary search
for a rowid.

FossilOrigin-Name: 55e5bfa231dd52a7cf9ec982967da4963867b9e5
2013-11-25 16:52:59 +00:00
drh d2022b0118 Arrange for sqlite3BtreeMovetoUnpacked() to always leave the cursor cell
parse cache invalidated.  This fixes issues with previous check-ins on this
branch and also runs faster.

FossilOrigin-Name: a74675607fe041e37a58a3ec287131de0e5090c3
2013-11-25 16:23:52 +00:00
drh bb933ef6e7 More optimizations to sqlite3BtreeMovetoUnpacked(). But there are failures
in TH3.  Committing this intermediate state to facilitate bisecting.

FossilOrigin-Name: f80497be446f84d2000e454e32d717887a7d0cee
2013-11-25 15:01:38 +00:00
drh d793f44723 More improvements to sqlite3BtreeMovetoUnpacked() performance.
FossilOrigin-Name: 88680698231b7141401f7166e3aff8dbc6008030
2013-11-25 14:10:15 +00:00
drh ec3e6b10f4 Performance improvements in sqlite3BtreeMovetoUnpacked().
FossilOrigin-Name: d0fb7acea7cbfe6f2d84782a28bb51675a06576f
2013-11-25 02:38:55 +00:00
drh 93307e9d06 Add the --scratch parameter to speedtest1. Improved error messages when
misconfiguring memory parameters in speedtest1.

FossilOrigin-Name: 8f3c767a30c552548ead104ca125f182ce4849ad
2013-11-24 01:14:14 +00:00
drh 0c2df17691 The MEMSYS5 algorithm does not have to return the block with the lowest
address.  Any block of the appropriate size will do.  Use the first block
found on the freelist for the appropriate size for a performance improvement.

FossilOrigin-Name: 12e612e8e7c4a6f83acf0daf5608151fb5ec1575
2013-11-24 00:46:00 +00:00
drh 9948e95674 A much simpler fix is to simply change MEMSYS5 so that it takes any free
block of the appropriate size (the first on the list of free blocks) rather
than searching for the one with the smallest address.  This is also faster
than using the min-heap algorithm.  Need to research to verify that the
allocator still satisfies the Robson proof, however.

FossilOrigin-Name: 8191b512122c13d7fa61d8e5487652f13ec172f7
2013-11-23 22:45:12 +00:00
drh 7b65ad31e1 Add newlines at the end of some error messages in speedtest1.
FossilOrigin-Name: 6b98f0af7a6522873245d30598d7c79b8aeb9fa0
2013-11-23 21:29:07 +00:00
drh e19f8327f8 Report errors from sqlite3_exec() and sqlite3_config() in speedtest1. Fix
a bug in the main testing logic that was found by these error reports.

FossilOrigin-Name: 659f1a98ae698d062269f8fdac84f733a460f5de
2013-11-23 11:45:58 +00:00
drh c7c9f7110b Fix the order of parameters to SQLITE_CONFIG_PAGECACHE in the
speedtest1.exe program.

FossilOrigin-Name: dbe85ef6d265ed31f4b56dfc0c72bad6adcfd7f0
2013-11-23 04:32:18 +00:00
mistachkin 1617577e77 Adjust MSVC makefile to avoid using forward slashes in file names.
FossilOrigin-Name: facf6deaa61ed2e1744711d621d7f50fe2067803
2013-11-23 04:22:19 +00:00
drh ad1ca9a792 Add the "speedtest1.exe" test program.
FossilOrigin-Name: fb6f0c6d77b2318e6e587951514aea91db128c3c
2013-11-23 04:16:58 +00:00
mistachkin 20b859530b Fix harmless compiler warning.
FossilOrigin-Name: f336c18fb72ab90e93640b12ac540d41accc7658
2013-11-22 21:32:44 +00:00
mistachkin f201496c6a Minor correction to the batch build tool for MSVC.
FossilOrigin-Name: 22144c9df260910c4b67960b0e6a6bd5a6758cd7
2013-11-22 00:49:43 +00:00
drh 0a30592c1e Fix a harmless clang warning in the command-line shell.
FossilOrigin-Name: 3d47a556f0074e39b880186fb7661b1b8955f742
2013-11-21 23:37:02 +00:00
drh cb4f870884 Slight change to the --timer output on wordcount for better display on
windows:  Avoid showing the full pathname of the executable.

FossilOrigin-Name: b9e047b9e3c2ee4df4a2d921db62f590fa5452d3
2013-11-21 22:02:52 +00:00
drh 501932ca68 Changes some offset and amount parameters from "int" to "u32" to avoid
harmless signed/unsigned comparison warnings.

FossilOrigin-Name: 4e8c5d0795cb7c603182bfa70f3855d654f0997e
2013-11-21 21:59:53 +00:00
drh 7a909855f2 Modify wordcount so that timer information appears on standard error instead
of standard output.  Rename the run-wordcount.bash script to run-wordcount.sh
and simplify it so that it stands a better chance of running on non-GNU 
systems.

FossilOrigin-Name: 586c11ed7cc6b8e2c7181231e37791c2fbc95272
2013-11-21 21:40:45 +00:00
drh d673cddad6 Do not reuse factored constants that might have had their encodings changed.
FossilOrigin-Name: 487f20366ce77f0c90865d10d5aaedd95af98694
2013-11-21 21:23:31 +00:00
drh d9f158e7b2 Fix the code generator to honor turning off constant expression factoring.
FossilOrigin-Name: 882622662dfadf49c65c7d80b7fd87533d079ce9
2013-11-21 20:48:42 +00:00
drh d2b637c2af Add the --timer option to the wordcount test program.
FossilOrigin-Name: a89fdf87553f01c150729c570796b5078a9b069d
2013-11-21 19:27:45 +00:00
drh 2b53e00f73 Remove a test from sqlite3VdbeMemFromBtree() which was unnecessary, and
after the recent OP_Column refactoring, unreachable.

FossilOrigin-Name: 23667f3ba09b7e839d76c42669dc9247a91262c8
2013-11-21 19:05:04 +00:00
drh 66e810247e Make sure the OP_Next and OP_NextIfOpen opcodes are numbered close together
for efficiency in switch() statements.  OP_Prev and OP_PrevIfOpen too.

FossilOrigin-Name: d4ccf0f5c656c8f0e1c32d5f7971b131f42c3cbd
2013-11-21 17:24:18 +00:00
drh d1a01edac9 When one or more arguments to a function are constants, try to factor
out just those arguments into initialization code.

FossilOrigin-Name: 50d350abbc9176cd6fc606bc45b8fc3020719500
2013-11-21 16:08:52 +00:00
drh 10f468f37a Remove the obsolete TK_CONST_FUNC token type.
FossilOrigin-Name: 9b4217f055e9bced186b4c56a5753bd6da7115b5
2013-11-21 14:44:38 +00:00
drh b1fba2868b Add the ability to factor constant functions out of inner loops. But do
not factor out non-constant functions, like random().

FossilOrigin-Name: 1b0f779e19a5c0d51eddd2d88db50034d77d132c
2013-11-21 14:33:48 +00:00
drh e09f43f8b7 Another improvement to OP_Function and an improvement to OP_Move.
FossilOrigin-Name: 70b056fb6f60cdfbe24e4b77a1770eef064a73c6
2013-11-21 04:18:31 +00:00
drh 76694c3ae5 A simple change to the OP_Function opcode improves overall performance by
about 0.5%.

FossilOrigin-Name: b890eefd57fbd189f7df611e82eb1fb4b197e1c3
2013-11-21 03:43:12 +00:00
drh f93cd949a0 Performance optimization to the OP_Next and OP_Prev opcodes.
FossilOrigin-Name: ecaac28a2e78aca148fc614fe54bf2706aed8be2
2013-11-21 03:12:25 +00:00
drh 3630a408f2 Refactor the OP_Column opcode to make it clearer and easier to maintain.
Overall, performance tests show about a 1% speed increase with this change.

FossilOrigin-Name: 972881c6d394c199961f01dcbeb4a6e8b5c919a1
2013-11-21 01:33:45 +00:00
drh 5cc1023e1c Reduce the size of VdbeCursor again, this time without a performance hit.
FossilOrigin-Name: 933939932c44bccb0958f203a5bd24e683c1cf38
2013-11-21 01:04:02 +00:00
drh 1fd522ff49 Unpack some fields, adding some space back to the VdbeCursor object,
in order to help the code to run a little faster.

FossilOrigin-Name: f8d5efcd7b92492b833b6cd1cb6bec006c6a0809
2013-11-21 00:10:35 +00:00
drh 14da87f8c5 Reduce the size of the VdbeCursor object from 144 to 120 bytes.
FossilOrigin-Name: 5f9d50688508affd0bc8e4d52e21dacfacdbb5ce
2013-11-20 21:51:33 +00:00
drh 380d685133 Improved comments on the OP_Column changes. Optimize out loading of overflow
pages for content with zero length.  Add test cases for the latter.

FossilOrigin-Name: 0e05679db7aa302a49e087a81f85203844b98cbe
2013-11-20 20:58:00 +00:00
drh c8606e416a Further performance tweaks to OP_Column.
FossilOrigin-Name: 0e3f5df695216a27602a53eed5d25231b055adc8
2013-11-20 19:28:03 +00:00
drh 399af1d2c2 Refactoring the OP_Column opcode for improved performance and
maintainability.

FossilOrigin-Name: 7c914e3997d2b28164a2fa7eb4398262b6ddb4b2
2013-11-20 17:25:55 +00:00
drh 79353dbd5f Simplifications to the VdbeCursor object.
FossilOrigin-Name: 5562cd343d8f69242e06a51a7f1aef7ee7d78eec
2013-11-20 02:53:58 +00:00
drh 83b301b0af Performance improvement for the OP_MustBeInt opcode in the VDBE.
FossilOrigin-Name: 96a65388e75fed96e2e73ef65726f6db88cc5ccd
2013-11-20 00:59:02 +00:00
drh 707f1c560a Fix a harmless MSVC compiler warning.
FossilOrigin-Name: 6cc023bb29be51847fbbfab95c24fc89993ccdba
2013-11-19 18:17:20 +00:00
drh c138dafe88 Minor performance improvement to sqlite3SerialTypeGet().
FossilOrigin-Name: 17e8524fc05aa1e6074c19a8ccccc5ab5883103a
2013-11-19 13:55:34 +00:00
drh 6bc69a2d4b Change Noop-comments in where.c into Module-comments, so that they are
omitting without SQLITE_ENABLE_MODULE_COMMENTS.

FossilOrigin-Name: 3e577f40183c56e60866d8382b044688a1b77eaf
2013-11-19 12:33:23 +00:00
drh 5c82f4df9f Avoid seeking on the main data table during the first loop of an UPDATE
if an index is sufficient to check the WHERE clause.

FossilOrigin-Name: 57158d9daf4d777411fffb1c1d20d89b291d9214
2013-11-19 02:34:11 +00:00
drh f37139f65b Fix an requirement mark in a test script so that it matches the
typo-corrected requirement.  No changes to code.

FossilOrigin-Name: 072412d5e3f92c9c6548f5c86d396d3f024df3f7
2013-11-19 00:31:25 +00:00
drh 64ff26f741 Add comments identifing where the skip-scan option is decided in the
query planner, to aid in tuning that decision.  No changes to code.

FossilOrigin-Name: e9df04cec48bb8b4ea26ec9024a22ea42b2338eb
2013-11-18 19:32:15 +00:00
drh 2365bac1e2 Fix documentation typos. No changes to code.
FossilOrigin-Name: 7caeb09c52bde4649b02b339f611c8e30f6d1c68
2013-11-18 18:48:50 +00:00
drh 2bea7cde6e Fix harmless compiler warnings from clang scan-build.
FossilOrigin-Name: 8d002740bffca2a76d2dfbc1a67293d34f9de9ba
2013-11-18 11:20:50 +00:00
dan c4650bb33d Fix a problem with the shell tool EXPLAIN indentation code and VDBE sub-programs.
FossilOrigin-Name: 9c8d6856253f8da06b2cb5dc6bd89b6952fa03ed
2013-11-18 08:41:06 +00:00
drh e73e067187 Enable the ONEPASS optimization for DELETE, for both rowid and WITHOUT
ROWID tables.

FossilOrigin-Name: 44a07afdd9b3ae2460bc963383295deb0915f899
2013-11-18 03:11:54 +00:00
37 changed files with 1697 additions and 612 deletions
+3
View File
@@ -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
+8 -4
View File
@@ -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
-1
View File
@@ -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
View File
@@ -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 );
+3
View File
@@ -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.
+39 -37
View File
@@ -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 Return\san\sSQLITE_CORRUPT\serror\sif\sthe\scontent\ssize\sfield\sof\sa\stable\srecord\nextends\soff\sthe\send\sof\sa\spage.
D 2013-11-25T20:14:13.468
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 a6247094079f3ef97dcd7a69d0e13ff718c7073e
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,19 +166,19 @@ 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 c308e64d89de5ea87e5538f7380af4477892e067
F src/btree.h a61ddebc78c66795a2b93181321a116746302cc9
F src/btreeInt.h f038e818bfadf75afbd09819ed93c26a333d39e0
F src/build.c 07054d45319953e54a89d726e589a423e9c1c590
F src/callback.c f99a8957ba2adf369645fac0db09ad8adcf1caa2
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c ea4b7f3623a0fcb1146e7f245d7410033e86859c
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/fkey.c 2ab0f5384b70594468ef3ac5c7ed8ca24bfd17d5
F src/func.c ef30d26ae4d79bbc7300c74e77fd117a0ba30235
F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
@@ -194,7 +194,7 @@ 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 2221f7e4619619d2df16fcb8a1da2a165ae56d9d
F src/memjournal.c 0683aac6cab6ec2b5374c0db37c0deb2436a3785
F src/mutex.c d3b66a569368015e0fcb1ac15f81c119f504d3bc
F src/mutex.h 5bc526e19dccc412b7ff04642f6fdad3fdfdabea
@@ -209,7 +209,7 @@ F src/os_unix.c 143624d9eabb3b997c59cf594e0d06c56edd43e9
F src/os_win.c ef091b347d682cb24fc575ac9a6290341af62e2b
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,14 +217,14 @@ 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 a70e32ae6ccb7b780f2b6d3e9e21837affc25ee5
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 c4d06a9238a515ff4bc86b8626139633c09a00a2
F src/sqlite.h.in a5dc058a909d9f14470bad9329d9e9303020ea4e
F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
F src/sqliteInt.h 03b91c6bceccd7718473f3d790abcb8d5c2b1bf1
F src/sqliteInt.h 9d586cb37572cd9e0a48242d449c6a69c2e74e72
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -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 c05a0ee658f1a149e0960dfd110f3b8bd846bcb0
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
F src/util.c 2fa6c821d28bbdbeec1b2a7b091a281c9ef8f918
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
F src/vdbe.c 5573893423aec2d64871e8d504fadbcdaad39fed
F src/vdbe.c 23d0cfba65b6dadf39a0805d0fba266e8146d678
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 5251f17828ff49664f457b6d8a1585297ce7a7a9
F src/vdbeblob.c 8cd05a5630e6d5563ad017bf82edaf812b28acde
F src/vdbemem.c cd02a6ade205ebe989983b7e3d64a5358b8e5e1f
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 e558bfa67009ab7de08a7a1960ae0dd443241cdd
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
@@ -437,7 +437,7 @@ F test/e_createtable.test 3b453432cd14a12732ee9467597d2274ca37ce36
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 7d7feeadb555b49476e9ca4a145fcf7c0a81ce34
F test/e_fkey.test d83a04478bb9c02d2c513518548a69f818869f41
F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459
F test/e_insert.test 1e44f84d2abe44d66e4fbf198be4b20e3cc724a0
@@ -573,10 +573,11 @@ 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
@@ -757,7 +758,7 @@ F test/rollback.test e9504a009a202c3ed711da2e6879ff60c5a4669c
F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
F test/rowid.test f777404492adb0e00868fd706a3721328fd3af48
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
@@ -818,6 +819,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 aa08ae8e3591bf5c028be9396a84237640761d8c
F test/spellfix.test 8c40b169b104086d8795781f670ba3c786d6d8be
F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298
F test/stat.test c8eccfe8fcd3f3cfc864ce22d5b9e803a3c69940
@@ -1088,10 +1090,10 @@ 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/wordcount.c 800b6ab98ac05b7c6343575c45055f72273c9cc2
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 +1142,7 @@ 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
P 5bf2a3feeb2c83671bf3edeb20a549239e6873bf
R 5bcbc7e134df92bc8848f497a4ca3642
U drh
Z 2718e457b564d6fbe8d10873d690a300
Z d267e18bd1e4ed89c545a37f1e6bffd5
+1 -1
View File
@@ -1 +1 @@
6bd5750b7d5da221b0689f6df6be5ed0dce61bec
b48c4e402125fb8d2208d358f6e9bbc351f3a49d
+2
View File
@@ -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++
+61 -53
View File
@@ -4206,7 +4206,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;
@@ -4256,7 +4256,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 +4265,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 +4647,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 +4662,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 +4711,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 +4742,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 +4751,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
View File
@@ -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);
+4 -5
View File
@@ -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
View File
@@ -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;
+2
View File
@@ -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
View File
@@ -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
+2 -20
View File
@@ -209,25 +209,6 @@ static int memsys5Size(void *p){
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;
+1 -6
View File
@@ -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);
}
+1 -2
View File
@@ -667,7 +667,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 +679,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 +723,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
View File
@@ -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;
+19 -8
View File
@@ -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);
}
+6 -7
View File
@@ -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
@@ -3106,7 +3106,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>
*/
@@ -3836,7 +3835,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 +4913,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()]
+24 -4
View File
@@ -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 */
@@ -2894,10 +2911,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*);
+5
View File
@@ -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
+260 -300
View File
@@ -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;
}
@@ -4130,7 +4075,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;
@@ -4267,7 +4212,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 +4252,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 +4271,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 +4291,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 +4364,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 +4440,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 +4448,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 +4467,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 +4476,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 +4490,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 +4499,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 +4568,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 +5819,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
View File
@@ -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) \
+9 -10
View File
@@ -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;
}
}
@@ -3206,7 +3205,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 +3283,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
View File
@@ -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);
+5 -5
View File
@@ -896,13 +896,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 +917,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 +936,7 @@ int sqlite3VdbeMemFromBtree(
sqlite3VdbeMemRelease(pMem);
}
}
pMem->n = amt;
pMem->n = (int)amt;
return rc;
}
+12 -7
View File
@@ -2406,7 +2406,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 +2756,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 +3461,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 +3918,15 @@ 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 50.
*/
if( pTerm==0
&& saved_nEq==saved_nSkip
&& saved_nEq+1<pProbe->nKeyCol
&& pProbe->aiRowEst[saved_nEq+1]>50
&& pProbe->aiRowEst[saved_nEq+1]>50 /* TUNING: Minimum for skip-scan */
){
LogEst nIter;
pNew->u.btree.nEq++;
@@ -5731,7 +5736,7 @@ WhereInfo *sqlite3WhereBegin(
}
/* Done. */
VdbeNoopComment((v, "Begin WHERE-core"));
VdbeModuleComment((v, "Begin WHERE-core"));
return pWInfo;
/* Jump here if malloc fails */
@@ -5758,7 +5763,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 +5809,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
View File
@@ -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}
#-------------------------------------------------------------------------
+3 -3
View File
@@ -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
+18
View File
@@ -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.
+33
View File
@@ -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
-66
View File
@@ -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
+78
View File
@@ -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
+951
View File
@@ -0,0 +1,951 @@
/*
** 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;
}
/*
** 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>=2147483648 ) fatal_error("parameter to large - max 2147483648");
return 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( 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;
}
/* 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 = 2903710987;
g.y = 1157229256;
}
/* 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( 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);
sqlite3_db_status(g.db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHi, 1);
printf("-- Page cache writes: %d\n", iCur);
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);
}
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);
sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHi, 0);
printf("-- Outstanding Allocations: %d (max %d)\n", iCur,iHi);
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;
}
+30
View File
@@ -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;
@@ -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);
+1 -1
View File
@@ -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