xref: /sqlite-3.40.0/src/test1.c (revision 6590493d)
1d1bf3512Sdrh /*
2b19a2bc6Sdrh ** 2001 September 15
3d1bf3512Sdrh **
4b19a2bc6Sdrh ** The author disclaims copyright to this source code.  In place of
5b19a2bc6Sdrh ** a legal notice, here is a blessing:
6d1bf3512Sdrh **
7b19a2bc6Sdrh **    May you do good and not evil.
8b19a2bc6Sdrh **    May you find forgiveness for yourself and forgive others.
9b19a2bc6Sdrh **    May you share freely, never taking more than you give.
10d1bf3512Sdrh **
11d1bf3512Sdrh *************************************************************************
12d1bf3512Sdrh ** Code for testing the printf() interface to SQLite.  This code
13d1bf3512Sdrh ** is not included in the SQLite library.  It is used for automated
14d1bf3512Sdrh ** testing of the SQLite library.
15d1bf3512Sdrh **
16*6590493dSdanielk1977 ** $Id: test1.c,v 1.55 2004/05/26 06:18:38 danielk1977 Exp $
17d1bf3512Sdrh */
18d1bf3512Sdrh #include "sqliteInt.h"
19d1bf3512Sdrh #include "tcl.h"
2094e92032Sdrh #include "os.h"
21d1bf3512Sdrh #include <stdlib.h>
22d1bf3512Sdrh #include <string.h>
23d1bf3512Sdrh 
2494e92032Sdrh #if OS_WIN
2594e92032Sdrh # define PTR_FMT "%x"
2694e92032Sdrh #else
2794e92032Sdrh # define PTR_FMT "%p"
2894e92032Sdrh #endif
2994e92032Sdrh 
306622cce3Sdanielk1977 static const char * errorName(int rc){
316622cce3Sdanielk1977   const char *zName = 0;
326622cce3Sdanielk1977   switch( rc ){
336622cce3Sdanielk1977     case SQLITE_OK:         zName = "SQLITE_OK";          break;
346622cce3Sdanielk1977     case SQLITE_ERROR:      zName = "SQLITE_ERROR";       break;
356622cce3Sdanielk1977     case SQLITE_INTERNAL:   zName = "SQLITE_INTERNAL";    break;
366622cce3Sdanielk1977     case SQLITE_PERM:       zName = "SQLITE_PERM";        break;
376622cce3Sdanielk1977     case SQLITE_ABORT:      zName = "SQLITE_ABORT";       break;
386622cce3Sdanielk1977     case SQLITE_BUSY:       zName = "SQLITE_BUSY";        break;
396622cce3Sdanielk1977     case SQLITE_LOCKED:     zName = "SQLITE_LOCKED";      break;
406622cce3Sdanielk1977     case SQLITE_NOMEM:      zName = "SQLITE_NOMEM";       break;
416622cce3Sdanielk1977     case SQLITE_READONLY:   zName = "SQLITE_READONLY";    break;
426622cce3Sdanielk1977     case SQLITE_INTERRUPT:  zName = "SQLITE_INTERRUPT";   break;
436622cce3Sdanielk1977     case SQLITE_IOERR:      zName = "SQLITE_IOERR";       break;
446622cce3Sdanielk1977     case SQLITE_CORRUPT:    zName = "SQLITE_CORRUPT";     break;
456622cce3Sdanielk1977     case SQLITE_NOTFOUND:   zName = "SQLITE_NOTFOUND";    break;
466622cce3Sdanielk1977     case SQLITE_FULL:       zName = "SQLITE_FULL";        break;
476622cce3Sdanielk1977     case SQLITE_CANTOPEN:   zName = "SQLITE_CANTOPEN";    break;
486622cce3Sdanielk1977     case SQLITE_PROTOCOL:   zName = "SQLITE_PROTOCOL";    break;
496622cce3Sdanielk1977     case SQLITE_EMPTY:      zName = "SQLITE_EMPTY";       break;
506622cce3Sdanielk1977     case SQLITE_SCHEMA:     zName = "SQLITE_SCHEMA";      break;
516622cce3Sdanielk1977     case SQLITE_TOOBIG:     zName = "SQLITE_TOOBIG";      break;
526622cce3Sdanielk1977     case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT";  break;
536622cce3Sdanielk1977     case SQLITE_MISMATCH:   zName = "SQLITE_MISMATCH";    break;
546622cce3Sdanielk1977     case SQLITE_MISUSE:     zName = "SQLITE_MISUSE";      break;
556622cce3Sdanielk1977     case SQLITE_NOLFS:      zName = "SQLITE_NOLFS";       break;
566622cce3Sdanielk1977     case SQLITE_AUTH:       zName = "SQLITE_AUTH";        break;
576622cce3Sdanielk1977     case SQLITE_FORMAT:     zName = "SQLITE_FORMAT";      break;
586622cce3Sdanielk1977     case SQLITE_RANGE:      zName = "SQLITE_RANGE";       break;
596622cce3Sdanielk1977     case SQLITE_ROW:        zName = "SQLITE_ROW";         break;
606622cce3Sdanielk1977     case SQLITE_DONE:       zName = "SQLITE_DONE";        break;
616622cce3Sdanielk1977     default:                zName = "SQLITE_Unknown";     break;
626622cce3Sdanielk1977   }
636622cce3Sdanielk1977   return zName;
646622cce3Sdanielk1977 }
656622cce3Sdanielk1977 
66d1bf3512Sdrh /*
67b86ccfb2Sdrh ** Decode a pointer to an sqlite object.
68b86ccfb2Sdrh */
6990f405e3Sdrh static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite **ppDb){
7090f405e3Sdrh   if( sscanf(zA, PTR_FMT, (void**)ppDb)!=1 &&
7190f405e3Sdrh       (zA[0]!='0' || zA[1]!='x' || sscanf(&zA[2], PTR_FMT, (void**)ppDb)!=1)
7290f405e3Sdrh   ){
7390f405e3Sdrh     Tcl_AppendResult(interp, "\"", zA, "\" is not a valid pointer value", 0);
74b86ccfb2Sdrh     return TCL_ERROR;
75b86ccfb2Sdrh   }
76b86ccfb2Sdrh   return TCL_OK;
77b86ccfb2Sdrh }
78b86ccfb2Sdrh 
79b86ccfb2Sdrh /*
8051e3d8e2Sdanielk1977 ** Decode a pointer to an sqlite3_stmt object.
8151e3d8e2Sdanielk1977 */
8251e3d8e2Sdanielk1977 static int getStmtPointer(
8351e3d8e2Sdanielk1977   Tcl_Interp *interp,
8451e3d8e2Sdanielk1977   const char *zArg,
8551e3d8e2Sdanielk1977   sqlite3_stmt **ppStmt
8651e3d8e2Sdanielk1977 ){
8751e3d8e2Sdanielk1977   if( sscanf(zArg, PTR_FMT, (void**)ppStmt)!=1 ){
8851e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0);
8951e3d8e2Sdanielk1977     return TCL_ERROR;
9051e3d8e2Sdanielk1977   }
9151e3d8e2Sdanielk1977   return TCL_OK;
9251e3d8e2Sdanielk1977 }
9351e3d8e2Sdanielk1977 
9451e3d8e2Sdanielk1977 /*
957d8085a8Sdrh ** Generate a text representation of a pointer that can be understood
967d8085a8Sdrh ** by the getDbPointer and getVmPointer routines above.
977d8085a8Sdrh **
987d8085a8Sdrh ** The problem is, on some machines (Solaris) if you do a printf with
997d8085a8Sdrh ** "%p" you cannot turn around and do a scanf with the same "%p" and
1007d8085a8Sdrh ** get your pointer back.  You have to prepend a "0x" before it will
1017d8085a8Sdrh ** work.  Or at least that is what is reported to me (drh).  But this
1027d8085a8Sdrh ** behavior varies from machine to machine.  The solution used her is
1037d8085a8Sdrh ** to test the string right after it is generated to see if it can be
1047d8085a8Sdrh ** understood by scanf, and if not, try prepending an "0x" to see if
1057d8085a8Sdrh ** that helps.  If nothing works, a fatal error is generated.
1067d8085a8Sdrh */
1077d8085a8Sdrh static int makePointerStr(Tcl_Interp *interp, char *zPtr, void *p){
1087d8085a8Sdrh   void *p2;
1097d8085a8Sdrh   sprintf(zPtr, PTR_FMT, p);
1107d8085a8Sdrh   if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){
1117d8085a8Sdrh     sprintf(zPtr, "0x" PTR_FMT, p);
1127d8085a8Sdrh     if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){
1137d8085a8Sdrh       Tcl_AppendResult(interp, "unable to convert a pointer to a string "
1147d8085a8Sdrh          "in the file " __FILE__ " in function makePointerStr().  Please "
1157d8085a8Sdrh          "report this problem to the SQLite mailing list or as a new but "
1167d8085a8Sdrh          "report.  Please provide detailed information about how you compiled "
1177d8085a8Sdrh          "SQLite and what computer you are running on.", 0);
1187d8085a8Sdrh       return TCL_ERROR;
1197d8085a8Sdrh     }
1207d8085a8Sdrh   }
1217d8085a8Sdrh   return TCL_OK;
1227d8085a8Sdrh }
1237d8085a8Sdrh 
1247d8085a8Sdrh /*
1256f8a503dSdanielk1977 ** The callback routine for sqlite3_exec_printf().
126d1bf3512Sdrh */
127d1bf3512Sdrh static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){
128d1bf3512Sdrh   Tcl_DString *str = (Tcl_DString*)pArg;
129d1bf3512Sdrh   int i;
130d1bf3512Sdrh 
131d1bf3512Sdrh   if( Tcl_DStringLength(str)==0 ){
132d1bf3512Sdrh     for(i=0; i<argc; i++){
133d1bf3512Sdrh       Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL");
134d1bf3512Sdrh     }
135d1bf3512Sdrh   }
136d1bf3512Sdrh   for(i=0; i<argc; i++){
137d1bf3512Sdrh     Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL");
138d1bf3512Sdrh   }
139d1bf3512Sdrh   return 0;
140d1bf3512Sdrh }
141d1bf3512Sdrh 
142d1bf3512Sdrh /*
1436f8a503dSdanielk1977 ** Usage:  sqlite3_exec_printf  DB  FORMAT  STRING
144d1bf3512Sdrh **
1456f8a503dSdanielk1977 ** Invoke the sqlite3_exec_printf() interface using the open database
146d1bf3512Sdrh ** DB.  The SQL is the string FORMAT.  The format string should contain
147d1bf3512Sdrh ** one %s or %q.  STRING is the value inserted into %s or %q.
148d1bf3512Sdrh */
149d1bf3512Sdrh static int test_exec_printf(
150d1bf3512Sdrh   void *NotUsed,
151d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
152d1bf3512Sdrh   int argc,              /* Number of arguments */
153d1bf3512Sdrh   char **argv            /* Text of each argument */
154d1bf3512Sdrh ){
155d1bf3512Sdrh   sqlite *db;
156d1bf3512Sdrh   Tcl_DString str;
157d1bf3512Sdrh   int rc;
158d1bf3512Sdrh   char *zErr = 0;
159d1bf3512Sdrh   char zBuf[30];
160d1bf3512Sdrh   if( argc!=4 ){
161d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
162d1bf3512Sdrh        " DB FORMAT STRING", 0);
163d1bf3512Sdrh     return TCL_ERROR;
164d1bf3512Sdrh   }
165b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
166d1bf3512Sdrh   Tcl_DStringInit(&str);
1676f8a503dSdanielk1977   rc = sqlite3_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]);
168d1bf3512Sdrh   sprintf(zBuf, "%d", rc);
169d1bf3512Sdrh   Tcl_AppendElement(interp, zBuf);
170d1bf3512Sdrh   Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
171d1bf3512Sdrh   Tcl_DStringFree(&str);
172d1bf3512Sdrh   if( zErr ) free(zErr);
173d1bf3512Sdrh   return TCL_OK;
174d1bf3512Sdrh }
175d1bf3512Sdrh 
176d1bf3512Sdrh /*
1776f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_z_test  SEPARATOR  ARG0  ARG1 ...
178d93d8a81Sdrh **
179d93d8a81Sdrh ** Test the %z format of mprintf().  Use multiple mprintf() calls to
180d93d8a81Sdrh ** concatenate arg0 through argn using separator as the separator.
181d93d8a81Sdrh ** Return the result.
182d93d8a81Sdrh */
183d93d8a81Sdrh static int test_mprintf_z(
184d93d8a81Sdrh   void *NotUsed,
185d93d8a81Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
186d93d8a81Sdrh   int argc,              /* Number of arguments */
187d93d8a81Sdrh   char **argv            /* Text of each argument */
188d93d8a81Sdrh ){
189d93d8a81Sdrh   char *zResult = 0;
190d93d8a81Sdrh   int i;
191d93d8a81Sdrh 
192d93d8a81Sdrh   for(i=2; i<argc; i++){
1934adee20fSdanielk1977     zResult = sqlite3MPrintf("%z%s%s", zResult, argv[1], argv[i]);
194d93d8a81Sdrh   }
195d93d8a81Sdrh   Tcl_AppendResult(interp, zResult, 0);
1965f968436Sdrh   sqliteFree(zResult);
197d93d8a81Sdrh   return TCL_OK;
198d93d8a81Sdrh }
199d93d8a81Sdrh 
200d93d8a81Sdrh /*
2016f8a503dSdanielk1977 ** Usage:  sqlite3_get_table_printf  DB  FORMAT  STRING
202d1bf3512Sdrh **
2036f8a503dSdanielk1977 ** Invoke the sqlite3_get_table_printf() interface using the open database
204d1bf3512Sdrh ** DB.  The SQL is the string FORMAT.  The format string should contain
205d1bf3512Sdrh ** one %s or %q.  STRING is the value inserted into %s or %q.
206d1bf3512Sdrh */
207d1bf3512Sdrh static int test_get_table_printf(
208d1bf3512Sdrh   void *NotUsed,
209d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
210d1bf3512Sdrh   int argc,              /* Number of arguments */
211d1bf3512Sdrh   char **argv            /* Text of each argument */
212d1bf3512Sdrh ){
213d1bf3512Sdrh   sqlite *db;
214d1bf3512Sdrh   Tcl_DString str;
215d1bf3512Sdrh   int rc;
216d1bf3512Sdrh   char *zErr = 0;
217d1bf3512Sdrh   int nRow, nCol;
218d1bf3512Sdrh   char **aResult;
219d1bf3512Sdrh   int i;
220d1bf3512Sdrh   char zBuf[30];
221d1bf3512Sdrh   if( argc!=4 ){
222d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
223d1bf3512Sdrh        " DB FORMAT STRING", 0);
224d1bf3512Sdrh     return TCL_ERROR;
225d1bf3512Sdrh   }
226b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
227d1bf3512Sdrh   Tcl_DStringInit(&str);
2286f8a503dSdanielk1977   rc = sqlite3_get_table_printf(db, argv[2], &aResult, &nRow, &nCol,
229d1bf3512Sdrh                &zErr, argv[3]);
230d1bf3512Sdrh   sprintf(zBuf, "%d", rc);
231d1bf3512Sdrh   Tcl_AppendElement(interp, zBuf);
232d1bf3512Sdrh   if( rc==SQLITE_OK ){
233d1bf3512Sdrh     sprintf(zBuf, "%d", nRow);
234d1bf3512Sdrh     Tcl_AppendElement(interp, zBuf);
235d1bf3512Sdrh     sprintf(zBuf, "%d", nCol);
236d1bf3512Sdrh     Tcl_AppendElement(interp, zBuf);
237d1bf3512Sdrh     for(i=0; i<(nRow+1)*nCol; i++){
238d1bf3512Sdrh       Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL");
239d1bf3512Sdrh     }
240d1bf3512Sdrh   }else{
241d1bf3512Sdrh     Tcl_AppendElement(interp, zErr);
242d1bf3512Sdrh   }
2436f8a503dSdanielk1977   sqlite3_free_table(aResult);
244d1bf3512Sdrh   if( zErr ) free(zErr);
245d1bf3512Sdrh   return TCL_OK;
246d1bf3512Sdrh }
247d1bf3512Sdrh 
248af9ff33aSdrh 
249af9ff33aSdrh /*
2506f8a503dSdanielk1977 ** Usage:  sqlite3_last_insert_rowid DB
251af9ff33aSdrh **
252af9ff33aSdrh ** Returns the integer ROWID of the most recent insert.
253af9ff33aSdrh */
254af9ff33aSdrh static int test_last_rowid(
255af9ff33aSdrh   void *NotUsed,
256af9ff33aSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
257af9ff33aSdrh   int argc,              /* Number of arguments */
258af9ff33aSdrh   char **argv            /* Text of each argument */
259af9ff33aSdrh ){
260af9ff33aSdrh   sqlite *db;
261af9ff33aSdrh   char zBuf[30];
262af9ff33aSdrh 
263af9ff33aSdrh   if( argc!=2 ){
264af9ff33aSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0);
265af9ff33aSdrh     return TCL_ERROR;
266af9ff33aSdrh   }
267b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
2686f8a503dSdanielk1977   sprintf(zBuf, "%d", sqlite3_last_insert_rowid(db));
269af9ff33aSdrh   Tcl_AppendResult(interp, zBuf, 0);
270af9ff33aSdrh   return SQLITE_OK;
271af9ff33aSdrh }
272af9ff33aSdrh 
273d1bf3512Sdrh /*
2746f8a503dSdanielk1977 ** Usage:  sqlite3_close DB
275d1bf3512Sdrh **
2766f8a503dSdanielk1977 ** Closes the database opened by sqlite3_open.
277d1bf3512Sdrh */
278d1bf3512Sdrh static int sqlite_test_close(
279d1bf3512Sdrh   void *NotUsed,
280d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
281d1bf3512Sdrh   int argc,              /* Number of arguments */
282d1bf3512Sdrh   char **argv            /* Text of each argument */
283d1bf3512Sdrh ){
284d1bf3512Sdrh   sqlite *db;
285d1bf3512Sdrh   if( argc!=2 ){
286d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
287d1bf3512Sdrh        " FILENAME\"", 0);
288d1bf3512Sdrh     return TCL_ERROR;
289d1bf3512Sdrh   }
290b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
2916f8a503dSdanielk1977   sqlite3_close(db);
292d1bf3512Sdrh   return TCL_OK;
293d1bf3512Sdrh }
294d1bf3512Sdrh 
295d1bf3512Sdrh /*
296c22bd47dSdrh ** Implementation of the x_coalesce() function.
297c22bd47dSdrh ** Return the first argument non-NULL argument.
298c22bd47dSdrh */
2990ae8b831Sdanielk1977 static void ifnullFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
300c22bd47dSdrh   int i;
301c22bd47dSdrh   for(i=0; i<argc; i++){
30251ad0ecdSdanielk1977     if( SQLITE3_NULL!=sqlite3_value_type(argv[i]) ){
3037e18c259Sdanielk1977       sqlite3_result_text(context, sqlite3_value_data(argv[i]), -1, 1);
304c22bd47dSdrh       break;
305c22bd47dSdrh     }
306c22bd47dSdrh   }
307c22bd47dSdrh }
308c22bd47dSdrh 
309c22bd47dSdrh /*
310d1d9fc33Sdrh ** A structure into which to accumulate text.
311d1d9fc33Sdrh */
312d1d9fc33Sdrh struct dstr {
313d1d9fc33Sdrh   int nAlloc;  /* Space allocated */
314d1d9fc33Sdrh   int nUsed;   /* Space used */
315d1d9fc33Sdrh   char *z;     /* The space */
316d1d9fc33Sdrh };
317d1d9fc33Sdrh 
318d1d9fc33Sdrh /*
319d1d9fc33Sdrh ** Append text to a dstr
320d1d9fc33Sdrh */
321d1d9fc33Sdrh static void dstrAppend(struct dstr *p, const char *z, int divider){
322d1d9fc33Sdrh   int n = strlen(z);
323d1d9fc33Sdrh   if( p->nUsed + n + 2 > p->nAlloc ){
324d1d9fc33Sdrh     char *zNew;
325d1d9fc33Sdrh     p->nAlloc = p->nAlloc*2 + n + 200;
326d1d9fc33Sdrh     zNew = sqliteRealloc(p->z, p->nAlloc);
327d1d9fc33Sdrh     if( zNew==0 ){
328d1d9fc33Sdrh       sqliteFree(p->z);
329d1d9fc33Sdrh       memset(p, 0, sizeof(*p));
330d1d9fc33Sdrh       return;
331d1d9fc33Sdrh     }
332d1d9fc33Sdrh     p->z = zNew;
333d1d9fc33Sdrh   }
334d1d9fc33Sdrh   if( divider && p->nUsed>0 ){
335d1d9fc33Sdrh     p->z[p->nUsed++] = divider;
336d1d9fc33Sdrh   }
337d1d9fc33Sdrh   memcpy(&p->z[p->nUsed], z, n+1);
338d1d9fc33Sdrh   p->nUsed += n;
339d1d9fc33Sdrh }
340d1d9fc33Sdrh 
341d1d9fc33Sdrh /*
3424adee20fSdanielk1977 ** Invoked for each callback from sqlite3ExecFunc
343d1d9fc33Sdrh */
344d1d9fc33Sdrh static int execFuncCallback(void *pData, int argc, char **argv, char **NotUsed){
345d1d9fc33Sdrh   struct dstr *p = (struct dstr*)pData;
346d1d9fc33Sdrh   int i;
347d1d9fc33Sdrh   for(i=0; i<argc; i++){
348d1d9fc33Sdrh     if( argv[i]==0 ){
349d1d9fc33Sdrh       dstrAppend(p, "NULL", ' ');
350d1d9fc33Sdrh     }else{
351d1d9fc33Sdrh       dstrAppend(p, argv[i], ' ');
352d1d9fc33Sdrh     }
353d1d9fc33Sdrh   }
354d1d9fc33Sdrh   return 0;
355d1d9fc33Sdrh }
356d1d9fc33Sdrh 
357d1d9fc33Sdrh /*
3586f8a503dSdanielk1977 ** Implementation of the x_sqlite3_exec() function.  This function takes
359c22bd47dSdrh ** a single argument and attempts to execute that argument as SQL code.
3606cbe1f1bSdrh ** This is illegal and should set the SQLITE_MISUSE flag on the database.
361c22bd47dSdrh **
3626f8a503dSdanielk1977 ** 2004-Jan-07:  We have changed this to make it legal to call sqlite3_exec()
363d1d9fc33Sdrh ** from within a function call.
364d1d9fc33Sdrh **
365c22bd47dSdrh ** This routine simulates the effect of having two threads attempt to
366c22bd47dSdrh ** use the same database at the same time.
367c22bd47dSdrh */
36851ad0ecdSdanielk1977 static void sqlite3ExecFunc(
3690ae8b831Sdanielk1977   sqlite3_context *context,
37051ad0ecdSdanielk1977   int argc,
37151ad0ecdSdanielk1977   sqlite3_value **argv
37251ad0ecdSdanielk1977 ){
373d1d9fc33Sdrh   struct dstr x;
374d1d9fc33Sdrh   memset(&x, 0, sizeof(x));
37551ad0ecdSdanielk1977   sqlite3_exec((sqlite*)sqlite3_user_data(context),
37651ad0ecdSdanielk1977       sqlite3_value_data(argv[0]),
377d1d9fc33Sdrh       execFuncCallback, &x, 0);
3787e18c259Sdanielk1977   sqlite3_result_text(context, x.z, x.nUsed, 1);
379d1d9fc33Sdrh   sqliteFree(x.z);
380c22bd47dSdrh }
381c22bd47dSdrh 
382c22bd47dSdrh /*
383c22bd47dSdrh ** Usage:  sqlite_test_create_function DB
384c22bd47dSdrh **
3856f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order
386c22bd47dSdrh ** to create a function named "x_coalesce".  This function does the same thing
387c22bd47dSdrh ** as the "coalesce" function.  This function also registers an SQL function
3886f8a503dSdanielk1977 ** named "x_sqlite3_exec" that invokes sqlite3_exec().  Invoking sqlite3_exec()
389c22bd47dSdrh ** in this way is illegal recursion and should raise an SQLITE_MISUSE error.
390c22bd47dSdrh ** The effect is similar to trying to use the same database connection from
391c22bd47dSdrh ** two threads at the same time.
392c22bd47dSdrh **
393c22bd47dSdrh ** The original motivation for this routine was to be able to call the
3946f8a503dSdanielk1977 ** sqlite3_create_function function while a query is in progress in order
395c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
396c22bd47dSdrh */
397c2eef3b3Sdrh static int test_create_function(
398c22bd47dSdrh   void *NotUsed,
399c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
400c22bd47dSdrh   int argc,              /* Number of arguments */
401c22bd47dSdrh   char **argv            /* Text of each argument */
402c22bd47dSdrh ){
403c22bd47dSdrh   sqlite *db;
404c22bd47dSdrh   extern void Md5_Register(sqlite*);
405c22bd47dSdrh   if( argc!=2 ){
406c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
407c22bd47dSdrh        " FILENAME\"", 0);
408c22bd47dSdrh     return TCL_ERROR;
409c22bd47dSdrh   }
410b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
411*6590493dSdanielk1977   sqlite3_create_function(db, "x_coalesce", -1, 0, 0, 0, ifnullFunc, 0, 0);
412*6590493dSdanielk1977   sqlite3_create_function(db, "x_sqlite3_exec", 1, 0, 0, db,
413*6590493dSdanielk1977       sqlite3ExecFunc, 0, 0);
414c22bd47dSdrh   return TCL_OK;
415c22bd47dSdrh }
416c22bd47dSdrh 
417c22bd47dSdrh /*
418c22bd47dSdrh ** Routines to implement the x_count() aggregate function.
419c22bd47dSdrh */
420c22bd47dSdrh typedef struct CountCtx CountCtx;
421c22bd47dSdrh struct CountCtx {
422c22bd47dSdrh   int n;
423c22bd47dSdrh };
4240ae8b831Sdanielk1977 static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
425c22bd47dSdrh   CountCtx *p;
4260ae8b831Sdanielk1977   p = sqlite3_get_context(context, sizeof(*p));
4276ddcca55Sdanielk1977   if( (argc==0 || SQLITE3_NULL!=sqlite3_value_type(argv[0]) ) && p ){
428c22bd47dSdrh     p->n++;
429c22bd47dSdrh   }
430c22bd47dSdrh }
4310ae8b831Sdanielk1977 static void countFinalize(sqlite3_context *context){
432c22bd47dSdrh   CountCtx *p;
4330ae8b831Sdanielk1977   p = sqlite3_get_context(context, sizeof(*p));
4347e18c259Sdanielk1977   sqlite3_result_int32(context, p ? p->n : 0);
435c22bd47dSdrh }
436c22bd47dSdrh 
437c22bd47dSdrh /*
438c22bd47dSdrh ** Usage:  sqlite_test_create_aggregate DB
439c22bd47dSdrh **
4406f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order
441c22bd47dSdrh ** to create a function named "x_count".  This function does the same thing
442c22bd47dSdrh ** as the "md5sum" function.
443c22bd47dSdrh **
444c22bd47dSdrh ** The original motivation for this routine was to be able to call the
4456f8a503dSdanielk1977 ** sqlite3_create_aggregate function while a query is in progress in order
446c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
447c22bd47dSdrh */
448c2eef3b3Sdrh static int test_create_aggregate(
449c22bd47dSdrh   void *NotUsed,
450c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
451c22bd47dSdrh   int argc,              /* Number of arguments */
452c22bd47dSdrh   char **argv            /* Text of each argument */
453c22bd47dSdrh ){
454c22bd47dSdrh   sqlite *db;
455c22bd47dSdrh   if( argc!=2 ){
456c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
457c22bd47dSdrh        " FILENAME\"", 0);
458c22bd47dSdrh     return TCL_ERROR;
459c22bd47dSdrh   }
460b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
461*6590493dSdanielk1977   sqlite3_create_function(db, "x_count", 0, 0, 0, 0, 0,countStep,countFinalize);
462*6590493dSdanielk1977   sqlite3_create_function(db, "x_count", 1, 0, 0, 0, 0,countStep,countFinalize);
463c22bd47dSdrh   return TCL_OK;
464c22bd47dSdrh }
465c22bd47dSdrh 
466c22bd47dSdrh 
467c22bd47dSdrh 
468c22bd47dSdrh /*
4696f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER
470d1bf3512Sdrh **
471d1bf3512Sdrh ** Call mprintf with three integer arguments
472d1bf3512Sdrh */
4736f8a503dSdanielk1977 static int sqlite3_mprintf_int(
474d1bf3512Sdrh   void *NotUsed,
475d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
476d1bf3512Sdrh   int argc,              /* Number of arguments */
477d1bf3512Sdrh   char **argv            /* Text of each argument */
478d1bf3512Sdrh ){
479d1bf3512Sdrh   int a[3], i;
480d1bf3512Sdrh   char *z;
481d1bf3512Sdrh   if( argc!=5 ){
482d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
483d1bf3512Sdrh        " FORMAT INT INT INT\"", 0);
484d1bf3512Sdrh     return TCL_ERROR;
485d1bf3512Sdrh   }
486d1bf3512Sdrh   for(i=2; i<5; i++){
487d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
488d1bf3512Sdrh   }
4896f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]);
490d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
4916f8a503dSdanielk1977   sqlite3_freemem(z);
492d1bf3512Sdrh   return TCL_OK;
493d1bf3512Sdrh }
494d1bf3512Sdrh 
495d1bf3512Sdrh /*
4966f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT INTEGER INTEGER STRING
497d1bf3512Sdrh **
498d1bf3512Sdrh ** Call mprintf with two integer arguments and one string argument
499d1bf3512Sdrh */
5006f8a503dSdanielk1977 static int sqlite3_mprintf_str(
501d1bf3512Sdrh   void *NotUsed,
502d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
503d1bf3512Sdrh   int argc,              /* Number of arguments */
504d1bf3512Sdrh   char **argv            /* Text of each argument */
505d1bf3512Sdrh ){
506d1bf3512Sdrh   int a[3], i;
507d1bf3512Sdrh   char *z;
508f220b24fSchw   if( argc<4 || argc>5 ){
509d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
510f220b24fSchw        " FORMAT INT INT ?STRING?\"", 0);
511d1bf3512Sdrh     return TCL_ERROR;
512d1bf3512Sdrh   }
513d1bf3512Sdrh   for(i=2; i<4; i++){
514d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
515d1bf3512Sdrh   }
5166f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL);
517d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
5186f8a503dSdanielk1977   sqlite3_freemem(z);
519d1bf3512Sdrh   return TCL_OK;
520d1bf3512Sdrh }
521d1bf3512Sdrh 
522d1bf3512Sdrh /*
5236f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT INTEGER INTEGER DOUBLE
524d1bf3512Sdrh **
525d1bf3512Sdrh ** Call mprintf with two integer arguments and one double argument
526d1bf3512Sdrh */
5276f8a503dSdanielk1977 static int sqlite3_mprintf_double(
528d1bf3512Sdrh   void *NotUsed,
529d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
530d1bf3512Sdrh   int argc,              /* Number of arguments */
531d1bf3512Sdrh   char **argv            /* Text of each argument */
532d1bf3512Sdrh ){
533d1bf3512Sdrh   int a[3], i;
534d1bf3512Sdrh   double r;
535d1bf3512Sdrh   char *z;
536d1bf3512Sdrh   if( argc!=5 ){
537d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
538d1bf3512Sdrh        " FORMAT INT INT STRING\"", 0);
539d1bf3512Sdrh     return TCL_ERROR;
540d1bf3512Sdrh   }
541d1bf3512Sdrh   for(i=2; i<4; i++){
542d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
543d1bf3512Sdrh   }
544d1bf3512Sdrh   if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR;
5456f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], r);
546d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
5476f8a503dSdanielk1977   sqlite3_freemem(z);
548d1bf3512Sdrh   return TCL_OK;
549d1bf3512Sdrh }
550d1bf3512Sdrh 
551d1bf3512Sdrh /*
5526f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT DOUBLE DOUBLE
553b621c237Sdrh **
554b621c237Sdrh ** Call mprintf with a single double argument which is the product of the
555b621c237Sdrh ** two arguments given above.  This is used to generate overflow and underflow
556b621c237Sdrh ** doubles to test that they are converted properly.
557b621c237Sdrh */
5586f8a503dSdanielk1977 static int sqlite3_mprintf_scaled(
559b621c237Sdrh   void *NotUsed,
560b621c237Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
561b621c237Sdrh   int argc,              /* Number of arguments */
562b621c237Sdrh   char **argv            /* Text of each argument */
563b621c237Sdrh ){
564b621c237Sdrh   int i;
565b621c237Sdrh   double r[2];
566b621c237Sdrh   char *z;
567b621c237Sdrh   if( argc!=4 ){
568b621c237Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
569b621c237Sdrh        " FORMAT DOUBLE DOUBLE\"", 0);
570b621c237Sdrh     return TCL_ERROR;
571b621c237Sdrh   }
572b621c237Sdrh   for(i=2; i<4; i++){
573b621c237Sdrh     if( Tcl_GetDouble(interp, argv[i], &r[i-2]) ) return TCL_ERROR;
574b621c237Sdrh   }
5756f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], r[0]*r[1]);
576b621c237Sdrh   Tcl_AppendResult(interp, z, 0);
5776f8a503dSdanielk1977   sqlite3_freemem(z);
578b621c237Sdrh   return TCL_OK;
579b621c237Sdrh }
580b621c237Sdrh 
581b621c237Sdrh /*
582daffd0e5Sdrh ** Usage: sqlite_malloc_fail N
583daffd0e5Sdrh **
584afa4a020Sdrh ** Rig sqliteMalloc() to fail on the N-th call.  Turn off this mechanism
5856f8a503dSdanielk1977 ** and reset the sqlite3_malloc_failed variable is N==0.
586daffd0e5Sdrh */
587daffd0e5Sdrh #ifdef MEMORY_DEBUG
588daffd0e5Sdrh static int sqlite_malloc_fail(
589daffd0e5Sdrh   void *NotUsed,
590daffd0e5Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
591daffd0e5Sdrh   int argc,              /* Number of arguments */
592daffd0e5Sdrh   char **argv            /* Text of each argument */
593daffd0e5Sdrh ){
594daffd0e5Sdrh   int n;
595daffd0e5Sdrh   if( argc!=2 ){
596daffd0e5Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0);
597daffd0e5Sdrh     return TCL_ERROR;
598daffd0e5Sdrh   }
599daffd0e5Sdrh   if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
6006f8a503dSdanielk1977   sqlite3_iMallocFail = n;
6016f8a503dSdanielk1977   sqlite3_malloc_failed = 0;
602daffd0e5Sdrh   return TCL_OK;
603daffd0e5Sdrh }
604daffd0e5Sdrh #endif
605daffd0e5Sdrh 
606daffd0e5Sdrh /*
607daffd0e5Sdrh ** Usage: sqlite_malloc_stat
608daffd0e5Sdrh **
609daffd0e5Sdrh ** Return the number of prior calls to sqliteMalloc() and sqliteFree().
610daffd0e5Sdrh */
611daffd0e5Sdrh #ifdef MEMORY_DEBUG
612daffd0e5Sdrh static int sqlite_malloc_stat(
613daffd0e5Sdrh   void *NotUsed,
614daffd0e5Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
615daffd0e5Sdrh   int argc,              /* Number of arguments */
616daffd0e5Sdrh   char **argv            /* Text of each argument */
617daffd0e5Sdrh ){
618daffd0e5Sdrh   char zBuf[200];
6196f8a503dSdanielk1977   sprintf(zBuf, "%d %d %d", sqlite3_nMalloc, sqlite3_nFree, sqlite3_iMallocFail);
620daffd0e5Sdrh   Tcl_AppendResult(interp, zBuf, 0);
621daffd0e5Sdrh   return TCL_OK;
622daffd0e5Sdrh }
623daffd0e5Sdrh #endif
624daffd0e5Sdrh 
625daffd0e5Sdrh /*
62628b4e489Sdrh ** Usage:  sqlite_abort
62728b4e489Sdrh **
62828b4e489Sdrh ** Shutdown the process immediately.  This is not a clean shutdown.
62928b4e489Sdrh ** This command is used to test the recoverability of a database in
63028b4e489Sdrh ** the event of a program crash.
63128b4e489Sdrh */
63228b4e489Sdrh static int sqlite_abort(
63328b4e489Sdrh   void *NotUsed,
63428b4e489Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
63528b4e489Sdrh   int argc,              /* Number of arguments */
63628b4e489Sdrh   char **argv            /* Text of each argument */
63728b4e489Sdrh ){
63828b4e489Sdrh   assert( interp==0 );   /* This will always fail */
63928b4e489Sdrh   return TCL_OK;
64028b4e489Sdrh }
64128b4e489Sdrh 
64228b4e489Sdrh /*
6436cbe1f1bSdrh ** The following routine is a user-defined SQL function whose purpose
6446cbe1f1bSdrh ** is to test the sqlite_set_result() API.
6456cbe1f1bSdrh */
6460ae8b831Sdanielk1977 static void testFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
6476cbe1f1bSdrh   while( argc>=2 ){
64851ad0ecdSdanielk1977     const char *zArg0 = sqlite3_value_data(argv[0]);
64951ad0ecdSdanielk1977     const char *zArg1 = sqlite3_value_data(argv[1]);
65051ad0ecdSdanielk1977     if( zArg0==0 ){
6517e18c259Sdanielk1977       sqlite3_result_error(context, "first argument to test function "
6526cbe1f1bSdrh          "may not be NULL", -1);
65351ad0ecdSdanielk1977     }else if( sqlite3StrICmp(zArg0,"string")==0 ){
6547e18c259Sdanielk1977       sqlite3_result_text(context, zArg1, -1, 1);
65551ad0ecdSdanielk1977     }else if( zArg1==0 ){
6567e18c259Sdanielk1977       sqlite3_result_error(context, "2nd argument may not be NULL if the "
6576cbe1f1bSdrh          "first argument is not \"string\"", -1);
65851ad0ecdSdanielk1977     }else if( sqlite3StrICmp(zArg0,"int")==0 ){
6597e18c259Sdanielk1977       sqlite3_result_int32(context, atoi(zArg1));
66051ad0ecdSdanielk1977     }else if( sqlite3StrICmp(zArg0,"double")==0 ){
6617e18c259Sdanielk1977       sqlite3_result_double(context, sqlite3AtoF(zArg1, 0));
6626cbe1f1bSdrh     }else{
6637e18c259Sdanielk1977       sqlite3_result_error(context,"first argument should be one of: "
6646cbe1f1bSdrh           "string int double", -1);
6656cbe1f1bSdrh     }
6666cbe1f1bSdrh     argc -= 2;
6676cbe1f1bSdrh     argv += 2;
6686cbe1f1bSdrh   }
6696cbe1f1bSdrh }
6706cbe1f1bSdrh 
6716cbe1f1bSdrh /*
6726cbe1f1bSdrh ** Usage:   sqlite_register_test_function  DB  NAME
6736cbe1f1bSdrh **
6746cbe1f1bSdrh ** Register the test SQL function on the database DB under the name NAME.
6756cbe1f1bSdrh */
676c2eef3b3Sdrh static int test_register_func(
6776cbe1f1bSdrh   void *NotUsed,
6786cbe1f1bSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6796cbe1f1bSdrh   int argc,              /* Number of arguments */
6806cbe1f1bSdrh   char **argv            /* Text of each argument */
6816cbe1f1bSdrh ){
6826cbe1f1bSdrh   sqlite *db;
6836cbe1f1bSdrh   int rc;
6846cbe1f1bSdrh   if( argc!=3 ){
6856cbe1f1bSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
6866cbe1f1bSdrh        " DB FUNCTION-NAME", 0);
6876cbe1f1bSdrh     return TCL_ERROR;
6886cbe1f1bSdrh   }
689b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
690*6590493dSdanielk1977   rc = sqlite3_create_function(db, argv[2], -1, 0, 0, 0, testFunc, 0, 0);
6916cbe1f1bSdrh   if( rc!=0 ){
6926f8a503dSdanielk1977     Tcl_AppendResult(interp, sqlite3_error_string(rc), 0);
6936cbe1f1bSdrh     return TCL_ERROR;
6946cbe1f1bSdrh   }
6956cbe1f1bSdrh   return TCL_OK;
6966cbe1f1bSdrh }
6976cbe1f1bSdrh 
6986cbe1f1bSdrh /*
6995a38705eSdrh ** This SQLite callback records the datatype of all columns.
7005a38705eSdrh **
7015a38705eSdrh ** The pArg argument is really a pointer to a TCL interpreter.  The
7025a38705eSdrh ** column names are inserted as the result of this interpreter.
7035a38705eSdrh **
7045a38705eSdrh ** This routine returns non-zero which causes the query to abort.
7055a38705eSdrh */
7065a38705eSdrh static int rememberDataTypes(void *pArg, int nCol, char **argv, char **colv){
7075a38705eSdrh   int i;
7085a38705eSdrh   Tcl_Interp *interp = (Tcl_Interp*)pArg;
7095a38705eSdrh   Tcl_Obj *pList, *pElem;
7105a38705eSdrh   if( colv[nCol+1]==0 ){
7115a38705eSdrh     return 1;
7125a38705eSdrh   }
7135a38705eSdrh   pList = Tcl_NewObj();
7145a38705eSdrh   for(i=0; i<nCol; i++){
7155a38705eSdrh     pElem = Tcl_NewStringObj(colv[i+nCol] ? colv[i+nCol] : "NULL", -1);
7165a38705eSdrh     Tcl_ListObjAppendElement(interp, pList, pElem);
7175a38705eSdrh   }
7185a38705eSdrh   Tcl_SetObjResult(interp, pList);
7195a38705eSdrh   return 1;
7205a38705eSdrh }
7215a38705eSdrh 
7225a38705eSdrh /*
7235a38705eSdrh ** Invoke an SQL statement but ignore all the data in the result.  Instead,
7245a38705eSdrh ** return a list that consists of the datatypes of the various columns.
7255a38705eSdrh **
7265a38705eSdrh ** This only works if "PRAGMA show_datatypes=on" has been executed against
7275a38705eSdrh ** the database connection.
7285a38705eSdrh */
7295a38705eSdrh static int sqlite_datatypes(
7305a38705eSdrh   void *NotUsed,
7315a38705eSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
7325a38705eSdrh   int argc,              /* Number of arguments */
7335a38705eSdrh   char **argv            /* Text of each argument */
7345a38705eSdrh ){
7355a38705eSdrh   sqlite *db;
7365a38705eSdrh   int rc;
7375a38705eSdrh   if( argc!=3 ){
7385a38705eSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
7395a38705eSdrh        " DB SQL", 0);
7405a38705eSdrh     return TCL_ERROR;
7415a38705eSdrh   }
742b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
7436f8a503dSdanielk1977   rc = sqlite3_exec(db, argv[2], rememberDataTypes, interp, 0);
7445a38705eSdrh   if( rc!=0 && rc!=SQLITE_ABORT ){
7456f8a503dSdanielk1977     Tcl_AppendResult(interp, sqlite3_error_string(rc), 0);
7465a38705eSdrh     return TCL_ERROR;
7475a38705eSdrh   }
7485a38705eSdrh   return TCL_OK;
7495a38705eSdrh }
7505a38705eSdrh 
751b86ccfb2Sdrh /*
752106bb236Sdanielk1977 ** Usage:  sqlite3_finalize  STMT
753b86ccfb2Sdrh **
754106bb236Sdanielk1977 ** Finalize a statement handle.
755b86ccfb2Sdrh */
756b86ccfb2Sdrh static int test_finalize(
757106bb236Sdanielk1977   void * clientData,
758106bb236Sdanielk1977   Tcl_Interp *interp,
759106bb236Sdanielk1977   int objc,
760106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
761b86ccfb2Sdrh ){
762106bb236Sdanielk1977   sqlite3_stmt *pStmt;
763b86ccfb2Sdrh   int rc;
764106bb236Sdanielk1977 
765106bb236Sdanielk1977   if( objc!=2 ){
766106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
767106bb236Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
768b86ccfb2Sdrh     return TCL_ERROR;
769b86ccfb2Sdrh   }
770106bb236Sdanielk1977 
771106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
772106bb236Sdanielk1977 
773fc57d7bfSdanielk1977   rc = sqlite3_finalize(pStmt);
774b86ccfb2Sdrh   if( rc ){
775106bb236Sdanielk1977     return TCL_ERROR;
776106bb236Sdanielk1977   }
777106bb236Sdanielk1977   return TCL_OK;
778106bb236Sdanielk1977 }
779106bb236Sdanielk1977 
780106bb236Sdanielk1977 /*
781106bb236Sdanielk1977 ** Usage:  sqlite3_reset  STMT
782106bb236Sdanielk1977 **
783106bb236Sdanielk1977 ** Finalize a statement handle.
784106bb236Sdanielk1977 */
785106bb236Sdanielk1977 static int test_reset(
786106bb236Sdanielk1977   void * clientData,
787106bb236Sdanielk1977   Tcl_Interp *interp,
788106bb236Sdanielk1977   int objc,
789106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
790106bb236Sdanielk1977 ){
791106bb236Sdanielk1977   sqlite3_stmt *pStmt;
792106bb236Sdanielk1977   int rc;
793106bb236Sdanielk1977 
794106bb236Sdanielk1977   if( objc!=2 ){
795106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
796106bb236Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
797106bb236Sdanielk1977     return TCL_ERROR;
798106bb236Sdanielk1977   }
799106bb236Sdanielk1977 
800106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
801106bb236Sdanielk1977 
802fc57d7bfSdanielk1977   rc = sqlite3_reset(pStmt);
803106bb236Sdanielk1977   if( rc ){
804b86ccfb2Sdrh     return TCL_ERROR;
805b86ccfb2Sdrh   }
806b86ccfb2Sdrh   return TCL_OK;
807b86ccfb2Sdrh }
808b86ccfb2Sdrh 
8095a38705eSdrh /*
8106f8a503dSdanielk1977 ** Usage:  sqlite3_reset   VM
81150457896Sdrh **
81250457896Sdrh ** Reset a virtual machine and prepare it to be run again.
81350457896Sdrh */
81450457896Sdrh 
81550457896Sdrh /*
8167c972decSdrh ** This is the "static_bind_value" that variables are bound to when
8176f8a503dSdanielk1977 ** the FLAG option of sqlite3_bind is "static"
81850457896Sdrh */
8197c972decSdrh static char *sqlite_static_bind_value = 0;
8207c972decSdrh 
8217c972decSdrh /*
8226f8a503dSdanielk1977 ** Usage:  sqlite3_bind  VM  IDX  VALUE  FLAGS
8237c972decSdrh **
8247c972decSdrh ** Sets the value of the IDX-th occurance of "?" in the original SQL
8257c972decSdrh ** string.  VALUE is the new value.  If FLAGS=="null" then VALUE is
8267c972decSdrh ** ignored and the value is set to NULL.  If FLAGS=="static" then
8277c972decSdrh ** the value is set to the value of a static variable named
8287c972decSdrh ** "sqlite_static_bind_value".  If FLAGS=="normal" then a copy
8297c972decSdrh ** of the VALUE is made.
8307c972decSdrh */
8317c972decSdrh static int test_bind(
83250457896Sdrh   void *NotUsed,
83350457896Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
83450457896Sdrh   int argc,              /* Number of arguments */
83550457896Sdrh   char **argv            /* Text of each argument */
83650457896Sdrh ){
837fc57d7bfSdanielk1977   sqlite3_stmt *pStmt;
83850457896Sdrh   int rc;
8397c972decSdrh   int idx;
8407c972decSdrh   if( argc!=5 ){
84150457896Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
8427c972decSdrh        " VM IDX VALUE (null|static|normal)\"", 0);
84350457896Sdrh     return TCL_ERROR;
84450457896Sdrh   }
845fc57d7bfSdanielk1977   if( getStmtPointer(interp, argv[1], &pStmt) ) return TCL_ERROR;
8467c972decSdrh   if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR;
8477c972decSdrh   if( strcmp(argv[4],"null")==0 ){
848fc57d7bfSdanielk1977     rc = sqlite3_bind_null(pStmt, idx);
8497c972decSdrh   }else if( strcmp(argv[4],"static")==0 ){
850fc57d7bfSdanielk1977     rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0);
8517c972decSdrh   }else if( strcmp(argv[4],"normal")==0 ){
852fc57d7bfSdanielk1977     rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, 1);
8537c972decSdrh   }else{
8547c972decSdrh     Tcl_AppendResult(interp, "4th argument should be "
8557c972decSdrh         "\"null\" or \"static\" or \"normal\"", 0);
8567c972decSdrh     return TCL_ERROR;
8577c972decSdrh   }
85850457896Sdrh   if( rc ){
85950457896Sdrh     char zBuf[50];
86050457896Sdrh     sprintf(zBuf, "(%d) ", rc);
8616f8a503dSdanielk1977     Tcl_AppendResult(interp, zBuf, sqlite3_error_string(rc), 0);
86250457896Sdrh     return TCL_ERROR;
86350457896Sdrh   }
86450457896Sdrh   return TCL_OK;
86550457896Sdrh }
86650457896Sdrh 
86750457896Sdrh /*
86899ee3600Sdrh ** Usage:    breakpoint
86999ee3600Sdrh **
87099ee3600Sdrh ** This routine exists for one purpose - to provide a place to put a
87199ee3600Sdrh ** breakpoint with GDB that can be triggered using TCL code.  The use
87299ee3600Sdrh ** for this is when a particular test fails on (say) the 1485th iteration.
87399ee3600Sdrh ** In the TCL test script, we can add code like this:
87499ee3600Sdrh **
87599ee3600Sdrh **     if {$i==1485} breakpoint
87699ee3600Sdrh **
87799ee3600Sdrh ** Then run testfixture in the debugger and wait for the breakpoint to
87899ee3600Sdrh ** fire.  Then additional breakpoints can be set to trace down the bug.
87999ee3600Sdrh */
88099ee3600Sdrh static int test_breakpoint(
88199ee3600Sdrh   void *NotUsed,
88299ee3600Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
88399ee3600Sdrh   int argc,              /* Number of arguments */
88499ee3600Sdrh   char **argv            /* Text of each argument */
88599ee3600Sdrh ){
88699ee3600Sdrh   return TCL_OK;         /* Do nothing */
88799ee3600Sdrh }
88899ee3600Sdrh 
88951e3d8e2Sdanielk1977 static int test_bind_int32(
89051e3d8e2Sdanielk1977   void * clientData,
89151e3d8e2Sdanielk1977   Tcl_Interp *interp,
89251e3d8e2Sdanielk1977   int objc,
89351e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
89451e3d8e2Sdanielk1977 ){
89551e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
89651e3d8e2Sdanielk1977   int idx;
89751e3d8e2Sdanielk1977   int value;
89851e3d8e2Sdanielk1977   int rc;
89951e3d8e2Sdanielk1977 
90051e3d8e2Sdanielk1977   if( objc!=4 ){
90151e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
90251e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
90351e3d8e2Sdanielk1977     return TCL_ERROR;
90451e3d8e2Sdanielk1977   }
90551e3d8e2Sdanielk1977 
90651e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
90751e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
90851e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &value) ) return TCL_ERROR;
90951e3d8e2Sdanielk1977 
91051e3d8e2Sdanielk1977   rc = sqlite3_bind_int32(pStmt, idx, value);
91151e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
91251e3d8e2Sdanielk1977     return TCL_ERROR;
91351e3d8e2Sdanielk1977   }
91451e3d8e2Sdanielk1977 
91551e3d8e2Sdanielk1977   return TCL_OK;
91651e3d8e2Sdanielk1977 }
91751e3d8e2Sdanielk1977 
91851e3d8e2Sdanielk1977 static int test_bind_int64(
91951e3d8e2Sdanielk1977   void * clientData,
92051e3d8e2Sdanielk1977   Tcl_Interp *interp,
92151e3d8e2Sdanielk1977   int objc,
92251e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
92351e3d8e2Sdanielk1977 ){
92451e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
92551e3d8e2Sdanielk1977   int idx;
92651e3d8e2Sdanielk1977   i64 value;
92751e3d8e2Sdanielk1977   int rc;
92851e3d8e2Sdanielk1977 
92951e3d8e2Sdanielk1977   if( objc!=4 ){
93051e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
93151e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
93251e3d8e2Sdanielk1977     return TCL_ERROR;
93351e3d8e2Sdanielk1977   }
93451e3d8e2Sdanielk1977 
93551e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
93651e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
93751e3d8e2Sdanielk1977   if( Tcl_GetWideIntFromObj(interp, objv[3], &value) ) return TCL_ERROR;
93851e3d8e2Sdanielk1977 
93951e3d8e2Sdanielk1977   rc = sqlite3_bind_int64(pStmt, idx, value);
94051e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
94151e3d8e2Sdanielk1977     return TCL_ERROR;
94251e3d8e2Sdanielk1977   }
94351e3d8e2Sdanielk1977 
94451e3d8e2Sdanielk1977   return TCL_OK;
94551e3d8e2Sdanielk1977 }
94651e3d8e2Sdanielk1977 
94751e3d8e2Sdanielk1977 static int test_bind_double(
94851e3d8e2Sdanielk1977   void * clientData,
94951e3d8e2Sdanielk1977   Tcl_Interp *interp,
95051e3d8e2Sdanielk1977   int objc,
95151e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
95251e3d8e2Sdanielk1977 ){
95351e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
95451e3d8e2Sdanielk1977   int idx;
95551e3d8e2Sdanielk1977   double value;
95651e3d8e2Sdanielk1977   int rc;
95751e3d8e2Sdanielk1977 
95851e3d8e2Sdanielk1977   if( objc!=4 ){
95951e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
96051e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
96151e3d8e2Sdanielk1977     return TCL_ERROR;
96251e3d8e2Sdanielk1977   }
96351e3d8e2Sdanielk1977 
96451e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
96551e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
96651e3d8e2Sdanielk1977   if( Tcl_GetDoubleFromObj(interp, objv[3], &value) ) return TCL_ERROR;
96751e3d8e2Sdanielk1977 
96851e3d8e2Sdanielk1977   rc = sqlite3_bind_double(pStmt, idx, value);
96951e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
97051e3d8e2Sdanielk1977     return TCL_ERROR;
97151e3d8e2Sdanielk1977   }
97251e3d8e2Sdanielk1977 
97351e3d8e2Sdanielk1977   return TCL_OK;
97451e3d8e2Sdanielk1977 }
97551e3d8e2Sdanielk1977 
97651e3d8e2Sdanielk1977 static int test_bind_null(
97751e3d8e2Sdanielk1977   void * clientData,
97851e3d8e2Sdanielk1977   Tcl_Interp *interp,
97951e3d8e2Sdanielk1977   int objc,
98051e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
98151e3d8e2Sdanielk1977 ){
98251e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
98351e3d8e2Sdanielk1977   int idx;
98451e3d8e2Sdanielk1977   int rc;
98551e3d8e2Sdanielk1977 
98651e3d8e2Sdanielk1977   if( objc!=3 ){
98751e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
98851e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.>", 0);
98951e3d8e2Sdanielk1977     return TCL_ERROR;
99051e3d8e2Sdanielk1977   }
99151e3d8e2Sdanielk1977 
99251e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
99351e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
99451e3d8e2Sdanielk1977 
99551e3d8e2Sdanielk1977   rc = sqlite3_bind_null(pStmt, idx);
99651e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
99751e3d8e2Sdanielk1977     return TCL_ERROR;
99851e3d8e2Sdanielk1977   }
99951e3d8e2Sdanielk1977 
100051e3d8e2Sdanielk1977   return TCL_OK;
100151e3d8e2Sdanielk1977 }
100251e3d8e2Sdanielk1977 
100351e3d8e2Sdanielk1977 static int test_bind_text(
100451e3d8e2Sdanielk1977   void * clientData,
100551e3d8e2Sdanielk1977   Tcl_Interp *interp,
100651e3d8e2Sdanielk1977   int objc,
100751e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
100851e3d8e2Sdanielk1977 ){
100951e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
101051e3d8e2Sdanielk1977   int idx;
101151e3d8e2Sdanielk1977   int bytes;
101251e3d8e2Sdanielk1977   char *value;
101351e3d8e2Sdanielk1977   int rc;
101451e3d8e2Sdanielk1977 
101551e3d8e2Sdanielk1977   if( objc!=5 ){
101651e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
101751e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
101851e3d8e2Sdanielk1977         " <bytes>", 0);
101951e3d8e2Sdanielk1977     return TCL_ERROR;
102051e3d8e2Sdanielk1977   }
102151e3d8e2Sdanielk1977 
102251e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
102351e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
102451e3d8e2Sdanielk1977   value = Tcl_GetString(objv[3]);
102551e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
102651e3d8e2Sdanielk1977 
102751e3d8e2Sdanielk1977   rc = sqlite3_bind_text(pStmt, idx, value, bytes, 1);
102851e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
102951e3d8e2Sdanielk1977     return TCL_ERROR;
103051e3d8e2Sdanielk1977   }
103151e3d8e2Sdanielk1977 
103251e3d8e2Sdanielk1977   return TCL_OK;
103351e3d8e2Sdanielk1977 }
103451e3d8e2Sdanielk1977 
103551e3d8e2Sdanielk1977 static int test_bind_text16(
103651e3d8e2Sdanielk1977   void * clientData,
103751e3d8e2Sdanielk1977   Tcl_Interp *interp,
103851e3d8e2Sdanielk1977   int objc,
103951e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
104051e3d8e2Sdanielk1977 ){
104151e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
104251e3d8e2Sdanielk1977   int idx;
104351e3d8e2Sdanielk1977   int bytes;
104451e3d8e2Sdanielk1977   char *value;
104551e3d8e2Sdanielk1977   int rc;
104651e3d8e2Sdanielk1977 
104751e3d8e2Sdanielk1977   if( objc!=5 ){
104851e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
104951e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
105051e3d8e2Sdanielk1977         " <bytes>", 0);
105151e3d8e2Sdanielk1977     return TCL_ERROR;
105251e3d8e2Sdanielk1977   }
105351e3d8e2Sdanielk1977 
105451e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
105551e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
105651e3d8e2Sdanielk1977   value = Tcl_GetByteArrayFromObj(objv[3], 0);
105751e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
105851e3d8e2Sdanielk1977 
105951e3d8e2Sdanielk1977   rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, 1);
106051e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
106151e3d8e2Sdanielk1977     return TCL_ERROR;
106251e3d8e2Sdanielk1977   }
106351e3d8e2Sdanielk1977 
106451e3d8e2Sdanielk1977   return TCL_OK;
106551e3d8e2Sdanielk1977 }
106651e3d8e2Sdanielk1977 
106751e3d8e2Sdanielk1977 static int test_bind_blob(
106851e3d8e2Sdanielk1977   void * clientData,
106951e3d8e2Sdanielk1977   Tcl_Interp *interp,
107051e3d8e2Sdanielk1977   int objc,
107151e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
107251e3d8e2Sdanielk1977 ){
107351e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
107451e3d8e2Sdanielk1977   int idx;
107551e3d8e2Sdanielk1977   int bytes;
107651e3d8e2Sdanielk1977   char *value;
107751e3d8e2Sdanielk1977   int rc;
107851e3d8e2Sdanielk1977 
107951e3d8e2Sdanielk1977   if( objc!=5 ){
108051e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
108151e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
108251e3d8e2Sdanielk1977         " <bytes>", 0);
108351e3d8e2Sdanielk1977     return TCL_ERROR;
108451e3d8e2Sdanielk1977   }
108551e3d8e2Sdanielk1977 
108651e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
108751e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
108851e3d8e2Sdanielk1977   value = Tcl_GetString(objv[3]);
108951e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &bytes) ) return TCL_ERROR;
109051e3d8e2Sdanielk1977 
109151e3d8e2Sdanielk1977   rc = sqlite3_bind_blob(pStmt, idx, value, bytes, 1);
109251e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
109351e3d8e2Sdanielk1977     return TCL_ERROR;
109451e3d8e2Sdanielk1977   }
109551e3d8e2Sdanielk1977 
109651e3d8e2Sdanielk1977   return TCL_OK;
109751e3d8e2Sdanielk1977 }
109851e3d8e2Sdanielk1977 
109999ee3600Sdrh /*
11006622cce3Sdanielk1977 ** Usage: sqlite3_errcode DB
11016622cce3Sdanielk1977 **
11026622cce3Sdanielk1977 ** Return the string representation of the most recent sqlite3_* API
11036622cce3Sdanielk1977 ** error code. e.g. "SQLITE_ERROR".
11046622cce3Sdanielk1977 */
11056622cce3Sdanielk1977 static int test_errcode(
11066622cce3Sdanielk1977   void * clientData,
11076622cce3Sdanielk1977   Tcl_Interp *interp,
11086622cce3Sdanielk1977   int objc,
11096622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
11106622cce3Sdanielk1977 ){
11116622cce3Sdanielk1977   sqlite3 *db;
11126622cce3Sdanielk1977 
11136622cce3Sdanielk1977   if( objc!=2 ){
11146622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
11156622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
11166622cce3Sdanielk1977     return TCL_ERROR;
11176622cce3Sdanielk1977   }
11186622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
11196622cce3Sdanielk1977   Tcl_SetResult(interp, (char *)errorName(sqlite3_errcode(db)), 0);
11206622cce3Sdanielk1977   return TCL_OK;
11216622cce3Sdanielk1977 }
11226622cce3Sdanielk1977 
11236622cce3Sdanielk1977 /*
11246622cce3Sdanielk1977 ** Usage:   test_errmsg DB
11256622cce3Sdanielk1977 **
11266622cce3Sdanielk1977 ** Returns the UTF-8 representation of the error message string for the
11276622cce3Sdanielk1977 ** most recent sqlite3_* API call.
11286622cce3Sdanielk1977 */
11296622cce3Sdanielk1977 static int test_errmsg(
11306622cce3Sdanielk1977   void * clientData,
11316622cce3Sdanielk1977   Tcl_Interp *interp,
11326622cce3Sdanielk1977   int objc,
11336622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
11346622cce3Sdanielk1977 ){
11356622cce3Sdanielk1977   sqlite *db;
11366622cce3Sdanielk1977   const char *zErr;
11376622cce3Sdanielk1977 
11386622cce3Sdanielk1977   if( objc!=2 ){
11396622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
11406622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
11416622cce3Sdanielk1977     return TCL_ERROR;
11426622cce3Sdanielk1977   }
11436622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
11446622cce3Sdanielk1977 
11456622cce3Sdanielk1977   zErr = sqlite3_errmsg(db);
11466622cce3Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
11476622cce3Sdanielk1977   return TCL_OK;
11486622cce3Sdanielk1977 }
11496622cce3Sdanielk1977 
11506622cce3Sdanielk1977 /*
11516622cce3Sdanielk1977 ** Usage:   test_errmsg16 DB
11526622cce3Sdanielk1977 **
11536622cce3Sdanielk1977 ** Returns the UTF-16 representation of the error message string for the
11546622cce3Sdanielk1977 ** most recent sqlite3_* API call. This is a byte array object at the TCL
11556622cce3Sdanielk1977 ** level, and it includes the 0x00 0x00 terminator bytes at the end of the
11566622cce3Sdanielk1977 ** UTF-16 string.
11576622cce3Sdanielk1977 */
11586622cce3Sdanielk1977 static int test_errmsg16(
11596622cce3Sdanielk1977   void * clientData,
11606622cce3Sdanielk1977   Tcl_Interp *interp,
11616622cce3Sdanielk1977   int objc,
11626622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
11636622cce3Sdanielk1977 ){
11646622cce3Sdanielk1977   sqlite *db;
11656622cce3Sdanielk1977   const void *zErr;
11666622cce3Sdanielk1977   int bytes;
11676622cce3Sdanielk1977 
11686622cce3Sdanielk1977   if( objc!=2 ){
11696622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
11706622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
11716622cce3Sdanielk1977     return TCL_ERROR;
11726622cce3Sdanielk1977   }
11736622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
11746622cce3Sdanielk1977 
11756622cce3Sdanielk1977   zErr = sqlite3_errmsg16(db);
11766622cce3Sdanielk1977   bytes = sqlite3utf16ByteLen(zErr, -1);
11776622cce3Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes));
11786622cce3Sdanielk1977   return TCL_OK;
11796622cce3Sdanielk1977 }
11806622cce3Sdanielk1977 
11816622cce3Sdanielk1977 /*
11826622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar
11836622cce3Sdanielk1977 **
11846622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
11856622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global
11866622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A
11876622cce3Sdanielk1977 ** STMT handle is returned.
11886622cce3Sdanielk1977 */
11896622cce3Sdanielk1977 static int test_prepare(
11906622cce3Sdanielk1977   void * clientData,
11916622cce3Sdanielk1977   Tcl_Interp *interp,
11926622cce3Sdanielk1977   int objc,
11936622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
11946622cce3Sdanielk1977 ){
11956622cce3Sdanielk1977   sqlite3 *db;
11966622cce3Sdanielk1977   const char *zSql;
11976622cce3Sdanielk1977   int bytes;
11986622cce3Sdanielk1977   const char *zTail = 0;
11996622cce3Sdanielk1977   sqlite3_stmt *pStmt = 0;
12006622cce3Sdanielk1977   char zBuf[50];
12014ad1713cSdanielk1977   int rc;
12026622cce3Sdanielk1977 
12036622cce3Sdanielk1977   if( objc!=5 ){
12046622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
12056622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
12066622cce3Sdanielk1977     return TCL_ERROR;
12076622cce3Sdanielk1977   }
12086622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
12096622cce3Sdanielk1977   zSql = Tcl_GetString(objv[2]);
12106622cce3Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
12116622cce3Sdanielk1977 
12124ad1713cSdanielk1977   rc = sqlite3_prepare(db, zSql, bytes, &pStmt, &zTail);
12136622cce3Sdanielk1977   if( zTail ){
12146622cce3Sdanielk1977     if( bytes>=0 ){
12156622cce3Sdanielk1977       bytes = bytes - (zTail-zSql);
12166622cce3Sdanielk1977     }
12176622cce3Sdanielk1977     Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
12186622cce3Sdanielk1977   }
12194ad1713cSdanielk1977   if( rc!=SQLITE_OK ){
12204ad1713cSdanielk1977     assert( pStmt==0 );
12214ad1713cSdanielk1977     sprintf(zBuf, "(%d) ", rc);
12224ad1713cSdanielk1977     Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
12234ad1713cSdanielk1977     return TCL_ERROR;
12244ad1713cSdanielk1977   }
12256622cce3Sdanielk1977 
12264ad1713cSdanielk1977   if( pStmt ){
12276622cce3Sdanielk1977     if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
12286622cce3Sdanielk1977     Tcl_AppendResult(interp, zBuf, 0);
12294ad1713cSdanielk1977   }
12306622cce3Sdanielk1977   return TCL_OK;
12316622cce3Sdanielk1977 }
12326622cce3Sdanielk1977 
12336622cce3Sdanielk1977 /*
12346622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar
12356622cce3Sdanielk1977 **
12366622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
12376622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global
12386622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A
12396622cce3Sdanielk1977 ** STMT handle is returned.
12406622cce3Sdanielk1977 */
12416622cce3Sdanielk1977 static int test_prepare16(
12426622cce3Sdanielk1977   void * clientData,
12436622cce3Sdanielk1977   Tcl_Interp *interp,
12446622cce3Sdanielk1977   int objc,
12456622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
12466622cce3Sdanielk1977 ){
12476622cce3Sdanielk1977   sqlite3 *db;
12486622cce3Sdanielk1977   const void *zSql;
12496622cce3Sdanielk1977   const void *zTail = 0;
12506622cce3Sdanielk1977   Tcl_Obj *pTail = 0;
12516622cce3Sdanielk1977   sqlite3_stmt *pStmt = 0;
12526622cce3Sdanielk1977   char zBuf[50];
12536622cce3Sdanielk1977   int bytes;                /* The integer specified as arg 3 */
12546622cce3Sdanielk1977   int objlen;               /* The byte-array length of arg 2 */
12556622cce3Sdanielk1977 
12566622cce3Sdanielk1977   if( objc!=5 ){
12576622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
12586622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
12596622cce3Sdanielk1977     return TCL_ERROR;
12606622cce3Sdanielk1977   }
12616622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
12626622cce3Sdanielk1977   zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen);
12636622cce3Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
12646622cce3Sdanielk1977 
12656622cce3Sdanielk1977   if( SQLITE_OK!=sqlite3_prepare16(db, zSql, bytes, &pStmt, &zTail) ){
12666622cce3Sdanielk1977     return TCL_ERROR;
12676622cce3Sdanielk1977   }
12686622cce3Sdanielk1977 
12696622cce3Sdanielk1977   if( zTail ){
12706622cce3Sdanielk1977     objlen = objlen - ((u8 *)zTail-(u8 *)zSql);
12716622cce3Sdanielk1977   }else{
12726622cce3Sdanielk1977     objlen = 0;
12736622cce3Sdanielk1977   }
12746622cce3Sdanielk1977   pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen);
12756622cce3Sdanielk1977   Tcl_IncrRefCount(pTail);
12766622cce3Sdanielk1977   Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0);
12774ad1713cSdanielk1977   Tcl_DecrRefCount(pTail);
12786622cce3Sdanielk1977 
12794ad1713cSdanielk1977   if( pStmt ){
12806622cce3Sdanielk1977     if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
12814ad1713cSdanielk1977   }
12826622cce3Sdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
12836622cce3Sdanielk1977   return TCL_OK;
12846622cce3Sdanielk1977 }
12856622cce3Sdanielk1977 
12864ad1713cSdanielk1977 /*
12874ad1713cSdanielk1977 ** Usage: sqlite3_open filename ?options-list?
12884ad1713cSdanielk1977 */
12894ad1713cSdanielk1977 static int test_open(
12904ad1713cSdanielk1977   void * clientData,
12914ad1713cSdanielk1977   Tcl_Interp *interp,
12924ad1713cSdanielk1977   int objc,
12934ad1713cSdanielk1977   Tcl_Obj *CONST objv[]
12944ad1713cSdanielk1977 ){
12954ad1713cSdanielk1977   const char *zFilename;
12964ad1713cSdanielk1977   sqlite3 *db;
12974ad1713cSdanielk1977   int rc;
12984ad1713cSdanielk1977   char zBuf[100];
12994ad1713cSdanielk1977 
13004ad1713cSdanielk1977   if( objc!=3 && objc!=2 ){
13014ad1713cSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
13024ad1713cSdanielk1977        Tcl_GetString(objv[0]), " filename options-list", 0);
13034ad1713cSdanielk1977     return TCL_ERROR;
13044ad1713cSdanielk1977   }
13054ad1713cSdanielk1977 
13064ad1713cSdanielk1977   zFilename = Tcl_GetString(objv[1]);
130780290863Sdanielk1977   rc = sqlite3_open(zFilename, &db, 0);
13084ad1713cSdanielk1977 
13094ad1713cSdanielk1977   if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
13104ad1713cSdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
13114ad1713cSdanielk1977   return TCL_OK;
13124ad1713cSdanielk1977 }
13134ad1713cSdanielk1977 
13144ad1713cSdanielk1977 /*
13154ad1713cSdanielk1977 ** Usage: sqlite3_open16 filename options
13164ad1713cSdanielk1977 */
13174ad1713cSdanielk1977 static int test_open16(
13184ad1713cSdanielk1977   void * clientData,
13194ad1713cSdanielk1977   Tcl_Interp *interp,
13204ad1713cSdanielk1977   int objc,
13214ad1713cSdanielk1977   Tcl_Obj *CONST objv[]
13224ad1713cSdanielk1977 ){
13234ad1713cSdanielk1977   const void *zFilename;
13244ad1713cSdanielk1977   sqlite3 *db;
13254ad1713cSdanielk1977   int rc;
13264ad1713cSdanielk1977   char zBuf[100];
13274ad1713cSdanielk1977 
13284ad1713cSdanielk1977   if( objc!=3 ){
13294ad1713cSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
13304ad1713cSdanielk1977        Tcl_GetString(objv[0]), " filename options-list", 0);
13314ad1713cSdanielk1977     return TCL_ERROR;
13324ad1713cSdanielk1977   }
13334ad1713cSdanielk1977 
13344ad1713cSdanielk1977   zFilename = Tcl_GetByteArrayFromObj(objv[1], 0);
13354ad1713cSdanielk1977   rc = sqlite3_open16(zFilename, &db, 0);
13364ad1713cSdanielk1977 
13374ad1713cSdanielk1977   if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
13384ad1713cSdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
13394ad1713cSdanielk1977   return TCL_OK;
13404ad1713cSdanielk1977 }
1341d3d39e93Sdrh 
1342d3d39e93Sdrh /*
1343106bb236Sdanielk1977 ** Usage: sqlite3_step STMT
1344106bb236Sdanielk1977 **
1345106bb236Sdanielk1977 ** Advance the statement to the next row.
1346106bb236Sdanielk1977 */
134717240fd9Sdanielk1977 static int test_step(
1348106bb236Sdanielk1977   void * clientData,
1349106bb236Sdanielk1977   Tcl_Interp *interp,
1350106bb236Sdanielk1977   int objc,
1351106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
1352106bb236Sdanielk1977 ){
1353106bb236Sdanielk1977   sqlite3_stmt *pStmt;
1354106bb236Sdanielk1977   int rc;
1355106bb236Sdanielk1977 
1356e1cd9874Sdanielk1977   if( objc!=2 ){
1357106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1358106bb236Sdanielk1977        Tcl_GetString(objv[0]), " STMT", 0);
1359106bb236Sdanielk1977     return TCL_ERROR;
1360106bb236Sdanielk1977   }
1361106bb236Sdanielk1977 
1362106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
136317240fd9Sdanielk1977   rc = sqlite3_step(pStmt);
1364106bb236Sdanielk1977 
1365e1cd9874Sdanielk1977   if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR;
1366*6590493dSdanielk1977   Tcl_SetResult(interp, (char *)errorName(rc), 0);
1367e1cd9874Sdanielk1977   return TCL_OK;
1368e1cd9874Sdanielk1977 }
1369e1cd9874Sdanielk1977 
1370e1cd9874Sdanielk1977 /*
1371e1cd9874Sdanielk1977 ** Usage: sqlite3_column_data STMT column
1372e1cd9874Sdanielk1977 **
1373e1cd9874Sdanielk1977 ** Advance the statement to the next row.
1374e1cd9874Sdanielk1977 */
1375e1cd9874Sdanielk1977 static int test_column_data(
1376e1cd9874Sdanielk1977   void * clientData,
1377e1cd9874Sdanielk1977   Tcl_Interp *interp,
1378e1cd9874Sdanielk1977   int objc,
1379e1cd9874Sdanielk1977   Tcl_Obj *CONST objv[]
1380e1cd9874Sdanielk1977 ){
1381e1cd9874Sdanielk1977   sqlite3_stmt *pStmt;
1382e1cd9874Sdanielk1977   int col;
1383e1cd9874Sdanielk1977   Tcl_Obj *pRet;
1384e1cd9874Sdanielk1977 
1385e1cd9874Sdanielk1977   if( objc!=3 ){
1386e1cd9874Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1387e1cd9874Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
1388e1cd9874Sdanielk1977     return TCL_ERROR;
1389e1cd9874Sdanielk1977   }
1390e1cd9874Sdanielk1977 
1391e1cd9874Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
1392e1cd9874Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
1393e1cd9874Sdanielk1977 
1394e1cd9874Sdanielk1977   if( SQLITE3_BLOB==sqlite3_column_type(pStmt, col) ){
1395e1cd9874Sdanielk1977     int len = sqlite3_column_bytes(pStmt, col);
1396e1cd9874Sdanielk1977     pRet = Tcl_NewByteArrayObj(sqlite3_column_data(pStmt, col), len);
1397e1cd9874Sdanielk1977   }else{
1398e1cd9874Sdanielk1977     pRet = Tcl_NewStringObj(sqlite3_column_data(pStmt, col), -1);
1399e1cd9874Sdanielk1977   }
1400e1cd9874Sdanielk1977   Tcl_SetObjResult(interp, pRet);
1401e1cd9874Sdanielk1977 
1402e1cd9874Sdanielk1977   return TCL_OK;
1403e1cd9874Sdanielk1977 }
1404e1cd9874Sdanielk1977 
1405e1cd9874Sdanielk1977 /*
1406e1cd9874Sdanielk1977 ** Usage: sqlite3_column_data16 STMT column
1407e1cd9874Sdanielk1977 **
1408e1cd9874Sdanielk1977 ** Advance the statement to the next row.
1409e1cd9874Sdanielk1977 */
1410e1cd9874Sdanielk1977 static int test_column_data16(
1411e1cd9874Sdanielk1977   void * clientData,
1412e1cd9874Sdanielk1977   Tcl_Interp *interp,
1413e1cd9874Sdanielk1977   int objc,
1414e1cd9874Sdanielk1977   Tcl_Obj *CONST objv[]
1415e1cd9874Sdanielk1977 ){
1416e1cd9874Sdanielk1977   sqlite3_stmt *pStmt;
1417e1cd9874Sdanielk1977   int col;
1418e1cd9874Sdanielk1977   Tcl_Obj *pRet;
1419e1cd9874Sdanielk1977   int len;
1420e1cd9874Sdanielk1977 
1421e1cd9874Sdanielk1977   if( objc!=3 ){
1422e1cd9874Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1423e1cd9874Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
1424e1cd9874Sdanielk1977     return TCL_ERROR;
1425e1cd9874Sdanielk1977   }
1426e1cd9874Sdanielk1977 
1427e1cd9874Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
1428e1cd9874Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
1429e1cd9874Sdanielk1977 
1430e1cd9874Sdanielk1977   len = sqlite3_column_bytes16(pStmt, col);
1431e1cd9874Sdanielk1977   pRet = Tcl_NewByteArrayObj(sqlite3_column_data16(pStmt, col), len);
1432e1cd9874Sdanielk1977   Tcl_SetObjResult(interp, pRet);
1433e1cd9874Sdanielk1977 
1434106bb236Sdanielk1977   return TCL_OK;
1435106bb236Sdanielk1977 }
1436106bb236Sdanielk1977 
1437106bb236Sdanielk1977 /*
143817240fd9Sdanielk1977 ** Usage: sqlite3_column_count STMT
143917240fd9Sdanielk1977 **
144017240fd9Sdanielk1977 ** Return the number of columns returned by the sql statement STMT.
144117240fd9Sdanielk1977 */
144217240fd9Sdanielk1977 static int test_column_count(
144317240fd9Sdanielk1977   void * clientData,
144417240fd9Sdanielk1977   Tcl_Interp *interp,
144517240fd9Sdanielk1977   int objc,
144617240fd9Sdanielk1977   Tcl_Obj *CONST objv[]
144717240fd9Sdanielk1977 ){
144817240fd9Sdanielk1977   sqlite3_stmt *pStmt;
144917240fd9Sdanielk1977 
145017240fd9Sdanielk1977   if( objc!=2 ){
145117240fd9Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
145217240fd9Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
145317240fd9Sdanielk1977     return TCL_ERROR;
145417240fd9Sdanielk1977   }
145517240fd9Sdanielk1977 
145617240fd9Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
145717240fd9Sdanielk1977 
145817240fd9Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_column_count(pStmt)));
145917240fd9Sdanielk1977   return TCL_OK;
146017240fd9Sdanielk1977 }
146117240fd9Sdanielk1977 
146217240fd9Sdanielk1977 /*
146317240fd9Sdanielk1977 ** Usage: sqlite3_data_count STMT
146417240fd9Sdanielk1977 **
146517240fd9Sdanielk1977 ** Return the number of columns returned by the sql statement STMT.
146617240fd9Sdanielk1977 */
146717240fd9Sdanielk1977 static int test_data_count(
146817240fd9Sdanielk1977   void * clientData,
146917240fd9Sdanielk1977   Tcl_Interp *interp,
147017240fd9Sdanielk1977   int objc,
147117240fd9Sdanielk1977   Tcl_Obj *CONST objv[]
147217240fd9Sdanielk1977 ){
147317240fd9Sdanielk1977   sqlite3_stmt *pStmt;
147417240fd9Sdanielk1977 
147517240fd9Sdanielk1977   if( objc!=2 ){
147617240fd9Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
147717240fd9Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
147817240fd9Sdanielk1977     return TCL_ERROR;
147917240fd9Sdanielk1977   }
148017240fd9Sdanielk1977 
148117240fd9Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
148217240fd9Sdanielk1977 
148317240fd9Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_data_count(pStmt)));
148417240fd9Sdanielk1977   return TCL_OK;
148517240fd9Sdanielk1977 }
148617240fd9Sdanielk1977 
148717240fd9Sdanielk1977 /*
1488d3d39e93Sdrh ** This is a collating function named "REVERSE" which sorts text
1489d3d39e93Sdrh ** in reverse order.
1490d3d39e93Sdrh */
1491d3d39e93Sdrh static int reverseCollatingFunc(
1492d3d39e93Sdrh   void *NotUsed,
1493d3d39e93Sdrh   int nKey1, const void *pKey1,
1494d3d39e93Sdrh   int nKey2, const void *pKey2
1495d3d39e93Sdrh ){
1496d3d39e93Sdrh   int rc, n;
1497d3d39e93Sdrh   n = nKey1<nKey2 ? nKey1 : nKey2;
1498d3d39e93Sdrh   rc = memcmp(pKey1, pKey2, n);
1499d3d39e93Sdrh   if( rc==0 ){
1500d3d39e93Sdrh     rc = nKey1 - nKey2;
1501d3d39e93Sdrh   }
1502d3d39e93Sdrh   return -rc;
1503d3d39e93Sdrh }
1504d3d39e93Sdrh 
1505d3d39e93Sdrh /*
1506d3d39e93Sdrh ** Usage: add_reverse_collating_func DB
1507d3d39e93Sdrh **
1508d3d39e93Sdrh ** This routine adds a collation named "REVERSE" to database given.
1509d3d39e93Sdrh ** REVERSE is used for testing only.
1510d3d39e93Sdrh */
1511d3d39e93Sdrh static int reverse_collfunc(
1512d3d39e93Sdrh   void * clientData,
1513d3d39e93Sdrh   Tcl_Interp *interp,
1514d3d39e93Sdrh   int objc,
1515d3d39e93Sdrh   Tcl_Obj *CONST objv[]
1516d3d39e93Sdrh ){
1517d3d39e93Sdrh   sqlite3 *db;
1518d3d39e93Sdrh 
1519d3d39e93Sdrh   if( objc!=2 ){
1520d3d39e93Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB");
1521d3d39e93Sdrh     return TCL_ERROR;
1522d3d39e93Sdrh   }
1523d3d39e93Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1524d3d39e93Sdrh   sqlite3ChangeCollatingFunction(db, "REVERSE", 7, 0, reverseCollatingFunc);
1525d3d39e93Sdrh   return TCL_OK;
1526d3d39e93Sdrh }
1527d3d39e93Sdrh 
1528d3d39e93Sdrh 
15296622cce3Sdanielk1977 /*
1530d1bf3512Sdrh ** Register commands with the TCL interpreter.
1531d1bf3512Sdrh */
1532d1bf3512Sdrh int Sqlitetest1_Init(Tcl_Interp *interp){
15336f8a503dSdanielk1977   extern int sqlite3_search_count;
15346f8a503dSdanielk1977   extern int sqlite3_interrupt_count;
15356f8a503dSdanielk1977   extern int sqlite3_open_file_count;
15366f8a503dSdanielk1977   extern int sqlite3_current_time;
1537c2eef3b3Sdrh   static struct {
1538c2eef3b3Sdrh      char *zName;
1539c2eef3b3Sdrh      Tcl_CmdProc *xProc;
1540c2eef3b3Sdrh   } aCmd[] = {
15416f8a503dSdanielk1977      { "sqlite3_mprintf_int",           (Tcl_CmdProc*)sqlite3_mprintf_int    },
15426f8a503dSdanielk1977      { "sqlite3_mprintf_str",           (Tcl_CmdProc*)sqlite3_mprintf_str    },
15436f8a503dSdanielk1977      { "sqlite3_mprintf_double",        (Tcl_CmdProc*)sqlite3_mprintf_double },
15446f8a503dSdanielk1977      { "sqlite3_mprintf_scaled",        (Tcl_CmdProc*)sqlite3_mprintf_scaled },
15456f8a503dSdanielk1977      { "sqlite3_mprintf_z_test",        (Tcl_CmdProc*)test_mprintf_z        },
15466f8a503dSdanielk1977      { "sqlite3_last_insert_rowid",     (Tcl_CmdProc*)test_last_rowid       },
15476f8a503dSdanielk1977      { "sqlite3_exec_printf",           (Tcl_CmdProc*)test_exec_printf      },
15486f8a503dSdanielk1977      { "sqlite3_get_table_printf",      (Tcl_CmdProc*)test_get_table_printf },
15496f8a503dSdanielk1977      { "sqlite3_close",                 (Tcl_CmdProc*)sqlite_test_close     },
15506f8a503dSdanielk1977      { "sqlite3_create_function",       (Tcl_CmdProc*)test_create_function  },
15516f8a503dSdanielk1977      { "sqlite3_create_aggregate",      (Tcl_CmdProc*)test_create_aggregate },
1552c2eef3b3Sdrh      { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func    },
1553c2eef3b3Sdrh      { "sqlite_abort",                  (Tcl_CmdProc*)sqlite_abort          },
15545a38705eSdrh      { "sqlite_datatypes",              (Tcl_CmdProc*)sqlite_datatypes      },
1555c2eef3b3Sdrh #ifdef MEMORY_DEBUG
1556c2eef3b3Sdrh      { "sqlite_malloc_fail",            (Tcl_CmdProc*)sqlite_malloc_fail    },
1557c2eef3b3Sdrh      { "sqlite_malloc_stat",            (Tcl_CmdProc*)sqlite_malloc_stat    },
1558c2eef3b3Sdrh #endif
155996fc5fe6Sdanielk1977      { "sqlite_bind",                    (Tcl_CmdProc*)test_bind             },
156099ee3600Sdrh      { "breakpoint",                     (Tcl_CmdProc*)test_breakpoint       },
1561c2eef3b3Sdrh   };
156251e3d8e2Sdanielk1977   static struct {
156351e3d8e2Sdanielk1977      char *zName;
156451e3d8e2Sdanielk1977      Tcl_ObjCmdProc *xProc;
156551e3d8e2Sdanielk1977   } aObjCmd[] = {
156651e3d8e2Sdanielk1977      { "sqlite3_bind_int32",            (Tcl_ObjCmdProc*)test_bind_int32    },
156751e3d8e2Sdanielk1977      { "sqlite3_bind_int64",            (Tcl_ObjCmdProc*)test_bind_int64    },
156851e3d8e2Sdanielk1977      { "sqlite3_bind_double",           (Tcl_ObjCmdProc*)test_bind_double   },
156951e3d8e2Sdanielk1977      { "sqlite3_bind_null",             (Tcl_ObjCmdProc*)test_bind_null     },
157051e3d8e2Sdanielk1977      { "sqlite3_bind_text",             (Tcl_ObjCmdProc*)test_bind_text     },
157151e3d8e2Sdanielk1977      { "sqlite3_bind_text16",           (Tcl_ObjCmdProc*)test_bind_text16   },
157251e3d8e2Sdanielk1977      { "sqlite3_bind_blob",             (Tcl_ObjCmdProc*)test_bind_blob     },
15736622cce3Sdanielk1977      { "sqlite3_errcode",               (Tcl_ObjCmdProc*)test_errcode       },
15746622cce3Sdanielk1977      { "sqlite3_errmsg",                (Tcl_ObjCmdProc*)test_errmsg        },
15756622cce3Sdanielk1977      { "sqlite3_errmsg16",              (Tcl_ObjCmdProc*)test_errmsg16      },
15766622cce3Sdanielk1977      { "sqlite3_prepare",               (Tcl_ObjCmdProc*)test_prepare       },
15776622cce3Sdanielk1977      { "sqlite3_prepare16",             (Tcl_ObjCmdProc*)test_prepare16     },
15784ad1713cSdanielk1977      { "sqlite3_open",                  (Tcl_ObjCmdProc*)test_open          },
15794ad1713cSdanielk1977      { "sqlite3_open16",                (Tcl_ObjCmdProc*)test_open16        },
1580106bb236Sdanielk1977      { "sqlite3_finalize",              (Tcl_ObjCmdProc*)test_finalize      },
1581106bb236Sdanielk1977      { "sqlite3_reset",                 (Tcl_ObjCmdProc*)test_reset         },
158217240fd9Sdanielk1977      { "sqlite3_step",                  (Tcl_ObjCmdProc*)test_step},
1583e1cd9874Sdanielk1977      { "sqlite3_column_data",           (Tcl_ObjCmdProc*)test_column_data   },
1584e1cd9874Sdanielk1977      { "sqlite3_column_data16",         (Tcl_ObjCmdProc*)test_column_data16   },
158517240fd9Sdanielk1977      { "sqlite3_column_count",          (Tcl_ObjCmdProc*)test_column_count   },
158617240fd9Sdanielk1977      { "sqlite3_data_count",            (Tcl_ObjCmdProc*)test_data_count   },
1587d3d39e93Sdrh      { "add_reverse_collating_func",    (Tcl_ObjCmdProc*)reverse_collfunc   },
158851e3d8e2Sdanielk1977   };
1589c2eef3b3Sdrh   int i;
1590c2eef3b3Sdrh 
1591c2eef3b3Sdrh   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
1592c2eef3b3Sdrh     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
1593c2eef3b3Sdrh   }
159451e3d8e2Sdanielk1977   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
159551e3d8e2Sdanielk1977     Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
159651e3d8e2Sdanielk1977   }
15976490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_search_count",
15986f8a503dSdanielk1977       (char*)&sqlite3_search_count, TCL_LINK_INT);
15996490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_interrupt_count",
16006f8a503dSdanielk1977       (char*)&sqlite3_interrupt_count, TCL_LINK_INT);
16016490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_open_file_count",
16026f8a503dSdanielk1977       (char*)&sqlite3_open_file_count, TCL_LINK_INT);
16036490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_current_time",
16046f8a503dSdanielk1977       (char*)&sqlite3_current_time, TCL_LINK_INT);
16057c972decSdrh   Tcl_LinkVar(interp, "sqlite_static_bind_value",
16067c972decSdrh       (char*)&sqlite_static_bind_value, TCL_LINK_STRING);
1607d1bf3512Sdrh   return TCL_OK;
1608d1bf3512Sdrh }
1609