source: trunk/src/3rdparty/sqlite/test1.c

Last change on this file was 205, checked in by rudi, 14 years ago

Added SQLite 2.8.17 sources. This allows to build at least one of the sql drivers / plugins.

File size: 30.9 KB
Line 
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*/
33static 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*/
46static 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 her 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*/
67static 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*/
89static 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*/
117static 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*/
139static 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*/
173static 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*/
197static 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*/
244static 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*/
268static 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*/
289static 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*/
302struct 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*/
311static 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*/
334static 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*/
358static 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*/
382static 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*/
404typedef struct CountCtx CountCtx;
405struct CountCtx {
406 int n;
407};
408static 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}
415static 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*/
432static 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*/
457static 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*/
484static 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*/
511static 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*/
542static 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
572static 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
596static 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*/
616static 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*/
630static 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*/
658static 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*/
688static 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*/
711static 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*/
740static 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*/
780static 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*/
839static 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*/
870static 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*/
900static 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*/
912static 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*/
961static 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*/
973int 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}
Note: See TracBrowser for help on using the repository browser.