Index: third_party/sqlite/src/src/test1.c |
diff --git a/third_party/sqlite/src/src/test1.c b/third_party/sqlite/src/src/test1.c |
index 8a0d09a7164752018c497f0e957345118593260a..85a16488ba850f82143dfd67f54a2eb673ac8db2 100644 |
--- a/third_party/sqlite/src/src/test1.c |
+++ b/third_party/sqlite/src/src/test1.c |
@@ -14,6 +14,11 @@ |
** testing of the SQLite library. |
*/ |
#include "sqliteInt.h" |
+#if SQLITE_OS_WIN |
+# include "os_win.h" |
+#endif |
+ |
+#include "vdbeInt.h" |
#include "tcl.h" |
#include <stdlib.h> |
#include <string.h> |
@@ -112,61 +117,18 @@ int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){ |
return TCL_OK; |
} |
+#if SQLITE_OS_WIN |
+/* |
+** Decode a Win32 HANDLE object. |
+*/ |
+int getWin32Handle(Tcl_Interp *interp, const char *zA, LPHANDLE phFile){ |
+ *phFile = (HANDLE)sqlite3TestTextToPtr(zA); |
+ return TCL_OK; |
+} |
+#endif |
-const char *sqlite3TestErrorName(int rc){ |
- const char *zName = 0; |
- switch( rc ){ |
- case SQLITE_OK: zName = "SQLITE_OK"; break; |
- case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; |
- case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break; |
- case SQLITE_PERM: zName = "SQLITE_PERM"; break; |
- case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; |
- case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; |
- case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break; |
- case SQLITE_LOCKED_SHAREDCACHE: zName = "SQLITE_LOCKED_SHAREDCACHE";break; |
- case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break; |
- case SQLITE_READONLY: zName = "SQLITE_READONLY"; break; |
- case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break; |
- case SQLITE_IOERR: zName = "SQLITE_IOERR"; break; |
- case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break; |
- case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break; |
- case SQLITE_FULL: zName = "SQLITE_FULL"; break; |
- case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break; |
- case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break; |
- case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break; |
- case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break; |
- case SQLITE_TOOBIG: zName = "SQLITE_TOOBIG"; break; |
- case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break; |
- case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break; |
- case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break; |
- case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break; |
- case SQLITE_AUTH: zName = "SQLITE_AUTH"; break; |
- case SQLITE_FORMAT: zName = "SQLITE_FORMAT"; break; |
- case SQLITE_RANGE: zName = "SQLITE_RANGE"; break; |
- case SQLITE_NOTADB: zName = "SQLITE_NOTADB"; break; |
- case SQLITE_ROW: zName = "SQLITE_ROW"; break; |
- case SQLITE_DONE: zName = "SQLITE_DONE"; break; |
- case SQLITE_IOERR_READ: zName = "SQLITE_IOERR_READ"; break; |
- case SQLITE_IOERR_SHORT_READ: zName = "SQLITE_IOERR_SHORT_READ"; break; |
- case SQLITE_IOERR_WRITE: zName = "SQLITE_IOERR_WRITE"; break; |
- case SQLITE_IOERR_FSYNC: zName = "SQLITE_IOERR_FSYNC"; break; |
- case SQLITE_IOERR_DIR_FSYNC: zName = "SQLITE_IOERR_DIR_FSYNC"; break; |
- case SQLITE_IOERR_TRUNCATE: zName = "SQLITE_IOERR_TRUNCATE"; break; |
- case SQLITE_IOERR_FSTAT: zName = "SQLITE_IOERR_FSTAT"; break; |
- case SQLITE_IOERR_UNLOCK: zName = "SQLITE_IOERR_UNLOCK"; break; |
- case SQLITE_IOERR_RDLOCK: zName = "SQLITE_IOERR_RDLOCK"; break; |
- case SQLITE_IOERR_DELETE: zName = "SQLITE_IOERR_DELETE"; break; |
- case SQLITE_IOERR_BLOCKED: zName = "SQLITE_IOERR_BLOCKED"; break; |
- case SQLITE_IOERR_NOMEM: zName = "SQLITE_IOERR_NOMEM"; break; |
- case SQLITE_IOERR_ACCESS: zName = "SQLITE_IOERR_ACCESS"; break; |
- case SQLITE_IOERR_CHECKRESERVEDLOCK: |
- zName = "SQLITE_IOERR_CHECKRESERVEDLOCK"; break; |
- case SQLITE_IOERR_LOCK: zName = "SQLITE_IOERR_LOCK"; break; |
- default: zName = "SQLITE_Unknown"; break; |
- } |
- return zName; |
-} |
-#define t1ErrorName sqlite3TestErrorName |
+extern const char *sqlite3ErrName(int); |
+#define t1ErrorName sqlite3ErrName |
/* |
** Convert an sqlite3_stmt* into an sqlite3*. This depends on the |
@@ -294,7 +256,28 @@ static int test_io_trace( |
return TCL_OK; |
} |
- |
+/* |
+** Usage: clang_sanitize_address |
+** |
+** Returns true if the program was compiled using clang with the |
+** -fsanitize=address switch on the command line. False otherwise. |
+*/ |
+static int clang_sanitize_address( |
+ void *NotUsed, |
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
+ int argc, /* Number of arguments */ |
+ char **argv /* Text of each argument */ |
+){ |
+ int res = 0; |
+#if defined(__has_feature) |
+# if __has_feature(address_sanitizer) |
+ res = 1; |
+# endif |
+#endif |
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(res)); |
+ return TCL_OK; |
+} |
+ |
/* |
** Usage: sqlite3_exec_printf DB FORMAT STRING |
** |
@@ -664,6 +647,7 @@ static int test_key( |
int argc, /* Number of arguments */ |
char **argv /* Text of each argument */ |
){ |
+#ifdef SQLITE_HAS_CODEC |
sqlite3 *db; |
const char *zKey; |
int nKey; |
@@ -675,7 +659,6 @@ static int test_key( |
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; |
zKey = argv[2]; |
nKey = strlen(zKey); |
-#ifdef SQLITE_HAS_CODEC |
sqlite3_key(db, zKey, nKey); |
#endif |
return TCL_OK; |
@@ -692,6 +675,7 @@ static int test_rekey( |
int argc, /* Number of arguments */ |
char **argv /* Text of each argument */ |
){ |
+#ifdef SQLITE_HAS_CODEC |
sqlite3 *db; |
const char *zKey; |
int nKey; |
@@ -703,7 +687,6 @@ static int test_rekey( |
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; |
zKey = argv[2]; |
nKey = strlen(zKey); |
-#ifdef SQLITE_HAS_CODEC |
sqlite3_rekey(db, zKey, nKey); |
#endif |
return TCL_OK; |
@@ -734,6 +717,30 @@ static int sqlite_test_close( |
} |
/* |
+** Usage: sqlite3_close_v2 DB |
+** |
+** Closes the database opened by sqlite3_open. |
+*/ |
+static int sqlite_test_close_v2( |
+ void *NotUsed, |
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
+ int argc, /* Number of arguments */ |
+ char **argv /* Text of each argument */ |
+){ |
+ sqlite3 *db; |
+ int rc; |
+ if( argc!=2 ){ |
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], |
+ " FILENAME\"", 0); |
+ return TCL_ERROR; |
+ } |
+ if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; |
+ rc = sqlite3_close_v2(db); |
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); |
+ return TCL_OK; |
+} |
+ |
+/* |
** Implementation of the x_coalesce() function. |
** Return the first argument non-NULL argument. |
*/ |
@@ -796,7 +803,7 @@ struct dstr { |
** Append text to a dstr |
*/ |
static void dstrAppend(struct dstr *p, const char *z, int divider){ |
- int n = strlen(z); |
+ int n = (int)strlen(z); |
if( p->nUsed + n + 2 > p->nAlloc ){ |
char *zNew; |
p->nAlloc = p->nAlloc*2 + n + 200; |
@@ -970,9 +977,21 @@ static void ptrChngFunction( |
sqlite3_result_int(context, p1!=p2); |
} |
+/* |
+** This SQL function returns a different answer each time it is called, even if |
+** the arguments are the same. |
+*/ |
+static void nondeterministicFunction( |
+ sqlite3_context *context, |
+ int argc, |
+ sqlite3_value **argv |
+){ |
+ static int cnt = 0; |
+ sqlite3_result_int(context, cnt++); |
+} |
/* |
-** Usage: sqlite_test_create_function DB |
+** Usage: sqlite3_create_function DB |
** |
** Call the sqlite3_create_function API on the given database in order |
** to create a function named "x_coalesce". This function does the same thing |
@@ -1001,16 +1020,16 @@ static int test_create_function( |
return TCL_ERROR; |
} |
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; |
- rc = sqlite3_create_function(db, "x_coalesce", -1, SQLITE_ANY, 0, |
+ rc = sqlite3_create_function(db, "x_coalesce", -1, SQLITE_UTF8, 0, |
t1_ifnullFunc, 0, 0); |
if( rc==SQLITE_OK ){ |
- rc = sqlite3_create_function(db, "hex8", 1, SQLITE_ANY, 0, |
- hex8Func, 0, 0); |
+ rc = sqlite3_create_function(db, "hex8", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC, |
+ 0, hex8Func, 0, 0); |
} |
#ifndef SQLITE_OMIT_UTF16 |
if( rc==SQLITE_OK ){ |
- rc = sqlite3_create_function(db, "hex16", 1, SQLITE_ANY, 0, |
- hex16Func, 0, 0); |
+ rc = sqlite3_create_function(db, "hex16", 1, SQLITE_UTF16 | SQLITE_DETERMINISTIC, |
+ 0, hex16Func, 0, 0); |
} |
#endif |
if( rc==SQLITE_OK ){ |
@@ -1022,6 +1041,19 @@ static int test_create_function( |
ptrChngFunction, 0, 0); |
} |
+ /* Functions counter1() and counter2() have the same implementation - they |
+ ** both return an ascending integer with each call. But counter1() is marked |
+ ** as non-deterministic and counter2() is marked as deterministic. |
+ */ |
+ if( rc==SQLITE_OK ){ |
+ rc = sqlite3_create_function(db, "counter1", -1, SQLITE_UTF8, |
+ 0, nondeterministicFunction, 0, 0); |
+ } |
+ if( rc==SQLITE_OK ){ |
+ rc = sqlite3_create_function(db, "counter2", -1, SQLITE_UTF8|SQLITE_DETERMINISTIC, |
+ 0, nondeterministicFunction, 0, 0); |
+ } |
+ |
#ifndef SQLITE_OMIT_UTF16 |
/* Use the sqlite3_create_function16() API here. Mainly for fun, but also |
** because it is not tested anywhere else. */ |
@@ -1711,7 +1743,7 @@ static int test_blob_read( |
if( rc==SQLITE_OK ){ |
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zBuf, nByte)); |
}else{ |
- Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); |
+ Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); |
} |
Tcl_Free((char *)zBuf); |
@@ -1761,7 +1793,7 @@ static int test_blob_write( |
} |
rc = sqlite3_blob_write(pBlob, zBuf, nBuf, iOffset); |
if( rc!=SQLITE_OK ){ |
- Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); |
+ Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); |
} |
return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); |
@@ -1787,7 +1819,7 @@ static int test_blob_reopen( |
rc = sqlite3_blob_reopen(pBlob, iRowid); |
if( rc!=SQLITE_OK ){ |
- Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); |
+ Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); |
} |
return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); |
@@ -1997,7 +2029,7 @@ static int test_create_function_v2( |
); |
if( rc!=SQLITE_OK ){ |
Tcl_ResetResult(interp); |
- Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0); |
+ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); |
return TCL_ERROR; |
} |
return TCL_OK; |
@@ -2246,6 +2278,7 @@ static int test_stmt_status( |
{ "SQLITE_STMTSTATUS_FULLSCAN_STEP", SQLITE_STMTSTATUS_FULLSCAN_STEP }, |
{ "SQLITE_STMTSTATUS_SORT", SQLITE_STMTSTATUS_SORT }, |
{ "SQLITE_STMTSTATUS_AUTOINDEX", SQLITE_STMTSTATUS_AUTOINDEX }, |
+ { "SQLITE_STMTSTATUS_VM_STEP", SQLITE_STMTSTATUS_VM_STEP }, |
}; |
if( objc!=4 ){ |
Tcl_WrongNumArgs(interp, 1, objv, "STMT PARAMETER RESETFLAG"); |
@@ -2326,6 +2359,58 @@ static int test_stmt_readonly( |
return TCL_OK; |
} |
+/* |
+** Usage: sqlite3_stmt_busy STMT |
+** |
+** Return true if STMT is a non-NULL pointer to a statement |
+** that has been stepped but not to completion. |
+*/ |
+static int test_stmt_busy( |
+ void * clientData, |
+ Tcl_Interp *interp, |
+ int objc, |
+ Tcl_Obj *CONST objv[] |
+){ |
+ sqlite3_stmt *pStmt; |
+ int rc; |
+ |
+ if( objc!=2 ){ |
+ Tcl_AppendResult(interp, "wrong # args: should be \"", |
+ Tcl_GetStringFromObj(objv[0], 0), " STMT", 0); |
+ return TCL_ERROR; |
+ } |
+ |
+ if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; |
+ rc = sqlite3_stmt_busy(pStmt); |
+ Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc)); |
+ return TCL_OK; |
+} |
+ |
+/* |
+** Usage: uses_stmt_journal STMT |
+** |
+** Return true if STMT uses a statement journal. |
+*/ |
+static int uses_stmt_journal( |
+ void * clientData, |
+ Tcl_Interp *interp, |
+ int objc, |
+ Tcl_Obj *CONST objv[] |
+){ |
+ sqlite3_stmt *pStmt; |
+ |
+ if( objc!=2 ){ |
+ Tcl_AppendResult(interp, "wrong # args: should be \"", |
+ Tcl_GetStringFromObj(objv[0], 0), " STMT", 0); |
+ return TCL_ERROR; |
+ } |
+ |
+ if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; |
+ sqlite3_stmt_readonly(pStmt); |
+ Tcl_SetObjResult(interp, Tcl_NewBooleanObj(((Vdbe *)pStmt)->usesStmtJournal)); |
+ return TCL_OK; |
+} |
+ |
/* |
** Usage: sqlite3_reset STMT |
@@ -2445,7 +2530,7 @@ static int sqlite_static_bind_nbyte = 0; |
/* |
** Usage: sqlite3_bind VM IDX VALUE FLAGS |
** |
-** Sets the value of the IDX-th occurance of "?" in the original SQL |
+** Sets the value of the IDX-th occurrence of "?" in the original SQL |
** string. VALUE is the new value. If FLAGS=="null" then VALUE is |
** ignored and the value is set to NULL. If FLAGS=="static" then |
** the value is set to the value of a static variable named |
@@ -2520,7 +2605,7 @@ static int test_bind( |
** SQLite selected to call. The TCL test script implements the |
** "test_collate" proc. |
** |
-** Note that this will only work with one intepreter at a time, as the |
+** Note that this will only work with one interpreter at a time, as the |
** interp pointer to use when evaluating the TCL script is stored in |
** pTestCollateInterp. |
*/ |
@@ -2621,7 +2706,7 @@ static int test_collate( |
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; |
if( rc!=SQLITE_OK ){ |
- Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0); |
+ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); |
return TCL_ERROR; |
} |
return TCL_OK; |
@@ -2633,6 +2718,46 @@ bad_args: |
} |
/* |
+** Usage: add_test_utf16bin_collate <db ptr> |
+** |
+** Add a utf-16 collation sequence named "utf16bin" to the database |
+** handle. This collation sequence compares arguments in the same way as the |
+** built-in collation "binary". |
+*/ |
+static int test_utf16bin_collate_func( |
+ void *pCtx, |
+ int nA, const void *zA, |
+ int nB, const void *zB |
+){ |
+ int nCmp = (nA>nB ? nB : nA); |
+ int res = memcmp(zA, zB, nCmp); |
+ if( res==0 ) res = nA - nB; |
+ return res; |
+} |
+static int test_utf16bin_collate( |
+ void * clientData, |
+ Tcl_Interp *interp, |
+ int objc, |
+ Tcl_Obj *CONST objv[] |
+){ |
+ sqlite3 *db; |
+ int rc; |
+ |
+ if( objc!=2 ) goto bad_args; |
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; |
+ |
+ rc = sqlite3_create_collation(db, "utf16bin", SQLITE_UTF16, 0, |
+ test_utf16bin_collate_func |
+ ); |
+ if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; |
+ return TCL_OK; |
+ |
+bad_args: |
+ Tcl_WrongNumArgs(interp, 1, objv, "DB"); |
+ return TCL_ERROR; |
+} |
+ |
+/* |
** When the collation needed callback is invoked, record the name of |
** the requested collating function here. The recorded name is linked |
** to a TCL variable and used to make sure that the requested collation |
@@ -3011,7 +3136,7 @@ static int test_bind_int64( |
){ |
sqlite3_stmt *pStmt; |
int idx; |
- i64 value; |
+ Tcl_WideInt value; |
int rc; |
if( objc!=4 ){ |
@@ -3179,7 +3304,7 @@ static int test_bind_text( |
rc = sqlite3_bind_text(pStmt, idx, value, bytes, SQLITE_TRANSIENT); |
if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; |
if( rc!=SQLITE_OK ){ |
- Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0); |
+ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); |
return TCL_ERROR; |
} |
@@ -3207,7 +3332,7 @@ static int test_bind_text16( |
char *value; |
int rc; |
- void (*xDel)() = (objc==6?SQLITE_STATIC:SQLITE_TRANSIENT); |
+ void (*xDel)(void*) = (objc==6?SQLITE_STATIC:SQLITE_TRANSIENT); |
Tcl_Obj *oStmt = objv[objc-4]; |
Tcl_Obj *oN = objv[objc-3]; |
Tcl_Obj *oString = objv[objc-2]; |
@@ -3227,7 +3352,7 @@ static int test_bind_text16( |
rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, xDel); |
if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; |
if( rc!=SQLITE_OK ){ |
- Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0); |
+ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); |
return TCL_ERROR; |
} |
@@ -3553,10 +3678,10 @@ static int test_prepare( |
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; |
if( zTail && objc>=5 ){ |
if( bytes>=0 ){ |
- bytes = bytes - (zTail-zSql); |
+ bytes = bytes - (int)(zTail-zSql); |
} |
- if( strlen(zTail)<bytes ){ |
- bytes = strlen(zTail); |
+ if( (int)strlen(zTail)<bytes ){ |
+ bytes = (int)strlen(zTail); |
} |
Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0); |
} |
@@ -3611,7 +3736,7 @@ static int test_prepare_v2( |
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; |
if( zTail && objc>=5 ){ |
if( bytes>=0 ){ |
- bytes = bytes - (zTail-zSql); |
+ bytes = bytes - (int)(zTail-zSql); |
} |
Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0); |
} |
@@ -3633,7 +3758,7 @@ static int test_prepare_v2( |
** Usage: sqlite3_prepare_tkt3134 DB |
** |
** Generate a prepared statement for a zero-byte string as a test |
-** for ticket #3134. The string should be preceeded by a zero byte. |
+** for ticket #3134. The string should be preceded by a zero byte. |
*/ |
static int test_prepare_tkt3134( |
void * clientData, |
@@ -3712,7 +3837,7 @@ static int test_prepare16( |
if( objc>=5 ){ |
if( zTail ){ |
- objlen = objlen - ((u8 *)zTail-(u8 *)zSql); |
+ objlen = objlen - (int)((u8 *)zTail-(u8 *)zSql); |
}else{ |
objlen = 0; |
} |
@@ -3772,7 +3897,7 @@ static int test_prepare16_v2( |
if( objc>=5 ){ |
if( zTail ){ |
- objlen = objlen - ((u8 *)zTail-(u8 *)zSql); |
+ objlen = objlen - (int)((u8 *)zTail-(u8 *)zSql); |
}else{ |
objlen = 0; |
} |
@@ -3801,7 +3926,6 @@ static int test_open( |
){ |
const char *zFilename; |
sqlite3 *db; |
- int rc; |
char zBuf[100]; |
if( objc!=3 && objc!=2 && objc!=1 ){ |
@@ -3811,7 +3935,7 @@ static int test_open( |
} |
zFilename = objc>1 ? Tcl_GetString(objv[1]) : 0; |
- rc = sqlite3_open(zFilename, &db); |
+ sqlite3_open(zFilename, &db); |
if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR; |
Tcl_AppendResult(interp, zBuf, 0); |
@@ -3819,6 +3943,76 @@ static int test_open( |
} |
/* |
+** Usage: sqlite3_open_v2 FILENAME FLAGS VFS |
+*/ |
+static int test_open_v2( |
+ void * clientData, |
+ Tcl_Interp *interp, |
+ int objc, |
+ Tcl_Obj *CONST objv[] |
+){ |
+ const char *zFilename; |
+ const char *zVfs; |
+ int flags = 0; |
+ sqlite3 *db; |
+ int rc; |
+ char zBuf[100]; |
+ |
+ int nFlag; |
+ Tcl_Obj **apFlag; |
+ int i; |
+ |
+ if( objc!=4 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, "FILENAME FLAGS VFS"); |
+ return TCL_ERROR; |
+ } |
+ zFilename = Tcl_GetString(objv[1]); |
+ zVfs = Tcl_GetString(objv[3]); |
+ if( zVfs[0]==0x00 ) zVfs = 0; |
+ |
+ rc = Tcl_ListObjGetElements(interp, objv[2], &nFlag, &apFlag); |
+ if( rc!=TCL_OK ) return rc; |
+ for(i=0; i<nFlag; i++){ |
+ int iFlag; |
+ struct OpenFlag { |
+ const char *zFlag; |
+ int flag; |
+ } aFlag[] = { |
+ { "SQLITE_OPEN_READONLY", SQLITE_OPEN_READONLY }, |
+ { "SQLITE_OPEN_READWRITE", SQLITE_OPEN_READWRITE }, |
+ { "SQLITE_OPEN_CREATE", SQLITE_OPEN_CREATE }, |
+ { "SQLITE_OPEN_DELETEONCLOSE", SQLITE_OPEN_DELETEONCLOSE }, |
+ { "SQLITE_OPEN_EXCLUSIVE", SQLITE_OPEN_EXCLUSIVE }, |
+ { "SQLITE_OPEN_AUTOPROXY", SQLITE_OPEN_AUTOPROXY }, |
+ { "SQLITE_OPEN_MAIN_DB", SQLITE_OPEN_MAIN_DB }, |
+ { "SQLITE_OPEN_TEMP_DB", SQLITE_OPEN_TEMP_DB }, |
+ { "SQLITE_OPEN_TRANSIENT_DB", SQLITE_OPEN_TRANSIENT_DB }, |
+ { "SQLITE_OPEN_MAIN_JOURNAL", SQLITE_OPEN_MAIN_JOURNAL }, |
+ { "SQLITE_OPEN_TEMP_JOURNAL", SQLITE_OPEN_TEMP_JOURNAL }, |
+ { "SQLITE_OPEN_SUBJOURNAL", SQLITE_OPEN_SUBJOURNAL }, |
+ { "SQLITE_OPEN_MASTER_JOURNAL", SQLITE_OPEN_MASTER_JOURNAL }, |
+ { "SQLITE_OPEN_NOMUTEX", SQLITE_OPEN_NOMUTEX }, |
+ { "SQLITE_OPEN_FULLMUTEX", SQLITE_OPEN_FULLMUTEX }, |
+ { "SQLITE_OPEN_SHAREDCACHE", SQLITE_OPEN_SHAREDCACHE }, |
+ { "SQLITE_OPEN_PRIVATECACHE", SQLITE_OPEN_PRIVATECACHE }, |
+ { "SQLITE_OPEN_WAL", SQLITE_OPEN_WAL }, |
+ { "SQLITE_OPEN_URI", SQLITE_OPEN_URI }, |
+ { 0, 0 } |
+ }; |
+ rc = Tcl_GetIndexFromObjStruct(interp, apFlag[i], aFlag, sizeof(aFlag[0]), |
+ "flag", 0, &iFlag |
+ ); |
+ if( rc!=TCL_OK ) return rc; |
+ flags |= aFlag[iFlag].flag; |
+ } |
+ |
+ rc = sqlite3_open_v2(zFilename, &db, flags, zVfs); |
+ if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR; |
+ Tcl_AppendResult(interp, zBuf, 0); |
+ return TCL_OK; |
+} |
+ |
+/* |
** Usage: sqlite3_open16 filename options |
*/ |
static int test_open16( |
@@ -3830,7 +4024,6 @@ static int test_open16( |
#ifndef SQLITE_OMIT_UTF16 |
const void *zFilename; |
sqlite3 *db; |
- int rc; |
char zBuf[100]; |
if( objc!=3 ){ |
@@ -3840,7 +4033,7 @@ static int test_open16( |
} |
zFilename = Tcl_GetByteArrayFromObj(objv[1], 0); |
- rc = sqlite3_open16(zFilename, &db); |
+ sqlite3_open16(zFilename, &db); |
if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR; |
Tcl_AppendResult(interp, zBuf, 0); |
@@ -4295,7 +4488,7 @@ static u8 *sqlite3_stack_baseline = 0; |
static void prepStack(void){ |
int i; |
u32 bigBuf[65536]; |
- for(i=0; i<sizeof(bigBuf); i++) bigBuf[i] = 0xdeadbeef; |
+ for(i=0; i<sizeof(bigBuf)/sizeof(bigBuf[0]); i++) bigBuf[i] = 0xdeadbeef; |
sqlite3_stack_baseline = (u8*)&bigBuf[65536]; |
} |
@@ -4433,7 +4626,7 @@ static int test_busy_timeout( |
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; |
if( Tcl_GetInt(interp, argv[2], &ms) ) return TCL_ERROR; |
rc = sqlite3_busy_timeout(db, ms); |
- Tcl_AppendResult(interp, sqlite3TestErrorName(rc), 0); |
+ Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); |
return TCL_OK; |
} |
@@ -4493,6 +4686,78 @@ static int test_release_memory( |
return TCL_OK; |
} |
+ |
+/* |
+** Usage: sqlite3_db_release_memory DB |
+** |
+** Attempt to release memory currently held by database DB. Return the |
+** result code (which in the current implementation is always zero). |
+*/ |
+static int test_db_release_memory( |
+ void * clientData, |
+ Tcl_Interp *interp, |
+ int objc, |
+ Tcl_Obj *CONST objv[] |
+){ |
+ sqlite3 *db; |
+ int rc; |
+ if( objc!=2 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, "DB"); |
+ return TCL_ERROR; |
+ } |
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; |
+ rc = sqlite3_db_release_memory(db); |
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); |
+ return TCL_OK; |
+} |
+ |
+/* |
+** Usage: sqlite3_db_filename DB DBNAME |
+** |
+** Return the name of a file associated with a database. |
+*/ |
+static int test_db_filename( |
+ void * clientData, |
+ Tcl_Interp *interp, |
+ int objc, |
+ Tcl_Obj *CONST objv[] |
+){ |
+ sqlite3 *db; |
+ const char *zDbName; |
+ if( objc!=3 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME"); |
+ return TCL_ERROR; |
+ } |
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; |
+ zDbName = Tcl_GetString(objv[2]); |
+ Tcl_AppendResult(interp, sqlite3_db_filename(db, zDbName), (void*)0); |
+ return TCL_OK; |
+} |
+ |
+/* |
+** Usage: sqlite3_db_readonly DB DBNAME |
+** |
+** Return 1 or 0 if DBNAME is readonly or not. Return -1 if DBNAME does |
+** not exist. |
+*/ |
+static int test_db_readonly( |
+ void * clientData, |
+ Tcl_Interp *interp, |
+ int objc, |
+ Tcl_Obj *CONST objv[] |
+){ |
+ sqlite3 *db; |
+ const char *zDbName; |
+ if( objc!=3 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME"); |
+ return TCL_ERROR; |
+ } |
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; |
+ zDbName = Tcl_GetString(objv[2]); |
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_db_readonly(db, zDbName))); |
+ return TCL_OK; |
+} |
+ |
/* |
** Usage: sqlite3_soft_heap_limit ?N? |
** |
@@ -4507,7 +4772,7 @@ static int test_soft_heap_limit( |
Tcl_Obj *CONST objv[] |
){ |
sqlite3_int64 amt; |
- sqlite3_int64 N = -1; |
+ Tcl_WideInt N = -1; |
if( objc!=1 && objc!=2 ){ |
Tcl_WrongNumArgs(interp, 1, objv, "?N?"); |
return TCL_ERROR; |
@@ -4882,7 +5147,7 @@ static int file_control_chunksize_test( |
rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_CHUNK_SIZE, (void *)&nSize); |
if( rc ){ |
- Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC); |
+ Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); |
return TCL_ERROR; |
} |
return TCL_OK; |
@@ -4891,9 +5156,8 @@ static int file_control_chunksize_test( |
/* |
** tclcmd: file_control_sizehint_test DB DBNAME SIZE |
** |
-** This TCL command runs the sqlite3_file_control interface and |
-** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and |
-** SQLITE_SET_LOCKPROXYFILE verbs. |
+** This TCL command runs the sqlite3_file_control interface |
+** with SQLITE_FCNTL_SIZE_HINT |
*/ |
static int file_control_sizehint_test( |
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ |
@@ -4901,7 +5165,7 @@ static int file_control_sizehint_test( |
int objc, /* Number of arguments */ |
Tcl_Obj *CONST objv[] /* Command arguments */ |
){ |
- sqlite3_int64 nSize; /* Hinted size */ |
+ Tcl_WideInt nSize; /* Hinted size */ |
char *zDb; /* Db name ("main", "temp" etc.) */ |
sqlite3 *db; /* Database handle */ |
int rc; /* file_control() return code */ |
@@ -4920,7 +5184,7 @@ static int file_control_sizehint_test( |
rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_SIZE_HINT, (void *)&nSize); |
if( rc ){ |
- Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC); |
+ Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC); |
return TCL_ERROR; |
} |
return TCL_OK; |
@@ -4940,8 +5204,6 @@ static int file_control_lockproxy_test( |
Tcl_Obj *CONST objv[] /* Command arguments */ |
){ |
sqlite3 *db; |
- const char *zPwd; |
- int nPwd; |
if( objc!=3 ){ |
Tcl_AppendResult(interp, "wrong # args: should be \"", |
@@ -4951,7 +5213,6 @@ static int file_control_lockproxy_test( |
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ |
return TCL_ERROR; |
} |
- zPwd = Tcl_GetStringFromObj(objv[2], &nPwd); |
#if !defined(SQLITE_ENABLE_LOCKING_STYLE) |
# if defined(__APPLE__) |
@@ -4964,8 +5225,11 @@ static int file_control_lockproxy_test( |
{ |
char *testPath; |
int rc; |
+ int nPwd; |
+ const char *zPwd; |
char proxyPath[400]; |
+ zPwd = Tcl_GetStringFromObj(objv[2], &nPwd); |
if( sizeof(proxyPath)<nPwd+20 ){ |
Tcl_AppendResult(interp, "PWD too big", (void*)0); |
return TCL_ERROR; |
@@ -4996,38 +5260,47 @@ static int file_control_lockproxy_test( |
return TCL_OK; |
} |
- |
+#if SQLITE_OS_WIN |
/* |
-** tclcmd: sqlite3_vfs_list |
+** tclcmd: file_control_win32_av_retry DB NRETRY DELAY |
** |
-** Return a tcl list containing the names of all registered vfs's. |
+** This TCL command runs the sqlite3_file_control interface with |
+** the SQLITE_FCNTL_WIN32_AV_RETRY opcode. |
*/ |
-static int vfs_list( |
+static int file_control_win32_av_retry( |
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ |
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
int objc, /* Number of arguments */ |
Tcl_Obj *CONST objv[] /* Command arguments */ |
){ |
- sqlite3_vfs *pVfs; |
- Tcl_Obj *pRet = Tcl_NewObj(); |
- if( objc!=1 ){ |
- Tcl_WrongNumArgs(interp, 1, objv, ""); |
+ sqlite3 *db; |
+ int rc; |
+ int a[2]; |
+ char z[100]; |
+ |
+ if( objc!=4 ){ |
+ Tcl_AppendResult(interp, "wrong # args: should be \"", |
+ Tcl_GetStringFromObj(objv[0], 0), " DB NRETRY DELAY", 0); |
return TCL_ERROR; |
} |
- for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){ |
- Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(pVfs->zName, -1)); |
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ |
+ return TCL_ERROR; |
} |
- Tcl_SetObjResult(interp, pRet); |
+ if( Tcl_GetIntFromObj(interp, objv[2], &a[0]) ) return TCL_ERROR; |
+ if( Tcl_GetIntFromObj(interp, objv[3], &a[1]) ) return TCL_ERROR; |
+ rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_WIN32_AV_RETRY, (void*)a); |
+ sqlite3_snprintf(sizeof(z), z, "%d %d %d", rc, a[0], a[1]); |
+ Tcl_AppendResult(interp, z, (char*)0); |
return TCL_OK; |
} |
/* |
-** tclcmd: sqlite3_limit DB ID VALUE |
+** tclcmd: file_control_win32_set_handle DB HANDLE |
** |
-** This TCL command runs the sqlite3_limit interface and |
-** verifies correct operation of the same. |
+** This TCL command runs the sqlite3_file_control interface with |
+** the SQLITE_FCNTL_WIN32_SET_HANDLE opcode. |
*/ |
-static int test_limit( |
+static int file_control_win32_set_handle( |
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ |
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
int objc, /* Number of arguments */ |
@@ -5035,29 +5308,220 @@ static int test_limit( |
){ |
sqlite3 *db; |
int rc; |
- static const struct { |
- char *zName; |
- int id; |
- } aId[] = { |
- { "SQLITE_LIMIT_LENGTH", SQLITE_LIMIT_LENGTH }, |
- { "SQLITE_LIMIT_SQL_LENGTH", SQLITE_LIMIT_SQL_LENGTH }, |
- { "SQLITE_LIMIT_COLUMN", SQLITE_LIMIT_COLUMN }, |
- { "SQLITE_LIMIT_EXPR_DEPTH", SQLITE_LIMIT_EXPR_DEPTH }, |
- { "SQLITE_LIMIT_COMPOUND_SELECT", SQLITE_LIMIT_COMPOUND_SELECT }, |
- { "SQLITE_LIMIT_VDBE_OP", SQLITE_LIMIT_VDBE_OP }, |
- { "SQLITE_LIMIT_FUNCTION_ARG", SQLITE_LIMIT_FUNCTION_ARG }, |
- { "SQLITE_LIMIT_ATTACHED", SQLITE_LIMIT_ATTACHED }, |
- { "SQLITE_LIMIT_LIKE_PATTERN_LENGTH", SQLITE_LIMIT_LIKE_PATTERN_LENGTH }, |
- { "SQLITE_LIMIT_VARIABLE_NUMBER", SQLITE_LIMIT_VARIABLE_NUMBER }, |
- { "SQLITE_LIMIT_TRIGGER_DEPTH", SQLITE_LIMIT_TRIGGER_DEPTH }, |
- |
- /* Out of range test cases */ |
- { "SQLITE_LIMIT_TOOSMALL", -1, }, |
- { "SQLITE_LIMIT_TOOBIG", SQLITE_LIMIT_TRIGGER_DEPTH+1 }, |
- }; |
- int i, id; |
- int val; |
- const char *zId; |
+ HANDLE hFile = NULL; |
+ char z[100]; |
+ |
+ if( objc!=3 ){ |
+ Tcl_AppendResult(interp, "wrong # args: should be \"", |
+ Tcl_GetStringFromObj(objv[0], 0), " DB HANDLE", 0); |
+ return TCL_ERROR; |
+ } |
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ |
+ return TCL_ERROR; |
+ } |
+ if( getWin32Handle(interp, Tcl_GetString(objv[2]), &hFile) ){ |
+ return TCL_ERROR; |
+ } |
+ rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_WIN32_SET_HANDLE, |
+ (void*)&hFile); |
+ sqlite3_snprintf(sizeof(z), z, "%d %p", rc, (void*)hFile); |
+ Tcl_AppendResult(interp, z, (char*)0); |
+ return TCL_OK; |
+} |
+#endif |
+ |
+/* |
+** tclcmd: file_control_persist_wal DB PERSIST-FLAG |
+** |
+** This TCL command runs the sqlite3_file_control interface with |
+** the SQLITE_FCNTL_PERSIST_WAL opcode. |
+*/ |
+static int file_control_persist_wal( |
+ ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ |
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
+ int objc, /* Number of arguments */ |
+ Tcl_Obj *CONST objv[] /* Command arguments */ |
+){ |
+ sqlite3 *db; |
+ int rc; |
+ int bPersist; |
+ char z[100]; |
+ |
+ if( objc!=3 ){ |
+ Tcl_AppendResult(interp, "wrong # args: should be \"", |
+ Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", 0); |
+ return TCL_ERROR; |
+ } |
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ |
+ return TCL_ERROR; |
+ } |
+ if( Tcl_GetIntFromObj(interp, objv[2], &bPersist) ) return TCL_ERROR; |
+ rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_PERSIST_WAL, (void*)&bPersist); |
+ sqlite3_snprintf(sizeof(z), z, "%d %d", rc, bPersist); |
+ Tcl_AppendResult(interp, z, (char*)0); |
+ return TCL_OK; |
+} |
+ |
+/* |
+** tclcmd: file_control_powersafe_overwrite DB PSOW-FLAG |
+** |
+** This TCL command runs the sqlite3_file_control interface with |
+** the SQLITE_FCNTL_POWERSAFE_OVERWRITE opcode. |
+*/ |
+static int file_control_powersafe_overwrite( |
+ ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ |
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
+ int objc, /* Number of arguments */ |
+ Tcl_Obj *CONST objv[] /* Command arguments */ |
+){ |
+ sqlite3 *db; |
+ int rc; |
+ int b; |
+ char z[100]; |
+ |
+ if( objc!=3 ){ |
+ Tcl_AppendResult(interp, "wrong # args: should be \"", |
+ Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", 0); |
+ return TCL_ERROR; |
+ } |
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ |
+ return TCL_ERROR; |
+ } |
+ if( Tcl_GetIntFromObj(interp, objv[2], &b) ) return TCL_ERROR; |
+ rc = sqlite3_file_control(db,NULL,SQLITE_FCNTL_POWERSAFE_OVERWRITE,(void*)&b); |
+ sqlite3_snprintf(sizeof(z), z, "%d %d", rc, b); |
+ Tcl_AppendResult(interp, z, (char*)0); |
+ return TCL_OK; |
+} |
+ |
+ |
+/* |
+** tclcmd: file_control_vfsname DB ?AUXDB? |
+** |
+** Return a string that describes the stack of VFSes. |
+*/ |
+static int file_control_vfsname( |
+ ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ |
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
+ int objc, /* Number of arguments */ |
+ Tcl_Obj *CONST objv[] /* Command arguments */ |
+){ |
+ sqlite3 *db; |
+ const char *zDbName = "main"; |
+ char *zVfsName = 0; |
+ |
+ if( objc!=2 && objc!=3 ){ |
+ Tcl_AppendResult(interp, "wrong # args: should be \"", |
+ Tcl_GetStringFromObj(objv[0], 0), " DB ?AUXDB?", 0); |
+ return TCL_ERROR; |
+ } |
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ |
+ return TCL_ERROR; |
+ } |
+ if( objc==3 ){ |
+ zDbName = Tcl_GetString(objv[2]); |
+ } |
+ sqlite3_file_control(db, zDbName, SQLITE_FCNTL_VFSNAME,(void*)&zVfsName); |
+ Tcl_AppendResult(interp, zVfsName, (char*)0); |
+ sqlite3_free(zVfsName); |
+ return TCL_OK; |
+} |
+ |
+/* |
+** tclcmd: file_control_tempfilename DB ?AUXDB? |
+** |
+** Return a string that is a temporary filename |
+*/ |
+static int file_control_tempfilename( |
+ ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ |
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
+ int objc, /* Number of arguments */ |
+ Tcl_Obj *CONST objv[] /* Command arguments */ |
+){ |
+ sqlite3 *db; |
+ const char *zDbName = "main"; |
+ char *zTName = 0; |
+ |
+ if( objc!=2 && objc!=3 ){ |
+ Tcl_AppendResult(interp, "wrong # args: should be \"", |
+ Tcl_GetStringFromObj(objv[0], 0), " DB ?AUXDB?", 0); |
+ return TCL_ERROR; |
+ } |
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ |
+ return TCL_ERROR; |
+ } |
+ if( objc==3 ){ |
+ zDbName = Tcl_GetString(objv[2]); |
+ } |
+ sqlite3_file_control(db, zDbName, SQLITE_FCNTL_TEMPFILENAME, (void*)&zTName); |
+ Tcl_AppendResult(interp, zTName, (char*)0); |
+ sqlite3_free(zTName); |
+ return TCL_OK; |
+} |
+ |
+ |
+/* |
+** tclcmd: sqlite3_vfs_list |
+** |
+** Return a tcl list containing the names of all registered vfs's. |
+*/ |
+static int vfs_list( |
+ ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ |
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
+ int objc, /* Number of arguments */ |
+ Tcl_Obj *CONST objv[] /* Command arguments */ |
+){ |
+ sqlite3_vfs *pVfs; |
+ Tcl_Obj *pRet = Tcl_NewObj(); |
+ if( objc!=1 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, ""); |
+ return TCL_ERROR; |
+ } |
+ for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){ |
+ Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(pVfs->zName, -1)); |
+ } |
+ Tcl_SetObjResult(interp, pRet); |
+ return TCL_OK; |
+} |
+ |
+/* |
+** tclcmd: sqlite3_limit DB ID VALUE |
+** |
+** This TCL command runs the sqlite3_limit interface and |
+** verifies correct operation of the same. |
+*/ |
+static int test_limit( |
+ ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ |
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
+ int objc, /* Number of arguments */ |
+ Tcl_Obj *CONST objv[] /* Command arguments */ |
+){ |
+ sqlite3 *db; |
+ int rc; |
+ static const struct { |
+ char *zName; |
+ int id; |
+ } aId[] = { |
+ { "SQLITE_LIMIT_LENGTH", SQLITE_LIMIT_LENGTH }, |
+ { "SQLITE_LIMIT_SQL_LENGTH", SQLITE_LIMIT_SQL_LENGTH }, |
+ { "SQLITE_LIMIT_COLUMN", SQLITE_LIMIT_COLUMN }, |
+ { "SQLITE_LIMIT_EXPR_DEPTH", SQLITE_LIMIT_EXPR_DEPTH }, |
+ { "SQLITE_LIMIT_COMPOUND_SELECT", SQLITE_LIMIT_COMPOUND_SELECT }, |
+ { "SQLITE_LIMIT_VDBE_OP", SQLITE_LIMIT_VDBE_OP }, |
+ { "SQLITE_LIMIT_FUNCTION_ARG", SQLITE_LIMIT_FUNCTION_ARG }, |
+ { "SQLITE_LIMIT_ATTACHED", SQLITE_LIMIT_ATTACHED }, |
+ { "SQLITE_LIMIT_LIKE_PATTERN_LENGTH", SQLITE_LIMIT_LIKE_PATTERN_LENGTH }, |
+ { "SQLITE_LIMIT_VARIABLE_NUMBER", SQLITE_LIMIT_VARIABLE_NUMBER }, |
+ { "SQLITE_LIMIT_TRIGGER_DEPTH", SQLITE_LIMIT_TRIGGER_DEPTH }, |
+ { "SQLITE_LIMIT_WORKER_THREADS", SQLITE_LIMIT_WORKER_THREADS }, |
+ |
+ /* Out of range test cases */ |
+ { "SQLITE_LIMIT_TOOSMALL", -1, }, |
+ { "SQLITE_LIMIT_TOOBIG", SQLITE_LIMIT_WORKER_THREADS+1 }, |
+ }; |
+ int i, id; |
+ int val; |
+ const char *zId; |
if( objc!=4 ){ |
Tcl_AppendResult(interp, "wrong # args: should be \"", |
@@ -5128,6 +5592,37 @@ static int reset_prng_state( |
} |
/* |
+** tclcmd: database_may_be_corrupt |
+** |
+** Indicate that database files might be corrupt. In other words, set the normal |
+** state of operation. |
+*/ |
+static int database_may_be_corrupt( |
+ ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ |
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
+ int objc, /* Number of arguments */ |
+ Tcl_Obj *CONST objv[] /* Command arguments */ |
+){ |
+ sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, 0); |
+ return TCL_OK; |
+} |
+/* |
+** tclcmd: database_never_corrupt |
+** |
+** Indicate that database files are always well-formed. This enables extra assert() |
+** statements that test conditions that are always true for well-formed databases. |
+*/ |
+static int database_never_corrupt( |
+ ClientData clientData, /* Pointer to sqlite3_enable_XXX function */ |
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
+ int objc, /* Number of arguments */ |
+ Tcl_Obj *CONST objv[] /* Command arguments */ |
+){ |
+ sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, 1); |
+ return TCL_OK; |
+} |
+ |
+/* |
** tclcmd: pcache_stats |
*/ |
static int test_pcache_stats( |
@@ -5238,7 +5733,7 @@ static int test_wal_checkpoint( |
** |
** Otherwise, this command returns a list of three integers. The first integer |
** is 1 if SQLITE_BUSY was returned, or 0 otherwise. The following two integers |
-** are the values returned via the output paramaters by wal_checkpoint_v2() - |
+** are the values returned via the output parameters by wal_checkpoint_v2() - |
** the number of frames in the log and the number of frames in the log |
** that have been checkpointed. |
*/ |
@@ -5302,7 +5797,7 @@ static void xLogcallback(void *unused, int err, char *zMsg){ |
Tcl_Obj *pNew = Tcl_DuplicateObj(logcallback.pObj); |
Tcl_IncrRefCount(pNew); |
Tcl_ListObjAppendElement( |
- 0, pNew, Tcl_NewStringObj(sqlite3TestErrorName(err), -1) |
+ 0, pNew, Tcl_NewStringObj(sqlite3ErrName(err), -1) |
); |
Tcl_ListObjAppendElement(0, pNew, Tcl_NewStringObj(zMsg, -1)); |
Tcl_EvalObjEx(logcallback.pInterp, pNew, TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT); |
@@ -5417,91 +5912,740 @@ static int test_print_eqp( |
} |
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; |
rc = printExplainQueryPlan(pStmt); |
+ /* This is needed on Windows so that a test case using this |
+ ** function can open a read pipe and get the output of |
+ ** printExplainQueryPlan() immediately. |
+ */ |
+ fflush(stdout); |
Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0); |
return TCL_OK; |
} |
#endif /* SQLITE_OMIT_EXPLAIN */ |
/* |
-** optimization_control DB OPT BOOLEAN |
-** |
-** Enable or disable query optimizations using the sqlite3_test_control() |
-** interface. Disable if BOOLEAN is false and enable if BOOLEAN is true. |
-** OPT is the name of the optimization to be disabled. |
+** sqlite3_test_control VERB ARGS... |
*/ |
-static int optimization_control( |
+static int test_test_control( |
void * clientData, |
Tcl_Interp *interp, |
int objc, |
Tcl_Obj *CONST objv[] |
){ |
- int i; |
- sqlite3 *db; |
- const char *zOpt; |
- int onoff; |
- int mask; |
- static const struct { |
- const char *zOptName; |
- int mask; |
- } aOpt[] = { |
- { "all", SQLITE_OptMask }, |
- { "query-flattener", SQLITE_QueryFlattener }, |
- { "column-cache", SQLITE_ColumnCache }, |
- { "index-sort", SQLITE_IndexSort }, |
- { "index-search", SQLITE_IndexSearch }, |
- { "index-cover", SQLITE_IndexCover }, |
- { "groupby-order", SQLITE_GroupByOrder }, |
- { "factor-constants", SQLITE_FactorOutConst }, |
+ struct Verb { |
+ const char *zName; |
+ int i; |
+ } aVerb[] = { |
+ { "SQLITE_TESTCTRL_LOCALTIME_FAULT", SQLITE_TESTCTRL_LOCALTIME_FAULT }, |
+ { "SQLITE_TESTCTRL_SORTER_MMAP", SQLITE_TESTCTRL_SORTER_MMAP }, |
}; |
+ int iVerb; |
+ int iFlag; |
+ int rc; |
- if( objc!=4 ){ |
- Tcl_WrongNumArgs(interp, 1, objv, "DB OPT BOOLEAN"); |
+ if( objc<2 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, "VERB ARGS..."); |
return TCL_ERROR; |
} |
- if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; |
- if( Tcl_GetBooleanFromObj(interp, objv[3], &onoff) ) return TCL_ERROR; |
- zOpt = Tcl_GetString(objv[2]); |
- for(i=0; i<sizeof(aOpt)/sizeof(aOpt[0]); i++){ |
- if( strcmp(zOpt, aOpt[i].zOptName)==0 ){ |
- mask = aOpt[i].mask; |
+ |
+ rc = Tcl_GetIndexFromObjStruct( |
+ interp, objv[1], aVerb, sizeof(aVerb[0]), "VERB", 0, &iVerb |
+ ); |
+ if( rc!=TCL_OK ) return rc; |
+ |
+ iFlag = aVerb[iVerb].i; |
+ switch( iFlag ){ |
+ case SQLITE_TESTCTRL_LOCALTIME_FAULT: { |
+ int val; |
+ if( objc!=3 ){ |
+ Tcl_WrongNumArgs(interp, 2, objv, "ONOFF"); |
+ return TCL_ERROR; |
+ } |
+ if( Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR; |
+ sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, val); |
break; |
} |
- } |
- if( onoff ) mask = ~mask; |
- if( i>=sizeof(aOpt)/sizeof(aOpt[0]) ){ |
- Tcl_AppendResult(interp, "unknown optimization - should be one of:", |
- (char*)0); |
- for(i=0; i<sizeof(aOpt)/sizeof(aOpt[0]); i++){ |
- Tcl_AppendResult(interp, " ", aOpt[i].zOptName); |
+ |
+ case SQLITE_TESTCTRL_SORTER_MMAP: { |
+ int val; |
+ sqlite3 *db; |
+ if( objc!=4 ){ |
+ Tcl_WrongNumArgs(interp, 2, objv, "DB LIMIT"); |
+ return TCL_ERROR; |
+ } |
+ if( getDbPointer(interp, Tcl_GetString(objv[2]), &db) ) return TCL_ERROR; |
+ if( Tcl_GetIntFromObj(interp, objv[3], &val) ) return TCL_ERROR; |
+ sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, val); |
+ break; |
} |
- return TCL_ERROR; |
} |
- sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, db, mask); |
+ |
+ Tcl_ResetResult(interp); |
+ return TCL_OK; |
+} |
+ |
+#if SQLITE_OS_UNIX |
+#include <sys/time.h> |
+#include <sys/resource.h> |
+ |
+static int test_getrusage( |
+ void * clientData, |
+ Tcl_Interp *interp, |
+ int objc, |
+ Tcl_Obj *CONST objv[] |
+){ |
+ char buf[1024]; |
+ struct rusage r; |
+ memset(&r, 0, sizeof(r)); |
+ getrusage(RUSAGE_SELF, &r); |
+ |
+ sprintf(buf, "ru_utime=%d.%06d ru_stime=%d.%06d ru_minflt=%d ru_majflt=%d", |
+ (int)r.ru_utime.tv_sec, (int)r.ru_utime.tv_usec, |
+ (int)r.ru_stime.tv_sec, (int)r.ru_stime.tv_usec, |
+ (int)r.ru_minflt, (int)r.ru_majflt |
+ ); |
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, -1)); |
return TCL_OK; |
} |
+#endif |
+#if SQLITE_OS_WIN |
/* |
-** Register commands with the TCL interpreter. |
+** Information passed from the main thread into the windows file locker |
+** background thread. |
*/ |
-int Sqlitetest1_Init(Tcl_Interp *interp){ |
- extern int sqlite3_search_count; |
- extern int sqlite3_found_count; |
- extern int sqlite3_interrupt_count; |
- extern int sqlite3_open_file_count; |
- extern int sqlite3_sort_count; |
- extern int sqlite3_current_time; |
-#if SQLITE_OS_UNIX && defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE |
- extern int sqlite3_hostid_num; |
+struct win32FileLocker { |
+ char *evName; /* Name of event to signal thread startup */ |
+ HANDLE h; /* Handle of the file to be locked */ |
+ int delay1; /* Delay before locking */ |
+ int delay2; /* Delay before unlocking */ |
+ int ok; /* Finished ok */ |
+ int err; /* True if an error occurs */ |
+}; |
#endif |
- extern int sqlite3_max_blobsize; |
- extern int sqlite3BtreeSharedCacheReport(void*, |
- Tcl_Interp*,int,Tcl_Obj*CONST*); |
- static struct { |
- char *zName; |
- Tcl_CmdProc *xProc; |
- } aCmd[] = { |
- { "db_enter", (Tcl_CmdProc*)db_enter }, |
- { "db_leave", (Tcl_CmdProc*)db_leave }, |
+ |
+ |
+#if SQLITE_OS_WIN |
+#include <process.h> |
+/* |
+** The background thread that does file locking. |
+*/ |
+static void win32_file_locker(void *pAppData){ |
+ struct win32FileLocker *p = (struct win32FileLocker*)pAppData; |
+ if( p->evName ){ |
+ HANDLE ev = OpenEvent(EVENT_MODIFY_STATE, FALSE, p->evName); |
+ if ( ev ){ |
+ SetEvent(ev); |
+ CloseHandle(ev); |
+ } |
+ } |
+ if( p->delay1 ) Sleep(p->delay1); |
+ if( LockFile(p->h, 0, 0, 100000000, 0) ){ |
+ Sleep(p->delay2); |
+ UnlockFile(p->h, 0, 0, 100000000, 0); |
+ p->ok = 1; |
+ }else{ |
+ p->err = 1; |
+ } |
+ CloseHandle(p->h); |
+ p->h = 0; |
+ p->delay1 = 0; |
+ p->delay2 = 0; |
+} |
+#endif |
+ |
+#if SQLITE_OS_WIN |
+/* |
+** lock_win32_file FILENAME DELAY1 DELAY2 |
+** |
+** Get an exclusive manditory lock on file for DELAY2 milliseconds. |
+** Wait DELAY1 milliseconds before acquiring the lock. |
+*/ |
+static int win32_file_lock( |
+ void * clientData, |
+ Tcl_Interp *interp, |
+ int objc, |
+ Tcl_Obj *CONST objv[] |
+){ |
+ static struct win32FileLocker x = { "win32_file_lock", 0, 0, 0, 0, 0 }; |
+ const char *zFilename; |
+ char zBuf[200]; |
+ int retry = 0; |
+ HANDLE ev; |
+ DWORD wResult; |
+ |
+ if( objc!=4 && objc!=1 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, "FILENAME DELAY1 DELAY2"); |
+ return TCL_ERROR; |
+ } |
+ if( objc==1 ){ |
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%d %d %d %d %d", |
+ x.ok, x.err, x.delay1, x.delay2, x.h); |
+ Tcl_AppendResult(interp, zBuf, (char*)0); |
+ return TCL_OK; |
+ } |
+ while( x.h && retry<30 ){ |
+ retry++; |
+ Sleep(100); |
+ } |
+ if( x.h ){ |
+ Tcl_AppendResult(interp, "busy", (char*)0); |
+ return TCL_ERROR; |
+ } |
+ if( Tcl_GetIntFromObj(interp, objv[2], &x.delay1) ) return TCL_ERROR; |
+ if( Tcl_GetIntFromObj(interp, objv[3], &x.delay2) ) return TCL_ERROR; |
+ zFilename = Tcl_GetString(objv[1]); |
+ x.h = CreateFile(zFilename, GENERIC_READ|GENERIC_WRITE, |
+ FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_ALWAYS, |
+ FILE_ATTRIBUTE_NORMAL, 0); |
+ if( !x.h ){ |
+ Tcl_AppendResult(interp, "cannot open file: ", zFilename, (char*)0); |
+ return TCL_ERROR; |
+ } |
+ ev = CreateEvent(NULL, TRUE, FALSE, x.evName); |
+ if ( !ev ){ |
+ Tcl_AppendResult(interp, "cannot create event: ", x.evName, (char*)0); |
+ return TCL_ERROR; |
+ } |
+ _beginthread(win32_file_locker, 0, (void*)&x); |
+ Sleep(0); |
+ if ( (wResult = WaitForSingleObject(ev, 10000))!=WAIT_OBJECT_0 ){ |
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "0x%x", wResult); |
+ Tcl_AppendResult(interp, "wait failed: ", zBuf, (char*)0); |
+ CloseHandle(ev); |
+ return TCL_ERROR; |
+ } |
+ CloseHandle(ev); |
+ return TCL_OK; |
+} |
+ |
+/* |
+** exists_win32_path PATH |
+** |
+** Returns non-zero if the specified path exists, whose fully qualified name |
+** may exceed 260 characters if it is prefixed with "\\?\". |
+*/ |
+static int win32_exists_path( |
+ void *clientData, |
+ Tcl_Interp *interp, |
+ int objc, |
+ Tcl_Obj *CONST objv[] |
+){ |
+ if( objc!=2 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, "PATH"); |
+ return TCL_ERROR; |
+ } |
+ Tcl_SetObjResult(interp, Tcl_NewBooleanObj( |
+ GetFileAttributesW( Tcl_GetUnicode(objv[1]))!=INVALID_FILE_ATTRIBUTES )); |
+ return TCL_OK; |
+} |
+ |
+/* |
+** find_win32_file PATTERN |
+** |
+** Returns a list of entries in a directory that match the specified pattern, |
+** whose fully qualified name may exceed 248 characters if it is prefixed with |
+** "\\?\". |
+*/ |
+static int win32_find_file( |
+ void *clientData, |
+ Tcl_Interp *interp, |
+ int objc, |
+ Tcl_Obj *CONST objv[] |
+){ |
+ HANDLE hFindFile = INVALID_HANDLE_VALUE; |
+ WIN32_FIND_DATAW findData; |
+ Tcl_Obj *listObj; |
+ DWORD lastErrno; |
+ if( objc!=2 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, "PATTERN"); |
+ return TCL_ERROR; |
+ } |
+ hFindFile = FindFirstFileW(Tcl_GetUnicode(objv[1]), &findData); |
+ if( hFindFile==INVALID_HANDLE_VALUE ){ |
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError())); |
+ return TCL_ERROR; |
+ } |
+ listObj = Tcl_NewObj(); |
+ Tcl_IncrRefCount(listObj); |
+ do { |
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewUnicodeObj( |
+ findData.cFileName, -1)); |
+ Tcl_ListObjAppendElement(interp, listObj, Tcl_NewWideIntObj( |
+ findData.dwFileAttributes)); |
+ } while( FindNextFileW(hFindFile, &findData) ); |
+ lastErrno = GetLastError(); |
+ if( lastErrno!=NO_ERROR && lastErrno!=ERROR_NO_MORE_FILES ){ |
+ FindClose(hFindFile); |
+ Tcl_DecrRefCount(listObj); |
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError())); |
+ return TCL_ERROR; |
+ } |
+ FindClose(hFindFile); |
+ Tcl_SetObjResult(interp, listObj); |
+ return TCL_OK; |
+} |
+ |
+/* |
+** delete_win32_file FILENAME |
+** |
+** Deletes the specified file, whose fully qualified name may exceed 260 |
+** characters if it is prefixed with "\\?\". |
+*/ |
+static int win32_delete_file( |
+ void *clientData, |
+ Tcl_Interp *interp, |
+ int objc, |
+ Tcl_Obj *CONST objv[] |
+){ |
+ if( objc!=2 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, "FILENAME"); |
+ return TCL_ERROR; |
+ } |
+ if( !DeleteFileW(Tcl_GetUnicode(objv[1])) ){ |
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError())); |
+ return TCL_ERROR; |
+ } |
+ Tcl_ResetResult(interp); |
+ return TCL_OK; |
+} |
+ |
+/* |
+** make_win32_dir DIRECTORY |
+** |
+** Creates the specified directory, whose fully qualified name may exceed 248 |
+** characters if it is prefixed with "\\?\". |
+*/ |
+static int win32_mkdir( |
+ void *clientData, |
+ Tcl_Interp *interp, |
+ int objc, |
+ Tcl_Obj *CONST objv[] |
+){ |
+ if( objc!=2 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, "DIRECTORY"); |
+ return TCL_ERROR; |
+ } |
+ if( !CreateDirectoryW(Tcl_GetUnicode(objv[1]), NULL) ){ |
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError())); |
+ return TCL_ERROR; |
+ } |
+ Tcl_ResetResult(interp); |
+ return TCL_OK; |
+} |
+ |
+/* |
+** remove_win32_dir DIRECTORY |
+** |
+** Removes the specified directory, whose fully qualified name may exceed 248 |
+** characters if it is prefixed with "\\?\". |
+*/ |
+static int win32_rmdir( |
+ void *clientData, |
+ Tcl_Interp *interp, |
+ int objc, |
+ Tcl_Obj *CONST objv[] |
+){ |
+ if( objc!=2 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, "DIRECTORY"); |
+ return TCL_ERROR; |
+ } |
+ if( !RemoveDirectoryW(Tcl_GetUnicode(objv[1])) ){ |
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError())); |
+ return TCL_ERROR; |
+ } |
+ Tcl_ResetResult(interp); |
+ return TCL_OK; |
+} |
+#endif |
+ |
+ |
+/* |
+** optimization_control DB OPT BOOLEAN |
+** |
+** Enable or disable query optimizations using the sqlite3_test_control() |
+** interface. Disable if BOOLEAN is false and enable if BOOLEAN is true. |
+** OPT is the name of the optimization to be disabled. |
+*/ |
+static int optimization_control( |
+ void * clientData, |
+ Tcl_Interp *interp, |
+ int objc, |
+ Tcl_Obj *CONST objv[] |
+){ |
+ int i; |
+ sqlite3 *db; |
+ const char *zOpt; |
+ int onoff; |
+ int mask = 0; |
+ static const struct { |
+ const char *zOptName; |
+ int mask; |
+ } aOpt[] = { |
+ { "all", SQLITE_AllOpts }, |
+ { "none", 0 }, |
+ { "query-flattener", SQLITE_QueryFlattener }, |
+ { "column-cache", SQLITE_ColumnCache }, |
+ { "groupby-order", SQLITE_GroupByOrder }, |
+ { "factor-constants", SQLITE_FactorOutConst }, |
+ { "distinct-opt", SQLITE_DistinctOpt }, |
+ { "cover-idx-scan", SQLITE_CoverIdxScan }, |
+ { "order-by-idx-join", SQLITE_OrderByIdxJoin }, |
+ { "transitive", SQLITE_Transitive }, |
+ { "subquery-coroutine", SQLITE_SubqCoroutine }, |
+ { "omit-noop-join", SQLITE_OmitNoopJoin }, |
+ { "stat3", SQLITE_Stat3 }, |
+ }; |
+ |
+ if( objc!=4 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, "DB OPT BOOLEAN"); |
+ return TCL_ERROR; |
+ } |
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; |
+ if( Tcl_GetBooleanFromObj(interp, objv[3], &onoff) ) return TCL_ERROR; |
+ zOpt = Tcl_GetString(objv[2]); |
+ for(i=0; i<sizeof(aOpt)/sizeof(aOpt[0]); i++){ |
+ if( strcmp(zOpt, aOpt[i].zOptName)==0 ){ |
+ mask = aOpt[i].mask; |
+ break; |
+ } |
+ } |
+ if( onoff ) mask = ~mask; |
+ if( i>=sizeof(aOpt)/sizeof(aOpt[0]) ){ |
+ Tcl_AppendResult(interp, "unknown optimization - should be one of:", |
+ (char*)0); |
+ for(i=0; i<sizeof(aOpt)/sizeof(aOpt[0]); i++){ |
+ Tcl_AppendResult(interp, " ", aOpt[i].zOptName, (char*)0); |
+ } |
+ return TCL_ERROR; |
+ } |
+ sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, db, mask); |
+ return TCL_OK; |
+} |
+ |
+typedef struct sqlite3_api_routines sqlite3_api_routines; |
+/* |
+** load_static_extension DB NAME ... |
+** |
+** Load one or more statically linked extensions. |
+*/ |
+static int tclLoadStaticExtensionCmd( |
+ void * clientData, |
+ Tcl_Interp *interp, |
+ int objc, |
+ Tcl_Obj *CONST objv[] |
+){ |
+ 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_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*); |
+ extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*); |
+ extern int sqlite3_percentile_init(sqlite3*,char**,const sqlite3_api_routines*); |
+ extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*); |
+ extern int sqlite3_spellfix_init(sqlite3*,char**,const sqlite3_api_routines*); |
+ extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*); |
+ extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*); |
+ static const struct { |
+ const char *zExtName; |
+ int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*); |
+ } aExtension[] = { |
+ { "amatch", sqlite3_amatch_init }, |
+ { "closure", sqlite3_closure_init }, |
+ { "fileio", sqlite3_fileio_init }, |
+ { "fuzzer", sqlite3_fuzzer_init }, |
+ { "ieee754", sqlite3_ieee_init }, |
+ { "nextchar", sqlite3_nextchar_init }, |
+ { "percentile", sqlite3_percentile_init }, |
+ { "regexp", sqlite3_regexp_init }, |
+ { "spellfix", sqlite3_spellfix_init }, |
+ { "totype", sqlite3_totype_init }, |
+ { "wholenumber", sqlite3_wholenumber_init }, |
+ }; |
+ sqlite3 *db; |
+ const char *zName; |
+ int i, j, rc; |
+ char *zErrMsg = 0; |
+ if( objc<3 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, "DB NAME ..."); |
+ return TCL_ERROR; |
+ } |
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; |
+ for(j=2; j<objc; j++){ |
+ zName = Tcl_GetString(objv[j]); |
+ for(i=0; i<ArraySize(aExtension); i++){ |
+ if( strcmp(zName, aExtension[i].zExtName)==0 ) break; |
+ } |
+ if( i>=ArraySize(aExtension) ){ |
+ Tcl_AppendResult(interp, "no such extension: ", zName, (char*)0); |
+ return TCL_ERROR; |
+ } |
+ rc = aExtension[i].pInit(db, &zErrMsg, 0); |
+ if( rc!=SQLITE_OK || zErrMsg ){ |
+ Tcl_AppendResult(interp, "initialization of ", zName, " failed: ", zErrMsg, |
+ (char*)0); |
+ sqlite3_free(zErrMsg); |
+ return TCL_ERROR; |
+ } |
+ } |
+ return TCL_OK; |
+} |
+ |
+/* |
+** sorter_test_fakeheap BOOL |
+** |
+*/ |
+static int sorter_test_fakeheap( |
+ void * clientData, |
+ Tcl_Interp *interp, |
+ int objc, |
+ Tcl_Obj *CONST objv[] |
+){ |
+ int bArg; |
+ if( objc!=2 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, "BOOL"); |
+ return TCL_ERROR; |
+ } |
+ |
+ if( Tcl_GetBooleanFromObj(interp, objv[1], &bArg) ){ |
+ return TCL_ERROR; |
+ } |
+ |
+ if( bArg ){ |
+ if( sqlite3GlobalConfig.pHeap==0 ){ |
+ sqlite3GlobalConfig.pHeap = SQLITE_INT_TO_PTR(-1); |
+ } |
+ }else{ |
+ if( sqlite3GlobalConfig.pHeap==SQLITE_INT_TO_PTR(-1) ){ |
+ sqlite3GlobalConfig.pHeap = 0; |
+ } |
+ } |
+ |
+ Tcl_ResetResult(interp); |
+ return TCL_OK; |
+} |
+ |
+/* |
+** sorter_test_sort4_helper DB SQL1 NSTEP SQL2 |
+** |
+** Compile SQL statement $SQL1 and step it $NSTEP times. For each row, |
+** check that the leftmost and rightmost columns returned are both integers, |
+** and that both contain the same value. |
+** |
+** Then execute statement $SQL2. Check that the statement returns the same |
+** set of integers in the same order as in the previous step (using $SQL1). |
+*/ |
+static int sorter_test_sort4_helper( |
+ void * clientData, |
+ Tcl_Interp *interp, |
+ int objc, |
+ Tcl_Obj *CONST objv[] |
+){ |
+ const char *zSql1; |
+ const char *zSql2; |
+ int nStep; |
+ int iStep; |
+ int iCksum1 = 0; |
+ int iCksum2 = 0; |
+ int rc; |
+ int iB; |
+ sqlite3 *db; |
+ sqlite3_stmt *pStmt; |
+ |
+ if( objc!=5 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, "DB SQL1 NSTEP SQL2"); |
+ return TCL_ERROR; |
+ } |
+ |
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; |
+ zSql1 = Tcl_GetString(objv[2]); |
+ if( Tcl_GetIntFromObj(interp, objv[3], &nStep) ) return TCL_ERROR; |
+ zSql2 = Tcl_GetString(objv[4]); |
+ |
+ rc = sqlite3_prepare_v2(db, zSql1, -1, &pStmt, 0); |
+ if( rc!=SQLITE_OK ) goto sql_error; |
+ |
+ iB = sqlite3_column_count(pStmt)-1; |
+ for(iStep=0; iStep<nStep && SQLITE_ROW==sqlite3_step(pStmt); iStep++){ |
+ int a = sqlite3_column_int(pStmt, 0); |
+ if( a!=sqlite3_column_int(pStmt, iB) ){ |
+ Tcl_AppendResult(interp, "data error: (a!=b)", 0); |
+ return TCL_ERROR; |
+ } |
+ |
+ iCksum1 += (iCksum1 << 3) + a; |
+ } |
+ rc = sqlite3_finalize(pStmt); |
+ if( rc!=SQLITE_OK ) goto sql_error; |
+ |
+ rc = sqlite3_prepare_v2(db, zSql2, -1, &pStmt, 0); |
+ if( rc!=SQLITE_OK ) goto sql_error; |
+ for(iStep=0; SQLITE_ROW==sqlite3_step(pStmt); iStep++){ |
+ int a = sqlite3_column_int(pStmt, 0); |
+ iCksum2 += (iCksum2 << 3) + a; |
+ } |
+ rc = sqlite3_finalize(pStmt); |
+ if( rc!=SQLITE_OK ) goto sql_error; |
+ |
+ if( iCksum1!=iCksum2 ){ |
+ Tcl_AppendResult(interp, "checksum mismatch", 0); |
+ return TCL_ERROR; |
+ } |
+ |
+ return TCL_OK; |
+ sql_error: |
+ Tcl_AppendResult(interp, "sql error: ", sqlite3_errmsg(db), 0); |
+ return TCL_ERROR; |
+} |
+ |
+ |
+#ifdef SQLITE_USER_AUTHENTICATION |
+#include "sqlite3userauth.h" |
+/* |
+** tclcmd: sqlite3_user_authenticate DB USERNAME PASSWORD |
+*/ |
+static int test_user_authenticate( |
+ ClientData clientData, /* Unused */ |
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
+ int objc, /* Number of arguments */ |
+ Tcl_Obj *CONST objv[] /* Command arguments */ |
+){ |
+ char *zUser = 0; |
+ char *zPasswd = 0; |
+ int nPasswd = 0; |
+ sqlite3 *db; |
+ int rc; |
+ |
+ if( objc!=4 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD"); |
+ return TCL_ERROR; |
+ } |
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ |
+ return TCL_ERROR; |
+ } |
+ zUser = Tcl_GetString(objv[2]); |
+ zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd); |
+ rc = sqlite3_user_authenticate(db, zUser, zPasswd, nPasswd); |
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); |
+ return TCL_OK; |
+} |
+#endif /* SQLITE_USER_AUTHENTICATION */ |
+ |
+#ifdef SQLITE_USER_AUTHENTICATION |
+/* |
+** tclcmd: sqlite3_user_add DB USERNAME PASSWORD ISADMIN |
+*/ |
+static int test_user_add( |
+ ClientData clientData, /* Unused */ |
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
+ int objc, /* Number of arguments */ |
+ Tcl_Obj *CONST objv[] /* Command arguments */ |
+){ |
+ char *zUser = 0; |
+ char *zPasswd = 0; |
+ int nPasswd = 0; |
+ int isAdmin = 0; |
+ sqlite3 *db; |
+ int rc; |
+ |
+ if( objc!=5 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD ISADMIN"); |
+ return TCL_ERROR; |
+ } |
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ |
+ return TCL_ERROR; |
+ } |
+ zUser = Tcl_GetString(objv[2]); |
+ zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd); |
+ Tcl_GetBooleanFromObj(interp, objv[4], &isAdmin); |
+ rc = sqlite3_user_add(db, zUser, zPasswd, nPasswd, isAdmin); |
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); |
+ return TCL_OK; |
+} |
+#endif /* SQLITE_USER_AUTHENTICATION */ |
+ |
+#ifdef SQLITE_USER_AUTHENTICATION |
+/* |
+** tclcmd: sqlite3_user_change DB USERNAME PASSWORD ISADMIN |
+*/ |
+static int test_user_change( |
+ ClientData clientData, /* Unused */ |
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
+ int objc, /* Number of arguments */ |
+ Tcl_Obj *CONST objv[] /* Command arguments */ |
+){ |
+ char *zUser = 0; |
+ char *zPasswd = 0; |
+ int nPasswd = 0; |
+ int isAdmin = 0; |
+ sqlite3 *db; |
+ int rc; |
+ |
+ if( objc!=5 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD ISADMIN"); |
+ return TCL_ERROR; |
+ } |
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ |
+ return TCL_ERROR; |
+ } |
+ zUser = Tcl_GetString(objv[2]); |
+ zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd); |
+ Tcl_GetBooleanFromObj(interp, objv[4], &isAdmin); |
+ rc = sqlite3_user_change(db, zUser, zPasswd, nPasswd, isAdmin); |
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); |
+ return TCL_OK; |
+} |
+#endif /* SQLITE_USER_AUTHENTICATION */ |
+ |
+#ifdef SQLITE_USER_AUTHENTICATION |
+/* |
+** tclcmd: sqlite3_user_delete DB USERNAME |
+*/ |
+static int test_user_delete( |
+ ClientData clientData, /* Unused */ |
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ |
+ int objc, /* Number of arguments */ |
+ Tcl_Obj *CONST objv[] /* Command arguments */ |
+){ |
+ char *zUser = 0; |
+ sqlite3 *db; |
+ int rc; |
+ |
+ if( objc!=3 ){ |
+ Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME"); |
+ return TCL_ERROR; |
+ } |
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ |
+ return TCL_ERROR; |
+ } |
+ zUser = Tcl_GetString(objv[2]); |
+ rc = sqlite3_user_delete(db, zUser); |
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); |
+ return TCL_OK; |
+} |
+#endif /* SQLITE_USER_AUTHENTICATION */ |
+ |
+/* |
+** Register commands with the TCL interpreter. |
+*/ |
+int Sqlitetest1_Init(Tcl_Interp *interp){ |
+ extern int sqlite3_search_count; |
+ extern int sqlite3_found_count; |
+ extern int sqlite3_interrupt_count; |
+ extern int sqlite3_open_file_count; |
+ extern int sqlite3_sort_count; |
+ extern int sqlite3_current_time; |
+#if SQLITE_OS_UNIX && defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE |
+ extern int sqlite3_hostid_num; |
+#endif |
+ extern int sqlite3_max_blobsize; |
+ extern int sqlite3BtreeSharedCacheReport(void*, |
+ Tcl_Interp*,int,Tcl_Obj*CONST*); |
+ static struct { |
+ char *zName; |
+ Tcl_CmdProc *xProc; |
+ } aCmd[] = { |
+ { "db_enter", (Tcl_CmdProc*)db_enter }, |
+ { "db_leave", (Tcl_CmdProc*)db_leave }, |
{ "sqlite3_mprintf_int", (Tcl_CmdProc*)sqlite3_mprintf_int }, |
{ "sqlite3_mprintf_int64", (Tcl_CmdProc*)sqlite3_mprintf_int64 }, |
{ "sqlite3_mprintf_long", (Tcl_CmdProc*)sqlite3_mprintf_long }, |
@@ -5523,6 +6667,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ |
{ "sqlite3_get_table_printf", (Tcl_CmdProc*)test_get_table_printf }, |
#endif |
{ "sqlite3_close", (Tcl_CmdProc*)sqlite_test_close }, |
+ { "sqlite3_close_v2", (Tcl_CmdProc*)sqlite_test_close_v2 }, |
{ "sqlite3_create_function", (Tcl_CmdProc*)test_create_function }, |
{ "sqlite3_create_aggregate", (Tcl_CmdProc*)test_create_aggregate }, |
{ "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func }, |
@@ -5540,6 +6685,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ |
{ "sqlite3_busy_timeout", (Tcl_CmdProc*)test_busy_timeout }, |
{ "printf", (Tcl_CmdProc*)test_printf }, |
{ "sqlite3IoTrace", (Tcl_CmdProc*)test_io_trace }, |
+ { "clang_sanitize_address", (Tcl_CmdProc*)clang_sanitize_address }, |
}; |
static struct { |
char *zName; |
@@ -5566,6 +6712,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ |
{ "sqlite3_errmsg16", test_errmsg16 ,0 }, |
{ "sqlite3_open", test_open ,0 }, |
{ "sqlite3_open16", test_open16 ,0 }, |
+ { "sqlite3_open_v2", test_open_v2 ,0 }, |
{ "sqlite3_complete16", test_complete16 ,0 }, |
{ "sqlite3_prepare", test_prepare ,0 }, |
@@ -5583,8 +6730,13 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ |
{ "sqlite3_sql", test_sql ,0 }, |
{ "sqlite3_next_stmt", test_next_stmt ,0 }, |
{ "sqlite3_stmt_readonly", test_stmt_readonly ,0 }, |
+ { "sqlite3_stmt_busy", test_stmt_busy ,0 }, |
+ { "uses_stmt_journal", uses_stmt_journal ,0 }, |
{ "sqlite3_release_memory", test_release_memory, 0}, |
+ { "sqlite3_db_release_memory", test_db_release_memory, 0}, |
+ { "sqlite3_db_filename", test_db_filename, 0}, |
+ { "sqlite3_db_readonly", test_db_readonly, 0}, |
{ "sqlite3_soft_heap_limit", test_soft_heap_limit, 0}, |
{ "sqlite3_thread_cleanup", test_thread_cleanup, 0}, |
{ "sqlite3_pager_refcounts", test_pager_refcounts, 0}, |
@@ -5597,7 +6749,17 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ |
{ "save_prng_state", save_prng_state, 0 }, |
{ "restore_prng_state", restore_prng_state, 0 }, |
{ "reset_prng_state", reset_prng_state, 0 }, |
+ { "database_never_corrupt", database_never_corrupt, 0}, |
+ { "database_may_be_corrupt", database_may_be_corrupt, 0}, |
{ "optimization_control", optimization_control,0}, |
+#if SQLITE_OS_WIN |
+ { "lock_win32_file", win32_file_lock, 0 }, |
+ { "exists_win32_path", win32_exists_path, 0 }, |
+ { "find_win32_file", win32_find_file, 0 }, |
+ { "delete_win32_file", win32_delete_file, 0 }, |
+ { "make_win32_dir", win32_mkdir, 0 }, |
+ { "remove_win32_dir", win32_rmdir, 0 }, |
+#endif |
{ "tcl_objproc", runAsObjProc, 0 }, |
/* sqlite3_column_*() API */ |
@@ -5630,7 +6792,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ |
#endif |
#ifdef SQLITE_ENABLE_COLUMN_METADATA |
{"sqlite3_column_database_name16", |
- test_stmt_utf16, sqlite3_column_database_name16}, |
+ test_stmt_utf16, (void*)sqlite3_column_database_name16}, |
{"sqlite3_column_table_name16", test_stmt_utf16, (void*)sqlite3_column_table_name16}, |
{"sqlite3_column_origin_name16", test_stmt_utf16, (void*)sqlite3_column_origin_name16}, |
#endif |
@@ -5646,7 +6808,15 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ |
{ "file_control_lasterrno_test", file_control_lasterrno_test, 0 }, |
{ "file_control_lockproxy_test", file_control_lockproxy_test, 0 }, |
{ "file_control_chunksize_test", file_control_chunksize_test, 0 }, |
- { "file_control_sizehint_test", file_control_sizehint_test, 0 }, |
+ { "file_control_sizehint_test", file_control_sizehint_test, 0 }, |
+#if SQLITE_OS_WIN |
+ { "file_control_win32_av_retry", file_control_win32_av_retry, 0 }, |
+ { "file_control_win32_set_handle", file_control_win32_set_handle, 0 }, |
+#endif |
+ { "file_control_persist_wal", file_control_persist_wal, 0 }, |
+ { "file_control_powersafe_overwrite",file_control_powersafe_overwrite,0}, |
+ { "file_control_vfsname", file_control_vfsname, 0 }, |
+ { "file_control_tempfilename", file_control_tempfilename, 0 }, |
{ "sqlite3_vfs_list", vfs_list, 0 }, |
{ "sqlite3_create_function_v2", test_create_function_v2, 0 }, |
@@ -5655,6 +6825,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ |
{ "add_test_collate", test_collate, 0 }, |
{ "add_test_collate_needed", test_collate_needed, 0 }, |
{ "add_test_function", test_function, 0 }, |
+ { "add_test_utf16bin_collate", test_utf16bin_collate, 0 }, |
#endif |
{ "sqlite3_test_errstr", test_errstr, 0 }, |
{ "tcl_variable_type", tcl_variable_type, 0 }, |
@@ -5683,6 +6854,20 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ |
#ifndef SQLITE_OMIT_EXPLAIN |
{ "print_explain_query_plan", test_print_eqp, 0 }, |
#endif |
+ { "sqlite3_test_control", test_test_control }, |
+#if SQLITE_OS_UNIX |
+ { "getrusage", test_getrusage }, |
+#endif |
+ { "load_static_extension", tclLoadStaticExtensionCmd }, |
+ { "sorter_test_fakeheap", sorter_test_fakeheap }, |
+ { "sorter_test_sort4_helper", sorter_test_sort4_helper }, |
+#ifdef SQLITE_USER_AUTHENTICATION |
+ { "sqlite3_user_authenticate", test_user_authenticate, 0 }, |
+ { "sqlite3_user_add", test_user_add, 0 }, |
+ { "sqlite3_user_change", test_user_change, 0 }, |
+ { "sqlite3_user_delete", test_user_delete, 0 }, |
+#endif |
+ |
}; |
static int bitmask_size = sizeof(Bitmask)*8; |
int i; |
@@ -5694,17 +6879,14 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ |
extern int sqlite3_pager_writedb_count; |
extern int sqlite3_pager_writej_count; |
#if SQLITE_OS_WIN |
- extern int sqlite3_os_type; |
+ extern LONG volatile sqlite3_os_type; |
#endif |
#ifdef SQLITE_DEBUG |
extern int sqlite3WhereTrace; |
extern int sqlite3OSTrace; |
- extern int sqlite3VdbeAddopTrace; |
extern int sqlite3WalTrace; |
#endif |
#ifdef SQLITE_TEST |
- extern char sqlite3_query_plan[]; |
- static char *query_plan = sqlite3_query_plan; |
#ifdef SQLITE_ENABLE_FTS3 |
extern int sqlite3_fts3_enable_parentheses; |
#endif |
@@ -5755,15 +6937,16 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ |
#endif |
#if SQLITE_OS_WIN |
Tcl_LinkVar(interp, "sqlite_os_type", |
- (char*)&sqlite3_os_type, TCL_LINK_INT); |
+ (char*)&sqlite3_os_type, TCL_LINK_LONG); |
#endif |
#ifdef SQLITE_TEST |
- Tcl_LinkVar(interp, "sqlite_query_plan", |
- (char*)&query_plan, TCL_LINK_STRING|TCL_LINK_READ_ONLY); |
+ { |
+ static const char *query_plan = "*** OBSOLETE VARIABLE ***"; |
+ Tcl_LinkVar(interp, "sqlite_query_plan", |
+ (char*)&query_plan, TCL_LINK_STRING|TCL_LINK_READ_ONLY); |
+ } |
#endif |
#ifdef SQLITE_DEBUG |
- Tcl_LinkVar(interp, "sqlite_addop_trace", |
- (char*)&sqlite3VdbeAddopTrace, TCL_LINK_INT); |
Tcl_LinkVar(interp, "sqlite_where_trace", |
(char*)&sqlite3WhereTrace, TCL_LINK_INT); |
Tcl_LinkVar(interp, "sqlite_os_trace", |
@@ -5783,6 +6966,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ |
(char*)&sqlite_static_bind_nbyte, TCL_LINK_INT); |
Tcl_LinkVar(interp, "sqlite_temp_directory", |
(char*)&sqlite3_temp_directory, TCL_LINK_STRING); |
+ Tcl_LinkVar(interp, "sqlite_data_directory", |
+ (char*)&sqlite3_data_directory, TCL_LINK_STRING); |
Tcl_LinkVar(interp, "bitmask_size", |
(char*)&bitmask_size, TCL_LINK_INT|TCL_LINK_READ_ONLY); |
Tcl_LinkVar(interp, "sqlite_sync_count", |