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*5f968436Sdrh ** $Id: test1.c,v 1.34 2004/02/21 19:02:30 drh 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 30d1bf3512Sdrh /* 31b86ccfb2Sdrh ** Decode a pointer to an sqlite object. 32b86ccfb2Sdrh */ 3390f405e3Sdrh static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite **ppDb){ 3490f405e3Sdrh if( sscanf(zA, PTR_FMT, (void**)ppDb)!=1 && 3590f405e3Sdrh (zA[0]!='0' || zA[1]!='x' || sscanf(&zA[2], PTR_FMT, (void**)ppDb)!=1) 3690f405e3Sdrh ){ 3790f405e3Sdrh Tcl_AppendResult(interp, "\"", zA, "\" is not a valid pointer value", 0); 38b86ccfb2Sdrh return TCL_ERROR; 39b86ccfb2Sdrh } 40b86ccfb2Sdrh return TCL_OK; 41b86ccfb2Sdrh } 42b86ccfb2Sdrh 43b86ccfb2Sdrh /* 44b86ccfb2Sdrh ** Decode a pointer to an sqlite_vm object. 45b86ccfb2Sdrh */ 46b86ccfb2Sdrh static int getVmPointer(Tcl_Interp *interp, const char *zArg, sqlite_vm **ppVm){ 4794e92032Sdrh if( sscanf(zArg, PTR_FMT, (void**)ppVm)!=1 ){ 48b86ccfb2Sdrh Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0); 49b86ccfb2Sdrh return TCL_ERROR; 50b86ccfb2Sdrh } 51b86ccfb2Sdrh return TCL_OK; 52b86ccfb2Sdrh } 53b86ccfb2Sdrh 54b86ccfb2Sdrh /* 557d8085a8Sdrh ** Generate a text representation of a pointer that can be understood 567d8085a8Sdrh ** by the getDbPointer and getVmPointer routines above. 577d8085a8Sdrh ** 587d8085a8Sdrh ** The problem is, on some machines (Solaris) if you do a printf with 597d8085a8Sdrh ** "%p" you cannot turn around and do a scanf with the same "%p" and 607d8085a8Sdrh ** get your pointer back. You have to prepend a "0x" before it will 617d8085a8Sdrh ** work. Or at least that is what is reported to me (drh). But this 627d8085a8Sdrh ** behavior varies from machine to machine. The solution used her is 637d8085a8Sdrh ** to test the string right after it is generated to see if it can be 647d8085a8Sdrh ** understood by scanf, and if not, try prepending an "0x" to see if 657d8085a8Sdrh ** that helps. If nothing works, a fatal error is generated. 667d8085a8Sdrh */ 677d8085a8Sdrh static int makePointerStr(Tcl_Interp *interp, char *zPtr, void *p){ 687d8085a8Sdrh void *p2; 697d8085a8Sdrh sprintf(zPtr, PTR_FMT, p); 707d8085a8Sdrh if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){ 717d8085a8Sdrh sprintf(zPtr, "0x" PTR_FMT, p); 727d8085a8Sdrh if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){ 737d8085a8Sdrh Tcl_AppendResult(interp, "unable to convert a pointer to a string " 747d8085a8Sdrh "in the file " __FILE__ " in function makePointerStr(). Please " 757d8085a8Sdrh "report this problem to the SQLite mailing list or as a new but " 767d8085a8Sdrh "report. Please provide detailed information about how you compiled " 777d8085a8Sdrh "SQLite and what computer you are running on.", 0); 787d8085a8Sdrh return TCL_ERROR; 797d8085a8Sdrh } 807d8085a8Sdrh } 817d8085a8Sdrh return TCL_OK; 827d8085a8Sdrh } 837d8085a8Sdrh 847d8085a8Sdrh /* 85d1bf3512Sdrh ** Usage: sqlite_open filename 86d1bf3512Sdrh ** 87d1bf3512Sdrh ** Returns: The name of an open database. 88d1bf3512Sdrh */ 89d1bf3512Sdrh static int sqlite_test_open( 90d1bf3512Sdrh void *NotUsed, 91d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 92d1bf3512Sdrh int argc, /* Number of arguments */ 93d1bf3512Sdrh char **argv /* Text of each argument */ 94d1bf3512Sdrh ){ 95d1bf3512Sdrh sqlite *db; 96d1bf3512Sdrh char *zErr = 0; 97d1bf3512Sdrh char zBuf[100]; 98d1bf3512Sdrh if( argc!=2 ){ 99d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 100d1bf3512Sdrh " FILENAME\"", 0); 101d1bf3512Sdrh return TCL_ERROR; 102d1bf3512Sdrh } 103d1bf3512Sdrh db = sqlite_open(argv[1], 0666, &zErr); 104d1bf3512Sdrh if( db==0 ){ 105d1bf3512Sdrh Tcl_AppendResult(interp, zErr, 0); 106d1bf3512Sdrh free(zErr); 107d1bf3512Sdrh return TCL_ERROR; 108d1bf3512Sdrh } 1097d8085a8Sdrh if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR; 110d1bf3512Sdrh Tcl_AppendResult(interp, zBuf, 0); 111d1bf3512Sdrh return TCL_OK; 112d1bf3512Sdrh } 113d1bf3512Sdrh 114d1bf3512Sdrh /* 115d1bf3512Sdrh ** The callback routine for sqlite_exec_printf(). 116d1bf3512Sdrh */ 117d1bf3512Sdrh static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){ 118d1bf3512Sdrh Tcl_DString *str = (Tcl_DString*)pArg; 119d1bf3512Sdrh int i; 120d1bf3512Sdrh 121d1bf3512Sdrh if( Tcl_DStringLength(str)==0 ){ 122d1bf3512Sdrh for(i=0; i<argc; i++){ 123d1bf3512Sdrh Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL"); 124d1bf3512Sdrh } 125d1bf3512Sdrh } 126d1bf3512Sdrh for(i=0; i<argc; i++){ 127d1bf3512Sdrh Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL"); 128d1bf3512Sdrh } 129d1bf3512Sdrh return 0; 130d1bf3512Sdrh } 131d1bf3512Sdrh 132d1bf3512Sdrh /* 133d1bf3512Sdrh ** Usage: sqlite_exec_printf DB FORMAT STRING 134d1bf3512Sdrh ** 135d1bf3512Sdrh ** Invoke the sqlite_exec_printf() interface using the open database 136d1bf3512Sdrh ** DB. The SQL is the string FORMAT. The format string should contain 137d1bf3512Sdrh ** one %s or %q. STRING is the value inserted into %s or %q. 138d1bf3512Sdrh */ 139d1bf3512Sdrh static int test_exec_printf( 140d1bf3512Sdrh void *NotUsed, 141d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 142d1bf3512Sdrh int argc, /* Number of arguments */ 143d1bf3512Sdrh char **argv /* Text of each argument */ 144d1bf3512Sdrh ){ 145d1bf3512Sdrh sqlite *db; 146d1bf3512Sdrh Tcl_DString str; 147d1bf3512Sdrh int rc; 148d1bf3512Sdrh char *zErr = 0; 149d1bf3512Sdrh char zBuf[30]; 150d1bf3512Sdrh if( argc!=4 ){ 151d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 152d1bf3512Sdrh " DB FORMAT STRING", 0); 153d1bf3512Sdrh return TCL_ERROR; 154d1bf3512Sdrh } 155b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 156d1bf3512Sdrh Tcl_DStringInit(&str); 157d1bf3512Sdrh rc = sqlite_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]); 158d1bf3512Sdrh sprintf(zBuf, "%d", rc); 159d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 160d1bf3512Sdrh Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr); 161d1bf3512Sdrh Tcl_DStringFree(&str); 162d1bf3512Sdrh if( zErr ) free(zErr); 163d1bf3512Sdrh return TCL_OK; 164d1bf3512Sdrh } 165d1bf3512Sdrh 166d1bf3512Sdrh /* 167d93d8a81Sdrh ** Usage: sqlite_mprintf_z_test SEPARATOR ARG0 ARG1 ... 168d93d8a81Sdrh ** 169d93d8a81Sdrh ** Test the %z format of mprintf(). Use multiple mprintf() calls to 170d93d8a81Sdrh ** concatenate arg0 through argn using separator as the separator. 171d93d8a81Sdrh ** Return the result. 172d93d8a81Sdrh */ 173d93d8a81Sdrh static int test_mprintf_z( 174d93d8a81Sdrh void *NotUsed, 175d93d8a81Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 176d93d8a81Sdrh int argc, /* Number of arguments */ 177d93d8a81Sdrh char **argv /* Text of each argument */ 178d93d8a81Sdrh ){ 179d93d8a81Sdrh char *zResult = 0; 180d93d8a81Sdrh int i; 181d93d8a81Sdrh 182d93d8a81Sdrh for(i=2; i<argc; i++){ 183*5f968436Sdrh zResult = sqliteMPrintf("%z%s%s", zResult, argv[1], argv[i]); 184d93d8a81Sdrh } 185d93d8a81Sdrh Tcl_AppendResult(interp, zResult, 0); 186*5f968436Sdrh sqliteFree(zResult); 187d93d8a81Sdrh return TCL_OK; 188d93d8a81Sdrh } 189d93d8a81Sdrh 190d93d8a81Sdrh /* 191d1bf3512Sdrh ** Usage: sqlite_get_table_printf DB FORMAT STRING 192d1bf3512Sdrh ** 193d1bf3512Sdrh ** Invoke the sqlite_get_table_printf() interface using the open database 194d1bf3512Sdrh ** DB. The SQL is the string FORMAT. The format string should contain 195d1bf3512Sdrh ** one %s or %q. STRING is the value inserted into %s or %q. 196d1bf3512Sdrh */ 197d1bf3512Sdrh static int test_get_table_printf( 198d1bf3512Sdrh void *NotUsed, 199d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 200d1bf3512Sdrh int argc, /* Number of arguments */ 201d1bf3512Sdrh char **argv /* Text of each argument */ 202d1bf3512Sdrh ){ 203d1bf3512Sdrh sqlite *db; 204d1bf3512Sdrh Tcl_DString str; 205d1bf3512Sdrh int rc; 206d1bf3512Sdrh char *zErr = 0; 207d1bf3512Sdrh int nRow, nCol; 208d1bf3512Sdrh char **aResult; 209d1bf3512Sdrh int i; 210d1bf3512Sdrh char zBuf[30]; 211d1bf3512Sdrh if( argc!=4 ){ 212d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 213d1bf3512Sdrh " DB FORMAT STRING", 0); 214d1bf3512Sdrh return TCL_ERROR; 215d1bf3512Sdrh } 216b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 217d1bf3512Sdrh Tcl_DStringInit(&str); 218d1bf3512Sdrh rc = sqlite_get_table_printf(db, argv[2], &aResult, &nRow, &nCol, 219d1bf3512Sdrh &zErr, argv[3]); 220d1bf3512Sdrh sprintf(zBuf, "%d", rc); 221d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 222d1bf3512Sdrh if( rc==SQLITE_OK ){ 223d1bf3512Sdrh sprintf(zBuf, "%d", nRow); 224d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 225d1bf3512Sdrh sprintf(zBuf, "%d", nCol); 226d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 227d1bf3512Sdrh for(i=0; i<(nRow+1)*nCol; i++){ 228d1bf3512Sdrh Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL"); 229d1bf3512Sdrh } 230d1bf3512Sdrh }else{ 231d1bf3512Sdrh Tcl_AppendElement(interp, zErr); 232d1bf3512Sdrh } 233d1bf3512Sdrh sqlite_free_table(aResult); 234d1bf3512Sdrh if( zErr ) free(zErr); 235d1bf3512Sdrh return TCL_OK; 236d1bf3512Sdrh } 237d1bf3512Sdrh 238af9ff33aSdrh 239af9ff33aSdrh /* 240af9ff33aSdrh ** Usage: sqlite_last_insert_rowid DB 241af9ff33aSdrh ** 242af9ff33aSdrh ** Returns the integer ROWID of the most recent insert. 243af9ff33aSdrh */ 244af9ff33aSdrh static int test_last_rowid( 245af9ff33aSdrh void *NotUsed, 246af9ff33aSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 247af9ff33aSdrh int argc, /* Number of arguments */ 248af9ff33aSdrh char **argv /* Text of each argument */ 249af9ff33aSdrh ){ 250af9ff33aSdrh sqlite *db; 251af9ff33aSdrh char zBuf[30]; 252af9ff33aSdrh 253af9ff33aSdrh if( argc!=2 ){ 254af9ff33aSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0); 255af9ff33aSdrh return TCL_ERROR; 256af9ff33aSdrh } 257b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 258af9ff33aSdrh sprintf(zBuf, "%d", sqlite_last_insert_rowid(db)); 259af9ff33aSdrh Tcl_AppendResult(interp, zBuf, 0); 260af9ff33aSdrh return SQLITE_OK; 261af9ff33aSdrh } 262af9ff33aSdrh 263d1bf3512Sdrh /* 264d1bf3512Sdrh ** Usage: sqlite_close DB 265d1bf3512Sdrh ** 266d1bf3512Sdrh ** Closes the database opened by sqlite_open. 267d1bf3512Sdrh */ 268d1bf3512Sdrh static int sqlite_test_close( 269d1bf3512Sdrh void *NotUsed, 270d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 271d1bf3512Sdrh int argc, /* Number of arguments */ 272d1bf3512Sdrh char **argv /* Text of each argument */ 273d1bf3512Sdrh ){ 274d1bf3512Sdrh sqlite *db; 275d1bf3512Sdrh if( argc!=2 ){ 276d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 277d1bf3512Sdrh " FILENAME\"", 0); 278d1bf3512Sdrh return TCL_ERROR; 279d1bf3512Sdrh } 280b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 281d1bf3512Sdrh sqlite_close(db); 282d1bf3512Sdrh return TCL_OK; 283d1bf3512Sdrh } 284d1bf3512Sdrh 285d1bf3512Sdrh /* 286c22bd47dSdrh ** Implementation of the x_coalesce() function. 287c22bd47dSdrh ** Return the first argument non-NULL argument. 288c22bd47dSdrh */ 289c22bd47dSdrh static void ifnullFunc(sqlite_func *context, int argc, const char **argv){ 290c22bd47dSdrh int i; 291c22bd47dSdrh for(i=0; i<argc; i++){ 292c22bd47dSdrh if( argv[i] ){ 293c22bd47dSdrh sqlite_set_result_string(context, argv[i], -1); 294c22bd47dSdrh break; 295c22bd47dSdrh } 296c22bd47dSdrh } 297c22bd47dSdrh } 298c22bd47dSdrh 299c22bd47dSdrh /* 300d1d9fc33Sdrh ** A structure into which to accumulate text. 301d1d9fc33Sdrh */ 302d1d9fc33Sdrh struct dstr { 303d1d9fc33Sdrh int nAlloc; /* Space allocated */ 304d1d9fc33Sdrh int nUsed; /* Space used */ 305d1d9fc33Sdrh char *z; /* The space */ 306d1d9fc33Sdrh }; 307d1d9fc33Sdrh 308d1d9fc33Sdrh /* 309d1d9fc33Sdrh ** Append text to a dstr 310d1d9fc33Sdrh */ 311d1d9fc33Sdrh static void dstrAppend(struct dstr *p, const char *z, int divider){ 312d1d9fc33Sdrh int n = strlen(z); 313d1d9fc33Sdrh if( p->nUsed + n + 2 > p->nAlloc ){ 314d1d9fc33Sdrh char *zNew; 315d1d9fc33Sdrh p->nAlloc = p->nAlloc*2 + n + 200; 316d1d9fc33Sdrh zNew = sqliteRealloc(p->z, p->nAlloc); 317d1d9fc33Sdrh if( zNew==0 ){ 318d1d9fc33Sdrh sqliteFree(p->z); 319d1d9fc33Sdrh memset(p, 0, sizeof(*p)); 320d1d9fc33Sdrh return; 321d1d9fc33Sdrh } 322d1d9fc33Sdrh p->z = zNew; 323d1d9fc33Sdrh } 324d1d9fc33Sdrh if( divider && p->nUsed>0 ){ 325d1d9fc33Sdrh p->z[p->nUsed++] = divider; 326d1d9fc33Sdrh } 327d1d9fc33Sdrh memcpy(&p->z[p->nUsed], z, n+1); 328d1d9fc33Sdrh p->nUsed += n; 329d1d9fc33Sdrh } 330d1d9fc33Sdrh 331d1d9fc33Sdrh /* 332d1d9fc33Sdrh ** Invoked for each callback from sqliteExecFunc 333d1d9fc33Sdrh */ 334d1d9fc33Sdrh static int execFuncCallback(void *pData, int argc, char **argv, char **NotUsed){ 335d1d9fc33Sdrh struct dstr *p = (struct dstr*)pData; 336d1d9fc33Sdrh int i; 337d1d9fc33Sdrh for(i=0; i<argc; i++){ 338d1d9fc33Sdrh if( argv[i]==0 ){ 339d1d9fc33Sdrh dstrAppend(p, "NULL", ' '); 340d1d9fc33Sdrh }else{ 341d1d9fc33Sdrh dstrAppend(p, argv[i], ' '); 342d1d9fc33Sdrh } 343d1d9fc33Sdrh } 344d1d9fc33Sdrh return 0; 345d1d9fc33Sdrh } 346d1d9fc33Sdrh 347d1d9fc33Sdrh /* 348c22bd47dSdrh ** Implementation of the x_sqlite_exec() function. This function takes 349c22bd47dSdrh ** a single argument and attempts to execute that argument as SQL code. 3506cbe1f1bSdrh ** This is illegal and should set the SQLITE_MISUSE flag on the database. 351c22bd47dSdrh ** 352d1d9fc33Sdrh ** 2004-Jan-07: We have changed this to make it legal to call sqlite_exec() 353d1d9fc33Sdrh ** from within a function call. 354d1d9fc33Sdrh ** 355c22bd47dSdrh ** This routine simulates the effect of having two threads attempt to 356c22bd47dSdrh ** use the same database at the same time. 357c22bd47dSdrh */ 358c22bd47dSdrh static void sqliteExecFunc(sqlite_func *context, int argc, const char **argv){ 359d1d9fc33Sdrh struct dstr x; 360d1d9fc33Sdrh memset(&x, 0, sizeof(x)); 361d1d9fc33Sdrh sqlite_exec((sqlite*)sqlite_user_data(context), argv[0], 362d1d9fc33Sdrh execFuncCallback, &x, 0); 363d1d9fc33Sdrh sqlite_set_result_string(context, x.z, x.nUsed); 364d1d9fc33Sdrh sqliteFree(x.z); 365c22bd47dSdrh } 366c22bd47dSdrh 367c22bd47dSdrh /* 368c22bd47dSdrh ** Usage: sqlite_test_create_function DB 369c22bd47dSdrh ** 370c22bd47dSdrh ** Call the sqlite_create_function API on the given database in order 371c22bd47dSdrh ** to create a function named "x_coalesce". This function does the same thing 372c22bd47dSdrh ** as the "coalesce" function. This function also registers an SQL function 373c22bd47dSdrh ** named "x_sqlite_exec" that invokes sqlite_exec(). Invoking sqlite_exec() 374c22bd47dSdrh ** in this way is illegal recursion and should raise an SQLITE_MISUSE error. 375c22bd47dSdrh ** The effect is similar to trying to use the same database connection from 376c22bd47dSdrh ** two threads at the same time. 377c22bd47dSdrh ** 378c22bd47dSdrh ** The original motivation for this routine was to be able to call the 379c22bd47dSdrh ** sqlite_create_function function while a query is in progress in order 380c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic. 381c22bd47dSdrh */ 382c2eef3b3Sdrh static int test_create_function( 383c22bd47dSdrh void *NotUsed, 384c22bd47dSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 385c22bd47dSdrh int argc, /* Number of arguments */ 386c22bd47dSdrh char **argv /* Text of each argument */ 387c22bd47dSdrh ){ 388c22bd47dSdrh sqlite *db; 389c22bd47dSdrh extern void Md5_Register(sqlite*); 390c22bd47dSdrh if( argc!=2 ){ 391c22bd47dSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 392c22bd47dSdrh " FILENAME\"", 0); 393c22bd47dSdrh return TCL_ERROR; 394c22bd47dSdrh } 395b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 396c22bd47dSdrh sqlite_create_function(db, "x_coalesce", -1, ifnullFunc, 0); 397c22bd47dSdrh sqlite_create_function(db, "x_sqlite_exec", 1, sqliteExecFunc, db); 398c22bd47dSdrh return TCL_OK; 399c22bd47dSdrh } 400c22bd47dSdrh 401c22bd47dSdrh /* 402c22bd47dSdrh ** Routines to implement the x_count() aggregate function. 403c22bd47dSdrh */ 404c22bd47dSdrh typedef struct CountCtx CountCtx; 405c22bd47dSdrh struct CountCtx { 406c22bd47dSdrh int n; 407c22bd47dSdrh }; 408c22bd47dSdrh static void countStep(sqlite_func *context, int argc, const char **argv){ 409c22bd47dSdrh CountCtx *p; 410c22bd47dSdrh p = sqlite_aggregate_context(context, sizeof(*p)); 411c22bd47dSdrh if( (argc==0 || argv[0]) && p ){ 412c22bd47dSdrh p->n++; 413c22bd47dSdrh } 414c22bd47dSdrh } 415c22bd47dSdrh static void countFinalize(sqlite_func *context){ 416c22bd47dSdrh CountCtx *p; 417c22bd47dSdrh p = sqlite_aggregate_context(context, sizeof(*p)); 418c22bd47dSdrh sqlite_set_result_int(context, p ? p->n : 0); 419c22bd47dSdrh } 420c22bd47dSdrh 421c22bd47dSdrh /* 422c22bd47dSdrh ** Usage: sqlite_test_create_aggregate DB 423c22bd47dSdrh ** 424c22bd47dSdrh ** Call the sqlite_create_function API on the given database in order 425c22bd47dSdrh ** to create a function named "x_count". This function does the same thing 426c22bd47dSdrh ** as the "md5sum" function. 427c22bd47dSdrh ** 428c22bd47dSdrh ** The original motivation for this routine was to be able to call the 429c22bd47dSdrh ** sqlite_create_aggregate function while a query is in progress in order 430c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic. 431c22bd47dSdrh */ 432c2eef3b3Sdrh static int test_create_aggregate( 433c22bd47dSdrh void *NotUsed, 434c22bd47dSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 435c22bd47dSdrh int argc, /* Number of arguments */ 436c22bd47dSdrh char **argv /* Text of each argument */ 437c22bd47dSdrh ){ 438c22bd47dSdrh sqlite *db; 439c22bd47dSdrh if( argc!=2 ){ 440c22bd47dSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 441c22bd47dSdrh " FILENAME\"", 0); 442c22bd47dSdrh return TCL_ERROR; 443c22bd47dSdrh } 444b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 445c22bd47dSdrh sqlite_create_aggregate(db, "x_count", 0, countStep, countFinalize, 0); 446c22bd47dSdrh sqlite_create_aggregate(db, "x_count", 1, countStep, countFinalize, 0); 447c22bd47dSdrh return TCL_OK; 448c22bd47dSdrh } 449c22bd47dSdrh 450c22bd47dSdrh 451c22bd47dSdrh 452c22bd47dSdrh /* 453d1bf3512Sdrh ** Usage: sqlite_mprintf_int FORMAT INTEGER INTEGER INTEGER 454d1bf3512Sdrh ** 455d1bf3512Sdrh ** Call mprintf with three integer arguments 456d1bf3512Sdrh */ 457d1bf3512Sdrh static int sqlite_mprintf_int( 458d1bf3512Sdrh void *NotUsed, 459d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 460d1bf3512Sdrh int argc, /* Number of arguments */ 461d1bf3512Sdrh char **argv /* Text of each argument */ 462d1bf3512Sdrh ){ 463d1bf3512Sdrh int a[3], i; 464d1bf3512Sdrh char *z; 465d1bf3512Sdrh if( argc!=5 ){ 466d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 467d1bf3512Sdrh " FORMAT INT INT INT\"", 0); 468d1bf3512Sdrh return TCL_ERROR; 469d1bf3512Sdrh } 470d1bf3512Sdrh for(i=2; i<5; i++){ 471d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 472d1bf3512Sdrh } 473d1bf3512Sdrh z = sqlite_mprintf(argv[1], a[0], a[1], a[2]); 474d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 475fa173a76Sdrh sqlite_freemem(z); 476d1bf3512Sdrh return TCL_OK; 477d1bf3512Sdrh } 478d1bf3512Sdrh 479d1bf3512Sdrh /* 480d1bf3512Sdrh ** Usage: sqlite_mprintf_str FORMAT INTEGER INTEGER STRING 481d1bf3512Sdrh ** 482d1bf3512Sdrh ** Call mprintf with two integer arguments and one string argument 483d1bf3512Sdrh */ 484d1bf3512Sdrh static int sqlite_mprintf_str( 485d1bf3512Sdrh void *NotUsed, 486d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 487d1bf3512Sdrh int argc, /* Number of arguments */ 488d1bf3512Sdrh char **argv /* Text of each argument */ 489d1bf3512Sdrh ){ 490d1bf3512Sdrh int a[3], i; 491d1bf3512Sdrh char *z; 492f220b24fSchw if( argc<4 || argc>5 ){ 493d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 494f220b24fSchw " FORMAT INT INT ?STRING?\"", 0); 495d1bf3512Sdrh return TCL_ERROR; 496d1bf3512Sdrh } 497d1bf3512Sdrh for(i=2; i<4; i++){ 498d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 499d1bf3512Sdrh } 500f220b24fSchw z = sqlite_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL); 501d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 502fa173a76Sdrh sqlite_freemem(z); 503d1bf3512Sdrh return TCL_OK; 504d1bf3512Sdrh } 505d1bf3512Sdrh 506d1bf3512Sdrh /* 507d1bf3512Sdrh ** Usage: sqlite_mprintf_str FORMAT INTEGER INTEGER DOUBLE 508d1bf3512Sdrh ** 509d1bf3512Sdrh ** Call mprintf with two integer arguments and one double argument 510d1bf3512Sdrh */ 511d1bf3512Sdrh static int sqlite_mprintf_double( 512d1bf3512Sdrh void *NotUsed, 513d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 514d1bf3512Sdrh int argc, /* Number of arguments */ 515d1bf3512Sdrh char **argv /* Text of each argument */ 516d1bf3512Sdrh ){ 517d1bf3512Sdrh int a[3], i; 518d1bf3512Sdrh double r; 519d1bf3512Sdrh char *z; 520d1bf3512Sdrh if( argc!=5 ){ 521d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 522d1bf3512Sdrh " FORMAT INT INT STRING\"", 0); 523d1bf3512Sdrh return TCL_ERROR; 524d1bf3512Sdrh } 525d1bf3512Sdrh for(i=2; i<4; i++){ 526d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 527d1bf3512Sdrh } 528d1bf3512Sdrh if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR; 529d1bf3512Sdrh z = sqlite_mprintf(argv[1], a[0], a[1], r); 530d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 531fa173a76Sdrh sqlite_freemem(z); 532d1bf3512Sdrh return TCL_OK; 533d1bf3512Sdrh } 534d1bf3512Sdrh 535d1bf3512Sdrh /* 536daffd0e5Sdrh ** Usage: sqlite_malloc_fail N 537daffd0e5Sdrh ** 538afa4a020Sdrh ** Rig sqliteMalloc() to fail on the N-th call. Turn off this mechanism 539daffd0e5Sdrh ** and reset the sqlite_malloc_failed variable is N==0. 540daffd0e5Sdrh */ 541daffd0e5Sdrh #ifdef MEMORY_DEBUG 542daffd0e5Sdrh static int sqlite_malloc_fail( 543daffd0e5Sdrh void *NotUsed, 544daffd0e5Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 545daffd0e5Sdrh int argc, /* Number of arguments */ 546daffd0e5Sdrh char **argv /* Text of each argument */ 547daffd0e5Sdrh ){ 548daffd0e5Sdrh int n; 549daffd0e5Sdrh if( argc!=2 ){ 550daffd0e5Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0); 551daffd0e5Sdrh return TCL_ERROR; 552daffd0e5Sdrh } 553daffd0e5Sdrh if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR; 554daffd0e5Sdrh sqlite_iMallocFail = n; 555daffd0e5Sdrh sqlite_malloc_failed = 0; 556daffd0e5Sdrh return TCL_OK; 557daffd0e5Sdrh } 558daffd0e5Sdrh #endif 559daffd0e5Sdrh 560daffd0e5Sdrh /* 561daffd0e5Sdrh ** Usage: sqlite_malloc_stat 562daffd0e5Sdrh ** 563daffd0e5Sdrh ** Return the number of prior calls to sqliteMalloc() and sqliteFree(). 564daffd0e5Sdrh */ 565daffd0e5Sdrh #ifdef MEMORY_DEBUG 566daffd0e5Sdrh static int sqlite_malloc_stat( 567daffd0e5Sdrh void *NotUsed, 568daffd0e5Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 569daffd0e5Sdrh int argc, /* Number of arguments */ 570daffd0e5Sdrh char **argv /* Text of each argument */ 571daffd0e5Sdrh ){ 572daffd0e5Sdrh char zBuf[200]; 573daffd0e5Sdrh sprintf(zBuf, "%d %d %d", sqlite_nMalloc, sqlite_nFree, sqlite_iMallocFail); 574daffd0e5Sdrh Tcl_AppendResult(interp, zBuf, 0); 575daffd0e5Sdrh return TCL_OK; 576daffd0e5Sdrh } 577daffd0e5Sdrh #endif 578daffd0e5Sdrh 579daffd0e5Sdrh /* 58028b4e489Sdrh ** Usage: sqlite_abort 58128b4e489Sdrh ** 58228b4e489Sdrh ** Shutdown the process immediately. This is not a clean shutdown. 58328b4e489Sdrh ** This command is used to test the recoverability of a database in 58428b4e489Sdrh ** the event of a program crash. 58528b4e489Sdrh */ 58628b4e489Sdrh static int sqlite_abort( 58728b4e489Sdrh void *NotUsed, 58828b4e489Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 58928b4e489Sdrh int argc, /* Number of arguments */ 59028b4e489Sdrh char **argv /* Text of each argument */ 59128b4e489Sdrh ){ 59228b4e489Sdrh assert( interp==0 ); /* This will always fail */ 59328b4e489Sdrh return TCL_OK; 59428b4e489Sdrh } 59528b4e489Sdrh 59628b4e489Sdrh /* 5976cbe1f1bSdrh ** The following routine is a user-defined SQL function whose purpose 5986cbe1f1bSdrh ** is to test the sqlite_set_result() API. 5996cbe1f1bSdrh */ 6006cbe1f1bSdrh static void testFunc(sqlite_func *context, int argc, const char **argv){ 6016cbe1f1bSdrh while( argc>=2 ){ 6026cbe1f1bSdrh if( argv[0]==0 ){ 6036cbe1f1bSdrh sqlite_set_result_error(context, "first argument to test function " 6046cbe1f1bSdrh "may not be NULL", -1); 6056cbe1f1bSdrh }else if( sqliteStrICmp(argv[0],"string")==0 ){ 6066cbe1f1bSdrh sqlite_set_result_string(context, argv[1], -1); 6076cbe1f1bSdrh }else if( argv[1]==0 ){ 6086cbe1f1bSdrh sqlite_set_result_error(context, "2nd argument may not be NULL if the " 6096cbe1f1bSdrh "first argument is not \"string\"", -1); 6106cbe1f1bSdrh }else if( sqliteStrICmp(argv[0],"int")==0 ){ 6116cbe1f1bSdrh sqlite_set_result_int(context, atoi(argv[1])); 6126cbe1f1bSdrh }else if( sqliteStrICmp(argv[0],"double")==0 ){ 61393a5c6bdSdrh sqlite_set_result_double(context, sqliteAtoF(argv[1])); 6146cbe1f1bSdrh }else{ 6156cbe1f1bSdrh sqlite_set_result_error(context,"first argument should be one of: " 6166cbe1f1bSdrh "string int double", -1); 6176cbe1f1bSdrh } 6186cbe1f1bSdrh argc -= 2; 6196cbe1f1bSdrh argv += 2; 6206cbe1f1bSdrh } 6216cbe1f1bSdrh } 6226cbe1f1bSdrh 6236cbe1f1bSdrh /* 6246cbe1f1bSdrh ** Usage: sqlite_register_test_function DB NAME 6256cbe1f1bSdrh ** 6266cbe1f1bSdrh ** Register the test SQL function on the database DB under the name NAME. 6276cbe1f1bSdrh */ 628c2eef3b3Sdrh static int test_register_func( 6296cbe1f1bSdrh void *NotUsed, 6306cbe1f1bSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 6316cbe1f1bSdrh int argc, /* Number of arguments */ 6326cbe1f1bSdrh char **argv /* Text of each argument */ 6336cbe1f1bSdrh ){ 6346cbe1f1bSdrh sqlite *db; 6356cbe1f1bSdrh int rc; 6366cbe1f1bSdrh if( argc!=3 ){ 6376cbe1f1bSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 6386cbe1f1bSdrh " DB FUNCTION-NAME", 0); 6396cbe1f1bSdrh return TCL_ERROR; 6406cbe1f1bSdrh } 641b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 6426cbe1f1bSdrh rc = sqlite_create_function(db, argv[2], -1, testFunc, 0); 6436cbe1f1bSdrh if( rc!=0 ){ 6446cbe1f1bSdrh Tcl_AppendResult(interp, sqlite_error_string(rc), 0); 6456cbe1f1bSdrh return TCL_ERROR; 6466cbe1f1bSdrh } 6476cbe1f1bSdrh return TCL_OK; 6486cbe1f1bSdrh } 6496cbe1f1bSdrh 6506cbe1f1bSdrh /* 6515a38705eSdrh ** This SQLite callback records the datatype of all columns. 6525a38705eSdrh ** 6535a38705eSdrh ** The pArg argument is really a pointer to a TCL interpreter. The 6545a38705eSdrh ** column names are inserted as the result of this interpreter. 6555a38705eSdrh ** 6565a38705eSdrh ** This routine returns non-zero which causes the query to abort. 6575a38705eSdrh */ 6585a38705eSdrh static int rememberDataTypes(void *pArg, int nCol, char **argv, char **colv){ 6595a38705eSdrh int i; 6605a38705eSdrh Tcl_Interp *interp = (Tcl_Interp*)pArg; 6615a38705eSdrh Tcl_Obj *pList, *pElem; 6625a38705eSdrh if( colv[nCol+1]==0 ){ 6635a38705eSdrh return 1; 6645a38705eSdrh } 6655a38705eSdrh pList = Tcl_NewObj(); 6665a38705eSdrh for(i=0; i<nCol; i++){ 6675a38705eSdrh pElem = Tcl_NewStringObj(colv[i+nCol] ? colv[i+nCol] : "NULL", -1); 6685a38705eSdrh Tcl_ListObjAppendElement(interp, pList, pElem); 6695a38705eSdrh } 6705a38705eSdrh Tcl_SetObjResult(interp, pList); 6715a38705eSdrh return 1; 6725a38705eSdrh } 6735a38705eSdrh 6745a38705eSdrh /* 6755a38705eSdrh ** Invoke an SQL statement but ignore all the data in the result. Instead, 6765a38705eSdrh ** return a list that consists of the datatypes of the various columns. 6775a38705eSdrh ** 6785a38705eSdrh ** This only works if "PRAGMA show_datatypes=on" has been executed against 6795a38705eSdrh ** the database connection. 6805a38705eSdrh */ 6815a38705eSdrh static int sqlite_datatypes( 6825a38705eSdrh void *NotUsed, 6835a38705eSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 6845a38705eSdrh int argc, /* Number of arguments */ 6855a38705eSdrh char **argv /* Text of each argument */ 6865a38705eSdrh ){ 6875a38705eSdrh sqlite *db; 6885a38705eSdrh int rc; 6895a38705eSdrh if( argc!=3 ){ 6905a38705eSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 6915a38705eSdrh " DB SQL", 0); 6925a38705eSdrh return TCL_ERROR; 6935a38705eSdrh } 694b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 6955a38705eSdrh rc = sqlite_exec(db, argv[2], rememberDataTypes, interp, 0); 6965a38705eSdrh if( rc!=0 && rc!=SQLITE_ABORT ){ 6975a38705eSdrh Tcl_AppendResult(interp, sqlite_error_string(rc), 0); 6985a38705eSdrh return TCL_ERROR; 6995a38705eSdrh } 7005a38705eSdrh return TCL_OK; 7015a38705eSdrh } 7025a38705eSdrh 703b86ccfb2Sdrh /* 704073e5a77Sdrh ** Usage: sqlite_compile DB SQL ?TAILVAR? 705b86ccfb2Sdrh ** 706b86ccfb2Sdrh ** Attempt to compile an SQL statement. Return a pointer to the virtual 707b86ccfb2Sdrh ** machine used to execute that statement. Unprocessed SQL is written 708b86ccfb2Sdrh ** into TAILVAR. 709b86ccfb2Sdrh */ 710b86ccfb2Sdrh static int test_compile( 711b86ccfb2Sdrh void *NotUsed, 712b86ccfb2Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 713b86ccfb2Sdrh int argc, /* Number of arguments */ 714b86ccfb2Sdrh char **argv /* Text of each argument */ 715b86ccfb2Sdrh ){ 716b86ccfb2Sdrh sqlite *db; 717b86ccfb2Sdrh sqlite_vm *vm; 718b86ccfb2Sdrh int rc; 719b86ccfb2Sdrh char *zErr = 0; 720b86ccfb2Sdrh const char *zTail; 721b86ccfb2Sdrh char zBuf[50]; 722073e5a77Sdrh if( argc!=3 && argc!=4 ){ 723b86ccfb2Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 724b86ccfb2Sdrh " DB SQL TAILVAR", 0); 725b86ccfb2Sdrh return TCL_ERROR; 726b86ccfb2Sdrh } 727b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 728073e5a77Sdrh rc = sqlite_compile(db, argv[2], argc==4 ? &zTail : 0, &vm, &zErr); 729073e5a77Sdrh if( argc==4 ) Tcl_SetVar(interp, argv[3], zTail, 0); 730b86ccfb2Sdrh if( rc ){ 731b86ccfb2Sdrh assert( vm==0 ); 732b86ccfb2Sdrh sprintf(zBuf, "(%d) ", rc); 733b86ccfb2Sdrh Tcl_AppendResult(interp, zBuf, zErr, 0); 734b86ccfb2Sdrh sqlite_freemem(zErr); 735b86ccfb2Sdrh return TCL_ERROR; 736b86ccfb2Sdrh } 737326dce74Sdrh if( vm ){ 7387d8085a8Sdrh if( makePointerStr(interp, zBuf, vm) ) return TCL_ERROR; 739b86ccfb2Sdrh Tcl_AppendResult(interp, zBuf, 0); 740326dce74Sdrh } 741b86ccfb2Sdrh return TCL_OK; 742b86ccfb2Sdrh } 743b86ccfb2Sdrh 744b86ccfb2Sdrh /* 745073e5a77Sdrh ** Usage: sqlite_step VM ?NVAR? ?VALUEVAR? ?COLNAMEVAR? 746b86ccfb2Sdrh ** 747b86ccfb2Sdrh ** Step a virtual machine. Return a the result code as a string. 748b86ccfb2Sdrh ** Column results are written into three variables. 749b86ccfb2Sdrh */ 750b86ccfb2Sdrh static int test_step( 751b86ccfb2Sdrh void *NotUsed, 752b86ccfb2Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 753b86ccfb2Sdrh int argc, /* Number of arguments */ 754b86ccfb2Sdrh char **argv /* Text of each argument */ 755b86ccfb2Sdrh ){ 756b86ccfb2Sdrh sqlite_vm *vm; 757b86ccfb2Sdrh int rc, i; 7583a84069dSdrh const char **azValue = 0; 7593a84069dSdrh const char **azColName = 0; 7603a84069dSdrh int N = 0; 761b86ccfb2Sdrh char *zRc; 762b86ccfb2Sdrh char zBuf[50]; 763073e5a77Sdrh if( argc<2 || argc>5 ){ 764b86ccfb2Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 765b86ccfb2Sdrh " VM NVAR VALUEVAR COLNAMEVAR", 0); 766b86ccfb2Sdrh return TCL_ERROR; 767b86ccfb2Sdrh } 768b86ccfb2Sdrh if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR; 769073e5a77Sdrh rc = sqlite_step(vm, argc>=3?&N:0, argc>=4?&azValue:0, argc==5?&azColName:0); 770073e5a77Sdrh if( argc>=3 ){ 771b86ccfb2Sdrh sprintf(zBuf, "%d", N); 772b86ccfb2Sdrh Tcl_SetVar(interp, argv[2], zBuf, 0); 773073e5a77Sdrh } 774073e5a77Sdrh if( argc>=4 ){ 775b86ccfb2Sdrh Tcl_SetVar(interp, argv[3], "", 0); 7763a84069dSdrh if( azValue ){ 777b86ccfb2Sdrh for(i=0; i<N; i++){ 778b86ccfb2Sdrh Tcl_SetVar(interp, argv[3], azValue[i] ? azValue[i] : "", 779b86ccfb2Sdrh TCL_APPEND_VALUE | TCL_LIST_ELEMENT); 780b86ccfb2Sdrh } 781b86ccfb2Sdrh } 782073e5a77Sdrh } 783073e5a77Sdrh if( argc==5 ){ 784b86ccfb2Sdrh Tcl_SetVar(interp, argv[4], "", 0); 7853a84069dSdrh if( azColName ){ 786b86ccfb2Sdrh for(i=0; i<N*2; i++){ 787326dce74Sdrh Tcl_SetVar(interp, argv[4], azColName[i] ? azColName[i] : "", 788b86ccfb2Sdrh TCL_APPEND_VALUE | TCL_LIST_ELEMENT); 789b86ccfb2Sdrh } 790b86ccfb2Sdrh } 791073e5a77Sdrh } 792b86ccfb2Sdrh switch( rc ){ 793b86ccfb2Sdrh case SQLITE_DONE: zRc = "SQLITE_DONE"; break; 794326dce74Sdrh case SQLITE_BUSY: zRc = "SQLITE_BUSY"; break; 795326dce74Sdrh case SQLITE_ROW: zRc = "SQLITE_ROW"; break; 796326dce74Sdrh case SQLITE_ERROR: zRc = "SQLITE_ERROR"; break; 797b86ccfb2Sdrh case SQLITE_MISUSE: zRc = "SQLITE_MISUSE"; break; 798b86ccfb2Sdrh default: zRc = "unknown"; break; 799b86ccfb2Sdrh } 800b86ccfb2Sdrh Tcl_AppendResult(interp, zRc, 0); 801b86ccfb2Sdrh return TCL_OK; 802b86ccfb2Sdrh } 803b86ccfb2Sdrh 804b86ccfb2Sdrh /* 805b86ccfb2Sdrh ** Usage: sqlite_finalize VM 806b86ccfb2Sdrh ** 807b86ccfb2Sdrh ** Shutdown a virtual machine. 808b86ccfb2Sdrh */ 809b86ccfb2Sdrh static int test_finalize( 810b86ccfb2Sdrh void *NotUsed, 811b86ccfb2Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 812b86ccfb2Sdrh int argc, /* Number of arguments */ 813b86ccfb2Sdrh char **argv /* Text of each argument */ 814b86ccfb2Sdrh ){ 815b86ccfb2Sdrh sqlite_vm *vm; 816b86ccfb2Sdrh int rc; 817b86ccfb2Sdrh char *zErrMsg = 0; 818b86ccfb2Sdrh if( argc!=2 ){ 819b86ccfb2Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 820326dce74Sdrh " VM\"", 0); 821b86ccfb2Sdrh return TCL_ERROR; 822b86ccfb2Sdrh } 823b86ccfb2Sdrh if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR; 824b86ccfb2Sdrh rc = sqlite_finalize(vm, &zErrMsg); 825b86ccfb2Sdrh if( rc ){ 826b86ccfb2Sdrh char zBuf[50]; 827b86ccfb2Sdrh sprintf(zBuf, "(%d) ", rc); 828b86ccfb2Sdrh Tcl_AppendResult(interp, zBuf, zErrMsg, 0); 829b86ccfb2Sdrh sqlite_freemem(zErrMsg); 830b86ccfb2Sdrh return TCL_ERROR; 831b86ccfb2Sdrh } 832b86ccfb2Sdrh return TCL_OK; 833b86ccfb2Sdrh } 834b86ccfb2Sdrh 8355a38705eSdrh /* 83650457896Sdrh ** Usage: sqlite_reset VM 83750457896Sdrh ** 83850457896Sdrh ** Reset a virtual machine and prepare it to be run again. 83950457896Sdrh */ 84050457896Sdrh static int test_reset( 84150457896Sdrh void *NotUsed, 84250457896Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 84350457896Sdrh int argc, /* Number of arguments */ 84450457896Sdrh char **argv /* Text of each argument */ 84550457896Sdrh ){ 84650457896Sdrh sqlite_vm *vm; 84750457896Sdrh int rc; 84850457896Sdrh char *zErrMsg = 0; 84950457896Sdrh if( argc!=2 ){ 85050457896Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 85150457896Sdrh " VM\"", 0); 85250457896Sdrh return TCL_ERROR; 85350457896Sdrh } 85450457896Sdrh if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR; 85550457896Sdrh rc = sqlite_reset(vm, &zErrMsg); 85650457896Sdrh if( rc ){ 85750457896Sdrh char zBuf[50]; 85850457896Sdrh sprintf(zBuf, "(%d) ", rc); 85950457896Sdrh Tcl_AppendResult(interp, zBuf, zErrMsg, 0); 86050457896Sdrh sqlite_freemem(zErrMsg); 86150457896Sdrh return TCL_ERROR; 86250457896Sdrh } 86350457896Sdrh return TCL_OK; 86450457896Sdrh } 86550457896Sdrh 86650457896Sdrh /* 8677c972decSdrh ** This is the "static_bind_value" that variables are bound to when 8687c972decSdrh ** the FLAG option of sqlite_bind is "static" 86950457896Sdrh */ 8707c972decSdrh static char *sqlite_static_bind_value = 0; 8717c972decSdrh 8727c972decSdrh /* 8737c972decSdrh ** Usage: sqlite_bind VM IDX VALUE FLAGS 8747c972decSdrh ** 8757c972decSdrh ** Sets the value of the IDX-th occurance of "?" in the original SQL 8767c972decSdrh ** string. VALUE is the new value. If FLAGS=="null" then VALUE is 8777c972decSdrh ** ignored and the value is set to NULL. If FLAGS=="static" then 8787c972decSdrh ** the value is set to the value of a static variable named 8797c972decSdrh ** "sqlite_static_bind_value". If FLAGS=="normal" then a copy 8807c972decSdrh ** of the VALUE is made. 8817c972decSdrh */ 8827c972decSdrh static int test_bind( 88350457896Sdrh void *NotUsed, 88450457896Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 88550457896Sdrh int argc, /* Number of arguments */ 88650457896Sdrh char **argv /* Text of each argument */ 88750457896Sdrh ){ 88850457896Sdrh sqlite_vm *vm; 88950457896Sdrh int rc; 8907c972decSdrh int idx; 8917c972decSdrh if( argc!=5 ){ 89250457896Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 8937c972decSdrh " VM IDX VALUE (null|static|normal)\"", 0); 89450457896Sdrh return TCL_ERROR; 89550457896Sdrh } 89650457896Sdrh if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR; 8977c972decSdrh if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR; 8987c972decSdrh if( strcmp(argv[4],"null")==0 ){ 8997c972decSdrh rc = sqlite_bind(vm, idx, 0, 0, 0); 9007c972decSdrh }else if( strcmp(argv[4],"static")==0 ){ 9017c972decSdrh rc = sqlite_bind(vm, idx, sqlite_static_bind_value, -1, 0); 9027c972decSdrh }else if( strcmp(argv[4],"normal")==0 ){ 9037c972decSdrh rc = sqlite_bind(vm, idx, argv[3], -1, 1); 9047c972decSdrh }else{ 9057c972decSdrh Tcl_AppendResult(interp, "4th argument should be " 9067c972decSdrh "\"null\" or \"static\" or \"normal\"", 0); 9077c972decSdrh return TCL_ERROR; 9087c972decSdrh } 90950457896Sdrh if( rc ){ 91050457896Sdrh char zBuf[50]; 91150457896Sdrh sprintf(zBuf, "(%d) ", rc); 91250457896Sdrh Tcl_AppendResult(interp, zBuf, sqlite_error_string(rc), 0); 91350457896Sdrh return TCL_ERROR; 91450457896Sdrh } 91550457896Sdrh return TCL_OK; 91650457896Sdrh } 91750457896Sdrh 91850457896Sdrh /* 91999ee3600Sdrh ** Usage: breakpoint 92099ee3600Sdrh ** 92199ee3600Sdrh ** This routine exists for one purpose - to provide a place to put a 92299ee3600Sdrh ** breakpoint with GDB that can be triggered using TCL code. The use 92399ee3600Sdrh ** for this is when a particular test fails on (say) the 1485th iteration. 92499ee3600Sdrh ** In the TCL test script, we can add code like this: 92599ee3600Sdrh ** 92699ee3600Sdrh ** if {$i==1485} breakpoint 92799ee3600Sdrh ** 92899ee3600Sdrh ** Then run testfixture in the debugger and wait for the breakpoint to 92999ee3600Sdrh ** fire. Then additional breakpoints can be set to trace down the bug. 93099ee3600Sdrh */ 93199ee3600Sdrh static int test_breakpoint( 93299ee3600Sdrh void *NotUsed, 93399ee3600Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 93499ee3600Sdrh int argc, /* Number of arguments */ 93599ee3600Sdrh char **argv /* Text of each argument */ 93699ee3600Sdrh ){ 93799ee3600Sdrh return TCL_OK; /* Do nothing */ 93899ee3600Sdrh } 93999ee3600Sdrh 94099ee3600Sdrh /* 941d1bf3512Sdrh ** Register commands with the TCL interpreter. 942d1bf3512Sdrh */ 943d1bf3512Sdrh int Sqlitetest1_Init(Tcl_Interp *interp){ 944487ab3caSdrh extern int sqlite_search_count; 945f6038713Sdrh extern int sqlite_interrupt_count; 94694e92032Sdrh extern int sqlite_open_file_count; 947e807febbSdrh extern int sqlite_current_time; 948c2eef3b3Sdrh static struct { 949c2eef3b3Sdrh char *zName; 950c2eef3b3Sdrh Tcl_CmdProc *xProc; 951c2eef3b3Sdrh } aCmd[] = { 952c2eef3b3Sdrh { "sqlite_mprintf_int", (Tcl_CmdProc*)sqlite_mprintf_int }, 953c2eef3b3Sdrh { "sqlite_mprintf_str", (Tcl_CmdProc*)sqlite_mprintf_str }, 954c2eef3b3Sdrh { "sqlite_mprintf_double", (Tcl_CmdProc*)sqlite_mprintf_double }, 955d93d8a81Sdrh { "sqlite_mprintf_z_test", (Tcl_CmdProc*)test_mprintf_z }, 956c2eef3b3Sdrh { "sqlite_open", (Tcl_CmdProc*)sqlite_test_open }, 957c2eef3b3Sdrh { "sqlite_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid }, 958c2eef3b3Sdrh { "sqlite_exec_printf", (Tcl_CmdProc*)test_exec_printf }, 959c2eef3b3Sdrh { "sqlite_get_table_printf", (Tcl_CmdProc*)test_get_table_printf }, 960c2eef3b3Sdrh { "sqlite_close", (Tcl_CmdProc*)sqlite_test_close }, 961c2eef3b3Sdrh { "sqlite_create_function", (Tcl_CmdProc*)test_create_function }, 962c2eef3b3Sdrh { "sqlite_create_aggregate", (Tcl_CmdProc*)test_create_aggregate }, 963c2eef3b3Sdrh { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func }, 964c2eef3b3Sdrh { "sqlite_abort", (Tcl_CmdProc*)sqlite_abort }, 9655a38705eSdrh { "sqlite_datatypes", (Tcl_CmdProc*)sqlite_datatypes }, 966c2eef3b3Sdrh #ifdef MEMORY_DEBUG 967c2eef3b3Sdrh { "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail }, 968c2eef3b3Sdrh { "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat }, 969c2eef3b3Sdrh #endif 970b86ccfb2Sdrh { "sqlite_compile", (Tcl_CmdProc*)test_compile }, 971b86ccfb2Sdrh { "sqlite_step", (Tcl_CmdProc*)test_step }, 972b86ccfb2Sdrh { "sqlite_finalize", (Tcl_CmdProc*)test_finalize }, 9737c972decSdrh { "sqlite_bind", (Tcl_CmdProc*)test_bind }, 97450457896Sdrh { "sqlite_reset", (Tcl_CmdProc*)test_reset }, 97599ee3600Sdrh { "breakpoint", (Tcl_CmdProc*)test_breakpoint }, 976c2eef3b3Sdrh }; 977c2eef3b3Sdrh int i; 978c2eef3b3Sdrh 979c2eef3b3Sdrh for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ 980c2eef3b3Sdrh Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); 981c2eef3b3Sdrh } 982487ab3caSdrh Tcl_LinkVar(interp, "sqlite_search_count", 983487ab3caSdrh (char*)&sqlite_search_count, TCL_LINK_INT); 984f6038713Sdrh Tcl_LinkVar(interp, "sqlite_interrupt_count", 985f6038713Sdrh (char*)&sqlite_interrupt_count, TCL_LINK_INT); 98694e92032Sdrh Tcl_LinkVar(interp, "sqlite_open_file_count", 98794e92032Sdrh (char*)&sqlite_open_file_count, TCL_LINK_INT); 988e807febbSdrh Tcl_LinkVar(interp, "sqlite_current_time", 989e807febbSdrh (char*)&sqlite_current_time, TCL_LINK_INT); 9907c972decSdrh Tcl_LinkVar(interp, "sqlite_static_bind_value", 9917c972decSdrh (char*)&sqlite_static_bind_value, TCL_LINK_STRING); 992d1bf3512Sdrh return TCL_OK; 993d1bf3512Sdrh } 994