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*b77f5dadSdanielk1977 ** $Id: test1.c,v 1.58 2004/05/26 13:27:00 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; 4116590493dSdanielk1977 sqlite3_create_function(db, "x_coalesce", -1, 0, 0, 0, ifnullFunc, 0, 0); 4126590493dSdanielk1977 sqlite3_create_function(db, "x_sqlite3_exec", 1, 0, 0, db, 4136590493dSdanielk1977 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; 4616590493dSdanielk1977 sqlite3_create_function(db, "x_count", 0, 0, 0, 0, 0,countStep,countFinalize); 4626590493dSdanielk1977 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; 6906590493dSdanielk1977 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 /* 699106bb236Sdanielk1977 ** Usage: sqlite3_finalize STMT 700b86ccfb2Sdrh ** 701106bb236Sdanielk1977 ** Finalize a statement handle. 702b86ccfb2Sdrh */ 703b86ccfb2Sdrh static int test_finalize( 704106bb236Sdanielk1977 void * clientData, 705106bb236Sdanielk1977 Tcl_Interp *interp, 706106bb236Sdanielk1977 int objc, 707106bb236Sdanielk1977 Tcl_Obj *CONST objv[] 708b86ccfb2Sdrh ){ 709106bb236Sdanielk1977 sqlite3_stmt *pStmt; 710b86ccfb2Sdrh int rc; 711106bb236Sdanielk1977 712106bb236Sdanielk1977 if( objc!=2 ){ 713106bb236Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 714106bb236Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0); 715b86ccfb2Sdrh return TCL_ERROR; 716b86ccfb2Sdrh } 717106bb236Sdanielk1977 718106bb236Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 719106bb236Sdanielk1977 720fc57d7bfSdanielk1977 rc = sqlite3_finalize(pStmt); 721*b77f5dadSdanielk1977 Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC); 722b86ccfb2Sdrh if( rc ){ 723106bb236Sdanielk1977 return TCL_ERROR; 724106bb236Sdanielk1977 } 725106bb236Sdanielk1977 return TCL_OK; 726106bb236Sdanielk1977 } 727106bb236Sdanielk1977 728106bb236Sdanielk1977 /* 729106bb236Sdanielk1977 ** Usage: sqlite3_reset STMT 730106bb236Sdanielk1977 ** 731106bb236Sdanielk1977 ** Finalize a statement handle. 732106bb236Sdanielk1977 */ 733106bb236Sdanielk1977 static int test_reset( 734106bb236Sdanielk1977 void * clientData, 735106bb236Sdanielk1977 Tcl_Interp *interp, 736106bb236Sdanielk1977 int objc, 737106bb236Sdanielk1977 Tcl_Obj *CONST objv[] 738106bb236Sdanielk1977 ){ 739106bb236Sdanielk1977 sqlite3_stmt *pStmt; 740106bb236Sdanielk1977 int rc; 741106bb236Sdanielk1977 742106bb236Sdanielk1977 if( objc!=2 ){ 743106bb236Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 744106bb236Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0); 745106bb236Sdanielk1977 return TCL_ERROR; 746106bb236Sdanielk1977 } 747106bb236Sdanielk1977 748106bb236Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 749106bb236Sdanielk1977 750fc57d7bfSdanielk1977 rc = sqlite3_reset(pStmt); 751106bb236Sdanielk1977 if( rc ){ 752b86ccfb2Sdrh return TCL_ERROR; 753b86ccfb2Sdrh } 754b86ccfb2Sdrh return TCL_OK; 755b86ccfb2Sdrh } 756b86ccfb2Sdrh 7575a38705eSdrh /* 7586f8a503dSdanielk1977 ** Usage: sqlite3_reset VM 75950457896Sdrh ** 76050457896Sdrh ** Reset a virtual machine and prepare it to be run again. 76150457896Sdrh */ 76250457896Sdrh 76350457896Sdrh /* 7647c972decSdrh ** This is the "static_bind_value" that variables are bound to when 7656f8a503dSdanielk1977 ** the FLAG option of sqlite3_bind is "static" 76650457896Sdrh */ 7677c972decSdrh static char *sqlite_static_bind_value = 0; 7687c972decSdrh 7697c972decSdrh /* 7706f8a503dSdanielk1977 ** Usage: sqlite3_bind VM IDX VALUE FLAGS 7717c972decSdrh ** 7727c972decSdrh ** Sets the value of the IDX-th occurance of "?" in the original SQL 7737c972decSdrh ** string. VALUE is the new value. If FLAGS=="null" then VALUE is 7747c972decSdrh ** ignored and the value is set to NULL. If FLAGS=="static" then 7757c972decSdrh ** the value is set to the value of a static variable named 7767c972decSdrh ** "sqlite_static_bind_value". If FLAGS=="normal" then a copy 7777c972decSdrh ** of the VALUE is made. 7787c972decSdrh */ 7797c972decSdrh static int test_bind( 78050457896Sdrh void *NotUsed, 78150457896Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 78250457896Sdrh int argc, /* Number of arguments */ 78350457896Sdrh char **argv /* Text of each argument */ 78450457896Sdrh ){ 785fc57d7bfSdanielk1977 sqlite3_stmt *pStmt; 78650457896Sdrh int rc; 7877c972decSdrh int idx; 7887c972decSdrh if( argc!=5 ){ 78950457896Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 7907c972decSdrh " VM IDX VALUE (null|static|normal)\"", 0); 79150457896Sdrh return TCL_ERROR; 79250457896Sdrh } 793fc57d7bfSdanielk1977 if( getStmtPointer(interp, argv[1], &pStmt) ) return TCL_ERROR; 7947c972decSdrh if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR; 7957c972decSdrh if( strcmp(argv[4],"null")==0 ){ 796fc57d7bfSdanielk1977 rc = sqlite3_bind_null(pStmt, idx); 7977c972decSdrh }else if( strcmp(argv[4],"static")==0 ){ 798fc57d7bfSdanielk1977 rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0); 7997c972decSdrh }else if( strcmp(argv[4],"normal")==0 ){ 800fc57d7bfSdanielk1977 rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, 1); 8017c972decSdrh }else{ 8027c972decSdrh Tcl_AppendResult(interp, "4th argument should be " 8037c972decSdrh "\"null\" or \"static\" or \"normal\"", 0); 8047c972decSdrh return TCL_ERROR; 8057c972decSdrh } 80650457896Sdrh if( rc ){ 80750457896Sdrh char zBuf[50]; 80850457896Sdrh sprintf(zBuf, "(%d) ", rc); 8096f8a503dSdanielk1977 Tcl_AppendResult(interp, zBuf, sqlite3_error_string(rc), 0); 81050457896Sdrh return TCL_ERROR; 81150457896Sdrh } 81250457896Sdrh return TCL_OK; 81350457896Sdrh } 81450457896Sdrh 81550457896Sdrh /* 81699ee3600Sdrh ** Usage: breakpoint 81799ee3600Sdrh ** 81899ee3600Sdrh ** This routine exists for one purpose - to provide a place to put a 81999ee3600Sdrh ** breakpoint with GDB that can be triggered using TCL code. The use 82099ee3600Sdrh ** for this is when a particular test fails on (say) the 1485th iteration. 82199ee3600Sdrh ** In the TCL test script, we can add code like this: 82299ee3600Sdrh ** 82399ee3600Sdrh ** if {$i==1485} breakpoint 82499ee3600Sdrh ** 82599ee3600Sdrh ** Then run testfixture in the debugger and wait for the breakpoint to 82699ee3600Sdrh ** fire. Then additional breakpoints can be set to trace down the bug. 82799ee3600Sdrh */ 82899ee3600Sdrh static int test_breakpoint( 82999ee3600Sdrh void *NotUsed, 83099ee3600Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 83199ee3600Sdrh int argc, /* Number of arguments */ 83299ee3600Sdrh char **argv /* Text of each argument */ 83399ee3600Sdrh ){ 83499ee3600Sdrh return TCL_OK; /* Do nothing */ 83599ee3600Sdrh } 83699ee3600Sdrh 83751e3d8e2Sdanielk1977 static int test_bind_int32( 83851e3d8e2Sdanielk1977 void * clientData, 83951e3d8e2Sdanielk1977 Tcl_Interp *interp, 84051e3d8e2Sdanielk1977 int objc, 84151e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 84251e3d8e2Sdanielk1977 ){ 84351e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 84451e3d8e2Sdanielk1977 int idx; 84551e3d8e2Sdanielk1977 int value; 84651e3d8e2Sdanielk1977 int rc; 84751e3d8e2Sdanielk1977 84851e3d8e2Sdanielk1977 if( objc!=4 ){ 84951e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 85051e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0); 85151e3d8e2Sdanielk1977 return TCL_ERROR; 85251e3d8e2Sdanielk1977 } 85351e3d8e2Sdanielk1977 85451e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 85551e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 85651e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[3], &value) ) return TCL_ERROR; 85751e3d8e2Sdanielk1977 85851e3d8e2Sdanielk1977 rc = sqlite3_bind_int32(pStmt, idx, value); 85951e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 86051e3d8e2Sdanielk1977 return TCL_ERROR; 86151e3d8e2Sdanielk1977 } 86251e3d8e2Sdanielk1977 86351e3d8e2Sdanielk1977 return TCL_OK; 86451e3d8e2Sdanielk1977 } 86551e3d8e2Sdanielk1977 86651e3d8e2Sdanielk1977 static int test_bind_int64( 86751e3d8e2Sdanielk1977 void * clientData, 86851e3d8e2Sdanielk1977 Tcl_Interp *interp, 86951e3d8e2Sdanielk1977 int objc, 87051e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 87151e3d8e2Sdanielk1977 ){ 87251e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 87351e3d8e2Sdanielk1977 int idx; 87451e3d8e2Sdanielk1977 i64 value; 87551e3d8e2Sdanielk1977 int rc; 87651e3d8e2Sdanielk1977 87751e3d8e2Sdanielk1977 if( objc!=4 ){ 87851e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 87951e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0); 88051e3d8e2Sdanielk1977 return TCL_ERROR; 88151e3d8e2Sdanielk1977 } 88251e3d8e2Sdanielk1977 88351e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 88451e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 88551e3d8e2Sdanielk1977 if( Tcl_GetWideIntFromObj(interp, objv[3], &value) ) return TCL_ERROR; 88651e3d8e2Sdanielk1977 88751e3d8e2Sdanielk1977 rc = sqlite3_bind_int64(pStmt, idx, value); 88851e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 88951e3d8e2Sdanielk1977 return TCL_ERROR; 89051e3d8e2Sdanielk1977 } 89151e3d8e2Sdanielk1977 89251e3d8e2Sdanielk1977 return TCL_OK; 89351e3d8e2Sdanielk1977 } 89451e3d8e2Sdanielk1977 89551e3d8e2Sdanielk1977 static int test_bind_double( 89651e3d8e2Sdanielk1977 void * clientData, 89751e3d8e2Sdanielk1977 Tcl_Interp *interp, 89851e3d8e2Sdanielk1977 int objc, 89951e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 90051e3d8e2Sdanielk1977 ){ 90151e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 90251e3d8e2Sdanielk1977 int idx; 90351e3d8e2Sdanielk1977 double value; 90451e3d8e2Sdanielk1977 int rc; 90551e3d8e2Sdanielk1977 90651e3d8e2Sdanielk1977 if( objc!=4 ){ 90751e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 90851e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0); 90951e3d8e2Sdanielk1977 return TCL_ERROR; 91051e3d8e2Sdanielk1977 } 91151e3d8e2Sdanielk1977 91251e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 91351e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 91451e3d8e2Sdanielk1977 if( Tcl_GetDoubleFromObj(interp, objv[3], &value) ) return TCL_ERROR; 91551e3d8e2Sdanielk1977 91651e3d8e2Sdanielk1977 rc = sqlite3_bind_double(pStmt, idx, value); 91751e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 91851e3d8e2Sdanielk1977 return TCL_ERROR; 91951e3d8e2Sdanielk1977 } 92051e3d8e2Sdanielk1977 92151e3d8e2Sdanielk1977 return TCL_OK; 92251e3d8e2Sdanielk1977 } 92351e3d8e2Sdanielk1977 92451e3d8e2Sdanielk1977 static int test_bind_null( 92551e3d8e2Sdanielk1977 void * clientData, 92651e3d8e2Sdanielk1977 Tcl_Interp *interp, 92751e3d8e2Sdanielk1977 int objc, 92851e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 92951e3d8e2Sdanielk1977 ){ 93051e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 93151e3d8e2Sdanielk1977 int idx; 93251e3d8e2Sdanielk1977 int rc; 93351e3d8e2Sdanielk1977 93451e3d8e2Sdanielk1977 if( objc!=3 ){ 93551e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 93651e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.>", 0); 93751e3d8e2Sdanielk1977 return TCL_ERROR; 93851e3d8e2Sdanielk1977 } 93951e3d8e2Sdanielk1977 94051e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 94151e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 94251e3d8e2Sdanielk1977 94351e3d8e2Sdanielk1977 rc = sqlite3_bind_null(pStmt, idx); 94451e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 94551e3d8e2Sdanielk1977 return TCL_ERROR; 94651e3d8e2Sdanielk1977 } 94751e3d8e2Sdanielk1977 94851e3d8e2Sdanielk1977 return TCL_OK; 94951e3d8e2Sdanielk1977 } 95051e3d8e2Sdanielk1977 95151e3d8e2Sdanielk1977 static int test_bind_text( 95251e3d8e2Sdanielk1977 void * clientData, 95351e3d8e2Sdanielk1977 Tcl_Interp *interp, 95451e3d8e2Sdanielk1977 int objc, 95551e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 95651e3d8e2Sdanielk1977 ){ 95751e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 95851e3d8e2Sdanielk1977 int idx; 95951e3d8e2Sdanielk1977 int bytes; 96051e3d8e2Sdanielk1977 char *value; 96151e3d8e2Sdanielk1977 int rc; 96251e3d8e2Sdanielk1977 96351e3d8e2Sdanielk1977 if( objc!=5 ){ 96451e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 96551e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>" 96651e3d8e2Sdanielk1977 " <bytes>", 0); 96751e3d8e2Sdanielk1977 return TCL_ERROR; 96851e3d8e2Sdanielk1977 } 96951e3d8e2Sdanielk1977 97051e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 97151e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 97251e3d8e2Sdanielk1977 value = Tcl_GetString(objv[3]); 97351e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; 97451e3d8e2Sdanielk1977 97551e3d8e2Sdanielk1977 rc = sqlite3_bind_text(pStmt, idx, value, bytes, 1); 97651e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 97751e3d8e2Sdanielk1977 return TCL_ERROR; 97851e3d8e2Sdanielk1977 } 97951e3d8e2Sdanielk1977 98051e3d8e2Sdanielk1977 return TCL_OK; 98151e3d8e2Sdanielk1977 } 98251e3d8e2Sdanielk1977 98351e3d8e2Sdanielk1977 static int test_bind_text16( 98451e3d8e2Sdanielk1977 void * clientData, 98551e3d8e2Sdanielk1977 Tcl_Interp *interp, 98651e3d8e2Sdanielk1977 int objc, 98751e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 98851e3d8e2Sdanielk1977 ){ 98951e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 99051e3d8e2Sdanielk1977 int idx; 99151e3d8e2Sdanielk1977 int bytes; 99251e3d8e2Sdanielk1977 char *value; 99351e3d8e2Sdanielk1977 int rc; 99451e3d8e2Sdanielk1977 99551e3d8e2Sdanielk1977 if( objc!=5 ){ 99651e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 99751e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>" 99851e3d8e2Sdanielk1977 " <bytes>", 0); 99951e3d8e2Sdanielk1977 return TCL_ERROR; 100051e3d8e2Sdanielk1977 } 100151e3d8e2Sdanielk1977 100251e3d8e2Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 100351e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; 100451e3d8e2Sdanielk1977 value = Tcl_GetByteArrayFromObj(objv[3], 0); 100551e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR; 100651e3d8e2Sdanielk1977 100751e3d8e2Sdanielk1977 rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, 1); 100851e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 100951e3d8e2Sdanielk1977 return TCL_ERROR; 101051e3d8e2Sdanielk1977 } 101151e3d8e2Sdanielk1977 101251e3d8e2Sdanielk1977 return TCL_OK; 101351e3d8e2Sdanielk1977 } 101451e3d8e2Sdanielk1977 101551e3d8e2Sdanielk1977 static int test_bind_blob( 101651e3d8e2Sdanielk1977 void * clientData, 101751e3d8e2Sdanielk1977 Tcl_Interp *interp, 101851e3d8e2Sdanielk1977 int objc, 101951e3d8e2Sdanielk1977 Tcl_Obj *CONST objv[] 102051e3d8e2Sdanielk1977 ){ 102151e3d8e2Sdanielk1977 sqlite3_stmt *pStmt; 102251e3d8e2Sdanielk1977 int idx; 102351e3d8e2Sdanielk1977 int bytes; 102451e3d8e2Sdanielk1977 char *value; 102551e3d8e2Sdanielk1977 int rc; 102651e3d8e2Sdanielk1977 102751e3d8e2Sdanielk1977 if( objc!=5 ){ 102851e3d8e2Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 102951e3d8e2Sdanielk1977 Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>" 103051e3d8e2Sdanielk1977 " <bytes>", 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 value = Tcl_GetString(objv[3]); 103751e3d8e2Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &bytes) ) return TCL_ERROR; 103851e3d8e2Sdanielk1977 103951e3d8e2Sdanielk1977 rc = sqlite3_bind_blob(pStmt, idx, value, bytes, 1); 104051e3d8e2Sdanielk1977 if( rc!=SQLITE_OK ){ 104151e3d8e2Sdanielk1977 return TCL_ERROR; 104251e3d8e2Sdanielk1977 } 104351e3d8e2Sdanielk1977 104451e3d8e2Sdanielk1977 return TCL_OK; 104551e3d8e2Sdanielk1977 } 104651e3d8e2Sdanielk1977 104799ee3600Sdrh /* 10486622cce3Sdanielk1977 ** Usage: sqlite3_errcode DB 10496622cce3Sdanielk1977 ** 10506622cce3Sdanielk1977 ** Return the string representation of the most recent sqlite3_* API 10516622cce3Sdanielk1977 ** error code. e.g. "SQLITE_ERROR". 10526622cce3Sdanielk1977 */ 10536622cce3Sdanielk1977 static int test_errcode( 10546622cce3Sdanielk1977 void * clientData, 10556622cce3Sdanielk1977 Tcl_Interp *interp, 10566622cce3Sdanielk1977 int objc, 10576622cce3Sdanielk1977 Tcl_Obj *CONST objv[] 10586622cce3Sdanielk1977 ){ 10596622cce3Sdanielk1977 sqlite3 *db; 10606622cce3Sdanielk1977 10616622cce3Sdanielk1977 if( objc!=2 ){ 10626622cce3Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 10636622cce3Sdanielk1977 Tcl_GetString(objv[0]), " DB", 0); 10646622cce3Sdanielk1977 return TCL_ERROR; 10656622cce3Sdanielk1977 } 10666622cce3Sdanielk1977 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 10676622cce3Sdanielk1977 Tcl_SetResult(interp, (char *)errorName(sqlite3_errcode(db)), 0); 10686622cce3Sdanielk1977 return TCL_OK; 10696622cce3Sdanielk1977 } 10706622cce3Sdanielk1977 10716622cce3Sdanielk1977 /* 10726622cce3Sdanielk1977 ** Usage: test_errmsg DB 10736622cce3Sdanielk1977 ** 10746622cce3Sdanielk1977 ** Returns the UTF-8 representation of the error message string for the 10756622cce3Sdanielk1977 ** most recent sqlite3_* API call. 10766622cce3Sdanielk1977 */ 10776622cce3Sdanielk1977 static int test_errmsg( 10786622cce3Sdanielk1977 void * clientData, 10796622cce3Sdanielk1977 Tcl_Interp *interp, 10806622cce3Sdanielk1977 int objc, 10816622cce3Sdanielk1977 Tcl_Obj *CONST objv[] 10826622cce3Sdanielk1977 ){ 10836622cce3Sdanielk1977 sqlite *db; 10846622cce3Sdanielk1977 const char *zErr; 10856622cce3Sdanielk1977 10866622cce3Sdanielk1977 if( objc!=2 ){ 10876622cce3Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 10886622cce3Sdanielk1977 Tcl_GetString(objv[0]), " DB", 0); 10896622cce3Sdanielk1977 return TCL_ERROR; 10906622cce3Sdanielk1977 } 10916622cce3Sdanielk1977 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 10926622cce3Sdanielk1977 10936622cce3Sdanielk1977 zErr = sqlite3_errmsg(db); 10946622cce3Sdanielk1977 Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1)); 10956622cce3Sdanielk1977 return TCL_OK; 10966622cce3Sdanielk1977 } 10976622cce3Sdanielk1977 10986622cce3Sdanielk1977 /* 10996622cce3Sdanielk1977 ** Usage: test_errmsg16 DB 11006622cce3Sdanielk1977 ** 11016622cce3Sdanielk1977 ** Returns the UTF-16 representation of the error message string for the 11026622cce3Sdanielk1977 ** most recent sqlite3_* API call. This is a byte array object at the TCL 11036622cce3Sdanielk1977 ** level, and it includes the 0x00 0x00 terminator bytes at the end of the 11046622cce3Sdanielk1977 ** UTF-16 string. 11056622cce3Sdanielk1977 */ 11066622cce3Sdanielk1977 static int test_errmsg16( 11076622cce3Sdanielk1977 void * clientData, 11086622cce3Sdanielk1977 Tcl_Interp *interp, 11096622cce3Sdanielk1977 int objc, 11106622cce3Sdanielk1977 Tcl_Obj *CONST objv[] 11116622cce3Sdanielk1977 ){ 11126622cce3Sdanielk1977 sqlite *db; 11136622cce3Sdanielk1977 const void *zErr; 11146622cce3Sdanielk1977 int bytes; 11156622cce3Sdanielk1977 11166622cce3Sdanielk1977 if( objc!=2 ){ 11176622cce3Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 11186622cce3Sdanielk1977 Tcl_GetString(objv[0]), " DB", 0); 11196622cce3Sdanielk1977 return TCL_ERROR; 11206622cce3Sdanielk1977 } 11216622cce3Sdanielk1977 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 11226622cce3Sdanielk1977 11236622cce3Sdanielk1977 zErr = sqlite3_errmsg16(db); 11246622cce3Sdanielk1977 bytes = sqlite3utf16ByteLen(zErr, -1); 11256622cce3Sdanielk1977 Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes)); 11266622cce3Sdanielk1977 return TCL_OK; 11276622cce3Sdanielk1977 } 11286622cce3Sdanielk1977 11296622cce3Sdanielk1977 /* 11306622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar 11316622cce3Sdanielk1977 ** 11326622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using 11336622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global 11346622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A 11356622cce3Sdanielk1977 ** STMT handle is returned. 11366622cce3Sdanielk1977 */ 11376622cce3Sdanielk1977 static int test_prepare( 11386622cce3Sdanielk1977 void * clientData, 11396622cce3Sdanielk1977 Tcl_Interp *interp, 11406622cce3Sdanielk1977 int objc, 11416622cce3Sdanielk1977 Tcl_Obj *CONST objv[] 11426622cce3Sdanielk1977 ){ 11436622cce3Sdanielk1977 sqlite3 *db; 11446622cce3Sdanielk1977 const char *zSql; 11456622cce3Sdanielk1977 int bytes; 11466622cce3Sdanielk1977 const char *zTail = 0; 11476622cce3Sdanielk1977 sqlite3_stmt *pStmt = 0; 11486622cce3Sdanielk1977 char zBuf[50]; 11494ad1713cSdanielk1977 int rc; 11506622cce3Sdanielk1977 11516622cce3Sdanielk1977 if( objc!=5 ){ 11526622cce3Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 11536622cce3Sdanielk1977 Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0); 11546622cce3Sdanielk1977 return TCL_ERROR; 11556622cce3Sdanielk1977 } 11566622cce3Sdanielk1977 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 11576622cce3Sdanielk1977 zSql = Tcl_GetString(objv[2]); 11586622cce3Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR; 11596622cce3Sdanielk1977 11604ad1713cSdanielk1977 rc = sqlite3_prepare(db, zSql, bytes, &pStmt, &zTail); 11616622cce3Sdanielk1977 if( zTail ){ 11626622cce3Sdanielk1977 if( bytes>=0 ){ 11636622cce3Sdanielk1977 bytes = bytes - (zTail-zSql); 11646622cce3Sdanielk1977 } 11656622cce3Sdanielk1977 Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0); 11666622cce3Sdanielk1977 } 11674ad1713cSdanielk1977 if( rc!=SQLITE_OK ){ 11684ad1713cSdanielk1977 assert( pStmt==0 ); 11694ad1713cSdanielk1977 sprintf(zBuf, "(%d) ", rc); 11704ad1713cSdanielk1977 Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0); 11714ad1713cSdanielk1977 return TCL_ERROR; 11724ad1713cSdanielk1977 } 11736622cce3Sdanielk1977 11744ad1713cSdanielk1977 if( pStmt ){ 11756622cce3Sdanielk1977 if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR; 11766622cce3Sdanielk1977 Tcl_AppendResult(interp, zBuf, 0); 11774ad1713cSdanielk1977 } 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_prepare16( 11906622cce3Sdanielk1977 void * clientData, 11916622cce3Sdanielk1977 Tcl_Interp *interp, 11926622cce3Sdanielk1977 int objc, 11936622cce3Sdanielk1977 Tcl_Obj *CONST objv[] 11946622cce3Sdanielk1977 ){ 11956622cce3Sdanielk1977 sqlite3 *db; 11966622cce3Sdanielk1977 const void *zSql; 11976622cce3Sdanielk1977 const void *zTail = 0; 11986622cce3Sdanielk1977 Tcl_Obj *pTail = 0; 11996622cce3Sdanielk1977 sqlite3_stmt *pStmt = 0; 12006622cce3Sdanielk1977 char zBuf[50]; 12016622cce3Sdanielk1977 int bytes; /* The integer specified as arg 3 */ 12026622cce3Sdanielk1977 int objlen; /* The byte-array length of arg 2 */ 12036622cce3Sdanielk1977 12046622cce3Sdanielk1977 if( objc!=5 ){ 12056622cce3Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 12066622cce3Sdanielk1977 Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0); 12076622cce3Sdanielk1977 return TCL_ERROR; 12086622cce3Sdanielk1977 } 12096622cce3Sdanielk1977 if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 12106622cce3Sdanielk1977 zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen); 12116622cce3Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR; 12126622cce3Sdanielk1977 12136622cce3Sdanielk1977 if( SQLITE_OK!=sqlite3_prepare16(db, zSql, bytes, &pStmt, &zTail) ){ 12146622cce3Sdanielk1977 return TCL_ERROR; 12156622cce3Sdanielk1977 } 12166622cce3Sdanielk1977 12176622cce3Sdanielk1977 if( zTail ){ 12186622cce3Sdanielk1977 objlen = objlen - ((u8 *)zTail-(u8 *)zSql); 12196622cce3Sdanielk1977 }else{ 12206622cce3Sdanielk1977 objlen = 0; 12216622cce3Sdanielk1977 } 12226622cce3Sdanielk1977 pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen); 12236622cce3Sdanielk1977 Tcl_IncrRefCount(pTail); 12246622cce3Sdanielk1977 Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0); 12254ad1713cSdanielk1977 Tcl_DecrRefCount(pTail); 12266622cce3Sdanielk1977 12274ad1713cSdanielk1977 if( pStmt ){ 12286622cce3Sdanielk1977 if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR; 12294ad1713cSdanielk1977 } 12306622cce3Sdanielk1977 Tcl_AppendResult(interp, zBuf, 0); 12316622cce3Sdanielk1977 return TCL_OK; 12326622cce3Sdanielk1977 } 12336622cce3Sdanielk1977 12344ad1713cSdanielk1977 /* 12354ad1713cSdanielk1977 ** Usage: sqlite3_open filename ?options-list? 12364ad1713cSdanielk1977 */ 12374ad1713cSdanielk1977 static int test_open( 12384ad1713cSdanielk1977 void * clientData, 12394ad1713cSdanielk1977 Tcl_Interp *interp, 12404ad1713cSdanielk1977 int objc, 12414ad1713cSdanielk1977 Tcl_Obj *CONST objv[] 12424ad1713cSdanielk1977 ){ 12434ad1713cSdanielk1977 const char *zFilename; 12444ad1713cSdanielk1977 sqlite3 *db; 12454ad1713cSdanielk1977 int rc; 12464ad1713cSdanielk1977 char zBuf[100]; 12474ad1713cSdanielk1977 12484ad1713cSdanielk1977 if( objc!=3 && objc!=2 ){ 12494ad1713cSdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 12504ad1713cSdanielk1977 Tcl_GetString(objv[0]), " filename options-list", 0); 12514ad1713cSdanielk1977 return TCL_ERROR; 12524ad1713cSdanielk1977 } 12534ad1713cSdanielk1977 12544ad1713cSdanielk1977 zFilename = Tcl_GetString(objv[1]); 125580290863Sdanielk1977 rc = sqlite3_open(zFilename, &db, 0); 12564ad1713cSdanielk1977 12574ad1713cSdanielk1977 if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR; 12584ad1713cSdanielk1977 Tcl_AppendResult(interp, zBuf, 0); 12594ad1713cSdanielk1977 return TCL_OK; 12604ad1713cSdanielk1977 } 12614ad1713cSdanielk1977 12624ad1713cSdanielk1977 /* 12634ad1713cSdanielk1977 ** Usage: sqlite3_open16 filename options 12644ad1713cSdanielk1977 */ 12654ad1713cSdanielk1977 static int test_open16( 12664ad1713cSdanielk1977 void * clientData, 12674ad1713cSdanielk1977 Tcl_Interp *interp, 12684ad1713cSdanielk1977 int objc, 12694ad1713cSdanielk1977 Tcl_Obj *CONST objv[] 12704ad1713cSdanielk1977 ){ 12714ad1713cSdanielk1977 const void *zFilename; 12724ad1713cSdanielk1977 sqlite3 *db; 12734ad1713cSdanielk1977 int rc; 12744ad1713cSdanielk1977 char zBuf[100]; 12754ad1713cSdanielk1977 12764ad1713cSdanielk1977 if( objc!=3 ){ 12774ad1713cSdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 12784ad1713cSdanielk1977 Tcl_GetString(objv[0]), " filename options-list", 0); 12794ad1713cSdanielk1977 return TCL_ERROR; 12804ad1713cSdanielk1977 } 12814ad1713cSdanielk1977 12824ad1713cSdanielk1977 zFilename = Tcl_GetByteArrayFromObj(objv[1], 0); 12834ad1713cSdanielk1977 rc = sqlite3_open16(zFilename, &db, 0); 12844ad1713cSdanielk1977 12854ad1713cSdanielk1977 if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR; 12864ad1713cSdanielk1977 Tcl_AppendResult(interp, zBuf, 0); 12874ad1713cSdanielk1977 return TCL_OK; 12884ad1713cSdanielk1977 } 1289d3d39e93Sdrh 1290d3d39e93Sdrh /* 1291106bb236Sdanielk1977 ** Usage: sqlite3_step STMT 1292106bb236Sdanielk1977 ** 1293106bb236Sdanielk1977 ** Advance the statement to the next row. 1294106bb236Sdanielk1977 */ 129517240fd9Sdanielk1977 static int test_step( 1296106bb236Sdanielk1977 void * clientData, 1297106bb236Sdanielk1977 Tcl_Interp *interp, 1298106bb236Sdanielk1977 int objc, 1299106bb236Sdanielk1977 Tcl_Obj *CONST objv[] 1300106bb236Sdanielk1977 ){ 1301106bb236Sdanielk1977 sqlite3_stmt *pStmt; 1302106bb236Sdanielk1977 int rc; 1303106bb236Sdanielk1977 1304e1cd9874Sdanielk1977 if( objc!=2 ){ 1305106bb236Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 1306106bb236Sdanielk1977 Tcl_GetString(objv[0]), " STMT", 0); 1307106bb236Sdanielk1977 return TCL_ERROR; 1308106bb236Sdanielk1977 } 1309106bb236Sdanielk1977 1310106bb236Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 131117240fd9Sdanielk1977 rc = sqlite3_step(pStmt); 1312106bb236Sdanielk1977 1313e1cd9874Sdanielk1977 if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR; 13146590493dSdanielk1977 Tcl_SetResult(interp, (char *)errorName(rc), 0); 1315e1cd9874Sdanielk1977 return TCL_OK; 1316e1cd9874Sdanielk1977 } 1317e1cd9874Sdanielk1977 1318e1cd9874Sdanielk1977 /* 1319e1cd9874Sdanielk1977 ** Usage: sqlite3_column_data STMT column 1320e1cd9874Sdanielk1977 ** 1321e1cd9874Sdanielk1977 ** Advance the statement to the next row. 1322e1cd9874Sdanielk1977 */ 1323e1cd9874Sdanielk1977 static int test_column_data( 1324e1cd9874Sdanielk1977 void * clientData, 1325e1cd9874Sdanielk1977 Tcl_Interp *interp, 1326e1cd9874Sdanielk1977 int objc, 1327e1cd9874Sdanielk1977 Tcl_Obj *CONST objv[] 1328e1cd9874Sdanielk1977 ){ 1329e1cd9874Sdanielk1977 sqlite3_stmt *pStmt; 1330e1cd9874Sdanielk1977 int col; 1331e1cd9874Sdanielk1977 Tcl_Obj *pRet; 1332e1cd9874Sdanielk1977 1333e1cd9874Sdanielk1977 if( objc!=3 ){ 1334e1cd9874Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 1335e1cd9874Sdanielk1977 Tcl_GetString(objv[0]), " STMT column", 0); 1336e1cd9874Sdanielk1977 return TCL_ERROR; 1337e1cd9874Sdanielk1977 } 1338e1cd9874Sdanielk1977 1339e1cd9874Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 1340e1cd9874Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; 1341e1cd9874Sdanielk1977 1342e1cd9874Sdanielk1977 if( SQLITE3_BLOB==sqlite3_column_type(pStmt, col) ){ 1343e1cd9874Sdanielk1977 int len = sqlite3_column_bytes(pStmt, col); 1344e1cd9874Sdanielk1977 pRet = Tcl_NewByteArrayObj(sqlite3_column_data(pStmt, col), len); 1345e1cd9874Sdanielk1977 }else{ 1346e1cd9874Sdanielk1977 pRet = Tcl_NewStringObj(sqlite3_column_data(pStmt, col), -1); 1347e1cd9874Sdanielk1977 } 1348e1cd9874Sdanielk1977 Tcl_SetObjResult(interp, pRet); 1349e1cd9874Sdanielk1977 1350e1cd9874Sdanielk1977 return TCL_OK; 1351e1cd9874Sdanielk1977 } 1352e1cd9874Sdanielk1977 1353e1cd9874Sdanielk1977 /* 1354e1cd9874Sdanielk1977 ** Usage: sqlite3_column_data16 STMT column 1355e1cd9874Sdanielk1977 ** 1356e1cd9874Sdanielk1977 ** Advance the statement to the next row. 1357e1cd9874Sdanielk1977 */ 1358e1cd9874Sdanielk1977 static int test_column_data16( 1359e1cd9874Sdanielk1977 void * clientData, 1360e1cd9874Sdanielk1977 Tcl_Interp *interp, 1361e1cd9874Sdanielk1977 int objc, 1362e1cd9874Sdanielk1977 Tcl_Obj *CONST objv[] 1363e1cd9874Sdanielk1977 ){ 1364e1cd9874Sdanielk1977 sqlite3_stmt *pStmt; 1365e1cd9874Sdanielk1977 int col; 1366e1cd9874Sdanielk1977 Tcl_Obj *pRet; 1367e1cd9874Sdanielk1977 int len; 1368e1cd9874Sdanielk1977 1369e1cd9874Sdanielk1977 if( objc!=3 ){ 1370e1cd9874Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 1371e1cd9874Sdanielk1977 Tcl_GetString(objv[0]), " STMT column", 0); 1372e1cd9874Sdanielk1977 return TCL_ERROR; 1373e1cd9874Sdanielk1977 } 1374e1cd9874Sdanielk1977 1375e1cd9874Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 1376e1cd9874Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; 1377e1cd9874Sdanielk1977 1378e1cd9874Sdanielk1977 len = sqlite3_column_bytes16(pStmt, col); 1379e1cd9874Sdanielk1977 pRet = Tcl_NewByteArrayObj(sqlite3_column_data16(pStmt, col), len); 1380e1cd9874Sdanielk1977 Tcl_SetObjResult(interp, pRet); 1381e1cd9874Sdanielk1977 1382106bb236Sdanielk1977 return TCL_OK; 1383106bb236Sdanielk1977 } 1384106bb236Sdanielk1977 1385106bb236Sdanielk1977 /* 13863cf86063Sdanielk1977 ** Usage: sqlite3_column_name STMT column 13873cf86063Sdanielk1977 ** 13883cf86063Sdanielk1977 ** Advance the statement to the next row. 13893cf86063Sdanielk1977 */ 13903cf86063Sdanielk1977 static int test_column_name( 13913cf86063Sdanielk1977 void * clientData, 13923cf86063Sdanielk1977 Tcl_Interp *interp, 13933cf86063Sdanielk1977 int objc, 13943cf86063Sdanielk1977 Tcl_Obj *CONST objv[] 13953cf86063Sdanielk1977 ){ 13963cf86063Sdanielk1977 sqlite3_stmt *pStmt; 13973cf86063Sdanielk1977 int col; 13983cf86063Sdanielk1977 13993cf86063Sdanielk1977 if( objc!=3 ){ 14003cf86063Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 14013cf86063Sdanielk1977 Tcl_GetString(objv[0]), " STMT column", 0); 14023cf86063Sdanielk1977 return TCL_ERROR; 14033cf86063Sdanielk1977 } 14043cf86063Sdanielk1977 14053cf86063Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 14063cf86063Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; 14073cf86063Sdanielk1977 14083cf86063Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_column_name(pStmt, col), 0); 14093cf86063Sdanielk1977 14103cf86063Sdanielk1977 return TCL_OK; 14113cf86063Sdanielk1977 } 14123cf86063Sdanielk1977 14133cf86063Sdanielk1977 /* 14143cf86063Sdanielk1977 ** Usage: sqlite3_column_name16 STMT column 14153cf86063Sdanielk1977 ** 14163cf86063Sdanielk1977 ** Advance the statement to the next row. 14173cf86063Sdanielk1977 */ 14183cf86063Sdanielk1977 static int test_column_name16( 14193cf86063Sdanielk1977 void * clientData, 14203cf86063Sdanielk1977 Tcl_Interp *interp, 14213cf86063Sdanielk1977 int objc, 14223cf86063Sdanielk1977 Tcl_Obj *CONST objv[] 14233cf86063Sdanielk1977 ){ 14243cf86063Sdanielk1977 sqlite3_stmt *pStmt; 14253cf86063Sdanielk1977 int col; 14263cf86063Sdanielk1977 Tcl_Obj *pRet; 14273cf86063Sdanielk1977 const void *zName16; 14283cf86063Sdanielk1977 14293cf86063Sdanielk1977 if( objc!=3 ){ 14303cf86063Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 14313cf86063Sdanielk1977 Tcl_GetString(objv[0]), " STMT column", 0); 14323cf86063Sdanielk1977 return TCL_ERROR; 14333cf86063Sdanielk1977 } 14343cf86063Sdanielk1977 14353cf86063Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 14363cf86063Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; 14373cf86063Sdanielk1977 14383cf86063Sdanielk1977 zName16 = sqlite3_column_name16(pStmt, col); 14393cf86063Sdanielk1977 pRet = Tcl_NewByteArrayObj(zName16, sqlite3utf16ByteLen(zName16, -1)+2); 14403cf86063Sdanielk1977 Tcl_SetObjResult(interp, pRet); 14413cf86063Sdanielk1977 14423cf86063Sdanielk1977 return TCL_OK; 14433cf86063Sdanielk1977 } 14443cf86063Sdanielk1977 14453cf86063Sdanielk1977 /* 144617240fd9Sdanielk1977 ** Usage: sqlite3_column_count STMT 144717240fd9Sdanielk1977 ** 144817240fd9Sdanielk1977 ** Return the number of columns returned by the sql statement STMT. 144917240fd9Sdanielk1977 */ 145017240fd9Sdanielk1977 static int test_column_count( 145117240fd9Sdanielk1977 void * clientData, 145217240fd9Sdanielk1977 Tcl_Interp *interp, 145317240fd9Sdanielk1977 int objc, 145417240fd9Sdanielk1977 Tcl_Obj *CONST objv[] 145517240fd9Sdanielk1977 ){ 145617240fd9Sdanielk1977 sqlite3_stmt *pStmt; 145717240fd9Sdanielk1977 145817240fd9Sdanielk1977 if( objc!=2 ){ 145917240fd9Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 146017240fd9Sdanielk1977 Tcl_GetString(objv[0]), " STMT column", 0); 146117240fd9Sdanielk1977 return TCL_ERROR; 146217240fd9Sdanielk1977 } 146317240fd9Sdanielk1977 146417240fd9Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 146517240fd9Sdanielk1977 146617240fd9Sdanielk1977 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_column_count(pStmt))); 146717240fd9Sdanielk1977 return TCL_OK; 146817240fd9Sdanielk1977 } 146917240fd9Sdanielk1977 147017240fd9Sdanielk1977 /* 14713cf86063Sdanielk1977 ** Usage: sqlite3_column_type STMT column 14723cf86063Sdanielk1977 ** 14733cf86063Sdanielk1977 ** Return the type of the data in column 'column' of the current row. 14743cf86063Sdanielk1977 */ 14753cf86063Sdanielk1977 static int test_column_type( 14763cf86063Sdanielk1977 void * clientData, 14773cf86063Sdanielk1977 Tcl_Interp *interp, 14783cf86063Sdanielk1977 int objc, 14793cf86063Sdanielk1977 Tcl_Obj *CONST objv[] 14803cf86063Sdanielk1977 ){ 14813cf86063Sdanielk1977 sqlite3_stmt *pStmt; 14823cf86063Sdanielk1977 int col; 14833cf86063Sdanielk1977 int tp; 14843cf86063Sdanielk1977 14853cf86063Sdanielk1977 if( objc!=3 ){ 14863cf86063Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 14873cf86063Sdanielk1977 Tcl_GetString(objv[0]), " STMT column", 0); 14883cf86063Sdanielk1977 return TCL_ERROR; 14893cf86063Sdanielk1977 } 14903cf86063Sdanielk1977 14913cf86063Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 14923cf86063Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; 14933cf86063Sdanielk1977 14943cf86063Sdanielk1977 tp = sqlite3_column_type(pStmt, col); 14953cf86063Sdanielk1977 switch( tp ){ 14963cf86063Sdanielk1977 case SQLITE3_INTEGER: 14973cf86063Sdanielk1977 Tcl_SetResult(interp, "INTEGER", TCL_STATIC); 14983cf86063Sdanielk1977 break; 14993cf86063Sdanielk1977 case SQLITE3_NULL: 15003cf86063Sdanielk1977 Tcl_SetResult(interp, "NULL", TCL_STATIC); 15013cf86063Sdanielk1977 break; 15023cf86063Sdanielk1977 case SQLITE3_FLOAT: 15033cf86063Sdanielk1977 Tcl_SetResult(interp, "FLOAT", TCL_STATIC); 15043cf86063Sdanielk1977 break; 15053cf86063Sdanielk1977 case SQLITE3_TEXT: 15063cf86063Sdanielk1977 Tcl_SetResult(interp, "TEXT", TCL_STATIC); 15073cf86063Sdanielk1977 break; 15083cf86063Sdanielk1977 case SQLITE3_BLOB: 15093cf86063Sdanielk1977 Tcl_SetResult(interp, "BLOB", TCL_STATIC); 15103cf86063Sdanielk1977 break; 15113cf86063Sdanielk1977 default: 15123cf86063Sdanielk1977 assert(0); 15133cf86063Sdanielk1977 } 15143cf86063Sdanielk1977 15153cf86063Sdanielk1977 return TCL_OK; 15163cf86063Sdanielk1977 } 15173cf86063Sdanielk1977 15183cf86063Sdanielk1977 /* 15193cf86063Sdanielk1977 ** Usage: sqlite3_column_int STMT column 15203cf86063Sdanielk1977 ** 15213cf86063Sdanielk1977 ** Return the data in column 'column' of the current row cast as an 15223cf86063Sdanielk1977 ** integer. 15233cf86063Sdanielk1977 */ 15243cf86063Sdanielk1977 static int test_column_int( 15253cf86063Sdanielk1977 void * clientData, 15263cf86063Sdanielk1977 Tcl_Interp *interp, 15273cf86063Sdanielk1977 int objc, 15283cf86063Sdanielk1977 Tcl_Obj *CONST objv[] 15293cf86063Sdanielk1977 ){ 15303cf86063Sdanielk1977 sqlite3_stmt *pStmt; 15313cf86063Sdanielk1977 int col; 15323cf86063Sdanielk1977 15333cf86063Sdanielk1977 if( objc!=3 ){ 15343cf86063Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 15353cf86063Sdanielk1977 Tcl_GetString(objv[0]), " STMT column", 0); 15363cf86063Sdanielk1977 return TCL_ERROR; 15373cf86063Sdanielk1977 } 15383cf86063Sdanielk1977 15393cf86063Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 15403cf86063Sdanielk1977 if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; 15413cf86063Sdanielk1977 15423cf86063Sdanielk1977 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_column_int(pStmt, col))); 15433cf86063Sdanielk1977 return TCL_OK; 15443cf86063Sdanielk1977 } 15453cf86063Sdanielk1977 15463cf86063Sdanielk1977 /* 154717240fd9Sdanielk1977 ** Usage: sqlite3_data_count STMT 154817240fd9Sdanielk1977 ** 154917240fd9Sdanielk1977 ** Return the number of columns returned by the sql statement STMT. 155017240fd9Sdanielk1977 */ 155117240fd9Sdanielk1977 static int test_data_count( 155217240fd9Sdanielk1977 void * clientData, 155317240fd9Sdanielk1977 Tcl_Interp *interp, 155417240fd9Sdanielk1977 int objc, 155517240fd9Sdanielk1977 Tcl_Obj *CONST objv[] 155617240fd9Sdanielk1977 ){ 155717240fd9Sdanielk1977 sqlite3_stmt *pStmt; 155817240fd9Sdanielk1977 155917240fd9Sdanielk1977 if( objc!=2 ){ 156017240fd9Sdanielk1977 Tcl_AppendResult(interp, "wrong # args: should be \"", 156117240fd9Sdanielk1977 Tcl_GetString(objv[0]), " STMT column", 0); 156217240fd9Sdanielk1977 return TCL_ERROR; 156317240fd9Sdanielk1977 } 156417240fd9Sdanielk1977 156517240fd9Sdanielk1977 if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; 156617240fd9Sdanielk1977 156717240fd9Sdanielk1977 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_data_count(pStmt))); 156817240fd9Sdanielk1977 return TCL_OK; 156917240fd9Sdanielk1977 } 157017240fd9Sdanielk1977 157117240fd9Sdanielk1977 /* 1572d3d39e93Sdrh ** This is a collating function named "REVERSE" which sorts text 1573d3d39e93Sdrh ** in reverse order. 1574d3d39e93Sdrh */ 1575d3d39e93Sdrh static int reverseCollatingFunc( 1576d3d39e93Sdrh void *NotUsed, 1577d3d39e93Sdrh int nKey1, const void *pKey1, 1578d3d39e93Sdrh int nKey2, const void *pKey2 1579d3d39e93Sdrh ){ 1580d3d39e93Sdrh int rc, n; 1581d3d39e93Sdrh n = nKey1<nKey2 ? nKey1 : nKey2; 1582d3d39e93Sdrh rc = memcmp(pKey1, pKey2, n); 1583d3d39e93Sdrh if( rc==0 ){ 1584d3d39e93Sdrh rc = nKey1 - nKey2; 1585d3d39e93Sdrh } 1586d3d39e93Sdrh return -rc; 1587d3d39e93Sdrh } 1588d3d39e93Sdrh 1589d3d39e93Sdrh /* 1590d3d39e93Sdrh ** Usage: add_reverse_collating_func DB 1591d3d39e93Sdrh ** 1592d3d39e93Sdrh ** This routine adds a collation named "REVERSE" to database given. 1593d3d39e93Sdrh ** REVERSE is used for testing only. 1594d3d39e93Sdrh */ 1595d3d39e93Sdrh static int reverse_collfunc( 1596d3d39e93Sdrh void * clientData, 1597d3d39e93Sdrh Tcl_Interp *interp, 1598d3d39e93Sdrh int objc, 1599d3d39e93Sdrh Tcl_Obj *CONST objv[] 1600d3d39e93Sdrh ){ 1601d3d39e93Sdrh sqlite3 *db; 1602d3d39e93Sdrh 1603d3d39e93Sdrh if( objc!=2 ){ 1604d3d39e93Sdrh Tcl_WrongNumArgs(interp, 1, objv, "DB"); 1605d3d39e93Sdrh return TCL_ERROR; 1606d3d39e93Sdrh } 1607d3d39e93Sdrh if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; 1608d3d39e93Sdrh sqlite3ChangeCollatingFunction(db, "REVERSE", 7, 0, reverseCollatingFunc); 1609d3d39e93Sdrh return TCL_OK; 1610d3d39e93Sdrh } 1611d3d39e93Sdrh 1612d3d39e93Sdrh 16136622cce3Sdanielk1977 /* 1614d1bf3512Sdrh ** Register commands with the TCL interpreter. 1615d1bf3512Sdrh */ 1616d1bf3512Sdrh int Sqlitetest1_Init(Tcl_Interp *interp){ 16176f8a503dSdanielk1977 extern int sqlite3_search_count; 16186f8a503dSdanielk1977 extern int sqlite3_interrupt_count; 16196f8a503dSdanielk1977 extern int sqlite3_open_file_count; 16206f8a503dSdanielk1977 extern int sqlite3_current_time; 1621c2eef3b3Sdrh static struct { 1622c2eef3b3Sdrh char *zName; 1623c2eef3b3Sdrh Tcl_CmdProc *xProc; 1624c2eef3b3Sdrh } aCmd[] = { 16256f8a503dSdanielk1977 { "sqlite3_mprintf_int", (Tcl_CmdProc*)sqlite3_mprintf_int }, 16266f8a503dSdanielk1977 { "sqlite3_mprintf_str", (Tcl_CmdProc*)sqlite3_mprintf_str }, 16276f8a503dSdanielk1977 { "sqlite3_mprintf_double", (Tcl_CmdProc*)sqlite3_mprintf_double }, 16286f8a503dSdanielk1977 { "sqlite3_mprintf_scaled", (Tcl_CmdProc*)sqlite3_mprintf_scaled }, 16296f8a503dSdanielk1977 { "sqlite3_mprintf_z_test", (Tcl_CmdProc*)test_mprintf_z }, 16306f8a503dSdanielk1977 { "sqlite3_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid }, 16316f8a503dSdanielk1977 { "sqlite3_exec_printf", (Tcl_CmdProc*)test_exec_printf }, 16326f8a503dSdanielk1977 { "sqlite3_get_table_printf", (Tcl_CmdProc*)test_get_table_printf }, 16336f8a503dSdanielk1977 { "sqlite3_close", (Tcl_CmdProc*)sqlite_test_close }, 16346f8a503dSdanielk1977 { "sqlite3_create_function", (Tcl_CmdProc*)test_create_function }, 16356f8a503dSdanielk1977 { "sqlite3_create_aggregate", (Tcl_CmdProc*)test_create_aggregate }, 1636c2eef3b3Sdrh { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func }, 1637c2eef3b3Sdrh { "sqlite_abort", (Tcl_CmdProc*)sqlite_abort }, 1638c2eef3b3Sdrh #ifdef MEMORY_DEBUG 1639c2eef3b3Sdrh { "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail }, 1640c2eef3b3Sdrh { "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat }, 1641c2eef3b3Sdrh #endif 164296fc5fe6Sdanielk1977 { "sqlite_bind", (Tcl_CmdProc*)test_bind }, 164399ee3600Sdrh { "breakpoint", (Tcl_CmdProc*)test_breakpoint }, 1644c2eef3b3Sdrh }; 164551e3d8e2Sdanielk1977 static struct { 164651e3d8e2Sdanielk1977 char *zName; 164751e3d8e2Sdanielk1977 Tcl_ObjCmdProc *xProc; 164851e3d8e2Sdanielk1977 } aObjCmd[] = { 164951e3d8e2Sdanielk1977 { "sqlite3_bind_int32", (Tcl_ObjCmdProc*)test_bind_int32 }, 165051e3d8e2Sdanielk1977 { "sqlite3_bind_int64", (Tcl_ObjCmdProc*)test_bind_int64 }, 165151e3d8e2Sdanielk1977 { "sqlite3_bind_double", (Tcl_ObjCmdProc*)test_bind_double }, 165251e3d8e2Sdanielk1977 { "sqlite3_bind_null", (Tcl_ObjCmdProc*)test_bind_null }, 165351e3d8e2Sdanielk1977 { "sqlite3_bind_text", (Tcl_ObjCmdProc*)test_bind_text }, 165451e3d8e2Sdanielk1977 { "sqlite3_bind_text16", (Tcl_ObjCmdProc*)test_bind_text16 }, 165551e3d8e2Sdanielk1977 { "sqlite3_bind_blob", (Tcl_ObjCmdProc*)test_bind_blob }, 16566622cce3Sdanielk1977 { "sqlite3_errcode", (Tcl_ObjCmdProc*)test_errcode }, 16576622cce3Sdanielk1977 { "sqlite3_errmsg", (Tcl_ObjCmdProc*)test_errmsg }, 16586622cce3Sdanielk1977 { "sqlite3_errmsg16", (Tcl_ObjCmdProc*)test_errmsg16 }, 16596622cce3Sdanielk1977 { "sqlite3_prepare", (Tcl_ObjCmdProc*)test_prepare }, 16606622cce3Sdanielk1977 { "sqlite3_prepare16", (Tcl_ObjCmdProc*)test_prepare16 }, 16614ad1713cSdanielk1977 { "sqlite3_open", (Tcl_ObjCmdProc*)test_open }, 16624ad1713cSdanielk1977 { "sqlite3_open16", (Tcl_ObjCmdProc*)test_open16 }, 1663106bb236Sdanielk1977 { "sqlite3_finalize", (Tcl_ObjCmdProc*)test_finalize }, 1664106bb236Sdanielk1977 { "sqlite3_reset", (Tcl_ObjCmdProc*)test_reset }, 166517240fd9Sdanielk1977 { "sqlite3_step", (Tcl_ObjCmdProc*)test_step}, 1666e1cd9874Sdanielk1977 { "sqlite3_column_data", (Tcl_ObjCmdProc*)test_column_data }, 1667e1cd9874Sdanielk1977 { "sqlite3_column_data16", (Tcl_ObjCmdProc*)test_column_data16 }, 166817240fd9Sdanielk1977 { "sqlite3_column_count", (Tcl_ObjCmdProc*)test_column_count }, 16693cf86063Sdanielk1977 { "sqlite3_column_name", (Tcl_ObjCmdProc*)test_column_name }, 16703cf86063Sdanielk1977 { "sqlite3_column_name16", (Tcl_ObjCmdProc*)test_column_name16 }, 16713cf86063Sdanielk1977 { "sqlite3_column_type", (Tcl_ObjCmdProc*)test_column_type }, 16723cf86063Sdanielk1977 { "sqlite3_column_int", (Tcl_ObjCmdProc*)test_column_int }, 167317240fd9Sdanielk1977 { "sqlite3_data_count", (Tcl_ObjCmdProc*)test_data_count }, 1674d3d39e93Sdrh { "add_reverse_collating_func", (Tcl_ObjCmdProc*)reverse_collfunc }, 167551e3d8e2Sdanielk1977 }; 1676c2eef3b3Sdrh int i; 1677c2eef3b3Sdrh 1678c2eef3b3Sdrh for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ 1679c2eef3b3Sdrh Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); 1680c2eef3b3Sdrh } 168151e3d8e2Sdanielk1977 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ 168251e3d8e2Sdanielk1977 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); 168351e3d8e2Sdanielk1977 } 16846490bebdSdanielk1977 Tcl_LinkVar(interp, "sqlite_search_count", 16856f8a503dSdanielk1977 (char*)&sqlite3_search_count, TCL_LINK_INT); 16866490bebdSdanielk1977 Tcl_LinkVar(interp, "sqlite_interrupt_count", 16876f8a503dSdanielk1977 (char*)&sqlite3_interrupt_count, TCL_LINK_INT); 16886490bebdSdanielk1977 Tcl_LinkVar(interp, "sqlite_open_file_count", 16896f8a503dSdanielk1977 (char*)&sqlite3_open_file_count, TCL_LINK_INT); 16906490bebdSdanielk1977 Tcl_LinkVar(interp, "sqlite_current_time", 16916f8a503dSdanielk1977 (char*)&sqlite3_current_time, TCL_LINK_INT); 16927c972decSdrh Tcl_LinkVar(interp, "sqlite_static_bind_value", 16937c972decSdrh (char*)&sqlite_static_bind_value, TCL_LINK_STRING); 1694d1bf3512Sdrh return TCL_OK; 1695d1bf3512Sdrh } 1696