xref: /illumos-gate/usr/src/lib/libsqlite/src/test1.c (revision 1da57d55)
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.36.2.1 2004/05/07 00:57:06 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 */
getDbPointer(Tcl_Interp * interp,const char * zA,sqlite ** ppDb)33 static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite **ppDb){
34   if( sscanf(zA, PTR_FMT, (void**)ppDb)!=1 &&
35       (zA[0]!='0' || zA[1]!='x' || sscanf(&zA[2], PTR_FMT, (void**)ppDb)!=1)
36   ){
37     Tcl_AppendResult(interp, "\"", zA, "\" is not a valid pointer value", 0);
38     return TCL_ERROR;
39   }
40   return TCL_OK;
41 }
42 
43 /*
44 ** Decode a pointer to an sqlite_vm object.
45 */
getVmPointer(Tcl_Interp * interp,const char * zArg,sqlite_vm ** ppVm)46 static int getVmPointer(Tcl_Interp *interp, const char *zArg, sqlite_vm **ppVm){
47   if( sscanf(zArg, PTR_FMT, (void**)ppVm)!=1 ){
48     Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0);
49     return TCL_ERROR;
50   }
51   return TCL_OK;
52 }
53 
54 /*
55 ** Generate a text representation of a pointer that can be understood
56 ** by the getDbPointer and getVmPointer routines above.
57 **
58 ** The problem is, on some machines (Solaris) if you do a printf with
59 ** "%p" you cannot turn around and do a scanf with the same "%p" and
60 ** get your pointer back.  You have to prepend a "0x" before it will
61 ** work.  Or at least that is what is reported to me (drh).  But this
62 ** behavior varies from machine to machine.  The solution used here is
63 ** to test the string right after it is generated to see if it can be
64 ** understood by scanf, and if not, try prepending an "0x" to see if
65 ** that helps.  If nothing works, a fatal error is generated.
66 */
makePointerStr(Tcl_Interp * interp,char * zPtr,void * p)67 static int makePointerStr(Tcl_Interp *interp, char *zPtr, void *p){
68   void *p2;
69   sprintf(zPtr, PTR_FMT, p);
70   if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){
71     sprintf(zPtr, "0x" PTR_FMT, p);
72     if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){
73       Tcl_AppendResult(interp, "unable to convert a pointer to a string "
74          "in the file " __FILE__ " in function makePointerStr().  Please "
75          "report this problem to the SQLite mailing list or as a new but "
76          "report.  Please provide detailed information about how you compiled "
77          "SQLite and what computer you are running on.", 0);
78       return TCL_ERROR;
79     }
80   }
81   return TCL_OK;
82 }
83 
84 /*
85 ** Usage:   sqlite_open filename
86 **
87 ** Returns:  The name of an open database.
88 */
sqlite_test_open(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)89 static int sqlite_test_open(
90   void *NotUsed,
91   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
92   int argc,              /* Number of arguments */
93   char **argv            /* Text of each argument */
94 ){
95   sqlite *db;
96   char *zErr = 0;
97   char zBuf[100];
98   if( argc!=2 ){
99     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
100        " FILENAME\"", 0);
101     return TCL_ERROR;
102   }
103   db = sqlite_open(argv[1], 0666, &zErr);
104   if( db==0 ){
105     Tcl_AppendResult(interp, zErr, 0);
106     free(zErr);
107     return TCL_ERROR;
108   }
109   if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
110   Tcl_AppendResult(interp, zBuf, 0);
111   return TCL_OK;
112 }
113 
114 /*
115 ** The callback routine for sqlite_exec_printf().
116 */
exec_printf_cb(void * pArg,int argc,char ** argv,char ** name)117 static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){
118   Tcl_DString *str = (Tcl_DString*)pArg;
119   int i;
120 
121   if( Tcl_DStringLength(str)==0 ){
122     for(i=0; i<argc; i++){
123       Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL");
124     }
125   }
126   for(i=0; i<argc; i++){
127     Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL");
128   }
129   return 0;
130 }
131 
132 /*
133 ** Usage:  sqlite_exec_printf  DB  FORMAT  STRING
134 **
135 ** Invoke the sqlite_exec_printf() interface using the open database
136 ** DB.  The SQL is the string FORMAT.  The format string should contain
137 ** one %s or %q.  STRING is the value inserted into %s or %q.
138 */
test_exec_printf(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)139 static int test_exec_printf(
140   void *NotUsed,
141   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
142   int argc,              /* Number of arguments */
143   char **argv            /* Text of each argument */
144 ){
145   sqlite *db;
146   Tcl_DString str;
147   int rc;
148   char *zErr = 0;
149   char zBuf[30];
150   if( argc!=4 ){
151     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
152        " DB FORMAT STRING", 0);
153     return TCL_ERROR;
154   }
155   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
156   Tcl_DStringInit(&str);
157   rc = sqlite_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]);
158   sprintf(zBuf, "%d", rc);
159   Tcl_AppendElement(interp, zBuf);
160   Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
161   Tcl_DStringFree(&str);
162   if( zErr ) free(zErr);
163   return TCL_OK;
164 }
165 
166 /*
167 ** Usage:  sqlite_mprintf_z_test  SEPARATOR  ARG0  ARG1 ...
168 **
169 ** Test the %z format of mprintf().  Use multiple mprintf() calls to
170 ** concatenate arg0 through argn using separator as the separator.
171 ** Return the result.
172 */
test_mprintf_z(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)173 static int test_mprintf_z(
174   void *NotUsed,
175   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
176   int argc,              /* Number of arguments */
177   char **argv            /* Text of each argument */
178 ){
179   char *zResult = 0;
180   int i;
181 
182   for(i=2; i<argc; i++){
183     zResult = sqliteMPrintf("%z%s%s", zResult, argv[1], argv[i]);
184   }
185   Tcl_AppendResult(interp, zResult, 0);
186   sqliteFree(zResult);
187   return TCL_OK;
188 }
189 
190 /*
191 ** Usage:  sqlite_get_table_printf  DB  FORMAT  STRING
192 **
193 ** Invoke the sqlite_get_table_printf() interface using the open database
194 ** DB.  The SQL is the string FORMAT.  The format string should contain
195 ** one %s or %q.  STRING is the value inserted into %s or %q.
196 */
test_get_table_printf(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)197 static int test_get_table_printf(
198   void *NotUsed,
199   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
200   int argc,              /* Number of arguments */
201   char **argv            /* Text of each argument */
202 ){
203   sqlite *db;
204   Tcl_DString str;
205   int rc;
206   char *zErr = 0;
207   int nRow, nCol;
208   char **aResult;
209   int i;
210   char zBuf[30];
211   if( argc!=4 ){
212     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
213        " DB FORMAT STRING", 0);
214     return TCL_ERROR;
215   }
216   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
217   Tcl_DStringInit(&str);
218   rc = sqlite_get_table_printf(db, argv[2], &aResult, &nRow, &nCol,
219                &zErr, argv[3]);
220   sprintf(zBuf, "%d", rc);
221   Tcl_AppendElement(interp, zBuf);
222   if( rc==SQLITE_OK ){
223     sprintf(zBuf, "%d", nRow);
224     Tcl_AppendElement(interp, zBuf);
225     sprintf(zBuf, "%d", nCol);
226     Tcl_AppendElement(interp, zBuf);
227     for(i=0; i<(nRow+1)*nCol; i++){
228       Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL");
229     }
230   }else{
231     Tcl_AppendElement(interp, zErr);
232   }
233   sqlite_free_table(aResult);
234   if( zErr ) free(zErr);
235   return TCL_OK;
236 }
237 
238 
239 /*
240 ** Usage:  sqlite_last_insert_rowid DB
241 **
242 ** Returns the integer ROWID of the most recent insert.
243 */
test_last_rowid(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)244 static int test_last_rowid(
245   void *NotUsed,
246   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
247   int argc,              /* Number of arguments */
248   char **argv            /* Text of each argument */
249 ){
250   sqlite *db;
251   char zBuf[30];
252 
253   if( argc!=2 ){
254     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0);
255     return TCL_ERROR;
256   }
257   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
258   sprintf(zBuf, "%d", sqlite_last_insert_rowid(db));
259   Tcl_AppendResult(interp, zBuf, 0);
260   return SQLITE_OK;
261 }
262 
263 /*
264 ** Usage:  sqlite_close DB
265 **
266 ** Closes the database opened by sqlite_open.
267 */
sqlite_test_close(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)268 static int sqlite_test_close(
269   void *NotUsed,
270   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
271   int argc,              /* Number of arguments */
272   char **argv            /* Text of each argument */
273 ){
274   sqlite *db;
275   if( argc!=2 ){
276     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
277        " FILENAME\"", 0);
278     return TCL_ERROR;
279   }
280   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
281   sqlite_close(db);
282   return TCL_OK;
283 }
284 
285 /*
286 ** Implementation of the x_coalesce() function.
287 ** Return the first argument non-NULL argument.
288 */
ifnullFunc(sqlite_func * context,int argc,const char ** argv)289 static void ifnullFunc(sqlite_func *context, int argc, const char **argv){
290   int i;
291   for(i=0; i<argc; i++){
292     if( argv[i] ){
293       sqlite_set_result_string(context, argv[i], -1);
294       break;
295     }
296   }
297 }
298 
299 /*
300 ** A structure into which to accumulate text.
301 */
302 struct dstr {
303   int nAlloc;  /* Space allocated */
304   int nUsed;   /* Space used */
305   char *z;     /* The space */
306 };
307 
308 /*
309 ** Append text to a dstr
310 */
dstrAppend(struct dstr * p,const char * z,int divider)311 static void dstrAppend(struct dstr *p, const char *z, int divider){
312   int n = strlen(z);
313   if( p->nUsed + n + 2 > p->nAlloc ){
314     char *zNew;
315     p->nAlloc = p->nAlloc*2 + n + 200;
316     zNew = sqliteRealloc(p->z, p->nAlloc);
317     if( zNew==0 ){
318       sqliteFree(p->z);
319       memset(p, 0, sizeof(*p));
320       return;
321     }
322     p->z = zNew;
323   }
324   if( divider && p->nUsed>0 ){
325     p->z[p->nUsed++] = divider;
326   }
327   memcpy(&p->z[p->nUsed], z, n+1);
328   p->nUsed += n;
329 }
330 
331 /*
332 ** Invoked for each callback from sqliteExecFunc
333 */
execFuncCallback(void * pData,int argc,char ** argv,char ** NotUsed)334 static int execFuncCallback(void *pData, int argc, char **argv, char **NotUsed){
335   struct dstr *p = (struct dstr*)pData;
336   int i;
337   for(i=0; i<argc; i++){
338     if( argv[i]==0 ){
339       dstrAppend(p, "NULL", ' ');
340     }else{
341       dstrAppend(p, argv[i], ' ');
342     }
343   }
344   return 0;
345 }
346 
347 /*
348 ** Implementation of the x_sqlite_exec() function.  This function takes
349 ** a single argument and attempts to execute that argument as SQL code.
350 ** This is illegal and should set the SQLITE_MISUSE flag on the database.
351 **
352 ** 2004-Jan-07:  We have changed this to make it legal to call sqlite_exec()
353 ** from within a function call.
354 **
355 ** This routine simulates the effect of having two threads attempt to
356 ** use the same database at the same time.
357 */
sqliteExecFunc(sqlite_func * context,int argc,const char ** argv)358 static void sqliteExecFunc(sqlite_func *context, int argc, const char **argv){
359   struct dstr x;
360   memset(&x, 0, sizeof(x));
361   sqlite_exec((sqlite*)sqlite_user_data(context), argv[0],
362       execFuncCallback, &x, 0);
363   sqlite_set_result_string(context, x.z, x.nUsed);
364   sqliteFree(x.z);
365 }
366 
367 /*
368 ** Usage:  sqlite_test_create_function DB
369 **
370 ** Call the sqlite_create_function API on the given database in order
371 ** to create a function named "x_coalesce".  This function does the same thing
372 ** as the "coalesce" function.  This function also registers an SQL function
373 ** named "x_sqlite_exec" that invokes sqlite_exec().  Invoking sqlite_exec()
374 ** in this way is illegal recursion and should raise an SQLITE_MISUSE error.
375 ** The effect is similar to trying to use the same database connection from
376 ** two threads at the same time.
377 **
378 ** The original motivation for this routine was to be able to call the
379 ** sqlite_create_function function while a query is in progress in order
380 ** to test the SQLITE_MISUSE detection logic.
381 */
test_create_function(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)382 static int test_create_function(
383   void *NotUsed,
384   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
385   int argc,              /* Number of arguments */
386   char **argv            /* Text of each argument */
387 ){
388   sqlite *db;
389   extern void Md5_Register(sqlite*);
390   if( argc!=2 ){
391     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
392        " FILENAME\"", 0);
393     return TCL_ERROR;
394   }
395   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
396   sqlite_create_function(db, "x_coalesce", -1, ifnullFunc, 0);
397   sqlite_create_function(db, "x_sqlite_exec", 1, sqliteExecFunc, db);
398   return TCL_OK;
399 }
400 
401 /*
402 ** Routines to implement the x_count() aggregate function.
403 */
404 typedef struct CountCtx CountCtx;
405 struct CountCtx {
406   int n;
407 };
countStep(sqlite_func * context,int argc,const char ** argv)408 static void countStep(sqlite_func *context, int argc, const char **argv){
409   CountCtx *p;
410   p = sqlite_aggregate_context(context, sizeof(*p));
411   if( (argc==0 || argv[0]) && p ){
412     p->n++;
413   }
414 }
countFinalize(sqlite_func * context)415 static void countFinalize(sqlite_func *context){
416   CountCtx *p;
417   p = sqlite_aggregate_context(context, sizeof(*p));
418   sqlite_set_result_int(context, p ? p->n : 0);
419 }
420 
421 /*
422 ** Usage:  sqlite_test_create_aggregate DB
423 **
424 ** Call the sqlite_create_function API on the given database in order
425 ** to create a function named "x_count".  This function does the same thing
426 ** as the "md5sum" function.
427 **
428 ** The original motivation for this routine was to be able to call the
429 ** sqlite_create_aggregate function while a query is in progress in order
430 ** to test the SQLITE_MISUSE detection logic.
431 */
test_create_aggregate(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)432 static int test_create_aggregate(
433   void *NotUsed,
434   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
435   int argc,              /* Number of arguments */
436   char **argv            /* Text of each argument */
437 ){
438   sqlite *db;
439   if( argc!=2 ){
440     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
441        " FILENAME\"", 0);
442     return TCL_ERROR;
443   }
444   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
445   sqlite_create_aggregate(db, "x_count", 0, countStep, countFinalize, 0);
446   sqlite_create_aggregate(db, "x_count", 1, countStep, countFinalize, 0);
447   return TCL_OK;
448 }
449 
450 
451 
452 /*
453 ** Usage:  sqlite_mprintf_int FORMAT INTEGER INTEGER INTEGER
454 **
455 ** Call mprintf with three integer arguments
456 */
sqlite_mprintf_int(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)457 static int sqlite_mprintf_int(
458   void *NotUsed,
459   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
460   int argc,              /* Number of arguments */
461   char **argv            /* Text of each argument */
462 ){
463   int a[3], i;
464   char *z;
465   if( argc!=5 ){
466     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
467        " FORMAT INT INT INT\"", 0);
468     return TCL_ERROR;
469   }
470   for(i=2; i<5; i++){
471     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
472   }
473   z = sqlite_mprintf(argv[1], a[0], a[1], a[2]);
474   Tcl_AppendResult(interp, z, 0);
475   sqlite_freemem(z);
476   return TCL_OK;
477 }
478 
479 /*
480 ** Usage:  sqlite_mprintf_str FORMAT INTEGER INTEGER STRING
481 **
482 ** Call mprintf with two integer arguments and one string argument
483 */
sqlite_mprintf_str(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)484 static int sqlite_mprintf_str(
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 a[3], i;
491   char *z;
492   if( argc<4 || argc>5 ){
493     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
494        " FORMAT INT INT ?STRING?\"", 0);
495     return TCL_ERROR;
496   }
497   for(i=2; i<4; i++){
498     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
499   }
500   z = sqlite_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL);
501   Tcl_AppendResult(interp, z, 0);
502   sqlite_freemem(z);
503   return TCL_OK;
504 }
505 
506 /*
507 ** Usage:  sqlite_mprintf_str FORMAT INTEGER INTEGER DOUBLE
508 **
509 ** Call mprintf with two integer arguments and one double argument
510 */
sqlite_mprintf_double(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)511 static int sqlite_mprintf_double(
512   void *NotUsed,
513   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
514   int argc,              /* Number of arguments */
515   char **argv            /* Text of each argument */
516 ){
517   int a[3], i;
518   double r;
519   char *z;
520   if( argc!=5 ){
521     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
522        " FORMAT INT INT STRING\"", 0);
523     return TCL_ERROR;
524   }
525   for(i=2; i<4; i++){
526     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
527   }
528   if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR;
529   z = sqlite_mprintf(argv[1], a[0], a[1], r);
530   Tcl_AppendResult(interp, z, 0);
531   sqlite_freemem(z);
532   return TCL_OK;
533 }
534 
535 /*
536 ** Usage:  sqlite_mprintf_str FORMAT DOUBLE DOUBLE
537 **
538 ** Call mprintf with a single double argument which is the product of the
539 ** two arguments given above.  This is used to generate overflow and underflow
540 ** doubles to test that they are converted properly.
541 */
sqlite_mprintf_scaled(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)542 static int sqlite_mprintf_scaled(
543   void *NotUsed,
544   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
545   int argc,              /* Number of arguments */
546   char **argv            /* Text of each argument */
547 ){
548   int i;
549   double r[2];
550   char *z;
551   if( argc!=4 ){
552     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
553        " FORMAT DOUBLE DOUBLE\"", 0);
554     return TCL_ERROR;
555   }
556   for(i=2; i<4; i++){
557     if( Tcl_GetDouble(interp, argv[i], &r[i-2]) ) return TCL_ERROR;
558   }
559   z = sqlite_mprintf(argv[1], r[0]*r[1]);
560   Tcl_AppendResult(interp, z, 0);
561   sqlite_freemem(z);
562   return TCL_OK;
563 }
564 
565 /*
566 ** Usage: sqlite_malloc_fail N
567 **
568 ** Rig sqliteMalloc() to fail on the N-th call.  Turn off this mechanism
569 ** and reset the sqlite_malloc_failed variable is N==0.
570 */
571 #ifdef MEMORY_DEBUG
sqlite_malloc_fail(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)572 static int sqlite_malloc_fail(
573   void *NotUsed,
574   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
575   int argc,              /* Number of arguments */
576   char **argv            /* Text of each argument */
577 ){
578   int n;
579   if( argc!=2 ){
580     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0);
581     return TCL_ERROR;
582   }
583   if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
584   sqlite_iMallocFail = n;
585   sqlite_malloc_failed = 0;
586   return TCL_OK;
587 }
588 #endif
589 
590 /*
591 ** Usage: sqlite_malloc_stat
592 **
593 ** Return the number of prior calls to sqliteMalloc() and sqliteFree().
594 */
595 #ifdef MEMORY_DEBUG
sqlite_malloc_stat(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)596 static int sqlite_malloc_stat(
597   void *NotUsed,
598   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
599   int argc,              /* Number of arguments */
600   char **argv            /* Text of each argument */
601 ){
602   char zBuf[200];
603   sprintf(zBuf, "%d %d %d", sqlite_nMalloc, sqlite_nFree, sqlite_iMallocFail);
604   Tcl_AppendResult(interp, zBuf, 0);
605   return TCL_OK;
606 }
607 #endif
608 
609 /*
610 ** Usage:  sqlite_abort
611 **
612 ** Shutdown the process immediately.  This is not a clean shutdown.
613 ** This command is used to test the recoverability of a database in
614 ** the event of a program crash.
615 */
sqlite_abort(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)616 static int sqlite_abort(
617   void *NotUsed,
618   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
619   int argc,              /* Number of arguments */
620   char **argv            /* Text of each argument */
621 ){
622   assert( interp==0 );   /* This will always fail */
623   return TCL_OK;
624 }
625 
626 /*
627 ** The following routine is a user-defined SQL function whose purpose
628 ** is to test the sqlite_set_result() API.
629 */
testFunc(sqlite_func * context,int argc,const char ** argv)630 static void testFunc(sqlite_func *context, int argc, const char **argv){
631   while( argc>=2 ){
632     if( argv[0]==0 ){
633       sqlite_set_result_error(context, "first argument to test function "
634          "may not be NULL", -1);
635     }else if( sqliteStrICmp(argv[0],"string")==0 ){
636       sqlite_set_result_string(context, argv[1], -1);
637     }else if( argv[1]==0 ){
638       sqlite_set_result_error(context, "2nd argument may not be NULL if the "
639          "first argument is not \"string\"", -1);
640     }else if( sqliteStrICmp(argv[0],"int")==0 ){
641       sqlite_set_result_int(context, atoi(argv[1]));
642     }else if( sqliteStrICmp(argv[0],"double")==0 ){
643       sqlite_set_result_double(context, sqliteAtoF(argv[1], 0));
644     }else{
645       sqlite_set_result_error(context,"first argument should be one of: "
646           "string int double", -1);
647     }
648     argc -= 2;
649     argv += 2;
650   }
651 }
652 
653 /*
654 ** Usage:   sqlite_register_test_function  DB  NAME
655 **
656 ** Register the test SQL function on the database DB under the name NAME.
657 */
test_register_func(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)658 static int test_register_func(
659   void *NotUsed,
660   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
661   int argc,              /* Number of arguments */
662   char **argv            /* Text of each argument */
663 ){
664   sqlite *db;
665   int rc;
666   if( argc!=3 ){
667     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
668        " DB FUNCTION-NAME", 0);
669     return TCL_ERROR;
670   }
671   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
672   rc = sqlite_create_function(db, argv[2], -1, testFunc, 0);
673   if( rc!=0 ){
674     Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
675     return TCL_ERROR;
676   }
677   return TCL_OK;
678 }
679 
680 /*
681 ** This SQLite callback records the datatype of all columns.
682 **
683 ** The pArg argument is really a pointer to a TCL interpreter.  The
684 ** column names are inserted as the result of this interpreter.
685 **
686 ** This routine returns non-zero which causes the query to abort.
687 */
rememberDataTypes(void * pArg,int nCol,char ** argv,char ** colv)688 static int rememberDataTypes(void *pArg, int nCol, char **argv, char **colv){
689   int i;
690   Tcl_Interp *interp = (Tcl_Interp*)pArg;
691   Tcl_Obj *pList, *pElem;
692   if( colv[nCol+1]==0 ){
693     return 1;
694   }
695   pList = Tcl_NewObj();
696   for(i=0; i<nCol; i++){
697     pElem = Tcl_NewStringObj(colv[i+nCol] ? colv[i+nCol] : "NULL", -1);
698     Tcl_ListObjAppendElement(interp, pList, pElem);
699   }
700   Tcl_SetObjResult(interp, pList);
701   return 1;
702 }
703 
704 /*
705 ** Invoke an SQL statement but ignore all the data in the result.  Instead,
706 ** return a list that consists of the datatypes of the various columns.
707 **
708 ** This only works if "PRAGMA show_datatypes=on" has been executed against
709 ** the database connection.
710 */
sqlite_datatypes(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)711 static int sqlite_datatypes(
712   void *NotUsed,
713   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
714   int argc,              /* Number of arguments */
715   char **argv            /* Text of each argument */
716 ){
717   sqlite *db;
718   int rc;
719   if( argc!=3 ){
720     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
721        " DB SQL", 0);
722     return TCL_ERROR;
723   }
724   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
725   rc = sqlite_exec(db, argv[2], rememberDataTypes, interp, 0);
726   if( rc!=0 && rc!=SQLITE_ABORT ){
727     Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
728     return TCL_ERROR;
729   }
730   return TCL_OK;
731 }
732 
733 /*
734 ** Usage:  sqlite_compile  DB  SQL  ?TAILVAR?
735 **
736 ** Attempt to compile an SQL statement.  Return a pointer to the virtual
737 ** machine used to execute that statement.  Unprocessed SQL is written
738 ** into TAILVAR.
739 */
test_compile(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)740 static int test_compile(
741   void *NotUsed,
742   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
743   int argc,              /* Number of arguments */
744   char **argv            /* Text of each argument */
745 ){
746   sqlite *db;
747   sqlite_vm *vm;
748   int rc;
749   char *zErr = 0;
750   const char *zTail;
751   char zBuf[50];
752   if( argc!=3 && argc!=4 ){
753     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
754        " DB SQL TAILVAR", 0);
755     return TCL_ERROR;
756   }
757   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
758   rc = sqlite_compile(db, argv[2], argc==4 ? &zTail : 0, &vm, &zErr);
759   if( argc==4 ) Tcl_SetVar(interp, argv[3], zTail, 0);
760   if( rc ){
761     assert( vm==0 );
762     sprintf(zBuf, "(%d) ", rc);
763     Tcl_AppendResult(interp, zBuf, zErr, 0);
764     sqlite_freemem(zErr);
765     return TCL_ERROR;
766   }
767   if( vm ){
768     if( makePointerStr(interp, zBuf, vm) ) return TCL_ERROR;
769     Tcl_AppendResult(interp, zBuf, 0);
770   }
771   return TCL_OK;
772 }
773 
774 /*
775 ** Usage:  sqlite_step  VM  ?NVAR?  ?VALUEVAR?  ?COLNAMEVAR?
776 **
777 ** Step a virtual machine.  Return a the result code as a string.
778 ** Column results are written into three variables.
779 */
test_step(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)780 static int test_step(
781   void *NotUsed,
782   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
783   int argc,              /* Number of arguments */
784   char **argv            /* Text of each argument */
785 ){
786   sqlite_vm *vm;
787   int rc, i;
788   const char **azValue = 0;
789   const char **azColName = 0;
790   int N = 0;
791   char *zRc;
792   char zBuf[50];
793   if( argc<2 || argc>5 ){
794     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
795        " VM NVAR VALUEVAR COLNAMEVAR", 0);
796     return TCL_ERROR;
797   }
798   if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
799   rc = sqlite_step(vm, argc>=3?&N:0, argc>=4?&azValue:0, argc==5?&azColName:0);
800   if( argc>=3 ){
801     sprintf(zBuf, "%d", N);
802     Tcl_SetVar(interp, argv[2], zBuf, 0);
803   }
804   if( argc>=4 ){
805     Tcl_SetVar(interp, argv[3], "", 0);
806     if( azValue ){
807       for(i=0; i<N; i++){
808         Tcl_SetVar(interp, argv[3], azValue[i] ? azValue[i] : "",
809             TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
810       }
811     }
812   }
813   if( argc==5 ){
814     Tcl_SetVar(interp, argv[4], "", 0);
815     if( azColName ){
816       for(i=0; i<N*2; i++){
817         Tcl_SetVar(interp, argv[4], azColName[i] ? azColName[i] : "",
818             TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
819       }
820     }
821   }
822   switch( rc ){
823     case SQLITE_DONE:   zRc = "SQLITE_DONE";    break;
824     case SQLITE_BUSY:   zRc = "SQLITE_BUSY";    break;
825     case SQLITE_ROW:    zRc = "SQLITE_ROW";     break;
826     case SQLITE_ERROR:  zRc = "SQLITE_ERROR";   break;
827     case SQLITE_MISUSE: zRc = "SQLITE_MISUSE";  break;
828     default:            zRc = "unknown";        break;
829   }
830   Tcl_AppendResult(interp, zRc, 0);
831   return TCL_OK;
832 }
833 
834 /*
835 ** Usage:  sqlite_finalize  VM
836 **
837 ** Shutdown a virtual machine.
838 */
test_finalize(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)839 static int test_finalize(
840   void *NotUsed,
841   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
842   int argc,              /* Number of arguments */
843   char **argv            /* Text of each argument */
844 ){
845   sqlite_vm *vm;
846   int rc;
847   char *zErrMsg = 0;
848   if( argc!=2 ){
849     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
850        " VM\"", 0);
851     return TCL_ERROR;
852   }
853   if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
854   rc = sqlite_finalize(vm, &zErrMsg);
855   if( rc ){
856     char zBuf[50];
857     sprintf(zBuf, "(%d) ", rc);
858     Tcl_AppendResult(interp, zBuf, zErrMsg, 0);
859     sqlite_freemem(zErrMsg);
860     return TCL_ERROR;
861   }
862   return TCL_OK;
863 }
864 
865 /*
866 ** Usage:  sqlite_reset   VM
867 **
868 ** Reset a virtual machine and prepare it to be run again.
869 */
test_reset(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)870 static int test_reset(
871   void *NotUsed,
872   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
873   int argc,              /* Number of arguments */
874   char **argv            /* Text of each argument */
875 ){
876   sqlite_vm *vm;
877   int rc;
878   char *zErrMsg = 0;
879   if( argc!=2 ){
880     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
881        " VM\"", 0);
882     return TCL_ERROR;
883   }
884   if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
885   rc = sqlite_reset(vm, &zErrMsg);
886   if( rc ){
887     char zBuf[50];
888     sprintf(zBuf, "(%d) ", rc);
889     Tcl_AppendResult(interp, zBuf, zErrMsg, 0);
890     sqlite_freemem(zErrMsg);
891     return TCL_ERROR;
892   }
893   return TCL_OK;
894 }
895 
896 /*
897 ** This is the "static_bind_value" that variables are bound to when
898 ** the FLAG option of sqlite_bind is "static"
899 */
900 static char *sqlite_static_bind_value = 0;
901 
902 /*
903 ** Usage:  sqlite_bind  VM  IDX  VALUE  FLAGS
904 **
905 ** Sets the value of the IDX-th occurance of "?" in the original SQL
906 ** string.  VALUE is the new value.  If FLAGS=="null" then VALUE is
907 ** ignored and the value is set to NULL.  If FLAGS=="static" then
908 ** the value is set to the value of a static variable named
909 ** "sqlite_static_bind_value".  If FLAGS=="normal" then a copy
910 ** of the VALUE is made.
911 */
test_bind(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)912 static int test_bind(
913   void *NotUsed,
914   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
915   int argc,              /* Number of arguments */
916   char **argv            /* Text of each argument */
917 ){
918   sqlite_vm *vm;
919   int rc;
920   int idx;
921   if( argc!=5 ){
922     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
923        " VM IDX VALUE (null|static|normal)\"", 0);
924     return TCL_ERROR;
925   }
926   if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
927   if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR;
928   if( strcmp(argv[4],"null")==0 ){
929     rc = sqlite_bind(vm, idx, 0, 0, 0);
930   }else if( strcmp(argv[4],"static")==0 ){
931     rc = sqlite_bind(vm, idx, sqlite_static_bind_value, -1, 0);
932   }else if( strcmp(argv[4],"normal")==0 ){
933     rc = sqlite_bind(vm, idx, argv[3], -1, 1);
934   }else{
935     Tcl_AppendResult(interp, "4th argument should be "
936         "\"null\" or \"static\" or \"normal\"", 0);
937     return TCL_ERROR;
938   }
939   if( rc ){
940     char zBuf[50];
941     sprintf(zBuf, "(%d) ", rc);
942     Tcl_AppendResult(interp, zBuf, sqlite_error_string(rc), 0);
943     return TCL_ERROR;
944   }
945   return TCL_OK;
946 }
947 
948 /*
949 ** Usage:    breakpoint
950 **
951 ** This routine exists for one purpose - to provide a place to put a
952 ** breakpoint with GDB that can be triggered using TCL code.  The use
953 ** for this is when a particular test fails on (say) the 1485th iteration.
954 ** In the TCL test script, we can add code like this:
955 **
956 **     if {$i==1485} breakpoint
957 **
958 ** Then run testfixture in the debugger and wait for the breakpoint to
959 ** fire.  Then additional breakpoints can be set to trace down the bug.
960 */
test_breakpoint(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)961 static int test_breakpoint(
962   void *NotUsed,
963   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
964   int argc,              /* Number of arguments */
965   char **argv            /* Text of each argument */
966 ){
967   return TCL_OK;         /* Do nothing */
968 }
969 
970 /*
971 ** Register commands with the TCL interpreter.
972 */
Sqlitetest1_Init(Tcl_Interp * interp)973 int Sqlitetest1_Init(Tcl_Interp *interp){
974   extern int sqlite_search_count;
975   extern int sqlite_interrupt_count;
976   extern int sqlite_open_file_count;
977   extern int sqlite_current_time;
978   extern int sqlite_temp_directory;
979   static struct {
980      char *zName;
981      Tcl_CmdProc *xProc;
982   } aCmd[] = {
983      { "sqlite_mprintf_int",             (Tcl_CmdProc*)sqlite_mprintf_int    },
984      { "sqlite_mprintf_str",             (Tcl_CmdProc*)sqlite_mprintf_str    },
985      { "sqlite_mprintf_double",          (Tcl_CmdProc*)sqlite_mprintf_double },
986      { "sqlite_mprintf_scaled",          (Tcl_CmdProc*)sqlite_mprintf_scaled },
987      { "sqlite_mprintf_z_test",          (Tcl_CmdProc*)test_mprintf_z        },
988      { "sqlite_open",                    (Tcl_CmdProc*)sqlite_test_open      },
989      { "sqlite_last_insert_rowid",       (Tcl_CmdProc*)test_last_rowid       },
990      { "sqlite_exec_printf",             (Tcl_CmdProc*)test_exec_printf      },
991      { "sqlite_get_table_printf",        (Tcl_CmdProc*)test_get_table_printf },
992      { "sqlite_close",                   (Tcl_CmdProc*)sqlite_test_close     },
993      { "sqlite_create_function",         (Tcl_CmdProc*)test_create_function  },
994      { "sqlite_create_aggregate",        (Tcl_CmdProc*)test_create_aggregate },
995      { "sqlite_register_test_function",  (Tcl_CmdProc*)test_register_func    },
996      { "sqlite_abort",                   (Tcl_CmdProc*)sqlite_abort          },
997      { "sqlite_datatypes",               (Tcl_CmdProc*)sqlite_datatypes      },
998 #ifdef MEMORY_DEBUG
999      { "sqlite_malloc_fail",             (Tcl_CmdProc*)sqlite_malloc_fail    },
1000      { "sqlite_malloc_stat",             (Tcl_CmdProc*)sqlite_malloc_stat    },
1001 #endif
1002      { "sqlite_compile",                 (Tcl_CmdProc*)test_compile          },
1003      { "sqlite_step",                    (Tcl_CmdProc*)test_step             },
1004      { "sqlite_finalize",                (Tcl_CmdProc*)test_finalize         },
1005      { "sqlite_bind",                    (Tcl_CmdProc*)test_bind             },
1006      { "sqlite_reset",                   (Tcl_CmdProc*)test_reset            },
1007      { "breakpoint",                     (Tcl_CmdProc*)test_breakpoint       },
1008   };
1009   int i;
1010 
1011   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
1012     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
1013   }
1014   Tcl_LinkVar(interp, "sqlite_search_count",
1015       (char*)&sqlite_search_count, TCL_LINK_INT);
1016   Tcl_LinkVar(interp, "sqlite_interrupt_count",
1017       (char*)&sqlite_interrupt_count, TCL_LINK_INT);
1018   Tcl_LinkVar(interp, "sqlite_open_file_count",
1019       (char*)&sqlite_open_file_count, TCL_LINK_INT);
1020   Tcl_LinkVar(interp, "sqlite_current_time",
1021       (char*)&sqlite_current_time, TCL_LINK_INT);
1022   Tcl_LinkVar(interp, "sqlite_static_bind_value",
1023       (char*)&sqlite_static_bind_value, TCL_LINK_STRING);
1024   Tcl_LinkVar(interp, "sqlite_temp_directory",
1025       (char*)&sqlite_temp_directory, TCL_LINK_STRING);
1026   return TCL_OK;
1027 }
1028