/* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the printf() interface to SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** $Id: test1.c,v 1.172 2005/12/09 14:25:08 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" #include "os.h" #include #include 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_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_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_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_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_ROW: zName = "SQLITE_ROW"; break; case SQLITE_DONE: zName = "SQLITE_DONE"; break; case SQLITE_NOTADB: zName = "SQLITE_NOTADB"; break; default: zName = "SQLITE_Unknown"; break; } return zName; } #define errorName sqlite3TestErrorName /* ** Convert an sqlite3_stmt* into an sqlite3*. This depends on the ** fact that the sqlite3* is the first field in the Vdbe structure. */ #define StmtToDb(X) sqlite3_db_handle(X) /* ** Check a return value to make sure it agrees with the results ** from sqlite3_errcode. */ int sqlite3TestErrCode(Tcl_Interp *interp, sqlite3 *db, int rc){ if( rc!=SQLITE_MISUSE && rc!=SQLITE_OK && sqlite3_errcode(db)!=rc ){ char zBuf[200]; int r2 = sqlite3_errcode(db); sprintf(zBuf, "error code %s (%d) does not match sqlite3_errcode %s (%d)", errorName(rc), rc, errorName(r2), r2); Tcl_ResetResult(interp); Tcl_AppendResult(interp, zBuf, 0); return 1; } return 0; } /* ** Decode a pointer to an sqlite3 object. */ static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){ *ppDb = (sqlite3*)sqlite3TextToPtr(zA); return TCL_OK; } /* ** Decode a pointer to an sqlite3_stmt object. */ static int getStmtPointer( Tcl_Interp *interp, const char *zArg, sqlite3_stmt **ppStmt ){ *ppStmt = (sqlite3_stmt*)sqlite3TextToPtr(zArg); return TCL_OK; } /* ** Decode a pointer to an sqlite3_stmt object. */ static int getFilePointer( Tcl_Interp *interp, const char *zArg, OsFile **ppFile ){ *ppFile = (OsFile*)sqlite3TextToPtr(zArg); return TCL_OK; } /* ** Generate a text representation of a pointer that can be understood ** by the getDbPointer and getVmPointer routines above. ** ** The problem is, on some machines (Solaris) if you do a printf with ** "%p" you cannot turn around and do a scanf with the same "%p" and ** get your pointer back. You have to prepend a "0x" before it will ** work. Or at least that is what is reported to me (drh). But this ** behavior varies from machine to machine. The solution used her is ** to test the string right after it is generated to see if it can be ** understood by scanf, and if not, try prepending an "0x" to see if ** that helps. If nothing works, a fatal error is generated. */ static int makePointerStr(Tcl_Interp *interp, char *zPtr, void *p){ sqlite3_snprintf(100, zPtr, "%p", p); return TCL_OK; } /* ** The callback routine for sqlite3_exec_printf(). */ static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){ Tcl_DString *str = (Tcl_DString*)pArg; int i; if( Tcl_DStringLength(str)==0 ){ for(i=0; inUsed + n + 2 > p->nAlloc ){ char *zNew; p->nAlloc = p->nAlloc*2 + n + 200; zNew = sqliteRealloc(p->z, p->nAlloc); if( zNew==0 ){ sqliteFree(p->z); memset(p, 0, sizeof(*p)); return; } p->z = zNew; } if( divider && p->nUsed>0 ){ p->z[p->nUsed++] = divider; } memcpy(&p->z[p->nUsed], z, n+1); p->nUsed += n; } /* ** Invoked for each callback from sqlite3ExecFunc */ static int execFuncCallback(void *pData, int argc, char **argv, char **NotUsed){ struct dstr *p = (struct dstr*)pData; int i; for(i=0; in++; } } static void countFinalize(sqlite3_context *context){ CountCtx *p; p = sqlite3_aggregate_context(context, sizeof(*p)); sqlite3_result_int(context, p ? p->n : 0); } /* ** Usage: sqlite_test_create_aggregate DB ** ** Call the sqlite3_create_function API on the given database in order ** to create a function named "x_count". This function does the same thing ** as the "md5sum" function. ** ** The original motivation for this routine was to be able to call the ** sqlite3_create_aggregate function while a query is in progress in order ** to test the SQLITE_MISUSE detection logic. */ static int test_create_aggregate( 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_create_function(db, "x_count", 0, SQLITE_UTF8, 0, 0, countStep,countFinalize); if( rc==SQLITE_OK ){ sqlite3_create_function(db, "x_count", 1, SQLITE_UTF8, 0, 0, countStep,countFinalize); } if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; return TCL_OK; } /* ** Usage: sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER ** ** Call mprintf with three integer arguments */ static int sqlite3_mprintf_int( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ int a[3], i; char *z; if( argc!=5 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FORMAT INT INT INT\"", 0); return TCL_ERROR; } for(i=2; i<5; i++){ if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; } z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]); Tcl_AppendResult(interp, z, 0); sqlite3_free(z); return TCL_OK; } /* ** If zNum represents an integer that will fit in 64-bits, then set ** *pValue to that integer and return true. Otherwise return false. */ static int sqlite3GetInt64(const char *zNum, i64 *pValue){ if( sqlite3FitsIn64Bits(zNum) ){ sqlite3atoi64(zNum, pValue); return 1; } return 0; } /* ** Usage: sqlite3_mprintf_int64 FORMAT INTEGER INTEGER INTEGER ** ** Call mprintf with three 64-bit integer arguments */ static int sqlite3_mprintf_int64( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ int i; sqlite_int64 a[3]; char *z; if( argc!=5 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FORMAT INT INT INT\"", 0); return TCL_ERROR; } for(i=2; i<5; i++){ if( !sqlite3GetInt64(argv[i], &a[i-2]) ){ Tcl_AppendResult(interp, "argument is not a valid 64-bit integer", 0); return TCL_ERROR; } } z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]); Tcl_AppendResult(interp, z, 0); sqlite3_free(z); return TCL_OK; } /* ** Usage: sqlite3_mprintf_str FORMAT INTEGER INTEGER STRING ** ** Call mprintf with two integer arguments and one string argument */ static int sqlite3_mprintf_str( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ int a[3], i; char *z; if( argc<4 || argc>5 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FORMAT INT INT ?STRING?\"", 0); return TCL_ERROR; } for(i=2; i<4; i++){ if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; } z = sqlite3_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL); Tcl_AppendResult(interp, z, 0); sqlite3_free(z); return TCL_OK; } /* ** Usage: sqlite3_mprintf_double FORMAT INTEGER INTEGER DOUBLE ** ** Call mprintf with two integer arguments and one double argument */ static int sqlite3_mprintf_double( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ int a[3], i; double r; char *z; if( argc!=5 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FORMAT INT INT DOUBLE\"", 0); return TCL_ERROR; } for(i=2; i<4; i++){ if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; } if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR; z = sqlite3_mprintf(argv[1], a[0], a[1], r); Tcl_AppendResult(interp, z, 0); sqlite3_free(z); return TCL_OK; } /* ** Usage: sqlite3_mprintf_scaled FORMAT DOUBLE DOUBLE ** ** Call mprintf with a single double argument which is the product of the ** two arguments given above. This is used to generate overflow and underflow ** doubles to test that they are converted properly. */ static int sqlite3_mprintf_scaled( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ int i; double r[2]; char *z; if( argc!=4 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FORMAT DOUBLE DOUBLE\"", 0); return TCL_ERROR; } for(i=2; i<4; i++){ if( Tcl_GetDouble(interp, argv[i], &r[i-2]) ) return TCL_ERROR; } z = sqlite3_mprintf(argv[1], r[0]*r[1]); Tcl_AppendResult(interp, z, 0); sqlite3_free(z); return TCL_OK; } /* ** Usage: sqlite3_mprintf_stronly FORMAT STRING ** ** Call mprintf with a single double argument which is the product of the ** two arguments given above. This is used to generate overflow and underflow ** doubles to test that they are converted properly. */ static int sqlite3_mprintf_stronly( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ char *z; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FORMAT STRING\"", 0); return TCL_ERROR; } z = sqlite3_mprintf(argv[1], argv[2]); Tcl_AppendResult(interp, z, 0); sqlite3_free(z); return TCL_OK; } /* ** Usage: sqlite3_mprintf_hexdouble FORMAT HEX ** ** Call mprintf with a single double argument which is derived from the ** hexadecimal encoding of an IEEE double. */ static int sqlite3_mprintf_hexdouble( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ char *z; double r; unsigned x1, x2; long long unsigned d; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " FORMAT STRING\"", 0); return TCL_ERROR; } if( sscanf(argv[2], "%08x%08x", &x2, &x1)!=2 ){ Tcl_AppendResult(interp, "2nd argument should be 16-characters of hex", 0); return TCL_ERROR; } d = x2; d = (d<<32) + x1; memcpy(&r, &d, sizeof(r)); z = sqlite3_mprintf(argv[1], r); Tcl_AppendResult(interp, z, 0); sqlite3_free(z); return TCL_OK; } /* ** Usage: sqlite_malloc_fail N ?REPEAT-INTERVAL? ** ** Rig sqliteMalloc() to fail on the N-th call and every REPEAT-INTERVAL call ** after that. If REPEAT-INTERVAL is 0 or is omitted, then only a single ** malloc will fail. If REPEAT-INTERVAL is 1 then all mallocs after the ** first failure will continue to fail on every call. If REPEAT-INTERVAL is ** 2 then every other malloc will fail. And so forth. ** ** Turn off this mechanism and reset the sqlite3Tsd()->mallocFailed variable is N==0. */ #ifdef SQLITE_MEMDEBUG static int sqlite_malloc_fail( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ int n; int rep; if( argc!=2 && argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0); return TCL_ERROR; } if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR; if( argc==3 ){ if( Tcl_GetInt(interp, argv[2], &rep) ) return TCL_ERROR; }else{ rep = 0; } sqlite3_iMallocFail = n; sqlite3_iMallocReset = rep; sqlite3Tsd()->mallocFailed = 0; return TCL_OK; } #endif /* ** Usage: sqlite_malloc_stat ** ** Return the number of prior calls to sqliteMalloc() and sqliteFree(). */ #ifdef SQLITE_MEMDEBUG static int sqlite_malloc_stat( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ char zBuf[200]; sprintf(zBuf, "%d %d %d", sqlite3_nMalloc, sqlite3_nFree, sqlite3_iMallocFail); Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; } static int sqlite_malloc_outstanding( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ extern int sqlite3OutstandingMallocs(Tcl_Interp *interp); return sqlite3OutstandingMallocs(interp); } #endif /* ** Usage: sqlite_abort ** ** Shutdown the process immediately. This is not a clean shutdown. ** This command is used to test the recoverability of a database in ** the event of a program crash. */ static int sqlite_abort( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ assert( interp==0 ); /* This will always fail */ return TCL_OK; } /* ** The following routine is a user-defined SQL function whose purpose ** is to test the sqlite_set_result() API. */ static void testFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ while( argc>=2 ){ const char *zArg0 = sqlite3_value_text(argv[0]); if( zArg0 ){ if( 0==sqlite3StrICmp(zArg0, "int") ){ sqlite3_result_int(context, sqlite3_value_int(argv[1])); }else if( sqlite3StrICmp(zArg0,"int64")==0 ){ sqlite3_result_int64(context, sqlite3_value_int64(argv[1])); }else if( sqlite3StrICmp(zArg0,"string")==0 ){ sqlite3_result_text(context, sqlite3_value_text(argv[1]), -1, SQLITE_TRANSIENT); }else if( sqlite3StrICmp(zArg0,"double")==0 ){ sqlite3_result_double(context, sqlite3_value_double(argv[1])); }else if( sqlite3StrICmp(zArg0,"null")==0 ){ sqlite3_result_null(context); }else if( sqlite3StrICmp(zArg0,"value")==0 ){ sqlite3_result_value(context, argv[sqlite3_value_int(argv[1])]); }else{ goto error_out; } }else{ goto error_out; } argc -= 2; argv += 2; } return; error_out: sqlite3_result_error(context,"first argument should be one of: " "int int64 string double null value", -1); } /* ** Usage: sqlite_register_test_function DB NAME ** ** Register the test SQL function on the database DB under the name NAME. */ static int test_register_func( 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!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB FUNCTION-NAME", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; rc = sqlite3_create_function(db, argv[2], -1, SQLITE_UTF8, 0, testFunc, 0, 0); if( rc!=0 ){ Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0); return TCL_ERROR; } if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; return TCL_OK; } /* ** Usage: sqlite3_finalize STMT ** ** Finalize a statement handle. */ static int test_finalize( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int rc; sqlite3 *db; if( objc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " ", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( pStmt ){ db = StmtToDb(pStmt); } rc = sqlite3_finalize(pStmt); Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC); if( db && sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; return TCL_OK; } /* ** Usage: sqlite3_reset STMT ** ** Reset a statement handle. */ static int test_reset( 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), " ", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; rc = sqlite3_reset(pStmt); if( pStmt && sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ){ return TCL_ERROR; } Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC); /* if( rc ){ return TCL_ERROR; } */ return TCL_OK; } /* ** Usage: sqlite3_expired STMT ** ** Return TRUE if a recompilation of the statement is recommended. */ static int test_expired( 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), " ", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; Tcl_SetObjResult(interp, Tcl_NewBooleanObj(sqlite3_expired(pStmt))); return TCL_OK; } /* ** Usage: sqlite3_transfer_bindings FROMSTMT TOSTMT ** ** Transfer all bindings from FROMSTMT over to TOSTMT */ static int test_transfer_bind( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt1, *pStmt2; if( objc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " FROM-STMT TO-STMT", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt1)) return TCL_ERROR; if( getStmtPointer(interp, Tcl_GetString(objv[2]), &pStmt2)) return TCL_ERROR; Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_transfer_bindings(pStmt1,pStmt2))); return TCL_OK; } /* ** Usage: sqlite3_changes DB ** ** Return the number of changes made to the database by the last SQL ** execution. */ static int test_changes( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; if( objc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " DB", 0); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_changes(db))); return TCL_OK; } /* ** This is the "static_bind_value" that variables are bound to when ** the FLAG option of sqlite3_bind is "static" */ static char *sqlite_static_bind_value = 0; /* ** Usage: sqlite3_bind VM IDX VALUE FLAGS ** ** Sets the value of the IDX-th occurance 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 ** "sqlite_static_bind_value". If FLAGS=="normal" then a copy ** of the VALUE is made. If FLAGS=="blob10" then a VALUE is ignored ** an a 10-byte blob "abc\000xyz\000pq" is inserted. */ static int test_bind( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite3_stmt *pStmt; int rc; int idx; if( argc!=5 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " VM IDX VALUE (null|static|normal)\"", 0); return TCL_ERROR; } if( getStmtPointer(interp, argv[1], &pStmt) ) return TCL_ERROR; if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR; if( strcmp(argv[4],"null")==0 ){ rc = sqlite3_bind_null(pStmt, idx); }else if( strcmp(argv[4],"static")==0 ){ rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0); }else if( strcmp(argv[4],"normal")==0 ){ rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, SQLITE_TRANSIENT); }else if( strcmp(argv[4],"blob10")==0 ){ rc = sqlite3_bind_text(pStmt, idx, "abc\000xyz\000pq", 10, SQLITE_STATIC); }else{ Tcl_AppendResult(interp, "4th argument should be " "\"null\" or \"static\" or \"normal\"", 0); return TCL_ERROR; } if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; if( rc ){ char zBuf[50]; sprintf(zBuf, "(%d) ", rc); Tcl_AppendResult(interp, zBuf, sqlite3ErrStr(rc), 0); return TCL_ERROR; } return TCL_OK; } #ifndef SQLITE_OMIT_UTF16 /* ** Usage: add_test_collate ** ** This function is used to test that SQLite selects the correct collation ** sequence callback when multiple versions (for different text encodings) ** are available. ** ** Calling this routine registers the collation sequence "test_collate" ** with database handle . The second argument must be a list of three ** boolean values. If the first is true, then a version of test_collate is ** registered for UTF-8, if the second is true, a version is registered for ** UTF-16le, if the third is true, a UTF-16be version is available. ** Previous versions of test_collate are deleted. ** ** The collation sequence test_collate is implemented by calling the ** following TCL script: ** ** "test_collate " ** ** The and are the two values being compared, encoded in UTF-8. ** The parameter is the encoding of the collation function that ** 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 ** interp pointer to use when evaluating the TCL script is stored in ** pTestCollateInterp. */ static Tcl_Interp* pTestCollateInterp; static int test_collate_func( void *pCtx, int nA, const void *zA, int nB, const void *zB ){ Tcl_Interp *i = pTestCollateInterp; int encin = (int)pCtx; int res; int n; sqlite3_value *pVal; Tcl_Obj *pX; pX = Tcl_NewStringObj("test_collate", -1); Tcl_IncrRefCount(pX); switch( encin ){ case SQLITE_UTF8: Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-8",-1)); break; case SQLITE_UTF16LE: Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-16LE",-1)); break; case SQLITE_UTF16BE: Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-16BE",-1)); break; default: assert(0); } pVal = sqlite3ValueNew(); sqlite3ValueSetStr(pVal, nA, zA, encin, SQLITE_STATIC); n = sqlite3_value_bytes(pVal); Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj(sqlite3_value_text(pVal),n)); sqlite3ValueSetStr(pVal, nB, zB, encin, SQLITE_STATIC); n = sqlite3_value_bytes(pVal); Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj(sqlite3_value_text(pVal),n)); sqlite3ValueFree(pVal); Tcl_EvalObjEx(i, pX, 0); Tcl_DecrRefCount(pX); Tcl_GetIntFromObj(i, Tcl_GetObjResult(i), &res); return res; } static int test_collate( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; int val; sqlite3_value *pVal; int rc; if( objc!=5 ) goto bad_args; pTestCollateInterp = interp; if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR; rc = sqlite3_create_collation(db, "test_collate", SQLITE_UTF8, (void *)SQLITE_UTF8, val?test_collate_func:0); if( rc==SQLITE_OK ){ if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &val) ) return TCL_ERROR; rc = sqlite3_create_collation(db, "test_collate", SQLITE_UTF16LE, (void *)SQLITE_UTF16LE, val?test_collate_func:0); if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[4], &val) ) return TCL_ERROR; pVal = sqlite3ValueNew(); sqlite3ValueSetStr(pVal, -1, "test_collate", SQLITE_UTF8, SQLITE_STATIC); sqlite3_create_collation16(db, sqlite3ValueText(pVal, SQLITE_UTF16NATIVE), SQLITE_UTF16BE, (void *)SQLITE_UTF16BE, val?test_collate_func:0); sqlite3ValueFree(pVal); } if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; return TCL_OK; bad_args: Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " ", 0); return TCL_ERROR; } static void test_collate_needed_cb( void *pCtx, sqlite3 *db, int eTextRep, const void *notUsed ){ int enc = db->enc; sqlite3_create_collation( db, "test_collate", db->enc, (void *)enc, test_collate_func); } /* ** Usage: add_test_collate_needed DB */ static int test_collate_needed( 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_collation_needed16(db, 0, test_collate_needed_cb); if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; return TCL_OK; bad_args: Tcl_WrongNumArgs(interp, 1, objv, "DB"); return TCL_ERROR; } #endif /* SQLITE_OMIT_UTF16 */ /* ** Usage: add_test_function ** ** This function is used to test that SQLite selects the correct user ** function callback when multiple versions (for different text encodings) ** are available. ** ** Calling this routine registers up to three versions of the user function ** "test_function" with database handle . If the second argument is ** true, then a version of test_function is registered for UTF-8, if the ** third is true, a version is registered for UTF-16le, if the fourth is ** true, a UTF-16be version is available. Previous versions of ** test_function are deleted. ** ** The user function is implemented by calling the following TCL script: ** ** "test_function " ** ** Where is one of UTF-8, UTF-16LE or UTF16BE, and is the ** single argument passed to the SQL function. The value returned by ** the TCL script is used as the return value of the SQL function. It ** is passed to SQLite using UTF-16BE for a UTF-8 test_function(), UTF-8 ** for a UTF-16LE test_function(), and UTF-16LE for an implementation that ** prefers UTF-16BE. */ #ifndef SQLITE_OMIT_UTF16 static void test_function_utf8( sqlite3_context *pCtx, int nArg, sqlite3_value **argv ){ Tcl_Interp *interp; Tcl_Obj *pX; sqlite3_value *pVal; interp = (Tcl_Interp *)sqlite3_user_data(pCtx); pX = Tcl_NewStringObj("test_function", -1); Tcl_IncrRefCount(pX); Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj("UTF-8", -1)); Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj(sqlite3_value_text(argv[0]), -1)); Tcl_EvalObjEx(interp, pX, 0); Tcl_DecrRefCount(pX); sqlite3_result_text(pCtx, Tcl_GetStringResult(interp), -1, SQLITE_TRANSIENT); pVal = sqlite3ValueNew(); sqlite3ValueSetStr(pVal, -1, Tcl_GetStringResult(interp), SQLITE_UTF8, SQLITE_STATIC); sqlite3_result_text16be(pCtx, sqlite3_value_text16be(pVal), -1, SQLITE_TRANSIENT); sqlite3ValueFree(pVal); } static void test_function_utf16le( sqlite3_context *pCtx, int nArg, sqlite3_value **argv ){ Tcl_Interp *interp; Tcl_Obj *pX; sqlite3_value *pVal; interp = (Tcl_Interp *)sqlite3_user_data(pCtx); pX = Tcl_NewStringObj("test_function", -1); Tcl_IncrRefCount(pX); Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj("UTF-16LE", -1)); Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj(sqlite3_value_text(argv[0]), -1)); Tcl_EvalObjEx(interp, pX, 0); Tcl_DecrRefCount(pX); pVal = sqlite3ValueNew(); sqlite3ValueSetStr(pVal, -1, Tcl_GetStringResult(interp), SQLITE_UTF8, SQLITE_STATIC); sqlite3_result_text(pCtx,sqlite3_value_text(pVal),-1,SQLITE_TRANSIENT); sqlite3ValueFree(pVal); } static void test_function_utf16be( sqlite3_context *pCtx, int nArg, sqlite3_value **argv ){ Tcl_Interp *interp; Tcl_Obj *pX; sqlite3_value *pVal; interp = (Tcl_Interp *)sqlite3_user_data(pCtx); pX = Tcl_NewStringObj("test_function", -1); Tcl_IncrRefCount(pX); Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj("UTF-16BE", -1)); Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj(sqlite3_value_text(argv[0]), -1)); Tcl_EvalObjEx(interp, pX, 0); Tcl_DecrRefCount(pX); pVal = sqlite3ValueNew(); sqlite3ValueSetStr(pVal, -1, Tcl_GetStringResult(interp), SQLITE_UTF8, SQLITE_STATIC); sqlite3_result_text16le(pCtx, sqlite3_value_text16le(pVal), -1, SQLITE_TRANSIENT); sqlite3ValueFree(pVal); } #endif /* SQLITE_OMIT_UTF16 */ static int test_function( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_UTF16 sqlite3 *db; int val; if( objc!=5 ) goto bad_args; if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR; if( val ){ sqlite3_create_function(db, "test_function", 1, SQLITE_UTF8, interp, test_function_utf8, 0, 0); } if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &val) ) return TCL_ERROR; if( val ){ sqlite3_create_function(db, "test_function", 1, SQLITE_UTF16LE, interp, test_function_utf16le, 0, 0); } if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[4], &val) ) return TCL_ERROR; if( val ){ sqlite3_create_function(db, "test_function", 1, SQLITE_UTF16BE, interp, test_function_utf16be, 0, 0); } return TCL_OK; bad_args: Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " ", 0); #endif /* SQLITE_OMIT_UTF16 */ return TCL_ERROR; } /* ** Usage: test_errstr ** ** Test that the english language string equivalents for sqlite error codes ** are sane. The parameter is an integer representing an sqlite error code. ** The result is a list of two elements, the string representation of the ** error code and the english language explanation. */ static int test_errstr( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ char *zCode; int i; if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); } zCode = Tcl_GetString(objv[1]); for(i=0; i<200; i++){ if( 0==strcmp(errorName(i), zCode) ) break; } Tcl_SetResult(interp, (char *)sqlite3ErrStr(i), 0); return TCL_OK; } /* ** Usage: breakpoint ** ** This routine exists for one purpose - to provide a place to put a ** breakpoint with GDB that can be triggered using TCL code. The use ** for this is when a particular test fails on (say) the 1485th iteration. ** In the TCL test script, we can add code like this: ** ** if {$i==1485} breakpoint ** ** Then run testfixture in the debugger and wait for the breakpoint to ** fire. Then additional breakpoints can be set to trace down the bug. */ static int test_breakpoint( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ return TCL_OK; /* Do nothing */ } /* ** Usage: sqlite3_bind_int STMT N VALUE ** ** Test the sqlite3_bind_int interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a 32-bit integer VALUE to that wildcard. */ static int test_bind_int( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int idx; int value; int rc; if( objc!=4 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[3], &value) ) return TCL_ERROR; rc = sqlite3_bind_int(pStmt, idx, value); if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; if( rc!=SQLITE_OK ){ return TCL_ERROR; } return TCL_OK; } /* ** Usage: sqlite3_bind_int64 STMT N VALUE ** ** Test the sqlite3_bind_int64 interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a 64-bit integer VALUE to that wildcard. */ static int test_bind_int64( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int idx; i64 value; int rc; if( objc!=4 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; if( Tcl_GetWideIntFromObj(interp, objv[3], &value) ) return TCL_ERROR; rc = sqlite3_bind_int64(pStmt, idx, value); if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; if( rc!=SQLITE_OK ){ return TCL_ERROR; } return TCL_OK; } /* ** Usage: sqlite3_bind_double STMT N VALUE ** ** Test the sqlite3_bind_double interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a 64-bit integer VALUE to that wildcard. */ static int test_bind_double( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int idx; double value; int rc; if( objc!=4 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; if( Tcl_GetDoubleFromObj(interp, objv[3], &value) ) return TCL_ERROR; rc = sqlite3_bind_double(pStmt, idx, value); if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; if( rc!=SQLITE_OK ){ return TCL_ERROR; } return TCL_OK; } /* ** Usage: sqlite3_bind_null STMT N ** ** Test the sqlite3_bind_null interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a NULL to the wildcard. */ static int test_bind_null( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int idx; int rc; if( objc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " STMT N", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; rc = sqlite3_bind_null(pStmt, idx); if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; if( rc!=SQLITE_OK ){ return TCL_ERROR; } return TCL_OK; } /* ** Usage: sqlite3_bind_text STMT N STRING BYTES ** ** Test the sqlite3_bind_text interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a UTF-8 string STRING to the wildcard. The string is BYTES bytes ** long. */ static int test_bind_text( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int idx; int bytes; char *value; int rc; if( objc!=5 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE BYTES", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; value = Tcl_GetString(objv[3]); if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; 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); return TCL_ERROR; } return TCL_OK; } /* ** Usage: sqlite3_bind_text16 STMT N STRING BYTES ** ** Test the sqlite3_bind_text16 interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a UTF-16 string STRING to the wildcard. The string is BYTES bytes ** long. */ static int test_bind_text16( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_UTF16 sqlite3_stmt *pStmt; int idx; int bytes; char *value; int rc; if( objc!=5 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE BYTES", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; value = Tcl_GetByteArrayFromObj(objv[3], 0); if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, SQLITE_TRANSIENT); if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; if( rc!=SQLITE_OK ){ return TCL_ERROR; } #endif /* SQLITE_OMIT_UTF16 */ return TCL_OK; } /* ** Usage: sqlite3_bind_blob STMT N DATA BYTES ** ** Test the sqlite3_bind_blob interface. STMT is a prepared statement. ** N is the index of a wildcard in the prepared statement. This command ** binds a BLOB to the wildcard. The BLOB is BYTES bytes in size. */ static int test_bind_blob( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int idx; int bytes; char *value; int rc; if( objc!=5 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " STMT N DATA BYTES", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; value = Tcl_GetString(objv[3]); if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; rc = sqlite3_bind_blob(pStmt, idx, value, bytes, SQLITE_TRANSIENT); if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; if( rc!=SQLITE_OK ){ return TCL_ERROR; } return TCL_OK; } /* ** Usage: sqlite3_bind_parameter_count STMT ** ** Return the number of wildcards in the given statement. */ static int test_bind_parameter_count( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "STMT"); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_bind_parameter_count(pStmt))); return TCL_OK; } /* ** Usage: sqlite3_bind_parameter_name STMT N ** ** Return the name of the Nth wildcard. The first wildcard is 1. ** An empty string is returned if N is out of range or if the wildcard ** is nameless. */ static int test_bind_parameter_name( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int i; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 1, objv, "STMT N"); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &i) ) return TCL_ERROR; Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_bind_parameter_name(pStmt,i),-1) ); return TCL_OK; } /* ** Usage: sqlite3_bind_parameter_index STMT NAME ** ** Return the index of the wildcard called NAME. Return 0 if there is ** no such wildcard. */ static int test_bind_parameter_index( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 1, objv, "STMT NAME"); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; Tcl_SetObjResult(interp, Tcl_NewIntObj( sqlite3_bind_parameter_index(pStmt,Tcl_GetString(objv[2])) ) ); return TCL_OK; } /* ** Usage: sqlite3_clear_bindings STMT ** */ #if 0 static int test_clear_bindings( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "STMT"); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_clear_bindings(pStmt))); return TCL_OK; } #endif /* ** Usage: sqlite3_errcode DB ** ** Return the string representation of the most recent sqlite3_* API ** error code. e.g. "SQLITE_ERROR". */ static int test_errcode( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; if( objc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " DB", 0); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; Tcl_SetResult(interp, (char *)errorName(sqlite3_errcode(db)), 0); return TCL_OK; } /* ** Usage: test_errmsg DB ** ** Returns the UTF-8 representation of the error message string for the ** most recent sqlite3_* API call. */ static int test_errmsg( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; const char *zErr; if( objc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " DB", 0); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zErr = sqlite3_errmsg(db); Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1)); return TCL_OK; } /* ** Usage: test_errmsg16 DB ** ** Returns the UTF-16 representation of the error message string for the ** most recent sqlite3_* API call. This is a byte array object at the TCL ** level, and it includes the 0x00 0x00 terminator bytes at the end of the ** UTF-16 string. */ static int test_errmsg16( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_UTF16 sqlite3 *db; const void *zErr; int bytes; if( objc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " DB", 0); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zErr = sqlite3_errmsg16(db); bytes = sqlite3utf16ByteLen(zErr, -1); Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes)); #endif /* SQLITE_OMIT_UTF16 */ return TCL_OK; } /* ** Usage: sqlite3_prepare DB sql bytes tailvar ** ** Compile up to bytes of the supplied SQL string using ** database handle . The parameter is the name of a global ** variable that is set to the unused portion of (if any). A ** STMT handle is returned. */ static int test_prepare( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; const char *zSql; int bytes; const char *zTail = 0; sqlite3_stmt *pStmt = 0; char zBuf[50]; int rc; if( objc!=5 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zSql = Tcl_GetString(objv[2]); if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR; rc = sqlite3_prepare(db, zSql, bytes, &pStmt, &zTail); if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; if( zTail ){ if( bytes>=0 ){ bytes = bytes - (zTail-zSql); } Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0); } if( rc!=SQLITE_OK ){ assert( pStmt==0 ); sprintf(zBuf, "(%d) ", rc); Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0); return TCL_ERROR; } if( pStmt ){ if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR; Tcl_AppendResult(interp, zBuf, 0); } return TCL_OK; } /* ** Usage: sqlite3_prepare DB sql bytes tailvar ** ** Compile up to bytes of the supplied SQL string using ** database handle . The parameter is the name of a global ** variable that is set to the unused portion of (if any). A ** STMT handle is returned. */ static int test_prepare16( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_UTF16 sqlite3 *db; const void *zSql; const void *zTail = 0; Tcl_Obj *pTail = 0; sqlite3_stmt *pStmt = 0; char zBuf[50]; int rc; int bytes; /* The integer specified as arg 3 */ int objlen; /* The byte-array length of arg 2 */ if( objc!=5 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen); if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR; rc = sqlite3_prepare16(db, zSql, bytes, &pStmt, &zTail); if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; if( rc ){ return TCL_ERROR; } if( zTail ){ objlen = objlen - ((u8 *)zTail-(u8 *)zSql); }else{ objlen = 0; } pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen); Tcl_IncrRefCount(pTail); Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0); Tcl_DecrRefCount(pTail); if( pStmt ){ if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR; } Tcl_AppendResult(interp, zBuf, 0); #endif /* SQLITE_OMIT_UTF16 */ return TCL_OK; } /* ** Usage: sqlite3_open filename ?options-list? */ static int test_open( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ const char *zFilename; sqlite3 *db; int rc; char zBuf[100]; if( objc!=3 && objc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " filename options-list", 0); return TCL_ERROR; } zFilename = Tcl_GetString(objv[1]); rc = sqlite3_open(zFilename, &db); if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR; Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; } /* ** Usage: sqlite3_open16 filename options */ static int test_open16( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_UTF16 const void *zFilename; sqlite3 *db; int rc; char zBuf[100]; if( objc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " filename options-list", 0); return TCL_ERROR; } zFilename = Tcl_GetByteArrayFromObj(objv[1], 0); rc = sqlite3_open16(zFilename, &db); if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR; Tcl_AppendResult(interp, zBuf, 0); #endif /* SQLITE_OMIT_UTF16 */ return TCL_OK; } /* ** Usage: sqlite3_complete16 ** ** Return 1 if the supplied argument is a complete SQL statement, or zero ** otherwise. */ static int test_complete16( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #if !defined(SQLITE_OMIT_COMPLETE) && !defined(SQLITE_OMIT_UTF16) char *zBuf; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } zBuf = Tcl_GetByteArrayFromObj(objv[1], 0); Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_complete16(zBuf))); #endif /* SQLITE_OMIT_COMPLETE && SQLITE_OMIT_UTF16 */ return TCL_OK; } /* ** Usage: sqlite3_step STMT ** ** Advance the statement to the next row. */ static int test_step( 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_GetString(objv[0]), " STMT", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; rc = sqlite3_step(pStmt); /* if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR; */ Tcl_SetResult(interp, (char *)errorName(rc), 0); return TCL_OK; } /* ** Usage: sqlite3_column_count STMT ** ** Return the number of columns returned by the sql statement STMT. */ static int test_column_count( 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_GetString(objv[0]), " STMT column", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_column_count(pStmt))); return TCL_OK; } /* ** Usage: sqlite3_column_type STMT column ** ** Return the type of the data in column 'column' of the current row. */ static int test_column_type( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int col; int tp; if( objc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " STMT column", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; tp = sqlite3_column_type(pStmt, col); switch( tp ){ case SQLITE_INTEGER: Tcl_SetResult(interp, "INTEGER", TCL_STATIC); break; case SQLITE_NULL: Tcl_SetResult(interp, "NULL", TCL_STATIC); break; case SQLITE_FLOAT: Tcl_SetResult(interp, "FLOAT", TCL_STATIC); break; case SQLITE_TEXT: Tcl_SetResult(interp, "TEXT", TCL_STATIC); break; case SQLITE_BLOB: Tcl_SetResult(interp, "BLOB", TCL_STATIC); break; default: assert(0); } return TCL_OK; } /* ** Usage: sqlite3_column_int64 STMT column ** ** Return the data in column 'column' of the current row cast as an ** wide (64-bit) integer. */ static int test_column_int64( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int col; i64 iVal; if( objc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " STMT column", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; iVal = sqlite3_column_int64(pStmt, col); Tcl_SetObjResult(interp, Tcl_NewWideIntObj(iVal)); return TCL_OK; } /* ** Usage: sqlite3_column_blob STMT column */ static int test_column_blob( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int col; int len; const void *pBlob; if( objc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " STMT column", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; pBlob = sqlite3_column_blob(pStmt, col); len = sqlite3_column_bytes(pStmt, col); Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pBlob, len)); return TCL_OK; } /* ** Usage: sqlite3_column_double STMT column ** ** Return the data in column 'column' of the current row cast as a double. */ static int test_column_double( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int col; double rVal; if( objc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " STMT column", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; rVal = sqlite3_column_double(pStmt, col); Tcl_SetObjResult(interp, Tcl_NewDoubleObj(rVal)); return TCL_OK; } /* ** Usage: sqlite3_data_count STMT ** ** Return the number of columns returned by the sql statement STMT. */ static int test_data_count( 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_GetString(objv[0]), " STMT column", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_data_count(pStmt))); return TCL_OK; } /* ** Usage: sqlite3_column_text STMT column ** ** Usage: sqlite3_column_decltype STMT column ** ** Usage: sqlite3_column_name STMT column */ static int test_stmt_utf8( void * clientData, /* Pointer to SQLite API function to be invoke */ Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int col; const char *(*xFunc)(sqlite3_stmt*, int) = clientData; const char *zRet; if( objc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " STMT column", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; zRet = xFunc(pStmt, col); if( zRet ){ Tcl_SetResult(interp, (char *)zRet, 0); } return TCL_OK; } static int test_global_recover( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_GLOBALRECOVER int rc; if( objc!=1 ){ Tcl_WrongNumArgs(interp, 1, objv, ""); return TCL_ERROR; } rc = sqlite3_global_recover(); Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC); #endif return TCL_OK; } /* ** Usage: sqlite3_column_text STMT column ** ** Usage: sqlite3_column_decltype STMT column ** ** Usage: sqlite3_column_name STMT column */ static int test_stmt_utf16( void * clientData, /* Pointer to SQLite API function to be invoked */ Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ #ifndef SQLITE_OMIT_UTF16 sqlite3_stmt *pStmt; int col; Tcl_Obj *pRet; const void *zName16; const void *(*xFunc)(sqlite3_stmt*, int) = clientData; if( objc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " STMT column", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; zName16 = xFunc(pStmt, col); if( zName16 ){ pRet = Tcl_NewByteArrayObj(zName16, sqlite3utf16ByteLen(zName16, -1)+2); Tcl_SetObjResult(interp, pRet); } #endif /* SQLITE_OMIT_UTF16 */ return TCL_OK; } /* ** Usage: sqlite3_column_int STMT column ** ** Usage: sqlite3_column_bytes STMT column ** ** Usage: sqlite3_column_bytes16 STMT column ** */ static int test_stmt_int( void * clientData, /* Pointer to SQLite API function to be invoked */ Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int col; int (*xFunc)(sqlite3_stmt*, int) = clientData; if( objc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " STMT column", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; Tcl_SetObjResult(interp, Tcl_NewIntObj(xFunc(pStmt, col))); return TCL_OK; } #ifndef SQLITE_OMIT_DISKIO /* ** Usage: sqlite3OsOpenReadWrite */ static int test_sqlite3OsOpenReadWrite( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ OsFile *pFile; int rc; int dummy; char zBuf[100]; if( objc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " filename", 0); return TCL_ERROR; } rc = sqlite3Os.xOpenReadWrite(Tcl_GetString(objv[1]), &pFile, &dummy); if( rc!=SQLITE_OK ){ Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC); return TCL_ERROR; } makePointerStr(interp, zBuf, pFile); Tcl_SetResult(interp, zBuf, 0); return TCL_ERROR; } /* ** Usage: sqlite3OsClose */ static int test_sqlite3OsClose( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ OsFile *pFile; int rc; if( objc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " filehandle", 0); return TCL_ERROR; } if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){ return TCL_ERROR; } rc = sqlite3OsClose(&pFile); if( rc!=SQLITE_OK ){ Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC); return TCL_ERROR; } return TCL_OK; } /* ** Usage: sqlite3OsLock */ static int test_sqlite3OsLock( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ OsFile * pFile; int rc; if( objc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " filehandle (SHARED|RESERVED|PENDING|EXCLUSIVE)", 0); return TCL_ERROR; } if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){ return TCL_ERROR; } if( 0==strcmp("SHARED", Tcl_GetString(objv[2])) ){ rc = sqlite3OsLock(pFile, SHARED_LOCK); } else if( 0==strcmp("RESERVED", Tcl_GetString(objv[2])) ){ rc = sqlite3OsLock(pFile, RESERVED_LOCK); } else if( 0==strcmp("PENDING", Tcl_GetString(objv[2])) ){ rc = sqlite3OsLock(pFile, PENDING_LOCK); } else if( 0==strcmp("EXCLUSIVE", Tcl_GetString(objv[2])) ){ rc = sqlite3OsLock(pFile, EXCLUSIVE_LOCK); }else{ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " filehandle (SHARED|RESERVED|PENDING|EXCLUSIVE)", 0); return TCL_ERROR; } if( rc!=SQLITE_OK ){ Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC); return TCL_ERROR; } return TCL_OK; } /* ** Usage: sqlite3OsUnlock */ static int test_sqlite3OsUnlock( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ OsFile * pFile; int rc; if( objc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " filehandle", 0); return TCL_ERROR; } if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){ return TCL_ERROR; } rc = sqlite3OsUnlock(pFile, NO_LOCK); if( rc!=SQLITE_OK ){ Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC); return TCL_ERROR; } return TCL_OK; } /* ** Usage: sqlite3OsTempFileName */ static int test_sqlite3OsTempFileName( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ char zFile[SQLITE_TEMPNAME_SIZE]; int rc; rc = sqlite3Os.xTempFileName(zFile); if( rc!=SQLITE_OK ){ Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC); return TCL_ERROR; } Tcl_AppendResult(interp, zFile, 0); return TCL_OK; } #endif /* ** Usage: sqlite_set_magic DB MAGIC-NUMBER ** ** Set the db->magic value. This is used to test error recovery logic. */ static int sqlite_set_magic( void * clientData, Tcl_Interp *interp, int argc, char **argv ){ sqlite3 *db; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB MAGIC", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; if( strcmp(argv[2], "SQLITE_MAGIC_OPEN")==0 ){ db->magic = SQLITE_MAGIC_OPEN; }else if( strcmp(argv[2], "SQLITE_MAGIC_CLOSED")==0 ){ db->magic = SQLITE_MAGIC_CLOSED; }else if( strcmp(argv[2], "SQLITE_MAGIC_BUSY")==0 ){ db->magic = SQLITE_MAGIC_BUSY; }else if( strcmp(argv[2], "SQLITE_MAGIC_ERROR")==0 ){ db->magic = SQLITE_MAGIC_ERROR; }else if( Tcl_GetInt(interp, argv[2], &db->magic) ){ return TCL_ERROR; } return TCL_OK; } /* ** Usage: sqlite3_interrupt DB ** ** Trigger an interrupt on DB */ static int test_interrupt( void * clientData, Tcl_Interp *interp, int argc, char **argv ){ sqlite3 *db; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; sqlite3_interrupt(db); return TCL_OK; } static u8 *sqlite3_stack_baseline = 0; /* ** Fill the stack with a known bitpattern. */ static void prepStack(void){ int i; u32 bigBuf[65536]; for(i=0; i=0 && ((u32*)sqlite3_stack_baseline)[-i]==0xdeadbeef; i--){} Tcl_SetObjResult(interp, Tcl_NewIntObj(i*4)); return TCL_OK; } /* ** Usage: sqlite_delete_function DB function-name ** ** Delete the user function 'function-name' from database handle DB. It ** is assumed that the user function was created as UTF8, any number of ** arguments (the way the TCL interface does it). */ static int delete_function( void * clientData, Tcl_Interp *interp, int argc, char **argv ){ int rc; sqlite3 *db; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB function-name", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; rc = sqlite3_create_function(db, argv[2], -1, SQLITE_UTF8, 0, 0, 0, 0); Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC); return TCL_OK; } /* ** Usage: sqlite_delete_collation DB collation-name ** ** Delete the collation sequence 'collation-name' from database handle ** DB. It is assumed that the collation sequence was created as UTF8 (the ** way the TCL interface does it). */ static int delete_collation( void * clientData, Tcl_Interp *interp, int argc, char **argv ){ int rc; sqlite3 *db; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB function-name", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; rc = sqlite3_create_collation(db, argv[2], SQLITE_UTF8, 0, 0); Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC); return TCL_OK; } /* ** Usage: sqlite3_get_autocommit DB ** ** Return true if the database DB is currently in auto-commit mode. ** Return false if not. */ static int get_autocommit( void * clientData, Tcl_Interp *interp, int argc, char **argv ){ char zBuf[30]; sqlite3 *db; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; sprintf(zBuf, "%d", sqlite3_get_autocommit(db)); Tcl_AppendResult(interp, zBuf, 0); return TCL_OK; } /* ** Usage: tcl_variable_type VARIABLENAME ** ** Return the name of the internal representation for the ** value of the given variable. */ static int tcl_variable_type( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ Tcl_Obj *pVar; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "VARIABLE"); return TCL_ERROR; } pVar = Tcl_GetVar2Ex(interp, Tcl_GetString(objv[1]), 0, TCL_LEAVE_ERR_MSG); if( pVar==0 ) return TCL_ERROR; if( pVar->typePtr ){ Tcl_SetObjResult(interp, Tcl_NewStringObj(pVar->typePtr->name, -1)); } return TCL_OK; } /* ** This routine sets entries in the global ::sqlite_options() array variable ** according to the compile-time configuration of the database. Test ** procedures use this to determine when tests should be omitted. */ static void set_options(Tcl_Interp *interp){ #ifdef SQLITE_32BIT_ROWID Tcl_SetVar2(interp, "sqlite_options", "rowid32", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "rowid32", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_CASE_SENSITIVE_LIKE Tcl_SetVar2(interp, "sqlite_options","casesensitivelike","1",TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options","casesensitivelike","0",TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_DISABLE_DIRSYNC Tcl_SetVar2(interp, "sqlite_options", "dirsync", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "dirsync", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_DISABLE_LFS Tcl_SetVar2(interp, "sqlite_options", "lfs", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "lfs", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_ALTERTABLE Tcl_SetVar2(interp, "sqlite_options", "altertable", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "altertable", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_ANALYZE Tcl_SetVar2(interp, "sqlite_options", "analyze", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "analyze", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_AUTHORIZATION Tcl_SetVar2(interp, "sqlite_options", "auth", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "auth", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_AUTOINCREMENT Tcl_SetVar2(interp, "sqlite_options", "autoinc", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "autoinc", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_AUTOVACUUM Tcl_SetVar2(interp, "sqlite_options", "autovacuum", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "autovacuum", "1", TCL_GLOBAL_ONLY); #endif /* SQLITE_OMIT_AUTOVACUUM */ #if !defined(SQLITE_DEFAULT_AUTOVACUUM) || SQLITE_DEFAULT_AUTOVACUUM==0 Tcl_SetVar2(interp,"sqlite_options","default_autovacuum","0",TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp,"sqlite_options","default_autovacuum","1",TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_BETWEEN_OPTIMIZATION Tcl_SetVar2(interp, "sqlite_options", "between_opt", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "between_opt", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_BLOB_LITERAL Tcl_SetVar2(interp, "sqlite_options", "bloblit", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "bloblit", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_CAST Tcl_SetVar2(interp, "sqlite_options", "cast", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "cast", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_CHECK Tcl_SetVar2(interp, "sqlite_options", "check", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "check", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_COMPLETE Tcl_SetVar2(interp, "sqlite_options", "complete", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "complete", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_COMPOUND_SELECT Tcl_SetVar2(interp, "sqlite_options", "compound", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "compound", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_CONFLICT_CLAUSE Tcl_SetVar2(interp, "sqlite_options", "conflict", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "conflict", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_DATETIME_FUNCS Tcl_SetVar2(interp, "sqlite_options", "datetime", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "datetime", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_DISKIO Tcl_SetVar2(interp, "sqlite_options", "diskio", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "diskio", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_EXPLAIN Tcl_SetVar2(interp, "sqlite_options", "explain", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "explain", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_FLOATING_POINT Tcl_SetVar2(interp, "sqlite_options", "floatingpoint", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "floatingpoint", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_FOREIGN_KEY Tcl_SetVar2(interp, "sqlite_options", "foreignkey", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "foreignkey", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_GLOBALRECOVER Tcl_SetVar2(interp, "sqlite_options", "globalrecover", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "globalrecover", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_INTEGRITY_CHECK Tcl_SetVar2(interp, "sqlite_options", "integrityck", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "integrityck", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_LIKE_OPTIMIZATION Tcl_SetVar2(interp, "sqlite_options", "like_opt", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "like_opt", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_MEMORYDB Tcl_SetVar2(interp, "sqlite_options", "memorydb", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "memorydb", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_OR_OPTIMIZATION Tcl_SetVar2(interp, "sqlite_options", "or_opt", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "or_opt", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_PAGER_PRAGMAS Tcl_SetVar2(interp, "sqlite_options", "pager_pragmas", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "pager_pragmas", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_PARSER Tcl_SetVar2(interp, "sqlite_options", "parser", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "parser", "1", TCL_GLOBAL_ONLY); #endif #if defined(SQLITE_OMIT_PRAGMA) || defined(SQLITE_OMIT_FLAG_PRAGMAS) Tcl_SetVar2(interp, "sqlite_options", "pragma", "0", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "sqlite_options", "integrityck", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "pragma", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_PROGRESS_CALLBACK Tcl_SetVar2(interp, "sqlite_options", "progress", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "progress", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_REINDEX Tcl_SetVar2(interp, "sqlite_options", "reindex", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "reindex", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_SCHEMA_PRAGMAS Tcl_SetVar2(interp, "sqlite_options", "schema_pragmas", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "schema_pragmas", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS Tcl_SetVar2(interp, "sqlite_options", "schema_version", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "schema_version", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_SUBQUERY Tcl_SetVar2(interp, "sqlite_options", "subquery", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "subquery", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_TCL_VARIABLE Tcl_SetVar2(interp, "sqlite_options", "tclvar", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "tclvar", "1", TCL_GLOBAL_ONLY); #endif #if defined(THREADSAFE) && THREADSAFE Tcl_SetVar2(interp, "sqlite_options", "threadsafe", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "threadsafe", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_TRACE Tcl_SetVar2(interp, "sqlite_options", "trace", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "trace", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_TRIGGER Tcl_SetVar2(interp, "sqlite_options", "trigger", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "trigger", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_TEMPDB Tcl_SetVar2(interp, "sqlite_options", "tempdb", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "tempdb", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_UTF16 Tcl_SetVar2(interp, "sqlite_options", "utf16", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "utf16", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_VACUUM Tcl_SetVar2(interp, "sqlite_options", "vacuum", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "vacuum", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_OMIT_VIEW Tcl_SetVar2(interp, "sqlite_options", "view", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "view", "1", TCL_GLOBAL_ONLY); #endif } /* ** Register commands with the TCL interpreter. */ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite3_search_count; extern int sqlite3_interrupt_count; extern int sqlite3_open_file_count; extern int sqlite3_sort_count; extern int sqlite3_current_time; static struct { char *zName; Tcl_CmdProc *xProc; } aCmd[] = { { "sqlite3_mprintf_int", (Tcl_CmdProc*)sqlite3_mprintf_int }, { "sqlite3_mprintf_int64", (Tcl_CmdProc*)sqlite3_mprintf_int64 }, { "sqlite3_mprintf_str", (Tcl_CmdProc*)sqlite3_mprintf_str }, { "sqlite3_mprintf_stronly", (Tcl_CmdProc*)sqlite3_mprintf_stronly}, { "sqlite3_mprintf_double", (Tcl_CmdProc*)sqlite3_mprintf_double }, { "sqlite3_mprintf_scaled", (Tcl_CmdProc*)sqlite3_mprintf_scaled }, { "sqlite3_mprintf_hexdouble", (Tcl_CmdProc*)sqlite3_mprintf_hexdouble}, { "sqlite3_mprintf_z_test", (Tcl_CmdProc*)test_mprintf_z }, { "sqlite3_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid }, { "sqlite3_exec_printf", (Tcl_CmdProc*)test_exec_printf }, { "sqlite3_get_table_printf", (Tcl_CmdProc*)test_get_table_printf }, { "sqlite3_close", (Tcl_CmdProc*)sqlite_test_close }, { "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 }, { "sqlite_abort", (Tcl_CmdProc*)sqlite_abort }, #ifdef SQLITE_MEMDEBUG { "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail }, { "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat }, { "sqlite_malloc_outstanding", (Tcl_CmdProc*)sqlite_malloc_outstanding}, #endif { "sqlite_bind", (Tcl_CmdProc*)test_bind }, { "breakpoint", (Tcl_CmdProc*)test_breakpoint }, { "sqlite3_key", (Tcl_CmdProc*)test_key }, { "sqlite3_rekey", (Tcl_CmdProc*)test_rekey }, { "sqlite_set_magic", (Tcl_CmdProc*)sqlite_set_magic }, { "sqlite3_interrupt", (Tcl_CmdProc*)test_interrupt }, #if 0 { "sqlite3_sleep", (Tcl_CmdProc*)test_sleep }, #endif { "sqlite_delete_function", (Tcl_CmdProc*)delete_function }, { "sqlite_delete_collation", (Tcl_CmdProc*)delete_collation }, { "sqlite3_get_autocommit", (Tcl_CmdProc*)get_autocommit }, { "sqlite3_stack_used", (Tcl_CmdProc*)test_stack_used }, }; static struct { char *zName; Tcl_ObjCmdProc *xProc; void *clientData; } aObjCmd[] = { { "sqlite3_bind_int", test_bind_int, 0 }, { "sqlite3_bind_int64", test_bind_int64, 0 }, { "sqlite3_bind_double", test_bind_double, 0 }, { "sqlite3_bind_null", test_bind_null ,0 }, { "sqlite3_bind_text", test_bind_text ,0 }, { "sqlite3_bind_text16", test_bind_text16 ,0 }, { "sqlite3_bind_blob", test_bind_blob ,0 }, { "sqlite3_bind_parameter_count", test_bind_parameter_count, 0}, { "sqlite3_bind_parameter_name", test_bind_parameter_name, 0}, { "sqlite3_bind_parameter_index", test_bind_parameter_index, 0}, #if 0 { "sqlite3_clear_bindings", test_clear_bindings, 0}, #endif { "sqlite3_errcode", test_errcode ,0 }, { "sqlite3_errmsg", test_errmsg ,0 }, { "sqlite3_errmsg16", test_errmsg16 ,0 }, { "sqlite3_open", test_open ,0 }, { "sqlite3_open16", test_open16 ,0 }, { "sqlite3_complete16", test_complete16 ,0 }, { "sqlite3_prepare", test_prepare ,0 }, { "sqlite3_prepare16", test_prepare16 ,0 }, { "sqlite3_finalize", test_finalize ,0 }, { "sqlite3_reset", test_reset ,0 }, { "sqlite3_expired", test_expired ,0 }, { "sqlite3_transfer_bindings", test_transfer_bind ,0 }, { "sqlite3_changes", test_changes ,0 }, { "sqlite3_step", test_step ,0 }, /* sqlite3_column_*() API */ { "sqlite3_column_count", test_column_count ,0 }, { "sqlite3_data_count", test_data_count ,0 }, { "sqlite3_column_type", test_column_type ,0 }, { "sqlite3_column_blob", test_column_blob ,0 }, { "sqlite3_column_double", test_column_double ,0 }, { "sqlite3_column_int64", test_column_int64 ,0 }, { "sqlite3_column_text", test_stmt_utf8, sqlite3_column_text }, { "sqlite3_column_decltype", test_stmt_utf8, sqlite3_column_decltype }, { "sqlite3_column_name", test_stmt_utf8, sqlite3_column_name }, { "sqlite3_column_int", test_stmt_int, sqlite3_column_int }, { "sqlite3_column_bytes", test_stmt_int, sqlite3_column_bytes }, #ifndef SQLITE_OMIT_UTF16 { "sqlite3_column_bytes16", test_stmt_int, sqlite3_column_bytes16 }, { "sqlite3_column_text16", test_stmt_utf16, sqlite3_column_text16 }, { "sqlite3_column_decltype16", test_stmt_utf16, sqlite3_column_decltype16}, { "sqlite3_column_name16", test_stmt_utf16, sqlite3_column_name16 }, #endif { "sqlite3_global_recover", test_global_recover, 0 }, /* Functions from os.h */ #ifndef SQLITE_OMIT_DISKIO { "sqlite3OsOpenReadWrite",test_sqlite3OsOpenReadWrite, 0 }, { "sqlite3OsClose", test_sqlite3OsClose, 0 }, { "sqlite3OsLock", test_sqlite3OsLock, 0 }, { "sqlite3OsTempFileName", test_sqlite3OsTempFileName, 0 }, /* Custom test interfaces */ { "sqlite3OsUnlock", test_sqlite3OsUnlock, 0 }, #endif #ifndef SQLITE_OMIT_UTF16 { "add_test_collate", test_collate, 0 }, { "add_test_collate_needed", test_collate_needed, 0 }, { "add_test_function", test_function, 0 }, #endif { "sqlite3_test_errstr", test_errstr, 0 }, { "tcl_variable_type", tcl_variable_type, 0 }, }; static int bitmask_size = sizeof(Bitmask)*8; int i; extern int sqlite3_os_trace; extern int sqlite3_where_trace; extern int sqlite3_sync_count, sqlite3_fullsync_count; extern int sqlite3_opentemp_count; extern int sqlite3_memUsed; extern int sqlite3_malloc_id; extern int sqlite3_memMax; extern int sqlite3_like_count; #if OS_WIN extern int sqlite3_os_type; #endif #ifdef SQLITE_DEBUG extern int sqlite3_vdbe_addop_trace; #endif #ifdef SQLITE_TEST extern char sqlite3_query_plan[]; static char *query_plan = sqlite3_query_plan; #endif for(i=0; i