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