xref: /sqlite-3.40.0/src/test1.c (revision 80290863)
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*80290863Sdanielk1977 ** $Id: test1.c,v 1.46 2004/05/22 09:21:21 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 /*
80b86ccfb2Sdrh ** Decode a pointer to an sqlite_vm object.
81b86ccfb2Sdrh */
82b86ccfb2Sdrh static int getVmPointer(Tcl_Interp *interp, const char *zArg, sqlite_vm **ppVm){
8394e92032Sdrh   if( sscanf(zArg, PTR_FMT, (void**)ppVm)!=1 ){
84b86ccfb2Sdrh     Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0);
85b86ccfb2Sdrh     return TCL_ERROR;
86b86ccfb2Sdrh   }
87b86ccfb2Sdrh   return TCL_OK;
88b86ccfb2Sdrh }
89b86ccfb2Sdrh 
90b86ccfb2Sdrh /*
9151e3d8e2Sdanielk1977 ** Decode a pointer to an sqlite3_stmt object.
9251e3d8e2Sdanielk1977 */
9351e3d8e2Sdanielk1977 static int getStmtPointer(
9451e3d8e2Sdanielk1977   Tcl_Interp *interp,
9551e3d8e2Sdanielk1977   const char *zArg,
9651e3d8e2Sdanielk1977   sqlite3_stmt **ppStmt
9751e3d8e2Sdanielk1977 ){
9851e3d8e2Sdanielk1977   if( sscanf(zArg, PTR_FMT, (void**)ppStmt)!=1 ){
9951e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0);
10051e3d8e2Sdanielk1977     return TCL_ERROR;
10151e3d8e2Sdanielk1977   }
10251e3d8e2Sdanielk1977   return TCL_OK;
10351e3d8e2Sdanielk1977 }
10451e3d8e2Sdanielk1977 
10551e3d8e2Sdanielk1977 /*
1067d8085a8Sdrh ** Generate a text representation of a pointer that can be understood
1077d8085a8Sdrh ** by the getDbPointer and getVmPointer routines above.
1087d8085a8Sdrh **
1097d8085a8Sdrh ** The problem is, on some machines (Solaris) if you do a printf with
1107d8085a8Sdrh ** "%p" you cannot turn around and do a scanf with the same "%p" and
1117d8085a8Sdrh ** get your pointer back.  You have to prepend a "0x" before it will
1127d8085a8Sdrh ** work.  Or at least that is what is reported to me (drh).  But this
1137d8085a8Sdrh ** behavior varies from machine to machine.  The solution used her is
1147d8085a8Sdrh ** to test the string right after it is generated to see if it can be
1157d8085a8Sdrh ** understood by scanf, and if not, try prepending an "0x" to see if
1167d8085a8Sdrh ** that helps.  If nothing works, a fatal error is generated.
1177d8085a8Sdrh */
1187d8085a8Sdrh static int makePointerStr(Tcl_Interp *interp, char *zPtr, void *p){
1197d8085a8Sdrh   void *p2;
1207d8085a8Sdrh   sprintf(zPtr, PTR_FMT, p);
1217d8085a8Sdrh   if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){
1227d8085a8Sdrh     sprintf(zPtr, "0x" PTR_FMT, p);
1237d8085a8Sdrh     if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){
1247d8085a8Sdrh       Tcl_AppendResult(interp, "unable to convert a pointer to a string "
1257d8085a8Sdrh          "in the file " __FILE__ " in function makePointerStr().  Please "
1267d8085a8Sdrh          "report this problem to the SQLite mailing list or as a new but "
1277d8085a8Sdrh          "report.  Please provide detailed information about how you compiled "
1287d8085a8Sdrh          "SQLite and what computer you are running on.", 0);
1297d8085a8Sdrh       return TCL_ERROR;
1307d8085a8Sdrh     }
1317d8085a8Sdrh   }
1327d8085a8Sdrh   return TCL_OK;
1337d8085a8Sdrh }
1347d8085a8Sdrh 
1357d8085a8Sdrh /*
1366f8a503dSdanielk1977 ** The callback routine for sqlite3_exec_printf().
137d1bf3512Sdrh */
138d1bf3512Sdrh static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){
139d1bf3512Sdrh   Tcl_DString *str = (Tcl_DString*)pArg;
140d1bf3512Sdrh   int i;
141d1bf3512Sdrh 
142d1bf3512Sdrh   if( Tcl_DStringLength(str)==0 ){
143d1bf3512Sdrh     for(i=0; i<argc; i++){
144d1bf3512Sdrh       Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL");
145d1bf3512Sdrh     }
146d1bf3512Sdrh   }
147d1bf3512Sdrh   for(i=0; i<argc; i++){
148d1bf3512Sdrh     Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL");
149d1bf3512Sdrh   }
150d1bf3512Sdrh   return 0;
151d1bf3512Sdrh }
152d1bf3512Sdrh 
153d1bf3512Sdrh /*
1546f8a503dSdanielk1977 ** Usage:  sqlite3_exec_printf  DB  FORMAT  STRING
155d1bf3512Sdrh **
1566f8a503dSdanielk1977 ** Invoke the sqlite3_exec_printf() interface using the open database
157d1bf3512Sdrh ** DB.  The SQL is the string FORMAT.  The format string should contain
158d1bf3512Sdrh ** one %s or %q.  STRING is the value inserted into %s or %q.
159d1bf3512Sdrh */
160d1bf3512Sdrh static int test_exec_printf(
161d1bf3512Sdrh   void *NotUsed,
162d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
163d1bf3512Sdrh   int argc,              /* Number of arguments */
164d1bf3512Sdrh   char **argv            /* Text of each argument */
165d1bf3512Sdrh ){
166d1bf3512Sdrh   sqlite *db;
167d1bf3512Sdrh   Tcl_DString str;
168d1bf3512Sdrh   int rc;
169d1bf3512Sdrh   char *zErr = 0;
170d1bf3512Sdrh   char zBuf[30];
171d1bf3512Sdrh   if( argc!=4 ){
172d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
173d1bf3512Sdrh        " DB FORMAT STRING", 0);
174d1bf3512Sdrh     return TCL_ERROR;
175d1bf3512Sdrh   }
176b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
177d1bf3512Sdrh   Tcl_DStringInit(&str);
1786f8a503dSdanielk1977   rc = sqlite3_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]);
179d1bf3512Sdrh   sprintf(zBuf, "%d", rc);
180d1bf3512Sdrh   Tcl_AppendElement(interp, zBuf);
181d1bf3512Sdrh   Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
182d1bf3512Sdrh   Tcl_DStringFree(&str);
183d1bf3512Sdrh   if( zErr ) free(zErr);
184d1bf3512Sdrh   return TCL_OK;
185d1bf3512Sdrh }
186d1bf3512Sdrh 
187d1bf3512Sdrh /*
1886f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_z_test  SEPARATOR  ARG0  ARG1 ...
189d93d8a81Sdrh **
190d93d8a81Sdrh ** Test the %z format of mprintf().  Use multiple mprintf() calls to
191d93d8a81Sdrh ** concatenate arg0 through argn using separator as the separator.
192d93d8a81Sdrh ** Return the result.
193d93d8a81Sdrh */
194d93d8a81Sdrh static int test_mprintf_z(
195d93d8a81Sdrh   void *NotUsed,
196d93d8a81Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
197d93d8a81Sdrh   int argc,              /* Number of arguments */
198d93d8a81Sdrh   char **argv            /* Text of each argument */
199d93d8a81Sdrh ){
200d93d8a81Sdrh   char *zResult = 0;
201d93d8a81Sdrh   int i;
202d93d8a81Sdrh 
203d93d8a81Sdrh   for(i=2; i<argc; i++){
2044adee20fSdanielk1977     zResult = sqlite3MPrintf("%z%s%s", zResult, argv[1], argv[i]);
205d93d8a81Sdrh   }
206d93d8a81Sdrh   Tcl_AppendResult(interp, zResult, 0);
2075f968436Sdrh   sqliteFree(zResult);
208d93d8a81Sdrh   return TCL_OK;
209d93d8a81Sdrh }
210d93d8a81Sdrh 
211d93d8a81Sdrh /*
2126f8a503dSdanielk1977 ** Usage:  sqlite3_get_table_printf  DB  FORMAT  STRING
213d1bf3512Sdrh **
2146f8a503dSdanielk1977 ** Invoke the sqlite3_get_table_printf() interface using the open database
215d1bf3512Sdrh ** DB.  The SQL is the string FORMAT.  The format string should contain
216d1bf3512Sdrh ** one %s or %q.  STRING is the value inserted into %s or %q.
217d1bf3512Sdrh */
218d1bf3512Sdrh static int test_get_table_printf(
219d1bf3512Sdrh   void *NotUsed,
220d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
221d1bf3512Sdrh   int argc,              /* Number of arguments */
222d1bf3512Sdrh   char **argv            /* Text of each argument */
223d1bf3512Sdrh ){
224d1bf3512Sdrh   sqlite *db;
225d1bf3512Sdrh   Tcl_DString str;
226d1bf3512Sdrh   int rc;
227d1bf3512Sdrh   char *zErr = 0;
228d1bf3512Sdrh   int nRow, nCol;
229d1bf3512Sdrh   char **aResult;
230d1bf3512Sdrh   int i;
231d1bf3512Sdrh   char zBuf[30];
232d1bf3512Sdrh   if( argc!=4 ){
233d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
234d1bf3512Sdrh        " DB FORMAT STRING", 0);
235d1bf3512Sdrh     return TCL_ERROR;
236d1bf3512Sdrh   }
237b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
238d1bf3512Sdrh   Tcl_DStringInit(&str);
2396f8a503dSdanielk1977   rc = sqlite3_get_table_printf(db, argv[2], &aResult, &nRow, &nCol,
240d1bf3512Sdrh                &zErr, argv[3]);
241d1bf3512Sdrh   sprintf(zBuf, "%d", rc);
242d1bf3512Sdrh   Tcl_AppendElement(interp, zBuf);
243d1bf3512Sdrh   if( rc==SQLITE_OK ){
244d1bf3512Sdrh     sprintf(zBuf, "%d", nRow);
245d1bf3512Sdrh     Tcl_AppendElement(interp, zBuf);
246d1bf3512Sdrh     sprintf(zBuf, "%d", nCol);
247d1bf3512Sdrh     Tcl_AppendElement(interp, zBuf);
248d1bf3512Sdrh     for(i=0; i<(nRow+1)*nCol; i++){
249d1bf3512Sdrh       Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL");
250d1bf3512Sdrh     }
251d1bf3512Sdrh   }else{
252d1bf3512Sdrh     Tcl_AppendElement(interp, zErr);
253d1bf3512Sdrh   }
2546f8a503dSdanielk1977   sqlite3_free_table(aResult);
255d1bf3512Sdrh   if( zErr ) free(zErr);
256d1bf3512Sdrh   return TCL_OK;
257d1bf3512Sdrh }
258d1bf3512Sdrh 
259af9ff33aSdrh 
260af9ff33aSdrh /*
2616f8a503dSdanielk1977 ** Usage:  sqlite3_last_insert_rowid DB
262af9ff33aSdrh **
263af9ff33aSdrh ** Returns the integer ROWID of the most recent insert.
264af9ff33aSdrh */
265af9ff33aSdrh static int test_last_rowid(
266af9ff33aSdrh   void *NotUsed,
267af9ff33aSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
268af9ff33aSdrh   int argc,              /* Number of arguments */
269af9ff33aSdrh   char **argv            /* Text of each argument */
270af9ff33aSdrh ){
271af9ff33aSdrh   sqlite *db;
272af9ff33aSdrh   char zBuf[30];
273af9ff33aSdrh 
274af9ff33aSdrh   if( argc!=2 ){
275af9ff33aSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0);
276af9ff33aSdrh     return TCL_ERROR;
277af9ff33aSdrh   }
278b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
2796f8a503dSdanielk1977   sprintf(zBuf, "%d", sqlite3_last_insert_rowid(db));
280af9ff33aSdrh   Tcl_AppendResult(interp, zBuf, 0);
281af9ff33aSdrh   return SQLITE_OK;
282af9ff33aSdrh }
283af9ff33aSdrh 
284d1bf3512Sdrh /*
2856f8a503dSdanielk1977 ** Usage:  sqlite3_close DB
286d1bf3512Sdrh **
2876f8a503dSdanielk1977 ** Closes the database opened by sqlite3_open.
288d1bf3512Sdrh */
289d1bf3512Sdrh static int sqlite_test_close(
290d1bf3512Sdrh   void *NotUsed,
291d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
292d1bf3512Sdrh   int argc,              /* Number of arguments */
293d1bf3512Sdrh   char **argv            /* Text of each argument */
294d1bf3512Sdrh ){
295d1bf3512Sdrh   sqlite *db;
296d1bf3512Sdrh   if( argc!=2 ){
297d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
298d1bf3512Sdrh        " FILENAME\"", 0);
299d1bf3512Sdrh     return TCL_ERROR;
300d1bf3512Sdrh   }
301b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
3026f8a503dSdanielk1977   sqlite3_close(db);
303d1bf3512Sdrh   return TCL_OK;
304d1bf3512Sdrh }
305d1bf3512Sdrh 
306d1bf3512Sdrh /*
307c22bd47dSdrh ** Implementation of the x_coalesce() function.
308c22bd47dSdrh ** Return the first argument non-NULL argument.
309c22bd47dSdrh */
310c22bd47dSdrh static void ifnullFunc(sqlite_func *context, int argc, const char **argv){
311c22bd47dSdrh   int i;
312c22bd47dSdrh   for(i=0; i<argc; i++){
313c22bd47dSdrh     if( argv[i] ){
3146f8a503dSdanielk1977       sqlite3_set_result_string(context, argv[i], -1);
315c22bd47dSdrh       break;
316c22bd47dSdrh     }
317c22bd47dSdrh   }
318c22bd47dSdrh }
319c22bd47dSdrh 
320c22bd47dSdrh /*
321d1d9fc33Sdrh ** A structure into which to accumulate text.
322d1d9fc33Sdrh */
323d1d9fc33Sdrh struct dstr {
324d1d9fc33Sdrh   int nAlloc;  /* Space allocated */
325d1d9fc33Sdrh   int nUsed;   /* Space used */
326d1d9fc33Sdrh   char *z;     /* The space */
327d1d9fc33Sdrh };
328d1d9fc33Sdrh 
329d1d9fc33Sdrh /*
330d1d9fc33Sdrh ** Append text to a dstr
331d1d9fc33Sdrh */
332d1d9fc33Sdrh static void dstrAppend(struct dstr *p, const char *z, int divider){
333d1d9fc33Sdrh   int n = strlen(z);
334d1d9fc33Sdrh   if( p->nUsed + n + 2 > p->nAlloc ){
335d1d9fc33Sdrh     char *zNew;
336d1d9fc33Sdrh     p->nAlloc = p->nAlloc*2 + n + 200;
337d1d9fc33Sdrh     zNew = sqliteRealloc(p->z, p->nAlloc);
338d1d9fc33Sdrh     if( zNew==0 ){
339d1d9fc33Sdrh       sqliteFree(p->z);
340d1d9fc33Sdrh       memset(p, 0, sizeof(*p));
341d1d9fc33Sdrh       return;
342d1d9fc33Sdrh     }
343d1d9fc33Sdrh     p->z = zNew;
344d1d9fc33Sdrh   }
345d1d9fc33Sdrh   if( divider && p->nUsed>0 ){
346d1d9fc33Sdrh     p->z[p->nUsed++] = divider;
347d1d9fc33Sdrh   }
348d1d9fc33Sdrh   memcpy(&p->z[p->nUsed], z, n+1);
349d1d9fc33Sdrh   p->nUsed += n;
350d1d9fc33Sdrh }
351d1d9fc33Sdrh 
352d1d9fc33Sdrh /*
3534adee20fSdanielk1977 ** Invoked for each callback from sqlite3ExecFunc
354d1d9fc33Sdrh */
355d1d9fc33Sdrh static int execFuncCallback(void *pData, int argc, char **argv, char **NotUsed){
356d1d9fc33Sdrh   struct dstr *p = (struct dstr*)pData;
357d1d9fc33Sdrh   int i;
358d1d9fc33Sdrh   for(i=0; i<argc; i++){
359d1d9fc33Sdrh     if( argv[i]==0 ){
360d1d9fc33Sdrh       dstrAppend(p, "NULL", ' ');
361d1d9fc33Sdrh     }else{
362d1d9fc33Sdrh       dstrAppend(p, argv[i], ' ');
363d1d9fc33Sdrh     }
364d1d9fc33Sdrh   }
365d1d9fc33Sdrh   return 0;
366d1d9fc33Sdrh }
367d1d9fc33Sdrh 
368d1d9fc33Sdrh /*
3696f8a503dSdanielk1977 ** Implementation of the x_sqlite3_exec() function.  This function takes
370c22bd47dSdrh ** a single argument and attempts to execute that argument as SQL code.
3716cbe1f1bSdrh ** This is illegal and should set the SQLITE_MISUSE flag on the database.
372c22bd47dSdrh **
3736f8a503dSdanielk1977 ** 2004-Jan-07:  We have changed this to make it legal to call sqlite3_exec()
374d1d9fc33Sdrh ** from within a function call.
375d1d9fc33Sdrh **
376c22bd47dSdrh ** This routine simulates the effect of having two threads attempt to
377c22bd47dSdrh ** use the same database at the same time.
378c22bd47dSdrh */
3794adee20fSdanielk1977 static void sqlite3ExecFunc(sqlite_func *context, int argc, const char **argv){
380d1d9fc33Sdrh   struct dstr x;
381d1d9fc33Sdrh   memset(&x, 0, sizeof(x));
3826f8a503dSdanielk1977   sqlite3_exec((sqlite*)sqlite3_user_data(context), argv[0],
383d1d9fc33Sdrh       execFuncCallback, &x, 0);
3846f8a503dSdanielk1977   sqlite3_set_result_string(context, x.z, x.nUsed);
385d1d9fc33Sdrh   sqliteFree(x.z);
386c22bd47dSdrh }
387c22bd47dSdrh 
388c22bd47dSdrh /*
389c22bd47dSdrh ** Usage:  sqlite_test_create_function DB
390c22bd47dSdrh **
3916f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order
392c22bd47dSdrh ** to create a function named "x_coalesce".  This function does the same thing
393c22bd47dSdrh ** as the "coalesce" function.  This function also registers an SQL function
3946f8a503dSdanielk1977 ** named "x_sqlite3_exec" that invokes sqlite3_exec().  Invoking sqlite3_exec()
395c22bd47dSdrh ** in this way is illegal recursion and should raise an SQLITE_MISUSE error.
396c22bd47dSdrh ** The effect is similar to trying to use the same database connection from
397c22bd47dSdrh ** two threads at the same time.
398c22bd47dSdrh **
399c22bd47dSdrh ** The original motivation for this routine was to be able to call the
4006f8a503dSdanielk1977 ** sqlite3_create_function function while a query is in progress in order
401c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
402c22bd47dSdrh */
403c2eef3b3Sdrh static int test_create_function(
404c22bd47dSdrh   void *NotUsed,
405c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
406c22bd47dSdrh   int argc,              /* Number of arguments */
407c22bd47dSdrh   char **argv            /* Text of each argument */
408c22bd47dSdrh ){
409c22bd47dSdrh   sqlite *db;
410c22bd47dSdrh   extern void Md5_Register(sqlite*);
411c22bd47dSdrh   if( argc!=2 ){
412c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
413c22bd47dSdrh        " FILENAME\"", 0);
414c22bd47dSdrh     return TCL_ERROR;
415c22bd47dSdrh   }
416b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
4176f8a503dSdanielk1977   sqlite3_create_function(db, "x_coalesce", -1, ifnullFunc, 0);
4186f8a503dSdanielk1977   sqlite3_create_function(db, "x_sqlite3_exec", 1, sqlite3ExecFunc, db);
419c22bd47dSdrh   return TCL_OK;
420c22bd47dSdrh }
421c22bd47dSdrh 
422c22bd47dSdrh /*
423c22bd47dSdrh ** Routines to implement the x_count() aggregate function.
424c22bd47dSdrh */
425c22bd47dSdrh typedef struct CountCtx CountCtx;
426c22bd47dSdrh struct CountCtx {
427c22bd47dSdrh   int n;
428c22bd47dSdrh };
429c22bd47dSdrh static void countStep(sqlite_func *context, int argc, const char **argv){
430c22bd47dSdrh   CountCtx *p;
4316f8a503dSdanielk1977   p = sqlite3_aggregate_context(context, sizeof(*p));
432c22bd47dSdrh   if( (argc==0 || argv[0]) && p ){
433c22bd47dSdrh     p->n++;
434c22bd47dSdrh   }
435c22bd47dSdrh }
436c22bd47dSdrh static void countFinalize(sqlite_func *context){
437c22bd47dSdrh   CountCtx *p;
4386f8a503dSdanielk1977   p = sqlite3_aggregate_context(context, sizeof(*p));
4396f8a503dSdanielk1977   sqlite3_set_result_int(context, p ? p->n : 0);
440c22bd47dSdrh }
441c22bd47dSdrh 
442c22bd47dSdrh /*
443c22bd47dSdrh ** Usage:  sqlite_test_create_aggregate DB
444c22bd47dSdrh **
4456f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order
446c22bd47dSdrh ** to create a function named "x_count".  This function does the same thing
447c22bd47dSdrh ** as the "md5sum" function.
448c22bd47dSdrh **
449c22bd47dSdrh ** The original motivation for this routine was to be able to call the
4506f8a503dSdanielk1977 ** sqlite3_create_aggregate function while a query is in progress in order
451c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
452c22bd47dSdrh */
453c2eef3b3Sdrh static int test_create_aggregate(
454c22bd47dSdrh   void *NotUsed,
455c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
456c22bd47dSdrh   int argc,              /* Number of arguments */
457c22bd47dSdrh   char **argv            /* Text of each argument */
458c22bd47dSdrh ){
459c22bd47dSdrh   sqlite *db;
460c22bd47dSdrh   if( argc!=2 ){
461c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
462c22bd47dSdrh        " FILENAME\"", 0);
463c22bd47dSdrh     return TCL_ERROR;
464c22bd47dSdrh   }
465b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
4666f8a503dSdanielk1977   sqlite3_create_aggregate(db, "x_count", 0, countStep, countFinalize, 0);
4676f8a503dSdanielk1977   sqlite3_create_aggregate(db, "x_count", 1, countStep, countFinalize, 0);
468c22bd47dSdrh   return TCL_OK;
469c22bd47dSdrh }
470c22bd47dSdrh 
471c22bd47dSdrh 
472c22bd47dSdrh 
473c22bd47dSdrh /*
4746f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER
475d1bf3512Sdrh **
476d1bf3512Sdrh ** Call mprintf with three integer arguments
477d1bf3512Sdrh */
4786f8a503dSdanielk1977 static int sqlite3_mprintf_int(
479d1bf3512Sdrh   void *NotUsed,
480d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
481d1bf3512Sdrh   int argc,              /* Number of arguments */
482d1bf3512Sdrh   char **argv            /* Text of each argument */
483d1bf3512Sdrh ){
484d1bf3512Sdrh   int a[3], i;
485d1bf3512Sdrh   char *z;
486d1bf3512Sdrh   if( argc!=5 ){
487d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
488d1bf3512Sdrh        " FORMAT INT INT INT\"", 0);
489d1bf3512Sdrh     return TCL_ERROR;
490d1bf3512Sdrh   }
491d1bf3512Sdrh   for(i=2; i<5; i++){
492d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
493d1bf3512Sdrh   }
4946f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]);
495d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
4966f8a503dSdanielk1977   sqlite3_freemem(z);
497d1bf3512Sdrh   return TCL_OK;
498d1bf3512Sdrh }
499d1bf3512Sdrh 
500d1bf3512Sdrh /*
5016f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT INTEGER INTEGER STRING
502d1bf3512Sdrh **
503d1bf3512Sdrh ** Call mprintf with two integer arguments and one string argument
504d1bf3512Sdrh */
5056f8a503dSdanielk1977 static int sqlite3_mprintf_str(
506d1bf3512Sdrh   void *NotUsed,
507d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
508d1bf3512Sdrh   int argc,              /* Number of arguments */
509d1bf3512Sdrh   char **argv            /* Text of each argument */
510d1bf3512Sdrh ){
511d1bf3512Sdrh   int a[3], i;
512d1bf3512Sdrh   char *z;
513f220b24fSchw   if( argc<4 || argc>5 ){
514d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
515f220b24fSchw        " FORMAT INT INT ?STRING?\"", 0);
516d1bf3512Sdrh     return TCL_ERROR;
517d1bf3512Sdrh   }
518d1bf3512Sdrh   for(i=2; i<4; i++){
519d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
520d1bf3512Sdrh   }
5216f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL);
522d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
5236f8a503dSdanielk1977   sqlite3_freemem(z);
524d1bf3512Sdrh   return TCL_OK;
525d1bf3512Sdrh }
526d1bf3512Sdrh 
527d1bf3512Sdrh /*
5286f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT INTEGER INTEGER DOUBLE
529d1bf3512Sdrh **
530d1bf3512Sdrh ** Call mprintf with two integer arguments and one double argument
531d1bf3512Sdrh */
5326f8a503dSdanielk1977 static int sqlite3_mprintf_double(
533d1bf3512Sdrh   void *NotUsed,
534d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
535d1bf3512Sdrh   int argc,              /* Number of arguments */
536d1bf3512Sdrh   char **argv            /* Text of each argument */
537d1bf3512Sdrh ){
538d1bf3512Sdrh   int a[3], i;
539d1bf3512Sdrh   double r;
540d1bf3512Sdrh   char *z;
541d1bf3512Sdrh   if( argc!=5 ){
542d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
543d1bf3512Sdrh        " FORMAT INT INT STRING\"", 0);
544d1bf3512Sdrh     return TCL_ERROR;
545d1bf3512Sdrh   }
546d1bf3512Sdrh   for(i=2; i<4; i++){
547d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
548d1bf3512Sdrh   }
549d1bf3512Sdrh   if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR;
5506f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], r);
551d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
5526f8a503dSdanielk1977   sqlite3_freemem(z);
553d1bf3512Sdrh   return TCL_OK;
554d1bf3512Sdrh }
555d1bf3512Sdrh 
556d1bf3512Sdrh /*
5576f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT DOUBLE DOUBLE
558b621c237Sdrh **
559b621c237Sdrh ** Call mprintf with a single double argument which is the product of the
560b621c237Sdrh ** two arguments given above.  This is used to generate overflow and underflow
561b621c237Sdrh ** doubles to test that they are converted properly.
562b621c237Sdrh */
5636f8a503dSdanielk1977 static int sqlite3_mprintf_scaled(
564b621c237Sdrh   void *NotUsed,
565b621c237Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
566b621c237Sdrh   int argc,              /* Number of arguments */
567b621c237Sdrh   char **argv            /* Text of each argument */
568b621c237Sdrh ){
569b621c237Sdrh   int i;
570b621c237Sdrh   double r[2];
571b621c237Sdrh   char *z;
572b621c237Sdrh   if( argc!=4 ){
573b621c237Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
574b621c237Sdrh        " FORMAT DOUBLE DOUBLE\"", 0);
575b621c237Sdrh     return TCL_ERROR;
576b621c237Sdrh   }
577b621c237Sdrh   for(i=2; i<4; i++){
578b621c237Sdrh     if( Tcl_GetDouble(interp, argv[i], &r[i-2]) ) return TCL_ERROR;
579b621c237Sdrh   }
5806f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], r[0]*r[1]);
581b621c237Sdrh   Tcl_AppendResult(interp, z, 0);
5826f8a503dSdanielk1977   sqlite3_freemem(z);
583b621c237Sdrh   return TCL_OK;
584b621c237Sdrh }
585b621c237Sdrh 
586b621c237Sdrh /*
587daffd0e5Sdrh ** Usage: sqlite_malloc_fail N
588daffd0e5Sdrh **
589afa4a020Sdrh ** Rig sqliteMalloc() to fail on the N-th call.  Turn off this mechanism
5906f8a503dSdanielk1977 ** and reset the sqlite3_malloc_failed variable is N==0.
591daffd0e5Sdrh */
592daffd0e5Sdrh #ifdef MEMORY_DEBUG
593daffd0e5Sdrh static int sqlite_malloc_fail(
594daffd0e5Sdrh   void *NotUsed,
595daffd0e5Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
596daffd0e5Sdrh   int argc,              /* Number of arguments */
597daffd0e5Sdrh   char **argv            /* Text of each argument */
598daffd0e5Sdrh ){
599daffd0e5Sdrh   int n;
600daffd0e5Sdrh   if( argc!=2 ){
601daffd0e5Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0);
602daffd0e5Sdrh     return TCL_ERROR;
603daffd0e5Sdrh   }
604daffd0e5Sdrh   if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
6056f8a503dSdanielk1977   sqlite3_iMallocFail = n;
6066f8a503dSdanielk1977   sqlite3_malloc_failed = 0;
607daffd0e5Sdrh   return TCL_OK;
608daffd0e5Sdrh }
609daffd0e5Sdrh #endif
610daffd0e5Sdrh 
611daffd0e5Sdrh /*
612daffd0e5Sdrh ** Usage: sqlite_malloc_stat
613daffd0e5Sdrh **
614daffd0e5Sdrh ** Return the number of prior calls to sqliteMalloc() and sqliteFree().
615daffd0e5Sdrh */
616daffd0e5Sdrh #ifdef MEMORY_DEBUG
617daffd0e5Sdrh static int sqlite_malloc_stat(
618daffd0e5Sdrh   void *NotUsed,
619daffd0e5Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
620daffd0e5Sdrh   int argc,              /* Number of arguments */
621daffd0e5Sdrh   char **argv            /* Text of each argument */
622daffd0e5Sdrh ){
623daffd0e5Sdrh   char zBuf[200];
6246f8a503dSdanielk1977   sprintf(zBuf, "%d %d %d", sqlite3_nMalloc, sqlite3_nFree, sqlite3_iMallocFail);
625daffd0e5Sdrh   Tcl_AppendResult(interp, zBuf, 0);
626daffd0e5Sdrh   return TCL_OK;
627daffd0e5Sdrh }
628daffd0e5Sdrh #endif
629daffd0e5Sdrh 
630daffd0e5Sdrh /*
63128b4e489Sdrh ** Usage:  sqlite_abort
63228b4e489Sdrh **
63328b4e489Sdrh ** Shutdown the process immediately.  This is not a clean shutdown.
63428b4e489Sdrh ** This command is used to test the recoverability of a database in
63528b4e489Sdrh ** the event of a program crash.
63628b4e489Sdrh */
63728b4e489Sdrh static int sqlite_abort(
63828b4e489Sdrh   void *NotUsed,
63928b4e489Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
64028b4e489Sdrh   int argc,              /* Number of arguments */
64128b4e489Sdrh   char **argv            /* Text of each argument */
64228b4e489Sdrh ){
64328b4e489Sdrh   assert( interp==0 );   /* This will always fail */
64428b4e489Sdrh   return TCL_OK;
64528b4e489Sdrh }
64628b4e489Sdrh 
64728b4e489Sdrh /*
6486cbe1f1bSdrh ** The following routine is a user-defined SQL function whose purpose
6496cbe1f1bSdrh ** is to test the sqlite_set_result() API.
6506cbe1f1bSdrh */
6516cbe1f1bSdrh static void testFunc(sqlite_func *context, int argc, const char **argv){
6526cbe1f1bSdrh   while( argc>=2 ){
6536cbe1f1bSdrh     if( argv[0]==0 ){
6546f8a503dSdanielk1977       sqlite3_set_result_error(context, "first argument to test function "
6556cbe1f1bSdrh          "may not be NULL", -1);
6564adee20fSdanielk1977     }else if( sqlite3StrICmp(argv[0],"string")==0 ){
6576f8a503dSdanielk1977       sqlite3_set_result_string(context, argv[1], -1);
6586cbe1f1bSdrh     }else if( argv[1]==0 ){
6596f8a503dSdanielk1977       sqlite3_set_result_error(context, "2nd argument may not be NULL if the "
6606cbe1f1bSdrh          "first argument is not \"string\"", -1);
6614adee20fSdanielk1977     }else if( sqlite3StrICmp(argv[0],"int")==0 ){
6626f8a503dSdanielk1977       sqlite3_set_result_int(context, atoi(argv[1]));
6634adee20fSdanielk1977     }else if( sqlite3StrICmp(argv[0],"double")==0 ){
6646f8a503dSdanielk1977       sqlite3_set_result_double(context, sqlite3AtoF(argv[1], 0));
6656cbe1f1bSdrh     }else{
6666f8a503dSdanielk1977       sqlite3_set_result_error(context,"first argument should be one of: "
6676cbe1f1bSdrh           "string int double", -1);
6686cbe1f1bSdrh     }
6696cbe1f1bSdrh     argc -= 2;
6706cbe1f1bSdrh     argv += 2;
6716cbe1f1bSdrh   }
6726cbe1f1bSdrh }
6736cbe1f1bSdrh 
6746cbe1f1bSdrh /*
6756cbe1f1bSdrh ** Usage:   sqlite_register_test_function  DB  NAME
6766cbe1f1bSdrh **
6776cbe1f1bSdrh ** Register the test SQL function on the database DB under the name NAME.
6786cbe1f1bSdrh */
679c2eef3b3Sdrh static int test_register_func(
6806cbe1f1bSdrh   void *NotUsed,
6816cbe1f1bSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6826cbe1f1bSdrh   int argc,              /* Number of arguments */
6836cbe1f1bSdrh   char **argv            /* Text of each argument */
6846cbe1f1bSdrh ){
6856cbe1f1bSdrh   sqlite *db;
6866cbe1f1bSdrh   int rc;
6876cbe1f1bSdrh   if( argc!=3 ){
6886cbe1f1bSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
6896cbe1f1bSdrh        " DB FUNCTION-NAME", 0);
6906cbe1f1bSdrh     return TCL_ERROR;
6916cbe1f1bSdrh   }
692b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
6936f8a503dSdanielk1977   rc = sqlite3_create_function(db, argv[2], -1, testFunc, 0);
6946cbe1f1bSdrh   if( rc!=0 ){
6956f8a503dSdanielk1977     Tcl_AppendResult(interp, sqlite3_error_string(rc), 0);
6966cbe1f1bSdrh     return TCL_ERROR;
6976cbe1f1bSdrh   }
6986cbe1f1bSdrh   return TCL_OK;
6996cbe1f1bSdrh }
7006cbe1f1bSdrh 
7016cbe1f1bSdrh /*
7025a38705eSdrh ** This SQLite callback records the datatype of all columns.
7035a38705eSdrh **
7045a38705eSdrh ** The pArg argument is really a pointer to a TCL interpreter.  The
7055a38705eSdrh ** column names are inserted as the result of this interpreter.
7065a38705eSdrh **
7075a38705eSdrh ** This routine returns non-zero which causes the query to abort.
7085a38705eSdrh */
7095a38705eSdrh static int rememberDataTypes(void *pArg, int nCol, char **argv, char **colv){
7105a38705eSdrh   int i;
7115a38705eSdrh   Tcl_Interp *interp = (Tcl_Interp*)pArg;
7125a38705eSdrh   Tcl_Obj *pList, *pElem;
7135a38705eSdrh   if( colv[nCol+1]==0 ){
7145a38705eSdrh     return 1;
7155a38705eSdrh   }
7165a38705eSdrh   pList = Tcl_NewObj();
7175a38705eSdrh   for(i=0; i<nCol; i++){
7185a38705eSdrh     pElem = Tcl_NewStringObj(colv[i+nCol] ? colv[i+nCol] : "NULL", -1);
7195a38705eSdrh     Tcl_ListObjAppendElement(interp, pList, pElem);
7205a38705eSdrh   }
7215a38705eSdrh   Tcl_SetObjResult(interp, pList);
7225a38705eSdrh   return 1;
7235a38705eSdrh }
7245a38705eSdrh 
7255a38705eSdrh /*
7265a38705eSdrh ** Invoke an SQL statement but ignore all the data in the result.  Instead,
7275a38705eSdrh ** return a list that consists of the datatypes of the various columns.
7285a38705eSdrh **
7295a38705eSdrh ** This only works if "PRAGMA show_datatypes=on" has been executed against
7305a38705eSdrh ** the database connection.
7315a38705eSdrh */
7325a38705eSdrh static int sqlite_datatypes(
7335a38705eSdrh   void *NotUsed,
7345a38705eSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
7355a38705eSdrh   int argc,              /* Number of arguments */
7365a38705eSdrh   char **argv            /* Text of each argument */
7375a38705eSdrh ){
7385a38705eSdrh   sqlite *db;
7395a38705eSdrh   int rc;
7405a38705eSdrh   if( argc!=3 ){
7415a38705eSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
7425a38705eSdrh        " DB SQL", 0);
7435a38705eSdrh     return TCL_ERROR;
7445a38705eSdrh   }
745b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
7466f8a503dSdanielk1977   rc = sqlite3_exec(db, argv[2], rememberDataTypes, interp, 0);
7475a38705eSdrh   if( rc!=0 && rc!=SQLITE_ABORT ){
7486f8a503dSdanielk1977     Tcl_AppendResult(interp, sqlite3_error_string(rc), 0);
7495a38705eSdrh     return TCL_ERROR;
7505a38705eSdrh   }
7515a38705eSdrh   return TCL_OK;
7525a38705eSdrh }
7535a38705eSdrh 
754b86ccfb2Sdrh /*
7556f8a503dSdanielk1977 ** Usage:  sqlite3_step  VM  ?NVAR?  ?VALUEVAR?  ?COLNAMEVAR?
756b86ccfb2Sdrh **
757b86ccfb2Sdrh ** Step a virtual machine.  Return a the result code as a string.
758b86ccfb2Sdrh ** Column results are written into three variables.
759b86ccfb2Sdrh */
760b86ccfb2Sdrh static int test_step(
761b86ccfb2Sdrh   void *NotUsed,
762b86ccfb2Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
763b86ccfb2Sdrh   int argc,              /* Number of arguments */
764b86ccfb2Sdrh   char **argv            /* Text of each argument */
765b86ccfb2Sdrh ){
766b86ccfb2Sdrh   sqlite_vm *vm;
767b86ccfb2Sdrh   int rc, i;
7683a84069dSdrh   const char **azValue = 0;
7693a84069dSdrh   const char **azColName = 0;
7703a84069dSdrh   int N = 0;
771b86ccfb2Sdrh   char *zRc;
772b86ccfb2Sdrh   char zBuf[50];
773073e5a77Sdrh   if( argc<2 || argc>5 ){
774b86ccfb2Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
775b86ccfb2Sdrh        " VM NVAR VALUEVAR COLNAMEVAR", 0);
776b86ccfb2Sdrh     return TCL_ERROR;
777b86ccfb2Sdrh   }
778b86ccfb2Sdrh   if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
7796f8a503dSdanielk1977   rc = sqlite3_step(vm, argc>=3?&N:0, argc>=4?&azValue:0, argc==5?&azColName:0);
780073e5a77Sdrh   if( argc>=3 ){
781b86ccfb2Sdrh     sprintf(zBuf, "%d", N);
782b86ccfb2Sdrh     Tcl_SetVar(interp, argv[2], zBuf, 0);
783073e5a77Sdrh   }
784073e5a77Sdrh   if( argc>=4 ){
785b86ccfb2Sdrh     Tcl_SetVar(interp, argv[3], "", 0);
7863a84069dSdrh     if( azValue ){
787b86ccfb2Sdrh       for(i=0; i<N; i++){
788b86ccfb2Sdrh         Tcl_SetVar(interp, argv[3], azValue[i] ? azValue[i] : "",
789b86ccfb2Sdrh             TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
790b86ccfb2Sdrh       }
791b86ccfb2Sdrh     }
792073e5a77Sdrh   }
793073e5a77Sdrh   if( argc==5 ){
794b86ccfb2Sdrh     Tcl_SetVar(interp, argv[4], "", 0);
7953a84069dSdrh     if( azColName ){
796b86ccfb2Sdrh       for(i=0; i<N*2; i++){
797326dce74Sdrh         Tcl_SetVar(interp, argv[4], azColName[i] ? azColName[i] : "",
798b86ccfb2Sdrh             TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
799b86ccfb2Sdrh       }
800b86ccfb2Sdrh     }
801073e5a77Sdrh   }
802b86ccfb2Sdrh   switch( rc ){
803b86ccfb2Sdrh     case SQLITE_DONE:   zRc = "SQLITE_DONE";    break;
804326dce74Sdrh     case SQLITE_BUSY:   zRc = "SQLITE_BUSY";    break;
805326dce74Sdrh     case SQLITE_ROW:    zRc = "SQLITE_ROW";     break;
806326dce74Sdrh     case SQLITE_ERROR:  zRc = "SQLITE_ERROR";   break;
807b86ccfb2Sdrh     case SQLITE_MISUSE: zRc = "SQLITE_MISUSE";  break;
808b86ccfb2Sdrh     default:            zRc = "unknown";        break;
809b86ccfb2Sdrh   }
810b86ccfb2Sdrh   Tcl_AppendResult(interp, zRc, 0);
811b86ccfb2Sdrh   return TCL_OK;
812b86ccfb2Sdrh }
813b86ccfb2Sdrh 
814b86ccfb2Sdrh /*
815106bb236Sdanielk1977 ** Usage:  sqlite3_finalize  STMT
816b86ccfb2Sdrh **
817106bb236Sdanielk1977 ** Finalize a statement handle.
818b86ccfb2Sdrh */
819b86ccfb2Sdrh static int test_finalize(
820106bb236Sdanielk1977   void * clientData,
821106bb236Sdanielk1977   Tcl_Interp *interp,
822106bb236Sdanielk1977   int objc,
823106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
824b86ccfb2Sdrh ){
825106bb236Sdanielk1977   sqlite3_stmt *pStmt;
826b86ccfb2Sdrh   int rc;
827106bb236Sdanielk1977 
828106bb236Sdanielk1977   if( objc!=2 ){
829106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
830106bb236Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
831b86ccfb2Sdrh     return TCL_ERROR;
832b86ccfb2Sdrh   }
833106bb236Sdanielk1977 
834106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
835106bb236Sdanielk1977 
836106bb236Sdanielk1977   rc = sqlite3_finalize_new(pStmt);
837b86ccfb2Sdrh   if( rc ){
838106bb236Sdanielk1977     return TCL_ERROR;
839106bb236Sdanielk1977   }
840106bb236Sdanielk1977   return TCL_OK;
841106bb236Sdanielk1977 }
842106bb236Sdanielk1977 
843106bb236Sdanielk1977 /*
844106bb236Sdanielk1977 ** Usage:  sqlite3_reset  STMT
845106bb236Sdanielk1977 **
846106bb236Sdanielk1977 ** Finalize a statement handle.
847106bb236Sdanielk1977 */
848106bb236Sdanielk1977 static int test_reset(
849106bb236Sdanielk1977   void * clientData,
850106bb236Sdanielk1977   Tcl_Interp *interp,
851106bb236Sdanielk1977   int objc,
852106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
853106bb236Sdanielk1977 ){
854106bb236Sdanielk1977   sqlite3_stmt *pStmt;
855106bb236Sdanielk1977   int rc;
856106bb236Sdanielk1977 
857106bb236Sdanielk1977   if( objc!=2 ){
858106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
859106bb236Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
860106bb236Sdanielk1977     return TCL_ERROR;
861106bb236Sdanielk1977   }
862106bb236Sdanielk1977 
863106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
864106bb236Sdanielk1977 
865106bb236Sdanielk1977   rc = sqlite3_reset_new(pStmt);
866106bb236Sdanielk1977   if( rc ){
867b86ccfb2Sdrh     return TCL_ERROR;
868b86ccfb2Sdrh   }
869b86ccfb2Sdrh   return TCL_OK;
870b86ccfb2Sdrh }
871b86ccfb2Sdrh 
8725a38705eSdrh /*
8736f8a503dSdanielk1977 ** Usage:  sqlite3_reset   VM
87450457896Sdrh **
87550457896Sdrh ** Reset a virtual machine and prepare it to be run again.
87650457896Sdrh */
87750457896Sdrh 
87850457896Sdrh /*
8797c972decSdrh ** This is the "static_bind_value" that variables are bound to when
8806f8a503dSdanielk1977 ** the FLAG option of sqlite3_bind is "static"
88150457896Sdrh */
8827c972decSdrh static char *sqlite_static_bind_value = 0;
8837c972decSdrh 
8847c972decSdrh /*
8856f8a503dSdanielk1977 ** Usage:  sqlite3_bind  VM  IDX  VALUE  FLAGS
8867c972decSdrh **
8877c972decSdrh ** Sets the value of the IDX-th occurance of "?" in the original SQL
8887c972decSdrh ** string.  VALUE is the new value.  If FLAGS=="null" then VALUE is
8897c972decSdrh ** ignored and the value is set to NULL.  If FLAGS=="static" then
8907c972decSdrh ** the value is set to the value of a static variable named
8917c972decSdrh ** "sqlite_static_bind_value".  If FLAGS=="normal" then a copy
8927c972decSdrh ** of the VALUE is made.
8937c972decSdrh */
8947c972decSdrh static int test_bind(
89550457896Sdrh   void *NotUsed,
89650457896Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
89750457896Sdrh   int argc,              /* Number of arguments */
89850457896Sdrh   char **argv            /* Text of each argument */
89950457896Sdrh ){
90050457896Sdrh   sqlite_vm *vm;
90150457896Sdrh   int rc;
9027c972decSdrh   int idx;
9037c972decSdrh   if( argc!=5 ){
90450457896Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
9057c972decSdrh        " VM IDX VALUE (null|static|normal)\"", 0);
90650457896Sdrh     return TCL_ERROR;
90750457896Sdrh   }
90850457896Sdrh   if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
9097c972decSdrh   if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR;
9107c972decSdrh   if( strcmp(argv[4],"null")==0 ){
9116f8a503dSdanielk1977     rc = sqlite3_bind(vm, idx, 0, 0, 0);
9127c972decSdrh   }else if( strcmp(argv[4],"static")==0 ){
9136f8a503dSdanielk1977     rc = sqlite3_bind(vm, idx, sqlite_static_bind_value, -1, 0);
9147c972decSdrh   }else if( strcmp(argv[4],"normal")==0 ){
9156f8a503dSdanielk1977     rc = sqlite3_bind(vm, idx, argv[3], -1, 1);
9167c972decSdrh   }else{
9177c972decSdrh     Tcl_AppendResult(interp, "4th argument should be "
9187c972decSdrh         "\"null\" or \"static\" or \"normal\"", 0);
9197c972decSdrh     return TCL_ERROR;
9207c972decSdrh   }
92150457896Sdrh   if( rc ){
92250457896Sdrh     char zBuf[50];
92350457896Sdrh     sprintf(zBuf, "(%d) ", rc);
9246f8a503dSdanielk1977     Tcl_AppendResult(interp, zBuf, sqlite3_error_string(rc), 0);
92550457896Sdrh     return TCL_ERROR;
92650457896Sdrh   }
92750457896Sdrh   return TCL_OK;
92850457896Sdrh }
92950457896Sdrh 
93050457896Sdrh /*
93199ee3600Sdrh ** Usage:    breakpoint
93299ee3600Sdrh **
93399ee3600Sdrh ** This routine exists for one purpose - to provide a place to put a
93499ee3600Sdrh ** breakpoint with GDB that can be triggered using TCL code.  The use
93599ee3600Sdrh ** for this is when a particular test fails on (say) the 1485th iteration.
93699ee3600Sdrh ** In the TCL test script, we can add code like this:
93799ee3600Sdrh **
93899ee3600Sdrh **     if {$i==1485} breakpoint
93999ee3600Sdrh **
94099ee3600Sdrh ** Then run testfixture in the debugger and wait for the breakpoint to
94199ee3600Sdrh ** fire.  Then additional breakpoints can be set to trace down the bug.
94299ee3600Sdrh */
94399ee3600Sdrh static int test_breakpoint(
94499ee3600Sdrh   void *NotUsed,
94599ee3600Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
94699ee3600Sdrh   int argc,              /* Number of arguments */
94799ee3600Sdrh   char **argv            /* Text of each argument */
94899ee3600Sdrh ){
94999ee3600Sdrh   return TCL_OK;         /* Do nothing */
95099ee3600Sdrh }
95199ee3600Sdrh 
95251e3d8e2Sdanielk1977 static int test_bind_int32(
95351e3d8e2Sdanielk1977   void * clientData,
95451e3d8e2Sdanielk1977   Tcl_Interp *interp,
95551e3d8e2Sdanielk1977   int objc,
95651e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
95751e3d8e2Sdanielk1977 ){
95851e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
95951e3d8e2Sdanielk1977   int idx;
96051e3d8e2Sdanielk1977   int value;
96151e3d8e2Sdanielk1977   int rc;
96251e3d8e2Sdanielk1977 
96351e3d8e2Sdanielk1977   if( objc!=4 ){
96451e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
96551e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
96651e3d8e2Sdanielk1977     return TCL_ERROR;
96751e3d8e2Sdanielk1977   }
96851e3d8e2Sdanielk1977 
96951e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
97051e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
97151e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &value) ) return TCL_ERROR;
97251e3d8e2Sdanielk1977 
97351e3d8e2Sdanielk1977   rc = sqlite3_bind_int32(pStmt, idx, value);
97451e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
97551e3d8e2Sdanielk1977     return TCL_ERROR;
97651e3d8e2Sdanielk1977   }
97751e3d8e2Sdanielk1977 
97851e3d8e2Sdanielk1977   return TCL_OK;
97951e3d8e2Sdanielk1977 }
98051e3d8e2Sdanielk1977 
98151e3d8e2Sdanielk1977 static int test_bind_int64(
98251e3d8e2Sdanielk1977   void * clientData,
98351e3d8e2Sdanielk1977   Tcl_Interp *interp,
98451e3d8e2Sdanielk1977   int objc,
98551e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
98651e3d8e2Sdanielk1977 ){
98751e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
98851e3d8e2Sdanielk1977   int idx;
98951e3d8e2Sdanielk1977   i64 value;
99051e3d8e2Sdanielk1977   int rc;
99151e3d8e2Sdanielk1977 
99251e3d8e2Sdanielk1977   if( objc!=4 ){
99351e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
99451e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
99551e3d8e2Sdanielk1977     return TCL_ERROR;
99651e3d8e2Sdanielk1977   }
99751e3d8e2Sdanielk1977 
99851e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
99951e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
100051e3d8e2Sdanielk1977   if( Tcl_GetWideIntFromObj(interp, objv[3], &value) ) return TCL_ERROR;
100151e3d8e2Sdanielk1977 
100251e3d8e2Sdanielk1977   rc = sqlite3_bind_int64(pStmt, idx, value);
100351e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
100451e3d8e2Sdanielk1977     return TCL_ERROR;
100551e3d8e2Sdanielk1977   }
100651e3d8e2Sdanielk1977 
100751e3d8e2Sdanielk1977   return TCL_OK;
100851e3d8e2Sdanielk1977 }
100951e3d8e2Sdanielk1977 
101051e3d8e2Sdanielk1977 static int test_bind_double(
101151e3d8e2Sdanielk1977   void * clientData,
101251e3d8e2Sdanielk1977   Tcl_Interp *interp,
101351e3d8e2Sdanielk1977   int objc,
101451e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
101551e3d8e2Sdanielk1977 ){
101651e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
101751e3d8e2Sdanielk1977   int idx;
101851e3d8e2Sdanielk1977   double value;
101951e3d8e2Sdanielk1977   int rc;
102051e3d8e2Sdanielk1977 
102151e3d8e2Sdanielk1977   if( objc!=4 ){
102251e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
102351e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
102451e3d8e2Sdanielk1977     return TCL_ERROR;
102551e3d8e2Sdanielk1977   }
102651e3d8e2Sdanielk1977 
102751e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
102851e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
102951e3d8e2Sdanielk1977   if( Tcl_GetDoubleFromObj(interp, objv[3], &value) ) return TCL_ERROR;
103051e3d8e2Sdanielk1977 
103151e3d8e2Sdanielk1977   rc = sqlite3_bind_double(pStmt, idx, value);
103251e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
103351e3d8e2Sdanielk1977     return TCL_ERROR;
103451e3d8e2Sdanielk1977   }
103551e3d8e2Sdanielk1977 
103651e3d8e2Sdanielk1977   return TCL_OK;
103751e3d8e2Sdanielk1977 }
103851e3d8e2Sdanielk1977 
103951e3d8e2Sdanielk1977 static int test_bind_null(
104051e3d8e2Sdanielk1977   void * clientData,
104151e3d8e2Sdanielk1977   Tcl_Interp *interp,
104251e3d8e2Sdanielk1977   int objc,
104351e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
104451e3d8e2Sdanielk1977 ){
104551e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
104651e3d8e2Sdanielk1977   int idx;
104751e3d8e2Sdanielk1977   int rc;
104851e3d8e2Sdanielk1977 
104951e3d8e2Sdanielk1977   if( objc!=3 ){
105051e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
105151e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.>", 0);
105251e3d8e2Sdanielk1977     return TCL_ERROR;
105351e3d8e2Sdanielk1977   }
105451e3d8e2Sdanielk1977 
105551e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
105651e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
105751e3d8e2Sdanielk1977 
105851e3d8e2Sdanielk1977   rc = sqlite3_bind_null(pStmt, idx);
105951e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
106051e3d8e2Sdanielk1977     return TCL_ERROR;
106151e3d8e2Sdanielk1977   }
106251e3d8e2Sdanielk1977 
106351e3d8e2Sdanielk1977   return TCL_OK;
106451e3d8e2Sdanielk1977 }
106551e3d8e2Sdanielk1977 
106651e3d8e2Sdanielk1977 static int test_bind_text(
106751e3d8e2Sdanielk1977   void * clientData,
106851e3d8e2Sdanielk1977   Tcl_Interp *interp,
106951e3d8e2Sdanielk1977   int objc,
107051e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
107151e3d8e2Sdanielk1977 ){
107251e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
107351e3d8e2Sdanielk1977   int idx;
107451e3d8e2Sdanielk1977   int bytes;
107551e3d8e2Sdanielk1977   char *value;
107651e3d8e2Sdanielk1977   int rc;
107751e3d8e2Sdanielk1977 
107851e3d8e2Sdanielk1977   if( objc!=5 ){
107951e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
108051e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
108151e3d8e2Sdanielk1977         " <bytes>", 0);
108251e3d8e2Sdanielk1977     return TCL_ERROR;
108351e3d8e2Sdanielk1977   }
108451e3d8e2Sdanielk1977 
108551e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
108651e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
108751e3d8e2Sdanielk1977   value = Tcl_GetString(objv[3]);
108851e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
108951e3d8e2Sdanielk1977 
109051e3d8e2Sdanielk1977   rc = sqlite3_bind_text(pStmt, idx, value, bytes, 1);
109151e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
109251e3d8e2Sdanielk1977     return TCL_ERROR;
109351e3d8e2Sdanielk1977   }
109451e3d8e2Sdanielk1977 
109551e3d8e2Sdanielk1977   return TCL_OK;
109651e3d8e2Sdanielk1977 }
109751e3d8e2Sdanielk1977 
109851e3d8e2Sdanielk1977 static int test_bind_text16(
109951e3d8e2Sdanielk1977   void * clientData,
110051e3d8e2Sdanielk1977   Tcl_Interp *interp,
110151e3d8e2Sdanielk1977   int objc,
110251e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
110351e3d8e2Sdanielk1977 ){
110451e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
110551e3d8e2Sdanielk1977   int idx;
110651e3d8e2Sdanielk1977   int bytes;
110751e3d8e2Sdanielk1977   char *value;
110851e3d8e2Sdanielk1977   int rc;
110951e3d8e2Sdanielk1977 
111051e3d8e2Sdanielk1977   if( objc!=5 ){
111151e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
111251e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
111351e3d8e2Sdanielk1977         " <bytes>", 0);
111451e3d8e2Sdanielk1977     return TCL_ERROR;
111551e3d8e2Sdanielk1977   }
111651e3d8e2Sdanielk1977 
111751e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
111851e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
111951e3d8e2Sdanielk1977   value = Tcl_GetByteArrayFromObj(objv[3], 0);
112051e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
112151e3d8e2Sdanielk1977 
112251e3d8e2Sdanielk1977   rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, 1);
112351e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
112451e3d8e2Sdanielk1977     return TCL_ERROR;
112551e3d8e2Sdanielk1977   }
112651e3d8e2Sdanielk1977 
112751e3d8e2Sdanielk1977   return TCL_OK;
112851e3d8e2Sdanielk1977 }
112951e3d8e2Sdanielk1977 
113051e3d8e2Sdanielk1977 static int test_bind_blob(
113151e3d8e2Sdanielk1977   void * clientData,
113251e3d8e2Sdanielk1977   Tcl_Interp *interp,
113351e3d8e2Sdanielk1977   int objc,
113451e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
113551e3d8e2Sdanielk1977 ){
113651e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
113751e3d8e2Sdanielk1977   int idx;
113851e3d8e2Sdanielk1977   int bytes;
113951e3d8e2Sdanielk1977   char *value;
114051e3d8e2Sdanielk1977   int rc;
114151e3d8e2Sdanielk1977 
114251e3d8e2Sdanielk1977   if( objc!=5 ){
114351e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
114451e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
114551e3d8e2Sdanielk1977         " <bytes>", 0);
114651e3d8e2Sdanielk1977     return TCL_ERROR;
114751e3d8e2Sdanielk1977   }
114851e3d8e2Sdanielk1977 
114951e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
115051e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
115151e3d8e2Sdanielk1977   value = Tcl_GetString(objv[3]);
115251e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &bytes) ) return TCL_ERROR;
115351e3d8e2Sdanielk1977 
115451e3d8e2Sdanielk1977   rc = sqlite3_bind_blob(pStmt, idx, value, bytes, 1);
115551e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
115651e3d8e2Sdanielk1977     return TCL_ERROR;
115751e3d8e2Sdanielk1977   }
115851e3d8e2Sdanielk1977 
115951e3d8e2Sdanielk1977   return TCL_OK;
116051e3d8e2Sdanielk1977 }
116151e3d8e2Sdanielk1977 
116299ee3600Sdrh /*
11636622cce3Sdanielk1977 ** Usage: sqlite3_errcode DB
11646622cce3Sdanielk1977 **
11656622cce3Sdanielk1977 ** Return the string representation of the most recent sqlite3_* API
11666622cce3Sdanielk1977 ** error code. e.g. "SQLITE_ERROR".
11676622cce3Sdanielk1977 */
11686622cce3Sdanielk1977 static int test_errcode(
11696622cce3Sdanielk1977   void * clientData,
11706622cce3Sdanielk1977   Tcl_Interp *interp,
11716622cce3Sdanielk1977   int objc,
11726622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
11736622cce3Sdanielk1977 ){
11746622cce3Sdanielk1977   sqlite3 *db;
11756622cce3Sdanielk1977 
11766622cce3Sdanielk1977   if( objc!=2 ){
11776622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
11786622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
11796622cce3Sdanielk1977     return TCL_ERROR;
11806622cce3Sdanielk1977   }
11816622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
11826622cce3Sdanielk1977   Tcl_SetResult(interp, (char *)errorName(sqlite3_errcode(db)), 0);
11836622cce3Sdanielk1977   return TCL_OK;
11846622cce3Sdanielk1977 }
11856622cce3Sdanielk1977 
11866622cce3Sdanielk1977 /*
11876622cce3Sdanielk1977 ** Usage:   test_errmsg DB
11886622cce3Sdanielk1977 **
11896622cce3Sdanielk1977 ** Returns the UTF-8 representation of the error message string for the
11906622cce3Sdanielk1977 ** most recent sqlite3_* API call.
11916622cce3Sdanielk1977 */
11926622cce3Sdanielk1977 static int test_errmsg(
11936622cce3Sdanielk1977   void * clientData,
11946622cce3Sdanielk1977   Tcl_Interp *interp,
11956622cce3Sdanielk1977   int objc,
11966622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
11976622cce3Sdanielk1977 ){
11986622cce3Sdanielk1977   sqlite *db;
11996622cce3Sdanielk1977   const char *zErr;
12006622cce3Sdanielk1977 
12016622cce3Sdanielk1977   if( objc!=2 ){
12026622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
12036622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
12046622cce3Sdanielk1977     return TCL_ERROR;
12056622cce3Sdanielk1977   }
12066622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
12076622cce3Sdanielk1977 
12086622cce3Sdanielk1977   zErr = sqlite3_errmsg(db);
12096622cce3Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
12106622cce3Sdanielk1977   return TCL_OK;
12116622cce3Sdanielk1977 }
12126622cce3Sdanielk1977 
12136622cce3Sdanielk1977 /*
12146622cce3Sdanielk1977 ** Usage:   test_errmsg16 DB
12156622cce3Sdanielk1977 **
12166622cce3Sdanielk1977 ** Returns the UTF-16 representation of the error message string for the
12176622cce3Sdanielk1977 ** most recent sqlite3_* API call. This is a byte array object at the TCL
12186622cce3Sdanielk1977 ** level, and it includes the 0x00 0x00 terminator bytes at the end of the
12196622cce3Sdanielk1977 ** UTF-16 string.
12206622cce3Sdanielk1977 */
12216622cce3Sdanielk1977 static int test_errmsg16(
12226622cce3Sdanielk1977   void * clientData,
12236622cce3Sdanielk1977   Tcl_Interp *interp,
12246622cce3Sdanielk1977   int objc,
12256622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
12266622cce3Sdanielk1977 ){
12276622cce3Sdanielk1977   sqlite *db;
12286622cce3Sdanielk1977   const void *zErr;
12296622cce3Sdanielk1977   int bytes;
12306622cce3Sdanielk1977 
12316622cce3Sdanielk1977   if( objc!=2 ){
12326622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
12336622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
12346622cce3Sdanielk1977     return TCL_ERROR;
12356622cce3Sdanielk1977   }
12366622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
12376622cce3Sdanielk1977 
12386622cce3Sdanielk1977   zErr = sqlite3_errmsg16(db);
12396622cce3Sdanielk1977   bytes = sqlite3utf16ByteLen(zErr, -1);
12406622cce3Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes));
12416622cce3Sdanielk1977   return TCL_OK;
12426622cce3Sdanielk1977 }
12436622cce3Sdanielk1977 
12446622cce3Sdanielk1977 /*
12456622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar
12466622cce3Sdanielk1977 **
12476622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
12486622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global
12496622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A
12506622cce3Sdanielk1977 ** STMT handle is returned.
12516622cce3Sdanielk1977 */
12526622cce3Sdanielk1977 static int test_prepare(
12536622cce3Sdanielk1977   void * clientData,
12546622cce3Sdanielk1977   Tcl_Interp *interp,
12556622cce3Sdanielk1977   int objc,
12566622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
12576622cce3Sdanielk1977 ){
12586622cce3Sdanielk1977   sqlite3 *db;
12596622cce3Sdanielk1977   const char *zSql;
12606622cce3Sdanielk1977   int bytes;
12616622cce3Sdanielk1977   const char *zTail = 0;
12626622cce3Sdanielk1977   sqlite3_stmt *pStmt = 0;
12636622cce3Sdanielk1977   char zBuf[50];
12644ad1713cSdanielk1977   int rc;
12656622cce3Sdanielk1977 
12666622cce3Sdanielk1977   if( objc!=5 ){
12676622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
12686622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
12696622cce3Sdanielk1977     return TCL_ERROR;
12706622cce3Sdanielk1977   }
12716622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
12726622cce3Sdanielk1977   zSql = Tcl_GetString(objv[2]);
12736622cce3Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
12746622cce3Sdanielk1977 
12754ad1713cSdanielk1977   rc = sqlite3_prepare(db, zSql, bytes, &pStmt, &zTail);
12766622cce3Sdanielk1977   if( zTail ){
12776622cce3Sdanielk1977     if( bytes>=0 ){
12786622cce3Sdanielk1977       bytes = bytes - (zTail-zSql);
12796622cce3Sdanielk1977     }
12806622cce3Sdanielk1977     Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
12816622cce3Sdanielk1977   }
12824ad1713cSdanielk1977   if( rc!=SQLITE_OK ){
12834ad1713cSdanielk1977     assert( pStmt==0 );
12844ad1713cSdanielk1977     sprintf(zBuf, "(%d) ", rc);
12854ad1713cSdanielk1977     Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
12864ad1713cSdanielk1977     return TCL_ERROR;
12874ad1713cSdanielk1977   }
12886622cce3Sdanielk1977 
12894ad1713cSdanielk1977   if( pStmt ){
12906622cce3Sdanielk1977     if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
12916622cce3Sdanielk1977     Tcl_AppendResult(interp, zBuf, 0);
12924ad1713cSdanielk1977   }
12936622cce3Sdanielk1977   return TCL_OK;
12946622cce3Sdanielk1977 }
12956622cce3Sdanielk1977 
12966622cce3Sdanielk1977 /*
12976622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar
12986622cce3Sdanielk1977 **
12996622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
13006622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global
13016622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A
13026622cce3Sdanielk1977 ** STMT handle is returned.
13036622cce3Sdanielk1977 */
13046622cce3Sdanielk1977 static int test_prepare16(
13056622cce3Sdanielk1977   void * clientData,
13066622cce3Sdanielk1977   Tcl_Interp *interp,
13076622cce3Sdanielk1977   int objc,
13086622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
13096622cce3Sdanielk1977 ){
13106622cce3Sdanielk1977   sqlite3 *db;
13116622cce3Sdanielk1977   const void *zSql;
13126622cce3Sdanielk1977   const void *zTail = 0;
13136622cce3Sdanielk1977   Tcl_Obj *pTail = 0;
13146622cce3Sdanielk1977   sqlite3_stmt *pStmt = 0;
13156622cce3Sdanielk1977   char zBuf[50];
13166622cce3Sdanielk1977   int bytes;                /* The integer specified as arg 3 */
13176622cce3Sdanielk1977   int objlen;               /* The byte-array length of arg 2 */
13186622cce3Sdanielk1977 
13196622cce3Sdanielk1977   if( objc!=5 ){
13206622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
13216622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
13226622cce3Sdanielk1977     return TCL_ERROR;
13236622cce3Sdanielk1977   }
13246622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
13256622cce3Sdanielk1977   zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen);
13266622cce3Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
13276622cce3Sdanielk1977 
13286622cce3Sdanielk1977   if( SQLITE_OK!=sqlite3_prepare16(db, zSql, bytes, &pStmt, &zTail) ){
13296622cce3Sdanielk1977     return TCL_ERROR;
13306622cce3Sdanielk1977   }
13316622cce3Sdanielk1977 
13326622cce3Sdanielk1977   if( zTail ){
13336622cce3Sdanielk1977     objlen = objlen - ((u8 *)zTail-(u8 *)zSql);
13346622cce3Sdanielk1977   }else{
13356622cce3Sdanielk1977     objlen = 0;
13366622cce3Sdanielk1977   }
13376622cce3Sdanielk1977   pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen);
13386622cce3Sdanielk1977   Tcl_IncrRefCount(pTail);
13396622cce3Sdanielk1977   Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0);
13404ad1713cSdanielk1977   Tcl_DecrRefCount(pTail);
13416622cce3Sdanielk1977 
13424ad1713cSdanielk1977   if( pStmt ){
13436622cce3Sdanielk1977     if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
13444ad1713cSdanielk1977   }
13456622cce3Sdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
13466622cce3Sdanielk1977   return TCL_OK;
13476622cce3Sdanielk1977 }
13486622cce3Sdanielk1977 
13494ad1713cSdanielk1977 /*
13504ad1713cSdanielk1977 ** Usage: sqlite3_open filename ?options-list?
13514ad1713cSdanielk1977 */
13524ad1713cSdanielk1977 static int test_open(
13534ad1713cSdanielk1977   void * clientData,
13544ad1713cSdanielk1977   Tcl_Interp *interp,
13554ad1713cSdanielk1977   int objc,
13564ad1713cSdanielk1977   Tcl_Obj *CONST objv[]
13574ad1713cSdanielk1977 ){
13584ad1713cSdanielk1977   const char *zFilename;
13594ad1713cSdanielk1977   sqlite3 *db;
13604ad1713cSdanielk1977   int rc;
13614ad1713cSdanielk1977   char zBuf[100];
13624ad1713cSdanielk1977 
13634ad1713cSdanielk1977   if( objc!=3 && objc!=2 ){
13644ad1713cSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
13654ad1713cSdanielk1977        Tcl_GetString(objv[0]), " filename options-list", 0);
13664ad1713cSdanielk1977     return TCL_ERROR;
13674ad1713cSdanielk1977   }
13684ad1713cSdanielk1977 
13694ad1713cSdanielk1977   zFilename = Tcl_GetString(objv[1]);
1370*80290863Sdanielk1977   rc = sqlite3_open(zFilename, &db, 0);
13714ad1713cSdanielk1977 
13724ad1713cSdanielk1977   if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
13734ad1713cSdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
13744ad1713cSdanielk1977   return TCL_OK;
13754ad1713cSdanielk1977 }
13764ad1713cSdanielk1977 
13774ad1713cSdanielk1977 /*
13784ad1713cSdanielk1977 ** Usage: sqlite3_open16 filename options
13794ad1713cSdanielk1977 */
13804ad1713cSdanielk1977 static int test_open16(
13814ad1713cSdanielk1977   void * clientData,
13824ad1713cSdanielk1977   Tcl_Interp *interp,
13834ad1713cSdanielk1977   int objc,
13844ad1713cSdanielk1977   Tcl_Obj *CONST objv[]
13854ad1713cSdanielk1977 ){
13864ad1713cSdanielk1977   const void *zFilename;
13874ad1713cSdanielk1977   sqlite3 *db;
13884ad1713cSdanielk1977   int rc;
13894ad1713cSdanielk1977   char zBuf[100];
13904ad1713cSdanielk1977 
13914ad1713cSdanielk1977   if( objc!=3 ){
13924ad1713cSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
13934ad1713cSdanielk1977        Tcl_GetString(objv[0]), " filename options-list", 0);
13944ad1713cSdanielk1977     return TCL_ERROR;
13954ad1713cSdanielk1977   }
13964ad1713cSdanielk1977 
13974ad1713cSdanielk1977   zFilename = Tcl_GetByteArrayFromObj(objv[1], 0);
13984ad1713cSdanielk1977   rc = sqlite3_open16(zFilename, &db, 0);
13994ad1713cSdanielk1977 
14004ad1713cSdanielk1977   if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
14014ad1713cSdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
14024ad1713cSdanielk1977   return TCL_OK;
14034ad1713cSdanielk1977 }
1404d3d39e93Sdrh 
1405d3d39e93Sdrh /*
1406106bb236Sdanielk1977 ** Usage: sqlite3_step STMT
1407106bb236Sdanielk1977 **
1408106bb236Sdanielk1977 ** Advance the statement to the next row.
1409106bb236Sdanielk1977 */
1410106bb236Sdanielk1977 static int test_step_new(
1411106bb236Sdanielk1977   void * clientData,
1412106bb236Sdanielk1977   Tcl_Interp *interp,
1413106bb236Sdanielk1977   int objc,
1414106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
1415106bb236Sdanielk1977 ){
1416106bb236Sdanielk1977   sqlite3_stmt *pStmt;
1417106bb236Sdanielk1977   int rc;
1418106bb236Sdanielk1977 
1419106bb236Sdanielk1977   if( objc!=3 ){
1420106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1421106bb236Sdanielk1977        Tcl_GetString(objv[0]), " STMT", 0);
1422106bb236Sdanielk1977     return TCL_ERROR;
1423106bb236Sdanielk1977   }
1424106bb236Sdanielk1977 
1425106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
1426106bb236Sdanielk1977   rc = sqlite3_step_new(pStmt);
1427106bb236Sdanielk1977 
1428106bb236Sdanielk1977   if( rc!=SQLITE_OK ) return TCL_ERROR;
1429106bb236Sdanielk1977   return TCL_OK;
1430106bb236Sdanielk1977 }
1431106bb236Sdanielk1977 
1432106bb236Sdanielk1977 /*
1433d3d39e93Sdrh ** This is a collating function named "REVERSE" which sorts text
1434d3d39e93Sdrh ** in reverse order.
1435d3d39e93Sdrh */
1436d3d39e93Sdrh static int reverseCollatingFunc(
1437d3d39e93Sdrh   void *NotUsed,
1438d3d39e93Sdrh   int nKey1, const void *pKey1,
1439d3d39e93Sdrh   int nKey2, const void *pKey2
1440d3d39e93Sdrh ){
1441d3d39e93Sdrh   int rc, n;
1442d3d39e93Sdrh   n = nKey1<nKey2 ? nKey1 : nKey2;
1443d3d39e93Sdrh   rc = memcmp(pKey1, pKey2, n);
1444d3d39e93Sdrh   if( rc==0 ){
1445d3d39e93Sdrh     rc = nKey1 - nKey2;
1446d3d39e93Sdrh   }
1447d3d39e93Sdrh   return -rc;
1448d3d39e93Sdrh }
1449d3d39e93Sdrh 
1450d3d39e93Sdrh /*
1451d3d39e93Sdrh ** Usage: add_reverse_collating_func DB
1452d3d39e93Sdrh **
1453d3d39e93Sdrh ** This routine adds a collation named "REVERSE" to database given.
1454d3d39e93Sdrh ** REVERSE is used for testing only.
1455d3d39e93Sdrh */
1456d3d39e93Sdrh static int reverse_collfunc(
1457d3d39e93Sdrh   void * clientData,
1458d3d39e93Sdrh   Tcl_Interp *interp,
1459d3d39e93Sdrh   int objc,
1460d3d39e93Sdrh   Tcl_Obj *CONST objv[]
1461d3d39e93Sdrh ){
1462d3d39e93Sdrh   sqlite3 *db;
1463d3d39e93Sdrh 
1464d3d39e93Sdrh   if( objc!=2 ){
1465d3d39e93Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB");
1466d3d39e93Sdrh     return TCL_ERROR;
1467d3d39e93Sdrh   }
1468d3d39e93Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1469d3d39e93Sdrh   sqlite3ChangeCollatingFunction(db, "REVERSE", 7, 0, reverseCollatingFunc);
1470d3d39e93Sdrh   return TCL_OK;
1471d3d39e93Sdrh }
1472d3d39e93Sdrh 
1473d3d39e93Sdrh 
14746622cce3Sdanielk1977 /*
1475d1bf3512Sdrh ** Register commands with the TCL interpreter.
1476d1bf3512Sdrh */
1477d1bf3512Sdrh int Sqlitetest1_Init(Tcl_Interp *interp){
14786f8a503dSdanielk1977   extern int sqlite3_search_count;
14796f8a503dSdanielk1977   extern int sqlite3_interrupt_count;
14806f8a503dSdanielk1977   extern int sqlite3_open_file_count;
14816f8a503dSdanielk1977   extern int sqlite3_current_time;
1482c2eef3b3Sdrh   static struct {
1483c2eef3b3Sdrh      char *zName;
1484c2eef3b3Sdrh      Tcl_CmdProc *xProc;
1485c2eef3b3Sdrh   } aCmd[] = {
14866f8a503dSdanielk1977      { "sqlite3_mprintf_int",           (Tcl_CmdProc*)sqlite3_mprintf_int    },
14876f8a503dSdanielk1977      { "sqlite3_mprintf_str",           (Tcl_CmdProc*)sqlite3_mprintf_str    },
14886f8a503dSdanielk1977      { "sqlite3_mprintf_double",        (Tcl_CmdProc*)sqlite3_mprintf_double },
14896f8a503dSdanielk1977      { "sqlite3_mprintf_scaled",        (Tcl_CmdProc*)sqlite3_mprintf_scaled },
14906f8a503dSdanielk1977      { "sqlite3_mprintf_z_test",        (Tcl_CmdProc*)test_mprintf_z        },
14914ad1713cSdanielk1977 //     { "sqlite3_open",                  (Tcl_CmdProc*)sqlite_test_open      },
14926f8a503dSdanielk1977      { "sqlite3_last_insert_rowid",     (Tcl_CmdProc*)test_last_rowid       },
14936f8a503dSdanielk1977      { "sqlite3_exec_printf",           (Tcl_CmdProc*)test_exec_printf      },
14946f8a503dSdanielk1977      { "sqlite3_get_table_printf",      (Tcl_CmdProc*)test_get_table_printf },
14956f8a503dSdanielk1977      { "sqlite3_close",                 (Tcl_CmdProc*)sqlite_test_close     },
14966f8a503dSdanielk1977      { "sqlite3_create_function",       (Tcl_CmdProc*)test_create_function  },
14976f8a503dSdanielk1977      { "sqlite3_create_aggregate",      (Tcl_CmdProc*)test_create_aggregate },
1498c2eef3b3Sdrh      { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func    },
1499c2eef3b3Sdrh      { "sqlite_abort",                  (Tcl_CmdProc*)sqlite_abort          },
15005a38705eSdrh      { "sqlite_datatypes",              (Tcl_CmdProc*)sqlite_datatypes      },
1501c2eef3b3Sdrh #ifdef MEMORY_DEBUG
1502c2eef3b3Sdrh      { "sqlite_malloc_fail",            (Tcl_CmdProc*)sqlite_malloc_fail    },
1503c2eef3b3Sdrh      { "sqlite_malloc_stat",            (Tcl_CmdProc*)sqlite_malloc_stat    },
1504c2eef3b3Sdrh #endif
150596fc5fe6Sdanielk1977      { "sqlite_step",                    (Tcl_CmdProc*)test_step             },
1506106bb236Sdanielk1977 // { "sqlite_finalize",                (Tcl_CmdProc*)test_finalize         },
150796fc5fe6Sdanielk1977      { "sqlite_bind",                    (Tcl_CmdProc*)test_bind             },
1508106bb236Sdanielk1977 // { "sqlite_reset",                   (Tcl_CmdProc*)test_reset            },
150999ee3600Sdrh      { "breakpoint",                     (Tcl_CmdProc*)test_breakpoint       },
1510c2eef3b3Sdrh   };
151151e3d8e2Sdanielk1977   static struct {
151251e3d8e2Sdanielk1977      char *zName;
151351e3d8e2Sdanielk1977      Tcl_ObjCmdProc *xProc;
151451e3d8e2Sdanielk1977   } aObjCmd[] = {
151551e3d8e2Sdanielk1977      { "sqlite3_bind_int32",            (Tcl_ObjCmdProc*)test_bind_int32    },
151651e3d8e2Sdanielk1977      { "sqlite3_bind_int64",            (Tcl_ObjCmdProc*)test_bind_int64    },
151751e3d8e2Sdanielk1977      { "sqlite3_bind_double",           (Tcl_ObjCmdProc*)test_bind_double   },
151851e3d8e2Sdanielk1977      { "sqlite3_bind_null",             (Tcl_ObjCmdProc*)test_bind_null     },
151951e3d8e2Sdanielk1977      { "sqlite3_bind_text",             (Tcl_ObjCmdProc*)test_bind_text     },
152051e3d8e2Sdanielk1977      { "sqlite3_bind_text16",           (Tcl_ObjCmdProc*)test_bind_text16   },
152151e3d8e2Sdanielk1977      { "sqlite3_bind_blob",             (Tcl_ObjCmdProc*)test_bind_blob     },
15226622cce3Sdanielk1977      { "sqlite3_errcode",               (Tcl_ObjCmdProc*)test_errcode       },
15236622cce3Sdanielk1977      { "sqlite3_errmsg",                (Tcl_ObjCmdProc*)test_errmsg        },
15246622cce3Sdanielk1977      { "sqlite3_errmsg16",              (Tcl_ObjCmdProc*)test_errmsg16      },
15256622cce3Sdanielk1977      { "sqlite3_prepare",               (Tcl_ObjCmdProc*)test_prepare       },
15266622cce3Sdanielk1977      { "sqlite3_prepare16",             (Tcl_ObjCmdProc*)test_prepare16     },
15274ad1713cSdanielk1977      { "sqlite3_open",                  (Tcl_ObjCmdProc*)test_open          },
15284ad1713cSdanielk1977      { "sqlite3_open16",                (Tcl_ObjCmdProc*)test_open16        },
1529106bb236Sdanielk1977      { "sqlite3_finalize",              (Tcl_ObjCmdProc*)test_finalize     },
1530106bb236Sdanielk1977      { "sqlite3_reset",                 (Tcl_ObjCmdProc*)test_reset        },
1531106bb236Sdanielk1977      { "sqlite3_step",                  (Tcl_ObjCmdProc*)test_step_new      },
1532d3d39e93Sdrh      { "add_reverse_collating_func",    (Tcl_ObjCmdProc*)reverse_collfunc   },
153351e3d8e2Sdanielk1977   };
1534c2eef3b3Sdrh   int i;
1535c2eef3b3Sdrh 
1536c2eef3b3Sdrh   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
1537c2eef3b3Sdrh     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
1538c2eef3b3Sdrh   }
153951e3d8e2Sdanielk1977   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
154051e3d8e2Sdanielk1977     Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
154151e3d8e2Sdanielk1977   }
15426490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_search_count",
15436f8a503dSdanielk1977       (char*)&sqlite3_search_count, TCL_LINK_INT);
15446490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_interrupt_count",
15456f8a503dSdanielk1977       (char*)&sqlite3_interrupt_count, TCL_LINK_INT);
15466490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_open_file_count",
15476f8a503dSdanielk1977       (char*)&sqlite3_open_file_count, TCL_LINK_INT);
15486490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_current_time",
15496f8a503dSdanielk1977       (char*)&sqlite3_current_time, TCL_LINK_INT);
15507c972decSdrh   Tcl_LinkVar(interp, "sqlite_static_bind_value",
15517c972decSdrh       (char*)&sqlite_static_bind_value, TCL_LINK_STRING);
1552d1bf3512Sdrh   return TCL_OK;
1553d1bf3512Sdrh }
1554