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*6590493dSdanielk1977 ** $Id: test1.c,v 1.55 2004/05/26 06:18:38 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 /* 8051e3d8e2Sdanielk1977 ** Decode a pointer to an sqlite3_stmt object. 8151e3d8e2Sdanielk1977 */ 8251e3d8e2Sdanielk1977 static int getStmtPointer( 8351e3d8e2Sdanielk1977 Tcl_Interp *interp, 8451e3d8e2Sdanielk1977 const char *zArg, 8551e3d8e2Sdanielk1977 sqlite3_stmt **ppStmt 8651e3d8e2Sdanielk1977 ){ 8751e3d8e2Sdanielk1977 if( sscanf(zArg, PTR_FMT, (void**)ppStmt)!=1 ){ 8851e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0); 8951e3d8e2Sdanielk1977 return TCL_ERROR; 9051e3d8e2Sdanielk1977 } 9151e3d8e2Sdanielk1977 return TCL_OK; 9251e3d8e2Sdanielk1977 } 9351e3d8e2Sdanielk1977 9451e3d8e2Sdanielk1977 /* 957d8085a8Sdrh ** Generate a text representation of a pointer that can be understood 967d8085a8Sdrh ** by the getDbPointer and getVmPointer routines above. 977d8085a8Sdrh ** 987d8085a8Sdrh ** The problem is, on some machines (Solaris) if you do a printf with 997d8085a8Sdrh ** "%p" you cannot turn around and do a scanf with the same "%p" and 1007d8085a8Sdrh ** get your pointer back. You have to prepend a "0x" before it will 1017d8085a8Sdrh ** work. Or at least that is what is reported to me (drh). But this 1027d8085a8Sdrh ** behavior varies from machine to machine. The solution used her is 1037d8085a8Sdrh ** to test the string right after it is generated to see if it can be 1047d8085a8Sdrh ** understood by scanf, and if not, try prepending an "0x" to see if 1057d8085a8Sdrh ** that helps. If nothing works, a fatal error is generated. 1067d8085a8Sdrh */ 1077d8085a8Sdrh static int makePointerStr(Tcl_Interp *interp, char *zPtr, void *p){ 1087d8085a8Sdrh void *p2; 1097d8085a8Sdrh sprintf(zPtr, PTR_FMT, p); 1107d8085a8Sdrh if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){ 1117d8085a8Sdrh sprintf(zPtr, "0x" PTR_FMT, p); 1127d8085a8Sdrh if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){ 1137d8085a8Sdrh Tcl_AppendResult(interp, "unable to convert a pointer to a string " 1147d8085a8Sdrh "in the file " __FILE__ " in function makePointerStr(). Please " 1157d8085a8Sdrh "report this problem to the SQLite mailing list or as a new but " 1167d8085a8Sdrh "report. Please provide detailed information about how you compiled " 1177d8085a8Sdrh "SQLite and what computer you are running on.", 0); 1187d8085a8Sdrh return TCL_ERROR; 1197d8085a8Sdrh } 1207d8085a8Sdrh } 1217d8085a8Sdrh return TCL_OK; 1227d8085a8Sdrh } 1237d8085a8Sdrh 1247d8085a8Sdrh /* 1256f8a503dSdanielk1977 ** The callback routine for sqlite3_exec_printf(). 126d1bf3512Sdrh */ 127d1bf3512Sdrh static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){ 128d1bf3512Sdrh Tcl_DString *str = (Tcl_DString*)pArg; 129d1bf3512Sdrh int i; 130d1bf3512Sdrh 131d1bf3512Sdrh if( Tcl_DStringLength(str)==0 ){ 132d1bf3512Sdrh for(i=0; i<argc; i++){ 133d1bf3512Sdrh Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL"); 134d1bf3512Sdrh } 135d1bf3512Sdrh } 136d1bf3512Sdrh for(i=0; i<argc; i++){ 137d1bf3512Sdrh Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL"); 138d1bf3512Sdrh } 139d1bf3512Sdrh return 0; 140d1bf3512Sdrh } 141d1bf3512Sdrh 142d1bf3512Sdrh /* 1436f8a503dSdanielk1977 ** Usage: sqlite3_exec_printf DB FORMAT STRING 144d1bf3512Sdrh ** 1456f8a503dSdanielk1977 ** Invoke the sqlite3_exec_printf() interface using the open database 146d1bf3512Sdrh ** DB. The SQL is the string FORMAT. The format string should contain 147d1bf3512Sdrh ** one %s or %q. STRING is the value inserted into %s or %q. 148d1bf3512Sdrh */ 149d1bf3512Sdrh static int test_exec_printf( 150d1bf3512Sdrh void *NotUsed, 151d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 152d1bf3512Sdrh int argc, /* Number of arguments */ 153d1bf3512Sdrh char **argv /* Text of each argument */ 154d1bf3512Sdrh ){ 155d1bf3512Sdrh sqlite *db; 156d1bf3512Sdrh Tcl_DString str; 157d1bf3512Sdrh int rc; 158d1bf3512Sdrh char *zErr = 0; 159d1bf3512Sdrh char zBuf[30]; 160d1bf3512Sdrh if( argc!=4 ){ 161d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 162d1bf3512Sdrh " DB FORMAT STRING", 0); 163d1bf3512Sdrh return TCL_ERROR; 164d1bf3512Sdrh } 165b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 166d1bf3512Sdrh Tcl_DStringInit(&str); 1676f8a503dSdanielk1977 rc = sqlite3_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]); 168d1bf3512Sdrh sprintf(zBuf, "%d", rc); 169d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 170d1bf3512Sdrh Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr); 171d1bf3512Sdrh Tcl_DStringFree(&str); 172d1bf3512Sdrh if( zErr ) free(zErr); 173d1bf3512Sdrh return TCL_OK; 174d1bf3512Sdrh } 175d1bf3512Sdrh 176d1bf3512Sdrh /* 1776f8a503dSdanielk1977 ** Usage: sqlite3_mprintf_z_test SEPARATOR ARG0 ARG1 ... 178d93d8a81Sdrh ** 179d93d8a81Sdrh ** Test the %z format of mprintf(). Use multiple mprintf() calls to 180d93d8a81Sdrh ** concatenate arg0 through argn using separator as the separator. 181d93d8a81Sdrh ** Return the result. 182d93d8a81Sdrh */ 183d93d8a81Sdrh static int test_mprintf_z( 184d93d8a81Sdrh void *NotUsed, 185d93d8a81Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 186d93d8a81Sdrh int argc, /* Number of arguments */ 187d93d8a81Sdrh char **argv /* Text of each argument */ 188d93d8a81Sdrh ){ 189d93d8a81Sdrh char *zResult = 0; 190d93d8a81Sdrh int i; 191d93d8a81Sdrh 192d93d8a81Sdrh for(i=2; i<argc; i++){ 1934adee20fSdanielk1977 zResult = sqlite3MPrintf("%z%s%s", zResult, argv[1], argv[i]); 194d93d8a81Sdrh } 195d93d8a81Sdrh Tcl_AppendResult(interp, zResult, 0); 1965f968436Sdrh sqliteFree(zResult); 197d93d8a81Sdrh return TCL_OK; 198d93d8a81Sdrh } 199d93d8a81Sdrh 200d93d8a81Sdrh /* 2016f8a503dSdanielk1977 ** Usage: sqlite3_get_table_printf DB FORMAT STRING 202d1bf3512Sdrh ** 2036f8a503dSdanielk1977 ** Invoke the sqlite3_get_table_printf() interface using the open database 204d1bf3512Sdrh ** DB. The SQL is the string FORMAT. The format string should contain 205d1bf3512Sdrh ** one %s or %q. STRING is the value inserted into %s or %q. 206d1bf3512Sdrh */ 207d1bf3512Sdrh static int test_get_table_printf( 208d1bf3512Sdrh void *NotUsed, 209d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 210d1bf3512Sdrh int argc, /* Number of arguments */ 211d1bf3512Sdrh char **argv /* Text of each argument */ 212d1bf3512Sdrh ){ 213d1bf3512Sdrh sqlite *db; 214d1bf3512Sdrh Tcl_DString str; 215d1bf3512Sdrh int rc; 216d1bf3512Sdrh char *zErr = 0; 217d1bf3512Sdrh int nRow, nCol; 218d1bf3512Sdrh char **aResult; 219d1bf3512Sdrh int i; 220d1bf3512Sdrh char zBuf[30]; 221d1bf3512Sdrh if( argc!=4 ){ 222d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 223d1bf3512Sdrh " DB FORMAT STRING", 0); 224d1bf3512Sdrh return TCL_ERROR; 225d1bf3512Sdrh } 226b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 227d1bf3512Sdrh Tcl_DStringInit(&str); 2286f8a503dSdanielk1977 rc = sqlite3_get_table_printf(db, argv[2], &aResult, &nRow, &nCol, 229d1bf3512Sdrh &zErr, argv[3]); 230d1bf3512Sdrh sprintf(zBuf, "%d", rc); 231d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 232d1bf3512Sdrh if( rc==SQLITE_OK ){ 233d1bf3512Sdrh sprintf(zBuf, "%d", nRow); 234d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 235d1bf3512Sdrh sprintf(zBuf, "%d", nCol); 236d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 237d1bf3512Sdrh for(i=0; i<(nRow+1)*nCol; i++){ 238d1bf3512Sdrh Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL"); 239d1bf3512Sdrh } 240d1bf3512Sdrh }else{ 241d1bf3512Sdrh Tcl_AppendElement(interp, zErr); 242d1bf3512Sdrh } 2436f8a503dSdanielk1977 sqlite3_free_table(aResult); 244d1bf3512Sdrh if( zErr ) free(zErr); 245d1bf3512Sdrh return TCL_OK; 246d1bf3512Sdrh } 247d1bf3512Sdrh 248af9ff33aSdrh 249af9ff33aSdrh /* 2506f8a503dSdanielk1977 ** Usage: sqlite3_last_insert_rowid DB 251af9ff33aSdrh ** 252af9ff33aSdrh ** Returns the integer ROWID of the most recent insert. 253af9ff33aSdrh */ 254af9ff33aSdrh static int test_last_rowid( 255af9ff33aSdrh void *NotUsed, 256af9ff33aSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 257af9ff33aSdrh int argc, /* Number of arguments */ 258af9ff33aSdrh char **argv /* Text of each argument */ 259af9ff33aSdrh ){ 260af9ff33aSdrh sqlite *db; 261af9ff33aSdrh char zBuf[30]; 262af9ff33aSdrh 263af9ff33aSdrh if( argc!=2 ){ 264af9ff33aSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0); 265af9ff33aSdrh return TCL_ERROR; 266af9ff33aSdrh } 267b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 2686f8a503dSdanielk1977 sprintf(zBuf, "%d", sqlite3_last_insert_rowid(db)); 269af9ff33aSdrh Tcl_AppendResult(interp, zBuf, 0); 270af9ff33aSdrh return SQLITE_OK; 271af9ff33aSdrh } 272af9ff33aSdrh 273d1bf3512Sdrh /* 2746f8a503dSdanielk1977 ** Usage: sqlite3_close DB 275d1bf3512Sdrh ** 2766f8a503dSdanielk1977 ** Closes the database opened by sqlite3_open. 277d1bf3512Sdrh */ 278d1bf3512Sdrh static int sqlite_test_close( 279d1bf3512Sdrh void *NotUsed, 280d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 281d1bf3512Sdrh int argc, /* Number of arguments */ 282d1bf3512Sdrh char **argv /* Text of each argument */ 283d1bf3512Sdrh ){ 284d1bf3512Sdrh sqlite *db; 285d1bf3512Sdrh if( argc!=2 ){ 286d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 287d1bf3512Sdrh " FILENAME\"", 0); 288d1bf3512Sdrh return TCL_ERROR; 289d1bf3512Sdrh } 290b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 2916f8a503dSdanielk1977 sqlite3_close(db); 292d1bf3512Sdrh return TCL_OK; 293d1bf3512Sdrh } 294d1bf3512Sdrh 295d1bf3512Sdrh /* 296c22bd47dSdrh ** Implementation of the x_coalesce() function. 297c22bd47dSdrh ** Return the first argument non-NULL argument. 298c22bd47dSdrh */ 2990ae8b831Sdanielk1977 static void ifnullFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ 300c22bd47dSdrh int i; 301c22bd47dSdrh for(i=0; i<argc; i++){ 30251ad0ecdSdanielk1977 if( SQLITE3_NULL!=sqlite3_value_type(argv[i]) ){ 3037e18c259Sdanielk1977 sqlite3_result_text(context, sqlite3_value_data(argv[i]), -1, 1); 304c22bd47dSdrh break; 305c22bd47dSdrh } 306c22bd47dSdrh } 307c22bd47dSdrh } 308c22bd47dSdrh 309c22bd47dSdrh /* 310d1d9fc33Sdrh ** A structure into which to accumulate text. 311d1d9fc33Sdrh */ 312d1d9fc33Sdrh struct dstr { 313d1d9fc33Sdrh int nAlloc; /* Space allocated */ 314d1d9fc33Sdrh int nUsed; /* Space used */ 315d1d9fc33Sdrh char *z; /* The space */ 316d1d9fc33Sdrh }; 317d1d9fc33Sdrh 318d1d9fc33Sdrh /* 319d1d9fc33Sdrh ** Append text to a dstr 320d1d9fc33Sdrh */ 321d1d9fc33Sdrh static void dstrAppend(struct dstr *p, const char *z, int divider){ 322d1d9fc33Sdrh int n = strlen(z); 323d1d9fc33Sdrh if( p->nUsed + n + 2 > p->nAlloc ){ 324d1d9fc33Sdrh char *zNew; 325d1d9fc33Sdrh p->nAlloc = p->nAlloc*2 + n + 200; 326d1d9fc33Sdrh zNew = sqliteRealloc(p->z, p->nAlloc); 327d1d9fc33Sdrh if( zNew==0 ){ 328d1d9fc33Sdrh sqliteFree(p->z); 329d1d9fc33Sdrh memset(p, 0, sizeof(*p)); 330d1d9fc33Sdrh return; 331d1d9fc33Sdrh } 332d1d9fc33Sdrh p->z = zNew; 333d1d9fc33Sdrh } 334d1d9fc33Sdrh if( divider && p->nUsed>0 ){ 335d1d9fc33Sdrh p->z[p->nUsed++] = divider; 336d1d9fc33Sdrh } 337d1d9fc33Sdrh memcpy(&p->z[p->nUsed], z, n+1); 338d1d9fc33Sdrh p->nUsed += n; 339d1d9fc33Sdrh } 340d1d9fc33Sdrh 341d1d9fc33Sdrh /* 3424adee20fSdanielk1977 ** Invoked for each callback from sqlite3ExecFunc 343d1d9fc33Sdrh */ 344d1d9fc33Sdrh static int execFuncCallback(void *pData, int argc, char **argv, char **NotUsed){ 345d1d9fc33Sdrh struct dstr *p = (struct dstr*)pData; 346d1d9fc33Sdrh int i; 347d1d9fc33Sdrh for(i=0; i<argc; i++){ 348d1d9fc33Sdrh if( argv[i]==0 ){ 349d1d9fc33Sdrh dstrAppend(p, "NULL", ' '); 350d1d9fc33Sdrh }else{ 351d1d9fc33Sdrh dstrAppend(p, argv[i], ' '); 352d1d9fc33Sdrh } 353d1d9fc33Sdrh } 354d1d9fc33Sdrh return 0; 355d1d9fc33Sdrh } 356d1d9fc33Sdrh 357d1d9fc33Sdrh /* 3586f8a503dSdanielk1977 ** Implementation of the x_sqlite3_exec() function. This function takes 359c22bd47dSdrh ** a single argument and attempts to execute that argument as SQL code. 3606cbe1f1bSdrh ** This is illegal and should set the SQLITE_MISUSE flag on the database. 361c22bd47dSdrh ** 3626f8a503dSdanielk1977 ** 2004-Jan-07: We have changed this to make it legal to call sqlite3_exec() 363d1d9fc33Sdrh ** from within a function call. 364d1d9fc33Sdrh ** 365c22bd47dSdrh ** This routine simulates the effect of having two threads attempt to 366c22bd47dSdrh ** use the same database at the same time. 367c22bd47dSdrh */ 36851ad0ecdSdanielk1977 static void sqlite3ExecFunc( 3690ae8b831Sdanielk1977 sqlite3_context *context, 37051ad0ecdSdanielk1977 int argc, 37151ad0ecdSdanielk1977 sqlite3_value **argv 37251ad0ecdSdanielk1977 ){ 373d1d9fc33Sdrh struct dstr x; 374d1d9fc33Sdrh memset(&x, 0, sizeof(x)); 37551ad0ecdSdanielk1977 sqlite3_exec((sqlite*)sqlite3_user_data(context), 37651ad0ecdSdanielk1977 sqlite3_value_data(argv[0]), 377d1d9fc33Sdrh execFuncCallback, &x, 0); 3787e18c259Sdanielk1977 sqlite3_result_text(context, x.z, x.nUsed, 1); 379d1d9fc33Sdrh sqliteFree(x.z); 380c22bd47dSdrh } 381c22bd47dSdrh 382c22bd47dSdrh /* 383c22bd47dSdrh ** Usage: sqlite_test_create_function DB 384c22bd47dSdrh ** 3856f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order 386c22bd47dSdrh ** to create a function named "x_coalesce". This function does the same thing 387c22bd47dSdrh ** as the "coalesce" function. This function also registers an SQL function 3886f8a503dSdanielk1977 ** named "x_sqlite3_exec" that invokes sqlite3_exec(). Invoking sqlite3_exec() 389c22bd47dSdrh ** in this way is illegal recursion and should raise an SQLITE_MISUSE error. 390c22bd47dSdrh ** The effect is similar to trying to use the same database connection from 391c22bd47dSdrh ** two threads at the same time. 392c22bd47dSdrh ** 393c22bd47dSdrh ** The original motivation for this routine was to be able to call the 3946f8a503dSdanielk1977 ** sqlite3_create_function function while a query is in progress in order 395c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic. 396c22bd47dSdrh */ 397c2eef3b3Sdrh static int test_create_function( 398c22bd47dSdrh void *NotUsed, 399c22bd47dSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 400c22bd47dSdrh int argc, /* Number of arguments */ 401c22bd47dSdrh char **argv /* Text of each argument */ 402c22bd47dSdrh ){ 403c22bd47dSdrh sqlite *db; 404c22bd47dSdrh extern void Md5_Register(sqlite*); 405c22bd47dSdrh if( argc!=2 ){ 406c22bd47dSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 407c22bd47dSdrh " FILENAME\"", 0); 408c22bd47dSdrh return TCL_ERROR; 409c22bd47dSdrh } 410b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 411*6590493dSdanielk1977 sqlite3_create_function(db, "x_coalesce", -1, 0, 0, 0, ifnullFunc, 0, 0); 412*6590493dSdanielk1977 sqlite3_create_function(db, "x_sqlite3_exec", 1, 0, 0, db, 413*6590493dSdanielk1977 sqlite3ExecFunc, 0, 0); 414c22bd47dSdrh return TCL_OK; 415c22bd47dSdrh } 416c22bd47dSdrh 417c22bd47dSdrh /* 418c22bd47dSdrh ** Routines to implement the x_count() aggregate function. 419c22bd47dSdrh */ 420c22bd47dSdrh typedef struct CountCtx CountCtx; 421c22bd47dSdrh struct CountCtx { 422c22bd47dSdrh int n; 423c22bd47dSdrh }; 4240ae8b831Sdanielk1977 static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){ 425c22bd47dSdrh CountCtx *p; 4260ae8b831Sdanielk1977 p = sqlite3_get_context(context, sizeof(*p)); 4276ddcca55Sdanielk1977 if( (argc==0 || SQLITE3_NULL!=sqlite3_value_type(argv[0]) ) && p ){ 428c22bd47dSdrh p->n++; 429c22bd47dSdrh } 430c22bd47dSdrh } 4310ae8b831Sdanielk1977 static void countFinalize(sqlite3_context *context){ 432c22bd47dSdrh CountCtx *p; 4330ae8b831Sdanielk1977 p = sqlite3_get_context(context, sizeof(*p)); 4347e18c259Sdanielk1977 sqlite3_result_int32(context, p ? p->n : 0); 435c22bd47dSdrh } 436c22bd47dSdrh 437c22bd47dSdrh /* 438c22bd47dSdrh ** Usage: sqlite_test_create_aggregate DB 439c22bd47dSdrh ** 4406f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order 441c22bd47dSdrh ** to create a function named "x_count". This function does the same thing 442c22bd47dSdrh ** as the "md5sum" function. 443c22bd47dSdrh ** 444c22bd47dSdrh ** The original motivation for this routine was to be able to call the 4456f8a503dSdanielk1977 ** sqlite3_create_aggregate function while a query is in progress in order 446c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic. 447c22bd47dSdrh */ 448c2eef3b3Sdrh static int test_create_aggregate( 449c22bd47dSdrh void *NotUsed, 450c22bd47dSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 451c22bd47dSdrh int argc, /* Number of arguments */ 452c22bd47dSdrh char **argv /* Text of each argument */ 453c22bd47dSdrh ){ 454c22bd47dSdrh sqlite *db; 455c22bd47dSdrh if( argc!=2 ){ 456c22bd47dSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 457c22bd47dSdrh " FILENAME\"", 0); 458c22bd47dSdrh return TCL_ERROR; 459c22bd47dSdrh } 460b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 461*6590493dSdanielk1977 sqlite3_create_function(db, "x_count", 0, 0, 0, 0, 0,countStep,countFinalize); 462*6590493dSdanielk1977 sqlite3_create_function(db, "x_count", 1, 0, 0, 0, 0,countStep,countFinalize); 463c22bd47dSdrh return TCL_OK; 464c22bd47dSdrh } 465c22bd47dSdrh 466c22bd47dSdrh 467c22bd47dSdrh 468c22bd47dSdrh /* 4696f8a503dSdanielk1977 ** Usage: sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER 470d1bf3512Sdrh ** 471d1bf3512Sdrh ** Call mprintf with three integer arguments 472d1bf3512Sdrh */ 4736f8a503dSdanielk1977 static int sqlite3_mprintf_int( 474d1bf3512Sdrh void *NotUsed, 475d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 476d1bf3512Sdrh int argc, /* Number of arguments */ 477d1bf3512Sdrh char **argv /* Text of each argument */ 478d1bf3512Sdrh ){ 479d1bf3512Sdrh int a[3], i; 480d1bf3512Sdrh char *z; 481d1bf3512Sdrh if( argc!=5 ){ 482d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 483d1bf3512Sdrh " FORMAT INT INT INT\"", 0); 484d1bf3512Sdrh return TCL_ERROR; 485d1bf3512Sdrh } 486d1bf3512Sdrh for(i=2; i<5; i++){ 487d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 488d1bf3512Sdrh } 4896f8a503dSdanielk1977 z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]); 490d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 4916f8a503dSdanielk1977 sqlite3_freemem(z); 492d1bf3512Sdrh return TCL_OK; 493d1bf3512Sdrh } 494d1bf3512Sdrh 495d1bf3512Sdrh /* 4966f8a503dSdanielk1977 ** Usage: sqlite3_mprintf_str FORMAT INTEGER INTEGER STRING 497d1bf3512Sdrh ** 498d1bf3512Sdrh ** Call mprintf with two integer arguments and one string argument 499d1bf3512Sdrh */ 5006f8a503dSdanielk1977 static int sqlite3_mprintf_str( 501d1bf3512Sdrh void *NotUsed, 502d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 503d1bf3512Sdrh int argc, /* Number of arguments */ 504d1bf3512Sdrh char **argv /* Text of each argument */ 505d1bf3512Sdrh ){ 506d1bf3512Sdrh int a[3], i; 507d1bf3512Sdrh char *z; 508f220b24fSchw if( argc<4 || argc>5 ){ 509d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 510f220b24fSchw " FORMAT INT INT ?STRING?\"", 0); 511d1bf3512Sdrh return TCL_ERROR; 512d1bf3512Sdrh } 513d1bf3512Sdrh for(i=2; i<4; i++){ 514d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 515d1bf3512Sdrh } 5166f8a503dSdanielk1977 z = sqlite3_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL); 517d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 5186f8a503dSdanielk1977 sqlite3_freemem(z); 519d1bf3512Sdrh return TCL_OK; 520d1bf3512Sdrh } 521d1bf3512Sdrh 522d1bf3512Sdrh /* 5236f8a503dSdanielk1977 ** Usage: sqlite3_mprintf_str FORMAT INTEGER INTEGER DOUBLE 524d1bf3512Sdrh ** 525d1bf3512Sdrh ** Call mprintf with two integer arguments and one double argument 526d1bf3512Sdrh */ 5276f8a503dSdanielk1977 static int sqlite3_mprintf_double( 528d1bf3512Sdrh void *NotUsed, 529d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 530d1bf3512Sdrh int argc, /* Number of arguments */ 531d1bf3512Sdrh char **argv /* Text of each argument */ 532d1bf3512Sdrh ){ 533d1bf3512Sdrh int a[3], i; 534d1bf3512Sdrh double r; 535d1bf3512Sdrh char *z; 536d1bf3512Sdrh if( argc!=5 ){ 537d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 538d1bf3512Sdrh " FORMAT INT INT STRING\"", 0); 539d1bf3512Sdrh return TCL_ERROR; 540d1bf3512Sdrh } 541d1bf3512Sdrh for(i=2; i<4; i++){ 542d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 543d1bf3512Sdrh } 544d1bf3512Sdrh if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR; 5456f8a503dSdanielk1977 z = sqlite3_mprintf(argv[1], a[0], a[1], r); 546d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 5476f8a503dSdanielk1977 sqlite3_freemem(z); 548d1bf3512Sdrh return TCL_OK; 549d1bf3512Sdrh } 550d1bf3512Sdrh 551d1bf3512Sdrh /* 5526f8a503dSdanielk1977 ** Usage: sqlite3_mprintf_str FORMAT DOUBLE DOUBLE 553b621c237Sdrh ** 554b621c237Sdrh ** Call mprintf with a single double argument which is the product of the 555b621c237Sdrh ** two arguments given above. This is used to generate overflow and underflow 556b621c237Sdrh ** doubles to test that they are converted properly. 557b621c237Sdrh */ 5586f8a503dSdanielk1977 static int sqlite3_mprintf_scaled( 559b621c237Sdrh void *NotUsed, 560b621c237Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 561b621c237Sdrh int argc, /* Number of arguments */ 562b621c237Sdrh char **argv /* Text of each argument */ 563b621c237Sdrh ){ 564b621c237Sdrh int i; 565b621c237Sdrh double r[2]; 566b621c237Sdrh char *z; 567b621c237Sdrh if( argc!=4 ){ 568b621c237Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 569b621c237Sdrh " FORMAT DOUBLE DOUBLE\"", 0); 570b621c237Sdrh return TCL_ERROR; 571b621c237Sdrh } 572b621c237Sdrh for(i=2; i<4; i++){ 573b621c237Sdrh if( Tcl_GetDouble(interp, argv[i], &r[i-2]) ) return TCL_ERROR; 574b621c237Sdrh } 5756f8a503dSdanielk1977 z = sqlite3_mprintf(argv[1], r[0]*r[1]); 576b621c237Sdrh Tcl_AppendResult(interp, z, 0); 5776f8a503dSdanielk1977 sqlite3_freemem(z); 578b621c237Sdrh return TCL_OK; 579b621c237Sdrh } 580b621c237Sdrh 581b621c237Sdrh /* 582daffd0e5Sdrh ** Usage: sqlite_malloc_fail N 583daffd0e5Sdrh ** 584afa4a020Sdrh ** Rig sqliteMalloc() to fail on the N-th call. Turn off this mechanism 5856f8a503dSdanielk1977 ** and reset the sqlite3_malloc_failed variable is N==0. 586daffd0e5Sdrh */ 587daffd0e5Sdrh #ifdef MEMORY_DEBUG 588daffd0e5Sdrh static int sqlite_malloc_fail( 589daffd0e5Sdrh void *NotUsed, 590daffd0e5Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 591daffd0e5Sdrh int argc, /* Number of arguments */ 592daffd0e5Sdrh char **argv /* Text of each argument */ 593daffd0e5Sdrh ){ 594daffd0e5Sdrh int n; 595daffd0e5Sdrh if( argc!=2 ){ 596daffd0e5Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0); 597daffd0e5Sdrh return TCL_ERROR; 598daffd0e5Sdrh } 599daffd0e5Sdrh if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR; 6006f8a503dSdanielk1977 sqlite3_iMallocFail = n; 6016f8a503dSdanielk1977 sqlite3_malloc_failed = 0; 602daffd0e5Sdrh return TCL_OK; 603daffd0e5Sdrh } 604daffd0e5Sdrh #endif 605daffd0e5Sdrh 606daffd0e5Sdrh /* 607daffd0e5Sdrh ** Usage: sqlite_malloc_stat 608daffd0e5Sdrh ** 609daffd0e5Sdrh ** Return the number of prior calls to sqliteMalloc() and sqliteFree(). 610daffd0e5Sdrh */ 611daffd0e5Sdrh #ifdef MEMORY_DEBUG 612daffd0e5Sdrh static int sqlite_malloc_stat( 613daffd0e5Sdrh void *NotUsed, 614daffd0e5Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 615daffd0e5Sdrh int argc, /* Number of arguments */ 616daffd0e5Sdrh char **argv /* Text of each argument */ 617daffd0e5Sdrh ){ 618daffd0e5Sdrh char zBuf[200]; 6196f8a503dSdanielk1977 sprintf(zBuf, "%d %d %d", sqlite3_nMalloc, sqlite3_nFree, sqlite3_iMallocFail); 620daffd0e5Sdrh Tcl_AppendResult(interp, zBuf, 0); 621daffd0e5Sdrh return TCL_OK; 622daffd0e5Sdrh } 623daffd0e5Sdrh #endif 624daffd0e5Sdrh 625daffd0e5Sdrh /* 62628b4e489Sdrh ** Usage: sqlite_abort 62728b4e489Sdrh ** 62828b4e489Sdrh ** Shutdown the process immediately. This is not a clean shutdown. 62928b4e489Sdrh ** This command is used to test the recoverability of a database in 63028b4e489Sdrh ** the event of a program crash. 63128b4e489Sdrh */ 63228b4e489Sdrh static int sqlite_abort( 63328b4e489Sdrh void *NotUsed, 63428b4e489Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 63528b4e489Sdrh int argc, /* Number of arguments */ 63628b4e489Sdrh char **argv /* Text of each argument */ 63728b4e489Sdrh ){ 63828b4e489Sdrh assert( interp==0 ); /* This will always fail */ 63928b4e489Sdrh return TCL_OK; 64028b4e489Sdrh } 64128b4e489Sdrh 64228b4e489Sdrh /* 6436cbe1f1bSdrh ** The following routine is a user-defined SQL function whose purpose 6446cbe1f1bSdrh ** is to test the sqlite_set_result() API. 6456cbe1f1bSdrh */ 6460ae8b831Sdanielk1977 static void testFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ 6476cbe1f1bSdrh while( argc>=2 ){ 64851ad0ecdSdanielk1977 const char *zArg0 = sqlite3_value_data(argv[0]); 64951ad0ecdSdanielk1977 const char *zArg1 = sqlite3_value_data(argv[1]); 65051ad0ecdSdanielk1977 if( zArg0==0 ){ 6517e18c259Sdanielk1977 sqlite3_result_error(context, "first argument to test function " 6526cbe1f1bSdrh "may not be NULL", -1); 65351ad0ecdSdanielk1977 }else if( sqlite3StrICmp(zArg0,"string")==0 ){ 6547e18c259Sdanielk1977 sqlite3_result_text(context, zArg1, -1, 1); 65551ad0ecdSdanielk1977 }else if( zArg1==0 ){ 6567e18c259Sdanielk1977 sqlite3_result_error(context, "2nd argument may not be NULL if the " 6576cbe1f1bSdrh "first argument is not \"string\"", -1); 65851ad0ecdSdanielk1977 }else if( sqlite3StrICmp(zArg0,"int")==0 ){ 6597e18c259Sdanielk1977 sqlite3_result_int32(context, atoi(zArg1)); 66051ad0ecdSdanielk1977 }else if( sqlite3StrICmp(zArg0,"double")==0 ){ 6617e18c259Sdanielk1977 sqlite3_result_double(context, sqlite3AtoF(zArg1, 0)); 6626cbe1f1bSdrh }else{ 6637e18c259Sdanielk1977 sqlite3_result_error(context,"first argument should be one of: " 6646cbe1f1bSdrh "string int double", -1); 6656cbe1f1bSdrh } 6666cbe1f1bSdrh argc -= 2; 6676cbe1f1bSdrh argv += 2; 6686cbe1f1bSdrh } 6696cbe1f1bSdrh } 6706cbe1f1bSdrh 6716cbe1f1bSdrh /* 6726cbe1f1bSdrh ** Usage: sqlite_register_test_function DB NAME 6736cbe1f1bSdrh ** 6746cbe1f1bSdrh ** Register the test SQL function on the database DB under the name NAME. 6756cbe1f1bSdrh */ 676c2eef3b3Sdrh static int test_register_func( 6776cbe1f1bSdrh void *NotUsed, 6786cbe1f1bSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 6796cbe1f1bSdrh int argc, /* Number of arguments */ 6806cbe1f1bSdrh char **argv /* Text of each argument */ 6816cbe1f1bSdrh ){ 6826cbe1f1bSdrh sqlite *db; 6836cbe1f1bSdrh int rc; 6846cbe1f1bSdrh if( argc!=3 ){ 6856cbe1f1bSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 6866cbe1f1bSdrh " DB FUNCTION-NAME", 0); 6876cbe1f1bSdrh return TCL_ERROR; 6886cbe1f1bSdrh } 689b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 690*6590493dSdanielk1977 rc = sqlite3_create_function(db, argv[2], -1, 0, 0, 0, testFunc, 0, 0); 6916cbe1f1bSdrh if( rc!=0 ){ 6926f8a503dSdanielk1977 Tcl_AppendResult(interp, sqlite3_error_string(rc), 0); 6936cbe1f1bSdrh return TCL_ERROR; 6946cbe1f1bSdrh } 6956cbe1f1bSdrh return TCL_OK; 6966cbe1f1bSdrh } 6976cbe1f1bSdrh 6986cbe1f1bSdrh /* 6995a38705eSdrh ** This SQLite callback records the datatype of all columns. 7005a38705eSdrh ** 7015a38705eSdrh ** The pArg argument is really a pointer to a TCL interpreter. The 7025a38705eSdrh ** column names are inserted as the result of this interpreter. 7035a38705eSdrh ** 7045a38705eSdrh ** This routine returns non-zero which causes the query to abort. 7055a38705eSdrh */ 7065a38705eSdrh static int rememberDataTypes(void *pArg, int nCol, char **argv, char **colv){ 7075a38705eSdrh int i; 7085a38705eSdrh Tcl_Interp *interp = (Tcl_Interp*)pArg; 7095a38705eSdrh Tcl_Obj *pList, *pElem; 7105a38705eSdrh if( colv[nCol+1]==0 ){ 7115a38705eSdrh return 1; 7125a38705eSdrh } 7135a38705eSdrh pList = Tcl_NewObj(); 7145a38705eSdrh for(i=0; i<nCol; i++){ 7155a38705eSdrh pElem = Tcl_NewStringObj(colv[i+nCol] ? colv[i+nCol] : "NULL", -1); 7165a38705eSdrh Tcl_ListObjAppendElement(interp, pList, pElem); 7175a38705eSdrh } 7185a38705eSdrh Tcl_SetObjResult(interp, pList); 7195a38705eSdrh return 1; 7205a38705eSdrh } 7215a38705eSdrh 7225a38705eSdrh /* 7235a38705eSdrh ** Invoke an SQL statement but ignore all the data in the result. Instead, 7245a38705eSdrh ** return a list that consists of the datatypes of the various columns. 7255a38705eSdrh ** 7265a38705eSdrh ** This only works if "PRAGMA show_datatypes=on" has been executed against 7275a38705eSdrh ** the database connection. 7285a38705eSdrh */ 7295a38705eSdrh static int sqlite_datatypes( 7305a38705eSdrh void *NotUsed, 7315a38705eSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 7325a38705eSdrh int argc, /* Number of arguments */ 7335a38705eSdrh char **argv /* Text of each argument */ 7345a38705eSdrh ){ 7355a38705eSdrh sqlite *db; 7365a38705eSdrh int rc; 7375a38705eSdrh if( argc!=3 ){ 7385a38705eSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 7395a38705eSdrh " DB SQL", 0); 7405a38705eSdrh return TCL_ERROR; 7415a38705eSdrh } 742b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 7436f8a503dSdanielk1977 rc = sqlite3_exec(db, argv[2], rememberDataTypes, interp, 0); 7445a38705eSdrh if( rc!=0 && rc!=SQLITE_ABORT ){ 7456f8a503dSdanielk1977 Tcl_AppendResult(interp, sqlite3_error_string(rc), 0); 7465a38705eSdrh return TCL_ERROR; 7475a38705eSdrh } 7485a38705eSdrh return TCL_OK; 7495a38705eSdrh } 7505a38705eSdrh 751b86ccfb2Sdrh /* 752106bb236Sdanielk1977 ** Usage: sqlite3_finalize STMT 753b86ccfb2Sdrh ** 754106bb236Sdanielk1977 ** Finalize a statement handle. 755b86ccfb2Sdrh */ 756b86ccfb2Sdrh static int test_finalize( 757106bb236Sdanielk1977 void * clientData, 758106bb236Sdanielk1977 Tcl_Interp *interp, 759106bb236Sdanielk1977 int objc, 760106bb236Sdanielk1977 Tcl_Obj *CONST objv[] 761b86ccfb2Sdrh ){ 762106bb236Sdanielk1977 sqlite3_stmt *pStmt; 763b86ccfb2Sdrh int rc; 764106bb236Sdanielk1977 765106bb236Sdanielk1977 if( objc!=2 ){ 766106bb236Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 767106bb236Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0); 768b86ccfb2Sdrh return TCL_ERROR; 769b86ccfb2Sdrh } 770106bb236Sdanielk1977 771106bb236Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 772106bb236Sdanielk1977 773fc57d7bfSdanielk1977 rc = sqlite3_finalize(pStmt); 774b86ccfb2Sdrh if( rc ){ 775106bb236Sdanielk1977 return TCL_ERROR; 776106bb236Sdanielk1977 } 777106bb236Sdanielk1977 return TCL_OK; 778106bb236Sdanielk1977 } 779106bb236Sdanielk1977 780106bb236Sdanielk1977 /* 781106bb236Sdanielk1977 ** Usage: sqlite3_reset STMT 782106bb236Sdanielk1977 ** 783106bb236Sdanielk1977 ** Finalize a statement handle. 784106bb236Sdanielk1977 */ 785106bb236Sdanielk1977 static int test_reset( 786106bb236Sdanielk1977 void * clientData, 787106bb236Sdanielk1977 Tcl_Interp *interp, 788106bb236Sdanielk1977 int objc, 789106bb236Sdanielk1977 Tcl_Obj *CONST objv[] 790106bb236Sdanielk1977 ){ 791106bb236Sdanielk1977 sqlite3_stmt *pStmt; 792106bb236Sdanielk1977 int rc; 793106bb236Sdanielk1977 794106bb236Sdanielk1977 if( objc!=2 ){ 795106bb236Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 796106bb236Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0); 797106bb236Sdanielk1977 return TCL_ERROR; 798106bb236Sdanielk1977 } 799106bb236Sdanielk1977 800106bb236Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 801106bb236Sdanielk1977 802fc57d7bfSdanielk1977 rc = sqlite3_reset(pStmt); 803106bb236Sdanielk1977 if( rc ){ 804b86ccfb2Sdrh return TCL_ERROR; 805b86ccfb2Sdrh } 806b86ccfb2Sdrh return TCL_OK; 807b86ccfb2Sdrh } 808b86ccfb2Sdrh 8095a38705eSdrh /* 8106f8a503dSdanielk1977 ** Usage: sqlite3_reset VM 81150457896Sdrh ** 81250457896Sdrh ** Reset a virtual machine and prepare it to be run again. 81350457896Sdrh */ 81450457896Sdrh 81550457896Sdrh /* 8167c972decSdrh ** This is the "static_bind_value" that variables are bound to when 8176f8a503dSdanielk1977 ** the FLAG option of sqlite3_bind is "static" 81850457896Sdrh */ 8197c972decSdrh static char *sqlite_static_bind_value = 0; 8207c972decSdrh 8217c972decSdrh /* 8226f8a503dSdanielk1977 ** Usage: sqlite3_bind VM IDX VALUE FLAGS 8237c972decSdrh ** 8247c972decSdrh ** Sets the value of the IDX-th occurance of "?" in the original SQL 8257c972decSdrh ** string. VALUE is the new value. If FLAGS=="null" then VALUE is 8267c972decSdrh ** ignored and the value is set to NULL. If FLAGS=="static" then 8277c972decSdrh ** the value is set to the value of a static variable named 8287c972decSdrh ** "sqlite_static_bind_value". If FLAGS=="normal" then a copy 8297c972decSdrh ** of the VALUE is made. 8307c972decSdrh */ 8317c972decSdrh static int test_bind( 83250457896Sdrh void *NotUsed, 83350457896Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 83450457896Sdrh int argc, /* Number of arguments */ 83550457896Sdrh char **argv /* Text of each argument */ 83650457896Sdrh ){ 837fc57d7bfSdanielk1977 sqlite3_stmt *pStmt; 83850457896Sdrh int rc; 8397c972decSdrh int idx; 8407c972decSdrh if( argc!=5 ){ 84150457896Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 8427c972decSdrh " VM IDX VALUE (null|static|normal)\"", 0); 84350457896Sdrh return TCL_ERROR; 84450457896Sdrh } 845fc57d7bfSdanielk1977 if( getStmtPointer(interp, argv[1], &pStmt) ) return TCL_ERROR; 8467c972decSdrh if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR; 8477c972decSdrh if( strcmp(argv[4],"null")==0 ){ 848fc57d7bfSdanielk1977 rc = sqlite3_bind_null(pStmt, idx); 8497c972decSdrh }else if( strcmp(argv[4],"static")==0 ){ 850fc57d7bfSdanielk1977 rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0); 8517c972decSdrh }else if( strcmp(argv[4],"normal")==0 ){ 852fc57d7bfSdanielk1977 rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, 1); 8537c972decSdrh }else{ 8547c972decSdrh Tcl_AppendResult(interp, "4th argument should be " 8557c972decSdrh "\"null\" or \"static\" or \"normal\"", 0); 8567c972decSdrh return TCL_ERROR; 8577c972decSdrh } 85850457896Sdrh if( rc ){ 85950457896Sdrh char zBuf[50]; 86050457896Sdrh sprintf(zBuf, "(%d) ", rc); 8616f8a503dSdanielk1977 Tcl_AppendResult(interp, zBuf, sqlite3_error_string(rc), 0); 86250457896Sdrh return TCL_ERROR; 86350457896Sdrh } 86450457896Sdrh return TCL_OK; 86550457896Sdrh } 86650457896Sdrh 86750457896Sdrh /* 86899ee3600Sdrh ** Usage: breakpoint 86999ee3600Sdrh ** 87099ee3600Sdrh ** This routine exists for one purpose - to provide a place to put a 87199ee3600Sdrh ** breakpoint with GDB that can be triggered using TCL code. The use 87299ee3600Sdrh ** for this is when a particular test fails on (say) the 1485th iteration. 87399ee3600Sdrh ** In the TCL test script, we can add code like this: 87499ee3600Sdrh ** 87599ee3600Sdrh ** if {$i==1485} breakpoint 87699ee3600Sdrh ** 87799ee3600Sdrh ** Then run testfixture in the debugger and wait for the breakpoint to 87899ee3600Sdrh ** fire. Then additional breakpoints can be set to trace down the bug. 87999ee3600Sdrh */ 88099ee3600Sdrh static int test_breakpoint( 88199ee3600Sdrh void *NotUsed, 88299ee3600Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 88399ee3600Sdrh int argc, /* Number of arguments */ 88499ee3600Sdrh char **argv /* Text of each argument */ 88599ee3600Sdrh ){ 88699ee3600Sdrh return TCL_OK; /* Do nothing */ 88799ee3600Sdrh } 88899ee3600Sdrh 88951e3d8e2Sdanielk1977 static int test_bind_int32( 89051e3d8e2Sdanielk1977 void * clientData, 89151e3d8e2Sdanielk1977 Tcl_Interp *interp, 89251e3d8e2Sdanielk1977 int objc, 89351e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 89451e3d8e2Sdanielk1977 ){ 89551e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 89651e3d8e2Sdanielk1977 int idx; 89751e3d8e2Sdanielk1977 int value; 89851e3d8e2Sdanielk1977 int rc; 89951e3d8e2Sdanielk1977 90051e3d8e2Sdanielk1977 if( objc!=4 ){ 90151e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 90251e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0); 90351e3d8e2Sdanielk1977 return TCL_ERROR; 90451e3d8e2Sdanielk1977 } 90551e3d8e2Sdanielk1977 90651e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 90751e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 90851e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[3], &value) ) return TCL_ERROR; 90951e3d8e2Sdanielk1977 91051e3d8e2Sdanielk1977 rc = sqlite3_bind_int32(pStmt, idx, value); 91151e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 91251e3d8e2Sdanielk1977 return TCL_ERROR; 91351e3d8e2Sdanielk1977 } 91451e3d8e2Sdanielk1977 91551e3d8e2Sdanielk1977 return TCL_OK; 91651e3d8e2Sdanielk1977 } 91751e3d8e2Sdanielk1977 91851e3d8e2Sdanielk1977 static int test_bind_int64( 91951e3d8e2Sdanielk1977 void * clientData, 92051e3d8e2Sdanielk1977 Tcl_Interp *interp, 92151e3d8e2Sdanielk1977 int objc, 92251e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 92351e3d8e2Sdanielk1977 ){ 92451e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 92551e3d8e2Sdanielk1977 int idx; 92651e3d8e2Sdanielk1977 i64 value; 92751e3d8e2Sdanielk1977 int rc; 92851e3d8e2Sdanielk1977 92951e3d8e2Sdanielk1977 if( objc!=4 ){ 93051e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 93151e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0); 93251e3d8e2Sdanielk1977 return TCL_ERROR; 93351e3d8e2Sdanielk1977 } 93451e3d8e2Sdanielk1977 93551e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 93651e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 93751e3d8e2Sdanielk1977 if( Tcl_GetWideIntFromObj(interp, objv[3], &value) ) return TCL_ERROR; 93851e3d8e2Sdanielk1977 93951e3d8e2Sdanielk1977 rc = sqlite3_bind_int64(pStmt, idx, value); 94051e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 94151e3d8e2Sdanielk1977 return TCL_ERROR; 94251e3d8e2Sdanielk1977 } 94351e3d8e2Sdanielk1977 94451e3d8e2Sdanielk1977 return TCL_OK; 94551e3d8e2Sdanielk1977 } 94651e3d8e2Sdanielk1977 94751e3d8e2Sdanielk1977 static int test_bind_double( 94851e3d8e2Sdanielk1977 void * clientData, 94951e3d8e2Sdanielk1977 Tcl_Interp *interp, 95051e3d8e2Sdanielk1977 int objc, 95151e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 95251e3d8e2Sdanielk1977 ){ 95351e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 95451e3d8e2Sdanielk1977 int idx; 95551e3d8e2Sdanielk1977 double value; 95651e3d8e2Sdanielk1977 int rc; 95751e3d8e2Sdanielk1977 95851e3d8e2Sdanielk1977 if( objc!=4 ){ 95951e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 96051e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0); 96151e3d8e2Sdanielk1977 return TCL_ERROR; 96251e3d8e2Sdanielk1977 } 96351e3d8e2Sdanielk1977 96451e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 96551e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 96651e3d8e2Sdanielk1977 if( Tcl_GetDoubleFromObj(interp, objv[3], &value) ) return TCL_ERROR; 96751e3d8e2Sdanielk1977 96851e3d8e2Sdanielk1977 rc = sqlite3_bind_double(pStmt, idx, value); 96951e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 97051e3d8e2Sdanielk1977 return TCL_ERROR; 97151e3d8e2Sdanielk1977 } 97251e3d8e2Sdanielk1977 97351e3d8e2Sdanielk1977 return TCL_OK; 97451e3d8e2Sdanielk1977 } 97551e3d8e2Sdanielk1977 97651e3d8e2Sdanielk1977 static int test_bind_null( 97751e3d8e2Sdanielk1977 void * clientData, 97851e3d8e2Sdanielk1977 Tcl_Interp *interp, 97951e3d8e2Sdanielk1977 int objc, 98051e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 98151e3d8e2Sdanielk1977 ){ 98251e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 98351e3d8e2Sdanielk1977 int idx; 98451e3d8e2Sdanielk1977 int rc; 98551e3d8e2Sdanielk1977 98651e3d8e2Sdanielk1977 if( objc!=3 ){ 98751e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 98851e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.>", 0); 98951e3d8e2Sdanielk1977 return TCL_ERROR; 99051e3d8e2Sdanielk1977 } 99151e3d8e2Sdanielk1977 99251e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 99351e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 99451e3d8e2Sdanielk1977 99551e3d8e2Sdanielk1977 rc = sqlite3_bind_null(pStmt, idx); 99651e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 99751e3d8e2Sdanielk1977 return TCL_ERROR; 99851e3d8e2Sdanielk1977 } 99951e3d8e2Sdanielk1977 100051e3d8e2Sdanielk1977 return TCL_OK; 100151e3d8e2Sdanielk1977 } 100251e3d8e2Sdanielk1977 100351e3d8e2Sdanielk1977 static int test_bind_text( 100451e3d8e2Sdanielk1977 void * clientData, 100551e3d8e2Sdanielk1977 Tcl_Interp *interp, 100651e3d8e2Sdanielk1977 int objc, 100751e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 100851e3d8e2Sdanielk1977 ){ 100951e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 101051e3d8e2Sdanielk1977 int idx; 101151e3d8e2Sdanielk1977 int bytes; 101251e3d8e2Sdanielk1977 char *value; 101351e3d8e2Sdanielk1977 int rc; 101451e3d8e2Sdanielk1977 101551e3d8e2Sdanielk1977 if( objc!=5 ){ 101651e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 101751e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>" 101851e3d8e2Sdanielk1977 " <bytes>", 0); 101951e3d8e2Sdanielk1977 return TCL_ERROR; 102051e3d8e2Sdanielk1977 } 102151e3d8e2Sdanielk1977 102251e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 102351e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 102451e3d8e2Sdanielk1977 value = Tcl_GetString(objv[3]); 102551e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; 102651e3d8e2Sdanielk1977 102751e3d8e2Sdanielk1977 rc = sqlite3_bind_text(pStmt, idx, value, bytes, 1); 102851e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 102951e3d8e2Sdanielk1977 return TCL_ERROR; 103051e3d8e2Sdanielk1977 } 103151e3d8e2Sdanielk1977 103251e3d8e2Sdanielk1977 return TCL_OK; 103351e3d8e2Sdanielk1977 } 103451e3d8e2Sdanielk1977 103551e3d8e2Sdanielk1977 static int test_bind_text16( 103651e3d8e2Sdanielk1977 void * clientData, 103751e3d8e2Sdanielk1977 Tcl_Interp *interp, 103851e3d8e2Sdanielk1977 int objc, 103951e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 104051e3d8e2Sdanielk1977 ){ 104151e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 104251e3d8e2Sdanielk1977 int idx; 104351e3d8e2Sdanielk1977 int bytes; 104451e3d8e2Sdanielk1977 char *value; 104551e3d8e2Sdanielk1977 int rc; 104651e3d8e2Sdanielk1977 104751e3d8e2Sdanielk1977 if( objc!=5 ){ 104851e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 104951e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>" 105051e3d8e2Sdanielk1977 " <bytes>", 0); 105151e3d8e2Sdanielk1977 return TCL_ERROR; 105251e3d8e2Sdanielk1977 } 105351e3d8e2Sdanielk1977 105451e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 105551e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 105651e3d8e2Sdanielk1977 value = Tcl_GetByteArrayFromObj(objv[3], 0); 105751e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; 105851e3d8e2Sdanielk1977 105951e3d8e2Sdanielk1977 rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, 1); 106051e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 106151e3d8e2Sdanielk1977 return TCL_ERROR; 106251e3d8e2Sdanielk1977 } 106351e3d8e2Sdanielk1977 106451e3d8e2Sdanielk1977 return TCL_OK; 106551e3d8e2Sdanielk1977 } 106651e3d8e2Sdanielk1977 106751e3d8e2Sdanielk1977 static int test_bind_blob( 106851e3d8e2Sdanielk1977 void * clientData, 106951e3d8e2Sdanielk1977 Tcl_Interp *interp, 107051e3d8e2Sdanielk1977 int objc, 107151e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 107251e3d8e2Sdanielk1977 ){ 107351e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 107451e3d8e2Sdanielk1977 int idx; 107551e3d8e2Sdanielk1977 int bytes; 107651e3d8e2Sdanielk1977 char *value; 107751e3d8e2Sdanielk1977 int rc; 107851e3d8e2Sdanielk1977 107951e3d8e2Sdanielk1977 if( objc!=5 ){ 108051e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 108151e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>" 108251e3d8e2Sdanielk1977 " <bytes>", 0); 108351e3d8e2Sdanielk1977 return TCL_ERROR; 108451e3d8e2Sdanielk1977 } 108551e3d8e2Sdanielk1977 108651e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 108751e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 108851e3d8e2Sdanielk1977 value = Tcl_GetString(objv[3]); 108951e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &bytes) ) return TCL_ERROR; 109051e3d8e2Sdanielk1977 109151e3d8e2Sdanielk1977 rc = sqlite3_bind_blob(pStmt, idx, value, bytes, 1); 109251e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 109351e3d8e2Sdanielk1977 return TCL_ERROR; 109451e3d8e2Sdanielk1977 } 109551e3d8e2Sdanielk1977 109651e3d8e2Sdanielk1977 return TCL_OK; 109751e3d8e2Sdanielk1977 } 109851e3d8e2Sdanielk1977 109999ee3600Sdrh /* 11006622cce3Sdanielk1977 ** Usage: sqlite3_errcode DB 11016622cce3Sdanielk1977 ** 11026622cce3Sdanielk1977 ** Return the string representation of the most recent sqlite3_* API 11036622cce3Sdanielk1977 ** error code. e.g. "SQLITE_ERROR". 11046622cce3Sdanielk1977 */ 11056622cce3Sdanielk1977 static int test_errcode( 11066622cce3Sdanielk1977 void * clientData, 11076622cce3Sdanielk1977 Tcl_Interp *interp, 11086622cce3Sdanielk1977 int objc, 11096622cce3Sdanielk1977 Tcl_Obj *CONST objv[] 11106622cce3Sdanielk1977 ){ 11116622cce3Sdanielk1977 sqlite3 *db; 11126622cce3Sdanielk1977 11136622cce3Sdanielk1977 if( objc!=2 ){ 11146622cce3Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 11156622cce3Sdanielk1977 Tcl_GetString(objv[0]), " DB", 0); 11166622cce3Sdanielk1977 return TCL_ERROR; 11176622cce3Sdanielk1977 } 11186622cce3Sdanielk1977 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 11196622cce3Sdanielk1977 Tcl_SetResult(interp, (char *)errorName(sqlite3_errcode(db)), 0); 11206622cce3Sdanielk1977 return TCL_OK; 11216622cce3Sdanielk1977 } 11226622cce3Sdanielk1977 11236622cce3Sdanielk1977 /* 11246622cce3Sdanielk1977 ** Usage: test_errmsg DB 11256622cce3Sdanielk1977 ** 11266622cce3Sdanielk1977 ** Returns the UTF-8 representation of the error message string for the 11276622cce3Sdanielk1977 ** most recent sqlite3_* API call. 11286622cce3Sdanielk1977 */ 11296622cce3Sdanielk1977 static int test_errmsg( 11306622cce3Sdanielk1977 void * clientData, 11316622cce3Sdanielk1977 Tcl_Interp *interp, 11326622cce3Sdanielk1977 int objc, 11336622cce3Sdanielk1977 Tcl_Obj *CONST objv[] 11346622cce3Sdanielk1977 ){ 11356622cce3Sdanielk1977 sqlite *db; 11366622cce3Sdanielk1977 const char *zErr; 11376622cce3Sdanielk1977 11386622cce3Sdanielk1977 if( objc!=2 ){ 11396622cce3Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 11406622cce3Sdanielk1977 Tcl_GetString(objv[0]), " DB", 0); 11416622cce3Sdanielk1977 return TCL_ERROR; 11426622cce3Sdanielk1977 } 11436622cce3Sdanielk1977 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 11446622cce3Sdanielk1977 11456622cce3Sdanielk1977 zErr = sqlite3_errmsg(db); 11466622cce3Sdanielk1977 Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1)); 11476622cce3Sdanielk1977 return TCL_OK; 11486622cce3Sdanielk1977 } 11496622cce3Sdanielk1977 11506622cce3Sdanielk1977 /* 11516622cce3Sdanielk1977 ** Usage: test_errmsg16 DB 11526622cce3Sdanielk1977 ** 11536622cce3Sdanielk1977 ** Returns the UTF-16 representation of the error message string for the 11546622cce3Sdanielk1977 ** most recent sqlite3_* API call. This is a byte array object at the TCL 11556622cce3Sdanielk1977 ** level, and it includes the 0x00 0x00 terminator bytes at the end of the 11566622cce3Sdanielk1977 ** UTF-16 string. 11576622cce3Sdanielk1977 */ 11586622cce3Sdanielk1977 static int test_errmsg16( 11596622cce3Sdanielk1977 void * clientData, 11606622cce3Sdanielk1977 Tcl_Interp *interp, 11616622cce3Sdanielk1977 int objc, 11626622cce3Sdanielk1977 Tcl_Obj *CONST objv[] 11636622cce3Sdanielk1977 ){ 11646622cce3Sdanielk1977 sqlite *db; 11656622cce3Sdanielk1977 const void *zErr; 11666622cce3Sdanielk1977 int bytes; 11676622cce3Sdanielk1977 11686622cce3Sdanielk1977 if( objc!=2 ){ 11696622cce3Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 11706622cce3Sdanielk1977 Tcl_GetString(objv[0]), " DB", 0); 11716622cce3Sdanielk1977 return TCL_ERROR; 11726622cce3Sdanielk1977 } 11736622cce3Sdanielk1977 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 11746622cce3Sdanielk1977 11756622cce3Sdanielk1977 zErr = sqlite3_errmsg16(db); 11766622cce3Sdanielk1977 bytes = sqlite3utf16ByteLen(zErr, -1); 11776622cce3Sdanielk1977 Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes)); 11786622cce3Sdanielk1977 return TCL_OK; 11796622cce3Sdanielk1977 } 11806622cce3Sdanielk1977 11816622cce3Sdanielk1977 /* 11826622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar 11836622cce3Sdanielk1977 ** 11846622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using 11856622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global 11866622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A 11876622cce3Sdanielk1977 ** STMT handle is returned. 11886622cce3Sdanielk1977 */ 11896622cce3Sdanielk1977 static int test_prepare( 11906622cce3Sdanielk1977 void * clientData, 11916622cce3Sdanielk1977 Tcl_Interp *interp, 11926622cce3Sdanielk1977 int objc, 11936622cce3Sdanielk1977 Tcl_Obj *CONST objv[] 11946622cce3Sdanielk1977 ){ 11956622cce3Sdanielk1977 sqlite3 *db; 11966622cce3Sdanielk1977 const char *zSql; 11976622cce3Sdanielk1977 int bytes; 11986622cce3Sdanielk1977 const char *zTail = 0; 11996622cce3Sdanielk1977 sqlite3_stmt *pStmt = 0; 12006622cce3Sdanielk1977 char zBuf[50]; 12014ad1713cSdanielk1977 int rc; 12026622cce3Sdanielk1977 12036622cce3Sdanielk1977 if( objc!=5 ){ 12046622cce3Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 12056622cce3Sdanielk1977 Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0); 12066622cce3Sdanielk1977 return TCL_ERROR; 12076622cce3Sdanielk1977 } 12086622cce3Sdanielk1977 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 12096622cce3Sdanielk1977 zSql = Tcl_GetString(objv[2]); 12106622cce3Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR; 12116622cce3Sdanielk1977 12124ad1713cSdanielk1977 rc = sqlite3_prepare(db, zSql, bytes, &pStmt, &zTail); 12136622cce3Sdanielk1977 if( zTail ){ 12146622cce3Sdanielk1977 if( bytes>=0 ){ 12156622cce3Sdanielk1977 bytes = bytes - (zTail-zSql); 12166622cce3Sdanielk1977 } 12176622cce3Sdanielk1977 Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0); 12186622cce3Sdanielk1977 } 12194ad1713cSdanielk1977 if( rc!=SQLITE_OK ){ 12204ad1713cSdanielk1977 assert( pStmt==0 ); 12214ad1713cSdanielk1977 sprintf(zBuf, "(%d) ", rc); 12224ad1713cSdanielk1977 Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0); 12234ad1713cSdanielk1977 return TCL_ERROR; 12244ad1713cSdanielk1977 } 12256622cce3Sdanielk1977 12264ad1713cSdanielk1977 if( pStmt ){ 12276622cce3Sdanielk1977 if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR; 12286622cce3Sdanielk1977 Tcl_AppendResult(interp, zBuf, 0); 12294ad1713cSdanielk1977 } 12306622cce3Sdanielk1977 return TCL_OK; 12316622cce3Sdanielk1977 } 12326622cce3Sdanielk1977 12336622cce3Sdanielk1977 /* 12346622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar 12356622cce3Sdanielk1977 ** 12366622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using 12376622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global 12386622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A 12396622cce3Sdanielk1977 ** STMT handle is returned. 12406622cce3Sdanielk1977 */ 12416622cce3Sdanielk1977 static int test_prepare16( 12426622cce3Sdanielk1977 void * clientData, 12436622cce3Sdanielk1977 Tcl_Interp *interp, 12446622cce3Sdanielk1977 int objc, 12456622cce3Sdanielk1977 Tcl_Obj *CONST objv[] 12466622cce3Sdanielk1977 ){ 12476622cce3Sdanielk1977 sqlite3 *db; 12486622cce3Sdanielk1977 const void *zSql; 12496622cce3Sdanielk1977 const void *zTail = 0; 12506622cce3Sdanielk1977 Tcl_Obj *pTail = 0; 12516622cce3Sdanielk1977 sqlite3_stmt *pStmt = 0; 12526622cce3Sdanielk1977 char zBuf[50]; 12536622cce3Sdanielk1977 int bytes; /* The integer specified as arg 3 */ 12546622cce3Sdanielk1977 int objlen; /* The byte-array length of arg 2 */ 12556622cce3Sdanielk1977 12566622cce3Sdanielk1977 if( objc!=5 ){ 12576622cce3Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 12586622cce3Sdanielk1977 Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0); 12596622cce3Sdanielk1977 return TCL_ERROR; 12606622cce3Sdanielk1977 } 12616622cce3Sdanielk1977 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 12626622cce3Sdanielk1977 zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen); 12636622cce3Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR; 12646622cce3Sdanielk1977 12656622cce3Sdanielk1977 if( SQLITE_OK!=sqlite3_prepare16(db, zSql, bytes, &pStmt, &zTail) ){ 12666622cce3Sdanielk1977 return TCL_ERROR; 12676622cce3Sdanielk1977 } 12686622cce3Sdanielk1977 12696622cce3Sdanielk1977 if( zTail ){ 12706622cce3Sdanielk1977 objlen = objlen - ((u8 *)zTail-(u8 *)zSql); 12716622cce3Sdanielk1977 }else{ 12726622cce3Sdanielk1977 objlen = 0; 12736622cce3Sdanielk1977 } 12746622cce3Sdanielk1977 pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen); 12756622cce3Sdanielk1977 Tcl_IncrRefCount(pTail); 12766622cce3Sdanielk1977 Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0); 12774ad1713cSdanielk1977 Tcl_DecrRefCount(pTail); 12786622cce3Sdanielk1977 12794ad1713cSdanielk1977 if( pStmt ){ 12806622cce3Sdanielk1977 if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR; 12814ad1713cSdanielk1977 } 12826622cce3Sdanielk1977 Tcl_AppendResult(interp, zBuf, 0); 12836622cce3Sdanielk1977 return TCL_OK; 12846622cce3Sdanielk1977 } 12856622cce3Sdanielk1977 12864ad1713cSdanielk1977 /* 12874ad1713cSdanielk1977 ** Usage: sqlite3_open filename ?options-list? 12884ad1713cSdanielk1977 */ 12894ad1713cSdanielk1977 static int test_open( 12904ad1713cSdanielk1977 void * clientData, 12914ad1713cSdanielk1977 Tcl_Interp *interp, 12924ad1713cSdanielk1977 int objc, 12934ad1713cSdanielk1977 Tcl_Obj *CONST objv[] 12944ad1713cSdanielk1977 ){ 12954ad1713cSdanielk1977 const char *zFilename; 12964ad1713cSdanielk1977 sqlite3 *db; 12974ad1713cSdanielk1977 int rc; 12984ad1713cSdanielk1977 char zBuf[100]; 12994ad1713cSdanielk1977 13004ad1713cSdanielk1977 if( objc!=3 && objc!=2 ){ 13014ad1713cSdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 13024ad1713cSdanielk1977 Tcl_GetString(objv[0]), " filename options-list", 0); 13034ad1713cSdanielk1977 return TCL_ERROR; 13044ad1713cSdanielk1977 } 13054ad1713cSdanielk1977 13064ad1713cSdanielk1977 zFilename = Tcl_GetString(objv[1]); 130780290863Sdanielk1977 rc = sqlite3_open(zFilename, &db, 0); 13084ad1713cSdanielk1977 13094ad1713cSdanielk1977 if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR; 13104ad1713cSdanielk1977 Tcl_AppendResult(interp, zBuf, 0); 13114ad1713cSdanielk1977 return TCL_OK; 13124ad1713cSdanielk1977 } 13134ad1713cSdanielk1977 13144ad1713cSdanielk1977 /* 13154ad1713cSdanielk1977 ** Usage: sqlite3_open16 filename options 13164ad1713cSdanielk1977 */ 13174ad1713cSdanielk1977 static int test_open16( 13184ad1713cSdanielk1977 void * clientData, 13194ad1713cSdanielk1977 Tcl_Interp *interp, 13204ad1713cSdanielk1977 int objc, 13214ad1713cSdanielk1977 Tcl_Obj *CONST objv[] 13224ad1713cSdanielk1977 ){ 13234ad1713cSdanielk1977 const void *zFilename; 13244ad1713cSdanielk1977 sqlite3 *db; 13254ad1713cSdanielk1977 int rc; 13264ad1713cSdanielk1977 char zBuf[100]; 13274ad1713cSdanielk1977 13284ad1713cSdanielk1977 if( objc!=3 ){ 13294ad1713cSdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 13304ad1713cSdanielk1977 Tcl_GetString(objv[0]), " filename options-list", 0); 13314ad1713cSdanielk1977 return TCL_ERROR; 13324ad1713cSdanielk1977 } 13334ad1713cSdanielk1977 13344ad1713cSdanielk1977 zFilename = Tcl_GetByteArrayFromObj(objv[1], 0); 13354ad1713cSdanielk1977 rc = sqlite3_open16(zFilename, &db, 0); 13364ad1713cSdanielk1977 13374ad1713cSdanielk1977 if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR; 13384ad1713cSdanielk1977 Tcl_AppendResult(interp, zBuf, 0); 13394ad1713cSdanielk1977 return TCL_OK; 13404ad1713cSdanielk1977 } 1341d3d39e93Sdrh 1342d3d39e93Sdrh /* 1343106bb236Sdanielk1977 ** Usage: sqlite3_step STMT 1344106bb236Sdanielk1977 ** 1345106bb236Sdanielk1977 ** Advance the statement to the next row. 1346106bb236Sdanielk1977 */ 134717240fd9Sdanielk1977 static int test_step( 1348106bb236Sdanielk1977 void * clientData, 1349106bb236Sdanielk1977 Tcl_Interp *interp, 1350106bb236Sdanielk1977 int objc, 1351106bb236Sdanielk1977 Tcl_Obj *CONST objv[] 1352106bb236Sdanielk1977 ){ 1353106bb236Sdanielk1977 sqlite3_stmt *pStmt; 1354106bb236Sdanielk1977 int rc; 1355106bb236Sdanielk1977 1356e1cd9874Sdanielk1977 if( objc!=2 ){ 1357106bb236Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 1358106bb236Sdanielk1977 Tcl_GetString(objv[0]), " STMT", 0); 1359106bb236Sdanielk1977 return TCL_ERROR; 1360106bb236Sdanielk1977 } 1361106bb236Sdanielk1977 1362106bb236Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 136317240fd9Sdanielk1977 rc = sqlite3_step(pStmt); 1364106bb236Sdanielk1977 1365e1cd9874Sdanielk1977 if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR; 1366*6590493dSdanielk1977 Tcl_SetResult(interp, (char *)errorName(rc), 0); 1367e1cd9874Sdanielk1977 return TCL_OK; 1368e1cd9874Sdanielk1977 } 1369e1cd9874Sdanielk1977 1370e1cd9874Sdanielk1977 /* 1371e1cd9874Sdanielk1977 ** Usage: sqlite3_column_data STMT column 1372e1cd9874Sdanielk1977 ** 1373e1cd9874Sdanielk1977 ** Advance the statement to the next row. 1374e1cd9874Sdanielk1977 */ 1375e1cd9874Sdanielk1977 static int test_column_data( 1376e1cd9874Sdanielk1977 void * clientData, 1377e1cd9874Sdanielk1977 Tcl_Interp *interp, 1378e1cd9874Sdanielk1977 int objc, 1379e1cd9874Sdanielk1977 Tcl_Obj *CONST objv[] 1380e1cd9874Sdanielk1977 ){ 1381e1cd9874Sdanielk1977 sqlite3_stmt *pStmt; 1382e1cd9874Sdanielk1977 int col; 1383e1cd9874Sdanielk1977 Tcl_Obj *pRet; 1384e1cd9874Sdanielk1977 1385e1cd9874Sdanielk1977 if( objc!=3 ){ 1386e1cd9874Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 1387e1cd9874Sdanielk1977 Tcl_GetString(objv[0]), " STMT column", 0); 1388e1cd9874Sdanielk1977 return TCL_ERROR; 1389e1cd9874Sdanielk1977 } 1390e1cd9874Sdanielk1977 1391e1cd9874Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 1392e1cd9874Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; 1393e1cd9874Sdanielk1977 1394e1cd9874Sdanielk1977 if( SQLITE3_BLOB==sqlite3_column_type(pStmt, col) ){ 1395e1cd9874Sdanielk1977 int len = sqlite3_column_bytes(pStmt, col); 1396e1cd9874Sdanielk1977 pRet = Tcl_NewByteArrayObj(sqlite3_column_data(pStmt, col), len); 1397e1cd9874Sdanielk1977 }else{ 1398e1cd9874Sdanielk1977 pRet = Tcl_NewStringObj(sqlite3_column_data(pStmt, col), -1); 1399e1cd9874Sdanielk1977 } 1400e1cd9874Sdanielk1977 Tcl_SetObjResult(interp, pRet); 1401e1cd9874Sdanielk1977 1402e1cd9874Sdanielk1977 return TCL_OK; 1403e1cd9874Sdanielk1977 } 1404e1cd9874Sdanielk1977 1405e1cd9874Sdanielk1977 /* 1406e1cd9874Sdanielk1977 ** Usage: sqlite3_column_data16 STMT column 1407e1cd9874Sdanielk1977 ** 1408e1cd9874Sdanielk1977 ** Advance the statement to the next row. 1409e1cd9874Sdanielk1977 */ 1410e1cd9874Sdanielk1977 static int test_column_data16( 1411e1cd9874Sdanielk1977 void * clientData, 1412e1cd9874Sdanielk1977 Tcl_Interp *interp, 1413e1cd9874Sdanielk1977 int objc, 1414e1cd9874Sdanielk1977 Tcl_Obj *CONST objv[] 1415e1cd9874Sdanielk1977 ){ 1416e1cd9874Sdanielk1977 sqlite3_stmt *pStmt; 1417e1cd9874Sdanielk1977 int col; 1418e1cd9874Sdanielk1977 Tcl_Obj *pRet; 1419e1cd9874Sdanielk1977 int len; 1420e1cd9874Sdanielk1977 1421e1cd9874Sdanielk1977 if( objc!=3 ){ 1422e1cd9874Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 1423e1cd9874Sdanielk1977 Tcl_GetString(objv[0]), " STMT column", 0); 1424e1cd9874Sdanielk1977 return TCL_ERROR; 1425e1cd9874Sdanielk1977 } 1426e1cd9874Sdanielk1977 1427e1cd9874Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 1428e1cd9874Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; 1429e1cd9874Sdanielk1977 1430e1cd9874Sdanielk1977 len = sqlite3_column_bytes16(pStmt, col); 1431e1cd9874Sdanielk1977 pRet = Tcl_NewByteArrayObj(sqlite3_column_data16(pStmt, col), len); 1432e1cd9874Sdanielk1977 Tcl_SetObjResult(interp, pRet); 1433e1cd9874Sdanielk1977 1434106bb236Sdanielk1977 return TCL_OK; 1435106bb236Sdanielk1977 } 1436106bb236Sdanielk1977 1437106bb236Sdanielk1977 /* 143817240fd9Sdanielk1977 ** Usage: sqlite3_column_count STMT 143917240fd9Sdanielk1977 ** 144017240fd9Sdanielk1977 ** Return the number of columns returned by the sql statement STMT. 144117240fd9Sdanielk1977 */ 144217240fd9Sdanielk1977 static int test_column_count( 144317240fd9Sdanielk1977 void * clientData, 144417240fd9Sdanielk1977 Tcl_Interp *interp, 144517240fd9Sdanielk1977 int objc, 144617240fd9Sdanielk1977 Tcl_Obj *CONST objv[] 144717240fd9Sdanielk1977 ){ 144817240fd9Sdanielk1977 sqlite3_stmt *pStmt; 144917240fd9Sdanielk1977 145017240fd9Sdanielk1977 if( objc!=2 ){ 145117240fd9Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 145217240fd9Sdanielk1977 Tcl_GetString(objv[0]), " STMT column", 0); 145317240fd9Sdanielk1977 return TCL_ERROR; 145417240fd9Sdanielk1977 } 145517240fd9Sdanielk1977 145617240fd9Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 145717240fd9Sdanielk1977 145817240fd9Sdanielk1977 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_column_count(pStmt))); 145917240fd9Sdanielk1977 return TCL_OK; 146017240fd9Sdanielk1977 } 146117240fd9Sdanielk1977 146217240fd9Sdanielk1977 /* 146317240fd9Sdanielk1977 ** Usage: sqlite3_data_count STMT 146417240fd9Sdanielk1977 ** 146517240fd9Sdanielk1977 ** Return the number of columns returned by the sql statement STMT. 146617240fd9Sdanielk1977 */ 146717240fd9Sdanielk1977 static int test_data_count( 146817240fd9Sdanielk1977 void * clientData, 146917240fd9Sdanielk1977 Tcl_Interp *interp, 147017240fd9Sdanielk1977 int objc, 147117240fd9Sdanielk1977 Tcl_Obj *CONST objv[] 147217240fd9Sdanielk1977 ){ 147317240fd9Sdanielk1977 sqlite3_stmt *pStmt; 147417240fd9Sdanielk1977 147517240fd9Sdanielk1977 if( objc!=2 ){ 147617240fd9Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 147717240fd9Sdanielk1977 Tcl_GetString(objv[0]), " STMT column", 0); 147817240fd9Sdanielk1977 return TCL_ERROR; 147917240fd9Sdanielk1977 } 148017240fd9Sdanielk1977 148117240fd9Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 148217240fd9Sdanielk1977 148317240fd9Sdanielk1977 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_data_count(pStmt))); 148417240fd9Sdanielk1977 return TCL_OK; 148517240fd9Sdanielk1977 } 148617240fd9Sdanielk1977 148717240fd9Sdanielk1977 /* 1488d3d39e93Sdrh ** This is a collating function named "REVERSE" which sorts text 1489d3d39e93Sdrh ** in reverse order. 1490d3d39e93Sdrh */ 1491d3d39e93Sdrh static int reverseCollatingFunc( 1492d3d39e93Sdrh void *NotUsed, 1493d3d39e93Sdrh int nKey1, const void *pKey1, 1494d3d39e93Sdrh int nKey2, const void *pKey2 1495d3d39e93Sdrh ){ 1496d3d39e93Sdrh int rc, n; 1497d3d39e93Sdrh n = nKey1<nKey2 ? nKey1 : nKey2; 1498d3d39e93Sdrh rc = memcmp(pKey1, pKey2, n); 1499d3d39e93Sdrh if( rc==0 ){ 1500d3d39e93Sdrh rc = nKey1 - nKey2; 1501d3d39e93Sdrh } 1502d3d39e93Sdrh return -rc; 1503d3d39e93Sdrh } 1504d3d39e93Sdrh 1505d3d39e93Sdrh /* 1506d3d39e93Sdrh ** Usage: add_reverse_collating_func DB 1507d3d39e93Sdrh ** 1508d3d39e93Sdrh ** This routine adds a collation named "REVERSE" to database given. 1509d3d39e93Sdrh ** REVERSE is used for testing only. 1510d3d39e93Sdrh */ 1511d3d39e93Sdrh static int reverse_collfunc( 1512d3d39e93Sdrh void * clientData, 1513d3d39e93Sdrh Tcl_Interp *interp, 1514d3d39e93Sdrh int objc, 1515d3d39e93Sdrh Tcl_Obj *CONST objv[] 1516d3d39e93Sdrh ){ 1517d3d39e93Sdrh sqlite3 *db; 1518d3d39e93Sdrh 1519d3d39e93Sdrh if( objc!=2 ){ 1520d3d39e93Sdrh Tcl_WrongNumArgs(interp, 1, objv, "DB"); 1521d3d39e93Sdrh return TCL_ERROR; 1522d3d39e93Sdrh } 1523d3d39e93Sdrh if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 1524d3d39e93Sdrh sqlite3ChangeCollatingFunction(db, "REVERSE", 7, 0, reverseCollatingFunc); 1525d3d39e93Sdrh return TCL_OK; 1526d3d39e93Sdrh } 1527d3d39e93Sdrh 1528d3d39e93Sdrh 15296622cce3Sdanielk1977 /* 1530d1bf3512Sdrh ** Register commands with the TCL interpreter. 1531d1bf3512Sdrh */ 1532d1bf3512Sdrh int Sqlitetest1_Init(Tcl_Interp *interp){ 15336f8a503dSdanielk1977 extern int sqlite3_search_count; 15346f8a503dSdanielk1977 extern int sqlite3_interrupt_count; 15356f8a503dSdanielk1977 extern int sqlite3_open_file_count; 15366f8a503dSdanielk1977 extern int sqlite3_current_time; 1537c2eef3b3Sdrh static struct { 1538c2eef3b3Sdrh char *zName; 1539c2eef3b3Sdrh Tcl_CmdProc *xProc; 1540c2eef3b3Sdrh } aCmd[] = { 15416f8a503dSdanielk1977 { "sqlite3_mprintf_int", (Tcl_CmdProc*)sqlite3_mprintf_int }, 15426f8a503dSdanielk1977 { "sqlite3_mprintf_str", (Tcl_CmdProc*)sqlite3_mprintf_str }, 15436f8a503dSdanielk1977 { "sqlite3_mprintf_double", (Tcl_CmdProc*)sqlite3_mprintf_double }, 15446f8a503dSdanielk1977 { "sqlite3_mprintf_scaled", (Tcl_CmdProc*)sqlite3_mprintf_scaled }, 15456f8a503dSdanielk1977 { "sqlite3_mprintf_z_test", (Tcl_CmdProc*)test_mprintf_z }, 15466f8a503dSdanielk1977 { "sqlite3_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid }, 15476f8a503dSdanielk1977 { "sqlite3_exec_printf", (Tcl_CmdProc*)test_exec_printf }, 15486f8a503dSdanielk1977 { "sqlite3_get_table_printf", (Tcl_CmdProc*)test_get_table_printf }, 15496f8a503dSdanielk1977 { "sqlite3_close", (Tcl_CmdProc*)sqlite_test_close }, 15506f8a503dSdanielk1977 { "sqlite3_create_function", (Tcl_CmdProc*)test_create_function }, 15516f8a503dSdanielk1977 { "sqlite3_create_aggregate", (Tcl_CmdProc*)test_create_aggregate }, 1552c2eef3b3Sdrh { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func }, 1553c2eef3b3Sdrh { "sqlite_abort", (Tcl_CmdProc*)sqlite_abort }, 15545a38705eSdrh { "sqlite_datatypes", (Tcl_CmdProc*)sqlite_datatypes }, 1555c2eef3b3Sdrh #ifdef MEMORY_DEBUG 1556c2eef3b3Sdrh { "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail }, 1557c2eef3b3Sdrh { "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat }, 1558c2eef3b3Sdrh #endif 155996fc5fe6Sdanielk1977 { "sqlite_bind", (Tcl_CmdProc*)test_bind }, 156099ee3600Sdrh { "breakpoint", (Tcl_CmdProc*)test_breakpoint }, 1561c2eef3b3Sdrh }; 156251e3d8e2Sdanielk1977 static struct { 156351e3d8e2Sdanielk1977 char *zName; 156451e3d8e2Sdanielk1977 Tcl_ObjCmdProc *xProc; 156551e3d8e2Sdanielk1977 } aObjCmd[] = { 156651e3d8e2Sdanielk1977 { "sqlite3_bind_int32", (Tcl_ObjCmdProc*)test_bind_int32 }, 156751e3d8e2Sdanielk1977 { "sqlite3_bind_int64", (Tcl_ObjCmdProc*)test_bind_int64 }, 156851e3d8e2Sdanielk1977 { "sqlite3_bind_double", (Tcl_ObjCmdProc*)test_bind_double }, 156951e3d8e2Sdanielk1977 { "sqlite3_bind_null", (Tcl_ObjCmdProc*)test_bind_null }, 157051e3d8e2Sdanielk1977 { "sqlite3_bind_text", (Tcl_ObjCmdProc*)test_bind_text }, 157151e3d8e2Sdanielk1977 { "sqlite3_bind_text16", (Tcl_ObjCmdProc*)test_bind_text16 }, 157251e3d8e2Sdanielk1977 { "sqlite3_bind_blob", (Tcl_ObjCmdProc*)test_bind_blob }, 15736622cce3Sdanielk1977 { "sqlite3_errcode", (Tcl_ObjCmdProc*)test_errcode }, 15746622cce3Sdanielk1977 { "sqlite3_errmsg", (Tcl_ObjCmdProc*)test_errmsg }, 15756622cce3Sdanielk1977 { "sqlite3_errmsg16", (Tcl_ObjCmdProc*)test_errmsg16 }, 15766622cce3Sdanielk1977 { "sqlite3_prepare", (Tcl_ObjCmdProc*)test_prepare }, 15776622cce3Sdanielk1977 { "sqlite3_prepare16", (Tcl_ObjCmdProc*)test_prepare16 }, 15784ad1713cSdanielk1977 { "sqlite3_open", (Tcl_ObjCmdProc*)test_open }, 15794ad1713cSdanielk1977 { "sqlite3_open16", (Tcl_ObjCmdProc*)test_open16 }, 1580106bb236Sdanielk1977 { "sqlite3_finalize", (Tcl_ObjCmdProc*)test_finalize }, 1581106bb236Sdanielk1977 { "sqlite3_reset", (Tcl_ObjCmdProc*)test_reset }, 158217240fd9Sdanielk1977 { "sqlite3_step", (Tcl_ObjCmdProc*)test_step}, 1583e1cd9874Sdanielk1977 { "sqlite3_column_data", (Tcl_ObjCmdProc*)test_column_data }, 1584e1cd9874Sdanielk1977 { "sqlite3_column_data16", (Tcl_ObjCmdProc*)test_column_data16 }, 158517240fd9Sdanielk1977 { "sqlite3_column_count", (Tcl_ObjCmdProc*)test_column_count }, 158617240fd9Sdanielk1977 { "sqlite3_data_count", (Tcl_ObjCmdProc*)test_data_count }, 1587d3d39e93Sdrh { "add_reverse_collating_func", (Tcl_ObjCmdProc*)reverse_collfunc }, 158851e3d8e2Sdanielk1977 }; 1589c2eef3b3Sdrh int i; 1590c2eef3b3Sdrh 1591c2eef3b3Sdrh for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ 1592c2eef3b3Sdrh Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); 1593c2eef3b3Sdrh } 159451e3d8e2Sdanielk1977 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ 159551e3d8e2Sdanielk1977 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); 159651e3d8e2Sdanielk1977 } 15976490bebdSdanielk1977 Tcl_LinkVar(interp, "sqlite_search_count", 15986f8a503dSdanielk1977 (char*)&sqlite3_search_count, TCL_LINK_INT); 15996490bebdSdanielk1977 Tcl_LinkVar(interp, "sqlite_interrupt_count", 16006f8a503dSdanielk1977 (char*)&sqlite3_interrupt_count, TCL_LINK_INT); 16016490bebdSdanielk1977 Tcl_LinkVar(interp, "sqlite_open_file_count", 16026f8a503dSdanielk1977 (char*)&sqlite3_open_file_count, TCL_LINK_INT); 16036490bebdSdanielk1977 Tcl_LinkVar(interp, "sqlite_current_time", 16046f8a503dSdanielk1977 (char*)&sqlite3_current_time, TCL_LINK_INT); 16057c972decSdrh Tcl_LinkVar(interp, "sqlite_static_bind_value", 16067c972decSdrh (char*)&sqlite_static_bind_value, TCL_LINK_STRING); 1607d1bf3512Sdrh return TCL_OK; 1608d1bf3512Sdrh } 1609