xref: /sqlite-3.40.0/src/test1.c (revision b77f5dad)
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*b77f5dadSdanielk1977 ** $Id: test1.c,v 1.58 2004/05/26 13:27:00 danielk1977 Exp $
17d1bf3512Sdrh */
18d1bf3512Sdrh #include "sqliteInt.h"
19d1bf3512Sdrh #include "tcl.h"
2094e92032Sdrh #include "os.h"
21d1bf3512Sdrh #include <stdlib.h>
22d1bf3512Sdrh #include <string.h>
23d1bf3512Sdrh 
2494e92032Sdrh #if OS_WIN
2594e92032Sdrh # define PTR_FMT "%x"
2694e92032Sdrh #else
2794e92032Sdrh # define PTR_FMT "%p"
2894e92032Sdrh #endif
2994e92032Sdrh 
306622cce3Sdanielk1977 static const char * errorName(int rc){
316622cce3Sdanielk1977   const char *zName = 0;
326622cce3Sdanielk1977   switch( rc ){
336622cce3Sdanielk1977     case SQLITE_OK:         zName = "SQLITE_OK";          break;
346622cce3Sdanielk1977     case SQLITE_ERROR:      zName = "SQLITE_ERROR";       break;
356622cce3Sdanielk1977     case SQLITE_INTERNAL:   zName = "SQLITE_INTERNAL";    break;
366622cce3Sdanielk1977     case SQLITE_PERM:       zName = "SQLITE_PERM";        break;
376622cce3Sdanielk1977     case SQLITE_ABORT:      zName = "SQLITE_ABORT";       break;
386622cce3Sdanielk1977     case SQLITE_BUSY:       zName = "SQLITE_BUSY";        break;
396622cce3Sdanielk1977     case SQLITE_LOCKED:     zName = "SQLITE_LOCKED";      break;
406622cce3Sdanielk1977     case SQLITE_NOMEM:      zName = "SQLITE_NOMEM";       break;
416622cce3Sdanielk1977     case SQLITE_READONLY:   zName = "SQLITE_READONLY";    break;
426622cce3Sdanielk1977     case SQLITE_INTERRUPT:  zName = "SQLITE_INTERRUPT";   break;
436622cce3Sdanielk1977     case SQLITE_IOERR:      zName = "SQLITE_IOERR";       break;
446622cce3Sdanielk1977     case SQLITE_CORRUPT:    zName = "SQLITE_CORRUPT";     break;
456622cce3Sdanielk1977     case SQLITE_NOTFOUND:   zName = "SQLITE_NOTFOUND";    break;
466622cce3Sdanielk1977     case SQLITE_FULL:       zName = "SQLITE_FULL";        break;
476622cce3Sdanielk1977     case SQLITE_CANTOPEN:   zName = "SQLITE_CANTOPEN";    break;
486622cce3Sdanielk1977     case SQLITE_PROTOCOL:   zName = "SQLITE_PROTOCOL";    break;
496622cce3Sdanielk1977     case SQLITE_EMPTY:      zName = "SQLITE_EMPTY";       break;
506622cce3Sdanielk1977     case SQLITE_SCHEMA:     zName = "SQLITE_SCHEMA";      break;
516622cce3Sdanielk1977     case SQLITE_TOOBIG:     zName = "SQLITE_TOOBIG";      break;
526622cce3Sdanielk1977     case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT";  break;
536622cce3Sdanielk1977     case SQLITE_MISMATCH:   zName = "SQLITE_MISMATCH";    break;
546622cce3Sdanielk1977     case SQLITE_MISUSE:     zName = "SQLITE_MISUSE";      break;
556622cce3Sdanielk1977     case SQLITE_NOLFS:      zName = "SQLITE_NOLFS";       break;
566622cce3Sdanielk1977     case SQLITE_AUTH:       zName = "SQLITE_AUTH";        break;
576622cce3Sdanielk1977     case SQLITE_FORMAT:     zName = "SQLITE_FORMAT";      break;
586622cce3Sdanielk1977     case SQLITE_RANGE:      zName = "SQLITE_RANGE";       break;
596622cce3Sdanielk1977     case SQLITE_ROW:        zName = "SQLITE_ROW";         break;
606622cce3Sdanielk1977     case SQLITE_DONE:       zName = "SQLITE_DONE";        break;
616622cce3Sdanielk1977     default:                zName = "SQLITE_Unknown";     break;
626622cce3Sdanielk1977   }
636622cce3Sdanielk1977   return zName;
646622cce3Sdanielk1977 }
656622cce3Sdanielk1977 
66d1bf3512Sdrh /*
67b86ccfb2Sdrh ** Decode a pointer to an sqlite object.
68b86ccfb2Sdrh */
6990f405e3Sdrh static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite **ppDb){
7090f405e3Sdrh   if( sscanf(zA, PTR_FMT, (void**)ppDb)!=1 &&
7190f405e3Sdrh       (zA[0]!='0' || zA[1]!='x' || sscanf(&zA[2], PTR_FMT, (void**)ppDb)!=1)
7290f405e3Sdrh   ){
7390f405e3Sdrh     Tcl_AppendResult(interp, "\"", zA, "\" is not a valid pointer value", 0);
74b86ccfb2Sdrh     return TCL_ERROR;
75b86ccfb2Sdrh   }
76b86ccfb2Sdrh   return TCL_OK;
77b86ccfb2Sdrh }
78b86ccfb2Sdrh 
79b86ccfb2Sdrh /*
8051e3d8e2Sdanielk1977 ** Decode a pointer to an sqlite3_stmt object.
8151e3d8e2Sdanielk1977 */
8251e3d8e2Sdanielk1977 static int getStmtPointer(
8351e3d8e2Sdanielk1977   Tcl_Interp *interp,
8451e3d8e2Sdanielk1977   const char *zArg,
8551e3d8e2Sdanielk1977   sqlite3_stmt **ppStmt
8651e3d8e2Sdanielk1977 ){
8751e3d8e2Sdanielk1977   if( sscanf(zArg, PTR_FMT, (void**)ppStmt)!=1 ){
8851e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0);
8951e3d8e2Sdanielk1977     return TCL_ERROR;
9051e3d8e2Sdanielk1977   }
9151e3d8e2Sdanielk1977   return TCL_OK;
9251e3d8e2Sdanielk1977 }
9351e3d8e2Sdanielk1977 
9451e3d8e2Sdanielk1977 /*
957d8085a8Sdrh ** Generate a text representation of a pointer that can be understood
967d8085a8Sdrh ** by the getDbPointer and getVmPointer routines above.
977d8085a8Sdrh **
987d8085a8Sdrh ** The problem is, on some machines (Solaris) if you do a printf with
997d8085a8Sdrh ** "%p" you cannot turn around and do a scanf with the same "%p" and
1007d8085a8Sdrh ** get your pointer back.  You have to prepend a "0x" before it will
1017d8085a8Sdrh ** work.  Or at least that is what is reported to me (drh).  But this
1027d8085a8Sdrh ** behavior varies from machine to machine.  The solution used her is
1037d8085a8Sdrh ** to test the string right after it is generated to see if it can be
1047d8085a8Sdrh ** understood by scanf, and if not, try prepending an "0x" to see if
1057d8085a8Sdrh ** that helps.  If nothing works, a fatal error is generated.
1067d8085a8Sdrh */
1077d8085a8Sdrh static int makePointerStr(Tcl_Interp *interp, char *zPtr, void *p){
1087d8085a8Sdrh   void *p2;
1097d8085a8Sdrh   sprintf(zPtr, PTR_FMT, p);
1107d8085a8Sdrh   if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){
1117d8085a8Sdrh     sprintf(zPtr, "0x" PTR_FMT, p);
1127d8085a8Sdrh     if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){
1137d8085a8Sdrh       Tcl_AppendResult(interp, "unable to convert a pointer to a string "
1147d8085a8Sdrh          "in the file " __FILE__ " in function makePointerStr().  Please "
1157d8085a8Sdrh          "report this problem to the SQLite mailing list or as a new but "
1167d8085a8Sdrh          "report.  Please provide detailed information about how you compiled "
1177d8085a8Sdrh          "SQLite and what computer you are running on.", 0);
1187d8085a8Sdrh       return TCL_ERROR;
1197d8085a8Sdrh     }
1207d8085a8Sdrh   }
1217d8085a8Sdrh   return TCL_OK;
1227d8085a8Sdrh }
1237d8085a8Sdrh 
1247d8085a8Sdrh /*
1256f8a503dSdanielk1977 ** The callback routine for sqlite3_exec_printf().
126d1bf3512Sdrh */
127d1bf3512Sdrh static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){
128d1bf3512Sdrh   Tcl_DString *str = (Tcl_DString*)pArg;
129d1bf3512Sdrh   int i;
130d1bf3512Sdrh 
131d1bf3512Sdrh   if( Tcl_DStringLength(str)==0 ){
132d1bf3512Sdrh     for(i=0; i<argc; i++){
133d1bf3512Sdrh       Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL");
134d1bf3512Sdrh     }
135d1bf3512Sdrh   }
136d1bf3512Sdrh   for(i=0; i<argc; i++){
137d1bf3512Sdrh     Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL");
138d1bf3512Sdrh   }
139d1bf3512Sdrh   return 0;
140d1bf3512Sdrh }
141d1bf3512Sdrh 
142d1bf3512Sdrh /*
1436f8a503dSdanielk1977 ** Usage:  sqlite3_exec_printf  DB  FORMAT  STRING
144d1bf3512Sdrh **
1456f8a503dSdanielk1977 ** Invoke the sqlite3_exec_printf() interface using the open database
146d1bf3512Sdrh ** DB.  The SQL is the string FORMAT.  The format string should contain
147d1bf3512Sdrh ** one %s or %q.  STRING is the value inserted into %s or %q.
148d1bf3512Sdrh */
149d1bf3512Sdrh static int test_exec_printf(
150d1bf3512Sdrh   void *NotUsed,
151d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
152d1bf3512Sdrh   int argc,              /* Number of arguments */
153d1bf3512Sdrh   char **argv            /* Text of each argument */
154d1bf3512Sdrh ){
155d1bf3512Sdrh   sqlite *db;
156d1bf3512Sdrh   Tcl_DString str;
157d1bf3512Sdrh   int rc;
158d1bf3512Sdrh   char *zErr = 0;
159d1bf3512Sdrh   char zBuf[30];
160d1bf3512Sdrh   if( argc!=4 ){
161d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
162d1bf3512Sdrh        " DB FORMAT STRING", 0);
163d1bf3512Sdrh     return TCL_ERROR;
164d1bf3512Sdrh   }
165b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
166d1bf3512Sdrh   Tcl_DStringInit(&str);
1676f8a503dSdanielk1977   rc = sqlite3_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]);
168d1bf3512Sdrh   sprintf(zBuf, "%d", rc);
169d1bf3512Sdrh   Tcl_AppendElement(interp, zBuf);
170d1bf3512Sdrh   Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
171d1bf3512Sdrh   Tcl_DStringFree(&str);
172d1bf3512Sdrh   if( zErr ) free(zErr);
173d1bf3512Sdrh   return TCL_OK;
174d1bf3512Sdrh }
175d1bf3512Sdrh 
176d1bf3512Sdrh /*
1776f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_z_test  SEPARATOR  ARG0  ARG1 ...
178d93d8a81Sdrh **
179d93d8a81Sdrh ** Test the %z format of mprintf().  Use multiple mprintf() calls to
180d93d8a81Sdrh ** concatenate arg0 through argn using separator as the separator.
181d93d8a81Sdrh ** Return the result.
182d93d8a81Sdrh */
183d93d8a81Sdrh static int test_mprintf_z(
184d93d8a81Sdrh   void *NotUsed,
185d93d8a81Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
186d93d8a81Sdrh   int argc,              /* Number of arguments */
187d93d8a81Sdrh   char **argv            /* Text of each argument */
188d93d8a81Sdrh ){
189d93d8a81Sdrh   char *zResult = 0;
190d93d8a81Sdrh   int i;
191d93d8a81Sdrh 
192d93d8a81Sdrh   for(i=2; i<argc; i++){
1934adee20fSdanielk1977     zResult = sqlite3MPrintf("%z%s%s", zResult, argv[1], argv[i]);
194d93d8a81Sdrh   }
195d93d8a81Sdrh   Tcl_AppendResult(interp, zResult, 0);
1965f968436Sdrh   sqliteFree(zResult);
197d93d8a81Sdrh   return TCL_OK;
198d93d8a81Sdrh }
199d93d8a81Sdrh 
200d93d8a81Sdrh /*
2016f8a503dSdanielk1977 ** Usage:  sqlite3_get_table_printf  DB  FORMAT  STRING
202d1bf3512Sdrh **
2036f8a503dSdanielk1977 ** Invoke the sqlite3_get_table_printf() interface using the open database
204d1bf3512Sdrh ** DB.  The SQL is the string FORMAT.  The format string should contain
205d1bf3512Sdrh ** one %s or %q.  STRING is the value inserted into %s or %q.
206d1bf3512Sdrh */
207d1bf3512Sdrh static int test_get_table_printf(
208d1bf3512Sdrh   void *NotUsed,
209d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
210d1bf3512Sdrh   int argc,              /* Number of arguments */
211d1bf3512Sdrh   char **argv            /* Text of each argument */
212d1bf3512Sdrh ){
213d1bf3512Sdrh   sqlite *db;
214d1bf3512Sdrh   Tcl_DString str;
215d1bf3512Sdrh   int rc;
216d1bf3512Sdrh   char *zErr = 0;
217d1bf3512Sdrh   int nRow, nCol;
218d1bf3512Sdrh   char **aResult;
219d1bf3512Sdrh   int i;
220d1bf3512Sdrh   char zBuf[30];
221d1bf3512Sdrh   if( argc!=4 ){
222d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
223d1bf3512Sdrh        " DB FORMAT STRING", 0);
224d1bf3512Sdrh     return TCL_ERROR;
225d1bf3512Sdrh   }
226b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
227d1bf3512Sdrh   Tcl_DStringInit(&str);
2286f8a503dSdanielk1977   rc = sqlite3_get_table_printf(db, argv[2], &aResult, &nRow, &nCol,
229d1bf3512Sdrh                &zErr, argv[3]);
230d1bf3512Sdrh   sprintf(zBuf, "%d", rc);
231d1bf3512Sdrh   Tcl_AppendElement(interp, zBuf);
232d1bf3512Sdrh   if( rc==SQLITE_OK ){
233d1bf3512Sdrh     sprintf(zBuf, "%d", nRow);
234d1bf3512Sdrh     Tcl_AppendElement(interp, zBuf);
235d1bf3512Sdrh     sprintf(zBuf, "%d", nCol);
236d1bf3512Sdrh     Tcl_AppendElement(interp, zBuf);
237d1bf3512Sdrh     for(i=0; i<(nRow+1)*nCol; i++){
238d1bf3512Sdrh       Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL");
239d1bf3512Sdrh     }
240d1bf3512Sdrh   }else{
241d1bf3512Sdrh     Tcl_AppendElement(interp, zErr);
242d1bf3512Sdrh   }
2436f8a503dSdanielk1977   sqlite3_free_table(aResult);
244d1bf3512Sdrh   if( zErr ) free(zErr);
245d1bf3512Sdrh   return TCL_OK;
246d1bf3512Sdrh }
247d1bf3512Sdrh 
248af9ff33aSdrh 
249af9ff33aSdrh /*
2506f8a503dSdanielk1977 ** Usage:  sqlite3_last_insert_rowid DB
251af9ff33aSdrh **
252af9ff33aSdrh ** Returns the integer ROWID of the most recent insert.
253af9ff33aSdrh */
254af9ff33aSdrh static int test_last_rowid(
255af9ff33aSdrh   void *NotUsed,
256af9ff33aSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
257af9ff33aSdrh   int argc,              /* Number of arguments */
258af9ff33aSdrh   char **argv            /* Text of each argument */
259af9ff33aSdrh ){
260af9ff33aSdrh   sqlite *db;
261af9ff33aSdrh   char zBuf[30];
262af9ff33aSdrh 
263af9ff33aSdrh   if( argc!=2 ){
264af9ff33aSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0);
265af9ff33aSdrh     return TCL_ERROR;
266af9ff33aSdrh   }
267b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
2686f8a503dSdanielk1977   sprintf(zBuf, "%d", sqlite3_last_insert_rowid(db));
269af9ff33aSdrh   Tcl_AppendResult(interp, zBuf, 0);
270af9ff33aSdrh   return SQLITE_OK;
271af9ff33aSdrh }
272af9ff33aSdrh 
273d1bf3512Sdrh /*
2746f8a503dSdanielk1977 ** Usage:  sqlite3_close DB
275d1bf3512Sdrh **
2766f8a503dSdanielk1977 ** Closes the database opened by sqlite3_open.
277d1bf3512Sdrh */
278d1bf3512Sdrh static int sqlite_test_close(
279d1bf3512Sdrh   void *NotUsed,
280d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
281d1bf3512Sdrh   int argc,              /* Number of arguments */
282d1bf3512Sdrh   char **argv            /* Text of each argument */
283d1bf3512Sdrh ){
284d1bf3512Sdrh   sqlite *db;
285d1bf3512Sdrh   if( argc!=2 ){
286d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
287d1bf3512Sdrh        " FILENAME\"", 0);
288d1bf3512Sdrh     return TCL_ERROR;
289d1bf3512Sdrh   }
290b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
2916f8a503dSdanielk1977   sqlite3_close(db);
292d1bf3512Sdrh   return TCL_OK;
293d1bf3512Sdrh }
294d1bf3512Sdrh 
295d1bf3512Sdrh /*
296c22bd47dSdrh ** Implementation of the x_coalesce() function.
297c22bd47dSdrh ** Return the first argument non-NULL argument.
298c22bd47dSdrh */
2990ae8b831Sdanielk1977 static void ifnullFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
300c22bd47dSdrh   int i;
301c22bd47dSdrh   for(i=0; i<argc; i++){
30251ad0ecdSdanielk1977     if( SQLITE3_NULL!=sqlite3_value_type(argv[i]) ){
3037e18c259Sdanielk1977       sqlite3_result_text(context, sqlite3_value_data(argv[i]), -1, 1);
304c22bd47dSdrh       break;
305c22bd47dSdrh     }
306c22bd47dSdrh   }
307c22bd47dSdrh }
308c22bd47dSdrh 
309c22bd47dSdrh /*
310d1d9fc33Sdrh ** A structure into which to accumulate text.
311d1d9fc33Sdrh */
312d1d9fc33Sdrh struct dstr {
313d1d9fc33Sdrh   int nAlloc;  /* Space allocated */
314d1d9fc33Sdrh   int nUsed;   /* Space used */
315d1d9fc33Sdrh   char *z;     /* The space */
316d1d9fc33Sdrh };
317d1d9fc33Sdrh 
318d1d9fc33Sdrh /*
319d1d9fc33Sdrh ** Append text to a dstr
320d1d9fc33Sdrh */
321d1d9fc33Sdrh static void dstrAppend(struct dstr *p, const char *z, int divider){
322d1d9fc33Sdrh   int n = strlen(z);
323d1d9fc33Sdrh   if( p->nUsed + n + 2 > p->nAlloc ){
324d1d9fc33Sdrh     char *zNew;
325d1d9fc33Sdrh     p->nAlloc = p->nAlloc*2 + n + 200;
326d1d9fc33Sdrh     zNew = sqliteRealloc(p->z, p->nAlloc);
327d1d9fc33Sdrh     if( zNew==0 ){
328d1d9fc33Sdrh       sqliteFree(p->z);
329d1d9fc33Sdrh       memset(p, 0, sizeof(*p));
330d1d9fc33Sdrh       return;
331d1d9fc33Sdrh     }
332d1d9fc33Sdrh     p->z = zNew;
333d1d9fc33Sdrh   }
334d1d9fc33Sdrh   if( divider && p->nUsed>0 ){
335d1d9fc33Sdrh     p->z[p->nUsed++] = divider;
336d1d9fc33Sdrh   }
337d1d9fc33Sdrh   memcpy(&p->z[p->nUsed], z, n+1);
338d1d9fc33Sdrh   p->nUsed += n;
339d1d9fc33Sdrh }
340d1d9fc33Sdrh 
341d1d9fc33Sdrh /*
3424adee20fSdanielk1977 ** Invoked for each callback from sqlite3ExecFunc
343d1d9fc33Sdrh */
344d1d9fc33Sdrh static int execFuncCallback(void *pData, int argc, char **argv, char **NotUsed){
345d1d9fc33Sdrh   struct dstr *p = (struct dstr*)pData;
346d1d9fc33Sdrh   int i;
347d1d9fc33Sdrh   for(i=0; i<argc; i++){
348d1d9fc33Sdrh     if( argv[i]==0 ){
349d1d9fc33Sdrh       dstrAppend(p, "NULL", ' ');
350d1d9fc33Sdrh     }else{
351d1d9fc33Sdrh       dstrAppend(p, argv[i], ' ');
352d1d9fc33Sdrh     }
353d1d9fc33Sdrh   }
354d1d9fc33Sdrh   return 0;
355d1d9fc33Sdrh }
356d1d9fc33Sdrh 
357d1d9fc33Sdrh /*
3586f8a503dSdanielk1977 ** Implementation of the x_sqlite3_exec() function.  This function takes
359c22bd47dSdrh ** a single argument and attempts to execute that argument as SQL code.
3606cbe1f1bSdrh ** This is illegal and should set the SQLITE_MISUSE flag on the database.
361c22bd47dSdrh **
3626f8a503dSdanielk1977 ** 2004-Jan-07:  We have changed this to make it legal to call sqlite3_exec()
363d1d9fc33Sdrh ** from within a function call.
364d1d9fc33Sdrh **
365c22bd47dSdrh ** This routine simulates the effect of having two threads attempt to
366c22bd47dSdrh ** use the same database at the same time.
367c22bd47dSdrh */
36851ad0ecdSdanielk1977 static void sqlite3ExecFunc(
3690ae8b831Sdanielk1977   sqlite3_context *context,
37051ad0ecdSdanielk1977   int argc,
37151ad0ecdSdanielk1977   sqlite3_value **argv
37251ad0ecdSdanielk1977 ){
373d1d9fc33Sdrh   struct dstr x;
374d1d9fc33Sdrh   memset(&x, 0, sizeof(x));
37551ad0ecdSdanielk1977   sqlite3_exec((sqlite*)sqlite3_user_data(context),
37651ad0ecdSdanielk1977       sqlite3_value_data(argv[0]),
377d1d9fc33Sdrh       execFuncCallback, &x, 0);
3787e18c259Sdanielk1977   sqlite3_result_text(context, x.z, x.nUsed, 1);
379d1d9fc33Sdrh   sqliteFree(x.z);
380c22bd47dSdrh }
381c22bd47dSdrh 
382c22bd47dSdrh /*
383c22bd47dSdrh ** Usage:  sqlite_test_create_function DB
384c22bd47dSdrh **
3856f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order
386c22bd47dSdrh ** to create a function named "x_coalesce".  This function does the same thing
387c22bd47dSdrh ** as the "coalesce" function.  This function also registers an SQL function
3886f8a503dSdanielk1977 ** named "x_sqlite3_exec" that invokes sqlite3_exec().  Invoking sqlite3_exec()
389c22bd47dSdrh ** in this way is illegal recursion and should raise an SQLITE_MISUSE error.
390c22bd47dSdrh ** The effect is similar to trying to use the same database connection from
391c22bd47dSdrh ** two threads at the same time.
392c22bd47dSdrh **
393c22bd47dSdrh ** The original motivation for this routine was to be able to call the
3946f8a503dSdanielk1977 ** sqlite3_create_function function while a query is in progress in order
395c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
396c22bd47dSdrh */
397c2eef3b3Sdrh static int test_create_function(
398c22bd47dSdrh   void *NotUsed,
399c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
400c22bd47dSdrh   int argc,              /* Number of arguments */
401c22bd47dSdrh   char **argv            /* Text of each argument */
402c22bd47dSdrh ){
403c22bd47dSdrh   sqlite *db;
404c22bd47dSdrh   extern void Md5_Register(sqlite*);
405c22bd47dSdrh   if( argc!=2 ){
406c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
407c22bd47dSdrh        " FILENAME\"", 0);
408c22bd47dSdrh     return TCL_ERROR;
409c22bd47dSdrh   }
410b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
4116590493dSdanielk1977   sqlite3_create_function(db, "x_coalesce", -1, 0, 0, 0, ifnullFunc, 0, 0);
4126590493dSdanielk1977   sqlite3_create_function(db, "x_sqlite3_exec", 1, 0, 0, db,
4136590493dSdanielk1977       sqlite3ExecFunc, 0, 0);
414c22bd47dSdrh   return TCL_OK;
415c22bd47dSdrh }
416c22bd47dSdrh 
417c22bd47dSdrh /*
418c22bd47dSdrh ** Routines to implement the x_count() aggregate function.
419c22bd47dSdrh */
420c22bd47dSdrh typedef struct CountCtx CountCtx;
421c22bd47dSdrh struct CountCtx {
422c22bd47dSdrh   int n;
423c22bd47dSdrh };
4240ae8b831Sdanielk1977 static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
425c22bd47dSdrh   CountCtx *p;
4260ae8b831Sdanielk1977   p = sqlite3_get_context(context, sizeof(*p));
4276ddcca55Sdanielk1977   if( (argc==0 || SQLITE3_NULL!=sqlite3_value_type(argv[0]) ) && p ){
428c22bd47dSdrh     p->n++;
429c22bd47dSdrh   }
430c22bd47dSdrh }
4310ae8b831Sdanielk1977 static void countFinalize(sqlite3_context *context){
432c22bd47dSdrh   CountCtx *p;
4330ae8b831Sdanielk1977   p = sqlite3_get_context(context, sizeof(*p));
4347e18c259Sdanielk1977   sqlite3_result_int32(context, p ? p->n : 0);
435c22bd47dSdrh }
436c22bd47dSdrh 
437c22bd47dSdrh /*
438c22bd47dSdrh ** Usage:  sqlite_test_create_aggregate DB
439c22bd47dSdrh **
4406f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order
441c22bd47dSdrh ** to create a function named "x_count".  This function does the same thing
442c22bd47dSdrh ** as the "md5sum" function.
443c22bd47dSdrh **
444c22bd47dSdrh ** The original motivation for this routine was to be able to call the
4456f8a503dSdanielk1977 ** sqlite3_create_aggregate function while a query is in progress in order
446c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
447c22bd47dSdrh */
448c2eef3b3Sdrh static int test_create_aggregate(
449c22bd47dSdrh   void *NotUsed,
450c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
451c22bd47dSdrh   int argc,              /* Number of arguments */
452c22bd47dSdrh   char **argv            /* Text of each argument */
453c22bd47dSdrh ){
454c22bd47dSdrh   sqlite *db;
455c22bd47dSdrh   if( argc!=2 ){
456c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
457c22bd47dSdrh        " FILENAME\"", 0);
458c22bd47dSdrh     return TCL_ERROR;
459c22bd47dSdrh   }
460b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
4616590493dSdanielk1977   sqlite3_create_function(db, "x_count", 0, 0, 0, 0, 0,countStep,countFinalize);
4626590493dSdanielk1977   sqlite3_create_function(db, "x_count", 1, 0, 0, 0, 0,countStep,countFinalize);
463c22bd47dSdrh   return TCL_OK;
464c22bd47dSdrh }
465c22bd47dSdrh 
466c22bd47dSdrh 
467c22bd47dSdrh 
468c22bd47dSdrh /*
4696f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER
470d1bf3512Sdrh **
471d1bf3512Sdrh ** Call mprintf with three integer arguments
472d1bf3512Sdrh */
4736f8a503dSdanielk1977 static int sqlite3_mprintf_int(
474d1bf3512Sdrh   void *NotUsed,
475d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
476d1bf3512Sdrh   int argc,              /* Number of arguments */
477d1bf3512Sdrh   char **argv            /* Text of each argument */
478d1bf3512Sdrh ){
479d1bf3512Sdrh   int a[3], i;
480d1bf3512Sdrh   char *z;
481d1bf3512Sdrh   if( argc!=5 ){
482d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
483d1bf3512Sdrh        " FORMAT INT INT INT\"", 0);
484d1bf3512Sdrh     return TCL_ERROR;
485d1bf3512Sdrh   }
486d1bf3512Sdrh   for(i=2; i<5; i++){
487d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
488d1bf3512Sdrh   }
4896f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]);
490d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
4916f8a503dSdanielk1977   sqlite3_freemem(z);
492d1bf3512Sdrh   return TCL_OK;
493d1bf3512Sdrh }
494d1bf3512Sdrh 
495d1bf3512Sdrh /*
4966f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT INTEGER INTEGER STRING
497d1bf3512Sdrh **
498d1bf3512Sdrh ** Call mprintf with two integer arguments and one string argument
499d1bf3512Sdrh */
5006f8a503dSdanielk1977 static int sqlite3_mprintf_str(
501d1bf3512Sdrh   void *NotUsed,
502d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
503d1bf3512Sdrh   int argc,              /* Number of arguments */
504d1bf3512Sdrh   char **argv            /* Text of each argument */
505d1bf3512Sdrh ){
506d1bf3512Sdrh   int a[3], i;
507d1bf3512Sdrh   char *z;
508f220b24fSchw   if( argc<4 || argc>5 ){
509d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
510f220b24fSchw        " FORMAT INT INT ?STRING?\"", 0);
511d1bf3512Sdrh     return TCL_ERROR;
512d1bf3512Sdrh   }
513d1bf3512Sdrh   for(i=2; i<4; i++){
514d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
515d1bf3512Sdrh   }
5166f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL);
517d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
5186f8a503dSdanielk1977   sqlite3_freemem(z);
519d1bf3512Sdrh   return TCL_OK;
520d1bf3512Sdrh }
521d1bf3512Sdrh 
522d1bf3512Sdrh /*
5236f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT INTEGER INTEGER DOUBLE
524d1bf3512Sdrh **
525d1bf3512Sdrh ** Call mprintf with two integer arguments and one double argument
526d1bf3512Sdrh */
5276f8a503dSdanielk1977 static int sqlite3_mprintf_double(
528d1bf3512Sdrh   void *NotUsed,
529d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
530d1bf3512Sdrh   int argc,              /* Number of arguments */
531d1bf3512Sdrh   char **argv            /* Text of each argument */
532d1bf3512Sdrh ){
533d1bf3512Sdrh   int a[3], i;
534d1bf3512Sdrh   double r;
535d1bf3512Sdrh   char *z;
536d1bf3512Sdrh   if( argc!=5 ){
537d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
538d1bf3512Sdrh        " FORMAT INT INT STRING\"", 0);
539d1bf3512Sdrh     return TCL_ERROR;
540d1bf3512Sdrh   }
541d1bf3512Sdrh   for(i=2; i<4; i++){
542d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
543d1bf3512Sdrh   }
544d1bf3512Sdrh   if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR;
5456f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], r);
546d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
5476f8a503dSdanielk1977   sqlite3_freemem(z);
548d1bf3512Sdrh   return TCL_OK;
549d1bf3512Sdrh }
550d1bf3512Sdrh 
551d1bf3512Sdrh /*
5526f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT DOUBLE DOUBLE
553b621c237Sdrh **
554b621c237Sdrh ** Call mprintf with a single double argument which is the product of the
555b621c237Sdrh ** two arguments given above.  This is used to generate overflow and underflow
556b621c237Sdrh ** doubles to test that they are converted properly.
557b621c237Sdrh */
5586f8a503dSdanielk1977 static int sqlite3_mprintf_scaled(
559b621c237Sdrh   void *NotUsed,
560b621c237Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
561b621c237Sdrh   int argc,              /* Number of arguments */
562b621c237Sdrh   char **argv            /* Text of each argument */
563b621c237Sdrh ){
564b621c237Sdrh   int i;
565b621c237Sdrh   double r[2];
566b621c237Sdrh   char *z;
567b621c237Sdrh   if( argc!=4 ){
568b621c237Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
569b621c237Sdrh        " FORMAT DOUBLE DOUBLE\"", 0);
570b621c237Sdrh     return TCL_ERROR;
571b621c237Sdrh   }
572b621c237Sdrh   for(i=2; i<4; i++){
573b621c237Sdrh     if( Tcl_GetDouble(interp, argv[i], &r[i-2]) ) return TCL_ERROR;
574b621c237Sdrh   }
5756f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], r[0]*r[1]);
576b621c237Sdrh   Tcl_AppendResult(interp, z, 0);
5776f8a503dSdanielk1977   sqlite3_freemem(z);
578b621c237Sdrh   return TCL_OK;
579b621c237Sdrh }
580b621c237Sdrh 
581b621c237Sdrh /*
582daffd0e5Sdrh ** Usage: sqlite_malloc_fail N
583daffd0e5Sdrh **
584afa4a020Sdrh ** Rig sqliteMalloc() to fail on the N-th call.  Turn off this mechanism
5856f8a503dSdanielk1977 ** and reset the sqlite3_malloc_failed variable is N==0.
586daffd0e5Sdrh */
587daffd0e5Sdrh #ifdef MEMORY_DEBUG
588daffd0e5Sdrh static int sqlite_malloc_fail(
589daffd0e5Sdrh   void *NotUsed,
590daffd0e5Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
591daffd0e5Sdrh   int argc,              /* Number of arguments */
592daffd0e5Sdrh   char **argv            /* Text of each argument */
593daffd0e5Sdrh ){
594daffd0e5Sdrh   int n;
595daffd0e5Sdrh   if( argc!=2 ){
596daffd0e5Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0);
597daffd0e5Sdrh     return TCL_ERROR;
598daffd0e5Sdrh   }
599daffd0e5Sdrh   if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
6006f8a503dSdanielk1977   sqlite3_iMallocFail = n;
6016f8a503dSdanielk1977   sqlite3_malloc_failed = 0;
602daffd0e5Sdrh   return TCL_OK;
603daffd0e5Sdrh }
604daffd0e5Sdrh #endif
605daffd0e5Sdrh 
606daffd0e5Sdrh /*
607daffd0e5Sdrh ** Usage: sqlite_malloc_stat
608daffd0e5Sdrh **
609daffd0e5Sdrh ** Return the number of prior calls to sqliteMalloc() and sqliteFree().
610daffd0e5Sdrh */
611daffd0e5Sdrh #ifdef MEMORY_DEBUG
612daffd0e5Sdrh static int sqlite_malloc_stat(
613daffd0e5Sdrh   void *NotUsed,
614daffd0e5Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
615daffd0e5Sdrh   int argc,              /* Number of arguments */
616daffd0e5Sdrh   char **argv            /* Text of each argument */
617daffd0e5Sdrh ){
618daffd0e5Sdrh   char zBuf[200];
6196f8a503dSdanielk1977   sprintf(zBuf, "%d %d %d", sqlite3_nMalloc, sqlite3_nFree, sqlite3_iMallocFail);
620daffd0e5Sdrh   Tcl_AppendResult(interp, zBuf, 0);
621daffd0e5Sdrh   return TCL_OK;
622daffd0e5Sdrh }
623daffd0e5Sdrh #endif
624daffd0e5Sdrh 
625daffd0e5Sdrh /*
62628b4e489Sdrh ** Usage:  sqlite_abort
62728b4e489Sdrh **
62828b4e489Sdrh ** Shutdown the process immediately.  This is not a clean shutdown.
62928b4e489Sdrh ** This command is used to test the recoverability of a database in
63028b4e489Sdrh ** the event of a program crash.
63128b4e489Sdrh */
63228b4e489Sdrh static int sqlite_abort(
63328b4e489Sdrh   void *NotUsed,
63428b4e489Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
63528b4e489Sdrh   int argc,              /* Number of arguments */
63628b4e489Sdrh   char **argv            /* Text of each argument */
63728b4e489Sdrh ){
63828b4e489Sdrh   assert( interp==0 );   /* This will always fail */
63928b4e489Sdrh   return TCL_OK;
64028b4e489Sdrh }
64128b4e489Sdrh 
64228b4e489Sdrh /*
6436cbe1f1bSdrh ** The following routine is a user-defined SQL function whose purpose
6446cbe1f1bSdrh ** is to test the sqlite_set_result() API.
6456cbe1f1bSdrh */
6460ae8b831Sdanielk1977 static void testFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
6476cbe1f1bSdrh   while( argc>=2 ){
64851ad0ecdSdanielk1977     const char *zArg0 = sqlite3_value_data(argv[0]);
64951ad0ecdSdanielk1977     const char *zArg1 = sqlite3_value_data(argv[1]);
65051ad0ecdSdanielk1977     if( zArg0==0 ){
6517e18c259Sdanielk1977       sqlite3_result_error(context, "first argument to test function "
6526cbe1f1bSdrh          "may not be NULL", -1);
65351ad0ecdSdanielk1977     }else if( sqlite3StrICmp(zArg0,"string")==0 ){
6547e18c259Sdanielk1977       sqlite3_result_text(context, zArg1, -1, 1);
65551ad0ecdSdanielk1977     }else if( zArg1==0 ){
6567e18c259Sdanielk1977       sqlite3_result_error(context, "2nd argument may not be NULL if the "
6576cbe1f1bSdrh          "first argument is not \"string\"", -1);
65851ad0ecdSdanielk1977     }else if( sqlite3StrICmp(zArg0,"int")==0 ){
6597e18c259Sdanielk1977       sqlite3_result_int32(context, atoi(zArg1));
66051ad0ecdSdanielk1977     }else if( sqlite3StrICmp(zArg0,"double")==0 ){
6617e18c259Sdanielk1977       sqlite3_result_double(context, sqlite3AtoF(zArg1, 0));
6626cbe1f1bSdrh     }else{
6637e18c259Sdanielk1977       sqlite3_result_error(context,"first argument should be one of: "
6646cbe1f1bSdrh           "string int double", -1);
6656cbe1f1bSdrh     }
6666cbe1f1bSdrh     argc -= 2;
6676cbe1f1bSdrh     argv += 2;
6686cbe1f1bSdrh   }
6696cbe1f1bSdrh }
6706cbe1f1bSdrh 
6716cbe1f1bSdrh /*
6726cbe1f1bSdrh ** Usage:   sqlite_register_test_function  DB  NAME
6736cbe1f1bSdrh **
6746cbe1f1bSdrh ** Register the test SQL function on the database DB under the name NAME.
6756cbe1f1bSdrh */
676c2eef3b3Sdrh static int test_register_func(
6776cbe1f1bSdrh   void *NotUsed,
6786cbe1f1bSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6796cbe1f1bSdrh   int argc,              /* Number of arguments */
6806cbe1f1bSdrh   char **argv            /* Text of each argument */
6816cbe1f1bSdrh ){
6826cbe1f1bSdrh   sqlite *db;
6836cbe1f1bSdrh   int rc;
6846cbe1f1bSdrh   if( argc!=3 ){
6856cbe1f1bSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
6866cbe1f1bSdrh        " DB FUNCTION-NAME", 0);
6876cbe1f1bSdrh     return TCL_ERROR;
6886cbe1f1bSdrh   }
689b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
6906590493dSdanielk1977   rc = sqlite3_create_function(db, argv[2], -1, 0, 0, 0, testFunc, 0, 0);
6916cbe1f1bSdrh   if( rc!=0 ){
6926f8a503dSdanielk1977     Tcl_AppendResult(interp, sqlite3_error_string(rc), 0);
6936cbe1f1bSdrh     return TCL_ERROR;
6946cbe1f1bSdrh   }
6956cbe1f1bSdrh   return TCL_OK;
6966cbe1f1bSdrh }
6976cbe1f1bSdrh 
6986cbe1f1bSdrh /*
699106bb236Sdanielk1977 ** Usage:  sqlite3_finalize  STMT
700b86ccfb2Sdrh **
701106bb236Sdanielk1977 ** Finalize a statement handle.
702b86ccfb2Sdrh */
703b86ccfb2Sdrh static int test_finalize(
704106bb236Sdanielk1977   void * clientData,
705106bb236Sdanielk1977   Tcl_Interp *interp,
706106bb236Sdanielk1977   int objc,
707106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
708b86ccfb2Sdrh ){
709106bb236Sdanielk1977   sqlite3_stmt *pStmt;
710b86ccfb2Sdrh   int rc;
711106bb236Sdanielk1977 
712106bb236Sdanielk1977   if( objc!=2 ){
713106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
714106bb236Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
715b86ccfb2Sdrh     return TCL_ERROR;
716b86ccfb2Sdrh   }
717106bb236Sdanielk1977 
718106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
719106bb236Sdanielk1977 
720fc57d7bfSdanielk1977   rc = sqlite3_finalize(pStmt);
721*b77f5dadSdanielk1977   Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
722b86ccfb2Sdrh   if( rc ){
723106bb236Sdanielk1977     return TCL_ERROR;
724106bb236Sdanielk1977   }
725106bb236Sdanielk1977   return TCL_OK;
726106bb236Sdanielk1977 }
727106bb236Sdanielk1977 
728106bb236Sdanielk1977 /*
729106bb236Sdanielk1977 ** Usage:  sqlite3_reset  STMT
730106bb236Sdanielk1977 **
731106bb236Sdanielk1977 ** Finalize a statement handle.
732106bb236Sdanielk1977 */
733106bb236Sdanielk1977 static int test_reset(
734106bb236Sdanielk1977   void * clientData,
735106bb236Sdanielk1977   Tcl_Interp *interp,
736106bb236Sdanielk1977   int objc,
737106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
738106bb236Sdanielk1977 ){
739106bb236Sdanielk1977   sqlite3_stmt *pStmt;
740106bb236Sdanielk1977   int rc;
741106bb236Sdanielk1977 
742106bb236Sdanielk1977   if( objc!=2 ){
743106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
744106bb236Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
745106bb236Sdanielk1977     return TCL_ERROR;
746106bb236Sdanielk1977   }
747106bb236Sdanielk1977 
748106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
749106bb236Sdanielk1977 
750fc57d7bfSdanielk1977   rc = sqlite3_reset(pStmt);
751106bb236Sdanielk1977   if( rc ){
752b86ccfb2Sdrh     return TCL_ERROR;
753b86ccfb2Sdrh   }
754b86ccfb2Sdrh   return TCL_OK;
755b86ccfb2Sdrh }
756b86ccfb2Sdrh 
7575a38705eSdrh /*
7586f8a503dSdanielk1977 ** Usage:  sqlite3_reset   VM
75950457896Sdrh **
76050457896Sdrh ** Reset a virtual machine and prepare it to be run again.
76150457896Sdrh */
76250457896Sdrh 
76350457896Sdrh /*
7647c972decSdrh ** This is the "static_bind_value" that variables are bound to when
7656f8a503dSdanielk1977 ** the FLAG option of sqlite3_bind is "static"
76650457896Sdrh */
7677c972decSdrh static char *sqlite_static_bind_value = 0;
7687c972decSdrh 
7697c972decSdrh /*
7706f8a503dSdanielk1977 ** Usage:  sqlite3_bind  VM  IDX  VALUE  FLAGS
7717c972decSdrh **
7727c972decSdrh ** Sets the value of the IDX-th occurance of "?" in the original SQL
7737c972decSdrh ** string.  VALUE is the new value.  If FLAGS=="null" then VALUE is
7747c972decSdrh ** ignored and the value is set to NULL.  If FLAGS=="static" then
7757c972decSdrh ** the value is set to the value of a static variable named
7767c972decSdrh ** "sqlite_static_bind_value".  If FLAGS=="normal" then a copy
7777c972decSdrh ** of the VALUE is made.
7787c972decSdrh */
7797c972decSdrh static int test_bind(
78050457896Sdrh   void *NotUsed,
78150457896Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
78250457896Sdrh   int argc,              /* Number of arguments */
78350457896Sdrh   char **argv            /* Text of each argument */
78450457896Sdrh ){
785fc57d7bfSdanielk1977   sqlite3_stmt *pStmt;
78650457896Sdrh   int rc;
7877c972decSdrh   int idx;
7887c972decSdrh   if( argc!=5 ){
78950457896Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
7907c972decSdrh        " VM IDX VALUE (null|static|normal)\"", 0);
79150457896Sdrh     return TCL_ERROR;
79250457896Sdrh   }
793fc57d7bfSdanielk1977   if( getStmtPointer(interp, argv[1], &pStmt) ) return TCL_ERROR;
7947c972decSdrh   if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR;
7957c972decSdrh   if( strcmp(argv[4],"null")==0 ){
796fc57d7bfSdanielk1977     rc = sqlite3_bind_null(pStmt, idx);
7977c972decSdrh   }else if( strcmp(argv[4],"static")==0 ){
798fc57d7bfSdanielk1977     rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0);
7997c972decSdrh   }else if( strcmp(argv[4],"normal")==0 ){
800fc57d7bfSdanielk1977     rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, 1);
8017c972decSdrh   }else{
8027c972decSdrh     Tcl_AppendResult(interp, "4th argument should be "
8037c972decSdrh         "\"null\" or \"static\" or \"normal\"", 0);
8047c972decSdrh     return TCL_ERROR;
8057c972decSdrh   }
80650457896Sdrh   if( rc ){
80750457896Sdrh     char zBuf[50];
80850457896Sdrh     sprintf(zBuf, "(%d) ", rc);
8096f8a503dSdanielk1977     Tcl_AppendResult(interp, zBuf, sqlite3_error_string(rc), 0);
81050457896Sdrh     return TCL_ERROR;
81150457896Sdrh   }
81250457896Sdrh   return TCL_OK;
81350457896Sdrh }
81450457896Sdrh 
81550457896Sdrh /*
81699ee3600Sdrh ** Usage:    breakpoint
81799ee3600Sdrh **
81899ee3600Sdrh ** This routine exists for one purpose - to provide a place to put a
81999ee3600Sdrh ** breakpoint with GDB that can be triggered using TCL code.  The use
82099ee3600Sdrh ** for this is when a particular test fails on (say) the 1485th iteration.
82199ee3600Sdrh ** In the TCL test script, we can add code like this:
82299ee3600Sdrh **
82399ee3600Sdrh **     if {$i==1485} breakpoint
82499ee3600Sdrh **
82599ee3600Sdrh ** Then run testfixture in the debugger and wait for the breakpoint to
82699ee3600Sdrh ** fire.  Then additional breakpoints can be set to trace down the bug.
82799ee3600Sdrh */
82899ee3600Sdrh static int test_breakpoint(
82999ee3600Sdrh   void *NotUsed,
83099ee3600Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
83199ee3600Sdrh   int argc,              /* Number of arguments */
83299ee3600Sdrh   char **argv            /* Text of each argument */
83399ee3600Sdrh ){
83499ee3600Sdrh   return TCL_OK;         /* Do nothing */
83599ee3600Sdrh }
83699ee3600Sdrh 
83751e3d8e2Sdanielk1977 static int test_bind_int32(
83851e3d8e2Sdanielk1977   void * clientData,
83951e3d8e2Sdanielk1977   Tcl_Interp *interp,
84051e3d8e2Sdanielk1977   int objc,
84151e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
84251e3d8e2Sdanielk1977 ){
84351e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
84451e3d8e2Sdanielk1977   int idx;
84551e3d8e2Sdanielk1977   int value;
84651e3d8e2Sdanielk1977   int rc;
84751e3d8e2Sdanielk1977 
84851e3d8e2Sdanielk1977   if( objc!=4 ){
84951e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
85051e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
85151e3d8e2Sdanielk1977     return TCL_ERROR;
85251e3d8e2Sdanielk1977   }
85351e3d8e2Sdanielk1977 
85451e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
85551e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
85651e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &value) ) return TCL_ERROR;
85751e3d8e2Sdanielk1977 
85851e3d8e2Sdanielk1977   rc = sqlite3_bind_int32(pStmt, idx, value);
85951e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
86051e3d8e2Sdanielk1977     return TCL_ERROR;
86151e3d8e2Sdanielk1977   }
86251e3d8e2Sdanielk1977 
86351e3d8e2Sdanielk1977   return TCL_OK;
86451e3d8e2Sdanielk1977 }
86551e3d8e2Sdanielk1977 
86651e3d8e2Sdanielk1977 static int test_bind_int64(
86751e3d8e2Sdanielk1977   void * clientData,
86851e3d8e2Sdanielk1977   Tcl_Interp *interp,
86951e3d8e2Sdanielk1977   int objc,
87051e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
87151e3d8e2Sdanielk1977 ){
87251e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
87351e3d8e2Sdanielk1977   int idx;
87451e3d8e2Sdanielk1977   i64 value;
87551e3d8e2Sdanielk1977   int rc;
87651e3d8e2Sdanielk1977 
87751e3d8e2Sdanielk1977   if( objc!=4 ){
87851e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
87951e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
88051e3d8e2Sdanielk1977     return TCL_ERROR;
88151e3d8e2Sdanielk1977   }
88251e3d8e2Sdanielk1977 
88351e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
88451e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
88551e3d8e2Sdanielk1977   if( Tcl_GetWideIntFromObj(interp, objv[3], &value) ) return TCL_ERROR;
88651e3d8e2Sdanielk1977 
88751e3d8e2Sdanielk1977   rc = sqlite3_bind_int64(pStmt, idx, value);
88851e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
88951e3d8e2Sdanielk1977     return TCL_ERROR;
89051e3d8e2Sdanielk1977   }
89151e3d8e2Sdanielk1977 
89251e3d8e2Sdanielk1977   return TCL_OK;
89351e3d8e2Sdanielk1977 }
89451e3d8e2Sdanielk1977 
89551e3d8e2Sdanielk1977 static int test_bind_double(
89651e3d8e2Sdanielk1977   void * clientData,
89751e3d8e2Sdanielk1977   Tcl_Interp *interp,
89851e3d8e2Sdanielk1977   int objc,
89951e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
90051e3d8e2Sdanielk1977 ){
90151e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
90251e3d8e2Sdanielk1977   int idx;
90351e3d8e2Sdanielk1977   double value;
90451e3d8e2Sdanielk1977   int rc;
90551e3d8e2Sdanielk1977 
90651e3d8e2Sdanielk1977   if( objc!=4 ){
90751e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
90851e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
90951e3d8e2Sdanielk1977     return TCL_ERROR;
91051e3d8e2Sdanielk1977   }
91151e3d8e2Sdanielk1977 
91251e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
91351e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
91451e3d8e2Sdanielk1977   if( Tcl_GetDoubleFromObj(interp, objv[3], &value) ) return TCL_ERROR;
91551e3d8e2Sdanielk1977 
91651e3d8e2Sdanielk1977   rc = sqlite3_bind_double(pStmt, idx, value);
91751e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
91851e3d8e2Sdanielk1977     return TCL_ERROR;
91951e3d8e2Sdanielk1977   }
92051e3d8e2Sdanielk1977 
92151e3d8e2Sdanielk1977   return TCL_OK;
92251e3d8e2Sdanielk1977 }
92351e3d8e2Sdanielk1977 
92451e3d8e2Sdanielk1977 static int test_bind_null(
92551e3d8e2Sdanielk1977   void * clientData,
92651e3d8e2Sdanielk1977   Tcl_Interp *interp,
92751e3d8e2Sdanielk1977   int objc,
92851e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
92951e3d8e2Sdanielk1977 ){
93051e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
93151e3d8e2Sdanielk1977   int idx;
93251e3d8e2Sdanielk1977   int rc;
93351e3d8e2Sdanielk1977 
93451e3d8e2Sdanielk1977   if( objc!=3 ){
93551e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
93651e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.>", 0);
93751e3d8e2Sdanielk1977     return TCL_ERROR;
93851e3d8e2Sdanielk1977   }
93951e3d8e2Sdanielk1977 
94051e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
94151e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
94251e3d8e2Sdanielk1977 
94351e3d8e2Sdanielk1977   rc = sqlite3_bind_null(pStmt, idx);
94451e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
94551e3d8e2Sdanielk1977     return TCL_ERROR;
94651e3d8e2Sdanielk1977   }
94751e3d8e2Sdanielk1977 
94851e3d8e2Sdanielk1977   return TCL_OK;
94951e3d8e2Sdanielk1977 }
95051e3d8e2Sdanielk1977 
95151e3d8e2Sdanielk1977 static int test_bind_text(
95251e3d8e2Sdanielk1977   void * clientData,
95351e3d8e2Sdanielk1977   Tcl_Interp *interp,
95451e3d8e2Sdanielk1977   int objc,
95551e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
95651e3d8e2Sdanielk1977 ){
95751e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
95851e3d8e2Sdanielk1977   int idx;
95951e3d8e2Sdanielk1977   int bytes;
96051e3d8e2Sdanielk1977   char *value;
96151e3d8e2Sdanielk1977   int rc;
96251e3d8e2Sdanielk1977 
96351e3d8e2Sdanielk1977   if( objc!=5 ){
96451e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
96551e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
96651e3d8e2Sdanielk1977         " <bytes>", 0);
96751e3d8e2Sdanielk1977     return TCL_ERROR;
96851e3d8e2Sdanielk1977   }
96951e3d8e2Sdanielk1977 
97051e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
97151e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
97251e3d8e2Sdanielk1977   value = Tcl_GetString(objv[3]);
97351e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
97451e3d8e2Sdanielk1977 
97551e3d8e2Sdanielk1977   rc = sqlite3_bind_text(pStmt, idx, value, bytes, 1);
97651e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
97751e3d8e2Sdanielk1977     return TCL_ERROR;
97851e3d8e2Sdanielk1977   }
97951e3d8e2Sdanielk1977 
98051e3d8e2Sdanielk1977   return TCL_OK;
98151e3d8e2Sdanielk1977 }
98251e3d8e2Sdanielk1977 
98351e3d8e2Sdanielk1977 static int test_bind_text16(
98451e3d8e2Sdanielk1977   void * clientData,
98551e3d8e2Sdanielk1977   Tcl_Interp *interp,
98651e3d8e2Sdanielk1977   int objc,
98751e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
98851e3d8e2Sdanielk1977 ){
98951e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
99051e3d8e2Sdanielk1977   int idx;
99151e3d8e2Sdanielk1977   int bytes;
99251e3d8e2Sdanielk1977   char *value;
99351e3d8e2Sdanielk1977   int rc;
99451e3d8e2Sdanielk1977 
99551e3d8e2Sdanielk1977   if( objc!=5 ){
99651e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
99751e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
99851e3d8e2Sdanielk1977         " <bytes>", 0);
99951e3d8e2Sdanielk1977     return TCL_ERROR;
100051e3d8e2Sdanielk1977   }
100151e3d8e2Sdanielk1977 
100251e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
100351e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
100451e3d8e2Sdanielk1977   value = Tcl_GetByteArrayFromObj(objv[3], 0);
100551e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
100651e3d8e2Sdanielk1977 
100751e3d8e2Sdanielk1977   rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, 1);
100851e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
100951e3d8e2Sdanielk1977     return TCL_ERROR;
101051e3d8e2Sdanielk1977   }
101151e3d8e2Sdanielk1977 
101251e3d8e2Sdanielk1977   return TCL_OK;
101351e3d8e2Sdanielk1977 }
101451e3d8e2Sdanielk1977 
101551e3d8e2Sdanielk1977 static int test_bind_blob(
101651e3d8e2Sdanielk1977   void * clientData,
101751e3d8e2Sdanielk1977   Tcl_Interp *interp,
101851e3d8e2Sdanielk1977   int objc,
101951e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
102051e3d8e2Sdanielk1977 ){
102151e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
102251e3d8e2Sdanielk1977   int idx;
102351e3d8e2Sdanielk1977   int bytes;
102451e3d8e2Sdanielk1977   char *value;
102551e3d8e2Sdanielk1977   int rc;
102651e3d8e2Sdanielk1977 
102751e3d8e2Sdanielk1977   if( objc!=5 ){
102851e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
102951e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
103051e3d8e2Sdanielk1977         " <bytes>", 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   value = Tcl_GetString(objv[3]);
103751e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &bytes) ) return TCL_ERROR;
103851e3d8e2Sdanielk1977 
103951e3d8e2Sdanielk1977   rc = sqlite3_bind_blob(pStmt, idx, value, bytes, 1);
104051e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
104151e3d8e2Sdanielk1977     return TCL_ERROR;
104251e3d8e2Sdanielk1977   }
104351e3d8e2Sdanielk1977 
104451e3d8e2Sdanielk1977   return TCL_OK;
104551e3d8e2Sdanielk1977 }
104651e3d8e2Sdanielk1977 
104799ee3600Sdrh /*
10486622cce3Sdanielk1977 ** Usage: sqlite3_errcode DB
10496622cce3Sdanielk1977 **
10506622cce3Sdanielk1977 ** Return the string representation of the most recent sqlite3_* API
10516622cce3Sdanielk1977 ** error code. e.g. "SQLITE_ERROR".
10526622cce3Sdanielk1977 */
10536622cce3Sdanielk1977 static int test_errcode(
10546622cce3Sdanielk1977   void * clientData,
10556622cce3Sdanielk1977   Tcl_Interp *interp,
10566622cce3Sdanielk1977   int objc,
10576622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
10586622cce3Sdanielk1977 ){
10596622cce3Sdanielk1977   sqlite3 *db;
10606622cce3Sdanielk1977 
10616622cce3Sdanielk1977   if( objc!=2 ){
10626622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
10636622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
10646622cce3Sdanielk1977     return TCL_ERROR;
10656622cce3Sdanielk1977   }
10666622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
10676622cce3Sdanielk1977   Tcl_SetResult(interp, (char *)errorName(sqlite3_errcode(db)), 0);
10686622cce3Sdanielk1977   return TCL_OK;
10696622cce3Sdanielk1977 }
10706622cce3Sdanielk1977 
10716622cce3Sdanielk1977 /*
10726622cce3Sdanielk1977 ** Usage:   test_errmsg DB
10736622cce3Sdanielk1977 **
10746622cce3Sdanielk1977 ** Returns the UTF-8 representation of the error message string for the
10756622cce3Sdanielk1977 ** most recent sqlite3_* API call.
10766622cce3Sdanielk1977 */
10776622cce3Sdanielk1977 static int test_errmsg(
10786622cce3Sdanielk1977   void * clientData,
10796622cce3Sdanielk1977   Tcl_Interp *interp,
10806622cce3Sdanielk1977   int objc,
10816622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
10826622cce3Sdanielk1977 ){
10836622cce3Sdanielk1977   sqlite *db;
10846622cce3Sdanielk1977   const char *zErr;
10856622cce3Sdanielk1977 
10866622cce3Sdanielk1977   if( objc!=2 ){
10876622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
10886622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
10896622cce3Sdanielk1977     return TCL_ERROR;
10906622cce3Sdanielk1977   }
10916622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
10926622cce3Sdanielk1977 
10936622cce3Sdanielk1977   zErr = sqlite3_errmsg(db);
10946622cce3Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
10956622cce3Sdanielk1977   return TCL_OK;
10966622cce3Sdanielk1977 }
10976622cce3Sdanielk1977 
10986622cce3Sdanielk1977 /*
10996622cce3Sdanielk1977 ** Usage:   test_errmsg16 DB
11006622cce3Sdanielk1977 **
11016622cce3Sdanielk1977 ** Returns the UTF-16 representation of the error message string for the
11026622cce3Sdanielk1977 ** most recent sqlite3_* API call. This is a byte array object at the TCL
11036622cce3Sdanielk1977 ** level, and it includes the 0x00 0x00 terminator bytes at the end of the
11046622cce3Sdanielk1977 ** UTF-16 string.
11056622cce3Sdanielk1977 */
11066622cce3Sdanielk1977 static int test_errmsg16(
11076622cce3Sdanielk1977   void * clientData,
11086622cce3Sdanielk1977   Tcl_Interp *interp,
11096622cce3Sdanielk1977   int objc,
11106622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
11116622cce3Sdanielk1977 ){
11126622cce3Sdanielk1977   sqlite *db;
11136622cce3Sdanielk1977   const void *zErr;
11146622cce3Sdanielk1977   int bytes;
11156622cce3Sdanielk1977 
11166622cce3Sdanielk1977   if( objc!=2 ){
11176622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
11186622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
11196622cce3Sdanielk1977     return TCL_ERROR;
11206622cce3Sdanielk1977   }
11216622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
11226622cce3Sdanielk1977 
11236622cce3Sdanielk1977   zErr = sqlite3_errmsg16(db);
11246622cce3Sdanielk1977   bytes = sqlite3utf16ByteLen(zErr, -1);
11256622cce3Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes));
11266622cce3Sdanielk1977   return TCL_OK;
11276622cce3Sdanielk1977 }
11286622cce3Sdanielk1977 
11296622cce3Sdanielk1977 /*
11306622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar
11316622cce3Sdanielk1977 **
11326622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
11336622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global
11346622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A
11356622cce3Sdanielk1977 ** STMT handle is returned.
11366622cce3Sdanielk1977 */
11376622cce3Sdanielk1977 static int test_prepare(
11386622cce3Sdanielk1977   void * clientData,
11396622cce3Sdanielk1977   Tcl_Interp *interp,
11406622cce3Sdanielk1977   int objc,
11416622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
11426622cce3Sdanielk1977 ){
11436622cce3Sdanielk1977   sqlite3 *db;
11446622cce3Sdanielk1977   const char *zSql;
11456622cce3Sdanielk1977   int bytes;
11466622cce3Sdanielk1977   const char *zTail = 0;
11476622cce3Sdanielk1977   sqlite3_stmt *pStmt = 0;
11486622cce3Sdanielk1977   char zBuf[50];
11494ad1713cSdanielk1977   int rc;
11506622cce3Sdanielk1977 
11516622cce3Sdanielk1977   if( objc!=5 ){
11526622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
11536622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
11546622cce3Sdanielk1977     return TCL_ERROR;
11556622cce3Sdanielk1977   }
11566622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
11576622cce3Sdanielk1977   zSql = Tcl_GetString(objv[2]);
11586622cce3Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
11596622cce3Sdanielk1977 
11604ad1713cSdanielk1977   rc = sqlite3_prepare(db, zSql, bytes, &pStmt, &zTail);
11616622cce3Sdanielk1977   if( zTail ){
11626622cce3Sdanielk1977     if( bytes>=0 ){
11636622cce3Sdanielk1977       bytes = bytes - (zTail-zSql);
11646622cce3Sdanielk1977     }
11656622cce3Sdanielk1977     Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
11666622cce3Sdanielk1977   }
11674ad1713cSdanielk1977   if( rc!=SQLITE_OK ){
11684ad1713cSdanielk1977     assert( pStmt==0 );
11694ad1713cSdanielk1977     sprintf(zBuf, "(%d) ", rc);
11704ad1713cSdanielk1977     Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
11714ad1713cSdanielk1977     return TCL_ERROR;
11724ad1713cSdanielk1977   }
11736622cce3Sdanielk1977 
11744ad1713cSdanielk1977   if( pStmt ){
11756622cce3Sdanielk1977     if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
11766622cce3Sdanielk1977     Tcl_AppendResult(interp, zBuf, 0);
11774ad1713cSdanielk1977   }
11786622cce3Sdanielk1977   return TCL_OK;
11796622cce3Sdanielk1977 }
11806622cce3Sdanielk1977 
11816622cce3Sdanielk1977 /*
11826622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar
11836622cce3Sdanielk1977 **
11846622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
11856622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global
11866622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A
11876622cce3Sdanielk1977 ** STMT handle is returned.
11886622cce3Sdanielk1977 */
11896622cce3Sdanielk1977 static int test_prepare16(
11906622cce3Sdanielk1977   void * clientData,
11916622cce3Sdanielk1977   Tcl_Interp *interp,
11926622cce3Sdanielk1977   int objc,
11936622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
11946622cce3Sdanielk1977 ){
11956622cce3Sdanielk1977   sqlite3 *db;
11966622cce3Sdanielk1977   const void *zSql;
11976622cce3Sdanielk1977   const void *zTail = 0;
11986622cce3Sdanielk1977   Tcl_Obj *pTail = 0;
11996622cce3Sdanielk1977   sqlite3_stmt *pStmt = 0;
12006622cce3Sdanielk1977   char zBuf[50];
12016622cce3Sdanielk1977   int bytes;                /* The integer specified as arg 3 */
12026622cce3Sdanielk1977   int objlen;               /* The byte-array length of arg 2 */
12036622cce3Sdanielk1977 
12046622cce3Sdanielk1977   if( objc!=5 ){
12056622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
12066622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
12076622cce3Sdanielk1977     return TCL_ERROR;
12086622cce3Sdanielk1977   }
12096622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
12106622cce3Sdanielk1977   zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen);
12116622cce3Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
12126622cce3Sdanielk1977 
12136622cce3Sdanielk1977   if( SQLITE_OK!=sqlite3_prepare16(db, zSql, bytes, &pStmt, &zTail) ){
12146622cce3Sdanielk1977     return TCL_ERROR;
12156622cce3Sdanielk1977   }
12166622cce3Sdanielk1977 
12176622cce3Sdanielk1977   if( zTail ){
12186622cce3Sdanielk1977     objlen = objlen - ((u8 *)zTail-(u8 *)zSql);
12196622cce3Sdanielk1977   }else{
12206622cce3Sdanielk1977     objlen = 0;
12216622cce3Sdanielk1977   }
12226622cce3Sdanielk1977   pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen);
12236622cce3Sdanielk1977   Tcl_IncrRefCount(pTail);
12246622cce3Sdanielk1977   Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0);
12254ad1713cSdanielk1977   Tcl_DecrRefCount(pTail);
12266622cce3Sdanielk1977 
12274ad1713cSdanielk1977   if( pStmt ){
12286622cce3Sdanielk1977     if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
12294ad1713cSdanielk1977   }
12306622cce3Sdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
12316622cce3Sdanielk1977   return TCL_OK;
12326622cce3Sdanielk1977 }
12336622cce3Sdanielk1977 
12344ad1713cSdanielk1977 /*
12354ad1713cSdanielk1977 ** Usage: sqlite3_open filename ?options-list?
12364ad1713cSdanielk1977 */
12374ad1713cSdanielk1977 static int test_open(
12384ad1713cSdanielk1977   void * clientData,
12394ad1713cSdanielk1977   Tcl_Interp *interp,
12404ad1713cSdanielk1977   int objc,
12414ad1713cSdanielk1977   Tcl_Obj *CONST objv[]
12424ad1713cSdanielk1977 ){
12434ad1713cSdanielk1977   const char *zFilename;
12444ad1713cSdanielk1977   sqlite3 *db;
12454ad1713cSdanielk1977   int rc;
12464ad1713cSdanielk1977   char zBuf[100];
12474ad1713cSdanielk1977 
12484ad1713cSdanielk1977   if( objc!=3 && objc!=2 ){
12494ad1713cSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
12504ad1713cSdanielk1977        Tcl_GetString(objv[0]), " filename options-list", 0);
12514ad1713cSdanielk1977     return TCL_ERROR;
12524ad1713cSdanielk1977   }
12534ad1713cSdanielk1977 
12544ad1713cSdanielk1977   zFilename = Tcl_GetString(objv[1]);
125580290863Sdanielk1977   rc = sqlite3_open(zFilename, &db, 0);
12564ad1713cSdanielk1977 
12574ad1713cSdanielk1977   if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
12584ad1713cSdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
12594ad1713cSdanielk1977   return TCL_OK;
12604ad1713cSdanielk1977 }
12614ad1713cSdanielk1977 
12624ad1713cSdanielk1977 /*
12634ad1713cSdanielk1977 ** Usage: sqlite3_open16 filename options
12644ad1713cSdanielk1977 */
12654ad1713cSdanielk1977 static int test_open16(
12664ad1713cSdanielk1977   void * clientData,
12674ad1713cSdanielk1977   Tcl_Interp *interp,
12684ad1713cSdanielk1977   int objc,
12694ad1713cSdanielk1977   Tcl_Obj *CONST objv[]
12704ad1713cSdanielk1977 ){
12714ad1713cSdanielk1977   const void *zFilename;
12724ad1713cSdanielk1977   sqlite3 *db;
12734ad1713cSdanielk1977   int rc;
12744ad1713cSdanielk1977   char zBuf[100];
12754ad1713cSdanielk1977 
12764ad1713cSdanielk1977   if( objc!=3 ){
12774ad1713cSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
12784ad1713cSdanielk1977        Tcl_GetString(objv[0]), " filename options-list", 0);
12794ad1713cSdanielk1977     return TCL_ERROR;
12804ad1713cSdanielk1977   }
12814ad1713cSdanielk1977 
12824ad1713cSdanielk1977   zFilename = Tcl_GetByteArrayFromObj(objv[1], 0);
12834ad1713cSdanielk1977   rc = sqlite3_open16(zFilename, &db, 0);
12844ad1713cSdanielk1977 
12854ad1713cSdanielk1977   if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
12864ad1713cSdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
12874ad1713cSdanielk1977   return TCL_OK;
12884ad1713cSdanielk1977 }
1289d3d39e93Sdrh 
1290d3d39e93Sdrh /*
1291106bb236Sdanielk1977 ** Usage: sqlite3_step STMT
1292106bb236Sdanielk1977 **
1293106bb236Sdanielk1977 ** Advance the statement to the next row.
1294106bb236Sdanielk1977 */
129517240fd9Sdanielk1977 static int test_step(
1296106bb236Sdanielk1977   void * clientData,
1297106bb236Sdanielk1977   Tcl_Interp *interp,
1298106bb236Sdanielk1977   int objc,
1299106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
1300106bb236Sdanielk1977 ){
1301106bb236Sdanielk1977   sqlite3_stmt *pStmt;
1302106bb236Sdanielk1977   int rc;
1303106bb236Sdanielk1977 
1304e1cd9874Sdanielk1977   if( objc!=2 ){
1305106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1306106bb236Sdanielk1977        Tcl_GetString(objv[0]), " STMT", 0);
1307106bb236Sdanielk1977     return TCL_ERROR;
1308106bb236Sdanielk1977   }
1309106bb236Sdanielk1977 
1310106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
131117240fd9Sdanielk1977   rc = sqlite3_step(pStmt);
1312106bb236Sdanielk1977 
1313e1cd9874Sdanielk1977   if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR;
13146590493dSdanielk1977   Tcl_SetResult(interp, (char *)errorName(rc), 0);
1315e1cd9874Sdanielk1977   return TCL_OK;
1316e1cd9874Sdanielk1977 }
1317e1cd9874Sdanielk1977 
1318e1cd9874Sdanielk1977 /*
1319e1cd9874Sdanielk1977 ** Usage: sqlite3_column_data STMT column
1320e1cd9874Sdanielk1977 **
1321e1cd9874Sdanielk1977 ** Advance the statement to the next row.
1322e1cd9874Sdanielk1977 */
1323e1cd9874Sdanielk1977 static int test_column_data(
1324e1cd9874Sdanielk1977   void * clientData,
1325e1cd9874Sdanielk1977   Tcl_Interp *interp,
1326e1cd9874Sdanielk1977   int objc,
1327e1cd9874Sdanielk1977   Tcl_Obj *CONST objv[]
1328e1cd9874Sdanielk1977 ){
1329e1cd9874Sdanielk1977   sqlite3_stmt *pStmt;
1330e1cd9874Sdanielk1977   int col;
1331e1cd9874Sdanielk1977   Tcl_Obj *pRet;
1332e1cd9874Sdanielk1977 
1333e1cd9874Sdanielk1977   if( objc!=3 ){
1334e1cd9874Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1335e1cd9874Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
1336e1cd9874Sdanielk1977     return TCL_ERROR;
1337e1cd9874Sdanielk1977   }
1338e1cd9874Sdanielk1977 
1339e1cd9874Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
1340e1cd9874Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
1341e1cd9874Sdanielk1977 
1342e1cd9874Sdanielk1977   if( SQLITE3_BLOB==sqlite3_column_type(pStmt, col) ){
1343e1cd9874Sdanielk1977     int len = sqlite3_column_bytes(pStmt, col);
1344e1cd9874Sdanielk1977     pRet = Tcl_NewByteArrayObj(sqlite3_column_data(pStmt, col), len);
1345e1cd9874Sdanielk1977   }else{
1346e1cd9874Sdanielk1977     pRet = Tcl_NewStringObj(sqlite3_column_data(pStmt, col), -1);
1347e1cd9874Sdanielk1977   }
1348e1cd9874Sdanielk1977   Tcl_SetObjResult(interp, pRet);
1349e1cd9874Sdanielk1977 
1350e1cd9874Sdanielk1977   return TCL_OK;
1351e1cd9874Sdanielk1977 }
1352e1cd9874Sdanielk1977 
1353e1cd9874Sdanielk1977 /*
1354e1cd9874Sdanielk1977 ** Usage: sqlite3_column_data16 STMT column
1355e1cd9874Sdanielk1977 **
1356e1cd9874Sdanielk1977 ** Advance the statement to the next row.
1357e1cd9874Sdanielk1977 */
1358e1cd9874Sdanielk1977 static int test_column_data16(
1359e1cd9874Sdanielk1977   void * clientData,
1360e1cd9874Sdanielk1977   Tcl_Interp *interp,
1361e1cd9874Sdanielk1977   int objc,
1362e1cd9874Sdanielk1977   Tcl_Obj *CONST objv[]
1363e1cd9874Sdanielk1977 ){
1364e1cd9874Sdanielk1977   sqlite3_stmt *pStmt;
1365e1cd9874Sdanielk1977   int col;
1366e1cd9874Sdanielk1977   Tcl_Obj *pRet;
1367e1cd9874Sdanielk1977   int len;
1368e1cd9874Sdanielk1977 
1369e1cd9874Sdanielk1977   if( objc!=3 ){
1370e1cd9874Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1371e1cd9874Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
1372e1cd9874Sdanielk1977     return TCL_ERROR;
1373e1cd9874Sdanielk1977   }
1374e1cd9874Sdanielk1977 
1375e1cd9874Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
1376e1cd9874Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
1377e1cd9874Sdanielk1977 
1378e1cd9874Sdanielk1977   len = sqlite3_column_bytes16(pStmt, col);
1379e1cd9874Sdanielk1977   pRet = Tcl_NewByteArrayObj(sqlite3_column_data16(pStmt, col), len);
1380e1cd9874Sdanielk1977   Tcl_SetObjResult(interp, pRet);
1381e1cd9874Sdanielk1977 
1382106bb236Sdanielk1977   return TCL_OK;
1383106bb236Sdanielk1977 }
1384106bb236Sdanielk1977 
1385106bb236Sdanielk1977 /*
13863cf86063Sdanielk1977 ** Usage: sqlite3_column_name STMT column
13873cf86063Sdanielk1977 **
13883cf86063Sdanielk1977 ** Advance the statement to the next row.
13893cf86063Sdanielk1977 */
13903cf86063Sdanielk1977 static int test_column_name(
13913cf86063Sdanielk1977   void * clientData,
13923cf86063Sdanielk1977   Tcl_Interp *interp,
13933cf86063Sdanielk1977   int objc,
13943cf86063Sdanielk1977   Tcl_Obj *CONST objv[]
13953cf86063Sdanielk1977 ){
13963cf86063Sdanielk1977   sqlite3_stmt *pStmt;
13973cf86063Sdanielk1977   int col;
13983cf86063Sdanielk1977 
13993cf86063Sdanielk1977   if( objc!=3 ){
14003cf86063Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
14013cf86063Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
14023cf86063Sdanielk1977     return TCL_ERROR;
14033cf86063Sdanielk1977   }
14043cf86063Sdanielk1977 
14053cf86063Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
14063cf86063Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
14073cf86063Sdanielk1977 
14083cf86063Sdanielk1977   Tcl_SetResult(interp, (char *)sqlite3_column_name(pStmt, col), 0);
14093cf86063Sdanielk1977 
14103cf86063Sdanielk1977   return TCL_OK;
14113cf86063Sdanielk1977 }
14123cf86063Sdanielk1977 
14133cf86063Sdanielk1977 /*
14143cf86063Sdanielk1977 ** Usage: sqlite3_column_name16 STMT column
14153cf86063Sdanielk1977 **
14163cf86063Sdanielk1977 ** Advance the statement to the next row.
14173cf86063Sdanielk1977 */
14183cf86063Sdanielk1977 static int test_column_name16(
14193cf86063Sdanielk1977   void * clientData,
14203cf86063Sdanielk1977   Tcl_Interp *interp,
14213cf86063Sdanielk1977   int objc,
14223cf86063Sdanielk1977   Tcl_Obj *CONST objv[]
14233cf86063Sdanielk1977 ){
14243cf86063Sdanielk1977   sqlite3_stmt *pStmt;
14253cf86063Sdanielk1977   int col;
14263cf86063Sdanielk1977   Tcl_Obj *pRet;
14273cf86063Sdanielk1977   const void *zName16;
14283cf86063Sdanielk1977 
14293cf86063Sdanielk1977   if( objc!=3 ){
14303cf86063Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
14313cf86063Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
14323cf86063Sdanielk1977     return TCL_ERROR;
14333cf86063Sdanielk1977   }
14343cf86063Sdanielk1977 
14353cf86063Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
14363cf86063Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
14373cf86063Sdanielk1977 
14383cf86063Sdanielk1977   zName16 = sqlite3_column_name16(pStmt, col);
14393cf86063Sdanielk1977   pRet = Tcl_NewByteArrayObj(zName16, sqlite3utf16ByteLen(zName16, -1)+2);
14403cf86063Sdanielk1977   Tcl_SetObjResult(interp, pRet);
14413cf86063Sdanielk1977 
14423cf86063Sdanielk1977   return TCL_OK;
14433cf86063Sdanielk1977 }
14443cf86063Sdanielk1977 
14453cf86063Sdanielk1977 /*
144617240fd9Sdanielk1977 ** Usage: sqlite3_column_count STMT
144717240fd9Sdanielk1977 **
144817240fd9Sdanielk1977 ** Return the number of columns returned by the sql statement STMT.
144917240fd9Sdanielk1977 */
145017240fd9Sdanielk1977 static int test_column_count(
145117240fd9Sdanielk1977   void * clientData,
145217240fd9Sdanielk1977   Tcl_Interp *interp,
145317240fd9Sdanielk1977   int objc,
145417240fd9Sdanielk1977   Tcl_Obj *CONST objv[]
145517240fd9Sdanielk1977 ){
145617240fd9Sdanielk1977   sqlite3_stmt *pStmt;
145717240fd9Sdanielk1977 
145817240fd9Sdanielk1977   if( objc!=2 ){
145917240fd9Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
146017240fd9Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
146117240fd9Sdanielk1977     return TCL_ERROR;
146217240fd9Sdanielk1977   }
146317240fd9Sdanielk1977 
146417240fd9Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
146517240fd9Sdanielk1977 
146617240fd9Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_column_count(pStmt)));
146717240fd9Sdanielk1977   return TCL_OK;
146817240fd9Sdanielk1977 }
146917240fd9Sdanielk1977 
147017240fd9Sdanielk1977 /*
14713cf86063Sdanielk1977 ** Usage: sqlite3_column_type STMT column
14723cf86063Sdanielk1977 **
14733cf86063Sdanielk1977 ** Return the type of the data in column 'column' of the current row.
14743cf86063Sdanielk1977 */
14753cf86063Sdanielk1977 static int test_column_type(
14763cf86063Sdanielk1977   void * clientData,
14773cf86063Sdanielk1977   Tcl_Interp *interp,
14783cf86063Sdanielk1977   int objc,
14793cf86063Sdanielk1977   Tcl_Obj *CONST objv[]
14803cf86063Sdanielk1977 ){
14813cf86063Sdanielk1977   sqlite3_stmt *pStmt;
14823cf86063Sdanielk1977   int col;
14833cf86063Sdanielk1977   int tp;
14843cf86063Sdanielk1977 
14853cf86063Sdanielk1977   if( objc!=3 ){
14863cf86063Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
14873cf86063Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
14883cf86063Sdanielk1977     return TCL_ERROR;
14893cf86063Sdanielk1977   }
14903cf86063Sdanielk1977 
14913cf86063Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
14923cf86063Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
14933cf86063Sdanielk1977 
14943cf86063Sdanielk1977   tp = sqlite3_column_type(pStmt, col);
14953cf86063Sdanielk1977   switch( tp ){
14963cf86063Sdanielk1977     case SQLITE3_INTEGER:
14973cf86063Sdanielk1977       Tcl_SetResult(interp, "INTEGER", TCL_STATIC);
14983cf86063Sdanielk1977       break;
14993cf86063Sdanielk1977     case SQLITE3_NULL:
15003cf86063Sdanielk1977       Tcl_SetResult(interp, "NULL", TCL_STATIC);
15013cf86063Sdanielk1977       break;
15023cf86063Sdanielk1977     case SQLITE3_FLOAT:
15033cf86063Sdanielk1977       Tcl_SetResult(interp, "FLOAT", TCL_STATIC);
15043cf86063Sdanielk1977       break;
15053cf86063Sdanielk1977     case SQLITE3_TEXT:
15063cf86063Sdanielk1977       Tcl_SetResult(interp, "TEXT", TCL_STATIC);
15073cf86063Sdanielk1977       break;
15083cf86063Sdanielk1977     case SQLITE3_BLOB:
15093cf86063Sdanielk1977       Tcl_SetResult(interp, "BLOB", TCL_STATIC);
15103cf86063Sdanielk1977       break;
15113cf86063Sdanielk1977     default:
15123cf86063Sdanielk1977       assert(0);
15133cf86063Sdanielk1977   }
15143cf86063Sdanielk1977 
15153cf86063Sdanielk1977   return TCL_OK;
15163cf86063Sdanielk1977 }
15173cf86063Sdanielk1977 
15183cf86063Sdanielk1977 /*
15193cf86063Sdanielk1977 ** Usage: sqlite3_column_int STMT column
15203cf86063Sdanielk1977 **
15213cf86063Sdanielk1977 ** Return the data in column 'column' of the current row cast as an
15223cf86063Sdanielk1977 ** integer.
15233cf86063Sdanielk1977 */
15243cf86063Sdanielk1977 static int test_column_int(
15253cf86063Sdanielk1977   void * clientData,
15263cf86063Sdanielk1977   Tcl_Interp *interp,
15273cf86063Sdanielk1977   int objc,
15283cf86063Sdanielk1977   Tcl_Obj *CONST objv[]
15293cf86063Sdanielk1977 ){
15303cf86063Sdanielk1977   sqlite3_stmt *pStmt;
15313cf86063Sdanielk1977   int col;
15323cf86063Sdanielk1977 
15333cf86063Sdanielk1977   if( objc!=3 ){
15343cf86063Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
15353cf86063Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
15363cf86063Sdanielk1977     return TCL_ERROR;
15373cf86063Sdanielk1977   }
15383cf86063Sdanielk1977 
15393cf86063Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
15403cf86063Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
15413cf86063Sdanielk1977 
15423cf86063Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_column_int(pStmt, col)));
15433cf86063Sdanielk1977   return TCL_OK;
15443cf86063Sdanielk1977 }
15453cf86063Sdanielk1977 
15463cf86063Sdanielk1977 /*
154717240fd9Sdanielk1977 ** Usage: sqlite3_data_count STMT
154817240fd9Sdanielk1977 **
154917240fd9Sdanielk1977 ** Return the number of columns returned by the sql statement STMT.
155017240fd9Sdanielk1977 */
155117240fd9Sdanielk1977 static int test_data_count(
155217240fd9Sdanielk1977   void * clientData,
155317240fd9Sdanielk1977   Tcl_Interp *interp,
155417240fd9Sdanielk1977   int objc,
155517240fd9Sdanielk1977   Tcl_Obj *CONST objv[]
155617240fd9Sdanielk1977 ){
155717240fd9Sdanielk1977   sqlite3_stmt *pStmt;
155817240fd9Sdanielk1977 
155917240fd9Sdanielk1977   if( objc!=2 ){
156017240fd9Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
156117240fd9Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
156217240fd9Sdanielk1977     return TCL_ERROR;
156317240fd9Sdanielk1977   }
156417240fd9Sdanielk1977 
156517240fd9Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
156617240fd9Sdanielk1977 
156717240fd9Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_data_count(pStmt)));
156817240fd9Sdanielk1977   return TCL_OK;
156917240fd9Sdanielk1977 }
157017240fd9Sdanielk1977 
157117240fd9Sdanielk1977 /*
1572d3d39e93Sdrh ** This is a collating function named "REVERSE" which sorts text
1573d3d39e93Sdrh ** in reverse order.
1574d3d39e93Sdrh */
1575d3d39e93Sdrh static int reverseCollatingFunc(
1576d3d39e93Sdrh   void *NotUsed,
1577d3d39e93Sdrh   int nKey1, const void *pKey1,
1578d3d39e93Sdrh   int nKey2, const void *pKey2
1579d3d39e93Sdrh ){
1580d3d39e93Sdrh   int rc, n;
1581d3d39e93Sdrh   n = nKey1<nKey2 ? nKey1 : nKey2;
1582d3d39e93Sdrh   rc = memcmp(pKey1, pKey2, n);
1583d3d39e93Sdrh   if( rc==0 ){
1584d3d39e93Sdrh     rc = nKey1 - nKey2;
1585d3d39e93Sdrh   }
1586d3d39e93Sdrh   return -rc;
1587d3d39e93Sdrh }
1588d3d39e93Sdrh 
1589d3d39e93Sdrh /*
1590d3d39e93Sdrh ** Usage: add_reverse_collating_func DB
1591d3d39e93Sdrh **
1592d3d39e93Sdrh ** This routine adds a collation named "REVERSE" to database given.
1593d3d39e93Sdrh ** REVERSE is used for testing only.
1594d3d39e93Sdrh */
1595d3d39e93Sdrh static int reverse_collfunc(
1596d3d39e93Sdrh   void * clientData,
1597d3d39e93Sdrh   Tcl_Interp *interp,
1598d3d39e93Sdrh   int objc,
1599d3d39e93Sdrh   Tcl_Obj *CONST objv[]
1600d3d39e93Sdrh ){
1601d3d39e93Sdrh   sqlite3 *db;
1602d3d39e93Sdrh 
1603d3d39e93Sdrh   if( objc!=2 ){
1604d3d39e93Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB");
1605d3d39e93Sdrh     return TCL_ERROR;
1606d3d39e93Sdrh   }
1607d3d39e93Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1608d3d39e93Sdrh   sqlite3ChangeCollatingFunction(db, "REVERSE", 7, 0, reverseCollatingFunc);
1609d3d39e93Sdrh   return TCL_OK;
1610d3d39e93Sdrh }
1611d3d39e93Sdrh 
1612d3d39e93Sdrh 
16136622cce3Sdanielk1977 /*
1614d1bf3512Sdrh ** Register commands with the TCL interpreter.
1615d1bf3512Sdrh */
1616d1bf3512Sdrh int Sqlitetest1_Init(Tcl_Interp *interp){
16176f8a503dSdanielk1977   extern int sqlite3_search_count;
16186f8a503dSdanielk1977   extern int sqlite3_interrupt_count;
16196f8a503dSdanielk1977   extern int sqlite3_open_file_count;
16206f8a503dSdanielk1977   extern int sqlite3_current_time;
1621c2eef3b3Sdrh   static struct {
1622c2eef3b3Sdrh      char *zName;
1623c2eef3b3Sdrh      Tcl_CmdProc *xProc;
1624c2eef3b3Sdrh   } aCmd[] = {
16256f8a503dSdanielk1977      { "sqlite3_mprintf_int",           (Tcl_CmdProc*)sqlite3_mprintf_int    },
16266f8a503dSdanielk1977      { "sqlite3_mprintf_str",           (Tcl_CmdProc*)sqlite3_mprintf_str    },
16276f8a503dSdanielk1977      { "sqlite3_mprintf_double",        (Tcl_CmdProc*)sqlite3_mprintf_double },
16286f8a503dSdanielk1977      { "sqlite3_mprintf_scaled",        (Tcl_CmdProc*)sqlite3_mprintf_scaled },
16296f8a503dSdanielk1977      { "sqlite3_mprintf_z_test",        (Tcl_CmdProc*)test_mprintf_z        },
16306f8a503dSdanielk1977      { "sqlite3_last_insert_rowid",     (Tcl_CmdProc*)test_last_rowid       },
16316f8a503dSdanielk1977      { "sqlite3_exec_printf",           (Tcl_CmdProc*)test_exec_printf      },
16326f8a503dSdanielk1977      { "sqlite3_get_table_printf",      (Tcl_CmdProc*)test_get_table_printf },
16336f8a503dSdanielk1977      { "sqlite3_close",                 (Tcl_CmdProc*)sqlite_test_close     },
16346f8a503dSdanielk1977      { "sqlite3_create_function",       (Tcl_CmdProc*)test_create_function  },
16356f8a503dSdanielk1977      { "sqlite3_create_aggregate",      (Tcl_CmdProc*)test_create_aggregate },
1636c2eef3b3Sdrh      { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func    },
1637c2eef3b3Sdrh      { "sqlite_abort",                  (Tcl_CmdProc*)sqlite_abort          },
1638c2eef3b3Sdrh #ifdef MEMORY_DEBUG
1639c2eef3b3Sdrh      { "sqlite_malloc_fail",            (Tcl_CmdProc*)sqlite_malloc_fail    },
1640c2eef3b3Sdrh      { "sqlite_malloc_stat",            (Tcl_CmdProc*)sqlite_malloc_stat    },
1641c2eef3b3Sdrh #endif
164296fc5fe6Sdanielk1977      { "sqlite_bind",                    (Tcl_CmdProc*)test_bind             },
164399ee3600Sdrh      { "breakpoint",                     (Tcl_CmdProc*)test_breakpoint       },
1644c2eef3b3Sdrh   };
164551e3d8e2Sdanielk1977   static struct {
164651e3d8e2Sdanielk1977      char *zName;
164751e3d8e2Sdanielk1977      Tcl_ObjCmdProc *xProc;
164851e3d8e2Sdanielk1977   } aObjCmd[] = {
164951e3d8e2Sdanielk1977      { "sqlite3_bind_int32",            (Tcl_ObjCmdProc*)test_bind_int32    },
165051e3d8e2Sdanielk1977      { "sqlite3_bind_int64",            (Tcl_ObjCmdProc*)test_bind_int64    },
165151e3d8e2Sdanielk1977      { "sqlite3_bind_double",           (Tcl_ObjCmdProc*)test_bind_double   },
165251e3d8e2Sdanielk1977      { "sqlite3_bind_null",             (Tcl_ObjCmdProc*)test_bind_null     },
165351e3d8e2Sdanielk1977      { "sqlite3_bind_text",             (Tcl_ObjCmdProc*)test_bind_text     },
165451e3d8e2Sdanielk1977      { "sqlite3_bind_text16",           (Tcl_ObjCmdProc*)test_bind_text16   },
165551e3d8e2Sdanielk1977      { "sqlite3_bind_blob",             (Tcl_ObjCmdProc*)test_bind_blob     },
16566622cce3Sdanielk1977      { "sqlite3_errcode",               (Tcl_ObjCmdProc*)test_errcode       },
16576622cce3Sdanielk1977      { "sqlite3_errmsg",                (Tcl_ObjCmdProc*)test_errmsg        },
16586622cce3Sdanielk1977      { "sqlite3_errmsg16",              (Tcl_ObjCmdProc*)test_errmsg16      },
16596622cce3Sdanielk1977      { "sqlite3_prepare",               (Tcl_ObjCmdProc*)test_prepare       },
16606622cce3Sdanielk1977      { "sqlite3_prepare16",             (Tcl_ObjCmdProc*)test_prepare16     },
16614ad1713cSdanielk1977      { "sqlite3_open",                  (Tcl_ObjCmdProc*)test_open          },
16624ad1713cSdanielk1977      { "sqlite3_open16",                (Tcl_ObjCmdProc*)test_open16        },
1663106bb236Sdanielk1977      { "sqlite3_finalize",              (Tcl_ObjCmdProc*)test_finalize      },
1664106bb236Sdanielk1977      { "sqlite3_reset",                 (Tcl_ObjCmdProc*)test_reset         },
166517240fd9Sdanielk1977      { "sqlite3_step",                  (Tcl_ObjCmdProc*)test_step},
1666e1cd9874Sdanielk1977      { "sqlite3_column_data",           (Tcl_ObjCmdProc*)test_column_data   },
1667e1cd9874Sdanielk1977      { "sqlite3_column_data16",         (Tcl_ObjCmdProc*)test_column_data16 },
166817240fd9Sdanielk1977      { "sqlite3_column_count",          (Tcl_ObjCmdProc*)test_column_count  },
16693cf86063Sdanielk1977      { "sqlite3_column_name",           (Tcl_ObjCmdProc*)test_column_name   },
16703cf86063Sdanielk1977      { "sqlite3_column_name16",         (Tcl_ObjCmdProc*)test_column_name16 },
16713cf86063Sdanielk1977      { "sqlite3_column_type",           (Tcl_ObjCmdProc*)test_column_type   },
16723cf86063Sdanielk1977      { "sqlite3_column_int",            (Tcl_ObjCmdProc*)test_column_int   },
167317240fd9Sdanielk1977      { "sqlite3_data_count",            (Tcl_ObjCmdProc*)test_data_count   },
1674d3d39e93Sdrh      { "add_reverse_collating_func",    (Tcl_ObjCmdProc*)reverse_collfunc   },
167551e3d8e2Sdanielk1977   };
1676c2eef3b3Sdrh   int i;
1677c2eef3b3Sdrh 
1678c2eef3b3Sdrh   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
1679c2eef3b3Sdrh     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
1680c2eef3b3Sdrh   }
168151e3d8e2Sdanielk1977   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
168251e3d8e2Sdanielk1977     Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0);
168351e3d8e2Sdanielk1977   }
16846490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_search_count",
16856f8a503dSdanielk1977       (char*)&sqlite3_search_count, TCL_LINK_INT);
16866490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_interrupt_count",
16876f8a503dSdanielk1977       (char*)&sqlite3_interrupt_count, TCL_LINK_INT);
16886490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_open_file_count",
16896f8a503dSdanielk1977       (char*)&sqlite3_open_file_count, TCL_LINK_INT);
16906490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_current_time",
16916f8a503dSdanielk1977       (char*)&sqlite3_current_time, TCL_LINK_INT);
16927c972decSdrh   Tcl_LinkVar(interp, "sqlite_static_bind_value",
16937c972decSdrh       (char*)&sqlite_static_bind_value, TCL_LINK_STRING);
1694d1bf3512Sdrh   return TCL_OK;
1695d1bf3512Sdrh }
1696