Compare commits

...

64 Commits

Author SHA1 Message Date
dan 8ea00d744e Merge trunk changes into this branch.
FossilOrigin-Name: d805fc0cf1c4ef07a7bc947f75828931e3788d0e64730caab3b42ae58009a194
2019-04-11 19:04:01 +00:00
dan e639128cb0 Further tweaks to wapptest.tcl. Add the ability to run the extra (n)debug tests that releasetest.tcl runs.
FossilOrigin-Name: ec9c4f6d8da25dcc834812c2bb24bda1017833b1c572bdbbf87f0191e1310706
2019-04-11 19:03:15 +00:00
drh 323096175e Remove the vfslog.c extension from the testfixture target in main.mk, as
that extension has no TCL bindings and is inaccessible.

FossilOrigin-Name: d71f8bbc4efd8af935671c4e7626862d6e5a4c2e51527b9e82b2f0c94ddf6e93
2019-04-11 17:06:54 +00:00
dan 971194aca3 Fix RBU so that it does not write rows that should be excluded into partial indexes (corrupting the database).
FossilOrigin-Name: 31eb27f438ad727b095a518bfe0f7ed37cb806fc1e6929b821eddcc6cc9de260
2019-04-11 16:54:20 +00:00
dan 579d41dc8d Fix the checksymbols target in Makefile.in.
FossilOrigin-Name: 1956eb348170a9a873878b522f377fa7303cdb3beca41f5515b6b9da1b1f544d
2019-04-11 06:50:52 +00:00
dan 93673620ec Have wapptest.tcl display the name, OS and architecture of the host.
FossilOrigin-Name: c47e53b4d0f29628bd20ba3daf7e759c4bfed07710d982c095445c01376d57f5
2019-04-10 19:45:19 +00:00
dan 523fb53f72 Various fixes for the wapptest.tcl script.
FossilOrigin-Name: cbf423656047f0cb5200be6981a205e0ae206eef8263aa686f4a3621fb07fb57
2019-04-10 18:56:30 +00:00
drh 6adba9031c Update the list of OMIT options in the omittest.tcl script.
FossilOrigin-Name: f294cfc173c5653ef161dbff63b7838dbccdcad797f5163c49b3173f9f35ab0f
2019-04-10 18:29:40 +00:00
drh 0364f229cc Further refinement of the sqlite3VdbeMEmExpandBlob() fix of check-in
[df58774e994bd] to prevent a reference to an unused variable - problem
discovered by Valgrind.

FossilOrigin-Name: 09435b5700a2650816ad9ffa628be5fa19da62369c30329801feb5e840463c7e
2019-04-10 13:24:35 +00:00
drh 0e1a574875 Change the name of some internal testing interfaces to avoid a name
conflict in AIX.

FossilOrigin-Name: c1cae7e7f0a612508c8f82b334d9ebc423f443e99b13092d52e26b348c7cbc5e
2019-04-10 12:02:55 +00:00
drh 86ec1eddde Do not place arbitrary restrictions on the length of the failure message
for a uniqueness constraint.

FossilOrigin-Name: 037da798fa5510ba7c776831ebcd683a85dca28e25bc657ff17bb2b08c3d406e
2019-04-10 00:58:07 +00:00
drh 9e26ac852a New test case for SQLITE_TOOBIG errors.
FossilOrigin-Name: 4c77fbbe5d54248821161d708d0631fab65659bef31f95a61af681d4639f5918
2019-04-09 21:37:27 +00:00
drh c3dcdba387 Improved reporting of SQLITE_TOOBIG errors while parsing.
FossilOrigin-Name: ea2d4b65e20e44e19219c821bf68e97ff3af1760b3b4762250d020ba2a5a6343
2019-04-09 21:32:46 +00:00
dan c7f3373ec7 Fix a problem caused by a small SQLITE_LIMIT_LENGTH value and a CREATE TABLE with a very large name.
FossilOrigin-Name: 9b5d408864920b302f2d21abcae1d90f1e0cd68b18262136554ba0e6219d6025
2019-04-09 20:50:44 +00:00
dan a3020dcb21 Add test/wapptest.tcl, a wapp alternative to releasetest.tcl.
FossilOrigin-Name: a4af0c2fee05aaa2e95ae6a5c847ff2d363e24f325f4ffdcf51bc264b9bf5e2d
2019-04-09 19:53:32 +00:00
drh 25050f2620 Use an unsigned integer to count free pages in btree.c:freePage2().
FossilOrigin-Name: 8820408597341344b308277ce6ef41b47c7514d6c613520789b05ee52cbedae8
2019-04-09 01:26:31 +00:00
drh 427db2d245 Make the testcase() macro added in the previous check-in reachable for
testing.

FossilOrigin-Name: 80704a16f6dbbeacc65fa36a3623df10292a28aeacf9e2c1d2891258479e3b89
2019-04-07 18:21:12 +00:00
drh 7d683394f1 Fix a faulty assert() in the sqlite3VdbeMemExpandBlob() routine.
FossilOrigin-Name: df58774e994bd306b1a2e1f259e7e4408f01c5b1dc104673698168bbf8a63ce5
2019-04-07 18:04:57 +00:00
dan ce3c3eeda0 Fix two assert() statements in fts5 that are only true if the database is not corrupt.
FossilOrigin-Name: edb095a9a679c8c702abd0a487e55ed4b09110b54bcd7d5275020576f2713a39
2019-04-06 15:38:46 +00:00
drh 7bbdc3c597 Remove some stale references to the addopcodes.tcl script from documentation.
FossilOrigin-Name: c0381b0bc90aa3c2415c4b3ac338cfe6d308bb5d4247bc6f2b6e919f549c254c
2019-04-05 21:17:11 +00:00
drh f1722baaf8 Eliminate the tool/addopcodes.tcl script. The purpose of that script was to
keep the number of parser codes below 256 in order to save parser table space.
But we have long since blown through that ceiling so the addopcodes.tcl script
was just needless complexity. There is no longer any reason to keep it around.

FossilOrigin-Name: d272819298083ebbde57962a2938925b1aaa1caf03e48bb3ea26ad91e0461d84
2019-04-05 20:56:46 +00:00
dan 6cf3009f6c Add further tests so that veryquick.test covers all vdbe branches.
FossilOrigin-Name: cbc67de5a3937fa65811ed7c13e870699c895660dc2132cf9d3cf5d83364e344
2019-04-05 20:47:15 +00:00
drh ce059e5219 Improved comment on the sqlite3FaultSim() function. No changes to code.
FossilOrigin-Name: 08b29672c552e5a6a3874746c6cc7025295e0e44dec43a1bfba3022acce849ff
2019-04-05 17:22:50 +00:00
dan 94c7ab5038 In the test_vfs.c VFS, if a Tcl xWrite script returns "SQLITE_OMIT", silently omit the write() call.
FossilOrigin-Name: 8b5a621e2ee3bb9d7d4f905217872e7e59153be9477aaa626cea287d56710b5b
2019-04-05 16:52:45 +00:00
drh e3bd232e2d Add the ability to override the new corruption detection logic
of the previous checkin, in order to exercise downstream corruption
detection during testing.

FossilOrigin-Name: e859d3184606dd453b9fc4ee388922d7be4b61aad84a66ac82107935ffd56f3a
2019-04-05 16:38:12 +00:00
drh 86223e8d65 In the xfer-optimization, do early detection of when the source and destination
index share the same btree, to avoid a long delay prior to reporting the
database corruption.

FossilOrigin-Name: af1e5873d44d31466023ae145bdfc6b4191eb48b62e5752c6e683bcf571980e7
2019-04-05 15:44:55 +00:00
dan d1f9932e4b Add further test cases to improve VDBE branch coverage.
FossilOrigin-Name: 51a95e52fc58d8be2c9c51576dff7258c705735b66d203948f80db017b4c10d2
2019-04-04 20:55:37 +00:00
drh 4c81cada05 Fix a typo in the documentation for sqlite3_value_frombind(). Also add a new
hyperlink to that same documentation.  No code changes.

FossilOrigin-Name: bf3cd9364fdfc951feb04f78728eb8e0dae12b3dc5702a36bb6e69c0abab8864
2019-04-04 19:21:45 +00:00
drh eacc8816dc Minor fixes to requirements marks.
FossilOrigin-Name: 02ebc60b9bbc1736f4989eb56f8d31ca97fe90c930841d10986c618381ceb8b4
2019-04-04 18:20:25 +00:00
dan b84b38fd89 Add test cases to improve coverage of VDBE branches. Still some to go.
FossilOrigin-Name: 4cef609d61de272cfdc2b39e1d49c7cd56ec834086bd63095116ff98f4d402bd
2019-04-04 17:58:34 +00:00
drh 80ac9cb3c0 Correctly initialize the loadable extension thunk.
FossilOrigin-Name: 4fca46ded7873d4939d7c6bff363ded41667f2255a4ab624a1a24bebbae733eb
2019-04-04 17:39:54 +00:00
drh 677525756b Simplification of the recent VACUUM changes that make the code more like
what it was before the change.  Also, make the VACUUM command a no-inline
procedure to work around a performance regression.

FossilOrigin-Name: 9cac5ac145d62117c918539baaa8a3c124230e031842e35fa1ba59f658c99518
2019-04-04 15:25:52 +00:00
drh eb80863cbf Fix an incorrect comment on a test case for rowid renumbering in VACUUM.
FossilOrigin-Name: 0d293fb43f2eb64026ac1e0422f54d4839b101898cc9913fc7746760c08ed41f
2019-04-04 14:36:02 +00:00
drh 4e61e88348 Only preserve rowid values for VACUUM INTO. Keep the legacy behavior of
renumbering rowids for ordinary VACUUM.

FossilOrigin-Name: 13a0ea6466b051ea5281865ed5285b8b5a99ec4307f400c5f7b03692723f1cd1
2019-04-04 14:00:23 +00:00
drh b92d7d264e Add a defense-in-depth NEVER() test to the WAL cleanup code.
FossilOrigin-Name: 8d3af2010f4f652865f5c0d18e3bc793de05f8e75e75cc77786f61004b2ad28f
2019-04-03 17:48:10 +00:00
dan 3f49c321e8 Fix a couple of problems with "RANGE BETWEEN <expr> PRECEDING AND <expr> PRECEDING" frames.
FossilOrigin-Name: 39225cc77579896214dceb93b7f224b4b3bc95b3505a2e19b41b0b18b184fbc4
2019-04-03 16:27:44 +00:00
drh 0f134f0267 Small optimizations to the grammar for window functions save about 120 bytes
of space in the parser tables.

FossilOrigin-Name: bce01d9584e52b23d7c07c2e832d5fa5d6e6235711c856b903a296725f61ed6e
2019-04-02 18:12:20 +00:00
drh 94809086e5 Use a separate bit on db->dbOptFlags to disable the xInverse optimization on
window functions, rather than reusing the query-flattener disable bit.

FossilOrigin-Name: bc0fb1c324be2fd668bc4398c7d364b7e3c5a98537fe5fb58a125b66f3e6d041
2019-04-02 17:45:56 +00:00
drh 3de52e8fa0 Including the phrase EXCLUDE NO OTHERS in the frame-spec of a window function
(which is the default setting for EXCLUDE) silently disables the xInverse
optimization.  This is a feature, but we will keep it undocumented for now
in case we later decide it is a bad idea.

FossilOrigin-Name: 10aedce3dd2c0c9f0ee9e0aefd0b4d2c2eb17c4ca72003c4db9768ea5cdafcf4
2019-04-02 17:45:01 +00:00
drh 3fda0aaf00 Put the list of keywords in mkkeywordhash.c into alphabetical order.
FossilOrigin-Name: ac98b23b34632fbc654a34a8b3d842ce65603e4c04d89c589b46f4d48a61152d
2019-04-02 13:10:50 +00:00
drh 860d2b08c6 Make sure the MEM_FromBind bit inthe Mem.flags field is not included in
the MEM_TypeMask.  This critical changes was omitted from the previous two
check-ins by mistake, and so those check-ins are not fully functional.

FossilOrigin-Name: f7ba2daf91c96ba16958188d6084a0ff129310d348932de493d326f1d24679cd
2019-04-02 00:56:20 +00:00
drh e8975ac9e1 Add new APIs to the extension loading mechanism.
FossilOrigin-Name: 6f122faf8a34b986e58ba4622cff918c6d133d6f91d4b723b50bd086d5bed8e1
2019-04-02 00:48:29 +00:00
drh 29ddbbbf36 Add the sqlite3_value_frombind() interface. Use that interface to
improve fts3_tokenizer().

FossilOrigin-Name: b3f2c3205a28dc21ea7080e5e1ba246ce9c9b90c1309262ca11d8e40943ed677
2019-04-02 00:28:54 +00:00
drh d6db6598ca Improvements to the sqlite3ExprImpliesNonNullRow() theorem prover.
FossilOrigin-Name: 3fde627616030ca0de87169467e2e453fdc91154942e3a3a92a221df5923b2d2
2019-04-01 19:42:42 +00:00
dan afb3f3c72c Add a test case to cover a missed VDBE branch generated by window.c.
FossilOrigin-Name: b36813d6467c82159bd3bb69d34ac28fc161a13052ca67d7cf9ad75e2aaea9d5
2019-04-01 18:43:09 +00:00
dan 1d07f1d8c7 If the library is built with SQLITE_VDBE_COVERAGE defined, have the Tcl tests generate a vdbe coverage report in file testdir/vdbe_coverage.txt.
FossilOrigin-Name: f0ed714637bf30443d0551d9b6fececa00fc9dfe9669fe720c4598ef71c61e2c
2019-04-01 17:24:20 +00:00
drh 495ed62e85 Frame range comparisons can never be NULL because the values will have
been checked for NULL prior to the test.

FossilOrigin-Name: fa37cf9a6aa3e4325674cb6af68f617d25e349c3f694d0117a19a36fc42daf15
2019-04-01 16:23:21 +00:00
drh 83c5bb997a Mark rowid-comparison opcodes as never-null for VDBE coverage tracking
purposes.

FossilOrigin-Name: a69bb4f257500e40ef4056d5628ef25266def5bcef07eebdb471a79fffe80237
2019-04-01 15:55:38 +00:00
drh 21826f44bf Improved VDBE branch coverage in the run-time frame-spec error detection
logic of window functions.

FossilOrigin-Name: f56d305a7bad6608d51d8c8cef417ddb66cff50f0a75d28554ea669e47f3d90d
2019-04-01 14:30:30 +00:00
drh c906533650 Improved comments on the VDBE branch coverage testing logic. Fix the
VDBE branch coverage measurement on the OP_MustBeInt opcode.

FossilOrigin-Name: 8681750e855a020ee374cb9f973f701a72068e33f97d0101a4fab3a228e5ebda
2019-04-01 14:01:21 +00:00
drh 6cbbcd8ad6 Fix a defect in the VDBE branch coverage testing logic.
FossilOrigin-Name: 1fcf3307d37f0e8e0c8c54491c609b73c7add6eaa38409a41c7cd6614a877a19
2019-04-01 13:06:19 +00:00
mistachkin 4e2d3d40dc Fix harmless compiler warnings seen with MSVC.
FossilOrigin-Name: 6cf8b18ec20f11c25ff7396f29c742404d3a88d5e97a5fd53ccfaff51dec3f33
2019-04-01 03:07:21 +00:00
drh 8fe25c64f1 Early detection of too many columns in an index avoid a possible 16-bit
signed integer overflow.

FossilOrigin-Name: 8af0caeb6d1e55f66ad2f12af94845dccfe1d0420faf326f5917fc07f8aa6050
2019-03-31 21:09:33 +00:00
drh ce5752cd1f Add some missing VdbeCoverage() macros.
FossilOrigin-Name: d03b611302f68483770d49b113b4ed685ba03526d2007647c306f8ec7ae697d2
2019-03-31 18:17:00 +00:00
drh 3fc6042992 Improvements to VdbeCoverage macros.
FossilOrigin-Name: 10ee9e337e5f8a846dc827f6deb07930a790ac9d290b62f73de59454e465d5a1
2019-03-30 20:43:40 +00:00
drh 6f88359df6 Fix issues with the previous check-in and add more VDBE branch coverage
testing macros.

FossilOrigin-Name: b5f72f10f2dfdbee9fe98c63ffb933e841203790746a920b99df14ca5c14127c
2019-03-30 20:37:04 +00:00
drh bf00f6d7ec Enhanced VdbeCoverage() macros in the new windows function code.
FossilOrigin-Name: f24066f8dd847dfb656f26c4a8142e7fb6a412ffe325aea6254cb122cfbb3e1c
2019-03-30 20:10:11 +00:00
drh b336d1ab83 Add a call to sqlite3FaultSim(410) inside of btreeRestoreCursorPosition()
to simplify testing of error scenarios.

FossilOrigin-Name: bb643bac535ac7d5fb4c13edb8782cd13540bbc7d2b2deb689f4ca8d1914f422
2019-03-30 19:17:35 +00:00
drh 119e1ffc5e The defragmentPage() routine detects corruption in the first-free-slot fields
at offset 1 in the header and throws an error, rather than asserting.

FossilOrigin-Name: fb125bd338ab32b33d02fe61b76497b6d4a2a160056d6e759e15c94903e61a41
2019-03-30 18:39:13 +00:00
drh 2c794b15a0 Add the blobio.c extension module implementing readblob() and writeblob().
Experimental.

FossilOrigin-Name: e3fde56da46e9592143b8beeee5eba4d74b8ef67edb7bf73a85edd2e0f7a8d21
2019-03-30 17:30:50 +00:00
dan 0708054570 Add an extra IO-error test to windowfault.test.
FossilOrigin-Name: 5b8c44cd39c529e8adbc51f67088409e963515b988868856120a59e6c7160210
2019-03-30 17:07:23 +00:00
drh 038ebf6875 Remove the unused P5 flag from the OP_Rewind opcode.
FossilOrigin-Name: c2edbf3b8c643edcd5823eb907fd7531cf5be8a8b6a014fa1b123eb0ea3231cf
2019-03-29 15:21:22 +00:00
dan 3580843595 Fix a fairly obscure problem causing the planner to sometimes choose sub-optimal plans for a query with a single virtual table in the FROM clause, and at least one IN(...) constraint in the WHERE clause.
FossilOrigin-Name: f5752517f590b37bfc0267650f5800320e22a8ecaba34aa6893281ce8d268026
2019-03-29 13:17:50 +00:00
drh a920b209ff Fix typos in the comments of the sessions extension, one of which affects
the generated documentation. No code changes.

