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