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

Last change on this file since 205 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.