FossilOrigin-Name: 040d5d515bcb37bea05e0d156dbaf066c68052ac574f1b0b2cb118d473a353e0
2019-03-29 11:48:10 +00:00
67 changed files with 3742 additions and 327 deletions
+5 -6
View File
@@ -422,6 +422,7 @@ TESTSRC = \
$(TOP)/src/test_tclsh.c \
$(TOP)/src/test_tclvar.c \
$(TOP)/src/test_thread.c \
$(TOP)/src/test_vdbecov.c \
$(TOP)/src/test_vfs.c \
$(TOP)/src/test_windirent.c \
$(TOP)/src/test_window.c \
@@ -1050,12 +1051,9 @@ opcodes.h: parse.h $(TOP)/src/vdbe.c $(TOP)/tool/mkopcodeh.tcl
#
parse.h: parse.c
parse.c: $(TOP)/src/parse.y lemon$(BEXE) $(TOP)/tool/addopcodes.tcl
parse.c: $(TOP)/src/parse.y lemon$(BEXE)
cp $(TOP)/src/parse.y .
rm -f parse.h
./lemon$(BEXE) $(OPT_FEATURE_FLAGS) $(OPTS) parse.y
mv parse.h parse.h.temp
$(TCLSH_CMD) $(TOP)/tool/addopcodes.tcl parse.h.temp >parse.h
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest mksourceid$(BEXE) $(TOP)/VERSION
$(TCLSH_CMD) $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
@@ -1374,8 +1372,9 @@ loadfts$(EXE): $(TOP)/tool/loadfts.c libsqlite3.la
# releasetest.tcl script.
#
VALIDIDS=' sqlite3(changeset|changegroup|session)?_'
checksymbols: sqlite3.lo
nm -g --defined-only sqlite3.lo | egrep -v $(VALIDIDS); test $$? -ne 0
checksymbols: sqlite3.o
nm -g --defined-only sqlite3.o
nm -g --defined-only sqlite3.o | egrep -v $(VALIDIDS); test $$? -ne 0
echo '0 errors out of 1 tests'
# Build the amalgamation-autoconf package. The amalamgation-tarball target builds
+3 -3
View File
@@ -1517,6 +1517,7 @@ TESTSRC = \
$(TOP)\src\test_tclsh.c \
$(TOP)\src\test_tclvar.c \
$(TOP)\src\test_thread.c \
$(TOP)\src\test_vdbecov.c \
$(TOP)\src\test_vfs.c \
$(TOP)\src\test_windirent.c \
$(TOP)\src\test_window.c \
@@ -2138,12 +2139,10 @@ opcodes.h: parse.h $(TOP)\src\vdbe.c $(TOP)\tool\mkopcodeh.tcl
#
parse.h: parse.c
parse.c: $(TOP)\src\parse.y lemon.exe $(TOP)\tool\addopcodes.tcl
parse.c: $(TOP)\src\parse.y lemon.exe
del /Q parse.y parse.h parse.h.temp 2>NUL
copy $(TOP)\src\parse.y .
.\lemon.exe $(REQ_FEATURE_FLAGS) $(OPT_FEATURE_FLAGS) $(EXT_FEATURE_FLAGS) $(OPTS) parse.y
move parse.h parse.h.temp
$(TCLSH_CMD) $(TOP)\tool\addopcodes.tcl parse.h.temp > parse.h
$(SQLITE3H): $(TOP)\src\sqlite.h.in $(TOP)\manifest mksourceid.exe $(TOP)\VERSION
$(TCLSH_CMD) $(TOP)\tool\mksqlite3h.tcl $(TOP:\=/) > $(SQLITE3H) $(MKSQLITE3H_ARGS)
@@ -2560,6 +2559,7 @@ clean:
del /Q .target_source 2>NUL
del /Q tclsqlite3.exe $(SQLITETCLH) $(SQLITETCLDECLSH) 2>NUL
del /Q lsm.dll lsmtest.exe 2>NUL
del /Q atrc.exe changesetfuzz.exe dbtotxt.exe index_usage.exe 2>NUL
del /Q testloadext.dll 2>NUL
del /Q testfixture.exe test.db 2>NUL
del /Q LogEst.exe fts3view.exe rollback-test.exe showdb.exe dbdump.exe 2>NUL
+1 -4
View File
@@ -175,11 +175,8 @@ the src/parse.y file. The conversion of "parse.y" into "parse.c" is done
by the [lemon](./doc/lemon.html) LALR(1) parser generator. The source code
for lemon is at tool/lemon.c. Lemon uses the tool/lempar.c file as a
template for generating its parser.
Lemon also generates the **parse.h** header file, at the same time it
generates parse.c. But the parse.h header file is
modified further (to add additional symbols) using the ./addopcodes.tcl
Tcl script.
generates parse.c.
The **opcodes.h** header file contains macros that define the numbers
corresponding to opcodes in the "VDBE" virtual machine. The opcodes.h
+2 -2
View File
@@ -2643,8 +2643,8 @@ static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){
}else{
int res = fts5BufferCompare(&p1->term, &p2->term);
if( res==0 ){
assert( i2>i1 );
assert( i2!=0 );
assert_nc( i2>i1 );
assert_nc( i2!=0 );
pRes->bTermEq = 1;
if( p1->iRowid==p2->iRowid ){
p1->bDel = p2->bDel;
+119
View File
@@ -7999,6 +7999,125 @@ do_catchsql_test 56.1 {
INSERT INTO t1(b) VALUES(randomblob(250));
} {1 {database disk image is malformed}}
#-------------------------------------------------------------------------
reset_db
do_test 57.0 {
sqlite3 db {}
db deserialize [decode_hexdb {
| size 28672 pagesize 4096 filename x.db
| page 1 offset 0
| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
| 16: 10 00 01 01 00 40 20 20 00 00 00 01 00 00 00 07 .....@ ........
| 32: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
| 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 ................
| 96: 00 2e 34 20 0d 00 00 00 07 0d d2 00 0f c4 0f 6d ..4 ...........m
| 112: 0f 02 0e ab 0e 4e 0d f6 0d d2 00 00 00 00 00 00 .....N..........
| 3536: 00 00 22 07 06 17 11 11 01 31 74 61 62 6c 65 74 .........1tablet
| 3552: 32 74 32 07 43 52 45 41 54 45 20 54 41 42 4c 45 2t2.CREATE TABLE
| 3568: 20 74 32 28 78 29 56 06 06 17 1f 1f 01 7d 74 61 t2(x)V.......ta
| 3584: 61 6b 65 74 31 5f 63 6f 6e 66 69 67 74 31 5f 63 aket1_configt1_c
| 3600: 6f 7e 66 69 67 06 43 52 45 41 54 45 20 54 41 42 o~fig.CREATE TAB
| 3616: 4c 45 20 27 74 31 5f 63 6f 6e 66 69 67 27 28 6b LE 't1_config'(k
| 3632: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 76 29 PRIMARY KEY, v)
| 3648: 20 57 49 54 48 4f 55 54 20 52 4f 57 49 44 5b 05 WITHOUT ROWID[.
| 3664: 07 17 21 21 01 81 01 74 61 62 6c 65 74 31 5f 64 ..!!...tablet1_d
| 3680: 6f 63 73 69 7a 65 74 31 5f 64 6f 63 73 69 7a 65 ocsizet1_docsize
| 3696: 05 43 52 45 41 54 45 20 54 41 42 4c 45 20 27 74 .CREATE TABLE 't
| 3712: 31 5f 64 6f 63 73 69 7a 65 27 28 69 64 20 49 4e 1_docsize'(id IN
| 3728: 54 45 47 45 52 20 50 52 49 4d 41 52 59 20 4b 45 TEGER PRIMARY KE
| 3744: 59 2c 20 73 7a 20 42 4c 4f 42 29 55 04 06 17 21 Y, sz BLOB)U...!
| 3760: 21 01 77 74 61 62 6c 65 74 31 5f 63 6f 6e 74 1d !.wtablet1_cont.
| 3776: 6e 74 74 31 5f 63 6f 6e 74 65 6e 74 04 43 52 45 ntt1_content.CRE
| 3792: 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 63 6f ATE TABLE 't1_co
| 3808: 6e 74 65 6e 74 27 28 69 64 20 49 4e 54 45 47 45 ntent'(id INTEGE
| 3824: 52 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 63 R PRIMARY KEY, c
| 3840: 30 29 69 03 07 17 19 19 01 81 2d 74 61 62 6c 65 0)i.......-table
| 3856: 74 31 5f 69 64 78 74 31 5f 59 64 78 03 43 52 45 t1_idxt1_Ydx.CRE
| 3872: 41 54 45 20 54 41 42 4c 45 20 27 74 31 5f 69 64 ATE TABLE 't1_id
| 3888: 78 27 28 73 65 67 69 64 2c 20 74 65 72 6d 2c 20 x'(segid, term,
| 3904: 70 67 6e 6f 2c 20 50 52 49 4d 41 52 59 20 4b 45 pgno, PRIMARY KE
| 3920: 59 28 73 65 67 69 64 2c 20 74 65 72 6d 29 29 20 Y(segid, term))
| 3936: 57 49 54 48 4f 55 54 20 52 4f 57 49 44 55 02 07 WITHOUT ROWIDU..
| 3952: 17 1b 1b 01 81 01 74 61 62 6c 65 74 31 5f 64 61 ......tablet1_da
| 3968: 74 61 74 31 5f 64 61 64 61 02 43 52 45 41 54 45 tat1_dada.CREATE
| 3984: 20 54 41 42 4c 45 20 27 74 31 5f 64 61 74 61 27 TABLE 't1_data'
| 4000: 28 69 64 20 49 4e 54 45 47 45 52 20 50 52 49 4d (id INTEGER PRIM
| 4016: 41 52 59 20 4b 45 59 2c 20 62 6c 6f 63 6b 20 42 ARY KEY, block B
| 4032: 4c 4f 42 29 3a 01 06 17 11 11 08 63 74 61 62 6c LOB):......ctabl
| 4048: 65 74 31 74 31 43 52 45 41 54 45 20 56 49 52 54 et1t1CREATE VIRT
| 4064: 55 41 4c 20 54 41 42 4c 45 20 74 31 20 55 53 49 UAL TABLE t1 USI
| 4080: 4e 47 20 66 74 73 35 28 63 6f 6e 74 65 6e 74 29 NG fts5(content)
| page 2 offset 4096
| 0: 0d 0e b4 00 06 0e 35 00 0f e8 0e 35 0f bd 0f 4e ......5....5...N
| 16: 0e cb 0e 4f 00 00 00 00 00 00 00 00 00 00 00 00 ...O............
| 3632: 00 00 00 00 00 18 0a 03 00 36 00 00 00 00 01 04 .........6......
| 3648: 04 00 04 01 01 01 02 01 01 03 01 01 04 01 01 5e ...............^
| 3664: 90 80 80 80 80 01 04 00 81 40 00 00 00 51 06 30 .........@...Q.0
| 3680: 61 62 61 63 6b 01 01 04 04 6e 64 6f 6e 01 01 02 aback....ndon...
| 3696: 04 63 69 76 65 01 01 02 04 6c 70 68 61 01 01 02 .cive....lpha...
| 3712: 03 74 6f 6d 01 01 01 06 62 61 63 6b 75 70 01 01 .tom....backup..
| 3728: 02 05 6f 6f 6d 65 72 01 01 01 06 63 68 61 6e 6e ..oomer....chann
| 3744: 65 01 01 01 04 74 65 73 74 01 01 04 09 08 08 08 e....test.......
| 3760: 07 0a 09 0a 0f 3a 00 17 30 00 00 00 00 01 03 03 .....:..0.......
| 3776: 00 03 01 01 01 02 01 01 03 01 01 68 8c 80 80 80 ...........h....
| 3792: 80 01 04 00 81 54 00 00 00 5b 06 30 61 62 61 63 .....T...[.0abac
| 3808: 6b 02 02 07 04 04 6e 64 6f 6e 02 02 05 02 04 63 k.....ndon.....c
| 3824: 69 76 65 02 02 0b 02 04 6c 70 68 61 02 04 02 0a ive.....lpha....
| 3840: 02 03 74 6f 6d 02 02 09 01 06 62 61 63 6b 75 70 ..tom.....backup
| 3856: 02 02 04 02 05 6f 6f 6d 65 72 02 02 08 01 06 63 .....oomer.....c
| 3872: 68 61 6e 6e 65 02 02 03 01 04 74 65 73 74 02 02 hanne.....test..
| 3888: 06 04 0a 09 09 0a 08 0b 0a 0b 0f ef 00 14 2a 00 ..............*.
| 3904: 00 00 00 01 02 02 00 02 01 01 01 02 01 01 68 88 ..............h.
| 3920: 80 80 80 80 01 04 00 81 54 00 00 00 5b 06 30 61 ........T...[.0a
| 3936: 62 61 63 6b 01 02 07 04 04 6e 64 6f 6e 01 02 05 back.....ndon...
| 3952: 02 04 63 69 76 65 01 02 0b 02 04 6c 70 68 61 01 ..cive.....lpha.
| 3968: 04 02 0a 02 03 74 6f 6d 01 02 09 01 06 62 61 63 .....tom.....bac
| 3984: 6b 75 70 01 02 04 02 05 6f 6f 6d 65 72 01 02 08 kup.....oomer...
| 4000: 01 06 63 68 61 6e 6e 65 01 02 03 01 04 74 65 73 ..channe.....tes
| 4016: 74 01 02 06 04 0a 09 09 0a 08 0b 0a 0b 24 84 80 t............$..
| 4032: 80 80 80 01 03 00 4e 00 00 00 1e 06 30 61 62 61 ......N.....0aba
| 4048: 63 6b 01 02 02 05 42 66 74 02 02 02 04 04 6e 64 ck....Bft.....nd
| 4064: 6f 6e 03 02 02 04 0a 07 05 01 03 00 10 04 0d 00 on..............
| 4080: 00 00 11 24 00 00 00 00 01 01 01 00 01 01 01 01 ...$............
| page 3 offset 8192
| 0: 0a 00 00 00 04 0f e5 00 00 00 0f f3 0f ec 0f e5 ................
| 4064: 00 00 00 00 00 06 04 01 0c 01 04 02 06 04 01 0c ................
| 4080: 01 03 02 06 04 01 0c 01 02 02 05 04 09 0d 01 02 ................
| page 4 offset 12288
| 0: 0d 0e bc 00 04 0e 78 00 00 00 00 00 00 00 0e 78 ......x........x
| 16: 0e 78 00 00 00 00 00 00 00 00 00 00 00 00 00 00 .x..............
| 3696: 00 00 00 00 00 00 00 00 42 02 04 00 81 09 61 6c ........B.....al
| 3712: 70 68 61 20 63 68 61 6e 6e 65 20 62 61 63 6b 75 pha channe backu
| 3728: 70 20 61 62 61 6e 64 6f 6e 20 74 65 73 74 20 61 p abandon test a
| 3744: 62 61 63 6b 20 62 6f 6f 6d 65 72 20 61 74 6f 6d back boomer atom
| 3760: 20 61 6c 70 68 61 20 61 63 69 76 65 00 00 00 44 alpha acive...D
| 3776: 81 09 61 6c 70 68 61 20 63 68 61 6e 6e 65 20 62 ..alpha channe b
| 3792: 61 63 6b 75 70 20 61 62 61 6e 64 6f 6e 20 74 65 ackup abandon te
| 3808: 73 74 20 61 62 61 63 6b 20 62 6f 6f 6d 65 72 20 st aback boomer
| 3824: 61 74 6f 6d 20 61 6c 70 68 61 20 61 63 69 76 65 atom alpha acive
| 4064: 0a 03 03 00 1b 61 4e 61 6e 64 6f 6e 08 02 03 00 .....aNandon....
| 4080: 17 61 62 61 66 74 08 01 03 00 17 61 62 71 63 6b .abaft.....abqck
| page 5 offset 16384
| 0: 0d 0f e8 00 04 0f e2 00 00 00 00 00 00 00 0f e2 ................
| 16: 0f e2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
| 4064: 00 00 04 02 03 00 0e 0a 00 00 00 06 0e 0a 04 03 ................
| 4080: 03 00 0e 01 04 02 03 00 0e 01 04 01 03 10 0e 01 ................
| page 6 offset 20480
| 0: 0a 00 00 00 01 0f f4 00 0f f4 00 00 00 00 00 00 ................
| 4080: 00 00 00 00 0b 03 1b 01 76 65 72 73 69 6f 6e 04 ........version.
| page 7 offset 24576
| 0: 0d 00 00 00 03 0f d6 00 0f f4 00 00 00 00 00 00 ................
| 4048: 00 00 00 00 00 00 09 03 02 1b 72 65 62 75 69 6c ..........rebuil
| 4064: 64 11 02 02 2b 69 6e 74 65 67 72 69 74 79 2d 63 d...+integrity-c
| 4080: 68 65 63 6b 0a 01 02 1d 6f 70 74 69 6d 69 7a 65 heck....optimize
| end x.db
}]} {}
do_catchsql_test 57.1 {
INSERT INTO t1(t1) VALUES('optimize')
} {1 {database disk image is malformed}}
sqlite3_fts5_may_be_corrupt 0
finish_test
+152
View File
@@ -0,0 +1,152 @@
/*
** 2019-03-30
**
** 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.
**
******************************************************************************
**
** An SQL function that uses the incremental BLOB I/O mechanism of SQLite
** to read or write part of a blob. This is intended for debugging use
** in the CLI.
**
** readblob(SCHEMA,TABLE,COLUMN,ROWID,OFFSET,N)
**
** Returns N bytes of the blob starting at OFFSET.
**
** writeblob(SCHEMA,TABLE,COLUMN,ROWID,OFFSET,NEWDATA)
**
** NEWDATA must be a blob. The content of NEWDATA overwrites the
** existing BLOB data at SCHEMA.TABLE.COLUMN for row ROWID beginning
** at OFFSET bytes into the blob.
*/
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#include <assert.h>
#include <string.h>
static void readblobFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
sqlite3_blob *pBlob = 0;
const char *zSchema;
const char *zTable;
const char *zColumn;
sqlite3_int64 iRowid;
int iOfst;
unsigned char *aData;
int nData;
sqlite3 *db;
int rc;
zSchema = (const char*)sqlite3_value_text(argv[0]);
zTable = (const char*)sqlite3_value_text(argv[1]);
if( zTable==0 ){
sqlite3_result_error(context, "bad table name", -1);
return;
}
zColumn = (const char*)sqlite3_value_text(argv[2]);
if( zTable==0 ){
sqlite3_result_error(context, "bad column name", -1);
return;
}
iRowid = sqlite3_value_int64(argv[3]);
iOfst = sqlite3_value_int(argv[4]);
nData = sqlite3_value_int(argv[5]);
if( nData<=0 ) return;
aData = sqlite3_malloc64( nData+1 );
if( aData==0 ){
sqlite3_result_error_nomem(context);
return;
}
db = sqlite3_context_db_handle(context);
rc = sqlite3_blob_open(db, zSchema, zTable, zColumn, iRowid, 0, &pBlob);
if( rc ){
sqlite3_free(aData);
sqlite3_result_error(context, "cannot open BLOB pointer", -1);
return;
}
rc = sqlite3_blob_read(pBlob, aData, nData, iOfst);
sqlite3_blob_close(pBlob);
if( rc ){
sqlite3_free(aData);
sqlite3_result_error(context, "BLOB write failed", -1);
}else{
sqlite3_result_blob(context, aData, nData, sqlite3_free);
}
}
static void writeblobFunc(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
sqlite3_blob *pBlob = 0;
const char *zSchema;
const char *zTable;
const char *zColumn;
sqlite3_int64 iRowid;
int iOfst;
unsigned char *aData;
int nData;
sqlite3 *db;
int rc;
zSchema = (const char*)sqlite3_value_text(argv[0]);
zTable = (const char*)sqlite3_value_text(argv[1]);
if( zTable==0 ){
sqlite3_result_error(context, "bad table name", -1);
return;
}
zColumn = (const char*)sqlite3_value_text(argv[2]);
if( zTable==0 ){
sqlite3_result_error(context, "bad column name", -1);
return;
}
iRowid = sqlite3_value_int64(argv[3]);
iOfst = sqlite3_value_int(argv[4]);
if( sqlite3_value_type(argv[5])!=SQLITE_BLOB ){
sqlite3_result_error(context, "6th argument must be a BLOB", -1);
return;
}
nData = sqlite3_value_bytes(argv[5]);
aData = (unsigned char *)sqlite3_value_blob(argv[5]);
db = sqlite3_context_db_handle(context);
rc = sqlite3_blob_open(db, zSchema, zTable, zColumn, iRowid, 1, &pBlob);
if( rc ){
sqlite3_result_error(context, "cannot open BLOB pointer", -1);
return;
}
rc = sqlite3_blob_write(pBlob, aData, nData, iOfst);
sqlite3_blob_close(pBlob);
if( rc ){
sqlite3_result_error(context, "BLOB write failed", -1);
}
}
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_blobio_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
(void)pzErrMsg; /* Unused parameter */
rc = sqlite3_create_function(db, "readblob", 6, SQLITE_UTF8, 0,
readblobFunc, 0, 0);
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "writeblob", 6, SQLITE_UTF8, 0,
writeblobFunc, 0, 0);
}
return rc;
}
+86
View File
@@ -0,0 +1,86 @@
# 2019 April 11
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
#
source [file join [file dirname [info script]] rbu_common.tcl]
set ::testprefix rbupartial
db close
sqlite3_shutdown
sqlite3_config_uri 1
foreach {tn without_rowid a b c d} {
1 "" a b c d
2 "WITHOUT ROWID" aaa bbb ccc ddd
3 "WITHOUT ROWID" "\"hello\"" {"one'two"} {[c]} ddd
4 "WITHOUT ROWID" {`a b`} {"one'two"} {[c c c]} ddd
5 "" a b c {"d""d"}
6 "" {'one''two'} b {"c""c"} {"d""d"}
} {
eval [string map [list \
%WITHOUT_ROWID% $without_rowid %A% $a %B% $b %C% $c %D% $d
] {
reset_db
do_execsql_test $tn.1.0 {
CREATE TABLE t1(%A% PRIMARY KEY, %B%, %C%, %D%) %WITHOUT_ROWID% ;
CREATE INDEX i1b ON t1(%B%);
CREATE INDEX i1b2 ON t1(%B%) WHERE %C%<5;
CREATE INDEX i1b3 ON t1(%B%) WHERE %C%>=5;
CREATE INDEX i1c ON t1(%C%);
CREATE INDEX i1c2 ON t1(%C%) WHERE %C% IS NULL;
CREATE INDEX i1c3 ON t1(%C%) WHERE %C% IS NOT NULL;
CREATE INDEX i1c4 ON t1(%C%) WHERE %D% < 'd';
}
do_execsql_test $tn.1.1 {
INSERT INTO t1 VALUES(0, NULL, NULL, 'a');
INSERT INTO t1 VALUES(1, 2, 3, 'b');
INSERT INTO t1 VALUES(4, 5, 6, 'c');
INSERT INTO t1 VALUES(7, 8, 9, 'd');
}
forcedelete rbu.db
do_test $tn.1.2 {
sqlite3 rbu rbu.db
rbu eval {
CREATE TABLE data_t1(%A%, %B%, %C%, %D%, rbu_control);
INSERT INTO data_t1 VALUES(10, 11, 12, 'e', 0);
INSERT INTO data_t1 VALUES(13, 14, NULL, 'f', 0);
INSERT INTO data_t1 VALUES(0, NULL, NULL, NULL, 1);
INSERT INTO data_t1 VALUES(4, NULL, NULL, NULL, 1);
INSERT INTO data_t1 VALUES(7, NULL, 4, NULL, '..x.');
INSERT INTO data_t1 VALUES(1, 10, NULL, NULL, '.xx.');
}
rbu close
} {}
do_test $tn.1.3 {
run_rbu test.db rbu.db
execsql { PRAGMA integrity_check }
} {ok}
do_execsql_test $tn.1.4 {
SELECT * FROM t1 ORDER BY %A%;
} {
1 10 {} b 7 8 4 d 10 11 12 e 13 14 {} f
}
set step 0
do_rbu_vacuum_test $tn.1.5 0
}]
}
finish_test
+77 -7
View File
@@ -240,6 +240,11 @@ struct RbuUpdateStmt {
** it points to an array of flags nTblCol elements in size. The flag is
** set for each column that is either a part of the PK or a part of an
** index. Or clear otherwise.
**
** If there are one or more partial indexes on the table, all fields of
** this array set set to 1. This is because in that case, the module has
** no way to tell which fields will be required to add and remove entries
** from the partial indexes.
**
*/
struct RbuObjIter {
@@ -1250,8 +1255,12 @@ static void rbuObjIterCacheIndexedCols(sqlite3rbu *p, RbuObjIter *pIter){
pIter->nIndex = 0;
while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pList) ){
const char *zIdx = (const char*)sqlite3_column_text(pList, 1);
int bPartial = sqlite3_column_int(pList, 4);
sqlite3_stmt *pXInfo = 0;
if( zIdx==0 ) break;
if( bPartial ){
memset(pIter->abIndexed, 0x01, sizeof(u8)*pIter->nTblCol);
}
p->rc = prepareFreeAndCollectError(p->dbMain, &pXInfo, &p->zErrmsg,
sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx)
);
@@ -1958,6 +1967,62 @@ static void rbuTmpInsertFunc(
}
}
static char *rbuObjIterGetIndexWhere(sqlite3rbu *p, RbuObjIter *pIter){
sqlite3_stmt *pStmt = 0;
int rc = p->rc;
char *zRet = 0;
if( rc==SQLITE_OK ){
rc = prepareAndCollectError(p->dbMain, &pStmt, &p->zErrmsg,
"SELECT trim(sql) FROM sqlite_master WHERE type='index' AND name=?"
);
}
if( rc==SQLITE_OK ){
int rc2;
rc = sqlite3_bind_text(pStmt, 1, pIter->zIdx, -1, SQLITE_STATIC);
if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
const char *zSql = (const char*)sqlite3_column_text(pStmt, 0);
if( zSql ){
int nParen = 0; /* Number of open parenthesis */
int i;
for(i=0; zSql[i]; i++){
char c = zSql[i];
if( c=='(' ){
nParen++;
}
else if( c==')' ){
nParen--;
if( nParen==0 ){
i++;
break;
}
}else if( c=='"' || c=='\'' || c=='`' ){
for(i++; 1; i++){
if( zSql[i]==c ){
if( zSql[i+1]!=c ) break;
i++;
}
}
}else if( c=='[' ){
for(i++; 1; i++){
if( zSql[i]==']' ) break;
}
}
}
if( zSql[i] ){
zRet = rbuStrndup(&zSql[i], &rc);
}
}
}
rc2 = sqlite3_finalize(pStmt);
if( rc==SQLITE_OK ) rc = rc2;
}
p->rc = rc;
return zRet;
}
/*
** Ensure that the SQLite statement handles required to update the
** target database object currently indicated by the iterator passed
@@ -1987,6 +2052,7 @@ static int rbuObjIterPrepareAll(
char *zImposterPK = 0; /* Primary key declaration for imposter */
char *zWhere = 0; /* WHERE clause on PK columns */
char *zBind = 0;
char *zPart = 0;
int nBind = 0;
assert( pIter->eType!=RBU_PK_VTAB );
@@ -1994,6 +2060,7 @@ static int rbuObjIterPrepareAll(
p, pIter, &zImposterCols, &zImposterPK, &zWhere, &nBind
);
zBind = rbuObjIterGetBindlist(p, nBind);
zPart = rbuObjIterGetIndexWhere(p, pIter);
/* Create the imposter table used to write to this index. */
sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->dbMain, "main", 0, 1);
@@ -2026,28 +2093,30 @@ static int rbuObjIterPrepareAll(
char *zSql;
if( rbuIsVacuum(p) ){
zSql = sqlite3_mprintf(
"SELECT %s, 0 AS rbu_control FROM '%q' ORDER BY %s%s",
"SELECT %s, 0 AS rbu_control FROM '%q' %s ORDER BY %s%s",
zCollist,
pIter->zDataTbl,
zCollist, zLimit
zPart, zCollist, zLimit
);
}else
if( pIter->eType==RBU_PK_EXTERNAL || pIter->eType==RBU_PK_NONE ){
zSql = sqlite3_mprintf(
"SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' ORDER BY %s%s",
"SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' %s ORDER BY %s%s",
zCollist, p->zStateDb, pIter->zDataTbl,
zCollist, zLimit
zPart, zCollist, zLimit
);
}else{
zSql = sqlite3_mprintf(
"SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' "
"SELECT %s, rbu_control FROM %s.'rbu_tmp_%q' %s "
"UNION ALL "
"SELECT %s, rbu_control FROM '%q' "
"WHERE typeof(rbu_control)='integer' AND rbu_control!=1 "
"%s %s typeof(rbu_control)='integer' AND rbu_control!=1 "
"ORDER BY %s%s",
zCollist, p->zStateDb, pIter->zDataTbl,
zCollist, p->zStateDb, pIter->zDataTbl, zPart,
zCollist, pIter->zDataTbl,
zPart,
(zPart ? "AND" : "WHERE"),
zCollist, zLimit
);
}
@@ -2058,6 +2127,7 @@ static int rbuObjIterPrepareAll(
sqlite3_free(zImposterPK);
sqlite3_free(zWhere);
sqlite3_free(zBind);
sqlite3_free(zPart);
}else{
int bRbuRowid = (pIter->eType==RBU_PK_VTAB)
||(pIter->eType==RBU_PK_NONE)
+11 -12
View File
@@ -154,17 +154,18 @@ static void fuzzReadFile(const char *zFilename, int *pSz, void **ppBuf){
pBuf = sqlite3_malloc64( sz ? sz : 1 );
if( pBuf==0 ){
fprintf(stderr, "cannot allocate %d to hold content of \"%s\"\n",
sz, zFilename);
(int)sz, zFilename);
exit(1);
}
if( sz>0 ){
if( fread(pBuf, sz, 1, f)!=1 ){
fprintf(stderr, "cannot read all %d bytes of \"%s\"\n", sz, zFilename);
if( fread(pBuf, (size_t)sz, 1, f)!=1 ){
fprintf(stderr, "cannot read all %d bytes of \"%s\"\n",
(int)sz, zFilename);
exit(1);
}
fclose(f);
}
*pSz = sz;
*pSz = (int)sz;
*ppBuf = pBuf;
}
@@ -343,7 +344,7 @@ struct FuzzChange {
static void *fuzzMalloc(sqlite3_int64 nByte){
void *pRet = sqlite3_malloc64(nByte);
if( pRet ){
memset(pRet, 0, nByte);
memset(pRet, 0, (size_t)nByte);
}
return pRet;
}
@@ -384,7 +385,7 @@ static int fuzzGetVarint(u8 *p, int *pnVal){
static int fuzzPutVarint(u8 *p, int nVal){
assert( nVal>0 && nVal<2097152 );
if( nVal<128 ){
p[0] = nVal;
p[0] = (u8)nVal;
return 1;
}
if( nVal<16384 ){
@@ -459,7 +460,7 @@ static int fuzzParseHeader(
pGrp->aPK = p;
p += pGrp->nCol;
pGrp->zTab = (const char*)p;
p = &p[strlen(p)+1];
p = &p[strlen((const char*)p)+1];
if( p>=pEnd ){
rc = fuzzCorrupt();
@@ -695,8 +696,6 @@ static int fuzzPrintRecord(FuzzChangesetGroup *pGrp, u8 **ppRec, int bPKOnly){
case 0x03: /* text */
case 0x04: { /* blob */
int nTxt;
int sz;
int i;
p += fuzzGetVarint(p, &nTxt);
printf("%s%s", zPre, eType==0x03 ? "'" : "X'");
for(i=0; i<nTxt; i++){
@@ -859,7 +858,7 @@ static int fuzzSelectChange(FuzzChangeset *pParse, FuzzChange *pChange){
case 0x03: /* text */
case 0x04: { /* blob */
int nByte = fuzzRandomInt(48);
pChange->aSub[1] = nByte;
pChange->aSub[1] = (u8)nByte;
fuzzRandomBlob(nByte, &pChange->aSub[2]);
if( pChange->aSub[0]==0x03 ){
int i;
@@ -1004,7 +1003,7 @@ static int fuzzCopyChange(
}else if( p==pFuzz->pSub2 ){
pCopy = pFuzz->pSub1;
}else if( i==iUndef ){
pCopy = "\0";
pCopy = (u8*)"\0";
}
if( pCopy[0]==0x00 && eNew!=eType && eType==SQLITE_UPDATE && iRec==0 ){
@@ -1067,7 +1066,7 @@ static int fuzzCopyChange(
for(i=0; i<pGrp->nCol; i++){
int sz;
u8 *pCopy = pCsr;
if( pGrp->aPK[i] ) pCopy = "\0";
if( pGrp->aPK[i] ) pCopy = (u8*)"\0";
fuzzChangeSize(pCopy, &sz);
memcpy(pOut, pCopy, sz);
pOut += sz;
+1 -1
View File
@@ -3862,7 +3862,7 @@ static int sessionSeekToRow(
}
/*
** This function is called from within sqlite3changset_apply_v2() when
** This function is called from within sqlite3changeset_apply_v2() when
** a conflict is encountered and resolved using conflict resolution
** mode eType (either SQLITE_CHANGESET_OMIT or SQLITE_CHANGESET_REPLACE)..
** It adds a conflict resolution record to the buffer in
+1 -1
View File
@@ -1415,7 +1415,7 @@ int sqlite3rebaser_configure(
** in size. This function allocates and populates a buffer with a copy
** of the changeset rebased rebased according to the configuration of the
** rebaser object passed as the first argument. If successful, (*ppOut)
** is set to point to the new buffer containing the rebased changset and
** is set to point to the new buffer containing the rebased changeset and
** (*pnOut) to its size in bytes and SQLITE_OK returned. It is the
** responsibility of the caller to eventually free the new buffer using
** sqlite3_free(). Otherwise, if an error occurs, (*ppOut) and (*pnOut)
+2 -5
View File
@@ -348,6 +348,7 @@ TESTSRC = \
$(TOP)/src/test_tclsh.c \
$(TOP)/src/test_tclvar.c \
$(TOP)/src/test_thread.c \
$(TOP)/src/test_vdbecov.c \
$(TOP)/src/test_vfs.c \
$(TOP)/src/test_windirent.c \
$(TOP)/src/test_window.c \
@@ -377,7 +378,6 @@ TESTSRC += \
$(TOP)/ext/misc/totype.c \
$(TOP)/ext/misc/unionvtab.c \
$(TOP)/ext/misc/wholenumber.c \
$(TOP)/ext/misc/vfslog.c \
$(TOP)/ext/misc/zipfile.c \
$(TOP)/ext/fts5/fts5_tcl.c \
$(TOP)/ext/fts5/fts5_test_mi.c \
@@ -715,12 +715,9 @@ opcodes.h: parse.h $(TOP)/src/vdbe.c $(TOP)/tool/mkopcodeh.tcl
#
parse.h: parse.c
parse.c: $(TOP)/src/parse.y lemon $(TOP)/tool/addopcodes.tcl
parse.c: $(TOP)/src/parse.y lemon
cp $(TOP)/src/parse.y .
rm -f parse.h
./lemon -s $(OPTS) parse.y
mv parse.h parse.h.temp
tclsh $(TOP)/tool/addopcodes.tcl parse.h.temp >parse.h
sqlite3.h: $(TOP)/src/sqlite.h.in $(TOP)/manifest mksourceid $(TOP)/VERSION $(TOP)/ext/rtree/sqlite3rtree.h
tclsh $(TOP)/tool/mksqlite3h.tcl $(TOP) >sqlite3.h
+70 -65
View File
@@ -1,12 +1,12 @@
C Performance\simprovement\son\sthe\sOP_Variable\sopcode.
D 2019-04-01T20:57:11.741
C Merge\strunk\schanges\sinto\sthis\sbranch.
D 2019-04-11T19:04:01.007
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F Makefile.in 236d2739dc3e823c3c909bca2d6cef93009bafbefd7018a8f3281074ecb92954
F Makefile.in 4640daf826b80947a924ac44275c451ffc13007c7c866a5730c8ce5cf9e1dc74
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc fb6dc0c6b09e491b3ad87fed2e1c63ace1b474d4c01091157d63839d376e54c8
F README.md 623c225551b176659e443ae9e466e91a2c8ff16157260618295db91aef0800b7
F Makefile.msc 26957950b2b4f3b26e311eeea70437f85a77765f71d3a06489466d66ee321100
F README.md 74745e53db87fdc86f571dd7ec1bd18e154d0abd6d37d2292a1062e931318a29
F VERSION 288d756b1b7be03ecdbf1795c23af2c8425f2e46ba6979a14ef53360308f080d
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
@@ -116,7 +116,7 @@ F ext/fts5/fts5_buffer.c 7d91caa0d862079d787660ec405d2fda6fd4f206d95b870dc7adc3b
F ext/fts5/fts5_config.c d7523cba5e66da077233c023aecbc3e6a37978ff75a18131c5ab5b1229d5bac7
F ext/fts5/fts5_expr.c 840c88d55e78083a5e61a35968df877712ae28791b347eced1e98e3b337d2d3c
F ext/fts5/fts5_hash.c 1cc0095646f5f3b46721aa112fb4f9bf29ae175cb5338f89dcec66ed97acfe75
F ext/fts5/fts5_index.c 865302c41aee4e8336b5dd06759e962e5d8b68ed3cb96ccf0e0dee451f399a34
F ext/fts5/fts5_index.c 8a3ef6f2dcf2a4c4212d0a6ad5ecc5f2d2912a5a5f6ced3a6ae0d5993ecce0f4
F ext/fts5/fts5_main.c de317d9890e9bb61e1d295a00b53d0a0b2d0ef08789108566bf530e6a1d06887
F ext/fts5/fts5_storage.c b24f6916fcdd68989a549f25962f286bdba9d9d59c7581567a6a0eb647cd07cc
F ext/fts5/fts5_tcl.c 39bcbae507f594aad778172fa914cad0f585bf92fd3b078c686e249282db0d95
@@ -157,7 +157,7 @@ F ext/fts5/test/fts5connect.test 08030168fc96fc278fa81f28654fb7e90566f33aff269c0
F ext/fts5/test/fts5content.test 688d5ac7af194ebc67495daea76a69e3cd5480122c2320e72d41241b423b4116
F ext/fts5/test/fts5corrupt.test 77ae6f41a7eba10620efb921cf7dbe218b0ef232b04519deb43581cb17a57ebe
F ext/fts5/test/fts5corrupt2.test 7453752ba12ce91690c469a6449d412561cc604b1dec994e16ab132952e7805f
F ext/fts5/test/fts5corrupt3.test f87317faf720259258437cd240cc0b2a7c8620abffd6fe005b54c45d142166f6
F ext/fts5/test/fts5corrupt3.test db13dbca9cf4cb68d4705344baea002310a8ff2252adc55fd1de217ca1e93747
F ext/fts5/test/fts5delete.test cbf87e3b8867c4d5cfcaed975c7475fd3f99d072bce2075fcedf43d1f82af775
F ext/fts5/test/fts5detail.test 31b240dbf6d44ac3507e2f8b65f29fdc12465ffd531212378c7ce1066766f54e
F ext/fts5/test/fts5determin.test 1b77879b2ae818b5b71c859e534ee334dac088b7cf3ff3bf76a2c82b1c788d11
@@ -277,6 +277,7 @@ F ext/misc/README.md d6dd0fe1d8af77040216798a6a2b0c46c73054d2f0ea544fbbcdccf6f23
F ext/misc/amatch.c 50a9ef2d38dabfa371f8c1904097d493271e63d58ccb0e9b79a4fa4a94e66660
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
F ext/misc/appendvfs.c 3777f22ec1057dc4e5fd89f2fbddcc7a29fbeef1ad038c736c54411bb1967af7
F ext/misc/blobio.c 085bbfa57ea58bb15d994ba4cd397bff6f0c38c4f618adbc62cf4d3780e5d88a
F ext/misc/btreeinfo.c 4f0ebf278f46e68e6306c667917766cebc5550fd35d5de17847988e22892d4d2
F ext/misc/carray.c ed96c218ea940b85c9a274c4d9c59fe9491c299147a38a8bba537687bd6c6005
F ext/misc/closure.c dbfd8543b2a017ae6b1a5843986b22ddf99ff126ec9634a2f4047cd14c85c243
@@ -348,6 +349,7 @@ F ext/rbu/rbufault3.test e0052ccba428ffdd2bb989d3ae84716f058ec5ab5f7196c64ba407b
F ext/rbu/rbufault4.test 03d2849c3df7d7bd14a622e789ff049e5080edd34a79cd432e01204db2a5930a
F ext/rbu/rbufts.test 0ae8d1da191c75bd776b86e24456db0fb6e97b7c944259fae5407ea55d23c31d
F ext/rbu/rbumulti.test 5fb139058f37ddc5a113c5b93238de915b769b7792de41b44c983bc7c18cf5b9
F ext/rbu/rbupartial.test 73baf12a5941fe6891a829106a6f2e0a973f89aa49bd8659b12f547beb29b482
F ext/rbu/rbuprogress.test 04614ff8820bab9c1ec1b7dbec1edc4b45474421d4fe7abbd2a879a9c02884f9
F ext/rbu/rburesume.test dbdc4ca504e9c76375a69e5f0d91205db967dcc509a5166ca80231f8fda49eb1
F ext/rbu/rbusave.test f4190a1a86fccf84f723af5c93813365ae33feda35845ba107b59683d1cdd926
@@ -356,7 +358,7 @@ F ext/rbu/rbutemplimit.test 7f408f49b90fa0a720d7599f3aec74a3c85e6cd78e56fdf726ce
F ext/rbu/rbuvacuum.test 55e101e90168c2b31df6c9638fe73dc7f7cc666b6142266d1563697d79f73534
F ext/rbu/rbuvacuum2.test b8e5b51dc8b2c0153373d024c0936be3f66f9234acbd6d0baab0869d56b14e6b
F ext/rbu/rbuvacuum3.test 8addd82e4b83b4c93fa47428eae4fd0dbf410f8512c186f38e348feb49ba03dc
F ext/rbu/sqlite3rbu.c d0627582dc894d96e70a1f4b3c8953abdd9fd4870f9a229479309ebfca9eda41
F ext/rbu/sqlite3rbu.c 3f21eda2ee997ac2db4b351d6ed87b723056a4ce5484e06f0be6671ed602cf3e
F ext/rbu/sqlite3rbu.h 1dc88ab7bd32d0f15890ea08d23476c4198d3da3056985403991f8c9cd389812
F ext/rbu/test_rbu.c 03f6f177096a5f822d68d8e4069ad8907fe572c62ff2d19b141f59742821828a
F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15
@@ -401,7 +403,7 @@ F ext/rtree/util/randomshape.tcl 54ee03d0d4a1c621806f7f44d5b78d2db8fac26e0e8687c
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
F ext/rtree/visual01.txt e9c2564083bcd30ec51b07f881bffbf0e12b50a3f6fced0c222c5c1d2f94ac66
F ext/session/changeset.c 7a1e6a14c7e92d36ca177e92e88b5281acd709f3b726298dc34ec0fb58869cb5
F ext/session/changesetfuzz.c 01023c41cfb02e191d144ea8bfdc46443393b62d13873f5fa044fc9886e60142
F ext/session/changesetfuzz.c 227076ab0ae4447d742c01ee88a564da6478bbf26b65108bf8fac9cd8b0b24aa
F ext/session/changesetfuzz1.test 2e1b90d888fbf0eea5e1bd2f1e527a48cc85f8e0ff75df1ec4e320b21f580b3a
F ext/session/session1.test 0b2f88995832ea040ae8e83a1ad4afa99c00b85c779d213da73a95ea4113233e
F ext/session/session2.test 284de45abae4cc1082bc52012ee81521d5ac58e0
@@ -429,8 +431,8 @@ F ext/session/sessioninvert.test ae1a003a9ab1f8d64227dbb5c3a4c97e65b561b01e7b295
F ext/session/sessionrebase.test ccfa716b23bd1d3b03217ee58cfd90c78d4b99f53e6a9a2f05e82363b9142810
F ext/session/sessionstat1.test 218d351cf9fcd6648f125a26b607b140310160184723c2666091b54450a68fb5
F ext/session/sessionwor.test 67b5ab91d4f93ce65ff1f58240ac5ddf73f8670facc1ffa49cef56293d52818d
F ext/session/sqlite3session.c 4c79daf65e89c78dd62fd97a1b2eac3e53be700b29914101453a0d951f7ba9c8
F ext/session/sqlite3session.h 54d6356f5769d3695e5f63d719c6ee27671b2614973a2b675a3ff4d30d574233
F ext/session/sqlite3session.c faf074fedbb3d17d82b1321575b5412e234746a2d5bd2244bc85484786ab686d
F ext/session/sqlite3session.h 919be6649d39d6413ce7a63fc3e3bca3270e18bc2d57ad4040a70007b9e54397
F ext/session/test_session.c 98797aba475a799376c9a42214f2d1debf2d0c3cb657d9c8bbf4f70bf3fb4aec
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04
@@ -438,7 +440,7 @@ F ext/userauth/userauth.c f81aa5a3ecacf406f170c62a144405858f6f6de51dbdc0920134e6
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
F main.mk 3930eb2fcbebe49ab7408f6fef3baa8c4bf3c84540f9f29dfe849bf561ff6e51
F main.mk 23d3660f7053d196aef76938bf78b10fc3ce1831a85d96bd71565758788f34d4
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
@@ -457,10 +459,10 @@ F src/auth.c 0fac71038875693a937e506bceb492c5f136dd7b1249fbd4ae70b4e8da14f9df
F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
F src/btree.c a644e8f3b71205e1e360ed5a28d8fc8feaa5c63fee3a49a36711ff83f4bdf6d2
F src/btree.h 63b94fb38ce571c15eb6a3661815561b501d23d5948b2d1e951fbd7a2d04e8d3
F src/btree.c 958939f608e351a36756e3749596472baa0e5aae54eebd14e6beffe7a68aafc7
F src/btree.h c11446f07ec0e9dc85af8041cb0855c52f5359c8b2a43e47e02a685282504d89
F src/btreeInt.h 6111c15868b90669f79081039d19e7ea8674013f907710baa3c814dc3f8bfd3f
F src/build.c 241006a97dee8a3e762a724aa549ca79171826a5b0b1d8e7ee41ffcd92bc5328
F src/build.c b3bda944006369ccc0ea79228474dab350d8bf7b4e32ae0a6b0d6206c827abfd
F src/callback.c 25dda5e1c2334a367b94a64077b1d06b2553369f616261ca6783c48bcb6bda73
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c 109e58d00f62e8e71ee1eb5944ac18b90171c928ab2e082e058056e1137cc20b
@@ -468,7 +470,7 @@ F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7
F src/dbstat.c c12833de69cb655751487d2c5a59607e36be1c58ba1f4bd536609909ad47b319
F src/delete.c d08c9e01a2664afd12edcfa3a9c6578517e8ff8735f35509582693adbe0edeaf
F src/expr.c f2d0ecf68213770be4fad83128ce02e67667deebaa0a44061313f7e4f2a4ae28
F src/expr.c 03f583cf773c10ec64b8b82b2f8326501c38c4ad12deda884c6efda9bb925b7c
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c bd0138acdc008c1845ccf92f8e73787880562de649471804801c06fed814c765
F src/func.c 2ccf4ae12430b1ae7096be5f0675887e1bd0732828af0ac0f7496339b7c6edee
@@ -477,9 +479,9 @@ F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c 4ce12b5ba3bcbfa17ec37ce960d499fc287b6289df2c00b31201f716a3c7df45
F src/insert.c fc3cf5c371f9a400144e8c2f148ab29cd3f67f7da7eaf47e6a6959f8255fd92c
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c e6f10875d52aca3b7e57ce1ec174aeafc9b6c00b43000cd30d791f9cb490b7a6
F src/loadext.c 22afc33c3a61b4fd80a60a54f1882688371e6bc64685df2696b008fce65a999c
F src/main.c 11714c8cefd458970cb1fd005251d0ad02ad69598893833b5564ffaaef192a1f
F src/malloc.c 0f9da2a66b230a5785af94b9672126845099b57b70a32c987d04ac28c69da990
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
@@ -505,23 +507,23 @@ F src/os_win.c 85d9e532d0444ab6c16d7431490c2e279e282aa0917b0e988996b1ae0de5c5a0
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 422fd8cfa59fb9173eff36a95878904a0eeb0dcc62ba49350acc8b1e51c4dc7b
F src/pager.h 217921e81eb5fe455caa5cda96061959706bcdd29ddb57166198645ef7822ac3
F src/parse.y a020386af1739371b2eafba077497aacf2a840d1a178508dc6f8c19448e42054
F src/parse.y 8de9b1da4dc0f9615cfa9f4cbdd368b4ac822e1cbbc57b0fe071d9a83988df6d
F src/pcache.c 696a01f1a6370c1b50a09c15972bc3bee3333f8fcd1f2da8e9a76b1b062c59ee
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
F src/pcache1.c a72804486dfa8e4b6bc30d666c97ecf1155f91a4351fc6e48ea4097e4eb304fb
F src/pragma.c af67dedaad8bafe9a5f9adcec32a0da6dd118617dd8220ad1d118f5a6bf83a02
F src/pragma.h a776bb9c915207e9d1117b5754743ddf1bf6a39cc092a4a44e74e6cb5fab1177
F src/prepare.c 78027c6231fbb19ca186a5f5f0c0a1375d9c2cec0655273f9bd90d9ff74a34b3
F src/printf.c 93a3d539019264683a444bc043c875e9a6cca43fe935ae7bf6cfff0af3bba118
F src/printf.c 67f79227273a9009d86a017619717c3f554f50b371294526da59faa6014ed2cd
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c 567888ee3faec14dae06519b4306201771058364a37560186a3e0e755ebc4cb8
F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93
F src/select.c 9263f5c30dd44c7ac2eb29f40a7ec64322a96885b71c00de6bc30b756c2e1c49
F src/shell.c.in c1986496062f9dba4ed5b70db06b5e0f32e1954cdcfab0b30372c6c186796810
F src/sqlite.h.in e8a8dd45ae6849b3e40b243eca41181a740b4f4ac67d5b65fcea519d454db785
F src/sqlite.h.in 38390767acc1914d58930e03149595ee4710afa4e3c43ab6c3a8aea3f1a6b8cd
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 960f1b86c3610fa23cb6a267572a97dcf286e77aa0dd3b9b23292ffaa1ea8683
F src/sqliteInt.h 59b625f88bf96cad4cd1a6a6ded615c161f518fb56da3e49f2ff70429e49095f
F src/sqlite3ext.h 9ecc93b8493bd20c0c07d52e2ac0ed8bab9b549c7f7955b59869597b650dd8b5
F src/sqliteInt.h d229b6a5f70fe6c57d2f91f0edc60a9c4437397b4a5b59fd72fe9eb3b94d3437
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
@@ -529,7 +531,7 @@ F src/tclsqlite.c cfe7f93daf9d8787f65e099efb67d7cdfc2c35236dec5d3f6758520bd35194
F src/test1.c cfb303eeddd3670409af6b58d2ddb928b8e9e70822d681d3df88dfaabb7bea6a
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
F src/test4.c 405834f6a93ec395cc4c9bb8ecebf7c3d8079e7ca16ae65e82d01afd229694bb
F src/test5.c 328aae2c010c57a9829d255dc099d6899311672d
F src/test6.c e8d839fbc552ce044bec8234561a2d5b8819b48e29548ad0ba400471697946a8
F src/test7.c 5612e9aecf934d6df7bba6ce861fdf5ba5456010
@@ -569,10 +571,11 @@ F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
F src/test_sqllog.c 11e6ce7575f489155c604ac4b439f2ac1d3d5aef
F src/test_superlock.c 4839644b9201da822f181c5bc406c0b2385f672e
F src/test_syscall.c 1073306ba2e9bfc886771871a13d3de281ed3939
F src/test_tclsh.c 06317648b0d85a85fd823f7973b55535c59a3156c1ef59394fe511f932cfa78d
F src/test_tclsh.c eeafce33ad2136d57e5dec10f1e9a4347447eb72ffd504a1c7b9c6bfe2e71578
F src/test_tclvar.c 33ff42149494a39c5fbb0df3d25d6fafb2f668888e41c0688d07273dcb268dfc
F src/test_thread.c 911d15fb14e19c0c542bdc8aabf981c2f10a4858
F src/test_vfs.c c6c6a58f66b26876c7b5769fb323a58b2c7120299b5084e7212c4116f902cbaa
F src/test_vdbecov.c f60c6f135ec42c0de013a1d5136777aa328a776d33277f92abac648930453d43
F src/test_vfs.c 0868f1d4d7cdc7c6df60e895ca26b19e4f433dd1be0fc9c18c3ee63755804039
F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
F src/test_windirent.c a895e2c068a06644eef91a7f0a32182445a893b9a0f33d0cdb4283dca2486ac1
F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a90484215
@@ -585,27 +588,27 @@ F src/trigger.c bb034c08eca111e66a19cda045903a12547c1be2294b5570d794b869d9c44a73
F src/update.c 0b973357d88092140531e07ff641139c26fb4380b0b9f5ed98c5f7691b4604d1
F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
F src/util.c 82a2e3f691a3b654be872e305dab1f455e565dedf5e6a90c818c1ab307c00432
F src/vacuum.c 532553ee1d47f69c1198858107b1f3af3d16af25f2ab4ce3b1263d9e333f26e2
F src/vdbe.c 09a2d9b2498f4a496413b9f23700eefd780657de352c38cdce0d30121e119030
F src/util.c 92276bde295e4f2c767d752adc358fa4b649f04eefffad3cfba5a81317f4a24a
F src/vacuum.c 72690ccb6877a88f8473a893cf9f6d7592236f3eebfebfa840b19c708acde574
F src/vdbe.c 711ef421b3bb3db3b2476067b2dc3c71ef5844d9b1a723026578f89f6da621e8
F src/vdbe.h 712bca562eaed1c25506b9faf9680bdc75fc42e2f4a1cd518d883fa79c7a4237
F src/vdbeInt.h 5ea6f6548a14b20a9210ca055a989478a37d16f84740cc123834f13e4527bce7
F src/vdbeInt.h 2c12704db9740c8e899786ecfc7a5797a9d067563496eb1b6ed03c592d7b8d90
F src/vdbeapi.c a6e462bd7853e272cf614d6fbda7f3f20c89a2d255805855b32895a5983ddcec
F src/vdbeaux.c 7aa412e7e56eb53649d87766f3064994a31991ee2b2716bf8c3129fa15cc7653
F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
F src/vdbemem.c 6d67403debf6eb2b0c8d956ea09bb0ad79b4b45af2a7e2b2736894e703ae3286
F src/vdbemem.c 8e6889761e344babdb8a56dd1ac8911501fa648396544d1644f1cd6a87c80dc0
F src/vdbesort.c 90aad5a92608f2dd771c96749beabdb562c9d881131a860a7a5bccf66dc3be7f
F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392
F src/vtab.c 2462b7d6fd72b0b916477f5ef210ee49ab58cec195483ebdac0c8c5e3ec42cab
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 3f4f653daf234fe713edbcbca3fec2350417d159d28801feabc702a22c4e213f
F src/wal.c 8bf87820896453ee3cca75f3082c57d7d82643e46cc089775612b18453732c12
F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
F src/walker.c 7607f1a68130c028255d8d56094ea602fc402c79e1e35a46e6282849d90d5fe4
F src/where.c 8a207cb2ca6b99e1edb1e4bbff9b0504385a759cbf66180d1deb34d80ca4b799
F src/where.c ff2955dc2743c1af05ba5a8232ab72724d9a63b76dbee256368f40fd3ef82db5
F src/whereInt.h 5f14db426ca46a83eabab1ae9aa6d4b8f27504ad35b64c290916289b1ddb2e88
F src/wherecode.c 6fa4056c5ce019e4a8af33795906340176813cb3c1236f4b7b08df76a1b6287b
F src/wherecode.c 83be72e8d1c0231d0db06ffe5cfd32c7834bd00d2ed869306a2c1e0828488752
F src/whereexpr.c 90859652920f153d2c03f075488744be2926625ebd36911bcbcb17d0d29c891c
F src/window.c 92b6d593a63f27b29360176f71eb5839562bdb7dae6effd35f4c69168ea5455d
F src/window.c 038c248267e74ff70a2bb9b1884d40fd145c5183b017823ecb6cbb14bc781478
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
@@ -660,7 +663,7 @@ F test/auth.test 3310d9c08e928beca42d3eadaaf53cef619d9d275f598565a3758a21ce63138
F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1
F test/auth3.test db21405b95257c24d29273b6b31d0efc59e1d337e3d5804ba2d1fd4897b1ae49
F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec
F test/autoinc.test 381f494fefa90acd999933829e2934efb6b40906db9d6a39e822e3f7b4c8bf61
F test/autoinc.test 997d6f185f138229dc4251583a1d04816423dddc2fc034871a01aeb1d728cb39
F test/autoindex1.test 96185415f5faacd5b8d7a7f505efddd5abb1f111d58338e9c0b1dc40b87cd3cc
F test/autoindex2.test 12ef578928102baaa0dc23ad397601a2f4ecb0df
F test/autoindex3.test 2dd997d6590438b53e4f715f9278aa91c9299cf3f81246a0915269c35beb790e
@@ -679,7 +682,7 @@ F test/backup_malloc.test 0c9abdf74c51e7bedb66d504cd684f28d4bd4027
F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f
F test/badutf2.test f5bc7f2d280670ecd79b9cf4f0f1760c607fe51f
F test/bc_common.tcl b5e42d80305be95697e6370e015af571e5333a1c
F test/bestindex1.test 852170bddbb21daa121fabcc274640ff83d7d8705912e8b5fe7ed2c5a9a9224a
F test/bestindex1.test 705b57d7f51d53ee5fd043dd9666236e1fc18f4d59abf51da0ea5ea1b4804947
F test/bestindex2.test 9a0ccd320b6525eec3a706aae6cdab7e1b7b5abca75027e39f39f755e76e5928
F test/bestindex3.test 7622e792ff2da16d262d3cea6ad914591ac4806d57ed128e6c940b7920b47b84
F test/bestindex4.test 038e3d0789332f3f1d61474f9bbc9c6d08c6bd1783a978f31f38ad82688de601
@@ -774,7 +777,7 @@ F test/crash7.test 1a194c4900a255258cf94b7fcbfd29536db572df
F test/crash8.test 64366e459c28dd62edfb7ad87253a409c7533b92d16fcc479a6a8131bdcc3100
F test/crashM.test d95f59046fa749b0d0822edf18a717788c8f318d
F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
F test/createtab.test b5de160630b209c4b8925bdcbbaf48cc90b67fe8
F test/createtab.test 85cdfdae5c3de331cd888d6c66e1aba575b47c2e3c3cc4a1d6f54140699f5165
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
F test/csv01.test c9c3af0d58c34e9ac970c5875a77939edb958762c8aafb95409e19a3f088b6cd
F test/ctime.test 78749e6c9a5f0010d67985be80788f841e3cd2da18114e2ed6010399a7d807f3
@@ -794,7 +797,7 @@ F test/default.test 3e46c421eebefd2787c2f96673efabf792d360f3a1d5073918cbe450ce67
F test/delete.test 31832b0c45ecb51a54348c68db173be462985901e6ed7f403d6d7a8f70ab4ef0
F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa
F test/delete3.test 555e84a00a99230b7d049d477a324a631126a6ab
F test/delete4.test 21d2113217eeaacac2d99defe14fe6611615ae86
F test/delete4.test 6aa279f459f4aa792cc251435c3809415c1ecaf9f27dce91675e26f05b503db3
F test/delete_db.test 096d828493c7907f9ea11a7098ea6a0f73edba89406487d5d6cc2228dc4ab8b0
F test/descidx1.test 6d03b44c8538fe0eb4924e19fba10cdd8f3c9240
F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
@@ -823,7 +826,7 @@ F test/e_select2.test aceb80ab927d46fba5ce7586ebabf23e2bb0604f
F test/e_totalchanges.test b12ee5809d3e63aeb83238dd501a7bca7fd72c10
F test/e_update.test f46c2554d915c9197548681e8d8c33a267e84528
F test/e_uri.test 47eeb2960e74613f0f8722b2f13aef08fde69daa16e5380ac93df84dac8b1f72
F test/e_vacuum.test 44acfe525e01071ca50e76c68875db6fa084dd7743a3a16b5b503455539d03ca
F test/e_vacuum.test 0d8832a2ce92350db0d0cff47b419465fd9772562e1f77ff7d9478c07a4980d2
F test/e_wal.test ae9a593207a77d711443ee69ffe081fda9243625
F test/e_walauto.test 248af31e73c98df23476a22bdb815524c9dc3ba8
F test/e_walckpt.test 28c371a6bb5e5fe7f31679c1df1763a19d19e8a0
@@ -994,7 +997,7 @@ F test/fuzzdata4.db b502c7d5498261715812dd8b3c2005bad08b3a26e6489414bd13926cd3e4
F test/fuzzdata5.db e35f64af17ec48926481cfaf3b3855e436bd40d1cfe2d59a9474cb4b748a52a5
F test/fuzzdata6.db 92a80e4afc172c24f662a10a612d188fb272de4a9bd19e017927c95f737de6d7
F test/fuzzdata7.db f46c9a5698c1ca75ca6280c7c879a3f46dc82fe4b1ce246827496b806488952d
F test/fuzzdata8.db 9dcffb6ca959e466e3da7d76f992d877dfc0b302d316554a786d320af97a6dd2
F test/fuzzdata8.db 5f12b6a8579e89616da9bd6dede1f38748eb04a1265f0b89117274f44d76b227
F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8
F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14
F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536
@@ -1008,7 +1011,7 @@ F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8
F test/icu.test 41aa8847745a879b897a7febea0f8f9efc8e67fe8bf680589b6e07c7b0a1569a
F test/ieee754.test 806fc0ce7f305f57e3331eaceeddcfec9339e607
F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8
F test/in.test 63933d7b71eed01a49df55541a73a75398302b50a05b5333f90481460a32ff49
F test/in.test 4b985774a64f143f486418cec53379bed3aeb0503179353cc7c7ce15fb464349
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
F test/in4.test d2b38cba404bc4320f4fe1b595b3d163f212c068
@@ -1042,7 +1045,7 @@ F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
F test/insert.test 9773604f8e1a2595f51488a5643c359d8a11dc55a11cb185910d93387d378458
F test/insert2.test 4d14b8f1b810a41995f6286b64a6943215d52208
F test/insert3.test 1b7db95a03ad9c5013fdf7d6722b6cd66ee55e30
F test/insert4.test 46bead5f39e181850ee56adcf49d3a3157c460c52249211714612ac89fe34835
F test/insert4.test 7802ada6ba8738661b9f6c0e26858d3375b40cc7180289fd350644cd7a08fec9
F test/insert5.test 394f96728d1258f406fe5f5aeb0aaf29487c39a6
F test/insertfault.test ac63d14ea3b49c573673a572f4014b9117383a03e497c58f308b5c776e4a7f74
F test/instr.test 9a8802f28437d8ade53fedfc47b2ca599b4e48ba
@@ -1199,7 +1202,7 @@ F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
F test/permutations.test b8f0da2f53ef1bd7ff149a140ee625aa7276c94ae15eb9acc2d8ed4af8f22b13
F test/pg_common.tcl 4740dc35190d6acdab14c097783331361301ab504a94d948f6afbb56ce0a51e8
F test/pragma.test c267bf02742c823a191960895b3d52933cebd7beee26757d1ed694f213fcd867
F test/pragma.test cf066fe0f7f5d49f4758de4986407b8676c61aaa7871599340d64f42a8edc352
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
F test/pragma3.test 8300aa9c63cff1027006ca34bf413a148abbd6dcd471fa9a1ded322fe18c0df9
F test/pragma4.test 52d8186f9e8d09b87189432cdd401dfa66d0b32445e837fa19046c8ae7621b0e
@@ -1225,6 +1228,7 @@ F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8
F test/regexp2.test 40e894223b3d6672655481493f1be12012f2b33c
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
F test/releasetest.tcl 7712811e0f4e2f198ec786cb2e1352b3793d7395f48a3cceef0572d8823eb75e x
F test/releasetest_data.tcl c3746248b5ad8f99a29020f83501bb25e024156ecc37e05c71c76da4fc8601c6
F test/resetdb.test 8062cf10a09d8c048f8de7711e94571c38b38168db0e5877ba7561789e5eeb2b
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
F test/rollback.test 06680159bc6746d0f26276e339e3ae2f951c64812468308838e0a3362d911eaa
@@ -1307,8 +1311,8 @@ F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
F test/shrink.test 1b4330b1fd9e818c04726d45cb28db73087535ce
F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
F test/skipscan1.test 3ea1cccca8f1b0e1cf3e73a63b43dd796f34d4aaee815e641f0d2ebb3fa448d4
F test/skipscan2.test ef143c6e4a5ba4f19c1d1e3f517811f7942bdf2142736cc568feb34e0b5fb763
F test/skipscan1.test b1fef3046d555836712d4a3a7c8ae8193356c6a15bee59cb3976e4ee98596c97
F test/skipscan2.test 3eb703ce794f139e7b83567911046298bcde29606116727f9b700ce34f559d2d
F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5
F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2
F test/skipscan6.test 0b4cd1b4ac9f84d91454df513c99a4932fa07e8f27b8049bea605068b3e34ac7
@@ -1341,7 +1345,7 @@ F test/spellfix2.test dfc8f519a3fc204cb2dfa8b4f29821ae90f6f8c3
F test/spellfix3.test 0f9efaaa502a0e0a09848028518a6fb096c8ad33
F test/spellfix4.test 51c7c26514ade169855c66bcf130bd5acfb4d7fd090cc624645ab275ae6a41fb
F test/sqldiff1.test 28cd737cf1b0078b1ec1bbf425e674c47785835e
F test/sqllimits1.test a74ee2a3740b9f9c2437c246d8fb77354862a142
F test/sqllimits1.test 264f4b0f941800ba139d25e33ee919c5d95fea06dfbe8ac291d6811a30984ca5
F test/sqllog.test 6af6cb0b09f4e44e1917e06ce85be7670302517a
F test/stat.test f8f1279ffffabe6df825723af18cc6e0ae70a893
F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1
@@ -1375,7 +1379,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
F test/temptable2.test d2940417496e2b9548e01d09990763fbe88c316504033256d51493e1f1a5ce6a
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
F test/tester.tcl 499a5086815aa416d971ff438d7425c64f41ed3233251db4836d270f9a6671e8
F test/tester.tcl 64ac253a411db1af7649438f674213a45876ca70609570310a8652edf23e5d77
F test/thread001.test b61a29dd87cf669f5f6ac96124a7c97d71b0c80d9012746072055877055cf9ef
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@@ -1550,7 +1554,7 @@ F test/trigger8.test 30cb0530bd7c4728055420e3f739aa00412eafa4
F test/trigger9.test 2226ec795a33b0460ab5cf8891e9054cc7edef41
F test/triggerA.test 837be862d8721f903dba3f3ceff05b32e0bee5214cf6ea3da5fadf12d3650e9d
F test/triggerB.test 56780c031b454abac2340dbb3b71ac5c56c3d7fe
F test/triggerC.test c7fbc3eb241b5a7ba4b0815f76c3708483e91890f9573add12a610c45b2a6022
F test/triggerC.test f1210921924f3a6aaa8c1538115fe56c9c448e8e3033bf0dab38ae78db937c41
F test/triggerD.test 8e7f3921a92a5797d472732108109e44575fa650
F test/triggerE.test ede2e4bce4ba802337bd69d39447fa04a938e06d84a8bfc53c76850fc36ed86d
F test/triggerF.test 5d76f0a8c428ff87a4d5ed52da06f6096a2c787a1e21b846111dfac4123de3ad
@@ -1647,7 +1651,9 @@ F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417
F test/walslow.test c05c68d4dc2700a982f89133ce103a1a84cc285f
F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2af51747
F test/walvfs.test c0faffda13d045a96dfc541347886bb1a3d6f3205857fc98e683edfab766ea88
F test/where.test 93738e224cd5e7819565a9f272c19fd0ee5893d9cd7f5238ce026bae09b8d710
F test/wapp.tcl b440cd8cf57953d3a49e7ee81e6a18f18efdaf113b69f7d8482b0710a64566ec
F test/wapptest.tcl a7ea78efd76045c1c9c5ee43964e359e6aaceeffbe52168ab370f128400e3938 x
F test/where.test 0607caa5a1fbfe7b93b95705981b463a3a0408038f22ae6e9dc11b36902b0e95
F test/where2.test 478d2170637b9211f593120648858593bf2445a1
F test/where3.test 2341a294e17193a6b1699ea7f192124a5286ca6acfcc3f4b06d16c931fbcda2c
F test/where4.test 4a371bfcc607f41d233701bdec33ac2972908ba8
@@ -1677,7 +1683,7 @@ F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2
F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972
F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
F test/window1.test 7484bf9a2ef2d845a50c9aff866efb8cd9d244b5916a9e97fb384e05f33d242b
F test/window1.test 8d453bfaa3f8f0873ba16ca1270c7368f18445065a0003a1b5954ac4e95797b4
F test/window2.tcl 9bfa842d8a62b0d36dc8c1b5972206393c43847433c6d75940b87fec93ce3143
F test/window2.test 8e6d2a1b9f54dfebee1cde961c8590cd87b4db45c50f44947a211e1b63c2a05e
F test/window3.tcl acea6e86a4324a210fd608d06741010ca83ded9fde438341cb978c49928faf03
@@ -1688,17 +1694,17 @@ F test/window5.test d328dd18221217c49c144181975eea17339eaeaf0e9aa558cee3afb84652
F test/window6.test 465e608c021020fb0948a90200e154cd787bc910449e3dafee44c9ca5bd407fe
F test/window7.tcl 6a1210f05d40ec89c22960213a22cd3f98d4e2f2eb20646c83c8c30d4d76108f
F test/window7.test ce7f865241fdd1c5c4db869cd7bb2986c3be836bc2e73649a6846dd920f63e0f
F test/window8.tcl 97de3829e0e1aae2c3aaae41a55c54bc1b0751bbc80dfdd93020431b7a889dad
F test/window8.test 0dd7e2d32605bf59dc6163b924faeff5951419c1c17a9e506e5a38606e97ab7e
F test/windowerr.tcl 678bb2c3ddcaaf605163bd9fe647454fa0097688cfd2fecc5dd9f3a5b45b13f2
F test/windowerr.test 7eb7439332d3855dd53c58dca8838f6990746f40fac7045c0153172083a9452b
F test/windowfault.test cb27a4d8c85982733b123af667921df3a96e23d3739b15d414de75054b334cbe
F test/window8.tcl 9e9a82ae9eea90a4a83481d641a812b974980c38f9247f3b89a6e3c8bed45518
F test/window8.test df187dc19921f7be0ab709d531d681bd80ccaac96a913a89ecee8b272b91d43f
F test/windowerr.tcl abf4d6d0c6d360213af98ed7d538295d905689e83692106f3ece0e3afb9d7f36
F test/windowerr.test 675b5e6debfc9370bfacb0b91e2a93a8923512f92600b16f4ea70a1cd9b8e6e4
F test/windowfault.test 16e906a2c4110c88372ff4bd5de59ac7397ec2f025912eff8e5677eedd126898
F test/with1.test a07b5aad7f77acdf13e52e8814ea94606fcc72e9ea4c99baf293e9d7c63940be
F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab
F test/with3.test 8d26920c88283e0a473ceebd3451554922108ce7b2a6a1157c47eb0a7011212c
F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f198205
F test/withM.test 693b61765f2b387b5e3e24a4536e2e82de15ff64
F test/without_rowid1.test 533add9100255e4cc430d371b3ecfb79f11f956b86c3a1b9d34413bf8e482d8f
F test/without_rowid1.test b5ec93f7df2c1d684e0923247dac6aca8888e088bf50a9f244c3933e0e813a72
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
F test/without_rowid3.test ea4b59dd1b0d7f5f5e4b7cca978cdb905752a9d7c57dc4344a591dba765a3691
F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a
@@ -1714,13 +1720,12 @@ F test/zipfilefault.test 44d4d7a7f7cca7521d569d7f71026b241d65a6b1757aa409c1a1688
F tool/GetFile.cs a15e08acb5dd7539b75ba23501581d7c2b462cb5
F tool/GetTclKit.bat 8995df40c4209808b31f24de0b58f90930239a234f7591e3675d45bfbb990c5d
F tool/Replace.cs 02c67258801c2fb5f63231e0ac0f220b4b36ba91
F tool/addopcodes.tcl 0288d5b26b9b35f4cb5affb76eec63f1dfce117bbc2020066708069ef60b86ff
F tool/build-all-msvc.bat c12328d06c45fec8baada5949e3d5af54bf8c887 x
F tool/build-shell.sh 950f47c6174f1eea171319438b93ba67ff5bf367
F tool/cg_anno.tcl c1f875f5a4c9caca3d59937b16aff716f8b1883935f1b4c9ae23124705bc8099 x
F tool/checkSpacing.c 810e51703529a204fc4e1eb060e9ab663e3c06d2
F tool/dbhash.c a06228aa21ebc4e6ea8daa486601d938499238a5
F tool/dbtotxt.c 04e25f26be7c7743cdfb4111a8483de0b111925d6afeeb7559ade0ceb73f7f52
F tool/dbtotxt.c b2221864a20fb391c46bd31bc1fbdc4a96f5c8a89bef58f421eb9b9c36b1702c
F tool/dbtotxt.md c9a57af8739957ef36d2cfad5c4b1443ff3688ed33e4901ee200c8b651f43f3c
F tool/extract-sqlite3h.tcl 069ceab0cee26cba99952bfa08c0b23e35941c837acabe143f0c355d96c9e2eb x
F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2
@@ -1741,7 +1746,7 @@ F tool/max-limits.c cbb635fbb37ae4d05f240bfb5b5270bb63c54439
F tool/mkautoconfamal.sh 422fc365358a2e92876ffc62971a0ff28ed472fc8bcf9de0df921c736fdeca5e
F tool/mkccode.tcl 86463e68ce9c15d3041610fedd285ce32a5cf7a58fc88b3202b8b76837650dbe x
F tool/mkctimec.tcl dd183b73ae1c28249669741c250525f0407e579a70482371668fd5f130d9feb3
F tool/mkkeywordhash.c 127d0b86eea32a461b79b6c6b11fa5fd223787b681156d682bf1824bb20e2494
F tool/mkkeywordhash.c 537b1a11ec1829b51b633da3ba2cc889b4a3f7356b06a07423b6d4cce92c2350
F tool/mkmsvcmin.tcl cad0c7b54d7dd92bc87d59f36d4cc4f070eb2e625f14159dc2f5c4204e6a13ea
F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c
F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21
@@ -1756,7 +1761,7 @@ F tool/mksqlite3h.tcl 080873e3856eceb9d289a08a00c4b30f875ea3feadcbece796bd509b15
F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b
F tool/mkvsix.tcl b9e0777a213c23156b6542842c238479e496ebf5
F tool/offsets.c fe4262fdfa378e8f5499a42136d17bf3b98f6091
F tool/omittest.tcl dfc8b18a23e9e5289104145b712cdb887c2d840c2d70dc09ce5dbeba8ed8d47c
F tool/omittest.tcl 27f9413c3343bac200a28d81e8234adb0f5e141c4771893cb19b40235a91f1e0
F tool/opcodesum.tcl 740ed206ba8c5040018988129abbf3089a0ccf4a
F tool/pagesig.c ff0ca355fd3c2398e933da5e22439bbff89b803b
F tool/replace.tcl 60f91e8dd06ab81f74d213ecbd9c9945f32ac048
@@ -1813,7 +1818,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 27160df7b3a04ac59d06013ede1d2ee27a4ace86a525ecc333bf7f8b5c580afb
R 35248090ce78ba3337b0ca54b485da2c
U drh
Z ce4b7fb940826537bfbabb06ad9779b9
P ec9c4f6d8da25dcc834812c2bb24bda1017833b1c572bdbbf87f0191e1310706 d71f8bbc4efd8af935671c4e7626862d6e5a4c2e51527b9e82b2f0c94ddf6e93
R 3c54551b10c87fc6f05051e8c995cc5e
U dan
Z 90203c7d6b4495f65199b8125515f7fd
+1 -1
View File
@@ -1 +1 @@
1dc7993bb6957587a6c63142e97b8e4137c3d81bbfd724f86048e0894bcb429b
d805fc0cf1c4ef07a7bc947f75828931e3788d0e64730caab3b42ae58009a194
+8 -25
View File
@@ -833,14 +833,18 @@ moveto_done:
*/
static int btreeRestoreCursorPosition(BtCursor *pCur){
int rc;
int skipNext;
int skipNext = 0;
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState>=CURSOR_REQUIRESEEK );
if( pCur->eState==CURSOR_FAULT ){
return pCur->skipNext;
}
pCur->eState = CURSOR_INVALID;
rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext);
if( sqlite3FaultSim(410) ){
rc = SQLITE_IOERR;
}else{
rc = btreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &skipNext);
}
if( rc==SQLITE_OK ){
sqlite3_free(pCur->pKey);
pCur->pKey = 0;
@@ -1432,11 +1436,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
** reconstruct the entire page. */
if( (int)data[hdr+7]<=nMaxFrag ){
int iFree = get2byte(&data[hdr+1]);
/* If the initial freeblock offset were out of bounds, that would have
** been detected by btreeComputeFreeSpace() when it was computing the
** number of free bytes on the page. */
assert( iFree<=usableSize-4 );
if( iFree>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage);
if( iFree ){
int iFree2 = get2byte(&data[iFree]);
if( iFree2>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage);
@@ -5273,23 +5273,6 @@ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
return rc;
}
/*
** This function is a no-op if cursor pCur does not point to a valid row.
** Otherwise, if pCur is valid, configure it so that the next call to
** sqlite3BtreeNext() is a no-op.
*/
#ifndef SQLITE_OMIT_WINDOWFUNC
void sqlite3BtreeSkipNext(BtCursor *pCur){
/* We believe that the cursor must always be in the valid state when
** this routine is called, but the proof is difficult, so we add an
** ALWaYS() test just in case we are wrong. */
if( ALWAYS(pCur->eState==CURSOR_VALID) ){
pCur->eState = CURSOR_SKIPNEXT;
pCur->skipNext = 1;
}
}
#endif /* SQLITE_OMIT_WINDOWFUNC */
/* Move the cursor to the last entry in the table. Return SQLITE_OK
** on success. Set *pRes to 0 if the cursor actually points to something
** or set *pRes to 1 if the table is empty.
@@ -6187,7 +6170,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
MemPage *pPage1 = pBt->pPage1; /* Local reference to page 1 */
MemPage *pPage; /* Page being freed. May be NULL. */
int rc; /* Return Code */
int nFree; /* Initial number of pages on free-list */
u32 nFree; /* Initial number of pages on free-list */
assert( sqlite3_mutex_held(pBt->mutex) );
assert( CORRUPT_DB || iPage>1 );
-3
View File
@@ -301,9 +301,6 @@ struct BtreePayload {
int sqlite3BtreeInsert(BtCursor*, const BtreePayload *pPayload,
int flags, int seekResult);
int sqlite3BtreeFirst(BtCursor*, int *pRes);
#ifndef SQLITE_OMIT_WINDOWFUNC
void sqlite3BtreeSkipNext(BtCursor*);
#endif
int sqlite3BtreeLast(BtCursor*, int *pRes);
int sqlite3BtreeNext(BtCursor*, int flags);
int sqlite3BtreeEof(BtCursor*);
+4 -1
View File
@@ -3265,6 +3265,7 @@ void sqlite3CreateIndex(
sqlite3ExprListSetSortOrder(pList, sortOrder);
}else{
sqlite3ExprListCheckLength(pParse, pList, "index");
if( pParse->nErr ) goto exit_create_index;
}
/* Figure out how many bytes of space are required to store explicitly
@@ -3283,6 +3284,7 @@ void sqlite3CreateIndex(
*/
nName = sqlite3Strlen30(zName);
nExtraCol = pPk ? pPk->nKeyCol : 1;
assert( pList->nExpr + nExtraCol <= 32767 /* Fits in i16 */ );
pIndex = sqlite3AllocateIndexObject(db, pList->nExpr + nExtraCol,
nName + nExtra + 1, &zExtra);
if( db->mallocFailed ){
@@ -4396,7 +4398,8 @@ void sqlite3UniqueConstraint(
StrAccum errMsg;
Table *pTab = pIdx->pTable;
sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0, 200);
sqlite3StrAccumInit(&errMsg, pParse->db, 0, 0,
pParse->db->aLimit[SQLITE_LIMIT_LENGTH]);
if( pIdx->aColExpr ){
sqlite3_str_appendf(&errMsg, "index '%q'", pIdx->zName);
}else{
+12 -1
View File
@@ -857,7 +857,7 @@ Expr *sqlite3PExpr(
p = sqlite3DbMallocRawNN(pParse->db, sizeof(Expr));
if( p ){
memset(p, 0, sizeof(Expr));
p->op = op & TKFLG_MASK;
p->op = op & 0xff;
p->iAgg = -1;
}
sqlite3ExprAttachSubtrees(pParse->db, p, pLeft, pRight);
@@ -5032,6 +5032,17 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
*/
int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){
Walker w;
p = sqlite3ExprSkipCollate(p);
while( p ){
if( p->op==TK_NOTNULL ){
p = p->pLeft;
}else if( p->op==TK_AND ){
if( sqlite3ExprImpliesNonNullRow(p->pLeft, iTab) ) return 1;
p = p->pRight;
}else{
break;
}
}
w.xExprCallback = impliesNotNullRow;
w.xSelectCallback = 0;
w.xSelectCallback2 = 0;
+8 -1
View File
@@ -2275,6 +2275,13 @@ static int xferOptimization(
if( pSrcIdx==0 ){
return 0; /* pDestIdx has no corresponding index in pSrc */
}
if( pSrcIdx->tnum==pDestIdx->tnum && pSrc->pSchema==pDest->pSchema
&& sqlite3FaultSim(411)==SQLITE_OK ){
/* The sqlite3FaultSim() call allows this corruption test to be
** bypassed during testing, in order to exercise other corruption tests
** further downstream. */
return 0; /* Corrupt schema - two indexes on the same btree */
}
}
#ifndef SQLITE_OMIT_CHECK
if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){
@@ -2352,7 +2359,7 @@ static int xferOptimization(
sqlite3RowidConstraint(pParse, onError, pDest);
sqlite3VdbeJumpHere(v, addr2);
autoIncStep(pParse, regAutoinc, regRowid);
}else if( pDest->pIndex==0 && !(db->mDbFlags & DBFLAG_Vacuum) ){
}else if( pDest->pIndex==0 && !(db->mDbFlags & DBFLAG_VacuumInto) ){
addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid);
}else{
addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid);
+5 -2
View File
@@ -455,10 +455,13 @@ static const sqlite3_api_routines sqlite3Apis = {
sqlite3_create_window_function,
/* Version 3.26.0 and later */
#ifdef SQLITE_ENABLE_NORMALIZE
sqlite3_normalized_sql
sqlite3_normalized_sql,
#else
0
0,
#endif
/* Version 3.28.0 and later */
sqlite3_stmt_isexplain,
sqlite3_value_frombind
};
/*
+56 -21
View File
@@ -193,9 +193,7 @@ columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);}
// improve performance and reduce the executable size. The goal here is
// to get the "jump" operations in ISNULL through ESCAPE to have numeric
// values that are early enough so that all jump operations are clustered
// at the beginning, but also so that the comparison tokens NE through GE
// are as large as possible so that they are near to FUNCTION, which is a
// token synthesized by addopcodes.tcl.
// at the beginning.
//
%token ABORT ACTION AFTER ANALYZE ASC ATTACH BEFORE BEGIN BY CASCADE CAST.
%token CONFLICT DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL.
@@ -1694,33 +1692,30 @@ frame_opt(A) ::= . {
frame_opt(A) ::= range_or_rows(X) frame_bound_s(Y) frame_exclude_opt(Z). {
A = sqlite3WindowAlloc(pParse, X, Y.eType, Y.pExpr, TK_CURRENT, 0, Z);
}
frame_opt(A) ::= range_or_rows(X) BETWEEN frame_bound_s(Y) AND frame_bound_e(Z) frame_exclude_opt(W). {
frame_opt(A) ::= range_or_rows(X) BETWEEN frame_bound_s(Y) AND
frame_bound_e(Z) frame_exclude_opt(W). {
A = sqlite3WindowAlloc(pParse, X, Y.eType, Y.pExpr, Z.eType, Z.pExpr, W);
}
range_or_rows(A) ::= RANGE. { A = TK_RANGE; }
range_or_rows(A) ::= ROWS. { A = TK_ROWS; }
range_or_rows(A) ::= GROUPS. { A = TK_GROUPS;}
range_or_rows(A) ::= RANGE|ROWS|GROUPS(X). {A = @X; /*A-overwrites-X*/}
frame_bound_s(A) ::= frame_bound(X). {A = X;}
frame_bound_s(A) ::= UNBOUNDED(X) PRECEDING. {A.eType = @X; A.pExpr = 0;}
frame_bound_e(A) ::= frame_bound(X). {A = X;}
frame_bound_e(A) ::= UNBOUNDED(X) FOLLOWING. {A.eType = @X; A.pExpr = 0;}
frame_bound_s(A) ::= frame_bound(X). { A = X; }
frame_bound_s(A) ::= UNBOUNDED PRECEDING. {A.eType = TK_UNBOUNDED; A.pExpr = 0;}
frame_bound_e(A) ::= frame_bound(X). { A = X; }
frame_bound_e(A) ::= UNBOUNDED FOLLOWING. {A.eType = TK_UNBOUNDED; A.pExpr = 0;}
frame_bound(A) ::= expr(X) PRECEDING. { A.eType = TK_PRECEDING; A.pExpr = X; }
frame_bound(A) ::= CURRENT ROW. { A.eType = TK_CURRENT ; A.pExpr = 0; }
frame_bound(A) ::= expr(X) FOLLOWING. { A.eType = TK_FOLLOWING; A.pExpr = X; }
frame_bound(A) ::= expr(X) PRECEDING|FOLLOWING(Y).
{A.eType = @Y; A.pExpr = X;}
frame_bound(A) ::= CURRENT(X) ROW. {A.eType = @X; A.pExpr = 0;}
%type frame_exclude_opt {u8}
frame_exclude_opt(A) ::= . { A = 0; }
frame_exclude_opt(A) ::= EXCLUDE frame_exclude(X). { A = X; }
frame_exclude_opt(A) ::= . {A = 0;}
frame_exclude_opt(A) ::= EXCLUDE frame_exclude(X). {A = X;}
%type frame_exclude {u8}
frame_exclude(A) ::= NO OTHERS. { A = 0; }
frame_exclude(A) ::= CURRENT ROW. { A = TK_CURRENT; }
frame_exclude(A) ::= GROUP. { A = TK_GROUP; }
frame_exclude(A) ::= TIES. { A = TK_TIES; }
frame_exclude(A) ::= NO(X) OTHERS. {A = @X; /*A-overwrites-X*/}
frame_exclude(A) ::= CURRENT(X) ROW. {A = @X; /*A-overwrites-X*/}
frame_exclude(A) ::= GROUP|TIES(X). {A = @X; /*A-overwrites-X*/}
%type window_clause {Window*}
@@ -1747,3 +1742,43 @@ over_clause(A) ::= filter_opt(W) OVER nm(Z). {
filter_opt(A) ::= . { A = 0; }
filter_opt(A) ::= FILTER LP WHERE expr(X) RP. { A = X; }
%endif /* SQLITE_OMIT_WINDOWFUNC */
/*
** The code generator needs some extra TK_ token values for tokens that
** are synthesized and do not actually appear in the grammar:
*/
%token
TRUEFALSE /* True or false keyword */
ISNOT /* Combination of IS and NOT */
FUNCTION /* A function invocation */
COLUMN /* Reference to a table column */
AGG_FUNCTION /* An aggregate function */
AGG_COLUMN /* An aggregated column */
UMINUS /* Unary minus */
UPLUS /* Unary plus */
TRUTH /* IS TRUE or IS FALSE or IS NOT TRUE or IS NOT FALSE */
REGISTER /* Reference to a VDBE register */
VECTOR /* Vector */
SELECT_COLUMN /* Choose a single column from a multi-column SELECT */
IF_NULL_ROW /* the if-null-row operator */
ASTERISK /* The "*" in count(*) and similar */
SPAN /* The span operator */
.
/* There must be no more than 255 tokens defined above. If this grammar
** is extended with new rules and tokens, they must either be so few in
** number that TK_SPAN is no more than 255, or else the new tokens must
** appear after this line.
*/
%include {
#if TK_SPAN>255
# error too many tokens in the grammar
#endif
}
/*
** The TK_SPACE and TK_ILLEGAL tokens must be the last two tokens. The
** parser depends on this. Those tokens are not used in any grammar rule.
** They are only used by the tokenizer. Declare them last so that they
** are guaranteed to be the last two tokens
*/
%token SPACE ILLEGAL.
+1
View File
@@ -137,6 +137,7 @@ static void setStrAccumError(StrAccum *p, u8 eError){
assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG );
p->accError = eError;
if( p->mxAlloc ) sqlite3_str_reset(p);
if( eError==SQLITE_TOOBIG ) sqlite3ErrorToParser(p->db, eError);
}
/*
+1 -1
View File
@@ -4980,7 +4980,7 @@ SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
** <td>&rarr;&nbsp;&nbsp;<td>True if the column is unchanged in an UPDATE
** against a virtual table.
** <tr><td><b>sqlite3_value_frombind&nbsp;&nbsp;</b>
** <td>&rarr;&nbsp;&nbsp;<td>True if value originated a bound parameter
** <td>&rarr;&nbsp;&nbsp;<td>True if value originated from a [bound parameter]
** </table></blockquote>
**
** <b>Details:</b>
+6
View File
@@ -319,6 +319,9 @@ struct sqlite3_api_routines {
void(*xDestroy)(void*));
/* Version 3.26.0 and later */
const char *(*normalized_sql)(sqlite3_stmt*);
/* Version 3.28.0 and later */
int (*stmt_isexplain)(sqlite3_stmt*);
int (*value_frombind)(sqlite3_value*);
};
/*
@@ -608,6 +611,9 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_create_window_function sqlite3_api->create_window_function
/* Version 3.26.0 and later */
#define sqlite3_normalized_sql sqlite3_api->normalized_sql
/* Version 3.28.0 and later */
#define sqlite3_stmt_isexplain sqlite3_api->isexplain
#define sqlite3_value_frombind sqlite3_api->frombind
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
+4 -2
View File
@@ -1565,7 +1565,8 @@ struct sqlite3 {
#define DBFLAG_SchemaChange 0x0001 /* Uncommitted Hash table changes */
#define DBFLAG_PreferBuiltin 0x0002 /* Preference to built-in funcs */
#define DBFLAG_Vacuum 0x0004 /* Currently in a VACUUM */
#define DBFLAG_SchemaKnownOk 0x0008 /* Schema is known to be valid */
#define DBFLAG_VacuumInto 0x0008 /* Currently running VACUUM INTO */
#define DBFLAG_SchemaKnownOk 0x0010 /* Schema is known to be valid */
/*
** Bits of the sqlite3.dbOptFlags field that are used by the
@@ -1573,7 +1574,7 @@ struct sqlite3 {
** selectively disable various optimizations.
*/
#define SQLITE_QueryFlattener 0x0001 /* Query flattening */
/* 0x0002 available for reuse */
#define SQLITE_WindowFunc 0x0002 /* Use xInverse for window functions */
#define SQLITE_GroupByOrder 0x0004 /* GROUPBY cover of ORDERBY */
#define SQLITE_FactorOutConst 0x0008 /* Constant factoring */
#define SQLITE_DistinctOpt 0x0010 /* DISTINCT using indexes */
@@ -3833,6 +3834,7 @@ char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
void sqlite3SetString(char **, sqlite3*, const char*);
void sqlite3ErrorMsg(Parse*, const char*, ...);
int sqlite3ErrorToParser(sqlite3*,int);
void sqlite3Dequote(char*);
void sqlite3DequoteExpr(Expr*);
void sqlite3TokenInit(Token*,char*);
+22 -22
View File
@@ -64,7 +64,7 @@ static Thread threadset[N_THREAD];
/*
** The main loop for a thread. Threads use busy waiting.
*/
static void *thread_main(void *pArg){
static void *test_thread_main(void *pArg){
Thread *p = (Thread*)pArg;
if( p->db ){
sqlite3_close(p->db);
@@ -151,7 +151,7 @@ static int SQLITE_TCLAPI tcl_thread_create(
threadset[i].zFilename = sqlite3_mprintf("%s", argv[2]);
threadset[i].opnum = 1;
threadset[i].completed = 0;
rc = pthread_create(&x, 0, thread_main, &threadset[i]);
rc = pthread_create(&x, 0, test_thread_main, &threadset[i]);
if( rc ){
Tcl_AppendResult(interp, "failed to create the thread", 0);
sqlite3_free(threadset[i].zFilename);
@@ -165,7 +165,7 @@ static int SQLITE_TCLAPI tcl_thread_create(
/*
** Wait for a thread to reach its idle state.
*/
static void thread_wait(Thread *p){
static void test_thread_wait(Thread *p){
while( p->opnum>p->completed ) sched_yield();
}
@@ -193,18 +193,18 @@ static int SQLITE_TCLAPI tcl_thread_wait(
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[i]);
test_thread_wait(&threadset[i]);
return TCL_OK;
}
/*
** Stop a thread.
*/
static void stop_thread(Thread *p){
thread_wait(p);
static void test_stop_thread(Thread *p){
test_thread_wait(p);
p->xOp = 0;
p->opnum++;
thread_wait(p);
test_thread_wait(p);
sqlite3_free(p->zArg);
p->zArg = 0;
sqlite3_free(p->zFilename);
@@ -233,7 +233,7 @@ static int SQLITE_TCLAPI tcl_thread_halt(
}
if( argv[1][0]=='*' && argv[1][1]==0 ){
for(i=0; i<N_THREAD; i++){
if( threadset[i].busy ) stop_thread(&threadset[i]);
if( threadset[i].busy ) test_stop_thread(&threadset[i]);
}
}else{
i = parse_thread_id(interp, argv[1]);
@@ -242,7 +242,7 @@ static int SQLITE_TCLAPI tcl_thread_halt(
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
stop_thread(&threadset[i]);
test_stop_thread(&threadset[i]);
}
return TCL_OK;
}
@@ -273,7 +273,7 @@ static int SQLITE_TCLAPI tcl_thread_argc(
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[i]);
test_thread_wait(&threadset[i]);
sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", threadset[i].argc);
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
@@ -306,7 +306,7 @@ static int SQLITE_TCLAPI tcl_thread_argv(
return TCL_ERROR;
}
if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
thread_wait(&threadset[i]);
test_thread_wait(&threadset[i]);
if( n<0 || n>=threadset[i].argc ){
Tcl_AppendResult(interp, "column number out of range", 0);
return TCL_ERROR;
@@ -342,7 +342,7 @@ static int SQLITE_TCLAPI tcl_thread_colname(
return TCL_ERROR;
}
if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
thread_wait(&threadset[i]);
test_thread_wait(&threadset[i]);
if( n<0 || n>=threadset[i].argc ){
Tcl_AppendResult(interp, "column number out of range", 0);
return TCL_ERROR;
@@ -377,7 +377,7 @@ static int SQLITE_TCLAPI tcl_thread_result(
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[i]);
test_thread_wait(&threadset[i]);
zName = sqlite3ErrName(threadset[i].rc);
Tcl_AppendResult(interp, zName, 0);
return TCL_OK;
@@ -408,7 +408,7 @@ static int SQLITE_TCLAPI tcl_thread_error(
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[i]);
test_thread_wait(&threadset[i]);
Tcl_AppendResult(interp, threadset[i].zErr, 0);
return TCL_OK;
}
@@ -452,7 +452,7 @@ static int SQLITE_TCLAPI tcl_thread_compile(
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[i]);
test_thread_wait(&threadset[i]);
threadset[i].xOp = do_compile;
sqlite3_free(threadset[i].zArg);
threadset[i].zArg = sqlite3_mprintf("%s", argv[2]);
@@ -505,7 +505,7 @@ static int SQLITE_TCLAPI tcl_thread_step(
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[i]);
test_thread_wait(&threadset[i]);
threadset[i].xOp = do_step;
threadset[i].opnum++;
return TCL_OK;
@@ -547,7 +547,7 @@ static int SQLITE_TCLAPI tcl_thread_finalize(
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[i]);
test_thread_wait(&threadset[i]);
threadset[i].xOp = do_finalize;
sqlite3_free(threadset[i].zArg);
threadset[i].zArg = 0;
@@ -579,14 +579,14 @@ static int SQLITE_TCLAPI tcl_thread_swap(
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[i]);
test_thread_wait(&threadset[i]);
j = parse_thread_id(interp, argv[2]);
if( j<0 ) return TCL_ERROR;
if( !threadset[j].busy ){
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[j]);
test_thread_wait(&threadset[j]);
temp = threadset[i].db;
threadset[i].db = threadset[j].db;
threadset[j].db = temp;
@@ -620,7 +620,7 @@ static int SQLITE_TCLAPI tcl_thread_db_get(
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[i]);
test_thread_wait(&threadset[i]);
sqlite3TestMakePointerStr(interp, zBuf, threadset[i].db);
threadset[i].db = 0;
Tcl_AppendResult(interp, zBuf, (char*)0);
@@ -651,7 +651,7 @@ static int SQLITE_TCLAPI tcl_thread_db_put(
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[i]);
test_thread_wait(&threadset[i]);
assert( !threadset[i].db );
threadset[i].db = (sqlite3*)sqlite3TestTextToPtr(argv[2]);
return TCL_OK;
@@ -683,7 +683,7 @@ static int SQLITE_TCLAPI tcl_thread_stmt_get(
Tcl_AppendResult(interp, "no such thread", 0);
return TCL_ERROR;
}
thread_wait(&threadset[i]);
test_thread_wait(&threadset[i]);
sqlite3TestMakePointerStr(interp, zBuf, threadset[i].pStmt);
threadset[i].pStmt = 0;
Tcl_AppendResult(interp, zBuf, (char*)0);
+2
View File
@@ -106,6 +106,7 @@ const char *sqlite3TestInit(Tcl_Interp *interp){
#endif
extern int TestExpert_Init(Tcl_Interp*);
extern int Sqlitetest_window_Init(Tcl_Interp *);
extern int Sqlitetestvdbecov_Init(Tcl_Interp *);
Tcl_CmdInfo cmdInfo;
@@ -171,6 +172,7 @@ const char *sqlite3TestInit(Tcl_Interp *interp){
#endif
TestExpert_Init(interp);
Sqlitetest_window_Init(interp);
Sqlitetestvdbecov_Init(interp);
Tcl_CreateObjCommand(
interp, "load_testfixture_extensions", load_testfixture_extensions,0,0
+120
View File
@@ -0,0 +1,120 @@
/*
** 2019 April 02
**
** 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.
**
******************************************************************************
**
*/
#if SQLITE_TEST /* This file is used for testing only */
#include "sqlite3.h"
#include "sqliteInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#ifdef SQLITE_VDBE_COVERAGE
static u8 aBranchArray[200000];
static void test_vdbe_branch(
void *pCtx,
unsigned int iSrc,
unsigned char iBranch,
unsigned char iType
){
if( iSrc<sizeof(aBranchArray) ){
aBranchArray[iSrc] |= iBranch;
}
}
static void appendToList(
Tcl_Obj *pList,
int iLine,
int iPath,
const char *zNever
){
Tcl_Obj *pNew = Tcl_NewObj();
Tcl_IncrRefCount(pNew);
Tcl_ListObjAppendElement(0, pNew, Tcl_NewIntObj(iLine));
Tcl_ListObjAppendElement(0, pNew, Tcl_NewIntObj(iPath));
Tcl_ListObjAppendElement(0, pNew, Tcl_NewStringObj(zNever, -1));
Tcl_ListObjAppendElement(0, pList, pNew);
Tcl_DecrRefCount(pNew);
}
static int SQLITE_TCLAPI test_vdbe_coverage(
ClientData cd,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
const char *aSub[] = { "start", "report", "stop", 0 };
int iSub = -1;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "sub-command");
return TCL_ERROR;
}
if( Tcl_GetIndexFromObj(interp, objv[1], aSub, "sub-command", 0, &iSub) ){
return TCL_ERROR;
}
Tcl_ResetResult(interp);
assert( iSub==0 || iSub==1 || iSub==2 );
switch( iSub ){
case 0: /* start */
memset(aBranchArray, 0, sizeof(aBranchArray));
sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE, test_vdbe_branch, 0);
break;
case 1: { /* report */
int i;
Tcl_Obj *pRes = Tcl_NewObj();
Tcl_IncrRefCount(pRes);
for(i=0; i<sizeof(aBranchArray); i++){
u8 b = aBranchArray[i];
int bFlag = ((b >> 4)==4);
if( b ){
if( (b & 0x01)==0 ){
appendToList(pRes, i, 0, bFlag ? "less than" : "falls through");
}
if( (b & 0x02)==0 ){
appendToList(pRes, i, 1, bFlag ? "equal" : "taken");
}
if( (b & 0x04)==0 ){
appendToList(pRes, i, 2, bFlag ? "greater-than" : "NULL");
}
}
}
Tcl_SetObjResult(interp, pRes);
Tcl_DecrRefCount(pRes);
break;
};
default: /* stop */
sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE, 0, 0);
break;
}
return TCL_OK;
}
#endif /* SQLITE_VDBE_COVERAGE */
int Sqlitetestvdbecov_Init(Tcl_Interp *interp){
#ifdef SQLITE_VDBE_COVERAGE
Tcl_CreateObjCommand(interp, "vdbe_coverage", test_vdbe_coverage, 0, 0);
#endif
return TCL_OK;
}
#endif
+2
View File
@@ -235,6 +235,7 @@ static int tvfsResultCode(Testvfs *p, int *pRc){
{ SQLITE_BUSY, "SQLITE_BUSY" },
{ SQLITE_READONLY, "SQLITE_READONLY" },
{ SQLITE_READONLY_CANTINIT, "SQLITE_READONLY_CANTINIT" },
{ -1, "SQLITE_OMIT" },
};
const char *z;
@@ -382,6 +383,7 @@ static int tvfsWrite(
Tcl_NewWideIntObj(iOfst), Tcl_NewIntObj(iAmt)
);
tvfsResultCode(p, &rc);
if( rc<0 ) return SQLITE_OK;
}
if( rc==SQLITE_OK && tvfsInjectFullerr(p) ){
+28 -7
View File
@@ -32,15 +32,23 @@ void sqlite3Coverage(int x){
#endif
/*
** Give a callback to the test harness that can be used to simulate faults
** in places where it is difficult or expensive to do so purely by means
** of inputs.
** Calls to sqlite3FaultSim() are used to simulate a failure during testing,
** or to bypass normal error detection during testing in order to let
** execute proceed futher downstream.
**
** The intent of the integer argument is to let the fault simulator know
** which of multiple sqlite3FaultSim() calls has been hit.
** In deployment, sqlite3FaultSim() *always* return SQLITE_OK (0). The
** sqlite3FaultSim() function only returns non-zero during testing.
**
** Return whatever integer value the test callback returns, or return
** SQLITE_OK if no test callback is installed.
** During testing, if the test harness has set a fault-sim callback using
** a call to sqlite3_test_control(SQLITE_TESTCTRL_FAULT_INSTALL), then
** each call to sqlite3FaultSim() is relayed to that application-supplied
** callback and the integer return value form the application-supplied
** callback is returned by sqlite3FaultSim().
**
** The integer argument to sqlite3FaultSim() is a code to identify which
** sqlite3FaultSim() instance is being invoked. Each call to sqlite3FaultSim()
** should have a unique code. To prevent legacy testing applications from
** breaking, the codes should not be changed or reused.
*/
#ifndef SQLITE_UNTESTABLE
int sqlite3FaultSim(int iTest){
@@ -225,6 +233,19 @@ void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){
}
}
/*
** If database connection db is currently parsing SQL, then transfer
** error code errCode to that parser if the parser has not already
** encountered some other kind of error.
*/
int sqlite3ErrorToParser(sqlite3 *db, int errCode){
Parse *pParse;
if( db==0 || (pParse = db->pParse)==0 ) return errCode;
pParse->rc = errCode;
pParse->nErr++;
return errCode;
}
/*
** Convert an SQL-style quoted string into a normal string by removing
** the quote characters. The conversion is done in-place. If the
+4 -3
View File
@@ -139,7 +139,7 @@ build_vacuum_end:
/*
** This routine implements the OP_Vacuum opcode of the VDBE.
*/
int sqlite3RunVacuum(
SQLITE_NOINLINE int sqlite3RunVacuum(
char **pzErrMsg, /* Write error message here */
sqlite3 *db, /* Database connection */
int iDb, /* Which attached DB to vacuum */
@@ -163,11 +163,11 @@ int sqlite3RunVacuum(
if( !db->autoCommit ){
sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction");
return SQLITE_ERROR;
return SQLITE_ERROR; /* IMP: R-12218-18073 */
}
if( db->nVdbeActive>1 ){
sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress");
return SQLITE_ERROR;
return SQLITE_ERROR; /* IMP: R-15610-35227 */
}
saved_openFlags = db->openFlags;
if( pOut ){
@@ -230,6 +230,7 @@ int sqlite3RunVacuum(
sqlite3SetString(pzErrMsg, db, "output file already exists");
goto end_of_vacuum;
}
db->mDbFlags |= DBFLAG_VacuumInto;
}
nRes = sqlite3BtreeGetOptimalReserve(pMain);
+33 -18
View File
@@ -122,12 +122,20 @@ int sqlite3_found_count = 0;
** feature is used for test suite validation only and does not appear an
** production builds.
**
** M is an integer between 2 and 4. 2 indicates a ordinary two-way
** branch (I=0 means fall through and I=1 means taken). 3 indicates
** a 3-way branch where the third way is when one of the operands is
** NULL. 4 indicates the OP_Jump instruction which has three destinations
** depending on whether the first operand is less than, equal to, or greater
** than the second.
** M is the type of branch. I is the direction taken for this instance of
** the branch.
**
** M: 2 - two-way branch (I=0: fall-thru 1: jump )
** 3 - two-way + NULL (I=0: fall-thru 1: jump 2: NULL )
** 4 - OP_Jump (I=0: jump p1 1: jump p2 2: jump p3)
**
** In other words, if M is 2, then I is either 0 (for fall-through) or
** 1 (for when the branch is taken). If M is 3, the I is 0 for an
** ordinary fall-through, I is 1 if the branch was taken, and I is 2
** if the result of comparison is NULL. For M=3, I=2 the jump may or
** may not be taken, depending on the SQLITE_JUMPIFNULL flags in p5.
** When M is 4, that means that an OP_Jump is being run. I is 0, 1, or 2
** depending on if the operands are less than, equal, or greater than.
**
** iSrcLine is the source code line (from the __LINE__ macro) that
** generated the VDBE instruction combined with flag bits. The source
@@ -138,9 +146,9 @@ int sqlite3_found_count = 0;
** alternate branch are never taken. If a branch is never taken then
** flags should be 0x06 since only the fall-through approach is allowed.
**
** Bit 0x04 of the flags indicates an OP_Jump opcode that is only
** Bit 0x08 of the flags indicates an OP_Jump opcode that is only
** interested in equal or not-equal. In other words, I==0 and I==2
** should be treated the same.
** should be treated as equivalent
**
** Since only a line number is retained, not the filename, this macro
** only works for amalgamation builds. But that is ok, since these macros
@@ -164,6 +172,18 @@ int sqlite3_found_count = 0;
mNever = iSrcLine >> 24;
assert( (I & mNever)==0 );
if( sqlite3GlobalConfig.xVdbeBranch==0 ) return; /*NO_TEST*/
/* Invoke the branch coverage callback with three arguments:
** iSrcLine - the line number of the VdbeCoverage() macro, with
** flags removed.
** I - Mask of bits 0x07 indicating which cases are are
** fulfilled by this instance of the jump. 0x01 means
** fall-thru, 0x02 means taken, 0x04 means NULL. Any
** impossible cases (ex: if the comparison is never NULL)
** are filled in automatically so that the coverage
** measurement logic does not flag those impossible cases
** as missed coverage.
** M - Type of jump. Same as M argument above
*/
I |= mNever;
if( M==2 ) I |= 0x04;
if( M==4 ){
@@ -1737,8 +1757,8 @@ case OP_MustBeInt: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
if( (pIn1->flags & MEM_Int)==0 ){
applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding);
VdbeBranchTaken((pIn1->flags&MEM_Int)==0, 2);
if( (pIn1->flags & MEM_Int)==0 ){
VdbeBranchTaken(1, 2);
if( pOp->p2==0 ){
rc = SQLITE_MISMATCH;
goto abort_due_to_error;
@@ -1747,6 +1767,7 @@ case OP_MustBeInt: { /* jump, in1 */
}
}
}
VdbeBranchTaken(0, 2);
MemSetTypeFlag(pIn1, MEM_Int);
break;
}
@@ -2047,7 +2068,7 @@ compare_op:
pOut->u.i = res2;
REGISTER_TRACE(pOp->p2, pOut);
}else{
VdbeBranchTaken(res!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3);
VdbeBranchTaken(res2!=0, (pOp->p5 & SQLITE_NULLEQ)?2:3);
if( res2 ){
goto jump_to_p2;
}
@@ -5117,7 +5138,7 @@ case OP_Sort: { /* jump */
p->aCounter[SQLITE_STMTSTATUS_SORT]++;
/* Fall through into OP_Rewind */
}
/* Opcode: Rewind P1 P2 * * P5
/* Opcode: Rewind P1 P2 * * *
**
** The next use of the Rowid or Column or Next instruction for P1
** will refer to the first entry in the database table or index.
@@ -5125,10 +5146,6 @@ case OP_Sort: { /* jump */
** If the table or index is not empty, fall through to the following
** instruction.
**
** If P5 is non-zero and the table is not empty, then the "skip-next"
** flag is set on the cursor so that the next OP_Next instruction
** executed on it is a no-op.
**
** This opcode leaves the cursor configured to move in forward order,
** from the beginning toward the end. In other words, the cursor is
** configured to use Next, not Prev.
@@ -5139,6 +5156,7 @@ case OP_Rewind: { /* jump */
int res;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p5==0 );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) );
@@ -5153,9 +5171,6 @@ case OP_Rewind: { /* jump */
pCrsr = pC->uc.pCursor;
assert( pCrsr );
rc = sqlite3BtreeFirst(pCrsr, &res);
#ifndef SQLITE_OMIT_WINDOWFUNC
if( pOp->p5 ) sqlite3BtreeSkipNext(pCrsr);
#endif
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
}
+7 -1
View File
@@ -250,7 +250,7 @@ struct sqlite3_value {
/* Available 0x0040 */
#define MEM_Undefined 0x0080 /* Value is undefined */
#define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */
#define MEM_TypeMask 0xc1ff /* Mask of type bits */
#define MEM_TypeMask 0xc1df /* Mask of type bits */
/* Whenever Mem contains a valid string or blob representation, one of
@@ -282,6 +282,12 @@ struct sqlite3_value {
#define MemSetTypeFlag(p, f) \
((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f)
/*
** True if Mem X is a NULL-nochng type.
*/
#define MemNullNochng(X) \
((X)->flags==(MEM_Null|MEM_Zero) && (X)->n==0 && (X)->u.nZero==0)
/*
** Return true if a memory cell is not marked as invalid. This macro
** is for use inside assert() statements only.
+4 -2
View File
@@ -298,13 +298,15 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){
int sqlite3VdbeMemExpandBlob(Mem *pMem){
int nByte;
assert( pMem->flags & MEM_Zero );
assert( pMem->flags&MEM_Blob );
assert( (pMem->flags&MEM_Blob)!=0 || MemNullNochng(pMem) );
testcase( sqlite3_value_nochange(pMem) );
assert( !sqlite3VdbeMemIsRowSet(pMem) );
assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
/* Set nByte to the number of bytes required to store the expanded blob. */
nByte = pMem->n + pMem->u.nZero;
if( nByte<=0 ){
if( (pMem->flags & MEM_Blob)==0 ) return SQLITE_OK;
nByte = 1;
}
if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){
@@ -1061,7 +1063,7 @@ int sqlite3VdbeMemSetStr(
nAlloc += (enc==SQLITE_UTF8?1:2);
}
if( nByte>iLimit ){
return SQLITE_TOOBIG;
return sqlite3ErrorToParser(pMem->db, SQLITE_TOOBIG);
}
testcase( nAlloc==0 );
testcase( nAlloc==31 );
+4 -2
View File
@@ -986,6 +986,7 @@ static void walCleanupHash(Wal *pWal){
int iLimit = 0; /* Zero values greater than this */
int nByte; /* Number of bytes to zero in aPgno[] */
int i; /* Used to iterate through aHash[] */
int rc; /* Return code form walHashGet() */
assert( pWal->writeLock );
testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE-1 );
@@ -996,11 +997,12 @@ static void walCleanupHash(Wal *pWal){
/* Obtain pointers to the hash-table and page-number array containing
** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed
** that the page said hash-table and array reside on is already mapped.
** that the page said hash-table and array reside on is already mapped.(1)
*/
assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) );
assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] );
walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &sLoc);
rc = walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &sLoc);
if( NEVER(rc) ) return; /* Defense-in-depth, in case (1) above is wrong */
/* Zero all hash-table entries that correspond to frame numbers greater
** than pWal->hdr.mxFrame.
+5 -5
View File
@@ -3335,11 +3335,11 @@ static int whereLoopAddVirtual(
rc = whereLoopAddVirtualOne(pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn);
/* If the call to xBestIndex() with all terms enabled produced a plan
** that does not require any source tables (IOW: a plan with mBest==0),
** then there is no point in making any further calls to xBestIndex()
** since they will all return the same result (if the xBestIndex()
** implementation is sane). */
if( rc==SQLITE_OK && (mBest = (pNew->prereq & ~mPrereq))!=0 ){
** that does not require any source tables (IOW: a plan with mBest==0)
** and does not use an IN(...) operator, then there is no point in making
** any further calls to xBestIndex() since they will all return the same
** result (if the xBestIndex() implementation is sane). */
if( rc==SQLITE_OK && ((mBest = (pNew->prereq & ~mPrereq))!=0 || bIn) ){
int seenZero = 0; /* True if a plan with no prereqs seen */
int seenZeroNoIN = 0; /* Plan with no prereqs and no IN(...) seen */
Bitmask mPrev = 0;
+8 -2
View File
@@ -1967,7 +1967,12 @@ Bitmask sqlite3WhereCodeOneLoopStart(
pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr);
}
if( pAndExpr ){
pAndExpr = sqlite3PExpr(pParse, TK_AND|TKFLG_DONTFOLD, 0, pAndExpr);
/* The extra 0x10000 bit on the opcode is masked off and does not
** become part of the new Expr.op. However, it does make the
** op==TK_AND comparison inside of sqlite3PExpr() false, and this
** prevents sqlite3PExpr() from implementing AND short-circuit
** optimization, which we do not want here. */
pAndExpr = sqlite3PExpr(pParse, TK_AND|0x10000, 0, pAndExpr);
}
}
@@ -2197,8 +2202,9 @@ Bitmask sqlite3WhereCodeOneLoopStart(
u32 x = pLevel->iLikeRepCntr;
if( x>0 ){
skipLikeAddr = sqlite3VdbeAddOp1(v, (x&1)?OP_IfNot:OP_If,(int)(x>>1));
VdbeCoverageIf(v, (x&1)==1);
VdbeCoverageIf(v, (x&1)==0);
}
VdbeCoverage(v);
#endif
}
#ifdef WHERETRACE_ENABLED /* 0xffff */
+38 -18
View File
@@ -1092,7 +1092,7 @@ Window *sqlite3WindowAlloc(
pWin->eFrmType = eType;
pWin->eStart = eStart;
pWin->eEnd = eEnd;
if( eExclude==0 && OptimizationDisabled(pParse->db, SQLITE_QueryFlattener) ){
if( eExclude==0 && OptimizationDisabled(pParse->db, SQLITE_WindowFunc) ){
eExclude = TK_NO;
}
pWin->eExclude = eExclude;
@@ -1309,21 +1309,25 @@ static void windowCheckValue(Parse *pParse, int reg, int eCond){
int regString = sqlite3GetTempReg(pParse);
sqlite3VdbeAddOp4(v, OP_String8, 0, regString, 0, "", P4_STATIC);
sqlite3VdbeAddOp3(v, OP_Ge, regString, sqlite3VdbeCurrentAddr(v)+2, reg);
sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC);
sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC|SQLITE_JUMPIFNULL);
VdbeCoverage(v);
assert( eCond==3 || eCond==4 );
VdbeCoverageIf(v, eCond==3);
VdbeCoverageIf(v, eCond==4);
}else{
sqlite3VdbeAddOp2(v, OP_MustBeInt, reg, sqlite3VdbeCurrentAddr(v)+2);
VdbeCoverage(v);
assert( eCond==0 || eCond==1 || eCond==2 );
VdbeCoverageIf(v, eCond==0);
VdbeCoverageIf(v, eCond==1);
VdbeCoverageIf(v, eCond==2);
}
VdbeCoverageIf(v, eCond==0);
VdbeCoverageIf(v, eCond==1);
VdbeCoverageIf(v, eCond==2);
VdbeCoverageIf(v, eCond==3);
VdbeCoverageIf(v, eCond==4);
sqlite3VdbeAddOp3(v, aOp[eCond], regZero, sqlite3VdbeCurrentAddr(v)+2, reg);
VdbeCoverageNeverNullIf(v, eCond==0);
VdbeCoverageNeverNullIf(v, eCond==1);
VdbeCoverageNeverNullIf(v, eCond==0); /* NULL case captured by */
VdbeCoverageNeverNullIf(v, eCond==1); /* the OP_MustBeInt */
VdbeCoverageNeverNullIf(v, eCond==2);
VdbeCoverageNeverNullIf(v, eCond==3);
VdbeCoverageNeverNullIf(v, eCond==4);
VdbeCoverageNeverNullIf(v, eCond==3); /* NULL case caught by */
VdbeCoverageNeverNullIf(v, eCond==4); /* the OP_Ge */
sqlite3MayAbort(pParse);
sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_ERROR, OE_Abort);
sqlite3VdbeAppendP4(v, (void*)azErr[eCond], P4_STATIC);
@@ -1573,6 +1577,7 @@ static void windowFullScan(WindowCodeArg *p){
if( pMWin->eExclude==TK_CURRENT ){
sqlite3VdbeAddOp3(v, OP_Eq, regCRowid, lblNext, regRowid);
VdbeCoverageNeverNull(v);
}else if( pMWin->eExclude!=TK_NO ){
int addr;
int addrEq = 0;
@@ -1583,6 +1588,7 @@ static void windowFullScan(WindowCodeArg *p){
}
if( pMWin->eExclude==TK_TIES ){
addrEq = sqlite3VdbeAddOp3(v, OP_Eq, regCRowid, 0, regRowid);
VdbeCoverageNeverNull(v);
}
if( pKeyInfo ){
windowReadPeerValues(p, csr, regPeer);
@@ -1833,9 +1839,13 @@ static void windowCodeRangeTest(
VdbeCoverage(v);
sqlite3VdbeAddOp3(v, arith, regVal, reg1, reg1);
sqlite3VdbeJumpHere(v, addrGe);
sqlite3VdbeAddOp3(v, op, reg2, lbl, reg1);
sqlite3VdbeAddOp3(v, op, reg2, lbl, reg1); VdbeCoverage(v);
sqlite3VdbeChangeP5(v, SQLITE_NULLEQ);
VdbeCoverage(v);
assert( op==OP_Ge || op==OP_Gt || op==OP_Lt || op==OP_Le );
testcase(op==OP_Ge); VdbeCoverageIf(v, op==OP_Ge);
testcase(op==OP_Lt); VdbeCoverageIf(v, op==OP_Lt);
testcase(op==OP_Le); VdbeCoverageIf(v, op==OP_Le);
testcase(op==OP_Gt); VdbeCoverageIf(v, op==OP_Gt);
sqlite3ReleaseTempReg(pParse, reg1);
sqlite3ReleaseTempReg(pParse, reg2);
@@ -2313,19 +2323,22 @@ static int windowExprGtZero(Parse *pParse, Expr *pExpr){
** regEnd = <expr2>
** regStart = <expr1>
** }else{
** while( (csrEnd.key + regEnd) <= csrCurrent.key ){
** if( (csrEnd.key + regEnd) <= csrCurrent.key ){
** AGGSTEP
** }
** RETURN_ROW
** while( (csrStart.key + regStart) < csrCurrent.key ){
** AGGINVERSE
** }
** RETURN_ROW
** }
** }
** flush:
** while( (csrEnd.key + regEnd) <= csrCurrent.key ){
** AGGSTEP
** }
** while( (csrStart.key + regStart) < csrCurrent.key ){
** AGGINVERSE
** }
** RETURN_ROW
**
** RANGE BETWEEN <expr1> FOLLOWING AND <expr2> FOLLOWING
@@ -2516,7 +2529,7 @@ void sqlite3WindowCodeStep(
sqlite3VdbeAddOp2(v, OP_NewRowid, csrWrite, regRowid);
sqlite3VdbeAddOp3(v, OP_Insert, csrWrite, regRecord, regRowid);
addrNe = sqlite3VdbeAddOp3(v, OP_Ne, pMWin->regOne, 0, regRowid);
VdbeCoverage(v);
VdbeCoverageNeverNull(v);
/* This block is run for the first row of each partition */
s.regArg = windowInitAccum(pParse, pMWin);
@@ -2533,7 +2546,8 @@ void sqlite3WindowCodeStep(
if( pMWin->eStart==pMWin->eEnd && regStart ){
int op = ((pMWin->eStart==TK_FOLLOWING) ? OP_Ge : OP_Le);
int addrGe = sqlite3VdbeAddOp3(v, op, regStart, 0, regEnd);
VdbeCoverage(v);
VdbeCoverageNeverNullIf(v, op==OP_Ge); /* NeverNull because bound <expr> */
VdbeCoverageNeverNullIf(v, op==OP_Le); /* values previously checked */
windowAggFinal(&s, 0);
sqlite3VdbeAddOp2(v, OP_Rewind, s.current.csr, 1);
VdbeCoverageNeverTaken(v);
@@ -2565,6 +2579,8 @@ void sqlite3WindowCodeStep(
sqlite3VdbeAddOp2(v, OP_Goto, 0, lblWhereEnd);
sqlite3VdbeJumpHere(v, addrNe);
/* Beginning of the block executed for the second and subsequent rows. */
if( regPeer ){
windowIfNewPeer(pParse, pOrderBy, regNewPeer, regPeer, lblWhereEnd);
}
@@ -2586,9 +2602,11 @@ void sqlite3WindowCodeStep(
}
}else
if( pMWin->eEnd==TK_PRECEDING ){
int bRPS = (pMWin->eStart==TK_PRECEDING && pMWin->eFrmType==TK_RANGE);
windowCodeOp(&s, WINDOW_AGGSTEP, regEnd, 0);
if( bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0);
windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0);
windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0);
if( !bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0);
}else{
int addr = 0;
windowCodeOp(&s, WINDOW_AGGSTEP, 0, 0);
@@ -2631,7 +2649,9 @@ void sqlite3WindowCodeStep(
addrEmpty = sqlite3VdbeAddOp1(v, OP_Rewind, csrWrite);
VdbeCoverage(v);
if( pMWin->eEnd==TK_PRECEDING ){
int bRPS = (pMWin->eStart==TK_PRECEDING && pMWin->eFrmType==TK_RANGE);
windowCodeOp(&s, WINDOW_AGGSTEP, regEnd, 0);
if( bRPS ) windowCodeOp(&s, WINDOW_AGGINVERSE, regStart, 0);
windowCodeOp(&s, WINDOW_RETURN_ROW, 0, 0);
}else if( pMWin->eStart==TK_FOLLOWING ){
int addrStart;
+24
View File
@@ -16,6 +16,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix autoinc
# If the library is not compiled with autoincrement support then
# skip all tests in this file.
@@ -856,4 +857,27 @@ do_test autoinc-12.7 {
lappend res $msg
} {0 ok}
#--------------------------------------------------------------------------
reset_db
do_execsql_test 13.0 {
CREATE TABLE t1(i INTEGER PRIMARY KEY AUTOINCREMENT, j);
CREATE TABLE t2(i INTEGER PRIMARY KEY AUTOINCREMENT, j);
CREATE TABLE t3(i INTEGER PRIMARY KEY AUTOINCREMENT, j);
INSERT INTO t1 VALUES(NULL, 1);
INSERT INTO t2 VALUES(NULL, 2);
INSERT INTO t3 VALUES(NULL, 3);
SELECT name FROM sqlite_sequence;
} {t1 t2 t3}
do_execsql_test 13.1 {
UPDATE sqlite_sequence SET name=NULL WHERE name='t2';
INSERT INTO t3 VALUES(NULL, 4);
DELETE FROM t3;
INSERT INTO t3 VALUES(NULL, 5);
SELECT * FROM t3;
} {3 5}
finish_test
+57
View File
@@ -266,5 +266,62 @@ do_execsql_test 3.5 {
4 0 ValueB 4 0 ValueB
}
#-------------------------------------------------------------------------
# If there is an IN(..) condition in the WHERE clause of a query on a
# virtual table, the xBestIndex method is first invoked with the IN(...)
# represented by a "usable" SQLITE_INDEX_CONSTRAINT_EQ constraint. If
# the virtual table elects to use the IN(...) constraint, then the
# xBestIndex method is invoked again, this time with the IN(...) marked
# as "not usable". Depending on the relative costs of the two plans as
# defined by the virtual table implementation, and the cardinality of the
# IN(...) operator, SQLite chooses the most efficient plan.
#
# At one point the second invocation of xBestIndex() was only being made
# for join queries. The following tests check that this problem has been
# fixed.
#
proc vtab_command {method args} {
switch -- $method {
xConnect {
return "CREATE TABLE t1(a, b, c, d)"
}
xBestIndex {
set clist [lindex $args 0]
lappend ::bestindex_calls $clist
set ret "cost 1000000 idxnum 555"
for {set i 0} {$i < [llength $clist]} {incr i} {
array set C [lindex $clist $i]
if {$C(usable)} { lappend ret use $i }
}
return $ret
}
}
return {}
}
do_execsql_test 4.0 {
CREATE VIRTUAL TABLE x1 USING tcl(vtab_command);
} {}
do_test 4.1 {
set ::bestindex_calls [list]
execsql {
SELECT * FROM x1 WHERE a=? AND b BETWEEN ? AND ? AND c IN (1, 2, 3, 4);
}
set ::bestindex_calls
} [list \
[list {op eq column 0 usable 1} \
{op eq column 2 usable 1} \
{op ge column 1 usable 1} \
{op le column 1 usable 1} \
] \
[list {op eq column 0 usable 1} \
{op eq column 2 usable 0} \
{op ge column 1 usable 1} \
{op le column 1 usable 1}
]
]
finish_test
+9 -1
View File
@@ -12,7 +12,6 @@
# focus of this file is testing that it is OK to create new tables
# and indices while creating existing tables and indices.
#
# $Id: createtab.test,v 1.3 2007/09/12 17:01:45 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
@@ -142,5 +141,14 @@ for {set av 0} {$av<=$upperBound} {incr av} {
integrity_check createtab-$av.40
}
# 2019-03-31 Ensure that a proper error is returned for an index
# with too many columns.
#
do_test createtab-3.1 {
db eval {DROP TABLE IF EXISTS t1;}
set sql "CREATE TABLE t1(x,UNIQUE(x[string repeat ,x 100000]))"
catchsql $sql
} {1 {too many columns in index}}
finish_test
+77
View File
@@ -183,5 +183,82 @@ do_execsql_test 6.1 {
SELECT x FROM t2;
} {5}
#-------------------------------------------------------------------------
# Test the effect of failing to find a table row based on an index key
# within a DELETE. Either because the db is corrupt, or a trigger on another
# row already deleted the entry, or because a BEFORE trigger on the current
# row has already deleted it.
#
do_execsql_test 7.1.0 {
CREATE TABLE t3(id INT PRIMARY KEY, a, b) WITHOUT ROWID;
CREATE INDEX t3a ON t3(a);
CREATE INDEX t3b ON t3(b);
INSERT INTO t3 VALUES(1, 1, 1);
INSERT INTO t3 VALUES(2, 2, 2);
INSERT INTO t3 VALUES(3, 3, 3);
INSERT INTO t3 VALUES(4, 4, 1);
}
do_execsql_test 7.1.1 {
DELETE FROM t3 WHERE a=4 OR b=1;
}
do_execsql_test 7.1.2 {
SELECT * FROM t3;
} { 2 2 2 3 3 3 }
do_execsql_test 7.2.0 {
CREATE TABLE t4(a PRIMARY KEY, b) WITHOUT ROWID;
CREATE INDEX t4i ON t4(b);
INSERT INTO t4 VALUES(1, 'hello');
INSERT INTO t4 VALUES(2, 'world');
CREATE TABLE t5(a PRIMARY KEY, b) WITHOUT ROWID;
CREATE INDEX t5i ON t5(b);
INSERT INTO t5 VALUES(1, 'hello');
INSERT INTO t5 VALUES(3, 'world');
PRAGMA writable_schema = 1;
UPDATE sqlite_master SET rootpage = (
SELECT rootpage FROM sqlite_master WHERE name = 't5'
) WHERE name = 't4';
}
db close
sqlite3 db test.db
do_execsql_test 7.2.1 {
DELETE FROM t4 WHERE b='world'
}
reset_db
do_execsql_test 7.3.0 {
CREATE TABLE t3(id INT PRIMARY KEY, a, b) WITHOUT ROWID;
INSERT INTO t3 VALUES(1, 2, 3);
INSERT INTO t3 VALUES(4, 5, 6);
INSERT INTO t3 VALUES(7, 8, 9);
CREATE TRIGGER t3t BEFORE DELETE ON t3 BEGIN
DELETE FROM t3 WHERE id=old.id+3;
END;
}
do_execsql_test 7.3.1 {
DELETE FROM t3 WHERE a IN(2, 5, 8);
SELECT * FROM t3;
} {}
do_execsql_test 7.3.2 {
DROP TRIGGER t3t;
INSERT INTO t3 VALUES(1, 2, 3);
INSERT INTO t3 VALUES(4, 5, 6);
INSERT INTO t3 VALUES(7, 8, 9);
CREATE TRIGGER t3t BEFORE DELETE ON t3 BEGIN
DELETE FROM t3 WHERE id=old.id;
END;
}
do_execsql_test 7.3.3 {
DELETE FROM t3 WHERE a IN(2, 5, 8);
SELECT * FROM t3;
} {}
finish_test
+43 -5
View File
@@ -232,9 +232,9 @@ do_execsql_test e_vacuum-3.1.1 {
do_execsql_test e_vacuum-3.1.2 {
VACUUM;
SELECT rowid, x FROM t4;
} {1 x 3 z}
# Was: {1 x 2 z}
} {1 x 2 z}
# Rowids are preserved if an INTEGER PRIMARY KEY is used
do_execsql_test e_vacuum-3.1.3 {
CREATE TABLE t5(x, y INTEGER PRIMARY KEY);
INSERT INTO t5(x) VALUES('x');
@@ -248,9 +248,47 @@ do_execsql_test e_vacuum-3.1.4 {
SELECT rowid, x FROM t5;
} {1 x 3 z}
# EVIDENCE-OF: R-49563-33883 A VACUUM will fail if there is an open
# transaction, or if there are one or more active SQL statements when it
# is run.
# Rowid is preserved for VACUUM INTO
do_execsql_test e_vacuum-3.1.5 {
DROP TABLE t5;
CREATE TABLE t5(x);
INSERT INTO t5(x) VALUES('x');
INSERT INTO t5(x) VALUES('y');
INSERT INTO t5(x) VALUES('z');
DELETE FROM t5 WHERE x = 'y';
SELECT rowid, x FROM t5;
} {1 x 3 z}
forcedelete test2.db
do_execsql_test e_vacuum-3.1.6 {
VACUUM INTO 'test2.db';
ATTACH 'test2.db' AS aux1;
SELECT rowid, x FROM aux1.t5;
DETACH aux1;
} {1 x 3 z}
# Rowids are not renumbered if the table being vacuumed
# has indexes.
do_execsql_test e_vacuum-3.1.7 {
DROP TABLE t5;
CREATE TABLE t5(x,y,z);
INSERT INTO t5(x) VALUES('x');
INSERT INTO t5(x) VALUES('y');
INSERT INTO t5(x) VALUES('z');
UPDATE t5 SET y=x, z=random();
DELETE FROM t5 WHERE x = 'y';
CREATE INDEX t5x ON t5(x);
CREATE UNIQUE INDEX t5y ON t5(y);
CREATE INDEX t5zxy ON t5(z,x,y);
SELECT rowid, x FROM t5;
} {1 x 3 z}
do_execsql_test e_vacuum-3.1.8 {
VACUUM;
SELECT rowid, x FROM t5;
} {1 x 3 z}
# EVIDENCE-OF: R-12218-18073 A VACUUM will fail if there is an open
# transaction on the database connection that is attempting to run the
# VACUUM.
#
do_execsql_test e_vacuum-3.2.1.1 { BEGIN } {}
do_catchsql_test e_vacuum-3.2.1.2 {
BIN
View File
Binary file not shown.
+21
View File
@@ -714,5 +714,26 @@ do_execsql_test in-15.6 {
);
} {1 Alice}
#-------------------------------------------------------------------------
reset_db
do_execsql_test in-16.0 {
CREATE TABLE x1(a, b);
INSERT INTO x1(a) VALUES(1), (2), (3), (4), (5), (6);
CREATE INDEX x1i ON x1(a, b);
}
do_execsql_test in-16.1 {
SELECT * FROM x1
WHERE a IN (SELECT a FROM x1 WHERE (a%2)==0)
ORDER BY a DESC, b;
} {6 {} 4 {} 2 {}}
do_execsql_test in-16.2 {
SELECT * FROM x1
WHERE a IN (SELECT a FROM x1 WHERE (a%7)==0)
ORDER BY a DESC, b;
} {}
finish_test
+20
View File
@@ -598,5 +598,25 @@ do_test 10.3 {
set sqlite3_xferopt_count
} {1}
#-------------------------------------------------------------------------
# xfer transfer between tables where the source has an empty partial index.
#
do_execsql_test 11.0 {
CREATE TABLE t9(a, b, c);
CREATE INDEX t9a ON t9(a);
CREATE INDEX t9b ON t9(b) WHERE c=0;
INSERT INTO t9 VALUES(1, 1, 1);
INSERT INTO t9 VALUES(2, 2, 2);
INSERT INTO t9 VALUES(3, 3, 3);
CREATE TABLE t10(a, b, c);
CREATE INDEX t10a ON t10(a);
CREATE INDEX t10b ON t10(b) WHERE c=0;
INSERT INTO t10 SELECT * FROM t9;
SELECT * FROM t10;
PRAGMA integrity_check;
} {1 1 1 2 2 2 3 3 3 ok}
finish_test
+25
View File
@@ -251,6 +251,31 @@ do_test pragma-1.14.4 {
PRAGMA synchronous;
}
} {2}
do_execsql_test 1.15.1 {
PRAGMA default_cache_size = 0;
}
do_execsql_test 1.15.2 {
PRAGMA default_cache_size;
} $DFLT_CACHE_SZ
do_execsql_test 1.15.3 {
PRAGMA default_cache_size = -500;
}
do_execsql_test 1.15.4 {
PRAGMA default_cache_size;
} 500
do_execsql_test 1.15.3 {
PRAGMA default_cache_size = 500;
}
do_execsql_test 1.15.4 {
PRAGMA default_cache_size;
} 500
db close
hexio_write test.db 48 FFFFFF00
sqlite3 db test.db
do_execsql_test 1.15.4 {
PRAGMA default_cache_size;
} 256
} ;# ifcapable pager_pragmas
# Test turning "flag" pragmas on and off.
+412
View File
@@ -0,0 +1,412 @@
# This file contains Configuration data used by "wapptest.tcl" and
# "releasetest.tcl".
#
# Omit comments (text between # and \n) in a long multi-line string.
#
proc strip_comments {in} {
regsub -all {#[^\n]*\n} $in {} out
return $out
}
array set ::Configs [strip_comments {
"Default" {
-O2
--disable-amalgamation --disable-shared
--enable-session
-DSQLITE_ENABLE_DESERIALIZE
}
"Sanitize" {
CC=clang -fsanitize=undefined
-DSQLITE_ENABLE_STAT4
--enable-session
}
"Stdcall" {
-DUSE_STDCALL=1
-O2
}
"Have-Not" {
# The "Have-Not" configuration sets all possible -UHAVE_feature options
# in order to verify that the code works even on platforms that lack
# these support services.
-DHAVE_FDATASYNC=0
-DHAVE_GMTIME_R=0
-DHAVE_ISNAN=0
-DHAVE_LOCALTIME_R=0
-DHAVE_LOCALTIME_S=0
-DHAVE_MALLOC_USABLE_SIZE=0
-DHAVE_STRCHRNUL=0
-DHAVE_USLEEP=0
-DHAVE_UTIME=0
}
"Unlock-Notify" {
-O2
-DSQLITE_ENABLE_UNLOCK_NOTIFY
-DSQLITE_THREADSAFE
-DSQLITE_TCL_DEFAULT_FULLMUTEX=1
}
"User-Auth" {
-O2
-DSQLITE_USER_AUTHENTICATION=1
}
"Secure-Delete" {
-O2
-DSQLITE_SECURE_DELETE=1
-DSQLITE_SOUNDEX=1
}
"Update-Delete-Limit" {
-O2
-DSQLITE_DEFAULT_FILE_FORMAT=4
-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
-DSQLITE_ENABLE_STMT_SCANSTATUS
-DSQLITE_LIKE_DOESNT_MATCH_BLOBS
-DSQLITE_ENABLE_CURSOR_HINTS
--enable-json1
}
"Check-Symbols" {
-DSQLITE_MEMDEBUG=1
-DSQLITE_ENABLE_FTS3_PARENTHESIS=1
-DSQLITE_ENABLE_FTS3=1
-DSQLITE_ENABLE_RTREE=1
-DSQLITE_ENABLE_MEMSYS5=1
-DSQLITE_ENABLE_MEMSYS3=1
-DSQLITE_ENABLE_COLUMN_METADATA=1
-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
-DSQLITE_SECURE_DELETE=1
-DSQLITE_SOUNDEX=1
-DSQLITE_ENABLE_ATOMIC_WRITE=1
-DSQLITE_ENABLE_MEMORY_MANAGEMENT=1
-DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1
-DSQLITE_ENABLE_STAT4
-DSQLITE_ENABLE_STMT_SCANSTATUS
--enable-json1 --enable-fts5 --enable-session
}
"Debug-One" {
--disable-shared
-O2 -funsigned-char
-DSQLITE_DEBUG=1
-DSQLITE_MEMDEBUG=1
-DSQLITE_MUTEX_NOOP=1
-DSQLITE_TCL_DEFAULT_FULLMUTEX=1
-DSQLITE_ENABLE_FTS3=1
-DSQLITE_ENABLE_RTREE=1
-DSQLITE_ENABLE_MEMSYS5=1
-DSQLITE_ENABLE_COLUMN_METADATA=1
-DSQLITE_ENABLE_STAT4
-DSQLITE_ENABLE_HIDDEN_COLUMNS
-DSQLITE_MAX_ATTACHED=125
-DSQLITE_MUTATION_TEST
--enable-fts5 --enable-json1
}
"Fast-One" {
-O6
-DSQLITE_ENABLE_FTS4=1
-DSQLITE_ENABLE_RTREE=1
-DSQLITE_ENABLE_STAT4
-DSQLITE_ENABLE_RBU
-DSQLITE_MAX_ATTACHED=125
-DLONGDOUBLE_TYPE=double
--enable-session
}
"Device-One" {
-O2
-DSQLITE_DEBUG=1
-DSQLITE_DEFAULT_AUTOVACUUM=1
-DSQLITE_DEFAULT_CACHE_SIZE=64
-DSQLITE_DEFAULT_PAGE_SIZE=1024
-DSQLITE_DEFAULT_TEMP_CACHE_SIZE=32
-DSQLITE_DISABLE_LFS=1
-DSQLITE_ENABLE_ATOMIC_WRITE=1
-DSQLITE_ENABLE_IOTRACE=1
-DSQLITE_ENABLE_MEMORY_MANAGEMENT=1
-DSQLITE_MAX_PAGE_SIZE=4096
-DSQLITE_OMIT_LOAD_EXTENSION=1
-DSQLITE_OMIT_PROGRESS_CALLBACK=1
-DSQLITE_OMIT_VIRTUALTABLE=1
-DSQLITE_ENABLE_HIDDEN_COLUMNS
-DSQLITE_TEMP_STORE=3
--enable-json1
}
"Device-Two" {
-DSQLITE_4_BYTE_ALIGNED_MALLOC=1
-DSQLITE_DEFAULT_AUTOVACUUM=1
-DSQLITE_DEFAULT_CACHE_SIZE=1000
-DSQLITE_DEFAULT_LOCKING_MODE=0
-DSQLITE_DEFAULT_PAGE_SIZE=1024
-DSQLITE_DEFAULT_TEMP_CACHE_SIZE=1000
-DSQLITE_DISABLE_LFS=1
-DSQLITE_ENABLE_FTS3=1
-DSQLITE_ENABLE_MEMORY_MANAGEMENT=1
-DSQLITE_ENABLE_RTREE=1
-DSQLITE_MAX_COMPOUND_SELECT=50
-DSQLITE_MAX_PAGE_SIZE=32768
-DSQLITE_OMIT_TRACE=1
-DSQLITE_TEMP_STORE=3
-DSQLITE_THREADSAFE=2
-DSQLITE_ENABLE_DESERIALIZE=1
--enable-json1 --enable-fts5 --enable-session
}
"Locking-Style" {
-O2
-DSQLITE_ENABLE_LOCKING_STYLE=1
}
"Apple" {
-Os
-DHAVE_GMTIME_R=1
-DHAVE_ISNAN=1
-DHAVE_LOCALTIME_R=1
-DHAVE_PREAD=1
-DHAVE_PWRITE=1
-DHAVE_USLEEP=1
-DHAVE_USLEEP=1
-DHAVE_UTIME=1
-DSQLITE_DEFAULT_CACHE_SIZE=1000
-DSQLITE_DEFAULT_CKPTFULLFSYNC=1
-DSQLITE_DEFAULT_MEMSTATUS=1
-DSQLITE_DEFAULT_PAGE_SIZE=1024
-DSQLITE_DISABLE_PAGECACHE_OVERFLOW_STATS=1
-DSQLITE_ENABLE_API_ARMOR=1
-DSQLITE_ENABLE_AUTO_PROFILE=1
-DSQLITE_ENABLE_FLOCKTIMEOUT=1
-DSQLITE_ENABLE_FTS3=1
-DSQLITE_ENABLE_FTS3_PARENTHESIS=1
-DSQLITE_ENABLE_FTS3_TOKENIZER=1
if:os=="Darwin" -DSQLITE_ENABLE_LOCKING_STYLE=1
-DSQLITE_ENABLE_PERSIST_WAL=1
-DSQLITE_ENABLE_PURGEABLE_PCACHE=1
-DSQLITE_ENABLE_RTREE=1
-DSQLITE_ENABLE_SNAPSHOT=1
# -DSQLITE_ENABLE_SQLLOG=1
-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1
-DSQLITE_MAX_LENGTH=2147483645
-DSQLITE_MAX_VARIABLE_NUMBER=500000
# -DSQLITE_MEMDEBUG=1
-DSQLITE_NO_SYNC=1
-DSQLITE_OMIT_AUTORESET=1
-DSQLITE_OMIT_LOAD_EXTENSION=1
-DSQLITE_PREFER_PROXY_LOCKING=1
-DSQLITE_SERIES_CONSTRAINT_VERIFY=1
-DSQLITE_THREADSAFE=2
-DSQLITE_USE_URI=1
-DSQLITE_WRITE_WALFRAME_PREBUFFERED=1
-DUSE_GUARDED_FD=1
-DUSE_PREAD=1
--enable-json1 --enable-fts5
}
"Extra-Robustness" {
-DSQLITE_ENABLE_OVERSIZE_CELL_CHECK=1
-DSQLITE_MAX_ATTACHED=62
}
"Devkit" {
-DSQLITE_DEFAULT_FILE_FORMAT=4
-DSQLITE_MAX_ATTACHED=30
-DSQLITE_ENABLE_COLUMN_METADATA
-DSQLITE_ENABLE_FTS4
-DSQLITE_ENABLE_FTS5
-DSQLITE_ENABLE_FTS4_PARENTHESIS
-DSQLITE_DISABLE_FTS4_DEFERRED
-DSQLITE_ENABLE_RTREE
--enable-json1 --enable-fts5
}
"No-lookaside" {
-DSQLITE_TEST_REALLOC_STRESS=1
-DSQLITE_OMIT_LOOKASIDE=1
-DHAVE_USLEEP=1
}
"Valgrind" {
-DSQLITE_ENABLE_STAT4
-DSQLITE_ENABLE_FTS4
-DSQLITE_ENABLE_RTREE
-DSQLITE_ENABLE_HIDDEN_COLUMNS
--enable-json1
}
# The next group of configurations are used only by the
# Failure-Detection platform. They are all the same, but we need
# different names for them all so that they results appear in separate
# subdirectories.
#
Fail0 {-O0}
Fail2 {-O0}
Fail3 {-O0}
Fail4 {-O0}
FuzzFail1 {-O0}
FuzzFail2 {-O0}
}]
array set ::Platforms [strip_comments {
Linux-x86_64 {
"Check-Symbols" checksymbols
"Fast-One" "fuzztest test"
"Debug-One" "mptest test"
"Have-Not" test
"Secure-Delete" test
"Unlock-Notify" "QUICKTEST_INCLUDE=notify2.test test"
"User-Auth" tcltest
"Update-Delete-Limit" test
"Extra-Robustness" test
"Device-Two" test
"No-lookaside" test
"Devkit" test
"Apple" test
"Sanitize" {QUICKTEST_OMIT=func4.test,nan.test test}
"Device-One" fulltest
"Default" "threadtest fulltest"
"Valgrind" valgrindtest
}
Linux-i686 {
"Devkit" test
"Have-Not" test
"Unlock-Notify" "QUICKTEST_INCLUDE=notify2.test test"
"Device-One" test
"Device-Two" test
"Default" "threadtest fulltest"
}
Darwin-i386 {
"Locking-Style" "mptest test"
"Have-Not" test
"Apple" "threadtest fulltest"
}
Darwin-x86_64 {
"Locking-Style" "mptest test"
"Have-Not" test
"Apple" "threadtest fulltest"
}
"Windows NT-intel" {
"Stdcall" test
"Have-Not" test
"Default" "mptest fulltestonly"
}
"Windows NT-amd64" {
"Stdcall" test
"Have-Not" test
"Default" "mptest fulltestonly"
}
# The Failure-Detection platform runs various tests that deliberately
# fail. This is used as a test of this script to verify that this script
# correctly identifies failures.
#
Failure-Detection {
Fail0 "TEST_FAILURE=0 test"
Sanitize "TEST_FAILURE=1 test"
Fail2 "TEST_FAILURE=2 valgrindtest"
Fail3 "TEST_FAILURE=3 valgrindtest"
Fail4 "TEST_FAILURE=4 test"
FuzzFail1 "TEST_FAILURE=5 test"
FuzzFail2 "TEST_FAILURE=5 valgrindtest"
}
}]
proc make_test_suite {msvc withtcl name testtarget config} {
# Tcl variable $opts is used to build up the value used to set the
# OPTS Makefile variable. Variable $cflags holds the value for
# CFLAGS. The makefile will pass OPTS to both gcc and lemon, but
# CFLAGS is only passed to gcc.
#
set makeOpts ""
set cflags [expr {$msvc ? "-Zi" : "-g"}]
set opts ""
set title ${name}($testtarget)
set configOpts $withtcl
set skip 0
regsub -all {#[^\n]*\n} $config \n config
foreach arg $config {
if {$skip} {
set skip 0
continue
}
if {[regexp {^-[UD]} $arg]} {
lappend opts $arg
} elseif {[regexp {^[A-Z]+=} $arg]} {
lappend testtarget $arg
} elseif {[regexp {^if:([a-z]+)(.*)} $arg all key tail]} {
# Arguments of the form 'if:os=="Linux"' will cause the subsequent
# argument to be skipped if the $tcl_platform(os) is not "Linux", for
# example...
set skip [expr !(\$::tcl_platform($key)$tail)]
} elseif {[regexp {^--(enable|disable)-} $arg]} {
if {$msvc} {
if {$arg eq "--disable-amalgamation"} {
lappend makeOpts USE_AMALGAMATION=0
continue
}
if {$arg eq "--disable-shared"} {
lappend makeOpts USE_CRT_DLL=0 DYNAMIC_SHELL=0
continue
}
if {$arg eq "--enable-fts5"} {
lappend opts -DSQLITE_ENABLE_FTS5
continue
}
if {$arg eq "--enable-json1"} {
lappend opts -DSQLITE_ENABLE_JSON1
continue
}
if {$arg eq "--enable-shared"} {
lappend makeOpts USE_CRT_DLL=1 DYNAMIC_SHELL=1
continue
}
}
lappend configOpts $arg
} else {
if {$msvc} {
if {$arg eq "-g"} {
lappend cflags -Zi
continue
}
if {[regexp -- {^-O(\d+)$} $arg all level]} then {
lappend makeOpts OPTIMIZATIONS=$level
continue
}
}
lappend cflags $arg
}
}
# Disable sync to make testing faster.
#
lappend opts -DSQLITE_NO_SYNC=1
# Some configurations already set HAVE_USLEEP; in that case, skip it.
#
if {[lsearch -regexp $opts {^-DHAVE_USLEEP(?:=|$)}]==-1} {
lappend opts -DHAVE_USLEEP=1
}
# Add the define for this platform.
#
if {$::tcl_platform(platform)=="windows"} {
lappend opts -DSQLITE_OS_WIN=1
} else {
lappend opts -DSQLITE_OS_UNIX=1
}
# Set the sub-directory to use.
#
set dir [string tolower [string map {- _ " " _ "(" _ ")" _} $name]]
# Join option lists into strings, using space as delimiter.
#
set makeOpts [join $makeOpts " "]
set cflags [join $cflags " "]
set opts [join $opts " "]
return [list $title $dir $configOpts $testtarget $makeOpts $cflags $opts]
}
# Configuration verification: Check that each entry in the list of configs
# specified for each platforms exists.
#
foreach {key value} [array get ::Platforms] {
foreach {v t} $value {
if {0==[info exists ::Configs($v)]} {
puts stderr "No such configuration: \"$v\""
exit -1
}
}
}
+28
View File
@@ -345,4 +345,32 @@ do_execsql_test skipscan1-9.3 {
} {/{SCAN TABLE t9a}/}
optimization_control db skip-scan 1
do_execsql_test skipscan1-2.1 {
CREATE TABLE t6(a TEXT, b INT, c INT, d INT);
CREATE INDEX t6abc ON t6(a,b,c);
INSERT INTO t6 VALUES('abc',123,4,5);
ANALYZE;
DELETE FROM sqlite_stat1;
INSERT INTO sqlite_stat1 VALUES('t6','t6abc','10000 5000 2000 10');
ANALYZE sqlite_master;
DELETE FROM t6;
} {}
do_execsql_test skipscan1-2.2eqp {
EXPLAIN QUERY PLAN
SELECT a,b,c,d,'|' FROM t6 WHERE d<>99 AND b=345 ORDER BY a;
} {/* USING INDEX t6abc (ANY(a) AND b=?)*/}
do_execsql_test skipscan1-2.2 {
SELECT a,b,c,d,'|' FROM t6 WHERE d<>99 AND b=345 ORDER BY a;
} {}
do_execsql_test skipscan1-2.3eqp {
EXPLAIN QUERY PLAN
SELECT a,b,c,d,'|' FROM t6 WHERE d<>99 AND b=345 ORDER BY a DESC;
} {/* USING INDEX t6abc (ANY(a) AND b=?)*/}
do_execsql_test skipscan1-2.3 {
SELECT a,b,c,d,'|' FROM t6 WHERE d<>99 AND b=345 ORDER BY a DESC;
} {}
finish_test
+1
View File
@@ -202,4 +202,5 @@ do_eqp_test skipscan2-3.3eqp {
} {SEARCH TABLE t3 USING PRIMARY KEY (ANY(a) AND b=?)}
finish_test
+10
View File
@@ -889,4 +889,14 @@ do_catchsql_test sqllimits1.17.0 {
foreach {key value} [array get saved] {
catch {set $key $value}
}
#-------------------------------------------------------------------------
# At one point the following caused an assert() to fail.
#
sqlite3_limit db SQLITE_LIMIT_LENGTH 10000
set nm [string repeat x 10000]
do_catchsql_test sqllimits1-17.1 "
CREATE TABLE $nm (x PRIMARY KEY)
" {1 {string or blob too big}}
finish_test
+40
View File
@@ -576,6 +576,10 @@ if {[info exists cmdlinearg]==0} {
if {$cmdlinearg(verbose)==""} {
set cmdlinearg(verbose) 1
}
if {[info commands vdbe_coverage]!=""} {
vdbe_coverage start
}
}
# Update the soft-heap-limit each time this script is run. In that
@@ -1296,6 +1300,9 @@ proc finalize_testing {} {
memdebug_log_sql leaks.tcl
}
}
if {[info commands vdbe_coverage]!=""} {
vdbe_coverage_report
}
foreach f [glob -nocomplain test.db-*-journal] {
forcedelete $f
}
@@ -1305,6 +1312,39 @@ proc finalize_testing {} {
exit [expr {$nErr>0}]
}
proc vdbe_coverage_report {} {
puts "Writing vdbe coverage report to vdbe_coverage.txt"
set lSrc [list]
set iLine 0
if {[file exists ../sqlite3.c]} {
set fd [open ../sqlite3.c]
set iLine
while { ![eof $fd] } {
set line [gets $fd]
incr iLine
if {[regexp {^/\** Begin file (.*\.c) \**/} $line -> file]} {
lappend lSrc [list $iLine $file]
}
}
close $fd
}
set fd [open vdbe_coverage.txt w]
foreach miss [vdbe_coverage report] {
foreach {line branch never} $miss {}
set nextfile ""
while {[llength $lSrc]>0 && [lindex $lSrc 0 0] < $line} {
set nextfile [lindex $lSrc 0 1]
set lSrc [lrange $lSrc 1 end]
}
if {$nextfile != ""} {
puts $fd ""
puts $fd "### $nextfile ###"
}
puts $fd "Vdbe branch $line: never $never (path $branch)"
}
close $fd
}
# Display memory statistics for analysis and debugging purposes.
#
proc show_memstats {} {
+14
View File
@@ -1057,5 +1057,19 @@ do_catchsql_test 16.2 {
HAVING raise(ABORT, 'msg');
} {1 {RAISE() may only be used within a trigger-program}}
#-------------------------------------------------------------------------
# Datatype mismatch on IPK when there are BEFORE triggers.
#
do_execsql_test 17.0 {
CREATE TABLE xyz(x INTEGER PRIMARY KEY, y, z);
CREATE TRIGGER xyz_tr BEFORE INSERT ON xyz BEGIN
SELECT new.x;
END;
}
do_catchsql_test 17.1 {
INSERT INTO xyz VALUES('hello', 2, 3);
} {1 {datatype mismatch}}
finish_test
+987
View File
@@ -0,0 +1,987 @@
# Copyright (c) 2017 D. Richard Hipp
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the Simplified BSD License (also
# known as the "2-Clause License" or "FreeBSD License".)
#
# This program is distributed in the hope that it will be useful,
# but without any warranty; without even the implied warranty of
# merchantability or fitness for a particular purpose.
#
#---------------------------------------------------------------------------
#
# Design rules:
#
# (1) All identifiers in the global namespace begin with "wapp"
#
# (2) Indentifiers intended for internal use only begin with "wappInt"
#
package require Tcl 8.6
# Add text to the end of the HTTP reply. No interpretation or transformation
# of the text is performs. The argument should be enclosed within {...}
#
proc wapp {txt} {
global wapp
dict append wapp .reply $txt
}
# Add text to the page under construction. Do no escaping on the text.
#
# Though "unsafe" in general, there are uses for this kind of thing.
# For example, if you want to return the complete, unmodified content of
# a file:
#
# set fd [open content.html rb]
# wapp-unsafe [read $fd]
# close $fd
#
# You could do the same thing using ordinary "wapp" instead of "wapp-unsafe".
# The difference is that wapp-safety-check will complain about the misuse
# of "wapp", but it assumes that the person who write "wapp-unsafe" understands
# the risks.
#
# Though occasionally necessary, the use of this interface should be minimized.
#
proc wapp-unsafe {txt} {
global wapp
dict append wapp .reply $txt
}
# Add text to the end of the reply under construction. The following
# substitutions are made:
#
# %html(...) Escape text for inclusion in HTML
# %url(...) Escape text for use as a URL
# %qp(...) Escape text for use as a URI query parameter
# %string(...) Escape text for use within a JSON string
# %unsafe(...) No transformations of the text
#
# The substitutions above terminate at the first ")" character. If the
# text of the TCL string in ... contains ")" characters itself, use instead:
#
# %html%(...)%
# %url%(...)%
# %qp%(...)%
# %string%(...)%
# %unsafe%(...)%
#
# In other words, use "%(...)%" instead of "(...)" to include the TCL string
# to substitute.
#
# The %unsafe substitution should be avoided whenever possible, obviously.
# In addition to the substitutions above, the text also does backslash
# escapes.
#
# The wapp-trim proc works the same as wapp-subst except that it also removes
# whitespace from the left margin, so that the generated HTML/CSS/Javascript
# does not appear to be indented when delivered to the client web browser.
#
if {$tcl_version>=8.7} {
proc wapp-subst {txt} {
global wapp
regsub -all -command \
{%(html|url|qp|string|unsafe){1,1}?(|%)\((.+)\)\2} $txt wappInt-enc txt
dict append wapp .reply [subst -novariables -nocommand $txt]
}
proc wapp-trim {txt} {
global wapp
regsub -all {\n\s+} [string trim $txt] \n txt
regsub -all -command \
{%(html|url|qp|string|unsafe){1,1}?(|%)\((.+)\)\2} $txt wappInt-enc txt
dict append wapp .reply [subst -novariables -nocommand $txt]
}
proc wappInt-enc {all mode nu1 txt} {
return [uplevel 2 "wappInt-enc-$mode \"$txt\""]
}
} else {
proc wapp-subst {txt} {
global wapp
regsub -all {%(html|url|qp|string|unsafe){1,1}?(|%)\((.+)\)\2} $txt \
{[wappInt-enc-\1 "\3"]} txt
dict append wapp .reply [uplevel 1 [list subst -novariables $txt]]
}
proc wapp-trim {txt} {
global wapp
regsub -all {\n\s+} [string trim $txt] \n txt
regsub -all {%(html|url|qp|string|unsafe){1,1}?(|%)\((.+)\)\2} $txt \
{[wappInt-enc-\1 "\3"]} txt
dict append wapp .reply [uplevel 1 [list subst -novariables $txt]]
}
}
# There must be a wappInt-enc-NAME routine for each possible substitution
# in wapp-subst. Thus there are routines for "html", "url", "qp", and "unsafe".
#
# wappInt-enc-html Escape text so that it is safe to use in the
# body of an HTML document.
#
# wappInt-enc-url Escape text so that it is safe to pass as an
# argument to href= and src= attributes in HTML.
#
# wappInt-enc-qp Escape text so that it is safe to use as the
# value of a query parameter in a URL or in
# post data or in a cookie.
#
# wappInt-enc-string Escape ", ', \, and < for using inside of a
# javascript string literal. The < character
# is escaped to prevent "</script>" from causing
# problems in embedded javascript.
#
# wappInt-enc-unsafe Perform no encoding at all. Unsafe.
#
proc wappInt-enc-html {txt} {
return [string map {& &amp; < &lt; > &gt; \" &quot; \\ &#92;} $txt]
}
proc wappInt-enc-unsafe {txt} {
return $txt
}
proc wappInt-enc-url {s} {
if {[regsub -all {[^-{}@~?=#_.:/a-zA-Z0-9]} $s {[wappInt-%HHchar {&}]} s]} {
set s [subst -novar -noback $s]
}
if {[regsub -all {[{}]} $s {[wappInt-%HHchar \\&]} s]} {
set s [subst -novar -noback $s]
}
return $s
}
proc wappInt-enc-qp {s} {
if {[regsub -all {[^-{}_.a-zA-Z0-9]} $s {[wappInt-%HHchar {&}]} s]} {
set s [subst -novar -noback $s]
}
if {[regsub -all {[{}]} $s {[wappInt-%HHchar \\&]} s]} {
set s [subst -novar -noback $s]
}
return $s
}
proc wappInt-enc-string {s} {
return [string map {\\ \\\\ \" \\\" ' \\' < \\u003c} $s]
}
# This is a helper routine for wappInt-enc-url and wappInt-enc-qp. It returns
# an appropriate %HH encoding for the single character c. If c is a unicode
# character, then this routine might return multiple bytes: %HH%HH%HH
#
proc wappInt-%HHchar {c} {
if {$c==" "} {return +}
return [regsub -all .. [binary encode hex [encoding convertto utf-8 $c]] {%&}]
}
# Undo the www-url-encoded format.
#
# HT: This code stolen from ncgi.tcl
#
proc wappInt-decode-url {str} {
set str [string map [list + { } "\\" "\\\\" \[ \\\[ \] \\\]] $str]
regsub -all -- \
{%([Ee][A-Fa-f0-9])%([89ABab][A-Fa-f0-9])%([89ABab][A-Fa-f0-9])} \
$str {[encoding convertfrom utf-8 [binary decode hex \1\2\3]]} str
regsub -all -- \
{%([CDcd][A-Fa-f0-9])%([89ABab][A-Fa-f0-9])} \
$str {[encoding convertfrom utf-8 [binary decode hex \1\2]]} str
regsub -all -- {%([0-7][A-Fa-f0-9])} $str {\\u00\1} str
return [subst -novar $str]
}
# Reset the document back to an empty string.
#
proc wapp-reset {} {
global wapp
dict set wapp .reply {}
}
# Change the mime-type of the result document.
#
proc wapp-mimetype {x} {
global wapp
dict set wapp .mimetype $x
}
# Change the reply code.
#
proc wapp-reply-code {x} {
global wapp
dict set wapp .reply-code $x
}
# Set a cookie
#
proc wapp-set-cookie {name value} {
global wapp
dict lappend wapp .new-cookies $name $value
}
# Unset a cookie
#
proc wapp-clear-cookie {name} {
wapp-set-cookie $name {}
}
# Add extra entries to the reply header
#
proc wapp-reply-extra {name value} {
global wapp
dict lappend wapp .reply-extra $name $value
}
# Specifies how the web-page under construction should be cached.
# The argument should be one of:
#
# no-cache
# max-age=N (for some integer number of seconds, N)
# private,max-age=N
#
proc wapp-cache-control {x} {
wapp-reply-extra Cache-Control $x
}
# Redirect to a different web page
#
proc wapp-redirect {uri} {
wapp-reply-code {307 Redirect}
wapp-reply-extra Location $uri
}
# Return the value of a wapp parameter
#
proc wapp-param {name {dflt {}}} {
global wapp
if {![dict exists $wapp $name]} {return $dflt}
return [dict get $wapp $name]
}
# Return true if a and only if the wapp parameter $name exists
#
proc wapp-param-exists {name} {
global wapp
return [dict exists $wapp $name]
}
# Set the value of a wapp parameter
#
proc wapp-set-param {name value} {
global wapp
dict set wapp $name $value
}
# Return all parameter names that match the GLOB pattern, or all
# names if the GLOB pattern is omitted.
#
proc wapp-param-list {{glob {*}}} {
global wapp
return [dict keys $wapp $glob]
}
# By default, Wapp does not decode query parameters and POST parameters
# for cross-origin requests. This is a security restriction, designed to
# help prevent cross-site request forgery (CSRF) attacks.
#
# As a consequence of this restriction, URLs for sites generated by Wapp
# that contain query parameters will not work as URLs found in other
# websites. You cannot create a link from a second website into a Wapp
# website if the link contains query planner, by default.
#
# Of course, it is sometimes desirable to allow query parameters on external
# links. For URLs for which this is safe, the application should invoke
# wapp-allow-xorigin-params. This procedure tells Wapp that it is safe to
# go ahead and decode the query parameters even for cross-site requests.
#
# In other words, for Wapp security is the default setting. Individual pages
# need to actively disable the cross-site request security if those pages
# are safe for cross-site access.
#
proc wapp-allow-xorigin-params {} {
global wapp
if {![dict exists $wapp .qp] && ![dict get $wapp SAME_ORIGIN]} {
wappInt-decode-query-params
}
}
# Set the content-security-policy.
#
# The default content-security-policy is very strict: "default-src 'self'"
# The default policy prohibits the use of in-line javascript or CSS.
#
# Provide an alternative CSP as the argument. Or use "off" to disable
# the CSP completely.
#
proc wapp-content-security-policy {val} {
global wapp
if {$val=="off"} {
dict unset wapp .csp
} else {
dict set wapp .csp $val
}
}
# Examine the bodys of all procedures in this program looking for
# unsafe calls to various Wapp interfaces. Return a text string
# containing warnings. Return an empty string if all is ok.
#
# This routine is advisory only. It misses some constructs that are
# dangerous and flags others that are safe.
#
proc wapp-safety-check {} {
set res {}
foreach p [info procs] {
set ln 0
foreach x [split [info body $p] \n] {
incr ln
if {[regexp {^[ \t]*wapp[ \t]+([^\n]+)} $x all tail]
&& [string index $tail 0]!="\173"
&& [regexp {[[$]} $tail]
} {
append res "$p:$ln: unsafe \"wapp\" call: \"[string trim $x]\"\n"
}
if {[regexp {^[ \t]*wapp-(subst|trim)[ \t]+[^\173]} $x all cx]} {
append res "$p:$ln: unsafe \"wapp-$cx\" call: \"[string trim $x]\"\n"
}
}
}
return $res
}
# Return a string that descripts the current environment. Applications
# might find this useful for debugging.
#
proc wapp-debug-env {} {
global wapp
set out {}
foreach var [lsort [dict keys $wapp]] {
if {[string index $var 0]=="."} continue
append out "$var = [list [dict get $wapp $var]]\n"
}
append out "\[pwd\] = [list [pwd]]\n"
return $out
}
# Tracing function for each HTTP request. This is overridden by wapp-start
# if tracing is enabled.
#
proc wappInt-trace {} {}
# Start up a listening socket. Arrange to invoke wappInt-new-connection
# for each inbound HTTP connection.
#
# port Listen on this TCP port. 0 means to select a port
# that is not currently in use
#
# wappmode One of "scgi", "remote-scgi", "server", or "local".
#
# fromip If not {}, then reject all requests from IP addresses
# other than $fromip
#
proc wappInt-start-listener {port wappmode fromip} {
if {[string match *scgi $wappmode]} {
set type SCGI
set server [list wappInt-new-connection \
wappInt-scgi-readable $wappmode $fromip]
} else {
set type HTTP
set server [list wappInt-new-connection \
wappInt-http-readable $wappmode $fromip]
}
if {$wappmode=="local" || $wappmode=="scgi"} {
set x [socket -server $server -myaddr 127.0.0.1 $port]
} else {
set x [socket -server $server $port]
}
set coninfo [chan configure $x -sockname]
set port [lindex $coninfo 2]
if {$wappmode=="local"} {
wappInt-start-browser http://127.0.0.1:$port/
} elseif {$fromip!=""} {
puts "Listening for $type requests on TCP port $port from IP $fromip"
} else {
puts "Listening for $type requests on TCP port $port"
}
}
# Start a web-browser and point it at $URL
#
proc wappInt-start-browser {url} {
global tcl_platform
if {$tcl_platform(platform)=="windows"} {
exec cmd /c start $url &
} elseif {$tcl_platform(os)=="Darwin"} {
exec open $url &
} elseif {[catch {exec xdg-open $url}]} {
exec firefox $url &
}
}
# This routine is a "socket -server" callback. The $chan, $ip, and $port
# arguments are added by the socket command.
#
# Arrange to invoke $callback when content is available on the new socket.
# The $callback will process inbound HTTP or SCGI content. Reject the
# request if $fromip is not an empty string and does not match $ip.
#
proc wappInt-new-connection {callback wappmode fromip chan ip port} {
upvar #0 wappInt-$chan W
if {$fromip!="" && ![string match $fromip $ip]} {
close $chan
return
}
set W [dict create REMOTE_ADDR $ip REMOTE_PORT $port WAPP_MODE $wappmode \
.header {}]
fconfigure $chan -blocking 0 -translation binary
fileevent $chan readable [list $callback $chan]
}
# Close an input channel
#
proc wappInt-close-channel {chan} {
if {$chan=="stdout"} {
# This happens after completing a CGI request
exit 0
} else {
unset ::wappInt-$chan
close $chan
}
}
# Process new text received on an inbound HTTP request
#
proc wappInt-http-readable {chan} {
if {[catch [list wappInt-http-readable-unsafe $chan] msg]} {
puts stderr "$msg\n$::errorInfo"
wappInt-close-channel $chan
}
}
proc wappInt-http-readable-unsafe {chan} {
upvar #0 wappInt-$chan W wapp wapp
if {![dict exists $W .toread]} {
# If the .toread key is not set, that means we are still reading
# the header
set line [string trimright [gets $chan]]
set n [string length $line]
if {$n>0} {
if {[dict get $W .header]=="" || [regexp {^\s+} $line]} {
dict append W .header $line
} else {
dict append W .header \n$line
}
if {[string length [dict get $W .header]]>100000} {
error "HTTP request header too big - possible DOS attack"
}
} elseif {$n==0} {
# We have reached the blank line that terminates the header.
global argv0
set a0 [file normalize $argv0]
dict set W SCRIPT_FILENAME $a0
dict set W DOCUMENT_ROOT [file dir $a0]
if {[wappInt-parse-header $chan]} {
catch {close $chan}
return
}
set len 0
if {[dict exists $W CONTENT_LENGTH]} {
set len [dict get $W CONTENT_LENGTH]
}
if {$len>0} {
# Still need to read the query content
dict set W .toread $len
} else {
# There is no query content, so handle the request immediately
set wapp $W
wappInt-handle-request $chan 0
}
}
} else {
# If .toread is set, that means we are reading the query content.
# Continue reading until .toread reaches zero.
set got [read $chan [dict get $W .toread]]
dict append W CONTENT $got
dict set W .toread [expr {[dict get $W .toread]-[string length $got]}]
if {[dict get $W .toread]<=0} {
# Handle the request as soon as all the query content is received
set wapp $W
wappInt-handle-request $chan 0
}
}
}
# Decode the HTTP request header.
#
# This routine is always running inside of a [catch], so if
# any problems arise, simply raise an error.
#
proc wappInt-parse-header {chan} {
upvar #0 wappInt-$chan W
set hdr [split [dict get $W .header] \n]
if {$hdr==""} {return 1}
set req [lindex $hdr 0]
dict set W REQUEST_METHOD [set method [lindex $req 0]]
if {[lsearch {GET HEAD POST} $method]<0} {
error "unsupported request method: \"[dict get $W REQUEST_METHOD]\""
}
set uri [lindex $req 1]
set split_uri [split $uri ?]
set uri0 [lindex $split_uri 0]
if {![regexp {^/[-.a-z0-9_/]*$} $uri0]} {
error "invalid request uri: \"$uri0\""
}
dict set W REQUEST_URI $uri0
dict set W PATH_INFO $uri0
set uri1 [lindex $split_uri 1]
dict set W QUERY_STRING $uri1
set n [llength $hdr]
for {set i 1} {$i<$n} {incr i} {
set x [lindex $hdr $i]
if {![regexp {^(.+): +(.*)$} $x all name value]} {
error "invalid header line: \"$x\""
}
set name [string toupper $name]
switch -- $name {
REFERER {set name HTTP_REFERER}
USER-AGENT {set name HTTP_USER_AGENT}
CONTENT-LENGTH {set name CONTENT_LENGTH}
CONTENT-TYPE {set name CONTENT_TYPE}
HOST {set name HTTP_HOST}
COOKIE {set name HTTP_COOKIE}
ACCEPT-ENCODING {set name HTTP_ACCEPT_ENCODING}
default {set name .hdr:$name}
}
dict set W $name $value
}
return 0
}
# Decode the QUERY_STRING parameters from a GET request or the
# application/x-www-form-urlencoded CONTENT from a POST request.
#
# This routine sets the ".qp" element of the ::wapp dict as a signal
# that query parameters have already been decoded.
#
proc wappInt-decode-query-params {} {
global wapp
dict set wapp .qp 1
if {[dict exists $wapp QUERY_STRING]} {
foreach qterm [split [dict get $wapp QUERY_STRING] &] {
set qsplit [split $qterm =]
set nm [lindex $qsplit 0]
if {[regexp {^[a-z][a-z0-9]*$} $nm]} {
dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]]
}
}
}
if {[dict exists $wapp CONTENT_TYPE] && [dict exists $wapp CONTENT]} {
set ctype [dict get $wapp CONTENT_TYPE]
if {$ctype=="application/x-www-form-urlencoded"} {
foreach qterm [split [string trim [dict get $wapp CONTENT]] &] {
set qsplit [split $qterm =]
set nm [lindex $qsplit 0]
if {[regexp {^[a-z][-a-z0-9_]*$} $nm]} {
dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]]
}
}
} elseif {[string match multipart/form-data* $ctype]} {
regexp {^(.*?)\r\n(.*)$} [dict get $wapp CONTENT] all divider body
set ndiv [string length $divider]
while {[string length $body]} {
set idx [string first $divider $body]
set unit [string range $body 0 [expr {$idx-3}]]
set body [string range $body [expr {$idx+$ndiv+2}] end]
if {[regexp {^Content-Disposition: form-data; (.*?)\r\n\r\n(.*)$} \
$unit unit hdr content]} {
if {[regexp {name="(.*)"; filename="(.*)"\r\nContent-Type: (.*?)$}\
$hdr hr name filename mimetype]} {
dict set wapp $name.filename \
[string map [list \\\" \" \\\\ \\] $filename]
dict set wapp $name.mimetype $mimetype
dict set wapp $name.content $content
} elseif {[regexp {name="(.*)"} $hdr hr name]} {
dict set wapp $name $content
}
}
}
}
}
}
# Invoke application-supplied methods to generate a reply to
# a single HTTP request.
#
# This routine always runs within [catch], so handle exceptions by
# invoking [error].
#
proc wappInt-handle-request {chan useCgi} {
global wapp
dict set wapp .reply {}
dict set wapp .mimetype {text/html; charset=utf-8}
dict set wapp .reply-code {200 Ok}
dict set wapp .csp {default-src 'self'}
# Set up additional CGI environment values
#
if {![dict exists $wapp HTTP_HOST]} {
dict set wapp BASE_URL {}
} elseif {[dict exists $wapp HTTPS]} {
dict set wapp BASE_URL https://[dict get $wapp HTTP_HOST]
} else {
dict set wapp BASE_URL http://[dict get $wapp HTTP_HOST]
}
if {![dict exists $wapp REQUEST_URI]} {
dict set wapp REQUEST_URI /
} elseif {[regsub {\?.*} [dict get $wapp REQUEST_URI] {} newR]} {
# Some servers (ex: nginx) append the query parameters to REQUEST_URI.
# These need to be stripped off
dict set wapp REQUEST_URI $newR
}
if {[dict exists $wapp SCRIPT_NAME]} {
dict append wapp BASE_URL [dict get $wapp SCRIPT_NAME]
} else {
dict set wapp SCRIPT_NAME {}
}
if {![dict exists $wapp PATH_INFO]} {
# If PATH_INFO is missing (ex: nginx) then construct it
set URI [dict get $wapp REQUEST_URI]
set skip [string length [dict get $wapp SCRIPT_NAME]]
dict set wapp PATH_INFO [string range $URI $skip end]
}
if {[regexp {^/([^/]+)(.*)$} [dict get $wapp PATH_INFO] all head tail]} {
dict set wapp PATH_HEAD $head
dict set wapp PATH_TAIL [string trimleft $tail /]
} else {
dict set wapp PATH_INFO {}
dict set wapp PATH_HEAD {}
dict set wapp PATH_TAIL {}
}
dict set wapp SELF_URL [dict get $wapp BASE_URL]/[dict get $wapp PATH_HEAD]
# Parse query parameters from the query string, the cookies, and
# POST data
#
if {[dict exists $wapp HTTP_COOKIE]} {
foreach qterm [split [dict get $wapp HTTP_COOKIE] {;}] {
set qsplit [split [string trim $qterm] =]
set nm [lindex $qsplit 0]
if {[regexp {^[a-z][-a-z0-9_]*$} $nm]} {
dict set wapp $nm [wappInt-decode-url [lindex $qsplit 1]]
}
}
}
set same_origin 0
if {[dict exists $wapp HTTP_REFERER]} {
set referer [dict get $wapp HTTP_REFERER]
set base [dict get $wapp BASE_URL]
if {$referer==$base || [string match $base/* $referer]} {
set same_origin 1
}
}
dict set wapp SAME_ORIGIN $same_origin
if {$same_origin} {
wappInt-decode-query-params
}
# Invoke the application-defined handler procedure for this page
# request. If an error occurs while running that procedure, generate
# an HTTP reply that contains the error message.
#
wapp-before-dispatch-hook
wappInt-trace
set mname [dict get $wapp PATH_HEAD]
if {[catch {
if {$mname!="" && [llength [info proc wapp-page-$mname]]>0} {
wapp-page-$mname
} else {
wapp-default
}
} msg]} {
if {[wapp-param WAPP_MODE]=="local" || [wapp-param WAPP_MODE]=="server"} {
puts "ERROR: $::errorInfo"
}
wapp-reset
wapp-reply-code "500 Internal Server Error"
wapp-mimetype text/html
wapp-trim {
<h1>Wapp Application Error</h1>
<pre>%html($::errorInfo)</pre>
}
dict unset wapp .new-cookies
}
# Transmit the HTTP reply
#
if {$chan=="stdout"} {
puts $chan "Status: [dict get $wapp .reply-code]\r"
} else {
puts $chan "HTTP/1.1 [dict get $wapp .reply-code]\r"
puts $chan "Server: wapp\r"
puts $chan "Connection: close\r"
}
if {[dict exists $wapp .reply-extra]} {
foreach {name value} [dict get $wapp .reply-extra] {
puts $chan "$name: $value\r"
}
}
if {[dict exists $wapp .csp]} {
puts $chan "Content-Security-Policy: [dict get $wapp .csp]\r"
}
set mimetype [dict get $wapp .mimetype]
puts $chan "Content-Type: $mimetype\r"
if {[dict exists $wapp .new-cookies]} {
foreach {nm val} [dict get $wapp .new-cookies] {
if {[regexp {^[a-z][-a-z0-9_]*$} $nm]} {
if {$val==""} {
puts $chan "Set-Cookie: $nm=; HttpOnly; Path=/; Max-Age=1\r"
} else {
set val [wappInt-enc-url $val]
puts $chan "Set-Cookie: $nm=$val; HttpOnly; Path=/\r"
}
}
}
}
if {[string match text/* $mimetype]} {
set reply [encoding convertto utf-8 [dict get $wapp .reply]]
if {[regexp {\ygzip\y} [wapp-param HTTP_ACCEPT_ENCODING]]} {
catch {
set x [zlib gzip $reply]
set reply $x
puts $chan "Content-Encoding: gzip\r"
}
}
} else {
set reply [dict get $wapp .reply]
}
puts $chan "Content-Length: [string length $reply]\r"
puts $chan \r
puts -nonewline $chan $reply
flush $chan
wappInt-close-channel $chan
}
# This routine runs just prior to request-handler dispatch. The
# default implementation is a no-op, but applications can override
# to do additional transformations or checks.
#
proc wapp-before-dispatch-hook {} {return}
# Process a single CGI request
#
proc wappInt-handle-cgi-request {} {
global wapp env
foreach key {
CONTENT_LENGTH
CONTENT_TYPE
DOCUMENT_ROOT
HTTP_ACCEPT_ENCODING
HTTP_COOKIE
HTTP_HOST
HTTP_REFERER
HTTP_USER_AGENT
HTTPS
PATH_INFO
QUERY_STRING
REMOTE_ADDR
REQUEST_METHOD
REQUEST_URI
REMOTE_USER
SCRIPT_FILENAME
SCRIPT_NAME
SERVER_NAME
SERVER_PORT
SERVER_PROTOCOL
} {
if {[info exists env($key)]} {
dict set wapp $key $env($key)
}
}
set len 0
if {[dict exists $wapp CONTENT_LENGTH]} {
set len [dict get $wapp CONTENT_LENGTH]
}
if {$len>0} {
fconfigure stdin -translation binary
dict set wapp CONTENT [read stdin $len]
}
dict set wapp WAPP_MODE cgi
fconfigure stdout -translation binary
wappInt-handle-request stdout 1
}
# Process new text received on an inbound SCGI request
#
proc wappInt-scgi-readable {chan} {
if {[catch [list wappInt-scgi-readable-unsafe $chan] msg]} {
puts stderr "$msg\n$::errorInfo"
wappInt-close-channel $chan
}
}
proc wappInt-scgi-readable-unsafe {chan} {
upvar #0 wappInt-$chan W wapp wapp
if {![dict exists $W .toread]} {
# If the .toread key is not set, that means we are still reading
# the header.
#
# An SGI header is short. This implementation assumes the entire
# header is available all at once.
#
dict set W .remove_addr [dict get $W REMOTE_ADDR]
set req [read $chan 15]
set n [string length $req]
scan $req %d:%s len hdr
incr len [string length "$len:,"]
append hdr [read $chan [expr {$len-15}]]
foreach {nm val} [split $hdr \000] {
if {$nm==","} break
dict set W $nm $val
}
set len 0
if {[dict exists $W CONTENT_LENGTH]} {
set len [dict get $W CONTENT_LENGTH]
}
if {$len>0} {
# Still need to read the query content
dict set W .toread $len
} else {
# There is no query content, so handle the request immediately
dict set W SERVER_ADDR [dict get $W .remove_addr]
set wapp $W
wappInt-handle-request $chan 0
}
} else {
# If .toread is set, that means we are reading the query content.
# Continue reading until .toread reaches zero.
set got [read $chan [dict get $W .toread]]
dict append W CONTENT $got
dict set W .toread [expr {[dict get $W .toread]-[string length $got]}]
if {[dict get $W .toread]<=0} {
# Handle the request as soon as all the query content is received
dict set W SERVER_ADDR [dict get $W .remove_addr]
set wapp $W
wappInt-handle-request $chan 0
}
}
}
# Start up the wapp framework. Parameters are a list passed as the
# single argument.
#
# -server $PORT Listen for HTTP requests on this TCP port $PORT
#
# -local $PORT Listen for HTTP requests on 127.0.0.1:$PORT
#
# -scgi $PORT Listen for SCGI requests on 127.0.0.1:$PORT
#
# -remote-scgi $PORT Listen for SCGI requests on TCP port $PORT
#
# -cgi Handle a single CGI request
#
# With no arguments, the behavior is called "auto". In "auto" mode,
# if the GATEWAY_INTERFACE environment variable indicates CGI, then run
# as CGI. Otherwise, start an HTTP server bound to the loopback address
# only, on an arbitrary TCP port, and automatically launch a web browser
# on that TCP port.
#
# Additional options:
#
# -fromip GLOB Reject any incoming request where the remote
# IP address does not match the GLOB pattern. This
# value defaults to '127.0.0.1' for -local and -scgi.
#
# -nowait Do not wait in the event loop. Return immediately
# after all event handlers are established.
#
# -trace "puts" each request URL as it is handled, for
# debugging
#
# -lint Run wapp-safety-check on the application instead
# of running the application itself
#
# -Dvar=value Set TCL global variable "var" to "value"
#
#
proc wapp-start {arglist} {
global env
set mode auto
set port 0
set nowait 0
set fromip {}
set n [llength $arglist]
for {set i 0} {$i<$n} {incr i} {
set term [lindex $arglist $i]
if {[string match --* $term]} {set term [string range $term 1 end]}
switch -glob -- $term {
-server {
incr i;
set mode "server"
set port [lindex $arglist $i]
}
-local {
incr i;
set mode "local"
set fromip 127.0.0.1
set port [lindex $arglist $i]
}
-scgi {
incr i;
set mode "scgi"
set fromip 127.0.0.1
set port [lindex $arglist $i]
}
-remote-scgi {
incr i;
set mode "remote-scgi"
set port [lindex $arglist $i]
}
-cgi {
set mode "cgi"
}
-fromip {
incr i
set fromip [lindex $arglist $i]
}
-nowait {
set nowait 1
}
-trace {
proc wappInt-trace {} {
set q [wapp-param QUERY_STRING]
set uri [wapp-param BASE_URL][wapp-param PATH_INFO]
if {$q!=""} {append uri ?$q}
puts $uri
}
}
-lint {
set res [wapp-safety-check]
if {$res!=""} {
puts "Potential problems in this code:"
puts $res
exit 1
} else {
exit
}
}
-D*=* {
if {[regexp {^.D([^=]+)=(.*)$} $term all var val]} {
set ::$var $val
}
}
default {
error "unknown option: $term"
}
}
}
if {$mode=="auto"} {
if {[info exists env(GATEWAY_INTERFACE)]
&& [string match CGI/1.* $env(GATEWAY_INTERFACE)]} {
set mode cgi
} else {
set mode local
}
}
if {$mode=="cgi"} {
wappInt-handle-cgi-request
} else {
wappInt-start-listener $port $mode $fromip
if {!$nowait} {
vwait ::forever
}
}
}
# Call this version 1.0
package provide wapp 1.0
+673
View File
@@ -0,0 +1,673 @@
#!/bin/sh
# \
exec wapptclsh "$0" ${1+"$@"}
# package required wapp
source [file join [file dirname [info script]] wapp.tcl]
# Read the data from the releasetest_data.tcl script.
#
source [file join [file dirname [info script]] releasetest_data.tcl]
# Variables set by the "control" form:
#
# G(platform) - User selected platform.
# G(test) - Set to "Normal", "Veryquick", "Smoketest" or "Build-Only".
# G(keep) - Boolean. True to delete no files after each test.
# G(msvc) - Boolean. True to use MSVC as the compiler.
# G(tcl) - Use Tcl from this directory for builds.
# G(jobs) - How many sub-processes to run simultaneously.
#
set G(platform) $::tcl_platform(os)-$::tcl_platform(machine)
set G(test) Normal
set G(keep) 0
set G(msvc) 0
set G(tcl) [::tcl::pkgconfig get libdir,install]
set G(jobs) 3
set G(debug) 0
proc wapptest_init {} {
global G
set lSave [list platform test keep msvc tcl jobs debug]
foreach k $lSave { set A($k) $G($k) }
array unset G
foreach k $lSave { set G($k) $A($k) }
# The root of the SQLite source tree.
set G(srcdir) [file dirname [file dirname [info script]]]
# releasetest.tcl script
set G(releaseTest) [file join [file dirname [info script]] releasetest.tcl]
set G(sqlite_version) "unknown"
# Either "config", "running" or "stopped":
set G(state) "config"
set G(hostname) "(unknown host)"
catch { set G(hostname) [exec hostname] }
set G(host) $G(hostname)
append G(host) " $::tcl_platform(os) $::tcl_platform(osVersion)"
append G(host) " $::tcl_platform(machine) $::tcl_platform(byteOrder)"
}
# Check to see if there are uncommitted changes in the SQLite source
# directory. Return true if there are, or false otherwise.
#
proc check_uncommitted {} {
global G
set ret 0
set pwd [pwd]
cd $G(srcdir)
if {[catch {exec fossil changes} res]==0 && [string trim $res]!=""} {
set ret 1
}
cd $pwd
return $ret
}
proc generate_fossil_info {} {
global G
set pwd [pwd]
cd $G(srcdir)
if {[catch {exec fossil info} r1]} return
if {[catch {exec fossil changes} r2]} return
cd $pwd
foreach line [split $r1 "\n"] {
if {[regexp {^checkout: *(.*)$} $line -> co]} {
wapp-trim { <br> %html($co) }
}
}
if {[string trim $r2]!=""} {
wapp-trim {
<br><span class=warning>
WARNING: Uncommitted changes in checkout
</span>
}
}
}
# If the application is in "config" state, set the contents of the
# ::G(test_array) global to reflect the tests that will be run. If the
# app is in some other state ("running" or "stopped"), this command
# is a no-op.
#
proc set_test_array {} {
global G
if { $G(state)=="config" } {
set G(test_array) [list]
foreach {config target} $::Platforms($G(platform)) {
# If using MSVC, do not run sanitize or valgrind tests. Or the
# checksymbols test.
if {$G(msvc) && (
"Sanitize" == $config
|| "checksymbols" in $target
|| "valgrindtest" in $target
)} {
continue
}
# If the test mode is not "Normal", override the target.
#
if {$target!="checksymbols" && $G(platform)!="Failure-Detection"} {
switch -- $G(test) {
Veryquick { set target quicktest }
Smoketest { set target smoketest }
Build-Only {
set target testfixture
if {$::tcl_platform(platform)=="windows"} {
set target testfixture.exe
}
}
}
}
lappend G(test_array) [dict create config $config target $target]
set exclude [list checksymbols valgrindtest fuzzoomtest]
if {$G(debug) && !($target in $exclude)} {
set debug_idx [lsearch -glob $::Configs($config) -DSQLITE_DEBUG*]
set xtarget $target
regsub -all {fulltest[a-z]*} $xtarget test xtarget
if {$debug_idx<0} {
lappend G(test_array) [
dict create config $config-(Debug) target $target
]
} else {
lappend G(test_array) [
dict create config $config-(NDebug) target $xtarget
]
}
}
}
}
}
proc count_tests_and_errors {name logfile} {
global G
set fd [open $logfile rb]
set seen 0
while {![eof $fd]} {
set line [gets $fd]
if {[regexp {(\d+) errors out of (\d+) tests} $line all nerr ntest]} {
incr G(test.$name.nError) $nerr
incr G(test.$name.nTest) $ntest
set seen 1
if {$nerr>0} {
set G(test.$name.errmsg) $line
}
}
if {[regexp {runtime error: +(.*)} $line all msg]} {
# skip over "value is outside range" errors
if {[regexp {value .* is outside the range of representable} $line]} {
# noop
} else {
incr G(test.$name.nError)
if {$G(test.$name.errmsg)==""} {
set G(test.$name.errmsg) $msg
}
}
}
if {[regexp {fatal error +(.*)} $line all msg]} {
incr G(test.$name.nError)
if {$G(test.$name.errmsg)==""} {
set G(test.$name.errmsg) $msg
}
}
if {[regexp {ERROR SUMMARY: (\d+) errors.*} $line all cnt] && $cnt>0} {
incr G(test.$name.nError)
if {$G(test.$name.errmsg)==""} {
set G(test.$name.errmsg) $all
}
}
if {[regexp {^VERSION: 3\.\d+.\d+} $line]} {
set v [string range $line 9 end]
if {$G(sqlite_version) eq "unknown"} {
set G(sqlite_version) $v
} elseif {$G(sqlite_version) ne $v} {
set G(test.$name.errmsg) "version conflict: {$G(sqlite_version)} vs. {$v}"
}
}
}
close $fd
if {$G(test) == "Build-Only"} {
incr G(test.$name.nTest)
if {$G(test.$name.nError)>0} {
set errmsg "Build failed"
}
} elseif {!$seen} {
set G(test.$name.errmsg) "Test did not complete"
if {[file readable core]} {
append G(test.$name.errmsg) " - core file exists"
}
}
}
proc slave_test_done {name rc} {
global G
set G(test.$name.done) [clock seconds]
set G(test.$name.nError) 0
set G(test.$name.nTest) 0
set G(test.$name.errmsg) ""
if {$rc} {
incr G(test.$name.nError)
}
if {[file exists $G(test.$name.log)]} {
count_tests_and_errors $name $G(test.$name.log)
}
}
proc slave_fileevent {name} {
global G
set fd $G(test.$name.channel)
if {[eof $fd]} {
fconfigure $fd -blocking 1
set rc [catch { close $fd }]
unset G(test.$name.channel)
slave_test_done $name $rc
} else {
set line [gets $fd]
if {[string trim $line] != ""} { puts "Trace : $name - \"$line\"" }
}
do_some_stuff
}
proc do_some_stuff {} {
global G
# Count the number of running jobs. A running job has an entry named
# "channel" in its dictionary.
set nRunning 0
set bFinished 1
foreach j $G(test_array) {
set name [dict get $j config]
if { [info exists G(test.$name.channel)]} { incr nRunning }
if {![info exists G(test.$name.done)]} { set bFinished 0 }
}
if {$bFinished} {
set nError 0
set nTest 0
set nConfig 0
foreach j $G(test_array) {
set name [dict get $j config]
incr nError $G(test.$name.nError)
incr nTest $G(test.$name.nTest)
incr nConfig
}
set G(result) "$nError errors from $nTest tests in $nConfig configurations."
catch {
append G(result) " SQLite version $G(sqlite_version)"
}
set G(state) "stopped"
} else {
set nLaunch [expr $G(jobs) - $nRunning]
foreach j $G(test_array) {
if {$nLaunch<=0} break
set name [dict get $j config]
if { ![info exists G(test.$name.channel)]
&& ![info exists G(test.$name.done)]
} {
set target [dict get $j target]
set G(test.$name.start) [clock seconds]
set fd [open "|[info nameofexecutable] $G(releaseTest) --slave" r+]
set G(test.$name.channel) $fd
fconfigure $fd -blocking 0
fileevent $fd readable [list slave_fileevent $name]
puts $fd [list 0 $G(msvc) 0 $G(keep)]
set wtcl ""
if {$G(tcl)!=""} { set wtcl "--with-tcl=$G(tcl)" }
# If this configuration is named <name>-(Debug) or <name>-(NDebug),
# then add or remove the SQLITE_DEBUG option from the base
# configuration before running the test.
if {[regexp -- {(.*)-(\(.*\))} $name -> head tail]} {
set opts $::Configs($head)
if {$tail=="(Debug)"} {
append opts " -DSQLITE_DEBUG=1 -DSQLITE_EXTRA_IFNULLROW=1"
} else {
regsub { *-DSQLITE_MEMDEBUG[^ ]* *} $opts { } opts
regsub { *-DSQLITE_DEBUG[^ ]* *} $opts { } opts
}
} else {
set opts $::Configs($name)
}
set L [make_test_suite $G(msvc) $wtcl $name $target $opts]
puts $fd $L
flush $fd
set G(test.$name.log) [file join [lindex $L 1] test.log]
incr nLaunch -1
}
}
}
}
proc generate_select_widget {label id lOpt opt} {
wapp-trim {
<label> %string($label) </label>
<select id=%string($id) name=%string($id)>
}
foreach o $lOpt {
set selected ""
if {$o==$opt} { set selected " selected=1" }
wapp-subst "<option $selected>$o</option>"
}
wapp-trim { </select> }
}
proc generate_main_page {{extra {}}} {
global G
set_test_array
set hostname $G(hostname)
wapp-trim {
<html>
<head>
<title> %html($hostname): wapptest.tcl </title>
<link rel="stylesheet" type="text/css" href="style.css"/>
</head>
<body>
}
set host $G(host)
wapp-trim {
<div class="border">%string($host)
}
generate_fossil_info
wapp-trim {
</div>
<div class="border" id=controls>
<form action="control" method="post" name="control">
}
# Build the "platform" select widget.
set lOpt [array names ::Platforms]
generate_select_widget Platform control_platform $lOpt $G(platform)
# Build the "test" select widget.
set lOpt [list Normal Veryquick Smoketest Build-Only]
generate_select_widget Test control_test $lOpt $G(test)
# Build the "jobs" select widget. Options are 1 to 8.
generate_select_widget Jobs control_jobs {1 2 3 4 5 6 7 8} $G(jobs)
switch $G(state) {
config {
set txt "Run Tests!"
set id control_run
}
running {
set txt "STOP Tests!"
set id control_stop
}
stopped {
set txt "Reset!"
set id control_reset
}
}
wapp-trim {
<div class=right>
<input id=%string($id) name=%string($id) type=submit value="%string($txt)">
</input>
</div>
}
wapp-trim {
<br><br>
<label> Tcl: </label>
<input id="control_tcl" name="control_tcl"></input>
<label> Keep files: </label>
<input id="control_keep" name="control_keep" type=checkbox value=1>
</input>
<label> Use MSVC: </label>
<input id="control_msvc" name="control_msvc" type=checkbox value=1>
<label> Debug tests: </label>
<input id="control_debug" name="control_debug" type=checkbox value=1>
</input>
}
wapp-trim {
</form>
}
wapp-trim {
</div>
<div id=tests>
}
wapp-page-tests
set script "script/$G(state).js"
wapp-trim {
</div>
<script src=%string($script)></script>
</body>
</html>
}
}
proc wapp-default {} {
generate_main_page
}
proc wapp-page-tests {} {
global G
wapp-trim { <table class="border" width=100%> }
foreach t $G(test_array) {
set config [dict get $t config]
set target [dict get $t target]
set class "testwait"
set seconds ""
if {[info exists G(test.$config.log)]} {
if {[info exists G(test.$config.channel)]} {
set class "testrunning"
set seconds [expr [clock seconds] - $G(test.$config.start)]
} elseif {[info exists G(test.$config.done)]} {
if {$G(test.$config.nError)>0} {
set class "testfail"
} else {
set class "testdone"
}
set seconds [expr $G(test.$config.done) - $G(test.$config.start)]
}
set min [format %.2d [expr ($seconds / 60) % 60]]
set hr [format %.2d [expr $seconds / 3600]]
set sec [format %.2d [expr $seconds % 60]]
set seconds "$hr:$min:$sec"
}
wapp-trim {
<tr class=%string($class)>
<td class="nowrap"> %html($config)
<td class="padleft nowrap"> %html($target)
<td class="padleft nowrap"> %html($seconds)
<td class="padleft nowrap">
}
if {[info exists G(test.$config.log)]} {
set log $G(test.$config.log)
set uri "log/$log"
wapp-trim {
<a href=%url($uri)> %html($log) </a>
}
}
if {[info exists G(test.$config.errmsg)] && $G(test.$config.errmsg)!=""} {
set errmsg $G(test.$config.errmsg)
wapp-trim {
<tr class=testfail>
<td> <td class="padleft" colspan=3> %html($errmsg)
}
}
}
wapp-trim { </table> }
if {[info exists G(result)]} {
set res $G(result)
wapp-trim {
<div class=border id=result> %string($res) </div>
}
}
}
# URI: /control
#
# Whenever the form at the top of the application page is submitted, it
# is submitted here.
#
proc wapp-page-control {} {
global G
if {$::G(state)=="config"} {
set lControls [list platform test tcl jobs keep msvc debug]
set G(msvc) 0
set G(keep) 0
set G(debug) 0
} else {
set lControls [list jobs]
}
foreach v $lControls {
if {[wapp-param-exists control_$v]} {
set G($v) [wapp-param control_$v]
}
}
if {[wapp-param-exists control_run]} {
# This is a "run test" command.
set_test_array
set ::G(state) "running"
}
if {[wapp-param-exists control_stop]} {
# A "STOP tests" command.
set G(state) "stopped"
set G(result) "Test halted by user"
foreach j $G(test_array) {
set name [dict get $j config]
if { [info exists G(test.$name.channel)] } {
close $G(test.$name.channel)
unset G(test.$name.channel)
slave_test_done $name 1
}
}
}
if {[wapp-param-exists control_reset]} {
# A "reset app" command.
set G(state) "config"
wapptest_init
}
if {$::G(state) == "running"} {
do_some_stuff
}
wapp-redirect /
}
# URI: /style.css
#
# Return the stylesheet for the application main page.
#
proc wapp-page-style.css {} {
wapp-subst {
/* The boxes with black borders use this class */
.border {
border: 3px groove #444444;
padding: 1em;
margin-top: 1em;
margin-bottom: 1em;
}
/* Float to the right (used for the Run/Stop/Reset button) */
.right { float: right; }
/* Style for the large red warning at the top of the page */
.warning {
color: red;
font-weight: bold;
}
/* Styles used by cells in the test table */
.padleft { padding-left: 5ex; }
.nowrap { white-space: nowrap; }
/* Styles for individual tests, depending on the outcome */
.testwait { }
.testrunning { color: blue }
.testdone { color: green }
.testfail { color: red }
}
}
# URI: /script/${state}.js
#
# The last part of this URI is always "config.js", "running.js" or
# "stopped.js", depending on the state of the application. It returns
# the javascript part of the front-end for the requested state to the
# browser.
#
proc wapp-page-script {} {
regexp {[^/]*$} [wapp-param REQUEST_URI] script
set tcl $::G(tcl)
set keep $::G(keep)
set msvc $::G(msvc)
set debug $::G(debug)
wapp-subst {
var lElem = \["control_platform", "control_test", "control_msvc",
"control_jobs", "control_debug"
\];
lElem.forEach(function(e) {
var elem = document.getElementById(e);
elem.addEventListener("change", function() { control.submit() } );
})
elem = document.getElementById("control_tcl");
elem.value = "%string($tcl)"
elem = document.getElementById("control_keep");
elem.checked = %string($keep);
elem = document.getElementById("control_msvc");
elem.checked = %string($msvc);
elem = document.getElementById("control_debug");
elem.checked = %string($debug);
}
if {$script != "config.js"} {
wapp-subst {
var lElem = \["control_platform", "control_test",
"control_tcl", "control_keep", "control_msvc"
\];
lElem.forEach(function(e) {
var elem = document.getElementById(e);
elem.disabled = true;
})
}
}
if {$script == "running.js"} {
wapp-subst {
function reload_tests() {
fetch('tests')
.then( data => data.text() )
.then( data => {
document.getElementById("tests").innerHTML = data;
})
.then( data => {
if( document.getElementById("result") ){
document.location = document.location;
} else {
setTimeout(reload_tests, 1000)
}
});
}
setTimeout(reload_tests, 1000)
}
}
}
# URI: /env
#
# This is for debugging only. Serves no other purpose.
#
proc wapp-page-env {} {
wapp-allow-xorigin-params
wapp-trim {
<h1>Wapp Environment</h1>\n<pre>
<pre>%html([wapp-debug-env])</pre>
}
}
# URI: /log/dirname/test.log
#
# This URI reads file "dirname/test.log" from disk, wraps it in a <pre>
# block, and returns it to the browser. Use for viewing log files.
#
proc wapp-page-log {} {
set log [string range [wapp-param REQUEST_URI] 5 end]
set fd [open $log]
set data [read $fd]
close $fd
wapp-trim {
<pre>
%html($data)
</pre>
}
}
wapptest_init
wapp-start $argv
+101
View File
@@ -1438,4 +1438,105 @@ do_execsql_test where-23.0 {
SELECT * FROM t1, t2 WHERE a=y AND y=3;
} {3 2 3}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test where-24.0 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
INSERT INTO t1 VALUES(1, 'one');
INSERT INTO t1 VALUES(2, 'two');
INSERT INTO t1 VALUES(3, 'three');
INSERT INTO t1 VALUES(4, 'four');
}
foreach {tn sql res} {
1 "SELECT b FROM t1" {one two three four}
2 "SELECT b FROM t1 WHERE a<4" {one two three}
3 "SELECT b FROM t1 WHERE a>1" {two three four}
4 "SELECT b FROM t1 WHERE a>1 AND a<4" {two three}
5 "SELECT b FROM t1 WHERE a>? AND a<4" {}
6 "SELECT b FROM t1 WHERE a>1 AND a<?" {}
7 "SELECT b FROM t1 WHERE a>? AND a<?" {}
7 "SELECT b FROM t1 WHERE a>=? AND a<=4" {}
8 "SELECT b FROM t1 WHERE a>=1 AND a<=?" {}
9 "SELECT b FROM t1 WHERE a>=? AND a<=?" {}
} {
set rev [list]
foreach r $res { set rev [concat $r $rev] }
do_execsql_test where-24.$tn.1 "$sql" $res
do_execsql_test where-24.$tn.2 "$sql ORDER BY rowid" $res
do_execsql_test where-24.$tn.3 "$sql ORDER BY rowid DESC" $rev
do_execsql_test where-24-$tn.4 "
BEGIN;
DELETE FROM t1;
$sql;
$sql ORDER BY rowid;
$sql ORDER BY rowid DESC;
ROLLBACK;
"
}
#-------------------------------------------------------------------------
#
reset_db
do_execsql_test where-25.0 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
CREATE UNIQUE INDEX i1 ON t1(c);
INSERT INTO t1 VALUES(1, 'one', 'i');
INSERT INTO t1 VALUES(2, 'two', 'ii');
CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c);
CREATE UNIQUE INDEX i2 ON t2(c);
INSERT INTO t2 VALUES(1, 'one', 'i');
INSERT INTO t2 VALUES(2, 'two', 'ii');
INSERT INTO t2 VALUES(3, 'three', 'iii');
PRAGMA writable_schema = 1;
UPDATE sqlite_master SET rootpage = (
SELECT rootpage FROM sqlite_master WHERE name = 'i2'
) WHERE name = 'i1';
}
db close
sqlite3 db test.db
do_catchsql_test where-25.1 {
DELETE FROM t1 WHERE c='iii'
} {1 {database disk image is malformed}}
do_catchsql_test where-25.2 {
INSERT INTO t1 VALUES(4, 'four', 'iii')
ON CONFLICT(c) DO UPDATE SET b=NULL
} {1 {database disk image is malformed}}
reset_db
do_execsql_test where-25.3 {
CREATE TABLE t1(a PRIMARY KEY, b, c) WITHOUT ROWID;
CREATE UNIQUE INDEX i1 ON t1(c);
INSERT INTO t1 VALUES(1, 'one', 'i');
INSERT INTO t1 VALUES(2, 'two', 'ii');
CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c);
CREATE UNIQUE INDEX i2 ON t2(c);
INSERT INTO t2 VALUES(1, 'one', 'i');
INSERT INTO t2 VALUES(2, 'two', 'ii');
INSERT INTO t2 VALUES(3, 'three', 'iii');
PRAGMA writable_schema = 1;
UPDATE sqlite_master SET rootpage = (
SELECT rootpage FROM sqlite_master WHERE name = 'i2'
) WHERE name = 'i1';
}
db close
sqlite3 db test.db
do_catchsql_test where-25.4 {
SELECT * FROM t1 WHERE c='iii'
} {0 {}}
do_catchsql_test where-25.5 {
INSERT INTO t1 VALUES(4, 'four', 'iii')
ON CONFLICT(c) DO UPDATE SET b=NULL
} {1 {corrupt database}}
finish_test
+98
View File
@@ -1067,7 +1067,105 @@ do_execsql_test 26.3 {
) FROM t2
} {1 1 2 0 3 1 4 0}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 27.0 {
CREATE TABLE t1(x);
INSERT INTO t1 VALUES(NULL), (1), (2), (3), (4), (5);
}
do_execsql_test 27.1 {
SELECT min(x) FROM t1;
} {1}
do_execsql_test 27.2 {
SELECT min(x) OVER win FROM t1
WINDOW win AS (ORDER BY rowid ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
} {1 1 1 2 3 4}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 28.1.1 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b CHAR(1), c CHAR(2), d ANY);
INSERT INTO t1 VALUES (3, 'C', 'cc', 1.0);
INSERT INTO t1 VALUES (13,'M', 'cc', NULL);
}
do_execsql_test 28.1.2 {
SELECT group_concat(b,'') OVER w1 FROM t1
WINDOW w1 AS (ORDER BY a RANGE BETWEEN 3 PRECEDING AND 1 PRECEDING)
} {
{} {}
}
do_execsql_test 28.2.1 {
CREATE TABLE t2(a TEXT, b INTEGER);
INSERT INTO t2 VALUES('A', NULL);
INSERT INTO t2 VALUES('B', NULL);
}
do_execsql_test 28.2.1 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b CHAR(1), c CHAR(2), d ANY);
INSERT INTO t1 VALUES
(10,'J', 'cc', NULL),
(11,'K', 'cc', 'xyz'),
(13,'M', 'cc', NULL);
}
do_execsql_test 28.2.2 {
SELECT a, b, c, quote(d), group_concat(b,'') OVER w1, '|' FROM t1
WINDOW w1 AS
(ORDER BY d DESC RANGE BETWEEN 7.0 PRECEDING AND 2.5 PRECEDING)
ORDER BY c, d, a;
} {
10 J cc NULL JM |
13 M cc NULL JM |
11 K cc 'xyz' K |
}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 29.1 {
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INTEGER PRIMARY KEY, b CHAR(1), c CHAR(2), d ANY);
INSERT INTO t1 VALUES
(1, 'A', 'aa', 2.5),
(2, 'B', 'bb', 3.75),
(3, 'C', 'cc', 1.0),
(4, 'D', 'cc', 8.25),
(5, 'E', 'bb', 6.5),
(6, 'F', 'aa', 6.5),
(7, 'G', 'aa', 6.0),
(8, 'H', 'bb', 9.0),
(9, 'I', 'aa', 3.75),
(10,'J', 'cc', NULL),
(11,'K', 'cc', 'xyz'),
(12,'L', 'cc', 'xyZ'),
(13,'M', 'cc', NULL);
}
do_execsql_test 29.2 {
SELECT a, b, c, quote(d), group_concat(b,'') OVER w1, '|' FROM t1
WINDOW w1 AS
(PARTITION BY c ORDER BY d DESC
RANGE BETWEEN 7.0 PRECEDING AND 2.5 PRECEDING)
ORDER BY c, d, a;
} {
1 A aa 2.5 FG |
9 I aa 3.75 F |
7 G aa 6 {} |
6 F aa 6.5 {} |
2 B bb 3.75 HE |
5 E bb 6.5 H |
8 H bb 9 {} |
10 J cc NULL JM |
13 M cc NULL JM |
3 C cc 1 {} |
4 D cc 8.25 {} |
12 L cc 'xyZ' L |
11 K cc 'xyz' K |
}
finish_test
+25
View File
@@ -269,6 +269,31 @@ foreach {tn ex} {
}
}
==========
execsql_test 6.0 {
DROP TABLE IF EXISTS t2;
CREATE TABLE t2(a TEXT, b INTEGER);
INSERT INTO t2 VALUES('A', NULL);
INSERT INTO t2 VALUES('B', NULL);
INSERT INTO t2 VALUES('C', 1);
}
execsql_test 6.1 {
SELECT string_agg(a, '.') OVER (
ORDER BY b NULLS FIRST RANGE BETWEEN 7 PRECEDING AND 2 PRECEDING
)
FROM t2
}
execsql_test 6.2 {
SELECT string_agg(a, '.') OVER (
ORDER BY b DESC NULLS LAST RANGE BETWEEN 7 PRECEDING AND 2 PRECEDING
)
FROM t2
}
finish_test
+32 -8
View File
@@ -3841,7 +3841,7 @@ do_execsql_test 5.1.7.1 {
count(a) OVER win
FROM t3
WINDOW win AS ( ORDER BY c , b , a
ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS )
ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS )
ORDER BY 1 , 2 , 3
} {979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83
979 102 83 979 113 81 979 113 82 979 133 80 979 148 79 979 158 77
@@ -3865,7 +3865,7 @@ do_execsql_test 5.1.7.2 {
dense_rank() OVER win
FROM t3
WINDOW win AS ( ORDER BY c , b , a
ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS )
ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE NO OTHERS )
ORDER BY 1 , 2 , 3
} {3830 89 89 4741 88 88 5640 84 84 5640 85 85 5640 86 86 5640 87 87
6485 81 81 6485 82 82 6485 83 83 7324 80 80 8163 78 78 8163 79 79
@@ -4166,7 +4166,7 @@ do_execsql_test 5.2.7.1 {
count(a) OVER win
FROM t3
WINDOW win AS ( ORDER BY c , b , a
ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW )
ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW )
ORDER BY 1 , 2 , 3
} {963 929 6 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82
979 102 83 979 113 80 979 113 81 979 113 82 979 133 79 979 148 78
@@ -4190,7 +4190,7 @@ do_execsql_test 5.2.7.2 {
dense_rank() OVER win
FROM t3
WINDOW win AS ( ORDER BY c , b , a
ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW )
ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE CURRENT ROW )
ORDER BY 1 , 2 , 3
} {2851 89 89 3778 88 88 4681 87 87 5556 83 83 5574 82 82 5586 81 81
5640 84 84 5640 85 85 5640 86 86 7324 80 80 8123 77 77 8129 73 73
@@ -4481,7 +4481,7 @@ do_execsql_test 5.3.7.1 {
count(a) OVER win
FROM t3
WINDOW win AS ( ORDER BY c , b , a
ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE GROUP )
ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE GROUP )
ORDER BY 1 , 2 , 3
} {963 929 6 979 102 82 979 102 82 979 102 82 979 102 82 979 102 82
979 102 83 979 113 80 979 113 81 979 113 82 979 133 79 979 148 78
@@ -4505,7 +4505,7 @@ do_execsql_test 5.3.7.2 {
dense_rank() OVER win
FROM t3
WINDOW win AS ( ORDER BY c , b , a
ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE GROUP )
ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE GROUP )
ORDER BY 1 , 2 , 3
} {2851 89 89 3778 88 88 4681 87 87 5556 83 83 5574 82 82 5586 81 81
5640 84 84 5640 85 85 5640 86 86 7324 80 80 8123 77 77 8129 73 73
@@ -4804,7 +4804,7 @@ do_execsql_test 5.4.7.1 {
count(a) OVER win
FROM t3
WINDOW win AS ( ORDER BY c , b , a
ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE TIES )
ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE TIES )
ORDER BY 1 , 2 , 3
} {979 102 83 979 102 83 979 102 83 979 102 83 979 102 83 979 102 83
979 102 83 979 113 81 979 113 82 979 133 80 979 148 79 979 158 77
@@ -4828,7 +4828,7 @@ do_execsql_test 5.4.7.2 {
dense_rank() OVER win
FROM t3
WINDOW win AS ( ORDER BY c , b , a
ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE TIES )
ROWS BETWEEN 6 PRECEDING AND UNBOUNDED FOLLOWING EXCLUDE TIES )
ORDER BY 1 , 2 , 3
} {3830 89 89 4741 88 88 5640 84 84 5640 85 85 5640 86 86 5640 87 87
6485 81 81 6485 82 82 6485 83 83 7324 80 80 8163 78 78 8163 79 79
@@ -4848,4 +4848,28 @@ do_execsql_test 5.4.7.2 {
22796 16 16 22929 10 10 23042 9 9 23155 1 1 23155 2 2 23155 3 3
23155 4 4 23155 5 5 23155 6 6 23155 7 7 23155 8 8}
#==========================================================================
do_execsql_test 6.0 {
DROP TABLE IF EXISTS t2;
CREATE TABLE t2(a TEXT, b INTEGER);
INSERT INTO t2 VALUES('A', NULL);
INSERT INTO t2 VALUES('B', NULL);
INSERT INTO t2 VALUES('C', 1);
} {}
do_execsql_test 6.1 {
SELECT group_concat(a, '.') OVER (
ORDER BY b RANGE BETWEEN 7 PRECEDING AND 2 PRECEDING
)
FROM t2
} {A.B A.B {}}
do_execsql_test 6.2 {
SELECT group_concat(a, '.') OVER (
ORDER BY b DESC RANGE BETWEEN 7 PRECEDING AND 2 PRECEDING
)
FROM t2
} {{} A.B A.B}
finish_test
+9
View File
@@ -55,6 +55,15 @@ errorsql_test 2.2 {
SELECT sum(a) OVER () AS xyz FROM t1 ORDER BY sum(xyz);
}
errorsql_test 3.0 {
SELECT sum(a) OVER win FROM t1
WINDOW win AS (ROWS BETWEEN 'hello' PRECEDING AND 10 FOLLOWING)
}
errorsql_test 3.2 {
SELECT sum(a) OVER win FROM t1
WINDOW win AS (ROWS BETWEEN 10 PRECEDING AND x'ABCD' FOLLOWING)
}
finish_test
+12
View File
@@ -96,4 +96,16 @@ do_test 2.2 { catch { execsql {
SELECT sum(a) OVER () AS xyz FROM t1 ORDER BY sum(xyz);
} } } 1
# PG says ERROR: invalid input syntax for integer: "hello"
do_test 3.0 { catch { execsql {
SELECT sum(a) OVER win FROM t1
WINDOW win AS (ROWS BETWEEN 'hello' PRECEDING AND 10 FOLLOWING)
} } } 1
# PG says ERROR: argument of ROWS must be type bigint, not type bit
do_test 3.2 { catch { execsql {
SELECT sum(a) OVER win FROM t1
WINDOW win AS (ROWS BETWEEN 10 PRECEDING AND x'ABCD' FOLLOWING)
} } } 1
finish_test
+61
View File
@@ -162,4 +162,65 @@ do_faultsim_test 8 -faults oom-t* -prep {
faultsim_test_result {0 {1 2 5 6 9 10}}
}
#-------------------------------------------------------------------------
# The following test causes a cursor in REQURESEEK state to be passed
# to sqlite3BtreeDelete(). An error is simulated within the seek operation
# to restore the cursors position.
#
reset_db
set big [string repeat x 900]
do_execsql_test 9.0 {
PRAGMA page_size = 512;
PRAGMA cache_size = 2;
CREATE TABLE t(x INTEGER PRIMARY KEY, y TEXT);
WITH s(i) AS (
VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<1900
)
INSERT INTO t(y) SELECT $big FROM s;
}
db close
testvfs tvfs -default 1
tvfs script vfs_callback
tvfs filter xRead
sqlite3 db test.db
proc vfs_callback {method file args} {
if {$file=="" && [info exists ::tmp_read_fail]} {
incr ::tmp_read_fail -1
if {$::tmp_read_fail<=0} {
return "SQLITE_IOERR"
}
}
return "SQLITE_OK"
}
set FAULTSIM(tmpread) [list \
-injectstart tmpread_injectstart \
-injectstop tmpread_injectstop \
-injecterrlist {{1 {disk I/O error}}} \
]
proc tmpread_injectstart {iFail} {
set ::tmp_read_fail $iFail
}
proc tmpread_injectstop {} {
set ret [expr $::tmp_read_fail<=0]
unset -nocomplain ::tmp_read_fail
return $ret
}
do_faultsim_test 9 -end 25 -faults tmpread -body {
execsql {
SELECT sum(y) OVER win FROM t
WINDOW win AS (
ORDER BY x ROWS BETWEEN UNBOUNDED PRECEDING AND 1800 FOLLOWING
)
}
} -test {
faultsim_test_result {0 {}}
}
catch {db close}
tvfs delete
finish_test
+36
View File
@@ -355,5 +355,41 @@ do_execsql_test 10.1 {
DELETE FROM t2 WHERE b=1
}
#-------------------------------------------------------------------------
# UNIQUE constraint violation in an UPDATE with a multi-column PK.
#
reset_db
do_execsql_test 10.0 {
CREATE TABLE t1(a, b, c UNIQUE, PRIMARY KEY(a, b)) WITHOUT ROWID;
INSERT INTO t1 VALUES('a', 'a', 1);
INSERT INTO t1 VALUES('a', 'b', 2);
INSERT INTO t1 VALUES('b', 'a', 3);
INSERT INTO t1 VALUES('b', 'b', 4);
}
do_catchsql_test 10.1 {
UPDATE t1 SET c=1 WHERE (a, b) = ('a', 'a');
} {0 {}}
do_catchsql_test 10.2 {
UPDATE t1 SET c=1 WHERE (a, b) = ('a', 'b');
} {1 {UNIQUE constraint failed: t1.c}}
do_catchsql_test 10.3 {
UPDATE t1 SET c=1 WHERE (a, b) = ('b', 'a');
} {1 {UNIQUE constraint failed: t1.c}}
do_catchsql_test 10.4 {
UPDATE t1 SET c=1 WHERE (a, b) = ('b', 'b');
} {1 {UNIQUE constraint failed: t1.c}}
do_catchsql_test 10.5 {
UPDATE t1 SET c=1 WHERE (a, b) = ('c', 'c');
} {0 {}}
do_execsql_test 10.6 {
CREATE TRIGGER t1_tr BEFORE UPDATE ON t1 BEGIN
DELETE FROM t1 WHERE a = new.a;
END;
UPDATE t1 SET c = c+1 WHERE a = 'a';
SELECT * FROM t1;
} {b a 3 b b 4}
finish_test
-64
View File
@@ -1,64 +0,0 @@
#!/usr/bin/tclsh
#
# This script appends additional token codes to the end of the
# parse.h file that lemon generates. These extra token codes are
# not used by the parser. But they are used by the tokenizer and/or
# the code generator.
#
#
set in [open [lindex $argv 0] rb]
set max 0
while {![eof $in]} {
set line [gets $in]
if {[regexp {^#define TK_} $line]} {
puts $line
set x [lindex $line 2]
if {$x>$max} {set max $x}
}
}
close $in
# The following are the extra token codes to be added. SPACE and
# ILLEGAL *must* be the last two token codes and they must be in that order.
#
set extras {
TRUEFALSE
ISNOT
FUNCTION
COLUMN
AGG_FUNCTION
AGG_COLUMN
UMINUS
UPLUS
TRUTH
REGISTER
VECTOR
SELECT_COLUMN
IF_NULL_ROW
ASTERISK
SPAN
END_OF_FILE
UNCLOSED_STRING
SPACE
ILLEGAL
}
if {[lrange $extras end-1 end]!="SPACE ILLEGAL"} {
error "SPACE and ILLEGAL must be the last two token codes and they\
must be in that order"
}
foreach x $extras {
incr max
puts [format "#define TK_%-29s %4d" $x $max]
}
# Some additional #defines related to token codes.
#
puts "\n/* The token codes above must all fit in 8 bits */"
puts [format "#define %-20s %-6s" TKFLG_MASK 0xff]
puts "\n/* Flags that can be added to a token code when it is not"
puts "** being stored in a u8: */"
foreach {fg val comment} {
TKFLG_DONTFOLD 0x100 {/* Omit constant folding optimizations */}
} {
puts [format "#define %-20s %-6s %s" $fg $val $comment]
}
+1 -1
View File
@@ -51,7 +51,7 @@ int main(int argc, char **argv){
unsigned char bShow[256]; /* Characters ok to display */
memset(bShow, '.', sizeof(bShow));
for(i=' '; i<='~'; i++){
if( i!='{' && i!='}' && i!='"' && i!='\\' ) bShow[i] = i;
if( i!='{' && i!='}' && i!='"' && i!='\\' ) bShow[i] = (unsigned char)i;
}
for(i=1; i<argc; i++){
if( argv[i][0]=='-' ){
+2 -2
View File
@@ -293,11 +293,11 @@ static Keyword aKeywordTable[] = {
{ "VALUES", "TK_VALUES", ALWAYS },
{ "VIEW", "TK_VIEW", VIEW },
{ "VIRTUAL", "TK_VIRTUAL", VTAB },
{ "WHEN", "TK_WHEN", ALWAYS },
{ "WHERE", "TK_WHERE", ALWAYS },
{ "WINDOW", "TK_WINDOW", WINDOWFUNC },
{ "WITH", "TK_WITH", CTE },
{ "WITHOUT", "TK_WITHOUT", ALWAYS },
{ "WHEN", "TK_WHEN", ALWAYS },
{ "WHERE", "TK_WHERE", ALWAYS },
};
/* Number of keywords */
+11 -2
View File
@@ -192,21 +192,23 @@ proc main {argv} {
SQLITE_OMIT_BETWEEN_OPTIMIZATION \
SQLITE_OMIT_BLOB_LITERAL \
SQLITE_OMIT_BTREECOUNT \
SQLITE_OMIT_BUILTIN_TEST \
SQLITE_OMIT_CAST \
SQLITE_OMIT_CHECK \
SQLITE_OMIT_COMPILEOPTION_DIAGS \
SQLITE_OMIT_COMPLETE \
SQLITE_OMIT_COMPOUND_SELECT \
SQLITE_OMIT_CONFLICT_CLAUSE \
SQLITE_OMIT_CTE \
SQLITE_OMIT_DATETIME_FUNCS \
SQLITE_OMIT_DECLTYPE \
SQLITE_OMIT_DEPRECATED \
SQLITE_OMIT_DISKIO \
SQLITE_OMIT_EXPLAIN \
SQLITE_OMIT_FLAG_PRAGMAS \
SQLITE_OMIT_FLOATING_POINT \
SQLITE_OMIT_FOREIGN_KEY \
SQLITE_OMIT_GET_TABLE \
SQLITE_OMIT_HEX_INTEGER \
SQLITE_OMIT_INCRBLOB \
SQLITE_OMIT_INTEGRITY_CHECK \
SQLITE_OMIT_LIKE_OPTIMIZATION \
@@ -214,27 +216,34 @@ proc main {argv} {
SQLITE_OMIT_LOCALTIME \
SQLITE_OMIT_LOOKASIDE \
SQLITE_OMIT_MEMORYDB \
SQLITE_OMIT_MEMORY_ALLOCATION \
SQLITE_OMIT_OR_OPTIMIZATION \
SQLITE_OMIT_PAGER_PRAGMAS \
SQLITE_OMIT_PARSER_TRACE \
SQLITE_OMIT_POPEN \
SQLITE_OMIT_PRAGMA \
SQLITE_OMIT_PROGRESS_CALLBACK \
SQLITE_OMIT_QUICKBALANCE \
SQLITE_OMIT_RANDOMNESS \
SQLITE_OMIT_REINDEX \
SQLITE_OMIT_SCHEMA_PRAGMAS \
SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS \
SQLITE_OMIT_SHARED_CACHE \
SQLITE_OMIT_SHUTDOWN_DIRECTORIES \
SQLITE_OMIT_SUBQUERY \
SQLITE_OMIT_TCL_VARIABLE \
SQLITE_OMIT_TEMPDB \
SQLITE_OMIT_TEST_CONTROL \
SQLITE_OMIT_TRACE \
SQLITE_OMIT_TRIGGER \
SQLITE_OMIT_TRUNCATE_OPTIMIZATION \
SQLITE_OMIT_UNIQUE_ENFORCEMENT \
SQLITE_OMIT_UPSERT \
SQLITE_OMIT_UTF16 \
SQLITE_OMIT_VACUUM \
SQLITE_OMIT_VIEW \
SQLITE_OMIT_VIRTUALTABLE \
SQLITE_OMIT_WAL \
SQLITE_OMIT_WINDOWFUNC \
SQLITE_OMIT_WSD \
SQLITE_OMIT_XFER_OPT \
]