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*e5f9c644Sdrh ** $Id: test1.c,v 1.16 2003/01/13 23:27:33 drh Exp $ 17d1bf3512Sdrh */ 18d1bf3512Sdrh #include "sqliteInt.h" 19d1bf3512Sdrh #include "tcl.h" 20d1bf3512Sdrh #include <stdlib.h> 21d1bf3512Sdrh #include <string.h> 22d1bf3512Sdrh 23d1bf3512Sdrh /* 24d1bf3512Sdrh ** Usage: sqlite_open filename 25d1bf3512Sdrh ** 26d1bf3512Sdrh ** Returns: The name of an open database. 27d1bf3512Sdrh */ 28d1bf3512Sdrh static int sqlite_test_open( 29d1bf3512Sdrh void *NotUsed, 30d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 31d1bf3512Sdrh int argc, /* Number of arguments */ 32d1bf3512Sdrh char **argv /* Text of each argument */ 33d1bf3512Sdrh ){ 34d1bf3512Sdrh sqlite *db; 35d1bf3512Sdrh char *zErr = 0; 36d1bf3512Sdrh char zBuf[100]; 37d1bf3512Sdrh if( argc!=2 ){ 38d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 39d1bf3512Sdrh " FILENAME\"", 0); 40d1bf3512Sdrh return TCL_ERROR; 41d1bf3512Sdrh } 42d1bf3512Sdrh db = sqlite_open(argv[1], 0666, &zErr); 43d1bf3512Sdrh if( db==0 ){ 44d1bf3512Sdrh Tcl_AppendResult(interp, zErr, 0); 45d1bf3512Sdrh free(zErr); 46d1bf3512Sdrh return TCL_ERROR; 47d1bf3512Sdrh } 48d1bf3512Sdrh sprintf(zBuf,"%d",(int)db); 49d1bf3512Sdrh Tcl_AppendResult(interp, zBuf, 0); 50d1bf3512Sdrh return TCL_OK; 51d1bf3512Sdrh } 52d1bf3512Sdrh 53d1bf3512Sdrh /* 54d1bf3512Sdrh ** The callback routine for sqlite_exec_printf(). 55d1bf3512Sdrh */ 56d1bf3512Sdrh static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){ 57d1bf3512Sdrh Tcl_DString *str = (Tcl_DString*)pArg; 58d1bf3512Sdrh int i; 59d1bf3512Sdrh 60d1bf3512Sdrh if( Tcl_DStringLength(str)==0 ){ 61d1bf3512Sdrh for(i=0; i<argc; i++){ 62d1bf3512Sdrh Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL"); 63d1bf3512Sdrh } 64d1bf3512Sdrh } 65d1bf3512Sdrh for(i=0; i<argc; i++){ 66d1bf3512Sdrh Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL"); 67d1bf3512Sdrh } 68d1bf3512Sdrh return 0; 69d1bf3512Sdrh } 70d1bf3512Sdrh 71d1bf3512Sdrh /* 72d1bf3512Sdrh ** Usage: sqlite_exec_printf DB FORMAT STRING 73d1bf3512Sdrh ** 74d1bf3512Sdrh ** Invoke the sqlite_exec_printf() interface using the open database 75d1bf3512Sdrh ** DB. The SQL is the string FORMAT. The format string should contain 76d1bf3512Sdrh ** one %s or %q. STRING is the value inserted into %s or %q. 77d1bf3512Sdrh */ 78d1bf3512Sdrh static int test_exec_printf( 79d1bf3512Sdrh void *NotUsed, 80d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 81d1bf3512Sdrh int argc, /* Number of arguments */ 82d1bf3512Sdrh char **argv /* Text of each argument */ 83d1bf3512Sdrh ){ 84d1bf3512Sdrh sqlite *db; 85d1bf3512Sdrh Tcl_DString str; 86d1bf3512Sdrh int rc; 87d1bf3512Sdrh char *zErr = 0; 88d1bf3512Sdrh char zBuf[30]; 89d1bf3512Sdrh if( argc!=4 ){ 90d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 91d1bf3512Sdrh " DB FORMAT STRING", 0); 92d1bf3512Sdrh return TCL_ERROR; 93d1bf3512Sdrh } 9406b2718aSdrh db = (sqlite*)strtol(argv[1], 0, 0); 95d1bf3512Sdrh Tcl_DStringInit(&str); 96d1bf3512Sdrh rc = sqlite_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]); 97d1bf3512Sdrh sprintf(zBuf, "%d", rc); 98d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 99d1bf3512Sdrh Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr); 100d1bf3512Sdrh Tcl_DStringFree(&str); 101d1bf3512Sdrh if( zErr ) free(zErr); 102d1bf3512Sdrh return TCL_OK; 103d1bf3512Sdrh } 104d1bf3512Sdrh 105d1bf3512Sdrh /* 106d1bf3512Sdrh ** Usage: sqlite_get_table_printf DB FORMAT STRING 107d1bf3512Sdrh ** 108d1bf3512Sdrh ** Invoke the sqlite_get_table_printf() interface using the open database 109d1bf3512Sdrh ** DB. The SQL is the string FORMAT. The format string should contain 110d1bf3512Sdrh ** one %s or %q. STRING is the value inserted into %s or %q. 111d1bf3512Sdrh */ 112d1bf3512Sdrh static int test_get_table_printf( 113d1bf3512Sdrh void *NotUsed, 114d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 115d1bf3512Sdrh int argc, /* Number of arguments */ 116d1bf3512Sdrh char **argv /* Text of each argument */ 117d1bf3512Sdrh ){ 118d1bf3512Sdrh sqlite *db; 119d1bf3512Sdrh Tcl_DString str; 120d1bf3512Sdrh int rc; 121d1bf3512Sdrh char *zErr = 0; 122d1bf3512Sdrh int nRow, nCol; 123d1bf3512Sdrh char **aResult; 124d1bf3512Sdrh int i; 125d1bf3512Sdrh char zBuf[30]; 126d1bf3512Sdrh if( argc!=4 ){ 127d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 128d1bf3512Sdrh " DB FORMAT STRING", 0); 129d1bf3512Sdrh return TCL_ERROR; 130d1bf3512Sdrh } 13106b2718aSdrh db = (sqlite*)strtol(argv[1], 0, 0); 132d1bf3512Sdrh Tcl_DStringInit(&str); 133d1bf3512Sdrh rc = sqlite_get_table_printf(db, argv[2], &aResult, &nRow, &nCol, 134d1bf3512Sdrh &zErr, argv[3]); 135d1bf3512Sdrh sprintf(zBuf, "%d", rc); 136d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 137d1bf3512Sdrh if( rc==SQLITE_OK ){ 138d1bf3512Sdrh sprintf(zBuf, "%d", nRow); 139d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 140d1bf3512Sdrh sprintf(zBuf, "%d", nCol); 141d1bf3512Sdrh Tcl_AppendElement(interp, zBuf); 142d1bf3512Sdrh for(i=0; i<(nRow+1)*nCol; i++){ 143d1bf3512Sdrh Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL"); 144d1bf3512Sdrh } 145d1bf3512Sdrh }else{ 146d1bf3512Sdrh Tcl_AppendElement(interp, zErr); 147d1bf3512Sdrh } 148d1bf3512Sdrh sqlite_free_table(aResult); 149d1bf3512Sdrh if( zErr ) free(zErr); 150d1bf3512Sdrh return TCL_OK; 151d1bf3512Sdrh } 152d1bf3512Sdrh 153af9ff33aSdrh 154af9ff33aSdrh /* 155af9ff33aSdrh ** Usage: sqlite_last_insert_rowid DB 156af9ff33aSdrh ** 157af9ff33aSdrh ** Returns the integer ROWID of the most recent insert. 158af9ff33aSdrh */ 159af9ff33aSdrh static int test_last_rowid( 160af9ff33aSdrh void *NotUsed, 161af9ff33aSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 162af9ff33aSdrh int argc, /* Number of arguments */ 163af9ff33aSdrh char **argv /* Text of each argument */ 164af9ff33aSdrh ){ 165af9ff33aSdrh sqlite *db; 166af9ff33aSdrh char zBuf[30]; 167af9ff33aSdrh 168af9ff33aSdrh if( argc!=2 ){ 169af9ff33aSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0); 170af9ff33aSdrh return TCL_ERROR; 171af9ff33aSdrh } 17206b2718aSdrh db = (sqlite*)strtol(argv[1], 0, 0); 173af9ff33aSdrh sprintf(zBuf, "%d", sqlite_last_insert_rowid(db)); 174af9ff33aSdrh Tcl_AppendResult(interp, zBuf, 0); 175af9ff33aSdrh return SQLITE_OK; 176af9ff33aSdrh } 177af9ff33aSdrh 178d1bf3512Sdrh /* 179d1bf3512Sdrh ** Usage: sqlite_close DB 180d1bf3512Sdrh ** 181d1bf3512Sdrh ** Closes the database opened by sqlite_open. 182d1bf3512Sdrh */ 183d1bf3512Sdrh static int sqlite_test_close( 184d1bf3512Sdrh void *NotUsed, 185d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 186d1bf3512Sdrh int argc, /* Number of arguments */ 187d1bf3512Sdrh char **argv /* Text of each argument */ 188d1bf3512Sdrh ){ 189d1bf3512Sdrh sqlite *db; 190d1bf3512Sdrh if( argc!=2 ){ 191d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 192d1bf3512Sdrh " FILENAME\"", 0); 193d1bf3512Sdrh return TCL_ERROR; 194d1bf3512Sdrh } 19506b2718aSdrh db = (sqlite*)strtol(argv[1], 0, 0); 196d1bf3512Sdrh sqlite_close(db); 197d1bf3512Sdrh return TCL_OK; 198d1bf3512Sdrh } 199d1bf3512Sdrh 200d1bf3512Sdrh /* 201c22bd47dSdrh ** Implementation of the x_coalesce() function. 202c22bd47dSdrh ** Return the first argument non-NULL argument. 203c22bd47dSdrh */ 204c22bd47dSdrh static void ifnullFunc(sqlite_func *context, int argc, const char **argv){ 205c22bd47dSdrh int i; 206c22bd47dSdrh for(i=0; i<argc; i++){ 207c22bd47dSdrh if( argv[i] ){ 208c22bd47dSdrh sqlite_set_result_string(context, argv[i], -1); 209c22bd47dSdrh break; 210c22bd47dSdrh } 211c22bd47dSdrh } 212c22bd47dSdrh } 213c22bd47dSdrh 214c22bd47dSdrh /* 215c22bd47dSdrh ** Implementation of the x_sqlite_exec() function. This function takes 216c22bd47dSdrh ** a single argument and attempts to execute that argument as SQL code. 2176cbe1f1bSdrh ** This is illegal and should set the SQLITE_MISUSE flag on the database. 218c22bd47dSdrh ** 219c22bd47dSdrh ** This routine simulates the effect of having two threads attempt to 220c22bd47dSdrh ** use the same database at the same time. 221c22bd47dSdrh */ 222c22bd47dSdrh static void sqliteExecFunc(sqlite_func *context, int argc, const char **argv){ 223c22bd47dSdrh sqlite_exec((sqlite*)sqlite_user_data(context), argv[0], 0, 0, 0); 224c22bd47dSdrh } 225c22bd47dSdrh 226c22bd47dSdrh /* 227c22bd47dSdrh ** Usage: sqlite_test_create_function DB 228c22bd47dSdrh ** 229c22bd47dSdrh ** Call the sqlite_create_function API on the given database in order 230c22bd47dSdrh ** to create a function named "x_coalesce". This function does the same thing 231c22bd47dSdrh ** as the "coalesce" function. This function also registers an SQL function 232c22bd47dSdrh ** named "x_sqlite_exec" that invokes sqlite_exec(). Invoking sqlite_exec() 233c22bd47dSdrh ** in this way is illegal recursion and should raise an SQLITE_MISUSE error. 234c22bd47dSdrh ** The effect is similar to trying to use the same database connection from 235c22bd47dSdrh ** two threads at the same time. 236c22bd47dSdrh ** 237c22bd47dSdrh ** The original motivation for this routine was to be able to call the 238c22bd47dSdrh ** sqlite_create_function function while a query is in progress in order 239c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic. 240c22bd47dSdrh */ 241c2eef3b3Sdrh static int test_create_function( 242c22bd47dSdrh void *NotUsed, 243c22bd47dSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 244c22bd47dSdrh int argc, /* Number of arguments */ 245c22bd47dSdrh char **argv /* Text of each argument */ 246c22bd47dSdrh ){ 247c22bd47dSdrh sqlite *db; 248c22bd47dSdrh extern void Md5_Register(sqlite*); 249c22bd47dSdrh if( argc!=2 ){ 250c22bd47dSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 251c22bd47dSdrh " FILENAME\"", 0); 252c22bd47dSdrh return TCL_ERROR; 253c22bd47dSdrh } 25406b2718aSdrh db = (sqlite*)strtol(argv[1], 0, 0); 255c22bd47dSdrh sqlite_create_function(db, "x_coalesce", -1, ifnullFunc, 0); 256c22bd47dSdrh sqlite_create_function(db, "x_sqlite_exec", 1, sqliteExecFunc, db); 257c22bd47dSdrh return TCL_OK; 258c22bd47dSdrh } 259c22bd47dSdrh 260c22bd47dSdrh /* 261c22bd47dSdrh ** Routines to implement the x_count() aggregate function. 262c22bd47dSdrh */ 263c22bd47dSdrh typedef struct CountCtx CountCtx; 264c22bd47dSdrh struct CountCtx { 265c22bd47dSdrh int n; 266c22bd47dSdrh }; 267c22bd47dSdrh static void countStep(sqlite_func *context, int argc, const char **argv){ 268c22bd47dSdrh CountCtx *p; 269c22bd47dSdrh p = sqlite_aggregate_context(context, sizeof(*p)); 270c22bd47dSdrh if( (argc==0 || argv[0]) && p ){ 271c22bd47dSdrh p->n++; 272c22bd47dSdrh } 273c22bd47dSdrh } 274c22bd47dSdrh static void countFinalize(sqlite_func *context){ 275c22bd47dSdrh CountCtx *p; 276c22bd47dSdrh p = sqlite_aggregate_context(context, sizeof(*p)); 277c22bd47dSdrh sqlite_set_result_int(context, p ? p->n : 0); 278c22bd47dSdrh } 279c22bd47dSdrh 280c22bd47dSdrh /* 281c22bd47dSdrh ** Usage: sqlite_test_create_aggregate DB 282c22bd47dSdrh ** 283c22bd47dSdrh ** Call the sqlite_create_function API on the given database in order 284c22bd47dSdrh ** to create a function named "x_count". This function does the same thing 285c22bd47dSdrh ** as the "md5sum" function. 286c22bd47dSdrh ** 287c22bd47dSdrh ** The original motivation for this routine was to be able to call the 288c22bd47dSdrh ** sqlite_create_aggregate function while a query is in progress in order 289c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic. 290c22bd47dSdrh */ 291c2eef3b3Sdrh static int test_create_aggregate( 292c22bd47dSdrh void *NotUsed, 293c22bd47dSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 294c22bd47dSdrh int argc, /* Number of arguments */ 295c22bd47dSdrh char **argv /* Text of each argument */ 296c22bd47dSdrh ){ 297c22bd47dSdrh sqlite *db; 298c22bd47dSdrh if( argc!=2 ){ 299c22bd47dSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 300c22bd47dSdrh " FILENAME\"", 0); 301c22bd47dSdrh return TCL_ERROR; 302c22bd47dSdrh } 30306b2718aSdrh db = (sqlite*)strtol(argv[1], 0, 0); 304c22bd47dSdrh sqlite_create_aggregate(db, "x_count", 0, countStep, countFinalize, 0); 305c22bd47dSdrh sqlite_create_aggregate(db, "x_count", 1, countStep, countFinalize, 0); 306c22bd47dSdrh return TCL_OK; 307c22bd47dSdrh } 308c22bd47dSdrh 309c22bd47dSdrh 310c22bd47dSdrh 311c22bd47dSdrh /* 312d1bf3512Sdrh ** Usage: sqlite_mprintf_int FORMAT INTEGER INTEGER INTEGER 313d1bf3512Sdrh ** 314d1bf3512Sdrh ** Call mprintf with three integer arguments 315d1bf3512Sdrh */ 316d1bf3512Sdrh static int sqlite_mprintf_int( 317d1bf3512Sdrh void *NotUsed, 318d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 319d1bf3512Sdrh int argc, /* Number of arguments */ 320d1bf3512Sdrh char **argv /* Text of each argument */ 321d1bf3512Sdrh ){ 322d1bf3512Sdrh int a[3], i; 323d1bf3512Sdrh char *z; 324d1bf3512Sdrh if( argc!=5 ){ 325d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 326d1bf3512Sdrh " FORMAT INT INT INT\"", 0); 327d1bf3512Sdrh return TCL_ERROR; 328d1bf3512Sdrh } 329d1bf3512Sdrh for(i=2; i<5; i++){ 330d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 331d1bf3512Sdrh } 332d1bf3512Sdrh z = sqlite_mprintf(argv[1], a[0], a[1], a[2]); 333d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 334fa173a76Sdrh sqlite_freemem(z); 335d1bf3512Sdrh return TCL_OK; 336d1bf3512Sdrh } 337d1bf3512Sdrh 338d1bf3512Sdrh /* 339d1bf3512Sdrh ** Usage: sqlite_mprintf_str FORMAT INTEGER INTEGER STRING 340d1bf3512Sdrh ** 341d1bf3512Sdrh ** Call mprintf with two integer arguments and one string argument 342d1bf3512Sdrh */ 343d1bf3512Sdrh static int sqlite_mprintf_str( 344d1bf3512Sdrh void *NotUsed, 345d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 346d1bf3512Sdrh int argc, /* Number of arguments */ 347d1bf3512Sdrh char **argv /* Text of each argument */ 348d1bf3512Sdrh ){ 349d1bf3512Sdrh int a[3], i; 350d1bf3512Sdrh char *z; 351f220b24fSchw if( argc<4 || argc>5 ){ 352d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 353f220b24fSchw " FORMAT INT INT ?STRING?\"", 0); 354d1bf3512Sdrh return TCL_ERROR; 355d1bf3512Sdrh } 356d1bf3512Sdrh for(i=2; i<4; i++){ 357d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 358d1bf3512Sdrh } 359f220b24fSchw z = sqlite_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL); 360d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 361fa173a76Sdrh sqlite_freemem(z); 362d1bf3512Sdrh return TCL_OK; 363d1bf3512Sdrh } 364d1bf3512Sdrh 365d1bf3512Sdrh /* 366d1bf3512Sdrh ** Usage: sqlite_mprintf_str FORMAT INTEGER INTEGER DOUBLE 367d1bf3512Sdrh ** 368d1bf3512Sdrh ** Call mprintf with two integer arguments and one double argument 369d1bf3512Sdrh */ 370d1bf3512Sdrh static int sqlite_mprintf_double( 371d1bf3512Sdrh void *NotUsed, 372d1bf3512Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 373d1bf3512Sdrh int argc, /* Number of arguments */ 374d1bf3512Sdrh char **argv /* Text of each argument */ 375d1bf3512Sdrh ){ 376d1bf3512Sdrh int a[3], i; 377d1bf3512Sdrh double r; 378d1bf3512Sdrh char *z; 379d1bf3512Sdrh if( argc!=5 ){ 380d1bf3512Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 381d1bf3512Sdrh " FORMAT INT INT STRING\"", 0); 382d1bf3512Sdrh return TCL_ERROR; 383d1bf3512Sdrh } 384d1bf3512Sdrh for(i=2; i<4; i++){ 385d1bf3512Sdrh if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 386d1bf3512Sdrh } 387d1bf3512Sdrh if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR; 388d1bf3512Sdrh z = sqlite_mprintf(argv[1], a[0], a[1], r); 389d1bf3512Sdrh Tcl_AppendResult(interp, z, 0); 390fa173a76Sdrh sqlite_freemem(z); 391d1bf3512Sdrh return TCL_OK; 392d1bf3512Sdrh } 393d1bf3512Sdrh 394d1bf3512Sdrh /* 395daffd0e5Sdrh ** Usage: sqlite_malloc_fail N 396daffd0e5Sdrh ** 397afa4a020Sdrh ** Rig sqliteMalloc() to fail on the N-th call. Turn off this mechanism 398daffd0e5Sdrh ** and reset the sqlite_malloc_failed variable is N==0. 399daffd0e5Sdrh */ 400daffd0e5Sdrh #ifdef MEMORY_DEBUG 401daffd0e5Sdrh static int sqlite_malloc_fail( 402daffd0e5Sdrh void *NotUsed, 403daffd0e5Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 404daffd0e5Sdrh int argc, /* Number of arguments */ 405daffd0e5Sdrh char **argv /* Text of each argument */ 406daffd0e5Sdrh ){ 407daffd0e5Sdrh int n; 408daffd0e5Sdrh if( argc!=2 ){ 409daffd0e5Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0); 410daffd0e5Sdrh return TCL_ERROR; 411daffd0e5Sdrh } 412daffd0e5Sdrh if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR; 413daffd0e5Sdrh sqlite_iMallocFail = n; 414daffd0e5Sdrh sqlite_malloc_failed = 0; 415daffd0e5Sdrh return TCL_OK; 416daffd0e5Sdrh } 417daffd0e5Sdrh #endif 418daffd0e5Sdrh 419daffd0e5Sdrh /* 420daffd0e5Sdrh ** Usage: sqlite_malloc_stat 421daffd0e5Sdrh ** 422daffd0e5Sdrh ** Return the number of prior calls to sqliteMalloc() and sqliteFree(). 423daffd0e5Sdrh */ 424daffd0e5Sdrh #ifdef MEMORY_DEBUG 425daffd0e5Sdrh static int sqlite_malloc_stat( 426daffd0e5Sdrh void *NotUsed, 427daffd0e5Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 428daffd0e5Sdrh int argc, /* Number of arguments */ 429daffd0e5Sdrh char **argv /* Text of each argument */ 430daffd0e5Sdrh ){ 431daffd0e5Sdrh char zBuf[200]; 432daffd0e5Sdrh sprintf(zBuf, "%d %d %d", sqlite_nMalloc, sqlite_nFree, sqlite_iMallocFail); 433daffd0e5Sdrh Tcl_AppendResult(interp, zBuf, 0); 434daffd0e5Sdrh return TCL_OK; 435daffd0e5Sdrh } 436daffd0e5Sdrh #endif 437daffd0e5Sdrh 438daffd0e5Sdrh /* 43928b4e489Sdrh ** Usage: sqlite_abort 44028b4e489Sdrh ** 44128b4e489Sdrh ** Shutdown the process immediately. This is not a clean shutdown. 44228b4e489Sdrh ** This command is used to test the recoverability of a database in 44328b4e489Sdrh ** the event of a program crash. 44428b4e489Sdrh */ 44528b4e489Sdrh static int sqlite_abort( 44628b4e489Sdrh void *NotUsed, 44728b4e489Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 44828b4e489Sdrh int argc, /* Number of arguments */ 44928b4e489Sdrh char **argv /* Text of each argument */ 45028b4e489Sdrh ){ 45128b4e489Sdrh assert( interp==0 ); /* This will always fail */ 45228b4e489Sdrh return TCL_OK; 45328b4e489Sdrh } 45428b4e489Sdrh 45528b4e489Sdrh /* 4566cbe1f1bSdrh ** The following routine is a user-defined SQL function whose purpose 4576cbe1f1bSdrh ** is to test the sqlite_set_result() API. 4586cbe1f1bSdrh */ 4596cbe1f1bSdrh static void testFunc(sqlite_func *context, int argc, const char **argv){ 4606cbe1f1bSdrh while( argc>=2 ){ 4616cbe1f1bSdrh if( argv[0]==0 ){ 4626cbe1f1bSdrh sqlite_set_result_error(context, "first argument to test function " 4636cbe1f1bSdrh "may not be NULL", -1); 4646cbe1f1bSdrh }else if( sqliteStrICmp(argv[0],"string")==0 ){ 4656cbe1f1bSdrh sqlite_set_result_string(context, argv[1], -1); 4666cbe1f1bSdrh }else if( argv[1]==0 ){ 4676cbe1f1bSdrh sqlite_set_result_error(context, "2nd argument may not be NULL if the " 4686cbe1f1bSdrh "first argument is not \"string\"", -1); 4696cbe1f1bSdrh }else if( sqliteStrICmp(argv[0],"int")==0 ){ 4706cbe1f1bSdrh sqlite_set_result_int(context, atoi(argv[1])); 4716cbe1f1bSdrh }else if( sqliteStrICmp(argv[0],"double")==0 ){ 4726cbe1f1bSdrh sqlite_set_result_double(context, atof(argv[1])); 4736cbe1f1bSdrh }else{ 4746cbe1f1bSdrh sqlite_set_result_error(context,"first argument should be one of: " 4756cbe1f1bSdrh "string int double", -1); 4766cbe1f1bSdrh } 4776cbe1f1bSdrh argc -= 2; 4786cbe1f1bSdrh argv += 2; 4796cbe1f1bSdrh } 4806cbe1f1bSdrh } 4816cbe1f1bSdrh 4826cbe1f1bSdrh /* 4836cbe1f1bSdrh ** Usage: sqlite_register_test_function DB NAME 4846cbe1f1bSdrh ** 4856cbe1f1bSdrh ** Register the test SQL function on the database DB under the name NAME. 4866cbe1f1bSdrh */ 487c2eef3b3Sdrh static int test_register_func( 4886cbe1f1bSdrh void *NotUsed, 4896cbe1f1bSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 4906cbe1f1bSdrh int argc, /* Number of arguments */ 4916cbe1f1bSdrh char **argv /* Text of each argument */ 4926cbe1f1bSdrh ){ 4936cbe1f1bSdrh sqlite *db; 4946cbe1f1bSdrh int rc; 4956cbe1f1bSdrh if( argc!=3 ){ 4966cbe1f1bSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 4976cbe1f1bSdrh " DB FUNCTION-NAME", 0); 4986cbe1f1bSdrh return TCL_ERROR; 4996cbe1f1bSdrh } 5006cbe1f1bSdrh db = (sqlite*)strtol(argv[1], 0, 0); 5016cbe1f1bSdrh rc = sqlite_create_function(db, argv[2], -1, testFunc, 0); 5026cbe1f1bSdrh if( rc!=0 ){ 5036cbe1f1bSdrh Tcl_AppendResult(interp, sqlite_error_string(rc), 0); 5046cbe1f1bSdrh return TCL_ERROR; 5056cbe1f1bSdrh } 5066cbe1f1bSdrh return TCL_OK; 5076cbe1f1bSdrh } 5086cbe1f1bSdrh 5096cbe1f1bSdrh /* 5105a38705eSdrh ** This SQLite callback records the datatype of all columns. 5115a38705eSdrh ** 5125a38705eSdrh ** The pArg argument is really a pointer to a TCL interpreter. The 5135a38705eSdrh ** column names are inserted as the result of this interpreter. 5145a38705eSdrh ** 5155a38705eSdrh ** This routine returns non-zero which causes the query to abort. 5165a38705eSdrh */ 5175a38705eSdrh static int rememberDataTypes(void *pArg, int nCol, char **argv, char **colv){ 5185a38705eSdrh int i; 5195a38705eSdrh Tcl_Interp *interp = (Tcl_Interp*)pArg; 5205a38705eSdrh Tcl_Obj *pList, *pElem; 5215a38705eSdrh if( colv[nCol+1]==0 ){ 5225a38705eSdrh return 1; 5235a38705eSdrh } 5245a38705eSdrh pList = Tcl_NewObj(); 5255a38705eSdrh for(i=0; i<nCol; i++){ 5265a38705eSdrh pElem = Tcl_NewStringObj(colv[i+nCol] ? colv[i+nCol] : "NULL", -1); 5275a38705eSdrh Tcl_ListObjAppendElement(interp, pList, pElem); 5285a38705eSdrh } 5295a38705eSdrh Tcl_SetObjResult(interp, pList); 5305a38705eSdrh return 1; 5315a38705eSdrh } 5325a38705eSdrh 5335a38705eSdrh /* 5345a38705eSdrh ** Invoke an SQL statement but ignore all the data in the result. Instead, 5355a38705eSdrh ** return a list that consists of the datatypes of the various columns. 5365a38705eSdrh ** 5375a38705eSdrh ** This only works if "PRAGMA show_datatypes=on" has been executed against 5385a38705eSdrh ** the database connection. 5395a38705eSdrh */ 5405a38705eSdrh static int sqlite_datatypes( 5415a38705eSdrh void *NotUsed, 5425a38705eSdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 5435a38705eSdrh int argc, /* Number of arguments */ 5445a38705eSdrh char **argv /* Text of each argument */ 5455a38705eSdrh ){ 5465a38705eSdrh sqlite *db; 5475a38705eSdrh int rc; 5485a38705eSdrh if( argc!=3 ){ 5495a38705eSdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 5505a38705eSdrh " DB SQL", 0); 5515a38705eSdrh return TCL_ERROR; 5525a38705eSdrh } 5535a38705eSdrh db = (sqlite*)strtol(argv[1], 0, 0); 5545a38705eSdrh rc = sqlite_exec(db, argv[2], rememberDataTypes, interp, 0); 5555a38705eSdrh if( rc!=0 && rc!=SQLITE_ABORT ){ 5565a38705eSdrh Tcl_AppendResult(interp, sqlite_error_string(rc), 0); 5575a38705eSdrh return TCL_ERROR; 5585a38705eSdrh } 5595a38705eSdrh return TCL_OK; 5605a38705eSdrh } 5615a38705eSdrh 562ed6c8671Sdrh #ifndef SQLITE_OMIT_AUTHORIZATION 563ed6c8671Sdrh /* 564ed6c8671Sdrh ** Information used by the authentication function. 565ed6c8671Sdrh */ 566ed6c8671Sdrh typedef struct AuthInfo AuthInfo; 567ed6c8671Sdrh struct AuthInfo { 568ed6c8671Sdrh Tcl_Interp *interp; /* Interpreter to use */ 569ed6c8671Sdrh int nCmd; /* Number of characters in zCmd[] */ 570ed6c8671Sdrh char zCmd[500]; /* Command to invoke */ 571ed6c8671Sdrh }; 572ed6c8671Sdrh 573ed6c8671Sdrh /* 574ed6c8671Sdrh ** We create a single static authenticator. This won't work in a 575ed6c8671Sdrh ** multi-threaded environment, but the test fixture is not multithreaded. 576ed6c8671Sdrh ** And be making it static, we don't have to worry about deallocating 577ed6c8671Sdrh ** after a test in order to void memory leaks. 578ed6c8671Sdrh */ 579ed6c8671Sdrh static AuthInfo authInfo; 580ed6c8671Sdrh 581ed6c8671Sdrh /* 582ed6c8671Sdrh ** This is the authentication function. It appends the authentication 583ed6c8671Sdrh ** type code and the two arguments to zCmd[] then invokes the result 584ed6c8671Sdrh ** on the interpreter. The reply is examined to determine if the 585ed6c8671Sdrh ** authentication fails or succeeds. 586ed6c8671Sdrh */ 587ed6c8671Sdrh static int auth_callback( 588ed6c8671Sdrh void *NotUsed, 589ed6c8671Sdrh int code, 590ed6c8671Sdrh const char *zArg1, 591ed6c8671Sdrh const char *zArg2 592ed6c8671Sdrh ){ 593ed6c8671Sdrh char *zCode; 594ed6c8671Sdrh Tcl_DString str; 595ed6c8671Sdrh int rc; 596ed6c8671Sdrh const char *zReply; 597ed6c8671Sdrh switch( code ){ 598*e5f9c644Sdrh case SQLITE_COPY : zCode="SQLITE_COPY"; break; 599*e5f9c644Sdrh case SQLITE_CREATE_INDEX : zCode="SQLITE_CREATE_INDEX"; break; 600*e5f9c644Sdrh case SQLITE_CREATE_TABLE : zCode="SQLITE_CREATE_TABLE"; break; 601*e5f9c644Sdrh case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break; 602*e5f9c644Sdrh case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break; 603*e5f9c644Sdrh case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break; 604*e5f9c644Sdrh case SQLITE_CREATE_TEMP_VIEW : zCode="SQLITE_CREATE_TEMP_VIEW"; break; 605*e5f9c644Sdrh case SQLITE_CREATE_TRIGGER : zCode="SQLITE_CREATE_TRIGGER"; break; 606*e5f9c644Sdrh case SQLITE_CREATE_VIEW : zCode="SQLITE_CREATE_VIEW"; break; 607*e5f9c644Sdrh case SQLITE_DELETE : zCode="SQLITE_DELETE"; break; 608*e5f9c644Sdrh case SQLITE_DROP_INDEX : zCode="SQLITE_DROP_INDEX"; break; 609*e5f9c644Sdrh case SQLITE_DROP_TABLE : zCode="SQLITE_DROP_TABLE"; break; 610*e5f9c644Sdrh case SQLITE_DROP_TEMP_INDEX : zCode="SQLITE_DROP_TEMP_INDEX"; break; 611*e5f9c644Sdrh case SQLITE_DROP_TEMP_TABLE : zCode="SQLITE_DROP_TEMP_TABLE"; break; 612*e5f9c644Sdrh case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break; 613*e5f9c644Sdrh case SQLITE_DROP_TEMP_VIEW : zCode="SQLITE_DROP_TEMP_VIEW"; break; 614*e5f9c644Sdrh case SQLITE_DROP_TRIGGER : zCode="SQLITE_DROP_TRIGGER"; break; 615*e5f9c644Sdrh case SQLITE_DROP_VIEW : zCode="SQLITE_DROP_VIEW"; break; 616*e5f9c644Sdrh case SQLITE_INSERT : zCode="SQLITE_INSERT"; break; 617*e5f9c644Sdrh case SQLITE_PRAGMA : zCode="SQLITE_PRAGMA"; break; 618*e5f9c644Sdrh case SQLITE_READ : zCode="SQLITE_READ"; break; 619*e5f9c644Sdrh case SQLITE_SELECT : zCode="SQLITE_SELECT"; break; 620*e5f9c644Sdrh case SQLITE_TRANSACTION : zCode="SQLITE_TRANSACTION"; break; 621*e5f9c644Sdrh case SQLITE_UPDATE : zCode="SQLITE_UPDATE"; break; 622*e5f9c644Sdrh default : zCode="????"; break; 623ed6c8671Sdrh } 624ed6c8671Sdrh Tcl_DStringInit(&str); 625ed6c8671Sdrh Tcl_DStringAppend(&str, authInfo.zCmd, -1); 626ed6c8671Sdrh Tcl_DStringAppendElement(&str, zCode); 627*e5f9c644Sdrh Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : ""); 628ed6c8671Sdrh Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : ""); 629ed6c8671Sdrh rc = Tcl_GlobalEval(authInfo.interp, Tcl_DStringValue(&str)); 630ed6c8671Sdrh Tcl_DStringFree(&str); 631ed6c8671Sdrh zReply = Tcl_GetStringResult(authInfo.interp); 632ed6c8671Sdrh if( strcmp(zReply,"SQLITE_OK")==0 ){ 633ed6c8671Sdrh rc = SQLITE_OK; 634ed6c8671Sdrh }else if( strcmp(zReply,"SQLITE_DENY")==0 ){ 635ed6c8671Sdrh rc = SQLITE_DENY; 636ed6c8671Sdrh }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){ 637ed6c8671Sdrh rc = SQLITE_IGNORE; 638ed6c8671Sdrh }else{ 639ed6c8671Sdrh rc = 999; 640ed6c8671Sdrh } 641ed6c8671Sdrh return rc; 642ed6c8671Sdrh } 643ed6c8671Sdrh 644ed6c8671Sdrh /* 645ed6c8671Sdrh ** This routine creates a new authenticator. It fills in the zCmd[] 646ed6c8671Sdrh ** field of the authentication function state variable and then registers 647ed6c8671Sdrh ** the authentication function with the SQLite library. 648ed6c8671Sdrh */ 649ed6c8671Sdrh static int test_set_authorizer( 650ed6c8671Sdrh void *NotUsed, 651ed6c8671Sdrh Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 652ed6c8671Sdrh int argc, /* Number of arguments */ 653ed6c8671Sdrh char **argv /* Text of each argument */ 654ed6c8671Sdrh ){ 655ed6c8671Sdrh sqlite *db; 656ed6c8671Sdrh char *zCmd; 657ed6c8671Sdrh if( argc!=3 ){ 658ed6c8671Sdrh Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 659ed6c8671Sdrh " DB CALLBACK\"", 0); 660ed6c8671Sdrh return TCL_ERROR; 661ed6c8671Sdrh } 662ed6c8671Sdrh db = (sqlite*)strtol(argv[1], 0, 0); 663ed6c8671Sdrh zCmd = argv[2]; 664ed6c8671Sdrh if( zCmd[0]==0 ){ 665ed6c8671Sdrh sqlite_set_authorizer(db, 0, 0); 666ed6c8671Sdrh return TCL_OK; 667ed6c8671Sdrh } 668ed6c8671Sdrh if( strlen(zCmd)>sizeof(authInfo.zCmd) ){ 669ed6c8671Sdrh Tcl_AppendResult(interp, "command too big", 0); 670ed6c8671Sdrh return TCL_ERROR; 671ed6c8671Sdrh } 672ed6c8671Sdrh authInfo.interp = interp; 673ed6c8671Sdrh authInfo.nCmd = strlen(zCmd); 674ed6c8671Sdrh strcpy(authInfo.zCmd, zCmd); 675ed6c8671Sdrh sqlite_set_authorizer(db, auth_callback, 0); 676ed6c8671Sdrh return TCL_OK; 677ed6c8671Sdrh } 678ed6c8671Sdrh #endif /* SQLITE_OMIT_AUTHORIZATION */ 6795a38705eSdrh 6805a38705eSdrh /* 681d1bf3512Sdrh ** Register commands with the TCL interpreter. 682d1bf3512Sdrh */ 683d1bf3512Sdrh int Sqlitetest1_Init(Tcl_Interp *interp){ 684487ab3caSdrh extern int sqlite_search_count; 685c2eef3b3Sdrh static struct { 686c2eef3b3Sdrh char *zName; 687c2eef3b3Sdrh Tcl_CmdProc *xProc; 688c2eef3b3Sdrh } aCmd[] = { 689c2eef3b3Sdrh { "sqlite_mprintf_int", (Tcl_CmdProc*)sqlite_mprintf_int }, 690c2eef3b3Sdrh { "sqlite_mprintf_str", (Tcl_CmdProc*)sqlite_mprintf_str }, 691c2eef3b3Sdrh { "sqlite_mprintf_double", (Tcl_CmdProc*)sqlite_mprintf_double }, 692c2eef3b3Sdrh { "sqlite_open", (Tcl_CmdProc*)sqlite_test_open }, 693c2eef3b3Sdrh { "sqlite_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid }, 694c2eef3b3Sdrh { "sqlite_exec_printf", (Tcl_CmdProc*)test_exec_printf }, 695c2eef3b3Sdrh { "sqlite_get_table_printf", (Tcl_CmdProc*)test_get_table_printf }, 696c2eef3b3Sdrh { "sqlite_close", (Tcl_CmdProc*)sqlite_test_close }, 697c2eef3b3Sdrh { "sqlite_create_function", (Tcl_CmdProc*)test_create_function }, 698c2eef3b3Sdrh { "sqlite_create_aggregate", (Tcl_CmdProc*)test_create_aggregate }, 699c2eef3b3Sdrh { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func }, 700c2eef3b3Sdrh { "sqlite_abort", (Tcl_CmdProc*)sqlite_abort }, 7015a38705eSdrh { "sqlite_datatypes", (Tcl_CmdProc*)sqlite_datatypes }, 702ed6c8671Sdrh #ifndef SQLITE_OMIT_AUTHORIZATION 703ed6c8671Sdrh { "sqlite_set_authorizer", (Tcl_CmdProc*)test_set_authorizer }, 704ed6c8671Sdrh #endif 705c2eef3b3Sdrh #ifdef MEMORY_DEBUG 706c2eef3b3Sdrh { "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail }, 707c2eef3b3Sdrh { "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat }, 708c2eef3b3Sdrh #endif 709c2eef3b3Sdrh }; 710c2eef3b3Sdrh int i; 711c2eef3b3Sdrh 712c2eef3b3Sdrh for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ 713c2eef3b3Sdrh Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); 714c2eef3b3Sdrh } 715487ab3caSdrh Tcl_LinkVar(interp, "sqlite_search_count", 716487ab3caSdrh (char*)&sqlite_search_count, TCL_LINK_INT); 717d1bf3512Sdrh return TCL_OK; 718d1bf3512Sdrh } 719