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