xref: /sqlite-3.40.0/src/test1.c (revision 9d213ef0)
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*9d213ef0Sdrh ** $Id: test1.c,v 1.91 2004/06/30 04:02:12 drh Exp $
17d1bf3512Sdrh */
18d1bf3512Sdrh #include "sqliteInt.h"
19d1bf3512Sdrh #include "tcl.h"
2094e92032Sdrh #include "os.h"
21d1bf3512Sdrh #include <stdlib.h>
22d1bf3512Sdrh #include <string.h>
23d1bf3512Sdrh 
2494e92032Sdrh #if OS_WIN
2594e92032Sdrh # define PTR_FMT "%x"
2694e92032Sdrh #else
2794e92032Sdrh # define PTR_FMT "%p"
2894e92032Sdrh #endif
2994e92032Sdrh 
30c572ef7fSdanielk1977 int sqlite3_exec_printf(
31c572ef7fSdanielk1977   sqlite *db,                   /* An open database */
32c572ef7fSdanielk1977   const char *sqlFormat,        /* printf-style format string for the SQL */
33c572ef7fSdanielk1977   sqlite_callback xCallback,    /* Callback function */
34c572ef7fSdanielk1977   void *pArg,                   /* 1st argument to callback function */
35c572ef7fSdanielk1977   char **errmsg,                /* Error msg written here */
36c572ef7fSdanielk1977   ...                           /* Arguments to the format string. */
37c572ef7fSdanielk1977 );
38c572ef7fSdanielk1977 int sqlite3_get_table_printf(
39c572ef7fSdanielk1977   sqlite *db,            /* An open database */
40c572ef7fSdanielk1977   const char *sqlFormat, /* printf-style format string for the SQL */
41c572ef7fSdanielk1977   char ***resultp,       /* Result written to a char *[]  that this points to */
42c572ef7fSdanielk1977   int *nrow,             /* Number of result rows written here */
43c572ef7fSdanielk1977   int *ncol,             /* Number of result columns written here */
44c572ef7fSdanielk1977   char **errmsg,         /* Error msg written here */
45c572ef7fSdanielk1977   ...                    /* Arguments to the format string */
46c572ef7fSdanielk1977 );
47c572ef7fSdanielk1977 
486622cce3Sdanielk1977 static const char * errorName(int rc){
496622cce3Sdanielk1977   const char *zName = 0;
506622cce3Sdanielk1977   switch( rc ){
516622cce3Sdanielk1977     case SQLITE_OK:         zName = "SQLITE_OK";          break;
526622cce3Sdanielk1977     case SQLITE_ERROR:      zName = "SQLITE_ERROR";       break;
536622cce3Sdanielk1977     case SQLITE_INTERNAL:   zName = "SQLITE_INTERNAL";    break;
546622cce3Sdanielk1977     case SQLITE_PERM:       zName = "SQLITE_PERM";        break;
556622cce3Sdanielk1977     case SQLITE_ABORT:      zName = "SQLITE_ABORT";       break;
566622cce3Sdanielk1977     case SQLITE_BUSY:       zName = "SQLITE_BUSY";        break;
576622cce3Sdanielk1977     case SQLITE_LOCKED:     zName = "SQLITE_LOCKED";      break;
586622cce3Sdanielk1977     case SQLITE_NOMEM:      zName = "SQLITE_NOMEM";       break;
596622cce3Sdanielk1977     case SQLITE_READONLY:   zName = "SQLITE_READONLY";    break;
606622cce3Sdanielk1977     case SQLITE_INTERRUPT:  zName = "SQLITE_INTERRUPT";   break;
616622cce3Sdanielk1977     case SQLITE_IOERR:      zName = "SQLITE_IOERR";       break;
626622cce3Sdanielk1977     case SQLITE_CORRUPT:    zName = "SQLITE_CORRUPT";     break;
636622cce3Sdanielk1977     case SQLITE_NOTFOUND:   zName = "SQLITE_NOTFOUND";    break;
646622cce3Sdanielk1977     case SQLITE_FULL:       zName = "SQLITE_FULL";        break;
656622cce3Sdanielk1977     case SQLITE_CANTOPEN:   zName = "SQLITE_CANTOPEN";    break;
666622cce3Sdanielk1977     case SQLITE_PROTOCOL:   zName = "SQLITE_PROTOCOL";    break;
676622cce3Sdanielk1977     case SQLITE_EMPTY:      zName = "SQLITE_EMPTY";       break;
686622cce3Sdanielk1977     case SQLITE_SCHEMA:     zName = "SQLITE_SCHEMA";      break;
696622cce3Sdanielk1977     case SQLITE_TOOBIG:     zName = "SQLITE_TOOBIG";      break;
706622cce3Sdanielk1977     case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT";  break;
716622cce3Sdanielk1977     case SQLITE_MISMATCH:   zName = "SQLITE_MISMATCH";    break;
726622cce3Sdanielk1977     case SQLITE_MISUSE:     zName = "SQLITE_MISUSE";      break;
736622cce3Sdanielk1977     case SQLITE_NOLFS:      zName = "SQLITE_NOLFS";       break;
746622cce3Sdanielk1977     case SQLITE_AUTH:       zName = "SQLITE_AUTH";        break;
756622cce3Sdanielk1977     case SQLITE_FORMAT:     zName = "SQLITE_FORMAT";      break;
766622cce3Sdanielk1977     case SQLITE_RANGE:      zName = "SQLITE_RANGE";       break;
776622cce3Sdanielk1977     case SQLITE_ROW:        zName = "SQLITE_ROW";         break;
786622cce3Sdanielk1977     case SQLITE_DONE:       zName = "SQLITE_DONE";        break;
79312d6b36Sdanielk1977     case SQLITE_NOTADB:     zName = "SQLITE_NOTADB";        break;
806622cce3Sdanielk1977     default:                zName = "SQLITE_Unknown";     break;
816622cce3Sdanielk1977   }
826622cce3Sdanielk1977   return zName;
836622cce3Sdanielk1977 }
846622cce3Sdanielk1977 
85d1bf3512Sdrh /*
86b86ccfb2Sdrh ** Decode a pointer to an sqlite object.
87b86ccfb2Sdrh */
8890f405e3Sdrh static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite **ppDb){
8990f405e3Sdrh   if( sscanf(zA, PTR_FMT, (void**)ppDb)!=1 &&
9090f405e3Sdrh       (zA[0]!='0' || zA[1]!='x' || sscanf(&zA[2], PTR_FMT, (void**)ppDb)!=1)
9190f405e3Sdrh   ){
9290f405e3Sdrh     Tcl_AppendResult(interp, "\"", zA, "\" is not a valid pointer value", 0);
93b86ccfb2Sdrh     return TCL_ERROR;
94b86ccfb2Sdrh   }
95b86ccfb2Sdrh   return TCL_OK;
96b86ccfb2Sdrh }
97b86ccfb2Sdrh 
98b86ccfb2Sdrh /*
9951e3d8e2Sdanielk1977 ** Decode a pointer to an sqlite3_stmt object.
10051e3d8e2Sdanielk1977 */
10151e3d8e2Sdanielk1977 static int getStmtPointer(
10251e3d8e2Sdanielk1977   Tcl_Interp *interp,
10351e3d8e2Sdanielk1977   const char *zArg,
10451e3d8e2Sdanielk1977   sqlite3_stmt **ppStmt
10551e3d8e2Sdanielk1977 ){
10651e3d8e2Sdanielk1977   if( sscanf(zArg, PTR_FMT, (void**)ppStmt)!=1 ){
10751e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0);
10851e3d8e2Sdanielk1977     return TCL_ERROR;
10951e3d8e2Sdanielk1977   }
11051e3d8e2Sdanielk1977   return TCL_OK;
11151e3d8e2Sdanielk1977 }
11251e3d8e2Sdanielk1977 
11351e3d8e2Sdanielk1977 /*
1149a1d0abeSdanielk1977 ** Decode a pointer to an sqlite3_stmt object.
1159a1d0abeSdanielk1977 */
1169a1d0abeSdanielk1977 static int getFilePointer(
1179a1d0abeSdanielk1977   Tcl_Interp *interp,
1189a1d0abeSdanielk1977   const char *zArg,
1199a1d0abeSdanielk1977   OsFile **ppFile
1209a1d0abeSdanielk1977 ){
1219a1d0abeSdanielk1977   if( sscanf(zArg, PTR_FMT, (void**)ppFile)!=1 ){
1229a1d0abeSdanielk1977     Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0);
1239a1d0abeSdanielk1977     return TCL_ERROR;
1249a1d0abeSdanielk1977   }
1259a1d0abeSdanielk1977   return TCL_OK;
1269a1d0abeSdanielk1977 }
1279a1d0abeSdanielk1977 
1289a1d0abeSdanielk1977 /*
1297d8085a8Sdrh ** Generate a text representation of a pointer that can be understood
1307d8085a8Sdrh ** by the getDbPointer and getVmPointer routines above.
1317d8085a8Sdrh **
1327d8085a8Sdrh ** The problem is, on some machines (Solaris) if you do a printf with
1337d8085a8Sdrh ** "%p" you cannot turn around and do a scanf with the same "%p" and
1347d8085a8Sdrh ** get your pointer back.  You have to prepend a "0x" before it will
1357d8085a8Sdrh ** work.  Or at least that is what is reported to me (drh).  But this
1367d8085a8Sdrh ** behavior varies from machine to machine.  The solution used her is
1377d8085a8Sdrh ** to test the string right after it is generated to see if it can be
1387d8085a8Sdrh ** understood by scanf, and if not, try prepending an "0x" to see if
1397d8085a8Sdrh ** that helps.  If nothing works, a fatal error is generated.
1407d8085a8Sdrh */
1417d8085a8Sdrh static int makePointerStr(Tcl_Interp *interp, char *zPtr, void *p){
1427d8085a8Sdrh   void *p2;
1437d8085a8Sdrh   sprintf(zPtr, PTR_FMT, p);
1447d8085a8Sdrh   if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){
1457d8085a8Sdrh     sprintf(zPtr, "0x" PTR_FMT, p);
1467d8085a8Sdrh     if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){
1477d8085a8Sdrh       Tcl_AppendResult(interp, "unable to convert a pointer to a string "
1487d8085a8Sdrh          "in the file " __FILE__ " in function makePointerStr().  Please "
1497d8085a8Sdrh          "report this problem to the SQLite mailing list or as a new but "
1507d8085a8Sdrh          "report.  Please provide detailed information about how you compiled "
1517d8085a8Sdrh          "SQLite and what computer you are running on.", 0);
1527d8085a8Sdrh       return TCL_ERROR;
1537d8085a8Sdrh     }
1547d8085a8Sdrh   }
1557d8085a8Sdrh   return TCL_OK;
1567d8085a8Sdrh }
1577d8085a8Sdrh 
1587d8085a8Sdrh /*
1596f8a503dSdanielk1977 ** The callback routine for sqlite3_exec_printf().
160d1bf3512Sdrh */
161d1bf3512Sdrh static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){
162d1bf3512Sdrh   Tcl_DString *str = (Tcl_DString*)pArg;
163d1bf3512Sdrh   int i;
164d1bf3512Sdrh 
165d1bf3512Sdrh   if( Tcl_DStringLength(str)==0 ){
166d1bf3512Sdrh     for(i=0; i<argc; i++){
167d1bf3512Sdrh       Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL");
168d1bf3512Sdrh     }
169d1bf3512Sdrh   }
170d1bf3512Sdrh   for(i=0; i<argc; i++){
171d1bf3512Sdrh     Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL");
172d1bf3512Sdrh   }
173d1bf3512Sdrh   return 0;
174d1bf3512Sdrh }
175d1bf3512Sdrh 
176d1bf3512Sdrh /*
1776f8a503dSdanielk1977 ** Usage:  sqlite3_exec_printf  DB  FORMAT  STRING
178d1bf3512Sdrh **
1796f8a503dSdanielk1977 ** Invoke the sqlite3_exec_printf() interface using the open database
180d1bf3512Sdrh ** DB.  The SQL is the string FORMAT.  The format string should contain
181d1bf3512Sdrh ** one %s or %q.  STRING is the value inserted into %s or %q.
182d1bf3512Sdrh */
183d1bf3512Sdrh static int test_exec_printf(
184d1bf3512Sdrh   void *NotUsed,
185d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
186d1bf3512Sdrh   int argc,              /* Number of arguments */
187d1bf3512Sdrh   char **argv            /* Text of each argument */
188d1bf3512Sdrh ){
189d1bf3512Sdrh   sqlite *db;
190d1bf3512Sdrh   Tcl_DString str;
191d1bf3512Sdrh   int rc;
192d1bf3512Sdrh   char *zErr = 0;
193d1bf3512Sdrh   char zBuf[30];
194d1bf3512Sdrh   if( argc!=4 ){
195d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
196d1bf3512Sdrh        " DB FORMAT STRING", 0);
197d1bf3512Sdrh     return TCL_ERROR;
198d1bf3512Sdrh   }
199b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
200d1bf3512Sdrh   Tcl_DStringInit(&str);
2016f8a503dSdanielk1977   rc = sqlite3_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]);
202d1bf3512Sdrh   sprintf(zBuf, "%d", rc);
203d1bf3512Sdrh   Tcl_AppendElement(interp, zBuf);
204d1bf3512Sdrh   Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
205d1bf3512Sdrh   Tcl_DStringFree(&str);
206d1bf3512Sdrh   if( zErr ) free(zErr);
207d1bf3512Sdrh   return TCL_OK;
208d1bf3512Sdrh }
209d1bf3512Sdrh 
210d1bf3512Sdrh /*
2116f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_z_test  SEPARATOR  ARG0  ARG1 ...
212d93d8a81Sdrh **
213d93d8a81Sdrh ** Test the %z format of mprintf().  Use multiple mprintf() calls to
214d93d8a81Sdrh ** concatenate arg0 through argn using separator as the separator.
215d93d8a81Sdrh ** Return the result.
216d93d8a81Sdrh */
217d93d8a81Sdrh static int test_mprintf_z(
218d93d8a81Sdrh   void *NotUsed,
219d93d8a81Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
220d93d8a81Sdrh   int argc,              /* Number of arguments */
221d93d8a81Sdrh   char **argv            /* Text of each argument */
222d93d8a81Sdrh ){
223d93d8a81Sdrh   char *zResult = 0;
224d93d8a81Sdrh   int i;
225d93d8a81Sdrh 
226d93d8a81Sdrh   for(i=2; i<argc; i++){
2274adee20fSdanielk1977     zResult = sqlite3MPrintf("%z%s%s", zResult, argv[1], argv[i]);
228d93d8a81Sdrh   }
229d93d8a81Sdrh   Tcl_AppendResult(interp, zResult, 0);
2305f968436Sdrh   sqliteFree(zResult);
231d93d8a81Sdrh   return TCL_OK;
232d93d8a81Sdrh }
233d93d8a81Sdrh 
234d93d8a81Sdrh /*
2356f8a503dSdanielk1977 ** Usage:  sqlite3_get_table_printf  DB  FORMAT  STRING
236d1bf3512Sdrh **
2376f8a503dSdanielk1977 ** Invoke the sqlite3_get_table_printf() interface using the open database
238d1bf3512Sdrh ** DB.  The SQL is the string FORMAT.  The format string should contain
239d1bf3512Sdrh ** one %s or %q.  STRING is the value inserted into %s or %q.
240d1bf3512Sdrh */
241d1bf3512Sdrh static int test_get_table_printf(
242d1bf3512Sdrh   void *NotUsed,
243d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
244d1bf3512Sdrh   int argc,              /* Number of arguments */
245d1bf3512Sdrh   char **argv            /* Text of each argument */
246d1bf3512Sdrh ){
247d1bf3512Sdrh   sqlite *db;
248d1bf3512Sdrh   Tcl_DString str;
249d1bf3512Sdrh   int rc;
250d1bf3512Sdrh   char *zErr = 0;
251d1bf3512Sdrh   int nRow, nCol;
252d1bf3512Sdrh   char **aResult;
253d1bf3512Sdrh   int i;
254d1bf3512Sdrh   char zBuf[30];
255d1bf3512Sdrh   if( argc!=4 ){
256d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
257d1bf3512Sdrh        " DB FORMAT STRING", 0);
258d1bf3512Sdrh     return TCL_ERROR;
259d1bf3512Sdrh   }
260b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
261d1bf3512Sdrh   Tcl_DStringInit(&str);
2626f8a503dSdanielk1977   rc = sqlite3_get_table_printf(db, argv[2], &aResult, &nRow, &nCol,
263d1bf3512Sdrh                &zErr, argv[3]);
264d1bf3512Sdrh   sprintf(zBuf, "%d", rc);
265d1bf3512Sdrh   Tcl_AppendElement(interp, zBuf);
266d1bf3512Sdrh   if( rc==SQLITE_OK ){
267d1bf3512Sdrh     sprintf(zBuf, "%d", nRow);
268d1bf3512Sdrh     Tcl_AppendElement(interp, zBuf);
269d1bf3512Sdrh     sprintf(zBuf, "%d", nCol);
270d1bf3512Sdrh     Tcl_AppendElement(interp, zBuf);
271d1bf3512Sdrh     for(i=0; i<(nRow+1)*nCol; i++){
272d1bf3512Sdrh       Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL");
273d1bf3512Sdrh     }
274d1bf3512Sdrh   }else{
275d1bf3512Sdrh     Tcl_AppendElement(interp, zErr);
276d1bf3512Sdrh   }
2776f8a503dSdanielk1977   sqlite3_free_table(aResult);
278d1bf3512Sdrh   if( zErr ) free(zErr);
279d1bf3512Sdrh   return TCL_OK;
280d1bf3512Sdrh }
281d1bf3512Sdrh 
282af9ff33aSdrh 
283af9ff33aSdrh /*
2846f8a503dSdanielk1977 ** Usage:  sqlite3_last_insert_rowid DB
285af9ff33aSdrh **
286af9ff33aSdrh ** Returns the integer ROWID of the most recent insert.
287af9ff33aSdrh */
288af9ff33aSdrh static int test_last_rowid(
289af9ff33aSdrh   void *NotUsed,
290af9ff33aSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
291af9ff33aSdrh   int argc,              /* Number of arguments */
292af9ff33aSdrh   char **argv            /* Text of each argument */
293af9ff33aSdrh ){
294af9ff33aSdrh   sqlite *db;
295af9ff33aSdrh   char zBuf[30];
296af9ff33aSdrh 
297af9ff33aSdrh   if( argc!=2 ){
298af9ff33aSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0);
299af9ff33aSdrh     return TCL_ERROR;
300af9ff33aSdrh   }
301b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
302c572ef7fSdanielk1977   sprintf(zBuf, "%lld", sqlite3_last_insert_rowid(db));
303af9ff33aSdrh   Tcl_AppendResult(interp, zBuf, 0);
304af9ff33aSdrh   return SQLITE_OK;
305af9ff33aSdrh }
306af9ff33aSdrh 
307d1bf3512Sdrh /*
3086f8a503dSdanielk1977 ** Usage:  sqlite3_close DB
309d1bf3512Sdrh **
3106f8a503dSdanielk1977 ** Closes the database opened by sqlite3_open.
311d1bf3512Sdrh */
312d1bf3512Sdrh static int sqlite_test_close(
313d1bf3512Sdrh   void *NotUsed,
314d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
315d1bf3512Sdrh   int argc,              /* Number of arguments */
316d1bf3512Sdrh   char **argv            /* Text of each argument */
317d1bf3512Sdrh ){
318d1bf3512Sdrh   sqlite *db;
31996d81f99Sdanielk1977   int rc;
320d1bf3512Sdrh   if( argc!=2 ){
321d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
322d1bf3512Sdrh        " FILENAME\"", 0);
323d1bf3512Sdrh     return TCL_ERROR;
324d1bf3512Sdrh   }
325b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
32696d81f99Sdanielk1977   rc = sqlite3_close(db);
327f9d64d2cSdanielk1977   Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
328d1bf3512Sdrh   return TCL_OK;
329d1bf3512Sdrh }
330d1bf3512Sdrh 
331d1bf3512Sdrh /*
332c22bd47dSdrh ** Implementation of the x_coalesce() function.
333c22bd47dSdrh ** Return the first argument non-NULL argument.
334c22bd47dSdrh */
3350ae8b831Sdanielk1977 static void ifnullFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
336c22bd47dSdrh   int i;
337c22bd47dSdrh   for(i=0; i<argc; i++){
3389c054830Sdrh     if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){
339d8123366Sdanielk1977       sqlite3_result_text(context, sqlite3_value_text(argv[i]), -1,
340d8123366Sdanielk1977           SQLITE_TRANSIENT);
341c22bd47dSdrh       break;
342c22bd47dSdrh     }
343c22bd47dSdrh   }
344c22bd47dSdrh }
345c22bd47dSdrh 
346c22bd47dSdrh /*
347d1d9fc33Sdrh ** A structure into which to accumulate text.
348d1d9fc33Sdrh */
349d1d9fc33Sdrh struct dstr {
350d1d9fc33Sdrh   int nAlloc;  /* Space allocated */
351d1d9fc33Sdrh   int nUsed;   /* Space used */
352d1d9fc33Sdrh   char *z;     /* The space */
353d1d9fc33Sdrh };
354d1d9fc33Sdrh 
355d1d9fc33Sdrh /*
356d1d9fc33Sdrh ** Append text to a dstr
357d1d9fc33Sdrh */
358d1d9fc33Sdrh static void dstrAppend(struct dstr *p, const char *z, int divider){
359d1d9fc33Sdrh   int n = strlen(z);
360d1d9fc33Sdrh   if( p->nUsed + n + 2 > p->nAlloc ){
361d1d9fc33Sdrh     char *zNew;
362d1d9fc33Sdrh     p->nAlloc = p->nAlloc*2 + n + 200;
363d1d9fc33Sdrh     zNew = sqliteRealloc(p->z, p->nAlloc);
364d1d9fc33Sdrh     if( zNew==0 ){
365d1d9fc33Sdrh       sqliteFree(p->z);
366d1d9fc33Sdrh       memset(p, 0, sizeof(*p));
367d1d9fc33Sdrh       return;
368d1d9fc33Sdrh     }
369d1d9fc33Sdrh     p->z = zNew;
370d1d9fc33Sdrh   }
371d1d9fc33Sdrh   if( divider && p->nUsed>0 ){
372d1d9fc33Sdrh     p->z[p->nUsed++] = divider;
373d1d9fc33Sdrh   }
374d1d9fc33Sdrh   memcpy(&p->z[p->nUsed], z, n+1);
375d1d9fc33Sdrh   p->nUsed += n;
376d1d9fc33Sdrh }
377d1d9fc33Sdrh 
378d1d9fc33Sdrh /*
3794adee20fSdanielk1977 ** Invoked for each callback from sqlite3ExecFunc
380d1d9fc33Sdrh */
381d1d9fc33Sdrh static int execFuncCallback(void *pData, int argc, char **argv, char **NotUsed){
382d1d9fc33Sdrh   struct dstr *p = (struct dstr*)pData;
383d1d9fc33Sdrh   int i;
384d1d9fc33Sdrh   for(i=0; i<argc; i++){
385d1d9fc33Sdrh     if( argv[i]==0 ){
386d1d9fc33Sdrh       dstrAppend(p, "NULL", ' ');
387d1d9fc33Sdrh     }else{
388d1d9fc33Sdrh       dstrAppend(p, argv[i], ' ');
389d1d9fc33Sdrh     }
390d1d9fc33Sdrh   }
391d1d9fc33Sdrh   return 0;
392d1d9fc33Sdrh }
393d1d9fc33Sdrh 
394d1d9fc33Sdrh /*
395e35ee196Sdanielk1977 ** Implementation of the x_sqlite_exec() function.  This function takes
396c22bd47dSdrh ** a single argument and attempts to execute that argument as SQL code.
3976cbe1f1bSdrh ** This is illegal and should set the SQLITE_MISUSE flag on the database.
398c22bd47dSdrh **
3996f8a503dSdanielk1977 ** 2004-Jan-07:  We have changed this to make it legal to call sqlite3_exec()
400d1d9fc33Sdrh ** from within a function call.
401d1d9fc33Sdrh **
402c22bd47dSdrh ** This routine simulates the effect of having two threads attempt to
403c22bd47dSdrh ** use the same database at the same time.
404c22bd47dSdrh */
40551ad0ecdSdanielk1977 static void sqlite3ExecFunc(
4060ae8b831Sdanielk1977   sqlite3_context *context,
40751ad0ecdSdanielk1977   int argc,
40851ad0ecdSdanielk1977   sqlite3_value **argv
40951ad0ecdSdanielk1977 ){
410d1d9fc33Sdrh   struct dstr x;
411d1d9fc33Sdrh   memset(&x, 0, sizeof(x));
41251ad0ecdSdanielk1977   sqlite3_exec((sqlite*)sqlite3_user_data(context),
4134f26d6c4Sdrh       sqlite3_value_text(argv[0]),
414d1d9fc33Sdrh       execFuncCallback, &x, 0);
415d8123366Sdanielk1977   sqlite3_result_text(context, x.z, x.nUsed, SQLITE_TRANSIENT);
416d1d9fc33Sdrh   sqliteFree(x.z);
417c22bd47dSdrh }
418c22bd47dSdrh 
419c22bd47dSdrh /*
420c22bd47dSdrh ** Usage:  sqlite_test_create_function DB
421c22bd47dSdrh **
4226f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order
423c22bd47dSdrh ** to create a function named "x_coalesce".  This function does the same thing
424c22bd47dSdrh ** as the "coalesce" function.  This function also registers an SQL function
425e35ee196Sdanielk1977 ** named "x_sqlite_exec" that invokes sqlite3_exec().  Invoking sqlite3_exec()
426c22bd47dSdrh ** in this way is illegal recursion and should raise an SQLITE_MISUSE error.
427c22bd47dSdrh ** The effect is similar to trying to use the same database connection from
428c22bd47dSdrh ** two threads at the same time.
429c22bd47dSdrh **
430c22bd47dSdrh ** The original motivation for this routine was to be able to call the
4316f8a503dSdanielk1977 ** sqlite3_create_function function while a query is in progress in order
432c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
433c22bd47dSdrh */
434c2eef3b3Sdrh static int test_create_function(
435c22bd47dSdrh   void *NotUsed,
436c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
437c22bd47dSdrh   int argc,              /* Number of arguments */
438c22bd47dSdrh   char **argv            /* Text of each argument */
439c22bd47dSdrh ){
440c22bd47dSdrh   sqlite *db;
441312d6b36Sdanielk1977   sqlite3_value *pVal;
442c22bd47dSdrh   extern void Md5_Register(sqlite*);
443312d6b36Sdanielk1977 
444c22bd47dSdrh   if( argc!=2 ){
445c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
446c22bd47dSdrh        " FILENAME\"", 0);
447c22bd47dSdrh     return TCL_ERROR;
448c22bd47dSdrh   }
449b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
450312d6b36Sdanielk1977   sqlite3_create_function(db, "x_coalesce", -1, SQLITE_ANY, 0,
451d8123366Sdanielk1977       ifnullFunc, 0, 0);
452312d6b36Sdanielk1977 
453312d6b36Sdanielk1977   /* Use the sqlite3_create_function16() API here. Mainly for fun, but also
454312d6b36Sdanielk1977   ** because it is not tested anywhere else. */
455312d6b36Sdanielk1977   pVal = sqlite3ValueNew();
456312d6b36Sdanielk1977   sqlite3ValueSetStr(pVal, -1, "x_sqlite_exec", SQLITE_UTF8, SQLITE_STATIC);
457312d6b36Sdanielk1977   sqlite3_create_function16(db, sqlite3ValueText(pVal, SQLITE_UTF16NATIVE),
458312d6b36Sdanielk1977       1, SQLITE_UTF16, db, sqlite3ExecFunc, 0, 0);
459312d6b36Sdanielk1977   sqlite3ValueFree(pVal);
460c22bd47dSdrh   return TCL_OK;
461c22bd47dSdrh }
462c22bd47dSdrh 
463c22bd47dSdrh /*
464c22bd47dSdrh ** Routines to implement the x_count() aggregate function.
465c22bd47dSdrh */
466c22bd47dSdrh typedef struct CountCtx CountCtx;
467c22bd47dSdrh struct CountCtx {
468c22bd47dSdrh   int n;
469c22bd47dSdrh };
4700ae8b831Sdanielk1977 static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
471c22bd47dSdrh   CountCtx *p;
4724f26d6c4Sdrh   p = sqlite3_aggregate_context(context, sizeof(*p));
4739c054830Sdrh   if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0]) ) && p ){
474c22bd47dSdrh     p->n++;
475c22bd47dSdrh   }
476c22bd47dSdrh }
4770ae8b831Sdanielk1977 static void countFinalize(sqlite3_context *context){
478c22bd47dSdrh   CountCtx *p;
4794f26d6c4Sdrh   p = sqlite3_aggregate_context(context, sizeof(*p));
480c572ef7fSdanielk1977   sqlite3_result_int(context, p ? p->n : 0);
481c22bd47dSdrh }
482c22bd47dSdrh 
483c22bd47dSdrh /*
484c22bd47dSdrh ** Usage:  sqlite_test_create_aggregate DB
485c22bd47dSdrh **
4866f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order
487c22bd47dSdrh ** to create a function named "x_count".  This function does the same thing
488c22bd47dSdrh ** as the "md5sum" function.
489c22bd47dSdrh **
490c22bd47dSdrh ** The original motivation for this routine was to be able to call the
4916f8a503dSdanielk1977 ** sqlite3_create_aggregate function while a query is in progress in order
492c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
493c22bd47dSdrh */
494c2eef3b3Sdrh static int test_create_aggregate(
495c22bd47dSdrh   void *NotUsed,
496c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
497c22bd47dSdrh   int argc,              /* Number of arguments */
498c22bd47dSdrh   char **argv            /* Text of each argument */
499c22bd47dSdrh ){
500c22bd47dSdrh   sqlite *db;
501c22bd47dSdrh   if( argc!=2 ){
502c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
503c22bd47dSdrh        " FILENAME\"", 0);
504c22bd47dSdrh     return TCL_ERROR;
505c22bd47dSdrh   }
506b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
507f9d64d2cSdanielk1977   sqlite3_create_function(db, "x_count", 0, SQLITE_UTF8, 0, 0,
508d8123366Sdanielk1977       countStep,countFinalize);
509f9d64d2cSdanielk1977   sqlite3_create_function(db, "x_count", 1, SQLITE_UTF8, 0, 0,
510d8123366Sdanielk1977       countStep,countFinalize);
511c22bd47dSdrh   return TCL_OK;
512c22bd47dSdrh }
513c22bd47dSdrh 
514c22bd47dSdrh 
515c22bd47dSdrh 
516c22bd47dSdrh /*
5176f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER
518d1bf3512Sdrh **
519d1bf3512Sdrh ** Call mprintf with three integer arguments
520d1bf3512Sdrh */
5216f8a503dSdanielk1977 static int sqlite3_mprintf_int(
522d1bf3512Sdrh   void *NotUsed,
523d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
524d1bf3512Sdrh   int argc,              /* Number of arguments */
525d1bf3512Sdrh   char **argv            /* Text of each argument */
526d1bf3512Sdrh ){
527d1bf3512Sdrh   int a[3], i;
528d1bf3512Sdrh   char *z;
529d1bf3512Sdrh   if( argc!=5 ){
530d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
531d1bf3512Sdrh        " FORMAT INT INT INT\"", 0);
532d1bf3512Sdrh     return TCL_ERROR;
533d1bf3512Sdrh   }
534d1bf3512Sdrh   for(i=2; i<5; i++){
535d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
536d1bf3512Sdrh   }
5376f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]);
538d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
5393f4fedb2Sdrh   sqlite3_free(z);
540d1bf3512Sdrh   return TCL_OK;
541d1bf3512Sdrh }
542d1bf3512Sdrh 
543d1bf3512Sdrh /*
544*9d213ef0Sdrh ** If zNum represents an integer that will fit in 64-bits, then set
545*9d213ef0Sdrh ** *pValue to that integer and return true.  Otherwise return false.
546*9d213ef0Sdrh */
547*9d213ef0Sdrh static int sqlite3GetInt64(const char *zNum, i64 *pValue){
548*9d213ef0Sdrh   if( sqlite3FitsIn64Bits(zNum) ){
549*9d213ef0Sdrh     sqlite3atoi64(zNum, pValue);
550*9d213ef0Sdrh     return 1;
551*9d213ef0Sdrh   }
552*9d213ef0Sdrh   return 0;
553*9d213ef0Sdrh }
554*9d213ef0Sdrh 
555*9d213ef0Sdrh /*
556e9707671Sdrh ** Usage:  sqlite3_mprintf_int64 FORMAT INTEGER INTEGER INTEGER
557e9707671Sdrh **
558e9707671Sdrh ** Call mprintf with three 64-bit integer arguments
559e9707671Sdrh */
560e9707671Sdrh static int sqlite3_mprintf_int64(
561e9707671Sdrh   void *NotUsed,
562e9707671Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
563e9707671Sdrh   int argc,              /* Number of arguments */
564e9707671Sdrh   char **argv            /* Text of each argument */
565e9707671Sdrh ){
566e9707671Sdrh   int i;
567e9707671Sdrh   sqlite_int64 a[3];
568e9707671Sdrh   char *z;
569e9707671Sdrh   if( argc!=5 ){
570e9707671Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
571e9707671Sdrh        " FORMAT INT INT INT\"", 0);
572e9707671Sdrh     return TCL_ERROR;
573e9707671Sdrh   }
574e9707671Sdrh   for(i=2; i<5; i++){
575e9707671Sdrh     if( !sqlite3GetInt64(argv[i], &a[i-2]) ){
576e9707671Sdrh       Tcl_AppendResult(interp, "argument is not a valid 64-bit integer", 0);
577e9707671Sdrh       return TCL_ERROR;
578e9707671Sdrh     }
579e9707671Sdrh   }
580e9707671Sdrh   z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]);
581e9707671Sdrh   Tcl_AppendResult(interp, z, 0);
582e9707671Sdrh   sqlite3_free(z);
583e9707671Sdrh   return TCL_OK;
584e9707671Sdrh }
585e9707671Sdrh 
586e9707671Sdrh /*
5876f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT INTEGER INTEGER STRING
588d1bf3512Sdrh **
589d1bf3512Sdrh ** Call mprintf with two integer arguments and one string argument
590d1bf3512Sdrh */
5916f8a503dSdanielk1977 static int sqlite3_mprintf_str(
592d1bf3512Sdrh   void *NotUsed,
593d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
594d1bf3512Sdrh   int argc,              /* Number of arguments */
595d1bf3512Sdrh   char **argv            /* Text of each argument */
596d1bf3512Sdrh ){
597d1bf3512Sdrh   int a[3], i;
598d1bf3512Sdrh   char *z;
599f220b24fSchw   if( argc<4 || argc>5 ){
600d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
601f220b24fSchw        " FORMAT INT INT ?STRING?\"", 0);
602d1bf3512Sdrh     return TCL_ERROR;
603d1bf3512Sdrh   }
604d1bf3512Sdrh   for(i=2; i<4; i++){
605d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
606d1bf3512Sdrh   }
6076f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL);
608d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
6093f4fedb2Sdrh   sqlite3_free(z);
610d1bf3512Sdrh   return TCL_OK;
611d1bf3512Sdrh }
612d1bf3512Sdrh 
613d1bf3512Sdrh /*
6146f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT INTEGER INTEGER DOUBLE
615d1bf3512Sdrh **
616d1bf3512Sdrh ** Call mprintf with two integer arguments and one double argument
617d1bf3512Sdrh */
6186f8a503dSdanielk1977 static int sqlite3_mprintf_double(
619d1bf3512Sdrh   void *NotUsed,
620d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
621d1bf3512Sdrh   int argc,              /* Number of arguments */
622d1bf3512Sdrh   char **argv            /* Text of each argument */
623d1bf3512Sdrh ){
624d1bf3512Sdrh   int a[3], i;
625d1bf3512Sdrh   double r;
626d1bf3512Sdrh   char *z;
627d1bf3512Sdrh   if( argc!=5 ){
628d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
629d1bf3512Sdrh        " FORMAT INT INT STRING\"", 0);
630d1bf3512Sdrh     return TCL_ERROR;
631d1bf3512Sdrh   }
632d1bf3512Sdrh   for(i=2; i<4; i++){
633d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
634d1bf3512Sdrh   }
635d1bf3512Sdrh   if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR;
6366f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], r);
637d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
6383f4fedb2Sdrh   sqlite3_free(z);
639d1bf3512Sdrh   return TCL_OK;
640d1bf3512Sdrh }
641d1bf3512Sdrh 
642d1bf3512Sdrh /*
6436f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT DOUBLE DOUBLE
644b621c237Sdrh **
645b621c237Sdrh ** Call mprintf with a single double argument which is the product of the
646b621c237Sdrh ** two arguments given above.  This is used to generate overflow and underflow
647b621c237Sdrh ** doubles to test that they are converted properly.
648b621c237Sdrh */
6496f8a503dSdanielk1977 static int sqlite3_mprintf_scaled(
650b621c237Sdrh   void *NotUsed,
651b621c237Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
652b621c237Sdrh   int argc,              /* Number of arguments */
653b621c237Sdrh   char **argv            /* Text of each argument */
654b621c237Sdrh ){
655b621c237Sdrh   int i;
656b621c237Sdrh   double r[2];
657b621c237Sdrh   char *z;
658b621c237Sdrh   if( argc!=4 ){
659b621c237Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
660b621c237Sdrh        " FORMAT DOUBLE DOUBLE\"", 0);
661b621c237Sdrh     return TCL_ERROR;
662b621c237Sdrh   }
663b621c237Sdrh   for(i=2; i<4; i++){
664b621c237Sdrh     if( Tcl_GetDouble(interp, argv[i], &r[i-2]) ) return TCL_ERROR;
665b621c237Sdrh   }
6666f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], r[0]*r[1]);
667b621c237Sdrh   Tcl_AppendResult(interp, z, 0);
6683f4fedb2Sdrh   sqlite3_free(z);
669b621c237Sdrh   return TCL_OK;
670b621c237Sdrh }
671b621c237Sdrh 
672b621c237Sdrh /*
673daffd0e5Sdrh ** Usage: sqlite_malloc_fail N
674daffd0e5Sdrh **
675afa4a020Sdrh ** Rig sqliteMalloc() to fail on the N-th call.  Turn off this mechanism
6766f8a503dSdanielk1977 ** and reset the sqlite3_malloc_failed variable is N==0.
677daffd0e5Sdrh */
678faa57accSdrh #ifdef SQLITE_DEBUG
679daffd0e5Sdrh static int sqlite_malloc_fail(
680daffd0e5Sdrh   void *NotUsed,
681daffd0e5Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
682daffd0e5Sdrh   int argc,              /* Number of arguments */
683daffd0e5Sdrh   char **argv            /* Text of each argument */
684daffd0e5Sdrh ){
685daffd0e5Sdrh   int n;
686daffd0e5Sdrh   if( argc!=2 ){
687daffd0e5Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0);
688daffd0e5Sdrh     return TCL_ERROR;
689daffd0e5Sdrh   }
690daffd0e5Sdrh   if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
6916f8a503dSdanielk1977   sqlite3_iMallocFail = n;
6926f8a503dSdanielk1977   sqlite3_malloc_failed = 0;
693daffd0e5Sdrh   return TCL_OK;
694daffd0e5Sdrh }
695daffd0e5Sdrh #endif
696daffd0e5Sdrh 
697daffd0e5Sdrh /*
698daffd0e5Sdrh ** Usage: sqlite_malloc_stat
699daffd0e5Sdrh **
700daffd0e5Sdrh ** Return the number of prior calls to sqliteMalloc() and sqliteFree().
701daffd0e5Sdrh */
702faa57accSdrh #ifdef SQLITE_DEBUG
703daffd0e5Sdrh static int sqlite_malloc_stat(
704daffd0e5Sdrh   void *NotUsed,
705daffd0e5Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
706daffd0e5Sdrh   int argc,              /* Number of arguments */
707daffd0e5Sdrh   char **argv            /* Text of each argument */
708daffd0e5Sdrh ){
709daffd0e5Sdrh   char zBuf[200];
7106f8a503dSdanielk1977   sprintf(zBuf, "%d %d %d", sqlite3_nMalloc, sqlite3_nFree, sqlite3_iMallocFail);
711daffd0e5Sdrh   Tcl_AppendResult(interp, zBuf, 0);
712daffd0e5Sdrh   return TCL_OK;
713daffd0e5Sdrh }
714daffd0e5Sdrh #endif
715daffd0e5Sdrh 
716daffd0e5Sdrh /*
71728b4e489Sdrh ** Usage:  sqlite_abort
71828b4e489Sdrh **
71928b4e489Sdrh ** Shutdown the process immediately.  This is not a clean shutdown.
72028b4e489Sdrh ** This command is used to test the recoverability of a database in
72128b4e489Sdrh ** the event of a program crash.
72228b4e489Sdrh */
72328b4e489Sdrh static int sqlite_abort(
72428b4e489Sdrh   void *NotUsed,
72528b4e489Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
72628b4e489Sdrh   int argc,              /* Number of arguments */
72728b4e489Sdrh   char **argv            /* Text of each argument */
72828b4e489Sdrh ){
72928b4e489Sdrh   assert( interp==0 );   /* This will always fail */
73028b4e489Sdrh   return TCL_OK;
73128b4e489Sdrh }
73228b4e489Sdrh 
73328b4e489Sdrh /*
7346cbe1f1bSdrh ** The following routine is a user-defined SQL function whose purpose
7356cbe1f1bSdrh ** is to test the sqlite_set_result() API.
7366cbe1f1bSdrh */
7370ae8b831Sdanielk1977 static void testFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
7386cbe1f1bSdrh   while( argc>=2 ){
7394f26d6c4Sdrh     const char *zArg0 = sqlite3_value_text(argv[0]);
7406d88bad4Sdanielk1977     if( zArg0 ){
7416d88bad4Sdanielk1977       if( 0==sqlite3StrICmp(zArg0, "int") ){
7426d88bad4Sdanielk1977         sqlite3_result_int(context, sqlite3_value_int(argv[1]));
7436d88bad4Sdanielk1977       }else if( sqlite3StrICmp(zArg0,"int64")==0 ){
7446d88bad4Sdanielk1977         sqlite3_result_int64(context, sqlite3_value_int64(argv[1]));
74551ad0ecdSdanielk1977       }else if( sqlite3StrICmp(zArg0,"string")==0 ){
746d8123366Sdanielk1977         sqlite3_result_text(context, sqlite3_value_text(argv[1]), -1,
747d8123366Sdanielk1977             SQLITE_TRANSIENT);
74851ad0ecdSdanielk1977       }else if( sqlite3StrICmp(zArg0,"double")==0 ){
7496d88bad4Sdanielk1977         sqlite3_result_double(context, sqlite3_value_double(argv[1]));
7506d88bad4Sdanielk1977       }else if( sqlite3StrICmp(zArg0,"null")==0 ){
7516d88bad4Sdanielk1977         sqlite3_result_null(context);
7526d88bad4Sdanielk1977       }else if( sqlite3StrICmp(zArg0,"value")==0 ){
7536d88bad4Sdanielk1977         sqlite3_result_value(context, argv[sqlite3_value_int(argv[1])]);
7546cbe1f1bSdrh       }else{
7556d88bad4Sdanielk1977         goto error_out;
7566d88bad4Sdanielk1977       }
7576d88bad4Sdanielk1977     }else{
7586d88bad4Sdanielk1977       goto error_out;
7596cbe1f1bSdrh     }
7606cbe1f1bSdrh     argc -= 2;
7616cbe1f1bSdrh     argv += 2;
7626cbe1f1bSdrh   }
7636d88bad4Sdanielk1977   return;
7646d88bad4Sdanielk1977 
7656d88bad4Sdanielk1977 error_out:
7666d88bad4Sdanielk1977   sqlite3_result_error(context,"first argument should be one of: "
7676d88bad4Sdanielk1977       "int int64 string double null value", -1);
7686cbe1f1bSdrh }
7696cbe1f1bSdrh 
7706cbe1f1bSdrh /*
7716cbe1f1bSdrh ** Usage:   sqlite_register_test_function  DB  NAME
7726cbe1f1bSdrh **
7736cbe1f1bSdrh ** Register the test SQL function on the database DB under the name NAME.
7746cbe1f1bSdrh */
775c2eef3b3Sdrh static int test_register_func(
7766cbe1f1bSdrh   void *NotUsed,
7776cbe1f1bSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
7786cbe1f1bSdrh   int argc,              /* Number of arguments */
7796cbe1f1bSdrh   char **argv            /* Text of each argument */
7806cbe1f1bSdrh ){
7816cbe1f1bSdrh   sqlite *db;
7826cbe1f1bSdrh   int rc;
7836cbe1f1bSdrh   if( argc!=3 ){
7846cbe1f1bSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
7856cbe1f1bSdrh        " DB FUNCTION-NAME", 0);
7866cbe1f1bSdrh     return TCL_ERROR;
7876cbe1f1bSdrh   }
788b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
789f9d64d2cSdanielk1977   rc = sqlite3_create_function(db, argv[2], -1, SQLITE_UTF8, 0,
790d8123366Sdanielk1977       testFunc, 0, 0);
7916cbe1f1bSdrh   if( rc!=0 ){
792f20b21c8Sdanielk1977     Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);
7936cbe1f1bSdrh     return TCL_ERROR;
7946cbe1f1bSdrh   }
7956cbe1f1bSdrh   return TCL_OK;
7966cbe1f1bSdrh }
7976cbe1f1bSdrh 
7986cbe1f1bSdrh /*
799106bb236Sdanielk1977 ** Usage:  sqlite3_finalize  STMT
800b86ccfb2Sdrh **
801106bb236Sdanielk1977 ** Finalize a statement handle.
802b86ccfb2Sdrh */
803b86ccfb2Sdrh static int test_finalize(
804106bb236Sdanielk1977   void * clientData,
805106bb236Sdanielk1977   Tcl_Interp *interp,
806106bb236Sdanielk1977   int objc,
807106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
808b86ccfb2Sdrh ){
809106bb236Sdanielk1977   sqlite3_stmt *pStmt;
810b86ccfb2Sdrh   int rc;
811106bb236Sdanielk1977 
812106bb236Sdanielk1977   if( objc!=2 ){
813106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
814106bb236Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
815b86ccfb2Sdrh     return TCL_ERROR;
816b86ccfb2Sdrh   }
817106bb236Sdanielk1977 
818106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
819106bb236Sdanielk1977 
820fc57d7bfSdanielk1977   rc = sqlite3_finalize(pStmt);
821b77f5dadSdanielk1977   Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
822106bb236Sdanielk1977   return TCL_OK;
823106bb236Sdanielk1977 }
824106bb236Sdanielk1977 
825106bb236Sdanielk1977 /*
826106bb236Sdanielk1977 ** Usage:  sqlite3_reset  STMT
827106bb236Sdanielk1977 **
828106bb236Sdanielk1977 ** Finalize a statement handle.
829106bb236Sdanielk1977 */
830106bb236Sdanielk1977 static int test_reset(
831106bb236Sdanielk1977   void * clientData,
832106bb236Sdanielk1977   Tcl_Interp *interp,
833106bb236Sdanielk1977   int objc,
834106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
835106bb236Sdanielk1977 ){
836106bb236Sdanielk1977   sqlite3_stmt *pStmt;
837106bb236Sdanielk1977   int rc;
838106bb236Sdanielk1977 
839106bb236Sdanielk1977   if( objc!=2 ){
840106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
841106bb236Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
842106bb236Sdanielk1977     return TCL_ERROR;
843106bb236Sdanielk1977   }
844106bb236Sdanielk1977 
845106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
846106bb236Sdanielk1977 
847fc57d7bfSdanielk1977   rc = sqlite3_reset(pStmt);
848106bb236Sdanielk1977   if( rc ){
849b86ccfb2Sdrh     return TCL_ERROR;
850b86ccfb2Sdrh   }
851b86ccfb2Sdrh   return TCL_OK;
852b86ccfb2Sdrh }
853b86ccfb2Sdrh 
8545a38705eSdrh /*
855fbcd585fSdanielk1977 ** Usage:  sqlite3_changes DB
85650457896Sdrh **
857fbcd585fSdanielk1977 ** Return the number of changes made to the database by the last SQL
858fbcd585fSdanielk1977 ** execution.
85950457896Sdrh */
860fbcd585fSdanielk1977 static int test_changes(
861fbcd585fSdanielk1977   void * clientData,
862fbcd585fSdanielk1977   Tcl_Interp *interp,
863fbcd585fSdanielk1977   int objc,
864fbcd585fSdanielk1977   Tcl_Obj *CONST objv[]
865fbcd585fSdanielk1977 ){
866fbcd585fSdanielk1977   sqlite3 *db;
867fbcd585fSdanielk1977   if( objc!=2 ){
868fbcd585fSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
869fbcd585fSdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
870fbcd585fSdanielk1977     return TCL_ERROR;
871fbcd585fSdanielk1977   }
872fbcd585fSdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
873fbcd585fSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_changes(db)));
874fbcd585fSdanielk1977   return TCL_OK;
875fbcd585fSdanielk1977 }
87650457896Sdrh 
87750457896Sdrh /*
8787c972decSdrh ** This is the "static_bind_value" that variables are bound to when
8796f8a503dSdanielk1977 ** the FLAG option of sqlite3_bind is "static"
88050457896Sdrh */
8817c972decSdrh static char *sqlite_static_bind_value = 0;
8827c972decSdrh 
8837c972decSdrh /*
8846f8a503dSdanielk1977 ** Usage:  sqlite3_bind  VM  IDX  VALUE  FLAGS
8857c972decSdrh **
8867c972decSdrh ** Sets the value of the IDX-th occurance of "?" in the original SQL
8877c972decSdrh ** string.  VALUE is the new value.  If FLAGS=="null" then VALUE is
8887c972decSdrh ** ignored and the value is set to NULL.  If FLAGS=="static" then
8897c972decSdrh ** the value is set to the value of a static variable named
8907c972decSdrh ** "sqlite_static_bind_value".  If FLAGS=="normal" then a copy
8917c972decSdrh ** of the VALUE is made.
8927c972decSdrh */
8937c972decSdrh static int test_bind(
89450457896Sdrh   void *NotUsed,
89550457896Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
89650457896Sdrh   int argc,              /* Number of arguments */
89750457896Sdrh   char **argv            /* Text of each argument */
89850457896Sdrh ){
899fc57d7bfSdanielk1977   sqlite3_stmt *pStmt;
90050457896Sdrh   int rc;
9017c972decSdrh   int idx;
9027c972decSdrh   if( argc!=5 ){
90350457896Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
9047c972decSdrh        " VM IDX VALUE (null|static|normal)\"", 0);
90550457896Sdrh     return TCL_ERROR;
90650457896Sdrh   }
907fc57d7bfSdanielk1977   if( getStmtPointer(interp, argv[1], &pStmt) ) return TCL_ERROR;
9087c972decSdrh   if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR;
9097c972decSdrh   if( strcmp(argv[4],"null")==0 ){
910fc57d7bfSdanielk1977     rc = sqlite3_bind_null(pStmt, idx);
9117c972decSdrh   }else if( strcmp(argv[4],"static")==0 ){
912fc57d7bfSdanielk1977     rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0);
9137c972decSdrh   }else if( strcmp(argv[4],"normal")==0 ){
914d8123366Sdanielk1977     rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, SQLITE_TRANSIENT);
9157c972decSdrh   }else{
9167c972decSdrh     Tcl_AppendResult(interp, "4th argument should be "
9177c972decSdrh         "\"null\" or \"static\" or \"normal\"", 0);
9187c972decSdrh     return TCL_ERROR;
9197c972decSdrh   }
92050457896Sdrh   if( rc ){
92150457896Sdrh     char zBuf[50];
92250457896Sdrh     sprintf(zBuf, "(%d) ", rc);
923f20b21c8Sdanielk1977     Tcl_AppendResult(interp, zBuf, sqlite3ErrStr(rc), 0);
92450457896Sdrh     return TCL_ERROR;
92550457896Sdrh   }
92650457896Sdrh   return TCL_OK;
92750457896Sdrh }
92850457896Sdrh 
9294e6af134Sdanielk1977 
9304e6af134Sdanielk1977 /*
9314e6af134Sdanielk1977 ** Usage: add_test_collate <db ptr> <utf8> <utf16le> <utf16be>
9324e6af134Sdanielk1977 **
9334e6af134Sdanielk1977 ** This function is used to test that SQLite selects the correct collation
9344e6af134Sdanielk1977 ** sequence callback when multiple versions (for different text encodings)
9354e6af134Sdanielk1977 ** are available.
9364e6af134Sdanielk1977 **
9374e6af134Sdanielk1977 ** Calling this routine registers the collation sequence "test_collate"
9384e6af134Sdanielk1977 ** with database handle <db>. The second argument must be a list of three
9394e6af134Sdanielk1977 ** boolean values. If the first is true, then a version of test_collate is
9404e6af134Sdanielk1977 ** registered for UTF-8, if the second is true, a version is registered for
9414e6af134Sdanielk1977 ** UTF-16le, if the third is true, a UTF-16be version is available.
9424e6af134Sdanielk1977 ** Previous versions of test_collate are deleted.
9434e6af134Sdanielk1977 **
9444e6af134Sdanielk1977 ** The collation sequence test_collate is implemented by calling the
9454e6af134Sdanielk1977 ** following TCL script:
9464e6af134Sdanielk1977 **
9474e6af134Sdanielk1977 **   "test_collate <enc> <lhs> <rhs>"
9484e6af134Sdanielk1977 **
9494e6af134Sdanielk1977 ** The <lhs> and <rhs> are the two values being compared, encoded in UTF-8.
9504e6af134Sdanielk1977 ** The <enc> parameter is the encoding of the collation function that
9514e6af134Sdanielk1977 ** SQLite selected to call. The TCL test script implements the
9524e6af134Sdanielk1977 ** "test_collate" proc.
9534e6af134Sdanielk1977 **
9544e6af134Sdanielk1977 ** Note that this will only work with one intepreter at a time, as the
9554e6af134Sdanielk1977 ** interp pointer to use when evaluating the TCL script is stored in
9564e6af134Sdanielk1977 ** pTestCollateInterp.
9574e6af134Sdanielk1977 */
9584e6af134Sdanielk1977 static Tcl_Interp* pTestCollateInterp;
9594e6af134Sdanielk1977 static int test_collate_func(
9604e6af134Sdanielk1977   void *pCtx,
9614e6af134Sdanielk1977   int nA, const void *zA,
9624e6af134Sdanielk1977   int nB, const void *zB
9634e6af134Sdanielk1977 ){
9644e6af134Sdanielk1977   Tcl_Interp *i = pTestCollateInterp;
9654e6af134Sdanielk1977   int encin = (int)pCtx;
9664e6af134Sdanielk1977   int res;
9674e6af134Sdanielk1977 
9684e6af134Sdanielk1977   sqlite3_value *pVal;
9694e6af134Sdanielk1977   Tcl_Obj *pX;
9704e6af134Sdanielk1977 
9714e6af134Sdanielk1977   pX = Tcl_NewStringObj("test_collate", -1);
9724e6af134Sdanielk1977   Tcl_IncrRefCount(pX);
9734e6af134Sdanielk1977 
9744e6af134Sdanielk1977   switch( encin ){
9754e6af134Sdanielk1977     case SQLITE_UTF8:
9764e6af134Sdanielk1977       Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-8",-1));
9774e6af134Sdanielk1977       break;
9784e6af134Sdanielk1977     case SQLITE_UTF16LE:
9794e6af134Sdanielk1977       Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-16LE",-1));
9804e6af134Sdanielk1977       break;
9814e6af134Sdanielk1977     case SQLITE_UTF16BE:
9824e6af134Sdanielk1977       Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-16BE",-1));
9834e6af134Sdanielk1977       break;
9844e6af134Sdanielk1977     default:
9854e6af134Sdanielk1977       assert(0);
9864e6af134Sdanielk1977   }
9874e6af134Sdanielk1977 
9884e6af134Sdanielk1977   pVal = sqlite3ValueNew();
989bfd6cce5Sdanielk1977   sqlite3ValueSetStr(pVal, nA, zA, encin, SQLITE_STATIC);
9904e6af134Sdanielk1977   Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj(sqlite3_value_text(pVal),-1));
991bfd6cce5Sdanielk1977   sqlite3ValueSetStr(pVal, nB, zB, encin, SQLITE_STATIC);
9924e6af134Sdanielk1977   Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj(sqlite3_value_text(pVal),-1));
9934e6af134Sdanielk1977   sqlite3ValueFree(pVal);
9944e6af134Sdanielk1977 
9954e6af134Sdanielk1977   Tcl_EvalObjEx(i, pX, 0);
9964e6af134Sdanielk1977   Tcl_DecrRefCount(pX);
9974e6af134Sdanielk1977   Tcl_GetIntFromObj(i, Tcl_GetObjResult(i), &res);
9984e6af134Sdanielk1977   return res;
9994e6af134Sdanielk1977 }
10004e6af134Sdanielk1977 static int test_collate(
10014e6af134Sdanielk1977   void * clientData,
10024e6af134Sdanielk1977   Tcl_Interp *interp,
10034e6af134Sdanielk1977   int objc,
10044e6af134Sdanielk1977   Tcl_Obj *CONST objv[]
10054e6af134Sdanielk1977 ){
10064e6af134Sdanielk1977   sqlite3 *db;
10074e6af134Sdanielk1977   int val;
1008312d6b36Sdanielk1977   sqlite3_value *pVal;
10094e6af134Sdanielk1977 
10104e6af134Sdanielk1977   if( objc!=5 ) goto bad_args;
10114e6af134Sdanielk1977   pTestCollateInterp = interp;
10124e6af134Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
10134e6af134Sdanielk1977 
10144e6af134Sdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR;
10154e6af134Sdanielk1977   sqlite3_create_collation(db, "test_collate", SQLITE_UTF8,
10164e6af134Sdanielk1977         (void *)SQLITE_UTF8, val?test_collate_func:0);
10174e6af134Sdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &val) ) return TCL_ERROR;
10184e6af134Sdanielk1977   sqlite3_create_collation(db, "test_collate", SQLITE_UTF16LE,
10194e6af134Sdanielk1977         (void *)SQLITE_UTF16LE, val?test_collate_func:0);
10204e6af134Sdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[4], &val) ) return TCL_ERROR;
1021312d6b36Sdanielk1977 
1022312d6b36Sdanielk1977   pVal = sqlite3ValueNew();
1023312d6b36Sdanielk1977   sqlite3ValueSetStr(pVal, -1, "test_collate", SQLITE_UTF8, SQLITE_STATIC);
1024312d6b36Sdanielk1977   sqlite3_create_collation16(db, sqlite3ValueText(pVal, SQLITE_UTF16NATIVE),
1025312d6b36Sdanielk1977         SQLITE_UTF16BE, (void *)SQLITE_UTF16BE, val?test_collate_func:0);
1026312d6b36Sdanielk1977   sqlite3ValueFree(pVal);
10274e6af134Sdanielk1977 
10284e6af134Sdanielk1977   return TCL_OK;
10294e6af134Sdanielk1977 
10304e6af134Sdanielk1977 bad_args:
10314e6af134Sdanielk1977   Tcl_AppendResult(interp, "wrong # args: should be \"",
10324e6af134Sdanielk1977       Tcl_GetStringFromObj(objv[0], 0), " <DB> <utf8> <utf16le> <utf16be>", 0);
10334e6af134Sdanielk1977   return TCL_ERROR;
10344e6af134Sdanielk1977 }
10354e6af134Sdanielk1977 
1036312d6b36Sdanielk1977 static void test_collate_needed_cb(
1037312d6b36Sdanielk1977   void *pCtx,
1038312d6b36Sdanielk1977   sqlite3 *db,
1039312d6b36Sdanielk1977   int eTextRep,
1040312d6b36Sdanielk1977   const void *notUsed
1041312d6b36Sdanielk1977 ){
1042312d6b36Sdanielk1977   int enc = db->enc;
1043312d6b36Sdanielk1977   sqlite3_create_collation(
1044312d6b36Sdanielk1977       db, "test_collate", db->enc, (void *)enc, test_collate_func);
1045312d6b36Sdanielk1977 }
1046312d6b36Sdanielk1977 
1047312d6b36Sdanielk1977 /*
1048312d6b36Sdanielk1977 ** Usage: add_test_collate_needed DB
1049312d6b36Sdanielk1977 */
1050312d6b36Sdanielk1977 static int test_collate_needed(
1051312d6b36Sdanielk1977   void * clientData,
1052312d6b36Sdanielk1977   Tcl_Interp *interp,
1053312d6b36Sdanielk1977   int objc,
1054312d6b36Sdanielk1977   Tcl_Obj *CONST objv[]
1055312d6b36Sdanielk1977 ){
1056312d6b36Sdanielk1977   sqlite3 *db;
1057312d6b36Sdanielk1977 
1058312d6b36Sdanielk1977   if( objc!=2 ) goto bad_args;
1059312d6b36Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1060312d6b36Sdanielk1977   sqlite3_collation_needed16(db, 0, test_collate_needed_cb);
1061312d6b36Sdanielk1977   return TCL_OK;
1062312d6b36Sdanielk1977 
1063312d6b36Sdanielk1977 bad_args:
1064312d6b36Sdanielk1977   Tcl_WrongNumArgs(interp, 1, objv, "DB");
1065312d6b36Sdanielk1977   return TCL_ERROR;
1066312d6b36Sdanielk1977 }
1067312d6b36Sdanielk1977 
1068c8e9a2dfSdanielk1977 /*
1069c8e9a2dfSdanielk1977 ** Usage: add_test_function <db ptr> <utf8> <utf16le> <utf16be>
1070c8e9a2dfSdanielk1977 **
1071c8e9a2dfSdanielk1977 ** This function is used to test that SQLite selects the correct user
1072c8e9a2dfSdanielk1977 ** function callback when multiple versions (for different text encodings)
1073c8e9a2dfSdanielk1977 ** are available.
1074c8e9a2dfSdanielk1977 **
1075c8e9a2dfSdanielk1977 ** Calling this routine registers up to three versions of the user function
1076c8e9a2dfSdanielk1977 ** "test_function" with database handle <db>.  If the second argument is
1077c8e9a2dfSdanielk1977 ** true, then a version of test_function is registered for UTF-8, if the
1078c8e9a2dfSdanielk1977 ** third is true, a version is registered for UTF-16le, if the fourth is
1079c8e9a2dfSdanielk1977 ** true, a UTF-16be version is available.  Previous versions of
1080c8e9a2dfSdanielk1977 ** test_function are deleted.
1081c8e9a2dfSdanielk1977 **
1082c8e9a2dfSdanielk1977 ** The user function is implemented by calling the following TCL script:
1083c8e9a2dfSdanielk1977 **
1084c8e9a2dfSdanielk1977 **   "test_function <enc> <arg>"
1085c8e9a2dfSdanielk1977 **
1086c8e9a2dfSdanielk1977 ** Where <enc> is one of UTF-8, UTF-16LE or UTF16BE, and <arg> is the
1087c8e9a2dfSdanielk1977 ** single argument passed to the SQL function. The value returned by
1088c8e9a2dfSdanielk1977 ** the TCL script is used as the return value of the SQL function. It
1089c8e9a2dfSdanielk1977 ** is passed to SQLite using UTF-16BE for a UTF-8 test_function(), UTF-8
1090c8e9a2dfSdanielk1977 ** for a UTF-16LE test_function(), and UTF-16LE for an implementation that
1091c8e9a2dfSdanielk1977 ** prefers UTF-16BE.
1092c8e9a2dfSdanielk1977 */
1093c8e9a2dfSdanielk1977 static void test_function_utf8(
1094c8e9a2dfSdanielk1977   sqlite3_context *pCtx,
1095c8e9a2dfSdanielk1977   int nArg,
1096c8e9a2dfSdanielk1977   sqlite3_value **argv
1097c8e9a2dfSdanielk1977 ){
1098c8e9a2dfSdanielk1977   Tcl_Interp *interp;
1099c8e9a2dfSdanielk1977   Tcl_Obj *pX;
1100c8e9a2dfSdanielk1977   sqlite3_value *pVal;
1101c8e9a2dfSdanielk1977   interp = (Tcl_Interp *)sqlite3_user_data(pCtx);
1102c8e9a2dfSdanielk1977   pX = Tcl_NewStringObj("test_function", -1);
1103c8e9a2dfSdanielk1977   Tcl_IncrRefCount(pX);
1104c8e9a2dfSdanielk1977   Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj("UTF-8", -1));
1105c8e9a2dfSdanielk1977   Tcl_ListObjAppendElement(interp, pX,
1106c8e9a2dfSdanielk1977       Tcl_NewStringObj(sqlite3_value_text(argv[0]), -1));
1107c8e9a2dfSdanielk1977   Tcl_EvalObjEx(interp, pX, 0);
1108c8e9a2dfSdanielk1977   Tcl_DecrRefCount(pX);
1109c8e9a2dfSdanielk1977   sqlite3_result_text(pCtx, Tcl_GetStringResult(interp), -1, SQLITE_TRANSIENT);
1110c8e9a2dfSdanielk1977   pVal = sqlite3ValueNew();
1111c8e9a2dfSdanielk1977   sqlite3ValueSetStr(pVal, -1, Tcl_GetStringResult(interp),
1112c8e9a2dfSdanielk1977       SQLITE_UTF8, SQLITE_STATIC);
1113c8e9a2dfSdanielk1977   sqlite3_result_text16be(pCtx, sqlite3_value_text16be(pVal),
1114c8e9a2dfSdanielk1977       -1, SQLITE_TRANSIENT);
1115c8e9a2dfSdanielk1977   sqlite3ValueFree(pVal);
1116c8e9a2dfSdanielk1977 }
1117c8e9a2dfSdanielk1977 static void test_function_utf16le(
1118c8e9a2dfSdanielk1977   sqlite3_context *pCtx,
1119c8e9a2dfSdanielk1977   int nArg,
1120c8e9a2dfSdanielk1977   sqlite3_value **argv
1121c8e9a2dfSdanielk1977 ){
1122c8e9a2dfSdanielk1977   Tcl_Interp *interp;
1123c8e9a2dfSdanielk1977   Tcl_Obj *pX;
1124c8e9a2dfSdanielk1977   sqlite3_value *pVal;
1125c8e9a2dfSdanielk1977   interp = (Tcl_Interp *)sqlite3_user_data(pCtx);
1126c8e9a2dfSdanielk1977   pX = Tcl_NewStringObj("test_function", -1);
1127c8e9a2dfSdanielk1977   Tcl_IncrRefCount(pX);
1128c8e9a2dfSdanielk1977   Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj("UTF-16LE", -1));
1129c8e9a2dfSdanielk1977   Tcl_ListObjAppendElement(interp, pX,
1130c8e9a2dfSdanielk1977       Tcl_NewStringObj(sqlite3_value_text(argv[0]), -1));
1131c8e9a2dfSdanielk1977   Tcl_EvalObjEx(interp, pX, 0);
1132c8e9a2dfSdanielk1977   Tcl_DecrRefCount(pX);
1133c8e9a2dfSdanielk1977   pVal = sqlite3ValueNew();
1134c8e9a2dfSdanielk1977   sqlite3ValueSetStr(pVal, -1, Tcl_GetStringResult(interp),
1135c8e9a2dfSdanielk1977       SQLITE_UTF8, SQLITE_STATIC);
1136c8e9a2dfSdanielk1977   sqlite3_result_text(pCtx,sqlite3_value_text(pVal),-1,SQLITE_TRANSIENT);
1137c8e9a2dfSdanielk1977   sqlite3ValueFree(pVal);
1138c8e9a2dfSdanielk1977 }
1139c8e9a2dfSdanielk1977 static void test_function_utf16be(
1140c8e9a2dfSdanielk1977   sqlite3_context *pCtx,
1141c8e9a2dfSdanielk1977   int nArg,
1142c8e9a2dfSdanielk1977   sqlite3_value **argv
1143c8e9a2dfSdanielk1977 ){
1144c8e9a2dfSdanielk1977   Tcl_Interp *interp;
1145c8e9a2dfSdanielk1977   Tcl_Obj *pX;
1146c8e9a2dfSdanielk1977   sqlite3_value *pVal;
1147c8e9a2dfSdanielk1977   interp = (Tcl_Interp *)sqlite3_user_data(pCtx);
1148c8e9a2dfSdanielk1977   pX = Tcl_NewStringObj("test_function", -1);
1149c8e9a2dfSdanielk1977   Tcl_IncrRefCount(pX);
1150c8e9a2dfSdanielk1977   Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj("UTF-16BE", -1));
1151c8e9a2dfSdanielk1977   Tcl_ListObjAppendElement(interp, pX,
1152c8e9a2dfSdanielk1977       Tcl_NewStringObj(sqlite3_value_text(argv[0]), -1));
1153c8e9a2dfSdanielk1977   Tcl_EvalObjEx(interp, pX, 0);
1154c8e9a2dfSdanielk1977   Tcl_DecrRefCount(pX);
1155c8e9a2dfSdanielk1977   pVal = sqlite3ValueNew();
1156c8e9a2dfSdanielk1977   sqlite3ValueSetStr(pVal, -1, Tcl_GetStringResult(interp),
1157c8e9a2dfSdanielk1977       SQLITE_UTF8, SQLITE_STATIC);
1158c8e9a2dfSdanielk1977   sqlite3_result_text16le(pCtx, sqlite3_value_text16le(pVal),
1159c8e9a2dfSdanielk1977       -1, SQLITE_TRANSIENT);
1160c8e9a2dfSdanielk1977   sqlite3ValueFree(pVal);
1161c8e9a2dfSdanielk1977 }
1162c8e9a2dfSdanielk1977 static int test_function(
1163c8e9a2dfSdanielk1977   void * clientData,
1164c8e9a2dfSdanielk1977   Tcl_Interp *interp,
1165c8e9a2dfSdanielk1977   int objc,
1166c8e9a2dfSdanielk1977   Tcl_Obj *CONST objv[]
1167c8e9a2dfSdanielk1977 ){
1168c8e9a2dfSdanielk1977   sqlite3 *db;
1169c8e9a2dfSdanielk1977   int val;
1170c8e9a2dfSdanielk1977 
1171c8e9a2dfSdanielk1977   if( objc!=5 ) goto bad_args;
1172c8e9a2dfSdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1173c8e9a2dfSdanielk1977 
1174c8e9a2dfSdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR;
1175c8e9a2dfSdanielk1977   if( val ){
1176c8e9a2dfSdanielk1977     sqlite3_create_function(db, "test_function", 1, SQLITE_UTF8,
1177c8e9a2dfSdanielk1977         interp, test_function_utf8, 0, 0);
1178c8e9a2dfSdanielk1977   }
1179c8e9a2dfSdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &val) ) return TCL_ERROR;
1180c8e9a2dfSdanielk1977   if( val ){
1181c8e9a2dfSdanielk1977     sqlite3_create_function(db, "test_function", 1, SQLITE_UTF16LE,
1182c8e9a2dfSdanielk1977         interp, test_function_utf16le, 0, 0);
1183c8e9a2dfSdanielk1977   }
1184c8e9a2dfSdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[4], &val) ) return TCL_ERROR;
1185c8e9a2dfSdanielk1977   if( val ){
1186c8e9a2dfSdanielk1977     sqlite3_create_function(db, "test_function", 1, SQLITE_UTF16BE,
1187c8e9a2dfSdanielk1977         interp, test_function_utf16be, 0, 0);
1188c8e9a2dfSdanielk1977   }
1189c8e9a2dfSdanielk1977 
1190c8e9a2dfSdanielk1977   return TCL_OK;
1191c8e9a2dfSdanielk1977 bad_args:
1192c8e9a2dfSdanielk1977   Tcl_AppendResult(interp, "wrong # args: should be \"",
1193c8e9a2dfSdanielk1977       Tcl_GetStringFromObj(objv[0], 0), " <DB> <utf8> <utf16le> <utf16be>", 0);
1194c8e9a2dfSdanielk1977   return TCL_ERROR;
1195c8e9a2dfSdanielk1977 }
1196c8e9a2dfSdanielk1977 
1197312d6b36Sdanielk1977 /*
1198312d6b36Sdanielk1977 ** Usage:         test_errstr <err code>
1199312d6b36Sdanielk1977 **
1200312d6b36Sdanielk1977 ** Test that the english language string equivalents for sqlite error codes
1201312d6b36Sdanielk1977 ** are sane. The parameter is an integer representing an sqlite error code.
1202312d6b36Sdanielk1977 ** The result is a list of two elements, the string representation of the
1203312d6b36Sdanielk1977 ** error code and the english language explanation.
1204312d6b36Sdanielk1977 */
1205312d6b36Sdanielk1977 static int test_errstr(
1206312d6b36Sdanielk1977   void * clientData,
1207312d6b36Sdanielk1977   Tcl_Interp *interp,
1208312d6b36Sdanielk1977   int objc,
1209312d6b36Sdanielk1977   Tcl_Obj *CONST objv[]
1210312d6b36Sdanielk1977 ){
1211312d6b36Sdanielk1977   char *zCode;
1212312d6b36Sdanielk1977   int i;
1213312d6b36Sdanielk1977   if( objc!=1 ){
1214312d6b36Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "<error code>");
1215312d6b36Sdanielk1977   }
1216312d6b36Sdanielk1977 
1217312d6b36Sdanielk1977   zCode = Tcl_GetString(objv[1]);
1218312d6b36Sdanielk1977   for(i=0; i<200; i++){
1219312d6b36Sdanielk1977     if( 0==strcmp(errorName(i), zCode) ) break;
1220312d6b36Sdanielk1977   }
1221312d6b36Sdanielk1977   Tcl_SetResult(interp, (char *)sqlite3ErrStr(i), 0);
1222312d6b36Sdanielk1977   return TCL_OK;
1223312d6b36Sdanielk1977 }
1224312d6b36Sdanielk1977 
1225c8e9a2dfSdanielk1977 static int sqlite3_crashparams(
12268a6c550dSdanielk1977   void * clientData,
12278a6c550dSdanielk1977   Tcl_Interp *interp,
12288a6c550dSdanielk1977   int objc,
12298a6c550dSdanielk1977   Tcl_Obj *CONST objv[]
12308a6c550dSdanielk1977 ){
12318a6c550dSdanielk1977 #ifdef OS_TEST
1232c8e9a2dfSdanielk1977   int delay;
1233c8e9a2dfSdanielk1977   if( objc!=3 ) goto bad_args;
1234c8e9a2dfSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[1], &delay) ) return TCL_ERROR;
1235c8e9a2dfSdanielk1977   sqlite3SetCrashParams(delay, Tcl_GetString(objv[2]));
12368a6c550dSdanielk1977 #endif
12378a6c550dSdanielk1977   return TCL_OK;
12388a6c550dSdanielk1977 
1239241db313Sdrh #ifdef OS_TEST
12408a6c550dSdanielk1977 bad_args:
12418a6c550dSdanielk1977   Tcl_AppendResult(interp, "wrong # args: should be \"",
1242c8e9a2dfSdanielk1977       Tcl_GetStringFromObj(objv[0], 0), "<delay> <filename>", 0);
12438a6c550dSdanielk1977   return TCL_ERROR;
1244241db313Sdrh #endif
12458a6c550dSdanielk1977 }
12468a6c550dSdanielk1977 
12478a6c550dSdanielk1977 
124850457896Sdrh /*
124999ee3600Sdrh ** Usage:    breakpoint
125099ee3600Sdrh **
125199ee3600Sdrh ** This routine exists for one purpose - to provide a place to put a
125299ee3600Sdrh ** breakpoint with GDB that can be triggered using TCL code.  The use
125399ee3600Sdrh ** for this is when a particular test fails on (say) the 1485th iteration.
125499ee3600Sdrh ** In the TCL test script, we can add code like this:
125599ee3600Sdrh **
125699ee3600Sdrh **     if {$i==1485} breakpoint
125799ee3600Sdrh **
125899ee3600Sdrh ** Then run testfixture in the debugger and wait for the breakpoint to
125999ee3600Sdrh ** fire.  Then additional breakpoints can be set to trace down the bug.
126099ee3600Sdrh */
126199ee3600Sdrh static int test_breakpoint(
126299ee3600Sdrh   void *NotUsed,
126399ee3600Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
126499ee3600Sdrh   int argc,              /* Number of arguments */
126599ee3600Sdrh   char **argv            /* Text of each argument */
126699ee3600Sdrh ){
126799ee3600Sdrh   return TCL_OK;         /* Do nothing */
126899ee3600Sdrh }
126999ee3600Sdrh 
1270241db313Sdrh /*
1271241db313Sdrh ** Usage:   sqlite3_bind_int  STMT N VALUE
1272241db313Sdrh **
1273241db313Sdrh ** Test the sqlite3_bind_int interface.  STMT is a prepared statement.
1274241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
1275241db313Sdrh ** binds a 32-bit integer VALUE to that wildcard.
1276241db313Sdrh */
1277241db313Sdrh static int test_bind_int(
127851e3d8e2Sdanielk1977   void * clientData,
127951e3d8e2Sdanielk1977   Tcl_Interp *interp,
128051e3d8e2Sdanielk1977   int objc,
128151e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
128251e3d8e2Sdanielk1977 ){
128351e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
128451e3d8e2Sdanielk1977   int idx;
128551e3d8e2Sdanielk1977   int value;
128651e3d8e2Sdanielk1977   int rc;
128751e3d8e2Sdanielk1977 
128851e3d8e2Sdanielk1977   if( objc!=4 ){
128951e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1290241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0);
129151e3d8e2Sdanielk1977     return TCL_ERROR;
129251e3d8e2Sdanielk1977   }
129351e3d8e2Sdanielk1977 
129451e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
129551e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
129651e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &value) ) return TCL_ERROR;
129751e3d8e2Sdanielk1977 
1298c572ef7fSdanielk1977   rc = sqlite3_bind_int(pStmt, idx, value);
129951e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
130051e3d8e2Sdanielk1977     return TCL_ERROR;
130151e3d8e2Sdanielk1977   }
130251e3d8e2Sdanielk1977 
130351e3d8e2Sdanielk1977   return TCL_OK;
130451e3d8e2Sdanielk1977 }
130551e3d8e2Sdanielk1977 
1306241db313Sdrh 
1307241db313Sdrh /*
1308241db313Sdrh ** Usage:   sqlite3_bind_int64  STMT N VALUE
1309241db313Sdrh **
1310241db313Sdrh ** Test the sqlite3_bind_int64 interface.  STMT is a prepared statement.
1311241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
1312241db313Sdrh ** binds a 64-bit integer VALUE to that wildcard.
1313241db313Sdrh */
131451e3d8e2Sdanielk1977 static int test_bind_int64(
131551e3d8e2Sdanielk1977   void * clientData,
131651e3d8e2Sdanielk1977   Tcl_Interp *interp,
131751e3d8e2Sdanielk1977   int objc,
131851e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
131951e3d8e2Sdanielk1977 ){
132051e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
132151e3d8e2Sdanielk1977   int idx;
132251e3d8e2Sdanielk1977   i64 value;
132351e3d8e2Sdanielk1977   int rc;
132451e3d8e2Sdanielk1977 
132551e3d8e2Sdanielk1977   if( objc!=4 ){
132651e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1327241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0);
132851e3d8e2Sdanielk1977     return TCL_ERROR;
132951e3d8e2Sdanielk1977   }
133051e3d8e2Sdanielk1977 
133151e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
133251e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
133351e3d8e2Sdanielk1977   if( Tcl_GetWideIntFromObj(interp, objv[3], &value) ) return TCL_ERROR;
133451e3d8e2Sdanielk1977 
133551e3d8e2Sdanielk1977   rc = sqlite3_bind_int64(pStmt, idx, value);
133651e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
133751e3d8e2Sdanielk1977     return TCL_ERROR;
133851e3d8e2Sdanielk1977   }
133951e3d8e2Sdanielk1977 
134051e3d8e2Sdanielk1977   return TCL_OK;
134151e3d8e2Sdanielk1977 }
134251e3d8e2Sdanielk1977 
1343241db313Sdrh 
1344241db313Sdrh /*
1345241db313Sdrh ** Usage:   sqlite3_bind_double  STMT N VALUE
1346241db313Sdrh **
1347241db313Sdrh ** Test the sqlite3_bind_double interface.  STMT is a prepared statement.
1348241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
1349241db313Sdrh ** binds a 64-bit integer VALUE to that wildcard.
1350241db313Sdrh */
135151e3d8e2Sdanielk1977 static int test_bind_double(
135251e3d8e2Sdanielk1977   void * clientData,
135351e3d8e2Sdanielk1977   Tcl_Interp *interp,
135451e3d8e2Sdanielk1977   int objc,
135551e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
135651e3d8e2Sdanielk1977 ){
135751e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
135851e3d8e2Sdanielk1977   int idx;
135951e3d8e2Sdanielk1977   double value;
136051e3d8e2Sdanielk1977   int rc;
136151e3d8e2Sdanielk1977 
136251e3d8e2Sdanielk1977   if( objc!=4 ){
136351e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1364241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0);
136551e3d8e2Sdanielk1977     return TCL_ERROR;
136651e3d8e2Sdanielk1977   }
136751e3d8e2Sdanielk1977 
136851e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
136951e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
137051e3d8e2Sdanielk1977   if( Tcl_GetDoubleFromObj(interp, objv[3], &value) ) return TCL_ERROR;
137151e3d8e2Sdanielk1977 
137251e3d8e2Sdanielk1977   rc = sqlite3_bind_double(pStmt, idx, value);
137351e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
137451e3d8e2Sdanielk1977     return TCL_ERROR;
137551e3d8e2Sdanielk1977   }
137651e3d8e2Sdanielk1977 
137751e3d8e2Sdanielk1977   return TCL_OK;
137851e3d8e2Sdanielk1977 }
137951e3d8e2Sdanielk1977 
1380241db313Sdrh /*
1381241db313Sdrh ** Usage:   sqlite3_bind_null  STMT N
1382241db313Sdrh **
1383241db313Sdrh ** Test the sqlite3_bind_null interface.  STMT is a prepared statement.
1384241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
1385241db313Sdrh ** binds a NULL to the wildcard.
1386241db313Sdrh */
138751e3d8e2Sdanielk1977 static int test_bind_null(
138851e3d8e2Sdanielk1977   void * clientData,
138951e3d8e2Sdanielk1977   Tcl_Interp *interp,
139051e3d8e2Sdanielk1977   int objc,
139151e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
139251e3d8e2Sdanielk1977 ){
139351e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
139451e3d8e2Sdanielk1977   int idx;
139551e3d8e2Sdanielk1977   int rc;
139651e3d8e2Sdanielk1977 
139751e3d8e2Sdanielk1977   if( objc!=3 ){
139851e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1399241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N", 0);
140051e3d8e2Sdanielk1977     return TCL_ERROR;
140151e3d8e2Sdanielk1977   }
140251e3d8e2Sdanielk1977 
140351e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
140451e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
140551e3d8e2Sdanielk1977 
140651e3d8e2Sdanielk1977   rc = sqlite3_bind_null(pStmt, idx);
140751e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
140851e3d8e2Sdanielk1977     return TCL_ERROR;
140951e3d8e2Sdanielk1977   }
141051e3d8e2Sdanielk1977 
141151e3d8e2Sdanielk1977   return TCL_OK;
141251e3d8e2Sdanielk1977 }
141351e3d8e2Sdanielk1977 
1414241db313Sdrh /*
1415241db313Sdrh ** Usage:   sqlite3_bind_text  STMT N STRING BYTES
1416241db313Sdrh **
1417241db313Sdrh ** Test the sqlite3_bind_text interface.  STMT is a prepared statement.
1418241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
1419241db313Sdrh ** binds a UTF-8 string STRING to the wildcard.  The string is BYTES bytes
1420241db313Sdrh ** long.
1421241db313Sdrh */
142251e3d8e2Sdanielk1977 static int test_bind_text(
142351e3d8e2Sdanielk1977   void * clientData,
142451e3d8e2Sdanielk1977   Tcl_Interp *interp,
142551e3d8e2Sdanielk1977   int objc,
142651e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
142751e3d8e2Sdanielk1977 ){
142851e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
142951e3d8e2Sdanielk1977   int idx;
143051e3d8e2Sdanielk1977   int bytes;
143151e3d8e2Sdanielk1977   char *value;
143251e3d8e2Sdanielk1977   int rc;
143351e3d8e2Sdanielk1977 
143451e3d8e2Sdanielk1977   if( objc!=5 ){
143551e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1436241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE BYTES", 0);
143751e3d8e2Sdanielk1977     return TCL_ERROR;
143851e3d8e2Sdanielk1977   }
143951e3d8e2Sdanielk1977 
144051e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
144151e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
144251e3d8e2Sdanielk1977   value = Tcl_GetString(objv[3]);
144351e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
144451e3d8e2Sdanielk1977 
1445d8123366Sdanielk1977   rc = sqlite3_bind_text(pStmt, idx, value, bytes, SQLITE_TRANSIENT);
144651e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
144751e3d8e2Sdanielk1977     return TCL_ERROR;
144851e3d8e2Sdanielk1977   }
144951e3d8e2Sdanielk1977 
145051e3d8e2Sdanielk1977   return TCL_OK;
145151e3d8e2Sdanielk1977 }
145251e3d8e2Sdanielk1977 
1453241db313Sdrh /*
1454241db313Sdrh ** Usage:   sqlite3_bind_text16  STMT N STRING BYTES
1455241db313Sdrh **
1456241db313Sdrh ** Test the sqlite3_bind_text16 interface.  STMT is a prepared statement.
1457241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
1458241db313Sdrh ** binds a UTF-16 string STRING to the wildcard.  The string is BYTES bytes
1459241db313Sdrh ** long.
1460241db313Sdrh */
146151e3d8e2Sdanielk1977 static int test_bind_text16(
146251e3d8e2Sdanielk1977   void * clientData,
146351e3d8e2Sdanielk1977   Tcl_Interp *interp,
146451e3d8e2Sdanielk1977   int objc,
146551e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
146651e3d8e2Sdanielk1977 ){
146751e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
146851e3d8e2Sdanielk1977   int idx;
146951e3d8e2Sdanielk1977   int bytes;
147051e3d8e2Sdanielk1977   char *value;
147151e3d8e2Sdanielk1977   int rc;
147251e3d8e2Sdanielk1977 
147351e3d8e2Sdanielk1977   if( objc!=5 ){
147451e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1475241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE BYTES", 0);
147651e3d8e2Sdanielk1977     return TCL_ERROR;
147751e3d8e2Sdanielk1977   }
147851e3d8e2Sdanielk1977 
147951e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
148051e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
148151e3d8e2Sdanielk1977   value = Tcl_GetByteArrayFromObj(objv[3], 0);
148251e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
148351e3d8e2Sdanielk1977 
1484d8123366Sdanielk1977   rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, SQLITE_TRANSIENT);
148551e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
148651e3d8e2Sdanielk1977     return TCL_ERROR;
148751e3d8e2Sdanielk1977   }
148851e3d8e2Sdanielk1977 
148951e3d8e2Sdanielk1977   return TCL_OK;
149051e3d8e2Sdanielk1977 }
149151e3d8e2Sdanielk1977 
1492241db313Sdrh /*
1493241db313Sdrh ** Usage:   sqlite3_bind_blob  STMT N DATA BYTES
1494241db313Sdrh **
1495241db313Sdrh ** Test the sqlite3_bind_blob interface.  STMT is a prepared statement.
1496241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
1497241db313Sdrh ** binds a BLOB to the wildcard.  The BLOB is BYTES bytes in size.
1498241db313Sdrh */
149951e3d8e2Sdanielk1977 static int test_bind_blob(
150051e3d8e2Sdanielk1977   void * clientData,
150151e3d8e2Sdanielk1977   Tcl_Interp *interp,
150251e3d8e2Sdanielk1977   int objc,
150351e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
150451e3d8e2Sdanielk1977 ){
150551e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
150651e3d8e2Sdanielk1977   int idx;
150751e3d8e2Sdanielk1977   int bytes;
150851e3d8e2Sdanielk1977   char *value;
150951e3d8e2Sdanielk1977   int rc;
151051e3d8e2Sdanielk1977 
151151e3d8e2Sdanielk1977   if( objc!=5 ){
151251e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1513241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N DATA BYTES", 0);
151451e3d8e2Sdanielk1977     return TCL_ERROR;
151551e3d8e2Sdanielk1977   }
151651e3d8e2Sdanielk1977 
151751e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
151851e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
151951e3d8e2Sdanielk1977   value = Tcl_GetString(objv[3]);
152049e4643eSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
152151e3d8e2Sdanielk1977 
1522d8123366Sdanielk1977   rc = sqlite3_bind_blob(pStmt, idx, value, bytes, SQLITE_TRANSIENT);
152351e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
152451e3d8e2Sdanielk1977     return TCL_ERROR;
152551e3d8e2Sdanielk1977   }
152651e3d8e2Sdanielk1977 
152751e3d8e2Sdanielk1977   return TCL_OK;
152851e3d8e2Sdanielk1977 }
152951e3d8e2Sdanielk1977 
153099ee3600Sdrh /*
15316622cce3Sdanielk1977 ** Usage: sqlite3_errcode DB
15326622cce3Sdanielk1977 **
15336622cce3Sdanielk1977 ** Return the string representation of the most recent sqlite3_* API
15346622cce3Sdanielk1977 ** error code. e.g. "SQLITE_ERROR".
15356622cce3Sdanielk1977 */
15366622cce3Sdanielk1977 static int test_errcode(
15376622cce3Sdanielk1977   void * clientData,
15386622cce3Sdanielk1977   Tcl_Interp *interp,
15396622cce3Sdanielk1977   int objc,
15406622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
15416622cce3Sdanielk1977 ){
15426622cce3Sdanielk1977   sqlite3 *db;
15436622cce3Sdanielk1977 
15446622cce3Sdanielk1977   if( objc!=2 ){
15456622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
15466622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
15476622cce3Sdanielk1977     return TCL_ERROR;
15486622cce3Sdanielk1977   }
15496622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
15506622cce3Sdanielk1977   Tcl_SetResult(interp, (char *)errorName(sqlite3_errcode(db)), 0);
15516622cce3Sdanielk1977   return TCL_OK;
15526622cce3Sdanielk1977 }
15536622cce3Sdanielk1977 
15546622cce3Sdanielk1977 /*
15556622cce3Sdanielk1977 ** Usage:   test_errmsg DB
15566622cce3Sdanielk1977 **
15576622cce3Sdanielk1977 ** Returns the UTF-8 representation of the error message string for the
15586622cce3Sdanielk1977 ** most recent sqlite3_* API call.
15596622cce3Sdanielk1977 */
15606622cce3Sdanielk1977 static int test_errmsg(
15616622cce3Sdanielk1977   void * clientData,
15626622cce3Sdanielk1977   Tcl_Interp *interp,
15636622cce3Sdanielk1977   int objc,
15646622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
15656622cce3Sdanielk1977 ){
15666622cce3Sdanielk1977   sqlite *db;
15676622cce3Sdanielk1977   const char *zErr;
15686622cce3Sdanielk1977 
15696622cce3Sdanielk1977   if( objc!=2 ){
15706622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
15716622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
15726622cce3Sdanielk1977     return TCL_ERROR;
15736622cce3Sdanielk1977   }
15746622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
15756622cce3Sdanielk1977 
15766622cce3Sdanielk1977   zErr = sqlite3_errmsg(db);
15776622cce3Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
15786622cce3Sdanielk1977   return TCL_OK;
15796622cce3Sdanielk1977 }
15806622cce3Sdanielk1977 
15816622cce3Sdanielk1977 /*
15826622cce3Sdanielk1977 ** Usage:   test_errmsg16 DB
15836622cce3Sdanielk1977 **
15846622cce3Sdanielk1977 ** Returns the UTF-16 representation of the error message string for the
15856622cce3Sdanielk1977 ** most recent sqlite3_* API call. This is a byte array object at the TCL
15866622cce3Sdanielk1977 ** level, and it includes the 0x00 0x00 terminator bytes at the end of the
15876622cce3Sdanielk1977 ** UTF-16 string.
15886622cce3Sdanielk1977 */
15896622cce3Sdanielk1977 static int test_errmsg16(
15906622cce3Sdanielk1977   void * clientData,
15916622cce3Sdanielk1977   Tcl_Interp *interp,
15926622cce3Sdanielk1977   int objc,
15936622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
15946622cce3Sdanielk1977 ){
15956622cce3Sdanielk1977   sqlite *db;
15966622cce3Sdanielk1977   const void *zErr;
15976622cce3Sdanielk1977   int bytes;
15986622cce3Sdanielk1977 
15996622cce3Sdanielk1977   if( objc!=2 ){
16006622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
16016622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
16026622cce3Sdanielk1977     return TCL_ERROR;
16036622cce3Sdanielk1977   }
16046622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
16056622cce3Sdanielk1977 
16066622cce3Sdanielk1977   zErr = sqlite3_errmsg16(db);
16076622cce3Sdanielk1977   bytes = sqlite3utf16ByteLen(zErr, -1);
16086622cce3Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes));
16096622cce3Sdanielk1977   return TCL_OK;
16106622cce3Sdanielk1977 }
16116622cce3Sdanielk1977 
16126622cce3Sdanielk1977 /*
16136622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar
16146622cce3Sdanielk1977 **
16156622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
16166622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global
16176622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A
16186622cce3Sdanielk1977 ** STMT handle is returned.
16196622cce3Sdanielk1977 */
16206622cce3Sdanielk1977 static int test_prepare(
16216622cce3Sdanielk1977   void * clientData,
16226622cce3Sdanielk1977   Tcl_Interp *interp,
16236622cce3Sdanielk1977   int objc,
16246622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
16256622cce3Sdanielk1977 ){
16266622cce3Sdanielk1977   sqlite3 *db;
16276622cce3Sdanielk1977   const char *zSql;
16286622cce3Sdanielk1977   int bytes;
16296622cce3Sdanielk1977   const char *zTail = 0;
16306622cce3Sdanielk1977   sqlite3_stmt *pStmt = 0;
16316622cce3Sdanielk1977   char zBuf[50];
16324ad1713cSdanielk1977   int rc;
16336622cce3Sdanielk1977 
16346622cce3Sdanielk1977   if( objc!=5 ){
16356622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
16366622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
16376622cce3Sdanielk1977     return TCL_ERROR;
16386622cce3Sdanielk1977   }
16396622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
16406622cce3Sdanielk1977   zSql = Tcl_GetString(objv[2]);
16416622cce3Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
16426622cce3Sdanielk1977 
16434ad1713cSdanielk1977   rc = sqlite3_prepare(db, zSql, bytes, &pStmt, &zTail);
16446622cce3Sdanielk1977   if( zTail ){
16456622cce3Sdanielk1977     if( bytes>=0 ){
16466622cce3Sdanielk1977       bytes = bytes - (zTail-zSql);
16476622cce3Sdanielk1977     }
16486622cce3Sdanielk1977     Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
16496622cce3Sdanielk1977   }
16504ad1713cSdanielk1977   if( rc!=SQLITE_OK ){
16514ad1713cSdanielk1977     assert( pStmt==0 );
16524ad1713cSdanielk1977     sprintf(zBuf, "(%d) ", rc);
16534ad1713cSdanielk1977     Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
16544ad1713cSdanielk1977     return TCL_ERROR;
16554ad1713cSdanielk1977   }
16566622cce3Sdanielk1977 
16574ad1713cSdanielk1977   if( pStmt ){
16586622cce3Sdanielk1977     if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
16596622cce3Sdanielk1977     Tcl_AppendResult(interp, zBuf, 0);
16604ad1713cSdanielk1977   }
16616622cce3Sdanielk1977   return TCL_OK;
16626622cce3Sdanielk1977 }
16636622cce3Sdanielk1977 
16646622cce3Sdanielk1977 /*
16656622cce3Sdanielk1977 ** Usage: sqlite3_prepare DB sql bytes tailvar
16666622cce3Sdanielk1977 **
16676622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
16686622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global
16696622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A
16706622cce3Sdanielk1977 ** STMT handle is returned.
16716622cce3Sdanielk1977 */
16726622cce3Sdanielk1977 static int test_prepare16(
16736622cce3Sdanielk1977   void * clientData,
16746622cce3Sdanielk1977   Tcl_Interp *interp,
16756622cce3Sdanielk1977   int objc,
16766622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
16776622cce3Sdanielk1977 ){
16786622cce3Sdanielk1977   sqlite3 *db;
16796622cce3Sdanielk1977   const void *zSql;
16806622cce3Sdanielk1977   const void *zTail = 0;
16816622cce3Sdanielk1977   Tcl_Obj *pTail = 0;
16826622cce3Sdanielk1977   sqlite3_stmt *pStmt = 0;
16836622cce3Sdanielk1977   char zBuf[50];
16846622cce3Sdanielk1977   int bytes;                /* The integer specified as arg 3 */
16856622cce3Sdanielk1977   int objlen;               /* The byte-array length of arg 2 */
16866622cce3Sdanielk1977 
16876622cce3Sdanielk1977   if( objc!=5 ){
16886622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
16896622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
16906622cce3Sdanielk1977     return TCL_ERROR;
16916622cce3Sdanielk1977   }
16926622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
16936622cce3Sdanielk1977   zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen);
16946622cce3Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
16956622cce3Sdanielk1977 
16966622cce3Sdanielk1977   if( SQLITE_OK!=sqlite3_prepare16(db, zSql, bytes, &pStmt, &zTail) ){
16976622cce3Sdanielk1977     return TCL_ERROR;
16986622cce3Sdanielk1977   }
16996622cce3Sdanielk1977 
17006622cce3Sdanielk1977   if( zTail ){
17016622cce3Sdanielk1977     objlen = objlen - ((u8 *)zTail-(u8 *)zSql);
17026622cce3Sdanielk1977   }else{
17036622cce3Sdanielk1977     objlen = 0;
17046622cce3Sdanielk1977   }
17056622cce3Sdanielk1977   pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen);
17066622cce3Sdanielk1977   Tcl_IncrRefCount(pTail);
17076622cce3Sdanielk1977   Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0);
17084ad1713cSdanielk1977   Tcl_DecrRefCount(pTail);
17096622cce3Sdanielk1977 
17104ad1713cSdanielk1977   if( pStmt ){
17116622cce3Sdanielk1977     if( makePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
17124ad1713cSdanielk1977   }
17136622cce3Sdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
17146622cce3Sdanielk1977   return TCL_OK;
17156622cce3Sdanielk1977 }
17166622cce3Sdanielk1977 
17174ad1713cSdanielk1977 /*
17184ad1713cSdanielk1977 ** Usage: sqlite3_open filename ?options-list?
17194ad1713cSdanielk1977 */
17204ad1713cSdanielk1977 static int test_open(
17214ad1713cSdanielk1977   void * clientData,
17224ad1713cSdanielk1977   Tcl_Interp *interp,
17234ad1713cSdanielk1977   int objc,
17244ad1713cSdanielk1977   Tcl_Obj *CONST objv[]
17254ad1713cSdanielk1977 ){
17264ad1713cSdanielk1977   const char *zFilename;
17274ad1713cSdanielk1977   sqlite3 *db;
17284ad1713cSdanielk1977   int rc;
17294ad1713cSdanielk1977   char zBuf[100];
17304ad1713cSdanielk1977 
17314ad1713cSdanielk1977   if( objc!=3 && objc!=2 ){
17324ad1713cSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
17334ad1713cSdanielk1977        Tcl_GetString(objv[0]), " filename options-list", 0);
17344ad1713cSdanielk1977     return TCL_ERROR;
17354ad1713cSdanielk1977   }
17364ad1713cSdanielk1977 
17374ad1713cSdanielk1977   zFilename = Tcl_GetString(objv[1]);
17384f057f90Sdanielk1977   rc = sqlite3_open(zFilename, &db);
17394ad1713cSdanielk1977 
17404ad1713cSdanielk1977   if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
17414ad1713cSdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
17424ad1713cSdanielk1977   return TCL_OK;
17434ad1713cSdanielk1977 }
17444ad1713cSdanielk1977 
17454ad1713cSdanielk1977 /*
17464ad1713cSdanielk1977 ** Usage: sqlite3_open16 filename options
17474ad1713cSdanielk1977 */
17484ad1713cSdanielk1977 static int test_open16(
17494ad1713cSdanielk1977   void * clientData,
17504ad1713cSdanielk1977   Tcl_Interp *interp,
17514ad1713cSdanielk1977   int objc,
17524ad1713cSdanielk1977   Tcl_Obj *CONST objv[]
17534ad1713cSdanielk1977 ){
17544ad1713cSdanielk1977   const void *zFilename;
17554ad1713cSdanielk1977   sqlite3 *db;
17564ad1713cSdanielk1977   int rc;
17574ad1713cSdanielk1977   char zBuf[100];
17584ad1713cSdanielk1977 
17594ad1713cSdanielk1977   if( objc!=3 ){
17604ad1713cSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
17614ad1713cSdanielk1977        Tcl_GetString(objv[0]), " filename options-list", 0);
17624ad1713cSdanielk1977     return TCL_ERROR;
17634ad1713cSdanielk1977   }
17644ad1713cSdanielk1977 
17654ad1713cSdanielk1977   zFilename = Tcl_GetByteArrayFromObj(objv[1], 0);
17664f057f90Sdanielk1977   rc = sqlite3_open16(zFilename, &db);
17674ad1713cSdanielk1977 
17684ad1713cSdanielk1977   if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
17694ad1713cSdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
17704ad1713cSdanielk1977   return TCL_OK;
17714ad1713cSdanielk1977 }
1772d3d39e93Sdrh 
1773d3d39e93Sdrh /*
1774106bb236Sdanielk1977 ** Usage: sqlite3_step STMT
1775106bb236Sdanielk1977 **
1776106bb236Sdanielk1977 ** Advance the statement to the next row.
1777106bb236Sdanielk1977 */
177817240fd9Sdanielk1977 static int test_step(
1779106bb236Sdanielk1977   void * clientData,
1780106bb236Sdanielk1977   Tcl_Interp *interp,
1781106bb236Sdanielk1977   int objc,
1782106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
1783106bb236Sdanielk1977 ){
1784106bb236Sdanielk1977   sqlite3_stmt *pStmt;
1785106bb236Sdanielk1977   int rc;
1786106bb236Sdanielk1977 
1787e1cd9874Sdanielk1977   if( objc!=2 ){
1788106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1789106bb236Sdanielk1977        Tcl_GetString(objv[0]), " STMT", 0);
1790106bb236Sdanielk1977     return TCL_ERROR;
1791106bb236Sdanielk1977   }
1792106bb236Sdanielk1977 
1793106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
179417240fd9Sdanielk1977   rc = sqlite3_step(pStmt);
1795106bb236Sdanielk1977 
1796fbcd585fSdanielk1977   /* if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR; */
17976590493dSdanielk1977   Tcl_SetResult(interp, (char *)errorName(rc), 0);
1798e1cd9874Sdanielk1977   return TCL_OK;
1799e1cd9874Sdanielk1977 }
1800e1cd9874Sdanielk1977 
1801e1cd9874Sdanielk1977 /*
180217240fd9Sdanielk1977 ** Usage: sqlite3_column_count STMT
180317240fd9Sdanielk1977 **
180417240fd9Sdanielk1977 ** Return the number of columns returned by the sql statement STMT.
180517240fd9Sdanielk1977 */
180617240fd9Sdanielk1977 static int test_column_count(
180717240fd9Sdanielk1977   void * clientData,
180817240fd9Sdanielk1977   Tcl_Interp *interp,
180917240fd9Sdanielk1977   int objc,
181017240fd9Sdanielk1977   Tcl_Obj *CONST objv[]
181117240fd9Sdanielk1977 ){
181217240fd9Sdanielk1977   sqlite3_stmt *pStmt;
181317240fd9Sdanielk1977 
181417240fd9Sdanielk1977   if( objc!=2 ){
181517240fd9Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
181617240fd9Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
181717240fd9Sdanielk1977     return TCL_ERROR;
181817240fd9Sdanielk1977   }
181917240fd9Sdanielk1977 
182017240fd9Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
182117240fd9Sdanielk1977 
182217240fd9Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_column_count(pStmt)));
182317240fd9Sdanielk1977   return TCL_OK;
182417240fd9Sdanielk1977 }
182517240fd9Sdanielk1977 
182617240fd9Sdanielk1977 /*
18273cf86063Sdanielk1977 ** Usage: sqlite3_column_type STMT column
18283cf86063Sdanielk1977 **
18293cf86063Sdanielk1977 ** Return the type of the data in column 'column' of the current row.
18303cf86063Sdanielk1977 */
18313cf86063Sdanielk1977 static int test_column_type(
18323cf86063Sdanielk1977   void * clientData,
18333cf86063Sdanielk1977   Tcl_Interp *interp,
18343cf86063Sdanielk1977   int objc,
18353cf86063Sdanielk1977   Tcl_Obj *CONST objv[]
18363cf86063Sdanielk1977 ){
18373cf86063Sdanielk1977   sqlite3_stmt *pStmt;
18383cf86063Sdanielk1977   int col;
18393cf86063Sdanielk1977   int tp;
18403cf86063Sdanielk1977 
18413cf86063Sdanielk1977   if( objc!=3 ){
18423cf86063Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
18433cf86063Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
18443cf86063Sdanielk1977     return TCL_ERROR;
18453cf86063Sdanielk1977   }
18463cf86063Sdanielk1977 
18473cf86063Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
18483cf86063Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
18493cf86063Sdanielk1977 
18503cf86063Sdanielk1977   tp = sqlite3_column_type(pStmt, col);
18513cf86063Sdanielk1977   switch( tp ){
18529c054830Sdrh     case SQLITE_INTEGER:
18533cf86063Sdanielk1977       Tcl_SetResult(interp, "INTEGER", TCL_STATIC);
18543cf86063Sdanielk1977       break;
18559c054830Sdrh     case SQLITE_NULL:
18563cf86063Sdanielk1977       Tcl_SetResult(interp, "NULL", TCL_STATIC);
18573cf86063Sdanielk1977       break;
18589c054830Sdrh     case SQLITE_FLOAT:
18593cf86063Sdanielk1977       Tcl_SetResult(interp, "FLOAT", TCL_STATIC);
18603cf86063Sdanielk1977       break;
18619c054830Sdrh     case SQLITE_TEXT:
18623cf86063Sdanielk1977       Tcl_SetResult(interp, "TEXT", TCL_STATIC);
18633cf86063Sdanielk1977       break;
18649c054830Sdrh     case SQLITE_BLOB:
18653cf86063Sdanielk1977       Tcl_SetResult(interp, "BLOB", TCL_STATIC);
18663cf86063Sdanielk1977       break;
18673cf86063Sdanielk1977     default:
18683cf86063Sdanielk1977       assert(0);
18693cf86063Sdanielk1977   }
18703cf86063Sdanielk1977 
18713cf86063Sdanielk1977   return TCL_OK;
18723cf86063Sdanielk1977 }
18733cf86063Sdanielk1977 
18743cf86063Sdanielk1977 /*
187504f2e68dSdanielk1977 ** Usage: sqlite3_column_int64 STMT column
18763cf86063Sdanielk1977 **
18773cf86063Sdanielk1977 ** Return the data in column 'column' of the current row cast as an
187804f2e68dSdanielk1977 ** wide (64-bit) integer.
18793cf86063Sdanielk1977 */
188004f2e68dSdanielk1977 static int test_column_int64(
18813cf86063Sdanielk1977   void * clientData,
18823cf86063Sdanielk1977   Tcl_Interp *interp,
18833cf86063Sdanielk1977   int objc,
18843cf86063Sdanielk1977   Tcl_Obj *CONST objv[]
18853cf86063Sdanielk1977 ){
18863cf86063Sdanielk1977   sqlite3_stmt *pStmt;
18873cf86063Sdanielk1977   int col;
188804f2e68dSdanielk1977   i64 iVal;
18893cf86063Sdanielk1977 
18903cf86063Sdanielk1977   if( objc!=3 ){
18913cf86063Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
18923cf86063Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
18933cf86063Sdanielk1977     return TCL_ERROR;
18943cf86063Sdanielk1977   }
18953cf86063Sdanielk1977 
18963cf86063Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
18973cf86063Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
18983cf86063Sdanielk1977 
189904f2e68dSdanielk1977   iVal = sqlite3_column_int64(pStmt, col);
190004f2e68dSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(iVal));
190104f2e68dSdanielk1977   return TCL_OK;
190204f2e68dSdanielk1977 }
190304f2e68dSdanielk1977 
190404f2e68dSdanielk1977 /*
1905ea61b2c4Sdanielk1977 ** Usage: sqlite3_column_blob STMT column
1906ea61b2c4Sdanielk1977 */
1907ea61b2c4Sdanielk1977 static int test_column_blob(
1908ea61b2c4Sdanielk1977   void * clientData,
1909ea61b2c4Sdanielk1977   Tcl_Interp *interp,
1910ea61b2c4Sdanielk1977   int objc,
1911ea61b2c4Sdanielk1977   Tcl_Obj *CONST objv[]
1912ea61b2c4Sdanielk1977 ){
1913ea61b2c4Sdanielk1977   sqlite3_stmt *pStmt;
1914ea61b2c4Sdanielk1977   int col;
1915ea61b2c4Sdanielk1977 
1916ea61b2c4Sdanielk1977   int len;
1917c572ef7fSdanielk1977   const void *pBlob;
1918ea61b2c4Sdanielk1977 
1919ea61b2c4Sdanielk1977   if( objc!=3 ){
1920ea61b2c4Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
1921ea61b2c4Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
1922ea61b2c4Sdanielk1977     return TCL_ERROR;
1923ea61b2c4Sdanielk1977   }
1924ea61b2c4Sdanielk1977 
1925ea61b2c4Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
1926ea61b2c4Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
1927ea61b2c4Sdanielk1977 
1928ea61b2c4Sdanielk1977   pBlob = sqlite3_column_blob(pStmt, col);
1929ea61b2c4Sdanielk1977   len = sqlite3_column_bytes(pStmt, col);
1930ea61b2c4Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pBlob, len));
1931ea61b2c4Sdanielk1977   return TCL_OK;
1932ea61b2c4Sdanielk1977 }
1933ea61b2c4Sdanielk1977 
1934ea61b2c4Sdanielk1977 /*
193504f2e68dSdanielk1977 ** Usage: sqlite3_column_double STMT column
193604f2e68dSdanielk1977 **
193704f2e68dSdanielk1977 ** Return the data in column 'column' of the current row cast as a double.
193804f2e68dSdanielk1977 */
193904f2e68dSdanielk1977 static int test_column_double(
194004f2e68dSdanielk1977   void * clientData,
194104f2e68dSdanielk1977   Tcl_Interp *interp,
194204f2e68dSdanielk1977   int objc,
194304f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
194404f2e68dSdanielk1977 ){
194504f2e68dSdanielk1977   sqlite3_stmt *pStmt;
194604f2e68dSdanielk1977   int col;
194704f2e68dSdanielk1977   double rVal;
194804f2e68dSdanielk1977 
194904f2e68dSdanielk1977   if( objc!=3 ){
195004f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
195104f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
195204f2e68dSdanielk1977     return TCL_ERROR;
195304f2e68dSdanielk1977   }
195404f2e68dSdanielk1977 
195504f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
195604f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
195704f2e68dSdanielk1977 
195804f2e68dSdanielk1977   rVal = sqlite3_column_double(pStmt, col);
1959c572ef7fSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewDoubleObj(rVal));
19603cf86063Sdanielk1977   return TCL_OK;
19613cf86063Sdanielk1977 }
19623cf86063Sdanielk1977 
19633cf86063Sdanielk1977 /*
196417240fd9Sdanielk1977 ** Usage: sqlite3_data_count STMT
196517240fd9Sdanielk1977 **
196617240fd9Sdanielk1977 ** Return the number of columns returned by the sql statement STMT.
196717240fd9Sdanielk1977 */
196817240fd9Sdanielk1977 static int test_data_count(
196917240fd9Sdanielk1977   void * clientData,
197017240fd9Sdanielk1977   Tcl_Interp *interp,
197117240fd9Sdanielk1977   int objc,
197217240fd9Sdanielk1977   Tcl_Obj *CONST objv[]
197317240fd9Sdanielk1977 ){
197417240fd9Sdanielk1977   sqlite3_stmt *pStmt;
197517240fd9Sdanielk1977 
197617240fd9Sdanielk1977   if( objc!=2 ){
197717240fd9Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
197817240fd9Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
197917240fd9Sdanielk1977     return TCL_ERROR;
198017240fd9Sdanielk1977   }
198117240fd9Sdanielk1977 
198217240fd9Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
198317240fd9Sdanielk1977 
198417240fd9Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_data_count(pStmt)));
198517240fd9Sdanielk1977   return TCL_OK;
198617240fd9Sdanielk1977 }
198717240fd9Sdanielk1977 
198817240fd9Sdanielk1977 /*
198904f2e68dSdanielk1977 ** Usage: sqlite3_column_text STMT column
199004f2e68dSdanielk1977 **
199104f2e68dSdanielk1977 ** Usage: sqlite3_column_decltype STMT column
199204f2e68dSdanielk1977 **
199304f2e68dSdanielk1977 ** Usage: sqlite3_column_name STMT column
199404f2e68dSdanielk1977 */
199504f2e68dSdanielk1977 static int test_stmt_utf8(
1996241db313Sdrh   void * clientData,        /* Pointer to SQLite API function to be invoke */
199704f2e68dSdanielk1977   Tcl_Interp *interp,
199804f2e68dSdanielk1977   int objc,
199904f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
200004f2e68dSdanielk1977 ){
200104f2e68dSdanielk1977   sqlite3_stmt *pStmt;
200204f2e68dSdanielk1977   int col;
2003c572ef7fSdanielk1977   const char *(*xFunc)(sqlite3_stmt*, int) = clientData;
2004f93bbbeaSdanielk1977   const char *zRet;
200504f2e68dSdanielk1977 
200604f2e68dSdanielk1977   if( objc!=3 ){
200704f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
200804f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
200904f2e68dSdanielk1977     return TCL_ERROR;
201004f2e68dSdanielk1977   }
201104f2e68dSdanielk1977 
201204f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
201304f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
2014f93bbbeaSdanielk1977   zRet = xFunc(pStmt, col);
2015f93bbbeaSdanielk1977   if( zRet ){
2016f93bbbeaSdanielk1977     Tcl_SetResult(interp, (char *)zRet, 0);
2017f93bbbeaSdanielk1977   }
201804f2e68dSdanielk1977   return TCL_OK;
201904f2e68dSdanielk1977 }
202004f2e68dSdanielk1977 
202104f2e68dSdanielk1977 /*
202204f2e68dSdanielk1977 ** Usage: sqlite3_column_text STMT column
202304f2e68dSdanielk1977 **
202404f2e68dSdanielk1977 ** Usage: sqlite3_column_decltype STMT column
202504f2e68dSdanielk1977 **
202604f2e68dSdanielk1977 ** Usage: sqlite3_column_name STMT column
202704f2e68dSdanielk1977 */
202804f2e68dSdanielk1977 static int test_stmt_utf16(
2029241db313Sdrh   void * clientData,     /* Pointer to SQLite API function to be invoked */
203004f2e68dSdanielk1977   Tcl_Interp *interp,
203104f2e68dSdanielk1977   int objc,
203204f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
203304f2e68dSdanielk1977 ){
203404f2e68dSdanielk1977   sqlite3_stmt *pStmt;
203504f2e68dSdanielk1977   int col;
203604f2e68dSdanielk1977   Tcl_Obj *pRet;
203704f2e68dSdanielk1977   const void *zName16;
2038c572ef7fSdanielk1977   const void *(*xFunc)(sqlite3_stmt*, int) = clientData;
203904f2e68dSdanielk1977 
204004f2e68dSdanielk1977   if( objc!=3 ){
204104f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
204204f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
204304f2e68dSdanielk1977     return TCL_ERROR;
204404f2e68dSdanielk1977   }
204504f2e68dSdanielk1977 
204604f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
204704f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
204804f2e68dSdanielk1977 
204904f2e68dSdanielk1977   zName16 = xFunc(pStmt, col);
2050f93bbbeaSdanielk1977   if( zName16 ){
205104f2e68dSdanielk1977     pRet = Tcl_NewByteArrayObj(zName16, sqlite3utf16ByteLen(zName16, -1)+2);
205204f2e68dSdanielk1977     Tcl_SetObjResult(interp, pRet);
2053f93bbbeaSdanielk1977   }
205404f2e68dSdanielk1977 
205504f2e68dSdanielk1977   return TCL_OK;
205604f2e68dSdanielk1977 }
205704f2e68dSdanielk1977 
205804f2e68dSdanielk1977 /*
205904f2e68dSdanielk1977 ** Usage: sqlite3_column_int STMT column
206004f2e68dSdanielk1977 **
206104f2e68dSdanielk1977 ** Usage: sqlite3_column_bytes STMT column
206204f2e68dSdanielk1977 **
206304f2e68dSdanielk1977 ** Usage: sqlite3_column_bytes16 STMT column
206404f2e68dSdanielk1977 **
206504f2e68dSdanielk1977 */
206604f2e68dSdanielk1977 static int test_stmt_int(
2067241db313Sdrh   void * clientData,    /* Pointer to SQLite API function to be invoked */
206804f2e68dSdanielk1977   Tcl_Interp *interp,
206904f2e68dSdanielk1977   int objc,
207004f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
207104f2e68dSdanielk1977 ){
207204f2e68dSdanielk1977   sqlite3_stmt *pStmt;
207304f2e68dSdanielk1977   int col;
2074c572ef7fSdanielk1977   int (*xFunc)(sqlite3_stmt*, int) = clientData;
207504f2e68dSdanielk1977 
207604f2e68dSdanielk1977   if( objc!=3 ){
207704f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
207804f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
207904f2e68dSdanielk1977     return TCL_ERROR;
208004f2e68dSdanielk1977   }
208104f2e68dSdanielk1977 
208204f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
208304f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
208404f2e68dSdanielk1977 
208504f2e68dSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(xFunc(pStmt, col)));
208604f2e68dSdanielk1977   return TCL_OK;
208704f2e68dSdanielk1977 }
208804f2e68dSdanielk1977 
20899a1d0abeSdanielk1977 /*
20909a1d0abeSdanielk1977 ** Usage:  sqlite3OsOpenReadWrite <filename>
20919a1d0abeSdanielk1977 */
20929a1d0abeSdanielk1977 static int test_sqlite3OsOpenReadWrite(
20939a1d0abeSdanielk1977   void * clientData,
20949a1d0abeSdanielk1977   Tcl_Interp *interp,
20959a1d0abeSdanielk1977   int objc,
20969a1d0abeSdanielk1977   Tcl_Obj *CONST objv[]
20979a1d0abeSdanielk1977 ){
20989a1d0abeSdanielk1977   OsFile * pFile;
20999a1d0abeSdanielk1977   int rc;
21009a1d0abeSdanielk1977   int dummy;
21019a1d0abeSdanielk1977   char zBuf[100];
210204f2e68dSdanielk1977 
21039a1d0abeSdanielk1977   if( objc!=2 ){
21049a1d0abeSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
21059a1d0abeSdanielk1977        Tcl_GetString(objv[0]), " filename", 0);
21069a1d0abeSdanielk1977     return TCL_ERROR;
21079a1d0abeSdanielk1977   }
21089a1d0abeSdanielk1977 
21099a1d0abeSdanielk1977   pFile = sqliteMalloc(sizeof(OsFile));
21109a1d0abeSdanielk1977   rc = sqlite3OsOpenReadWrite(Tcl_GetString(objv[1]), pFile, &dummy);
21119a1d0abeSdanielk1977   if( rc!=SQLITE_OK ){
21129a1d0abeSdanielk1977     sqliteFree(pFile);
21139a1d0abeSdanielk1977     Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
21149a1d0abeSdanielk1977     return TCL_ERROR;
21159a1d0abeSdanielk1977   }
21169a1d0abeSdanielk1977   makePointerStr(interp, zBuf, pFile);
21179a1d0abeSdanielk1977   Tcl_SetResult(interp, zBuf, 0);
21189a1d0abeSdanielk1977   return TCL_ERROR;
21199a1d0abeSdanielk1977 }
21209a1d0abeSdanielk1977 
21219a1d0abeSdanielk1977 /*
21229a1d0abeSdanielk1977 ** Usage:  sqlite3OsClose <file handle>
21239a1d0abeSdanielk1977 */
21249a1d0abeSdanielk1977 static int test_sqlite3OsClose(
21259a1d0abeSdanielk1977   void * clientData,
21269a1d0abeSdanielk1977   Tcl_Interp *interp,
21279a1d0abeSdanielk1977   int objc,
21289a1d0abeSdanielk1977   Tcl_Obj *CONST objv[]
21299a1d0abeSdanielk1977 ){
21309a1d0abeSdanielk1977   OsFile * pFile;
21319a1d0abeSdanielk1977   int rc;
21329a1d0abeSdanielk1977 
21339a1d0abeSdanielk1977   if( objc!=2 ){
21349a1d0abeSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
21359a1d0abeSdanielk1977        Tcl_GetString(objv[0]), " filehandle", 0);
21369a1d0abeSdanielk1977     return TCL_ERROR;
21379a1d0abeSdanielk1977   }
21389a1d0abeSdanielk1977 
21399a1d0abeSdanielk1977   if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
21409a1d0abeSdanielk1977     return TCL_ERROR;
21419a1d0abeSdanielk1977   }
21429a1d0abeSdanielk1977   rc = sqlite3OsClose(pFile);
21439a1d0abeSdanielk1977   if( rc!=SQLITE_OK ){
21449a1d0abeSdanielk1977     Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
21459a1d0abeSdanielk1977     return TCL_ERROR;
21469a1d0abeSdanielk1977   }
21479a1d0abeSdanielk1977   sqliteFree(pFile);
21489a1d0abeSdanielk1977   return TCL_OK;
21499a1d0abeSdanielk1977 }
21509a1d0abeSdanielk1977 
21519a1d0abeSdanielk1977 /*
21529a1d0abeSdanielk1977 ** Usage:  sqlite3OsLock <file handle> <locktype>
21539a1d0abeSdanielk1977 */
21549a1d0abeSdanielk1977 static int test_sqlite3OsLock(
21559a1d0abeSdanielk1977   void * clientData,
21569a1d0abeSdanielk1977   Tcl_Interp *interp,
21579a1d0abeSdanielk1977   int objc,
21589a1d0abeSdanielk1977   Tcl_Obj *CONST objv[]
21599a1d0abeSdanielk1977 ){
21609a1d0abeSdanielk1977   OsFile * pFile;
21619a1d0abeSdanielk1977   int rc;
21629a1d0abeSdanielk1977 
21639a1d0abeSdanielk1977   if( objc!=3 ){
21649a1d0abeSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
21659a1d0abeSdanielk1977         Tcl_GetString(objv[0]),
21669a1d0abeSdanielk1977         " filehandle (SHARED|RESERVED|PENDING|EXCLUSIVE)", 0);
21679a1d0abeSdanielk1977     return TCL_ERROR;
21689a1d0abeSdanielk1977   }
21699a1d0abeSdanielk1977 
21709a1d0abeSdanielk1977   if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
21719a1d0abeSdanielk1977     return TCL_ERROR;
21729a1d0abeSdanielk1977   }
21739a1d0abeSdanielk1977 
21749a1d0abeSdanielk1977   if( 0==strcmp("SHARED", Tcl_GetString(objv[2])) ){
21759a1d0abeSdanielk1977     rc = sqlite3OsLock(pFile, SHARED_LOCK);
21769a1d0abeSdanielk1977   }
21779a1d0abeSdanielk1977   else if( 0==strcmp("RESERVED", Tcl_GetString(objv[2])) ){
21789a1d0abeSdanielk1977     rc = sqlite3OsLock(pFile, RESERVED_LOCK);
21799a1d0abeSdanielk1977   }
21809a1d0abeSdanielk1977   else if( 0==strcmp("PENDING", Tcl_GetString(objv[2])) ){
21819a1d0abeSdanielk1977     rc = sqlite3OsLock(pFile, PENDING_LOCK);
21829a1d0abeSdanielk1977   }
21839a1d0abeSdanielk1977   else if( 0==strcmp("EXCLUSIVE", Tcl_GetString(objv[2])) ){
21849a1d0abeSdanielk1977     rc = sqlite3OsLock(pFile, EXCLUSIVE_LOCK);
21859a1d0abeSdanielk1977   }else{
21869a1d0abeSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
21879a1d0abeSdanielk1977         Tcl_GetString(objv[0]),
21889a1d0abeSdanielk1977         " filehandle (SHARED|RESERVED|PENDING|EXCLUSIVE)", 0);
21899a1d0abeSdanielk1977     return TCL_ERROR;
21909a1d0abeSdanielk1977   }
21919a1d0abeSdanielk1977 
21929a1d0abeSdanielk1977   if( rc!=SQLITE_OK ){
21939a1d0abeSdanielk1977     Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
21949a1d0abeSdanielk1977     return TCL_ERROR;
21959a1d0abeSdanielk1977   }
21969a1d0abeSdanielk1977   return TCL_OK;
21979a1d0abeSdanielk1977 }
21989a1d0abeSdanielk1977 
21999a1d0abeSdanielk1977 /*
22009a1d0abeSdanielk1977 ** Usage:  sqlite3OsUnlock <file handle>
22019a1d0abeSdanielk1977 */
22029a1d0abeSdanielk1977 static int test_sqlite3OsUnlock(
22039a1d0abeSdanielk1977   void * clientData,
22049a1d0abeSdanielk1977   Tcl_Interp *interp,
22059a1d0abeSdanielk1977   int objc,
22069a1d0abeSdanielk1977   Tcl_Obj *CONST objv[]
22079a1d0abeSdanielk1977 ){
22089a1d0abeSdanielk1977   OsFile * pFile;
22099a1d0abeSdanielk1977   int rc;
22109a1d0abeSdanielk1977 
22119a1d0abeSdanielk1977   if( objc!=2 ){
22129a1d0abeSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
22139a1d0abeSdanielk1977        Tcl_GetString(objv[0]), " filehandle", 0);
22149a1d0abeSdanielk1977     return TCL_ERROR;
22159a1d0abeSdanielk1977   }
22169a1d0abeSdanielk1977 
22179a1d0abeSdanielk1977   if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){
22189a1d0abeSdanielk1977     return TCL_ERROR;
22199a1d0abeSdanielk1977   }
2220a6abd041Sdrh   rc = sqlite3OsUnlock(pFile, NO_LOCK);
22219a1d0abeSdanielk1977   if( rc!=SQLITE_OK ){
22229a1d0abeSdanielk1977     Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
22239a1d0abeSdanielk1977     return TCL_ERROR;
22249a1d0abeSdanielk1977   }
22259a1d0abeSdanielk1977   return TCL_OK;
22269a1d0abeSdanielk1977 }
2227d3d39e93Sdrh 
2228d8123366Sdanielk1977 
22296622cce3Sdanielk1977 /*
2230d1bf3512Sdrh ** Register commands with the TCL interpreter.
2231d1bf3512Sdrh */
2232d1bf3512Sdrh int Sqlitetest1_Init(Tcl_Interp *interp){
22336f8a503dSdanielk1977   extern int sqlite3_search_count;
22346f8a503dSdanielk1977   extern int sqlite3_interrupt_count;
22356f8a503dSdanielk1977   extern int sqlite3_open_file_count;
22366f8a503dSdanielk1977   extern int sqlite3_current_time;
2237c2eef3b3Sdrh   static struct {
2238c2eef3b3Sdrh      char *zName;
2239c2eef3b3Sdrh      Tcl_CmdProc *xProc;
2240c2eef3b3Sdrh   } aCmd[] = {
22416f8a503dSdanielk1977      { "sqlite3_mprintf_int",           (Tcl_CmdProc*)sqlite3_mprintf_int    },
2242e9707671Sdrh      { "sqlite3_mprintf_int64",         (Tcl_CmdProc*)sqlite3_mprintf_int64  },
22436f8a503dSdanielk1977      { "sqlite3_mprintf_str",           (Tcl_CmdProc*)sqlite3_mprintf_str    },
22446f8a503dSdanielk1977      { "sqlite3_mprintf_double",        (Tcl_CmdProc*)sqlite3_mprintf_double },
22456f8a503dSdanielk1977      { "sqlite3_mprintf_scaled",        (Tcl_CmdProc*)sqlite3_mprintf_scaled },
22466f8a503dSdanielk1977      { "sqlite3_mprintf_z_test",        (Tcl_CmdProc*)test_mprintf_z        },
22476f8a503dSdanielk1977      { "sqlite3_last_insert_rowid",     (Tcl_CmdProc*)test_last_rowid       },
22486f8a503dSdanielk1977      { "sqlite3_exec_printf",           (Tcl_CmdProc*)test_exec_printf      },
22496f8a503dSdanielk1977      { "sqlite3_get_table_printf",      (Tcl_CmdProc*)test_get_table_printf },
22506f8a503dSdanielk1977      { "sqlite3_close",                 (Tcl_CmdProc*)sqlite_test_close     },
22516f8a503dSdanielk1977      { "sqlite3_create_function",       (Tcl_CmdProc*)test_create_function  },
22526f8a503dSdanielk1977      { "sqlite3_create_aggregate",      (Tcl_CmdProc*)test_create_aggregate },
2253c2eef3b3Sdrh      { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func    },
2254c2eef3b3Sdrh      { "sqlite_abort",                  (Tcl_CmdProc*)sqlite_abort          },
2255faa57accSdrh #ifdef SQLITE_DEBUG
2256c2eef3b3Sdrh      { "sqlite_malloc_fail",            (Tcl_CmdProc*)sqlite_malloc_fail    },
2257c2eef3b3Sdrh      { "sqlite_malloc_stat",            (Tcl_CmdProc*)sqlite_malloc_stat    },
2258c2eef3b3Sdrh #endif
225996fc5fe6Sdanielk1977      { "sqlite_bind",                    (Tcl_CmdProc*)test_bind             },
226099ee3600Sdrh      { "breakpoint",                     (Tcl_CmdProc*)test_breakpoint       },
2261c2eef3b3Sdrh   };
226251e3d8e2Sdanielk1977   static struct {
226351e3d8e2Sdanielk1977      char *zName;
226451e3d8e2Sdanielk1977      Tcl_ObjCmdProc *xProc;
226504f2e68dSdanielk1977      void *clientData;
226651e3d8e2Sdanielk1977   } aObjCmd[] = {
2267241db313Sdrh      { "sqlite3_bind_int",              test_bind_int,      0 },
226804f2e68dSdanielk1977      { "sqlite3_bind_int64",            test_bind_int64,    0 },
226904f2e68dSdanielk1977      { "sqlite3_bind_double",           test_bind_double,   0 },
227004f2e68dSdanielk1977      { "sqlite3_bind_null",             test_bind_null     ,0 },
227104f2e68dSdanielk1977      { "sqlite3_bind_text",             test_bind_text     ,0 },
227204f2e68dSdanielk1977      { "sqlite3_bind_text16",           test_bind_text16   ,0 },
227304f2e68dSdanielk1977      { "sqlite3_bind_blob",             test_bind_blob     ,0 },
227404f2e68dSdanielk1977      { "sqlite3_errcode",               test_errcode       ,0 },
227504f2e68dSdanielk1977      { "sqlite3_errmsg",                test_errmsg        ,0 },
227604f2e68dSdanielk1977      { "sqlite3_errmsg16",              test_errmsg16      ,0 },
227704f2e68dSdanielk1977      { "sqlite3_open",                  test_open          ,0 },
227804f2e68dSdanielk1977      { "sqlite3_open16",                test_open16        ,0 },
227904f2e68dSdanielk1977 
228004f2e68dSdanielk1977      { "sqlite3_prepare",               test_prepare       ,0 },
228104f2e68dSdanielk1977      { "sqlite3_prepare16",             test_prepare16     ,0 },
228204f2e68dSdanielk1977      { "sqlite3_finalize",              test_finalize      ,0 },
228304f2e68dSdanielk1977      { "sqlite3_reset",                 test_reset         ,0 },
2284fbcd585fSdanielk1977      { "sqlite3_changes",               test_changes       ,0 },
228504f2e68dSdanielk1977      { "sqlite3_step",                  test_step          ,0 },
228604f2e68dSdanielk1977 
228704f2e68dSdanielk1977      /* sqlite3_column_*() API */
228804f2e68dSdanielk1977      { "sqlite3_column_count",          test_column_count  ,0 },
228904f2e68dSdanielk1977      { "sqlite3_data_count",            test_data_count    ,0 },
229004f2e68dSdanielk1977      { "sqlite3_column_type",           test_column_type   ,0 },
2291ea61b2c4Sdanielk1977      { "sqlite3_column_blob",           test_column_blob   ,0 },
229204f2e68dSdanielk1977      { "sqlite3_column_double",         test_column_double ,0 },
229304f2e68dSdanielk1977      { "sqlite3_column_int64",          test_column_int64  ,0 },
229404f2e68dSdanielk1977      { "sqlite3_column_int",        test_stmt_int,   sqlite3_column_int       },
229504f2e68dSdanielk1977      { "sqlite3_column_bytes",      test_stmt_int,   sqlite3_column_bytes     },
229604f2e68dSdanielk1977      { "sqlite3_column_bytes16",    test_stmt_int,   sqlite3_column_bytes16   },
229704f2e68dSdanielk1977      { "sqlite3_column_text",       test_stmt_utf8,  sqlite3_column_text      },
229804f2e68dSdanielk1977      { "sqlite3_column_decltype",   test_stmt_utf8,  sqlite3_column_decltype  },
229904f2e68dSdanielk1977      { "sqlite3_column_name",       test_stmt_utf8,  sqlite3_column_name      },
230004f2e68dSdanielk1977      { "sqlite3_column_text16",     test_stmt_utf16, sqlite3_column_text16    },
230104f2e68dSdanielk1977      { "sqlite3_column_decltype16", test_stmt_utf16, sqlite3_column_decltype16},
230204f2e68dSdanielk1977      { "sqlite3_column_name16",     test_stmt_utf16, sqlite3_column_name16    },
230304f2e68dSdanielk1977 
23049a1d0abeSdanielk1977      /* Functions from os.h */
23059a1d0abeSdanielk1977      { "sqlite3OsOpenReadWrite",test_sqlite3OsOpenReadWrite, 0 },
23069a1d0abeSdanielk1977      { "sqlite3OsClose",        test_sqlite3OsClose, 0 },
23079a1d0abeSdanielk1977      { "sqlite3OsLock",         test_sqlite3OsLock, 0 },
2308312d6b36Sdanielk1977 
2309312d6b36Sdanielk1977      /* Custom test interfaces */
23109a1d0abeSdanielk1977      { "sqlite3OsUnlock",         test_sqlite3OsUnlock, 0    },
23114e6af134Sdanielk1977      { "add_test_collate",        test_collate, 0            },
2312312d6b36Sdanielk1977      { "add_test_collate_needed", test_collate_needed, 0     },
2313c8e9a2dfSdanielk1977      { "add_test_function",       test_function, 0           },
2314c8e9a2dfSdanielk1977      { "sqlite3_crashparams",     sqlite3_crashparams, 0     },
2315312d6b36Sdanielk1977      { "sqlite3_test_errstr",     test_errstr, 0             },
23169a1d0abeSdanielk1977 
231751e3d8e2Sdanielk1977   };
2318c2eef3b3Sdrh   int i;
23192ac3ee97Sdrh   extern int sqlite3_os_trace;
2320c2eef3b3Sdrh 
2321c2eef3b3Sdrh   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
2322c2eef3b3Sdrh     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
2323c2eef3b3Sdrh   }
232451e3d8e2Sdanielk1977   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
2325c572ef7fSdanielk1977     Tcl_CreateObjCommand(interp, aObjCmd[i].zName,
2326c572ef7fSdanielk1977         aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
232751e3d8e2Sdanielk1977   }
23286490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_search_count",
23296f8a503dSdanielk1977       (char*)&sqlite3_search_count, TCL_LINK_INT);
23306490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_interrupt_count",
23316f8a503dSdanielk1977       (char*)&sqlite3_interrupt_count, TCL_LINK_INT);
23326490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_open_file_count",
23336f8a503dSdanielk1977       (char*)&sqlite3_open_file_count, TCL_LINK_INT);
23346490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_current_time",
23356f8a503dSdanielk1977       (char*)&sqlite3_current_time, TCL_LINK_INT);
23362ac3ee97Sdrh   Tcl_LinkVar(interp, "sqlite_os_trace",
23372ac3ee97Sdrh       (char*)&sqlite3_os_trace, TCL_LINK_INT);
23387c972decSdrh   Tcl_LinkVar(interp, "sqlite_static_bind_value",
23397c972decSdrh       (char*)&sqlite_static_bind_value, TCL_LINK_STRING);
2340d1bf3512Sdrh   return TCL_OK;
2341d1bf3512Sdrh }
2342