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