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*94e92032Sdrh ** $Id: test1.c,v 1.22 2003/02/16 22:21:32 drh Exp $ 17d1bf3512Sdrh */ 18d1bf3512Sdrh #include "sqliteInt.h" 19d1bf3512Sdrh #include "tcl.h" 20*94e92032Sdrh #include "os.h" 21d1bf3512Sdrh #include <stdlib.h> 22d1bf3512Sdrh #include <string.h> 23d1bf3512Sdrh 24*94e92032Sdrh #if OS_WIN 25*94e92032Sdrh # define PTR_FMT "%x" 26*94e92032Sdrh #else 27*94e92032Sdrh # define PTR_FMT "%p" 28*94e92032Sdrh #endif 29*94e92032Sdrh 30d1bf3512Sdrh /* 31b86ccfb2Sdrh ** Decode a pointer to an sqlite object. 32b86ccfb2Sdrh */ 33b86ccfb2Sdrh static int getDbPointer(Tcl_Interp *interp, const char *zArg, sqlite **ppDb){ 34*94e92032Sdrh 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){ 45*94e92032Sdrh 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 /* 53d1bf3512Sdrh ** Usage: sqlite_open filename 54d1bf3512Sdrh ** 55d1bf3512Sdrh ** Returns: The name of an open database. 56d1bf3512Sdrh */ 57d1bf3512Sdrh static int sqlite_test_open( 58d1bf3512Sdrh void *NotUsed, 59d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 60d1bf3512Sdrh int argc, /* Number of arguments */ 61d1bf3512Sdrh char **argv /* Text of each argument */ 62d1bf3512Sdrh ){ 63d1bf3512Sdrh sqlite *db; 64d1bf3512Sdrh char *zErr = 0; 65d1bf3512Sdrh char zBuf[100]; 66d1bf3512Sdrh if( argc!=2 ){ 67d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 68d1bf3512Sdrh " FILENAME\"", 0); 69d1bf3512Sdrh return TCL_ERROR; 70d1bf3512Sdrh } 71d1bf3512Sdrh db = sqlite_open(argv[1], 0666, &zErr); 72d1bf3512Sdrh if( db==0 ){ 73d1bf3512Sdrh Tcl_AppendResult(interp, zErr, 0); 74d1bf3512Sdrh free(zErr); 75d1bf3512Sdrh return TCL_ERROR; 76d1bf3512Sdrh } 77*94e92032Sdrh sprintf(zBuf,PTR_FMT, db); 78d1bf3512Sdrh Tcl_AppendResult(interp, zBuf, 0); 79d1bf3512Sdrh return TCL_OK; 80d1bf3512Sdrh } 81d1bf3512Sdrh 82d1bf3512Sdrh /* 83d1bf3512Sdrh ** The callback routine for sqlite_exec_printf(). 84d1bf3512Sdrh */ 85d1bf3512Sdrh static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){ 86d1bf3512Sdrh Tcl_DString *str = (Tcl_DString*)pArg; 87d1bf3512Sdrh int i; 88d1bf3512Sdrh 89d1bf3512Sdrh if( Tcl_DStringLength(str)==0 ){ 90d1bf3512Sdrh for(i=0; i<argc; i++){ 91d1bf3512Sdrh Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL"); 92d1bf3512Sdrh } 93d1bf3512Sdrh } 94d1bf3512Sdrh for(i=0; i<argc; i++){ 95d1bf3512Sdrh Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL"); 96d1bf3512Sdrh } 97d1bf3512Sdrh return 0; 98d1bf3512Sdrh } 99d1bf3512Sdrh 100d1bf3512Sdrh /* 101d1bf3512Sdrh ** Usage: sqlite_exec_printf DB FORMAT STRING 102d1bf3512Sdrh ** 103d1bf3512Sdrh ** Invoke the sqlite_exec_printf() interface using the open database 104d1bf3512Sdrh ** DB. The SQL is the string FORMAT. The format string should contain 105d1bf3512Sdrh ** one %s or %q. STRING is the value inserted into %s or %q. 106d1bf3512Sdrh */ 107d1bf3512Sdrh static int test_exec_printf( 108d1bf3512Sdrh void *NotUsed, 109d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 110d1bf3512Sdrh int argc, /* Number of arguments */ 111d1bf3512Sdrh char **argv /* Text of each argument */ 112d1bf3512Sdrh ){ 113d1bf3512Sdrh sqlite *db; 114d1bf3512Sdrh Tcl_DString str; 115d1bf3512Sdrh int rc; 116d1bf3512Sdrh char *zErr = 0; 117d1bf3512Sdrh char zBuf[30]; 118d1bf3512Sdrh if( argc!=4 ){ 119d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 120d1bf3512Sdrh " DB FORMAT STRING", 0); 121d1bf3512Sdrh return TCL_ERROR; 122d1bf3512Sdrh } 123b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 124d1bf3512Sdrh Tcl_DStringInit(&str); 125d1bf3512Sdrh rc = sqlite_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]); 126d1bf3512Sdrh sprintf(zBuf, "%d", rc); 127d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 128d1bf3512Sdrh Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr); 129d1bf3512Sdrh Tcl_DStringFree(&str); 130d1bf3512Sdrh if( zErr ) free(zErr); 131d1bf3512Sdrh return TCL_OK; 132d1bf3512Sdrh } 133d1bf3512Sdrh 134d1bf3512Sdrh /* 135d1bf3512Sdrh ** Usage: sqlite_get_table_printf DB FORMAT STRING 136d1bf3512Sdrh ** 137d1bf3512Sdrh ** Invoke the sqlite_get_table_printf() interface using the open database 138d1bf3512Sdrh ** DB. The SQL is the string FORMAT. The format string should contain 139d1bf3512Sdrh ** one %s or %q. STRING is the value inserted into %s or %q. 140d1bf3512Sdrh */ 141d1bf3512Sdrh static int test_get_table_printf( 142d1bf3512Sdrh void *NotUsed, 143d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 144d1bf3512Sdrh int argc, /* Number of arguments */ 145d1bf3512Sdrh char **argv /* Text of each argument */ 146d1bf3512Sdrh ){ 147d1bf3512Sdrh sqlite *db; 148d1bf3512Sdrh Tcl_DString str; 149d1bf3512Sdrh int rc; 150d1bf3512Sdrh char *zErr = 0; 151d1bf3512Sdrh int nRow, nCol; 152d1bf3512Sdrh char **aResult; 153d1bf3512Sdrh int i; 154d1bf3512Sdrh char zBuf[30]; 155d1bf3512Sdrh if( argc!=4 ){ 156d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 157d1bf3512Sdrh " DB FORMAT STRING", 0); 158d1bf3512Sdrh return TCL_ERROR; 159d1bf3512Sdrh } 160b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 161d1bf3512Sdrh Tcl_DStringInit(&str); 162d1bf3512Sdrh rc = sqlite_get_table_printf(db, argv[2], &aResult, &nRow, &nCol, 163d1bf3512Sdrh &zErr, argv[3]); 164d1bf3512Sdrh sprintf(zBuf, "%d", rc); 165d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 166d1bf3512Sdrh if( rc==SQLITE_OK ){ 167d1bf3512Sdrh sprintf(zBuf, "%d", nRow); 168d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 169d1bf3512Sdrh sprintf(zBuf, "%d", nCol); 170d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 171d1bf3512Sdrh for(i=0; i<(nRow+1)*nCol; i++){ 172d1bf3512Sdrh Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL"); 173d1bf3512Sdrh } 174d1bf3512Sdrh }else{ 175d1bf3512Sdrh Tcl_AppendElement(interp, zErr); 176d1bf3512Sdrh } 177d1bf3512Sdrh sqlite_free_table(aResult); 178d1bf3512Sdrh if( zErr ) free(zErr); 179d1bf3512Sdrh return TCL_OK; 180d1bf3512Sdrh } 181d1bf3512Sdrh 182af9ff33aSdrh 183af9ff33aSdrh /* 184af9ff33aSdrh ** Usage: sqlite_last_insert_rowid DB 185af9ff33aSdrh ** 186af9ff33aSdrh ** Returns the integer ROWID of the most recent insert. 187af9ff33aSdrh */ 188af9ff33aSdrh static int test_last_rowid( 189af9ff33aSdrh void *NotUsed, 190af9ff33aSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 191af9ff33aSdrh int argc, /* Number of arguments */ 192af9ff33aSdrh char **argv /* Text of each argument */ 193af9ff33aSdrh ){ 194af9ff33aSdrh sqlite *db; 195af9ff33aSdrh char zBuf[30]; 196af9ff33aSdrh 197af9ff33aSdrh if( argc!=2 ){ 198af9ff33aSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0); 199af9ff33aSdrh return TCL_ERROR; 200af9ff33aSdrh } 201b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 202af9ff33aSdrh sprintf(zBuf, "%d", sqlite_last_insert_rowid(db)); 203af9ff33aSdrh Tcl_AppendResult(interp, zBuf, 0); 204af9ff33aSdrh return SQLITE_OK; 205af9ff33aSdrh } 206af9ff33aSdrh 207d1bf3512Sdrh /* 208d1bf3512Sdrh ** Usage: sqlite_close DB 209d1bf3512Sdrh ** 210d1bf3512Sdrh ** Closes the database opened by sqlite_open. 211d1bf3512Sdrh */ 212d1bf3512Sdrh static int sqlite_test_close( 213d1bf3512Sdrh void *NotUsed, 214d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 215d1bf3512Sdrh int argc, /* Number of arguments */ 216d1bf3512Sdrh char **argv /* Text of each argument */ 217d1bf3512Sdrh ){ 218d1bf3512Sdrh sqlite *db; 219d1bf3512Sdrh if( argc!=2 ){ 220d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 221d1bf3512Sdrh " FILENAME\"", 0); 222d1bf3512Sdrh return TCL_ERROR; 223d1bf3512Sdrh } 224b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 225d1bf3512Sdrh sqlite_close(db); 226d1bf3512Sdrh return TCL_OK; 227d1bf3512Sdrh } 228d1bf3512Sdrh 229d1bf3512Sdrh /* 230c22bd47dSdrh ** Implementation of the x_coalesce() function. 231c22bd47dSdrh ** Return the first argument non-NULL argument. 232c22bd47dSdrh */ 233c22bd47dSdrh static void ifnullFunc(sqlite_func *context, int argc, const char **argv){ 234c22bd47dSdrh int i; 235c22bd47dSdrh for(i=0; i<argc; i++){ 236c22bd47dSdrh if( argv[i] ){ 237c22bd47dSdrh sqlite_set_result_string(context, argv[i], -1); 238c22bd47dSdrh break; 239c22bd47dSdrh } 240c22bd47dSdrh } 241c22bd47dSdrh } 242c22bd47dSdrh 243c22bd47dSdrh /* 244c22bd47dSdrh ** Implementation of the x_sqlite_exec() function. This function takes 245c22bd47dSdrh ** a single argument and attempts to execute that argument as SQL code. 2466cbe1f1bSdrh ** This is illegal and should set the SQLITE_MISUSE flag on the database. 247c22bd47dSdrh ** 248c22bd47dSdrh ** This routine simulates the effect of having two threads attempt to 249c22bd47dSdrh ** use the same database at the same time. 250c22bd47dSdrh */ 251c22bd47dSdrh static void sqliteExecFunc(sqlite_func *context, int argc, const char **argv){ 252c22bd47dSdrh sqlite_exec((sqlite*)sqlite_user_data(context), argv[0], 0, 0, 0); 253c22bd47dSdrh } 254c22bd47dSdrh 255c22bd47dSdrh /* 256c22bd47dSdrh ** Usage: sqlite_test_create_function DB 257c22bd47dSdrh ** 258c22bd47dSdrh ** Call the sqlite_create_function API on the given database in order 259c22bd47dSdrh ** to create a function named "x_coalesce". This function does the same thing 260c22bd47dSdrh ** as the "coalesce" function. This function also registers an SQL function 261c22bd47dSdrh ** named "x_sqlite_exec" that invokes sqlite_exec(). Invoking sqlite_exec() 262c22bd47dSdrh ** in this way is illegal recursion and should raise an SQLITE_MISUSE error. 263c22bd47dSdrh ** The effect is similar to trying to use the same database connection from 264c22bd47dSdrh ** two threads at the same time. 265c22bd47dSdrh ** 266c22bd47dSdrh ** The original motivation for this routine was to be able to call the 267c22bd47dSdrh ** sqlite_create_function function while a query is in progress in order 268c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic. 269c22bd47dSdrh */ 270c2eef3b3Sdrh static int test_create_function( 271c22bd47dSdrh void *NotUsed, 272c22bd47dSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 273c22bd47dSdrh int argc, /* Number of arguments */ 274c22bd47dSdrh char **argv /* Text of each argument */ 275c22bd47dSdrh ){ 276c22bd47dSdrh sqlite *db; 277c22bd47dSdrh extern void Md5_Register(sqlite*); 278c22bd47dSdrh if( argc!=2 ){ 279c22bd47dSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 280c22bd47dSdrh " FILENAME\"", 0); 281c22bd47dSdrh return TCL_ERROR; 282c22bd47dSdrh } 283b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 284c22bd47dSdrh sqlite_create_function(db, "x_coalesce", -1, ifnullFunc, 0); 285c22bd47dSdrh sqlite_create_function(db, "x_sqlite_exec", 1, sqliteExecFunc, db); 286c22bd47dSdrh return TCL_OK; 287c22bd47dSdrh } 288c22bd47dSdrh 289c22bd47dSdrh /* 290c22bd47dSdrh ** Routines to implement the x_count() aggregate function. 291c22bd47dSdrh */ 292c22bd47dSdrh typedef struct CountCtx CountCtx; 293c22bd47dSdrh struct CountCtx { 294c22bd47dSdrh int n; 295c22bd47dSdrh }; 296c22bd47dSdrh static void countStep(sqlite_func *context, int argc, const char **argv){ 297c22bd47dSdrh CountCtx *p; 298c22bd47dSdrh p = sqlite_aggregate_context(context, sizeof(*p)); 299c22bd47dSdrh if( (argc==0 || argv[0]) && p ){ 300c22bd47dSdrh p->n++; 301c22bd47dSdrh } 302c22bd47dSdrh } 303c22bd47dSdrh static void countFinalize(sqlite_func *context){ 304c22bd47dSdrh CountCtx *p; 305c22bd47dSdrh p = sqlite_aggregate_context(context, sizeof(*p)); 306c22bd47dSdrh sqlite_set_result_int(context, p ? p->n : 0); 307c22bd47dSdrh } 308c22bd47dSdrh 309c22bd47dSdrh /* 310c22bd47dSdrh ** Usage: sqlite_test_create_aggregate DB 311c22bd47dSdrh ** 312c22bd47dSdrh ** Call the sqlite_create_function API on the given database in order 313c22bd47dSdrh ** to create a function named "x_count". This function does the same thing 314c22bd47dSdrh ** as the "md5sum" function. 315c22bd47dSdrh ** 316c22bd47dSdrh ** The original motivation for this routine was to be able to call the 317c22bd47dSdrh ** sqlite_create_aggregate function while a query is in progress in order 318c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic. 319c22bd47dSdrh */ 320c2eef3b3Sdrh static int test_create_aggregate( 321c22bd47dSdrh void *NotUsed, 322c22bd47dSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 323c22bd47dSdrh int argc, /* Number of arguments */ 324c22bd47dSdrh char **argv /* Text of each argument */ 325c22bd47dSdrh ){ 326c22bd47dSdrh sqlite *db; 327c22bd47dSdrh if( argc!=2 ){ 328c22bd47dSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 329c22bd47dSdrh " FILENAME\"", 0); 330c22bd47dSdrh return TCL_ERROR; 331c22bd47dSdrh } 332b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 333c22bd47dSdrh sqlite_create_aggregate(db, "x_count", 0, countStep, countFinalize, 0); 334c22bd47dSdrh sqlite_create_aggregate(db, "x_count", 1, countStep, countFinalize, 0); 335c22bd47dSdrh return TCL_OK; 336c22bd47dSdrh } 337c22bd47dSdrh 338c22bd47dSdrh 339c22bd47dSdrh 340c22bd47dSdrh /* 341d1bf3512Sdrh ** Usage: sqlite_mprintf_int FORMAT INTEGER INTEGER INTEGER 342d1bf3512Sdrh ** 343d1bf3512Sdrh ** Call mprintf with three integer arguments 344d1bf3512Sdrh */ 345d1bf3512Sdrh static int sqlite_mprintf_int( 346d1bf3512Sdrh void *NotUsed, 347d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 348d1bf3512Sdrh int argc, /* Number of arguments */ 349d1bf3512Sdrh char **argv /* Text of each argument */ 350d1bf3512Sdrh ){ 351d1bf3512Sdrh int a[3], i; 352d1bf3512Sdrh char *z; 353d1bf3512Sdrh if( argc!=5 ){ 354d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 355d1bf3512Sdrh " FORMAT INT INT INT\"", 0); 356d1bf3512Sdrh return TCL_ERROR; 357d1bf3512Sdrh } 358d1bf3512Sdrh for(i=2; i<5; i++){ 359d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 360d1bf3512Sdrh } 361d1bf3512Sdrh z = sqlite_mprintf(argv[1], a[0], a[1], a[2]); 362d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 363fa173a76Sdrh sqlite_freemem(z); 364d1bf3512Sdrh return TCL_OK; 365d1bf3512Sdrh } 366d1bf3512Sdrh 367d1bf3512Sdrh /* 368d1bf3512Sdrh ** Usage: sqlite_mprintf_str FORMAT INTEGER INTEGER STRING 369d1bf3512Sdrh ** 370d1bf3512Sdrh ** Call mprintf with two integer arguments and one string argument 371d1bf3512Sdrh */ 372d1bf3512Sdrh static int sqlite_mprintf_str( 373d1bf3512Sdrh void *NotUsed, 374d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 375d1bf3512Sdrh int argc, /* Number of arguments */ 376d1bf3512Sdrh char **argv /* Text of each argument */ 377d1bf3512Sdrh ){ 378d1bf3512Sdrh int a[3], i; 379d1bf3512Sdrh char *z; 380f220b24fSchw if( argc<4 || argc>5 ){ 381d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 382f220b24fSchw " FORMAT INT INT ?STRING?\"", 0); 383d1bf3512Sdrh return TCL_ERROR; 384d1bf3512Sdrh } 385d1bf3512Sdrh for(i=2; i<4; i++){ 386d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 387d1bf3512Sdrh } 388f220b24fSchw z = sqlite_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL); 389d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 390fa173a76Sdrh sqlite_freemem(z); 391d1bf3512Sdrh return TCL_OK; 392d1bf3512Sdrh } 393d1bf3512Sdrh 394d1bf3512Sdrh /* 395d1bf3512Sdrh ** Usage: sqlite_mprintf_str FORMAT INTEGER INTEGER DOUBLE 396d1bf3512Sdrh ** 397d1bf3512Sdrh ** Call mprintf with two integer arguments and one double argument 398d1bf3512Sdrh */ 399d1bf3512Sdrh static int sqlite_mprintf_double( 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 double r; 407d1bf3512Sdrh char *z; 408d1bf3512Sdrh if( argc!=5 ){ 409d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 410d1bf3512Sdrh " FORMAT INT INT STRING\"", 0); 411d1bf3512Sdrh return TCL_ERROR; 412d1bf3512Sdrh } 413d1bf3512Sdrh for(i=2; i<4; i++){ 414d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 415d1bf3512Sdrh } 416d1bf3512Sdrh if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR; 417d1bf3512Sdrh z = sqlite_mprintf(argv[1], a[0], a[1], r); 418d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 419fa173a76Sdrh sqlite_freemem(z); 420d1bf3512Sdrh return TCL_OK; 421d1bf3512Sdrh } 422d1bf3512Sdrh 423d1bf3512Sdrh /* 424daffd0e5Sdrh ** Usage: sqlite_malloc_fail N 425daffd0e5Sdrh ** 426afa4a020Sdrh ** Rig sqliteMalloc() to fail on the N-th call. Turn off this mechanism 427daffd0e5Sdrh ** and reset the sqlite_malloc_failed variable is N==0. 428daffd0e5Sdrh */ 429daffd0e5Sdrh #ifdef MEMORY_DEBUG 430daffd0e5Sdrh static int sqlite_malloc_fail( 431daffd0e5Sdrh void *NotUsed, 432daffd0e5Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 433daffd0e5Sdrh int argc, /* Number of arguments */ 434daffd0e5Sdrh char **argv /* Text of each argument */ 435daffd0e5Sdrh ){ 436daffd0e5Sdrh int n; 437daffd0e5Sdrh if( argc!=2 ){ 438daffd0e5Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0); 439daffd0e5Sdrh return TCL_ERROR; 440daffd0e5Sdrh } 441daffd0e5Sdrh if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR; 442daffd0e5Sdrh sqlite_iMallocFail = n; 443daffd0e5Sdrh sqlite_malloc_failed = 0; 444daffd0e5Sdrh return TCL_OK; 445daffd0e5Sdrh } 446daffd0e5Sdrh #endif 447daffd0e5Sdrh 448daffd0e5Sdrh /* 449daffd0e5Sdrh ** Usage: sqlite_malloc_stat 450daffd0e5Sdrh ** 451daffd0e5Sdrh ** Return the number of prior calls to sqliteMalloc() and sqliteFree(). 452daffd0e5Sdrh */ 453daffd0e5Sdrh #ifdef MEMORY_DEBUG 454daffd0e5Sdrh static int sqlite_malloc_stat( 455daffd0e5Sdrh void *NotUsed, 456daffd0e5Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 457daffd0e5Sdrh int argc, /* Number of arguments */ 458daffd0e5Sdrh char **argv /* Text of each argument */ 459daffd0e5Sdrh ){ 460daffd0e5Sdrh char zBuf[200]; 461daffd0e5Sdrh sprintf(zBuf, "%d %d %d", sqlite_nMalloc, sqlite_nFree, sqlite_iMallocFail); 462daffd0e5Sdrh Tcl_AppendResult(interp, zBuf, 0); 463daffd0e5Sdrh return TCL_OK; 464daffd0e5Sdrh } 465daffd0e5Sdrh #endif 466daffd0e5Sdrh 467daffd0e5Sdrh /* 46828b4e489Sdrh ** Usage: sqlite_abort 46928b4e489Sdrh ** 47028b4e489Sdrh ** Shutdown the process immediately. This is not a clean shutdown. 47128b4e489Sdrh ** This command is used to test the recoverability of a database in 47228b4e489Sdrh ** the event of a program crash. 47328b4e489Sdrh */ 47428b4e489Sdrh static int sqlite_abort( 47528b4e489Sdrh void *NotUsed, 47628b4e489Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 47728b4e489Sdrh int argc, /* Number of arguments */ 47828b4e489Sdrh char **argv /* Text of each argument */ 47928b4e489Sdrh ){ 48028b4e489Sdrh assert( interp==0 ); /* This will always fail */ 48128b4e489Sdrh return TCL_OK; 48228b4e489Sdrh } 48328b4e489Sdrh 48428b4e489Sdrh /* 4856cbe1f1bSdrh ** The following routine is a user-defined SQL function whose purpose 4866cbe1f1bSdrh ** is to test the sqlite_set_result() API. 4876cbe1f1bSdrh */ 4886cbe1f1bSdrh static void testFunc(sqlite_func *context, int argc, const char **argv){ 4896cbe1f1bSdrh while( argc>=2 ){ 4906cbe1f1bSdrh if( argv[0]==0 ){ 4916cbe1f1bSdrh sqlite_set_result_error(context, "first argument to test function " 4926cbe1f1bSdrh "may not be NULL", -1); 4936cbe1f1bSdrh }else if( sqliteStrICmp(argv[0],"string")==0 ){ 4946cbe1f1bSdrh sqlite_set_result_string(context, argv[1], -1); 4956cbe1f1bSdrh }else if( argv[1]==0 ){ 4966cbe1f1bSdrh sqlite_set_result_error(context, "2nd argument may not be NULL if the " 4976cbe1f1bSdrh "first argument is not \"string\"", -1); 4986cbe1f1bSdrh }else if( sqliteStrICmp(argv[0],"int")==0 ){ 4996cbe1f1bSdrh sqlite_set_result_int(context, atoi(argv[1])); 5006cbe1f1bSdrh }else if( sqliteStrICmp(argv[0],"double")==0 ){ 5016cbe1f1bSdrh sqlite_set_result_double(context, atof(argv[1])); 5026cbe1f1bSdrh }else{ 5036cbe1f1bSdrh sqlite_set_result_error(context,"first argument should be one of: " 5046cbe1f1bSdrh "string int double", -1); 5056cbe1f1bSdrh } 5066cbe1f1bSdrh argc -= 2; 5076cbe1f1bSdrh argv += 2; 5086cbe1f1bSdrh } 5096cbe1f1bSdrh } 5106cbe1f1bSdrh 5116cbe1f1bSdrh /* 5126cbe1f1bSdrh ** Usage: sqlite_register_test_function DB NAME 5136cbe1f1bSdrh ** 5146cbe1f1bSdrh ** Register the test SQL function on the database DB under the name NAME. 5156cbe1f1bSdrh */ 516c2eef3b3Sdrh static int test_register_func( 5176cbe1f1bSdrh void *NotUsed, 5186cbe1f1bSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 5196cbe1f1bSdrh int argc, /* Number of arguments */ 5206cbe1f1bSdrh char **argv /* Text of each argument */ 5216cbe1f1bSdrh ){ 5226cbe1f1bSdrh sqlite *db; 5236cbe1f1bSdrh int rc; 5246cbe1f1bSdrh if( argc!=3 ){ 5256cbe1f1bSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 5266cbe1f1bSdrh " DB FUNCTION-NAME", 0); 5276cbe1f1bSdrh return TCL_ERROR; 5286cbe1f1bSdrh } 529b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 5306cbe1f1bSdrh rc = sqlite_create_function(db, argv[2], -1, testFunc, 0); 5316cbe1f1bSdrh if( rc!=0 ){ 5326cbe1f1bSdrh Tcl_AppendResult(interp, sqlite_error_string(rc), 0); 5336cbe1f1bSdrh return TCL_ERROR; 5346cbe1f1bSdrh } 5356cbe1f1bSdrh return TCL_OK; 5366cbe1f1bSdrh } 5376cbe1f1bSdrh 5386cbe1f1bSdrh /* 5395a38705eSdrh ** This SQLite callback records the datatype of all columns. 5405a38705eSdrh ** 5415a38705eSdrh ** The pArg argument is really a pointer to a TCL interpreter. The 5425a38705eSdrh ** column names are inserted as the result of this interpreter. 5435a38705eSdrh ** 5445a38705eSdrh ** This routine returns non-zero which causes the query to abort. 5455a38705eSdrh */ 5465a38705eSdrh static int rememberDataTypes(void *pArg, int nCol, char **argv, char **colv){ 5475a38705eSdrh int i; 5485a38705eSdrh Tcl_Interp *interp = (Tcl_Interp*)pArg; 5495a38705eSdrh Tcl_Obj *pList, *pElem; 5505a38705eSdrh if( colv[nCol+1]==0 ){ 5515a38705eSdrh return 1; 5525a38705eSdrh } 5535a38705eSdrh pList = Tcl_NewObj(); 5545a38705eSdrh for(i=0; i<nCol; i++){ 5555a38705eSdrh pElem = Tcl_NewStringObj(colv[i+nCol] ? colv[i+nCol] : "NULL", -1); 5565a38705eSdrh Tcl_ListObjAppendElement(interp, pList, pElem); 5575a38705eSdrh } 5585a38705eSdrh Tcl_SetObjResult(interp, pList); 5595a38705eSdrh return 1; 5605a38705eSdrh } 5615a38705eSdrh 5625a38705eSdrh /* 5635a38705eSdrh ** Invoke an SQL statement but ignore all the data in the result. Instead, 5645a38705eSdrh ** return a list that consists of the datatypes of the various columns. 5655a38705eSdrh ** 5665a38705eSdrh ** This only works if "PRAGMA show_datatypes=on" has been executed against 5675a38705eSdrh ** the database connection. 5685a38705eSdrh */ 5695a38705eSdrh static int sqlite_datatypes( 5705a38705eSdrh void *NotUsed, 5715a38705eSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 5725a38705eSdrh int argc, /* Number of arguments */ 5735a38705eSdrh char **argv /* Text of each argument */ 5745a38705eSdrh ){ 5755a38705eSdrh sqlite *db; 5765a38705eSdrh int rc; 5775a38705eSdrh if( argc!=3 ){ 5785a38705eSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 5795a38705eSdrh " DB SQL", 0); 5805a38705eSdrh return TCL_ERROR; 5815a38705eSdrh } 582b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 5835a38705eSdrh rc = sqlite_exec(db, argv[2], rememberDataTypes, interp, 0); 5845a38705eSdrh if( rc!=0 && rc!=SQLITE_ABORT ){ 5855a38705eSdrh Tcl_AppendResult(interp, sqlite_error_string(rc), 0); 5865a38705eSdrh return TCL_ERROR; 5875a38705eSdrh } 5885a38705eSdrh return TCL_OK; 5895a38705eSdrh } 5905a38705eSdrh 591ed6c8671Sdrh #ifndef SQLITE_OMIT_AUTHORIZATION 592ed6c8671Sdrh /* 593ed6c8671Sdrh ** Information used by the authentication function. 594ed6c8671Sdrh */ 595ed6c8671Sdrh typedef struct AuthInfo AuthInfo; 596ed6c8671Sdrh struct AuthInfo { 597ed6c8671Sdrh Tcl_Interp *interp; /* Interpreter to use */ 598ed6c8671Sdrh int nCmd; /* Number of characters in zCmd[] */ 599ed6c8671Sdrh char zCmd[500]; /* Command to invoke */ 600ed6c8671Sdrh }; 601ed6c8671Sdrh 602ed6c8671Sdrh /* 603ed6c8671Sdrh ** We create a single static authenticator. This won't work in a 604ed6c8671Sdrh ** multi-threaded environment, but the test fixture is not multithreaded. 605ed6c8671Sdrh ** And be making it static, we don't have to worry about deallocating 606ed6c8671Sdrh ** after a test in order to void memory leaks. 607ed6c8671Sdrh */ 608ed6c8671Sdrh static AuthInfo authInfo; 609ed6c8671Sdrh 610ed6c8671Sdrh /* 611ed6c8671Sdrh ** This is the authentication function. It appends the authentication 612ed6c8671Sdrh ** type code and the two arguments to zCmd[] then invokes the result 613ed6c8671Sdrh ** on the interpreter. The reply is examined to determine if the 614ed6c8671Sdrh ** authentication fails or succeeds. 615ed6c8671Sdrh */ 616ed6c8671Sdrh static int auth_callback( 617ed6c8671Sdrh void *NotUsed, 618ed6c8671Sdrh int code, 619ed6c8671Sdrh const char *zArg1, 620ed6c8671Sdrh const char *zArg2 621ed6c8671Sdrh ){ 622ed6c8671Sdrh char *zCode; 623ed6c8671Sdrh Tcl_DString str; 624ed6c8671Sdrh int rc; 625ed6c8671Sdrh const char *zReply; 626ed6c8671Sdrh switch( code ){ 627e5f9c644Sdrh case SQLITE_COPY : zCode="SQLITE_COPY"; break; 628e5f9c644Sdrh case SQLITE_CREATE_INDEX : zCode="SQLITE_CREATE_INDEX"; break; 629e5f9c644Sdrh case SQLITE_CREATE_TABLE : zCode="SQLITE_CREATE_TABLE"; break; 630e5f9c644Sdrh case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break; 631e5f9c644Sdrh case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break; 632e5f9c644Sdrh case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break; 633e5f9c644Sdrh case SQLITE_CREATE_TEMP_VIEW : zCode="SQLITE_CREATE_TEMP_VIEW"; break; 634e5f9c644Sdrh case SQLITE_CREATE_TRIGGER : zCode="SQLITE_CREATE_TRIGGER"; break; 635e5f9c644Sdrh case SQLITE_CREATE_VIEW : zCode="SQLITE_CREATE_VIEW"; break; 636e5f9c644Sdrh case SQLITE_DELETE : zCode="SQLITE_DELETE"; break; 637e5f9c644Sdrh case SQLITE_DROP_INDEX : zCode="SQLITE_DROP_INDEX"; break; 638e5f9c644Sdrh case SQLITE_DROP_TABLE : zCode="SQLITE_DROP_TABLE"; break; 639e5f9c644Sdrh case SQLITE_DROP_TEMP_INDEX : zCode="SQLITE_DROP_TEMP_INDEX"; break; 640e5f9c644Sdrh case SQLITE_DROP_TEMP_TABLE : zCode="SQLITE_DROP_TEMP_TABLE"; break; 641e5f9c644Sdrh case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break; 642e5f9c644Sdrh case SQLITE_DROP_TEMP_VIEW : zCode="SQLITE_DROP_TEMP_VIEW"; break; 643e5f9c644Sdrh case SQLITE_DROP_TRIGGER : zCode="SQLITE_DROP_TRIGGER"; break; 644e5f9c644Sdrh case SQLITE_DROP_VIEW : zCode="SQLITE_DROP_VIEW"; break; 645e5f9c644Sdrh case SQLITE_INSERT : zCode="SQLITE_INSERT"; break; 646e5f9c644Sdrh case SQLITE_PRAGMA : zCode="SQLITE_PRAGMA"; break; 647e5f9c644Sdrh case SQLITE_READ : zCode="SQLITE_READ"; break; 648e5f9c644Sdrh case SQLITE_SELECT : zCode="SQLITE_SELECT"; break; 649e5f9c644Sdrh case SQLITE_TRANSACTION : zCode="SQLITE_TRANSACTION"; break; 650e5f9c644Sdrh case SQLITE_UPDATE : zCode="SQLITE_UPDATE"; break; 651e5f9c644Sdrh default : zCode="????"; break; 652ed6c8671Sdrh } 653ed6c8671Sdrh Tcl_DStringInit(&str); 654ed6c8671Sdrh Tcl_DStringAppend(&str, authInfo.zCmd, -1); 655ed6c8671Sdrh Tcl_DStringAppendElement(&str, zCode); 656e5f9c644Sdrh Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : ""); 657ed6c8671Sdrh Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : ""); 658ed6c8671Sdrh rc = Tcl_GlobalEval(authInfo.interp, Tcl_DStringValue(&str)); 659ed6c8671Sdrh Tcl_DStringFree(&str); 660ed6c8671Sdrh zReply = Tcl_GetStringResult(authInfo.interp); 661ed6c8671Sdrh if( strcmp(zReply,"SQLITE_OK")==0 ){ 662ed6c8671Sdrh rc = SQLITE_OK; 663ed6c8671Sdrh }else if( strcmp(zReply,"SQLITE_DENY")==0 ){ 664ed6c8671Sdrh rc = SQLITE_DENY; 665ed6c8671Sdrh }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){ 666ed6c8671Sdrh rc = SQLITE_IGNORE; 667ed6c8671Sdrh }else{ 668ed6c8671Sdrh rc = 999; 669ed6c8671Sdrh } 670ed6c8671Sdrh return rc; 671ed6c8671Sdrh } 672ed6c8671Sdrh 673ed6c8671Sdrh /* 674ed6c8671Sdrh ** This routine creates a new authenticator. It fills in the zCmd[] 675ed6c8671Sdrh ** field of the authentication function state variable and then registers 676ed6c8671Sdrh ** the authentication function with the SQLite library. 677ed6c8671Sdrh */ 678ed6c8671Sdrh static int test_set_authorizer( 679ed6c8671Sdrh void *NotUsed, 680ed6c8671Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 681ed6c8671Sdrh int argc, /* Number of arguments */ 682ed6c8671Sdrh char **argv /* Text of each argument */ 683ed6c8671Sdrh ){ 684ed6c8671Sdrh sqlite *db; 685ed6c8671Sdrh char *zCmd; 686ed6c8671Sdrh if( argc!=3 ){ 687ed6c8671Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 688ed6c8671Sdrh " DB CALLBACK\"", 0); 689ed6c8671Sdrh return TCL_ERROR; 690ed6c8671Sdrh } 691b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 692ed6c8671Sdrh zCmd = argv[2]; 693ed6c8671Sdrh if( zCmd[0]==0 ){ 694ed6c8671Sdrh sqlite_set_authorizer(db, 0, 0); 695ed6c8671Sdrh return TCL_OK; 696ed6c8671Sdrh } 697ed6c8671Sdrh if( strlen(zCmd)>sizeof(authInfo.zCmd) ){ 698ed6c8671Sdrh Tcl_AppendResult(interp, "command too big", 0); 699ed6c8671Sdrh return TCL_ERROR; 700ed6c8671Sdrh } 701ed6c8671Sdrh authInfo.interp = interp; 702ed6c8671Sdrh authInfo.nCmd = strlen(zCmd); 703ed6c8671Sdrh strcpy(authInfo.zCmd, zCmd); 704ed6c8671Sdrh sqlite_set_authorizer(db, auth_callback, 0); 705ed6c8671Sdrh return TCL_OK; 706ed6c8671Sdrh } 707ed6c8671Sdrh #endif /* SQLITE_OMIT_AUTHORIZATION */ 7085a38705eSdrh 709b86ccfb2Sdrh 710b86ccfb2Sdrh /* 711b86ccfb2Sdrh ** Usage: sqlite_compile DB SQL TAILVAR 712b86ccfb2Sdrh ** 713b86ccfb2Sdrh ** Attempt to compile an SQL statement. Return a pointer to the virtual 714b86ccfb2Sdrh ** machine used to execute that statement. Unprocessed SQL is written 715b86ccfb2Sdrh ** into TAILVAR. 716b86ccfb2Sdrh */ 717b86ccfb2Sdrh static int test_compile( 718b86ccfb2Sdrh void *NotUsed, 719b86ccfb2Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 720b86ccfb2Sdrh int argc, /* Number of arguments */ 721b86ccfb2Sdrh char **argv /* Text of each argument */ 722b86ccfb2Sdrh ){ 723b86ccfb2Sdrh sqlite *db; 724b86ccfb2Sdrh sqlite_vm *vm; 725b86ccfb2Sdrh int rc; 726b86ccfb2Sdrh char *zErr = 0; 727b86ccfb2Sdrh const char *zTail; 728b86ccfb2Sdrh char zBuf[50]; 729b86ccfb2Sdrh if( argc!=4 ){ 730b86ccfb2Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 731b86ccfb2Sdrh " DB SQL TAILVAR", 0); 732b86ccfb2Sdrh return TCL_ERROR; 733b86ccfb2Sdrh } 734b86ccfb2Sdrh if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 735b86ccfb2Sdrh rc = sqlite_compile(db, argv[2], &zTail, &vm, &zErr); 736483750baSdrh Tcl_SetVar(interp, argv[3], zTail, 0); 737b86ccfb2Sdrh if( rc ){ 738b86ccfb2Sdrh assert( vm==0 ); 739b86ccfb2Sdrh sprintf(zBuf, "(%d) ", rc); 740b86ccfb2Sdrh Tcl_AppendResult(interp, zBuf, zErr, 0); 741b86ccfb2Sdrh sqlite_freemem(zErr); 742b86ccfb2Sdrh return TCL_ERROR; 743b86ccfb2Sdrh } 744326dce74Sdrh if( vm ){ 745*94e92032Sdrh sprintf(zBuf, PTR_FMT, vm); 746b86ccfb2Sdrh Tcl_AppendResult(interp, zBuf, 0); 747326dce74Sdrh } 748b86ccfb2Sdrh return TCL_OK; 749b86ccfb2Sdrh } 750b86ccfb2Sdrh 751b86ccfb2Sdrh /* 752b86ccfb2Sdrh ** Usage: sqlite_step VM NVAR VALUEVAR COLNAMEVAR 753b86ccfb2Sdrh ** 754b86ccfb2Sdrh ** Step a virtual machine. Return a the result code as a string. 755b86ccfb2Sdrh ** Column results are written into three variables. 756b86ccfb2Sdrh */ 757b86ccfb2Sdrh static int test_step( 758b86ccfb2Sdrh void *NotUsed, 759b86ccfb2Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 760b86ccfb2Sdrh int argc, /* Number of arguments */ 761b86ccfb2Sdrh char **argv /* Text of each argument */ 762b86ccfb2Sdrh ){ 763b86ccfb2Sdrh sqlite_vm *vm; 764b86ccfb2Sdrh int rc, i; 7653a84069dSdrh const char **azValue = 0; 7663a84069dSdrh const char **azColName = 0; 7673a84069dSdrh int N = 0; 768b86ccfb2Sdrh char *zRc; 769b86ccfb2Sdrh char zBuf[50]; 770b86ccfb2Sdrh if( argc!=5 ){ 771b86ccfb2Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 772b86ccfb2Sdrh " VM NVAR VALUEVAR COLNAMEVAR", 0); 773b86ccfb2Sdrh return TCL_ERROR; 774b86ccfb2Sdrh } 775b86ccfb2Sdrh if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR; 776b86ccfb2Sdrh rc = sqlite_step(vm, &N, &azValue, &azColName); 777b86ccfb2Sdrh sprintf(zBuf, "%d", N); 778b86ccfb2Sdrh Tcl_SetVar(interp, argv[2], zBuf, 0); 779b86ccfb2Sdrh Tcl_SetVar(interp, argv[3], "", 0); 7803a84069dSdrh if( azValue ){ 781b86ccfb2Sdrh for(i=0; i<N; i++){ 782b86ccfb2Sdrh Tcl_SetVar(interp, argv[3], azValue[i] ? azValue[i] : "", 783b86ccfb2Sdrh TCL_APPEND_VALUE | TCL_LIST_ELEMENT); 784b86ccfb2Sdrh } 785b86ccfb2Sdrh } 786b86ccfb2Sdrh Tcl_SetVar(interp, argv[4], "", 0); 7873a84069dSdrh if( azColName ){ 788b86ccfb2Sdrh for(i=0; i<N*2; i++){ 789326dce74Sdrh Tcl_SetVar(interp, argv[4], azColName[i] ? azColName[i] : "", 790b86ccfb2Sdrh TCL_APPEND_VALUE | TCL_LIST_ELEMENT); 791b86ccfb2Sdrh } 792b86ccfb2Sdrh } 793b86ccfb2Sdrh switch( rc ){ 794b86ccfb2Sdrh case SQLITE_DONE: zRc = "SQLITE_DONE"; break; 795326dce74Sdrh case SQLITE_BUSY: zRc = "SQLITE_BUSY"; break; 796326dce74Sdrh case SQLITE_ROW: zRc = "SQLITE_ROW"; break; 797326dce74Sdrh case SQLITE_ERROR: zRc = "SQLITE_ERROR"; break; 798b86ccfb2Sdrh case SQLITE_MISUSE: zRc = "SQLITE_MISUSE"; break; 799b86ccfb2Sdrh default: zRc = "unknown"; break; 800b86ccfb2Sdrh } 801b86ccfb2Sdrh Tcl_AppendResult(interp, zRc, 0); 802b86ccfb2Sdrh return TCL_OK; 803b86ccfb2Sdrh } 804b86ccfb2Sdrh 805b86ccfb2Sdrh /* 806b86ccfb2Sdrh ** Usage: sqlite_finalize VM 807b86ccfb2Sdrh ** 808b86ccfb2Sdrh ** Shutdown a virtual machine. 809b86ccfb2Sdrh */ 810b86ccfb2Sdrh static int test_finalize( 811b86ccfb2Sdrh void *NotUsed, 812b86ccfb2Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 813b86ccfb2Sdrh int argc, /* Number of arguments */ 814b86ccfb2Sdrh char **argv /* Text of each argument */ 815b86ccfb2Sdrh ){ 816b86ccfb2Sdrh sqlite_vm *vm; 817b86ccfb2Sdrh int rc; 818b86ccfb2Sdrh char *zErrMsg = 0; 819b86ccfb2Sdrh if( argc!=2 ){ 820b86ccfb2Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 821326dce74Sdrh " VM\"", 0); 822b86ccfb2Sdrh return TCL_ERROR; 823b86ccfb2Sdrh } 824b86ccfb2Sdrh if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR; 825b86ccfb2Sdrh rc = sqlite_finalize(vm, &zErrMsg); 826b86ccfb2Sdrh if( rc ){ 827b86ccfb2Sdrh char zBuf[50]; 828b86ccfb2Sdrh sprintf(zBuf, "(%d) ", rc); 829b86ccfb2Sdrh Tcl_AppendResult(interp, zBuf, zErrMsg, 0); 830b86ccfb2Sdrh sqlite_freemem(zErrMsg); 831b86ccfb2Sdrh return TCL_ERROR; 832b86ccfb2Sdrh } 833b86ccfb2Sdrh return TCL_OK; 834b86ccfb2Sdrh } 835b86ccfb2Sdrh 8365a38705eSdrh /* 83799ee3600Sdrh ** Usage: breakpoint 83899ee3600Sdrh ** 83999ee3600Sdrh ** This routine exists for one purpose - to provide a place to put a 84099ee3600Sdrh ** breakpoint with GDB that can be triggered using TCL code. The use 84199ee3600Sdrh ** for this is when a particular test fails on (say) the 1485th iteration. 84299ee3600Sdrh ** In the TCL test script, we can add code like this: 84399ee3600Sdrh ** 84499ee3600Sdrh ** if {$i==1485} breakpoint 84599ee3600Sdrh ** 84699ee3600Sdrh ** Then run testfixture in the debugger and wait for the breakpoint to 84799ee3600Sdrh ** fire. Then additional breakpoints can be set to trace down the bug. 84899ee3600Sdrh */ 84999ee3600Sdrh static int test_breakpoint( 85099ee3600Sdrh void *NotUsed, 85199ee3600Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 85299ee3600Sdrh int argc, /* Number of arguments */ 85399ee3600Sdrh char **argv /* Text of each argument */ 85499ee3600Sdrh ){ 85599ee3600Sdrh return TCL_OK; /* Do nothing */ 85699ee3600Sdrh } 85799ee3600Sdrh 85899ee3600Sdrh /* 859d1bf3512Sdrh ** Register commands with the TCL interpreter. 860d1bf3512Sdrh */ 861d1bf3512Sdrh int Sqlitetest1_Init(Tcl_Interp *interp){ 862487ab3caSdrh extern int sqlite_search_count; 863*94e92032Sdrh extern int sqlite_open_file_count; 864c2eef3b3Sdrh static struct { 865c2eef3b3Sdrh char *zName; 866c2eef3b3Sdrh Tcl_CmdProc *xProc; 867c2eef3b3Sdrh } aCmd[] = { 868c2eef3b3Sdrh { "sqlite_mprintf_int", (Tcl_CmdProc*)sqlite_mprintf_int }, 869c2eef3b3Sdrh { "sqlite_mprintf_str", (Tcl_CmdProc*)sqlite_mprintf_str }, 870c2eef3b3Sdrh { "sqlite_mprintf_double", (Tcl_CmdProc*)sqlite_mprintf_double }, 871c2eef3b3Sdrh { "sqlite_open", (Tcl_CmdProc*)sqlite_test_open }, 872c2eef3b3Sdrh { "sqlite_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid }, 873c2eef3b3Sdrh { "sqlite_exec_printf", (Tcl_CmdProc*)test_exec_printf }, 874c2eef3b3Sdrh { "sqlite_get_table_printf", (Tcl_CmdProc*)test_get_table_printf }, 875c2eef3b3Sdrh { "sqlite_close", (Tcl_CmdProc*)sqlite_test_close }, 876c2eef3b3Sdrh { "sqlite_create_function", (Tcl_CmdProc*)test_create_function }, 877c2eef3b3Sdrh { "sqlite_create_aggregate", (Tcl_CmdProc*)test_create_aggregate }, 878c2eef3b3Sdrh { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func }, 879c2eef3b3Sdrh { "sqlite_abort", (Tcl_CmdProc*)sqlite_abort }, 8805a38705eSdrh { "sqlite_datatypes", (Tcl_CmdProc*)sqlite_datatypes }, 881ed6c8671Sdrh #ifndef SQLITE_OMIT_AUTHORIZATION 882ed6c8671Sdrh { "sqlite_set_authorizer", (Tcl_CmdProc*)test_set_authorizer }, 883ed6c8671Sdrh #endif 884c2eef3b3Sdrh #ifdef MEMORY_DEBUG 885c2eef3b3Sdrh { "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail }, 886c2eef3b3Sdrh { "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat }, 887c2eef3b3Sdrh #endif 888b86ccfb2Sdrh { "sqlite_compile", (Tcl_CmdProc*)test_compile }, 889b86ccfb2Sdrh { "sqlite_step", (Tcl_CmdProc*)test_step }, 890b86ccfb2Sdrh { "sqlite_finalize", (Tcl_CmdProc*)test_finalize }, 89199ee3600Sdrh { "breakpoint", (Tcl_CmdProc*)test_breakpoint }, 892c2eef3b3Sdrh }; 893c2eef3b3Sdrh int i; 894c2eef3b3Sdrh 895c2eef3b3Sdrh for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ 896c2eef3b3Sdrh Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); 897c2eef3b3Sdrh } 898487ab3caSdrh Tcl_LinkVar(interp, "sqlite_search_count", 899487ab3caSdrh (char*)&sqlite_search_count, TCL_LINK_INT); 900*94e92032Sdrh Tcl_LinkVar(interp, "sqlite_open_file_count", 901*94e92032Sdrh (char*)&sqlite_open_file_count, TCL_LINK_INT); 902d1bf3512Sdrh return TCL_OK; 903d1bf3512Sdrh } 904