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