xref: /sqlite-3.40.0/src/test1.c (revision 94e92032)
1d1bf3512Sdrh /*
2b19a2bc6Sdrh ** 2001 September 15
3d1bf3512Sdrh **
4b19a2bc6Sdrh ** The author disclaims copyright to this source code.  In place of
5b19a2bc6Sdrh ** a legal notice, here is a blessing:
6d1bf3512Sdrh **
7b19a2bc6Sdrh **    May you do good and not evil.
8b19a2bc6Sdrh **    May you find forgiveness for yourself and forgive others.
9b19a2bc6Sdrh **    May you share freely, never taking more than you give.
10d1bf3512Sdrh **
11d1bf3512Sdrh *************************************************************************
12d1bf3512Sdrh ** Code for testing the printf() interface to SQLite.  This code
13d1bf3512Sdrh ** is not included in the SQLite library.  It is used for automated
14d1bf3512Sdrh ** testing of the SQLite library.
15d1bf3512Sdrh **
16*94e92032Sdrh ** $Id: test1.c,v 1.22 2003/02/16 22:21:32 drh Exp $
17d1bf3512Sdrh */
18d1bf3512Sdrh #include "sqliteInt.h"
19d1bf3512Sdrh #include "tcl.h"
20*94e92032Sdrh #include "os.h"
21d1bf3512Sdrh #include <stdlib.h>
22d1bf3512Sdrh #include <string.h>
23d1bf3512Sdrh 
24*94e92032Sdrh #if OS_WIN
25*94e92032Sdrh # define PTR_FMT "%x"
26*94e92032Sdrh #else
27*94e92032Sdrh # define PTR_FMT "%p"
28*94e92032Sdrh #endif
29*94e92032Sdrh 
30d1bf3512Sdrh /*
31b86ccfb2Sdrh ** Decode a pointer to an sqlite object.
32b86ccfb2Sdrh */
33b86ccfb2Sdrh static int getDbPointer(Tcl_Interp *interp, const char *zArg, sqlite **ppDb){
34*94e92032Sdrh   if( sscanf(zArg, PTR_FMT, (void**)ppDb)!=1 ){
35b86ccfb2Sdrh     Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0);
36b86ccfb2Sdrh     return TCL_ERROR;
37b86ccfb2Sdrh   }
38b86ccfb2Sdrh   return TCL_OK;
39b86ccfb2Sdrh }
40b86ccfb2Sdrh 
41b86ccfb2Sdrh /*
42b86ccfb2Sdrh ** Decode a pointer to an sqlite_vm object.
43b86ccfb2Sdrh */
44b86ccfb2Sdrh static int getVmPointer(Tcl_Interp *interp, const char *zArg, sqlite_vm **ppVm){
45*94e92032Sdrh   if( sscanf(zArg, PTR_FMT, (void**)ppVm)!=1 ){
46b86ccfb2Sdrh     Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0);
47b86ccfb2Sdrh     return TCL_ERROR;
48b86ccfb2Sdrh   }
49b86ccfb2Sdrh   return TCL_OK;
50b86ccfb2Sdrh }
51b86ccfb2Sdrh 
52b86ccfb2Sdrh /*
53d1bf3512Sdrh ** Usage:   sqlite_open filename
54d1bf3512Sdrh **
55d1bf3512Sdrh ** Returns:  The name of an open database.
56d1bf3512Sdrh */
57d1bf3512Sdrh static int sqlite_test_open(
58d1bf3512Sdrh   void *NotUsed,
59d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
60d1bf3512Sdrh   int argc,              /* Number of arguments */
61d1bf3512Sdrh   char **argv            /* Text of each argument */
62d1bf3512Sdrh ){
63d1bf3512Sdrh   sqlite *db;
64d1bf3512Sdrh   char *zErr = 0;
65d1bf3512Sdrh   char zBuf[100];
66d1bf3512Sdrh   if( argc!=2 ){
67d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
68d1bf3512Sdrh        " FILENAME\"", 0);
69d1bf3512Sdrh     return TCL_ERROR;
70d1bf3512Sdrh   }
71d1bf3512Sdrh   db = sqlite_open(argv[1], 0666, &zErr);
72d1bf3512Sdrh   if( db==0 ){
73d1bf3512Sdrh     Tcl_AppendResult(interp, zErr, 0);
74d1bf3512Sdrh     free(zErr);
75d1bf3512Sdrh     return TCL_ERROR;
76d1bf3512Sdrh   }
77*94e92032Sdrh   sprintf(zBuf,PTR_FMT, db);
78d1bf3512Sdrh   Tcl_AppendResult(interp, zBuf, 0);
79d1bf3512Sdrh   return TCL_OK;
80d1bf3512Sdrh }
81d1bf3512Sdrh 
82d1bf3512Sdrh /*
83d1bf3512Sdrh ** The callback routine for sqlite_exec_printf().
84d1bf3512Sdrh */
85d1bf3512Sdrh static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){
86d1bf3512Sdrh   Tcl_DString *str = (Tcl_DString*)pArg;
87d1bf3512Sdrh   int i;
88d1bf3512Sdrh 
89d1bf3512Sdrh   if( Tcl_DStringLength(str)==0 ){
90d1bf3512Sdrh     for(i=0; i<argc; i++){
91d1bf3512Sdrh       Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL");
92d1bf3512Sdrh     }
93d1bf3512Sdrh   }
94d1bf3512Sdrh   for(i=0; i<argc; i++){
95d1bf3512Sdrh     Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL");
96d1bf3512Sdrh   }
97d1bf3512Sdrh   return 0;
98d1bf3512Sdrh }
99d1bf3512Sdrh 
100d1bf3512Sdrh /*
101d1bf3512Sdrh ** Usage:  sqlite_exec_printf  DB  FORMAT  STRING
102d1bf3512Sdrh **
103d1bf3512Sdrh ** Invoke the sqlite_exec_printf() interface using the open database
104d1bf3512Sdrh ** DB.  The SQL is the string FORMAT.  The format string should contain
105d1bf3512Sdrh ** one %s or %q.  STRING is the value inserted into %s or %q.
106d1bf3512Sdrh */
107d1bf3512Sdrh static int test_exec_printf(
108d1bf3512Sdrh   void *NotUsed,
109d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
110d1bf3512Sdrh   int argc,              /* Number of arguments */
111d1bf3512Sdrh   char **argv            /* Text of each argument */
112d1bf3512Sdrh ){
113d1bf3512Sdrh   sqlite *db;
114d1bf3512Sdrh   Tcl_DString str;
115d1bf3512Sdrh   int rc;
116d1bf3512Sdrh   char *zErr = 0;
117d1bf3512Sdrh   char zBuf[30];
118d1bf3512Sdrh   if( argc!=4 ){
119d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
120d1bf3512Sdrh        " DB FORMAT STRING", 0);
121d1bf3512Sdrh     return TCL_ERROR;
122d1bf3512Sdrh   }
123b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
124d1bf3512Sdrh   Tcl_DStringInit(&str);
125d1bf3512Sdrh   rc = sqlite_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]);
126d1bf3512Sdrh   sprintf(zBuf, "%d", rc);
127d1bf3512Sdrh   Tcl_AppendElement(interp, zBuf);
128d1bf3512Sdrh   Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
129d1bf3512Sdrh   Tcl_DStringFree(&str);
130d1bf3512Sdrh   if( zErr ) free(zErr);
131d1bf3512Sdrh   return TCL_OK;
132d1bf3512Sdrh }
133d1bf3512Sdrh 
134d1bf3512Sdrh /*
135d1bf3512Sdrh ** Usage:  sqlite_get_table_printf  DB  FORMAT  STRING
136d1bf3512Sdrh **
137d1bf3512Sdrh ** Invoke the sqlite_get_table_printf() interface using the open database
138d1bf3512Sdrh ** DB.  The SQL is the string FORMAT.  The format string should contain
139d1bf3512Sdrh ** one %s or %q.  STRING is the value inserted into %s or %q.
140d1bf3512Sdrh */
141d1bf3512Sdrh static int test_get_table_printf(
142d1bf3512Sdrh   void *NotUsed,
143d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
144d1bf3512Sdrh   int argc,              /* Number of arguments */
145d1bf3512Sdrh   char **argv            /* Text of each argument */
146d1bf3512Sdrh ){
147d1bf3512Sdrh   sqlite *db;
148d1bf3512Sdrh   Tcl_DString str;
149d1bf3512Sdrh   int rc;
150d1bf3512Sdrh   char *zErr = 0;
151d1bf3512Sdrh   int nRow, nCol;
152d1bf3512Sdrh   char **aResult;
153d1bf3512Sdrh   int i;
154d1bf3512Sdrh   char zBuf[30];
155d1bf3512Sdrh   if( argc!=4 ){
156d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
157d1bf3512Sdrh        " DB FORMAT STRING", 0);
158d1bf3512Sdrh     return TCL_ERROR;
159d1bf3512Sdrh   }
160b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
161d1bf3512Sdrh   Tcl_DStringInit(&str);
162d1bf3512Sdrh   rc = sqlite_get_table_printf(db, argv[2], &aResult, &nRow, &nCol,
163d1bf3512Sdrh                &zErr, argv[3]);
164d1bf3512Sdrh   sprintf(zBuf, "%d", rc);
165d1bf3512Sdrh   Tcl_AppendElement(interp, zBuf);
166d1bf3512Sdrh   if( rc==SQLITE_OK ){
167d1bf3512Sdrh     sprintf(zBuf, "%d", nRow);
168d1bf3512Sdrh     Tcl_AppendElement(interp, zBuf);
169d1bf3512Sdrh     sprintf(zBuf, "%d", nCol);
170d1bf3512Sdrh     Tcl_AppendElement(interp, zBuf);
171d1bf3512Sdrh     for(i=0; i<(nRow+1)*nCol; i++){
172d1bf3512Sdrh       Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL");
173d1bf3512Sdrh     }
174d1bf3512Sdrh   }else{
175d1bf3512Sdrh     Tcl_AppendElement(interp, zErr);
176d1bf3512Sdrh   }
177d1bf3512Sdrh   sqlite_free_table(aResult);
178d1bf3512Sdrh   if( zErr ) free(zErr);
179d1bf3512Sdrh   return TCL_OK;
180d1bf3512Sdrh }
181d1bf3512Sdrh 
182af9ff33aSdrh 
183af9ff33aSdrh /*
184af9ff33aSdrh ** Usage:  sqlite_last_insert_rowid DB
185af9ff33aSdrh **
186af9ff33aSdrh ** Returns the integer ROWID of the most recent insert.
187af9ff33aSdrh */
188af9ff33aSdrh static int test_last_rowid(
189af9ff33aSdrh   void *NotUsed,
190af9ff33aSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
191af9ff33aSdrh   int argc,              /* Number of arguments */
192af9ff33aSdrh   char **argv            /* Text of each argument */
193af9ff33aSdrh ){
194af9ff33aSdrh   sqlite *db;
195af9ff33aSdrh   char zBuf[30];
196af9ff33aSdrh 
197af9ff33aSdrh   if( argc!=2 ){
198af9ff33aSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0);
199af9ff33aSdrh     return TCL_ERROR;
200af9ff33aSdrh   }
201b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
202af9ff33aSdrh   sprintf(zBuf, "%d", sqlite_last_insert_rowid(db));
203af9ff33aSdrh   Tcl_AppendResult(interp, zBuf, 0);
204af9ff33aSdrh   return SQLITE_OK;
205af9ff33aSdrh }
206af9ff33aSdrh 
207d1bf3512Sdrh /*
208d1bf3512Sdrh ** Usage:  sqlite_close DB
209d1bf3512Sdrh **
210d1bf3512Sdrh ** Closes the database opened by sqlite_open.
211d1bf3512Sdrh */
212d1bf3512Sdrh static int sqlite_test_close(
213d1bf3512Sdrh   void *NotUsed,
214d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
215d1bf3512Sdrh   int argc,              /* Number of arguments */
216d1bf3512Sdrh   char **argv            /* Text of each argument */
217d1bf3512Sdrh ){
218d1bf3512Sdrh   sqlite *db;
219d1bf3512Sdrh   if( argc!=2 ){
220d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
221d1bf3512Sdrh        " FILENAME\"", 0);
222d1bf3512Sdrh     return TCL_ERROR;
223d1bf3512Sdrh   }
224b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
225d1bf3512Sdrh   sqlite_close(db);
226d1bf3512Sdrh   return TCL_OK;
227d1bf3512Sdrh }
228d1bf3512Sdrh 
229d1bf3512Sdrh /*
230c22bd47dSdrh ** Implementation of the x_coalesce() function.
231c22bd47dSdrh ** Return the first argument non-NULL argument.
232c22bd47dSdrh */
233c22bd47dSdrh static void ifnullFunc(sqlite_func *context, int argc, const char **argv){
234c22bd47dSdrh   int i;
235c22bd47dSdrh   for(i=0; i<argc; i++){
236c22bd47dSdrh     if( argv[i] ){
237c22bd47dSdrh       sqlite_set_result_string(context, argv[i], -1);
238c22bd47dSdrh       break;
239c22bd47dSdrh     }
240c22bd47dSdrh   }
241c22bd47dSdrh }
242c22bd47dSdrh 
243c22bd47dSdrh /*
244c22bd47dSdrh ** Implementation of the x_sqlite_exec() function.  This function takes
245c22bd47dSdrh ** a single argument and attempts to execute that argument as SQL code.
2466cbe1f1bSdrh ** This is illegal and should set the SQLITE_MISUSE flag on the database.
247c22bd47dSdrh **
248c22bd47dSdrh ** This routine simulates the effect of having two threads attempt to
249c22bd47dSdrh ** use the same database at the same time.
250c22bd47dSdrh */
251c22bd47dSdrh static void sqliteExecFunc(sqlite_func *context, int argc, const char **argv){
252c22bd47dSdrh   sqlite_exec((sqlite*)sqlite_user_data(context), argv[0], 0, 0, 0);
253c22bd47dSdrh }
254c22bd47dSdrh 
255c22bd47dSdrh /*
256c22bd47dSdrh ** Usage:  sqlite_test_create_function DB
257c22bd47dSdrh **
258c22bd47dSdrh ** Call the sqlite_create_function API on the given database in order
259c22bd47dSdrh ** to create a function named "x_coalesce".  This function does the same thing
260c22bd47dSdrh ** as the "coalesce" function.  This function also registers an SQL function
261c22bd47dSdrh ** named "x_sqlite_exec" that invokes sqlite_exec().  Invoking sqlite_exec()
262c22bd47dSdrh ** in this way is illegal recursion and should raise an SQLITE_MISUSE error.
263c22bd47dSdrh ** The effect is similar to trying to use the same database connection from
264c22bd47dSdrh ** two threads at the same time.
265c22bd47dSdrh **
266c22bd47dSdrh ** The original motivation for this routine was to be able to call the
267c22bd47dSdrh ** sqlite_create_function function while a query is in progress in order
268c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
269c22bd47dSdrh */
270c2eef3b3Sdrh static int test_create_function(
271c22bd47dSdrh   void *NotUsed,
272c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
273c22bd47dSdrh   int argc,              /* Number of arguments */
274c22bd47dSdrh   char **argv            /* Text of each argument */
275c22bd47dSdrh ){
276c22bd47dSdrh   sqlite *db;
277c22bd47dSdrh   extern void Md5_Register(sqlite*);
278c22bd47dSdrh   if( argc!=2 ){
279c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
280c22bd47dSdrh        " FILENAME\"", 0);
281c22bd47dSdrh     return TCL_ERROR;
282c22bd47dSdrh   }
283b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
284c22bd47dSdrh   sqlite_create_function(db, "x_coalesce", -1, ifnullFunc, 0);
285c22bd47dSdrh   sqlite_create_function(db, "x_sqlite_exec", 1, sqliteExecFunc, db);
286c22bd47dSdrh   return TCL_OK;
287c22bd47dSdrh }
288c22bd47dSdrh 
289c22bd47dSdrh /*
290c22bd47dSdrh ** Routines to implement the x_count() aggregate function.
291c22bd47dSdrh */
292c22bd47dSdrh typedef struct CountCtx CountCtx;
293c22bd47dSdrh struct CountCtx {
294c22bd47dSdrh   int n;
295c22bd47dSdrh };
296c22bd47dSdrh static void countStep(sqlite_func *context, int argc, const char **argv){
297c22bd47dSdrh   CountCtx *p;
298c22bd47dSdrh   p = sqlite_aggregate_context(context, sizeof(*p));
299c22bd47dSdrh   if( (argc==0 || argv[0]) && p ){
300c22bd47dSdrh     p->n++;
301c22bd47dSdrh   }
302c22bd47dSdrh }
303c22bd47dSdrh static void countFinalize(sqlite_func *context){
304c22bd47dSdrh   CountCtx *p;
305c22bd47dSdrh   p = sqlite_aggregate_context(context, sizeof(*p));
306c22bd47dSdrh   sqlite_set_result_int(context, p ? p->n : 0);
307c22bd47dSdrh }
308c22bd47dSdrh 
309c22bd47dSdrh /*
310c22bd47dSdrh ** Usage:  sqlite_test_create_aggregate DB
311c22bd47dSdrh **
312c22bd47dSdrh ** Call the sqlite_create_function API on the given database in order
313c22bd47dSdrh ** to create a function named "x_count".  This function does the same thing
314c22bd47dSdrh ** as the "md5sum" function.
315c22bd47dSdrh **
316c22bd47dSdrh ** The original motivation for this routine was to be able to call the
317c22bd47dSdrh ** sqlite_create_aggregate function while a query is in progress in order
318c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
319c22bd47dSdrh */
320c2eef3b3Sdrh static int test_create_aggregate(
321c22bd47dSdrh   void *NotUsed,
322c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
323c22bd47dSdrh   int argc,              /* Number of arguments */
324c22bd47dSdrh   char **argv            /* Text of each argument */
325c22bd47dSdrh ){
326c22bd47dSdrh   sqlite *db;
327c22bd47dSdrh   if( argc!=2 ){
328c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
329c22bd47dSdrh        " FILENAME\"", 0);
330c22bd47dSdrh     return TCL_ERROR;
331c22bd47dSdrh   }
332b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
333c22bd47dSdrh   sqlite_create_aggregate(db, "x_count", 0, countStep, countFinalize, 0);
334c22bd47dSdrh   sqlite_create_aggregate(db, "x_count", 1, countStep, countFinalize, 0);
335c22bd47dSdrh   return TCL_OK;
336c22bd47dSdrh }
337c22bd47dSdrh 
338c22bd47dSdrh 
339c22bd47dSdrh 
340c22bd47dSdrh /*
341d1bf3512Sdrh ** Usage:  sqlite_mprintf_int FORMAT INTEGER INTEGER INTEGER
342d1bf3512Sdrh **
343d1bf3512Sdrh ** Call mprintf with three integer arguments
344d1bf3512Sdrh */
345d1bf3512Sdrh static int sqlite_mprintf_int(
346d1bf3512Sdrh   void *NotUsed,
347d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
348d1bf3512Sdrh   int argc,              /* Number of arguments */
349d1bf3512Sdrh   char **argv            /* Text of each argument */
350d1bf3512Sdrh ){
351d1bf3512Sdrh   int a[3], i;
352d1bf3512Sdrh   char *z;
353d1bf3512Sdrh   if( argc!=5 ){
354d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
355d1bf3512Sdrh        " FORMAT INT INT INT\"", 0);
356d1bf3512Sdrh     return TCL_ERROR;
357d1bf3512Sdrh   }
358d1bf3512Sdrh   for(i=2; i<5; i++){
359d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
360d1bf3512Sdrh   }
361d1bf3512Sdrh   z = sqlite_mprintf(argv[1], a[0], a[1], a[2]);
362d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
363fa173a76Sdrh   sqlite_freemem(z);
364d1bf3512Sdrh   return TCL_OK;
365d1bf3512Sdrh }
366d1bf3512Sdrh 
367d1bf3512Sdrh /*
368d1bf3512Sdrh ** Usage:  sqlite_mprintf_str FORMAT INTEGER INTEGER STRING
369d1bf3512Sdrh **
370d1bf3512Sdrh ** Call mprintf with two integer arguments and one string argument
371d1bf3512Sdrh */
372d1bf3512Sdrh static int sqlite_mprintf_str(
373d1bf3512Sdrh   void *NotUsed,
374d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
375d1bf3512Sdrh   int argc,              /* Number of arguments */
376d1bf3512Sdrh   char **argv            /* Text of each argument */
377d1bf3512Sdrh ){
378d1bf3512Sdrh   int a[3], i;
379d1bf3512Sdrh   char *z;
380f220b24fSchw   if( argc<4 || argc>5 ){
381d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
382f220b24fSchw        " FORMAT INT INT ?STRING?\"", 0);
383d1bf3512Sdrh     return TCL_ERROR;
384d1bf3512Sdrh   }
385d1bf3512Sdrh   for(i=2; i<4; i++){
386d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
387d1bf3512Sdrh   }
388f220b24fSchw   z = sqlite_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL);
389d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
390fa173a76Sdrh   sqlite_freemem(z);
391d1bf3512Sdrh   return TCL_OK;
392d1bf3512Sdrh }
393d1bf3512Sdrh 
394d1bf3512Sdrh /*
395d1bf3512Sdrh ** Usage:  sqlite_mprintf_str FORMAT INTEGER INTEGER DOUBLE
396d1bf3512Sdrh **
397d1bf3512Sdrh ** Call mprintf with two integer arguments and one double argument
398d1bf3512Sdrh */
399d1bf3512Sdrh static int sqlite_mprintf_double(
400d1bf3512Sdrh   void *NotUsed,
401d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
402d1bf3512Sdrh   int argc,              /* Number of arguments */
403d1bf3512Sdrh   char **argv            /* Text of each argument */
404d1bf3512Sdrh ){
405d1bf3512Sdrh   int a[3], i;
406d1bf3512Sdrh   double r;
407d1bf3512Sdrh   char *z;
408d1bf3512Sdrh   if( argc!=5 ){
409d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
410d1bf3512Sdrh        " FORMAT INT INT STRING\"", 0);
411d1bf3512Sdrh     return TCL_ERROR;
412d1bf3512Sdrh   }
413d1bf3512Sdrh   for(i=2; i<4; i++){
414d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
415d1bf3512Sdrh   }
416d1bf3512Sdrh   if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR;
417d1bf3512Sdrh   z = sqlite_mprintf(argv[1], a[0], a[1], r);
418d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
419fa173a76Sdrh   sqlite_freemem(z);
420d1bf3512Sdrh   return TCL_OK;
421d1bf3512Sdrh }
422d1bf3512Sdrh 
423d1bf3512Sdrh /*
424daffd0e5Sdrh ** Usage: sqlite_malloc_fail N
425daffd0e5Sdrh **
426afa4a020Sdrh ** Rig sqliteMalloc() to fail on the N-th call.  Turn off this mechanism
427daffd0e5Sdrh ** and reset the sqlite_malloc_failed variable is N==0.
428daffd0e5Sdrh */
429daffd0e5Sdrh #ifdef MEMORY_DEBUG
430daffd0e5Sdrh static int sqlite_malloc_fail(
431daffd0e5Sdrh   void *NotUsed,
432daffd0e5Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
433daffd0e5Sdrh   int argc,              /* Number of arguments */
434daffd0e5Sdrh   char **argv            /* Text of each argument */
435daffd0e5Sdrh ){
436daffd0e5Sdrh   int n;
437daffd0e5Sdrh   if( argc!=2 ){
438daffd0e5Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0);
439daffd0e5Sdrh     return TCL_ERROR;
440daffd0e5Sdrh   }
441daffd0e5Sdrh   if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
442daffd0e5Sdrh   sqlite_iMallocFail = n;
443daffd0e5Sdrh   sqlite_malloc_failed = 0;
444daffd0e5Sdrh   return TCL_OK;
445daffd0e5Sdrh }
446daffd0e5Sdrh #endif
447daffd0e5Sdrh 
448daffd0e5Sdrh /*
449daffd0e5Sdrh ** Usage: sqlite_malloc_stat
450daffd0e5Sdrh **
451daffd0e5Sdrh ** Return the number of prior calls to sqliteMalloc() and sqliteFree().
452daffd0e5Sdrh */
453daffd0e5Sdrh #ifdef MEMORY_DEBUG
454daffd0e5Sdrh static int sqlite_malloc_stat(
455daffd0e5Sdrh   void *NotUsed,
456daffd0e5Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
457daffd0e5Sdrh   int argc,              /* Number of arguments */
458daffd0e5Sdrh   char **argv            /* Text of each argument */
459daffd0e5Sdrh ){
460daffd0e5Sdrh   char zBuf[200];
461daffd0e5Sdrh   sprintf(zBuf, "%d %d %d", sqlite_nMalloc, sqlite_nFree, sqlite_iMallocFail);
462daffd0e5Sdrh   Tcl_AppendResult(interp, zBuf, 0);
463daffd0e5Sdrh   return TCL_OK;
464daffd0e5Sdrh }
465daffd0e5Sdrh #endif
466daffd0e5Sdrh 
467daffd0e5Sdrh /*
46828b4e489Sdrh ** Usage:  sqlite_abort
46928b4e489Sdrh **
47028b4e489Sdrh ** Shutdown the process immediately.  This is not a clean shutdown.
47128b4e489Sdrh ** This command is used to test the recoverability of a database in
47228b4e489Sdrh ** the event of a program crash.
47328b4e489Sdrh */
47428b4e489Sdrh static int sqlite_abort(
47528b4e489Sdrh   void *NotUsed,
47628b4e489Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
47728b4e489Sdrh   int argc,              /* Number of arguments */
47828b4e489Sdrh   char **argv            /* Text of each argument */
47928b4e489Sdrh ){
48028b4e489Sdrh   assert( interp==0 );   /* This will always fail */
48128b4e489Sdrh   return TCL_OK;
48228b4e489Sdrh }
48328b4e489Sdrh 
48428b4e489Sdrh /*
4856cbe1f1bSdrh ** The following routine is a user-defined SQL function whose purpose
4866cbe1f1bSdrh ** is to test the sqlite_set_result() API.
4876cbe1f1bSdrh */
4886cbe1f1bSdrh static void testFunc(sqlite_func *context, int argc, const char **argv){
4896cbe1f1bSdrh   while( argc>=2 ){
4906cbe1f1bSdrh     if( argv[0]==0 ){
4916cbe1f1bSdrh       sqlite_set_result_error(context, "first argument to test function "
4926cbe1f1bSdrh          "may not be NULL", -1);
4936cbe1f1bSdrh     }else if( sqliteStrICmp(argv[0],"string")==0 ){
4946cbe1f1bSdrh       sqlite_set_result_string(context, argv[1], -1);
4956cbe1f1bSdrh     }else if( argv[1]==0 ){
4966cbe1f1bSdrh       sqlite_set_result_error(context, "2nd argument may not be NULL if the "
4976cbe1f1bSdrh          "first argument is not \"string\"", -1);
4986cbe1f1bSdrh     }else if( sqliteStrICmp(argv[0],"int")==0 ){
4996cbe1f1bSdrh       sqlite_set_result_int(context, atoi(argv[1]));
5006cbe1f1bSdrh     }else if( sqliteStrICmp(argv[0],"double")==0 ){
5016cbe1f1bSdrh       sqlite_set_result_double(context, atof(argv[1]));
5026cbe1f1bSdrh     }else{
5036cbe1f1bSdrh       sqlite_set_result_error(context,"first argument should be one of: "
5046cbe1f1bSdrh           "string int double", -1);
5056cbe1f1bSdrh     }
5066cbe1f1bSdrh     argc -= 2;
5076cbe1f1bSdrh     argv += 2;
5086cbe1f1bSdrh   }
5096cbe1f1bSdrh }
5106cbe1f1bSdrh 
5116cbe1f1bSdrh /*
5126cbe1f1bSdrh ** Usage:   sqlite_register_test_function  DB  NAME
5136cbe1f1bSdrh **
5146cbe1f1bSdrh ** Register the test SQL function on the database DB under the name NAME.
5156cbe1f1bSdrh */
516c2eef3b3Sdrh static int test_register_func(
5176cbe1f1bSdrh   void *NotUsed,
5186cbe1f1bSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
5196cbe1f1bSdrh   int argc,              /* Number of arguments */
5206cbe1f1bSdrh   char **argv            /* Text of each argument */
5216cbe1f1bSdrh ){
5226cbe1f1bSdrh   sqlite *db;
5236cbe1f1bSdrh   int rc;
5246cbe1f1bSdrh   if( argc!=3 ){
5256cbe1f1bSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
5266cbe1f1bSdrh        " DB FUNCTION-NAME", 0);
5276cbe1f1bSdrh     return TCL_ERROR;
5286cbe1f1bSdrh   }
529b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
5306cbe1f1bSdrh   rc = sqlite_create_function(db, argv[2], -1, testFunc, 0);
5316cbe1f1bSdrh   if( rc!=0 ){
5326cbe1f1bSdrh     Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
5336cbe1f1bSdrh     return TCL_ERROR;
5346cbe1f1bSdrh   }
5356cbe1f1bSdrh   return TCL_OK;
5366cbe1f1bSdrh }
5376cbe1f1bSdrh 
5386cbe1f1bSdrh /*
5395a38705eSdrh ** This SQLite callback records the datatype of all columns.
5405a38705eSdrh **
5415a38705eSdrh ** The pArg argument is really a pointer to a TCL interpreter.  The
5425a38705eSdrh ** column names are inserted as the result of this interpreter.
5435a38705eSdrh **
5445a38705eSdrh ** This routine returns non-zero which causes the query to abort.
5455a38705eSdrh */
5465a38705eSdrh static int rememberDataTypes(void *pArg, int nCol, char **argv, char **colv){
5475a38705eSdrh   int i;
5485a38705eSdrh   Tcl_Interp *interp = (Tcl_Interp*)pArg;
5495a38705eSdrh   Tcl_Obj *pList, *pElem;
5505a38705eSdrh   if( colv[nCol+1]==0 ){
5515a38705eSdrh     return 1;
5525a38705eSdrh   }
5535a38705eSdrh   pList = Tcl_NewObj();
5545a38705eSdrh   for(i=0; i<nCol; i++){
5555a38705eSdrh     pElem = Tcl_NewStringObj(colv[i+nCol] ? colv[i+nCol] : "NULL", -1);
5565a38705eSdrh     Tcl_ListObjAppendElement(interp, pList, pElem);
5575a38705eSdrh   }
5585a38705eSdrh   Tcl_SetObjResult(interp, pList);
5595a38705eSdrh   return 1;
5605a38705eSdrh }
5615a38705eSdrh 
5625a38705eSdrh /*
5635a38705eSdrh ** Invoke an SQL statement but ignore all the data in the result.  Instead,
5645a38705eSdrh ** return a list that consists of the datatypes of the various columns.
5655a38705eSdrh **
5665a38705eSdrh ** This only works if "PRAGMA show_datatypes=on" has been executed against
5675a38705eSdrh ** the database connection.
5685a38705eSdrh */
5695a38705eSdrh static int sqlite_datatypes(
5705a38705eSdrh   void *NotUsed,
5715a38705eSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
5725a38705eSdrh   int argc,              /* Number of arguments */
5735a38705eSdrh   char **argv            /* Text of each argument */
5745a38705eSdrh ){
5755a38705eSdrh   sqlite *db;
5765a38705eSdrh   int rc;
5775a38705eSdrh   if( argc!=3 ){
5785a38705eSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
5795a38705eSdrh        " DB SQL", 0);
5805a38705eSdrh     return TCL_ERROR;
5815a38705eSdrh   }
582b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
5835a38705eSdrh   rc = sqlite_exec(db, argv[2], rememberDataTypes, interp, 0);
5845a38705eSdrh   if( rc!=0 && rc!=SQLITE_ABORT ){
5855a38705eSdrh     Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
5865a38705eSdrh     return TCL_ERROR;
5875a38705eSdrh   }
5885a38705eSdrh   return TCL_OK;
5895a38705eSdrh }
5905a38705eSdrh 
591ed6c8671Sdrh #ifndef SQLITE_OMIT_AUTHORIZATION
592ed6c8671Sdrh /*
593ed6c8671Sdrh ** Information used by the authentication function.
594ed6c8671Sdrh */
595ed6c8671Sdrh typedef struct AuthInfo AuthInfo;
596ed6c8671Sdrh struct AuthInfo {
597ed6c8671Sdrh   Tcl_Interp *interp;    /* Interpreter to use */
598ed6c8671Sdrh   int nCmd;              /* Number of characters in zCmd[] */
599ed6c8671Sdrh   char zCmd[500];        /* Command to invoke */
600ed6c8671Sdrh };
601ed6c8671Sdrh 
602ed6c8671Sdrh /*
603ed6c8671Sdrh ** We create a single static authenticator.  This won't work in a
604ed6c8671Sdrh ** multi-threaded environment, but the test fixture is not multithreaded.
605ed6c8671Sdrh ** And be making it static, we don't have to worry about deallocating
606ed6c8671Sdrh ** after a test in order to void memory leaks.
607ed6c8671Sdrh */
608ed6c8671Sdrh static AuthInfo authInfo;
609ed6c8671Sdrh 
610ed6c8671Sdrh /*
611ed6c8671Sdrh ** This is the authentication function.  It appends the authentication
612ed6c8671Sdrh ** type code and the two arguments to zCmd[] then invokes the result
613ed6c8671Sdrh ** on the interpreter.  The reply is examined to determine if the
614ed6c8671Sdrh ** authentication fails or succeeds.
615ed6c8671Sdrh */
616ed6c8671Sdrh static int auth_callback(
617ed6c8671Sdrh   void *NotUsed,
618ed6c8671Sdrh   int code,
619ed6c8671Sdrh   const char *zArg1,
620ed6c8671Sdrh   const char *zArg2
621ed6c8671Sdrh ){
622ed6c8671Sdrh   char *zCode;
623ed6c8671Sdrh   Tcl_DString str;
624ed6c8671Sdrh   int rc;
625ed6c8671Sdrh   const char *zReply;
626ed6c8671Sdrh   switch( code ){
627e5f9c644Sdrh     case SQLITE_COPY              : zCode="SQLITE_COPY"; break;
628e5f9c644Sdrh     case SQLITE_CREATE_INDEX      : zCode="SQLITE_CREATE_INDEX"; break;
629e5f9c644Sdrh     case SQLITE_CREATE_TABLE      : zCode="SQLITE_CREATE_TABLE"; break;
630e5f9c644Sdrh     case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break;
631e5f9c644Sdrh     case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break;
632e5f9c644Sdrh     case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break;
633e5f9c644Sdrh     case SQLITE_CREATE_TEMP_VIEW  : zCode="SQLITE_CREATE_TEMP_VIEW"; break;
634e5f9c644Sdrh     case SQLITE_CREATE_TRIGGER    : zCode="SQLITE_CREATE_TRIGGER"; break;
635e5f9c644Sdrh     case SQLITE_CREATE_VIEW       : zCode="SQLITE_CREATE_VIEW"; break;
636e5f9c644Sdrh     case SQLITE_DELETE            : zCode="SQLITE_DELETE"; break;
637e5f9c644Sdrh     case SQLITE_DROP_INDEX        : zCode="SQLITE_DROP_INDEX"; break;
638e5f9c644Sdrh     case SQLITE_DROP_TABLE        : zCode="SQLITE_DROP_TABLE"; break;
639e5f9c644Sdrh     case SQLITE_DROP_TEMP_INDEX   : zCode="SQLITE_DROP_TEMP_INDEX"; break;
640e5f9c644Sdrh     case SQLITE_DROP_TEMP_TABLE   : zCode="SQLITE_DROP_TEMP_TABLE"; break;
641e5f9c644Sdrh     case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break;
642e5f9c644Sdrh     case SQLITE_DROP_TEMP_VIEW    : zCode="SQLITE_DROP_TEMP_VIEW"; break;
643e5f9c644Sdrh     case SQLITE_DROP_TRIGGER      : zCode="SQLITE_DROP_TRIGGER"; break;
644e5f9c644Sdrh     case SQLITE_DROP_VIEW         : zCode="SQLITE_DROP_VIEW"; break;
645e5f9c644Sdrh     case SQLITE_INSERT            : zCode="SQLITE_INSERT"; break;
646e5f9c644Sdrh     case SQLITE_PRAGMA            : zCode="SQLITE_PRAGMA"; break;
647e5f9c644Sdrh     case SQLITE_READ              : zCode="SQLITE_READ"; break;
648e5f9c644Sdrh     case SQLITE_SELECT            : zCode="SQLITE_SELECT"; break;
649e5f9c644Sdrh     case SQLITE_TRANSACTION       : zCode="SQLITE_TRANSACTION"; break;
650e5f9c644Sdrh     case SQLITE_UPDATE            : zCode="SQLITE_UPDATE"; break;
651e5f9c644Sdrh     default                       : zCode="????"; break;
652ed6c8671Sdrh   }
653ed6c8671Sdrh   Tcl_DStringInit(&str);
654ed6c8671Sdrh   Tcl_DStringAppend(&str, authInfo.zCmd, -1);
655ed6c8671Sdrh   Tcl_DStringAppendElement(&str, zCode);
656e5f9c644Sdrh   Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : "");
657ed6c8671Sdrh   Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : "");
658ed6c8671Sdrh   rc = Tcl_GlobalEval(authInfo.interp, Tcl_DStringValue(&str));
659ed6c8671Sdrh   Tcl_DStringFree(&str);
660ed6c8671Sdrh   zReply = Tcl_GetStringResult(authInfo.interp);
661ed6c8671Sdrh   if( strcmp(zReply,"SQLITE_OK")==0 ){
662ed6c8671Sdrh     rc = SQLITE_OK;
663ed6c8671Sdrh   }else if( strcmp(zReply,"SQLITE_DENY")==0 ){
664ed6c8671Sdrh     rc = SQLITE_DENY;
665ed6c8671Sdrh   }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){
666ed6c8671Sdrh     rc = SQLITE_IGNORE;
667ed6c8671Sdrh   }else{
668ed6c8671Sdrh     rc = 999;
669ed6c8671Sdrh   }
670ed6c8671Sdrh   return rc;
671ed6c8671Sdrh }
672ed6c8671Sdrh 
673ed6c8671Sdrh /*
674ed6c8671Sdrh ** This routine creates a new authenticator.  It fills in the zCmd[]
675ed6c8671Sdrh ** field of the authentication function state variable and then registers
676ed6c8671Sdrh ** the authentication function with the SQLite library.
677ed6c8671Sdrh */
678ed6c8671Sdrh static int test_set_authorizer(
679ed6c8671Sdrh   void *NotUsed,
680ed6c8671Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
681ed6c8671Sdrh   int argc,              /* Number of arguments */
682ed6c8671Sdrh   char **argv            /* Text of each argument */
683ed6c8671Sdrh ){
684ed6c8671Sdrh   sqlite *db;
685ed6c8671Sdrh   char *zCmd;
686ed6c8671Sdrh   if( argc!=3 ){
687ed6c8671Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
688ed6c8671Sdrh          " DB CALLBACK\"", 0);
689ed6c8671Sdrh     return TCL_ERROR;
690ed6c8671Sdrh   }
691b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
692ed6c8671Sdrh   zCmd = argv[2];
693ed6c8671Sdrh   if( zCmd[0]==0 ){
694ed6c8671Sdrh     sqlite_set_authorizer(db, 0, 0);
695ed6c8671Sdrh     return TCL_OK;
696ed6c8671Sdrh   }
697ed6c8671Sdrh   if( strlen(zCmd)>sizeof(authInfo.zCmd) ){
698ed6c8671Sdrh     Tcl_AppendResult(interp, "command too big", 0);
699ed6c8671Sdrh     return TCL_ERROR;
700ed6c8671Sdrh   }
701ed6c8671Sdrh   authInfo.interp = interp;
702ed6c8671Sdrh   authInfo.nCmd = strlen(zCmd);
703ed6c8671Sdrh   strcpy(authInfo.zCmd, zCmd);
704ed6c8671Sdrh   sqlite_set_authorizer(db, auth_callback, 0);
705ed6c8671Sdrh   return TCL_OK;
706ed6c8671Sdrh }
707ed6c8671Sdrh #endif /* SQLITE_OMIT_AUTHORIZATION */
7085a38705eSdrh 
709b86ccfb2Sdrh 
710b86ccfb2Sdrh /*
711b86ccfb2Sdrh ** Usage:  sqlite_compile  DB  SQL  TAILVAR
712b86ccfb2Sdrh **
713b86ccfb2Sdrh ** Attempt to compile an SQL statement.  Return a pointer to the virtual
714b86ccfb2Sdrh ** machine used to execute that statement.  Unprocessed SQL is written
715b86ccfb2Sdrh ** into TAILVAR.
716b86ccfb2Sdrh */
717b86ccfb2Sdrh static int test_compile(
718b86ccfb2Sdrh   void *NotUsed,
719b86ccfb2Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
720b86ccfb2Sdrh   int argc,              /* Number of arguments */
721b86ccfb2Sdrh   char **argv            /* Text of each argument */
722b86ccfb2Sdrh ){
723b86ccfb2Sdrh   sqlite *db;
724b86ccfb2Sdrh   sqlite_vm *vm;
725b86ccfb2Sdrh   int rc;
726b86ccfb2Sdrh   char *zErr = 0;
727b86ccfb2Sdrh   const char *zTail;
728b86ccfb2Sdrh   char zBuf[50];
729b86ccfb2Sdrh   if( argc!=4 ){
730b86ccfb2Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
731b86ccfb2Sdrh        " DB SQL TAILVAR", 0);
732b86ccfb2Sdrh     return TCL_ERROR;
733b86ccfb2Sdrh   }
734b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
735b86ccfb2Sdrh   rc = sqlite_compile(db, argv[2], &zTail, &vm, &zErr);
736483750baSdrh   Tcl_SetVar(interp, argv[3], zTail, 0);
737b86ccfb2Sdrh   if( rc ){
738b86ccfb2Sdrh     assert( vm==0 );
739b86ccfb2Sdrh     sprintf(zBuf, "(%d) ", rc);
740b86ccfb2Sdrh     Tcl_AppendResult(interp, zBuf, zErr, 0);
741b86ccfb2Sdrh     sqlite_freemem(zErr);
742b86ccfb2Sdrh     return TCL_ERROR;
743b86ccfb2Sdrh   }
744326dce74Sdrh   if( vm ){
745*94e92032Sdrh     sprintf(zBuf, PTR_FMT, vm);
746b86ccfb2Sdrh     Tcl_AppendResult(interp, zBuf, 0);
747326dce74Sdrh   }
748b86ccfb2Sdrh   return TCL_OK;
749b86ccfb2Sdrh }
750b86ccfb2Sdrh 
751b86ccfb2Sdrh /*
752b86ccfb2Sdrh ** Usage:  sqlite_step  VM  NVAR  VALUEVAR  COLNAMEVAR
753b86ccfb2Sdrh **
754b86ccfb2Sdrh ** Step a virtual machine.  Return a the result code as a string.
755b86ccfb2Sdrh ** Column results are written into three variables.
756b86ccfb2Sdrh */
757b86ccfb2Sdrh static int test_step(
758b86ccfb2Sdrh   void *NotUsed,
759b86ccfb2Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
760b86ccfb2Sdrh   int argc,              /* Number of arguments */
761b86ccfb2Sdrh   char **argv            /* Text of each argument */
762b86ccfb2Sdrh ){
763b86ccfb2Sdrh   sqlite_vm *vm;
764b86ccfb2Sdrh   int rc, i;
7653a84069dSdrh   const char **azValue = 0;
7663a84069dSdrh   const char **azColName = 0;
7673a84069dSdrh   int N = 0;
768b86ccfb2Sdrh   char *zRc;
769b86ccfb2Sdrh   char zBuf[50];
770b86ccfb2Sdrh   if( argc!=5 ){
771b86ccfb2Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
772b86ccfb2Sdrh        " VM NVAR VALUEVAR COLNAMEVAR", 0);
773b86ccfb2Sdrh     return TCL_ERROR;
774b86ccfb2Sdrh   }
775b86ccfb2Sdrh   if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
776b86ccfb2Sdrh   rc = sqlite_step(vm, &N, &azValue, &azColName);
777b86ccfb2Sdrh   sprintf(zBuf, "%d", N);
778b86ccfb2Sdrh   Tcl_SetVar(interp, argv[2], zBuf, 0);
779b86ccfb2Sdrh   Tcl_SetVar(interp, argv[3], "", 0);
7803a84069dSdrh   if( azValue ){
781b86ccfb2Sdrh     for(i=0; i<N; i++){
782b86ccfb2Sdrh       Tcl_SetVar(interp, argv[3], azValue[i] ? azValue[i] : "",
783b86ccfb2Sdrh           TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
784b86ccfb2Sdrh     }
785b86ccfb2Sdrh   }
786b86ccfb2Sdrh   Tcl_SetVar(interp, argv[4], "", 0);
7873a84069dSdrh   if( azColName ){
788b86ccfb2Sdrh     for(i=0; i<N*2; i++){
789326dce74Sdrh       Tcl_SetVar(interp, argv[4], azColName[i] ? azColName[i] : "",
790b86ccfb2Sdrh           TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
791b86ccfb2Sdrh     }
792b86ccfb2Sdrh   }
793b86ccfb2Sdrh   switch( rc ){
794b86ccfb2Sdrh     case SQLITE_DONE:   zRc = "SQLITE_DONE";    break;
795326dce74Sdrh     case SQLITE_BUSY:   zRc = "SQLITE_BUSY";    break;
796326dce74Sdrh     case SQLITE_ROW:    zRc = "SQLITE_ROW";     break;
797326dce74Sdrh     case SQLITE_ERROR:  zRc = "SQLITE_ERROR";   break;
798b86ccfb2Sdrh     case SQLITE_MISUSE: zRc = "SQLITE_MISUSE";  break;
799b86ccfb2Sdrh     default:            zRc = "unknown";        break;
800b86ccfb2Sdrh   }
801b86ccfb2Sdrh   Tcl_AppendResult(interp, zRc, 0);
802b86ccfb2Sdrh   return TCL_OK;
803b86ccfb2Sdrh }
804b86ccfb2Sdrh 
805b86ccfb2Sdrh /*
806b86ccfb2Sdrh ** Usage:  sqlite_finalize  VM
807b86ccfb2Sdrh **
808b86ccfb2Sdrh ** Shutdown a virtual machine.
809b86ccfb2Sdrh */
810b86ccfb2Sdrh static int test_finalize(
811b86ccfb2Sdrh   void *NotUsed,
812b86ccfb2Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
813b86ccfb2Sdrh   int argc,              /* Number of arguments */
814b86ccfb2Sdrh   char **argv            /* Text of each argument */
815b86ccfb2Sdrh ){
816b86ccfb2Sdrh   sqlite_vm *vm;
817b86ccfb2Sdrh   int rc;
818b86ccfb2Sdrh   char *zErrMsg = 0;
819b86ccfb2Sdrh   if( argc!=2 ){
820b86ccfb2Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
821326dce74Sdrh        " VM\"", 0);
822b86ccfb2Sdrh     return TCL_ERROR;
823b86ccfb2Sdrh   }
824b86ccfb2Sdrh   if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
825b86ccfb2Sdrh   rc = sqlite_finalize(vm, &zErrMsg);
826b86ccfb2Sdrh   if( rc ){
827b86ccfb2Sdrh     char zBuf[50];
828b86ccfb2Sdrh     sprintf(zBuf, "(%d) ", rc);
829b86ccfb2Sdrh     Tcl_AppendResult(interp, zBuf, zErrMsg, 0);
830b86ccfb2Sdrh     sqlite_freemem(zErrMsg);
831b86ccfb2Sdrh     return TCL_ERROR;
832b86ccfb2Sdrh   }
833b86ccfb2Sdrh   return TCL_OK;
834b86ccfb2Sdrh }
835b86ccfb2Sdrh 
8365a38705eSdrh /*
83799ee3600Sdrh ** Usage:    breakpoint
83899ee3600Sdrh **
83999ee3600Sdrh ** This routine exists for one purpose - to provide a place to put a
84099ee3600Sdrh ** breakpoint with GDB that can be triggered using TCL code.  The use
84199ee3600Sdrh ** for this is when a particular test fails on (say) the 1485th iteration.
84299ee3600Sdrh ** In the TCL test script, we can add code like this:
84399ee3600Sdrh **
84499ee3600Sdrh **     if {$i==1485} breakpoint
84599ee3600Sdrh **
84699ee3600Sdrh ** Then run testfixture in the debugger and wait for the breakpoint to
84799ee3600Sdrh ** fire.  Then additional breakpoints can be set to trace down the bug.
84899ee3600Sdrh */
84999ee3600Sdrh static int test_breakpoint(
85099ee3600Sdrh   void *NotUsed,
85199ee3600Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
85299ee3600Sdrh   int argc,              /* Number of arguments */
85399ee3600Sdrh   char **argv            /* Text of each argument */
85499ee3600Sdrh ){
85599ee3600Sdrh   return TCL_OK;         /* Do nothing */
85699ee3600Sdrh }
85799ee3600Sdrh 
85899ee3600Sdrh /*
859d1bf3512Sdrh ** Register commands with the TCL interpreter.
860d1bf3512Sdrh */
861d1bf3512Sdrh int Sqlitetest1_Init(Tcl_Interp *interp){
862487ab3caSdrh   extern int sqlite_search_count;
863*94e92032Sdrh   extern int sqlite_open_file_count;
864c2eef3b3Sdrh   static struct {
865c2eef3b3Sdrh      char *zName;
866c2eef3b3Sdrh      Tcl_CmdProc *xProc;
867c2eef3b3Sdrh   } aCmd[] = {
868c2eef3b3Sdrh      { "sqlite_mprintf_int",             (Tcl_CmdProc*)sqlite_mprintf_int    },
869c2eef3b3Sdrh      { "sqlite_mprintf_str",             (Tcl_CmdProc*)sqlite_mprintf_str    },
870c2eef3b3Sdrh      { "sqlite_mprintf_double",          (Tcl_CmdProc*)sqlite_mprintf_double },
871c2eef3b3Sdrh      { "sqlite_open",                    (Tcl_CmdProc*)sqlite_test_open      },
872c2eef3b3Sdrh      { "sqlite_last_insert_rowid",       (Tcl_CmdProc*)test_last_rowid       },
873c2eef3b3Sdrh      { "sqlite_exec_printf",             (Tcl_CmdProc*)test_exec_printf      },
874c2eef3b3Sdrh      { "sqlite_get_table_printf",        (Tcl_CmdProc*)test_get_table_printf },
875c2eef3b3Sdrh      { "sqlite_close",                   (Tcl_CmdProc*)sqlite_test_close     },
876c2eef3b3Sdrh      { "sqlite_create_function",         (Tcl_CmdProc*)test_create_function  },
877c2eef3b3Sdrh      { "sqlite_create_aggregate",        (Tcl_CmdProc*)test_create_aggregate },
878c2eef3b3Sdrh      { "sqlite_register_test_function",  (Tcl_CmdProc*)test_register_func    },
879c2eef3b3Sdrh      { "sqlite_abort",                   (Tcl_CmdProc*)sqlite_abort          },
8805a38705eSdrh      { "sqlite_datatypes",               (Tcl_CmdProc*)sqlite_datatypes      },
881ed6c8671Sdrh #ifndef SQLITE_OMIT_AUTHORIZATION
882ed6c8671Sdrh      { "sqlite_set_authorizer",          (Tcl_CmdProc*)test_set_authorizer   },
883ed6c8671Sdrh #endif
884c2eef3b3Sdrh #ifdef MEMORY_DEBUG
885c2eef3b3Sdrh      { "sqlite_malloc_fail",             (Tcl_CmdProc*)sqlite_malloc_fail    },
886c2eef3b3Sdrh      { "sqlite_malloc_stat",             (Tcl_CmdProc*)sqlite_malloc_stat    },
887c2eef3b3Sdrh #endif
888b86ccfb2Sdrh      { "sqlite_compile",                 (Tcl_CmdProc*)test_compile          },
889b86ccfb2Sdrh      { "sqlite_step",                    (Tcl_CmdProc*)test_step             },
890b86ccfb2Sdrh      { "sqlite_finalize",                (Tcl_CmdProc*)test_finalize         },
89199ee3600Sdrh      { "breakpoint",                     (Tcl_CmdProc*)test_breakpoint       },
892c2eef3b3Sdrh   };
893c2eef3b3Sdrh   int i;
894c2eef3b3Sdrh 
895c2eef3b3Sdrh   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
896c2eef3b3Sdrh     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
897c2eef3b3Sdrh   }
898487ab3caSdrh   Tcl_LinkVar(interp, "sqlite_search_count",
899487ab3caSdrh       (char*)&sqlite_search_count, TCL_LINK_INT);
900*94e92032Sdrh   Tcl_LinkVar(interp, "sqlite_open_file_count",
901*94e92032Sdrh       (char*)&sqlite_open_file_count, TCL_LINK_INT);
902d1bf3512Sdrh   return TCL_OK;
903d1bf3512Sdrh }
904