xref: /sqlite-3.40.0/src/test1.c (revision ed6c8671)
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*ed6c8671Sdrh ** $Id: test1.c,v 1.15 2003/01/12 18:02:19 drh Exp $
17d1bf3512Sdrh */
18d1bf3512Sdrh #include "sqliteInt.h"
19d1bf3512Sdrh #include "tcl.h"
20d1bf3512Sdrh #include <stdlib.h>
21d1bf3512Sdrh #include <string.h>
22d1bf3512Sdrh 
23d1bf3512Sdrh /*
24d1bf3512Sdrh ** Usage:   sqlite_open filename
25d1bf3512Sdrh **
26d1bf3512Sdrh ** Returns:  The name of an open database.
27d1bf3512Sdrh */
28d1bf3512Sdrh static int sqlite_test_open(
29d1bf3512Sdrh   void *NotUsed,
30d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
31d1bf3512Sdrh   int argc,              /* Number of arguments */
32d1bf3512Sdrh   char **argv            /* Text of each argument */
33d1bf3512Sdrh ){
34d1bf3512Sdrh   sqlite *db;
35d1bf3512Sdrh   char *zErr = 0;
36d1bf3512Sdrh   char zBuf[100];
37d1bf3512Sdrh   if( argc!=2 ){
38d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
39d1bf3512Sdrh        " FILENAME\"", 0);
40d1bf3512Sdrh     return TCL_ERROR;
41d1bf3512Sdrh   }
42d1bf3512Sdrh   db = sqlite_open(argv[1], 0666, &zErr);
43d1bf3512Sdrh   if( db==0 ){
44d1bf3512Sdrh     Tcl_AppendResult(interp, zErr, 0);
45d1bf3512Sdrh     free(zErr);
46d1bf3512Sdrh     return TCL_ERROR;
47d1bf3512Sdrh   }
48d1bf3512Sdrh   sprintf(zBuf,"%d",(int)db);
49d1bf3512Sdrh   Tcl_AppendResult(interp, zBuf, 0);
50d1bf3512Sdrh   return TCL_OK;
51d1bf3512Sdrh }
52d1bf3512Sdrh 
53d1bf3512Sdrh /*
54d1bf3512Sdrh ** The callback routine for sqlite_exec_printf().
55d1bf3512Sdrh */
56d1bf3512Sdrh static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){
57d1bf3512Sdrh   Tcl_DString *str = (Tcl_DString*)pArg;
58d1bf3512Sdrh   int i;
59d1bf3512Sdrh 
60d1bf3512Sdrh   if( Tcl_DStringLength(str)==0 ){
61d1bf3512Sdrh     for(i=0; i<argc; i++){
62d1bf3512Sdrh       Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL");
63d1bf3512Sdrh     }
64d1bf3512Sdrh   }
65d1bf3512Sdrh   for(i=0; i<argc; i++){
66d1bf3512Sdrh     Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL");
67d1bf3512Sdrh   }
68d1bf3512Sdrh   return 0;
69d1bf3512Sdrh }
70d1bf3512Sdrh 
71d1bf3512Sdrh /*
72d1bf3512Sdrh ** Usage:  sqlite_exec_printf  DB  FORMAT  STRING
73d1bf3512Sdrh **
74d1bf3512Sdrh ** Invoke the sqlite_exec_printf() interface using the open database
75d1bf3512Sdrh ** DB.  The SQL is the string FORMAT.  The format string should contain
76d1bf3512Sdrh ** one %s or %q.  STRING is the value inserted into %s or %q.
77d1bf3512Sdrh */
78d1bf3512Sdrh static int test_exec_printf(
79d1bf3512Sdrh   void *NotUsed,
80d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
81d1bf3512Sdrh   int argc,              /* Number of arguments */
82d1bf3512Sdrh   char **argv            /* Text of each argument */
83d1bf3512Sdrh ){
84d1bf3512Sdrh   sqlite *db;
85d1bf3512Sdrh   Tcl_DString str;
86d1bf3512Sdrh   int rc;
87d1bf3512Sdrh   char *zErr = 0;
88d1bf3512Sdrh   char zBuf[30];
89d1bf3512Sdrh   if( argc!=4 ){
90d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
91d1bf3512Sdrh        " DB FORMAT STRING", 0);
92d1bf3512Sdrh     return TCL_ERROR;
93d1bf3512Sdrh   }
9406b2718aSdrh   db = (sqlite*)strtol(argv[1], 0, 0);
95d1bf3512Sdrh   Tcl_DStringInit(&str);
96d1bf3512Sdrh   rc = sqlite_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]);
97d1bf3512Sdrh   sprintf(zBuf, "%d", rc);
98d1bf3512Sdrh   Tcl_AppendElement(interp, zBuf);
99d1bf3512Sdrh   Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
100d1bf3512Sdrh   Tcl_DStringFree(&str);
101d1bf3512Sdrh   if( zErr ) free(zErr);
102d1bf3512Sdrh   return TCL_OK;
103d1bf3512Sdrh }
104d1bf3512Sdrh 
105d1bf3512Sdrh /*
106d1bf3512Sdrh ** Usage:  sqlite_get_table_printf  DB  FORMAT  STRING
107d1bf3512Sdrh **
108d1bf3512Sdrh ** Invoke the sqlite_get_table_printf() interface using the open database
109d1bf3512Sdrh ** DB.  The SQL is the string FORMAT.  The format string should contain
110d1bf3512Sdrh ** one %s or %q.  STRING is the value inserted into %s or %q.
111d1bf3512Sdrh */
112d1bf3512Sdrh static int test_get_table_printf(
113d1bf3512Sdrh   void *NotUsed,
114d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
115d1bf3512Sdrh   int argc,              /* Number of arguments */
116d1bf3512Sdrh   char **argv            /* Text of each argument */
117d1bf3512Sdrh ){
118d1bf3512Sdrh   sqlite *db;
119d1bf3512Sdrh   Tcl_DString str;
120d1bf3512Sdrh   int rc;
121d1bf3512Sdrh   char *zErr = 0;
122d1bf3512Sdrh   int nRow, nCol;
123d1bf3512Sdrh   char **aResult;
124d1bf3512Sdrh   int i;
125d1bf3512Sdrh   char zBuf[30];
126d1bf3512Sdrh   if( argc!=4 ){
127d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
128d1bf3512Sdrh        " DB FORMAT STRING", 0);
129d1bf3512Sdrh     return TCL_ERROR;
130d1bf3512Sdrh   }
13106b2718aSdrh   db = (sqlite*)strtol(argv[1], 0, 0);
132d1bf3512Sdrh   Tcl_DStringInit(&str);
133d1bf3512Sdrh   rc = sqlite_get_table_printf(db, argv[2], &aResult, &nRow, &nCol,
134d1bf3512Sdrh                &zErr, argv[3]);
135d1bf3512Sdrh   sprintf(zBuf, "%d", rc);
136d1bf3512Sdrh   Tcl_AppendElement(interp, zBuf);
137d1bf3512Sdrh   if( rc==SQLITE_OK ){
138d1bf3512Sdrh     sprintf(zBuf, "%d", nRow);
139d1bf3512Sdrh     Tcl_AppendElement(interp, zBuf);
140d1bf3512Sdrh     sprintf(zBuf, "%d", nCol);
141d1bf3512Sdrh     Tcl_AppendElement(interp, zBuf);
142d1bf3512Sdrh     for(i=0; i<(nRow+1)*nCol; i++){
143d1bf3512Sdrh       Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL");
144d1bf3512Sdrh     }
145d1bf3512Sdrh   }else{
146d1bf3512Sdrh     Tcl_AppendElement(interp, zErr);
147d1bf3512Sdrh   }
148d1bf3512Sdrh   sqlite_free_table(aResult);
149d1bf3512Sdrh   if( zErr ) free(zErr);
150d1bf3512Sdrh   return TCL_OK;
151d1bf3512Sdrh }
152d1bf3512Sdrh 
153af9ff33aSdrh 
154af9ff33aSdrh /*
155af9ff33aSdrh ** Usage:  sqlite_last_insert_rowid DB
156af9ff33aSdrh **
157af9ff33aSdrh ** Returns the integer ROWID of the most recent insert.
158af9ff33aSdrh */
159af9ff33aSdrh static int test_last_rowid(
160af9ff33aSdrh   void *NotUsed,
161af9ff33aSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
162af9ff33aSdrh   int argc,              /* Number of arguments */
163af9ff33aSdrh   char **argv            /* Text of each argument */
164af9ff33aSdrh ){
165af9ff33aSdrh   sqlite *db;
166af9ff33aSdrh   char zBuf[30];
167af9ff33aSdrh 
168af9ff33aSdrh   if( argc!=2 ){
169af9ff33aSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0);
170af9ff33aSdrh     return TCL_ERROR;
171af9ff33aSdrh   }
17206b2718aSdrh   db = (sqlite*)strtol(argv[1], 0, 0);
173af9ff33aSdrh   sprintf(zBuf, "%d", sqlite_last_insert_rowid(db));
174af9ff33aSdrh   Tcl_AppendResult(interp, zBuf, 0);
175af9ff33aSdrh   return SQLITE_OK;
176af9ff33aSdrh }
177af9ff33aSdrh 
178d1bf3512Sdrh /*
179d1bf3512Sdrh ** Usage:  sqlite_close DB
180d1bf3512Sdrh **
181d1bf3512Sdrh ** Closes the database opened by sqlite_open.
182d1bf3512Sdrh */
183d1bf3512Sdrh static int sqlite_test_close(
184d1bf3512Sdrh   void *NotUsed,
185d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
186d1bf3512Sdrh   int argc,              /* Number of arguments */
187d1bf3512Sdrh   char **argv            /* Text of each argument */
188d1bf3512Sdrh ){
189d1bf3512Sdrh   sqlite *db;
190d1bf3512Sdrh   if( argc!=2 ){
191d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
192d1bf3512Sdrh        " FILENAME\"", 0);
193d1bf3512Sdrh     return TCL_ERROR;
194d1bf3512Sdrh   }
19506b2718aSdrh   db = (sqlite*)strtol(argv[1], 0, 0);
196d1bf3512Sdrh   sqlite_close(db);
197d1bf3512Sdrh   return TCL_OK;
198d1bf3512Sdrh }
199d1bf3512Sdrh 
200d1bf3512Sdrh /*
201c22bd47dSdrh ** Implementation of the x_coalesce() function.
202c22bd47dSdrh ** Return the first argument non-NULL argument.
203c22bd47dSdrh */
204c22bd47dSdrh static void ifnullFunc(sqlite_func *context, int argc, const char **argv){
205c22bd47dSdrh   int i;
206c22bd47dSdrh   for(i=0; i<argc; i++){
207c22bd47dSdrh     if( argv[i] ){
208c22bd47dSdrh       sqlite_set_result_string(context, argv[i], -1);
209c22bd47dSdrh       break;
210c22bd47dSdrh     }
211c22bd47dSdrh   }
212c22bd47dSdrh }
213c22bd47dSdrh 
214c22bd47dSdrh /*
215c22bd47dSdrh ** Implementation of the x_sqlite_exec() function.  This function takes
216c22bd47dSdrh ** a single argument and attempts to execute that argument as SQL code.
2176cbe1f1bSdrh ** This is illegal and should set the SQLITE_MISUSE flag on the database.
218c22bd47dSdrh **
219c22bd47dSdrh ** This routine simulates the effect of having two threads attempt to
220c22bd47dSdrh ** use the same database at the same time.
221c22bd47dSdrh */
222c22bd47dSdrh static void sqliteExecFunc(sqlite_func *context, int argc, const char **argv){
223c22bd47dSdrh   sqlite_exec((sqlite*)sqlite_user_data(context), argv[0], 0, 0, 0);
224c22bd47dSdrh }
225c22bd47dSdrh 
226c22bd47dSdrh /*
227c22bd47dSdrh ** Usage:  sqlite_test_create_function DB
228c22bd47dSdrh **
229c22bd47dSdrh ** Call the sqlite_create_function API on the given database in order
230c22bd47dSdrh ** to create a function named "x_coalesce".  This function does the same thing
231c22bd47dSdrh ** as the "coalesce" function.  This function also registers an SQL function
232c22bd47dSdrh ** named "x_sqlite_exec" that invokes sqlite_exec().  Invoking sqlite_exec()
233c22bd47dSdrh ** in this way is illegal recursion and should raise an SQLITE_MISUSE error.
234c22bd47dSdrh ** The effect is similar to trying to use the same database connection from
235c22bd47dSdrh ** two threads at the same time.
236c22bd47dSdrh **
237c22bd47dSdrh ** The original motivation for this routine was to be able to call the
238c22bd47dSdrh ** sqlite_create_function function while a query is in progress in order
239c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
240c22bd47dSdrh */
241c2eef3b3Sdrh static int test_create_function(
242c22bd47dSdrh   void *NotUsed,
243c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
244c22bd47dSdrh   int argc,              /* Number of arguments */
245c22bd47dSdrh   char **argv            /* Text of each argument */
246c22bd47dSdrh ){
247c22bd47dSdrh   sqlite *db;
248c22bd47dSdrh   extern void Md5_Register(sqlite*);
249c22bd47dSdrh   if( argc!=2 ){
250c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
251c22bd47dSdrh        " FILENAME\"", 0);
252c22bd47dSdrh     return TCL_ERROR;
253c22bd47dSdrh   }
25406b2718aSdrh   db = (sqlite*)strtol(argv[1], 0, 0);
255c22bd47dSdrh   sqlite_create_function(db, "x_coalesce", -1, ifnullFunc, 0);
256c22bd47dSdrh   sqlite_create_function(db, "x_sqlite_exec", 1, sqliteExecFunc, db);
257c22bd47dSdrh   return TCL_OK;
258c22bd47dSdrh }
259c22bd47dSdrh 
260c22bd47dSdrh /*
261c22bd47dSdrh ** Routines to implement the x_count() aggregate function.
262c22bd47dSdrh */
263c22bd47dSdrh typedef struct CountCtx CountCtx;
264c22bd47dSdrh struct CountCtx {
265c22bd47dSdrh   int n;
266c22bd47dSdrh };
267c22bd47dSdrh static void countStep(sqlite_func *context, int argc, const char **argv){
268c22bd47dSdrh   CountCtx *p;
269c22bd47dSdrh   p = sqlite_aggregate_context(context, sizeof(*p));
270c22bd47dSdrh   if( (argc==0 || argv[0]) && p ){
271c22bd47dSdrh     p->n++;
272c22bd47dSdrh   }
273c22bd47dSdrh }
274c22bd47dSdrh static void countFinalize(sqlite_func *context){
275c22bd47dSdrh   CountCtx *p;
276c22bd47dSdrh   p = sqlite_aggregate_context(context, sizeof(*p));
277c22bd47dSdrh   sqlite_set_result_int(context, p ? p->n : 0);
278c22bd47dSdrh }
279c22bd47dSdrh 
280c22bd47dSdrh /*
281c22bd47dSdrh ** Usage:  sqlite_test_create_aggregate DB
282c22bd47dSdrh **
283c22bd47dSdrh ** Call the sqlite_create_function API on the given database in order
284c22bd47dSdrh ** to create a function named "x_count".  This function does the same thing
285c22bd47dSdrh ** as the "md5sum" function.
286c22bd47dSdrh **
287c22bd47dSdrh ** The original motivation for this routine was to be able to call the
288c22bd47dSdrh ** sqlite_create_aggregate function while a query is in progress in order
289c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
290c22bd47dSdrh */
291c2eef3b3Sdrh static int test_create_aggregate(
292c22bd47dSdrh   void *NotUsed,
293c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
294c22bd47dSdrh   int argc,              /* Number of arguments */
295c22bd47dSdrh   char **argv            /* Text of each argument */
296c22bd47dSdrh ){
297c22bd47dSdrh   sqlite *db;
298c22bd47dSdrh   if( argc!=2 ){
299c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
300c22bd47dSdrh        " FILENAME\"", 0);
301c22bd47dSdrh     return TCL_ERROR;
302c22bd47dSdrh   }
30306b2718aSdrh   db = (sqlite*)strtol(argv[1], 0, 0);
304c22bd47dSdrh   sqlite_create_aggregate(db, "x_count", 0, countStep, countFinalize, 0);
305c22bd47dSdrh   sqlite_create_aggregate(db, "x_count", 1, countStep, countFinalize, 0);
306c22bd47dSdrh   return TCL_OK;
307c22bd47dSdrh }
308c22bd47dSdrh 
309c22bd47dSdrh 
310c22bd47dSdrh 
311c22bd47dSdrh /*
312d1bf3512Sdrh ** Usage:  sqlite_mprintf_int FORMAT INTEGER INTEGER INTEGER
313d1bf3512Sdrh **
314d1bf3512Sdrh ** Call mprintf with three integer arguments
315d1bf3512Sdrh */
316d1bf3512Sdrh static int sqlite_mprintf_int(
317d1bf3512Sdrh   void *NotUsed,
318d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
319d1bf3512Sdrh   int argc,              /* Number of arguments */
320d1bf3512Sdrh   char **argv            /* Text of each argument */
321d1bf3512Sdrh ){
322d1bf3512Sdrh   int a[3], i;
323d1bf3512Sdrh   char *z;
324d1bf3512Sdrh   if( argc!=5 ){
325d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
326d1bf3512Sdrh        " FORMAT INT INT INT\"", 0);
327d1bf3512Sdrh     return TCL_ERROR;
328d1bf3512Sdrh   }
329d1bf3512Sdrh   for(i=2; i<5; i++){
330d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
331d1bf3512Sdrh   }
332d1bf3512Sdrh   z = sqlite_mprintf(argv[1], a[0], a[1], a[2]);
333d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
334fa173a76Sdrh   sqlite_freemem(z);
335d1bf3512Sdrh   return TCL_OK;
336d1bf3512Sdrh }
337d1bf3512Sdrh 
338d1bf3512Sdrh /*
339d1bf3512Sdrh ** Usage:  sqlite_mprintf_str FORMAT INTEGER INTEGER STRING
340d1bf3512Sdrh **
341d1bf3512Sdrh ** Call mprintf with two integer arguments and one string argument
342d1bf3512Sdrh */
343d1bf3512Sdrh static int sqlite_mprintf_str(
344d1bf3512Sdrh   void *NotUsed,
345d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
346d1bf3512Sdrh   int argc,              /* Number of arguments */
347d1bf3512Sdrh   char **argv            /* Text of each argument */
348d1bf3512Sdrh ){
349d1bf3512Sdrh   int a[3], i;
350d1bf3512Sdrh   char *z;
351f220b24fSchw   if( argc<4 || argc>5 ){
352d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
353f220b24fSchw        " FORMAT INT INT ?STRING?\"", 0);
354d1bf3512Sdrh     return TCL_ERROR;
355d1bf3512Sdrh   }
356d1bf3512Sdrh   for(i=2; i<4; i++){
357d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
358d1bf3512Sdrh   }
359f220b24fSchw   z = sqlite_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL);
360d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
361fa173a76Sdrh   sqlite_freemem(z);
362d1bf3512Sdrh   return TCL_OK;
363d1bf3512Sdrh }
364d1bf3512Sdrh 
365d1bf3512Sdrh /*
366d1bf3512Sdrh ** Usage:  sqlite_mprintf_str FORMAT INTEGER INTEGER DOUBLE
367d1bf3512Sdrh **
368d1bf3512Sdrh ** Call mprintf with two integer arguments and one double argument
369d1bf3512Sdrh */
370d1bf3512Sdrh static int sqlite_mprintf_double(
371d1bf3512Sdrh   void *NotUsed,
372d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
373d1bf3512Sdrh   int argc,              /* Number of arguments */
374d1bf3512Sdrh   char **argv            /* Text of each argument */
375d1bf3512Sdrh ){
376d1bf3512Sdrh   int a[3], i;
377d1bf3512Sdrh   double r;
378d1bf3512Sdrh   char *z;
379d1bf3512Sdrh   if( argc!=5 ){
380d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
381d1bf3512Sdrh        " FORMAT INT INT STRING\"", 0);
382d1bf3512Sdrh     return TCL_ERROR;
383d1bf3512Sdrh   }
384d1bf3512Sdrh   for(i=2; i<4; i++){
385d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
386d1bf3512Sdrh   }
387d1bf3512Sdrh   if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR;
388d1bf3512Sdrh   z = sqlite_mprintf(argv[1], a[0], a[1], r);
389d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
390fa173a76Sdrh   sqlite_freemem(z);
391d1bf3512Sdrh   return TCL_OK;
392d1bf3512Sdrh }
393d1bf3512Sdrh 
394d1bf3512Sdrh /*
395daffd0e5Sdrh ** Usage: sqlite_malloc_fail N
396daffd0e5Sdrh **
397afa4a020Sdrh ** Rig sqliteMalloc() to fail on the N-th call.  Turn off this mechanism
398daffd0e5Sdrh ** and reset the sqlite_malloc_failed variable is N==0.
399daffd0e5Sdrh */
400daffd0e5Sdrh #ifdef MEMORY_DEBUG
401daffd0e5Sdrh static int sqlite_malloc_fail(
402daffd0e5Sdrh   void *NotUsed,
403daffd0e5Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
404daffd0e5Sdrh   int argc,              /* Number of arguments */
405daffd0e5Sdrh   char **argv            /* Text of each argument */
406daffd0e5Sdrh ){
407daffd0e5Sdrh   int n;
408daffd0e5Sdrh   if( argc!=2 ){
409daffd0e5Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0);
410daffd0e5Sdrh     return TCL_ERROR;
411daffd0e5Sdrh   }
412daffd0e5Sdrh   if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
413daffd0e5Sdrh   sqlite_iMallocFail = n;
414daffd0e5Sdrh   sqlite_malloc_failed = 0;
415daffd0e5Sdrh   return TCL_OK;
416daffd0e5Sdrh }
417daffd0e5Sdrh #endif
418daffd0e5Sdrh 
419daffd0e5Sdrh /*
420daffd0e5Sdrh ** Usage: sqlite_malloc_stat
421daffd0e5Sdrh **
422daffd0e5Sdrh ** Return the number of prior calls to sqliteMalloc() and sqliteFree().
423daffd0e5Sdrh */
424daffd0e5Sdrh #ifdef MEMORY_DEBUG
425daffd0e5Sdrh static int sqlite_malloc_stat(
426daffd0e5Sdrh   void *NotUsed,
427daffd0e5Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
428daffd0e5Sdrh   int argc,              /* Number of arguments */
429daffd0e5Sdrh   char **argv            /* Text of each argument */
430daffd0e5Sdrh ){
431daffd0e5Sdrh   char zBuf[200];
432daffd0e5Sdrh   sprintf(zBuf, "%d %d %d", sqlite_nMalloc, sqlite_nFree, sqlite_iMallocFail);
433daffd0e5Sdrh   Tcl_AppendResult(interp, zBuf, 0);
434daffd0e5Sdrh   return TCL_OK;
435daffd0e5Sdrh }
436daffd0e5Sdrh #endif
437daffd0e5Sdrh 
438daffd0e5Sdrh /*
43928b4e489Sdrh ** Usage:  sqlite_abort
44028b4e489Sdrh **
44128b4e489Sdrh ** Shutdown the process immediately.  This is not a clean shutdown.
44228b4e489Sdrh ** This command is used to test the recoverability of a database in
44328b4e489Sdrh ** the event of a program crash.
44428b4e489Sdrh */
44528b4e489Sdrh static int sqlite_abort(
44628b4e489Sdrh   void *NotUsed,
44728b4e489Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
44828b4e489Sdrh   int argc,              /* Number of arguments */
44928b4e489Sdrh   char **argv            /* Text of each argument */
45028b4e489Sdrh ){
45128b4e489Sdrh   assert( interp==0 );   /* This will always fail */
45228b4e489Sdrh   return TCL_OK;
45328b4e489Sdrh }
45428b4e489Sdrh 
45528b4e489Sdrh /*
4566cbe1f1bSdrh ** The following routine is a user-defined SQL function whose purpose
4576cbe1f1bSdrh ** is to test the sqlite_set_result() API.
4586cbe1f1bSdrh */
4596cbe1f1bSdrh static void testFunc(sqlite_func *context, int argc, const char **argv){
4606cbe1f1bSdrh   while( argc>=2 ){
4616cbe1f1bSdrh     if( argv[0]==0 ){
4626cbe1f1bSdrh       sqlite_set_result_error(context, "first argument to test function "
4636cbe1f1bSdrh          "may not be NULL", -1);
4646cbe1f1bSdrh     }else if( sqliteStrICmp(argv[0],"string")==0 ){
4656cbe1f1bSdrh       sqlite_set_result_string(context, argv[1], -1);
4666cbe1f1bSdrh     }else if( argv[1]==0 ){
4676cbe1f1bSdrh       sqlite_set_result_error(context, "2nd argument may not be NULL if the "
4686cbe1f1bSdrh          "first argument is not \"string\"", -1);
4696cbe1f1bSdrh     }else if( sqliteStrICmp(argv[0],"int")==0 ){
4706cbe1f1bSdrh       sqlite_set_result_int(context, atoi(argv[1]));
4716cbe1f1bSdrh     }else if( sqliteStrICmp(argv[0],"double")==0 ){
4726cbe1f1bSdrh       sqlite_set_result_double(context, atof(argv[1]));
4736cbe1f1bSdrh     }else{
4746cbe1f1bSdrh       sqlite_set_result_error(context,"first argument should be one of: "
4756cbe1f1bSdrh           "string int double", -1);
4766cbe1f1bSdrh     }
4776cbe1f1bSdrh     argc -= 2;
4786cbe1f1bSdrh     argv += 2;
4796cbe1f1bSdrh   }
4806cbe1f1bSdrh }
4816cbe1f1bSdrh 
4826cbe1f1bSdrh /*
4836cbe1f1bSdrh ** Usage:   sqlite_register_test_function  DB  NAME
4846cbe1f1bSdrh **
4856cbe1f1bSdrh ** Register the test SQL function on the database DB under the name NAME.
4866cbe1f1bSdrh */
487c2eef3b3Sdrh static int test_register_func(
4886cbe1f1bSdrh   void *NotUsed,
4896cbe1f1bSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
4906cbe1f1bSdrh   int argc,              /* Number of arguments */
4916cbe1f1bSdrh   char **argv            /* Text of each argument */
4926cbe1f1bSdrh ){
4936cbe1f1bSdrh   sqlite *db;
4946cbe1f1bSdrh   int rc;
4956cbe1f1bSdrh   if( argc!=3 ){
4966cbe1f1bSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
4976cbe1f1bSdrh        " DB FUNCTION-NAME", 0);
4986cbe1f1bSdrh     return TCL_ERROR;
4996cbe1f1bSdrh   }
5006cbe1f1bSdrh   db = (sqlite*)strtol(argv[1], 0, 0);
5016cbe1f1bSdrh   rc = sqlite_create_function(db, argv[2], -1, testFunc, 0);
5026cbe1f1bSdrh   if( rc!=0 ){
5036cbe1f1bSdrh     Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
5046cbe1f1bSdrh     return TCL_ERROR;
5056cbe1f1bSdrh   }
5066cbe1f1bSdrh   return TCL_OK;
5076cbe1f1bSdrh }
5086cbe1f1bSdrh 
5096cbe1f1bSdrh /*
5105a38705eSdrh ** This SQLite callback records the datatype of all columns.
5115a38705eSdrh **
5125a38705eSdrh ** The pArg argument is really a pointer to a TCL interpreter.  The
5135a38705eSdrh ** column names are inserted as the result of this interpreter.
5145a38705eSdrh **
5155a38705eSdrh ** This routine returns non-zero which causes the query to abort.
5165a38705eSdrh */
5175a38705eSdrh static int rememberDataTypes(void *pArg, int nCol, char **argv, char **colv){
5185a38705eSdrh   int i;
5195a38705eSdrh   Tcl_Interp *interp = (Tcl_Interp*)pArg;
5205a38705eSdrh   Tcl_Obj *pList, *pElem;
5215a38705eSdrh   if( colv[nCol+1]==0 ){
5225a38705eSdrh     return 1;
5235a38705eSdrh   }
5245a38705eSdrh   pList = Tcl_NewObj();
5255a38705eSdrh   for(i=0; i<nCol; i++){
5265a38705eSdrh     pElem = Tcl_NewStringObj(colv[i+nCol] ? colv[i+nCol] : "NULL", -1);
5275a38705eSdrh     Tcl_ListObjAppendElement(interp, pList, pElem);
5285a38705eSdrh   }
5295a38705eSdrh   Tcl_SetObjResult(interp, pList);
5305a38705eSdrh   return 1;
5315a38705eSdrh }
5325a38705eSdrh 
5335a38705eSdrh /*
5345a38705eSdrh ** Invoke an SQL statement but ignore all the data in the result.  Instead,
5355a38705eSdrh ** return a list that consists of the datatypes of the various columns.
5365a38705eSdrh **
5375a38705eSdrh ** This only works if "PRAGMA show_datatypes=on" has been executed against
5385a38705eSdrh ** the database connection.
5395a38705eSdrh */
5405a38705eSdrh static int sqlite_datatypes(
5415a38705eSdrh   void *NotUsed,
5425a38705eSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
5435a38705eSdrh   int argc,              /* Number of arguments */
5445a38705eSdrh   char **argv            /* Text of each argument */
5455a38705eSdrh ){
5465a38705eSdrh   sqlite *db;
5475a38705eSdrh   int rc;
5485a38705eSdrh   if( argc!=3 ){
5495a38705eSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
5505a38705eSdrh        " DB SQL", 0);
5515a38705eSdrh     return TCL_ERROR;
5525a38705eSdrh   }
5535a38705eSdrh   db = (sqlite*)strtol(argv[1], 0, 0);
5545a38705eSdrh   rc = sqlite_exec(db, argv[2], rememberDataTypes, interp, 0);
5555a38705eSdrh   if( rc!=0 && rc!=SQLITE_ABORT ){
5565a38705eSdrh     Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
5575a38705eSdrh     return TCL_ERROR;
5585a38705eSdrh   }
5595a38705eSdrh   return TCL_OK;
5605a38705eSdrh }
5615a38705eSdrh 
562*ed6c8671Sdrh #ifndef SQLITE_OMIT_AUTHORIZATION
563*ed6c8671Sdrh /*
564*ed6c8671Sdrh ** Information used by the authentication function.
565*ed6c8671Sdrh */
566*ed6c8671Sdrh typedef struct AuthInfo AuthInfo;
567*ed6c8671Sdrh struct AuthInfo {
568*ed6c8671Sdrh   Tcl_Interp *interp;    /* Interpreter to use */
569*ed6c8671Sdrh   int nCmd;              /* Number of characters in zCmd[] */
570*ed6c8671Sdrh   char zCmd[500];        /* Command to invoke */
571*ed6c8671Sdrh };
572*ed6c8671Sdrh 
573*ed6c8671Sdrh /*
574*ed6c8671Sdrh ** We create a single static authenticator.  This won't work in a
575*ed6c8671Sdrh ** multi-threaded environment, but the test fixture is not multithreaded.
576*ed6c8671Sdrh ** And be making it static, we don't have to worry about deallocating
577*ed6c8671Sdrh ** after a test in order to void memory leaks.
578*ed6c8671Sdrh */
579*ed6c8671Sdrh static AuthInfo authInfo;
580*ed6c8671Sdrh 
581*ed6c8671Sdrh /*
582*ed6c8671Sdrh ** This is the authentication function.  It appends the authentication
583*ed6c8671Sdrh ** type code and the two arguments to zCmd[] then invokes the result
584*ed6c8671Sdrh ** on the interpreter.  The reply is examined to determine if the
585*ed6c8671Sdrh ** authentication fails or succeeds.
586*ed6c8671Sdrh */
587*ed6c8671Sdrh static int auth_callback(
588*ed6c8671Sdrh   void *NotUsed,
589*ed6c8671Sdrh   int code,
590*ed6c8671Sdrh   const char *zArg1,
591*ed6c8671Sdrh   const char *zArg2
592*ed6c8671Sdrh ){
593*ed6c8671Sdrh   char *zCode;
594*ed6c8671Sdrh   Tcl_DString str;
595*ed6c8671Sdrh   int rc;
596*ed6c8671Sdrh   const char *zReply;
597*ed6c8671Sdrh   switch( code ){
598*ed6c8671Sdrh     case SQLITE_READ_COLUMN:   zCode="SQLITE_READ_COLUMN";  break;
599*ed6c8671Sdrh     case SQLITE_WRITE_COLUMN:  zCode="SQLITE_WRITE_COLUMN"; break;
600*ed6c8671Sdrh     case SQLITE_INSERT_ROW:    zCode="SQLITE_INSERT_ROW";   break;
601*ed6c8671Sdrh     case SQLITE_DELETE_ROW:    zCode="SQLITE_DELETE_ROW";   break;
602*ed6c8671Sdrh     case SQLITE_COMMAND:       zCode="SQLITE_COMMAND";      break;
603*ed6c8671Sdrh     default:                   zCode="unknown code";        break;
604*ed6c8671Sdrh   }
605*ed6c8671Sdrh   Tcl_DStringInit(&str);
606*ed6c8671Sdrh   Tcl_DStringAppend(&str, authInfo.zCmd, -1);
607*ed6c8671Sdrh   Tcl_DStringAppendElement(&str, zCode);
608*ed6c8671Sdrh   Tcl_DStringAppendElement(&str, zArg1);
609*ed6c8671Sdrh   Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : "");
610*ed6c8671Sdrh   rc = Tcl_GlobalEval(authInfo.interp, Tcl_DStringValue(&str));
611*ed6c8671Sdrh   Tcl_DStringFree(&str);
612*ed6c8671Sdrh   zReply = Tcl_GetStringResult(authInfo.interp);
613*ed6c8671Sdrh   if( strcmp(zReply,"SQLITE_OK")==0 ){
614*ed6c8671Sdrh     rc = SQLITE_OK;
615*ed6c8671Sdrh   }else if( strcmp(zReply,"SQLITE_DENY")==0 ){
616*ed6c8671Sdrh     rc = SQLITE_DENY;
617*ed6c8671Sdrh   }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){
618*ed6c8671Sdrh     rc = SQLITE_IGNORE;
619*ed6c8671Sdrh   }else{
620*ed6c8671Sdrh     rc = 999;
621*ed6c8671Sdrh   }
622*ed6c8671Sdrh   return rc;
623*ed6c8671Sdrh }
624*ed6c8671Sdrh 
625*ed6c8671Sdrh /*
626*ed6c8671Sdrh ** This routine creates a new authenticator.  It fills in the zCmd[]
627*ed6c8671Sdrh ** field of the authentication function state variable and then registers
628*ed6c8671Sdrh ** the authentication function with the SQLite library.
629*ed6c8671Sdrh */
630*ed6c8671Sdrh static int test_set_authorizer(
631*ed6c8671Sdrh   void *NotUsed,
632*ed6c8671Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
633*ed6c8671Sdrh   int argc,              /* Number of arguments */
634*ed6c8671Sdrh   char **argv            /* Text of each argument */
635*ed6c8671Sdrh ){
636*ed6c8671Sdrh   sqlite *db;
637*ed6c8671Sdrh   char *zCmd;
638*ed6c8671Sdrh   if( argc!=3 ){
639*ed6c8671Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
640*ed6c8671Sdrh          " DB CALLBACK\"", 0);
641*ed6c8671Sdrh     return TCL_ERROR;
642*ed6c8671Sdrh   }
643*ed6c8671Sdrh   db = (sqlite*)strtol(argv[1], 0, 0);
644*ed6c8671Sdrh   zCmd = argv[2];
645*ed6c8671Sdrh   if( zCmd[0]==0 ){
646*ed6c8671Sdrh     sqlite_set_authorizer(db, 0, 0);
647*ed6c8671Sdrh     return TCL_OK;
648*ed6c8671Sdrh   }
649*ed6c8671Sdrh   if( strlen(zCmd)>sizeof(authInfo.zCmd) ){
650*ed6c8671Sdrh     Tcl_AppendResult(interp, "command too big", 0);
651*ed6c8671Sdrh     return TCL_ERROR;
652*ed6c8671Sdrh   }
653*ed6c8671Sdrh   authInfo.interp = interp;
654*ed6c8671Sdrh   authInfo.nCmd = strlen(zCmd);
655*ed6c8671Sdrh   strcpy(authInfo.zCmd, zCmd);
656*ed6c8671Sdrh   sqlite_set_authorizer(db, auth_callback, 0);
657*ed6c8671Sdrh   return TCL_OK;
658*ed6c8671Sdrh }
659*ed6c8671Sdrh #endif /* SQLITE_OMIT_AUTHORIZATION */
6605a38705eSdrh 
6615a38705eSdrh /*
662d1bf3512Sdrh ** Register commands with the TCL interpreter.
663d1bf3512Sdrh */
664d1bf3512Sdrh int Sqlitetest1_Init(Tcl_Interp *interp){
665487ab3caSdrh   extern int sqlite_search_count;
666c2eef3b3Sdrh   static struct {
667c2eef3b3Sdrh      char *zName;
668c2eef3b3Sdrh      Tcl_CmdProc *xProc;
669c2eef3b3Sdrh   } aCmd[] = {
670c2eef3b3Sdrh      { "sqlite_mprintf_int",             (Tcl_CmdProc*)sqlite_mprintf_int    },
671c2eef3b3Sdrh      { "sqlite_mprintf_str",             (Tcl_CmdProc*)sqlite_mprintf_str    },
672c2eef3b3Sdrh      { "sqlite_mprintf_double",          (Tcl_CmdProc*)sqlite_mprintf_double },
673c2eef3b3Sdrh      { "sqlite_open",                    (Tcl_CmdProc*)sqlite_test_open      },
674c2eef3b3Sdrh      { "sqlite_last_insert_rowid",       (Tcl_CmdProc*)test_last_rowid       },
675c2eef3b3Sdrh      { "sqlite_exec_printf",             (Tcl_CmdProc*)test_exec_printf      },
676c2eef3b3Sdrh      { "sqlite_get_table_printf",        (Tcl_CmdProc*)test_get_table_printf },
677c2eef3b3Sdrh      { "sqlite_close",                   (Tcl_CmdProc*)sqlite_test_close     },
678c2eef3b3Sdrh      { "sqlite_create_function",         (Tcl_CmdProc*)test_create_function  },
679c2eef3b3Sdrh      { "sqlite_create_aggregate",        (Tcl_CmdProc*)test_create_aggregate },
680c2eef3b3Sdrh      { "sqlite_register_test_function",  (Tcl_CmdProc*)test_register_func    },
681c2eef3b3Sdrh      { "sqlite_abort",                   (Tcl_CmdProc*)sqlite_abort          },
6825a38705eSdrh      { "sqlite_datatypes",               (Tcl_CmdProc*)sqlite_datatypes      },
683*ed6c8671Sdrh #ifndef SQLITE_OMIT_AUTHORIZATION
684*ed6c8671Sdrh      { "sqlite_set_authorizer",          (Tcl_CmdProc*)test_set_authorizer   },
685*ed6c8671Sdrh #endif
686c2eef3b3Sdrh #ifdef MEMORY_DEBUG
687c2eef3b3Sdrh      { "sqlite_malloc_fail",             (Tcl_CmdProc*)sqlite_malloc_fail    },
688c2eef3b3Sdrh      { "sqlite_malloc_stat",             (Tcl_CmdProc*)sqlite_malloc_stat    },
689c2eef3b3Sdrh #endif
690c2eef3b3Sdrh   };
691c2eef3b3Sdrh   int i;
692c2eef3b3Sdrh 
693c2eef3b3Sdrh   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
694c2eef3b3Sdrh     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
695c2eef3b3Sdrh   }
696487ab3caSdrh   Tcl_LinkVar(interp, "sqlite_search_count",
697487ab3caSdrh       (char*)&sqlite_search_count, TCL_LINK_INT);
698d1bf3512Sdrh   return TCL_OK;
699d1bf3512Sdrh }
700