Compare commits
90 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 464a2dd1f5 | |||
| 351064b452 | |||
| a895a4d22c | |||
| ffc8f3e201 | |||
| 2c3abeb8c3 | |||
| 5de7d966bd | |||
| dea7d70d1b | |||
| 1d32488037 | |||
| 72673a24e2 | |||
| d8922052b2 | |||
| 063970a15f | |||
| a25165fa68 | |||
| dd90d7ee81 | |||
| 86e166a778 | |||
| bb9a378df3 | |||
| 5b875311a3 | |||
| 2d2e7bfeff | |||
| 2f89546001 | |||
| 0fe8c1b967 | |||
| f26a1549ac | |||
| 1fd2d7d471 | |||
| 9b5444af6c | |||
| ac5649a985 | |||
| cb7fe0ab9c | |||
| d89b834f54 | |||
| 3f2d22e1a3 | |||
| 5ab63775dd | |||
| 0a79238b39 | |||
| 0da10d3289 | |||
| ab4624d005 | |||
| 7a1bca7e74 | |||
| a3898250d4 | |||
| 643091f071 | |||
| 2d8233157d | |||
| 341eca7f68 | |||
| 5e3b49bc42 | |||
| fdab02635c | |||
| 1b40e63f9b | |||
| 654858d7f4 | |||
| 113762a284 | |||
| 42a7b4bac9 | |||
| 664f85dd59 | |||
| fead4ed8f3 | |||
| 36ff0bf684 | |||
| 64b600ff13 | |||
| bea3b976a9 | |||
| 58f95c43ad | |||
| bb8f925294 | |||
| 4429c20b86 | |||
| c5352b996a | |||
| 756d3b3e9d | |||
| 2b8669a9da | |||
| d816e00d13 | |||
| 77b1deec40 | |||
| 13835c41e8 | |||
| 302f583aa4 | |||
| f9df2fbdcd | |||
| 70273d0bab | |||
| 0a9d9d566e | |||
| dd715f7c57 | |||
| 8ac1a67eff | |||
| fad01993b7 | |||
| 6f9c5669e2 | |||
| d7b06909ad | |||
| 8023104252 | |||
| 5a2c8c885c | |||
| 51a205410c | |||
| 85fabf1444 | |||
| bfa395d085 | |||
| 2d8e3caa2e | |||
| 949d43a5fd | |||
| 43f4066e10 | |||
| 47b7fc7843 | |||
| de58f4fe7f | |||
| 923c4b35be | |||
| 1728bcb07f | |||
| 4ace5362c2 | |||
| b391b94431 | |||
| 97d3898335 | |||
| 9a06d30bb5 | |||
| 86a11b8a6a | |||
| 6137138ded | |||
| 8790b6e860 | |||
| b1a6eada1d | |||
| 7abfe9d0c6 | |||
| 35404253f6 | |||
| a26b9a7727 | |||
| bba8206be9 | |||
| 739383d25d | |||
| 62ecc28caf |
@@ -359,6 +359,7 @@ TESTSRC = \
|
||||
$(TOP)/src/test_autoext.c \
|
||||
$(TOP)/src/test_async.c \
|
||||
$(TOP)/src/test_backup.c \
|
||||
$(TOP)/src/test_blob.c \
|
||||
$(TOP)/src/test_btree.c \
|
||||
$(TOP)/src/test_config.c \
|
||||
$(TOP)/src/test_demovfs.c \
|
||||
@@ -394,6 +395,7 @@ TESTSRC = \
|
||||
TESTSRC += \
|
||||
$(TOP)/ext/misc/amatch.c \
|
||||
$(TOP)/ext/misc/closure.c \
|
||||
$(TOP)/ext/misc/eval.c \
|
||||
$(TOP)/ext/misc/fileio.c \
|
||||
$(TOP)/ext/misc/fuzzer.c \
|
||||
$(TOP)/ext/misc/ieee754.c \
|
||||
|
||||
@@ -828,6 +828,7 @@ TESTSRC = \
|
||||
$(TOP)\src\test_autoext.c \
|
||||
$(TOP)\src\test_async.c \
|
||||
$(TOP)\src\test_backup.c \
|
||||
$(TOP)\src\test_blob.c \
|
||||
$(TOP)\src\test_btree.c \
|
||||
$(TOP)\src\test_config.c \
|
||||
$(TOP)\src\test_demovfs.c \
|
||||
@@ -863,6 +864,7 @@ TESTSRC = \
|
||||
TESTEXT = \
|
||||
$(TOP)\ext\misc\amatch.c \
|
||||
$(TOP)\ext\misc\closure.c \
|
||||
$(TOP)\ext\misc\eval.c \
|
||||
$(TOP)\ext\misc\fileio.c \
|
||||
$(TOP)\ext\misc\fuzzer.c \
|
||||
$(TOP)\ext\misc\ieee754.c \
|
||||
|
||||
@@ -183,7 +183,7 @@ static int isVowel(const char *z){
|
||||
** by a consonant.
|
||||
**
|
||||
** In this routine z[] is in reverse order. So we are really looking
|
||||
** for an instance of of a consonant followed by a vowel.
|
||||
** for an instance of a consonant followed by a vowel.
|
||||
*/
|
||||
static int m_gt_0(const char *z){
|
||||
while( isVowel(z) ){ z++; }
|
||||
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
** 2014-11-10
|
||||
**
|
||||
** 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 SQLite extension implements SQL function eval() which runs
|
||||
** SQL statements recursively.
|
||||
*/
|
||||
#include "sqlite3ext.h"
|
||||
SQLITE_EXTENSION_INIT1
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
** Structure used to accumulate the output
|
||||
*/
|
||||
struct EvalResult {
|
||||
char *z; /* Accumulated output */
|
||||
const char *zSep; /* Separator */
|
||||
int szSep; /* Size of the separator string */
|
||||
sqlite3_int64 nAlloc; /* Number of bytes allocated for z[] */
|
||||
sqlite3_int64 nUsed; /* Number of bytes of z[] actually used */
|
||||
};
|
||||
|
||||
/*
|
||||
** Callback from sqlite_exec() for the eval() function.
|
||||
*/
|
||||
static int callback(void *pCtx, int argc, char **argv, char **colnames){
|
||||
struct EvalResult *p = (struct EvalResult*)pCtx;
|
||||
int i;
|
||||
for(i=0; i<argc; i++){
|
||||
const char *z = argv[i] ? argv[i] : "";
|
||||
size_t sz = strlen(z);
|
||||
if( (sqlite3_int64)sz+p->nUsed+p->szSep+1 > p->nAlloc ){
|
||||
char *zNew;
|
||||
p->nAlloc = p->nAlloc*2 + sz + p->szSep + 1;
|
||||
/* Using sqlite3_realloc64() would be better, but it is a recent
|
||||
** addition and will cause a segfault if loaded by an older version
|
||||
** of SQLite. */
|
||||
zNew = p->nAlloc<=0x7fffffff ? sqlite3_realloc(p->z, (int)p->nAlloc) : 0;
|
||||
if( zNew==0 ){
|
||||
sqlite3_free(p->z);
|
||||
memset(p, 0, sizeof(*p));
|
||||
return 1;
|
||||
}
|
||||
p->z = zNew;
|
||||
}
|
||||
if( p->nUsed>0 ){
|
||||
memcpy(&p->z[p->nUsed], p->zSep, p->szSep);
|
||||
p->nUsed += p->szSep;
|
||||
}
|
||||
memcpy(&p->z[p->nUsed], z, sz);
|
||||
p->nUsed += sz;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the eval(X) and eval(X,Y) SQL functions.
|
||||
**
|
||||
** Evaluate the SQL text in X. Return the results, using string
|
||||
** Y as the separator. If Y is omitted, use a single space character.
|
||||
*/
|
||||
static void sqlEvalFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
const char *zSql;
|
||||
sqlite3 *db;
|
||||
char *zErr = 0;
|
||||
int rc;
|
||||
struct EvalResult x;
|
||||
|
||||
memset(&x, 0, sizeof(x));
|
||||
x.zSep = " ";
|
||||
zSql = (const char*)sqlite3_value_text(argv[0]);
|
||||
if( zSql==0 ) return;
|
||||
if( argc>1 ){
|
||||
x.zSep = (const char*)sqlite3_value_text(argv[1]);
|
||||
if( x.zSep==0 ) return;
|
||||
}
|
||||
x.szSep = (int)strlen(x.zSep);
|
||||
db = sqlite3_context_db_handle(context);
|
||||
rc = sqlite3_exec(db, zSql, callback, &x, &zErr);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqlite3_result_error(context, zErr, -1);
|
||||
sqlite3_free(zErr);
|
||||
}else if( x.zSep==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
sqlite3_free(x.z);
|
||||
}else{
|
||||
sqlite3_result_text(context, x.z, (int)x.nUsed, sqlite3_free);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
int sqlite3_eval_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, "eval", 1, SQLITE_UTF8, 0,
|
||||
sqlEvalFunc, 0, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0,
|
||||
sqlEvalFunc, 0, 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -246,6 +246,7 @@ TESTSRC = \
|
||||
$(TOP)/src/test_autoext.c \
|
||||
$(TOP)/src/test_async.c \
|
||||
$(TOP)/src/test_backup.c \
|
||||
$(TOP)/src/test_blob.c \
|
||||
$(TOP)/src/test_btree.c \
|
||||
$(TOP)/src/test_config.c \
|
||||
$(TOP)/src/test_demovfs.c \
|
||||
@@ -280,6 +281,7 @@ TESTSRC = \
|
||||
TESTSRC += \
|
||||
$(TOP)/ext/misc/amatch.c \
|
||||
$(TOP)/ext/misc/closure.c \
|
||||
$(TOP)/ext/misc/eval.c \
|
||||
$(TOP)/ext/misc/fileio.c \
|
||||
$(TOP)/ext/misc/fuzzer.c \
|
||||
$(TOP)/ext/misc/ieee754.c \
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
C Further\simprovements\sto\sthe\s".scanstats\son"\sdisplay\sin\sthe\sshell.\s\sBe\ssure\nto\sshow\sthe\sresults\sof\sall\ssubqueries\seven\sif\sthere\sare\sgaps\sin\sthe\s\nSELECTID\svalues.\s\sAdd\s".scanstats"\sto\sthe\s".help"\soutput.
|
||||
D 2014-11-06T12:46:16.708
|
||||
C Add\scode\sto\scheck\sthe\svalidity\sof\sCollSeq\sobjects\sduring\sruntime.\s\sThis\scode\nwas\snot\sable\sto\sdetect\sanomalies\ssuch\sas\scame\sup\sas\sa\sresult\sof\nticket\s[e4a18565a36884b00edf66541f38c693827968ab]\sso\sit\sis\sput\sinto\sa\sbranch\nfor\shistorical\sreference,\swith\sthe\sintent\sof\sleaving\sit\sout\sof\strunk.
|
||||
D 2014-12-05T14:36:15.903
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in cf57f673d77606ab0f2d9627ca52a9ba1464146a
|
||||
F Makefile.in 6c4f961fa91d0b4fa121946a19f9e5eac2f2f809
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
F Makefile.msc e31dee24038965fb6269d6d61073fd6b7e331dec
|
||||
F Makefile.msc 10720782f88648bf2b5dcedf4c1524b067d43e47
|
||||
F Makefile.vxworks 034289efa9d591b04b1a73598623119c306cbba0
|
||||
F README.md 64f270c43c38c46de749e419c22f0ae2f4499fe8
|
||||
F VERSION d846487aff892625eb8e75960234e7285f0462fe
|
||||
@@ -86,7 +86,7 @@ F ext/fts3/fts3_expr.c 40123785eaa3ebd4c45c9b23407cc44ac0c49905
|
||||
F ext/fts3/fts3_hash.c 29b986e43f4e9dd40110eafa377dc0d63c422c60
|
||||
F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf
|
||||
F ext/fts3/fts3_icu.c e319e108661147bcca8dd511cd562f33a1ba81b5
|
||||
F ext/fts3/fts3_porter.c 7f8b4bf5af7c0f20f73b8e87e14fa9298f52e290
|
||||
F ext/fts3/fts3_porter.c 3565faf04b626cddf85f03825e86056a4562c009
|
||||
F ext/fts3/fts3_snippet.c 51beb5c1498176fd9caccaf1c75b55cb803a985a
|
||||
F ext/fts3/fts3_term.c a521f75132f9a495bdca1bdd45949b3191c52763
|
||||
F ext/fts3/fts3_test.c 8a3a78c4458b2d7c631fcf4b152a5cd656fa7038
|
||||
@@ -109,6 +109,7 @@ F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
|
||||
F ext/misc/amatch.c 678056a4bfcd83c4e82dea81d37543cd1d6dbee1
|
||||
F ext/misc/closure.c 636024302cde41b2bf0c542f81c40c624cfb7012
|
||||
F ext/misc/compress.c 76e45655f4046e756064ab10c62e18f2eb846b9f
|
||||
F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2
|
||||
F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f
|
||||
F ext/misc/fuzzer.c 136533c53cfce0957f0b48fa11dba27e21c5c01d
|
||||
F ext/misc/ieee754.c b0362167289170627659e84173f5d2e8fee8566e
|
||||
@@ -151,7 +152,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e
|
||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||
F main.mk bbc8b6000ed143a1a8d31d3b4995c359a3188fa1
|
||||
F main.mk 084976077a4aa3bd985154b5423e7aed88e4a2e9
|
||||
F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
|
||||
F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5
|
||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||
@@ -166,26 +167,26 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
|
||||
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
|
||||
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
|
||||
F src/alter.c ba266a779bc7ce10e52e59e7d3dc79fa342e8fdb
|
||||
F src/analyze.c afbcca663c3f3625340b8e30d440cd7a97ded6bc
|
||||
F src/analyze.c f7d774356ba5a14e7ad4fb637681af16875ad88f
|
||||
F src/attach.c f4e94df2d1826feda65eb0939f7f6f5f923a0ad9
|
||||
F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
|
||||
F src/backup.c 7f841396adfd47507ff670a471162d2bfcda3136
|
||||
F src/backup.c 7ddee9c7d505e07e959a575b18498f17c71e53ea
|
||||
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
|
||||
F src/btmutex.c 49ca66250c7dfa844a4d4cb8272b87420d27d3a5
|
||||
F src/btree.c 4a126e2066076872ab6f37f9ad116eb5f651cd38
|
||||
F src/btree.h 49b408be9c1cd41249076898e0673711071205d8
|
||||
F src/btreeInt.h 026d0129724e8f265fdc60d44ec240cf5a4e6179
|
||||
F src/btree.c 44b58cd798a32579816ce274e415de262df9843d
|
||||
F src/btree.h e31a3a3ebdedb1caf9bda3ad5dbab3db9b780f6e
|
||||
F src/btreeInt.h 3363e18fd76f69a27a870b25221b2345b3fd4d21
|
||||
F src/build.c 67bb05b1077e0cdaccb2e36bfcbe7a5df9ed31e8
|
||||
F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0
|
||||
F src/callback.c 759c9aff944f72fd7fb810594d95af1092a8433a
|
||||
F src/complete.c c4ba6e0626bb94bc77a0861735f3382fcf7cc818
|
||||
F src/ctime.c df19848891c8a553c80e6f5a035e768280952d1a
|
||||
F src/date.c 57a7f9ba9f6b4d5268f5e411739066a611f99036
|
||||
F src/date.c 93594514aae68de117ca4a2a0d6cc63eddf26744
|
||||
F src/delete.c 0750b1eb4d96cd3fb2c798599a3a7c85e92f1417
|
||||
F src/expr.c 0391a657df4959eaf2a2fd7d77de5ebe750686ee
|
||||
F src/expr.c 00da3072f362b06f39ce4052baa1d4ce2bb36d1c
|
||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||
F src/fkey.c da985ae673efef2c712caef825a5d2edb087ead7
|
||||
F src/func.c ba47c1671ab3cfdafa6e9d6ee490939ea578adee
|
||||
F src/global.c a50ad0b9ee328107a65aa8f5f3cd34905e74745c
|
||||
F src/func.c 6d3c4ebd72aa7923ce9b110a7dc15f9b8c548430
|
||||
F src/global.c 6ded36dda9466fc1c9a3c5492ded81d79bf3977d
|
||||
F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5
|
||||
F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094
|
||||
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
|
||||
@@ -194,7 +195,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
|
||||
F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e
|
||||
F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770
|
||||
F src/loadext.c de741e66e5ddc1598d904d7289239696e40ed994
|
||||
F src/main.c 42f857be3cef3e1f9752d8e46d61345f80932396
|
||||
F src/main.c fa9f0e511a64caf66b8e7bb835c55172e7d61527
|
||||
F src/malloc.c 740db54387204c9a2eb67c6d98e68b08e9ef4eab
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c faf615aafd8be74a71494dfa027c113ea5c6615f
|
||||
@@ -215,29 +216,29 @@ F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
|
||||
F src/os_unix.c fb587121840f690101336879adfa6d0b2cd0e8c7
|
||||
F src/os_win.c a9e500dd963fb1f67d7860e58b5772abe6123862
|
||||
F src/os_win.h 09e751b20bbc107ffbd46e13555dc73576d88e21
|
||||
F src/pager.c 8d97b3633f098fef817656dcbf167ca904511d78
|
||||
F src/pager.c 7a5c5bc0e29b9b16834f5558a9d5d22bbae59a08
|
||||
F src/pager.h d1eee3c3f741be247ce6d82752a178515fc8578b
|
||||
F src/parse.y 5dfead8aed90cb0c7c1115898ee2266804daff45
|
||||
F src/pcache.c ace1b67632deeaa84859b4c16c27711dfb7db3d4
|
||||
F src/pcache.h b44658c9c932d203510279439d891a2a83e12ba8
|
||||
F src/pcache1.c facbdd3ecc09c8f750089d941305694301328e98
|
||||
F src/pragma.c 3f3e959390a10c0131676f0e307acce372777e0f
|
||||
F src/pragma.c d54cdd40b63d608f2d95b7482c710690e3593a73
|
||||
F src/prepare.c b7b7bf020bd4c962f7c8aed5a3c542c7dfe9f9c7
|
||||
F src/printf.c 9e75a6a0b55bf61cfff7d7e19d89834a1b938236
|
||||
F src/random.c ba2679f80ec82c4190062d756f22d0c358180696
|
||||
F src/resolve.c 4965007d6497b6a4d7a6d98751cc39712885f952
|
||||
F src/resolve.c f6c46d3434439ab2084618d603e6d6dbeb0d6ada
|
||||
F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e
|
||||
F src/select.c 428165951748151e87a15295b7357221433e311b
|
||||
F src/shell.c 48fe276aada42a15722aee2584e6321345ed4609
|
||||
F src/sqlite.h.in 087d30a4c7ec7ae19bcaa03a9db9d6ee7a73b0b3
|
||||
F src/select.c f377fb8a5c73c10678ea74f3400f7913943e3d75
|
||||
F src/shell.c 45d9c9bd7cde07845af957f2d849933b990773cf
|
||||
F src/sqlite.h.in 6ec654324cb490ea3d8a7be28b8c7d37fe4ad282
|
||||
F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad
|
||||
F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d
|
||||
F src/sqliteInt.h 8f67ca79e957b8ece7453b8e320b6a996e1b4761
|
||||
F src/sqliteInt.h ef42a0515a846ab2a670bda705be494d7acc2535
|
||||
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
|
||||
F src/status.c 81712116e826b0089bb221b018929536b2b5406f
|
||||
F src/table.c f142bba7903e93ca8d113a5b8877a108ad1a27dc
|
||||
F src/tclsqlite.c 7cdd4dd3c2a4183483feca260070d73d6e22cd47
|
||||
F src/test1.c ac7f3bad83ef4508d5efc85b32e86da48db8ed7e
|
||||
F src/tclsqlite.c 0a874655dd39a9875e39c5d3c464db662171d228
|
||||
F src/test1.c c24d7f67252348d756773a6dbe23a61b4552f709
|
||||
F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712
|
||||
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
|
||||
F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df
|
||||
@@ -249,8 +250,9 @@ F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
|
||||
F src/test_async.c 21e11293a2f72080eda70e1124e9102044531cd8
|
||||
F src/test_autoext.c dea8a01a7153b9adc97bd26161e4226329546e12
|
||||
F src/test_backup.c 3875e899222b651e18b662f86e0e50daa946344e
|
||||
F src/test_blob.c 1f2e3e25255b731c4fcf15ee7990d06347cb6c09
|
||||
F src/test_btree.c 2e9978eca99a9a4bfa8cae949efb00886860a64f
|
||||
F src/test_config.c c8b8b50bf2fe5102de10e4c7100b746d7f6bf62f
|
||||
F src/test_config.c 035c17a173937d019b8dfc1d524f9d3fc8123504
|
||||
F src/test_demovfs.c 69b2085076654ebc18014cbc6386f04409c959a9
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
F src/test_fs.c ced436e3d4b8e4681328409b8081051ce614e28f
|
||||
@@ -288,21 +290,21 @@ F src/trigger.c 25571661fdeae8c7f975ff40ffec205520a3f92f
|
||||
F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13
|
||||
F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c
|
||||
F src/util.c 3b627daa45c7308c1e36e3dbaa3f9ce7e5c7fa73
|
||||
F src/vacuum.c 59f03f92bcff57faa6a8ca256eb29ccddfb0614a
|
||||
F src/vdbe.c 3fd4ebd3e87b63175bfd2be747608bae1670b4df
|
||||
F src/vacuum.c 9b30ec729337dd012ed88d4c292922c8ef9cf00c
|
||||
F src/vdbe.c 1a9e671c9cfc259e4d2affc71f7df4a4c00a842c
|
||||
F src/vdbe.h 6fc69d9c5e146302c56e163cb4b31d1ee64a18c3
|
||||
F src/vdbeInt.h 9bb69ff2447c34b6ccc58b34ec35b615f86ead78
|
||||
F src/vdbeapi.c 07acb615d1e4170e71fc1b0d087f3c53a1ad8e83
|
||||
F src/vdbeaux.c 9b0a251b6dfab349dd6c6efb40062eb7386b26f5
|
||||
F src/vdbeblob.c 8b5442ff0954c44b45cbabbe2e94091a2e16fdef
|
||||
F src/vdbeaux.c 7e0a097ac7cf716300128f18147ef9af7c9d1130
|
||||
F src/vdbeblob.c 4af4bfb71f6df7778397b4a0ebc1879793276778
|
||||
F src/vdbemem.c 31d8eabb0cd78bfeab4e5124c7363c3e9e54db9f
|
||||
F src/vdbesort.c 87f3923483113d1c95d84640becb4e4946f27d9a
|
||||
F src/vdbesort.c 42c166f7ca78cb643c7f4e4bdfa83c59d363d1a6
|
||||
F src/vdbetrace.c 7e4222955e07dd707a2f360c0eb73452be1cb010
|
||||
F src/vtab.c 2a30791bbd7926b589401bd09c3abb33de563793
|
||||
F src/wal.c 825c948066c7604a07d56e67958cdab210749016
|
||||
F src/vtab.c c08ec66f45919eaa726bf88aa53eb08379d607f9
|
||||
F src/wal.c 847692349eb6e1fb8543dbc97e69ddbfa4cc7ea7
|
||||
F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4
|
||||
F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804
|
||||
F src/where.c 3862a1173ae2716bde12f1ab3fb649f1d85b05c2
|
||||
F src/where.c d67fe69dd1bb32ad3d488a8c5bc803a29814f357
|
||||
F src/whereInt.h d3633e9b592103241b74b0ec76185f3e5b8b62e0
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
|
||||
@@ -344,16 +346,17 @@ F test/auth2.test 264c6af53cad9aba5218c68bbe18036e39007bfa
|
||||
F test/auth3.test 5cfa94ed90c6617c42b7ba4b133fd79678b251c7
|
||||
F test/autoinc.test c58912526998a39e11f66b533e23cfabea7f25b7
|
||||
F test/autoindex1.test 6ff78b94f43a59616c06c11c55b12935173506d7
|
||||
F test/autoindex2.test 60d2fc6f38364308ce73a9beb01b47ded38697de
|
||||
F test/autoindex3.test 8254f689c3241081fad52b7bea18ba53e07e14a2
|
||||
F test/autoindex2.test af7e595c6864cc6ef5fc38d5db579a3e34940cb8
|
||||
F test/autoindex3.test a3be0d1a53a7d2edff208a5e442312957047e972
|
||||
F test/autoindex4.test fc807f9efd158bec60f5dfdf34ebe46fb274612d
|
||||
F test/autovacuum.test 941892505d2c0f410a0cb5970dfa1c7c4e5f6e74
|
||||
F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4
|
||||
F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85
|
||||
F test/backcompat.test 19a1f337c68419b020a7481dd272a472c4ad8ef4
|
||||
F test/backup.test c9cdd23a495864b9edf75a9fa66f5cb7e10fcf62
|
||||
F test/backup.test b79299a536a4c6d919094786595b95be56d02014
|
||||
F test/backup2.test 34986ef926ea522911a51dfdb2f8e99b7b75ebcf
|
||||
F test/backup4.test 2a2e4a64388090b152de753fd9e123f28f6a3bd4
|
||||
F test/backup5.test ee5da6d7fe5082f5b9b0bbfa31d016f52412a2e4
|
||||
F test/backup_ioerr.test 4c3c7147cee85b024ecf6e150e090c32fdbb5135
|
||||
F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450
|
||||
F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f
|
||||
@@ -363,6 +366,7 @@ F test/between.test 34d375fb5ce1ae283ffe82b6b233e9f38e84fc6c
|
||||
F test/bigfile.test aa74f4e5db51c8e54a1d9de9fa65d01d1eb20b59
|
||||
F test/bigfile2.test 1b489a3a39ae90c7f027b79110d6b4e1dbc71bfc
|
||||
F test/bigrow.test f0aeb7573dcb8caaafea76454be3ade29b7fc747
|
||||
F test/bigsort.test 835478d0ce83bd1e5b05c90571dedd9871a09196
|
||||
F test/bind.test 3c7b320969000c441a70952b0b15938fbb66237c
|
||||
F test/bindxfer.test efecd12c580c14df5f4ad3b3e83c667744a4f7e0
|
||||
F test/bitvec.test 75894a880520164d73b1305c1c3f96882615e142
|
||||
@@ -375,14 +379,15 @@ F test/boundary3.tcl 23361e108a125dca9c4080c2feb884fe54d69243
|
||||
F test/boundary3.test 56ef82096b4329aca2be74fa1e2b0f762ea0eb45
|
||||
F test/boundary4.tcl 0bb4b1a94f4fc5ae59b79b9a2b7a140c405e2983
|
||||
F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b
|
||||
F test/btree01.test e08b3613540145b353f20c81cb18ead54ff12e0f
|
||||
F test/btreefault.test c2bcb542685eea44621275cfedbd8a13f65201e3
|
||||
F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
|
||||
F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de
|
||||
F test/capi2.test 011c16da245fdc0106a2785035de6b242c05e738
|
||||
F test/capi3.test 71bcf2fbd36a9732f617766dfd752552c8e491b5
|
||||
F test/capi3.test f0718f4f90d0efdc980119bfbdf1d7f1541ee5ef
|
||||
F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
|
||||
F test/capi3c.test a21869e4d50d5dbb7e566e328fc0bc7c2efa6a32
|
||||
F test/capi3d.test c84af0c49267f9c3fbf4c1c46aa647646023811e
|
||||
F test/capi3c.test fdc0d67a2cb8e8fc400d5b7735e330161ea057a2
|
||||
F test/capi3d.test a82b6321c50a1cfc848e386fa2c851893606f68c
|
||||
F test/capi3e.test 3d49c01ef2a1a55f41d73cba2b23b5059ec460fe
|
||||
F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3
|
||||
F test/check.test 5831ddb6f2c687782eaf2e1a07b6e17f24c4f763
|
||||
@@ -421,7 +426,7 @@ F test/corruptD.test b3c205fac7952b1de645ce44bb02335cd9e3e040
|
||||
F test/corruptE.test 193b4ca4e927e77c1d5f4f56203ddc998432a7ee
|
||||
F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4
|
||||
F test/corruptG.test 1ab3bf97ee7bdba70e0ff3ba2320657df55d1804
|
||||
F test/corruptH.test 88ed71a086e13591c917aac6de32750e7c7281cb
|
||||
F test/corruptH.test 5dd4fa98c6c1ed33b178f9e8a48c4fdd3cfc9067
|
||||
F test/corruptI.test 221ad8b7f0a9ac6b80fc577e73b5ad8cdea31243
|
||||
F test/cost.test 19d314526616ce4473eb4e4e450fcb94499ce318
|
||||
F test/count.test 42a251178e32f617eda33f76236a7f79825a50b5
|
||||
@@ -449,8 +454,12 @@ F test/descidx1.test 6d03b44c8538fe0eb4924e19fba10cdd8f3c9240
|
||||
F test/descidx2.test 9f1a0c83fd57f8667c82310ca21b30a350888b5d
|
||||
F test/descidx3.test 09ddbe3f5295f482d2f8b687cf6db8bad7acd9a2
|
||||
F test/diskfull.test 106391384780753ea6896b7b4f005d10e9866b6e
|
||||
F test/distinct.test 086e70c765f172e8974e9f83b9ac5ca03c154e77
|
||||
F test/distinct.test 175d49ee783febaf368192dfe7f5afbc68910230
|
||||
F test/distinctagg.test 1a6ef9c87a58669438fc771450d7a72577417376
|
||||
F test/e_blobbytes.test 9bea1d3e2b20f3010b04abba58f6ba172301f49f
|
||||
F test/e_blobclose.test df756753f571bc30e42e3a6cba2807576e49e716
|
||||
F test/e_blobopen.test 234f960d90235a9b51ec3ca1e062e8541dd558d8
|
||||
F test/e_blobwrite.test 615b405f29feb2cfb5a1f03dab7933258294fa26
|
||||
F test/e_changes.test fd66105385153dbf21fdb35eb8ef6c3e1eade579
|
||||
F test/e_createtable.test c7e67b49e6cf92473c8fb30ab26143e9e2128cf7
|
||||
F test/e_delete.test d5186e2f5478b659f16a2c8b66c09892823e542a
|
||||
@@ -491,7 +500,7 @@ F test/fkey3.test 76d475c80b84ee7a5d062e56ccb6ea68882e2b49
|
||||
F test/fkey4.test 86446017011273aad8f9a99c1a65019e7bd9ca9d
|
||||
F test/fkey5.test 8a1fde4e7721ae00b05b3178888833726ca2df8d
|
||||
F test/fkey6.test abb59f866c1b44926fd02d1fdd217d831fe04f48
|
||||
F test/fkey7.test e31d0e71a41c1d29349a16448d6c420e2c53a8fc
|
||||
F test/fkey7.test 72e915890ee4a005daaf3002cb208e8fe973ac13
|
||||
F test/fkey_malloc.test 594a7ea1fbab553c036c70813cd8bd9407d63749
|
||||
F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb
|
||||
F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c
|
||||
@@ -620,7 +629,7 @@ F test/in.test 047c4671328e9032ab95666a67021adbbd36e98e
|
||||
F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
|
||||
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
|
||||
F test/in4.test d2b38cba404bc4320f4fe1b595b3d163f212c068
|
||||
F test/in5.test 99f9a40af01711b06d2d614ecfe96129f334fba3
|
||||
F test/in5.test 1de657472fa9ac2924be25c2c959ac5ca1aae554
|
||||
F test/incrblob.test e81846d214f3637622620fbde7cd526781cfe328
|
||||
F test/incrblob2.test bf4d549aa4a466d7fbe3e3a3693d3861263d5600
|
||||
F test/incrblob3.test d8d036fde015d4a159cd3cbae9d29003b37227a4
|
||||
@@ -652,7 +661,7 @@ F test/interrupt.test dfe9a67a94b0b2d8f70545ba1a6cca10780d71cc
|
||||
F test/intpkey.test 7506090fc08e028712a8bf47e5f54111947e3844
|
||||
F test/io.test 3a7abcef18727cc0f2399e04b0e8903eccae50f8
|
||||
F test/ioerr.test 2a24bd6ed5a8b062e64bfe1f6cf94fb25e92210d
|
||||
F test/ioerr2.test 9d71166f8466eda510f1af6137bdabaa82b5408d
|
||||
F test/ioerr2.test 2593563599e2cc6b6b4fcf5878b177bdd5d8df26
|
||||
F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd
|
||||
F test/ioerr4.test f130fe9e71008577b342b8874d52984bd04ede2c
|
||||
F test/ioerr5.test 2edfa4fb0f896f733071303b42224df8bedd9da4
|
||||
@@ -661,7 +670,7 @@ F test/join.test 52d4d49f86d0cf46926672878c4eaf0da399104a
|
||||
F test/join2.test f2171c265e57ee298a27e57e7051d22962f9f324
|
||||
F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0
|
||||
F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
|
||||
F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe
|
||||
F test/join5.test 5df23eba184f159ed9705a954957e765a10c141d
|
||||
F test/join6.test cfe6503791ceb0cbb509966740286ec423cbf10b
|
||||
F test/journal1.test 69abc726c51b4a0409189f9a85191205297c0577
|
||||
F test/journal2.test ae06f566c28552c313ded3fee79a6c69e6d049b1
|
||||
@@ -727,6 +736,7 @@ F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6
|
||||
F test/misc5.test 528468b26d03303b1f047146e5eefc941b9069f5
|
||||
F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
|
||||
F test/misc7.test edd0b63e2ee29a256900b0514f6fff27e19e9bb2
|
||||
F test/misc8.test fc2754d38892f7dac30c22db3616c2764f117d66
|
||||
F test/misuse.test 3c34719944ba045cc6c188a4852ba04680728912
|
||||
F test/mmap1.test 1bfd611b9841eafb44f7d83c0788e146d84a33c9
|
||||
F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022
|
||||
@@ -768,8 +778,8 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
|
||||
F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d
|
||||
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
|
||||
F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54
|
||||
F test/permutations.test cef25f5e8499a15846eccd06785f17f4180407ab
|
||||
F test/pragma.test 19d0241a007bcdd77fc2606ec60fc60357e7fc8b
|
||||
F test/permutations.test 4e12d43f4639ea8a0e366d9c64e0009afe2eb544
|
||||
F test/pragma.test 49ac8a73c0daa574824538fed28727d1259fe735
|
||||
F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13
|
||||
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
|
||||
F test/printf2.test b4acd4bf8734243257f01ddefa17c4fb090acc8a
|
||||
@@ -789,19 +799,21 @@ F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
|
||||
F test/releasetest.mk 2eced2f9ae701fd0a29e714a241760503ccba25a
|
||||
F test/releasetest.tcl a4279c890698584feb2ffc86735857a4e4474180
|
||||
F test/resolver01.test 33abf37ff8335e6bf98f2b45a0af3e06996ccd9a
|
||||
F test/rollback.test e9504a009a202c3ed711da2e6879ff60c5a4669c
|
||||
F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea
|
||||
F test/rollback2.test fc14cf6d1a2b250d2735ef16124b971bce152f14
|
||||
F test/rollbackfault.test 6a004f71087cc399296cffbb5429ea6da655ae65
|
||||
F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
|
||||
F test/rowid.test 742b5741584a8a44fd83e856cc2896688401d645
|
||||
F test/rtree.test 0c8d9dd458d6824e59683c19ab2ffa9ef946f798
|
||||
F test/run-wordcount.sh 891e89c4c2d16e629cd45951d4ed899ad12afc09
|
||||
F test/savepoint.test 51d3900dc071a7c2ad4248578a5925631b476313
|
||||
F test/savepoint.test c671fdbd34cd3bfe1518a777526ada595180cf8d
|
||||
F test/savepoint2.test 9b8543940572a2f01a18298c3135ad0c9f4f67d7
|
||||
F test/savepoint3.test e328085853b14898d78ceea00dfe7db18bb6a9ec
|
||||
F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0
|
||||
F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd
|
||||
F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7
|
||||
F test/savepoint7.test fbf319a7b2dda089ec5be30a424a0e95f121d423
|
||||
F test/scanstatus.test a6dd739bc4d9638e8f5c2493b518057f2b681655
|
||||
F test/savepoint7.test db3db281486c925095f305aad09fe806e5188ff3
|
||||
F test/scanstatus.test 5253c219e331318a437f436268e0e82345700285
|
||||
F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481
|
||||
F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5
|
||||
F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38
|
||||
@@ -834,10 +846,11 @@ F test/shared7.test a81e99f83e6c51b02ac99c96fb3a2a7b5978c956
|
||||
F test/shared8.test 00a07bf5e1337ecf72e94542bdefdc330d7a2538
|
||||
F test/shared9.test 5f2a8f79b4d6c7d107a01ffa1ed05ae7e6333e21
|
||||
F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5
|
||||
F test/shared_err.test 0079c05c97d88cfa03989b7c20a8b266983087aa
|
||||
F test/sharedB.test 16cc7178e20965d75278f410943109b77b2e645e
|
||||
F test/shared_err.test 2f2aee20db294b9924e81f6ccbe60f19e21e8506
|
||||
F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304
|
||||
F test/shell1.test d60946b5fde4d85fe06db7331dfe89011f564350
|
||||
F test/shell2.test c57da3a381c099b02c813ba156298d5c2f5c93a3
|
||||
F test/shell1.test ab6025d941f9c84c5b83412c6b4d8b57f78dfa3a
|
||||
F test/shell2.test 12b8bf901b0e3a8ac58cf5c0c63a0a388d4d1862
|
||||
F test/shell3.test 5e8545ec72c4413a0e8d4c6be56496e3c257ca29
|
||||
F test/shell4.test 8a9c08976291e6c6c808b4d718f4a8b299f339f5
|
||||
F test/shell5.test 15a419cc1df21c892ed64f5596ae7a501f2816f2
|
||||
@@ -845,7 +858,7 @@ F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3
|
||||
F test/show_speedtest1_rtree.tcl 32e6c5f073d7426148a6936a0408f4b5b169aba5
|
||||
F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868
|
||||
F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329
|
||||
F test/skipscan1.test 7e15e1cc524524e7b2c4595ec85c75501d22f4ff
|
||||
F test/skipscan1.test 2ddfe5d168462170c4487f534e2a99fb006b2076
|
||||
F test/skipscan2.test d1d1450952b7275f0b0a3a981f0230532743951a
|
||||
F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5
|
||||
F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2
|
||||
@@ -853,7 +866,7 @@ F test/skipscan6.test 5866039d03a56f5bd0b3d172a012074a1d90a15b
|
||||
F test/soak.test 0b5b6375c9f4110c828070b826b3b4b0bb65cd5f
|
||||
F test/softheap1.test 40562fe6cac6d9827b7b42b86d45aedf12c15e24
|
||||
F test/sort.test c4400e7533748f6bd7413851ff148645e82b9e2d
|
||||
F test/sort2.test 269f4f50c6e468cc32b302ae7ff0add8338ec6de
|
||||
F test/sort2.test 84a92eebf697feee9c6697746918c7d67373eea1
|
||||
F test/sort3.test 6178ade30810ac9166fcdf14b7065e49c0f534e2
|
||||
F test/sort4.test 6c37d85f7cd28d50cce222fcab84ccd771e105cb
|
||||
F test/sort5.test a448240a42b49239edc00f85d6d7ac7a1b261e1f
|
||||
@@ -949,7 +962,7 @@ F test/tkt-d635236375.test 9d37e988b47d87505bc9445be0ca447002df5d09
|
||||
F test/tkt-d82e3f3721.test bcc0dfba658d15bab30fd4a9320c9e35d214ce30
|
||||
F test/tkt-f3e5abed55.test d5a0126118142d13e27f6ce9f4c47096e9321c00
|
||||
F test/tkt-f67b41381a.test a23bc124c981662db712167bacd0ed8ad11abac9
|
||||
F test/tkt-f777251dc7a.test af6531446c64bfd268416f07b4df7be7f9c749d2
|
||||
F test/tkt-f777251dc7a.test d1a8fc3eefb7a9e64d19ff24d5c8c94c34a632fb
|
||||
F test/tkt-f7b4edec.test d998a08ff2b18b7f62edce8e3044317c45efe6c7
|
||||
F test/tkt-f973c7ac31.test 28ef85c7f015477916795246d8286aeda39d4ead
|
||||
F test/tkt-fa7bf5ec.test 9102dfea58aa371d78969da735f9392c57e2e035
|
||||
@@ -1044,7 +1057,7 @@ F test/trace.test 73a5508100f7fccfbc3f8018d5f6963ed478eea0
|
||||
F test/trace2.test 93b47ca6996c66b47f57224cfb146f34e07df382
|
||||
F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6
|
||||
F test/trans2.test 62bd045bfc7a1c14c5ba83ba64d21ade31583f76
|
||||
F test/trans3.test 373ac5183cc56be69f48ae44090e7f672939f732
|
||||
F test/trans3.test 91a100e5412b488e22a655fe423a14c26403ab94
|
||||
F test/transitive1.test 03f532954f46cdf5608f7766bff0b0c52bf2a7cd
|
||||
F test/trigger1.test dc47573ac79ffe0ee3eecaa517d70d8dacbccd03
|
||||
F test/trigger2.test 5cd7d69a7ba1143ee045e4ae2963ff32ae4c87a6
|
||||
@@ -1079,7 +1092,7 @@ F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9
|
||||
F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
|
||||
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
|
||||
F test/view.test f311691d696a5cc27e3c1b875cec1b0866b4ccd9
|
||||
F test/vtab1.test b631d147b198cfd7903ab5fed028eb2a3d321dc6
|
||||
F test/vtab1.test 1cef14310144718812351a61c5cfb4ba8494a171
|
||||
F test/vtab2.test 7bcffc050da5c68f4f312e49e443063e2d391c0d
|
||||
F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e
|
||||
F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275
|
||||
@@ -1101,7 +1114,7 @@ F test/wal.test 885f32b2b390b30b4aa3dbb0e568f8f78d40f5cc
|
||||
F test/wal2.test 1f841d2048080d32f552942e333fd99ce541dada
|
||||
F test/wal3.test b22eb662bcbc148c5f6d956eaf94b047f7afe9c0
|
||||
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
|
||||
F test/wal5.test 8f888b50f66b78821e61ed0e233ded5de378224b
|
||||
F test/wal5.test 174cc1512e304a7dfa28ac30527e28ea02fc37df
|
||||
F test/wal6.test 527581f5527bf9c24394991e2be83000aace5f9e
|
||||
F test/wal64k.test 163655ecd2cb8afef4737cac2a40fdd2eeaf20b8
|
||||
F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd
|
||||
@@ -1142,7 +1155,7 @@ F test/whereF.test 5b2ba0dbe8074aa13e416b37c753991f0a2492d7
|
||||
F test/whereG.test 69f5ec4b15760a8c860f80e2d55525669390aab3
|
||||
F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2
|
||||
F test/whereI.test 1d89199697919d4930be05a71e7fe620f114e622
|
||||
F test/whereJ.test 63599653dfefe4e74ebb358db753417fe0aa8a49
|
||||
F test/whereJ.test 55a3221706a7ab706293f17cc8f96da563bf0767
|
||||
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
|
||||
F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
|
||||
F test/win32heap.test ea19770974795cff26e11575e12d422dbd16893c
|
||||
@@ -1155,7 +1168,7 @@ F test/without_rowid1.test 7862e605753c8d25329f665fa09072e842183151
|
||||
F test/without_rowid2.test af260339f79d13cb220288b67cd287fbcf81ad99
|
||||
F test/without_rowid3.test 1081aabf60a1e1123b7f9a8f6ae19954351843b0
|
||||
F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a
|
||||
F test/without_rowid5.test b4a639a367f04d382d20e8f44fc1be4f2d57d107
|
||||
F test/without_rowid5.test 61256715b686359df48ca1742db50cc7e3e7b862
|
||||
F test/wordcount.c 9915e06cb33d8ca8109b8700791afe80d305afda
|
||||
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
|
||||
F test/zerodamage.test cf6748bad89553cc1632be51a6f54e487e4039ac
|
||||
@@ -1211,7 +1224,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
|
||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P d1c51c8455d5ce972a77720c2d56228646ced27c
|
||||
R 1f66f00948a1acda590c099646f9e3d3
|
||||
P 71f589e3f82a07513425e212072f32748c0732d4
|
||||
R 02b8ea23886487ef9860b5ee40d238ab
|
||||
T *branch * collseq-checking
|
||||
T *sym-collseq-checking *
|
||||
T -sym-fix-stale-keyinfo-cache *
|
||||
U drh
|
||||
Z 2bc412ec02d784f50574dd160207db0a
|
||||
Z 74adfe1c6f95aa3cd0aa6e2d3a771e07
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
ee922682bb7235dbcd23a22fcfdfa188f6d3228a
|
||||
68b23c3d41ce9303f42251d0c199181312e148f9
|
||||
+18
-13
@@ -1457,23 +1457,28 @@ static void decodeIntArray(
|
||||
if( *z==' ' ) z++;
|
||||
}
|
||||
#ifndef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
assert( pIndex!=0 );
|
||||
assert( pIndex!=0 ); {
|
||||
#else
|
||||
if( pIndex )
|
||||
if( pIndex ){
|
||||
#endif
|
||||
while( z[0] ){
|
||||
if( sqlite3_strglob("unordered*", z)==0 ){
|
||||
pIndex->bUnordered = 1;
|
||||
}else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){
|
||||
pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3));
|
||||
}
|
||||
pIndex->bUnordered = 0;
|
||||
pIndex->noSkipScan = 0;
|
||||
while( z[0] ){
|
||||
if( sqlite3_strglob("unordered*", z)==0 ){
|
||||
pIndex->bUnordered = 1;
|
||||
}else if( sqlite3_strglob("sz=[0-9]*", z)==0 ){
|
||||
pIndex->szIdxRow = sqlite3LogEst(sqlite3Atoi(z+3));
|
||||
}else if( sqlite3_strglob("noskipscan*", z)==0 ){
|
||||
pIndex->noSkipScan = 1;
|
||||
}
|
||||
#ifdef SQLITE_ENABLE_COSTMULT
|
||||
else if( sqlite3_strglob("costmult=[0-9]*",z)==0 ){
|
||||
pIndex->pTable->costMult = sqlite3LogEst(sqlite3Atoi(z+9));
|
||||
}
|
||||
else if( sqlite3_strglob("costmult=[0-9]*",z)==0 ){
|
||||
pIndex->pTable->costMult = sqlite3LogEst(sqlite3Atoi(z+9));
|
||||
}
|
||||
#endif
|
||||
while( z[0]!=0 && z[0]!=' ' ) z++;
|
||||
while( z[0]==' ' ) z++;
|
||||
while( z[0]!=0 && z[0]!=' ' ) z++;
|
||||
while( z[0]==' ' ) z++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+23
-6
@@ -122,6 +122,20 @@ static int setDestPgsz(sqlite3_backup *p){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check that there is no open read-transaction on the b-tree passed as the
|
||||
** second argument. If there is not, return SQLITE_OK. Otherwise, if there
|
||||
** is an open read-transaction, return SQLITE_ERROR and leave an error
|
||||
** message in database handle db.
|
||||
*/
|
||||
static int checkReadTransaction(sqlite3 *db, Btree *p){
|
||||
if( sqlite3BtreeIsInReadTrans(p) ){
|
||||
sqlite3ErrorWithMsg(db, SQLITE_ERROR, "destination database is in use");
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create an sqlite3_backup process to copy the contents of zSrcDb from
|
||||
** connection handle pSrcDb to zDestDb in pDestDb. If successful, return
|
||||
@@ -181,12 +195,15 @@ sqlite3_backup *sqlite3_backup_init(
|
||||
p->iNext = 1;
|
||||
p->isAttached = 0;
|
||||
|
||||
if( 0==p->pSrc || 0==p->pDest || setDestPgsz(p)==SQLITE_NOMEM ){
|
||||
if( 0==p->pSrc || 0==p->pDest
|
||||
|| setDestPgsz(p)==SQLITE_NOMEM
|
||||
|| checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK
|
||||
){
|
||||
/* One (or both) of the named databases did not exist or an OOM
|
||||
** error was hit. The error has already been written into the
|
||||
** pDestDb handle. All that is left to do here is free the
|
||||
** sqlite3_backup structure.
|
||||
*/
|
||||
** error was hit. Or there is a transaction open on the destination
|
||||
** database. The error has already been written into the pDestDb
|
||||
** handle. All that is left to do here is free the sqlite3_backup
|
||||
** structure. */
|
||||
sqlite3_free(p);
|
||||
p = 0;
|
||||
}
|
||||
@@ -607,7 +624,7 @@ int sqlite3_backup_finish(sqlite3_backup *p){
|
||||
}
|
||||
|
||||
/* If a transaction is still open on the Btree, roll it back. */
|
||||
sqlite3BtreeRollback(p->pDest, SQLITE_OK);
|
||||
sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0);
|
||||
|
||||
/* Set the error code of the destination database handle. */
|
||||
rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc;
|
||||
|
||||
+208
-61
@@ -1139,6 +1139,11 @@ static void ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell, int *pRC){
|
||||
** end of the page and all free space is collected into one
|
||||
** big FreeBlk that occurs in between the header and cell
|
||||
** pointer array and the cell content area.
|
||||
**
|
||||
** EVIDENCE-OF: R-44582-60138 SQLite may from time to time reorganize a
|
||||
** b-tree page so that there are no freeblocks or fragment bytes, all
|
||||
** unused bytes are contained in the unallocated space region, and all
|
||||
** cells are packed tightly at the end of the page.
|
||||
*/
|
||||
static int defragmentPage(MemPage *pPage){
|
||||
int i; /* Loop counter */
|
||||
@@ -1247,16 +1252,23 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc, int *pbDefrag){
|
||||
|
||||
for(iAddr=hdr+1; (pc = get2byte(&aData[iAddr]))>0; iAddr=pc){
|
||||
int size; /* Size of the free slot */
|
||||
/* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of
|
||||
** increasing offset. */
|
||||
if( pc>usableSize-4 || pc<iAddr+4 ){
|
||||
*pRc = SQLITE_CORRUPT_BKPT;
|
||||
return 0;
|
||||
}
|
||||
/* EVIDENCE-OF: R-22710-53328 The third and fourth bytes of each
|
||||
** freeblock form a big-endian integer which is the size of the freeblock
|
||||
** in bytes, including the 4-byte header. */
|
||||
size = get2byte(&aData[pc+2]);
|
||||
if( size>=nByte ){
|
||||
int x = size - nByte;
|
||||
testcase( x==4 );
|
||||
testcase( x==3 );
|
||||
if( x<4 ){
|
||||
/* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total
|
||||
** number of bytes in fragments may not exceed 60. */
|
||||
if( aData[hdr+7]>=60 ){
|
||||
if( pbDefrag ) *pbDefrag = 1;
|
||||
return 0;
|
||||
@@ -1311,14 +1323,13 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
|
||||
assert( pPage->cellOffset == hdr + 12 - 4*pPage->leaf );
|
||||
gap = pPage->cellOffset + 2*pPage->nCell;
|
||||
assert( gap<=65536 );
|
||||
top = get2byte(&data[hdr+5]);
|
||||
if( gap>top ){
|
||||
if( top==0 ){
|
||||
top = 65536;
|
||||
}else{
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
}
|
||||
/* EVIDENCE-OF: R-29356-02391 If the database uses a 65536-byte page size
|
||||
** and the reserved space is zero (the usual value for reserved space)
|
||||
** then the cell content offset of an empty page wants to be 65536.
|
||||
** However, that integer is too large to be stored in a 2-byte unsigned
|
||||
** integer, so a value of 0 is used in its place. */
|
||||
top = get2byteNotZero(&data[hdr+5]);
|
||||
if( gap>top ) return SQLITE_CORRUPT_BKPT;
|
||||
|
||||
/* If there is enough space between gap and top for one more cell pointer
|
||||
** array entry offset, and if the freelist is not empty, then search the
|
||||
@@ -1345,7 +1356,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
|
||||
testcase( gap+2+nByte==top );
|
||||
if( gap+2+nByte>top ){
|
||||
defragment_page:
|
||||
testcase( pPage->nCell==0 );
|
||||
assert( pPage->nCell>0 || CORRUPT_DB );
|
||||
rc = defragmentPage(pPage);
|
||||
if( rc ) return rc;
|
||||
top = get2byteNotZero(&data[hdr+5]);
|
||||
@@ -1487,18 +1498,32 @@ static int decodeFlags(MemPage *pPage, int flagByte){
|
||||
pPage->childPtrSize = 4-4*pPage->leaf;
|
||||
pBt = pPage->pBt;
|
||||
if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){
|
||||
/* EVIDENCE-OF: R-03640-13415 A value of 5 means the page is an interior
|
||||
** table b-tree page. */
|
||||
assert( (PTF_LEAFDATA|PTF_INTKEY)==5 );
|
||||
/* EVIDENCE-OF: R-20501-61796 A value of 13 means the page is a leaf
|
||||
** table b-tree page. */
|
||||
assert( (PTF_LEAFDATA|PTF_INTKEY|PTF_LEAF)==13 );
|
||||
pPage->intKey = 1;
|
||||
pPage->intKeyLeaf = pPage->leaf;
|
||||
pPage->noPayload = !pPage->leaf;
|
||||
pPage->maxLocal = pBt->maxLeaf;
|
||||
pPage->minLocal = pBt->minLeaf;
|
||||
}else if( flagByte==PTF_ZERODATA ){
|
||||
/* EVIDENCE-OF: R-27225-53936 A value of 2 means the page is an interior
|
||||
** index b-tree page. */
|
||||
assert( (PTF_ZERODATA)==2 );
|
||||
/* EVIDENCE-OF: R-16571-11615 A value of 10 means the page is a leaf
|
||||
** index b-tree page. */
|
||||
assert( (PTF_ZERODATA|PTF_LEAF)==10 );
|
||||
pPage->intKey = 0;
|
||||
pPage->intKeyLeaf = 0;
|
||||
pPage->noPayload = 0;
|
||||
pPage->maxLocal = pBt->maxLocal;
|
||||
pPage->minLocal = pBt->minLocal;
|
||||
}else{
|
||||
/* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is
|
||||
** an error. */
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
pPage->max1bytePayload = pBt->max1bytePayload;
|
||||
@@ -1538,21 +1563,33 @@ static int btreeInitPage(MemPage *pPage){
|
||||
|
||||
hdr = pPage->hdrOffset;
|
||||
data = pPage->aData;
|
||||
/* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating
|
||||
** the b-tree page type. */
|
||||
if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT;
|
||||
assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
|
||||
pPage->maskPage = (u16)(pBt->pageSize - 1);
|
||||
pPage->nOverflow = 0;
|
||||
usableSize = pBt->usableSize;
|
||||
pPage->cellOffset = cellOffset = hdr + 12 - 4*pPage->leaf;
|
||||
pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize;
|
||||
pPage->aDataEnd = &data[usableSize];
|
||||
pPage->aCellIdx = &data[cellOffset];
|
||||
/* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates
|
||||
** the start of the cell content area. A zero value for this integer is
|
||||
** interpreted as 65536. */
|
||||
top = get2byteNotZero(&data[hdr+5]);
|
||||
/* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
|
||||
** number of cells on the page. */
|
||||
pPage->nCell = get2byte(&data[hdr+3]);
|
||||
if( pPage->nCell>MX_CELL(pBt) ){
|
||||
/* To many cells for a single page. The page must be corrupt */
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
testcase( pPage->nCell==MX_CELL(pBt) );
|
||||
/* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only
|
||||
** possible for a root page of a table that contains no rows) then the
|
||||
** offset to the cell content area will equal the page size minus the
|
||||
** bytes of reserved space. */
|
||||
assert( pPage->nCell>0 || top==usableSize || CORRUPT_DB );
|
||||
|
||||
/* A malformed database page might cause us to read past the end
|
||||
** of page when parsing a cell.
|
||||
@@ -1586,13 +1623,20 @@ static int btreeInitPage(MemPage *pPage){
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Compute the total free space on the page */
|
||||
/* Compute the total free space on the page
|
||||
** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the
|
||||
** start of the first freeblock on the page, or is zero if there are no
|
||||
** freeblocks. */
|
||||
pc = get2byte(&data[hdr+1]);
|
||||
nFree = data[hdr+7] + top;
|
||||
nFree = data[hdr+7] + top; /* Init nFree to non-freeblock free space */
|
||||
while( pc>0 ){
|
||||
u16 next, size;
|
||||
if( pc<iCellFirst || pc>iCellLast ){
|
||||
/* Start of free block is off the page */
|
||||
/* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will
|
||||
** always be at least one cell before the first freeblock.
|
||||
**
|
||||
** Or, the freeblock is off the end of the page
|
||||
*/
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
next = get2byte(&data[pc]);
|
||||
@@ -1998,6 +2042,9 @@ int sqlite3BtreeOpen(
|
||||
#ifdef SQLITE_SECURE_DELETE
|
||||
pBt->btsFlags |= BTS_SECURE_DELETE;
|
||||
#endif
|
||||
/* EVIDENCE-OF: R-51873-39618 The page size for a database file is
|
||||
** determined by the 2-byte integer located at an offset of 16 bytes from
|
||||
** the beginning of the database file. */
|
||||
pBt->pageSize = (zDbHeader[16]<<8) | (zDbHeader[17]<<16);
|
||||
if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE
|
||||
|| ((pBt->pageSize-1)&pBt->pageSize)!=0 ){
|
||||
@@ -2016,6 +2063,9 @@ int sqlite3BtreeOpen(
|
||||
#endif
|
||||
nReserve = 0;
|
||||
}else{
|
||||
/* EVIDENCE-OF: R-37497-42412 The size of the reserved region is
|
||||
** determined by the one-byte unsigned integer found at an offset of 20
|
||||
** into the database file header. */
|
||||
nReserve = zDbHeader[20];
|
||||
pBt->btsFlags |= BTS_PAGESIZE_FIXED;
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
@@ -2213,7 +2263,7 @@ int sqlite3BtreeClose(Btree *p){
|
||||
** The call to sqlite3BtreeRollback() drops any table-locks held by
|
||||
** this handle.
|
||||
*/
|
||||
sqlite3BtreeRollback(p, SQLITE_OK);
|
||||
sqlite3BtreeRollback(p, SQLITE_OK, 0);
|
||||
sqlite3BtreeLeave(p);
|
||||
|
||||
/* If there are still other outstanding references to the shared-btree
|
||||
@@ -2525,6 +2575,9 @@ static int lockBtree(BtShared *pBt){
|
||||
u32 usableSize;
|
||||
u8 *page1 = pPage1->aData;
|
||||
rc = SQLITE_NOTADB;
|
||||
/* EVIDENCE-OF: R-43737-39999 Every valid SQLite database file begins
|
||||
** with the following 16 bytes (in hex): 53 51 4c 69 74 65 20 66 6f 72 6d
|
||||
** 61 74 20 33 00. */
|
||||
if( memcmp(page1, zMagicHeader, 16)!=0 ){
|
||||
goto page1_init_failed;
|
||||
}
|
||||
@@ -2565,15 +2618,21 @@ static int lockBtree(BtShared *pBt){
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The maximum embedded fraction must be exactly 25%. And the minimum
|
||||
** embedded fraction must be 12.5% for both leaf-data and non-leaf-data.
|
||||
/* EVIDENCE-OF: R-15465-20813 The maximum and minimum embedded payload
|
||||
** fractions and the leaf payload fraction values must be 64, 32, and 32.
|
||||
**
|
||||
** The original design allowed these amounts to vary, but as of
|
||||
** version 3.6.0, we require them to be fixed.
|
||||
*/
|
||||
if( memcmp(&page1[21], "\100\040\040",3)!=0 ){
|
||||
goto page1_init_failed;
|
||||
}
|
||||
/* EVIDENCE-OF: R-51873-39618 The page size for a database file is
|
||||
** determined by the 2-byte integer located at an offset of 16 bytes from
|
||||
** the beginning of the database file. */
|
||||
pageSize = (page1[16]<<8) | (page1[17]<<16);
|
||||
/* EVIDENCE-OF: R-25008-21688 The size of a page is a power of two
|
||||
** between 512 and 65536 inclusive. */
|
||||
if( ((pageSize-1)&pageSize)!=0
|
||||
|| pageSize>SQLITE_MAX_PAGE_SIZE
|
||||
|| pageSize<=256
|
||||
@@ -2581,6 +2640,13 @@ static int lockBtree(BtShared *pBt){
|
||||
goto page1_init_failed;
|
||||
}
|
||||
assert( (pageSize & 7)==0 );
|
||||
/* EVIDENCE-OF: R-59310-51205 The "reserved space" size in the 1-byte
|
||||
** integer at offset 20 is the number of bytes of space at the end of
|
||||
** each page to reserve for extensions.
|
||||
**
|
||||
** EVIDENCE-OF: R-37497-42412 The size of the reserved region is
|
||||
** determined by the one-byte unsigned integer found at an offset of 20
|
||||
** into the database file header. */
|
||||
usableSize = pageSize - page1[20];
|
||||
if( (u32)pageSize!=pBt->pageSize ){
|
||||
/* After reading the first page of the database assuming a page size
|
||||
@@ -2601,6 +2667,9 @@ static int lockBtree(BtShared *pBt){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto page1_init_failed;
|
||||
}
|
||||
/* EVIDENCE-OF: R-28312-64704 However, the usable size is not allowed to
|
||||
** be less than 480. In other words, if the page size is 512, then the
|
||||
** reserved space size cannot exceed 32. */
|
||||
if( usableSize<480 ){
|
||||
goto page1_init_failed;
|
||||
}
|
||||
@@ -3506,60 +3575,91 @@ int sqlite3BtreeCommit(Btree *p){
|
||||
|
||||
/*
|
||||
** This routine sets the state to CURSOR_FAULT and the error
|
||||
** code to errCode for every cursor on BtShared that pBtree
|
||||
** references.
|
||||
** code to errCode for every cursor on any BtShared that pBtree
|
||||
** references. Or if the writeOnly flag is set to 1, then only
|
||||
** trip write cursors and leave read cursors unchanged.
|
||||
**
|
||||
** Every cursor is tripped, including cursors that belong
|
||||
** to other database connections that happen to be sharing
|
||||
** the cache with pBtree.
|
||||
** Every cursor is a candidate to be tripped, including cursors
|
||||
** that belong to other database connections that happen to be
|
||||
** sharing the cache with pBtree.
|
||||
**
|
||||
** This routine gets called when a rollback occurs.
|
||||
** All cursors using the same cache must be tripped
|
||||
** to prevent them from trying to use the btree after
|
||||
** the rollback. The rollback may have deleted tables
|
||||
** or moved root pages, so it is not sufficient to
|
||||
** save the state of the cursor. The cursor must be
|
||||
** invalidated.
|
||||
** This routine gets called when a rollback occurs. If the writeOnly
|
||||
** flag is true, then only write-cursors need be tripped - read-only
|
||||
** cursors save their current positions so that they may continue
|
||||
** following the rollback. Or, if writeOnly is false, all cursors are
|
||||
** tripped. In general, writeOnly is false if the transaction being
|
||||
** rolled back modified the database schema. In this case b-tree root
|
||||
** pages may be moved or deleted from the database altogether, making
|
||||
** it unsafe for read cursors to continue.
|
||||
**
|
||||
** If the writeOnly flag is true and an error is encountered while
|
||||
** saving the current position of a read-only cursor, all cursors,
|
||||
** including all read-cursors are tripped.
|
||||
**
|
||||
** SQLITE_OK is returned if successful, or if an error occurs while
|
||||
** saving a cursor position, an SQLite error code.
|
||||
*/
|
||||
void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){
|
||||
int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){
|
||||
BtCursor *p;
|
||||
if( pBtree==0 ) return;
|
||||
sqlite3BtreeEnter(pBtree);
|
||||
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
|
||||
int i;
|
||||
sqlite3BtreeClearCursor(p);
|
||||
p->eState = CURSOR_FAULT;
|
||||
p->skipNext = errCode;
|
||||
for(i=0; i<=p->iPage; i++){
|
||||
releasePage(p->apPage[i]);
|
||||
p->apPage[i] = 0;
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
assert( (writeOnly==0 || writeOnly==1) && BTCF_WriteFlag==1 );
|
||||
if( pBtree ){
|
||||
sqlite3BtreeEnter(pBtree);
|
||||
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
|
||||
int i;
|
||||
if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){
|
||||
if( p->eState==CURSOR_VALID ){
|
||||
rc = saveCursorPosition(p);
|
||||
if( rc!=SQLITE_OK ){
|
||||
(void)sqlite3BtreeTripAllCursors(pBtree, rc, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
sqlite3BtreeClearCursor(p);
|
||||
p->eState = CURSOR_FAULT;
|
||||
p->skipNext = errCode;
|
||||
}
|
||||
for(i=0; i<=p->iPage; i++){
|
||||
releasePage(p->apPage[i]);
|
||||
p->apPage[i] = 0;
|
||||
}
|
||||
}
|
||||
sqlite3BtreeLeave(pBtree);
|
||||
}
|
||||
sqlite3BtreeLeave(pBtree);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Rollback the transaction in progress. All cursors will be
|
||||
** invalided by this operation. Any attempt to use a cursor
|
||||
** that was open at the beginning of this operation will result
|
||||
** in an error.
|
||||
** Rollback the transaction in progress.
|
||||
**
|
||||
** If tripCode is not SQLITE_OK then cursors will be invalidated (tripped).
|
||||
** Only write cursors are tripped if writeOnly is true but all cursors are
|
||||
** tripped if writeOnly is false. Any attempt to use
|
||||
** a tripped cursor will result in an error.
|
||||
**
|
||||
** This will release the write lock on the database file. If there
|
||||
** are no active cursors, it also releases the read lock.
|
||||
*/
|
||||
int sqlite3BtreeRollback(Btree *p, int tripCode){
|
||||
int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){
|
||||
int rc;
|
||||
BtShared *pBt = p->pBt;
|
||||
MemPage *pPage1;
|
||||
|
||||
assert( writeOnly==1 || writeOnly==0 );
|
||||
assert( tripCode==SQLITE_ABORT_ROLLBACK || tripCode==SQLITE_OK );
|
||||
sqlite3BtreeEnter(p);
|
||||
if( tripCode==SQLITE_OK ){
|
||||
rc = tripCode = saveAllCursors(pBt, 0, 0);
|
||||
if( rc ) writeOnly = 0;
|
||||
}else{
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
if( tripCode ){
|
||||
sqlite3BtreeTripAllCursors(p, tripCode);
|
||||
int rc2 = sqlite3BtreeTripAllCursors(p, tripCode, writeOnly);
|
||||
assert( rc==SQLITE_OK || (writeOnly==0 && rc2==SQLITE_OK) );
|
||||
if( rc2!=SQLITE_OK ) rc = rc2;
|
||||
}
|
||||
btreeIntegrity(p);
|
||||
|
||||
@@ -3894,13 +3994,9 @@ int sqlite3BtreeCursorIsValid(BtCursor *pCur){
|
||||
*/
|
||||
int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
|
||||
assert( cursorHoldsMutex(pCur) );
|
||||
assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID );
|
||||
if( pCur->eState!=CURSOR_VALID ){
|
||||
*pSize = 0;
|
||||
}else{
|
||||
getCellInfo(pCur);
|
||||
*pSize = pCur->info.nKey;
|
||||
}
|
||||
assert( pCur->eState==CURSOR_VALID );
|
||||
getCellInfo(pCur);
|
||||
*pSize = pCur->info.nKey;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@@ -5151,6 +5247,8 @@ static int allocateBtreePage(
|
||||
assert( eMode==BTALLOC_ANY || (nearby>0 && IfNotOmitAV(pBt->autoVacuum)) );
|
||||
pPage1 = pBt->pPage1;
|
||||
mxPage = btreePagecount(pBt);
|
||||
/* EVIDENCE-OF: R-05119-02637 The 4-byte big-endian integer at offset 36
|
||||
** stores stores the total number of pages on the freelist. */
|
||||
n = get4byte(&pPage1->aData[36]);
|
||||
testcase( n==mxPage-1 );
|
||||
if( n>=mxPage ){
|
||||
@@ -5197,8 +5295,14 @@ static int allocateBtreePage(
|
||||
do {
|
||||
pPrevTrunk = pTrunk;
|
||||
if( pPrevTrunk ){
|
||||
/* EVIDENCE-OF: R-01506-11053 The first integer on a freelist trunk page
|
||||
** is the page number of the next freelist trunk page in the list or
|
||||
** zero if this is the last freelist trunk page. */
|
||||
iTrunk = get4byte(&pPrevTrunk->aData[0]);
|
||||
}else{
|
||||
/* EVIDENCE-OF: R-59841-13798 The 4-byte big-endian integer at offset 32
|
||||
** stores the page number of the first page of the freelist, or zero if
|
||||
** the freelist is empty. */
|
||||
iTrunk = get4byte(&pPage1->aData[32]);
|
||||
}
|
||||
testcase( iTrunk==mxPage );
|
||||
@@ -5213,8 +5317,9 @@ static int allocateBtreePage(
|
||||
}
|
||||
assert( pTrunk!=0 );
|
||||
assert( pTrunk->aData!=0 );
|
||||
|
||||
k = get4byte(&pTrunk->aData[4]); /* # of leaves on this trunk page */
|
||||
/* EVIDENCE-OF: R-13523-04394 The second integer on a freelist trunk page
|
||||
** is the number of leaf page pointers to follow. */
|
||||
k = get4byte(&pTrunk->aData[4]);
|
||||
if( k==0 && !searchList ){
|
||||
/* The trunk has no leaves and the list is not being searched.
|
||||
** So extract the trunk page itself and use it as the newly
|
||||
@@ -5532,6 +5637,11 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
|
||||
** for now. At some point in the future (once everyone has upgraded
|
||||
** to 3.6.0 or later) we should consider fixing the conditional above
|
||||
** to read "usableSize/4-2" instead of "usableSize/4-8".
|
||||
**
|
||||
** EVIDENCE-OF: R-19920-11576 However, newer versions of SQLite still
|
||||
** avoid using the last six entries in the freelist trunk page array in
|
||||
** order that database files created by newer versions of SQLite can be
|
||||
** read by older versions of SQLite.
|
||||
*/
|
||||
rc = sqlite3PagerWrite(pTrunk->pDbPage);
|
||||
if( rc==SQLITE_OK ){
|
||||
@@ -5883,9 +5993,17 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
|
||||
return;
|
||||
}
|
||||
pPage->nCell--;
|
||||
memmove(ptr, ptr+2, 2*(pPage->nCell - idx));
|
||||
put2byte(&data[hdr+3], pPage->nCell);
|
||||
pPage->nFree += 2;
|
||||
if( pPage->nCell==0 ){
|
||||
memset(&data[hdr+1], 0, 4);
|
||||
data[hdr+7] = 0;
|
||||
put2byte(&data[hdr+5], pPage->pBt->usableSize);
|
||||
pPage->nFree = pPage->pBt->usableSize - pPage->hdrOffset
|
||||
- pPage->childPtrSize - 8;
|
||||
}else{
|
||||
memmove(ptr, ptr+2, 2*(pPage->nCell - idx));
|
||||
put2byte(&data[hdr+3], pPage->nCell);
|
||||
pPage->nFree += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -6139,6 +6257,14 @@ static int pageFreeArray(
|
||||
}
|
||||
|
||||
/*
|
||||
** apCell[] and szCell[] contains pointers to and sizes of all cells in the
|
||||
** pages being balanced. The current page, pPg, has pPg->nCell cells starting
|
||||
** with apCell[iOld]. After balancing, this page should hold nNew cells
|
||||
** starting at apCell[iNew].
|
||||
**
|
||||
** This routine makes the necessary adjustments to pPg so that it contains
|
||||
** the correct cells after being balanced.
|
||||
**
|
||||
** The pPg->nFree field is invalid when this function returns. It is the
|
||||
** responsibility of the caller to set it correctly.
|
||||
*/
|
||||
@@ -6179,12 +6305,13 @@ static void editPage(
|
||||
);
|
||||
}
|
||||
|
||||
pData = &aData[get2byte(&aData[hdr+5])];
|
||||
pData = &aData[get2byteNotZero(&aData[hdr+5])];
|
||||
if( pData<pBegin ) goto editpage_fail;
|
||||
|
||||
/* Add cells to the start of the page */
|
||||
if( iNew<iOld ){
|
||||
int nAdd = iOld-iNew;
|
||||
int nAdd = MIN(nNew,iOld-iNew);
|
||||
assert( (iOld-iNew)<nNew || nCell==0 || CORRUPT_DB );
|
||||
pCellptr = pPg->aCellIdx;
|
||||
memmove(&pCellptr[nAdd*2], pCellptr, nCell*2);
|
||||
if( pageInsertArray(
|
||||
@@ -6289,7 +6416,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
|
||||
assert( pPage->nOverflow==1 );
|
||||
|
||||
/* This error condition is now caught prior to reaching this function */
|
||||
if( pPage->nCell==0 ) return SQLITE_CORRUPT_BKPT;
|
||||
if( NEVER(pPage->nCell==0) ) return SQLITE_CORRUPT_BKPT;
|
||||
|
||||
/* Allocate a new page. This page will become the right-sibling of
|
||||
** pPage. Make the parent page writable, so that the new divider cell
|
||||
@@ -8533,8 +8660,14 @@ static int checkTreePage(
|
||||
assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
|
||||
memset(hit+contentOffset, 0, usableSize-contentOffset);
|
||||
memset(hit, 1, contentOffset);
|
||||
/* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the
|
||||
** number of cells on the page. */
|
||||
nCell = get2byte(&data[hdr+3]);
|
||||
/* EVIDENCE-OF: R-23882-45353 The cell pointer array of a b-tree page
|
||||
** immediately follows the b-tree page header. */
|
||||
cellStart = hdr + 12 - 4*pPage->leaf;
|
||||
/* EVIDENCE-OF: R-02776-14802 The cell pointer array consists of K 2-byte
|
||||
** integer offsets to the cell contents. */
|
||||
for(i=0; i<nCell; i++){
|
||||
int pc = get2byte(&data[cellStart+i*2]);
|
||||
u32 size = 65536;
|
||||
@@ -8550,6 +8683,9 @@ static int checkTreePage(
|
||||
for(j=pc+size-1; j>=pc; j--) hit[j]++;
|
||||
}
|
||||
}
|
||||
/* EVIDENCE-OF: R-20690-50594 The second field of the b-tree page header
|
||||
** is the offset of the first freeblock, or zero if there are no
|
||||
** freeblocks on the page. */
|
||||
i = get2byte(&data[hdr+1]);
|
||||
while( i>0 ){
|
||||
int size, j;
|
||||
@@ -8557,7 +8693,13 @@ static int checkTreePage(
|
||||
size = get2byte(&data[i+2]);
|
||||
assert( i+size<=usableSize ); /* Enforced by btreeInitPage() */
|
||||
for(j=i+size-1; j>=i; j--) hit[j]++;
|
||||
/* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a
|
||||
** big-endian integer which is the offset in the b-tree page of the next
|
||||
** freeblock in the chain, or zero if the freeblock is the last on the
|
||||
** chain. */
|
||||
j = get2byte(&data[i]);
|
||||
/* EVIDENCE-OF: R-06866-39125 Freeblocks are always connected in order of
|
||||
** increasing offset. */
|
||||
assert( j==0 || j>i+size ); /* Enforced by btreeInitPage() */
|
||||
assert( j<=usableSize-4 ); /* Enforced by btreeInitPage() */
|
||||
i = j;
|
||||
@@ -8571,6 +8713,11 @@ static int checkTreePage(
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* EVIDENCE-OF: R-43263-13491 The total number of bytes in all fragments
|
||||
** is stored in the fifth field of the b-tree page header.
|
||||
** EVIDENCE-OF: R-07161-27322 The one-byte integer at offset 7 gives the
|
||||
** number of fragmented free bytes within the cell content area.
|
||||
*/
|
||||
if( cnt!=data[hdr+7] ){
|
||||
checkAppendMsg(pCheck,
|
||||
"Fragmentation of %d bytes reported as %d on page %d",
|
||||
|
||||
+2
-2
@@ -83,7 +83,7 @@ int sqlite3BtreeBeginTrans(Btree*,int);
|
||||
int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
|
||||
int sqlite3BtreeCommitPhaseTwo(Btree*, int);
|
||||
int sqlite3BtreeCommit(Btree*);
|
||||
int sqlite3BtreeRollback(Btree*,int);
|
||||
int sqlite3BtreeRollback(Btree*,int,int);
|
||||
int sqlite3BtreeBeginStmt(Btree*,int);
|
||||
int sqlite3BtreeCreateTable(Btree*, int*, int flags);
|
||||
int sqlite3BtreeIsInTrans(Btree*);
|
||||
@@ -116,7 +116,7 @@ int sqlite3BtreeIncrVacuum(Btree *);
|
||||
int sqlite3BtreeDropTable(Btree*, int, int*);
|
||||
int sqlite3BtreeClearTable(Btree*, int, int*);
|
||||
int sqlite3BtreeClearTableOfCursor(BtCursor*);
|
||||
void sqlite3BtreeTripAllCursors(Btree*, int);
|
||||
int sqlite3BtreeTripAllCursors(Btree*, int, int);
|
||||
|
||||
void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue);
|
||||
int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
|
||||
|
||||
+8
-2
@@ -489,6 +489,11 @@ struct CellInfo {
|
||||
**
|
||||
** Fields in this structure are accessed under the BtShared.mutex
|
||||
** found at self->pBt->mutex.
|
||||
**
|
||||
** skipNext meaning:
|
||||
** eState==SKIPNEXT && skipNext>0: Next sqlite3BtreeNext() is no-op.
|
||||
** eState==SKIPNEXT && skipNext<0: Next sqlite3BtreePrevious() is no-op.
|
||||
** eState==FAULT: Cursor fault with skipNext as error code.
|
||||
*/
|
||||
struct BtCursor {
|
||||
Btree *pBtree; /* The Btree to which this cursor belongs */
|
||||
@@ -501,7 +506,8 @@ struct BtCursor {
|
||||
void *pKey; /* Saved key that was cursor last known position */
|
||||
Pgno pgnoRoot; /* The root page of this tree */
|
||||
int nOvflAlloc; /* Allocated size of aOverflow[] array */
|
||||
int skipNext; /* Prev() is noop if negative. Next() is noop if positive */
|
||||
int skipNext; /* Prev() is noop if negative. Next() is noop if positive.
|
||||
** Error code if eState==CURSOR_FAULT */
|
||||
u8 curFlags; /* zero or more BTCF_* flags defined below */
|
||||
u8 eState; /* One of the CURSOR_XXX constants (see below) */
|
||||
u8 hints; /* As configured by CursorSetHints() */
|
||||
@@ -547,7 +553,7 @@ struct BtCursor {
|
||||
** on a different connection that shares the BtShared cache with this
|
||||
** cursor. The error has left the cache in an inconsistent state.
|
||||
** Do nothing else with this cursor. Any attempt to use the cursor
|
||||
** should return the error code stored in BtCursor.skip
|
||||
** should return the error code stored in BtCursor.skipNext
|
||||
*/
|
||||
#define CURSOR_INVALID 0
|
||||
#define CURSOR_VALID 1
|
||||
|
||||
+30
-2
@@ -102,7 +102,7 @@ CollSeq *sqlite3GetCollSeq(
|
||||
if( p && !p->xCmp && synthCollSeq(db, p) ){
|
||||
p = 0;
|
||||
}
|
||||
assert( !p || p->xCmp );
|
||||
assert( p==0 || (sqlite3ValidCollSeq(p) && p->xCmp!=0) );
|
||||
if( p==0 ){
|
||||
sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
|
||||
}
|
||||
@@ -186,6 +186,31 @@ static CollSeq *findCollSeqEntry(
|
||||
return pColl;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** The following routine does sanity checking on a CollSeq object and
|
||||
** returns 1 if everything looks ok and 0 if the CollSeq object appears
|
||||
** to be corrupt. This routine is used only inside of assert() statements.
|
||||
*/
|
||||
int sqlite3ValidCollSeq(const CollSeq *p){
|
||||
/* The CollSeq must be one of a triple and the zName field must
|
||||
** point to the first byte after that triple
|
||||
*/
|
||||
int n = (int)(p->zName - (char*)p)/sizeof(CollSeq);
|
||||
if( n<=0 || n>3 ) return 0;
|
||||
|
||||
/* Check for valid enc values */
|
||||
if( p->enc==SQLITE_UTF8 ) return 1;
|
||||
if( p->enc==SQLITE_UTF16LE ) return 1;
|
||||
if( p->enc==SQLITE_UTF16BE ) return 1;
|
||||
if( p->enc==(SQLITE_UTF16LE|SQLITE_UTF16_ALIGNED) ) return 1;
|
||||
if( p->enc==(SQLITE_UTF16BE|SQLITE_UTF16_ALIGNED) ) return 1;
|
||||
|
||||
/* Otherwise, malformed */
|
||||
return 0;
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
/*
|
||||
** Parameter zName points to a UTF-8 encoded string nName bytes long.
|
||||
** Return the CollSeq* pointer for the collation sequence named zName
|
||||
@@ -215,7 +240,10 @@ CollSeq *sqlite3FindCollSeq(
|
||||
}
|
||||
assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
|
||||
assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE );
|
||||
if( pColl ) pColl += enc-1;
|
||||
if( pColl ){
|
||||
pColl += enc-1;
|
||||
assert( sqlite3ValidCollSeq(pColl) );
|
||||
}
|
||||
return pColl;
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -16,7 +16,7 @@
|
||||
** sqlite3RegisterDateTimeFunctions() found at the bottom of the file.
|
||||
** All other code has file scope.
|
||||
**
|
||||
** SQLite processes all times and dates as Julian Day numbers. The
|
||||
** SQLite processes all times and dates as julian day numbers. The
|
||||
** dates and times are stored as the number of days since noon
|
||||
** in Greenwich on November 24, 4714 B.C. according to the Gregorian
|
||||
** calendar system.
|
||||
@@ -31,7 +31,7 @@
|
||||
**
|
||||
** The Gregorian calendar system is used for all dates and times,
|
||||
** even those that predate the Gregorian calendar. Historians usually
|
||||
** use the Julian calendar for dates prior to 1582-10-15 and for some
|
||||
** use the julian calendar for dates prior to 1582-10-15 and for some
|
||||
** dates afterwards, depending on locale. Beware of this difference.
|
||||
**
|
||||
** The conversion algorithms are implemented based on descriptions
|
||||
@@ -304,7 +304,7 @@ static int setDateTimeToCurrent(sqlite3_context *context, DateTime *p){
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to parse the given string into a Julian Day Number. Return
|
||||
** Attempt to parse the given string into a julian day number. Return
|
||||
** the number of errors.
|
||||
**
|
||||
** The following are acceptable forms for the input string:
|
||||
@@ -875,7 +875,7 @@ static void dateFunc(
|
||||
** %f ** fractional seconds SS.SSS
|
||||
** %H hour 00-24
|
||||
** %j day of year 000-366
|
||||
** %J ** Julian day number
|
||||
** %J ** julian day number
|
||||
** %m month 01-12
|
||||
** %M minute 00-59
|
||||
** %s seconds since 1970-01-01
|
||||
|
||||
+6
-3
@@ -1414,7 +1414,8 @@ int sqlite3ExprCanBeNull(const Expr *p){
|
||||
return 0;
|
||||
case TK_COLUMN:
|
||||
assert( p->pTab!=0 );
|
||||
return p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0;
|
||||
return ExprHasProperty(p, EP_CanBeNull) ||
|
||||
(p->iColumn>=0 && p->pTab->aCol[p->iColumn].notNull==0);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
@@ -1857,7 +1858,6 @@ int sqlite3CodeSubselect(
|
||||
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
|
||||
pSelect->iLimit = 0;
|
||||
testcase( pSelect->selFlags & SF_Distinct );
|
||||
pSelect->selFlags &= ~SF_Distinct;
|
||||
testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
|
||||
if( sqlite3Select(pParse, pSelect, &dest) ){
|
||||
sqlite3KeyInfoUnref(pKeyInfo);
|
||||
@@ -3004,7 +3004,10 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
|
||||
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
/* If the column has REAL affinity, it may currently be stored as an
|
||||
** integer. Use OP_RealAffinity to make sure it is really real. */
|
||||
** integer. Use OP_RealAffinity to make sure it is really real.
|
||||
**
|
||||
** EVIDENCE-OF: R-60985-57662 SQLite will convert the value back to
|
||||
** floating point when extracting it from the record. */
|
||||
if( pExpr->iColumn>=0
|
||||
&& pTab->aCol[pExpr->iColumn].affinity==SQLITE_AFF_REAL
|
||||
){
|
||||
|
||||
+2
-2
@@ -157,8 +157,8 @@ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
default: {
|
||||
/* Because sqlite3_value_double() returns 0.0 if the argument is not
|
||||
** something that can be converted into a number, we have:
|
||||
** IMP: R-57326-31541 Abs(X) return 0.0 if X is a string or blob that
|
||||
** cannot be converted to a numeric value.
|
||||
** IMP: R-01992-00519 Abs(X) returns 0.0 if X is a string or blob
|
||||
** that cannot be converted to a numeric value.
|
||||
*/
|
||||
double rVal = sqlite3_value_double(argv[0]);
|
||||
if( rVal<0 ) rVal = -rVal;
|
||||
|
||||
+2
-2
@@ -237,8 +237,8 @@ const Token sqlite3IntTokens[] = {
|
||||
**
|
||||
** IMPORTANT: Changing the pending byte to any value other than
|
||||
** 0x40000000 results in an incompatible database file format!
|
||||
** Changing the pending byte during operating results in undefined
|
||||
** and dileterious behavior.
|
||||
** Changing the pending byte during operation will result in undefined
|
||||
** and incorrect behavior.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_WSD
|
||||
int sqlite3PendingByte = 0x40000000;
|
||||
|
||||
+60
-23
@@ -457,6 +457,9 @@ int sqlite3_config(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
/* EVIDENCE-OF: R-06626-12911 The SQLITE_CONFIG_HEAP option is only
|
||||
** available if SQLite is compiled with either SQLITE_ENABLE_MEMSYS3 or
|
||||
** SQLITE_ENABLE_MEMSYS5 and returns SQLITE_ERROR if invoked otherwise. */
|
||||
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
|
||||
case SQLITE_CONFIG_HEAP: {
|
||||
/* EVIDENCE-OF: R-19854-42126 There are three arguments to
|
||||
@@ -474,17 +477,19 @@ int sqlite3_config(int op, ...){
|
||||
}
|
||||
|
||||
if( sqlite3GlobalConfig.pHeap==0 ){
|
||||
/* If the heap pointer is NULL, then restore the malloc implementation
|
||||
** back to NULL pointers too. This will cause the malloc to go
|
||||
** back to its default implementation when sqlite3_initialize() is
|
||||
** run.
|
||||
/* EVIDENCE-OF: R-49920-60189 If the first pointer (the memory pointer)
|
||||
** is NULL, then SQLite reverts to using its default memory allocator
|
||||
** (the system malloc() implementation), undoing any prior invocation of
|
||||
** SQLITE_CONFIG_MALLOC.
|
||||
**
|
||||
** Setting sqlite3GlobalConfig.m to all zeros will cause malloc to
|
||||
** revert to its default implementation when sqlite3_initialize() is run
|
||||
*/
|
||||
memset(&sqlite3GlobalConfig.m, 0, sizeof(sqlite3GlobalConfig.m));
|
||||
}else{
|
||||
/* The heap pointer is not NULL, then install one of the
|
||||
** mem5.c/mem3.c methods. The enclosing #if guarantees at
|
||||
** least one of these methods is currently enabled.
|
||||
*/
|
||||
/* EVIDENCE-OF: R-61006-08918 If the memory pointer is not NULL then the
|
||||
** alternative memory allocator is engaged to handle all of SQLites
|
||||
** memory allocation needs. */
|
||||
#ifdef SQLITE_ENABLE_MEMSYS3
|
||||
sqlite3GlobalConfig.m = *sqlite3MemGetMemsys3();
|
||||
#endif
|
||||
@@ -557,7 +562,13 @@ int sqlite3_config(int op, ...){
|
||||
sqlite3_int64 szMmap = va_arg(ap, sqlite3_int64);
|
||||
sqlite3_int64 mxMmap = va_arg(ap, sqlite3_int64);
|
||||
/* EVIDENCE-OF: R-53367-43190 If either argument to this option is
|
||||
** negative, then that argument is changed to its compile-time default. */
|
||||
** negative, then that argument is changed to its compile-time default.
|
||||
**
|
||||
** EVIDENCE-OF: R-34993-45031 The maximum allowed mmap size will be
|
||||
** silently truncated if necessary so that it does not exceed the
|
||||
** compile-time maximum mmap size set by the SQLITE_MAX_MMAP_SIZE
|
||||
** compile-time option.
|
||||
*/
|
||||
if( mxMmap<0 || mxMmap>SQLITE_MAX_MMAP_SIZE ) mxMmap = SQLITE_MAX_MMAP_SIZE;
|
||||
if( szMmap<0 ) szMmap = SQLITE_DEFAULT_MMAP_SIZE;
|
||||
if( szMmap>mxMmap) szMmap = mxMmap;
|
||||
@@ -762,13 +773,20 @@ static int binCollFunc(
|
||||
){
|
||||
int rc, n;
|
||||
n = nKey1<nKey2 ? nKey1 : nKey2;
|
||||
/* EVIDENCE-OF: R-65033-28449 The built-in BINARY collation compares
|
||||
** strings byte by byte using the memcmp() function from the standard C
|
||||
** library. */
|
||||
rc = memcmp(pKey1, pKey2, n);
|
||||
if( rc==0 ){
|
||||
if( padFlag
|
||||
&& allSpaces(((char*)pKey1)+n, nKey1-n)
|
||||
&& allSpaces(((char*)pKey2)+n, nKey2-n)
|
||||
){
|
||||
/* Leave rc unchanged at 0 */
|
||||
/* EVIDENCE-OF: R-31624-24737 RTRIM is like BINARY except that extra
|
||||
** spaces at the end of either string do not change the result. In other
|
||||
** words, strings will compare equal to one another as long as they
|
||||
** differ only in the number of spaces at the end.
|
||||
*/
|
||||
}else{
|
||||
rc = nKey1 - nKey2;
|
||||
}
|
||||
@@ -1016,7 +1034,13 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
|
||||
if( pDb->pBt ){
|
||||
sqlite3BtreeClose(pDb->pBt);
|
||||
pDb->pBt = 0;
|
||||
if( j!=1 ){
|
||||
if( j!=1 && pDb->pSchema ){
|
||||
/* Must clear the KeyInfo cache. See ticket [e4a18565a36884b00edf] */
|
||||
for(i=sqliteHashFirst(&pDb->pSchema->idxHash); i; i=sqliteHashNext(i)){
|
||||
Index *pIdx = sqliteHashData(i);
|
||||
sqlite3KeyInfoUnref(pIdx->pKeyInfo);
|
||||
pIdx->pKeyInfo = 0;
|
||||
}
|
||||
pDb->pSchema = 0;
|
||||
}
|
||||
}
|
||||
@@ -1100,13 +1124,15 @@ void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
|
||||
|
||||
/*
|
||||
** Rollback all database files. If tripCode is not SQLITE_OK, then
|
||||
** any open cursors are invalidated ("tripped" - as in "tripping a circuit
|
||||
** any write cursors are invalidated ("tripped" - as in "tripping a circuit
|
||||
** breaker") and made to return tripCode if there are any further
|
||||
** attempts to use that cursor.
|
||||
** attempts to use that cursor. Read cursors remain open and valid
|
||||
** but are "saved" in case the table pages are moved around.
|
||||
*/
|
||||
void sqlite3RollbackAll(sqlite3 *db, int tripCode){
|
||||
int i;
|
||||
int inTrans = 0;
|
||||
int schemaChange;
|
||||
assert( sqlite3_mutex_held(db->mutex) );
|
||||
sqlite3BeginBenignMalloc();
|
||||
|
||||
@@ -1117,6 +1143,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
|
||||
** the database rollback and schema reset, which can cause false
|
||||
** corruption reports in some cases. */
|
||||
sqlite3BtreeEnterAll(db);
|
||||
schemaChange = (db->flags & SQLITE_InternChanges)!=0 && db->init.busy==0;
|
||||
|
||||
for(i=0; i<db->nDb; i++){
|
||||
Btree *p = db->aDb[i].pBt;
|
||||
@@ -1124,7 +1151,7 @@ void sqlite3RollbackAll(sqlite3 *db, int tripCode){
|
||||
if( sqlite3BtreeIsInTrans(p) ){
|
||||
inTrans = 1;
|
||||
}
|
||||
sqlite3BtreeRollback(p, tripCode);
|
||||
sqlite3BtreeRollback(p, tripCode, !schemaChange);
|
||||
}
|
||||
}
|
||||
sqlite3VtabRollback(db);
|
||||
@@ -1915,10 +1942,13 @@ int sqlite3_wal_checkpoint_v2(
|
||||
if( pnLog ) *pnLog = -1;
|
||||
if( pnCkpt ) *pnCkpt = -1;
|
||||
|
||||
assert( SQLITE_CHECKPOINT_FULL>SQLITE_CHECKPOINT_PASSIVE );
|
||||
assert( SQLITE_CHECKPOINT_FULL<SQLITE_CHECKPOINT_RESTART );
|
||||
assert( SQLITE_CHECKPOINT_PASSIVE+2==SQLITE_CHECKPOINT_RESTART );
|
||||
if( eMode<SQLITE_CHECKPOINT_PASSIVE || eMode>SQLITE_CHECKPOINT_RESTART ){
|
||||
assert( SQLITE_CHECKPOINT_PASSIVE==0 );
|
||||
assert( SQLITE_CHECKPOINT_FULL==1 );
|
||||
assert( SQLITE_CHECKPOINT_RESTART==2 );
|
||||
assert( SQLITE_CHECKPOINT_TRUNCATE==3 );
|
||||
if( eMode<SQLITE_CHECKPOINT_PASSIVE || eMode>SQLITE_CHECKPOINT_TRUNCATE ){
|
||||
/* EVIDENCE-OF: R-03996-12088 The M parameter must be a valid checkpoint
|
||||
** mode: */
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
|
||||
@@ -1946,7 +1976,9 @@ int sqlite3_wal_checkpoint_v2(
|
||||
** checkpointed.
|
||||
*/
|
||||
int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb){
|
||||
return sqlite3_wal_checkpoint_v2(db, zDb, SQLITE_CHECKPOINT_PASSIVE, 0, 0);
|
||||
/* EVIDENCE-OF: R-41613-20553 The sqlite3_wal_checkpoint(D,X) is equivalent to
|
||||
** sqlite3_wal_checkpoint_v2(D,X,SQLITE_CHECKPOINT_PASSIVE,0,0). */
|
||||
return sqlite3_wal_checkpoint_v2(db,zDb,SQLITE_CHECKPOINT_PASSIVE,0,0);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
@@ -2389,7 +2421,8 @@ int sqlite3ParseUri(
|
||||
|
||||
assert( *pzErrMsg==0 );
|
||||
|
||||
if( ((flags & SQLITE_OPEN_URI) || sqlite3GlobalConfig.bOpenUri)
|
||||
if( ((flags & SQLITE_OPEN_URI) /* IMP: R-48725-32206 */
|
||||
|| sqlite3GlobalConfig.bOpenUri) /* IMP: R-51689-46548 */
|
||||
&& nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */
|
||||
){
|
||||
char *zOpt;
|
||||
@@ -2715,20 +2748,24 @@ static int openDatabase(
|
||||
/* Add the default collation sequence BINARY. BINARY works for both UTF-8
|
||||
** and UTF-16, so add a version for each to avoid any unnecessary
|
||||
** conversions. The only error that can occur here is a malloc() failure.
|
||||
**
|
||||
** EVIDENCE-OF: R-52786-44878 SQLite defines three built-in collating
|
||||
** functions:
|
||||
*/
|
||||
createCollation(db, "BINARY", SQLITE_UTF8, 0, binCollFunc, 0);
|
||||
createCollation(db, "BINARY", SQLITE_UTF16BE, 0, binCollFunc, 0);
|
||||
createCollation(db, "BINARY", SQLITE_UTF16LE, 0, binCollFunc, 0);
|
||||
createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);
|
||||
createCollation(db, "RTRIM", SQLITE_UTF8, (void*)1, binCollFunc, 0);
|
||||
if( db->mallocFailed ){
|
||||
goto opendb_out;
|
||||
}
|
||||
/* EVIDENCE-OF: R-08308-17224 The default collating function for all
|
||||
** strings is BINARY.
|
||||
*/
|
||||
db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 0);
|
||||
assert( db->pDfltColl!=0 );
|
||||
|
||||
/* Also add a UTF-8 case-insensitive collation sequence. */
|
||||
createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0);
|
||||
|
||||
/* Parse the filename/URI argument. */
|
||||
db->openFlags = flags;
|
||||
rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
|
||||
|
||||
+3
-2
@@ -2899,7 +2899,7 @@ static int readDbPage(PgHdr *pPg, u32 iFrame){
|
||||
**
|
||||
** For an encrypted database, the situation is more complex: bytes
|
||||
** 24..39 of the database are white noise. But the probability of
|
||||
** white noising equaling 16 bytes of 0xff is vanishingly small so
|
||||
** white noise equaling 16 bytes of 0xff is vanishingly small so
|
||||
** we should still be ok.
|
||||
*/
|
||||
memset(pPager->dbFileVers, 0xff, sizeof(pPager->dbFileVers));
|
||||
@@ -7075,7 +7075,8 @@ int sqlite3PagerCheckpoint(Pager *pPager, int eMode, int *pnLog, int *pnCkpt){
|
||||
int rc = SQLITE_OK;
|
||||
if( pPager->pWal ){
|
||||
rc = sqlite3WalCheckpoint(pPager->pWal, eMode,
|
||||
pPager->xBusyHandler, pPager->pBusyHandlerArg,
|
||||
(eMode==SQLITE_CHECKPOINT_PASSIVE ? 0 : pPager->xBusyHandler),
|
||||
pPager->pBusyHandlerArg,
|
||||
pPager->ckptSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
|
||||
pnLog, pnCkpt
|
||||
);
|
||||
|
||||
+3
-1
@@ -2195,7 +2195,7 @@ void sqlite3Pragma(
|
||||
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
/*
|
||||
** PRAGMA [database.]wal_checkpoint = passive|full|restart
|
||||
** PRAGMA [database.]wal_checkpoint = passive|full|restart|truncate
|
||||
**
|
||||
** Checkpoint the database.
|
||||
*/
|
||||
@@ -2207,6 +2207,8 @@ void sqlite3Pragma(
|
||||
eMode = SQLITE_CHECKPOINT_FULL;
|
||||
}else if( sqlite3StrICmp(zRight, "restart")==0 ){
|
||||
eMode = SQLITE_CHECKPOINT_RESTART;
|
||||
}else if( sqlite3StrICmp(zRight, "truncate")==0 ){
|
||||
eMode = SQLITE_CHECKPOINT_TRUNCATE;
|
||||
}
|
||||
}
|
||||
sqlite3VdbeSetNumCols(v, 3);
|
||||
|
||||
@@ -320,6 +320,10 @@ static int lookupName(
|
||||
if( pMatch ){
|
||||
pExpr->iTable = pMatch->iCursor;
|
||||
pExpr->pTab = pMatch->pTab;
|
||||
assert( (pMatch->jointype & JT_RIGHT)==0 ); /* RIGHT JOIN not (yet) supported */
|
||||
if( (pMatch->jointype & JT_LEFT)!=0 ){
|
||||
ExprSetProperty(pExpr, EP_CanBeNull);
|
||||
}
|
||||
pSchema = pExpr->pTab->pSchema;
|
||||
}
|
||||
} /* if( pSrcList ) */
|
||||
|
||||
+1
-2
@@ -4829,7 +4829,7 @@ int sqlite3Select(
|
||||
**
|
||||
** is transformed to:
|
||||
**
|
||||
** SELECT xyz FROM ... GROUP BY xyz
|
||||
** SELECT xyz FROM ... GROUP BY xyz ORDER BY xyz
|
||||
**
|
||||
** The second form is preferred as a single index (or temp-table) may be
|
||||
** used for both the ORDER BY and DISTINCT processing. As originally
|
||||
@@ -4842,7 +4842,6 @@ int sqlite3Select(
|
||||
p->selFlags &= ~SF_Distinct;
|
||||
p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0);
|
||||
pGroupBy = p->pGroupBy;
|
||||
sSort.pOrderBy = 0;
|
||||
/* Notice that even thought SF_Distinct has been cleared from p->selFlags,
|
||||
** the sDistinct.isTnct is still set. Hence, isTnct represents the
|
||||
** original setting of the SF_Distinct flag, not the current setting */
|
||||
|
||||
+117
-62
@@ -172,7 +172,8 @@ static HANDLE hProcess;
|
||||
static FILETIME ftKernelBegin;
|
||||
static FILETIME ftUserBegin;
|
||||
static sqlite3_int64 ftWallBegin;
|
||||
typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME);
|
||||
typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME,
|
||||
LPFILETIME, LPFILETIME);
|
||||
static GETPROCTIMES getProcessTimesAddr = NULL;
|
||||
|
||||
/*
|
||||
@@ -183,15 +184,16 @@ static int hasTimer(void){
|
||||
if( getProcessTimesAddr ){
|
||||
return 1;
|
||||
} else {
|
||||
/* GetProcessTimes() isn't supported in WIN95 and some other Windows versions.
|
||||
** See if the version we are running on has it, and if it does, save off
|
||||
** a pointer to it and the current process handle.
|
||||
/* GetProcessTimes() isn't supported in WIN95 and some other Windows
|
||||
** versions. See if the version we are running on has it, and if it
|
||||
** does, save off a pointer to it and the current process handle.
|
||||
*/
|
||||
hProcess = GetCurrentProcess();
|
||||
if( hProcess ){
|
||||
HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll"));
|
||||
if( NULL != hinstLib ){
|
||||
getProcessTimesAddr = (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes");
|
||||
getProcessTimesAddr =
|
||||
(GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes");
|
||||
if( NULL != getProcessTimesAddr ){
|
||||
return 1;
|
||||
}
|
||||
@@ -208,7 +210,8 @@ static int hasTimer(void){
|
||||
static void beginTimer(void){
|
||||
if( enableTimer && getProcessTimesAddr ){
|
||||
FILETIME ftCreation, ftExit;
|
||||
getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelBegin, &ftUserBegin);
|
||||
getProcessTimesAddr(hProcess,&ftCreation,&ftExit,
|
||||
&ftKernelBegin,&ftUserBegin);
|
||||
ftWallBegin = timeOfDay();
|
||||
}
|
||||
}
|
||||
@@ -227,7 +230,7 @@ static void endTimer(void){
|
||||
if( enableTimer && getProcessTimesAddr){
|
||||
FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
|
||||
sqlite3_int64 ftWallEnd = timeOfDay();
|
||||
getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd);
|
||||
getProcessTimesAddr(hProcess,&ftCreation,&ftExit,&ftKernelEnd,&ftUserEnd);
|
||||
printf("Run Time: real %.3f user %f sys %f\n",
|
||||
(ftWallEnd - ftWallBegin)*0.001,
|
||||
timeDiff(&ftUserBegin, &ftUserEnd),
|
||||
@@ -726,7 +729,13 @@ static void interrupt_handler(int NotUsed){
|
||||
** This is the callback routine that the shell
|
||||
** invokes for each row of a query result.
|
||||
*/
|
||||
static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int *aiType){
|
||||
static int shell_callback(
|
||||
void *pArg,
|
||||
int nArg, /* Number of result columns */
|
||||
char **azArg, /* Text of each result column */
|
||||
char **azCol, /* Column names */
|
||||
int *aiType /* Column types */
|
||||
){
|
||||
int i;
|
||||
ShellState *p = (ShellState*)pArg;
|
||||
|
||||
@@ -1105,57 +1114,77 @@ static int display_stats(
|
||||
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Memory Used: %d (max %d) bytes\n", iCur, iHiwtr);
|
||||
fprintf(pArg->out,
|
||||
"Memory Used: %d (max %d) bytes\n",
|
||||
iCur, iHiwtr);
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Number of Outstanding Allocations: %d (max %d)\n", iCur, iHiwtr);
|
||||
fprintf(pArg->out, "Number of Outstanding Allocations: %d (max %d)\n",
|
||||
iCur, iHiwtr);
|
||||
if( pArg->shellFlgs & SHFLG_Pagecache ){
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Number of Pcache Pages Used: %d (max %d) pages\n", iCur, iHiwtr);
|
||||
fprintf(pArg->out,
|
||||
"Number of Pcache Pages Used: %d (max %d) pages\n",
|
||||
iCur, iHiwtr);
|
||||
}
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Number of Pcache Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr);
|
||||
fprintf(pArg->out,
|
||||
"Number of Pcache Overflow Bytes: %d (max %d) bytes\n",
|
||||
iCur, iHiwtr);
|
||||
if( pArg->shellFlgs & SHFLG_Scratch ){
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Number of Scratch Allocations Used: %d (max %d)\n", iCur, iHiwtr);
|
||||
fprintf(pArg->out, "Number of Scratch Allocations Used: %d (max %d)\n",
|
||||
iCur, iHiwtr);
|
||||
}
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Number of Scratch Overflow Bytes: %d (max %d) bytes\n", iCur, iHiwtr);
|
||||
fprintf(pArg->out,
|
||||
"Number of Scratch Overflow Bytes: %d (max %d) bytes\n",
|
||||
iCur, iHiwtr);
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Largest Allocation: %d bytes\n", iHiwtr);
|
||||
fprintf(pArg->out, "Largest Allocation: %d bytes\n",
|
||||
iHiwtr);
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Largest Pcache Allocation: %d bytes\n", iHiwtr);
|
||||
fprintf(pArg->out, "Largest Pcache Allocation: %d bytes\n",
|
||||
iHiwtr);
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Largest Scratch Allocation: %d bytes\n", iHiwtr);
|
||||
fprintf(pArg->out, "Largest Scratch Allocation: %d bytes\n",
|
||||
iHiwtr);
|
||||
#ifdef YYTRACKMAXSTACKDEPTH
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_status(SQLITE_STATUS_PARSER_STACK, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Deepest Parser Stack: %d (max %d)\n", iCur, iHiwtr);
|
||||
fprintf(pArg->out, "Deepest Parser Stack: %d (max %d)\n",
|
||||
iCur, iHiwtr);
|
||||
#endif
|
||||
}
|
||||
|
||||
if( pArg && pArg->out && db ){
|
||||
if( pArg->shellFlgs & SHFLG_Lookaside ){
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Lookaside Slots Used: %d (max %d)\n", iCur, iHiwtr);
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHiwtr, bReset);
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED,
|
||||
&iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Lookaside Slots Used: %d (max %d)\n",
|
||||
iCur, iHiwtr);
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT,
|
||||
&iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Successful lookaside attempts: %d\n", iHiwtr);
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur, &iHiwtr, bReset);
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE,
|
||||
&iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Lookaside failures due to size: %d\n", iHiwtr);
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur, &iHiwtr, bReset);
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL,
|
||||
&iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Lookaside failures due to OOM: %d\n", iHiwtr);
|
||||
}
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Pager Heap Usage: %d bytes\n", iCur); iHiwtr = iCur = -1;
|
||||
fprintf(pArg->out, "Pager Heap Usage: %d bytes\n",iCur);
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
|
||||
fprintf(pArg->out, "Page cache hits: %d\n", iCur);
|
||||
iHiwtr = iCur = -1;
|
||||
@@ -1166,18 +1195,19 @@ static int display_stats(
|
||||
fprintf(pArg->out, "Page cache writes: %d\n", iCur);
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Schema Heap Usage: %d bytes\n", iCur);
|
||||
fprintf(pArg->out, "Schema Heap Usage: %d bytes\n",iCur);
|
||||
iHiwtr = iCur = -1;
|
||||
sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
|
||||
fprintf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n", iCur);
|
||||
fprintf(pArg->out, "Statement Heap/Lookaside Usage: %d bytes\n",iCur);
|
||||
}
|
||||
|
||||
if( pArg && pArg->out && db && pArg->pStmt ){
|
||||
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset);
|
||||
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP,
|
||||
bReset);
|
||||
fprintf(pArg->out, "Fullscan Steps: %d\n", iCur);
|
||||
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
|
||||
fprintf(pArg->out, "Sort Operations: %d\n", iCur);
|
||||
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX, bReset);
|
||||
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX,bReset);
|
||||
fprintf(pArg->out, "Autoindex Inserts: %d\n", iCur);
|
||||
iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_VM_STEP, bReset);
|
||||
fprintf(pArg->out, "Virtual Machine Steps: %d\n", iCur);
|
||||
@@ -1221,8 +1251,9 @@ static void display_scanstats(
|
||||
sqlite3_stmt_scanstatus(p, i, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain);
|
||||
fprintf(pArg->out, "Loop %2d: %s\n", n, zExplain);
|
||||
rEstLoop *= rEst;
|
||||
fprintf(pArg->out, " nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n",
|
||||
nLoop, nVisit, (sqlite3_int64)rEstLoop, rEst
|
||||
fprintf(pArg->out,
|
||||
" nLoop=%-8lld nRow=%-8lld estRow=%-8lld estRow/Loop=%-8g\n",
|
||||
nLoop, nVisit, (sqlite3_int64)(rEstLoop+0.5), rEst
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1271,7 +1302,8 @@ static void explain_data_prepare(ShellState *p, sqlite3_stmt *pSql){
|
||||
|
||||
const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext",
|
||||
"NextIfOpen", "PrevIfOpen", 0 };
|
||||
const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead", "Rewind", 0 };
|
||||
const char *azYield[] = { "Yield", "SeekLT", "SeekGT", "RowSetRead",
|
||||
"Rewind", 0 };
|
||||
const char *azGoto[] = { "Goto", 0 };
|
||||
|
||||
/* Try to figure out if this is really an EXPLAIN statement. If this
|
||||
@@ -1384,7 +1416,8 @@ static int shell_exec(
|
||||
/* Show the EXPLAIN QUERY PLAN if .eqp is on */
|
||||
if( pArg && pArg->autoEQP ){
|
||||
sqlite3_stmt *pExplain;
|
||||
char *zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", sqlite3_sql(pStmt));
|
||||
char *zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s",
|
||||
sqlite3_sql(pStmt));
|
||||
rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
while( sqlite3_step(pExplain)==SQLITE_ROW ){
|
||||
@@ -3335,7 +3368,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
for(i=0; i<nPrintRow; i++){
|
||||
for(j=i; j<nRow; j+=nPrintRow){
|
||||
char *zSp = j<nPrintRow ? "" : " ";
|
||||
fprintf(p->out, "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
|
||||
fprintf(p->out, "%s%-*s", zSp, maxlen, azResult[j] ? azResult[j]:"");
|
||||
}
|
||||
fprintf(p->out, "\n");
|
||||
}
|
||||
@@ -3805,7 +3838,8 @@ static char *find_home_dir(void){
|
||||
static char *home_dir = NULL;
|
||||
if( home_dir ) return home_dir;
|
||||
|
||||
#if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) && !defined(__RTP__) && !defined(_WRS_KERNEL)
|
||||
#if !defined(_WIN32) && !defined(WIN32) && !defined(_WIN32_WCE) \
|
||||
&& !defined(__RTP__) && !defined(_WRS_KERNEL)
|
||||
{
|
||||
struct passwd *pwent;
|
||||
uid_t uid = getuid();
|
||||
@@ -4004,10 +4038,12 @@ int main(int argc, char **argv){
|
||||
char *zErrMsg = 0;
|
||||
ShellState data;
|
||||
const char *zInitFile = 0;
|
||||
char *zFirstCmd = 0;
|
||||
int i;
|
||||
int rc = 0;
|
||||
int warnInmemoryDb = 0;
|
||||
int readStdin = 1;
|
||||
int nCmd = 0;
|
||||
char **azCmd = 0;
|
||||
|
||||
#if USE_SYSTEM_SQLITE+0!=1
|
||||
if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){
|
||||
@@ -4027,6 +4063,18 @@ int main(int argc, char **argv){
|
||||
signal(SIGINT, interrupt_handler);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_SHELL_DBNAME_PROC
|
||||
{
|
||||
/* If the SQLITE_SHELL_DBNAME_PROC macro is defined, then it is the name
|
||||
** of a C-function that will provide the name of the database file. Use
|
||||
** this compile-time option to embed this shell program in larger
|
||||
** applications. */
|
||||
extern void SQLITE_SHELL_DBNAME_PROC(const char**);
|
||||
SQLITE_SHELL_DBNAME_PROC(&data.zDbFilename);
|
||||
warnInmemoryDb = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Do an initial pass through the command-line argument to locate
|
||||
** the name of the database file, the name of the initialization file,
|
||||
** the size of the alternative malloc heap,
|
||||
@@ -4038,15 +4086,18 @@ int main(int argc, char **argv){
|
||||
if( z[0]!='-' ){
|
||||
if( data.zDbFilename==0 ){
|
||||
data.zDbFilename = z;
|
||||
continue;
|
||||
}else{
|
||||
/* Excesss arguments are interpreted as SQL (or dot-commands) and
|
||||
** mean that nothing is read from stdin */
|
||||
readStdin = 0;
|
||||
nCmd++;
|
||||
azCmd = realloc(azCmd, sizeof(azCmd[0])*nCmd);
|
||||
if( azCmd==0 ){
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
azCmd[nCmd-1] = z;
|
||||
}
|
||||
if( zFirstCmd==0 ){
|
||||
zFirstCmd = z;
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr,"%s: Error: too many options: \"%s\"\n", Argv0, argv[i]);
|
||||
fprintf(stderr,"Use -help for a list of options.\n");
|
||||
return 1;
|
||||
}
|
||||
if( z[1]=='-' ) z++;
|
||||
if( strcmp(z,"-separator")==0
|
||||
@@ -4136,11 +4187,6 @@ int main(int argc, char **argv){
|
||||
#else
|
||||
fprintf(stderr,"%s: Error: no database filename specified\n", Argv0);
|
||||
return 1;
|
||||
#endif
|
||||
#ifdef SQLITE_SHELL_DBNAME_PROC
|
||||
{ extern void SQLITE_SHELL_DBNAME_PROC(const char**);
|
||||
SQLITE_SHELL_DBNAME_PROC(&data.zDbFilename);
|
||||
warnInmemoryDb = 0; }
|
||||
#endif
|
||||
}
|
||||
data.out = stdout;
|
||||
@@ -4238,6 +4284,10 @@ int main(int argc, char **argv){
|
||||
}else if( strcmp(z,"-help")==0 ){
|
||||
usage(1);
|
||||
}else if( strcmp(z,"-cmd")==0 ){
|
||||
/* Run commands that follow -cmd first and separately from commands
|
||||
** that simply appear on the command-line. This seems goofy. It would
|
||||
** be better if all commands ran in the order that they appear. But
|
||||
** we retain the goofy behavior for historical compatibility. */
|
||||
if( i==argc-1 ) break;
|
||||
z = cmdline_option_value(argc,argv,++i);
|
||||
if( z[0]=='.' ){
|
||||
@@ -4261,23 +4311,28 @@ int main(int argc, char **argv){
|
||||
}
|
||||
}
|
||||
|
||||
if( zFirstCmd ){
|
||||
/* Run just the command that follows the database name
|
||||
if( !readStdin ){
|
||||
/* Run all arguments that do not begin with '-' as if they were separate
|
||||
** command-line inputs, except for the argToSkip argument which contains
|
||||
** the database filename.
|
||||
*/
|
||||
if( zFirstCmd[0]=='.' ){
|
||||
rc = do_meta_command(zFirstCmd, &data);
|
||||
if( rc==2 ) rc = 0;
|
||||
}else{
|
||||
open_db(&data, 0);
|
||||
rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg);
|
||||
if( zErrMsg!=0 ){
|
||||
fprintf(stderr,"Error: %s\n", zErrMsg);
|
||||
return rc!=0 ? rc : 1;
|
||||
}else if( rc!=0 ){
|
||||
fprintf(stderr,"Error: unable to process SQL \"%s\"\n", zFirstCmd);
|
||||
return rc;
|
||||
for(i=0; i<nCmd; i++){
|
||||
if( azCmd[i][0]=='.' ){
|
||||
rc = do_meta_command(azCmd[i], &data);
|
||||
if( rc ) return rc==2 ? 0 : rc;
|
||||
}else{
|
||||
open_db(&data, 0);
|
||||
rc = shell_exec(data.db, azCmd[i], shell_callback, &data, &zErrMsg);
|
||||
if( zErrMsg!=0 ){
|
||||
fprintf(stderr,"Error: %s\n", zErrMsg);
|
||||
return rc!=0 ? rc : 1;
|
||||
}else if( rc!=0 ){
|
||||
fprintf(stderr,"Error: unable to process SQL: %s\n", azCmd[i]);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(azCmd);
|
||||
}else{
|
||||
/* Run commands received from standard input
|
||||
*/
|
||||
|
||||
+233
-194
@@ -52,7 +52,7 @@ extern "C" {
|
||||
/*
|
||||
** These no-op macros are used in front of interfaces to mark those
|
||||
** interfaces as either deprecated or experimental. New applications
|
||||
** should not use deprecated interfaces - they are support for backwards
|
||||
** should not use deprecated interfaces - they are supported for backwards
|
||||
** compatibility only. Application writers should be aware that
|
||||
** experimental interfaces are subject to change in point releases.
|
||||
**
|
||||
@@ -1216,7 +1216,7 @@ struct sqlite3_vfs {
|
||||
** </ul>
|
||||
**
|
||||
** When unlocking, the same SHARED or EXCLUSIVE flag must be supplied as
|
||||
** was given no the corresponding lock.
|
||||
** was given on the corresponding lock.
|
||||
**
|
||||
** The xShmLock method can transition between unlocked and SHARED or
|
||||
** between unlocked and EXCLUSIVE. It cannot transition between SHARED
|
||||
@@ -1519,8 +1519,8 @@ struct sqlite3_mem_methods {
|
||||
** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt>
|
||||
** <dd> ^The SQLITE_CONFIG_MEMSTATUS option takes single argument of type int,
|
||||
** interpreted as a boolean, which enables or disables the collection of
|
||||
** memory allocation statistics. ^(When memory allocation statistics are disabled, the
|
||||
** following SQLite interfaces become non-operational:
|
||||
** memory allocation statistics. ^(When memory allocation statistics are
|
||||
** disabled, the following SQLite interfaces become non-operational:
|
||||
** <ul>
|
||||
** <li> [sqlite3_memory_used()]
|
||||
** <li> [sqlite3_memory_highwater()]
|
||||
@@ -1561,7 +1561,8 @@ struct sqlite3_mem_methods {
|
||||
** This configuration should not be used if an application-define page
|
||||
** cache implementation is loaded using the [SQLITE_CONFIG_PCACHE2]
|
||||
** configuration option.
|
||||
** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to 8-byte aligned
|
||||
** ^There are three arguments to SQLITE_CONFIG_PAGECACHE: A pointer to
|
||||
** 8-byte aligned
|
||||
** memory, the size of each page buffer (sz), and the number of pages (N).
|
||||
** The sz argument should be the size of the largest database page
|
||||
** (a power of two between 512 and 32768) plus some extra bytes for each
|
||||
@@ -1581,15 +1582,18 @@ struct sqlite3_mem_methods {
|
||||
** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt>
|
||||
** <dd> ^The SQLITE_CONFIG_HEAP option specifies a static memory buffer
|
||||
** that SQLite will use for all of its dynamic memory allocation needs
|
||||
** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE].
|
||||
** beyond those provided for by [SQLITE_CONFIG_SCRATCH] and
|
||||
** [SQLITE_CONFIG_PAGECACHE].
|
||||
** ^The SQLITE_CONFIG_HEAP option is only available if SQLite is compiled
|
||||
** with either [SQLITE_ENABLE_MEMSYS3] or [SQLITE_ENABLE_MEMSYS5] and returns
|
||||
** [SQLITE_ERROR] if invoked otherwise.
|
||||
** ^There are three arguments to SQLITE_CONFIG_HEAP:
|
||||
** An 8-byte aligned pointer to the memory,
|
||||
** the number of bytes in the memory buffer, and the minimum allocation size.
|
||||
** ^If the first pointer (the memory pointer) is NULL, then SQLite reverts
|
||||
** to using its default memory allocator (the system malloc() implementation),
|
||||
** undoing any prior invocation of [SQLITE_CONFIG_MALLOC]. ^If the
|
||||
** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or
|
||||
** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
|
||||
** memory pointer is not NULL then the alternative memory
|
||||
** allocator is engaged to handle all of SQLites memory allocation needs.
|
||||
** The first pointer (the memory pointer) must be aligned to an 8-byte
|
||||
** boundary or subsequent behavior of SQLite will be undefined.
|
||||
@@ -1599,9 +1603,9 @@ struct sqlite3_mem_methods {
|
||||
** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt>
|
||||
** <dd> ^(The SQLITE_CONFIG_MUTEX option takes a single argument which is a
|
||||
** pointer to an instance of the [sqlite3_mutex_methods] structure.
|
||||
** The argument specifies alternative low-level mutex routines to be used in place
|
||||
** the mutex routines built into SQLite.)^ ^SQLite makes a copy of the
|
||||
** content of the [sqlite3_mutex_methods] structure before the call to
|
||||
** The argument specifies alternative low-level mutex routines to be used
|
||||
** in place the mutex routines built into SQLite.)^ ^SQLite makes a copy of
|
||||
** the content of the [sqlite3_mutex_methods] structure before the call to
|
||||
** [sqlite3_config()] returns. ^If SQLite is compiled with
|
||||
** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then
|
||||
** the entire mutexing subsystem is omitted from the build and hence calls to
|
||||
@@ -1639,8 +1643,8 @@ struct sqlite3_mem_methods {
|
||||
**
|
||||
** [[SQLITE_CONFIG_GETPCACHE2]] <dt>SQLITE_CONFIG_GETPCACHE2</dt>
|
||||
** <dd> ^(The SQLITE_CONFIG_GETPCACHE2 option takes a single argument which
|
||||
** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies of the current
|
||||
** page cache implementation into that object.)^ </dd>
|
||||
** is a pointer to an [sqlite3_pcache_methods2] object. SQLite copies of
|
||||
** the current page cache implementation into that object.)^ </dd>
|
||||
**
|
||||
** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt>
|
||||
** <dd> The SQLITE_CONFIG_LOG option is used to configure the SQLite
|
||||
@@ -1665,8 +1669,9 @@ struct sqlite3_mem_methods {
|
||||
** [[SQLITE_CONFIG_URI]] <dt>SQLITE_CONFIG_URI
|
||||
** <dd>^(The SQLITE_CONFIG_URI option takes a single argument of type int.
|
||||
** If non-zero, then URI handling is globally enabled. If the parameter is zero,
|
||||
** then URI handling is globally disabled.)^ ^If URI handling is globally enabled,
|
||||
** all filenames passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or
|
||||
** then URI handling is globally disabled.)^ ^If URI handling is globally
|
||||
** enabled, all filenames passed to [sqlite3_open()], [sqlite3_open_v2()],
|
||||
** [sqlite3_open16()] or
|
||||
** specified as part of [ATTACH] commands are interpreted as URIs, regardless
|
||||
** of whether or not the [SQLITE_OPEN_URI] flag is set when the database
|
||||
** connection is opened. ^If it is globally disabled, filenames are
|
||||
@@ -1719,8 +1724,8 @@ struct sqlite3_mem_methods {
|
||||
** ^The default setting can be overridden by each database connection using
|
||||
** either the [PRAGMA mmap_size] command, or by using the
|
||||
** [SQLITE_FCNTL_MMAP_SIZE] file control. ^(The maximum allowed mmap size
|
||||
** cannot be changed at run-time. Nor may the maximum allowed mmap size
|
||||
** exceed the compile-time maximum mmap size set by the
|
||||
** will be silently truncated if necessary so that it does not exceed the
|
||||
** compile-time maximum mmap size set by the
|
||||
** [SQLITE_MAX_MMAP_SIZE] compile-time option.)^
|
||||
** ^If either argument to this option is negative, then that argument is
|
||||
** changed to its compile-time default.
|
||||
@@ -1728,8 +1733,8 @@ struct sqlite3_mem_methods {
|
||||
** [[SQLITE_CONFIG_WIN32_HEAPSIZE]]
|
||||
** <dt>SQLITE_CONFIG_WIN32_HEAPSIZE
|
||||
** <dd>^The SQLITE_CONFIG_WIN32_HEAPSIZE option is only available if SQLite is
|
||||
** compiled for Windows with the [SQLITE_WIN32_MALLOC] pre-processor macro defined.
|
||||
** ^SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value
|
||||
** compiled for Windows with the [SQLITE_WIN32_MALLOC] pre-processor macro
|
||||
** defined. ^SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value
|
||||
** that specifies the maximum size of the created heap.
|
||||
** </dl>
|
||||
**
|
||||
@@ -1737,8 +1742,8 @@ struct sqlite3_mem_methods {
|
||||
** <dt>SQLITE_CONFIG_PCACHE_HDRSZ
|
||||
** <dd>^The SQLITE_CONFIG_PCACHE_HDRSZ option takes a single parameter which
|
||||
** is a pointer to an integer and writes into that integer the number of extra
|
||||
** bytes per page required for each page in [SQLITE_CONFIG_PAGECACHE]. The amount of
|
||||
** extra space required can change depending on the compiler,
|
||||
** bytes per page required for each page in [SQLITE_CONFIG_PAGECACHE].
|
||||
** The amount of extra space required can change depending on the compiler,
|
||||
** target platform, and SQLite version.
|
||||
** </dl>
|
||||
*/
|
||||
@@ -2042,6 +2047,7 @@ int sqlite3_complete16(const void *sql);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors
|
||||
** KEYWORDS: {busy-handler callback} {busy handler}
|
||||
**
|
||||
** ^The sqlite3_busy_handler(D,X,P) routine sets a callback function X
|
||||
** that might be invoked with argument P whenever
|
||||
@@ -2058,7 +2064,7 @@ int sqlite3_complete16(const void *sql);
|
||||
** ^The first argument to the busy handler is a copy of the void* pointer which
|
||||
** is the third argument to sqlite3_busy_handler(). ^The second argument to
|
||||
** the busy handler callback is the number of times that the busy handler has
|
||||
** been invoked for the same locking event. ^If the
|
||||
** been invoked previously for the same locking event. ^If the
|
||||
** busy callback returns 0, then no additional attempts are made to
|
||||
** access the database and [SQLITE_BUSY] is returned
|
||||
** to the application.
|
||||
@@ -4162,9 +4168,9 @@ int sqlite3_create_function_v2(
|
||||
** These constant define integer codes that represent the various
|
||||
** text encodings supported by SQLite.
|
||||
*/
|
||||
#define SQLITE_UTF8 1
|
||||
#define SQLITE_UTF16LE 2
|
||||
#define SQLITE_UTF16BE 3
|
||||
#define SQLITE_UTF8 1 /* IMP: R-37514-35566 */
|
||||
#define SQLITE_UTF16LE 2 /* IMP: R-03371-37637 */
|
||||
#define SQLITE_UTF16BE 3 /* IMP: R-51971-34154 */
|
||||
#define SQLITE_UTF16 4 /* Use native byte order */
|
||||
#define SQLITE_ANY 5 /* Deprecated */
|
||||
#define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */
|
||||
@@ -4513,7 +4519,8 @@ typedef void (*sqlite3_destructor_type)(void*);
|
||||
** the [sqlite3_context] pointer, the results are undefined.
|
||||
*/
|
||||
void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
|
||||
void sqlite3_result_blob64(sqlite3_context*,const void*,sqlite3_uint64,void(*)(void*));
|
||||
void sqlite3_result_blob64(sqlite3_context*,const void*,
|
||||
sqlite3_uint64,void(*)(void*));
|
||||
void sqlite3_result_double(sqlite3_context*, double);
|
||||
void sqlite3_result_error(sqlite3_context*, const char*, int);
|
||||
void sqlite3_result_error16(sqlite3_context*, const void*, int);
|
||||
@@ -5655,26 +5662,42 @@ typedef struct sqlite3_blob sqlite3_blob;
|
||||
** SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
|
||||
** </pre>)^
|
||||
**
|
||||
** ^(Parameter zDb is not the filename that contains the database, but
|
||||
** rather the symbolic name of the database. For attached databases, this is
|
||||
** the name that appears after the AS keyword in the [ATTACH] statement.
|
||||
** For the main database file, the database name is "main". For TEMP
|
||||
** tables, the database name is "temp".)^
|
||||
**
|
||||
** ^If the flags parameter is non-zero, then the BLOB is opened for read
|
||||
** and write access. ^If it is zero, the BLOB is opened for read access.
|
||||
** ^It is not possible to open a column that is part of an index or primary
|
||||
** key for writing. ^If [foreign key constraints] are enabled, it is
|
||||
** not possible to open a column that is part of a [child key] for writing.
|
||||
** and write access. ^If the flags parameter is zero, the BLOB is opened for
|
||||
** read-only access.
|
||||
**
|
||||
** ^Note that the database name is not the filename that contains
|
||||
** the database but rather the symbolic name of the database that
|
||||
** appears after the AS keyword when the database is connected using [ATTACH].
|
||||
** ^For the main database file, the database name is "main".
|
||||
** ^For TEMP tables, the database name is "temp".
|
||||
** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored
|
||||
** in *ppBlob. Otherwise an [error code] is returned and, unless the error
|
||||
** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided
|
||||
** the API is not misused, it is always safe to call [sqlite3_blob_close()]
|
||||
** on *ppBlob after this function it returns.
|
||||
**
|
||||
** This function fails with SQLITE_ERROR if any of the following are true:
|
||||
** <ul>
|
||||
** <li> ^(Database zDb does not exist)^,
|
||||
** <li> ^(Table zTable does not exist within database zDb)^,
|
||||
** <li> ^(Table zTable is a WITHOUT ROWID table)^,
|
||||
** <li> ^(Column zColumn does not exist)^,
|
||||
** <li> ^(Row iRow is not present in the table)^,
|
||||
** <li> ^(The specified column of row iRow contains a value that is not
|
||||
** a TEXT or BLOB value)^,
|
||||
** <li> ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE
|
||||
** constraint and the blob is being opened for read/write access)^,
|
||||
** <li> ^([foreign key constraints | Foreign key constraints] are enabled,
|
||||
** column zColumn is part of a [child key] definition and the blob is
|
||||
** being opened for read/write access)^.
|
||||
** </ul>
|
||||
**
|
||||
** ^Unless it returns SQLITE_MISUSE, this function sets the
|
||||
** [database connection] error code and message accessible via
|
||||
** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
|
||||
**
|
||||
** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is written
|
||||
** to *ppBlob. Otherwise an [error code] is returned and *ppBlob is set
|
||||
** to be a null pointer.)^
|
||||
** ^This function sets the [database connection] error code and message
|
||||
** accessible via [sqlite3_errcode()] and [sqlite3_errmsg()] and related
|
||||
** functions. ^Note that the *ppBlob variable is always initialized in a
|
||||
** way that makes it safe to invoke [sqlite3_blob_close()] on *ppBlob
|
||||
** regardless of the success or failure of this routine.
|
||||
**
|
||||
** ^(If the row that a BLOB handle points to is modified by an
|
||||
** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects
|
||||
@@ -5692,13 +5715,9 @@ typedef struct sqlite3_blob sqlite3_blob;
|
||||
** interface. Use the [UPDATE] SQL command to change the size of a
|
||||
** blob.
|
||||
**
|
||||
** ^The [sqlite3_blob_open()] interface will fail for a [WITHOUT ROWID]
|
||||
** table. Incremental BLOB I/O is not possible on [WITHOUT ROWID] tables.
|
||||
**
|
||||
** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces
|
||||
** and the built-in [zeroblob] SQL function can be used, if desired,
|
||||
** to create an empty, zero-filled blob in which to read or write using
|
||||
** this interface.
|
||||
** and the built-in [zeroblob] SQL function may be used to create a
|
||||
** zero-filled blob to read or write using the incremental-blob interface.
|
||||
**
|
||||
** To avoid a resource leak, every open [BLOB handle] should eventually
|
||||
** be released by a call to [sqlite3_blob_close()].
|
||||
@@ -5740,24 +5759,22 @@ SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
|
||||
/*
|
||||
** CAPI3REF: Close A BLOB Handle
|
||||
**
|
||||
** ^Closes an open [BLOB handle].
|
||||
** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed
|
||||
** unconditionally. Even if this routine returns an error code, the
|
||||
** handle is still closed.)^
|
||||
**
|
||||
** ^Closing a BLOB shall cause the current transaction to commit
|
||||
** if there are no other BLOBs, no pending prepared statements, and the
|
||||
** database connection is in [autocommit mode].
|
||||
** ^If any writes were made to the BLOB, they might be held in cache
|
||||
** until the close operation if they will fit.
|
||||
** ^If the blob handle being closed was opened for read-write access, and if
|
||||
** the database is in auto-commit mode and there are no other open read-write
|
||||
** blob handles or active write statements, the current transaction is
|
||||
** committed. ^If an error occurs while committing the transaction, an error
|
||||
** code is returned and the transaction rolled back.
|
||||
**
|
||||
** ^(Closing the BLOB often forces the changes
|
||||
** out to disk and so if any I/O errors occur, they will likely occur
|
||||
** at the time when the BLOB is closed. Any errors that occur during
|
||||
** closing are reported as a non-zero return value.)^
|
||||
**
|
||||
** ^(The BLOB is closed unconditionally. Even if this routine returns
|
||||
** an error code, the BLOB is still closed.)^
|
||||
**
|
||||
** ^Calling this routine with a null pointer (such as would be returned
|
||||
** by a failed call to [sqlite3_blob_open()]) is a harmless no-op.
|
||||
** Calling this function with an argument that is not a NULL pointer or an
|
||||
** open blob handle results in undefined behaviour. ^Calling this routine
|
||||
** with a null pointer (such as would be returned by a failed call to
|
||||
** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function
|
||||
** is passed a valid open blob handle, the values returned by the
|
||||
** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning.
|
||||
*/
|
||||
int sqlite3_blob_close(sqlite3_blob *);
|
||||
|
||||
@@ -5807,21 +5824,27 @@ int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
|
||||
/*
|
||||
** CAPI3REF: Write Data Into A BLOB Incrementally
|
||||
**
|
||||
** ^This function is used to write data into an open [BLOB handle] from a
|
||||
** caller-supplied buffer. ^N bytes of data are copied from the buffer Z
|
||||
** into the open BLOB, starting at offset iOffset.
|
||||
** ^(This function is used to write data into an open [BLOB handle] from a
|
||||
** caller-supplied buffer. N bytes of data are copied from the buffer Z
|
||||
** into the open BLOB, starting at offset iOffset.)^
|
||||
**
|
||||
** ^(On success, sqlite3_blob_write() returns SQLITE_OK.
|
||||
** Otherwise, an [error code] or an [extended error code] is returned.)^
|
||||
** ^Unless SQLITE_MISUSE is returned, this function sets the
|
||||
** [database connection] error code and message accessible via
|
||||
** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions.
|
||||
**
|
||||
** ^If the [BLOB handle] passed as the first argument was not opened for
|
||||
** writing (the flags parameter to [sqlite3_blob_open()] was zero),
|
||||
** this function returns [SQLITE_READONLY].
|
||||
**
|
||||
** ^This function may only modify the contents of the BLOB; it is
|
||||
** This function may only modify the contents of the BLOB; it is
|
||||
** not possible to increase the size of a BLOB using this API.
|
||||
** ^If offset iOffset is less than N bytes from the end of the BLOB,
|
||||
** [SQLITE_ERROR] is returned and no data is written. ^If N is
|
||||
** less than zero [SQLITE_ERROR] is returned and no data is written.
|
||||
** The size of the BLOB (and hence the maximum value of N+iOffset)
|
||||
** can be determined using the [sqlite3_blob_bytes()] interface.
|
||||
** [SQLITE_ERROR] is returned and no data is written. The size of the
|
||||
** BLOB (and hence the maximum value of N+iOffset) can be determined
|
||||
** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less
|
||||
** than zero [SQLITE_ERROR] is returned and no data is written.
|
||||
**
|
||||
** ^An attempt to write to an expired [BLOB handle] fails with an
|
||||
** error code of [SQLITE_ABORT]. ^Writes to the BLOB that occurred
|
||||
@@ -5830,9 +5853,6 @@ int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);
|
||||
** have been overwritten by the statement that expired the BLOB handle
|
||||
** or by other independent statements.
|
||||
**
|
||||
** ^(On success, sqlite3_blob_write() returns SQLITE_OK.
|
||||
** Otherwise, an [error code] or an [extended error code] is returned.)^
|
||||
**
|
||||
** This routine only works on a [BLOB handle] which has been created
|
||||
** by a prior successful call to [sqlite3_blob_open()] and which has not
|
||||
** been closed by [sqlite3_blob_close()]. Passing any other pointer in
|
||||
@@ -5885,34 +5905,34 @@ int sqlite3_vfs_unregister(sqlite3_vfs*);
|
||||
**
|
||||
** The SQLite source code contains multiple implementations
|
||||
** of these mutex routines. An appropriate implementation
|
||||
** is selected automatically at compile-time. ^(The following
|
||||
** is selected automatically at compile-time. The following
|
||||
** implementations are available in the SQLite core:
|
||||
**
|
||||
** <ul>
|
||||
** <li> SQLITE_MUTEX_PTHREADS
|
||||
** <li> SQLITE_MUTEX_W32
|
||||
** <li> SQLITE_MUTEX_NOOP
|
||||
** </ul>)^
|
||||
** </ul>
|
||||
**
|
||||
** ^The SQLITE_MUTEX_NOOP implementation is a set of routines
|
||||
** The SQLITE_MUTEX_NOOP implementation is a set of routines
|
||||
** that does no real locking and is appropriate for use in
|
||||
** a single-threaded application. ^The SQLITE_MUTEX_PTHREADS and
|
||||
** a single-threaded application. The SQLITE_MUTEX_PTHREADS and
|
||||
** SQLITE_MUTEX_W32 implementations are appropriate for use on Unix
|
||||
** and Windows.
|
||||
**
|
||||
** ^(If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
|
||||
** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
|
||||
** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex
|
||||
** implementation is included with the library. In this case the
|
||||
** application must supply a custom mutex implementation using the
|
||||
** [SQLITE_CONFIG_MUTEX] option of the sqlite3_config() function
|
||||
** before calling sqlite3_initialize() or any other public sqlite3_
|
||||
** function that calls sqlite3_initialize().)^
|
||||
** function that calls sqlite3_initialize().
|
||||
**
|
||||
** ^The sqlite3_mutex_alloc() routine allocates a new
|
||||
** mutex and returns a pointer to it. ^If it returns NULL
|
||||
** that means that a mutex could not be allocated. ^SQLite
|
||||
** will unwind its stack and return an error. ^(The argument
|
||||
** to sqlite3_mutex_alloc() is one of these integer constants:
|
||||
** mutex and returns a pointer to it. ^The sqlite3_mutex_alloc()
|
||||
** routine returns NULL if it is unable to allocate the requested
|
||||
** mutex. The argument to sqlite3_mutex_alloc() must one of these
|
||||
** integer constants:
|
||||
**
|
||||
** <ul>
|
||||
** <li> SQLITE_MUTEX_FAST
|
||||
@@ -5925,7 +5945,8 @@ int sqlite3_vfs_unregister(sqlite3_vfs*);
|
||||
** <li> SQLITE_MUTEX_STATIC_PMEM
|
||||
** <li> SQLITE_MUTEX_STATIC_APP1
|
||||
** <li> SQLITE_MUTEX_STATIC_APP2
|
||||
** </ul>)^
|
||||
** <li> SQLITE_MUTEX_STATIC_APP3
|
||||
** </ul>
|
||||
**
|
||||
** ^The first two constants (SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE)
|
||||
** cause sqlite3_mutex_alloc() to create
|
||||
@@ -5933,14 +5954,14 @@ int sqlite3_vfs_unregister(sqlite3_vfs*);
|
||||
** is used but not necessarily so when SQLITE_MUTEX_FAST is used.
|
||||
** The mutex implementation does not need to make a distinction
|
||||
** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
|
||||
** not want to. ^SQLite will only request a recursive mutex in
|
||||
** cases where it really needs one. ^If a faster non-recursive mutex
|
||||
** not want to. SQLite will only request a recursive mutex in
|
||||
** cases where it really needs one. If a faster non-recursive mutex
|
||||
** implementation is available on the host platform, the mutex subsystem
|
||||
** might return such a mutex in response to SQLITE_MUTEX_FAST.
|
||||
**
|
||||
** ^The other allowed parameters to sqlite3_mutex_alloc() (anything other
|
||||
** than SQLITE_MUTEX_FAST and SQLITE_MUTEX_RECURSIVE) each return
|
||||
** a pointer to a static preexisting mutex. ^Six static mutexes are
|
||||
** a pointer to a static preexisting mutex. ^Nine static mutexes are
|
||||
** used by the current version of SQLite. Future versions of SQLite
|
||||
** may add additional static mutexes. Static mutexes are for internal
|
||||
** use by SQLite only. Applications that use SQLite mutexes should
|
||||
@@ -5949,16 +5970,13 @@ int sqlite3_vfs_unregister(sqlite3_vfs*);
|
||||
**
|
||||
** ^Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
|
||||
** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
|
||||
** returns a different mutex on every call. ^But for the static
|
||||
** returns a different mutex on every call. ^For the static
|
||||
** mutex types, the same mutex is returned on every call that has
|
||||
** the same type number.
|
||||
**
|
||||
** ^The sqlite3_mutex_free() routine deallocates a previously
|
||||
** allocated dynamic mutex. ^SQLite is careful to deallocate every
|
||||
** dynamic mutex that it allocates. The dynamic mutexes must not be in
|
||||
** use when they are deallocated. Attempting to deallocate a static
|
||||
** mutex results in undefined behavior. ^SQLite never deallocates
|
||||
** a static mutex.
|
||||
** allocated dynamic mutex. Attempting to deallocate a static
|
||||
** mutex results in undefined behavior.
|
||||
**
|
||||
** ^The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
|
||||
** to enter a mutex. ^If another thread is already within the mutex,
|
||||
@@ -5966,23 +5984,21 @@ int sqlite3_vfs_unregister(sqlite3_vfs*);
|
||||
** SQLITE_BUSY. ^The sqlite3_mutex_try() interface returns [SQLITE_OK]
|
||||
** upon successful entry. ^(Mutexes created using
|
||||
** SQLITE_MUTEX_RECURSIVE can be entered multiple times by the same thread.
|
||||
** In such cases the,
|
||||
** In such cases, the
|
||||
** mutex must be exited an equal number of times before another thread
|
||||
** can enter.)^ ^(If the same thread tries to enter any other
|
||||
** kind of mutex more than once, the behavior is undefined.
|
||||
** SQLite will never exhibit
|
||||
** such behavior in its own use of mutexes.)^
|
||||
** can enter.)^ If the same thread tries to enter any mutex other
|
||||
** than an SQLITE_MUTEX_RECURSIVE more than once, the behavior is undefined.
|
||||
**
|
||||
** ^(Some systems (for example, Windows 95) do not support the operation
|
||||
** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try()
|
||||
** will always return SQLITE_BUSY. The SQLite core only ever uses
|
||||
** sqlite3_mutex_try() as an optimization so this is acceptable behavior.)^
|
||||
** will always return SQLITE_BUSY. The SQLite core only ever uses
|
||||
** sqlite3_mutex_try() as an optimization so this is acceptable
|
||||
** behavior.)^
|
||||
**
|
||||
** ^The sqlite3_mutex_leave() routine exits a mutex that was
|
||||
** previously entered by the same thread. ^(The behavior
|
||||
** previously entered by the same thread. The behavior
|
||||
** is undefined if the mutex is not currently entered by the
|
||||
** calling thread or is not currently allocated. SQLite will
|
||||
** never do either.)^
|
||||
** calling thread or is not currently allocated.
|
||||
**
|
||||
** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or
|
||||
** sqlite3_mutex_leave() is a NULL pointer, then all three routines
|
||||
@@ -6003,9 +6019,9 @@ void sqlite3_mutex_leave(sqlite3_mutex*);
|
||||
** used to allocate and use mutexes.
|
||||
**
|
||||
** Usually, the default mutex implementations provided by SQLite are
|
||||
** sufficient, however the user has the option of substituting a custom
|
||||
** sufficient, however the application has the option of substituting a custom
|
||||
** implementation for specialized deployments or systems for which SQLite
|
||||
** does not provide a suitable implementation. In this case, the user
|
||||
** does not provide a suitable implementation. In this case, the application
|
||||
** creates and populates an instance of this structure to pass
|
||||
** to sqlite3_config() along with the [SQLITE_CONFIG_MUTEX] option.
|
||||
** Additionally, an instance of this structure can be used as an
|
||||
@@ -6046,13 +6062,13 @@ void sqlite3_mutex_leave(sqlite3_mutex*);
|
||||
** (i.e. it is acceptable to provide an implementation that segfaults if
|
||||
** it is passed a NULL pointer).
|
||||
**
|
||||
** The xMutexInit() method must be threadsafe. ^It must be harmless to
|
||||
** The xMutexInit() method must be threadsafe. It must be harmless to
|
||||
** invoke xMutexInit() multiple times within the same process and without
|
||||
** intervening calls to xMutexEnd(). Second and subsequent calls to
|
||||
** xMutexInit() must be no-ops.
|
||||
**
|
||||
** ^xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()]
|
||||
** and its associates). ^Similarly, xMutexAlloc() must not use SQLite memory
|
||||
** xMutexInit() must not use SQLite memory allocation ([sqlite3_malloc()]
|
||||
** and its associates). Similarly, xMutexAlloc() must not use SQLite memory
|
||||
** allocation for a static mutex. ^However xMutexAlloc() may use SQLite
|
||||
** memory allocation for a fast or recursive mutex.
|
||||
**
|
||||
@@ -6078,29 +6094,29 @@ struct sqlite3_mutex_methods {
|
||||
** CAPI3REF: Mutex Verification Routines
|
||||
**
|
||||
** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines
|
||||
** are intended for use inside assert() statements. ^The SQLite core
|
||||
** are intended for use inside assert() statements. The SQLite core
|
||||
** never uses these routines except inside an assert() and applications
|
||||
** are advised to follow the lead of the core. ^The SQLite core only
|
||||
** are advised to follow the lead of the core. The SQLite core only
|
||||
** provides implementations for these routines when it is compiled
|
||||
** with the SQLITE_DEBUG flag. ^External mutex implementations
|
||||
** with the SQLITE_DEBUG flag. External mutex implementations
|
||||
** are only required to provide these routines if SQLITE_DEBUG is
|
||||
** defined and if NDEBUG is not defined.
|
||||
**
|
||||
** ^These routines should return true if the mutex in their argument
|
||||
** These routines should return true if the mutex in their argument
|
||||
** is held or not held, respectively, by the calling thread.
|
||||
**
|
||||
** ^The implementation is not required to provide versions of these
|
||||
** The implementation is not required to provide versions of these
|
||||
** routines that actually work. If the implementation does not provide working
|
||||
** versions of these routines, it should at least provide stubs that always
|
||||
** return true so that one does not get spurious assertion failures.
|
||||
**
|
||||
** ^If the argument to sqlite3_mutex_held() is a NULL pointer then
|
||||
** If the argument to sqlite3_mutex_held() is a NULL pointer then
|
||||
** the routine should return 1. This seems counter-intuitive since
|
||||
** clearly the mutex cannot be held if it does not exist. But
|
||||
** the reason the mutex does not exist is because the build is not
|
||||
** using mutexes. And we do not want the assert() containing the
|
||||
** call to sqlite3_mutex_held() to fail, so a non-zero return is
|
||||
** the appropriate thing to do. ^The sqlite3_mutex_notheld()
|
||||
** the appropriate thing to do. The sqlite3_mutex_notheld()
|
||||
** interface should also return 1 when given a NULL pointer.
|
||||
*/
|
||||
#ifndef NDEBUG
|
||||
@@ -6833,6 +6849,10 @@ typedef struct sqlite3_backup sqlite3_backup;
|
||||
** must be different or else sqlite3_backup_init(D,N,S,M) will fail with
|
||||
** an error.
|
||||
**
|
||||
** ^A call to sqlite3_backup_init() will fail, returning SQLITE_ERROR, if
|
||||
** there is already a read or read-write transaction open on the
|
||||
** destination database.
|
||||
**
|
||||
** ^If an error occurs within sqlite3_backup_init(D,N,S,M), then NULL is
|
||||
** returned and an error code and error message are stored in the
|
||||
** destination [database connection] D.
|
||||
@@ -7226,97 +7246,114 @@ int sqlite3_wal_autocheckpoint(sqlite3 *db, int N);
|
||||
/*
|
||||
** CAPI3REF: Checkpoint a database
|
||||
**
|
||||
** ^The [sqlite3_wal_checkpoint(D,X)] interface causes database named X
|
||||
** on [database connection] D to be [checkpointed]. ^If X is NULL or an
|
||||
** empty string, then a checkpoint is run on all databases of
|
||||
** connection D. ^If the database connection D is not in
|
||||
** [WAL | write-ahead log mode] then this interface is a harmless no-op.
|
||||
** ^The [sqlite3_wal_checkpoint(D,X)] interface initiates a
|
||||
** [sqlite3_wal_checkpoint_v2|PASSIVE] checkpoint.
|
||||
** Use the [sqlite3_wal_checkpoint_v2()] interface to get a FULL
|
||||
** or RESET checkpoint.
|
||||
** ^(The sqlite3_wal_checkpoint(D,X) is equivalent to
|
||||
** [sqlite3_wal_checkpoint_v2](D,X,[SQLITE_CHECKPOINT_PASSIVE],0,0).)^
|
||||
**
|
||||
** ^The [wal_checkpoint pragma] can be used to invoke this interface
|
||||
** from SQL. ^The [sqlite3_wal_autocheckpoint()] interface and the
|
||||
** [wal_autocheckpoint pragma] can be used to cause this interface to be
|
||||
** run whenever the WAL reaches a certain size threshold.
|
||||
** In brief, sqlite3_wal_checkpoint(D,X) causes the content in the
|
||||
** [write-ahead log] for database X on [database connection] D to be
|
||||
** transferred into the database file and for the write-ahead log to
|
||||
** be reset. See the [checkpointing] documentation for addition
|
||||
** information.
|
||||
**
|
||||
** See also: [sqlite3_wal_checkpoint_v2()]
|
||||
** This interface used to be the only way to cause a checkpoint to
|
||||
** occur. But then the newer and more powerful [sqlite3_wal_checkpoint_v2()]
|
||||
** interface was added. This interface is retained for backwards
|
||||
** compatibility and as a convenience for applications that need to manually
|
||||
** start a callback but which do not need the full power (and corresponding
|
||||
** complication) of [sqlite3_wal_checkpoint_v2()].
|
||||
*/
|
||||
int sqlite3_wal_checkpoint(sqlite3 *db, const char *zDb);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Checkpoint a database
|
||||
**
|
||||
** Run a checkpoint operation on WAL database zDb attached to database
|
||||
** handle db. The specific operation is determined by the value of the
|
||||
** eMode parameter:
|
||||
** ^(The sqlite3_wal_checkpoint_v2(D,X,M,L,C) interface runs a checkpoint
|
||||
** operation on database X of [database connection] D in mode M. Status
|
||||
** information is written back into integers pointed to by L and C.)^
|
||||
** ^(The M parameter must be a valid [checkpoint mode]:)^
|
||||
**
|
||||
** <dl>
|
||||
** <dt>SQLITE_CHECKPOINT_PASSIVE<dd>
|
||||
** Checkpoint as many frames as possible without waiting for any database
|
||||
** readers or writers to finish. Sync the db file if all frames in the log
|
||||
** are checkpointed. This mode is the same as calling
|
||||
** sqlite3_wal_checkpoint(). The [sqlite3_busy_handler|busy-handler callback]
|
||||
** is never invoked.
|
||||
** ^Checkpoint as many frames as possible without waiting for any database
|
||||
** readers or writers to finish, then sync the database file if all frames
|
||||
** in the log were checkpointed. ^The [busy-handler callback]
|
||||
** is never invoked in the SQLITE_CHECKPOINT_PASSIVE mode.
|
||||
** ^On the other hand, passive mode might leave the checkpoint unfinished
|
||||
** if there are concurrent readers or writers.
|
||||
**
|
||||
** <dt>SQLITE_CHECKPOINT_FULL<dd>
|
||||
** This mode blocks (it invokes the
|
||||
** ^This mode blocks (it invokes the
|
||||
** [sqlite3_busy_handler|busy-handler callback]) until there is no
|
||||
** database writer and all readers are reading from the most recent database
|
||||
** snapshot. It then checkpoints all frames in the log file and syncs the
|
||||
** database file. This call blocks database writers while it is running,
|
||||
** but not database readers.
|
||||
** snapshot. ^It then checkpoints all frames in the log file and syncs the
|
||||
** database file. ^This mode blocks new database writers while it is pending,
|
||||
** but new database readers are allowed to continue unimpeded.
|
||||
**
|
||||
** <dt>SQLITE_CHECKPOINT_RESTART<dd>
|
||||
** This mode works the same way as SQLITE_CHECKPOINT_FULL, except after
|
||||
** checkpointing the log file it blocks (calls the
|
||||
** [sqlite3_busy_handler|busy-handler callback])
|
||||
** until all readers are reading from the database file only. This ensures
|
||||
** that the next client to write to the database file restarts the log file
|
||||
** from the beginning. This call blocks database writers while it is running,
|
||||
** but not database readers.
|
||||
** ^This mode works the same way as SQLITE_CHECKPOINT_FULL with the addition
|
||||
** that after checkpointing the log file it blocks (calls the
|
||||
** [busy-handler callback])
|
||||
** until all readers are reading from the database file only. ^This ensures
|
||||
** that the next writer will restart the log file from the beginning.
|
||||
** ^Like SQLITE_CHECKPOINT_FULL, this mode blocks new
|
||||
** database writer attempts while it is pending, but does not impede readers.
|
||||
**
|
||||
** <dt>SQLITE_CHECKPOINT_TRUNCATE<dd>
|
||||
** ^This mode works the same way as SQLITE_CHECKPOINT_RESTART with the
|
||||
** addition that it also truncates the log file to zero bytes just prior
|
||||
** to a successful return.
|
||||
** </dl>
|
||||
**
|
||||
** If pnLog is not NULL, then *pnLog is set to the total number of frames in
|
||||
** the log file before returning. If pnCkpt is not NULL, then *pnCkpt is set to
|
||||
** the total number of checkpointed frames (including any that were already
|
||||
** checkpointed when this function is called). *pnLog and *pnCkpt may be
|
||||
** populated even if sqlite3_wal_checkpoint_v2() returns other than SQLITE_OK.
|
||||
** If no values are available because of an error, they are both set to -1
|
||||
** before returning to communicate this to the caller.
|
||||
** ^If pnLog is not NULL, then *pnLog is set to the total number of frames in
|
||||
** the log file or to -1 if the checkpoint could not run because
|
||||
** of an error or because the database is not in [WAL mode]. ^If pnCkpt is not
|
||||
** NULL,then *pnCkpt is set to the total number of checkpointed frames in the
|
||||
** log file (including any that were already checkpointed before the function
|
||||
** was called) or to -1 if the checkpoint could not run due to an error or
|
||||
** because the database is not in WAL mode. ^Note that upon successful
|
||||
** completion of an SQLITE_CHECKPOINT_TRUNCATE, the log file will have been
|
||||
** truncated to zero bytes and so both *pnLog and *pnCkpt will be set to zero.
|
||||
**
|
||||
** All calls obtain an exclusive "checkpoint" lock on the database file. If
|
||||
** ^All calls obtain an exclusive "checkpoint" lock on the database file. ^If
|
||||
** any other process is running a checkpoint operation at the same time, the
|
||||
** lock cannot be obtained and SQLITE_BUSY is returned. Even if there is a
|
||||
** lock cannot be obtained and SQLITE_BUSY is returned. ^Even if there is a
|
||||
** busy-handler configured, it will not be invoked in this case.
|
||||
**
|
||||
** The SQLITE_CHECKPOINT_FULL and RESTART modes also obtain the exclusive
|
||||
** "writer" lock on the database file. If the writer lock cannot be obtained
|
||||
** immediately, and a busy-handler is configured, it is invoked and the writer
|
||||
** lock retried until either the busy-handler returns 0 or the lock is
|
||||
** successfully obtained. The busy-handler is also invoked while waiting for
|
||||
** database readers as described above. If the busy-handler returns 0 before
|
||||
** ^The SQLITE_CHECKPOINT_FULL, RESTART and TRUNCATE modes also obtain the
|
||||
** exclusive "writer" lock on the database file. ^If the writer lock cannot be
|
||||
** obtained immediately, and a busy-handler is configured, it is invoked and
|
||||
** the writer lock retried until either the busy-handler returns 0 or the lock
|
||||
** is successfully obtained. ^The busy-handler is also invoked while waiting for
|
||||
** database readers as described above. ^If the busy-handler returns 0 before
|
||||
** the writer lock is obtained or while waiting for database readers, the
|
||||
** checkpoint operation proceeds from that point in the same way as
|
||||
** SQLITE_CHECKPOINT_PASSIVE - checkpointing as many frames as possible
|
||||
** without blocking any further. SQLITE_BUSY is returned in this case.
|
||||
** without blocking any further. ^SQLITE_BUSY is returned in this case.
|
||||
**
|
||||
** If parameter zDb is NULL or points to a zero length string, then the
|
||||
** specified operation is attempted on all WAL databases. In this case the
|
||||
** values written to output parameters *pnLog and *pnCkpt are undefined. If
|
||||
** ^If parameter zDb is NULL or points to a zero length string, then the
|
||||
** specified operation is attempted on all WAL databases [attached] to
|
||||
** [database connection] db. In this case the
|
||||
** values written to output parameters *pnLog and *pnCkpt are undefined. ^If
|
||||
** an SQLITE_BUSY error is encountered when processing one or more of the
|
||||
** attached WAL databases, the operation is still attempted on any remaining
|
||||
** attached databases and SQLITE_BUSY is returned to the caller. If any other
|
||||
** attached databases and SQLITE_BUSY is returned at the end. ^If any other
|
||||
** error occurs while processing an attached database, processing is abandoned
|
||||
** and the error code returned to the caller immediately. If no error
|
||||
** and the error code is returned to the caller immediately. ^If no error
|
||||
** (SQLITE_BUSY or otherwise) is encountered while processing the attached
|
||||
** databases, SQLITE_OK is returned.
|
||||
**
|
||||
** If database zDb is the name of an attached database that is not in WAL
|
||||
** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. If
|
||||
** ^If database zDb is the name of an attached database that is not in WAL
|
||||
** mode, SQLITE_OK is returned and both *pnLog and *pnCkpt set to -1. ^If
|
||||
** zDb is not NULL (or a zero length string) and is not the name of any
|
||||
** attached database, SQLITE_ERROR is returned to the caller.
|
||||
**
|
||||
** ^Unless it returns SQLITE_MISUSE,
|
||||
** the sqlite3_wal_checkpoint_v2() interface
|
||||
** sets the error information that is queried by
|
||||
** [sqlite3_errcode()] and [sqlite3_errmsg()].
|
||||
**
|
||||
** ^The [PRAGMA wal_checkpoint] command can be used to invoke this interface
|
||||
** from SQL.
|
||||
*/
|
||||
int sqlite3_wal_checkpoint_v2(
|
||||
sqlite3 *db, /* Database handle */
|
||||
@@ -7327,16 +7364,18 @@ int sqlite3_wal_checkpoint_v2(
|
||||
);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Checkpoint operation parameters
|
||||
** CAPI3REF: Checkpoint Mode Values
|
||||
** KEYWORDS: {checkpoint mode}
|
||||
**
|
||||
** These constants can be used as the 3rd parameter to
|
||||
** [sqlite3_wal_checkpoint_v2()]. See the [sqlite3_wal_checkpoint_v2()]
|
||||
** documentation for additional information about the meaning and use of
|
||||
** each of these values.
|
||||
** These constants define all valid values for the "checkpoint mode" passed
|
||||
** as the third parameter to the [sqlite3_wal_checkpoint_v2()] interface.
|
||||
** See the [sqlite3_wal_checkpoint_v2()] documentation for details on the
|
||||
** meaning of each of these checkpoint modes.
|
||||
*/
|
||||
#define SQLITE_CHECKPOINT_PASSIVE 0
|
||||
#define SQLITE_CHECKPOINT_FULL 1
|
||||
#define SQLITE_CHECKPOINT_RESTART 2
|
||||
#define SQLITE_CHECKPOINT_PASSIVE 0 /* Do as much as possible w/o blocking */
|
||||
#define SQLITE_CHECKPOINT_FULL 1 /* Wait for writers, then checkpoint */
|
||||
#define SQLITE_CHECKPOINT_RESTART 2 /* Like FULL but wait for for readers */
|
||||
#define SQLITE_CHECKPOINT_TRUNCATE 3 /* Like RESTART but also truncate WAL */
|
||||
|
||||
/*
|
||||
** CAPI3REF: Virtual Table Interface Configuration
|
||||
@@ -7435,12 +7474,12 @@ int sqlite3_vtab_on_conflict(sqlite3 *);
|
||||
**
|
||||
** <dl>
|
||||
** [[SQLITE_SCANSTAT_NLOOP]] <dt>SQLITE_SCANSTAT_NLOOP</dt>
|
||||
** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be set to the
|
||||
** total number of times that the X-th loop has run.</dd>
|
||||
** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be
|
||||
** set to the total number of times that the X-th loop has run.</dd>
|
||||
**
|
||||
** [[SQLITE_SCANSTAT_NVISIT]] <dt>SQLITE_SCANSTAT_NVISIT</dt>
|
||||
** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be set to the
|
||||
** total number of rows examined by all iterations of the X-th loop.</dd>
|
||||
** <dd>^The [sqlite3_int64] variable pointed to by the T parameter will be set
|
||||
** to the total number of rows examined by all iterations of the X-th loop.</dd>
|
||||
**
|
||||
** [[SQLITE_SCANSTAT_EST]] <dt>SQLITE_SCANSTAT_EST</dt>
|
||||
** <dd>^The "double" variable pointed to by the T parameter will be set to the
|
||||
@@ -7451,14 +7490,14 @@ int sqlite3_vtab_on_conflict(sqlite3 *);
|
||||
** be the NLOOP value for the current loop.
|
||||
**
|
||||
** [[SQLITE_SCANSTAT_NAME]] <dt>SQLITE_SCANSTAT_NAME</dt>
|
||||
** <dd>^The "const char *" variable pointed to by the T parameter will be set to
|
||||
** a zero-terminated UTF-8 string containing the name of the index or table used
|
||||
** for the X-th loop.
|
||||
** <dd>^The "const char *" variable pointed to by the T parameter will be set
|
||||
** to a zero-terminated UTF-8 string containing the name of the index or table
|
||||
** used for the X-th loop.
|
||||
**
|
||||
** [[SQLITE_SCANSTAT_EXPLAIN]] <dt>SQLITE_SCANSTAT_EXPLAIN</dt>
|
||||
** <dd>^The "const char *" variable pointed to by the T parameter will be set to
|
||||
** a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN] description
|
||||
** for the X-th loop.
|
||||
** <dd>^The "const char *" variable pointed to by the T parameter will be set
|
||||
** to a zero-terminated UTF-8 string containing the [EXPLAIN QUERY PLAN]
|
||||
** description for the X-th loop.
|
||||
**
|
||||
** [[SQLITE_SCANSTAT_SELECTID]] <dt>SQLITE_SCANSTAT_SELECT</dt>
|
||||
** <dd>^The "int" variable pointed to by the T parameter will be set to the
|
||||
@@ -7481,8 +7520,8 @@ int sqlite3_vtab_on_conflict(sqlite3 *);
|
||||
** Return status data for a single loop within query pStmt.
|
||||
**
|
||||
** The "iScanStatusOp" parameter determines which status information to return.
|
||||
** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior of
|
||||
** this interface is undefined.
|
||||
** The "iScanStatusOp" must be one of the [scanstatus options] or the behavior
|
||||
** of this interface is undefined.
|
||||
** ^The requested measurement is written into a variable pointed to by
|
||||
** the "pOut" parameter.
|
||||
** Parameter "idx" identifies the specific loop to retrieve statistics for.
|
||||
|
||||
+7
-2
@@ -562,7 +562,7 @@ typedef INT8_TYPE i8; /* 1-byte signed integer */
|
||||
** gives a possible range of values of approximately 1.0e986 to 1e-986.
|
||||
** But the allowed values are "grainy". Not every value is representable.
|
||||
** For example, quantities 16 and 17 are both represented by a LogEst
|
||||
** of 40. However, since LogEst quantaties are suppose to be estimates,
|
||||
** of 40. However, since LogEst quantities are suppose to be estimates,
|
||||
** not exact values, this imprecision is not a problem.
|
||||
**
|
||||
** "LogEst" is short for "Logarithmic Estimate".
|
||||
@@ -1795,6 +1795,7 @@ struct Index {
|
||||
unsigned uniqNotNull:1; /* True if UNIQUE and NOT NULL for all columns */
|
||||
unsigned isResized:1; /* True if resizeIndexObject() has been called */
|
||||
unsigned isCovering:1; /* True if this is a covering index */
|
||||
unsigned noSkipScan:1; /* Do not try to use skip-scan if true */
|
||||
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
|
||||
int nSample; /* Number of elements in aSample[] */
|
||||
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
|
||||
@@ -2014,7 +2015,7 @@ struct Expr {
|
||||
/*
|
||||
** The following are the meanings of bits in the Expr.flags field.
|
||||
*/
|
||||
#define EP_FromJoin 0x000001 /* Originated in ON or USING clause of a join */
|
||||
#define EP_FromJoin 0x000001 /* Originates in ON/USING clause of outer join */
|
||||
#define EP_Agg 0x000002 /* Contains one or more aggregate functions */
|
||||
#define EP_Resolved 0x000004 /* IDs have been resolved to COLUMNs */
|
||||
#define EP_Error 0x000008 /* Expression contains one or more errors */
|
||||
@@ -2034,6 +2035,7 @@ struct Expr {
|
||||
#define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
|
||||
#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */
|
||||
#define EP_Constant 0x080000 /* Node is a constant */
|
||||
#define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */
|
||||
|
||||
/*
|
||||
** These macros can be used to test, set, or clear bits in the
|
||||
@@ -3451,6 +3453,9 @@ const char *sqlite3ErrName(int);
|
||||
|
||||
const char *sqlite3ErrStr(int);
|
||||
int sqlite3ReadSchema(Parse *pParse);
|
||||
#if defined(SQLITE_DEBUG)
|
||||
int sqlite3ValidCollSeq(const CollSeq*);
|
||||
#endif
|
||||
CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
|
||||
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
|
||||
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
|
||||
|
||||
@@ -3725,6 +3725,7 @@ static void init_all(Tcl_Interp *interp){
|
||||
extern int Sqlitetest9_Init(Tcl_Interp*);
|
||||
extern int Sqlitetestasync_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_autoext_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_blob_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_demovfs_Init(Tcl_Interp *);
|
||||
extern int Sqlitetest_func_Init(Tcl_Interp*);
|
||||
extern int Sqlitetest_hexio_Init(Tcl_Interp*);
|
||||
@@ -3768,6 +3769,7 @@ static void init_all(Tcl_Interp *interp){
|
||||
Sqlitetest9_Init(interp);
|
||||
Sqlitetestasync_Init(interp);
|
||||
Sqlitetest_autoext_Init(interp);
|
||||
Sqlitetest_blob_Init(interp);
|
||||
Sqlitetest_demovfs_Init(interp);
|
||||
Sqlitetest_func_Init(interp);
|
||||
Sqlitetest_hexio_Init(interp);
|
||||
|
||||
+20
-154
@@ -1651,154 +1651,6 @@ static int blobHandleFromObj(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite3_blob_bytes CHANNEL
|
||||
*/
|
||||
static int test_blob_bytes(
|
||||
ClientData clientData, /* Not used */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3_blob *pBlob;
|
||||
int nByte;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR;
|
||||
nByte = sqlite3_blob_bytes(pBlob);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(nByte));
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite3_blob_close CHANNEL
|
||||
*/
|
||||
static int test_blob_close(
|
||||
ClientData clientData, /* Not used */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3_blob *pBlob;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR;
|
||||
sqlite3_blob_close(pBlob);
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite3_blob_read CHANNEL OFFSET N
|
||||
**
|
||||
** This command is used to test the sqlite3_blob_read() in ways that
|
||||
** the Tcl channel interface does not. The first argument should
|
||||
** be the name of a valid channel created by the [incrblob] method
|
||||
** of a database handle. This function calls sqlite3_blob_read()
|
||||
** to read N bytes from offset OFFSET from the underlying SQLite
|
||||
** blob handle.
|
||||
**
|
||||
** On success, a byte-array object containing the read data is
|
||||
** returned. On failure, the interpreter result is set to the
|
||||
** text representation of the returned error code (i.e. "SQLITE_NOMEM")
|
||||
** and a Tcl exception is thrown.
|
||||
*/
|
||||
static int test_blob_read(
|
||||
ClientData clientData, /* Not used */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3_blob *pBlob;
|
||||
int nByte;
|
||||
int iOffset;
|
||||
unsigned char *zBuf = 0;
|
||||
int rc;
|
||||
|
||||
if( objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET N");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR;
|
||||
if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset)
|
||||
|| TCL_OK!=Tcl_GetIntFromObj(interp, objv[3], &nByte)
|
||||
){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( nByte>0 ){
|
||||
zBuf = (unsigned char *)Tcl_Alloc(nByte);
|
||||
}
|
||||
rc = sqlite3_blob_read(pBlob, zBuf, nByte, iOffset);
|
||||
if( rc==SQLITE_OK ){
|
||||
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zBuf, nByte));
|
||||
}else{
|
||||
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
|
||||
}
|
||||
Tcl_Free((char *)zBuf);
|
||||
|
||||
return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite3_blob_write CHANNEL OFFSET DATA ?NDATA?
|
||||
**
|
||||
** This command is used to test the sqlite3_blob_write() in ways that
|
||||
** the Tcl channel interface does not. The first argument should
|
||||
** be the name of a valid channel created by the [incrblob] method
|
||||
** of a database handle. This function calls sqlite3_blob_write()
|
||||
** to write the DATA byte-array to the underlying SQLite blob handle.
|
||||
** at offset OFFSET.
|
||||
**
|
||||
** On success, an empty string is returned. On failure, the interpreter
|
||||
** result is set to the text representation of the returned error code
|
||||
** (i.e. "SQLITE_NOMEM") and a Tcl exception is thrown.
|
||||
*/
|
||||
static int test_blob_write(
|
||||
ClientData clientData, /* Not used */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3_blob *pBlob;
|
||||
int iOffset;
|
||||
int rc;
|
||||
|
||||
unsigned char *zBuf;
|
||||
int nBuf;
|
||||
|
||||
if( objc!=4 && objc!=5 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET DATA ?NDATA?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR;
|
||||
if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
zBuf = Tcl_GetByteArrayFromObj(objv[3], &nBuf);
|
||||
if( objc==5 && Tcl_GetIntFromObj(interp, objv[4], &nBuf) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
rc = sqlite3_blob_write(pBlob, zBuf, nBuf, iOffset);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
|
||||
}
|
||||
|
||||
return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR);
|
||||
}
|
||||
|
||||
static int test_blob_reopen(
|
||||
ClientData clientData, /* Not used */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
@@ -3786,6 +3638,7 @@ static int test_prepare_v2(
|
||||
){
|
||||
sqlite3 *db;
|
||||
const char *zSql;
|
||||
char *zCopy = 0; /* malloc() copy of zSql */
|
||||
int bytes;
|
||||
const char *zTail = 0;
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
@@ -3801,7 +3654,21 @@ static int test_prepare_v2(
|
||||
zSql = Tcl_GetString(objv[2]);
|
||||
if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
|
||||
|
||||
rc = sqlite3_prepare_v2(db, zSql, bytes, &pStmt, objc>=5 ? &zTail : 0);
|
||||
/* Instead of using zSql directly, make a copy into a buffer obtained
|
||||
** directly from malloc(). The idea is to make it easier for valgrind
|
||||
** to spot buffer overreads. */
|
||||
if( bytes>=0 ){
|
||||
zCopy = malloc(bytes);
|
||||
memcpy(zCopy, zSql, bytes);
|
||||
}else{
|
||||
int n = (int)strlen(zSql) + 1;
|
||||
zCopy = malloc(n);
|
||||
memcpy(zCopy, zSql, n);
|
||||
}
|
||||
rc = sqlite3_prepare_v2(db, zCopy, bytes, &pStmt, objc>=5 ? &zTail : 0);
|
||||
free(zCopy);
|
||||
zTail = &zSql[(zTail - zCopy)];
|
||||
|
||||
assert(rc==SQLITE_OK || pStmt==0);
|
||||
Tcl_ResetResult(interp);
|
||||
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
|
||||
@@ -5823,10 +5690,11 @@ static int test_wal_checkpoint_v2(
|
||||
int nCkpt = -555;
|
||||
Tcl_Obj *pRet;
|
||||
|
||||
const char * aMode[] = { "passive", "full", "restart", 0 };
|
||||
const char * aMode[] = { "passive", "full", "restart", "truncate", 0 };
|
||||
assert( SQLITE_CHECKPOINT_PASSIVE==0 );
|
||||
assert( SQLITE_CHECKPOINT_FULL==1 );
|
||||
assert( SQLITE_CHECKPOINT_RESTART==2 );
|
||||
assert( SQLITE_CHECKPOINT_TRUNCATE==3 );
|
||||
|
||||
if( objc!=3 && objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "DB MODE ?NAME?");
|
||||
@@ -6408,6 +6276,7 @@ static int tclLoadStaticExtensionCmd(
|
||||
){
|
||||
extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*);
|
||||
@@ -6423,6 +6292,7 @@ static int tclLoadStaticExtensionCmd(
|
||||
} aExtension[] = {
|
||||
{ "amatch", sqlite3_amatch_init },
|
||||
{ "closure", sqlite3_closure_init },
|
||||
{ "eval", sqlite3_eval_init },
|
||||
{ "fileio", sqlite3_fileio_init },
|
||||
{ "fuzzer", sqlite3_fuzzer_init },
|
||||
{ "ieee754", sqlite3_ieee_init },
|
||||
@@ -6910,11 +6780,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "sqlite3_table_column_metadata", test_table_column_metadata, 0 },
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_INCRBLOB
|
||||
{ "sqlite3_blob_read", test_blob_read, 0 },
|
||||
{ "sqlite3_blob_write", test_blob_write, 0 },
|
||||
{ "sqlite3_blob_reopen", test_blob_reopen, 0 },
|
||||
{ "sqlite3_blob_bytes", test_blob_bytes, 0 },
|
||||
{ "sqlite3_blob_close", test_blob_close, 0 },
|
||||
#endif
|
||||
{ "pcache_stats", test_pcache_stats, 0 },
|
||||
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
|
||||
|
||||
+319
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
** 2014 October 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.
|
||||
**
|
||||
*************************************************************************
|
||||
**
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "tcl.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* These functions are implemented in main.c. */
|
||||
extern const char *sqlite3ErrName(int);
|
||||
|
||||
/* From test1.c: */
|
||||
extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
|
||||
extern void *sqlite3TestTextToPtr(const char *z);
|
||||
|
||||
/*
|
||||
** Return a pointer to a buffer containing a text representation of the
|
||||
** pointer passed as the only argument. The original pointer may be extracted
|
||||
** from the text using sqlite3TestTextToPtr().
|
||||
*/
|
||||
static char *ptrToText(void *p){
|
||||
static char buf[100];
|
||||
sqlite3_snprintf(sizeof(buf)-1, buf, "%p", p);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to extract a blob handle (type sqlite3_blob*) from the Tcl
|
||||
** object passed as the second argument. If successful, set *ppBlob to
|
||||
** point to the blob handle and return TCL_OK. Otherwise, store an error
|
||||
** message in the tcl interpreter and return TCL_ERROR. The final value
|
||||
** of *ppBlob is undefined in this case.
|
||||
**
|
||||
** If the object contains a string that begins with "incrblob_", then it
|
||||
** is assumed to be the name of a Tcl channel opened using the [db incrblob]
|
||||
** command (see tclsqlite.c). Otherwise, it is assumed to be a pointer
|
||||
** encoded using the ptrToText() routine or similar.
|
||||
*/
|
||||
static int blobHandleFromObj(
|
||||
Tcl_Interp *interp,
|
||||
Tcl_Obj *pObj,
|
||||
sqlite3_blob **ppBlob
|
||||
){
|
||||
char *z;
|
||||
int n;
|
||||
|
||||
z = Tcl_GetStringFromObj(pObj, &n);
|
||||
if( n==0 ){
|
||||
*ppBlob = 0;
|
||||
}else if( n>9 && 0==memcmp("incrblob_", z, 9) ){
|
||||
int notUsed;
|
||||
Tcl_Channel channel;
|
||||
ClientData instanceData;
|
||||
|
||||
channel = Tcl_GetChannel(interp, z, ¬Used);
|
||||
if( !channel ) return TCL_ERROR;
|
||||
|
||||
Tcl_Flush(channel);
|
||||
Tcl_Seek(channel, 0, SEEK_SET);
|
||||
|
||||
instanceData = Tcl_GetChannelInstanceData(channel);
|
||||
*ppBlob = *((sqlite3_blob **)instanceData);
|
||||
}else{
|
||||
*ppBlob = (sqlite3_blob*)sqlite3TestTextToPtr(z);
|
||||
}
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Like Tcl_GetString(), except that if the string is 0 bytes in size, a
|
||||
** NULL Pointer is returned.
|
||||
*/
|
||||
static char *blobStringFromObj(Tcl_Obj *pObj){
|
||||
int n;
|
||||
char *z;
|
||||
z = Tcl_GetStringFromObj(pObj, &n);
|
||||
return (n ? z : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite3_blob_open DB DATABASE TABLE COLUMN ROWID FLAGS VARNAME
|
||||
**
|
||||
** Tcl test harness for the sqlite3_blob_open() function.
|
||||
*/
|
||||
static int test_blob_open(
|
||||
ClientData clientData, /* Not used */
|
||||
Tcl_Interp *interp, /* Calling TCL interpreter */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3 *db;
|
||||
const char *zDb;
|
||||
const char *zTable;
|
||||
const char *zColumn;
|
||||
sqlite_int64 iRowid;
|
||||
int flags;
|
||||
const char *zVarname;
|
||||
int nVarname;
|
||||
|
||||
sqlite3_blob *pBlob = (sqlite3_blob*)0xFFFFFFFF;
|
||||
int rc;
|
||||
|
||||
if( objc!=8 ){
|
||||
const char *zUsage = "DB DATABASE TABLE COLUMN ROWID FLAGS VARNAME";
|
||||
Tcl_WrongNumArgs(interp, 1, objv, zUsage);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
|
||||
zDb = Tcl_GetString(objv[2]);
|
||||
zTable = blobStringFromObj(objv[3]);
|
||||
zColumn = Tcl_GetString(objv[4]);
|
||||
if( Tcl_GetWideIntFromObj(interp, objv[5], &iRowid) ) return TCL_ERROR;
|
||||
if( Tcl_GetIntFromObj(interp, objv[6], &flags) ) return TCL_ERROR;
|
||||
zVarname = Tcl_GetStringFromObj(objv[7], &nVarname);
|
||||
|
||||
if( nVarname>0 ){
|
||||
rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRowid, flags, &pBlob);
|
||||
Tcl_SetVar(interp, zVarname, ptrToText(pBlob), 0);
|
||||
}else{
|
||||
rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRowid, flags, 0);
|
||||
}
|
||||
|
||||
if( rc==SQLITE_OK ){
|
||||
Tcl_ResetResult(interp);
|
||||
}else{
|
||||
Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** sqlite3_blob_close HANDLE
|
||||
*/
|
||||
static int test_blob_close(
|
||||
ClientData clientData, /* Not used */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3_blob *pBlob;
|
||||
int rc;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR;
|
||||
rc = sqlite3_blob_close(pBlob);
|
||||
|
||||
if( rc ){
|
||||
Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE);
|
||||
}else{
|
||||
Tcl_ResetResult(interp);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite3_blob_bytes HANDLE
|
||||
*/
|
||||
static int test_blob_bytes(
|
||||
ClientData clientData, /* Not used */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3_blob *pBlob;
|
||||
int nByte;
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "HANDLE");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR;
|
||||
nByte = sqlite3_blob_bytes(pBlob);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(nByte));
|
||||
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite3_blob_read CHANNEL OFFSET N
|
||||
**
|
||||
** This command is used to test the sqlite3_blob_read() in ways that
|
||||
** the Tcl channel interface does not. The first argument should
|
||||
** be the name of a valid channel created by the [incrblob] method
|
||||
** of a database handle. This function calls sqlite3_blob_read()
|
||||
** to read N bytes from offset OFFSET from the underlying SQLite
|
||||
** blob handle.
|
||||
**
|
||||
** On success, a byte-array object containing the read data is
|
||||
** returned. On failure, the interpreter result is set to the
|
||||
** text representation of the returned error code (i.e. "SQLITE_NOMEM")
|
||||
** and a Tcl exception is thrown.
|
||||
*/
|
||||
static int test_blob_read(
|
||||
ClientData clientData, /* Not used */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3_blob *pBlob;
|
||||
int nByte;
|
||||
int iOffset;
|
||||
unsigned char *zBuf = 0;
|
||||
int rc;
|
||||
|
||||
if( objc!=4 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET N");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR;
|
||||
if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset)
|
||||
|| TCL_OK!=Tcl_GetIntFromObj(interp, objv[3], &nByte)
|
||||
){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( nByte>0 ){
|
||||
zBuf = (unsigned char *)Tcl_Alloc(nByte);
|
||||
}
|
||||
rc = sqlite3_blob_read(pBlob, zBuf, nByte, iOffset);
|
||||
if( rc==SQLITE_OK ){
|
||||
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zBuf, nByte));
|
||||
}else{
|
||||
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
|
||||
}
|
||||
Tcl_Free((char *)zBuf);
|
||||
|
||||
return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
** sqlite3_blob_write HANDLE OFFSET DATA ?NDATA?
|
||||
**
|
||||
** This command is used to test the sqlite3_blob_write() in ways that
|
||||
** the Tcl channel interface does not. The first argument should
|
||||
** be the name of a valid channel created by the [incrblob] method
|
||||
** of a database handle. This function calls sqlite3_blob_write()
|
||||
** to write the DATA byte-array to the underlying SQLite blob handle.
|
||||
** at offset OFFSET.
|
||||
**
|
||||
** On success, an empty string is returned. On failure, the interpreter
|
||||
** result is set to the text representation of the returned error code
|
||||
** (i.e. "SQLITE_NOMEM") and a Tcl exception is thrown.
|
||||
*/
|
||||
static int test_blob_write(
|
||||
ClientData clientData, /* Not used */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
sqlite3_blob *pBlob;
|
||||
int iOffset;
|
||||
int rc;
|
||||
|
||||
unsigned char *zBuf;
|
||||
int nBuf;
|
||||
|
||||
if( objc!=4 && objc!=5 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "HANDLE OFFSET DATA ?NDATA?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR;
|
||||
if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
zBuf = Tcl_GetByteArrayFromObj(objv[3], &nBuf);
|
||||
if( objc==5 && Tcl_GetIntFromObj(interp, objv[4], &nBuf) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
rc = sqlite3_blob_write(pBlob, zBuf, nBuf, iOffset);
|
||||
if( rc!=SQLITE_OK ){
|
||||
Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
|
||||
}
|
||||
|
||||
return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Register commands with the TCL interpreter.
|
||||
*/
|
||||
int Sqlitetest_blob_Init(Tcl_Interp *interp){
|
||||
static struct {
|
||||
char *zName;
|
||||
Tcl_ObjCmdProc *xProc;
|
||||
} aObjCmd[] = {
|
||||
{ "sqlite3_blob_open", test_blob_open },
|
||||
{ "sqlite3_blob_close", test_blob_close },
|
||||
{ "sqlite3_blob_bytes", test_blob_bytes },
|
||||
{ "sqlite3_blob_read", test_blob_read },
|
||||
{ "sqlite3_blob_write", test_blob_write },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
|
||||
Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
|
||||
}
|
||||
return TCL_OK;
|
||||
}
|
||||
@@ -155,6 +155,12 @@ static void set_options(Tcl_Interp *interp){
|
||||
Tcl_SetVar2(interp, "sqlite_options", "analyze", "1", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_API_ARMOR
|
||||
Tcl_SetVar2(interp, "sqlite_options", "api_armor", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
Tcl_SetVar2(interp, "sqlite_options", "api_armor", "0", TCL_GLOBAL_ONLY);
|
||||
#endif
|
||||
|
||||
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
||||
Tcl_SetVar2(interp, "sqlite_options", "atomicwrite", "1", TCL_GLOBAL_ONLY);
|
||||
#else
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ static int execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
|
||||
** overwriting the database with the vacuumed content.
|
||||
**
|
||||
** Only 1x temporary space and only 1x writes would be required if
|
||||
** the copy of step (3) were replace by deleting the original database
|
||||
** the copy of step (3) were replaced by deleting the original database
|
||||
** and renaming the transient database as the original. But that will
|
||||
** not work if other processes are attached to the original database.
|
||||
** And a power loss in between deleting the original and renaming the
|
||||
|
||||
+27
-8
@@ -2636,7 +2636,10 @@ case OP_MakeRecord: {
|
||||
nHdr += serial_type<=127 ? 1 : sqlite3VarintLen(serial_type);
|
||||
}while( (--pRec)>=pData0 );
|
||||
|
||||
/* Add the initial header varint and total the size */
|
||||
/* EVIDENCE-OF: R-22564-11647 The header begins with a single varint
|
||||
** which determines the total number of bytes in the header. The varint
|
||||
** value is the size of the header in bytes including the size varint
|
||||
** itself. */
|
||||
testcase( nHdr==126 );
|
||||
testcase( nHdr==127 );
|
||||
if( nHdr<=126 ){
|
||||
@@ -2670,7 +2673,11 @@ case OP_MakeRecord: {
|
||||
pRec = pData0;
|
||||
do{
|
||||
serial_type = pRec->uTemp;
|
||||
/* EVIDENCE-OF: R-06529-47362 Following the size varint are one or more
|
||||
** additional varints, one per column. */
|
||||
i += putVarint32(&zNewRecord[i], serial_type); /* serial type */
|
||||
/* EVIDENCE-OF: R-64536-51728 The values for each column in the record
|
||||
** immediately follow the header. */
|
||||
j += sqlite3VdbeSerialPut(&zNewRecord[j], pRec, serial_type); /* content */
|
||||
}while( (++pRec)<=pLast );
|
||||
assert( i==nHdr );
|
||||
@@ -2825,11 +2832,18 @@ case OP_Savepoint: {
|
||||
db->isTransactionSavepoint = 0;
|
||||
rc = p->rc;
|
||||
}else{
|
||||
int isSchemaChange;
|
||||
iSavepoint = db->nSavepoint - iSavepoint - 1;
|
||||
if( p1==SAVEPOINT_ROLLBACK ){
|
||||
isSchemaChange = (db->flags & SQLITE_InternChanges)!=0;
|
||||
for(ii=0; ii<db->nDb; ii++){
|
||||
sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT);
|
||||
rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt,
|
||||
SQLITE_ABORT_ROLLBACK,
|
||||
isSchemaChange==0);
|
||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
||||
}
|
||||
}else{
|
||||
isSchemaChange = 0;
|
||||
}
|
||||
for(ii=0; ii<db->nDb; ii++){
|
||||
rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint);
|
||||
@@ -2837,7 +2851,7 @@ case OP_Savepoint: {
|
||||
goto abort_due_to_error;
|
||||
}
|
||||
}
|
||||
if( p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){
|
||||
if( isSchemaChange ){
|
||||
sqlite3ExpirePreparedStatements(db);
|
||||
sqlite3ResetAllSchemasOfConnection(db);
|
||||
db->flags = (db->flags | SQLITE_InternChanges);
|
||||
@@ -3234,7 +3248,7 @@ case OP_OpenWrite: {
|
||||
|| p->readOnly==0 );
|
||||
|
||||
if( p->expired ){
|
||||
rc = SQLITE_ABORT;
|
||||
rc = SQLITE_ABORT_ROLLBACK;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3798,10 +3812,10 @@ case OP_Found: { /* jump, in3 */
|
||||
}else{
|
||||
pIdxKey = sqlite3VdbeAllocUnpackedRecord(
|
||||
pC->pKeyInfo, aTempRec, sizeof(aTempRec), &pFree
|
||||
);
|
||||
);
|
||||
if( pIdxKey==0 ) goto no_mem;
|
||||
assert( pIn3->flags & MEM_Blob );
|
||||
assert( (pIn3->flags & MEM_Zero)==0 ); /* zeroblobs already expanded */
|
||||
ExpandBlob(pIn3);
|
||||
sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey);
|
||||
}
|
||||
pIdxKey->default_rc = 0;
|
||||
@@ -4401,6 +4415,10 @@ case OP_Rowid: { /* out2-prerelease */
|
||||
assert( pC->pCursor!=0 );
|
||||
rc = sqlite3VdbeCursorRestore(pC);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
if( pC->nullRow ){
|
||||
pOut->flags = MEM_Null;
|
||||
break;
|
||||
}
|
||||
rc = sqlite3BtreeKeySize(pC->pCursor, &v);
|
||||
assert( rc==SQLITE_OK ); /* Always so because of CursorRestore() above */
|
||||
}
|
||||
@@ -5687,8 +5705,8 @@ case OP_AggFinal: {
|
||||
/* Opcode: Checkpoint P1 P2 P3 * *
|
||||
**
|
||||
** Checkpoint database P1. This is a no-op if P1 is not currently in
|
||||
** WAL mode. Parameter P2 is one of SQLITE_CHECKPOINT_PASSIVE, FULL
|
||||
** or RESTART. Write 1 or 0 into mem[P3] if the checkpoint returns
|
||||
** WAL mode. Parameter P2 is one of SQLITE_CHECKPOINT_PASSIVE, FULL,
|
||||
** RESTART, or TRUNCATE. Write 1 or 0 into mem[P3] if the checkpoint returns
|
||||
** SQLITE_BUSY or not, respectively. Write the number of pages in the
|
||||
** WAL after the checkpoint into mem[P3+1] and the number of pages
|
||||
** in the WAL that have been checkpointed after the checkpoint
|
||||
@@ -5706,6 +5724,7 @@ case OP_Checkpoint: {
|
||||
assert( pOp->p2==SQLITE_CHECKPOINT_PASSIVE
|
||||
|| pOp->p2==SQLITE_CHECKPOINT_FULL
|
||||
|| pOp->p2==SQLITE_CHECKPOINT_RESTART
|
||||
|| pOp->p2==SQLITE_CHECKPOINT_TRUNCATE
|
||||
);
|
||||
rc = sqlite3Checkpoint(db, pOp->p1, pOp->p2, &aRes[1], &aRes[2]);
|
||||
if( rc==SQLITE_BUSY ){
|
||||
|
||||
+28
-6
@@ -1054,6 +1054,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){
|
||||
CollSeq *pColl = pKeyInfo->aColl[j];
|
||||
const char *zColl = pColl ? pColl->zName : "nil";
|
||||
int n = sqlite3Strlen30(zColl);
|
||||
assert( pColl==0 || sqlite3ValidCollSeq(pColl) );
|
||||
if( n==6 && memcmp(zColl,"BINARY",6)==0 ){
|
||||
zColl = "B";
|
||||
n = 1;
|
||||
@@ -1742,7 +1743,7 @@ void sqlite3VdbeMakeReady(
|
||||
p->aVar[n].db = db;
|
||||
}
|
||||
}
|
||||
if( p->azVar ){
|
||||
if( p->azVar && pParse->nzVar>0 ){
|
||||
p->nzVar = pParse->nzVar;
|
||||
memcpy(p->azVar, pParse->azVar, p->nzVar*sizeof(p->azVar[0]));
|
||||
memset(pParse->azVar, 0, pParse->nzVar*sizeof(pParse->azVar[0]));
|
||||
@@ -2883,9 +2884,7 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
|
||||
i64 i = pMem->u.i;
|
||||
u64 u;
|
||||
if( i<0 ){
|
||||
if( i<(-MAX_6BYTE) ) return 6;
|
||||
/* Previous test prevents: u = -(-9223372036854775808) */
|
||||
u = -i;
|
||||
u = ~i;
|
||||
}else{
|
||||
u = i;
|
||||
}
|
||||
@@ -3051,10 +3050,14 @@ static u32 SQLITE_NOINLINE serialGet(
|
||||
u32 y = FOUR_BYTE_UINT(buf+4);
|
||||
x = (x<<32) + y;
|
||||
if( serial_type==6 ){
|
||||
/* EVIDENCE-OF: R-29851-52272 Value is a big-endian 64-bit
|
||||
** twos-complement integer. */
|
||||
pMem->u.i = *(i64*)&x;
|
||||
pMem->flags = MEM_Int;
|
||||
testcase( pMem->u.i<0 );
|
||||
}else{
|
||||
/* EVIDENCE-OF: R-57343-49114 Value is a big-endian IEEE 754-2008 64-bit
|
||||
** floating point number. */
|
||||
#if !defined(NDEBUG) && !defined(SQLITE_OMIT_FLOATING_POINT)
|
||||
/* Verify that integers and floating point values use the same
|
||||
** byte order. Or, that if SQLITE_MIXED_ENDIAN_64BIT_FLOAT is
|
||||
@@ -3082,35 +3085,46 @@ u32 sqlite3VdbeSerialGet(
|
||||
switch( serial_type ){
|
||||
case 10: /* Reserved for future use */
|
||||
case 11: /* Reserved for future use */
|
||||
case 0: { /* NULL */
|
||||
case 0: { /* Null */
|
||||
/* EVIDENCE-OF: R-24078-09375 Value is a NULL. */
|
||||
pMem->flags = MEM_Null;
|
||||
break;
|
||||
}
|
||||
case 1: { /* 1-byte signed integer */
|
||||
case 1: {
|
||||
/* EVIDENCE-OF: R-44885-25196 Value is an 8-bit twos-complement
|
||||
** integer. */
|
||||
pMem->u.i = ONE_BYTE_INT(buf);
|
||||
pMem->flags = MEM_Int;
|
||||
testcase( pMem->u.i<0 );
|
||||
return 1;
|
||||
}
|
||||
case 2: { /* 2-byte signed integer */
|
||||
/* EVIDENCE-OF: R-49794-35026 Value is a big-endian 16-bit
|
||||
** twos-complement integer. */
|
||||
pMem->u.i = TWO_BYTE_INT(buf);
|
||||
pMem->flags = MEM_Int;
|
||||
testcase( pMem->u.i<0 );
|
||||
return 2;
|
||||
}
|
||||
case 3: { /* 3-byte signed integer */
|
||||
/* EVIDENCE-OF: R-37839-54301 Value is a big-endian 24-bit
|
||||
** twos-complement integer. */
|
||||
pMem->u.i = THREE_BYTE_INT(buf);
|
||||
pMem->flags = MEM_Int;
|
||||
testcase( pMem->u.i<0 );
|
||||
return 3;
|
||||
}
|
||||
case 4: { /* 4-byte signed integer */
|
||||
/* EVIDENCE-OF: R-01849-26079 Value is a big-endian 32-bit
|
||||
** twos-complement integer. */
|
||||
pMem->u.i = FOUR_BYTE_INT(buf);
|
||||
pMem->flags = MEM_Int;
|
||||
testcase( pMem->u.i<0 );
|
||||
return 4;
|
||||
}
|
||||
case 5: { /* 6-byte signed integer */
|
||||
/* EVIDENCE-OF: R-50385-09674 Value is a big-endian 48-bit
|
||||
** twos-complement integer. */
|
||||
pMem->u.i = FOUR_BYTE_UINT(buf+2) + (((i64)1)<<32)*TWO_BYTE_INT(buf);
|
||||
pMem->flags = MEM_Int;
|
||||
testcase( pMem->u.i<0 );
|
||||
@@ -3124,11 +3138,17 @@ u32 sqlite3VdbeSerialGet(
|
||||
}
|
||||
case 8: /* Integer 0 */
|
||||
case 9: { /* Integer 1 */
|
||||
/* EVIDENCE-OF: R-12976-22893 Value is the integer 0. */
|
||||
/* EVIDENCE-OF: R-18143-12121 Value is the integer 1. */
|
||||
pMem->u.i = serial_type-8;
|
||||
pMem->flags = MEM_Int;
|
||||
return 0;
|
||||
}
|
||||
default: {
|
||||
/* EVIDENCE-OF: R-14606-31564 Value is a BLOB that is (N-12)/2 bytes in
|
||||
** length.
|
||||
** EVIDENCE-OF: R-28401-00140 Value is a string in the text encoding and
|
||||
** (N-13)/2 bytes in length. */
|
||||
static const u16 aFlag[] = { MEM_Blob|MEM_Ephem, MEM_Str|MEM_Ephem };
|
||||
pMem->z = (char *)buf;
|
||||
pMem->n = (serial_type-12)/2;
|
||||
@@ -3339,6 +3359,7 @@ static int vdbeCompareMemString(
|
||||
const CollSeq *pColl,
|
||||
u8 *prcErr /* If an OOM occurs, set to SQLITE_NOMEM */
|
||||
){
|
||||
assert( sqlite3ValidCollSeq(pColl) );
|
||||
if( pMem1->enc==pColl->enc ){
|
||||
/* The strings are already in the correct encoding. Call the
|
||||
** comparison function directly */
|
||||
@@ -3454,6 +3475,7 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
|
||||
assert( !pColl || pColl->xCmp );
|
||||
|
||||
if( pColl ){
|
||||
assert( sqlite3ValidCollSeq(pColl) );
|
||||
return vdbeCompareMemString(pMem1, pMem2, pColl, 0);
|
||||
}
|
||||
/* If a NULL pointer was passed as the collate function, fall through
|
||||
|
||||
+1
-2
@@ -376,7 +376,6 @@ static int blobReadWrite(
|
||||
if( n<0 || iOffset<0 || (iOffset+n)>p->nByte ){
|
||||
/* Request is out of range. Return a transient error. */
|
||||
rc = SQLITE_ERROR;
|
||||
sqlite3Error(db, SQLITE_ERROR);
|
||||
}else if( v==0 ){
|
||||
/* If there is no statement handle, then the blob-handle has
|
||||
** already been invalidated. Return SQLITE_ABORT in this case.
|
||||
@@ -394,10 +393,10 @@ static int blobReadWrite(
|
||||
sqlite3VdbeFinalize(v);
|
||||
p->pStmt = 0;
|
||||
}else{
|
||||
db->errCode = rc;
|
||||
v->rc = rc;
|
||||
}
|
||||
}
|
||||
sqlite3Error(db, rc);
|
||||
rc = sqlite3ApiExit(db, rc);
|
||||
sqlite3_mutex_leave(db->mutex);
|
||||
return rc;
|
||||
|
||||
+8
-1
@@ -147,6 +147,13 @@
|
||||
# define SQLITE_DEBUG_SORTER_THREADS 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Hard-coded maximum amount of data to accumulate in memory before flushing
|
||||
** to a level 0 PMA. The purpose of this limit is to prevent various integer
|
||||
** overflows. 512MiB.
|
||||
*/
|
||||
#define SQLITE_MAX_MXPMASIZE (1<<29)
|
||||
|
||||
/*
|
||||
** Private objects used by the sorter
|
||||
*/
|
||||
@@ -845,7 +852,7 @@ int sqlite3VdbeSorterInit(
|
||||
pSorter->mnPmaSize = SORTER_MIN_WORKING * pgsz;
|
||||
mxCache = db->aDb[0].pSchema->cache_size;
|
||||
if( mxCache<SORTER_MIN_WORKING ) mxCache = SORTER_MIN_WORKING;
|
||||
pSorter->mxPmaSize = mxCache * pgsz;
|
||||
pSorter->mxPmaSize = MIN((i64)mxCache*pgsz, SQLITE_MAX_MXPMASIZE);
|
||||
|
||||
/* EVIDENCE-OF: R-26747-61719 When the application provides any amount of
|
||||
** scratch memory using SQLITE_CONFIG_SCRATCH, SQLite avoids unnecessary
|
||||
|
||||
+6
-1
@@ -332,7 +332,12 @@ void sqlite3VtabBeginParse(
|
||||
addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName));
|
||||
addModuleArgument(db, pTable, 0);
|
||||
addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName));
|
||||
pParse->sNameToken.n = (int)(&pModuleName->z[pModuleName->n] - pName1->z);
|
||||
assert( (pParse->sNameToken.z==pName2->z && pName2->z!=0)
|
||||
|| (pParse->sNameToken.z==pName1->z && pName2->z==0)
|
||||
);
|
||||
pParse->sNameToken.n = (int)(
|
||||
&pModuleName->z[pModuleName->n] - pParse->sNameToken.z
|
||||
);
|
||||
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
/* Creating a virtual table invokes the authorization callback twice.
|
||||
|
||||
@@ -1623,6 +1623,38 @@ static int walPagesize(Wal *pWal){
|
||||
return (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
|
||||
}
|
||||
|
||||
/*
|
||||
** The following is guaranteed when this function is called:
|
||||
**
|
||||
** a) the WRITER lock is held,
|
||||
** b) the entire log file has been checkpointed, and
|
||||
** c) any existing readers are reading exclusively from the database
|
||||
** file - there are no readers that may attempt to read a frame from
|
||||
** the log file.
|
||||
**
|
||||
** This function updates the shared-memory structures so that the next
|
||||
** client to write to the database (which may be this one) does so by
|
||||
** writing frames into the start of the log file.
|
||||
**
|
||||
** The value of parameter salt1 is used as the aSalt[1] value in the
|
||||
** new wal-index header. It should be passed a pseudo-random value (i.e.
|
||||
** one obtained from sqlite3_randomness()).
|
||||
*/
|
||||
static void walRestartHdr(Wal *pWal, u32 salt1){
|
||||
volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
|
||||
int i; /* Loop counter */
|
||||
u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */
|
||||
pWal->nCkpt++;
|
||||
pWal->hdr.mxFrame = 0;
|
||||
sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
|
||||
memcpy(&pWal->hdr.aSalt[1], &salt1, 4);
|
||||
walIndexWriteHdr(pWal);
|
||||
pInfo->nBackfill = 0;
|
||||
pInfo->aReadMark[1] = 0;
|
||||
for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
|
||||
assert( pInfo->aReadMark[0]==0 );
|
||||
}
|
||||
|
||||
/*
|
||||
** Copy as much content as we can from the WAL back into the database file
|
||||
** in response to an sqlite3_wal_checkpoint() request or the equivalent.
|
||||
@@ -1657,7 +1689,7 @@ static int walPagesize(Wal *pWal){
|
||||
static int walCheckpoint(
|
||||
Wal *pWal, /* Wal connection */
|
||||
int eMode, /* One of PASSIVE, FULL or RESTART */
|
||||
int (*xBusyCall)(void*), /* Function to call when busy */
|
||||
int (*xBusy)(void*), /* Function to call when busy */
|
||||
void *pBusyArg, /* Context argument for xBusyHandler */
|
||||
int sync_flags, /* Flags for OsSync() (or 0) */
|
||||
u8 *zBuf /* Temporary buffer to use */
|
||||
@@ -1671,7 +1703,6 @@ static int walCheckpoint(
|
||||
u32 mxPage; /* Max database page to write */
|
||||
int i; /* Loop counter */
|
||||
volatile WalCkptInfo *pInfo; /* The checkpoint status information */
|
||||
int (*xBusy)(void*) = 0; /* Function to call when waiting for locks */
|
||||
|
||||
szPage = walPagesize(pWal);
|
||||
testcase( szPage<=32768 );
|
||||
@@ -1686,7 +1717,9 @@ static int walCheckpoint(
|
||||
}
|
||||
assert( pIter );
|
||||
|
||||
if( eMode!=SQLITE_CHECKPOINT_PASSIVE ) xBusy = xBusyCall;
|
||||
/* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
|
||||
** in the SQLITE_CHECKPOINT_PASSIVE mode. */
|
||||
assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
|
||||
|
||||
/* Compute in mxSafeFrame the index of the last frame of the WAL that is
|
||||
** safe to write into the database. Frames beyond mxSafeFrame might
|
||||
@@ -1775,19 +1808,38 @@ static int walCheckpoint(
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
|
||||
/* If this is an SQLITE_CHECKPOINT_RESTART operation, and the entire wal
|
||||
** file has been copied into the database file, then block until all
|
||||
** readers have finished using the wal file. This ensures that the next
|
||||
** process to write to the database restarts the wal file.
|
||||
/* If this is an SQLITE_CHECKPOINT_RESTART or TRUNCATE operation, and the
|
||||
** entire wal file has been copied into the database file, then block
|
||||
** until all readers have finished using the wal file. This ensures that
|
||||
** the next process to write to the database restarts the wal file.
|
||||
*/
|
||||
if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
|
||||
assert( pWal->writeLock );
|
||||
if( pInfo->nBackfill<pWal->hdr.mxFrame ){
|
||||
rc = SQLITE_BUSY;
|
||||
}else if( eMode==SQLITE_CHECKPOINT_RESTART ){
|
||||
}else if( eMode>=SQLITE_CHECKPOINT_RESTART ){
|
||||
u32 salt1;
|
||||
sqlite3_randomness(4, &salt1);
|
||||
assert( mxSafeFrame==pWal->hdr.mxFrame );
|
||||
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( eMode==SQLITE_CHECKPOINT_TRUNCATE ){
|
||||
/* IMPLEMENTATION-OF: R-44699-57140 This mode works the same way as
|
||||
** SQLITE_CHECKPOINT_RESTART with the addition that it also
|
||||
** truncates the log file to zero bytes just prior to a
|
||||
** successful return.
|
||||
**
|
||||
** In theory, it might be safe to do this without updating the
|
||||
** wal-index header in shared memory, as all subsequent reader or
|
||||
** writer clients should see that the entire log file has been
|
||||
** checkpointed and behave accordingly. This seems unsafe though,
|
||||
** as it would leave the system in a state where the contents of
|
||||
** the wal-index header do not match the contents of the
|
||||
** file-system. To avoid this, update the wal-index header to
|
||||
** indicate that the log file contains zero valid frames. */
|
||||
walRestartHdr(pWal, salt1);
|
||||
rc = sqlite3OsTruncate(pWal->pWalFd, 0);
|
||||
}
|
||||
walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
|
||||
}
|
||||
}
|
||||
@@ -2525,7 +2577,6 @@ int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){
|
||||
}
|
||||
if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
|
||||
}
|
||||
assert( rc==SQLITE_OK );
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -2574,7 +2625,6 @@ int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This function is called just before writing a set of frames to the log
|
||||
** file (see sqlite3WalFrames()). It checks to see if, instead of appending
|
||||
@@ -2607,20 +2657,8 @@ static int walRestartLog(Wal *pWal){
|
||||
** In theory it would be Ok to update the cache of the header only
|
||||
** at this point. But updating the actual wal-index header is also
|
||||
** safe and means there is no special case for sqlite3WalUndo()
|
||||
** to handle if this transaction is rolled back.
|
||||
*/
|
||||
int i; /* Loop counter */
|
||||
u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */
|
||||
|
||||
pWal->nCkpt++;
|
||||
pWal->hdr.mxFrame = 0;
|
||||
sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
|
||||
aSalt[1] = salt1;
|
||||
walIndexWriteHdr(pWal);
|
||||
pInfo->nBackfill = 0;
|
||||
pInfo->aReadMark[1] = 0;
|
||||
for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
|
||||
assert( pInfo->aReadMark[0]==0 );
|
||||
** to handle if this transaction is rolled back. */
|
||||
walRestartHdr(pWal, salt1);
|
||||
walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
|
||||
}else if( rc!=SQLITE_BUSY ){
|
||||
return rc;
|
||||
@@ -2908,7 +2946,7 @@ int sqlite3WalFrames(
|
||||
*/
|
||||
int sqlite3WalCheckpoint(
|
||||
Wal *pWal, /* Wal connection */
|
||||
int eMode, /* PASSIVE, FULL or RESTART */
|
||||
int eMode, /* PASSIVE, FULL, RESTART, or TRUNCATE */
|
||||
int (*xBusy)(void*), /* Function to call when busy */
|
||||
void *pBusyArg, /* Context argument for xBusyHandler */
|
||||
int sync_flags, /* Flags to sync db file with (or 0) */
|
||||
@@ -2920,29 +2958,42 @@ int sqlite3WalCheckpoint(
|
||||
int rc; /* Return code */
|
||||
int isChanged = 0; /* True if a new wal-index header is loaded */
|
||||
int eMode2 = eMode; /* Mode to pass to walCheckpoint() */
|
||||
int (*xBusy2)(void*) = xBusy; /* Busy handler for eMode2 */
|
||||
|
||||
assert( pWal->ckptLock==0 );
|
||||
assert( pWal->writeLock==0 );
|
||||
|
||||
/* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
|
||||
** in the SQLITE_CHECKPOINT_PASSIVE mode. */
|
||||
assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
|
||||
|
||||
if( pWal->readOnly ) return SQLITE_READONLY;
|
||||
WALTRACE(("WAL%p: checkpoint begins\n", pWal));
|
||||
|
||||
/* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
|
||||
** "checkpoint" lock on the database file. */
|
||||
rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
|
||||
if( rc ){
|
||||
/* Usually this is SQLITE_BUSY meaning that another thread or process
|
||||
** is already running a checkpoint, or maybe a recovery. But it might
|
||||
** also be SQLITE_IOERR. */
|
||||
/* EVIDENCE-OF: R-10421-19736 If any other process is running a
|
||||
** checkpoint operation at the same time, the lock cannot be obtained and
|
||||
** SQLITE_BUSY is returned.
|
||||
** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured,
|
||||
** it will not be invoked in this case.
|
||||
*/
|
||||
testcase( rc==SQLITE_BUSY );
|
||||
testcase( xBusy!=0 );
|
||||
return rc;
|
||||
}
|
||||
pWal->ckptLock = 1;
|
||||
|
||||
/* If this is a blocking-checkpoint, then obtain the write-lock as well
|
||||
** to prevent any writers from running while the checkpoint is underway.
|
||||
** This has to be done before the call to walIndexReadHdr() below.
|
||||
/* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and
|
||||
** TRUNCATE modes also obtain the exclusive "writer" lock on the database
|
||||
** file.
|
||||
**
|
||||
** If the writer lock cannot be obtained, then a passive checkpoint is
|
||||
** run instead. Since the checkpointer is not holding the writer lock,
|
||||
** there is no point in blocking waiting for any readers. Assuming no
|
||||
** other error occurs, this function will return SQLITE_BUSY to the caller.
|
||||
** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained
|
||||
** immediately, and a busy-handler is configured, it is invoked and the
|
||||
** writer lock retried until either the busy-handler returns 0 or the
|
||||
** lock is successfully obtained.
|
||||
*/
|
||||
if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
|
||||
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
|
||||
@@ -2950,6 +3001,7 @@ int sqlite3WalCheckpoint(
|
||||
pWal->writeLock = 1;
|
||||
}else if( rc==SQLITE_BUSY ){
|
||||
eMode2 = SQLITE_CHECKPOINT_PASSIVE;
|
||||
xBusy2 = 0;
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
}
|
||||
@@ -2967,7 +3019,7 @@ int sqlite3WalCheckpoint(
|
||||
if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
}else{
|
||||
rc = walCheckpoint(pWal, eMode2, xBusy, pBusyArg, sync_flags, zBuf);
|
||||
rc = walCheckpoint(pWal, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
|
||||
}
|
||||
|
||||
/* If no error occurred, set the output variables. */
|
||||
|
||||
+45
-17
@@ -3591,10 +3591,9 @@ static Bitmask codeOneLoopStart(
|
||||
Expr *pExpr = pWC->a[iTerm].pExpr;
|
||||
if( &pWC->a[iTerm] == pTerm ) continue;
|
||||
if( ExprHasProperty(pExpr, EP_FromJoin) ) continue;
|
||||
testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO );
|
||||
testcase( pWC->a[iTerm].wtFlags & TERM_VIRTUAL );
|
||||
if( pWC->a[iTerm].wtFlags & (TERM_ORINFO|TERM_VIRTUAL) ) continue;
|
||||
if( (pWC->a[iTerm].wtFlags & TERM_VIRTUAL)!=0 ) continue;
|
||||
if( (pWC->a[iTerm].eOperator & WO_ALL)==0 ) continue;
|
||||
testcase( pWC->a[iTerm].wtFlags & TERM_ORINFO );
|
||||
pExpr = sqlite3ExprDup(db, pExpr, 0);
|
||||
pAndExpr = sqlite3ExprAnd(db, pAndExpr, pExpr);
|
||||
}
|
||||
@@ -4130,8 +4129,9 @@ static WhereLoop **whereLoopFindLesser(
|
||||
|
||||
/* Any loop using an appliation-defined index (or PRIMARY KEY or
|
||||
** UNIQUE constraint) with one or more == constraints is better
|
||||
** than an automatic index. */
|
||||
** than an automatic index. Unless it is a skip-scan. */
|
||||
if( (p->wsFlags & WHERE_AUTO_INDEX)!=0
|
||||
&& (pTemplate->nSkip)==0
|
||||
&& (pTemplate->wsFlags & WHERE_INDEXED)!=0
|
||||
&& (pTemplate->wsFlags & WHERE_COLUMN_EQ)!=0
|
||||
&& (p->prereq & pTemplate->prereq)==pTemplate->prereq
|
||||
@@ -4290,10 +4290,30 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
|
||||
** Adjust the WhereLoop.nOut value downward to account for terms of the
|
||||
** WHERE clause that reference the loop but which are not used by an
|
||||
** index.
|
||||
*
|
||||
** For every WHERE clause term that is not used by the index
|
||||
** and which has a truth probability assigned by one of the likelihood(),
|
||||
** likely(), or unlikely() SQL functions, reduce the estimated number
|
||||
** of output rows by the probability specified.
|
||||
**
|
||||
** In the current implementation, the first extra WHERE clause term reduces
|
||||
** the number of output rows by a factor of 10 and each additional term
|
||||
** reduces the number of output rows by sqrt(2).
|
||||
** TUNING: For every WHERE clause term that is not used by the index
|
||||
** and which does not have an assigned truth probability, heuristics
|
||||
** described below are used to try to estimate the truth probability.
|
||||
** TODO --> Perhaps this is something that could be improved by better
|
||||
** table statistics.
|
||||
**
|
||||
** Heuristic 1: Estimate the truth probability as 93.75%. The 93.75%
|
||||
** value corresponds to -1 in LogEst notation, so this means decrement
|
||||
** the WhereLoop.nOut field for every such WHERE clause term.
|
||||
**
|
||||
** Heuristic 2: If there exists one or more WHERE clause terms of the
|
||||
** form "x==EXPR" and EXPR is not a constant 0 or 1, then make sure the
|
||||
** final output row estimate is no greater than 1/4 of the total number
|
||||
** of rows in the table. In other words, assume that x==EXPR will filter
|
||||
** out at least 3 out of 4 rows. If EXPR is -1 or 0 or 1, then maybe the
|
||||
** "x" column is boolean or else -1 or 0 or 1 is a common default value
|
||||
** on the "x" column and so in that case only cap the output row estimate
|
||||
** at 1/2 instead of 1/4.
|
||||
*/
|
||||
static void whereLoopOutputAdjust(
|
||||
WhereClause *pWC, /* The WHERE clause */
|
||||
@@ -4302,9 +4322,10 @@ static void whereLoopOutputAdjust(
|
||||
){
|
||||
WhereTerm *pTerm, *pX;
|
||||
Bitmask notAllowed = ~(pLoop->prereq|pLoop->maskSelf);
|
||||
int i, j;
|
||||
int nEq = 0; /* Number of = constraints not within likely()/unlikely() */
|
||||
int i, j, k;
|
||||
LogEst iReduce = 0; /* pLoop->nOut should not exceed nRow-iReduce */
|
||||
|
||||
assert( (pLoop->wsFlags & WHERE_AUTO_INDEX)==0 );
|
||||
for(i=pWC->nTerm, pTerm=pWC->a; i>0; i--, pTerm++){
|
||||
if( (pTerm->wtFlags & TERM_VIRTUAL)!=0 ) break;
|
||||
if( (pTerm->prereqAll & pLoop->maskSelf)==0 ) continue;
|
||||
@@ -4317,20 +4338,26 @@ static void whereLoopOutputAdjust(
|
||||
}
|
||||
if( j<0 ){
|
||||
if( pTerm->truthProb<=0 ){
|
||||
/* If a truth probability is specified using the likelihood() hints,
|
||||
** then use the probability provided by the application. */
|
||||
pLoop->nOut += pTerm->truthProb;
|
||||
}else{
|
||||
/* In the absence of explicit truth probabilities, use heuristics to
|
||||
** guess a reasonable truth probability. */
|
||||
pLoop->nOut--;
|
||||
if( pTerm->eOperator&WO_EQ ) nEq++;
|
||||
if( pTerm->eOperator&WO_EQ ){
|
||||
Expr *pRight = pTerm->pExpr->pRight;
|
||||
if( sqlite3ExprIsInteger(pRight, &k) && k>=(-1) && k<=1 ){
|
||||
k = 10;
|
||||
}else{
|
||||
k = 20;
|
||||
}
|
||||
if( iReduce<k ) iReduce = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* TUNING: If there is at least one equality constraint in the WHERE
|
||||
** clause that does not have a likelihood() explicitly assigned to it
|
||||
** then do not let the estimated number of output rows exceed half
|
||||
** the number of rows in the table. */
|
||||
if( nEq && pLoop->nOut>nRow-10 ){
|
||||
pLoop->nOut = nRow - 10;
|
||||
}
|
||||
if( pLoop->nOut > nRow-iReduce ) pLoop->nOut = nRow - iReduce;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4587,6 +4614,7 @@ static int whereLoopAddBtreeIndex(
|
||||
assert( 42==sqlite3LogEst(18) );
|
||||
if( saved_nEq==saved_nSkip
|
||||
&& saved_nEq+1<pProbe->nKeyCol
|
||||
&& pProbe->noSkipScan==0
|
||||
&& pProbe->aiRowLogEst[saved_nEq+1]>=42 /* TUNING: Minimum for skip-scan */
|
||||
&& (rc = whereLoopResize(db, pNew, pNew->nLTerm+1))==SQLITE_OK
|
||||
){
|
||||
|
||||
@@ -224,48 +224,4 @@ do_execsql_test autoindex2-120 {
|
||||
# on t3 and reordering the tables so that t3 was in the outer loop and
|
||||
# implementing the ORDER BY clause using a B-Tree.
|
||||
|
||||
do_execsql_test autoindex2-120 {
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT
|
||||
t1_id,
|
||||
t1.did,
|
||||
param2,
|
||||
param3,
|
||||
t1.ptime,
|
||||
t1.trange,
|
||||
t1.exmass,
|
||||
t1.mass,
|
||||
t1.vstatus,
|
||||
type,
|
||||
subtype,
|
||||
t1.deviation,
|
||||
t1.formula,
|
||||
dparam1,
|
||||
reserve1,
|
||||
reserve2,
|
||||
param4,
|
||||
t1.last_operation,
|
||||
t1.admin_uuid,
|
||||
t1.previous_value,
|
||||
t1.job_id,
|
||||
client_did,
|
||||
t1.last_t1,
|
||||
t1.data_t1,
|
||||
t1.previous_date,
|
||||
param5,
|
||||
param6,
|
||||
mgr_uuid
|
||||
FROM
|
||||
t3,
|
||||
t2,
|
||||
t1
|
||||
WHERE
|
||||
t1.ptime > 1393520400
|
||||
AND param3<>9001
|
||||
AND t3.flg7 = 1
|
||||
AND t1.did = t2.did
|
||||
AND t2.uid = t3.uid
|
||||
ORDER BY t1.ptime desc LIMIT 500;
|
||||
} {0 0 2 {SEARCH TABLE t1 USING INDEX t1x1 (ptime>?)} 0 1 1 {SEARCH TABLE t2 USING INDEX t2x0 (did=?)} 0 2 0 {SEARCH TABLE t3 USING INDEX t3x0 (uid=?)}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix autoindex3
|
||||
|
||||
# The t1b and t2d indexes are not very selective. It used to be that
|
||||
# the autoindex mechanism would create automatic indexes on t1(b) or
|
||||
@@ -54,5 +55,38 @@ do_execsql_test autoindex3-140 {
|
||||
EXPLAIN QUERY PLAN SELECT * FROM t1, t2 WHERE d IN (5,b) AND x=y;
|
||||
} {/AUTO/}
|
||||
|
||||
reset_db
|
||||
do_execsql_test 210 {
|
||||
CREATE TABLE v(b, d, e);
|
||||
CREATE TABLE u(a, b, c);
|
||||
ANALYZE sqlite_master;
|
||||
INSERT INTO "sqlite_stat1" VALUES('u','uab','40000 400 1');
|
||||
INSERT INTO "sqlite_stat1" VALUES('v','vbde','40000 400 1 1');
|
||||
INSERT INTO "sqlite_stat1" VALUES('v','ve','40000 21');
|
||||
|
||||
CREATE INDEX uab on u(a, b);
|
||||
CREATE INDEX ve on v(e);
|
||||
CREATE INDEX vbde on v(b,d,e);
|
||||
|
||||
DROP TABLE IF EXISTS sqlite_stat4;
|
||||
ANALYZE sqlite_master;
|
||||
}
|
||||
|
||||
# At one point, SQLite was using the inferior plan:
|
||||
#
|
||||
# 0|0|1|SEARCH TABLE v USING INDEX ve (e>?)
|
||||
# 0|1|0|SEARCH TABLE u USING COVERING INDEX uab (ANY(a) AND b=?)
|
||||
#
|
||||
# on the basis that the real index "uab" must be better than the automatic
|
||||
# index. This is not right - a skip-scan is not necessarily better than an
|
||||
# automatic index scan.
|
||||
#
|
||||
do_eqp_test 220 {
|
||||
select count(*) from u, v where u.b = v.b and v.e > 34;
|
||||
} {
|
||||
0 0 1 {SEARCH TABLE v USING INDEX ve (e>?)}
|
||||
0 1 0 {SEARCH TABLE u USING AUTOMATIC COVERING INDEX (b=?)}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -217,6 +217,7 @@ foreach nPagePerStep {1 200} {
|
||||
INSERT INTO ${file_dest}.t1 VALUES(1, randstr(1000,1000))
|
||||
" $db_dest
|
||||
}
|
||||
execsql COMMIT $db_dest
|
||||
}
|
||||
|
||||
# Backup the source database.
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# 2014 November 13
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix backup5
|
||||
|
||||
forcedelete test2.db
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a, b);
|
||||
CREATE TABLE t2(a, b);
|
||||
INSERT INTO t2 VALUES(1, 1);
|
||||
INSERT INTO t2 VALUES(2, 2);
|
||||
INSERT INTO t2 VALUES(3, 3);
|
||||
}
|
||||
|
||||
do_test 1.1 {
|
||||
forcecopy test.db test.db2
|
||||
db eval {
|
||||
DROP TABLE t2;
|
||||
INSERT INTO t1 VALUES(zeroblob(1000), zeroblob(1000));
|
||||
INSERT INTO t1 VALUES(randomblob(1000), randomblob(1000));
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test 1.2 {
|
||||
sqlite3 db2 test.db2
|
||||
set stmt [sqlite3_prepare_v2 db2 "SELECT * FROM t2" -1 dummy]
|
||||
sqlite3_step $stmt
|
||||
} {SQLITE_ROW}
|
||||
|
||||
do_test 1.3 {
|
||||
list [catch { sqlite3_backup B db2 main db main } msg] $msg
|
||||
} {1 {sqlite3_backup_init() failed}}
|
||||
|
||||
do_test 1.4 {
|
||||
sqlite3_errmsg db2
|
||||
} {destination database is in use}
|
||||
|
||||
do_test 1.5 {
|
||||
sqlite3_reset $stmt
|
||||
sqlite3_backup B db2 main db main
|
||||
B step 200
|
||||
B finish
|
||||
} {SQLITE_OK}
|
||||
|
||||
do_test 1.6 {
|
||||
list [sqlite3_step $stmt] [sqlite3_finalize $stmt]
|
||||
} {SQLITE_ERROR SQLITE_ERROR}
|
||||
|
||||
do_test 1.7 {
|
||||
sqlite3_errmsg db2
|
||||
} {no such table: t2}
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,43 @@
|
||||
# 2014 November 26
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix bigsort
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# At one point there was an overflow problem if the product of the
|
||||
# cache-size and page-size was larger than 2^31. Causing an infinite
|
||||
# loop if the product was also an integer multiple of 2^32, or
|
||||
# inefficiency otherwise.
|
||||
#
|
||||
do_execsql_test 1.0 {
|
||||
PRAGMA page_size = 1024;
|
||||
CREATE TABLE t1(a, b);
|
||||
BEGIN;
|
||||
WITH data(x,y) AS (
|
||||
SELECT 1, zeroblob(10000)
|
||||
UNION ALL
|
||||
SELECT x+1, y FROM data WHERE x < 300000
|
||||
)
|
||||
INSERT INTO t1 SELECT * FROM data;
|
||||
COMMIT;
|
||||
}
|
||||
do_execsql_test 1.1 {
|
||||
PRAGMA cache_size = 4194304;
|
||||
CREATE INDEX i1 ON t1(a, b);
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
# 2014-11-27
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file contains test cases for b-tree logic.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix btree01
|
||||
|
||||
# The refactoring on the b-tree balance() routine in check-in
|
||||
# http://www.sqlite.org/src/info/face33bea1ba3a (2014-10-27)
|
||||
# caused the integrity_check on the following SQL to fail.
|
||||
#
|
||||
do_execsql_test btree01-1.1 {
|
||||
PRAGMA page_size=65536;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB);
|
||||
WITH RECURSIVE
|
||||
c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<30)
|
||||
INSERT INTO t1(a,b) SELECT i, zeroblob(6500) FROM c;
|
||||
UPDATE t1 SET b=zeroblob(3000);
|
||||
UPDATE t1 SET b=zeroblob(64000) WHERE a=2;
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
|
||||
# The previous test is sufficient to prevent a regression. But we
|
||||
# add a number of additional tests to stress the balancer in similar
|
||||
# ways, looking for related problems.
|
||||
#
|
||||
for {set i 1} {$i<=30} {incr i} {
|
||||
do_test btree01-1.2.$i {
|
||||
db eval {
|
||||
DELETE FROM t1;
|
||||
WITH RECURSIVE
|
||||
c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<30)
|
||||
INSERT INTO t1(a,b) SELECT i, zeroblob(6500) FROM c;
|
||||
UPDATE t1 SET b=zeroblob(3000);
|
||||
UPDATE t1 SET b=zeroblob(64000) WHERE a=$::i;
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} {ok}
|
||||
}
|
||||
for {set i 1} {$i<=30} {incr i} {
|
||||
do_test btree01-1.3.$i {
|
||||
db eval {
|
||||
DELETE FROM t1;
|
||||
WITH RECURSIVE
|
||||
c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<30)
|
||||
INSERT INTO t1(a,b) SELECT i, zeroblob(6500) FROM c;
|
||||
UPDATE t1 SET b=zeroblob(2000);
|
||||
UPDATE t1 SET b=zeroblob(64000) WHERE a=$::i;
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} {ok}
|
||||
}
|
||||
for {set i 1} {$i<=30} {incr i} {
|
||||
do_test btree01-1.4.$i {
|
||||
db eval {
|
||||
DELETE FROM t1;
|
||||
WITH RECURSIVE
|
||||
c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<30)
|
||||
INSERT INTO t1(a,b) SELECT i, zeroblob(6500) FROM c;
|
||||
UPDATE t1 SET b=zeroblob(6499) WHERE (a%3)==0;
|
||||
UPDATE t1 SET b=zeroblob(6499) WHERE (a%3)==1;
|
||||
UPDATE t1 SET b=zeroblob(6499) WHERE (a%3)==2;
|
||||
UPDATE t1 SET b=zeroblob(64000) WHERE a=$::i;
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} {ok}
|
||||
}
|
||||
for {set i 1} {$i<=30} {incr i} {
|
||||
do_test btree01-1.5.$i {
|
||||
db eval {
|
||||
DELETE FROM t1;
|
||||
WITH RECURSIVE
|
||||
c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<30)
|
||||
INSERT INTO t1(a,b) SELECT i, zeroblob(6542) FROM c;
|
||||
UPDATE t1 SET b=zeroblob(2331);
|
||||
UPDATE t1 SET b=zeroblob(65496) WHERE a=$::i;
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} {ok}
|
||||
}
|
||||
for {set i 1} {$i<=30} {incr i} {
|
||||
do_test btree01-1.6.$i {
|
||||
db eval {
|
||||
DELETE FROM t1;
|
||||
WITH RECURSIVE
|
||||
c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<30)
|
||||
INSERT INTO t1(a,b) SELECT i, zeroblob(6542) FROM c;
|
||||
UPDATE t1 SET b=zeroblob(2332);
|
||||
UPDATE t1 SET b=zeroblob(65496) WHERE a=$::i;
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} {ok}
|
||||
}
|
||||
for {set i 1} {$i<=30} {incr i} {
|
||||
do_test btree01-1.7.$i {
|
||||
db eval {
|
||||
DELETE FROM t1;
|
||||
WITH RECURSIVE
|
||||
c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<30)
|
||||
INSERT INTO t1(a,b) SELECT i, zeroblob(6500) FROM c;
|
||||
UPDATE t1 SET b=zeroblob(1);
|
||||
UPDATE t1 SET b=zeroblob(65000) WHERE a=$::i;
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} {ok}
|
||||
}
|
||||
for {set i 1} {$i<=31} {incr i} {
|
||||
do_test btree01-1.8.$i {
|
||||
db eval {
|
||||
DELETE FROM t1;
|
||||
WITH RECURSIVE
|
||||
c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<31)
|
||||
INSERT INTO t1(a,b) SELECT i, zeroblob(6500) FROM c;
|
||||
UPDATE t1 SET b=zeroblob(4000);
|
||||
UPDATE t1 SET b=zeroblob(65000) WHERE a=$::i;
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} {ok}
|
||||
}
|
||||
|
||||
finish_test
|
||||
+3
-3
@@ -912,7 +912,7 @@ do_test capi3-11.9.3 {
|
||||
} 1
|
||||
do_test capi3-11.10 {
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_ERROR}
|
||||
} {SQLITE_ROW}
|
||||
ifcapable !autoreset {
|
||||
# If SQLITE_OMIT_AUTORESET is defined, then the statement must be
|
||||
# reset() before it can be passed to step() again.
|
||||
@@ -921,11 +921,11 @@ ifcapable !autoreset {
|
||||
}
|
||||
do_test capi3-11.11 {
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_ROW}
|
||||
} {SQLITE_DONE}
|
||||
do_test capi3-11.12 {
|
||||
sqlite3_step $STMT
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_DONE}
|
||||
} {SQLITE_ROW}
|
||||
do_test capi3-11.13 {
|
||||
sqlite3_finalize $STMT
|
||||
} {SQLITE_OK}
|
||||
|
||||
+3
-3
@@ -863,7 +863,7 @@ do_test capi3c-11.9.3 {
|
||||
} 1
|
||||
do_test capi3c-11.10 {
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_ABORT}
|
||||
} {SQLITE_ROW}
|
||||
ifcapable !autoreset {
|
||||
# If SQLITE_OMIT_AUTORESET is defined, then the statement must be
|
||||
# reset() before it can be passed to step() again.
|
||||
@@ -872,11 +872,11 @@ ifcapable !autoreset {
|
||||
}
|
||||
do_test capi3c-11.11 {
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_ROW}
|
||||
} {SQLITE_DONE}
|
||||
do_test capi3c-11.12 {
|
||||
sqlite3_step $STMT
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_DONE}
|
||||
} {SQLITE_ROW}
|
||||
do_test capi3c-11.13 {
|
||||
sqlite3_finalize $STMT
|
||||
} {SQLITE_OK}
|
||||
|
||||
@@ -155,7 +155,6 @@ do_execsql_test capi3d-4.1 {
|
||||
}
|
||||
|
||||
do_test capi3d-4.2.1 {
|
||||
breakpoint
|
||||
set ::s1 [sqlite3_prepare_v2 db "ROLLBACK" -1 notused]
|
||||
sqlite3_step $::s1
|
||||
} {SQLITE_DONE}
|
||||
|
||||
@@ -64,7 +64,6 @@ do_test 1.2 {
|
||||
} {}
|
||||
|
||||
do_test 1.3 {
|
||||
breakpoint
|
||||
db eval { PRAGMA secure_delete=1 }
|
||||
list [catch {
|
||||
db eval { SELECT * FROM t1 WHERE a IN (1, 2) } {
|
||||
|
||||
@@ -222,4 +222,34 @@ do_execsql_test 4.1 {
|
||||
SELECT quote(x) FROM t2 ORDER BY 1;
|
||||
} {'xyzzy' X'0000000000'}
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Ticket [c5ea805691bfc4204b1cb9e9aa0103bd48bc7d34] (2014-12-04)
|
||||
# Make sure that DISTINCT works together with ORDER BY and descending
|
||||
# indexes.
|
||||
#
|
||||
do_execsql_test 5.1 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(x);
|
||||
INSERT INTO t1(x) VALUES(3),(1),(5),(2),(6),(4),(5),(1),(3);
|
||||
CREATE INDEX t1x ON t1(x DESC);
|
||||
SELECT DISTINCT x FROM t1 ORDER BY x ASC;
|
||||
} {1 2 3 4 5 6}
|
||||
do_execsql_test 5.2 {
|
||||
SELECT DISTINCT x FROM t1 ORDER BY x DESC;
|
||||
} {6 5 4 3 2 1}
|
||||
do_execsql_test 5.3 {
|
||||
SELECT DISTINCT x FROM t1 ORDER BY x;
|
||||
} {1 2 3 4 5 6}
|
||||
do_execsql_test 5.4 {
|
||||
DROP INDEX t1x;
|
||||
CREATE INDEX t1x ON t1(x ASC);
|
||||
SELECT DISTINCT x FROM t1 ORDER BY x ASC;
|
||||
} {1 2 3 4 5 6}
|
||||
do_execsql_test 5.5 {
|
||||
SELECT DISTINCT x FROM t1 ORDER BY x DESC;
|
||||
} {6 5 4 3 2 1}
|
||||
do_execsql_test 5.6 {
|
||||
SELECT DISTINCT x FROM t1 ORDER BY x;
|
||||
} {1 2 3 4 5 6}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
# 2014 October 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix e_blobbytes
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE q1(r INTEGER PRIMARY KEY, s TEXT);
|
||||
WITH d(a, b) AS (
|
||||
SELECT 0, ''
|
||||
UNION ALL
|
||||
SELECT a+1, b||'.' FROM d WHERE a<10000
|
||||
)
|
||||
INSERT INTO q1 SELECT * FROM d;
|
||||
}
|
||||
|
||||
|
||||
# EVIDENCE-OF: R-07796-55423 Returns the size in bytes of the BLOB
|
||||
# accessible via the successfully opened BLOB handle in its only
|
||||
# argument.
|
||||
#
|
||||
proc check_blob_size {tn rowid bytes} {
|
||||
uplevel [list do_test $tn [subst -nocommands {
|
||||
sqlite3_blob_open db main q1 s $rowid 0 B
|
||||
set res [sqlite3_blob_bytes [set B]]
|
||||
sqlite3_blob_close [set B]
|
||||
set res
|
||||
}] $bytes]
|
||||
}
|
||||
check_blob_size 1.1 43 43
|
||||
check_blob_size 1.2 391 391
|
||||
check_blob_size 1.3 6349 6349
|
||||
check_blob_size 1.4 2621 2621
|
||||
check_blob_size 1.5 7771 7771
|
||||
check_blob_size 1.6 7949 7949
|
||||
check_blob_size 1.7 4374 4374
|
||||
check_blob_size 1.8 2578 2578
|
||||
check_blob_size 1.9 7004 7004
|
||||
check_blob_size 1.10 2180 2180
|
||||
check_blob_size 1.11 3796 3796
|
||||
check_blob_size 1.12 7101 7101
|
||||
check_blob_size 1.13 7449 7449
|
||||
check_blob_size 1.14 7224 7224
|
||||
check_blob_size 1.15 3038 3038
|
||||
check_blob_size 1.16 1083 1083
|
||||
check_blob_size 1.17 5157 5157
|
||||
check_blob_size 1.18 6686 6686
|
||||
check_blob_size 1.19 6592 6592
|
||||
check_blob_size 1.20 0 0
|
||||
|
||||
|
||||
# EVIDENCE-OF: R-53088-19343 The incremental blob I/O routines can only
|
||||
# read or overwriting existing blob content; they cannot change the size
|
||||
# of a blob.
|
||||
#
|
||||
# Also demonstrated in other e_blobXXX.test files.
|
||||
#
|
||||
do_test 2.1 {
|
||||
sqlite3_blob_open db main q1 s 86 1 B
|
||||
list [catch { sqlite3_blob_write $B 86 "1" 1 } msg] $msg
|
||||
} {1 SQLITE_ERROR}
|
||||
sqlite3_blob_close $B
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
# 2014 October 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix e_blobclose
|
||||
|
||||
set dots [string repeat . 40]
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE x1(a INTEGER PRIMARY KEY, b DOTS);
|
||||
INSERT INTO x1 VALUES(-1, $dots);
|
||||
INSERT INTO x1 VALUES(-10, $dots);
|
||||
INSERT INTO x1 VALUES(-100, $dots);
|
||||
INSERT INTO x1 VALUES(-1000, $dots);
|
||||
INSERT INTO x1 VALUES(-10000, $dots);
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-03145-46390 This function closes an open BLOB handle.
|
||||
#
|
||||
# It's not clear how to test that a blob handle really is closed.
|
||||
# Attempting to use a closed blob handle will likely crash the process.
|
||||
# Assume here that if the SHARED lock on the db file is released,
|
||||
# the blob handle has been closed.
|
||||
#
|
||||
do_execsql_test 1.1 { PRAGMA lock_status } {main unlocked temp closed}
|
||||
sqlite3_blob_open db main x1 b -1 0 B
|
||||
do_execsql_test 1.2 { PRAGMA lock_status } {main shared temp closed}
|
||||
sqlite3_blob_close $B
|
||||
do_execsql_test 1.3 { PRAGMA lock_status } {main unlocked temp closed}
|
||||
|
||||
|
||||
# EVIDENCE-OF: R-34027-00617 If the blob handle being closed was opened
|
||||
# for read-write access, and if the database is in auto-commit mode and
|
||||
# there are no other open read-write blob handles or active write
|
||||
# statements, the current transaction is committed.
|
||||
#
|
||||
# 2.1.*: Transaction is not committed if there are other open
|
||||
# read-write blob handles.
|
||||
#
|
||||
# 2.2.*: Transaction is not committed if not in auto-commit mode.
|
||||
#
|
||||
# 2.3.*: Active write statements.
|
||||
#
|
||||
do_test 2.1.1 {
|
||||
sqlite3_blob_open db main x1 b -100 1 B1
|
||||
sqlite3_blob_open db main x1 b -1000 1 B2
|
||||
sqlite3_blob_open db main x1 b -10000 1 B3
|
||||
sqlite3_blob_open db main x1 b -10000 0 B4 ;# B4 is read-only!
|
||||
execsql { PRAGMA lock_status }
|
||||
} {main reserved temp closed}
|
||||
do_test 2.1.2 {
|
||||
sqlite3_blob_close $B1
|
||||
execsql { PRAGMA lock_status }
|
||||
} {main reserved temp closed}
|
||||
do_test 2.1.3 {
|
||||
sqlite3_blob_close $B2
|
||||
execsql { PRAGMA lock_status }
|
||||
} {main reserved temp closed}
|
||||
do_test 2.1.4 {
|
||||
sqlite3_blob_close $B3
|
||||
execsql { PRAGMA lock_status }
|
||||
} {main shared temp closed}
|
||||
do_test 2.1.5 {
|
||||
sqlite3_blob_close $B4
|
||||
execsql { PRAGMA lock_status }
|
||||
} {main unlocked temp closed}
|
||||
|
||||
do_test 2.2.1 {
|
||||
sqlite3_blob_open db main x1 b -100 1 B1
|
||||
execsql { PRAGMA lock_status }
|
||||
} {main reserved temp closed}
|
||||
do_test 2.2.2 {
|
||||
execsql { BEGIN }
|
||||
sqlite3_blob_close $B1
|
||||
execsql { PRAGMA lock_status }
|
||||
} {main reserved temp closed}
|
||||
do_test 2.2.3 {
|
||||
execsql { COMMIT }
|
||||
execsql { PRAGMA lock_status }
|
||||
} {main unlocked temp closed}
|
||||
|
||||
proc val {} {
|
||||
sqlite3_blob_close $::B
|
||||
db eval { PRAGMA lock_status }
|
||||
}
|
||||
db func val val
|
||||
do_test 2.3.1 {
|
||||
sqlite3_blob_open db main x1 b -100 1 B
|
||||
execsql { PRAGMA lock_status }
|
||||
} {main reserved temp closed}
|
||||
do_test 2.3.2 {
|
||||
execsql { INSERT INTO x1 VALUES(15, val()) }
|
||||
execsql { PRAGMA lock_status }
|
||||
} {main unlocked temp closed}
|
||||
do_test 2.3.3 {
|
||||
execsql { SELECT * FROM x1 WHERE a = 15 }
|
||||
} {15 {main reserved temp closed}}
|
||||
|
||||
# A reader does not inhibit commit.
|
||||
do_test 2.3.4 {
|
||||
sqlite3_blob_open db main x1 b -100 1 B
|
||||
execsql { PRAGMA lock_status }
|
||||
} {main reserved temp closed}
|
||||
do_test 2.3.5 {
|
||||
execsql { SELECT a, val() FROM x1 LIMIT 1 }
|
||||
} {-10000 {main shared temp closed}}
|
||||
|
||||
|
||||
do_test 3.1 {
|
||||
sqlite3_blob_open db main x1 b -10 1 B
|
||||
execsql {
|
||||
INSERT INTO x1 VALUES(1, 'abc');
|
||||
SELECT * FROM x1 WHERE a=1;
|
||||
}
|
||||
} {1 abc}
|
||||
do_test 3.2 {
|
||||
sqlite3_blob_write $B 0 "abcdefghij" 10
|
||||
execsql { SELECT * FROM x1 WHERE a=-10 }
|
||||
} {-10 abcdefghij..............................}
|
||||
|
||||
do_test 3.3 {
|
||||
sqlite3 db2 test.db
|
||||
execsql { BEGIN ; SELECT * FROM x1 } db2
|
||||
sqlite3_blob_close $B
|
||||
} {SQLITE_BUSY}
|
||||
|
||||
# EVIDENCE-OF: R-41959-38737 Otherwise, if this function is passed a
|
||||
# valid open blob handle, the values returned by the sqlite3_errcode()
|
||||
# and sqlite3_errmsg() functions are set before returning.
|
||||
#
|
||||
do_test 3.4 {
|
||||
list [sqlite3_errcode db] [sqlite3_errmsg db]
|
||||
} {SQLITE_BUSY {database is locked}}
|
||||
|
||||
# EVIDENCE-OF: R-37801-37633 The BLOB handle is closed unconditionally.
|
||||
# Even if this routine returns an error code, the handle is still
|
||||
# closed.
|
||||
#
|
||||
# Test that the lock has been released. Assume this means the handle
|
||||
# is closed, even though blob_close() returned SQLITE_BUSY.
|
||||
#
|
||||
do_execsql_test 3.4 { PRAGMA lock_status } {main unlocked temp closed}
|
||||
|
||||
# EVIDENCE-OF: R-35111-05628 If an error occurs while committing the
|
||||
# transaction, an error code is returned and the transaction rolled
|
||||
# back.
|
||||
#
|
||||
# Row 1 is removed (it was inserted this transaction) and row -10
|
||||
# is restored to its original state. Transaction has been rolled back.
|
||||
#
|
||||
do_execsql_test 3.5 {
|
||||
SELECT * FROM x1 WHERE a IN (1, -10);
|
||||
} {-10 ........................................}
|
||||
|
||||
# EVIDENCE-OF: R-25894-51060 Calling this routine with a null pointer
|
||||
# (such as would be returned by a failed call to sqlite3_blob_open()) is
|
||||
# a harmless no-op.
|
||||
#
|
||||
do_test 4.0 { sqlite3_blob_close 0 } {}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,549 @@
|
||||
# 2014 October 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix e_blobopen
|
||||
|
||||
forcedelete test.db2
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
ATTACH 'test.db2' AS aux;
|
||||
|
||||
CREATE TABLE main.t1(a INTEGER PRIMARY KEY, b TEXT, c BLOB);
|
||||
CREATE TEMP TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c BLOB);
|
||||
CREATE TABLE aux.t1(a INTEGER PRIMARY KEY, b TEXT, c BLOB);
|
||||
|
||||
CREATE TABLE main.x1(a INTEGER PRIMARY KEY, b TEXT, c BLOB);
|
||||
CREATE TEMP TABLE x2(a INTEGER PRIMARY KEY, b TEXT, c BLOB);
|
||||
CREATE TABLE aux.x3(a INTEGER PRIMARY KEY, b TEXT, c BLOB);
|
||||
|
||||
INSERT INTO main.t1 VALUES(1, 'main one', X'0101');
|
||||
INSERT INTO main.t1 VALUES(2, 'main two', X'0102');
|
||||
INSERT INTO main.t1 VALUES(3, 'main three', X'0103');
|
||||
INSERT INTO main.t1 VALUES(4, 'main four', X'0104');
|
||||
INSERT INTO main.t1 VALUES(5, 'main five', X'0105');
|
||||
|
||||
INSERT INTO main.x1 VALUES(1, 'x main one', X'000101');
|
||||
INSERT INTO main.x1 VALUES(2, 'x main two', X'000102');
|
||||
INSERT INTO main.x1 VALUES(3, 'x main three', X'000103');
|
||||
INSERT INTO main.x1 VALUES(4, 'x main four', X'000104');
|
||||
INSERT INTO main.x1 VALUES(5, 'x main five', X'000105');
|
||||
|
||||
INSERT INTO temp.t1 VALUES(1, 'temp one', X'0201');
|
||||
INSERT INTO temp.t1 VALUES(2, 'temp two', X'0202');
|
||||
INSERT INTO temp.t1 VALUES(3, 'temp three', X'0203');
|
||||
INSERT INTO temp.t1 VALUES(4, 'temp four', X'0204');
|
||||
INSERT INTO temp.t1 VALUES(5, 'temp five', X'0205');
|
||||
|
||||
INSERT INTO temp.x2 VALUES(1, 'x temp one', X'000201');
|
||||
INSERT INTO temp.x2 VALUES(2, 'x temp two', X'000202');
|
||||
INSERT INTO temp.x2 VALUES(3, 'x temp three', X'000203');
|
||||
INSERT INTO temp.x2 VALUES(4, 'x temp four', X'000204');
|
||||
INSERT INTO temp.x2 VALUES(5, 'x temp five', X'000205');
|
||||
|
||||
INSERT INTO aux.t1 VALUES(1, 'aux one', X'0301');
|
||||
INSERT INTO aux.t1 VALUES(2, 'aux two', X'0302');
|
||||
INSERT INTO aux.t1 VALUES(3, 'aux three', X'0303');
|
||||
INSERT INTO aux.t1 VALUES(4, 'aux four', X'0304');
|
||||
INSERT INTO aux.t1 VALUES(5, 'aux five', X'0305');
|
||||
|
||||
INSERT INTO aux.x3 VALUES(1, 'x aux one', X'000301');
|
||||
INSERT INTO aux.x3 VALUES(2, 'x aux two', X'000302');
|
||||
INSERT INTO aux.x3 VALUES(3, 'x aux three', X'000303');
|
||||
INSERT INTO aux.x3 VALUES(4, 'x aux four', X'000304');
|
||||
INSERT INTO aux.x3 VALUES(5, 'x aux five', X'000305');
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# EVIDENCE-OF: R-37639-55938 This interfaces opens a handle to the BLOB
|
||||
# located in row iRow, column zColumn, table zTable in database zDb; in
|
||||
# other words, the same BLOB that would be selected by: SELECT zColumn
|
||||
# FROM zDb.zTable WHERE rowid = iRow;
|
||||
#
|
||||
proc read_blob {zDb zTab zCol iRow} {
|
||||
sqlite3_blob_open db $zDb $zTab $zCol $iRow 0 B
|
||||
set nByte [sqlite3_blob_bytes $B]
|
||||
set data [sqlite3_blob_read $B 0 $nByte]
|
||||
sqlite3_blob_close $B
|
||||
return $data
|
||||
}
|
||||
|
||||
do_test 1.1.1 { read_blob main t1 b 1 } "main one"
|
||||
do_test 1.1.2 { read_blob main t1 c 1 } "\01\01"
|
||||
do_test 1.1.3 { read_blob temp t1 b 1 } "temp one"
|
||||
do_test 1.1.4 { read_blob temp t1 c 1 } "\02\01"
|
||||
do_test 1.1.6 { read_blob aux t1 b 1 } "aux one"
|
||||
do_test 1.1.7 { read_blob aux t1 c 1 } "\03\01"
|
||||
|
||||
do_test 1.2.1 { read_blob main t1 b 4 } "main four"
|
||||
do_test 1.2.2 { read_blob main t1 c 4 } "\01\04"
|
||||
do_test 1.2.3 { read_blob temp t1 b 4 } "temp four"
|
||||
do_test 1.2.4 { read_blob temp t1 c 4 } "\02\04"
|
||||
do_test 1.2.6 { read_blob aux t1 b 4 } "aux four"
|
||||
do_test 1.2.7 { read_blob aux t1 c 4 } "\03\04"
|
||||
|
||||
do_test 1.3.1 { read_blob main x1 b 2 } "x main two"
|
||||
do_test 1.3.2 { read_blob main x1 c 2 } "\00\01\02"
|
||||
do_test 1.3.3 { read_blob temp x2 b 2 } "x temp two"
|
||||
do_test 1.3.4 { read_blob temp x2 c 2 } "\00\02\02"
|
||||
do_test 1.3.6 { read_blob aux x3 b 2 } "x aux two"
|
||||
do_test 1.3.7 { read_blob aux x3 c 2 } "\00\03\02"
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# EVIDENCE-OF: R-27234-05761 Parameter zDb is not the filename that
|
||||
# contains the database, but rather the symbolic name of the database.
|
||||
# For attached databases, this is the name that appears after the AS
|
||||
# keyword in the ATTACH statement. For the main database file, the
|
||||
# database name is "main". For TEMP tables, the database name is "temp".
|
||||
#
|
||||
# The test cases immediately above demonstrate that the database name
|
||||
# for the main db, for TEMP tables and for those in attached databases
|
||||
# is correct. The following tests check that filenames cannot be
|
||||
# used as well.
|
||||
#
|
||||
do_test 2.1 {
|
||||
list [catch { sqlite3_blob_open db "test.db" t1 b 1 0 B } msg] $msg
|
||||
} {1 SQLITE_ERROR}
|
||||
do_test 2.2 {
|
||||
list [catch { sqlite3_blob_open db "test.db2" t1 b 1 0 B } msg] $msg
|
||||
} {1 SQLITE_ERROR}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# EVIDENCE-OF: R-50854-53979 If the flags parameter is non-zero, then
|
||||
# the BLOB is opened for read and write access.
|
||||
#
|
||||
# EVIDENCE-OF: R-03922-41160 If the flags parameter is zero, the BLOB is
|
||||
# opened for read-only access.
|
||||
#
|
||||
foreach {tn iRow flags} {
|
||||
1 1 0
|
||||
2 2 1
|
||||
3 3 -1
|
||||
4 4 2147483647
|
||||
5 5 -2147483648
|
||||
} {
|
||||
do_test 3.$tn.1 {
|
||||
sqlite3_blob_open db main x1 c $iRow $flags B
|
||||
set n [sqlite3_blob_bytes $B]
|
||||
sqlite3_blob_read $B 0 $n
|
||||
} [binary format ccc 0 1 $iRow]
|
||||
|
||||
if {$flags==0} {
|
||||
# Blob was opened for read-only access - writing returns an error.
|
||||
do_test 3.$tn.2 {
|
||||
list [catch { sqlite3_blob_write $B 0 xxx 3 } msg] $msg
|
||||
} {1 SQLITE_READONLY}
|
||||
|
||||
do_execsql_test 3.$tn.3 {
|
||||
SELECT c FROM x1 WHERE a=$iRow;
|
||||
} [binary format ccc 0 1 $iRow]
|
||||
} else {
|
||||
# Blob was opened for read/write access - writing succeeds
|
||||
do_test 3.$tn.4 {
|
||||
list [catch { sqlite3_blob_write $B 0 xxx 3 } msg] $msg
|
||||
} {0 {}}
|
||||
|
||||
do_execsql_test 3.$tn.5 {
|
||||
SELECT c FROM x1 WHERE a=$iRow;
|
||||
} {xxx}
|
||||
}
|
||||
|
||||
sqlite3_blob_close $B
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE t1(x, y);
|
||||
INSERT INTO t1 VALUES('abcd', 152);
|
||||
INSERT INTO t1 VALUES(NULL, X'00010203');
|
||||
INSERT INTO t1 VALUES('', 154.2);
|
||||
|
||||
CREATE TABLE t2(x PRIMARY KEY, y) WITHOUT ROWID;
|
||||
INSERT INTO t2 VALUES(1, 'blob');
|
||||
|
||||
CREATE TABLE t3(a PRIMARY KEY, b, c, d, e, f, UNIQUE(e, f));
|
||||
INSERT INTO t3 VALUES('aaaa', 'bbbb', 'cccc', 'dddd', 'eeee', 'ffff');
|
||||
CREATE INDEX t3b ON t3(b);
|
||||
|
||||
CREATE TABLE p1(x PRIMARY KEY);
|
||||
INSERT INTO p1 VALUES('abc');
|
||||
|
||||
CREATE TABLE c1(a INTEGER PRIMARY KEY, b REFERENCES p1);
|
||||
INSERT INTO c1 VALUES(45, 'abc');
|
||||
}
|
||||
|
||||
proc test_blob_open {tn zDb zTab zCol iRow flags errcode errmsg} {
|
||||
global B
|
||||
set B "0x1234"
|
||||
|
||||
if {$errcode=="SQLITE_OK"} {
|
||||
set expected "0 {}"
|
||||
} else {
|
||||
set expected "1 $errcode"
|
||||
}
|
||||
|
||||
set ::res [list [
|
||||
catch { sqlite3_blob_open db $zDb $zTab $zCol $iRow $flags B } msg
|
||||
] $msg]
|
||||
do_test 4.$tn.1 { set ::res } $expected
|
||||
|
||||
# EVIDENCE-OF: R-08940-21305 Unless it returns SQLITE_MISUSE, this
|
||||
# function sets the database connection error code and message
|
||||
# accessible via sqlite3_errcode() and sqlite3_errmsg() and related
|
||||
# functions.
|
||||
#
|
||||
# This proc (test_blob_open) is used below to test various error and
|
||||
# non-error conditions. But never SQLITE_MISUSE conditions. So these
|
||||
# test cases are considered as partly verifying the requirement above.
|
||||
# See below for a test of the SQLITE_MISUSE case.
|
||||
#
|
||||
do_test 4.$tn.2 {
|
||||
sqlite3_errcode db
|
||||
} $errcode
|
||||
do_test 4.$tn.3 {
|
||||
sqlite3_errmsg db
|
||||
} $errmsg
|
||||
|
||||
# EVIDENCE-OF: R-31086-35521 On success, SQLITE_OK is returned and the
|
||||
# new BLOB handle is stored in *ppBlob. Otherwise an error code is
|
||||
# returned and, unless the error code is SQLITE_MISUSE, *ppBlob is set
|
||||
# to NULL.
|
||||
#
|
||||
do_test 4.$tn.4 {
|
||||
expr {$B == "0"}
|
||||
} [expr {$errcode != "SQLITE_OK"}]
|
||||
|
||||
# EVIDENCE-OF: R-63421-15521 This means that, provided the API is not
|
||||
# misused, it is always safe to call sqlite3_blob_close() on *ppBlob
|
||||
# after this function it returns.
|
||||
do_test 4.$tn.5 {
|
||||
sqlite3_blob_close $B
|
||||
} {}
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-31204-44780 Database zDb does not exist
|
||||
test_blob_open 1 nosuchdb t1 x 1 0 SQLITE_ERROR "no such table: nosuchdb.t1"
|
||||
|
||||
# EVIDENCE-OF: R-28676-08005 Table zTable does not exist within database zDb
|
||||
test_blob_open 2 main tt1 x 1 0 SQLITE_ERROR "no such table: main.tt1"
|
||||
|
||||
# EVIDENCE-OF: R-40134-30296 Table zTable is a WITHOUT ROWID table
|
||||
test_blob_open 3 main t2 y 1 0 SQLITE_ERROR \
|
||||
"cannot open table without rowid: t2"
|
||||
|
||||
# EVIDENCE-OF: R-56376-21261 Column zColumn does not exist
|
||||
test_blob_open 4 main t1 z 2 0 SQLITE_ERROR "no such column: \"z\""
|
||||
|
||||
# EVIDENCE-OF: R-28258-23166 Row iRow is not present in the table
|
||||
test_blob_open 5 main t1 y 6 0 SQLITE_ERROR "no such rowid: 6"
|
||||
|
||||
# EVIDENCE-OF: R-11683-62380 The specified column of row iRow contains a
|
||||
# value that is not a TEXT or BLOB value
|
||||
test_blob_open 6 main t1 x 2 0 SQLITE_ERROR "cannot open value of type null"
|
||||
test_blob_open 7 main t1 y 1 0 SQLITE_ERROR "cannot open value of type integer"
|
||||
test_blob_open 8 main t1 y 3 0 SQLITE_ERROR "cannot open value of type real"
|
||||
|
||||
# EVIDENCE-OF: R-34146-30782 Column zColumn is part of an index, PRIMARY
|
||||
# KEY or UNIQUE constraint and the blob is being opened for read/write
|
||||
# access
|
||||
#
|
||||
# Test cases 8.1.* show that such columns can be opened for read-access.
|
||||
# Tests 8.2.* show that read-write access is different. Columns "c" and "c"
|
||||
# are not part of an index, PK or UNIQUE constraint, so they work in both
|
||||
# cases.
|
||||
#
|
||||
test_blob_open 8.1.1 main t3 a 1 0 SQLITE_OK "not an error"
|
||||
test_blob_open 8.1.2 main t3 b 1 0 SQLITE_OK "not an error"
|
||||
test_blob_open 8.1.3 main t3 c 1 0 SQLITE_OK "not an error"
|
||||
test_blob_open 8.1.4 main t3 d 1 0 SQLITE_OK "not an error"
|
||||
test_blob_open 8.1.5 main t3 e 1 0 SQLITE_OK "not an error"
|
||||
test_blob_open 8.1.6 main t3 f 1 0 SQLITE_OK "not an error"
|
||||
|
||||
set cannot "cannot open indexed column for writing"
|
||||
test_blob_open 8.2.1 main t3 a 1 8 SQLITE_ERROR $cannot
|
||||
test_blob_open 8.2.2 main t3 b 1 8 SQLITE_ERROR $cannot
|
||||
test_blob_open 8.2.3 main t3 c 1 8 SQLITE_OK "not an error"
|
||||
test_blob_open 8.2.4 main t3 d 1 8 SQLITE_OK "not an error"
|
||||
test_blob_open 8.2.5 main t3 e 1 8 SQLITE_ERROR $cannot
|
||||
test_blob_open 8.2.6 main t3 f 1 8 SQLITE_ERROR $cannot
|
||||
|
||||
# EVIDENCE-OF: R-50117-55204 Foreign key constraints are enabled, column
|
||||
# zColumn is part of a child key definition and the blob is being opened
|
||||
# for read/write access
|
||||
#
|
||||
# 9.1: FK disabled, read-only access.
|
||||
# 9.2: FK disabled, read-only access.
|
||||
# 9.3: FK enabled, read/write access.
|
||||
# 9.4: FK enabled, read/write access.
|
||||
#
|
||||
test_blob_open 9.1 main c1 b 45 0 SQLITE_OK "not an error"
|
||||
test_blob_open 9.2 main c1 b 45 1 SQLITE_OK "not an error"
|
||||
execsql { PRAGMA foreign_keys = ON }
|
||||
test_blob_open 9.3 main c1 b 45 0 SQLITE_OK "not an error"
|
||||
test_blob_open 9.4 main c1 b 45 1 SQLITE_ERROR \
|
||||
"cannot open foreign key column for writing"
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# EVIDENCE-OF: R-08940-21305 Unless it returns SQLITE_MISUSE, this
|
||||
# function sets the database connection error code and message
|
||||
# accessible via sqlite3_errcode() and sqlite3_errmsg() and related
|
||||
# functions.
|
||||
#
|
||||
# This requirement is partially verified by the many uses of test
|
||||
# command [test_blob_open] above. All that is left is to verify the
|
||||
# SQLITE_MISUSE case.
|
||||
#
|
||||
# SQLITE_MISUSE is only returned if SQLITE_ENABLE_API_ARMOR is defined
|
||||
# during compilation.
|
||||
#
|
||||
ifcapable api_armor {
|
||||
sqlite3_blob_open db main t1 x 1 0 B
|
||||
|
||||
do_test 10.1.1 {
|
||||
list [catch {sqlite3_blob_open $B main t1 x 1 0 B2} msg] $msg
|
||||
} {1 SQLITE_MISUSE}
|
||||
do_test 10.1.2 {
|
||||
list [sqlite3_errcode db] [sqlite3_errmsg db]
|
||||
} {SQLITE_OK {not an error}}
|
||||
sqlite3_blob_close $B
|
||||
|
||||
do_test 10.2.1 {
|
||||
list [catch {sqlite3_blob_open db main {} x 1 0 B} msg] $msg
|
||||
} {1 SQLITE_MISUSE}
|
||||
do_test 10.2.2 {
|
||||
list [sqlite3_errcode db] [sqlite3_errmsg db]
|
||||
} {SQLITE_OK {not an error}}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# EVIDENCE-OF: R-50542-62589 If the row that a BLOB handle points to is
|
||||
# modified by an UPDATE, DELETE, or by ON CONFLICT side-effects then the
|
||||
# BLOB handle is marked as "expired". This is true if any column of the
|
||||
# row is changed, even a column other than the one the BLOB handle is
|
||||
# open on.
|
||||
#
|
||||
# EVIDENCE-OF: R-48367-20048 Calls to sqlite3_blob_read() and
|
||||
# sqlite3_blob_write() for an expired BLOB handle fail with a return
|
||||
# code of SQLITE_ABORT.
|
||||
#
|
||||
# 11.2: read-only handle, DELETE.
|
||||
# 11.3: read-only handle, UPDATE.
|
||||
# 11.4: read-only handle, REPLACE.
|
||||
# 11.5: read/write handle, DELETE.
|
||||
# 11.6: read/write handle, UPDATE.
|
||||
# 11.7: read/write handle, REPLACE.
|
||||
#
|
||||
do_execsql_test 11.1 {
|
||||
CREATE TABLE b1(a INTEGER PRIMARY KEY, b, c UNIQUE);
|
||||
INSERT INTO b1 VALUES(1, '1234567890', 1);
|
||||
INSERT INTO b1 VALUES(2, '1234567890', 2);
|
||||
INSERT INTO b1 VALUES(3, '1234567890', 3);
|
||||
INSERT INTO b1 VALUES(4, '1234567890', 4);
|
||||
INSERT INTO b1 VALUES(5, '1234567890', 5);
|
||||
INSERT INTO b1 VALUES(6, '1234567890', 6);
|
||||
|
||||
CREATE TABLE b2(a INTEGER PRIMARY KEY, b, c UNIQUE);
|
||||
INSERT INTO b2 VALUES(1, '1234567890', 1);
|
||||
INSERT INTO b2 VALUES(2, '1234567890', 2);
|
||||
INSERT INTO b2 VALUES(3, '1234567890', 3);
|
||||
INSERT INTO b2 VALUES(4, '1234567890', 4);
|
||||
INSERT INTO b2 VALUES(5, '1234567890', 5);
|
||||
INSERT INTO b2 VALUES(6, '1234567890', 6);
|
||||
}
|
||||
|
||||
do_test 11.2.1 {
|
||||
sqlite3_blob_open db main b1 b 2 0 B
|
||||
sqlite3_blob_read $B 0 10
|
||||
} {1234567890}
|
||||
do_test 11.2.2 {
|
||||
# Deleting a different row does not invalidate the blob handle.
|
||||
execsql { DELETE FROM b1 WHERE a = 1 }
|
||||
sqlite3_blob_read $B 0 10
|
||||
} {1234567890}
|
||||
do_test 11.2.3 {
|
||||
execsql { DELETE FROM b1 WHERE a = 2 }
|
||||
list [catch { sqlite3_blob_read $B 0 10 } msg] $msg
|
||||
} {1 SQLITE_ABORT}
|
||||
do_test 11.2.4 {
|
||||
sqlite3_blob_close $B
|
||||
} {}
|
||||
|
||||
do_test 11.3.1 {
|
||||
sqlite3_blob_open db main b1 b 3 0 B
|
||||
sqlite3_blob_read $B 0 10
|
||||
} {1234567890}
|
||||
do_test 11.3.2 {
|
||||
# Updating a different row
|
||||
execsql { UPDATE b1 SET c = 42 WHERE a=4 }
|
||||
sqlite3_blob_read $B 0 10
|
||||
} {1234567890}
|
||||
do_test 11.3.3 {
|
||||
execsql { UPDATE b1 SET c = 43 WHERE a=3 }
|
||||
list [catch { sqlite3_blob_read $B 0 10 } msg] $msg
|
||||
} {1 SQLITE_ABORT}
|
||||
do_test 11.3.4 {
|
||||
sqlite3_blob_close $B
|
||||
} {}
|
||||
|
||||
do_test 11.4.1 {
|
||||
sqlite3_blob_open db main b1 b 6 0 B
|
||||
sqlite3_blob_read $B 0 10
|
||||
} {1234567890}
|
||||
do_test 11.4.2 {
|
||||
# Replace a different row
|
||||
execsql { INSERT OR REPLACE INTO b1 VALUES(10, 'abcdefghij', 5) }
|
||||
sqlite3_blob_read $B 0 10
|
||||
} {1234567890}
|
||||
do_test 11.4.3 {
|
||||
execsql { INSERT OR REPLACE INTO b1 VALUES(11, 'abcdefghij', 6) }
|
||||
list [catch { sqlite3_blob_read $B 0 10 } msg] $msg
|
||||
} {1 SQLITE_ABORT}
|
||||
do_test 11.4.4 {
|
||||
sqlite3_blob_close $B
|
||||
} {}
|
||||
|
||||
do_test 11.4.1 {
|
||||
sqlite3_blob_open db main b2 b 2 1 B
|
||||
sqlite3_blob_write $B 0 "abcdefghij"
|
||||
} {}
|
||||
do_test 11.4.2 {
|
||||
# Deleting a different row does not invalidate the blob handle.
|
||||
execsql { DELETE FROM b2 WHERE a = 1 }
|
||||
sqlite3_blob_write $B 0 "ABCDEFGHIJ"
|
||||
} {}
|
||||
do_test 11.4.3 {
|
||||
execsql { DELETE FROM b2 WHERE a = 2 }
|
||||
list [catch { sqlite3_blob_write $B 0 "0987654321" } msg] $msg
|
||||
} {1 SQLITE_ABORT}
|
||||
do_test 11.4.4 {
|
||||
sqlite3_blob_close $B
|
||||
} {}
|
||||
|
||||
do_test 11.5.1 {
|
||||
sqlite3_blob_open db main b2 b 3 1 B
|
||||
sqlite3_blob_write $B 0 "abcdefghij"
|
||||
} {}
|
||||
do_test 11.5.2 {
|
||||
# Updating a different row
|
||||
execsql { UPDATE b2 SET c = 42 WHERE a=4 }
|
||||
sqlite3_blob_write $B 0 "ABCDEFGHIJ"
|
||||
} {}
|
||||
do_test 11.5.3 {
|
||||
execsql { UPDATE b2 SET c = 43 WHERE a=3 }
|
||||
list [catch { sqlite3_blob_write $B 0 "0987654321" } msg] $msg
|
||||
} {1 SQLITE_ABORT}
|
||||
do_test 11.5.4 {
|
||||
sqlite3_blob_close $B
|
||||
} {}
|
||||
|
||||
do_test 11.6.1 {
|
||||
sqlite3_blob_open db main b2 b 6 1 B
|
||||
sqlite3_blob_write $B 0 "abcdefghij"
|
||||
} {}
|
||||
do_test 11.6.2 {
|
||||
# Replace a different row
|
||||
execsql { INSERT OR REPLACE INTO b2 VALUES(10, 'abcdefghij', 5) }
|
||||
sqlite3_blob_write $B 0 "ABCDEFGHIJ"
|
||||
} {}
|
||||
do_test 11.6.3 {
|
||||
execsql { INSERT OR REPLACE INTO b2 VALUES(11, 'abcdefghij', 6) }
|
||||
list [catch { sqlite3_blob_write $B 0 "0987654321" } msg] $msg
|
||||
} {1 SQLITE_ABORT}
|
||||
do_test 11.6.4 {
|
||||
sqlite3_blob_close $B
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# EVIDENCE-OF: R-45408-40694 Changes written into a BLOB prior to the
|
||||
# BLOB expiring are not rolled back by the expiration of the BLOB. Such
|
||||
# changes will eventually commit if the transaction continues to
|
||||
# completion.
|
||||
#
|
||||
do_execsql_test 12.1 {
|
||||
CREATE TABLE b3(x INTEGER PRIMARY KEY, y TEXT, z INTEGER);
|
||||
INSERT INTO b3 VALUES(22, '..........', NULL);
|
||||
}
|
||||
do_test 12.2 {
|
||||
sqlite3_blob_open db main b3 y 22 1 B
|
||||
sqlite3_blob_write $B 0 "xxxxx" 5
|
||||
} {}
|
||||
do_execsql_test 12.3 {
|
||||
UPDATE b3 SET z = 'not null';
|
||||
}
|
||||
do_test 12.4 {
|
||||
list [catch {sqlite3_blob_write $B 5 "xxxxx" 5} msg] $msg
|
||||
} {1 SQLITE_ABORT}
|
||||
do_execsql_test 12.5 {
|
||||
SELECT * FROM b3;
|
||||
} {22 xxxxx..... {not null}}
|
||||
do_test 12.5 {
|
||||
sqlite3_blob_close $B
|
||||
} {}
|
||||
do_execsql_test 12.6 {
|
||||
SELECT * FROM b3;
|
||||
} {22 xxxxx..... {not null}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# EVIDENCE-OF: R-58813-55036 The sqlite3_bind_zeroblob() and
|
||||
# sqlite3_result_zeroblob() interfaces and the built-in zeroblob SQL
|
||||
# function may be used to create a zero-filled blob to read or write
|
||||
# using the incremental-blob interface.
|
||||
#
|
||||
do_execsql_test 13.1 {
|
||||
CREATE TABLE c2(i INTEGER PRIMARY KEY, j);
|
||||
INSERT INTO c2 VALUES(10, zeroblob(24));
|
||||
}
|
||||
|
||||
do_test 13.2 {
|
||||
set stmt [sqlite3_prepare_v2 db "INSERT INTO c2 VALUES(11, ?)" -1]
|
||||
sqlite3_bind_zeroblob $stmt 1 45
|
||||
sqlite3_step $stmt
|
||||
sqlite3_finalize $stmt
|
||||
} {SQLITE_OK}
|
||||
|
||||
# The blobs can be read:
|
||||
#
|
||||
do_test 13.3.1 {
|
||||
sqlite3_blob_open db main c2 j 10 1 B
|
||||
sqlite3_blob_open db main c2 j 11 1 B2
|
||||
list [sqlite3_blob_bytes $B] [sqlite3_blob_bytes $B2]
|
||||
} {24 45}
|
||||
do_test 13.3.2 {
|
||||
sqlite3_blob_read $B 0 24
|
||||
} [string repeat [binary format c 0] 24]
|
||||
do_test 13.3.3 {
|
||||
sqlite3_blob_read $B2 0 45
|
||||
} [string repeat [binary format c 0] 45]
|
||||
|
||||
# And also written:
|
||||
#
|
||||
do_test 13.4.1 {
|
||||
sqlite3_blob_write $B 0 [string repeat [binary format c 1] 24]
|
||||
} {}
|
||||
do_test 13.4.2 {
|
||||
sqlite3_blob_write $B2 0 [string repeat [binary format c 1] 45]
|
||||
} {}
|
||||
do_test 13.5 {
|
||||
sqlite3_blob_close $B
|
||||
sqlite3_blob_close $B2
|
||||
execsql { SELECT j FROM c2 }
|
||||
} [list \
|
||||
[string repeat [binary format c 1] 24] \
|
||||
[string repeat [binary format c 1] 45] \
|
||||
]
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
# 2014 October 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix e_blobwrite
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
# EVIDENCE-OF: R-62898-22698 This function is used to write data into an
|
||||
# open BLOB handle from a caller-supplied buffer. N bytes of data are
|
||||
# copied from the buffer Z into the open BLOB, starting at offset
|
||||
# iOffset.
|
||||
#
|
||||
set dots [string repeat . 40]
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, t TEXT);
|
||||
INSERT INTO t1 VALUES(-1, $dots);
|
||||
INSERT INTO t1 VALUES(-2, $dots);
|
||||
INSERT INTO t1 VALUES(-3, $dots);
|
||||
INSERT INTO t1 VALUES(-4, $dots);
|
||||
INSERT INTO t1 VALUES(-5, $dots);
|
||||
INSERT INTO t1 VALUES(-6, $dots);
|
||||
}
|
||||
|
||||
proc blob_write_test {tn id iOffset blob nData final} {
|
||||
sqlite3_blob_open db main t1 t $id 1 B
|
||||
|
||||
# EVIDENCE-OF: R-45864-01884 On success, sqlite3_blob_write() returns
|
||||
# SQLITE_OK. Otherwise, an error code or an extended error code is
|
||||
# returned.
|
||||
#
|
||||
# This block tests the SQLITE_OK case in the requirement above (the
|
||||
# Tcl sqlite3_blob_write() wrapper uses an empty string in place of
|
||||
# "SQLITE_OK"). The error cases are tested by the "blob_write_error_test"
|
||||
# tests below.
|
||||
#
|
||||
set res [sqlite3_blob_write $B $iOffset $blob $nData]
|
||||
uplevel [list do_test $tn.1 [list set {} $res] {}]
|
||||
|
||||
sqlite3_blob_close $B
|
||||
uplevel [list do_execsql_test $tn.3 "SELECT t FROM t1 WHERE a=$id" $final]
|
||||
}
|
||||
|
||||
set blob "0123456789012345678901234567890123456789"
|
||||
blob_write_test 1.1 -1 0 $blob 10 { 0123456789.............................. }
|
||||
blob_write_test 1.2 -2 8 $blob 10 { ........0123456789...................... }
|
||||
blob_write_test 1.3 -3 8 $blob 1 { ........0............................... }
|
||||
blob_write_test 1.4 -4 18 $blob 22 { ..................0123456789012345678901 }
|
||||
blob_write_test 1.5 -5 18 $blob 0 { ........................................ }
|
||||
blob_write_test 1.6 -6 0 $blob 40 { 0123456789012345678901234567890123456789 }
|
||||
|
||||
|
||||
proc blob_write_error_test {tn B iOffset blob nData errcode errmsg} {
|
||||
|
||||
# In cases where the underlying sqlite3_blob_write() function returns
|
||||
# SQLITE_OK, the Tcl wrapper returns an empty string. If the underlying
|
||||
# function returns an error, the Tcl wrapper throws an exception with
|
||||
# the error code as the Tcl exception message.
|
||||
#
|
||||
if {$errcode=="SQLITE_OK"} {
|
||||
set ret ""
|
||||
set isError 0
|
||||
} else {
|
||||
set ret $errcode
|
||||
set isError 1
|
||||
}
|
||||
|
||||
set cmd [list sqlite3_blob_write $B $iOffset $blob $nData]
|
||||
uplevel [list do_test $tn.1 [subst -nocommands {
|
||||
list [catch {$cmd} msg] [set msg]
|
||||
}] [list $isError $ret]]
|
||||
|
||||
# EVIDENCE-OF: R-34782-18311 Unless SQLITE_MISUSE is returned, this
|
||||
# function sets the database connection error code and message
|
||||
# accessible via sqlite3_errcode() and sqlite3_errmsg() and related
|
||||
# functions.
|
||||
#
|
||||
if {$errcode == "SQLITE_MISUSE"} { error "test proc misuse!" }
|
||||
uplevel [list do_test $tn.2 [list sqlite3_errcode db] $errcode]
|
||||
uplevel [list do_test $tn.3 [list sqlite3_errmsg db] $errmsg]
|
||||
}
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE t2(a TEXT, b INTEGER PRIMARY KEY);
|
||||
INSERT INTO t2 VALUES($dots, 43);
|
||||
INSERT INTO t2 VALUES($dots, 44);
|
||||
INSERT INTO t2 VALUES($dots, 45);
|
||||
}
|
||||
|
||||
# EVIDENCE-OF: R-63341-57517 If the BLOB handle passed as the first
|
||||
# argument was not opened for writing (the flags parameter to
|
||||
# sqlite3_blob_open() was zero), this function returns SQLITE_READONLY.
|
||||
#
|
||||
sqlite3_blob_open db main t2 a 43 0 B
|
||||
blob_write_error_test 2.1 $B 0 $blob 10 \
|
||||
SQLITE_READONLY {attempt to write a readonly database}
|
||||
sqlite3_blob_close $B
|
||||
|
||||
# EVIDENCE-OF: R-29804-27366 If offset iOffset is less than N bytes from
|
||||
# the end of the BLOB, SQLITE_ERROR is returned and no data is written.
|
||||
#
|
||||
sqlite3_blob_open db main t2 a 44 3 B
|
||||
blob_write_error_test 2.2.1 $B 31 $blob 10 \
|
||||
SQLITE_ERROR {SQL logic error or missing database}
|
||||
|
||||
# Make a successful write to the blob handle. This shows that the
|
||||
# sqlite3_errcode() and sqlite3_errmsg() values are set even if the
|
||||
# blob_write() call succeeds (see requirement in the [blob_write_error_test]
|
||||
# proc).
|
||||
blob_write_error_test 2.2.1 $B 30 $blob 10 SQLITE_OK {not an error}
|
||||
|
||||
# EVIDENCE-OF: R-58570-38916 If N or iOffset are less than zero
|
||||
# SQLITE_ERROR is returned and no data is written.
|
||||
#
|
||||
blob_write_error_test 2.2.2 $B 31 $blob -1 \
|
||||
SQLITE_ERROR {SQL logic error or missing database}
|
||||
blob_write_error_test 2.2.3 $B 20 $blob 10 SQLITE_OK {not an error}
|
||||
blob_write_error_test 2.2.4 $B -1 $blob 10 \
|
||||
SQLITE_ERROR {SQL logic error or missing database}
|
||||
sqlite3_blob_close $B
|
||||
|
||||
# EVIDENCE-OF: R-20958-54138 An attempt to write to an expired BLOB
|
||||
# handle fails with an error code of SQLITE_ABORT.
|
||||
#
|
||||
do_test 2.3 {
|
||||
sqlite3_blob_open db main t2 a 43 0 B
|
||||
execsql { DELETE FROM t2 WHERE b=43 }
|
||||
} {}
|
||||
blob_write_error_test 2.3.1 $B 5 $blob 5 \
|
||||
SQLITE_ABORT {callback requested query abort}
|
||||
do_test 2.3.2 {
|
||||
execsql { SELECT 1, 2, 3 }
|
||||
sqlite3_errcode db
|
||||
} {SQLITE_OK}
|
||||
blob_write_error_test 2.3.3 $B 5 $blob 5 \
|
||||
SQLITE_ABORT {callback requested query abort}
|
||||
sqlite3_blob_close $B
|
||||
|
||||
# EVIDENCE-OF: R-08382-59936 Writes to the BLOB that occurred before the
|
||||
# BLOB handle expired are not rolled back by the expiration of the
|
||||
# handle, though of course those changes might have been overwritten by
|
||||
# the statement that expired the BLOB handle or by other independent
|
||||
# statements.
|
||||
#
|
||||
# 3.1.*: not rolled back,
|
||||
# 3.2.*: overwritten.
|
||||
#
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE t3(i INTEGER PRIMARY KEY, j TEXT, k TEXT);
|
||||
INSERT INTO t3 VALUES(1, $dots, $dots);
|
||||
INSERT INTO t3 VALUES(2, $dots, $dots);
|
||||
SELECT * FROM t3 WHERE i=1;
|
||||
} {
|
||||
1
|
||||
........................................
|
||||
........................................
|
||||
}
|
||||
sqlite3_blob_open db main t3 j 1 1 B
|
||||
blob_write_error_test 3.1.1 $B 5 $blob 10 SQLITE_OK {not an error}
|
||||
do_execsql_test 3.1.2 {
|
||||
UPDATE t3 SET k = 'xyz' WHERE i=1;
|
||||
SELECT * FROM t3 WHERE i=1;
|
||||
} {
|
||||
1 .....0123456789......................... xyz
|
||||
}
|
||||
blob_write_error_test 3.1.3 $B 15 $blob 10 \
|
||||
SQLITE_ABORT {callback requested query abort}
|
||||
sqlite3_blob_close $B
|
||||
do_execsql_test 3.1.4 {
|
||||
SELECT * FROM t3 WHERE i=1;
|
||||
} {
|
||||
1 .....0123456789......................... xyz
|
||||
}
|
||||
|
||||
sqlite3_blob_open db main t3 j 2 1 B
|
||||
blob_write_error_test 3.2.1 $B 5 $blob 10 SQLITE_OK {not an error}
|
||||
do_execsql_test 3.2.2 {
|
||||
UPDATE t3 SET j = 'xyz' WHERE i=2;
|
||||
SELECT * FROM t3 WHERE i=2;
|
||||
} {
|
||||
2 xyz ........................................
|
||||
}
|
||||
blob_write_error_test 3.2.3 $B 15 $blob 10 \
|
||||
SQLITE_ABORT {callback requested query abort}
|
||||
sqlite3_blob_close $B
|
||||
do_execsql_test 3.2.4 {
|
||||
SELECT * FROM t3 WHERE i=2;
|
||||
} {
|
||||
2 xyz ........................................
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -50,5 +50,22 @@ do_tblsread_test 1.3 { UPDATE par SET a=? WHERE b=? } {c1 c2 par}
|
||||
do_tblsread_test 1.4 { UPDATE par SET c=? WHERE b=? } {c3 par}
|
||||
do_tblsread_test 1.5 { UPDATE par SET a=?,b=?,c=? WHERE b=? } {c1 c2 c3 par s1}
|
||||
|
||||
ifcapable incrblob {
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE pX(x PRIMARY KEY);
|
||||
CREATE TABLE cX(a INTEGER PRIMARY KEY, b REFERENCES pX);
|
||||
}
|
||||
|
||||
do_catchsql_test 2.1 {
|
||||
INSERT INTO cX VALUES(11, zeroblob(40));
|
||||
} {1 {FOREIGN KEY constraint failed}}
|
||||
|
||||
do_test 2.2 {
|
||||
set stmt [sqlite3_prepare_v2 db "INSERT INTO cX VALUES(11, ?)" -1]
|
||||
sqlite3_bind_zeroblob $stmt 1 45
|
||||
sqlite3_step $stmt
|
||||
sqlite3_finalize $stmt
|
||||
} {SQLITE_CONSTRAINT}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix in5
|
||||
|
||||
do_test in5-1.1 {
|
||||
execsql {
|
||||
@@ -135,4 +136,51 @@ do_test in5-5.3 {
|
||||
}]
|
||||
} {0}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# At one point SQLite was removing the DISTINCT keyword from expressions
|
||||
# similar to:
|
||||
#
|
||||
# <expr1> IN (SELECT DISTINCT <expr2> FROM...)
|
||||
#
|
||||
# However, there are a few obscure cases where this is incorrect. For
|
||||
# example, if the SELECT features a LIMIT clause, or if the collation
|
||||
# sequence or affinity used by the DISTINCT does not match the one used
|
||||
# by the IN(...) expression.
|
||||
#
|
||||
do_execsql_test 6.1.1 {
|
||||
CREATE TABLE t1(a COLLATE nocase);
|
||||
INSERT INTO t1 VALUES('one');
|
||||
INSERT INTO t1 VALUES('ONE');
|
||||
}
|
||||
do_execsql_test 6.1.2 {
|
||||
SELECT count(*) FROM t1 WHERE a COLLATE BINARY IN (SELECT DISTINCT a FROM t1)
|
||||
} {1}
|
||||
|
||||
do_execsql_test 6.2.1 {
|
||||
CREATE TABLE t3(a, b);
|
||||
INSERT INTO t3 VALUES(1, 1);
|
||||
INSERT INTO t3 VALUES(1, 2);
|
||||
INSERT INTO t3 VALUES(1, 3);
|
||||
INSERT INTO t3 VALUES(2, 4);
|
||||
INSERT INTO t3 VALUES(2, 5);
|
||||
INSERT INTO t3 VALUES(2, 6);
|
||||
INSERT INTO t3 VALUES(3, 7);
|
||||
INSERT INTO t3 VALUES(3, 8);
|
||||
INSERT INTO t3 VALUES(3, 9);
|
||||
}
|
||||
do_execsql_test 6.2.2 {
|
||||
SELECT count(*) FROM t3 WHERE b IN (SELECT DISTINCT a FROM t3 LIMIT 5);
|
||||
} {3}
|
||||
do_execsql_test 6.2.3 {
|
||||
SELECT count(*) FROM t3 WHERE b IN (SELECT a FROM t3 LIMIT 5);
|
||||
} {2}
|
||||
|
||||
do_execsql_test 6.3.1 {
|
||||
CREATE TABLE x1(a);
|
||||
CREATE TABLE x2(b);
|
||||
INSERT INTO x1 VALUES(1), (1), (2);
|
||||
INSERT INTO x2 VALUES(1), (2);
|
||||
SELECT count(*) FROM x2 WHERE b IN (SELECT DISTINCT a FROM x1 LIMIT 2);
|
||||
} {2}
|
||||
|
||||
finish_test
|
||||
|
||||
+7
-1
@@ -112,6 +112,12 @@ foreach bPersist [list 0 1] {
|
||||
}
|
||||
}
|
||||
|
||||
# When this test was written, an IO error within the UPDATE statement caused
|
||||
# a rollback, which tripped all read-cursors, causing the outer SELECT to
|
||||
# fail with "abort due to ROLLBACK". Now, the loop continues until the UPDATE
|
||||
# is run successfully. At this point the next IO error occurs within the
|
||||
# SELECT - throwing the "disk I/O error" that the test case now expects.
|
||||
#
|
||||
do_test ioerr2-5 {
|
||||
execsql {
|
||||
CREATE TABLE t2 AS SELECT * FROM t1;
|
||||
@@ -130,7 +136,7 @@ do_test ioerr2-5 {
|
||||
}
|
||||
} msg]
|
||||
list $rc $msg
|
||||
} {1 {abort due to ROLLBACK}}
|
||||
} {1 {disk I/O error}} ;# used to be "{1 {abort due to ROLLBACK}}"
|
||||
|
||||
if {$::tcl_platform(platform) == "unix"} {
|
||||
# Cause the call to xAccess used by [pragma temp_store_directory] to
|
||||
|
||||
@@ -106,5 +106,59 @@ do_test join5-2.12 {
|
||||
execsql {SELECT * FROM xy LEFT JOIN ab ON NULL WHERE NULL}
|
||||
} {}
|
||||
|
||||
# Ticket https://www.sqlite.org/src/tktview/6f2222d550f5b0ee7ed37601
|
||||
# Incorrect output on a LEFT JOIN.
|
||||
#
|
||||
do_execsql_test join5-3.1 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t2;
|
||||
DROP TABLE IF EXISTS t3;
|
||||
CREATE TABLE x1(a);
|
||||
INSERT INTO x1 VALUES(1);
|
||||
CREATE TABLE x2(b NOT NULL);
|
||||
CREATE TABLE x3(c, d);
|
||||
INSERT INTO x3 VALUES('a', NULL);
|
||||
INSERT INTO x3 VALUES('b', NULL);
|
||||
INSERT INTO x3 VALUES('c', NULL);
|
||||
SELECT * FROM x1 LEFT JOIN x2 LEFT JOIN x3 ON x3.d = x2.b;
|
||||
} {1 {} {} {}}
|
||||
do_execsql_test join5-3.2 {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
DROP TABLE IF EXISTS t2;
|
||||
DROP TABLE IF EXISTS t3;
|
||||
DROP TABLE IF EXISTS t4;
|
||||
DROP TABLE IF EXISTS t5;
|
||||
CREATE TABLE t1(x text NOT NULL, y text);
|
||||
CREATE TABLE t2(u text NOT NULL, x text NOT NULL);
|
||||
CREATE TABLE t3(w text NOT NULL, v text);
|
||||
CREATE TABLE t4(w text NOT NULL, z text NOT NULL);
|
||||
CREATE TABLE t5(z text NOT NULL, m text);
|
||||
INSERT INTO t1 VALUES('f6d7661f-4efe-4c90-87b5-858e61cd178b',NULL);
|
||||
INSERT INTO t1 VALUES('f6ea82c3-2cad-45ce-ae8f-3ddca4fb2f48',NULL);
|
||||
INSERT INTO t1 VALUES('f6f47499-ecb4-474b-9a02-35be73c235e5',NULL);
|
||||
INSERT INTO t1 VALUES('56f47499-ecb4-474b-9a02-35be73c235e5',NULL);
|
||||
INSERT INTO t3 VALUES('007f2033-cb20-494c-b135-a1e4eb66130c',
|
||||
'f6d7661f-4efe-4c90-87b5-858e61cd178b');
|
||||
SELECT *
|
||||
FROM t3
|
||||
INNER JOIN t1 ON t1.x= t3.v AND t1.y IS NULL
|
||||
LEFT JOIN t4 ON t4.w = t3.w
|
||||
LEFT JOIN t5 ON t5.z = t4.z
|
||||
LEFT JOIN t2 ON t2.u = t5.m
|
||||
LEFT JOIN t1 xyz ON xyz.y = t2.x;
|
||||
} {007f2033-cb20-494c-b135-a1e4eb66130c f6d7661f-4efe-4c90-87b5-858e61cd178b f6d7661f-4efe-4c90-87b5-858e61cd178b {} {} {} {} {} {} {} {} {}}
|
||||
do_execsql_test join5-3.3 {
|
||||
DROP TABLE IF EXISTS x1;
|
||||
DROP TABLE IF EXISTS x2;
|
||||
DROP TABLE IF EXISTS x3;
|
||||
CREATE TABLE x1(a);
|
||||
INSERT INTO x1 VALUES(1);
|
||||
CREATE TABLE x2(b NOT NULL);
|
||||
CREATE TABLE x3(c, d);
|
||||
INSERT INTO x3 VALUES('a', NULL);
|
||||
INSERT INTO x3 VALUES('b', NULL);
|
||||
INSERT INTO x3 VALUES('c', NULL);
|
||||
SELECT * FROM x1 LEFT JOIN x2 JOIN x3 WHERE x3.d = x2.b;
|
||||
} {}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
# 2014-11-10
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library.
|
||||
# The focus of this script is testing the "eval.c" loadable extension.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
load_static_extension db eval
|
||||
do_execsql_test misc8-1.0 {
|
||||
CREATE TABLE t1(a,b,c);
|
||||
INSERT INTO t1 VALUES(1,2,3),(4,5,6);
|
||||
SELECT quote(eval('SELECT * FROM t1 ORDER BY a','-abc-'));
|
||||
} {'1-abc-2-abc-3-abc-4-abc-5-abc-6'}
|
||||
do_execsql_test misc8-1.1 {
|
||||
SELECT quote(eval('SELECT * FROM t1 ORDER BY a'));
|
||||
} {{'1 2 3 4 5 6'}}
|
||||
do_catchsql_test misc8-1.2 {
|
||||
SELECT quote(eval('SELECT d FROM t1 ORDER BY a'));
|
||||
} {1 {no such column: d}}
|
||||
do_execsql_test misc8-1.3 {
|
||||
INSERT INTO t1 VALUES(7,null,9);
|
||||
SELECT eval('SELECT * FROM t1 ORDER BY a',',');
|
||||
} {1,2,3,4,5,6,7,,9}
|
||||
do_catchsql_test misc8-1.4 {
|
||||
BEGIN;
|
||||
INSERT INTO t1 VALUES(10,11,12);
|
||||
SELECT a, coalesce(b, eval('ROLLBACK; SELECT ''bam'';')), c
|
||||
FROM t1 ORDER BY a;
|
||||
} {0 {1 2 3 4 5 6 7 bam 9}}
|
||||
do_catchsql_test misc8-1.5 {
|
||||
INSERT INTO t1 VALUES(10,11,12);
|
||||
SELECT a, coalesce(b, eval('SELECT ''bam''')), c
|
||||
FROM t1
|
||||
ORDER BY rowid;
|
||||
} {0 {1 2 3 4 5 6 7 bam 9 10 11 12}}
|
||||
do_catchsql_test misc8-1.6 {
|
||||
SELECT a, coalesce(b, eval('DELETE FROM t1; SELECT ''bam''')), c
|
||||
FROM t1
|
||||
ORDER BY rowid;
|
||||
} {0 {1 2 3 4 5 6 7 bam {}}}
|
||||
do_catchsql_test misc8-1.7 {
|
||||
INSERT INTO t1 VALUES(1,2,3),(4,5,6),(7,null,9);
|
||||
BEGIN;
|
||||
CREATE TABLE t2(x);
|
||||
SELECT a, coalesce(b, eval('ROLLBACK; SELECT ''bam''')), c
|
||||
FROM t1
|
||||
ORDER BY rowid;
|
||||
} {1 {abort due to ROLLBACK}}
|
||||
|
||||
|
||||
reset_db
|
||||
|
||||
proc dbeval {sql} { db eval $sql }
|
||||
db func eval dbeval
|
||||
|
||||
do_execsql_test misc8-2.1 {
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b INTEGER) WITHOUT ROWID;
|
||||
CREATE TABLE t2(c INTEGER PRIMARY KEY, d INTEGER, x BLOB);
|
||||
INSERT INTO t1 VALUES(0,0);
|
||||
INSERT INTO t1 VALUES(10,10);
|
||||
INSERT INTO t2 VALUES(1,1,zeroblob(200));
|
||||
INSERT INTO t2 VALUES(2,2,zeroblob(200));
|
||||
INSERT INTO t2 VALUES(3,3,zeroblob(200));
|
||||
INSERT INTO t2 VALUES(4,4,zeroblob(200));
|
||||
INSERT INTO t2 VALUES(5,5,zeroblob(200));
|
||||
INSERT INTO t2 VALUES(6,6,zeroblob(200));
|
||||
INSERT INTO t2 VALUES(7,7,zeroblob(200));
|
||||
INSERT INTO t2 VALUES(8,8,zeroblob(200));
|
||||
INSERT INTO t2 VALUES(9,9,zeroblob(200));
|
||||
INSERT INTO t2 VALUES(10,10,zeroblob(200));
|
||||
SELECT a, c, eval(
|
||||
printf('DELETE FROM t2 WHERE c=%d AND %d>5', a+c, a+c)
|
||||
) FROM t1, t2;
|
||||
} {
|
||||
0 1 {} 10 1 {}
|
||||
0 2 {} 10 2 {}
|
||||
0 3 {} 10 3 {}
|
||||
0 4 {} 10 4 {}
|
||||
0 5 {} 10 5 {}
|
||||
0 6 {} 10 {} {}
|
||||
0 7 {} 10 {} {}
|
||||
0 8 {} 10 {} {}
|
||||
0 9 {} 10 {} {}
|
||||
0 10 {} 10 {} {}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -113,6 +113,7 @@ set allquicktests [test_set $alltests -exclude {
|
||||
vtab_err.test walslow.test walcrash.test walcrash3.test
|
||||
walthread.test rtree3.test indexfault.test securedel2.test
|
||||
sort3.test sort4.test fts4growth.test fts4growth2.test
|
||||
bigsort.test
|
||||
}]
|
||||
if {[info exists ::env(QUICKTEST_INCLUDE)]} {
|
||||
set allquicktests [concat $allquicktests $::env(QUICKTEST_INCLUDE)]
|
||||
|
||||
+2
-2
@@ -1190,13 +1190,13 @@ ifcapable schema_pragmas {
|
||||
execsql2 {
|
||||
pragma collation_list;
|
||||
}
|
||||
} {seq 0 name NOCASE seq 1 name RTRIM seq 2 name BINARY}
|
||||
} {seq 0 name RTRIM seq 1 name NOCASE seq 2 name BINARY}
|
||||
do_test pragma-11.2 {
|
||||
db collate New_Collation blah...
|
||||
execsql {
|
||||
pragma collation_list;
|
||||
}
|
||||
} {0 New_Collation 1 NOCASE 2 RTRIM 3 BINARY}
|
||||
} {0 New_Collation 1 RTRIM 2 NOCASE 3 BINARY}
|
||||
}
|
||||
|
||||
ifcapable schema_pragmas&&tempdb {
|
||||
|
||||
+2
-2
@@ -60,11 +60,11 @@ ifcapable conflict {
|
||||
#
|
||||
do_test rollback-1.5 {
|
||||
sqlite3_step $STMT
|
||||
} {SQLITE_ERROR}
|
||||
} {SQLITE_ROW}
|
||||
|
||||
# Restart the SELECT statement
|
||||
#
|
||||
do_test rollback-1.6 { sqlite3_reset $STMT } {SQLITE_ABORT}
|
||||
do_test rollback-1.6 { sqlite3_reset $STMT } {SQLITE_OK}
|
||||
} else {
|
||||
do_test rollback-1.6 { sqlite3_reset $STMT } {SQLITE_OK}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
# 2014 November 12
|
||||
#
|
||||
# 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 containst tests to verify that ROLLBACK or ROLLBACK TO
|
||||
# operations interact correctly with ongoing SELECT statements.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix rollback2
|
||||
|
||||
proc int2hex {i} { format %.2X $i }
|
||||
db func int2hex int2hex
|
||||
do_execsql_test 1.0 {
|
||||
SELECT int2hex(0), int2hex(100), int2hex(255)
|
||||
} {00 64 FF}
|
||||
do_execsql_test 1.1 {
|
||||
CREATE TABLE t1(i, h);
|
||||
CREATE INDEX i1 ON t1(h);
|
||||
WITH data(a, b) AS (
|
||||
SELECT 1, int2hex(1)
|
||||
UNION ALL
|
||||
SELECT a+1, int2hex(a+1) FROM data WHERE a<40
|
||||
)
|
||||
INSERT INTO t1 SELECT * FROM data;
|
||||
} {}
|
||||
|
||||
|
||||
# do_rollback_test ID SWITCHES
|
||||
#
|
||||
# where SWITCHES are:
|
||||
#
|
||||
# -setup SQL script to open transaction and begin writing.
|
||||
# -select SELECT to execute after -setup script
|
||||
# -result Expected result of -select statement
|
||||
# -rollback Use this SQL command ("ROLLBACK" or "ROLLBACK TO ...") to
|
||||
# rollback the transaction in the middle of the -select statment
|
||||
# execution.
|
||||
#
|
||||
proc do_rollback_test {tn args} {
|
||||
set A(-setup) ""
|
||||
set A(-select) ""
|
||||
set A(-result) ""
|
||||
set A(-rollback) ROLLBACK
|
||||
|
||||
array set O $args
|
||||
foreach k [array names O] {
|
||||
if {[info exists A($k)]==0} { error "unknown option: $k" }
|
||||
set A($k) $O($k)
|
||||
}
|
||||
|
||||
for {set iRollback 0} 1 {incr iRollback} {
|
||||
catch { db eval ROLLBACK }
|
||||
set res [list]
|
||||
db eval $A(-setup)
|
||||
|
||||
set i 0
|
||||
db eval $A(-select) x {
|
||||
if {$i==$iRollback} { db eval $A(-rollback) }
|
||||
foreach k $x(*) { lappend res $x($k) }
|
||||
incr i
|
||||
}
|
||||
|
||||
do_test $tn.$iRollback [list set {} $res] [list {*}$A(-result)]
|
||||
if {$i < $iRollback} break
|
||||
}
|
||||
}
|
||||
|
||||
do_rollback_test 2.1 -setup {
|
||||
BEGIN;
|
||||
DELETE FROM t1 WHERE (i%2)==1;
|
||||
} -select {
|
||||
SELECT i FROM t1 WHERE (i%2)==0
|
||||
} -result {
|
||||
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40
|
||||
}
|
||||
|
||||
do_rollback_test 2.2 -setup {
|
||||
BEGIN;
|
||||
DELETE FROM t1 WHERE (i%4)==1;
|
||||
SAVEPOINT one;
|
||||
DELETE FROM t1 WHERE (i%2)==1;
|
||||
} -rollback {
|
||||
ROLLBACK TO one;
|
||||
} -select {
|
||||
SELECT i FROM t1 WHERE (i%2)==0
|
||||
} -result {
|
||||
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Try with some index scans
|
||||
#
|
||||
do_eqp_test 3.1 {
|
||||
SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC;
|
||||
} {0 0 0 {SCAN TABLE t1 USING INDEX i1}}
|
||||
do_rollback_test 3.2 -setup {
|
||||
BEGIN;
|
||||
DELETE FROM t1 WHERE (i%2)==1;
|
||||
} -select {
|
||||
SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC;
|
||||
} -result {
|
||||
40 38 36 34 32 30 28 26 24 22 20 18 16 14 12 10 8 6 4 2
|
||||
}
|
||||
do_rollback_test 3.3 -setup {
|
||||
BEGIN;
|
||||
DELETE FROM t1 WHERE (i%4)==1;
|
||||
SAVEPOINT one;
|
||||
DELETE FROM t1 WHERE (i%2)==1;
|
||||
} -rollback {
|
||||
ROLLBACK TO one;
|
||||
} -select {
|
||||
SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC;
|
||||
} -result {
|
||||
40 38 36 34 32 30 28 26 24 22 20 18 16 14 12 10 8 6 4 2
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Now with some index scans that feature overflow keys.
|
||||
#
|
||||
set leader [string repeat "abcdefghij" 70]
|
||||
do_execsql_test 4.1 { UPDATE t1 SET h = $leader || h; }
|
||||
|
||||
do_eqp_test 4.2 {
|
||||
SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC;
|
||||
} {0 0 0 {SCAN TABLE t1 USING INDEX i1}}
|
||||
do_rollback_test 4.3 -setup {
|
||||
BEGIN;
|
||||
DELETE FROM t1 WHERE (i%2)==1;
|
||||
} -select {
|
||||
SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC;
|
||||
} -result {
|
||||
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40
|
||||
}
|
||||
do_rollback_test 4.4 -setup {
|
||||
BEGIN;
|
||||
DELETE FROM t1 WHERE (i%4)==1;
|
||||
SAVEPOINT one;
|
||||
DELETE FROM t1 WHERE (i%2)==1;
|
||||
} -rollback {
|
||||
ROLLBACK TO one;
|
||||
} -select {
|
||||
SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC;
|
||||
} -result {
|
||||
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
# 2014-11-12
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Test that errors encountered during a ROLLBACK operation correctly
|
||||
# affect ongoing SQL statements.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
set testprefix rollbackfault
|
||||
|
||||
|
||||
proc int2hex {i} { format %.2X $i }
|
||||
db func int2hex int2hex
|
||||
do_execsql_test 1.0 {
|
||||
SELECT int2hex(0), int2hex(100), int2hex(255)
|
||||
} {00 64 FF}
|
||||
do_execsql_test 1.1 {
|
||||
CREATE TABLE t1(i, h);
|
||||
CREATE INDEX i1 ON t1(h);
|
||||
WITH data(a, b) AS (
|
||||
SELECT 1, int2hex(1)
|
||||
UNION ALL
|
||||
SELECT a+1, int2hex(a+1) FROM data WHERE a<40
|
||||
)
|
||||
INSERT INTO t1 SELECT * FROM data;
|
||||
} {}
|
||||
|
||||
foreach f {oom ioerr} {
|
||||
do_faultsim_test 1.2 -faults $f* -prep {
|
||||
set sql1 { SELECT i FROM t1 WHERE (i%2)==0 }
|
||||
set sql2 { SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h }
|
||||
set ::s1 [sqlite3_prepare db $sql1 -1 dummy]
|
||||
set ::s2 [sqlite3_prepare db $sql2 -1 dummy]
|
||||
|
||||
for {set i 0} {$i < 10} {incr i} { sqlite3_step $::s1 }
|
||||
for {set i 0} {$i < 3} {incr i} { sqlite3_step $::s2 }
|
||||
|
||||
execsql {
|
||||
BEGIN; DELETE FROM t1 WHERE (i%2)
|
||||
}
|
||||
} -body {
|
||||
execsql { ROLLBACK }
|
||||
} -test {
|
||||
|
||||
set res1 [list]
|
||||
set res2 [list]
|
||||
while {"SQLITE_ROW" == [sqlite3_step $::s1]} {
|
||||
lappend res1 [sqlite3_column_text $::s1 0]
|
||||
}
|
||||
while {"SQLITE_ROW" == [sqlite3_step $::s2]} {
|
||||
lappend res2 [sqlite3_column_text $::s2 0]
|
||||
}
|
||||
set rc1 [sqlite3_finalize $::s1]
|
||||
set rc2 [sqlite3_finalize $::s2]
|
||||
|
||||
catchsql { ROLLBACK }
|
||||
|
||||
if {$rc1=="SQLITE_OK" && $rc2=="SQLITE_OK"
|
||||
&& $res1=="22 24 26 28 30 32 34 36 38 40"
|
||||
&& $res2=="8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40"
|
||||
} {
|
||||
# This is Ok.
|
||||
} elseif {$rc1!="SQLITE_OK" && $rc2!="SQLITE_OK" && $res1=="" &&$res2==""} {
|
||||
# Also Ok.
|
||||
} else {
|
||||
error "statements don't look right"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
+1
-1
@@ -315,7 +315,7 @@ ifcapable incrblob {
|
||||
do_test savepoint-5.3.2.3 {
|
||||
set rc [catch {seek $fd 0; read $fd} res]
|
||||
set rc
|
||||
} {1}
|
||||
} {0}
|
||||
do_test savepoint-5.3.3 {
|
||||
catchsql {RELEASE def}
|
||||
} {0 {}}
|
||||
|
||||
@@ -30,6 +30,7 @@ do_test savepoint7-1.1 {
|
||||
db eval {SELECT * FROM t1} {
|
||||
db eval {
|
||||
SAVEPOINT x2;
|
||||
CREATE TABLE IF NOT EXISTS t3(xyz);
|
||||
INSERT INTO t2 VALUES($a,$b,$c);
|
||||
RELEASE x2;
|
||||
}
|
||||
@@ -46,7 +47,7 @@ do_test savepoint7-1.2 {
|
||||
RELEASE x2;
|
||||
}
|
||||
}
|
||||
db eval {SELECT * FROM t2}
|
||||
db eval {SELECT * FROM t2;}
|
||||
} {1 2 3 4 5 6 7 8 9}
|
||||
|
||||
do_test savepoint7-1.3 {
|
||||
@@ -65,7 +66,7 @@ do_test savepoint7-1.3 {
|
||||
# queries in outer contexts.
|
||||
#
|
||||
do_test savepoint7-2.1 {
|
||||
db eval {DELETE FROM t2; SAVEPOINT x1;}
|
||||
db eval {DELETE FROM t2; SAVEPOINT x1; CREATE TABLE t4(abc);}
|
||||
set rc [catch {
|
||||
db eval {SELECT * FROM t1} {
|
||||
db eval {
|
||||
@@ -77,7 +78,7 @@ do_test savepoint7-2.1 {
|
||||
} msg]
|
||||
db eval {RELEASE x1}
|
||||
list $rc $msg [db eval {SELECT * FROM t2}]
|
||||
} {1 {callback requested query abort} {}}
|
||||
} {1 {abort due to ROLLBACK} {}}
|
||||
|
||||
do_test savepoint7-2.2 {
|
||||
db eval {DELETE FROM t2;}
|
||||
@@ -85,12 +86,13 @@ do_test savepoint7-2.2 {
|
||||
db eval {SELECT * FROM t1} {
|
||||
db eval {
|
||||
SAVEPOINT x2;
|
||||
CREATE TABLE t5(pqr);
|
||||
INSERT INTO t2 VALUES($a,$b,$c);
|
||||
ROLLBACK TO x2;
|
||||
}
|
||||
}
|
||||
} msg]
|
||||
list $rc $msg [db eval {SELECT * FROM t2}]
|
||||
} {1 {callback requested query abort} {}}
|
||||
} {1 {abort due to ROLLBACK} {}}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -268,7 +268,7 @@ do_scanstatus_test 4.2.2 {
|
||||
nLoop 1 nVisit 1 nEst 1.0 zName sqlite_autoindex_p1_1
|
||||
zExplain {SEARCH TABLE p1 USING INDEX sqlite_autoindex_p1_1 (x=?)}
|
||||
|
||||
nLoop 1 nVisit 3 nEst 524288.0 zName c1 zExplain {SCAN TABLE c1}
|
||||
nLoop 1 nVisit 3 nEst 262144.0 zName c1 zExplain {SCAN TABLE c1}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
# 2014-12-05
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# Open two database connections on the same database in shared cache
|
||||
# mode. Hold one open while repeatedly closing, reopening, and using
|
||||
# the second.
|
||||
#
|
||||
# This test is designed to demostrate that the fix for ticket
|
||||
# [e4a18565a36884b00edf66541f38c693827968ab] works.
|
||||
#
|
||||
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
if {[run_thread_tests]==0} { finish_test ; return }
|
||||
db close
|
||||
set ::testprefix sharedB
|
||||
|
||||
set ::enable_shared_cache [sqlite3_enable_shared_cache 1]
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
do_test 1.1 {
|
||||
sqlite3 db1 test.db
|
||||
sqlite3 db2 test.db
|
||||
|
||||
db1 eval {
|
||||
CREATE TABLE t1(x,y TEXT COLLATE nocase);
|
||||
WITH RECURSIVE
|
||||
c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<100)
|
||||
INSERT INTO t1(x,y) SELECT i, printf('x%03dy',i) FROM c;
|
||||
CREATE INDEX t1yx ON t1(y,x);
|
||||
}
|
||||
db2 eval {
|
||||
SELECT x FROM t1 WHERE y='X014Y';
|
||||
}
|
||||
} {14}
|
||||
|
||||
for {set j 1} {$j<=100} {incr j} {
|
||||
do_test 1.2.$j {
|
||||
db2 close
|
||||
sqlite3 db2 test.db
|
||||
db2 eval {
|
||||
SELECT x FROM t1 WHERE y='X014Y';
|
||||
}
|
||||
} {14}
|
||||
}
|
||||
|
||||
db1 close
|
||||
db2 close
|
||||
sqlite3_enable_shared_cache $::enable_shared_cache
|
||||
finish_test
|
||||
@@ -446,9 +446,15 @@ do_malloc_test shared_err-8 -tclprep {
|
||||
} {1}
|
||||
db2 close
|
||||
}
|
||||
|
||||
# When this test case was written, OOM errors in write statements would
|
||||
# cause transaction rollback, which would trip cursors in other statements,
|
||||
# aborting them. This no longer happens.
|
||||
#
|
||||
do_test shared_malloc-8.X {
|
||||
# Test that one or more queries were aborted due to the malloc() failure.
|
||||
expr $::aborted>=1
|
||||
# expr $::aborted>=1
|
||||
expr $::aborted==0
|
||||
} {1}
|
||||
|
||||
# This test is designed to catch a specific bug that was present during
|
||||
|
||||
+16
-15
@@ -45,20 +45,21 @@ do_test shell1-1.1.1 {
|
||||
list $rc \
|
||||
[regexp {Error: unknown option: -bad} $res]
|
||||
} {1 1}
|
||||
do_test shell1-1.1.1b {
|
||||
set res [catchcmd "test.db -bad" ""]
|
||||
set rc [lindex $res 0]
|
||||
list $rc \
|
||||
[regexp {Error: unknown option: -bad} $res]
|
||||
} {1 1}
|
||||
# error on extra options
|
||||
do_test shell1-1.1.2 {
|
||||
set res [catchcmd "-bad test.db \"select 3\" \"select 4\"" ""]
|
||||
set rc [lindex $res 0]
|
||||
list $rc \
|
||||
[regexp {Error: too many options: "select 4"} $res]
|
||||
} {1 1}
|
||||
catchcmd "test.db \"select 3\" \"select 4\"" ""
|
||||
} {0 {3
|
||||
4}}
|
||||
# error on extra options
|
||||
do_test shell1-1.1.3 {
|
||||
set res [catchcmd "-bad FOO test.db BAD" ".quit"]
|
||||
set rc [lindex $res 0]
|
||||
list $rc \
|
||||
[regexp {Error: too many options: "BAD"} $res]
|
||||
} {1 1}
|
||||
catchcmd "test.db FOO test.db BAD" ".quit"
|
||||
} {1 {Error: near "FOO": syntax error}}
|
||||
|
||||
# -help
|
||||
do_test shell1-1.2.1 {
|
||||
@@ -75,11 +76,11 @@ do_test shell1-1.3.1 {
|
||||
catchcmd "-init FOO test.db" ""
|
||||
} {0 {}}
|
||||
do_test shell1-1.3.2 {
|
||||
set res [catchcmd "-init FOO test.db .quit BAD" ""]
|
||||
set rc [lindex $res 0]
|
||||
list $rc \
|
||||
[regexp {Error: too many options: "BAD"} $res]
|
||||
} {1 1}
|
||||
catchcmd "-init FOO test.db .quit BAD" ""
|
||||
} {0 {}}
|
||||
do_test shell1-1.3.3 {
|
||||
catchcmd "-init FOO test.db BAD .quit" ""
|
||||
} {1 {Error: near "BAD": syntax error}}
|
||||
|
||||
# -echo print commands before execution
|
||||
do_test shell1-1.4.1 {
|
||||
|
||||
+3
-3
@@ -52,9 +52,9 @@ do_test shell2-1.1.1 {
|
||||
# Ticket [f5cb008a65].
|
||||
do_test shell2-1.2.1 {
|
||||
set rc [catch { eval exec $CLI \":memory:\" \"select 3\" \"select 4\" } msg]
|
||||
list $rc \
|
||||
[regexp {Error: too many options: "select 4"} $msg]
|
||||
} {1 1}
|
||||
list $rc $msg
|
||||
} {0 {3
|
||||
4}}
|
||||
|
||||
# Test a problem reported on the mailing list. The shell was at one point
|
||||
# returning the generic SQLITE_ERROR message ("SQL error or missing database")
|
||||
|
||||
@@ -273,4 +273,23 @@ do_execsql_test skipscan1-6.3 {
|
||||
EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=1;
|
||||
} {~/ANY/}
|
||||
|
||||
# If the sqlite_stat1 entry includes the "noskipscan" token, then never use
|
||||
# skipscan with that index.
|
||||
#
|
||||
do_execsql_test skipscan1-7.1 {
|
||||
UPDATE sqlite_stat1 SET stat='500000 125000 1 sz=100';
|
||||
ANALYZE sqlite_master;
|
||||
EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=1;
|
||||
} {/ANY/}
|
||||
do_execsql_test skipscan1-7.2 {
|
||||
UPDATE sqlite_stat1 SET stat='500000 125000 1 noskipscan sz=100';
|
||||
ANALYZE sqlite_master;
|
||||
EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=1;
|
||||
} {~/ANY/}
|
||||
do_execsql_test skipscan1-7.3 {
|
||||
UPDATE sqlite_stat1 SET stat='500000 125000 1 sz=100 noskipscan';
|
||||
ANALYZE sqlite_master;
|
||||
EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=1;
|
||||
} {~/ANY/}
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -62,7 +62,6 @@ foreach {tn script} {
|
||||
|
||||
do_execsql_test $tn.2.4 { PRAGMA integrity_check } {ok}
|
||||
|
||||
breakpoint
|
||||
do_execsql_test $tn.3 {
|
||||
PRAGMA cache_size = 5;
|
||||
WITH r(x,y) AS (
|
||||
|
||||
@@ -40,6 +40,7 @@ db function force_rollback force_rollback
|
||||
do_test tkt-f7772-1.2 {
|
||||
catchsql {
|
||||
BEGIN IMMEDIATE;
|
||||
CREATE TABLE xyzzy(abc);
|
||||
SELECT x, force_rollback(), EXISTS(SELECT 1 FROM t3 WHERE w=x) FROM t2;
|
||||
}
|
||||
} {1 {abort due to ROLLBACK}}
|
||||
@@ -67,7 +68,7 @@ do_test tkt-f7772-2.2 {
|
||||
catchsql {
|
||||
SELECT x, force_rollback(), EXISTS(SELECT 1 FROM t3 WHERE w=x) FROM t2
|
||||
}
|
||||
} {1 {callback requested query abort}}
|
||||
} {1 {abort due to ROLLBACK}}
|
||||
do_test tkt-f7772-2.3 {
|
||||
sqlite3_get_autocommit db
|
||||
} {1}
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ do_test trans3-1.4 {
|
||||
db eval {SELECT * FROM t1}
|
||||
} {1 2 3 4}
|
||||
do_test trans3-1.5 {
|
||||
db eval BEGIN
|
||||
db eval {BEGIN; CREATE TABLE xyzzy(abc);}
|
||||
db eval {INSERT INTO t1 VALUES(5);}
|
||||
set ::ecode {}
|
||||
set x [catch {
|
||||
|
||||
@@ -1395,4 +1395,46 @@ do_execsql_test 21.3 {
|
||||
SELECT * FROM t9v WHERE a=b;
|
||||
} {2 2 2}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# At one point executing a CREATE VIRTUAL TABLE statement that specified
|
||||
# a database name but no virtual table arguments was causing an internal
|
||||
# buffer overread. Valgrind would report errors while running the following
|
||||
# tests. Specifically:
|
||||
#
|
||||
# CREATE VIRTUAL TABLE t1 USING fts4; -- Ok - no db name.
|
||||
# CREATE VIRTUAL TABLE main.t1 USING fts4(x); -- Ok - has vtab arguments.
|
||||
# CREATE VIRTUAL TABLE main.t1 USING fts4; -- Had the problem.
|
||||
#
|
||||
ifcapable fts3 {
|
||||
forcedelete test.db2
|
||||
set nm [string repeat abcdefghij 100]
|
||||
do_execsql_test 22.1 {
|
||||
ATTACH 'test.db2' AS $nm
|
||||
}
|
||||
|
||||
execsql "SELECT * FROM sqlite_master"
|
||||
do_execsql_test 22.2 "CREATE VIRTUAL TABLE ${nm}.t1 USING fts4"
|
||||
|
||||
do_test 22.3.1 {
|
||||
set sql "CREATE VIRTUAL TABLE ${nm}.t2 USING fts4"
|
||||
set stmt [sqlite3_prepare_v2 db $sql -1 dummy]
|
||||
sqlite3_step $stmt
|
||||
} {SQLITE_DONE}
|
||||
|
||||
do_test 22.3.2 {
|
||||
sqlite3_finalize $stmt
|
||||
} {SQLITE_OK}
|
||||
|
||||
do_test 22.4.1 {
|
||||
set sql "CREATE VIRTUAL TABLE ${nm}.t3 USING fts4"
|
||||
set n [string length $sql]
|
||||
set stmt [sqlite3_prepare db "${sql}xyz" $n dummy]
|
||||
sqlite3_step $stmt
|
||||
} {SQLITE_DONE}
|
||||
|
||||
do_test 22.4.2 {
|
||||
sqlite3_finalize $stmt
|
||||
} {SQLITE_OK}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
+42
-1
@@ -55,7 +55,8 @@ foreach {testprefix do_wal_checkpoint} {
|
||||
if {[lsearch {-mode -db} $key]<0} { error "unknown switch: $key" }
|
||||
}
|
||||
|
||||
if {$a(-mode)!="restart" && $a(-mode)!="full"} { set a(-mode) passive }
|
||||
set vals {restart full truncate}
|
||||
if {[lsearch -exact $vals $a(-mode)]<0} { set a(-mode) passive }
|
||||
|
||||
set cmd [list sqlite3_wal_checkpoint_v2 $dbhandle $a(-mode)]
|
||||
if {[info exists a(-db)]} { lappend sql $a(-db) }
|
||||
@@ -278,6 +279,11 @@ foreach {testprefix do_wal_checkpoint} {
|
||||
9 RESTART 2 {1 4 3} 2
|
||||
10 RESTART 3 {1 4 4} 3
|
||||
|
||||
11 TRUNCATE - {0 0 0} 3
|
||||
12 TRUNCATE 1 {1 3 3} 1
|
||||
13 TRUNCATE 2 {1 4 3} 2
|
||||
14 TRUNCATE 3 {1 4 4} 3
|
||||
|
||||
} {
|
||||
do_multiclient_test tn {
|
||||
setup_and_attach_aux
|
||||
@@ -348,6 +354,41 @@ foreach {testprefix do_wal_checkpoint} {
|
||||
|
||||
do_test 3.$tn.6 { code3 { do_wal_checkpoint db3 } } {0 0 0}
|
||||
}
|
||||
|
||||
# Test SQLITE_CHECKPOINT_TRUNCATE.
|
||||
#
|
||||
do_multiclient_test tn {
|
||||
|
||||
code1 $do_wal_checkpoint
|
||||
code2 $do_wal_checkpoint
|
||||
code3 $do_wal_checkpoint
|
||||
|
||||
do_test 3.$tn.1 {
|
||||
sql1 {
|
||||
PRAGMA page_size = 1024;
|
||||
PRAGMA journal_mode = WAL;
|
||||
PRAGMA synchronous = normal;
|
||||
CREATE TABLE t1(x, y);
|
||||
CREATE INDEX i1 ON t1(x, y);
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
INSERT INTO t1 VALUES(3, 4);
|
||||
}
|
||||
file size test.db-wal
|
||||
} [wal_file_size 8 1024]
|
||||
|
||||
do_test 3.$tn.2 { do_wal_checkpoint db -mode truncate } {0 0 0}
|
||||
do_test 3.$tn.3 { file size test.db-wal } 0
|
||||
|
||||
do_test 3.$tn.4 {
|
||||
sql2 { SELECT * FROM t1 }
|
||||
} {1 2 3 4}
|
||||
|
||||
do_test 3.$tn.5 {
|
||||
sql2 { INSERT INTO t1 VALUES('a', 'b') }
|
||||
file size test.db-wal
|
||||
} [wal_file_size 2 1024]
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -640,4 +640,39 @@ do_execsql_test 4.2 {
|
||||
} {/.*SCAN TABLE cx.*SEARCH TABLE px.*SEARCH TABLE le.*/}
|
||||
|
||||
|
||||
# The following test is derived from a performance problem reported from
|
||||
# the field. Notice the multiple indexes with the same initial tables,
|
||||
# and the unusual WHERE clause terms.
|
||||
#
|
||||
do_test 5.1 {
|
||||
set res [db eval {
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1(a,b,c,d,e,f,g,h);
|
||||
CREATE INDEX t1abc ON t1(a,b,c);
|
||||
CREATE INDEX t1abe ON t1(a,b,e);
|
||||
CREATE INDEX t1abf ON t1(a,b,f);
|
||||
ANALYZE;
|
||||
DROP TABLE IF EXISTS sqlite_stat4;
|
||||
DROP TABLE IF EXISTS sqlite_stat3;
|
||||
DELETE FROM sqlite_stat1;
|
||||
INSERT INTO sqlite_stat1(tbl,idx,stat)
|
||||
VALUES('t1','t1abc','2000000 8000 1600 800'),
|
||||
('t1','t1abe','2000000 8000 1600 150'),
|
||||
('t1','t1abf','2000000 8000 1600 150');
|
||||
ANALYZE sqlite_master;
|
||||
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT * FROM t1
|
||||
WHERE (a=1 OR a=2)
|
||||
AND (b=3 OR b=4)
|
||||
AND (d>=5 AND d<=5)
|
||||
AND ((e>=7 AND e<=7) OR (f>=8 AND f<=8))
|
||||
AND g>0;
|
||||
}]
|
||||
} {~/ANY/}
|
||||
do_test 5.2 {set res} {/USING INDEX t1abe/}
|
||||
do_test 5.3 {set res} {/USING INDEX t1abf/}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
@@ -185,8 +185,7 @@ do_execsql_test without_rowid5-5.9 {
|
||||
# EVIDENCE-OF: R-12643-30541 The incremental blob I/O mechanism does not
|
||||
# work for WITHOUT ROWID tables.
|
||||
#
|
||||
# EVIDENCE-OF: R-25760-33257 The sqlite3_blob_open() interface will fail
|
||||
# for a WITHOUT ROWID table.
|
||||
# EVIDENCE-OF: R-40134-30296 Table zTable is a WITHOUT ROWID table
|
||||
#
|
||||
do_execsql_test without_rowid5-6.1 {
|
||||
CREATE TABLE b1(a INTEGER PRIMARY KEY, b BLOB) WITHOUT ROWID;
|
||||
|
||||
Reference in New Issue
Block a user