1 /* 2 ** 2001 September 15 3 ** 4 ** The author disclaims copyright to this source code. In place of 5 ** a legal notice, here is a blessing: 6 ** 7 ** May you do good and not evil. 8 ** May you find forgiveness for yourself and forgive others. 9 ** May you share freely, never taking more than you give. 10 ** 11 ************************************************************************* 12 ** Code for testing the printf() interface to SQLite. This code 13 ** is not included in the SQLite library. It is used for automated 14 ** testing of the SQLite library. 15 ** 16 ** $Id: test1.c,v 1.26 2003/07/09 00:28:15 drh Exp $ 17 */ 18 #include "sqliteInt.h" 19 #include "tcl.h" 20 #include "os.h" 21 #include <stdlib.h> 22 #include <string.h> 23 24 #if OS_WIN 25 # define PTR_FMT "%x" 26 #else 27 # define PTR_FMT "%p" 28 #endif 29 30 /* 31 ** Decode a pointer to an sqlite object. 32 */ 33 static int getDbPointer(Tcl_Interp *interp, const char *zArg, sqlite **ppDb){ 34 if( sscanf(zArg, PTR_FMT, (void**)ppDb)!=1 ){ 35 Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0); 36 return TCL_ERROR; 37 } 38 return TCL_OK; 39 } 40 41 /* 42 ** Decode a pointer to an sqlite_vm object. 43 */ 44 static int getVmPointer(Tcl_Interp *interp, const char *zArg, sqlite_vm **ppVm){ 45 if( sscanf(zArg, PTR_FMT, (void**)ppVm)!=1 ){ 46 Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0); 47 return TCL_ERROR; 48 } 49 return TCL_OK; 50 } 51 52 /* 53 ** Generate a text representation of a pointer that can be understood 54 ** by the getDbPointer and getVmPointer routines above. 55 ** 56 ** The problem is, on some machines (Solaris) if you do a printf with 57 ** "%p" you cannot turn around and do a scanf with the same "%p" and 58 ** get your pointer back. You have to prepend a "0x" before it will 59 ** work. Or at least that is what is reported to me (drh). But this 60 ** behavior varies from machine to machine. The solution used her is 61 ** to test the string right after it is generated to see if it can be 62 ** understood by scanf, and if not, try prepending an "0x" to see if 63 ** that helps. If nothing works, a fatal error is generated. 64 */ 65 static int makePointerStr(Tcl_Interp *interp, char *zPtr, void *p){ 66 void *p2; 67 sprintf(zPtr, PTR_FMT, p); 68 if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){ 69 sprintf(zPtr, "0x" PTR_FMT, p); 70 if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){ 71 Tcl_AppendResult(interp, "unable to convert a pointer to a string " 72 "in the file " __FILE__ " in function makePointerStr(). Please " 73 "report this problem to the SQLite mailing list or as a new but " 74 "report. Please provide detailed information about how you compiled " 75 "SQLite and what computer you are running on.", 0); 76 return TCL_ERROR; 77 } 78 } 79 return TCL_OK; 80 } 81 82 /* 83 ** Usage: sqlite_open filename 84 ** 85 ** Returns: The name of an open database. 86 */ 87 static int sqlite_test_open( 88 void *NotUsed, 89 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 90 int argc, /* Number of arguments */ 91 char **argv /* Text of each argument */ 92 ){ 93 sqlite *db; 94 char *zErr = 0; 95 char zBuf[100]; 96 if( argc!=2 ){ 97 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 98 " FILENAME\"", 0); 99 return TCL_ERROR; 100 } 101 db = sqlite_open(argv[1], 0666, &zErr); 102 if( db==0 ){ 103 Tcl_AppendResult(interp, zErr, 0); 104 free(zErr); 105 return TCL_ERROR; 106 } 107 if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR; 108 Tcl_AppendResult(interp, zBuf, 0); 109 return TCL_OK; 110 } 111 112 /* 113 ** The callback routine for sqlite_exec_printf(). 114 */ 115 static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){ 116 Tcl_DString *str = (Tcl_DString*)pArg; 117 int i; 118 119 if( Tcl_DStringLength(str)==0 ){ 120 for(i=0; i<argc; i++){ 121 Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL"); 122 } 123 } 124 for(i=0; i<argc; i++){ 125 Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL"); 126 } 127 return 0; 128 } 129 130 /* 131 ** Usage: sqlite_exec_printf DB FORMAT STRING 132 ** 133 ** Invoke the sqlite_exec_printf() interface using the open database 134 ** DB. The SQL is the string FORMAT. The format string should contain 135 ** one %s or %q. STRING is the value inserted into %s or %q. 136 */ 137 static int test_exec_printf( 138 void *NotUsed, 139 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 140 int argc, /* Number of arguments */ 141 char **argv /* Text of each argument */ 142 ){ 143 sqlite *db; 144 Tcl_DString str; 145 int rc; 146 char *zErr = 0; 147 char zBuf[30]; 148 if( argc!=4 ){ 149 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 150 " DB FORMAT STRING", 0); 151 return TCL_ERROR; 152 } 153 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 154 Tcl_DStringInit(&str); 155 rc = sqlite_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]); 156 sprintf(zBuf, "%d", rc); 157 Tcl_AppendElement(interp, zBuf); 158 Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr); 159 Tcl_DStringFree(&str); 160 if( zErr ) free(zErr); 161 return TCL_OK; 162 } 163 164 /* 165 ** Usage: sqlite_mprintf_z_test SEPARATOR ARG0 ARG1 ... 166 ** 167 ** Test the %z format of mprintf(). Use multiple mprintf() calls to 168 ** concatenate arg0 through argn using separator as the separator. 169 ** Return the result. 170 */ 171 static int test_mprintf_z( 172 void *NotUsed, 173 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 174 int argc, /* Number of arguments */ 175 char **argv /* Text of each argument */ 176 ){ 177 char *zResult = 0; 178 int i; 179 180 for(i=2; i<argc; i++){ 181 zResult = sqlite_mprintf("%z%s%s", zResult, argv[1], argv[i]); 182 } 183 Tcl_AppendResult(interp, zResult, 0); 184 sqlite_freemem(zResult); 185 return TCL_OK; 186 } 187 188 /* 189 ** Usage: sqlite_get_table_printf DB FORMAT STRING 190 ** 191 ** Invoke the sqlite_get_table_printf() interface using the open database 192 ** DB. The SQL is the string FORMAT. The format string should contain 193 ** one %s or %q. STRING is the value inserted into %s or %q. 194 */ 195 static int test_get_table_printf( 196 void *NotUsed, 197 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 198 int argc, /* Number of arguments */ 199 char **argv /* Text of each argument */ 200 ){ 201 sqlite *db; 202 Tcl_DString str; 203 int rc; 204 char *zErr = 0; 205 int nRow, nCol; 206 char **aResult; 207 int i; 208 char zBuf[30]; 209 if( argc!=4 ){ 210 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 211 " DB FORMAT STRING", 0); 212 return TCL_ERROR; 213 } 214 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 215 Tcl_DStringInit(&str); 216 rc = sqlite_get_table_printf(db, argv[2], &aResult, &nRow, &nCol, 217 &zErr, argv[3]); 218 sprintf(zBuf, "%d", rc); 219 Tcl_AppendElement(interp, zBuf); 220 if( rc==SQLITE_OK ){ 221 sprintf(zBuf, "%d", nRow); 222 Tcl_AppendElement(interp, zBuf); 223 sprintf(zBuf, "%d", nCol); 224 Tcl_AppendElement(interp, zBuf); 225 for(i=0; i<(nRow+1)*nCol; i++){ 226 Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL"); 227 } 228 }else{ 229 Tcl_AppendElement(interp, zErr); 230 } 231 sqlite_free_table(aResult); 232 if( zErr ) free(zErr); 233 return TCL_OK; 234 } 235 236 237 /* 238 ** Usage: sqlite_last_insert_rowid DB 239 ** 240 ** Returns the integer ROWID of the most recent insert. 241 */ 242 static int test_last_rowid( 243 void *NotUsed, 244 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 245 int argc, /* Number of arguments */ 246 char **argv /* Text of each argument */ 247 ){ 248 sqlite *db; 249 char zBuf[30]; 250 251 if( argc!=2 ){ 252 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0); 253 return TCL_ERROR; 254 } 255 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 256 sprintf(zBuf, "%d", sqlite_last_insert_rowid(db)); 257 Tcl_AppendResult(interp, zBuf, 0); 258 return SQLITE_OK; 259 } 260 261 /* 262 ** Usage: sqlite_close DB 263 ** 264 ** Closes the database opened by sqlite_open. 265 */ 266 static int sqlite_test_close( 267 void *NotUsed, 268 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 269 int argc, /* Number of arguments */ 270 char **argv /* Text of each argument */ 271 ){ 272 sqlite *db; 273 if( argc!=2 ){ 274 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 275 " FILENAME\"", 0); 276 return TCL_ERROR; 277 } 278 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 279 sqlite_close(db); 280 return TCL_OK; 281 } 282 283 /* 284 ** Implementation of the x_coalesce() function. 285 ** Return the first argument non-NULL argument. 286 */ 287 static void ifnullFunc(sqlite_func *context, int argc, const char **argv){ 288 int i; 289 for(i=0; i<argc; i++){ 290 if( argv[i] ){ 291 sqlite_set_result_string(context, argv[i], -1); 292 break; 293 } 294 } 295 } 296 297 /* 298 ** Implementation of the x_sqlite_exec() function. This function takes 299 ** a single argument and attempts to execute that argument as SQL code. 300 ** This is illegal and should set the SQLITE_MISUSE flag on the database. 301 ** 302 ** This routine simulates the effect of having two threads attempt to 303 ** use the same database at the same time. 304 */ 305 static void sqliteExecFunc(sqlite_func *context, int argc, const char **argv){ 306 sqlite_exec((sqlite*)sqlite_user_data(context), argv[0], 0, 0, 0); 307 } 308 309 /* 310 ** Usage: sqlite_test_create_function DB 311 ** 312 ** Call the sqlite_create_function API on the given database in order 313 ** to create a function named "x_coalesce". This function does the same thing 314 ** as the "coalesce" function. This function also registers an SQL function 315 ** named "x_sqlite_exec" that invokes sqlite_exec(). Invoking sqlite_exec() 316 ** in this way is illegal recursion and should raise an SQLITE_MISUSE error. 317 ** The effect is similar to trying to use the same database connection from 318 ** two threads at the same time. 319 ** 320 ** The original motivation for this routine was to be able to call the 321 ** sqlite_create_function function while a query is in progress in order 322 ** to test the SQLITE_MISUSE detection logic. 323 */ 324 static int test_create_function( 325 void *NotUsed, 326 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 327 int argc, /* Number of arguments */ 328 char **argv /* Text of each argument */ 329 ){ 330 sqlite *db; 331 extern void Md5_Register(sqlite*); 332 if( argc!=2 ){ 333 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 334 " FILENAME\"", 0); 335 return TCL_ERROR; 336 } 337 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 338 sqlite_create_function(db, "x_coalesce", -1, ifnullFunc, 0); 339 sqlite_create_function(db, "x_sqlite_exec", 1, sqliteExecFunc, db); 340 return TCL_OK; 341 } 342 343 /* 344 ** Routines to implement the x_count() aggregate function. 345 */ 346 typedef struct CountCtx CountCtx; 347 struct CountCtx { 348 int n; 349 }; 350 static void countStep(sqlite_func *context, int argc, const char **argv){ 351 CountCtx *p; 352 p = sqlite_aggregate_context(context, sizeof(*p)); 353 if( (argc==0 || argv[0]) && p ){ 354 p->n++; 355 } 356 } 357 static void countFinalize(sqlite_func *context){ 358 CountCtx *p; 359 p = sqlite_aggregate_context(context, sizeof(*p)); 360 sqlite_set_result_int(context, p ? p->n : 0); 361 } 362 363 /* 364 ** Usage: sqlite_test_create_aggregate DB 365 ** 366 ** Call the sqlite_create_function API on the given database in order 367 ** to create a function named "x_count". This function does the same thing 368 ** as the "md5sum" function. 369 ** 370 ** The original motivation for this routine was to be able to call the 371 ** sqlite_create_aggregate function while a query is in progress in order 372 ** to test the SQLITE_MISUSE detection logic. 373 */ 374 static int test_create_aggregate( 375 void *NotUsed, 376 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 377 int argc, /* Number of arguments */ 378 char **argv /* Text of each argument */ 379 ){ 380 sqlite *db; 381 if( argc!=2 ){ 382 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 383 " FILENAME\"", 0); 384 return TCL_ERROR; 385 } 386 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 387 sqlite_create_aggregate(db, "x_count", 0, countStep, countFinalize, 0); 388 sqlite_create_aggregate(db, "x_count", 1, countStep, countFinalize, 0); 389 return TCL_OK; 390 } 391 392 393 394 /* 395 ** Usage: sqlite_mprintf_int FORMAT INTEGER INTEGER INTEGER 396 ** 397 ** Call mprintf with three integer arguments 398 */ 399 static int sqlite_mprintf_int( 400 void *NotUsed, 401 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 402 int argc, /* Number of arguments */ 403 char **argv /* Text of each argument */ 404 ){ 405 int a[3], i; 406 char *z; 407 if( argc!=5 ){ 408 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 409 " FORMAT INT INT INT\"", 0); 410 return TCL_ERROR; 411 } 412 for(i=2; i<5; i++){ 413 if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 414 } 415 z = sqlite_mprintf(argv[1], a[0], a[1], a[2]); 416 Tcl_AppendResult(interp, z, 0); 417 sqlite_freemem(z); 418 return TCL_OK; 419 } 420 421 /* 422 ** Usage: sqlite_mprintf_str FORMAT INTEGER INTEGER STRING 423 ** 424 ** Call mprintf with two integer arguments and one string argument 425 */ 426 static int sqlite_mprintf_str( 427 void *NotUsed, 428 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 429 int argc, /* Number of arguments */ 430 char **argv /* Text of each argument */ 431 ){ 432 int a[3], i; 433 char *z; 434 if( argc<4 || argc>5 ){ 435 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 436 " FORMAT INT INT ?STRING?\"", 0); 437 return TCL_ERROR; 438 } 439 for(i=2; i<4; i++){ 440 if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 441 } 442 z = sqlite_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL); 443 Tcl_AppendResult(interp, z, 0); 444 sqlite_freemem(z); 445 return TCL_OK; 446 } 447 448 /* 449 ** Usage: sqlite_mprintf_str FORMAT INTEGER INTEGER DOUBLE 450 ** 451 ** Call mprintf with two integer arguments and one double argument 452 */ 453 static int sqlite_mprintf_double( 454 void *NotUsed, 455 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 456 int argc, /* Number of arguments */ 457 char **argv /* Text of each argument */ 458 ){ 459 int a[3], i; 460 double r; 461 char *z; 462 if( argc!=5 ){ 463 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 464 " FORMAT INT INT STRING\"", 0); 465 return TCL_ERROR; 466 } 467 for(i=2; i<4; i++){ 468 if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR; 469 } 470 if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR; 471 z = sqlite_mprintf(argv[1], a[0], a[1], r); 472 Tcl_AppendResult(interp, z, 0); 473 sqlite_freemem(z); 474 return TCL_OK; 475 } 476 477 /* 478 ** Usage: sqlite_malloc_fail N 479 ** 480 ** Rig sqliteMalloc() to fail on the N-th call. Turn off this mechanism 481 ** and reset the sqlite_malloc_failed variable is N==0. 482 */ 483 #ifdef MEMORY_DEBUG 484 static int sqlite_malloc_fail( 485 void *NotUsed, 486 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 487 int argc, /* Number of arguments */ 488 char **argv /* Text of each argument */ 489 ){ 490 int n; 491 if( argc!=2 ){ 492 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0); 493 return TCL_ERROR; 494 } 495 if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR; 496 sqlite_iMallocFail = n; 497 sqlite_malloc_failed = 0; 498 return TCL_OK; 499 } 500 #endif 501 502 /* 503 ** Usage: sqlite_malloc_stat 504 ** 505 ** Return the number of prior calls to sqliteMalloc() and sqliteFree(). 506 */ 507 #ifdef MEMORY_DEBUG 508 static int sqlite_malloc_stat( 509 void *NotUsed, 510 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 511 int argc, /* Number of arguments */ 512 char **argv /* Text of each argument */ 513 ){ 514 char zBuf[200]; 515 sprintf(zBuf, "%d %d %d", sqlite_nMalloc, sqlite_nFree, sqlite_iMallocFail); 516 Tcl_AppendResult(interp, zBuf, 0); 517 return TCL_OK; 518 } 519 #endif 520 521 /* 522 ** Usage: sqlite_abort 523 ** 524 ** Shutdown the process immediately. This is not a clean shutdown. 525 ** This command is used to test the recoverability of a database in 526 ** the event of a program crash. 527 */ 528 static int sqlite_abort( 529 void *NotUsed, 530 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 531 int argc, /* Number of arguments */ 532 char **argv /* Text of each argument */ 533 ){ 534 assert( interp==0 ); /* This will always fail */ 535 return TCL_OK; 536 } 537 538 /* 539 ** The following routine is a user-defined SQL function whose purpose 540 ** is to test the sqlite_set_result() API. 541 */ 542 static void testFunc(sqlite_func *context, int argc, const char **argv){ 543 while( argc>=2 ){ 544 if( argv[0]==0 ){ 545 sqlite_set_result_error(context, "first argument to test function " 546 "may not be NULL", -1); 547 }else if( sqliteStrICmp(argv[0],"string")==0 ){ 548 sqlite_set_result_string(context, argv[1], -1); 549 }else if( argv[1]==0 ){ 550 sqlite_set_result_error(context, "2nd argument may not be NULL if the " 551 "first argument is not \"string\"", -1); 552 }else if( sqliteStrICmp(argv[0],"int")==0 ){ 553 sqlite_set_result_int(context, atoi(argv[1])); 554 }else if( sqliteStrICmp(argv[0],"double")==0 ){ 555 sqlite_set_result_double(context, atof(argv[1])); 556 }else{ 557 sqlite_set_result_error(context,"first argument should be one of: " 558 "string int double", -1); 559 } 560 argc -= 2; 561 argv += 2; 562 } 563 } 564 565 /* 566 ** Usage: sqlite_register_test_function DB NAME 567 ** 568 ** Register the test SQL function on the database DB under the name NAME. 569 */ 570 static int test_register_func( 571 void *NotUsed, 572 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 573 int argc, /* Number of arguments */ 574 char **argv /* Text of each argument */ 575 ){ 576 sqlite *db; 577 int rc; 578 if( argc!=3 ){ 579 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 580 " DB FUNCTION-NAME", 0); 581 return TCL_ERROR; 582 } 583 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 584 rc = sqlite_create_function(db, argv[2], -1, testFunc, 0); 585 if( rc!=0 ){ 586 Tcl_AppendResult(interp, sqlite_error_string(rc), 0); 587 return TCL_ERROR; 588 } 589 return TCL_OK; 590 } 591 592 /* 593 ** This SQLite callback records the datatype of all columns. 594 ** 595 ** The pArg argument is really a pointer to a TCL interpreter. The 596 ** column names are inserted as the result of this interpreter. 597 ** 598 ** This routine returns non-zero which causes the query to abort. 599 */ 600 static int rememberDataTypes(void *pArg, int nCol, char **argv, char **colv){ 601 int i; 602 Tcl_Interp *interp = (Tcl_Interp*)pArg; 603 Tcl_Obj *pList, *pElem; 604 if( colv[nCol+1]==0 ){ 605 return 1; 606 } 607 pList = Tcl_NewObj(); 608 for(i=0; i<nCol; i++){ 609 pElem = Tcl_NewStringObj(colv[i+nCol] ? colv[i+nCol] : "NULL", -1); 610 Tcl_ListObjAppendElement(interp, pList, pElem); 611 } 612 Tcl_SetObjResult(interp, pList); 613 return 1; 614 } 615 616 /* 617 ** Invoke an SQL statement but ignore all the data in the result. Instead, 618 ** return a list that consists of the datatypes of the various columns. 619 ** 620 ** This only works if "PRAGMA show_datatypes=on" has been executed against 621 ** the database connection. 622 */ 623 static int sqlite_datatypes( 624 void *NotUsed, 625 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 626 int argc, /* Number of arguments */ 627 char **argv /* Text of each argument */ 628 ){ 629 sqlite *db; 630 int rc; 631 if( argc!=3 ){ 632 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 633 " DB SQL", 0); 634 return TCL_ERROR; 635 } 636 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 637 rc = sqlite_exec(db, argv[2], rememberDataTypes, interp, 0); 638 if( rc!=0 && rc!=SQLITE_ABORT ){ 639 Tcl_AppendResult(interp, sqlite_error_string(rc), 0); 640 return TCL_ERROR; 641 } 642 return TCL_OK; 643 } 644 645 /* 646 ** Usage: sqlite_compile DB SQL ?TAILVAR? 647 ** 648 ** Attempt to compile an SQL statement. Return a pointer to the virtual 649 ** machine used to execute that statement. Unprocessed SQL is written 650 ** into TAILVAR. 651 */ 652 static int test_compile( 653 void *NotUsed, 654 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 655 int argc, /* Number of arguments */ 656 char **argv /* Text of each argument */ 657 ){ 658 sqlite *db; 659 sqlite_vm *vm; 660 int rc; 661 char *zErr = 0; 662 const char *zTail; 663 char zBuf[50]; 664 if( argc!=3 && argc!=4 ){ 665 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 666 " DB SQL TAILVAR", 0); 667 return TCL_ERROR; 668 } 669 if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; 670 rc = sqlite_compile(db, argv[2], argc==4 ? &zTail : 0, &vm, &zErr); 671 if( argc==4 ) Tcl_SetVar(interp, argv[3], zTail, 0); 672 if( rc ){ 673 assert( vm==0 ); 674 sprintf(zBuf, "(%d) ", rc); 675 Tcl_AppendResult(interp, zBuf, zErr, 0); 676 sqlite_freemem(zErr); 677 return TCL_ERROR; 678 } 679 if( vm ){ 680 if( makePointerStr(interp, zBuf, vm) ) return TCL_ERROR; 681 Tcl_AppendResult(interp, zBuf, 0); 682 } 683 return TCL_OK; 684 } 685 686 /* 687 ** Usage: sqlite_step VM ?NVAR? ?VALUEVAR? ?COLNAMEVAR? 688 ** 689 ** Step a virtual machine. Return a the result code as a string. 690 ** Column results are written into three variables. 691 */ 692 static int test_step( 693 void *NotUsed, 694 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 695 int argc, /* Number of arguments */ 696 char **argv /* Text of each argument */ 697 ){ 698 sqlite_vm *vm; 699 int rc, i; 700 const char **azValue = 0; 701 const char **azColName = 0; 702 int N = 0; 703 char *zRc; 704 char zBuf[50]; 705 if( argc<2 || argc>5 ){ 706 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 707 " VM NVAR VALUEVAR COLNAMEVAR", 0); 708 return TCL_ERROR; 709 } 710 if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR; 711 rc = sqlite_step(vm, argc>=3?&N:0, argc>=4?&azValue:0, argc==5?&azColName:0); 712 if( argc>=3 ){ 713 sprintf(zBuf, "%d", N); 714 Tcl_SetVar(interp, argv[2], zBuf, 0); 715 } 716 if( argc>=4 ){ 717 Tcl_SetVar(interp, argv[3], "", 0); 718 if( azValue ){ 719 for(i=0; i<N; i++){ 720 Tcl_SetVar(interp, argv[3], azValue[i] ? azValue[i] : "", 721 TCL_APPEND_VALUE | TCL_LIST_ELEMENT); 722 } 723 } 724 } 725 if( argc==5 ){ 726 Tcl_SetVar(interp, argv[4], "", 0); 727 if( azColName ){ 728 for(i=0; i<N*2; i++){ 729 Tcl_SetVar(interp, argv[4], azColName[i] ? azColName[i] : "", 730 TCL_APPEND_VALUE | TCL_LIST_ELEMENT); 731 } 732 } 733 } 734 switch( rc ){ 735 case SQLITE_DONE: zRc = "SQLITE_DONE"; break; 736 case SQLITE_BUSY: zRc = "SQLITE_BUSY"; break; 737 case SQLITE_ROW: zRc = "SQLITE_ROW"; break; 738 case SQLITE_ERROR: zRc = "SQLITE_ERROR"; break; 739 case SQLITE_MISUSE: zRc = "SQLITE_MISUSE"; break; 740 default: zRc = "unknown"; break; 741 } 742 Tcl_AppendResult(interp, zRc, 0); 743 return TCL_OK; 744 } 745 746 /* 747 ** Usage: sqlite_finalize VM 748 ** 749 ** Shutdown a virtual machine. 750 */ 751 static int test_finalize( 752 void *NotUsed, 753 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 754 int argc, /* Number of arguments */ 755 char **argv /* Text of each argument */ 756 ){ 757 sqlite_vm *vm; 758 int rc; 759 char *zErrMsg = 0; 760 if( argc!=2 ){ 761 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 762 " VM\"", 0); 763 return TCL_ERROR; 764 } 765 if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR; 766 rc = sqlite_finalize(vm, &zErrMsg); 767 if( rc ){ 768 char zBuf[50]; 769 sprintf(zBuf, "(%d) ", rc); 770 Tcl_AppendResult(interp, zBuf, zErrMsg, 0); 771 sqlite_freemem(zErrMsg); 772 return TCL_ERROR; 773 } 774 return TCL_OK; 775 } 776 777 /* 778 ** Usage: breakpoint 779 ** 780 ** This routine exists for one purpose - to provide a place to put a 781 ** breakpoint with GDB that can be triggered using TCL code. The use 782 ** for this is when a particular test fails on (say) the 1485th iteration. 783 ** In the TCL test script, we can add code like this: 784 ** 785 ** if {$i==1485} breakpoint 786 ** 787 ** Then run testfixture in the debugger and wait for the breakpoint to 788 ** fire. Then additional breakpoints can be set to trace down the bug. 789 */ 790 static int test_breakpoint( 791 void *NotUsed, 792 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ 793 int argc, /* Number of arguments */ 794 char **argv /* Text of each argument */ 795 ){ 796 return TCL_OK; /* Do nothing */ 797 } 798 799 /* 800 ** Register commands with the TCL interpreter. 801 */ 802 int Sqlitetest1_Init(Tcl_Interp *interp){ 803 extern int sqlite_search_count; 804 extern int sqlite_open_file_count; 805 static struct { 806 char *zName; 807 Tcl_CmdProc *xProc; 808 } aCmd[] = { 809 { "sqlite_mprintf_int", (Tcl_CmdProc*)sqlite_mprintf_int }, 810 { "sqlite_mprintf_str", (Tcl_CmdProc*)sqlite_mprintf_str }, 811 { "sqlite_mprintf_double", (Tcl_CmdProc*)sqlite_mprintf_double }, 812 { "sqlite_mprintf_z_test", (Tcl_CmdProc*)test_mprintf_z }, 813 { "sqlite_open", (Tcl_CmdProc*)sqlite_test_open }, 814 { "sqlite_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid }, 815 { "sqlite_exec_printf", (Tcl_CmdProc*)test_exec_printf }, 816 { "sqlite_get_table_printf", (Tcl_CmdProc*)test_get_table_printf }, 817 { "sqlite_close", (Tcl_CmdProc*)sqlite_test_close }, 818 { "sqlite_create_function", (Tcl_CmdProc*)test_create_function }, 819 { "sqlite_create_aggregate", (Tcl_CmdProc*)test_create_aggregate }, 820 { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func }, 821 { "sqlite_abort", (Tcl_CmdProc*)sqlite_abort }, 822 { "sqlite_datatypes", (Tcl_CmdProc*)sqlite_datatypes }, 823 #ifdef MEMORY_DEBUG 824 { "sqlite_malloc_fail", (Tcl_CmdProc*)sqlite_malloc_fail }, 825 { "sqlite_malloc_stat", (Tcl_CmdProc*)sqlite_malloc_stat }, 826 #endif 827 { "sqlite_compile", (Tcl_CmdProc*)test_compile }, 828 { "sqlite_step", (Tcl_CmdProc*)test_step }, 829 { "sqlite_finalize", (Tcl_CmdProc*)test_finalize }, 830 { "breakpoint", (Tcl_CmdProc*)test_breakpoint }, 831 }; 832 int i; 833 834 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ 835 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); 836 } 837 Tcl_LinkVar(interp, "sqlite_search_count", 838 (char*)&sqlite_search_count, TCL_LINK_INT); 839 Tcl_LinkVar(interp, "sqlite_open_file_count", 840 (char*)&sqlite_open_file_count, TCL_LINK_INT); 841 return TCL_OK; 842 } 843