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