xref: /sqlite-3.40.0/src/test1.c (revision 8a6c550d)
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*8a6c550dSdanielk1977 ** $Id: test1.c,v 1.81 2004/06/22 12:18:32 danielk1977 Exp $
17d1bf3512Sdrh */
18d1bf3512Sdrh #include "sqliteInt.h"
19d1bf3512Sdrh #include "tcl.h"
2094e92032Sdrh #include "os.h"
21d1bf3512Sdrh #include <stdlib.h>
22d1bf3512Sdrh #include <string.h>
23d1bf3512Sdrh 
2494e92032Sdrh #if OS_WIN
2594e92032Sdrh # define PTR_FMT "%x"
2694e92032Sdrh #else
2794e92032Sdrh # define PTR_FMT "%p"
2894e92032Sdrh #endif
2994e92032Sdrh 
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;
32696d81f99Sdanielk1977   int rc;
327d1bf3512Sdrh   if( argc!=2 ){
328d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
329d1bf3512Sdrh        " FILENAME\"", 0);
330d1bf3512Sdrh     return TCL_ERROR;
331d1bf3512Sdrh   }
332b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
33396d81f99Sdanielk1977   rc = sqlite3_close(db);
334f9d64d2cSdanielk1977   Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
335d1bf3512Sdrh   return TCL_OK;
336d1bf3512Sdrh }
337d1bf3512Sdrh 
338d1bf3512Sdrh /*
339c22bd47dSdrh ** Implementation of the x_coalesce() function.
340c22bd47dSdrh ** Return the first argument non-NULL argument.
341c22bd47dSdrh */
3420ae8b831Sdanielk1977 static void ifnullFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
343c22bd47dSdrh   int i;
344c22bd47dSdrh   for(i=0; i<argc; i++){
3459c054830Sdrh     if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){
346d8123366Sdanielk1977       sqlite3_result_text(context, sqlite3_value_text(argv[i]), -1,
347d8123366Sdanielk1977           SQLITE_TRANSIENT);
348c22bd47dSdrh       break;
349c22bd47dSdrh     }
350c22bd47dSdrh   }
351c22bd47dSdrh }
352c22bd47dSdrh 
353c22bd47dSdrh /*
354d1d9fc33Sdrh ** A structure into which to accumulate text.
355d1d9fc33Sdrh */
356d1d9fc33Sdrh struct dstr {
357d1d9fc33Sdrh   int nAlloc;  /* Space allocated */
358d1d9fc33Sdrh   int nUsed;   /* Space used */
359d1d9fc33Sdrh   char *z;     /* The space */
360d1d9fc33Sdrh };
361d1d9fc33Sdrh 
362d1d9fc33Sdrh /*
363d1d9fc33Sdrh ** Append text to a dstr
364d1d9fc33Sdrh */
365d1d9fc33Sdrh static void dstrAppend(struct dstr *p, const char *z, int divider){
366d1d9fc33Sdrh   int n = strlen(z);
367d1d9fc33Sdrh   if( p->nUsed + n + 2 > p->nAlloc ){
368d1d9fc33Sdrh     char *zNew;
369d1d9fc33Sdrh     p->nAlloc = p->nAlloc*2 + n + 200;
370d1d9fc33Sdrh     zNew = sqliteRealloc(p->z, p->nAlloc);
371d1d9fc33Sdrh     if( zNew==0 ){
372d1d9fc33Sdrh       sqliteFree(p->z);
373d1d9fc33Sdrh       memset(p, 0, sizeof(*p));
374d1d9fc33Sdrh       return;
375d1d9fc33Sdrh     }
376d1d9fc33Sdrh     p->z = zNew;
377d1d9fc33Sdrh   }
378d1d9fc33Sdrh   if( divider && p->nUsed>0 ){
379d1d9fc33Sdrh     p->z[p->nUsed++] = divider;
380d1d9fc33Sdrh   }
381d1d9fc33Sdrh   memcpy(&p->z[p->nUsed], z, n+1);
382d1d9fc33Sdrh   p->nUsed += n;
383d1d9fc33Sdrh }
384d1d9fc33Sdrh 
385d1d9fc33Sdrh /*
3864adee20fSdanielk1977 ** Invoked for each callback from sqlite3ExecFunc
387d1d9fc33Sdrh */
388d1d9fc33Sdrh static int execFuncCallback(void *pData, int argc, char **argv, char **NotUsed){
389d1d9fc33Sdrh   struct dstr *p = (struct dstr*)pData;
390d1d9fc33Sdrh   int i;
391d1d9fc33Sdrh   for(i=0; i<argc; i++){
392d1d9fc33Sdrh     if( argv[i]==0 ){
393d1d9fc33Sdrh       dstrAppend(p, "NULL", ' ');
394d1d9fc33Sdrh     }else{
395d1d9fc33Sdrh       dstrAppend(p, argv[i], ' ');
396d1d9fc33Sdrh     }
397d1d9fc33Sdrh   }
398d1d9fc33Sdrh   return 0;
399d1d9fc33Sdrh }
400d1d9fc33Sdrh 
401d1d9fc33Sdrh /*
4026f8a503dSdanielk1977 ** Implementation of the x_sqlite3_exec() function.  This function takes
403c22bd47dSdrh ** a single argument and attempts to execute that argument as SQL code.
4046cbe1f1bSdrh ** This is illegal and should set the SQLITE_MISUSE flag on the database.
405c22bd47dSdrh **
4066f8a503dSdanielk1977 ** 2004-Jan-07:  We have changed this to make it legal to call sqlite3_exec()
407d1d9fc33Sdrh ** from within a function call.
408d1d9fc33Sdrh **
409c22bd47dSdrh ** This routine simulates the effect of having two threads attempt to
410c22bd47dSdrh ** use the same database at the same time.
411c22bd47dSdrh */
41251ad0ecdSdanielk1977 static void sqlite3ExecFunc(
4130ae8b831Sdanielk1977   sqlite3_context *context,
41451ad0ecdSdanielk1977   int argc,
41551ad0ecdSdanielk1977   sqlite3_value **argv
41651ad0ecdSdanielk1977 ){
417d1d9fc33Sdrh   struct dstr x;
418d1d9fc33Sdrh   memset(&x, 0, sizeof(x));
41951ad0ecdSdanielk1977   sqlite3_exec((sqlite*)sqlite3_user_data(context),
4204f26d6c4Sdrh       sqlite3_value_text(argv[0]),
421d1d9fc33Sdrh       execFuncCallback, &x, 0);
422d8123366Sdanielk1977   sqlite3_result_text(context, x.z, x.nUsed, SQLITE_TRANSIENT);
423d1d9fc33Sdrh   sqliteFree(x.z);
424c22bd47dSdrh }
425c22bd47dSdrh 
426c22bd47dSdrh /*
427c22bd47dSdrh ** Usage:  sqlite_test_create_function DB
428c22bd47dSdrh **
4296f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order
430c22bd47dSdrh ** to create a function named "x_coalesce".  This function does the same thing
431c22bd47dSdrh ** as the "coalesce" function.  This function also registers an SQL function
4326f8a503dSdanielk1977 ** named "x_sqlite3_exec" that invokes sqlite3_exec().  Invoking sqlite3_exec()
433c22bd47dSdrh ** in this way is illegal recursion and should raise an SQLITE_MISUSE error.
434c22bd47dSdrh ** The effect is similar to trying to use the same database connection from
435c22bd47dSdrh ** two threads at the same time.
436c22bd47dSdrh **
437c22bd47dSdrh ** The original motivation for this routine was to be able to call the
4386f8a503dSdanielk1977 ** sqlite3_create_function function while a query is in progress in order
439c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
440c22bd47dSdrh */
441c2eef3b3Sdrh static int test_create_function(
442c22bd47dSdrh   void *NotUsed,
443c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
444c22bd47dSdrh   int argc,              /* Number of arguments */
445c22bd47dSdrh   char **argv            /* Text of each argument */
446c22bd47dSdrh ){
447c22bd47dSdrh   sqlite *db;
448c22bd47dSdrh   extern void Md5_Register(sqlite*);
449c22bd47dSdrh   if( argc!=2 ){
450c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
451c22bd47dSdrh        " FILENAME\"", 0);
452c22bd47dSdrh     return TCL_ERROR;
453c22bd47dSdrh   }
454b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
455f9d64d2cSdanielk1977   sqlite3_create_function(db, "x_coalesce", -1, SQLITE_UTF8, 0,
456d8123366Sdanielk1977       ifnullFunc, 0, 0);
457f9d64d2cSdanielk1977   sqlite3_create_function(db, "x_sqlite3_exec", 1, SQLITE_UTF8, db,
4586590493dSdanielk1977       sqlite3ExecFunc, 0, 0);
459c22bd47dSdrh   return TCL_OK;
460c22bd47dSdrh }
461c22bd47dSdrh 
462c22bd47dSdrh /*
463c22bd47dSdrh ** Routines to implement the x_count() aggregate function.
464c22bd47dSdrh */
465c22bd47dSdrh typedef struct CountCtx CountCtx;
466c22bd47dSdrh struct CountCtx {
467c22bd47dSdrh   int n;
468c22bd47dSdrh };
4690ae8b831Sdanielk1977 static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
470c22bd47dSdrh   CountCtx *p;
4714f26d6c4Sdrh   p = sqlite3_aggregate_context(context, sizeof(*p));
4729c054830Sdrh   if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0]) ) && p ){
473c22bd47dSdrh     p->n++;
474c22bd47dSdrh   }
475c22bd47dSdrh }
4760ae8b831Sdanielk1977 static void countFinalize(sqlite3_context *context){
477c22bd47dSdrh   CountCtx *p;
4784f26d6c4Sdrh   p = sqlite3_aggregate_context(context, sizeof(*p));
479c572ef7fSdanielk1977   sqlite3_result_int(context, p ? p->n : 0);
480c22bd47dSdrh }
481c22bd47dSdrh 
482c22bd47dSdrh /*
483c22bd47dSdrh ** Usage:  sqlite_test_create_aggregate DB
484c22bd47dSdrh **
4856f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order
486c22bd47dSdrh ** to create a function named "x_count".  This function does the same thing
487c22bd47dSdrh ** as the "md5sum" function.
488c22bd47dSdrh **
489c22bd47dSdrh ** The original motivation for this routine was to be able to call the
4906f8a503dSdanielk1977 ** sqlite3_create_aggregate function while a query is in progress in order
491c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
492c22bd47dSdrh */
493c2eef3b3Sdrh static int test_create_aggregate(
494c22bd47dSdrh   void *NotUsed,
495c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
496c22bd47dSdrh   int argc,              /* Number of arguments */
497c22bd47dSdrh   char **argv            /* Text of each argument */
498c22bd47dSdrh ){
499c22bd47dSdrh   sqlite *db;
500c22bd47dSdrh   if( argc!=2 ){
501c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
502c22bd47dSdrh        " FILENAME\"", 0);
503c22bd47dSdrh     return TCL_ERROR;
504c22bd47dSdrh   }
505b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
506f9d64d2cSdanielk1977   sqlite3_create_function(db, "x_count", 0, SQLITE_UTF8, 0, 0,
507d8123366Sdanielk1977       countStep,countFinalize);
508f9d64d2cSdanielk1977   sqlite3_create_function(db, "x_count", 1, SQLITE_UTF8, 0, 0,
509d8123366Sdanielk1977       countStep,countFinalize);
510c22bd47dSdrh   return TCL_OK;
511c22bd47dSdrh }
512c22bd47dSdrh 
513c22bd47dSdrh 
514c22bd47dSdrh 
515c22bd47dSdrh /*
5166f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER
517d1bf3512Sdrh **
518d1bf3512Sdrh ** Call mprintf with three integer arguments
519d1bf3512Sdrh */
5206f8a503dSdanielk1977 static int sqlite3_mprintf_int(
521d1bf3512Sdrh   void *NotUsed,
522d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
523d1bf3512Sdrh   int argc,              /* Number of arguments */
524d1bf3512Sdrh   char **argv            /* Text of each argument */
525d1bf3512Sdrh ){
526d1bf3512Sdrh   int a[3], i;
527d1bf3512Sdrh   char *z;
528d1bf3512Sdrh   if( argc!=5 ){
529d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
530d1bf3512Sdrh        " FORMAT INT INT INT\"", 0);
531d1bf3512Sdrh     return TCL_ERROR;
532d1bf3512Sdrh   }
533d1bf3512Sdrh   for(i=2; i<5; i++){
534d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
535d1bf3512Sdrh   }
5366f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]);
537d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
5383f4fedb2Sdrh   sqlite3_free(z);
539d1bf3512Sdrh   return TCL_OK;
540d1bf3512Sdrh }
541d1bf3512Sdrh 
542d1bf3512Sdrh /*
5436f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT INTEGER INTEGER STRING
544d1bf3512Sdrh **
545d1bf3512Sdrh ** Call mprintf with two integer arguments and one string argument
546d1bf3512Sdrh */
5476f8a503dSdanielk1977 static int sqlite3_mprintf_str(
548d1bf3512Sdrh   void *NotUsed,
549d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
550d1bf3512Sdrh   int argc,              /* Number of arguments */
551d1bf3512Sdrh   char **argv            /* Text of each argument */
552d1bf3512Sdrh ){
553d1bf3512Sdrh   int a[3], i;
554d1bf3512Sdrh   char *z;
555f220b24fSchw   if( argc<4 || argc>5 ){
556d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
557f220b24fSchw        " FORMAT INT INT ?STRING?\"", 0);
558d1bf3512Sdrh     return TCL_ERROR;
559d1bf3512Sdrh   }
560d1bf3512Sdrh   for(i=2; i<4; i++){
561d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
562d1bf3512Sdrh   }
5636f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL);
564d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
5653f4fedb2Sdrh   sqlite3_free(z);
566d1bf3512Sdrh   return TCL_OK;
567d1bf3512Sdrh }
568d1bf3512Sdrh 
569d1bf3512Sdrh /*
5706f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT INTEGER INTEGER DOUBLE
571d1bf3512Sdrh **
572d1bf3512Sdrh ** Call mprintf with two integer arguments and one double argument
573d1bf3512Sdrh */
5746f8a503dSdanielk1977 static int sqlite3_mprintf_double(
575d1bf3512Sdrh   void *NotUsed,
576d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
577d1bf3512Sdrh   int argc,              /* Number of arguments */
578d1bf3512Sdrh   char **argv            /* Text of each argument */
579d1bf3512Sdrh ){
580d1bf3512Sdrh   int a[3], i;
581d1bf3512Sdrh   double r;
582d1bf3512Sdrh   char *z;
583d1bf3512Sdrh   if( argc!=5 ){
584d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
585d1bf3512Sdrh        " FORMAT INT INT STRING\"", 0);
586d1bf3512Sdrh     return TCL_ERROR;
587d1bf3512Sdrh   }
588d1bf3512Sdrh   for(i=2; i<4; i++){
589d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
590d1bf3512Sdrh   }
591d1bf3512Sdrh   if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR;
5926f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], r);
593d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
5943f4fedb2Sdrh   sqlite3_free(z);
595d1bf3512Sdrh   return TCL_OK;
596d1bf3512Sdrh }
597d1bf3512Sdrh 
598d1bf3512Sdrh /*
5996f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT DOUBLE DOUBLE
600b621c237Sdrh **
601b621c237Sdrh ** Call mprintf with a single double argument which is the product of the
602b621c237Sdrh ** two arguments given above.  This is used to generate overflow and underflow
603b621c237Sdrh ** doubles to test that they are converted properly.
604b621c237Sdrh */
6056f8a503dSdanielk1977 static int sqlite3_mprintf_scaled(
606b621c237Sdrh   void *NotUsed,
607b621c237Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
608b621c237Sdrh   int argc,              /* Number of arguments */
609b621c237Sdrh   char **argv            /* Text of each argument */
610b621c237Sdrh ){
611b621c237Sdrh   int i;
612b621c237Sdrh   double r[2];
613b621c237Sdrh   char *z;
614b621c237Sdrh   if( argc!=4 ){
615b621c237Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
616b621c237Sdrh        " FORMAT DOUBLE DOUBLE\"", 0);
617b621c237Sdrh     return TCL_ERROR;
618b621c237Sdrh   }
619b621c237Sdrh   for(i=2; i<4; i++){
620b621c237Sdrh     if( Tcl_GetDouble(interp, argv[i], &r[i-2]) ) return TCL_ERROR;
621b621c237Sdrh   }
6226f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], r[0]*r[1]);
623b621c237Sdrh   Tcl_AppendResult(interp, z, 0);
6243f4fedb2Sdrh   sqlite3_free(z);
625b621c237Sdrh   return TCL_OK;
626b621c237Sdrh }
627b621c237Sdrh 
628b621c237Sdrh /*
629daffd0e5Sdrh ** Usage: sqlite_malloc_fail N
630daffd0e5Sdrh **
631afa4a020Sdrh ** Rig sqliteMalloc() to fail on the N-th call.  Turn off this mechanism
6326f8a503dSdanielk1977 ** and reset the sqlite3_malloc_failed variable is N==0.
633daffd0e5Sdrh */
634faa57accSdrh #ifdef SQLITE_DEBUG
635daffd0e5Sdrh static int sqlite_malloc_fail(
636daffd0e5Sdrh   void *NotUsed,
637daffd0e5Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
638daffd0e5Sdrh   int argc,              /* Number of arguments */
639daffd0e5Sdrh   char **argv            /* Text of each argument */
640daffd0e5Sdrh ){
641daffd0e5Sdrh   int n;
642daffd0e5Sdrh   if( argc!=2 ){
643daffd0e5Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0);
644daffd0e5Sdrh     return TCL_ERROR;
645daffd0e5Sdrh   }
646daffd0e5Sdrh   if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
6476f8a503dSdanielk1977   sqlite3_iMallocFail = n;
6486f8a503dSdanielk1977   sqlite3_malloc_failed = 0;
649daffd0e5Sdrh   return TCL_OK;
650daffd0e5Sdrh }
651daffd0e5Sdrh #endif
652daffd0e5Sdrh 
653daffd0e5Sdrh /*
654daffd0e5Sdrh ** Usage: sqlite_malloc_stat
655daffd0e5Sdrh **
656daffd0e5Sdrh ** Return the number of prior calls to sqliteMalloc() and sqliteFree().
657daffd0e5Sdrh */
658faa57accSdrh #ifdef SQLITE_DEBUG
659daffd0e5Sdrh static int sqlite_malloc_stat(
660daffd0e5Sdrh   void *NotUsed,
661daffd0e5Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
662daffd0e5Sdrh   int argc,              /* Number of arguments */
663daffd0e5Sdrh   char **argv            /* Text of each argument */
664daffd0e5Sdrh ){
665daffd0e5Sdrh   char zBuf[200];
6666f8a503dSdanielk1977   sprintf(zBuf, "%d %d %d", sqlite3_nMalloc, sqlite3_nFree, sqlite3_iMallocFail);
667daffd0e5Sdrh   Tcl_AppendResult(interp, zBuf, 0);
668daffd0e5Sdrh   return TCL_OK;
669daffd0e5Sdrh }
670daffd0e5Sdrh #endif
671daffd0e5Sdrh 
672daffd0e5Sdrh /*
67328b4e489Sdrh ** Usage:  sqlite_abort
67428b4e489Sdrh **
67528b4e489Sdrh ** Shutdown the process immediately.  This is not a clean shutdown.
67628b4e489Sdrh ** This command is used to test the recoverability of a database in
67728b4e489Sdrh ** the event of a program crash.
67828b4e489Sdrh */
67928b4e489Sdrh static int sqlite_abort(
68028b4e489Sdrh   void *NotUsed,
68128b4e489Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
68228b4e489Sdrh   int argc,              /* Number of arguments */
68328b4e489Sdrh   char **argv            /* Text of each argument */
68428b4e489Sdrh ){
68528b4e489Sdrh   assert( interp==0 );   /* This will always fail */
68628b4e489Sdrh   return TCL_OK;
68728b4e489Sdrh }
68828b4e489Sdrh 
68928b4e489Sdrh /*
6906cbe1f1bSdrh ** The following routine is a user-defined SQL function whose purpose
6916cbe1f1bSdrh ** is to test the sqlite_set_result() API.
6926cbe1f1bSdrh */
6930ae8b831Sdanielk1977 static void testFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
6946cbe1f1bSdrh   while( argc>=2 ){
6954f26d6c4Sdrh     const char *zArg0 = sqlite3_value_text(argv[0]);
6966d88bad4Sdanielk1977     if( zArg0 ){
6976d88bad4Sdanielk1977       if( 0==sqlite3StrICmp(zArg0, "int") ){
6986d88bad4Sdanielk1977         sqlite3_result_int(context, sqlite3_value_int(argv[1]));
6996d88bad4Sdanielk1977       }else if( sqlite3StrICmp(zArg0,"int64")==0 ){
7006d88bad4Sdanielk1977         sqlite3_result_int64(context, sqlite3_value_int64(argv[1]));
70151ad0ecdSdanielk1977       }else if( sqlite3StrICmp(zArg0,"string")==0 ){
702d8123366Sdanielk1977         sqlite3_result_text(context, sqlite3_value_text(argv[1]), -1,
703d8123366Sdanielk1977             SQLITE_TRANSIENT);
70451ad0ecdSdanielk1977       }else if( sqlite3StrICmp(zArg0,"double")==0 ){
7056d88bad4Sdanielk1977         sqlite3_result_double(context, sqlite3_value_double(argv[1]));
7066d88bad4Sdanielk1977       }else if( sqlite3StrICmp(zArg0,"null")==0 ){
7076d88bad4Sdanielk1977         sqlite3_result_null(context);
7086d88bad4Sdanielk1977       }else if( sqlite3StrICmp(zArg0,"value")==0 ){
7096d88bad4Sdanielk1977         sqlite3_result_value(context, argv[sqlite3_value_int(argv[1])]);
7106cbe1f1bSdrh       }else{
7116d88bad4Sdanielk1977         goto error_out;
7126d88bad4Sdanielk1977       }
7136d88bad4Sdanielk1977     }else{
7146d88bad4Sdanielk1977       goto error_out;
7156cbe1f1bSdrh     }
7166cbe1f1bSdrh     argc -= 2;
7176cbe1f1bSdrh     argv += 2;
7186cbe1f1bSdrh   }
7196d88bad4Sdanielk1977   return;
7206d88bad4Sdanielk1977 
7216d88bad4Sdanielk1977 error_out:
7226d88bad4Sdanielk1977   sqlite3_result_error(context,"first argument should be one of: "
7236d88bad4Sdanielk1977       "int int64 string double null value", -1);
7246cbe1f1bSdrh }
7256cbe1f1bSdrh 
7266cbe1f1bSdrh /*
7276cbe1f1bSdrh ** Usage:   sqlite_register_test_function  DB  NAME
7286cbe1f1bSdrh **
7296cbe1f1bSdrh ** Register the test SQL function on the database DB under the name NAME.
7306cbe1f1bSdrh */
731c2eef3b3Sdrh static int test_register_func(
7326cbe1f1bSdrh   void *NotUsed,
7336cbe1f1bSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
7346cbe1f1bSdrh   int argc,              /* Number of arguments */
7356cbe1f1bSdrh   char **argv            /* Text of each argument */
7366cbe1f1bSdrh ){
7376cbe1f1bSdrh   sqlite *db;
7386cbe1f1bSdrh   int rc;
7396cbe1f1bSdrh   if( argc!=3 ){
7406cbe1f1bSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
7416cbe1f1bSdrh        " DB FUNCTION-NAME", 0);
7426cbe1f1bSdrh     return TCL_ERROR;
7436cbe1f1bSdrh   }
744b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
745f9d64d2cSdanielk1977   rc = sqlite3_create_function(db, argv[2], -1, SQLITE_UTF8, 0,
746d8123366Sdanielk1977       testFunc, 0, 0);
7476cbe1f1bSdrh   if( rc!=0 ){
748f20b21c8Sdanielk1977     Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);
7496cbe1f1bSdrh     return TCL_ERROR;
7506cbe1f1bSdrh   }
7516cbe1f1bSdrh   return TCL_OK;
7526cbe1f1bSdrh }
7536cbe1f1bSdrh 
7546cbe1f1bSdrh /*
755106bb236Sdanielk1977 ** Usage:  sqlite3_finalize  STMT
756b86ccfb2Sdrh **
757106bb236Sdanielk1977 ** Finalize a statement handle.
758b86ccfb2Sdrh */
759b86ccfb2Sdrh static int test_finalize(
760106bb236Sdanielk1977   void * clientData,
761106bb236Sdanielk1977   Tcl_Interp *interp,
762106bb236Sdanielk1977   int objc,
763106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
764b86ccfb2Sdrh ){
765106bb236Sdanielk1977   sqlite3_stmt *pStmt;
766b86ccfb2Sdrh   int rc;
767106bb236Sdanielk1977 
768106bb236Sdanielk1977   if( objc!=2 ){
769106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
770106bb236Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
771b86ccfb2Sdrh     return TCL_ERROR;
772b86ccfb2Sdrh   }
773106bb236Sdanielk1977 
774106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
775106bb236Sdanielk1977 
776fc57d7bfSdanielk1977   rc = sqlite3_finalize(pStmt);
777b77f5dadSdanielk1977   Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
778106bb236Sdanielk1977   return TCL_OK;
779106bb236Sdanielk1977 }
780106bb236Sdanielk1977 
781106bb236Sdanielk1977 /*
782106bb236Sdanielk1977 ** Usage:  sqlite3_reset  STMT
783106bb236Sdanielk1977 **
784106bb236Sdanielk1977 ** Finalize a statement handle.
785106bb236Sdanielk1977 */
786106bb236Sdanielk1977 static int test_reset(
787106bb236Sdanielk1977   void * clientData,
788106bb236Sdanielk1977   Tcl_Interp *interp,
789106bb236Sdanielk1977   int objc,
790106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
791106bb236Sdanielk1977 ){
792106bb236Sdanielk1977   sqlite3_stmt *pStmt;
793106bb236Sdanielk1977   int rc;
794106bb236Sdanielk1977 
795106bb236Sdanielk1977   if( objc!=2 ){
796106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
797106bb236Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
798106bb236Sdanielk1977     return TCL_ERROR;
799106bb236Sdanielk1977   }
800106bb236Sdanielk1977 
801106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
802106bb236Sdanielk1977 
803fc57d7bfSdanielk1977   rc = sqlite3_reset(pStmt);
804106bb236Sdanielk1977   if( rc ){
805b86ccfb2Sdrh     return TCL_ERROR;
806b86ccfb2Sdrh   }
807b86ccfb2Sdrh   return TCL_OK;
808b86ccfb2Sdrh }
809b86ccfb2Sdrh 
8105a38705eSdrh /*
811fbcd585fSdanielk1977 ** Usage:  sqlite3_changes DB
81250457896Sdrh **
813fbcd585fSdanielk1977 ** Return the number of changes made to the database by the last SQL
814fbcd585fSdanielk1977 ** execution.
81550457896Sdrh */
816fbcd585fSdanielk1977 static int test_changes(
817fbcd585fSdanielk1977   void * clientData,
818fbcd585fSdanielk1977   Tcl_Interp *interp,
819fbcd585fSdanielk1977   int objc,
820fbcd585fSdanielk1977   Tcl_Obj *CONST objv[]
821fbcd585fSdanielk1977 ){
822fbcd585fSdanielk1977   sqlite3 *db;
823fbcd585fSdanielk1977   if( objc!=2 ){
824fbcd585fSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
825fbcd585fSdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
826fbcd585fSdanielk1977     return TCL_ERROR;
827fbcd585fSdanielk1977   }
828fbcd585fSdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
829fbcd585fSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_changes(db)));
830fbcd585fSdanielk1977   return TCL_OK;
831fbcd585fSdanielk1977 }
83250457896Sdrh 
83350457896Sdrh /*
8347c972decSdrh ** This is the "static_bind_value" that variables are bound to when
8356f8a503dSdanielk1977 ** the FLAG option of sqlite3_bind is "static"
83650457896Sdrh */
8377c972decSdrh static char *sqlite_static_bind_value = 0;
8387c972decSdrh 
8397c972decSdrh /*
8406f8a503dSdanielk1977 ** Usage:  sqlite3_bind  VM  IDX  VALUE  FLAGS
8417c972decSdrh **
8427c972decSdrh ** Sets the value of the IDX-th occurance of "?" in the original SQL
8437c972decSdrh ** string.  VALUE is the new value.  If FLAGS=="null" then VALUE is
8447c972decSdrh ** ignored and the value is set to NULL.  If FLAGS=="static" then
8457c972decSdrh ** the value is set to the value of a static variable named
8467c972decSdrh ** "sqlite_static_bind_value".  If FLAGS=="normal" then a copy
8477c972decSdrh ** of the VALUE is made.
8487c972decSdrh */
8497c972decSdrh static int test_bind(
85050457896Sdrh   void *NotUsed,
85150457896Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
85250457896Sdrh   int argc,              /* Number of arguments */
85350457896Sdrh   char **argv            /* Text of each argument */
85450457896Sdrh ){
855fc57d7bfSdanielk1977   sqlite3_stmt *pStmt;
85650457896Sdrh   int rc;
8577c972decSdrh   int idx;
8587c972decSdrh   if( argc!=5 ){
85950457896Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
8607c972decSdrh        " VM IDX VALUE (null|static|normal)\"", 0);
86150457896Sdrh     return TCL_ERROR;
86250457896Sdrh   }
863fc57d7bfSdanielk1977   if( getStmtPointer(interp, argv[1], &pStmt) ) return TCL_ERROR;
8647c972decSdrh   if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR;
8657c972decSdrh   if( strcmp(argv[4],"null")==0 ){
866fc57d7bfSdanielk1977     rc = sqlite3_bind_null(pStmt, idx);
8677c972decSdrh   }else if( strcmp(argv[4],"static")==0 ){
868fc57d7bfSdanielk1977     rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0);
8697c972decSdrh   }else if( strcmp(argv[4],"normal")==0 ){
870d8123366Sdanielk1977     rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, SQLITE_TRANSIENT);
8717c972decSdrh   }else{
8727c972decSdrh     Tcl_AppendResult(interp, "4th argument should be "
8737c972decSdrh         "\"null\" or \"static\" or \"normal\"", 0);
8747c972decSdrh     return TCL_ERROR;
8757c972decSdrh   }
87650457896Sdrh   if( rc ){
87750457896Sdrh     char zBuf[50];
87850457896Sdrh     sprintf(zBuf, "(%d) ", rc);
879f20b21c8Sdanielk1977     Tcl_AppendResult(interp, zBuf, sqlite3ErrStr(rc), 0);
88050457896Sdrh     return TCL_ERROR;
88150457896Sdrh   }
88250457896Sdrh   return TCL_OK;
88350457896Sdrh }
88450457896Sdrh 
8854e6af134Sdanielk1977 
8864e6af134Sdanielk1977 /*
8874e6af134Sdanielk1977 ** Usage: add_test_collate <db ptr> <utf8> <utf16le> <utf16be>
8884e6af134Sdanielk1977 **
8894e6af134Sdanielk1977 ** This function is used to test that SQLite selects the correct collation
8904e6af134Sdanielk1977 ** sequence callback when multiple versions (for different text encodings)
8914e6af134Sdanielk1977 ** are available.
8924e6af134Sdanielk1977 **
8934e6af134Sdanielk1977 ** Calling this routine registers the collation sequence "test_collate"
8944e6af134Sdanielk1977 ** with database handle <db>. The second argument must be a list of three
8954e6af134Sdanielk1977 ** boolean values. If the first is true, then a version of test_collate is
8964e6af134Sdanielk1977 ** registered for UTF-8, if the second is true, a version is registered for
8974e6af134Sdanielk1977 ** UTF-16le, if the third is true, a UTF-16be version is available.
8984e6af134Sdanielk1977 ** Previous versions of test_collate are deleted.
8994e6af134Sdanielk1977 **
9004e6af134Sdanielk1977 ** The collation sequence test_collate is implemented by calling the
9014e6af134Sdanielk1977 ** following TCL script:
9024e6af134Sdanielk1977 **
9034e6af134Sdanielk1977 **   "test_collate <enc> <lhs> <rhs>"
9044e6af134Sdanielk1977 **
9054e6af134Sdanielk1977 ** The <lhs> and <rhs> are the two values being compared, encoded in UTF-8.
9064e6af134Sdanielk1977 ** The <enc> parameter is the encoding of the collation function that
9074e6af134Sdanielk1977 ** SQLite selected to call. The TCL test script implements the
9084e6af134Sdanielk1977 ** "test_collate" proc.
9094e6af134Sdanielk1977 **
9104e6af134Sdanielk1977 ** Note that this will only work with one intepreter at a time, as the
9114e6af134Sdanielk1977 ** interp pointer to use when evaluating the TCL script is stored in
9124e6af134Sdanielk1977 ** pTestCollateInterp.
9134e6af134Sdanielk1977 */
9144e6af134Sdanielk1977 static Tcl_Interp* pTestCollateInterp;
9154e6af134Sdanielk1977 static int test_collate_func(
9164e6af134Sdanielk1977   void *pCtx,
9174e6af134Sdanielk1977   int nA, const void *zA,
9184e6af134Sdanielk1977   int nB, const void *zB
9194e6af134Sdanielk1977 ){
9204e6af134Sdanielk1977   Tcl_Interp *i = pTestCollateInterp;
9214e6af134Sdanielk1977   int encin = (int)pCtx;
9224e6af134Sdanielk1977   int res;
9234e6af134Sdanielk1977 
9244e6af134Sdanielk1977   sqlite3_value *pVal;
9254e6af134Sdanielk1977   Tcl_Obj *pX;
9264e6af134Sdanielk1977 
9274e6af134Sdanielk1977   pX = Tcl_NewStringObj("test_collate", -1);
9284e6af134Sdanielk1977   Tcl_IncrRefCount(pX);
9294e6af134Sdanielk1977 
9304e6af134Sdanielk1977   switch( encin ){
9314e6af134Sdanielk1977     case SQLITE_UTF8:
9324e6af134Sdanielk1977       Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-8",-1));
9334e6af134Sdanielk1977       break;
9344e6af134Sdanielk1977     case SQLITE_UTF16LE:
9354e6af134Sdanielk1977       Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-16LE",-1));
9364e6af134Sdanielk1977       break;
9374e6af134Sdanielk1977     case SQLITE_UTF16BE:
9384e6af134Sdanielk1977       Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-16BE",-1));
9394e6af134Sdanielk1977       break;
9404e6af134Sdanielk1977     default:
9414e6af134Sdanielk1977       assert(0);
9424e6af134Sdanielk1977   }
9434e6af134Sdanielk1977 
9444e6af134Sdanielk1977   pVal = sqlite3ValueNew();
945bfd6cce5Sdanielk1977   sqlite3ValueSetStr(pVal, nA, zA, encin, SQLITE_STATIC);
9464e6af134Sdanielk1977   Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj(sqlite3_value_text(pVal),-1));
947bfd6cce5Sdanielk1977   sqlite3ValueSetStr(pVal, nB, zB, encin, SQLITE_STATIC);
9484e6af134Sdanielk1977   Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj(sqlite3_value_text(pVal),-1));
9494e6af134Sdanielk1977   sqlite3ValueFree(pVal);
9504e6af134Sdanielk1977 
9514e6af134Sdanielk1977   Tcl_EvalObjEx(i, pX, 0);
9524e6af134Sdanielk1977   Tcl_DecrRefCount(pX);
9534e6af134Sdanielk1977   Tcl_GetIntFromObj(i, Tcl_GetObjResult(i), &res);
9544e6af134Sdanielk1977   return res;
9554e6af134Sdanielk1977 }
9564e6af134Sdanielk1977 static int test_collate(
9574e6af134Sdanielk1977   void * clientData,
9584e6af134Sdanielk1977   Tcl_Interp *interp,
9594e6af134Sdanielk1977   int objc,
9604e6af134Sdanielk1977   Tcl_Obj *CONST objv[]
9614e6af134Sdanielk1977 ){
9624e6af134Sdanielk1977   sqlite3 *db;
9634e6af134Sdanielk1977   int val;
9644e6af134Sdanielk1977 
9654e6af134Sdanielk1977   if( objc!=5 ) goto bad_args;
9664e6af134Sdanielk1977   pTestCollateInterp = interp;
9674e6af134Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
9684e6af134Sdanielk1977 
9694e6af134Sdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR;
9704e6af134Sdanielk1977   sqlite3_create_collation(db, "test_collate", SQLITE_UTF8,
9714e6af134Sdanielk1977         (void *)SQLITE_UTF8, val?test_collate_func:0);
9724e6af134Sdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &val) ) return TCL_ERROR;
9734e6af134Sdanielk1977   sqlite3_create_collation(db, "test_collate", SQLITE_UTF16LE,
9744e6af134Sdanielk1977         (void *)SQLITE_UTF16LE, val?test_collate_func:0);
9754e6af134Sdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[4], &val) ) return TCL_ERROR;
9764e6af134Sdanielk1977   sqlite3_create_collation(db, "test_collate", SQLITE_UTF16BE,
9774e6af134Sdanielk1977         (void *)SQLITE_UTF16BE, val?test_collate_func:0);
9784e6af134Sdanielk1977 
9794e6af134Sdanielk1977   return TCL_OK;
9804e6af134Sdanielk1977 
9814e6af134Sdanielk1977 bad_args:
9824e6af134Sdanielk1977   Tcl_AppendResult(interp, "wrong # args: should be \"",
9834e6af134Sdanielk1977       Tcl_GetStringFromObj(objv[0], 0), " <DB> <utf8> <utf16le> <utf16be>", 0);
9844e6af134Sdanielk1977   return TCL_ERROR;
9854e6af134Sdanielk1977 }
9864e6af134Sdanielk1977 
987*8a6c550dSdanielk1977 static int sqlite3_crashseed(
988*8a6c550dSdanielk1977   void * clientData,
989*8a6c550dSdanielk1977   Tcl_Interp *interp,
990*8a6c550dSdanielk1977   int objc,
991*8a6c550dSdanielk1977   Tcl_Obj *CONST objv[]
992*8a6c550dSdanielk1977 ){
993*8a6c550dSdanielk1977 #ifdef OS_TEST
994*8a6c550dSdanielk1977   int seed;
995*8a6c550dSdanielk1977   if( objc!=2 ) goto bad_args;
996*8a6c550dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &seed) ) return TCL_ERROR;
997*8a6c550dSdanielk1977   sqlite3SetCrashseed(seed);
998*8a6c550dSdanielk1977 #endif
999*8a6c550dSdanielk1977   return TCL_OK;
1000*8a6c550dSdanielk1977 
1001*8a6c550dSdanielk1977 bad_args:
1002*8a6c550dSdanielk1977   Tcl_AppendResult(interp, "wrong # args: should be \"",
1003*8a6c550dSdanielk1977       Tcl_GetStringFromObj(objv[0], 0), "<seed>", 0);
1004*8a6c550dSdanielk1977   return TCL_ERROR;
1005*8a6c550dSdanielk1977 }
1006*8a6c550dSdanielk1977 
1007*8a6c550dSdanielk1977 
100850457896Sdrh /*
100999ee3600Sdrh ** Usage:    breakpoint
101099ee3600Sdrh **
101199ee3600Sdrh ** This routine exists for one purpose - to provide a place to put a
101299ee3600Sdrh ** breakpoint with GDB that can be triggered using TCL code.  The use
101399ee3600Sdrh ** for this is when a particular test fails on (say) the 1485th iteration.
101499ee3600Sdrh ** In the TCL test script, we can add code like this:
101599ee3600Sdrh **
101699ee3600Sdrh **     if {$i==1485} breakpoint
101799ee3600Sdrh **
101899ee3600Sdrh ** Then run testfixture in the debugger and wait for the breakpoint to
101999ee3600Sdrh ** fire.  Then additional breakpoints can be set to trace down the bug.
102099ee3600Sdrh */
102199ee3600Sdrh static int test_breakpoint(
102299ee3600Sdrh   void *NotUsed,
102399ee3600Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
102499ee3600Sdrh   int argc,              /* Number of arguments */
102599ee3600Sdrh   char **argv            /* Text of each argument */
102699ee3600Sdrh ){
102799ee3600Sdrh   return TCL_OK;         /* Do nothing */
102899ee3600Sdrh }
102999ee3600Sdrh 
103051e3d8e2Sdanielk1977 static int test_bind_int32(
103151e3d8e2Sdanielk1977   void * clientData,
103251e3d8e2Sdanielk1977   Tcl_Interp *interp,
103351e3d8e2Sdanielk1977   int objc,
103451e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
103551e3d8e2Sdanielk1977 ){
103651e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
103751e3d8e2Sdanielk1977   int idx;
103851e3d8e2Sdanielk1977   int value;
103951e3d8e2Sdanielk1977   int rc;
104051e3d8e2Sdanielk1977 
104151e3d8e2Sdanielk1977   if( objc!=4 ){
104251e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
104351e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
104451e3d8e2Sdanielk1977     return TCL_ERROR;
104551e3d8e2Sdanielk1977   }
104651e3d8e2Sdanielk1977 
104751e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
104851e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
104951e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &value) ) return TCL_ERROR;
105051e3d8e2Sdanielk1977 
1051c572ef7fSdanielk1977   rc = sqlite3_bind_int(pStmt, idx, value);
105251e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
105351e3d8e2Sdanielk1977     return TCL_ERROR;
105451e3d8e2Sdanielk1977   }
105551e3d8e2Sdanielk1977 
105651e3d8e2Sdanielk1977   return TCL_OK;
105751e3d8e2Sdanielk1977 }
105851e3d8e2Sdanielk1977 
105951e3d8e2Sdanielk1977 static int test_bind_int64(
106051e3d8e2Sdanielk1977   void * clientData,
106151e3d8e2Sdanielk1977   Tcl_Interp *interp,
106251e3d8e2Sdanielk1977   int objc,
106351e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
106451e3d8e2Sdanielk1977 ){
106551e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
106651e3d8e2Sdanielk1977   int idx;
106751e3d8e2Sdanielk1977   i64 value;
106851e3d8e2Sdanielk1977   int rc;
106951e3d8e2Sdanielk1977 
107051e3d8e2Sdanielk1977   if( objc!=4 ){
107151e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
107251e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
107351e3d8e2Sdanielk1977     return TCL_ERROR;
107451e3d8e2Sdanielk1977   }
107551e3d8e2Sdanielk1977 
107651e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
107751e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
107851e3d8e2Sdanielk1977   if( Tcl_GetWideIntFromObj(interp, objv[3], &value) ) return TCL_ERROR;
107951e3d8e2Sdanielk1977 
108051e3d8e2Sdanielk1977   rc = sqlite3_bind_int64(pStmt, idx, value);
108151e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
108251e3d8e2Sdanielk1977     return TCL_ERROR;
108351e3d8e2Sdanielk1977   }
108451e3d8e2Sdanielk1977 
108551e3d8e2Sdanielk1977   return TCL_OK;
108651e3d8e2Sdanielk1977 }
108751e3d8e2Sdanielk1977 
108851e3d8e2Sdanielk1977 static int test_bind_double(
108951e3d8e2Sdanielk1977   void * clientData,
109051e3d8e2Sdanielk1977   Tcl_Interp *interp,
109151e3d8e2Sdanielk1977   int objc,
109251e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
109351e3d8e2Sdanielk1977 ){
109451e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
109551e3d8e2Sdanielk1977   int idx;
109651e3d8e2Sdanielk1977   double value;
109751e3d8e2Sdanielk1977   int rc;
109851e3d8e2Sdanielk1977 
109951e3d8e2Sdanielk1977   if( objc!=4 ){
110051e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
110151e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
110251e3d8e2Sdanielk1977     return TCL_ERROR;
110351e3d8e2Sdanielk1977   }
110451e3d8e2Sdanielk1977 
110551e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
110651e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
110751e3d8e2Sdanielk1977   if( Tcl_GetDoubleFromObj(interp, objv[3], &value) ) return TCL_ERROR;
110851e3d8e2Sdanielk1977 
110951e3d8e2Sdanielk1977   rc = sqlite3_bind_double(pStmt, idx, value);
111051e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
111151e3d8e2Sdanielk1977     return TCL_ERROR;
111251e3d8e2Sdanielk1977   }
111351e3d8e2Sdanielk1977 
111451e3d8e2Sdanielk1977   return TCL_OK;
111551e3d8e2Sdanielk1977 }
111651e3d8e2Sdanielk1977 
111751e3d8e2Sdanielk1977 static int test_bind_null(
111851e3d8e2Sdanielk1977   void * clientData,
111951e3d8e2Sdanielk1977   Tcl_Interp *interp,
112051e3d8e2Sdanielk1977   int objc,
112151e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
112251e3d8e2Sdanielk1977 ){
112351e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
112451e3d8e2Sdanielk1977   int idx;
112551e3d8e2Sdanielk1977   int rc;
112651e3d8e2Sdanielk1977 
112751e3d8e2Sdanielk1977   if( objc!=3 ){
112851e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
112951e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.>", 0);
113051e3d8e2Sdanielk1977     return TCL_ERROR;
113151e3d8e2Sdanielk1977   }
113251e3d8e2Sdanielk1977 
113351e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
113451e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
113551e3d8e2Sdanielk1977 
113651e3d8e2Sdanielk1977   rc = sqlite3_bind_null(pStmt, idx);
113751e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
113851e3d8e2Sdanielk1977     return TCL_ERROR;
113951e3d8e2Sdanielk1977   }
114051e3d8e2Sdanielk1977 
114151e3d8e2Sdanielk1977   return TCL_OK;
114251e3d8e2Sdanielk1977 }
114351e3d8e2Sdanielk1977 
114451e3d8e2Sdanielk1977 static int test_bind_text(
114551e3d8e2Sdanielk1977   void * clientData,
114651e3d8e2Sdanielk1977   Tcl_Interp *interp,
114751e3d8e2Sdanielk1977   int objc,
114851e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
114951e3d8e2Sdanielk1977 ){
115051e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
115151e3d8e2Sdanielk1977   int idx;
115251e3d8e2Sdanielk1977   int bytes;
115351e3d8e2Sdanielk1977   char *value;
115451e3d8e2Sdanielk1977   int rc;
115551e3d8e2Sdanielk1977 
115651e3d8e2Sdanielk1977   if( objc!=5 ){
115751e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
115851e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
115951e3d8e2Sdanielk1977         " <bytes>", 0);
116051e3d8e2Sdanielk1977     return TCL_ERROR;
116151e3d8e2Sdanielk1977   }
116251e3d8e2Sdanielk1977 
116351e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
116451e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
116551e3d8e2Sdanielk1977   value = Tcl_GetString(objv[3]);
116651e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
116751e3d8e2Sdanielk1977 
1168d8123366Sdanielk1977   rc = sqlite3_bind_text(pStmt, idx, value, bytes, SQLITE_TRANSIENT);
116951e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
117051e3d8e2Sdanielk1977     return TCL_ERROR;
117151e3d8e2Sdanielk1977   }
117251e3d8e2Sdanielk1977 
117351e3d8e2Sdanielk1977   return TCL_OK;
117451e3d8e2Sdanielk1977 }
117551e3d8e2Sdanielk1977 
117651e3d8e2Sdanielk1977 static int test_bind_text16(
117751e3d8e2Sdanielk1977   void * clientData,
117851e3d8e2Sdanielk1977   Tcl_Interp *interp,
117951e3d8e2Sdanielk1977   int objc,
118051e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
118151e3d8e2Sdanielk1977 ){
118251e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
118351e3d8e2Sdanielk1977   int idx;
118451e3d8e2Sdanielk1977   int bytes;
118551e3d8e2Sdanielk1977   char *value;
118651e3d8e2Sdanielk1977   int rc;
118751e3d8e2Sdanielk1977 
118851e3d8e2Sdanielk1977   if( objc!=5 ){
118951e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
119051e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
119151e3d8e2Sdanielk1977         " <bytes>", 0);
119251e3d8e2Sdanielk1977     return TCL_ERROR;
119351e3d8e2Sdanielk1977   }
119451e3d8e2Sdanielk1977 
119551e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
119651e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
119751e3d8e2Sdanielk1977   value = Tcl_GetByteArrayFromObj(objv[3], 0);
119851e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
119951e3d8e2Sdanielk1977 
1200d8123366Sdanielk1977   rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, SQLITE_TRANSIENT);
120151e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
120251e3d8e2Sdanielk1977     return TCL_ERROR;
120351e3d8e2Sdanielk1977   }
120451e3d8e2Sdanielk1977 
120551e3d8e2Sdanielk1977   return TCL_OK;
120651e3d8e2Sdanielk1977 }
120751e3d8e2Sdanielk1977 
120851e3d8e2Sdanielk1977 static int test_bind_blob(
120951e3d8e2Sdanielk1977   void * clientData,
121051e3d8e2Sdanielk1977   Tcl_Interp *interp,
121151e3d8e2Sdanielk1977   int objc,
121251e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
121351e3d8e2Sdanielk1977 ){
121451e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
121551e3d8e2Sdanielk1977   int idx;
121651e3d8e2Sdanielk1977   int bytes;
121751e3d8e2Sdanielk1977   char *value;
121851e3d8e2Sdanielk1977   int rc;
121951e3d8e2Sdanielk1977 
122051e3d8e2Sdanielk1977   if( objc!=5 ){
122151e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
122251e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
122351e3d8e2Sdanielk1977         " <bytes>", 0);
122451e3d8e2Sdanielk1977     return TCL_ERROR;
122551e3d8e2Sdanielk1977   }
122651e3d8e2Sdanielk1977 
122751e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
122851e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
122951e3d8e2Sdanielk1977   value = Tcl_GetString(objv[3]);
123049e4643eSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
123151e3d8e2Sdanielk1977 
1232d8123366Sdanielk1977   rc = sqlite3_bind_blob(pStmt, idx, value, bytes, SQLITE_TRANSIENT);
123351e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
123451e3d8e2Sdanielk1977     return TCL_ERROR;
123551e3d8e2Sdanielk1977   }
123651e3d8e2Sdanielk1977 
123751e3d8e2Sdanielk1977   return TCL_OK;
123851e3d8e2Sdanielk1977 }
123951e3d8e2Sdanielk1977 
124099ee3600Sdrh /*
12416622cce3Sdanielk1977 ** Usage: sqlite3_errcode DB
12426622cce3Sdanielk1977 **
12436622cce3Sdanielk1977 ** Return the string representation of the most recent sqlite3_* API
12446622cce3Sdanielk1977 ** error code. e.g. "SQLITE_ERROR".
12456622cce3Sdanielk1977 */
12466622cce3Sdanielk1977 static int test_errcode(
12476622cce3Sdanielk1977   void * clientData,
12486622cce3Sdanielk1977   Tcl_Interp *interp,
12496622cce3Sdanielk1977   int objc,
12506622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
12516622cce3Sdanielk1977 ){
12526622cce3Sdanielk1977   sqlite3 *db;
12536622cce3Sdanielk1977 
12546622cce3Sdanielk1977   if( objc!=2 ){
12556622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
12566622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
12576622cce3Sdanielk1977     return TCL_ERROR;
12586622cce3Sdanielk1977   }
12596622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
12606622cce3Sdanielk1977   Tcl_SetResult(interp, (char *)errorName(sqlite3_errcode(db)), 0);
12616622cce3Sdanielk1977   return TCL_OK;
12626622cce3Sdanielk1977 }
12636622cce3Sdanielk1977 
12646622cce3Sdanielk1977 /*
12656622cce3Sdanielk1977 ** Usage:   test_errmsg DB
12666622cce3Sdanielk1977 **
12676622cce3Sdanielk1977 ** Returns the UTF-8 representation of the error message string for the
12686622cce3Sdanielk1977 ** most recent sqlite3_* API call.
12696622cce3Sdanielk1977 */
12706622cce3Sdanielk1977 static int test_errmsg(
12716622cce3Sdanielk1977   void * clientData,
12726622cce3Sdanielk1977   Tcl_Interp *interp,
12736622cce3Sdanielk1977   int objc,
12746622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
12756622cce3Sdanielk1977 ){
12766622cce3Sdanielk1977   sqlite *db;
12776622cce3Sdanielk1977   const char *zErr;
12786622cce3Sdanielk1977 
12796622cce3Sdanielk1977   if( objc!=2 ){
12806622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
12816622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
12826622cce3Sdanielk1977     return TCL_ERROR;
12836622cce3Sdanielk1977   }
12846622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
12856622cce3Sdanielk1977 
12866622cce3Sdanielk1977   zErr = sqlite3_errmsg(db);
12876622cce3Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
12886622cce3Sdanielk1977   return TCL_OK;
12896622cce3Sdanielk1977 }
12906622cce3Sdanielk1977 
12916622cce3Sdanielk1977 /*
12926622cce3Sdanielk1977 ** Usage:   test_errmsg16 DB
12936622cce3Sdanielk1977 **
12946622cce3Sdanielk1977 ** Returns the UTF-16 representation of the error message string for the
12956622cce3Sdanielk1977 ** most recent sqlite3_* API call. This is a byte array object at the TCL
12966622cce3Sdanielk1977 ** level, and it includes the 0x00 0x00 terminator bytes at the end of the
12976622cce3Sdanielk1977 ** UTF-16 string.
12986622cce3Sdanielk1977 */
12996622cce3Sdanielk1977 static int test_errmsg16(
13006622cce3Sdanielk1977   void * clientData,
13016622cce3Sdanielk1977   Tcl_Interp *interp,
13026622cce3Sdanielk1977   int objc,
13036622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
13046622cce3Sdanielk1977 ){
13056622cce3Sdanielk1977   sqlite *db;
13066622cce3Sdanielk1977   const void *zErr;
13076622cce3Sdanielk1977   int bytes;
13086622cce3Sdanielk1977 
13096622cce3Sdanielk1977   if( objc!=2 ){
13106622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
13116622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
13126622cce3Sdanielk1977     return TCL_ERROR;
13136622cce3Sdanielk1977   }
13146622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
13156622cce3Sdanielk1977 
13166622cce3Sdanielk1977   zErr = sqlite3_errmsg16(db);
13176622cce3Sdanielk1977   bytes = sqlite3utf16ByteLen(zErr, -1);
13186622cce3Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes));
13196622cce3Sdanielk1977   return TCL_OK;
13206622cce3Sdanielk1977 }
13216622cce3Sdanielk1977 
13226622cce3Sdanielk1977 /*
13236622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar
13246622cce3Sdanielk1977 **
13256622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
13266622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global
13276622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A
13286622cce3Sdanielk1977 ** STMT handle is returned.
13296622cce3Sdanielk1977 */
13306622cce3Sdanielk1977 static int test_prepare(
13316622cce3Sdanielk1977   void * clientData,
13326622cce3Sdanielk1977   Tcl_Interp *interp,
13336622cce3Sdanielk1977   int objc,
13346622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
13356622cce3Sdanielk1977 ){
13366622cce3Sdanielk1977   sqlite3 *db;
13376622cce3Sdanielk1977   const char *zSql;
13386622cce3Sdanielk1977   int bytes;
13396622cce3Sdanielk1977   const char *zTail = 0;
13406622cce3Sdanielk1977   sqlite3_stmt *pStmt = 0;
13416622cce3Sdanielk1977   char zBuf[50];
13424ad1713cSdanielk1977   int rc;
13436622cce3Sdanielk1977 
13446622cce3Sdanielk1977   if( objc!=5 ){
13456622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
13466622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
13476622cce3Sdanielk1977     return TCL_ERROR;
13486622cce3Sdanielk1977   }
13496622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
13506622cce3Sdanielk1977   zSql = Tcl_GetString(objv[2]);
13516622cce3Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
13526622cce3Sdanielk1977 
13534ad1713cSdanielk1977   rc = sqlite3_prepare(db, zSql, bytes, &pStmt, &zTail);
13546622cce3Sdanielk1977   if( zTail ){
13556622cce3Sdanielk1977     if( bytes>=0 ){
13566622cce3Sdanielk1977       bytes = bytes - (zTail-zSql);
13576622cce3Sdanielk1977     }
13586622cce3Sdanielk1977     Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
13596622cce3Sdanielk1977   }
13604ad1713cSdanielk1977   if( rc!=SQLITE_OK ){
13614ad1713cSdanielk1977     assert( pStmt==0 );
13624ad1713cSdanielk1977     sprintf(zBuf, "(%d) ", rc);
13634ad1713cSdanielk1977     Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
13644ad1713cSdanielk1977     return TCL_ERROR;
13654ad1713cSdanielk1977   }
13666622cce3Sdanielk1977 
13674ad1713cSdanielk1977   if( pStmt ){
13686622cce3Sdanielk1977     if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
13696622cce3Sdanielk1977     Tcl_AppendResult(interp, zBuf, 0);
13704ad1713cSdanielk1977   }
13716622cce3Sdanielk1977   return TCL_OK;
13726622cce3Sdanielk1977 }
13736622cce3Sdanielk1977 
13746622cce3Sdanielk1977 /*
13756622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar
13766622cce3Sdanielk1977 **
13776622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
13786622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global
13796622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A
13806622cce3Sdanielk1977 ** STMT handle is returned.
13816622cce3Sdanielk1977 */
13826622cce3Sdanielk1977 static int test_prepare16(
13836622cce3Sdanielk1977   void * clientData,
13846622cce3Sdanielk1977   Tcl_Interp *interp,
13856622cce3Sdanielk1977   int objc,
13866622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
13876622cce3Sdanielk1977 ){
13886622cce3Sdanielk1977   sqlite3 *db;
13896622cce3Sdanielk1977   const void *zSql;
13906622cce3Sdanielk1977   const void *zTail = 0;
13916622cce3Sdanielk1977   Tcl_Obj *pTail = 0;
13926622cce3Sdanielk1977   sqlite3_stmt *pStmt = 0;
13936622cce3Sdanielk1977   char zBuf[50];
13946622cce3Sdanielk1977   int bytes;                /* The integer specified as arg 3 */
13956622cce3Sdanielk1977   int objlen;               /* The byte-array length of arg 2 */
13966622cce3Sdanielk1977 
13976622cce3Sdanielk1977   if( objc!=5 ){
13986622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
13996622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
14006622cce3Sdanielk1977     return TCL_ERROR;
14016622cce3Sdanielk1977   }
14026622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
14036622cce3Sdanielk1977   zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen);
14046622cce3Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
14056622cce3Sdanielk1977 
14066622cce3Sdanielk1977   if( SQLITE_OK!=sqlite3_prepare16(db, zSql, bytes, &pStmt, &zTail) ){
14076622cce3Sdanielk1977     return TCL_ERROR;
14086622cce3Sdanielk1977   }
14096622cce3Sdanielk1977 
14106622cce3Sdanielk1977   if( zTail ){
14116622cce3Sdanielk1977     objlen = objlen - ((u8 *)zTail-(u8 *)zSql);
14126622cce3Sdanielk1977   }else{
14136622cce3Sdanielk1977     objlen = 0;
14146622cce3Sdanielk1977   }
14156622cce3Sdanielk1977   pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen);
14166622cce3Sdanielk1977   Tcl_IncrRefCount(pTail);
14176622cce3Sdanielk1977   Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0);
14184ad1713cSdanielk1977   Tcl_DecrRefCount(pTail);
14196622cce3Sdanielk1977 
14204ad1713cSdanielk1977   if( pStmt ){
14216622cce3Sdanielk1977     if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
14224ad1713cSdanielk1977   }
14236622cce3Sdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
14246622cce3Sdanielk1977   return TCL_OK;
14256622cce3Sdanielk1977 }
14266622cce3Sdanielk1977 
14274ad1713cSdanielk1977 /*
14284ad1713cSdanielk1977 ** Usage: sqlite3_open filename ?options-list?
14294ad1713cSdanielk1977 */
14304ad1713cSdanielk1977 static int test_open(
14314ad1713cSdanielk1977   void * clientData,
14324ad1713cSdanielk1977   Tcl_Interp *interp,
14334ad1713cSdanielk1977   int objc,
14344ad1713cSdanielk1977   Tcl_Obj *CONST objv[]
14354ad1713cSdanielk1977 ){
14364ad1713cSdanielk1977   const char *zFilename;
14374ad1713cSdanielk1977   sqlite3 *db;
14384ad1713cSdanielk1977   int rc;
14394ad1713cSdanielk1977   char zBuf[100];
14404ad1713cSdanielk1977 
14414ad1713cSdanielk1977   if( objc!=3 && objc!=2 ){
14424ad1713cSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
14434ad1713cSdanielk1977        Tcl_GetString(objv[0]), " filename options-list", 0);
14444ad1713cSdanielk1977     return TCL_ERROR;
14454ad1713cSdanielk1977   }
14464ad1713cSdanielk1977 
14474ad1713cSdanielk1977   zFilename = Tcl_GetString(objv[1]);
14484f057f90Sdanielk1977   rc = sqlite3_open(zFilename, &db);
14494ad1713cSdanielk1977 
14504ad1713cSdanielk1977   if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
14514ad1713cSdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
14524ad1713cSdanielk1977   return TCL_OK;
14534ad1713cSdanielk1977 }
14544ad1713cSdanielk1977 
14554ad1713cSdanielk1977 /*
14564ad1713cSdanielk1977 ** Usage: sqlite3_open16 filename options
14574ad1713cSdanielk1977 */
14584ad1713cSdanielk1977 static int test_open16(
14594ad1713cSdanielk1977   void * clientData,
14604ad1713cSdanielk1977   Tcl_Interp *interp,
14614ad1713cSdanielk1977   int objc,
14624ad1713cSdanielk1977   Tcl_Obj *CONST objv[]
14634ad1713cSdanielk1977 ){
14644ad1713cSdanielk1977   const void *zFilename;
14654ad1713cSdanielk1977   sqlite3 *db;
14664ad1713cSdanielk1977   int rc;
14674ad1713cSdanielk1977   char zBuf[100];
14684ad1713cSdanielk1977 
14694ad1713cSdanielk1977   if( objc!=3 ){
14704ad1713cSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
14714ad1713cSdanielk1977        Tcl_GetString(objv[0]), " filename options-list", 0);
14724ad1713cSdanielk1977     return TCL_ERROR;
14734ad1713cSdanielk1977   }
14744ad1713cSdanielk1977 
14754ad1713cSdanielk1977   zFilename = Tcl_GetByteArrayFromObj(objv[1], 0);
14764f057f90Sdanielk1977   rc = sqlite3_open16(zFilename, &db);
14774ad1713cSdanielk1977 
14784ad1713cSdanielk1977   if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
14794ad1713cSdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
14804ad1713cSdanielk1977   return TCL_OK;
14814ad1713cSdanielk1977 }
1482d3d39e93Sdrh 
1483d3d39e93Sdrh /*
1484106bb236Sdanielk1977 ** Usage: sqlite3_step STMT
1485106bb236Sdanielk1977 **
1486106bb236Sdanielk1977 ** Advance the statement to the next row.
1487106bb236Sdanielk1977 */
148817240fd9Sdanielk1977 static int test_step(
1489106bb236Sdanielk1977   void * clientData,
1490106bb236Sdanielk1977   Tcl_Interp *interp,
1491106bb236Sdanielk1977   int objc,
1492106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
1493106bb236Sdanielk1977 ){
1494106bb236Sdanielk1977   sqlite3_stmt *pStmt;
1495106bb236Sdanielk1977   int rc;
1496106bb236Sdanielk1977 
1497e1cd9874Sdanielk1977   if( objc!=2 ){
1498106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1499106bb236Sdanielk1977        Tcl_GetString(objv[0]), " STMT", 0);
1500106bb236Sdanielk1977     return TCL_ERROR;
1501106bb236Sdanielk1977   }
1502106bb236Sdanielk1977 
1503106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
150417240fd9Sdanielk1977   rc = sqlite3_step(pStmt);
1505106bb236Sdanielk1977 
1506fbcd585fSdanielk1977   /* if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR; */
15076590493dSdanielk1977   Tcl_SetResult(interp, (char *)errorName(rc), 0);
1508e1cd9874Sdanielk1977   return TCL_OK;
1509e1cd9874Sdanielk1977 }
1510e1cd9874Sdanielk1977 
1511e1cd9874Sdanielk1977 /*
151217240fd9Sdanielk1977 ** Usage: sqlite3_column_count STMT
151317240fd9Sdanielk1977 **
151417240fd9Sdanielk1977 ** Return the number of columns returned by the sql statement STMT.
151517240fd9Sdanielk1977 */
151617240fd9Sdanielk1977 static int test_column_count(
151717240fd9Sdanielk1977   void * clientData,
151817240fd9Sdanielk1977   Tcl_Interp *interp,
151917240fd9Sdanielk1977   int objc,
152017240fd9Sdanielk1977   Tcl_Obj *CONST objv[]
152117240fd9Sdanielk1977 ){
152217240fd9Sdanielk1977   sqlite3_stmt *pStmt;
152317240fd9Sdanielk1977 
152417240fd9Sdanielk1977   if( objc!=2 ){
152517240fd9Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
152617240fd9Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
152717240fd9Sdanielk1977     return TCL_ERROR;
152817240fd9Sdanielk1977   }
152917240fd9Sdanielk1977 
153017240fd9Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
153117240fd9Sdanielk1977 
153217240fd9Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_column_count(pStmt)));
153317240fd9Sdanielk1977   return TCL_OK;
153417240fd9Sdanielk1977 }
153517240fd9Sdanielk1977 
153617240fd9Sdanielk1977 /*
15373cf86063Sdanielk1977 ** Usage: sqlite3_column_type STMT column
15383cf86063Sdanielk1977 **
15393cf86063Sdanielk1977 ** Return the type of the data in column 'column' of the current row.
15403cf86063Sdanielk1977 */
15413cf86063Sdanielk1977 static int test_column_type(
15423cf86063Sdanielk1977   void * clientData,
15433cf86063Sdanielk1977   Tcl_Interp *interp,
15443cf86063Sdanielk1977   int objc,
15453cf86063Sdanielk1977   Tcl_Obj *CONST objv[]
15463cf86063Sdanielk1977 ){
15473cf86063Sdanielk1977   sqlite3_stmt *pStmt;
15483cf86063Sdanielk1977   int col;
15493cf86063Sdanielk1977   int tp;
15503cf86063Sdanielk1977 
15513cf86063Sdanielk1977   if( objc!=3 ){
15523cf86063Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
15533cf86063Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
15543cf86063Sdanielk1977     return TCL_ERROR;
15553cf86063Sdanielk1977   }
15563cf86063Sdanielk1977 
15573cf86063Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
15583cf86063Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
15593cf86063Sdanielk1977 
15603cf86063Sdanielk1977   tp = sqlite3_column_type(pStmt, col);
15613cf86063Sdanielk1977   switch( tp ){
15629c054830Sdrh     case SQLITE_INTEGER:
15633cf86063Sdanielk1977       Tcl_SetResult(interp, "INTEGER", TCL_STATIC);
15643cf86063Sdanielk1977       break;
15659c054830Sdrh     case SQLITE_NULL:
15663cf86063Sdanielk1977       Tcl_SetResult(interp, "NULL", TCL_STATIC);
15673cf86063Sdanielk1977       break;
15689c054830Sdrh     case SQLITE_FLOAT:
15693cf86063Sdanielk1977       Tcl_SetResult(interp, "FLOAT", TCL_STATIC);
15703cf86063Sdanielk1977       break;
15719c054830Sdrh     case SQLITE_TEXT:
15723cf86063Sdanielk1977       Tcl_SetResult(interp, "TEXT", TCL_STATIC);
15733cf86063Sdanielk1977       break;
15749c054830Sdrh     case SQLITE_BLOB:
15753cf86063Sdanielk1977       Tcl_SetResult(interp, "BLOB", TCL_STATIC);
15763cf86063Sdanielk1977       break;
15773cf86063Sdanielk1977     default:
15783cf86063Sdanielk1977       assert(0);
15793cf86063Sdanielk1977   }
15803cf86063Sdanielk1977 
15813cf86063Sdanielk1977   return TCL_OK;
15823cf86063Sdanielk1977 }
15833cf86063Sdanielk1977 
15843cf86063Sdanielk1977 /*
158504f2e68dSdanielk1977 ** Usage: sqlite3_column_int64 STMT column
15863cf86063Sdanielk1977 **
15873cf86063Sdanielk1977 ** Return the data in column 'column' of the current row cast as an
158804f2e68dSdanielk1977 ** wide (64-bit) integer.
15893cf86063Sdanielk1977 */
159004f2e68dSdanielk1977 static int test_column_int64(
15913cf86063Sdanielk1977   void * clientData,
15923cf86063Sdanielk1977   Tcl_Interp *interp,
15933cf86063Sdanielk1977   int objc,
15943cf86063Sdanielk1977   Tcl_Obj *CONST objv[]
15953cf86063Sdanielk1977 ){
15963cf86063Sdanielk1977   sqlite3_stmt *pStmt;
15973cf86063Sdanielk1977   int col;
159804f2e68dSdanielk1977   i64 iVal;
15993cf86063Sdanielk1977 
16003cf86063Sdanielk1977   if( objc!=3 ){
16013cf86063Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
16023cf86063Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
16033cf86063Sdanielk1977     return TCL_ERROR;
16043cf86063Sdanielk1977   }
16053cf86063Sdanielk1977 
16063cf86063Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
16073cf86063Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
16083cf86063Sdanielk1977 
160904f2e68dSdanielk1977   iVal = sqlite3_column_int64(pStmt, col);
161004f2e68dSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(iVal));
161104f2e68dSdanielk1977   return TCL_OK;
161204f2e68dSdanielk1977 }
161304f2e68dSdanielk1977 
161404f2e68dSdanielk1977 /*
1615ea61b2c4Sdanielk1977 ** Usage: sqlite3_column_blob STMT column
1616ea61b2c4Sdanielk1977 */
1617ea61b2c4Sdanielk1977 static int test_column_blob(
1618ea61b2c4Sdanielk1977   void * clientData,
1619ea61b2c4Sdanielk1977   Tcl_Interp *interp,
1620ea61b2c4Sdanielk1977   int objc,
1621ea61b2c4Sdanielk1977   Tcl_Obj *CONST objv[]
1622ea61b2c4Sdanielk1977 ){
1623ea61b2c4Sdanielk1977   sqlite3_stmt *pStmt;
1624ea61b2c4Sdanielk1977   int col;
1625ea61b2c4Sdanielk1977 
1626ea61b2c4Sdanielk1977   int len;
1627c572ef7fSdanielk1977   const void *pBlob;
1628ea61b2c4Sdanielk1977 
1629ea61b2c4Sdanielk1977   if( objc!=3 ){
1630ea61b2c4Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1631ea61b2c4Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
1632ea61b2c4Sdanielk1977     return TCL_ERROR;
1633ea61b2c4Sdanielk1977   }
1634ea61b2c4Sdanielk1977 
1635ea61b2c4Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
1636ea61b2c4Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
1637ea61b2c4Sdanielk1977 
1638ea61b2c4Sdanielk1977   pBlob = sqlite3_column_blob(pStmt, col);
1639ea61b2c4Sdanielk1977   len = sqlite3_column_bytes(pStmt, col);
1640ea61b2c4Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pBlob, len));
1641ea61b2c4Sdanielk1977   return TCL_OK;
1642ea61b2c4Sdanielk1977 }
1643ea61b2c4Sdanielk1977 
1644ea61b2c4Sdanielk1977 /*
164504f2e68dSdanielk1977 ** Usage: sqlite3_column_double STMT column
164604f2e68dSdanielk1977 **
164704f2e68dSdanielk1977 ** Return the data in column 'column' of the current row cast as a double.
164804f2e68dSdanielk1977 */
164904f2e68dSdanielk1977 static int test_column_double(
165004f2e68dSdanielk1977   void * clientData,
165104f2e68dSdanielk1977   Tcl_Interp *interp,
165204f2e68dSdanielk1977   int objc,
165304f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
165404f2e68dSdanielk1977 ){
165504f2e68dSdanielk1977   sqlite3_stmt *pStmt;
165604f2e68dSdanielk1977   int col;
165704f2e68dSdanielk1977   double rVal;
165804f2e68dSdanielk1977 
165904f2e68dSdanielk1977   if( objc!=3 ){
166004f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
166104f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
166204f2e68dSdanielk1977     return TCL_ERROR;
166304f2e68dSdanielk1977   }
166404f2e68dSdanielk1977 
166504f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
166604f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
166704f2e68dSdanielk1977 
166804f2e68dSdanielk1977   rVal = sqlite3_column_double(pStmt, col);
1669c572ef7fSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewDoubleObj(rVal));
16703cf86063Sdanielk1977   return TCL_OK;
16713cf86063Sdanielk1977 }
16723cf86063Sdanielk1977 
16733cf86063Sdanielk1977 /*
167417240fd9Sdanielk1977 ** Usage: sqlite3_data_count STMT
167517240fd9Sdanielk1977 **
167617240fd9Sdanielk1977 ** Return the number of columns returned by the sql statement STMT.
167717240fd9Sdanielk1977 */
167817240fd9Sdanielk1977 static int test_data_count(
167917240fd9Sdanielk1977   void * clientData,
168017240fd9Sdanielk1977   Tcl_Interp *interp,
168117240fd9Sdanielk1977   int objc,
168217240fd9Sdanielk1977   Tcl_Obj *CONST objv[]
168317240fd9Sdanielk1977 ){
168417240fd9Sdanielk1977   sqlite3_stmt *pStmt;
168517240fd9Sdanielk1977 
168617240fd9Sdanielk1977   if( objc!=2 ){
168717240fd9Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
168817240fd9Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
168917240fd9Sdanielk1977     return TCL_ERROR;
169017240fd9Sdanielk1977   }
169117240fd9Sdanielk1977 
169217240fd9Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
169317240fd9Sdanielk1977 
169417240fd9Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_data_count(pStmt)));
169517240fd9Sdanielk1977   return TCL_OK;
169617240fd9Sdanielk1977 }
169717240fd9Sdanielk1977 
169817240fd9Sdanielk1977 /*
169904f2e68dSdanielk1977 ** Usage: sqlite3_column_text STMT column
170004f2e68dSdanielk1977 **
170104f2e68dSdanielk1977 ** Usage: sqlite3_column_decltype STMT column
170204f2e68dSdanielk1977 **
170304f2e68dSdanielk1977 ** Usage: sqlite3_column_name STMT column
170404f2e68dSdanielk1977 */
170504f2e68dSdanielk1977 static int test_stmt_utf8(
170604f2e68dSdanielk1977   void * clientData,
170704f2e68dSdanielk1977   Tcl_Interp *interp,
170804f2e68dSdanielk1977   int objc,
170904f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
171004f2e68dSdanielk1977 ){
171104f2e68dSdanielk1977   sqlite3_stmt *pStmt;
171204f2e68dSdanielk1977   int col;
1713c572ef7fSdanielk1977   const char *(*xFunc)(sqlite3_stmt*, int) = clientData;
1714f93bbbeaSdanielk1977   const char *zRet;
171504f2e68dSdanielk1977 
171604f2e68dSdanielk1977   if( objc!=3 ){
171704f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
171804f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
171904f2e68dSdanielk1977     return TCL_ERROR;
172004f2e68dSdanielk1977   }
172104f2e68dSdanielk1977 
172204f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
172304f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
1724f93bbbeaSdanielk1977   zRet = xFunc(pStmt, col);
1725f93bbbeaSdanielk1977   if( zRet ){
1726f93bbbeaSdanielk1977     Tcl_SetResult(interp, (char *)zRet, 0);
1727f93bbbeaSdanielk1977   }
172804f2e68dSdanielk1977   return TCL_OK;
172904f2e68dSdanielk1977 }
173004f2e68dSdanielk1977 
173104f2e68dSdanielk1977 /*
173204f2e68dSdanielk1977 ** Usage: sqlite3_column_text STMT column
173304f2e68dSdanielk1977 **
173404f2e68dSdanielk1977 ** Usage: sqlite3_column_decltype STMT column
173504f2e68dSdanielk1977 **
173604f2e68dSdanielk1977 ** Usage: sqlite3_column_name STMT column
173704f2e68dSdanielk1977 */
173804f2e68dSdanielk1977 static int test_stmt_utf16(
173904f2e68dSdanielk1977   void * clientData,
174004f2e68dSdanielk1977   Tcl_Interp *interp,
174104f2e68dSdanielk1977   int objc,
174204f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
174304f2e68dSdanielk1977 ){
174404f2e68dSdanielk1977   sqlite3_stmt *pStmt;
174504f2e68dSdanielk1977   int col;
174604f2e68dSdanielk1977   Tcl_Obj *pRet;
174704f2e68dSdanielk1977   const void *zName16;
1748c572ef7fSdanielk1977   const void *(*xFunc)(sqlite3_stmt*, int) = clientData;
174904f2e68dSdanielk1977 
175004f2e68dSdanielk1977   if( objc!=3 ){
175104f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
175204f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
175304f2e68dSdanielk1977     return TCL_ERROR;
175404f2e68dSdanielk1977   }
175504f2e68dSdanielk1977 
175604f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
175704f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
175804f2e68dSdanielk1977 
175904f2e68dSdanielk1977   zName16 = xFunc(pStmt, col);
1760f93bbbeaSdanielk1977   if( zName16 ){
176104f2e68dSdanielk1977     pRet = Tcl_NewByteArrayObj(zName16, sqlite3utf16ByteLen(zName16, -1)+2);
176204f2e68dSdanielk1977     Tcl_SetObjResult(interp, pRet);
1763f93bbbeaSdanielk1977   }
176404f2e68dSdanielk1977 
176504f2e68dSdanielk1977   return TCL_OK;
176604f2e68dSdanielk1977 }
176704f2e68dSdanielk1977 
176804f2e68dSdanielk1977 /*
176904f2e68dSdanielk1977 ** Usage: sqlite3_column_int STMT column
177004f2e68dSdanielk1977 **
177104f2e68dSdanielk1977 ** Usage: sqlite3_column_bytes STMT column
177204f2e68dSdanielk1977 **
177304f2e68dSdanielk1977 ** Usage: sqlite3_column_bytes16 STMT column
177404f2e68dSdanielk1977 **
177504f2e68dSdanielk1977 */
177604f2e68dSdanielk1977 static int test_stmt_int(
177704f2e68dSdanielk1977   void * clientData,
177804f2e68dSdanielk1977   Tcl_Interp *interp,
177904f2e68dSdanielk1977   int objc,
178004f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
178104f2e68dSdanielk1977 ){
178204f2e68dSdanielk1977   sqlite3_stmt *pStmt;
178304f2e68dSdanielk1977   int col;
1784c572ef7fSdanielk1977   int (*xFunc)(sqlite3_stmt*, int) = clientData;
178504f2e68dSdanielk1977 
178604f2e68dSdanielk1977   if( objc!=3 ){
178704f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
178804f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
178904f2e68dSdanielk1977     return TCL_ERROR;
179004f2e68dSdanielk1977   }
179104f2e68dSdanielk1977 
179204f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
179304f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
179404f2e68dSdanielk1977 
179504f2e68dSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(xFunc(pStmt, col)));
179604f2e68dSdanielk1977   return TCL_OK;
179704f2e68dSdanielk1977 }
179804f2e68dSdanielk1977 
17999a1d0abeSdanielk1977 /*
18009a1d0abeSdanielk1977 ** Usage:  sqlite3OsOpenReadWrite <filename>
18019a1d0abeSdanielk1977 */
18029a1d0abeSdanielk1977 static int test_sqlite3OsOpenReadWrite(
18039a1d0abeSdanielk1977   void * clientData,
18049a1d0abeSdanielk1977   Tcl_Interp *interp,
18059a1d0abeSdanielk1977   int objc,
18069a1d0abeSdanielk1977   Tcl_Obj *CONST objv[]
18079a1d0abeSdanielk1977 ){
18089a1d0abeSdanielk1977   OsFile * pFile;
18099a1d0abeSdanielk1977   int rc;
18109a1d0abeSdanielk1977   int dummy;
18119a1d0abeSdanielk1977   char zBuf[100];
181204f2e68dSdanielk1977 
18139a1d0abeSdanielk1977   if( objc!=2 ){
18149a1d0abeSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
18159a1d0abeSdanielk1977        Tcl_GetString(objv[0]), " filename", 0);
18169a1d0abeSdanielk1977     return TCL_ERROR;
18179a1d0abeSdanielk1977   }
18189a1d0abeSdanielk1977 
18199a1d0abeSdanielk1977   pFile = sqliteMalloc(sizeof(OsFile));
18209a1d0abeSdanielk1977   rc = sqlite3OsOpenReadWrite(Tcl_GetString(objv[1]), pFile, &dummy);
18219a1d0abeSdanielk1977   if( rc!=SQLITE_OK ){
18229a1d0abeSdanielk1977     sqliteFree(pFile);
18239a1d0abeSdanielk1977     Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
18249a1d0abeSdanielk1977     return TCL_ERROR;
18259a1d0abeSdanielk1977   }
18269a1d0abeSdanielk1977   makePointerStr(interp, zBuf, pFile);
18279a1d0abeSdanielk1977   Tcl_SetResult(interp, zBuf, 0);
18289a1d0abeSdanielk1977   return TCL_ERROR;
18299a1d0abeSdanielk1977 }
18309a1d0abeSdanielk1977 
18319a1d0abeSdanielk1977 /*
18329a1d0abeSdanielk1977 ** Usage:  sqlite3OsClose <file handle>
18339a1d0abeSdanielk1977 */
18349a1d0abeSdanielk1977 static int test_sqlite3OsClose(
18359a1d0abeSdanielk1977   void * clientData,
18369a1d0abeSdanielk1977   Tcl_Interp *interp,
18379a1d0abeSdanielk1977   int objc,
18389a1d0abeSdanielk1977   Tcl_Obj *CONST objv[]
18399a1d0abeSdanielk1977 ){
18409a1d0abeSdanielk1977   OsFile * pFile;
18419a1d0abeSdanielk1977   int rc;
18429a1d0abeSdanielk1977 
18439a1d0abeSdanielk1977   if( objc!=2 ){
18449a1d0abeSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
18459a1d0abeSdanielk1977        Tcl_GetString(objv[0]), " filehandle", 0);
18469a1d0abeSdanielk1977     return TCL_ERROR;
18479a1d0abeSdanielk1977   }
18489a1d0abeSdanielk1977 
18499a1d0abeSdanielk1977   if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
18509a1d0abeSdanielk1977     return TCL_ERROR;
18519a1d0abeSdanielk1977   }
18529a1d0abeSdanielk1977   rc = sqlite3OsClose(pFile);
18539a1d0abeSdanielk1977   if( rc!=SQLITE_OK ){
18549a1d0abeSdanielk1977     Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
18559a1d0abeSdanielk1977     return TCL_ERROR;
18569a1d0abeSdanielk1977   }
18579a1d0abeSdanielk1977   sqliteFree(pFile);
18589a1d0abeSdanielk1977   return TCL_OK;
18599a1d0abeSdanielk1977 }
18609a1d0abeSdanielk1977 
18619a1d0abeSdanielk1977 /*
18629a1d0abeSdanielk1977 ** Usage:  sqlite3OsLock <file handle> <locktype>
18639a1d0abeSdanielk1977 */
18649a1d0abeSdanielk1977 static int test_sqlite3OsLock(
18659a1d0abeSdanielk1977   void * clientData,
18669a1d0abeSdanielk1977   Tcl_Interp *interp,
18679a1d0abeSdanielk1977   int objc,
18689a1d0abeSdanielk1977   Tcl_Obj *CONST objv[]
18699a1d0abeSdanielk1977 ){
18709a1d0abeSdanielk1977   OsFile * pFile;
18719a1d0abeSdanielk1977   int rc;
18729a1d0abeSdanielk1977 
18739a1d0abeSdanielk1977   if( objc!=3 ){
18749a1d0abeSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
18759a1d0abeSdanielk1977         Tcl_GetString(objv[0]),
18769a1d0abeSdanielk1977         " filehandle (SHARED|RESERVED|PENDING|EXCLUSIVE)", 0);
18779a1d0abeSdanielk1977     return TCL_ERROR;
18789a1d0abeSdanielk1977   }
18799a1d0abeSdanielk1977 
18809a1d0abeSdanielk1977   if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
18819a1d0abeSdanielk1977     return TCL_ERROR;
18829a1d0abeSdanielk1977   }
18839a1d0abeSdanielk1977 
18849a1d0abeSdanielk1977   if( 0==strcmp("SHARED", Tcl_GetString(objv[2])) ){
18859a1d0abeSdanielk1977     rc = sqlite3OsLock(pFile, SHARED_LOCK);
18869a1d0abeSdanielk1977   }
18879a1d0abeSdanielk1977   else if( 0==strcmp("RESERVED", Tcl_GetString(objv[2])) ){
18889a1d0abeSdanielk1977     rc = sqlite3OsLock(pFile, RESERVED_LOCK);
18899a1d0abeSdanielk1977   }
18909a1d0abeSdanielk1977   else if( 0==strcmp("PENDING", Tcl_GetString(objv[2])) ){
18919a1d0abeSdanielk1977     rc = sqlite3OsLock(pFile, PENDING_LOCK);
18929a1d0abeSdanielk1977   }
18939a1d0abeSdanielk1977   else if( 0==strcmp("EXCLUSIVE", Tcl_GetString(objv[2])) ){
18949a1d0abeSdanielk1977     rc = sqlite3OsLock(pFile, EXCLUSIVE_LOCK);
18959a1d0abeSdanielk1977   }else{
18969a1d0abeSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
18979a1d0abeSdanielk1977         Tcl_GetString(objv[0]),
18989a1d0abeSdanielk1977         " filehandle (SHARED|RESERVED|PENDING|EXCLUSIVE)", 0);
18999a1d0abeSdanielk1977     return TCL_ERROR;
19009a1d0abeSdanielk1977   }
19019a1d0abeSdanielk1977 
19029a1d0abeSdanielk1977   if( rc!=SQLITE_OK ){
19039a1d0abeSdanielk1977     Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
19049a1d0abeSdanielk1977     return TCL_ERROR;
19059a1d0abeSdanielk1977   }
19069a1d0abeSdanielk1977   return TCL_OK;
19079a1d0abeSdanielk1977 }
19089a1d0abeSdanielk1977 
19099a1d0abeSdanielk1977 /*
19109a1d0abeSdanielk1977 ** Usage:  sqlite3OsUnlock <file handle>
19119a1d0abeSdanielk1977 */
19129a1d0abeSdanielk1977 static int test_sqlite3OsUnlock(
19139a1d0abeSdanielk1977   void * clientData,
19149a1d0abeSdanielk1977   Tcl_Interp *interp,
19159a1d0abeSdanielk1977   int objc,
19169a1d0abeSdanielk1977   Tcl_Obj *CONST objv[]
19179a1d0abeSdanielk1977 ){
19189a1d0abeSdanielk1977   OsFile * pFile;
19199a1d0abeSdanielk1977   int rc;
19209a1d0abeSdanielk1977 
19219a1d0abeSdanielk1977   if( objc!=2 ){
19229a1d0abeSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
19239a1d0abeSdanielk1977        Tcl_GetString(objv[0]), " filehandle", 0);
19249a1d0abeSdanielk1977     return TCL_ERROR;
19259a1d0abeSdanielk1977   }
19269a1d0abeSdanielk1977 
19279a1d0abeSdanielk1977   if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
19289a1d0abeSdanielk1977     return TCL_ERROR;
19299a1d0abeSdanielk1977   }
1930a6abd041Sdrh   rc = sqlite3OsUnlock(pFile, NO_LOCK);
19319a1d0abeSdanielk1977   if( rc!=SQLITE_OK ){
19329a1d0abeSdanielk1977     Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
19339a1d0abeSdanielk1977     return TCL_ERROR;
19349a1d0abeSdanielk1977   }
19359a1d0abeSdanielk1977   return TCL_OK;
19369a1d0abeSdanielk1977 }
1937d3d39e93Sdrh 
1938d8123366Sdanielk1977 
19396622cce3Sdanielk1977 /*
1940d1bf3512Sdrh ** Register commands with the TCL interpreter.
1941d1bf3512Sdrh */
1942d1bf3512Sdrh int Sqlitetest1_Init(Tcl_Interp *interp){
19436f8a503dSdanielk1977   extern int sqlite3_search_count;
19446f8a503dSdanielk1977   extern int sqlite3_interrupt_count;
19456f8a503dSdanielk1977   extern int sqlite3_open_file_count;
19466f8a503dSdanielk1977   extern int sqlite3_current_time;
1947c2eef3b3Sdrh   static struct {
1948c2eef3b3Sdrh      char *zName;
1949c2eef3b3Sdrh      Tcl_CmdProc *xProc;
1950c2eef3b3Sdrh   } aCmd[] = {
19516f8a503dSdanielk1977      { "sqlite3_mprintf_int",           (Tcl_CmdProc*)sqlite3_mprintf_int    },
19526f8a503dSdanielk1977      { "sqlite3_mprintf_str",           (Tcl_CmdProc*)sqlite3_mprintf_str    },
19536f8a503dSdanielk1977      { "sqlite3_mprintf_double",        (Tcl_CmdProc*)sqlite3_mprintf_double },
19546f8a503dSdanielk1977      { "sqlite3_mprintf_scaled",        (Tcl_CmdProc*)sqlite3_mprintf_scaled },
19556f8a503dSdanielk1977      { "sqlite3_mprintf_z_test",        (Tcl_CmdProc*)test_mprintf_z        },
19566f8a503dSdanielk1977      { "sqlite3_last_insert_rowid",     (Tcl_CmdProc*)test_last_rowid       },
19576f8a503dSdanielk1977      { "sqlite3_exec_printf",           (Tcl_CmdProc*)test_exec_printf      },
19586f8a503dSdanielk1977      { "sqlite3_get_table_printf",      (Tcl_CmdProc*)test_get_table_printf },
19596f8a503dSdanielk1977      { "sqlite3_close",                 (Tcl_CmdProc*)sqlite_test_close     },
19606f8a503dSdanielk1977      { "sqlite3_create_function",       (Tcl_CmdProc*)test_create_function  },
19616f8a503dSdanielk1977      { "sqlite3_create_aggregate",      (Tcl_CmdProc*)test_create_aggregate },
1962c2eef3b3Sdrh      { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func    },
1963c2eef3b3Sdrh      { "sqlite_abort",                  (Tcl_CmdProc*)sqlite_abort          },
1964faa57accSdrh #ifdef SQLITE_DEBUG
1965c2eef3b3Sdrh      { "sqlite_malloc_fail",            (Tcl_CmdProc*)sqlite_malloc_fail    },
1966c2eef3b3Sdrh      { "sqlite_malloc_stat",            (Tcl_CmdProc*)sqlite_malloc_stat    },
1967c2eef3b3Sdrh #endif
196896fc5fe6Sdanielk1977      { "sqlite_bind",                    (Tcl_CmdProc*)test_bind             },
196999ee3600Sdrh      { "breakpoint",                     (Tcl_CmdProc*)test_breakpoint       },
1970c2eef3b3Sdrh   };
197151e3d8e2Sdanielk1977   static struct {
197251e3d8e2Sdanielk1977      char *zName;
197351e3d8e2Sdanielk1977      Tcl_ObjCmdProc *xProc;
197404f2e68dSdanielk1977      void *clientData;
197551e3d8e2Sdanielk1977   } aObjCmd[] = {
197604f2e68dSdanielk1977      { "sqlite3_bind_int32",            test_bind_int32, 0    },
197704f2e68dSdanielk1977      { "sqlite3_bind_int64",            test_bind_int64 , 0   },
197804f2e68dSdanielk1977      { "sqlite3_bind_double",           test_bind_double, 0   },
197904f2e68dSdanielk1977      { "sqlite3_bind_null",             test_bind_null     ,0 },
198004f2e68dSdanielk1977      { "sqlite3_bind_text",             test_bind_text     ,0 },
198104f2e68dSdanielk1977      { "sqlite3_bind_text16",           test_bind_text16   ,0 },
198204f2e68dSdanielk1977      { "sqlite3_bind_blob",             test_bind_blob     ,0 },
198304f2e68dSdanielk1977      { "sqlite3_errcode",               test_errcode       ,0 },
198404f2e68dSdanielk1977      { "sqlite3_errmsg",                test_errmsg        ,0 },
198504f2e68dSdanielk1977      { "sqlite3_errmsg16",              test_errmsg16      ,0 },
198604f2e68dSdanielk1977      { "sqlite3_open",                  test_open          ,0 },
198704f2e68dSdanielk1977      { "sqlite3_open16",                test_open16        ,0 },
198804f2e68dSdanielk1977 
198904f2e68dSdanielk1977      { "sqlite3_prepare",               test_prepare       ,0 },
199004f2e68dSdanielk1977      { "sqlite3_prepare16",             test_prepare16     ,0 },
199104f2e68dSdanielk1977      { "sqlite3_finalize",              test_finalize      ,0 },
199204f2e68dSdanielk1977      { "sqlite3_reset",                 test_reset         ,0 },
1993fbcd585fSdanielk1977      { "sqlite3_changes",               test_changes       ,0 },
199404f2e68dSdanielk1977      { "sqlite3_step",                  test_step          ,0 },
199504f2e68dSdanielk1977 
199604f2e68dSdanielk1977      /* sqlite3_column_*() API */
199704f2e68dSdanielk1977      { "sqlite3_column_count",          test_column_count  ,0 },
199804f2e68dSdanielk1977      { "sqlite3_data_count",            test_data_count    ,0 },
199904f2e68dSdanielk1977      { "sqlite3_column_type",           test_column_type   ,0 },
2000ea61b2c4Sdanielk1977      { "sqlite3_column_blob",           test_column_blob   ,0 },
200104f2e68dSdanielk1977      { "sqlite3_column_double",         test_column_double ,0 },
200204f2e68dSdanielk1977      { "sqlite3_column_int64",          test_column_int64  ,0 },
200304f2e68dSdanielk1977      { "sqlite3_column_int", test_stmt_int ,sqlite3_column_int },
200404f2e68dSdanielk1977      { "sqlite3_column_bytes", test_stmt_int ,sqlite3_column_bytes },
200504f2e68dSdanielk1977      { "sqlite3_column_bytes16", test_stmt_int ,sqlite3_column_bytes16 },
200604f2e68dSdanielk1977      { "sqlite3_column_text", test_stmt_utf8,       sqlite3_column_text},
200704f2e68dSdanielk1977      { "sqlite3_column_decltype", test_stmt_utf8,   sqlite3_column_decltype},
200804f2e68dSdanielk1977      { "sqlite3_column_name", test_stmt_utf8,       sqlite3_column_name},
200904f2e68dSdanielk1977      { "sqlite3_column_text16", test_stmt_utf16,    sqlite3_column_text16},
201004f2e68dSdanielk1977      { "sqlite3_column_decltype16", test_stmt_utf16,sqlite3_column_decltype16},
201104f2e68dSdanielk1977      { "sqlite3_column_name16", test_stmt_utf16,    sqlite3_column_name16},
201204f2e68dSdanielk1977 
20139a1d0abeSdanielk1977      /* Functions from os.h */
20149a1d0abeSdanielk1977      { "sqlite3OsOpenReadWrite",test_sqlite3OsOpenReadWrite, 0 },
20159a1d0abeSdanielk1977      { "sqlite3OsClose",        test_sqlite3OsClose, 0 },
20169a1d0abeSdanielk1977      { "sqlite3OsLock",         test_sqlite3OsLock, 0 },
20179a1d0abeSdanielk1977      { "sqlite3OsUnlock",       test_sqlite3OsUnlock, 0 },
20184e6af134Sdanielk1977      { "add_test_collate",      test_collate, 0         },
2019*8a6c550dSdanielk1977      { "sqlite3_crashseed",     sqlite3_crashseed, 0         },
20209a1d0abeSdanielk1977 
202151e3d8e2Sdanielk1977   };
2022c2eef3b3Sdrh   int i;
20232ac3ee97Sdrh   extern int sqlite3_os_trace;
2024c2eef3b3Sdrh 
2025c2eef3b3Sdrh   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
2026c2eef3b3Sdrh     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
2027c2eef3b3Sdrh   }
202851e3d8e2Sdanielk1977   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
2029c572ef7fSdanielk1977     Tcl_CreateObjCommand(interp, aObjCmd[i].zName,
2030c572ef7fSdanielk1977         aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
203151e3d8e2Sdanielk1977   }
20326490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_search_count",
20336f8a503dSdanielk1977       (char*)&sqlite3_search_count, TCL_LINK_INT);
20346490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_interrupt_count",
20356f8a503dSdanielk1977       (char*)&sqlite3_interrupt_count, TCL_LINK_INT);
20366490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_open_file_count",
20376f8a503dSdanielk1977       (char*)&sqlite3_open_file_count, TCL_LINK_INT);
20386490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_current_time",
20396f8a503dSdanielk1977       (char*)&sqlite3_current_time, TCL_LINK_INT);
20402ac3ee97Sdrh   Tcl_LinkVar(interp, "sqlite_os_trace",
20412ac3ee97Sdrh       (char*)&sqlite3_os_trace, TCL_LINK_INT);
20427c972decSdrh   Tcl_LinkVar(interp, "sqlite_static_bind_value",
20437c972decSdrh       (char*)&sqlite_static_bind_value, TCL_LINK_STRING);
2044d1bf3512Sdrh   return TCL_OK;
2045d1bf3512Sdrh }
2046