xref: /sqlite-3.40.0/src/test1.c (revision 6ddcca55)
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*6ddcca55Sdanielk1977 ** $Id: test1.c,v 1.49 2004/05/24 23:48:27 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 */
31051ad0ecdSdanielk1977 static void ifnullFunc(sqlite_func *context, int argc, sqlite3_value **argv){
311c22bd47dSdrh   int i;
312c22bd47dSdrh   for(i=0; i<argc; i++){
31351ad0ecdSdanielk1977     if( SQLITE3_NULL!=sqlite3_value_type(argv[i]) ){
31451ad0ecdSdanielk1977       sqlite3_set_result_string(context, sqlite3_value_data(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 */
37951ad0ecdSdanielk1977 static void sqlite3ExecFunc(
38051ad0ecdSdanielk1977   sqlite_func *context,
38151ad0ecdSdanielk1977   int argc,
38251ad0ecdSdanielk1977   sqlite3_value **argv
38351ad0ecdSdanielk1977 ){
384d1d9fc33Sdrh   struct dstr x;
385d1d9fc33Sdrh   memset(&x, 0, sizeof(x));
38651ad0ecdSdanielk1977   sqlite3_exec((sqlite*)sqlite3_user_data(context),
38751ad0ecdSdanielk1977       sqlite3_value_data(argv[0]),
388d1d9fc33Sdrh       execFuncCallback, &x, 0);
3896f8a503dSdanielk1977   sqlite3_set_result_string(context, x.z, x.nUsed);
390d1d9fc33Sdrh   sqliteFree(x.z);
391c22bd47dSdrh }
392c22bd47dSdrh 
393c22bd47dSdrh /*
394c22bd47dSdrh ** Usage:  sqlite_test_create_function DB
395c22bd47dSdrh **
3966f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order
397c22bd47dSdrh ** to create a function named "x_coalesce".  This function does the same thing
398c22bd47dSdrh ** as the "coalesce" function.  This function also registers an SQL function
3996f8a503dSdanielk1977 ** named "x_sqlite3_exec" that invokes sqlite3_exec().  Invoking sqlite3_exec()
400c22bd47dSdrh ** in this way is illegal recursion and should raise an SQLITE_MISUSE error.
401c22bd47dSdrh ** The effect is similar to trying to use the same database connection from
402c22bd47dSdrh ** two threads at the same time.
403c22bd47dSdrh **
404c22bd47dSdrh ** The original motivation for this routine was to be able to call the
4056f8a503dSdanielk1977 ** sqlite3_create_function function while a query is in progress in order
406c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
407c22bd47dSdrh */
408c2eef3b3Sdrh static int test_create_function(
409c22bd47dSdrh   void *NotUsed,
410c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
411c22bd47dSdrh   int argc,              /* Number of arguments */
412c22bd47dSdrh   char **argv            /* Text of each argument */
413c22bd47dSdrh ){
414c22bd47dSdrh   sqlite *db;
415c22bd47dSdrh   extern void Md5_Register(sqlite*);
416c22bd47dSdrh   if( argc!=2 ){
417c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
418c22bd47dSdrh        " FILENAME\"", 0);
419c22bd47dSdrh     return TCL_ERROR;
420c22bd47dSdrh   }
421b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
4226f8a503dSdanielk1977   sqlite3_create_function(db, "x_coalesce", -1, ifnullFunc, 0);
4236f8a503dSdanielk1977   sqlite3_create_function(db, "x_sqlite3_exec", 1, sqlite3ExecFunc, db);
424c22bd47dSdrh   return TCL_OK;
425c22bd47dSdrh }
426c22bd47dSdrh 
427c22bd47dSdrh /*
428c22bd47dSdrh ** Routines to implement the x_count() aggregate function.
429c22bd47dSdrh */
430c22bd47dSdrh typedef struct CountCtx CountCtx;
431c22bd47dSdrh struct CountCtx {
432c22bd47dSdrh   int n;
433c22bd47dSdrh };
434*6ddcca55Sdanielk1977 static void countStep(sqlite_func *context, int argc, sqlite3_value **argv){
435c22bd47dSdrh   CountCtx *p;
4366f8a503dSdanielk1977   p = sqlite3_aggregate_context(context, sizeof(*p));
437*6ddcca55Sdanielk1977   if( (argc==0 || SQLITE3_NULL!=sqlite3_value_type(argv[0]) ) && p ){
438c22bd47dSdrh     p->n++;
439c22bd47dSdrh   }
440c22bd47dSdrh }
441c22bd47dSdrh static void countFinalize(sqlite_func *context){
442c22bd47dSdrh   CountCtx *p;
4436f8a503dSdanielk1977   p = sqlite3_aggregate_context(context, sizeof(*p));
4446f8a503dSdanielk1977   sqlite3_set_result_int(context, p ? p->n : 0);
445c22bd47dSdrh }
446c22bd47dSdrh 
447c22bd47dSdrh /*
448c22bd47dSdrh ** Usage:  sqlite_test_create_aggregate DB
449c22bd47dSdrh **
4506f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order
451c22bd47dSdrh ** to create a function named "x_count".  This function does the same thing
452c22bd47dSdrh ** as the "md5sum" function.
453c22bd47dSdrh **
454c22bd47dSdrh ** The original motivation for this routine was to be able to call the
4556f8a503dSdanielk1977 ** sqlite3_create_aggregate function while a query is in progress in order
456c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
457c22bd47dSdrh */
458c2eef3b3Sdrh static int test_create_aggregate(
459c22bd47dSdrh   void *NotUsed,
460c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
461c22bd47dSdrh   int argc,              /* Number of arguments */
462c22bd47dSdrh   char **argv            /* Text of each argument */
463c22bd47dSdrh ){
464c22bd47dSdrh   sqlite *db;
465c22bd47dSdrh   if( argc!=2 ){
466c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
467c22bd47dSdrh        " FILENAME\"", 0);
468c22bd47dSdrh     return TCL_ERROR;
469c22bd47dSdrh   }
470b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
4716f8a503dSdanielk1977   sqlite3_create_aggregate(db, "x_count", 0, countStep, countFinalize, 0);
4726f8a503dSdanielk1977   sqlite3_create_aggregate(db, "x_count", 1, countStep, countFinalize, 0);
473c22bd47dSdrh   return TCL_OK;
474c22bd47dSdrh }
475c22bd47dSdrh 
476c22bd47dSdrh 
477c22bd47dSdrh 
478c22bd47dSdrh /*
4796f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER
480d1bf3512Sdrh **
481d1bf3512Sdrh ** Call mprintf with three integer arguments
482d1bf3512Sdrh */
4836f8a503dSdanielk1977 static int sqlite3_mprintf_int(
484d1bf3512Sdrh   void *NotUsed,
485d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
486d1bf3512Sdrh   int argc,              /* Number of arguments */
487d1bf3512Sdrh   char **argv            /* Text of each argument */
488d1bf3512Sdrh ){
489d1bf3512Sdrh   int a[3], i;
490d1bf3512Sdrh   char *z;
491d1bf3512Sdrh   if( argc!=5 ){
492d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
493d1bf3512Sdrh        " FORMAT INT INT INT\"", 0);
494d1bf3512Sdrh     return TCL_ERROR;
495d1bf3512Sdrh   }
496d1bf3512Sdrh   for(i=2; i<5; i++){
497d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
498d1bf3512Sdrh   }
4996f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]);
500d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
5016f8a503dSdanielk1977   sqlite3_freemem(z);
502d1bf3512Sdrh   return TCL_OK;
503d1bf3512Sdrh }
504d1bf3512Sdrh 
505d1bf3512Sdrh /*
5066f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT INTEGER INTEGER STRING
507d1bf3512Sdrh **
508d1bf3512Sdrh ** Call mprintf with two integer arguments and one string argument
509d1bf3512Sdrh */
5106f8a503dSdanielk1977 static int sqlite3_mprintf_str(
511d1bf3512Sdrh   void *NotUsed,
512d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
513d1bf3512Sdrh   int argc,              /* Number of arguments */
514d1bf3512Sdrh   char **argv            /* Text of each argument */
515d1bf3512Sdrh ){
516d1bf3512Sdrh   int a[3], i;
517d1bf3512Sdrh   char *z;
518f220b24fSchw   if( argc<4 || argc>5 ){
519d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
520f220b24fSchw        " FORMAT INT INT ?STRING?\"", 0);
521d1bf3512Sdrh     return TCL_ERROR;
522d1bf3512Sdrh   }
523d1bf3512Sdrh   for(i=2; i<4; i++){
524d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
525d1bf3512Sdrh   }
5266f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL);
527d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
5286f8a503dSdanielk1977   sqlite3_freemem(z);
529d1bf3512Sdrh   return TCL_OK;
530d1bf3512Sdrh }
531d1bf3512Sdrh 
532d1bf3512Sdrh /*
5336f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT INTEGER INTEGER DOUBLE
534d1bf3512Sdrh **
535d1bf3512Sdrh ** Call mprintf with two integer arguments and one double argument
536d1bf3512Sdrh */
5376f8a503dSdanielk1977 static int sqlite3_mprintf_double(
538d1bf3512Sdrh   void *NotUsed,
539d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
540d1bf3512Sdrh   int argc,              /* Number of arguments */
541d1bf3512Sdrh   char **argv            /* Text of each argument */
542d1bf3512Sdrh ){
543d1bf3512Sdrh   int a[3], i;
544d1bf3512Sdrh   double r;
545d1bf3512Sdrh   char *z;
546d1bf3512Sdrh   if( argc!=5 ){
547d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
548d1bf3512Sdrh        " FORMAT INT INT STRING\"", 0);
549d1bf3512Sdrh     return TCL_ERROR;
550d1bf3512Sdrh   }
551d1bf3512Sdrh   for(i=2; i<4; i++){
552d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
553d1bf3512Sdrh   }
554d1bf3512Sdrh   if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR;
5556f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], r);
556d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
5576f8a503dSdanielk1977   sqlite3_freemem(z);
558d1bf3512Sdrh   return TCL_OK;
559d1bf3512Sdrh }
560d1bf3512Sdrh 
561d1bf3512Sdrh /*
5626f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT DOUBLE DOUBLE
563b621c237Sdrh **
564b621c237Sdrh ** Call mprintf with a single double argument which is the product of the
565b621c237Sdrh ** two arguments given above.  This is used to generate overflow and underflow
566b621c237Sdrh ** doubles to test that they are converted properly.
567b621c237Sdrh */
5686f8a503dSdanielk1977 static int sqlite3_mprintf_scaled(
569b621c237Sdrh   void *NotUsed,
570b621c237Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
571b621c237Sdrh   int argc,              /* Number of arguments */
572b621c237Sdrh   char **argv            /* Text of each argument */
573b621c237Sdrh ){
574b621c237Sdrh   int i;
575b621c237Sdrh   double r[2];
576b621c237Sdrh   char *z;
577b621c237Sdrh   if( argc!=4 ){
578b621c237Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
579b621c237Sdrh        " FORMAT DOUBLE DOUBLE\"", 0);
580b621c237Sdrh     return TCL_ERROR;
581b621c237Sdrh   }
582b621c237Sdrh   for(i=2; i<4; i++){
583b621c237Sdrh     if( Tcl_GetDouble(interp, argv[i], &r[i-2]) ) return TCL_ERROR;
584b621c237Sdrh   }
5856f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], r[0]*r[1]);
586b621c237Sdrh   Tcl_AppendResult(interp, z, 0);
5876f8a503dSdanielk1977   sqlite3_freemem(z);
588b621c237Sdrh   return TCL_OK;
589b621c237Sdrh }
590b621c237Sdrh 
591b621c237Sdrh /*
592daffd0e5Sdrh ** Usage: sqlite_malloc_fail N
593daffd0e5Sdrh **
594afa4a020Sdrh ** Rig sqliteMalloc() to fail on the N-th call.  Turn off this mechanism
5956f8a503dSdanielk1977 ** and reset the sqlite3_malloc_failed variable is N==0.
596daffd0e5Sdrh */
597daffd0e5Sdrh #ifdef MEMORY_DEBUG
598daffd0e5Sdrh static int sqlite_malloc_fail(
599daffd0e5Sdrh   void *NotUsed,
600daffd0e5Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
601daffd0e5Sdrh   int argc,              /* Number of arguments */
602daffd0e5Sdrh   char **argv            /* Text of each argument */
603daffd0e5Sdrh ){
604daffd0e5Sdrh   int n;
605daffd0e5Sdrh   if( argc!=2 ){
606daffd0e5Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0);
607daffd0e5Sdrh     return TCL_ERROR;
608daffd0e5Sdrh   }
609daffd0e5Sdrh   if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
6106f8a503dSdanielk1977   sqlite3_iMallocFail = n;
6116f8a503dSdanielk1977   sqlite3_malloc_failed = 0;
612daffd0e5Sdrh   return TCL_OK;
613daffd0e5Sdrh }
614daffd0e5Sdrh #endif
615daffd0e5Sdrh 
616daffd0e5Sdrh /*
617daffd0e5Sdrh ** Usage: sqlite_malloc_stat
618daffd0e5Sdrh **
619daffd0e5Sdrh ** Return the number of prior calls to sqliteMalloc() and sqliteFree().
620daffd0e5Sdrh */
621daffd0e5Sdrh #ifdef MEMORY_DEBUG
622daffd0e5Sdrh static int sqlite_malloc_stat(
623daffd0e5Sdrh   void *NotUsed,
624daffd0e5Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
625daffd0e5Sdrh   int argc,              /* Number of arguments */
626daffd0e5Sdrh   char **argv            /* Text of each argument */
627daffd0e5Sdrh ){
628daffd0e5Sdrh   char zBuf[200];
6296f8a503dSdanielk1977   sprintf(zBuf, "%d %d %d", sqlite3_nMalloc, sqlite3_nFree, sqlite3_iMallocFail);
630daffd0e5Sdrh   Tcl_AppendResult(interp, zBuf, 0);
631daffd0e5Sdrh   return TCL_OK;
632daffd0e5Sdrh }
633daffd0e5Sdrh #endif
634daffd0e5Sdrh 
635daffd0e5Sdrh /*
63628b4e489Sdrh ** Usage:  sqlite_abort
63728b4e489Sdrh **
63828b4e489Sdrh ** Shutdown the process immediately.  This is not a clean shutdown.
63928b4e489Sdrh ** This command is used to test the recoverability of a database in
64028b4e489Sdrh ** the event of a program crash.
64128b4e489Sdrh */
64228b4e489Sdrh static int sqlite_abort(
64328b4e489Sdrh   void *NotUsed,
64428b4e489Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
64528b4e489Sdrh   int argc,              /* Number of arguments */
64628b4e489Sdrh   char **argv            /* Text of each argument */
64728b4e489Sdrh ){
64828b4e489Sdrh   assert( interp==0 );   /* This will always fail */
64928b4e489Sdrh   return TCL_OK;
65028b4e489Sdrh }
65128b4e489Sdrh 
65228b4e489Sdrh /*
6536cbe1f1bSdrh ** The following routine is a user-defined SQL function whose purpose
6546cbe1f1bSdrh ** is to test the sqlite_set_result() API.
6556cbe1f1bSdrh */
65651ad0ecdSdanielk1977 static void testFunc(sqlite_func *context, int argc, sqlite3_value **argv){
6576cbe1f1bSdrh   while( argc>=2 ){
65851ad0ecdSdanielk1977     const char *zArg0 = sqlite3_value_data(argv[0]);
65951ad0ecdSdanielk1977     const char *zArg1 = sqlite3_value_data(argv[1]);
66051ad0ecdSdanielk1977     if( zArg0==0 ){
6616f8a503dSdanielk1977       sqlite3_set_result_error(context, "first argument to test function "
6626cbe1f1bSdrh          "may not be NULL", -1);
66351ad0ecdSdanielk1977     }else if( sqlite3StrICmp(zArg0,"string")==0 ){
66451ad0ecdSdanielk1977       sqlite3_set_result_string(context, zArg1, -1);
66551ad0ecdSdanielk1977     }else if( zArg1==0 ){
6666f8a503dSdanielk1977       sqlite3_set_result_error(context, "2nd argument may not be NULL if the "
6676cbe1f1bSdrh          "first argument is not \"string\"", -1);
66851ad0ecdSdanielk1977     }else if( sqlite3StrICmp(zArg0,"int")==0 ){
66951ad0ecdSdanielk1977       sqlite3_set_result_int(context, atoi(zArg1));
67051ad0ecdSdanielk1977     }else if( sqlite3StrICmp(zArg0,"double")==0 ){
67151ad0ecdSdanielk1977       sqlite3_set_result_double(context, sqlite3AtoF(zArg1, 0));
6726cbe1f1bSdrh     }else{
6736f8a503dSdanielk1977       sqlite3_set_result_error(context,"first argument should be one of: "
6746cbe1f1bSdrh           "string int double", -1);
6756cbe1f1bSdrh     }
6766cbe1f1bSdrh     argc -= 2;
6776cbe1f1bSdrh     argv += 2;
6786cbe1f1bSdrh   }
6796cbe1f1bSdrh }
6806cbe1f1bSdrh 
6816cbe1f1bSdrh /*
6826cbe1f1bSdrh ** Usage:   sqlite_register_test_function  DB  NAME
6836cbe1f1bSdrh **
6846cbe1f1bSdrh ** Register the test SQL function on the database DB under the name NAME.
6856cbe1f1bSdrh */
686c2eef3b3Sdrh static int test_register_func(
6876cbe1f1bSdrh   void *NotUsed,
6886cbe1f1bSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6896cbe1f1bSdrh   int argc,              /* Number of arguments */
6906cbe1f1bSdrh   char **argv            /* Text of each argument */
6916cbe1f1bSdrh ){
6926cbe1f1bSdrh   sqlite *db;
6936cbe1f1bSdrh   int rc;
6946cbe1f1bSdrh   if( argc!=3 ){
6956cbe1f1bSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
6966cbe1f1bSdrh        " DB FUNCTION-NAME", 0);
6976cbe1f1bSdrh     return TCL_ERROR;
6986cbe1f1bSdrh   }
699b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
7006f8a503dSdanielk1977   rc = sqlite3_create_function(db, argv[2], -1, testFunc, 0);
7016cbe1f1bSdrh   if( rc!=0 ){
7026f8a503dSdanielk1977     Tcl_AppendResult(interp, sqlite3_error_string(rc), 0);
7036cbe1f1bSdrh     return TCL_ERROR;
7046cbe1f1bSdrh   }
7056cbe1f1bSdrh   return TCL_OK;
7066cbe1f1bSdrh }
7076cbe1f1bSdrh 
7086cbe1f1bSdrh /*
7095a38705eSdrh ** This SQLite callback records the datatype of all columns.
7105a38705eSdrh **
7115a38705eSdrh ** The pArg argument is really a pointer to a TCL interpreter.  The
7125a38705eSdrh ** column names are inserted as the result of this interpreter.
7135a38705eSdrh **
7145a38705eSdrh ** This routine returns non-zero which causes the query to abort.
7155a38705eSdrh */
7165a38705eSdrh static int rememberDataTypes(void *pArg, int nCol, char **argv, char **colv){
7175a38705eSdrh   int i;
7185a38705eSdrh   Tcl_Interp *interp = (Tcl_Interp*)pArg;
7195a38705eSdrh   Tcl_Obj *pList, *pElem;
7205a38705eSdrh   if( colv[nCol+1]==0 ){
7215a38705eSdrh     return 1;
7225a38705eSdrh   }
7235a38705eSdrh   pList = Tcl_NewObj();
7245a38705eSdrh   for(i=0; i<nCol; i++){
7255a38705eSdrh     pElem = Tcl_NewStringObj(colv[i+nCol] ? colv[i+nCol] : "NULL", -1);
7265a38705eSdrh     Tcl_ListObjAppendElement(interp, pList, pElem);
7275a38705eSdrh   }
7285a38705eSdrh   Tcl_SetObjResult(interp, pList);
7295a38705eSdrh   return 1;
7305a38705eSdrh }
7315a38705eSdrh 
7325a38705eSdrh /*
7335a38705eSdrh ** Invoke an SQL statement but ignore all the data in the result.  Instead,
7345a38705eSdrh ** return a list that consists of the datatypes of the various columns.
7355a38705eSdrh **
7365a38705eSdrh ** This only works if "PRAGMA show_datatypes=on" has been executed against
7375a38705eSdrh ** the database connection.
7385a38705eSdrh */
7395a38705eSdrh static int sqlite_datatypes(
7405a38705eSdrh   void *NotUsed,
7415a38705eSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
7425a38705eSdrh   int argc,              /* Number of arguments */
7435a38705eSdrh   char **argv            /* Text of each argument */
7445a38705eSdrh ){
7455a38705eSdrh   sqlite *db;
7465a38705eSdrh   int rc;
7475a38705eSdrh   if( argc!=3 ){
7485a38705eSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
7495a38705eSdrh        " DB SQL", 0);
7505a38705eSdrh     return TCL_ERROR;
7515a38705eSdrh   }
752b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
7536f8a503dSdanielk1977   rc = sqlite3_exec(db, argv[2], rememberDataTypes, interp, 0);
7545a38705eSdrh   if( rc!=0 && rc!=SQLITE_ABORT ){
7556f8a503dSdanielk1977     Tcl_AppendResult(interp, sqlite3_error_string(rc), 0);
7565a38705eSdrh     return TCL_ERROR;
7575a38705eSdrh   }
7585a38705eSdrh   return TCL_OK;
7595a38705eSdrh }
7605a38705eSdrh 
761b86ccfb2Sdrh /*
7626f8a503dSdanielk1977 ** Usage:  sqlite3_step  VM  ?NVAR?  ?VALUEVAR?  ?COLNAMEVAR?
763b86ccfb2Sdrh **
764b86ccfb2Sdrh ** Step a virtual machine.  Return a the result code as a string.
765b86ccfb2Sdrh ** Column results are written into three variables.
766b86ccfb2Sdrh */
767b86ccfb2Sdrh static int test_step(
768b86ccfb2Sdrh   void *NotUsed,
769b86ccfb2Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
770b86ccfb2Sdrh   int argc,              /* Number of arguments */
771b86ccfb2Sdrh   char **argv            /* Text of each argument */
772b86ccfb2Sdrh ){
773b86ccfb2Sdrh   sqlite_vm *vm;
774b86ccfb2Sdrh   int rc, i;
7753a84069dSdrh   const char **azValue = 0;
7763a84069dSdrh   const char **azColName = 0;
7773a84069dSdrh   int N = 0;
778b86ccfb2Sdrh   char *zRc;
779b86ccfb2Sdrh   char zBuf[50];
780073e5a77Sdrh   if( argc<2 || argc>5 ){
781b86ccfb2Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
782b86ccfb2Sdrh        " VM NVAR VALUEVAR COLNAMEVAR", 0);
783b86ccfb2Sdrh     return TCL_ERROR;
784b86ccfb2Sdrh   }
785b86ccfb2Sdrh   if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
7866f8a503dSdanielk1977   rc = sqlite3_step(vm, argc>=3?&N:0, argc>=4?&azValue:0, argc==5?&azColName:0);
787073e5a77Sdrh   if( argc>=3 ){
788b86ccfb2Sdrh     sprintf(zBuf, "%d", N);
789b86ccfb2Sdrh     Tcl_SetVar(interp, argv[2], zBuf, 0);
790073e5a77Sdrh   }
791073e5a77Sdrh   if( argc>=4 ){
792b86ccfb2Sdrh     Tcl_SetVar(interp, argv[3], "", 0);
7933a84069dSdrh     if( azValue ){
794b86ccfb2Sdrh       for(i=0; i<N; i++){
795b86ccfb2Sdrh         Tcl_SetVar(interp, argv[3], azValue[i] ? azValue[i] : "",
796b86ccfb2Sdrh             TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
797b86ccfb2Sdrh       }
798b86ccfb2Sdrh     }
799073e5a77Sdrh   }
800073e5a77Sdrh   if( argc==5 ){
801b86ccfb2Sdrh     Tcl_SetVar(interp, argv[4], "", 0);
8023a84069dSdrh     if( azColName ){
803b86ccfb2Sdrh       for(i=0; i<N*2; i++){
804326dce74Sdrh         Tcl_SetVar(interp, argv[4], azColName[i] ? azColName[i] : "",
805b86ccfb2Sdrh             TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
806b86ccfb2Sdrh       }
807b86ccfb2Sdrh     }
808073e5a77Sdrh   }
809b86ccfb2Sdrh   switch( rc ){
810b86ccfb2Sdrh     case SQLITE_DONE:   zRc = "SQLITE_DONE";    break;
811326dce74Sdrh     case SQLITE_BUSY:   zRc = "SQLITE_BUSY";    break;
812326dce74Sdrh     case SQLITE_ROW:    zRc = "SQLITE_ROW";     break;
813326dce74Sdrh     case SQLITE_ERROR:  zRc = "SQLITE_ERROR";   break;
814b86ccfb2Sdrh     case SQLITE_MISUSE: zRc = "SQLITE_MISUSE";  break;
815b86ccfb2Sdrh     default:            zRc = "unknown";        break;
816b86ccfb2Sdrh   }
817b86ccfb2Sdrh   Tcl_AppendResult(interp, zRc, 0);
818b86ccfb2Sdrh   return TCL_OK;
819b86ccfb2Sdrh }
820b86ccfb2Sdrh 
821b86ccfb2Sdrh /*
822106bb236Sdanielk1977 ** Usage:  sqlite3_finalize  STMT
823b86ccfb2Sdrh **
824106bb236Sdanielk1977 ** Finalize a statement handle.
825b86ccfb2Sdrh */
826b86ccfb2Sdrh static int test_finalize(
827106bb236Sdanielk1977   void * clientData,
828106bb236Sdanielk1977   Tcl_Interp *interp,
829106bb236Sdanielk1977   int objc,
830106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
831b86ccfb2Sdrh ){
832106bb236Sdanielk1977   sqlite3_stmt *pStmt;
833b86ccfb2Sdrh   int rc;
834106bb236Sdanielk1977 
835106bb236Sdanielk1977   if( objc!=2 ){
836106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
837106bb236Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
838b86ccfb2Sdrh     return TCL_ERROR;
839b86ccfb2Sdrh   }
840106bb236Sdanielk1977 
841106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
842106bb236Sdanielk1977 
843106bb236Sdanielk1977   rc = sqlite3_finalize_new(pStmt);
844b86ccfb2Sdrh   if( rc ){
845106bb236Sdanielk1977     return TCL_ERROR;
846106bb236Sdanielk1977   }
847106bb236Sdanielk1977   return TCL_OK;
848106bb236Sdanielk1977 }
849106bb236Sdanielk1977 
850106bb236Sdanielk1977 /*
851106bb236Sdanielk1977 ** Usage:  sqlite3_reset  STMT
852106bb236Sdanielk1977 **
853106bb236Sdanielk1977 ** Finalize a statement handle.
854106bb236Sdanielk1977 */
855106bb236Sdanielk1977 static int test_reset(
856106bb236Sdanielk1977   void * clientData,
857106bb236Sdanielk1977   Tcl_Interp *interp,
858106bb236Sdanielk1977   int objc,
859106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
860106bb236Sdanielk1977 ){
861106bb236Sdanielk1977   sqlite3_stmt *pStmt;
862106bb236Sdanielk1977   int rc;
863106bb236Sdanielk1977 
864106bb236Sdanielk1977   if( objc!=2 ){
865106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
866106bb236Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
867106bb236Sdanielk1977     return TCL_ERROR;
868106bb236Sdanielk1977   }
869106bb236Sdanielk1977 
870106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
871106bb236Sdanielk1977 
872106bb236Sdanielk1977   rc = sqlite3_reset_new(pStmt);
873106bb236Sdanielk1977   if( rc ){
874b86ccfb2Sdrh     return TCL_ERROR;
875b86ccfb2Sdrh   }
876b86ccfb2Sdrh   return TCL_OK;
877b86ccfb2Sdrh }
878b86ccfb2Sdrh 
8795a38705eSdrh /*
8806f8a503dSdanielk1977 ** Usage:  sqlite3_reset   VM
88150457896Sdrh **
88250457896Sdrh ** Reset a virtual machine and prepare it to be run again.
88350457896Sdrh */
88450457896Sdrh 
88550457896Sdrh /*
8867c972decSdrh ** This is the "static_bind_value" that variables are bound to when
8876f8a503dSdanielk1977 ** the FLAG option of sqlite3_bind is "static"
88850457896Sdrh */
8897c972decSdrh static char *sqlite_static_bind_value = 0;
8907c972decSdrh 
8917c972decSdrh /*
8926f8a503dSdanielk1977 ** Usage:  sqlite3_bind  VM  IDX  VALUE  FLAGS
8937c972decSdrh **
8947c972decSdrh ** Sets the value of the IDX-th occurance of "?" in the original SQL
8957c972decSdrh ** string.  VALUE is the new value.  If FLAGS=="null" then VALUE is
8967c972decSdrh ** ignored and the value is set to NULL.  If FLAGS=="static" then
8977c972decSdrh ** the value is set to the value of a static variable named
8987c972decSdrh ** "sqlite_static_bind_value".  If FLAGS=="normal" then a copy
8997c972decSdrh ** of the VALUE is made.
9007c972decSdrh */
9017c972decSdrh static int test_bind(
90250457896Sdrh   void *NotUsed,
90350457896Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
90450457896Sdrh   int argc,              /* Number of arguments */
90550457896Sdrh   char **argv            /* Text of each argument */
90650457896Sdrh ){
90750457896Sdrh   sqlite_vm *vm;
90850457896Sdrh   int rc;
9097c972decSdrh   int idx;
9107c972decSdrh   if( argc!=5 ){
91150457896Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
9127c972decSdrh        " VM IDX VALUE (null|static|normal)\"", 0);
91350457896Sdrh     return TCL_ERROR;
91450457896Sdrh   }
91550457896Sdrh   if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
9167c972decSdrh   if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR;
9177c972decSdrh   if( strcmp(argv[4],"null")==0 ){
9186f8a503dSdanielk1977     rc = sqlite3_bind(vm, idx, 0, 0, 0);
9197c972decSdrh   }else if( strcmp(argv[4],"static")==0 ){
9206f8a503dSdanielk1977     rc = sqlite3_bind(vm, idx, sqlite_static_bind_value, -1, 0);
9217c972decSdrh   }else if( strcmp(argv[4],"normal")==0 ){
9226f8a503dSdanielk1977     rc = sqlite3_bind(vm, idx, argv[3], -1, 1);
9237c972decSdrh   }else{
9247c972decSdrh     Tcl_AppendResult(interp, "4th argument should be "
9257c972decSdrh         "\"null\" or \"static\" or \"normal\"", 0);
9267c972decSdrh     return TCL_ERROR;
9277c972decSdrh   }
92850457896Sdrh   if( rc ){
92950457896Sdrh     char zBuf[50];
93050457896Sdrh     sprintf(zBuf, "(%d) ", rc);
9316f8a503dSdanielk1977     Tcl_AppendResult(interp, zBuf, sqlite3_error_string(rc), 0);
93250457896Sdrh     return TCL_ERROR;
93350457896Sdrh   }
93450457896Sdrh   return TCL_OK;
93550457896Sdrh }
93650457896Sdrh 
93750457896Sdrh /*
93899ee3600Sdrh ** Usage:    breakpoint
93999ee3600Sdrh **
94099ee3600Sdrh ** This routine exists for one purpose - to provide a place to put a
94199ee3600Sdrh ** breakpoint with GDB that can be triggered using TCL code.  The use
94299ee3600Sdrh ** for this is when a particular test fails on (say) the 1485th iteration.
94399ee3600Sdrh ** In the TCL test script, we can add code like this:
94499ee3600Sdrh **
94599ee3600Sdrh **     if {$i==1485} breakpoint
94699ee3600Sdrh **
94799ee3600Sdrh ** Then run testfixture in the debugger and wait for the breakpoint to
94899ee3600Sdrh ** fire.  Then additional breakpoints can be set to trace down the bug.
94999ee3600Sdrh */
95099ee3600Sdrh static int test_breakpoint(
95199ee3600Sdrh   void *NotUsed,
95299ee3600Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
95399ee3600Sdrh   int argc,              /* Number of arguments */
95499ee3600Sdrh   char **argv            /* Text of each argument */
95599ee3600Sdrh ){
95699ee3600Sdrh   return TCL_OK;         /* Do nothing */
95799ee3600Sdrh }
95899ee3600Sdrh 
95951e3d8e2Sdanielk1977 static int test_bind_int32(
96051e3d8e2Sdanielk1977   void * clientData,
96151e3d8e2Sdanielk1977   Tcl_Interp *interp,
96251e3d8e2Sdanielk1977   int objc,
96351e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
96451e3d8e2Sdanielk1977 ){
96551e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
96651e3d8e2Sdanielk1977   int idx;
96751e3d8e2Sdanielk1977   int value;
96851e3d8e2Sdanielk1977   int rc;
96951e3d8e2Sdanielk1977 
97051e3d8e2Sdanielk1977   if( objc!=4 ){
97151e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
97251e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
97351e3d8e2Sdanielk1977     return TCL_ERROR;
97451e3d8e2Sdanielk1977   }
97551e3d8e2Sdanielk1977 
97651e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
97751e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
97851e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &value) ) return TCL_ERROR;
97951e3d8e2Sdanielk1977 
98051e3d8e2Sdanielk1977   rc = sqlite3_bind_int32(pStmt, idx, value);
98151e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
98251e3d8e2Sdanielk1977     return TCL_ERROR;
98351e3d8e2Sdanielk1977   }
98451e3d8e2Sdanielk1977 
98551e3d8e2Sdanielk1977   return TCL_OK;
98651e3d8e2Sdanielk1977 }
98751e3d8e2Sdanielk1977 
98851e3d8e2Sdanielk1977 static int test_bind_int64(
98951e3d8e2Sdanielk1977   void * clientData,
99051e3d8e2Sdanielk1977   Tcl_Interp *interp,
99151e3d8e2Sdanielk1977   int objc,
99251e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
99351e3d8e2Sdanielk1977 ){
99451e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
99551e3d8e2Sdanielk1977   int idx;
99651e3d8e2Sdanielk1977   i64 value;
99751e3d8e2Sdanielk1977   int rc;
99851e3d8e2Sdanielk1977 
99951e3d8e2Sdanielk1977   if( objc!=4 ){
100051e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
100151e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
100251e3d8e2Sdanielk1977     return TCL_ERROR;
100351e3d8e2Sdanielk1977   }
100451e3d8e2Sdanielk1977 
100551e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
100651e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
100751e3d8e2Sdanielk1977   if( Tcl_GetWideIntFromObj(interp, objv[3], &value) ) return TCL_ERROR;
100851e3d8e2Sdanielk1977 
100951e3d8e2Sdanielk1977   rc = sqlite3_bind_int64(pStmt, idx, value);
101051e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
101151e3d8e2Sdanielk1977     return TCL_ERROR;
101251e3d8e2Sdanielk1977   }
101351e3d8e2Sdanielk1977 
101451e3d8e2Sdanielk1977   return TCL_OK;
101551e3d8e2Sdanielk1977 }
101651e3d8e2Sdanielk1977 
101751e3d8e2Sdanielk1977 static int test_bind_double(
101851e3d8e2Sdanielk1977   void * clientData,
101951e3d8e2Sdanielk1977   Tcl_Interp *interp,
102051e3d8e2Sdanielk1977   int objc,
102151e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
102251e3d8e2Sdanielk1977 ){
102351e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
102451e3d8e2Sdanielk1977   int idx;
102551e3d8e2Sdanielk1977   double value;
102651e3d8e2Sdanielk1977   int rc;
102751e3d8e2Sdanielk1977 
102851e3d8e2Sdanielk1977   if( objc!=4 ){
102951e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
103051e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
103151e3d8e2Sdanielk1977     return TCL_ERROR;
103251e3d8e2Sdanielk1977   }
103351e3d8e2Sdanielk1977 
103451e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
103551e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
103651e3d8e2Sdanielk1977   if( Tcl_GetDoubleFromObj(interp, objv[3], &value) ) return TCL_ERROR;
103751e3d8e2Sdanielk1977 
103851e3d8e2Sdanielk1977   rc = sqlite3_bind_double(pStmt, idx, value);
103951e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
104051e3d8e2Sdanielk1977     return TCL_ERROR;
104151e3d8e2Sdanielk1977   }
104251e3d8e2Sdanielk1977 
104351e3d8e2Sdanielk1977   return TCL_OK;
104451e3d8e2Sdanielk1977 }
104551e3d8e2Sdanielk1977 
104651e3d8e2Sdanielk1977 static int test_bind_null(
104751e3d8e2Sdanielk1977   void * clientData,
104851e3d8e2Sdanielk1977   Tcl_Interp *interp,
104951e3d8e2Sdanielk1977   int objc,
105051e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
105151e3d8e2Sdanielk1977 ){
105251e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
105351e3d8e2Sdanielk1977   int idx;
105451e3d8e2Sdanielk1977   int rc;
105551e3d8e2Sdanielk1977 
105651e3d8e2Sdanielk1977   if( objc!=3 ){
105751e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
105851e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.>", 0);
105951e3d8e2Sdanielk1977     return TCL_ERROR;
106051e3d8e2Sdanielk1977   }
106151e3d8e2Sdanielk1977 
106251e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
106351e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
106451e3d8e2Sdanielk1977 
106551e3d8e2Sdanielk1977   rc = sqlite3_bind_null(pStmt, idx);
106651e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
106751e3d8e2Sdanielk1977     return TCL_ERROR;
106851e3d8e2Sdanielk1977   }
106951e3d8e2Sdanielk1977 
107051e3d8e2Sdanielk1977   return TCL_OK;
107151e3d8e2Sdanielk1977 }
107251e3d8e2Sdanielk1977 
107351e3d8e2Sdanielk1977 static int test_bind_text(
107451e3d8e2Sdanielk1977   void * clientData,
107551e3d8e2Sdanielk1977   Tcl_Interp *interp,
107651e3d8e2Sdanielk1977   int objc,
107751e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
107851e3d8e2Sdanielk1977 ){
107951e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
108051e3d8e2Sdanielk1977   int idx;
108151e3d8e2Sdanielk1977   int bytes;
108251e3d8e2Sdanielk1977   char *value;
108351e3d8e2Sdanielk1977   int rc;
108451e3d8e2Sdanielk1977 
108551e3d8e2Sdanielk1977   if( objc!=5 ){
108651e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
108751e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
108851e3d8e2Sdanielk1977         " <bytes>", 0);
108951e3d8e2Sdanielk1977     return TCL_ERROR;
109051e3d8e2Sdanielk1977   }
109151e3d8e2Sdanielk1977 
109251e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
109351e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
109451e3d8e2Sdanielk1977   value = Tcl_GetString(objv[3]);
109551e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
109651e3d8e2Sdanielk1977 
109751e3d8e2Sdanielk1977   rc = sqlite3_bind_text(pStmt, idx, value, bytes, 1);
109851e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
109951e3d8e2Sdanielk1977     return TCL_ERROR;
110051e3d8e2Sdanielk1977   }
110151e3d8e2Sdanielk1977 
110251e3d8e2Sdanielk1977   return TCL_OK;
110351e3d8e2Sdanielk1977 }
110451e3d8e2Sdanielk1977 
110551e3d8e2Sdanielk1977 static int test_bind_text16(
110651e3d8e2Sdanielk1977   void * clientData,
110751e3d8e2Sdanielk1977   Tcl_Interp *interp,
110851e3d8e2Sdanielk1977   int objc,
110951e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
111051e3d8e2Sdanielk1977 ){
111151e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
111251e3d8e2Sdanielk1977   int idx;
111351e3d8e2Sdanielk1977   int bytes;
111451e3d8e2Sdanielk1977   char *value;
111551e3d8e2Sdanielk1977   int rc;
111651e3d8e2Sdanielk1977 
111751e3d8e2Sdanielk1977   if( objc!=5 ){
111851e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
111951e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
112051e3d8e2Sdanielk1977         " <bytes>", 0);
112151e3d8e2Sdanielk1977     return TCL_ERROR;
112251e3d8e2Sdanielk1977   }
112351e3d8e2Sdanielk1977 
112451e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
112551e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
112651e3d8e2Sdanielk1977   value = Tcl_GetByteArrayFromObj(objv[3], 0);
112751e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
112851e3d8e2Sdanielk1977 
112951e3d8e2Sdanielk1977   rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, 1);
113051e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
113151e3d8e2Sdanielk1977     return TCL_ERROR;
113251e3d8e2Sdanielk1977   }
113351e3d8e2Sdanielk1977 
113451e3d8e2Sdanielk1977   return TCL_OK;
113551e3d8e2Sdanielk1977 }
113651e3d8e2Sdanielk1977 
113751e3d8e2Sdanielk1977 static int test_bind_blob(
113851e3d8e2Sdanielk1977   void * clientData,
113951e3d8e2Sdanielk1977   Tcl_Interp *interp,
114051e3d8e2Sdanielk1977   int objc,
114151e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
114251e3d8e2Sdanielk1977 ){
114351e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
114451e3d8e2Sdanielk1977   int idx;
114551e3d8e2Sdanielk1977   int bytes;
114651e3d8e2Sdanielk1977   char *value;
114751e3d8e2Sdanielk1977   int rc;
114851e3d8e2Sdanielk1977 
114951e3d8e2Sdanielk1977   if( objc!=5 ){
115051e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
115151e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
115251e3d8e2Sdanielk1977         " <bytes>", 0);
115351e3d8e2Sdanielk1977     return TCL_ERROR;
115451e3d8e2Sdanielk1977   }
115551e3d8e2Sdanielk1977 
115651e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
115751e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
115851e3d8e2Sdanielk1977   value = Tcl_GetString(objv[3]);
115951e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &bytes) ) return TCL_ERROR;
116051e3d8e2Sdanielk1977 
116151e3d8e2Sdanielk1977   rc = sqlite3_bind_blob(pStmt, idx, value, bytes, 1);
116251e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
116351e3d8e2Sdanielk1977     return TCL_ERROR;
116451e3d8e2Sdanielk1977   }
116551e3d8e2Sdanielk1977 
116651e3d8e2Sdanielk1977   return TCL_OK;
116751e3d8e2Sdanielk1977 }
116851e3d8e2Sdanielk1977 
116999ee3600Sdrh /*
11706622cce3Sdanielk1977 ** Usage: sqlite3_errcode DB
11716622cce3Sdanielk1977 **
11726622cce3Sdanielk1977 ** Return the string representation of the most recent sqlite3_* API
11736622cce3Sdanielk1977 ** error code. e.g. "SQLITE_ERROR".
11746622cce3Sdanielk1977 */
11756622cce3Sdanielk1977 static int test_errcode(
11766622cce3Sdanielk1977   void * clientData,
11776622cce3Sdanielk1977   Tcl_Interp *interp,
11786622cce3Sdanielk1977   int objc,
11796622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
11806622cce3Sdanielk1977 ){
11816622cce3Sdanielk1977   sqlite3 *db;
11826622cce3Sdanielk1977 
11836622cce3Sdanielk1977   if( objc!=2 ){
11846622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
11856622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
11866622cce3Sdanielk1977     return TCL_ERROR;
11876622cce3Sdanielk1977   }
11886622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
11896622cce3Sdanielk1977   Tcl_SetResult(interp, (char *)errorName(sqlite3_errcode(db)), 0);
11906622cce3Sdanielk1977   return TCL_OK;
11916622cce3Sdanielk1977 }
11926622cce3Sdanielk1977 
11936622cce3Sdanielk1977 /*
11946622cce3Sdanielk1977 ** Usage:   test_errmsg DB
11956622cce3Sdanielk1977 **
11966622cce3Sdanielk1977 ** Returns the UTF-8 representation of the error message string for the
11976622cce3Sdanielk1977 ** most recent sqlite3_* API call.
11986622cce3Sdanielk1977 */
11996622cce3Sdanielk1977 static int test_errmsg(
12006622cce3Sdanielk1977   void * clientData,
12016622cce3Sdanielk1977   Tcl_Interp *interp,
12026622cce3Sdanielk1977   int objc,
12036622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
12046622cce3Sdanielk1977 ){
12056622cce3Sdanielk1977   sqlite *db;
12066622cce3Sdanielk1977   const char *zErr;
12076622cce3Sdanielk1977 
12086622cce3Sdanielk1977   if( objc!=2 ){
12096622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
12106622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
12116622cce3Sdanielk1977     return TCL_ERROR;
12126622cce3Sdanielk1977   }
12136622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
12146622cce3Sdanielk1977 
12156622cce3Sdanielk1977   zErr = sqlite3_errmsg(db);
12166622cce3Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
12176622cce3Sdanielk1977   return TCL_OK;
12186622cce3Sdanielk1977 }
12196622cce3Sdanielk1977 
12206622cce3Sdanielk1977 /*
12216622cce3Sdanielk1977 ** Usage:   test_errmsg16 DB
12226622cce3Sdanielk1977 **
12236622cce3Sdanielk1977 ** Returns the UTF-16 representation of the error message string for the
12246622cce3Sdanielk1977 ** most recent sqlite3_* API call. This is a byte array object at the TCL
12256622cce3Sdanielk1977 ** level, and it includes the 0x00 0x00 terminator bytes at the end of the
12266622cce3Sdanielk1977 ** UTF-16 string.
12276622cce3Sdanielk1977 */
12286622cce3Sdanielk1977 static int test_errmsg16(
12296622cce3Sdanielk1977   void * clientData,
12306622cce3Sdanielk1977   Tcl_Interp *interp,
12316622cce3Sdanielk1977   int objc,
12326622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
12336622cce3Sdanielk1977 ){
12346622cce3Sdanielk1977   sqlite *db;
12356622cce3Sdanielk1977   const void *zErr;
12366622cce3Sdanielk1977   int bytes;
12376622cce3Sdanielk1977 
12386622cce3Sdanielk1977   if( objc!=2 ){
12396622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
12406622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
12416622cce3Sdanielk1977     return TCL_ERROR;
12426622cce3Sdanielk1977   }
12436622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
12446622cce3Sdanielk1977 
12456622cce3Sdanielk1977   zErr = sqlite3_errmsg16(db);
12466622cce3Sdanielk1977   bytes = sqlite3utf16ByteLen(zErr, -1);
12476622cce3Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes));
12486622cce3Sdanielk1977   return TCL_OK;
12496622cce3Sdanielk1977 }
12506622cce3Sdanielk1977 
12516622cce3Sdanielk1977 /*
12526622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar
12536622cce3Sdanielk1977 **
12546622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
12556622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global
12566622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A
12576622cce3Sdanielk1977 ** STMT handle is returned.
12586622cce3Sdanielk1977 */
12596622cce3Sdanielk1977 static int test_prepare(
12606622cce3Sdanielk1977   void * clientData,
12616622cce3Sdanielk1977   Tcl_Interp *interp,
12626622cce3Sdanielk1977   int objc,
12636622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
12646622cce3Sdanielk1977 ){
12656622cce3Sdanielk1977   sqlite3 *db;
12666622cce3Sdanielk1977   const char *zSql;
12676622cce3Sdanielk1977   int bytes;
12686622cce3Sdanielk1977   const char *zTail = 0;
12696622cce3Sdanielk1977   sqlite3_stmt *pStmt = 0;
12706622cce3Sdanielk1977   char zBuf[50];
12714ad1713cSdanielk1977   int rc;
12726622cce3Sdanielk1977 
12736622cce3Sdanielk1977   if( objc!=5 ){
12746622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
12756622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
12766622cce3Sdanielk1977     return TCL_ERROR;
12776622cce3Sdanielk1977   }
12786622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
12796622cce3Sdanielk1977   zSql = Tcl_GetString(objv[2]);
12806622cce3Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
12816622cce3Sdanielk1977 
12824ad1713cSdanielk1977   rc = sqlite3_prepare(db, zSql, bytes, &pStmt, &zTail);
12836622cce3Sdanielk1977   if( zTail ){
12846622cce3Sdanielk1977     if( bytes>=0 ){
12856622cce3Sdanielk1977       bytes = bytes - (zTail-zSql);
12866622cce3Sdanielk1977     }
12876622cce3Sdanielk1977     Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
12886622cce3Sdanielk1977   }
12894ad1713cSdanielk1977   if( rc!=SQLITE_OK ){
12904ad1713cSdanielk1977     assert( pStmt==0 );
12914ad1713cSdanielk1977     sprintf(zBuf, "(%d) ", rc);
12924ad1713cSdanielk1977     Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
12934ad1713cSdanielk1977     return TCL_ERROR;
12944ad1713cSdanielk1977   }
12956622cce3Sdanielk1977 
12964ad1713cSdanielk1977   if( pStmt ){
12976622cce3Sdanielk1977     if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
12986622cce3Sdanielk1977     Tcl_AppendResult(interp, zBuf, 0);
12994ad1713cSdanielk1977   }
13006622cce3Sdanielk1977   return TCL_OK;
13016622cce3Sdanielk1977 }
13026622cce3Sdanielk1977 
13036622cce3Sdanielk1977 /*
13046622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar
13056622cce3Sdanielk1977 **
13066622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
13076622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global
13086622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A
13096622cce3Sdanielk1977 ** STMT handle is returned.
13106622cce3Sdanielk1977 */
13116622cce3Sdanielk1977 static int test_prepare16(
13126622cce3Sdanielk1977   void * clientData,
13136622cce3Sdanielk1977   Tcl_Interp *interp,
13146622cce3Sdanielk1977   int objc,
13156622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
13166622cce3Sdanielk1977 ){
13176622cce3Sdanielk1977   sqlite3 *db;
13186622cce3Sdanielk1977   const void *zSql;
13196622cce3Sdanielk1977   const void *zTail = 0;
13206622cce3Sdanielk1977   Tcl_Obj *pTail = 0;
13216622cce3Sdanielk1977   sqlite3_stmt *pStmt = 0;
13226622cce3Sdanielk1977   char zBuf[50];
13236622cce3Sdanielk1977   int bytes;                /* The integer specified as arg 3 */
13246622cce3Sdanielk1977   int objlen;               /* The byte-array length of arg 2 */
13256622cce3Sdanielk1977 
13266622cce3Sdanielk1977   if( objc!=5 ){
13276622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
13286622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
13296622cce3Sdanielk1977     return TCL_ERROR;
13306622cce3Sdanielk1977   }
13316622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
13326622cce3Sdanielk1977   zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen);
13336622cce3Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
13346622cce3Sdanielk1977 
13356622cce3Sdanielk1977   if( SQLITE_OK!=sqlite3_prepare16(db, zSql, bytes, &pStmt, &zTail) ){
13366622cce3Sdanielk1977     return TCL_ERROR;
13376622cce3Sdanielk1977   }
13386622cce3Sdanielk1977 
13396622cce3Sdanielk1977   if( zTail ){
13406622cce3Sdanielk1977     objlen = objlen - ((u8 *)zTail-(u8 *)zSql);
13416622cce3Sdanielk1977   }else{
13426622cce3Sdanielk1977     objlen = 0;
13436622cce3Sdanielk1977   }
13446622cce3Sdanielk1977   pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen);
13456622cce3Sdanielk1977   Tcl_IncrRefCount(pTail);
13466622cce3Sdanielk1977   Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0);
13474ad1713cSdanielk1977   Tcl_DecrRefCount(pTail);
13486622cce3Sdanielk1977 
13494ad1713cSdanielk1977   if( pStmt ){
13506622cce3Sdanielk1977     if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
13514ad1713cSdanielk1977   }
13526622cce3Sdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
13536622cce3Sdanielk1977   return TCL_OK;
13546622cce3Sdanielk1977 }
13556622cce3Sdanielk1977 
13564ad1713cSdanielk1977 /*
13574ad1713cSdanielk1977 ** Usage: sqlite3_open filename ?options-list?
13584ad1713cSdanielk1977 */
13594ad1713cSdanielk1977 static int test_open(
13604ad1713cSdanielk1977   void * clientData,
13614ad1713cSdanielk1977   Tcl_Interp *interp,
13624ad1713cSdanielk1977   int objc,
13634ad1713cSdanielk1977   Tcl_Obj *CONST objv[]
13644ad1713cSdanielk1977 ){
13654ad1713cSdanielk1977   const char *zFilename;
13664ad1713cSdanielk1977   sqlite3 *db;
13674ad1713cSdanielk1977   int rc;
13684ad1713cSdanielk1977   char zBuf[100];
13694ad1713cSdanielk1977 
13704ad1713cSdanielk1977   if( objc!=3 && objc!=2 ){
13714ad1713cSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
13724ad1713cSdanielk1977        Tcl_GetString(objv[0]), " filename options-list", 0);
13734ad1713cSdanielk1977     return TCL_ERROR;
13744ad1713cSdanielk1977   }
13754ad1713cSdanielk1977 
13764ad1713cSdanielk1977   zFilename = Tcl_GetString(objv[1]);
137780290863Sdanielk1977   rc = sqlite3_open(zFilename, &db, 0);
13784ad1713cSdanielk1977 
13794ad1713cSdanielk1977   if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
13804ad1713cSdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
13814ad1713cSdanielk1977   return TCL_OK;
13824ad1713cSdanielk1977 }
13834ad1713cSdanielk1977 
13844ad1713cSdanielk1977 /*
13854ad1713cSdanielk1977 ** Usage: sqlite3_open16 filename options
13864ad1713cSdanielk1977 */
13874ad1713cSdanielk1977 static int test_open16(
13884ad1713cSdanielk1977   void * clientData,
13894ad1713cSdanielk1977   Tcl_Interp *interp,
13904ad1713cSdanielk1977   int objc,
13914ad1713cSdanielk1977   Tcl_Obj *CONST objv[]
13924ad1713cSdanielk1977 ){
13934ad1713cSdanielk1977   const void *zFilename;
13944ad1713cSdanielk1977   sqlite3 *db;
13954ad1713cSdanielk1977   int rc;
13964ad1713cSdanielk1977   char zBuf[100];
13974ad1713cSdanielk1977 
13984ad1713cSdanielk1977   if( objc!=3 ){
13994ad1713cSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
14004ad1713cSdanielk1977        Tcl_GetString(objv[0]), " filename options-list", 0);
14014ad1713cSdanielk1977     return TCL_ERROR;
14024ad1713cSdanielk1977   }
14034ad1713cSdanielk1977 
14044ad1713cSdanielk1977   zFilename = Tcl_GetByteArrayFromObj(objv[1], 0);
14054ad1713cSdanielk1977   rc = sqlite3_open16(zFilename, &db, 0);
14064ad1713cSdanielk1977 
14074ad1713cSdanielk1977   if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
14084ad1713cSdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
14094ad1713cSdanielk1977   return TCL_OK;
14104ad1713cSdanielk1977 }
1411d3d39e93Sdrh 
1412d3d39e93Sdrh /*
1413106bb236Sdanielk1977 ** Usage: sqlite3_step STMT
1414106bb236Sdanielk1977 **
1415106bb236Sdanielk1977 ** Advance the statement to the next row.
1416106bb236Sdanielk1977 */
1417106bb236Sdanielk1977 static int test_step_new(
1418106bb236Sdanielk1977   void * clientData,
1419106bb236Sdanielk1977   Tcl_Interp *interp,
1420106bb236Sdanielk1977   int objc,
1421106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
1422106bb236Sdanielk1977 ){
1423106bb236Sdanielk1977   sqlite3_stmt *pStmt;
1424106bb236Sdanielk1977   int rc;
1425106bb236Sdanielk1977 
1426e1cd9874Sdanielk1977   if( objc!=2 ){
1427106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1428106bb236Sdanielk1977        Tcl_GetString(objv[0]), " STMT", 0);
1429106bb236Sdanielk1977     return TCL_ERROR;
1430106bb236Sdanielk1977   }
1431106bb236Sdanielk1977 
1432106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
1433106bb236Sdanielk1977   rc = sqlite3_step_new(pStmt);
1434106bb236Sdanielk1977 
1435e1cd9874Sdanielk1977   if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR;
1436e1cd9874Sdanielk1977   return TCL_OK;
1437e1cd9874Sdanielk1977 }
1438e1cd9874Sdanielk1977 
1439e1cd9874Sdanielk1977 /*
1440e1cd9874Sdanielk1977 ** Usage: sqlite3_column_data STMT column
1441e1cd9874Sdanielk1977 **
1442e1cd9874Sdanielk1977 ** Advance the statement to the next row.
1443e1cd9874Sdanielk1977 */
1444e1cd9874Sdanielk1977 static int test_column_data(
1445e1cd9874Sdanielk1977   void * clientData,
1446e1cd9874Sdanielk1977   Tcl_Interp *interp,
1447e1cd9874Sdanielk1977   int objc,
1448e1cd9874Sdanielk1977   Tcl_Obj *CONST objv[]
1449e1cd9874Sdanielk1977 ){
1450e1cd9874Sdanielk1977   sqlite3_stmt *pStmt;
1451e1cd9874Sdanielk1977   int col;
1452e1cd9874Sdanielk1977   Tcl_Obj *pRet;
1453e1cd9874Sdanielk1977 
1454e1cd9874Sdanielk1977   if( objc!=3 ){
1455e1cd9874Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1456e1cd9874Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
1457e1cd9874Sdanielk1977     return TCL_ERROR;
1458e1cd9874Sdanielk1977   }
1459e1cd9874Sdanielk1977 
1460e1cd9874Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
1461e1cd9874Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
1462e1cd9874Sdanielk1977 
1463e1cd9874Sdanielk1977   if( SQLITE3_BLOB==sqlite3_column_type(pStmt, col) ){
1464e1cd9874Sdanielk1977     int len = sqlite3_column_bytes(pStmt, col);
1465e1cd9874Sdanielk1977     pRet = Tcl_NewByteArrayObj(sqlite3_column_data(pStmt, col), len);
1466e1cd9874Sdanielk1977   }else{
1467e1cd9874Sdanielk1977     pRet = Tcl_NewStringObj(sqlite3_column_data(pStmt, col), -1);
1468e1cd9874Sdanielk1977   }
1469e1cd9874Sdanielk1977   Tcl_SetObjResult(interp, pRet);
1470e1cd9874Sdanielk1977 
1471e1cd9874Sdanielk1977   return TCL_OK;
1472e1cd9874Sdanielk1977 }
1473e1cd9874Sdanielk1977 
1474e1cd9874Sdanielk1977 /*
1475e1cd9874Sdanielk1977 ** Usage: sqlite3_column_data16 STMT column
1476e1cd9874Sdanielk1977 **
1477e1cd9874Sdanielk1977 ** Advance the statement to the next row.
1478e1cd9874Sdanielk1977 */
1479e1cd9874Sdanielk1977 static int test_column_data16(
1480e1cd9874Sdanielk1977   void * clientData,
1481e1cd9874Sdanielk1977   Tcl_Interp *interp,
1482e1cd9874Sdanielk1977   int objc,
1483e1cd9874Sdanielk1977   Tcl_Obj *CONST objv[]
1484e1cd9874Sdanielk1977 ){
1485e1cd9874Sdanielk1977   sqlite3_stmt *pStmt;
1486e1cd9874Sdanielk1977   int col;
1487e1cd9874Sdanielk1977   Tcl_Obj *pRet;
1488e1cd9874Sdanielk1977   int len;
1489e1cd9874Sdanielk1977 
1490e1cd9874Sdanielk1977   if( objc!=3 ){
1491e1cd9874Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1492e1cd9874Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
1493e1cd9874Sdanielk1977     return TCL_ERROR;
1494e1cd9874Sdanielk1977   }
1495e1cd9874Sdanielk1977 
1496e1cd9874Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
1497e1cd9874Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
1498e1cd9874Sdanielk1977 
1499e1cd9874Sdanielk1977   len = sqlite3_column_bytes16(pStmt, col);
1500e1cd9874Sdanielk1977   pRet = Tcl_NewByteArrayObj(sqlite3_column_data16(pStmt, col), len);
1501e1cd9874Sdanielk1977   Tcl_SetObjResult(interp, pRet);
1502e1cd9874Sdanielk1977 
1503106bb236Sdanielk1977   return TCL_OK;
1504106bb236Sdanielk1977 }
1505106bb236Sdanielk1977 
1506106bb236Sdanielk1977 /*
1507d3d39e93Sdrh ** This is a collating function named "REVERSE" which sorts text
1508d3d39e93Sdrh ** in reverse order.
1509d3d39e93Sdrh */
1510d3d39e93Sdrh static int reverseCollatingFunc(
1511d3d39e93Sdrh   void *NotUsed,
1512d3d39e93Sdrh   int nKey1, const void *pKey1,
1513d3d39e93Sdrh   int nKey2, const void *pKey2
1514d3d39e93Sdrh ){
1515d3d39e93Sdrh   int rc, n;
1516d3d39e93Sdrh   n = nKey1<nKey2 ? nKey1 : nKey2;
1517d3d39e93Sdrh   rc = memcmp(pKey1, pKey2, n);
1518d3d39e93Sdrh   if( rc==0 ){
1519d3d39e93Sdrh     rc = nKey1 - nKey2;
1520d3d39e93Sdrh   }
1521d3d39e93Sdrh   return -rc;
1522d3d39e93Sdrh }
1523d3d39e93Sdrh 
1524d3d39e93Sdrh /*
1525d3d39e93Sdrh ** Usage: add_reverse_collating_func DB
1526d3d39e93Sdrh **
1527d3d39e93Sdrh ** This routine adds a collation named "REVERSE" to database given.
1528d3d39e93Sdrh ** REVERSE is used for testing only.
1529d3d39e93Sdrh */
1530d3d39e93Sdrh static int reverse_collfunc(
1531d3d39e93Sdrh   void * clientData,
1532d3d39e93Sdrh   Tcl_Interp *interp,
1533d3d39e93Sdrh   int objc,
1534d3d39e93Sdrh   Tcl_Obj *CONST objv[]
1535d3d39e93Sdrh ){
1536d3d39e93Sdrh   sqlite3 *db;
1537d3d39e93Sdrh 
1538d3d39e93Sdrh   if( objc!=2 ){
1539d3d39e93Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB");
1540d3d39e93Sdrh     return TCL_ERROR;
1541d3d39e93Sdrh   }
1542d3d39e93Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1543d3d39e93Sdrh   sqlite3ChangeCollatingFunction(db, "REVERSE", 7, 0, reverseCollatingFunc);
1544d3d39e93Sdrh   return TCL_OK;
1545d3d39e93Sdrh }
1546d3d39e93Sdrh 
1547d3d39e93Sdrh 
15486622cce3Sdanielk1977 /*
1549d1bf3512Sdrh ** Register commands with the TCL interpreter.
1550d1bf3512Sdrh */
1551d1bf3512Sdrh int Sqlitetest1_Init(Tcl_Interp *interp){
15526f8a503dSdanielk1977   extern int sqlite3_search_count;
15536f8a503dSdanielk1977   extern int sqlite3_interrupt_count;
15546f8a503dSdanielk1977   extern int sqlite3_open_file_count;
15556f8a503dSdanielk1977   extern int sqlite3_current_time;
1556c2eef3b3Sdrh   static struct {
1557c2eef3b3Sdrh      char *zName;
1558c2eef3b3Sdrh      Tcl_CmdProc *xProc;
1559c2eef3b3Sdrh   } aCmd[] = {
15606f8a503dSdanielk1977      { "sqlite3_mprintf_int",           (Tcl_CmdProc*)sqlite3_mprintf_int    },
15616f8a503dSdanielk1977      { "sqlite3_mprintf_str",           (Tcl_CmdProc*)sqlite3_mprintf_str    },
15626f8a503dSdanielk1977      { "sqlite3_mprintf_double",        (Tcl_CmdProc*)sqlite3_mprintf_double },
15636f8a503dSdanielk1977      { "sqlite3_mprintf_scaled",        (Tcl_CmdProc*)sqlite3_mprintf_scaled },
15646f8a503dSdanielk1977      { "sqlite3_mprintf_z_test",        (Tcl_CmdProc*)test_mprintf_z        },
15654ad1713cSdanielk1977 //     { "sqlite3_open",                  (Tcl_CmdProc*)sqlite_test_open      },
15666f8a503dSdanielk1977      { "sqlite3_last_insert_rowid",     (Tcl_CmdProc*)test_last_rowid       },
15676f8a503dSdanielk1977      { "sqlite3_exec_printf",           (Tcl_CmdProc*)test_exec_printf      },
15686f8a503dSdanielk1977      { "sqlite3_get_table_printf",      (Tcl_CmdProc*)test_get_table_printf },
15696f8a503dSdanielk1977      { "sqlite3_close",                 (Tcl_CmdProc*)sqlite_test_close     },
15706f8a503dSdanielk1977      { "sqlite3_create_function",       (Tcl_CmdProc*)test_create_function  },
15716f8a503dSdanielk1977      { "sqlite3_create_aggregate",      (Tcl_CmdProc*)test_create_aggregate },
1572c2eef3b3Sdrh      { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func    },
1573c2eef3b3Sdrh      { "sqlite_abort",                  (Tcl_CmdProc*)sqlite_abort          },
15745a38705eSdrh      { "sqlite_datatypes",              (Tcl_CmdProc*)sqlite_datatypes      },
1575c2eef3b3Sdrh #ifdef MEMORY_DEBUG
1576c2eef3b3Sdrh      { "sqlite_malloc_fail",            (Tcl_CmdProc*)sqlite_malloc_fail    },
1577c2eef3b3Sdrh      { "sqlite_malloc_stat",            (Tcl_CmdProc*)sqlite_malloc_stat    },
1578c2eef3b3Sdrh #endif
157996fc5fe6Sdanielk1977      { "sqlite_step",                    (Tcl_CmdProc*)test_step             },
1580106bb236Sdanielk1977 // { "sqlite_finalize",                (Tcl_CmdProc*)test_finalize         },
158196fc5fe6Sdanielk1977      { "sqlite_bind",                    (Tcl_CmdProc*)test_bind             },
1582106bb236Sdanielk1977 // { "sqlite_reset",                   (Tcl_CmdProc*)test_reset            },
158399ee3600Sdrh      { "breakpoint",                     (Tcl_CmdProc*)test_breakpoint       },
1584c2eef3b3Sdrh   };
158551e3d8e2Sdanielk1977   static struct {
158651e3d8e2Sdanielk1977      char *zName;
158751e3d8e2Sdanielk1977      Tcl_ObjCmdProc *xProc;
158851e3d8e2Sdanielk1977   } aObjCmd[] = {
158951e3d8e2Sdanielk1977      { "sqlite3_bind_int32",            (Tcl_ObjCmdProc*)test_bind_int32    },
159051e3d8e2Sdanielk1977      { "sqlite3_bind_int64",            (Tcl_ObjCmdProc*)test_bind_int64    },
159151e3d8e2Sdanielk1977      { "sqlite3_bind_double",           (Tcl_ObjCmdProc*)test_bind_double   },
159251e3d8e2Sdanielk1977      { "sqlite3_bind_null",             (Tcl_ObjCmdProc*)test_bind_null     },
159351e3d8e2Sdanielk1977      { "sqlite3_bind_text",             (Tcl_ObjCmdProc*)test_bind_text     },
159451e3d8e2Sdanielk1977      { "sqlite3_bind_text16",           (Tcl_ObjCmdProc*)test_bind_text16   },
159551e3d8e2Sdanielk1977      { "sqlite3_bind_blob",             (Tcl_ObjCmdProc*)test_bind_blob     },
15966622cce3Sdanielk1977      { "sqlite3_errcode",               (Tcl_ObjCmdProc*)test_errcode       },
15976622cce3Sdanielk1977      { "sqlite3_errmsg",                (Tcl_ObjCmdProc*)test_errmsg        },
15986622cce3Sdanielk1977      { "sqlite3_errmsg16",              (Tcl_ObjCmdProc*)test_errmsg16      },
15996622cce3Sdanielk1977      { "sqlite3_prepare",               (Tcl_ObjCmdProc*)test_prepare       },
16006622cce3Sdanielk1977      { "sqlite3_prepare16",             (Tcl_ObjCmdProc*)test_prepare16     },
16014ad1713cSdanielk1977      { "sqlite3_open",                  (Tcl_ObjCmdProc*)test_open          },
16024ad1713cSdanielk1977      { "sqlite3_open16",                (Tcl_ObjCmdProc*)test_open16        },
1603106bb236Sdanielk1977      { "sqlite3_finalize",              (Tcl_ObjCmdProc*)test_finalize      },
1604106bb236Sdanielk1977      { "sqlite3_reset",                 (Tcl_ObjCmdProc*)test_reset         },
1605106bb236Sdanielk1977      { "sqlite3_step",                  (Tcl_ObjCmdProc*)test_step_new      },
1606e1cd9874Sdanielk1977      { "sqlite3_column_data",           (Tcl_ObjCmdProc*)test_column_data   },
1607e1cd9874Sdanielk1977      { "sqlite3_column_data16",         (Tcl_ObjCmdProc*)test_column_data16   },
1608d3d39e93Sdrh      { "add_reverse_collating_func",    (Tcl_ObjCmdProc*)reverse_collfunc   },
160951e3d8e2Sdanielk1977   };
1610c2eef3b3Sdrh   int i;
1611c2eef3b3Sdrh 
1612c2eef3b3Sdrh   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
1613c2eef3b3Sdrh     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
1614c2eef3b3Sdrh   }
161551e3d8e2Sdanielk1977   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
161651e3d8e2Sdanielk1977     Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
161751e3d8e2Sdanielk1977   }
16186490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_search_count",
16196f8a503dSdanielk1977       (char*)&sqlite3_search_count, TCL_LINK_INT);
16206490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_interrupt_count",
16216f8a503dSdanielk1977       (char*)&sqlite3_interrupt_count, TCL_LINK_INT);
16226490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_open_file_count",
16236f8a503dSdanielk1977       (char*)&sqlite3_open_file_count, TCL_LINK_INT);
16246490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_current_time",
16256f8a503dSdanielk1977       (char*)&sqlite3_current_time, TCL_LINK_INT);
16267c972decSdrh   Tcl_LinkVar(interp, "sqlite_static_bind_value",
16277c972decSdrh       (char*)&sqlite_static_bind_value, TCL_LINK_STRING);
1628d1bf3512Sdrh   return TCL_OK;
1629d1bf3512Sdrh }
1630