xref: /sqlite-3.40.0/src/test1.c (revision bfd6cce5)
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*bfd6cce5Sdanielk1977 ** $Id: test1.c,v 1.78 2004/06/18 04:24:55 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;
326d1bf3512Sdrh   if( argc!=2 ){
327d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
328d1bf3512Sdrh        " FILENAME\"", 0);
329d1bf3512Sdrh     return TCL_ERROR;
330d1bf3512Sdrh   }
331b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
3326f8a503dSdanielk1977   sqlite3_close(db);
333d1bf3512Sdrh   return TCL_OK;
334d1bf3512Sdrh }
335d1bf3512Sdrh 
336d1bf3512Sdrh /*
337c22bd47dSdrh ** Implementation of the x_coalesce() function.
338c22bd47dSdrh ** Return the first argument non-NULL argument.
339c22bd47dSdrh */
3400ae8b831Sdanielk1977 static void ifnullFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
341c22bd47dSdrh   int i;
342c22bd47dSdrh   for(i=0; i<argc; i++){
3439c054830Sdrh     if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){
344d8123366Sdanielk1977       sqlite3_result_text(context, sqlite3_value_text(argv[i]), -1,
345d8123366Sdanielk1977           SQLITE_TRANSIENT);
346c22bd47dSdrh       break;
347c22bd47dSdrh     }
348c22bd47dSdrh   }
349c22bd47dSdrh }
350c22bd47dSdrh 
351c22bd47dSdrh /*
352d1d9fc33Sdrh ** A structure into which to accumulate text.
353d1d9fc33Sdrh */
354d1d9fc33Sdrh struct dstr {
355d1d9fc33Sdrh   int nAlloc;  /* Space allocated */
356d1d9fc33Sdrh   int nUsed;   /* Space used */
357d1d9fc33Sdrh   char *z;     /* The space */
358d1d9fc33Sdrh };
359d1d9fc33Sdrh 
360d1d9fc33Sdrh /*
361d1d9fc33Sdrh ** Append text to a dstr
362d1d9fc33Sdrh */
363d1d9fc33Sdrh static void dstrAppend(struct dstr *p, const char *z, int divider){
364d1d9fc33Sdrh   int n = strlen(z);
365d1d9fc33Sdrh   if( p->nUsed + n + 2 > p->nAlloc ){
366d1d9fc33Sdrh     char *zNew;
367d1d9fc33Sdrh     p->nAlloc = p->nAlloc*2 + n + 200;
368d1d9fc33Sdrh     zNew = sqliteRealloc(p->z, p->nAlloc);
369d1d9fc33Sdrh     if( zNew==0 ){
370d1d9fc33Sdrh       sqliteFree(p->z);
371d1d9fc33Sdrh       memset(p, 0, sizeof(*p));
372d1d9fc33Sdrh       return;
373d1d9fc33Sdrh     }
374d1d9fc33Sdrh     p->z = zNew;
375d1d9fc33Sdrh   }
376d1d9fc33Sdrh   if( divider && p->nUsed>0 ){
377d1d9fc33Sdrh     p->z[p->nUsed++] = divider;
378d1d9fc33Sdrh   }
379d1d9fc33Sdrh   memcpy(&p->z[p->nUsed], z, n+1);
380d1d9fc33Sdrh   p->nUsed += n;
381d1d9fc33Sdrh }
382d1d9fc33Sdrh 
383d1d9fc33Sdrh /*
3844adee20fSdanielk1977 ** Invoked for each callback from sqlite3ExecFunc
385d1d9fc33Sdrh */
386d1d9fc33Sdrh static int execFuncCallback(void *pData, int argc, char **argv, char **NotUsed){
387d1d9fc33Sdrh   struct dstr *p = (struct dstr*)pData;
388d1d9fc33Sdrh   int i;
389d1d9fc33Sdrh   for(i=0; i<argc; i++){
390d1d9fc33Sdrh     if( argv[i]==0 ){
391d1d9fc33Sdrh       dstrAppend(p, "NULL", ' ');
392d1d9fc33Sdrh     }else{
393d1d9fc33Sdrh       dstrAppend(p, argv[i], ' ');
394d1d9fc33Sdrh     }
395d1d9fc33Sdrh   }
396d1d9fc33Sdrh   return 0;
397d1d9fc33Sdrh }
398d1d9fc33Sdrh 
399d1d9fc33Sdrh /*
4006f8a503dSdanielk1977 ** Implementation of the x_sqlite3_exec() function.  This function takes
401c22bd47dSdrh ** a single argument and attempts to execute that argument as SQL code.
4026cbe1f1bSdrh ** This is illegal and should set the SQLITE_MISUSE flag on the database.
403c22bd47dSdrh **
4046f8a503dSdanielk1977 ** 2004-Jan-07:  We have changed this to make it legal to call sqlite3_exec()
405d1d9fc33Sdrh ** from within a function call.
406d1d9fc33Sdrh **
407c22bd47dSdrh ** This routine simulates the effect of having two threads attempt to
408c22bd47dSdrh ** use the same database at the same time.
409c22bd47dSdrh */
41051ad0ecdSdanielk1977 static void sqlite3ExecFunc(
4110ae8b831Sdanielk1977   sqlite3_context *context,
41251ad0ecdSdanielk1977   int argc,
41351ad0ecdSdanielk1977   sqlite3_value **argv
41451ad0ecdSdanielk1977 ){
415d1d9fc33Sdrh   struct dstr x;
416d1d9fc33Sdrh   memset(&x, 0, sizeof(x));
41751ad0ecdSdanielk1977   sqlite3_exec((sqlite*)sqlite3_user_data(context),
4184f26d6c4Sdrh       sqlite3_value_text(argv[0]),
419d1d9fc33Sdrh       execFuncCallback, &x, 0);
420d8123366Sdanielk1977   sqlite3_result_text(context, x.z, x.nUsed, SQLITE_TRANSIENT);
421d1d9fc33Sdrh   sqliteFree(x.z);
422c22bd47dSdrh }
423c22bd47dSdrh 
424c22bd47dSdrh /*
425c22bd47dSdrh ** Usage:  sqlite_test_create_function DB
426c22bd47dSdrh **
4276f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order
428c22bd47dSdrh ** to create a function named "x_coalesce".  This function does the same thing
429c22bd47dSdrh ** as the "coalesce" function.  This function also registers an SQL function
4306f8a503dSdanielk1977 ** named "x_sqlite3_exec" that invokes sqlite3_exec().  Invoking sqlite3_exec()
431c22bd47dSdrh ** in this way is illegal recursion and should raise an SQLITE_MISUSE error.
432c22bd47dSdrh ** The effect is similar to trying to use the same database connection from
433c22bd47dSdrh ** two threads at the same time.
434c22bd47dSdrh **
435c22bd47dSdrh ** The original motivation for this routine was to be able to call the
4366f8a503dSdanielk1977 ** sqlite3_create_function function while a query is in progress in order
437c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
438c22bd47dSdrh */
439c2eef3b3Sdrh static int test_create_function(
440c22bd47dSdrh   void *NotUsed,
441c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
442c22bd47dSdrh   int argc,              /* Number of arguments */
443c22bd47dSdrh   char **argv            /* Text of each argument */
444c22bd47dSdrh ){
445c22bd47dSdrh   sqlite *db;
446c22bd47dSdrh   extern void Md5_Register(sqlite*);
447c22bd47dSdrh   if( argc!=2 ){
448c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
449c22bd47dSdrh        " FILENAME\"", 0);
450c22bd47dSdrh     return TCL_ERROR;
451c22bd47dSdrh   }
452b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
453d8123366Sdanielk1977   sqlite3_create_function(db, "x_coalesce", -1, SQLITE_UTF8, 0, 0,
454d8123366Sdanielk1977       ifnullFunc, 0, 0);
455d8123366Sdanielk1977   sqlite3_create_function(db, "x_sqlite3_exec", 1, SQLITE_UTF8, 0, db,
4566590493dSdanielk1977       sqlite3ExecFunc, 0, 0);
457c22bd47dSdrh   return TCL_OK;
458c22bd47dSdrh }
459c22bd47dSdrh 
460c22bd47dSdrh /*
461c22bd47dSdrh ** Routines to implement the x_count() aggregate function.
462c22bd47dSdrh */
463c22bd47dSdrh typedef struct CountCtx CountCtx;
464c22bd47dSdrh struct CountCtx {
465c22bd47dSdrh   int n;
466c22bd47dSdrh };
4670ae8b831Sdanielk1977 static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
468c22bd47dSdrh   CountCtx *p;
4694f26d6c4Sdrh   p = sqlite3_aggregate_context(context, sizeof(*p));
4709c054830Sdrh   if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0]) ) && p ){
471c22bd47dSdrh     p->n++;
472c22bd47dSdrh   }
473c22bd47dSdrh }
4740ae8b831Sdanielk1977 static void countFinalize(sqlite3_context *context){
475c22bd47dSdrh   CountCtx *p;
4764f26d6c4Sdrh   p = sqlite3_aggregate_context(context, sizeof(*p));
477c572ef7fSdanielk1977   sqlite3_result_int(context, p ? p->n : 0);
478c22bd47dSdrh }
479c22bd47dSdrh 
480c22bd47dSdrh /*
481c22bd47dSdrh ** Usage:  sqlite_test_create_aggregate DB
482c22bd47dSdrh **
4836f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order
484c22bd47dSdrh ** to create a function named "x_count".  This function does the same thing
485c22bd47dSdrh ** as the "md5sum" function.
486c22bd47dSdrh **
487c22bd47dSdrh ** The original motivation for this routine was to be able to call the
4886f8a503dSdanielk1977 ** sqlite3_create_aggregate function while a query is in progress in order
489c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
490c22bd47dSdrh */
491c2eef3b3Sdrh static int test_create_aggregate(
492c22bd47dSdrh   void *NotUsed,
493c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
494c22bd47dSdrh   int argc,              /* Number of arguments */
495c22bd47dSdrh   char **argv            /* Text of each argument */
496c22bd47dSdrh ){
497c22bd47dSdrh   sqlite *db;
498c22bd47dSdrh   if( argc!=2 ){
499c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
500c22bd47dSdrh        " FILENAME\"", 0);
501c22bd47dSdrh     return TCL_ERROR;
502c22bd47dSdrh   }
503b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
504d8123366Sdanielk1977   sqlite3_create_function(db, "x_count", 0, SQLITE_UTF8, 0, 0, 0,
505d8123366Sdanielk1977       countStep,countFinalize);
506d8123366Sdanielk1977   sqlite3_create_function(db, "x_count", 1, SQLITE_UTF8, 0, 0, 0,
507d8123366Sdanielk1977       countStep,countFinalize);
508c22bd47dSdrh   return TCL_OK;
509c22bd47dSdrh }
510c22bd47dSdrh 
511c22bd47dSdrh 
512c22bd47dSdrh 
513c22bd47dSdrh /*
5146f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER
515d1bf3512Sdrh **
516d1bf3512Sdrh ** Call mprintf with three integer arguments
517d1bf3512Sdrh */
5186f8a503dSdanielk1977 static int sqlite3_mprintf_int(
519d1bf3512Sdrh   void *NotUsed,
520d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
521d1bf3512Sdrh   int argc,              /* Number of arguments */
522d1bf3512Sdrh   char **argv            /* Text of each argument */
523d1bf3512Sdrh ){
524d1bf3512Sdrh   int a[3], i;
525d1bf3512Sdrh   char *z;
526d1bf3512Sdrh   if( argc!=5 ){
527d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
528d1bf3512Sdrh        " FORMAT INT INT INT\"", 0);
529d1bf3512Sdrh     return TCL_ERROR;
530d1bf3512Sdrh   }
531d1bf3512Sdrh   for(i=2; i<5; i++){
532d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
533d1bf3512Sdrh   }
5346f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]);
535d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
5363f4fedb2Sdrh   sqlite3_free(z);
537d1bf3512Sdrh   return TCL_OK;
538d1bf3512Sdrh }
539d1bf3512Sdrh 
540d1bf3512Sdrh /*
5416f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT INTEGER INTEGER STRING
542d1bf3512Sdrh **
543d1bf3512Sdrh ** Call mprintf with two integer arguments and one string argument
544d1bf3512Sdrh */
5456f8a503dSdanielk1977 static int sqlite3_mprintf_str(
546d1bf3512Sdrh   void *NotUsed,
547d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
548d1bf3512Sdrh   int argc,              /* Number of arguments */
549d1bf3512Sdrh   char **argv            /* Text of each argument */
550d1bf3512Sdrh ){
551d1bf3512Sdrh   int a[3], i;
552d1bf3512Sdrh   char *z;
553f220b24fSchw   if( argc<4 || argc>5 ){
554d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
555f220b24fSchw        " FORMAT INT INT ?STRING?\"", 0);
556d1bf3512Sdrh     return TCL_ERROR;
557d1bf3512Sdrh   }
558d1bf3512Sdrh   for(i=2; i<4; i++){
559d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
560d1bf3512Sdrh   }
5616f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL);
562d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
5633f4fedb2Sdrh   sqlite3_free(z);
564d1bf3512Sdrh   return TCL_OK;
565d1bf3512Sdrh }
566d1bf3512Sdrh 
567d1bf3512Sdrh /*
5686f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT INTEGER INTEGER DOUBLE
569d1bf3512Sdrh **
570d1bf3512Sdrh ** Call mprintf with two integer arguments and one double argument
571d1bf3512Sdrh */
5726f8a503dSdanielk1977 static int sqlite3_mprintf_double(
573d1bf3512Sdrh   void *NotUsed,
574d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
575d1bf3512Sdrh   int argc,              /* Number of arguments */
576d1bf3512Sdrh   char **argv            /* Text of each argument */
577d1bf3512Sdrh ){
578d1bf3512Sdrh   int a[3], i;
579d1bf3512Sdrh   double r;
580d1bf3512Sdrh   char *z;
581d1bf3512Sdrh   if( argc!=5 ){
582d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
583d1bf3512Sdrh        " FORMAT INT INT STRING\"", 0);
584d1bf3512Sdrh     return TCL_ERROR;
585d1bf3512Sdrh   }
586d1bf3512Sdrh   for(i=2; i<4; i++){
587d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
588d1bf3512Sdrh   }
589d1bf3512Sdrh   if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR;
5906f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], r);
591d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
5923f4fedb2Sdrh   sqlite3_free(z);
593d1bf3512Sdrh   return TCL_OK;
594d1bf3512Sdrh }
595d1bf3512Sdrh 
596d1bf3512Sdrh /*
5976f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT DOUBLE DOUBLE
598b621c237Sdrh **
599b621c237Sdrh ** Call mprintf with a single double argument which is the product of the
600b621c237Sdrh ** two arguments given above.  This is used to generate overflow and underflow
601b621c237Sdrh ** doubles to test that they are converted properly.
602b621c237Sdrh */
6036f8a503dSdanielk1977 static int sqlite3_mprintf_scaled(
604b621c237Sdrh   void *NotUsed,
605b621c237Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
606b621c237Sdrh   int argc,              /* Number of arguments */
607b621c237Sdrh   char **argv            /* Text of each argument */
608b621c237Sdrh ){
609b621c237Sdrh   int i;
610b621c237Sdrh   double r[2];
611b621c237Sdrh   char *z;
612b621c237Sdrh   if( argc!=4 ){
613b621c237Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
614b621c237Sdrh        " FORMAT DOUBLE DOUBLE\"", 0);
615b621c237Sdrh     return TCL_ERROR;
616b621c237Sdrh   }
617b621c237Sdrh   for(i=2; i<4; i++){
618b621c237Sdrh     if( Tcl_GetDouble(interp, argv[i], &r[i-2]) ) return TCL_ERROR;
619b621c237Sdrh   }
6206f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], r[0]*r[1]);
621b621c237Sdrh   Tcl_AppendResult(interp, z, 0);
6223f4fedb2Sdrh   sqlite3_free(z);
623b621c237Sdrh   return TCL_OK;
624b621c237Sdrh }
625b621c237Sdrh 
626b621c237Sdrh /*
627daffd0e5Sdrh ** Usage: sqlite_malloc_fail N
628daffd0e5Sdrh **
629afa4a020Sdrh ** Rig sqliteMalloc() to fail on the N-th call.  Turn off this mechanism
6306f8a503dSdanielk1977 ** and reset the sqlite3_malloc_failed variable is N==0.
631daffd0e5Sdrh */
632faa57accSdrh #ifdef SQLITE_DEBUG
633daffd0e5Sdrh static int sqlite_malloc_fail(
634daffd0e5Sdrh   void *NotUsed,
635daffd0e5Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
636daffd0e5Sdrh   int argc,              /* Number of arguments */
637daffd0e5Sdrh   char **argv            /* Text of each argument */
638daffd0e5Sdrh ){
639daffd0e5Sdrh   int n;
640daffd0e5Sdrh   if( argc!=2 ){
641daffd0e5Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0);
642daffd0e5Sdrh     return TCL_ERROR;
643daffd0e5Sdrh   }
644daffd0e5Sdrh   if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
6456f8a503dSdanielk1977   sqlite3_iMallocFail = n;
6466f8a503dSdanielk1977   sqlite3_malloc_failed = 0;
647daffd0e5Sdrh   return TCL_OK;
648daffd0e5Sdrh }
649daffd0e5Sdrh #endif
650daffd0e5Sdrh 
651daffd0e5Sdrh /*
652daffd0e5Sdrh ** Usage: sqlite_malloc_stat
653daffd0e5Sdrh **
654daffd0e5Sdrh ** Return the number of prior calls to sqliteMalloc() and sqliteFree().
655daffd0e5Sdrh */
656faa57accSdrh #ifdef SQLITE_DEBUG
657daffd0e5Sdrh static int sqlite_malloc_stat(
658daffd0e5Sdrh   void *NotUsed,
659daffd0e5Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
660daffd0e5Sdrh   int argc,              /* Number of arguments */
661daffd0e5Sdrh   char **argv            /* Text of each argument */
662daffd0e5Sdrh ){
663daffd0e5Sdrh   char zBuf[200];
6646f8a503dSdanielk1977   sprintf(zBuf, "%d %d %d", sqlite3_nMalloc, sqlite3_nFree, sqlite3_iMallocFail);
665daffd0e5Sdrh   Tcl_AppendResult(interp, zBuf, 0);
666daffd0e5Sdrh   return TCL_OK;
667daffd0e5Sdrh }
668daffd0e5Sdrh #endif
669daffd0e5Sdrh 
670daffd0e5Sdrh /*
67128b4e489Sdrh ** Usage:  sqlite_abort
67228b4e489Sdrh **
67328b4e489Sdrh ** Shutdown the process immediately.  This is not a clean shutdown.
67428b4e489Sdrh ** This command is used to test the recoverability of a database in
67528b4e489Sdrh ** the event of a program crash.
67628b4e489Sdrh */
67728b4e489Sdrh static int sqlite_abort(
67828b4e489Sdrh   void *NotUsed,
67928b4e489Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
68028b4e489Sdrh   int argc,              /* Number of arguments */
68128b4e489Sdrh   char **argv            /* Text of each argument */
68228b4e489Sdrh ){
68328b4e489Sdrh   assert( interp==0 );   /* This will always fail */
68428b4e489Sdrh   return TCL_OK;
68528b4e489Sdrh }
68628b4e489Sdrh 
68728b4e489Sdrh /*
6886cbe1f1bSdrh ** The following routine is a user-defined SQL function whose purpose
6896cbe1f1bSdrh ** is to test the sqlite_set_result() API.
6906cbe1f1bSdrh */
6910ae8b831Sdanielk1977 static void testFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
6926cbe1f1bSdrh   while( argc>=2 ){
6934f26d6c4Sdrh     const char *zArg0 = sqlite3_value_text(argv[0]);
6946d88bad4Sdanielk1977     if( zArg0 ){
6956d88bad4Sdanielk1977       if( 0==sqlite3StrICmp(zArg0, "int") ){
6966d88bad4Sdanielk1977         sqlite3_result_int(context, sqlite3_value_int(argv[1]));
6976d88bad4Sdanielk1977       }else if( sqlite3StrICmp(zArg0,"int64")==0 ){
6986d88bad4Sdanielk1977         sqlite3_result_int64(context, sqlite3_value_int64(argv[1]));
69951ad0ecdSdanielk1977       }else if( sqlite3StrICmp(zArg0,"string")==0 ){
700d8123366Sdanielk1977         sqlite3_result_text(context, sqlite3_value_text(argv[1]), -1,
701d8123366Sdanielk1977             SQLITE_TRANSIENT);
70251ad0ecdSdanielk1977       }else if( sqlite3StrICmp(zArg0,"double")==0 ){
7036d88bad4Sdanielk1977         sqlite3_result_double(context, sqlite3_value_double(argv[1]));
7046d88bad4Sdanielk1977       }else if( sqlite3StrICmp(zArg0,"null")==0 ){
7056d88bad4Sdanielk1977         sqlite3_result_null(context);
7066d88bad4Sdanielk1977       }else if( sqlite3StrICmp(zArg0,"value")==0 ){
7076d88bad4Sdanielk1977         sqlite3_result_value(context, argv[sqlite3_value_int(argv[1])]);
7086cbe1f1bSdrh       }else{
7096d88bad4Sdanielk1977         goto error_out;
7106d88bad4Sdanielk1977       }
7116d88bad4Sdanielk1977     }else{
7126d88bad4Sdanielk1977       goto error_out;
7136cbe1f1bSdrh     }
7146cbe1f1bSdrh     argc -= 2;
7156cbe1f1bSdrh     argv += 2;
7166cbe1f1bSdrh   }
7176d88bad4Sdanielk1977   return;
7186d88bad4Sdanielk1977 
7196d88bad4Sdanielk1977 error_out:
7206d88bad4Sdanielk1977   sqlite3_result_error(context,"first argument should be one of: "
7216d88bad4Sdanielk1977       "int int64 string double null value", -1);
7226cbe1f1bSdrh }
7236cbe1f1bSdrh 
7246cbe1f1bSdrh /*
7256cbe1f1bSdrh ** Usage:   sqlite_register_test_function  DB  NAME
7266cbe1f1bSdrh **
7276cbe1f1bSdrh ** Register the test SQL function on the database DB under the name NAME.
7286cbe1f1bSdrh */
729c2eef3b3Sdrh static int test_register_func(
7306cbe1f1bSdrh   void *NotUsed,
7316cbe1f1bSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
7326cbe1f1bSdrh   int argc,              /* Number of arguments */
7336cbe1f1bSdrh   char **argv            /* Text of each argument */
7346cbe1f1bSdrh ){
7356cbe1f1bSdrh   sqlite *db;
7366cbe1f1bSdrh   int rc;
7376cbe1f1bSdrh   if( argc!=3 ){
7386cbe1f1bSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
7396cbe1f1bSdrh        " DB FUNCTION-NAME", 0);
7406cbe1f1bSdrh     return TCL_ERROR;
7416cbe1f1bSdrh   }
742b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
743d8123366Sdanielk1977   rc = sqlite3_create_function(db, argv[2], -1, SQLITE_UTF8, 0, 0,
744d8123366Sdanielk1977       testFunc, 0, 0);
7456cbe1f1bSdrh   if( rc!=0 ){
746f20b21c8Sdanielk1977     Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);
7476cbe1f1bSdrh     return TCL_ERROR;
7486cbe1f1bSdrh   }
7496cbe1f1bSdrh   return TCL_OK;
7506cbe1f1bSdrh }
7516cbe1f1bSdrh 
7526cbe1f1bSdrh /*
753106bb236Sdanielk1977 ** Usage:  sqlite3_finalize  STMT
754b86ccfb2Sdrh **
755106bb236Sdanielk1977 ** Finalize a statement handle.
756b86ccfb2Sdrh */
757b86ccfb2Sdrh static int test_finalize(
758106bb236Sdanielk1977   void * clientData,
759106bb236Sdanielk1977   Tcl_Interp *interp,
760106bb236Sdanielk1977   int objc,
761106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
762b86ccfb2Sdrh ){
763106bb236Sdanielk1977   sqlite3_stmt *pStmt;
764b86ccfb2Sdrh   int rc;
765106bb236Sdanielk1977 
766106bb236Sdanielk1977   if( objc!=2 ){
767106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
768106bb236Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
769b86ccfb2Sdrh     return TCL_ERROR;
770b86ccfb2Sdrh   }
771106bb236Sdanielk1977 
772106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
773106bb236Sdanielk1977 
774fc57d7bfSdanielk1977   rc = sqlite3_finalize(pStmt);
775b77f5dadSdanielk1977   Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
776106bb236Sdanielk1977   return TCL_OK;
777106bb236Sdanielk1977 }
778106bb236Sdanielk1977 
779106bb236Sdanielk1977 /*
780106bb236Sdanielk1977 ** Usage:  sqlite3_reset  STMT
781106bb236Sdanielk1977 **
782106bb236Sdanielk1977 ** Finalize a statement handle.
783106bb236Sdanielk1977 */
784106bb236Sdanielk1977 static int test_reset(
785106bb236Sdanielk1977   void * clientData,
786106bb236Sdanielk1977   Tcl_Interp *interp,
787106bb236Sdanielk1977   int objc,
788106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
789106bb236Sdanielk1977 ){
790106bb236Sdanielk1977   sqlite3_stmt *pStmt;
791106bb236Sdanielk1977   int rc;
792106bb236Sdanielk1977 
793106bb236Sdanielk1977   if( objc!=2 ){
794106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
795106bb236Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
796106bb236Sdanielk1977     return TCL_ERROR;
797106bb236Sdanielk1977   }
798106bb236Sdanielk1977 
799106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
800106bb236Sdanielk1977 
801fc57d7bfSdanielk1977   rc = sqlite3_reset(pStmt);
802106bb236Sdanielk1977   if( rc ){
803b86ccfb2Sdrh     return TCL_ERROR;
804b86ccfb2Sdrh   }
805b86ccfb2Sdrh   return TCL_OK;
806b86ccfb2Sdrh }
807b86ccfb2Sdrh 
8085a38705eSdrh /*
809fbcd585fSdanielk1977 ** Usage:  sqlite3_changes DB
81050457896Sdrh **
811fbcd585fSdanielk1977 ** Return the number of changes made to the database by the last SQL
812fbcd585fSdanielk1977 ** execution.
81350457896Sdrh */
814fbcd585fSdanielk1977 static int test_changes(
815fbcd585fSdanielk1977   void * clientData,
816fbcd585fSdanielk1977   Tcl_Interp *interp,
817fbcd585fSdanielk1977   int objc,
818fbcd585fSdanielk1977   Tcl_Obj *CONST objv[]
819fbcd585fSdanielk1977 ){
820fbcd585fSdanielk1977   sqlite3 *db;
821fbcd585fSdanielk1977   if( objc!=2 ){
822fbcd585fSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
823fbcd585fSdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
824fbcd585fSdanielk1977     return TCL_ERROR;
825fbcd585fSdanielk1977   }
826fbcd585fSdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
827fbcd585fSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_changes(db)));
828fbcd585fSdanielk1977   return TCL_OK;
829fbcd585fSdanielk1977 }
83050457896Sdrh 
83150457896Sdrh /*
8327c972decSdrh ** This is the "static_bind_value" that variables are bound to when
8336f8a503dSdanielk1977 ** the FLAG option of sqlite3_bind is "static"
83450457896Sdrh */
8357c972decSdrh static char *sqlite_static_bind_value = 0;
8367c972decSdrh 
8377c972decSdrh /*
8386f8a503dSdanielk1977 ** Usage:  sqlite3_bind  VM  IDX  VALUE  FLAGS
8397c972decSdrh **
8407c972decSdrh ** Sets the value of the IDX-th occurance of "?" in the original SQL
8417c972decSdrh ** string.  VALUE is the new value.  If FLAGS=="null" then VALUE is
8427c972decSdrh ** ignored and the value is set to NULL.  If FLAGS=="static" then
8437c972decSdrh ** the value is set to the value of a static variable named
8447c972decSdrh ** "sqlite_static_bind_value".  If FLAGS=="normal" then a copy
8457c972decSdrh ** of the VALUE is made.
8467c972decSdrh */
8477c972decSdrh static int test_bind(
84850457896Sdrh   void *NotUsed,
84950457896Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
85050457896Sdrh   int argc,              /* Number of arguments */
85150457896Sdrh   char **argv            /* Text of each argument */
85250457896Sdrh ){
853fc57d7bfSdanielk1977   sqlite3_stmt *pStmt;
85450457896Sdrh   int rc;
8557c972decSdrh   int idx;
8567c972decSdrh   if( argc!=5 ){
85750457896Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
8587c972decSdrh        " VM IDX VALUE (null|static|normal)\"", 0);
85950457896Sdrh     return TCL_ERROR;
86050457896Sdrh   }
861fc57d7bfSdanielk1977   if( getStmtPointer(interp, argv[1], &pStmt) ) return TCL_ERROR;
8627c972decSdrh   if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR;
8637c972decSdrh   if( strcmp(argv[4],"null")==0 ){
864fc57d7bfSdanielk1977     rc = sqlite3_bind_null(pStmt, idx);
8657c972decSdrh   }else if( strcmp(argv[4],"static")==0 ){
866fc57d7bfSdanielk1977     rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0);
8677c972decSdrh   }else if( strcmp(argv[4],"normal")==0 ){
868d8123366Sdanielk1977     rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, SQLITE_TRANSIENT);
8697c972decSdrh   }else{
8707c972decSdrh     Tcl_AppendResult(interp, "4th argument should be "
8717c972decSdrh         "\"null\" or \"static\" or \"normal\"", 0);
8727c972decSdrh     return TCL_ERROR;
8737c972decSdrh   }
87450457896Sdrh   if( rc ){
87550457896Sdrh     char zBuf[50];
87650457896Sdrh     sprintf(zBuf, "(%d) ", rc);
877f20b21c8Sdanielk1977     Tcl_AppendResult(interp, zBuf, sqlite3ErrStr(rc), 0);
87850457896Sdrh     return TCL_ERROR;
87950457896Sdrh   }
88050457896Sdrh   return TCL_OK;
88150457896Sdrh }
88250457896Sdrh 
8834e6af134Sdanielk1977 
8844e6af134Sdanielk1977 /*
8854e6af134Sdanielk1977 ** Usage: add_test_collate <db ptr> <utf8> <utf16le> <utf16be>
8864e6af134Sdanielk1977 **
8874e6af134Sdanielk1977 ** This function is used to test that SQLite selects the correct collation
8884e6af134Sdanielk1977 ** sequence callback when multiple versions (for different text encodings)
8894e6af134Sdanielk1977 ** are available.
8904e6af134Sdanielk1977 **
8914e6af134Sdanielk1977 ** Calling this routine registers the collation sequence "test_collate"
8924e6af134Sdanielk1977 ** with database handle <db>. The second argument must be a list of three
8934e6af134Sdanielk1977 ** boolean values. If the first is true, then a version of test_collate is
8944e6af134Sdanielk1977 ** registered for UTF-8, if the second is true, a version is registered for
8954e6af134Sdanielk1977 ** UTF-16le, if the third is true, a UTF-16be version is available.
8964e6af134Sdanielk1977 ** Previous versions of test_collate are deleted.
8974e6af134Sdanielk1977 **
8984e6af134Sdanielk1977 ** The collation sequence test_collate is implemented by calling the
8994e6af134Sdanielk1977 ** following TCL script:
9004e6af134Sdanielk1977 **
9014e6af134Sdanielk1977 **   "test_collate <enc> <lhs> <rhs>"
9024e6af134Sdanielk1977 **
9034e6af134Sdanielk1977 ** The <lhs> and <rhs> are the two values being compared, encoded in UTF-8.
9044e6af134Sdanielk1977 ** The <enc> parameter is the encoding of the collation function that
9054e6af134Sdanielk1977 ** SQLite selected to call. The TCL test script implements the
9064e6af134Sdanielk1977 ** "test_collate" proc.
9074e6af134Sdanielk1977 **
9084e6af134Sdanielk1977 ** Note that this will only work with one intepreter at a time, as the
9094e6af134Sdanielk1977 ** interp pointer to use when evaluating the TCL script is stored in
9104e6af134Sdanielk1977 ** pTestCollateInterp.
9114e6af134Sdanielk1977 */
9124e6af134Sdanielk1977 static Tcl_Interp* pTestCollateInterp;
9134e6af134Sdanielk1977 static int test_collate_func(
9144e6af134Sdanielk1977   void *pCtx,
9154e6af134Sdanielk1977   int nA, const void *zA,
9164e6af134Sdanielk1977   int nB, const void *zB
9174e6af134Sdanielk1977 ){
9184e6af134Sdanielk1977   Tcl_Interp *i = pTestCollateInterp;
9194e6af134Sdanielk1977   int encin = (int)pCtx;
9204e6af134Sdanielk1977   int res;
9214e6af134Sdanielk1977 
9224e6af134Sdanielk1977   sqlite3_value *pVal;
9234e6af134Sdanielk1977   Tcl_Obj *pX;
9244e6af134Sdanielk1977 
9254e6af134Sdanielk1977   pX = Tcl_NewStringObj("test_collate", -1);
9264e6af134Sdanielk1977   Tcl_IncrRefCount(pX);
9274e6af134Sdanielk1977 
9284e6af134Sdanielk1977   switch( encin ){
9294e6af134Sdanielk1977     case SQLITE_UTF8:
9304e6af134Sdanielk1977       Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-8",-1));
9314e6af134Sdanielk1977       break;
9324e6af134Sdanielk1977     case SQLITE_UTF16LE:
9334e6af134Sdanielk1977       Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-16LE",-1));
9344e6af134Sdanielk1977       break;
9354e6af134Sdanielk1977     case SQLITE_UTF16BE:
9364e6af134Sdanielk1977       Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-16BE",-1));
9374e6af134Sdanielk1977       break;
9384e6af134Sdanielk1977     default:
9394e6af134Sdanielk1977       assert(0);
9404e6af134Sdanielk1977   }
9414e6af134Sdanielk1977 
9424e6af134Sdanielk1977   pVal = sqlite3ValueNew();
943*bfd6cce5Sdanielk1977   sqlite3ValueSetStr(pVal, nA, zA, encin, SQLITE_STATIC);
9444e6af134Sdanielk1977   Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj(sqlite3_value_text(pVal),-1));
945*bfd6cce5Sdanielk1977   sqlite3ValueSetStr(pVal, nB, zB, encin, SQLITE_STATIC);
9464e6af134Sdanielk1977   Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj(sqlite3_value_text(pVal),-1));
9474e6af134Sdanielk1977   sqlite3ValueFree(pVal);
9484e6af134Sdanielk1977 
9494e6af134Sdanielk1977   Tcl_EvalObjEx(i, pX, 0);
9504e6af134Sdanielk1977   Tcl_DecrRefCount(pX);
9514e6af134Sdanielk1977   Tcl_GetIntFromObj(i, Tcl_GetObjResult(i), &res);
9524e6af134Sdanielk1977   return res;
9534e6af134Sdanielk1977 }
9544e6af134Sdanielk1977 static int test_collate(
9554e6af134Sdanielk1977   void * clientData,
9564e6af134Sdanielk1977   Tcl_Interp *interp,
9574e6af134Sdanielk1977   int objc,
9584e6af134Sdanielk1977   Tcl_Obj *CONST objv[]
9594e6af134Sdanielk1977 ){
9604e6af134Sdanielk1977   sqlite3 *db;
9614e6af134Sdanielk1977   int val;
9624e6af134Sdanielk1977 
9634e6af134Sdanielk1977   if( objc!=5 ) goto bad_args;
9644e6af134Sdanielk1977   pTestCollateInterp = interp;
9654e6af134Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
9664e6af134Sdanielk1977 
9674e6af134Sdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR;
9684e6af134Sdanielk1977   sqlite3_create_collation(db, "test_collate", SQLITE_UTF8,
9694e6af134Sdanielk1977         (void *)SQLITE_UTF8, val?test_collate_func:0);
9704e6af134Sdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &val) ) return TCL_ERROR;
9714e6af134Sdanielk1977   sqlite3_create_collation(db, "test_collate", SQLITE_UTF16LE,
9724e6af134Sdanielk1977         (void *)SQLITE_UTF16LE, val?test_collate_func:0);
9734e6af134Sdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[4], &val) ) return TCL_ERROR;
9744e6af134Sdanielk1977   sqlite3_create_collation(db, "test_collate", SQLITE_UTF16BE,
9754e6af134Sdanielk1977         (void *)SQLITE_UTF16BE, val?test_collate_func:0);
9764e6af134Sdanielk1977 
9774e6af134Sdanielk1977   return TCL_OK;
9784e6af134Sdanielk1977 
9794e6af134Sdanielk1977 bad_args:
9804e6af134Sdanielk1977   Tcl_AppendResult(interp, "wrong # args: should be \"",
9814e6af134Sdanielk1977       Tcl_GetStringFromObj(objv[0], 0), " <DB> <utf8> <utf16le> <utf16be>", 0);
9824e6af134Sdanielk1977   return TCL_ERROR;
9834e6af134Sdanielk1977 }
9844e6af134Sdanielk1977 
98550457896Sdrh /*
98699ee3600Sdrh ** Usage:    breakpoint
98799ee3600Sdrh **
98899ee3600Sdrh ** This routine exists for one purpose - to provide a place to put a
98999ee3600Sdrh ** breakpoint with GDB that can be triggered using TCL code.  The use
99099ee3600Sdrh ** for this is when a particular test fails on (say) the 1485th iteration.
99199ee3600Sdrh ** In the TCL test script, we can add code like this:
99299ee3600Sdrh **
99399ee3600Sdrh **     if {$i==1485} breakpoint
99499ee3600Sdrh **
99599ee3600Sdrh ** Then run testfixture in the debugger and wait for the breakpoint to
99699ee3600Sdrh ** fire.  Then additional breakpoints can be set to trace down the bug.
99799ee3600Sdrh */
99899ee3600Sdrh static int test_breakpoint(
99999ee3600Sdrh   void *NotUsed,
100099ee3600Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
100199ee3600Sdrh   int argc,              /* Number of arguments */
100299ee3600Sdrh   char **argv            /* Text of each argument */
100399ee3600Sdrh ){
100499ee3600Sdrh   return TCL_OK;         /* Do nothing */
100599ee3600Sdrh }
100699ee3600Sdrh 
100751e3d8e2Sdanielk1977 static int test_bind_int32(
100851e3d8e2Sdanielk1977   void * clientData,
100951e3d8e2Sdanielk1977   Tcl_Interp *interp,
101051e3d8e2Sdanielk1977   int objc,
101151e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
101251e3d8e2Sdanielk1977 ){
101351e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
101451e3d8e2Sdanielk1977   int idx;
101551e3d8e2Sdanielk1977   int value;
101651e3d8e2Sdanielk1977   int rc;
101751e3d8e2Sdanielk1977 
101851e3d8e2Sdanielk1977   if( objc!=4 ){
101951e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
102051e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
102151e3d8e2Sdanielk1977     return TCL_ERROR;
102251e3d8e2Sdanielk1977   }
102351e3d8e2Sdanielk1977 
102451e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
102551e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
102651e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &value) ) return TCL_ERROR;
102751e3d8e2Sdanielk1977 
1028c572ef7fSdanielk1977   rc = sqlite3_bind_int(pStmt, idx, value);
102951e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
103051e3d8e2Sdanielk1977     return TCL_ERROR;
103151e3d8e2Sdanielk1977   }
103251e3d8e2Sdanielk1977 
103351e3d8e2Sdanielk1977   return TCL_OK;
103451e3d8e2Sdanielk1977 }
103551e3d8e2Sdanielk1977 
103651e3d8e2Sdanielk1977 static int test_bind_int64(
103751e3d8e2Sdanielk1977   void * clientData,
103851e3d8e2Sdanielk1977   Tcl_Interp *interp,
103951e3d8e2Sdanielk1977   int objc,
104051e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
104151e3d8e2Sdanielk1977 ){
104251e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
104351e3d8e2Sdanielk1977   int idx;
104451e3d8e2Sdanielk1977   i64 value;
104551e3d8e2Sdanielk1977   int rc;
104651e3d8e2Sdanielk1977 
104751e3d8e2Sdanielk1977   if( objc!=4 ){
104851e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
104951e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
105051e3d8e2Sdanielk1977     return TCL_ERROR;
105151e3d8e2Sdanielk1977   }
105251e3d8e2Sdanielk1977 
105351e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
105451e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
105551e3d8e2Sdanielk1977   if( Tcl_GetWideIntFromObj(interp, objv[3], &value) ) return TCL_ERROR;
105651e3d8e2Sdanielk1977 
105751e3d8e2Sdanielk1977   rc = sqlite3_bind_int64(pStmt, idx, value);
105851e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
105951e3d8e2Sdanielk1977     return TCL_ERROR;
106051e3d8e2Sdanielk1977   }
106151e3d8e2Sdanielk1977 
106251e3d8e2Sdanielk1977   return TCL_OK;
106351e3d8e2Sdanielk1977 }
106451e3d8e2Sdanielk1977 
106551e3d8e2Sdanielk1977 static int test_bind_double(
106651e3d8e2Sdanielk1977   void * clientData,
106751e3d8e2Sdanielk1977   Tcl_Interp *interp,
106851e3d8e2Sdanielk1977   int objc,
106951e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
107051e3d8e2Sdanielk1977 ){
107151e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
107251e3d8e2Sdanielk1977   int idx;
107351e3d8e2Sdanielk1977   double value;
107451e3d8e2Sdanielk1977   int rc;
107551e3d8e2Sdanielk1977 
107651e3d8e2Sdanielk1977   if( objc!=4 ){
107751e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
107851e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>", 0);
107951e3d8e2Sdanielk1977     return TCL_ERROR;
108051e3d8e2Sdanielk1977   }
108151e3d8e2Sdanielk1977 
108251e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
108351e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
108451e3d8e2Sdanielk1977   if( Tcl_GetDoubleFromObj(interp, objv[3], &value) ) return TCL_ERROR;
108551e3d8e2Sdanielk1977 
108651e3d8e2Sdanielk1977   rc = sqlite3_bind_double(pStmt, idx, value);
108751e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
108851e3d8e2Sdanielk1977     return TCL_ERROR;
108951e3d8e2Sdanielk1977   }
109051e3d8e2Sdanielk1977 
109151e3d8e2Sdanielk1977   return TCL_OK;
109251e3d8e2Sdanielk1977 }
109351e3d8e2Sdanielk1977 
109451e3d8e2Sdanielk1977 static int test_bind_null(
109551e3d8e2Sdanielk1977   void * clientData,
109651e3d8e2Sdanielk1977   Tcl_Interp *interp,
109751e3d8e2Sdanielk1977   int objc,
109851e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
109951e3d8e2Sdanielk1977 ){
110051e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
110151e3d8e2Sdanielk1977   int idx;
110251e3d8e2Sdanielk1977   int rc;
110351e3d8e2Sdanielk1977 
110451e3d8e2Sdanielk1977   if( objc!=3 ){
110551e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
110651e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.>", 0);
110751e3d8e2Sdanielk1977     return TCL_ERROR;
110851e3d8e2Sdanielk1977   }
110951e3d8e2Sdanielk1977 
111051e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
111151e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
111251e3d8e2Sdanielk1977 
111351e3d8e2Sdanielk1977   rc = sqlite3_bind_null(pStmt, idx);
111451e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
111551e3d8e2Sdanielk1977     return TCL_ERROR;
111651e3d8e2Sdanielk1977   }
111751e3d8e2Sdanielk1977 
111851e3d8e2Sdanielk1977   return TCL_OK;
111951e3d8e2Sdanielk1977 }
112051e3d8e2Sdanielk1977 
112151e3d8e2Sdanielk1977 static int test_bind_text(
112251e3d8e2Sdanielk1977   void * clientData,
112351e3d8e2Sdanielk1977   Tcl_Interp *interp,
112451e3d8e2Sdanielk1977   int objc,
112551e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
112651e3d8e2Sdanielk1977 ){
112751e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
112851e3d8e2Sdanielk1977   int idx;
112951e3d8e2Sdanielk1977   int bytes;
113051e3d8e2Sdanielk1977   char *value;
113151e3d8e2Sdanielk1977   int rc;
113251e3d8e2Sdanielk1977 
113351e3d8e2Sdanielk1977   if( objc!=5 ){
113451e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
113551e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
113651e3d8e2Sdanielk1977         " <bytes>", 0);
113751e3d8e2Sdanielk1977     return TCL_ERROR;
113851e3d8e2Sdanielk1977   }
113951e3d8e2Sdanielk1977 
114051e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
114151e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
114251e3d8e2Sdanielk1977   value = Tcl_GetString(objv[3]);
114351e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
114451e3d8e2Sdanielk1977 
1145d8123366Sdanielk1977   rc = sqlite3_bind_text(pStmt, idx, value, bytes, SQLITE_TRANSIENT);
114651e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
114751e3d8e2Sdanielk1977     return TCL_ERROR;
114851e3d8e2Sdanielk1977   }
114951e3d8e2Sdanielk1977 
115051e3d8e2Sdanielk1977   return TCL_OK;
115151e3d8e2Sdanielk1977 }
115251e3d8e2Sdanielk1977 
115351e3d8e2Sdanielk1977 static int test_bind_text16(
115451e3d8e2Sdanielk1977   void * clientData,
115551e3d8e2Sdanielk1977   Tcl_Interp *interp,
115651e3d8e2Sdanielk1977   int objc,
115751e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
115851e3d8e2Sdanielk1977 ){
115951e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
116051e3d8e2Sdanielk1977   int idx;
116151e3d8e2Sdanielk1977   int bytes;
116251e3d8e2Sdanielk1977   char *value;
116351e3d8e2Sdanielk1977   int rc;
116451e3d8e2Sdanielk1977 
116551e3d8e2Sdanielk1977   if( objc!=5 ){
116651e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
116751e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
116851e3d8e2Sdanielk1977         " <bytes>", 0);
116951e3d8e2Sdanielk1977     return TCL_ERROR;
117051e3d8e2Sdanielk1977   }
117151e3d8e2Sdanielk1977 
117251e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
117351e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
117451e3d8e2Sdanielk1977   value = Tcl_GetByteArrayFromObj(objv[3], 0);
117551e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
117651e3d8e2Sdanielk1977 
1177d8123366Sdanielk1977   rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, SQLITE_TRANSIENT);
117851e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
117951e3d8e2Sdanielk1977     return TCL_ERROR;
118051e3d8e2Sdanielk1977   }
118151e3d8e2Sdanielk1977 
118251e3d8e2Sdanielk1977   return TCL_OK;
118351e3d8e2Sdanielk1977 }
118451e3d8e2Sdanielk1977 
118551e3d8e2Sdanielk1977 static int test_bind_blob(
118651e3d8e2Sdanielk1977   void * clientData,
118751e3d8e2Sdanielk1977   Tcl_Interp *interp,
118851e3d8e2Sdanielk1977   int objc,
118951e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
119051e3d8e2Sdanielk1977 ){
119151e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
119251e3d8e2Sdanielk1977   int idx;
119351e3d8e2Sdanielk1977   int bytes;
119451e3d8e2Sdanielk1977   char *value;
119551e3d8e2Sdanielk1977   int rc;
119651e3d8e2Sdanielk1977 
119751e3d8e2Sdanielk1977   if( objc!=5 ){
119851e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
119951e3d8e2Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT> <param no.> <value>"
120051e3d8e2Sdanielk1977         " <bytes>", 0);
120151e3d8e2Sdanielk1977     return TCL_ERROR;
120251e3d8e2Sdanielk1977   }
120351e3d8e2Sdanielk1977 
120451e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
120551e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
120651e3d8e2Sdanielk1977   value = Tcl_GetString(objv[3]);
120749e4643eSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
120851e3d8e2Sdanielk1977 
1209d8123366Sdanielk1977   rc = sqlite3_bind_blob(pStmt, idx, value, bytes, SQLITE_TRANSIENT);
121051e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
121151e3d8e2Sdanielk1977     return TCL_ERROR;
121251e3d8e2Sdanielk1977   }
121351e3d8e2Sdanielk1977 
121451e3d8e2Sdanielk1977   return TCL_OK;
121551e3d8e2Sdanielk1977 }
121651e3d8e2Sdanielk1977 
121799ee3600Sdrh /*
12186622cce3Sdanielk1977 ** Usage: sqlite3_errcode DB
12196622cce3Sdanielk1977 **
12206622cce3Sdanielk1977 ** Return the string representation of the most recent sqlite3_* API
12216622cce3Sdanielk1977 ** error code. e.g. "SQLITE_ERROR".
12226622cce3Sdanielk1977 */
12236622cce3Sdanielk1977 static int test_errcode(
12246622cce3Sdanielk1977   void * clientData,
12256622cce3Sdanielk1977   Tcl_Interp *interp,
12266622cce3Sdanielk1977   int objc,
12276622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
12286622cce3Sdanielk1977 ){
12296622cce3Sdanielk1977   sqlite3 *db;
12306622cce3Sdanielk1977 
12316622cce3Sdanielk1977   if( objc!=2 ){
12326622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
12336622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
12346622cce3Sdanielk1977     return TCL_ERROR;
12356622cce3Sdanielk1977   }
12366622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
12376622cce3Sdanielk1977   Tcl_SetResult(interp, (char *)errorName(sqlite3_errcode(db)), 0);
12386622cce3Sdanielk1977   return TCL_OK;
12396622cce3Sdanielk1977 }
12406622cce3Sdanielk1977 
12416622cce3Sdanielk1977 /*
12426622cce3Sdanielk1977 ** Usage:   test_errmsg DB
12436622cce3Sdanielk1977 **
12446622cce3Sdanielk1977 ** Returns the UTF-8 representation of the error message string for the
12456622cce3Sdanielk1977 ** most recent sqlite3_* API call.
12466622cce3Sdanielk1977 */
12476622cce3Sdanielk1977 static int test_errmsg(
12486622cce3Sdanielk1977   void * clientData,
12496622cce3Sdanielk1977   Tcl_Interp *interp,
12506622cce3Sdanielk1977   int objc,
12516622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
12526622cce3Sdanielk1977 ){
12536622cce3Sdanielk1977   sqlite *db;
12546622cce3Sdanielk1977   const char *zErr;
12556622cce3Sdanielk1977 
12566622cce3Sdanielk1977   if( objc!=2 ){
12576622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
12586622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
12596622cce3Sdanielk1977     return TCL_ERROR;
12606622cce3Sdanielk1977   }
12616622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
12626622cce3Sdanielk1977 
12636622cce3Sdanielk1977   zErr = sqlite3_errmsg(db);
12646622cce3Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
12656622cce3Sdanielk1977   return TCL_OK;
12666622cce3Sdanielk1977 }
12676622cce3Sdanielk1977 
12686622cce3Sdanielk1977 /*
12696622cce3Sdanielk1977 ** Usage:   test_errmsg16 DB
12706622cce3Sdanielk1977 **
12716622cce3Sdanielk1977 ** Returns the UTF-16 representation of the error message string for the
12726622cce3Sdanielk1977 ** most recent sqlite3_* API call. This is a byte array object at the TCL
12736622cce3Sdanielk1977 ** level, and it includes the 0x00 0x00 terminator bytes at the end of the
12746622cce3Sdanielk1977 ** UTF-16 string.
12756622cce3Sdanielk1977 */
12766622cce3Sdanielk1977 static int test_errmsg16(
12776622cce3Sdanielk1977   void * clientData,
12786622cce3Sdanielk1977   Tcl_Interp *interp,
12796622cce3Sdanielk1977   int objc,
12806622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
12816622cce3Sdanielk1977 ){
12826622cce3Sdanielk1977   sqlite *db;
12836622cce3Sdanielk1977   const void *zErr;
12846622cce3Sdanielk1977   int bytes;
12856622cce3Sdanielk1977 
12866622cce3Sdanielk1977   if( objc!=2 ){
12876622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
12886622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
12896622cce3Sdanielk1977     return TCL_ERROR;
12906622cce3Sdanielk1977   }
12916622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
12926622cce3Sdanielk1977 
12936622cce3Sdanielk1977   zErr = sqlite3_errmsg16(db);
12946622cce3Sdanielk1977   bytes = sqlite3utf16ByteLen(zErr, -1);
12956622cce3Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes));
12966622cce3Sdanielk1977   return TCL_OK;
12976622cce3Sdanielk1977 }
12986622cce3Sdanielk1977 
12996622cce3Sdanielk1977 /*
13006622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar
13016622cce3Sdanielk1977 **
13026622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
13036622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global
13046622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A
13056622cce3Sdanielk1977 ** STMT handle is returned.
13066622cce3Sdanielk1977 */
13076622cce3Sdanielk1977 static int test_prepare(
13086622cce3Sdanielk1977   void * clientData,
13096622cce3Sdanielk1977   Tcl_Interp *interp,
13106622cce3Sdanielk1977   int objc,
13116622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
13126622cce3Sdanielk1977 ){
13136622cce3Sdanielk1977   sqlite3 *db;
13146622cce3Sdanielk1977   const char *zSql;
13156622cce3Sdanielk1977   int bytes;
13166622cce3Sdanielk1977   const char *zTail = 0;
13176622cce3Sdanielk1977   sqlite3_stmt *pStmt = 0;
13186622cce3Sdanielk1977   char zBuf[50];
13194ad1713cSdanielk1977   int rc;
13206622cce3Sdanielk1977 
13216622cce3Sdanielk1977   if( objc!=5 ){
13226622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
13236622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
13246622cce3Sdanielk1977     return TCL_ERROR;
13256622cce3Sdanielk1977   }
13266622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
13276622cce3Sdanielk1977   zSql = Tcl_GetString(objv[2]);
13286622cce3Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
13296622cce3Sdanielk1977 
13304ad1713cSdanielk1977   rc = sqlite3_prepare(db, zSql, bytes, &pStmt, &zTail);
13316622cce3Sdanielk1977   if( zTail ){
13326622cce3Sdanielk1977     if( bytes>=0 ){
13336622cce3Sdanielk1977       bytes = bytes - (zTail-zSql);
13346622cce3Sdanielk1977     }
13356622cce3Sdanielk1977     Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
13366622cce3Sdanielk1977   }
13374ad1713cSdanielk1977   if( rc!=SQLITE_OK ){
13384ad1713cSdanielk1977     assert( pStmt==0 );
13394ad1713cSdanielk1977     sprintf(zBuf, "(%d) ", rc);
13404ad1713cSdanielk1977     Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
13414ad1713cSdanielk1977     return TCL_ERROR;
13424ad1713cSdanielk1977   }
13436622cce3Sdanielk1977 
13444ad1713cSdanielk1977   if( pStmt ){
13456622cce3Sdanielk1977     if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
13466622cce3Sdanielk1977     Tcl_AppendResult(interp, zBuf, 0);
13474ad1713cSdanielk1977   }
13486622cce3Sdanielk1977   return TCL_OK;
13496622cce3Sdanielk1977 }
13506622cce3Sdanielk1977 
13516622cce3Sdanielk1977 /*
13526622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar
13536622cce3Sdanielk1977 **
13546622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
13556622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global
13566622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A
13576622cce3Sdanielk1977 ** STMT handle is returned.
13586622cce3Sdanielk1977 */
13596622cce3Sdanielk1977 static int test_prepare16(
13606622cce3Sdanielk1977   void * clientData,
13616622cce3Sdanielk1977   Tcl_Interp *interp,
13626622cce3Sdanielk1977   int objc,
13636622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
13646622cce3Sdanielk1977 ){
13656622cce3Sdanielk1977   sqlite3 *db;
13666622cce3Sdanielk1977   const void *zSql;
13676622cce3Sdanielk1977   const void *zTail = 0;
13686622cce3Sdanielk1977   Tcl_Obj *pTail = 0;
13696622cce3Sdanielk1977   sqlite3_stmt *pStmt = 0;
13706622cce3Sdanielk1977   char zBuf[50];
13716622cce3Sdanielk1977   int bytes;                /* The integer specified as arg 3 */
13726622cce3Sdanielk1977   int objlen;               /* The byte-array length of arg 2 */
13736622cce3Sdanielk1977 
13746622cce3Sdanielk1977   if( objc!=5 ){
13756622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
13766622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
13776622cce3Sdanielk1977     return TCL_ERROR;
13786622cce3Sdanielk1977   }
13796622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
13806622cce3Sdanielk1977   zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen);
13816622cce3Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
13826622cce3Sdanielk1977 
13836622cce3Sdanielk1977   if( SQLITE_OK!=sqlite3_prepare16(db, zSql, bytes, &pStmt, &zTail) ){
13846622cce3Sdanielk1977     return TCL_ERROR;
13856622cce3Sdanielk1977   }
13866622cce3Sdanielk1977 
13876622cce3Sdanielk1977   if( zTail ){
13886622cce3Sdanielk1977     objlen = objlen - ((u8 *)zTail-(u8 *)zSql);
13896622cce3Sdanielk1977   }else{
13906622cce3Sdanielk1977     objlen = 0;
13916622cce3Sdanielk1977   }
13926622cce3Sdanielk1977   pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen);
13936622cce3Sdanielk1977   Tcl_IncrRefCount(pTail);
13946622cce3Sdanielk1977   Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0);
13954ad1713cSdanielk1977   Tcl_DecrRefCount(pTail);
13966622cce3Sdanielk1977 
13974ad1713cSdanielk1977   if( pStmt ){
13986622cce3Sdanielk1977     if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
13994ad1713cSdanielk1977   }
14006622cce3Sdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
14016622cce3Sdanielk1977   return TCL_OK;
14026622cce3Sdanielk1977 }
14036622cce3Sdanielk1977 
14044ad1713cSdanielk1977 /*
14054ad1713cSdanielk1977 ** Usage: sqlite3_open filename ?options-list?
14064ad1713cSdanielk1977 */
14074ad1713cSdanielk1977 static int test_open(
14084ad1713cSdanielk1977   void * clientData,
14094ad1713cSdanielk1977   Tcl_Interp *interp,
14104ad1713cSdanielk1977   int objc,
14114ad1713cSdanielk1977   Tcl_Obj *CONST objv[]
14124ad1713cSdanielk1977 ){
14134ad1713cSdanielk1977   const char *zFilename;
14144ad1713cSdanielk1977   sqlite3 *db;
14154ad1713cSdanielk1977   int rc;
14164ad1713cSdanielk1977   char zBuf[100];
14174ad1713cSdanielk1977 
14184ad1713cSdanielk1977   if( objc!=3 && objc!=2 ){
14194ad1713cSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
14204ad1713cSdanielk1977        Tcl_GetString(objv[0]), " filename options-list", 0);
14214ad1713cSdanielk1977     return TCL_ERROR;
14224ad1713cSdanielk1977   }
14234ad1713cSdanielk1977 
14244ad1713cSdanielk1977   zFilename = Tcl_GetString(objv[1]);
14254f057f90Sdanielk1977   rc = sqlite3_open(zFilename, &db);
14264ad1713cSdanielk1977 
14274ad1713cSdanielk1977   if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
14284ad1713cSdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
14294ad1713cSdanielk1977   return TCL_OK;
14304ad1713cSdanielk1977 }
14314ad1713cSdanielk1977 
14324ad1713cSdanielk1977 /*
14334ad1713cSdanielk1977 ** Usage: sqlite3_open16 filename options
14344ad1713cSdanielk1977 */
14354ad1713cSdanielk1977 static int test_open16(
14364ad1713cSdanielk1977   void * clientData,
14374ad1713cSdanielk1977   Tcl_Interp *interp,
14384ad1713cSdanielk1977   int objc,
14394ad1713cSdanielk1977   Tcl_Obj *CONST objv[]
14404ad1713cSdanielk1977 ){
14414ad1713cSdanielk1977   const void *zFilename;
14424ad1713cSdanielk1977   sqlite3 *db;
14434ad1713cSdanielk1977   int rc;
14444ad1713cSdanielk1977   char zBuf[100];
14454ad1713cSdanielk1977 
14464ad1713cSdanielk1977   if( objc!=3 ){
14474ad1713cSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
14484ad1713cSdanielk1977        Tcl_GetString(objv[0]), " filename options-list", 0);
14494ad1713cSdanielk1977     return TCL_ERROR;
14504ad1713cSdanielk1977   }
14514ad1713cSdanielk1977 
14524ad1713cSdanielk1977   zFilename = Tcl_GetByteArrayFromObj(objv[1], 0);
14534f057f90Sdanielk1977   rc = sqlite3_open16(zFilename, &db);
14544ad1713cSdanielk1977 
14554ad1713cSdanielk1977   if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
14564ad1713cSdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
14574ad1713cSdanielk1977   return TCL_OK;
14584ad1713cSdanielk1977 }
1459d3d39e93Sdrh 
1460d3d39e93Sdrh /*
1461106bb236Sdanielk1977 ** Usage: sqlite3_step STMT
1462106bb236Sdanielk1977 **
1463106bb236Sdanielk1977 ** Advance the statement to the next row.
1464106bb236Sdanielk1977 */
146517240fd9Sdanielk1977 static int test_step(
1466106bb236Sdanielk1977   void * clientData,
1467106bb236Sdanielk1977   Tcl_Interp *interp,
1468106bb236Sdanielk1977   int objc,
1469106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
1470106bb236Sdanielk1977 ){
1471106bb236Sdanielk1977   sqlite3_stmt *pStmt;
1472106bb236Sdanielk1977   int rc;
1473106bb236Sdanielk1977 
1474e1cd9874Sdanielk1977   if( objc!=2 ){
1475106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1476106bb236Sdanielk1977        Tcl_GetString(objv[0]), " STMT", 0);
1477106bb236Sdanielk1977     return TCL_ERROR;
1478106bb236Sdanielk1977   }
1479106bb236Sdanielk1977 
1480106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
148117240fd9Sdanielk1977   rc = sqlite3_step(pStmt);
1482106bb236Sdanielk1977 
1483fbcd585fSdanielk1977   /* if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR; */
14846590493dSdanielk1977   Tcl_SetResult(interp, (char *)errorName(rc), 0);
1485e1cd9874Sdanielk1977   return TCL_OK;
1486e1cd9874Sdanielk1977 }
1487e1cd9874Sdanielk1977 
1488e1cd9874Sdanielk1977 /*
148917240fd9Sdanielk1977 ** Usage: sqlite3_column_count STMT
149017240fd9Sdanielk1977 **
149117240fd9Sdanielk1977 ** Return the number of columns returned by the sql statement STMT.
149217240fd9Sdanielk1977 */
149317240fd9Sdanielk1977 static int test_column_count(
149417240fd9Sdanielk1977   void * clientData,
149517240fd9Sdanielk1977   Tcl_Interp *interp,
149617240fd9Sdanielk1977   int objc,
149717240fd9Sdanielk1977   Tcl_Obj *CONST objv[]
149817240fd9Sdanielk1977 ){
149917240fd9Sdanielk1977   sqlite3_stmt *pStmt;
150017240fd9Sdanielk1977 
150117240fd9Sdanielk1977   if( objc!=2 ){
150217240fd9Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
150317240fd9Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
150417240fd9Sdanielk1977     return TCL_ERROR;
150517240fd9Sdanielk1977   }
150617240fd9Sdanielk1977 
150717240fd9Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
150817240fd9Sdanielk1977 
150917240fd9Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_column_count(pStmt)));
151017240fd9Sdanielk1977   return TCL_OK;
151117240fd9Sdanielk1977 }
151217240fd9Sdanielk1977 
151317240fd9Sdanielk1977 /*
15143cf86063Sdanielk1977 ** Usage: sqlite3_column_type STMT column
15153cf86063Sdanielk1977 **
15163cf86063Sdanielk1977 ** Return the type of the data in column 'column' of the current row.
15173cf86063Sdanielk1977 */
15183cf86063Sdanielk1977 static int test_column_type(
15193cf86063Sdanielk1977   void * clientData,
15203cf86063Sdanielk1977   Tcl_Interp *interp,
15213cf86063Sdanielk1977   int objc,
15223cf86063Sdanielk1977   Tcl_Obj *CONST objv[]
15233cf86063Sdanielk1977 ){
15243cf86063Sdanielk1977   sqlite3_stmt *pStmt;
15253cf86063Sdanielk1977   int col;
15263cf86063Sdanielk1977   int tp;
15273cf86063Sdanielk1977 
15283cf86063Sdanielk1977   if( objc!=3 ){
15293cf86063Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
15303cf86063Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
15313cf86063Sdanielk1977     return TCL_ERROR;
15323cf86063Sdanielk1977   }
15333cf86063Sdanielk1977 
15343cf86063Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
15353cf86063Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
15363cf86063Sdanielk1977 
15373cf86063Sdanielk1977   tp = sqlite3_column_type(pStmt, col);
15383cf86063Sdanielk1977   switch( tp ){
15399c054830Sdrh     case SQLITE_INTEGER:
15403cf86063Sdanielk1977       Tcl_SetResult(interp, "INTEGER", TCL_STATIC);
15413cf86063Sdanielk1977       break;
15429c054830Sdrh     case SQLITE_NULL:
15433cf86063Sdanielk1977       Tcl_SetResult(interp, "NULL", TCL_STATIC);
15443cf86063Sdanielk1977       break;
15459c054830Sdrh     case SQLITE_FLOAT:
15463cf86063Sdanielk1977       Tcl_SetResult(interp, "FLOAT", TCL_STATIC);
15473cf86063Sdanielk1977       break;
15489c054830Sdrh     case SQLITE_TEXT:
15493cf86063Sdanielk1977       Tcl_SetResult(interp, "TEXT", TCL_STATIC);
15503cf86063Sdanielk1977       break;
15519c054830Sdrh     case SQLITE_BLOB:
15523cf86063Sdanielk1977       Tcl_SetResult(interp, "BLOB", TCL_STATIC);
15533cf86063Sdanielk1977       break;
15543cf86063Sdanielk1977     default:
15553cf86063Sdanielk1977       assert(0);
15563cf86063Sdanielk1977   }
15573cf86063Sdanielk1977 
15583cf86063Sdanielk1977   return TCL_OK;
15593cf86063Sdanielk1977 }
15603cf86063Sdanielk1977 
15613cf86063Sdanielk1977 /*
156204f2e68dSdanielk1977 ** Usage: sqlite3_column_int64 STMT column
15633cf86063Sdanielk1977 **
15643cf86063Sdanielk1977 ** Return the data in column 'column' of the current row cast as an
156504f2e68dSdanielk1977 ** wide (64-bit) integer.
15663cf86063Sdanielk1977 */
156704f2e68dSdanielk1977 static int test_column_int64(
15683cf86063Sdanielk1977   void * clientData,
15693cf86063Sdanielk1977   Tcl_Interp *interp,
15703cf86063Sdanielk1977   int objc,
15713cf86063Sdanielk1977   Tcl_Obj *CONST objv[]
15723cf86063Sdanielk1977 ){
15733cf86063Sdanielk1977   sqlite3_stmt *pStmt;
15743cf86063Sdanielk1977   int col;
157504f2e68dSdanielk1977   i64 iVal;
15763cf86063Sdanielk1977 
15773cf86063Sdanielk1977   if( objc!=3 ){
15783cf86063Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
15793cf86063Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
15803cf86063Sdanielk1977     return TCL_ERROR;
15813cf86063Sdanielk1977   }
15823cf86063Sdanielk1977 
15833cf86063Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
15843cf86063Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
15853cf86063Sdanielk1977 
158604f2e68dSdanielk1977   iVal = sqlite3_column_int64(pStmt, col);
158704f2e68dSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(iVal));
158804f2e68dSdanielk1977   return TCL_OK;
158904f2e68dSdanielk1977 }
159004f2e68dSdanielk1977 
159104f2e68dSdanielk1977 /*
1592ea61b2c4Sdanielk1977 ** Usage: sqlite3_column_blob STMT column
1593ea61b2c4Sdanielk1977 */
1594ea61b2c4Sdanielk1977 static int test_column_blob(
1595ea61b2c4Sdanielk1977   void * clientData,
1596ea61b2c4Sdanielk1977   Tcl_Interp *interp,
1597ea61b2c4Sdanielk1977   int objc,
1598ea61b2c4Sdanielk1977   Tcl_Obj *CONST objv[]
1599ea61b2c4Sdanielk1977 ){
1600ea61b2c4Sdanielk1977   sqlite3_stmt *pStmt;
1601ea61b2c4Sdanielk1977   int col;
1602ea61b2c4Sdanielk1977 
1603ea61b2c4Sdanielk1977   int len;
1604c572ef7fSdanielk1977   const void *pBlob;
1605ea61b2c4Sdanielk1977 
1606ea61b2c4Sdanielk1977   if( objc!=3 ){
1607ea61b2c4Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1608ea61b2c4Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
1609ea61b2c4Sdanielk1977     return TCL_ERROR;
1610ea61b2c4Sdanielk1977   }
1611ea61b2c4Sdanielk1977 
1612ea61b2c4Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
1613ea61b2c4Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
1614ea61b2c4Sdanielk1977 
1615ea61b2c4Sdanielk1977   pBlob = sqlite3_column_blob(pStmt, col);
1616ea61b2c4Sdanielk1977   len = sqlite3_column_bytes(pStmt, col);
1617ea61b2c4Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pBlob, len));
1618ea61b2c4Sdanielk1977   return TCL_OK;
1619ea61b2c4Sdanielk1977 }
1620ea61b2c4Sdanielk1977 
1621ea61b2c4Sdanielk1977 /*
162204f2e68dSdanielk1977 ** Usage: sqlite3_column_double STMT column
162304f2e68dSdanielk1977 **
162404f2e68dSdanielk1977 ** Return the data in column 'column' of the current row cast as a double.
162504f2e68dSdanielk1977 */
162604f2e68dSdanielk1977 static int test_column_double(
162704f2e68dSdanielk1977   void * clientData,
162804f2e68dSdanielk1977   Tcl_Interp *interp,
162904f2e68dSdanielk1977   int objc,
163004f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
163104f2e68dSdanielk1977 ){
163204f2e68dSdanielk1977   sqlite3_stmt *pStmt;
163304f2e68dSdanielk1977   int col;
163404f2e68dSdanielk1977   double rVal;
163504f2e68dSdanielk1977 
163604f2e68dSdanielk1977   if( objc!=3 ){
163704f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
163804f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
163904f2e68dSdanielk1977     return TCL_ERROR;
164004f2e68dSdanielk1977   }
164104f2e68dSdanielk1977 
164204f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
164304f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
164404f2e68dSdanielk1977 
164504f2e68dSdanielk1977   rVal = sqlite3_column_double(pStmt, col);
1646c572ef7fSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewDoubleObj(rVal));
16473cf86063Sdanielk1977   return TCL_OK;
16483cf86063Sdanielk1977 }
16493cf86063Sdanielk1977 
16503cf86063Sdanielk1977 /*
165117240fd9Sdanielk1977 ** Usage: sqlite3_data_count STMT
165217240fd9Sdanielk1977 **
165317240fd9Sdanielk1977 ** Return the number of columns returned by the sql statement STMT.
165417240fd9Sdanielk1977 */
165517240fd9Sdanielk1977 static int test_data_count(
165617240fd9Sdanielk1977   void * clientData,
165717240fd9Sdanielk1977   Tcl_Interp *interp,
165817240fd9Sdanielk1977   int objc,
165917240fd9Sdanielk1977   Tcl_Obj *CONST objv[]
166017240fd9Sdanielk1977 ){
166117240fd9Sdanielk1977   sqlite3_stmt *pStmt;
166217240fd9Sdanielk1977 
166317240fd9Sdanielk1977   if( objc!=2 ){
166417240fd9Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
166517240fd9Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
166617240fd9Sdanielk1977     return TCL_ERROR;
166717240fd9Sdanielk1977   }
166817240fd9Sdanielk1977 
166917240fd9Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
167017240fd9Sdanielk1977 
167117240fd9Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_data_count(pStmt)));
167217240fd9Sdanielk1977   return TCL_OK;
167317240fd9Sdanielk1977 }
167417240fd9Sdanielk1977 
167517240fd9Sdanielk1977 /*
167604f2e68dSdanielk1977 ** Usage: sqlite3_column_text STMT column
167704f2e68dSdanielk1977 **
167804f2e68dSdanielk1977 ** Usage: sqlite3_column_decltype STMT column
167904f2e68dSdanielk1977 **
168004f2e68dSdanielk1977 ** Usage: sqlite3_column_name STMT column
168104f2e68dSdanielk1977 */
168204f2e68dSdanielk1977 static int test_stmt_utf8(
168304f2e68dSdanielk1977   void * clientData,
168404f2e68dSdanielk1977   Tcl_Interp *interp,
168504f2e68dSdanielk1977   int objc,
168604f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
168704f2e68dSdanielk1977 ){
168804f2e68dSdanielk1977   sqlite3_stmt *pStmt;
168904f2e68dSdanielk1977   int col;
1690c572ef7fSdanielk1977   const char *(*xFunc)(sqlite3_stmt*, int) = clientData;
1691f93bbbeaSdanielk1977   const char *zRet;
169204f2e68dSdanielk1977 
169304f2e68dSdanielk1977   if( objc!=3 ){
169404f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
169504f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
169604f2e68dSdanielk1977     return TCL_ERROR;
169704f2e68dSdanielk1977   }
169804f2e68dSdanielk1977 
169904f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
170004f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
1701f93bbbeaSdanielk1977   zRet = xFunc(pStmt, col);
1702f93bbbeaSdanielk1977   if( zRet ){
1703f93bbbeaSdanielk1977     Tcl_SetResult(interp, (char *)zRet, 0);
1704f93bbbeaSdanielk1977   }
170504f2e68dSdanielk1977   return TCL_OK;
170604f2e68dSdanielk1977 }
170704f2e68dSdanielk1977 
170804f2e68dSdanielk1977 /*
170904f2e68dSdanielk1977 ** Usage: sqlite3_column_text STMT column
171004f2e68dSdanielk1977 **
171104f2e68dSdanielk1977 ** Usage: sqlite3_column_decltype STMT column
171204f2e68dSdanielk1977 **
171304f2e68dSdanielk1977 ** Usage: sqlite3_column_name STMT column
171404f2e68dSdanielk1977 */
171504f2e68dSdanielk1977 static int test_stmt_utf16(
171604f2e68dSdanielk1977   void * clientData,
171704f2e68dSdanielk1977   Tcl_Interp *interp,
171804f2e68dSdanielk1977   int objc,
171904f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
172004f2e68dSdanielk1977 ){
172104f2e68dSdanielk1977   sqlite3_stmt *pStmt;
172204f2e68dSdanielk1977   int col;
172304f2e68dSdanielk1977   Tcl_Obj *pRet;
172404f2e68dSdanielk1977   const void *zName16;
1725c572ef7fSdanielk1977   const void *(*xFunc)(sqlite3_stmt*, int) = clientData;
172604f2e68dSdanielk1977 
172704f2e68dSdanielk1977   if( objc!=3 ){
172804f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
172904f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
173004f2e68dSdanielk1977     return TCL_ERROR;
173104f2e68dSdanielk1977   }
173204f2e68dSdanielk1977 
173304f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
173404f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
173504f2e68dSdanielk1977 
173604f2e68dSdanielk1977   zName16 = xFunc(pStmt, col);
1737f93bbbeaSdanielk1977   if( zName16 ){
173804f2e68dSdanielk1977     pRet = Tcl_NewByteArrayObj(zName16, sqlite3utf16ByteLen(zName16, -1)+2);
173904f2e68dSdanielk1977     Tcl_SetObjResult(interp, pRet);
1740f93bbbeaSdanielk1977   }
174104f2e68dSdanielk1977 
174204f2e68dSdanielk1977   return TCL_OK;
174304f2e68dSdanielk1977 }
174404f2e68dSdanielk1977 
174504f2e68dSdanielk1977 /*
174604f2e68dSdanielk1977 ** Usage: sqlite3_column_int STMT column
174704f2e68dSdanielk1977 **
174804f2e68dSdanielk1977 ** Usage: sqlite3_column_bytes STMT column
174904f2e68dSdanielk1977 **
175004f2e68dSdanielk1977 ** Usage: sqlite3_column_bytes16 STMT column
175104f2e68dSdanielk1977 **
175204f2e68dSdanielk1977 */
175304f2e68dSdanielk1977 static int test_stmt_int(
175404f2e68dSdanielk1977   void * clientData,
175504f2e68dSdanielk1977   Tcl_Interp *interp,
175604f2e68dSdanielk1977   int objc,
175704f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
175804f2e68dSdanielk1977 ){
175904f2e68dSdanielk1977   sqlite3_stmt *pStmt;
176004f2e68dSdanielk1977   int col;
1761c572ef7fSdanielk1977   int (*xFunc)(sqlite3_stmt*, int) = clientData;
176204f2e68dSdanielk1977 
176304f2e68dSdanielk1977   if( objc!=3 ){
176404f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
176504f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
176604f2e68dSdanielk1977     return TCL_ERROR;
176704f2e68dSdanielk1977   }
176804f2e68dSdanielk1977 
176904f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
177004f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
177104f2e68dSdanielk1977 
177204f2e68dSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(xFunc(pStmt, col)));
177304f2e68dSdanielk1977   return TCL_OK;
177404f2e68dSdanielk1977 }
177504f2e68dSdanielk1977 
17769a1d0abeSdanielk1977 /*
17779a1d0abeSdanielk1977 ** Usage:  sqlite3OsOpenReadWrite <filename>
17789a1d0abeSdanielk1977 */
17799a1d0abeSdanielk1977 static int test_sqlite3OsOpenReadWrite(
17809a1d0abeSdanielk1977   void * clientData,
17819a1d0abeSdanielk1977   Tcl_Interp *interp,
17829a1d0abeSdanielk1977   int objc,
17839a1d0abeSdanielk1977   Tcl_Obj *CONST objv[]
17849a1d0abeSdanielk1977 ){
17859a1d0abeSdanielk1977   OsFile * pFile;
17869a1d0abeSdanielk1977   int rc;
17879a1d0abeSdanielk1977   int dummy;
17889a1d0abeSdanielk1977   char zBuf[100];
178904f2e68dSdanielk1977 
17909a1d0abeSdanielk1977   if( objc!=2 ){
17919a1d0abeSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
17929a1d0abeSdanielk1977        Tcl_GetString(objv[0]), " filename", 0);
17939a1d0abeSdanielk1977     return TCL_ERROR;
17949a1d0abeSdanielk1977   }
17959a1d0abeSdanielk1977 
17969a1d0abeSdanielk1977   pFile = sqliteMalloc(sizeof(OsFile));
17979a1d0abeSdanielk1977   rc = sqlite3OsOpenReadWrite(Tcl_GetString(objv[1]), pFile, &dummy);
17989a1d0abeSdanielk1977   if( rc!=SQLITE_OK ){
17999a1d0abeSdanielk1977     sqliteFree(pFile);
18009a1d0abeSdanielk1977     Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
18019a1d0abeSdanielk1977     return TCL_ERROR;
18029a1d0abeSdanielk1977   }
18039a1d0abeSdanielk1977   makePointerStr(interp, zBuf, pFile);
18049a1d0abeSdanielk1977   Tcl_SetResult(interp, zBuf, 0);
18059a1d0abeSdanielk1977   return TCL_ERROR;
18069a1d0abeSdanielk1977 }
18079a1d0abeSdanielk1977 
18089a1d0abeSdanielk1977 /*
18099a1d0abeSdanielk1977 ** Usage:  sqlite3OsClose <file handle>
18109a1d0abeSdanielk1977 */
18119a1d0abeSdanielk1977 static int test_sqlite3OsClose(
18129a1d0abeSdanielk1977   void * clientData,
18139a1d0abeSdanielk1977   Tcl_Interp *interp,
18149a1d0abeSdanielk1977   int objc,
18159a1d0abeSdanielk1977   Tcl_Obj *CONST objv[]
18169a1d0abeSdanielk1977 ){
18179a1d0abeSdanielk1977   OsFile * pFile;
18189a1d0abeSdanielk1977   int rc;
18199a1d0abeSdanielk1977 
18209a1d0abeSdanielk1977   if( objc!=2 ){
18219a1d0abeSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
18229a1d0abeSdanielk1977        Tcl_GetString(objv[0]), " filehandle", 0);
18239a1d0abeSdanielk1977     return TCL_ERROR;
18249a1d0abeSdanielk1977   }
18259a1d0abeSdanielk1977 
18269a1d0abeSdanielk1977   if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
18279a1d0abeSdanielk1977     return TCL_ERROR;
18289a1d0abeSdanielk1977   }
18299a1d0abeSdanielk1977   rc = sqlite3OsClose(pFile);
18309a1d0abeSdanielk1977   if( rc!=SQLITE_OK ){
18319a1d0abeSdanielk1977     Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
18329a1d0abeSdanielk1977     return TCL_ERROR;
18339a1d0abeSdanielk1977   }
18349a1d0abeSdanielk1977   sqliteFree(pFile);
18359a1d0abeSdanielk1977   return TCL_OK;
18369a1d0abeSdanielk1977 }
18379a1d0abeSdanielk1977 
18389a1d0abeSdanielk1977 /*
18399a1d0abeSdanielk1977 ** Usage:  sqlite3OsLock <file handle> <locktype>
18409a1d0abeSdanielk1977 */
18419a1d0abeSdanielk1977 static int test_sqlite3OsLock(
18429a1d0abeSdanielk1977   void * clientData,
18439a1d0abeSdanielk1977   Tcl_Interp *interp,
18449a1d0abeSdanielk1977   int objc,
18459a1d0abeSdanielk1977   Tcl_Obj *CONST objv[]
18469a1d0abeSdanielk1977 ){
18479a1d0abeSdanielk1977   OsFile * pFile;
18489a1d0abeSdanielk1977   int rc;
18499a1d0abeSdanielk1977 
18509a1d0abeSdanielk1977   if( objc!=3 ){
18519a1d0abeSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
18529a1d0abeSdanielk1977         Tcl_GetString(objv[0]),
18539a1d0abeSdanielk1977         " filehandle (SHARED|RESERVED|PENDING|EXCLUSIVE)", 0);
18549a1d0abeSdanielk1977     return TCL_ERROR;
18559a1d0abeSdanielk1977   }
18569a1d0abeSdanielk1977 
18579a1d0abeSdanielk1977   if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
18589a1d0abeSdanielk1977     return TCL_ERROR;
18599a1d0abeSdanielk1977   }
18609a1d0abeSdanielk1977 
18619a1d0abeSdanielk1977   if( 0==strcmp("SHARED", Tcl_GetString(objv[2])) ){
18629a1d0abeSdanielk1977     rc = sqlite3OsLock(pFile, SHARED_LOCK);
18639a1d0abeSdanielk1977   }
18649a1d0abeSdanielk1977   else if( 0==strcmp("RESERVED", Tcl_GetString(objv[2])) ){
18659a1d0abeSdanielk1977     rc = sqlite3OsLock(pFile, RESERVED_LOCK);
18669a1d0abeSdanielk1977   }
18679a1d0abeSdanielk1977   else if( 0==strcmp("PENDING", Tcl_GetString(objv[2])) ){
18689a1d0abeSdanielk1977     rc = sqlite3OsLock(pFile, PENDING_LOCK);
18699a1d0abeSdanielk1977   }
18709a1d0abeSdanielk1977   else if( 0==strcmp("EXCLUSIVE", Tcl_GetString(objv[2])) ){
18719a1d0abeSdanielk1977     rc = sqlite3OsLock(pFile, EXCLUSIVE_LOCK);
18729a1d0abeSdanielk1977   }else{
18739a1d0abeSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
18749a1d0abeSdanielk1977         Tcl_GetString(objv[0]),
18759a1d0abeSdanielk1977         " filehandle (SHARED|RESERVED|PENDING|EXCLUSIVE)", 0);
18769a1d0abeSdanielk1977     return TCL_ERROR;
18779a1d0abeSdanielk1977   }
18789a1d0abeSdanielk1977 
18799a1d0abeSdanielk1977   if( rc!=SQLITE_OK ){
18809a1d0abeSdanielk1977     Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
18819a1d0abeSdanielk1977     return TCL_ERROR;
18829a1d0abeSdanielk1977   }
18839a1d0abeSdanielk1977   return TCL_OK;
18849a1d0abeSdanielk1977 }
18859a1d0abeSdanielk1977 
18869a1d0abeSdanielk1977 /*
18879a1d0abeSdanielk1977 ** Usage:  sqlite3OsUnlock <file handle>
18889a1d0abeSdanielk1977 */
18899a1d0abeSdanielk1977 static int test_sqlite3OsUnlock(
18909a1d0abeSdanielk1977   void * clientData,
18919a1d0abeSdanielk1977   Tcl_Interp *interp,
18929a1d0abeSdanielk1977   int objc,
18939a1d0abeSdanielk1977   Tcl_Obj *CONST objv[]
18949a1d0abeSdanielk1977 ){
18959a1d0abeSdanielk1977   OsFile * pFile;
18969a1d0abeSdanielk1977   int rc;
18979a1d0abeSdanielk1977 
18989a1d0abeSdanielk1977   if( objc!=2 ){
18999a1d0abeSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
19009a1d0abeSdanielk1977        Tcl_GetString(objv[0]), " filehandle", 0);
19019a1d0abeSdanielk1977     return TCL_ERROR;
19029a1d0abeSdanielk1977   }
19039a1d0abeSdanielk1977 
19049a1d0abeSdanielk1977   if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
19059a1d0abeSdanielk1977     return TCL_ERROR;
19069a1d0abeSdanielk1977   }
1907a6abd041Sdrh   rc = sqlite3OsUnlock(pFile, NO_LOCK);
19089a1d0abeSdanielk1977   if( rc!=SQLITE_OK ){
19099a1d0abeSdanielk1977     Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
19109a1d0abeSdanielk1977     return TCL_ERROR;
19119a1d0abeSdanielk1977   }
19129a1d0abeSdanielk1977   return TCL_OK;
19139a1d0abeSdanielk1977 }
1914d3d39e93Sdrh 
1915d8123366Sdanielk1977 
19166622cce3Sdanielk1977 /*
1917d1bf3512Sdrh ** Register commands with the TCL interpreter.
1918d1bf3512Sdrh */
1919d1bf3512Sdrh int Sqlitetest1_Init(Tcl_Interp *interp){
19206f8a503dSdanielk1977   extern int sqlite3_search_count;
19216f8a503dSdanielk1977   extern int sqlite3_interrupt_count;
19226f8a503dSdanielk1977   extern int sqlite3_open_file_count;
19236f8a503dSdanielk1977   extern int sqlite3_current_time;
1924c2eef3b3Sdrh   static struct {
1925c2eef3b3Sdrh      char *zName;
1926c2eef3b3Sdrh      Tcl_CmdProc *xProc;
1927c2eef3b3Sdrh   } aCmd[] = {
19286f8a503dSdanielk1977      { "sqlite3_mprintf_int",           (Tcl_CmdProc*)sqlite3_mprintf_int    },
19296f8a503dSdanielk1977      { "sqlite3_mprintf_str",           (Tcl_CmdProc*)sqlite3_mprintf_str    },
19306f8a503dSdanielk1977      { "sqlite3_mprintf_double",        (Tcl_CmdProc*)sqlite3_mprintf_double },
19316f8a503dSdanielk1977      { "sqlite3_mprintf_scaled",        (Tcl_CmdProc*)sqlite3_mprintf_scaled },
19326f8a503dSdanielk1977      { "sqlite3_mprintf_z_test",        (Tcl_CmdProc*)test_mprintf_z        },
19336f8a503dSdanielk1977      { "sqlite3_last_insert_rowid",     (Tcl_CmdProc*)test_last_rowid       },
19346f8a503dSdanielk1977      { "sqlite3_exec_printf",           (Tcl_CmdProc*)test_exec_printf      },
19356f8a503dSdanielk1977      { "sqlite3_get_table_printf",      (Tcl_CmdProc*)test_get_table_printf },
19366f8a503dSdanielk1977      { "sqlite3_close",                 (Tcl_CmdProc*)sqlite_test_close     },
19376f8a503dSdanielk1977      { "sqlite3_create_function",       (Tcl_CmdProc*)test_create_function  },
19386f8a503dSdanielk1977      { "sqlite3_create_aggregate",      (Tcl_CmdProc*)test_create_aggregate },
1939c2eef3b3Sdrh      { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func    },
1940c2eef3b3Sdrh      { "sqlite_abort",                  (Tcl_CmdProc*)sqlite_abort          },
1941faa57accSdrh #ifdef SQLITE_DEBUG
1942c2eef3b3Sdrh      { "sqlite_malloc_fail",            (Tcl_CmdProc*)sqlite_malloc_fail    },
1943c2eef3b3Sdrh      { "sqlite_malloc_stat",            (Tcl_CmdProc*)sqlite_malloc_stat    },
1944c2eef3b3Sdrh #endif
194596fc5fe6Sdanielk1977      { "sqlite_bind",                    (Tcl_CmdProc*)test_bind             },
194699ee3600Sdrh      { "breakpoint",                     (Tcl_CmdProc*)test_breakpoint       },
1947c2eef3b3Sdrh   };
194851e3d8e2Sdanielk1977   static struct {
194951e3d8e2Sdanielk1977      char *zName;
195051e3d8e2Sdanielk1977      Tcl_ObjCmdProc *xProc;
195104f2e68dSdanielk1977      void *clientData;
195251e3d8e2Sdanielk1977   } aObjCmd[] = {
195304f2e68dSdanielk1977      { "sqlite3_bind_int32",            test_bind_int32, 0    },
195404f2e68dSdanielk1977      { "sqlite3_bind_int64",            test_bind_int64 , 0   },
195504f2e68dSdanielk1977      { "sqlite3_bind_double",           test_bind_double, 0   },
195604f2e68dSdanielk1977      { "sqlite3_bind_null",             test_bind_null     ,0 },
195704f2e68dSdanielk1977      { "sqlite3_bind_text",             test_bind_text     ,0 },
195804f2e68dSdanielk1977      { "sqlite3_bind_text16",           test_bind_text16   ,0 },
195904f2e68dSdanielk1977      { "sqlite3_bind_blob",             test_bind_blob     ,0 },
196004f2e68dSdanielk1977      { "sqlite3_errcode",               test_errcode       ,0 },
196104f2e68dSdanielk1977      { "sqlite3_errmsg",                test_errmsg        ,0 },
196204f2e68dSdanielk1977      { "sqlite3_errmsg16",              test_errmsg16      ,0 },
196304f2e68dSdanielk1977      { "sqlite3_open",                  test_open          ,0 },
196404f2e68dSdanielk1977      { "sqlite3_open16",                test_open16        ,0 },
196504f2e68dSdanielk1977 
196604f2e68dSdanielk1977      { "sqlite3_prepare",               test_prepare       ,0 },
196704f2e68dSdanielk1977      { "sqlite3_prepare16",             test_prepare16     ,0 },
196804f2e68dSdanielk1977      { "sqlite3_finalize",              test_finalize      ,0 },
196904f2e68dSdanielk1977      { "sqlite3_reset",                 test_reset         ,0 },
1970fbcd585fSdanielk1977      { "sqlite3_changes",               test_changes       ,0 },
197104f2e68dSdanielk1977      { "sqlite3_step",                  test_step          ,0 },
197204f2e68dSdanielk1977 
197304f2e68dSdanielk1977      /* sqlite3_column_*() API */
197404f2e68dSdanielk1977      { "sqlite3_column_count",          test_column_count  ,0 },
197504f2e68dSdanielk1977      { "sqlite3_data_count",            test_data_count    ,0 },
197604f2e68dSdanielk1977      { "sqlite3_column_type",           test_column_type   ,0 },
1977ea61b2c4Sdanielk1977      { "sqlite3_column_blob",           test_column_blob   ,0 },
197804f2e68dSdanielk1977      { "sqlite3_column_double",         test_column_double ,0 },
197904f2e68dSdanielk1977      { "sqlite3_column_int64",          test_column_int64  ,0 },
198004f2e68dSdanielk1977      { "sqlite3_column_int", test_stmt_int ,sqlite3_column_int },
198104f2e68dSdanielk1977      { "sqlite3_column_bytes", test_stmt_int ,sqlite3_column_bytes },
198204f2e68dSdanielk1977      { "sqlite3_column_bytes16", test_stmt_int ,sqlite3_column_bytes16 },
198304f2e68dSdanielk1977      { "sqlite3_column_text", test_stmt_utf8,       sqlite3_column_text},
198404f2e68dSdanielk1977      { "sqlite3_column_decltype", test_stmt_utf8,   sqlite3_column_decltype},
198504f2e68dSdanielk1977      { "sqlite3_column_name", test_stmt_utf8,       sqlite3_column_name},
198604f2e68dSdanielk1977      { "sqlite3_column_text16", test_stmt_utf16,    sqlite3_column_text16},
198704f2e68dSdanielk1977      { "sqlite3_column_decltype16", test_stmt_utf16,sqlite3_column_decltype16},
198804f2e68dSdanielk1977      { "sqlite3_column_name16", test_stmt_utf16,    sqlite3_column_name16},
198904f2e68dSdanielk1977 
19909a1d0abeSdanielk1977      /* Functions from os.h */
19919a1d0abeSdanielk1977      { "sqlite3OsOpenReadWrite",test_sqlite3OsOpenReadWrite, 0 },
19929a1d0abeSdanielk1977      { "sqlite3OsClose",        test_sqlite3OsClose, 0 },
19939a1d0abeSdanielk1977      { "sqlite3OsLock",         test_sqlite3OsLock, 0 },
19949a1d0abeSdanielk1977      { "sqlite3OsUnlock",       test_sqlite3OsUnlock, 0 },
19954e6af134Sdanielk1977      { "add_test_collate",      test_collate, 0         },
19969a1d0abeSdanielk1977 
199751e3d8e2Sdanielk1977   };
1998c2eef3b3Sdrh   int i;
19992ac3ee97Sdrh   extern int sqlite3_os_trace;
2000c2eef3b3Sdrh 
2001c2eef3b3Sdrh   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
2002c2eef3b3Sdrh     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
2003c2eef3b3Sdrh   }
200451e3d8e2Sdanielk1977   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
2005c572ef7fSdanielk1977     Tcl_CreateObjCommand(interp, aObjCmd[i].zName,
2006c572ef7fSdanielk1977         aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
200751e3d8e2Sdanielk1977   }
20086490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_search_count",
20096f8a503dSdanielk1977       (char*)&sqlite3_search_count, TCL_LINK_INT);
20106490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_interrupt_count",
20116f8a503dSdanielk1977       (char*)&sqlite3_interrupt_count, TCL_LINK_INT);
20126490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_open_file_count",
20136f8a503dSdanielk1977       (char*)&sqlite3_open_file_count, TCL_LINK_INT);
20146490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_current_time",
20156f8a503dSdanielk1977       (char*)&sqlite3_current_time, TCL_LINK_INT);
20162ac3ee97Sdrh   Tcl_LinkVar(interp, "sqlite_os_trace",
20172ac3ee97Sdrh       (char*)&sqlite3_os_trace, TCL_LINK_INT);
20187c972decSdrh   Tcl_LinkVar(interp, "sqlite_static_bind_value",
20197c972decSdrh       (char*)&sqlite_static_bind_value, TCL_LINK_STRING);
2020d1bf3512Sdrh   return TCL_OK;
2021d1bf3512Sdrh }
2022