xref: /sqlite-3.40.0/src/test1.c (revision fa3d4c19)
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 *************************************************************************
1205a82983Sdrh ** Code for testing all sorts of SQLite interfaces.  This code
13d1bf3512Sdrh ** is not included in the SQLite library.  It is used for automated
14d1bf3512Sdrh ** testing of the SQLite library.
15d1bf3512Sdrh */
16d1bf3512Sdrh #include "sqliteInt.h"
17f74b9e09Smistachkin #if SQLITE_OS_WIN
18f74b9e09Smistachkin #  include "os_win.h"
19f74b9e09Smistachkin #endif
20f74b9e09Smistachkin 
21d9495cd0Sdan #include "vdbeInt.h"
2252b1dbb5Smistachkin #if defined(INCLUDE_SQLITE_TCL_H)
2352b1dbb5Smistachkin #  include "sqlite_tcl.h"
2452b1dbb5Smistachkin #else
25d1bf3512Sdrh #  include "tcl.h"
2652b1dbb5Smistachkin #endif
27d1bf3512Sdrh #include <stdlib.h>
28d1bf3512Sdrh #include <string.h>
29d1bf3512Sdrh 
30dddca286Sdrh /*
31dddca286Sdrh ** This is a copy of the first part of the SqliteDb structure in
32dddca286Sdrh ** tclsqlite.c.  We need it here so that the get_sqlite_pointer routine
33dddca286Sdrh ** can extract the sqlite3* pointer from an existing Tcl SQLite
34dddca286Sdrh ** connection.
35dddca286Sdrh */
36dddca286Sdrh struct SqliteDb {
37dddca286Sdrh   sqlite3 *db;
38dddca286Sdrh };
39dddca286Sdrh 
40dddca286Sdrh /*
41a3152895Sdrh ** Convert text generated by the "%p" conversion format back into
42a3152895Sdrh ** a pointer.
43a3152895Sdrh */
44a3152895Sdrh static int testHexToInt(int h){
45a3152895Sdrh   if( h>='0' && h<='9' ){
46a3152895Sdrh     return h - '0';
47a3152895Sdrh   }else if( h>='a' && h<='f' ){
48a3152895Sdrh     return h - 'a' + 10;
49a3152895Sdrh   }else{
50a3152895Sdrh     assert( h>='A' && h<='F' );
51a3152895Sdrh     return h - 'A' + 10;
52a3152895Sdrh   }
53a3152895Sdrh }
54e8f52c50Sdrh void *sqlite3TestTextToPtr(const char *z){
55a3152895Sdrh   void *p;
56a3152895Sdrh   u64 v;
57a3152895Sdrh   u32 v2;
58a3152895Sdrh   if( z[0]=='0' && z[1]=='x' ){
59a3152895Sdrh     z += 2;
60a3152895Sdrh   }
61a3152895Sdrh   v = 0;
62a3152895Sdrh   while( *z ){
63a3152895Sdrh     v = (v<<4) + testHexToInt(*z);
64a3152895Sdrh     z++;
65a3152895Sdrh   }
66a3152895Sdrh   if( sizeof(p)==sizeof(v) ){
67a3152895Sdrh     memcpy(&p, &v, sizeof(p));
68a3152895Sdrh   }else{
69a3152895Sdrh     assert( sizeof(p)==sizeof(v2) );
70a3152895Sdrh     v2 = (u32)v;
71a3152895Sdrh     memcpy(&p, &v2, sizeof(p));
72a3152895Sdrh   }
73a3152895Sdrh   return p;
74a3152895Sdrh }
75a3152895Sdrh 
76a3152895Sdrh 
77a3152895Sdrh /*
78dddca286Sdrh ** A TCL command that returns the address of the sqlite* pointer
79dddca286Sdrh ** for an sqlite connection instance.  Bad things happen if the
80dddca286Sdrh ** input is not an sqlite connection.
81dddca286Sdrh */
827617e4a8Smistachkin static int SQLITE_TCLAPI get_sqlite_pointer(
83dddca286Sdrh   void * clientData,
84dddca286Sdrh   Tcl_Interp *interp,
85dddca286Sdrh   int objc,
86dddca286Sdrh   Tcl_Obj *CONST objv[]
87dddca286Sdrh ){
88dddca286Sdrh   struct SqliteDb *p;
89dddca286Sdrh   Tcl_CmdInfo cmdInfo;
90dddca286Sdrh   char zBuf[100];
91dddca286Sdrh   if( objc!=2 ){
92dddca286Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "SQLITE-CONNECTION");
93dddca286Sdrh     return TCL_ERROR;
94dddca286Sdrh   }
95dddca286Sdrh   if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){
96dddca286Sdrh     Tcl_AppendResult(interp, "command not found: ",
97dddca286Sdrh            Tcl_GetString(objv[1]), (char*)0);
98dddca286Sdrh     return TCL_ERROR;
99dddca286Sdrh   }
100dddca286Sdrh   p = (struct SqliteDb*)cmdInfo.objClientData;
10165545b59Sdrh   sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", p->db);
102dddca286Sdrh   Tcl_AppendResult(interp, zBuf, 0);
103dddca286Sdrh   return TCL_OK;
104dddca286Sdrh }
105dddca286Sdrh 
106b62c335eSdrh /*
107b62c335eSdrh ** Decode a pointer to an sqlite3 object.
108b62c335eSdrh */
10924b58dd7Sdrh int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){
110b62c335eSdrh   struct SqliteDb *p;
111b62c335eSdrh   Tcl_CmdInfo cmdInfo;
112b62c335eSdrh   if( Tcl_GetCommandInfo(interp, zA, &cmdInfo) ){
113b62c335eSdrh     p = (struct SqliteDb*)cmdInfo.objClientData;
114b62c335eSdrh     *ppDb = p->db;
115b62c335eSdrh   }else{
116e8f52c50Sdrh     *ppDb = (sqlite3*)sqlite3TestTextToPtr(zA);
117b62c335eSdrh   }
118b62c335eSdrh   return TCL_OK;
119b62c335eSdrh }
120b62c335eSdrh 
1216b98d67bSmistachkin #if SQLITE_OS_WIN
1226b98d67bSmistachkin /*
1236b98d67bSmistachkin ** Decode a Win32 HANDLE object.
1246b98d67bSmistachkin */
1256b98d67bSmistachkin int getWin32Handle(Tcl_Interp *interp, const char *zA, LPHANDLE phFile){
1266b98d67bSmistachkin   *phFile = (HANDLE)sqlite3TestTextToPtr(zA);
1276b98d67bSmistachkin   return TCL_OK;
1286b98d67bSmistachkin }
1296b98d67bSmistachkin #endif
1306b98d67bSmistachkin 
131e84d8d32Smistachkin extern const char *sqlite3ErrName(int);
132e84d8d32Smistachkin #define t1ErrorName sqlite3ErrName
1336622cce3Sdanielk1977 
134d1bf3512Sdrh /*
135c60d0446Sdrh ** Convert an sqlite3_stmt* into an sqlite3*.  This depends on the
136c60d0446Sdrh ** fact that the sqlite3* is the first field in the Vdbe structure.
137c60d0446Sdrh */
13851942bc3Sdrh #define StmtToDb(X)   sqlite3_db_handle(X)
139c60d0446Sdrh 
140c60d0446Sdrh /*
141c60d0446Sdrh ** Check a return value to make sure it agrees with the results
142c60d0446Sdrh ** from sqlite3_errcode.
143c60d0446Sdrh */
144c60d0446Sdrh int sqlite3TestErrCode(Tcl_Interp *interp, sqlite3 *db, int rc){
145b8613ab1Sdrh   if( sqlite3_threadsafe()==0 && rc!=SQLITE_MISUSE && rc!=SQLITE_OK
146b8613ab1Sdrh    && sqlite3_errcode(db)!=rc ){
147c60d0446Sdrh     char zBuf[200];
148c60d0446Sdrh     int r2 = sqlite3_errcode(db);
14965545b59Sdrh     sqlite3_snprintf(sizeof(zBuf), zBuf,
15065545b59Sdrh        "error code %s (%d) does not match sqlite3_errcode %s (%d)",
1514f0c5878Sdrh        t1ErrorName(rc), rc, t1ErrorName(r2), r2);
152c60d0446Sdrh     Tcl_ResetResult(interp);
153c60d0446Sdrh     Tcl_AppendResult(interp, zBuf, 0);
154c60d0446Sdrh     return 1;
155c60d0446Sdrh   }
156c60d0446Sdrh   return 0;
157c60d0446Sdrh }
158c60d0446Sdrh 
159c60d0446Sdrh /*
16051e3d8e2Sdanielk1977 ** Decode a pointer to an sqlite3_stmt object.
16151e3d8e2Sdanielk1977 */
16251e3d8e2Sdanielk1977 static int getStmtPointer(
16351e3d8e2Sdanielk1977   Tcl_Interp *interp,
16451e3d8e2Sdanielk1977   const char *zArg,
16551e3d8e2Sdanielk1977   sqlite3_stmt **ppStmt
16651e3d8e2Sdanielk1977 ){
167e8f52c50Sdrh   *ppStmt = (sqlite3_stmt*)sqlite3TestTextToPtr(zArg);
16851e3d8e2Sdanielk1977   return TCL_OK;
16951e3d8e2Sdanielk1977 }
17051e3d8e2Sdanielk1977 
17151e3d8e2Sdanielk1977 /*
1727d8085a8Sdrh ** Generate a text representation of a pointer that can be understood
1737d8085a8Sdrh ** by the getDbPointer and getVmPointer routines above.
1747d8085a8Sdrh **
1757d8085a8Sdrh ** The problem is, on some machines (Solaris) if you do a printf with
1767d8085a8Sdrh ** "%p" you cannot turn around and do a scanf with the same "%p" and
1777d8085a8Sdrh ** get your pointer back.  You have to prepend a "0x" before it will
1787d8085a8Sdrh ** work.  Or at least that is what is reported to me (drh).  But this
1797d8085a8Sdrh ** behavior varies from machine to machine.  The solution used her is
1807d8085a8Sdrh ** to test the string right after it is generated to see if it can be
1817d8085a8Sdrh ** understood by scanf, and if not, try prepending an "0x" to see if
1827d8085a8Sdrh ** that helps.  If nothing works, a fatal error is generated.
1837d8085a8Sdrh */
18464b1bea3Sdrh int sqlite3TestMakePointerStr(Tcl_Interp *interp, char *zPtr, void *p){
185fe63d1c9Sdrh   sqlite3_snprintf(100, zPtr, "%p", p);
1867d8085a8Sdrh   return TCL_OK;
1877d8085a8Sdrh }
1887d8085a8Sdrh 
1897d8085a8Sdrh /*
1906f8a503dSdanielk1977 ** The callback routine for sqlite3_exec_printf().
191d1bf3512Sdrh */
192d1bf3512Sdrh static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){
193d1bf3512Sdrh   Tcl_DString *str = (Tcl_DString*)pArg;
194d1bf3512Sdrh   int i;
195d1bf3512Sdrh 
196d1bf3512Sdrh   if( Tcl_DStringLength(str)==0 ){
197d1bf3512Sdrh     for(i=0; i<argc; i++){
198d1bf3512Sdrh       Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL");
199d1bf3512Sdrh     }
200d1bf3512Sdrh   }
201d1bf3512Sdrh   for(i=0; i<argc; i++){
202d1bf3512Sdrh     Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL");
203d1bf3512Sdrh   }
204d1bf3512Sdrh   return 0;
205d1bf3512Sdrh }
206d1bf3512Sdrh 
207d1bf3512Sdrh /*
208538f570cSdrh ** The I/O tracing callback.
209538f570cSdrh */
210afdd23a4Sshane #if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE)
211538f570cSdrh static FILE *iotrace_file = 0;
212538f570cSdrh static void io_trace_callback(const char *zFormat, ...){
213538f570cSdrh   va_list ap;
214538f570cSdrh   va_start(ap, zFormat);
215538f570cSdrh   vfprintf(iotrace_file, zFormat, ap);
216538f570cSdrh   va_end(ap);
217538f570cSdrh   fflush(iotrace_file);
218538f570cSdrh }
219afdd23a4Sshane #endif
220538f570cSdrh 
221538f570cSdrh /*
222538f570cSdrh ** Usage:  io_trace FILENAME
223538f570cSdrh **
224538f570cSdrh ** Turn I/O tracing on or off.  If FILENAME is not an empty string,
225538f570cSdrh ** I/O tracing begins going into FILENAME. If FILENAME is an empty
226538f570cSdrh ** string, I/O tracing is turned off.
227538f570cSdrh */
2287617e4a8Smistachkin static int SQLITE_TCLAPI test_io_trace(
229538f570cSdrh   void *NotUsed,
230538f570cSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
231538f570cSdrh   int argc,              /* Number of arguments */
232538f570cSdrh   char **argv            /* Text of each argument */
233538f570cSdrh ){
234286d2f4aSdanielk1977 #if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE)
235538f570cSdrh   if( argc!=2 ){
236538f570cSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
237538f570cSdrh           " FILENAME\"", 0);
238538f570cSdrh     return TCL_ERROR;
239538f570cSdrh   }
240538f570cSdrh   if( iotrace_file ){
241538f570cSdrh     if( iotrace_file!=stdout && iotrace_file!=stderr ){
242538f570cSdrh       fclose(iotrace_file);
243538f570cSdrh     }
244538f570cSdrh     iotrace_file = 0;
2453a00f907Smlcreech     sqlite3IoTrace = 0;
246538f570cSdrh   }
247538f570cSdrh   if( argv[1][0] ){
248538f570cSdrh     if( strcmp(argv[1],"stdout")==0 ){
249538f570cSdrh       iotrace_file = stdout;
250538f570cSdrh     }else if( strcmp(argv[1],"stderr")==0 ){
251538f570cSdrh       iotrace_file = stderr;
252538f570cSdrh     }else{
253538f570cSdrh       iotrace_file = fopen(argv[1], "w");
254538f570cSdrh     }
2553a00f907Smlcreech     sqlite3IoTrace = io_trace_callback;
256538f570cSdrh   }
257286d2f4aSdanielk1977 #endif
258286d2f4aSdanielk1977   return TCL_OK;
259538f570cSdrh }
260538f570cSdrh 
261afcf9bd8Sdan /*
262afcf9bd8Sdan ** Usage:  clang_sanitize_address
263afcf9bd8Sdan **
264afcf9bd8Sdan ** Returns true if the program was compiled using clang with the
265afcf9bd8Sdan ** -fsanitize=address switch on the command line. False otherwise.
26632e1f279Sdrh **
26732e1f279Sdrh ** Also return true if the OMIT_MISUSE environment variable exists.
268afcf9bd8Sdan */
2697617e4a8Smistachkin static int SQLITE_TCLAPI clang_sanitize_address(
270afcf9bd8Sdan   void *NotUsed,
271afcf9bd8Sdan   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
272afcf9bd8Sdan   int argc,              /* Number of arguments */
273afcf9bd8Sdan   char **argv            /* Text of each argument */
274afcf9bd8Sdan ){
275afcf9bd8Sdan   int res = 0;
276afcf9bd8Sdan #if defined(__has_feature)
277afcf9bd8Sdan # if __has_feature(address_sanitizer)
278afcf9bd8Sdan   res = 1;
279afcf9bd8Sdan # endif
280afcf9bd8Sdan #endif
281618ee61eSdrh #ifdef __SANITIZE_ADDRESS__
282618ee61eSdrh   res = 1;
283618ee61eSdrh #endif
28432e1f279Sdrh   if( res==0 && getenv("OMIT_MISUSE")!=0 ) res = 1;
285afcf9bd8Sdan   Tcl_SetObjResult(interp, Tcl_NewIntObj(res));
286afcf9bd8Sdan   return TCL_OK;
287afcf9bd8Sdan }
288538f570cSdrh 
289538f570cSdrh /*
2906f8a503dSdanielk1977 ** Usage:  sqlite3_exec_printf  DB  FORMAT  STRING
291d1bf3512Sdrh **
2926f8a503dSdanielk1977 ** Invoke the sqlite3_exec_printf() interface using the open database
293d1bf3512Sdrh ** DB.  The SQL is the string FORMAT.  The format string should contain
294d1bf3512Sdrh ** one %s or %q.  STRING is the value inserted into %s or %q.
295d1bf3512Sdrh */
2967617e4a8Smistachkin static int SQLITE_TCLAPI test_exec_printf(
297d1bf3512Sdrh   void *NotUsed,
298d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
299d1bf3512Sdrh   int argc,              /* Number of arguments */
300d1bf3512Sdrh   char **argv            /* Text of each argument */
301d1bf3512Sdrh ){
3029bb575fdSdrh   sqlite3 *db;
303d1bf3512Sdrh   Tcl_DString str;
304d1bf3512Sdrh   int rc;
305d1bf3512Sdrh   char *zErr = 0;
3061211de37Sdrh   char *zSql;
307d1bf3512Sdrh   char zBuf[30];
308d1bf3512Sdrh   if( argc!=4 ){
309d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
310d1bf3512Sdrh        " DB FORMAT STRING", 0);
311d1bf3512Sdrh     return TCL_ERROR;
312d1bf3512Sdrh   }
313b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
314d1bf3512Sdrh   Tcl_DStringInit(&str);
3151211de37Sdrh   zSql = sqlite3_mprintf(argv[2], argv[3]);
3161211de37Sdrh   rc = sqlite3_exec(db, zSql, exec_printf_cb, &str, &zErr);
3171211de37Sdrh   sqlite3_free(zSql);
31865545b59Sdrh   sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", rc);
319d1bf3512Sdrh   Tcl_AppendElement(interp, zBuf);
320d1bf3512Sdrh   Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
321d1bf3512Sdrh   Tcl_DStringFree(&str);
322926aab22Sdanielk1977   if( zErr ) sqlite3_free(zErr);
323c60d0446Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
324d1bf3512Sdrh   return TCL_OK;
325d1bf3512Sdrh }
326d1bf3512Sdrh 
327d1bf3512Sdrh /*
3285bd98aefSdrh ** Usage:  sqlite3_exec_hex  DB  HEX
3295bd98aefSdrh **
3305bd98aefSdrh ** Invoke the sqlite3_exec() on a string that is obtained by translating
3315bd98aefSdrh ** HEX into ASCII.  Most characters are translated as is.  %HH becomes
3325bd98aefSdrh ** a hex character.
3335bd98aefSdrh */
3347617e4a8Smistachkin static int SQLITE_TCLAPI test_exec_hex(
3355bd98aefSdrh   void *NotUsed,
3365bd98aefSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
3375bd98aefSdrh   int argc,              /* Number of arguments */
3385bd98aefSdrh   char **argv            /* Text of each argument */
3395bd98aefSdrh ){
3405bd98aefSdrh   sqlite3 *db;
3415bd98aefSdrh   Tcl_DString str;
3425bd98aefSdrh   int rc, i, j;
3435bd98aefSdrh   char *zErr = 0;
3445bd98aefSdrh   char *zHex;
345dca92904Sdan   char zSql[501];
3465bd98aefSdrh   char zBuf[30];
3475bd98aefSdrh   if( argc!=3 ){
3485bd98aefSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
3495bd98aefSdrh        " DB HEX", 0);
3505bd98aefSdrh     return TCL_ERROR;
3515bd98aefSdrh   }
3525bd98aefSdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
3535bd98aefSdrh   zHex = argv[2];
354dca92904Sdan   for(i=j=0; i<(sizeof(zSql)-1) && zHex[j]; i++, j++){
3555bd98aefSdrh     if( zHex[j]=='%' && zHex[j+2] && zHex[j+2] ){
3565bd98aefSdrh       zSql[i] = (testHexToInt(zHex[j+1])<<4) + testHexToInt(zHex[j+2]);
3575bd98aefSdrh       j += 2;
3585bd98aefSdrh     }else{
3595bd98aefSdrh       zSql[i] = zHex[j];
3605bd98aefSdrh     }
3615bd98aefSdrh   }
3625bd98aefSdrh   zSql[i] = 0;
3635bd98aefSdrh   Tcl_DStringInit(&str);
3645bd98aefSdrh   rc = sqlite3_exec(db, zSql, exec_printf_cb, &str, &zErr);
36565545b59Sdrh   sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", rc);
3665bd98aefSdrh   Tcl_AppendElement(interp, zBuf);
3675bd98aefSdrh   Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
3685bd98aefSdrh   Tcl_DStringFree(&str);
3695bd98aefSdrh   if( zErr ) sqlite3_free(zErr);
3705bd98aefSdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
3715bd98aefSdrh   return TCL_OK;
3725bd98aefSdrh }
3735bd98aefSdrh 
3745bd98aefSdrh /*
37527641703Sdrh ** Usage:  db_enter DB
37627641703Sdrh **         db_leave DB
37727641703Sdrh **
37827641703Sdrh ** Enter or leave the mutex on a database connection.
37927641703Sdrh */
3807617e4a8Smistachkin static int SQLITE_TCLAPI db_enter(
38127641703Sdrh   void *NotUsed,
38227641703Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
38327641703Sdrh   int argc,              /* Number of arguments */
38427641703Sdrh   char **argv            /* Text of each argument */
38527641703Sdrh ){
38627641703Sdrh   sqlite3 *db;
38727641703Sdrh   if( argc!=2 ){
38827641703Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
38927641703Sdrh        " DB", 0);
39027641703Sdrh     return TCL_ERROR;
39127641703Sdrh   }
39227641703Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
39327641703Sdrh   sqlite3_mutex_enter(db->mutex);
39427641703Sdrh   return TCL_OK;
39527641703Sdrh }
3967617e4a8Smistachkin static int SQLITE_TCLAPI db_leave(
39727641703Sdrh   void *NotUsed,
39827641703Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
39927641703Sdrh   int argc,              /* Number of arguments */
40027641703Sdrh   char **argv            /* Text of each argument */
40127641703Sdrh ){
40227641703Sdrh   sqlite3 *db;
40327641703Sdrh   if( argc!=2 ){
40427641703Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
40527641703Sdrh        " DB", 0);
40627641703Sdrh     return TCL_ERROR;
40727641703Sdrh   }
40827641703Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
40927641703Sdrh   sqlite3_mutex_leave(db->mutex);
41027641703Sdrh   return TCL_OK;
41127641703Sdrh }
41227641703Sdrh 
41327641703Sdrh /*
414b62c335eSdrh ** Usage:  sqlite3_exec  DB  SQL
415b62c335eSdrh **
416b62c335eSdrh ** Invoke the sqlite3_exec interface using the open database DB
417b62c335eSdrh */
4187617e4a8Smistachkin static int SQLITE_TCLAPI test_exec(
419b62c335eSdrh   void *NotUsed,
420b62c335eSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
421b62c335eSdrh   int argc,              /* Number of arguments */
422b62c335eSdrh   char **argv            /* Text of each argument */
423b62c335eSdrh ){
424b62c335eSdrh   sqlite3 *db;
425b62c335eSdrh   Tcl_DString str;
426b62c335eSdrh   int rc;
427b62c335eSdrh   char *zErr = 0;
4284e5dd851Sdrh   char *zSql;
4294e5dd851Sdrh   int i, j;
430b62c335eSdrh   char zBuf[30];
431b62c335eSdrh   if( argc!=3 ){
432b62c335eSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
433b62c335eSdrh        " DB SQL", 0);
434b62c335eSdrh     return TCL_ERROR;
435b62c335eSdrh   }
436b62c335eSdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
437b62c335eSdrh   Tcl_DStringInit(&str);
4384e5dd851Sdrh   zSql = sqlite3_mprintf("%s", argv[2]);
4394e5dd851Sdrh   for(i=j=0; zSql[i];){
4404e5dd851Sdrh     if( zSql[i]=='%' ){
4414e5dd851Sdrh       zSql[j++] = (testHexToInt(zSql[i+1])<<4) + testHexToInt(zSql[i+2]);
4424e5dd851Sdrh       i += 3;
4434e5dd851Sdrh     }else{
4444e5dd851Sdrh       zSql[j++] = zSql[i++];
4454e5dd851Sdrh     }
4464e5dd851Sdrh   }
4474e5dd851Sdrh   zSql[j] = 0;
4484e5dd851Sdrh   rc = sqlite3_exec(db, zSql, exec_printf_cb, &str, &zErr);
4494e5dd851Sdrh   sqlite3_free(zSql);
45065545b59Sdrh   sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", rc);
451b62c335eSdrh   Tcl_AppendElement(interp, zBuf);
452b62c335eSdrh   Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
453b62c335eSdrh   Tcl_DStringFree(&str);
454b62c335eSdrh   if( zErr ) sqlite3_free(zErr);
455b62c335eSdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
456b62c335eSdrh   return TCL_OK;
457b62c335eSdrh }
458b62c335eSdrh 
459b62c335eSdrh /*
460b62c335eSdrh ** Usage:  sqlite3_exec_nr  DB  SQL
461b62c335eSdrh **
462b62c335eSdrh ** Invoke the sqlite3_exec interface using the open database DB.  Discard
463b62c335eSdrh ** all results
464b62c335eSdrh */
4657617e4a8Smistachkin static int SQLITE_TCLAPI test_exec_nr(
466b62c335eSdrh   void *NotUsed,
467b62c335eSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
468b62c335eSdrh   int argc,              /* Number of arguments */
469b62c335eSdrh   char **argv            /* Text of each argument */
470b62c335eSdrh ){
471b62c335eSdrh   sqlite3 *db;
472b62c335eSdrh   int rc;
473b62c335eSdrh   char *zErr = 0;
474b62c335eSdrh   if( argc!=3 ){
475b62c335eSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
476b62c335eSdrh        " DB SQL", 0);
477b62c335eSdrh     return TCL_ERROR;
478b62c335eSdrh   }
479b62c335eSdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
480b62c335eSdrh   rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
481b62c335eSdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
482b62c335eSdrh   return TCL_OK;
483b62c335eSdrh }
484b62c335eSdrh 
485b62c335eSdrh /*
4866f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_z_test  SEPARATOR  ARG0  ARG1 ...
487d93d8a81Sdrh **
488bc6160b0Sdrh ** Test the %z format of sqlite_mprintf().  Use multiple mprintf() calls to
489d93d8a81Sdrh ** concatenate arg0 through argn using separator as the separator.
490d93d8a81Sdrh ** Return the result.
491d93d8a81Sdrh */
4927617e4a8Smistachkin static int SQLITE_TCLAPI test_mprintf_z(
493d93d8a81Sdrh   void *NotUsed,
494d93d8a81Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
495d93d8a81Sdrh   int argc,              /* Number of arguments */
496d93d8a81Sdrh   char **argv            /* Text of each argument */
497d93d8a81Sdrh ){
498d93d8a81Sdrh   char *zResult = 0;
499d93d8a81Sdrh   int i;
500d93d8a81Sdrh 
501ca0c8971Sdanielk1977   for(i=2; i<argc && (i==2 || zResult); i++){
502bc6160b0Sdrh     zResult = sqlite3_mprintf("%z%s%s", zResult, argv[1], argv[i]);
503d93d8a81Sdrh   }
504d93d8a81Sdrh   Tcl_AppendResult(interp, zResult, 0);
50517435752Sdrh   sqlite3_free(zResult);
506d93d8a81Sdrh   return TCL_OK;
507d93d8a81Sdrh }
508d93d8a81Sdrh 
509d93d8a81Sdrh /*
51005a82983Sdrh ** Usage:  sqlite3_mprintf_n_test  STRING
51105a82983Sdrh **
512bc6160b0Sdrh ** Test the %n format of sqlite_mprintf().  Return the length of the
51305a82983Sdrh ** input string.
51405a82983Sdrh */
5157617e4a8Smistachkin static int SQLITE_TCLAPI test_mprintf_n(
51605a82983Sdrh   void *NotUsed,
51705a82983Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
51805a82983Sdrh   int argc,              /* Number of arguments */
51905a82983Sdrh   char **argv            /* Text of each argument */
52005a82983Sdrh ){
52105a82983Sdrh   char *zStr;
52205a82983Sdrh   int n = 0;
523bc6160b0Sdrh   zStr = sqlite3_mprintf("%s%n", argv[1], &n);
52417435752Sdrh   sqlite3_free(zStr);
52505a82983Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(n));
52605a82983Sdrh   return TCL_OK;
52705a82983Sdrh }
52805a82983Sdrh 
52905a82983Sdrh /*
53068853907Sdrh ** Usage:  sqlite3_snprintf_int  SIZE FORMAT  INT
53168853907Sdrh **
53268853907Sdrh ** Test the of sqlite3_snprintf() routine.  SIZE is the size of the
53368853907Sdrh ** output buffer in bytes.  The maximum size is 100.  FORMAT is the
53468853907Sdrh ** format string.  INT is a single integer argument.  The FORMAT
53568853907Sdrh ** string must require no more than this one integer argument.  If
53668853907Sdrh ** You pass in a format string that requires more than one argument,
53768853907Sdrh ** bad things will happen.
53868853907Sdrh */
5397617e4a8Smistachkin static int SQLITE_TCLAPI test_snprintf_int(
54068853907Sdrh   void *NotUsed,
54168853907Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
54268853907Sdrh   int argc,              /* Number of arguments */
54368853907Sdrh   char **argv            /* Text of each argument */
54468853907Sdrh ){
54568853907Sdrh   char zStr[100];
54668853907Sdrh   int n = atoi(argv[1]);
54768853907Sdrh   const char *zFormat = argv[2];
54868853907Sdrh   int a1 = atoi(argv[3]);
549daf276d4Sdrh   if( n>sizeof(zStr) ) n = sizeof(zStr);
5507694574aSdrh   sqlite3_snprintf(sizeof(zStr), zStr, "abcdefghijklmnopqrstuvwxyz");
55168853907Sdrh   sqlite3_snprintf(n, zStr, zFormat, a1);
55268853907Sdrh   Tcl_AppendResult(interp, zStr, 0);
55368853907Sdrh   return TCL_OK;
55468853907Sdrh }
55568853907Sdrh 
5568225f5acSshane #ifndef SQLITE_OMIT_GET_TABLE
5578225f5acSshane 
55868853907Sdrh /*
559d2b3e23bSdrh ** Usage:  sqlite3_get_table_printf  DB  FORMAT  STRING  ?--no-counts?
560d1bf3512Sdrh **
5616f8a503dSdanielk1977 ** Invoke the sqlite3_get_table_printf() interface using the open database
562d1bf3512Sdrh ** DB.  The SQL is the string FORMAT.  The format string should contain
563d1bf3512Sdrh ** one %s or %q.  STRING is the value inserted into %s or %q.
564d1bf3512Sdrh */
5657617e4a8Smistachkin static int SQLITE_TCLAPI test_get_table_printf(
566d1bf3512Sdrh   void *NotUsed,
567d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
568d1bf3512Sdrh   int argc,              /* Number of arguments */
569d1bf3512Sdrh   char **argv            /* Text of each argument */
570d1bf3512Sdrh ){
5719bb575fdSdrh   sqlite3 *db;
572d1bf3512Sdrh   Tcl_DString str;
573d1bf3512Sdrh   int rc;
574d1bf3512Sdrh   char *zErr = 0;
57527b2f053Smistachkin   int nRow = 0, nCol = 0;
576d1bf3512Sdrh   char **aResult;
577d1bf3512Sdrh   int i;
578d1bf3512Sdrh   char zBuf[30];
5791211de37Sdrh   char *zSql;
580d2b3e23bSdrh   int resCount = -1;
581d2b3e23bSdrh   if( argc==5 ){
582d2b3e23bSdrh     if( Tcl_GetInt(interp, argv[4], &resCount) ) return TCL_ERROR;
583d2b3e23bSdrh   }
584d2b3e23bSdrh   if( argc!=4 && argc!=5 ){
585d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
586d2b3e23bSdrh        " DB FORMAT STRING ?COUNT?", 0);
587d1bf3512Sdrh     return TCL_ERROR;
588d1bf3512Sdrh   }
589b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
590d1bf3512Sdrh   Tcl_DStringInit(&str);
5911211de37Sdrh   zSql = sqlite3_mprintf(argv[2],argv[3]);
592d2b3e23bSdrh   if( argc==5 ){
593d2b3e23bSdrh     rc = sqlite3_get_table(db, zSql, &aResult, 0, 0, &zErr);
594d2b3e23bSdrh   }else{
5951211de37Sdrh     rc = sqlite3_get_table(db, zSql, &aResult, &nRow, &nCol, &zErr);
596d2b3e23bSdrh     resCount = (nRow+1)*nCol;
597d2b3e23bSdrh   }
5981211de37Sdrh   sqlite3_free(zSql);
59965545b59Sdrh   sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", rc);
600d1bf3512Sdrh   Tcl_AppendElement(interp, zBuf);
601d1bf3512Sdrh   if( rc==SQLITE_OK ){
602d2b3e23bSdrh     if( argc==4 ){
60365545b59Sdrh       sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nRow);
604d1bf3512Sdrh       Tcl_AppendElement(interp, zBuf);
60565545b59Sdrh       sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", nCol);
606d1bf3512Sdrh       Tcl_AppendElement(interp, zBuf);
607d2b3e23bSdrh     }
608d2b3e23bSdrh     for(i=0; i<resCount; i++){
609d1bf3512Sdrh       Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL");
610d1bf3512Sdrh     }
611d1bf3512Sdrh   }else{
612d1bf3512Sdrh     Tcl_AppendElement(interp, zErr);
613d1bf3512Sdrh   }
6146f8a503dSdanielk1977   sqlite3_free_table(aResult);
615926aab22Sdanielk1977   if( zErr ) sqlite3_free(zErr);
616c60d0446Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
617d1bf3512Sdrh   return TCL_OK;
618d1bf3512Sdrh }
619d1bf3512Sdrh 
6208225f5acSshane #endif /* SQLITE_OMIT_GET_TABLE */
6218225f5acSshane 
622af9ff33aSdrh 
623af9ff33aSdrh /*
6246f8a503dSdanielk1977 ** Usage:  sqlite3_last_insert_rowid DB
625af9ff33aSdrh **
626af9ff33aSdrh ** Returns the integer ROWID of the most recent insert.
627af9ff33aSdrh */
6287617e4a8Smistachkin static int SQLITE_TCLAPI test_last_rowid(
629af9ff33aSdrh   void *NotUsed,
630af9ff33aSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
631af9ff33aSdrh   int argc,              /* Number of arguments */
632af9ff33aSdrh   char **argv            /* Text of each argument */
633af9ff33aSdrh ){
6349bb575fdSdrh   sqlite3 *db;
635af9ff33aSdrh   char zBuf[30];
636af9ff33aSdrh 
637af9ff33aSdrh   if( argc!=2 ){
638af9ff33aSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0);
639af9ff33aSdrh     return TCL_ERROR;
640af9ff33aSdrh   }
641b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
64265545b59Sdrh   sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", sqlite3_last_insert_rowid(db));
643af9ff33aSdrh   Tcl_AppendResult(interp, zBuf, 0);
644af9ff33aSdrh   return SQLITE_OK;
645af9ff33aSdrh }
646af9ff33aSdrh 
647d1bf3512Sdrh /*
64825d6543dSdrh ** Usage:  sqlite3_key DB KEY
64925d6543dSdrh **
65025d6543dSdrh ** Set the codec key.
65125d6543dSdrh */
6527617e4a8Smistachkin static int SQLITE_TCLAPI test_key(
65325d6543dSdrh   void *NotUsed,
65425d6543dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
65525d6543dSdrh   int argc,              /* Number of arguments */
65625d6543dSdrh   char **argv            /* Text of each argument */
65725d6543dSdrh ){
65832f57d4cSdrh #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL)
6599bb575fdSdrh   sqlite3 *db;
66025d6543dSdrh   const char *zKey;
66125d6543dSdrh   int nKey;
66225d6543dSdrh   if( argc!=3 ){
66325d6543dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
66425d6543dSdrh        " FILENAME\"", 0);
66525d6543dSdrh     return TCL_ERROR;
66625d6543dSdrh   }
66725d6543dSdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
66825d6543dSdrh   zKey = argv[2];
66925d6543dSdrh   nKey = strlen(zKey);
67025d6543dSdrh   sqlite3_key(db, zKey, nKey);
67125d6543dSdrh #endif
67225d6543dSdrh   return TCL_OK;
67325d6543dSdrh }
67425d6543dSdrh 
67525d6543dSdrh /*
67625d6543dSdrh ** Usage:  sqlite3_rekey DB KEY
67725d6543dSdrh **
67825d6543dSdrh ** Change the codec key.
67925d6543dSdrh */
6807617e4a8Smistachkin static int SQLITE_TCLAPI test_rekey(
68125d6543dSdrh   void *NotUsed,
68225d6543dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
68325d6543dSdrh   int argc,              /* Number of arguments */
68425d6543dSdrh   char **argv            /* Text of each argument */
68525d6543dSdrh ){
686caffb1a5Sdrh #ifdef SQLITE_HAS_CODEC
6879bb575fdSdrh   sqlite3 *db;
68825d6543dSdrh   const char *zKey;
68925d6543dSdrh   int nKey;
69025d6543dSdrh   if( argc!=3 ){
69125d6543dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
69225d6543dSdrh        " FILENAME\"", 0);
69325d6543dSdrh     return TCL_ERROR;
69425d6543dSdrh   }
69525d6543dSdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
69625d6543dSdrh   zKey = argv[2];
69725d6543dSdrh   nKey = strlen(zKey);
69825d6543dSdrh   sqlite3_rekey(db, zKey, nKey);
69925d6543dSdrh #endif
70025d6543dSdrh   return TCL_OK;
70125d6543dSdrh }
70225d6543dSdrh 
70325d6543dSdrh /*
7046f8a503dSdanielk1977 ** Usage:  sqlite3_close DB
705d1bf3512Sdrh **
7066f8a503dSdanielk1977 ** Closes the database opened by sqlite3_open.
707d1bf3512Sdrh */
7087617e4a8Smistachkin static int SQLITE_TCLAPI sqlite_test_close(
709d1bf3512Sdrh   void *NotUsed,
710d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
711d1bf3512Sdrh   int argc,              /* Number of arguments */
712d1bf3512Sdrh   char **argv            /* Text of each argument */
713d1bf3512Sdrh ){
7149bb575fdSdrh   sqlite3 *db;
71596d81f99Sdanielk1977   int rc;
716d1bf3512Sdrh   if( argc!=2 ){
717d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
718d1bf3512Sdrh        " FILENAME\"", 0);
719d1bf3512Sdrh     return TCL_ERROR;
720d1bf3512Sdrh   }
721b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
72296d81f99Sdanielk1977   rc = sqlite3_close(db);
7234f0c5878Sdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
724d1bf3512Sdrh   return TCL_OK;
725d1bf3512Sdrh }
726d1bf3512Sdrh 
727d1bf3512Sdrh /*
728617dc860Sdan ** Usage:  sqlite3_close_v2 DB
729617dc860Sdan **
730617dc860Sdan ** Closes the database opened by sqlite3_open.
731617dc860Sdan */
7327617e4a8Smistachkin static int SQLITE_TCLAPI sqlite_test_close_v2(
733617dc860Sdan   void *NotUsed,
734617dc860Sdan   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
735617dc860Sdan   int argc,              /* Number of arguments */
736617dc860Sdan   char **argv            /* Text of each argument */
737617dc860Sdan ){
738617dc860Sdan   sqlite3 *db;
739617dc860Sdan   int rc;
740617dc860Sdan   if( argc!=2 ){
741617dc860Sdan     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
742617dc860Sdan        " FILENAME\"", 0);
743617dc860Sdan     return TCL_ERROR;
744617dc860Sdan   }
745617dc860Sdan   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
746617dc860Sdan   rc = sqlite3_close_v2(db);
747617dc860Sdan   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
748617dc860Sdan   return TCL_OK;
749617dc860Sdan }
750617dc860Sdan 
751617dc860Sdan /*
752c22bd47dSdrh ** Implementation of the x_coalesce() function.
753c22bd47dSdrh ** Return the first argument non-NULL argument.
754c22bd47dSdrh */
7554f0c5878Sdrh static void t1_ifnullFunc(
7564f0c5878Sdrh   sqlite3_context *context,
7574f0c5878Sdrh   int argc,
7584f0c5878Sdrh   sqlite3_value **argv
7594f0c5878Sdrh ){
760c22bd47dSdrh   int i;
761c22bd47dSdrh   for(i=0; i<argc; i++){
7629c054830Sdrh     if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){
7639310ef23Sdrh       int n = sqlite3_value_bytes(argv[i]);
76403d847eaSdrh       sqlite3_result_text(context, (char*)sqlite3_value_text(argv[i]),
7659310ef23Sdrh           n, SQLITE_TRANSIENT);
766c22bd47dSdrh       break;
767c22bd47dSdrh     }
768c22bd47dSdrh   }
769c22bd47dSdrh }
770c22bd47dSdrh 
771c22bd47dSdrh /*
772f0313813Sdrh ** These are test functions.    hex8() interprets its argument as
773f0313813Sdrh ** UTF8 and returns a hex encoding.  hex16le() interprets its argument
774f0313813Sdrh ** as UTF16le and returns a hex encoding.
775f0313813Sdrh */
776f0313813Sdrh static void hex8Func(sqlite3_context *p, int argc, sqlite3_value **argv){
777f0313813Sdrh   const unsigned char *z;
778f0313813Sdrh   int i;
779f0313813Sdrh   char zBuf[200];
780f0313813Sdrh   z = sqlite3_value_text(argv[0]);
781f0313813Sdrh   for(i=0; i<sizeof(zBuf)/2 - 2 && z[i]; i++){
78265545b59Sdrh     sqlite3_snprintf(sizeof(zBuf)-i*2, &zBuf[i*2], "%02x", z[i]);
783f0313813Sdrh   }
784f0313813Sdrh   zBuf[i*2] = 0;
785f0313813Sdrh   sqlite3_result_text(p, (char*)zBuf, -1, SQLITE_TRANSIENT);
786f0313813Sdrh }
787af30469dSdrh #ifndef SQLITE_OMIT_UTF16
788f0313813Sdrh static void hex16Func(sqlite3_context *p, int argc, sqlite3_value **argv){
789f0313813Sdrh   const unsigned short int *z;
790f0313813Sdrh   int i;
791f0313813Sdrh   char zBuf[400];
792f0313813Sdrh   z = sqlite3_value_text16(argv[0]);
793f0313813Sdrh   for(i=0; i<sizeof(zBuf)/4 - 4 && z[i]; i++){
79465545b59Sdrh     sqlite3_snprintf(sizeof(zBuf)-i*4, &zBuf[i*4],"%04x", z[i]&0xff);
795f0313813Sdrh   }
796f0313813Sdrh   zBuf[i*4] = 0;
797f0313813Sdrh   sqlite3_result_text(p, (char*)zBuf, -1, SQLITE_TRANSIENT);
798f0313813Sdrh }
799af30469dSdrh #endif
800f0313813Sdrh 
801f0313813Sdrh /*
802d1d9fc33Sdrh ** A structure into which to accumulate text.
803d1d9fc33Sdrh */
804d1d9fc33Sdrh struct dstr {
805d1d9fc33Sdrh   int nAlloc;  /* Space allocated */
806d1d9fc33Sdrh   int nUsed;   /* Space used */
807d1d9fc33Sdrh   char *z;     /* The space */
808d1d9fc33Sdrh };
809d1d9fc33Sdrh 
810d1d9fc33Sdrh /*
811d1d9fc33Sdrh ** Append text to a dstr
812d1d9fc33Sdrh */
813d1d9fc33Sdrh static void dstrAppend(struct dstr *p, const char *z, int divider){
81483cc1392Sdrh   int n = (int)strlen(z);
815d1d9fc33Sdrh   if( p->nUsed + n + 2 > p->nAlloc ){
816d1d9fc33Sdrh     char *zNew;
817d1d9fc33Sdrh     p->nAlloc = p->nAlloc*2 + n + 200;
81817435752Sdrh     zNew = sqlite3_realloc(p->z, p->nAlloc);
819d1d9fc33Sdrh     if( zNew==0 ){
82017435752Sdrh       sqlite3_free(p->z);
821d1d9fc33Sdrh       memset(p, 0, sizeof(*p));
822d1d9fc33Sdrh       return;
823d1d9fc33Sdrh     }
824d1d9fc33Sdrh     p->z = zNew;
825d1d9fc33Sdrh   }
826d1d9fc33Sdrh   if( divider && p->nUsed>0 ){
827d1d9fc33Sdrh     p->z[p->nUsed++] = divider;
828d1d9fc33Sdrh   }
829d1d9fc33Sdrh   memcpy(&p->z[p->nUsed], z, n+1);
830d1d9fc33Sdrh   p->nUsed += n;
831d1d9fc33Sdrh }
832d1d9fc33Sdrh 
833d1d9fc33Sdrh /*
8344adee20fSdanielk1977 ** Invoked for each callback from sqlite3ExecFunc
835d1d9fc33Sdrh */
836d1d9fc33Sdrh static int execFuncCallback(void *pData, int argc, char **argv, char **NotUsed){
837d1d9fc33Sdrh   struct dstr *p = (struct dstr*)pData;
838d1d9fc33Sdrh   int i;
839d1d9fc33Sdrh   for(i=0; i<argc; i++){
840d1d9fc33Sdrh     if( argv[i]==0 ){
841d1d9fc33Sdrh       dstrAppend(p, "NULL", ' ');
842d1d9fc33Sdrh     }else{
843d1d9fc33Sdrh       dstrAppend(p, argv[i], ' ');
844d1d9fc33Sdrh     }
845d1d9fc33Sdrh   }
846d1d9fc33Sdrh   return 0;
847d1d9fc33Sdrh }
848d1d9fc33Sdrh 
849d1d9fc33Sdrh /*
850e35ee196Sdanielk1977 ** Implementation of the x_sqlite_exec() function.  This function takes
851c22bd47dSdrh ** a single argument and attempts to execute that argument as SQL code.
8526cbe1f1bSdrh ** This is illegal and should set the SQLITE_MISUSE flag on the database.
853c22bd47dSdrh **
8546f8a503dSdanielk1977 ** 2004-Jan-07:  We have changed this to make it legal to call sqlite3_exec()
855d1d9fc33Sdrh ** from within a function call.
856d1d9fc33Sdrh **
857c22bd47dSdrh ** This routine simulates the effect of having two threads attempt to
858c22bd47dSdrh ** use the same database at the same time.
859c22bd47dSdrh */
86051ad0ecdSdanielk1977 static void sqlite3ExecFunc(
8610ae8b831Sdanielk1977   sqlite3_context *context,
86251ad0ecdSdanielk1977   int argc,
86351ad0ecdSdanielk1977   sqlite3_value **argv
86451ad0ecdSdanielk1977 ){
865d1d9fc33Sdrh   struct dstr x;
866d1d9fc33Sdrh   memset(&x, 0, sizeof(x));
8673752785fSdrh   (void)sqlite3_exec((sqlite3*)sqlite3_user_data(context),
86803d847eaSdrh       (char*)sqlite3_value_text(argv[0]),
869d1d9fc33Sdrh       execFuncCallback, &x, 0);
870d8123366Sdanielk1977   sqlite3_result_text(context, x.z, x.nUsed, SQLITE_TRANSIENT);
87117435752Sdrh   sqlite3_free(x.z);
872c22bd47dSdrh }
873c22bd47dSdrh 
874c22bd47dSdrh /*
875d7263927Sdanielk1977 ** Implementation of tkt2213func(), a scalar function that takes exactly
876d7263927Sdanielk1977 ** one argument. It has two interesting features:
877d7263927Sdanielk1977 **
878d7263927Sdanielk1977 ** * It calls sqlite3_value_text() 3 times on the argument sqlite3_value*.
879d7263927Sdanielk1977 **   If the three pointers returned are not the same an SQL error is raised.
880d7263927Sdanielk1977 **
88185b623f2Sdrh ** * Otherwise it returns a copy of the text representation of its
882d7263927Sdanielk1977 **   argument in such a way as the VDBE representation is a Mem* cell
883d7263927Sdanielk1977 **   with the MEM_Term flag clear.
884d7263927Sdanielk1977 **
885d7263927Sdanielk1977 ** Ticket #2213 can therefore be tested by evaluating the following
886d7263927Sdanielk1977 ** SQL expression:
887d7263927Sdanielk1977 **
888d7263927Sdanielk1977 **   tkt2213func(tkt2213func('a string'));
889d7263927Sdanielk1977 */
890d7263927Sdanielk1977 static void tkt2213Function(
891d7263927Sdanielk1977   sqlite3_context *context,
892d7263927Sdanielk1977   int argc,
893d7263927Sdanielk1977   sqlite3_value **argv
894d7263927Sdanielk1977 ){
895d7263927Sdanielk1977   int nText;
896d7263927Sdanielk1977   unsigned char const *zText1;
897d7263927Sdanielk1977   unsigned char const *zText2;
898d7263927Sdanielk1977   unsigned char const *zText3;
899d7263927Sdanielk1977 
900d7263927Sdanielk1977   nText = sqlite3_value_bytes(argv[0]);
901d7263927Sdanielk1977   zText1 = sqlite3_value_text(argv[0]);
902d7263927Sdanielk1977   zText2 = sqlite3_value_text(argv[0]);
903d7263927Sdanielk1977   zText3 = sqlite3_value_text(argv[0]);
904d7263927Sdanielk1977 
905d7263927Sdanielk1977   if( zText1!=zText2 || zText2!=zText3 ){
906d7263927Sdanielk1977     sqlite3_result_error(context, "tkt2213 is not fixed", -1);
907d7263927Sdanielk1977   }else{
908d7263927Sdanielk1977     char *zCopy = (char *)sqlite3_malloc(nText);
909d7263927Sdanielk1977     memcpy(zCopy, zText1, nText);
910d7263927Sdanielk1977     sqlite3_result_text(context, zCopy, nText, sqlite3_free);
911d7263927Sdanielk1977   }
912d7263927Sdanielk1977 }
913d7263927Sdanielk1977 
914d7263927Sdanielk1977 /*
9159310ef23Sdrh ** The following SQL function takes 4 arguments.  The 2nd and
9169310ef23Sdrh ** 4th argument must be one of these strings:  'text', 'text16',
9179310ef23Sdrh ** or 'blob' corresponding to API functions
9189310ef23Sdrh **
9199310ef23Sdrh **      sqlite3_value_text()
9209310ef23Sdrh **      sqlite3_value_text16()
9219310ef23Sdrh **      sqlite3_value_blob()
9229310ef23Sdrh **
9239310ef23Sdrh ** The third argument is a string, either 'bytes' or 'bytes16' or 'noop',
9249310ef23Sdrh ** corresponding to APIs:
9259310ef23Sdrh **
9269310ef23Sdrh **      sqlite3_value_bytes()
9279310ef23Sdrh **      sqlite3_value_bytes16()
9289310ef23Sdrh **      noop
9299310ef23Sdrh **
9309310ef23Sdrh ** The APIs designated by the 2nd through 4th arguments are applied
9319310ef23Sdrh ** to the first argument in order.  If the pointers returned by the
9329310ef23Sdrh ** second and fourth are different, this routine returns 1.  Otherwise,
9339310ef23Sdrh ** this routine returns 0.
9349310ef23Sdrh **
9359310ef23Sdrh ** This function is used to test to see when returned pointers from
9369310ef23Sdrh ** the _text(), _text16() and _blob() APIs become invalidated.
9379310ef23Sdrh */
9389310ef23Sdrh static void ptrChngFunction(
9399310ef23Sdrh   sqlite3_context *context,
9409310ef23Sdrh   int argc,
9419310ef23Sdrh   sqlite3_value **argv
9429310ef23Sdrh ){
9439310ef23Sdrh   const void *p1, *p2;
9449310ef23Sdrh   const char *zCmd;
9459310ef23Sdrh   if( argc!=4 ) return;
9469310ef23Sdrh   zCmd = (const char*)sqlite3_value_text(argv[1]);
9479310ef23Sdrh   if( zCmd==0 ) return;
9489310ef23Sdrh   if( strcmp(zCmd,"text")==0 ){
9499310ef23Sdrh     p1 = (const void*)sqlite3_value_text(argv[0]);
9509310ef23Sdrh #ifndef SQLITE_OMIT_UTF16
9519310ef23Sdrh   }else if( strcmp(zCmd, "text16")==0 ){
9529310ef23Sdrh     p1 = (const void*)sqlite3_value_text16(argv[0]);
9539310ef23Sdrh #endif
9549310ef23Sdrh   }else if( strcmp(zCmd, "blob")==0 ){
9559310ef23Sdrh     p1 = (const void*)sqlite3_value_blob(argv[0]);
9569310ef23Sdrh   }else{
9579310ef23Sdrh     return;
9589310ef23Sdrh   }
9599310ef23Sdrh   zCmd = (const char*)sqlite3_value_text(argv[2]);
9609310ef23Sdrh   if( zCmd==0 ) return;
9619310ef23Sdrh   if( strcmp(zCmd,"bytes")==0 ){
9629310ef23Sdrh     sqlite3_value_bytes(argv[0]);
9639310ef23Sdrh #ifndef SQLITE_OMIT_UTF16
9649310ef23Sdrh   }else if( strcmp(zCmd, "bytes16")==0 ){
9659310ef23Sdrh     sqlite3_value_bytes16(argv[0]);
9669310ef23Sdrh #endif
9679310ef23Sdrh   }else if( strcmp(zCmd, "noop")==0 ){
9689310ef23Sdrh     /* do nothing */
9699310ef23Sdrh   }else{
9709310ef23Sdrh     return;
9719310ef23Sdrh   }
9729310ef23Sdrh   zCmd = (const char*)sqlite3_value_text(argv[3]);
9739310ef23Sdrh   if( zCmd==0 ) return;
9749310ef23Sdrh   if( strcmp(zCmd,"text")==0 ){
9759310ef23Sdrh     p2 = (const void*)sqlite3_value_text(argv[0]);
9769310ef23Sdrh #ifndef SQLITE_OMIT_UTF16
9779310ef23Sdrh   }else if( strcmp(zCmd, "text16")==0 ){
9789310ef23Sdrh     p2 = (const void*)sqlite3_value_text16(argv[0]);
9799310ef23Sdrh #endif
9809310ef23Sdrh   }else if( strcmp(zCmd, "blob")==0 ){
9819310ef23Sdrh     p2 = (const void*)sqlite3_value_blob(argv[0]);
9829310ef23Sdrh   }else{
9839310ef23Sdrh     return;
9849310ef23Sdrh   }
9859310ef23Sdrh   sqlite3_result_int(context, p1!=p2);
9869310ef23Sdrh }
9879310ef23Sdrh 
9884a8ee3dfSdrh /*
9894a8ee3dfSdrh ** This SQL function returns a different answer each time it is called, even if
9904a8ee3dfSdrh ** the arguments are the same.
9914a8ee3dfSdrh */
9924a8ee3dfSdrh static void nondeterministicFunction(
9934a8ee3dfSdrh   sqlite3_context *context,
9944a8ee3dfSdrh   int argc,
9954a8ee3dfSdrh   sqlite3_value **argv
9964a8ee3dfSdrh ){
9974a8ee3dfSdrh   static int cnt = 0;
9984a8ee3dfSdrh   sqlite3_result_int(context, cnt++);
9994a8ee3dfSdrh }
10009310ef23Sdrh 
10019310ef23Sdrh /*
10024a8ee3dfSdrh ** Usage:  sqlite3_create_function DB
1003c22bd47dSdrh **
10046f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order
1005c22bd47dSdrh ** to create a function named "x_coalesce".  This function does the same thing
1006c22bd47dSdrh ** as the "coalesce" function.  This function also registers an SQL function
1007e35ee196Sdanielk1977 ** named "x_sqlite_exec" that invokes sqlite3_exec().  Invoking sqlite3_exec()
1008c22bd47dSdrh ** in this way is illegal recursion and should raise an SQLITE_MISUSE error.
1009c22bd47dSdrh ** The effect is similar to trying to use the same database connection from
1010c22bd47dSdrh ** two threads at the same time.
1011c22bd47dSdrh **
1012c22bd47dSdrh ** The original motivation for this routine was to be able to call the
10136f8a503dSdanielk1977 ** sqlite3_create_function function while a query is in progress in order
1014c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
1015c22bd47dSdrh */
10167617e4a8Smistachkin static int SQLITE_TCLAPI test_create_function(
1017c22bd47dSdrh   void *NotUsed,
1018c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1019c22bd47dSdrh   int argc,              /* Number of arguments */
1020c22bd47dSdrh   char **argv            /* Text of each argument */
1021c22bd47dSdrh ){
1022c60d0446Sdrh   int rc;
10239bb575fdSdrh   sqlite3 *db;
1024312d6b36Sdanielk1977 
1025c22bd47dSdrh   if( argc!=2 ){
1026c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
10274397de57Sdanielk1977        " DB\"", 0);
1028c22bd47dSdrh     return TCL_ERROR;
1029c22bd47dSdrh   }
1030b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
10314a8ee3dfSdrh   rc = sqlite3_create_function(db, "x_coalesce", -1, SQLITE_UTF8, 0,
10324f0c5878Sdrh         t1_ifnullFunc, 0, 0);
1033235a818eSdrh   if( rc==SQLITE_OK ){
10344a8ee3dfSdrh     rc = sqlite3_create_function(db, "hex8", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC,
10354a8ee3dfSdrh           0, hex8Func, 0, 0);
1036235a818eSdrh   }
1037af30469dSdrh #ifndef SQLITE_OMIT_UTF16
1038235a818eSdrh   if( rc==SQLITE_OK ){
10394a8ee3dfSdrh     rc = sqlite3_create_function(db, "hex16", 1, SQLITE_UTF16 | SQLITE_DETERMINISTIC,
10404a8ee3dfSdrh           0, hex16Func, 0, 0);
1041235a818eSdrh   }
1042af30469dSdrh #endif
1043d7263927Sdanielk1977   if( rc==SQLITE_OK ){
1044d7263927Sdanielk1977     rc = sqlite3_create_function(db, "tkt2213func", 1, SQLITE_ANY, 0,
1045d7263927Sdanielk1977           tkt2213Function, 0, 0);
1046d7263927Sdanielk1977   }
10479310ef23Sdrh   if( rc==SQLITE_OK ){
10489310ef23Sdrh     rc = sqlite3_create_function(db, "pointer_change", 4, SQLITE_ANY, 0,
10499310ef23Sdrh           ptrChngFunction, 0, 0);
10509310ef23Sdrh   }
1051312d6b36Sdanielk1977 
10524a8ee3dfSdrh   /* Functions counter1() and counter2() have the same implementation - they
10534a8ee3dfSdrh   ** both return an ascending integer with each call.  But counter1() is marked
10544a8ee3dfSdrh   ** as non-deterministic and counter2() is marked as deterministic.
10554a8ee3dfSdrh   */
10564a8ee3dfSdrh   if( rc==SQLITE_OK ){
10574a8ee3dfSdrh     rc = sqlite3_create_function(db, "counter1", -1, SQLITE_UTF8,
10584a8ee3dfSdrh           0, nondeterministicFunction, 0, 0);
10594a8ee3dfSdrh   }
10604a8ee3dfSdrh   if( rc==SQLITE_OK ){
10614a8ee3dfSdrh     rc = sqlite3_create_function(db, "counter2", -1, SQLITE_UTF8|SQLITE_DETERMINISTIC,
10624a8ee3dfSdrh           0, nondeterministicFunction, 0, 0);
10634a8ee3dfSdrh   }
10644a8ee3dfSdrh 
10655436dc2dSdrh #ifndef SQLITE_OMIT_UTF16
1066312d6b36Sdanielk1977   /* Use the sqlite3_create_function16() API here. Mainly for fun, but also
1067312d6b36Sdanielk1977   ** because it is not tested anywhere else. */
1068c60d0446Sdrh   if( rc==SQLITE_OK ){
1069eee4c8caSdrh     const void *zUtf16;
1070576ec6b3Sdanielk1977     sqlite3_value *pVal;
1071f3a65f7eSdrh     sqlite3_mutex_enter(db->mutex);
1072f3a65f7eSdrh     pVal = sqlite3ValueNew(db);
1073b21c8cd4Sdrh     sqlite3ValueSetStr(pVal, -1, "x_sqlite_exec", SQLITE_UTF8, SQLITE_STATIC);
1074a7a8e14bSdanielk1977     zUtf16 = sqlite3ValueText(pVal, SQLITE_UTF16NATIVE);
1075f3a65f7eSdrh     if( db->mallocFailed ){
1076f3a65f7eSdrh       rc = SQLITE_NOMEM;
1077f3a65f7eSdrh     }else{
1078a7a8e14bSdanielk1977       rc = sqlite3_create_function16(db, zUtf16,
1079312d6b36Sdanielk1977                 1, SQLITE_UTF16, db, sqlite3ExecFunc, 0, 0);
1080f3a65f7eSdrh     }
1081312d6b36Sdanielk1977     sqlite3ValueFree(pVal);
1082f3a65f7eSdrh     sqlite3_mutex_leave(db->mutex);
1083c60d0446Sdrh   }
10845436dc2dSdrh #endif
10855436dc2dSdrh 
1086c60d0446Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
10874f0c5878Sdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
1088c22bd47dSdrh   return TCL_OK;
1089c22bd47dSdrh }
1090c22bd47dSdrh 
1091c22bd47dSdrh /*
1092c22bd47dSdrh ** Routines to implement the x_count() aggregate function.
109390669c1dSdrh **
109490669c1dSdrh ** x_count() counts the number of non-null arguments.  But there are
109590669c1dSdrh ** some twists for testing purposes.
109690669c1dSdrh **
109790669c1dSdrh ** If the argument to x_count() is 40 then a UTF-8 error is reported
109890669c1dSdrh ** on the step function.  If x_count(41) is seen, then a UTF-16 error
109990669c1dSdrh ** is reported on the step function.  If the total count is 42, then
110090669c1dSdrh ** a UTF-8 error is reported on the finalize function.
1101c22bd47dSdrh */
11024f0c5878Sdrh typedef struct t1CountCtx t1CountCtx;
11034f0c5878Sdrh struct t1CountCtx {
1104c22bd47dSdrh   int n;
1105c22bd47dSdrh };
11064f0c5878Sdrh static void t1CountStep(
11074f0c5878Sdrh   sqlite3_context *context,
11084f0c5878Sdrh   int argc,
11094f0c5878Sdrh   sqlite3_value **argv
11104f0c5878Sdrh ){
11114f0c5878Sdrh   t1CountCtx *p;
11124f26d6c4Sdrh   p = sqlite3_aggregate_context(context, sizeof(*p));
11139c054830Sdrh   if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0]) ) && p ){
1114c22bd47dSdrh     p->n++;
1115c22bd47dSdrh   }
111690669c1dSdrh   if( argc>0 ){
111790669c1dSdrh     int v = sqlite3_value_int(argv[0]);
111890669c1dSdrh     if( v==40 ){
111990669c1dSdrh       sqlite3_result_error(context, "value of 40 handed to x_count", -1);
1120a1686c9aSdanielk1977 #ifndef SQLITE_OMIT_UTF16
112190669c1dSdrh     }else if( v==41 ){
112290669c1dSdrh       const char zUtf16ErrMsg[] = { 0, 0x61, 0, 0x62, 0, 0x63, 0, 0, 0};
112390669c1dSdrh       sqlite3_result_error16(context, &zUtf16ErrMsg[1-SQLITE_BIGENDIAN], -1);
1124a1686c9aSdanielk1977 #endif
112590669c1dSdrh     }
112690669c1dSdrh   }
1127c22bd47dSdrh }
11284f0c5878Sdrh static void t1CountFinalize(sqlite3_context *context){
11294f0c5878Sdrh   t1CountCtx *p;
11304f26d6c4Sdrh   p = sqlite3_aggregate_context(context, sizeof(*p));
113190669c1dSdrh   if( p ){
113290669c1dSdrh     if( p->n==42 ){
113390669c1dSdrh       sqlite3_result_error(context, "x_count totals to 42", -1);
113490669c1dSdrh     }else{
1135c572ef7fSdanielk1977       sqlite3_result_int(context, p ? p->n : 0);
1136c22bd47dSdrh     }
113790669c1dSdrh   }
113890669c1dSdrh }
1139c22bd47dSdrh 
1140c5512882Sdanielk1977 #ifndef SQLITE_OMIT_DEPRECATED
1141fa18beceSdanielk1977 static void legacyCountStep(
1142fa18beceSdanielk1977   sqlite3_context *context,
1143fa18beceSdanielk1977   int argc,
1144fa18beceSdanielk1977   sqlite3_value **argv
1145fa18beceSdanielk1977 ){
1146fa18beceSdanielk1977   /* no-op */
1147fa18beceSdanielk1977 }
1148eec556d3Sshane 
1149fa18beceSdanielk1977 static void legacyCountFinalize(sqlite3_context *context){
1150fa18beceSdanielk1977   sqlite3_result_int(context, sqlite3_aggregate_count(context));
1151fa18beceSdanielk1977 }
1152eec556d3Sshane #endif
1153fa18beceSdanielk1977 
1154c22bd47dSdrh /*
1155fa18beceSdanielk1977 ** Usage:  sqlite3_create_aggregate DB
1156c22bd47dSdrh **
11576f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order
1158fa18beceSdanielk1977 ** to create a function named "x_count".  This function is similar
1159fa18beceSdanielk1977 ** to the built-in count() function, with a few special quirks
1160fa18beceSdanielk1977 ** for testing the sqlite3_result_error() APIs.
1161c22bd47dSdrh **
1162c22bd47dSdrh ** The original motivation for this routine was to be able to call the
11636f8a503dSdanielk1977 ** sqlite3_create_aggregate function while a query is in progress in order
116490669c1dSdrh ** to test the SQLITE_MISUSE detection logic.  See misuse.test.
116590669c1dSdrh **
116690669c1dSdrh ** This routine was later extended to test the use of sqlite3_result_error()
116790669c1dSdrh ** within aggregate functions.
1168fa18beceSdanielk1977 **
1169fa18beceSdanielk1977 ** Later: It is now also extended to register the aggregate function
1170fa18beceSdanielk1977 ** "legacy_count()" with the supplied database handle. This is used
1171fa18beceSdanielk1977 ** to test the deprecated sqlite3_aggregate_count() API.
1172c22bd47dSdrh */
11737617e4a8Smistachkin static int SQLITE_TCLAPI test_create_aggregate(
1174c22bd47dSdrh   void *NotUsed,
1175c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1176c22bd47dSdrh   int argc,              /* Number of arguments */
1177c22bd47dSdrh   char **argv            /* Text of each argument */
1178c22bd47dSdrh ){
11799bb575fdSdrh   sqlite3 *db;
1180c60d0446Sdrh   int rc;
1181c22bd47dSdrh   if( argc!=2 ){
1182c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1183c22bd47dSdrh        " FILENAME\"", 0);
1184c22bd47dSdrh     return TCL_ERROR;
1185c22bd47dSdrh   }
1186b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
1187c60d0446Sdrh   rc = sqlite3_create_function(db, "x_count", 0, SQLITE_UTF8, 0, 0,
11884f0c5878Sdrh       t1CountStep,t1CountFinalize);
1189c60d0446Sdrh   if( rc==SQLITE_OK ){
1190fa18beceSdanielk1977     rc = sqlite3_create_function(db, "x_count", 1, SQLITE_UTF8, 0, 0,
11914f0c5878Sdrh         t1CountStep,t1CountFinalize);
1192c60d0446Sdrh   }
1193eec556d3Sshane #ifndef SQLITE_OMIT_DEPRECATED
1194fa18beceSdanielk1977   if( rc==SQLITE_OK ){
1195fa18beceSdanielk1977     rc = sqlite3_create_function(db, "legacy_count", 0, SQLITE_ANY, 0, 0,
1196fa18beceSdanielk1977         legacyCountStep, legacyCountFinalize
1197fa18beceSdanielk1977     );
1198fa18beceSdanielk1977   }
1199eec556d3Sshane #endif
1200c60d0446Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
1201fa18beceSdanielk1977   Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
1202c22bd47dSdrh   return TCL_OK;
1203c22bd47dSdrh }
1204c22bd47dSdrh 
1205c22bd47dSdrh 
12063c23a885Sdrh /*
12073c23a885Sdrh ** Usage:  printf TEXT
12083c23a885Sdrh **
12093c23a885Sdrh ** Send output to printf.  Use this rather than puts to merge the output
12103c23a885Sdrh ** in the correct sequence with debugging printfs inserted into C code.
12113c23a885Sdrh ** Puts uses a separate buffer and debugging statements will be out of
12123c23a885Sdrh ** sequence if it is used.
12133c23a885Sdrh */
12147617e4a8Smistachkin static int SQLITE_TCLAPI test_printf(
12153c23a885Sdrh   void *NotUsed,
12163c23a885Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
12173c23a885Sdrh   int argc,              /* Number of arguments */
12183c23a885Sdrh   char **argv            /* Text of each argument */
12193c23a885Sdrh ){
12203c23a885Sdrh   if( argc!=2 ){
12213c23a885Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
12223c23a885Sdrh        " TEXT\"", 0);
12233c23a885Sdrh     return TCL_ERROR;
12243c23a885Sdrh   }
12253c23a885Sdrh   printf("%s\n", argv[1]);
12263c23a885Sdrh   return TCL_OK;
12273c23a885Sdrh }
12283c23a885Sdrh 
12293c23a885Sdrh 
1230c22bd47dSdrh 
1231c22bd47dSdrh /*
12326f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER
1233d1bf3512Sdrh **
1234d1bf3512Sdrh ** Call mprintf with three integer arguments
1235d1bf3512Sdrh */
12367617e4a8Smistachkin static int SQLITE_TCLAPI sqlite3_mprintf_int(
1237d1bf3512Sdrh   void *NotUsed,
1238d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1239d1bf3512Sdrh   int argc,              /* Number of arguments */
1240d1bf3512Sdrh   char **argv            /* Text of each argument */
1241d1bf3512Sdrh ){
1242d1bf3512Sdrh   int a[3], i;
1243d1bf3512Sdrh   char *z;
1244d1bf3512Sdrh   if( argc!=5 ){
1245d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1246d1bf3512Sdrh        " FORMAT INT INT INT\"", 0);
1247d1bf3512Sdrh     return TCL_ERROR;
1248d1bf3512Sdrh   }
1249d1bf3512Sdrh   for(i=2; i<5; i++){
1250d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
1251d1bf3512Sdrh   }
12526f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]);
1253d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
12543f4fedb2Sdrh   sqlite3_free(z);
1255d1bf3512Sdrh   return TCL_OK;
1256d1bf3512Sdrh }
1257d1bf3512Sdrh 
1258d1bf3512Sdrh /*
1259e9707671Sdrh ** Usage:  sqlite3_mprintf_int64 FORMAT INTEGER INTEGER INTEGER
1260e9707671Sdrh **
1261e9707671Sdrh ** Call mprintf with three 64-bit integer arguments
1262e9707671Sdrh */
12637617e4a8Smistachkin static int SQLITE_TCLAPI sqlite3_mprintf_int64(
1264e9707671Sdrh   void *NotUsed,
1265e9707671Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1266e9707671Sdrh   int argc,              /* Number of arguments */
1267e9707671Sdrh   char **argv            /* Text of each argument */
1268e9707671Sdrh ){
1269e9707671Sdrh   int i;
1270e9707671Sdrh   sqlite_int64 a[3];
1271e9707671Sdrh   char *z;
1272e9707671Sdrh   if( argc!=5 ){
1273e9707671Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1274e9707671Sdrh        " FORMAT INT INT INT\"", 0);
1275e9707671Sdrh     return TCL_ERROR;
1276e9707671Sdrh   }
1277e9707671Sdrh   for(i=2; i<5; i++){
1278609d5846Sdrh     if( sqlite3Atoi64(argv[i], &a[i-2], sqlite3Strlen30(argv[i]), SQLITE_UTF8) ){
1279e9707671Sdrh       Tcl_AppendResult(interp, "argument is not a valid 64-bit integer", 0);
1280e9707671Sdrh       return TCL_ERROR;
1281e9707671Sdrh     }
1282e9707671Sdrh   }
1283e9707671Sdrh   z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]);
1284e9707671Sdrh   Tcl_AppendResult(interp, z, 0);
1285e9707671Sdrh   sqlite3_free(z);
1286e9707671Sdrh   return TCL_OK;
1287e9707671Sdrh }
1288e9707671Sdrh 
1289e9707671Sdrh /*
1290c5cad1e3Sdrh ** Usage:  sqlite3_mprintf_long FORMAT INTEGER INTEGER INTEGER
1291c5cad1e3Sdrh **
1292c5cad1e3Sdrh ** Call mprintf with three long integer arguments.   This might be the
1293c5cad1e3Sdrh ** same as sqlite3_mprintf_int or sqlite3_mprintf_int64, depending on
1294c5cad1e3Sdrh ** platform.
1295c5cad1e3Sdrh */
12967617e4a8Smistachkin static int SQLITE_TCLAPI sqlite3_mprintf_long(
1297c5cad1e3Sdrh   void *NotUsed,
1298c5cad1e3Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1299c5cad1e3Sdrh   int argc,              /* Number of arguments */
1300c5cad1e3Sdrh   char **argv            /* Text of each argument */
1301c5cad1e3Sdrh ){
1302c5cad1e3Sdrh   int i;
1303c5cad1e3Sdrh   long int a[3];
1304c5cad1e3Sdrh   int b[3];
1305c5cad1e3Sdrh   char *z;
1306c5cad1e3Sdrh   if( argc!=5 ){
1307c5cad1e3Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1308c5cad1e3Sdrh        " FORMAT INT INT INT\"", 0);
1309c5cad1e3Sdrh     return TCL_ERROR;
1310c5cad1e3Sdrh   }
1311c5cad1e3Sdrh   for(i=2; i<5; i++){
1312c5cad1e3Sdrh     if( Tcl_GetInt(interp, argv[i], &b[i-2]) ) return TCL_ERROR;
1313c5cad1e3Sdrh     a[i-2] = (long int)b[i-2];
13147ed0cae2Sdrh     a[i-2] &= (((u64)1)<<(sizeof(int)*8))-1;
1315c5cad1e3Sdrh   }
1316c5cad1e3Sdrh   z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]);
1317c5cad1e3Sdrh   Tcl_AppendResult(interp, z, 0);
1318c5cad1e3Sdrh   sqlite3_free(z);
1319c5cad1e3Sdrh   return TCL_OK;
1320c5cad1e3Sdrh }
1321c5cad1e3Sdrh 
1322c5cad1e3Sdrh /*
13236f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT INTEGER INTEGER STRING
1324d1bf3512Sdrh **
1325d1bf3512Sdrh ** Call mprintf with two integer arguments and one string argument
1326d1bf3512Sdrh */
13277617e4a8Smistachkin static int SQLITE_TCLAPI sqlite3_mprintf_str(
1328d1bf3512Sdrh   void *NotUsed,
1329d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1330d1bf3512Sdrh   int argc,              /* Number of arguments */
1331d1bf3512Sdrh   char **argv            /* Text of each argument */
1332d1bf3512Sdrh ){
1333d1bf3512Sdrh   int a[3], i;
1334d1bf3512Sdrh   char *z;
1335f220b24fSchw   if( argc<4 || argc>5 ){
1336d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1337f220b24fSchw        " FORMAT INT INT ?STRING?\"", 0);
1338d1bf3512Sdrh     return TCL_ERROR;
1339d1bf3512Sdrh   }
1340d1bf3512Sdrh   for(i=2; i<4; i++){
1341d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
1342d1bf3512Sdrh   }
13436f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL);
1344d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
13453f4fedb2Sdrh   sqlite3_free(z);
1346d1bf3512Sdrh   return TCL_OK;
1347d1bf3512Sdrh }
1348d1bf3512Sdrh 
1349d1bf3512Sdrh /*
1350b3738b6cSdrh ** Usage:  sqlite3_snprintf_str INTEGER FORMAT INTEGER INTEGER STRING
1351b3738b6cSdrh **
1352b3738b6cSdrh ** Call mprintf with two integer arguments and one string argument
1353b3738b6cSdrh */
13547617e4a8Smistachkin static int SQLITE_TCLAPI sqlite3_snprintf_str(
1355b3738b6cSdrh   void *NotUsed,
1356b3738b6cSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1357b3738b6cSdrh   int argc,              /* Number of arguments */
1358b3738b6cSdrh   char **argv            /* Text of each argument */
1359b3738b6cSdrh ){
1360b3738b6cSdrh   int a[3], i;
1361b3738b6cSdrh   int n;
1362b3738b6cSdrh   char *z;
1363b3738b6cSdrh   if( argc<5 || argc>6 ){
1364b3738b6cSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1365b3738b6cSdrh        " INT FORMAT INT INT ?STRING?\"", 0);
1366b3738b6cSdrh     return TCL_ERROR;
1367b3738b6cSdrh   }
1368b3738b6cSdrh   if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
1369b3738b6cSdrh   if( n<0 ){
1370b3738b6cSdrh     Tcl_AppendResult(interp, "N must be non-negative", 0);
1371b3738b6cSdrh     return TCL_ERROR;
1372b3738b6cSdrh   }
1373b3738b6cSdrh   for(i=3; i<5; i++){
1374b3738b6cSdrh     if( Tcl_GetInt(interp, argv[i], &a[i-3]) ) return TCL_ERROR;
1375b3738b6cSdrh   }
1376b3738b6cSdrh   z = sqlite3_malloc( n+1 );
1377b3738b6cSdrh   sqlite3_snprintf(n, z, argv[2], a[0], a[1], argc>4 ? argv[5] : NULL);
1378b3738b6cSdrh   Tcl_AppendResult(interp, z, 0);
1379b3738b6cSdrh   sqlite3_free(z);
1380b3738b6cSdrh   return TCL_OK;
1381b3738b6cSdrh }
1382b3738b6cSdrh 
1383b3738b6cSdrh /*
138463782855Sdrh ** Usage:  sqlite3_mprintf_double FORMAT INTEGER INTEGER DOUBLE
1385d1bf3512Sdrh **
1386d1bf3512Sdrh ** Call mprintf with two integer arguments and one double argument
1387d1bf3512Sdrh */
13887617e4a8Smistachkin static int SQLITE_TCLAPI sqlite3_mprintf_double(
1389d1bf3512Sdrh   void *NotUsed,
1390d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1391d1bf3512Sdrh   int argc,              /* Number of arguments */
1392d1bf3512Sdrh   char **argv            /* Text of each argument */
1393d1bf3512Sdrh ){
1394d1bf3512Sdrh   int a[3], i;
1395d1bf3512Sdrh   double r;
1396d1bf3512Sdrh   char *z;
1397d1bf3512Sdrh   if( argc!=5 ){
1398d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
139963782855Sdrh        " FORMAT INT INT DOUBLE\"", 0);
1400d1bf3512Sdrh     return TCL_ERROR;
1401d1bf3512Sdrh   }
1402d1bf3512Sdrh   for(i=2; i<4; i++){
1403d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
1404d1bf3512Sdrh   }
1405d1bf3512Sdrh   if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR;
14066f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], r);
1407d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
14083f4fedb2Sdrh   sqlite3_free(z);
1409d1bf3512Sdrh   return TCL_OK;
1410d1bf3512Sdrh }
1411d1bf3512Sdrh 
1412d1bf3512Sdrh /*
141363782855Sdrh ** Usage:  sqlite3_mprintf_scaled FORMAT DOUBLE DOUBLE
1414b621c237Sdrh **
1415b621c237Sdrh ** Call mprintf with a single double argument which is the product of the
1416b621c237Sdrh ** two arguments given above.  This is used to generate overflow and underflow
1417b621c237Sdrh ** doubles to test that they are converted properly.
1418b621c237Sdrh */
14197617e4a8Smistachkin static int SQLITE_TCLAPI sqlite3_mprintf_scaled(
1420b621c237Sdrh   void *NotUsed,
1421b621c237Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1422b621c237Sdrh   int argc,              /* Number of arguments */
1423b621c237Sdrh   char **argv            /* Text of each argument */
1424b621c237Sdrh ){
1425b621c237Sdrh   int i;
1426b621c237Sdrh   double r[2];
1427b621c237Sdrh   char *z;
1428b621c237Sdrh   if( argc!=4 ){
1429b621c237Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1430b621c237Sdrh        " FORMAT DOUBLE DOUBLE\"", 0);
1431b621c237Sdrh     return TCL_ERROR;
1432b621c237Sdrh   }
1433b621c237Sdrh   for(i=2; i<4; i++){
1434b621c237Sdrh     if( Tcl_GetDouble(interp, argv[i], &r[i-2]) ) return TCL_ERROR;
1435b621c237Sdrh   }
14366f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], r[0]*r[1]);
1437b621c237Sdrh   Tcl_AppendResult(interp, z, 0);
14383f4fedb2Sdrh   sqlite3_free(z);
1439b621c237Sdrh   return TCL_OK;
1440b621c237Sdrh }
1441b621c237Sdrh 
1442b621c237Sdrh /*
1443e29b1a05Sdrh ** Usage:  sqlite3_mprintf_stronly FORMAT STRING
1444e29b1a05Sdrh **
1445e29b1a05Sdrh ** Call mprintf with a single double argument which is the product of the
1446e29b1a05Sdrh ** two arguments given above.  This is used to generate overflow and underflow
1447e29b1a05Sdrh ** doubles to test that they are converted properly.
1448e29b1a05Sdrh */
14497617e4a8Smistachkin static int SQLITE_TCLAPI sqlite3_mprintf_stronly(
1450e29b1a05Sdrh   void *NotUsed,
1451e29b1a05Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1452e29b1a05Sdrh   int argc,              /* Number of arguments */
1453e29b1a05Sdrh   char **argv            /* Text of each argument */
1454e29b1a05Sdrh ){
1455e29b1a05Sdrh   char *z;
1456e29b1a05Sdrh   if( argc!=3 ){
1457e29b1a05Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1458e29b1a05Sdrh        " FORMAT STRING\"", 0);
1459e29b1a05Sdrh     return TCL_ERROR;
1460e29b1a05Sdrh   }
1461e29b1a05Sdrh   z = sqlite3_mprintf(argv[1], argv[2]);
1462e29b1a05Sdrh   Tcl_AppendResult(interp, z, 0);
1463e29b1a05Sdrh   sqlite3_free(z);
1464e29b1a05Sdrh   return TCL_OK;
1465e29b1a05Sdrh }
1466e29b1a05Sdrh 
1467e29b1a05Sdrh /*
146863782855Sdrh ** Usage:  sqlite3_mprintf_hexdouble FORMAT HEX
146963782855Sdrh **
147063782855Sdrh ** Call mprintf with a single double argument which is derived from the
147163782855Sdrh ** hexadecimal encoding of an IEEE double.
147263782855Sdrh */
14737617e4a8Smistachkin static int SQLITE_TCLAPI sqlite3_mprintf_hexdouble(
147463782855Sdrh   void *NotUsed,
147563782855Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
147663782855Sdrh   int argc,              /* Number of arguments */
147763782855Sdrh   char **argv            /* Text of each argument */
147863782855Sdrh ){
147963782855Sdrh   char *z;
148063782855Sdrh   double r;
14815e73db36Sshane   unsigned int x1, x2;
14825e73db36Sshane   sqlite_uint64 d;
148363782855Sdrh   if( argc!=3 ){
148463782855Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
148563782855Sdrh        " FORMAT STRING\"", 0);
148663782855Sdrh     return TCL_ERROR;
148763782855Sdrh   }
148863782855Sdrh   if( sscanf(argv[2], "%08x%08x", &x2, &x1)!=2 ){
148963782855Sdrh     Tcl_AppendResult(interp, "2nd argument should be 16-characters of hex", 0);
149063782855Sdrh     return TCL_ERROR;
149163782855Sdrh   }
149263782855Sdrh   d = x2;
149363782855Sdrh   d = (d<<32) + x1;
149463782855Sdrh   memcpy(&r, &d, sizeof(r));
149563782855Sdrh   z = sqlite3_mprintf(argv[1], r);
149663782855Sdrh   Tcl_AppendResult(interp, z, 0);
149763782855Sdrh   sqlite3_free(z);
149863782855Sdrh   return TCL_OK;
149963782855Sdrh }
150063782855Sdrh 
150163782855Sdrh /*
1502c1def3e0Sdanielk1977 ** Usage: sqlite3_enable_shared_cache ?BOOLEAN?
1503aef0bf64Sdanielk1977 **
1504aef0bf64Sdanielk1977 */
15056f7adc8aSdrh #if !defined(SQLITE_OMIT_SHARED_CACHE)
15067617e4a8Smistachkin static int SQLITE_TCLAPI test_enable_shared(
150752622828Sdanielk1977   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
1508aef0bf64Sdanielk1977   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1509aef0bf64Sdanielk1977   int objc,              /* Number of arguments */
1510aef0bf64Sdanielk1977   Tcl_Obj *CONST objv[]  /* Command arguments */
1511aef0bf64Sdanielk1977 ){
1512aef0bf64Sdanielk1977   int rc;
1513aef0bf64Sdanielk1977   int enable;
151452622828Sdanielk1977   int ret = 0;
1515aef0bf64Sdanielk1977 
1516c1def3e0Sdanielk1977   if( objc!=2 && objc!=1 ){
1517c1def3e0Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "?BOOLEAN?");
1518aef0bf64Sdanielk1977     return TCL_ERROR;
1519aef0bf64Sdanielk1977   }
1520502b4e00Sdanielk1977   ret = sqlite3GlobalConfig.sharedCacheEnabled;
1521c1def3e0Sdanielk1977 
1522c1def3e0Sdanielk1977   if( objc==2 ){
1523c1def3e0Sdanielk1977     if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ){
1524c1def3e0Sdanielk1977       return TCL_ERROR;
1525c1def3e0Sdanielk1977     }
15266f7adc8aSdrh     rc = sqlite3_enable_shared_cache(enable);
1527aef0bf64Sdanielk1977     if( rc!=SQLITE_OK ){
1528aef0bf64Sdanielk1977       Tcl_SetResult(interp, (char *)sqlite3ErrStr(rc), TCL_STATIC);
1529aef0bf64Sdanielk1977       return TCL_ERROR;
1530aef0bf64Sdanielk1977     }
1531c1def3e0Sdanielk1977   }
153252622828Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewBooleanObj(ret));
1533aef0bf64Sdanielk1977   return TCL_OK;
1534aef0bf64Sdanielk1977 }
1535aef0bf64Sdanielk1977 #endif
1536aef0bf64Sdanielk1977 
153716a9b836Sdrh 
153816a9b836Sdrh 
1539aef0bf64Sdanielk1977 /*
15404ac285a1Sdrh ** Usage: sqlite3_extended_result_codes   DB    BOOLEAN
15414ac285a1Sdrh **
15424ac285a1Sdrh */
15437617e4a8Smistachkin static int SQLITE_TCLAPI test_extended_result_codes(
15444ac285a1Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
15454ac285a1Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
15464ac285a1Sdrh   int objc,              /* Number of arguments */
15474ac285a1Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
15484ac285a1Sdrh ){
15494ac285a1Sdrh   int enable;
15504ac285a1Sdrh   sqlite3 *db;
15514ac285a1Sdrh 
15524ac285a1Sdrh   if( objc!=3 ){
15534ac285a1Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB BOOLEAN");
15544ac285a1Sdrh     return TCL_ERROR;
15554ac285a1Sdrh   }
15564ac285a1Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
15574ac285a1Sdrh   if( Tcl_GetBooleanFromObj(interp, objv[2], &enable) ) return TCL_ERROR;
15584ac285a1Sdrh   sqlite3_extended_result_codes(db, enable);
15594ac285a1Sdrh   return TCL_OK;
15604ac285a1Sdrh }
15614ac285a1Sdrh 
15624ac285a1Sdrh /*
1563161fb796Sdanielk1977 ** Usage: sqlite3_libversion_number
1564161fb796Sdanielk1977 **
1565161fb796Sdanielk1977 */
15667617e4a8Smistachkin static int SQLITE_TCLAPI test_libversion_number(
1567161fb796Sdanielk1977   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
1568161fb796Sdanielk1977   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1569161fb796Sdanielk1977   int objc,              /* Number of arguments */
1570161fb796Sdanielk1977   Tcl_Obj *CONST objv[]  /* Command arguments */
1571161fb796Sdanielk1977 ){
1572161fb796Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_libversion_number()));
1573161fb796Sdanielk1977   return TCL_OK;
1574161fb796Sdanielk1977 }
1575161fb796Sdanielk1977 
1576161fb796Sdanielk1977 /*
1577deb802cdSdanielk1977 ** Usage: sqlite3_table_column_metadata DB dbname tblname colname
1578deb802cdSdanielk1977 **
1579deb802cdSdanielk1977 */
15807617e4a8Smistachkin static int SQLITE_TCLAPI test_table_column_metadata(
1581deb802cdSdanielk1977   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
1582deb802cdSdanielk1977   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1583deb802cdSdanielk1977   int objc,              /* Number of arguments */
1584deb802cdSdanielk1977   Tcl_Obj *CONST objv[]  /* Command arguments */
1585deb802cdSdanielk1977 ){
1586deb802cdSdanielk1977   sqlite3 *db;
1587deb802cdSdanielk1977   const char *zDb;
1588deb802cdSdanielk1977   const char *zTbl;
1589deb802cdSdanielk1977   const char *zCol;
1590deb802cdSdanielk1977   int rc;
1591deb802cdSdanielk1977   Tcl_Obj *pRet;
1592deb802cdSdanielk1977 
1593deb802cdSdanielk1977   const char *zDatatype;
1594deb802cdSdanielk1977   const char *zCollseq;
1595deb802cdSdanielk1977   int notnull;
1596deb802cdSdanielk1977   int primarykey;
1597deb802cdSdanielk1977   int autoincrement;
1598deb802cdSdanielk1977 
159945d1b206Sdrh   if( objc!=5 && objc!=4 ){
1600deb802cdSdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "DB dbname tblname colname");
1601deb802cdSdanielk1977     return TCL_ERROR;
1602deb802cdSdanielk1977   }
1603deb802cdSdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1604deb802cdSdanielk1977   zDb = Tcl_GetString(objv[2]);
1605deb802cdSdanielk1977   zTbl = Tcl_GetString(objv[3]);
160645d1b206Sdrh   zCol = objc==5 ? Tcl_GetString(objv[4]) : 0;
1607deb802cdSdanielk1977 
1608deb802cdSdanielk1977   if( strlen(zDb)==0 ) zDb = 0;
1609deb802cdSdanielk1977 
1610deb802cdSdanielk1977   rc = sqlite3_table_column_metadata(db, zDb, zTbl, zCol,
1611deb802cdSdanielk1977       &zDatatype, &zCollseq, &notnull, &primarykey, &autoincrement);
1612deb802cdSdanielk1977 
1613deb802cdSdanielk1977   if( rc!=SQLITE_OK ){
1614deb802cdSdanielk1977     Tcl_AppendResult(interp, sqlite3_errmsg(db), 0);
1615deb802cdSdanielk1977     return TCL_ERROR;
1616deb802cdSdanielk1977   }
1617deb802cdSdanielk1977 
1618deb802cdSdanielk1977   pRet = Tcl_NewObj();
1619deb802cdSdanielk1977   Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zDatatype, -1));
1620deb802cdSdanielk1977   Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zCollseq, -1));
1621deb802cdSdanielk1977   Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(notnull));
1622deb802cdSdanielk1977   Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(primarykey));
1623deb802cdSdanielk1977   Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(autoincrement));
1624deb802cdSdanielk1977   Tcl_SetObjResult(interp, pRet);
1625deb802cdSdanielk1977 
1626deb802cdSdanielk1977   return TCL_OK;
1627deb802cdSdanielk1977 }
1628deb802cdSdanielk1977 
1629dcbb5d3fSdanielk1977 #ifndef SQLITE_OMIT_INCRBLOB
1630dcbb5d3fSdanielk1977 
16317617e4a8Smistachkin static int SQLITE_TCLAPI blobHandleFromObj(
163261c7f59cSdan   Tcl_Interp *interp,
163361c7f59cSdan   Tcl_Obj *pObj,
163461c7f59cSdan   sqlite3_blob **ppBlob
163561c7f59cSdan ){
163661c7f59cSdan   char *z;
163761c7f59cSdan   int n;
163861c7f59cSdan 
163961c7f59cSdan   z = Tcl_GetStringFromObj(pObj, &n);
164061c7f59cSdan   if( n==0 ){
164161c7f59cSdan     *ppBlob = 0;
164261c7f59cSdan   }else{
164361c7f59cSdan     int notUsed;
164461c7f59cSdan     Tcl_Channel channel;
164561c7f59cSdan     ClientData instanceData;
164661c7f59cSdan 
164761c7f59cSdan     channel = Tcl_GetChannel(interp, z, &notUsed);
164861c7f59cSdan     if( !channel ) return TCL_ERROR;
164961c7f59cSdan 
165061c7f59cSdan     Tcl_Flush(channel);
165161c7f59cSdan     Tcl_Seek(channel, 0, SEEK_SET);
165261c7f59cSdan 
165361c7f59cSdan     instanceData = Tcl_GetChannelInstanceData(channel);
165461c7f59cSdan     *ppBlob = *((sqlite3_blob **)instanceData);
165561c7f59cSdan   }
165661c7f59cSdan 
165761c7f59cSdan   return TCL_OK;
165861c7f59cSdan }
165961c7f59cSdan 
16607617e4a8Smistachkin static int SQLITE_TCLAPI test_blob_reopen(
16614e76cc36Sdan   ClientData clientData, /* Not used */
16624e76cc36Sdan   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
16634e76cc36Sdan   int objc,              /* Number of arguments */
16644e76cc36Sdan   Tcl_Obj *CONST objv[]  /* Command arguments */
16654e76cc36Sdan ){
16664e76cc36Sdan   Tcl_WideInt iRowid;
16674e76cc36Sdan   sqlite3_blob *pBlob;
16684e76cc36Sdan   int rc;
16694e76cc36Sdan 
16704e76cc36Sdan   if( objc!=3 ){
16714e76cc36Sdan     Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL ROWID");
16724e76cc36Sdan     return TCL_ERROR;
16734e76cc36Sdan   }
16744e76cc36Sdan 
167561c7f59cSdan   if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR;
167661c7f59cSdan   if( Tcl_GetWideIntFromObj(interp, objv[2], &iRowid) ) return TCL_ERROR;
16774e76cc36Sdan 
16784e76cc36Sdan   rc = sqlite3_blob_reopen(pBlob, iRowid);
16794e76cc36Sdan   if( rc!=SQLITE_OK ){
1680e84d8d32Smistachkin     Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
16814e76cc36Sdan   }
16824e76cc36Sdan 
16834e76cc36Sdan   return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR);
16844e76cc36Sdan }
16854e76cc36Sdan 
1686dcbb5d3fSdanielk1977 #endif
1687c2e87a3eSdrh 
1688deb802cdSdanielk1977 /*
1689a393c036Sdanielk1977 ** Usage: sqlite3_create_collation_v2 DB-HANDLE NAME CMP-PROC DEL-PROC
1690a9808b31Sdanielk1977 **
1691a9808b31Sdanielk1977 **   This Tcl proc is used for testing the experimental
1692a393c036Sdanielk1977 **   sqlite3_create_collation_v2() interface.
1693a9808b31Sdanielk1977 */
1694a9808b31Sdanielk1977 struct TestCollationX {
1695a9808b31Sdanielk1977   Tcl_Interp *interp;
1696a9808b31Sdanielk1977   Tcl_Obj *pCmp;
1697a9808b31Sdanielk1977   Tcl_Obj *pDel;
1698a9808b31Sdanielk1977 };
1699a9808b31Sdanielk1977 typedef struct TestCollationX TestCollationX;
1700a9808b31Sdanielk1977 static void testCreateCollationDel(void *pCtx){
1701a9808b31Sdanielk1977   TestCollationX *p = (TestCollationX *)pCtx;
1702a9808b31Sdanielk1977 
1703a9808b31Sdanielk1977   int rc = Tcl_EvalObjEx(p->interp, p->pDel, TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL);
1704a9808b31Sdanielk1977   if( rc!=TCL_OK ){
1705a9808b31Sdanielk1977     Tcl_BackgroundError(p->interp);
1706a9808b31Sdanielk1977   }
1707a9808b31Sdanielk1977 
1708a9808b31Sdanielk1977   Tcl_DecrRefCount(p->pCmp);
1709a9808b31Sdanielk1977   Tcl_DecrRefCount(p->pDel);
1710a9808b31Sdanielk1977   sqlite3_free((void *)p);
1711a9808b31Sdanielk1977 }
1712a9808b31Sdanielk1977 static int testCreateCollationCmp(
1713a9808b31Sdanielk1977   void *pCtx,
1714a9808b31Sdanielk1977   int nLeft,
1715a9808b31Sdanielk1977   const void *zLeft,
1716a9808b31Sdanielk1977   int nRight,
1717a9808b31Sdanielk1977   const void *zRight
1718a9808b31Sdanielk1977 ){
1719a9808b31Sdanielk1977   TestCollationX *p = (TestCollationX *)pCtx;
1720a9808b31Sdanielk1977   Tcl_Obj *pScript = Tcl_DuplicateObj(p->pCmp);
1721a9808b31Sdanielk1977   int iRes = 0;
1722a9808b31Sdanielk1977 
1723a9808b31Sdanielk1977   Tcl_IncrRefCount(pScript);
1724a9808b31Sdanielk1977   Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj((char *)zLeft, nLeft));
1725a9808b31Sdanielk1977   Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj((char *)zRight,nRight));
1726a9808b31Sdanielk1977 
1727a9808b31Sdanielk1977   if( TCL_OK!=Tcl_EvalObjEx(p->interp, pScript, TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL)
1728a9808b31Sdanielk1977    || TCL_OK!=Tcl_GetIntFromObj(p->interp, Tcl_GetObjResult(p->interp), &iRes)
1729a9808b31Sdanielk1977   ){
1730a9808b31Sdanielk1977     Tcl_BackgroundError(p->interp);
1731a9808b31Sdanielk1977   }
1732a9808b31Sdanielk1977   Tcl_DecrRefCount(pScript);
1733a9808b31Sdanielk1977 
1734a9808b31Sdanielk1977   return iRes;
1735a9808b31Sdanielk1977 }
17367617e4a8Smistachkin static int SQLITE_TCLAPI test_create_collation_v2(
1737a9808b31Sdanielk1977   ClientData clientData, /* Not used */
1738a9808b31Sdanielk1977   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1739a9808b31Sdanielk1977   int objc,              /* Number of arguments */
1740a9808b31Sdanielk1977   Tcl_Obj *CONST objv[]  /* Command arguments */
1741a9808b31Sdanielk1977 ){
1742a9808b31Sdanielk1977   TestCollationX *p;
1743a9808b31Sdanielk1977   sqlite3 *db;
1744d55d57edSdrh   int rc;
1745a9808b31Sdanielk1977 
1746a9808b31Sdanielk1977   if( objc!=5 ){
1747a9808b31Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "DB-HANDLE NAME CMP-PROC DEL-PROC");
1748a9808b31Sdanielk1977     return TCL_ERROR;
1749a9808b31Sdanielk1977   }
1750a9808b31Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1751a9808b31Sdanielk1977 
1752a9808b31Sdanielk1977   p = (TestCollationX *)sqlite3_malloc(sizeof(TestCollationX));
1753a9808b31Sdanielk1977   p->pCmp = objv[3];
1754a9808b31Sdanielk1977   p->pDel = objv[4];
1755a9808b31Sdanielk1977   p->interp = interp;
1756a9808b31Sdanielk1977   Tcl_IncrRefCount(p->pCmp);
1757a9808b31Sdanielk1977   Tcl_IncrRefCount(p->pDel);
1758a9808b31Sdanielk1977 
1759d55d57edSdrh   rc = sqlite3_create_collation_v2(db, Tcl_GetString(objv[2]), 16,
1760d55d57edSdrh       (void *)p, testCreateCollationCmp, testCreateCollationDel
1761d55d57edSdrh   );
1762d55d57edSdrh   if( rc!=SQLITE_MISUSE ){
1763d55d57edSdrh     Tcl_AppendResult(interp, "sqlite3_create_collate_v2() failed to detect "
1764d55d57edSdrh       "an invalid encoding", (char*)0);
1765d55d57edSdrh     return TCL_ERROR;
1766d55d57edSdrh   }
1767d55d57edSdrh   rc = sqlite3_create_collation_v2(db, Tcl_GetString(objv[2]), SQLITE_UTF8,
1768a9808b31Sdanielk1977       (void *)p, testCreateCollationCmp, testCreateCollationDel
1769a9808b31Sdanielk1977   );
1770a9808b31Sdanielk1977   return TCL_OK;
1771a9808b31Sdanielk1977 }
1772a9808b31Sdanielk1977 
1773a9808b31Sdanielk1977 /*
1774d2199f0fSdan ** USAGE: sqlite3_create_function_v2 DB NAME NARG ENC ?SWITCHES?
1775d2199f0fSdan **
1776d2199f0fSdan ** Available switches are:
1777d2199f0fSdan **
1778d2199f0fSdan **   -func    SCRIPT
1779d2199f0fSdan **   -step    SCRIPT
1780d2199f0fSdan **   -final   SCRIPT
1781d2199f0fSdan **   -destroy SCRIPT
1782d2199f0fSdan */
1783d2199f0fSdan typedef struct CreateFunctionV2 CreateFunctionV2;
1784d2199f0fSdan struct CreateFunctionV2 {
1785d2199f0fSdan   Tcl_Interp *interp;
1786d2199f0fSdan   Tcl_Obj *pFunc;                 /* Script for function invocation */
1787d2199f0fSdan   Tcl_Obj *pStep;                 /* Script for agg. step invocation */
1788d2199f0fSdan   Tcl_Obj *pFinal;                /* Script for agg. finalization invocation */
1789d2199f0fSdan   Tcl_Obj *pDestroy;              /* Destructor script */
1790d2199f0fSdan };
1791d2199f0fSdan static void cf2Func(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
1792d2199f0fSdan }
1793d2199f0fSdan static void cf2Step(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
1794d2199f0fSdan }
1795d2199f0fSdan static void cf2Final(sqlite3_context *ctx){
1796d2199f0fSdan }
1797d2199f0fSdan static void cf2Destroy(void *pUser){
1798d2199f0fSdan   CreateFunctionV2 *p = (CreateFunctionV2 *)pUser;
1799d2199f0fSdan 
1800d2199f0fSdan   if( p->interp && p->pDestroy ){
1801d2199f0fSdan     int rc = Tcl_EvalObjEx(p->interp, p->pDestroy, 0);
1802d2199f0fSdan     if( rc!=TCL_OK ) Tcl_BackgroundError(p->interp);
1803d2199f0fSdan   }
1804d2199f0fSdan 
1805d2199f0fSdan   if( p->pFunc ) Tcl_DecrRefCount(p->pFunc);
1806d2199f0fSdan   if( p->pStep ) Tcl_DecrRefCount(p->pStep);
1807d2199f0fSdan   if( p->pFinal ) Tcl_DecrRefCount(p->pFinal);
1808d2199f0fSdan   if( p->pDestroy ) Tcl_DecrRefCount(p->pDestroy);
1809d2199f0fSdan   sqlite3_free(p);
1810d2199f0fSdan }
18117617e4a8Smistachkin static int SQLITE_TCLAPI test_create_function_v2(
1812d2199f0fSdan   ClientData clientData,          /* Not used */
1813d2199f0fSdan   Tcl_Interp *interp,             /* The invoking TCL interpreter */
1814d2199f0fSdan   int objc,                       /* Number of arguments */
1815d2199f0fSdan   Tcl_Obj *CONST objv[]           /* Command arguments */
1816d2199f0fSdan ){
1817d2199f0fSdan   sqlite3 *db;
1818d2199f0fSdan   const char *zFunc;
1819d2199f0fSdan   int nArg;
1820d2199f0fSdan   int enc;
1821d2199f0fSdan   CreateFunctionV2 *p;
1822d2199f0fSdan   int i;
1823d2199f0fSdan   int rc;
1824d2199f0fSdan 
1825d2199f0fSdan   struct EncTable {
1826d2199f0fSdan     const char *zEnc;
1827d2199f0fSdan     int enc;
1828d2199f0fSdan   } aEnc[] = {
1829d2199f0fSdan     {"utf8",    SQLITE_UTF8 },
1830d2199f0fSdan     {"utf16",   SQLITE_UTF16 },
1831d2199f0fSdan     {"utf16le", SQLITE_UTF16LE },
1832d2199f0fSdan     {"utf16be", SQLITE_UTF16BE },
1833d2199f0fSdan     {"any",     SQLITE_ANY },
1834d2199f0fSdan     {"0", 0 }
1835d2199f0fSdan   };
1836d2199f0fSdan 
1837d2199f0fSdan   if( objc<5 || (objc%2)==0 ){
1838d2199f0fSdan     Tcl_WrongNumArgs(interp, 1, objv, "DB NAME NARG ENC SWITCHES...");
1839d2199f0fSdan     return TCL_ERROR;
1840d2199f0fSdan   }
1841d2199f0fSdan 
1842d2199f0fSdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1843d2199f0fSdan   zFunc = Tcl_GetString(objv[2]);
1844d2199f0fSdan   if( Tcl_GetIntFromObj(interp, objv[3], &nArg) ) return TCL_ERROR;
1845d2199f0fSdan   if( Tcl_GetIndexFromObjStruct(interp, objv[4], aEnc, sizeof(aEnc[0]),
1846d2199f0fSdan           "encoding", 0, &enc)
1847d2199f0fSdan   ){
1848d2199f0fSdan     return TCL_ERROR;
1849d2199f0fSdan   }
1850d2199f0fSdan   enc = aEnc[enc].enc;
1851d2199f0fSdan 
1852d2199f0fSdan   p = sqlite3_malloc(sizeof(CreateFunctionV2));
1853d2199f0fSdan   assert( p );
1854d2199f0fSdan   memset(p, 0, sizeof(CreateFunctionV2));
1855d2199f0fSdan   p->interp = interp;
1856d2199f0fSdan 
1857d2199f0fSdan   for(i=5; i<objc; i+=2){
1858d2199f0fSdan     int iSwitch;
1859d2199f0fSdan     const char *azSwitch[] = {"-func", "-step", "-final", "-destroy", 0};
1860d2199f0fSdan     if( Tcl_GetIndexFromObj(interp, objv[i], azSwitch, "switch", 0, &iSwitch) ){
1861d2199f0fSdan       sqlite3_free(p);
1862d2199f0fSdan       return TCL_ERROR;
1863d2199f0fSdan     }
1864d2199f0fSdan 
1865d2199f0fSdan     switch( iSwitch ){
1866d2199f0fSdan       case 0: p->pFunc = objv[i+1];      break;
1867d2199f0fSdan       case 1: p->pStep = objv[i+1];      break;
1868d2199f0fSdan       case 2: p->pFinal = objv[i+1];     break;
1869d2199f0fSdan       case 3: p->pDestroy = objv[i+1];   break;
1870d2199f0fSdan     }
1871d2199f0fSdan   }
1872d2199f0fSdan   if( p->pFunc ) p->pFunc = Tcl_DuplicateObj(p->pFunc);
1873d2199f0fSdan   if( p->pStep ) p->pStep = Tcl_DuplicateObj(p->pStep);
1874d2199f0fSdan   if( p->pFinal ) p->pFinal = Tcl_DuplicateObj(p->pFinal);
1875d2199f0fSdan   if( p->pDestroy ) p->pDestroy = Tcl_DuplicateObj(p->pDestroy);
1876d2199f0fSdan 
1877d2199f0fSdan   if( p->pFunc ) Tcl_IncrRefCount(p->pFunc);
1878d2199f0fSdan   if( p->pStep ) Tcl_IncrRefCount(p->pStep);
1879d2199f0fSdan   if( p->pFinal ) Tcl_IncrRefCount(p->pFinal);
1880d2199f0fSdan   if( p->pDestroy ) Tcl_IncrRefCount(p->pDestroy);
1881d2199f0fSdan 
1882d2199f0fSdan   rc = sqlite3_create_function_v2(db, zFunc, nArg, enc, (void *)p,
1883d2199f0fSdan       (p->pFunc ? cf2Func : 0),
1884d2199f0fSdan       (p->pStep ? cf2Step : 0),
1885d2199f0fSdan       (p->pFinal ? cf2Final : 0),
1886d2199f0fSdan       cf2Destroy
1887d2199f0fSdan   );
1888d2199f0fSdan   if( rc!=SQLITE_OK ){
1889d2199f0fSdan     Tcl_ResetResult(interp);
1890e84d8d32Smistachkin     Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
1891d2199f0fSdan     return TCL_ERROR;
1892d2199f0fSdan   }
1893d2199f0fSdan   return TCL_OK;
1894d2199f0fSdan }
1895d2199f0fSdan 
1896d2199f0fSdan /*
189769e777f3Sdanielk1977 ** Usage: sqlite3_load_extension DB-HANDLE FILE ?PROC?
189869e777f3Sdanielk1977 */
18997617e4a8Smistachkin static int SQLITE_TCLAPI test_load_extension(
190069e777f3Sdanielk1977   ClientData clientData, /* Not used */
190169e777f3Sdanielk1977   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
190269e777f3Sdanielk1977   int objc,              /* Number of arguments */
190369e777f3Sdanielk1977   Tcl_Obj *CONST objv[]  /* Command arguments */
190469e777f3Sdanielk1977 ){
190569e777f3Sdanielk1977   Tcl_CmdInfo cmdInfo;
190669e777f3Sdanielk1977   sqlite3 *db;
190769e777f3Sdanielk1977   int rc;
190869e777f3Sdanielk1977   char *zDb;
190969e777f3Sdanielk1977   char *zFile;
191069e777f3Sdanielk1977   char *zProc = 0;
191169e777f3Sdanielk1977   char *zErr = 0;
191269e777f3Sdanielk1977 
191369e777f3Sdanielk1977   if( objc!=4 && objc!=3 ){
191469e777f3Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "DB-HANDLE FILE ?PROC?");
191569e777f3Sdanielk1977     return TCL_ERROR;
191669e777f3Sdanielk1977   }
191769e777f3Sdanielk1977   zDb = Tcl_GetString(objv[1]);
191869e777f3Sdanielk1977   zFile = Tcl_GetString(objv[2]);
191969e777f3Sdanielk1977   if( objc==4 ){
192069e777f3Sdanielk1977     zProc = Tcl_GetString(objv[3]);
192169e777f3Sdanielk1977   }
192269e777f3Sdanielk1977 
192369e777f3Sdanielk1977   /* Extract the C database handle from the Tcl command name */
192469e777f3Sdanielk1977   if( !Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){
192569e777f3Sdanielk1977     Tcl_AppendResult(interp, "command not found: ", zDb, (char*)0);
192669e777f3Sdanielk1977     return TCL_ERROR;
192769e777f3Sdanielk1977   }
192869e777f3Sdanielk1977   db = ((struct SqliteDb*)cmdInfo.objClientData)->db;
192969e777f3Sdanielk1977   assert(db);
193069e777f3Sdanielk1977 
193169e777f3Sdanielk1977   /* Call the underlying C function. If an error occurs, set rc to
193269e777f3Sdanielk1977   ** TCL_ERROR and load any error string into the interpreter. If no
193369e777f3Sdanielk1977   ** error occurs, set rc to TCL_OK.
193469e777f3Sdanielk1977   */
1935c2e87a3eSdrh #ifdef SQLITE_OMIT_LOAD_EXTENSION
1936c2e87a3eSdrh   rc = SQLITE_ERROR;
1937c2e87a3eSdrh   zErr = sqlite3_mprintf("this build omits sqlite3_load_extension()");
19389493cafeSdrh   (void)zProc;
19399493cafeSdrh   (void)zFile;
1940c2e87a3eSdrh #else
194169e777f3Sdanielk1977   rc = sqlite3_load_extension(db, zFile, zProc, &zErr);
1942c2e87a3eSdrh #endif
194369e777f3Sdanielk1977   if( rc!=SQLITE_OK ){
194469e777f3Sdanielk1977     Tcl_SetResult(interp, zErr ? zErr : "", TCL_VOLATILE);
194569e777f3Sdanielk1977     rc = TCL_ERROR;
194669e777f3Sdanielk1977   }else{
194769e777f3Sdanielk1977     rc = TCL_OK;
194869e777f3Sdanielk1977   }
194969e777f3Sdanielk1977   sqlite3_free(zErr);
195069e777f3Sdanielk1977 
195169e777f3Sdanielk1977   return rc;
195269e777f3Sdanielk1977 }
195369e777f3Sdanielk1977 
195469e777f3Sdanielk1977 /*
1955c2e87a3eSdrh ** Usage: sqlite3_enable_load_extension DB-HANDLE ONOFF
1956c2e87a3eSdrh */
19577617e4a8Smistachkin static int SQLITE_TCLAPI test_enable_load(
1958c2e87a3eSdrh   ClientData clientData, /* Not used */
1959c2e87a3eSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1960c2e87a3eSdrh   int objc,              /* Number of arguments */
1961c2e87a3eSdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
1962c2e87a3eSdrh ){
1963c2e87a3eSdrh   Tcl_CmdInfo cmdInfo;
1964c2e87a3eSdrh   sqlite3 *db;
1965c2e87a3eSdrh   char *zDb;
1966c2e87a3eSdrh   int onoff;
1967c2e87a3eSdrh 
1968c2e87a3eSdrh   if( objc!=3 ){
1969c2e87a3eSdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB-HANDLE ONOFF");
1970c2e87a3eSdrh     return TCL_ERROR;
1971c2e87a3eSdrh   }
1972c2e87a3eSdrh   zDb = Tcl_GetString(objv[1]);
1973c2e87a3eSdrh 
1974c2e87a3eSdrh   /* Extract the C database handle from the Tcl command name */
1975c2e87a3eSdrh   if( !Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){
1976c2e87a3eSdrh     Tcl_AppendResult(interp, "command not found: ", zDb, (char*)0);
1977c2e87a3eSdrh     return TCL_ERROR;
1978c2e87a3eSdrh   }
1979c2e87a3eSdrh   db = ((struct SqliteDb*)cmdInfo.objClientData)->db;
1980c2e87a3eSdrh   assert(db);
1981c2e87a3eSdrh 
1982c2e87a3eSdrh   /* Get the onoff parameter */
1983c2e87a3eSdrh   if( Tcl_GetBooleanFromObj(interp, objv[2], &onoff) ){
1984c2e87a3eSdrh     return TCL_ERROR;
1985c2e87a3eSdrh   }
1986c2e87a3eSdrh 
1987c2e87a3eSdrh #ifdef SQLITE_OMIT_LOAD_EXTENSION
1988c2e87a3eSdrh   Tcl_AppendResult(interp, "this build omits sqlite3_load_extension()");
1989c2e87a3eSdrh   return TCL_ERROR;
1990c2e87a3eSdrh #else
1991c2e87a3eSdrh   sqlite3_enable_load_extension(db, onoff);
1992c2e87a3eSdrh   return TCL_OK;
1993c2e87a3eSdrh #endif
1994c2e87a3eSdrh }
1995c2e87a3eSdrh 
1996c2e87a3eSdrh /*
199728b4e489Sdrh ** Usage:  sqlite_abort
199828b4e489Sdrh **
199928b4e489Sdrh ** Shutdown the process immediately.  This is not a clean shutdown.
200028b4e489Sdrh ** This command is used to test the recoverability of a database in
200128b4e489Sdrh ** the event of a program crash.
200228b4e489Sdrh */
20037617e4a8Smistachkin static int SQLITE_TCLAPI sqlite_abort(
200428b4e489Sdrh   void *NotUsed,
200528b4e489Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
200628b4e489Sdrh   int argc,              /* Number of arguments */
200728b4e489Sdrh   char **argv            /* Text of each argument */
200828b4e489Sdrh ){
20092ceced15Sshaneh #if defined(_MSC_VER)
20102ceced15Sshaneh   /* We do this, otherwise the test will halt with a popup message
20112ceced15Sshaneh    * that we have to click away before the test will continue.
20122ceced15Sshaneh    */
20132ceced15Sshaneh   _set_abort_behavior( 0, _CALL_REPORTFAULT );
20142ceced15Sshaneh #endif
2015d3f6b81aSdan   exit(255);
201628b4e489Sdrh   assert( interp==0 );   /* This will always fail */
201728b4e489Sdrh   return TCL_OK;
201828b4e489Sdrh }
201928b4e489Sdrh 
202028b4e489Sdrh /*
20216cbe1f1bSdrh ** The following routine is a user-defined SQL function whose purpose
20226cbe1f1bSdrh ** is to test the sqlite_set_result() API.
20236cbe1f1bSdrh */
20240ae8b831Sdanielk1977 static void testFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
20256cbe1f1bSdrh   while( argc>=2 ){
202603d847eaSdrh     const char *zArg0 = (char*)sqlite3_value_text(argv[0]);
20276d88bad4Sdanielk1977     if( zArg0 ){
20286d88bad4Sdanielk1977       if( 0==sqlite3StrICmp(zArg0, "int") ){
20296d88bad4Sdanielk1977         sqlite3_result_int(context, sqlite3_value_int(argv[1]));
20306d88bad4Sdanielk1977       }else if( sqlite3StrICmp(zArg0,"int64")==0 ){
20316d88bad4Sdanielk1977         sqlite3_result_int64(context, sqlite3_value_int64(argv[1]));
203251ad0ecdSdanielk1977       }else if( sqlite3StrICmp(zArg0,"string")==0 ){
203303d847eaSdrh         sqlite3_result_text(context, (char*)sqlite3_value_text(argv[1]), -1,
2034d8123366Sdanielk1977             SQLITE_TRANSIENT);
203551ad0ecdSdanielk1977       }else if( sqlite3StrICmp(zArg0,"double")==0 ){
20366d88bad4Sdanielk1977         sqlite3_result_double(context, sqlite3_value_double(argv[1]));
20376d88bad4Sdanielk1977       }else if( sqlite3StrICmp(zArg0,"null")==0 ){
20386d88bad4Sdanielk1977         sqlite3_result_null(context);
20396d88bad4Sdanielk1977       }else if( sqlite3StrICmp(zArg0,"value")==0 ){
20406d88bad4Sdanielk1977         sqlite3_result_value(context, argv[sqlite3_value_int(argv[1])]);
20416cbe1f1bSdrh       }else{
20426d88bad4Sdanielk1977         goto error_out;
20436d88bad4Sdanielk1977       }
20446d88bad4Sdanielk1977     }else{
20456d88bad4Sdanielk1977       goto error_out;
20466cbe1f1bSdrh     }
20476cbe1f1bSdrh     argc -= 2;
20486cbe1f1bSdrh     argv += 2;
20496cbe1f1bSdrh   }
20506d88bad4Sdanielk1977   return;
20516d88bad4Sdanielk1977 
20526d88bad4Sdanielk1977 error_out:
20536d88bad4Sdanielk1977   sqlite3_result_error(context,"first argument should be one of: "
20546d88bad4Sdanielk1977       "int int64 string double null value", -1);
20556cbe1f1bSdrh }
20566cbe1f1bSdrh 
20576cbe1f1bSdrh /*
20586cbe1f1bSdrh ** Usage:   sqlite_register_test_function  DB  NAME
20596cbe1f1bSdrh **
20606cbe1f1bSdrh ** Register the test SQL function on the database DB under the name NAME.
20616cbe1f1bSdrh */
20627617e4a8Smistachkin static int SQLITE_TCLAPI test_register_func(
20636cbe1f1bSdrh   void *NotUsed,
20646cbe1f1bSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
20656cbe1f1bSdrh   int argc,              /* Number of arguments */
20666cbe1f1bSdrh   char **argv            /* Text of each argument */
20676cbe1f1bSdrh ){
20689bb575fdSdrh   sqlite3 *db;
20696cbe1f1bSdrh   int rc;
20706cbe1f1bSdrh   if( argc!=3 ){
20716cbe1f1bSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
20726cbe1f1bSdrh        " DB FUNCTION-NAME", 0);
20736cbe1f1bSdrh     return TCL_ERROR;
20746cbe1f1bSdrh   }
2075b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
2076f9d64d2cSdanielk1977   rc = sqlite3_create_function(db, argv[2], -1, SQLITE_UTF8, 0,
2077d8123366Sdanielk1977       testFunc, 0, 0);
20786cbe1f1bSdrh   if( rc!=0 ){
2079f20b21c8Sdanielk1977     Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);
20806cbe1f1bSdrh     return TCL_ERROR;
20816cbe1f1bSdrh   }
2082c60d0446Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
20836cbe1f1bSdrh   return TCL_OK;
20846cbe1f1bSdrh }
20856cbe1f1bSdrh 
20866cbe1f1bSdrh /*
2087106bb236Sdanielk1977 ** Usage:  sqlite3_finalize  STMT
2088b86ccfb2Sdrh **
2089106bb236Sdanielk1977 ** Finalize a statement handle.
2090b86ccfb2Sdrh */
20917617e4a8Smistachkin static int SQLITE_TCLAPI test_finalize(
2092106bb236Sdanielk1977   void * clientData,
2093106bb236Sdanielk1977   Tcl_Interp *interp,
2094106bb236Sdanielk1977   int objc,
2095106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
2096b86ccfb2Sdrh ){
2097106bb236Sdanielk1977   sqlite3_stmt *pStmt;
2098b86ccfb2Sdrh   int rc;
2099dddb2f23Sdrh   sqlite3 *db = 0;
2100106bb236Sdanielk1977 
2101106bb236Sdanielk1977   if( objc!=2 ){
2102106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
2103106bb236Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
2104b86ccfb2Sdrh     return TCL_ERROR;
2105b86ccfb2Sdrh   }
2106106bb236Sdanielk1977 
2107106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
2108106bb236Sdanielk1977 
21094397de57Sdanielk1977   if( pStmt ){
2110c60d0446Sdrh     db = StmtToDb(pStmt);
21114397de57Sdanielk1977   }
2112fc57d7bfSdanielk1977   rc = sqlite3_finalize(pStmt);
21134f0c5878Sdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
21144397de57Sdanielk1977   if( db && sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
2115106bb236Sdanielk1977   return TCL_OK;
2116106bb236Sdanielk1977 }
2117106bb236Sdanielk1977 
2118106bb236Sdanielk1977 /*
2119d1d38488Sdrh ** Usage:  sqlite3_stmt_status  STMT  CODE  RESETFLAG
2120d1d38488Sdrh **
2121d1d38488Sdrh ** Get the value of a status counter from a statement.
2122d1d38488Sdrh */
21237617e4a8Smistachkin static int SQLITE_TCLAPI test_stmt_status(
2124d1d38488Sdrh   void * clientData,
2125d1d38488Sdrh   Tcl_Interp *interp,
2126d1d38488Sdrh   int objc,
2127d1d38488Sdrh   Tcl_Obj *CONST objv[]
2128d1d38488Sdrh ){
2129d1d38488Sdrh   int iValue;
213027b2f053Smistachkin   int i, op = 0, resetFlag;
2131d1d38488Sdrh   const char *zOpName;
2132d1d38488Sdrh   sqlite3_stmt *pStmt;
2133d1d38488Sdrh 
2134d1d38488Sdrh   static const struct {
2135d1d38488Sdrh     const char *zName;
2136d1d38488Sdrh     int op;
2137d1d38488Sdrh   } aOp[] = {
2138d1d38488Sdrh     { "SQLITE_STMTSTATUS_FULLSCAN_STEP",   SQLITE_STMTSTATUS_FULLSCAN_STEP   },
2139d1d38488Sdrh     { "SQLITE_STMTSTATUS_SORT",            SQLITE_STMTSTATUS_SORT            },
2140a21a64ddSdrh     { "SQLITE_STMTSTATUS_AUTOINDEX",       SQLITE_STMTSTATUS_AUTOINDEX       },
2141bf159fa2Sdrh     { "SQLITE_STMTSTATUS_VM_STEP",         SQLITE_STMTSTATUS_VM_STEP         },
214200d11d40Sdrh     { "SQLITE_STMTSTATUS_REPREPARE",       SQLITE_STMTSTATUS_REPREPARE       },
214300d11d40Sdrh     { "SQLITE_STMTSTATUS_RUN",             SQLITE_STMTSTATUS_RUN             },
214400d11d40Sdrh     { "SQLITE_STMTSTATUS_MEMUSED",         SQLITE_STMTSTATUS_MEMUSED         },
2145d1d38488Sdrh   };
2146d1d38488Sdrh   if( objc!=4 ){
2147d1d38488Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "STMT PARAMETER RESETFLAG");
2148d1d38488Sdrh     return TCL_ERROR;
2149d1d38488Sdrh   }
2150d1d38488Sdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
2151d1d38488Sdrh   zOpName = Tcl_GetString(objv[2]);
2152d1d38488Sdrh   for(i=0; i<ArraySize(aOp); i++){
2153d1d38488Sdrh     if( strcmp(aOp[i].zName, zOpName)==0 ){
2154d1d38488Sdrh       op = aOp[i].op;
2155d1d38488Sdrh       break;
2156d1d38488Sdrh     }
2157d1d38488Sdrh   }
2158d1d38488Sdrh   if( i>=ArraySize(aOp) ){
2159d1d38488Sdrh     if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR;
2160d1d38488Sdrh   }
2161d1d38488Sdrh   if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR;
2162d1d38488Sdrh   iValue = sqlite3_stmt_status(pStmt, op, resetFlag);
2163d1d38488Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(iValue));
2164d1d38488Sdrh   return TCL_OK;
2165d1d38488Sdrh }
2166d1d38488Sdrh 
216704489b6dSdan #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
216804489b6dSdan /*
216904489b6dSdan ** Usage:  sqlite3_stmt_scanstatus STMT IDX
217004489b6dSdan */
21717617e4a8Smistachkin static int SQLITE_TCLAPI test_stmt_scanstatus(
217204489b6dSdan   void * clientData,
217304489b6dSdan   Tcl_Interp *interp,
217404489b6dSdan   int objc,
217504489b6dSdan   Tcl_Obj *CONST objv[]
217604489b6dSdan ){
217704489b6dSdan   sqlite3_stmt *pStmt;            /* First argument */
217804489b6dSdan   int idx;                        /* Second argument */
217904489b6dSdan 
218004489b6dSdan   const char *zName;
218104489b6dSdan   const char *zExplain;
218204489b6dSdan   sqlite3_int64 nLoop;
218304489b6dSdan   sqlite3_int64 nVisit;
2184518140edSdrh   double rEst;
218504489b6dSdan   int res;
218604489b6dSdan 
218704489b6dSdan   if( objc!=3 ){
218804489b6dSdan     Tcl_WrongNumArgs(interp, 1, objv, "STMT IDX");
218904489b6dSdan     return TCL_ERROR;
219004489b6dSdan   }
219104489b6dSdan   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
219204489b6dSdan   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
219304489b6dSdan 
2194d1a1c234Sdrh   res = sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop);
219504489b6dSdan   if( res==0 ){
219604489b6dSdan     Tcl_Obj *pRet = Tcl_NewObj();
219704489b6dSdan     Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nLoop", -1));
219804489b6dSdan     Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nLoop));
2199d1a1c234Sdrh     sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit);
220004489b6dSdan     Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nVisit", -1));
220104489b6dSdan     Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nVisit));
2202518140edSdrh     sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_EST, (void*)&rEst);
220304489b6dSdan     Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nEst", -1));
2204518140edSdrh     Tcl_ListObjAppendElement(0, pRet, Tcl_NewDoubleObj(rEst));
2205d1a1c234Sdrh     sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NAME, (void*)&zName);
220604489b6dSdan     Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("zName", -1));
220704489b6dSdan     Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zName, -1));
2208d1a1c234Sdrh     sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain);
220904489b6dSdan     Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("zExplain", -1));
221004489b6dSdan     Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zExplain, -1));
221104489b6dSdan     Tcl_SetObjResult(interp, pRet);
221204489b6dSdan   }else{
221304489b6dSdan     Tcl_ResetResult(interp);
221404489b6dSdan   }
221504489b6dSdan   return TCL_OK;
221604489b6dSdan }
221704489b6dSdan 
221804489b6dSdan /*
221904489b6dSdan ** Usage:  sqlite3_stmt_scanstatus_reset  STMT
222004489b6dSdan */
22217617e4a8Smistachkin static int SQLITE_TCLAPI test_stmt_scanstatus_reset(
222204489b6dSdan   void * clientData,
222304489b6dSdan   Tcl_Interp *interp,
222404489b6dSdan   int objc,
222504489b6dSdan   Tcl_Obj *CONST objv[]
222604489b6dSdan ){
222704489b6dSdan   sqlite3_stmt *pStmt;            /* First argument */
222804489b6dSdan   if( objc!=2 ){
222904489b6dSdan     Tcl_WrongNumArgs(interp, 1, objv, "STMT");
223004489b6dSdan     return TCL_ERROR;
223104489b6dSdan   }
223204489b6dSdan   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
223304489b6dSdan   sqlite3_stmt_scanstatus_reset(pStmt);
223404489b6dSdan   return TCL_OK;
223504489b6dSdan }
223604489b6dSdan #endif
223704489b6dSdan 
2238d83f7ca1Sdan #ifdef SQLITE_ENABLE_SQLLOG
2239d83f7ca1Sdan /*
2240d83f7ca1Sdan ** Usage:  sqlite3_config_sqllog
2241d83f7ca1Sdan **
2242d83f7ca1Sdan ** Zero the SQLITE_CONFIG_SQLLOG configuration
2243d83f7ca1Sdan */
22447617e4a8Smistachkin static int SQLITE_TCLAPI test_config_sqllog(
2245d83f7ca1Sdan   void * clientData,
2246d83f7ca1Sdan   Tcl_Interp *interp,
2247d83f7ca1Sdan   int objc,
2248d83f7ca1Sdan   Tcl_Obj *CONST objv[]
2249d83f7ca1Sdan ){
2250d83f7ca1Sdan   if( objc!=1 ){
2251d83f7ca1Sdan     Tcl_WrongNumArgs(interp, 1, objv, "");
2252d83f7ca1Sdan     return TCL_ERROR;
2253d83f7ca1Sdan   }
2254d83f7ca1Sdan   sqlite3_config(SQLITE_CONFIG_SQLLOG, 0, 0);
2255d83f7ca1Sdan   return TCL_OK;
2256d83f7ca1Sdan }
2257d83f7ca1Sdan #endif
2258d83f7ca1Sdan 
2259d1d38488Sdrh /*
22602e3a5a81Sdan ** Usage:  sqlite3_config_sorterref
22612e3a5a81Sdan **
22622e3a5a81Sdan ** Set the SQLITE_CONFIG_SORTERREF_SIZE configuration option
22632e3a5a81Sdan */
22642e3a5a81Sdan static int SQLITE_TCLAPI test_config_sorterref(
22652e3a5a81Sdan   void * clientData,
22662e3a5a81Sdan   Tcl_Interp *interp,
22672e3a5a81Sdan   int objc,
22682e3a5a81Sdan   Tcl_Obj *CONST objv[]
22692e3a5a81Sdan ){
22702e3a5a81Sdan   int iVal;
22712e3a5a81Sdan   if( objc!=2 ){
22722e3a5a81Sdan     Tcl_WrongNumArgs(interp, 1, objv, "NBYTE");
22732e3a5a81Sdan     return TCL_ERROR;
22742e3a5a81Sdan   }
22752e3a5a81Sdan   if( Tcl_GetIntFromObj(interp, objv[1], &iVal) ) return TCL_ERROR;
22762e3a5a81Sdan   sqlite3_config(SQLITE_CONFIG_SORTERREF_SIZE, iVal);
22772e3a5a81Sdan   return TCL_OK;
22782e3a5a81Sdan }
22792e3a5a81Sdan 
22802e3a5a81Sdan /*
2281e4e416e8Sdan ** Usage: vfs_current_time_int64
2282e4e416e8Sdan **
2283e4e416e8Sdan ** Return the value returned by the default VFS's xCurrentTimeInt64 method.
2284e4e416e8Sdan */
22857617e4a8Smistachkin static int SQLITE_TCLAPI vfsCurrentTimeInt64(
2286e4e416e8Sdan   void * clientData,
2287e4e416e8Sdan   Tcl_Interp *interp,
2288e4e416e8Sdan   int objc,
2289e4e416e8Sdan   Tcl_Obj *CONST objv[]
2290e4e416e8Sdan ){
2291e4e416e8Sdan   i64 t;
2292e4e416e8Sdan   sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
2293e4e416e8Sdan   if( objc!=1 ){
2294e4e416e8Sdan     Tcl_WrongNumArgs(interp, 1, objv, "");
2295e4e416e8Sdan     return TCL_ERROR;
2296e4e416e8Sdan   }
2297e4e416e8Sdan   pVfs->xCurrentTimeInt64(pVfs, &t);
2298e4e416e8Sdan   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(t));
2299e4e416e8Sdan   return TCL_OK;
2300e4e416e8Sdan }
2301e4e416e8Sdan 
2302ee3b7a27Sdrh #ifdef SQLITE_ENABLE_SNAPSHOT
2303e4e416e8Sdan /*
2304fc1acf33Sdan ** Usage: sqlite3_snapshot_get DB DBNAME
2305fc1acf33Sdan */
23067617e4a8Smistachkin static int SQLITE_TCLAPI test_snapshot_get(
2307fc1acf33Sdan   void * clientData,
2308fc1acf33Sdan   Tcl_Interp *interp,
2309fc1acf33Sdan   int objc,
2310fc1acf33Sdan   Tcl_Obj *CONST objv[]
2311fc1acf33Sdan ){
2312fc1acf33Sdan   int rc;
2313fc1acf33Sdan   sqlite3 *db;
2314fc1acf33Sdan   char *zName;
2315fc1acf33Sdan   sqlite3_snapshot *pSnapshot = 0;
2316fc1acf33Sdan 
2317fc1acf33Sdan   if( objc!=3 ){
2318fc1acf33Sdan     Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
2319fc1acf33Sdan     return TCL_ERROR;
2320fc1acf33Sdan   }
2321fc1acf33Sdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
2322fc1acf33Sdan   zName = Tcl_GetString(objv[2]);
2323fc1acf33Sdan 
2324fc1acf33Sdan   rc = sqlite3_snapshot_get(db, zName, &pSnapshot);
2325fc1acf33Sdan   if( rc!=SQLITE_OK ){
2326fc1acf33Sdan     Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
2327fc1acf33Sdan     return TCL_ERROR;
2328fc1acf33Sdan   }else{
2329fc1acf33Sdan     char zBuf[100];
2330fc1acf33Sdan     if( sqlite3TestMakePointerStr(interp, zBuf, pSnapshot) ) return TCL_ERROR;
2331fc1acf33Sdan     Tcl_SetObjResult(interp, Tcl_NewStringObj(zBuf, -1));
2332fc1acf33Sdan   }
2333fc1acf33Sdan   return TCL_OK;
2334fc1acf33Sdan }
2335ee3b7a27Sdrh #endif /* SQLITE_ENABLE_SNAPSHOT */
2336fc1acf33Sdan 
2337ee3b7a27Sdrh #ifdef SQLITE_ENABLE_SNAPSHOT
2338fc1acf33Sdan /*
23391158498dSdan ** Usage: sqlite3_snapshot_recover DB DBNAME
23401158498dSdan */
23411158498dSdan static int SQLITE_TCLAPI test_snapshot_recover(
23421158498dSdan   void * clientData,
23431158498dSdan   Tcl_Interp *interp,
23441158498dSdan   int objc,
23451158498dSdan   Tcl_Obj *CONST objv[]
23461158498dSdan ){
23471158498dSdan   int rc;
23481158498dSdan   sqlite3 *db;
23491158498dSdan   char *zName;
23501158498dSdan 
23511158498dSdan   if( objc!=3 ){
23521158498dSdan     Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
23531158498dSdan     return TCL_ERROR;
23541158498dSdan   }
23551158498dSdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
23561158498dSdan   zName = Tcl_GetString(objv[2]);
23571158498dSdan 
23581158498dSdan   rc = sqlite3_snapshot_recover(db, zName);
23591158498dSdan   if( rc!=SQLITE_OK ){
23601158498dSdan     Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
23611158498dSdan     return TCL_ERROR;
23621158498dSdan   }else{
23631158498dSdan     Tcl_ResetResult(interp);
23641158498dSdan   }
23651158498dSdan   return TCL_OK;
23661158498dSdan }
23671158498dSdan #endif /* SQLITE_ENABLE_SNAPSHOT */
23681158498dSdan 
23691158498dSdan #ifdef SQLITE_ENABLE_SNAPSHOT
23701158498dSdan /*
2371fc1acf33Sdan ** Usage: sqlite3_snapshot_open DB DBNAME SNAPSHOT
2372fc1acf33Sdan */
23737617e4a8Smistachkin static int SQLITE_TCLAPI test_snapshot_open(
2374fc1acf33Sdan   void * clientData,
2375fc1acf33Sdan   Tcl_Interp *interp,
2376fc1acf33Sdan   int objc,
2377fc1acf33Sdan   Tcl_Obj *CONST objv[]
2378fc1acf33Sdan ){
2379fc1acf33Sdan   int rc;
2380fc1acf33Sdan   sqlite3 *db;
2381fc1acf33Sdan   char *zName;
2382fc1acf33Sdan   sqlite3_snapshot *pSnapshot;
2383fc1acf33Sdan 
2384fc1acf33Sdan   if( objc!=4 ){
2385fc1acf33Sdan     Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SNAPSHOT");
2386fc1acf33Sdan     return TCL_ERROR;
2387fc1acf33Sdan   }
2388fc1acf33Sdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
2389fc1acf33Sdan   zName = Tcl_GetString(objv[2]);
2390fc1acf33Sdan   pSnapshot = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[3]));
2391fc1acf33Sdan 
2392fc1acf33Sdan   rc = sqlite3_snapshot_open(db, zName, pSnapshot);
2393fc1acf33Sdan   if( rc!=SQLITE_OK ){
2394fc1acf33Sdan     Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
2395fc1acf33Sdan     return TCL_ERROR;
2396*fa3d4c19Sdan   }else{
2397*fa3d4c19Sdan     Tcl_ResetResult(interp);
2398fc1acf33Sdan   }
2399fc1acf33Sdan   return TCL_OK;
2400fc1acf33Sdan }
2401ee3b7a27Sdrh #endif /* SQLITE_ENABLE_SNAPSHOT */
2402fc1acf33Sdan 
2403ee3b7a27Sdrh #ifdef SQLITE_ENABLE_SNAPSHOT
2404fc1acf33Sdan /*
2405fc1acf33Sdan ** Usage: sqlite3_snapshot_free SNAPSHOT
2406fc1acf33Sdan */
24077617e4a8Smistachkin static int SQLITE_TCLAPI test_snapshot_free(
2408fc1acf33Sdan   void * clientData,
2409fc1acf33Sdan   Tcl_Interp *interp,
2410fc1acf33Sdan   int objc,
2411fc1acf33Sdan   Tcl_Obj *CONST objv[]
2412fc1acf33Sdan ){
2413fc1acf33Sdan   sqlite3_snapshot *pSnapshot;
2414fc1acf33Sdan   if( objc!=2 ){
2415fc1acf33Sdan     Tcl_WrongNumArgs(interp, 1, objv, "SNAPSHOT");
2416fc1acf33Sdan     return TCL_ERROR;
2417fc1acf33Sdan   }
2418fc1acf33Sdan   pSnapshot = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
2419fc1acf33Sdan   sqlite3_snapshot_free(pSnapshot);
2420fc1acf33Sdan   return TCL_OK;
2421fc1acf33Sdan }
2422ee3b7a27Sdrh #endif /* SQLITE_ENABLE_SNAPSHOT */
2423fc1acf33Sdan 
2424ad2d5bafSdan #ifdef SQLITE_ENABLE_SNAPSHOT
2425ad2d5bafSdan /*
2426ad2d5bafSdan ** Usage: sqlite3_snapshot_cmp SNAPSHOT1 SNAPSHOT2
2427ad2d5bafSdan */
24287617e4a8Smistachkin static int SQLITE_TCLAPI test_snapshot_cmp(
2429ad2d5bafSdan   void * clientData,
2430ad2d5bafSdan   Tcl_Interp *interp,
2431ad2d5bafSdan   int objc,
2432ad2d5bafSdan   Tcl_Obj *CONST objv[]
2433ad2d5bafSdan ){
2434ad2d5bafSdan   int res;
2435ad2d5bafSdan   sqlite3_snapshot *p1;
2436ad2d5bafSdan   sqlite3_snapshot *p2;
2437ad2d5bafSdan   if( objc!=3 ){
2438ad2d5bafSdan     Tcl_WrongNumArgs(interp, 1, objv, "SNAPSHOT1 SNAPSHOT2");
2439ad2d5bafSdan     return TCL_ERROR;
2440ad2d5bafSdan   }
2441ad2d5bafSdan   p1 = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
2442ad2d5bafSdan   p2 = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[2]));
2443ad2d5bafSdan   res = sqlite3_snapshot_cmp(p1, p2);
2444ad2d5bafSdan   Tcl_SetObjResult(interp, Tcl_NewIntObj(res));
2445ad2d5bafSdan   return TCL_OK;
2446ad2d5bafSdan }
2447ad2d5bafSdan #endif /* SQLITE_ENABLE_SNAPSHOT */
2448ad2d5bafSdan 
244925accbcaSdan #ifdef SQLITE_ENABLE_SNAPSHOT
245025accbcaSdan /*
245125accbcaSdan ** Usage: sqlite3_snapshot_get_blob DB DBNAME
245225accbcaSdan */
245325accbcaSdan static int SQLITE_TCLAPI test_snapshot_get_blob(
245425accbcaSdan   void * clientData,
245525accbcaSdan   Tcl_Interp *interp,
245625accbcaSdan   int objc,
245725accbcaSdan   Tcl_Obj *CONST objv[]
245825accbcaSdan ){
245925accbcaSdan   int rc;
246025accbcaSdan   sqlite3 *db;
246125accbcaSdan   char *zName;
246225accbcaSdan   sqlite3_snapshot *pSnapshot = 0;
246325accbcaSdan 
246425accbcaSdan   if( objc!=3 ){
246525accbcaSdan     Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
246625accbcaSdan     return TCL_ERROR;
246725accbcaSdan   }
246825accbcaSdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
246925accbcaSdan   zName = Tcl_GetString(objv[2]);
247025accbcaSdan 
247125accbcaSdan   rc = sqlite3_snapshot_get(db, zName, &pSnapshot);
247225accbcaSdan   if( rc!=SQLITE_OK ){
247325accbcaSdan     Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
247425accbcaSdan     return TCL_ERROR;
247525accbcaSdan   }else{
247625accbcaSdan     Tcl_SetObjResult(interp,
247725accbcaSdan         Tcl_NewByteArrayObj((unsigned char*)pSnapshot, sizeof(sqlite3_snapshot))
247825accbcaSdan     );
247925accbcaSdan     sqlite3_snapshot_free(pSnapshot);
248025accbcaSdan   }
248125accbcaSdan   return TCL_OK;
248225accbcaSdan }
248325accbcaSdan #endif /* SQLITE_ENABLE_SNAPSHOT */
248425accbcaSdan 
248525accbcaSdan #ifdef SQLITE_ENABLE_SNAPSHOT
248625accbcaSdan   /*
248725accbcaSdan   ** Usage: sqlite3_snapshot_open_blob DB DBNAME SNAPSHOT
248825accbcaSdan */
248925accbcaSdan static int SQLITE_TCLAPI test_snapshot_open_blob(
249025accbcaSdan   void * clientData,
249125accbcaSdan   Tcl_Interp *interp,
249225accbcaSdan   int objc,
249325accbcaSdan   Tcl_Obj *CONST objv[]
249425accbcaSdan ){
249525accbcaSdan   int rc;
249625accbcaSdan   sqlite3 *db;
249725accbcaSdan   char *zName;
249825accbcaSdan   unsigned char *pBlob;
249925accbcaSdan   int nBlob;
250025accbcaSdan 
250125accbcaSdan   if( objc!=4 ){
250225accbcaSdan     Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SNAPSHOT");
250325accbcaSdan     return TCL_ERROR;
250425accbcaSdan   }
250525accbcaSdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
250625accbcaSdan   zName = Tcl_GetString(objv[2]);
250725accbcaSdan   pBlob = Tcl_GetByteArrayFromObj(objv[3], &nBlob);
250825accbcaSdan   if( nBlob!=sizeof(sqlite3_snapshot) ){
250925accbcaSdan     Tcl_AppendResult(interp, "bad SNAPSHOT", 0);
251025accbcaSdan     return TCL_ERROR;
251125accbcaSdan   }
251225accbcaSdan   rc = sqlite3_snapshot_open(db, zName, (sqlite3_snapshot*)pBlob);
251325accbcaSdan   if( rc!=SQLITE_OK ){
251425accbcaSdan     Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
251525accbcaSdan     return TCL_ERROR;
251625accbcaSdan   }
251725accbcaSdan   return TCL_OK;
251825accbcaSdan }
251925accbcaSdan #endif /* SQLITE_ENABLE_SNAPSHOT */
252025accbcaSdan 
252125accbcaSdan #ifdef SQLITE_ENABLE_SNAPSHOT
252225accbcaSdan /*
252325accbcaSdan ** Usage: sqlite3_snapshot_cmp_blob SNAPSHOT1 SNAPSHOT2
252425accbcaSdan */
252525accbcaSdan static int SQLITE_TCLAPI test_snapshot_cmp_blob(
252625accbcaSdan   void * clientData,
252725accbcaSdan   Tcl_Interp *interp,
252825accbcaSdan   int objc,
252925accbcaSdan   Tcl_Obj *CONST objv[]
253025accbcaSdan ){
253125accbcaSdan   int res;
253225accbcaSdan   unsigned char *p1;
253325accbcaSdan   unsigned char *p2;
253425accbcaSdan   int n1;
253525accbcaSdan   int n2;
253625accbcaSdan 
253725accbcaSdan   if( objc!=3 ){
253825accbcaSdan     Tcl_WrongNumArgs(interp, 1, objv, "SNAPSHOT1 SNAPSHOT2");
253925accbcaSdan     return TCL_ERROR;
254025accbcaSdan   }
254125accbcaSdan 
254225accbcaSdan   p1 = Tcl_GetByteArrayFromObj(objv[1], &n1);
254325accbcaSdan   p2 = Tcl_GetByteArrayFromObj(objv[2], &n2);
254425accbcaSdan 
254525accbcaSdan   if( n1!=sizeof(sqlite3_snapshot) || n1!=n2 ){
254625accbcaSdan     Tcl_AppendResult(interp, "bad SNAPSHOT", 0);
254725accbcaSdan     return TCL_ERROR;
254825accbcaSdan   }
254925accbcaSdan 
255025accbcaSdan   res = sqlite3_snapshot_cmp((sqlite3_snapshot*)p1, (sqlite3_snapshot*)p2);
255125accbcaSdan   Tcl_SetObjResult(interp, Tcl_NewIntObj(res));
255225accbcaSdan   return TCL_OK;
255325accbcaSdan }
255425accbcaSdan #endif /* SQLITE_ENABLE_SNAPSHOT */
255525accbcaSdan 
2556fc1acf33Sdan /*
2557000f95b1Sdan ** Usage: sqlite3_delete_database FILENAME
2558000f95b1Sdan */
2559000f95b1Sdan int sqlite3_delete_database(const char*);   /* in test_delete.c */
2560000f95b1Sdan static int SQLITE_TCLAPI test_delete_database(
2561000f95b1Sdan   void * clientData,
2562000f95b1Sdan   Tcl_Interp *interp,
2563000f95b1Sdan   int objc,
2564000f95b1Sdan   Tcl_Obj *CONST objv[]
2565000f95b1Sdan ){
2566000f95b1Sdan   int rc;
2567000f95b1Sdan   const char *zFile;
2568000f95b1Sdan   if( objc!=2 ){
2569000f95b1Sdan     Tcl_WrongNumArgs(interp, 1, objv, "FILE");
2570000f95b1Sdan     return TCL_ERROR;
2571000f95b1Sdan   }
2572000f95b1Sdan   zFile = (const char*)Tcl_GetString(objv[1]);
2573000f95b1Sdan   rc = sqlite3_delete_database(zFile);
2574000f95b1Sdan 
2575000f95b1Sdan   Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
2576000f95b1Sdan   return TCL_OK;
2577000f95b1Sdan }
2578000f95b1Sdan 
2579000f95b1Sdan /*
25804da30f88Sdan ** Usage: atomic_batch_write PATH
25814da30f88Sdan */
25824da30f88Sdan static int SQLITE_TCLAPI test_atomic_batch_write(
25834da30f88Sdan   void * clientData,
25844da30f88Sdan   Tcl_Interp *interp,
25854da30f88Sdan   int objc,
25864da30f88Sdan   Tcl_Obj *CONST objv[]
25874da30f88Sdan ){
25884da30f88Sdan   char *zFile = 0;                /* Path to file to test */
25894da30f88Sdan   sqlite3 *db = 0;                /* Database handle */
25904da30f88Sdan   sqlite3_file *pFd = 0;          /* SQLite fd open on zFile */
25914da30f88Sdan   int bRes = 0;                   /* Integer result of this command */
25924da30f88Sdan   int dc = 0;                     /* Device-characteristics mask */
25934da30f88Sdan   int rc;                         /* sqlite3_open() return code */
25944da30f88Sdan 
25954da30f88Sdan   if( objc!=2 ){
25964da30f88Sdan     Tcl_WrongNumArgs(interp, 1, objv, "PATH");
25974da30f88Sdan     return TCL_ERROR;
25984da30f88Sdan   }
25994da30f88Sdan   zFile = Tcl_GetString(objv[1]);
26004da30f88Sdan 
26014da30f88Sdan   rc = sqlite3_open(zFile, &db);
26024da30f88Sdan   if( rc!=SQLITE_OK ){
26034da30f88Sdan     Tcl_AppendResult(interp, sqlite3_errmsg(db), 0);
26044da30f88Sdan     sqlite3_close(db);
26054da30f88Sdan     return TCL_ERROR;
26064da30f88Sdan   }
26074da30f88Sdan 
26084da30f88Sdan   rc = sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void*)&pFd);
26094da30f88Sdan   dc = pFd->pMethods->xDeviceCharacteristics(pFd);
26104da30f88Sdan   if( dc & SQLITE_IOCAP_BATCH_ATOMIC ){
26114da30f88Sdan     bRes = 1;
26124da30f88Sdan   }
26134da30f88Sdan 
26144da30f88Sdan   Tcl_SetObjResult(interp, Tcl_NewIntObj(bRes));
26154da30f88Sdan   sqlite3_close(db);
26164da30f88Sdan   return TCL_OK;
26174da30f88Sdan }
26184da30f88Sdan 
26194da30f88Sdan /*
2620bb5a9c3eSdrh ** Usage:  sqlite3_next_stmt  DB  STMT
2621bb5a9c3eSdrh **
2622bb5a9c3eSdrh ** Return the next statment in sequence after STMT.
2623bb5a9c3eSdrh */
26247617e4a8Smistachkin static int SQLITE_TCLAPI test_next_stmt(
2625bb5a9c3eSdrh   void * clientData,
2626bb5a9c3eSdrh   Tcl_Interp *interp,
2627bb5a9c3eSdrh   int objc,
2628bb5a9c3eSdrh   Tcl_Obj *CONST objv[]
2629bb5a9c3eSdrh ){
2630bb5a9c3eSdrh   sqlite3_stmt *pStmt;
2631bb5a9c3eSdrh   sqlite3 *db = 0;
2632bb5a9c3eSdrh   char zBuf[50];
2633bb5a9c3eSdrh 
2634bb5a9c3eSdrh   if( objc!=3 ){
2635bb5a9c3eSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
2636bb5a9c3eSdrh         Tcl_GetStringFromObj(objv[0], 0), " DB STMT", 0);
2637bb5a9c3eSdrh     return TCL_ERROR;
2638bb5a9c3eSdrh   }
2639bb5a9c3eSdrh 
2640bb5a9c3eSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
2641bb5a9c3eSdrh   if( getStmtPointer(interp, Tcl_GetString(objv[2]), &pStmt) ) return TCL_ERROR;
2642bb5a9c3eSdrh   pStmt = sqlite3_next_stmt(db, pStmt);
2643bb5a9c3eSdrh   if( pStmt ){
2644bb5a9c3eSdrh     if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
2645bb5a9c3eSdrh     Tcl_AppendResult(interp, zBuf, 0);
2646bb5a9c3eSdrh   }
2647bb5a9c3eSdrh   return TCL_OK;
2648bb5a9c3eSdrh }
2649bb5a9c3eSdrh 
2650f03d9cccSdrh /*
2651f03d9cccSdrh ** Usage:  sqlite3_stmt_readonly  STMT
2652f03d9cccSdrh **
2653f03d9cccSdrh ** Return true if STMT is a NULL pointer or a pointer to a statement
2654f03d9cccSdrh ** that is guaranteed to leave the database unmodified.
2655f03d9cccSdrh */
26567617e4a8Smistachkin static int SQLITE_TCLAPI test_stmt_readonly(
2657f03d9cccSdrh   void * clientData,
2658f03d9cccSdrh   Tcl_Interp *interp,
2659f03d9cccSdrh   int objc,
2660f03d9cccSdrh   Tcl_Obj *CONST objv[]
2661f03d9cccSdrh ){
2662f03d9cccSdrh   sqlite3_stmt *pStmt;
2663f03d9cccSdrh   int rc;
2664f03d9cccSdrh 
2665f03d9cccSdrh   if( objc!=2 ){
2666f03d9cccSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
2667f03d9cccSdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT", 0);
2668f03d9cccSdrh     return TCL_ERROR;
2669f03d9cccSdrh   }
2670f03d9cccSdrh 
2671f03d9cccSdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
2672f03d9cccSdrh   rc = sqlite3_stmt_readonly(pStmt);
2673f03d9cccSdrh   Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc));
2674f03d9cccSdrh   return TCL_OK;
2675f03d9cccSdrh }
2676f03d9cccSdrh 
2677d9495cd0Sdan /*
26782fb6693eSdrh ** Usage:  sqlite3_stmt_busy  STMT
26792fb6693eSdrh **
26802fb6693eSdrh ** Return true if STMT is a non-NULL pointer to a statement
26812fb6693eSdrh ** that has been stepped but not to completion.
26822fb6693eSdrh */
26837617e4a8Smistachkin static int SQLITE_TCLAPI test_stmt_busy(
26842fb6693eSdrh   void * clientData,
26852fb6693eSdrh   Tcl_Interp *interp,
26862fb6693eSdrh   int objc,
26872fb6693eSdrh   Tcl_Obj *CONST objv[]
26882fb6693eSdrh ){
26892fb6693eSdrh   sqlite3_stmt *pStmt;
26902fb6693eSdrh   int rc;
26912fb6693eSdrh 
26922fb6693eSdrh   if( objc!=2 ){
26932fb6693eSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
26942fb6693eSdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT", 0);
26952fb6693eSdrh     return TCL_ERROR;
26962fb6693eSdrh   }
26972fb6693eSdrh 
26982fb6693eSdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
26992fb6693eSdrh   rc = sqlite3_stmt_busy(pStmt);
27002fb6693eSdrh   Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc));
27012fb6693eSdrh   return TCL_OK;
27022fb6693eSdrh }
27032fb6693eSdrh 
27042fb6693eSdrh /*
2705d9495cd0Sdan ** Usage:  uses_stmt_journal  STMT
2706d9495cd0Sdan **
2707d9495cd0Sdan ** Return true if STMT uses a statement journal.
2708d9495cd0Sdan */
27097617e4a8Smistachkin static int SQLITE_TCLAPI uses_stmt_journal(
2710d9495cd0Sdan   void * clientData,
2711d9495cd0Sdan   Tcl_Interp *interp,
2712d9495cd0Sdan   int objc,
2713d9495cd0Sdan   Tcl_Obj *CONST objv[]
2714d9495cd0Sdan ){
2715d9495cd0Sdan   sqlite3_stmt *pStmt;
2716d9495cd0Sdan 
2717d9495cd0Sdan   if( objc!=2 ){
2718d9495cd0Sdan     Tcl_AppendResult(interp, "wrong # args: should be \"",
2719d9495cd0Sdan         Tcl_GetStringFromObj(objv[0], 0), " STMT", 0);
2720d9495cd0Sdan     return TCL_ERROR;
2721d9495cd0Sdan   }
2722d9495cd0Sdan 
2723d9495cd0Sdan   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
2724caffb1a5Sdrh   sqlite3_stmt_readonly(pStmt);
2725d9495cd0Sdan   Tcl_SetObjResult(interp, Tcl_NewBooleanObj(((Vdbe *)pStmt)->usesStmtJournal));
2726d9495cd0Sdan   return TCL_OK;
2727d9495cd0Sdan }
2728d9495cd0Sdan 
2729bb5a9c3eSdrh 
2730bb5a9c3eSdrh /*
2731106bb236Sdanielk1977 ** Usage:  sqlite3_reset  STMT
2732106bb236Sdanielk1977 **
2733261919ccSdanielk1977 ** Reset a statement handle.
2734106bb236Sdanielk1977 */
27357617e4a8Smistachkin static int SQLITE_TCLAPI test_reset(
2736106bb236Sdanielk1977   void * clientData,
2737106bb236Sdanielk1977   Tcl_Interp *interp,
2738106bb236Sdanielk1977   int objc,
2739106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
2740106bb236Sdanielk1977 ){
2741106bb236Sdanielk1977   sqlite3_stmt *pStmt;
2742106bb236Sdanielk1977   int rc;
2743106bb236Sdanielk1977 
2744106bb236Sdanielk1977   if( objc!=2 ){
2745106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
2746106bb236Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
2747106bb236Sdanielk1977     return TCL_ERROR;
2748106bb236Sdanielk1977   }
2749106bb236Sdanielk1977 
2750106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
2751106bb236Sdanielk1977 
2752fc57d7bfSdanielk1977   rc = sqlite3_reset(pStmt);
2753261919ccSdanielk1977   if( pStmt && sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ){
2754261919ccSdanielk1977     return TCL_ERROR;
2755261919ccSdanielk1977   }
27564f0c5878Sdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
2757261919ccSdanielk1977 /*
2758106bb236Sdanielk1977   if( rc ){
2759b86ccfb2Sdrh     return TCL_ERROR;
2760b86ccfb2Sdrh   }
2761261919ccSdanielk1977 */
2762b86ccfb2Sdrh   return TCL_OK;
2763b86ccfb2Sdrh }
2764b86ccfb2Sdrh 
27655a38705eSdrh /*
2766d89bd007Sdrh ** Usage:  sqlite3_expired STMT
2767d89bd007Sdrh **
2768d89bd007Sdrh ** Return TRUE if a recompilation of the statement is recommended.
2769d89bd007Sdrh */
27707617e4a8Smistachkin static int SQLITE_TCLAPI test_expired(
2771d89bd007Sdrh   void * clientData,
2772d89bd007Sdrh   Tcl_Interp *interp,
2773d89bd007Sdrh   int objc,
2774d89bd007Sdrh   Tcl_Obj *CONST objv[]
2775d89bd007Sdrh ){
2776eec556d3Sshane #ifndef SQLITE_OMIT_DEPRECATED
2777d89bd007Sdrh   sqlite3_stmt *pStmt;
2778d89bd007Sdrh   if( objc!=2 ){
2779d89bd007Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
2780d89bd007Sdrh         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
2781d89bd007Sdrh     return TCL_ERROR;
2782d89bd007Sdrh   }
2783d89bd007Sdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
2784d89bd007Sdrh   Tcl_SetObjResult(interp, Tcl_NewBooleanObj(sqlite3_expired(pStmt)));
2785eec556d3Sshane #endif
2786d89bd007Sdrh   return TCL_OK;
2787d89bd007Sdrh }
2788d89bd007Sdrh 
2789d89bd007Sdrh /*
2790f8db1bc0Sdrh ** Usage:  sqlite3_transfer_bindings FROMSTMT TOSTMT
2791f8db1bc0Sdrh **
2792f8db1bc0Sdrh ** Transfer all bindings from FROMSTMT over to TOSTMT
2793f8db1bc0Sdrh */
27947617e4a8Smistachkin static int SQLITE_TCLAPI test_transfer_bind(
2795f8db1bc0Sdrh   void * clientData,
2796f8db1bc0Sdrh   Tcl_Interp *interp,
2797f8db1bc0Sdrh   int objc,
2798f8db1bc0Sdrh   Tcl_Obj *CONST objv[]
2799f8db1bc0Sdrh ){
2800eec556d3Sshane #ifndef SQLITE_OMIT_DEPRECATED
2801f8db1bc0Sdrh   sqlite3_stmt *pStmt1, *pStmt2;
2802f8db1bc0Sdrh   if( objc!=3 ){
2803f8db1bc0Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
2804f8db1bc0Sdrh         Tcl_GetStringFromObj(objv[0], 0), " FROM-STMT TO-STMT", 0);
2805f8db1bc0Sdrh     return TCL_ERROR;
2806f8db1bc0Sdrh   }
2807f8db1bc0Sdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt1)) return TCL_ERROR;
2808f8db1bc0Sdrh   if( getStmtPointer(interp, Tcl_GetString(objv[2]), &pStmt2)) return TCL_ERROR;
2809f8db1bc0Sdrh   Tcl_SetObjResult(interp,
2810f8db1bc0Sdrh      Tcl_NewIntObj(sqlite3_transfer_bindings(pStmt1,pStmt2)));
2811eec556d3Sshane #endif
2812f8db1bc0Sdrh   return TCL_OK;
2813f8db1bc0Sdrh }
2814f8db1bc0Sdrh 
2815f8db1bc0Sdrh /*
2816fbcd585fSdanielk1977 ** Usage:  sqlite3_changes DB
281750457896Sdrh **
2818fbcd585fSdanielk1977 ** Return the number of changes made to the database by the last SQL
2819fbcd585fSdanielk1977 ** execution.
282050457896Sdrh */
28217617e4a8Smistachkin static int SQLITE_TCLAPI test_changes(
2822fbcd585fSdanielk1977   void * clientData,
2823fbcd585fSdanielk1977   Tcl_Interp *interp,
2824fbcd585fSdanielk1977   int objc,
2825fbcd585fSdanielk1977   Tcl_Obj *CONST objv[]
2826fbcd585fSdanielk1977 ){
2827fbcd585fSdanielk1977   sqlite3 *db;
2828fbcd585fSdanielk1977   if( objc!=2 ){
2829fbcd585fSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
2830fbcd585fSdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
2831fbcd585fSdanielk1977     return TCL_ERROR;
2832fbcd585fSdanielk1977   }
2833fbcd585fSdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
2834fbcd585fSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_changes(db)));
2835fbcd585fSdanielk1977   return TCL_OK;
2836fbcd585fSdanielk1977 }
283750457896Sdrh 
283850457896Sdrh /*
28397c972decSdrh ** This is the "static_bind_value" that variables are bound to when
28406f8a503dSdanielk1977 ** the FLAG option of sqlite3_bind is "static"
284150457896Sdrh */
28427c972decSdrh static char *sqlite_static_bind_value = 0;
2843f0313813Sdrh static int sqlite_static_bind_nbyte = 0;
28447c972decSdrh 
28457c972decSdrh /*
28466f8a503dSdanielk1977 ** Usage:  sqlite3_bind  VM  IDX  VALUE  FLAGS
28477c972decSdrh **
2848f7b5496eSdrh ** Sets the value of the IDX-th occurrence of "?" in the original SQL
28497c972decSdrh ** string.  VALUE is the new value.  If FLAGS=="null" then VALUE is
28507c972decSdrh ** ignored and the value is set to NULL.  If FLAGS=="static" then
28517c972decSdrh ** the value is set to the value of a static variable named
28527c972decSdrh ** "sqlite_static_bind_value".  If FLAGS=="normal" then a copy
2853bf8aa2a6Sdrh ** of the VALUE is made.  If FLAGS=="blob10" then a VALUE is ignored
2854bf8aa2a6Sdrh ** an a 10-byte blob "abc\000xyz\000pq" is inserted.
28557c972decSdrh */
28567617e4a8Smistachkin static int SQLITE_TCLAPI test_bind(
285750457896Sdrh   void *NotUsed,
285850457896Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
285950457896Sdrh   int argc,              /* Number of arguments */
286050457896Sdrh   char **argv            /* Text of each argument */
286150457896Sdrh ){
2862fc57d7bfSdanielk1977   sqlite3_stmt *pStmt;
286350457896Sdrh   int rc;
28647c972decSdrh   int idx;
28657c972decSdrh   if( argc!=5 ){
286650457896Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
28677c972decSdrh        " VM IDX VALUE (null|static|normal)\"", 0);
286850457896Sdrh     return TCL_ERROR;
286950457896Sdrh   }
2870fc57d7bfSdanielk1977   if( getStmtPointer(interp, argv[1], &pStmt) ) return TCL_ERROR;
28717c972decSdrh   if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR;
28727c972decSdrh   if( strcmp(argv[4],"null")==0 ){
2873fc57d7bfSdanielk1977     rc = sqlite3_bind_null(pStmt, idx);
28747c972decSdrh   }else if( strcmp(argv[4],"static")==0 ){
2875fc57d7bfSdanielk1977     rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0);
2876f0313813Sdrh   }else if( strcmp(argv[4],"static-nbytes")==0 ){
2877f0313813Sdrh     rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value,
2878f0313813Sdrh                                        sqlite_static_bind_nbyte, 0);
28797c972decSdrh   }else if( strcmp(argv[4],"normal")==0 ){
2880d8123366Sdanielk1977     rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, SQLITE_TRANSIENT);
2881bf8aa2a6Sdrh   }else if( strcmp(argv[4],"blob10")==0 ){
2882bf8aa2a6Sdrh     rc = sqlite3_bind_text(pStmt, idx, "abc\000xyz\000pq", 10, SQLITE_STATIC);
28837c972decSdrh   }else{
28847c972decSdrh     Tcl_AppendResult(interp, "4th argument should be "
28857c972decSdrh         "\"null\" or \"static\" or \"normal\"", 0);
28867c972decSdrh     return TCL_ERROR;
28877c972decSdrh   }
2888c60d0446Sdrh   if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
288950457896Sdrh   if( rc ){
289050457896Sdrh     char zBuf[50];
289165545b59Sdrh     sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc);
2892f20b21c8Sdanielk1977     Tcl_AppendResult(interp, zBuf, sqlite3ErrStr(rc), 0);
289350457896Sdrh     return TCL_ERROR;
289450457896Sdrh   }
289550457896Sdrh   return TCL_OK;
289650457896Sdrh }
289750457896Sdrh 
28985436dc2dSdrh #ifndef SQLITE_OMIT_UTF16
28994e6af134Sdanielk1977 /*
29004e6af134Sdanielk1977 ** Usage: add_test_collate <db ptr> <utf8> <utf16le> <utf16be>
29014e6af134Sdanielk1977 **
29024e6af134Sdanielk1977 ** This function is used to test that SQLite selects the correct collation
29034e6af134Sdanielk1977 ** sequence callback when multiple versions (for different text encodings)
29044e6af134Sdanielk1977 ** are available.
29054e6af134Sdanielk1977 **
29064e6af134Sdanielk1977 ** Calling this routine registers the collation sequence "test_collate"
29074e6af134Sdanielk1977 ** with database handle <db>. The second argument must be a list of three
29084e6af134Sdanielk1977 ** boolean values. If the first is true, then a version of test_collate is
29094e6af134Sdanielk1977 ** registered for UTF-8, if the second is true, a version is registered for
29104e6af134Sdanielk1977 ** UTF-16le, if the third is true, a UTF-16be version is available.
29114e6af134Sdanielk1977 ** Previous versions of test_collate are deleted.
29124e6af134Sdanielk1977 **
29134e6af134Sdanielk1977 ** The collation sequence test_collate is implemented by calling the
29144e6af134Sdanielk1977 ** following TCL script:
29154e6af134Sdanielk1977 **
29164e6af134Sdanielk1977 **   "test_collate <enc> <lhs> <rhs>"
29174e6af134Sdanielk1977 **
29184e6af134Sdanielk1977 ** The <lhs> and <rhs> are the two values being compared, encoded in UTF-8.
29194e6af134Sdanielk1977 ** The <enc> parameter is the encoding of the collation function that
29204e6af134Sdanielk1977 ** SQLite selected to call. The TCL test script implements the
29214e6af134Sdanielk1977 ** "test_collate" proc.
29224e6af134Sdanielk1977 **
292360ec914cSpeter.d.reid ** Note that this will only work with one interpreter at a time, as the
29244e6af134Sdanielk1977 ** interp pointer to use when evaluating the TCL script is stored in
29254e6af134Sdanielk1977 ** pTestCollateInterp.
29264e6af134Sdanielk1977 */
29274e6af134Sdanielk1977 static Tcl_Interp* pTestCollateInterp;
29284e6af134Sdanielk1977 static int test_collate_func(
29294e6af134Sdanielk1977   void *pCtx,
29304e6af134Sdanielk1977   int nA, const void *zA,
29314e6af134Sdanielk1977   int nB, const void *zB
29324e6af134Sdanielk1977 ){
29334e6af134Sdanielk1977   Tcl_Interp *i = pTestCollateInterp;
2934d2199f0fSdan   int encin = SQLITE_PTR_TO_INT(pCtx);
29354e6af134Sdanielk1977   int res;
29364db38a70Sdrh   int n;
29374e6af134Sdanielk1977 
29384e6af134Sdanielk1977   sqlite3_value *pVal;
29394e6af134Sdanielk1977   Tcl_Obj *pX;
29404e6af134Sdanielk1977 
29414e6af134Sdanielk1977   pX = Tcl_NewStringObj("test_collate", -1);
29424e6af134Sdanielk1977   Tcl_IncrRefCount(pX);
29434e6af134Sdanielk1977 
29444e6af134Sdanielk1977   switch( encin ){
29454e6af134Sdanielk1977     case SQLITE_UTF8:
29464e6af134Sdanielk1977       Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-8",-1));
29474e6af134Sdanielk1977       break;
29484e6af134Sdanielk1977     case SQLITE_UTF16LE:
29494e6af134Sdanielk1977       Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-16LE",-1));
29504e6af134Sdanielk1977       break;
29514e6af134Sdanielk1977     case SQLITE_UTF16BE:
29524e6af134Sdanielk1977       Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-16BE",-1));
29534e6af134Sdanielk1977       break;
29544e6af134Sdanielk1977     default:
29554e6af134Sdanielk1977       assert(0);
29564e6af134Sdanielk1977   }
29574e6af134Sdanielk1977 
295802fa4696Sdan   sqlite3BeginBenignMalloc();
29591e536953Sdanielk1977   pVal = sqlite3ValueNew(0);
296002fa4696Sdan   if( pVal ){
2961b21c8cd4Sdrh     sqlite3ValueSetStr(pVal, nA, zA, encin, SQLITE_STATIC);
29624db38a70Sdrh     n = sqlite3_value_bytes(pVal);
296303d847eaSdrh     Tcl_ListObjAppendElement(i,pX,
296403d847eaSdrh         Tcl_NewStringObj((char*)sqlite3_value_text(pVal),n));
2965b21c8cd4Sdrh     sqlite3ValueSetStr(pVal, nB, zB, encin, SQLITE_STATIC);
29664db38a70Sdrh     n = sqlite3_value_bytes(pVal);
296703d847eaSdrh     Tcl_ListObjAppendElement(i,pX,
296803d847eaSdrh         Tcl_NewStringObj((char*)sqlite3_value_text(pVal),n));
29694e6af134Sdanielk1977     sqlite3ValueFree(pVal);
297002fa4696Sdan   }
297102fa4696Sdan   sqlite3EndBenignMalloc();
29724e6af134Sdanielk1977 
29734e6af134Sdanielk1977   Tcl_EvalObjEx(i, pX, 0);
29744e6af134Sdanielk1977   Tcl_DecrRefCount(pX);
29754e6af134Sdanielk1977   Tcl_GetIntFromObj(i, Tcl_GetObjResult(i), &res);
29764e6af134Sdanielk1977   return res;
29774e6af134Sdanielk1977 }
29787617e4a8Smistachkin static int SQLITE_TCLAPI test_collate(
29794e6af134Sdanielk1977   void * clientData,
29804e6af134Sdanielk1977   Tcl_Interp *interp,
29814e6af134Sdanielk1977   int objc,
29824e6af134Sdanielk1977   Tcl_Obj *CONST objv[]
29834e6af134Sdanielk1977 ){
29844e6af134Sdanielk1977   sqlite3 *db;
29854e6af134Sdanielk1977   int val;
2986312d6b36Sdanielk1977   sqlite3_value *pVal;
2987c60d0446Sdrh   int rc;
29884e6af134Sdanielk1977 
29894e6af134Sdanielk1977   if( objc!=5 ) goto bad_args;
29904e6af134Sdanielk1977   pTestCollateInterp = interp;
29914e6af134Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
29924e6af134Sdanielk1977 
29934e6af134Sdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR;
2994c60d0446Sdrh   rc = sqlite3_create_collation(db, "test_collate", SQLITE_UTF8,
29954e6af134Sdanielk1977           (void *)SQLITE_UTF8, val?test_collate_func:0);
2996c60d0446Sdrh   if( rc==SQLITE_OK ){
2997eee4c8caSdrh     const void *zUtf16;
29984e6af134Sdanielk1977     if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &val) ) return TCL_ERROR;
2999c60d0446Sdrh     rc = sqlite3_create_collation(db, "test_collate", SQLITE_UTF16LE,
30004e6af134Sdanielk1977             (void *)SQLITE_UTF16LE, val?test_collate_func:0);
30014e6af134Sdanielk1977     if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[4], &val) ) return TCL_ERROR;
3002312d6b36Sdanielk1977 
300386f8c197Sdrh #if 0
30049a30cf65Sdanielk1977     if( sqlite3_iMallocFail>0 ){
30059a30cf65Sdanielk1977       sqlite3_iMallocFail++;
30069a30cf65Sdanielk1977     }
30079a30cf65Sdanielk1977 #endif
3008f3a65f7eSdrh     sqlite3_mutex_enter(db->mutex);
3009f3a65f7eSdrh     pVal = sqlite3ValueNew(db);
3010b21c8cd4Sdrh     sqlite3ValueSetStr(pVal, -1, "test_collate", SQLITE_UTF8, SQLITE_STATIC);
3011a7a8e14bSdanielk1977     zUtf16 = sqlite3ValueText(pVal, SQLITE_UTF16NATIVE);
3012f3a65f7eSdrh     if( db->mallocFailed ){
3013f3a65f7eSdrh       rc = SQLITE_NOMEM;
3014f3a65f7eSdrh     }else{
3015a7a8e14bSdanielk1977       rc = sqlite3_create_collation16(db, zUtf16, SQLITE_UTF16BE,
30169a30cf65Sdanielk1977           (void *)SQLITE_UTF16BE, val?test_collate_func:0);
3017f3a65f7eSdrh     }
3018312d6b36Sdanielk1977     sqlite3ValueFree(pVal);
3019f3a65f7eSdrh     sqlite3_mutex_leave(db->mutex);
3020c60d0446Sdrh   }
3021c60d0446Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
30229a30cf65Sdanielk1977 
30239a30cf65Sdanielk1977   if( rc!=SQLITE_OK ){
3024e84d8d32Smistachkin     Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
30259a30cf65Sdanielk1977     return TCL_ERROR;
30269a30cf65Sdanielk1977   }
30274e6af134Sdanielk1977   return TCL_OK;
30284e6af134Sdanielk1977 
30294e6af134Sdanielk1977 bad_args:
30304e6af134Sdanielk1977   Tcl_AppendResult(interp, "wrong # args: should be \"",
30314e6af134Sdanielk1977       Tcl_GetStringFromObj(objv[0], 0), " <DB> <utf8> <utf16le> <utf16be>", 0);
30324e6af134Sdanielk1977   return TCL_ERROR;
30334e6af134Sdanielk1977 }
30344e6af134Sdanielk1977 
3035268803a9Sdrh /*
303638fdead8Sdan ** Usage: add_test_utf16bin_collate <db ptr>
303738fdead8Sdan **
303838fdead8Sdan ** Add a utf-16 collation sequence named "utf16bin" to the database
303938fdead8Sdan ** handle. This collation sequence compares arguments in the same way as the
304038fdead8Sdan ** built-in collation "binary".
304138fdead8Sdan */
304238fdead8Sdan static int test_utf16bin_collate_func(
304338fdead8Sdan   void *pCtx,
304438fdead8Sdan   int nA, const void *zA,
304538fdead8Sdan   int nB, const void *zB
304638fdead8Sdan ){
304738fdead8Sdan   int nCmp = (nA>nB ? nB : nA);
304838fdead8Sdan   int res = memcmp(zA, zB, nCmp);
304938fdead8Sdan   if( res==0 ) res = nA - nB;
305038fdead8Sdan   return res;
305138fdead8Sdan }
30527617e4a8Smistachkin static int SQLITE_TCLAPI test_utf16bin_collate(
305338fdead8Sdan   void * clientData,
305438fdead8Sdan   Tcl_Interp *interp,
305538fdead8Sdan   int objc,
305638fdead8Sdan   Tcl_Obj *CONST objv[]
305738fdead8Sdan ){
305838fdead8Sdan   sqlite3 *db;
305938fdead8Sdan   int rc;
306038fdead8Sdan 
306138fdead8Sdan   if( objc!=2 ) goto bad_args;
306238fdead8Sdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
306338fdead8Sdan 
306438fdead8Sdan   rc = sqlite3_create_collation(db, "utf16bin", SQLITE_UTF16, 0,
306538fdead8Sdan       test_utf16bin_collate_func
306638fdead8Sdan   );
306738fdead8Sdan   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
306838fdead8Sdan   return TCL_OK;
306938fdead8Sdan 
307038fdead8Sdan bad_args:
307138fdead8Sdan   Tcl_WrongNumArgs(interp, 1, objv, "DB");
307238fdead8Sdan   return TCL_ERROR;
307338fdead8Sdan }
307438fdead8Sdan 
307538fdead8Sdan /*
3076268803a9Sdrh ** When the collation needed callback is invoked, record the name of
3077268803a9Sdrh ** the requested collating function here.  The recorded name is linked
3078268803a9Sdrh ** to a TCL variable and used to make sure that the requested collation
3079268803a9Sdrh ** name is correct.
3080268803a9Sdrh */
3081268803a9Sdrh static char zNeededCollation[200];
3082268803a9Sdrh static char *pzNeededCollation = zNeededCollation;
3083268803a9Sdrh 
3084268803a9Sdrh 
3085268803a9Sdrh /*
3086268803a9Sdrh ** Called when a collating sequence is needed.  Registered using
3087268803a9Sdrh ** sqlite3_collation_needed16().
3088268803a9Sdrh */
3089312d6b36Sdanielk1977 static void test_collate_needed_cb(
3090312d6b36Sdanielk1977   void *pCtx,
3091312d6b36Sdanielk1977   sqlite3 *db,
3092312d6b36Sdanielk1977   int eTextRep,
3093268803a9Sdrh   const void *pName
3094312d6b36Sdanielk1977 ){
309514db2665Sdanielk1977   int enc = ENC(db);
3096268803a9Sdrh   int i;
3097268803a9Sdrh   char *z;
3098268803a9Sdrh   for(z = (char*)pName, i=0; *z || z[1]; z++){
3099268803a9Sdrh     if( *z ) zNeededCollation[i++] = *z;
3100268803a9Sdrh   }
3101268803a9Sdrh   zNeededCollation[i] = 0;
3102312d6b36Sdanielk1977   sqlite3_create_collation(
3103d2199f0fSdan       db, "test_collate", ENC(db), SQLITE_INT_TO_PTR(enc), test_collate_func);
3104312d6b36Sdanielk1977 }
3105312d6b36Sdanielk1977 
3106312d6b36Sdanielk1977 /*
3107312d6b36Sdanielk1977 ** Usage: add_test_collate_needed DB
3108312d6b36Sdanielk1977 */
31097617e4a8Smistachkin static int SQLITE_TCLAPI test_collate_needed(
3110312d6b36Sdanielk1977   void * clientData,
3111312d6b36Sdanielk1977   Tcl_Interp *interp,
3112312d6b36Sdanielk1977   int objc,
3113312d6b36Sdanielk1977   Tcl_Obj *CONST objv[]
3114312d6b36Sdanielk1977 ){
3115312d6b36Sdanielk1977   sqlite3 *db;
3116c60d0446Sdrh   int rc;
3117312d6b36Sdanielk1977 
3118312d6b36Sdanielk1977   if( objc!=2 ) goto bad_args;
3119312d6b36Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
3120c60d0446Sdrh   rc = sqlite3_collation_needed16(db, 0, test_collate_needed_cb);
3121268803a9Sdrh   zNeededCollation[0] = 0;
3122c60d0446Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
3123312d6b36Sdanielk1977   return TCL_OK;
3124312d6b36Sdanielk1977 
3125312d6b36Sdanielk1977 bad_args:
3126312d6b36Sdanielk1977   Tcl_WrongNumArgs(interp, 1, objv, "DB");
3127312d6b36Sdanielk1977   return TCL_ERROR;
3128312d6b36Sdanielk1977 }
31297d9bd4e1Sdrh 
31307d9bd4e1Sdrh /*
31317d9bd4e1Sdrh ** tclcmd:   add_alignment_test_collations  DB
31327d9bd4e1Sdrh **
31337d9bd4e1Sdrh ** Add two new collating sequences to the database DB
31347d9bd4e1Sdrh **
31357d9bd4e1Sdrh **     utf16_aligned
31367d9bd4e1Sdrh **     utf16_unaligned
31377d9bd4e1Sdrh **
31387d9bd4e1Sdrh ** Both collating sequences use the same sort order as BINARY.
31397d9bd4e1Sdrh ** The only difference is that the utf16_aligned collating
31407d9bd4e1Sdrh ** sequence is declared with the SQLITE_UTF16_ALIGNED flag.
31417d9bd4e1Sdrh ** Both collating functions increment the unaligned utf16 counter
31427d9bd4e1Sdrh ** whenever they see a string that begins on an odd byte boundary.
31437d9bd4e1Sdrh */
31447d9bd4e1Sdrh static int unaligned_string_counter = 0;
31457d9bd4e1Sdrh static int alignmentCollFunc(
31467d9bd4e1Sdrh   void *NotUsed,
31477d9bd4e1Sdrh   int nKey1, const void *pKey1,
31487d9bd4e1Sdrh   int nKey2, const void *pKey2
31497d9bd4e1Sdrh ){
31507d9bd4e1Sdrh   int rc, n;
31517d9bd4e1Sdrh   n = nKey1<nKey2 ? nKey1 : nKey2;
3152d2199f0fSdan   if( nKey1>0 && 1==(1&(SQLITE_PTR_TO_INT(pKey1))) ) unaligned_string_counter++;
3153d2199f0fSdan   if( nKey2>0 && 1==(1&(SQLITE_PTR_TO_INT(pKey2))) ) unaligned_string_counter++;
31547d9bd4e1Sdrh   rc = memcmp(pKey1, pKey2, n);
31557d9bd4e1Sdrh   if( rc==0 ){
31567d9bd4e1Sdrh     rc = nKey1 - nKey2;
31577d9bd4e1Sdrh   }
31587d9bd4e1Sdrh   return rc;
31597d9bd4e1Sdrh }
31607617e4a8Smistachkin static int SQLITE_TCLAPI add_alignment_test_collations(
31617d9bd4e1Sdrh   void * clientData,
31627d9bd4e1Sdrh   Tcl_Interp *interp,
31637d9bd4e1Sdrh   int objc,
31647d9bd4e1Sdrh   Tcl_Obj *CONST objv[]
31657d9bd4e1Sdrh ){
31667d9bd4e1Sdrh   sqlite3 *db;
31677d9bd4e1Sdrh   if( objc>=2 ){
31687d9bd4e1Sdrh     if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
3169ebb32939Sdanielk1977     sqlite3_create_collation(db, "utf16_unaligned", SQLITE_UTF16,
31707d9bd4e1Sdrh         0, alignmentCollFunc);
3171ebb32939Sdanielk1977     sqlite3_create_collation(db, "utf16_aligned", SQLITE_UTF16_ALIGNED,
31727d9bd4e1Sdrh         0, alignmentCollFunc);
31737d9bd4e1Sdrh   }
31747d9bd4e1Sdrh   return SQLITE_OK;
31757d9bd4e1Sdrh }
31767d9bd4e1Sdrh #endif /* !defined(SQLITE_OMIT_UTF16) */
3177312d6b36Sdanielk1977 
3178c8e9a2dfSdanielk1977 /*
3179c8e9a2dfSdanielk1977 ** Usage: add_test_function <db ptr> <utf8> <utf16le> <utf16be>
3180c8e9a2dfSdanielk1977 **
3181c8e9a2dfSdanielk1977 ** This function is used to test that SQLite selects the correct user
3182c8e9a2dfSdanielk1977 ** function callback when multiple versions (for different text encodings)
3183c8e9a2dfSdanielk1977 ** are available.
3184c8e9a2dfSdanielk1977 **
3185c8e9a2dfSdanielk1977 ** Calling this routine registers up to three versions of the user function
3186c8e9a2dfSdanielk1977 ** "test_function" with database handle <db>.  If the second argument is
3187c8e9a2dfSdanielk1977 ** true, then a version of test_function is registered for UTF-8, if the
3188c8e9a2dfSdanielk1977 ** third is true, a version is registered for UTF-16le, if the fourth is
3189c8e9a2dfSdanielk1977 ** true, a UTF-16be version is available.  Previous versions of
3190c8e9a2dfSdanielk1977 ** test_function are deleted.
3191c8e9a2dfSdanielk1977 **
3192c8e9a2dfSdanielk1977 ** The user function is implemented by calling the following TCL script:
3193c8e9a2dfSdanielk1977 **
3194c8e9a2dfSdanielk1977 **   "test_function <enc> <arg>"
3195c8e9a2dfSdanielk1977 **
3196c8e9a2dfSdanielk1977 ** Where <enc> is one of UTF-8, UTF-16LE or UTF16BE, and <arg> is the
3197c8e9a2dfSdanielk1977 ** single argument passed to the SQL function. The value returned by
3198c8e9a2dfSdanielk1977 ** the TCL script is used as the return value of the SQL function. It
3199c8e9a2dfSdanielk1977 ** is passed to SQLite using UTF-16BE for a UTF-8 test_function(), UTF-8
3200c8e9a2dfSdanielk1977 ** for a UTF-16LE test_function(), and UTF-16LE for an implementation that
3201c8e9a2dfSdanielk1977 ** prefers UTF-16BE.
3202c8e9a2dfSdanielk1977 */
32035436dc2dSdrh #ifndef SQLITE_OMIT_UTF16
3204c8e9a2dfSdanielk1977 static void test_function_utf8(
3205c8e9a2dfSdanielk1977   sqlite3_context *pCtx,
3206c8e9a2dfSdanielk1977   int nArg,
3207c8e9a2dfSdanielk1977   sqlite3_value **argv
3208c8e9a2dfSdanielk1977 ){
3209c8e9a2dfSdanielk1977   Tcl_Interp *interp;
3210c8e9a2dfSdanielk1977   Tcl_Obj *pX;
3211c8e9a2dfSdanielk1977   sqlite3_value *pVal;
3212c8e9a2dfSdanielk1977   interp = (Tcl_Interp *)sqlite3_user_data(pCtx);
3213c8e9a2dfSdanielk1977   pX = Tcl_NewStringObj("test_function", -1);
3214c8e9a2dfSdanielk1977   Tcl_IncrRefCount(pX);
3215c8e9a2dfSdanielk1977   Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj("UTF-8", -1));
3216c8e9a2dfSdanielk1977   Tcl_ListObjAppendElement(interp, pX,
321703d847eaSdrh       Tcl_NewStringObj((char*)sqlite3_value_text(argv[0]), -1));
3218c8e9a2dfSdanielk1977   Tcl_EvalObjEx(interp, pX, 0);
3219c8e9a2dfSdanielk1977   Tcl_DecrRefCount(pX);
3220c8e9a2dfSdanielk1977   sqlite3_result_text(pCtx, Tcl_GetStringResult(interp), -1, SQLITE_TRANSIENT);
32211e536953Sdanielk1977   pVal = sqlite3ValueNew(0);
3222b21c8cd4Sdrh   sqlite3ValueSetStr(pVal, -1, Tcl_GetStringResult(interp),
3223c8e9a2dfSdanielk1977       SQLITE_UTF8, SQLITE_STATIC);
3224c8e9a2dfSdanielk1977   sqlite3_result_text16be(pCtx, sqlite3_value_text16be(pVal),
3225c8e9a2dfSdanielk1977       -1, SQLITE_TRANSIENT);
3226c8e9a2dfSdanielk1977   sqlite3ValueFree(pVal);
3227c8e9a2dfSdanielk1977 }
3228c8e9a2dfSdanielk1977 static void test_function_utf16le(
3229c8e9a2dfSdanielk1977   sqlite3_context *pCtx,
3230c8e9a2dfSdanielk1977   int nArg,
3231c8e9a2dfSdanielk1977   sqlite3_value **argv
3232c8e9a2dfSdanielk1977 ){
3233c8e9a2dfSdanielk1977   Tcl_Interp *interp;
3234c8e9a2dfSdanielk1977   Tcl_Obj *pX;
3235c8e9a2dfSdanielk1977   sqlite3_value *pVal;
3236c8e9a2dfSdanielk1977   interp = (Tcl_Interp *)sqlite3_user_data(pCtx);
3237c8e9a2dfSdanielk1977   pX = Tcl_NewStringObj("test_function", -1);
3238c8e9a2dfSdanielk1977   Tcl_IncrRefCount(pX);
3239c8e9a2dfSdanielk1977   Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj("UTF-16LE", -1));
3240c8e9a2dfSdanielk1977   Tcl_ListObjAppendElement(interp, pX,
324103d847eaSdrh       Tcl_NewStringObj((char*)sqlite3_value_text(argv[0]), -1));
3242c8e9a2dfSdanielk1977   Tcl_EvalObjEx(interp, pX, 0);
3243c8e9a2dfSdanielk1977   Tcl_DecrRefCount(pX);
32441e536953Sdanielk1977   pVal = sqlite3ValueNew(0);
3245b21c8cd4Sdrh   sqlite3ValueSetStr(pVal, -1, Tcl_GetStringResult(interp),
3246c8e9a2dfSdanielk1977       SQLITE_UTF8, SQLITE_STATIC);
324703d847eaSdrh   sqlite3_result_text(pCtx,(char*)sqlite3_value_text(pVal),-1,SQLITE_TRANSIENT);
3248c8e9a2dfSdanielk1977   sqlite3ValueFree(pVal);
3249c8e9a2dfSdanielk1977 }
3250c8e9a2dfSdanielk1977 static void test_function_utf16be(
3251c8e9a2dfSdanielk1977   sqlite3_context *pCtx,
3252c8e9a2dfSdanielk1977   int nArg,
3253c8e9a2dfSdanielk1977   sqlite3_value **argv
3254c8e9a2dfSdanielk1977 ){
3255c8e9a2dfSdanielk1977   Tcl_Interp *interp;
3256c8e9a2dfSdanielk1977   Tcl_Obj *pX;
3257c8e9a2dfSdanielk1977   sqlite3_value *pVal;
3258c8e9a2dfSdanielk1977   interp = (Tcl_Interp *)sqlite3_user_data(pCtx);
3259c8e9a2dfSdanielk1977   pX = Tcl_NewStringObj("test_function", -1);
3260c8e9a2dfSdanielk1977   Tcl_IncrRefCount(pX);
3261c8e9a2dfSdanielk1977   Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj("UTF-16BE", -1));
3262c8e9a2dfSdanielk1977   Tcl_ListObjAppendElement(interp, pX,
326303d847eaSdrh       Tcl_NewStringObj((char*)sqlite3_value_text(argv[0]), -1));
3264c8e9a2dfSdanielk1977   Tcl_EvalObjEx(interp, pX, 0);
3265c8e9a2dfSdanielk1977   Tcl_DecrRefCount(pX);
32661e536953Sdanielk1977   pVal = sqlite3ValueNew(0);
3267b21c8cd4Sdrh   sqlite3ValueSetStr(pVal, -1, Tcl_GetStringResult(interp),
3268c8e9a2dfSdanielk1977       SQLITE_UTF8, SQLITE_STATIC);
3269de4fcfddSdrh   sqlite3_result_text16(pCtx, sqlite3_value_text16le(pVal),
3270de4fcfddSdrh       -1, SQLITE_TRANSIENT);
3271de4fcfddSdrh   sqlite3_result_text16be(pCtx, sqlite3_value_text16le(pVal),
3272de4fcfddSdrh       -1, SQLITE_TRANSIENT);
3273c8e9a2dfSdanielk1977   sqlite3_result_text16le(pCtx, sqlite3_value_text16le(pVal),
3274c8e9a2dfSdanielk1977       -1, SQLITE_TRANSIENT);
3275c8e9a2dfSdanielk1977   sqlite3ValueFree(pVal);
3276c8e9a2dfSdanielk1977 }
32775436dc2dSdrh #endif /* SQLITE_OMIT_UTF16 */
32787617e4a8Smistachkin static int SQLITE_TCLAPI test_function(
3279c8e9a2dfSdanielk1977   void * clientData,
3280c8e9a2dfSdanielk1977   Tcl_Interp *interp,
3281c8e9a2dfSdanielk1977   int objc,
3282c8e9a2dfSdanielk1977   Tcl_Obj *CONST objv[]
3283c8e9a2dfSdanielk1977 ){
32845436dc2dSdrh #ifndef SQLITE_OMIT_UTF16
3285c8e9a2dfSdanielk1977   sqlite3 *db;
3286c8e9a2dfSdanielk1977   int val;
3287c8e9a2dfSdanielk1977 
3288c8e9a2dfSdanielk1977   if( objc!=5 ) goto bad_args;
3289c8e9a2dfSdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
3290c8e9a2dfSdanielk1977 
3291c8e9a2dfSdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR;
3292c8e9a2dfSdanielk1977   if( val ){
3293c8e9a2dfSdanielk1977     sqlite3_create_function(db, "test_function", 1, SQLITE_UTF8,
3294c8e9a2dfSdanielk1977         interp, test_function_utf8, 0, 0);
3295c8e9a2dfSdanielk1977   }
3296c8e9a2dfSdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &val) ) return TCL_ERROR;
3297c8e9a2dfSdanielk1977   if( val ){
3298c8e9a2dfSdanielk1977     sqlite3_create_function(db, "test_function", 1, SQLITE_UTF16LE,
3299c8e9a2dfSdanielk1977         interp, test_function_utf16le, 0, 0);
3300c8e9a2dfSdanielk1977   }
3301c8e9a2dfSdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[4], &val) ) return TCL_ERROR;
3302c8e9a2dfSdanielk1977   if( val ){
3303c8e9a2dfSdanielk1977     sqlite3_create_function(db, "test_function", 1, SQLITE_UTF16BE,
3304c8e9a2dfSdanielk1977         interp, test_function_utf16be, 0, 0);
3305c8e9a2dfSdanielk1977   }
3306c8e9a2dfSdanielk1977 
3307c8e9a2dfSdanielk1977   return TCL_OK;
3308c8e9a2dfSdanielk1977 bad_args:
3309c8e9a2dfSdanielk1977   Tcl_AppendResult(interp, "wrong # args: should be \"",
3310c8e9a2dfSdanielk1977       Tcl_GetStringFromObj(objv[0], 0), " <DB> <utf8> <utf16le> <utf16be>", 0);
33115436dc2dSdrh #endif /* SQLITE_OMIT_UTF16 */
3312c8e9a2dfSdanielk1977   return TCL_ERROR;
3313c8e9a2dfSdanielk1977 }
3314c8e9a2dfSdanielk1977 
3315312d6b36Sdanielk1977 /*
3316ba3cbf3dSdan ** Usage:         sqlite3_test_errstr <err code>
3317312d6b36Sdanielk1977 **
3318312d6b36Sdanielk1977 ** Test that the english language string equivalents for sqlite error codes
3319312d6b36Sdanielk1977 ** are sane. The parameter is an integer representing an sqlite error code.
3320312d6b36Sdanielk1977 ** The result is a list of two elements, the string representation of the
3321312d6b36Sdanielk1977 ** error code and the english language explanation.
3322312d6b36Sdanielk1977 */
33237617e4a8Smistachkin static int SQLITE_TCLAPI test_errstr(
3324312d6b36Sdanielk1977   void * clientData,
3325312d6b36Sdanielk1977   Tcl_Interp *interp,
3326312d6b36Sdanielk1977   int objc,
3327312d6b36Sdanielk1977   Tcl_Obj *CONST objv[]
3328312d6b36Sdanielk1977 ){
3329312d6b36Sdanielk1977   char *zCode;
3330312d6b36Sdanielk1977   int i;
3331312d6b36Sdanielk1977   if( objc!=1 ){
3332312d6b36Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "<error code>");
3333312d6b36Sdanielk1977   }
3334312d6b36Sdanielk1977 
3335312d6b36Sdanielk1977   zCode = Tcl_GetString(objv[1]);
3336312d6b36Sdanielk1977   for(i=0; i<200; i++){
33374f0c5878Sdrh     if( 0==strcmp(t1ErrorName(i), zCode) ) break;
3338312d6b36Sdanielk1977   }
3339312d6b36Sdanielk1977   Tcl_SetResult(interp, (char *)sqlite3ErrStr(i), 0);
3340312d6b36Sdanielk1977   return TCL_OK;
3341312d6b36Sdanielk1977 }
3342312d6b36Sdanielk1977 
334350457896Sdrh /*
334499ee3600Sdrh ** Usage:    breakpoint
334599ee3600Sdrh **
334699ee3600Sdrh ** This routine exists for one purpose - to provide a place to put a
334799ee3600Sdrh ** breakpoint with GDB that can be triggered using TCL code.  The use
334899ee3600Sdrh ** for this is when a particular test fails on (say) the 1485th iteration.
334999ee3600Sdrh ** In the TCL test script, we can add code like this:
335099ee3600Sdrh **
335199ee3600Sdrh **     if {$i==1485} breakpoint
335299ee3600Sdrh **
335399ee3600Sdrh ** Then run testfixture in the debugger and wait for the breakpoint to
335499ee3600Sdrh ** fire.  Then additional breakpoints can be set to trace down the bug.
335599ee3600Sdrh */
33567617e4a8Smistachkin static int SQLITE_TCLAPI test_breakpoint(
335799ee3600Sdrh   void *NotUsed,
335899ee3600Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
335999ee3600Sdrh   int argc,              /* Number of arguments */
336099ee3600Sdrh   char **argv            /* Text of each argument */
336199ee3600Sdrh ){
336299ee3600Sdrh   return TCL_OK;         /* Do nothing */
336399ee3600Sdrh }
336499ee3600Sdrh 
3365241db313Sdrh /*
3366b026e05eSdrh ** Usage:   sqlite3_bind_zeroblob  STMT IDX N
3367b026e05eSdrh **
3368b026e05eSdrh ** Test the sqlite3_bind_zeroblob interface.  STMT is a prepared statement.
3369b026e05eSdrh ** IDX is the index of a wildcard in the prepared statement.  This command
3370b026e05eSdrh ** binds a N-byte zero-filled BLOB to the wildcard.
3371b026e05eSdrh */
33727617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_zeroblob(
3373b026e05eSdrh   void * clientData,
3374b026e05eSdrh   Tcl_Interp *interp,
3375b026e05eSdrh   int objc,
3376b026e05eSdrh   Tcl_Obj *CONST objv[]
3377b026e05eSdrh ){
3378b026e05eSdrh   sqlite3_stmt *pStmt;
3379b026e05eSdrh   int idx;
3380b026e05eSdrh   int n;
3381b026e05eSdrh   int rc;
3382b026e05eSdrh 
3383b026e05eSdrh   if( objc!=4 ){
338428c66307Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "STMT IDX N");
3385b026e05eSdrh     return TCL_ERROR;
3386b026e05eSdrh   }
3387b026e05eSdrh 
3388b026e05eSdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
3389b026e05eSdrh   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
3390b026e05eSdrh   if( Tcl_GetIntFromObj(interp, objv[3], &n) ) return TCL_ERROR;
3391b026e05eSdrh 
3392b026e05eSdrh   rc = sqlite3_bind_zeroblob(pStmt, idx, n);
3393b026e05eSdrh   if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
3394b026e05eSdrh   if( rc!=SQLITE_OK ){
3395b026e05eSdrh     return TCL_ERROR;
3396b026e05eSdrh   }
3397b026e05eSdrh 
3398b026e05eSdrh   return TCL_OK;
3399b026e05eSdrh }
3400b026e05eSdrh 
3401b026e05eSdrh /*
340280c03022Sdan ** Usage:   sqlite3_bind_zeroblob64  STMT IDX N
340380c03022Sdan **
340480c03022Sdan ** Test the sqlite3_bind_zeroblob64 interface.  STMT is a prepared statement.
340580c03022Sdan ** IDX is the index of a wildcard in the prepared statement.  This command
340680c03022Sdan ** binds a N-byte zero-filled BLOB to the wildcard.
340780c03022Sdan */
34087617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_zeroblob64(
340980c03022Sdan   void * clientData,
341080c03022Sdan   Tcl_Interp *interp,
341180c03022Sdan   int objc,
341280c03022Sdan   Tcl_Obj *CONST objv[]
341380c03022Sdan ){
341480c03022Sdan   sqlite3_stmt *pStmt;
341580c03022Sdan   int idx;
34169a1e85eeSdrh   Tcl_WideInt n;
341780c03022Sdan   int rc;
341880c03022Sdan 
341980c03022Sdan   if( objc!=4 ){
342080c03022Sdan     Tcl_WrongNumArgs(interp, 1, objv, "STMT IDX N");
342180c03022Sdan     return TCL_ERROR;
342280c03022Sdan   }
342380c03022Sdan 
342480c03022Sdan   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
342580c03022Sdan   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
342680c03022Sdan   if( Tcl_GetWideIntFromObj(interp, objv[3], &n) ) return TCL_ERROR;
342780c03022Sdan 
342880c03022Sdan   rc = sqlite3_bind_zeroblob64(pStmt, idx, n);
342980c03022Sdan   if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
343080c03022Sdan   if( rc!=SQLITE_OK ){
343180c03022Sdan     Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
343280c03022Sdan     return TCL_ERROR;
343380c03022Sdan   }
343480c03022Sdan 
343580c03022Sdan   return TCL_OK;
343680c03022Sdan }
343780c03022Sdan 
343880c03022Sdan /*
3439241db313Sdrh ** Usage:   sqlite3_bind_int  STMT N VALUE
3440241db313Sdrh **
3441241db313Sdrh ** Test the sqlite3_bind_int interface.  STMT is a prepared statement.
3442241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
3443241db313Sdrh ** binds a 32-bit integer VALUE to that wildcard.
3444241db313Sdrh */
34457617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_int(
344651e3d8e2Sdanielk1977   void * clientData,
344751e3d8e2Sdanielk1977   Tcl_Interp *interp,
344851e3d8e2Sdanielk1977   int objc,
344951e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
345051e3d8e2Sdanielk1977 ){
345151e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
345251e3d8e2Sdanielk1977   int idx;
345351e3d8e2Sdanielk1977   int value;
345451e3d8e2Sdanielk1977   int rc;
345551e3d8e2Sdanielk1977 
345651e3d8e2Sdanielk1977   if( objc!=4 ){
345751e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
3458241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0);
345951e3d8e2Sdanielk1977     return TCL_ERROR;
346051e3d8e2Sdanielk1977   }
346151e3d8e2Sdanielk1977 
346251e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
346351e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
346451e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &value) ) return TCL_ERROR;
346551e3d8e2Sdanielk1977 
3466c572ef7fSdanielk1977   rc = sqlite3_bind_int(pStmt, idx, value);
3467c60d0446Sdrh   if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
346851e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
346951e3d8e2Sdanielk1977     return TCL_ERROR;
347051e3d8e2Sdanielk1977   }
347151e3d8e2Sdanielk1977 
347251e3d8e2Sdanielk1977   return TCL_OK;
347351e3d8e2Sdanielk1977 }
347451e3d8e2Sdanielk1977 
3475241db313Sdrh 
3476241db313Sdrh /*
34772e3f87aeSdrh ** Usage:   intarray_addr  INT  ...
34784841624aSdrh **
34792e3f87aeSdrh ** Return the address of a C-language array of 32-bit integers.
34802e3f87aeSdrh **
34812e3f87aeSdrh ** Space to hold the array is obtained from malloc().  Call this procedure once
34822e3f87aeSdrh ** with no arguments in order to release memory.  Each call to this procedure
34832e3f87aeSdrh ** overwrites the previous array.
34844841624aSdrh */
34857617e4a8Smistachkin static int SQLITE_TCLAPI test_intarray_addr(
34864841624aSdrh   void * clientData,
34874841624aSdrh   Tcl_Interp *interp,
34884841624aSdrh   int objc,
34894841624aSdrh   Tcl_Obj *CONST objv[]
34904841624aSdrh ){
34914841624aSdrh   int i;
34924841624aSdrh   static int *p = 0;
34934841624aSdrh 
34944841624aSdrh   sqlite3_free(p);
34954841624aSdrh   p = 0;
34962e3f87aeSdrh   if( objc>1 ){
34972e3f87aeSdrh     p = sqlite3_malloc( sizeof(p[0])*(objc-1) );
34984841624aSdrh     if( p==0 ) return TCL_ERROR;
34992e3f87aeSdrh     for(i=0; i<objc-1; i++){
35002e3f87aeSdrh       if( Tcl_GetIntFromObj(interp, objv[1+i], &p[i]) ){
35014841624aSdrh         sqlite3_free(p);
35022e3f87aeSdrh         p = 0;
35034841624aSdrh         return TCL_ERROR;
35044841624aSdrh       }
35054841624aSdrh     }
35062e3f87aeSdrh   }
35072e3f87aeSdrh   Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p));
35082e3f87aeSdrh   return TCL_OK;
35092e3f87aeSdrh }
35102e3f87aeSdrh /*
35112e3f87aeSdrh ** Usage:   intarray_addr  INT  ...
35122e3f87aeSdrh **
35132e3f87aeSdrh ** Return the address of a C-language array of 32-bit integers.
35142e3f87aeSdrh **
35152e3f87aeSdrh ** Space to hold the array is obtained from malloc().  Call this procedure once
35162e3f87aeSdrh ** with no arguments in order to release memory.  Each call to this procedure
35172e3f87aeSdrh ** overwrites the previous array.
35182e3f87aeSdrh */
35197617e4a8Smistachkin static int SQLITE_TCLAPI test_int64array_addr(
35202e3f87aeSdrh   void * clientData,
35212e3f87aeSdrh   Tcl_Interp *interp,
35222e3f87aeSdrh   int objc,
35232e3f87aeSdrh   Tcl_Obj *CONST objv[]
35242e3f87aeSdrh ){
35252e3f87aeSdrh   int i;
35262e3f87aeSdrh   static sqlite3_int64 *p = 0;
35272e3f87aeSdrh 
35282e3f87aeSdrh   sqlite3_free(p);
35292e3f87aeSdrh   p = 0;
35302e3f87aeSdrh   if( objc>1 ){
35312e3f87aeSdrh     p = sqlite3_malloc( sizeof(p[0])*(objc-1) );
35322e3f87aeSdrh     if( p==0 ) return TCL_ERROR;
35332e3f87aeSdrh     for(i=0; i<objc-1; i++){
3534a912348aSdrh       Tcl_WideInt v;
3535a912348aSdrh       if( Tcl_GetWideIntFromObj(interp, objv[1+i], &v) ){
35362e3f87aeSdrh         sqlite3_free(p);
35372e3f87aeSdrh         p = 0;
35382e3f87aeSdrh         return TCL_ERROR;
35392e3f87aeSdrh       }
3540a912348aSdrh       p[i] = v;
35412e3f87aeSdrh     }
35422e3f87aeSdrh   }
35432e3f87aeSdrh   Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p));
35442e3f87aeSdrh   return TCL_OK;
35452e3f87aeSdrh }
35462e3f87aeSdrh /*
35472e3f87aeSdrh ** Usage:   doublearray_addr  INT  ...
35482e3f87aeSdrh **
35492e3f87aeSdrh ** Return the address of a C-language array of doubles.
35502e3f87aeSdrh **
35512e3f87aeSdrh ** Space to hold the array is obtained from malloc().  Call this procedure once
35522e3f87aeSdrh ** with no arguments in order to release memory.  Each call to this procedure
35532e3f87aeSdrh ** overwrites the previous array.
35542e3f87aeSdrh */
35557617e4a8Smistachkin static int SQLITE_TCLAPI test_doublearray_addr(
35562e3f87aeSdrh   void * clientData,
35572e3f87aeSdrh   Tcl_Interp *interp,
35582e3f87aeSdrh   int objc,
35592e3f87aeSdrh   Tcl_Obj *CONST objv[]
35602e3f87aeSdrh ){
35612e3f87aeSdrh   int i;
35622e3f87aeSdrh   static double *p = 0;
35632e3f87aeSdrh 
35642e3f87aeSdrh   sqlite3_free(p);
35652e3f87aeSdrh   p = 0;
35662e3f87aeSdrh   if( objc>1 ){
35672e3f87aeSdrh     p = sqlite3_malloc( sizeof(p[0])*(objc-1) );
35682e3f87aeSdrh     if( p==0 ) return TCL_ERROR;
35692e3f87aeSdrh     for(i=0; i<objc-1; i++){
35702e3f87aeSdrh       if( Tcl_GetDoubleFromObj(interp, objv[1+i], &p[i]) ){
35712e3f87aeSdrh         sqlite3_free(p);
35722e3f87aeSdrh         p = 0;
35732e3f87aeSdrh         return TCL_ERROR;
35742e3f87aeSdrh       }
35752e3f87aeSdrh     }
35762e3f87aeSdrh   }
35772e3f87aeSdrh   Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p));
35782e3f87aeSdrh   return TCL_OK;
35792e3f87aeSdrh }
35802e3f87aeSdrh /*
35812e3f87aeSdrh ** Usage:   textarray_addr  TEXT ...
35822e3f87aeSdrh **
35832e3f87aeSdrh ** Return the address of a C-language array of strings.
35842e3f87aeSdrh **
35852e3f87aeSdrh ** Space to hold the array is obtained from malloc().  Call this procedure once
35862e3f87aeSdrh ** with no arguments in order to release memory.  Each call to this procedure
35872e3f87aeSdrh ** overwrites the previous array.
35882e3f87aeSdrh */
35897617e4a8Smistachkin static int SQLITE_TCLAPI test_textarray_addr(
35902e3f87aeSdrh   void * clientData,
35912e3f87aeSdrh   Tcl_Interp *interp,
35922e3f87aeSdrh   int objc,
35932e3f87aeSdrh   Tcl_Obj *CONST objv[]
35942e3f87aeSdrh ){
35952e3f87aeSdrh   int i;
35962e3f87aeSdrh   static int n = 0;
35972e3f87aeSdrh   static char **p = 0;
35982e3f87aeSdrh 
35992e3f87aeSdrh   for(i=0; i<n; i++) sqlite3_free(p[i]);
36002e3f87aeSdrh   sqlite3_free(p);
36012e3f87aeSdrh   p = 0;
36022e3f87aeSdrh   if( objc>1 ){
36032e3f87aeSdrh     p = sqlite3_malloc( sizeof(p[0])*(objc-1) );
36042e3f87aeSdrh     if( p==0 ) return TCL_ERROR;
36052e3f87aeSdrh     for(i=0; i<objc-1; i++){
36062e3f87aeSdrh       p[i] = sqlite3_mprintf("%s", Tcl_GetString(objv[1+i]));
36072e3f87aeSdrh     }
36082e3f87aeSdrh   }
360950687436Sdan   n = objc-1;
36102e3f87aeSdrh   Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p));
36114841624aSdrh   return TCL_OK;
36124841624aSdrh }
36134841624aSdrh 
36144841624aSdrh 
36154841624aSdrh /*
3616241db313Sdrh ** Usage:   sqlite3_bind_int64  STMT N VALUE
3617241db313Sdrh **
3618241db313Sdrh ** Test the sqlite3_bind_int64 interface.  STMT is a prepared statement.
3619241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
3620241db313Sdrh ** binds a 64-bit integer VALUE to that wildcard.
3621241db313Sdrh */
36227617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_int64(
362351e3d8e2Sdanielk1977   void * clientData,
362451e3d8e2Sdanielk1977   Tcl_Interp *interp,
362551e3d8e2Sdanielk1977   int objc,
362651e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
362751e3d8e2Sdanielk1977 ){
362851e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
362951e3d8e2Sdanielk1977   int idx;
3630b3f787f4Sdrh   Tcl_WideInt value;
363151e3d8e2Sdanielk1977   int rc;
363251e3d8e2Sdanielk1977 
363351e3d8e2Sdanielk1977   if( objc!=4 ){
363451e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
3635241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0);
363651e3d8e2Sdanielk1977     return TCL_ERROR;
363751e3d8e2Sdanielk1977   }
363851e3d8e2Sdanielk1977 
363951e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
364051e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
364151e3d8e2Sdanielk1977   if( Tcl_GetWideIntFromObj(interp, objv[3], &value) ) return TCL_ERROR;
364251e3d8e2Sdanielk1977 
364351e3d8e2Sdanielk1977   rc = sqlite3_bind_int64(pStmt, idx, value);
3644c60d0446Sdrh   if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
364551e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
364651e3d8e2Sdanielk1977     return TCL_ERROR;
364751e3d8e2Sdanielk1977   }
364851e3d8e2Sdanielk1977 
364951e3d8e2Sdanielk1977   return TCL_OK;
365051e3d8e2Sdanielk1977 }
365151e3d8e2Sdanielk1977 
3652241db313Sdrh 
3653241db313Sdrh /*
3654241db313Sdrh ** Usage:   sqlite3_bind_double  STMT N VALUE
3655241db313Sdrh **
3656241db313Sdrh ** Test the sqlite3_bind_double interface.  STMT is a prepared statement.
3657241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
3658241db313Sdrh ** binds a 64-bit integer VALUE to that wildcard.
3659241db313Sdrh */
36607617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_double(
366151e3d8e2Sdanielk1977   void * clientData,
366251e3d8e2Sdanielk1977   Tcl_Interp *interp,
366351e3d8e2Sdanielk1977   int objc,
366451e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
366551e3d8e2Sdanielk1977 ){
366651e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
366751e3d8e2Sdanielk1977   int idx;
366827b2f053Smistachkin   double value = 0;
366951e3d8e2Sdanielk1977   int rc;
3670a06f17feSdrh   const char *zVal;
3671a06f17feSdrh   int i;
3672a06f17feSdrh   static const struct {
3673a06f17feSdrh     const char *zName;     /* Name of the special floating point value */
3674a06f17feSdrh     unsigned int iUpper;   /* Upper 32 bits */
3675a06f17feSdrh     unsigned int iLower;   /* Lower 32 bits */
3676a06f17feSdrh   } aSpecialFp[] = {
3677a06f17feSdrh     {  "NaN",      0x7fffffff, 0xffffffff },
3678a06f17feSdrh     {  "SNaN",     0x7ff7ffff, 0xffffffff },
3679a06f17feSdrh     {  "-NaN",     0xffffffff, 0xffffffff },
3680a06f17feSdrh     {  "-SNaN",    0xfff7ffff, 0xffffffff },
3681a06f17feSdrh     {  "+Inf",     0x7ff00000, 0x00000000 },
3682a06f17feSdrh     {  "-Inf",     0xfff00000, 0x00000000 },
3683a06f17feSdrh     {  "Epsilon",  0x00000000, 0x00000001 },
3684a06f17feSdrh     {  "-Epsilon", 0x80000000, 0x00000001 },
3685a06f17feSdrh     {  "NaN0",     0x7ff80000, 0x00000000 },
3686a06f17feSdrh     {  "-NaN0",    0xfff80000, 0x00000000 },
3687a06f17feSdrh   };
368851e3d8e2Sdanielk1977 
368951e3d8e2Sdanielk1977   if( objc!=4 ){
369051e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
3691241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0);
369251e3d8e2Sdanielk1977     return TCL_ERROR;
369351e3d8e2Sdanielk1977   }
369451e3d8e2Sdanielk1977 
369551e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
369651e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
369751e3d8e2Sdanielk1977 
3698394f07efSdrh   /* Intercept the string "NaN" and generate a NaN value for it.
3699394f07efSdrh   ** All other strings are passed through to Tcl_GetDoubleFromObj().
3700394f07efSdrh   ** Tcl_GetDoubleFromObj() should understand "NaN" but some versions
3701394f07efSdrh   ** contain a bug.
3702394f07efSdrh   */
3703a06f17feSdrh   zVal = Tcl_GetString(objv[3]);
3704a06f17feSdrh   for(i=0; i<sizeof(aSpecialFp)/sizeof(aSpecialFp[0]); i++){
3705a06f17feSdrh     if( strcmp(aSpecialFp[i].zName, zVal)==0 ){
3706a06f17feSdrh       sqlite3_uint64 x;
3707a06f17feSdrh       x = aSpecialFp[i].iUpper;
3708a06f17feSdrh       x <<= 32;
3709a06f17feSdrh       x |= aSpecialFp[i].iLower;
37100a66733aSdrh       assert( sizeof(value)==8 );
37110a66733aSdrh       assert( sizeof(x)==8 );
37120a66733aSdrh       memcpy(&value, &x, 8);
3713a06f17feSdrh       break;
3714a06f17feSdrh     }
3715a06f17feSdrh   }
3716a06f17feSdrh   if( i>=sizeof(aSpecialFp)/sizeof(aSpecialFp[0]) &&
3717a06f17feSdrh          Tcl_GetDoubleFromObj(interp, objv[3], &value) ){
3718394f07efSdrh     return TCL_ERROR;
3719394f07efSdrh   }
372051e3d8e2Sdanielk1977   rc = sqlite3_bind_double(pStmt, idx, value);
3721c60d0446Sdrh   if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
372251e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
372351e3d8e2Sdanielk1977     return TCL_ERROR;
372451e3d8e2Sdanielk1977   }
372551e3d8e2Sdanielk1977 
372651e3d8e2Sdanielk1977   return TCL_OK;
372751e3d8e2Sdanielk1977 }
372851e3d8e2Sdanielk1977 
3729241db313Sdrh /*
3730241db313Sdrh ** Usage:   sqlite3_bind_null  STMT N
3731241db313Sdrh **
3732241db313Sdrh ** Test the sqlite3_bind_null interface.  STMT is a prepared statement.
3733241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
3734241db313Sdrh ** binds a NULL to the wildcard.
3735241db313Sdrh */
37367617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_null(
373751e3d8e2Sdanielk1977   void * clientData,
373851e3d8e2Sdanielk1977   Tcl_Interp *interp,
373951e3d8e2Sdanielk1977   int objc,
374051e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
374151e3d8e2Sdanielk1977 ){
374251e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
374351e3d8e2Sdanielk1977   int idx;
374451e3d8e2Sdanielk1977   int rc;
374551e3d8e2Sdanielk1977 
374651e3d8e2Sdanielk1977   if( objc!=3 ){
374751e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
3748241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N", 0);
374951e3d8e2Sdanielk1977     return TCL_ERROR;
375051e3d8e2Sdanielk1977   }
375151e3d8e2Sdanielk1977 
375251e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
375351e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
375451e3d8e2Sdanielk1977 
375551e3d8e2Sdanielk1977   rc = sqlite3_bind_null(pStmt, idx);
3756c60d0446Sdrh   if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
375751e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
375851e3d8e2Sdanielk1977     return TCL_ERROR;
375951e3d8e2Sdanielk1977   }
376051e3d8e2Sdanielk1977 
376151e3d8e2Sdanielk1977   return TCL_OK;
376251e3d8e2Sdanielk1977 }
376351e3d8e2Sdanielk1977 
3764241db313Sdrh /*
3765241db313Sdrh ** Usage:   sqlite3_bind_text  STMT N STRING BYTES
3766241db313Sdrh **
3767241db313Sdrh ** Test the sqlite3_bind_text interface.  STMT is a prepared statement.
3768241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
3769241db313Sdrh ** binds a UTF-8 string STRING to the wildcard.  The string is BYTES bytes
3770241db313Sdrh ** long.
3771241db313Sdrh */
37727617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_text(
377351e3d8e2Sdanielk1977   void * clientData,
377451e3d8e2Sdanielk1977   Tcl_Interp *interp,
377551e3d8e2Sdanielk1977   int objc,
377651e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
377751e3d8e2Sdanielk1977 ){
377851e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
377951e3d8e2Sdanielk1977   int idx;
378051e3d8e2Sdanielk1977   int bytes;
378151e3d8e2Sdanielk1977   char *value;
378251e3d8e2Sdanielk1977   int rc;
378351e3d8e2Sdanielk1977 
378451e3d8e2Sdanielk1977   if( objc!=5 ){
378551e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
3786241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE BYTES", 0);
378751e3d8e2Sdanielk1977     return TCL_ERROR;
378851e3d8e2Sdanielk1977   }
378951e3d8e2Sdanielk1977 
379051e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
379151e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
379210dfbbb5Sdrh   value = (char*)Tcl_GetByteArrayFromObj(objv[3], &bytes);
379351e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
379451e3d8e2Sdanielk1977 
3795d8123366Sdanielk1977   rc = sqlite3_bind_text(pStmt, idx, value, bytes, SQLITE_TRANSIENT);
3796c60d0446Sdrh   if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
379751e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
3798e84d8d32Smistachkin     Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
379951e3d8e2Sdanielk1977     return TCL_ERROR;
380051e3d8e2Sdanielk1977   }
380151e3d8e2Sdanielk1977 
380251e3d8e2Sdanielk1977   return TCL_OK;
380351e3d8e2Sdanielk1977 }
380451e3d8e2Sdanielk1977 
3805241db313Sdrh /*
3806161fb796Sdanielk1977 ** Usage:   sqlite3_bind_text16 ?-static? STMT N STRING BYTES
3807241db313Sdrh **
3808241db313Sdrh ** Test the sqlite3_bind_text16 interface.  STMT is a prepared statement.
3809241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
3810241db313Sdrh ** binds a UTF-16 string STRING to the wildcard.  The string is BYTES bytes
3811241db313Sdrh ** long.
3812241db313Sdrh */
38137617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_text16(
381451e3d8e2Sdanielk1977   void * clientData,
381551e3d8e2Sdanielk1977   Tcl_Interp *interp,
381651e3d8e2Sdanielk1977   int objc,
381751e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
381851e3d8e2Sdanielk1977 ){
38195436dc2dSdrh #ifndef SQLITE_OMIT_UTF16
382051e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
382151e3d8e2Sdanielk1977   int idx;
382251e3d8e2Sdanielk1977   int bytes;
382351e3d8e2Sdanielk1977   char *value;
382451e3d8e2Sdanielk1977   int rc;
382551e3d8e2Sdanielk1977 
38267da5fcb0Sdrh   void (*xDel)(void*) = (objc==6?SQLITE_STATIC:SQLITE_TRANSIENT);
3827161fb796Sdanielk1977   Tcl_Obj *oStmt    = objv[objc-4];
3828161fb796Sdanielk1977   Tcl_Obj *oN       = objv[objc-3];
3829161fb796Sdanielk1977   Tcl_Obj *oString  = objv[objc-2];
3830161fb796Sdanielk1977   Tcl_Obj *oBytes   = objv[objc-1];
3831161fb796Sdanielk1977 
3832161fb796Sdanielk1977   if( objc!=5 && objc!=6){
383351e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
3834241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE BYTES", 0);
383551e3d8e2Sdanielk1977     return TCL_ERROR;
383651e3d8e2Sdanielk1977   }
383751e3d8e2Sdanielk1977 
3838161fb796Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(oStmt), &pStmt) ) return TCL_ERROR;
3839161fb796Sdanielk1977   if( Tcl_GetIntFromObj(interp, oN, &idx) ) return TCL_ERROR;
3840161fb796Sdanielk1977   value = (char*)Tcl_GetByteArrayFromObj(oString, 0);
3841161fb796Sdanielk1977   if( Tcl_GetIntFromObj(interp, oBytes, &bytes) ) return TCL_ERROR;
384251e3d8e2Sdanielk1977 
3843161fb796Sdanielk1977   rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, xDel);
3844c60d0446Sdrh   if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
384551e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
3846e84d8d32Smistachkin     Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
384751e3d8e2Sdanielk1977     return TCL_ERROR;
384851e3d8e2Sdanielk1977   }
384951e3d8e2Sdanielk1977 
38505436dc2dSdrh #endif /* SQLITE_OMIT_UTF16 */
385151e3d8e2Sdanielk1977   return TCL_OK;
385251e3d8e2Sdanielk1977 }
385351e3d8e2Sdanielk1977 
3854241db313Sdrh /*
38555b159dc3Sdanielk1977 ** Usage:   sqlite3_bind_blob ?-static? STMT N DATA BYTES
3856241db313Sdrh **
3857241db313Sdrh ** Test the sqlite3_bind_blob interface.  STMT is a prepared statement.
3858241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
3859241db313Sdrh ** binds a BLOB to the wildcard.  The BLOB is BYTES bytes in size.
3860241db313Sdrh */
38617617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_blob(
386251e3d8e2Sdanielk1977   void * clientData,
386351e3d8e2Sdanielk1977   Tcl_Interp *interp,
386451e3d8e2Sdanielk1977   int objc,
386551e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
386651e3d8e2Sdanielk1977 ){
386751e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
3868de6fde6aSmistachkin   int len, idx;
386951e3d8e2Sdanielk1977   int bytes;
387051e3d8e2Sdanielk1977   char *value;
387151e3d8e2Sdanielk1977   int rc;
38725b159dc3Sdanielk1977   sqlite3_destructor_type xDestructor = SQLITE_TRANSIENT;
387351e3d8e2Sdanielk1977 
38745b159dc3Sdanielk1977   if( objc!=5 && objc!=6 ){
387551e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
3876241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N DATA BYTES", 0);
387751e3d8e2Sdanielk1977     return TCL_ERROR;
387851e3d8e2Sdanielk1977   }
387951e3d8e2Sdanielk1977 
38805b159dc3Sdanielk1977   if( objc==6 ){
38815b159dc3Sdanielk1977     xDestructor = SQLITE_STATIC;
38825b159dc3Sdanielk1977     objv++;
38835b159dc3Sdanielk1977   }
38845b159dc3Sdanielk1977 
388551e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
388651e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
3887de6fde6aSmistachkin 
38888d853642Sdrh   value = (char*)Tcl_GetByteArrayFromObj(objv[3], &len);
388949e4643eSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
389051e3d8e2Sdanielk1977 
3891de6fde6aSmistachkin   if( bytes>len ){
3892de6fde6aSmistachkin     char zBuf[200];
3893de6fde6aSmistachkin     sqlite3_snprintf(sizeof(zBuf), zBuf,
3894de6fde6aSmistachkin                      "cannot use %d blob bytes, have %d", bytes, len);
3895de6fde6aSmistachkin     Tcl_AppendResult(interp, zBuf, -1);
3896de6fde6aSmistachkin     return TCL_ERROR;
3897de6fde6aSmistachkin   }
3898de6fde6aSmistachkin 
38995b159dc3Sdanielk1977   rc = sqlite3_bind_blob(pStmt, idx, value, bytes, xDestructor);
3900c60d0446Sdrh   if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
390151e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
390251e3d8e2Sdanielk1977     return TCL_ERROR;
390351e3d8e2Sdanielk1977   }
390451e3d8e2Sdanielk1977 
390551e3d8e2Sdanielk1977   return TCL_OK;
390651e3d8e2Sdanielk1977 }
390751e3d8e2Sdanielk1977 
390899ee3600Sdrh /*
390975f6a032Sdrh ** Usage:   sqlite3_bind_parameter_count  STMT
391075f6a032Sdrh **
391175f6a032Sdrh ** Return the number of wildcards in the given statement.
391275f6a032Sdrh */
39137617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_parameter_count(
391475f6a032Sdrh   void * clientData,
391575f6a032Sdrh   Tcl_Interp *interp,
391675f6a032Sdrh   int objc,
391775f6a032Sdrh   Tcl_Obj *CONST objv[]
391875f6a032Sdrh ){
391975f6a032Sdrh   sqlite3_stmt *pStmt;
392075f6a032Sdrh 
392175f6a032Sdrh   if( objc!=2 ){
392275f6a032Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "STMT");
392375f6a032Sdrh     return TCL_ERROR;
392475f6a032Sdrh   }
392575f6a032Sdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
392675f6a032Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_bind_parameter_count(pStmt)));
392775f6a032Sdrh   return TCL_OK;
392875f6a032Sdrh }
392975f6a032Sdrh 
393075f6a032Sdrh /*
3931895d7472Sdrh ** Usage:   sqlite3_bind_parameter_name  STMT  N
3932895d7472Sdrh **
3933895d7472Sdrh ** Return the name of the Nth wildcard.  The first wildcard is 1.
3934895d7472Sdrh ** An empty string is returned if N is out of range or if the wildcard
3935895d7472Sdrh ** is nameless.
3936895d7472Sdrh */
39377617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_parameter_name(
3938895d7472Sdrh   void * clientData,
3939895d7472Sdrh   Tcl_Interp *interp,
3940895d7472Sdrh   int objc,
3941895d7472Sdrh   Tcl_Obj *CONST objv[]
3942895d7472Sdrh ){
3943895d7472Sdrh   sqlite3_stmt *pStmt;
3944895d7472Sdrh   int i;
3945895d7472Sdrh 
3946895d7472Sdrh   if( objc!=3 ){
3947895d7472Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "STMT N");
3948895d7472Sdrh     return TCL_ERROR;
3949895d7472Sdrh   }
3950895d7472Sdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
3951895d7472Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &i) ) return TCL_ERROR;
3952895d7472Sdrh   Tcl_SetObjResult(interp,
3953895d7472Sdrh      Tcl_NewStringObj(sqlite3_bind_parameter_name(pStmt,i),-1)
3954895d7472Sdrh   );
3955895d7472Sdrh   return TCL_OK;
3956895d7472Sdrh }
3957895d7472Sdrh 
3958895d7472Sdrh /*
3959fa6bc000Sdrh ** Usage:   sqlite3_bind_parameter_index  STMT  NAME
3960fa6bc000Sdrh **
3961fa6bc000Sdrh ** Return the index of the wildcard called NAME.  Return 0 if there is
3962fa6bc000Sdrh ** no such wildcard.
3963fa6bc000Sdrh */
39647617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_parameter_index(
3965fa6bc000Sdrh   void * clientData,
3966fa6bc000Sdrh   Tcl_Interp *interp,
3967fa6bc000Sdrh   int objc,
3968fa6bc000Sdrh   Tcl_Obj *CONST objv[]
3969fa6bc000Sdrh ){
3970fa6bc000Sdrh   sqlite3_stmt *pStmt;
3971fa6bc000Sdrh 
3972fa6bc000Sdrh   if( objc!=3 ){
3973fa6bc000Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "STMT NAME");
3974fa6bc000Sdrh     return TCL_ERROR;
3975fa6bc000Sdrh   }
3976fa6bc000Sdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
3977fa6bc000Sdrh   Tcl_SetObjResult(interp,
3978fa6bc000Sdrh      Tcl_NewIntObj(
3979fa6bc000Sdrh        sqlite3_bind_parameter_index(pStmt,Tcl_GetString(objv[2]))
3980fa6bc000Sdrh      )
3981fa6bc000Sdrh   );
3982fa6bc000Sdrh   return TCL_OK;
3983fa6bc000Sdrh }
3984fa6bc000Sdrh 
3985fa6bc000Sdrh /*
3986600dd0baSdanielk1977 ** Usage:   sqlite3_clear_bindings STMT
3987600dd0baSdanielk1977 **
3988600dd0baSdanielk1977 */
39897617e4a8Smistachkin static int SQLITE_TCLAPI test_clear_bindings(
3990600dd0baSdanielk1977   void * clientData,
3991600dd0baSdanielk1977   Tcl_Interp *interp,
3992600dd0baSdanielk1977   int objc,
3993600dd0baSdanielk1977   Tcl_Obj *CONST objv[]
3994600dd0baSdanielk1977 ){
3995600dd0baSdanielk1977   sqlite3_stmt *pStmt;
3996600dd0baSdanielk1977 
3997600dd0baSdanielk1977   if( objc!=2 ){
3998600dd0baSdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "STMT");
3999600dd0baSdanielk1977     return TCL_ERROR;
4000600dd0baSdanielk1977   }
4001600dd0baSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
4002600dd0baSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_clear_bindings(pStmt)));
4003600dd0baSdanielk1977   return TCL_OK;
4004600dd0baSdanielk1977 }
4005f9cb7f58Sdrh 
4006f9cb7f58Sdrh /*
4007f9cb7f58Sdrh ** Usage:   sqlite3_sleep MILLISECONDS
4008f9cb7f58Sdrh */
40097617e4a8Smistachkin static int SQLITE_TCLAPI test_sleep(
4010f9cb7f58Sdrh   void * clientData,
4011f9cb7f58Sdrh   Tcl_Interp *interp,
4012f9cb7f58Sdrh   int objc,
4013f9cb7f58Sdrh   Tcl_Obj *CONST objv[]
4014f9cb7f58Sdrh ){
4015f9cb7f58Sdrh   int ms;
4016f9cb7f58Sdrh 
4017f9cb7f58Sdrh   if( objc!=2 ){
4018f9cb7f58Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "MILLISECONDS");
4019f9cb7f58Sdrh     return TCL_ERROR;
4020f9cb7f58Sdrh   }
4021f9cb7f58Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &ms) ){
4022f9cb7f58Sdrh     return TCL_ERROR;
4023f9cb7f58Sdrh   }
4024f9cb7f58Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_sleep(ms)));
4025f9cb7f58Sdrh   return TCL_OK;
4026f9cb7f58Sdrh }
4027600dd0baSdanielk1977 
4028600dd0baSdanielk1977 /*
402999dfe5ebSdrh ** Usage: sqlite3_extended_errcode DB
403099dfe5ebSdrh **
403199dfe5ebSdrh ** Return the string representation of the most recent sqlite3_* API
403299dfe5ebSdrh ** error code. e.g. "SQLITE_ERROR".
403399dfe5ebSdrh */
40347617e4a8Smistachkin static int SQLITE_TCLAPI test_ex_errcode(
403599dfe5ebSdrh   void * clientData,
403699dfe5ebSdrh   Tcl_Interp *interp,
403799dfe5ebSdrh   int objc,
403899dfe5ebSdrh   Tcl_Obj *CONST objv[]
403999dfe5ebSdrh ){
404099dfe5ebSdrh   sqlite3 *db;
404199dfe5ebSdrh   int rc;
404299dfe5ebSdrh 
404399dfe5ebSdrh   if( objc!=2 ){
404499dfe5ebSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
404599dfe5ebSdrh        Tcl_GetString(objv[0]), " DB", 0);
404699dfe5ebSdrh     return TCL_ERROR;
404799dfe5ebSdrh   }
404899dfe5ebSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
404999dfe5ebSdrh   rc = sqlite3_extended_errcode(db);
405099dfe5ebSdrh   Tcl_AppendResult(interp, (char *)t1ErrorName(rc), 0);
405199dfe5ebSdrh   return TCL_OK;
405299dfe5ebSdrh }
405399dfe5ebSdrh 
405499dfe5ebSdrh 
405599dfe5ebSdrh /*
40566622cce3Sdanielk1977 ** Usage: sqlite3_errcode DB
40576622cce3Sdanielk1977 **
40586622cce3Sdanielk1977 ** Return the string representation of the most recent sqlite3_* API
40596622cce3Sdanielk1977 ** error code. e.g. "SQLITE_ERROR".
40606622cce3Sdanielk1977 */
40617617e4a8Smistachkin static int SQLITE_TCLAPI test_errcode(
40626622cce3Sdanielk1977   void * clientData,
40636622cce3Sdanielk1977   Tcl_Interp *interp,
40646622cce3Sdanielk1977   int objc,
40656622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
40666622cce3Sdanielk1977 ){
40676622cce3Sdanielk1977   sqlite3 *db;
40684ac285a1Sdrh   int rc;
40696622cce3Sdanielk1977 
40706622cce3Sdanielk1977   if( objc!=2 ){
40716622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
40726622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
40736622cce3Sdanielk1977     return TCL_ERROR;
40746622cce3Sdanielk1977   }
40756622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
40764ac285a1Sdrh   rc = sqlite3_errcode(db);
407799dfe5ebSdrh   Tcl_AppendResult(interp, (char *)t1ErrorName(rc), 0);
40786622cce3Sdanielk1977   return TCL_OK;
40796622cce3Sdanielk1977 }
40806622cce3Sdanielk1977 
40816622cce3Sdanielk1977 /*
40820410302eSdanielk1977 ** Usage:   sqlite3_errmsg DB
40836622cce3Sdanielk1977 **
40846622cce3Sdanielk1977 ** Returns the UTF-8 representation of the error message string for the
40856622cce3Sdanielk1977 ** most recent sqlite3_* API call.
40866622cce3Sdanielk1977 */
40877617e4a8Smistachkin static int SQLITE_TCLAPI test_errmsg(
40886622cce3Sdanielk1977   void * clientData,
40896622cce3Sdanielk1977   Tcl_Interp *interp,
40906622cce3Sdanielk1977   int objc,
40916622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
40926622cce3Sdanielk1977 ){
40939bb575fdSdrh   sqlite3 *db;
40946622cce3Sdanielk1977   const char *zErr;
40956622cce3Sdanielk1977 
40966622cce3Sdanielk1977   if( objc!=2 ){
40976622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
40986622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
40996622cce3Sdanielk1977     return TCL_ERROR;
41006622cce3Sdanielk1977   }
41016622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
41026622cce3Sdanielk1977 
41036622cce3Sdanielk1977   zErr = sqlite3_errmsg(db);
41046622cce3Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
41056622cce3Sdanielk1977   return TCL_OK;
41066622cce3Sdanielk1977 }
41076622cce3Sdanielk1977 
41086622cce3Sdanielk1977 /*
41096622cce3Sdanielk1977 ** Usage:   test_errmsg16 DB
41106622cce3Sdanielk1977 **
41116622cce3Sdanielk1977 ** Returns the UTF-16 representation of the error message string for the
41126622cce3Sdanielk1977 ** most recent sqlite3_* API call. This is a byte array object at the TCL
41136622cce3Sdanielk1977 ** level, and it includes the 0x00 0x00 terminator bytes at the end of the
41146622cce3Sdanielk1977 ** UTF-16 string.
41156622cce3Sdanielk1977 */
41167617e4a8Smistachkin static int SQLITE_TCLAPI test_errmsg16(
41176622cce3Sdanielk1977   void * clientData,
41186622cce3Sdanielk1977   Tcl_Interp *interp,
41196622cce3Sdanielk1977   int objc,
41206622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
41216622cce3Sdanielk1977 ){
41225436dc2dSdrh #ifndef SQLITE_OMIT_UTF16
41239bb575fdSdrh   sqlite3 *db;
41246622cce3Sdanielk1977   const void *zErr;
4125aed382f9Sdrh   const char *z;
4126950f054cSdanielk1977   int bytes = 0;
41276622cce3Sdanielk1977 
41286622cce3Sdanielk1977   if( objc!=2 ){
41296622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
41306622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
41316622cce3Sdanielk1977     return TCL_ERROR;
41326622cce3Sdanielk1977   }
41336622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
41346622cce3Sdanielk1977 
41356622cce3Sdanielk1977   zErr = sqlite3_errmsg16(db);
4136950f054cSdanielk1977   if( zErr ){
4137aed382f9Sdrh     z = zErr;
4138aed382f9Sdrh     for(bytes=0; z[bytes] || z[bytes+1]; bytes+=2){}
4139950f054cSdanielk1977   }
41406622cce3Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes));
41415436dc2dSdrh #endif /* SQLITE_OMIT_UTF16 */
41426622cce3Sdanielk1977   return TCL_OK;
41436622cce3Sdanielk1977 }
41446622cce3Sdanielk1977 
41456622cce3Sdanielk1977 /*
41461c767f0dSdrh ** Usage: sqlite3_prepare DB sql bytes ?tailvar?
41476622cce3Sdanielk1977 **
41486622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
41496622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global
41506622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A
41516622cce3Sdanielk1977 ** STMT handle is returned.
41526622cce3Sdanielk1977 */
41537617e4a8Smistachkin static int SQLITE_TCLAPI test_prepare(
41546622cce3Sdanielk1977   void * clientData,
41556622cce3Sdanielk1977   Tcl_Interp *interp,
41566622cce3Sdanielk1977   int objc,
41576622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
41586622cce3Sdanielk1977 ){
41596622cce3Sdanielk1977   sqlite3 *db;
41606622cce3Sdanielk1977   const char *zSql;
41616622cce3Sdanielk1977   int bytes;
41626622cce3Sdanielk1977   const char *zTail = 0;
41636622cce3Sdanielk1977   sqlite3_stmt *pStmt = 0;
41646622cce3Sdanielk1977   char zBuf[50];
41654ad1713cSdanielk1977   int rc;
41666622cce3Sdanielk1977 
41671c767f0dSdrh   if( objc!=5 && objc!=4 ){
41686622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
41691c767f0dSdrh        Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", 0);
41706622cce3Sdanielk1977     return TCL_ERROR;
41716622cce3Sdanielk1977   }
41726622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
41736622cce3Sdanielk1977   zSql = Tcl_GetString(objv[2]);
41746622cce3Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
41756622cce3Sdanielk1977 
41761c767f0dSdrh   rc = sqlite3_prepare(db, zSql, bytes, &pStmt, objc>=5 ? &zTail : 0);
4177937d0deaSdan   Tcl_ResetResult(interp);
4178c60d0446Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
41791c767f0dSdrh   if( zTail && objc>=5 ){
41806622cce3Sdanielk1977     if( bytes>=0 ){
418183cc1392Sdrh       bytes = bytes - (int)(zTail-zSql);
41826622cce3Sdanielk1977     }
41837da5fcb0Sdrh     if( (int)strlen(zTail)<bytes ){
418483cc1392Sdrh       bytes = (int)strlen(zTail);
41853a2c8c8bSdanielk1977     }
41866622cce3Sdanielk1977     Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
41876622cce3Sdanielk1977   }
41884ad1713cSdanielk1977   if( rc!=SQLITE_OK ){
41894ad1713cSdanielk1977     assert( pStmt==0 );
419065545b59Sdrh     sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc);
41914ad1713cSdanielk1977     Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
41924ad1713cSdanielk1977     return TCL_ERROR;
41934ad1713cSdanielk1977   }
41946622cce3Sdanielk1977 
41954ad1713cSdanielk1977   if( pStmt ){
419664b1bea3Sdrh     if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
41976622cce3Sdanielk1977     Tcl_AppendResult(interp, zBuf, 0);
41984ad1713cSdanielk1977   }
41996622cce3Sdanielk1977   return TCL_OK;
42006622cce3Sdanielk1977 }
42016622cce3Sdanielk1977 
42026622cce3Sdanielk1977 /*
42031c767f0dSdrh ** Usage: sqlite3_prepare_v2 DB sql bytes ?tailvar?
4204b900aaf3Sdrh **
4205b900aaf3Sdrh ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
4206b900aaf3Sdrh ** database handle <DB>. The parameter <tailval> is the name of a global
4207b900aaf3Sdrh ** variable that is set to the unused portion of <sql> (if any). A
4208b900aaf3Sdrh ** STMT handle is returned.
4209b900aaf3Sdrh */
42107617e4a8Smistachkin static int SQLITE_TCLAPI test_prepare_v2(
4211b900aaf3Sdrh   void * clientData,
4212b900aaf3Sdrh   Tcl_Interp *interp,
4213b900aaf3Sdrh   int objc,
4214b900aaf3Sdrh   Tcl_Obj *CONST objv[]
4215b900aaf3Sdrh ){
4216b900aaf3Sdrh   sqlite3 *db;
4217b900aaf3Sdrh   const char *zSql;
4218d89b834fSdan   char *zCopy = 0;                /* malloc() copy of zSql */
4219b900aaf3Sdrh   int bytes;
4220b900aaf3Sdrh   const char *zTail = 0;
4221b900aaf3Sdrh   sqlite3_stmt *pStmt = 0;
4222b900aaf3Sdrh   char zBuf[50];
4223b900aaf3Sdrh   int rc;
4224b900aaf3Sdrh 
42251c767f0dSdrh   if( objc!=5 && objc!=4 ){
4226b900aaf3Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
4227b900aaf3Sdrh        Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
4228b900aaf3Sdrh     return TCL_ERROR;
4229b900aaf3Sdrh   }
4230b900aaf3Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
4231b900aaf3Sdrh   zSql = Tcl_GetString(objv[2]);
4232b900aaf3Sdrh   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
4233b900aaf3Sdrh 
4234d89b834fSdan   /* Instead of using zSql directly, make a copy into a buffer obtained
4235d89b834fSdan   ** directly from malloc(). The idea is to make it easier for valgrind
4236d89b834fSdan   ** to spot buffer overreads.  */
4237d89b834fSdan   if( bytes>=0 ){
4238d89b834fSdan     zCopy = malloc(bytes);
4239d89b834fSdan     memcpy(zCopy, zSql, bytes);
4240d89b834fSdan   }else{
42412c3abeb8Sdrh     int n = (int)strlen(zSql) + 1;
4242d89b834fSdan     zCopy = malloc(n);
4243d89b834fSdan     memcpy(zCopy, zSql, n);
4244d89b834fSdan   }
4245d89b834fSdan   rc = sqlite3_prepare_v2(db, zCopy, bytes, &pStmt, objc>=5 ? &zTail : 0);
4246d89b834fSdan   free(zCopy);
4247d89b834fSdan   zTail = &zSql[(zTail - zCopy)];
4248d89b834fSdan 
42497e29e956Sdanielk1977   assert(rc==SQLITE_OK || pStmt==0);
4250937d0deaSdan   Tcl_ResetResult(interp);
4251b900aaf3Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
4252e5d7bf1eSdrh   if( rc==SQLITE_OK && zTail && objc>=5 ){
4253b900aaf3Sdrh     if( bytes>=0 ){
425483cc1392Sdrh       bytes = bytes - (int)(zTail-zSql);
4255b900aaf3Sdrh     }
4256b900aaf3Sdrh     Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
4257b900aaf3Sdrh   }
4258b900aaf3Sdrh   if( rc!=SQLITE_OK ){
4259b900aaf3Sdrh     assert( pStmt==0 );
426065545b59Sdrh     sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc);
4261b900aaf3Sdrh     Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
4262b900aaf3Sdrh     return TCL_ERROR;
4263b900aaf3Sdrh   }
4264b900aaf3Sdrh 
4265b900aaf3Sdrh   if( pStmt ){
4266b900aaf3Sdrh     if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
4267b900aaf3Sdrh     Tcl_AppendResult(interp, zBuf, 0);
4268b900aaf3Sdrh   }
4269b900aaf3Sdrh   return TCL_OK;
4270b900aaf3Sdrh }
4271b900aaf3Sdrh 
4272b900aaf3Sdrh /*
42734837f531Sdrh ** Usage: sqlite3_prepare_tkt3134 DB
42744837f531Sdrh **
42754837f531Sdrh ** Generate a prepared statement for a zero-byte string as a test
427660ec914cSpeter.d.reid ** for ticket #3134.  The string should be preceded by a zero byte.
42774837f531Sdrh */
42787617e4a8Smistachkin static int SQLITE_TCLAPI test_prepare_tkt3134(
42794837f531Sdrh   void * clientData,
42804837f531Sdrh   Tcl_Interp *interp,
42814837f531Sdrh   int objc,
42824837f531Sdrh   Tcl_Obj *CONST objv[]
42834837f531Sdrh ){
42844837f531Sdrh   sqlite3 *db;
42854837f531Sdrh   static const char zSql[] = "\000SELECT 1";
42864837f531Sdrh   sqlite3_stmt *pStmt = 0;
42874837f531Sdrh   char zBuf[50];
42884837f531Sdrh   int rc;
42894837f531Sdrh 
42904837f531Sdrh   if( objc!=2 ){
42914837f531Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
42924837f531Sdrh        Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
42934837f531Sdrh     return TCL_ERROR;
42944837f531Sdrh   }
42954837f531Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
42964837f531Sdrh   rc = sqlite3_prepare_v2(db, &zSql[1], 0, &pStmt, 0);
42974837f531Sdrh   assert(rc==SQLITE_OK || pStmt==0);
42984837f531Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
42994837f531Sdrh   if( rc!=SQLITE_OK ){
43004837f531Sdrh     assert( pStmt==0 );
430165545b59Sdrh     sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc);
43024837f531Sdrh     Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
43034837f531Sdrh     return TCL_ERROR;
43044837f531Sdrh   }
43054837f531Sdrh 
43064837f531Sdrh   if( pStmt ){
43074837f531Sdrh     if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
43084837f531Sdrh     Tcl_AppendResult(interp, zBuf, 0);
43094837f531Sdrh   }
43104837f531Sdrh   return TCL_OK;
43114837f531Sdrh }
43124837f531Sdrh 
43134837f531Sdrh /*
4314b900aaf3Sdrh ** Usage: sqlite3_prepare16 DB sql bytes tailvar
43156622cce3Sdanielk1977 **
43166622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
43176622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global
43186622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A
43196622cce3Sdanielk1977 ** STMT handle is returned.
43206622cce3Sdanielk1977 */
43217617e4a8Smistachkin static int SQLITE_TCLAPI test_prepare16(
43226622cce3Sdanielk1977   void * clientData,
43236622cce3Sdanielk1977   Tcl_Interp *interp,
43246622cce3Sdanielk1977   int objc,
43256622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
43266622cce3Sdanielk1977 ){
43275436dc2dSdrh #ifndef SQLITE_OMIT_UTF16
43286622cce3Sdanielk1977   sqlite3 *db;
43296622cce3Sdanielk1977   const void *zSql;
43306622cce3Sdanielk1977   const void *zTail = 0;
43316622cce3Sdanielk1977   Tcl_Obj *pTail = 0;
43326622cce3Sdanielk1977   sqlite3_stmt *pStmt = 0;
43336622cce3Sdanielk1977   char zBuf[50];
4334c60d0446Sdrh   int rc;
43356622cce3Sdanielk1977   int bytes;                /* The integer specified as arg 3 */
43366622cce3Sdanielk1977   int objlen;               /* The byte-array length of arg 2 */
43376622cce3Sdanielk1977 
43381c767f0dSdrh   if( objc!=5 && objc!=4 ){
43396622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
43401c767f0dSdrh        Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", 0);
43416622cce3Sdanielk1977     return TCL_ERROR;
43426622cce3Sdanielk1977   }
43436622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
43446622cce3Sdanielk1977   zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen);
43456622cce3Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
43466622cce3Sdanielk1977 
43471c767f0dSdrh   rc = sqlite3_prepare16(db, zSql, bytes, &pStmt, objc>=5 ? &zTail : 0);
4348c60d0446Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
4349c60d0446Sdrh   if( rc ){
43506622cce3Sdanielk1977     return TCL_ERROR;
43516622cce3Sdanielk1977   }
43526622cce3Sdanielk1977 
43531c767f0dSdrh   if( objc>=5 ){
43546622cce3Sdanielk1977     if( zTail ){
435583cc1392Sdrh       objlen = objlen - (int)((u8 *)zTail-(u8 *)zSql);
43566622cce3Sdanielk1977     }else{
43576622cce3Sdanielk1977       objlen = 0;
43586622cce3Sdanielk1977     }
43596622cce3Sdanielk1977     pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen);
43606622cce3Sdanielk1977     Tcl_IncrRefCount(pTail);
43616622cce3Sdanielk1977     Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0);
43624ad1713cSdanielk1977     Tcl_DecrRefCount(pTail);
43631c767f0dSdrh   }
43646622cce3Sdanielk1977 
43654ad1713cSdanielk1977   if( pStmt ){
436664b1bea3Sdrh     if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
43674ad1713cSdanielk1977   }
43686622cce3Sdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
43695436dc2dSdrh #endif /* SQLITE_OMIT_UTF16 */
43706622cce3Sdanielk1977   return TCL_OK;
43716622cce3Sdanielk1977 }
43726622cce3Sdanielk1977 
43734ad1713cSdanielk1977 /*
43741c767f0dSdrh ** Usage: sqlite3_prepare16_v2 DB sql bytes ?tailvar?
4375b900aaf3Sdrh **
4376b900aaf3Sdrh ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
4377b900aaf3Sdrh ** database handle <DB>. The parameter <tailval> is the name of a global
4378b900aaf3Sdrh ** variable that is set to the unused portion of <sql> (if any). A
4379b900aaf3Sdrh ** STMT handle is returned.
4380b900aaf3Sdrh */
43817617e4a8Smistachkin static int SQLITE_TCLAPI test_prepare16_v2(
4382b900aaf3Sdrh   void * clientData,
4383b900aaf3Sdrh   Tcl_Interp *interp,
4384b900aaf3Sdrh   int objc,
4385b900aaf3Sdrh   Tcl_Obj *CONST objv[]
4386b900aaf3Sdrh ){
4387b900aaf3Sdrh #ifndef SQLITE_OMIT_UTF16
4388b900aaf3Sdrh   sqlite3 *db;
4389b900aaf3Sdrh   const void *zSql;
4390b900aaf3Sdrh   const void *zTail = 0;
4391b900aaf3Sdrh   Tcl_Obj *pTail = 0;
4392b900aaf3Sdrh   sqlite3_stmt *pStmt = 0;
4393b900aaf3Sdrh   char zBuf[50];
4394b900aaf3Sdrh   int rc;
4395b900aaf3Sdrh   int bytes;                /* The integer specified as arg 3 */
4396b900aaf3Sdrh   int objlen;               /* The byte-array length of arg 2 */
4397b900aaf3Sdrh 
43981c767f0dSdrh   if( objc!=5 && objc!=4 ){
4399b900aaf3Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
44001c767f0dSdrh        Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", 0);
4401b900aaf3Sdrh     return TCL_ERROR;
4402b900aaf3Sdrh   }
4403b900aaf3Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
4404b900aaf3Sdrh   zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen);
4405b900aaf3Sdrh   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
4406b900aaf3Sdrh 
44071c767f0dSdrh   rc = sqlite3_prepare16_v2(db, zSql, bytes, &pStmt, objc>=5 ? &zTail : 0);
4408b900aaf3Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
4409b900aaf3Sdrh   if( rc ){
4410b900aaf3Sdrh     return TCL_ERROR;
4411b900aaf3Sdrh   }
4412b900aaf3Sdrh 
44131c767f0dSdrh   if( objc>=5 ){
4414b900aaf3Sdrh     if( zTail ){
441583cc1392Sdrh       objlen = objlen - (int)((u8 *)zTail-(u8 *)zSql);
4416b900aaf3Sdrh     }else{
4417b900aaf3Sdrh       objlen = 0;
4418b900aaf3Sdrh     }
4419b900aaf3Sdrh     pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen);
4420b900aaf3Sdrh     Tcl_IncrRefCount(pTail);
4421b900aaf3Sdrh     Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0);
4422b900aaf3Sdrh     Tcl_DecrRefCount(pTail);
44231c767f0dSdrh   }
4424b900aaf3Sdrh 
4425b900aaf3Sdrh   if( pStmt ){
4426b900aaf3Sdrh     if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
4427b900aaf3Sdrh   }
4428b900aaf3Sdrh   Tcl_AppendResult(interp, zBuf, 0);
4429b900aaf3Sdrh #endif /* SQLITE_OMIT_UTF16 */
4430b900aaf3Sdrh   return TCL_OK;
4431b900aaf3Sdrh }
4432b900aaf3Sdrh 
4433b900aaf3Sdrh /*
44344ad1713cSdanielk1977 ** Usage: sqlite3_open filename ?options-list?
44354ad1713cSdanielk1977 */
44367617e4a8Smistachkin static int SQLITE_TCLAPI test_open(
44374ad1713cSdanielk1977   void * clientData,
44384ad1713cSdanielk1977   Tcl_Interp *interp,
44394ad1713cSdanielk1977   int objc,
44404ad1713cSdanielk1977   Tcl_Obj *CONST objv[]
44414ad1713cSdanielk1977 ){
44424ad1713cSdanielk1977   const char *zFilename;
44434ad1713cSdanielk1977   sqlite3 *db;
44444ad1713cSdanielk1977   char zBuf[100];
44454ad1713cSdanielk1977 
4446afc91047Sdrh   if( objc!=3 && objc!=2 && objc!=1 ){
44474ad1713cSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
44484ad1713cSdanielk1977        Tcl_GetString(objv[0]), " filename options-list", 0);
44494ad1713cSdanielk1977     return TCL_ERROR;
44504ad1713cSdanielk1977   }
44514ad1713cSdanielk1977 
4452afc91047Sdrh   zFilename = objc>1 ? Tcl_GetString(objv[1]) : 0;
4453caffb1a5Sdrh   sqlite3_open(zFilename, &db);
44544ad1713cSdanielk1977 
445564b1bea3Sdrh   if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR;
44564ad1713cSdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
44574ad1713cSdanielk1977   return TCL_OK;
44584ad1713cSdanielk1977 }
44594ad1713cSdanielk1977 
44604ad1713cSdanielk1977 /*
4461286ab7c2Sdan ** Usage: sqlite3_open_v2 FILENAME FLAGS VFS
4462286ab7c2Sdan */
44637617e4a8Smistachkin static int SQLITE_TCLAPI test_open_v2(
4464286ab7c2Sdan   void * clientData,
4465286ab7c2Sdan   Tcl_Interp *interp,
4466286ab7c2Sdan   int objc,
4467286ab7c2Sdan   Tcl_Obj *CONST objv[]
4468286ab7c2Sdan ){
4469286ab7c2Sdan   const char *zFilename;
4470286ab7c2Sdan   const char *zVfs;
4471286ab7c2Sdan   int flags = 0;
4472286ab7c2Sdan   sqlite3 *db;
4473286ab7c2Sdan   int rc;
4474286ab7c2Sdan   char zBuf[100];
4475286ab7c2Sdan 
4476286ab7c2Sdan   int nFlag;
4477286ab7c2Sdan   Tcl_Obj **apFlag;
4478286ab7c2Sdan   int i;
4479286ab7c2Sdan 
4480286ab7c2Sdan   if( objc!=4 ){
4481286ab7c2Sdan     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME FLAGS VFS");
4482286ab7c2Sdan     return TCL_ERROR;
4483286ab7c2Sdan   }
4484286ab7c2Sdan   zFilename = Tcl_GetString(objv[1]);
4485286ab7c2Sdan   zVfs = Tcl_GetString(objv[3]);
4486286ab7c2Sdan   if( zVfs[0]==0x00 ) zVfs = 0;
4487286ab7c2Sdan 
4488286ab7c2Sdan   rc = Tcl_ListObjGetElements(interp, objv[2], &nFlag, &apFlag);
4489286ab7c2Sdan   if( rc!=TCL_OK ) return rc;
4490286ab7c2Sdan   for(i=0; i<nFlag; i++){
4491286ab7c2Sdan     int iFlag;
4492286ab7c2Sdan     struct OpenFlag {
4493286ab7c2Sdan       const char *zFlag;
4494286ab7c2Sdan       int flag;
4495286ab7c2Sdan     } aFlag[] = {
4496286ab7c2Sdan       { "SQLITE_OPEN_READONLY", SQLITE_OPEN_READONLY },
4497286ab7c2Sdan       { "SQLITE_OPEN_READWRITE", SQLITE_OPEN_READWRITE },
4498286ab7c2Sdan       { "SQLITE_OPEN_CREATE", SQLITE_OPEN_CREATE },
4499286ab7c2Sdan       { "SQLITE_OPEN_DELETEONCLOSE", SQLITE_OPEN_DELETEONCLOSE },
4500286ab7c2Sdan       { "SQLITE_OPEN_EXCLUSIVE", SQLITE_OPEN_EXCLUSIVE },
4501286ab7c2Sdan       { "SQLITE_OPEN_AUTOPROXY", SQLITE_OPEN_AUTOPROXY },
4502286ab7c2Sdan       { "SQLITE_OPEN_MAIN_DB", SQLITE_OPEN_MAIN_DB },
4503286ab7c2Sdan       { "SQLITE_OPEN_TEMP_DB", SQLITE_OPEN_TEMP_DB },
4504286ab7c2Sdan       { "SQLITE_OPEN_TRANSIENT_DB", SQLITE_OPEN_TRANSIENT_DB },
4505286ab7c2Sdan       { "SQLITE_OPEN_MAIN_JOURNAL", SQLITE_OPEN_MAIN_JOURNAL },
4506286ab7c2Sdan       { "SQLITE_OPEN_TEMP_JOURNAL", SQLITE_OPEN_TEMP_JOURNAL },
4507286ab7c2Sdan       { "SQLITE_OPEN_SUBJOURNAL", SQLITE_OPEN_SUBJOURNAL },
4508286ab7c2Sdan       { "SQLITE_OPEN_MASTER_JOURNAL", SQLITE_OPEN_MASTER_JOURNAL },
4509286ab7c2Sdan       { "SQLITE_OPEN_NOMUTEX", SQLITE_OPEN_NOMUTEX },
4510286ab7c2Sdan       { "SQLITE_OPEN_FULLMUTEX", SQLITE_OPEN_FULLMUTEX },
4511286ab7c2Sdan       { "SQLITE_OPEN_SHAREDCACHE", SQLITE_OPEN_SHAREDCACHE },
4512286ab7c2Sdan       { "SQLITE_OPEN_PRIVATECACHE", SQLITE_OPEN_PRIVATECACHE },
4513286ab7c2Sdan       { "SQLITE_OPEN_WAL", SQLITE_OPEN_WAL },
4514286ab7c2Sdan       { "SQLITE_OPEN_URI", SQLITE_OPEN_URI },
4515286ab7c2Sdan       { 0, 0 }
4516286ab7c2Sdan     };
4517286ab7c2Sdan     rc = Tcl_GetIndexFromObjStruct(interp, apFlag[i], aFlag, sizeof(aFlag[0]),
4518286ab7c2Sdan         "flag", 0, &iFlag
4519286ab7c2Sdan     );
4520286ab7c2Sdan     if( rc!=TCL_OK ) return rc;
4521286ab7c2Sdan     flags |= aFlag[iFlag].flag;
4522286ab7c2Sdan   }
4523286ab7c2Sdan 
4524286ab7c2Sdan   rc = sqlite3_open_v2(zFilename, &db, flags, zVfs);
4525286ab7c2Sdan   if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR;
4526286ab7c2Sdan   Tcl_AppendResult(interp, zBuf, 0);
4527286ab7c2Sdan   return TCL_OK;
4528286ab7c2Sdan }
4529286ab7c2Sdan 
4530286ab7c2Sdan /*
45314ad1713cSdanielk1977 ** Usage: sqlite3_open16 filename options
45324ad1713cSdanielk1977 */
45337617e4a8Smistachkin static int SQLITE_TCLAPI test_open16(
45344ad1713cSdanielk1977   void * clientData,
45354ad1713cSdanielk1977   Tcl_Interp *interp,
45364ad1713cSdanielk1977   int objc,
45374ad1713cSdanielk1977   Tcl_Obj *CONST objv[]
45384ad1713cSdanielk1977 ){
45395436dc2dSdrh #ifndef SQLITE_OMIT_UTF16
45404ad1713cSdanielk1977   const void *zFilename;
45414ad1713cSdanielk1977   sqlite3 *db;
45424ad1713cSdanielk1977   char zBuf[100];
45434ad1713cSdanielk1977 
45444ad1713cSdanielk1977   if( objc!=3 ){
45454ad1713cSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
45464ad1713cSdanielk1977        Tcl_GetString(objv[0]), " filename options-list", 0);
45474ad1713cSdanielk1977     return TCL_ERROR;
45484ad1713cSdanielk1977   }
45494ad1713cSdanielk1977 
45504ad1713cSdanielk1977   zFilename = Tcl_GetByteArrayFromObj(objv[1], 0);
4551caffb1a5Sdrh   sqlite3_open16(zFilename, &db);
45524ad1713cSdanielk1977 
455364b1bea3Sdrh   if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR;
45544ad1713cSdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
45555436dc2dSdrh #endif /* SQLITE_OMIT_UTF16 */
45564ad1713cSdanielk1977   return TCL_OK;
45574ad1713cSdanielk1977 }
4558d3d39e93Sdrh 
4559d3d39e93Sdrh /*
4560bc6ada41Sdanielk1977 ** Usage: sqlite3_complete16 <UTF-16 string>
4561bc6ada41Sdanielk1977 **
4562bc6ada41Sdanielk1977 ** Return 1 if the supplied argument is a complete SQL statement, or zero
4563bc6ada41Sdanielk1977 ** otherwise.
4564bc6ada41Sdanielk1977 */
45657617e4a8Smistachkin static int SQLITE_TCLAPI test_complete16(
4566bc6ada41Sdanielk1977   void * clientData,
4567bc6ada41Sdanielk1977   Tcl_Interp *interp,
4568bc6ada41Sdanielk1977   int objc,
4569bc6ada41Sdanielk1977   Tcl_Obj *CONST objv[]
4570bc6ada41Sdanielk1977 ){
4571ccae6026Sdrh #if !defined(SQLITE_OMIT_COMPLETE) && !defined(SQLITE_OMIT_UTF16)
4572bc6ada41Sdanielk1977   char *zBuf;
4573bc6ada41Sdanielk1977 
4574bc6ada41Sdanielk1977   if( objc!=2 ){
4575bc6ada41Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "<utf-16 sql>");
4576bc6ada41Sdanielk1977     return TCL_ERROR;
4577bc6ada41Sdanielk1977   }
4578bc6ada41Sdanielk1977 
457903d847eaSdrh   zBuf = (char*)Tcl_GetByteArrayFromObj(objv[1], 0);
4580bc6ada41Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_complete16(zBuf)));
4581ccae6026Sdrh #endif /* SQLITE_OMIT_COMPLETE && SQLITE_OMIT_UTF16 */
4582bc6ada41Sdanielk1977   return TCL_OK;
4583bc6ada41Sdanielk1977 }
4584bc6ada41Sdanielk1977 
4585bc6ada41Sdanielk1977 /*
458691694dbdSdrh ** Usage: sqlite3_normalize SQL
458791694dbdSdrh **
458891694dbdSdrh ** Return the normalized value for an SQL statement.
458991694dbdSdrh */
459091694dbdSdrh static int SQLITE_TCLAPI test_normalize(
459191694dbdSdrh   void * clientData,
459291694dbdSdrh   Tcl_Interp *interp,
459391694dbdSdrh   int objc,
459491694dbdSdrh   Tcl_Obj *CONST objv[]
459591694dbdSdrh ){
459691694dbdSdrh   char *zSql;
459791694dbdSdrh   char *zNorm;
459891694dbdSdrh   extern char *sqlite3_normalize(const char*);
459991694dbdSdrh 
460091694dbdSdrh   if( objc!=2 ){
460191694dbdSdrh     Tcl_WrongNumArgs(interp, 1, objv, "SQL");
460291694dbdSdrh     return TCL_ERROR;
460391694dbdSdrh   }
460491694dbdSdrh 
460591694dbdSdrh   zSql = (char*)Tcl_GetString(objv[1]);
460691694dbdSdrh   zNorm = sqlite3_normalize(zSql);
460791694dbdSdrh   if( zNorm ){
460891694dbdSdrh     Tcl_SetObjResult(interp, Tcl_NewStringObj(zNorm, -1));
460991694dbdSdrh     sqlite3_free(zNorm);
461091694dbdSdrh   }
461191694dbdSdrh   return TCL_OK;
461291694dbdSdrh }
461391694dbdSdrh 
461491694dbdSdrh /*
4615106bb236Sdanielk1977 ** Usage: sqlite3_step STMT
4616106bb236Sdanielk1977 **
4617106bb236Sdanielk1977 ** Advance the statement to the next row.
4618106bb236Sdanielk1977 */
46197617e4a8Smistachkin static int SQLITE_TCLAPI test_step(
4620106bb236Sdanielk1977   void * clientData,
4621106bb236Sdanielk1977   Tcl_Interp *interp,
4622106bb236Sdanielk1977   int objc,
4623106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
4624106bb236Sdanielk1977 ){
4625106bb236Sdanielk1977   sqlite3_stmt *pStmt;
4626106bb236Sdanielk1977   int rc;
4627106bb236Sdanielk1977 
4628e1cd9874Sdanielk1977   if( objc!=2 ){
4629106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
4630106bb236Sdanielk1977        Tcl_GetString(objv[0]), " STMT", 0);
4631106bb236Sdanielk1977     return TCL_ERROR;
4632106bb236Sdanielk1977   }
4633106bb236Sdanielk1977 
4634106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
463517240fd9Sdanielk1977   rc = sqlite3_step(pStmt);
4636106bb236Sdanielk1977 
4637fbcd585fSdanielk1977   /* if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR; */
46384f0c5878Sdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
4639e1cd9874Sdanielk1977   return TCL_OK;
4640e1cd9874Sdanielk1977 }
4641e1cd9874Sdanielk1977 
46427617e4a8Smistachkin static int SQLITE_TCLAPI test_sql(
4643404ca075Sdanielk1977   void * clientData,
4644404ca075Sdanielk1977   Tcl_Interp *interp,
4645404ca075Sdanielk1977   int objc,
4646404ca075Sdanielk1977   Tcl_Obj *CONST objv[]
4647404ca075Sdanielk1977 ){
4648404ca075Sdanielk1977   sqlite3_stmt *pStmt;
4649404ca075Sdanielk1977 
4650404ca075Sdanielk1977   if( objc!=2 ){
4651404ca075Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "STMT");
4652404ca075Sdanielk1977     return TCL_ERROR;
4653404ca075Sdanielk1977   }
4654404ca075Sdanielk1977 
4655404ca075Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
4656404ca075Sdanielk1977   Tcl_SetResult(interp, (char *)sqlite3_sql(pStmt), TCL_VOLATILE);
4657404ca075Sdanielk1977   return TCL_OK;
4658404ca075Sdanielk1977 }
46597617e4a8Smistachkin static int SQLITE_TCLAPI test_ex_sql(
4660fca760c8Sdrh   void * clientData,
4661fca760c8Sdrh   Tcl_Interp *interp,
4662fca760c8Sdrh   int objc,
4663fca760c8Sdrh   Tcl_Obj *CONST objv[]
4664fca760c8Sdrh ){
4665fca760c8Sdrh   sqlite3_stmt *pStmt;
4666fca760c8Sdrh   char *z;
4667fca760c8Sdrh 
4668fca760c8Sdrh   if( objc!=2 ){
4669fca760c8Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "STMT");
4670fca760c8Sdrh     return TCL_ERROR;
4671fca760c8Sdrh   }
4672fca760c8Sdrh 
4673fca760c8Sdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
4674fca760c8Sdrh   z = sqlite3_expanded_sql(pStmt);
4675fca760c8Sdrh   Tcl_SetResult(interp, z, TCL_VOLATILE);
4676fca760c8Sdrh   sqlite3_free(z);
4677fca760c8Sdrh   return TCL_OK;
4678fca760c8Sdrh }
4679404ca075Sdanielk1977 
4680e1cd9874Sdanielk1977 /*
468117240fd9Sdanielk1977 ** Usage: sqlite3_column_count STMT
468217240fd9Sdanielk1977 **
468317240fd9Sdanielk1977 ** Return the number of columns returned by the sql statement STMT.
468417240fd9Sdanielk1977 */
46857617e4a8Smistachkin static int SQLITE_TCLAPI test_column_count(
468617240fd9Sdanielk1977   void * clientData,
468717240fd9Sdanielk1977   Tcl_Interp *interp,
468817240fd9Sdanielk1977   int objc,
468917240fd9Sdanielk1977   Tcl_Obj *CONST objv[]
469017240fd9Sdanielk1977 ){
469117240fd9Sdanielk1977   sqlite3_stmt *pStmt;
469217240fd9Sdanielk1977 
469317240fd9Sdanielk1977   if( objc!=2 ){
469417240fd9Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
469517240fd9Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
469617240fd9Sdanielk1977     return TCL_ERROR;
469717240fd9Sdanielk1977   }
469817240fd9Sdanielk1977 
469917240fd9Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
470017240fd9Sdanielk1977 
470117240fd9Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_column_count(pStmt)));
470217240fd9Sdanielk1977   return TCL_OK;
470317240fd9Sdanielk1977 }
470417240fd9Sdanielk1977 
470517240fd9Sdanielk1977 /*
47063cf86063Sdanielk1977 ** Usage: sqlite3_column_type STMT column
47073cf86063Sdanielk1977 **
47083cf86063Sdanielk1977 ** Return the type of the data in column 'column' of the current row.
47093cf86063Sdanielk1977 */
47107617e4a8Smistachkin static int SQLITE_TCLAPI test_column_type(
47113cf86063Sdanielk1977   void * clientData,
47123cf86063Sdanielk1977   Tcl_Interp *interp,
47133cf86063Sdanielk1977   int objc,
47143cf86063Sdanielk1977   Tcl_Obj *CONST objv[]
47153cf86063Sdanielk1977 ){
47163cf86063Sdanielk1977   sqlite3_stmt *pStmt;
47173cf86063Sdanielk1977   int col;
47183cf86063Sdanielk1977   int tp;
47193cf86063Sdanielk1977 
47203cf86063Sdanielk1977   if( objc!=3 ){
47213cf86063Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
47223cf86063Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
47233cf86063Sdanielk1977     return TCL_ERROR;
47243cf86063Sdanielk1977   }
47253cf86063Sdanielk1977 
47263cf86063Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
47273cf86063Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
47283cf86063Sdanielk1977 
47293cf86063Sdanielk1977   tp = sqlite3_column_type(pStmt, col);
47303cf86063Sdanielk1977   switch( tp ){
47319c054830Sdrh     case SQLITE_INTEGER:
47323cf86063Sdanielk1977       Tcl_SetResult(interp, "INTEGER", TCL_STATIC);
47333cf86063Sdanielk1977       break;
47349c054830Sdrh     case SQLITE_NULL:
47353cf86063Sdanielk1977       Tcl_SetResult(interp, "NULL", TCL_STATIC);
47363cf86063Sdanielk1977       break;
47379c054830Sdrh     case SQLITE_FLOAT:
47383cf86063Sdanielk1977       Tcl_SetResult(interp, "FLOAT", TCL_STATIC);
47393cf86063Sdanielk1977       break;
47409c054830Sdrh     case SQLITE_TEXT:
47413cf86063Sdanielk1977       Tcl_SetResult(interp, "TEXT", TCL_STATIC);
47423cf86063Sdanielk1977       break;
47439c054830Sdrh     case SQLITE_BLOB:
47443cf86063Sdanielk1977       Tcl_SetResult(interp, "BLOB", TCL_STATIC);
47453cf86063Sdanielk1977       break;
47463cf86063Sdanielk1977     default:
47473cf86063Sdanielk1977       assert(0);
47483cf86063Sdanielk1977   }
47493cf86063Sdanielk1977 
47503cf86063Sdanielk1977   return TCL_OK;
47513cf86063Sdanielk1977 }
47523cf86063Sdanielk1977 
47533cf86063Sdanielk1977 /*
475404f2e68dSdanielk1977 ** Usage: sqlite3_column_int64 STMT column
47553cf86063Sdanielk1977 **
47563cf86063Sdanielk1977 ** Return the data in column 'column' of the current row cast as an
475704f2e68dSdanielk1977 ** wide (64-bit) integer.
47583cf86063Sdanielk1977 */
47597617e4a8Smistachkin static int SQLITE_TCLAPI test_column_int64(
47603cf86063Sdanielk1977   void * clientData,
47613cf86063Sdanielk1977   Tcl_Interp *interp,
47623cf86063Sdanielk1977   int objc,
47633cf86063Sdanielk1977   Tcl_Obj *CONST objv[]
47643cf86063Sdanielk1977 ){
47653cf86063Sdanielk1977   sqlite3_stmt *pStmt;
47663cf86063Sdanielk1977   int col;
476704f2e68dSdanielk1977   i64 iVal;
47683cf86063Sdanielk1977 
47693cf86063Sdanielk1977   if( objc!=3 ){
47703cf86063Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
47713cf86063Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
47723cf86063Sdanielk1977     return TCL_ERROR;
47733cf86063Sdanielk1977   }
47743cf86063Sdanielk1977 
47753cf86063Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
47763cf86063Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
47773cf86063Sdanielk1977 
477804f2e68dSdanielk1977   iVal = sqlite3_column_int64(pStmt, col);
477904f2e68dSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(iVal));
478004f2e68dSdanielk1977   return TCL_OK;
478104f2e68dSdanielk1977 }
478204f2e68dSdanielk1977 
478304f2e68dSdanielk1977 /*
4784ea61b2c4Sdanielk1977 ** Usage: sqlite3_column_blob STMT column
4785ea61b2c4Sdanielk1977 */
47867617e4a8Smistachkin static int SQLITE_TCLAPI test_column_blob(
4787ea61b2c4Sdanielk1977   void * clientData,
4788ea61b2c4Sdanielk1977   Tcl_Interp *interp,
4789ea61b2c4Sdanielk1977   int objc,
4790ea61b2c4Sdanielk1977   Tcl_Obj *CONST objv[]
4791ea61b2c4Sdanielk1977 ){
4792ea61b2c4Sdanielk1977   sqlite3_stmt *pStmt;
4793ea61b2c4Sdanielk1977   int col;
4794ea61b2c4Sdanielk1977 
4795ea61b2c4Sdanielk1977   int len;
4796c572ef7fSdanielk1977   const void *pBlob;
4797ea61b2c4Sdanielk1977 
4798ea61b2c4Sdanielk1977   if( objc!=3 ){
4799ea61b2c4Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
4800ea61b2c4Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
4801ea61b2c4Sdanielk1977     return TCL_ERROR;
4802ea61b2c4Sdanielk1977   }
4803ea61b2c4Sdanielk1977 
4804ea61b2c4Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
4805ea61b2c4Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
4806ea61b2c4Sdanielk1977 
4807ea61b2c4Sdanielk1977   len = sqlite3_column_bytes(pStmt, col);
48089310ef23Sdrh   pBlob = sqlite3_column_blob(pStmt, col);
4809ea61b2c4Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pBlob, len));
4810ea61b2c4Sdanielk1977   return TCL_OK;
4811ea61b2c4Sdanielk1977 }
4812ea61b2c4Sdanielk1977 
4813ea61b2c4Sdanielk1977 /*
481404f2e68dSdanielk1977 ** Usage: sqlite3_column_double STMT column
481504f2e68dSdanielk1977 **
481604f2e68dSdanielk1977 ** Return the data in column 'column' of the current row cast as a double.
481704f2e68dSdanielk1977 */
48187617e4a8Smistachkin static int SQLITE_TCLAPI test_column_double(
481904f2e68dSdanielk1977   void * clientData,
482004f2e68dSdanielk1977   Tcl_Interp *interp,
482104f2e68dSdanielk1977   int objc,
482204f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
482304f2e68dSdanielk1977 ){
482404f2e68dSdanielk1977   sqlite3_stmt *pStmt;
482504f2e68dSdanielk1977   int col;
482604f2e68dSdanielk1977   double rVal;
482704f2e68dSdanielk1977 
482804f2e68dSdanielk1977   if( objc!=3 ){
482904f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
483004f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
483104f2e68dSdanielk1977     return TCL_ERROR;
483204f2e68dSdanielk1977   }
483304f2e68dSdanielk1977 
483404f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
483504f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
483604f2e68dSdanielk1977 
483704f2e68dSdanielk1977   rVal = sqlite3_column_double(pStmt, col);
4838c572ef7fSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewDoubleObj(rVal));
48393cf86063Sdanielk1977   return TCL_OK;
48403cf86063Sdanielk1977 }
48413cf86063Sdanielk1977 
48423cf86063Sdanielk1977 /*
484317240fd9Sdanielk1977 ** Usage: sqlite3_data_count STMT
484417240fd9Sdanielk1977 **
484517240fd9Sdanielk1977 ** Return the number of columns returned by the sql statement STMT.
484617240fd9Sdanielk1977 */
48477617e4a8Smistachkin static int SQLITE_TCLAPI test_data_count(
484817240fd9Sdanielk1977   void * clientData,
484917240fd9Sdanielk1977   Tcl_Interp *interp,
485017240fd9Sdanielk1977   int objc,
485117240fd9Sdanielk1977   Tcl_Obj *CONST objv[]
485217240fd9Sdanielk1977 ){
485317240fd9Sdanielk1977   sqlite3_stmt *pStmt;
485417240fd9Sdanielk1977 
485517240fd9Sdanielk1977   if( objc!=2 ){
485617240fd9Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
485717240fd9Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
485817240fd9Sdanielk1977     return TCL_ERROR;
485917240fd9Sdanielk1977   }
486017240fd9Sdanielk1977 
486117240fd9Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
486217240fd9Sdanielk1977 
486317240fd9Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_data_count(pStmt)));
486417240fd9Sdanielk1977   return TCL_OK;
486517240fd9Sdanielk1977 }
486617240fd9Sdanielk1977 
486717240fd9Sdanielk1977 /*
486804f2e68dSdanielk1977 ** Usage: sqlite3_column_text STMT column
486904f2e68dSdanielk1977 **
487004f2e68dSdanielk1977 ** Usage: sqlite3_column_decltype STMT column
487104f2e68dSdanielk1977 **
487204f2e68dSdanielk1977 ** Usage: sqlite3_column_name STMT column
487304f2e68dSdanielk1977 */
48747617e4a8Smistachkin static int SQLITE_TCLAPI test_stmt_utf8(
4875241db313Sdrh   void * clientData,        /* Pointer to SQLite API function to be invoke */
487604f2e68dSdanielk1977   Tcl_Interp *interp,
487704f2e68dSdanielk1977   int objc,
487804f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
487904f2e68dSdanielk1977 ){
488004f2e68dSdanielk1977   sqlite3_stmt *pStmt;
488104f2e68dSdanielk1977   int col;
488244a376f6Sdanielk1977   const char *(*xFunc)(sqlite3_stmt*, int);
4883f93bbbeaSdanielk1977   const char *zRet;
488404f2e68dSdanielk1977 
488544a376f6Sdanielk1977   xFunc = (const char *(*)(sqlite3_stmt*, int))clientData;
488604f2e68dSdanielk1977   if( objc!=3 ){
488704f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
488804f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
488904f2e68dSdanielk1977     return TCL_ERROR;
489004f2e68dSdanielk1977   }
489104f2e68dSdanielk1977 
489204f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
489304f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
4894f93bbbeaSdanielk1977   zRet = xFunc(pStmt, col);
4895f93bbbeaSdanielk1977   if( zRet ){
4896f93bbbeaSdanielk1977     Tcl_SetResult(interp, (char *)zRet, 0);
4897f93bbbeaSdanielk1977   }
489804f2e68dSdanielk1977   return TCL_OK;
489904f2e68dSdanielk1977 }
490004f2e68dSdanielk1977 
49017617e4a8Smistachkin static int SQLITE_TCLAPI test_global_recover(
49026b456a2bSdanielk1977   void * clientData,
49036b456a2bSdanielk1977   Tcl_Interp *interp,
49046b456a2bSdanielk1977   int objc,
49056b456a2bSdanielk1977   Tcl_Obj *CONST objv[]
49066b456a2bSdanielk1977 ){
4907eec556d3Sshane #ifndef SQLITE_OMIT_DEPRECATED
49086b456a2bSdanielk1977   int rc;
49096b456a2bSdanielk1977   if( objc!=1 ){
49106b456a2bSdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "");
49116b456a2bSdanielk1977     return TCL_ERROR;
49126b456a2bSdanielk1977   }
49136b456a2bSdanielk1977   rc = sqlite3_global_recover();
49144f0c5878Sdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
49156b456a2bSdanielk1977 #endif
49166b456a2bSdanielk1977   return TCL_OK;
49176b456a2bSdanielk1977 }
49186b456a2bSdanielk1977 
491904f2e68dSdanielk1977 /*
492004f2e68dSdanielk1977 ** Usage: sqlite3_column_text STMT column
492104f2e68dSdanielk1977 **
492204f2e68dSdanielk1977 ** Usage: sqlite3_column_decltype STMT column
492304f2e68dSdanielk1977 **
492404f2e68dSdanielk1977 ** Usage: sqlite3_column_name STMT column
492504f2e68dSdanielk1977 */
49267617e4a8Smistachkin static int SQLITE_TCLAPI test_stmt_utf16(
4927241db313Sdrh   void * clientData,     /* Pointer to SQLite API function to be invoked */
492804f2e68dSdanielk1977   Tcl_Interp *interp,
492904f2e68dSdanielk1977   int objc,
493004f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
493104f2e68dSdanielk1977 ){
49325436dc2dSdrh #ifndef SQLITE_OMIT_UTF16
493304f2e68dSdanielk1977   sqlite3_stmt *pStmt;
493404f2e68dSdanielk1977   int col;
493504f2e68dSdanielk1977   Tcl_Obj *pRet;
493604f2e68dSdanielk1977   const void *zName16;
493744a376f6Sdanielk1977   const void *(*xFunc)(sqlite3_stmt*, int);
493804f2e68dSdanielk1977 
493944a376f6Sdanielk1977   xFunc = (const void *(*)(sqlite3_stmt*, int))clientData;
494004f2e68dSdanielk1977   if( objc!=3 ){
494104f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
494204f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
494304f2e68dSdanielk1977     return TCL_ERROR;
494404f2e68dSdanielk1977   }
494504f2e68dSdanielk1977 
494604f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
494704f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
494804f2e68dSdanielk1977 
494904f2e68dSdanielk1977   zName16 = xFunc(pStmt, col);
4950f93bbbeaSdanielk1977   if( zName16 ){
4951aed382f9Sdrh     int n;
4952aed382f9Sdrh     const char *z = zName16;
4953aed382f9Sdrh     for(n=0; z[n] || z[n+1]; n+=2){}
4954aed382f9Sdrh     pRet = Tcl_NewByteArrayObj(zName16, n+2);
495504f2e68dSdanielk1977     Tcl_SetObjResult(interp, pRet);
4956f93bbbeaSdanielk1977   }
49575436dc2dSdrh #endif /* SQLITE_OMIT_UTF16 */
495804f2e68dSdanielk1977 
495904f2e68dSdanielk1977   return TCL_OK;
496004f2e68dSdanielk1977 }
496104f2e68dSdanielk1977 
496204f2e68dSdanielk1977 /*
496304f2e68dSdanielk1977 ** Usage: sqlite3_column_int STMT column
496404f2e68dSdanielk1977 **
496504f2e68dSdanielk1977 ** Usage: sqlite3_column_bytes STMT column
496604f2e68dSdanielk1977 **
496704f2e68dSdanielk1977 ** Usage: sqlite3_column_bytes16 STMT column
496804f2e68dSdanielk1977 **
496904f2e68dSdanielk1977 */
49707617e4a8Smistachkin static int SQLITE_TCLAPI test_stmt_int(
4971241db313Sdrh   void * clientData,    /* Pointer to SQLite API function to be invoked */
497204f2e68dSdanielk1977   Tcl_Interp *interp,
497304f2e68dSdanielk1977   int objc,
497404f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
497504f2e68dSdanielk1977 ){
497604f2e68dSdanielk1977   sqlite3_stmt *pStmt;
497704f2e68dSdanielk1977   int col;
497844a376f6Sdanielk1977   int (*xFunc)(sqlite3_stmt*, int);
497904f2e68dSdanielk1977 
498055a25a12Sdanielk1977   xFunc = (int (*)(sqlite3_stmt*, int))clientData;
498104f2e68dSdanielk1977   if( objc!=3 ){
498204f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
498304f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
498404f2e68dSdanielk1977     return TCL_ERROR;
498504f2e68dSdanielk1977   }
498604f2e68dSdanielk1977 
498704f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
498804f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
498904f2e68dSdanielk1977 
499004f2e68dSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(xFunc(pStmt, col)));
499104f2e68dSdanielk1977   return TCL_OK;
499204f2e68dSdanielk1977 }
499304f2e68dSdanielk1977 
49946622cce3Sdanielk1977 /*
4995cacb208eSdrh ** Usage:  sqlite_set_magic  DB  MAGIC-NUMBER
4996cacb208eSdrh **
4997cacb208eSdrh ** Set the db->magic value.  This is used to test error recovery logic.
4998cacb208eSdrh */
49997617e4a8Smistachkin static int SQLITE_TCLAPI sqlite_set_magic(
5000cacb208eSdrh   void * clientData,
5001cacb208eSdrh   Tcl_Interp *interp,
5002cacb208eSdrh   int argc,
5003cacb208eSdrh   char **argv
5004cacb208eSdrh ){
5005cacb208eSdrh   sqlite3 *db;
5006cacb208eSdrh   if( argc!=3 ){
5007cacb208eSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
5008cacb208eSdrh          " DB MAGIC", 0);
5009cacb208eSdrh     return TCL_ERROR;
5010cacb208eSdrh   }
5011cacb208eSdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
5012cacb208eSdrh   if( strcmp(argv[2], "SQLITE_MAGIC_OPEN")==0 ){
5013cacb208eSdrh     db->magic = SQLITE_MAGIC_OPEN;
5014cacb208eSdrh   }else if( strcmp(argv[2], "SQLITE_MAGIC_CLOSED")==0 ){
5015cacb208eSdrh     db->magic = SQLITE_MAGIC_CLOSED;
5016cacb208eSdrh   }else if( strcmp(argv[2], "SQLITE_MAGIC_BUSY")==0 ){
5017cacb208eSdrh     db->magic = SQLITE_MAGIC_BUSY;
5018cacb208eSdrh   }else if( strcmp(argv[2], "SQLITE_MAGIC_ERROR")==0 ){
5019cacb208eSdrh     db->magic = SQLITE_MAGIC_ERROR;
5020902b9ee4Sdrh   }else if( Tcl_GetInt(interp, argv[2], (int*)&db->magic) ){
5021cacb208eSdrh     return TCL_ERROR;
5022cacb208eSdrh   }
5023cacb208eSdrh   return TCL_OK;
5024cacb208eSdrh }
5025cacb208eSdrh 
5026cacb208eSdrh /*
5027c5cdca61Sdrh ** Usage:  sqlite3_interrupt  DB
5028c5cdca61Sdrh **
5029c5cdca61Sdrh ** Trigger an interrupt on DB
5030c5cdca61Sdrh */
50317617e4a8Smistachkin static int SQLITE_TCLAPI test_interrupt(
5032c5cdca61Sdrh   void * clientData,
5033c5cdca61Sdrh   Tcl_Interp *interp,
5034c5cdca61Sdrh   int argc,
5035c5cdca61Sdrh   char **argv
5036c5cdca61Sdrh ){
5037c5cdca61Sdrh   sqlite3 *db;
5038c5cdca61Sdrh   if( argc!=2 ){
5039c5cdca61Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB", 0);
5040c5cdca61Sdrh     return TCL_ERROR;
5041c5cdca61Sdrh   }
5042c5cdca61Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
5043c5cdca61Sdrh   sqlite3_interrupt(db);
5044c5cdca61Sdrh   return TCL_OK;
5045c5cdca61Sdrh }
5046c5cdca61Sdrh 
5047600dd0baSdanielk1977 /*
50489636c4e1Sdanielk1977 ** Usage: sqlite_delete_function DB function-name
50499636c4e1Sdanielk1977 **
50509636c4e1Sdanielk1977 ** Delete the user function 'function-name' from database handle DB. It
50519636c4e1Sdanielk1977 ** is assumed that the user function was created as UTF8, any number of
50529636c4e1Sdanielk1977 ** arguments (the way the TCL interface does it).
50539636c4e1Sdanielk1977 */
50547617e4a8Smistachkin static int SQLITE_TCLAPI delete_function(
50559636c4e1Sdanielk1977   void * clientData,
50569636c4e1Sdanielk1977   Tcl_Interp *interp,
50579636c4e1Sdanielk1977   int argc,
50589636c4e1Sdanielk1977   char **argv
50599636c4e1Sdanielk1977 ){
50609636c4e1Sdanielk1977   int rc;
50619636c4e1Sdanielk1977   sqlite3 *db;
50629636c4e1Sdanielk1977   if( argc!=3 ){
50639636c4e1Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
50649636c4e1Sdanielk1977         " DB function-name", 0);
50659636c4e1Sdanielk1977     return TCL_ERROR;
50669636c4e1Sdanielk1977   }
50679636c4e1Sdanielk1977   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
50689636c4e1Sdanielk1977   rc = sqlite3_create_function(db, argv[2], -1, SQLITE_UTF8, 0, 0, 0, 0);
50694f0c5878Sdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
50709636c4e1Sdanielk1977   return TCL_OK;
50719636c4e1Sdanielk1977 }
50729636c4e1Sdanielk1977 
50739636c4e1Sdanielk1977 /*
50749636c4e1Sdanielk1977 ** Usage: sqlite_delete_collation DB collation-name
50759636c4e1Sdanielk1977 **
50769636c4e1Sdanielk1977 ** Delete the collation sequence 'collation-name' from database handle
50779636c4e1Sdanielk1977 ** DB. It is assumed that the collation sequence was created as UTF8 (the
50789636c4e1Sdanielk1977 ** way the TCL interface does it).
50799636c4e1Sdanielk1977 */
50807617e4a8Smistachkin static int SQLITE_TCLAPI delete_collation(
50819636c4e1Sdanielk1977   void * clientData,
50829636c4e1Sdanielk1977   Tcl_Interp *interp,
50839636c4e1Sdanielk1977   int argc,
50849636c4e1Sdanielk1977   char **argv
50859636c4e1Sdanielk1977 ){
50869636c4e1Sdanielk1977   int rc;
50879636c4e1Sdanielk1977   sqlite3 *db;
50889636c4e1Sdanielk1977   if( argc!=3 ){
50899636c4e1Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
50909636c4e1Sdanielk1977         " DB function-name", 0);
50919636c4e1Sdanielk1977     return TCL_ERROR;
50929636c4e1Sdanielk1977   }
50939636c4e1Sdanielk1977   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
50949636c4e1Sdanielk1977   rc = sqlite3_create_collation(db, argv[2], SQLITE_UTF8, 0, 0);
50954f0c5878Sdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
50969636c4e1Sdanielk1977   return TCL_OK;
50979636c4e1Sdanielk1977 }
50989636c4e1Sdanielk1977 
50999636c4e1Sdanielk1977 /*
51003e1d8e63Sdrh ** Usage: sqlite3_get_autocommit DB
51013e1d8e63Sdrh **
51023e1d8e63Sdrh ** Return true if the database DB is currently in auto-commit mode.
51033e1d8e63Sdrh ** Return false if not.
51043e1d8e63Sdrh */
51057617e4a8Smistachkin static int SQLITE_TCLAPI get_autocommit(
51063e1d8e63Sdrh   void * clientData,
51073e1d8e63Sdrh   Tcl_Interp *interp,
51083e1d8e63Sdrh   int argc,
51093e1d8e63Sdrh   char **argv
51103e1d8e63Sdrh ){
51113e1d8e63Sdrh   char zBuf[30];
51123e1d8e63Sdrh   sqlite3 *db;
51133e1d8e63Sdrh   if( argc!=2 ){
51143e1d8e63Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
51153e1d8e63Sdrh         " DB", 0);
51163e1d8e63Sdrh     return TCL_ERROR;
51173e1d8e63Sdrh   }
51183e1d8e63Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
511965545b59Sdrh   sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", sqlite3_get_autocommit(db));
51203e1d8e63Sdrh   Tcl_AppendResult(interp, zBuf, 0);
51213e1d8e63Sdrh   return TCL_OK;
51223e1d8e63Sdrh }
51233e1d8e63Sdrh 
51243e1d8e63Sdrh /*
51253086765bSdrh ** Usage: sqlite3_busy_timeout DB MS
51263086765bSdrh **
51273086765bSdrh ** Set the busy timeout.  This is more easily done using the timeout
51283086765bSdrh ** method of the TCL interface.  But we need a way to test the case
51293086765bSdrh ** where it returns SQLITE_MISUSE.
51303086765bSdrh */
51317617e4a8Smistachkin static int SQLITE_TCLAPI test_busy_timeout(
51323086765bSdrh   void * clientData,
51333086765bSdrh   Tcl_Interp *interp,
51343086765bSdrh   int argc,
51353086765bSdrh   char **argv
51363086765bSdrh ){
51373086765bSdrh   int rc, ms;
51383086765bSdrh   sqlite3 *db;
51393086765bSdrh   if( argc!=3 ){
51403086765bSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
51413086765bSdrh         " DB", 0);
51423086765bSdrh     return TCL_ERROR;
51433086765bSdrh   }
51443086765bSdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
51453086765bSdrh   if( Tcl_GetInt(interp, argv[2], &ms) ) return TCL_ERROR;
51463086765bSdrh   rc = sqlite3_busy_timeout(db, ms);
5147e84d8d32Smistachkin   Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
51483086765bSdrh   return TCL_OK;
51493086765bSdrh }
51503086765bSdrh 
51513086765bSdrh /*
515292febd92Sdrh ** Usage:  tcl_variable_type VARIABLENAME
515392febd92Sdrh **
515492febd92Sdrh ** Return the name of the internal representation for the
515592febd92Sdrh ** value of the given variable.
515692febd92Sdrh */
51577617e4a8Smistachkin static int SQLITE_TCLAPI tcl_variable_type(
515892febd92Sdrh   void * clientData,
515992febd92Sdrh   Tcl_Interp *interp,
516092febd92Sdrh   int objc,
516192febd92Sdrh   Tcl_Obj *CONST objv[]
516292febd92Sdrh ){
516392febd92Sdrh   Tcl_Obj *pVar;
516492febd92Sdrh   if( objc!=2 ){
516592febd92Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "VARIABLE");
516692febd92Sdrh     return TCL_ERROR;
516792febd92Sdrh   }
516892febd92Sdrh   pVar = Tcl_GetVar2Ex(interp, Tcl_GetString(objv[1]), 0, TCL_LEAVE_ERR_MSG);
516992febd92Sdrh   if( pVar==0 ) return TCL_ERROR;
517092febd92Sdrh   if( pVar->typePtr ){
517192febd92Sdrh     Tcl_SetObjResult(interp, Tcl_NewStringObj(pVar->typePtr->name, -1));
517292febd92Sdrh   }
517392febd92Sdrh   return TCL_OK;
517492febd92Sdrh }
517592febd92Sdrh 
517692febd92Sdrh /*
51776aafc29bSdrh ** Usage:  sqlite3_release_memory ?N?
51786aafc29bSdrh **
51796aafc29bSdrh ** Attempt to release memory currently held but not actually required.
51806aafc29bSdrh ** The integer N is the number of bytes we are trying to release.  The
51816aafc29bSdrh ** return value is the amount of memory actually released.
51826aafc29bSdrh */
51837617e4a8Smistachkin static int SQLITE_TCLAPI test_release_memory(
51846aafc29bSdrh   void * clientData,
51856aafc29bSdrh   Tcl_Interp *interp,
51866aafc29bSdrh   int objc,
51876aafc29bSdrh   Tcl_Obj *CONST objv[]
51886aafc29bSdrh ){
51896f7adc8aSdrh #if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO)
51906aafc29bSdrh   int N;
51916aafc29bSdrh   int amt;
51926aafc29bSdrh   if( objc!=1 && objc!=2 ){
51936aafc29bSdrh     Tcl_WrongNumArgs(interp, 1, objv, "?N?");
51946aafc29bSdrh     return TCL_ERROR;
51956aafc29bSdrh   }
51966aafc29bSdrh   if( objc==2 ){
51976aafc29bSdrh     if( Tcl_GetIntFromObj(interp, objv[1], &N) ) return TCL_ERROR;
51986aafc29bSdrh   }else{
51996aafc29bSdrh     N = -1;
52006aafc29bSdrh   }
52016aafc29bSdrh   amt = sqlite3_release_memory(N);
52026aafc29bSdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(amt));
52036aafc29bSdrh #endif
52046aafc29bSdrh   return TCL_OK;
52056aafc29bSdrh }
52066aafc29bSdrh 
520709419b4bSdrh 
520809419b4bSdrh /*
520909419b4bSdrh ** Usage:  sqlite3_db_release_memory DB
521009419b4bSdrh **
521109419b4bSdrh ** Attempt to release memory currently held by database DB.  Return the
521209419b4bSdrh ** result code (which in the current implementation is always zero).
521309419b4bSdrh */
52147617e4a8Smistachkin static int SQLITE_TCLAPI test_db_release_memory(
521509419b4bSdrh   void * clientData,
521609419b4bSdrh   Tcl_Interp *interp,
521709419b4bSdrh   int objc,
521809419b4bSdrh   Tcl_Obj *CONST objv[]
521909419b4bSdrh ){
522009419b4bSdrh   sqlite3 *db;
522109419b4bSdrh   int rc;
522209419b4bSdrh   if( objc!=2 ){
522309419b4bSdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB");
522409419b4bSdrh     return TCL_ERROR;
522509419b4bSdrh   }
522609419b4bSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
522709419b4bSdrh   rc = sqlite3_db_release_memory(db);
522809419b4bSdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
522909419b4bSdrh   return TCL_OK;
523009419b4bSdrh }
523109419b4bSdrh 
52326aafc29bSdrh /*
52336fa255fdSdan ** Usage:  sqlite3_db_cacheflush DB
52346fa255fdSdan **
52356fa255fdSdan ** Attempt to flush any dirty pages to disk.
52366fa255fdSdan */
52377617e4a8Smistachkin static int SQLITE_TCLAPI test_db_cacheflush(
52386fa255fdSdan   void * clientData,
52396fa255fdSdan   Tcl_Interp *interp,
52406fa255fdSdan   int objc,
52416fa255fdSdan   Tcl_Obj *CONST objv[]
52426fa255fdSdan ){
52436fa255fdSdan   sqlite3 *db;
52446fa255fdSdan   int rc;
52456fa255fdSdan   if( objc!=2 ){
52466fa255fdSdan     Tcl_WrongNumArgs(interp, 1, objv, "DB");
52476fa255fdSdan     return TCL_ERROR;
52486fa255fdSdan   }
52496fa255fdSdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
52506fa255fdSdan   rc = sqlite3_db_cacheflush(db);
52516fa255fdSdan   if( rc ){
52526fa255fdSdan     Tcl_SetResult(interp, (char *)sqlite3ErrStr(rc), TCL_STATIC);
52536fa255fdSdan     return TCL_ERROR;
52546fa255fdSdan   }
52556fa255fdSdan 
52566fa255fdSdan   Tcl_ResetResult(interp);
52576fa255fdSdan   return TCL_OK;
52586fa255fdSdan }
52596fa255fdSdan 
52606fa255fdSdan /*
52610e80e509Sdrh ** Usage:  sqlite3_system_errno DB
52620e80e509Sdrh **
52630e80e509Sdrh ** Return the low-level system errno value.
52640e80e509Sdrh */
52657617e4a8Smistachkin static int SQLITE_TCLAPI test_system_errno(
52660e80e509Sdrh   void * clientData,
52670e80e509Sdrh   Tcl_Interp *interp,
52680e80e509Sdrh   int objc,
52690e80e509Sdrh   Tcl_Obj *CONST objv[]
52700e80e509Sdrh ){
52710e80e509Sdrh   sqlite3 *db;
52720e80e509Sdrh   int iErrno;
52730e80e509Sdrh   if( objc!=2 ){
52740e80e509Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB");
52750e80e509Sdrh     return TCL_ERROR;
52760e80e509Sdrh   }
52770e80e509Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
52780e80e509Sdrh   iErrno = sqlite3_system_errno(db);
52790e80e509Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(iErrno));
52800e80e509Sdrh   return TCL_OK;
52810e80e509Sdrh }
52820e80e509Sdrh 
52830e80e509Sdrh /*
5284283829cbSdrh ** Usage:  sqlite3_db_filename DB DBNAME
5285283829cbSdrh **
5286283829cbSdrh ** Return the name of a file associated with a database.
5287283829cbSdrh */
52887617e4a8Smistachkin static int SQLITE_TCLAPI test_db_filename(
5289283829cbSdrh   void * clientData,
5290283829cbSdrh   Tcl_Interp *interp,
5291283829cbSdrh   int objc,
5292283829cbSdrh   Tcl_Obj *CONST objv[]
5293283829cbSdrh ){
5294283829cbSdrh   sqlite3 *db;
5295283829cbSdrh   const char *zDbName;
5296283829cbSdrh   if( objc!=3 ){
5297283829cbSdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
5298283829cbSdrh     return TCL_ERROR;
5299283829cbSdrh   }
5300283829cbSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
5301283829cbSdrh   zDbName = Tcl_GetString(objv[2]);
5302283829cbSdrh   Tcl_AppendResult(interp, sqlite3_db_filename(db, zDbName), (void*)0);
5303283829cbSdrh   return TCL_OK;
5304283829cbSdrh }
5305283829cbSdrh 
5306283829cbSdrh /*
5307421377e6Sdrh ** Usage:  sqlite3_db_readonly DB DBNAME
5308421377e6Sdrh **
5309421377e6Sdrh ** Return 1 or 0 if DBNAME is readonly or not.  Return -1 if DBNAME does
5310421377e6Sdrh ** not exist.
5311421377e6Sdrh */
53127617e4a8Smistachkin static int SQLITE_TCLAPI test_db_readonly(
5313421377e6Sdrh   void * clientData,
5314421377e6Sdrh   Tcl_Interp *interp,
5315421377e6Sdrh   int objc,
5316421377e6Sdrh   Tcl_Obj *CONST objv[]
5317421377e6Sdrh ){
5318421377e6Sdrh   sqlite3 *db;
5319421377e6Sdrh   const char *zDbName;
5320421377e6Sdrh   if( objc!=3 ){
5321421377e6Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
5322421377e6Sdrh     return TCL_ERROR;
5323421377e6Sdrh   }
5324421377e6Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
5325421377e6Sdrh   zDbName = Tcl_GetString(objv[2]);
5326421377e6Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_db_readonly(db, zDbName)));
5327421377e6Sdrh   return TCL_OK;
5328421377e6Sdrh }
5329421377e6Sdrh 
5330421377e6Sdrh /*
53316aafc29bSdrh ** Usage:  sqlite3_soft_heap_limit ?N?
53326aafc29bSdrh **
53336aafc29bSdrh ** Query or set the soft heap limit for the current thread.  The
53346aafc29bSdrh ** limit is only changed if the N is present.  The previous limit
53356aafc29bSdrh ** is returned.
53366aafc29bSdrh */
53377617e4a8Smistachkin static int SQLITE_TCLAPI test_soft_heap_limit(
53386aafc29bSdrh   void * clientData,
53396aafc29bSdrh   Tcl_Interp *interp,
53406aafc29bSdrh   int objc,
53416aafc29bSdrh   Tcl_Obj *CONST objv[]
53426aafc29bSdrh ){
5343f82ccf64Sdrh   sqlite3_int64 amt;
5344b3f787f4Sdrh   Tcl_WideInt N = -1;
53456aafc29bSdrh   if( objc!=1 && objc!=2 ){
53466aafc29bSdrh     Tcl_WrongNumArgs(interp, 1, objv, "?N?");
53476aafc29bSdrh     return TCL_ERROR;
53486aafc29bSdrh   }
53496aafc29bSdrh   if( objc==2 ){
5350f82ccf64Sdrh     if( Tcl_GetWideIntFromObj(interp, objv[1], &N) ) return TCL_ERROR;
53516aafc29bSdrh   }
5352f82ccf64Sdrh   amt = sqlite3_soft_heap_limit64(N);
5353f82ccf64Sdrh   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(amt));
53546aafc29bSdrh   return TCL_OK;
53556aafc29bSdrh }
53566aafc29bSdrh 
53576aafc29bSdrh /*
5358b4bc7057Sdrh ** Usage:   sqlite3_thread_cleanup
5359b4bc7057Sdrh **
5360b4bc7057Sdrh ** Call the sqlite3_thread_cleanup API.
5361b4bc7057Sdrh */
53627617e4a8Smistachkin static int SQLITE_TCLAPI test_thread_cleanup(
5363b4bc7057Sdrh   void * clientData,
5364b4bc7057Sdrh   Tcl_Interp *interp,
5365b4bc7057Sdrh   int objc,
5366b4bc7057Sdrh   Tcl_Obj *CONST objv[]
5367b4bc7057Sdrh ){
5368eec556d3Sshane #ifndef SQLITE_OMIT_DEPRECATED
5369b4bc7057Sdrh   sqlite3_thread_cleanup();
5370eec556d3Sshane #endif
5371b4bc7057Sdrh   return TCL_OK;
5372b4bc7057Sdrh }
5373b4bc7057Sdrh 
5374b4bc7057Sdrh /*
5375c6ba55f4Sdrh ** Usage:   sqlite3_pager_refcounts  DB
5376c6ba55f4Sdrh **
5377f5345443Sdrh ** Return a list of numbers which are the PagerRefcount for all
5378f5345443Sdrh ** pagers on each database connection.
5379c6ba55f4Sdrh */
53807617e4a8Smistachkin static int SQLITE_TCLAPI test_pager_refcounts(
5381c6ba55f4Sdrh   void * clientData,
5382c6ba55f4Sdrh   Tcl_Interp *interp,
5383c6ba55f4Sdrh   int objc,
5384c6ba55f4Sdrh   Tcl_Obj *CONST objv[]
5385c6ba55f4Sdrh ){
5386c6ba55f4Sdrh   sqlite3 *db;
5387c6ba55f4Sdrh   int i;
5388c6ba55f4Sdrh   int v, *a;
5389c6ba55f4Sdrh   Tcl_Obj *pResult;
5390c6ba55f4Sdrh 
5391c6ba55f4Sdrh   if( objc!=2 ){
5392c6ba55f4Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
5393f5345443Sdrh         Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
5394c6ba55f4Sdrh     return TCL_ERROR;
5395c6ba55f4Sdrh   }
5396c6ba55f4Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
5397c6ba55f4Sdrh   pResult = Tcl_NewObj();
5398c6ba55f4Sdrh   for(i=0; i<db->nDb; i++){
5399c6ba55f4Sdrh     if( db->aDb[i].pBt==0 ){
5400c6ba55f4Sdrh       v = -1;
5401c6ba55f4Sdrh     }else{
540227641703Sdrh       sqlite3_mutex_enter(db->mutex);
5403c6ba55f4Sdrh       a = sqlite3PagerStats(sqlite3BtreePager(db->aDb[i].pBt));
5404c6ba55f4Sdrh       v = a[0];
540527641703Sdrh       sqlite3_mutex_leave(db->mutex);
5406c6ba55f4Sdrh     }
5407c6ba55f4Sdrh     Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(v));
5408c6ba55f4Sdrh   }
5409c6ba55f4Sdrh   Tcl_SetObjResult(interp, pResult);
5410c6ba55f4Sdrh   return TCL_OK;
5411c6ba55f4Sdrh }
5412c6ba55f4Sdrh 
5413c6ba55f4Sdrh 
5414c6ba55f4Sdrh /*
541580788d8bSdrh ** tclcmd:   working_64bit_int
541680788d8bSdrh **
541780788d8bSdrh ** Some TCL builds (ex: cygwin) do not support 64-bit integers.  This
541880788d8bSdrh ** leads to a number of test failures.  The present command checks the
541980788d8bSdrh ** TCL build to see whether or not it supports 64-bit integers.  It
542080788d8bSdrh ** returns TRUE if it does and FALSE if not.
542180788d8bSdrh **
542280788d8bSdrh ** This command is used to warn users that their TCL build is defective
542380788d8bSdrh ** and that the errors they are seeing in the test scripts might be
542480788d8bSdrh ** a result of their defective TCL rather than problems in SQLite.
542580788d8bSdrh */
54267617e4a8Smistachkin static int SQLITE_TCLAPI working_64bit_int(
542780788d8bSdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
542880788d8bSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
542980788d8bSdrh   int objc,              /* Number of arguments */
543080788d8bSdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
543180788d8bSdrh ){
543280788d8bSdrh   Tcl_Obj *pTestObj;
543380788d8bSdrh   int working = 0;
543480788d8bSdrh 
543580788d8bSdrh   pTestObj = Tcl_NewWideIntObj(1000000*(i64)1234567890);
543680788d8bSdrh   working = strcmp(Tcl_GetString(pTestObj), "1234567890000000")==0;
543780788d8bSdrh   Tcl_DecrRefCount(pTestObj);
543880788d8bSdrh   Tcl_SetObjResult(interp, Tcl_NewBooleanObj(working));
543980788d8bSdrh   return TCL_OK;
544080788d8bSdrh }
544180788d8bSdrh 
544280788d8bSdrh 
544380788d8bSdrh /*
54449bc5449fSdrh ** tclcmd:   vfs_unlink_test
54459bc5449fSdrh **
54469bc5449fSdrh ** This TCL command unregisters the primary VFS and then registers
54479bc5449fSdrh ** it back again.  This is used to test the ability to register a
54489bc5449fSdrh ** VFS when none are previously registered, and the ability to
54499bc5449fSdrh ** unregister the only available VFS.  Ticket #2738
54509bc5449fSdrh */
54517617e4a8Smistachkin static int SQLITE_TCLAPI vfs_unlink_test(
54529bc5449fSdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
54539bc5449fSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
54549bc5449fSdrh   int objc,              /* Number of arguments */
54559bc5449fSdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
54569bc5449fSdrh ){
54579bc5449fSdrh   int i;
545891fd4d46Sdrh   sqlite3_vfs *pMain;
54599bc5449fSdrh   sqlite3_vfs *apVfs[20];
546091fd4d46Sdrh   sqlite3_vfs one, two;
54619bc5449fSdrh 
546291fd4d46Sdrh   sqlite3_vfs_unregister(0);   /* Unregister of NULL is harmless */
546391fd4d46Sdrh   one.zName = "__one";
546491fd4d46Sdrh   two.zName = "__two";
546591fd4d46Sdrh 
546691fd4d46Sdrh   /* Calling sqlite3_vfs_register with 2nd argument of 0 does not
546791fd4d46Sdrh   ** change the default VFS
546891fd4d46Sdrh   */
546991fd4d46Sdrh   pMain = sqlite3_vfs_find(0);
547091fd4d46Sdrh   sqlite3_vfs_register(&one, 0);
547191fd4d46Sdrh   assert( pMain==0 || pMain==sqlite3_vfs_find(0) );
547291fd4d46Sdrh   sqlite3_vfs_register(&two, 0);
547391fd4d46Sdrh   assert( pMain==0 || pMain==sqlite3_vfs_find(0) );
547491fd4d46Sdrh 
547591fd4d46Sdrh   /* We can find a VFS by its name */
547691fd4d46Sdrh   assert( sqlite3_vfs_find("__one")==&one );
547791fd4d46Sdrh   assert( sqlite3_vfs_find("__two")==&two );
547891fd4d46Sdrh 
547991fd4d46Sdrh   /* Calling sqlite_vfs_register with non-zero second parameter changes the
548091fd4d46Sdrh   ** default VFS, even if the 1st parameter is an existig VFS that is
548191fd4d46Sdrh   ** previously registered as the non-default.
548291fd4d46Sdrh   */
548391fd4d46Sdrh   sqlite3_vfs_register(&one, 1);
548491fd4d46Sdrh   assert( sqlite3_vfs_find("__one")==&one );
548591fd4d46Sdrh   assert( sqlite3_vfs_find("__two")==&two );
548691fd4d46Sdrh   assert( sqlite3_vfs_find(0)==&one );
548791fd4d46Sdrh   sqlite3_vfs_register(&two, 1);
548891fd4d46Sdrh   assert( sqlite3_vfs_find("__one")==&one );
548991fd4d46Sdrh   assert( sqlite3_vfs_find("__two")==&two );
549091fd4d46Sdrh   assert( sqlite3_vfs_find(0)==&two );
549191fd4d46Sdrh   if( pMain ){
549291fd4d46Sdrh     sqlite3_vfs_register(pMain, 1);
549391fd4d46Sdrh     assert( sqlite3_vfs_find("__one")==&one );
549491fd4d46Sdrh     assert( sqlite3_vfs_find("__two")==&two );
549591fd4d46Sdrh     assert( sqlite3_vfs_find(0)==pMain );
549691fd4d46Sdrh   }
549791fd4d46Sdrh 
549891fd4d46Sdrh   /* Unlink the default VFS.  Repeat until there are no more VFSes
549991fd4d46Sdrh   ** registered.
550091fd4d46Sdrh   */
55019bc5449fSdrh   for(i=0; i<sizeof(apVfs)/sizeof(apVfs[0]); i++){
55029bc5449fSdrh     apVfs[i] = sqlite3_vfs_find(0);
55039bc5449fSdrh     if( apVfs[i] ){
55049bc5449fSdrh       assert( apVfs[i]==sqlite3_vfs_find(apVfs[i]->zName) );
55059bc5449fSdrh       sqlite3_vfs_unregister(apVfs[i]);
55069bc5449fSdrh       assert( 0==sqlite3_vfs_find(apVfs[i]->zName) );
55079bc5449fSdrh     }
55089bc5449fSdrh   }
55099bc5449fSdrh   assert( 0==sqlite3_vfs_find(0) );
551091fd4d46Sdrh 
55111f045330Smlcreech   /* Register the main VFS as non-default (will be made default, since
55121f045330Smlcreech   ** it'll be the only one in existence).
55131f045330Smlcreech   */
55141f045330Smlcreech   sqlite3_vfs_register(pMain, 0);
55151f045330Smlcreech   assert( sqlite3_vfs_find(0)==pMain );
55161f045330Smlcreech 
55171f045330Smlcreech   /* Un-register the main VFS again to restore an empty VFS list */
55181f045330Smlcreech   sqlite3_vfs_unregister(pMain);
55191f045330Smlcreech   assert( 0==sqlite3_vfs_find(0) );
55201f045330Smlcreech 
552191fd4d46Sdrh   /* Relink all VFSes in reverse order. */
55229bc5449fSdrh   for(i=sizeof(apVfs)/sizeof(apVfs[0])-1; i>=0; i--){
55239bc5449fSdrh     if( apVfs[i] ){
55249bc5449fSdrh       sqlite3_vfs_register(apVfs[i], 1);
55259bc5449fSdrh       assert( apVfs[i]==sqlite3_vfs_find(0) );
55269bc5449fSdrh       assert( apVfs[i]==sqlite3_vfs_find(apVfs[i]->zName) );
55279bc5449fSdrh     }
55289bc5449fSdrh   }
552991fd4d46Sdrh 
553091fd4d46Sdrh   /* Unregister out sample VFSes. */
553191fd4d46Sdrh   sqlite3_vfs_unregister(&one);
553291fd4d46Sdrh   sqlite3_vfs_unregister(&two);
553391fd4d46Sdrh 
553491fd4d46Sdrh   /* Unregistering a VFS that is not currently registered is harmless */
553591fd4d46Sdrh   sqlite3_vfs_unregister(&one);
553691fd4d46Sdrh   sqlite3_vfs_unregister(&two);
553791fd4d46Sdrh   assert( sqlite3_vfs_find("__one")==0 );
553891fd4d46Sdrh   assert( sqlite3_vfs_find("__two")==0 );
553991fd4d46Sdrh 
554091fd4d46Sdrh   /* We should be left with the original default VFS back as the
554191fd4d46Sdrh   ** original */
554291fd4d46Sdrh   assert( sqlite3_vfs_find(0)==pMain );
554391fd4d46Sdrh 
55449bc5449fSdrh   return TCL_OK;
55459bc5449fSdrh }
55469bc5449fSdrh 
554793aed5a1Sdrh /*
5548c8d75674Sdrh ** tclcmd:   vfs_initfail_test
5549c8d75674Sdrh **
5550c8d75674Sdrh ** This TCL command attempts to vfs_find and vfs_register when the
5551c8d75674Sdrh ** sqlite3_initialize() interface is failing.  All calls should fail.
5552c8d75674Sdrh */
55537617e4a8Smistachkin static int SQLITE_TCLAPI vfs_initfail_test(
5554c8d75674Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
5555c8d75674Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
5556c8d75674Sdrh   int objc,              /* Number of arguments */
5557c8d75674Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
5558c8d75674Sdrh ){
5559c8d75674Sdrh   sqlite3_vfs one;
5560c8d75674Sdrh   one.zName = "__one";
5561c8d75674Sdrh 
5562c8d75674Sdrh   if( sqlite3_vfs_find(0) ) return TCL_ERROR;
5563c8d75674Sdrh   sqlite3_vfs_register(&one, 0);
5564c8d75674Sdrh   if( sqlite3_vfs_find(0) ) return TCL_ERROR;
5565c8d75674Sdrh   sqlite3_vfs_register(&one, 1);
5566c8d75674Sdrh   if( sqlite3_vfs_find(0) ) return TCL_ERROR;
5567c8d75674Sdrh   return TCL_OK;
5568c8d75674Sdrh }
5569c8d75674Sdrh 
5570c8d75674Sdrh /*
5571a2820970Sdrh ** Saved VFSes
5572a2820970Sdrh */
5573a2820970Sdrh static sqlite3_vfs *apVfs[20];
5574a2820970Sdrh static int nVfs = 0;
5575a2820970Sdrh 
5576a2820970Sdrh /*
5577a2820970Sdrh ** tclcmd:   vfs_unregister_all
5578a2820970Sdrh **
5579a2820970Sdrh ** Unregister all VFSes.
5580a2820970Sdrh */
55817617e4a8Smistachkin static int SQLITE_TCLAPI vfs_unregister_all(
5582a2820970Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
5583a2820970Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
5584a2820970Sdrh   int objc,              /* Number of arguments */
5585a2820970Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
5586a2820970Sdrh ){
5587a2820970Sdrh   int i;
5588a2820970Sdrh   for(i=0; i<ArraySize(apVfs); i++){
5589a2820970Sdrh     apVfs[i] = sqlite3_vfs_find(0);
5590a2820970Sdrh     if( apVfs[i]==0 ) break;
5591a2820970Sdrh     sqlite3_vfs_unregister(apVfs[i]);
5592a2820970Sdrh   }
5593a2820970Sdrh   nVfs = i;
5594a2820970Sdrh   return TCL_OK;
5595a2820970Sdrh }
5596a2820970Sdrh /*
5597a2820970Sdrh ** tclcmd:   vfs_reregister_all
5598a2820970Sdrh **
559905accd22Sdan ** Restore all VFSes that were removed using vfs_unregister_all. Taking
560005accd22Sdan ** care to put the linked list back together in the same order as it was
560105accd22Sdan ** in before vfs_unregister_all was invoked.
5602a2820970Sdrh */
56037617e4a8Smistachkin static int SQLITE_TCLAPI vfs_reregister_all(
5604a2820970Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
5605a2820970Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
5606a2820970Sdrh   int objc,              /* Number of arguments */
5607a2820970Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
5608a2820970Sdrh ){
5609a2820970Sdrh   int i;
561005accd22Sdan   for(i=nVfs-1; i>=0; i--){
561105accd22Sdan     sqlite3_vfs_register(apVfs[i], 1);
5612a2820970Sdrh   }
5613a2820970Sdrh   return TCL_OK;
5614a2820970Sdrh }
5615a2820970Sdrh 
5616a2820970Sdrh 
5617a2820970Sdrh /*
561855176259Sdrh ** tclcmd:   file_control_test DB
561955176259Sdrh **
562055176259Sdrh ** This TCL command runs the sqlite3_file_control interface and
562155176259Sdrh ** verifies correct operation of the same.
562255176259Sdrh */
56237617e4a8Smistachkin static int SQLITE_TCLAPI file_control_test(
562455176259Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
562555176259Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
562655176259Sdrh   int objc,              /* Number of arguments */
562755176259Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
562855176259Sdrh ){
562955176259Sdrh   int iArg = 0;
563055176259Sdrh   sqlite3 *db;
563155176259Sdrh   int rc;
563255176259Sdrh 
563355176259Sdrh   if( objc!=2 ){
563455176259Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
563555176259Sdrh         Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
563655176259Sdrh     return TCL_ERROR;
563755176259Sdrh   }
563855176259Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
563955176259Sdrh   rc = sqlite3_file_control(db, 0, 0, &iArg);
56400b52b7d0Sdrh   assert( rc==SQLITE_NOTFOUND );
564155176259Sdrh   rc = sqlite3_file_control(db, "notadatabase", SQLITE_FCNTL_LOCKSTATE, &iArg);
564255176259Sdrh   assert( rc==SQLITE_ERROR );
564355176259Sdrh   rc = sqlite3_file_control(db, "main", -1, &iArg);
56440b52b7d0Sdrh   assert( rc==SQLITE_NOTFOUND );
564555176259Sdrh   rc = sqlite3_file_control(db, "temp", -1, &iArg);
56460b52b7d0Sdrh   assert( rc==SQLITE_NOTFOUND || rc==SQLITE_ERROR );
5647aebf413dSaswift 
564855176259Sdrh   return TCL_OK;
564955176259Sdrh }
565055176259Sdrh 
5651aebf413dSaswift 
5652aebf413dSaswift /*
5653aebf413dSaswift ** tclcmd:   file_control_lasterrno_test DB
5654aebf413dSaswift **
5655aebf413dSaswift ** This TCL command runs the sqlite3_file_control interface and
5656aebf413dSaswift ** verifies correct operation of the SQLITE_LAST_ERRNO verb.
5657aebf413dSaswift */
56587617e4a8Smistachkin static int SQLITE_TCLAPI file_control_lasterrno_test(
5659aebf413dSaswift   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
5660aebf413dSaswift   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
5661aebf413dSaswift   int objc,              /* Number of arguments */
5662aebf413dSaswift   Tcl_Obj *CONST objv[]  /* Command arguments */
5663aebf413dSaswift ){
5664aebf413dSaswift   int iArg = 0;
5665aebf413dSaswift   sqlite3 *db;
5666aebf413dSaswift   int rc;
5667aebf413dSaswift 
5668aebf413dSaswift   if( objc!=2 ){
5669aebf413dSaswift     Tcl_AppendResult(interp, "wrong # args: should be \"",
5670aebf413dSaswift         Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
5671aebf413dSaswift     return TCL_ERROR;
5672aebf413dSaswift   }
56739db299fbSshane   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
56749db299fbSshane     return TCL_ERROR;
56759db299fbSshane   }
5676aebf413dSaswift   rc = sqlite3_file_control(db, NULL, SQLITE_LAST_ERRNO, &iArg);
56779db299fbSshane   if( rc ){
56789db299fbSshane     Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
56799db299fbSshane     return TCL_ERROR;
56809db299fbSshane   }
5681aebf413dSaswift   if( iArg!=0 ) {
5682aebf413dSaswift     Tcl_AppendResult(interp, "Unexpected non-zero errno: ",
5683aebf413dSaswift                      Tcl_GetStringFromObj(Tcl_NewIntObj(iArg), 0), " ", 0);
5684aebf413dSaswift     return TCL_ERROR;
5685aebf413dSaswift   }
5686aebf413dSaswift   return TCL_OK;
5687aebf413dSaswift }
5688aebf413dSaswift 
5689aebf413dSaswift /*
5690ea99a31cSdrh ** tclcmd:   file_control_data_version DB DBNAME
5691ea99a31cSdrh **
5692ea99a31cSdrh ** This TCL command runs the sqlite3_file_control with the
5693ea99a31cSdrh ** SQLITE_FCNTL_DATA_VERSION opcode, returning the result.
5694ea99a31cSdrh */
5695ea99a31cSdrh static int SQLITE_TCLAPI file_control_data_version(
5696ea99a31cSdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
5697ea99a31cSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
5698ea99a31cSdrh   int objc,              /* Number of arguments */
5699ea99a31cSdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
5700ea99a31cSdrh ){
5701ea99a31cSdrh   unsigned int iVers;             /* data version */
5702ea99a31cSdrh   char *zDb;                      /* Db name ("main", "temp" etc.) */
5703ea99a31cSdrh   sqlite3 *db;                    /* Database handle */
5704ea99a31cSdrh   int rc;                         /* file_control() return code */
5705ea99a31cSdrh   char zBuf[100];
5706ea99a31cSdrh 
5707ea99a31cSdrh   if( objc!=3 && objc!=2 ){
5708ea99a31cSdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB [DBNAME]");
5709ea99a31cSdrh     return TCL_ERROR;
5710ea99a31cSdrh   }
5711ea99a31cSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
5712ea99a31cSdrh    return TCL_ERROR;
5713ea99a31cSdrh   }
5714ea99a31cSdrh   zDb = objc==3 ? Tcl_GetString(objv[2]) : NULL;
5715ea99a31cSdrh 
5716ea99a31cSdrh   rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_DATA_VERSION, (void *)&iVers);
5717ea99a31cSdrh   if( rc ){
5718ea99a31cSdrh     Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
5719ea99a31cSdrh     return TCL_ERROR;
5720ea99a31cSdrh   }else{
5721ea99a31cSdrh     sqlite3_snprintf(sizeof(zBuf),zBuf,"%u",iVers);
5722ea99a31cSdrh     Tcl_SetResult(interp, (char *)zBuf, TCL_VOLATILE);
5723ea99a31cSdrh     return TCL_OK;
5724ea99a31cSdrh   }
5725ea99a31cSdrh }
5726ea99a31cSdrh 
5727ea99a31cSdrh /*
57286e09d69cSdan ** tclcmd:   file_control_chunksize_test DB DBNAME SIZE
57296e09d69cSdan **
57306e09d69cSdan ** This TCL command runs the sqlite3_file_control interface and
57316e09d69cSdan ** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and
57326e09d69cSdan ** SQLITE_SET_LOCKPROXYFILE verbs.
57336e09d69cSdan */
57347617e4a8Smistachkin static int SQLITE_TCLAPI file_control_chunksize_test(
57356e09d69cSdan   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
57366e09d69cSdan   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
57376e09d69cSdan   int objc,              /* Number of arguments */
57386e09d69cSdan   Tcl_Obj *CONST objv[]  /* Command arguments */
57396e09d69cSdan ){
57406e09d69cSdan   int nSize;                      /* New chunk size */
57416e09d69cSdan   char *zDb;                      /* Db name ("main", "temp" etc.) */
57426e09d69cSdan   sqlite3 *db;                    /* Database handle */
57436e09d69cSdan   int rc;                         /* file_control() return code */
57446e09d69cSdan 
57456e09d69cSdan   if( objc!=4 ){
57466e09d69cSdan     Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SIZE");
57476e09d69cSdan     return TCL_ERROR;
57486e09d69cSdan   }
57496e09d69cSdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db)
57506e09d69cSdan    || Tcl_GetIntFromObj(interp, objv[3], &nSize)
57516e09d69cSdan   ){
57526e09d69cSdan    return TCL_ERROR;
57536e09d69cSdan   }
57546e09d69cSdan   zDb = Tcl_GetString(objv[2]);
57556e09d69cSdan   if( zDb[0]=='\0' ) zDb = NULL;
57566e09d69cSdan 
57576e09d69cSdan   rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_CHUNK_SIZE, (void *)&nSize);
57586e09d69cSdan   if( rc ){
5759e84d8d32Smistachkin     Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
57606e09d69cSdan     return TCL_ERROR;
57616e09d69cSdan   }
57626e09d69cSdan   return TCL_OK;
57636e09d69cSdan }
57646e09d69cSdan 
57656e09d69cSdan /*
5766661d71afSdan ** tclcmd:   file_control_sizehint_test DB DBNAME SIZE
5767661d71afSdan **
5768fdd7f71eSdrh ** This TCL command runs the sqlite3_file_control interface
5769fdd7f71eSdrh ** with SQLITE_FCNTL_SIZE_HINT
5770661d71afSdan */
57717617e4a8Smistachkin static int SQLITE_TCLAPI file_control_sizehint_test(
5772661d71afSdan   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
5773661d71afSdan   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
5774661d71afSdan   int objc,              /* Number of arguments */
5775661d71afSdan   Tcl_Obj *CONST objv[]  /* Command arguments */
5776661d71afSdan ){
5777b3f787f4Sdrh   Tcl_WideInt nSize;              /* Hinted size */
5778661d71afSdan   char *zDb;                      /* Db name ("main", "temp" etc.) */
5779661d71afSdan   sqlite3 *db;                    /* Database handle */
5780661d71afSdan   int rc;                         /* file_control() return code */
5781661d71afSdan 
5782661d71afSdan   if( objc!=4 ){
5783661d71afSdan     Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SIZE");
5784661d71afSdan     return TCL_ERROR;
5785661d71afSdan   }
5786661d71afSdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db)
5787661d71afSdan    || Tcl_GetWideIntFromObj(interp, objv[3], &nSize)
5788661d71afSdan   ){
5789661d71afSdan    return TCL_ERROR;
5790661d71afSdan   }
5791661d71afSdan   zDb = Tcl_GetString(objv[2]);
5792661d71afSdan   if( zDb[0]=='\0' ) zDb = NULL;
5793661d71afSdan 
5794661d71afSdan   rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_SIZE_HINT, (void *)&nSize);
5795661d71afSdan   if( rc ){
5796e84d8d32Smistachkin     Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
5797661d71afSdan     return TCL_ERROR;
5798661d71afSdan   }
5799661d71afSdan   return TCL_OK;
5800661d71afSdan }
5801661d71afSdan 
5802661d71afSdan /*
5803ad24581eSdrh ** tclcmd:   file_control_lockproxy_test DB PWD
5804aebf413dSaswift **
5805aebf413dSaswift ** This TCL command runs the sqlite3_file_control interface and
5806aebf413dSaswift ** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and
5807aebf413dSaswift ** SQLITE_SET_LOCKPROXYFILE verbs.
5808aebf413dSaswift */
58097617e4a8Smistachkin static int SQLITE_TCLAPI file_control_lockproxy_test(
5810aebf413dSaswift   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
5811aebf413dSaswift   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
5812aebf413dSaswift   int objc,              /* Number of arguments */
5813aebf413dSaswift   Tcl_Obj *CONST objv[]  /* Command arguments */
5814aebf413dSaswift ){
5815aebf413dSaswift   sqlite3 *db;
5816aebf413dSaswift 
5817ad24581eSdrh   if( objc!=3 ){
5818aebf413dSaswift     Tcl_AppendResult(interp, "wrong # args: should be \"",
5819ad24581eSdrh                      Tcl_GetStringFromObj(objv[0], 0), " DB PWD", 0);
5820aebf413dSaswift     return TCL_ERROR;
5821aebf413dSaswift   }
58229db299fbSshane   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
58239db299fbSshane    return TCL_ERROR;
58249db299fbSshane   }
5825aebf413dSaswift 
58269b35ea62Sdrh #if !defined(SQLITE_ENABLE_LOCKING_STYLE)
5827d2cb50b7Sdrh #  if defined(__APPLE__)
58289b35ea62Sdrh #    define SQLITE_ENABLE_LOCKING_STYLE 1
58299b35ea62Sdrh #  else
58309b35ea62Sdrh #    define SQLITE_ENABLE_LOCKING_STYLE 0
58319b35ea62Sdrh #  endif
58329b35ea62Sdrh #endif
5833d2cb50b7Sdrh #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
5834aebf413dSaswift   {
5835aebf413dSaswift     char *testPath;
5836103fe743Sdrh     int rc;
5837caffb1a5Sdrh     int nPwd;
5838caffb1a5Sdrh     const char *zPwd;
5839ad24581eSdrh     char proxyPath[400];
5840ad24581eSdrh 
5841caffb1a5Sdrh     zPwd = Tcl_GetStringFromObj(objv[2], &nPwd);
5842ad24581eSdrh     if( sizeof(proxyPath)<nPwd+20 ){
5843ad24581eSdrh       Tcl_AppendResult(interp, "PWD too big", (void*)0);
5844ad24581eSdrh       return TCL_ERROR;
5845ad24581eSdrh     }
584665545b59Sdrh     sqlite3_snprintf(sizeof(proxyPath), proxyPath, "%s/test.proxy", zPwd);
5847aebf413dSaswift     rc = sqlite3_file_control(db, NULL, SQLITE_SET_LOCKPROXYFILE, proxyPath);
58487708e972Sdrh     if( rc ){
58499db299fbSshane       Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
58509db299fbSshane       return TCL_ERROR;
58517708e972Sdrh     }
5852aebf413dSaswift     rc = sqlite3_file_control(db, NULL, SQLITE_GET_LOCKPROXYFILE, &testPath);
5853aebf413dSaswift     if( strncmp(proxyPath,testPath,11) ){
58547708e972Sdrh       Tcl_AppendResult(interp, "Lock proxy file did not match the "
58557708e972Sdrh                                "previously assigned value", 0);
5856aebf413dSaswift       return TCL_ERROR;
5857aebf413dSaswift     }
58587708e972Sdrh     if( rc ){
58597708e972Sdrh       Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
58607708e972Sdrh       return TCL_ERROR;
58617708e972Sdrh     }
5862aebf413dSaswift     rc = sqlite3_file_control(db, NULL, SQLITE_SET_LOCKPROXYFILE, proxyPath);
58637708e972Sdrh     if( rc ){
58647708e972Sdrh       Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
58657708e972Sdrh       return TCL_ERROR;
58667708e972Sdrh     }
5867aebf413dSaswift   }
5868aebf413dSaswift #endif
5869aebf413dSaswift   return TCL_OK;
5870aebf413dSaswift }
5871aebf413dSaswift 
58726b98d67bSmistachkin #if SQLITE_OS_WIN
5873d0cdf012Sdrh /*
5874d0cdf012Sdrh ** tclcmd:   file_control_win32_av_retry DB  NRETRY  DELAY
5875d0cdf012Sdrh **
5876d0cdf012Sdrh ** This TCL command runs the sqlite3_file_control interface with
5877d0cdf012Sdrh ** the SQLITE_FCNTL_WIN32_AV_RETRY opcode.
5878d0cdf012Sdrh */
58797617e4a8Smistachkin static int SQLITE_TCLAPI file_control_win32_av_retry(
5880d0cdf012Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
5881d0cdf012Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
5882d0cdf012Sdrh   int objc,              /* Number of arguments */
5883d0cdf012Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
5884d0cdf012Sdrh ){
5885d0cdf012Sdrh   sqlite3 *db;
5886d0cdf012Sdrh   int rc;
5887d0cdf012Sdrh   int a[2];
5888d0cdf012Sdrh   char z[100];
5889d0cdf012Sdrh 
5890d0cdf012Sdrh   if( objc!=4 ){
5891d0cdf012Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
5892d0cdf012Sdrh         Tcl_GetStringFromObj(objv[0], 0), " DB NRETRY DELAY", 0);
5893d0cdf012Sdrh     return TCL_ERROR;
5894d0cdf012Sdrh   }
5895d0cdf012Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
5896d0cdf012Sdrh     return TCL_ERROR;
5897d0cdf012Sdrh   }
5898d0cdf012Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &a[0]) ) return TCL_ERROR;
5899d0cdf012Sdrh   if( Tcl_GetIntFromObj(interp, objv[3], &a[1]) ) return TCL_ERROR;
5900d0cdf012Sdrh   rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_WIN32_AV_RETRY, (void*)a);
5901d0cdf012Sdrh   sqlite3_snprintf(sizeof(z), z, "%d %d %d", rc, a[0], a[1]);
5902d0cdf012Sdrh   Tcl_AppendResult(interp, z, (char*)0);
5903d0cdf012Sdrh   return TCL_OK;
5904d0cdf012Sdrh }
5905d0cdf012Sdrh 
5906253cea5cSdrh /*
59071b361ff3Smistachkin ** tclcmd:   file_control_win32_get_handle DB
59081b361ff3Smistachkin **
59091b361ff3Smistachkin ** This TCL command runs the sqlite3_file_control interface with
59101b361ff3Smistachkin ** the SQLITE_FCNTL_WIN32_GET_HANDLE opcode.
59111b361ff3Smistachkin */
59121b361ff3Smistachkin static int file_control_win32_get_handle(
59131b361ff3Smistachkin   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
59141b361ff3Smistachkin   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
59151b361ff3Smistachkin   int objc,              /* Number of arguments */
59161b361ff3Smistachkin   Tcl_Obj *CONST objv[]  /* Command arguments */
59171b361ff3Smistachkin ){
59181b361ff3Smistachkin   sqlite3 *db;
59191b361ff3Smistachkin   int rc;
59201b361ff3Smistachkin   HANDLE hFile = NULL;
59211b361ff3Smistachkin   char z[100];
59221b361ff3Smistachkin 
59231b361ff3Smistachkin   if( objc!=2 ){
59241b361ff3Smistachkin     Tcl_AppendResult(interp, "wrong # args: should be \"",
59251b361ff3Smistachkin         Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
59261b361ff3Smistachkin     return TCL_ERROR;
59271b361ff3Smistachkin   }
59281b361ff3Smistachkin   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
59291b361ff3Smistachkin     return TCL_ERROR;
59301b361ff3Smistachkin   }
59311b361ff3Smistachkin   rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_WIN32_GET_HANDLE,
59321b361ff3Smistachkin                             (void*)&hFile);
59331b361ff3Smistachkin   sqlite3_snprintf(sizeof(z), z, "%d %p", rc, (void*)hFile);
59341b361ff3Smistachkin   Tcl_AppendResult(interp, z, (char*)0);
59351b361ff3Smistachkin   return TCL_OK;
59361b361ff3Smistachkin }
59371b361ff3Smistachkin 
59381b361ff3Smistachkin /*
59396b98d67bSmistachkin ** tclcmd:   file_control_win32_set_handle DB HANDLE
59406b98d67bSmistachkin **
59416b98d67bSmistachkin ** This TCL command runs the sqlite3_file_control interface with
59426b98d67bSmistachkin ** the SQLITE_FCNTL_WIN32_SET_HANDLE opcode.
59436b98d67bSmistachkin */
59447617e4a8Smistachkin static int SQLITE_TCLAPI file_control_win32_set_handle(
59456b98d67bSmistachkin   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
59466b98d67bSmistachkin   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
59476b98d67bSmistachkin   int objc,              /* Number of arguments */
59486b98d67bSmistachkin   Tcl_Obj *CONST objv[]  /* Command arguments */
59496b98d67bSmistachkin ){
59506b98d67bSmistachkin   sqlite3 *db;
59516b98d67bSmistachkin   int rc;
59526b98d67bSmistachkin   HANDLE hFile = NULL;
59536b98d67bSmistachkin   char z[100];
59546b98d67bSmistachkin 
59556b98d67bSmistachkin   if( objc!=3 ){
59566b98d67bSmistachkin     Tcl_AppendResult(interp, "wrong # args: should be \"",
59576b98d67bSmistachkin         Tcl_GetStringFromObj(objv[0], 0), " DB HANDLE", 0);
59586b98d67bSmistachkin     return TCL_ERROR;
59596b98d67bSmistachkin   }
59606b98d67bSmistachkin   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
59616b98d67bSmistachkin     return TCL_ERROR;
59626b98d67bSmistachkin   }
59636b98d67bSmistachkin   if( getWin32Handle(interp, Tcl_GetString(objv[2]), &hFile) ){
59646b98d67bSmistachkin     return TCL_ERROR;
59656b98d67bSmistachkin   }
59666b98d67bSmistachkin   rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_WIN32_SET_HANDLE,
59676b98d67bSmistachkin                             (void*)&hFile);
59686b98d67bSmistachkin   sqlite3_snprintf(sizeof(z), z, "%d %p", rc, (void*)hFile);
59696b98d67bSmistachkin   Tcl_AppendResult(interp, z, (char*)0);
59706b98d67bSmistachkin   return TCL_OK;
59716b98d67bSmistachkin }
59726b98d67bSmistachkin #endif
59736b98d67bSmistachkin 
59746b98d67bSmistachkin /*
5975253cea5cSdrh ** tclcmd:   file_control_persist_wal DB PERSIST-FLAG
5976253cea5cSdrh **
5977253cea5cSdrh ** This TCL command runs the sqlite3_file_control interface with
5978253cea5cSdrh ** the SQLITE_FCNTL_PERSIST_WAL opcode.
5979253cea5cSdrh */
59807617e4a8Smistachkin static int SQLITE_TCLAPI file_control_persist_wal(
5981253cea5cSdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
5982253cea5cSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
5983253cea5cSdrh   int objc,              /* Number of arguments */
5984253cea5cSdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
5985253cea5cSdrh ){
5986253cea5cSdrh   sqlite3 *db;
5987253cea5cSdrh   int rc;
5988253cea5cSdrh   int bPersist;
5989253cea5cSdrh   char z[100];
5990253cea5cSdrh 
5991253cea5cSdrh   if( objc!=3 ){
5992253cea5cSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
5993253cea5cSdrh         Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", 0);
5994253cea5cSdrh     return TCL_ERROR;
5995253cea5cSdrh   }
5996253cea5cSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
5997253cea5cSdrh     return TCL_ERROR;
5998253cea5cSdrh   }
5999253cea5cSdrh   if( Tcl_GetIntFromObj(interp, objv[2], &bPersist) ) return TCL_ERROR;
6000253cea5cSdrh   rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_PERSIST_WAL, (void*)&bPersist);
6001253cea5cSdrh   sqlite3_snprintf(sizeof(z), z, "%d %d", rc, bPersist);
6002253cea5cSdrh   Tcl_AppendResult(interp, z, (char*)0);
6003253cea5cSdrh   return TCL_OK;
6004253cea5cSdrh }
6005253cea5cSdrh 
6006f12b3f60Sdrh /*
6007cb15f35fSdrh ** tclcmd:   file_control_powersafe_overwrite DB PSOW-FLAG
6008f12b3f60Sdrh **
6009f12b3f60Sdrh ** This TCL command runs the sqlite3_file_control interface with
6010cb15f35fSdrh ** the SQLITE_FCNTL_POWERSAFE_OVERWRITE opcode.
6011f12b3f60Sdrh */
60127617e4a8Smistachkin static int SQLITE_TCLAPI file_control_powersafe_overwrite(
6013f12b3f60Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6014f12b3f60Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6015f12b3f60Sdrh   int objc,              /* Number of arguments */
6016f12b3f60Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
6017f12b3f60Sdrh ){
6018f12b3f60Sdrh   sqlite3 *db;
6019f12b3f60Sdrh   int rc;
6020cb15f35fSdrh   int b;
6021f12b3f60Sdrh   char z[100];
6022f12b3f60Sdrh 
6023f12b3f60Sdrh   if( objc!=3 ){
6024f12b3f60Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
6025f12b3f60Sdrh         Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", 0);
6026f12b3f60Sdrh     return TCL_ERROR;
6027f12b3f60Sdrh   }
6028f12b3f60Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
6029f12b3f60Sdrh     return TCL_ERROR;
6030f12b3f60Sdrh   }
6031cb15f35fSdrh   if( Tcl_GetIntFromObj(interp, objv[2], &b) ) return TCL_ERROR;
6032cb15f35fSdrh   rc = sqlite3_file_control(db,NULL,SQLITE_FCNTL_POWERSAFE_OVERWRITE,(void*)&b);
6033cb15f35fSdrh   sqlite3_snprintf(sizeof(z), z, "%d %d", rc, b);
6034f12b3f60Sdrh   Tcl_AppendResult(interp, z, (char*)0);
6035f12b3f60Sdrh   return TCL_OK;
6036f12b3f60Sdrh }
6037f12b3f60Sdrh 
6038aebf413dSaswift 
603955176259Sdrh /*
6040de60fc2dSdrh ** tclcmd:   file_control_vfsname DB ?AUXDB?
6041de60fc2dSdrh **
6042de60fc2dSdrh ** Return a string that describes the stack of VFSes.
6043de60fc2dSdrh */
60447617e4a8Smistachkin static int SQLITE_TCLAPI file_control_vfsname(
6045de60fc2dSdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6046de60fc2dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6047de60fc2dSdrh   int objc,              /* Number of arguments */
6048de60fc2dSdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
6049de60fc2dSdrh ){
6050de60fc2dSdrh   sqlite3 *db;
6051de60fc2dSdrh   const char *zDbName = "main";
6052de60fc2dSdrh   char *zVfsName = 0;
6053de60fc2dSdrh 
6054de60fc2dSdrh   if( objc!=2 && objc!=3 ){
6055de60fc2dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
6056de60fc2dSdrh         Tcl_GetStringFromObj(objv[0], 0), " DB ?AUXDB?", 0);
6057de60fc2dSdrh     return TCL_ERROR;
6058de60fc2dSdrh   }
6059de60fc2dSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
6060de60fc2dSdrh     return TCL_ERROR;
6061de60fc2dSdrh   }
6062de60fc2dSdrh   if( objc==3 ){
6063de60fc2dSdrh     zDbName = Tcl_GetString(objv[2]);
6064de60fc2dSdrh   }
6065de60fc2dSdrh   sqlite3_file_control(db, zDbName, SQLITE_FCNTL_VFSNAME,(void*)&zVfsName);
6066de60fc2dSdrh   Tcl_AppendResult(interp, zVfsName, (char*)0);
6067de60fc2dSdrh   sqlite3_free(zVfsName);
6068de60fc2dSdrh   return TCL_OK;
6069de60fc2dSdrh }
6070de60fc2dSdrh 
6071696b33e6Sdrh /*
6072696b33e6Sdrh ** tclcmd:   file_control_tempfilename DB ?AUXDB?
6073696b33e6Sdrh **
6074696b33e6Sdrh ** Return a string that is a temporary filename
6075696b33e6Sdrh */
60767617e4a8Smistachkin static int SQLITE_TCLAPI file_control_tempfilename(
6077696b33e6Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6078696b33e6Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6079696b33e6Sdrh   int objc,              /* Number of arguments */
6080696b33e6Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
6081696b33e6Sdrh ){
6082696b33e6Sdrh   sqlite3 *db;
6083696b33e6Sdrh   const char *zDbName = "main";
6084696b33e6Sdrh   char *zTName = 0;
6085696b33e6Sdrh 
6086696b33e6Sdrh   if( objc!=2 && objc!=3 ){
6087696b33e6Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
6088696b33e6Sdrh         Tcl_GetStringFromObj(objv[0], 0), " DB ?AUXDB?", 0);
6089696b33e6Sdrh     return TCL_ERROR;
6090696b33e6Sdrh   }
6091696b33e6Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
6092696b33e6Sdrh     return TCL_ERROR;
6093696b33e6Sdrh   }
6094696b33e6Sdrh   if( objc==3 ){
6095696b33e6Sdrh     zDbName = Tcl_GetString(objv[2]);
6096696b33e6Sdrh   }
6097696b33e6Sdrh   sqlite3_file_control(db, zDbName, SQLITE_FCNTL_TEMPFILENAME, (void*)&zTName);
6098696b33e6Sdrh   Tcl_AppendResult(interp, zTName, (char*)0);
6099696b33e6Sdrh   sqlite3_free(zTName);
6100696b33e6Sdrh   return TCL_OK;
6101696b33e6Sdrh }
6102696b33e6Sdrh 
6103de60fc2dSdrh 
6104de60fc2dSdrh /*
6105e339d65aSdanielk1977 ** tclcmd:   sqlite3_vfs_list
6106e339d65aSdanielk1977 **
6107e339d65aSdanielk1977 **   Return a tcl list containing the names of all registered vfs's.
6108e339d65aSdanielk1977 */
61097617e4a8Smistachkin static int SQLITE_TCLAPI vfs_list(
6110e339d65aSdanielk1977   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6111e339d65aSdanielk1977   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6112e339d65aSdanielk1977   int objc,              /* Number of arguments */
6113e339d65aSdanielk1977   Tcl_Obj *CONST objv[]  /* Command arguments */
6114e339d65aSdanielk1977 ){
6115e339d65aSdanielk1977   sqlite3_vfs *pVfs;
6116e339d65aSdanielk1977   Tcl_Obj *pRet = Tcl_NewObj();
6117e339d65aSdanielk1977   if( objc!=1 ){
6118e339d65aSdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "");
6119e339d65aSdanielk1977     return TCL_ERROR;
6120e339d65aSdanielk1977   }
6121e339d65aSdanielk1977   for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){
6122e339d65aSdanielk1977     Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(pVfs->zName, -1));
6123e339d65aSdanielk1977   }
6124e339d65aSdanielk1977   Tcl_SetObjResult(interp, pRet);
6125e339d65aSdanielk1977   return TCL_OK;
6126e339d65aSdanielk1977 }
6127e339d65aSdanielk1977 
6128e339d65aSdanielk1977 /*
6129b1a6c3c1Sdrh ** tclcmd:   sqlite3_limit DB ID VALUE
6130b1a6c3c1Sdrh **
6131b1a6c3c1Sdrh ** This TCL command runs the sqlite3_limit interface and
6132b1a6c3c1Sdrh ** verifies correct operation of the same.
6133b1a6c3c1Sdrh */
61347617e4a8Smistachkin static int SQLITE_TCLAPI test_limit(
6135b1a6c3c1Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6136b1a6c3c1Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6137b1a6c3c1Sdrh   int objc,              /* Number of arguments */
6138b1a6c3c1Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
6139b1a6c3c1Sdrh ){
6140b1a6c3c1Sdrh   sqlite3 *db;
6141b1a6c3c1Sdrh   int rc;
6142b1a6c3c1Sdrh   static const struct {
6143b1a6c3c1Sdrh      char *zName;
6144b1a6c3c1Sdrh      int id;
6145b1a6c3c1Sdrh   } aId[] = {
6146b1a6c3c1Sdrh     { "SQLITE_LIMIT_LENGTH",              SQLITE_LIMIT_LENGTH               },
6147b1a6c3c1Sdrh     { "SQLITE_LIMIT_SQL_LENGTH",          SQLITE_LIMIT_SQL_LENGTH           },
6148b1a6c3c1Sdrh     { "SQLITE_LIMIT_COLUMN",              SQLITE_LIMIT_COLUMN               },
6149b1a6c3c1Sdrh     { "SQLITE_LIMIT_EXPR_DEPTH",          SQLITE_LIMIT_EXPR_DEPTH           },
6150b1a6c3c1Sdrh     { "SQLITE_LIMIT_COMPOUND_SELECT",     SQLITE_LIMIT_COMPOUND_SELECT      },
6151b1a6c3c1Sdrh     { "SQLITE_LIMIT_VDBE_OP",             SQLITE_LIMIT_VDBE_OP              },
6152b1a6c3c1Sdrh     { "SQLITE_LIMIT_FUNCTION_ARG",        SQLITE_LIMIT_FUNCTION_ARG         },
6153b1a6c3c1Sdrh     { "SQLITE_LIMIT_ATTACHED",            SQLITE_LIMIT_ATTACHED             },
6154b1a6c3c1Sdrh     { "SQLITE_LIMIT_LIKE_PATTERN_LENGTH", SQLITE_LIMIT_LIKE_PATTERN_LENGTH  },
6155b1a6c3c1Sdrh     { "SQLITE_LIMIT_VARIABLE_NUMBER",     SQLITE_LIMIT_VARIABLE_NUMBER      },
6156417168adSdrh     { "SQLITE_LIMIT_TRIGGER_DEPTH",       SQLITE_LIMIT_TRIGGER_DEPTH        },
61573705ef6aSdrh     { "SQLITE_LIMIT_WORKER_THREADS",      SQLITE_LIMIT_WORKER_THREADS       },
6158521cc849Sdrh 
6159521cc849Sdrh     /* Out of range test cases */
6160521cc849Sdrh     { "SQLITE_LIMIT_TOOSMALL",            -1,                               },
61613705ef6aSdrh     { "SQLITE_LIMIT_TOOBIG",              SQLITE_LIMIT_WORKER_THREADS+1     },
6162b1a6c3c1Sdrh   };
616327b2f053Smistachkin   int i, id = 0;
6164b1a6c3c1Sdrh   int val;
6165b1a6c3c1Sdrh   const char *zId;
6166b1a6c3c1Sdrh 
6167b1a6c3c1Sdrh   if( objc!=4 ){
6168b1a6c3c1Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
6169b1a6c3c1Sdrh         Tcl_GetStringFromObj(objv[0], 0), " DB ID VALUE", 0);
6170b1a6c3c1Sdrh     return TCL_ERROR;
6171b1a6c3c1Sdrh   }
6172b1a6c3c1Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
6173b1a6c3c1Sdrh   zId = Tcl_GetString(objv[2]);
6174b1a6c3c1Sdrh   for(i=0; i<sizeof(aId)/sizeof(aId[0]); i++){
6175b1a6c3c1Sdrh     if( strcmp(zId, aId[i].zName)==0 ){
6176b1a6c3c1Sdrh       id = aId[i].id;
6177b1a6c3c1Sdrh       break;
6178b1a6c3c1Sdrh     }
6179b1a6c3c1Sdrh   }
6180b1a6c3c1Sdrh   if( i>=sizeof(aId)/sizeof(aId[0]) ){
6181b1a6c3c1Sdrh     Tcl_AppendResult(interp, "unknown limit type: ", zId, (char*)0);
6182b1a6c3c1Sdrh     return TCL_ERROR;
6183b1a6c3c1Sdrh   }
6184b1a6c3c1Sdrh   if( Tcl_GetIntFromObj(interp, objv[3], &val) ) return TCL_ERROR;
6185b1a6c3c1Sdrh   rc = sqlite3_limit(db, id, val);
6186b1a6c3c1Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
6187b1a6c3c1Sdrh   return TCL_OK;
6188b1a6c3c1Sdrh }
6189b1a6c3c1Sdrh 
6190b1a6c3c1Sdrh /*
619193aed5a1Sdrh ** tclcmd:  save_prng_state
6192a2820970Sdrh **
6193a2820970Sdrh ** Save the state of the pseudo-random number generator.
6194a2820970Sdrh ** At the same time, verify that sqlite3_test_control works even when
6195a2820970Sdrh ** called with an out-of-range opcode.
619693aed5a1Sdrh */
61977617e4a8Smistachkin static int SQLITE_TCLAPI save_prng_state(
619893aed5a1Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
619993aed5a1Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
620093aed5a1Sdrh   int objc,              /* Number of arguments */
620193aed5a1Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
620293aed5a1Sdrh ){
6203a2820970Sdrh   int rc = sqlite3_test_control(9999);
6204a2820970Sdrh   assert( rc==0 );
6205a2820970Sdrh   rc = sqlite3_test_control(-1);
6206a2820970Sdrh   assert( rc==0 );
62072fa1868fSdrh   sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SAVE);
620893aed5a1Sdrh   return TCL_OK;
620993aed5a1Sdrh }
621093aed5a1Sdrh /*
621193aed5a1Sdrh ** tclcmd:  restore_prng_state
621293aed5a1Sdrh */
62137617e4a8Smistachkin static int SQLITE_TCLAPI restore_prng_state(
621493aed5a1Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
621593aed5a1Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
621693aed5a1Sdrh   int objc,              /* Number of arguments */
621793aed5a1Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
621893aed5a1Sdrh ){
62192fa1868fSdrh   sqlite3_test_control(SQLITE_TESTCTRL_PRNG_RESTORE);
622093aed5a1Sdrh   return TCL_OK;
622193aed5a1Sdrh }
622293aed5a1Sdrh /*
622393aed5a1Sdrh ** tclcmd:  reset_prng_state
622493aed5a1Sdrh */
62257617e4a8Smistachkin static int SQLITE_TCLAPI reset_prng_state(
622693aed5a1Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
622793aed5a1Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
622893aed5a1Sdrh   int objc,              /* Number of arguments */
622993aed5a1Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
623093aed5a1Sdrh ){
62312fa1868fSdrh   sqlite3_test_control(SQLITE_TESTCTRL_PRNG_RESET);
623293aed5a1Sdrh   return TCL_OK;
623393aed5a1Sdrh }
623493aed5a1Sdrh 
6235062d4cb0Sdanielk1977 /*
623609fe6143Sdrh ** tclcmd:  database_may_be_corrupt
623709fe6143Sdrh **
623809fe6143Sdrh ** Indicate that database files might be corrupt.  In other words, set the normal
623909fe6143Sdrh ** state of operation.
624009fe6143Sdrh */
62417617e4a8Smistachkin static int SQLITE_TCLAPI database_may_be_corrupt(
624209fe6143Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
624309fe6143Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
624409fe6143Sdrh   int objc,              /* Number of arguments */
624509fe6143Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
624609fe6143Sdrh ){
624709fe6143Sdrh   sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, 0);
624809fe6143Sdrh   return TCL_OK;
624909fe6143Sdrh }
625009fe6143Sdrh /*
625109fe6143Sdrh ** tclcmd:  database_never_corrupt
625209fe6143Sdrh **
625309fe6143Sdrh ** Indicate that database files are always well-formed.  This enables extra assert()
625409fe6143Sdrh ** statements that test conditions that are always true for well-formed databases.
625509fe6143Sdrh */
62567617e4a8Smistachkin static int SQLITE_TCLAPI database_never_corrupt(
625709fe6143Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
625809fe6143Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
625909fe6143Sdrh   int objc,              /* Number of arguments */
626009fe6143Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
626109fe6143Sdrh ){
626209fe6143Sdrh   sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, 1);
626309fe6143Sdrh   return TCL_OK;
626409fe6143Sdrh }
626509fe6143Sdrh 
626609fe6143Sdrh /*
6267062d4cb0Sdanielk1977 ** tclcmd:  pcache_stats
6268062d4cb0Sdanielk1977 */
62697617e4a8Smistachkin static int SQLITE_TCLAPI test_pcache_stats(
6270062d4cb0Sdanielk1977   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6271062d4cb0Sdanielk1977   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6272062d4cb0Sdanielk1977   int objc,              /* Number of arguments */
6273062d4cb0Sdanielk1977   Tcl_Obj *CONST objv[]  /* Command arguments */
6274062d4cb0Sdanielk1977 ){
6275062d4cb0Sdanielk1977   int nMin;
6276062d4cb0Sdanielk1977   int nMax;
6277062d4cb0Sdanielk1977   int nCurrent;
6278062d4cb0Sdanielk1977   int nRecyclable;
6279062d4cb0Sdanielk1977   Tcl_Obj *pRet;
6280062d4cb0Sdanielk1977 
6281062d4cb0Sdanielk1977   sqlite3PcacheStats(&nCurrent, &nMax, &nMin, &nRecyclable);
6282062d4cb0Sdanielk1977 
6283062d4cb0Sdanielk1977   pRet = Tcl_NewObj();
6284062d4cb0Sdanielk1977   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("current", -1));
6285062d4cb0Sdanielk1977   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nCurrent));
6286062d4cb0Sdanielk1977   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("max", -1));
6287062d4cb0Sdanielk1977   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nMax));
6288062d4cb0Sdanielk1977   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("min", -1));
6289062d4cb0Sdanielk1977   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nMin));
6290062d4cb0Sdanielk1977   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("recyclable", -1));
6291062d4cb0Sdanielk1977   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nRecyclable));
6292062d4cb0Sdanielk1977 
6293062d4cb0Sdanielk1977   Tcl_SetObjResult(interp, pRet);
6294062d4cb0Sdanielk1977 
6295062d4cb0Sdanielk1977   return TCL_OK;
6296062d4cb0Sdanielk1977 }
6297062d4cb0Sdanielk1977 
629869910da9Sdrh #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
6299404ca075Sdanielk1977 static void test_unlock_notify_cb(void **aArg, int nArg){
6300404ca075Sdanielk1977   int ii;
6301404ca075Sdanielk1977   for(ii=0; ii<nArg; ii++){
6302404ca075Sdanielk1977     Tcl_EvalEx((Tcl_Interp *)aArg[ii], "unlock_notify", -1, TCL_EVAL_GLOBAL);
6303404ca075Sdanielk1977   }
6304404ca075Sdanielk1977 }
630569910da9Sdrh #endif /* SQLITE_ENABLE_UNLOCK_NOTIFY */
6306404ca075Sdanielk1977 
6307404ca075Sdanielk1977 /*
6308404ca075Sdanielk1977 ** tclcmd:  sqlite3_unlock_notify db
6309404ca075Sdanielk1977 */
6310404ca075Sdanielk1977 #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
63117617e4a8Smistachkin static int SQLITE_TCLAPI test_unlock_notify(
6312404ca075Sdanielk1977   ClientData clientData, /* Unused */
6313404ca075Sdanielk1977   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6314404ca075Sdanielk1977   int objc,              /* Number of arguments */
6315404ca075Sdanielk1977   Tcl_Obj *CONST objv[]  /* Command arguments */
6316404ca075Sdanielk1977 ){
6317404ca075Sdanielk1977   sqlite3 *db;
6318404ca075Sdanielk1977   int rc;
6319404ca075Sdanielk1977 
6320404ca075Sdanielk1977   if( objc!=2 ){
6321404ca075Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "DB");
6322404ca075Sdanielk1977     return TCL_ERROR;
6323404ca075Sdanielk1977   }
6324404ca075Sdanielk1977 
6325404ca075Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
6326404ca075Sdanielk1977     return TCL_ERROR;
6327404ca075Sdanielk1977   }
6328404ca075Sdanielk1977   rc = sqlite3_unlock_notify(db, test_unlock_notify_cb, (void *)interp);
6329404ca075Sdanielk1977   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
6330404ca075Sdanielk1977   return TCL_OK;
6331404ca075Sdanielk1977 }
6332404ca075Sdanielk1977 #endif
6333404ca075Sdanielk1977 
633487c1fe1bSdan /*
633587c1fe1bSdan ** tclcmd:  sqlite3_wal_checkpoint db ?NAME?
633687c1fe1bSdan */
63377617e4a8Smistachkin static int SQLITE_TCLAPI test_wal_checkpoint(
633887c1fe1bSdan   ClientData clientData, /* Unused */
633987c1fe1bSdan   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
634087c1fe1bSdan   int objc,              /* Number of arguments */
634187c1fe1bSdan   Tcl_Obj *CONST objv[]  /* Command arguments */
634287c1fe1bSdan ){
634387c1fe1bSdan   char *zDb = 0;
634487c1fe1bSdan   sqlite3 *db;
634587c1fe1bSdan   int rc;
634687c1fe1bSdan 
634787c1fe1bSdan   if( objc!=3 && objc!=2 ){
634887c1fe1bSdan     Tcl_WrongNumArgs(interp, 1, objv, "DB ?NAME?");
634987c1fe1bSdan     return TCL_ERROR;
635087c1fe1bSdan   }
635187c1fe1bSdan 
635287c1fe1bSdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
635387c1fe1bSdan     return TCL_ERROR;
635487c1fe1bSdan   }
635587c1fe1bSdan   if( objc==3 ){
635687c1fe1bSdan     zDb = Tcl_GetString(objv[2]);
635787c1fe1bSdan   }
635887c1fe1bSdan   rc = sqlite3_wal_checkpoint(db, zDb);
635987c1fe1bSdan   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
636087c1fe1bSdan   return TCL_OK;
636187c1fe1bSdan }
636287c1fe1bSdan 
6363eb8763d7Sdan /*
63649c5e3680Sdan ** tclcmd:  sqlite3_wal_checkpoint_v2 db MODE ?NAME?
63659c5e3680Sdan **
63669c5e3680Sdan ** This command calls the wal_checkpoint_v2() function with the specified
63679c5e3680Sdan ** mode argument (passive, full or restart). If present, the database name
63689c5e3680Sdan ** NAME is passed as the second argument to wal_checkpoint_v2(). If it the
63699c5e3680Sdan ** NAME argument is not present, a NULL pointer is passed instead.
63709c5e3680Sdan **
63719c5e3680Sdan ** If wal_checkpoint_v2() returns any value other than SQLITE_BUSY or
63729c5e3680Sdan ** SQLITE_OK, then this command returns TCL_ERROR. The Tcl result is set
63739c5e3680Sdan ** to the error message obtained from sqlite3_errmsg().
63749c5e3680Sdan **
63759c5e3680Sdan ** Otherwise, this command returns a list of three integers. The first integer
63769c5e3680Sdan ** is 1 if SQLITE_BUSY was returned, or 0 otherwise. The following two integers
6377f7b5496eSdrh ** are the values returned via the output parameters by wal_checkpoint_v2() -
63789c5e3680Sdan ** the number of frames in the log and the number of frames in the log
63799c5e3680Sdan ** that have been checkpointed.
63809c5e3680Sdan */
63817617e4a8Smistachkin static int SQLITE_TCLAPI test_wal_checkpoint_v2(
63829c5e3680Sdan   ClientData clientData, /* Unused */
63839c5e3680Sdan   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
63849c5e3680Sdan   int objc,              /* Number of arguments */
63859c5e3680Sdan   Tcl_Obj *CONST objv[]  /* Command arguments */
63869c5e3680Sdan ){
63879c5e3680Sdan   char *zDb = 0;
63889c5e3680Sdan   sqlite3 *db;
63899c5e3680Sdan   int rc;
63909c5e3680Sdan 
63919c5e3680Sdan   int eMode;
63929c5e3680Sdan   int nLog = -555;
63939c5e3680Sdan   int nCkpt = -555;
63949c5e3680Sdan   Tcl_Obj *pRet;
63959c5e3680Sdan 
6396f26a1549Sdan   const char * aMode[] = { "passive", "full", "restart", "truncate", 0 };
63979c5e3680Sdan   assert( SQLITE_CHECKPOINT_PASSIVE==0 );
63989c5e3680Sdan   assert( SQLITE_CHECKPOINT_FULL==1 );
63999c5e3680Sdan   assert( SQLITE_CHECKPOINT_RESTART==2 );
6400f26a1549Sdan   assert( SQLITE_CHECKPOINT_TRUNCATE==3 );
64019c5e3680Sdan 
64029c5e3680Sdan   if( objc!=3 && objc!=4 ){
64039c5e3680Sdan     Tcl_WrongNumArgs(interp, 1, objv, "DB MODE ?NAME?");
64049c5e3680Sdan     return TCL_ERROR;
64059c5e3680Sdan   }
64069c5e3680Sdan 
64079c5e3680Sdan   if( objc==4 ){
64089c5e3680Sdan     zDb = Tcl_GetString(objv[3]);
64099c5e3680Sdan   }
64102928d327Sdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) || (
64112928d327Sdan       TCL_OK!=Tcl_GetIntFromObj(0, objv[2], &eMode)
64122928d327Sdan    && TCL_OK!=Tcl_GetIndexFromObj(interp, objv[2], aMode, "mode", 0, &eMode)
64132928d327Sdan   )){
64149c5e3680Sdan     return TCL_ERROR;
64159c5e3680Sdan   }
64169c5e3680Sdan 
64179c5e3680Sdan   rc = sqlite3_wal_checkpoint_v2(db, zDb, eMode, &nLog, &nCkpt);
64189c5e3680Sdan   if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
64192928d327Sdan     const char *zErrCode = sqlite3ErrName(rc);
64209778bd72Sdan     Tcl_ResetResult(interp);
64212928d327Sdan     Tcl_AppendResult(interp, zErrCode, " - ", (char *)sqlite3_errmsg(db), 0);
64229c5e3680Sdan     return TCL_ERROR;
64239c5e3680Sdan   }
64249c5e3680Sdan 
64259c5e3680Sdan   pRet = Tcl_NewObj();
64269c5e3680Sdan   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(rc==SQLITE_BUSY?1:0));
64279c5e3680Sdan   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nLog));
64289c5e3680Sdan   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nCkpt));
64299c5e3680Sdan   Tcl_SetObjResult(interp, pRet);
64309c5e3680Sdan 
64319c5e3680Sdan   return TCL_OK;
64329c5e3680Sdan }
64339c5e3680Sdan 
64349c5e3680Sdan /*
64359af10620Sdan ** tclcmd:  sqlite3_wal_autocheckpoint db VALUE
64369af10620Sdan */
64377617e4a8Smistachkin static int SQLITE_TCLAPI test_wal_autocheckpoint(
64389af10620Sdan   ClientData clientData, /* Unused */
64399af10620Sdan   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
64409af10620Sdan   int objc,              /* Number of arguments */
64419af10620Sdan   Tcl_Obj *CONST objv[]  /* Command arguments */
64429af10620Sdan ){
64439af10620Sdan   sqlite3 *db;
64449af10620Sdan   int rc;
64459af10620Sdan   int iVal;
64469af10620Sdan 
64479af10620Sdan 
64489af10620Sdan   if( objc!=3 ){
64499af10620Sdan     Tcl_WrongNumArgs(interp, 1, objv, "DB VALUE");
64509af10620Sdan     return TCL_ERROR;
64519af10620Sdan   }
64529af10620Sdan 
64539af10620Sdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db)
64549af10620Sdan    || Tcl_GetIntFromObj(0, objv[2], &iVal)
64559af10620Sdan   ){
64569af10620Sdan     return TCL_ERROR;
64579af10620Sdan   }
64589af10620Sdan 
64599af10620Sdan   rc = sqlite3_wal_autocheckpoint(db, iVal);
64609af10620Sdan   Tcl_ResetResult(interp);
64619af10620Sdan   if( rc!=SQLITE_OK ){
64629af10620Sdan     const char *zErrCode = sqlite3ErrName(rc);
64639af10620Sdan     Tcl_SetObjResult(interp, Tcl_NewStringObj(zErrCode, -1));
64649af10620Sdan     return TCL_ERROR;
64659af10620Sdan   }
64669af10620Sdan 
64679af10620Sdan   return TCL_OK;
64689af10620Sdan }
64699af10620Sdan 
64709af10620Sdan 
64719af10620Sdan /*
6472eb8763d7Sdan ** tclcmd:  test_sqlite3_log ?SCRIPT?
6473eb8763d7Sdan */
6474eb8763d7Sdan static struct LogCallback {
6475eb8763d7Sdan   Tcl_Interp *pInterp;
6476eb8763d7Sdan   Tcl_Obj *pObj;
6477eb8763d7Sdan } logcallback = {0, 0};
6478eb8763d7Sdan static void xLogcallback(void *unused, int err, char *zMsg){
6479eb8763d7Sdan   Tcl_Obj *pNew = Tcl_DuplicateObj(logcallback.pObj);
6480eb8763d7Sdan   Tcl_IncrRefCount(pNew);
6481eb8763d7Sdan   Tcl_ListObjAppendElement(
6482e84d8d32Smistachkin       0, pNew, Tcl_NewStringObj(sqlite3ErrName(err), -1)
6483eb8763d7Sdan   );
6484eb8763d7Sdan   Tcl_ListObjAppendElement(0, pNew, Tcl_NewStringObj(zMsg, -1));
6485eb8763d7Sdan   Tcl_EvalObjEx(logcallback.pInterp, pNew, TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT);
6486eb8763d7Sdan   Tcl_DecrRefCount(pNew);
6487eb8763d7Sdan }
64887617e4a8Smistachkin static int SQLITE_TCLAPI test_sqlite3_log(
6489eb8763d7Sdan   ClientData clientData,
6490eb8763d7Sdan   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6491eb8763d7Sdan   int objc,              /* Number of arguments */
6492eb8763d7Sdan   Tcl_Obj *CONST objv[]  /* Command arguments */
6493eb8763d7Sdan ){
6494eb8763d7Sdan   if( objc>2 ){
6495eb8763d7Sdan     Tcl_WrongNumArgs(interp, 1, objv, "SCRIPT");
6496eb8763d7Sdan     return TCL_ERROR;
6497eb8763d7Sdan   }
6498eb8763d7Sdan   if( logcallback.pObj ){
6499eb8763d7Sdan     Tcl_DecrRefCount(logcallback.pObj);
6500eb8763d7Sdan     logcallback.pObj = 0;
6501eb8763d7Sdan     logcallback.pInterp = 0;
6502d797a9b5Sdrh     sqlite3_config(SQLITE_CONFIG_LOG, (void*)0, (void*)0);
6503eb8763d7Sdan   }
6504eb8763d7Sdan   if( objc>1 ){
6505eb8763d7Sdan     logcallback.pObj = objv[1];
6506eb8763d7Sdan     Tcl_IncrRefCount(logcallback.pObj);
6507eb8763d7Sdan     logcallback.pInterp = interp;
6508d797a9b5Sdrh     sqlite3_config(SQLITE_CONFIG_LOG, xLogcallback, (void*)0);
6509eb8763d7Sdan   }
6510eb8763d7Sdan   return TCL_OK;
6511eb8763d7Sdan }
65129bc5449fSdrh 
65139bc5449fSdrh /*
6514a2c8a95bSdrh **     tcl_objproc COMMANDNAME ARGS...
6515a2c8a95bSdrh **
6516a2c8a95bSdrh ** Run a TCL command using its objProc interface.  Throw an error if
6517a2c8a95bSdrh ** the command has no objProc interface.
6518a2c8a95bSdrh */
65197617e4a8Smistachkin static int SQLITE_TCLAPI runAsObjProc(
6520a2c8a95bSdrh   void * clientData,
6521a2c8a95bSdrh   Tcl_Interp *interp,
6522a2c8a95bSdrh   int objc,
6523a2c8a95bSdrh   Tcl_Obj *CONST objv[]
6524a2c8a95bSdrh ){
6525a2c8a95bSdrh   Tcl_CmdInfo cmdInfo;
6526a2c8a95bSdrh   if( objc<2 ){
6527a2c8a95bSdrh     Tcl_WrongNumArgs(interp, 1, objv, "COMMAND ...");
6528a2c8a95bSdrh     return TCL_ERROR;
6529a2c8a95bSdrh   }
6530a2c8a95bSdrh   if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){
6531a2c8a95bSdrh     Tcl_AppendResult(interp, "command not found: ",
6532a2c8a95bSdrh            Tcl_GetString(objv[1]), (char*)0);
6533a2c8a95bSdrh     return TCL_ERROR;
6534a2c8a95bSdrh   }
6535a2c8a95bSdrh   if( cmdInfo.objProc==0 ){
6536a2c8a95bSdrh     Tcl_AppendResult(interp, "command has no objProc: ",
6537a2c8a95bSdrh            Tcl_GetString(objv[1]), (char*)0);
6538a2c8a95bSdrh     return TCL_ERROR;
6539a2c8a95bSdrh   }
6540a2c8a95bSdrh   return cmdInfo.objProc(cmdInfo.objClientData, interp, objc-1, objv+1);
6541a2c8a95bSdrh }
6542a2c8a95bSdrh 
654391da6b83Sdan #ifndef SQLITE_OMIT_EXPLAIN
654491da6b83Sdan /*
654591da6b83Sdan ** WARNING: The following function, printExplainQueryPlan() is an exact
654691da6b83Sdan ** copy of example code from eqp.in (eqp.html). If this code is modified,
654791da6b83Sdan ** then the documentation copy needs to be modified as well.
654891da6b83Sdan */
654991da6b83Sdan /*
655091da6b83Sdan ** Argument pStmt is a prepared SQL statement. This function compiles
655191da6b83Sdan ** an EXPLAIN QUERY PLAN command to report on the prepared statement,
655291da6b83Sdan ** and prints the report to stdout using printf().
655391da6b83Sdan */
655491da6b83Sdan int printExplainQueryPlan(sqlite3_stmt *pStmt){
655591da6b83Sdan   const char *zSql;               /* Input SQL */
655691da6b83Sdan   char *zExplain;                 /* SQL with EXPLAIN QUERY PLAN prepended */
655791da6b83Sdan   sqlite3_stmt *pExplain;         /* Compiled EXPLAIN QUERY PLAN command */
655891da6b83Sdan   int rc;                         /* Return code from sqlite3_prepare_v2() */
655991da6b83Sdan 
656091da6b83Sdan   zSql = sqlite3_sql(pStmt);
656191da6b83Sdan   if( zSql==0 ) return SQLITE_ERROR;
656291da6b83Sdan 
656391da6b83Sdan   zExplain = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zSql);
656491da6b83Sdan   if( zExplain==0 ) return SQLITE_NOMEM;
656591da6b83Sdan 
656691da6b83Sdan   rc = sqlite3_prepare_v2(sqlite3_db_handle(pStmt), zExplain, -1, &pExplain, 0);
656791da6b83Sdan   sqlite3_free(zExplain);
656891da6b83Sdan   if( rc!=SQLITE_OK ) return rc;
656991da6b83Sdan 
657091da6b83Sdan   while( SQLITE_ROW==sqlite3_step(pExplain) ){
657191da6b83Sdan     int iSelectid = sqlite3_column_int(pExplain, 0);
657291da6b83Sdan     int iOrder = sqlite3_column_int(pExplain, 1);
657391da6b83Sdan     int iFrom = sqlite3_column_int(pExplain, 2);
657491da6b83Sdan     const char *zDetail = (const char *)sqlite3_column_text(pExplain, 3);
657591da6b83Sdan 
657691da6b83Sdan     printf("%d %d %d %s\n", iSelectid, iOrder, iFrom, zDetail);
657791da6b83Sdan   }
657891da6b83Sdan 
657991da6b83Sdan   return sqlite3_finalize(pExplain);
658091da6b83Sdan }
658191da6b83Sdan 
65827617e4a8Smistachkin static int SQLITE_TCLAPI test_print_eqp(
658391da6b83Sdan   void * clientData,
658491da6b83Sdan   Tcl_Interp *interp,
658591da6b83Sdan   int objc,
658691da6b83Sdan   Tcl_Obj *CONST objv[]
658791da6b83Sdan ){
658891da6b83Sdan   int rc;
658991da6b83Sdan   sqlite3_stmt *pStmt;
659091da6b83Sdan 
659191da6b83Sdan   if( objc!=2 ){
659291da6b83Sdan     Tcl_WrongNumArgs(interp, 1, objv, "STMT");
659391da6b83Sdan     return TCL_ERROR;
659491da6b83Sdan   }
659591da6b83Sdan   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
659691da6b83Sdan   rc = printExplainQueryPlan(pStmt);
65977c5d8fb7Sshaneh   /* This is needed on Windows so that a test case using this
65987c5d8fb7Sshaneh   ** function can open a read pipe and get the output of
65997c5d8fb7Sshaneh   ** printExplainQueryPlan() immediately.
66007c5d8fb7Sshaneh   */
66017c5d8fb7Sshaneh   fflush(stdout);
660291da6b83Sdan   Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
660391da6b83Sdan   return TCL_OK;
660491da6b83Sdan }
660591da6b83Sdan #endif /* SQLITE_OMIT_EXPLAIN */
6606a2c8a95bSdrh 
6607a2c8a95bSdrh /*
6608c17d696cSdan ** sqlite3_test_control VERB ARGS...
6609c17d696cSdan */
66107617e4a8Smistachkin static int SQLITE_TCLAPI test_test_control(
6611c17d696cSdan   void * clientData,
6612c17d696cSdan   Tcl_Interp *interp,
6613c17d696cSdan   int objc,
6614c17d696cSdan   Tcl_Obj *CONST objv[]
6615c17d696cSdan ){
6616c17d696cSdan   struct Verb {
6617c17d696cSdan     const char *zName;
6618c17d696cSdan     int i;
6619c17d696cSdan   } aVerb[] = {
6620c17d696cSdan     { "SQLITE_TESTCTRL_LOCALTIME_FAULT", SQLITE_TESTCTRL_LOCALTIME_FAULT },
66218930c2abSdan     { "SQLITE_TESTCTRL_SORTER_MMAP",     SQLITE_TESTCTRL_SORTER_MMAP     },
66221ffede8cSdrh     { "SQLITE_TESTCTRL_IMPOSTER",        SQLITE_TESTCTRL_IMPOSTER        },
6623c17d696cSdan   };
6624c17d696cSdan   int iVerb;
6625c17d696cSdan   int iFlag;
6626c17d696cSdan   int rc;
6627c17d696cSdan 
6628c17d696cSdan   if( objc<2 ){
6629c17d696cSdan     Tcl_WrongNumArgs(interp, 1, objv, "VERB ARGS...");
6630c17d696cSdan     return TCL_ERROR;
6631c17d696cSdan   }
6632c17d696cSdan 
6633c17d696cSdan   rc = Tcl_GetIndexFromObjStruct(
6634c17d696cSdan       interp, objv[1], aVerb, sizeof(aVerb[0]), "VERB", 0, &iVerb
6635c17d696cSdan   );
6636c17d696cSdan   if( rc!=TCL_OK ) return rc;
6637c17d696cSdan 
6638c17d696cSdan   iFlag = aVerb[iVerb].i;
6639c17d696cSdan   switch( iFlag ){
6640c17d696cSdan     case SQLITE_TESTCTRL_LOCALTIME_FAULT: {
6641c17d696cSdan       int val;
6642c17d696cSdan       if( objc!=3 ){
6643c17d696cSdan         Tcl_WrongNumArgs(interp, 2, objv, "ONOFF");
6644c17d696cSdan         return TCL_ERROR;
6645c17d696cSdan       }
6646c17d696cSdan       if( Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR;
6647c17d696cSdan       sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, val);
6648c17d696cSdan       break;
6649c17d696cSdan     }
66508930c2abSdan 
66518930c2abSdan     case SQLITE_TESTCTRL_SORTER_MMAP: {
66528930c2abSdan       int val;
66538930c2abSdan       sqlite3 *db;
66548930c2abSdan       if( objc!=4 ){
66558930c2abSdan         Tcl_WrongNumArgs(interp, 2, objv, "DB LIMIT");
66568930c2abSdan         return TCL_ERROR;
66578930c2abSdan       }
66588930c2abSdan       if( getDbPointer(interp, Tcl_GetString(objv[2]), &db) ) return TCL_ERROR;
66598930c2abSdan       if( Tcl_GetIntFromObj(interp, objv[3], &val) ) return TCL_ERROR;
66608930c2abSdan       sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, val);
66618930c2abSdan       break;
66628930c2abSdan     }
6663917682a4Sdrh 
66641ffede8cSdrh     case SQLITE_TESTCTRL_IMPOSTER: {
66651ffede8cSdrh       int onOff, tnum;
66661ffede8cSdrh       const char *zDbName;
6667917682a4Sdrh       sqlite3 *db;
6668917682a4Sdrh       if( objc!=6 ){
66691ffede8cSdrh         Tcl_WrongNumArgs(interp, 2, objv, "DB dbName onOff tnum");
6670917682a4Sdrh         return TCL_ERROR;
6671917682a4Sdrh       }
6672917682a4Sdrh       if( getDbPointer(interp, Tcl_GetString(objv[2]), &db) ) return TCL_ERROR;
66731ffede8cSdrh       zDbName = Tcl_GetString(objv[3]);
66741ffede8cSdrh       if( Tcl_GetIntFromObj(interp, objv[4], &onOff) ) return TCL_ERROR;
66751ffede8cSdrh       if( Tcl_GetIntFromObj(interp, objv[5], &tnum) ) return TCL_ERROR;
66761ffede8cSdrh       sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, zDbName, onOff, tnum);
6677917682a4Sdrh       break;
6678917682a4Sdrh     }
6679c17d696cSdan   }
6680c17d696cSdan 
6681c17d696cSdan   Tcl_ResetResult(interp);
6682c17d696cSdan   return TCL_OK;
6683c17d696cSdan }
6684c17d696cSdan 
6685daf9a5a4Smistachkin #if SQLITE_OS_UNIX
6686a72014faSdan #include <sys/time.h>
6687a72014faSdan #include <sys/resource.h>
6688a72014faSdan 
66897617e4a8Smistachkin static int SQLITE_TCLAPI test_getrusage(
6690a72014faSdan   void * clientData,
6691a72014faSdan   Tcl_Interp *interp,
6692a72014faSdan   int objc,
6693a72014faSdan   Tcl_Obj *CONST objv[]
6694a72014faSdan ){
6695a72014faSdan   char buf[1024];
6696a72014faSdan   struct rusage r;
6697a72014faSdan   memset(&r, 0, sizeof(r));
6698a72014faSdan   getrusage(RUSAGE_SELF, &r);
6699a72014faSdan 
670065545b59Sdrh   sqlite3_snprintf(sizeof(buf), buf,
670165545b59Sdrh     "ru_utime=%d.%06d ru_stime=%d.%06d ru_minflt=%d ru_majflt=%d",
67025d8a1372Sdan     (int)r.ru_utime.tv_sec, (int)r.ru_utime.tv_usec,
67035d8a1372Sdan     (int)r.ru_stime.tv_sec, (int)r.ru_stime.tv_usec,
67045d8a1372Sdan     (int)r.ru_minflt, (int)r.ru_majflt
6705a72014faSdan   );
6706a72014faSdan   Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, -1));
6707a72014faSdan   return TCL_OK;
6708a72014faSdan }
6709daf9a5a4Smistachkin #endif
6710a72014faSdan 
671180084ca8Sdrh #if SQLITE_OS_WIN
671280084ca8Sdrh /*
671380084ca8Sdrh ** Information passed from the main thread into the windows file locker
671480084ca8Sdrh ** background thread.
671580084ca8Sdrh */
671680084ca8Sdrh struct win32FileLocker {
6717176f1b47Smistachkin   char *evName;       /* Name of event to signal thread startup */
671880084ca8Sdrh   HANDLE h;           /* Handle of the file to be locked */
671980084ca8Sdrh   int delay1;         /* Delay before locking */
672080084ca8Sdrh   int delay2;         /* Delay before unlocking */
672180084ca8Sdrh   int ok;             /* Finished ok */
672280084ca8Sdrh   int err;            /* True if an error occurs */
672380084ca8Sdrh };
672480084ca8Sdrh #endif
672580084ca8Sdrh 
672680084ca8Sdrh 
672780084ca8Sdrh #if SQLITE_OS_WIN
67287da5fcb0Sdrh #include <process.h>
672980084ca8Sdrh /*
673080084ca8Sdrh ** The background thread that does file locking.
673180084ca8Sdrh */
673269def7ffSmistachkin static void SQLITE_CDECL win32_file_locker(void *pAppData){
673380084ca8Sdrh   struct win32FileLocker *p = (struct win32FileLocker*)pAppData;
6734176f1b47Smistachkin   if( p->evName ){
6735176f1b47Smistachkin     HANDLE ev = OpenEvent(EVENT_MODIFY_STATE, FALSE, p->evName);
6736176f1b47Smistachkin     if ( ev ){
6737176f1b47Smistachkin       SetEvent(ev);
6738176f1b47Smistachkin       CloseHandle(ev);
6739176f1b47Smistachkin     }
6740176f1b47Smistachkin   }
674180084ca8Sdrh   if( p->delay1 ) Sleep(p->delay1);
674280084ca8Sdrh   if( LockFile(p->h, 0, 0, 100000000, 0) ){
674380084ca8Sdrh     Sleep(p->delay2);
674480084ca8Sdrh     UnlockFile(p->h, 0, 0, 100000000, 0);
674580084ca8Sdrh     p->ok = 1;
674680084ca8Sdrh   }else{
674780084ca8Sdrh     p->err = 1;
674880084ca8Sdrh   }
674980084ca8Sdrh   CloseHandle(p->h);
675080084ca8Sdrh   p->h = 0;
675180084ca8Sdrh   p->delay1 = 0;
675280084ca8Sdrh   p->delay2 = 0;
675380084ca8Sdrh }
675480084ca8Sdrh #endif
675580084ca8Sdrh 
675680084ca8Sdrh #if SQLITE_OS_WIN
675780084ca8Sdrh /*
675880084ca8Sdrh **      lock_win32_file FILENAME DELAY1 DELAY2
675980084ca8Sdrh **
676080084ca8Sdrh ** Get an exclusive manditory lock on file for DELAY2 milliseconds.
676180084ca8Sdrh ** Wait DELAY1 milliseconds before acquiring the lock.
676280084ca8Sdrh */
67637617e4a8Smistachkin static int SQLITE_TCLAPI win32_file_lock(
676480084ca8Sdrh   void * clientData,
676580084ca8Sdrh   Tcl_Interp *interp,
676680084ca8Sdrh   int objc,
676780084ca8Sdrh   Tcl_Obj *CONST objv[]
676880084ca8Sdrh ){
6769176f1b47Smistachkin   static struct win32FileLocker x = { "win32_file_lock", 0, 0, 0, 0, 0 };
677080084ca8Sdrh   const char *zFilename;
6771176f1b47Smistachkin   char zBuf[200];
677280084ca8Sdrh   int retry = 0;
6773176f1b47Smistachkin   HANDLE ev;
6774176f1b47Smistachkin   DWORD wResult;
677580084ca8Sdrh 
677680084ca8Sdrh   if( objc!=4 && objc!=1 ){
677780084ca8Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME DELAY1 DELAY2");
677880084ca8Sdrh     return TCL_ERROR;
677980084ca8Sdrh   }
678080084ca8Sdrh   if( objc==1 ){
678180084ca8Sdrh     sqlite3_snprintf(sizeof(zBuf), zBuf, "%d %d %d %d %d",
678280084ca8Sdrh                      x.ok, x.err, x.delay1, x.delay2, x.h);
678380084ca8Sdrh     Tcl_AppendResult(interp, zBuf, (char*)0);
678480084ca8Sdrh     return TCL_OK;
678580084ca8Sdrh   }
6786d0cdf012Sdrh   while( x.h && retry<30 ){
678780084ca8Sdrh     retry++;
678880084ca8Sdrh     Sleep(100);
678980084ca8Sdrh   }
679080084ca8Sdrh   if( x.h ){
679180084ca8Sdrh     Tcl_AppendResult(interp, "busy", (char*)0);
679280084ca8Sdrh     return TCL_ERROR;
679380084ca8Sdrh   }
679480084ca8Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &x.delay1) ) return TCL_ERROR;
679580084ca8Sdrh   if( Tcl_GetIntFromObj(interp, objv[3], &x.delay2) ) return TCL_ERROR;
679680084ca8Sdrh   zFilename = Tcl_GetString(objv[1]);
679780084ca8Sdrh   x.h = CreateFile(zFilename, GENERIC_READ|GENERIC_WRITE,
679880084ca8Sdrh               FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_ALWAYS,
679980084ca8Sdrh               FILE_ATTRIBUTE_NORMAL, 0);
680080084ca8Sdrh   if( !x.h ){
680180084ca8Sdrh     Tcl_AppendResult(interp, "cannot open file: ", zFilename, (char*)0);
680280084ca8Sdrh     return TCL_ERROR;
680380084ca8Sdrh   }
6804176f1b47Smistachkin   ev = CreateEvent(NULL, TRUE, FALSE, x.evName);
6805176f1b47Smistachkin   if ( !ev ){
6806176f1b47Smistachkin     Tcl_AppendResult(interp, "cannot create event: ", x.evName, (char*)0);
6807176f1b47Smistachkin     return TCL_ERROR;
6808176f1b47Smistachkin   }
680980084ca8Sdrh   _beginthread(win32_file_locker, 0, (void*)&x);
681080084ca8Sdrh   Sleep(0);
6811176f1b47Smistachkin   if ( (wResult = WaitForSingleObject(ev, 10000))!=WAIT_OBJECT_0 ){
6812176f1b47Smistachkin     sqlite3_snprintf(sizeof(zBuf), zBuf, "0x%x", wResult);
6813176f1b47Smistachkin     Tcl_AppendResult(interp, "wait failed: ", zBuf, (char*)0);
6814176f1b47Smistachkin     CloseHandle(ev);
6815176f1b47Smistachkin     return TCL_ERROR;
6816176f1b47Smistachkin   }
6817176f1b47Smistachkin   CloseHandle(ev);
681880084ca8Sdrh   return TCL_OK;
681980084ca8Sdrh }
68203741827eSmistachkin 
68213741827eSmistachkin /*
68223741827eSmistachkin **      exists_win32_path PATH
68233741827eSmistachkin **
68243741827eSmistachkin ** Returns non-zero if the specified path exists, whose fully qualified name
68253259fe79Smistachkin ** may exceed 260 characters if it is prefixed with "\\?\".
68263741827eSmistachkin */
68277617e4a8Smistachkin static int SQLITE_TCLAPI win32_exists_path(
68283741827eSmistachkin   void *clientData,
68293741827eSmistachkin   Tcl_Interp *interp,
68303741827eSmistachkin   int objc,
68313741827eSmistachkin   Tcl_Obj *CONST objv[]
68323741827eSmistachkin ){
68333741827eSmistachkin   if( objc!=2 ){
68343741827eSmistachkin     Tcl_WrongNumArgs(interp, 1, objv, "PATH");
68353741827eSmistachkin     return TCL_ERROR;
68363741827eSmistachkin   }
68373741827eSmistachkin   Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
68383741827eSmistachkin       GetFileAttributesW( Tcl_GetUnicode(objv[1]))!=INVALID_FILE_ATTRIBUTES ));
68393741827eSmistachkin   return TCL_OK;
68403741827eSmistachkin }
68413741827eSmistachkin 
68423741827eSmistachkin /*
68433741827eSmistachkin **      find_win32_file PATTERN
68443741827eSmistachkin **
68453741827eSmistachkin ** Returns a list of entries in a directory that match the specified pattern,
68463741827eSmistachkin ** whose fully qualified name may exceed 248 characters if it is prefixed with
68473741827eSmistachkin ** "\\?\".
68483741827eSmistachkin */
68497617e4a8Smistachkin static int SQLITE_TCLAPI win32_find_file(
68503741827eSmistachkin   void *clientData,
68513741827eSmistachkin   Tcl_Interp *interp,
68523741827eSmistachkin   int objc,
68533741827eSmistachkin   Tcl_Obj *CONST objv[]
68543741827eSmistachkin ){
68553741827eSmistachkin   HANDLE hFindFile = INVALID_HANDLE_VALUE;
68563741827eSmistachkin   WIN32_FIND_DATAW findData;
68573741827eSmistachkin   Tcl_Obj *listObj;
68583741827eSmistachkin   DWORD lastErrno;
68593741827eSmistachkin   if( objc!=2 ){
68603741827eSmistachkin     Tcl_WrongNumArgs(interp, 1, objv, "PATTERN");
68613741827eSmistachkin     return TCL_ERROR;
68623741827eSmistachkin   }
68633741827eSmistachkin   hFindFile = FindFirstFileW(Tcl_GetUnicode(objv[1]), &findData);
68643741827eSmistachkin   if( hFindFile==INVALID_HANDLE_VALUE ){
68653741827eSmistachkin     Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
68663741827eSmistachkin     return TCL_ERROR;
68673741827eSmistachkin   }
68683741827eSmistachkin   listObj = Tcl_NewObj();
68693741827eSmistachkin   Tcl_IncrRefCount(listObj);
68703741827eSmistachkin   do {
68713741827eSmistachkin     Tcl_ListObjAppendElement(interp, listObj, Tcl_NewUnicodeObj(
68723741827eSmistachkin         findData.cFileName, -1));
68733741827eSmistachkin     Tcl_ListObjAppendElement(interp, listObj, Tcl_NewWideIntObj(
68743741827eSmistachkin         findData.dwFileAttributes));
68753741827eSmistachkin   } while( FindNextFileW(hFindFile, &findData) );
68763741827eSmistachkin   lastErrno = GetLastError();
68773741827eSmistachkin   if( lastErrno!=NO_ERROR && lastErrno!=ERROR_NO_MORE_FILES ){
68783741827eSmistachkin     FindClose(hFindFile);
68793741827eSmistachkin     Tcl_DecrRefCount(listObj);
68803741827eSmistachkin     Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
68813741827eSmistachkin     return TCL_ERROR;
68823741827eSmistachkin   }
68833741827eSmistachkin   FindClose(hFindFile);
68843741827eSmistachkin   Tcl_SetObjResult(interp, listObj);
68853741827eSmistachkin   return TCL_OK;
68863741827eSmistachkin }
68873741827eSmistachkin 
68883741827eSmistachkin /*
68893741827eSmistachkin **      delete_win32_file FILENAME
68903741827eSmistachkin **
68913259fe79Smistachkin ** Deletes the specified file, whose fully qualified name may exceed 260
68923741827eSmistachkin ** characters if it is prefixed with "\\?\".
68933741827eSmistachkin */
68947617e4a8Smistachkin static int SQLITE_TCLAPI win32_delete_file(
68953741827eSmistachkin   void *clientData,
68963741827eSmistachkin   Tcl_Interp *interp,
68973741827eSmistachkin   int objc,
68983741827eSmistachkin   Tcl_Obj *CONST objv[]
68993741827eSmistachkin ){
69003741827eSmistachkin   if( objc!=2 ){
69013741827eSmistachkin     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
69023741827eSmistachkin     return TCL_ERROR;
69033741827eSmistachkin   }
69043741827eSmistachkin   if( !DeleteFileW(Tcl_GetUnicode(objv[1])) ){
69053741827eSmistachkin     Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
69063741827eSmistachkin     return TCL_ERROR;
69073741827eSmistachkin   }
69083741827eSmistachkin   Tcl_ResetResult(interp);
69093741827eSmistachkin   return TCL_OK;
69103741827eSmistachkin }
69113741827eSmistachkin 
69123741827eSmistachkin /*
69133741827eSmistachkin **      make_win32_dir DIRECTORY
69143741827eSmistachkin **
69153741827eSmistachkin ** Creates the specified directory, whose fully qualified name may exceed 248
69163741827eSmistachkin ** characters if it is prefixed with "\\?\".
69173741827eSmistachkin */
69187617e4a8Smistachkin static int SQLITE_TCLAPI win32_mkdir(
69193741827eSmistachkin   void *clientData,
69203741827eSmistachkin   Tcl_Interp *interp,
69213741827eSmistachkin   int objc,
69223741827eSmistachkin   Tcl_Obj *CONST objv[]
69233741827eSmistachkin ){
69243741827eSmistachkin   if( objc!=2 ){
69253741827eSmistachkin     Tcl_WrongNumArgs(interp, 1, objv, "DIRECTORY");
69263741827eSmistachkin     return TCL_ERROR;
69273741827eSmistachkin   }
69283741827eSmistachkin   if( !CreateDirectoryW(Tcl_GetUnicode(objv[1]), NULL) ){
69293741827eSmistachkin     Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
69303741827eSmistachkin     return TCL_ERROR;
69313741827eSmistachkin   }
69323741827eSmistachkin   Tcl_ResetResult(interp);
69333741827eSmistachkin   return TCL_OK;
69343741827eSmistachkin }
69353741827eSmistachkin 
69363741827eSmistachkin /*
69373741827eSmistachkin **      remove_win32_dir DIRECTORY
69383741827eSmistachkin **
69393741827eSmistachkin ** Removes the specified directory, whose fully qualified name may exceed 248
69403741827eSmistachkin ** characters if it is prefixed with "\\?\".
69413741827eSmistachkin */
69427617e4a8Smistachkin static int SQLITE_TCLAPI win32_rmdir(
69433741827eSmistachkin   void *clientData,
69443741827eSmistachkin   Tcl_Interp *interp,
69453741827eSmistachkin   int objc,
69463741827eSmistachkin   Tcl_Obj *CONST objv[]
69473741827eSmistachkin ){
69483741827eSmistachkin   if( objc!=2 ){
69493741827eSmistachkin     Tcl_WrongNumArgs(interp, 1, objv, "DIRECTORY");
69503741827eSmistachkin     return TCL_ERROR;
69513741827eSmistachkin   }
69523741827eSmistachkin   if( !RemoveDirectoryW(Tcl_GetUnicode(objv[1])) ){
69533741827eSmistachkin     Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
69543741827eSmistachkin     return TCL_ERROR;
69553741827eSmistachkin   }
69563741827eSmistachkin   Tcl_ResetResult(interp);
69573741827eSmistachkin   return TCL_OK;
69583741827eSmistachkin }
695980084ca8Sdrh #endif
6960c17d696cSdan 
6961d0cdf012Sdrh 
6962c17d696cSdan /*
6963f58ee7f1Sdrh **      optimization_control DB OPT BOOLEAN
6964f58ee7f1Sdrh **
6965f58ee7f1Sdrh ** Enable or disable query optimizations using the sqlite3_test_control()
6966f58ee7f1Sdrh ** interface.  Disable if BOOLEAN is false and enable if BOOLEAN is true.
6967f58ee7f1Sdrh ** OPT is the name of the optimization to be disabled.
6968f58ee7f1Sdrh */
69697617e4a8Smistachkin static int SQLITE_TCLAPI optimization_control(
6970f58ee7f1Sdrh   void * clientData,
6971f58ee7f1Sdrh   Tcl_Interp *interp,
6972f58ee7f1Sdrh   int objc,
6973f58ee7f1Sdrh   Tcl_Obj *CONST objv[]
6974f58ee7f1Sdrh ){
6975f58ee7f1Sdrh   int i;
6976f58ee7f1Sdrh   sqlite3 *db;
6977f58ee7f1Sdrh   const char *zOpt;
6978f58ee7f1Sdrh   int onoff;
6979fc30b042Sdrh   int mask = 0;
6980f58ee7f1Sdrh   static const struct {
6981f58ee7f1Sdrh     const char *zOptName;
6982f58ee7f1Sdrh     int mask;
6983f58ee7f1Sdrh   } aOpt[] = {
69847e5418e4Sdrh     { "all",                 SQLITE_AllOpts        },
69859d5a579cSdrh     { "none",                0                     },
6986f58ee7f1Sdrh     { "query-flattener",     SQLITE_QueryFlattener },
6987f58ee7f1Sdrh     { "groupby-order",       SQLITE_GroupByOrder   },
6988f58ee7f1Sdrh     { "factor-constants",    SQLITE_FactorOutConst },
6989f4af1089Sdrh     { "distinct-opt",        SQLITE_DistinctOpt    },
6990de9a7b8aSdrh     { "cover-idx-scan",      SQLITE_CoverIdxScan   },
69917e5418e4Sdrh     { "order-by-idx-join",   SQLITE_OrderByIdxJoin },
69929d5a579cSdrh     { "transitive",          SQLITE_Transitive     },
69939d5a579cSdrh     { "omit-noop-join",      SQLITE_OmitNoopJoin   },
6994d7d71470Sdrh     { "stat3",               SQLITE_Stat34         },
6995d7d71470Sdrh     { "stat4",               SQLITE_Stat34         },
6996e8825519Sdan     { "skip-scan",           SQLITE_SkipScan       },
6997f58ee7f1Sdrh   };
6998f58ee7f1Sdrh 
6999f58ee7f1Sdrh   if( objc!=4 ){
7000f58ee7f1Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB OPT BOOLEAN");
7001f58ee7f1Sdrh     return TCL_ERROR;
7002f58ee7f1Sdrh   }
7003f58ee7f1Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
7004f58ee7f1Sdrh   if( Tcl_GetBooleanFromObj(interp, objv[3], &onoff) ) return TCL_ERROR;
7005f58ee7f1Sdrh   zOpt = Tcl_GetString(objv[2]);
7006f58ee7f1Sdrh   for(i=0; i<sizeof(aOpt)/sizeof(aOpt[0]); i++){
7007f58ee7f1Sdrh     if( strcmp(zOpt, aOpt[i].zOptName)==0 ){
7008f58ee7f1Sdrh       mask = aOpt[i].mask;
7009f58ee7f1Sdrh       break;
7010f58ee7f1Sdrh     }
7011f58ee7f1Sdrh   }
7012f58ee7f1Sdrh   if( onoff ) mask = ~mask;
7013f58ee7f1Sdrh   if( i>=sizeof(aOpt)/sizeof(aOpt[0]) ){
7014f58ee7f1Sdrh     Tcl_AppendResult(interp, "unknown optimization - should be one of:",
7015f58ee7f1Sdrh                      (char*)0);
7016f58ee7f1Sdrh     for(i=0; i<sizeof(aOpt)/sizeof(aOpt[0]); i++){
70179d5a579cSdrh       Tcl_AppendResult(interp, " ", aOpt[i].zOptName, (char*)0);
7018f58ee7f1Sdrh     }
7019f58ee7f1Sdrh     return TCL_ERROR;
7020f58ee7f1Sdrh   }
7021f58ee7f1Sdrh   sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, db, mask);
7022f58ee7f1Sdrh   return TCL_OK;
7023f58ee7f1Sdrh }
7024f58ee7f1Sdrh 
7025248f2be9Sdrh /*
7026ea41dc44Sdrh **     load_static_extension DB NAME ...
7027248f2be9Sdrh **
7028ea41dc44Sdrh ** Load one or more statically linked extensions.
7029248f2be9Sdrh */
70307617e4a8Smistachkin static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
7031248f2be9Sdrh   void * clientData,
7032248f2be9Sdrh   Tcl_Interp *interp,
7033248f2be9Sdrh   int objc,
7034248f2be9Sdrh   Tcl_Obj *CONST objv[]
7035248f2be9Sdrh ){
70368416fc7fSdrh   extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*);
70372e3f87aeSdrh   extern int sqlite3_carray_init(sqlite3*,char**,const sqlite3_api_routines*);
70388416fc7fSdrh   extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*);
703935db31b2Sdrh   extern int sqlite3_csv_init(sqlite3*,char**,const sqlite3_api_routines*);
70401728bcb0Sdrh   extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*);
704151ed2983Sdrh   extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*);
7042e50db1c5Sdrh   extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*);
70438416fc7fSdrh   extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*);
7044ea41dc44Sdrh   extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*);
7045def3367eSdrh   extern int sqlite3_percentile_init(sqlite3*,char**,const sqlite3_api_routines*);
7046248f2be9Sdrh   extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*);
70476bada272Sdrh   extern int sqlite3_remember_init(sqlite3*,char**,const sqlite3_api_routines*);
7048398f872dSdrh   extern int sqlite3_series_init(sqlite3*,char**,const sqlite3_api_routines*);
7049b7045ab2Sdrh   extern int sqlite3_spellfix_init(sqlite3*,char**,const sqlite3_api_routines*);
70505f8cdac6Sdrh   extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*);
705124b6422dSdrh   extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*);
7052d8ecefa5Sdan   extern int sqlite3_unionvtab_init(sqlite3*,char**,const sqlite3_api_routines*);
705391f7211cSmistachkin #ifdef SQLITE_HAVE_ZLIB
7054373dc3bbSdan   extern int sqlite3_zipfile_init(sqlite3*,char**,const sqlite3_api_routines*);
705591f7211cSmistachkin #endif
7056248f2be9Sdrh   static const struct {
7057248f2be9Sdrh     const char *zExtName;
7058248f2be9Sdrh     int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*);
7059248f2be9Sdrh   } aExtension[] = {
70608416fc7fSdrh     { "amatch",                sqlite3_amatch_init               },
70612e3f87aeSdrh     { "carray",                sqlite3_carray_init               },
70628416fc7fSdrh     { "closure",               sqlite3_closure_init              },
706335db31b2Sdrh     { "csv",                   sqlite3_csv_init                  },
70641728bcb0Sdrh     { "eval",                  sqlite3_eval_init                 },
706551ed2983Sdrh     { "fileio",                sqlite3_fileio_init               },
7066e50db1c5Sdrh     { "fuzzer",                sqlite3_fuzzer_init               },
70678416fc7fSdrh     { "ieee754",               sqlite3_ieee_init                 },
7068ea41dc44Sdrh     { "nextchar",              sqlite3_nextchar_init             },
7069def3367eSdrh     { "percentile",            sqlite3_percentile_init           },
7070248f2be9Sdrh     { "regexp",                sqlite3_regexp_init               },
70716bada272Sdrh     { "remember",              sqlite3_remember_init             },
7072398f872dSdrh     { "series",                sqlite3_series_init               },
7073b7045ab2Sdrh     { "spellfix",              sqlite3_spellfix_init             },
70745f8cdac6Sdrh     { "totype",                sqlite3_totype_init               },
7075d8ecefa5Sdan     { "unionvtab",             sqlite3_unionvtab_init            },
707624b6422dSdrh     { "wholenumber",           sqlite3_wholenumber_init          },
707791f7211cSmistachkin #ifdef SQLITE_HAVE_ZLIB
7078373dc3bbSdan     { "zipfile",               sqlite3_zipfile_init              },
707991f7211cSmistachkin #endif
7080248f2be9Sdrh   };
7081248f2be9Sdrh   sqlite3 *db;
7082248f2be9Sdrh   const char *zName;
7083ea41dc44Sdrh   int i, j, rc;
7084248f2be9Sdrh   char *zErrMsg = 0;
7085ea41dc44Sdrh   if( objc<3 ){
7086ea41dc44Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB NAME ...");
7087248f2be9Sdrh     return TCL_ERROR;
7088248f2be9Sdrh   }
7089248f2be9Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
7090ea41dc44Sdrh   for(j=2; j<objc; j++){
7091ea41dc44Sdrh     zName = Tcl_GetString(objv[j]);
7092248f2be9Sdrh     for(i=0; i<ArraySize(aExtension); i++){
7093248f2be9Sdrh       if( strcmp(zName, aExtension[i].zExtName)==0 ) break;
7094248f2be9Sdrh     }
7095248f2be9Sdrh     if( i>=ArraySize(aExtension) ){
7096248f2be9Sdrh       Tcl_AppendResult(interp, "no such extension: ", zName, (char*)0);
7097248f2be9Sdrh       return TCL_ERROR;
7098248f2be9Sdrh     }
7099c306e08aSdrh     if( aExtension[i].pInit ){
7100248f2be9Sdrh       rc = aExtension[i].pInit(db, &zErrMsg, 0);
7101c306e08aSdrh     }else{
7102c306e08aSdrh       rc = SQLITE_OK;
7103c306e08aSdrh     }
7104248f2be9Sdrh     if( rc!=SQLITE_OK || zErrMsg ){
7105248f2be9Sdrh       Tcl_AppendResult(interp, "initialization of ", zName, " failed: ", zErrMsg,
7106248f2be9Sdrh                        (char*)0);
7107248f2be9Sdrh       sqlite3_free(zErrMsg);
7108248f2be9Sdrh       return TCL_ERROR;
7109248f2be9Sdrh     }
7110ea41dc44Sdrh   }
7111248f2be9Sdrh   return TCL_OK;
7112248f2be9Sdrh }
7113248f2be9Sdrh 
71140d51def2Sdan /*
71150d51def2Sdan **     sorter_test_fakeheap BOOL
71160d51def2Sdan **
71170d51def2Sdan */
71187617e4a8Smistachkin static int SQLITE_TCLAPI sorter_test_fakeheap(
71190d51def2Sdan   void * clientData,
71200d51def2Sdan   Tcl_Interp *interp,
71210d51def2Sdan   int objc,
71220d51def2Sdan   Tcl_Obj *CONST objv[]
71230d51def2Sdan ){
71240d51def2Sdan   int bArg;
71250d51def2Sdan   if( objc!=2 ){
71260d51def2Sdan     Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
71270d51def2Sdan     return TCL_ERROR;
71280d51def2Sdan   }
71290d51def2Sdan 
71300d51def2Sdan   if( Tcl_GetBooleanFromObj(interp, objv[1], &bArg) ){
71310d51def2Sdan     return TCL_ERROR;
71320d51def2Sdan   }
71330d51def2Sdan 
71340d51def2Sdan   if( bArg ){
71350d51def2Sdan     if( sqlite3GlobalConfig.pHeap==0 ){
71360d51def2Sdan       sqlite3GlobalConfig.pHeap = SQLITE_INT_TO_PTR(-1);
71370d51def2Sdan     }
71380d51def2Sdan   }else{
71390d51def2Sdan     if( sqlite3GlobalConfig.pHeap==SQLITE_INT_TO_PTR(-1) ){
71400d51def2Sdan       sqlite3GlobalConfig.pHeap = 0;
71410d51def2Sdan     }
71420d51def2Sdan   }
71430d51def2Sdan 
71440d51def2Sdan   Tcl_ResetResult(interp);
71450d51def2Sdan   return TCL_OK;
71460d51def2Sdan }
71470d51def2Sdan 
7148dfea4533Sdan /*
7149dfea4533Sdan **     sorter_test_sort4_helper DB SQL1 NSTEP SQL2
7150dfea4533Sdan **
7151dfea4533Sdan ** Compile SQL statement $SQL1 and step it $NSTEP times. For each row,
7152dfea4533Sdan ** check that the leftmost and rightmost columns returned are both integers,
7153dfea4533Sdan ** and that both contain the same value.
7154dfea4533Sdan **
7155dfea4533Sdan ** Then execute statement $SQL2. Check that the statement returns the same
7156dfea4533Sdan ** set of integers in the same order as in the previous step (using $SQL1).
7157dfea4533Sdan */
71587617e4a8Smistachkin static int SQLITE_TCLAPI sorter_test_sort4_helper(
7159dfea4533Sdan   void * clientData,
7160dfea4533Sdan   Tcl_Interp *interp,
7161dfea4533Sdan   int objc,
7162dfea4533Sdan   Tcl_Obj *CONST objv[]
7163dfea4533Sdan ){
7164dfea4533Sdan   const char *zSql1;
7165dfea4533Sdan   const char *zSql2;
7166dfea4533Sdan   int nStep;
7167dfea4533Sdan   int iStep;
716848cd59a5Sdrh   unsigned int iCksum1 = 0;
716948cd59a5Sdrh   unsigned int iCksum2 = 0;
7170dfea4533Sdan   int rc;
7171dfea4533Sdan   int iB;
7172dfea4533Sdan   sqlite3 *db;
7173dfea4533Sdan   sqlite3_stmt *pStmt;
7174dfea4533Sdan 
7175dfea4533Sdan   if( objc!=5 ){
7176dfea4533Sdan     Tcl_WrongNumArgs(interp, 1, objv, "DB SQL1 NSTEP SQL2");
7177dfea4533Sdan     return TCL_ERROR;
7178dfea4533Sdan   }
7179dfea4533Sdan 
7180dfea4533Sdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
7181dfea4533Sdan   zSql1 = Tcl_GetString(objv[2]);
7182dfea4533Sdan   if( Tcl_GetIntFromObj(interp, objv[3], &nStep) ) return TCL_ERROR;
7183dfea4533Sdan   zSql2 = Tcl_GetString(objv[4]);
7184dfea4533Sdan 
7185dfea4533Sdan   rc = sqlite3_prepare_v2(db, zSql1, -1, &pStmt, 0);
7186dfea4533Sdan   if( rc!=SQLITE_OK ) goto sql_error;
7187dfea4533Sdan 
7188dfea4533Sdan   iB = sqlite3_column_count(pStmt)-1;
7189dfea4533Sdan   for(iStep=0; iStep<nStep && SQLITE_ROW==sqlite3_step(pStmt); iStep++){
7190dfea4533Sdan     int a = sqlite3_column_int(pStmt, 0);
7191dfea4533Sdan     if( a!=sqlite3_column_int(pStmt, iB) ){
7192dfea4533Sdan       Tcl_AppendResult(interp, "data error: (a!=b)", 0);
7193dfea4533Sdan       return TCL_ERROR;
7194dfea4533Sdan     }
7195dfea4533Sdan 
719648cd59a5Sdrh     iCksum1 += (iCksum1 << 3) + (unsigned int)a;
7197dfea4533Sdan   }
7198dfea4533Sdan   rc = sqlite3_finalize(pStmt);
7199dfea4533Sdan   if( rc!=SQLITE_OK ) goto sql_error;
7200dfea4533Sdan 
7201dfea4533Sdan   rc = sqlite3_prepare_v2(db, zSql2, -1, &pStmt, 0);
7202dfea4533Sdan   if( rc!=SQLITE_OK ) goto sql_error;
7203dfea4533Sdan   for(iStep=0; SQLITE_ROW==sqlite3_step(pStmt); iStep++){
7204dfea4533Sdan     int a = sqlite3_column_int(pStmt, 0);
720548cd59a5Sdrh     iCksum2 += (iCksum2 << 3) + (unsigned int)a;
7206dfea4533Sdan   }
7207dfea4533Sdan   rc = sqlite3_finalize(pStmt);
7208dfea4533Sdan   if( rc!=SQLITE_OK ) goto sql_error;
7209dfea4533Sdan 
7210dfea4533Sdan   if( iCksum1!=iCksum2 ){
7211dfea4533Sdan     Tcl_AppendResult(interp, "checksum mismatch", 0);
7212dfea4533Sdan     return TCL_ERROR;
7213dfea4533Sdan   }
7214dfea4533Sdan 
7215dfea4533Sdan   return TCL_OK;
7216dfea4533Sdan  sql_error:
7217dfea4533Sdan   Tcl_AppendResult(interp, "sql error: ", sqlite3_errmsg(db), 0);
7218dfea4533Sdan   return TCL_ERROR;
7219dfea4533Sdan }
7220dfea4533Sdan 
7221248f2be9Sdrh 
7222d39c40ffSdrh #ifdef SQLITE_USER_AUTHENTICATION
7223d39c40ffSdrh #include "sqlite3userauth.h"
7224d39c40ffSdrh /*
7225d39c40ffSdrh ** tclcmd:  sqlite3_user_authenticate DB USERNAME PASSWORD
7226d39c40ffSdrh */
72277617e4a8Smistachkin static int SQLITE_TCLAPI test_user_authenticate(
7228d39c40ffSdrh   ClientData clientData, /* Unused */
7229d39c40ffSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
7230d39c40ffSdrh   int objc,              /* Number of arguments */
7231d39c40ffSdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
7232d39c40ffSdrh ){
7233d39c40ffSdrh   char *zUser = 0;
7234d39c40ffSdrh   char *zPasswd = 0;
7235d39c40ffSdrh   int nPasswd = 0;
7236d39c40ffSdrh   sqlite3 *db;
7237d39c40ffSdrh   int rc;
7238d39c40ffSdrh 
7239d39c40ffSdrh   if( objc!=4 ){
7240d39c40ffSdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD");
7241d39c40ffSdrh     return TCL_ERROR;
7242d39c40ffSdrh   }
7243d39c40ffSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
7244d39c40ffSdrh     return TCL_ERROR;
7245d39c40ffSdrh   }
7246d39c40ffSdrh   zUser = Tcl_GetString(objv[2]);
7247d39c40ffSdrh   zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd);
7248d39c40ffSdrh   rc = sqlite3_user_authenticate(db, zUser, zPasswd, nPasswd);
7249d39c40ffSdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
7250d39c40ffSdrh   return TCL_OK;
7251d39c40ffSdrh }
7252d39c40ffSdrh #endif /* SQLITE_USER_AUTHENTICATION */
7253d39c40ffSdrh 
7254d39c40ffSdrh #ifdef SQLITE_USER_AUTHENTICATION
7255d39c40ffSdrh /*
7256d39c40ffSdrh ** tclcmd:  sqlite3_user_add DB USERNAME PASSWORD ISADMIN
7257d39c40ffSdrh */
72587617e4a8Smistachkin static int SQLITE_TCLAPI test_user_add(
7259d39c40ffSdrh   ClientData clientData, /* Unused */
7260d39c40ffSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
7261d39c40ffSdrh   int objc,              /* Number of arguments */
7262d39c40ffSdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
7263d39c40ffSdrh ){
7264d39c40ffSdrh   char *zUser = 0;
7265d39c40ffSdrh   char *zPasswd = 0;
7266d39c40ffSdrh   int nPasswd = 0;
7267d39c40ffSdrh   int isAdmin = 0;
7268d39c40ffSdrh   sqlite3 *db;
7269d39c40ffSdrh   int rc;
7270d39c40ffSdrh 
7271d39c40ffSdrh   if( objc!=5 ){
7272d39c40ffSdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD ISADMIN");
7273d39c40ffSdrh     return TCL_ERROR;
7274d39c40ffSdrh   }
7275d39c40ffSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
7276d39c40ffSdrh     return TCL_ERROR;
7277d39c40ffSdrh   }
7278d39c40ffSdrh   zUser = Tcl_GetString(objv[2]);
7279d39c40ffSdrh   zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd);
7280d39c40ffSdrh   Tcl_GetBooleanFromObj(interp, objv[4], &isAdmin);
7281d39c40ffSdrh   rc = sqlite3_user_add(db, zUser, zPasswd, nPasswd, isAdmin);
7282d39c40ffSdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
7283d39c40ffSdrh   return TCL_OK;
7284d39c40ffSdrh }
7285d39c40ffSdrh #endif /* SQLITE_USER_AUTHENTICATION */
7286d39c40ffSdrh 
7287d39c40ffSdrh #ifdef SQLITE_USER_AUTHENTICATION
7288d39c40ffSdrh /*
7289d39c40ffSdrh ** tclcmd:  sqlite3_user_change DB USERNAME PASSWORD ISADMIN
7290d39c40ffSdrh */
72917617e4a8Smistachkin static int SQLITE_TCLAPI test_user_change(
7292d39c40ffSdrh   ClientData clientData, /* Unused */
7293d39c40ffSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
7294d39c40ffSdrh   int objc,              /* Number of arguments */
7295d39c40ffSdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
7296d39c40ffSdrh ){
7297d39c40ffSdrh   char *zUser = 0;
7298d39c40ffSdrh   char *zPasswd = 0;
7299d39c40ffSdrh   int nPasswd = 0;
7300d39c40ffSdrh   int isAdmin = 0;
7301d39c40ffSdrh   sqlite3 *db;
7302d39c40ffSdrh   int rc;
7303d39c40ffSdrh 
7304d39c40ffSdrh   if( objc!=5 ){
7305d39c40ffSdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD ISADMIN");
7306d39c40ffSdrh     return TCL_ERROR;
7307d39c40ffSdrh   }
7308d39c40ffSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
7309d39c40ffSdrh     return TCL_ERROR;
7310d39c40ffSdrh   }
7311d39c40ffSdrh   zUser = Tcl_GetString(objv[2]);
7312d39c40ffSdrh   zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd);
7313d39c40ffSdrh   Tcl_GetBooleanFromObj(interp, objv[4], &isAdmin);
7314d39c40ffSdrh   rc = sqlite3_user_change(db, zUser, zPasswd, nPasswd, isAdmin);
7315d39c40ffSdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
7316d39c40ffSdrh   return TCL_OK;
7317d39c40ffSdrh }
7318d39c40ffSdrh #endif /* SQLITE_USER_AUTHENTICATION */
7319d39c40ffSdrh 
7320d39c40ffSdrh #ifdef SQLITE_USER_AUTHENTICATION
7321d39c40ffSdrh /*
7322d39c40ffSdrh ** tclcmd:  sqlite3_user_delete DB USERNAME
7323d39c40ffSdrh */
73247617e4a8Smistachkin static int SQLITE_TCLAPI test_user_delete(
7325d39c40ffSdrh   ClientData clientData, /* Unused */
7326d39c40ffSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
7327d39c40ffSdrh   int objc,              /* Number of arguments */
7328d39c40ffSdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
7329d39c40ffSdrh ){
7330d39c40ffSdrh   char *zUser = 0;
7331d39c40ffSdrh   sqlite3 *db;
7332d39c40ffSdrh   int rc;
7333d39c40ffSdrh 
7334d39c40ffSdrh   if( objc!=3 ){
7335d39c40ffSdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME");
7336d39c40ffSdrh     return TCL_ERROR;
7337d39c40ffSdrh   }
7338d39c40ffSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
7339d39c40ffSdrh     return TCL_ERROR;
7340d39c40ffSdrh   }
7341d39c40ffSdrh   zUser = Tcl_GetString(objv[2]);
7342d39c40ffSdrh   rc = sqlite3_user_delete(db, zUser);
7343d39c40ffSdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
7344d39c40ffSdrh   return TCL_OK;
7345d39c40ffSdrh }
7346d39c40ffSdrh #endif /* SQLITE_USER_AUTHENTICATION */
7347d39c40ffSdrh 
7348f58ee7f1Sdrh /*
7349edb31cd1Sdrh ** tclcmd: bad_behavior TYPE
7350edb31cd1Sdrh **
7351edb31cd1Sdrh ** Do some things that should trigger a valgrind or -fsanitize=undefined
7352edb31cd1Sdrh ** warning.  This is used to verify that errors and warnings output by those
7353edb31cd1Sdrh ** tools are detected by the test scripts.
7354edb31cd1Sdrh **
7355edb31cd1Sdrh **       TYPE       BEHAVIOR
7356edb31cd1Sdrh **       1          Overflow a signed integer
7357edb31cd1Sdrh **       2          Jump based on an uninitialized variable
7358edb31cd1Sdrh **       3          Read after free
7359db6bafaeSdrh **       4          Panic
7360edb31cd1Sdrh */
73617617e4a8Smistachkin static int SQLITE_TCLAPI test_bad_behavior(
7362edb31cd1Sdrh   ClientData clientData, /* Pointer to an integer containing zero */
7363edb31cd1Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
7364edb31cd1Sdrh   int objc,              /* Number of arguments */
7365edb31cd1Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
7366edb31cd1Sdrh ){
7367edb31cd1Sdrh   int iType;
7368edb31cd1Sdrh   int xyz;
7369edb31cd1Sdrh   int i = *(int*)clientData;
7370edb31cd1Sdrh   int j;
7371edb31cd1Sdrh   int w[10];
7372edb31cd1Sdrh   int *a;
7373edb31cd1Sdrh   if( objc!=2 ){
7374edb31cd1Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "TYPE");
7375edb31cd1Sdrh     return TCL_ERROR;
7376edb31cd1Sdrh   }
7377edb31cd1Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &iType) ) return TCL_ERROR;
7378edb31cd1Sdrh   switch( iType ){
7379edb31cd1Sdrh     case 1: {
7380edb31cd1Sdrh       xyz = 0x7fffff00 - i;
7381edb31cd1Sdrh       xyz += 0x100;
7382edb31cd1Sdrh       Tcl_SetObjResult(interp, Tcl_NewIntObj(xyz));
7383edb31cd1Sdrh       break;
7384edb31cd1Sdrh     }
7385edb31cd1Sdrh     case 2: {
7386edb31cd1Sdrh       w[1] = 5;
7387edb31cd1Sdrh       if( w[i]>0 ) w[1]++;
7388edb31cd1Sdrh       Tcl_SetObjResult(interp, Tcl_NewIntObj(w[1]));
7389edb31cd1Sdrh       break;
7390edb31cd1Sdrh     }
7391edb31cd1Sdrh     case 3: {
7392edb31cd1Sdrh       a = malloc( sizeof(int)*10 );
7393edb31cd1Sdrh       for(j=0; j<10; j++) a[j] = j;
7394edb31cd1Sdrh       free(a);
7395edb31cd1Sdrh       Tcl_SetObjResult(interp, Tcl_NewIntObj(a[i]));
7396edb31cd1Sdrh       break;
7397edb31cd1Sdrh     }
7398db6bafaeSdrh     case 4: {
7399db6bafaeSdrh       Tcl_Panic("Deliberate panic");
7400db6bafaeSdrh       break;
7401db6bafaeSdrh     }
7402edb31cd1Sdrh   }
7403edb31cd1Sdrh   return TCL_OK;
7404edb31cd1Sdrh }
7405edb31cd1Sdrh 
74063e0327d5Sdrh /*
74073e0327d5Sdrh ** tclcmd:   register_dbstat_vtab DB
74083e0327d5Sdrh **
74093e0327d5Sdrh ** Cause the dbstat virtual table to be available on the connection DB
74103e0327d5Sdrh */
74117617e4a8Smistachkin static int SQLITE_TCLAPI test_register_dbstat_vtab(
74123e0327d5Sdrh   void *clientData,
74133e0327d5Sdrh   Tcl_Interp *interp,
74143e0327d5Sdrh   int objc,
74153e0327d5Sdrh   Tcl_Obj *CONST objv[]
74163e0327d5Sdrh ){
74173e0327d5Sdrh #ifdef SQLITE_OMIT_VIRTUALTABLE
74183e0327d5Sdrh   Tcl_AppendResult(interp, "dbstat not available because of "
74193e0327d5Sdrh                            "SQLITE_OMIT_VIRTUALTABLE", (void*)0);
74203e0327d5Sdrh   return TCL_ERROR;
74213e0327d5Sdrh #else
74223e0327d5Sdrh   struct SqliteDb { sqlite3 *db; };
74233e0327d5Sdrh   char *zDb;
74243e0327d5Sdrh   Tcl_CmdInfo cmdInfo;
74253e0327d5Sdrh 
74263e0327d5Sdrh   if( objc!=2 ){
74273e0327d5Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB");
74283e0327d5Sdrh     return TCL_ERROR;
74293e0327d5Sdrh   }
74303e0327d5Sdrh 
74313e0327d5Sdrh   zDb = Tcl_GetString(objv[1]);
74323e0327d5Sdrh   if( Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){
74333e0327d5Sdrh     sqlite3* db = ((struct SqliteDb*)cmdInfo.objClientData)->db;
74343e0327d5Sdrh     sqlite3DbstatRegister(db);
74353e0327d5Sdrh   }
74363e0327d5Sdrh   return TCL_OK;
74373e0327d5Sdrh #endif /* SQLITE_OMIT_VIRTUALTABLE */
74383e0327d5Sdrh }
7439edb31cd1Sdrh 
7440edb31cd1Sdrh /*
7441d42908fbSdrh ** tclcmd:   sqlite3_db_config DB SETTING VALUE
7442d42908fbSdrh **
7443d42908fbSdrh ** Invoke sqlite3_db_config() for one of the setting values.
7444d42908fbSdrh */
74457617e4a8Smistachkin static int SQLITE_TCLAPI test_sqlite3_db_config(
7446d42908fbSdrh   void *clientData,
7447d42908fbSdrh   Tcl_Interp *interp,
7448d42908fbSdrh   int objc,
7449d42908fbSdrh   Tcl_Obj *CONST objv[]
7450d42908fbSdrh ){
7451d42908fbSdrh   static const struct {
7452d42908fbSdrh     const char *zName;
7453d42908fbSdrh     int eVal;
7454d42908fbSdrh   } aSetting[] = {
7455d42908fbSdrh     { "FKEY",            SQLITE_DBCONFIG_ENABLE_FKEY },
7456d42908fbSdrh     { "TRIGGER",         SQLITE_DBCONFIG_ENABLE_TRIGGER },
7457d42908fbSdrh     { "FTS3_TOKENIZER",  SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER },
7458191dd061Sdrh     { "LOAD_EXTENSION",  SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION },
7459298af023Sdan     { "NO_CKPT_ON_CLOSE",SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE },
7460169dd928Sdrh     { "QPSG",            SQLITE_DBCONFIG_ENABLE_QPSG },
74617df01196Sdrh     { "TRIGGER_EQP",     SQLITE_DBCONFIG_TRIGGER_EQP },
74627df01196Sdrh     { "RESET_DB",        SQLITE_DBCONFIG_RESET_DATABASE },
7463d42908fbSdrh   };
7464d42908fbSdrh   int i;
7465d42908fbSdrh   int v;
7466d42908fbSdrh   const char *zSetting;
7467d42908fbSdrh   sqlite3 *db;
7468d42908fbSdrh 
7469d42908fbSdrh   if( objc!=4 ){
7470d42908fbSdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB SETTING VALUE");
7471d42908fbSdrh     return TCL_ERROR;
7472d42908fbSdrh   }
7473d42908fbSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
7474d42908fbSdrh   zSetting = Tcl_GetString(objv[2]);
7475d42908fbSdrh   if( sqlite3_strglob("SQLITE_*", zSetting)==0 ) zSetting += 7;
7476d42908fbSdrh   if( sqlite3_strglob("DBCONFIG_*", zSetting)==0 ) zSetting += 9;
7477d42908fbSdrh   if( sqlite3_strglob("ENABLE_*", zSetting)==0 ) zSetting += 7;
7478d42908fbSdrh   for(i=0; i<ArraySize(aSetting); i++){
7479d42908fbSdrh     if( strcmp(zSetting, aSetting[i].zName)==0 ) break;
7480d42908fbSdrh   }
7481d42908fbSdrh   if( i>=ArraySize(aSetting) ){
7482d42908fbSdrh     Tcl_SetObjResult(interp,
7483d42908fbSdrh       Tcl_NewStringObj("unknown sqlite3_db_config setting", -1));
7484d42908fbSdrh     return TCL_ERROR;
7485d42908fbSdrh   }
7486d42908fbSdrh   if( Tcl_GetIntFromObj(interp, objv[3], &v) ) return TCL_ERROR;
7487d42908fbSdrh   sqlite3_db_config(db, aSetting[i].eVal, v, &v);
7488d42908fbSdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(v));
7489d42908fbSdrh   return TCL_OK;
7490d42908fbSdrh }
7491d42908fbSdrh 
7492d42908fbSdrh /*
7493da84dcaeSdrh ** Change the name of the main database schema from "main" to "icecube".
7494da84dcaeSdrh */
7495da84dcaeSdrh static int SQLITE_TCLAPI test_dbconfig_maindbname_icecube(
7496da84dcaeSdrh   void * clientData,
7497da84dcaeSdrh   Tcl_Interp *interp,
7498da84dcaeSdrh   int objc,
7499da84dcaeSdrh   Tcl_Obj *CONST objv[]
7500da84dcaeSdrh ){
7501da84dcaeSdrh   int rc;
7502da84dcaeSdrh   sqlite3 *db;
7503da84dcaeSdrh   extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
7504da84dcaeSdrh   if( objc!=2 ){
7505da84dcaeSdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB");
7506da84dcaeSdrh     return TCL_ERROR;
7507da84dcaeSdrh   }else{
7508da84dcaeSdrh     if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
7509da84dcaeSdrh     rc = sqlite3_db_config(db, SQLITE_DBCONFIG_MAINDBNAME, "icecube");
7510da84dcaeSdrh     Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
7511da84dcaeSdrh     return TCL_OK;
7512da84dcaeSdrh   }
7513da84dcaeSdrh }
7514da84dcaeSdrh 
7515da84dcaeSdrh /*
7516460f1fa5Sdan ** Usage: sqlite3_mmap_warm DB DBNAME
7517460f1fa5Sdan */
7518460f1fa5Sdan static int SQLITE_TCLAPI test_mmap_warm(
7519460f1fa5Sdan   void * clientData,
7520460f1fa5Sdan   Tcl_Interp *interp,
7521460f1fa5Sdan   int objc,
7522460f1fa5Sdan   Tcl_Obj *CONST objv[]
7523460f1fa5Sdan ){
7524460f1fa5Sdan   extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
7525460f1fa5Sdan   extern int sqlite3_mmap_warm(sqlite3 *db, const char *);
7526460f1fa5Sdan 
7527460f1fa5Sdan   if( objc!=2 && objc!=3 ){
7528460f1fa5Sdan     Tcl_WrongNumArgs(interp, 1, objv, "DB ?DBNAME?");
7529460f1fa5Sdan     return TCL_ERROR;
7530460f1fa5Sdan   }else{
7531460f1fa5Sdan     int rc;
7532460f1fa5Sdan     sqlite3 *db;
7533460f1fa5Sdan     const char *zDb = 0;
7534460f1fa5Sdan     if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
7535460f1fa5Sdan     if( objc==3 ){
7536460f1fa5Sdan       zDb = Tcl_GetString(objv[2]);
7537460f1fa5Sdan     }
7538460f1fa5Sdan     rc = sqlite3_mmap_warm(db, zDb);
7539460f1fa5Sdan     Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
7540460f1fa5Sdan     return TCL_OK;
7541460f1fa5Sdan   }
7542460f1fa5Sdan }
7543460f1fa5Sdan 
7544460f1fa5Sdan /*
7545d1bf3512Sdrh ** Register commands with the TCL interpreter.
7546d1bf3512Sdrh */
7547d1bf3512Sdrh int Sqlitetest1_Init(Tcl_Interp *interp){
75486f8a503dSdanielk1977   extern int sqlite3_search_count;
75490ff297eaSdan   extern int sqlite3_found_count;
75506f8a503dSdanielk1977   extern int sqlite3_interrupt_count;
75516f8a503dSdanielk1977   extern int sqlite3_open_file_count;
75526bf89570Sdrh   extern int sqlite3_sort_count;
75536f8a503dSdanielk1977   extern int sqlite3_current_time;
755484a2bf67Sdrh #if SQLITE_OS_UNIX && defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
7555aebf413dSaswift   extern int sqlite3_hostid_num;
7556aabbed22Spweilbacher #endif
7557ae7e151aSdrh   extern int sqlite3_max_blobsize;
75587617e4a8Smistachkin   extern int SQLITE_TCLAPI sqlite3BtreeSharedCacheReport(void*,
755916a9b836Sdrh                                           Tcl_Interp*,int,Tcl_Obj*CONST*);
7560edb31cd1Sdrh   static int iZero = 0;
7561c2eef3b3Sdrh   static struct {
7562c2eef3b3Sdrh      char *zName;
7563c2eef3b3Sdrh      Tcl_CmdProc *xProc;
7564c2eef3b3Sdrh   } aCmd[] = {
756527641703Sdrh      { "db_enter",                      (Tcl_CmdProc*)db_enter               },
756627641703Sdrh      { "db_leave",                      (Tcl_CmdProc*)db_leave               },
75676f8a503dSdanielk1977      { "sqlite3_mprintf_int",           (Tcl_CmdProc*)sqlite3_mprintf_int    },
7568e9707671Sdrh      { "sqlite3_mprintf_int64",         (Tcl_CmdProc*)sqlite3_mprintf_int64  },
7569c5cad1e3Sdrh      { "sqlite3_mprintf_long",          (Tcl_CmdProc*)sqlite3_mprintf_long   },
75706f8a503dSdanielk1977      { "sqlite3_mprintf_str",           (Tcl_CmdProc*)sqlite3_mprintf_str    },
7571b3738b6cSdrh      { "sqlite3_snprintf_str",          (Tcl_CmdProc*)sqlite3_snprintf_str   },
7572e29b1a05Sdrh      { "sqlite3_mprintf_stronly",       (Tcl_CmdProc*)sqlite3_mprintf_stronly},
75736f8a503dSdanielk1977      { "sqlite3_mprintf_double",        (Tcl_CmdProc*)sqlite3_mprintf_double },
75746f8a503dSdanielk1977      { "sqlite3_mprintf_scaled",        (Tcl_CmdProc*)sqlite3_mprintf_scaled },
757563782855Sdrh      { "sqlite3_mprintf_hexdouble",   (Tcl_CmdProc*)sqlite3_mprintf_hexdouble},
75766f8a503dSdanielk1977      { "sqlite3_mprintf_z_test",        (Tcl_CmdProc*)test_mprintf_z        },
757705a82983Sdrh      { "sqlite3_mprintf_n_test",        (Tcl_CmdProc*)test_mprintf_n        },
757868853907Sdrh      { "sqlite3_snprintf_int",          (Tcl_CmdProc*)test_snprintf_int     },
75796f8a503dSdanielk1977      { "sqlite3_last_insert_rowid",     (Tcl_CmdProc*)test_last_rowid       },
75806f8a503dSdanielk1977      { "sqlite3_exec_printf",           (Tcl_CmdProc*)test_exec_printf      },
75815bd98aefSdrh      { "sqlite3_exec_hex",              (Tcl_CmdProc*)test_exec_hex         },
7582b62c335eSdrh      { "sqlite3_exec",                  (Tcl_CmdProc*)test_exec             },
7583b62c335eSdrh      { "sqlite3_exec_nr",               (Tcl_CmdProc*)test_exec_nr          },
75848225f5acSshane #ifndef SQLITE_OMIT_GET_TABLE
75856f8a503dSdanielk1977      { "sqlite3_get_table_printf",      (Tcl_CmdProc*)test_get_table_printf },
75868225f5acSshane #endif
75876f8a503dSdanielk1977      { "sqlite3_close",                 (Tcl_CmdProc*)sqlite_test_close     },
7588617dc860Sdan      { "sqlite3_close_v2",              (Tcl_CmdProc*)sqlite_test_close_v2  },
75896f8a503dSdanielk1977      { "sqlite3_create_function",       (Tcl_CmdProc*)test_create_function  },
75906f8a503dSdanielk1977      { "sqlite3_create_aggregate",      (Tcl_CmdProc*)test_create_aggregate },
7591c2eef3b3Sdrh      { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func    },
7592c2eef3b3Sdrh      { "sqlite_abort",                  (Tcl_CmdProc*)sqlite_abort          },
759396fc5fe6Sdanielk1977      { "sqlite_bind",                   (Tcl_CmdProc*)test_bind             },
759499ee3600Sdrh      { "breakpoint",                    (Tcl_CmdProc*)test_breakpoint       },
759525d6543dSdrh      { "sqlite3_key",                   (Tcl_CmdProc*)test_key              },
759625d6543dSdrh      { "sqlite3_rekey",                 (Tcl_CmdProc*)test_rekey            },
7597cacb208eSdrh      { "sqlite_set_magic",              (Tcl_CmdProc*)sqlite_set_magic      },
7598c5cdca61Sdrh      { "sqlite3_interrupt",             (Tcl_CmdProc*)test_interrupt        },
75999636c4e1Sdanielk1977      { "sqlite_delete_function",        (Tcl_CmdProc*)delete_function       },
76003e1d8e63Sdrh      { "sqlite_delete_collation",       (Tcl_CmdProc*)delete_collation      },
76013e1d8e63Sdrh      { "sqlite3_get_autocommit",        (Tcl_CmdProc*)get_autocommit        },
76023086765bSdrh      { "sqlite3_busy_timeout",          (Tcl_CmdProc*)test_busy_timeout     },
76033c23a885Sdrh      { "printf",                        (Tcl_CmdProc*)test_printf           },
76043a00f907Smlcreech      { "sqlite3IoTrace",              (Tcl_CmdProc*)test_io_trace         },
7605afcf9bd8Sdan      { "clang_sanitize_address",        (Tcl_CmdProc*)clang_sanitize_address },
7606c2eef3b3Sdrh   };
760751e3d8e2Sdanielk1977   static struct {
760851e3d8e2Sdanielk1977      char *zName;
760951e3d8e2Sdanielk1977      Tcl_ObjCmdProc *xProc;
761004f2e68dSdanielk1977      void *clientData;
761151e3d8e2Sdanielk1977   } aObjCmd[] = {
7612d42908fbSdrh      { "sqlite3_db_config",             test_sqlite3_db_config, 0 },
7613edb31cd1Sdrh      { "bad_behavior",                  test_bad_behavior,  (void*)&iZero },
76143e0327d5Sdrh      { "register_dbstat_vtab",          test_register_dbstat_vtab  },
7615dddca286Sdrh      { "sqlite3_connection_pointer",    get_sqlite_pointer, 0 },
76162e3f87aeSdrh      { "intarray_addr",                 test_intarray_addr, 0 },
76172e3f87aeSdrh      { "int64array_addr",               test_int64array_addr, 0 },
76182e3f87aeSdrh      { "doublearray_addr",              test_doublearray_addr, 0 },
76192e3f87aeSdrh      { "textarray_addr",                test_textarray_addr, 0 },
7620241db313Sdrh      { "sqlite3_bind_int",              test_bind_int,      0 },
7621b026e05eSdrh      { "sqlite3_bind_zeroblob",         test_bind_zeroblob, 0 },
762280c03022Sdan      { "sqlite3_bind_zeroblob64",       test_bind_zeroblob64, 0 },
762304f2e68dSdanielk1977      { "sqlite3_bind_int64",            test_bind_int64,    0 },
762404f2e68dSdanielk1977      { "sqlite3_bind_double",           test_bind_double,   0 },
762504f2e68dSdanielk1977      { "sqlite3_bind_null",             test_bind_null     ,0 },
762604f2e68dSdanielk1977      { "sqlite3_bind_text",             test_bind_text     ,0 },
762704f2e68dSdanielk1977      { "sqlite3_bind_text16",           test_bind_text16   ,0 },
762804f2e68dSdanielk1977      { "sqlite3_bind_blob",             test_bind_blob     ,0 },
762975f6a032Sdrh      { "sqlite3_bind_parameter_count",  test_bind_parameter_count, 0},
7630895d7472Sdrh      { "sqlite3_bind_parameter_name",   test_bind_parameter_name,  0},
7631fa6bc000Sdrh      { "sqlite3_bind_parameter_index",  test_bind_parameter_index, 0},
7632600dd0baSdanielk1977      { "sqlite3_clear_bindings",        test_clear_bindings, 0},
7633f9cb7f58Sdrh      { "sqlite3_sleep",                 test_sleep,          0},
763404f2e68dSdanielk1977      { "sqlite3_errcode",               test_errcode       ,0 },
763599dfe5ebSdrh      { "sqlite3_extended_errcode",      test_ex_errcode    ,0 },
763604f2e68dSdanielk1977      { "sqlite3_errmsg",                test_errmsg        ,0 },
763704f2e68dSdanielk1977      { "sqlite3_errmsg16",              test_errmsg16      ,0 },
763804f2e68dSdanielk1977      { "sqlite3_open",                  test_open          ,0 },
763904f2e68dSdanielk1977      { "sqlite3_open16",                test_open16        ,0 },
7640286ab7c2Sdan      { "sqlite3_open_v2",               test_open_v2       ,0 },
7641bc6ada41Sdanielk1977      { "sqlite3_complete16",            test_complete16    ,0 },
764291694dbdSdrh      { "sqlite3_normalize",             test_normalize     ,0 },
764304f2e68dSdanielk1977 
764404f2e68dSdanielk1977      { "sqlite3_prepare",               test_prepare       ,0 },
764504f2e68dSdanielk1977      { "sqlite3_prepare16",             test_prepare16     ,0 },
7646b900aaf3Sdrh      { "sqlite3_prepare_v2",            test_prepare_v2    ,0 },
76474837f531Sdrh      { "sqlite3_prepare_tkt3134",       test_prepare_tkt3134, 0},
7648b900aaf3Sdrh      { "sqlite3_prepare16_v2",          test_prepare16_v2  ,0 },
764904f2e68dSdanielk1977      { "sqlite3_finalize",              test_finalize      ,0 },
7650d1d38488Sdrh      { "sqlite3_stmt_status",           test_stmt_status   ,0 },
765104f2e68dSdanielk1977      { "sqlite3_reset",                 test_reset         ,0 },
7652d89bd007Sdrh      { "sqlite3_expired",               test_expired       ,0 },
7653f8db1bc0Sdrh      { "sqlite3_transfer_bindings",     test_transfer_bind ,0 },
7654fbcd585fSdanielk1977      { "sqlite3_changes",               test_changes       ,0 },
765504f2e68dSdanielk1977      { "sqlite3_step",                  test_step          ,0 },
7656404ca075Sdanielk1977      { "sqlite3_sql",                   test_sql           ,0 },
7657fca760c8Sdrh      { "sqlite3_expanded_sql",          test_ex_sql        ,0 },
7658bb5a9c3eSdrh      { "sqlite3_next_stmt",             test_next_stmt     ,0 },
7659f03d9cccSdrh      { "sqlite3_stmt_readonly",         test_stmt_readonly ,0 },
76602fb6693eSdrh      { "sqlite3_stmt_busy",             test_stmt_busy     ,0 },
7661d9495cd0Sdan      { "uses_stmt_journal",             uses_stmt_journal ,0 },
766204f2e68dSdanielk1977 
76636aafc29bSdrh      { "sqlite3_release_memory",        test_release_memory,     0},
766409419b4bSdrh      { "sqlite3_db_release_memory",     test_db_release_memory,  0},
76656fa255fdSdan      { "sqlite3_db_cacheflush",         test_db_cacheflush,      0},
76660e80e509Sdrh      { "sqlite3_system_errno",          test_system_errno,       0},
7667283829cbSdrh      { "sqlite3_db_filename",           test_db_filename,        0},
7668421377e6Sdrh      { "sqlite3_db_readonly",           test_db_readonly,        0},
76696aafc29bSdrh      { "sqlite3_soft_heap_limit",       test_soft_heap_limit,    0},
7670b4bc7057Sdrh      { "sqlite3_thread_cleanup",        test_thread_cleanup,     0},
7671c6ba55f4Sdrh      { "sqlite3_pager_refcounts",       test_pager_refcounts,    0},
76726aafc29bSdrh 
7673c2e87a3eSdrh      { "sqlite3_load_extension",        test_load_extension,     0},
7674c2e87a3eSdrh      { "sqlite3_enable_load_extension", test_enable_load,        0},
76754ac285a1Sdrh      { "sqlite3_extended_result_codes", test_extended_result_codes, 0},
7676b1a6c3c1Sdrh      { "sqlite3_limit",                 test_limit,                 0},
7677da84dcaeSdrh      { "dbconfig_maindbname_icecube",   test_dbconfig_maindbname_icecube },
7678c2e87a3eSdrh 
767993aed5a1Sdrh      { "save_prng_state",               save_prng_state,    0 },
768093aed5a1Sdrh      { "restore_prng_state",            restore_prng_state, 0 },
768193aed5a1Sdrh      { "reset_prng_state",              reset_prng_state,   0 },
768209fe6143Sdrh      { "database_never_corrupt",        database_never_corrupt, 0},
768309fe6143Sdrh      { "database_may_be_corrupt",       database_may_be_corrupt, 0},
7684f58ee7f1Sdrh      { "optimization_control",          optimization_control,0},
768580084ca8Sdrh #if SQLITE_OS_WIN
768680084ca8Sdrh      { "lock_win32_file",               win32_file_lock,    0 },
76873741827eSmistachkin      { "exists_win32_path",             win32_exists_path,  0 },
76883741827eSmistachkin      { "find_win32_file",               win32_find_file,    0 },
76893741827eSmistachkin      { "delete_win32_file",             win32_delete_file,  0 },
76903741827eSmistachkin      { "make_win32_dir",                win32_mkdir,        0 },
76913741827eSmistachkin      { "remove_win32_dir",              win32_rmdir,        0 },
769280084ca8Sdrh #endif
7693a2c8a95bSdrh      { "tcl_objproc",                   runAsObjProc,       0 },
769493aed5a1Sdrh 
769504f2e68dSdanielk1977      /* sqlite3_column_*() API */
769604f2e68dSdanielk1977      { "sqlite3_column_count",          test_column_count  ,0 },
769704f2e68dSdanielk1977      { "sqlite3_data_count",            test_data_count    ,0 },
769804f2e68dSdanielk1977      { "sqlite3_column_type",           test_column_type   ,0 },
7699ea61b2c4Sdanielk1977      { "sqlite3_column_blob",           test_column_blob   ,0 },
770004f2e68dSdanielk1977      { "sqlite3_column_double",         test_column_double ,0 },
770104f2e68dSdanielk1977      { "sqlite3_column_int64",          test_column_int64  ,0 },
770244a376f6Sdanielk1977      { "sqlite3_column_text",   test_stmt_utf8,  (void*)sqlite3_column_text },
770344a376f6Sdanielk1977      { "sqlite3_column_name",   test_stmt_utf8,  (void*)sqlite3_column_name },
770444a376f6Sdanielk1977      { "sqlite3_column_int",    test_stmt_int,   (void*)sqlite3_column_int  },
770544a376f6Sdanielk1977      { "sqlite3_column_bytes",  test_stmt_int,   (void*)sqlite3_column_bytes},
77063f913576Sdrh #ifndef SQLITE_OMIT_DECLTYPE
770744a376f6Sdanielk1977      { "sqlite3_column_decltype",test_stmt_utf8,(void*)sqlite3_column_decltype},
77083f913576Sdrh #endif
77094b1ae99dSdanielk1977 #ifdef SQLITE_ENABLE_COLUMN_METADATA
771044a376f6Sdanielk1977 { "sqlite3_column_database_name",test_stmt_utf8,(void*)sqlite3_column_database_name},
771144a376f6Sdanielk1977 { "sqlite3_column_table_name",test_stmt_utf8,(void*)sqlite3_column_table_name},
771244a376f6Sdanielk1977 { "sqlite3_column_origin_name",test_stmt_utf8,(void*)sqlite3_column_origin_name},
77134b1ae99dSdanielk1977 #endif
7714955de52cSdanielk1977 
77156c62608fSdrh #ifndef SQLITE_OMIT_UTF16
771644a376f6Sdanielk1977      { "sqlite3_column_bytes16", test_stmt_int, (void*)sqlite3_column_bytes16 },
771744a376f6Sdanielk1977      { "sqlite3_column_text16",  test_stmt_utf16, (void*)sqlite3_column_text16},
771844a376f6Sdanielk1977      { "sqlite3_column_name16",  test_stmt_utf16, (void*)sqlite3_column_name16},
77197d9bd4e1Sdrh      { "add_alignment_test_collations", add_alignment_test_collations, 0      },
77203f913576Sdrh #ifndef SQLITE_OMIT_DECLTYPE
772144a376f6Sdanielk1977      { "sqlite3_column_decltype16",test_stmt_utf16,(void*)sqlite3_column_decltype16},
77223f913576Sdrh #endif
77234b1ae99dSdanielk1977 #ifdef SQLITE_ENABLE_COLUMN_METADATA
7724955de52cSdanielk1977 {"sqlite3_column_database_name16",
77257da5fcb0Sdrh   test_stmt_utf16, (void*)sqlite3_column_database_name16},
772644a376f6Sdanielk1977 {"sqlite3_column_table_name16", test_stmt_utf16, (void*)sqlite3_column_table_name16},
772744a376f6Sdanielk1977 {"sqlite3_column_origin_name16", test_stmt_utf16, (void*)sqlite3_column_origin_name16},
77286c62608fSdrh #endif
77294b1ae99dSdanielk1977 #endif
7730a393c036Sdanielk1977      { "sqlite3_create_collation_v2", test_create_collation_v2, 0 },
77316b456a2bSdanielk1977      { "sqlite3_global_recover",     test_global_recover, 0   },
773280788d8bSdrh      { "working_64bit_int",          working_64bit_int,   0   },
77339bc5449fSdrh      { "vfs_unlink_test",            vfs_unlink_test,     0   },
7734c8d75674Sdrh      { "vfs_initfail_test",          vfs_initfail_test,   0   },
7735a2820970Sdrh      { "vfs_unregister_all",         vfs_unregister_all,  0   },
7736a2820970Sdrh      { "vfs_reregister_all",         vfs_reregister_all,  0   },
773755176259Sdrh      { "file_control_test",          file_control_test,   0   },
7738aebf413dSaswift      { "file_control_lasterrno_test", file_control_lasterrno_test,  0   },
7739aebf413dSaswift      { "file_control_lockproxy_test", file_control_lockproxy_test,  0   },
77406e09d69cSdan      { "file_control_chunksize_test", file_control_chunksize_test,  0   },
7741661d71afSdan      { "file_control_sizehint_test",  file_control_sizehint_test,   0   },
7742ea99a31cSdrh      { "file_control_data_version",   file_control_data_version,    0   },
77436b98d67bSmistachkin #if SQLITE_OS_WIN
7744d0cdf012Sdrh      { "file_control_win32_av_retry", file_control_win32_av_retry,  0   },
77451b361ff3Smistachkin      { "file_control_win32_get_handle", file_control_win32_get_handle, 0  },
77466b98d67bSmistachkin      { "file_control_win32_set_handle", file_control_win32_set_handle, 0  },
77476b98d67bSmistachkin #endif
7748253cea5cSdrh      { "file_control_persist_wal",    file_control_persist_wal,     0   },
7749cb15f35fSdrh      { "file_control_powersafe_overwrite",file_control_powersafe_overwrite,0},
7750de60fc2dSdrh      { "file_control_vfsname",        file_control_vfsname,         0   },
7751696b33e6Sdrh      { "file_control_tempfilename",   file_control_tempfilename,    0   },
7752e339d65aSdanielk1977      { "sqlite3_vfs_list",           vfs_list,     0   },
7753d2199f0fSdan      { "sqlite3_create_function_v2", test_create_function_v2, 0 },
775404f2e68dSdanielk1977 
77559a1d0abeSdanielk1977      /* Functions from os.h */
77565436dc2dSdrh #ifndef SQLITE_OMIT_UTF16
77574e6af134Sdanielk1977      { "add_test_collate",        test_collate, 0            },
7758312d6b36Sdanielk1977      { "add_test_collate_needed", test_collate_needed, 0     },
7759c8e9a2dfSdanielk1977      { "add_test_function",       test_function, 0           },
776038fdead8Sdan      { "add_test_utf16bin_collate",    test_utf16bin_collate, 0        },
77615436dc2dSdrh #endif
7762312d6b36Sdanielk1977      { "sqlite3_test_errstr",     test_errstr, 0             },
776392febd92Sdrh      { "tcl_variable_type",       tcl_variable_type, 0       },
7764aef0bf64Sdanielk1977 #ifndef SQLITE_OMIT_SHARED_CACHE
77656f7adc8aSdrh      { "sqlite3_enable_shared_cache", test_enable_shared, 0  },
776616a9b836Sdrh      { "sqlite3_shared_cache_report", sqlite3BtreeSharedCacheReport, 0},
7767aef0bf64Sdanielk1977 #endif
7768161fb796Sdanielk1977      { "sqlite3_libversion_number", test_libversion_number, 0  },
7769deb802cdSdanielk1977      { "sqlite3_table_column_metadata", test_table_column_metadata, 0  },
7770dcbb5d3fSdanielk1977 #ifndef SQLITE_OMIT_INCRBLOB
77714e76cc36Sdan      { "sqlite3_blob_reopen", test_blob_reopen, 0  },
7772dcbb5d3fSdanielk1977 #endif
7773062d4cb0Sdanielk1977      { "pcache_stats",       test_pcache_stats, 0  },
7774404ca075Sdanielk1977 #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
7775404ca075Sdanielk1977      { "sqlite3_unlock_notify", test_unlock_notify, 0  },
7776404ca075Sdanielk1977 #endif
777787c1fe1bSdan      { "sqlite3_wal_checkpoint",   test_wal_checkpoint, 0  },
77789c5e3680Sdan      { "sqlite3_wal_checkpoint_v2",test_wal_checkpoint_v2, 0  },
77799af10620Sdan      { "sqlite3_wal_autocheckpoint",test_wal_autocheckpoint, 0  },
7780eb8763d7Sdan      { "test_sqlite3_log",         test_sqlite3_log, 0  },
7781bb201344Sshaneh #ifndef SQLITE_OMIT_EXPLAIN
778291da6b83Sdan      { "print_explain_query_plan", test_print_eqp, 0  },
7783bb201344Sshaneh #endif
7784c17d696cSdan      { "sqlite3_test_control", test_test_control },
7785daf9a5a4Smistachkin #if SQLITE_OS_UNIX
7786a72014faSdan      { "getrusage", test_getrusage },
7787daf9a5a4Smistachkin #endif
7788248f2be9Sdrh      { "load_static_extension", tclLoadStaticExtensionCmd },
77890d51def2Sdan      { "sorter_test_fakeheap", sorter_test_fakeheap },
7790dfea4533Sdan      { "sorter_test_sort4_helper", sorter_test_sort4_helper },
7791d39c40ffSdrh #ifdef SQLITE_USER_AUTHENTICATION
7792d39c40ffSdrh      { "sqlite3_user_authenticate", test_user_authenticate, 0 },
7793d39c40ffSdrh      { "sqlite3_user_add",          test_user_add,          0 },
7794d39c40ffSdrh      { "sqlite3_user_change",       test_user_change,       0 },
7795d39c40ffSdrh      { "sqlite3_user_delete",       test_user_delete,       0 },
7796d39c40ffSdrh #endif
779704489b6dSdan #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
779804489b6dSdan      { "sqlite3_stmt_scanstatus",       test_stmt_scanstatus,   0 },
779904489b6dSdan      { "sqlite3_stmt_scanstatus_reset", test_stmt_scanstatus_reset,   0 },
780004489b6dSdan #endif
7801d83f7ca1Sdan #ifdef SQLITE_ENABLE_SQLLOG
7802d83f7ca1Sdan      { "sqlite3_config_sqllog",         test_config_sqllog,   0 },
7803d83f7ca1Sdan #endif
7804e4e416e8Sdan      { "vfs_current_time_int64",           vfsCurrentTimeInt64,   0 },
7805fc1acf33Sdan #ifdef SQLITE_ENABLE_SNAPSHOT
7806fc1acf33Sdan      { "sqlite3_snapshot_get", test_snapshot_get, 0 },
7807fc1acf33Sdan      { "sqlite3_snapshot_open", test_snapshot_open, 0 },
7808fc1acf33Sdan      { "sqlite3_snapshot_free", test_snapshot_free, 0 },
7809ad2d5bafSdan      { "sqlite3_snapshot_cmp", test_snapshot_cmp, 0 },
78101158498dSdan      { "sqlite3_snapshot_recover", test_snapshot_recover, 0 },
781125accbcaSdan      { "sqlite3_snapshot_get_blob", test_snapshot_get_blob, 0 },
781225accbcaSdan      { "sqlite3_snapshot_open_blob", test_snapshot_open_blob, 0 },
781325accbcaSdan      { "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 },
7814fc1acf33Sdan #endif
7815000f95b1Sdan      { "sqlite3_delete_database", test_delete_database,    0 },
78164da30f88Sdan      { "atomic_batch_write",      test_atomic_batch_write, 0 },
7817460f1fa5Sdan      { "sqlite3_mmap_warm",       test_mmap_warm,          0 },
78182e3a5a81Sdan      { "sqlite3_config_sorterref", test_config_sorterref,   0 },
781951e3d8e2Sdanielk1977   };
78201398ad36Sdrh   static int bitmask_size = sizeof(Bitmask)*8;
78212ab410aaSdrh   static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
7822c2eef3b3Sdrh   int i;
7823b851b2c9Sdrh   extern int sqlite3_sync_count, sqlite3_fullsync_count;
7824af6df11fSdrh   extern int sqlite3_opentemp_count;
782555ef4d97Sdrh   extern int sqlite3_like_count;
7826dd73521bSdrh   extern int sqlite3_xferopt_count;
7827538f570cSdrh   extern int sqlite3_pager_readdb_count;
7828538f570cSdrh   extern int sqlite3_pager_writedb_count;
7829538f570cSdrh   extern int sqlite3_pager_writej_count;
783029bafeabSdanielk1977 #if SQLITE_OS_WIN
7831202cb641Smistachkin   extern LONG volatile sqlite3_os_type;
7832c0929987Sdrh #endif
78338b3d990bSdrh #ifdef SQLITE_DEBUG
78343a00f907Smlcreech   extern int sqlite3WhereTrace;
78353a00f907Smlcreech   extern int sqlite3OSTrace;
7836c74c3334Sdrh   extern int sqlite3WalTrace;
7837549c8b68Sdrh #endif
7838549c8b68Sdrh #ifdef SQLITE_TEST
783933e89035Sdanielk1977 #ifdef SQLITE_ENABLE_FTS3
784033e89035Sdanielk1977   extern int sqlite3_fts3_enable_parentheses;
784133e89035Sdanielk1977 #endif
784248083ceeSdrh #endif
784386fb6e17Sdan #if defined(SQLITE_ENABLE_SELECTTRACE)
784486fb6e17Sdan   extern int sqlite3SelectTrace;
784586fb6e17Sdan #endif
7846c2eef3b3Sdrh 
7847c2eef3b3Sdrh   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
7848c2eef3b3Sdrh     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
7849c2eef3b3Sdrh   }
785051e3d8e2Sdanielk1977   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
7851c572ef7fSdanielk1977     Tcl_CreateObjCommand(interp, aObjCmd[i].zName,
7852c572ef7fSdanielk1977         aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
785351e3d8e2Sdanielk1977   }
78546490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_search_count",
78556f8a503dSdanielk1977       (char*)&sqlite3_search_count, TCL_LINK_INT);
78560ff297eaSdan   Tcl_LinkVar(interp, "sqlite_found_count",
78570ff297eaSdan       (char*)&sqlite3_found_count, TCL_LINK_INT);
78586bf89570Sdrh   Tcl_LinkVar(interp, "sqlite_sort_count",
78596bf89570Sdrh       (char*)&sqlite3_sort_count, TCL_LINK_INT);
7860ae7e151aSdrh   Tcl_LinkVar(interp, "sqlite3_max_blobsize",
7861ae7e151aSdrh       (char*)&sqlite3_max_blobsize, TCL_LINK_INT);
786255ef4d97Sdrh   Tcl_LinkVar(interp, "sqlite_like_count",
786355ef4d97Sdrh       (char*)&sqlite3_like_count, TCL_LINK_INT);
78646490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_interrupt_count",
78656f8a503dSdanielk1977       (char*)&sqlite3_interrupt_count, TCL_LINK_INT);
78666490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_open_file_count",
78676f8a503dSdanielk1977       (char*)&sqlite3_open_file_count, TCL_LINK_INT);
78686490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_current_time",
78696f8a503dSdanielk1977       (char*)&sqlite3_current_time, TCL_LINK_INT);
787084a2bf67Sdrh #if SQLITE_OS_UNIX && defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
7871aebf413dSaswift   Tcl_LinkVar(interp, "sqlite_hostid_num",
7872aebf413dSaswift       (char*)&sqlite3_hostid_num, TCL_LINK_INT);
7873aabbed22Spweilbacher #endif
7874dd73521bSdrh   Tcl_LinkVar(interp, "sqlite3_xferopt_count",
7875dd73521bSdrh       (char*)&sqlite3_xferopt_count, TCL_LINK_INT);
7876538f570cSdrh   Tcl_LinkVar(interp, "sqlite3_pager_readdb_count",
7877538f570cSdrh       (char*)&sqlite3_pager_readdb_count, TCL_LINK_INT);
7878538f570cSdrh   Tcl_LinkVar(interp, "sqlite3_pager_writedb_count",
7879538f570cSdrh       (char*)&sqlite3_pager_writedb_count, TCL_LINK_INT);
7880538f570cSdrh   Tcl_LinkVar(interp, "sqlite3_pager_writej_count",
7881538f570cSdrh       (char*)&sqlite3_pager_writej_count, TCL_LINK_INT);
78824b2688abSdanielk1977 #ifndef SQLITE_OMIT_UTF16
78837d9bd4e1Sdrh   Tcl_LinkVar(interp, "unaligned_string_counter",
78847d9bd4e1Sdrh       (char*)&unaligned_string_counter, TCL_LINK_INT);
78854b2688abSdanielk1977 #endif
7886268803a9Sdrh #ifndef SQLITE_OMIT_UTF16
7887268803a9Sdrh   Tcl_LinkVar(interp, "sqlite_last_needed_collation",
7888268803a9Sdrh       (char*)&pzNeededCollation, TCL_LINK_STRING|TCL_LINK_READ_ONLY);
7889268803a9Sdrh #endif
789029bafeabSdanielk1977 #if SQLITE_OS_WIN
7891c0929987Sdrh   Tcl_LinkVar(interp, "sqlite_os_type",
7892202cb641Smistachkin       (char*)&sqlite3_os_type, TCL_LINK_LONG);
7893c0929987Sdrh #endif
7894549c8b68Sdrh #ifdef SQLITE_TEST
78956fa978daSdrh   {
78966fa978daSdrh     static const char *query_plan = "*** OBSOLETE VARIABLE ***";
7897549c8b68Sdrh     Tcl_LinkVar(interp, "sqlite_query_plan",
7898549c8b68Sdrh        (char*)&query_plan, TCL_LINK_STRING|TCL_LINK_READ_ONLY);
78996fa978daSdrh   }
7900549c8b68Sdrh #endif
79018b3d990bSdrh #ifdef SQLITE_DEBUG
790248083ceeSdrh   Tcl_LinkVar(interp, "sqlite_where_trace",
79033a00f907Smlcreech       (char*)&sqlite3WhereTrace, TCL_LINK_INT);
790473be5013Sdrh   Tcl_LinkVar(interp, "sqlite_os_trace",
79053a00f907Smlcreech       (char*)&sqlite3OSTrace, TCL_LINK_INT);
790638e1a279Sdan #ifndef SQLITE_OMIT_WAL
7907c74c3334Sdrh   Tcl_LinkVar(interp, "sqlite_wal_trace",
7908c74c3334Sdrh       (char*)&sqlite3WalTrace, TCL_LINK_INT);
79098b3d990bSdrh #endif
791038e1a279Sdan #endif
7911cbe21be3Sdanielk1977 #ifndef SQLITE_OMIT_DISKIO
7912af6df11fSdrh   Tcl_LinkVar(interp, "sqlite_opentemp_count",
7913af6df11fSdrh       (char*)&sqlite3_opentemp_count, TCL_LINK_INT);
7914cbe21be3Sdanielk1977 #endif
79157c972decSdrh   Tcl_LinkVar(interp, "sqlite_static_bind_value",
79167c972decSdrh       (char*)&sqlite_static_bind_value, TCL_LINK_STRING);
7917f0313813Sdrh   Tcl_LinkVar(interp, "sqlite_static_bind_nbyte",
7918f0313813Sdrh       (char*)&sqlite_static_bind_nbyte, TCL_LINK_INT);
7919ab3f9feaSdrh   Tcl_LinkVar(interp, "sqlite_temp_directory",
7920effd02bcSdrh       (char*)&sqlite3_temp_directory, TCL_LINK_STRING);
7921a112d140Smistachkin   Tcl_LinkVar(interp, "sqlite_data_directory",
7922a112d140Smistachkin       (char*)&sqlite3_data_directory, TCL_LINK_STRING);
79231398ad36Sdrh   Tcl_LinkVar(interp, "bitmask_size",
79241398ad36Sdrh       (char*)&bitmask_size, TCL_LINK_INT|TCL_LINK_READ_ONLY);
79252ab410aaSdrh   Tcl_LinkVar(interp, "longdouble_size",
79262ab410aaSdrh       (char*)&longdouble_size, TCL_LINK_INT|TCL_LINK_READ_ONLY);
7927b851b2c9Sdrh   Tcl_LinkVar(interp, "sqlite_sync_count",
7928b851b2c9Sdrh       (char*)&sqlite3_sync_count, TCL_LINK_INT);
7929b851b2c9Sdrh   Tcl_LinkVar(interp, "sqlite_fullsync_count",
7930b851b2c9Sdrh       (char*)&sqlite3_fullsync_count, TCL_LINK_INT);
793186fb6e17Sdan #if defined(SQLITE_ENABLE_SELECTTRACE)
793286fb6e17Sdan   Tcl_LinkVar(interp, "sqlite3SelectTrace",
793386fb6e17Sdan       (char*)&sqlite3SelectTrace, TCL_LINK_INT);
793486fb6e17Sdan #endif
7935d1fa7bcaSdrh #if defined(SQLITE_ENABLE_FTS3) && defined(SQLITE_TEST)
793633e89035Sdanielk1977   Tcl_LinkVar(interp, "sqlite_fts3_enable_parentheses",
793733e89035Sdanielk1977       (char*)&sqlite3_fts3_enable_parentheses, TCL_LINK_INT);
793833e89035Sdanielk1977 #endif
7939d1bf3512Sdrh   return TCL_OK;
7940d1bf3512Sdrh }
7941