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*073e5a77Sdrh ** $Id: test1.c,v 1.26 2003/07/09 00:28:15 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 */ 33b86ccfb2Sdrh static int getDbPointer(Tcl_Interp *interp, const char *zArg, sqlite **ppDb){ 3494e92032Sdrh if( sscanf(zArg, PTR_FMT, (void**)ppDb)!=1 ){ 35b86ccfb2Sdrh Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0); 36b86ccfb2Sdrh return TCL_ERROR; 37b86ccfb2Sdrh } 38b86ccfb2Sdrh return TCL_OK; 39b86ccfb2Sdrh } 40b86ccfb2Sdrh 41b86ccfb2Sdrh /* 42b86ccfb2Sdrh ** Decode a pointer to an sqlite_vm object. 43b86ccfb2Sdrh */ 44b86ccfb2Sdrh static int getVmPointer(Tcl_Interp *interp, const char *zArg, sqlite_vm **ppVm){ 4594e92032Sdrh if( sscanf(zArg, PTR_FMT, (void**)ppVm)!=1 ){ 46b86ccfb2Sdrh Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0); 47b86ccfb2Sdrh return TCL_ERROR; 48b86ccfb2Sdrh } 49b86ccfb2Sdrh return TCL_OK; 50b86ccfb2Sdrh } 51b86ccfb2Sdrh 52b86ccfb2Sdrh /* 537d8085a8Sdrh ** Generate a text representation of a pointer that can be understood 547d8085a8Sdrh ** by the getDbPointer and getVmPointer routines above. 557d8085a8Sdrh ** 567d8085a8Sdrh ** The problem is, on some machines (Solaris) if you do a printf with 577d8085a8Sdrh ** "%p" you cannot turn around and do a scanf with the same "%p" and 587d8085a8Sdrh ** get your pointer back. You have to prepend a "0x" before it will 597d8085a8Sdrh ** work. Or at least that is what is reported to me (drh). But this 607d8085a8Sdrh ** behavior varies from machine to machine. The solution used her is 617d8085a8Sdrh ** to test the string right after it is generated to see if it can be 627d8085a8Sdrh ** understood by scanf, and if not, try prepending an "0x" to see if 637d8085a8Sdrh ** that helps. If nothing works, a fatal error is generated. 647d8085a8Sdrh */ 657d8085a8Sdrh static int makePointerStr(Tcl_Interp *interp, char *zPtr, void *p){ 667d8085a8Sdrh void *p2; 677d8085a8Sdrh sprintf(zPtr, PTR_FMT, p); 687d8085a8Sdrh if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){ 697d8085a8Sdrh sprintf(zPtr, "0x" PTR_FMT, p); 707d8085a8Sdrh if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){ 717d8085a8Sdrh Tcl_AppendResult(interp, "unable to convert a pointer to a string " 727d8085a8Sdrh "in the file " __FILE__ " in function makePointerStr(). Please " 737d8085a8Sdrh "report this problem to the SQLite mailing list or as a new but " 747d8085a8Sdrh "report. Please provide detailed information about how you compiled " 757d8085a8Sdrh "SQLite and what computer you are running on.", 0); 767d8085a8Sdrh return TCL_ERROR; 777d8085a8Sdrh } 787d8085a8Sdrh } 797d8085a8Sdrh return TCL_OK; 807d8085a8Sdrh } 817d8085a8Sdrh 827d8085a8Sdrh /* 83d1bf3512Sdrh ** Usage: sqlite_open filename 84d1bf3512Sdrh ** 85d1bf3512Sdrh ** Returns: The name of an open database. 86d1bf3512Sdrh */ 87d1bf3512Sdrh static int sqlite_test_open( 88d1bf3512Sdrh void *NotUsed, 89d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 90d1bf3512Sdrh int argc, /* Number of arguments */ 91d1bf3512Sdrh char **argv /* Text of each argument */ 92d1bf3512Sdrh ){ 93d1bf3512Sdrh sqlite *db; 94d1bf3512Sdrh char *zErr = 0; 95d1bf3512Sdrh char zBuf[100]; 96d1bf3512Sdrh if( argc!=2 ){ 97d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 98d1bf3512Sdrh " FILENAME\"", 0); 99d1bf3512Sdrh return TCL_ERROR; 100d1bf3512Sdrh } 101d1bf3512Sdrh db = sqlite_open(argv[1], 0666, &zErr); 102d1bf3512Sdrh if( db==0 ){ 103d1bf3512Sdrh Tcl_AppendResult(interp, zErr, 0); 104d1bf3512Sdrh free(zErr); 105d1bf3512Sdrh return TCL_ERROR; 106d1bf3512Sdrh } 1077d8085a8Sdrh if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR; 108d1bf3512Sdrh Tcl_AppendResult(interp, zBuf, 0); 109d1bf3512Sdrh return TCL_OK; 110d1bf3512Sdrh } 111d1bf3512Sdrh 112d1bf3512Sdrh /* 113d1bf3512Sdrh ** The callback routine for sqlite_exec_printf(). 114d1bf3512Sdrh */ 115d1bf3512Sdrh static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){ 116d1bf3512Sdrh Tcl_DString *str = (Tcl_DString*)pArg; 117d1bf3512Sdrh int i; 118d1bf3512Sdrh 119d1bf3512Sdrh if( Tcl_DStringLength(str)==0 ){ 120d1bf3512Sdrh for(i=0; i<argc; i++){ 121d1bf3512Sdrh Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL"); 122d1bf3512Sdrh } 123d1bf3512Sdrh } 124d1bf3512Sdrh for(i=0; i<argc; i++){ 125d1bf3512Sdrh Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL"); 126d1bf3512Sdrh } 127d1bf3512Sdrh return 0; 128d1bf3512Sdrh } 129d1bf3512Sdrh 130d1bf3512Sdrh /* 131d1bf3512Sdrh ** Usage: sqlite_exec_printf DB FORMAT STRING 132d1bf3512Sdrh ** 133d1bf3512Sdrh ** Invoke the sqlite_exec_printf() interface using the open database 134d1bf3512Sdrh ** DB. The SQL is the string FORMAT. The format string should contain 135d1bf3512Sdrh ** one %s or %q. STRING is the value inserted into %s or %q. 136d1bf3512Sdrh */ 137d1bf3512Sdrh static int test_exec_printf( 138d1bf3512Sdrh void *NotUsed, 139d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 140d1bf3512Sdrh int argc, /* Number of arguments */ 141d1bf3512Sdrh char **argv /* Text of each argument */ 142d1bf3512Sdrh ){ 143d1bf3512Sdrh sqlite *db; 144d1bf3512Sdrh Tcl_DString str; 145d1bf3512Sdrh int rc; 146d1bf3512Sdrh char *zErr = 0; 147d1bf3512Sdrh char zBuf[30]; 148d1bf3512Sdrh if( argc!=4 ){ 149d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 150d1bf3512Sdrh " DB FORMAT STRING", 0); 151d1bf3512Sdrh return TCL_ERROR; 152d1bf3512Sdrh } 153b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 154d1bf3512Sdrh Tcl_DStringInit(&str); 155d1bf3512Sdrh rc = sqlite_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]); 156d1bf3512Sdrh sprintf(zBuf, "%d", rc); 157d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 158d1bf3512Sdrh Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr); 159d1bf3512Sdrh Tcl_DStringFree(&str); 160d1bf3512Sdrh if( zErr ) free(zErr); 161d1bf3512Sdrh return TCL_OK; 162d1bf3512Sdrh } 163d1bf3512Sdrh 164d1bf3512Sdrh /* 165d93d8a81Sdrh ** Usage: sqlite_mprintf_z_test SEPARATOR ARG0 ARG1 ... 166d93d8a81Sdrh ** 167d93d8a81Sdrh ** Test the %z format of mprintf(). Use multiple mprintf() calls to 168d93d8a81Sdrh ** concatenate arg0 through argn using separator as the separator. 169d93d8a81Sdrh ** Return the result. 170d93d8a81Sdrh */ 171d93d8a81Sdrh static int test_mprintf_z( 172d93d8a81Sdrh void *NotUsed, 173d93d8a81Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 174d93d8a81Sdrh int argc, /* Number of arguments */ 175d93d8a81Sdrh char **argv /* Text of each argument */ 176d93d8a81Sdrh ){ 177d93d8a81Sdrh char *zResult = 0; 178d93d8a81Sdrh int i; 179d93d8a81Sdrh 180d93d8a81Sdrh for(i=2; i<argc; i++){ 181d93d8a81Sdrh zResult = sqlite_mprintf("%z%s%s", zResult, argv[1], argv[i]); 182d93d8a81Sdrh } 183d93d8a81Sdrh Tcl_AppendResult(interp, zResult, 0); 184d93d8a81Sdrh sqlite_freemem(zResult); 185d93d8a81Sdrh return TCL_OK; 186d93d8a81Sdrh } 187d93d8a81Sdrh 188d93d8a81Sdrh /* 189d1bf3512Sdrh ** Usage: sqlite_get_table_printf DB FORMAT STRING 190d1bf3512Sdrh ** 191d1bf3512Sdrh ** Invoke the sqlite_get_table_printf() interface using the open database 192d1bf3512Sdrh ** DB. The SQL is the string FORMAT. The format string should contain 193d1bf3512Sdrh ** one %s or %q. STRING is the value inserted into %s or %q. 194d1bf3512Sdrh */ 195d1bf3512Sdrh static int test_get_table_printf( 196d1bf3512Sdrh void *NotUsed, 197d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 198d1bf3512Sdrh int argc, /* Number of arguments */ 199d1bf3512Sdrh char **argv /* Text of each argument */ 200d1bf3512Sdrh ){ 201d1bf3512Sdrh sqlite *db; 202d1bf3512Sdrh Tcl_DString str; 203d1bf3512Sdrh int rc; 204d1bf3512Sdrh char *zErr = 0; 205d1bf3512Sdrh int nRow, nCol; 206d1bf3512Sdrh char **aResult; 207d1bf3512Sdrh int i; 208d1bf3512Sdrh char zBuf[30]; 209d1bf3512Sdrh if( argc!=4 ){ 210d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 211d1bf3512Sdrh " DB FORMAT STRING", 0); 212d1bf3512Sdrh return TCL_ERROR; 213d1bf3512Sdrh } 214b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 215d1bf3512Sdrh Tcl_DStringInit(&str); 216d1bf3512Sdrh rc = sqlite_get_table_printf(db, argv[2], &aResult, &nRow, &nCol, 217d1bf3512Sdrh &zErr, argv[3]); 218d1bf3512Sdrh sprintf(zBuf, "%d", rc); 219d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 220d1bf3512Sdrh if( rc==SQLITE_OK ){ 221d1bf3512Sdrh sprintf(zBuf, "%d", nRow); 222d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 223d1bf3512Sdrh sprintf(zBuf, "%d", nCol); 224d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 225d1bf3512Sdrh for(i=0; i<(nRow+1)*nCol; i++){ 226d1bf3512Sdrh Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL"); 227d1bf3512Sdrh } 228d1bf3512Sdrh }else{ 229d1bf3512Sdrh Tcl_AppendElement(interp, zErr); 230d1bf3512Sdrh } 231d1bf3512Sdrh sqlite_free_table(aResult); 232d1bf3512Sdrh if( zErr ) free(zErr); 233d1bf3512Sdrh return TCL_OK; 234d1bf3512Sdrh } 235d1bf3512Sdrh 236af9ff33aSdrh 237af9ff33aSdrh /* 238af9ff33aSdrh ** Usage: sqlite_last_insert_rowid DB 239af9ff33aSdrh ** 240af9ff33aSdrh ** Returns the integer ROWID of the most recent insert. 241af9ff33aSdrh */ 242af9ff33aSdrh static int test_last_rowid( 243af9ff33aSdrh void *NotUsed, 244af9ff33aSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 245af9ff33aSdrh int argc, /* Number of arguments */ 246af9ff33aSdrh char **argv /* Text of each argument */ 247af9ff33aSdrh ){ 248af9ff33aSdrh sqlite *db; 249af9ff33aSdrh char zBuf[30]; 250af9ff33aSdrh 251af9ff33aSdrh if( argc!=2 ){ 252af9ff33aSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0); 253af9ff33aSdrh return TCL_ERROR; 254af9ff33aSdrh } 255b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 256af9ff33aSdrh sprintf(zBuf, "%d", sqlite_last_insert_rowid(db)); 257af9ff33aSdrh Tcl_AppendResult(interp, zBuf, 0); 258af9ff33aSdrh return SQLITE_OK; 259af9ff33aSdrh } 260af9ff33aSdrh 261d1bf3512Sdrh /* 262d1bf3512Sdrh ** Usage: sqlite_close DB 263d1bf3512Sdrh ** 264d1bf3512Sdrh ** Closes the database opened by sqlite_open. 265d1bf3512Sdrh */ 266d1bf3512Sdrh static int sqlite_test_close( 267d1bf3512Sdrh void *NotUsed, 268d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 269d1bf3512Sdrh int argc, /* Number of arguments */ 270d1bf3512Sdrh char **argv /* Text of each argument */ 271d1bf3512Sdrh ){ 272d1bf3512Sdrh sqlite *db; 273d1bf3512Sdrh if( argc!=2 ){ 274d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 275d1bf3512Sdrh " FILENAME\"", 0); 276d1bf3512Sdrh return TCL_ERROR; 277d1bf3512Sdrh } 278b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 279d1bf3512Sdrh sqlite_close(db); 280d1bf3512Sdrh return TCL_OK; 281d1bf3512Sdrh } 282d1bf3512Sdrh 283d1bf3512Sdrh /* 284c22bd47dSdrh ** Implementation of the x_coalesce() function. 285c22bd47dSdrh ** Return the first argument non-NULL argument. 286c22bd47dSdrh */ 287c22bd47dSdrh static void ifnullFunc(sqlite_func *context, int argc, const char **argv){ 288c22bd47dSdrh int i; 289c22bd47dSdrh for(i=0; i<argc; i++){ 290c22bd47dSdrh if( argv[i] ){ 291c22bd47dSdrh sqlite_set_result_string(context, argv[i], -1); 292c22bd47dSdrh break; 293c22bd47dSdrh } 294c22bd47dSdrh } 295c22bd47dSdrh } 296c22bd47dSdrh 297c22bd47dSdrh /* 298c22bd47dSdrh ** Implementation of the x_sqlite_exec() function. This function takes 299c22bd47dSdrh ** a single argument and attempts to execute that argument as SQL code. 3006cbe1f1bSdrh ** This is illegal and should set the SQLITE_MISUSE flag on the database. 301c22bd47dSdrh ** 302c22bd47dSdrh ** This routine simulates the effect of having two threads attempt to 303c22bd47dSdrh ** use the same database at the same time. 304c22bd47dSdrh */ 305c22bd47dSdrh static void sqliteExecFunc(sqlite_func *context, int argc, const char **argv){ 306c22bd47dSdrh sqlite_exec((sqlite*)sqlite_user_data(context), argv[0], 0, 0, 0); 307c22bd47dSdrh } 308c22bd47dSdrh 309c22bd47dSdrh /* 310c22bd47dSdrh ** Usage: sqlite_test_create_function DB 311c22bd47dSdrh ** 312c22bd47dSdrh ** Call the sqlite_create_function API on the given database in order 313c22bd47dSdrh ** to create a function named "x_coalesce". This function does the same thing 314c22bd47dSdrh ** as the "coalesce" function. This function also registers an SQL function 315c22bd47dSdrh ** named "x_sqlite_exec" that invokes sqlite_exec(). Invoking sqlite_exec() 316c22bd47dSdrh ** in this way is illegal recursion and should raise an SQLITE_MISUSE error. 317c22bd47dSdrh ** The effect is similar to trying to use the same database connection from 318c22bd47dSdrh ** two threads at the same time. 319c22bd47dSdrh ** 320c22bd47dSdrh ** The original motivation for this routine was to be able to call the 321c22bd47dSdrh ** sqlite_create_function function while a query is in progress in order 322c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic. 323c22bd47dSdrh */ 324c2eef3b3Sdrh static int test_create_function( 325c22bd47dSdrh void *NotUsed, 326c22bd47dSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 327c22bd47dSdrh int argc, /* Number of arguments */ 328c22bd47dSdrh char **argv /* Text of each argument */ 329c22bd47dSdrh ){ 330c22bd47dSdrh sqlite *db; 331c22bd47dSdrh extern void Md5_Register(sqlite*); 332c22bd47dSdrh if( argc!=2 ){ 333c22bd47dSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 334c22bd47dSdrh " FILENAME\"", 0); 335c22bd47dSdrh return TCL_ERROR; 336c22bd47dSdrh } 337b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 338c22bd47dSdrh sqlite_create_function(db, "x_coalesce", -1, ifnullFunc, 0); 339c22bd47dSdrh sqlite_create_function(db, "x_sqlite_exec", 1, sqliteExecFunc, db); 340c22bd47dSdrh return TCL_OK; 341c22bd47dSdrh } 342c22bd47dSdrh 343c22bd47dSdrh /* 344c22bd47dSdrh ** Routines to implement the x_count() aggregate function. 345c22bd47dSdrh */ 346c22bd47dSdrh typedef struct CountCtx CountCtx; 347c22bd47dSdrh struct CountCtx { 348c22bd47dSdrh int n; 349c22bd47dSdrh }; 350c22bd47dSdrh static void countStep(sqlite_func *context, int argc, const char **argv){ 351c22bd47dSdrh CountCtx *p; 352c22bd47dSdrh p = sqlite_aggregate_context(context, sizeof(*p)); 353c22bd47dSdrh if( (argc==0 || argv[0]) && p ){ 354c22bd47dSdrh p->n++; 355c22bd47dSdrh } 356c22bd47dSdrh } 357c22bd47dSdrh static void countFinalize(sqlite_func *context){ 358c22bd47dSdrh CountCtx *p; 359c22bd47dSdrh p = sqlite_aggregate_context(context, sizeof(*p)); 360c22bd47dSdrh sqlite_set_result_int(context, p ? p->n : 0); 361c22bd47dSdrh } 362c22bd47dSdrh 363c22bd47dSdrh /* 364c22bd47dSdrh ** Usage: sqlite_test_create_aggregate DB 365c22bd47dSdrh ** 366c22bd47dSdrh ** Call the sqlite_create_function API on the given database in order 367c22bd47dSdrh ** to create a function named "x_count". This function does the same thing 368c22bd47dSdrh ** as the "md5sum" function. 369c22bd47dSdrh ** 370c22bd47dSdrh ** The original motivation for this routine was to be able to call the 371c22bd47dSdrh ** sqlite_create_aggregate function while a query is in progress in order 372c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic. 373c22bd47dSdrh */ 374c2eef3b3Sdrh static int test_create_aggregate( 375c22bd47dSdrh void *NotUsed, 376c22bd47dSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 377c22bd47dSdrh int argc, /* Number of arguments */ 378c22bd47dSdrh char **argv /* Text of each argument */ 379c22bd47dSdrh ){ 380c22bd47dSdrh sqlite *db; 381c22bd47dSdrh if( argc!=2 ){ 382c22bd47dSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 383c22bd47dSdrh " FILENAME\"", 0); 384c22bd47dSdrh return TCL_ERROR; 385c22bd47dSdrh } 386b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 387c22bd47dSdrh sqlite_create_aggregate(db, "x_count", 0, countStep, countFinalize, 0); 388c22bd47dSdrh sqlite_create_aggregate(db, "x_count", 1, countStep, countFinalize, 0); 389c22bd47dSdrh return TCL_OK; 390c22bd47dSdrh } 391c22bd47dSdrh 392c22bd47dSdrh 393c22bd47dSdrh 394c22bd47dSdrh /* 395d1bf3512Sdrh ** Usage: sqlite_mprintf_int FORMAT INTEGER INTEGER INTEGER 396d1bf3512Sdrh ** 397d1bf3512Sdrh ** Call mprintf with three integer arguments 398d1bf3512Sdrh */ 399d1bf3512Sdrh static int sqlite_mprintf_int( 400d1bf3512Sdrh void *NotUsed, 401d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 402d1bf3512Sdrh int argc, /* Number of arguments */ 403d1bf3512Sdrh char **argv /* Text of each argument */ 404d1bf3512Sdrh ){ 405d1bf3512Sdrh int a[3], i; 406d1bf3512Sdrh char *z; 407d1bf3512Sdrh if( argc!=5 ){ 408d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 409d1bf3512Sdrh " FORMAT INT INT INT\"", 0); 410d1bf3512Sdrh return TCL_ERROR; 411d1bf3512Sdrh } 412d1bf3512Sdrh for(i=2; i<5; i++){ 413d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 414d1bf3512Sdrh } 415d1bf3512Sdrh z = sqlite_mprintf(argv[1], a[0], a[1], a[2]); 416d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 417fa173a76Sdrh sqlite_freemem(z); 418d1bf3512Sdrh return TCL_OK; 419d1bf3512Sdrh } 420d1bf3512Sdrh 421d1bf3512Sdrh /* 422d1bf3512Sdrh ** Usage: sqlite_mprintf_str FORMAT INTEGER INTEGER STRING 423d1bf3512Sdrh ** 424d1bf3512Sdrh ** Call mprintf with two integer arguments and one string argument 425d1bf3512Sdrh */ 426d1bf3512Sdrh static int sqlite_mprintf_str( 427d1bf3512Sdrh void *NotUsed, 428d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 429d1bf3512Sdrh int argc, /* Number of arguments */ 430d1bf3512Sdrh char **argv /* Text of each argument */ 431d1bf3512Sdrh ){ 432d1bf3512Sdrh int a[3], i; 433d1bf3512Sdrh char *z; 434f220b24fSchw if( argc<4 || argc>5 ){ 435d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 436f220b24fSchw " FORMAT INT INT ?STRING?\"", 0); 437d1bf3512Sdrh return TCL_ERROR; 438d1bf3512Sdrh } 439d1bf3512Sdrh for(i=2; i<4; i++){ 440d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 441d1bf3512Sdrh } 442f220b24fSchw z = sqlite_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL); 443d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 444fa173a76Sdrh sqlite_freemem(z); 445d1bf3512Sdrh return TCL_OK; 446d1bf3512Sdrh } 447d1bf3512Sdrh 448d1bf3512Sdrh /* 449d1bf3512Sdrh ** Usage: sqlite_mprintf_str FORMAT INTEGER INTEGER DOUBLE 450d1bf3512Sdrh ** 451d1bf3512Sdrh ** Call mprintf with two integer arguments and one double argument 452d1bf3512Sdrh */ 453d1bf3512Sdrh static int sqlite_mprintf_double( 454d1bf3512Sdrh void *NotUsed, 455d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 456d1bf3512Sdrh int argc, /* Number of arguments */ 457d1bf3512Sdrh char **argv /* Text of each argument */ 458d1bf3512Sdrh ){ 459d1bf3512Sdrh int a[3], i; 460d1bf3512Sdrh double r; 461d1bf3512Sdrh char *z; 462d1bf3512Sdrh if( argc!=5 ){ 463d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 464d1bf3512Sdrh " FORMAT INT INT STRING\"", 0); 465d1bf3512Sdrh return TCL_ERROR; 466d1bf3512Sdrh } 467d1bf3512Sdrh for(i=2; i<4; i++){ 468d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 469d1bf3512Sdrh } 470d1bf3512Sdrh if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR; 471d1bf3512Sdrh z = sqlite_mprintf(argv[1], a[0], a[1], r); 472d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 473fa173a76Sdrh sqlite_freemem(z); 474d1bf3512Sdrh return TCL_OK; 475d1bf3512Sdrh } 476d1bf3512Sdrh 477d1bf3512Sdrh /* 478daffd0e5Sdrh ** Usage: sqlite_malloc_fail N 479daffd0e5Sdrh ** 480afa4a020Sdrh ** Rig sqliteMalloc() to fail on the N-th call. Turn off this mechanism 481daffd0e5Sdrh ** and reset the sqlite_malloc_failed variable is N==0. 482daffd0e5Sdrh */ 483daffd0e5Sdrh #ifdef MEMORY_DEBUG 484daffd0e5Sdrh static int sqlite_malloc_fail( 485daffd0e5Sdrh void *NotUsed, 486daffd0e5Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 487daffd0e5Sdrh int argc, /* Number of arguments */ 488daffd0e5Sdrh char **argv /* Text of each argument */ 489daffd0e5Sdrh ){ 490daffd0e5Sdrh int n; 491daffd0e5Sdrh if( argc!=2 ){ 492daffd0e5Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0); 493daffd0e5Sdrh return TCL_ERROR; 494daffd0e5Sdrh } 495daffd0e5Sdrh if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR; 496daffd0e5Sdrh sqlite_iMallocFail = n; 497daffd0e5Sdrh sqlite_malloc_failed = 0; 498daffd0e5Sdrh return TCL_OK; 499daffd0e5Sdrh } 500daffd0e5Sdrh #endif 501daffd0e5Sdrh 502daffd0e5Sdrh /* 503daffd0e5Sdrh ** Usage: sqlite_malloc_stat 504daffd0e5Sdrh ** 505daffd0e5Sdrh ** Return the number of prior calls to sqliteMalloc() and sqliteFree(). 506daffd0e5Sdrh */ 507daffd0e5Sdrh #ifdef MEMORY_DEBUG 508daffd0e5Sdrh static int sqlite_malloc_stat( 509daffd0e5Sdrh void *NotUsed, 510daffd0e5Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 511daffd0e5Sdrh int argc, /* Number of arguments */ 512daffd0e5Sdrh char **argv /* Text of each argument */ 513daffd0e5Sdrh ){ 514daffd0e5Sdrh char zBuf[200]; 515daffd0e5Sdrh sprintf(zBuf, "%d %d %d", sqlite_nMalloc, sqlite_nFree, sqlite_iMallocFail); 516daffd0e5Sdrh Tcl_AppendResult(interp, zBuf, 0); 517daffd0e5Sdrh return TCL_OK; 518daffd0e5Sdrh } 519daffd0e5Sdrh #endif 520daffd0e5Sdrh 521daffd0e5Sdrh /* 52228b4e489Sdrh ** Usage: sqlite_abort 52328b4e489Sdrh ** 52428b4e489Sdrh ** Shutdown the process immediately. This is not a clean shutdown. 52528b4e489Sdrh ** This command is used to test the recoverability of a database in 52628b4e489Sdrh ** the event of a program crash. 52728b4e489Sdrh */ 52828b4e489Sdrh static int sqlite_abort( 52928b4e489Sdrh void *NotUsed, 53028b4e489Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 53128b4e489Sdrh int argc, /* Number of arguments */ 53228b4e489Sdrh char **argv /* Text of each argument */ 53328b4e489Sdrh ){ 53428b4e489Sdrh assert( interp==0 ); /* This will always fail */ 53528b4e489Sdrh return TCL_OK; 53628b4e489Sdrh } 53728b4e489Sdrh 53828b4e489Sdrh /* 5396cbe1f1bSdrh ** The following routine is a user-defined SQL function whose purpose 5406cbe1f1bSdrh ** is to test the sqlite_set_result() API. 5416cbe1f1bSdrh */ 5426cbe1f1bSdrh static void testFunc(sqlite_func *context, int argc, const char **argv){ 5436cbe1f1bSdrh while( argc>=2 ){ 5446cbe1f1bSdrh if( argv[0]==0 ){ 5456cbe1f1bSdrh sqlite_set_result_error(context, "first argument to test function " 5466cbe1f1bSdrh "may not be NULL", -1); 5476cbe1f1bSdrh }else if( sqliteStrICmp(argv[0],"string")==0 ){ 5486cbe1f1bSdrh sqlite_set_result_string(context, argv[1], -1); 5496cbe1f1bSdrh }else if( argv[1]==0 ){ 5506cbe1f1bSdrh sqlite_set_result_error(context, "2nd argument may not be NULL if the " 5516cbe1f1bSdrh "first argument is not \"string\"", -1); 5526cbe1f1bSdrh }else if( sqliteStrICmp(argv[0],"int")==0 ){ 5536cbe1f1bSdrh sqlite_set_result_int(context, atoi(argv[1])); 5546cbe1f1bSdrh }else if( sqliteStrICmp(argv[0],"double")==0 ){ 5556cbe1f1bSdrh sqlite_set_result_double(context, atof(argv[1])); 5566cbe1f1bSdrh }else{ 5576cbe1f1bSdrh sqlite_set_result_error(context,"first argument should be one of: " 5586cbe1f1bSdrh "string int double", -1); 5596cbe1f1bSdrh } 5606cbe1f1bSdrh argc -= 2; 5616cbe1f1bSdrh argv += 2; 5626cbe1f1bSdrh } 5636cbe1f1bSdrh } 5646cbe1f1bSdrh 5656cbe1f1bSdrh /* 5666cbe1f1bSdrh ** Usage: sqlite_register_test_function DB NAME 5676cbe1f1bSdrh ** 5686cbe1f1bSdrh ** Register the test SQL function on the database DB under the name NAME. 5696cbe1f1bSdrh */ 570c2eef3b3Sdrh static int test_register_func( 5716cbe1f1bSdrh void *NotUsed, 5726cbe1f1bSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 5736cbe1f1bSdrh int argc, /* Number of arguments */ 5746cbe1f1bSdrh char **argv /* Text of each argument */ 5756cbe1f1bSdrh ){ 5766cbe1f1bSdrh sqlite *db; 5776cbe1f1bSdrh int rc; 5786cbe1f1bSdrh if( argc!=3 ){ 5796cbe1f1bSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 5806cbe1f1bSdrh " DB FUNCTION-NAME", 0); 5816cbe1f1bSdrh return TCL_ERROR; 5826cbe1f1bSdrh } 583b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 5846cbe1f1bSdrh rc = sqlite_create_function(db, argv[2], -1, testFunc, 0); 5856cbe1f1bSdrh if( rc!=0 ){ 5866cbe1f1bSdrh Tcl_AppendResult(interp, sqlite_error_string(rc), 0); 5876cbe1f1bSdrh return TCL_ERROR; 5886cbe1f1bSdrh } 5896cbe1f1bSdrh return TCL_OK; 5906cbe1f1bSdrh } 5916cbe1f1bSdrh 5926cbe1f1bSdrh /* 5935a38705eSdrh ** This SQLite callback records the datatype of all columns. 5945a38705eSdrh ** 5955a38705eSdrh ** The pArg argument is really a pointer to a TCL interpreter. The 5965a38705eSdrh ** column names are inserted as the result of this interpreter. 5975a38705eSdrh ** 5985a38705eSdrh ** This routine returns non-zero which causes the query to abort. 5995a38705eSdrh */ 6005a38705eSdrh static int rememberDataTypes(void *pArg, int nCol, char **argv, char **colv){ 6015a38705eSdrh int i; 6025a38705eSdrh Tcl_Interp *interp = (Tcl_Interp*)pArg; 6035a38705eSdrh Tcl_Obj *pList, *pElem; 6045a38705eSdrh if( colv[nCol+1]==0 ){ 6055a38705eSdrh return 1; 6065a38705eSdrh } 6075a38705eSdrh pList = Tcl_NewObj(); 6085a38705eSdrh for(i=0; i<nCol; i++){ 6095a38705eSdrh pElem = Tcl_NewStringObj(colv[i+nCol] ? colv[i+nCol] : "NULL", -1); 6105a38705eSdrh Tcl_ListObjAppendElement(interp, pList, pElem); 6115a38705eSdrh } 6125a38705eSdrh Tcl_SetObjResult(interp, pList); 6135a38705eSdrh return 1; 6145a38705eSdrh } 6155a38705eSdrh 6165a38705eSdrh /* 6175a38705eSdrh ** Invoke an SQL statement but ignore all the data in the result. Instead, 6185a38705eSdrh ** return a list that consists of the datatypes of the various columns. 6195a38705eSdrh ** 6205a38705eSdrh ** This only works if "PRAGMA show_datatypes=on" has been executed against 6215a38705eSdrh ** the database connection. 6225a38705eSdrh */ 6235a38705eSdrh static int sqlite_datatypes( 6245a38705eSdrh void *NotUsed, 6255a38705eSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 6265a38705eSdrh int argc, /* Number of arguments */ 6275a38705eSdrh char **argv /* Text of each argument */ 6285a38705eSdrh ){ 6295a38705eSdrh sqlite *db; 6305a38705eSdrh int rc; 6315a38705eSdrh if( argc!=3 ){ 6325a38705eSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 6335a38705eSdrh " DB SQL", 0); 6345a38705eSdrh return TCL_ERROR; 6355a38705eSdrh } 636b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 6375a38705eSdrh rc = sqlite_exec(db, argv[2], rememberDataTypes, interp, 0); 6385a38705eSdrh if( rc!=0 && rc!=SQLITE_ABORT ){ 6395a38705eSdrh Tcl_AppendResult(interp, sqlite_error_string(rc), 0); 6405a38705eSdrh return TCL_ERROR; 6415a38705eSdrh } 6425a38705eSdrh return TCL_OK; 6435a38705eSdrh } 6445a38705eSdrh 645b86ccfb2Sdrh /* 646*073e5a77Sdrh ** Usage: sqlite_compile DB SQL ?TAILVAR? 647b86ccfb2Sdrh ** 648b86ccfb2Sdrh ** Attempt to compile an SQL statement. Return a pointer to the virtual 649b86ccfb2Sdrh ** machine used to execute that statement. Unprocessed SQL is written 650b86ccfb2Sdrh ** into TAILVAR. 651b86ccfb2Sdrh */ 652b86ccfb2Sdrh static int test_compile( 653b86ccfb2Sdrh void *NotUsed, 654b86ccfb2Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 655b86ccfb2Sdrh int argc, /* Number of arguments */ 656b86ccfb2Sdrh char **argv /* Text of each argument */ 657b86ccfb2Sdrh ){ 658b86ccfb2Sdrh sqlite *db; 659b86ccfb2Sdrh sqlite_vm *vm; 660b86ccfb2Sdrh int rc; 661b86ccfb2Sdrh char *zErr = 0; 662b86ccfb2Sdrh const char *zTail; 663b86ccfb2Sdrh char zBuf[50]; 664*073e5a77Sdrh if( argc!=3 && argc!=4 ){ 665b86ccfb2Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 666b86ccfb2Sdrh " DB SQL TAILVAR", 0); 667b86ccfb2Sdrh return TCL_ERROR; 668b86ccfb2Sdrh } 669b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 670*073e5a77Sdrh rc = sqlite_compile(db, argv[2], argc==4 ? &zTail : 0, &vm, &zErr); 671*073e5a77Sdrh if( argc==4 ) Tcl_SetVar(interp, argv[3], zTail, 0); 672b86ccfb2Sdrh if( rc ){ 673b86ccfb2Sdrh assert( vm==0 ); 674b86ccfb2Sdrh sprintf(zBuf, "(%d) ", rc); 675b86ccfb2Sdrh Tcl_AppendResult(interp, zBuf, zErr, 0); 676b86ccfb2Sdrh sqlite_freemem(zErr); 677b86ccfb2Sdrh return TCL_ERROR; 678b86ccfb2Sdrh } 679326dce74Sdrh if( vm ){ 6807d8085a8Sdrh if( makePointerStr(interp, zBuf, vm) ) return TCL_ERROR; 681b86ccfb2Sdrh Tcl_AppendResult(interp, zBuf, 0); 682326dce74Sdrh } 683b86ccfb2Sdrh return TCL_OK; 684b86ccfb2Sdrh } 685b86ccfb2Sdrh 686b86ccfb2Sdrh /* 687*073e5a77Sdrh ** Usage: sqlite_step VM ?NVAR? ?VALUEVAR? ?COLNAMEVAR? 688b86ccfb2Sdrh ** 689b86ccfb2Sdrh ** Step a virtual machine. Return a the result code as a string. 690b86ccfb2Sdrh ** Column results are written into three variables. 691b86ccfb2Sdrh */ 692b86ccfb2Sdrh static int test_step( 693b86ccfb2Sdrh void *NotUsed, 694b86ccfb2Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 695b86ccfb2Sdrh int argc, /* Number of arguments */ 696b86ccfb2Sdrh char **argv /* Text of each argument */ 697b86ccfb2Sdrh ){ 698b86ccfb2Sdrh sqlite_vm *vm; 699b86ccfb2Sdrh int rc, i; 7003a84069dSdrh const char **azValue = 0; 7013a84069dSdrh const char **azColName = 0; 7023a84069dSdrh int N = 0; 703b86ccfb2Sdrh char *zRc; 704b86ccfb2Sdrh char zBuf[50]; 705*073e5a77Sdrh if( argc<2 || argc>5 ){ 706b86ccfb2Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 707b86ccfb2Sdrh " VM NVAR VALUEVAR COLNAMEVAR", 0); 708b86ccfb2Sdrh return TCL_ERROR; 709b86ccfb2Sdrh } 710b86ccfb2Sdrh if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR; 711*073e5a77Sdrh rc = sqlite_step(vm, argc>=3?&N:0, argc>=4?&azValue:0, argc==5?&azColName:0); 712*073e5a77Sdrh if( argc>=3 ){ 713b86ccfb2Sdrh sprintf(zBuf, "%d", N); 714b86ccfb2Sdrh Tcl_SetVar(interp, argv[2], zBuf, 0); 715*073e5a77Sdrh } 716*073e5a77Sdrh if( argc>=4 ){ 717b86ccfb2Sdrh Tcl_SetVar(interp, argv[3], "", 0); 7183a84069dSdrh if( azValue ){ 719b86ccfb2Sdrh for(i=0; i<N; i++){ 720b86ccfb2Sdrh Tcl_SetVar(interp, argv[3], azValue[i] ? azValue[i] : "", 721b86ccfb2Sdrh TCL_APPEND_VALUE | TCL_LIST_ELEMENT); 722b86ccfb2Sdrh } 723b86ccfb2Sdrh } 724*073e5a77Sdrh } 725*073e5a77Sdrh if( argc==5 ){ 726b86ccfb2Sdrh Tcl_SetVar(interp, argv[4], "", 0); 7273a84069dSdrh if( azColName ){ 728b86ccfb2Sdrh for(i=0; i<N*2; i++){ 729326dce74Sdrh Tcl_SetVar(interp, argv[4], azColName[i] ? azColName[i] : "", 730b86ccfb2Sdrh TCL_APPEND_VALUE | TCL_LIST_ELEMENT); 731b86ccfb2Sdrh } 732b86ccfb2Sdrh } 733*073e5a77Sdrh } 734b86ccfb2Sdrh switch( rc ){ 735b86ccfb2Sdrh case SQLITE_DONE: zRc = "SQLITE_DONE"; break; 736326dce74Sdrh case SQLITE_BUSY: zRc = "SQLITE_BUSY"; break; 737326dce74Sdrh case SQLITE_ROW: zRc = "SQLITE_ROW"; break; 738326dce74Sdrh case SQLITE_ERROR: zRc = "SQLITE_ERROR"; break; 739b86ccfb2Sdrh case SQLITE_MISUSE: zRc = "SQLITE_MISUSE"; break; 740b86ccfb2Sdrh default: zRc = "unknown"; break; 741b86ccfb2Sdrh } 742b86ccfb2Sdrh Tcl_AppendResult(interp, zRc, 0); 743b86ccfb2Sdrh return TCL_OK; 744b86ccfb2Sdrh } 745b86ccfb2Sdrh 746b86ccfb2Sdrh /* 747b86ccfb2Sdrh ** Usage: sqlite_finalize VM 748b86ccfb2Sdrh ** 749b86ccfb2Sdrh ** Shutdown a virtual machine. 750b86ccfb2Sdrh */ 751b86ccfb2Sdrh static int test_finalize( 752b86ccfb2Sdrh void *NotUsed, 753b86ccfb2Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 754b86ccfb2Sdrh int argc, /* Number of arguments */ 755b86ccfb2Sdrh char **argv /* Text of each argument */ 756b86ccfb2Sdrh ){ 757b86ccfb2Sdrh sqlite_vm *vm; 758b86ccfb2Sdrh int rc; 759b86ccfb2Sdrh char *zErrMsg = 0; 760b86ccfb2Sdrh if( argc!=2 ){ 761b86ccfb2Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 762326dce74Sdrh " VM\"", 0); 763b86ccfb2Sdrh return TCL_ERROR; 764b86ccfb2Sdrh } 765b86ccfb2Sdrh if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR; 766b86ccfb2Sdrh rc = sqlite_finalize(vm, &zErrMsg); 767b86ccfb2Sdrh if( rc ){ 768b86ccfb2Sdrh char zBuf[50]; 769b86ccfb2Sdrh sprintf(zBuf, "(%d) ", rc); 770b86ccfb2Sdrh Tcl_AppendResult(interp, zBuf, zErrMsg, 0); 771b86ccfb2Sdrh sqlite_freemem(zErrMsg); 772b86ccfb2Sdrh return TCL_ERROR; 773b86ccfb2Sdrh } 774b86ccfb2Sdrh return TCL_OK; 775b86ccfb2Sdrh } 776b86ccfb2Sdrh 7775a38705eSdrh /* 77899ee3600Sdrh ** Usage: breakpoint 77999ee3600Sdrh ** 78099ee3600Sdrh ** This routine exists for one purpose - to provide a place to put a 78199ee3600Sdrh ** breakpoint with GDB that can be triggered using TCL code. The use 78299ee3600Sdrh ** for this is when a particular test fails on (say) the 1485th iteration. 78399ee3600Sdrh ** In the TCL test script, we can add code like this: 78499ee3600Sdrh ** 78599ee3600Sdrh ** if {$i==1485} breakpoint 78699ee3600Sdrh ** 78799ee3600Sdrh ** Then run testfixture in the debugger and wait for the breakpoint to 78899ee3600Sdrh ** fire. Then additional breakpoints can be set to trace down the bug. 78999ee3600Sdrh */ 79099ee3600Sdrh static int test_breakpoint( 79199ee3600Sdrh void *NotUsed, 79299ee3600Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 79399ee3600Sdrh int argc, /* Number of arguments */ 79499ee3600Sdrh char **argv /* Text of each argument */ 79599ee3600Sdrh ){ 79699ee3600Sdrh return TCL_OK; /* Do nothing */ 79799ee3600Sdrh } 79899ee3600Sdrh 79999ee3600Sdrh /* 800d1bf3512Sdrh ** Register commands with the TCL interpreter. 801d1bf3512Sdrh */ 802d1bf3512Sdrh int Sqlitetest1_Init(Tcl_Interp *interp){ 803487ab3caSdrh extern int sqlite_search_count; 80494e92032Sdrh extern int sqlite_open_file_count; 805c2eef3b3Sdrh static struct { 806c2eef3b3Sdrh char *zName; 807c2eef3b3Sdrh Tcl_CmdProc *xProc; 808c2eef3b3Sdrh } aCmd[] = { 809c2eef3b3Sdrh { "sqlite_mprintf_int", (Tcl_CmdProc*)sqlite_mprintf_int }, 810c2eef3b3Sdrh { "sqlite_mprintf_str", (Tcl_CmdProc*)sqlite_mprintf_str }, 811c2eef3b3Sdrh { "sqlite_mprintf_double", (Tcl_CmdProc*)sqlite_mprintf_double }, 812d93d8a81Sdrh { "sqlite_mprintf_z_test", (Tcl_CmdProc*)test_mprintf_z }, 813c2eef3b3Sdrh { "sqlite_open", (Tcl_CmdProc*)sqlite_test_open }, 814c2eef3b3Sdrh { "sqlite_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid }, 815c2eef3b3Sdrh { "sqlite_exec_printf", (Tcl_CmdProc*)test_exec_printf }, 816c2eef3b3Sdrh { "sqlite_get_table_printf", (Tcl_CmdProc*)test_get_table_printf }, 817c2eef3b3Sdrh { "sqlite_close", (Tcl_CmdProc*)sqlite_test_close }, 818c2eef3b3Sdrh { "sqlite_create_function", (Tcl_CmdProc*)test_create_function }, 819c2eef3b3Sdrh { "sqlite_create_aggregate", (Tcl_CmdProc*)test_create_aggregate }, 820c2eef3b3Sdrh { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func }, 821c2eef3b3Sdrh { "sqlite_abort", (Tcl_CmdProc*)sqlite_abort }, 8225a38705eSdrh { "sqlite_datatypes", (Tcl_CmdProc*)sqlite_datatypes }, 823c2eef3b3Sdrh #ifdef MEMORY_DEBUG 824c2eef3b3Sdrh { "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail }, 825c2eef3b3Sdrh { "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat }, 826c2eef3b3Sdrh #endif 827b86ccfb2Sdrh { "sqlite_compile", (Tcl_CmdProc*)test_compile }, 828b86ccfb2Sdrh { "sqlite_step", (Tcl_CmdProc*)test_step }, 829b86ccfb2Sdrh { "sqlite_finalize", (Tcl_CmdProc*)test_finalize }, 83099ee3600Sdrh { "breakpoint", (Tcl_CmdProc*)test_breakpoint }, 831c2eef3b3Sdrh }; 832c2eef3b3Sdrh int i; 833c2eef3b3Sdrh 834c2eef3b3Sdrh for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ 835c2eef3b3Sdrh Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); 836c2eef3b3Sdrh } 837487ab3caSdrh Tcl_LinkVar(interp, "sqlite_search_count", 838487ab3caSdrh (char*)&sqlite_search_count, TCL_LINK_INT); 83994e92032Sdrh Tcl_LinkVar(interp, "sqlite_open_file_count", 84094e92032Sdrh (char*)&sqlite_open_file_count, TCL_LINK_INT); 841d1bf3512Sdrh return TCL_OK; 842d1bf3512Sdrh } 843