1d1bf3512Sdrh /* 2b19a2bc6Sdrh ** 2001 September 15 3d1bf3512Sdrh ** 4b19a2bc6Sdrh ** The author disclaims copyright to this source code. In place of 5b19a2bc6Sdrh ** a legal notice, here is a blessing: 6d1bf3512Sdrh ** 7b19a2bc6Sdrh ** May you do good and not evil. 8b19a2bc6Sdrh ** May you find forgiveness for yourself and forgive others. 9b19a2bc6Sdrh ** May you share freely, never taking more than you give. 10d1bf3512Sdrh ** 11d1bf3512Sdrh ************************************************************************* 12d1bf3512Sdrh ** Code for testing the printf() interface to SQLite. This code 13d1bf3512Sdrh ** is not included in the SQLite library. It is used for automated 14d1bf3512Sdrh ** testing of the SQLite library. 15d1bf3512Sdrh ** 16*80290863Sdanielk1977 ** $Id: test1.c,v 1.46 2004/05/22 09:21:21 danielk1977 Exp $ 17d1bf3512Sdrh */ 18d1bf3512Sdrh #include "sqliteInt.h" 19d1bf3512Sdrh #include "tcl.h" 2094e92032Sdrh #include "os.h" 21d1bf3512Sdrh #include <stdlib.h> 22d1bf3512Sdrh #include <string.h> 23d1bf3512Sdrh 2494e92032Sdrh #if OS_WIN 2594e92032Sdrh # define PTR_FMT "%x" 2694e92032Sdrh #else 2794e92032Sdrh # define PTR_FMT "%p" 2894e92032Sdrh #endif 2994e92032Sdrh 306622cce3Sdanielk1977 static const char * errorName(int rc){ 316622cce3Sdanielk1977 const char *zName = 0; 326622cce3Sdanielk1977 switch( rc ){ 336622cce3Sdanielk1977 case SQLITE_OK: zName = "SQLITE_OK"; break; 346622cce3Sdanielk1977 case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; 356622cce3Sdanielk1977 case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break; 366622cce3Sdanielk1977 case SQLITE_PERM: zName = "SQLITE_PERM"; break; 376622cce3Sdanielk1977 case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; 386622cce3Sdanielk1977 case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; 396622cce3Sdanielk1977 case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break; 406622cce3Sdanielk1977 case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break; 416622cce3Sdanielk1977 case SQLITE_READONLY: zName = "SQLITE_READONLY"; break; 426622cce3Sdanielk1977 case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break; 436622cce3Sdanielk1977 case SQLITE_IOERR: zName = "SQLITE_IOERR"; break; 446622cce3Sdanielk1977 case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break; 456622cce3Sdanielk1977 case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break; 466622cce3Sdanielk1977 case SQLITE_FULL: zName = "SQLITE_FULL"; break; 476622cce3Sdanielk1977 case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break; 486622cce3Sdanielk1977 case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break; 496622cce3Sdanielk1977 case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break; 506622cce3Sdanielk1977 case SQLITE_SCHEMA: zName = "SQLITE_SCHEMA"; break; 516622cce3Sdanielk1977 case SQLITE_TOOBIG: zName = "SQLITE_TOOBIG"; break; 526622cce3Sdanielk1977 case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT"; break; 536622cce3Sdanielk1977 case SQLITE_MISMATCH: zName = "SQLITE_MISMATCH"; break; 546622cce3Sdanielk1977 case SQLITE_MISUSE: zName = "SQLITE_MISUSE"; break; 556622cce3Sdanielk1977 case SQLITE_NOLFS: zName = "SQLITE_NOLFS"; break; 566622cce3Sdanielk1977 case SQLITE_AUTH: zName = "SQLITE_AUTH"; break; 576622cce3Sdanielk1977 case SQLITE_FORMAT: zName = "SQLITE_FORMAT"; break; 586622cce3Sdanielk1977 case SQLITE_RANGE: zName = "SQLITE_RANGE"; break; 596622cce3Sdanielk1977 case SQLITE_ROW: zName = "SQLITE_ROW"; break; 606622cce3Sdanielk1977 case SQLITE_DONE: zName = "SQLITE_DONE"; break; 616622cce3Sdanielk1977 default: zName = "SQLITE_Unknown"; break; 626622cce3Sdanielk1977 } 636622cce3Sdanielk1977 return zName; 646622cce3Sdanielk1977 } 656622cce3Sdanielk1977 66d1bf3512Sdrh /* 67b86ccfb2Sdrh ** Decode a pointer to an sqlite object. 68b86ccfb2Sdrh */ 6990f405e3Sdrh static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite **ppDb){ 7090f405e3Sdrh if( sscanf(zA, PTR_FMT, (void**)ppDb)!=1 && 7190f405e3Sdrh (zA[0]!='0' || zA[1]!='x' || sscanf(&zA[2], PTR_FMT, (void**)ppDb)!=1) 7290f405e3Sdrh ){ 7390f405e3Sdrh Tcl_AppendResult(interp, "\"", zA, "\" is not a valid pointer value", 0); 74b86ccfb2Sdrh return TCL_ERROR; 75b86ccfb2Sdrh } 76b86ccfb2Sdrh return TCL_OK; 77b86ccfb2Sdrh } 78b86ccfb2Sdrh 79b86ccfb2Sdrh /* 80b86ccfb2Sdrh ** Decode a pointer to an sqlite_vm object. 81b86ccfb2Sdrh */ 82b86ccfb2Sdrh static int getVmPointer(Tcl_Interp *interp, const char *zArg, sqlite_vm **ppVm){ 8394e92032Sdrh if( sscanf(zArg, PTR_FMT, (void**)ppVm)!=1 ){ 84b86ccfb2Sdrh Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0); 85b86ccfb2Sdrh return TCL_ERROR; 86b86ccfb2Sdrh } 87b86ccfb2Sdrh return TCL_OK; 88b86ccfb2Sdrh } 89b86ccfb2Sdrh 90b86ccfb2Sdrh /* 9151e3d8e2Sdanielk1977 ** Decode a pointer to an sqlite3_stmt object. 9251e3d8e2Sdanielk1977 */ 9351e3d8e2Sdanielk1977 static int getStmtPointer( 9451e3d8e2Sdanielk1977 Tcl_Interp *interp, 9551e3d8e2Sdanielk1977 const char *zArg, 9651e3d8e2Sdanielk1977 sqlite3_stmt **ppStmt 9751e3d8e2Sdanielk1977 ){ 9851e3d8e2Sdanielk1977 if( sscanf(zArg, PTR_FMT, (void**)ppStmt)!=1 ){ 9951e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0); 10051e3d8e2Sdanielk1977 return TCL_ERROR; 10151e3d8e2Sdanielk1977 } 10251e3d8e2Sdanielk1977 return TCL_OK; 10351e3d8e2Sdanielk1977 } 10451e3d8e2Sdanielk1977 10551e3d8e2Sdanielk1977 /* 1067d8085a8Sdrh ** Generate a text representation of a pointer that can be understood 1077d8085a8Sdrh ** by the getDbPointer and getVmPointer routines above. 1087d8085a8Sdrh ** 1097d8085a8Sdrh ** The problem is, on some machines (Solaris) if you do a printf with 1107d8085a8Sdrh ** "%p" you cannot turn around and do a scanf with the same "%p" and 1117d8085a8Sdrh ** get your pointer back. You have to prepend a "0x" before it will 1127d8085a8Sdrh ** work. Or at least that is what is reported to me (drh). But this 1137d8085a8Sdrh ** behavior varies from machine to machine. The solution used her is 1147d8085a8Sdrh ** to test the string right after it is generated to see if it can be 1157d8085a8Sdrh ** understood by scanf, and if not, try prepending an "0x" to see if 1167d8085a8Sdrh ** that helps. If nothing works, a fatal error is generated. 1177d8085a8Sdrh */ 1187d8085a8Sdrh static int makePointerStr(Tcl_Interp *interp, char *zPtr, void *p){ 1197d8085a8Sdrh void *p2; 1207d8085a8Sdrh sprintf(zPtr, PTR_FMT, p); 1217d8085a8Sdrh if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){ 1227d8085a8Sdrh sprintf(zPtr, "0x" PTR_FMT, p); 1237d8085a8Sdrh if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){ 1247d8085a8Sdrh Tcl_AppendResult(interp, "unable to convert a pointer to a string " 1257d8085a8Sdrh "in the file " __FILE__ " in function makePointerStr(). Please " 1267d8085a8Sdrh "report this problem to the SQLite mailing list or as a new but " 1277d8085a8Sdrh "report. Please provide detailed information about how you compiled " 1287d8085a8Sdrh "SQLite and what computer you are running on.", 0); 1297d8085a8Sdrh return TCL_ERROR; 1307d8085a8Sdrh } 1317d8085a8Sdrh } 1327d8085a8Sdrh return TCL_OK; 1337d8085a8Sdrh } 1347d8085a8Sdrh 1357d8085a8Sdrh /* 1366f8a503dSdanielk1977 ** The callback routine for sqlite3_exec_printf(). 137d1bf3512Sdrh */ 138d1bf3512Sdrh static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){ 139d1bf3512Sdrh Tcl_DString *str = (Tcl_DString*)pArg; 140d1bf3512Sdrh int i; 141d1bf3512Sdrh 142d1bf3512Sdrh if( Tcl_DStringLength(str)==0 ){ 143d1bf3512Sdrh for(i=0; i<argc; i++){ 144d1bf3512Sdrh Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL"); 145d1bf3512Sdrh } 146d1bf3512Sdrh } 147d1bf3512Sdrh for(i=0; i<argc; i++){ 148d1bf3512Sdrh Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL"); 149d1bf3512Sdrh } 150d1bf3512Sdrh return 0; 151d1bf3512Sdrh } 152d1bf3512Sdrh 153d1bf3512Sdrh /* 1546f8a503dSdanielk1977 ** Usage: sqlite3_exec_printf DB FORMAT STRING 155d1bf3512Sdrh ** 1566f8a503dSdanielk1977 ** Invoke the sqlite3_exec_printf() interface using the open database 157d1bf3512Sdrh ** DB. The SQL is the string FORMAT. The format string should contain 158d1bf3512Sdrh ** one %s or %q. STRING is the value inserted into %s or %q. 159d1bf3512Sdrh */ 160d1bf3512Sdrh static int test_exec_printf( 161d1bf3512Sdrh void *NotUsed, 162d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 163d1bf3512Sdrh int argc, /* Number of arguments */ 164d1bf3512Sdrh char **argv /* Text of each argument */ 165d1bf3512Sdrh ){ 166d1bf3512Sdrh sqlite *db; 167d1bf3512Sdrh Tcl_DString str; 168d1bf3512Sdrh int rc; 169d1bf3512Sdrh char *zErr = 0; 170d1bf3512Sdrh char zBuf[30]; 171d1bf3512Sdrh if( argc!=4 ){ 172d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 173d1bf3512Sdrh " DB FORMAT STRING", 0); 174d1bf3512Sdrh return TCL_ERROR; 175d1bf3512Sdrh } 176b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 177d1bf3512Sdrh Tcl_DStringInit(&str); 1786f8a503dSdanielk1977 rc = sqlite3_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]); 179d1bf3512Sdrh sprintf(zBuf, "%d", rc); 180d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 181d1bf3512Sdrh Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr); 182d1bf3512Sdrh Tcl_DStringFree(&str); 183d1bf3512Sdrh if( zErr ) free(zErr); 184d1bf3512Sdrh return TCL_OK; 185d1bf3512Sdrh } 186d1bf3512Sdrh 187d1bf3512Sdrh /* 1886f8a503dSdanielk1977 ** Usage: sqlite3_mprintf_z_test SEPARATOR ARG0 ARG1 ... 189d93d8a81Sdrh ** 190d93d8a81Sdrh ** Test the %z format of mprintf(). Use multiple mprintf() calls to 191d93d8a81Sdrh ** concatenate arg0 through argn using separator as the separator. 192d93d8a81Sdrh ** Return the result. 193d93d8a81Sdrh */ 194d93d8a81Sdrh static int test_mprintf_z( 195d93d8a81Sdrh void *NotUsed, 196d93d8a81Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 197d93d8a81Sdrh int argc, /* Number of arguments */ 198d93d8a81Sdrh char **argv /* Text of each argument */ 199d93d8a81Sdrh ){ 200d93d8a81Sdrh char *zResult = 0; 201d93d8a81Sdrh int i; 202d93d8a81Sdrh 203d93d8a81Sdrh for(i=2; i<argc; i++){ 2044adee20fSdanielk1977 zResult = sqlite3MPrintf("%z%s%s", zResult, argv[1], argv[i]); 205d93d8a81Sdrh } 206d93d8a81Sdrh Tcl_AppendResult(interp, zResult, 0); 2075f968436Sdrh sqliteFree(zResult); 208d93d8a81Sdrh return TCL_OK; 209d93d8a81Sdrh } 210d93d8a81Sdrh 211d93d8a81Sdrh /* 2126f8a503dSdanielk1977 ** Usage: sqlite3_get_table_printf DB FORMAT STRING 213d1bf3512Sdrh ** 2146f8a503dSdanielk1977 ** Invoke the sqlite3_get_table_printf() interface using the open database 215d1bf3512Sdrh ** DB. The SQL is the string FORMAT. The format string should contain 216d1bf3512Sdrh ** one %s or %q. STRING is the value inserted into %s or %q. 217d1bf3512Sdrh */ 218d1bf3512Sdrh static int test_get_table_printf( 219d1bf3512Sdrh void *NotUsed, 220d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 221d1bf3512Sdrh int argc, /* Number of arguments */ 222d1bf3512Sdrh char **argv /* Text of each argument */ 223d1bf3512Sdrh ){ 224d1bf3512Sdrh sqlite *db; 225d1bf3512Sdrh Tcl_DString str; 226d1bf3512Sdrh int rc; 227d1bf3512Sdrh char *zErr = 0; 228d1bf3512Sdrh int nRow, nCol; 229d1bf3512Sdrh char **aResult; 230d1bf3512Sdrh int i; 231d1bf3512Sdrh char zBuf[30]; 232d1bf3512Sdrh if( argc!=4 ){ 233d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 234d1bf3512Sdrh " DB FORMAT STRING", 0); 235d1bf3512Sdrh return TCL_ERROR; 236d1bf3512Sdrh } 237b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 238d1bf3512Sdrh Tcl_DStringInit(&str); 2396f8a503dSdanielk1977 rc = sqlite3_get_table_printf(db, argv[2], &aResult, &nRow, &nCol, 240d1bf3512Sdrh &zErr, argv[3]); 241d1bf3512Sdrh sprintf(zBuf, "%d", rc); 242d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 243d1bf3512Sdrh if( rc==SQLITE_OK ){ 244d1bf3512Sdrh sprintf(zBuf, "%d", nRow); 245d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 246d1bf3512Sdrh sprintf(zBuf, "%d", nCol); 247d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 248d1bf3512Sdrh for(i=0; i<(nRow+1)*nCol; i++){ 249d1bf3512Sdrh Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL"); 250d1bf3512Sdrh } 251d1bf3512Sdrh }else{ 252d1bf3512Sdrh Tcl_AppendElement(interp, zErr); 253d1bf3512Sdrh } 2546f8a503dSdanielk1977 sqlite3_free_table(aResult); 255d1bf3512Sdrh if( zErr ) free(zErr); 256d1bf3512Sdrh return TCL_OK; 257d1bf3512Sdrh } 258d1bf3512Sdrh 259af9ff33aSdrh 260af9ff33aSdrh /* 2616f8a503dSdanielk1977 ** Usage: sqlite3_last_insert_rowid DB 262af9ff33aSdrh ** 263af9ff33aSdrh ** Returns the integer ROWID of the most recent insert. 264af9ff33aSdrh */ 265af9ff33aSdrh static int test_last_rowid( 266af9ff33aSdrh void *NotUsed, 267af9ff33aSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 268af9ff33aSdrh int argc, /* Number of arguments */ 269af9ff33aSdrh char **argv /* Text of each argument */ 270af9ff33aSdrh ){ 271af9ff33aSdrh sqlite *db; 272af9ff33aSdrh char zBuf[30]; 273af9ff33aSdrh 274af9ff33aSdrh if( argc!=2 ){ 275af9ff33aSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0); 276af9ff33aSdrh return TCL_ERROR; 277af9ff33aSdrh } 278b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 2796f8a503dSdanielk1977 sprintf(zBuf, "%d", sqlite3_last_insert_rowid(db)); 280af9ff33aSdrh Tcl_AppendResult(interp, zBuf, 0); 281af9ff33aSdrh return SQLITE_OK; 282af9ff33aSdrh } 283af9ff33aSdrh 284d1bf3512Sdrh /* 2856f8a503dSdanielk1977 ** Usage: sqlite3_close DB 286d1bf3512Sdrh ** 2876f8a503dSdanielk1977 ** Closes the database opened by sqlite3_open. 288d1bf3512Sdrh */ 289d1bf3512Sdrh static int sqlite_test_close( 290d1bf3512Sdrh void *NotUsed, 291d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 292d1bf3512Sdrh int argc, /* Number of arguments */ 293d1bf3512Sdrh char **argv /* Text of each argument */ 294d1bf3512Sdrh ){ 295d1bf3512Sdrh sqlite *db; 296d1bf3512Sdrh if( argc!=2 ){ 297d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 298d1bf3512Sdrh " FILENAME\"", 0); 299d1bf3512Sdrh return TCL_ERROR; 300d1bf3512Sdrh } 301b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 3026f8a503dSdanielk1977 sqlite3_close(db); 303d1bf3512Sdrh return TCL_OK; 304d1bf3512Sdrh } 305d1bf3512Sdrh 306d1bf3512Sdrh /* 307c22bd47dSdrh ** Implementation of the x_coalesce() function. 308c22bd47dSdrh ** Return the first argument non-NULL argument. 309c22bd47dSdrh */ 310c22bd47dSdrh static void ifnullFunc(sqlite_func *context, int argc, const char **argv){ 311c22bd47dSdrh int i; 312c22bd47dSdrh for(i=0; i<argc; i++){ 313c22bd47dSdrh if( argv[i] ){ 3146f8a503dSdanielk1977 sqlite3_set_result_string(context, argv[i], -1); 315c22bd47dSdrh break; 316c22bd47dSdrh } 317c22bd47dSdrh } 318c22bd47dSdrh } 319c22bd47dSdrh 320c22bd47dSdrh /* 321d1d9fc33Sdrh ** A structure into which to accumulate text. 322d1d9fc33Sdrh */ 323d1d9fc33Sdrh struct dstr { 324d1d9fc33Sdrh int nAlloc; /* Space allocated */ 325d1d9fc33Sdrh int nUsed; /* Space used */ 326d1d9fc33Sdrh char *z; /* The space */ 327d1d9fc33Sdrh }; 328d1d9fc33Sdrh 329d1d9fc33Sdrh /* 330d1d9fc33Sdrh ** Append text to a dstr 331d1d9fc33Sdrh */ 332d1d9fc33Sdrh static void dstrAppend(struct dstr *p, const char *z, int divider){ 333d1d9fc33Sdrh int n = strlen(z); 334d1d9fc33Sdrh if( p->nUsed + n + 2 > p->nAlloc ){ 335d1d9fc33Sdrh char *zNew; 336d1d9fc33Sdrh p->nAlloc = p->nAlloc*2 + n + 200; 337d1d9fc33Sdrh zNew = sqliteRealloc(p->z, p->nAlloc); 338d1d9fc33Sdrh if( zNew==0 ){ 339d1d9fc33Sdrh sqliteFree(p->z); 340d1d9fc33Sdrh memset(p, 0, sizeof(*p)); 341d1d9fc33Sdrh return; 342d1d9fc33Sdrh } 343d1d9fc33Sdrh p->z = zNew; 344d1d9fc33Sdrh } 345d1d9fc33Sdrh if( divider && p->nUsed>0 ){ 346d1d9fc33Sdrh p->z[p->nUsed++] = divider; 347d1d9fc33Sdrh } 348d1d9fc33Sdrh memcpy(&p->z[p->nUsed], z, n+1); 349d1d9fc33Sdrh p->nUsed += n; 350d1d9fc33Sdrh } 351d1d9fc33Sdrh 352d1d9fc33Sdrh /* 3534adee20fSdanielk1977 ** Invoked for each callback from sqlite3ExecFunc 354d1d9fc33Sdrh */ 355d1d9fc33Sdrh static int execFuncCallback(void *pData, int argc, char **argv, char **NotUsed){ 356d1d9fc33Sdrh struct dstr *p = (struct dstr*)pData; 357d1d9fc33Sdrh int i; 358d1d9fc33Sdrh for(i=0; i<argc; i++){ 359d1d9fc33Sdrh if( argv[i]==0 ){ 360d1d9fc33Sdrh dstrAppend(p, "NULL", ' '); 361d1d9fc33Sdrh }else{ 362d1d9fc33Sdrh dstrAppend(p, argv[i], ' '); 363d1d9fc33Sdrh } 364d1d9fc33Sdrh } 365d1d9fc33Sdrh return 0; 366d1d9fc33Sdrh } 367d1d9fc33Sdrh 368d1d9fc33Sdrh /* 3696f8a503dSdanielk1977 ** Implementation of the x_sqlite3_exec() function. This function takes 370c22bd47dSdrh ** a single argument and attempts to execute that argument as SQL code. 3716cbe1f1bSdrh ** This is illegal and should set the SQLITE_MISUSE flag on the database. 372c22bd47dSdrh ** 3736f8a503dSdanielk1977 ** 2004-Jan-07: We have changed this to make it legal to call sqlite3_exec() 374d1d9fc33Sdrh ** from within a function call. 375d1d9fc33Sdrh ** 376c22bd47dSdrh ** This routine simulates the effect of having two threads attempt to 377c22bd47dSdrh ** use the same database at the same time. 378c22bd47dSdrh */ 3794adee20fSdanielk1977 static void sqlite3ExecFunc(sqlite_func *context, int argc, const char **argv){ 380d1d9fc33Sdrh struct dstr x; 381d1d9fc33Sdrh memset(&x, 0, sizeof(x)); 3826f8a503dSdanielk1977 sqlite3_exec((sqlite*)sqlite3_user_data(context), argv[0], 383d1d9fc33Sdrh execFuncCallback, &x, 0); 3846f8a503dSdanielk1977 sqlite3_set_result_string(context, x.z, x.nUsed); 385d1d9fc33Sdrh sqliteFree(x.z); 386c22bd47dSdrh } 387c22bd47dSdrh 388c22bd47dSdrh /* 389c22bd47dSdrh ** Usage: sqlite_test_create_function DB 390c22bd47dSdrh ** 3916f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order 392c22bd47dSdrh ** to create a function named "x_coalesce". This function does the same thing 393c22bd47dSdrh ** as the "coalesce" function. This function also registers an SQL function 3946f8a503dSdanielk1977 ** named "x_sqlite3_exec" that invokes sqlite3_exec(). Invoking sqlite3_exec() 395c22bd47dSdrh ** in this way is illegal recursion and should raise an SQLITE_MISUSE error. 396c22bd47dSdrh ** The effect is similar to trying to use the same database connection from 397c22bd47dSdrh ** two threads at the same time. 398c22bd47dSdrh ** 399c22bd47dSdrh ** The original motivation for this routine was to be able to call the 4006f8a503dSdanielk1977 ** sqlite3_create_function function while a query is in progress in order 401c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic. 402c22bd47dSdrh */ 403c2eef3b3Sdrh static int test_create_function( 404c22bd47dSdrh void *NotUsed, 405c22bd47dSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 406c22bd47dSdrh int argc, /* Number of arguments */ 407c22bd47dSdrh char **argv /* Text of each argument */ 408c22bd47dSdrh ){ 409c22bd47dSdrh sqlite *db; 410c22bd47dSdrh extern void Md5_Register(sqlite*); 411c22bd47dSdrh if( argc!=2 ){ 412c22bd47dSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 413c22bd47dSdrh " FILENAME\"", 0); 414c22bd47dSdrh return TCL_ERROR; 415c22bd47dSdrh } 416b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 4176f8a503dSdanielk1977 sqlite3_create_function(db, "x_coalesce", -1, ifnullFunc, 0); 4186f8a503dSdanielk1977 sqlite3_create_function(db, "x_sqlite3_exec", 1, sqlite3ExecFunc, db); 419c22bd47dSdrh return TCL_OK; 420c22bd47dSdrh } 421c22bd47dSdrh 422c22bd47dSdrh /* 423c22bd47dSdrh ** Routines to implement the x_count() aggregate function. 424c22bd47dSdrh */ 425c22bd47dSdrh typedef struct CountCtx CountCtx; 426c22bd47dSdrh struct CountCtx { 427c22bd47dSdrh int n; 428c22bd47dSdrh }; 429c22bd47dSdrh static void countStep(sqlite_func *context, int argc, const char **argv){ 430c22bd47dSdrh CountCtx *p; 4316f8a503dSdanielk1977 p = sqlite3_aggregate_context(context, sizeof(*p)); 432c22bd47dSdrh if( (argc==0 || argv[0]) && p ){ 433c22bd47dSdrh p->n++; 434c22bd47dSdrh } 435c22bd47dSdrh } 436c22bd47dSdrh static void countFinalize(sqlite_func *context){ 437c22bd47dSdrh CountCtx *p; 4386f8a503dSdanielk1977 p = sqlite3_aggregate_context(context, sizeof(*p)); 4396f8a503dSdanielk1977 sqlite3_set_result_int(context, p ? p->n : 0); 440c22bd47dSdrh } 441c22bd47dSdrh 442c22bd47dSdrh /* 443c22bd47dSdrh ** Usage: sqlite_test_create_aggregate DB 444c22bd47dSdrh ** 4456f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order 446c22bd47dSdrh ** to create a function named "x_count". This function does the same thing 447c22bd47dSdrh ** as the "md5sum" function. 448c22bd47dSdrh ** 449c22bd47dSdrh ** The original motivation for this routine was to be able to call the 4506f8a503dSdanielk1977 ** sqlite3_create_aggregate function while a query is in progress in order 451c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic. 452c22bd47dSdrh */ 453c2eef3b3Sdrh static int test_create_aggregate( 454c22bd47dSdrh void *NotUsed, 455c22bd47dSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 456c22bd47dSdrh int argc, /* Number of arguments */ 457c22bd47dSdrh char **argv /* Text of each argument */ 458c22bd47dSdrh ){ 459c22bd47dSdrh sqlite *db; 460c22bd47dSdrh if( argc!=2 ){ 461c22bd47dSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 462c22bd47dSdrh " FILENAME\"", 0); 463c22bd47dSdrh return TCL_ERROR; 464c22bd47dSdrh } 465b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 4666f8a503dSdanielk1977 sqlite3_create_aggregate(db, "x_count", 0, countStep, countFinalize, 0); 4676f8a503dSdanielk1977 sqlite3_create_aggregate(db, "x_count", 1, countStep, countFinalize, 0); 468c22bd47dSdrh return TCL_OK; 469c22bd47dSdrh } 470c22bd47dSdrh 471c22bd47dSdrh 472c22bd47dSdrh 473c22bd47dSdrh /* 4746f8a503dSdanielk1977 ** Usage: sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER 475d1bf3512Sdrh ** 476d1bf3512Sdrh ** Call mprintf with three integer arguments 477d1bf3512Sdrh */ 4786f8a503dSdanielk1977 static int sqlite3_mprintf_int( 479d1bf3512Sdrh void *NotUsed, 480d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 481d1bf3512Sdrh int argc, /* Number of arguments */ 482d1bf3512Sdrh char **argv /* Text of each argument */ 483d1bf3512Sdrh ){ 484d1bf3512Sdrh int a[3], i; 485d1bf3512Sdrh char *z; 486d1bf3512Sdrh if( argc!=5 ){ 487d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 488d1bf3512Sdrh " FORMAT INT INT INT\"", 0); 489d1bf3512Sdrh return TCL_ERROR; 490d1bf3512Sdrh } 491d1bf3512Sdrh for(i=2; i<5; i++){ 492d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 493d1bf3512Sdrh } 4946f8a503dSdanielk1977 z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]); 495d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 4966f8a503dSdanielk1977 sqlite3_freemem(z); 497d1bf3512Sdrh return TCL_OK; 498d1bf3512Sdrh } 499d1bf3512Sdrh 500d1bf3512Sdrh /* 5016f8a503dSdanielk1977 ** Usage: sqlite3_mprintf_str FORMAT INTEGER INTEGER STRING 502d1bf3512Sdrh ** 503d1bf3512Sdrh ** Call mprintf with two integer arguments and one string argument 504d1bf3512Sdrh */ 5056f8a503dSdanielk1977 static int sqlite3_mprintf_str( 506d1bf3512Sdrh void *NotUsed, 507d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 508d1bf3512Sdrh int argc, /* Number of arguments */ 509d1bf3512Sdrh char **argv /* Text of each argument */ 510d1bf3512Sdrh ){ 511d1bf3512Sdrh int a[3], i; 512d1bf3512Sdrh char *z; 513f220b24fSchw if( argc<4 || argc>5 ){ 514d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 515f220b24fSchw " FORMAT INT INT ?STRING?\"", 0); 516d1bf3512Sdrh return TCL_ERROR; 517d1bf3512Sdrh } 518d1bf3512Sdrh for(i=2; i<4; i++){ 519d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 520d1bf3512Sdrh } 5216f8a503dSdanielk1977 z = sqlite3_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL); 522d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 5236f8a503dSdanielk1977 sqlite3_freemem(z); 524d1bf3512Sdrh return TCL_OK; 525d1bf3512Sdrh } 526d1bf3512Sdrh 527d1bf3512Sdrh /* 5286f8a503dSdanielk1977 ** Usage: sqlite3_mprintf_str FORMAT INTEGER INTEGER DOUBLE 529d1bf3512Sdrh ** 530d1bf3512Sdrh ** Call mprintf with two integer arguments and one double argument 531d1bf3512Sdrh */ 5326f8a503dSdanielk1977 static int sqlite3_mprintf_double( 533d1bf3512Sdrh void *NotUsed, 534d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 535d1bf3512Sdrh int argc, /* Number of arguments */ 536d1bf3512Sdrh char **argv /* Text of each argument */ 537d1bf3512Sdrh ){ 538d1bf3512Sdrh int a[3], i; 539d1bf3512Sdrh double r; 540d1bf3512Sdrh char *z; 541d1bf3512Sdrh if( argc!=5 ){ 542d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 543d1bf3512Sdrh " FORMAT INT INT STRING\"", 0); 544d1bf3512Sdrh return TCL_ERROR; 545d1bf3512Sdrh } 546d1bf3512Sdrh for(i=2; i<4; i++){ 547d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 548d1bf3512Sdrh } 549d1bf3512Sdrh if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR; 5506f8a503dSdanielk1977 z = sqlite3_mprintf(argv[1], a[0], a[1], r); 551d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 5526f8a503dSdanielk1977 sqlite3_freemem(z); 553d1bf3512Sdrh return TCL_OK; 554d1bf3512Sdrh } 555d1bf3512Sdrh 556d1bf3512Sdrh /* 5576f8a503dSdanielk1977 ** Usage: sqlite3_mprintf_str FORMAT DOUBLE DOUBLE 558b621c237Sdrh ** 559b621c237Sdrh ** Call mprintf with a single double argument which is the product of the 560b621c237Sdrh ** two arguments given above. This is used to generate overflow and underflow 561b621c237Sdrh ** doubles to test that they are converted properly. 562b621c237Sdrh */ 5636f8a503dSdanielk1977 static int sqlite3_mprintf_scaled( 564b621c237Sdrh void *NotUsed, 565b621c237Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 566b621c237Sdrh int argc, /* Number of arguments */ 567b621c237Sdrh char **argv /* Text of each argument */ 568b621c237Sdrh ){ 569b621c237Sdrh int i; 570b621c237Sdrh double r[2]; 571b621c237Sdrh char *z; 572b621c237Sdrh if( argc!=4 ){ 573b621c237Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 574b621c237Sdrh " FORMAT DOUBLE DOUBLE\"", 0); 575b621c237Sdrh return TCL_ERROR; 576b621c237Sdrh } 577b621c237Sdrh for(i=2; i<4; i++){ 578b621c237Sdrh if( Tcl_GetDouble(interp, argv[i], &r[i-2]) ) return TCL_ERROR; 579b621c237Sdrh } 5806f8a503dSdanielk1977 z = sqlite3_mprintf(argv[1], r[0]*r[1]); 581b621c237Sdrh Tcl_AppendResult(interp, z, 0); 5826f8a503dSdanielk1977 sqlite3_freemem(z); 583b621c237Sdrh return TCL_OK; 584b621c237Sdrh } 585b621c237Sdrh 586b621c237Sdrh /* 587daffd0e5Sdrh ** Usage: sqlite_malloc_fail N 588daffd0e5Sdrh ** 589afa4a020Sdrh ** Rig sqliteMalloc() to fail on the N-th call. Turn off this mechanism 5906f8a503dSdanielk1977 ** and reset the sqlite3_malloc_failed variable is N==0. 591daffd0e5Sdrh */ 592daffd0e5Sdrh #ifdef MEMORY_DEBUG 593daffd0e5Sdrh static int sqlite_malloc_fail( 594daffd0e5Sdrh void *NotUsed, 595daffd0e5Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 596daffd0e5Sdrh int argc, /* Number of arguments */ 597daffd0e5Sdrh char **argv /* Text of each argument */ 598daffd0e5Sdrh ){ 599daffd0e5Sdrh int n; 600daffd0e5Sdrh if( argc!=2 ){ 601daffd0e5Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0); 602daffd0e5Sdrh return TCL_ERROR; 603daffd0e5Sdrh } 604daffd0e5Sdrh if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR; 6056f8a503dSdanielk1977 sqlite3_iMallocFail = n; 6066f8a503dSdanielk1977 sqlite3_malloc_failed = 0; 607daffd0e5Sdrh return TCL_OK; 608daffd0e5Sdrh } 609daffd0e5Sdrh #endif 610daffd0e5Sdrh 611daffd0e5Sdrh /* 612daffd0e5Sdrh ** Usage: sqlite_malloc_stat 613daffd0e5Sdrh ** 614daffd0e5Sdrh ** Return the number of prior calls to sqliteMalloc() and sqliteFree(). 615daffd0e5Sdrh */ 616daffd0e5Sdrh #ifdef MEMORY_DEBUG 617daffd0e5Sdrh static int sqlite_malloc_stat( 618daffd0e5Sdrh void *NotUsed, 619daffd0e5Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 620daffd0e5Sdrh int argc, /* Number of arguments */ 621daffd0e5Sdrh char **argv /* Text of each argument */ 622daffd0e5Sdrh ){ 623daffd0e5Sdrh char zBuf[200]; 6246f8a503dSdanielk1977 sprintf(zBuf, "%d %d %d", sqlite3_nMalloc, sqlite3_nFree, sqlite3_iMallocFail); 625daffd0e5Sdrh Tcl_AppendResult(interp, zBuf, 0); 626daffd0e5Sdrh return TCL_OK; 627daffd0e5Sdrh } 628daffd0e5Sdrh #endif 629daffd0e5Sdrh 630daffd0e5Sdrh /* 63128b4e489Sdrh ** Usage: sqlite_abort 63228b4e489Sdrh ** 63328b4e489Sdrh ** Shutdown the process immediately. This is not a clean shutdown. 63428b4e489Sdrh ** This command is used to test the recoverability of a database in 63528b4e489Sdrh ** the event of a program crash. 63628b4e489Sdrh */ 63728b4e489Sdrh static int sqlite_abort( 63828b4e489Sdrh void *NotUsed, 63928b4e489Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 64028b4e489Sdrh int argc, /* Number of arguments */ 64128b4e489Sdrh char **argv /* Text of each argument */ 64228b4e489Sdrh ){ 64328b4e489Sdrh assert( interp==0 ); /* This will always fail */ 64428b4e489Sdrh return TCL_OK; 64528b4e489Sdrh } 64628b4e489Sdrh 64728b4e489Sdrh /* 6486cbe1f1bSdrh ** The following routine is a user-defined SQL function whose purpose 6496cbe1f1bSdrh ** is to test the sqlite_set_result() API. 6506cbe1f1bSdrh */ 6516cbe1f1bSdrh static void testFunc(sqlite_func *context, int argc, const char **argv){ 6526cbe1f1bSdrh while( argc>=2 ){ 6536cbe1f1bSdrh if( argv[0]==0 ){ 6546f8a503dSdanielk1977 sqlite3_set_result_error(context, "first argument to test function " 6556cbe1f1bSdrh "may not be NULL", -1); 6564adee20fSdanielk1977 }else if( sqlite3StrICmp(argv[0],"string")==0 ){ 6576f8a503dSdanielk1977 sqlite3_set_result_string(context, argv[1], -1); 6586cbe1f1bSdrh }else if( argv[1]==0 ){ 6596f8a503dSdanielk1977 sqlite3_set_result_error(context, "2nd argument may not be NULL if the " 6606cbe1f1bSdrh "first argument is not \"string\"", -1); 6614adee20fSdanielk1977 }else if( sqlite3StrICmp(argv[0],"int")==0 ){ 6626f8a503dSdanielk1977 sqlite3_set_result_int(context, atoi(argv[1])); 6634adee20fSdanielk1977 }else if( sqlite3StrICmp(argv[0],"double")==0 ){ 6646f8a503dSdanielk1977 sqlite3_set_result_double(context, sqlite3AtoF(argv[1], 0)); 6656cbe1f1bSdrh }else{ 6666f8a503dSdanielk1977 sqlite3_set_result_error(context,"first argument should be one of: " 6676cbe1f1bSdrh "string int double", -1); 6686cbe1f1bSdrh } 6696cbe1f1bSdrh argc -= 2; 6706cbe1f1bSdrh argv += 2; 6716cbe1f1bSdrh } 6726cbe1f1bSdrh } 6736cbe1f1bSdrh 6746cbe1f1bSdrh /* 6756cbe1f1bSdrh ** Usage: sqlite_register_test_function DB NAME 6766cbe1f1bSdrh ** 6776cbe1f1bSdrh ** Register the test SQL function on the database DB under the name NAME. 6786cbe1f1bSdrh */ 679c2eef3b3Sdrh static int test_register_func( 6806cbe1f1bSdrh void *NotUsed, 6816cbe1f1bSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 6826cbe1f1bSdrh int argc, /* Number of arguments */ 6836cbe1f1bSdrh char **argv /* Text of each argument */ 6846cbe1f1bSdrh ){ 6856cbe1f1bSdrh sqlite *db; 6866cbe1f1bSdrh int rc; 6876cbe1f1bSdrh if( argc!=3 ){ 6886cbe1f1bSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 6896cbe1f1bSdrh " DB FUNCTION-NAME", 0); 6906cbe1f1bSdrh return TCL_ERROR; 6916cbe1f1bSdrh } 692b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 6936f8a503dSdanielk1977 rc = sqlite3_create_function(db, argv[2], -1, testFunc, 0); 6946cbe1f1bSdrh if( rc!=0 ){ 6956f8a503dSdanielk1977 Tcl_AppendResult(interp, sqlite3_error_string(rc), 0); 6966cbe1f1bSdrh return TCL_ERROR; 6976cbe1f1bSdrh } 6986cbe1f1bSdrh return TCL_OK; 6996cbe1f1bSdrh } 7006cbe1f1bSdrh 7016cbe1f1bSdrh /* 7025a38705eSdrh ** This SQLite callback records the datatype of all columns. 7035a38705eSdrh ** 7045a38705eSdrh ** The pArg argument is really a pointer to a TCL interpreter. The 7055a38705eSdrh ** column names are inserted as the result of this interpreter. 7065a38705eSdrh ** 7075a38705eSdrh ** This routine returns non-zero which causes the query to abort. 7085a38705eSdrh */ 7095a38705eSdrh static int rememberDataTypes(void *pArg, int nCol, char **argv, char **colv){ 7105a38705eSdrh int i; 7115a38705eSdrh Tcl_Interp *interp = (Tcl_Interp*)pArg; 7125a38705eSdrh Tcl_Obj *pList, *pElem; 7135a38705eSdrh if( colv[nCol+1]==0 ){ 7145a38705eSdrh return 1; 7155a38705eSdrh } 7165a38705eSdrh pList = Tcl_NewObj(); 7175a38705eSdrh for(i=0; i<nCol; i++){ 7185a38705eSdrh pElem = Tcl_NewStringObj(colv[i+nCol] ? colv[i+nCol] : "NULL", -1); 7195a38705eSdrh Tcl_ListObjAppendElement(interp, pList, pElem); 7205a38705eSdrh } 7215a38705eSdrh Tcl_SetObjResult(interp, pList); 7225a38705eSdrh return 1; 7235a38705eSdrh } 7245a38705eSdrh 7255a38705eSdrh /* 7265a38705eSdrh ** Invoke an SQL statement but ignore all the data in the result. Instead, 7275a38705eSdrh ** return a list that consists of the datatypes of the various columns. 7285a38705eSdrh ** 7295a38705eSdrh ** This only works if "PRAGMA show_datatypes=on" has been executed against 7305a38705eSdrh ** the database connection. 7315a38705eSdrh */ 7325a38705eSdrh static int sqlite_datatypes( 7335a38705eSdrh void *NotUsed, 7345a38705eSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 7355a38705eSdrh int argc, /* Number of arguments */ 7365a38705eSdrh char **argv /* Text of each argument */ 7375a38705eSdrh ){ 7385a38705eSdrh sqlite *db; 7395a38705eSdrh int rc; 7405a38705eSdrh if( argc!=3 ){ 7415a38705eSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 7425a38705eSdrh " DB SQL", 0); 7435a38705eSdrh return TCL_ERROR; 7445a38705eSdrh } 745b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 7466f8a503dSdanielk1977 rc = sqlite3_exec(db, argv[2], rememberDataTypes, interp, 0); 7475a38705eSdrh if( rc!=0 && rc!=SQLITE_ABORT ){ 7486f8a503dSdanielk1977 Tcl_AppendResult(interp, sqlite3_error_string(rc), 0); 7495a38705eSdrh return TCL_ERROR; 7505a38705eSdrh } 7515a38705eSdrh return TCL_OK; 7525a38705eSdrh } 7535a38705eSdrh 754b86ccfb2Sdrh /* 7556f8a503dSdanielk1977 ** Usage: sqlite3_step VM ?NVAR? ?VALUEVAR? ?COLNAMEVAR? 756b86ccfb2Sdrh ** 757b86ccfb2Sdrh ** Step a virtual machine. Return a the result code as a string. 758b86ccfb2Sdrh ** Column results are written into three variables. 759b86ccfb2Sdrh */ 760b86ccfb2Sdrh static int test_step( 761b86ccfb2Sdrh void *NotUsed, 762b86ccfb2Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 763b86ccfb2Sdrh int argc, /* Number of arguments */ 764b86ccfb2Sdrh char **argv /* Text of each argument */ 765b86ccfb2Sdrh ){ 766b86ccfb2Sdrh sqlite_vm *vm; 767b86ccfb2Sdrh int rc, i; 7683a84069dSdrh const char **azValue = 0; 7693a84069dSdrh const char **azColName = 0; 7703a84069dSdrh int N = 0; 771b86ccfb2Sdrh char *zRc; 772b86ccfb2Sdrh char zBuf[50]; 773073e5a77Sdrh if( argc<2 || argc>5 ){ 774b86ccfb2Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 775b86ccfb2Sdrh " VM NVAR VALUEVAR COLNAMEVAR", 0); 776b86ccfb2Sdrh return TCL_ERROR; 777b86ccfb2Sdrh } 778b86ccfb2Sdrh if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR; 7796f8a503dSdanielk1977 rc = sqlite3_step(vm, argc>=3?&N:0, argc>=4?&azValue:0, argc==5?&azColName:0); 780073e5a77Sdrh if( argc>=3 ){ 781b86ccfb2Sdrh sprintf(zBuf, "%d", N); 782b86ccfb2Sdrh Tcl_SetVar(interp, argv[2], zBuf, 0); 783073e5a77Sdrh } 784073e5a77Sdrh if( argc>=4 ){ 785b86ccfb2Sdrh Tcl_SetVar(interp, argv[3], "", 0); 7863a84069dSdrh if( azValue ){ 787b86ccfb2Sdrh for(i=0; i<N; i++){ 788b86ccfb2Sdrh Tcl_SetVar(interp, argv[3], azValue[i] ? azValue[i] : "", 789b86ccfb2Sdrh TCL_APPEND_VALUE | TCL_LIST_ELEMENT); 790b86ccfb2Sdrh } 791b86ccfb2Sdrh } 792073e5a77Sdrh } 793073e5a77Sdrh if( argc==5 ){ 794b86ccfb2Sdrh Tcl_SetVar(interp, argv[4], "", 0); 7953a84069dSdrh if( azColName ){ 796b86ccfb2Sdrh for(i=0; i<N*2; i++){ 797326dce74Sdrh Tcl_SetVar(interp, argv[4], azColName[i] ? azColName[i] : "", 798b86ccfb2Sdrh TCL_APPEND_VALUE | TCL_LIST_ELEMENT); 799b86ccfb2Sdrh } 800b86ccfb2Sdrh } 801073e5a77Sdrh } 802b86ccfb2Sdrh switch( rc ){ 803b86ccfb2Sdrh case SQLITE_DONE: zRc = "SQLITE_DONE"; break; 804326dce74Sdrh case SQLITE_BUSY: zRc = "SQLITE_BUSY"; break; 805326dce74Sdrh case SQLITE_ROW: zRc = "SQLITE_ROW"; break; 806326dce74Sdrh case SQLITE_ERROR: zRc = "SQLITE_ERROR"; break; 807b86ccfb2Sdrh case SQLITE_MISUSE: zRc = "SQLITE_MISUSE"; break; 808b86ccfb2Sdrh default: zRc = "unknown"; break; 809b86ccfb2Sdrh } 810b86ccfb2Sdrh Tcl_AppendResult(interp, zRc, 0); 811b86ccfb2Sdrh return TCL_OK; 812b86ccfb2Sdrh } 813b86ccfb2Sdrh 814b86ccfb2Sdrh /* 815106bb236Sdanielk1977 ** Usage: sqlite3_finalize STMT 816b86ccfb2Sdrh ** 817106bb236Sdanielk1977 ** Finalize a statement handle. 818b86ccfb2Sdrh */ 819b86ccfb2Sdrh static int test_finalize( 820106bb236Sdanielk1977 void * clientData, 821106bb236Sdanielk1977 Tcl_Interp *interp, 822106bb236Sdanielk1977 int objc, 823106bb236Sdanielk1977 Tcl_Obj *CONST objv[] 824b86ccfb2Sdrh ){ 825106bb236Sdanielk1977 sqlite3_stmt *pStmt; 826b86ccfb2Sdrh int rc; 827106bb236Sdanielk1977 828106bb236Sdanielk1977 if( objc!=2 ){ 829106bb236Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 830106bb236Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0); 831b86ccfb2Sdrh return TCL_ERROR; 832b86ccfb2Sdrh } 833106bb236Sdanielk1977 834106bb236Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 835106bb236Sdanielk1977 836106bb236Sdanielk1977 rc = sqlite3_finalize_new(pStmt); 837b86ccfb2Sdrh if( rc ){ 838106bb236Sdanielk1977 return TCL_ERROR; 839106bb236Sdanielk1977 } 840106bb236Sdanielk1977 return TCL_OK; 841106bb236Sdanielk1977 } 842106bb236Sdanielk1977 843106bb236Sdanielk1977 /* 844106bb236Sdanielk1977 ** Usage: sqlite3_reset STMT 845106bb236Sdanielk1977 ** 846106bb236Sdanielk1977 ** Finalize a statement handle. 847106bb236Sdanielk1977 */ 848106bb236Sdanielk1977 static int test_reset( 849106bb236Sdanielk1977 void * clientData, 850106bb236Sdanielk1977 Tcl_Interp *interp, 851106bb236Sdanielk1977 int objc, 852106bb236Sdanielk1977 Tcl_Obj *CONST objv[] 853106bb236Sdanielk1977 ){ 854106bb236Sdanielk1977 sqlite3_stmt *pStmt; 855106bb236Sdanielk1977 int rc; 856106bb236Sdanielk1977 857106bb236Sdanielk1977 if( objc!=2 ){ 858106bb236Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 859106bb236Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0); 860106bb236Sdanielk1977 return TCL_ERROR; 861106bb236Sdanielk1977 } 862106bb236Sdanielk1977 863106bb236Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 864106bb236Sdanielk1977 865106bb236Sdanielk1977 rc = sqlite3_reset_new(pStmt); 866106bb236Sdanielk1977 if( rc ){ 867b86ccfb2Sdrh return TCL_ERROR; 868b86ccfb2Sdrh } 869b86ccfb2Sdrh return TCL_OK; 870b86ccfb2Sdrh } 871b86ccfb2Sdrh 8725a38705eSdrh /* 8736f8a503dSdanielk1977 ** Usage: sqlite3_reset VM 87450457896Sdrh ** 87550457896Sdrh ** Reset a virtual machine and prepare it to be run again. 87650457896Sdrh */ 87750457896Sdrh 87850457896Sdrh /* 8797c972decSdrh ** This is the "static_bind_value" that variables are bound to when 8806f8a503dSdanielk1977 ** the FLAG option of sqlite3_bind is "static" 88150457896Sdrh */ 8827c972decSdrh static char *sqlite_static_bind_value = 0; 8837c972decSdrh 8847c972decSdrh /* 8856f8a503dSdanielk1977 ** Usage: sqlite3_bind VM IDX VALUE FLAGS 8867c972decSdrh ** 8877c972decSdrh ** Sets the value of the IDX-th occurance of "?" in the original SQL 8887c972decSdrh ** string. VALUE is the new value. If FLAGS=="null" then VALUE is 8897c972decSdrh ** ignored and the value is set to NULL. If FLAGS=="static" then 8907c972decSdrh ** the value is set to the value of a static variable named 8917c972decSdrh ** "sqlite_static_bind_value". If FLAGS=="normal" then a copy 8927c972decSdrh ** of the VALUE is made. 8937c972decSdrh */ 8947c972decSdrh static int test_bind( 89550457896Sdrh void *NotUsed, 89650457896Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 89750457896Sdrh int argc, /* Number of arguments */ 89850457896Sdrh char **argv /* Text of each argument */ 89950457896Sdrh ){ 90050457896Sdrh sqlite_vm *vm; 90150457896Sdrh int rc; 9027c972decSdrh int idx; 9037c972decSdrh if( argc!=5 ){ 90450457896Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 9057c972decSdrh " VM IDX VALUE (null|static|normal)\"", 0); 90650457896Sdrh return TCL_ERROR; 90750457896Sdrh } 90850457896Sdrh if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR; 9097c972decSdrh if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR; 9107c972decSdrh if( strcmp(argv[4],"null")==0 ){ 9116f8a503dSdanielk1977 rc = sqlite3_bind(vm, idx, 0, 0, 0); 9127c972decSdrh }else if( strcmp(argv[4],"static")==0 ){ 9136f8a503dSdanielk1977 rc = sqlite3_bind(vm, idx, sqlite_static_bind_value, -1, 0); 9147c972decSdrh }else if( strcmp(argv[4],"normal")==0 ){ 9156f8a503dSdanielk1977 rc = sqlite3_bind(vm, idx, argv[3], -1, 1); 9167c972decSdrh }else{ 9177c972decSdrh Tcl_AppendResult(interp, "4th argument should be " 9187c972decSdrh "\"null\" or \"static\" or \"normal\"", 0); 9197c972decSdrh return TCL_ERROR; 9207c972decSdrh } 92150457896Sdrh if( rc ){ 92250457896Sdrh char zBuf[50]; 92350457896Sdrh sprintf(zBuf, "(%d) ", rc); 9246f8a503dSdanielk1977 Tcl_AppendResult(interp, zBuf, sqlite3_error_string(rc), 0); 92550457896Sdrh return TCL_ERROR; 92650457896Sdrh } 92750457896Sdrh return TCL_OK; 92850457896Sdrh } 92950457896Sdrh 93050457896Sdrh /* 93199ee3600Sdrh ** Usage: breakpoint 93299ee3600Sdrh ** 93399ee3600Sdrh ** This routine exists for one purpose - to provide a place to put a 93499ee3600Sdrh ** breakpoint with GDB that can be triggered using TCL code. The use 93599ee3600Sdrh ** for this is when a particular test fails on (say) the 1485th iteration. 93699ee3600Sdrh ** In the TCL test script, we can add code like this: 93799ee3600Sdrh ** 93899ee3600Sdrh ** if {$i==1485} breakpoint 93999ee3600Sdrh ** 94099ee3600Sdrh ** Then run testfixture in the debugger and wait for the breakpoint to 94199ee3600Sdrh ** fire. Then additional breakpoints can be set to trace down the bug. 94299ee3600Sdrh */ 94399ee3600Sdrh static int test_breakpoint( 94499ee3600Sdrh void *NotUsed, 94599ee3600Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 94699ee3600Sdrh int argc, /* Number of arguments */ 94799ee3600Sdrh char **argv /* Text of each argument */ 94899ee3600Sdrh ){ 94999ee3600Sdrh return TCL_OK; /* Do nothing */ 95099ee3600Sdrh } 95199ee3600Sdrh 95251e3d8e2Sdanielk1977 static int test_bind_int32( 95351e3d8e2Sdanielk1977 void * clientData, 95451e3d8e2Sdanielk1977 Tcl_Interp *interp, 95551e3d8e2Sdanielk1977 int objc, 95651e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 95751e3d8e2Sdanielk1977 ){ 95851e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 95951e3d8e2Sdanielk1977 int idx; 96051e3d8e2Sdanielk1977 int value; 96151e3d8e2Sdanielk1977 int rc; 96251e3d8e2Sdanielk1977 96351e3d8e2Sdanielk1977 if( objc!=4 ){ 96451e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 96551e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0); 96651e3d8e2Sdanielk1977 return TCL_ERROR; 96751e3d8e2Sdanielk1977 } 96851e3d8e2Sdanielk1977 96951e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 97051e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 97151e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[3], &value) ) return TCL_ERROR; 97251e3d8e2Sdanielk1977 97351e3d8e2Sdanielk1977 rc = sqlite3_bind_int32(pStmt, idx, value); 97451e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 97551e3d8e2Sdanielk1977 return TCL_ERROR; 97651e3d8e2Sdanielk1977 } 97751e3d8e2Sdanielk1977 97851e3d8e2Sdanielk1977 return TCL_OK; 97951e3d8e2Sdanielk1977 } 98051e3d8e2Sdanielk1977 98151e3d8e2Sdanielk1977 static int test_bind_int64( 98251e3d8e2Sdanielk1977 void * clientData, 98351e3d8e2Sdanielk1977 Tcl_Interp *interp, 98451e3d8e2Sdanielk1977 int objc, 98551e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 98651e3d8e2Sdanielk1977 ){ 98751e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 98851e3d8e2Sdanielk1977 int idx; 98951e3d8e2Sdanielk1977 i64 value; 99051e3d8e2Sdanielk1977 int rc; 99151e3d8e2Sdanielk1977 99251e3d8e2Sdanielk1977 if( objc!=4 ){ 99351e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 99451e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0); 99551e3d8e2Sdanielk1977 return TCL_ERROR; 99651e3d8e2Sdanielk1977 } 99751e3d8e2Sdanielk1977 99851e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 99951e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 100051e3d8e2Sdanielk1977 if( Tcl_GetWideIntFromObj(interp, objv[3], &value) ) return TCL_ERROR; 100151e3d8e2Sdanielk1977 100251e3d8e2Sdanielk1977 rc = sqlite3_bind_int64(pStmt, idx, value); 100351e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 100451e3d8e2Sdanielk1977 return TCL_ERROR; 100551e3d8e2Sdanielk1977 } 100651e3d8e2Sdanielk1977 100751e3d8e2Sdanielk1977 return TCL_OK; 100851e3d8e2Sdanielk1977 } 100951e3d8e2Sdanielk1977 101051e3d8e2Sdanielk1977 static int test_bind_double( 101151e3d8e2Sdanielk1977 void * clientData, 101251e3d8e2Sdanielk1977 Tcl_Interp *interp, 101351e3d8e2Sdanielk1977 int objc, 101451e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 101551e3d8e2Sdanielk1977 ){ 101651e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 101751e3d8e2Sdanielk1977 int idx; 101851e3d8e2Sdanielk1977 double value; 101951e3d8e2Sdanielk1977 int rc; 102051e3d8e2Sdanielk1977 102151e3d8e2Sdanielk1977 if( objc!=4 ){ 102251e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 102351e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0); 102451e3d8e2Sdanielk1977 return TCL_ERROR; 102551e3d8e2Sdanielk1977 } 102651e3d8e2Sdanielk1977 102751e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 102851e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 102951e3d8e2Sdanielk1977 if( Tcl_GetDoubleFromObj(interp, objv[3], &value) ) return TCL_ERROR; 103051e3d8e2Sdanielk1977 103151e3d8e2Sdanielk1977 rc = sqlite3_bind_double(pStmt, idx, value); 103251e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 103351e3d8e2Sdanielk1977 return TCL_ERROR; 103451e3d8e2Sdanielk1977 } 103551e3d8e2Sdanielk1977 103651e3d8e2Sdanielk1977 return TCL_OK; 103751e3d8e2Sdanielk1977 } 103851e3d8e2Sdanielk1977 103951e3d8e2Sdanielk1977 static int test_bind_null( 104051e3d8e2Sdanielk1977 void * clientData, 104151e3d8e2Sdanielk1977 Tcl_Interp *interp, 104251e3d8e2Sdanielk1977 int objc, 104351e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 104451e3d8e2Sdanielk1977 ){ 104551e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 104651e3d8e2Sdanielk1977 int idx; 104751e3d8e2Sdanielk1977 int rc; 104851e3d8e2Sdanielk1977 104951e3d8e2Sdanielk1977 if( objc!=3 ){ 105051e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 105151e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.>", 0); 105251e3d8e2Sdanielk1977 return TCL_ERROR; 105351e3d8e2Sdanielk1977 } 105451e3d8e2Sdanielk1977 105551e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 105651e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 105751e3d8e2Sdanielk1977 105851e3d8e2Sdanielk1977 rc = sqlite3_bind_null(pStmt, idx); 105951e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 106051e3d8e2Sdanielk1977 return TCL_ERROR; 106151e3d8e2Sdanielk1977 } 106251e3d8e2Sdanielk1977 106351e3d8e2Sdanielk1977 return TCL_OK; 106451e3d8e2Sdanielk1977 } 106551e3d8e2Sdanielk1977 106651e3d8e2Sdanielk1977 static int test_bind_text( 106751e3d8e2Sdanielk1977 void * clientData, 106851e3d8e2Sdanielk1977 Tcl_Interp *interp, 106951e3d8e2Sdanielk1977 int objc, 107051e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 107151e3d8e2Sdanielk1977 ){ 107251e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 107351e3d8e2Sdanielk1977 int idx; 107451e3d8e2Sdanielk1977 int bytes; 107551e3d8e2Sdanielk1977 char *value; 107651e3d8e2Sdanielk1977 int rc; 107751e3d8e2Sdanielk1977 107851e3d8e2Sdanielk1977 if( objc!=5 ){ 107951e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 108051e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>" 108151e3d8e2Sdanielk1977 " <bytes>", 0); 108251e3d8e2Sdanielk1977 return TCL_ERROR; 108351e3d8e2Sdanielk1977 } 108451e3d8e2Sdanielk1977 108551e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 108651e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 108751e3d8e2Sdanielk1977 value = Tcl_GetString(objv[3]); 108851e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; 108951e3d8e2Sdanielk1977 109051e3d8e2Sdanielk1977 rc = sqlite3_bind_text(pStmt, idx, value, bytes, 1); 109151e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 109251e3d8e2Sdanielk1977 return TCL_ERROR; 109351e3d8e2Sdanielk1977 } 109451e3d8e2Sdanielk1977 109551e3d8e2Sdanielk1977 return TCL_OK; 109651e3d8e2Sdanielk1977 } 109751e3d8e2Sdanielk1977 109851e3d8e2Sdanielk1977 static int test_bind_text16( 109951e3d8e2Sdanielk1977 void * clientData, 110051e3d8e2Sdanielk1977 Tcl_Interp *interp, 110151e3d8e2Sdanielk1977 int objc, 110251e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 110351e3d8e2Sdanielk1977 ){ 110451e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 110551e3d8e2Sdanielk1977 int idx; 110651e3d8e2Sdanielk1977 int bytes; 110751e3d8e2Sdanielk1977 char *value; 110851e3d8e2Sdanielk1977 int rc; 110951e3d8e2Sdanielk1977 111051e3d8e2Sdanielk1977 if( objc!=5 ){ 111151e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 111251e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>" 111351e3d8e2Sdanielk1977 " <bytes>", 0); 111451e3d8e2Sdanielk1977 return TCL_ERROR; 111551e3d8e2Sdanielk1977 } 111651e3d8e2Sdanielk1977 111751e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 111851e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 111951e3d8e2Sdanielk1977 value = Tcl_GetByteArrayFromObj(objv[3], 0); 112051e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; 112151e3d8e2Sdanielk1977 112251e3d8e2Sdanielk1977 rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, 1); 112351e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 112451e3d8e2Sdanielk1977 return TCL_ERROR; 112551e3d8e2Sdanielk1977 } 112651e3d8e2Sdanielk1977 112751e3d8e2Sdanielk1977 return TCL_OK; 112851e3d8e2Sdanielk1977 } 112951e3d8e2Sdanielk1977 113051e3d8e2Sdanielk1977 static int test_bind_blob( 113151e3d8e2Sdanielk1977 void * clientData, 113251e3d8e2Sdanielk1977 Tcl_Interp *interp, 113351e3d8e2Sdanielk1977 int objc, 113451e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 113551e3d8e2Sdanielk1977 ){ 113651e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 113751e3d8e2Sdanielk1977 int idx; 113851e3d8e2Sdanielk1977 int bytes; 113951e3d8e2Sdanielk1977 char *value; 114051e3d8e2Sdanielk1977 int rc; 114151e3d8e2Sdanielk1977 114251e3d8e2Sdanielk1977 if( objc!=5 ){ 114351e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 114451e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>" 114551e3d8e2Sdanielk1977 " <bytes>", 0); 114651e3d8e2Sdanielk1977 return TCL_ERROR; 114751e3d8e2Sdanielk1977 } 114851e3d8e2Sdanielk1977 114951e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 115051e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 115151e3d8e2Sdanielk1977 value = Tcl_GetString(objv[3]); 115251e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &bytes) ) return TCL_ERROR; 115351e3d8e2Sdanielk1977 115451e3d8e2Sdanielk1977 rc = sqlite3_bind_blob(pStmt, idx, value, bytes, 1); 115551e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 115651e3d8e2Sdanielk1977 return TCL_ERROR; 115751e3d8e2Sdanielk1977 } 115851e3d8e2Sdanielk1977 115951e3d8e2Sdanielk1977 return TCL_OK; 116051e3d8e2Sdanielk1977 } 116151e3d8e2Sdanielk1977 116299ee3600Sdrh /* 11636622cce3Sdanielk1977 ** Usage: sqlite3_errcode DB 11646622cce3Sdanielk1977 ** 11656622cce3Sdanielk1977 ** Return the string representation of the most recent sqlite3_* API 11666622cce3Sdanielk1977 ** error code. e.g. "SQLITE_ERROR". 11676622cce3Sdanielk1977 */ 11686622cce3Sdanielk1977 static int test_errcode( 11696622cce3Sdanielk1977 void * clientData, 11706622cce3Sdanielk1977 Tcl_Interp *interp, 11716622cce3Sdanielk1977 int objc, 11726622cce3Sdanielk1977 Tcl_Obj *CONST objv[] 11736622cce3Sdanielk1977 ){ 11746622cce3Sdanielk1977 sqlite3 *db; 11756622cce3Sdanielk1977 11766622cce3Sdanielk1977 if( objc!=2 ){ 11776622cce3Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 11786622cce3Sdanielk1977 Tcl_GetString(objv[0]), " DB", 0); 11796622cce3Sdanielk1977 return TCL_ERROR; 11806622cce3Sdanielk1977 } 11816622cce3Sdanielk1977 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 11826622cce3Sdanielk1977 Tcl_SetResult(interp, (char *)errorName(sqlite3_errcode(db)), 0); 11836622cce3Sdanielk1977 return TCL_OK; 11846622cce3Sdanielk1977 } 11856622cce3Sdanielk1977 11866622cce3Sdanielk1977 /* 11876622cce3Sdanielk1977 ** Usage: test_errmsg DB 11886622cce3Sdanielk1977 ** 11896622cce3Sdanielk1977 ** Returns the UTF-8 representation of the error message string for the 11906622cce3Sdanielk1977 ** most recent sqlite3_* API call. 11916622cce3Sdanielk1977 */ 11926622cce3Sdanielk1977 static int test_errmsg( 11936622cce3Sdanielk1977 void * clientData, 11946622cce3Sdanielk1977 Tcl_Interp *interp, 11956622cce3Sdanielk1977 int objc, 11966622cce3Sdanielk1977 Tcl_Obj *CONST objv[] 11976622cce3Sdanielk1977 ){ 11986622cce3Sdanielk1977 sqlite *db; 11996622cce3Sdanielk1977 const char *zErr; 12006622cce3Sdanielk1977 12016622cce3Sdanielk1977 if( objc!=2 ){ 12026622cce3Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 12036622cce3Sdanielk1977 Tcl_GetString(objv[0]), " DB", 0); 12046622cce3Sdanielk1977 return TCL_ERROR; 12056622cce3Sdanielk1977 } 12066622cce3Sdanielk1977 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 12076622cce3Sdanielk1977 12086622cce3Sdanielk1977 zErr = sqlite3_errmsg(db); 12096622cce3Sdanielk1977 Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1)); 12106622cce3Sdanielk1977 return TCL_OK; 12116622cce3Sdanielk1977 } 12126622cce3Sdanielk1977 12136622cce3Sdanielk1977 /* 12146622cce3Sdanielk1977 ** Usage: test_errmsg16 DB 12156622cce3Sdanielk1977 ** 12166622cce3Sdanielk1977 ** Returns the UTF-16 representation of the error message string for the 12176622cce3Sdanielk1977 ** most recent sqlite3_* API call. This is a byte array object at the TCL 12186622cce3Sdanielk1977 ** level, and it includes the 0x00 0x00 terminator bytes at the end of the 12196622cce3Sdanielk1977 ** UTF-16 string. 12206622cce3Sdanielk1977 */ 12216622cce3Sdanielk1977 static int test_errmsg16( 12226622cce3Sdanielk1977 void * clientData, 12236622cce3Sdanielk1977 Tcl_Interp *interp, 12246622cce3Sdanielk1977 int objc, 12256622cce3Sdanielk1977 Tcl_Obj *CONST objv[] 12266622cce3Sdanielk1977 ){ 12276622cce3Sdanielk1977 sqlite *db; 12286622cce3Sdanielk1977 const void *zErr; 12296622cce3Sdanielk1977 int bytes; 12306622cce3Sdanielk1977 12316622cce3Sdanielk1977 if( objc!=2 ){ 12326622cce3Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 12336622cce3Sdanielk1977 Tcl_GetString(objv[0]), " DB", 0); 12346622cce3Sdanielk1977 return TCL_ERROR; 12356622cce3Sdanielk1977 } 12366622cce3Sdanielk1977 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 12376622cce3Sdanielk1977 12386622cce3Sdanielk1977 zErr = sqlite3_errmsg16(db); 12396622cce3Sdanielk1977 bytes = sqlite3utf16ByteLen(zErr, -1); 12406622cce3Sdanielk1977 Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes)); 12416622cce3Sdanielk1977 return TCL_OK; 12426622cce3Sdanielk1977 } 12436622cce3Sdanielk1977 12446622cce3Sdanielk1977 /* 12456622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar 12466622cce3Sdanielk1977 ** 12476622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using 12486622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global 12496622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A 12506622cce3Sdanielk1977 ** STMT handle is returned. 12516622cce3Sdanielk1977 */ 12526622cce3Sdanielk1977 static int test_prepare( 12536622cce3Sdanielk1977 void * clientData, 12546622cce3Sdanielk1977 Tcl_Interp *interp, 12556622cce3Sdanielk1977 int objc, 12566622cce3Sdanielk1977 Tcl_Obj *CONST objv[] 12576622cce3Sdanielk1977 ){ 12586622cce3Sdanielk1977 sqlite3 *db; 12596622cce3Sdanielk1977 const char *zSql; 12606622cce3Sdanielk1977 int bytes; 12616622cce3Sdanielk1977 const char *zTail = 0; 12626622cce3Sdanielk1977 sqlite3_stmt *pStmt = 0; 12636622cce3Sdanielk1977 char zBuf[50]; 12644ad1713cSdanielk1977 int rc; 12656622cce3Sdanielk1977 12666622cce3Sdanielk1977 if( objc!=5 ){ 12676622cce3Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 12686622cce3Sdanielk1977 Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0); 12696622cce3Sdanielk1977 return TCL_ERROR; 12706622cce3Sdanielk1977 } 12716622cce3Sdanielk1977 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 12726622cce3Sdanielk1977 zSql = Tcl_GetString(objv[2]); 12736622cce3Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR; 12746622cce3Sdanielk1977 12754ad1713cSdanielk1977 rc = sqlite3_prepare(db, zSql, bytes, &pStmt, &zTail); 12766622cce3Sdanielk1977 if( zTail ){ 12776622cce3Sdanielk1977 if( bytes>=0 ){ 12786622cce3Sdanielk1977 bytes = bytes - (zTail-zSql); 12796622cce3Sdanielk1977 } 12806622cce3Sdanielk1977 Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0); 12816622cce3Sdanielk1977 } 12824ad1713cSdanielk1977 if( rc!=SQLITE_OK ){ 12834ad1713cSdanielk1977 assert( pStmt==0 ); 12844ad1713cSdanielk1977 sprintf(zBuf, "(%d) ", rc); 12854ad1713cSdanielk1977 Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0); 12864ad1713cSdanielk1977 return TCL_ERROR; 12874ad1713cSdanielk1977 } 12886622cce3Sdanielk1977 12894ad1713cSdanielk1977 if( pStmt ){ 12906622cce3Sdanielk1977 if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR; 12916622cce3Sdanielk1977 Tcl_AppendResult(interp, zBuf, 0); 12924ad1713cSdanielk1977 } 12936622cce3Sdanielk1977 return TCL_OK; 12946622cce3Sdanielk1977 } 12956622cce3Sdanielk1977 12966622cce3Sdanielk1977 /* 12976622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar 12986622cce3Sdanielk1977 ** 12996622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using 13006622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global 13016622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A 13026622cce3Sdanielk1977 ** STMT handle is returned. 13036622cce3Sdanielk1977 */ 13046622cce3Sdanielk1977 static int test_prepare16( 13056622cce3Sdanielk1977 void * clientData, 13066622cce3Sdanielk1977 Tcl_Interp *interp, 13076622cce3Sdanielk1977 int objc, 13086622cce3Sdanielk1977 Tcl_Obj *CONST objv[] 13096622cce3Sdanielk1977 ){ 13106622cce3Sdanielk1977 sqlite3 *db; 13116622cce3Sdanielk1977 const void *zSql; 13126622cce3Sdanielk1977 const void *zTail = 0; 13136622cce3Sdanielk1977 Tcl_Obj *pTail = 0; 13146622cce3Sdanielk1977 sqlite3_stmt *pStmt = 0; 13156622cce3Sdanielk1977 char zBuf[50]; 13166622cce3Sdanielk1977 int bytes; /* The integer specified as arg 3 */ 13176622cce3Sdanielk1977 int objlen; /* The byte-array length of arg 2 */ 13186622cce3Sdanielk1977 13196622cce3Sdanielk1977 if( objc!=5 ){ 13206622cce3Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 13216622cce3Sdanielk1977 Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0); 13226622cce3Sdanielk1977 return TCL_ERROR; 13236622cce3Sdanielk1977 } 13246622cce3Sdanielk1977 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 13256622cce3Sdanielk1977 zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen); 13266622cce3Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR; 13276622cce3Sdanielk1977 13286622cce3Sdanielk1977 if( SQLITE_OK!=sqlite3_prepare16(db, zSql, bytes, &pStmt, &zTail) ){ 13296622cce3Sdanielk1977 return TCL_ERROR; 13306622cce3Sdanielk1977 } 13316622cce3Sdanielk1977 13326622cce3Sdanielk1977 if( zTail ){ 13336622cce3Sdanielk1977 objlen = objlen - ((u8 *)zTail-(u8 *)zSql); 13346622cce3Sdanielk1977 }else{ 13356622cce3Sdanielk1977 objlen = 0; 13366622cce3Sdanielk1977 } 13376622cce3Sdanielk1977 pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen); 13386622cce3Sdanielk1977 Tcl_IncrRefCount(pTail); 13396622cce3Sdanielk1977 Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0); 13404ad1713cSdanielk1977 Tcl_DecrRefCount(pTail); 13416622cce3Sdanielk1977 13424ad1713cSdanielk1977 if( pStmt ){ 13436622cce3Sdanielk1977 if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR; 13444ad1713cSdanielk1977 } 13456622cce3Sdanielk1977 Tcl_AppendResult(interp, zBuf, 0); 13466622cce3Sdanielk1977 return TCL_OK; 13476622cce3Sdanielk1977 } 13486622cce3Sdanielk1977 13494ad1713cSdanielk1977 /* 13504ad1713cSdanielk1977 ** Usage: sqlite3_open filename ?options-list? 13514ad1713cSdanielk1977 */ 13524ad1713cSdanielk1977 static int test_open( 13534ad1713cSdanielk1977 void * clientData, 13544ad1713cSdanielk1977 Tcl_Interp *interp, 13554ad1713cSdanielk1977 int objc, 13564ad1713cSdanielk1977 Tcl_Obj *CONST objv[] 13574ad1713cSdanielk1977 ){ 13584ad1713cSdanielk1977 const char *zFilename; 13594ad1713cSdanielk1977 sqlite3 *db; 13604ad1713cSdanielk1977 int rc; 13614ad1713cSdanielk1977 char zBuf[100]; 13624ad1713cSdanielk1977 13634ad1713cSdanielk1977 if( objc!=3 && objc!=2 ){ 13644ad1713cSdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 13654ad1713cSdanielk1977 Tcl_GetString(objv[0]), " filename options-list", 0); 13664ad1713cSdanielk1977 return TCL_ERROR; 13674ad1713cSdanielk1977 } 13684ad1713cSdanielk1977 13694ad1713cSdanielk1977 zFilename = Tcl_GetString(objv[1]); 1370*80290863Sdanielk1977 rc = sqlite3_open(zFilename, &db, 0); 13714ad1713cSdanielk1977 13724ad1713cSdanielk1977 if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR; 13734ad1713cSdanielk1977 Tcl_AppendResult(interp, zBuf, 0); 13744ad1713cSdanielk1977 return TCL_OK; 13754ad1713cSdanielk1977 } 13764ad1713cSdanielk1977 13774ad1713cSdanielk1977 /* 13784ad1713cSdanielk1977 ** Usage: sqlite3_open16 filename options 13794ad1713cSdanielk1977 */ 13804ad1713cSdanielk1977 static int test_open16( 13814ad1713cSdanielk1977 void * clientData, 13824ad1713cSdanielk1977 Tcl_Interp *interp, 13834ad1713cSdanielk1977 int objc, 13844ad1713cSdanielk1977 Tcl_Obj *CONST objv[] 13854ad1713cSdanielk1977 ){ 13864ad1713cSdanielk1977 const void *zFilename; 13874ad1713cSdanielk1977 sqlite3 *db; 13884ad1713cSdanielk1977 int rc; 13894ad1713cSdanielk1977 char zBuf[100]; 13904ad1713cSdanielk1977 13914ad1713cSdanielk1977 if( objc!=3 ){ 13924ad1713cSdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 13934ad1713cSdanielk1977 Tcl_GetString(objv[0]), " filename options-list", 0); 13944ad1713cSdanielk1977 return TCL_ERROR; 13954ad1713cSdanielk1977 } 13964ad1713cSdanielk1977 13974ad1713cSdanielk1977 zFilename = Tcl_GetByteArrayFromObj(objv[1], 0); 13984ad1713cSdanielk1977 rc = sqlite3_open16(zFilename, &db, 0); 13994ad1713cSdanielk1977 14004ad1713cSdanielk1977 if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR; 14014ad1713cSdanielk1977 Tcl_AppendResult(interp, zBuf, 0); 14024ad1713cSdanielk1977 return TCL_OK; 14034ad1713cSdanielk1977 } 1404d3d39e93Sdrh 1405d3d39e93Sdrh /* 1406106bb236Sdanielk1977 ** Usage: sqlite3_step STMT 1407106bb236Sdanielk1977 ** 1408106bb236Sdanielk1977 ** Advance the statement to the next row. 1409106bb236Sdanielk1977 */ 1410106bb236Sdanielk1977 static int test_step_new( 1411106bb236Sdanielk1977 void * clientData, 1412106bb236Sdanielk1977 Tcl_Interp *interp, 1413106bb236Sdanielk1977 int objc, 1414106bb236Sdanielk1977 Tcl_Obj *CONST objv[] 1415106bb236Sdanielk1977 ){ 1416106bb236Sdanielk1977 sqlite3_stmt *pStmt; 1417106bb236Sdanielk1977 int rc; 1418106bb236Sdanielk1977 1419106bb236Sdanielk1977 if( objc!=3 ){ 1420106bb236Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 1421106bb236Sdanielk1977 Tcl_GetString(objv[0]), " STMT", 0); 1422106bb236Sdanielk1977 return TCL_ERROR; 1423106bb236Sdanielk1977 } 1424106bb236Sdanielk1977 1425106bb236Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 1426106bb236Sdanielk1977 rc = sqlite3_step_new(pStmt); 1427106bb236Sdanielk1977 1428106bb236Sdanielk1977 if( rc!=SQLITE_OK ) return TCL_ERROR; 1429106bb236Sdanielk1977 return TCL_OK; 1430106bb236Sdanielk1977 } 1431106bb236Sdanielk1977 1432106bb236Sdanielk1977 /* 1433d3d39e93Sdrh ** This is a collating function named "REVERSE" which sorts text 1434d3d39e93Sdrh ** in reverse order. 1435d3d39e93Sdrh */ 1436d3d39e93Sdrh static int reverseCollatingFunc( 1437d3d39e93Sdrh void *NotUsed, 1438d3d39e93Sdrh int nKey1, const void *pKey1, 1439d3d39e93Sdrh int nKey2, const void *pKey2 1440d3d39e93Sdrh ){ 1441d3d39e93Sdrh int rc, n; 1442d3d39e93Sdrh n = nKey1<nKey2 ? nKey1 : nKey2; 1443d3d39e93Sdrh rc = memcmp(pKey1, pKey2, n); 1444d3d39e93Sdrh if( rc==0 ){ 1445d3d39e93Sdrh rc = nKey1 - nKey2; 1446d3d39e93Sdrh } 1447d3d39e93Sdrh return -rc; 1448d3d39e93Sdrh } 1449d3d39e93Sdrh 1450d3d39e93Sdrh /* 1451d3d39e93Sdrh ** Usage: add_reverse_collating_func DB 1452d3d39e93Sdrh ** 1453d3d39e93Sdrh ** This routine adds a collation named "REVERSE" to database given. 1454d3d39e93Sdrh ** REVERSE is used for testing only. 1455d3d39e93Sdrh */ 1456d3d39e93Sdrh static int reverse_collfunc( 1457d3d39e93Sdrh void * clientData, 1458d3d39e93Sdrh Tcl_Interp *interp, 1459d3d39e93Sdrh int objc, 1460d3d39e93Sdrh Tcl_Obj *CONST objv[] 1461d3d39e93Sdrh ){ 1462d3d39e93Sdrh sqlite3 *db; 1463d3d39e93Sdrh 1464d3d39e93Sdrh if( objc!=2 ){ 1465d3d39e93Sdrh Tcl_WrongNumArgs(interp, 1, objv, "DB"); 1466d3d39e93Sdrh return TCL_ERROR; 1467d3d39e93Sdrh } 1468d3d39e93Sdrh if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 1469d3d39e93Sdrh sqlite3ChangeCollatingFunction(db, "REVERSE", 7, 0, reverseCollatingFunc); 1470d3d39e93Sdrh return TCL_OK; 1471d3d39e93Sdrh } 1472d3d39e93Sdrh 1473d3d39e93Sdrh 14746622cce3Sdanielk1977 /* 1475d1bf3512Sdrh ** Register commands with the TCL interpreter. 1476d1bf3512Sdrh */ 1477d1bf3512Sdrh int Sqlitetest1_Init(Tcl_Interp *interp){ 14786f8a503dSdanielk1977 extern int sqlite3_search_count; 14796f8a503dSdanielk1977 extern int sqlite3_interrupt_count; 14806f8a503dSdanielk1977 extern int sqlite3_open_file_count; 14816f8a503dSdanielk1977 extern int sqlite3_current_time; 1482c2eef3b3Sdrh static struct { 1483c2eef3b3Sdrh char *zName; 1484c2eef3b3Sdrh Tcl_CmdProc *xProc; 1485c2eef3b3Sdrh } aCmd[] = { 14866f8a503dSdanielk1977 { "sqlite3_mprintf_int", (Tcl_CmdProc*)sqlite3_mprintf_int }, 14876f8a503dSdanielk1977 { "sqlite3_mprintf_str", (Tcl_CmdProc*)sqlite3_mprintf_str }, 14886f8a503dSdanielk1977 { "sqlite3_mprintf_double", (Tcl_CmdProc*)sqlite3_mprintf_double }, 14896f8a503dSdanielk1977 { "sqlite3_mprintf_scaled", (Tcl_CmdProc*)sqlite3_mprintf_scaled }, 14906f8a503dSdanielk1977 { "sqlite3_mprintf_z_test", (Tcl_CmdProc*)test_mprintf_z }, 14914ad1713cSdanielk1977 // { "sqlite3_open", (Tcl_CmdProc*)sqlite_test_open }, 14926f8a503dSdanielk1977 { "sqlite3_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid }, 14936f8a503dSdanielk1977 { "sqlite3_exec_printf", (Tcl_CmdProc*)test_exec_printf }, 14946f8a503dSdanielk1977 { "sqlite3_get_table_printf", (Tcl_CmdProc*)test_get_table_printf }, 14956f8a503dSdanielk1977 { "sqlite3_close", (Tcl_CmdProc*)sqlite_test_close }, 14966f8a503dSdanielk1977 { "sqlite3_create_function", (Tcl_CmdProc*)test_create_function }, 14976f8a503dSdanielk1977 { "sqlite3_create_aggregate", (Tcl_CmdProc*)test_create_aggregate }, 1498c2eef3b3Sdrh { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func }, 1499c2eef3b3Sdrh { "sqlite_abort", (Tcl_CmdProc*)sqlite_abort }, 15005a38705eSdrh { "sqlite_datatypes", (Tcl_CmdProc*)sqlite_datatypes }, 1501c2eef3b3Sdrh #ifdef MEMORY_DEBUG 1502c2eef3b3Sdrh { "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail }, 1503c2eef3b3Sdrh { "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat }, 1504c2eef3b3Sdrh #endif 150596fc5fe6Sdanielk1977 { "sqlite_step", (Tcl_CmdProc*)test_step }, 1506106bb236Sdanielk1977 // { "sqlite_finalize", (Tcl_CmdProc*)test_finalize }, 150796fc5fe6Sdanielk1977 { "sqlite_bind", (Tcl_CmdProc*)test_bind }, 1508106bb236Sdanielk1977 // { "sqlite_reset", (Tcl_CmdProc*)test_reset }, 150999ee3600Sdrh { "breakpoint", (Tcl_CmdProc*)test_breakpoint }, 1510c2eef3b3Sdrh }; 151151e3d8e2Sdanielk1977 static struct { 151251e3d8e2Sdanielk1977 char *zName; 151351e3d8e2Sdanielk1977 Tcl_ObjCmdProc *xProc; 151451e3d8e2Sdanielk1977 } aObjCmd[] = { 151551e3d8e2Sdanielk1977 { "sqlite3_bind_int32", (Tcl_ObjCmdProc*)test_bind_int32 }, 151651e3d8e2Sdanielk1977 { "sqlite3_bind_int64", (Tcl_ObjCmdProc*)test_bind_int64 }, 151751e3d8e2Sdanielk1977 { "sqlite3_bind_double", (Tcl_ObjCmdProc*)test_bind_double }, 151851e3d8e2Sdanielk1977 { "sqlite3_bind_null", (Tcl_ObjCmdProc*)test_bind_null }, 151951e3d8e2Sdanielk1977 { "sqlite3_bind_text", (Tcl_ObjCmdProc*)test_bind_text }, 152051e3d8e2Sdanielk1977 { "sqlite3_bind_text16", (Tcl_ObjCmdProc*)test_bind_text16 }, 152151e3d8e2Sdanielk1977 { "sqlite3_bind_blob", (Tcl_ObjCmdProc*)test_bind_blob }, 15226622cce3Sdanielk1977 { "sqlite3_errcode", (Tcl_ObjCmdProc*)test_errcode }, 15236622cce3Sdanielk1977 { "sqlite3_errmsg", (Tcl_ObjCmdProc*)test_errmsg }, 15246622cce3Sdanielk1977 { "sqlite3_errmsg16", (Tcl_ObjCmdProc*)test_errmsg16 }, 15256622cce3Sdanielk1977 { "sqlite3_prepare", (Tcl_ObjCmdProc*)test_prepare }, 15266622cce3Sdanielk1977 { "sqlite3_prepare16", (Tcl_ObjCmdProc*)test_prepare16 }, 15274ad1713cSdanielk1977 { "sqlite3_open", (Tcl_ObjCmdProc*)test_open }, 15284ad1713cSdanielk1977 { "sqlite3_open16", (Tcl_ObjCmdProc*)test_open16 }, 1529106bb236Sdanielk1977 { "sqlite3_finalize", (Tcl_ObjCmdProc*)test_finalize }, 1530106bb236Sdanielk1977 { "sqlite3_reset", (Tcl_ObjCmdProc*)test_reset }, 1531106bb236Sdanielk1977 { "sqlite3_step", (Tcl_ObjCmdProc*)test_step_new }, 1532d3d39e93Sdrh { "add_reverse_collating_func", (Tcl_ObjCmdProc*)reverse_collfunc }, 153351e3d8e2Sdanielk1977 }; 1534c2eef3b3Sdrh int i; 1535c2eef3b3Sdrh 1536c2eef3b3Sdrh for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ 1537c2eef3b3Sdrh Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); 1538c2eef3b3Sdrh } 153951e3d8e2Sdanielk1977 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ 154051e3d8e2Sdanielk1977 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); 154151e3d8e2Sdanielk1977 } 15426490bebdSdanielk1977 Tcl_LinkVar(interp, "sqlite_search_count", 15436f8a503dSdanielk1977 (char*)&sqlite3_search_count, TCL_LINK_INT); 15446490bebdSdanielk1977 Tcl_LinkVar(interp, "sqlite_interrupt_count", 15456f8a503dSdanielk1977 (char*)&sqlite3_interrupt_count, TCL_LINK_INT); 15466490bebdSdanielk1977 Tcl_LinkVar(interp, "sqlite_open_file_count", 15476f8a503dSdanielk1977 (char*)&sqlite3_open_file_count, TCL_LINK_INT); 15486490bebdSdanielk1977 Tcl_LinkVar(interp, "sqlite_current_time", 15496f8a503dSdanielk1977 (char*)&sqlite3_current_time, TCL_LINK_INT); 15507c972decSdrh Tcl_LinkVar(interp, "sqlite_static_bind_value", 15517c972decSdrh (char*)&sqlite_static_bind_value, TCL_LINK_STRING); 1552d1bf3512Sdrh return TCL_OK; 1553d1bf3512Sdrh } 1554