Main Page | Directories | File List

test1.c

00001 /*
00002 ** 2001 September 15
00003 **
00004 ** The author disclaims copyright to this source code.  In place of
00005 ** a legal notice, here is a blessing:
00006 **
00007 **    May you do good and not evil.
00008 **    May you find forgiveness for yourself and forgive others.
00009 **    May you share freely, never taking more than you give.
00010 **
00011 *************************************************************************
00012 ** Code for testing the printf() interface to SQLite.  This code
00013 ** is not included in the SQLite library.  It is used for automated
00014 ** testing of the SQLite library.
00015 **
00016 ** $Id: test1.c,v 1.36.2.1 2004/05/07 00:57:06 drh Exp $
00017 */
00018 #include "sqliteInt.h"
00019 #include "tcl.h"
00020 #include "os.h"
00021 #include <stdlib.h>
00022 #include <string.h>
00023 
00024 #if OS_WIN
00025 # define PTR_FMT "%x"
00026 #else
00027 # define PTR_FMT "%p"
00028 #endif
00029 
00030 /*
00031 ** Decode a pointer to an sqlite object.
00032 */
00033 static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite **ppDb){
00034   if( sscanf(zA, PTR_FMT, (void**)ppDb)!=1 && 
00035       (zA[0]!='0' || zA[1]!='x' || sscanf(&zA[2], PTR_FMT, (void**)ppDb)!=1)
00036   ){
00037     Tcl_AppendResult(interp, "\"", zA, "\" is not a valid pointer value", 0);
00038     return TCL_ERROR;
00039   }
00040   return TCL_OK;
00041 }
00042 
00043 /*
00044 ** Decode a pointer to an sqlite_vm object.
00045 */
00046 static int getVmPointer(Tcl_Interp *interp, const char *zArg, sqlite_vm **ppVm){
00047   if( sscanf(zArg, PTR_FMT, (void**)ppVm)!=1 ){
00048     Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0);
00049     return TCL_ERROR;
00050   }
00051   return TCL_OK;
00052 }
00053 
00054 /*
00055 ** Generate a text representation of a pointer that can be understood
00056 ** by the getDbPointer and getVmPointer routines above.
00057 **
00058 ** The problem is, on some machines (Solaris) if you do a printf with
00059 ** "%p" you cannot turn around and do a scanf with the same "%p" and
00060 ** get your pointer back.  You have to prepend a "0x" before it will
00061 ** work.  Or at least that is what is reported to me (drh).  But this
00062 ** behavior varies from machine to machine.  The solution used her is
00063 ** to test the string right after it is generated to see if it can be
00064 ** understood by scanf, and if not, try prepending an "0x" to see if
00065 ** that helps.  If nothing works, a fatal error is generated.
00066 */
00067 static int makePointerStr(Tcl_Interp *interp, char *zPtr, void *p){
00068   void *p2;
00069   sprintf(zPtr, PTR_FMT, p);
00070   if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){
00071     sprintf(zPtr, "0x" PTR_FMT, p);
00072     if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){
00073       Tcl_AppendResult(interp, "unable to convert a pointer to a string "
00074          "in the file " __FILE__ " in function makePointerStr().  Please "
00075          "report this problem to the SQLite mailing list or as a new but "
00076          "report.  Please provide detailed information about how you compiled "
00077          "SQLite and what computer you are running on.", 0);
00078       return TCL_ERROR;
00079     }
00080   }
00081   return TCL_OK;
00082 }
00083 
00084 /*
00085 ** Usage:   sqlite_open filename
00086 **
00087 ** Returns:  The name of an open database.
00088 */
00089 static int sqlite_test_open(
00090   void *NotUsed,
00091   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00092   int argc,              /* Number of arguments */
00093   char **argv            /* Text of each argument */
00094 ){
00095   sqlite *db;
00096   char *zErr = 0;
00097   char zBuf[100];
00098   if( argc!=2 ){
00099     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
00100        " FILENAME\"", 0);
00101     return TCL_ERROR;
00102   }
00103   db = sqlite_open(argv[1], 0666, &zErr);
00104   if( db==0 ){
00105     Tcl_AppendResult(interp, zErr, 0);
00106     free(zErr);
00107     return TCL_ERROR;
00108   }
00109   if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
00110   Tcl_AppendResult(interp, zBuf, 0);
00111   return TCL_OK;
00112 }
00113 
00114 /*
00115 ** The callback routine for sqlite_exec_printf().
00116 */
00117 static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){
00118   Tcl_DString *str = (Tcl_DString*)pArg;
00119   int i;
00120 
00121   if( Tcl_DStringLength(str)==0 ){
00122     for(i=0; i<argc; i++){
00123       Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL");
00124     }
00125   }
00126   for(i=0; i<argc; i++){
00127     Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL");
00128   }
00129   return 0;
00130 }
00131 
00132 /*
00133 ** Usage:  sqlite_exec_printf  DB  FORMAT  STRING
00134 **
00135 ** Invoke the sqlite_exec_printf() interface using the open database
00136 ** DB.  The SQL is the string FORMAT.  The format string should contain
00137 ** one %s or %q.  STRING is the value inserted into %s or %q.
00138 */
00139 static int test_exec_printf(
00140   void *NotUsed,
00141   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00142   int argc,              /* Number of arguments */
00143   char **argv            /* Text of each argument */
00144 ){
00145   sqlite *db;
00146   Tcl_DString str;
00147   int rc;
00148   char *zErr = 0;
00149   char zBuf[30];
00150   if( argc!=4 ){
00151     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 
00152        " DB FORMAT STRING", 0);
00153     return TCL_ERROR;
00154   }
00155   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
00156   Tcl_DStringInit(&str);
00157   rc = sqlite_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]);
00158   sprintf(zBuf, "%d", rc);
00159   Tcl_AppendElement(interp, zBuf);
00160   Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
00161   Tcl_DStringFree(&str);
00162   if( zErr ) free(zErr);
00163   return TCL_OK;
00164 }
00165 
00166 /*
00167 ** Usage:  sqlite_mprintf_z_test  SEPARATOR  ARG0  ARG1 ...
00168 **
00169 ** Test the %z format of mprintf().  Use multiple mprintf() calls to 
00170 ** concatenate arg0 through argn using separator as the separator.
00171 ** Return the result.
00172 */
00173 static int test_mprintf_z(
00174   void *NotUsed,
00175   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00176   int argc,              /* Number of arguments */
00177   char **argv            /* Text of each argument */
00178 ){
00179   char *zResult = 0;
00180   int i;
00181 
00182   for(i=2; i<argc; i++){
00183     zResult = sqliteMPrintf("%z%s%s", zResult, argv[1], argv[i]);
00184   }
00185   Tcl_AppendResult(interp, zResult, 0);
00186   sqliteFree(zResult);
00187   return TCL_OK;
00188 }
00189 
00190 /*
00191 ** Usage:  sqlite_get_table_printf  DB  FORMAT  STRING
00192 **
00193 ** Invoke the sqlite_get_table_printf() interface using the open database
00194 ** DB.  The SQL is the string FORMAT.  The format string should contain
00195 ** one %s or %q.  STRING is the value inserted into %s or %q.
00196 */
00197 static int test_get_table_printf(
00198   void *NotUsed,
00199   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00200   int argc,              /* Number of arguments */
00201   char **argv            /* Text of each argument */
00202 ){
00203   sqlite *db;
00204   Tcl_DString str;
00205   int rc;
00206   char *zErr = 0;
00207   int nRow, nCol;
00208   char **aResult;
00209   int i;
00210   char zBuf[30];
00211   if( argc!=4 ){
00212     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 
00213        " DB FORMAT STRING", 0);
00214     return TCL_ERROR;
00215   }
00216   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
00217   Tcl_DStringInit(&str);
00218   rc = sqlite_get_table_printf(db, argv[2], &aResult, &nRow, &nCol, 
00219                &zErr, argv[3]);
00220   sprintf(zBuf, "%d", rc);
00221   Tcl_AppendElement(interp, zBuf);
00222   if( rc==SQLITE_OK ){
00223     sprintf(zBuf, "%d", nRow);
00224     Tcl_AppendElement(interp, zBuf);
00225     sprintf(zBuf, "%d", nCol);
00226     Tcl_AppendElement(interp, zBuf);
00227     for(i=0; i<(nRow+1)*nCol; i++){
00228       Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL");
00229     }
00230   }else{
00231     Tcl_AppendElement(interp, zErr);
00232   }
00233   sqlite_free_table(aResult);
00234   if( zErr ) free(zErr);
00235   return TCL_OK;
00236 }
00237 
00238 
00239 /*
00240 ** Usage:  sqlite_last_insert_rowid DB
00241 **
00242 ** Returns the integer ROWID of the most recent insert.
00243 */
00244 static int test_last_rowid(
00245   void *NotUsed,
00246   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00247   int argc,              /* Number of arguments */
00248   char **argv            /* Text of each argument */
00249 ){
00250   sqlite *db;
00251   char zBuf[30];
00252 
00253   if( argc!=2 ){
00254     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0);
00255     return TCL_ERROR;
00256   }
00257   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
00258   sprintf(zBuf, "%d", sqlite_last_insert_rowid(db));
00259   Tcl_AppendResult(interp, zBuf, 0);
00260   return SQLITE_OK;
00261 }
00262 
00263 /*
00264 ** Usage:  sqlite_close DB
00265 **
00266 ** Closes the database opened by sqlite_open.
00267 */
00268 static int sqlite_test_close(
00269   void *NotUsed,
00270   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00271   int argc,              /* Number of arguments */
00272   char **argv            /* Text of each argument */
00273 ){
00274   sqlite *db;
00275   if( argc!=2 ){
00276     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
00277        " FILENAME\"", 0);
00278     return TCL_ERROR;
00279   }
00280   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
00281   sqlite_close(db);
00282   return TCL_OK;
00283 }
00284 
00285 /*
00286 ** Implementation of the x_coalesce() function.
00287 ** Return the first argument non-NULL argument.
00288 */
00289 static void ifnullFunc(sqlite_func *context, int argc, const char **argv){
00290   int i;
00291   for(i=0; i<argc; i++){
00292     if( argv[i] ){
00293       sqlite_set_result_string(context, argv[i], -1);
00294       break;
00295     }
00296   }
00297 }
00298 
00299 /*
00300 ** A structure into which to accumulate text.
00301 */
00302 struct dstr {
00303   int nAlloc;  /* Space allocated */
00304   int nUsed;   /* Space used */
00305   char *z;     /* The space */
00306 };
00307 
00308 /*
00309 ** Append text to a dstr
00310 */
00311 static void dstrAppend(struct dstr *p, const char *z, int divider){
00312   int n = strlen(z);
00313   if( p->nUsed + n + 2 > p->nAlloc ){
00314     char *zNew;
00315     p->nAlloc = p->nAlloc*2 + n + 200;
00316     zNew = sqliteRealloc(p->z, p->nAlloc);
00317     if( zNew==0 ){
00318       sqliteFree(p->z);
00319       memset(p, 0, sizeof(*p));
00320       return;
00321     }
00322     p->z = zNew;
00323   }
00324   if( divider && p->nUsed>0 ){
00325     p->z[p->nUsed++] = divider;
00326   }
00327   memcpy(&p->z[p->nUsed], z, n+1);
00328   p->nUsed += n;
00329 }
00330 
00331 /*
00332 ** Invoked for each callback from sqliteExecFunc
00333 */
00334 static int execFuncCallback(void *pData, int argc, char **argv, char **NotUsed){
00335   struct dstr *p = (struct dstr*)pData;
00336   int i;
00337   for(i=0; i<argc; i++){
00338     if( argv[i]==0 ){
00339       dstrAppend(p, "NULL", ' ');
00340     }else{
00341       dstrAppend(p, argv[i], ' ');
00342     }
00343   }
00344   return 0;
00345 }
00346 
00347 /*
00348 ** Implementation of the x_sqlite_exec() function.  This function takes
00349 ** a single argument and attempts to execute that argument as SQL code.
00350 ** This is illegal and should set the SQLITE_MISUSE flag on the database.
00351 **
00352 ** 2004-Jan-07:  We have changed this to make it legal to call sqlite_exec()
00353 ** from within a function call.  
00354 ** 
00355 ** This routine simulates the effect of having two threads attempt to
00356 ** use the same database at the same time.
00357 */
00358 static void sqliteExecFunc(sqlite_func *context, int argc, const char **argv){
00359   struct dstr x;
00360   memset(&x, 0, sizeof(x));
00361   sqlite_exec((sqlite*)sqlite_user_data(context), argv[0], 
00362       execFuncCallback, &x, 0);
00363   sqlite_set_result_string(context, x.z, x.nUsed);
00364   sqliteFree(x.z);
00365 }
00366 
00367 /*
00368 ** Usage:  sqlite_test_create_function DB
00369 **
00370 ** Call the sqlite_create_function API on the given database in order
00371 ** to create a function named "x_coalesce".  This function does the same thing
00372 ** as the "coalesce" function.  This function also registers an SQL function
00373 ** named "x_sqlite_exec" that invokes sqlite_exec().  Invoking sqlite_exec()
00374 ** in this way is illegal recursion and should raise an SQLITE_MISUSE error.
00375 ** The effect is similar to trying to use the same database connection from
00376 ** two threads at the same time.
00377 **
00378 ** The original motivation for this routine was to be able to call the
00379 ** sqlite_create_function function while a query is in progress in order
00380 ** to test the SQLITE_MISUSE detection logic.
00381 */
00382 static int test_create_function(
00383   void *NotUsed,
00384   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00385   int argc,              /* Number of arguments */
00386   char **argv            /* Text of each argument */
00387 ){
00388   sqlite *db;
00389   extern void Md5_Register(sqlite*);
00390   if( argc!=2 ){
00391     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
00392        " FILENAME\"", 0);
00393     return TCL_ERROR;
00394   }
00395   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
00396   sqlite_create_function(db, "x_coalesce", -1, ifnullFunc, 0);
00397   sqlite_create_function(db, "x_sqlite_exec", 1, sqliteExecFunc, db);
00398   return TCL_OK;
00399 }
00400 
00401 /*
00402 ** Routines to implement the x_count() aggregate function.
00403 */
00404 typedef struct CountCtx CountCtx;
00405 struct CountCtx {
00406   int n;
00407 };
00408 static void countStep(sqlite_func *context, int argc, const char **argv){
00409   CountCtx *p;
00410   p = sqlite_aggregate_context(context, sizeof(*p));
00411   if( (argc==0 || argv[0]) && p ){
00412     p->n++;
00413   }
00414 }   
00415 static void countFinalize(sqlite_func *context){
00416   CountCtx *p;
00417   p = sqlite_aggregate_context(context, sizeof(*p));
00418   sqlite_set_result_int(context, p ? p->n : 0);
00419 }
00420 
00421 /*
00422 ** Usage:  sqlite_test_create_aggregate DB
00423 **
00424 ** Call the sqlite_create_function API on the given database in order
00425 ** to create a function named "x_count".  This function does the same thing
00426 ** as the "md5sum" function.
00427 **
00428 ** The original motivation for this routine was to be able to call the
00429 ** sqlite_create_aggregate function while a query is in progress in order
00430 ** to test the SQLITE_MISUSE detection logic.
00431 */
00432 static int test_create_aggregate(
00433   void *NotUsed,
00434   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00435   int argc,              /* Number of arguments */
00436   char **argv            /* Text of each argument */
00437 ){
00438   sqlite *db;
00439   if( argc!=2 ){
00440     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
00441        " FILENAME\"", 0);
00442     return TCL_ERROR;
00443   }
00444   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
00445   sqlite_create_aggregate(db, "x_count", 0, countStep, countFinalize, 0);
00446   sqlite_create_aggregate(db, "x_count", 1, countStep, countFinalize, 0);
00447   return TCL_OK;
00448 }
00449 
00450 
00451 
00452 /*
00453 ** Usage:  sqlite_mprintf_int FORMAT INTEGER INTEGER INTEGER
00454 **
00455 ** Call mprintf with three integer arguments
00456 */
00457 static int sqlite_mprintf_int(
00458   void *NotUsed,
00459   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00460   int argc,              /* Number of arguments */
00461   char **argv            /* Text of each argument */
00462 ){
00463   int a[3], i;
00464   char *z;
00465   if( argc!=5 ){
00466     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
00467        " FORMAT INT INT INT\"", 0);
00468     return TCL_ERROR;
00469   }
00470   for(i=2; i<5; i++){
00471     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
00472   }
00473   z = sqlite_mprintf(argv[1], a[0], a[1], a[2]);
00474   Tcl_AppendResult(interp, z, 0);
00475   sqlite_freemem(z);
00476   return TCL_OK;
00477 }
00478 
00479 /*
00480 ** Usage:  sqlite_mprintf_str FORMAT INTEGER INTEGER STRING
00481 **
00482 ** Call mprintf with two integer arguments and one string argument
00483 */
00484 static int sqlite_mprintf_str(
00485   void *NotUsed,
00486   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00487   int argc,              /* Number of arguments */
00488   char **argv            /* Text of each argument */
00489 ){
00490   int a[3], i;
00491   char *z;
00492   if( argc<4 || argc>5 ){
00493     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
00494        " FORMAT INT INT ?STRING?\"", 0);
00495     return TCL_ERROR;
00496   }
00497   for(i=2; i<4; i++){
00498     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
00499   }
00500   z = sqlite_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL);
00501   Tcl_AppendResult(interp, z, 0);
00502   sqlite_freemem(z);
00503   return TCL_OK;
00504 }
00505 
00506 /*
00507 ** Usage:  sqlite_mprintf_str FORMAT INTEGER INTEGER DOUBLE
00508 **
00509 ** Call mprintf with two integer arguments and one double argument
00510 */
00511 static int sqlite_mprintf_double(
00512   void *NotUsed,
00513   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00514   int argc,              /* Number of arguments */
00515   char **argv            /* Text of each argument */
00516 ){
00517   int a[3], i;
00518   double r;
00519   char *z;
00520   if( argc!=5 ){
00521     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
00522        " FORMAT INT INT STRING\"", 0);
00523     return TCL_ERROR;
00524   }
00525   for(i=2; i<4; i++){
00526     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
00527   }
00528   if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR;
00529   z = sqlite_mprintf(argv[1], a[0], a[1], r);
00530   Tcl_AppendResult(interp, z, 0);
00531   sqlite_freemem(z);
00532   return TCL_OK;
00533 }
00534 
00535 /*
00536 ** Usage:  sqlite_mprintf_str FORMAT DOUBLE DOUBLE
00537 **
00538 ** Call mprintf with a single double argument which is the product of the
00539 ** two arguments given above.  This is used to generate overflow and underflow
00540 ** doubles to test that they are converted properly.
00541 */
00542 static int sqlite_mprintf_scaled(
00543   void *NotUsed,
00544   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00545   int argc,              /* Number of arguments */
00546   char **argv            /* Text of each argument */
00547 ){
00548   int i;
00549   double r[2];
00550   char *z;
00551   if( argc!=4 ){
00552     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
00553        " FORMAT DOUBLE DOUBLE\"", 0);
00554     return TCL_ERROR;
00555   }
00556   for(i=2; i<4; i++){
00557     if( Tcl_GetDouble(interp, argv[i], &r[i-2]) ) return TCL_ERROR;
00558   }
00559   z = sqlite_mprintf(argv[1], r[0]*r[1]);
00560   Tcl_AppendResult(interp, z, 0);
00561   sqlite_freemem(z);
00562   return TCL_OK;
00563 }
00564 
00565 /*
00566 ** Usage: sqlite_malloc_fail N
00567 **
00568 ** Rig sqliteMalloc() to fail on the N-th call.  Turn off this mechanism
00569 ** and reset the sqlite_malloc_failed variable is N==0.
00570 */
00571 #ifdef MEMORY_DEBUG
00572 static int sqlite_malloc_fail(
00573   void *NotUsed,
00574   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00575   int argc,              /* Number of arguments */
00576   char **argv            /* Text of each argument */
00577 ){
00578   int n;
00579   if( argc!=2 ){
00580     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0);
00581     return TCL_ERROR;
00582   }
00583   if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
00584   sqlite_iMallocFail = n;
00585   sqlite_malloc_failed = 0;
00586   return TCL_OK;
00587 }
00588 #endif
00589 
00590 /*
00591 ** Usage: sqlite_malloc_stat
00592 **
00593 ** Return the number of prior calls to sqliteMalloc() and sqliteFree().
00594 */
00595 #ifdef MEMORY_DEBUG
00596 static int sqlite_malloc_stat(
00597   void *NotUsed,
00598   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00599   int argc,              /* Number of arguments */
00600   char **argv            /* Text of each argument */
00601 ){
00602   char zBuf[200];
00603   sprintf(zBuf, "%d %d %d", sqlite_nMalloc, sqlite_nFree, sqlite_iMallocFail);
00604   Tcl_AppendResult(interp, zBuf, 0);
00605   return TCL_OK;
00606 }
00607 #endif
00608 
00609 /*
00610 ** Usage:  sqlite_abort
00611 **
00612 ** Shutdown the process immediately.  This is not a clean shutdown.
00613 ** This command is used to test the recoverability of a database in
00614 ** the event of a program crash.
00615 */
00616 static int sqlite_abort(
00617   void *NotUsed,
00618   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00619   int argc,              /* Number of arguments */
00620   char **argv            /* Text of each argument */
00621 ){
00622   assert( interp==0 );   /* This will always fail */
00623   return TCL_OK;
00624 }
00625 
00626 /*
00627 ** The following routine is a user-defined SQL function whose purpose
00628 ** is to test the sqlite_set_result() API.
00629 */
00630 static void testFunc(sqlite_func *context, int argc, const char **argv){
00631   while( argc>=2 ){
00632     if( argv[0]==0 ){
00633       sqlite_set_result_error(context, "first argument to test function "
00634          "may not be NULL", -1);
00635     }else if( sqliteStrICmp(argv[0],"string")==0 ){
00636       sqlite_set_result_string(context, argv[1], -1);
00637     }else if( argv[1]==0 ){
00638       sqlite_set_result_error(context, "2nd argument may not be NULL if the "
00639          "first argument is not \"string\"", -1);
00640     }else if( sqliteStrICmp(argv[0],"int")==0 ){
00641       sqlite_set_result_int(context, atoi(argv[1]));
00642     }else if( sqliteStrICmp(argv[0],"double")==0 ){
00643       sqlite_set_result_double(context, sqliteAtoF(argv[1], 0));
00644     }else{
00645       sqlite_set_result_error(context,"first argument should be one of: "
00646           "string int double", -1);
00647     }
00648     argc -= 2;
00649     argv += 2;
00650   }
00651 }
00652 
00653 /*
00654 ** Usage:   sqlite_register_test_function  DB  NAME
00655 **
00656 ** Register the test SQL function on the database DB under the name NAME.
00657 */
00658 static int test_register_func(
00659   void *NotUsed,
00660   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00661   int argc,              /* Number of arguments */
00662   char **argv            /* Text of each argument */
00663 ){
00664   sqlite *db;
00665   int rc;
00666   if( argc!=3 ){
00667     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 
00668        " DB FUNCTION-NAME", 0);
00669     return TCL_ERROR;
00670   }
00671   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
00672   rc = sqlite_create_function(db, argv[2], -1, testFunc, 0);
00673   if( rc!=0 ){
00674     Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
00675     return TCL_ERROR;
00676   }
00677   return TCL_OK;
00678 }
00679 
00680 /*
00681 ** This SQLite callback records the datatype of all columns.
00682 **
00683 ** The pArg argument is really a pointer to a TCL interpreter.  The
00684 ** column names are inserted as the result of this interpreter.
00685 **
00686 ** This routine returns non-zero which causes the query to abort.
00687 */
00688 static int rememberDataTypes(void *pArg, int nCol, char **argv, char **colv){
00689   int i;
00690   Tcl_Interp *interp = (Tcl_Interp*)pArg;
00691   Tcl_Obj *pList, *pElem;
00692   if( colv[nCol+1]==0 ){
00693     return 1;
00694   }
00695   pList = Tcl_NewObj();
00696   for(i=0; i<nCol; i++){
00697     pElem = Tcl_NewStringObj(colv[i+nCol] ? colv[i+nCol] : "NULL", -1);
00698     Tcl_ListObjAppendElement(interp, pList, pElem);
00699   }
00700   Tcl_SetObjResult(interp, pList);
00701   return 1;
00702 }
00703 
00704 /*
00705 ** Invoke an SQL statement but ignore all the data in the result.  Instead,
00706 ** return a list that consists of the datatypes of the various columns.
00707 **
00708 ** This only works if "PRAGMA show_datatypes=on" has been executed against
00709 ** the database connection.
00710 */
00711 static int sqlite_datatypes(
00712   void *NotUsed,
00713   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00714   int argc,              /* Number of arguments */
00715   char **argv            /* Text of each argument */
00716 ){
00717   sqlite *db;
00718   int rc;
00719   if( argc!=3 ){
00720     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 
00721        " DB SQL", 0);
00722     return TCL_ERROR;
00723   }
00724   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
00725   rc = sqlite_exec(db, argv[2], rememberDataTypes, interp, 0);
00726   if( rc!=0 && rc!=SQLITE_ABORT ){
00727     Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
00728     return TCL_ERROR;
00729   }
00730   return TCL_OK;
00731 }
00732 
00733 /*
00734 ** Usage:  sqlite_compile  DB  SQL  ?TAILVAR?
00735 **
00736 ** Attempt to compile an SQL statement.  Return a pointer to the virtual
00737 ** machine used to execute that statement.  Unprocessed SQL is written
00738 ** into TAILVAR.
00739 */
00740 static int test_compile(
00741   void *NotUsed,
00742   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00743   int argc,              /* Number of arguments */
00744   char **argv            /* Text of each argument */
00745 ){
00746   sqlite *db;
00747   sqlite_vm *vm;
00748   int rc;
00749   char *zErr = 0;
00750   const char *zTail;
00751   char zBuf[50];
00752   if( argc!=3 && argc!=4 ){
00753     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 
00754        " DB SQL TAILVAR", 0);
00755     return TCL_ERROR;
00756   }
00757   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
00758   rc = sqlite_compile(db, argv[2], argc==4 ? &zTail : 0, &vm, &zErr);
00759   if( argc==4 ) Tcl_SetVar(interp, argv[3], zTail, 0);
00760   if( rc ){
00761     assert( vm==0 );
00762     sprintf(zBuf, "(%d) ", rc);
00763     Tcl_AppendResult(interp, zBuf, zErr, 0);
00764     sqlite_freemem(zErr);
00765     return TCL_ERROR;
00766   }
00767   if( vm ){
00768     if( makePointerStr(interp, zBuf, vm) ) return TCL_ERROR;
00769     Tcl_AppendResult(interp, zBuf, 0);
00770   }
00771   return TCL_OK;
00772 }
00773 
00774 /*
00775 ** Usage:  sqlite_step  VM  ?NVAR?  ?VALUEVAR?  ?COLNAMEVAR?
00776 **
00777 ** Step a virtual machine.  Return a the result code as a string.
00778 ** Column results are written into three variables.
00779 */
00780 static int test_step(
00781   void *NotUsed,
00782   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00783   int argc,              /* Number of arguments */
00784   char **argv            /* Text of each argument */
00785 ){
00786   sqlite_vm *vm;
00787   int rc, i;
00788   const char **azValue = 0;
00789   const char **azColName = 0;
00790   int N = 0;
00791   char *zRc;
00792   char zBuf[50];
00793   if( argc<2 || argc>5 ){
00794     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 
00795        " VM NVAR VALUEVAR COLNAMEVAR", 0);
00796     return TCL_ERROR;
00797   }
00798   if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
00799   rc = sqlite_step(vm, argc>=3?&N:0, argc>=4?&azValue:0, argc==5?&azColName:0);
00800   if( argc>=3 ){
00801     sprintf(zBuf, "%d", N);
00802     Tcl_SetVar(interp, argv[2], zBuf, 0);
00803   }
00804   if( argc>=4 ){
00805     Tcl_SetVar(interp, argv[3], "", 0);
00806     if( azValue ){
00807       for(i=0; i<N; i++){
00808         Tcl_SetVar(interp, argv[3], azValue[i] ? azValue[i] : "",
00809             TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
00810       }
00811     }
00812   }
00813   if( argc==5 ){
00814     Tcl_SetVar(interp, argv[4], "", 0);
00815     if( azColName ){
00816       for(i=0; i<N*2; i++){
00817         Tcl_SetVar(interp, argv[4], azColName[i] ? azColName[i] : "",
00818             TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
00819       }
00820     }
00821   }
00822   switch( rc ){
00823     case SQLITE_DONE:   zRc = "SQLITE_DONE";    break;
00824     case SQLITE_BUSY:   zRc = "SQLITE_BUSY";    break;
00825     case SQLITE_ROW:    zRc = "SQLITE_ROW";     break;
00826     case SQLITE_ERROR:  zRc = "SQLITE_ERROR";   break;
00827     case SQLITE_MISUSE: zRc = "SQLITE_MISUSE";  break;
00828     default:            zRc = "unknown";        break;
00829   }
00830   Tcl_AppendResult(interp, zRc, 0);
00831   return TCL_OK;
00832 }
00833 
00834 /*
00835 ** Usage:  sqlite_finalize  VM 
00836 **
00837 ** Shutdown a virtual machine.
00838 */
00839 static int test_finalize(
00840   void *NotUsed,
00841   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00842   int argc,              /* Number of arguments */
00843   char **argv            /* Text of each argument */
00844 ){
00845   sqlite_vm *vm;
00846   int rc;
00847   char *zErrMsg = 0;
00848   if( argc!=2 ){
00849     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 
00850        " VM\"", 0);
00851     return TCL_ERROR;
00852   }
00853   if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
00854   rc = sqlite_finalize(vm, &zErrMsg);
00855   if( rc ){
00856     char zBuf[50];
00857     sprintf(zBuf, "(%d) ", rc);
00858     Tcl_AppendResult(interp, zBuf, zErrMsg, 0);
00859     sqlite_freemem(zErrMsg);
00860     return TCL_ERROR;
00861   }
00862   return TCL_OK;
00863 }
00864 
00865 /*
00866 ** Usage:  sqlite_reset   VM 
00867 **
00868 ** Reset a virtual machine and prepare it to be run again.
00869 */
00870 static int test_reset(
00871   void *NotUsed,
00872   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00873   int argc,              /* Number of arguments */
00874   char **argv            /* Text of each argument */
00875 ){
00876   sqlite_vm *vm;
00877   int rc;
00878   char *zErrMsg = 0;
00879   if( argc!=2 ){
00880     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 
00881        " VM\"", 0);
00882     return TCL_ERROR;
00883   }
00884   if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
00885   rc = sqlite_reset(vm, &zErrMsg);
00886   if( rc ){
00887     char zBuf[50];
00888     sprintf(zBuf, "(%d) ", rc);
00889     Tcl_AppendResult(interp, zBuf, zErrMsg, 0);
00890     sqlite_freemem(zErrMsg);
00891     return TCL_ERROR;
00892   }
00893   return TCL_OK;
00894 }
00895 
00896 /*
00897 ** This is the "static_bind_value" that variables are bound to when
00898 ** the FLAG option of sqlite_bind is "static"
00899 */
00900 static char *sqlite_static_bind_value = 0;
00901 
00902 /*
00903 ** Usage:  sqlite_bind  VM  IDX  VALUE  FLAGS
00904 **
00905 ** Sets the value of the IDX-th occurance of "?" in the original SQL
00906 ** string.  VALUE is the new value.  If FLAGS=="null" then VALUE is
00907 ** ignored and the value is set to NULL.  If FLAGS=="static" then
00908 ** the value is set to the value of a static variable named
00909 ** "sqlite_static_bind_value".  If FLAGS=="normal" then a copy
00910 ** of the VALUE is made.
00911 */
00912 static int test_bind(
00913   void *NotUsed,
00914   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00915   int argc,              /* Number of arguments */
00916   char **argv            /* Text of each argument */
00917 ){
00918   sqlite_vm *vm;
00919   int rc;
00920   int idx;
00921   if( argc!=5 ){
00922     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 
00923        " VM IDX VALUE (null|static|normal)\"", 0);
00924     return TCL_ERROR;
00925   }
00926   if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
00927   if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR;
00928   if( strcmp(argv[4],"null")==0 ){
00929     rc = sqlite_bind(vm, idx, 0, 0, 0);
00930   }else if( strcmp(argv[4],"static")==0 ){
00931     rc = sqlite_bind(vm, idx, sqlite_static_bind_value, -1, 0);
00932   }else if( strcmp(argv[4],"normal")==0 ){
00933     rc = sqlite_bind(vm, idx, argv[3], -1, 1);
00934   }else{
00935     Tcl_AppendResult(interp, "4th argument should be "
00936         "\"null\" or \"static\" or \"normal\"", 0);
00937     return TCL_ERROR;
00938   }
00939   if( rc ){
00940     char zBuf[50];
00941     sprintf(zBuf, "(%d) ", rc);
00942     Tcl_AppendResult(interp, zBuf, sqlite_error_string(rc), 0);
00943     return TCL_ERROR;
00944   }
00945   return TCL_OK;
00946 }
00947 
00948 /*
00949 ** Usage:    breakpoint
00950 **
00951 ** This routine exists for one purpose - to provide a place to put a
00952 ** breakpoint with GDB that can be triggered using TCL code.  The use
00953 ** for this is when a particular test fails on (say) the 1485th iteration.
00954 ** In the TCL test script, we can add code like this:
00955 **
00956 **     if {$i==1485} breakpoint
00957 **
00958 ** Then run testfixture in the debugger and wait for the breakpoint to
00959 ** fire.  Then additional breakpoints can be set to trace down the bug.
00960 */
00961 static int test_breakpoint(
00962   void *NotUsed,
00963   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
00964   int argc,              /* Number of arguments */
00965   char **argv            /* Text of each argument */
00966 ){
00967   return TCL_OK;         /* Do nothing */
00968 }
00969 
00970 /*
00971 ** Register commands with the TCL interpreter.
00972 */
00973 int Sqlitetest1_Init(Tcl_Interp *interp){
00974   extern int sqlite_search_count;
00975   extern int sqlite_interrupt_count;
00976   extern int sqlite_open_file_count;
00977   extern int sqlite_current_time;
00978   extern int sqlite_temp_directory;
00979   static struct {
00980      char *zName;
00981      Tcl_CmdProc *xProc;
00982   } aCmd[] = {
00983      { "sqlite_mprintf_int",             (Tcl_CmdProc*)sqlite_mprintf_int    },
00984      { "sqlite_mprintf_str",             (Tcl_CmdProc*)sqlite_mprintf_str    },
00985      { "sqlite_mprintf_double",          (Tcl_CmdProc*)sqlite_mprintf_double },
00986      { "sqlite_mprintf_scaled",          (Tcl_CmdProc*)sqlite_mprintf_scaled },
00987      { "sqlite_mprintf_z_test",          (Tcl_CmdProc*)test_mprintf_z        },
00988      { "sqlite_open",                    (Tcl_CmdProc*)sqlite_test_open      },
00989      { "sqlite_last_insert_rowid",       (Tcl_CmdProc*)test_last_rowid       },
00990      { "sqlite_exec_printf",             (Tcl_CmdProc*)test_exec_printf      },
00991      { "sqlite_get_table_printf",        (Tcl_CmdProc*)test_get_table_printf },
00992      { "sqlite_close",                   (Tcl_CmdProc*)sqlite_test_close     },
00993      { "sqlite_create_function",         (Tcl_CmdProc*)test_create_function  },
00994      { "sqlite_create_aggregate",        (Tcl_CmdProc*)test_create_aggregate },
00995      { "sqlite_register_test_function",  (Tcl_CmdProc*)test_register_func    },
00996      { "sqlite_abort",                   (Tcl_CmdProc*)sqlite_abort          },
00997      { "sqlite_datatypes",               (Tcl_CmdProc*)sqlite_datatypes      },
00998 #ifdef MEMORY_DEBUG
00999      { "sqlite_malloc_fail",             (Tcl_CmdProc*)sqlite_malloc_fail    },
01000      { "sqlite_malloc_stat",             (Tcl_CmdProc*)sqlite_malloc_stat    },
01001 #endif
01002      { "sqlite_compile",                 (Tcl_CmdProc*)test_compile          },
01003      { "sqlite_step",                    (Tcl_CmdProc*)test_step             },
01004      { "sqlite_finalize",                (Tcl_CmdProc*)test_finalize         },
01005      { "sqlite_bind",                    (Tcl_CmdProc*)test_bind             },
01006      { "sqlite_reset",                   (Tcl_CmdProc*)test_reset            },
01007      { "breakpoint",                     (Tcl_CmdProc*)test_breakpoint       },
01008   };
01009   int i;
01010 
01011   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
01012     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
01013   }
01014   Tcl_LinkVar(interp, "sqlite_search_count", 
01015       (char*)&sqlite_search_count, TCL_LINK_INT);
01016   Tcl_LinkVar(interp, "sqlite_interrupt_count", 
01017       (char*)&sqlite_interrupt_count, TCL_LINK_INT);
01018   Tcl_LinkVar(interp, "sqlite_open_file_count", 
01019       (char*)&sqlite_open_file_count, TCL_LINK_INT);
01020   Tcl_LinkVar(interp, "sqlite_current_time", 
01021       (char*)&sqlite_current_time, TCL_LINK_INT);
01022   Tcl_LinkVar(interp, "sqlite_static_bind_value",
01023       (char*)&sqlite_static_bind_value, TCL_LINK_STRING);
01024   Tcl_LinkVar(interp, "sqlite_temp_directory",
01025       (char*)&sqlite_temp_directory, TCL_LINK_STRING);
01026   return TCL_OK;
01027 }

Generated on Sun Dec 25 12:29:52 2005 for sqlite 2.8.17 by  doxygen 1.4.2