Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ea00d744e | |||
| e639128cb0 | |||
| 323096175e | |||
| 971194aca3 | |||
| 579d41dc8d | |||
| 93673620ec | |||
| 523fb53f72 | |||
| 6adba9031c | |||
| 0364f229cc | |||
| 0e1a574875 | |||
| 86ec1eddde | |||
| 9e26ac852a | |||
| c3dcdba387 | |||
| c7f3373ec7 | |||
| a3020dcb21 | |||
| 25050f2620 | |||
| 427db2d245 | |||
| 7d683394f1 | |||
| ce3c3eeda0 | |||
| 7bbdc3c597 | |||
| f1722baaf8 | |||
| 6cf3009f6c | |||
| ce059e5219 | |||
| 94c7ab5038 | |||
| e3bd232e2d | |||
| 86223e8d65 | |||
| d1f9932e4b | |||
| 4c81cada05 | |||
| eacc8816dc | |||
| b84b38fd89 | |||
| 80ac9cb3c0 | |||
| 677525756b | |||
| eb80863cbf | |||
| 4e61e88348 | |||
| b92d7d264e | |||
| 3f49c321e8 | |||
| 0f134f0267 | |||
| 94809086e5 | |||
| 3de52e8fa0 | |||
| 3fda0aaf00 | |||
| 860d2b08c6 | |||
| e8975ac9e1 | |||
| 29ddbbbf36 | |||
| d6db6598ca | |||
| afb3f3c72c | |||
| 1d07f1d8c7 | |||
| 495ed62e85 | |||
| 83c5bb997a | |||
| 21826f44bf | |||
| c906533650 | |||
| 6cbbcd8ad6 | |||
| 4e2d3d40dc | |||
| 8fe25c64f1 | |||
| ce5752cd1f | |||
| 3fc6042992 | |||
| 6f88359df6 | |||
| bf00f6d7ec | |||
| b336d1ab83 | |||
| 119e1ffc5e | |||
| 2c794b15a0 | |||
| 0708054570 | |||
| 038ebf6875 | |||
| 3580843595 | |||
| a920b209ff |
+5
-6
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -1 +1 @@
|
||||
1dc7993bb6957587a6c63142e97b8e4137c3d81bbfd724f86048e0894bcb429b
|
||||
d805fc0cf1c4ef07a7bc947f75828931e3788d0e64730caab3b42ae58009a194
|
||||
+8
-25
@@ -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 );
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
@@ -4980,7 +4980,7 @@ SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
|
||||
** <td>→ <td>True if the column is unchanged in an UPDATE
|
||||
** against a virtual table.
|
||||
** <tr><td><b>sqlite3_value_frombind </b>
|
||||
** <td>→ <td>True if value originated a bound parameter
|
||||
** <td>→ <td>True if value originated from a [bound parameter]
|
||||
** </table></blockquote>
|
||||
**
|
||||
** <b>Details:</b>
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 );
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -202,4 +202,5 @@ do_eqp_test skipscan2-3.3eqp {
|
||||
} {SEARCH TABLE t3 USING PRIMARY KEY (ANY(a) AND b=?)}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {} {
|
||||
|
||||
@@ -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
@@ -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 {& & < < > > \" " \\ \} $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
|
||||
Executable
+673
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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]=='-' ){
|
||||
|
||||
@@ -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
@@ -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 \
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user