aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/fts5/fts5_storage.c6
-rw-r--r--ext/fts5/test/fts5rank.test35
-rw-r--r--ext/misc/carray.c2
-rw-r--r--ext/misc/csv.c20
-rw-r--r--ext/rbu/rbudiff.test60
-rw-r--r--manifest56
-rw-r--r--manifest.uuid2
-rw-r--r--src/main.c32
-rw-r--r--src/sqlite.h.in128
-rw-r--r--src/sqlite3ext.h6
-rw-r--r--src/sqliteInt.h12
-rw-r--r--src/tclsqlite.c338
-rw-r--r--src/test1.c34
-rw-r--r--src/vacuum.c8
-rw-r--r--src/vdbe.c18
-rw-r--r--src/vdbeapi.c47
-rw-r--r--src/vdbeaux.c8
-rw-r--r--src/vdbetrace.c12
-rw-r--r--test/csv01.test2
-rw-r--r--test/dbstatus.test1
-rw-r--r--test/tclsqlite.test2
-rw-r--r--test/trace3.test233
-rw-r--r--test/vacuummem.test59
-rw-r--r--tool/sqldiff.c2
24 files changed, 959 insertions, 164 deletions
diff --git a/ext/fts5/fts5_storage.c b/ext/fts5/fts5_storage.c
index 90df3396c..a69588745 100644
--- a/ext/fts5/fts5_storage.c
+++ b/ext/fts5/fts5_storage.c
@@ -247,7 +247,11 @@ int sqlite3Fts5CreateTable(
char *zErr = 0;
rc = fts5ExecPrintf(pConfig->db, &zErr, "CREATE TABLE %Q.'%q_%q'(%s)%s",
- pConfig->zDb, pConfig->zName, zPost, zDefn, bWithout?" WITHOUT ROWID":""
+ pConfig->zDb, pConfig->zName, zPost, zDefn,
+#ifndef SQLITE_FTS5_NO_WITHOUT_ROWID
+ bWithout?" WITHOUT ROWID":
+#endif
+ ""
);
if( zErr ){
*pzErr = sqlite3_mprintf(
diff --git a/ext/fts5/test/fts5rank.test b/ext/fts5/test/fts5rank.test
index e958aea15..a70c5d68e 100644
--- a/ext/fts5/test/fts5rank.test
+++ b/ext/fts5/test/fts5rank.test
@@ -100,30 +100,55 @@ do_test 2.7 {
# following tests verify that that problem has been addressed.
#
foreach_detail_mode $::testprefix {
- do_execsql_test 3.0 {
+ do_execsql_test 3.1.0 {
CREATE VIRTUAL TABLE y1 USING fts5(z, detail=%DETAIL%);
INSERT INTO y1 VALUES('test xyz');
INSERT INTO y1 VALUES('test test xyz test');
INSERT INTO y1 VALUES('test test xyz');
}
- do_execsql_test 3.1 {
+ do_execsql_test 3.1.1 {
SELECT rowid FROM y1('test OR tset');
} {1 2 3}
- do_execsql_test 3.2 {
+ do_execsql_test 3.1.2 {
SELECT rowid FROM y1('test OR tset') ORDER BY bm25(y1)
} {2 3 1}
- do_execsql_test 3.3 {
+ do_execsql_test 3.1.3 {
SELECT rowid FROM y1('test OR tset') ORDER BY +rank
} {2 3 1}
- do_execsql_test 3.4 {
+ do_execsql_test 3.1.4 {
SELECT rowid FROM y1('test OR tset') ORDER BY rank
} {2 3 1}
+
+ do_execsql_test 3.1.5 {
+ SELECT rowid FROM y1('test OR xyz') ORDER BY rank
+ } {3 2 1}
+
+
+ do_execsql_test 3.2.1 {
+ CREATE VIRTUAL TABLE z1 USING fts5(a, detail=%DETAIL%);
+ INSERT INTO z1 VALUES('wrinkle in time');
+ SELECT * FROM z1 WHERE z1 MATCH 'wrinkle in time OR a wrinkle in time';
+ } {{wrinkle in time}}
}
+do_execsql_test 4.1 {
+ DROP TABLE IF EXISTS VTest;
+ CREATE virtual TABLE VTest USING FTS5(
+ Title, AUthor, tokenize ='porter unicode61 remove_diacritics 1',
+ columnsize='1', detail=full
+ );
+ INSERT INTO VTest (Title, Author) VALUES ('wrinkle in time', 'Bill Smith');
+
+ SELECT * FROM VTest WHERE
+ VTest MATCH 'wrinkle in time OR a wrinkle in time' ORDER BY rank;
+} {{wrinkle in time} {Bill Smith}}
+
+
+
finish_test
diff --git a/ext/misc/carray.c b/ext/misc/carray.c
index 6fdbecf57..025eb5db2 100644
--- a/ext/misc/carray.c
+++ b/ext/misc/carray.c
@@ -237,7 +237,7 @@ static int carrayFilter(
if( idxNum<3 ){
pCur->eType = CARRAY_INT32;
}else{
- int i;
+ unsigned char i;
const char *zType = (const char*)sqlite3_value_text(argv[2]);
for(i=0; i<sizeof(azType)/sizeof(azType[0]); i++){
if( sqlite3_stricmp(zType, azType[i])==0 ) break;
diff --git a/ext/misc/csv.c b/ext/misc/csv.c
index 3a7e32d31..2a9463bd6 100644
--- a/ext/misc/csv.c
+++ b/ext/misc/csv.c
@@ -48,6 +48,8 @@ SQLITE_EXTENSION_INIT1
#include <ctype.h>
#include <stdio.h>
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
/*
** A macro to hint to the compiler that a function should not be
** inlined.
@@ -230,7 +232,7 @@ static char *csv_read_one_field(CsvReader *p){
|| (c==EOF && pc=='"')
){
do{ p->n--; }while( p->z[p->n]!='"' );
- p->cTerm = c;
+ p->cTerm = (char)c;
break;
}
if( pc=='"' && c!='\r' ){
@@ -240,7 +242,7 @@ static char *csv_read_one_field(CsvReader *p){
if( c==EOF ){
csv_errmsg(p, "line %d: unterminated %c-quoted field\n",
startLine, '"');
- p->cTerm = c;
+ p->cTerm = (char)c;
break;
}
}
@@ -257,7 +259,7 @@ static char *csv_read_one_field(CsvReader *p){
p->nLine++;
if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--;
}
- p->cTerm = c;
+ p->cTerm = (char)c;
}
if( p->z ) p->z[p->n] = 0;
return p->z;
@@ -336,9 +338,9 @@ static void csv_trim_whitespace(char *z){
/* Dequote the string */
static void csv_dequote(char *z){
- int i, j;
+ int j;
char cQuote = z[0];
- size_t n;
+ size_t i, n;
if( cQuote!='\'' && cQuote!='"' ) return;
n = strlen(z);
@@ -723,7 +725,8 @@ static int csvtabFilter(
pCur->iRowid = 0;
if( pCur->rdr.in==0 ){
assert( pCur->rdr.zIn==pTab->zData );
- assert( pTab->iStart<=pCur->rdr.nIn );
+ assert( pTab->iStart>=0 );
+ assert( (size_t)pTab->iStart<=pCur->rdr.nIn );
pCur->rdr.iIn = pTab->iStart;
}else{
fseek(pCur->rdr.in, pTab->iStart, SEEK_SET);
@@ -834,6 +837,7 @@ static sqlite3_module CsvModuleFauxWrite = {
};
#endif /* SQLITE_TEST */
+#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */
#ifdef _WIN32
@@ -849,6 +853,7 @@ int sqlite3_csv_init(
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
+#ifndef SQLITE_OMIT_VIRTUALTABLE
int rc;
SQLITE_EXTENSION_INIT2(pApi);
rc = sqlite3_create_module(db, "csv", &CsvModule, 0);
@@ -858,4 +863,7 @@ int sqlite3_csv_init(
}
#endif
return rc;
+#else
+ return SQLITE_OK;
+#endif
}
diff --git a/ext/rbu/rbudiff.test b/ext/rbu/rbudiff.test
index fa8de319d..041a24242 100644
--- a/ext/rbu/rbudiff.test
+++ b/ext/rbu/rbudiff.test
@@ -203,7 +203,6 @@ foreach {tn init mod} {
DELETE FROM 'x''y' WHERE rowid = 1;
INSERT INTO 'x''y' VALUES('one two three');
}
-
} {
forcedelete test.db test.db2
@@ -222,5 +221,64 @@ foreach {tn init mod} {
}
+ifcapable fts5 {
+ foreach {tn init mod} {
+ 1 {
+ CREATE VIRTUAL TABLE t1 USING fts5(c);
+ INSERT INTO t1 VALUES('a b c');
+ INSERT INTO t1 VALUES('a b c');
+ } {
+ DELETE FROM t1 WHERE rowid = 1;
+ INSERT INTO t1 VALUES('a b c');
+ }
+
+ 2 {
+ CREATE VIRTUAL TABLE t1 USING FTs5(c);
+ INSERT INTO t1 VALUES('a b c');
+ INSERT INTO t1 VALUES('a b c');
+ } {
+ DELETE FROM t1 WHERE rowid = 1;
+ INSERT INTO t1 VALUES('a b c');
+ }
+
+ 3 {
+ creAte virTUal
+tablE t1 USING FTs5(c);
+ INSERT INTO t1 VALUES('a b c');
+ INSERT INTO t1 VALUES('a b c');
+ } {
+ DELETE FROM t1 WHERE rowid = 1;
+ INSERT INTO t1 VALUES('a b c');
+ }
+
+ } {
+ forcedelete test.db test.db2
+ sqlite3 db test.db
+ db eval "$init"
+ sqlite3 db test.db2
+ db eval "$init ; $mod"
+ db eval { INSERT INTO t1(t1) VALUES('optimize') }
+ db close
+
+ do_test 3.$tn.1 {
+ set sql [get_vtab_rbudiff_sql test.db test.db2]
+ apply_rbudiff $sql test.db
+ } {SQLITE_DONE}
+
+ sqlite3 db test.db
+ sqlite3 db2 test.db2
+ do_test 3.$tn.2 {
+ db2 eval { SELECT * FROM t1 ORDER BY rowid }
+ } [db eval { SELECT * FROM t1 ORDER BY rowid }]
+
+ do_test 3.$tn.3 {
+ db2 eval { INSERT INTO t1(t1) VALUES('integrity-check') }
+ } {}
+
+ db close
+ db2 close
+ }
+}
+
finish_test
diff --git a/manifest b/manifest
index 47fc104dd..9c7215a36 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Minor\stweak\sthe\sthe\sb-tree\sbalancer.
-D 2016-07-14T19:48:08.366
+C Small\stweak\sto\sthe\sbtree\sbalancer\sfor\simproved\stree\sbalance.
+D 2016-07-23T19:18:55.177
F Makefile.in 6c20d44f72d4564f11652b26291a214c8367e5db
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc d66d0395c38571aab3804f8db0fa20707ae4609a
@@ -106,7 +106,7 @@ F ext/fts5/fts5_expr.c bcb238ee4ac1164302ab528487520488516bd030
F ext/fts5/fts5_hash.c 880998e596b60f078348d48732ca4ad9a90caad2
F ext/fts5/fts5_index.c b429e23fabb57506f71e406997cc46b89190dc97
F ext/fts5/fts5_main.c f85281445dcf8be32d18841c93a6f90fe27dbfe2
-F ext/fts5/fts5_storage.c 3309c6a8e34b974513016fd1ef47c83f5898f94c
+F ext/fts5/fts5_storage.c de0ed8a06738bde433afe11e92295ceaffbc4e58
F ext/fts5/fts5_tcl.c f8731e0508299bd43f1a2eff7dbeaac870768966
F ext/fts5/fts5_test_mi.c 783b86697ebf773c18fc109992426c0173a055bc
F ext/fts5/fts5_test_tok.c db08af63673c3a7d39f053b36fd6e065017706be
@@ -176,7 +176,7 @@ F ext/fts5/test/fts5porter.test 7cdc07bef301d70eebbfa75dcaf45c3680e1d0e1
F ext/fts5/test/fts5porter2.test 2e65633d58a1c525d5af0f6c01e5a59155bb3487
F ext/fts5/test/fts5prefix.test efd42e00bb8e8a36383f25c838185508681c093f
F ext/fts5/test/fts5query.test f5ec25f5f2fbb70033424113cdffc101b1985a40
-F ext/fts5/test/fts5rank.test 3e55e7eeb4c98728e4a3171c9e994e1a2f24eb99
+F ext/fts5/test/fts5rank.test 2bdc0c5f22ccc1f9dbe9f4d0b82a491dce6f8a32
F ext/fts5/test/fts5rebuild.test 03935f617ace91ed23a6099c7c74d905227ff29b
F ext/fts5/test/fts5restart.test c17728fdea26e7d0f617d22ad5b4b2862b994c17
F ext/fts5/test/fts5rowid.test 16908a99d6efc9ba21081b4f2b86b3fc699839a6
@@ -204,10 +204,10 @@ F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
F ext/icu/icu.c 43df9d8ef2fae7a325100ebd713ab089dc829dd7
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
F ext/misc/amatch.c 211108e201105e4bb0c076527b8cfd34330fc234
-F ext/misc/carray.c 214c9e9d909ceaae3b2f5f917cc2204deca85cc6
+F ext/misc/carray.c 40c27641010a4dc67e3690bdb7c9d36ca58b3c2d
F ext/misc/closure.c 0d2a038df8fbae7f19de42e7c7d71f2e4dc88704
F ext/misc/compress.c 122faa92d25033d6c3f07c39231de074ab3d2e83
-F ext/misc/csv.c b92692b057707f5b7bb91feaedde790b2e38304e
+F ext/misc/csv.c 816a3715356e4210dae2d242057745e937050896
F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2
F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f
F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25
@@ -244,7 +244,7 @@ F ext/rbu/rbuB.test c25bc325b8072a766e56bb76c001866b405925c2
F ext/rbu/rbuC.test efe47db508a0269b683cb2a1913a425ffd39a831
F ext/rbu/rbu_common.tcl a38e8e2d4a50fd6aaf151633714c1b1d2fae3ead
F ext/rbu/rbucrash.test 8d2ed5d4b05fef6c00c2a6b5f7ead71fa172a695
-F ext/rbu/rbudiff.test 4c9f8df6f723f553781d3d117501b7e9d170a145
+F ext/rbu/rbudiff.test b3c7675810b81de98a930a87fcd40d9ae545619d
F ext/rbu/rbufault.test cc0be8d5d392d98b0c2d6a51be377ea989250a89
F ext/rbu/rbufault2.test 9a7f19edd6ea35c4c9f807d8a3db0a03a5670c06
F ext/rbu/rbufault3.test 54a399888ac4af44c68f9f58afbed23149428bca
@@ -348,7 +348,7 @@ F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
F src/insert.c 8f4e9fcbd8e95e85f15647ba8b413b18d556ec2b
F src/legacy.c 75d3023be8f0d2b99d60f905090341a03358c58e
F src/loadext.c 4237fd37ca589f1d90b3ea925dd9df20da8e0c84
-F src/main.c 405d13e3a4f7c5add9fb27702ae70ed0a6e32cca
+F src/main.c 2d3e62a971e7f169a74448e81af9ebde95b07381
F src/malloc.c 1443d1ad95d67c21d77af7ae3f44678252f0efec
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 6919bcf12f221868ea066eec27e579fed95ce98b
@@ -385,15 +385,15 @@ F src/resolve.c cca3aa77b95706df5d635a2141a4d1de60ae6598
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c f3c6e9065fb34f6a23af27ec7f1f717ffbfc2ee4
F src/shell.c a8a9e392a6a2777fabf5feb536931cb190f235e5
-F src/sqlite.h.in b9ba728c1083b7a8ab5f6a628b25cd2a00325fbf
+F src/sqlite.h.in 3dc7317ded4bf66facd845705f45f21d03517940
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
-F src/sqlite3ext.h 2a170163d121095c6ab1ef05ed0413722f391d01
-F src/sqliteInt.h dcf43b8abc5605b70f54ba80f42b6ad054b8ba95
+F src/sqlite3ext.h 46f300b6e300e0fa916d7d58c44b53415b8471a9
+F src/sqliteInt.h 48cd97eb134665348393dfe277b4c14d1085bfc7
F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247
F src/status.c 5b18f9526900f61189ab0b83f1ef41d9f871a2ab
F src/table.c 5226df15ab9179b9ed558d89575ea0ce37b03fc9
-F src/tclsqlite.c 25fbbbb97f76dbfd113153fb63f52d7ecfac5dd0
-F src/test1.c 640f862c490c8eee09a9d02d0d128c6a8a75336d
+F src/tclsqlite.c 573e63c959b314d77486f3565fa79c60cda3df7e
+F src/test1.c 186e3b53c402b7a73bcb4ade2b77709675c39fe3
F src/test2.c 5586f43fcd9a1be0830793cf9d354082c261b25b
F src/test3.c c75c8af0eadb335236c9e61b51044c58a8f7dd59
F src/test4.c d168f83cc78d02e8d35567bb5630e40dcd85ac1e
@@ -448,16 +448,16 @@ F src/trigger.c e14840ee0c3e549e758ec9bf3e4146e166002280
F src/update.c 4f05ea8cddfa367d045e03589756c02199e8f9bd
F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c
F src/util.c 810ec3f22e2d1b62e66c30fe3621ebdedd23584d
-F src/vacuum.c feb1eabb20987983d9350cad98299b21fa811f52
-F src/vdbe.c 22b46c3b725e950e9f2760e2d76953d592600ad4
+F src/vacuum.c 544ec90a66a4b0460b7c1baeadbc21b45e6ca0b6
+F src/vdbe.c 7b5570f77e32766949fd8f9478e4a9bb06e6ab24
F src/vdbe.h 67bc551f7faf04c33493892e4b378aada823ed10
F src/vdbeInt.h c59381049af5c7751a83456c39b80d1a6fde1f9d
-F src/vdbeapi.c 02bcbc2ca5d2004b029088b05b468b394881e103
-F src/vdbeaux.c c90275b0e55a2b32c03dc09314194fe46f2429d8
+F src/vdbeapi.c c3f6715a99995c11748ecad91d25e93fd9fc390b
+F src/vdbeaux.c a32d79aeaa88dc2b97c261172d952d395254a055
F src/vdbeblob.c 83d2d266383157b02e2b809350bb197e89d7895b
F src/vdbemem.c 1ecaa5ee0caff07255f25d04e8dc88befb6f88d1
F src/vdbesort.c 91fda3909326860382b0ca8aa251e609c6a9d62c
-F src/vdbetrace.c f75c5455d8cf389ef86a8bfdfd3177e0e3692484
+F src/vdbetrace.c 41963d5376f0349842b5fc4aaaaacd7d9cdc0834
F src/vtab.c 948d2d4984219eee37a7bf427d6667e21e6eb92e
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 02eeecc265f6ffd0597378f5d8ae9070b62a406a
@@ -616,12 +616,12 @@ F test/crashM.test d95f59046fa749b0d0822edf18a717788c8f318d
F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
F test/createtab.test b5de160630b209c4b8925bdcbbaf48cc90b67fe8
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
-F test/csv01.test 0929a9ce47021519512be92861f29e32d2538e5f
+F test/csv01.test e0ba3caaa57e4c667a0b45977689fb8082f14348
F test/ctime.test 0b995accd44a52914bd4744d5c1b6e1a56c7897c
F test/cursorhint.test 7bc346788390475e77a345da2b92270d04d35856
F test/cursorhint2.test 2b45341d32d1aae9991a00ef31ebca339b274255
F test/date.test 984ac1e3e5e031386866f034006148d3972b4a65
-F test/dbstatus.test 85833ba5bc95262749d080dcd40af87072ea8d5b
+F test/dbstatus.test 2bb4d576f11c0f57f5633dad373ad1a57c2a7195
F test/dbstatus2.test e93ab03bfae6d62d4d935f20de928c19ca0ed0ab
F test/default.test 0cb49b1c315a0d81c81d775e407f66906a2a604d
F test/delete.test e1bcdf8926234e27aac24b346ad83d3329ec8b6f
@@ -1120,7 +1120,7 @@ F test/tabfunc01.test 50a9fb379f9747fd0d40ea6d8fa3a101361bb537
F test/table.test b708f3e5fa2542fa51dfab21fc07b36ea445cb2f
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
-F test/tclsqlite.test cf0d0a3fd03d64892cec2d48aae9fb2f148680a5
+F test/tclsqlite.test 1d73b9203b1ca8798d7d7310742b8d3febc0d56e
F test/tempdb.test bd92eba8f20e16a9136e434e20b280794de3cdb6
F test/tempdb2.test 4fc92055f2a3f7626c0f2eabbb637dc021b311d5
F test/tempfault.test 0c0d349c9a99bf5f374655742577f8712c647900
@@ -1285,6 +1285,7 @@ F test/tokenize.test ce430a7aed48fc98301611429595883fdfcab5d7
F test/tpch01.test 04adbf8d8300fa60a222f28d901abd76e7be6dd4
F test/trace.test 6f676313e3ebd2a50585036d2f212a3319dd5836
F test/trace2.test f5cb67ad3bc09e0c58e8cca78dfd0b5639259983
+F test/trace3.test 01e4111d582c7b20ab1c63156169157d256bc3d5
F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6
F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76
F test/trans3.test 91a100e5412b488e22a655fe423a14c26403ab94
@@ -1323,6 +1324,7 @@ F test/vacuum.test ce91c39f7f91a4273bf620efad21086b5aa6ef1d
F test/vacuum2.test aa048abee196c16c9ba308465494009057b79f9b
F test/vacuum3.test 77ecdd54592b45a0bcb133339f99f1ae0ae94d0d
F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9
+F test/vacuummem.test ae20cc80a4960d3507d27cf0f2f4555988ceb6df
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
F test/view.test 765802c7a66d37fabd5ac8e2f2dbe572b43eb9ab
@@ -1472,7 +1474,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 7ce07da76b5e745783e703a834417d725b7d45fd
F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
-F tool/sqldiff.c af5d80cdc88a91a0f3cccfaa316b5a27b213568a
+F tool/sqldiff.c 4478f0d30230de6adde90bdb0bfe60f68c5ab782
F tool/srcck1.c 4c39bdfa9a92edd20233ee720df84dbeb2417602
F tool/stack_usage.tcl f8e71b92cdb099a147dad572375595eae55eca43
F tool/symbols-mingw.sh 4dbcea7e74768305384c9fd2ed2b41bbf9f0414d
@@ -1505,10 +1507,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P a7db6e45ad45be9b3003f61d4163f543498a7c9d
-R cf8c76c330a7fe6ea73db33dfc44a97f
-T *branch * btree-tuning
-T *sym-btree-tuning *
-T -sym-trunk *
+P d0bcaf0cd92ae5bbea7ad68537ba89437d5c39e8 d2a0af7a37e390439c3001fedb5834f47fb24a1f
+R e49116b4c5057a2c64e23fc9fb71ef64
+T +closed d2a0af7a37e390439c3001fedb5834f47fb24a1f
U drh
-Z 48948e5bf85e9b289f89aa7970884ba4
+Z 96bd00cbee88b7adc25980f9570baf91
diff --git a/manifest.uuid b/manifest.uuid
index 467d7f99b..e3e685726 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-d2a0af7a37e390439c3001fedb5834f47fb24a1f \ No newline at end of file
+8817dedb75430e6c78ff527f7ded4abb35776cef \ No newline at end of file
diff --git a/src/main.c b/src/main.c
index 30370f8ca..5cd1ea718 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1033,6 +1033,9 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
return SQLITE_MISUSE_BKPT;
}
sqlite3_mutex_enter(db->mutex);
+ if( db->mTrace & SQLITE_TRACE_CLOSE ){
+ db->xTrace(SQLITE_TRACE_CLOSE, db->pTraceArg, db, 0);
+ }
/* Force xDisconnect calls on all virtual tables */
disconnectAllVtab(db);
@@ -1801,7 +1804,8 @@ int sqlite3_overload_function(
** trace is a pointer to a function that is invoked at the start of each
** SQL statement.
*/
-void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
+#ifndef SQLITE_OMIT_DEPRECATED
+void *sqlite3_trace(sqlite3 *db, void(*xTrace)(void*,const char*), void *pArg){
void *pOld;
#ifdef SQLITE_ENABLE_API_ARMOR
@@ -1812,11 +1816,35 @@ void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
#endif
sqlite3_mutex_enter(db->mutex);
pOld = db->pTraceArg;
- db->xTrace = xTrace;
+ db->mTrace = xTrace ? SQLITE_TRACE_LEGACY : 0;
+ db->xTrace = (int(*)(u32,void*,void*,void*))xTrace;
db->pTraceArg = pArg;
sqlite3_mutex_leave(db->mutex);
return pOld;
}
+#endif /* SQLITE_OMIT_DEPRECATED */
+
+/* Register a trace callback using the version-2 interface.
+*/
+int sqlite3_trace_v2(
+ sqlite3 *db, /* Trace this connection */
+ unsigned mTrace, /* Mask of events to be traced */
+ int(*xTrace)(unsigned,void*,void*,void*), /* Callback to invoke */
+ void *pArg /* Context */
+){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+ sqlite3_mutex_enter(db->mutex);
+ db->mTrace = mTrace;
+ db->xTrace = xTrace;
+ db->pTraceArg = pArg;
+ sqlite3_mutex_leave(db->mutex);
+ return SQLITE_OK;
+}
+
/*
** Register a profile function. The pArg from the previously registered
** profile function is returned.
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 12a07a9b4..ed68cf0a1 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -2755,6 +2755,9 @@ int sqlite3_set_authorizer(
** CAPI3REF: Tracing And Profiling Functions
** METHOD: sqlite3
**
+** These routines are deprecated. Use the [sqlite3_trace_v2()] interface
+** instead of the routines described here.
+**
** These routines register callback functions that can be used for
** tracing and profiling the execution of SQL statements.
**
@@ -2780,11 +2783,102 @@ int sqlite3_set_authorizer(
** sqlite3_profile() function is considered experimental and is
** subject to change in future versions of SQLite.
*/
-void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
-SQLITE_EXPERIMENTAL void *sqlite3_profile(sqlite3*,
+SQLITE_DEPRECATED void *sqlite3_trace(sqlite3*,
+ void(*xTrace)(void*,const char*), void*);
+SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
/*
+** CAPI3REF: SQL Trace Event Codes
+** KEYWORDS: SQLITE_TRACE
+**
+** These constants identify classes of events that can be monitored
+** using the [sqlite3_trace_v2()] tracing logic. The third argument
+** to [sqlite3_trace_v2()] is an OR-ed combination of one or more of
+** the following constants. ^The first argument to the trace callback
+** is one of the following constants.
+**
+** New tracing constants may be added in future releases.
+**
+** ^A trace callback has four arguments: xCallback(T,C,P,X).
+** ^The T argument is one of the integer type codes above.
+** ^The C argument is a copy of the context pointer passed in as the
+** fourth argument to [sqlite3_trace_v2()].
+** The P and X arguments are pointers whose meanings depend on T.
+**
+** <dl>
+** [[SQLITE_TRACE_STMT]] <dt>SQLITE_TRACE_STMT</dt>
+** <dd>^An SQLITE_TRACE_STMT callback is invoked when a prepared statement
+** first begins running and possibly at other times during the
+** execution of the prepared statement, such as at the start of each
+** trigger subprogram. ^The P argument is a pointer to the
+** [prepared statement]. ^The X argument is a pointer to a string which
+** is the expanded SQL text of the prepared statement or a comment that
+** indicates the invocation of a trigger.
+**
+** [[SQLITE_TRACE_PROFILE]] <dt>SQLITE_TRACE_PROFILE</dt>
+** <dd>^An SQLITE_TRACE_PROFILE callback provides approximately the same
+** information as is provided by the [sqlite3_profile()] callback.
+** ^The P argument is a pointer to the [prepared statement] and the
+** X argument points to a 64-bit integer which is the estimated of
+** the number of nanosecond that the prepared statement took to run.
+** ^The SQLITE_TRACE_PROFILE callback is invoked when the statement finishes.
+**
+** [[SQLITE_TRACE_ROW]] <dt>SQLITE_TRACE_ROW</dt>
+** <dd>^An SQLITE_TRACE_ROW callback is invoked whenever a prepared
+** statement generates a single row of result.
+** ^The P argument is a pointer to the [prepared statement] and the
+** X argument is unused.
+**
+** [[SQLITE_TRACE_CLOSE]] <dt>SQLITE_TRACE_CLOSE</dt>
+** <dd>^An SQLITE_TRACE_CLOSE callback is invoked when a database
+** connection closes.
+** ^The P argument is a pointer to the [database connection] object
+** and the X argument is unused.
+** </dl>
+*/
+#define SQLITE_TRACE_STMT 0x01
+#define SQLITE_TRACE_PROFILE 0x02
+#define SQLITE_TRACE_ROW 0x04
+#define SQLITE_TRACE_CLOSE 0x08
+
+/*
+** CAPI3REF: SQL Trace Hook
+** METHOD: sqlite3
+**
+** ^The sqlite3_trace_v2(D,M,X,P) interface registers a trace callback
+** function X against [database connection] D, using property mask M
+** and context pointer P. ^If the X callback is
+** NULL or if the M mask is zero, then tracing is disabled. The
+** M argument should be the bitwise OR-ed combination of
+** zero or more [SQLITE_TRACE] constants.
+**
+** ^Each call to either sqlite3_trace() or sqlite3_trace_v2() overrides
+** (cancels) any prior calls to sqlite3_trace() or sqlite3_trace_v2().
+**
+** ^The X callback is invoked whenever any of the events identified by
+** mask M occur. ^The integer return value from the callback is currently
+** ignored, though this may change in future releases. Callback
+** implementations should return zero to ensure future compatibility.
+**
+** ^A trace callback is invoked with four arguments: callback(T,C,P,X).
+** ^The T argument is one of the [SQLITE_TRACE]
+** constants to indicate why the callback was invoked.
+** ^The C argument is a copy of the context pointer.
+** The P and X arguments are pointers whose meanings depend on T.
+**
+** The sqlite3_trace_v2() interface is intended to replace the legacy
+** interfaces [sqlite3_trace()] and [sqlite3_profile()], both of which
+** are deprecated.
+*/
+int sqlite3_trace_v2(
+ sqlite3*,
+ unsigned uMask,
+ int(*xCallback)(unsigned,void*,void*,void*),
+ void *pCtx
+);
+
+/*
** CAPI3REF: Query Progress Callbacks
** METHOD: sqlite3
**
@@ -3402,11 +3496,35 @@ int sqlite3_prepare16_v2(
** CAPI3REF: Retrieving Statement SQL
** METHOD: sqlite3_stmt
**
-** ^This interface can be used to retrieve a saved copy of the original
-** SQL text used to create a [prepared statement] if that statement was
-** compiled using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
+** ^The sqlite3_sql(P) interface returns a pointer to a copy of the UTF-8
+** SQL text used to create [prepared statement] P if P was
+** created by either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()].
+** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8
+** string containing the SQL text of prepared statement P with
+** [bound parameters] expanded.
+**
+** ^(For example, if a prepared statement is created using the SQL
+** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345
+** and parameter :xyz is unbound, then sqlite3_sql() will return
+** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql()
+** will return "SELECT 2345,NULL".)^
+**
+** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory
+** is available to hold the result, or if the result would exceed the
+** the maximum string length determined by the [SQLITE_LIMIT_LENGTH].
+**
+** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of
+** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time
+** option causes sqlite3_expanded_sql() to always return NULL.
+**
+** ^The string returned by sqlite3_sql(P) is managed by SQLite and is
+** automatically freed when the prepared statement is finalized.
+** ^The string returned by sqlite3_expanded_sql(P), on the other hand,
+** is obtained from [sqlite3_malloc()] and must be free by the application
+** by passing it to [sqlite3_free()].
*/
const char *sqlite3_sql(sqlite3_stmt *pStmt);
+char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
/*
** CAPI3REF: Determine If An SQL Statement Writes The Database
diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h
index 2d38e87ae..338e1becd 100644
--- a/src/sqlite3ext.h
+++ b/src/sqlite3ext.h
@@ -281,6 +281,9 @@ struct sqlite3_api_routines {
int (*db_cacheflush)(sqlite3*);
/* Version 3.12.0 and later */
int (*system_errno)(sqlite3*);
+ /* Version 3.14.0 and later */
+ int (*trace_v2)(sqlite3*,unsigned,int(*)(unsigned,void*,void*,void*),void*);
+ char *(*expanded_sql)(sqlite3_stmt*);
};
/*
@@ -526,6 +529,9 @@ struct sqlite3_api_routines {
#define sqlite3_db_cacheflush sqlite3_api->db_cacheflush
/* Version 3.12.0 and later */
#define sqlite3_system_errno sqlite3_api->system_errno
+/* Version 3.14.0 and later */
+#define sqlite3_trace_v2 sqlite3_api->trace_v2
+#define sqlite3_expanded_sql sqlite3_api->expanded_sql
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 998a17dac..0be494751 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1241,6 +1241,15 @@ void sqlite3CryptFunc(sqlite3_context*,int,sqlite3_value**);
const char*);
#endif
+#ifndef SQLITE_OMIT_DEPRECATED
+/* This is an extra SQLITE_TRACE macro that indicates "legacy" tracing
+** in the style of sqlite3_trace()
+*/
+#define SQLITE_TRACE_LEGACY 0x80
+#else
+#define SQLITE_TRACE_LEGACY 0
+#endif /* SQLITE_OMIT_DEPRECATED */
+
/*
** Each database connection is an instance of the following structure.
@@ -1270,6 +1279,7 @@ struct sqlite3 {
u8 suppressErr; /* Do not issue error messages if true */
u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */
u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */
+ u8 mTrace; /* zero or more SQLITE_TRACE flags */
int nextPagesize; /* Pagesize after VACUUM if >0 */
u32 magic; /* Magic number for detect library misuse */
int nChange; /* Value returned by sqlite3_changes() */
@@ -1290,7 +1300,7 @@ struct sqlite3 {
int nVDestroy; /* Number of active OP_VDestroy operations */
int nExtension; /* Number of loaded extensions */
void **aExtension; /* Array of shared library handles */
- void (*xTrace)(void*,const char*); /* Trace function */
+ int (*xTrace)(u32,void*,void*,void*); /* Trace function */
void *pTraceArg; /* Argument to the trace function */
void (*xProfile)(void*,const char*,u64); /* Profiling function */
void *pProfileArg; /* Argument to profile function */
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index 476bdf235..43dfedb72 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -133,6 +133,7 @@ struct SqliteDb {
char *zBusy; /* The busy callback routine */
char *zCommit; /* The commit hook callback routine */
char *zTrace; /* The trace callback routine */
+ char *zTraceV2; /* The trace_v2 callback routine */
char *zProfile; /* The profile callback routine */
char *zProgress; /* The progress callback routine */
char *zAuth; /* The authorization callback routine */
@@ -192,7 +193,7 @@ static void closeIncrblobChannels(SqliteDb *pDb){
for(p=pDb->pIncrblob; p; p=pNext){
pNext = p->pNext;
- /* Note: Calling unregister here call Tcl_Close on the incrblob channel,
+ /* Note: Calling unregister here call Tcl_Close on the incrblob channel,
** which deletes the IncrblobChannel structure at *p. So do not
** call Tcl_Free() here.
*/
@@ -233,8 +234,8 @@ static int incrblobClose(ClientData instanceData, Tcl_Interp *interp){
** Read data from an incremental blob channel.
*/
static int incrblobInput(
- ClientData instanceData,
- char *buf,
+ ClientData instanceData,
+ char *buf,
int bufSize,
int *errorCodePtr
){
@@ -265,8 +266,8 @@ static int incrblobInput(
** Write data to an incremental blob channel.
*/
static int incrblobOutput(
- ClientData instanceData,
- CONST char *buf,
+ ClientData instanceData,
+ CONST char *buf,
int toWrite,
int *errorCodePtr
){
@@ -298,7 +299,7 @@ static int incrblobOutput(
** Seek an incremental blob channel.
*/
static int incrblobSeek(
- ClientData instanceData,
+ ClientData instanceData,
long offset,
int seekMode,
int *errorCodePtr
@@ -323,8 +324,8 @@ static int incrblobSeek(
}
-static void incrblobWatch(ClientData instanceData, int mode){
- /* NO-OP */
+static void incrblobWatch(ClientData instanceData, int mode){
+ /* NO-OP */
}
static int incrblobHandle(ClientData instanceData, int dir, ClientData *hPtr){
return TCL_ERROR;
@@ -352,11 +353,11 @@ static Tcl_ChannelType IncrblobChannelType = {
** Create a new incrblob channel.
*/
static int createIncrblobChannel(
- Tcl_Interp *interp,
- SqliteDb *pDb,
+ Tcl_Interp *interp,
+ SqliteDb *pDb,
const char *zDb,
- const char *zTable,
- const char *zColumn,
+ const char *zTable,
+ const char *zColumn,
sqlite_int64 iRow,
int isReadonly
){
@@ -438,7 +439,7 @@ static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){
pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + nName + 1 );
pNew->zName = (char*)&pNew[1];
memcpy(pNew->zName, zName, nName+1);
- for(p=pDb->pFunc; p; p=p->pNext){
+ for(p=pDb->pFunc; p; p=p->pNext){
if( sqlite3_stricmp(p->zName, pNew->zName)==0 ){
Tcl_Free((char*)pNew);
return p;
@@ -508,6 +509,9 @@ static void DbDeleteCmd(void *db){
if( pDb->zTrace ){
Tcl_Free(pDb->zTrace);
}
+ if( pDb->zTraceV2 ){
+ Tcl_Free(pDb->zTraceV2);
+ }
if( pDb->zProfile ){
Tcl_Free(pDb->zProfile);
}
@@ -589,6 +593,82 @@ static void DbTraceHandler(void *cd, const char *zSql){
#ifndef SQLITE_OMIT_TRACE
/*
+** This routine is called by the SQLite trace_v2 handler whenever a new
+** supported event is generated. Unsupported event types are ignored.
+** The TCL script in pDb->zTraceV2 is executed, with the arguments for
+** the event appended to it (as list elements).
+*/
+static int DbTraceV2Handler(
+ unsigned type, /* One of the SQLITE_TRACE_* event types. */
+ void *cd, /* The original context data pointer. */
+ void *pd, /* Primary event data, depends on event type. */
+ void *xd /* Extra event data, depends on event type. */
+){
+ SqliteDb *pDb = (SqliteDb*)cd;
+ Tcl_Obj *pCmd;
+
+ switch( type ){
+ case SQLITE_TRACE_STMT: {
+ sqlite3_stmt *pStmt = (sqlite3_stmt *)pd;
+ char *zSql = (char *)xd;
+
+ pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
+ Tcl_IncrRefCount(pCmd);
+ Tcl_ListObjAppendElement(pDb->interp, pCmd,
+ Tcl_NewWideIntObj((Tcl_WideInt)pStmt));
+ Tcl_ListObjAppendElement(pDb->interp, pCmd,
+ Tcl_NewStringObj(zSql, -1));
+ Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
+ Tcl_DecrRefCount(pCmd);
+ Tcl_ResetResult(pDb->interp);
+ break;
+ }
+ case SQLITE_TRACE_PROFILE: {
+ sqlite3_stmt *pStmt = (sqlite3_stmt *)pd;
+ sqlite3_int64 ns = (sqlite3_int64)xd;
+
+ pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
+ Tcl_IncrRefCount(pCmd);
+ Tcl_ListObjAppendElement(pDb->interp, pCmd,
+ Tcl_NewWideIntObj((Tcl_WideInt)pStmt));
+ Tcl_ListObjAppendElement(pDb->interp, pCmd,
+ Tcl_NewWideIntObj((Tcl_WideInt)ns));
+ Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
+ Tcl_DecrRefCount(pCmd);
+ Tcl_ResetResult(pDb->interp);
+ break;
+ }
+ case SQLITE_TRACE_ROW: {
+ sqlite3_stmt *pStmt = (sqlite3_stmt *)pd;
+
+ pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
+ Tcl_IncrRefCount(pCmd);
+ Tcl_ListObjAppendElement(pDb->interp, pCmd,
+ Tcl_NewWideIntObj((Tcl_WideInt)pStmt));
+ Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
+ Tcl_DecrRefCount(pCmd);
+ Tcl_ResetResult(pDb->interp);
+ break;
+ }
+ case SQLITE_TRACE_CLOSE: {
+ sqlite3 *db = (sqlite3 *)pd;
+
+ pCmd = Tcl_NewStringObj(pDb->zTraceV2, -1);
+ Tcl_IncrRefCount(pCmd);
+ Tcl_ListObjAppendElement(pDb->interp, pCmd,
+ Tcl_NewWideIntObj((Tcl_WideInt)db));
+ Tcl_EvalObjEx(pDb->interp, pCmd, TCL_EVAL_DIRECT);
+ Tcl_DecrRefCount(pCmd);
+ Tcl_ResetResult(pDb->interp);
+ break;
+ }
+ }
+ return SQLITE_OK;
+}
+#endif
+
+#ifndef SQLITE_OMIT_TRACE
+/*
** This routine is called by the SQLite profile handler after a statement
** SQL has executed. The TCL script in pDb->zProfile is evaluated.
*/
@@ -637,9 +717,9 @@ static void DbRollbackHandler(void *clientData){
** This procedure handles wal_hook callbacks.
*/
static int DbWalHandler(
- void *clientData,
- sqlite3 *db,
- const char *zDb,
+ void *clientData,
+ sqlite3 *db,
+ const char *zDb,
int nEntry
){
int ret = SQLITE_OK;
@@ -653,7 +733,7 @@ static int DbWalHandler(
Tcl_IncrRefCount(p);
Tcl_ListObjAppendElement(interp, p, Tcl_NewStringObj(zDb, -1));
Tcl_ListObjAppendElement(interp, p, Tcl_NewIntObj(nEntry));
- if( TCL_OK!=Tcl_EvalObjEx(interp, p, 0)
+ if( TCL_OK!=Tcl_EvalObjEx(interp, p, 0)
|| TCL_OK!=Tcl_GetIntFromObj(interp, Tcl_GetObjResult(interp), &ret)
){
Tcl_BackgroundError(interp);
@@ -695,11 +775,11 @@ static void DbUnlockNotify(void **apArg, int nArg){
** Pre-update hook callback.
*/
static void DbPreUpdateHandler(
- void *p,
+ void *p,
sqlite3 *db,
int op,
- const char *zDb,
- const char *zTbl,
+ const char *zDb,
+ const char *zTbl,
sqlite_int64 iKey1,
sqlite_int64 iKey2
){
@@ -727,10 +807,10 @@ static void DbPreUpdateHandler(
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
static void DbUpdateHandler(
- void *p,
+ void *p,
int op,
- const char *zDb,
- const char *zTbl,
+ const char *zDb,
+ const char *zTbl,
sqlite_int64 rowid
){
SqliteDb *pDb = (SqliteDb *)p;
@@ -815,7 +895,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
** script object, lappend the arguments, then evaluate the copy.
**
** By "shallow" copy, we mean only the outer list Tcl_Obj is duplicated.
- ** The new Tcl_Obj contains pointers to the original list elements.
+ ** The new Tcl_Obj contains pointers to the original list elements.
** That way, when Tcl_EvalObjv() is run and shimmers the first element
** of the list to tclCmdNameType, that alternate representation will
** be preserved and reused on the next invocation.
@@ -823,15 +903,15 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
Tcl_Obj **aArg;
int nArg;
if( Tcl_ListObjGetElements(p->interp, p->pScript, &nArg, &aArg) ){
- sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
+ sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
return;
- }
+ }
pCmd = Tcl_NewListObj(nArg, aArg);
Tcl_IncrRefCount(pCmd);
for(i=0; i<argc; i++){
sqlite3_value *pIn = argv[i];
Tcl_Obj *pVal;
-
+
/* Set pVal to contain the i'th column of this row. */
switch( sqlite3_value_type(pIn) ){
case SQLITE_BLOB: {
@@ -866,7 +946,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
rc = Tcl_ListObjAppendElement(p->interp, pCmd, pVal);
if( rc ){
Tcl_DecrRefCount(pCmd);
- sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
+ sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
return;
}
}
@@ -881,7 +961,7 @@ static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
}
if( rc && rc!=TCL_RETURN ){
- sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
+ sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
}else{
Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);
int n;
@@ -983,7 +1063,7 @@ static int auth_callback(
Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : "");
#ifdef SQLITE_USER_AUTHENTICATION
Tcl_DStringAppendElement(&str, zArg5 ? zArg5 : "");
-#endif
+#endif
rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str));
Tcl_DStringFree(&str);
zReply = rc==TCL_OK ? Tcl_GetStringResult(pDb->interp) : "SQLITE_DENY";
@@ -1075,12 +1155,12 @@ static int DbTransPostCmd(
pDb->disableAuth++;
if( sqlite3_exec(pDb->db, zEnd, 0, 0, 0) ){
/* This is a tricky scenario to handle. The most likely cause of an
- ** error is that the exec() above was an attempt to commit the
+ ** error is that the exec() above was an attempt to commit the
** top-level transaction that returned SQLITE_BUSY. Or, less likely,
** that an IO-error has occurred. In either case, throw a Tcl exception
** and try to rollback the transaction.
**
- ** But it could also be that the user executed one or more BEGIN,
+ ** But it could also be that the user executed one or more BEGIN,
** COMMIT, SAVEPOINT, RELEASE or ROLLBACK commands that are confusing
** this method's logic. Not clear how this would be best handled.
*/
@@ -1099,7 +1179,7 @@ static int DbTransPostCmd(
** Unless SQLITE_TEST is defined, this function is a simple wrapper around
** sqlite3_prepare_v2(). If SQLITE_TEST is defined, then it uses either
** sqlite3_prepare_v2() or legacy interface sqlite3_prepare(), depending
-** on whether or not the [db_use_legacy_prepare] command has been used to
+** on whether or not the [db_use_legacy_prepare] command has been used to
** configure the connection.
*/
static int dbPrepare(
@@ -1155,7 +1235,7 @@ static int dbPrepareAndBind(
for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pPreStmt->pNext){
int n = pPreStmt->nSql;
- if( nSql>=n
+ if( nSql>=n
&& memcmp(pPreStmt->zSql, zSql, n)==0
&& (zSql[n]==0 || zSql[n-1]==';')
){
@@ -1181,7 +1261,7 @@ static int dbPrepareAndBind(
break;
}
}
-
+
/* If no prepared statement was found. Compile the SQL text. Also allocate
** a new SqlPreparedStmt structure. */
if( pPreStmt==0 ){
@@ -1227,7 +1307,7 @@ static int dbPrepareAndBind(
assert( strlen30(pPreStmt->zSql)==pPreStmt->nSql );
assert( 0==memcmp(pPreStmt->zSql, zSql, pPreStmt->nSql) );
- /* Bind values to parameters that begin with $ or : */
+ /* Bind values to parameters that begin with $ or : */
for(i=1; i<=nVar; i++){
const char *zVar = sqlite3_bind_parameter_name(pStmt, i);
if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':' || zVar[0]=='@') ){
@@ -1315,8 +1395,8 @@ static void dbReleaseStmt(
assert( pDb->nStmt>0 );
}
pDb->nStmt++;
-
- /* If we have too many statement in cache, remove the surplus from
+
+ /* If we have too many statement in cache, remove the surplus from
** the end of the cache list. */
while( pDb->nStmt>pDb->maxStmt ){
SqlPreparedStmt *pLast = pDb->stmtLast;
@@ -1370,8 +1450,8 @@ static void dbReleaseColumnNames(DbEvalContext *p){
** If pArray is not NULL, then it contains the name of a Tcl array
** variable. The "*" member of this array is set to a list containing
** the names of the columns returned by the statement as part of each
-** call to dbEvalStep(), in order from left to right. e.g. if the names
-** of the returned columns are a, b and c, it does the equivalent of the
+** call to dbEvalStep(), in order from left to right. e.g. if the names
+** of the returned columns are a, b and c, it does the equivalent of the
** tcl command:
**
** set ${pArray}(*) {a b c}
@@ -1492,7 +1572,7 @@ static int dbEvalStep(DbEvalContext *p){
#if SQLITE_TEST
if( p->pDb->bLegacyPrepare && rcs==SQLITE_SCHEMA && zPrevSql ){
/* If the runtime error was an SQLITE_SCHEMA, and the database
- ** handle is configured to use the legacy sqlite3_prepare()
+ ** handle is configured to use the legacy sqlite3_prepare()
** interface, retry prepare()/step() on the same SQL statement.
** This only happens once. If there is a second SQLITE_SCHEMA
** error, the error will be returned to the caller. */
@@ -1580,11 +1660,11 @@ static int DbUseNre(void){
return( (major==8 && minor>=6) || major>8 );
}
#else
-/*
+/*
** Compiling using headers earlier than 8.6. In this case NR cannot be
** used, so DbUseNre() to always return zero. Add #defines for the other
** Tcl_NRxxx() functions to prevent them from causing compilation errors,
-** even though the only invocations of them are within conditional blocks
+** even though the only invocations of them are within conditional blocks
** of the form:
**
** if( DbUseNre() ) { ... }
@@ -1630,11 +1710,11 @@ static int DbEvalNextCmd(
}
}
- /* The required interpreter variables are now populated with the data
+ /* The required interpreter variables are now populated with the data
** from the current row. If using NRE, schedule callbacks to evaluate
** script pScript, then to invoke this function again to fetch the next
** row (or clean up if there is no next row or the script throws an
- ** exception). After scheduling the callbacks, return control to the
+ ** exception). After scheduling the callbacks, return control to the
** caller.
**
** If not using NRE, evaluate pScript directly and continue with the
@@ -1659,7 +1739,7 @@ static int DbEvalNextCmd(
}
/*
-** This function is used by the implementations of the following database
+** This function is used by the implementations of the following database
** handle sub-commands:
**
** $db update_hook ?SCRIPT?
@@ -1726,9 +1806,10 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
"preupdate", "profile", "progress",
"rekey", "restore", "rollback_hook",
"status", "timeout", "total_changes",
- "trace", "transaction", "unlock_notify",
- "update_hook", "version", "wal_hook",
- 0
+ "trace", "trace_v2", "transaction",
+ "unlock_notify", "update_hook", "version",
+ "wal_hook",
+ 0
};
enum DB_enum {
DB_AUTHORIZER, DB_BACKUP, DB_BUSY,
@@ -1741,8 +1822,9 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
DB_PREUPDATE, DB_PROFILE, DB_PROGRESS,
DB_REKEY, DB_RESTORE, DB_ROLLBACK_HOOK,
DB_STATUS, DB_TIMEOUT, DB_TOTAL_CHANGES,
- DB_TRACE, DB_TRANSACTION, DB_UNLOCK_NOTIFY,
- DB_UPDATE_HOOK, DB_VERSION, DB_WAL_HOOK,
+ DB_TRACE, DB_TRACE_V2, DB_TRANSACTION,
+ DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK, DB_VERSION,
+ DB_WAL_HOOK,
};
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
@@ -1928,7 +2010,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
return TCL_ERROR;
}else{
if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){
- Tcl_AppendResult( interp, "cannot convert \"",
+ Tcl_AppendResult( interp, "cannot convert \"",
Tcl_GetStringFromObj(objv[3],0), "\" to integer", (char*)0);
return TCL_ERROR;
}else{
@@ -1942,7 +2024,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
}
}else{
- Tcl_AppendResult( interp, "bad option \"",
+ Tcl_AppendResult( interp, "bad option \"",
Tcl_GetStringFromObj(objv[2],0), "\": must be flush or size",
(char*)0);
return TCL_ERROR;
@@ -1953,7 +2035,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
/* $db changes
**
** Return the number of rows that were modified, inserted, or deleted by
- ** the most recent INSERT, UPDATE or DELETE statement, not including
+ ** the most recent INSERT, UPDATE or DELETE statement, not including
** any changes made by trigger programs.
*/
case DB_CHANGES: {
@@ -2000,7 +2082,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
pCollate->zScript = (char*)&pCollate[1];
pDb->pCollate = pCollate;
memcpy(pCollate->zScript, zScript, nScript+1);
- if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8,
+ if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8,
pCollate, tclSqlCollate) ){
Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE);
return TCL_ERROR;
@@ -2126,7 +2208,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
const char *zSep;
const char *zNull;
if( objc<5 || objc>7 ){
- Tcl_WrongNumArgs(interp, 2, objv,
+ Tcl_WrongNumArgs(interp, 2, objv,
"CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?");
return TCL_ERROR;
}
@@ -2155,7 +2237,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
strcmp(zConflict, "fail" ) != 0 &&
strcmp(zConflict, "ignore" ) != 0 &&
strcmp(zConflict, "replace" ) != 0 ) {
- Tcl_AppendResult(interp, "Error: \"", zConflict,
+ Tcl_AppendResult(interp, "Error: \"", zConflict,
"\", conflict-algorithm must be one of: rollback, "
"abort, fail, ignore, or replace", (char*)0);
return TCL_ERROR;
@@ -2244,7 +2326,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
for(i=0; i<nCol; i++){
/* check for null data, if so, bind as null */
if( (nNull>0 && strcmp(azCol[i], zNull)==0)
- || strlen30(azCol[i])==0
+ || strlen30(azCol[i])==0
){
sqlite3_bind_null(pStmt, i+1);
}else{
@@ -2323,7 +2405,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
** The onecolumn method is the equivalent of:
** lindex [$db eval $sql] 0
*/
- case DB_EXISTS:
+ case DB_EXISTS:
case DB_ONECOLUMN: {
Tcl_Obj *pResult = 0;
DbEvalContext sEval;
@@ -2351,7 +2433,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
break;
}
-
+
/*
** $db eval $sql ?array? ?{ ...code... }?
**
@@ -2397,7 +2479,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
pScript = objv[objc-1];
Tcl_IncrRefCount(pScript);
-
+
p = (DbEvalContext *)Tcl_Alloc(sizeof(DbEvalContext));
dbEvalInit(p, pDb, objv[2], pArray);
@@ -2444,7 +2526,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
if( n>2 && strncmp(z, "-deterministic",n)==0 ){
flags |= SQLITE_DETERMINISTIC;
}else{
- Tcl_AppendResult(interp, "bad option \"", z,
+ Tcl_AppendResult(interp, "bad option \"", z,
"\": must be -argcount or -deterministic", 0
);
return TCL_ERROR;
@@ -2553,7 +2635,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
/*
- ** $db last_insert_rowid
+ ** $db last_insert_rowid
**
** Return an integer which is the ROWID for the most recent insert.
*/
@@ -2575,7 +2657,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
*/
/* $db progress ?N CALLBACK?
- **
+ **
** Invoke the given callback every N virtual machine opcodes while executing
** queries.
*/
@@ -2682,7 +2764,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
/* $db restore ?DATABASE? FILENAME
**
- ** Open a database file named FILENAME. Transfer the content
+ ** Open a database file named FILENAME. Transfer the content
** of FILENAME into the local database DATABASE (default: "main").
*/
case DB_RESTORE: {
@@ -2743,7 +2825,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
/*
** $db status (step|sort|autoindex)
**
- ** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or
+ ** Display SQLITE_STMTSTATUS_FULLSCAN_STEP or
** SQLITE_STMTSTATUS_SORT for the most recent eval.
*/
case DB_STATUS: {
@@ -2761,15 +2843,15 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}else if( strcmp(zOp, "autoindex")==0 ){
v = pDb->nIndex;
}else{
- Tcl_AppendResult(interp,
- "bad argument: should be autoindex, step, or sort",
+ Tcl_AppendResult(interp,
+ "bad argument: should be autoindex, step, or sort",
(char*)0);
return TCL_ERROR;
}
Tcl_SetObjResult(interp, Tcl_NewIntObj(v));
break;
}
-
+
/*
** $db timeout MILLESECONDS
**
@@ -2785,11 +2867,11 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
sqlite3_busy_timeout(pDb->db, ms);
break;
}
-
+
/*
** $db total_changes
**
- ** Return the number of rows that were modified, inserted, or deleted
+ ** Return the number of rows that were modified, inserted, or deleted
** since the database handle was created.
*/
case DB_TOTAL_CHANGES: {
@@ -2842,6 +2924,88 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
break;
}
+ /* $db trace_v2 ?CALLBACK? ?MASK?
+ **
+ ** Make arrangements to invoke the CALLBACK routine for each trace event
+ ** matching the mask that is generated. The parameters are appended to
+ ** CALLBACK before it is executed.
+ */
+ case DB_TRACE_V2: {
+ if( objc>4 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK? ?MASK?");
+ return TCL_ERROR;
+ }else if( objc==2 ){
+ if( pDb->zTraceV2 ){
+ Tcl_AppendResult(interp, pDb->zTraceV2, (char*)0);
+ }
+ }else{
+ char *zTraceV2;
+ int len;
+ Tcl_WideInt wMask = 0;
+ if( objc==4 ){
+ static const char *TTYPE_strs[] = {
+ "statement", "profile", "row", "close", 0
+ };
+ enum TTYPE_enum {
+ TTYPE_STMT, TTYPE_PROFILE, TTYPE_ROW, TTYPE_CLOSE
+ };
+ int i;
+ if( TCL_OK!=Tcl_ListObjLength(interp, objv[3], &len) ){
+ return TCL_ERROR;
+ }
+ for(i=0; i<len; i++){
+ Tcl_Obj *pObj;
+ int ttype;
+ if( TCL_OK!=Tcl_ListObjIndex(interp, objv[3], i, &pObj) ){
+ return TCL_ERROR;
+ }
+ if( Tcl_GetIndexFromObj(interp, pObj, TTYPE_strs, "trace type",
+ 0, &ttype)!=TCL_OK ){
+ Tcl_WideInt wType;
+ Tcl_Obj *pError = Tcl_DuplicateObj(Tcl_GetObjResult(interp));
+ Tcl_IncrRefCount(pError);
+ if( TCL_OK==Tcl_GetWideIntFromObj(interp, pObj, &wType) ){
+ Tcl_DecrRefCount(pError);
+ wMask |= wType;
+ }else{
+ Tcl_SetObjResult(interp, pError);
+ Tcl_DecrRefCount(pError);
+ return TCL_ERROR;
+ }
+ }else{
+ switch( (enum TTYPE_enum)ttype ){
+ case TTYPE_STMT: wMask |= SQLITE_TRACE_STMT; break;
+ case TTYPE_PROFILE: wMask |= SQLITE_TRACE_PROFILE; break;
+ case TTYPE_ROW: wMask |= SQLITE_TRACE_ROW; break;
+ case TTYPE_CLOSE: wMask |= SQLITE_TRACE_CLOSE; break;
+ }
+ }
+ }
+ }else{
+ wMask = SQLITE_TRACE_STMT; /* use the "legacy" default */
+ }
+ if( pDb->zTraceV2 ){
+ Tcl_Free(pDb->zTraceV2);
+ }
+ zTraceV2 = Tcl_GetStringFromObj(objv[2], &len);
+ if( zTraceV2 && len>0 ){
+ pDb->zTraceV2 = Tcl_Alloc( len + 1 );
+ memcpy(pDb->zTraceV2, zTraceV2, len+1);
+ }else{
+ pDb->zTraceV2 = 0;
+ }
+#if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT)
+ if( pDb->zTraceV2 ){
+ pDb->interp = interp;
+ sqlite3_trace_v2(pDb->db, (unsigned)wMask, DbTraceV2Handler, pDb);
+ }else{
+ sqlite3_trace_v2(pDb->db, 0, 0, 0);
+ }
+#endif
+ }
+ break;
+ }
+
/* $db transaction [-deferred|-immediate|-exclusive] SCRIPT
**
** Start a new transaction (if we are not already in the midst of a
@@ -2894,7 +3058,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
/* If using NRE, schedule a callback to invoke the script pScript, then
** a second callback to commit (or rollback) the transaction or savepoint
** opened above. If not using NRE, evaluate the script directly, then
- ** call function DbTransPostCmd() to commit (or rollback) the transaction
+ ** call function DbTransPostCmd() to commit (or rollback) the transaction
** or savepoint. */
if( DbUseNre() ){
Tcl_NRAddCallback(interp, DbTransPostCmd, cd, 0, 0, 0);
@@ -2925,14 +3089,14 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
Tcl_DecrRefCount(pDb->pUnlockNotify);
pDb->pUnlockNotify = 0;
}
-
+
if( objc==3 ){
xNotify = DbUnlockNotify;
pNotifyArg = (void *)pDb;
pDb->pUnlockNotify = objv[2];
Tcl_IncrRefCount(pDb->pUnlockNotify);
}
-
+
if( sqlite3_unlock_notify(pDb->db, xNotify, pNotifyArg) ){
Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), (char*)0);
rc = TCL_ERROR;
@@ -3031,13 +3195,13 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
** $db update_hook ?script?
** $db rollback_hook ?script?
*/
- case DB_WAL_HOOK:
- case DB_UPDATE_HOOK:
+ case DB_WAL_HOOK:
+ case DB_UPDATE_HOOK:
case DB_ROLLBACK_HOOK: {
- /* set ppHook to point at pUpdateHook or pRollbackHook, depending on
+ /* set ppHook to point at pUpdateHook or pRollbackHook, depending on
** whether [$db update_hook] or [$db rollback_hook] was invoked.
*/
- Tcl_Obj **ppHook = 0;
+ Tcl_Obj **ppHook = 0;
if( choice==DB_WAL_HOOK ) ppHook = &pDb->pWalHook;
if( choice==DB_UPDATE_HOOK ) ppHook = &pDb->pUpdateHook;
if( choice==DB_ROLLBACK_HOOK ) ppHook = &pDb->pRollbackHook;
@@ -3198,7 +3362,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
}
if( objc<3 || (objc&1)!=1 ){
- Tcl_WrongNumArgs(interp, 1, objv,
+ Tcl_WrongNumArgs(interp, 1, objv,
"HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?"
" ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?"
#if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
@@ -3490,7 +3654,7 @@ static void MD5Init(MD5Context *ctx){
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
-static
+static
void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){
uint32 t;
@@ -3536,7 +3700,7 @@ void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len){
}
/*
- * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
static void MD5Final(unsigned char digest[16], MD5Context *ctx){
@@ -3612,7 +3776,7 @@ static void MD5DigestToBase10x8(unsigned char digest[16], char zDigest[50]){
/*
** A TCL command for md5. The argument is the text to be hashed. The
-** Result is the hash in base64.
+** Result is the hash in base64.
*/
static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){
MD5Context ctx;
@@ -3621,7 +3785,7 @@ static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){
void (*converter)(unsigned char*, char*);
if( argc!=2 ){
- Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
+ Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
" TEXT\"", (char*)0);
return TCL_ERROR;
}
@@ -3646,13 +3810,13 @@ static int md5file_cmd(void*cd, Tcl_Interp*interp, int argc, const char **argv){
char zBuf[10240];
if( argc!=2 ){
- Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
+ Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
" FILENAME\"", (char*)0);
return TCL_ERROR;
}
in = fopen(argv[1],"rb");
if( in==0 ){
- Tcl_AppendResult(interp,"unable to open file \"", argv[1],
+ Tcl_AppendResult(interp,"unable to open file \"", argv[1],
"\" for reading", (char*)0);
return TCL_ERROR;
}
@@ -3719,7 +3883,7 @@ static void md5finalize(sqlite3_context *context){
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
}
int Md5_Register(sqlite3 *db){
- int rc = sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0,
+ int rc = sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0,
md5step, md5finalize);
sqlite3_overload_function(db, "md5sum", -1); /* To exercise this API */
return rc;
@@ -3870,7 +4034,7 @@ static int db_last_stmt_ptr(
** Configure the interpreter passed as the first argument to have access
** to the commands and linked variables that make up:
**
-** * the [sqlite3] extension itself,
+** * the [sqlite3] extension itself,
**
** * If SQLITE_TCLMD5 or SQLITE_TEST is defined, the Md5 commands, and
**
diff --git a/src/test1.c b/src/test1.c
index 5ce818bf7..7d8388113 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -3633,7 +3633,7 @@ static int test_bind_blob(
Tcl_Obj *CONST objv[]
){
sqlite3_stmt *pStmt;
- int idx;
+ int len, idx;
int bytes;
char *value;
int rc;
@@ -3652,9 +3652,18 @@ static int test_bind_blob(
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
- value = Tcl_GetString(objv[3]);
+
+ value = (char*)Tcl_GetByteArrayFromObj(objv[3], &len);
if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
+ if( bytes>len ){
+ char zBuf[200];
+ sqlite3_snprintf(sizeof(zBuf), zBuf,
+ "cannot use %d blob bytes, have %d", bytes, len);
+ Tcl_AppendResult(interp, zBuf, -1);
+ return TCL_ERROR;
+ }
+
rc = sqlite3_bind_blob(pStmt, idx, value, bytes, xDestructor);
if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
if( rc!=SQLITE_OK ){
@@ -4386,6 +4395,26 @@ static int test_sql(
Tcl_SetResult(interp, (char *)sqlite3_sql(pStmt), TCL_VOLATILE);
return TCL_OK;
}
+static int test_ex_sql(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3_stmt *pStmt;
+ char *z;
+
+ if( objc!=2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "STMT");
+ return TCL_ERROR;
+ }
+
+ if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
+ z = sqlite3_expanded_sql(pStmt);
+ Tcl_SetResult(interp, z, TCL_VOLATILE);
+ sqlite3_free(z);
+ return TCL_OK;
+}
/*
** Usage: sqlite3_column_count STMT
@@ -7276,6 +7305,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_changes", test_changes ,0 },
{ "sqlite3_step", test_step ,0 },
{ "sqlite3_sql", test_sql ,0 },
+ { "sqlite3_expanded_sql", test_ex_sql ,0 },
{ "sqlite3_next_stmt", test_next_stmt ,0 },
{ "sqlite3_stmt_readonly", test_stmt_readonly ,0 },
{ "sqlite3_stmt_busy", test_stmt_busy ,0 },
diff --git a/src/vacuum.c b/src/vacuum.c
index bc7b5831b..9ab7f766e 100644
--- a/src/vacuum.c
+++ b/src/vacuum.c
@@ -121,7 +121,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
int saved_flags; /* Saved value of the db->flags */
int saved_nChange; /* Saved value of db->nChange */
int saved_nTotalChange; /* Saved value of db->nTotalChange */
- void (*saved_xTrace)(void*,const char*); /* Saved db->xTrace */
+ u8 saved_mTrace; /* Saved trace settings */
Db *pDb = 0; /* Database to detach at end of vacuum */
int isMemDb; /* True if vacuuming a :memory: database */
int nRes; /* Bytes of reserved space at the end of each page */
@@ -142,10 +142,10 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
saved_flags = db->flags;
saved_nChange = db->nChange;
saved_nTotalChange = db->nTotalChange;
- saved_xTrace = db->xTrace;
+ saved_mTrace = db->mTrace;
db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin;
db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder);
- db->xTrace = 0;
+ db->mTrace = 0;
pMain = db->aDb[0].pBt;
isMemDb = sqlite3PagerIsMemdb(sqlite3BtreePager(pMain));
@@ -345,7 +345,7 @@ end_of_vacuum:
db->flags = saved_flags;
db->nChange = saved_nChange;
db->nTotalChange = saved_nTotalChange;
- db->xTrace = saved_xTrace;
+ db->mTrace = saved_mTrace;
sqlite3BtreeSetPageSize(pMain, -1, -1, 1);
/* Currently there is an SQL level transaction open on the vacuum
diff --git a/src/vdbe.c b/src/vdbe.c
index 6adbcbbec..cdbd7301b 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -1383,6 +1383,10 @@ case OP_ResultRow: {
}
if( db->mallocFailed ) goto no_mem;
+ if( db->mTrace & SQLITE_TRACE_ROW ){
+ db->xTrace(SQLITE_TRACE_ROW, db->pTraceArg, p, 0);
+ }
+
/* Return SQLITE_ROW
*/
p->pc = (int)(pOp - aOp) + 1;
@@ -6781,13 +6785,21 @@ case OP_Init: { /* jump */
char *z;
#ifndef SQLITE_OMIT_TRACE
- if( db->xTrace
+ if( (db->mTrace & (SQLITE_TRACE_STMT|SQLITE_TRACE_LEGACY))!=0
&& !p->doingRerun
&& (zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql))!=0
){
z = sqlite3VdbeExpandSql(p, zTrace);
- db->xTrace(db->pTraceArg, z);
- sqlite3DbFree(db, z);
+#ifndef SQLITE_OMIT_DEPRECATED
+ if( db->mTrace & SQLITE_TRACE_LEGACY ){
+ void (*x)(void*,const char*) = (void(*)(void*,const char*))db->xTrace;
+ x(db->pTraceArg, z);
+ }else
+#endif
+ {
+ (void)db->xTrace(SQLITE_TRACE_STMT,db->pTraceArg,p,z);
+ }
+ sqlite3_free(z);
}
#ifdef SQLITE_USE_FCNTL_TRACE
zTrace = (pOp->p4.z ? pOp->p4.z : p->zSql);
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index 83718eae3..b17c0e0a4 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -60,12 +60,19 @@ static int vdbeSafetyNotNull(Vdbe *p){
*/
static SQLITE_NOINLINE void invokeProfileCallback(sqlite3 *db, Vdbe *p){
sqlite3_int64 iNow;
+ sqlite3_int64 iElapse;
assert( p->startTime>0 );
- assert( db->xProfile!=0 );
+ assert( db->xProfile!=0 || (db->mTrace & SQLITE_TRACE_PROFILE)!=0 );
assert( db->init.busy==0 );
assert( p->zSql!=0 );
sqlite3OsCurrentTimeInt64(db->pVfs, &iNow);
- db->xProfile(db->pProfileArg, p->zSql, (iNow - p->startTime)*1000000);
+ iElapse = (iNow - p->startTime)*1000000;
+ if( db->xProfile ){
+ db->xProfile(db->pProfileArg, p->zSql, iElapse);
+ }
+ if( db->mTrace & SQLITE_TRACE_PROFILE ){
+ db->xTrace(SQLITE_TRACE_PROFILE, db->pTraceArg, p, (void*)&iElapse);
+ }
p->startTime = 0;
}
/*
@@ -569,7 +576,8 @@ static int sqlite3Step(Vdbe *p){
);
#ifndef SQLITE_OMIT_TRACE
- if( db->xProfile && !db->init.busy && p->zSql ){
+ if( (db->xProfile || (db->mTrace & SQLITE_TRACE_PROFILE)!=0)
+ && !db->init.busy && p->zSql ){
sqlite3OsCurrentTimeInt64(db->pVfs, &p->startTime);
}else{
assert( p->startTime==0 );
@@ -1604,6 +1612,39 @@ int sqlite3_stmt_status(sqlite3_stmt *pStmt, int op, int resetFlag){
return (int)v;
}
+/*
+** Return the SQL associated with a prepared statement
+*/
+const char *sqlite3_sql(sqlite3_stmt *pStmt){
+ Vdbe *p = (Vdbe *)pStmt;
+ return p ? p->zSql : 0;
+}
+
+/*
+** Return the SQL associated with a prepared statement with
+** bound parameters expanded. Space to hold the returned string is
+** obtained from sqlite3_malloc(). The caller is responsible for
+** freeing the returned string by passing it to sqlite3_free().
+**
+** The SQLITE_TRACE_SIZE_LIMIT puts an upper bound on the size of
+** expanded bound parameters.
+*/
+char *sqlite3_expanded_sql(sqlite3_stmt *pStmt){
+#ifdef SQLITE_OMIT_TRACE
+ return 0;
+#else
+ char *z = 0;
+ const char *zSql = sqlite3_sql(pStmt);
+ if( zSql ){
+ Vdbe *p = (Vdbe *)pStmt;
+ sqlite3_mutex_enter(p->db->mutex);
+ z = sqlite3VdbeExpandSql(p, zSql);
+ sqlite3_mutex_leave(p->db->mutex);
+ }
+ return z;
+#endif
+}
+
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
/*
** Allocate and populate an UnpackedRecord structure based on the serialized
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 63609d72d..992fa4db9 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -65,14 +65,6 @@ void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, int isPrepareV2){
}
/*
-** Return the SQL associated with a prepared statement
-*/
-const char *sqlite3_sql(sqlite3_stmt *pStmt){
- Vdbe *p = (Vdbe *)pStmt;
- return p ? p->zSql : 0;
-}
-
-/*
** Swap all content between two VDBE structures.
*/
void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
diff --git a/src/vdbetrace.c b/src/vdbetrace.c
index 07235c931..7b4736399 100644
--- a/src/vdbetrace.c
+++ b/src/vdbetrace.c
@@ -81,10 +81,13 @@ char *sqlite3VdbeExpandSql(
int i; /* Loop counter */
Mem *pVar; /* Value of a host parameter */
StrAccum out; /* Accumulate the output here */
+#ifndef SQLITE_OMIT_UTF16
+ Mem utf8; /* Used to convert UTF16 parameters into UTF8 for display */
+#endif
char zBase[100]; /* Initial working space */
db = p->db;
- sqlite3StrAccumInit(&out, db, zBase, sizeof(zBase),
+ sqlite3StrAccumInit(&out, 0, zBase, sizeof(zBase),
db->aLimit[SQLITE_LIMIT_LENGTH]);
if( db->nVdbeExec>1 ){
while( *zRawSql ){
@@ -135,12 +138,14 @@ char *sqlite3VdbeExpandSql(
int nOut; /* Number of bytes of the string text to include in output */
#ifndef SQLITE_OMIT_UTF16
u8 enc = ENC(db);
- Mem utf8;
if( enc!=SQLITE_UTF8 ){
memset(&utf8, 0, sizeof(utf8));
utf8.db = db;
sqlite3VdbeMemSetStr(&utf8, pVar->z, pVar->n, enc, SQLITE_STATIC);
- sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8);
+ if( SQLITE_NOMEM==sqlite3VdbeChangeEncoding(&utf8, SQLITE_UTF8) ){
+ out.accError = STRACCUM_NOMEM;
+ out.nAlloc = 0;
+ }
pVar = &utf8;
}
#endif
@@ -182,6 +187,7 @@ char *sqlite3VdbeExpandSql(
}
}
}
+ if( out.accError ) sqlite3StrAccumReset(&out);
return sqlite3StrAccumFinish(&out);
}
diff --git a/test/csv01.test b/test/csv01.test
index a6fff81c3..8151c4771 100644
--- a/test/csv01.test
+++ b/test/csv01.test
@@ -13,7 +13,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
-set testprefix closure01
+set testprefix csv01
ifcapable !vtab||!cte { finish_test ; return }
diff --git a/test/dbstatus.test b/test/dbstatus.test
index 00c5deabd..fb4cbe04b 100644
--- a/test/dbstatus.test
+++ b/test/dbstatus.test
@@ -390,6 +390,7 @@ ifcapable shared_cache {
sqlite3 db file:test.db?cache=shared
do_execsql_test 4.0 {
+ PRAGMA auto_vacuum=NONE;
CREATE TABLE t1(a, b, c);
INSERT INTO t1 VALUES(1, 2, 3);
}
diff --git a/test/tclsqlite.test b/test/tclsqlite.test
index 767dd01be..bdb0fc56d 100644
--- a/test/tclsqlite.test
+++ b/test/tclsqlite.test
@@ -34,7 +34,7 @@ do_test tcl-1.1 {
do_test tcl-1.2 {
set v [catch {db bogus} msg]
lappend v $msg
-} {1 {bad option "bogus": must be authorizer, backup, busy, cache, changes, close, collate, collation_needed, commit_hook, complete, copy, enable_load_extension, errorcode, eval, exists, function, incrblob, interrupt, last_insert_rowid, nullvalue, onecolumn, preupdate, profile, progress, rekey, restore, rollback_hook, status, timeout, total_changes, trace, transaction, unlock_notify, update_hook, version, or wal_hook}}
+} {1 {bad option "bogus": must be authorizer, backup, busy, cache, changes, close, collate, collation_needed, commit_hook, complete, copy, enable_load_extension, errorcode, eval, exists, function, incrblob, interrupt, last_insert_rowid, nullvalue, onecolumn, preupdate, profile, progress, rekey, restore, rollback_hook, status, timeout, total_changes, trace, trace_v2, transaction, unlock_notify, update_hook, version, or wal_hook}}
do_test tcl-1.2.1 {
set v [catch {db cache bogus} msg]
lappend v $msg
diff --git a/test/trace3.test b/test/trace3.test
new file mode 100644
index 000000000..0809759d8
--- /dev/null
+++ b/test/trace3.test
@@ -0,0 +1,233 @@
+# 2016 July 14
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library. The focus of
+# this test file is the "sqlite3_trace_v2()" and "sqlite3_expanded_sql()"
+# APIs.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+ifcapable !trace { finish_test ; return }
+set ::testprefix trace3
+
+proc trace_v2_error { args } {
+ lappend ::stmtlist(error) [string trim $args]
+ error "trace error"; # this will be ignored.
+}
+proc trace_v2_record { args } {
+ lappend ::stmtlist(record) [string trim $args]
+}
+proc trace_v2_nop { args } {}; # do nothing.
+
+do_test trace3-1.0 {
+ execsql {
+ CREATE TABLE t1(a,b);
+ INSERT INTO t1 VALUES(1,NULL);
+ INSERT INTO t1 VALUES(2,-1);
+ INSERT INTO t1 VALUES(3,0);
+ INSERT INTO t1 VALUES(4,1);
+ INSERT INTO t1 VALUES(5,-2147483648);
+ INSERT INTO t1 VALUES(6,2147483647);
+ INSERT INTO t1 VALUES(7,-9223372036854775808);
+ INSERT INTO t1 VALUES(8,9223372036854775807);
+ INSERT INTO t1 VALUES(9,-1.0);
+ INSERT INTO t1 VALUES(10,0.0);
+ INSERT INTO t1 VALUES(11,1.0);
+ INSERT INTO t1 VALUES(12,'');
+ INSERT INTO t1 VALUES(13,'1');
+ INSERT INTO t1 VALUES(14,'one');
+ INSERT INTO t1 VALUES(15,x'abcd0123');
+ INSERT INTO t1 VALUES(16,x'4567cdef');
+ }
+} {}
+
+do_test trace3-1.1 {
+ set rc [catch {db trace_v2 1 2 3} msg]
+ lappend rc $msg
+} {1 {wrong # args: should be "db trace_v2 ?CALLBACK? ?MASK?"}}
+do_test trace3-1.2 {
+ set rc [catch {db trace_v2 1 bad} msg]
+ lappend rc $msg
+} {1 {bad trace type "bad": must be statement, profile, row, or close}}
+
+do_test trace3-2.1 {
+ db trace_v2 trace_v2_nop
+ db trace_v2
+} {trace_v2_nop}
+
+do_test trace3-3.1 {
+ unset -nocomplain ::stmtlist
+ db trace_v2 trace_v2_nop
+ execsql {
+ SELECT a, b FROM t1 ORDER BY a;
+ }
+ array get ::stmtlist
+} {}
+do_test trace3-3.2 {
+ set ::stmtlist(error) {}
+ db trace_v2 trace_v2_error
+ execsql {
+ SELECT a, b FROM t1 ORDER BY a;
+ }
+ set ::stmtlist(error)
+} {/^\{-?\d+ \{SELECT a, b FROM t1 ORDER BY a;\}\}$/}
+do_test trace3-3.3 {
+ set ::stmtlist(record) {}
+ db trace_v2 trace_v2_record
+ execsql {
+ SELECT a, b FROM t1 ORDER BY a;
+ }
+ set ::stmtlist(record)
+} {/^\{-?\d+ \{SELECT a, b FROM t1 ORDER BY a;\}\}$/}
+do_test trace3-3.4 {
+ set ::stmtlist(record) {}
+ db trace_v2 trace_v2_record statement
+ execsql {
+ SELECT a, b FROM t1 ORDER BY a;
+ }
+ set ::stmtlist(record)
+} {/^\{-?\d+ \{SELECT a, b FROM t1 ORDER BY a;\}\}$/}
+do_test trace3-3.5 {
+ set ::stmtlist(record) {}
+ db trace_v2 trace_v2_record 1
+ execsql {
+ SELECT a, b FROM t1 ORDER BY a;
+ }
+ set ::stmtlist(record)
+} {/^\{-?\d+ \{SELECT a, b FROM t1 ORDER BY a;\}\}$/}
+
+do_test trace3-4.1 {
+ set ::stmtlist(record) {}
+ db trace_v2 trace_v2_record profile
+ execsql {
+ SELECT a, b FROM t1 ORDER BY a;
+ }
+ set ::stmtlist(record)
+} {/^\{-?\d+ -?\d+\}$/}
+do_test trace3-4.2 {
+ set ::stmtlist(record) {}
+ db trace_v2 trace_v2_record 2
+ execsql {
+ SELECT a, b FROM t1 ORDER BY a;
+ }
+ set ::stmtlist(record)
+} {/^\{-?\d+ -?\d+\}$/}
+
+do_test trace3-5.1 {
+ set ::stmtlist(record) {}
+ db trace_v2 trace_v2_record row
+ execsql {
+ SELECT a, b FROM t1 ORDER BY a;
+ }
+ set ::stmtlist(record)
+} "/^[string trim [string repeat {\d+ } 16]]\$/"
+do_test trace3-5.2 {
+ set ::stmtlist(record) {}
+ db trace_v2 trace_v2_record 4
+ execsql {
+ SELECT a, b FROM t1 ORDER BY a;
+ }
+ set ::stmtlist(record)
+} "/^[string trim [string repeat {\d+ } 16]]\$/"
+
+do_test trace3-6.1 {
+ set ::stmtlist(record) {}
+ db trace_v2 trace_v2_record {profile row}
+ execsql {
+ SELECT a, b FROM t1 ORDER BY a;
+ }
+ set ::stmtlist(record)
+} "/^[string trim [string repeat {-?\d+ } 16]] \\\{-?\\d+ -?\\d+\\\}\$/"
+do_test trace3-6.2 {
+ set ::stmtlist(record) {}
+ db trace_v2 trace_v2_record {statement profile row}
+ execsql {
+ SELECT a, b FROM t1 ORDER BY a;
+ }
+ set ::stmtlist(record)
+} "/^\\\{-?\\d+ \\\{SELECT a, b FROM t1 ORDER BY a;\\\}\\\} [string trim \
+[string repeat {-?\d+ } 16]] \\\{-?\\d+ -?\\d+\\\}\$/"
+
+do_test trace3-7.1 {
+ set DB [sqlite3_connection_pointer db]
+
+ set STMT [sqlite3_prepare_v2 $DB \
+ "SELECT a, b FROM t1 WHERE b = ? ORDER BY a;" -1 TAIL]
+} {/^[0-9A-Fa-f]+$/}
+
+do_test trace3-8.1 {
+ list [sqlite3_bind_null $STMT 1] [sqlite3_expanded_sql $STMT]
+} {{} {SELECT a, b FROM t1 WHERE b = NULL ORDER BY a;}}
+do_test trace3-8.2 {
+ list [sqlite3_bind_int $STMT 1 123] [sqlite3_expanded_sql $STMT]
+} {{} {SELECT a, b FROM t1 WHERE b = 123 ORDER BY a;}}
+do_test trace3-8.3 {
+ list [sqlite3_bind_int64 $STMT 1 123] [sqlite3_expanded_sql $STMT]
+} {{} {SELECT a, b FROM t1 WHERE b = 123 ORDER BY a;}}
+do_test trace3-8.4 {
+ list [sqlite3_bind_text $STMT 1 "some string" 11] \
+ [sqlite3_expanded_sql $STMT]
+} {{} {SELECT a, b FROM t1 WHERE b = 'some string' ORDER BY a;}}
+do_test trace3-8.5 {
+ list [sqlite3_bind_text $STMT 1 "some 'bad' string" 17] \
+ [sqlite3_expanded_sql $STMT]
+} {{} {SELECT a, b FROM t1 WHERE b = 'some ''bad'' string' ORDER BY a;}}
+do_test trace3-8.6 {
+ list [sqlite3_bind_double $STMT 1 123] [sqlite3_expanded_sql $STMT]
+} {{} {SELECT a, b FROM t1 WHERE b = 123.0 ORDER BY a;}}
+do_test trace3-8.7 {
+ list [sqlite3_bind_text16 $STMT 1 \
+ [encoding convertto unicode hi\000yall\000] 16] \
+ [sqlite3_expanded_sql $STMT]
+} {{} {SELECT a, b FROM t1 WHERE b = 'hi' ORDER BY a;}}
+do_test trace3-8.8 {
+ list [sqlite3_bind_blob $STMT 1 "\x12\x34\x56" 3] \
+ [sqlite3_expanded_sql $STMT]
+} {{} {SELECT a, b FROM t1 WHERE b = x'123456' ORDER BY a;}}
+do_test trace3-8.9 {
+ list [sqlite3_bind_blob $STMT 1 "\xAB\xCD\xEF" 3] \
+ [sqlite3_expanded_sql $STMT]
+} {{} {SELECT a, b FROM t1 WHERE b = x'abcdef' ORDER BY a;}}
+
+do_test trace3-9.1 {
+ sqlite3_finalize $STMT
+} {SQLITE_OK}
+
+do_test trace3-10.1 {
+ db trace_v2 ""
+ db trace_v2
+} {}
+do_test trace3-10.2 {
+ unset -nocomplain ::stmtlist
+ db trace_v2 "" {statement profile row}
+ execsql {
+ SELECT a, b FROM t1 ORDER BY a;
+ }
+ array get ::stmtlist
+} {}
+
+do_test trace3-11.1 {
+ set ::stmtlist(record) {}
+ db trace_v2 trace_v2_record close
+ db close
+ set ::stmtlist(record)
+} {/^-?\d+$/}
+
+reset_db
+
+do_test trace3-11.2 {
+ set ::stmtlist(record) {}
+ db trace_v2 trace_v2_record 8
+ db close
+ set ::stmtlist(record)
+} {/^-?\d+$/}
+
+finish_test
diff --git a/test/vacuummem.test b/test/vacuummem.test
new file mode 100644
index 000000000..b0f5cf203
--- /dev/null
+++ b/test/vacuummem.test
@@ -0,0 +1,59 @@
+# 2005 February 15
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library. The
+# focus of this file is testing that the VACUUM statement correctly
+# frees any memory used for a temporary cache.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix vacuummem
+
+if {[permutation]=="memsubsys1"} {
+ finish_test
+ return
+}
+
+
+proc memory_used {} {
+ set stat [sqlite3_status SQLITE_STATUS_MEMORY_USED 1]
+ lindex $stat 1
+}
+
+do_execsql_test 1.0 {
+ PRAGMA cache_size = -2000;
+ CREATE TABLE t1(a, b, c);
+
+ WITH r(i) AS (
+ SELECT 1 UNION ALL SELECT i+1 FROM r WHERE i<100000
+ )
+ INSERT INTO t1 SELECT randomblob(100),randomblob(100),randomblob(100) FROM r;
+
+ CREATE INDEX t1a ON t1(a);
+ CREATE INDEX t1b ON t1(b);
+ CREATE INDEX t1c ON t1(c);
+}
+
+do_test 1.1 { memory_used } {#/2300000/}
+
+do_execsql_test 1.2 VACUUM
+
+do_test 1.3 { memory_used } {#/2300000/}
+
+do_execsql_test 1.4 {
+ SELECT count(*) FROM t1 WHERE +a IS NOT NULL
+} {100000}
+
+do_test 1.5 { memory_used } {#/2300000/}
+
+
+
+finish_test
diff --git a/tool/sqldiff.c b/tool/sqldiff.c
index dbdf726df..e92e8aab2 100644
--- a/tool/sqldiff.c
+++ b/tool/sqldiff.c
@@ -1822,7 +1822,7 @@ const char *all_tables_sql(){
int rc;
rc = sqlite3_exec(g.db,
- "CREATE TEMP TABLE tblmap(module, postfix);"
+ "CREATE TEMP TABLE tblmap(module COLLATE nocase, postfix);"
"INSERT INTO temp.tblmap VALUES"
"('fts3', '_content'), ('fts3', '_segments'), ('fts3', '_segdir'),"