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*7e18c259Sdanielk1977 ** $Id: test1.c,v 1.50 2004/05/25 11:47:26 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 */ 31051ad0ecdSdanielk1977 static void ifnullFunc(sqlite_func *context, int argc, sqlite3_value **argv){ 311c22bd47dSdrh int i; 312c22bd47dSdrh for(i=0; i<argc; i++){ 31351ad0ecdSdanielk1977 if( SQLITE3_NULL!=sqlite3_value_type(argv[i]) ){ 314*7e18c259Sdanielk1977 sqlite3_result_text(context, sqlite3_value_data(argv[i]), -1, 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 */ 37951ad0ecdSdanielk1977 static void sqlite3ExecFunc( 38051ad0ecdSdanielk1977 sqlite_func *context, 38151ad0ecdSdanielk1977 int argc, 38251ad0ecdSdanielk1977 sqlite3_value **argv 38351ad0ecdSdanielk1977 ){ 384d1d9fc33Sdrh struct dstr x; 385d1d9fc33Sdrh memset(&x, 0, sizeof(x)); 38651ad0ecdSdanielk1977 sqlite3_exec((sqlite*)sqlite3_user_data(context), 38751ad0ecdSdanielk1977 sqlite3_value_data(argv[0]), 388d1d9fc33Sdrh execFuncCallback, &x, 0); 389*7e18c259Sdanielk1977 sqlite3_result_text(context, x.z, x.nUsed, 1); 390d1d9fc33Sdrh sqliteFree(x.z); 391c22bd47dSdrh } 392c22bd47dSdrh 393c22bd47dSdrh /* 394c22bd47dSdrh ** Usage: sqlite_test_create_function DB 395c22bd47dSdrh ** 3966f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order 397c22bd47dSdrh ** to create a function named "x_coalesce". This function does the same thing 398c22bd47dSdrh ** as the "coalesce" function. This function also registers an SQL function 3996f8a503dSdanielk1977 ** named "x_sqlite3_exec" that invokes sqlite3_exec(). Invoking sqlite3_exec() 400c22bd47dSdrh ** in this way is illegal recursion and should raise an SQLITE_MISUSE error. 401c22bd47dSdrh ** The effect is similar to trying to use the same database connection from 402c22bd47dSdrh ** two threads at the same time. 403c22bd47dSdrh ** 404c22bd47dSdrh ** The original motivation for this routine was to be able to call the 4056f8a503dSdanielk1977 ** sqlite3_create_function function while a query is in progress in order 406c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic. 407c22bd47dSdrh */ 408c2eef3b3Sdrh static int test_create_function( 409c22bd47dSdrh void *NotUsed, 410c22bd47dSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 411c22bd47dSdrh int argc, /* Number of arguments */ 412c22bd47dSdrh char **argv /* Text of each argument */ 413c22bd47dSdrh ){ 414c22bd47dSdrh sqlite *db; 415c22bd47dSdrh extern void Md5_Register(sqlite*); 416c22bd47dSdrh if( argc!=2 ){ 417c22bd47dSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 418c22bd47dSdrh " FILENAME\"", 0); 419c22bd47dSdrh return TCL_ERROR; 420c22bd47dSdrh } 421b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 4226f8a503dSdanielk1977 sqlite3_create_function(db, "x_coalesce", -1, ifnullFunc, 0); 4236f8a503dSdanielk1977 sqlite3_create_function(db, "x_sqlite3_exec", 1, sqlite3ExecFunc, db); 424c22bd47dSdrh return TCL_OK; 425c22bd47dSdrh } 426c22bd47dSdrh 427c22bd47dSdrh /* 428c22bd47dSdrh ** Routines to implement the x_count() aggregate function. 429c22bd47dSdrh */ 430c22bd47dSdrh typedef struct CountCtx CountCtx; 431c22bd47dSdrh struct CountCtx { 432c22bd47dSdrh int n; 433c22bd47dSdrh }; 4346ddcca55Sdanielk1977 static void countStep(sqlite_func *context, int argc, sqlite3_value **argv){ 435c22bd47dSdrh CountCtx *p; 4366f8a503dSdanielk1977 p = sqlite3_aggregate_context(context, sizeof(*p)); 4376ddcca55Sdanielk1977 if( (argc==0 || SQLITE3_NULL!=sqlite3_value_type(argv[0]) ) && p ){ 438c22bd47dSdrh p->n++; 439c22bd47dSdrh } 440c22bd47dSdrh } 441c22bd47dSdrh static void countFinalize(sqlite_func *context){ 442c22bd47dSdrh CountCtx *p; 4436f8a503dSdanielk1977 p = sqlite3_aggregate_context(context, sizeof(*p)); 444*7e18c259Sdanielk1977 sqlite3_result_int32(context, p ? p->n : 0); 445c22bd47dSdrh } 446c22bd47dSdrh 447c22bd47dSdrh /* 448c22bd47dSdrh ** Usage: sqlite_test_create_aggregate DB 449c22bd47dSdrh ** 4506f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order 451c22bd47dSdrh ** to create a function named "x_count". This function does the same thing 452c22bd47dSdrh ** as the "md5sum" function. 453c22bd47dSdrh ** 454c22bd47dSdrh ** The original motivation for this routine was to be able to call the 4556f8a503dSdanielk1977 ** sqlite3_create_aggregate function while a query is in progress in order 456c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic. 457c22bd47dSdrh */ 458c2eef3b3Sdrh static int test_create_aggregate( 459c22bd47dSdrh void *NotUsed, 460c22bd47dSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 461c22bd47dSdrh int argc, /* Number of arguments */ 462c22bd47dSdrh char **argv /* Text of each argument */ 463c22bd47dSdrh ){ 464c22bd47dSdrh sqlite *db; 465c22bd47dSdrh if( argc!=2 ){ 466c22bd47dSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 467c22bd47dSdrh " FILENAME\"", 0); 468c22bd47dSdrh return TCL_ERROR; 469c22bd47dSdrh } 470b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 4716f8a503dSdanielk1977 sqlite3_create_aggregate(db, "x_count", 0, countStep, countFinalize, 0); 4726f8a503dSdanielk1977 sqlite3_create_aggregate(db, "x_count", 1, countStep, countFinalize, 0); 473c22bd47dSdrh return TCL_OK; 474c22bd47dSdrh } 475c22bd47dSdrh 476c22bd47dSdrh 477c22bd47dSdrh 478c22bd47dSdrh /* 4796f8a503dSdanielk1977 ** Usage: sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER 480d1bf3512Sdrh ** 481d1bf3512Sdrh ** Call mprintf with three integer arguments 482d1bf3512Sdrh */ 4836f8a503dSdanielk1977 static int sqlite3_mprintf_int( 484d1bf3512Sdrh void *NotUsed, 485d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 486d1bf3512Sdrh int argc, /* Number of arguments */ 487d1bf3512Sdrh char **argv /* Text of each argument */ 488d1bf3512Sdrh ){ 489d1bf3512Sdrh int a[3], i; 490d1bf3512Sdrh char *z; 491d1bf3512Sdrh if( argc!=5 ){ 492d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 493d1bf3512Sdrh " FORMAT INT INT INT\"", 0); 494d1bf3512Sdrh return TCL_ERROR; 495d1bf3512Sdrh } 496d1bf3512Sdrh for(i=2; i<5; i++){ 497d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 498d1bf3512Sdrh } 4996f8a503dSdanielk1977 z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]); 500d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 5016f8a503dSdanielk1977 sqlite3_freemem(z); 502d1bf3512Sdrh return TCL_OK; 503d1bf3512Sdrh } 504d1bf3512Sdrh 505d1bf3512Sdrh /* 5066f8a503dSdanielk1977 ** Usage: sqlite3_mprintf_str FORMAT INTEGER INTEGER STRING 507d1bf3512Sdrh ** 508d1bf3512Sdrh ** Call mprintf with two integer arguments and one string argument 509d1bf3512Sdrh */ 5106f8a503dSdanielk1977 static int sqlite3_mprintf_str( 511d1bf3512Sdrh void *NotUsed, 512d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 513d1bf3512Sdrh int argc, /* Number of arguments */ 514d1bf3512Sdrh char **argv /* Text of each argument */ 515d1bf3512Sdrh ){ 516d1bf3512Sdrh int a[3], i; 517d1bf3512Sdrh char *z; 518f220b24fSchw if( argc<4 || argc>5 ){ 519d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 520f220b24fSchw " FORMAT INT INT ?STRING?\"", 0); 521d1bf3512Sdrh return TCL_ERROR; 522d1bf3512Sdrh } 523d1bf3512Sdrh for(i=2; i<4; i++){ 524d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 525d1bf3512Sdrh } 5266f8a503dSdanielk1977 z = sqlite3_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL); 527d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 5286f8a503dSdanielk1977 sqlite3_freemem(z); 529d1bf3512Sdrh return TCL_OK; 530d1bf3512Sdrh } 531d1bf3512Sdrh 532d1bf3512Sdrh /* 5336f8a503dSdanielk1977 ** Usage: sqlite3_mprintf_str FORMAT INTEGER INTEGER DOUBLE 534d1bf3512Sdrh ** 535d1bf3512Sdrh ** Call mprintf with two integer arguments and one double argument 536d1bf3512Sdrh */ 5376f8a503dSdanielk1977 static int sqlite3_mprintf_double( 538d1bf3512Sdrh void *NotUsed, 539d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 540d1bf3512Sdrh int argc, /* Number of arguments */ 541d1bf3512Sdrh char **argv /* Text of each argument */ 542d1bf3512Sdrh ){ 543d1bf3512Sdrh int a[3], i; 544d1bf3512Sdrh double r; 545d1bf3512Sdrh char *z; 546d1bf3512Sdrh if( argc!=5 ){ 547d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 548d1bf3512Sdrh " FORMAT INT INT STRING\"", 0); 549d1bf3512Sdrh return TCL_ERROR; 550d1bf3512Sdrh } 551d1bf3512Sdrh for(i=2; i<4; i++){ 552d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 553d1bf3512Sdrh } 554d1bf3512Sdrh if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR; 5556f8a503dSdanielk1977 z = sqlite3_mprintf(argv[1], a[0], a[1], r); 556d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 5576f8a503dSdanielk1977 sqlite3_freemem(z); 558d1bf3512Sdrh return TCL_OK; 559d1bf3512Sdrh } 560d1bf3512Sdrh 561d1bf3512Sdrh /* 5626f8a503dSdanielk1977 ** Usage: sqlite3_mprintf_str FORMAT DOUBLE DOUBLE 563b621c237Sdrh ** 564b621c237Sdrh ** Call mprintf with a single double argument which is the product of the 565b621c237Sdrh ** two arguments given above. This is used to generate overflow and underflow 566b621c237Sdrh ** doubles to test that they are converted properly. 567b621c237Sdrh */ 5686f8a503dSdanielk1977 static int sqlite3_mprintf_scaled( 569b621c237Sdrh void *NotUsed, 570b621c237Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 571b621c237Sdrh int argc, /* Number of arguments */ 572b621c237Sdrh char **argv /* Text of each argument */ 573b621c237Sdrh ){ 574b621c237Sdrh int i; 575b621c237Sdrh double r[2]; 576b621c237Sdrh char *z; 577b621c237Sdrh if( argc!=4 ){ 578b621c237Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 579b621c237Sdrh " FORMAT DOUBLE DOUBLE\"", 0); 580b621c237Sdrh return TCL_ERROR; 581b621c237Sdrh } 582b621c237Sdrh for(i=2; i<4; i++){ 583b621c237Sdrh if( Tcl_GetDouble(interp, argv[i], &r[i-2]) ) return TCL_ERROR; 584b621c237Sdrh } 5856f8a503dSdanielk1977 z = sqlite3_mprintf(argv[1], r[0]*r[1]); 586b621c237Sdrh Tcl_AppendResult(interp, z, 0); 5876f8a503dSdanielk1977 sqlite3_freemem(z); 588b621c237Sdrh return TCL_OK; 589b621c237Sdrh } 590b621c237Sdrh 591b621c237Sdrh /* 592daffd0e5Sdrh ** Usage: sqlite_malloc_fail N 593daffd0e5Sdrh ** 594afa4a020Sdrh ** Rig sqliteMalloc() to fail on the N-th call. Turn off this mechanism 5956f8a503dSdanielk1977 ** and reset the sqlite3_malloc_failed variable is N==0. 596daffd0e5Sdrh */ 597daffd0e5Sdrh #ifdef MEMORY_DEBUG 598daffd0e5Sdrh static int sqlite_malloc_fail( 599daffd0e5Sdrh void *NotUsed, 600daffd0e5Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 601daffd0e5Sdrh int argc, /* Number of arguments */ 602daffd0e5Sdrh char **argv /* Text of each argument */ 603daffd0e5Sdrh ){ 604daffd0e5Sdrh int n; 605daffd0e5Sdrh if( argc!=2 ){ 606daffd0e5Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0); 607daffd0e5Sdrh return TCL_ERROR; 608daffd0e5Sdrh } 609daffd0e5Sdrh if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR; 6106f8a503dSdanielk1977 sqlite3_iMallocFail = n; 6116f8a503dSdanielk1977 sqlite3_malloc_failed = 0; 612daffd0e5Sdrh return TCL_OK; 613daffd0e5Sdrh } 614daffd0e5Sdrh #endif 615daffd0e5Sdrh 616daffd0e5Sdrh /* 617daffd0e5Sdrh ** Usage: sqlite_malloc_stat 618daffd0e5Sdrh ** 619daffd0e5Sdrh ** Return the number of prior calls to sqliteMalloc() and sqliteFree(). 620daffd0e5Sdrh */ 621daffd0e5Sdrh #ifdef MEMORY_DEBUG 622daffd0e5Sdrh static int sqlite_malloc_stat( 623daffd0e5Sdrh void *NotUsed, 624daffd0e5Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 625daffd0e5Sdrh int argc, /* Number of arguments */ 626daffd0e5Sdrh char **argv /* Text of each argument */ 627daffd0e5Sdrh ){ 628daffd0e5Sdrh char zBuf[200]; 6296f8a503dSdanielk1977 sprintf(zBuf, "%d %d %d", sqlite3_nMalloc, sqlite3_nFree, sqlite3_iMallocFail); 630daffd0e5Sdrh Tcl_AppendResult(interp, zBuf, 0); 631daffd0e5Sdrh return TCL_OK; 632daffd0e5Sdrh } 633daffd0e5Sdrh #endif 634daffd0e5Sdrh 635daffd0e5Sdrh /* 63628b4e489Sdrh ** Usage: sqlite_abort 63728b4e489Sdrh ** 63828b4e489Sdrh ** Shutdown the process immediately. This is not a clean shutdown. 63928b4e489Sdrh ** This command is used to test the recoverability of a database in 64028b4e489Sdrh ** the event of a program crash. 64128b4e489Sdrh */ 64228b4e489Sdrh static int sqlite_abort( 64328b4e489Sdrh void *NotUsed, 64428b4e489Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 64528b4e489Sdrh int argc, /* Number of arguments */ 64628b4e489Sdrh char **argv /* Text of each argument */ 64728b4e489Sdrh ){ 64828b4e489Sdrh assert( interp==0 ); /* This will always fail */ 64928b4e489Sdrh return TCL_OK; 65028b4e489Sdrh } 65128b4e489Sdrh 65228b4e489Sdrh /* 6536cbe1f1bSdrh ** The following routine is a user-defined SQL function whose purpose 6546cbe1f1bSdrh ** is to test the sqlite_set_result() API. 6556cbe1f1bSdrh */ 65651ad0ecdSdanielk1977 static void testFunc(sqlite_func *context, int argc, sqlite3_value **argv){ 6576cbe1f1bSdrh while( argc>=2 ){ 65851ad0ecdSdanielk1977 const char *zArg0 = sqlite3_value_data(argv[0]); 65951ad0ecdSdanielk1977 const char *zArg1 = sqlite3_value_data(argv[1]); 66051ad0ecdSdanielk1977 if( zArg0==0 ){ 661*7e18c259Sdanielk1977 sqlite3_result_error(context, "first argument to test function " 6626cbe1f1bSdrh "may not be NULL", -1); 66351ad0ecdSdanielk1977 }else if( sqlite3StrICmp(zArg0,"string")==0 ){ 664*7e18c259Sdanielk1977 sqlite3_result_text(context, zArg1, -1, 1); 66551ad0ecdSdanielk1977 }else if( zArg1==0 ){ 666*7e18c259Sdanielk1977 sqlite3_result_error(context, "2nd argument may not be NULL if the " 6676cbe1f1bSdrh "first argument is not \"string\"", -1); 66851ad0ecdSdanielk1977 }else if( sqlite3StrICmp(zArg0,"int")==0 ){ 669*7e18c259Sdanielk1977 sqlite3_result_int32(context, atoi(zArg1)); 67051ad0ecdSdanielk1977 }else if( sqlite3StrICmp(zArg0,"double")==0 ){ 671*7e18c259Sdanielk1977 sqlite3_result_double(context, sqlite3AtoF(zArg1, 0)); 6726cbe1f1bSdrh }else{ 673*7e18c259Sdanielk1977 sqlite3_result_error(context,"first argument should be one of: " 6746cbe1f1bSdrh "string int double", -1); 6756cbe1f1bSdrh } 6766cbe1f1bSdrh argc -= 2; 6776cbe1f1bSdrh argv += 2; 6786cbe1f1bSdrh } 6796cbe1f1bSdrh } 6806cbe1f1bSdrh 6816cbe1f1bSdrh /* 6826cbe1f1bSdrh ** Usage: sqlite_register_test_function DB NAME 6836cbe1f1bSdrh ** 6846cbe1f1bSdrh ** Register the test SQL function on the database DB under the name NAME. 6856cbe1f1bSdrh */ 686c2eef3b3Sdrh static int test_register_func( 6876cbe1f1bSdrh void *NotUsed, 6886cbe1f1bSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 6896cbe1f1bSdrh int argc, /* Number of arguments */ 6906cbe1f1bSdrh char **argv /* Text of each argument */ 6916cbe1f1bSdrh ){ 6926cbe1f1bSdrh sqlite *db; 6936cbe1f1bSdrh int rc; 6946cbe1f1bSdrh if( argc!=3 ){ 6956cbe1f1bSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 6966cbe1f1bSdrh " DB FUNCTION-NAME", 0); 6976cbe1f1bSdrh return TCL_ERROR; 6986cbe1f1bSdrh } 699b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 7006f8a503dSdanielk1977 rc = sqlite3_create_function(db, argv[2], -1, testFunc, 0); 7016cbe1f1bSdrh if( rc!=0 ){ 7026f8a503dSdanielk1977 Tcl_AppendResult(interp, sqlite3_error_string(rc), 0); 7036cbe1f1bSdrh return TCL_ERROR; 7046cbe1f1bSdrh } 7056cbe1f1bSdrh return TCL_OK; 7066cbe1f1bSdrh } 7076cbe1f1bSdrh 7086cbe1f1bSdrh /* 7095a38705eSdrh ** This SQLite callback records the datatype of all columns. 7105a38705eSdrh ** 7115a38705eSdrh ** The pArg argument is really a pointer to a TCL interpreter. The 7125a38705eSdrh ** column names are inserted as the result of this interpreter. 7135a38705eSdrh ** 7145a38705eSdrh ** This routine returns non-zero which causes the query to abort. 7155a38705eSdrh */ 7165a38705eSdrh static int rememberDataTypes(void *pArg, int nCol, char **argv, char **colv){ 7175a38705eSdrh int i; 7185a38705eSdrh Tcl_Interp *interp = (Tcl_Interp*)pArg; 7195a38705eSdrh Tcl_Obj *pList, *pElem; 7205a38705eSdrh if( colv[nCol+1]==0 ){ 7215a38705eSdrh return 1; 7225a38705eSdrh } 7235a38705eSdrh pList = Tcl_NewObj(); 7245a38705eSdrh for(i=0; i<nCol; i++){ 7255a38705eSdrh pElem = Tcl_NewStringObj(colv[i+nCol] ? colv[i+nCol] : "NULL", -1); 7265a38705eSdrh Tcl_ListObjAppendElement(interp, pList, pElem); 7275a38705eSdrh } 7285a38705eSdrh Tcl_SetObjResult(interp, pList); 7295a38705eSdrh return 1; 7305a38705eSdrh } 7315a38705eSdrh 7325a38705eSdrh /* 7335a38705eSdrh ** Invoke an SQL statement but ignore all the data in the result. Instead, 7345a38705eSdrh ** return a list that consists of the datatypes of the various columns. 7355a38705eSdrh ** 7365a38705eSdrh ** This only works if "PRAGMA show_datatypes=on" has been executed against 7375a38705eSdrh ** the database connection. 7385a38705eSdrh */ 7395a38705eSdrh static int sqlite_datatypes( 7405a38705eSdrh void *NotUsed, 7415a38705eSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 7425a38705eSdrh int argc, /* Number of arguments */ 7435a38705eSdrh char **argv /* Text of each argument */ 7445a38705eSdrh ){ 7455a38705eSdrh sqlite *db; 7465a38705eSdrh int rc; 7475a38705eSdrh if( argc!=3 ){ 7485a38705eSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 7495a38705eSdrh " DB SQL", 0); 7505a38705eSdrh return TCL_ERROR; 7515a38705eSdrh } 752b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 7536f8a503dSdanielk1977 rc = sqlite3_exec(db, argv[2], rememberDataTypes, interp, 0); 7545a38705eSdrh if( rc!=0 && rc!=SQLITE_ABORT ){ 7556f8a503dSdanielk1977 Tcl_AppendResult(interp, sqlite3_error_string(rc), 0); 7565a38705eSdrh return TCL_ERROR; 7575a38705eSdrh } 7585a38705eSdrh return TCL_OK; 7595a38705eSdrh } 7605a38705eSdrh 761b86ccfb2Sdrh /* 7626f8a503dSdanielk1977 ** Usage: sqlite3_step VM ?NVAR? ?VALUEVAR? ?COLNAMEVAR? 763b86ccfb2Sdrh ** 764b86ccfb2Sdrh ** Step a virtual machine. Return a the result code as a string. 765b86ccfb2Sdrh ** Column results are written into three variables. 766b86ccfb2Sdrh */ 767b86ccfb2Sdrh static int test_step( 768b86ccfb2Sdrh void *NotUsed, 769b86ccfb2Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 770b86ccfb2Sdrh int argc, /* Number of arguments */ 771b86ccfb2Sdrh char **argv /* Text of each argument */ 772b86ccfb2Sdrh ){ 773b86ccfb2Sdrh sqlite_vm *vm; 774b86ccfb2Sdrh int rc, i; 7753a84069dSdrh const char **azValue = 0; 7763a84069dSdrh const char **azColName = 0; 7773a84069dSdrh int N = 0; 778b86ccfb2Sdrh char *zRc; 779b86ccfb2Sdrh char zBuf[50]; 780073e5a77Sdrh if( argc<2 || argc>5 ){ 781b86ccfb2Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 782b86ccfb2Sdrh " VM NVAR VALUEVAR COLNAMEVAR", 0); 783b86ccfb2Sdrh return TCL_ERROR; 784b86ccfb2Sdrh } 785b86ccfb2Sdrh if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR; 7866f8a503dSdanielk1977 rc = sqlite3_step(vm, argc>=3?&N:0, argc>=4?&azValue:0, argc==5?&azColName:0); 787073e5a77Sdrh if( argc>=3 ){ 788b86ccfb2Sdrh sprintf(zBuf, "%d", N); 789b86ccfb2Sdrh Tcl_SetVar(interp, argv[2], zBuf, 0); 790073e5a77Sdrh } 791073e5a77Sdrh if( argc>=4 ){ 792b86ccfb2Sdrh Tcl_SetVar(interp, argv[3], "", 0); 7933a84069dSdrh if( azValue ){ 794b86ccfb2Sdrh for(i=0; i<N; i++){ 795b86ccfb2Sdrh Tcl_SetVar(interp, argv[3], azValue[i] ? azValue[i] : "", 796b86ccfb2Sdrh TCL_APPEND_VALUE | TCL_LIST_ELEMENT); 797b86ccfb2Sdrh } 798b86ccfb2Sdrh } 799073e5a77Sdrh } 800073e5a77Sdrh if( argc==5 ){ 801b86ccfb2Sdrh Tcl_SetVar(interp, argv[4], "", 0); 8023a84069dSdrh if( azColName ){ 803b86ccfb2Sdrh for(i=0; i<N*2; i++){ 804326dce74Sdrh Tcl_SetVar(interp, argv[4], azColName[i] ? azColName[i] : "", 805b86ccfb2Sdrh TCL_APPEND_VALUE | TCL_LIST_ELEMENT); 806b86ccfb2Sdrh } 807b86ccfb2Sdrh } 808073e5a77Sdrh } 809b86ccfb2Sdrh switch( rc ){ 810b86ccfb2Sdrh case SQLITE_DONE: zRc = "SQLITE_DONE"; break; 811326dce74Sdrh case SQLITE_BUSY: zRc = "SQLITE_BUSY"; break; 812326dce74Sdrh case SQLITE_ROW: zRc = "SQLITE_ROW"; break; 813326dce74Sdrh case SQLITE_ERROR: zRc = "SQLITE_ERROR"; break; 814b86ccfb2Sdrh case SQLITE_MISUSE: zRc = "SQLITE_MISUSE"; break; 815b86ccfb2Sdrh default: zRc = "unknown"; break; 816b86ccfb2Sdrh } 817b86ccfb2Sdrh Tcl_AppendResult(interp, zRc, 0); 818b86ccfb2Sdrh return TCL_OK; 819b86ccfb2Sdrh } 820b86ccfb2Sdrh 821b86ccfb2Sdrh /* 822106bb236Sdanielk1977 ** Usage: sqlite3_finalize STMT 823b86ccfb2Sdrh ** 824106bb236Sdanielk1977 ** Finalize a statement handle. 825b86ccfb2Sdrh */ 826b86ccfb2Sdrh static int test_finalize( 827106bb236Sdanielk1977 void * clientData, 828106bb236Sdanielk1977 Tcl_Interp *interp, 829106bb236Sdanielk1977 int objc, 830106bb236Sdanielk1977 Tcl_Obj *CONST objv[] 831b86ccfb2Sdrh ){ 832106bb236Sdanielk1977 sqlite3_stmt *pStmt; 833b86ccfb2Sdrh int rc; 834106bb236Sdanielk1977 835106bb236Sdanielk1977 if( objc!=2 ){ 836106bb236Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 837106bb236Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0); 838b86ccfb2Sdrh return TCL_ERROR; 839b86ccfb2Sdrh } 840106bb236Sdanielk1977 841106bb236Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 842106bb236Sdanielk1977 843106bb236Sdanielk1977 rc = sqlite3_finalize_new(pStmt); 844b86ccfb2Sdrh if( rc ){ 845106bb236Sdanielk1977 return TCL_ERROR; 846106bb236Sdanielk1977 } 847106bb236Sdanielk1977 return TCL_OK; 848106bb236Sdanielk1977 } 849106bb236Sdanielk1977 850106bb236Sdanielk1977 /* 851106bb236Sdanielk1977 ** Usage: sqlite3_reset STMT 852106bb236Sdanielk1977 ** 853106bb236Sdanielk1977 ** Finalize a statement handle. 854106bb236Sdanielk1977 */ 855106bb236Sdanielk1977 static int test_reset( 856106bb236Sdanielk1977 void * clientData, 857106bb236Sdanielk1977 Tcl_Interp *interp, 858106bb236Sdanielk1977 int objc, 859106bb236Sdanielk1977 Tcl_Obj *CONST objv[] 860106bb236Sdanielk1977 ){ 861106bb236Sdanielk1977 sqlite3_stmt *pStmt; 862106bb236Sdanielk1977 int rc; 863106bb236Sdanielk1977 864106bb236Sdanielk1977 if( objc!=2 ){ 865106bb236Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 866106bb236Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0); 867106bb236Sdanielk1977 return TCL_ERROR; 868106bb236Sdanielk1977 } 869106bb236Sdanielk1977 870106bb236Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 871106bb236Sdanielk1977 872106bb236Sdanielk1977 rc = sqlite3_reset_new(pStmt); 873106bb236Sdanielk1977 if( rc ){ 874b86ccfb2Sdrh return TCL_ERROR; 875b86ccfb2Sdrh } 876b86ccfb2Sdrh return TCL_OK; 877b86ccfb2Sdrh } 878b86ccfb2Sdrh 8795a38705eSdrh /* 8806f8a503dSdanielk1977 ** Usage: sqlite3_reset VM 88150457896Sdrh ** 88250457896Sdrh ** Reset a virtual machine and prepare it to be run again. 88350457896Sdrh */ 88450457896Sdrh 88550457896Sdrh /* 8867c972decSdrh ** This is the "static_bind_value" that variables are bound to when 8876f8a503dSdanielk1977 ** the FLAG option of sqlite3_bind is "static" 88850457896Sdrh */ 8897c972decSdrh static char *sqlite_static_bind_value = 0; 8907c972decSdrh 8917c972decSdrh /* 8926f8a503dSdanielk1977 ** Usage: sqlite3_bind VM IDX VALUE FLAGS 8937c972decSdrh ** 8947c972decSdrh ** Sets the value of the IDX-th occurance of "?" in the original SQL 8957c972decSdrh ** string. VALUE is the new value. If FLAGS=="null" then VALUE is 8967c972decSdrh ** ignored and the value is set to NULL. If FLAGS=="static" then 8977c972decSdrh ** the value is set to the value of a static variable named 8987c972decSdrh ** "sqlite_static_bind_value". If FLAGS=="normal" then a copy 8997c972decSdrh ** of the VALUE is made. 9007c972decSdrh */ 9017c972decSdrh static int test_bind( 90250457896Sdrh void *NotUsed, 90350457896Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 90450457896Sdrh int argc, /* Number of arguments */ 90550457896Sdrh char **argv /* Text of each argument */ 90650457896Sdrh ){ 90750457896Sdrh sqlite_vm *vm; 90850457896Sdrh int rc; 9097c972decSdrh int idx; 9107c972decSdrh if( argc!=5 ){ 91150457896Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 9127c972decSdrh " VM IDX VALUE (null|static|normal)\"", 0); 91350457896Sdrh return TCL_ERROR; 91450457896Sdrh } 91550457896Sdrh if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR; 9167c972decSdrh if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR; 9177c972decSdrh if( strcmp(argv[4],"null")==0 ){ 9186f8a503dSdanielk1977 rc = sqlite3_bind(vm, idx, 0, 0, 0); 9197c972decSdrh }else if( strcmp(argv[4],"static")==0 ){ 9206f8a503dSdanielk1977 rc = sqlite3_bind(vm, idx, sqlite_static_bind_value, -1, 0); 9217c972decSdrh }else if( strcmp(argv[4],"normal")==0 ){ 9226f8a503dSdanielk1977 rc = sqlite3_bind(vm, idx, argv[3], -1, 1); 9237c972decSdrh }else{ 9247c972decSdrh Tcl_AppendResult(interp, "4th argument should be " 9257c972decSdrh "\"null\" or \"static\" or \"normal\"", 0); 9267c972decSdrh return TCL_ERROR; 9277c972decSdrh } 92850457896Sdrh if( rc ){ 92950457896Sdrh char zBuf[50]; 93050457896Sdrh sprintf(zBuf, "(%d) ", rc); 9316f8a503dSdanielk1977 Tcl_AppendResult(interp, zBuf, sqlite3_error_string(rc), 0); 93250457896Sdrh return TCL_ERROR; 93350457896Sdrh } 93450457896Sdrh return TCL_OK; 93550457896Sdrh } 93650457896Sdrh 93750457896Sdrh /* 93899ee3600Sdrh ** Usage: breakpoint 93999ee3600Sdrh ** 94099ee3600Sdrh ** This routine exists for one purpose - to provide a place to put a 94199ee3600Sdrh ** breakpoint with GDB that can be triggered using TCL code. The use 94299ee3600Sdrh ** for this is when a particular test fails on (say) the 1485th iteration. 94399ee3600Sdrh ** In the TCL test script, we can add code like this: 94499ee3600Sdrh ** 94599ee3600Sdrh ** if {$i==1485} breakpoint 94699ee3600Sdrh ** 94799ee3600Sdrh ** Then run testfixture in the debugger and wait for the breakpoint to 94899ee3600Sdrh ** fire. Then additional breakpoints can be set to trace down the bug. 94999ee3600Sdrh */ 95099ee3600Sdrh static int test_breakpoint( 95199ee3600Sdrh void *NotUsed, 95299ee3600Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 95399ee3600Sdrh int argc, /* Number of arguments */ 95499ee3600Sdrh char **argv /* Text of each argument */ 95599ee3600Sdrh ){ 95699ee3600Sdrh return TCL_OK; /* Do nothing */ 95799ee3600Sdrh } 95899ee3600Sdrh 95951e3d8e2Sdanielk1977 static int test_bind_int32( 96051e3d8e2Sdanielk1977 void * clientData, 96151e3d8e2Sdanielk1977 Tcl_Interp *interp, 96251e3d8e2Sdanielk1977 int objc, 96351e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 96451e3d8e2Sdanielk1977 ){ 96551e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 96651e3d8e2Sdanielk1977 int idx; 96751e3d8e2Sdanielk1977 int value; 96851e3d8e2Sdanielk1977 int rc; 96951e3d8e2Sdanielk1977 97051e3d8e2Sdanielk1977 if( objc!=4 ){ 97151e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 97251e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0); 97351e3d8e2Sdanielk1977 return TCL_ERROR; 97451e3d8e2Sdanielk1977 } 97551e3d8e2Sdanielk1977 97651e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 97751e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 97851e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[3], &value) ) return TCL_ERROR; 97951e3d8e2Sdanielk1977 98051e3d8e2Sdanielk1977 rc = sqlite3_bind_int32(pStmt, idx, value); 98151e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 98251e3d8e2Sdanielk1977 return TCL_ERROR; 98351e3d8e2Sdanielk1977 } 98451e3d8e2Sdanielk1977 98551e3d8e2Sdanielk1977 return TCL_OK; 98651e3d8e2Sdanielk1977 } 98751e3d8e2Sdanielk1977 98851e3d8e2Sdanielk1977 static int test_bind_int64( 98951e3d8e2Sdanielk1977 void * clientData, 99051e3d8e2Sdanielk1977 Tcl_Interp *interp, 99151e3d8e2Sdanielk1977 int objc, 99251e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 99351e3d8e2Sdanielk1977 ){ 99451e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 99551e3d8e2Sdanielk1977 int idx; 99651e3d8e2Sdanielk1977 i64 value; 99751e3d8e2Sdanielk1977 int rc; 99851e3d8e2Sdanielk1977 99951e3d8e2Sdanielk1977 if( objc!=4 ){ 100051e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 100151e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0); 100251e3d8e2Sdanielk1977 return TCL_ERROR; 100351e3d8e2Sdanielk1977 } 100451e3d8e2Sdanielk1977 100551e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 100651e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 100751e3d8e2Sdanielk1977 if( Tcl_GetWideIntFromObj(interp, objv[3], &value) ) return TCL_ERROR; 100851e3d8e2Sdanielk1977 100951e3d8e2Sdanielk1977 rc = sqlite3_bind_int64(pStmt, idx, value); 101051e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 101151e3d8e2Sdanielk1977 return TCL_ERROR; 101251e3d8e2Sdanielk1977 } 101351e3d8e2Sdanielk1977 101451e3d8e2Sdanielk1977 return TCL_OK; 101551e3d8e2Sdanielk1977 } 101651e3d8e2Sdanielk1977 101751e3d8e2Sdanielk1977 static int test_bind_double( 101851e3d8e2Sdanielk1977 void * clientData, 101951e3d8e2Sdanielk1977 Tcl_Interp *interp, 102051e3d8e2Sdanielk1977 int objc, 102151e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 102251e3d8e2Sdanielk1977 ){ 102351e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 102451e3d8e2Sdanielk1977 int idx; 102551e3d8e2Sdanielk1977 double value; 102651e3d8e2Sdanielk1977 int rc; 102751e3d8e2Sdanielk1977 102851e3d8e2Sdanielk1977 if( objc!=4 ){ 102951e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 103051e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0); 103151e3d8e2Sdanielk1977 return TCL_ERROR; 103251e3d8e2Sdanielk1977 } 103351e3d8e2Sdanielk1977 103451e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 103551e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 103651e3d8e2Sdanielk1977 if( Tcl_GetDoubleFromObj(interp, objv[3], &value) ) return TCL_ERROR; 103751e3d8e2Sdanielk1977 103851e3d8e2Sdanielk1977 rc = sqlite3_bind_double(pStmt, idx, value); 103951e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 104051e3d8e2Sdanielk1977 return TCL_ERROR; 104151e3d8e2Sdanielk1977 } 104251e3d8e2Sdanielk1977 104351e3d8e2Sdanielk1977 return TCL_OK; 104451e3d8e2Sdanielk1977 } 104551e3d8e2Sdanielk1977 104651e3d8e2Sdanielk1977 static int test_bind_null( 104751e3d8e2Sdanielk1977 void * clientData, 104851e3d8e2Sdanielk1977 Tcl_Interp *interp, 104951e3d8e2Sdanielk1977 int objc, 105051e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 105151e3d8e2Sdanielk1977 ){ 105251e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 105351e3d8e2Sdanielk1977 int idx; 105451e3d8e2Sdanielk1977 int rc; 105551e3d8e2Sdanielk1977 105651e3d8e2Sdanielk1977 if( objc!=3 ){ 105751e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 105851e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.>", 0); 105951e3d8e2Sdanielk1977 return TCL_ERROR; 106051e3d8e2Sdanielk1977 } 106151e3d8e2Sdanielk1977 106251e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 106351e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 106451e3d8e2Sdanielk1977 106551e3d8e2Sdanielk1977 rc = sqlite3_bind_null(pStmt, idx); 106651e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 106751e3d8e2Sdanielk1977 return TCL_ERROR; 106851e3d8e2Sdanielk1977 } 106951e3d8e2Sdanielk1977 107051e3d8e2Sdanielk1977 return TCL_OK; 107151e3d8e2Sdanielk1977 } 107251e3d8e2Sdanielk1977 107351e3d8e2Sdanielk1977 static int test_bind_text( 107451e3d8e2Sdanielk1977 void * clientData, 107551e3d8e2Sdanielk1977 Tcl_Interp *interp, 107651e3d8e2Sdanielk1977 int objc, 107751e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 107851e3d8e2Sdanielk1977 ){ 107951e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 108051e3d8e2Sdanielk1977 int idx; 108151e3d8e2Sdanielk1977 int bytes; 108251e3d8e2Sdanielk1977 char *value; 108351e3d8e2Sdanielk1977 int rc; 108451e3d8e2Sdanielk1977 108551e3d8e2Sdanielk1977 if( objc!=5 ){ 108651e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 108751e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>" 108851e3d8e2Sdanielk1977 " <bytes>", 0); 108951e3d8e2Sdanielk1977 return TCL_ERROR; 109051e3d8e2Sdanielk1977 } 109151e3d8e2Sdanielk1977 109251e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 109351e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 109451e3d8e2Sdanielk1977 value = Tcl_GetString(objv[3]); 109551e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; 109651e3d8e2Sdanielk1977 109751e3d8e2Sdanielk1977 rc = sqlite3_bind_text(pStmt, idx, value, bytes, 1); 109851e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 109951e3d8e2Sdanielk1977 return TCL_ERROR; 110051e3d8e2Sdanielk1977 } 110151e3d8e2Sdanielk1977 110251e3d8e2Sdanielk1977 return TCL_OK; 110351e3d8e2Sdanielk1977 } 110451e3d8e2Sdanielk1977 110551e3d8e2Sdanielk1977 static int test_bind_text16( 110651e3d8e2Sdanielk1977 void * clientData, 110751e3d8e2Sdanielk1977 Tcl_Interp *interp, 110851e3d8e2Sdanielk1977 int objc, 110951e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 111051e3d8e2Sdanielk1977 ){ 111151e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 111251e3d8e2Sdanielk1977 int idx; 111351e3d8e2Sdanielk1977 int bytes; 111451e3d8e2Sdanielk1977 char *value; 111551e3d8e2Sdanielk1977 int rc; 111651e3d8e2Sdanielk1977 111751e3d8e2Sdanielk1977 if( objc!=5 ){ 111851e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 111951e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>" 112051e3d8e2Sdanielk1977 " <bytes>", 0); 112151e3d8e2Sdanielk1977 return TCL_ERROR; 112251e3d8e2Sdanielk1977 } 112351e3d8e2Sdanielk1977 112451e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 112551e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 112651e3d8e2Sdanielk1977 value = Tcl_GetByteArrayFromObj(objv[3], 0); 112751e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; 112851e3d8e2Sdanielk1977 112951e3d8e2Sdanielk1977 rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, 1); 113051e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 113151e3d8e2Sdanielk1977 return TCL_ERROR; 113251e3d8e2Sdanielk1977 } 113351e3d8e2Sdanielk1977 113451e3d8e2Sdanielk1977 return TCL_OK; 113551e3d8e2Sdanielk1977 } 113651e3d8e2Sdanielk1977 113751e3d8e2Sdanielk1977 static int test_bind_blob( 113851e3d8e2Sdanielk1977 void * clientData, 113951e3d8e2Sdanielk1977 Tcl_Interp *interp, 114051e3d8e2Sdanielk1977 int objc, 114151e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 114251e3d8e2Sdanielk1977 ){ 114351e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 114451e3d8e2Sdanielk1977 int idx; 114551e3d8e2Sdanielk1977 int bytes; 114651e3d8e2Sdanielk1977 char *value; 114751e3d8e2Sdanielk1977 int rc; 114851e3d8e2Sdanielk1977 114951e3d8e2Sdanielk1977 if( objc!=5 ){ 115051e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 115151e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>" 115251e3d8e2Sdanielk1977 " <bytes>", 0); 115351e3d8e2Sdanielk1977 return TCL_ERROR; 115451e3d8e2Sdanielk1977 } 115551e3d8e2Sdanielk1977 115651e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 115751e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 115851e3d8e2Sdanielk1977 value = Tcl_GetString(objv[3]); 115951e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &bytes) ) return TCL_ERROR; 116051e3d8e2Sdanielk1977 116151e3d8e2Sdanielk1977 rc = sqlite3_bind_blob(pStmt, idx, value, bytes, 1); 116251e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 116351e3d8e2Sdanielk1977 return TCL_ERROR; 116451e3d8e2Sdanielk1977 } 116551e3d8e2Sdanielk1977 116651e3d8e2Sdanielk1977 return TCL_OK; 116751e3d8e2Sdanielk1977 } 116851e3d8e2Sdanielk1977 116999ee3600Sdrh /* 11706622cce3Sdanielk1977 ** Usage: sqlite3_errcode DB 11716622cce3Sdanielk1977 ** 11726622cce3Sdanielk1977 ** Return the string representation of the most recent sqlite3_* API 11736622cce3Sdanielk1977 ** error code. e.g. "SQLITE_ERROR". 11746622cce3Sdanielk1977 */ 11756622cce3Sdanielk1977 static int test_errcode( 11766622cce3Sdanielk1977 void * clientData, 11776622cce3Sdanielk1977 Tcl_Interp *interp, 11786622cce3Sdanielk1977 int objc, 11796622cce3Sdanielk1977 Tcl_Obj *CONST objv[] 11806622cce3Sdanielk1977 ){ 11816622cce3Sdanielk1977 sqlite3 *db; 11826622cce3Sdanielk1977 11836622cce3Sdanielk1977 if( objc!=2 ){ 11846622cce3Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 11856622cce3Sdanielk1977 Tcl_GetString(objv[0]), " DB", 0); 11866622cce3Sdanielk1977 return TCL_ERROR; 11876622cce3Sdanielk1977 } 11886622cce3Sdanielk1977 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 11896622cce3Sdanielk1977 Tcl_SetResult(interp, (char *)errorName(sqlite3_errcode(db)), 0); 11906622cce3Sdanielk1977 return TCL_OK; 11916622cce3Sdanielk1977 } 11926622cce3Sdanielk1977 11936622cce3Sdanielk1977 /* 11946622cce3Sdanielk1977 ** Usage: test_errmsg DB 11956622cce3Sdanielk1977 ** 11966622cce3Sdanielk1977 ** Returns the UTF-8 representation of the error message string for the 11976622cce3Sdanielk1977 ** most recent sqlite3_* API call. 11986622cce3Sdanielk1977 */ 11996622cce3Sdanielk1977 static int test_errmsg( 12006622cce3Sdanielk1977 void * clientData, 12016622cce3Sdanielk1977 Tcl_Interp *interp, 12026622cce3Sdanielk1977 int objc, 12036622cce3Sdanielk1977 Tcl_Obj *CONST objv[] 12046622cce3Sdanielk1977 ){ 12056622cce3Sdanielk1977 sqlite *db; 12066622cce3Sdanielk1977 const char *zErr; 12076622cce3Sdanielk1977 12086622cce3Sdanielk1977 if( objc!=2 ){ 12096622cce3Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 12106622cce3Sdanielk1977 Tcl_GetString(objv[0]), " DB", 0); 12116622cce3Sdanielk1977 return TCL_ERROR; 12126622cce3Sdanielk1977 } 12136622cce3Sdanielk1977 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 12146622cce3Sdanielk1977 12156622cce3Sdanielk1977 zErr = sqlite3_errmsg(db); 12166622cce3Sdanielk1977 Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1)); 12176622cce3Sdanielk1977 return TCL_OK; 12186622cce3Sdanielk1977 } 12196622cce3Sdanielk1977 12206622cce3Sdanielk1977 /* 12216622cce3Sdanielk1977 ** Usage: test_errmsg16 DB 12226622cce3Sdanielk1977 ** 12236622cce3Sdanielk1977 ** Returns the UTF-16 representation of the error message string for the 12246622cce3Sdanielk1977 ** most recent sqlite3_* API call. This is a byte array object at the TCL 12256622cce3Sdanielk1977 ** level, and it includes the 0x00 0x00 terminator bytes at the end of the 12266622cce3Sdanielk1977 ** UTF-16 string. 12276622cce3Sdanielk1977 */ 12286622cce3Sdanielk1977 static int test_errmsg16( 12296622cce3Sdanielk1977 void * clientData, 12306622cce3Sdanielk1977 Tcl_Interp *interp, 12316622cce3Sdanielk1977 int objc, 12326622cce3Sdanielk1977 Tcl_Obj *CONST objv[] 12336622cce3Sdanielk1977 ){ 12346622cce3Sdanielk1977 sqlite *db; 12356622cce3Sdanielk1977 const void *zErr; 12366622cce3Sdanielk1977 int bytes; 12376622cce3Sdanielk1977 12386622cce3Sdanielk1977 if( objc!=2 ){ 12396622cce3Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 12406622cce3Sdanielk1977 Tcl_GetString(objv[0]), " DB", 0); 12416622cce3Sdanielk1977 return TCL_ERROR; 12426622cce3Sdanielk1977 } 12436622cce3Sdanielk1977 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 12446622cce3Sdanielk1977 12456622cce3Sdanielk1977 zErr = sqlite3_errmsg16(db); 12466622cce3Sdanielk1977 bytes = sqlite3utf16ByteLen(zErr, -1); 12476622cce3Sdanielk1977 Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes)); 12486622cce3Sdanielk1977 return TCL_OK; 12496622cce3Sdanielk1977 } 12506622cce3Sdanielk1977 12516622cce3Sdanielk1977 /* 12526622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar 12536622cce3Sdanielk1977 ** 12546622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using 12556622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global 12566622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A 12576622cce3Sdanielk1977 ** STMT handle is returned. 12586622cce3Sdanielk1977 */ 12596622cce3Sdanielk1977 static int test_prepare( 12606622cce3Sdanielk1977 void * clientData, 12616622cce3Sdanielk1977 Tcl_Interp *interp, 12626622cce3Sdanielk1977 int objc, 12636622cce3Sdanielk1977 Tcl_Obj *CONST objv[] 12646622cce3Sdanielk1977 ){ 12656622cce3Sdanielk1977 sqlite3 *db; 12666622cce3Sdanielk1977 const char *zSql; 12676622cce3Sdanielk1977 int bytes; 12686622cce3Sdanielk1977 const char *zTail = 0; 12696622cce3Sdanielk1977 sqlite3_stmt *pStmt = 0; 12706622cce3Sdanielk1977 char zBuf[50]; 12714ad1713cSdanielk1977 int rc; 12726622cce3Sdanielk1977 12736622cce3Sdanielk1977 if( objc!=5 ){ 12746622cce3Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 12756622cce3Sdanielk1977 Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0); 12766622cce3Sdanielk1977 return TCL_ERROR; 12776622cce3Sdanielk1977 } 12786622cce3Sdanielk1977 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 12796622cce3Sdanielk1977 zSql = Tcl_GetString(objv[2]); 12806622cce3Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR; 12816622cce3Sdanielk1977 12824ad1713cSdanielk1977 rc = sqlite3_prepare(db, zSql, bytes, &pStmt, &zTail); 12836622cce3Sdanielk1977 if( zTail ){ 12846622cce3Sdanielk1977 if( bytes>=0 ){ 12856622cce3Sdanielk1977 bytes = bytes - (zTail-zSql); 12866622cce3Sdanielk1977 } 12876622cce3Sdanielk1977 Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0); 12886622cce3Sdanielk1977 } 12894ad1713cSdanielk1977 if( rc!=SQLITE_OK ){ 12904ad1713cSdanielk1977 assert( pStmt==0 ); 12914ad1713cSdanielk1977 sprintf(zBuf, "(%d) ", rc); 12924ad1713cSdanielk1977 Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0); 12934ad1713cSdanielk1977 return TCL_ERROR; 12944ad1713cSdanielk1977 } 12956622cce3Sdanielk1977 12964ad1713cSdanielk1977 if( pStmt ){ 12976622cce3Sdanielk1977 if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR; 12986622cce3Sdanielk1977 Tcl_AppendResult(interp, zBuf, 0); 12994ad1713cSdanielk1977 } 13006622cce3Sdanielk1977 return TCL_OK; 13016622cce3Sdanielk1977 } 13026622cce3Sdanielk1977 13036622cce3Sdanielk1977 /* 13046622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar 13056622cce3Sdanielk1977 ** 13066622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using 13076622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global 13086622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A 13096622cce3Sdanielk1977 ** STMT handle is returned. 13106622cce3Sdanielk1977 */ 13116622cce3Sdanielk1977 static int test_prepare16( 13126622cce3Sdanielk1977 void * clientData, 13136622cce3Sdanielk1977 Tcl_Interp *interp, 13146622cce3Sdanielk1977 int objc, 13156622cce3Sdanielk1977 Tcl_Obj *CONST objv[] 13166622cce3Sdanielk1977 ){ 13176622cce3Sdanielk1977 sqlite3 *db; 13186622cce3Sdanielk1977 const void *zSql; 13196622cce3Sdanielk1977 const void *zTail = 0; 13206622cce3Sdanielk1977 Tcl_Obj *pTail = 0; 13216622cce3Sdanielk1977 sqlite3_stmt *pStmt = 0; 13226622cce3Sdanielk1977 char zBuf[50]; 13236622cce3Sdanielk1977 int bytes; /* The integer specified as arg 3 */ 13246622cce3Sdanielk1977 int objlen; /* The byte-array length of arg 2 */ 13256622cce3Sdanielk1977 13266622cce3Sdanielk1977 if( objc!=5 ){ 13276622cce3Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 13286622cce3Sdanielk1977 Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0); 13296622cce3Sdanielk1977 return TCL_ERROR; 13306622cce3Sdanielk1977 } 13316622cce3Sdanielk1977 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 13326622cce3Sdanielk1977 zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen); 13336622cce3Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR; 13346622cce3Sdanielk1977 13356622cce3Sdanielk1977 if( SQLITE_OK!=sqlite3_prepare16(db, zSql, bytes, &pStmt, &zTail) ){ 13366622cce3Sdanielk1977 return TCL_ERROR; 13376622cce3Sdanielk1977 } 13386622cce3Sdanielk1977 13396622cce3Sdanielk1977 if( zTail ){ 13406622cce3Sdanielk1977 objlen = objlen - ((u8 *)zTail-(u8 *)zSql); 13416622cce3Sdanielk1977 }else{ 13426622cce3Sdanielk1977 objlen = 0; 13436622cce3Sdanielk1977 } 13446622cce3Sdanielk1977 pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen); 13456622cce3Sdanielk1977 Tcl_IncrRefCount(pTail); 13466622cce3Sdanielk1977 Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0); 13474ad1713cSdanielk1977 Tcl_DecrRefCount(pTail); 13486622cce3Sdanielk1977 13494ad1713cSdanielk1977 if( pStmt ){ 13506622cce3Sdanielk1977 if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR; 13514ad1713cSdanielk1977 } 13526622cce3Sdanielk1977 Tcl_AppendResult(interp, zBuf, 0); 13536622cce3Sdanielk1977 return TCL_OK; 13546622cce3Sdanielk1977 } 13556622cce3Sdanielk1977 13564ad1713cSdanielk1977 /* 13574ad1713cSdanielk1977 ** Usage: sqlite3_open filename ?options-list? 13584ad1713cSdanielk1977 */ 13594ad1713cSdanielk1977 static int test_open( 13604ad1713cSdanielk1977 void * clientData, 13614ad1713cSdanielk1977 Tcl_Interp *interp, 13624ad1713cSdanielk1977 int objc, 13634ad1713cSdanielk1977 Tcl_Obj *CONST objv[] 13644ad1713cSdanielk1977 ){ 13654ad1713cSdanielk1977 const char *zFilename; 13664ad1713cSdanielk1977 sqlite3 *db; 13674ad1713cSdanielk1977 int rc; 13684ad1713cSdanielk1977 char zBuf[100]; 13694ad1713cSdanielk1977 13704ad1713cSdanielk1977 if( objc!=3 && objc!=2 ){ 13714ad1713cSdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 13724ad1713cSdanielk1977 Tcl_GetString(objv[0]), " filename options-list", 0); 13734ad1713cSdanielk1977 return TCL_ERROR; 13744ad1713cSdanielk1977 } 13754ad1713cSdanielk1977 13764ad1713cSdanielk1977 zFilename = Tcl_GetString(objv[1]); 137780290863Sdanielk1977 rc = sqlite3_open(zFilename, &db, 0); 13784ad1713cSdanielk1977 13794ad1713cSdanielk1977 if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR; 13804ad1713cSdanielk1977 Tcl_AppendResult(interp, zBuf, 0); 13814ad1713cSdanielk1977 return TCL_OK; 13824ad1713cSdanielk1977 } 13834ad1713cSdanielk1977 13844ad1713cSdanielk1977 /* 13854ad1713cSdanielk1977 ** Usage: sqlite3_open16 filename options 13864ad1713cSdanielk1977 */ 13874ad1713cSdanielk1977 static int test_open16( 13884ad1713cSdanielk1977 void * clientData, 13894ad1713cSdanielk1977 Tcl_Interp *interp, 13904ad1713cSdanielk1977 int objc, 13914ad1713cSdanielk1977 Tcl_Obj *CONST objv[] 13924ad1713cSdanielk1977 ){ 13934ad1713cSdanielk1977 const void *zFilename; 13944ad1713cSdanielk1977 sqlite3 *db; 13954ad1713cSdanielk1977 int rc; 13964ad1713cSdanielk1977 char zBuf[100]; 13974ad1713cSdanielk1977 13984ad1713cSdanielk1977 if( objc!=3 ){ 13994ad1713cSdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 14004ad1713cSdanielk1977 Tcl_GetString(objv[0]), " filename options-list", 0); 14014ad1713cSdanielk1977 return TCL_ERROR; 14024ad1713cSdanielk1977 } 14034ad1713cSdanielk1977 14044ad1713cSdanielk1977 zFilename = Tcl_GetByteArrayFromObj(objv[1], 0); 14054ad1713cSdanielk1977 rc = sqlite3_open16(zFilename, &db, 0); 14064ad1713cSdanielk1977 14074ad1713cSdanielk1977 if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR; 14084ad1713cSdanielk1977 Tcl_AppendResult(interp, zBuf, 0); 14094ad1713cSdanielk1977 return TCL_OK; 14104ad1713cSdanielk1977 } 1411d3d39e93Sdrh 1412d3d39e93Sdrh /* 1413106bb236Sdanielk1977 ** Usage: sqlite3_step STMT 1414106bb236Sdanielk1977 ** 1415106bb236Sdanielk1977 ** Advance the statement to the next row. 1416106bb236Sdanielk1977 */ 1417106bb236Sdanielk1977 static int test_step_new( 1418106bb236Sdanielk1977 void * clientData, 1419106bb236Sdanielk1977 Tcl_Interp *interp, 1420106bb236Sdanielk1977 int objc, 1421106bb236Sdanielk1977 Tcl_Obj *CONST objv[] 1422106bb236Sdanielk1977 ){ 1423106bb236Sdanielk1977 sqlite3_stmt *pStmt; 1424106bb236Sdanielk1977 int rc; 1425106bb236Sdanielk1977 1426e1cd9874Sdanielk1977 if( objc!=2 ){ 1427106bb236Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 1428106bb236Sdanielk1977 Tcl_GetString(objv[0]), " STMT", 0); 1429106bb236Sdanielk1977 return TCL_ERROR; 1430106bb236Sdanielk1977 } 1431106bb236Sdanielk1977 1432106bb236Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 1433106bb236Sdanielk1977 rc = sqlite3_step_new(pStmt); 1434106bb236Sdanielk1977 1435e1cd9874Sdanielk1977 if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR; 1436e1cd9874Sdanielk1977 return TCL_OK; 1437e1cd9874Sdanielk1977 } 1438e1cd9874Sdanielk1977 1439e1cd9874Sdanielk1977 /* 1440e1cd9874Sdanielk1977 ** Usage: sqlite3_column_data STMT column 1441e1cd9874Sdanielk1977 ** 1442e1cd9874Sdanielk1977 ** Advance the statement to the next row. 1443e1cd9874Sdanielk1977 */ 1444e1cd9874Sdanielk1977 static int test_column_data( 1445e1cd9874Sdanielk1977 void * clientData, 1446e1cd9874Sdanielk1977 Tcl_Interp *interp, 1447e1cd9874Sdanielk1977 int objc, 1448e1cd9874Sdanielk1977 Tcl_Obj *CONST objv[] 1449e1cd9874Sdanielk1977 ){ 1450e1cd9874Sdanielk1977 sqlite3_stmt *pStmt; 1451e1cd9874Sdanielk1977 int col; 1452e1cd9874Sdanielk1977 Tcl_Obj *pRet; 1453e1cd9874Sdanielk1977 1454e1cd9874Sdanielk1977 if( objc!=3 ){ 1455e1cd9874Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 1456e1cd9874Sdanielk1977 Tcl_GetString(objv[0]), " STMT column", 0); 1457e1cd9874Sdanielk1977 return TCL_ERROR; 1458e1cd9874Sdanielk1977 } 1459e1cd9874Sdanielk1977 1460e1cd9874Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 1461e1cd9874Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; 1462e1cd9874Sdanielk1977 1463e1cd9874Sdanielk1977 if( SQLITE3_BLOB==sqlite3_column_type(pStmt, col) ){ 1464e1cd9874Sdanielk1977 int len = sqlite3_column_bytes(pStmt, col); 1465e1cd9874Sdanielk1977 pRet = Tcl_NewByteArrayObj(sqlite3_column_data(pStmt, col), len); 1466e1cd9874Sdanielk1977 }else{ 1467e1cd9874Sdanielk1977 pRet = Tcl_NewStringObj(sqlite3_column_data(pStmt, col), -1); 1468e1cd9874Sdanielk1977 } 1469e1cd9874Sdanielk1977 Tcl_SetObjResult(interp, pRet); 1470e1cd9874Sdanielk1977 1471e1cd9874Sdanielk1977 return TCL_OK; 1472e1cd9874Sdanielk1977 } 1473e1cd9874Sdanielk1977 1474e1cd9874Sdanielk1977 /* 1475e1cd9874Sdanielk1977 ** Usage: sqlite3_column_data16 STMT column 1476e1cd9874Sdanielk1977 ** 1477e1cd9874Sdanielk1977 ** Advance the statement to the next row. 1478e1cd9874Sdanielk1977 */ 1479e1cd9874Sdanielk1977 static int test_column_data16( 1480e1cd9874Sdanielk1977 void * clientData, 1481e1cd9874Sdanielk1977 Tcl_Interp *interp, 1482e1cd9874Sdanielk1977 int objc, 1483e1cd9874Sdanielk1977 Tcl_Obj *CONST objv[] 1484e1cd9874Sdanielk1977 ){ 1485e1cd9874Sdanielk1977 sqlite3_stmt *pStmt; 1486e1cd9874Sdanielk1977 int col; 1487e1cd9874Sdanielk1977 Tcl_Obj *pRet; 1488e1cd9874Sdanielk1977 int len; 1489e1cd9874Sdanielk1977 1490e1cd9874Sdanielk1977 if( objc!=3 ){ 1491e1cd9874Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 1492e1cd9874Sdanielk1977 Tcl_GetString(objv[0]), " STMT column", 0); 1493e1cd9874Sdanielk1977 return TCL_ERROR; 1494e1cd9874Sdanielk1977 } 1495e1cd9874Sdanielk1977 1496e1cd9874Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 1497e1cd9874Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; 1498e1cd9874Sdanielk1977 1499e1cd9874Sdanielk1977 len = sqlite3_column_bytes16(pStmt, col); 1500e1cd9874Sdanielk1977 pRet = Tcl_NewByteArrayObj(sqlite3_column_data16(pStmt, col), len); 1501e1cd9874Sdanielk1977 Tcl_SetObjResult(interp, pRet); 1502e1cd9874Sdanielk1977 1503106bb236Sdanielk1977 return TCL_OK; 1504106bb236Sdanielk1977 } 1505106bb236Sdanielk1977 1506106bb236Sdanielk1977 /* 1507d3d39e93Sdrh ** This is a collating function named "REVERSE" which sorts text 1508d3d39e93Sdrh ** in reverse order. 1509d3d39e93Sdrh */ 1510d3d39e93Sdrh static int reverseCollatingFunc( 1511d3d39e93Sdrh void *NotUsed, 1512d3d39e93Sdrh int nKey1, const void *pKey1, 1513d3d39e93Sdrh int nKey2, const void *pKey2 1514d3d39e93Sdrh ){ 1515d3d39e93Sdrh int rc, n; 1516d3d39e93Sdrh n = nKey1<nKey2 ? nKey1 : nKey2; 1517d3d39e93Sdrh rc = memcmp(pKey1, pKey2, n); 1518d3d39e93Sdrh if( rc==0 ){ 1519d3d39e93Sdrh rc = nKey1 - nKey2; 1520d3d39e93Sdrh } 1521d3d39e93Sdrh return -rc; 1522d3d39e93Sdrh } 1523d3d39e93Sdrh 1524d3d39e93Sdrh /* 1525d3d39e93Sdrh ** Usage: add_reverse_collating_func DB 1526d3d39e93Sdrh ** 1527d3d39e93Sdrh ** This routine adds a collation named "REVERSE" to database given. 1528d3d39e93Sdrh ** REVERSE is used for testing only. 1529d3d39e93Sdrh */ 1530d3d39e93Sdrh static int reverse_collfunc( 1531d3d39e93Sdrh void * clientData, 1532d3d39e93Sdrh Tcl_Interp *interp, 1533d3d39e93Sdrh int objc, 1534d3d39e93Sdrh Tcl_Obj *CONST objv[] 1535d3d39e93Sdrh ){ 1536d3d39e93Sdrh sqlite3 *db; 1537d3d39e93Sdrh 1538d3d39e93Sdrh if( objc!=2 ){ 1539d3d39e93Sdrh Tcl_WrongNumArgs(interp, 1, objv, "DB"); 1540d3d39e93Sdrh return TCL_ERROR; 1541d3d39e93Sdrh } 1542d3d39e93Sdrh if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 1543d3d39e93Sdrh sqlite3ChangeCollatingFunction(db, "REVERSE", 7, 0, reverseCollatingFunc); 1544d3d39e93Sdrh return TCL_OK; 1545d3d39e93Sdrh } 1546d3d39e93Sdrh 1547d3d39e93Sdrh 15486622cce3Sdanielk1977 /* 1549d1bf3512Sdrh ** Register commands with the TCL interpreter. 1550d1bf3512Sdrh */ 1551d1bf3512Sdrh int Sqlitetest1_Init(Tcl_Interp *interp){ 15526f8a503dSdanielk1977 extern int sqlite3_search_count; 15536f8a503dSdanielk1977 extern int sqlite3_interrupt_count; 15546f8a503dSdanielk1977 extern int sqlite3_open_file_count; 15556f8a503dSdanielk1977 extern int sqlite3_current_time; 1556c2eef3b3Sdrh static struct { 1557c2eef3b3Sdrh char *zName; 1558c2eef3b3Sdrh Tcl_CmdProc *xProc; 1559c2eef3b3Sdrh } aCmd[] = { 15606f8a503dSdanielk1977 { "sqlite3_mprintf_int", (Tcl_CmdProc*)sqlite3_mprintf_int }, 15616f8a503dSdanielk1977 { "sqlite3_mprintf_str", (Tcl_CmdProc*)sqlite3_mprintf_str }, 15626f8a503dSdanielk1977 { "sqlite3_mprintf_double", (Tcl_CmdProc*)sqlite3_mprintf_double }, 15636f8a503dSdanielk1977 { "sqlite3_mprintf_scaled", (Tcl_CmdProc*)sqlite3_mprintf_scaled }, 15646f8a503dSdanielk1977 { "sqlite3_mprintf_z_test", (Tcl_CmdProc*)test_mprintf_z }, 15654ad1713cSdanielk1977 // { "sqlite3_open", (Tcl_CmdProc*)sqlite_test_open }, 15666f8a503dSdanielk1977 { "sqlite3_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid }, 15676f8a503dSdanielk1977 { "sqlite3_exec_printf", (Tcl_CmdProc*)test_exec_printf }, 15686f8a503dSdanielk1977 { "sqlite3_get_table_printf", (Tcl_CmdProc*)test_get_table_printf }, 15696f8a503dSdanielk1977 { "sqlite3_close", (Tcl_CmdProc*)sqlite_test_close }, 15706f8a503dSdanielk1977 { "sqlite3_create_function", (Tcl_CmdProc*)test_create_function }, 15716f8a503dSdanielk1977 { "sqlite3_create_aggregate", (Tcl_CmdProc*)test_create_aggregate }, 1572c2eef3b3Sdrh { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func }, 1573c2eef3b3Sdrh { "sqlite_abort", (Tcl_CmdProc*)sqlite_abort }, 15745a38705eSdrh { "sqlite_datatypes", (Tcl_CmdProc*)sqlite_datatypes }, 1575c2eef3b3Sdrh #ifdef MEMORY_DEBUG 1576c2eef3b3Sdrh { "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail }, 1577c2eef3b3Sdrh { "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat }, 1578c2eef3b3Sdrh #endif 157996fc5fe6Sdanielk1977 { "sqlite_step", (Tcl_CmdProc*)test_step }, 1580106bb236Sdanielk1977 // { "sqlite_finalize", (Tcl_CmdProc*)test_finalize }, 158196fc5fe6Sdanielk1977 { "sqlite_bind", (Tcl_CmdProc*)test_bind }, 1582106bb236Sdanielk1977 // { "sqlite_reset", (Tcl_CmdProc*)test_reset }, 158399ee3600Sdrh { "breakpoint", (Tcl_CmdProc*)test_breakpoint }, 1584c2eef3b3Sdrh }; 158551e3d8e2Sdanielk1977 static struct { 158651e3d8e2Sdanielk1977 char *zName; 158751e3d8e2Sdanielk1977 Tcl_ObjCmdProc *xProc; 158851e3d8e2Sdanielk1977 } aObjCmd[] = { 158951e3d8e2Sdanielk1977 { "sqlite3_bind_int32", (Tcl_ObjCmdProc*)test_bind_int32 }, 159051e3d8e2Sdanielk1977 { "sqlite3_bind_int64", (Tcl_ObjCmdProc*)test_bind_int64 }, 159151e3d8e2Sdanielk1977 { "sqlite3_bind_double", (Tcl_ObjCmdProc*)test_bind_double }, 159251e3d8e2Sdanielk1977 { "sqlite3_bind_null", (Tcl_ObjCmdProc*)test_bind_null }, 159351e3d8e2Sdanielk1977 { "sqlite3_bind_text", (Tcl_ObjCmdProc*)test_bind_text }, 159451e3d8e2Sdanielk1977 { "sqlite3_bind_text16", (Tcl_ObjCmdProc*)test_bind_text16 }, 159551e3d8e2Sdanielk1977 { "sqlite3_bind_blob", (Tcl_ObjCmdProc*)test_bind_blob }, 15966622cce3Sdanielk1977 { "sqlite3_errcode", (Tcl_ObjCmdProc*)test_errcode }, 15976622cce3Sdanielk1977 { "sqlite3_errmsg", (Tcl_ObjCmdProc*)test_errmsg }, 15986622cce3Sdanielk1977 { "sqlite3_errmsg16", (Tcl_ObjCmdProc*)test_errmsg16 }, 15996622cce3Sdanielk1977 { "sqlite3_prepare", (Tcl_ObjCmdProc*)test_prepare }, 16006622cce3Sdanielk1977 { "sqlite3_prepare16", (Tcl_ObjCmdProc*)test_prepare16 }, 16014ad1713cSdanielk1977 { "sqlite3_open", (Tcl_ObjCmdProc*)test_open }, 16024ad1713cSdanielk1977 { "sqlite3_open16", (Tcl_ObjCmdProc*)test_open16 }, 1603106bb236Sdanielk1977 { "sqlite3_finalize", (Tcl_ObjCmdProc*)test_finalize }, 1604106bb236Sdanielk1977 { "sqlite3_reset", (Tcl_ObjCmdProc*)test_reset }, 1605106bb236Sdanielk1977 { "sqlite3_step", (Tcl_ObjCmdProc*)test_step_new }, 1606e1cd9874Sdanielk1977 { "sqlite3_column_data", (Tcl_ObjCmdProc*)test_column_data }, 1607e1cd9874Sdanielk1977 { "sqlite3_column_data16", (Tcl_ObjCmdProc*)test_column_data16 }, 1608d3d39e93Sdrh { "add_reverse_collating_func", (Tcl_ObjCmdProc*)reverse_collfunc }, 160951e3d8e2Sdanielk1977 }; 1610c2eef3b3Sdrh int i; 1611c2eef3b3Sdrh 1612c2eef3b3Sdrh for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ 1613c2eef3b3Sdrh Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); 1614c2eef3b3Sdrh } 161551e3d8e2Sdanielk1977 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ 161651e3d8e2Sdanielk1977 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); 161751e3d8e2Sdanielk1977 } 16186490bebdSdanielk1977 Tcl_LinkVar(interp, "sqlite_search_count", 16196f8a503dSdanielk1977 (char*)&sqlite3_search_count, TCL_LINK_INT); 16206490bebdSdanielk1977 Tcl_LinkVar(interp, "sqlite_interrupt_count", 16216f8a503dSdanielk1977 (char*)&sqlite3_interrupt_count, TCL_LINK_INT); 16226490bebdSdanielk1977 Tcl_LinkVar(interp, "sqlite_open_file_count", 16236f8a503dSdanielk1977 (char*)&sqlite3_open_file_count, TCL_LINK_INT); 16246490bebdSdanielk1977 Tcl_LinkVar(interp, "sqlite_current_time", 16256f8a503dSdanielk1977 (char*)&sqlite3_current_time, TCL_LINK_INT); 16267c972decSdrh Tcl_LinkVar(interp, "sqlite_static_bind_value", 16277c972decSdrh (char*)&sqlite_static_bind_value, TCL_LINK_STRING); 1628d1bf3512Sdrh return TCL_OK; 1629d1bf3512Sdrh } 1630