xref: /sqlite-3.40.0/src/test1.c (revision faa57acc)
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*faa57accSdrh ** $Id: test1.c,v 1.73 2004/06/09 14:01:51 drh 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 
30c572ef7fSdanielk1977 int sqlite3_exec_printf(
31c572ef7fSdanielk1977   sqlite *db,                   /* An open database */
32c572ef7fSdanielk1977   const char *sqlFormat,        /* printf-style format string for the SQL */
33c572ef7fSdanielk1977   sqlite_callback xCallback,    /* Callback function */
34c572ef7fSdanielk1977   void *pArg,                   /* 1st argument to callback function */
35c572ef7fSdanielk1977   char **errmsg,                /* Error msg written here */
36c572ef7fSdanielk1977   ...                           /* Arguments to the format string. */
37c572ef7fSdanielk1977 );
38c572ef7fSdanielk1977 int sqlite3_exec_printf(
39c572ef7fSdanielk1977   sqlite *db,                   /* An open database */
40c572ef7fSdanielk1977   const char *sqlFormat,        /* printf-style format string for the SQL */
41c572ef7fSdanielk1977   sqlite_callback xCallback,    /* Callback function */
42c572ef7fSdanielk1977   void *pArg,                   /* 1st argument to callback function */
43c572ef7fSdanielk1977   char **errmsg,                /* Error msg written here */
44c572ef7fSdanielk1977   ...                           /* Arguments to the format string. */
45c572ef7fSdanielk1977 );
46c572ef7fSdanielk1977 int sqlite3_get_table_printf(
47c572ef7fSdanielk1977   sqlite *db,            /* An open database */
48c572ef7fSdanielk1977   const char *sqlFormat, /* printf-style format string for the SQL */
49c572ef7fSdanielk1977   char ***resultp,       /* Result written to a char *[]  that this points to */
50c572ef7fSdanielk1977   int *nrow,             /* Number of result rows written here */
51c572ef7fSdanielk1977   int *ncol,             /* Number of result columns written here */
52c572ef7fSdanielk1977   char **errmsg,         /* Error msg written here */
53c572ef7fSdanielk1977   ...                    /* Arguments to the format string */
54c572ef7fSdanielk1977 );
55c572ef7fSdanielk1977 
566622cce3Sdanielk1977 static const char * errorName(int rc){
576622cce3Sdanielk1977   const char *zName = 0;
586622cce3Sdanielk1977   switch( rc ){
596622cce3Sdanielk1977     case SQLITE_OK:         zName = "SQLITE_OK";          break;
606622cce3Sdanielk1977     case SQLITE_ERROR:      zName = "SQLITE_ERROR";       break;
616622cce3Sdanielk1977     case SQLITE_INTERNAL:   zName = "SQLITE_INTERNAL";    break;
626622cce3Sdanielk1977     case SQLITE_PERM:       zName = "SQLITE_PERM";        break;
636622cce3Sdanielk1977     case SQLITE_ABORT:      zName = "SQLITE_ABORT";       break;
646622cce3Sdanielk1977     case SQLITE_BUSY:       zName = "SQLITE_BUSY";        break;
656622cce3Sdanielk1977     case SQLITE_LOCKED:     zName = "SQLITE_LOCKED";      break;
666622cce3Sdanielk1977     case SQLITE_NOMEM:      zName = "SQLITE_NOMEM";       break;
676622cce3Sdanielk1977     case SQLITE_READONLY:   zName = "SQLITE_READONLY";    break;
686622cce3Sdanielk1977     case SQLITE_INTERRUPT:  zName = "SQLITE_INTERRUPT";   break;
696622cce3Sdanielk1977     case SQLITE_IOERR:      zName = "SQLITE_IOERR";       break;
706622cce3Sdanielk1977     case SQLITE_CORRUPT:    zName = "SQLITE_CORRUPT";     break;
716622cce3Sdanielk1977     case SQLITE_NOTFOUND:   zName = "SQLITE_NOTFOUND";    break;
726622cce3Sdanielk1977     case SQLITE_FULL:       zName = "SQLITE_FULL";        break;
736622cce3Sdanielk1977     case SQLITE_CANTOPEN:   zName = "SQLITE_CANTOPEN";    break;
746622cce3Sdanielk1977     case SQLITE_PROTOCOL:   zName = "SQLITE_PROTOCOL";    break;
756622cce3Sdanielk1977     case SQLITE_EMPTY:      zName = "SQLITE_EMPTY";       break;
766622cce3Sdanielk1977     case SQLITE_SCHEMA:     zName = "SQLITE_SCHEMA";      break;
776622cce3Sdanielk1977     case SQLITE_TOOBIG:     zName = "SQLITE_TOOBIG";      break;
786622cce3Sdanielk1977     case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT";  break;
796622cce3Sdanielk1977     case SQLITE_MISMATCH:   zName = "SQLITE_MISMATCH";    break;
806622cce3Sdanielk1977     case SQLITE_MISUSE:     zName = "SQLITE_MISUSE";      break;
816622cce3Sdanielk1977     case SQLITE_NOLFS:      zName = "SQLITE_NOLFS";       break;
826622cce3Sdanielk1977     case SQLITE_AUTH:       zName = "SQLITE_AUTH";        break;
836622cce3Sdanielk1977     case SQLITE_FORMAT:     zName = "SQLITE_FORMAT";      break;
846622cce3Sdanielk1977     case SQLITE_RANGE:      zName = "SQLITE_RANGE";       break;
856622cce3Sdanielk1977     case SQLITE_ROW:        zName = "SQLITE_ROW";         break;
866622cce3Sdanielk1977     case SQLITE_DONE:       zName = "SQLITE_DONE";        break;
876622cce3Sdanielk1977     default:                zName = "SQLITE_Unknown";     break;
886622cce3Sdanielk1977   }
896622cce3Sdanielk1977   return zName;
906622cce3Sdanielk1977 }
916622cce3Sdanielk1977 
92d1bf3512Sdrh /*
93b86ccfb2Sdrh ** Decode a pointer to an sqlite object.
94b86ccfb2Sdrh */
9590f405e3Sdrh static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite **ppDb){
9690f405e3Sdrh   if( sscanf(zA, PTR_FMT, (void**)ppDb)!=1 &&
9790f405e3Sdrh       (zA[0]!='0' || zA[1]!='x' || sscanf(&zA[2], PTR_FMT, (void**)ppDb)!=1)
9890f405e3Sdrh   ){
9990f405e3Sdrh     Tcl_AppendResult(interp, "\"", zA, "\" is not a valid pointer value", 0);
100b86ccfb2Sdrh     return TCL_ERROR;
101b86ccfb2Sdrh   }
102b86ccfb2Sdrh   return TCL_OK;
103b86ccfb2Sdrh }
104b86ccfb2Sdrh 
105b86ccfb2Sdrh /*
10651e3d8e2Sdanielk1977 ** Decode a pointer to an sqlite3_stmt object.
10751e3d8e2Sdanielk1977 */
10851e3d8e2Sdanielk1977 static int getStmtPointer(
10951e3d8e2Sdanielk1977   Tcl_Interp *interp,
11051e3d8e2Sdanielk1977   const char *zArg,
11151e3d8e2Sdanielk1977   sqlite3_stmt **ppStmt
11251e3d8e2Sdanielk1977 ){
11351e3d8e2Sdanielk1977   if( sscanf(zArg, PTR_FMT, (void**)ppStmt)!=1 ){
11451e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0);
11551e3d8e2Sdanielk1977     return TCL_ERROR;
11651e3d8e2Sdanielk1977   }
11751e3d8e2Sdanielk1977   return TCL_OK;
11851e3d8e2Sdanielk1977 }
11951e3d8e2Sdanielk1977 
12051e3d8e2Sdanielk1977 /*
1219a1d0abeSdanielk1977 ** Decode a pointer to an sqlite3_stmt object.
1229a1d0abeSdanielk1977 */
1239a1d0abeSdanielk1977 static int getFilePointer(
1249a1d0abeSdanielk1977   Tcl_Interp *interp,
1259a1d0abeSdanielk1977   const char *zArg,
1269a1d0abeSdanielk1977   OsFile **ppFile
1279a1d0abeSdanielk1977 ){
1289a1d0abeSdanielk1977   if( sscanf(zArg, PTR_FMT, (void**)ppFile)!=1 ){
1299a1d0abeSdanielk1977     Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0);
1309a1d0abeSdanielk1977     return TCL_ERROR;
1319a1d0abeSdanielk1977   }
1329a1d0abeSdanielk1977   return TCL_OK;
1339a1d0abeSdanielk1977 }
1349a1d0abeSdanielk1977 
1359a1d0abeSdanielk1977 /*
1367d8085a8Sdrh ** Generate a text representation of a pointer that can be understood
1377d8085a8Sdrh ** by the getDbPointer and getVmPointer routines above.
1387d8085a8Sdrh **
1397d8085a8Sdrh ** The problem is, on some machines (Solaris) if you do a printf with
1407d8085a8Sdrh ** "%p" you cannot turn around and do a scanf with the same "%p" and
1417d8085a8Sdrh ** get your pointer back.  You have to prepend a "0x" before it will
1427d8085a8Sdrh ** work.  Or at least that is what is reported to me (drh).  But this
1437d8085a8Sdrh ** behavior varies from machine to machine.  The solution used her is
1447d8085a8Sdrh ** to test the string right after it is generated to see if it can be
1457d8085a8Sdrh ** understood by scanf, and if not, try prepending an "0x" to see if
1467d8085a8Sdrh ** that helps.  If nothing works, a fatal error is generated.
1477d8085a8Sdrh */
1487d8085a8Sdrh static int makePointerStr(Tcl_Interp *interp, char *zPtr, void *p){
1497d8085a8Sdrh   void *p2;
1507d8085a8Sdrh   sprintf(zPtr, PTR_FMT, p);
1517d8085a8Sdrh   if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){
1527d8085a8Sdrh     sprintf(zPtr, "0x" PTR_FMT, p);
1537d8085a8Sdrh     if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){
1547d8085a8Sdrh       Tcl_AppendResult(interp, "unable to convert a pointer to a string "
1557d8085a8Sdrh          "in the file " __FILE__ " in function makePointerStr().  Please "
1567d8085a8Sdrh          "report this problem to the SQLite mailing list or as a new but "
1577d8085a8Sdrh          "report.  Please provide detailed information about how you compiled "
1587d8085a8Sdrh          "SQLite and what computer you are running on.", 0);
1597d8085a8Sdrh       return TCL_ERROR;
1607d8085a8Sdrh     }
1617d8085a8Sdrh   }
1627d8085a8Sdrh   return TCL_OK;
1637d8085a8Sdrh }
1647d8085a8Sdrh 
1657d8085a8Sdrh /*
1666f8a503dSdanielk1977 ** The callback routine for sqlite3_exec_printf().
167d1bf3512Sdrh */
168d1bf3512Sdrh static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){
169d1bf3512Sdrh   Tcl_DString *str = (Tcl_DString*)pArg;
170d1bf3512Sdrh   int i;
171d1bf3512Sdrh 
172d1bf3512Sdrh   if( Tcl_DStringLength(str)==0 ){
173d1bf3512Sdrh     for(i=0; i<argc; i++){
174d1bf3512Sdrh       Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL");
175d1bf3512Sdrh     }
176d1bf3512Sdrh   }
177d1bf3512Sdrh   for(i=0; i<argc; i++){
178d1bf3512Sdrh     Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL");
179d1bf3512Sdrh   }
180d1bf3512Sdrh   return 0;
181d1bf3512Sdrh }
182d1bf3512Sdrh 
183d1bf3512Sdrh /*
1846f8a503dSdanielk1977 ** Usage:  sqlite3_exec_printf  DB  FORMAT  STRING
185d1bf3512Sdrh **
1866f8a503dSdanielk1977 ** Invoke the sqlite3_exec_printf() interface using the open database
187d1bf3512Sdrh ** DB.  The SQL is the string FORMAT.  The format string should contain
188d1bf3512Sdrh ** one %s or %q.  STRING is the value inserted into %s or %q.
189d1bf3512Sdrh */
190d1bf3512Sdrh static int test_exec_printf(
191d1bf3512Sdrh   void *NotUsed,
192d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
193d1bf3512Sdrh   int argc,              /* Number of arguments */
194d1bf3512Sdrh   char **argv            /* Text of each argument */
195d1bf3512Sdrh ){
196d1bf3512Sdrh   sqlite *db;
197d1bf3512Sdrh   Tcl_DString str;
198d1bf3512Sdrh   int rc;
199d1bf3512Sdrh   char *zErr = 0;
200d1bf3512Sdrh   char zBuf[30];
201d1bf3512Sdrh   if( argc!=4 ){
202d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
203d1bf3512Sdrh        " DB FORMAT STRING", 0);
204d1bf3512Sdrh     return TCL_ERROR;
205d1bf3512Sdrh   }
206b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
207d1bf3512Sdrh   Tcl_DStringInit(&str);
2086f8a503dSdanielk1977   rc = sqlite3_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]);
209d1bf3512Sdrh   sprintf(zBuf, "%d", rc);
210d1bf3512Sdrh   Tcl_AppendElement(interp, zBuf);
211d1bf3512Sdrh   Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
212d1bf3512Sdrh   Tcl_DStringFree(&str);
213d1bf3512Sdrh   if( zErr ) free(zErr);
214d1bf3512Sdrh   return TCL_OK;
215d1bf3512Sdrh }
216d1bf3512Sdrh 
217d1bf3512Sdrh /*
2186f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_z_test  SEPARATOR  ARG0  ARG1 ...
219d93d8a81Sdrh **
220d93d8a81Sdrh ** Test the %z format of mprintf().  Use multiple mprintf() calls to
221d93d8a81Sdrh ** concatenate arg0 through argn using separator as the separator.
222d93d8a81Sdrh ** Return the result.
223d93d8a81Sdrh */
224d93d8a81Sdrh static int test_mprintf_z(
225d93d8a81Sdrh   void *NotUsed,
226d93d8a81Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
227d93d8a81Sdrh   int argc,              /* Number of arguments */
228d93d8a81Sdrh   char **argv            /* Text of each argument */
229d93d8a81Sdrh ){
230d93d8a81Sdrh   char *zResult = 0;
231d93d8a81Sdrh   int i;
232d93d8a81Sdrh 
233d93d8a81Sdrh   for(i=2; i<argc; i++){
2344adee20fSdanielk1977     zResult = sqlite3MPrintf("%z%s%s", zResult, argv[1], argv[i]);
235d93d8a81Sdrh   }
236d93d8a81Sdrh   Tcl_AppendResult(interp, zResult, 0);
2375f968436Sdrh   sqliteFree(zResult);
238d93d8a81Sdrh   return TCL_OK;
239d93d8a81Sdrh }
240d93d8a81Sdrh 
241d93d8a81Sdrh /*
2426f8a503dSdanielk1977 ** Usage:  sqlite3_get_table_printf  DB  FORMAT  STRING
243d1bf3512Sdrh **
2446f8a503dSdanielk1977 ** Invoke the sqlite3_get_table_printf() interface using the open database
245d1bf3512Sdrh ** DB.  The SQL is the string FORMAT.  The format string should contain
246d1bf3512Sdrh ** one %s or %q.  STRING is the value inserted into %s or %q.
247d1bf3512Sdrh */
248d1bf3512Sdrh static int test_get_table_printf(
249d1bf3512Sdrh   void *NotUsed,
250d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
251d1bf3512Sdrh   int argc,              /* Number of arguments */
252d1bf3512Sdrh   char **argv            /* Text of each argument */
253d1bf3512Sdrh ){
254d1bf3512Sdrh   sqlite *db;
255d1bf3512Sdrh   Tcl_DString str;
256d1bf3512Sdrh   int rc;
257d1bf3512Sdrh   char *zErr = 0;
258d1bf3512Sdrh   int nRow, nCol;
259d1bf3512Sdrh   char **aResult;
260d1bf3512Sdrh   int i;
261d1bf3512Sdrh   char zBuf[30];
262d1bf3512Sdrh   if( argc!=4 ){
263d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
264d1bf3512Sdrh        " DB FORMAT STRING", 0);
265d1bf3512Sdrh     return TCL_ERROR;
266d1bf3512Sdrh   }
267b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
268d1bf3512Sdrh   Tcl_DStringInit(&str);
2696f8a503dSdanielk1977   rc = sqlite3_get_table_printf(db, argv[2], &aResult, &nRow, &nCol,
270d1bf3512Sdrh                &zErr, argv[3]);
271d1bf3512Sdrh   sprintf(zBuf, "%d", rc);
272d1bf3512Sdrh   Tcl_AppendElement(interp, zBuf);
273d1bf3512Sdrh   if( rc==SQLITE_OK ){
274d1bf3512Sdrh     sprintf(zBuf, "%d", nRow);
275d1bf3512Sdrh     Tcl_AppendElement(interp, zBuf);
276d1bf3512Sdrh     sprintf(zBuf, "%d", nCol);
277d1bf3512Sdrh     Tcl_AppendElement(interp, zBuf);
278d1bf3512Sdrh     for(i=0; i<(nRow+1)*nCol; i++){
279d1bf3512Sdrh       Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL");
280d1bf3512Sdrh     }
281d1bf3512Sdrh   }else{
282d1bf3512Sdrh     Tcl_AppendElement(interp, zErr);
283d1bf3512Sdrh   }
2846f8a503dSdanielk1977   sqlite3_free_table(aResult);
285d1bf3512Sdrh   if( zErr ) free(zErr);
286d1bf3512Sdrh   return TCL_OK;
287d1bf3512Sdrh }
288d1bf3512Sdrh 
289af9ff33aSdrh 
290af9ff33aSdrh /*
2916f8a503dSdanielk1977 ** Usage:  sqlite3_last_insert_rowid DB
292af9ff33aSdrh **
293af9ff33aSdrh ** Returns the integer ROWID of the most recent insert.
294af9ff33aSdrh */
295af9ff33aSdrh static int test_last_rowid(
296af9ff33aSdrh   void *NotUsed,
297af9ff33aSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
298af9ff33aSdrh   int argc,              /* Number of arguments */
299af9ff33aSdrh   char **argv            /* Text of each argument */
300af9ff33aSdrh ){
301af9ff33aSdrh   sqlite *db;
302af9ff33aSdrh   char zBuf[30];
303af9ff33aSdrh 
304af9ff33aSdrh   if( argc!=2 ){
305af9ff33aSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0);
306af9ff33aSdrh     return TCL_ERROR;
307af9ff33aSdrh   }
308b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
309c572ef7fSdanielk1977   sprintf(zBuf, "%lld", sqlite3_last_insert_rowid(db));
310af9ff33aSdrh   Tcl_AppendResult(interp, zBuf, 0);
311af9ff33aSdrh   return SQLITE_OK;
312af9ff33aSdrh }
313af9ff33aSdrh 
314d1bf3512Sdrh /*
3156f8a503dSdanielk1977 ** Usage:  sqlite3_close DB
316d1bf3512Sdrh **
3176f8a503dSdanielk1977 ** Closes the database opened by sqlite3_open.
318d1bf3512Sdrh */
319d1bf3512Sdrh static int sqlite_test_close(
320d1bf3512Sdrh   void *NotUsed,
321d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
322d1bf3512Sdrh   int argc,              /* Number of arguments */
323d1bf3512Sdrh   char **argv            /* Text of each argument */
324d1bf3512Sdrh ){
325d1bf3512Sdrh   sqlite *db;
326d1bf3512Sdrh   if( argc!=2 ){
327d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
328d1bf3512Sdrh        " FILENAME\"", 0);
329d1bf3512Sdrh     return TCL_ERROR;
330d1bf3512Sdrh   }
331b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
3326f8a503dSdanielk1977   sqlite3_close(db);
333d1bf3512Sdrh   return TCL_OK;
334d1bf3512Sdrh }
335d1bf3512Sdrh 
336d1bf3512Sdrh /*
337c22bd47dSdrh ** Implementation of the x_coalesce() function.
338c22bd47dSdrh ** Return the first argument non-NULL argument.
339c22bd47dSdrh */
3400ae8b831Sdanielk1977 static void ifnullFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
341c22bd47dSdrh   int i;
342c22bd47dSdrh   for(i=0; i<argc; i++){
3439c054830Sdrh     if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){
3444f26d6c4Sdrh       sqlite3_result_text(context, sqlite3_value_text(argv[i]), -1, 1);
345c22bd47dSdrh       break;
346c22bd47dSdrh     }
347c22bd47dSdrh   }
348c22bd47dSdrh }
349c22bd47dSdrh 
350c22bd47dSdrh /*
351d1d9fc33Sdrh ** A structure into which to accumulate text.
352d1d9fc33Sdrh */
353d1d9fc33Sdrh struct dstr {
354d1d9fc33Sdrh   int nAlloc;  /* Space allocated */
355d1d9fc33Sdrh   int nUsed;   /* Space used */
356d1d9fc33Sdrh   char *z;     /* The space */
357d1d9fc33Sdrh };
358d1d9fc33Sdrh 
359d1d9fc33Sdrh /*
360d1d9fc33Sdrh ** Append text to a dstr
361d1d9fc33Sdrh */
362d1d9fc33Sdrh static void dstrAppend(struct dstr *p, const char *z, int divider){
363d1d9fc33Sdrh   int n = strlen(z);
364d1d9fc33Sdrh   if( p->nUsed + n + 2 > p->nAlloc ){
365d1d9fc33Sdrh     char *zNew;
366d1d9fc33Sdrh     p->nAlloc = p->nAlloc*2 + n + 200;
367d1d9fc33Sdrh     zNew = sqliteRealloc(p->z, p->nAlloc);
368d1d9fc33Sdrh     if( zNew==0 ){
369d1d9fc33Sdrh       sqliteFree(p->z);
370d1d9fc33Sdrh       memset(p, 0, sizeof(*p));
371d1d9fc33Sdrh       return;
372d1d9fc33Sdrh     }
373d1d9fc33Sdrh     p->z = zNew;
374d1d9fc33Sdrh   }
375d1d9fc33Sdrh   if( divider && p->nUsed>0 ){
376d1d9fc33Sdrh     p->z[p->nUsed++] = divider;
377d1d9fc33Sdrh   }
378d1d9fc33Sdrh   memcpy(&p->z[p->nUsed], z, n+1);
379d1d9fc33Sdrh   p->nUsed += n;
380d1d9fc33Sdrh }
381d1d9fc33Sdrh 
382d1d9fc33Sdrh /*
3834adee20fSdanielk1977 ** Invoked for each callback from sqlite3ExecFunc
384d1d9fc33Sdrh */
385d1d9fc33Sdrh static int execFuncCallback(void *pData, int argc, char **argv, char **NotUsed){
386d1d9fc33Sdrh   struct dstr *p = (struct dstr*)pData;
387d1d9fc33Sdrh   int i;
388d1d9fc33Sdrh   for(i=0; i<argc; i++){
389d1d9fc33Sdrh     if( argv[i]==0 ){
390d1d9fc33Sdrh       dstrAppend(p, "NULL", ' ');
391d1d9fc33Sdrh     }else{
392d1d9fc33Sdrh       dstrAppend(p, argv[i], ' ');
393d1d9fc33Sdrh     }
394d1d9fc33Sdrh   }
395d1d9fc33Sdrh   return 0;
396d1d9fc33Sdrh }
397d1d9fc33Sdrh 
398d1d9fc33Sdrh /*
3996f8a503dSdanielk1977 ** Implementation of the x_sqlite3_exec() function.  This function takes
400c22bd47dSdrh ** a single argument and attempts to execute that argument as SQL code.
4016cbe1f1bSdrh ** This is illegal and should set the SQLITE_MISUSE flag on the database.
402c22bd47dSdrh **
4036f8a503dSdanielk1977 ** 2004-Jan-07:  We have changed this to make it legal to call sqlite3_exec()
404d1d9fc33Sdrh ** from within a function call.
405d1d9fc33Sdrh **
406c22bd47dSdrh ** This routine simulates the effect of having two threads attempt to
407c22bd47dSdrh ** use the same database at the same time.
408c22bd47dSdrh */
40951ad0ecdSdanielk1977 static void sqlite3ExecFunc(
4100ae8b831Sdanielk1977   sqlite3_context *context,
41151ad0ecdSdanielk1977   int argc,
41251ad0ecdSdanielk1977   sqlite3_value **argv
41351ad0ecdSdanielk1977 ){
414d1d9fc33Sdrh   struct dstr x;
415d1d9fc33Sdrh   memset(&x, 0, sizeof(x));
41651ad0ecdSdanielk1977   sqlite3_exec((sqlite*)sqlite3_user_data(context),
4174f26d6c4Sdrh       sqlite3_value_text(argv[0]),
418d1d9fc33Sdrh       execFuncCallback, &x, 0);
4197e18c259Sdanielk1977   sqlite3_result_text(context, x.z, x.nUsed, 1);
420d1d9fc33Sdrh   sqliteFree(x.z);
421c22bd47dSdrh }
422c22bd47dSdrh 
423c22bd47dSdrh /*
424c22bd47dSdrh ** Usage:  sqlite_test_create_function DB
425c22bd47dSdrh **
4266f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order
427c22bd47dSdrh ** to create a function named "x_coalesce".  This function does the same thing
428c22bd47dSdrh ** as the "coalesce" function.  This function also registers an SQL function
4296f8a503dSdanielk1977 ** named "x_sqlite3_exec" that invokes sqlite3_exec().  Invoking sqlite3_exec()
430c22bd47dSdrh ** in this way is illegal recursion and should raise an SQLITE_MISUSE error.
431c22bd47dSdrh ** The effect is similar to trying to use the same database connection from
432c22bd47dSdrh ** two threads at the same time.
433c22bd47dSdrh **
434c22bd47dSdrh ** The original motivation for this routine was to be able to call the
4356f8a503dSdanielk1977 ** sqlite3_create_function function while a query is in progress in order
436c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
437c22bd47dSdrh */
438c2eef3b3Sdrh static int test_create_function(
439c22bd47dSdrh   void *NotUsed,
440c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
441c22bd47dSdrh   int argc,              /* Number of arguments */
442c22bd47dSdrh   char **argv            /* Text of each argument */
443c22bd47dSdrh ){
444c22bd47dSdrh   sqlite *db;
445c22bd47dSdrh   extern void Md5_Register(sqlite*);
446c22bd47dSdrh   if( argc!=2 ){
447c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
448c22bd47dSdrh        " FILENAME\"", 0);
449c22bd47dSdrh     return TCL_ERROR;
450c22bd47dSdrh   }
451b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
4526590493dSdanielk1977   sqlite3_create_function(db, "x_coalesce", -1, 0, 0, 0, ifnullFunc, 0, 0);
4536590493dSdanielk1977   sqlite3_create_function(db, "x_sqlite3_exec", 1, 0, 0, db,
4546590493dSdanielk1977       sqlite3ExecFunc, 0, 0);
455c22bd47dSdrh   return TCL_OK;
456c22bd47dSdrh }
457c22bd47dSdrh 
458c22bd47dSdrh /*
459c22bd47dSdrh ** Routines to implement the x_count() aggregate function.
460c22bd47dSdrh */
461c22bd47dSdrh typedef struct CountCtx CountCtx;
462c22bd47dSdrh struct CountCtx {
463c22bd47dSdrh   int n;
464c22bd47dSdrh };
4650ae8b831Sdanielk1977 static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
466c22bd47dSdrh   CountCtx *p;
4674f26d6c4Sdrh   p = sqlite3_aggregate_context(context, sizeof(*p));
4689c054830Sdrh   if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0]) ) && p ){
469c22bd47dSdrh     p->n++;
470c22bd47dSdrh   }
471c22bd47dSdrh }
4720ae8b831Sdanielk1977 static void countFinalize(sqlite3_context *context){
473c22bd47dSdrh   CountCtx *p;
4744f26d6c4Sdrh   p = sqlite3_aggregate_context(context, sizeof(*p));
475c572ef7fSdanielk1977   sqlite3_result_int(context, p ? p->n : 0);
476c22bd47dSdrh }
477c22bd47dSdrh 
478c22bd47dSdrh /*
479c22bd47dSdrh ** Usage:  sqlite_test_create_aggregate DB
480c22bd47dSdrh **
4816f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order
482c22bd47dSdrh ** to create a function named "x_count".  This function does the same thing
483c22bd47dSdrh ** as the "md5sum" function.
484c22bd47dSdrh **
485c22bd47dSdrh ** The original motivation for this routine was to be able to call the
4866f8a503dSdanielk1977 ** sqlite3_create_aggregate function while a query is in progress in order
487c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
488c22bd47dSdrh */
489c2eef3b3Sdrh static int test_create_aggregate(
490c22bd47dSdrh   void *NotUsed,
491c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
492c22bd47dSdrh   int argc,              /* Number of arguments */
493c22bd47dSdrh   char **argv            /* Text of each argument */
494c22bd47dSdrh ){
495c22bd47dSdrh   sqlite *db;
496c22bd47dSdrh   if( argc!=2 ){
497c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
498c22bd47dSdrh        " FILENAME\"", 0);
499c22bd47dSdrh     return TCL_ERROR;
500c22bd47dSdrh   }
501b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
5026590493dSdanielk1977   sqlite3_create_function(db, "x_count", 0, 0, 0, 0, 0,countStep,countFinalize);
5036590493dSdanielk1977   sqlite3_create_function(db, "x_count", 1, 0, 0, 0, 0,countStep,countFinalize);
504c22bd47dSdrh   return TCL_OK;
505c22bd47dSdrh }
506c22bd47dSdrh 
507c22bd47dSdrh 
508c22bd47dSdrh 
509c22bd47dSdrh /*
5106f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER
511d1bf3512Sdrh **
512d1bf3512Sdrh ** Call mprintf with three integer arguments
513d1bf3512Sdrh */
5146f8a503dSdanielk1977 static int sqlite3_mprintf_int(
515d1bf3512Sdrh   void *NotUsed,
516d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
517d1bf3512Sdrh   int argc,              /* Number of arguments */
518d1bf3512Sdrh   char **argv            /* Text of each argument */
519d1bf3512Sdrh ){
520d1bf3512Sdrh   int a[3], i;
521d1bf3512Sdrh   char *z;
522d1bf3512Sdrh   if( argc!=5 ){
523d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
524d1bf3512Sdrh        " FORMAT INT INT INT\"", 0);
525d1bf3512Sdrh     return TCL_ERROR;
526d1bf3512Sdrh   }
527d1bf3512Sdrh   for(i=2; i<5; i++){
528d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
529d1bf3512Sdrh   }
5306f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]);
531d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
5323f4fedb2Sdrh   sqlite3_free(z);
533d1bf3512Sdrh   return TCL_OK;
534d1bf3512Sdrh }
535d1bf3512Sdrh 
536d1bf3512Sdrh /*
5376f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT INTEGER INTEGER STRING
538d1bf3512Sdrh **
539d1bf3512Sdrh ** Call mprintf with two integer arguments and one string argument
540d1bf3512Sdrh */
5416f8a503dSdanielk1977 static int sqlite3_mprintf_str(
542d1bf3512Sdrh   void *NotUsed,
543d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
544d1bf3512Sdrh   int argc,              /* Number of arguments */
545d1bf3512Sdrh   char **argv            /* Text of each argument */
546d1bf3512Sdrh ){
547d1bf3512Sdrh   int a[3], i;
548d1bf3512Sdrh   char *z;
549f220b24fSchw   if( argc<4 || argc>5 ){
550d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
551f220b24fSchw        " FORMAT INT INT ?STRING?\"", 0);
552d1bf3512Sdrh     return TCL_ERROR;
553d1bf3512Sdrh   }
554d1bf3512Sdrh   for(i=2; i<4; i++){
555d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
556d1bf3512Sdrh   }
5576f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL);
558d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
5593f4fedb2Sdrh   sqlite3_free(z);
560d1bf3512Sdrh   return TCL_OK;
561d1bf3512Sdrh }
562d1bf3512Sdrh 
563d1bf3512Sdrh /*
5646f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT INTEGER INTEGER DOUBLE
565d1bf3512Sdrh **
566d1bf3512Sdrh ** Call mprintf with two integer arguments and one double argument
567d1bf3512Sdrh */
5686f8a503dSdanielk1977 static int sqlite3_mprintf_double(
569d1bf3512Sdrh   void *NotUsed,
570d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
571d1bf3512Sdrh   int argc,              /* Number of arguments */
572d1bf3512Sdrh   char **argv            /* Text of each argument */
573d1bf3512Sdrh ){
574d1bf3512Sdrh   int a[3], i;
575d1bf3512Sdrh   double r;
576d1bf3512Sdrh   char *z;
577d1bf3512Sdrh   if( argc!=5 ){
578d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
579d1bf3512Sdrh        " FORMAT INT INT STRING\"", 0);
580d1bf3512Sdrh     return TCL_ERROR;
581d1bf3512Sdrh   }
582d1bf3512Sdrh   for(i=2; i<4; i++){
583d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
584d1bf3512Sdrh   }
585d1bf3512Sdrh   if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR;
5866f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], r);
587d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
5883f4fedb2Sdrh   sqlite3_free(z);
589d1bf3512Sdrh   return TCL_OK;
590d1bf3512Sdrh }
591d1bf3512Sdrh 
592d1bf3512Sdrh /*
5936f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT DOUBLE DOUBLE
594b621c237Sdrh **
595b621c237Sdrh ** Call mprintf with a single double argument which is the product of the
596b621c237Sdrh ** two arguments given above.  This is used to generate overflow and underflow
597b621c237Sdrh ** doubles to test that they are converted properly.
598b621c237Sdrh */
5996f8a503dSdanielk1977 static int sqlite3_mprintf_scaled(
600b621c237Sdrh   void *NotUsed,
601b621c237Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
602b621c237Sdrh   int argc,              /* Number of arguments */
603b621c237Sdrh   char **argv            /* Text of each argument */
604b621c237Sdrh ){
605b621c237Sdrh   int i;
606b621c237Sdrh   double r[2];
607b621c237Sdrh   char *z;
608b621c237Sdrh   if( argc!=4 ){
609b621c237Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
610b621c237Sdrh        " FORMAT DOUBLE DOUBLE\"", 0);
611b621c237Sdrh     return TCL_ERROR;
612b621c237Sdrh   }
613b621c237Sdrh   for(i=2; i<4; i++){
614b621c237Sdrh     if( Tcl_GetDouble(interp, argv[i], &r[i-2]) ) return TCL_ERROR;
615b621c237Sdrh   }
6166f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], r[0]*r[1]);
617b621c237Sdrh   Tcl_AppendResult(interp, z, 0);
6183f4fedb2Sdrh   sqlite3_free(z);
619b621c237Sdrh   return TCL_OK;
620b621c237Sdrh }
621b621c237Sdrh 
622b621c237Sdrh /*
623daffd0e5Sdrh ** Usage: sqlite_malloc_fail N
624daffd0e5Sdrh **
625afa4a020Sdrh ** Rig sqliteMalloc() to fail on the N-th call.  Turn off this mechanism
6266f8a503dSdanielk1977 ** and reset the sqlite3_malloc_failed variable is N==0.
627daffd0e5Sdrh */
628*faa57accSdrh #ifdef SQLITE_DEBUG
629daffd0e5Sdrh static int sqlite_malloc_fail(
630daffd0e5Sdrh   void *NotUsed,
631daffd0e5Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
632daffd0e5Sdrh   int argc,              /* Number of arguments */
633daffd0e5Sdrh   char **argv            /* Text of each argument */
634daffd0e5Sdrh ){
635daffd0e5Sdrh   int n;
636daffd0e5Sdrh   if( argc!=2 ){
637daffd0e5Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0);
638daffd0e5Sdrh     return TCL_ERROR;
639daffd0e5Sdrh   }
640daffd0e5Sdrh   if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
6416f8a503dSdanielk1977   sqlite3_iMallocFail = n;
6426f8a503dSdanielk1977   sqlite3_malloc_failed = 0;
643daffd0e5Sdrh   return TCL_OK;
644daffd0e5Sdrh }
645daffd0e5Sdrh #endif
646daffd0e5Sdrh 
647daffd0e5Sdrh /*
648daffd0e5Sdrh ** Usage: sqlite_malloc_stat
649daffd0e5Sdrh **
650daffd0e5Sdrh ** Return the number of prior calls to sqliteMalloc() and sqliteFree().
651daffd0e5Sdrh */
652*faa57accSdrh #ifdef SQLITE_DEBUG
653daffd0e5Sdrh static int sqlite_malloc_stat(
654daffd0e5Sdrh   void *NotUsed,
655daffd0e5Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
656daffd0e5Sdrh   int argc,              /* Number of arguments */
657daffd0e5Sdrh   char **argv            /* Text of each argument */
658daffd0e5Sdrh ){
659daffd0e5Sdrh   char zBuf[200];
6606f8a503dSdanielk1977   sprintf(zBuf, "%d %d %d", sqlite3_nMalloc, sqlite3_nFree, sqlite3_iMallocFail);
661daffd0e5Sdrh   Tcl_AppendResult(interp, zBuf, 0);
662daffd0e5Sdrh   return TCL_OK;
663daffd0e5Sdrh }
664daffd0e5Sdrh #endif
665daffd0e5Sdrh 
666daffd0e5Sdrh /*
66728b4e489Sdrh ** Usage:  sqlite_abort
66828b4e489Sdrh **
66928b4e489Sdrh ** Shutdown the process immediately.  This is not a clean shutdown.
67028b4e489Sdrh ** This command is used to test the recoverability of a database in
67128b4e489Sdrh ** the event of a program crash.
67228b4e489Sdrh */
67328b4e489Sdrh static int sqlite_abort(
67428b4e489Sdrh   void *NotUsed,
67528b4e489Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
67628b4e489Sdrh   int argc,              /* Number of arguments */
67728b4e489Sdrh   char **argv            /* Text of each argument */
67828b4e489Sdrh ){
67928b4e489Sdrh   assert( interp==0 );   /* This will always fail */
68028b4e489Sdrh   return TCL_OK;
68128b4e489Sdrh }
68228b4e489Sdrh 
68328b4e489Sdrh /*
6846cbe1f1bSdrh ** The following routine is a user-defined SQL function whose purpose
6856cbe1f1bSdrh ** is to test the sqlite_set_result() API.
6866cbe1f1bSdrh */
6870ae8b831Sdanielk1977 static void testFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
6886cbe1f1bSdrh   while( argc>=2 ){
6894f26d6c4Sdrh     const char *zArg0 = sqlite3_value_text(argv[0]);
6906d88bad4Sdanielk1977     if( zArg0 ){
6916d88bad4Sdanielk1977       if( 0==sqlite3StrICmp(zArg0, "int") ){
6926d88bad4Sdanielk1977         sqlite3_result_int(context, sqlite3_value_int(argv[1]));
6936d88bad4Sdanielk1977       }else if( sqlite3StrICmp(zArg0,"int64")==0 ){
6946d88bad4Sdanielk1977         sqlite3_result_int64(context, sqlite3_value_int64(argv[1]));
69551ad0ecdSdanielk1977       }else if( sqlite3StrICmp(zArg0,"string")==0 ){
6966d88bad4Sdanielk1977         sqlite3_result_text(context, sqlite3_value_text(argv[1]), -1, 1);
69751ad0ecdSdanielk1977       }else if( sqlite3StrICmp(zArg0,"double")==0 ){
6986d88bad4Sdanielk1977         sqlite3_result_double(context, sqlite3_value_double(argv[1]));
6996d88bad4Sdanielk1977       }else if( sqlite3StrICmp(zArg0,"null")==0 ){
7006d88bad4Sdanielk1977         sqlite3_result_null(context);
7016d88bad4Sdanielk1977       }else if( sqlite3StrICmp(zArg0,"value")==0 ){
7026d88bad4Sdanielk1977         sqlite3_result_value(context, argv[sqlite3_value_int(argv[1])]);
7036cbe1f1bSdrh       }else{
7046d88bad4Sdanielk1977         goto error_out;
7056d88bad4Sdanielk1977       }
7066d88bad4Sdanielk1977     }else{
7076d88bad4Sdanielk1977       goto error_out;
7086cbe1f1bSdrh     }
7096cbe1f1bSdrh     argc -= 2;
7106cbe1f1bSdrh     argv += 2;
7116cbe1f1bSdrh   }
7126d88bad4Sdanielk1977   return;
7136d88bad4Sdanielk1977 
7146d88bad4Sdanielk1977 error_out:
7156d88bad4Sdanielk1977   sqlite3_result_error(context,"first argument should be one of: "
7166d88bad4Sdanielk1977       "int int64 string double null value", -1);
7176cbe1f1bSdrh }
7186cbe1f1bSdrh 
7196cbe1f1bSdrh /*
7206cbe1f1bSdrh ** Usage:   sqlite_register_test_function  DB  NAME
7216cbe1f1bSdrh **
7226cbe1f1bSdrh ** Register the test SQL function on the database DB under the name NAME.
7236cbe1f1bSdrh */
724c2eef3b3Sdrh static int test_register_func(
7256cbe1f1bSdrh   void *NotUsed,
7266cbe1f1bSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
7276cbe1f1bSdrh   int argc,              /* Number of arguments */
7286cbe1f1bSdrh   char **argv            /* Text of each argument */
7296cbe1f1bSdrh ){
7306cbe1f1bSdrh   sqlite *db;
7316cbe1f1bSdrh   int rc;
7326cbe1f1bSdrh   if( argc!=3 ){
7336cbe1f1bSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
7346cbe1f1bSdrh        " DB FUNCTION-NAME", 0);
7356cbe1f1bSdrh     return TCL_ERROR;
7366cbe1f1bSdrh   }
737b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
7386590493dSdanielk1977   rc = sqlite3_create_function(db, argv[2], -1, 0, 0, 0, testFunc, 0, 0);
7396cbe1f1bSdrh   if( rc!=0 ){
740f20b21c8Sdanielk1977     Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);
7416cbe1f1bSdrh     return TCL_ERROR;
7426cbe1f1bSdrh   }
7436cbe1f1bSdrh   return TCL_OK;
7446cbe1f1bSdrh }
7456cbe1f1bSdrh 
7466cbe1f1bSdrh /*
747106bb236Sdanielk1977 ** Usage:  sqlite3_finalize  STMT
748b86ccfb2Sdrh **
749106bb236Sdanielk1977 ** Finalize a statement handle.
750b86ccfb2Sdrh */
751b86ccfb2Sdrh static int test_finalize(
752106bb236Sdanielk1977   void * clientData,
753106bb236Sdanielk1977   Tcl_Interp *interp,
754106bb236Sdanielk1977   int objc,
755106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
756b86ccfb2Sdrh ){
757106bb236Sdanielk1977   sqlite3_stmt *pStmt;
758b86ccfb2Sdrh   int rc;
759106bb236Sdanielk1977 
760106bb236Sdanielk1977   if( objc!=2 ){
761106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
762106bb236Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
763b86ccfb2Sdrh     return TCL_ERROR;
764b86ccfb2Sdrh   }
765106bb236Sdanielk1977 
766106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
767106bb236Sdanielk1977 
768fc57d7bfSdanielk1977   rc = sqlite3_finalize(pStmt);
769b77f5dadSdanielk1977   Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
770b86ccfb2Sdrh   if( rc ){
771106bb236Sdanielk1977     return TCL_ERROR;
772106bb236Sdanielk1977   }
773106bb236Sdanielk1977   return TCL_OK;
774106bb236Sdanielk1977 }
775106bb236Sdanielk1977 
776106bb236Sdanielk1977 /*
777106bb236Sdanielk1977 ** Usage:  sqlite3_reset  STMT
778106bb236Sdanielk1977 **
779106bb236Sdanielk1977 ** Finalize a statement handle.
780106bb236Sdanielk1977 */
781106bb236Sdanielk1977 static int test_reset(
782106bb236Sdanielk1977   void * clientData,
783106bb236Sdanielk1977   Tcl_Interp *interp,
784106bb236Sdanielk1977   int objc,
785106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
786106bb236Sdanielk1977 ){
787106bb236Sdanielk1977   sqlite3_stmt *pStmt;
788106bb236Sdanielk1977   int rc;
789106bb236Sdanielk1977 
790106bb236Sdanielk1977   if( objc!=2 ){
791106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
792106bb236Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
793106bb236Sdanielk1977     return TCL_ERROR;
794106bb236Sdanielk1977   }
795106bb236Sdanielk1977 
796106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
797106bb236Sdanielk1977 
798fc57d7bfSdanielk1977   rc = sqlite3_reset(pStmt);
799106bb236Sdanielk1977   if( rc ){
800b86ccfb2Sdrh     return TCL_ERROR;
801b86ccfb2Sdrh   }
802b86ccfb2Sdrh   return TCL_OK;
803b86ccfb2Sdrh }
804b86ccfb2Sdrh 
8055a38705eSdrh /*
8066f8a503dSdanielk1977 ** Usage:  sqlite3_reset   VM
80750457896Sdrh **
80850457896Sdrh ** Reset a virtual machine and prepare it to be run again.
80950457896Sdrh */
81050457896Sdrh 
81150457896Sdrh /*
8127c972decSdrh ** This is the "static_bind_value" that variables are bound to when
8136f8a503dSdanielk1977 ** the FLAG option of sqlite3_bind is "static"
81450457896Sdrh */
8157c972decSdrh static char *sqlite_static_bind_value = 0;
8167c972decSdrh 
8177c972decSdrh /*
8186f8a503dSdanielk1977 ** Usage:  sqlite3_bind  VM  IDX  VALUE  FLAGS
8197c972decSdrh **
8207c972decSdrh ** Sets the value of the IDX-th occurance of "?" in the original SQL
8217c972decSdrh ** string.  VALUE is the new value.  If FLAGS=="null" then VALUE is
8227c972decSdrh ** ignored and the value is set to NULL.  If FLAGS=="static" then
8237c972decSdrh ** the value is set to the value of a static variable named
8247c972decSdrh ** "sqlite_static_bind_value".  If FLAGS=="normal" then a copy
8257c972decSdrh ** of the VALUE is made.
8267c972decSdrh */
8277c972decSdrh static int test_bind(
82850457896Sdrh   void *NotUsed,
82950457896Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
83050457896Sdrh   int argc,              /* Number of arguments */
83150457896Sdrh   char **argv            /* Text of each argument */
83250457896Sdrh ){
833fc57d7bfSdanielk1977   sqlite3_stmt *pStmt;
83450457896Sdrh   int rc;
8357c972decSdrh   int idx;
8367c972decSdrh   if( argc!=5 ){
83750457896Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
8387c972decSdrh        " VM IDX VALUE (null|static|normal)\"", 0);
83950457896Sdrh     return TCL_ERROR;
84050457896Sdrh   }
841fc57d7bfSdanielk1977   if( getStmtPointer(interp, argv[1], &pStmt) ) return TCL_ERROR;
8427c972decSdrh   if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR;
8437c972decSdrh   if( strcmp(argv[4],"null")==0 ){
844fc57d7bfSdanielk1977     rc = sqlite3_bind_null(pStmt, idx);
8457c972decSdrh   }else if( strcmp(argv[4],"static")==0 ){
846fc57d7bfSdanielk1977     rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0);
8477c972decSdrh   }else if( strcmp(argv[4],"normal")==0 ){
848fc57d7bfSdanielk1977     rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, 1);
8497c972decSdrh   }else{
8507c972decSdrh     Tcl_AppendResult(interp, "4th argument should be "
8517c972decSdrh         "\"null\" or \"static\" or \"normal\"", 0);
8527c972decSdrh     return TCL_ERROR;
8537c972decSdrh   }
85450457896Sdrh   if( rc ){
85550457896Sdrh     char zBuf[50];
85650457896Sdrh     sprintf(zBuf, "(%d) ", rc);
857f20b21c8Sdanielk1977     Tcl_AppendResult(interp, zBuf, sqlite3ErrStr(rc), 0);
85850457896Sdrh     return TCL_ERROR;
85950457896Sdrh   }
86050457896Sdrh   return TCL_OK;
86150457896Sdrh }
86250457896Sdrh 
86350457896Sdrh /*
86499ee3600Sdrh ** Usage:    breakpoint
86599ee3600Sdrh **
86699ee3600Sdrh ** This routine exists for one purpose - to provide a place to put a
86799ee3600Sdrh ** breakpoint with GDB that can be triggered using TCL code.  The use
86899ee3600Sdrh ** for this is when a particular test fails on (say) the 1485th iteration.
86999ee3600Sdrh ** In the TCL test script, we can add code like this:
87099ee3600Sdrh **
87199ee3600Sdrh **     if {$i==1485} breakpoint
87299ee3600Sdrh **
87399ee3600Sdrh ** Then run testfixture in the debugger and wait for the breakpoint to
87499ee3600Sdrh ** fire.  Then additional breakpoints can be set to trace down the bug.
87599ee3600Sdrh */
87699ee3600Sdrh static int test_breakpoint(
87799ee3600Sdrh   void *NotUsed,
87899ee3600Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
87999ee3600Sdrh   int argc,              /* Number of arguments */
88099ee3600Sdrh   char **argv            /* Text of each argument */
88199ee3600Sdrh ){
88299ee3600Sdrh   return TCL_OK;         /* Do nothing */
88399ee3600Sdrh }
88499ee3600Sdrh 
88551e3d8e2Sdanielk1977 static int test_bind_int32(
88651e3d8e2Sdanielk1977   void * clientData,
88751e3d8e2Sdanielk1977   Tcl_Interp *interp,
88851e3d8e2Sdanielk1977   int objc,
88951e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
89051e3d8e2Sdanielk1977 ){
89151e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
89251e3d8e2Sdanielk1977   int idx;
89351e3d8e2Sdanielk1977   int value;
89451e3d8e2Sdanielk1977   int rc;
89551e3d8e2Sdanielk1977 
89651e3d8e2Sdanielk1977   if( objc!=4 ){
89751e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
89851e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
89951e3d8e2Sdanielk1977     return TCL_ERROR;
90051e3d8e2Sdanielk1977   }
90151e3d8e2Sdanielk1977 
90251e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
90351e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
90451e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &value) ) return TCL_ERROR;
90551e3d8e2Sdanielk1977 
906c572ef7fSdanielk1977   rc = sqlite3_bind_int(pStmt, idx, value);
90751e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
90851e3d8e2Sdanielk1977     return TCL_ERROR;
90951e3d8e2Sdanielk1977   }
91051e3d8e2Sdanielk1977 
91151e3d8e2Sdanielk1977   return TCL_OK;
91251e3d8e2Sdanielk1977 }
91351e3d8e2Sdanielk1977 
91451e3d8e2Sdanielk1977 static int test_bind_int64(
91551e3d8e2Sdanielk1977   void * clientData,
91651e3d8e2Sdanielk1977   Tcl_Interp *interp,
91751e3d8e2Sdanielk1977   int objc,
91851e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
91951e3d8e2Sdanielk1977 ){
92051e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
92151e3d8e2Sdanielk1977   int idx;
92251e3d8e2Sdanielk1977   i64 value;
92351e3d8e2Sdanielk1977   int rc;
92451e3d8e2Sdanielk1977 
92551e3d8e2Sdanielk1977   if( objc!=4 ){
92651e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
92751e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
92851e3d8e2Sdanielk1977     return TCL_ERROR;
92951e3d8e2Sdanielk1977   }
93051e3d8e2Sdanielk1977 
93151e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
93251e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
93351e3d8e2Sdanielk1977   if( Tcl_GetWideIntFromObj(interp, objv[3], &value) ) return TCL_ERROR;
93451e3d8e2Sdanielk1977 
93551e3d8e2Sdanielk1977   rc = sqlite3_bind_int64(pStmt, idx, value);
93651e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
93751e3d8e2Sdanielk1977     return TCL_ERROR;
93851e3d8e2Sdanielk1977   }
93951e3d8e2Sdanielk1977 
94051e3d8e2Sdanielk1977   return TCL_OK;
94151e3d8e2Sdanielk1977 }
94251e3d8e2Sdanielk1977 
94351e3d8e2Sdanielk1977 static int test_bind_double(
94451e3d8e2Sdanielk1977   void * clientData,
94551e3d8e2Sdanielk1977   Tcl_Interp *interp,
94651e3d8e2Sdanielk1977   int objc,
94751e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
94851e3d8e2Sdanielk1977 ){
94951e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
95051e3d8e2Sdanielk1977   int idx;
95151e3d8e2Sdanielk1977   double value;
95251e3d8e2Sdanielk1977   int rc;
95351e3d8e2Sdanielk1977 
95451e3d8e2Sdanielk1977   if( objc!=4 ){
95551e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
95651e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
95751e3d8e2Sdanielk1977     return TCL_ERROR;
95851e3d8e2Sdanielk1977   }
95951e3d8e2Sdanielk1977 
96051e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
96151e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
96251e3d8e2Sdanielk1977   if( Tcl_GetDoubleFromObj(interp, objv[3], &value) ) return TCL_ERROR;
96351e3d8e2Sdanielk1977 
96451e3d8e2Sdanielk1977   rc = sqlite3_bind_double(pStmt, idx, value);
96551e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
96651e3d8e2Sdanielk1977     return TCL_ERROR;
96751e3d8e2Sdanielk1977   }
96851e3d8e2Sdanielk1977 
96951e3d8e2Sdanielk1977   return TCL_OK;
97051e3d8e2Sdanielk1977 }
97151e3d8e2Sdanielk1977 
97251e3d8e2Sdanielk1977 static int test_bind_null(
97351e3d8e2Sdanielk1977   void * clientData,
97451e3d8e2Sdanielk1977   Tcl_Interp *interp,
97551e3d8e2Sdanielk1977   int objc,
97651e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
97751e3d8e2Sdanielk1977 ){
97851e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
97951e3d8e2Sdanielk1977   int idx;
98051e3d8e2Sdanielk1977   int rc;
98151e3d8e2Sdanielk1977 
98251e3d8e2Sdanielk1977   if( objc!=3 ){
98351e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
98451e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.>", 0);
98551e3d8e2Sdanielk1977     return TCL_ERROR;
98651e3d8e2Sdanielk1977   }
98751e3d8e2Sdanielk1977 
98851e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
98951e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
99051e3d8e2Sdanielk1977 
99151e3d8e2Sdanielk1977   rc = sqlite3_bind_null(pStmt, idx);
99251e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
99351e3d8e2Sdanielk1977     return TCL_ERROR;
99451e3d8e2Sdanielk1977   }
99551e3d8e2Sdanielk1977 
99651e3d8e2Sdanielk1977   return TCL_OK;
99751e3d8e2Sdanielk1977 }
99851e3d8e2Sdanielk1977 
99951e3d8e2Sdanielk1977 static int test_bind_text(
100051e3d8e2Sdanielk1977   void * clientData,
100151e3d8e2Sdanielk1977   Tcl_Interp *interp,
100251e3d8e2Sdanielk1977   int objc,
100351e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
100451e3d8e2Sdanielk1977 ){
100551e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
100651e3d8e2Sdanielk1977   int idx;
100751e3d8e2Sdanielk1977   int bytes;
100851e3d8e2Sdanielk1977   char *value;
100951e3d8e2Sdanielk1977   int rc;
101051e3d8e2Sdanielk1977 
101151e3d8e2Sdanielk1977   if( objc!=5 ){
101251e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
101351e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
101451e3d8e2Sdanielk1977         " <bytes>", 0);
101551e3d8e2Sdanielk1977     return TCL_ERROR;
101651e3d8e2Sdanielk1977   }
101751e3d8e2Sdanielk1977 
101851e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
101951e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
102051e3d8e2Sdanielk1977   value = Tcl_GetString(objv[3]);
102151e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
102251e3d8e2Sdanielk1977 
102351e3d8e2Sdanielk1977   rc = sqlite3_bind_text(pStmt, idx, value, bytes, 1);
102451e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
102551e3d8e2Sdanielk1977     return TCL_ERROR;
102651e3d8e2Sdanielk1977   }
102751e3d8e2Sdanielk1977 
102851e3d8e2Sdanielk1977   return TCL_OK;
102951e3d8e2Sdanielk1977 }
103051e3d8e2Sdanielk1977 
103151e3d8e2Sdanielk1977 static int test_bind_text16(
103251e3d8e2Sdanielk1977   void * clientData,
103351e3d8e2Sdanielk1977   Tcl_Interp *interp,
103451e3d8e2Sdanielk1977   int objc,
103551e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
103651e3d8e2Sdanielk1977 ){
103751e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
103851e3d8e2Sdanielk1977   int idx;
103951e3d8e2Sdanielk1977   int bytes;
104051e3d8e2Sdanielk1977   char *value;
104151e3d8e2Sdanielk1977   int rc;
104251e3d8e2Sdanielk1977 
104351e3d8e2Sdanielk1977   if( objc!=5 ){
104451e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
104551e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
104651e3d8e2Sdanielk1977         " <bytes>", 0);
104751e3d8e2Sdanielk1977     return TCL_ERROR;
104851e3d8e2Sdanielk1977   }
104951e3d8e2Sdanielk1977 
105051e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
105151e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
105251e3d8e2Sdanielk1977   value = Tcl_GetByteArrayFromObj(objv[3], 0);
105351e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
105451e3d8e2Sdanielk1977 
105551e3d8e2Sdanielk1977   rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, 1);
105651e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
105751e3d8e2Sdanielk1977     return TCL_ERROR;
105851e3d8e2Sdanielk1977   }
105951e3d8e2Sdanielk1977 
106051e3d8e2Sdanielk1977   return TCL_OK;
106151e3d8e2Sdanielk1977 }
106251e3d8e2Sdanielk1977 
106351e3d8e2Sdanielk1977 static int test_bind_blob(
106451e3d8e2Sdanielk1977   void * clientData,
106551e3d8e2Sdanielk1977   Tcl_Interp *interp,
106651e3d8e2Sdanielk1977   int objc,
106751e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
106851e3d8e2Sdanielk1977 ){
106951e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
107051e3d8e2Sdanielk1977   int idx;
107151e3d8e2Sdanielk1977   int bytes;
107251e3d8e2Sdanielk1977   char *value;
107351e3d8e2Sdanielk1977   int rc;
107451e3d8e2Sdanielk1977 
107551e3d8e2Sdanielk1977   if( objc!=5 ){
107651e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
107751e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
107851e3d8e2Sdanielk1977         " <bytes>", 0);
107951e3d8e2Sdanielk1977     return TCL_ERROR;
108051e3d8e2Sdanielk1977   }
108151e3d8e2Sdanielk1977 
108251e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
108351e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
108451e3d8e2Sdanielk1977   value = Tcl_GetString(objv[3]);
108549e4643eSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
108651e3d8e2Sdanielk1977 
108751e3d8e2Sdanielk1977   rc = sqlite3_bind_blob(pStmt, idx, value, bytes, 1);
108851e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
108951e3d8e2Sdanielk1977     return TCL_ERROR;
109051e3d8e2Sdanielk1977   }
109151e3d8e2Sdanielk1977 
109251e3d8e2Sdanielk1977   return TCL_OK;
109351e3d8e2Sdanielk1977 }
109451e3d8e2Sdanielk1977 
109599ee3600Sdrh /*
10966622cce3Sdanielk1977 ** Usage: sqlite3_errcode DB
10976622cce3Sdanielk1977 **
10986622cce3Sdanielk1977 ** Return the string representation of the most recent sqlite3_* API
10996622cce3Sdanielk1977 ** error code. e.g. "SQLITE_ERROR".
11006622cce3Sdanielk1977 */
11016622cce3Sdanielk1977 static int test_errcode(
11026622cce3Sdanielk1977   void * clientData,
11036622cce3Sdanielk1977   Tcl_Interp *interp,
11046622cce3Sdanielk1977   int objc,
11056622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
11066622cce3Sdanielk1977 ){
11076622cce3Sdanielk1977   sqlite3 *db;
11086622cce3Sdanielk1977 
11096622cce3Sdanielk1977   if( objc!=2 ){
11106622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
11116622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
11126622cce3Sdanielk1977     return TCL_ERROR;
11136622cce3Sdanielk1977   }
11146622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
11156622cce3Sdanielk1977   Tcl_SetResult(interp, (char *)errorName(sqlite3_errcode(db)), 0);
11166622cce3Sdanielk1977   return TCL_OK;
11176622cce3Sdanielk1977 }
11186622cce3Sdanielk1977 
11196622cce3Sdanielk1977 /*
11206622cce3Sdanielk1977 ** Usage:   test_errmsg DB
11216622cce3Sdanielk1977 **
11226622cce3Sdanielk1977 ** Returns the UTF-8 representation of the error message string for the
11236622cce3Sdanielk1977 ** most recent sqlite3_* API call.
11246622cce3Sdanielk1977 */
11256622cce3Sdanielk1977 static int test_errmsg(
11266622cce3Sdanielk1977   void * clientData,
11276622cce3Sdanielk1977   Tcl_Interp *interp,
11286622cce3Sdanielk1977   int objc,
11296622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
11306622cce3Sdanielk1977 ){
11316622cce3Sdanielk1977   sqlite *db;
11326622cce3Sdanielk1977   const char *zErr;
11336622cce3Sdanielk1977 
11346622cce3Sdanielk1977   if( objc!=2 ){
11356622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
11366622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
11376622cce3Sdanielk1977     return TCL_ERROR;
11386622cce3Sdanielk1977   }
11396622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
11406622cce3Sdanielk1977 
11416622cce3Sdanielk1977   zErr = sqlite3_errmsg(db);
11426622cce3Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
11436622cce3Sdanielk1977   return TCL_OK;
11446622cce3Sdanielk1977 }
11456622cce3Sdanielk1977 
11466622cce3Sdanielk1977 /*
11476622cce3Sdanielk1977 ** Usage:   test_errmsg16 DB
11486622cce3Sdanielk1977 **
11496622cce3Sdanielk1977 ** Returns the UTF-16 representation of the error message string for the
11506622cce3Sdanielk1977 ** most recent sqlite3_* API call. This is a byte array object at the TCL
11516622cce3Sdanielk1977 ** level, and it includes the 0x00 0x00 terminator bytes at the end of the
11526622cce3Sdanielk1977 ** UTF-16 string.
11536622cce3Sdanielk1977 */
11546622cce3Sdanielk1977 static int test_errmsg16(
11556622cce3Sdanielk1977   void * clientData,
11566622cce3Sdanielk1977   Tcl_Interp *interp,
11576622cce3Sdanielk1977   int objc,
11586622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
11596622cce3Sdanielk1977 ){
11606622cce3Sdanielk1977   sqlite *db;
11616622cce3Sdanielk1977   const void *zErr;
11626622cce3Sdanielk1977   int bytes;
11636622cce3Sdanielk1977 
11646622cce3Sdanielk1977   if( objc!=2 ){
11656622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
11666622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
11676622cce3Sdanielk1977     return TCL_ERROR;
11686622cce3Sdanielk1977   }
11696622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
11706622cce3Sdanielk1977 
11716622cce3Sdanielk1977   zErr = sqlite3_errmsg16(db);
11726622cce3Sdanielk1977   bytes = sqlite3utf16ByteLen(zErr, -1);
11736622cce3Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes));
11746622cce3Sdanielk1977   return TCL_OK;
11756622cce3Sdanielk1977 }
11766622cce3Sdanielk1977 
11776622cce3Sdanielk1977 /*
11786622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar
11796622cce3Sdanielk1977 **
11806622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
11816622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global
11826622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A
11836622cce3Sdanielk1977 ** STMT handle is returned.
11846622cce3Sdanielk1977 */
11856622cce3Sdanielk1977 static int test_prepare(
11866622cce3Sdanielk1977   void * clientData,
11876622cce3Sdanielk1977   Tcl_Interp *interp,
11886622cce3Sdanielk1977   int objc,
11896622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
11906622cce3Sdanielk1977 ){
11916622cce3Sdanielk1977   sqlite3 *db;
11926622cce3Sdanielk1977   const char *zSql;
11936622cce3Sdanielk1977   int bytes;
11946622cce3Sdanielk1977   const char *zTail = 0;
11956622cce3Sdanielk1977   sqlite3_stmt *pStmt = 0;
11966622cce3Sdanielk1977   char zBuf[50];
11974ad1713cSdanielk1977   int rc;
11986622cce3Sdanielk1977 
11996622cce3Sdanielk1977   if( objc!=5 ){
12006622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
12016622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
12026622cce3Sdanielk1977     return TCL_ERROR;
12036622cce3Sdanielk1977   }
12046622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
12056622cce3Sdanielk1977   zSql = Tcl_GetString(objv[2]);
12066622cce3Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
12076622cce3Sdanielk1977 
12084ad1713cSdanielk1977   rc = sqlite3_prepare(db, zSql, bytes, &pStmt, &zTail);
12096622cce3Sdanielk1977   if( zTail ){
12106622cce3Sdanielk1977     if( bytes>=0 ){
12116622cce3Sdanielk1977       bytes = bytes - (zTail-zSql);
12126622cce3Sdanielk1977     }
12136622cce3Sdanielk1977     Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
12146622cce3Sdanielk1977   }
12154ad1713cSdanielk1977   if( rc!=SQLITE_OK ){
12164ad1713cSdanielk1977     assert( pStmt==0 );
12174ad1713cSdanielk1977     sprintf(zBuf, "(%d) ", rc);
12184ad1713cSdanielk1977     Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
12194ad1713cSdanielk1977     return TCL_ERROR;
12204ad1713cSdanielk1977   }
12216622cce3Sdanielk1977 
12224ad1713cSdanielk1977   if( pStmt ){
12236622cce3Sdanielk1977     if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
12246622cce3Sdanielk1977     Tcl_AppendResult(interp, zBuf, 0);
12254ad1713cSdanielk1977   }
12266622cce3Sdanielk1977   return TCL_OK;
12276622cce3Sdanielk1977 }
12286622cce3Sdanielk1977 
12296622cce3Sdanielk1977 /*
12306622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar
12316622cce3Sdanielk1977 **
12326622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
12336622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global
12346622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A
12356622cce3Sdanielk1977 ** STMT handle is returned.
12366622cce3Sdanielk1977 */
12376622cce3Sdanielk1977 static int test_prepare16(
12386622cce3Sdanielk1977   void * clientData,
12396622cce3Sdanielk1977   Tcl_Interp *interp,
12406622cce3Sdanielk1977   int objc,
12416622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
12426622cce3Sdanielk1977 ){
12436622cce3Sdanielk1977   sqlite3 *db;
12446622cce3Sdanielk1977   const void *zSql;
12456622cce3Sdanielk1977   const void *zTail = 0;
12466622cce3Sdanielk1977   Tcl_Obj *pTail = 0;
12476622cce3Sdanielk1977   sqlite3_stmt *pStmt = 0;
12486622cce3Sdanielk1977   char zBuf[50];
12496622cce3Sdanielk1977   int bytes;                /* The integer specified as arg 3 */
12506622cce3Sdanielk1977   int objlen;               /* The byte-array length of arg 2 */
12516622cce3Sdanielk1977 
12526622cce3Sdanielk1977   if( objc!=5 ){
12536622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
12546622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
12556622cce3Sdanielk1977     return TCL_ERROR;
12566622cce3Sdanielk1977   }
12576622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
12586622cce3Sdanielk1977   zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen);
12596622cce3Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
12606622cce3Sdanielk1977 
12616622cce3Sdanielk1977   if( SQLITE_OK!=sqlite3_prepare16(db, zSql, bytes, &pStmt, &zTail) ){
12626622cce3Sdanielk1977     return TCL_ERROR;
12636622cce3Sdanielk1977   }
12646622cce3Sdanielk1977 
12656622cce3Sdanielk1977   if( zTail ){
12666622cce3Sdanielk1977     objlen = objlen - ((u8 *)zTail-(u8 *)zSql);
12676622cce3Sdanielk1977   }else{
12686622cce3Sdanielk1977     objlen = 0;
12696622cce3Sdanielk1977   }
12706622cce3Sdanielk1977   pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen);
12716622cce3Sdanielk1977   Tcl_IncrRefCount(pTail);
12726622cce3Sdanielk1977   Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0);
12734ad1713cSdanielk1977   Tcl_DecrRefCount(pTail);
12746622cce3Sdanielk1977 
12754ad1713cSdanielk1977   if( pStmt ){
12766622cce3Sdanielk1977     if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
12774ad1713cSdanielk1977   }
12786622cce3Sdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
12796622cce3Sdanielk1977   return TCL_OK;
12806622cce3Sdanielk1977 }
12816622cce3Sdanielk1977 
12824ad1713cSdanielk1977 /*
12834ad1713cSdanielk1977 ** Usage: sqlite3_open filename ?options-list?
12844ad1713cSdanielk1977 */
12854ad1713cSdanielk1977 static int test_open(
12864ad1713cSdanielk1977   void * clientData,
12874ad1713cSdanielk1977   Tcl_Interp *interp,
12884ad1713cSdanielk1977   int objc,
12894ad1713cSdanielk1977   Tcl_Obj *CONST objv[]
12904ad1713cSdanielk1977 ){
12914ad1713cSdanielk1977   const char *zFilename;
12924ad1713cSdanielk1977   sqlite3 *db;
12934ad1713cSdanielk1977   int rc;
12944ad1713cSdanielk1977   char zBuf[100];
12954ad1713cSdanielk1977 
12964ad1713cSdanielk1977   if( objc!=3 && objc!=2 ){
12974ad1713cSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
12984ad1713cSdanielk1977        Tcl_GetString(objv[0]), " filename options-list", 0);
12994ad1713cSdanielk1977     return TCL_ERROR;
13004ad1713cSdanielk1977   }
13014ad1713cSdanielk1977 
13024ad1713cSdanielk1977   zFilename = Tcl_GetString(objv[1]);
13034f057f90Sdanielk1977   rc = sqlite3_open(zFilename, &db);
13044ad1713cSdanielk1977 
13054ad1713cSdanielk1977   if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
13064ad1713cSdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
13074ad1713cSdanielk1977   return TCL_OK;
13084ad1713cSdanielk1977 }
13094ad1713cSdanielk1977 
13104ad1713cSdanielk1977 /*
13114ad1713cSdanielk1977 ** Usage: sqlite3_open16 filename options
13124ad1713cSdanielk1977 */
13134ad1713cSdanielk1977 static int test_open16(
13144ad1713cSdanielk1977   void * clientData,
13154ad1713cSdanielk1977   Tcl_Interp *interp,
13164ad1713cSdanielk1977   int objc,
13174ad1713cSdanielk1977   Tcl_Obj *CONST objv[]
13184ad1713cSdanielk1977 ){
13194ad1713cSdanielk1977   const void *zFilename;
13204ad1713cSdanielk1977   sqlite3 *db;
13214ad1713cSdanielk1977   int rc;
13224ad1713cSdanielk1977   char zBuf[100];
13234ad1713cSdanielk1977 
13244ad1713cSdanielk1977   if( objc!=3 ){
13254ad1713cSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
13264ad1713cSdanielk1977        Tcl_GetString(objv[0]), " filename options-list", 0);
13274ad1713cSdanielk1977     return TCL_ERROR;
13284ad1713cSdanielk1977   }
13294ad1713cSdanielk1977 
13304ad1713cSdanielk1977   zFilename = Tcl_GetByteArrayFromObj(objv[1], 0);
13314f057f90Sdanielk1977   rc = sqlite3_open16(zFilename, &db);
13324ad1713cSdanielk1977 
13334ad1713cSdanielk1977   if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
13344ad1713cSdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
13354ad1713cSdanielk1977   return TCL_OK;
13364ad1713cSdanielk1977 }
1337d3d39e93Sdrh 
1338d3d39e93Sdrh /*
1339106bb236Sdanielk1977 ** Usage: sqlite3_step STMT
1340106bb236Sdanielk1977 **
1341106bb236Sdanielk1977 ** Advance the statement to the next row.
1342106bb236Sdanielk1977 */
134317240fd9Sdanielk1977 static int test_step(
1344106bb236Sdanielk1977   void * clientData,
1345106bb236Sdanielk1977   Tcl_Interp *interp,
1346106bb236Sdanielk1977   int objc,
1347106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
1348106bb236Sdanielk1977 ){
1349106bb236Sdanielk1977   sqlite3_stmt *pStmt;
1350106bb236Sdanielk1977   int rc;
1351106bb236Sdanielk1977 
1352e1cd9874Sdanielk1977   if( objc!=2 ){
1353106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1354106bb236Sdanielk1977        Tcl_GetString(objv[0]), " STMT", 0);
1355106bb236Sdanielk1977     return TCL_ERROR;
1356106bb236Sdanielk1977   }
1357106bb236Sdanielk1977 
1358106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
135917240fd9Sdanielk1977   rc = sqlite3_step(pStmt);
1360106bb236Sdanielk1977 
1361e1cd9874Sdanielk1977   if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR;
13626590493dSdanielk1977   Tcl_SetResult(interp, (char *)errorName(rc), 0);
1363e1cd9874Sdanielk1977   return TCL_OK;
1364e1cd9874Sdanielk1977 }
1365e1cd9874Sdanielk1977 
1366e1cd9874Sdanielk1977 /*
136717240fd9Sdanielk1977 ** Usage: sqlite3_column_count STMT
136817240fd9Sdanielk1977 **
136917240fd9Sdanielk1977 ** Return the number of columns returned by the sql statement STMT.
137017240fd9Sdanielk1977 */
137117240fd9Sdanielk1977 static int test_column_count(
137217240fd9Sdanielk1977   void * clientData,
137317240fd9Sdanielk1977   Tcl_Interp *interp,
137417240fd9Sdanielk1977   int objc,
137517240fd9Sdanielk1977   Tcl_Obj *CONST objv[]
137617240fd9Sdanielk1977 ){
137717240fd9Sdanielk1977   sqlite3_stmt *pStmt;
137817240fd9Sdanielk1977 
137917240fd9Sdanielk1977   if( objc!=2 ){
138017240fd9Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
138117240fd9Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
138217240fd9Sdanielk1977     return TCL_ERROR;
138317240fd9Sdanielk1977   }
138417240fd9Sdanielk1977 
138517240fd9Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
138617240fd9Sdanielk1977 
138717240fd9Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_column_count(pStmt)));
138817240fd9Sdanielk1977   return TCL_OK;
138917240fd9Sdanielk1977 }
139017240fd9Sdanielk1977 
139117240fd9Sdanielk1977 /*
13923cf86063Sdanielk1977 ** Usage: sqlite3_column_type STMT column
13933cf86063Sdanielk1977 **
13943cf86063Sdanielk1977 ** Return the type of the data in column 'column' of the current row.
13953cf86063Sdanielk1977 */
13963cf86063Sdanielk1977 static int test_column_type(
13973cf86063Sdanielk1977   void * clientData,
13983cf86063Sdanielk1977   Tcl_Interp *interp,
13993cf86063Sdanielk1977   int objc,
14003cf86063Sdanielk1977   Tcl_Obj *CONST objv[]
14013cf86063Sdanielk1977 ){
14023cf86063Sdanielk1977   sqlite3_stmt *pStmt;
14033cf86063Sdanielk1977   int col;
14043cf86063Sdanielk1977   int tp;
14053cf86063Sdanielk1977 
14063cf86063Sdanielk1977   if( objc!=3 ){
14073cf86063Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
14083cf86063Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
14093cf86063Sdanielk1977     return TCL_ERROR;
14103cf86063Sdanielk1977   }
14113cf86063Sdanielk1977 
14123cf86063Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
14133cf86063Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
14143cf86063Sdanielk1977 
14153cf86063Sdanielk1977   tp = sqlite3_column_type(pStmt, col);
14163cf86063Sdanielk1977   switch( tp ){
14179c054830Sdrh     case SQLITE_INTEGER:
14183cf86063Sdanielk1977       Tcl_SetResult(interp, "INTEGER", TCL_STATIC);
14193cf86063Sdanielk1977       break;
14209c054830Sdrh     case SQLITE_NULL:
14213cf86063Sdanielk1977       Tcl_SetResult(interp, "NULL", TCL_STATIC);
14223cf86063Sdanielk1977       break;
14239c054830Sdrh     case SQLITE_FLOAT:
14243cf86063Sdanielk1977       Tcl_SetResult(interp, "FLOAT", TCL_STATIC);
14253cf86063Sdanielk1977       break;
14269c054830Sdrh     case SQLITE_TEXT:
14273cf86063Sdanielk1977       Tcl_SetResult(interp, "TEXT", TCL_STATIC);
14283cf86063Sdanielk1977       break;
14299c054830Sdrh     case SQLITE_BLOB:
14303cf86063Sdanielk1977       Tcl_SetResult(interp, "BLOB", TCL_STATIC);
14313cf86063Sdanielk1977       break;
14323cf86063Sdanielk1977     default:
14333cf86063Sdanielk1977       assert(0);
14343cf86063Sdanielk1977   }
14353cf86063Sdanielk1977 
14363cf86063Sdanielk1977   return TCL_OK;
14373cf86063Sdanielk1977 }
14383cf86063Sdanielk1977 
14393cf86063Sdanielk1977 /*
144004f2e68dSdanielk1977 ** Usage: sqlite3_column_int64 STMT column
14413cf86063Sdanielk1977 **
14423cf86063Sdanielk1977 ** Return the data in column 'column' of the current row cast as an
144304f2e68dSdanielk1977 ** wide (64-bit) integer.
14443cf86063Sdanielk1977 */
144504f2e68dSdanielk1977 static int test_column_int64(
14463cf86063Sdanielk1977   void * clientData,
14473cf86063Sdanielk1977   Tcl_Interp *interp,
14483cf86063Sdanielk1977   int objc,
14493cf86063Sdanielk1977   Tcl_Obj *CONST objv[]
14503cf86063Sdanielk1977 ){
14513cf86063Sdanielk1977   sqlite3_stmt *pStmt;
14523cf86063Sdanielk1977   int col;
145304f2e68dSdanielk1977   i64 iVal;
14543cf86063Sdanielk1977 
14553cf86063Sdanielk1977   if( objc!=3 ){
14563cf86063Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
14573cf86063Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
14583cf86063Sdanielk1977     return TCL_ERROR;
14593cf86063Sdanielk1977   }
14603cf86063Sdanielk1977 
14613cf86063Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
14623cf86063Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
14633cf86063Sdanielk1977 
146404f2e68dSdanielk1977   iVal = sqlite3_column_int64(pStmt, col);
146504f2e68dSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(iVal));
146604f2e68dSdanielk1977   return TCL_OK;
146704f2e68dSdanielk1977 }
146804f2e68dSdanielk1977 
146904f2e68dSdanielk1977 /*
1470ea61b2c4Sdanielk1977 ** Usage: sqlite3_column_blob STMT column
1471ea61b2c4Sdanielk1977 */
1472ea61b2c4Sdanielk1977 static int test_column_blob(
1473ea61b2c4Sdanielk1977   void * clientData,
1474ea61b2c4Sdanielk1977   Tcl_Interp *interp,
1475ea61b2c4Sdanielk1977   int objc,
1476ea61b2c4Sdanielk1977   Tcl_Obj *CONST objv[]
1477ea61b2c4Sdanielk1977 ){
1478ea61b2c4Sdanielk1977   sqlite3_stmt *pStmt;
1479ea61b2c4Sdanielk1977   int col;
1480ea61b2c4Sdanielk1977 
1481ea61b2c4Sdanielk1977   int len;
1482c572ef7fSdanielk1977   const void *pBlob;
1483ea61b2c4Sdanielk1977 
1484ea61b2c4Sdanielk1977   if( objc!=3 ){
1485ea61b2c4Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1486ea61b2c4Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
1487ea61b2c4Sdanielk1977     return TCL_ERROR;
1488ea61b2c4Sdanielk1977   }
1489ea61b2c4Sdanielk1977 
1490ea61b2c4Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
1491ea61b2c4Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
1492ea61b2c4Sdanielk1977 
1493ea61b2c4Sdanielk1977   pBlob = sqlite3_column_blob(pStmt, col);
1494ea61b2c4Sdanielk1977   len = sqlite3_column_bytes(pStmt, col);
1495ea61b2c4Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pBlob, len));
1496ea61b2c4Sdanielk1977   return TCL_OK;
1497ea61b2c4Sdanielk1977 }
1498ea61b2c4Sdanielk1977 
1499ea61b2c4Sdanielk1977 /*
150004f2e68dSdanielk1977 ** Usage: sqlite3_column_double STMT column
150104f2e68dSdanielk1977 **
150204f2e68dSdanielk1977 ** Return the data in column 'column' of the current row cast as a double.
150304f2e68dSdanielk1977 */
150404f2e68dSdanielk1977 static int test_column_double(
150504f2e68dSdanielk1977   void * clientData,
150604f2e68dSdanielk1977   Tcl_Interp *interp,
150704f2e68dSdanielk1977   int objc,
150804f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
150904f2e68dSdanielk1977 ){
151004f2e68dSdanielk1977   sqlite3_stmt *pStmt;
151104f2e68dSdanielk1977   int col;
151204f2e68dSdanielk1977   double rVal;
151304f2e68dSdanielk1977 
151404f2e68dSdanielk1977   if( objc!=3 ){
151504f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
151604f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
151704f2e68dSdanielk1977     return TCL_ERROR;
151804f2e68dSdanielk1977   }
151904f2e68dSdanielk1977 
152004f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
152104f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
152204f2e68dSdanielk1977 
152304f2e68dSdanielk1977   rVal = sqlite3_column_double(pStmt, col);
1524c572ef7fSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewDoubleObj(rVal));
15253cf86063Sdanielk1977   return TCL_OK;
15263cf86063Sdanielk1977 }
15273cf86063Sdanielk1977 
15283cf86063Sdanielk1977 /*
152917240fd9Sdanielk1977 ** Usage: sqlite3_data_count STMT
153017240fd9Sdanielk1977 **
153117240fd9Sdanielk1977 ** Return the number of columns returned by the sql statement STMT.
153217240fd9Sdanielk1977 */
153317240fd9Sdanielk1977 static int test_data_count(
153417240fd9Sdanielk1977   void * clientData,
153517240fd9Sdanielk1977   Tcl_Interp *interp,
153617240fd9Sdanielk1977   int objc,
153717240fd9Sdanielk1977   Tcl_Obj *CONST objv[]
153817240fd9Sdanielk1977 ){
153917240fd9Sdanielk1977   sqlite3_stmt *pStmt;
154017240fd9Sdanielk1977 
154117240fd9Sdanielk1977   if( objc!=2 ){
154217240fd9Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
154317240fd9Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
154417240fd9Sdanielk1977     return TCL_ERROR;
154517240fd9Sdanielk1977   }
154617240fd9Sdanielk1977 
154717240fd9Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
154817240fd9Sdanielk1977 
154917240fd9Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_data_count(pStmt)));
155017240fd9Sdanielk1977   return TCL_OK;
155117240fd9Sdanielk1977 }
155217240fd9Sdanielk1977 
155317240fd9Sdanielk1977 /*
155404f2e68dSdanielk1977 ** Usage: sqlite3_column_text STMT column
155504f2e68dSdanielk1977 **
155604f2e68dSdanielk1977 ** Usage: sqlite3_column_decltype STMT column
155704f2e68dSdanielk1977 **
155804f2e68dSdanielk1977 ** Usage: sqlite3_column_name STMT column
155904f2e68dSdanielk1977 */
156004f2e68dSdanielk1977 static int test_stmt_utf8(
156104f2e68dSdanielk1977   void * clientData,
156204f2e68dSdanielk1977   Tcl_Interp *interp,
156304f2e68dSdanielk1977   int objc,
156404f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
156504f2e68dSdanielk1977 ){
156604f2e68dSdanielk1977   sqlite3_stmt *pStmt;
156704f2e68dSdanielk1977   int col;
1568c572ef7fSdanielk1977   const char *(*xFunc)(sqlite3_stmt*, int) = clientData;
1569f93bbbeaSdanielk1977   const char *zRet;
157004f2e68dSdanielk1977 
157104f2e68dSdanielk1977   if( objc!=3 ){
157204f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
157304f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
157404f2e68dSdanielk1977     return TCL_ERROR;
157504f2e68dSdanielk1977   }
157604f2e68dSdanielk1977 
157704f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
157804f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
1579f93bbbeaSdanielk1977   zRet = xFunc(pStmt, col);
1580f93bbbeaSdanielk1977   if( zRet ){
1581f93bbbeaSdanielk1977     Tcl_SetResult(interp, (char *)zRet, 0);
1582f93bbbeaSdanielk1977   }
158304f2e68dSdanielk1977   return TCL_OK;
158404f2e68dSdanielk1977 }
158504f2e68dSdanielk1977 
158604f2e68dSdanielk1977 /*
158704f2e68dSdanielk1977 ** Usage: sqlite3_column_text STMT column
158804f2e68dSdanielk1977 **
158904f2e68dSdanielk1977 ** Usage: sqlite3_column_decltype STMT column
159004f2e68dSdanielk1977 **
159104f2e68dSdanielk1977 ** Usage: sqlite3_column_name STMT column
159204f2e68dSdanielk1977 */
159304f2e68dSdanielk1977 static int test_stmt_utf16(
159404f2e68dSdanielk1977   void * clientData,
159504f2e68dSdanielk1977   Tcl_Interp *interp,
159604f2e68dSdanielk1977   int objc,
159704f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
159804f2e68dSdanielk1977 ){
159904f2e68dSdanielk1977   sqlite3_stmt *pStmt;
160004f2e68dSdanielk1977   int col;
160104f2e68dSdanielk1977   Tcl_Obj *pRet;
160204f2e68dSdanielk1977   const void *zName16;
1603c572ef7fSdanielk1977   const void *(*xFunc)(sqlite3_stmt*, int) = clientData;
160404f2e68dSdanielk1977 
160504f2e68dSdanielk1977   if( objc!=3 ){
160604f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
160704f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
160804f2e68dSdanielk1977     return TCL_ERROR;
160904f2e68dSdanielk1977   }
161004f2e68dSdanielk1977 
161104f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
161204f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
161304f2e68dSdanielk1977 
161404f2e68dSdanielk1977   zName16 = xFunc(pStmt, col);
1615f93bbbeaSdanielk1977   if( zName16 ){
161604f2e68dSdanielk1977     pRet = Tcl_NewByteArrayObj(zName16, sqlite3utf16ByteLen(zName16, -1)+2);
161704f2e68dSdanielk1977     Tcl_SetObjResult(interp, pRet);
1618f93bbbeaSdanielk1977   }
161904f2e68dSdanielk1977 
162004f2e68dSdanielk1977   return TCL_OK;
162104f2e68dSdanielk1977 }
162204f2e68dSdanielk1977 
162304f2e68dSdanielk1977 /*
162404f2e68dSdanielk1977 ** Usage: sqlite3_column_int STMT column
162504f2e68dSdanielk1977 **
162604f2e68dSdanielk1977 ** Usage: sqlite3_column_bytes STMT column
162704f2e68dSdanielk1977 **
162804f2e68dSdanielk1977 ** Usage: sqlite3_column_bytes16 STMT column
162904f2e68dSdanielk1977 **
163004f2e68dSdanielk1977 */
163104f2e68dSdanielk1977 static int test_stmt_int(
163204f2e68dSdanielk1977   void * clientData,
163304f2e68dSdanielk1977   Tcl_Interp *interp,
163404f2e68dSdanielk1977   int objc,
163504f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
163604f2e68dSdanielk1977 ){
163704f2e68dSdanielk1977   sqlite3_stmt *pStmt;
163804f2e68dSdanielk1977   int col;
1639c572ef7fSdanielk1977   int (*xFunc)(sqlite3_stmt*, int) = clientData;
164004f2e68dSdanielk1977 
164104f2e68dSdanielk1977   if( objc!=3 ){
164204f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
164304f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
164404f2e68dSdanielk1977     return TCL_ERROR;
164504f2e68dSdanielk1977   }
164604f2e68dSdanielk1977 
164704f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
164804f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
164904f2e68dSdanielk1977 
165004f2e68dSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(xFunc(pStmt, col)));
165104f2e68dSdanielk1977   return TCL_OK;
165204f2e68dSdanielk1977 }
165304f2e68dSdanielk1977 
16549a1d0abeSdanielk1977 /*
16559a1d0abeSdanielk1977 ** Usage:  sqlite3OsOpenReadWrite <filename>
16569a1d0abeSdanielk1977 */
16579a1d0abeSdanielk1977 static int test_sqlite3OsOpenReadWrite(
16589a1d0abeSdanielk1977   void * clientData,
16599a1d0abeSdanielk1977   Tcl_Interp *interp,
16609a1d0abeSdanielk1977   int objc,
16619a1d0abeSdanielk1977   Tcl_Obj *CONST objv[]
16629a1d0abeSdanielk1977 ){
16639a1d0abeSdanielk1977   OsFile * pFile;
16649a1d0abeSdanielk1977   int rc;
16659a1d0abeSdanielk1977   int dummy;
16669a1d0abeSdanielk1977   char zBuf[100];
166704f2e68dSdanielk1977 
16689a1d0abeSdanielk1977   if( objc!=2 ){
16699a1d0abeSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
16709a1d0abeSdanielk1977        Tcl_GetString(objv[0]), " filename", 0);
16719a1d0abeSdanielk1977     return TCL_ERROR;
16729a1d0abeSdanielk1977   }
16739a1d0abeSdanielk1977 
16749a1d0abeSdanielk1977   pFile = sqliteMalloc(sizeof(OsFile));
16759a1d0abeSdanielk1977   rc = sqlite3OsOpenReadWrite(Tcl_GetString(objv[1]), pFile, &dummy);
16769a1d0abeSdanielk1977   if( rc!=SQLITE_OK ){
16779a1d0abeSdanielk1977     sqliteFree(pFile);
16789a1d0abeSdanielk1977     Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
16799a1d0abeSdanielk1977     return TCL_ERROR;
16809a1d0abeSdanielk1977   }
16819a1d0abeSdanielk1977   makePointerStr(interp, zBuf, pFile);
16829a1d0abeSdanielk1977   Tcl_SetResult(interp, zBuf, 0);
16839a1d0abeSdanielk1977   return TCL_ERROR;
16849a1d0abeSdanielk1977 }
16859a1d0abeSdanielk1977 
16869a1d0abeSdanielk1977 /*
16879a1d0abeSdanielk1977 ** Usage:  sqlite3OsClose <file handle>
16889a1d0abeSdanielk1977 */
16899a1d0abeSdanielk1977 static int test_sqlite3OsClose(
16909a1d0abeSdanielk1977   void * clientData,
16919a1d0abeSdanielk1977   Tcl_Interp *interp,
16929a1d0abeSdanielk1977   int objc,
16939a1d0abeSdanielk1977   Tcl_Obj *CONST objv[]
16949a1d0abeSdanielk1977 ){
16959a1d0abeSdanielk1977   OsFile * pFile;
16969a1d0abeSdanielk1977   int rc;
16979a1d0abeSdanielk1977 
16989a1d0abeSdanielk1977   if( objc!=2 ){
16999a1d0abeSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
17009a1d0abeSdanielk1977        Tcl_GetString(objv[0]), " filehandle", 0);
17019a1d0abeSdanielk1977     return TCL_ERROR;
17029a1d0abeSdanielk1977   }
17039a1d0abeSdanielk1977 
17049a1d0abeSdanielk1977   if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
17059a1d0abeSdanielk1977     return TCL_ERROR;
17069a1d0abeSdanielk1977   }
17079a1d0abeSdanielk1977   rc = sqlite3OsClose(pFile);
17089a1d0abeSdanielk1977   if( rc!=SQLITE_OK ){
17099a1d0abeSdanielk1977     Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
17109a1d0abeSdanielk1977     return TCL_ERROR;
17119a1d0abeSdanielk1977   }
17129a1d0abeSdanielk1977   sqliteFree(pFile);
17139a1d0abeSdanielk1977   return TCL_OK;
17149a1d0abeSdanielk1977 }
17159a1d0abeSdanielk1977 
17169a1d0abeSdanielk1977 /*
17179a1d0abeSdanielk1977 ** Usage:  sqlite3OsLock <file handle> <locktype>
17189a1d0abeSdanielk1977 */
17199a1d0abeSdanielk1977 static int test_sqlite3OsLock(
17209a1d0abeSdanielk1977   void * clientData,
17219a1d0abeSdanielk1977   Tcl_Interp *interp,
17229a1d0abeSdanielk1977   int objc,
17239a1d0abeSdanielk1977   Tcl_Obj *CONST objv[]
17249a1d0abeSdanielk1977 ){
17259a1d0abeSdanielk1977   OsFile * pFile;
17269a1d0abeSdanielk1977   int rc;
17279a1d0abeSdanielk1977 
17289a1d0abeSdanielk1977   if( objc!=3 ){
17299a1d0abeSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
17309a1d0abeSdanielk1977         Tcl_GetString(objv[0]),
17319a1d0abeSdanielk1977         " filehandle (SHARED|RESERVED|PENDING|EXCLUSIVE)", 0);
17329a1d0abeSdanielk1977     return TCL_ERROR;
17339a1d0abeSdanielk1977   }
17349a1d0abeSdanielk1977 
17359a1d0abeSdanielk1977   if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
17369a1d0abeSdanielk1977     return TCL_ERROR;
17379a1d0abeSdanielk1977   }
17389a1d0abeSdanielk1977 
17399a1d0abeSdanielk1977   if( 0==strcmp("SHARED", Tcl_GetString(objv[2])) ){
17409a1d0abeSdanielk1977     rc = sqlite3OsLock(pFile, SHARED_LOCK);
17419a1d0abeSdanielk1977   }
17429a1d0abeSdanielk1977   else if( 0==strcmp("RESERVED", Tcl_GetString(objv[2])) ){
17439a1d0abeSdanielk1977     rc = sqlite3OsLock(pFile, RESERVED_LOCK);
17449a1d0abeSdanielk1977   }
17459a1d0abeSdanielk1977   else if( 0==strcmp("PENDING", Tcl_GetString(objv[2])) ){
17469a1d0abeSdanielk1977     rc = sqlite3OsLock(pFile, PENDING_LOCK);
17479a1d0abeSdanielk1977   }
17489a1d0abeSdanielk1977   else if( 0==strcmp("EXCLUSIVE", Tcl_GetString(objv[2])) ){
17499a1d0abeSdanielk1977     rc = sqlite3OsLock(pFile, EXCLUSIVE_LOCK);
17509a1d0abeSdanielk1977   }else{
17519a1d0abeSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
17529a1d0abeSdanielk1977         Tcl_GetString(objv[0]),
17539a1d0abeSdanielk1977         " filehandle (SHARED|RESERVED|PENDING|EXCLUSIVE)", 0);
17549a1d0abeSdanielk1977     return TCL_ERROR;
17559a1d0abeSdanielk1977   }
17569a1d0abeSdanielk1977 
17579a1d0abeSdanielk1977   if( rc!=SQLITE_OK ){
17589a1d0abeSdanielk1977     Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
17599a1d0abeSdanielk1977     return TCL_ERROR;
17609a1d0abeSdanielk1977   }
17619a1d0abeSdanielk1977   return TCL_OK;
17629a1d0abeSdanielk1977 }
17639a1d0abeSdanielk1977 
17649a1d0abeSdanielk1977 /*
17659a1d0abeSdanielk1977 ** Usage:  sqlite3OsUnlock <file handle>
17669a1d0abeSdanielk1977 */
17679a1d0abeSdanielk1977 static int test_sqlite3OsUnlock(
17689a1d0abeSdanielk1977   void * clientData,
17699a1d0abeSdanielk1977   Tcl_Interp *interp,
17709a1d0abeSdanielk1977   int objc,
17719a1d0abeSdanielk1977   Tcl_Obj *CONST objv[]
17729a1d0abeSdanielk1977 ){
17739a1d0abeSdanielk1977   OsFile * pFile;
17749a1d0abeSdanielk1977   int rc;
17759a1d0abeSdanielk1977 
17769a1d0abeSdanielk1977   if( objc!=2 ){
17779a1d0abeSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
17789a1d0abeSdanielk1977        Tcl_GetString(objv[0]), " filehandle", 0);
17799a1d0abeSdanielk1977     return TCL_ERROR;
17809a1d0abeSdanielk1977   }
17819a1d0abeSdanielk1977 
17829a1d0abeSdanielk1977   if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
17839a1d0abeSdanielk1977     return TCL_ERROR;
17849a1d0abeSdanielk1977   }
17859a1d0abeSdanielk1977   rc = sqlite3OsUnlock(pFile);
17869a1d0abeSdanielk1977   if( rc!=SQLITE_OK ){
17879a1d0abeSdanielk1977     Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
17889a1d0abeSdanielk1977     return TCL_ERROR;
17899a1d0abeSdanielk1977   }
17909a1d0abeSdanielk1977   return TCL_OK;
17919a1d0abeSdanielk1977 }
1792d3d39e93Sdrh 
17936622cce3Sdanielk1977 /*
1794d1bf3512Sdrh ** Register commands with the TCL interpreter.
1795d1bf3512Sdrh */
1796d1bf3512Sdrh int Sqlitetest1_Init(Tcl_Interp *interp){
17976f8a503dSdanielk1977   extern int sqlite3_search_count;
17986f8a503dSdanielk1977   extern int sqlite3_interrupt_count;
17996f8a503dSdanielk1977   extern int sqlite3_open_file_count;
18006f8a503dSdanielk1977   extern int sqlite3_current_time;
1801c2eef3b3Sdrh   static struct {
1802c2eef3b3Sdrh      char *zName;
1803c2eef3b3Sdrh      Tcl_CmdProc *xProc;
1804c2eef3b3Sdrh   } aCmd[] = {
18056f8a503dSdanielk1977      { "sqlite3_mprintf_int",           (Tcl_CmdProc*)sqlite3_mprintf_int    },
18066f8a503dSdanielk1977      { "sqlite3_mprintf_str",           (Tcl_CmdProc*)sqlite3_mprintf_str    },
18076f8a503dSdanielk1977      { "sqlite3_mprintf_double",        (Tcl_CmdProc*)sqlite3_mprintf_double },
18086f8a503dSdanielk1977      { "sqlite3_mprintf_scaled",        (Tcl_CmdProc*)sqlite3_mprintf_scaled },
18096f8a503dSdanielk1977      { "sqlite3_mprintf_z_test",        (Tcl_CmdProc*)test_mprintf_z        },
18106f8a503dSdanielk1977      { "sqlite3_last_insert_rowid",     (Tcl_CmdProc*)test_last_rowid       },
18116f8a503dSdanielk1977      { "sqlite3_exec_printf",           (Tcl_CmdProc*)test_exec_printf      },
18126f8a503dSdanielk1977      { "sqlite3_get_table_printf",      (Tcl_CmdProc*)test_get_table_printf },
18136f8a503dSdanielk1977      { "sqlite3_close",                 (Tcl_CmdProc*)sqlite_test_close     },
18146f8a503dSdanielk1977      { "sqlite3_create_function",       (Tcl_CmdProc*)test_create_function  },
18156f8a503dSdanielk1977      { "sqlite3_create_aggregate",      (Tcl_CmdProc*)test_create_aggregate },
1816c2eef3b3Sdrh      { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func    },
1817c2eef3b3Sdrh      { "sqlite_abort",                  (Tcl_CmdProc*)sqlite_abort          },
1818*faa57accSdrh #ifdef SQLITE_DEBUG
1819c2eef3b3Sdrh      { "sqlite_malloc_fail",            (Tcl_CmdProc*)sqlite_malloc_fail    },
1820c2eef3b3Sdrh      { "sqlite_malloc_stat",            (Tcl_CmdProc*)sqlite_malloc_stat    },
1821c2eef3b3Sdrh #endif
182296fc5fe6Sdanielk1977      { "sqlite_bind",                    (Tcl_CmdProc*)test_bind             },
182399ee3600Sdrh      { "breakpoint",                     (Tcl_CmdProc*)test_breakpoint       },
1824c2eef3b3Sdrh   };
182551e3d8e2Sdanielk1977   static struct {
182651e3d8e2Sdanielk1977      char *zName;
182751e3d8e2Sdanielk1977      Tcl_ObjCmdProc *xProc;
182804f2e68dSdanielk1977      void *clientData;
182951e3d8e2Sdanielk1977   } aObjCmd[] = {
183004f2e68dSdanielk1977      { "sqlite3_bind_int32",            test_bind_int32, 0    },
183104f2e68dSdanielk1977      { "sqlite3_bind_int64",            test_bind_int64 , 0   },
183204f2e68dSdanielk1977      { "sqlite3_bind_double",           test_bind_double, 0   },
183304f2e68dSdanielk1977      { "sqlite3_bind_null",             test_bind_null     ,0 },
183404f2e68dSdanielk1977      { "sqlite3_bind_text",             test_bind_text     ,0 },
183504f2e68dSdanielk1977      { "sqlite3_bind_text16",           test_bind_text16   ,0 },
183604f2e68dSdanielk1977      { "sqlite3_bind_blob",             test_bind_blob     ,0 },
183704f2e68dSdanielk1977      { "sqlite3_errcode",               test_errcode       ,0 },
183804f2e68dSdanielk1977      { "sqlite3_errmsg",                test_errmsg        ,0 },
183904f2e68dSdanielk1977      { "sqlite3_errmsg16",              test_errmsg16      ,0 },
184004f2e68dSdanielk1977      { "sqlite3_open",                  test_open          ,0 },
184104f2e68dSdanielk1977      { "sqlite3_open16",                test_open16        ,0 },
184204f2e68dSdanielk1977 
184304f2e68dSdanielk1977      { "sqlite3_prepare",               test_prepare       ,0 },
184404f2e68dSdanielk1977      { "sqlite3_prepare16",             test_prepare16     ,0 },
184504f2e68dSdanielk1977      { "sqlite3_finalize",              test_finalize      ,0 },
184604f2e68dSdanielk1977      { "sqlite3_reset",                 test_reset         ,0 },
184704f2e68dSdanielk1977      { "sqlite3_step",                  test_step,0 },
184804f2e68dSdanielk1977 
184904f2e68dSdanielk1977      /* sqlite3_column_*() API */
185004f2e68dSdanielk1977      { "sqlite3_column_count",          test_column_count  ,0 },
185104f2e68dSdanielk1977      { "sqlite3_data_count",            test_data_count    ,0 },
185204f2e68dSdanielk1977      { "sqlite3_column_type",           test_column_type   ,0 },
1853ea61b2c4Sdanielk1977      { "sqlite3_column_blob",           test_column_blob   ,0 },
185404f2e68dSdanielk1977      { "sqlite3_column_double",         test_column_double ,0 },
185504f2e68dSdanielk1977      { "sqlite3_column_int64",          test_column_int64  ,0 },
185604f2e68dSdanielk1977      { "sqlite3_column_int", test_stmt_int ,sqlite3_column_int },
185704f2e68dSdanielk1977      { "sqlite3_column_bytes", test_stmt_int ,sqlite3_column_bytes },
185804f2e68dSdanielk1977      { "sqlite3_column_bytes16", test_stmt_int ,sqlite3_column_bytes16 },
185904f2e68dSdanielk1977      { "sqlite3_column_text", test_stmt_utf8,       sqlite3_column_text},
186004f2e68dSdanielk1977      { "sqlite3_column_decltype", test_stmt_utf8,   sqlite3_column_decltype},
186104f2e68dSdanielk1977      { "sqlite3_column_name", test_stmt_utf8,       sqlite3_column_name},
186204f2e68dSdanielk1977      { "sqlite3_column_text16", test_stmt_utf16,    sqlite3_column_text16},
186304f2e68dSdanielk1977      { "sqlite3_column_decltype16", test_stmt_utf16,sqlite3_column_decltype16},
186404f2e68dSdanielk1977      { "sqlite3_column_name16", test_stmt_utf16,    sqlite3_column_name16},
186504f2e68dSdanielk1977 
18669a1d0abeSdanielk1977      /* Functions from os.h */
18679a1d0abeSdanielk1977      { "sqlite3OsOpenReadWrite",test_sqlite3OsOpenReadWrite, 0 },
18689a1d0abeSdanielk1977      { "sqlite3OsClose",        test_sqlite3OsClose, 0 },
18699a1d0abeSdanielk1977      { "sqlite3OsLock",         test_sqlite3OsLock, 0 },
18709a1d0abeSdanielk1977      { "sqlite3OsUnlock",       test_sqlite3OsUnlock, 0 },
18719a1d0abeSdanielk1977 
187251e3d8e2Sdanielk1977   };
1873c2eef3b3Sdrh   int i;
18742ac3ee97Sdrh   extern int sqlite3_os_trace;
1875c2eef3b3Sdrh 
1876c2eef3b3Sdrh   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
1877c2eef3b3Sdrh     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
1878c2eef3b3Sdrh   }
187951e3d8e2Sdanielk1977   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
1880c572ef7fSdanielk1977     Tcl_CreateObjCommand(interp, aObjCmd[i].zName,
1881c572ef7fSdanielk1977         aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
188251e3d8e2Sdanielk1977   }
18836490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_search_count",
18846f8a503dSdanielk1977       (char*)&sqlite3_search_count, TCL_LINK_INT);
18856490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_interrupt_count",
18866f8a503dSdanielk1977       (char*)&sqlite3_interrupt_count, TCL_LINK_INT);
18876490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_open_file_count",
18886f8a503dSdanielk1977       (char*)&sqlite3_open_file_count, TCL_LINK_INT);
18896490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_current_time",
18906f8a503dSdanielk1977       (char*)&sqlite3_current_time, TCL_LINK_INT);
18912ac3ee97Sdrh   Tcl_LinkVar(interp, "sqlite_os_trace",
18922ac3ee97Sdrh       (char*)&sqlite3_os_trace, TCL_LINK_INT);
18937c972decSdrh   Tcl_LinkVar(interp, "sqlite_static_bind_value",
18947c972decSdrh       (char*)&sqlite_static_bind_value, TCL_LINK_STRING);
1895d1bf3512Sdrh   return TCL_OK;
1896d1bf3512Sdrh }
1897