xref: /sqlite-3.40.0/src/test1.c (revision dc5e8c63)
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 */
testHexToInt(int h)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 }
sqlite3TestTextToPtr(const char * z)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 */
get_sqlite_pointer(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])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 */
getDbPointer(Tcl_Interp * interp,const char * zA,sqlite3 ** ppDb)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 */
getWin32Handle(Tcl_Interp * interp,const char * zA,LPHANDLE phFile)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 */
sqlite3TestErrCode(Tcl_Interp * interp,sqlite3 * db,int rc)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 */
getStmtPointer(Tcl_Interp * interp,const char * zArg,sqlite3_stmt ** ppStmt)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 */
sqlite3TestMakePointerStr(Tcl_Interp * interp,char * zPtr,void * p)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 */
exec_printf_cb(void * pArg,int argc,char ** argv,char ** name)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;
io_trace_callback(const char * zFormat,...)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 */
test_io_trace(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)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 */
clang_sanitize_address(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)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 */
test_exec_printf(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)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 */
test_exec_hex(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)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 */
db_enter(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)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 }
db_leave(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)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 */
test_exec(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)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 */
test_exec_nr(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)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 */
test_mprintf_z(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)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 */
test_mprintf_n(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)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 */
test_snprintf_int(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)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 */
test_get_table_printf(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)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 */
test_last_rowid(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)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 */
test_key(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)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 ){
65825d6543dSdrh   return TCL_OK;
65925d6543dSdrh }
66025d6543dSdrh 
66125d6543dSdrh /*
66225d6543dSdrh ** Usage:  sqlite3_rekey DB KEY
66325d6543dSdrh **
66425d6543dSdrh ** Change the codec key.
66525d6543dSdrh */
test_rekey(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)6667617e4a8Smistachkin static int SQLITE_TCLAPI test_rekey(
66725d6543dSdrh   void *NotUsed,
66825d6543dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
66925d6543dSdrh   int argc,              /* Number of arguments */
67025d6543dSdrh   char **argv            /* Text of each argument */
67125d6543dSdrh ){
67225d6543dSdrh   return TCL_OK;
67325d6543dSdrh }
67425d6543dSdrh 
67525d6543dSdrh /*
6766f8a503dSdanielk1977 ** Usage:  sqlite3_close DB
677d1bf3512Sdrh **
6786f8a503dSdanielk1977 ** Closes the database opened by sqlite3_open.
679d1bf3512Sdrh */
sqlite_test_close(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)6807617e4a8Smistachkin static int SQLITE_TCLAPI sqlite_test_close(
681d1bf3512Sdrh   void *NotUsed,
682d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
683d1bf3512Sdrh   int argc,              /* Number of arguments */
684d1bf3512Sdrh   char **argv            /* Text of each argument */
685d1bf3512Sdrh ){
6869bb575fdSdrh   sqlite3 *db;
68796d81f99Sdanielk1977   int rc;
688d1bf3512Sdrh   if( argc!=2 ){
689d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
690d1bf3512Sdrh        " FILENAME\"", 0);
691d1bf3512Sdrh     return TCL_ERROR;
692d1bf3512Sdrh   }
693b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
69496d81f99Sdanielk1977   rc = sqlite3_close(db);
6954f0c5878Sdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
696d1bf3512Sdrh   return TCL_OK;
697d1bf3512Sdrh }
698d1bf3512Sdrh 
699d1bf3512Sdrh /*
700617dc860Sdan ** Usage:  sqlite3_close_v2 DB
701617dc860Sdan **
702617dc860Sdan ** Closes the database opened by sqlite3_open.
703617dc860Sdan */
sqlite_test_close_v2(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)7047617e4a8Smistachkin static int SQLITE_TCLAPI sqlite_test_close_v2(
705617dc860Sdan   void *NotUsed,
706617dc860Sdan   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
707617dc860Sdan   int argc,              /* Number of arguments */
708617dc860Sdan   char **argv            /* Text of each argument */
709617dc860Sdan ){
710617dc860Sdan   sqlite3 *db;
711617dc860Sdan   int rc;
712617dc860Sdan   if( argc!=2 ){
713617dc860Sdan     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
714617dc860Sdan        " FILENAME\"", 0);
715617dc860Sdan     return TCL_ERROR;
716617dc860Sdan   }
717617dc860Sdan   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
718617dc860Sdan   rc = sqlite3_close_v2(db);
719617dc860Sdan   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
720617dc860Sdan   return TCL_OK;
721617dc860Sdan }
722617dc860Sdan 
723617dc860Sdan /*
724c22bd47dSdrh ** Implementation of the x_coalesce() function.
725c22bd47dSdrh ** Return the first argument non-NULL argument.
726c22bd47dSdrh */
t1_ifnullFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)7274f0c5878Sdrh static void t1_ifnullFunc(
7284f0c5878Sdrh   sqlite3_context *context,
7294f0c5878Sdrh   int argc,
7304f0c5878Sdrh   sqlite3_value **argv
7314f0c5878Sdrh ){
732c22bd47dSdrh   int i;
733c22bd47dSdrh   for(i=0; i<argc; i++){
7349c054830Sdrh     if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){
7359310ef23Sdrh       int n = sqlite3_value_bytes(argv[i]);
73603d847eaSdrh       sqlite3_result_text(context, (char*)sqlite3_value_text(argv[i]),
7379310ef23Sdrh           n, SQLITE_TRANSIENT);
738c22bd47dSdrh       break;
739c22bd47dSdrh     }
740c22bd47dSdrh   }
741c22bd47dSdrh }
742c22bd47dSdrh 
743c22bd47dSdrh /*
744f0313813Sdrh ** These are test functions.    hex8() interprets its argument as
745f0313813Sdrh ** UTF8 and returns a hex encoding.  hex16le() interprets its argument
746f0313813Sdrh ** as UTF16le and returns a hex encoding.
747f0313813Sdrh */
hex8Func(sqlite3_context * p,int argc,sqlite3_value ** argv)748f0313813Sdrh static void hex8Func(sqlite3_context *p, int argc, sqlite3_value **argv){
749f0313813Sdrh   const unsigned char *z;
750f0313813Sdrh   int i;
751f0313813Sdrh   char zBuf[200];
752f0313813Sdrh   z = sqlite3_value_text(argv[0]);
753f0313813Sdrh   for(i=0; i<sizeof(zBuf)/2 - 2 && z[i]; i++){
75465545b59Sdrh     sqlite3_snprintf(sizeof(zBuf)-i*2, &zBuf[i*2], "%02x", z[i]);
755f0313813Sdrh   }
756f0313813Sdrh   zBuf[i*2] = 0;
757f0313813Sdrh   sqlite3_result_text(p, (char*)zBuf, -1, SQLITE_TRANSIENT);
758f0313813Sdrh }
759af30469dSdrh #ifndef SQLITE_OMIT_UTF16
hex16Func(sqlite3_context * p,int argc,sqlite3_value ** argv)760f0313813Sdrh static void hex16Func(sqlite3_context *p, int argc, sqlite3_value **argv){
761f0313813Sdrh   const unsigned short int *z;
762f0313813Sdrh   int i;
763f0313813Sdrh   char zBuf[400];
764f0313813Sdrh   z = sqlite3_value_text16(argv[0]);
765f0313813Sdrh   for(i=0; i<sizeof(zBuf)/4 - 4 && z[i]; i++){
76665545b59Sdrh     sqlite3_snprintf(sizeof(zBuf)-i*4, &zBuf[i*4],"%04x", z[i]&0xff);
767f0313813Sdrh   }
768f0313813Sdrh   zBuf[i*4] = 0;
769f0313813Sdrh   sqlite3_result_text(p, (char*)zBuf, -1, SQLITE_TRANSIENT);
770f0313813Sdrh }
771af30469dSdrh #endif
772f0313813Sdrh 
773f0313813Sdrh /*
774d1d9fc33Sdrh ** A structure into which to accumulate text.
775d1d9fc33Sdrh */
776d1d9fc33Sdrh struct dstr {
777d1d9fc33Sdrh   int nAlloc;  /* Space allocated */
778d1d9fc33Sdrh   int nUsed;   /* Space used */
779d1d9fc33Sdrh   char *z;     /* The space */
780d1d9fc33Sdrh };
781d1d9fc33Sdrh 
782d1d9fc33Sdrh /*
783d1d9fc33Sdrh ** Append text to a dstr
784d1d9fc33Sdrh */
dstrAppend(struct dstr * p,const char * z,int divider)785d1d9fc33Sdrh static void dstrAppend(struct dstr *p, const char *z, int divider){
78683cc1392Sdrh   int n = (int)strlen(z);
787d1d9fc33Sdrh   if( p->nUsed + n + 2 > p->nAlloc ){
788d1d9fc33Sdrh     char *zNew;
789d1d9fc33Sdrh     p->nAlloc = p->nAlloc*2 + n + 200;
79017435752Sdrh     zNew = sqlite3_realloc(p->z, p->nAlloc);
791d1d9fc33Sdrh     if( zNew==0 ){
79217435752Sdrh       sqlite3_free(p->z);
793d1d9fc33Sdrh       memset(p, 0, sizeof(*p));
794d1d9fc33Sdrh       return;
795d1d9fc33Sdrh     }
796d1d9fc33Sdrh     p->z = zNew;
797d1d9fc33Sdrh   }
798d1d9fc33Sdrh   if( divider && p->nUsed>0 ){
799d1d9fc33Sdrh     p->z[p->nUsed++] = divider;
800d1d9fc33Sdrh   }
801d1d9fc33Sdrh   memcpy(&p->z[p->nUsed], z, n+1);
802d1d9fc33Sdrh   p->nUsed += n;
803d1d9fc33Sdrh }
804d1d9fc33Sdrh 
805d1d9fc33Sdrh /*
8064adee20fSdanielk1977 ** Invoked for each callback from sqlite3ExecFunc
807d1d9fc33Sdrh */
execFuncCallback(void * pData,int argc,char ** argv,char ** NotUsed)808d1d9fc33Sdrh static int execFuncCallback(void *pData, int argc, char **argv, char **NotUsed){
809d1d9fc33Sdrh   struct dstr *p = (struct dstr*)pData;
810d1d9fc33Sdrh   int i;
811d1d9fc33Sdrh   for(i=0; i<argc; i++){
812d1d9fc33Sdrh     if( argv[i]==0 ){
813d1d9fc33Sdrh       dstrAppend(p, "NULL", ' ');
814d1d9fc33Sdrh     }else{
815d1d9fc33Sdrh       dstrAppend(p, argv[i], ' ');
816d1d9fc33Sdrh     }
817d1d9fc33Sdrh   }
818d1d9fc33Sdrh   return 0;
819d1d9fc33Sdrh }
820d1d9fc33Sdrh 
821d1d9fc33Sdrh /*
822e35ee196Sdanielk1977 ** Implementation of the x_sqlite_exec() function.  This function takes
823c22bd47dSdrh ** a single argument and attempts to execute that argument as SQL code.
8246cbe1f1bSdrh ** This is illegal and should set the SQLITE_MISUSE flag on the database.
825c22bd47dSdrh **
8266f8a503dSdanielk1977 ** 2004-Jan-07:  We have changed this to make it legal to call sqlite3_exec()
827d1d9fc33Sdrh ** from within a function call.
828d1d9fc33Sdrh **
829c22bd47dSdrh ** This routine simulates the effect of having two threads attempt to
830c22bd47dSdrh ** use the same database at the same time.
831c22bd47dSdrh */
sqlite3ExecFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)83251ad0ecdSdanielk1977 static void sqlite3ExecFunc(
8330ae8b831Sdanielk1977   sqlite3_context *context,
83451ad0ecdSdanielk1977   int argc,
83551ad0ecdSdanielk1977   sqlite3_value **argv
83651ad0ecdSdanielk1977 ){
837d1d9fc33Sdrh   struct dstr x;
838d1d9fc33Sdrh   memset(&x, 0, sizeof(x));
8393752785fSdrh   (void)sqlite3_exec((sqlite3*)sqlite3_user_data(context),
84003d847eaSdrh       (char*)sqlite3_value_text(argv[0]),
841d1d9fc33Sdrh       execFuncCallback, &x, 0);
842d8123366Sdanielk1977   sqlite3_result_text(context, x.z, x.nUsed, SQLITE_TRANSIENT);
84317435752Sdrh   sqlite3_free(x.z);
844c22bd47dSdrh }
845c22bd47dSdrh 
846c22bd47dSdrh /*
847d7263927Sdanielk1977 ** Implementation of tkt2213func(), a scalar function that takes exactly
848d7263927Sdanielk1977 ** one argument. It has two interesting features:
849d7263927Sdanielk1977 **
850d7263927Sdanielk1977 ** * It calls sqlite3_value_text() 3 times on the argument sqlite3_value*.
851d7263927Sdanielk1977 **   If the three pointers returned are not the same an SQL error is raised.
852d7263927Sdanielk1977 **
85385b623f2Sdrh ** * Otherwise it returns a copy of the text representation of its
854d7263927Sdanielk1977 **   argument in such a way as the VDBE representation is a Mem* cell
855d7263927Sdanielk1977 **   with the MEM_Term flag clear.
856d7263927Sdanielk1977 **
857d7263927Sdanielk1977 ** Ticket #2213 can therefore be tested by evaluating the following
858d7263927Sdanielk1977 ** SQL expression:
859d7263927Sdanielk1977 **
860d7263927Sdanielk1977 **   tkt2213func(tkt2213func('a string'));
861d7263927Sdanielk1977 */
tkt2213Function(sqlite3_context * context,int argc,sqlite3_value ** argv)862d7263927Sdanielk1977 static void tkt2213Function(
863d7263927Sdanielk1977   sqlite3_context *context,
864d7263927Sdanielk1977   int argc,
865d7263927Sdanielk1977   sqlite3_value **argv
866d7263927Sdanielk1977 ){
867d7263927Sdanielk1977   int nText;
868d7263927Sdanielk1977   unsigned char const *zText1;
869d7263927Sdanielk1977   unsigned char const *zText2;
870d7263927Sdanielk1977   unsigned char const *zText3;
871d7263927Sdanielk1977 
872d7263927Sdanielk1977   nText = sqlite3_value_bytes(argv[0]);
873d7263927Sdanielk1977   zText1 = sqlite3_value_text(argv[0]);
874d7263927Sdanielk1977   zText2 = sqlite3_value_text(argv[0]);
875d7263927Sdanielk1977   zText3 = sqlite3_value_text(argv[0]);
876d7263927Sdanielk1977 
877d7263927Sdanielk1977   if( zText1!=zText2 || zText2!=zText3 ){
878d7263927Sdanielk1977     sqlite3_result_error(context, "tkt2213 is not fixed", -1);
879d7263927Sdanielk1977   }else{
880d7263927Sdanielk1977     char *zCopy = (char *)sqlite3_malloc(nText);
881d7263927Sdanielk1977     memcpy(zCopy, zText1, nText);
882d7263927Sdanielk1977     sqlite3_result_text(context, zCopy, nText, sqlite3_free);
883d7263927Sdanielk1977   }
884d7263927Sdanielk1977 }
885d7263927Sdanielk1977 
886d7263927Sdanielk1977 /*
8879310ef23Sdrh ** The following SQL function takes 4 arguments.  The 2nd and
8889310ef23Sdrh ** 4th argument must be one of these strings:  'text', 'text16',
8899310ef23Sdrh ** or 'blob' corresponding to API functions
8909310ef23Sdrh **
8919310ef23Sdrh **      sqlite3_value_text()
8929310ef23Sdrh **      sqlite3_value_text16()
8939310ef23Sdrh **      sqlite3_value_blob()
8949310ef23Sdrh **
8959310ef23Sdrh ** The third argument is a string, either 'bytes' or 'bytes16' or 'noop',
8969310ef23Sdrh ** corresponding to APIs:
8979310ef23Sdrh **
8989310ef23Sdrh **      sqlite3_value_bytes()
8999310ef23Sdrh **      sqlite3_value_bytes16()
9009310ef23Sdrh **      noop
9019310ef23Sdrh **
9029310ef23Sdrh ** The APIs designated by the 2nd through 4th arguments are applied
9039310ef23Sdrh ** to the first argument in order.  If the pointers returned by the
9049310ef23Sdrh ** second and fourth are different, this routine returns 1.  Otherwise,
9059310ef23Sdrh ** this routine returns 0.
9069310ef23Sdrh **
9079310ef23Sdrh ** This function is used to test to see when returned pointers from
9089310ef23Sdrh ** the _text(), _text16() and _blob() APIs become invalidated.
9099310ef23Sdrh */
ptrChngFunction(sqlite3_context * context,int argc,sqlite3_value ** argv)9109310ef23Sdrh static void ptrChngFunction(
9119310ef23Sdrh   sqlite3_context *context,
9129310ef23Sdrh   int argc,
9139310ef23Sdrh   sqlite3_value **argv
9149310ef23Sdrh ){
9159310ef23Sdrh   const void *p1, *p2;
9169310ef23Sdrh   const char *zCmd;
9179310ef23Sdrh   if( argc!=4 ) return;
9189310ef23Sdrh   zCmd = (const char*)sqlite3_value_text(argv[1]);
9199310ef23Sdrh   if( zCmd==0 ) return;
9209310ef23Sdrh   if( strcmp(zCmd,"text")==0 ){
9219310ef23Sdrh     p1 = (const void*)sqlite3_value_text(argv[0]);
9229310ef23Sdrh #ifndef SQLITE_OMIT_UTF16
9239310ef23Sdrh   }else if( strcmp(zCmd, "text16")==0 ){
9249310ef23Sdrh     p1 = (const void*)sqlite3_value_text16(argv[0]);
9259310ef23Sdrh #endif
9269310ef23Sdrh   }else if( strcmp(zCmd, "blob")==0 ){
9279310ef23Sdrh     p1 = (const void*)sqlite3_value_blob(argv[0]);
9289310ef23Sdrh   }else{
9299310ef23Sdrh     return;
9309310ef23Sdrh   }
9319310ef23Sdrh   zCmd = (const char*)sqlite3_value_text(argv[2]);
9329310ef23Sdrh   if( zCmd==0 ) return;
9339310ef23Sdrh   if( strcmp(zCmd,"bytes")==0 ){
9349310ef23Sdrh     sqlite3_value_bytes(argv[0]);
9359310ef23Sdrh #ifndef SQLITE_OMIT_UTF16
9369310ef23Sdrh   }else if( strcmp(zCmd, "bytes16")==0 ){
9379310ef23Sdrh     sqlite3_value_bytes16(argv[0]);
9389310ef23Sdrh #endif
9399310ef23Sdrh   }else if( strcmp(zCmd, "noop")==0 ){
9409310ef23Sdrh     /* do nothing */
9419310ef23Sdrh   }else{
9429310ef23Sdrh     return;
9439310ef23Sdrh   }
9449310ef23Sdrh   zCmd = (const char*)sqlite3_value_text(argv[3]);
9459310ef23Sdrh   if( zCmd==0 ) return;
9469310ef23Sdrh   if( strcmp(zCmd,"text")==0 ){
9479310ef23Sdrh     p2 = (const void*)sqlite3_value_text(argv[0]);
9489310ef23Sdrh #ifndef SQLITE_OMIT_UTF16
9499310ef23Sdrh   }else if( strcmp(zCmd, "text16")==0 ){
9509310ef23Sdrh     p2 = (const void*)sqlite3_value_text16(argv[0]);
9519310ef23Sdrh #endif
9529310ef23Sdrh   }else if( strcmp(zCmd, "blob")==0 ){
9539310ef23Sdrh     p2 = (const void*)sqlite3_value_blob(argv[0]);
9549310ef23Sdrh   }else{
9559310ef23Sdrh     return;
9569310ef23Sdrh   }
9579310ef23Sdrh   sqlite3_result_int(context, p1!=p2);
9589310ef23Sdrh }
9599310ef23Sdrh 
9604a8ee3dfSdrh /*
9614a8ee3dfSdrh ** This SQL function returns a different answer each time it is called, even if
9624a8ee3dfSdrh ** the arguments are the same.
9634a8ee3dfSdrh */
nondeterministicFunction(sqlite3_context * context,int argc,sqlite3_value ** argv)9644a8ee3dfSdrh static void nondeterministicFunction(
9654a8ee3dfSdrh   sqlite3_context *context,
9664a8ee3dfSdrh   int argc,
9674a8ee3dfSdrh   sqlite3_value **argv
9684a8ee3dfSdrh ){
9694a8ee3dfSdrh   static int cnt = 0;
9704a8ee3dfSdrh   sqlite3_result_int(context, cnt++);
9714a8ee3dfSdrh }
9729310ef23Sdrh 
9739310ef23Sdrh /*
9740c8f4038Sdrh ** This SQL function returns the integer value of its argument as a MEM_IntReal
9750c8f4038Sdrh ** value.
9760c8f4038Sdrh */
intrealFunction(sqlite3_context * context,int argc,sqlite3_value ** argv)9770c8f4038Sdrh static void intrealFunction(
9780c8f4038Sdrh   sqlite3_context *context,
9790c8f4038Sdrh   int argc,
9800c8f4038Sdrh   sqlite3_value **argv
9810c8f4038Sdrh ){
9820c8f4038Sdrh   sqlite3_int64 v = sqlite3_value_int64(argv[0]);
9830c8f4038Sdrh   sqlite3_result_int64(context, v);
9840c8f4038Sdrh   sqlite3_test_control(SQLITE_TESTCTRL_RESULT_INTREAL, context);
9850c8f4038Sdrh }
9860c8f4038Sdrh 
9870c8f4038Sdrh /*
9884a8ee3dfSdrh ** Usage:  sqlite3_create_function DB
989c22bd47dSdrh **
9906f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order
991c22bd47dSdrh ** to create a function named "x_coalesce".  This function does the same thing
992c22bd47dSdrh ** as the "coalesce" function.  This function also registers an SQL function
993e35ee196Sdanielk1977 ** named "x_sqlite_exec" that invokes sqlite3_exec().  Invoking sqlite3_exec()
994c22bd47dSdrh ** in this way is illegal recursion and should raise an SQLITE_MISUSE error.
995c22bd47dSdrh ** The effect is similar to trying to use the same database connection from
996c22bd47dSdrh ** two threads at the same time.
997c22bd47dSdrh **
998c22bd47dSdrh ** The original motivation for this routine was to be able to call the
9996f8a503dSdanielk1977 ** sqlite3_create_function function while a query is in progress in order
1000c22bd47dSdrh ** to test the SQLITE_MISUSE detection logic.
1001c22bd47dSdrh */
test_create_function(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)10027617e4a8Smistachkin static int SQLITE_TCLAPI test_create_function(
1003c22bd47dSdrh   void *NotUsed,
1004c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1005c22bd47dSdrh   int argc,              /* Number of arguments */
1006c22bd47dSdrh   char **argv            /* Text of each argument */
1007c22bd47dSdrh ){
1008c60d0446Sdrh   int rc;
10099bb575fdSdrh   sqlite3 *db;
1010312d6b36Sdanielk1977 
1011c22bd47dSdrh   if( argc!=2 ){
1012c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
10134397de57Sdanielk1977        " DB\"", 0);
1014c22bd47dSdrh     return TCL_ERROR;
1015c22bd47dSdrh   }
1016b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
10174a8ee3dfSdrh   rc = sqlite3_create_function(db, "x_coalesce", -1, SQLITE_UTF8, 0,
10184f0c5878Sdrh         t1_ifnullFunc, 0, 0);
1019235a818eSdrh   if( rc==SQLITE_OK ){
10204a8ee3dfSdrh     rc = sqlite3_create_function(db, "hex8", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC,
10214a8ee3dfSdrh           0, hex8Func, 0, 0);
1022235a818eSdrh   }
1023af30469dSdrh #ifndef SQLITE_OMIT_UTF16
1024235a818eSdrh   if( rc==SQLITE_OK ){
10254a8ee3dfSdrh     rc = sqlite3_create_function(db, "hex16", 1, SQLITE_UTF16 | SQLITE_DETERMINISTIC,
10264a8ee3dfSdrh           0, hex16Func, 0, 0);
1027235a818eSdrh   }
1028af30469dSdrh #endif
1029d7263927Sdanielk1977   if( rc==SQLITE_OK ){
1030d7263927Sdanielk1977     rc = sqlite3_create_function(db, "tkt2213func", 1, SQLITE_ANY, 0,
1031d7263927Sdanielk1977           tkt2213Function, 0, 0);
1032d7263927Sdanielk1977   }
10339310ef23Sdrh   if( rc==SQLITE_OK ){
10349310ef23Sdrh     rc = sqlite3_create_function(db, "pointer_change", 4, SQLITE_ANY, 0,
10359310ef23Sdrh           ptrChngFunction, 0, 0);
10369310ef23Sdrh   }
1037312d6b36Sdanielk1977 
10384a8ee3dfSdrh   /* Functions counter1() and counter2() have the same implementation - they
10394a8ee3dfSdrh   ** both return an ascending integer with each call.  But counter1() is marked
10404a8ee3dfSdrh   ** as non-deterministic and counter2() is marked as deterministic.
10414a8ee3dfSdrh   */
10424a8ee3dfSdrh   if( rc==SQLITE_OK ){
10434a8ee3dfSdrh     rc = sqlite3_create_function(db, "counter1", -1, SQLITE_UTF8,
10444a8ee3dfSdrh           0, nondeterministicFunction, 0, 0);
10454a8ee3dfSdrh   }
10464a8ee3dfSdrh   if( rc==SQLITE_OK ){
10474a8ee3dfSdrh     rc = sqlite3_create_function(db, "counter2", -1, SQLITE_UTF8|SQLITE_DETERMINISTIC,
10484a8ee3dfSdrh           0, nondeterministicFunction, 0, 0);
10494a8ee3dfSdrh   }
10504a8ee3dfSdrh 
10510c8f4038Sdrh   /* The intreal() function converts its argument to an integer and returns
10520c8f4038Sdrh   ** it as a MEM_IntReal.
10530c8f4038Sdrh   */
10540c8f4038Sdrh   if( rc==SQLITE_OK ){
10550c8f4038Sdrh     rc = sqlite3_create_function(db, "intreal", 1, SQLITE_UTF8,
10560c8f4038Sdrh           0, intrealFunction, 0, 0);
10570c8f4038Sdrh   }
10580c8f4038Sdrh 
10595436dc2dSdrh #ifndef SQLITE_OMIT_UTF16
1060312d6b36Sdanielk1977   /* Use the sqlite3_create_function16() API here. Mainly for fun, but also
1061312d6b36Sdanielk1977   ** because it is not tested anywhere else. */
1062c60d0446Sdrh   if( rc==SQLITE_OK ){
1063eee4c8caSdrh     const void *zUtf16;
1064576ec6b3Sdanielk1977     sqlite3_value *pVal;
1065f3a65f7eSdrh     sqlite3_mutex_enter(db->mutex);
1066f3a65f7eSdrh     pVal = sqlite3ValueNew(db);
1067b21c8cd4Sdrh     sqlite3ValueSetStr(pVal, -1, "x_sqlite_exec", SQLITE_UTF8, SQLITE_STATIC);
1068a7a8e14bSdanielk1977     zUtf16 = sqlite3ValueText(pVal, SQLITE_UTF16NATIVE);
1069f3a65f7eSdrh     if( db->mallocFailed ){
1070f3a65f7eSdrh       rc = SQLITE_NOMEM;
1071f3a65f7eSdrh     }else{
1072a7a8e14bSdanielk1977       rc = sqlite3_create_function16(db, zUtf16,
1073312d6b36Sdanielk1977                 1, SQLITE_UTF16, db, sqlite3ExecFunc, 0, 0);
1074f3a65f7eSdrh     }
1075312d6b36Sdanielk1977     sqlite3ValueFree(pVal);
1076f3a65f7eSdrh     sqlite3_mutex_leave(db->mutex);
1077c60d0446Sdrh   }
10785436dc2dSdrh #endif
10795436dc2dSdrh 
1080c60d0446Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
10814f0c5878Sdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
1082c22bd47dSdrh   return TCL_OK;
1083c22bd47dSdrh }
1084c22bd47dSdrh 
1085c22bd47dSdrh /*
10868c754a36Sdrh ** Usage:  sqlite3_drop_modules DB ?NAME ...?
10875df84280Sdrh **
10888c754a36Sdrh ** Invoke the sqlite3_drop_modules(D,L) interface on database
10895df84280Sdrh ** connection DB, in order to drop all modules except those named in
10905df84280Sdrh ** the argument.
10915df84280Sdrh */
test_drop_modules(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)10928c754a36Sdrh static int SQLITE_TCLAPI test_drop_modules(
10935df84280Sdrh   void *NotUsed,
10945df84280Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
10955df84280Sdrh   int argc,              /* Number of arguments */
10965df84280Sdrh   char **argv            /* Text of each argument */
10975df84280Sdrh ){
10985df84280Sdrh   sqlite3 *db;
10995df84280Sdrh 
11002999068dSdan   if( argc<2 ){
11015df84280Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
11025df84280Sdrh        " DB\"", 0);
11035df84280Sdrh     return TCL_ERROR;
11045df84280Sdrh   }
11055df84280Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
1106e2b7a769Sdrh #ifndef SQLITE_OMIT_VIRTUALTABLE
11078c754a36Sdrh   sqlite3_drop_modules(db, argc>2 ? (const char**)(argv+2) : 0);
1108e2b7a769Sdrh #endif
11095df84280Sdrh   return TCL_OK;
11105df84280Sdrh }
11115df84280Sdrh 
11125df84280Sdrh /*
1113c22bd47dSdrh ** Routines to implement the x_count() aggregate function.
111490669c1dSdrh **
111590669c1dSdrh ** x_count() counts the number of non-null arguments.  But there are
111690669c1dSdrh ** some twists for testing purposes.
111790669c1dSdrh **
111890669c1dSdrh ** If the argument to x_count() is 40 then a UTF-8 error is reported
111990669c1dSdrh ** on the step function.  If x_count(41) is seen, then a UTF-16 error
112090669c1dSdrh ** is reported on the step function.  If the total count is 42, then
112190669c1dSdrh ** a UTF-8 error is reported on the finalize function.
1122c22bd47dSdrh */
11234f0c5878Sdrh typedef struct t1CountCtx t1CountCtx;
11244f0c5878Sdrh struct t1CountCtx {
1125c22bd47dSdrh   int n;
1126c22bd47dSdrh };
t1CountStep(sqlite3_context * context,int argc,sqlite3_value ** argv)11274f0c5878Sdrh static void t1CountStep(
11284f0c5878Sdrh   sqlite3_context *context,
11294f0c5878Sdrh   int argc,
11304f0c5878Sdrh   sqlite3_value **argv
11314f0c5878Sdrh ){
11324f0c5878Sdrh   t1CountCtx *p;
11334f26d6c4Sdrh   p = sqlite3_aggregate_context(context, sizeof(*p));
11349c054830Sdrh   if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0]) ) && p ){
1135c22bd47dSdrh     p->n++;
1136c22bd47dSdrh   }
113790669c1dSdrh   if( argc>0 ){
113890669c1dSdrh     int v = sqlite3_value_int(argv[0]);
113990669c1dSdrh     if( v==40 ){
114090669c1dSdrh       sqlite3_result_error(context, "value of 40 handed to x_count", -1);
1141a1686c9aSdanielk1977 #ifndef SQLITE_OMIT_UTF16
114290669c1dSdrh     }else if( v==41 ){
114390669c1dSdrh       const char zUtf16ErrMsg[] = { 0, 0x61, 0, 0x62, 0, 0x63, 0, 0, 0};
114490669c1dSdrh       sqlite3_result_error16(context, &zUtf16ErrMsg[1-SQLITE_BIGENDIAN], -1);
1145a1686c9aSdanielk1977 #endif
114690669c1dSdrh     }
114790669c1dSdrh   }
1148c22bd47dSdrh }
t1CountFinalize(sqlite3_context * context)11494f0c5878Sdrh static void t1CountFinalize(sqlite3_context *context){
11504f0c5878Sdrh   t1CountCtx *p;
11514f26d6c4Sdrh   p = sqlite3_aggregate_context(context, sizeof(*p));
115290669c1dSdrh   if( p ){
115390669c1dSdrh     if( p->n==42 ){
115490669c1dSdrh       sqlite3_result_error(context, "x_count totals to 42", -1);
115590669c1dSdrh     }else{
1156c572ef7fSdanielk1977       sqlite3_result_int(context, p ? p->n : 0);
1157c22bd47dSdrh     }
115890669c1dSdrh   }
115990669c1dSdrh }
1160c22bd47dSdrh 
1161c5512882Sdanielk1977 #ifndef SQLITE_OMIT_DEPRECATED
legacyCountStep(sqlite3_context * context,int argc,sqlite3_value ** argv)1162fa18beceSdanielk1977 static void legacyCountStep(
1163fa18beceSdanielk1977   sqlite3_context *context,
1164fa18beceSdanielk1977   int argc,
1165fa18beceSdanielk1977   sqlite3_value **argv
1166fa18beceSdanielk1977 ){
1167fa18beceSdanielk1977   /* no-op */
1168fa18beceSdanielk1977 }
1169eec556d3Sshane 
legacyCountFinalize(sqlite3_context * context)1170fa18beceSdanielk1977 static void legacyCountFinalize(sqlite3_context *context){
1171fa18beceSdanielk1977   sqlite3_result_int(context, sqlite3_aggregate_count(context));
1172fa18beceSdanielk1977 }
1173eec556d3Sshane #endif
1174fa18beceSdanielk1977 
1175c22bd47dSdrh /*
1176fa18beceSdanielk1977 ** Usage:  sqlite3_create_aggregate DB
1177c22bd47dSdrh **
11786f8a503dSdanielk1977 ** Call the sqlite3_create_function API on the given database in order
1179fa18beceSdanielk1977 ** to create a function named "x_count".  This function is similar
1180fa18beceSdanielk1977 ** to the built-in count() function, with a few special quirks
1181fa18beceSdanielk1977 ** for testing the sqlite3_result_error() APIs.
1182c22bd47dSdrh **
1183c22bd47dSdrh ** The original motivation for this routine was to be able to call the
11846f8a503dSdanielk1977 ** sqlite3_create_aggregate function while a query is in progress in order
118590669c1dSdrh ** to test the SQLITE_MISUSE detection logic.  See misuse.test.
118690669c1dSdrh **
118790669c1dSdrh ** This routine was later extended to test the use of sqlite3_result_error()
118890669c1dSdrh ** within aggregate functions.
1189fa18beceSdanielk1977 **
1190fa18beceSdanielk1977 ** Later: It is now also extended to register the aggregate function
1191fa18beceSdanielk1977 ** "legacy_count()" with the supplied database handle. This is used
1192fa18beceSdanielk1977 ** to test the deprecated sqlite3_aggregate_count() API.
1193c22bd47dSdrh */
test_create_aggregate(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)11947617e4a8Smistachkin static int SQLITE_TCLAPI test_create_aggregate(
1195c22bd47dSdrh   void *NotUsed,
1196c22bd47dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1197c22bd47dSdrh   int argc,              /* Number of arguments */
1198c22bd47dSdrh   char **argv            /* Text of each argument */
1199c22bd47dSdrh ){
12009bb575fdSdrh   sqlite3 *db;
1201c60d0446Sdrh   int rc;
1202c22bd47dSdrh   if( argc!=2 ){
1203c22bd47dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1204c22bd47dSdrh        " FILENAME\"", 0);
1205c22bd47dSdrh     return TCL_ERROR;
1206c22bd47dSdrh   }
1207b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
1208c60d0446Sdrh   rc = sqlite3_create_function(db, "x_count", 0, SQLITE_UTF8, 0, 0,
12094f0c5878Sdrh       t1CountStep,t1CountFinalize);
1210c60d0446Sdrh   if( rc==SQLITE_OK ){
1211fa18beceSdanielk1977     rc = sqlite3_create_function(db, "x_count", 1, SQLITE_UTF8, 0, 0,
12124f0c5878Sdrh         t1CountStep,t1CountFinalize);
1213c60d0446Sdrh   }
1214eec556d3Sshane #ifndef SQLITE_OMIT_DEPRECATED
1215fa18beceSdanielk1977   if( rc==SQLITE_OK ){
1216fa18beceSdanielk1977     rc = sqlite3_create_function(db, "legacy_count", 0, SQLITE_ANY, 0, 0,
1217fa18beceSdanielk1977         legacyCountStep, legacyCountFinalize
1218fa18beceSdanielk1977     );
1219fa18beceSdanielk1977   }
1220eec556d3Sshane #endif
1221c60d0446Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
1222fa18beceSdanielk1977   Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
1223c22bd47dSdrh   return TCL_OK;
1224c22bd47dSdrh }
1225c22bd47dSdrh 
1226c22bd47dSdrh 
12273c23a885Sdrh /*
12283c23a885Sdrh ** Usage:  printf TEXT
12293c23a885Sdrh **
12303c23a885Sdrh ** Send output to printf.  Use this rather than puts to merge the output
12313c23a885Sdrh ** in the correct sequence with debugging printfs inserted into C code.
12323c23a885Sdrh ** Puts uses a separate buffer and debugging statements will be out of
12333c23a885Sdrh ** sequence if it is used.
12343c23a885Sdrh */
test_printf(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)12357617e4a8Smistachkin static int SQLITE_TCLAPI test_printf(
12363c23a885Sdrh   void *NotUsed,
12373c23a885Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
12383c23a885Sdrh   int argc,              /* Number of arguments */
12393c23a885Sdrh   char **argv            /* Text of each argument */
12403c23a885Sdrh ){
12413c23a885Sdrh   if( argc!=2 ){
12423c23a885Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
12433c23a885Sdrh        " TEXT\"", 0);
12443c23a885Sdrh     return TCL_ERROR;
12453c23a885Sdrh   }
12463c23a885Sdrh   printf("%s\n", argv[1]);
12473c23a885Sdrh   return TCL_OK;
12483c23a885Sdrh }
12493c23a885Sdrh 
12503c23a885Sdrh 
1251c22bd47dSdrh 
1252c22bd47dSdrh /*
12536f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER
1254d1bf3512Sdrh **
1255d1bf3512Sdrh ** Call mprintf with three integer arguments
1256d1bf3512Sdrh */
sqlite3_mprintf_int(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)12577617e4a8Smistachkin static int SQLITE_TCLAPI sqlite3_mprintf_int(
1258d1bf3512Sdrh   void *NotUsed,
1259d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1260d1bf3512Sdrh   int argc,              /* Number of arguments */
1261d1bf3512Sdrh   char **argv            /* Text of each argument */
1262d1bf3512Sdrh ){
1263d1bf3512Sdrh   int a[3], i;
1264d1bf3512Sdrh   char *z;
1265d1bf3512Sdrh   if( argc!=5 ){
1266d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1267d1bf3512Sdrh        " FORMAT INT INT INT\"", 0);
1268d1bf3512Sdrh     return TCL_ERROR;
1269d1bf3512Sdrh   }
1270d1bf3512Sdrh   for(i=2; i<5; i++){
1271d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
1272d1bf3512Sdrh   }
12736f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]);
1274d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
12753f4fedb2Sdrh   sqlite3_free(z);
1276d1bf3512Sdrh   return TCL_OK;
1277d1bf3512Sdrh }
1278d1bf3512Sdrh 
1279d1bf3512Sdrh /*
1280e9707671Sdrh ** Usage:  sqlite3_mprintf_int64 FORMAT INTEGER INTEGER INTEGER
1281e9707671Sdrh **
1282e9707671Sdrh ** Call mprintf with three 64-bit integer arguments
1283e9707671Sdrh */
sqlite3_mprintf_int64(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)12847617e4a8Smistachkin static int SQLITE_TCLAPI sqlite3_mprintf_int64(
1285e9707671Sdrh   void *NotUsed,
1286e9707671Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1287e9707671Sdrh   int argc,              /* Number of arguments */
1288e9707671Sdrh   char **argv            /* Text of each argument */
1289e9707671Sdrh ){
1290e9707671Sdrh   int i;
1291e9707671Sdrh   sqlite_int64 a[3];
1292e9707671Sdrh   char *z;
1293e9707671Sdrh   if( argc!=5 ){
1294e9707671Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1295e9707671Sdrh        " FORMAT INT INT INT\"", 0);
1296e9707671Sdrh     return TCL_ERROR;
1297e9707671Sdrh   }
1298e9707671Sdrh   for(i=2; i<5; i++){
1299609d5846Sdrh     if( sqlite3Atoi64(argv[i], &a[i-2], sqlite3Strlen30(argv[i]), SQLITE_UTF8) ){
1300e9707671Sdrh       Tcl_AppendResult(interp, "argument is not a valid 64-bit integer", 0);
1301e9707671Sdrh       return TCL_ERROR;
1302e9707671Sdrh     }
1303e9707671Sdrh   }
1304e9707671Sdrh   z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]);
1305e9707671Sdrh   Tcl_AppendResult(interp, z, 0);
1306e9707671Sdrh   sqlite3_free(z);
1307e9707671Sdrh   return TCL_OK;
1308e9707671Sdrh }
1309e9707671Sdrh 
1310e9707671Sdrh /*
1311c5cad1e3Sdrh ** Usage:  sqlite3_mprintf_long FORMAT INTEGER INTEGER INTEGER
1312c5cad1e3Sdrh **
1313c5cad1e3Sdrh ** Call mprintf with three long integer arguments.   This might be the
1314c5cad1e3Sdrh ** same as sqlite3_mprintf_int or sqlite3_mprintf_int64, depending on
1315c5cad1e3Sdrh ** platform.
1316c5cad1e3Sdrh */
sqlite3_mprintf_long(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)13177617e4a8Smistachkin static int SQLITE_TCLAPI sqlite3_mprintf_long(
1318c5cad1e3Sdrh   void *NotUsed,
1319c5cad1e3Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1320c5cad1e3Sdrh   int argc,              /* Number of arguments */
1321c5cad1e3Sdrh   char **argv            /* Text of each argument */
1322c5cad1e3Sdrh ){
1323c5cad1e3Sdrh   int i;
1324c5cad1e3Sdrh   long int a[3];
1325c5cad1e3Sdrh   int b[3];
1326c5cad1e3Sdrh   char *z;
1327c5cad1e3Sdrh   if( argc!=5 ){
1328c5cad1e3Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1329c5cad1e3Sdrh        " FORMAT INT INT INT\"", 0);
1330c5cad1e3Sdrh     return TCL_ERROR;
1331c5cad1e3Sdrh   }
1332c5cad1e3Sdrh   for(i=2; i<5; i++){
1333c5cad1e3Sdrh     if( Tcl_GetInt(interp, argv[i], &b[i-2]) ) return TCL_ERROR;
1334c5cad1e3Sdrh     a[i-2] = (long int)b[i-2];
13357ed0cae2Sdrh     a[i-2] &= (((u64)1)<<(sizeof(int)*8))-1;
1336c5cad1e3Sdrh   }
1337c5cad1e3Sdrh   z = sqlite3_mprintf(argv[1], a[0], a[1], a[2]);
1338c5cad1e3Sdrh   Tcl_AppendResult(interp, z, 0);
1339c5cad1e3Sdrh   sqlite3_free(z);
1340c5cad1e3Sdrh   return TCL_OK;
1341c5cad1e3Sdrh }
1342c5cad1e3Sdrh 
1343c5cad1e3Sdrh /*
13446f8a503dSdanielk1977 ** Usage:  sqlite3_mprintf_str FORMAT INTEGER INTEGER STRING
1345d1bf3512Sdrh **
1346d1bf3512Sdrh ** Call mprintf with two integer arguments and one string argument
1347d1bf3512Sdrh */
sqlite3_mprintf_str(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)13487617e4a8Smistachkin static int SQLITE_TCLAPI sqlite3_mprintf_str(
1349d1bf3512Sdrh   void *NotUsed,
1350d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1351d1bf3512Sdrh   int argc,              /* Number of arguments */
1352d1bf3512Sdrh   char **argv            /* Text of each argument */
1353d1bf3512Sdrh ){
1354d1bf3512Sdrh   int a[3], i;
1355d1bf3512Sdrh   char *z;
1356f220b24fSchw   if( argc<4 || argc>5 ){
1357d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1358f220b24fSchw        " FORMAT INT INT ?STRING?\"", 0);
1359d1bf3512Sdrh     return TCL_ERROR;
1360d1bf3512Sdrh   }
1361d1bf3512Sdrh   for(i=2; i<4; i++){
1362d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
1363d1bf3512Sdrh   }
13646f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL);
1365d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
13663f4fedb2Sdrh   sqlite3_free(z);
1367d1bf3512Sdrh   return TCL_OK;
1368d1bf3512Sdrh }
1369d1bf3512Sdrh 
1370d1bf3512Sdrh /*
1371b3738b6cSdrh ** Usage:  sqlite3_snprintf_str INTEGER FORMAT INTEGER INTEGER STRING
1372b3738b6cSdrh **
1373b3738b6cSdrh ** Call mprintf with two integer arguments and one string argument
1374b3738b6cSdrh */
sqlite3_snprintf_str(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)13757617e4a8Smistachkin static int SQLITE_TCLAPI sqlite3_snprintf_str(
1376b3738b6cSdrh   void *NotUsed,
1377b3738b6cSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1378b3738b6cSdrh   int argc,              /* Number of arguments */
1379b3738b6cSdrh   char **argv            /* Text of each argument */
1380b3738b6cSdrh ){
1381b3738b6cSdrh   int a[3], i;
1382b3738b6cSdrh   int n;
1383b3738b6cSdrh   char *z;
1384b3738b6cSdrh   if( argc<5 || argc>6 ){
1385b3738b6cSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1386b3738b6cSdrh        " INT FORMAT INT INT ?STRING?\"", 0);
1387b3738b6cSdrh     return TCL_ERROR;
1388b3738b6cSdrh   }
1389b3738b6cSdrh   if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
1390b3738b6cSdrh   if( n<0 ){
1391b3738b6cSdrh     Tcl_AppendResult(interp, "N must be non-negative", 0);
1392b3738b6cSdrh     return TCL_ERROR;
1393b3738b6cSdrh   }
1394b3738b6cSdrh   for(i=3; i<5; i++){
1395b3738b6cSdrh     if( Tcl_GetInt(interp, argv[i], &a[i-3]) ) return TCL_ERROR;
1396b3738b6cSdrh   }
1397b3738b6cSdrh   z = sqlite3_malloc( n+1 );
1398b3738b6cSdrh   sqlite3_snprintf(n, z, argv[2], a[0], a[1], argc>4 ? argv[5] : NULL);
1399b3738b6cSdrh   Tcl_AppendResult(interp, z, 0);
1400b3738b6cSdrh   sqlite3_free(z);
1401b3738b6cSdrh   return TCL_OK;
1402b3738b6cSdrh }
1403b3738b6cSdrh 
1404b3738b6cSdrh /*
140563782855Sdrh ** Usage:  sqlite3_mprintf_double FORMAT INTEGER INTEGER DOUBLE
1406d1bf3512Sdrh **
1407d1bf3512Sdrh ** Call mprintf with two integer arguments and one double argument
1408d1bf3512Sdrh */
sqlite3_mprintf_double(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)14097617e4a8Smistachkin static int SQLITE_TCLAPI sqlite3_mprintf_double(
1410d1bf3512Sdrh   void *NotUsed,
1411d1bf3512Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1412d1bf3512Sdrh   int argc,              /* Number of arguments */
1413d1bf3512Sdrh   char **argv            /* Text of each argument */
1414d1bf3512Sdrh ){
1415d1bf3512Sdrh   int a[3], i;
1416d1bf3512Sdrh   double r;
1417d1bf3512Sdrh   char *z;
1418d1bf3512Sdrh   if( argc!=5 ){
1419d1bf3512Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
142063782855Sdrh        " FORMAT INT INT DOUBLE\"", 0);
1421d1bf3512Sdrh     return TCL_ERROR;
1422d1bf3512Sdrh   }
1423d1bf3512Sdrh   for(i=2; i<4; i++){
1424d1bf3512Sdrh     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
1425d1bf3512Sdrh   }
1426d1bf3512Sdrh   if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR;
14276f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], a[0], a[1], r);
1428d1bf3512Sdrh   Tcl_AppendResult(interp, z, 0);
14293f4fedb2Sdrh   sqlite3_free(z);
1430d1bf3512Sdrh   return TCL_OK;
1431d1bf3512Sdrh }
1432d1bf3512Sdrh 
1433d1bf3512Sdrh /*
143463782855Sdrh ** Usage:  sqlite3_mprintf_scaled FORMAT DOUBLE DOUBLE
1435b621c237Sdrh **
1436b621c237Sdrh ** Call mprintf with a single double argument which is the product of the
1437b621c237Sdrh ** two arguments given above.  This is used to generate overflow and underflow
1438b621c237Sdrh ** doubles to test that they are converted properly.
1439b621c237Sdrh */
sqlite3_mprintf_scaled(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)14407617e4a8Smistachkin static int SQLITE_TCLAPI sqlite3_mprintf_scaled(
1441b621c237Sdrh   void *NotUsed,
1442b621c237Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1443b621c237Sdrh   int argc,              /* Number of arguments */
1444b621c237Sdrh   char **argv            /* Text of each argument */
1445b621c237Sdrh ){
1446b621c237Sdrh   int i;
1447b621c237Sdrh   double r[2];
1448b621c237Sdrh   char *z;
1449b621c237Sdrh   if( argc!=4 ){
1450b621c237Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1451b621c237Sdrh        " FORMAT DOUBLE DOUBLE\"", 0);
1452b621c237Sdrh     return TCL_ERROR;
1453b621c237Sdrh   }
1454b621c237Sdrh   for(i=2; i<4; i++){
1455b621c237Sdrh     if( Tcl_GetDouble(interp, argv[i], &r[i-2]) ) return TCL_ERROR;
1456b621c237Sdrh   }
14576f8a503dSdanielk1977   z = sqlite3_mprintf(argv[1], r[0]*r[1]);
1458b621c237Sdrh   Tcl_AppendResult(interp, z, 0);
14593f4fedb2Sdrh   sqlite3_free(z);
1460b621c237Sdrh   return TCL_OK;
1461b621c237Sdrh }
1462b621c237Sdrh 
1463b621c237Sdrh /*
1464e29b1a05Sdrh ** Usage:  sqlite3_mprintf_stronly FORMAT STRING
1465e29b1a05Sdrh **
1466e29b1a05Sdrh ** Call mprintf with a single double argument which is the product of the
1467e29b1a05Sdrh ** two arguments given above.  This is used to generate overflow and underflow
1468e29b1a05Sdrh ** doubles to test that they are converted properly.
1469e29b1a05Sdrh */
sqlite3_mprintf_stronly(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)14707617e4a8Smistachkin static int SQLITE_TCLAPI sqlite3_mprintf_stronly(
1471e29b1a05Sdrh   void *NotUsed,
1472e29b1a05Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1473e29b1a05Sdrh   int argc,              /* Number of arguments */
1474e29b1a05Sdrh   char **argv            /* Text of each argument */
1475e29b1a05Sdrh ){
1476e29b1a05Sdrh   char *z;
1477e29b1a05Sdrh   if( argc!=3 ){
1478e29b1a05Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1479e29b1a05Sdrh        " FORMAT STRING\"", 0);
1480e29b1a05Sdrh     return TCL_ERROR;
1481e29b1a05Sdrh   }
1482e29b1a05Sdrh   z = sqlite3_mprintf(argv[1], argv[2]);
1483e29b1a05Sdrh   Tcl_AppendResult(interp, z, 0);
1484e29b1a05Sdrh   sqlite3_free(z);
1485e29b1a05Sdrh   return TCL_OK;
1486e29b1a05Sdrh }
1487e29b1a05Sdrh 
1488e29b1a05Sdrh /*
148963782855Sdrh ** Usage:  sqlite3_mprintf_hexdouble FORMAT HEX
149063782855Sdrh **
149163782855Sdrh ** Call mprintf with a single double argument which is derived from the
149263782855Sdrh ** hexadecimal encoding of an IEEE double.
149363782855Sdrh */
sqlite3_mprintf_hexdouble(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)14947617e4a8Smistachkin static int SQLITE_TCLAPI sqlite3_mprintf_hexdouble(
149563782855Sdrh   void *NotUsed,
149663782855Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
149763782855Sdrh   int argc,              /* Number of arguments */
149863782855Sdrh   char **argv            /* Text of each argument */
149963782855Sdrh ){
150063782855Sdrh   char *z;
150163782855Sdrh   double r;
15025e73db36Sshane   unsigned int x1, x2;
15035e73db36Sshane   sqlite_uint64 d;
150463782855Sdrh   if( argc!=3 ){
150563782855Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
150663782855Sdrh        " FORMAT STRING\"", 0);
150763782855Sdrh     return TCL_ERROR;
150863782855Sdrh   }
150963782855Sdrh   if( sscanf(argv[2], "%08x%08x", &x2, &x1)!=2 ){
151063782855Sdrh     Tcl_AppendResult(interp, "2nd argument should be 16-characters of hex", 0);
151163782855Sdrh     return TCL_ERROR;
151263782855Sdrh   }
151363782855Sdrh   d = x2;
151463782855Sdrh   d = (d<<32) + x1;
151563782855Sdrh   memcpy(&r, &d, sizeof(r));
151663782855Sdrh   z = sqlite3_mprintf(argv[1], r);
151763782855Sdrh   Tcl_AppendResult(interp, z, 0);
151863782855Sdrh   sqlite3_free(z);
151963782855Sdrh   return TCL_OK;
152063782855Sdrh }
152163782855Sdrh 
152263782855Sdrh /*
1523c1def3e0Sdanielk1977 ** Usage: sqlite3_enable_shared_cache ?BOOLEAN?
1524aef0bf64Sdanielk1977 **
1525aef0bf64Sdanielk1977 */
15266f7adc8aSdrh #if !defined(SQLITE_OMIT_SHARED_CACHE)
test_enable_shared(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])15277617e4a8Smistachkin static int SQLITE_TCLAPI test_enable_shared(
152852622828Sdanielk1977   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
1529aef0bf64Sdanielk1977   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1530aef0bf64Sdanielk1977   int objc,              /* Number of arguments */
1531aef0bf64Sdanielk1977   Tcl_Obj *CONST objv[]  /* Command arguments */
1532aef0bf64Sdanielk1977 ){
1533aef0bf64Sdanielk1977   int rc;
1534aef0bf64Sdanielk1977   int enable;
153552622828Sdanielk1977   int ret = 0;
1536aef0bf64Sdanielk1977 
1537c1def3e0Sdanielk1977   if( objc!=2 && objc!=1 ){
1538c1def3e0Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "?BOOLEAN?");
1539aef0bf64Sdanielk1977     return TCL_ERROR;
1540aef0bf64Sdanielk1977   }
1541502b4e00Sdanielk1977   ret = sqlite3GlobalConfig.sharedCacheEnabled;
1542c1def3e0Sdanielk1977 
1543c1def3e0Sdanielk1977   if( objc==2 ){
1544c1def3e0Sdanielk1977     if( Tcl_GetBooleanFromObj(interp, objv[1], &enable) ){
1545c1def3e0Sdanielk1977       return TCL_ERROR;
1546c1def3e0Sdanielk1977     }
15476f7adc8aSdrh     rc = sqlite3_enable_shared_cache(enable);
1548aef0bf64Sdanielk1977     if( rc!=SQLITE_OK ){
1549aef0bf64Sdanielk1977       Tcl_SetResult(interp, (char *)sqlite3ErrStr(rc), TCL_STATIC);
1550aef0bf64Sdanielk1977       return TCL_ERROR;
1551aef0bf64Sdanielk1977     }
1552c1def3e0Sdanielk1977   }
155352622828Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewBooleanObj(ret));
1554aef0bf64Sdanielk1977   return TCL_OK;
1555aef0bf64Sdanielk1977 }
1556aef0bf64Sdanielk1977 #endif
1557aef0bf64Sdanielk1977 
155816a9b836Sdrh 
155916a9b836Sdrh 
1560aef0bf64Sdanielk1977 /*
15614ac285a1Sdrh ** Usage: sqlite3_extended_result_codes   DB    BOOLEAN
15624ac285a1Sdrh **
15634ac285a1Sdrh */
test_extended_result_codes(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])15647617e4a8Smistachkin static int SQLITE_TCLAPI test_extended_result_codes(
15654ac285a1Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
15664ac285a1Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
15674ac285a1Sdrh   int objc,              /* Number of arguments */
15684ac285a1Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
15694ac285a1Sdrh ){
15704ac285a1Sdrh   int enable;
15714ac285a1Sdrh   sqlite3 *db;
15724ac285a1Sdrh 
15734ac285a1Sdrh   if( objc!=3 ){
15744ac285a1Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB BOOLEAN");
15754ac285a1Sdrh     return TCL_ERROR;
15764ac285a1Sdrh   }
15774ac285a1Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
15784ac285a1Sdrh   if( Tcl_GetBooleanFromObj(interp, objv[2], &enable) ) return TCL_ERROR;
15794ac285a1Sdrh   sqlite3_extended_result_codes(db, enable);
15804ac285a1Sdrh   return TCL_OK;
15814ac285a1Sdrh }
15824ac285a1Sdrh 
15834ac285a1Sdrh /*
1584161fb796Sdanielk1977 ** Usage: sqlite3_libversion_number
1585161fb796Sdanielk1977 **
1586161fb796Sdanielk1977 */
test_libversion_number(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])15877617e4a8Smistachkin static int SQLITE_TCLAPI test_libversion_number(
1588161fb796Sdanielk1977   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
1589161fb796Sdanielk1977   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1590161fb796Sdanielk1977   int objc,              /* Number of arguments */
1591161fb796Sdanielk1977   Tcl_Obj *CONST objv[]  /* Command arguments */
1592161fb796Sdanielk1977 ){
1593161fb796Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_libversion_number()));
1594161fb796Sdanielk1977   return TCL_OK;
1595161fb796Sdanielk1977 }
1596161fb796Sdanielk1977 
1597161fb796Sdanielk1977 /*
1598deb802cdSdanielk1977 ** Usage: sqlite3_table_column_metadata DB dbname tblname colname
1599deb802cdSdanielk1977 **
1600deb802cdSdanielk1977 */
test_table_column_metadata(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])16017617e4a8Smistachkin static int SQLITE_TCLAPI test_table_column_metadata(
1602deb802cdSdanielk1977   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
1603deb802cdSdanielk1977   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1604deb802cdSdanielk1977   int objc,              /* Number of arguments */
1605deb802cdSdanielk1977   Tcl_Obj *CONST objv[]  /* Command arguments */
1606deb802cdSdanielk1977 ){
1607deb802cdSdanielk1977   sqlite3 *db;
1608deb802cdSdanielk1977   const char *zDb;
1609deb802cdSdanielk1977   const char *zTbl;
1610deb802cdSdanielk1977   const char *zCol;
1611deb802cdSdanielk1977   int rc;
1612deb802cdSdanielk1977   Tcl_Obj *pRet;
1613deb802cdSdanielk1977 
1614deb802cdSdanielk1977   const char *zDatatype;
1615deb802cdSdanielk1977   const char *zCollseq;
1616deb802cdSdanielk1977   int notnull;
1617deb802cdSdanielk1977   int primarykey;
1618deb802cdSdanielk1977   int autoincrement;
1619deb802cdSdanielk1977 
162045d1b206Sdrh   if( objc!=5 && objc!=4 ){
1621deb802cdSdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "DB dbname tblname colname");
1622deb802cdSdanielk1977     return TCL_ERROR;
1623deb802cdSdanielk1977   }
1624deb802cdSdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1625deb802cdSdanielk1977   zDb = Tcl_GetString(objv[2]);
1626deb802cdSdanielk1977   zTbl = Tcl_GetString(objv[3]);
162745d1b206Sdrh   zCol = objc==5 ? Tcl_GetString(objv[4]) : 0;
1628deb802cdSdanielk1977 
1629deb802cdSdanielk1977   if( strlen(zDb)==0 ) zDb = 0;
1630deb802cdSdanielk1977 
1631deb802cdSdanielk1977   rc = sqlite3_table_column_metadata(db, zDb, zTbl, zCol,
1632deb802cdSdanielk1977       &zDatatype, &zCollseq, &notnull, &primarykey, &autoincrement);
1633deb802cdSdanielk1977 
1634deb802cdSdanielk1977   if( rc!=SQLITE_OK ){
1635deb802cdSdanielk1977     Tcl_AppendResult(interp, sqlite3_errmsg(db), 0);
1636deb802cdSdanielk1977     return TCL_ERROR;
1637deb802cdSdanielk1977   }
1638deb802cdSdanielk1977 
1639deb802cdSdanielk1977   pRet = Tcl_NewObj();
1640deb802cdSdanielk1977   Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zDatatype, -1));
1641deb802cdSdanielk1977   Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zCollseq, -1));
1642deb802cdSdanielk1977   Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(notnull));
1643deb802cdSdanielk1977   Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(primarykey));
1644deb802cdSdanielk1977   Tcl_ListObjAppendElement(0, pRet, Tcl_NewIntObj(autoincrement));
1645deb802cdSdanielk1977   Tcl_SetObjResult(interp, pRet);
1646deb802cdSdanielk1977 
1647deb802cdSdanielk1977   return TCL_OK;
1648deb802cdSdanielk1977 }
1649deb802cdSdanielk1977 
1650dcbb5d3fSdanielk1977 #ifndef SQLITE_OMIT_INCRBLOB
1651dcbb5d3fSdanielk1977 
blobHandleFromObj(Tcl_Interp * interp,Tcl_Obj * pObj,sqlite3_blob ** ppBlob)16527617e4a8Smistachkin static int SQLITE_TCLAPI blobHandleFromObj(
165361c7f59cSdan   Tcl_Interp *interp,
165461c7f59cSdan   Tcl_Obj *pObj,
165561c7f59cSdan   sqlite3_blob **ppBlob
165661c7f59cSdan ){
165761c7f59cSdan   char *z;
165861c7f59cSdan   int n;
165961c7f59cSdan 
166061c7f59cSdan   z = Tcl_GetStringFromObj(pObj, &n);
166161c7f59cSdan   if( n==0 ){
166261c7f59cSdan     *ppBlob = 0;
166361c7f59cSdan   }else{
166461c7f59cSdan     int notUsed;
166561c7f59cSdan     Tcl_Channel channel;
166661c7f59cSdan     ClientData instanceData;
166761c7f59cSdan 
166861c7f59cSdan     channel = Tcl_GetChannel(interp, z, &notUsed);
166961c7f59cSdan     if( !channel ) return TCL_ERROR;
167061c7f59cSdan 
167161c7f59cSdan     Tcl_Flush(channel);
167261c7f59cSdan     Tcl_Seek(channel, 0, SEEK_SET);
167361c7f59cSdan 
167461c7f59cSdan     instanceData = Tcl_GetChannelInstanceData(channel);
167561c7f59cSdan     *ppBlob = *((sqlite3_blob **)instanceData);
167661c7f59cSdan   }
167761c7f59cSdan 
167861c7f59cSdan   return TCL_OK;
167961c7f59cSdan }
168061c7f59cSdan 
test_blob_reopen(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])16817617e4a8Smistachkin static int SQLITE_TCLAPI test_blob_reopen(
16824e76cc36Sdan   ClientData clientData, /* Not used */
16834e76cc36Sdan   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
16844e76cc36Sdan   int objc,              /* Number of arguments */
16854e76cc36Sdan   Tcl_Obj *CONST objv[]  /* Command arguments */
16864e76cc36Sdan ){
16874e76cc36Sdan   Tcl_WideInt iRowid;
16884e76cc36Sdan   sqlite3_blob *pBlob;
16894e76cc36Sdan   int rc;
16904e76cc36Sdan 
16914e76cc36Sdan   if( objc!=3 ){
16924e76cc36Sdan     Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL ROWID");
16934e76cc36Sdan     return TCL_ERROR;
16944e76cc36Sdan   }
16954e76cc36Sdan 
169661c7f59cSdan   if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR;
169761c7f59cSdan   if( Tcl_GetWideIntFromObj(interp, objv[2], &iRowid) ) return TCL_ERROR;
16984e76cc36Sdan 
16994e76cc36Sdan   rc = sqlite3_blob_reopen(pBlob, iRowid);
17004e76cc36Sdan   if( rc!=SQLITE_OK ){
1701e84d8d32Smistachkin     Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
17024e76cc36Sdan   }
17034e76cc36Sdan 
17044e76cc36Sdan   return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR);
17054e76cc36Sdan }
17064e76cc36Sdan 
1707dcbb5d3fSdanielk1977 #endif
1708c2e87a3eSdrh 
1709deb802cdSdanielk1977 /*
1710a393c036Sdanielk1977 ** Usage: sqlite3_create_collation_v2 DB-HANDLE NAME CMP-PROC DEL-PROC
1711a9808b31Sdanielk1977 **
1712a9808b31Sdanielk1977 **   This Tcl proc is used for testing the experimental
1713a393c036Sdanielk1977 **   sqlite3_create_collation_v2() interface.
1714a9808b31Sdanielk1977 */
1715a9808b31Sdanielk1977 struct TestCollationX {
1716a9808b31Sdanielk1977   Tcl_Interp *interp;
1717a9808b31Sdanielk1977   Tcl_Obj *pCmp;
1718a9808b31Sdanielk1977   Tcl_Obj *pDel;
1719a9808b31Sdanielk1977 };
1720a9808b31Sdanielk1977 typedef struct TestCollationX TestCollationX;
testCreateCollationDel(void * pCtx)1721a9808b31Sdanielk1977 static void testCreateCollationDel(void *pCtx){
1722a9808b31Sdanielk1977   TestCollationX *p = (TestCollationX *)pCtx;
1723a9808b31Sdanielk1977 
1724a9808b31Sdanielk1977   int rc = Tcl_EvalObjEx(p->interp, p->pDel, TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL);
1725a9808b31Sdanielk1977   if( rc!=TCL_OK ){
1726a9808b31Sdanielk1977     Tcl_BackgroundError(p->interp);
1727a9808b31Sdanielk1977   }
1728a9808b31Sdanielk1977 
1729a9808b31Sdanielk1977   Tcl_DecrRefCount(p->pCmp);
1730a9808b31Sdanielk1977   Tcl_DecrRefCount(p->pDel);
1731a9808b31Sdanielk1977   sqlite3_free((void *)p);
1732a9808b31Sdanielk1977 }
testCreateCollationCmp(void * pCtx,int nLeft,const void * zLeft,int nRight,const void * zRight)1733a9808b31Sdanielk1977 static int testCreateCollationCmp(
1734a9808b31Sdanielk1977   void *pCtx,
1735a9808b31Sdanielk1977   int nLeft,
1736a9808b31Sdanielk1977   const void *zLeft,
1737a9808b31Sdanielk1977   int nRight,
1738a9808b31Sdanielk1977   const void *zRight
1739a9808b31Sdanielk1977 ){
1740a9808b31Sdanielk1977   TestCollationX *p = (TestCollationX *)pCtx;
1741a9808b31Sdanielk1977   Tcl_Obj *pScript = Tcl_DuplicateObj(p->pCmp);
1742a9808b31Sdanielk1977   int iRes = 0;
1743a9808b31Sdanielk1977 
1744a9808b31Sdanielk1977   Tcl_IncrRefCount(pScript);
1745a9808b31Sdanielk1977   Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj((char *)zLeft, nLeft));
1746a9808b31Sdanielk1977   Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj((char *)zRight,nRight));
1747a9808b31Sdanielk1977 
1748a9808b31Sdanielk1977   if( TCL_OK!=Tcl_EvalObjEx(p->interp, pScript, TCL_EVAL_DIRECT|TCL_EVAL_GLOBAL)
1749a9808b31Sdanielk1977    || TCL_OK!=Tcl_GetIntFromObj(p->interp, Tcl_GetObjResult(p->interp), &iRes)
1750a9808b31Sdanielk1977   ){
1751a9808b31Sdanielk1977     Tcl_BackgroundError(p->interp);
1752a9808b31Sdanielk1977   }
1753a9808b31Sdanielk1977   Tcl_DecrRefCount(pScript);
1754a9808b31Sdanielk1977 
1755a9808b31Sdanielk1977   return iRes;
1756a9808b31Sdanielk1977 }
test_create_collation_v2(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])17577617e4a8Smistachkin static int SQLITE_TCLAPI test_create_collation_v2(
1758a9808b31Sdanielk1977   ClientData clientData, /* Not used */
1759a9808b31Sdanielk1977   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1760a9808b31Sdanielk1977   int objc,              /* Number of arguments */
1761a9808b31Sdanielk1977   Tcl_Obj *CONST objv[]  /* Command arguments */
1762a9808b31Sdanielk1977 ){
1763a9808b31Sdanielk1977   TestCollationX *p;
1764a9808b31Sdanielk1977   sqlite3 *db;
1765d55d57edSdrh   int rc;
1766a9808b31Sdanielk1977 
1767a9808b31Sdanielk1977   if( objc!=5 ){
1768a9808b31Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "DB-HANDLE NAME CMP-PROC DEL-PROC");
1769a9808b31Sdanielk1977     return TCL_ERROR;
1770a9808b31Sdanielk1977   }
1771a9808b31Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1772a9808b31Sdanielk1977 
1773a9808b31Sdanielk1977   p = (TestCollationX *)sqlite3_malloc(sizeof(TestCollationX));
1774a9808b31Sdanielk1977   p->pCmp = objv[3];
1775a9808b31Sdanielk1977   p->pDel = objv[4];
1776a9808b31Sdanielk1977   p->interp = interp;
1777a9808b31Sdanielk1977   Tcl_IncrRefCount(p->pCmp);
1778a9808b31Sdanielk1977   Tcl_IncrRefCount(p->pDel);
1779a9808b31Sdanielk1977 
1780d55d57edSdrh   rc = sqlite3_create_collation_v2(db, Tcl_GetString(objv[2]), 16,
1781d55d57edSdrh       (void *)p, testCreateCollationCmp, testCreateCollationDel
1782d55d57edSdrh   );
1783d55d57edSdrh   if( rc!=SQLITE_MISUSE ){
1784d55d57edSdrh     Tcl_AppendResult(interp, "sqlite3_create_collate_v2() failed to detect "
1785d55d57edSdrh       "an invalid encoding", (char*)0);
1786d55d57edSdrh     return TCL_ERROR;
1787d55d57edSdrh   }
1788d55d57edSdrh   rc = sqlite3_create_collation_v2(db, Tcl_GetString(objv[2]), SQLITE_UTF8,
1789a9808b31Sdanielk1977       (void *)p, testCreateCollationCmp, testCreateCollationDel
1790a9808b31Sdanielk1977   );
1791a9808b31Sdanielk1977   return TCL_OK;
1792a9808b31Sdanielk1977 }
1793a9808b31Sdanielk1977 
1794a9808b31Sdanielk1977 /*
1795d2199f0fSdan ** USAGE: sqlite3_create_function_v2 DB NAME NARG ENC ?SWITCHES?
1796d2199f0fSdan **
1797d2199f0fSdan ** Available switches are:
1798d2199f0fSdan **
1799d2199f0fSdan **   -func    SCRIPT
1800d2199f0fSdan **   -step    SCRIPT
1801d2199f0fSdan **   -final   SCRIPT
1802d2199f0fSdan **   -destroy SCRIPT
1803d2199f0fSdan */
1804d2199f0fSdan typedef struct CreateFunctionV2 CreateFunctionV2;
1805d2199f0fSdan struct CreateFunctionV2 {
1806d2199f0fSdan   Tcl_Interp *interp;
1807d2199f0fSdan   Tcl_Obj *pFunc;                 /* Script for function invocation */
1808d2199f0fSdan   Tcl_Obj *pStep;                 /* Script for agg. step invocation */
1809d2199f0fSdan   Tcl_Obj *pFinal;                /* Script for agg. finalization invocation */
1810d2199f0fSdan   Tcl_Obj *pDestroy;              /* Destructor script */
1811d2199f0fSdan };
cf2Func(sqlite3_context * ctx,int nArg,sqlite3_value ** aArg)1812d2199f0fSdan static void cf2Func(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
1813d2199f0fSdan }
cf2Step(sqlite3_context * ctx,int nArg,sqlite3_value ** aArg)1814d2199f0fSdan static void cf2Step(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
1815d2199f0fSdan }
cf2Final(sqlite3_context * ctx)1816d2199f0fSdan static void cf2Final(sqlite3_context *ctx){
1817d2199f0fSdan }
cf2Destroy(void * pUser)1818d2199f0fSdan static void cf2Destroy(void *pUser){
1819d2199f0fSdan   CreateFunctionV2 *p = (CreateFunctionV2 *)pUser;
1820d2199f0fSdan 
1821d2199f0fSdan   if( p->interp && p->pDestroy ){
1822d2199f0fSdan     int rc = Tcl_EvalObjEx(p->interp, p->pDestroy, 0);
1823d2199f0fSdan     if( rc!=TCL_OK ) Tcl_BackgroundError(p->interp);
1824d2199f0fSdan   }
1825d2199f0fSdan 
1826d2199f0fSdan   if( p->pFunc ) Tcl_DecrRefCount(p->pFunc);
1827d2199f0fSdan   if( p->pStep ) Tcl_DecrRefCount(p->pStep);
1828d2199f0fSdan   if( p->pFinal ) Tcl_DecrRefCount(p->pFinal);
1829d2199f0fSdan   if( p->pDestroy ) Tcl_DecrRefCount(p->pDestroy);
1830d2199f0fSdan   sqlite3_free(p);
1831d2199f0fSdan }
test_create_function_v2(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])18327617e4a8Smistachkin static int SQLITE_TCLAPI test_create_function_v2(
1833d2199f0fSdan   ClientData clientData,          /* Not used */
1834d2199f0fSdan   Tcl_Interp *interp,             /* The invoking TCL interpreter */
1835d2199f0fSdan   int objc,                       /* Number of arguments */
1836d2199f0fSdan   Tcl_Obj *CONST objv[]           /* Command arguments */
1837d2199f0fSdan ){
1838d2199f0fSdan   sqlite3 *db;
1839d2199f0fSdan   const char *zFunc;
1840d2199f0fSdan   int nArg;
1841d2199f0fSdan   int enc;
1842d2199f0fSdan   CreateFunctionV2 *p;
1843d2199f0fSdan   int i;
1844d2199f0fSdan   int rc;
1845d2199f0fSdan 
1846d2199f0fSdan   struct EncTable {
1847d2199f0fSdan     const char *zEnc;
1848d2199f0fSdan     int enc;
1849d2199f0fSdan   } aEnc[] = {
1850d2199f0fSdan     {"utf8",    SQLITE_UTF8 },
1851d2199f0fSdan     {"utf16",   SQLITE_UTF16 },
1852d2199f0fSdan     {"utf16le", SQLITE_UTF16LE },
1853d2199f0fSdan     {"utf16be", SQLITE_UTF16BE },
1854d2199f0fSdan     {"any",     SQLITE_ANY },
18559b6a2833Sdan     {"0", 0 },
18569b6a2833Sdan     {0, 0 }
1857d2199f0fSdan   };
1858d2199f0fSdan 
1859d2199f0fSdan   if( objc<5 || (objc%2)==0 ){
1860d2199f0fSdan     Tcl_WrongNumArgs(interp, 1, objv, "DB NAME NARG ENC SWITCHES...");
1861d2199f0fSdan     return TCL_ERROR;
1862d2199f0fSdan   }
1863d2199f0fSdan 
1864d2199f0fSdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
1865d2199f0fSdan   zFunc = Tcl_GetString(objv[2]);
1866d2199f0fSdan   if( Tcl_GetIntFromObj(interp, objv[3], &nArg) ) return TCL_ERROR;
1867d2199f0fSdan   if( Tcl_GetIndexFromObjStruct(interp, objv[4], aEnc, sizeof(aEnc[0]),
1868d2199f0fSdan           "encoding", 0, &enc)
1869d2199f0fSdan   ){
1870d2199f0fSdan     return TCL_ERROR;
1871d2199f0fSdan   }
1872d2199f0fSdan   enc = aEnc[enc].enc;
1873d2199f0fSdan 
1874d2199f0fSdan   p = sqlite3_malloc(sizeof(CreateFunctionV2));
1875d2199f0fSdan   assert( p );
1876d2199f0fSdan   memset(p, 0, sizeof(CreateFunctionV2));
1877d2199f0fSdan   p->interp = interp;
1878d2199f0fSdan 
1879d2199f0fSdan   for(i=5; i<objc; i+=2){
1880d2199f0fSdan     int iSwitch;
1881d2199f0fSdan     const char *azSwitch[] = {"-func", "-step", "-final", "-destroy", 0};
1882d2199f0fSdan     if( Tcl_GetIndexFromObj(interp, objv[i], azSwitch, "switch", 0, &iSwitch) ){
1883d2199f0fSdan       sqlite3_free(p);
1884d2199f0fSdan       return TCL_ERROR;
1885d2199f0fSdan     }
1886d2199f0fSdan 
1887d2199f0fSdan     switch( iSwitch ){
1888d2199f0fSdan       case 0: p->pFunc = objv[i+1];      break;
1889d2199f0fSdan       case 1: p->pStep = objv[i+1];      break;
1890d2199f0fSdan       case 2: p->pFinal = objv[i+1];     break;
1891d2199f0fSdan       case 3: p->pDestroy = objv[i+1];   break;
1892d2199f0fSdan     }
1893d2199f0fSdan   }
1894d2199f0fSdan   if( p->pFunc ) p->pFunc = Tcl_DuplicateObj(p->pFunc);
1895d2199f0fSdan   if( p->pStep ) p->pStep = Tcl_DuplicateObj(p->pStep);
1896d2199f0fSdan   if( p->pFinal ) p->pFinal = Tcl_DuplicateObj(p->pFinal);
1897d2199f0fSdan   if( p->pDestroy ) p->pDestroy = Tcl_DuplicateObj(p->pDestroy);
1898d2199f0fSdan 
1899d2199f0fSdan   if( p->pFunc ) Tcl_IncrRefCount(p->pFunc);
1900d2199f0fSdan   if( p->pStep ) Tcl_IncrRefCount(p->pStep);
1901d2199f0fSdan   if( p->pFinal ) Tcl_IncrRefCount(p->pFinal);
1902d2199f0fSdan   if( p->pDestroy ) Tcl_IncrRefCount(p->pDestroy);
1903d2199f0fSdan 
1904d2199f0fSdan   rc = sqlite3_create_function_v2(db, zFunc, nArg, enc, (void *)p,
1905d2199f0fSdan       (p->pFunc ? cf2Func : 0),
1906d2199f0fSdan       (p->pStep ? cf2Step : 0),
1907d2199f0fSdan       (p->pFinal ? cf2Final : 0),
1908d2199f0fSdan       cf2Destroy
1909d2199f0fSdan   );
1910d2199f0fSdan   if( rc!=SQLITE_OK ){
1911d2199f0fSdan     Tcl_ResetResult(interp);
1912e84d8d32Smistachkin     Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
1913d2199f0fSdan     return TCL_ERROR;
1914d2199f0fSdan   }
1915d2199f0fSdan   return TCL_OK;
1916d2199f0fSdan }
1917d2199f0fSdan 
1918d2199f0fSdan /*
191969e777f3Sdanielk1977 ** Usage: sqlite3_load_extension DB-HANDLE FILE ?PROC?
192069e777f3Sdanielk1977 */
test_load_extension(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])19217617e4a8Smistachkin static int SQLITE_TCLAPI test_load_extension(
192269e777f3Sdanielk1977   ClientData clientData, /* Not used */
192369e777f3Sdanielk1977   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
192469e777f3Sdanielk1977   int objc,              /* Number of arguments */
192569e777f3Sdanielk1977   Tcl_Obj *CONST objv[]  /* Command arguments */
192669e777f3Sdanielk1977 ){
192769e777f3Sdanielk1977   Tcl_CmdInfo cmdInfo;
192869e777f3Sdanielk1977   sqlite3 *db;
192969e777f3Sdanielk1977   int rc;
193069e777f3Sdanielk1977   char *zDb;
193169e777f3Sdanielk1977   char *zFile;
193269e777f3Sdanielk1977   char *zProc = 0;
193369e777f3Sdanielk1977   char *zErr = 0;
193469e777f3Sdanielk1977 
193569e777f3Sdanielk1977   if( objc!=4 && objc!=3 ){
193669e777f3Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "DB-HANDLE FILE ?PROC?");
193769e777f3Sdanielk1977     return TCL_ERROR;
193869e777f3Sdanielk1977   }
193969e777f3Sdanielk1977   zDb = Tcl_GetString(objv[1]);
194069e777f3Sdanielk1977   zFile = Tcl_GetString(objv[2]);
194169e777f3Sdanielk1977   if( objc==4 ){
194269e777f3Sdanielk1977     zProc = Tcl_GetString(objv[3]);
194369e777f3Sdanielk1977   }
194469e777f3Sdanielk1977 
194569e777f3Sdanielk1977   /* Extract the C database handle from the Tcl command name */
194669e777f3Sdanielk1977   if( !Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){
194769e777f3Sdanielk1977     Tcl_AppendResult(interp, "command not found: ", zDb, (char*)0);
194869e777f3Sdanielk1977     return TCL_ERROR;
194969e777f3Sdanielk1977   }
195069e777f3Sdanielk1977   db = ((struct SqliteDb*)cmdInfo.objClientData)->db;
195169e777f3Sdanielk1977   assert(db);
195269e777f3Sdanielk1977 
195369e777f3Sdanielk1977   /* Call the underlying C function. If an error occurs, set rc to
195469e777f3Sdanielk1977   ** TCL_ERROR and load any error string into the interpreter. If no
195569e777f3Sdanielk1977   ** error occurs, set rc to TCL_OK.
195669e777f3Sdanielk1977   */
1957c2e87a3eSdrh #ifdef SQLITE_OMIT_LOAD_EXTENSION
1958c2e87a3eSdrh   rc = SQLITE_ERROR;
1959c2e87a3eSdrh   zErr = sqlite3_mprintf("this build omits sqlite3_load_extension()");
19609493cafeSdrh   (void)zProc;
19619493cafeSdrh   (void)zFile;
1962c2e87a3eSdrh #else
196369e777f3Sdanielk1977   rc = sqlite3_load_extension(db, zFile, zProc, &zErr);
1964c2e87a3eSdrh #endif
196569e777f3Sdanielk1977   if( rc!=SQLITE_OK ){
196669e777f3Sdanielk1977     Tcl_SetResult(interp, zErr ? zErr : "", TCL_VOLATILE);
196769e777f3Sdanielk1977     rc = TCL_ERROR;
196869e777f3Sdanielk1977   }else{
196969e777f3Sdanielk1977     rc = TCL_OK;
197069e777f3Sdanielk1977   }
197169e777f3Sdanielk1977   sqlite3_free(zErr);
197269e777f3Sdanielk1977 
197369e777f3Sdanielk1977   return rc;
197469e777f3Sdanielk1977 }
197569e777f3Sdanielk1977 
197669e777f3Sdanielk1977 /*
1977c2e87a3eSdrh ** Usage: sqlite3_enable_load_extension DB-HANDLE ONOFF
1978c2e87a3eSdrh */
test_enable_load(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])19797617e4a8Smistachkin static int SQLITE_TCLAPI test_enable_load(
1980c2e87a3eSdrh   ClientData clientData, /* Not used */
1981c2e87a3eSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1982c2e87a3eSdrh   int objc,              /* Number of arguments */
1983c2e87a3eSdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
1984c2e87a3eSdrh ){
1985c2e87a3eSdrh   Tcl_CmdInfo cmdInfo;
1986c2e87a3eSdrh   sqlite3 *db;
1987c2e87a3eSdrh   char *zDb;
1988c2e87a3eSdrh   int onoff;
1989c2e87a3eSdrh 
1990c2e87a3eSdrh   if( objc!=3 ){
1991c2e87a3eSdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB-HANDLE ONOFF");
1992c2e87a3eSdrh     return TCL_ERROR;
1993c2e87a3eSdrh   }
1994c2e87a3eSdrh   zDb = Tcl_GetString(objv[1]);
1995c2e87a3eSdrh 
1996c2e87a3eSdrh   /* Extract the C database handle from the Tcl command name */
1997c2e87a3eSdrh   if( !Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){
1998c2e87a3eSdrh     Tcl_AppendResult(interp, "command not found: ", zDb, (char*)0);
1999c2e87a3eSdrh     return TCL_ERROR;
2000c2e87a3eSdrh   }
2001c2e87a3eSdrh   db = ((struct SqliteDb*)cmdInfo.objClientData)->db;
2002c2e87a3eSdrh   assert(db);
2003c2e87a3eSdrh 
2004c2e87a3eSdrh   /* Get the onoff parameter */
2005c2e87a3eSdrh   if( Tcl_GetBooleanFromObj(interp, objv[2], &onoff) ){
2006c2e87a3eSdrh     return TCL_ERROR;
2007c2e87a3eSdrh   }
2008c2e87a3eSdrh 
2009c2e87a3eSdrh #ifdef SQLITE_OMIT_LOAD_EXTENSION
2010c2e87a3eSdrh   Tcl_AppendResult(interp, "this build omits sqlite3_load_extension()");
2011c2e87a3eSdrh   return TCL_ERROR;
2012c2e87a3eSdrh #else
2013c2e87a3eSdrh   sqlite3_enable_load_extension(db, onoff);
2014c2e87a3eSdrh   return TCL_OK;
2015c2e87a3eSdrh #endif
2016c2e87a3eSdrh }
2017c2e87a3eSdrh 
2018c2e87a3eSdrh /*
201928b4e489Sdrh ** Usage:  sqlite_abort
202028b4e489Sdrh **
202128b4e489Sdrh ** Shutdown the process immediately.  This is not a clean shutdown.
202228b4e489Sdrh ** This command is used to test the recoverability of a database in
202328b4e489Sdrh ** the event of a program crash.
202428b4e489Sdrh */
sqlite_abort(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)20257617e4a8Smistachkin static int SQLITE_TCLAPI sqlite_abort(
202628b4e489Sdrh   void *NotUsed,
202728b4e489Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
202828b4e489Sdrh   int argc,              /* Number of arguments */
202928b4e489Sdrh   char **argv            /* Text of each argument */
203028b4e489Sdrh ){
20312ceced15Sshaneh #if defined(_MSC_VER)
20322ceced15Sshaneh   /* We do this, otherwise the test will halt with a popup message
20332ceced15Sshaneh    * that we have to click away before the test will continue.
20342ceced15Sshaneh    */
20352ceced15Sshaneh   _set_abort_behavior( 0, _CALL_REPORTFAULT );
20362ceced15Sshaneh #endif
2037d3f6b81aSdan   exit(255);
203828b4e489Sdrh   assert( interp==0 );   /* This will always fail */
203928b4e489Sdrh   return TCL_OK;
204028b4e489Sdrh }
204128b4e489Sdrh 
204228b4e489Sdrh /*
20436cbe1f1bSdrh ** The following routine is a user-defined SQL function whose purpose
20446cbe1f1bSdrh ** is to test the sqlite_set_result() API.
20456cbe1f1bSdrh */
testFunc(sqlite3_context * context,int argc,sqlite3_value ** argv)20460ae8b831Sdanielk1977 static void testFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
20476cbe1f1bSdrh   while( argc>=2 ){
204803d847eaSdrh     const char *zArg0 = (char*)sqlite3_value_text(argv[0]);
20496d88bad4Sdanielk1977     if( zArg0 ){
20506d88bad4Sdanielk1977       if( 0==sqlite3StrICmp(zArg0, "int") ){
20516d88bad4Sdanielk1977         sqlite3_result_int(context, sqlite3_value_int(argv[1]));
20526d88bad4Sdanielk1977       }else if( sqlite3StrICmp(zArg0,"int64")==0 ){
20536d88bad4Sdanielk1977         sqlite3_result_int64(context, sqlite3_value_int64(argv[1]));
205451ad0ecdSdanielk1977       }else if( sqlite3StrICmp(zArg0,"string")==0 ){
205503d847eaSdrh         sqlite3_result_text(context, (char*)sqlite3_value_text(argv[1]), -1,
2056d8123366Sdanielk1977             SQLITE_TRANSIENT);
205751ad0ecdSdanielk1977       }else if( sqlite3StrICmp(zArg0,"double")==0 ){
20586d88bad4Sdanielk1977         sqlite3_result_double(context, sqlite3_value_double(argv[1]));
20596d88bad4Sdanielk1977       }else if( sqlite3StrICmp(zArg0,"null")==0 ){
20606d88bad4Sdanielk1977         sqlite3_result_null(context);
20616d88bad4Sdanielk1977       }else if( sqlite3StrICmp(zArg0,"value")==0 ){
20626d88bad4Sdanielk1977         sqlite3_result_value(context, argv[sqlite3_value_int(argv[1])]);
20636cbe1f1bSdrh       }else{
20646d88bad4Sdanielk1977         goto error_out;
20656d88bad4Sdanielk1977       }
20666d88bad4Sdanielk1977     }else{
20676d88bad4Sdanielk1977       goto error_out;
20686cbe1f1bSdrh     }
20696cbe1f1bSdrh     argc -= 2;
20706cbe1f1bSdrh     argv += 2;
20716cbe1f1bSdrh   }
20726d88bad4Sdanielk1977   return;
20736d88bad4Sdanielk1977 
20746d88bad4Sdanielk1977 error_out:
20756d88bad4Sdanielk1977   sqlite3_result_error(context,"first argument should be one of: "
20766d88bad4Sdanielk1977       "int int64 string double null value", -1);
20776cbe1f1bSdrh }
20786cbe1f1bSdrh 
20796cbe1f1bSdrh /*
20806cbe1f1bSdrh ** Usage:   sqlite_register_test_function  DB  NAME
20816cbe1f1bSdrh **
20826cbe1f1bSdrh ** Register the test SQL function on the database DB under the name NAME.
20836cbe1f1bSdrh */
test_register_func(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)20847617e4a8Smistachkin static int SQLITE_TCLAPI test_register_func(
20856cbe1f1bSdrh   void *NotUsed,
20866cbe1f1bSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
20876cbe1f1bSdrh   int argc,              /* Number of arguments */
20886cbe1f1bSdrh   char **argv            /* Text of each argument */
20896cbe1f1bSdrh ){
20909bb575fdSdrh   sqlite3 *db;
20916cbe1f1bSdrh   int rc;
20926cbe1f1bSdrh   if( argc!=3 ){
20936cbe1f1bSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
20946cbe1f1bSdrh        " DB FUNCTION-NAME", 0);
20956cbe1f1bSdrh     return TCL_ERROR;
20966cbe1f1bSdrh   }
2097b86ccfb2Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
2098f9d64d2cSdanielk1977   rc = sqlite3_create_function(db, argv[2], -1, SQLITE_UTF8, 0,
2099d8123366Sdanielk1977       testFunc, 0, 0);
21006cbe1f1bSdrh   if( rc!=0 ){
2101f20b21c8Sdanielk1977     Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);
21026cbe1f1bSdrh     return TCL_ERROR;
21036cbe1f1bSdrh   }
2104c60d0446Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
21056cbe1f1bSdrh   return TCL_OK;
21066cbe1f1bSdrh }
21076cbe1f1bSdrh 
21086cbe1f1bSdrh /*
2109106bb236Sdanielk1977 ** Usage:  sqlite3_finalize  STMT
2110b86ccfb2Sdrh **
2111106bb236Sdanielk1977 ** Finalize a statement handle.
2112b86ccfb2Sdrh */
test_finalize(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])21137617e4a8Smistachkin static int SQLITE_TCLAPI test_finalize(
2114106bb236Sdanielk1977   void * clientData,
2115106bb236Sdanielk1977   Tcl_Interp *interp,
2116106bb236Sdanielk1977   int objc,
2117106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
2118b86ccfb2Sdrh ){
2119106bb236Sdanielk1977   sqlite3_stmt *pStmt;
2120b86ccfb2Sdrh   int rc;
2121dddb2f23Sdrh   sqlite3 *db = 0;
2122106bb236Sdanielk1977 
2123106bb236Sdanielk1977   if( objc!=2 ){
2124106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
2125106bb236Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
2126b86ccfb2Sdrh     return TCL_ERROR;
2127b86ccfb2Sdrh   }
2128106bb236Sdanielk1977 
2129106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
2130106bb236Sdanielk1977 
21314397de57Sdanielk1977   if( pStmt ){
2132c60d0446Sdrh     db = StmtToDb(pStmt);
21334397de57Sdanielk1977   }
2134fc57d7bfSdanielk1977   rc = sqlite3_finalize(pStmt);
21354f0c5878Sdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
21364397de57Sdanielk1977   if( db && sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
2137106bb236Sdanielk1977   return TCL_OK;
2138106bb236Sdanielk1977 }
2139106bb236Sdanielk1977 
2140106bb236Sdanielk1977 /*
2141d1d38488Sdrh ** Usage:  sqlite3_stmt_status  STMT  CODE  RESETFLAG
2142d1d38488Sdrh **
2143d1d38488Sdrh ** Get the value of a status counter from a statement.
2144d1d38488Sdrh */
test_stmt_status(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])21457617e4a8Smistachkin static int SQLITE_TCLAPI test_stmt_status(
2146d1d38488Sdrh   void * clientData,
2147d1d38488Sdrh   Tcl_Interp *interp,
2148d1d38488Sdrh   int objc,
2149d1d38488Sdrh   Tcl_Obj *CONST objv[]
2150d1d38488Sdrh ){
2151d1d38488Sdrh   int iValue;
215227b2f053Smistachkin   int i, op = 0, resetFlag;
2153d1d38488Sdrh   const char *zOpName;
2154d1d38488Sdrh   sqlite3_stmt *pStmt;
2155d1d38488Sdrh 
2156d1d38488Sdrh   static const struct {
2157d1d38488Sdrh     const char *zName;
2158d1d38488Sdrh     int op;
2159d1d38488Sdrh   } aOp[] = {
2160d1d38488Sdrh     { "SQLITE_STMTSTATUS_FULLSCAN_STEP",   SQLITE_STMTSTATUS_FULLSCAN_STEP   },
2161d1d38488Sdrh     { "SQLITE_STMTSTATUS_SORT",            SQLITE_STMTSTATUS_SORT            },
2162a21a64ddSdrh     { "SQLITE_STMTSTATUS_AUTOINDEX",       SQLITE_STMTSTATUS_AUTOINDEX       },
2163bf159fa2Sdrh     { "SQLITE_STMTSTATUS_VM_STEP",         SQLITE_STMTSTATUS_VM_STEP         },
216400d11d40Sdrh     { "SQLITE_STMTSTATUS_REPREPARE",       SQLITE_STMTSTATUS_REPREPARE       },
216500d11d40Sdrh     { "SQLITE_STMTSTATUS_RUN",             SQLITE_STMTSTATUS_RUN             },
216600d11d40Sdrh     { "SQLITE_STMTSTATUS_MEMUSED",         SQLITE_STMTSTATUS_MEMUSED         },
2167d1d38488Sdrh   };
2168d1d38488Sdrh   if( objc!=4 ){
2169d1d38488Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "STMT PARAMETER RESETFLAG");
2170d1d38488Sdrh     return TCL_ERROR;
2171d1d38488Sdrh   }
2172d1d38488Sdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
2173d1d38488Sdrh   zOpName = Tcl_GetString(objv[2]);
2174d1d38488Sdrh   for(i=0; i<ArraySize(aOp); i++){
2175d1d38488Sdrh     if( strcmp(aOp[i].zName, zOpName)==0 ){
2176d1d38488Sdrh       op = aOp[i].op;
2177d1d38488Sdrh       break;
2178d1d38488Sdrh     }
2179d1d38488Sdrh   }
2180d1d38488Sdrh   if( i>=ArraySize(aOp) ){
2181d1d38488Sdrh     if( Tcl_GetIntFromObj(interp, objv[2], &op) ) return TCL_ERROR;
2182d1d38488Sdrh   }
2183d1d38488Sdrh   if( Tcl_GetBooleanFromObj(interp, objv[3], &resetFlag) ) return TCL_ERROR;
2184d1d38488Sdrh   iValue = sqlite3_stmt_status(pStmt, op, resetFlag);
2185d1d38488Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(iValue));
2186d1d38488Sdrh   return TCL_OK;
2187d1d38488Sdrh }
2188d1d38488Sdrh 
218904489b6dSdan #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
219004489b6dSdan /*
219104489b6dSdan ** Usage:  sqlite3_stmt_scanstatus STMT IDX
219204489b6dSdan */
test_stmt_scanstatus(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])21937617e4a8Smistachkin static int SQLITE_TCLAPI test_stmt_scanstatus(
219404489b6dSdan   void * clientData,
219504489b6dSdan   Tcl_Interp *interp,
219604489b6dSdan   int objc,
219704489b6dSdan   Tcl_Obj *CONST objv[]
219804489b6dSdan ){
219904489b6dSdan   sqlite3_stmt *pStmt;            /* First argument */
220004489b6dSdan   int idx;                        /* Second argument */
220104489b6dSdan 
220204489b6dSdan   const char *zName;
220304489b6dSdan   const char *zExplain;
220404489b6dSdan   sqlite3_int64 nLoop;
220504489b6dSdan   sqlite3_int64 nVisit;
2206518140edSdrh   double rEst;
220704489b6dSdan   int res;
220804489b6dSdan 
220904489b6dSdan   if( objc!=3 ){
221004489b6dSdan     Tcl_WrongNumArgs(interp, 1, objv, "STMT IDX");
221104489b6dSdan     return TCL_ERROR;
221204489b6dSdan   }
221304489b6dSdan   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
221404489b6dSdan   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
221504489b6dSdan 
2216d1a1c234Sdrh   res = sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NLOOP, (void*)&nLoop);
221704489b6dSdan   if( res==0 ){
221804489b6dSdan     Tcl_Obj *pRet = Tcl_NewObj();
221904489b6dSdan     Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nLoop", -1));
222004489b6dSdan     Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nLoop));
2221d1a1c234Sdrh     sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NVISIT, (void*)&nVisit);
222204489b6dSdan     Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nVisit", -1));
222304489b6dSdan     Tcl_ListObjAppendElement(0, pRet, Tcl_NewWideIntObj(nVisit));
2224518140edSdrh     sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_EST, (void*)&rEst);
222504489b6dSdan     Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("nEst", -1));
2226518140edSdrh     Tcl_ListObjAppendElement(0, pRet, Tcl_NewDoubleObj(rEst));
2227d1a1c234Sdrh     sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_NAME, (void*)&zName);
222804489b6dSdan     Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("zName", -1));
222904489b6dSdan     Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zName, -1));
2230d1a1c234Sdrh     sqlite3_stmt_scanstatus(pStmt, idx, SQLITE_SCANSTAT_EXPLAIN, (void*)&zExplain);
223104489b6dSdan     Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj("zExplain", -1));
223204489b6dSdan     Tcl_ListObjAppendElement(0, pRet, Tcl_NewStringObj(zExplain, -1));
223304489b6dSdan     Tcl_SetObjResult(interp, pRet);
223404489b6dSdan   }else{
223504489b6dSdan     Tcl_ResetResult(interp);
223604489b6dSdan   }
223704489b6dSdan   return TCL_OK;
223804489b6dSdan }
223904489b6dSdan 
224004489b6dSdan /*
224104489b6dSdan ** Usage:  sqlite3_stmt_scanstatus_reset  STMT
224204489b6dSdan */
test_stmt_scanstatus_reset(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])22437617e4a8Smistachkin static int SQLITE_TCLAPI test_stmt_scanstatus_reset(
224404489b6dSdan   void * clientData,
224504489b6dSdan   Tcl_Interp *interp,
224604489b6dSdan   int objc,
224704489b6dSdan   Tcl_Obj *CONST objv[]
224804489b6dSdan ){
224904489b6dSdan   sqlite3_stmt *pStmt;            /* First argument */
225004489b6dSdan   if( objc!=2 ){
225104489b6dSdan     Tcl_WrongNumArgs(interp, 1, objv, "STMT");
225204489b6dSdan     return TCL_ERROR;
225304489b6dSdan   }
225404489b6dSdan   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
225504489b6dSdan   sqlite3_stmt_scanstatus_reset(pStmt);
225604489b6dSdan   return TCL_OK;
225704489b6dSdan }
225804489b6dSdan #endif
225904489b6dSdan 
2260d83f7ca1Sdan #ifdef SQLITE_ENABLE_SQLLOG
2261d83f7ca1Sdan /*
2262d83f7ca1Sdan ** Usage:  sqlite3_config_sqllog
2263d83f7ca1Sdan **
2264d83f7ca1Sdan ** Zero the SQLITE_CONFIG_SQLLOG configuration
2265d83f7ca1Sdan */
test_config_sqllog(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])22667617e4a8Smistachkin static int SQLITE_TCLAPI test_config_sqllog(
2267d83f7ca1Sdan   void * clientData,
2268d83f7ca1Sdan   Tcl_Interp *interp,
2269d83f7ca1Sdan   int objc,
2270d83f7ca1Sdan   Tcl_Obj *CONST objv[]
2271d83f7ca1Sdan ){
2272d83f7ca1Sdan   if( objc!=1 ){
2273d83f7ca1Sdan     Tcl_WrongNumArgs(interp, 1, objv, "");
2274d83f7ca1Sdan     return TCL_ERROR;
2275d83f7ca1Sdan   }
2276d83f7ca1Sdan   sqlite3_config(SQLITE_CONFIG_SQLLOG, 0, 0);
2277d83f7ca1Sdan   return TCL_OK;
2278d83f7ca1Sdan }
2279d83f7ca1Sdan #endif
2280d83f7ca1Sdan 
2281d1d38488Sdrh /*
22822e3a5a81Sdan ** Usage:  sqlite3_config_sorterref
22832e3a5a81Sdan **
22842e3a5a81Sdan ** Set the SQLITE_CONFIG_SORTERREF_SIZE configuration option
22852e3a5a81Sdan */
test_config_sorterref(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])22862e3a5a81Sdan static int SQLITE_TCLAPI test_config_sorterref(
22872e3a5a81Sdan   void * clientData,
22882e3a5a81Sdan   Tcl_Interp *interp,
22892e3a5a81Sdan   int objc,
22902e3a5a81Sdan   Tcl_Obj *CONST objv[]
22912e3a5a81Sdan ){
22922e3a5a81Sdan   int iVal;
22932e3a5a81Sdan   if( objc!=2 ){
22942e3a5a81Sdan     Tcl_WrongNumArgs(interp, 1, objv, "NBYTE");
22952e3a5a81Sdan     return TCL_ERROR;
22962e3a5a81Sdan   }
22972e3a5a81Sdan   if( Tcl_GetIntFromObj(interp, objv[1], &iVal) ) return TCL_ERROR;
22982e3a5a81Sdan   sqlite3_config(SQLITE_CONFIG_SORTERREF_SIZE, iVal);
22992e3a5a81Sdan   return TCL_OK;
23002e3a5a81Sdan }
23012e3a5a81Sdan 
23022e3a5a81Sdan /*
2303e4e416e8Sdan ** Usage: vfs_current_time_int64
2304e4e416e8Sdan **
2305e4e416e8Sdan ** Return the value returned by the default VFS's xCurrentTimeInt64 method.
2306e4e416e8Sdan */
vfsCurrentTimeInt64(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])23077617e4a8Smistachkin static int SQLITE_TCLAPI vfsCurrentTimeInt64(
2308e4e416e8Sdan   void * clientData,
2309e4e416e8Sdan   Tcl_Interp *interp,
2310e4e416e8Sdan   int objc,
2311e4e416e8Sdan   Tcl_Obj *CONST objv[]
2312e4e416e8Sdan ){
2313e4e416e8Sdan   i64 t;
2314e4e416e8Sdan   sqlite3_vfs *pVfs = sqlite3_vfs_find(0);
2315e4e416e8Sdan   if( objc!=1 ){
2316e4e416e8Sdan     Tcl_WrongNumArgs(interp, 1, objv, "");
2317e4e416e8Sdan     return TCL_ERROR;
2318e4e416e8Sdan   }
2319e4e416e8Sdan   pVfs->xCurrentTimeInt64(pVfs, &t);
2320e4e416e8Sdan   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(t));
2321e4e416e8Sdan   return TCL_OK;
2322e4e416e8Sdan }
2323e4e416e8Sdan 
2324ee3b7a27Sdrh #ifdef SQLITE_ENABLE_SNAPSHOT
2325e4e416e8Sdan /*
2326fc1acf33Sdan ** Usage: sqlite3_snapshot_get DB DBNAME
2327fc1acf33Sdan */
test_snapshot_get(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])23287617e4a8Smistachkin static int SQLITE_TCLAPI test_snapshot_get(
2329fc1acf33Sdan   void * clientData,
2330fc1acf33Sdan   Tcl_Interp *interp,
2331fc1acf33Sdan   int objc,
2332fc1acf33Sdan   Tcl_Obj *CONST objv[]
2333fc1acf33Sdan ){
2334fc1acf33Sdan   int rc;
2335fc1acf33Sdan   sqlite3 *db;
2336fc1acf33Sdan   char *zName;
2337fc1acf33Sdan   sqlite3_snapshot *pSnapshot = 0;
2338fc1acf33Sdan 
2339fc1acf33Sdan   if( objc!=3 ){
2340fc1acf33Sdan     Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
2341fc1acf33Sdan     return TCL_ERROR;
2342fc1acf33Sdan   }
2343fc1acf33Sdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
2344fc1acf33Sdan   zName = Tcl_GetString(objv[2]);
2345fc1acf33Sdan 
2346fc1acf33Sdan   rc = sqlite3_snapshot_get(db, zName, &pSnapshot);
2347fc1acf33Sdan   if( rc!=SQLITE_OK ){
2348fc1acf33Sdan     Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
2349fc1acf33Sdan     return TCL_ERROR;
2350fc1acf33Sdan   }else{
2351fc1acf33Sdan     char zBuf[100];
2352fc1acf33Sdan     if( sqlite3TestMakePointerStr(interp, zBuf, pSnapshot) ) return TCL_ERROR;
2353fc1acf33Sdan     Tcl_SetObjResult(interp, Tcl_NewStringObj(zBuf, -1));
2354fc1acf33Sdan   }
2355fc1acf33Sdan   return TCL_OK;
2356fc1acf33Sdan }
2357ee3b7a27Sdrh #endif /* SQLITE_ENABLE_SNAPSHOT */
2358fc1acf33Sdan 
2359ee3b7a27Sdrh #ifdef SQLITE_ENABLE_SNAPSHOT
2360fc1acf33Sdan /*
23611158498dSdan ** Usage: sqlite3_snapshot_recover DB DBNAME
23621158498dSdan */
test_snapshot_recover(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])23631158498dSdan static int SQLITE_TCLAPI test_snapshot_recover(
23641158498dSdan   void * clientData,
23651158498dSdan   Tcl_Interp *interp,
23661158498dSdan   int objc,
23671158498dSdan   Tcl_Obj *CONST objv[]
23681158498dSdan ){
23691158498dSdan   int rc;
23701158498dSdan   sqlite3 *db;
23711158498dSdan   char *zName;
23721158498dSdan 
23731158498dSdan   if( objc!=3 ){
23741158498dSdan     Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
23751158498dSdan     return TCL_ERROR;
23761158498dSdan   }
23771158498dSdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
23781158498dSdan   zName = Tcl_GetString(objv[2]);
23791158498dSdan 
23801158498dSdan   rc = sqlite3_snapshot_recover(db, zName);
23811158498dSdan   if( rc!=SQLITE_OK ){
23821158498dSdan     Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
23831158498dSdan     return TCL_ERROR;
23841158498dSdan   }else{
23851158498dSdan     Tcl_ResetResult(interp);
23861158498dSdan   }
23871158498dSdan   return TCL_OK;
23881158498dSdan }
23891158498dSdan #endif /* SQLITE_ENABLE_SNAPSHOT */
23901158498dSdan 
23911158498dSdan #ifdef SQLITE_ENABLE_SNAPSHOT
23921158498dSdan /*
2393fc1acf33Sdan ** Usage: sqlite3_snapshot_open DB DBNAME SNAPSHOT
2394fc1acf33Sdan */
test_snapshot_open(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])23957617e4a8Smistachkin static int SQLITE_TCLAPI test_snapshot_open(
2396fc1acf33Sdan   void * clientData,
2397fc1acf33Sdan   Tcl_Interp *interp,
2398fc1acf33Sdan   int objc,
2399fc1acf33Sdan   Tcl_Obj *CONST objv[]
2400fc1acf33Sdan ){
2401fc1acf33Sdan   int rc;
2402fc1acf33Sdan   sqlite3 *db;
2403fc1acf33Sdan   char *zName;
2404fc1acf33Sdan   sqlite3_snapshot *pSnapshot;
2405fc1acf33Sdan 
2406fc1acf33Sdan   if( objc!=4 ){
2407fc1acf33Sdan     Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SNAPSHOT");
2408fc1acf33Sdan     return TCL_ERROR;
2409fc1acf33Sdan   }
2410fc1acf33Sdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
2411fc1acf33Sdan   zName = Tcl_GetString(objv[2]);
2412fc1acf33Sdan   pSnapshot = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[3]));
2413fc1acf33Sdan 
2414fc1acf33Sdan   rc = sqlite3_snapshot_open(db, zName, pSnapshot);
2415fc1acf33Sdan   if( rc!=SQLITE_OK ){
2416fc1acf33Sdan     Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
2417fc1acf33Sdan     return TCL_ERROR;
2418fa3d4c19Sdan   }else{
2419fa3d4c19Sdan     Tcl_ResetResult(interp);
2420fc1acf33Sdan   }
2421fc1acf33Sdan   return TCL_OK;
2422fc1acf33Sdan }
2423ee3b7a27Sdrh #endif /* SQLITE_ENABLE_SNAPSHOT */
2424fc1acf33Sdan 
2425ee3b7a27Sdrh #ifdef SQLITE_ENABLE_SNAPSHOT
2426fc1acf33Sdan /*
2427fc1acf33Sdan ** Usage: sqlite3_snapshot_free SNAPSHOT
2428fc1acf33Sdan */
test_snapshot_free(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])24297617e4a8Smistachkin static int SQLITE_TCLAPI test_snapshot_free(
2430fc1acf33Sdan   void * clientData,
2431fc1acf33Sdan   Tcl_Interp *interp,
2432fc1acf33Sdan   int objc,
2433fc1acf33Sdan   Tcl_Obj *CONST objv[]
2434fc1acf33Sdan ){
2435fc1acf33Sdan   sqlite3_snapshot *pSnapshot;
2436fc1acf33Sdan   if( objc!=2 ){
2437fc1acf33Sdan     Tcl_WrongNumArgs(interp, 1, objv, "SNAPSHOT");
2438fc1acf33Sdan     return TCL_ERROR;
2439fc1acf33Sdan   }
2440fc1acf33Sdan   pSnapshot = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
2441fc1acf33Sdan   sqlite3_snapshot_free(pSnapshot);
2442fc1acf33Sdan   return TCL_OK;
2443fc1acf33Sdan }
2444ee3b7a27Sdrh #endif /* SQLITE_ENABLE_SNAPSHOT */
2445fc1acf33Sdan 
2446ad2d5bafSdan #ifdef SQLITE_ENABLE_SNAPSHOT
2447ad2d5bafSdan /*
2448ad2d5bafSdan ** Usage: sqlite3_snapshot_cmp SNAPSHOT1 SNAPSHOT2
2449ad2d5bafSdan */
test_snapshot_cmp(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])24507617e4a8Smistachkin static int SQLITE_TCLAPI test_snapshot_cmp(
2451ad2d5bafSdan   void * clientData,
2452ad2d5bafSdan   Tcl_Interp *interp,
2453ad2d5bafSdan   int objc,
2454ad2d5bafSdan   Tcl_Obj *CONST objv[]
2455ad2d5bafSdan ){
2456ad2d5bafSdan   int res;
2457ad2d5bafSdan   sqlite3_snapshot *p1;
2458ad2d5bafSdan   sqlite3_snapshot *p2;
2459ad2d5bafSdan   if( objc!=3 ){
2460ad2d5bafSdan     Tcl_WrongNumArgs(interp, 1, objv, "SNAPSHOT1 SNAPSHOT2");
2461ad2d5bafSdan     return TCL_ERROR;
2462ad2d5bafSdan   }
2463ad2d5bafSdan   p1 = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
2464ad2d5bafSdan   p2 = (sqlite3_snapshot*)sqlite3TestTextToPtr(Tcl_GetString(objv[2]));
2465ad2d5bafSdan   res = sqlite3_snapshot_cmp(p1, p2);
2466ad2d5bafSdan   Tcl_SetObjResult(interp, Tcl_NewIntObj(res));
2467ad2d5bafSdan   return TCL_OK;
2468ad2d5bafSdan }
2469ad2d5bafSdan #endif /* SQLITE_ENABLE_SNAPSHOT */
2470ad2d5bafSdan 
247125accbcaSdan #ifdef SQLITE_ENABLE_SNAPSHOT
247225accbcaSdan /*
247325accbcaSdan ** Usage: sqlite3_snapshot_get_blob DB DBNAME
247425accbcaSdan */
test_snapshot_get_blob(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])247525accbcaSdan static int SQLITE_TCLAPI test_snapshot_get_blob(
247625accbcaSdan   void * clientData,
247725accbcaSdan   Tcl_Interp *interp,
247825accbcaSdan   int objc,
247925accbcaSdan   Tcl_Obj *CONST objv[]
248025accbcaSdan ){
248125accbcaSdan   int rc;
248225accbcaSdan   sqlite3 *db;
248325accbcaSdan   char *zName;
248425accbcaSdan   sqlite3_snapshot *pSnapshot = 0;
248525accbcaSdan 
248625accbcaSdan   if( objc!=3 ){
248725accbcaSdan     Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
248825accbcaSdan     return TCL_ERROR;
248925accbcaSdan   }
249025accbcaSdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
249125accbcaSdan   zName = Tcl_GetString(objv[2]);
249225accbcaSdan 
249325accbcaSdan   rc = sqlite3_snapshot_get(db, zName, &pSnapshot);
249425accbcaSdan   if( rc!=SQLITE_OK ){
249525accbcaSdan     Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
249625accbcaSdan     return TCL_ERROR;
249725accbcaSdan   }else{
249825accbcaSdan     Tcl_SetObjResult(interp,
249925accbcaSdan         Tcl_NewByteArrayObj((unsigned char*)pSnapshot, sizeof(sqlite3_snapshot))
250025accbcaSdan     );
250125accbcaSdan     sqlite3_snapshot_free(pSnapshot);
250225accbcaSdan   }
250325accbcaSdan   return TCL_OK;
250425accbcaSdan }
250525accbcaSdan #endif /* SQLITE_ENABLE_SNAPSHOT */
250625accbcaSdan 
250725accbcaSdan #ifdef SQLITE_ENABLE_SNAPSHOT
250825accbcaSdan   /*
250925accbcaSdan   ** Usage: sqlite3_snapshot_open_blob DB DBNAME SNAPSHOT
251025accbcaSdan */
test_snapshot_open_blob(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])251125accbcaSdan static int SQLITE_TCLAPI test_snapshot_open_blob(
251225accbcaSdan   void * clientData,
251325accbcaSdan   Tcl_Interp *interp,
251425accbcaSdan   int objc,
251525accbcaSdan   Tcl_Obj *CONST objv[]
251625accbcaSdan ){
251725accbcaSdan   int rc;
251825accbcaSdan   sqlite3 *db;
251925accbcaSdan   char *zName;
252025accbcaSdan   unsigned char *pBlob;
252125accbcaSdan   int nBlob;
252225accbcaSdan 
252325accbcaSdan   if( objc!=4 ){
252425accbcaSdan     Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SNAPSHOT");
252525accbcaSdan     return TCL_ERROR;
252625accbcaSdan   }
252725accbcaSdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
252825accbcaSdan   zName = Tcl_GetString(objv[2]);
252925accbcaSdan   pBlob = Tcl_GetByteArrayFromObj(objv[3], &nBlob);
253025accbcaSdan   if( nBlob!=sizeof(sqlite3_snapshot) ){
253125accbcaSdan     Tcl_AppendResult(interp, "bad SNAPSHOT", 0);
253225accbcaSdan     return TCL_ERROR;
253325accbcaSdan   }
253425accbcaSdan   rc = sqlite3_snapshot_open(db, zName, (sqlite3_snapshot*)pBlob);
253525accbcaSdan   if( rc!=SQLITE_OK ){
253625accbcaSdan     Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
253725accbcaSdan     return TCL_ERROR;
253825accbcaSdan   }
253925accbcaSdan   return TCL_OK;
254025accbcaSdan }
254125accbcaSdan #endif /* SQLITE_ENABLE_SNAPSHOT */
254225accbcaSdan 
254325accbcaSdan #ifdef SQLITE_ENABLE_SNAPSHOT
254425accbcaSdan /*
254525accbcaSdan ** Usage: sqlite3_snapshot_cmp_blob SNAPSHOT1 SNAPSHOT2
254625accbcaSdan */
test_snapshot_cmp_blob(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])254725accbcaSdan static int SQLITE_TCLAPI test_snapshot_cmp_blob(
254825accbcaSdan   void * clientData,
254925accbcaSdan   Tcl_Interp *interp,
255025accbcaSdan   int objc,
255125accbcaSdan   Tcl_Obj *CONST objv[]
255225accbcaSdan ){
255325accbcaSdan   int res;
255425accbcaSdan   unsigned char *p1;
255525accbcaSdan   unsigned char *p2;
255625accbcaSdan   int n1;
255725accbcaSdan   int n2;
255825accbcaSdan 
255925accbcaSdan   if( objc!=3 ){
256025accbcaSdan     Tcl_WrongNumArgs(interp, 1, objv, "SNAPSHOT1 SNAPSHOT2");
256125accbcaSdan     return TCL_ERROR;
256225accbcaSdan   }
256325accbcaSdan 
256425accbcaSdan   p1 = Tcl_GetByteArrayFromObj(objv[1], &n1);
256525accbcaSdan   p2 = Tcl_GetByteArrayFromObj(objv[2], &n2);
256625accbcaSdan 
256725accbcaSdan   if( n1!=sizeof(sqlite3_snapshot) || n1!=n2 ){
256825accbcaSdan     Tcl_AppendResult(interp, "bad SNAPSHOT", 0);
256925accbcaSdan     return TCL_ERROR;
257025accbcaSdan   }
257125accbcaSdan 
257225accbcaSdan   res = sqlite3_snapshot_cmp((sqlite3_snapshot*)p1, (sqlite3_snapshot*)p2);
257325accbcaSdan   Tcl_SetObjResult(interp, Tcl_NewIntObj(res));
257425accbcaSdan   return TCL_OK;
257525accbcaSdan }
257625accbcaSdan #endif /* SQLITE_ENABLE_SNAPSHOT */
257725accbcaSdan 
2578fc1acf33Sdan /*
2579000f95b1Sdan ** Usage: sqlite3_delete_database FILENAME
2580000f95b1Sdan */
2581000f95b1Sdan int sqlite3_delete_database(const char*);   /* in test_delete.c */
test_delete_database(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])2582000f95b1Sdan static int SQLITE_TCLAPI test_delete_database(
2583000f95b1Sdan   void * clientData,
2584000f95b1Sdan   Tcl_Interp *interp,
2585000f95b1Sdan   int objc,
2586000f95b1Sdan   Tcl_Obj *CONST objv[]
2587000f95b1Sdan ){
2588000f95b1Sdan   int rc;
2589000f95b1Sdan   const char *zFile;
2590000f95b1Sdan   if( objc!=2 ){
2591000f95b1Sdan     Tcl_WrongNumArgs(interp, 1, objv, "FILE");
2592000f95b1Sdan     return TCL_ERROR;
2593000f95b1Sdan   }
2594000f95b1Sdan   zFile = (const char*)Tcl_GetString(objv[1]);
2595000f95b1Sdan   rc = sqlite3_delete_database(zFile);
2596000f95b1Sdan 
2597000f95b1Sdan   Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
2598000f95b1Sdan   return TCL_OK;
2599000f95b1Sdan }
2600000f95b1Sdan 
2601000f95b1Sdan /*
26024da30f88Sdan ** Usage: atomic_batch_write PATH
26034da30f88Sdan */
test_atomic_batch_write(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])26044da30f88Sdan static int SQLITE_TCLAPI test_atomic_batch_write(
26054da30f88Sdan   void * clientData,
26064da30f88Sdan   Tcl_Interp *interp,
26074da30f88Sdan   int objc,
26084da30f88Sdan   Tcl_Obj *CONST objv[]
26094da30f88Sdan ){
26104da30f88Sdan   char *zFile = 0;                /* Path to file to test */
26114da30f88Sdan   sqlite3 *db = 0;                /* Database handle */
26124da30f88Sdan   sqlite3_file *pFd = 0;          /* SQLite fd open on zFile */
26134da30f88Sdan   int bRes = 0;                   /* Integer result of this command */
26144da30f88Sdan   int dc = 0;                     /* Device-characteristics mask */
26154da30f88Sdan   int rc;                         /* sqlite3_open() return code */
26164da30f88Sdan 
26174da30f88Sdan   if( objc!=2 ){
26184da30f88Sdan     Tcl_WrongNumArgs(interp, 1, objv, "PATH");
26194da30f88Sdan     return TCL_ERROR;
26204da30f88Sdan   }
26214da30f88Sdan   zFile = Tcl_GetString(objv[1]);
26224da30f88Sdan 
26234da30f88Sdan   rc = sqlite3_open(zFile, &db);
26244da30f88Sdan   if( rc!=SQLITE_OK ){
26254da30f88Sdan     Tcl_AppendResult(interp, sqlite3_errmsg(db), 0);
26264da30f88Sdan     sqlite3_close(db);
26274da30f88Sdan     return TCL_ERROR;
26284da30f88Sdan   }
26294da30f88Sdan 
26304da30f88Sdan   rc = sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void*)&pFd);
26314da30f88Sdan   dc = pFd->pMethods->xDeviceCharacteristics(pFd);
26324da30f88Sdan   if( dc & SQLITE_IOCAP_BATCH_ATOMIC ){
26334da30f88Sdan     bRes = 1;
26344da30f88Sdan   }
26354da30f88Sdan 
26364da30f88Sdan   Tcl_SetObjResult(interp, Tcl_NewIntObj(bRes));
26374da30f88Sdan   sqlite3_close(db);
26384da30f88Sdan   return TCL_OK;
26394da30f88Sdan }
26404da30f88Sdan 
26414da30f88Sdan /*
2642bb5a9c3eSdrh ** Usage:  sqlite3_next_stmt  DB  STMT
2643bb5a9c3eSdrh **
2644bb5a9c3eSdrh ** Return the next statment in sequence after STMT.
2645bb5a9c3eSdrh */
test_next_stmt(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])26467617e4a8Smistachkin static int SQLITE_TCLAPI test_next_stmt(
2647bb5a9c3eSdrh   void * clientData,
2648bb5a9c3eSdrh   Tcl_Interp *interp,
2649bb5a9c3eSdrh   int objc,
2650bb5a9c3eSdrh   Tcl_Obj *CONST objv[]
2651bb5a9c3eSdrh ){
2652bb5a9c3eSdrh   sqlite3_stmt *pStmt;
2653bb5a9c3eSdrh   sqlite3 *db = 0;
2654bb5a9c3eSdrh   char zBuf[50];
2655bb5a9c3eSdrh 
2656bb5a9c3eSdrh   if( objc!=3 ){
2657bb5a9c3eSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
2658bb5a9c3eSdrh         Tcl_GetStringFromObj(objv[0], 0), " DB STMT", 0);
2659bb5a9c3eSdrh     return TCL_ERROR;
2660bb5a9c3eSdrh   }
2661bb5a9c3eSdrh 
2662bb5a9c3eSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
2663bb5a9c3eSdrh   if( getStmtPointer(interp, Tcl_GetString(objv[2]), &pStmt) ) return TCL_ERROR;
2664bb5a9c3eSdrh   pStmt = sqlite3_next_stmt(db, pStmt);
2665bb5a9c3eSdrh   if( pStmt ){
2666bb5a9c3eSdrh     if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
2667bb5a9c3eSdrh     Tcl_AppendResult(interp, zBuf, 0);
2668bb5a9c3eSdrh   }
2669bb5a9c3eSdrh   return TCL_OK;
2670bb5a9c3eSdrh }
2671bb5a9c3eSdrh 
2672f03d9cccSdrh /*
2673f03d9cccSdrh ** Usage:  sqlite3_stmt_readonly  STMT
2674f03d9cccSdrh **
2675f03d9cccSdrh ** Return true if STMT is a NULL pointer or a pointer to a statement
2676f03d9cccSdrh ** that is guaranteed to leave the database unmodified.
2677f03d9cccSdrh */
test_stmt_readonly(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])26787617e4a8Smistachkin static int SQLITE_TCLAPI test_stmt_readonly(
2679f03d9cccSdrh   void * clientData,
2680f03d9cccSdrh   Tcl_Interp *interp,
2681f03d9cccSdrh   int objc,
2682f03d9cccSdrh   Tcl_Obj *CONST objv[]
2683f03d9cccSdrh ){
2684f03d9cccSdrh   sqlite3_stmt *pStmt;
2685f03d9cccSdrh   int rc;
2686f03d9cccSdrh 
2687f03d9cccSdrh   if( objc!=2 ){
2688f03d9cccSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
2689f03d9cccSdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT", 0);
2690f03d9cccSdrh     return TCL_ERROR;
2691f03d9cccSdrh   }
2692f03d9cccSdrh 
2693f03d9cccSdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
2694f03d9cccSdrh   rc = sqlite3_stmt_readonly(pStmt);
2695f03d9cccSdrh   Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc));
2696f03d9cccSdrh   return TCL_OK;
2697f03d9cccSdrh }
2698f03d9cccSdrh 
2699d9495cd0Sdan /*
270039c5c4aeSdrh ** Usage:  sqlite3_stmt_isexplain  STMT
270139c5c4aeSdrh **
270239c5c4aeSdrh ** Return 1, 2, or 0 respectively if STMT is an EXPLAIN statement, an
270339c5c4aeSdrh ** EXPLAIN QUERY PLAN statement or an ordinary statement or NULL pointer.
270439c5c4aeSdrh */
test_stmt_isexplain(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])270539c5c4aeSdrh static int SQLITE_TCLAPI test_stmt_isexplain(
270639c5c4aeSdrh   void * clientData,
270739c5c4aeSdrh   Tcl_Interp *interp,
270839c5c4aeSdrh   int objc,
270939c5c4aeSdrh   Tcl_Obj *CONST objv[]
271039c5c4aeSdrh ){
271139c5c4aeSdrh   sqlite3_stmt *pStmt;
271239c5c4aeSdrh   int rc;
271339c5c4aeSdrh 
271439c5c4aeSdrh   if( objc!=2 ){
271539c5c4aeSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
271639c5c4aeSdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT", 0);
271739c5c4aeSdrh     return TCL_ERROR;
271839c5c4aeSdrh   }
271939c5c4aeSdrh 
272039c5c4aeSdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
272139c5c4aeSdrh   rc = sqlite3_stmt_isexplain(pStmt);
272239c5c4aeSdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
272339c5c4aeSdrh   return TCL_OK;
272439c5c4aeSdrh }
272539c5c4aeSdrh 
272639c5c4aeSdrh /*
27272fb6693eSdrh ** Usage:  sqlite3_stmt_busy  STMT
27282fb6693eSdrh **
27292fb6693eSdrh ** Return true if STMT is a non-NULL pointer to a statement
27302fb6693eSdrh ** that has been stepped but not to completion.
27312fb6693eSdrh */
test_stmt_busy(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])27327617e4a8Smistachkin static int SQLITE_TCLAPI test_stmt_busy(
27332fb6693eSdrh   void * clientData,
27342fb6693eSdrh   Tcl_Interp *interp,
27352fb6693eSdrh   int objc,
27362fb6693eSdrh   Tcl_Obj *CONST objv[]
27372fb6693eSdrh ){
27382fb6693eSdrh   sqlite3_stmt *pStmt;
27392fb6693eSdrh   int rc;
27402fb6693eSdrh 
27412fb6693eSdrh   if( objc!=2 ){
27422fb6693eSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
27432fb6693eSdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT", 0);
27442fb6693eSdrh     return TCL_ERROR;
27452fb6693eSdrh   }
27462fb6693eSdrh 
27472fb6693eSdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
27482fb6693eSdrh   rc = sqlite3_stmt_busy(pStmt);
27492fb6693eSdrh   Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc));
27502fb6693eSdrh   return TCL_OK;
27512fb6693eSdrh }
27522fb6693eSdrh 
27532fb6693eSdrh /*
2754d9495cd0Sdan ** Usage:  uses_stmt_journal  STMT
2755d9495cd0Sdan **
2756d9495cd0Sdan ** Return true if STMT uses a statement journal.
2757d9495cd0Sdan */
uses_stmt_journal(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])27587617e4a8Smistachkin static int SQLITE_TCLAPI uses_stmt_journal(
2759d9495cd0Sdan   void * clientData,
2760d9495cd0Sdan   Tcl_Interp *interp,
2761d9495cd0Sdan   int objc,
2762d9495cd0Sdan   Tcl_Obj *CONST objv[]
2763d9495cd0Sdan ){
2764d9495cd0Sdan   sqlite3_stmt *pStmt;
2765d9495cd0Sdan 
2766d9495cd0Sdan   if( objc!=2 ){
2767d9495cd0Sdan     Tcl_AppendResult(interp, "wrong # args: should be \"",
2768d9495cd0Sdan         Tcl_GetStringFromObj(objv[0], 0), " STMT", 0);
2769d9495cd0Sdan     return TCL_ERROR;
2770d9495cd0Sdan   }
2771d9495cd0Sdan 
2772d9495cd0Sdan   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
2773caffb1a5Sdrh   sqlite3_stmt_readonly(pStmt);
2774d9495cd0Sdan   Tcl_SetObjResult(interp, Tcl_NewBooleanObj(((Vdbe *)pStmt)->usesStmtJournal));
2775d9495cd0Sdan   return TCL_OK;
2776d9495cd0Sdan }
2777d9495cd0Sdan 
2778bb5a9c3eSdrh 
2779bb5a9c3eSdrh /*
2780106bb236Sdanielk1977 ** Usage:  sqlite3_reset  STMT
2781106bb236Sdanielk1977 **
2782261919ccSdanielk1977 ** Reset a statement handle.
2783106bb236Sdanielk1977 */
test_reset(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])27847617e4a8Smistachkin static int SQLITE_TCLAPI test_reset(
2785106bb236Sdanielk1977   void * clientData,
2786106bb236Sdanielk1977   Tcl_Interp *interp,
2787106bb236Sdanielk1977   int objc,
2788106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
2789106bb236Sdanielk1977 ){
2790106bb236Sdanielk1977   sqlite3_stmt *pStmt;
2791106bb236Sdanielk1977   int rc;
2792106bb236Sdanielk1977 
2793106bb236Sdanielk1977   if( objc!=2 ){
2794106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
2795106bb236Sdanielk1977         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
2796106bb236Sdanielk1977     return TCL_ERROR;
2797106bb236Sdanielk1977   }
2798106bb236Sdanielk1977 
2799106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
2800106bb236Sdanielk1977 
2801fc57d7bfSdanielk1977   rc = sqlite3_reset(pStmt);
2802261919ccSdanielk1977   if( pStmt && sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ){
2803261919ccSdanielk1977     return TCL_ERROR;
2804261919ccSdanielk1977   }
28054f0c5878Sdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
2806261919ccSdanielk1977 /*
2807106bb236Sdanielk1977   if( rc ){
2808b86ccfb2Sdrh     return TCL_ERROR;
2809b86ccfb2Sdrh   }
2810261919ccSdanielk1977 */
2811b86ccfb2Sdrh   return TCL_OK;
2812b86ccfb2Sdrh }
2813b86ccfb2Sdrh 
28145a38705eSdrh /*
2815d89bd007Sdrh ** Usage:  sqlite3_expired STMT
2816d89bd007Sdrh **
2817d89bd007Sdrh ** Return TRUE if a recompilation of the statement is recommended.
2818d89bd007Sdrh */
test_expired(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])28197617e4a8Smistachkin static int SQLITE_TCLAPI test_expired(
2820d89bd007Sdrh   void * clientData,
2821d89bd007Sdrh   Tcl_Interp *interp,
2822d89bd007Sdrh   int objc,
2823d89bd007Sdrh   Tcl_Obj *CONST objv[]
2824d89bd007Sdrh ){
2825eec556d3Sshane #ifndef SQLITE_OMIT_DEPRECATED
2826d89bd007Sdrh   sqlite3_stmt *pStmt;
2827d89bd007Sdrh   if( objc!=2 ){
2828d89bd007Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
2829d89bd007Sdrh         Tcl_GetStringFromObj(objv[0], 0), " <STMT>", 0);
2830d89bd007Sdrh     return TCL_ERROR;
2831d89bd007Sdrh   }
2832d89bd007Sdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
2833d89bd007Sdrh   Tcl_SetObjResult(interp, Tcl_NewBooleanObj(sqlite3_expired(pStmt)));
2834eec556d3Sshane #endif
2835d89bd007Sdrh   return TCL_OK;
2836d89bd007Sdrh }
2837d89bd007Sdrh 
2838d89bd007Sdrh /*
2839f8db1bc0Sdrh ** Usage:  sqlite3_transfer_bindings FROMSTMT TOSTMT
2840f8db1bc0Sdrh **
2841f8db1bc0Sdrh ** Transfer all bindings from FROMSTMT over to TOSTMT
2842f8db1bc0Sdrh */
test_transfer_bind(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])28437617e4a8Smistachkin static int SQLITE_TCLAPI test_transfer_bind(
2844f8db1bc0Sdrh   void * clientData,
2845f8db1bc0Sdrh   Tcl_Interp *interp,
2846f8db1bc0Sdrh   int objc,
2847f8db1bc0Sdrh   Tcl_Obj *CONST objv[]
2848f8db1bc0Sdrh ){
2849eec556d3Sshane #ifndef SQLITE_OMIT_DEPRECATED
2850f8db1bc0Sdrh   sqlite3_stmt *pStmt1, *pStmt2;
2851f8db1bc0Sdrh   if( objc!=3 ){
2852f8db1bc0Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
2853f8db1bc0Sdrh         Tcl_GetStringFromObj(objv[0], 0), " FROM-STMT TO-STMT", 0);
2854f8db1bc0Sdrh     return TCL_ERROR;
2855f8db1bc0Sdrh   }
2856f8db1bc0Sdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt1)) return TCL_ERROR;
2857f8db1bc0Sdrh   if( getStmtPointer(interp, Tcl_GetString(objv[2]), &pStmt2)) return TCL_ERROR;
2858f8db1bc0Sdrh   Tcl_SetObjResult(interp,
2859f8db1bc0Sdrh      Tcl_NewIntObj(sqlite3_transfer_bindings(pStmt1,pStmt2)));
2860eec556d3Sshane #endif
2861f8db1bc0Sdrh   return TCL_OK;
2862f8db1bc0Sdrh }
2863f8db1bc0Sdrh 
2864f8db1bc0Sdrh /*
2865fbcd585fSdanielk1977 ** Usage:  sqlite3_changes DB
286650457896Sdrh **
2867fbcd585fSdanielk1977 ** Return the number of changes made to the database by the last SQL
2868fbcd585fSdanielk1977 ** execution.
286950457896Sdrh */
test_changes(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])28707617e4a8Smistachkin static int SQLITE_TCLAPI test_changes(
2871fbcd585fSdanielk1977   void * clientData,
2872fbcd585fSdanielk1977   Tcl_Interp *interp,
2873fbcd585fSdanielk1977   int objc,
2874fbcd585fSdanielk1977   Tcl_Obj *CONST objv[]
2875fbcd585fSdanielk1977 ){
2876fbcd585fSdanielk1977   sqlite3 *db;
2877fbcd585fSdanielk1977   if( objc!=2 ){
2878fbcd585fSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
2879fbcd585fSdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
2880fbcd585fSdanielk1977     return TCL_ERROR;
2881fbcd585fSdanielk1977   }
2882fbcd585fSdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
2883fbcd585fSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_changes(db)));
2884fbcd585fSdanielk1977   return TCL_OK;
2885fbcd585fSdanielk1977 }
288650457896Sdrh 
288750457896Sdrh /*
28887c972decSdrh ** This is the "static_bind_value" that variables are bound to when
28896f8a503dSdanielk1977 ** the FLAG option of sqlite3_bind is "static"
289050457896Sdrh */
28917c972decSdrh static char *sqlite_static_bind_value = 0;
2892f0313813Sdrh static int sqlite_static_bind_nbyte = 0;
28937c972decSdrh 
28947c972decSdrh /*
28956f8a503dSdanielk1977 ** Usage:  sqlite3_bind  VM  IDX  VALUE  FLAGS
28967c972decSdrh **
2897f7b5496eSdrh ** Sets the value of the IDX-th occurrence of "?" in the original SQL
28987c972decSdrh ** string.  VALUE is the new value.  If FLAGS=="null" then VALUE is
28997c972decSdrh ** ignored and the value is set to NULL.  If FLAGS=="static" then
29007c972decSdrh ** the value is set to the value of a static variable named
29017c972decSdrh ** "sqlite_static_bind_value".  If FLAGS=="normal" then a copy
2902bf8aa2a6Sdrh ** of the VALUE is made.  If FLAGS=="blob10" then a VALUE is ignored
2903bf8aa2a6Sdrh ** an a 10-byte blob "abc\000xyz\000pq" is inserted.
29047c972decSdrh */
test_bind(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)29057617e4a8Smistachkin static int SQLITE_TCLAPI test_bind(
290650457896Sdrh   void *NotUsed,
290750457896Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
290850457896Sdrh   int argc,              /* Number of arguments */
290950457896Sdrh   char **argv            /* Text of each argument */
291050457896Sdrh ){
2911fc57d7bfSdanielk1977   sqlite3_stmt *pStmt;
291250457896Sdrh   int rc;
29137c972decSdrh   int idx;
29147c972decSdrh   if( argc!=5 ){
291550457896Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
29167c972decSdrh        " VM IDX VALUE (null|static|normal)\"", 0);
291750457896Sdrh     return TCL_ERROR;
291850457896Sdrh   }
2919fc57d7bfSdanielk1977   if( getStmtPointer(interp, argv[1], &pStmt) ) return TCL_ERROR;
29207c972decSdrh   if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR;
29217c972decSdrh   if( strcmp(argv[4],"null")==0 ){
2922fc57d7bfSdanielk1977     rc = sqlite3_bind_null(pStmt, idx);
29237c972decSdrh   }else if( strcmp(argv[4],"static")==0 ){
2924fc57d7bfSdanielk1977     rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0);
2925f0313813Sdrh   }else if( strcmp(argv[4],"static-nbytes")==0 ){
2926f0313813Sdrh     rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value,
2927f0313813Sdrh                                        sqlite_static_bind_nbyte, 0);
29287c972decSdrh   }else if( strcmp(argv[4],"normal")==0 ){
2929d8123366Sdanielk1977     rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, SQLITE_TRANSIENT);
2930bf8aa2a6Sdrh   }else if( strcmp(argv[4],"blob10")==0 ){
2931bf8aa2a6Sdrh     rc = sqlite3_bind_text(pStmt, idx, "abc\000xyz\000pq", 10, SQLITE_STATIC);
29327c972decSdrh   }else{
29337c972decSdrh     Tcl_AppendResult(interp, "4th argument should be "
29347c972decSdrh         "\"null\" or \"static\" or \"normal\"", 0);
29357c972decSdrh     return TCL_ERROR;
29367c972decSdrh   }
2937c60d0446Sdrh   if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
293850457896Sdrh   if( rc ){
293950457896Sdrh     char zBuf[50];
294065545b59Sdrh     sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc);
2941f20b21c8Sdanielk1977     Tcl_AppendResult(interp, zBuf, sqlite3ErrStr(rc), 0);
294250457896Sdrh     return TCL_ERROR;
294350457896Sdrh   }
294450457896Sdrh   return TCL_OK;
294550457896Sdrh }
294650457896Sdrh 
29475436dc2dSdrh #ifndef SQLITE_OMIT_UTF16
29484e6af134Sdanielk1977 /*
29494e6af134Sdanielk1977 ** Usage: add_test_collate <db ptr> <utf8> <utf16le> <utf16be>
29504e6af134Sdanielk1977 **
29514e6af134Sdanielk1977 ** This function is used to test that SQLite selects the correct collation
29524e6af134Sdanielk1977 ** sequence callback when multiple versions (for different text encodings)
29534e6af134Sdanielk1977 ** are available.
29544e6af134Sdanielk1977 **
29554e6af134Sdanielk1977 ** Calling this routine registers the collation sequence "test_collate"
29564e6af134Sdanielk1977 ** with database handle <db>. The second argument must be a list of three
29574e6af134Sdanielk1977 ** boolean values. If the first is true, then a version of test_collate is
29584e6af134Sdanielk1977 ** registered for UTF-8, if the second is true, a version is registered for
29594e6af134Sdanielk1977 ** UTF-16le, if the third is true, a UTF-16be version is available.
29604e6af134Sdanielk1977 ** Previous versions of test_collate are deleted.
29614e6af134Sdanielk1977 **
29624e6af134Sdanielk1977 ** The collation sequence test_collate is implemented by calling the
29634e6af134Sdanielk1977 ** following TCL script:
29644e6af134Sdanielk1977 **
29654e6af134Sdanielk1977 **   "test_collate <enc> <lhs> <rhs>"
29664e6af134Sdanielk1977 **
29674e6af134Sdanielk1977 ** The <lhs> and <rhs> are the two values being compared, encoded in UTF-8.
29684e6af134Sdanielk1977 ** The <enc> parameter is the encoding of the collation function that
29694e6af134Sdanielk1977 ** SQLite selected to call. The TCL test script implements the
29704e6af134Sdanielk1977 ** "test_collate" proc.
29714e6af134Sdanielk1977 **
297260ec914cSpeter.d.reid ** Note that this will only work with one interpreter at a time, as the
29734e6af134Sdanielk1977 ** interp pointer to use when evaluating the TCL script is stored in
29744e6af134Sdanielk1977 ** pTestCollateInterp.
29754e6af134Sdanielk1977 */
29764e6af134Sdanielk1977 static Tcl_Interp* pTestCollateInterp;
test_collate_func(void * pCtx,int nA,const void * zA,int nB,const void * zB)29774e6af134Sdanielk1977 static int test_collate_func(
29784e6af134Sdanielk1977   void *pCtx,
29794e6af134Sdanielk1977   int nA, const void *zA,
29804e6af134Sdanielk1977   int nB, const void *zB
29814e6af134Sdanielk1977 ){
29824e6af134Sdanielk1977   Tcl_Interp *i = pTestCollateInterp;
2983d2199f0fSdan   int encin = SQLITE_PTR_TO_INT(pCtx);
29844e6af134Sdanielk1977   int res;
29854db38a70Sdrh   int n;
29864e6af134Sdanielk1977 
29874e6af134Sdanielk1977   sqlite3_value *pVal;
29884e6af134Sdanielk1977   Tcl_Obj *pX;
29894e6af134Sdanielk1977 
29904e6af134Sdanielk1977   pX = Tcl_NewStringObj("test_collate", -1);
29914e6af134Sdanielk1977   Tcl_IncrRefCount(pX);
29924e6af134Sdanielk1977 
29934e6af134Sdanielk1977   switch( encin ){
29944e6af134Sdanielk1977     case SQLITE_UTF8:
29954e6af134Sdanielk1977       Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-8",-1));
29964e6af134Sdanielk1977       break;
29974e6af134Sdanielk1977     case SQLITE_UTF16LE:
29984e6af134Sdanielk1977       Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-16LE",-1));
29994e6af134Sdanielk1977       break;
30004e6af134Sdanielk1977     case SQLITE_UTF16BE:
30014e6af134Sdanielk1977       Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj("UTF-16BE",-1));
30024e6af134Sdanielk1977       break;
30034e6af134Sdanielk1977     default:
30044e6af134Sdanielk1977       assert(0);
30054e6af134Sdanielk1977   }
30064e6af134Sdanielk1977 
300702fa4696Sdan   sqlite3BeginBenignMalloc();
30081e536953Sdanielk1977   pVal = sqlite3ValueNew(0);
300902fa4696Sdan   if( pVal ){
3010b21c8cd4Sdrh     sqlite3ValueSetStr(pVal, nA, zA, encin, SQLITE_STATIC);
30114db38a70Sdrh     n = sqlite3_value_bytes(pVal);
301203d847eaSdrh     Tcl_ListObjAppendElement(i,pX,
301303d847eaSdrh         Tcl_NewStringObj((char*)sqlite3_value_text(pVal),n));
3014b21c8cd4Sdrh     sqlite3ValueSetStr(pVal, nB, zB, encin, SQLITE_STATIC);
30154db38a70Sdrh     n = sqlite3_value_bytes(pVal);
301603d847eaSdrh     Tcl_ListObjAppendElement(i,pX,
301703d847eaSdrh         Tcl_NewStringObj((char*)sqlite3_value_text(pVal),n));
30184e6af134Sdanielk1977     sqlite3ValueFree(pVal);
301902fa4696Sdan   }
302002fa4696Sdan   sqlite3EndBenignMalloc();
30214e6af134Sdanielk1977 
30224e6af134Sdanielk1977   Tcl_EvalObjEx(i, pX, 0);
30234e6af134Sdanielk1977   Tcl_DecrRefCount(pX);
30244e6af134Sdanielk1977   Tcl_GetIntFromObj(i, Tcl_GetObjResult(i), &res);
30254e6af134Sdanielk1977   return res;
30264e6af134Sdanielk1977 }
test_collate(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])30277617e4a8Smistachkin static int SQLITE_TCLAPI test_collate(
30284e6af134Sdanielk1977   void * clientData,
30294e6af134Sdanielk1977   Tcl_Interp *interp,
30304e6af134Sdanielk1977   int objc,
30314e6af134Sdanielk1977   Tcl_Obj *CONST objv[]
30324e6af134Sdanielk1977 ){
30334e6af134Sdanielk1977   sqlite3 *db;
30344e6af134Sdanielk1977   int val;
3035312d6b36Sdanielk1977   sqlite3_value *pVal;
3036c60d0446Sdrh   int rc;
30374e6af134Sdanielk1977 
30384e6af134Sdanielk1977   if( objc!=5 ) goto bad_args;
30394e6af134Sdanielk1977   pTestCollateInterp = interp;
30404e6af134Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
30414e6af134Sdanielk1977 
30424e6af134Sdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR;
3043c60d0446Sdrh   rc = sqlite3_create_collation(db, "test_collate", SQLITE_UTF8,
30444e6af134Sdanielk1977           (void *)SQLITE_UTF8, val?test_collate_func:0);
3045c60d0446Sdrh   if( rc==SQLITE_OK ){
3046eee4c8caSdrh     const void *zUtf16;
30474e6af134Sdanielk1977     if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &val) ) return TCL_ERROR;
3048c60d0446Sdrh     rc = sqlite3_create_collation(db, "test_collate", SQLITE_UTF16LE,
30494e6af134Sdanielk1977             (void *)SQLITE_UTF16LE, val?test_collate_func:0);
30504e6af134Sdanielk1977     if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[4], &val) ) return TCL_ERROR;
3051312d6b36Sdanielk1977 
305286f8c197Sdrh #if 0
30539a30cf65Sdanielk1977     if( sqlite3_iMallocFail>0 ){
30549a30cf65Sdanielk1977       sqlite3_iMallocFail++;
30559a30cf65Sdanielk1977     }
30569a30cf65Sdanielk1977 #endif
3057f3a65f7eSdrh     sqlite3_mutex_enter(db->mutex);
3058f3a65f7eSdrh     pVal = sqlite3ValueNew(db);
3059b21c8cd4Sdrh     sqlite3ValueSetStr(pVal, -1, "test_collate", SQLITE_UTF8, SQLITE_STATIC);
3060a7a8e14bSdanielk1977     zUtf16 = sqlite3ValueText(pVal, SQLITE_UTF16NATIVE);
3061f3a65f7eSdrh     if( db->mallocFailed ){
3062f3a65f7eSdrh       rc = SQLITE_NOMEM;
3063f3a65f7eSdrh     }else{
3064a7a8e14bSdanielk1977       rc = sqlite3_create_collation16(db, zUtf16, SQLITE_UTF16BE,
30659a30cf65Sdanielk1977           (void *)SQLITE_UTF16BE, val?test_collate_func:0);
3066f3a65f7eSdrh     }
3067312d6b36Sdanielk1977     sqlite3ValueFree(pVal);
3068f3a65f7eSdrh     sqlite3_mutex_leave(db->mutex);
3069c60d0446Sdrh   }
3070c60d0446Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
30719a30cf65Sdanielk1977 
30729a30cf65Sdanielk1977   if( rc!=SQLITE_OK ){
3073e84d8d32Smistachkin     Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
30749a30cf65Sdanielk1977     return TCL_ERROR;
30759a30cf65Sdanielk1977   }
30764e6af134Sdanielk1977   return TCL_OK;
30774e6af134Sdanielk1977 
30784e6af134Sdanielk1977 bad_args:
30794e6af134Sdanielk1977   Tcl_AppendResult(interp, "wrong # args: should be \"",
30804e6af134Sdanielk1977       Tcl_GetStringFromObj(objv[0], 0), " <DB> <utf8> <utf16le> <utf16be>", 0);
30814e6af134Sdanielk1977   return TCL_ERROR;
30824e6af134Sdanielk1977 }
30834e6af134Sdanielk1977 
3084268803a9Sdrh /*
308538fdead8Sdan ** Usage: add_test_utf16bin_collate <db ptr>
308638fdead8Sdan **
308738fdead8Sdan ** Add a utf-16 collation sequence named "utf16bin" to the database
308838fdead8Sdan ** handle. This collation sequence compares arguments in the same way as the
308938fdead8Sdan ** built-in collation "binary".
309038fdead8Sdan */
test_utf16bin_collate_func(void * pCtx,int nA,const void * zA,int nB,const void * zB)309138fdead8Sdan static int test_utf16bin_collate_func(
309238fdead8Sdan   void *pCtx,
309338fdead8Sdan   int nA, const void *zA,
309438fdead8Sdan   int nB, const void *zB
309538fdead8Sdan ){
309638fdead8Sdan   int nCmp = (nA>nB ? nB : nA);
309738fdead8Sdan   int res = memcmp(zA, zB, nCmp);
309838fdead8Sdan   if( res==0 ) res = nA - nB;
309938fdead8Sdan   return res;
310038fdead8Sdan }
test_utf16bin_collate(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])31017617e4a8Smistachkin static int SQLITE_TCLAPI test_utf16bin_collate(
310238fdead8Sdan   void * clientData,
310338fdead8Sdan   Tcl_Interp *interp,
310438fdead8Sdan   int objc,
310538fdead8Sdan   Tcl_Obj *CONST objv[]
310638fdead8Sdan ){
310738fdead8Sdan   sqlite3 *db;
310838fdead8Sdan   int rc;
310938fdead8Sdan 
311038fdead8Sdan   if( objc!=2 ) goto bad_args;
311138fdead8Sdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
311238fdead8Sdan 
311338fdead8Sdan   rc = sqlite3_create_collation(db, "utf16bin", SQLITE_UTF16, 0,
311438fdead8Sdan       test_utf16bin_collate_func
311538fdead8Sdan   );
311638fdead8Sdan   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
311738fdead8Sdan   return TCL_OK;
311838fdead8Sdan 
311938fdead8Sdan bad_args:
312038fdead8Sdan   Tcl_WrongNumArgs(interp, 1, objv, "DB");
312138fdead8Sdan   return TCL_ERROR;
312238fdead8Sdan }
312338fdead8Sdan 
312438fdead8Sdan /*
3125268803a9Sdrh ** When the collation needed callback is invoked, record the name of
3126268803a9Sdrh ** the requested collating function here.  The recorded name is linked
3127268803a9Sdrh ** to a TCL variable and used to make sure that the requested collation
3128268803a9Sdrh ** name is correct.
3129268803a9Sdrh */
3130268803a9Sdrh static char zNeededCollation[200];
3131268803a9Sdrh static char *pzNeededCollation = zNeededCollation;
3132268803a9Sdrh 
3133268803a9Sdrh 
3134268803a9Sdrh /*
3135268803a9Sdrh ** Called when a collating sequence is needed.  Registered using
3136268803a9Sdrh ** sqlite3_collation_needed16().
3137268803a9Sdrh */
test_collate_needed_cb(void * pCtx,sqlite3 * db,int eTextRep,const void * pName)3138312d6b36Sdanielk1977 static void test_collate_needed_cb(
3139312d6b36Sdanielk1977   void *pCtx,
3140312d6b36Sdanielk1977   sqlite3 *db,
3141312d6b36Sdanielk1977   int eTextRep,
3142268803a9Sdrh   const void *pName
3143312d6b36Sdanielk1977 ){
314414db2665Sdanielk1977   int enc = ENC(db);
3145268803a9Sdrh   int i;
3146268803a9Sdrh   char *z;
3147268803a9Sdrh   for(z = (char*)pName, i=0; *z || z[1]; z++){
3148268803a9Sdrh     if( *z ) zNeededCollation[i++] = *z;
3149268803a9Sdrh   }
3150268803a9Sdrh   zNeededCollation[i] = 0;
3151312d6b36Sdanielk1977   sqlite3_create_collation(
3152d2199f0fSdan       db, "test_collate", ENC(db), SQLITE_INT_TO_PTR(enc), test_collate_func);
3153312d6b36Sdanielk1977 }
3154312d6b36Sdanielk1977 
3155312d6b36Sdanielk1977 /*
3156312d6b36Sdanielk1977 ** Usage: add_test_collate_needed DB
3157312d6b36Sdanielk1977 */
test_collate_needed(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])31587617e4a8Smistachkin static int SQLITE_TCLAPI test_collate_needed(
3159312d6b36Sdanielk1977   void * clientData,
3160312d6b36Sdanielk1977   Tcl_Interp *interp,
3161312d6b36Sdanielk1977   int objc,
3162312d6b36Sdanielk1977   Tcl_Obj *CONST objv[]
3163312d6b36Sdanielk1977 ){
3164312d6b36Sdanielk1977   sqlite3 *db;
3165c60d0446Sdrh   int rc;
3166312d6b36Sdanielk1977 
3167312d6b36Sdanielk1977   if( objc!=2 ) goto bad_args;
3168312d6b36Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
3169c60d0446Sdrh   rc = sqlite3_collation_needed16(db, 0, test_collate_needed_cb);
3170268803a9Sdrh   zNeededCollation[0] = 0;
3171c60d0446Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
3172312d6b36Sdanielk1977   return TCL_OK;
3173312d6b36Sdanielk1977 
3174312d6b36Sdanielk1977 bad_args:
3175312d6b36Sdanielk1977   Tcl_WrongNumArgs(interp, 1, objv, "DB");
3176312d6b36Sdanielk1977   return TCL_ERROR;
3177312d6b36Sdanielk1977 }
31787d9bd4e1Sdrh 
31797d9bd4e1Sdrh /*
31807d9bd4e1Sdrh ** tclcmd:   add_alignment_test_collations  DB
31817d9bd4e1Sdrh **
31827d9bd4e1Sdrh ** Add two new collating sequences to the database DB
31837d9bd4e1Sdrh **
31847d9bd4e1Sdrh **     utf16_aligned
31857d9bd4e1Sdrh **     utf16_unaligned
31867d9bd4e1Sdrh **
31877d9bd4e1Sdrh ** Both collating sequences use the same sort order as BINARY.
31887d9bd4e1Sdrh ** The only difference is that the utf16_aligned collating
31897d9bd4e1Sdrh ** sequence is declared with the SQLITE_UTF16_ALIGNED flag.
31907d9bd4e1Sdrh ** Both collating functions increment the unaligned utf16 counter
31917d9bd4e1Sdrh ** whenever they see a string that begins on an odd byte boundary.
31927d9bd4e1Sdrh */
31937d9bd4e1Sdrh static int unaligned_string_counter = 0;
alignmentCollFunc(void * NotUsed,int nKey1,const void * pKey1,int nKey2,const void * pKey2)31947d9bd4e1Sdrh static int alignmentCollFunc(
31957d9bd4e1Sdrh   void *NotUsed,
31967d9bd4e1Sdrh   int nKey1, const void *pKey1,
31977d9bd4e1Sdrh   int nKey2, const void *pKey2
31987d9bd4e1Sdrh ){
31997d9bd4e1Sdrh   int rc, n;
32007d9bd4e1Sdrh   n = nKey1<nKey2 ? nKey1 : nKey2;
3201d2199f0fSdan   if( nKey1>0 && 1==(1&(SQLITE_PTR_TO_INT(pKey1))) ) unaligned_string_counter++;
3202d2199f0fSdan   if( nKey2>0 && 1==(1&(SQLITE_PTR_TO_INT(pKey2))) ) unaligned_string_counter++;
32037d9bd4e1Sdrh   rc = memcmp(pKey1, pKey2, n);
32047d9bd4e1Sdrh   if( rc==0 ){
32057d9bd4e1Sdrh     rc = nKey1 - nKey2;
32067d9bd4e1Sdrh   }
32077d9bd4e1Sdrh   return rc;
32087d9bd4e1Sdrh }
add_alignment_test_collations(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])32097617e4a8Smistachkin static int SQLITE_TCLAPI add_alignment_test_collations(
32107d9bd4e1Sdrh   void * clientData,
32117d9bd4e1Sdrh   Tcl_Interp *interp,
32127d9bd4e1Sdrh   int objc,
32137d9bd4e1Sdrh   Tcl_Obj *CONST objv[]
32147d9bd4e1Sdrh ){
32157d9bd4e1Sdrh   sqlite3 *db;
32167d9bd4e1Sdrh   if( objc>=2 ){
32177d9bd4e1Sdrh     if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
3218ebb32939Sdanielk1977     sqlite3_create_collation(db, "utf16_unaligned", SQLITE_UTF16,
32197d9bd4e1Sdrh         0, alignmentCollFunc);
3220ebb32939Sdanielk1977     sqlite3_create_collation(db, "utf16_aligned", SQLITE_UTF16_ALIGNED,
32217d9bd4e1Sdrh         0, alignmentCollFunc);
32227d9bd4e1Sdrh   }
32237d9bd4e1Sdrh   return SQLITE_OK;
32247d9bd4e1Sdrh }
32257d9bd4e1Sdrh #endif /* !defined(SQLITE_OMIT_UTF16) */
3226312d6b36Sdanielk1977 
3227c8e9a2dfSdanielk1977 /*
3228c8e9a2dfSdanielk1977 ** Usage: add_test_function <db ptr> <utf8> <utf16le> <utf16be>
3229c8e9a2dfSdanielk1977 **
3230c8e9a2dfSdanielk1977 ** This function is used to test that SQLite selects the correct user
3231c8e9a2dfSdanielk1977 ** function callback when multiple versions (for different text encodings)
3232c8e9a2dfSdanielk1977 ** are available.
3233c8e9a2dfSdanielk1977 **
3234c8e9a2dfSdanielk1977 ** Calling this routine registers up to three versions of the user function
3235c8e9a2dfSdanielk1977 ** "test_function" with database handle <db>.  If the second argument is
3236c8e9a2dfSdanielk1977 ** true, then a version of test_function is registered for UTF-8, if the
3237c8e9a2dfSdanielk1977 ** third is true, a version is registered for UTF-16le, if the fourth is
3238c8e9a2dfSdanielk1977 ** true, a UTF-16be version is available.  Previous versions of
3239c8e9a2dfSdanielk1977 ** test_function are deleted.
3240c8e9a2dfSdanielk1977 **
3241c8e9a2dfSdanielk1977 ** The user function is implemented by calling the following TCL script:
3242c8e9a2dfSdanielk1977 **
3243c8e9a2dfSdanielk1977 **   "test_function <enc> <arg>"
3244c8e9a2dfSdanielk1977 **
3245c8e9a2dfSdanielk1977 ** Where <enc> is one of UTF-8, UTF-16LE or UTF16BE, and <arg> is the
3246c8e9a2dfSdanielk1977 ** single argument passed to the SQL function. The value returned by
3247c8e9a2dfSdanielk1977 ** the TCL script is used as the return value of the SQL function. It
3248c8e9a2dfSdanielk1977 ** is passed to SQLite using UTF-16BE for a UTF-8 test_function(), UTF-8
3249c8e9a2dfSdanielk1977 ** for a UTF-16LE test_function(), and UTF-16LE for an implementation that
3250c8e9a2dfSdanielk1977 ** prefers UTF-16BE.
3251c8e9a2dfSdanielk1977 */
32525436dc2dSdrh #ifndef SQLITE_OMIT_UTF16
test_function_utf8(sqlite3_context * pCtx,int nArg,sqlite3_value ** argv)3253c8e9a2dfSdanielk1977 static void test_function_utf8(
3254c8e9a2dfSdanielk1977   sqlite3_context *pCtx,
3255c8e9a2dfSdanielk1977   int nArg,
3256c8e9a2dfSdanielk1977   sqlite3_value **argv
3257c8e9a2dfSdanielk1977 ){
3258c8e9a2dfSdanielk1977   Tcl_Interp *interp;
3259c8e9a2dfSdanielk1977   Tcl_Obj *pX;
3260c8e9a2dfSdanielk1977   sqlite3_value *pVal;
3261c8e9a2dfSdanielk1977   interp = (Tcl_Interp *)sqlite3_user_data(pCtx);
3262c8e9a2dfSdanielk1977   pX = Tcl_NewStringObj("test_function", -1);
3263c8e9a2dfSdanielk1977   Tcl_IncrRefCount(pX);
3264c8e9a2dfSdanielk1977   Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj("UTF-8", -1));
3265c8e9a2dfSdanielk1977   Tcl_ListObjAppendElement(interp, pX,
326603d847eaSdrh       Tcl_NewStringObj((char*)sqlite3_value_text(argv[0]), -1));
3267c8e9a2dfSdanielk1977   Tcl_EvalObjEx(interp, pX, 0);
3268c8e9a2dfSdanielk1977   Tcl_DecrRefCount(pX);
3269c8e9a2dfSdanielk1977   sqlite3_result_text(pCtx, Tcl_GetStringResult(interp), -1, SQLITE_TRANSIENT);
32701e536953Sdanielk1977   pVal = sqlite3ValueNew(0);
3271b21c8cd4Sdrh   sqlite3ValueSetStr(pVal, -1, Tcl_GetStringResult(interp),
3272c8e9a2dfSdanielk1977       SQLITE_UTF8, SQLITE_STATIC);
3273c8e9a2dfSdanielk1977   sqlite3_result_text16be(pCtx, sqlite3_value_text16be(pVal),
3274c8e9a2dfSdanielk1977       -1, SQLITE_TRANSIENT);
3275c8e9a2dfSdanielk1977   sqlite3ValueFree(pVal);
3276c8e9a2dfSdanielk1977 }
test_function_utf16le(sqlite3_context * pCtx,int nArg,sqlite3_value ** argv)3277c8e9a2dfSdanielk1977 static void test_function_utf16le(
3278c8e9a2dfSdanielk1977   sqlite3_context *pCtx,
3279c8e9a2dfSdanielk1977   int nArg,
3280c8e9a2dfSdanielk1977   sqlite3_value **argv
3281c8e9a2dfSdanielk1977 ){
3282c8e9a2dfSdanielk1977   Tcl_Interp *interp;
3283c8e9a2dfSdanielk1977   Tcl_Obj *pX;
3284c8e9a2dfSdanielk1977   sqlite3_value *pVal;
3285c8e9a2dfSdanielk1977   interp = (Tcl_Interp *)sqlite3_user_data(pCtx);
3286c8e9a2dfSdanielk1977   pX = Tcl_NewStringObj("test_function", -1);
3287c8e9a2dfSdanielk1977   Tcl_IncrRefCount(pX);
3288c8e9a2dfSdanielk1977   Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj("UTF-16LE", -1));
3289c8e9a2dfSdanielk1977   Tcl_ListObjAppendElement(interp, pX,
329003d847eaSdrh       Tcl_NewStringObj((char*)sqlite3_value_text(argv[0]), -1));
3291c8e9a2dfSdanielk1977   Tcl_EvalObjEx(interp, pX, 0);
3292c8e9a2dfSdanielk1977   Tcl_DecrRefCount(pX);
32931e536953Sdanielk1977   pVal = sqlite3ValueNew(0);
3294b21c8cd4Sdrh   sqlite3ValueSetStr(pVal, -1, Tcl_GetStringResult(interp),
3295c8e9a2dfSdanielk1977       SQLITE_UTF8, SQLITE_STATIC);
329603d847eaSdrh   sqlite3_result_text(pCtx,(char*)sqlite3_value_text(pVal),-1,SQLITE_TRANSIENT);
3297c8e9a2dfSdanielk1977   sqlite3ValueFree(pVal);
3298c8e9a2dfSdanielk1977 }
test_function_utf16be(sqlite3_context * pCtx,int nArg,sqlite3_value ** argv)3299c8e9a2dfSdanielk1977 static void test_function_utf16be(
3300c8e9a2dfSdanielk1977   sqlite3_context *pCtx,
3301c8e9a2dfSdanielk1977   int nArg,
3302c8e9a2dfSdanielk1977   sqlite3_value **argv
3303c8e9a2dfSdanielk1977 ){
3304c8e9a2dfSdanielk1977   Tcl_Interp *interp;
3305c8e9a2dfSdanielk1977   Tcl_Obj *pX;
3306c8e9a2dfSdanielk1977   sqlite3_value *pVal;
3307c8e9a2dfSdanielk1977   interp = (Tcl_Interp *)sqlite3_user_data(pCtx);
3308c8e9a2dfSdanielk1977   pX = Tcl_NewStringObj("test_function", -1);
3309c8e9a2dfSdanielk1977   Tcl_IncrRefCount(pX);
3310c8e9a2dfSdanielk1977   Tcl_ListObjAppendElement(interp, pX, Tcl_NewStringObj("UTF-16BE", -1));
3311c8e9a2dfSdanielk1977   Tcl_ListObjAppendElement(interp, pX,
331203d847eaSdrh       Tcl_NewStringObj((char*)sqlite3_value_text(argv[0]), -1));
3313c8e9a2dfSdanielk1977   Tcl_EvalObjEx(interp, pX, 0);
3314c8e9a2dfSdanielk1977   Tcl_DecrRefCount(pX);
33151e536953Sdanielk1977   pVal = sqlite3ValueNew(0);
3316b21c8cd4Sdrh   sqlite3ValueSetStr(pVal, -1, Tcl_GetStringResult(interp),
3317c8e9a2dfSdanielk1977       SQLITE_UTF8, SQLITE_STATIC);
3318de4fcfddSdrh   sqlite3_result_text16(pCtx, sqlite3_value_text16le(pVal),
3319de4fcfddSdrh       -1, SQLITE_TRANSIENT);
3320de4fcfddSdrh   sqlite3_result_text16be(pCtx, sqlite3_value_text16le(pVal),
3321de4fcfddSdrh       -1, SQLITE_TRANSIENT);
3322c8e9a2dfSdanielk1977   sqlite3_result_text16le(pCtx, sqlite3_value_text16le(pVal),
3323c8e9a2dfSdanielk1977       -1, SQLITE_TRANSIENT);
3324c8e9a2dfSdanielk1977   sqlite3ValueFree(pVal);
3325c8e9a2dfSdanielk1977 }
33265436dc2dSdrh #endif /* SQLITE_OMIT_UTF16 */
test_function(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])33277617e4a8Smistachkin static int SQLITE_TCLAPI test_function(
3328c8e9a2dfSdanielk1977   void * clientData,
3329c8e9a2dfSdanielk1977   Tcl_Interp *interp,
3330c8e9a2dfSdanielk1977   int objc,
3331c8e9a2dfSdanielk1977   Tcl_Obj *CONST objv[]
3332c8e9a2dfSdanielk1977 ){
33335436dc2dSdrh #ifndef SQLITE_OMIT_UTF16
3334c8e9a2dfSdanielk1977   sqlite3 *db;
3335c8e9a2dfSdanielk1977   int val;
3336c8e9a2dfSdanielk1977 
3337c8e9a2dfSdanielk1977   if( objc!=5 ) goto bad_args;
3338c8e9a2dfSdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
3339c8e9a2dfSdanielk1977 
3340c8e9a2dfSdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR;
3341c8e9a2dfSdanielk1977   if( val ){
3342c8e9a2dfSdanielk1977     sqlite3_create_function(db, "test_function", 1, SQLITE_UTF8,
3343c8e9a2dfSdanielk1977         interp, test_function_utf8, 0, 0);
3344c8e9a2dfSdanielk1977   }
3345c8e9a2dfSdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &val) ) return TCL_ERROR;
3346c8e9a2dfSdanielk1977   if( val ){
3347c8e9a2dfSdanielk1977     sqlite3_create_function(db, "test_function", 1, SQLITE_UTF16LE,
3348c8e9a2dfSdanielk1977         interp, test_function_utf16le, 0, 0);
3349c8e9a2dfSdanielk1977   }
3350c8e9a2dfSdanielk1977   if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[4], &val) ) return TCL_ERROR;
3351c8e9a2dfSdanielk1977   if( val ){
3352c8e9a2dfSdanielk1977     sqlite3_create_function(db, "test_function", 1, SQLITE_UTF16BE,
3353c8e9a2dfSdanielk1977         interp, test_function_utf16be, 0, 0);
3354c8e9a2dfSdanielk1977   }
3355c8e9a2dfSdanielk1977 
3356c8e9a2dfSdanielk1977   return TCL_OK;
3357c8e9a2dfSdanielk1977 bad_args:
3358c8e9a2dfSdanielk1977   Tcl_AppendResult(interp, "wrong # args: should be \"",
3359c8e9a2dfSdanielk1977       Tcl_GetStringFromObj(objv[0], 0), " <DB> <utf8> <utf16le> <utf16be>", 0);
33605436dc2dSdrh #endif /* SQLITE_OMIT_UTF16 */
3361c8e9a2dfSdanielk1977   return TCL_ERROR;
3362c8e9a2dfSdanielk1977 }
3363c8e9a2dfSdanielk1977 
3364312d6b36Sdanielk1977 /*
3365ba3cbf3dSdan ** Usage:         sqlite3_test_errstr <err code>
3366312d6b36Sdanielk1977 **
3367312d6b36Sdanielk1977 ** Test that the english language string equivalents for sqlite error codes
3368312d6b36Sdanielk1977 ** are sane. The parameter is an integer representing an sqlite error code.
3369312d6b36Sdanielk1977 ** The result is a list of two elements, the string representation of the
3370312d6b36Sdanielk1977 ** error code and the english language explanation.
3371312d6b36Sdanielk1977 */
test_errstr(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])33727617e4a8Smistachkin static int SQLITE_TCLAPI test_errstr(
3373312d6b36Sdanielk1977   void * clientData,
3374312d6b36Sdanielk1977   Tcl_Interp *interp,
3375312d6b36Sdanielk1977   int objc,
3376312d6b36Sdanielk1977   Tcl_Obj *CONST objv[]
3377312d6b36Sdanielk1977 ){
3378312d6b36Sdanielk1977   char *zCode;
3379312d6b36Sdanielk1977   int i;
3380312d6b36Sdanielk1977   if( objc!=1 ){
3381312d6b36Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "<error code>");
3382312d6b36Sdanielk1977   }
3383312d6b36Sdanielk1977 
3384312d6b36Sdanielk1977   zCode = Tcl_GetString(objv[1]);
3385312d6b36Sdanielk1977   for(i=0; i<200; i++){
33864f0c5878Sdrh     if( 0==strcmp(t1ErrorName(i), zCode) ) break;
3387312d6b36Sdanielk1977   }
3388312d6b36Sdanielk1977   Tcl_SetResult(interp, (char *)sqlite3ErrStr(i), 0);
3389312d6b36Sdanielk1977   return TCL_OK;
3390312d6b36Sdanielk1977 }
3391312d6b36Sdanielk1977 
339250457896Sdrh /*
339399ee3600Sdrh ** Usage:    breakpoint
339499ee3600Sdrh **
339599ee3600Sdrh ** This routine exists for one purpose - to provide a place to put a
339699ee3600Sdrh ** breakpoint with GDB that can be triggered using TCL code.  The use
339799ee3600Sdrh ** for this is when a particular test fails on (say) the 1485th iteration.
339899ee3600Sdrh ** In the TCL test script, we can add code like this:
339999ee3600Sdrh **
340099ee3600Sdrh **     if {$i==1485} breakpoint
340199ee3600Sdrh **
340299ee3600Sdrh ** Then run testfixture in the debugger and wait for the breakpoint to
340399ee3600Sdrh ** fire.  Then additional breakpoints can be set to trace down the bug.
340499ee3600Sdrh */
test_breakpoint(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)34057617e4a8Smistachkin static int SQLITE_TCLAPI test_breakpoint(
340699ee3600Sdrh   void *NotUsed,
340799ee3600Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
340899ee3600Sdrh   int argc,              /* Number of arguments */
340999ee3600Sdrh   char **argv            /* Text of each argument */
341099ee3600Sdrh ){
341199ee3600Sdrh   return TCL_OK;         /* Do nothing */
341299ee3600Sdrh }
341399ee3600Sdrh 
3414241db313Sdrh /*
3415b026e05eSdrh ** Usage:   sqlite3_bind_zeroblob  STMT IDX N
3416b026e05eSdrh **
3417b026e05eSdrh ** Test the sqlite3_bind_zeroblob interface.  STMT is a prepared statement.
3418b026e05eSdrh ** IDX is the index of a wildcard in the prepared statement.  This command
3419b026e05eSdrh ** binds a N-byte zero-filled BLOB to the wildcard.
3420b026e05eSdrh */
test_bind_zeroblob(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])34217617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_zeroblob(
3422b026e05eSdrh   void * clientData,
3423b026e05eSdrh   Tcl_Interp *interp,
3424b026e05eSdrh   int objc,
3425b026e05eSdrh   Tcl_Obj *CONST objv[]
3426b026e05eSdrh ){
3427b026e05eSdrh   sqlite3_stmt *pStmt;
3428b026e05eSdrh   int idx;
3429b026e05eSdrh   int n;
3430b026e05eSdrh   int rc;
3431b026e05eSdrh 
3432b026e05eSdrh   if( objc!=4 ){
343328c66307Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "STMT IDX N");
3434b026e05eSdrh     return TCL_ERROR;
3435b026e05eSdrh   }
3436b026e05eSdrh 
3437b026e05eSdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
3438b026e05eSdrh   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
3439b026e05eSdrh   if( Tcl_GetIntFromObj(interp, objv[3], &n) ) return TCL_ERROR;
3440b026e05eSdrh 
3441b026e05eSdrh   rc = sqlite3_bind_zeroblob(pStmt, idx, n);
3442b026e05eSdrh   if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
3443b026e05eSdrh   if( rc!=SQLITE_OK ){
3444b026e05eSdrh     return TCL_ERROR;
3445b026e05eSdrh   }
3446b026e05eSdrh 
3447b026e05eSdrh   return TCL_OK;
3448b026e05eSdrh }
3449b026e05eSdrh 
3450b026e05eSdrh /*
345180c03022Sdan ** Usage:   sqlite3_bind_zeroblob64  STMT IDX N
345280c03022Sdan **
345380c03022Sdan ** Test the sqlite3_bind_zeroblob64 interface.  STMT is a prepared statement.
345480c03022Sdan ** IDX is the index of a wildcard in the prepared statement.  This command
345580c03022Sdan ** binds a N-byte zero-filled BLOB to the wildcard.
345680c03022Sdan */
test_bind_zeroblob64(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])34577617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_zeroblob64(
345880c03022Sdan   void * clientData,
345980c03022Sdan   Tcl_Interp *interp,
346080c03022Sdan   int objc,
346180c03022Sdan   Tcl_Obj *CONST objv[]
346280c03022Sdan ){
346380c03022Sdan   sqlite3_stmt *pStmt;
346480c03022Sdan   int idx;
34659a1e85eeSdrh   Tcl_WideInt n;
346680c03022Sdan   int rc;
346780c03022Sdan 
346880c03022Sdan   if( objc!=4 ){
346980c03022Sdan     Tcl_WrongNumArgs(interp, 1, objv, "STMT IDX N");
347080c03022Sdan     return TCL_ERROR;
347180c03022Sdan   }
347280c03022Sdan 
347380c03022Sdan   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
347480c03022Sdan   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
347580c03022Sdan   if( Tcl_GetWideIntFromObj(interp, objv[3], &n) ) return TCL_ERROR;
347680c03022Sdan 
347780c03022Sdan   rc = sqlite3_bind_zeroblob64(pStmt, idx, n);
347880c03022Sdan   if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
347980c03022Sdan   if( rc!=SQLITE_OK ){
348080c03022Sdan     Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
348180c03022Sdan     return TCL_ERROR;
348280c03022Sdan   }
348380c03022Sdan 
348480c03022Sdan   return TCL_OK;
348580c03022Sdan }
348680c03022Sdan 
348780c03022Sdan /*
3488241db313Sdrh ** Usage:   sqlite3_bind_int  STMT N VALUE
3489241db313Sdrh **
3490241db313Sdrh ** Test the sqlite3_bind_int interface.  STMT is a prepared statement.
3491241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
3492241db313Sdrh ** binds a 32-bit integer VALUE to that wildcard.
3493241db313Sdrh */
test_bind_int(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])34947617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_int(
349551e3d8e2Sdanielk1977   void * clientData,
349651e3d8e2Sdanielk1977   Tcl_Interp *interp,
349751e3d8e2Sdanielk1977   int objc,
349851e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
349951e3d8e2Sdanielk1977 ){
350051e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
350151e3d8e2Sdanielk1977   int idx;
350251e3d8e2Sdanielk1977   int value;
350351e3d8e2Sdanielk1977   int rc;
350451e3d8e2Sdanielk1977 
350551e3d8e2Sdanielk1977   if( objc!=4 ){
350651e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
3507241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0);
350851e3d8e2Sdanielk1977     return TCL_ERROR;
350951e3d8e2Sdanielk1977   }
351051e3d8e2Sdanielk1977 
351151e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
351251e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
351351e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &value) ) return TCL_ERROR;
351451e3d8e2Sdanielk1977 
3515c572ef7fSdanielk1977   rc = sqlite3_bind_int(pStmt, idx, value);
3516c60d0446Sdrh   if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
351751e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
351851e3d8e2Sdanielk1977     return TCL_ERROR;
351951e3d8e2Sdanielk1977   }
352051e3d8e2Sdanielk1977 
352151e3d8e2Sdanielk1977   return TCL_OK;
352251e3d8e2Sdanielk1977 }
352351e3d8e2Sdanielk1977 
3524241db313Sdrh 
3525241db313Sdrh /*
35262e3f87aeSdrh ** Usage:   intarray_addr  INT  ...
35274841624aSdrh **
35282e3f87aeSdrh ** Return the address of a C-language array of 32-bit integers.
35292e3f87aeSdrh **
35302e3f87aeSdrh ** Space to hold the array is obtained from malloc().  Call this procedure once
35312e3f87aeSdrh ** with no arguments in order to release memory.  Each call to this procedure
35322e3f87aeSdrh ** overwrites the previous array.
35334841624aSdrh */
test_intarray_addr(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])35347617e4a8Smistachkin static int SQLITE_TCLAPI test_intarray_addr(
35354841624aSdrh   void * clientData,
35364841624aSdrh   Tcl_Interp *interp,
35374841624aSdrh   int objc,
35384841624aSdrh   Tcl_Obj *CONST objv[]
35394841624aSdrh ){
35404841624aSdrh   int i;
35414841624aSdrh   static int *p = 0;
35424841624aSdrh 
35434841624aSdrh   sqlite3_free(p);
35444841624aSdrh   p = 0;
35452e3f87aeSdrh   if( objc>1 ){
35462e3f87aeSdrh     p = sqlite3_malloc( sizeof(p[0])*(objc-1) );
35474841624aSdrh     if( p==0 ) return TCL_ERROR;
35482e3f87aeSdrh     for(i=0; i<objc-1; i++){
35492e3f87aeSdrh       if( Tcl_GetIntFromObj(interp, objv[1+i], &p[i]) ){
35504841624aSdrh         sqlite3_free(p);
35512e3f87aeSdrh         p = 0;
35524841624aSdrh         return TCL_ERROR;
35534841624aSdrh       }
35544841624aSdrh     }
35552e3f87aeSdrh   }
35562e3f87aeSdrh   Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p));
35572e3f87aeSdrh   return TCL_OK;
35582e3f87aeSdrh }
35592e3f87aeSdrh /*
35602e3f87aeSdrh ** Usage:   intarray_addr  INT  ...
35612e3f87aeSdrh **
35622e3f87aeSdrh ** Return the address of a C-language array of 32-bit integers.
35632e3f87aeSdrh **
35642e3f87aeSdrh ** Space to hold the array is obtained from malloc().  Call this procedure once
35652e3f87aeSdrh ** with no arguments in order to release memory.  Each call to this procedure
35662e3f87aeSdrh ** overwrites the previous array.
35672e3f87aeSdrh */
test_int64array_addr(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])35687617e4a8Smistachkin static int SQLITE_TCLAPI test_int64array_addr(
35692e3f87aeSdrh   void * clientData,
35702e3f87aeSdrh   Tcl_Interp *interp,
35712e3f87aeSdrh   int objc,
35722e3f87aeSdrh   Tcl_Obj *CONST objv[]
35732e3f87aeSdrh ){
35742e3f87aeSdrh   int i;
35752e3f87aeSdrh   static sqlite3_int64 *p = 0;
35762e3f87aeSdrh 
35772e3f87aeSdrh   sqlite3_free(p);
35782e3f87aeSdrh   p = 0;
35792e3f87aeSdrh   if( objc>1 ){
35802e3f87aeSdrh     p = sqlite3_malloc( sizeof(p[0])*(objc-1) );
35812e3f87aeSdrh     if( p==0 ) return TCL_ERROR;
35822e3f87aeSdrh     for(i=0; i<objc-1; i++){
3583a912348aSdrh       Tcl_WideInt v;
3584a912348aSdrh       if( Tcl_GetWideIntFromObj(interp, objv[1+i], &v) ){
35852e3f87aeSdrh         sqlite3_free(p);
35862e3f87aeSdrh         p = 0;
35872e3f87aeSdrh         return TCL_ERROR;
35882e3f87aeSdrh       }
3589a912348aSdrh       p[i] = v;
35902e3f87aeSdrh     }
35912e3f87aeSdrh   }
35922e3f87aeSdrh   Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p));
35932e3f87aeSdrh   return TCL_OK;
35942e3f87aeSdrh }
35952e3f87aeSdrh /*
35962e3f87aeSdrh ** Usage:   doublearray_addr  INT  ...
35972e3f87aeSdrh **
35982e3f87aeSdrh ** Return the address of a C-language array of doubles.
35992e3f87aeSdrh **
36002e3f87aeSdrh ** Space to hold the array is obtained from malloc().  Call this procedure once
36012e3f87aeSdrh ** with no arguments in order to release memory.  Each call to this procedure
36022e3f87aeSdrh ** overwrites the previous array.
36032e3f87aeSdrh */
test_doublearray_addr(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])36047617e4a8Smistachkin static int SQLITE_TCLAPI test_doublearray_addr(
36052e3f87aeSdrh   void * clientData,
36062e3f87aeSdrh   Tcl_Interp *interp,
36072e3f87aeSdrh   int objc,
36082e3f87aeSdrh   Tcl_Obj *CONST objv[]
36092e3f87aeSdrh ){
36102e3f87aeSdrh   int i;
36112e3f87aeSdrh   static double *p = 0;
36122e3f87aeSdrh 
36132e3f87aeSdrh   sqlite3_free(p);
36142e3f87aeSdrh   p = 0;
36152e3f87aeSdrh   if( objc>1 ){
36162e3f87aeSdrh     p = sqlite3_malloc( sizeof(p[0])*(objc-1) );
36172e3f87aeSdrh     if( p==0 ) return TCL_ERROR;
36182e3f87aeSdrh     for(i=0; i<objc-1; i++){
36192e3f87aeSdrh       if( Tcl_GetDoubleFromObj(interp, objv[1+i], &p[i]) ){
36202e3f87aeSdrh         sqlite3_free(p);
36212e3f87aeSdrh         p = 0;
36222e3f87aeSdrh         return TCL_ERROR;
36232e3f87aeSdrh       }
36242e3f87aeSdrh     }
36252e3f87aeSdrh   }
36262e3f87aeSdrh   Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p));
36272e3f87aeSdrh   return TCL_OK;
36282e3f87aeSdrh }
36292e3f87aeSdrh /*
36302e3f87aeSdrh ** Usage:   textarray_addr  TEXT ...
36312e3f87aeSdrh **
36322e3f87aeSdrh ** Return the address of a C-language array of strings.
36332e3f87aeSdrh **
36342e3f87aeSdrh ** Space to hold the array is obtained from malloc().  Call this procedure once
36352e3f87aeSdrh ** with no arguments in order to release memory.  Each call to this procedure
36362e3f87aeSdrh ** overwrites the previous array.
36372e3f87aeSdrh */
test_textarray_addr(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])36387617e4a8Smistachkin static int SQLITE_TCLAPI test_textarray_addr(
36392e3f87aeSdrh   void * clientData,
36402e3f87aeSdrh   Tcl_Interp *interp,
36412e3f87aeSdrh   int objc,
36422e3f87aeSdrh   Tcl_Obj *CONST objv[]
36432e3f87aeSdrh ){
36442e3f87aeSdrh   int i;
36452e3f87aeSdrh   static int n = 0;
36462e3f87aeSdrh   static char **p = 0;
36472e3f87aeSdrh 
36482e3f87aeSdrh   for(i=0; i<n; i++) sqlite3_free(p[i]);
36492e3f87aeSdrh   sqlite3_free(p);
36502e3f87aeSdrh   p = 0;
36512e3f87aeSdrh   if( objc>1 ){
36522e3f87aeSdrh     p = sqlite3_malloc( sizeof(p[0])*(objc-1) );
36532e3f87aeSdrh     if( p==0 ) return TCL_ERROR;
36542e3f87aeSdrh     for(i=0; i<objc-1; i++){
36552e3f87aeSdrh       p[i] = sqlite3_mprintf("%s", Tcl_GetString(objv[1+i]));
36562e3f87aeSdrh     }
36572e3f87aeSdrh   }
365850687436Sdan   n = objc-1;
36592e3f87aeSdrh   Tcl_SetObjResult(interp, Tcl_NewWideIntObj((sqlite3_int64)p));
36604841624aSdrh   return TCL_OK;
36614841624aSdrh }
36624841624aSdrh 
36634841624aSdrh 
36644841624aSdrh /*
3665241db313Sdrh ** Usage:   sqlite3_bind_int64  STMT N VALUE
3666241db313Sdrh **
3667241db313Sdrh ** Test the sqlite3_bind_int64 interface.  STMT is a prepared statement.
3668241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
3669241db313Sdrh ** binds a 64-bit integer VALUE to that wildcard.
3670241db313Sdrh */
test_bind_int64(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])36717617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_int64(
367251e3d8e2Sdanielk1977   void * clientData,
367351e3d8e2Sdanielk1977   Tcl_Interp *interp,
367451e3d8e2Sdanielk1977   int objc,
367551e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
367651e3d8e2Sdanielk1977 ){
367751e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
367851e3d8e2Sdanielk1977   int idx;
3679b3f787f4Sdrh   Tcl_WideInt value;
368051e3d8e2Sdanielk1977   int rc;
368151e3d8e2Sdanielk1977 
368251e3d8e2Sdanielk1977   if( objc!=4 ){
368351e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
3684241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0);
368551e3d8e2Sdanielk1977     return TCL_ERROR;
368651e3d8e2Sdanielk1977   }
368751e3d8e2Sdanielk1977 
368851e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
368951e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
369051e3d8e2Sdanielk1977   if( Tcl_GetWideIntFromObj(interp, objv[3], &value) ) return TCL_ERROR;
369151e3d8e2Sdanielk1977 
369251e3d8e2Sdanielk1977   rc = sqlite3_bind_int64(pStmt, idx, value);
3693c60d0446Sdrh   if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
369451e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
369551e3d8e2Sdanielk1977     return TCL_ERROR;
369651e3d8e2Sdanielk1977   }
369751e3d8e2Sdanielk1977 
369851e3d8e2Sdanielk1977   return TCL_OK;
369951e3d8e2Sdanielk1977 }
370051e3d8e2Sdanielk1977 
3701241db313Sdrh 
3702241db313Sdrh /*
3703241db313Sdrh ** Usage:   sqlite3_bind_double  STMT N VALUE
3704241db313Sdrh **
3705241db313Sdrh ** Test the sqlite3_bind_double interface.  STMT is a prepared statement.
3706241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
3707241db313Sdrh ** binds a 64-bit integer VALUE to that wildcard.
3708241db313Sdrh */
test_bind_double(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])37097617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_double(
371051e3d8e2Sdanielk1977   void * clientData,
371151e3d8e2Sdanielk1977   Tcl_Interp *interp,
371251e3d8e2Sdanielk1977   int objc,
371351e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
371451e3d8e2Sdanielk1977 ){
371551e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
371651e3d8e2Sdanielk1977   int idx;
371727b2f053Smistachkin   double value = 0;
371851e3d8e2Sdanielk1977   int rc;
3719a06f17feSdrh   const char *zVal;
3720a06f17feSdrh   int i;
3721a06f17feSdrh   static const struct {
3722a06f17feSdrh     const char *zName;     /* Name of the special floating point value */
3723a06f17feSdrh     unsigned int iUpper;   /* Upper 32 bits */
3724a06f17feSdrh     unsigned int iLower;   /* Lower 32 bits */
3725a06f17feSdrh   } aSpecialFp[] = {
3726a06f17feSdrh     {  "NaN",      0x7fffffff, 0xffffffff },
3727a06f17feSdrh     {  "SNaN",     0x7ff7ffff, 0xffffffff },
3728a06f17feSdrh     {  "-NaN",     0xffffffff, 0xffffffff },
3729a06f17feSdrh     {  "-SNaN",    0xfff7ffff, 0xffffffff },
3730a06f17feSdrh     {  "+Inf",     0x7ff00000, 0x00000000 },
3731a06f17feSdrh     {  "-Inf",     0xfff00000, 0x00000000 },
3732a06f17feSdrh     {  "Epsilon",  0x00000000, 0x00000001 },
3733a06f17feSdrh     {  "-Epsilon", 0x80000000, 0x00000001 },
3734a06f17feSdrh     {  "NaN0",     0x7ff80000, 0x00000000 },
3735a06f17feSdrh     {  "-NaN0",    0xfff80000, 0x00000000 },
3736a06f17feSdrh   };
373751e3d8e2Sdanielk1977 
373851e3d8e2Sdanielk1977   if( objc!=4 ){
373951e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
3740241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0);
374151e3d8e2Sdanielk1977     return TCL_ERROR;
374251e3d8e2Sdanielk1977   }
374351e3d8e2Sdanielk1977 
374451e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
374551e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
374651e3d8e2Sdanielk1977 
3747394f07efSdrh   /* Intercept the string "NaN" and generate a NaN value for it.
3748394f07efSdrh   ** All other strings are passed through to Tcl_GetDoubleFromObj().
3749394f07efSdrh   ** Tcl_GetDoubleFromObj() should understand "NaN" but some versions
3750394f07efSdrh   ** contain a bug.
3751394f07efSdrh   */
3752a06f17feSdrh   zVal = Tcl_GetString(objv[3]);
3753a06f17feSdrh   for(i=0; i<sizeof(aSpecialFp)/sizeof(aSpecialFp[0]); i++){
3754a06f17feSdrh     if( strcmp(aSpecialFp[i].zName, zVal)==0 ){
3755a06f17feSdrh       sqlite3_uint64 x;
3756a06f17feSdrh       x = aSpecialFp[i].iUpper;
3757a06f17feSdrh       x <<= 32;
3758a06f17feSdrh       x |= aSpecialFp[i].iLower;
37590a66733aSdrh       assert( sizeof(value)==8 );
37600a66733aSdrh       assert( sizeof(x)==8 );
37610a66733aSdrh       memcpy(&value, &x, 8);
3762a06f17feSdrh       break;
3763a06f17feSdrh     }
3764a06f17feSdrh   }
3765a06f17feSdrh   if( i>=sizeof(aSpecialFp)/sizeof(aSpecialFp[0]) &&
3766a06f17feSdrh          Tcl_GetDoubleFromObj(interp, objv[3], &value) ){
3767394f07efSdrh     return TCL_ERROR;
3768394f07efSdrh   }
376951e3d8e2Sdanielk1977   rc = sqlite3_bind_double(pStmt, idx, value);
3770c60d0446Sdrh   if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
377151e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
377251e3d8e2Sdanielk1977     return TCL_ERROR;
377351e3d8e2Sdanielk1977   }
377451e3d8e2Sdanielk1977 
377551e3d8e2Sdanielk1977   return TCL_OK;
377651e3d8e2Sdanielk1977 }
377751e3d8e2Sdanielk1977 
3778241db313Sdrh /*
3779241db313Sdrh ** Usage:   sqlite3_bind_null  STMT N
3780241db313Sdrh **
3781241db313Sdrh ** Test the sqlite3_bind_null interface.  STMT is a prepared statement.
3782241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
3783241db313Sdrh ** binds a NULL to the wildcard.
3784241db313Sdrh */
test_bind_null(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])37857617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_null(
378651e3d8e2Sdanielk1977   void * clientData,
378751e3d8e2Sdanielk1977   Tcl_Interp *interp,
378851e3d8e2Sdanielk1977   int objc,
378951e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
379051e3d8e2Sdanielk1977 ){
379151e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
379251e3d8e2Sdanielk1977   int idx;
379351e3d8e2Sdanielk1977   int rc;
379451e3d8e2Sdanielk1977 
379551e3d8e2Sdanielk1977   if( objc!=3 ){
379651e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
3797241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N", 0);
379851e3d8e2Sdanielk1977     return TCL_ERROR;
379951e3d8e2Sdanielk1977   }
380051e3d8e2Sdanielk1977 
380151e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
380251e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
380351e3d8e2Sdanielk1977 
380451e3d8e2Sdanielk1977   rc = sqlite3_bind_null(pStmt, idx);
3805c60d0446Sdrh   if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
380651e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
380751e3d8e2Sdanielk1977     return TCL_ERROR;
380851e3d8e2Sdanielk1977   }
380951e3d8e2Sdanielk1977 
381051e3d8e2Sdanielk1977   return TCL_OK;
381151e3d8e2Sdanielk1977 }
381251e3d8e2Sdanielk1977 
3813241db313Sdrh /*
3814241db313Sdrh ** Usage:   sqlite3_bind_text  STMT N STRING BYTES
3815241db313Sdrh **
3816241db313Sdrh ** Test the sqlite3_bind_text interface.  STMT is a prepared statement.
3817241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
3818241db313Sdrh ** binds a UTF-8 string STRING to the wildcard.  The string is BYTES bytes
3819241db313Sdrh ** long.
3820241db313Sdrh */
test_bind_text(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])38217617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_text(
382251e3d8e2Sdanielk1977   void * clientData,
382351e3d8e2Sdanielk1977   Tcl_Interp *interp,
382451e3d8e2Sdanielk1977   int objc,
382551e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
382651e3d8e2Sdanielk1977 ){
382751e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
382851e3d8e2Sdanielk1977   int idx;
3829639ae98cSdrh   int trueLength = 0;
383051e3d8e2Sdanielk1977   int bytes;
383151e3d8e2Sdanielk1977   char *value;
383251e3d8e2Sdanielk1977   int rc;
3833639ae98cSdrh   char *toFree = 0;
383451e3d8e2Sdanielk1977 
383551e3d8e2Sdanielk1977   if( objc!=5 ){
383651e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
3837241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE BYTES", 0);
383851e3d8e2Sdanielk1977     return TCL_ERROR;
383951e3d8e2Sdanielk1977   }
384051e3d8e2Sdanielk1977 
384151e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
384251e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
3843639ae98cSdrh   value = (char*)Tcl_GetByteArrayFromObj(objv[3], &trueLength);
384451e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
3845639ae98cSdrh   if( bytes<0 ){
3846639ae98cSdrh     toFree = malloc( trueLength + 1 );
3847639ae98cSdrh     if( toFree==0 ){
3848639ae98cSdrh       Tcl_AppendResult(interp, "out of memory", (void*)0);
3849639ae98cSdrh       return TCL_ERROR;
3850639ae98cSdrh     }
3851639ae98cSdrh     memcpy(toFree, value, trueLength);
3852639ae98cSdrh     toFree[trueLength] = 0;
3853639ae98cSdrh     value = toFree;
3854639ae98cSdrh   }
3855d8123366Sdanielk1977   rc = sqlite3_bind_text(pStmt, idx, value, bytes, SQLITE_TRANSIENT);
3856639ae98cSdrh   free(toFree);
3857c60d0446Sdrh   if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
385851e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
3859639ae98cSdrh     Tcl_AppendResult(interp, sqlite3ErrName(rc), (void*)0);
386051e3d8e2Sdanielk1977     return TCL_ERROR;
386151e3d8e2Sdanielk1977   }
386251e3d8e2Sdanielk1977 
386351e3d8e2Sdanielk1977   return TCL_OK;
386451e3d8e2Sdanielk1977 }
386551e3d8e2Sdanielk1977 
3866241db313Sdrh /*
3867161fb796Sdanielk1977 ** Usage:   sqlite3_bind_text16 ?-static? STMT N STRING BYTES
3868241db313Sdrh **
3869241db313Sdrh ** Test the sqlite3_bind_text16 interface.  STMT is a prepared statement.
3870241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
3871241db313Sdrh ** binds a UTF-16 string STRING to the wildcard.  The string is BYTES bytes
3872241db313Sdrh ** long.
3873241db313Sdrh */
test_bind_text16(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])38747617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_text16(
387551e3d8e2Sdanielk1977   void * clientData,
387651e3d8e2Sdanielk1977   Tcl_Interp *interp,
387751e3d8e2Sdanielk1977   int objc,
387851e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
387951e3d8e2Sdanielk1977 ){
38805436dc2dSdrh #ifndef SQLITE_OMIT_UTF16
388151e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
388251e3d8e2Sdanielk1977   int idx;
388351e3d8e2Sdanielk1977   int bytes;
388451e3d8e2Sdanielk1977   char *value;
3885639ae98cSdrh   char *toFree = 0;
388651e3d8e2Sdanielk1977   int rc;
3887639ae98cSdrh   int trueLength = 0;
388851e3d8e2Sdanielk1977 
38897da5fcb0Sdrh   void (*xDel)(void*) = (objc==6?SQLITE_STATIC:SQLITE_TRANSIENT);
3890161fb796Sdanielk1977   Tcl_Obj *oStmt    = objv[objc-4];
3891161fb796Sdanielk1977   Tcl_Obj *oN       = objv[objc-3];
3892161fb796Sdanielk1977   Tcl_Obj *oString  = objv[objc-2];
3893161fb796Sdanielk1977   Tcl_Obj *oBytes   = objv[objc-1];
3894161fb796Sdanielk1977 
3895161fb796Sdanielk1977   if( objc!=5 && objc!=6){
389651e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
3897241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE BYTES", 0);
389851e3d8e2Sdanielk1977     return TCL_ERROR;
389951e3d8e2Sdanielk1977   }
390051e3d8e2Sdanielk1977 
3901161fb796Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(oStmt), &pStmt) ) return TCL_ERROR;
3902161fb796Sdanielk1977   if( Tcl_GetIntFromObj(interp, oN, &idx) ) return TCL_ERROR;
3903639ae98cSdrh   value = (char*)Tcl_GetByteArrayFromObj(oString, &trueLength);
3904161fb796Sdanielk1977   if( Tcl_GetIntFromObj(interp, oBytes, &bytes) ) return TCL_ERROR;
3905639ae98cSdrh   if( bytes<0 && xDel==SQLITE_TRANSIENT ){
39065e23ae50Sdrh     toFree = malloc( trueLength + 3 );
3907639ae98cSdrh     if( toFree==0 ){
3908639ae98cSdrh       Tcl_AppendResult(interp, "out of memory", (void*)0);
3909639ae98cSdrh       return TCL_ERROR;
3910639ae98cSdrh     }
3911639ae98cSdrh     memcpy(toFree, value, trueLength);
39125e23ae50Sdrh     memset(toFree+trueLength, 0, 3);
3913639ae98cSdrh     value = toFree;
3914639ae98cSdrh   }
3915161fb796Sdanielk1977   rc = sqlite3_bind_text16(pStmt, idx, (void *)value, bytes, xDel);
3916639ae98cSdrh   free(toFree);
3917c60d0446Sdrh   if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
391851e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
3919e84d8d32Smistachkin     Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
392051e3d8e2Sdanielk1977     return TCL_ERROR;
392151e3d8e2Sdanielk1977   }
392251e3d8e2Sdanielk1977 
39235436dc2dSdrh #endif /* SQLITE_OMIT_UTF16 */
392451e3d8e2Sdanielk1977   return TCL_OK;
392551e3d8e2Sdanielk1977 }
392651e3d8e2Sdanielk1977 
3927241db313Sdrh /*
39285b159dc3Sdanielk1977 ** Usage:   sqlite3_bind_blob ?-static? STMT N DATA BYTES
3929241db313Sdrh **
3930241db313Sdrh ** Test the sqlite3_bind_blob interface.  STMT is a prepared statement.
3931241db313Sdrh ** N is the index of a wildcard in the prepared statement.  This command
3932241db313Sdrh ** binds a BLOB to the wildcard.  The BLOB is BYTES bytes in size.
3933241db313Sdrh */
test_bind_blob(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])39347617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_blob(
393551e3d8e2Sdanielk1977   void * clientData,
393651e3d8e2Sdanielk1977   Tcl_Interp *interp,
393751e3d8e2Sdanielk1977   int objc,
393851e3d8e2Sdanielk1977   Tcl_Obj *CONST objv[]
393951e3d8e2Sdanielk1977 ){
394051e3d8e2Sdanielk1977   sqlite3_stmt *pStmt;
3941de6fde6aSmistachkin   int len, idx;
394251e3d8e2Sdanielk1977   int bytes;
394351e3d8e2Sdanielk1977   char *value;
394451e3d8e2Sdanielk1977   int rc;
39455b159dc3Sdanielk1977   sqlite3_destructor_type xDestructor = SQLITE_TRANSIENT;
394651e3d8e2Sdanielk1977 
39475b159dc3Sdanielk1977   if( objc!=5 && objc!=6 ){
394851e3d8e2Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
3949241db313Sdrh         Tcl_GetStringFromObj(objv[0], 0), " STMT N DATA BYTES", 0);
395051e3d8e2Sdanielk1977     return TCL_ERROR;
395151e3d8e2Sdanielk1977   }
395251e3d8e2Sdanielk1977 
39535b159dc3Sdanielk1977   if( objc==6 ){
39545b159dc3Sdanielk1977     xDestructor = SQLITE_STATIC;
39555b159dc3Sdanielk1977     objv++;
39565b159dc3Sdanielk1977   }
39575b159dc3Sdanielk1977 
395851e3d8e2Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
395951e3d8e2Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
3960de6fde6aSmistachkin 
39618d853642Sdrh   value = (char*)Tcl_GetByteArrayFromObj(objv[3], &len);
396249e4643eSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[4], &bytes) ) return TCL_ERROR;
396351e3d8e2Sdanielk1977 
3964de6fde6aSmistachkin   if( bytes>len ){
3965de6fde6aSmistachkin     char zBuf[200];
3966de6fde6aSmistachkin     sqlite3_snprintf(sizeof(zBuf), zBuf,
3967de6fde6aSmistachkin                      "cannot use %d blob bytes, have %d", bytes, len);
3968ea847f1bSdrh     Tcl_AppendResult(interp, zBuf, (char*)0);
3969de6fde6aSmistachkin     return TCL_ERROR;
3970de6fde6aSmistachkin   }
3971de6fde6aSmistachkin 
39725b159dc3Sdanielk1977   rc = sqlite3_bind_blob(pStmt, idx, value, bytes, xDestructor);
3973c60d0446Sdrh   if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR;
397451e3d8e2Sdanielk1977   if( rc!=SQLITE_OK ){
397551e3d8e2Sdanielk1977     return TCL_ERROR;
397651e3d8e2Sdanielk1977   }
397751e3d8e2Sdanielk1977 
397851e3d8e2Sdanielk1977   return TCL_OK;
397951e3d8e2Sdanielk1977 }
398051e3d8e2Sdanielk1977 
3981252fe67bSdan /*
3982252fe67bSdan ** Usage:   sqlite3_bind_value_from_preupdate STMT N NEW|OLD IDX
3983252fe67bSdan **
3984252fe67bSdan ** Test the sqlite3_bind_value interface using sqlite3_value objects
3985252fe67bSdan ** obtained from either sqlite3_preupdate_new() (if arg[3]=="new") or
3986252fe67bSdan ** sqlite3_preupdate_old() if (arg[3]=="old"). IDX is the index to
3987252fe67bSdan ** pass to the sqlite3_preupdate_xxx() function.
3988252fe67bSdan */
test_bind_value_from_preupdate(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])3989252fe67bSdan static int SQLITE_TCLAPI test_bind_value_from_preupdate(
3990252fe67bSdan   void * clientData,
3991252fe67bSdan   Tcl_Interp *interp,
3992252fe67bSdan   int objc,
3993252fe67bSdan   Tcl_Obj *CONST objv[]
3994252fe67bSdan ){
3995252fe67bSdan   sqlite3_stmt *pStmt;
3996252fe67bSdan   int idx;
3997252fe67bSdan   int bidx;
3998252fe67bSdan   const char *z3 = 0;
3999252fe67bSdan   sqlite3 *db = 0;
4000252fe67bSdan   sqlite3_value *pVal = 0;
4001252fe67bSdan 
4002252fe67bSdan   if( objc!=5 ){
4003252fe67bSdan     Tcl_WrongNumArgs(interp, 1, objv, "STMT N NEW|OLD IDX");
4004252fe67bSdan     return TCL_ERROR;
4005252fe67bSdan   }
4006252fe67bSdan 
4007252fe67bSdan   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
4008252fe67bSdan   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
4009252fe67bSdan   z3 = Tcl_GetString(objv[3]);
4010252fe67bSdan   if( Tcl_GetIntFromObj(interp, objv[4], &bidx) ) return TCL_ERROR;
4011252fe67bSdan   db = sqlite3_db_handle(pStmt);
4012252fe67bSdan 
4013ddd3fe6fSdrh #ifdef SQLITE_ENABLE_PREUPDATE_HOOK
4014252fe67bSdan   if( z3[0]=='n' ){
4015252fe67bSdan     sqlite3_preupdate_new(db, bidx, &pVal);
4016252fe67bSdan   }else if( z3[0]=='o' ){
4017252fe67bSdan     sqlite3_preupdate_old(db, bidx, &pVal);
4018252fe67bSdan   }else{
4019252fe67bSdan     Tcl_AppendResult(interp, "expected new or old, got: ", z3, (char*)0);
4020252fe67bSdan     return TCL_ERROR;
4021252fe67bSdan   }
4022252fe67bSdan   sqlite3_bind_value(pStmt, idx, pVal);
4023ddd3fe6fSdrh #endif
4024252fe67bSdan 
4025252fe67bSdan   return TCL_OK;
4026252fe67bSdan }
4027252fe67bSdan 
4028252fe67bSdan /*
4029252fe67bSdan ** Usage:   sqlite3_bind_value_from_select STMT N SELECT
4030252fe67bSdan **
4031252fe67bSdan ** Test the sqlite3_bind_value interface.  STMT is a prepared statement.
4032252fe67bSdan ** N is the index of a wildcard in the prepared statement.
4033252fe67bSdan */
test_bind_value_from_select(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])4034252fe67bSdan static int SQLITE_TCLAPI test_bind_value_from_select(
4035252fe67bSdan   void * clientData,
4036252fe67bSdan   Tcl_Interp *interp,
4037252fe67bSdan   int objc,
4038252fe67bSdan   Tcl_Obj *CONST objv[]
4039252fe67bSdan ){
4040252fe67bSdan   sqlite3_stmt *pStmt;
4041252fe67bSdan   sqlite3_stmt *pStmt2;
4042252fe67bSdan   int idx;
4043252fe67bSdan   const char *zSql = 0;
4044252fe67bSdan   sqlite3 *db = 0;
4045252fe67bSdan   int rc = SQLITE_OK;
4046252fe67bSdan 
4047252fe67bSdan   if( objc!=4 ){
4048252fe67bSdan     Tcl_WrongNumArgs(interp, 1, objv, "STMT N SELECT");
4049252fe67bSdan     return TCL_ERROR;
4050252fe67bSdan   }
4051252fe67bSdan 
4052252fe67bSdan   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
4053252fe67bSdan   if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR;
4054252fe67bSdan   zSql = Tcl_GetString(objv[3]);
4055252fe67bSdan   db = sqlite3_db_handle(pStmt);
4056252fe67bSdan 
4057252fe67bSdan   rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt2, 0);
4058252fe67bSdan   if( rc!=SQLITE_OK ){
4059252fe67bSdan     Tcl_AppendResult(interp, "error in SQL: ", sqlite3_errmsg(db), (char*)0);
4060252fe67bSdan     return TCL_ERROR;
4061252fe67bSdan   }
4062252fe67bSdan   if( sqlite3_step(pStmt2)==SQLITE_ROW ){
4063252fe67bSdan     sqlite3_value *pVal = sqlite3_column_value(pStmt2, 0);
4064252fe67bSdan     sqlite3_bind_value(pStmt, idx, pVal);
4065252fe67bSdan   }
4066252fe67bSdan   rc = sqlite3_finalize(pStmt2);
4067252fe67bSdan   if( rc!=SQLITE_OK ){
4068252fe67bSdan     Tcl_AppendResult(interp,
4069252fe67bSdan         "error runnning SQL: ", sqlite3_errmsg(db), (char*)0
4070252fe67bSdan     );
4071252fe67bSdan     return TCL_ERROR;
4072252fe67bSdan   }
4073252fe67bSdan 
4074252fe67bSdan   return TCL_OK;
4075252fe67bSdan }
4076252fe67bSdan 
4077ea847f1bSdrh 
40785011bb8dSdan #ifndef SQLITE_OMIT_VIRTUALTABLE
4079ea847f1bSdrh /*
4080ea847f1bSdrh ** sqlite3_carray_bind [options...] STMT NAME VALUE ...
4081ea847f1bSdrh **
4082ea847f1bSdrh ** Options:
4083ea847f1bSdrh **    -transient
4084ea847f1bSdrh **    -static
4085ea847f1bSdrh **    -int32
4086ea847f1bSdrh **    -int64
4087ea847f1bSdrh **    -double
4088ea847f1bSdrh **    -text
4089ea847f1bSdrh **
4090ea847f1bSdrh ** Each call clears static data.  Called with no options does nothing
4091ea847f1bSdrh ** but clear static data.
4092ea847f1bSdrh */
test_carray_bind(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])4093ea847f1bSdrh static int SQLITE_TCLAPI test_carray_bind(
4094ea847f1bSdrh   void * clientData,
4095ea847f1bSdrh   Tcl_Interp *interp,
4096ea847f1bSdrh   int objc,
4097ea847f1bSdrh   Tcl_Obj *CONST objv[]
4098ea847f1bSdrh ){
4099ea847f1bSdrh   sqlite3_stmt *pStmt;
4100ea847f1bSdrh   int eType = 0;   /* CARRAY_INT32 */
4101ea847f1bSdrh   int nData = 0;
4102ea847f1bSdrh   void *aData = 0;
4103ea847f1bSdrh   int isTransient = 0;
4104ea847f1bSdrh   int isStatic = 0;
4105ea847f1bSdrh   int idx;
4106ea847f1bSdrh   int i, j;
4107ea847f1bSdrh   int rc;
4108ea847f1bSdrh   void (*xDel)(void*) = sqlite3_free;
4109ea847f1bSdrh   static void *aStaticData = 0;
4110ea847f1bSdrh   static int nStaticData = 0;
4111ea847f1bSdrh   static int eStaticType = 0;
4112ea847f1bSdrh   extern int sqlite3_carray_bind(
4113ea847f1bSdrh     sqlite3_stmt *pStmt,
4114ea847f1bSdrh     int i,
4115ea847f1bSdrh     void *aData,
4116ea847f1bSdrh     int nData,
4117ea847f1bSdrh     int mFlags,
4118ea847f1bSdrh     void (*xDestroy)(void*)
4119ea847f1bSdrh   );
4120ea847f1bSdrh 
4121ea847f1bSdrh   if( aStaticData ){
4122ea847f1bSdrh     /* Always clear preexisting static data on every call */
4123ea847f1bSdrh     if( eStaticType==3 ){
4124ea847f1bSdrh       for(i=0; i<nStaticData; i++){
4125ea847f1bSdrh         sqlite3_free(((char**)aStaticData)[i]);
4126ea847f1bSdrh       }
4127ea847f1bSdrh     }
4128ea847f1bSdrh     sqlite3_free(aStaticData);
4129ea847f1bSdrh     aStaticData = 0;
4130ea847f1bSdrh     nStaticData = 0;
4131ea847f1bSdrh     eStaticType = 0;
4132ea847f1bSdrh   }
4133ea847f1bSdrh   if( objc==1 ) return TCL_OK;
4134ea847f1bSdrh 
4135ea847f1bSdrh   for(i=1; i<objc && Tcl_GetString(objv[i])[0]=='-'; i++){
4136ea847f1bSdrh     const char *z = Tcl_GetString(objv[i]);
4137ea847f1bSdrh     if( strcmp(z, "-transient")==0 ){
4138ea847f1bSdrh       isTransient = 1;
4139ea847f1bSdrh       xDel = SQLITE_TRANSIENT;
4140ea847f1bSdrh     }else
4141ea847f1bSdrh     if( strcmp(z, "-static")==0 ){
4142ea847f1bSdrh       isStatic = 1;
4143ea847f1bSdrh       xDel = SQLITE_STATIC;
4144ea847f1bSdrh     }else
4145ea847f1bSdrh     if( strcmp(z, "-int32")==0 ){
4146ea847f1bSdrh       eType = 0;  /* CARRAY_INT32 */
4147ea847f1bSdrh     }else
4148ea847f1bSdrh     if( strcmp(z, "-int64")==0 ){
4149ea847f1bSdrh       eType = 1;  /* CARRAY_INT64 */
4150ea847f1bSdrh     }else
4151ea847f1bSdrh     if( strcmp(z, "-double")==0 ){
4152ea847f1bSdrh       eType = 2;  /* CARRAY_DOUBLE */
4153ea847f1bSdrh     }else
4154ea847f1bSdrh     if( strcmp(z, "-text")==0 ){
4155ea847f1bSdrh       eType = 3;  /* CARRAY_TEXT */
4156ea847f1bSdrh     }else
4157ea847f1bSdrh     if( strcmp(z, "--")==0 ){
4158ea847f1bSdrh       break;
4159ea847f1bSdrh     }else
4160ea847f1bSdrh     {
4161ea847f1bSdrh       Tcl_AppendResult(interp, "unknown option: ", z, (char*)0);
4162ea847f1bSdrh       return TCL_ERROR;
4163ea847f1bSdrh     }
4164ea847f1bSdrh   }
4165ea847f1bSdrh   if( eType==3 && !isStatic && !isTransient ){
4166ea847f1bSdrh     Tcl_AppendResult(interp, "text data must be either -static or -transient",
4167ea847f1bSdrh                      (char*)0);
4168ea847f1bSdrh     return TCL_ERROR;
4169ea847f1bSdrh   }
4170ea847f1bSdrh   if( isStatic && isTransient ){
4171ea847f1bSdrh     Tcl_AppendResult(interp, "cannot be both -static and -transient",
4172ea847f1bSdrh                      (char*)0);
4173ea847f1bSdrh     return TCL_ERROR;
4174ea847f1bSdrh   }
4175ea847f1bSdrh   if( objc-i < 2 ){
4176ea847f1bSdrh     Tcl_WrongNumArgs(interp, 1, objv, "[OPTIONS] STMT IDX VALUE ...");
4177ea847f1bSdrh     return TCL_ERROR;
4178ea847f1bSdrh   }
4179ea847f1bSdrh   if( getStmtPointer(interp, Tcl_GetString(objv[i]), &pStmt) ) return TCL_ERROR;
4180ea847f1bSdrh   i++;
4181ea847f1bSdrh   if( Tcl_GetIntFromObj(interp, objv[i], &idx) ) return TCL_ERROR;
4182ea847f1bSdrh   i++;
4183ea847f1bSdrh   nData = objc - i;
4184ea847f1bSdrh   switch( eType + 4*(nData<=0) ){
4185ea847f1bSdrh     case 0: { /* INT32 */
4186ea847f1bSdrh       int *a = sqlite3_malloc( sizeof(int)*nData );
4187ea847f1bSdrh       if( a==0 ){ rc = SQLITE_NOMEM; goto carray_bind_done; }
4188ea847f1bSdrh       for(j=0; j<nData; j++){
4189ea847f1bSdrh         int v;
4190ea847f1bSdrh         if( Tcl_GetIntFromObj(interp, objv[i+j], &v) ){
4191ea847f1bSdrh           sqlite3_free(a);
4192ea847f1bSdrh           return TCL_ERROR;
4193ea847f1bSdrh         }
4194ea847f1bSdrh         a[j] = v;
4195ea847f1bSdrh       }
4196ea847f1bSdrh       aData = a;
4197ea847f1bSdrh       break;
4198ea847f1bSdrh     }
4199ea847f1bSdrh     case 1: { /* INT64 */
4200ea847f1bSdrh       sqlite3_int64 *a = sqlite3_malloc( sizeof(sqlite3_int64)*nData );
4201ea847f1bSdrh       if( a==0 ){ rc = SQLITE_NOMEM; goto carray_bind_done; }
4202ea847f1bSdrh       for(j=0; j<nData; j++){
4203ea847f1bSdrh         Tcl_WideInt v;
4204ea847f1bSdrh         if( Tcl_GetWideIntFromObj(interp, objv[i+j], &v) ){
4205ea847f1bSdrh           sqlite3_free(a);
4206ea847f1bSdrh           return TCL_ERROR;
4207ea847f1bSdrh         }
4208ea847f1bSdrh         a[j] = v;
4209ea847f1bSdrh       }
4210ea847f1bSdrh       aData = a;
4211ea847f1bSdrh       break;
4212ea847f1bSdrh     }
4213ea847f1bSdrh     case 2: { /* DOUBLE */
4214ea847f1bSdrh       double *a = sqlite3_malloc( sizeof(double)*nData );
4215ea847f1bSdrh       if( a==0 ){ rc = SQLITE_NOMEM; goto carray_bind_done; }
4216ea847f1bSdrh       for(j=0; j<nData; j++){
4217ea847f1bSdrh         double v;
4218ea847f1bSdrh         if( Tcl_GetDoubleFromObj(interp, objv[i+j], &v) ){
4219ea847f1bSdrh           sqlite3_free(a);
4220ea847f1bSdrh           return TCL_ERROR;
4221ea847f1bSdrh         }
4222ea847f1bSdrh         a[j] = v;
4223ea847f1bSdrh       }
4224ea847f1bSdrh       aData = a;
4225ea847f1bSdrh       break;
4226ea847f1bSdrh     }
4227ea847f1bSdrh     case 3: { /* TEXT */
4228ea847f1bSdrh       char **a = sqlite3_malloc( sizeof(char*)*nData );
4229ea847f1bSdrh       if( a==0 ){ rc = SQLITE_NOMEM; goto carray_bind_done; }
4230ea847f1bSdrh       for(j=0; j<nData; j++){
4231ea847f1bSdrh         const char *v = Tcl_GetString(objv[i+j]);
4232ea847f1bSdrh         a[j] = sqlite3_mprintf("%s", v);
4233ea847f1bSdrh       }
4234ea847f1bSdrh       aData = a;
4235ea847f1bSdrh       break;
4236ea847f1bSdrh     }
4237ea847f1bSdrh     case 4: { /* nData==0 */
4238ea847f1bSdrh       aData = "";
4239ea847f1bSdrh       xDel = SQLITE_STATIC;
4240ea847f1bSdrh       isTransient = 0;
4241ea847f1bSdrh       isStatic = 0;
4242ea847f1bSdrh       break;
4243ea847f1bSdrh     }
4244ea847f1bSdrh   }
4245ea847f1bSdrh   if( isStatic ){
4246ea847f1bSdrh     aStaticData = aData;
4247ea847f1bSdrh     nStaticData = nData;
4248ea847f1bSdrh     eStaticType = eType;
4249ea847f1bSdrh   }
4250ea847f1bSdrh   rc = sqlite3_carray_bind(pStmt, idx, aData, nData, eType, xDel);
4251ea847f1bSdrh   if( isTransient ){
4252ea847f1bSdrh     if( eType==3 ){
4253ea847f1bSdrh       for(i=0; i<nData; i++) sqlite3_free(((char**)aData)[i]);
4254ea847f1bSdrh     }
4255ea847f1bSdrh     sqlite3_free(aData);
4256ea847f1bSdrh   }
4257ea847f1bSdrh carray_bind_done:
4258ea847f1bSdrh   if( rc ){
4259ea847f1bSdrh     Tcl_AppendResult(interp, sqlite3_errstr(rc), (char*)0);
4260ea847f1bSdrh     return TCL_ERROR;
4261ea847f1bSdrh   }
4262ea847f1bSdrh   return TCL_OK;
4263ea847f1bSdrh }
42645011bb8dSdan #endif /* SQLITE_OMIT_VIRTUALTABLE */
4265ea847f1bSdrh 
426699ee3600Sdrh /*
426775f6a032Sdrh ** Usage:   sqlite3_bind_parameter_count  STMT
426875f6a032Sdrh **
426975f6a032Sdrh ** Return the number of wildcards in the given statement.
427075f6a032Sdrh */
test_bind_parameter_count(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])42717617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_parameter_count(
427275f6a032Sdrh   void * clientData,
427375f6a032Sdrh   Tcl_Interp *interp,
427475f6a032Sdrh   int objc,
427575f6a032Sdrh   Tcl_Obj *CONST objv[]
427675f6a032Sdrh ){
427775f6a032Sdrh   sqlite3_stmt *pStmt;
427875f6a032Sdrh 
427975f6a032Sdrh   if( objc!=2 ){
428075f6a032Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "STMT");
428175f6a032Sdrh     return TCL_ERROR;
428275f6a032Sdrh   }
428375f6a032Sdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
428475f6a032Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_bind_parameter_count(pStmt)));
428575f6a032Sdrh   return TCL_OK;
428675f6a032Sdrh }
428775f6a032Sdrh 
428875f6a032Sdrh /*
4289895d7472Sdrh ** Usage:   sqlite3_bind_parameter_name  STMT  N
4290895d7472Sdrh **
4291895d7472Sdrh ** Return the name of the Nth wildcard.  The first wildcard is 1.
4292895d7472Sdrh ** An empty string is returned if N is out of range or if the wildcard
4293895d7472Sdrh ** is nameless.
4294895d7472Sdrh */
test_bind_parameter_name(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])42957617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_parameter_name(
4296895d7472Sdrh   void * clientData,
4297895d7472Sdrh   Tcl_Interp *interp,
4298895d7472Sdrh   int objc,
4299895d7472Sdrh   Tcl_Obj *CONST objv[]
4300895d7472Sdrh ){
4301895d7472Sdrh   sqlite3_stmt *pStmt;
4302895d7472Sdrh   int i;
4303895d7472Sdrh 
4304895d7472Sdrh   if( objc!=3 ){
4305895d7472Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "STMT N");
4306895d7472Sdrh     return TCL_ERROR;
4307895d7472Sdrh   }
4308895d7472Sdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
4309895d7472Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &i) ) return TCL_ERROR;
4310895d7472Sdrh   Tcl_SetObjResult(interp,
4311895d7472Sdrh      Tcl_NewStringObj(sqlite3_bind_parameter_name(pStmt,i),-1)
4312895d7472Sdrh   );
4313895d7472Sdrh   return TCL_OK;
4314895d7472Sdrh }
4315895d7472Sdrh 
4316895d7472Sdrh /*
4317fa6bc000Sdrh ** Usage:   sqlite3_bind_parameter_index  STMT  NAME
4318fa6bc000Sdrh **
4319fa6bc000Sdrh ** Return the index of the wildcard called NAME.  Return 0 if there is
4320fa6bc000Sdrh ** no such wildcard.
4321fa6bc000Sdrh */
test_bind_parameter_index(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])43227617e4a8Smistachkin static int SQLITE_TCLAPI test_bind_parameter_index(
4323fa6bc000Sdrh   void * clientData,
4324fa6bc000Sdrh   Tcl_Interp *interp,
4325fa6bc000Sdrh   int objc,
4326fa6bc000Sdrh   Tcl_Obj *CONST objv[]
4327fa6bc000Sdrh ){
4328fa6bc000Sdrh   sqlite3_stmt *pStmt;
4329fa6bc000Sdrh 
4330fa6bc000Sdrh   if( objc!=3 ){
4331fa6bc000Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "STMT NAME");
4332fa6bc000Sdrh     return TCL_ERROR;
4333fa6bc000Sdrh   }
4334fa6bc000Sdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
4335fa6bc000Sdrh   Tcl_SetObjResult(interp,
4336fa6bc000Sdrh      Tcl_NewIntObj(
4337fa6bc000Sdrh        sqlite3_bind_parameter_index(pStmt,Tcl_GetString(objv[2]))
4338fa6bc000Sdrh      )
4339fa6bc000Sdrh   );
4340fa6bc000Sdrh   return TCL_OK;
4341fa6bc000Sdrh }
4342fa6bc000Sdrh 
4343fa6bc000Sdrh /*
4344600dd0baSdanielk1977 ** Usage:   sqlite3_clear_bindings STMT
4345600dd0baSdanielk1977 **
4346600dd0baSdanielk1977 */
test_clear_bindings(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])43477617e4a8Smistachkin static int SQLITE_TCLAPI test_clear_bindings(
4348600dd0baSdanielk1977   void * clientData,
4349600dd0baSdanielk1977   Tcl_Interp *interp,
4350600dd0baSdanielk1977   int objc,
4351600dd0baSdanielk1977   Tcl_Obj *CONST objv[]
4352600dd0baSdanielk1977 ){
4353600dd0baSdanielk1977   sqlite3_stmt *pStmt;
4354600dd0baSdanielk1977 
4355600dd0baSdanielk1977   if( objc!=2 ){
4356600dd0baSdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "STMT");
4357600dd0baSdanielk1977     return TCL_ERROR;
4358600dd0baSdanielk1977   }
4359600dd0baSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
4360600dd0baSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_clear_bindings(pStmt)));
4361600dd0baSdanielk1977   return TCL_OK;
4362600dd0baSdanielk1977 }
4363f9cb7f58Sdrh 
4364f9cb7f58Sdrh /*
4365f9cb7f58Sdrh ** Usage:   sqlite3_sleep MILLISECONDS
4366f9cb7f58Sdrh */
test_sleep(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])43677617e4a8Smistachkin static int SQLITE_TCLAPI test_sleep(
4368f9cb7f58Sdrh   void * clientData,
4369f9cb7f58Sdrh   Tcl_Interp *interp,
4370f9cb7f58Sdrh   int objc,
4371f9cb7f58Sdrh   Tcl_Obj *CONST objv[]
4372f9cb7f58Sdrh ){
4373f9cb7f58Sdrh   int ms;
4374f9cb7f58Sdrh 
4375f9cb7f58Sdrh   if( objc!=2 ){
4376f9cb7f58Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "MILLISECONDS");
4377f9cb7f58Sdrh     return TCL_ERROR;
4378f9cb7f58Sdrh   }
4379f9cb7f58Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &ms) ){
4380f9cb7f58Sdrh     return TCL_ERROR;
4381f9cb7f58Sdrh   }
4382f9cb7f58Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_sleep(ms)));
4383f9cb7f58Sdrh   return TCL_OK;
4384f9cb7f58Sdrh }
4385600dd0baSdanielk1977 
4386600dd0baSdanielk1977 /*
438799dfe5ebSdrh ** Usage: sqlite3_extended_errcode DB
438899dfe5ebSdrh **
438999dfe5ebSdrh ** Return the string representation of the most recent sqlite3_* API
439099dfe5ebSdrh ** error code. e.g. "SQLITE_ERROR".
439199dfe5ebSdrh */
test_ex_errcode(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])43927617e4a8Smistachkin static int SQLITE_TCLAPI test_ex_errcode(
439399dfe5ebSdrh   void * clientData,
439499dfe5ebSdrh   Tcl_Interp *interp,
439599dfe5ebSdrh   int objc,
439699dfe5ebSdrh   Tcl_Obj *CONST objv[]
439799dfe5ebSdrh ){
439899dfe5ebSdrh   sqlite3 *db;
439999dfe5ebSdrh   int rc;
440099dfe5ebSdrh 
440199dfe5ebSdrh   if( objc!=2 ){
440299dfe5ebSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
440399dfe5ebSdrh        Tcl_GetString(objv[0]), " DB", 0);
440499dfe5ebSdrh     return TCL_ERROR;
440599dfe5ebSdrh   }
440699dfe5ebSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
440799dfe5ebSdrh   rc = sqlite3_extended_errcode(db);
440899dfe5ebSdrh   Tcl_AppendResult(interp, (char *)t1ErrorName(rc), 0);
440999dfe5ebSdrh   return TCL_OK;
441099dfe5ebSdrh }
441199dfe5ebSdrh 
441299dfe5ebSdrh 
441399dfe5ebSdrh /*
44146622cce3Sdanielk1977 ** Usage: sqlite3_errcode DB
44156622cce3Sdanielk1977 **
44166622cce3Sdanielk1977 ** Return the string representation of the most recent sqlite3_* API
44176622cce3Sdanielk1977 ** error code. e.g. "SQLITE_ERROR".
44186622cce3Sdanielk1977 */
test_errcode(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])44197617e4a8Smistachkin static int SQLITE_TCLAPI test_errcode(
44206622cce3Sdanielk1977   void * clientData,
44216622cce3Sdanielk1977   Tcl_Interp *interp,
44226622cce3Sdanielk1977   int objc,
44236622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
44246622cce3Sdanielk1977 ){
44256622cce3Sdanielk1977   sqlite3 *db;
44264ac285a1Sdrh   int rc;
44276622cce3Sdanielk1977 
44286622cce3Sdanielk1977   if( objc!=2 ){
44296622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
44306622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
44316622cce3Sdanielk1977     return TCL_ERROR;
44326622cce3Sdanielk1977   }
44336622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
44344ac285a1Sdrh   rc = sqlite3_errcode(db);
443599dfe5ebSdrh   Tcl_AppendResult(interp, (char *)t1ErrorName(rc), 0);
44366622cce3Sdanielk1977   return TCL_OK;
44376622cce3Sdanielk1977 }
44386622cce3Sdanielk1977 
44396622cce3Sdanielk1977 /*
44400410302eSdanielk1977 ** Usage:   sqlite3_errmsg DB
44416622cce3Sdanielk1977 **
44426622cce3Sdanielk1977 ** Returns the UTF-8 representation of the error message string for the
44436622cce3Sdanielk1977 ** most recent sqlite3_* API call.
44446622cce3Sdanielk1977 */
test_errmsg(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])44457617e4a8Smistachkin static int SQLITE_TCLAPI test_errmsg(
44466622cce3Sdanielk1977   void * clientData,
44476622cce3Sdanielk1977   Tcl_Interp *interp,
44486622cce3Sdanielk1977   int objc,
44496622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
44506622cce3Sdanielk1977 ){
44519bb575fdSdrh   sqlite3 *db;
44526622cce3Sdanielk1977   const char *zErr;
44536622cce3Sdanielk1977 
44546622cce3Sdanielk1977   if( objc!=2 ){
44556622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
44566622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
44576622cce3Sdanielk1977     return TCL_ERROR;
44586622cce3Sdanielk1977   }
44596622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
44606622cce3Sdanielk1977 
44616622cce3Sdanielk1977   zErr = sqlite3_errmsg(db);
44626622cce3Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewStringObj(zErr, -1));
44636622cce3Sdanielk1977   return TCL_OK;
44646622cce3Sdanielk1977 }
44656622cce3Sdanielk1977 
4466f62641e9Sdrh 
4467f62641e9Sdrh /*
4468f62641e9Sdrh ** Usage:   sqlite3_error_offset DB
4469f62641e9Sdrh **
4470f62641e9Sdrh ** Return the byte offset into the input UTF8 SQL for the most recent
4471f62641e9Sdrh ** error, or -1 of the error does not refer to a specific token.
4472f62641e9Sdrh */
test_error_offset(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])4473f62641e9Sdrh static int SQLITE_TCLAPI test_error_offset(
4474f62641e9Sdrh   void * clientData,
4475f62641e9Sdrh   Tcl_Interp *interp,
4476f62641e9Sdrh   int objc,
4477f62641e9Sdrh   Tcl_Obj *CONST objv[]
4478f62641e9Sdrh ){
4479f62641e9Sdrh   sqlite3 *db;
4480f62641e9Sdrh   int iByteOffset;
4481f62641e9Sdrh 
4482f62641e9Sdrh   if( objc!=2 ){
4483f62641e9Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
4484f62641e9Sdrh        Tcl_GetString(objv[0]), " DB", 0);
4485f62641e9Sdrh     return TCL_ERROR;
4486f62641e9Sdrh   }
4487f62641e9Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
4488f62641e9Sdrh 
4489f62641e9Sdrh   iByteOffset = sqlite3_error_offset(db);
44909169d0cbSdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(iByteOffset));
4491f62641e9Sdrh   return TCL_OK;
4492f62641e9Sdrh }
4493f62641e9Sdrh 
44946622cce3Sdanielk1977 /*
44956622cce3Sdanielk1977 ** Usage:   test_errmsg16 DB
44966622cce3Sdanielk1977 **
44976622cce3Sdanielk1977 ** Returns the UTF-16 representation of the error message string for the
44986622cce3Sdanielk1977 ** most recent sqlite3_* API call. This is a byte array object at the TCL
44996622cce3Sdanielk1977 ** level, and it includes the 0x00 0x00 terminator bytes at the end of the
45006622cce3Sdanielk1977 ** UTF-16 string.
45016622cce3Sdanielk1977 */
test_errmsg16(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])45027617e4a8Smistachkin static int SQLITE_TCLAPI test_errmsg16(
45036622cce3Sdanielk1977   void * clientData,
45046622cce3Sdanielk1977   Tcl_Interp *interp,
45056622cce3Sdanielk1977   int objc,
45066622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
45076622cce3Sdanielk1977 ){
45085436dc2dSdrh #ifndef SQLITE_OMIT_UTF16
45099bb575fdSdrh   sqlite3 *db;
45106622cce3Sdanielk1977   const void *zErr;
4511aed382f9Sdrh   const char *z;
4512950f054cSdanielk1977   int bytes = 0;
45136622cce3Sdanielk1977 
45146622cce3Sdanielk1977   if( objc!=2 ){
45156622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
45166622cce3Sdanielk1977        Tcl_GetString(objv[0]), " DB", 0);
45176622cce3Sdanielk1977     return TCL_ERROR;
45186622cce3Sdanielk1977   }
45196622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
45206622cce3Sdanielk1977 
45216622cce3Sdanielk1977   zErr = sqlite3_errmsg16(db);
4522950f054cSdanielk1977   if( zErr ){
4523aed382f9Sdrh     z = zErr;
4524aed382f9Sdrh     for(bytes=0; z[bytes] || z[bytes+1]; bytes+=2){}
4525950f054cSdanielk1977   }
45266622cce3Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zErr, bytes));
45275436dc2dSdrh #endif /* SQLITE_OMIT_UTF16 */
45286622cce3Sdanielk1977   return TCL_OK;
45296622cce3Sdanielk1977 }
45306622cce3Sdanielk1977 
45316622cce3Sdanielk1977 /*
45321c767f0dSdrh ** Usage: sqlite3_prepare DB sql bytes ?tailvar?
45336622cce3Sdanielk1977 **
45346622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
45356622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global
45366622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A
45376622cce3Sdanielk1977 ** STMT handle is returned.
45386622cce3Sdanielk1977 */
test_prepare(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])45397617e4a8Smistachkin static int SQLITE_TCLAPI test_prepare(
45406622cce3Sdanielk1977   void * clientData,
45416622cce3Sdanielk1977   Tcl_Interp *interp,
45426622cce3Sdanielk1977   int objc,
45436622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
45446622cce3Sdanielk1977 ){
45456622cce3Sdanielk1977   sqlite3 *db;
45466622cce3Sdanielk1977   const char *zSql;
45476622cce3Sdanielk1977   int bytes;
45486622cce3Sdanielk1977   const char *zTail = 0;
45496622cce3Sdanielk1977   sqlite3_stmt *pStmt = 0;
45506622cce3Sdanielk1977   char zBuf[50];
45514ad1713cSdanielk1977   int rc;
45526622cce3Sdanielk1977 
45531c767f0dSdrh   if( objc!=5 && objc!=4 ){
45546622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
45551c767f0dSdrh        Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", 0);
45566622cce3Sdanielk1977     return TCL_ERROR;
45576622cce3Sdanielk1977   }
45586622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
45596622cce3Sdanielk1977   zSql = Tcl_GetString(objv[2]);
45606622cce3Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
45616622cce3Sdanielk1977 
45621c767f0dSdrh   rc = sqlite3_prepare(db, zSql, bytes, &pStmt, objc>=5 ? &zTail : 0);
4563937d0deaSdan   Tcl_ResetResult(interp);
4564c60d0446Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
45651c767f0dSdrh   if( zTail && objc>=5 ){
45666622cce3Sdanielk1977     if( bytes>=0 ){
456783cc1392Sdrh       bytes = bytes - (int)(zTail-zSql);
45686622cce3Sdanielk1977     }
45697da5fcb0Sdrh     if( (int)strlen(zTail)<bytes ){
457083cc1392Sdrh       bytes = (int)strlen(zTail);
45713a2c8c8bSdanielk1977     }
45726622cce3Sdanielk1977     Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
45736622cce3Sdanielk1977   }
45744ad1713cSdanielk1977   if( rc!=SQLITE_OK ){
45754ad1713cSdanielk1977     assert( pStmt==0 );
457665545b59Sdrh     sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc);
45774ad1713cSdanielk1977     Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
45784ad1713cSdanielk1977     return TCL_ERROR;
45794ad1713cSdanielk1977   }
45806622cce3Sdanielk1977 
45814ad1713cSdanielk1977   if( pStmt ){
458264b1bea3Sdrh     if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
45836622cce3Sdanielk1977     Tcl_AppendResult(interp, zBuf, 0);
45844ad1713cSdanielk1977   }
45856622cce3Sdanielk1977   return TCL_OK;
45866622cce3Sdanielk1977 }
45876622cce3Sdanielk1977 
45886622cce3Sdanielk1977 /*
45891c767f0dSdrh ** Usage: sqlite3_prepare_v2 DB sql bytes ?tailvar?
4590b900aaf3Sdrh **
4591b900aaf3Sdrh ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
4592b900aaf3Sdrh ** database handle <DB>. The parameter <tailval> is the name of a global
4593b900aaf3Sdrh ** variable that is set to the unused portion of <sql> (if any). A
4594b900aaf3Sdrh ** STMT handle is returned.
4595b900aaf3Sdrh */
test_prepare_v2(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])45967617e4a8Smistachkin static int SQLITE_TCLAPI test_prepare_v2(
4597b900aaf3Sdrh   void * clientData,
4598b900aaf3Sdrh   Tcl_Interp *interp,
4599b900aaf3Sdrh   int objc,
4600b900aaf3Sdrh   Tcl_Obj *CONST objv[]
4601b900aaf3Sdrh ){
4602b900aaf3Sdrh   sqlite3 *db;
4603b900aaf3Sdrh   const char *zSql;
4604d89b834fSdan   char *zCopy = 0;                /* malloc() copy of zSql */
4605b900aaf3Sdrh   int bytes;
4606b900aaf3Sdrh   const char *zTail = 0;
46078bee11a4Smistachkin   const char **pzTail;
4608b900aaf3Sdrh   sqlite3_stmt *pStmt = 0;
4609b900aaf3Sdrh   char zBuf[50];
4610b900aaf3Sdrh   int rc;
4611b900aaf3Sdrh 
46121c767f0dSdrh   if( objc!=5 && objc!=4 ){
4613b900aaf3Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
4614b900aaf3Sdrh        Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
4615b900aaf3Sdrh     return TCL_ERROR;
4616b900aaf3Sdrh   }
4617b900aaf3Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
4618b900aaf3Sdrh   zSql = Tcl_GetString(objv[2]);
4619b900aaf3Sdrh   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
4620b900aaf3Sdrh 
4621d89b834fSdan   /* Instead of using zSql directly, make a copy into a buffer obtained
4622d89b834fSdan   ** directly from malloc(). The idea is to make it easier for valgrind
4623d89b834fSdan   ** to spot buffer overreads.  */
4624d89b834fSdan   if( bytes>=0 ){
4625d89b834fSdan     zCopy = malloc(bytes);
4626d89b834fSdan     memcpy(zCopy, zSql, bytes);
4627d89b834fSdan   }else{
46282c3abeb8Sdrh     int n = (int)strlen(zSql) + 1;
4629d89b834fSdan     zCopy = malloc(n);
4630d89b834fSdan     memcpy(zCopy, zSql, n);
4631d89b834fSdan   }
46328bee11a4Smistachkin   pzTail = objc>=5 ? &zTail : 0;
46338bee11a4Smistachkin   rc = sqlite3_prepare_v2(db, zCopy, bytes, &pStmt, pzTail);
4634112e1740Sdan   if( objc>=5 ){
4635d89b834fSdan     zTail = &zSql[(zTail - zCopy)];
4636112e1740Sdan   }
4637112e1740Sdan   free(zCopy);
4638d89b834fSdan 
46397e29e956Sdanielk1977   assert(rc==SQLITE_OK || pStmt==0);
4640937d0deaSdan   Tcl_ResetResult(interp);
4641b900aaf3Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
4642112e1740Sdan   if( rc==SQLITE_OK && objc>=5 && zTail ){
4643b900aaf3Sdrh     if( bytes>=0 ){
464483cc1392Sdrh       bytes = bytes - (int)(zTail-zSql);
4645b900aaf3Sdrh     }
4646b900aaf3Sdrh     Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
4647b900aaf3Sdrh   }
4648b900aaf3Sdrh   if( rc!=SQLITE_OK ){
4649b900aaf3Sdrh     assert( pStmt==0 );
465065545b59Sdrh     sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc);
4651b900aaf3Sdrh     Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
4652b900aaf3Sdrh     return TCL_ERROR;
4653b900aaf3Sdrh   }
4654b900aaf3Sdrh 
4655b900aaf3Sdrh   if( pStmt ){
4656b900aaf3Sdrh     if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
4657b900aaf3Sdrh     Tcl_AppendResult(interp, zBuf, 0);
4658b900aaf3Sdrh   }
4659b900aaf3Sdrh   return TCL_OK;
4660b900aaf3Sdrh }
4661b900aaf3Sdrh 
4662b900aaf3Sdrh /*
46638bee11a4Smistachkin ** Usage: sqlite3_prepare_v3 DB sql bytes flags ?tailvar?
46648bee11a4Smistachkin **
46658bee11a4Smistachkin ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
46668bee11a4Smistachkin ** database handle <DB> and flags <flags>. The parameter <tailval> is
46678bee11a4Smistachkin ** the name of a global variable that is set to the unused portion of
46688bee11a4Smistachkin ** <sql> (if any). A STMT handle is returned.
46698bee11a4Smistachkin */
test_prepare_v3(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])46708bee11a4Smistachkin static int SQLITE_TCLAPI test_prepare_v3(
46718bee11a4Smistachkin   void * clientData,
46728bee11a4Smistachkin   Tcl_Interp *interp,
46738bee11a4Smistachkin   int objc,
46748bee11a4Smistachkin   Tcl_Obj *CONST objv[]
46758bee11a4Smistachkin ){
46768bee11a4Smistachkin   sqlite3 *db;
46778bee11a4Smistachkin   const char *zSql;
46788bee11a4Smistachkin   char *zCopy = 0;                /* malloc() copy of zSql */
46798bee11a4Smistachkin   int bytes, flags;
46808bee11a4Smistachkin   const char *zTail = 0;
46818bee11a4Smistachkin   const char **pzTail;
46828bee11a4Smistachkin   sqlite3_stmt *pStmt = 0;
46838bee11a4Smistachkin   char zBuf[50];
46848bee11a4Smistachkin   int rc;
46858bee11a4Smistachkin 
46868bee11a4Smistachkin   if( objc!=6 && objc!=5 ){
46878bee11a4Smistachkin     Tcl_AppendResult(interp, "wrong # args: should be \"",
46888bee11a4Smistachkin        Tcl_GetString(objv[0]), " DB sql bytes flags tailvar", 0);
46898bee11a4Smistachkin     return TCL_ERROR;
46908bee11a4Smistachkin   }
46918bee11a4Smistachkin   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
46928bee11a4Smistachkin   zSql = Tcl_GetString(objv[2]);
46938bee11a4Smistachkin   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
46948bee11a4Smistachkin   if( Tcl_GetIntFromObj(interp, objv[4], &flags) ) return TCL_ERROR;
46958bee11a4Smistachkin 
46968bee11a4Smistachkin   /* Instead of using zSql directly, make a copy into a buffer obtained
46978bee11a4Smistachkin   ** directly from malloc(). The idea is to make it easier for valgrind
46988bee11a4Smistachkin   ** to spot buffer overreads.  */
46998bee11a4Smistachkin   if( bytes>=0 ){
47008bee11a4Smistachkin     zCopy = malloc(bytes);
47018bee11a4Smistachkin     memcpy(zCopy, zSql, bytes);
47028bee11a4Smistachkin   }else{
47038bee11a4Smistachkin     int n = (int)strlen(zSql) + 1;
47048bee11a4Smistachkin     zCopy = malloc(n);
47058bee11a4Smistachkin     memcpy(zCopy, zSql, n);
47068bee11a4Smistachkin   }
47078bee11a4Smistachkin   pzTail = objc>=6 ? &zTail : 0;
47088bee11a4Smistachkin   rc = sqlite3_prepare_v3(db, zCopy, bytes, (unsigned int)flags,&pStmt,pzTail);
47098bee11a4Smistachkin   free(zCopy);
47108bee11a4Smistachkin   zTail = &zSql[(zTail - zCopy)];
47118bee11a4Smistachkin 
47128bee11a4Smistachkin   assert(rc==SQLITE_OK || pStmt==0);
47138bee11a4Smistachkin   Tcl_ResetResult(interp);
47148bee11a4Smistachkin   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
47158bee11a4Smistachkin   if( rc==SQLITE_OK && zTail && objc>=6 ){
47168bee11a4Smistachkin     if( bytes>=0 ){
47178bee11a4Smistachkin       bytes = bytes - (int)(zTail-zSql);
47188bee11a4Smistachkin     }
47198bee11a4Smistachkin     Tcl_ObjSetVar2(interp, objv[5], 0, Tcl_NewStringObj(zTail, bytes), 0);
47208bee11a4Smistachkin   }
47218bee11a4Smistachkin   if( rc!=SQLITE_OK ){
47228bee11a4Smistachkin     assert( pStmt==0 );
47238bee11a4Smistachkin     sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc);
47248bee11a4Smistachkin     Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
47258bee11a4Smistachkin     return TCL_ERROR;
47268bee11a4Smistachkin   }
47278bee11a4Smistachkin 
47288bee11a4Smistachkin   if( pStmt ){
47298bee11a4Smistachkin     if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
47308bee11a4Smistachkin     Tcl_AppendResult(interp, zBuf, 0);
47318bee11a4Smistachkin   }
47328bee11a4Smistachkin   return TCL_OK;
47338bee11a4Smistachkin }
47348bee11a4Smistachkin 
47358bee11a4Smistachkin /*
47364837f531Sdrh ** Usage: sqlite3_prepare_tkt3134 DB
47374837f531Sdrh **
47384837f531Sdrh ** Generate a prepared statement for a zero-byte string as a test
473960ec914cSpeter.d.reid ** for ticket #3134.  The string should be preceded by a zero byte.
47404837f531Sdrh */
test_prepare_tkt3134(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])47417617e4a8Smistachkin static int SQLITE_TCLAPI test_prepare_tkt3134(
47424837f531Sdrh   void * clientData,
47434837f531Sdrh   Tcl_Interp *interp,
47444837f531Sdrh   int objc,
47454837f531Sdrh   Tcl_Obj *CONST objv[]
47464837f531Sdrh ){
47474837f531Sdrh   sqlite3 *db;
47484837f531Sdrh   static const char zSql[] = "\000SELECT 1";
47494837f531Sdrh   sqlite3_stmt *pStmt = 0;
47504837f531Sdrh   char zBuf[50];
47514837f531Sdrh   int rc;
47524837f531Sdrh 
47534837f531Sdrh   if( objc!=2 ){
47544837f531Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
47554837f531Sdrh        Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
47564837f531Sdrh     return TCL_ERROR;
47574837f531Sdrh   }
47584837f531Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
47594837f531Sdrh   rc = sqlite3_prepare_v2(db, &zSql[1], 0, &pStmt, 0);
47604837f531Sdrh   assert(rc==SQLITE_OK || pStmt==0);
47614837f531Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
47624837f531Sdrh   if( rc!=SQLITE_OK ){
47634837f531Sdrh     assert( pStmt==0 );
476465545b59Sdrh     sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc);
47654837f531Sdrh     Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
47664837f531Sdrh     return TCL_ERROR;
47674837f531Sdrh   }
47684837f531Sdrh 
47694837f531Sdrh   if( pStmt ){
47704837f531Sdrh     if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
47714837f531Sdrh     Tcl_AppendResult(interp, zBuf, 0);
47724837f531Sdrh   }
47734837f531Sdrh   return TCL_OK;
47744837f531Sdrh }
47754837f531Sdrh 
47764837f531Sdrh /*
4777b900aaf3Sdrh ** Usage: sqlite3_prepare16 DB sql bytes tailvar
47786622cce3Sdanielk1977 **
47796622cce3Sdanielk1977 ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
47806622cce3Sdanielk1977 ** database handle <DB>. The parameter <tailval> is the name of a global
47816622cce3Sdanielk1977 ** variable that is set to the unused portion of <sql> (if any). A
47826622cce3Sdanielk1977 ** STMT handle is returned.
47836622cce3Sdanielk1977 */
test_prepare16(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])47847617e4a8Smistachkin static int SQLITE_TCLAPI test_prepare16(
47856622cce3Sdanielk1977   void * clientData,
47866622cce3Sdanielk1977   Tcl_Interp *interp,
47876622cce3Sdanielk1977   int objc,
47886622cce3Sdanielk1977   Tcl_Obj *CONST objv[]
47896622cce3Sdanielk1977 ){
47905436dc2dSdrh #ifndef SQLITE_OMIT_UTF16
47916622cce3Sdanielk1977   sqlite3 *db;
47926622cce3Sdanielk1977   const void *zSql;
47936622cce3Sdanielk1977   const void *zTail = 0;
47946622cce3Sdanielk1977   Tcl_Obj *pTail = 0;
47956622cce3Sdanielk1977   sqlite3_stmt *pStmt = 0;
47966622cce3Sdanielk1977   char zBuf[50];
4797c60d0446Sdrh   int rc;
47986622cce3Sdanielk1977   int bytes;                /* The integer specified as arg 3 */
47996622cce3Sdanielk1977   int objlen;               /* The byte-array length of arg 2 */
48006622cce3Sdanielk1977 
48011c767f0dSdrh   if( objc!=5 && objc!=4 ){
48026622cce3Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
48031c767f0dSdrh        Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", 0);
48046622cce3Sdanielk1977     return TCL_ERROR;
48056622cce3Sdanielk1977   }
48066622cce3Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
48076622cce3Sdanielk1977   zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen);
48086622cce3Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
48096622cce3Sdanielk1977 
48101c767f0dSdrh   rc = sqlite3_prepare16(db, zSql, bytes, &pStmt, objc>=5 ? &zTail : 0);
4811c60d0446Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
4812c60d0446Sdrh   if( rc ){
48136622cce3Sdanielk1977     return TCL_ERROR;
48146622cce3Sdanielk1977   }
48156622cce3Sdanielk1977 
48161c767f0dSdrh   if( objc>=5 ){
48176622cce3Sdanielk1977     if( zTail ){
481883cc1392Sdrh       objlen = objlen - (int)((u8 *)zTail-(u8 *)zSql);
48196622cce3Sdanielk1977     }else{
48206622cce3Sdanielk1977       objlen = 0;
48216622cce3Sdanielk1977     }
48226622cce3Sdanielk1977     pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen);
48236622cce3Sdanielk1977     Tcl_IncrRefCount(pTail);
48246622cce3Sdanielk1977     Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0);
48254ad1713cSdanielk1977     Tcl_DecrRefCount(pTail);
48261c767f0dSdrh   }
48276622cce3Sdanielk1977 
48284ad1713cSdanielk1977   if( pStmt ){
482964b1bea3Sdrh     if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
48304ad1713cSdanielk1977   }
48316622cce3Sdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
48325436dc2dSdrh #endif /* SQLITE_OMIT_UTF16 */
48336622cce3Sdanielk1977   return TCL_OK;
48346622cce3Sdanielk1977 }
48356622cce3Sdanielk1977 
48364ad1713cSdanielk1977 /*
48371c767f0dSdrh ** Usage: sqlite3_prepare16_v2 DB sql bytes ?tailvar?
4838b900aaf3Sdrh **
4839b900aaf3Sdrh ** Compile up to <bytes> bytes of the supplied SQL string <sql> using
4840b900aaf3Sdrh ** database handle <DB>. The parameter <tailval> is the name of a global
4841b900aaf3Sdrh ** variable that is set to the unused portion of <sql> (if any). A
4842b900aaf3Sdrh ** STMT handle is returned.
4843b900aaf3Sdrh */
test_prepare16_v2(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])48447617e4a8Smistachkin static int SQLITE_TCLAPI test_prepare16_v2(
4845b900aaf3Sdrh   void * clientData,
4846b900aaf3Sdrh   Tcl_Interp *interp,
4847b900aaf3Sdrh   int objc,
4848b900aaf3Sdrh   Tcl_Obj *CONST objv[]
4849b900aaf3Sdrh ){
4850b900aaf3Sdrh #ifndef SQLITE_OMIT_UTF16
4851b900aaf3Sdrh   sqlite3 *db;
4852b900aaf3Sdrh   const void *zSql;
4853b900aaf3Sdrh   const void *zTail = 0;
4854b900aaf3Sdrh   Tcl_Obj *pTail = 0;
4855b900aaf3Sdrh   sqlite3_stmt *pStmt = 0;
4856b900aaf3Sdrh   char zBuf[50];
4857b900aaf3Sdrh   int rc;
4858b900aaf3Sdrh   int bytes;                /* The integer specified as arg 3 */
4859b900aaf3Sdrh   int objlen;               /* The byte-array length of arg 2 */
4860b900aaf3Sdrh 
48611c767f0dSdrh   if( objc!=5 && objc!=4 ){
4862b900aaf3Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
48631c767f0dSdrh        Tcl_GetString(objv[0]), " DB sql bytes ?tailvar?", 0);
4864b900aaf3Sdrh     return TCL_ERROR;
4865b900aaf3Sdrh   }
4866b900aaf3Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
4867b900aaf3Sdrh   zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen);
4868b900aaf3Sdrh   if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
4869b900aaf3Sdrh 
48701c767f0dSdrh   rc = sqlite3_prepare16_v2(db, zSql, bytes, &pStmt, objc>=5 ? &zTail : 0);
4871b900aaf3Sdrh   if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
4872b900aaf3Sdrh   if( rc ){
4873b900aaf3Sdrh     return TCL_ERROR;
4874b900aaf3Sdrh   }
4875b900aaf3Sdrh 
48761c767f0dSdrh   if( objc>=5 ){
4877b900aaf3Sdrh     if( zTail ){
487883cc1392Sdrh       objlen = objlen - (int)((u8 *)zTail-(u8 *)zSql);
4879b900aaf3Sdrh     }else{
4880b900aaf3Sdrh       objlen = 0;
4881b900aaf3Sdrh     }
4882b900aaf3Sdrh     pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen);
4883b900aaf3Sdrh     Tcl_IncrRefCount(pTail);
4884b900aaf3Sdrh     Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0);
4885b900aaf3Sdrh     Tcl_DecrRefCount(pTail);
48861c767f0dSdrh   }
4887b900aaf3Sdrh 
4888b900aaf3Sdrh   if( pStmt ){
4889b900aaf3Sdrh     if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
4890b900aaf3Sdrh   }
4891b900aaf3Sdrh   Tcl_AppendResult(interp, zBuf, 0);
4892b900aaf3Sdrh #endif /* SQLITE_OMIT_UTF16 */
4893b900aaf3Sdrh   return TCL_OK;
4894b900aaf3Sdrh }
4895b900aaf3Sdrh 
4896b900aaf3Sdrh /*
48974ad1713cSdanielk1977 ** Usage: sqlite3_open filename ?options-list?
48984ad1713cSdanielk1977 */
test_open(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])48997617e4a8Smistachkin static int SQLITE_TCLAPI test_open(
49004ad1713cSdanielk1977   void * clientData,
49014ad1713cSdanielk1977   Tcl_Interp *interp,
49024ad1713cSdanielk1977   int objc,
49034ad1713cSdanielk1977   Tcl_Obj *CONST objv[]
49044ad1713cSdanielk1977 ){
49054ad1713cSdanielk1977   const char *zFilename;
49064ad1713cSdanielk1977   sqlite3 *db;
49074ad1713cSdanielk1977   char zBuf[100];
49084ad1713cSdanielk1977 
4909afc91047Sdrh   if( objc!=3 && objc!=2 && objc!=1 ){
49104ad1713cSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
49114ad1713cSdanielk1977        Tcl_GetString(objv[0]), " filename options-list", 0);
49124ad1713cSdanielk1977     return TCL_ERROR;
49134ad1713cSdanielk1977   }
49144ad1713cSdanielk1977 
4915afc91047Sdrh   zFilename = objc>1 ? Tcl_GetString(objv[1]) : 0;
4916caffb1a5Sdrh   sqlite3_open(zFilename, &db);
49174ad1713cSdanielk1977 
491864b1bea3Sdrh   if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR;
49194ad1713cSdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
49204ad1713cSdanielk1977   return TCL_OK;
49214ad1713cSdanielk1977 }
49224ad1713cSdanielk1977 
49234ad1713cSdanielk1977 /*
4924286ab7c2Sdan ** Usage: sqlite3_open_v2 FILENAME FLAGS VFS
4925286ab7c2Sdan */
test_open_v2(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])49267617e4a8Smistachkin static int SQLITE_TCLAPI test_open_v2(
4927286ab7c2Sdan   void * clientData,
4928286ab7c2Sdan   Tcl_Interp *interp,
4929286ab7c2Sdan   int objc,
4930286ab7c2Sdan   Tcl_Obj *CONST objv[]
4931286ab7c2Sdan ){
4932286ab7c2Sdan   const char *zFilename;
4933286ab7c2Sdan   const char *zVfs;
4934286ab7c2Sdan   int flags = 0;
4935286ab7c2Sdan   sqlite3 *db;
4936286ab7c2Sdan   int rc;
4937286ab7c2Sdan   char zBuf[100];
4938286ab7c2Sdan 
4939286ab7c2Sdan   int nFlag;
4940286ab7c2Sdan   Tcl_Obj **apFlag;
4941286ab7c2Sdan   int i;
4942286ab7c2Sdan 
4943286ab7c2Sdan   if( objc!=4 ){
4944286ab7c2Sdan     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME FLAGS VFS");
4945286ab7c2Sdan     return TCL_ERROR;
4946286ab7c2Sdan   }
4947286ab7c2Sdan   zFilename = Tcl_GetString(objv[1]);
4948286ab7c2Sdan   zVfs = Tcl_GetString(objv[3]);
4949286ab7c2Sdan   if( zVfs[0]==0x00 ) zVfs = 0;
4950286ab7c2Sdan 
4951286ab7c2Sdan   rc = Tcl_ListObjGetElements(interp, objv[2], &nFlag, &apFlag);
4952286ab7c2Sdan   if( rc!=TCL_OK ) return rc;
4953286ab7c2Sdan   for(i=0; i<nFlag; i++){
4954286ab7c2Sdan     int iFlag;
4955286ab7c2Sdan     struct OpenFlag {
4956286ab7c2Sdan       const char *zFlag;
4957286ab7c2Sdan       int flag;
4958286ab7c2Sdan     } aFlag[] = {
4959286ab7c2Sdan       { "SQLITE_OPEN_READONLY", SQLITE_OPEN_READONLY },
4960286ab7c2Sdan       { "SQLITE_OPEN_READWRITE", SQLITE_OPEN_READWRITE },
4961286ab7c2Sdan       { "SQLITE_OPEN_CREATE", SQLITE_OPEN_CREATE },
4962286ab7c2Sdan       { "SQLITE_OPEN_DELETEONCLOSE", SQLITE_OPEN_DELETEONCLOSE },
4963286ab7c2Sdan       { "SQLITE_OPEN_EXCLUSIVE", SQLITE_OPEN_EXCLUSIVE },
4964286ab7c2Sdan       { "SQLITE_OPEN_AUTOPROXY", SQLITE_OPEN_AUTOPROXY },
4965286ab7c2Sdan       { "SQLITE_OPEN_MAIN_DB", SQLITE_OPEN_MAIN_DB },
4966286ab7c2Sdan       { "SQLITE_OPEN_TEMP_DB", SQLITE_OPEN_TEMP_DB },
4967286ab7c2Sdan       { "SQLITE_OPEN_TRANSIENT_DB", SQLITE_OPEN_TRANSIENT_DB },
4968286ab7c2Sdan       { "SQLITE_OPEN_MAIN_JOURNAL", SQLITE_OPEN_MAIN_JOURNAL },
4969286ab7c2Sdan       { "SQLITE_OPEN_TEMP_JOURNAL", SQLITE_OPEN_TEMP_JOURNAL },
4970286ab7c2Sdan       { "SQLITE_OPEN_SUBJOURNAL", SQLITE_OPEN_SUBJOURNAL },
4971ccb2113aSdrh       { "SQLITE_OPEN_SUPER_JOURNAL", SQLITE_OPEN_SUPER_JOURNAL },
4972286ab7c2Sdan       { "SQLITE_OPEN_NOMUTEX", SQLITE_OPEN_NOMUTEX },
4973286ab7c2Sdan       { "SQLITE_OPEN_FULLMUTEX", SQLITE_OPEN_FULLMUTEX },
4974286ab7c2Sdan       { "SQLITE_OPEN_SHAREDCACHE", SQLITE_OPEN_SHAREDCACHE },
4975286ab7c2Sdan       { "SQLITE_OPEN_PRIVATECACHE", SQLITE_OPEN_PRIVATECACHE },
4976286ab7c2Sdan       { "SQLITE_OPEN_WAL", SQLITE_OPEN_WAL },
4977286ab7c2Sdan       { "SQLITE_OPEN_URI", SQLITE_OPEN_URI },
497891acf7d3Sdrh       { "SQLITE_OPEN_EXRESCODE", SQLITE_OPEN_EXRESCODE },
4979286ab7c2Sdan       { 0, 0 }
4980286ab7c2Sdan     };
4981286ab7c2Sdan     rc = Tcl_GetIndexFromObjStruct(interp, apFlag[i], aFlag, sizeof(aFlag[0]),
4982286ab7c2Sdan         "flag", 0, &iFlag
4983286ab7c2Sdan     );
4984286ab7c2Sdan     if( rc!=TCL_OK ) return rc;
4985286ab7c2Sdan     flags |= aFlag[iFlag].flag;
4986286ab7c2Sdan   }
4987286ab7c2Sdan 
4988286ab7c2Sdan   rc = sqlite3_open_v2(zFilename, &db, flags, zVfs);
4989286ab7c2Sdan   if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR;
4990286ab7c2Sdan   Tcl_AppendResult(interp, zBuf, 0);
4991286ab7c2Sdan   return TCL_OK;
4992286ab7c2Sdan }
4993286ab7c2Sdan 
4994286ab7c2Sdan /*
49954ad1713cSdanielk1977 ** Usage: sqlite3_open16 filename options
49964ad1713cSdanielk1977 */
test_open16(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])49977617e4a8Smistachkin static int SQLITE_TCLAPI test_open16(
49984ad1713cSdanielk1977   void * clientData,
49994ad1713cSdanielk1977   Tcl_Interp *interp,
50004ad1713cSdanielk1977   int objc,
50014ad1713cSdanielk1977   Tcl_Obj *CONST objv[]
50024ad1713cSdanielk1977 ){
50035436dc2dSdrh #ifndef SQLITE_OMIT_UTF16
50044ad1713cSdanielk1977   const void *zFilename;
50054ad1713cSdanielk1977   sqlite3 *db;
50064ad1713cSdanielk1977   char zBuf[100];
50074ad1713cSdanielk1977 
50084ad1713cSdanielk1977   if( objc!=3 ){
50094ad1713cSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
50104ad1713cSdanielk1977        Tcl_GetString(objv[0]), " filename options-list", 0);
50114ad1713cSdanielk1977     return TCL_ERROR;
50124ad1713cSdanielk1977   }
50134ad1713cSdanielk1977 
50144ad1713cSdanielk1977   zFilename = Tcl_GetByteArrayFromObj(objv[1], 0);
5015caffb1a5Sdrh   sqlite3_open16(zFilename, &db);
50164ad1713cSdanielk1977 
501764b1bea3Sdrh   if( sqlite3TestMakePointerStr(interp, zBuf, db) ) return TCL_ERROR;
50184ad1713cSdanielk1977   Tcl_AppendResult(interp, zBuf, 0);
50195436dc2dSdrh #endif /* SQLITE_OMIT_UTF16 */
50204ad1713cSdanielk1977   return TCL_OK;
50214ad1713cSdanielk1977 }
5022d3d39e93Sdrh 
5023d3d39e93Sdrh /*
5024bc6ada41Sdanielk1977 ** Usage: sqlite3_complete16 <UTF-16 string>
5025bc6ada41Sdanielk1977 **
5026bc6ada41Sdanielk1977 ** Return 1 if the supplied argument is a complete SQL statement, or zero
5027bc6ada41Sdanielk1977 ** otherwise.
5028bc6ada41Sdanielk1977 */
test_complete16(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])50297617e4a8Smistachkin static int SQLITE_TCLAPI test_complete16(
5030bc6ada41Sdanielk1977   void * clientData,
5031bc6ada41Sdanielk1977   Tcl_Interp *interp,
5032bc6ada41Sdanielk1977   int objc,
5033bc6ada41Sdanielk1977   Tcl_Obj *CONST objv[]
5034bc6ada41Sdanielk1977 ){
5035ccae6026Sdrh #if !defined(SQLITE_OMIT_COMPLETE) && !defined(SQLITE_OMIT_UTF16)
5036bc6ada41Sdanielk1977   char *zBuf;
5037bc6ada41Sdanielk1977 
5038bc6ada41Sdanielk1977   if( objc!=2 ){
5039bc6ada41Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "<utf-16 sql>");
5040bc6ada41Sdanielk1977     return TCL_ERROR;
5041bc6ada41Sdanielk1977   }
5042bc6ada41Sdanielk1977 
504303d847eaSdrh   zBuf = (char*)Tcl_GetByteArrayFromObj(objv[1], 0);
5044bc6ada41Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_complete16(zBuf)));
5045ccae6026Sdrh #endif /* SQLITE_OMIT_COMPLETE && SQLITE_OMIT_UTF16 */
5046bc6ada41Sdanielk1977   return TCL_OK;
5047bc6ada41Sdanielk1977 }
5048bc6ada41Sdanielk1977 
5049bc6ada41Sdanielk1977 /*
505091694dbdSdrh ** Usage: sqlite3_normalize SQL
505191694dbdSdrh **
505291694dbdSdrh ** Return the normalized value for an SQL statement.
505391694dbdSdrh */
test_normalize(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])505491694dbdSdrh static int SQLITE_TCLAPI test_normalize(
505591694dbdSdrh   void * clientData,
505691694dbdSdrh   Tcl_Interp *interp,
505791694dbdSdrh   int objc,
505891694dbdSdrh   Tcl_Obj *CONST objv[]
505991694dbdSdrh ){
506091694dbdSdrh   char *zSql;
506191694dbdSdrh   char *zNorm;
506291694dbdSdrh   extern char *sqlite3_normalize(const char*);
506391694dbdSdrh 
506491694dbdSdrh   if( objc!=2 ){
506591694dbdSdrh     Tcl_WrongNumArgs(interp, 1, objv, "SQL");
506691694dbdSdrh     return TCL_ERROR;
506791694dbdSdrh   }
506891694dbdSdrh 
506991694dbdSdrh   zSql = (char*)Tcl_GetString(objv[1]);
507091694dbdSdrh   zNorm = sqlite3_normalize(zSql);
507191694dbdSdrh   if( zNorm ){
507291694dbdSdrh     Tcl_SetObjResult(interp, Tcl_NewStringObj(zNorm, -1));
507391694dbdSdrh     sqlite3_free(zNorm);
507491694dbdSdrh   }
507591694dbdSdrh   return TCL_OK;
507691694dbdSdrh }
507791694dbdSdrh 
507891694dbdSdrh /*
5079106bb236Sdanielk1977 ** Usage: sqlite3_step STMT
5080106bb236Sdanielk1977 **
5081106bb236Sdanielk1977 ** Advance the statement to the next row.
5082106bb236Sdanielk1977 */
test_step(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])50837617e4a8Smistachkin static int SQLITE_TCLAPI test_step(
5084106bb236Sdanielk1977   void * clientData,
5085106bb236Sdanielk1977   Tcl_Interp *interp,
5086106bb236Sdanielk1977   int objc,
5087106bb236Sdanielk1977   Tcl_Obj *CONST objv[]
5088106bb236Sdanielk1977 ){
5089106bb236Sdanielk1977   sqlite3_stmt *pStmt;
5090106bb236Sdanielk1977   int rc;
5091106bb236Sdanielk1977 
5092e1cd9874Sdanielk1977   if( objc!=2 ){
5093106bb236Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
5094106bb236Sdanielk1977        Tcl_GetString(objv[0]), " STMT", 0);
5095106bb236Sdanielk1977     return TCL_ERROR;
5096106bb236Sdanielk1977   }
5097106bb236Sdanielk1977 
5098106bb236Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
509917240fd9Sdanielk1977   rc = sqlite3_step(pStmt);
5100106bb236Sdanielk1977 
5101fbcd585fSdanielk1977   /* if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR; */
51024f0c5878Sdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
5103e1cd9874Sdanielk1977   return TCL_OK;
5104e1cd9874Sdanielk1977 }
5105e1cd9874Sdanielk1977 
test_sql(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])51067617e4a8Smistachkin static int SQLITE_TCLAPI test_sql(
5107404ca075Sdanielk1977   void * clientData,
5108404ca075Sdanielk1977   Tcl_Interp *interp,
5109404ca075Sdanielk1977   int objc,
5110404ca075Sdanielk1977   Tcl_Obj *CONST objv[]
5111404ca075Sdanielk1977 ){
5112404ca075Sdanielk1977   sqlite3_stmt *pStmt;
5113404ca075Sdanielk1977 
5114404ca075Sdanielk1977   if( objc!=2 ){
5115404ca075Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "STMT");
5116404ca075Sdanielk1977     return TCL_ERROR;
5117404ca075Sdanielk1977   }
5118404ca075Sdanielk1977 
5119404ca075Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
5120404ca075Sdanielk1977   Tcl_SetResult(interp, (char *)sqlite3_sql(pStmt), TCL_VOLATILE);
5121404ca075Sdanielk1977   return TCL_OK;
5122404ca075Sdanielk1977 }
test_ex_sql(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])51237617e4a8Smistachkin static int SQLITE_TCLAPI test_ex_sql(
5124fca760c8Sdrh   void * clientData,
5125fca760c8Sdrh   Tcl_Interp *interp,
5126fca760c8Sdrh   int objc,
5127fca760c8Sdrh   Tcl_Obj *CONST objv[]
5128fca760c8Sdrh ){
5129fca760c8Sdrh   sqlite3_stmt *pStmt;
5130fca760c8Sdrh   char *z;
5131fca760c8Sdrh 
5132fca760c8Sdrh   if( objc!=2 ){
5133fca760c8Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "STMT");
5134fca760c8Sdrh     return TCL_ERROR;
5135fca760c8Sdrh   }
5136fca760c8Sdrh 
5137fca760c8Sdrh   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
5138fca760c8Sdrh   z = sqlite3_expanded_sql(pStmt);
5139fca760c8Sdrh   Tcl_SetResult(interp, z, TCL_VOLATILE);
5140fca760c8Sdrh   sqlite3_free(z);
5141fca760c8Sdrh   return TCL_OK;
5142fca760c8Sdrh }
51438bee11a4Smistachkin #ifdef SQLITE_ENABLE_NORMALIZE
test_norm_sql(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])51448bee11a4Smistachkin static int SQLITE_TCLAPI test_norm_sql(
51458bee11a4Smistachkin   void * clientData,
51468bee11a4Smistachkin   Tcl_Interp *interp,
51478bee11a4Smistachkin   int objc,
51488bee11a4Smistachkin   Tcl_Obj *CONST objv[]
51498bee11a4Smistachkin ){
51508bee11a4Smistachkin   sqlite3_stmt *pStmt;
51518bee11a4Smistachkin 
51528bee11a4Smistachkin   if( objc!=2 ){
51538bee11a4Smistachkin     Tcl_WrongNumArgs(interp, 1, objv, "STMT");
51548bee11a4Smistachkin     return TCL_ERROR;
51558bee11a4Smistachkin   }
51568bee11a4Smistachkin 
51578bee11a4Smistachkin   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
51588bee11a4Smistachkin   Tcl_SetResult(interp, (char *)sqlite3_normalized_sql(pStmt), TCL_VOLATILE);
51598bee11a4Smistachkin   return TCL_OK;
51608bee11a4Smistachkin }
51618bee11a4Smistachkin #endif /* SQLITE_ENABLE_NORMALIZE */
5162404ca075Sdanielk1977 
5163e1cd9874Sdanielk1977 /*
516417240fd9Sdanielk1977 ** Usage: sqlite3_column_count STMT
516517240fd9Sdanielk1977 **
516617240fd9Sdanielk1977 ** Return the number of columns returned by the sql statement STMT.
516717240fd9Sdanielk1977 */
test_column_count(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])51687617e4a8Smistachkin static int SQLITE_TCLAPI test_column_count(
516917240fd9Sdanielk1977   void * clientData,
517017240fd9Sdanielk1977   Tcl_Interp *interp,
517117240fd9Sdanielk1977   int objc,
517217240fd9Sdanielk1977   Tcl_Obj *CONST objv[]
517317240fd9Sdanielk1977 ){
517417240fd9Sdanielk1977   sqlite3_stmt *pStmt;
517517240fd9Sdanielk1977 
517617240fd9Sdanielk1977   if( objc!=2 ){
517717240fd9Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
517817240fd9Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
517917240fd9Sdanielk1977     return TCL_ERROR;
518017240fd9Sdanielk1977   }
518117240fd9Sdanielk1977 
518217240fd9Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
518317240fd9Sdanielk1977 
518417240fd9Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_column_count(pStmt)));
518517240fd9Sdanielk1977   return TCL_OK;
518617240fd9Sdanielk1977 }
518717240fd9Sdanielk1977 
518817240fd9Sdanielk1977 /*
51893cf86063Sdanielk1977 ** Usage: sqlite3_column_type STMT column
51903cf86063Sdanielk1977 **
51913cf86063Sdanielk1977 ** Return the type of the data in column 'column' of the current row.
51923cf86063Sdanielk1977 */
test_column_type(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])51937617e4a8Smistachkin static int SQLITE_TCLAPI test_column_type(
51943cf86063Sdanielk1977   void * clientData,
51953cf86063Sdanielk1977   Tcl_Interp *interp,
51963cf86063Sdanielk1977   int objc,
51973cf86063Sdanielk1977   Tcl_Obj *CONST objv[]
51983cf86063Sdanielk1977 ){
51993cf86063Sdanielk1977   sqlite3_stmt *pStmt;
52003cf86063Sdanielk1977   int col;
52013cf86063Sdanielk1977   int tp;
52023cf86063Sdanielk1977 
52033cf86063Sdanielk1977   if( objc!=3 ){
52043cf86063Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
52053cf86063Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
52063cf86063Sdanielk1977     return TCL_ERROR;
52073cf86063Sdanielk1977   }
52083cf86063Sdanielk1977 
52093cf86063Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
52103cf86063Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
52113cf86063Sdanielk1977 
52123cf86063Sdanielk1977   tp = sqlite3_column_type(pStmt, col);
52133cf86063Sdanielk1977   switch( tp ){
52149c054830Sdrh     case SQLITE_INTEGER:
52153cf86063Sdanielk1977       Tcl_SetResult(interp, "INTEGER", TCL_STATIC);
52163cf86063Sdanielk1977       break;
52179c054830Sdrh     case SQLITE_NULL:
52183cf86063Sdanielk1977       Tcl_SetResult(interp, "NULL", TCL_STATIC);
52193cf86063Sdanielk1977       break;
52209c054830Sdrh     case SQLITE_FLOAT:
52213cf86063Sdanielk1977       Tcl_SetResult(interp, "FLOAT", TCL_STATIC);
52223cf86063Sdanielk1977       break;
52239c054830Sdrh     case SQLITE_TEXT:
52243cf86063Sdanielk1977       Tcl_SetResult(interp, "TEXT", TCL_STATIC);
52253cf86063Sdanielk1977       break;
52269c054830Sdrh     case SQLITE_BLOB:
52273cf86063Sdanielk1977       Tcl_SetResult(interp, "BLOB", TCL_STATIC);
52283cf86063Sdanielk1977       break;
52293cf86063Sdanielk1977     default:
52303cf86063Sdanielk1977       assert(0);
52313cf86063Sdanielk1977   }
52323cf86063Sdanielk1977 
52333cf86063Sdanielk1977   return TCL_OK;
52343cf86063Sdanielk1977 }
52353cf86063Sdanielk1977 
52363cf86063Sdanielk1977 /*
523704f2e68dSdanielk1977 ** Usage: sqlite3_column_int64 STMT column
52383cf86063Sdanielk1977 **
52393cf86063Sdanielk1977 ** Return the data in column 'column' of the current row cast as an
524004f2e68dSdanielk1977 ** wide (64-bit) integer.
52413cf86063Sdanielk1977 */
test_column_int64(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])52427617e4a8Smistachkin static int SQLITE_TCLAPI test_column_int64(
52433cf86063Sdanielk1977   void * clientData,
52443cf86063Sdanielk1977   Tcl_Interp *interp,
52453cf86063Sdanielk1977   int objc,
52463cf86063Sdanielk1977   Tcl_Obj *CONST objv[]
52473cf86063Sdanielk1977 ){
52483cf86063Sdanielk1977   sqlite3_stmt *pStmt;
52493cf86063Sdanielk1977   int col;
525004f2e68dSdanielk1977   i64 iVal;
52513cf86063Sdanielk1977 
52523cf86063Sdanielk1977   if( objc!=3 ){
52533cf86063Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
52543cf86063Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
52553cf86063Sdanielk1977     return TCL_ERROR;
52563cf86063Sdanielk1977   }
52573cf86063Sdanielk1977 
52583cf86063Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
52593cf86063Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
52603cf86063Sdanielk1977 
526104f2e68dSdanielk1977   iVal = sqlite3_column_int64(pStmt, col);
526204f2e68dSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(iVal));
526304f2e68dSdanielk1977   return TCL_OK;
526404f2e68dSdanielk1977 }
526504f2e68dSdanielk1977 
526604f2e68dSdanielk1977 /*
5267ea61b2c4Sdanielk1977 ** Usage: sqlite3_column_blob STMT column
5268ea61b2c4Sdanielk1977 */
test_column_blob(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])52697617e4a8Smistachkin static int SQLITE_TCLAPI test_column_blob(
5270ea61b2c4Sdanielk1977   void * clientData,
5271ea61b2c4Sdanielk1977   Tcl_Interp *interp,
5272ea61b2c4Sdanielk1977   int objc,
5273ea61b2c4Sdanielk1977   Tcl_Obj *CONST objv[]
5274ea61b2c4Sdanielk1977 ){
5275ea61b2c4Sdanielk1977   sqlite3_stmt *pStmt;
5276ea61b2c4Sdanielk1977   int col;
5277ea61b2c4Sdanielk1977 
5278ea61b2c4Sdanielk1977   int len;
5279c572ef7fSdanielk1977   const void *pBlob;
5280ea61b2c4Sdanielk1977 
5281ea61b2c4Sdanielk1977   if( objc!=3 ){
5282ea61b2c4Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
5283ea61b2c4Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
5284ea61b2c4Sdanielk1977     return TCL_ERROR;
5285ea61b2c4Sdanielk1977   }
5286ea61b2c4Sdanielk1977 
5287ea61b2c4Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
5288ea61b2c4Sdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
5289ea61b2c4Sdanielk1977 
5290ea61b2c4Sdanielk1977   len = sqlite3_column_bytes(pStmt, col);
52919310ef23Sdrh   pBlob = sqlite3_column_blob(pStmt, col);
5292ea61b2c4Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pBlob, len));
5293ea61b2c4Sdanielk1977   return TCL_OK;
5294ea61b2c4Sdanielk1977 }
5295ea61b2c4Sdanielk1977 
5296ea61b2c4Sdanielk1977 /*
529704f2e68dSdanielk1977 ** Usage: sqlite3_column_double STMT column
529804f2e68dSdanielk1977 **
529904f2e68dSdanielk1977 ** Return the data in column 'column' of the current row cast as a double.
530004f2e68dSdanielk1977 */
test_column_double(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])53017617e4a8Smistachkin static int SQLITE_TCLAPI test_column_double(
530204f2e68dSdanielk1977   void * clientData,
530304f2e68dSdanielk1977   Tcl_Interp *interp,
530404f2e68dSdanielk1977   int objc,
530504f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
530604f2e68dSdanielk1977 ){
530704f2e68dSdanielk1977   sqlite3_stmt *pStmt;
530804f2e68dSdanielk1977   int col;
530904f2e68dSdanielk1977   double rVal;
531004f2e68dSdanielk1977 
531104f2e68dSdanielk1977   if( objc!=3 ){
531204f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
531304f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
531404f2e68dSdanielk1977     return TCL_ERROR;
531504f2e68dSdanielk1977   }
531604f2e68dSdanielk1977 
531704f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
531804f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
531904f2e68dSdanielk1977 
532004f2e68dSdanielk1977   rVal = sqlite3_column_double(pStmt, col);
5321c572ef7fSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewDoubleObj(rVal));
53223cf86063Sdanielk1977   return TCL_OK;
53233cf86063Sdanielk1977 }
53243cf86063Sdanielk1977 
53253cf86063Sdanielk1977 /*
532617240fd9Sdanielk1977 ** Usage: sqlite3_data_count STMT
532717240fd9Sdanielk1977 **
532817240fd9Sdanielk1977 ** Return the number of columns returned by the sql statement STMT.
532917240fd9Sdanielk1977 */
test_data_count(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])53307617e4a8Smistachkin static int SQLITE_TCLAPI test_data_count(
533117240fd9Sdanielk1977   void * clientData,
533217240fd9Sdanielk1977   Tcl_Interp *interp,
533317240fd9Sdanielk1977   int objc,
533417240fd9Sdanielk1977   Tcl_Obj *CONST objv[]
533517240fd9Sdanielk1977 ){
533617240fd9Sdanielk1977   sqlite3_stmt *pStmt;
533717240fd9Sdanielk1977 
533817240fd9Sdanielk1977   if( objc!=2 ){
533917240fd9Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
534017240fd9Sdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
534117240fd9Sdanielk1977     return TCL_ERROR;
534217240fd9Sdanielk1977   }
534317240fd9Sdanielk1977 
534417240fd9Sdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
534517240fd9Sdanielk1977 
534617240fd9Sdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_data_count(pStmt)));
534717240fd9Sdanielk1977   return TCL_OK;
534817240fd9Sdanielk1977 }
534917240fd9Sdanielk1977 
535017240fd9Sdanielk1977 /*
535104f2e68dSdanielk1977 ** Usage: sqlite3_column_text STMT column
535204f2e68dSdanielk1977 **
535304f2e68dSdanielk1977 ** Usage: sqlite3_column_decltype STMT column
535404f2e68dSdanielk1977 **
535504f2e68dSdanielk1977 ** Usage: sqlite3_column_name STMT column
535604f2e68dSdanielk1977 */
test_stmt_utf8(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])53577617e4a8Smistachkin static int SQLITE_TCLAPI test_stmt_utf8(
5358241db313Sdrh   void * clientData,        /* Pointer to SQLite API function to be invoke */
535904f2e68dSdanielk1977   Tcl_Interp *interp,
536004f2e68dSdanielk1977   int objc,
536104f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
536204f2e68dSdanielk1977 ){
536304f2e68dSdanielk1977   sqlite3_stmt *pStmt;
536404f2e68dSdanielk1977   int col;
536544a376f6Sdanielk1977   const char *(*xFunc)(sqlite3_stmt*, int);
5366f93bbbeaSdanielk1977   const char *zRet;
536704f2e68dSdanielk1977 
536844a376f6Sdanielk1977   xFunc = (const char *(*)(sqlite3_stmt*, int))clientData;
536904f2e68dSdanielk1977   if( objc!=3 ){
537004f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
537104f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
537204f2e68dSdanielk1977     return TCL_ERROR;
537304f2e68dSdanielk1977   }
537404f2e68dSdanielk1977 
537504f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
537604f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
5377f93bbbeaSdanielk1977   zRet = xFunc(pStmt, col);
5378f93bbbeaSdanielk1977   if( zRet ){
5379f93bbbeaSdanielk1977     Tcl_SetResult(interp, (char *)zRet, 0);
5380f93bbbeaSdanielk1977   }
538104f2e68dSdanielk1977   return TCL_OK;
538204f2e68dSdanielk1977 }
538304f2e68dSdanielk1977 
test_global_recover(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])53847617e4a8Smistachkin static int SQLITE_TCLAPI test_global_recover(
53856b456a2bSdanielk1977   void * clientData,
53866b456a2bSdanielk1977   Tcl_Interp *interp,
53876b456a2bSdanielk1977   int objc,
53886b456a2bSdanielk1977   Tcl_Obj *CONST objv[]
53896b456a2bSdanielk1977 ){
5390eec556d3Sshane #ifndef SQLITE_OMIT_DEPRECATED
53916b456a2bSdanielk1977   int rc;
53926b456a2bSdanielk1977   if( objc!=1 ){
53936b456a2bSdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "");
53946b456a2bSdanielk1977     return TCL_ERROR;
53956b456a2bSdanielk1977   }
53966b456a2bSdanielk1977   rc = sqlite3_global_recover();
53974f0c5878Sdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
53986b456a2bSdanielk1977 #endif
53996b456a2bSdanielk1977   return TCL_OK;
54006b456a2bSdanielk1977 }
54016b456a2bSdanielk1977 
540204f2e68dSdanielk1977 /*
540304f2e68dSdanielk1977 ** Usage: sqlite3_column_text STMT column
540404f2e68dSdanielk1977 **
540504f2e68dSdanielk1977 ** Usage: sqlite3_column_decltype STMT column
540604f2e68dSdanielk1977 **
540704f2e68dSdanielk1977 ** Usage: sqlite3_column_name STMT column
540804f2e68dSdanielk1977 */
test_stmt_utf16(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])54097617e4a8Smistachkin static int SQLITE_TCLAPI test_stmt_utf16(
5410241db313Sdrh   void * clientData,     /* Pointer to SQLite API function to be invoked */
541104f2e68dSdanielk1977   Tcl_Interp *interp,
541204f2e68dSdanielk1977   int objc,
541304f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
541404f2e68dSdanielk1977 ){
54155436dc2dSdrh #ifndef SQLITE_OMIT_UTF16
541604f2e68dSdanielk1977   sqlite3_stmt *pStmt;
541704f2e68dSdanielk1977   int col;
541804f2e68dSdanielk1977   Tcl_Obj *pRet;
541904f2e68dSdanielk1977   const void *zName16;
542044a376f6Sdanielk1977   const void *(*xFunc)(sqlite3_stmt*, int);
542104f2e68dSdanielk1977 
542244a376f6Sdanielk1977   xFunc = (const void *(*)(sqlite3_stmt*, int))clientData;
542304f2e68dSdanielk1977   if( objc!=3 ){
542404f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
542504f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
542604f2e68dSdanielk1977     return TCL_ERROR;
542704f2e68dSdanielk1977   }
542804f2e68dSdanielk1977 
542904f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
543004f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
543104f2e68dSdanielk1977 
543204f2e68dSdanielk1977   zName16 = xFunc(pStmt, col);
5433f93bbbeaSdanielk1977   if( zName16 ){
5434aed382f9Sdrh     int n;
5435aed382f9Sdrh     const char *z = zName16;
5436aed382f9Sdrh     for(n=0; z[n] || z[n+1]; n+=2){}
5437aed382f9Sdrh     pRet = Tcl_NewByteArrayObj(zName16, n+2);
543804f2e68dSdanielk1977     Tcl_SetObjResult(interp, pRet);
5439f93bbbeaSdanielk1977   }
54405436dc2dSdrh #endif /* SQLITE_OMIT_UTF16 */
544104f2e68dSdanielk1977 
544204f2e68dSdanielk1977   return TCL_OK;
544304f2e68dSdanielk1977 }
544404f2e68dSdanielk1977 
544504f2e68dSdanielk1977 /*
544604f2e68dSdanielk1977 ** Usage: sqlite3_column_int STMT column
544704f2e68dSdanielk1977 **
544804f2e68dSdanielk1977 ** Usage: sqlite3_column_bytes STMT column
544904f2e68dSdanielk1977 **
545004f2e68dSdanielk1977 ** Usage: sqlite3_column_bytes16 STMT column
545104f2e68dSdanielk1977 **
545204f2e68dSdanielk1977 */
test_stmt_int(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])54537617e4a8Smistachkin static int SQLITE_TCLAPI test_stmt_int(
5454241db313Sdrh   void * clientData,    /* Pointer to SQLite API function to be invoked */
545504f2e68dSdanielk1977   Tcl_Interp *interp,
545604f2e68dSdanielk1977   int objc,
545704f2e68dSdanielk1977   Tcl_Obj *CONST objv[]
545804f2e68dSdanielk1977 ){
545904f2e68dSdanielk1977   sqlite3_stmt *pStmt;
546004f2e68dSdanielk1977   int col;
546144a376f6Sdanielk1977   int (*xFunc)(sqlite3_stmt*, int);
546204f2e68dSdanielk1977 
546355a25a12Sdanielk1977   xFunc = (int (*)(sqlite3_stmt*, int))clientData;
546404f2e68dSdanielk1977   if( objc!=3 ){
546504f2e68dSdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"",
546604f2e68dSdanielk1977        Tcl_GetString(objv[0]), " STMT column", 0);
546704f2e68dSdanielk1977     return TCL_ERROR;
546804f2e68dSdanielk1977   }
546904f2e68dSdanielk1977 
547004f2e68dSdanielk1977   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
547104f2e68dSdanielk1977   if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
547204f2e68dSdanielk1977 
547304f2e68dSdanielk1977   Tcl_SetObjResult(interp, Tcl_NewIntObj(xFunc(pStmt, col)));
547404f2e68dSdanielk1977   return TCL_OK;
547504f2e68dSdanielk1977 }
547604f2e68dSdanielk1977 
5477cacb208eSdrh 
5478cacb208eSdrh /*
5479c5cdca61Sdrh ** Usage:  sqlite3_interrupt  DB
5480c5cdca61Sdrh **
5481c5cdca61Sdrh ** Trigger an interrupt on DB
5482c5cdca61Sdrh */
test_interrupt(void * clientData,Tcl_Interp * interp,int argc,char ** argv)54837617e4a8Smistachkin static int SQLITE_TCLAPI test_interrupt(
5484c5cdca61Sdrh   void * clientData,
5485c5cdca61Sdrh   Tcl_Interp *interp,
5486c5cdca61Sdrh   int argc,
5487c5cdca61Sdrh   char **argv
5488c5cdca61Sdrh ){
5489c5cdca61Sdrh   sqlite3 *db;
5490c5cdca61Sdrh   if( argc!=2 ){
5491c5cdca61Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB", 0);
5492c5cdca61Sdrh     return TCL_ERROR;
5493c5cdca61Sdrh   }
5494c5cdca61Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
5495c5cdca61Sdrh   sqlite3_interrupt(db);
5496c5cdca61Sdrh   return TCL_OK;
5497c5cdca61Sdrh }
5498c5cdca61Sdrh 
5499600dd0baSdanielk1977 /*
55009636c4e1Sdanielk1977 ** Usage: sqlite_delete_function DB function-name
55019636c4e1Sdanielk1977 **
55029636c4e1Sdanielk1977 ** Delete the user function 'function-name' from database handle DB. It
55039636c4e1Sdanielk1977 ** is assumed that the user function was created as UTF8, any number of
55049636c4e1Sdanielk1977 ** arguments (the way the TCL interface does it).
55059636c4e1Sdanielk1977 */
delete_function(void * clientData,Tcl_Interp * interp,int argc,char ** argv)55067617e4a8Smistachkin static int SQLITE_TCLAPI delete_function(
55079636c4e1Sdanielk1977   void * clientData,
55089636c4e1Sdanielk1977   Tcl_Interp *interp,
55099636c4e1Sdanielk1977   int argc,
55109636c4e1Sdanielk1977   char **argv
55119636c4e1Sdanielk1977 ){
55129636c4e1Sdanielk1977   int rc;
55139636c4e1Sdanielk1977   sqlite3 *db;
55149636c4e1Sdanielk1977   if( argc!=3 ){
55159636c4e1Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
55169636c4e1Sdanielk1977         " DB function-name", 0);
55179636c4e1Sdanielk1977     return TCL_ERROR;
55189636c4e1Sdanielk1977   }
55199636c4e1Sdanielk1977   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
55209636c4e1Sdanielk1977   rc = sqlite3_create_function(db, argv[2], -1, SQLITE_UTF8, 0, 0, 0, 0);
55214f0c5878Sdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
55229636c4e1Sdanielk1977   return TCL_OK;
55239636c4e1Sdanielk1977 }
55249636c4e1Sdanielk1977 
55259636c4e1Sdanielk1977 /*
55269636c4e1Sdanielk1977 ** Usage: sqlite_delete_collation DB collation-name
55279636c4e1Sdanielk1977 **
55289636c4e1Sdanielk1977 ** Delete the collation sequence 'collation-name' from database handle
55299636c4e1Sdanielk1977 ** DB. It is assumed that the collation sequence was created as UTF8 (the
55309636c4e1Sdanielk1977 ** way the TCL interface does it).
55319636c4e1Sdanielk1977 */
delete_collation(void * clientData,Tcl_Interp * interp,int argc,char ** argv)55327617e4a8Smistachkin static int SQLITE_TCLAPI delete_collation(
55339636c4e1Sdanielk1977   void * clientData,
55349636c4e1Sdanielk1977   Tcl_Interp *interp,
55359636c4e1Sdanielk1977   int argc,
55369636c4e1Sdanielk1977   char **argv
55379636c4e1Sdanielk1977 ){
55389636c4e1Sdanielk1977   int rc;
55399636c4e1Sdanielk1977   sqlite3 *db;
55409636c4e1Sdanielk1977   if( argc!=3 ){
55419636c4e1Sdanielk1977     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
55429636c4e1Sdanielk1977         " DB function-name", 0);
55439636c4e1Sdanielk1977     return TCL_ERROR;
55449636c4e1Sdanielk1977   }
55459636c4e1Sdanielk1977   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
55469636c4e1Sdanielk1977   rc = sqlite3_create_collation(db, argv[2], SQLITE_UTF8, 0, 0);
55474f0c5878Sdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
55489636c4e1Sdanielk1977   return TCL_OK;
55499636c4e1Sdanielk1977 }
55509636c4e1Sdanielk1977 
55519636c4e1Sdanielk1977 /*
55523e1d8e63Sdrh ** Usage: sqlite3_get_autocommit DB
55533e1d8e63Sdrh **
55543e1d8e63Sdrh ** Return true if the database DB is currently in auto-commit mode.
55553e1d8e63Sdrh ** Return false if not.
55563e1d8e63Sdrh */
get_autocommit(void * clientData,Tcl_Interp * interp,int argc,char ** argv)55577617e4a8Smistachkin static int SQLITE_TCLAPI get_autocommit(
55583e1d8e63Sdrh   void * clientData,
55593e1d8e63Sdrh   Tcl_Interp *interp,
55603e1d8e63Sdrh   int argc,
55613e1d8e63Sdrh   char **argv
55623e1d8e63Sdrh ){
55633e1d8e63Sdrh   char zBuf[30];
55643e1d8e63Sdrh   sqlite3 *db;
55653e1d8e63Sdrh   if( argc!=2 ){
55663e1d8e63Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
55673e1d8e63Sdrh         " DB", 0);
55683e1d8e63Sdrh     return TCL_ERROR;
55693e1d8e63Sdrh   }
55703e1d8e63Sdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
557165545b59Sdrh   sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", sqlite3_get_autocommit(db));
55723e1d8e63Sdrh   Tcl_AppendResult(interp, zBuf, 0);
55733e1d8e63Sdrh   return TCL_OK;
55743e1d8e63Sdrh }
55753e1d8e63Sdrh 
55763e1d8e63Sdrh /*
55773086765bSdrh ** Usage: sqlite3_busy_timeout DB MS
55783086765bSdrh **
55793086765bSdrh ** Set the busy timeout.  This is more easily done using the timeout
55803086765bSdrh ** method of the TCL interface.  But we need a way to test the case
55813086765bSdrh ** where it returns SQLITE_MISUSE.
55823086765bSdrh */
test_busy_timeout(void * clientData,Tcl_Interp * interp,int argc,char ** argv)55837617e4a8Smistachkin static int SQLITE_TCLAPI test_busy_timeout(
55843086765bSdrh   void * clientData,
55853086765bSdrh   Tcl_Interp *interp,
55863086765bSdrh   int argc,
55873086765bSdrh   char **argv
55883086765bSdrh ){
55893086765bSdrh   int rc, ms;
55903086765bSdrh   sqlite3 *db;
55913086765bSdrh   if( argc!=3 ){
55923086765bSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
55933086765bSdrh         " DB", 0);
55943086765bSdrh     return TCL_ERROR;
55953086765bSdrh   }
55963086765bSdrh   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
55973086765bSdrh   if( Tcl_GetInt(interp, argv[2], &ms) ) return TCL_ERROR;
55983086765bSdrh   rc = sqlite3_busy_timeout(db, ms);
5599e84d8d32Smistachkin   Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
56003086765bSdrh   return TCL_OK;
56013086765bSdrh }
56023086765bSdrh 
56033086765bSdrh /*
560492febd92Sdrh ** Usage:  tcl_variable_type VARIABLENAME
560592febd92Sdrh **
560692febd92Sdrh ** Return the name of the internal representation for the
560792febd92Sdrh ** value of the given variable.
560892febd92Sdrh */
tcl_variable_type(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])56097617e4a8Smistachkin static int SQLITE_TCLAPI tcl_variable_type(
561092febd92Sdrh   void * clientData,
561192febd92Sdrh   Tcl_Interp *interp,
561292febd92Sdrh   int objc,
561392febd92Sdrh   Tcl_Obj *CONST objv[]
561492febd92Sdrh ){
561592febd92Sdrh   Tcl_Obj *pVar;
561692febd92Sdrh   if( objc!=2 ){
561792febd92Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "VARIABLE");
561892febd92Sdrh     return TCL_ERROR;
561992febd92Sdrh   }
562092febd92Sdrh   pVar = Tcl_GetVar2Ex(interp, Tcl_GetString(objv[1]), 0, TCL_LEAVE_ERR_MSG);
562192febd92Sdrh   if( pVar==0 ) return TCL_ERROR;
562292febd92Sdrh   if( pVar->typePtr ){
562392febd92Sdrh     Tcl_SetObjResult(interp, Tcl_NewStringObj(pVar->typePtr->name, -1));
562492febd92Sdrh   }
562592febd92Sdrh   return TCL_OK;
562692febd92Sdrh }
562792febd92Sdrh 
562892febd92Sdrh /*
56296aafc29bSdrh ** Usage:  sqlite3_release_memory ?N?
56306aafc29bSdrh **
56316aafc29bSdrh ** Attempt to release memory currently held but not actually required.
56326aafc29bSdrh ** The integer N is the number of bytes we are trying to release.  The
56336aafc29bSdrh ** return value is the amount of memory actually released.
56346aafc29bSdrh */
test_release_memory(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])56357617e4a8Smistachkin static int SQLITE_TCLAPI test_release_memory(
56366aafc29bSdrh   void * clientData,
56376aafc29bSdrh   Tcl_Interp *interp,
56386aafc29bSdrh   int objc,
56396aafc29bSdrh   Tcl_Obj *CONST objv[]
56406aafc29bSdrh ){
56416f7adc8aSdrh #if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO)
56426aafc29bSdrh   int N;
56436aafc29bSdrh   int amt;
56446aafc29bSdrh   if( objc!=1 && objc!=2 ){
56456aafc29bSdrh     Tcl_WrongNumArgs(interp, 1, objv, "?N?");
56466aafc29bSdrh     return TCL_ERROR;
56476aafc29bSdrh   }
56486aafc29bSdrh   if( objc==2 ){
56496aafc29bSdrh     if( Tcl_GetIntFromObj(interp, objv[1], &N) ) return TCL_ERROR;
56506aafc29bSdrh   }else{
56516aafc29bSdrh     N = -1;
56526aafc29bSdrh   }
56536aafc29bSdrh   amt = sqlite3_release_memory(N);
56546aafc29bSdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(amt));
56556aafc29bSdrh #endif
56566aafc29bSdrh   return TCL_OK;
56576aafc29bSdrh }
56586aafc29bSdrh 
565909419b4bSdrh 
566009419b4bSdrh /*
566109419b4bSdrh ** Usage:  sqlite3_db_release_memory DB
566209419b4bSdrh **
566309419b4bSdrh ** Attempt to release memory currently held by database DB.  Return the
566409419b4bSdrh ** result code (which in the current implementation is always zero).
566509419b4bSdrh */
test_db_release_memory(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])56667617e4a8Smistachkin static int SQLITE_TCLAPI test_db_release_memory(
566709419b4bSdrh   void * clientData,
566809419b4bSdrh   Tcl_Interp *interp,
566909419b4bSdrh   int objc,
567009419b4bSdrh   Tcl_Obj *CONST objv[]
567109419b4bSdrh ){
567209419b4bSdrh   sqlite3 *db;
567309419b4bSdrh   int rc;
567409419b4bSdrh   if( objc!=2 ){
567509419b4bSdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB");
567609419b4bSdrh     return TCL_ERROR;
567709419b4bSdrh   }
567809419b4bSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
567909419b4bSdrh   rc = sqlite3_db_release_memory(db);
568009419b4bSdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
568109419b4bSdrh   return TCL_OK;
568209419b4bSdrh }
568309419b4bSdrh 
56846aafc29bSdrh /*
56856fa255fdSdan ** Usage:  sqlite3_db_cacheflush DB
56866fa255fdSdan **
56876fa255fdSdan ** Attempt to flush any dirty pages to disk.
56886fa255fdSdan */
test_db_cacheflush(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])56897617e4a8Smistachkin static int SQLITE_TCLAPI test_db_cacheflush(
56906fa255fdSdan   void * clientData,
56916fa255fdSdan   Tcl_Interp *interp,
56926fa255fdSdan   int objc,
56936fa255fdSdan   Tcl_Obj *CONST objv[]
56946fa255fdSdan ){
56956fa255fdSdan   sqlite3 *db;
56966fa255fdSdan   int rc;
56976fa255fdSdan   if( objc!=2 ){
56986fa255fdSdan     Tcl_WrongNumArgs(interp, 1, objv, "DB");
56996fa255fdSdan     return TCL_ERROR;
57006fa255fdSdan   }
57016fa255fdSdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
57026fa255fdSdan   rc = sqlite3_db_cacheflush(db);
57036fa255fdSdan   if( rc ){
57046fa255fdSdan     Tcl_SetResult(interp, (char *)sqlite3ErrStr(rc), TCL_STATIC);
57056fa255fdSdan     return TCL_ERROR;
57066fa255fdSdan   }
57076fa255fdSdan 
57086fa255fdSdan   Tcl_ResetResult(interp);
57096fa255fdSdan   return TCL_OK;
57106fa255fdSdan }
57116fa255fdSdan 
57126fa255fdSdan /*
57130e80e509Sdrh ** Usage:  sqlite3_system_errno DB
57140e80e509Sdrh **
57150e80e509Sdrh ** Return the low-level system errno value.
57160e80e509Sdrh */
test_system_errno(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])57177617e4a8Smistachkin static int SQLITE_TCLAPI test_system_errno(
57180e80e509Sdrh   void * clientData,
57190e80e509Sdrh   Tcl_Interp *interp,
57200e80e509Sdrh   int objc,
57210e80e509Sdrh   Tcl_Obj *CONST objv[]
57220e80e509Sdrh ){
57230e80e509Sdrh   sqlite3 *db;
57240e80e509Sdrh   int iErrno;
57250e80e509Sdrh   if( objc!=2 ){
57260e80e509Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB");
57270e80e509Sdrh     return TCL_ERROR;
57280e80e509Sdrh   }
57290e80e509Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
57300e80e509Sdrh   iErrno = sqlite3_system_errno(db);
57310e80e509Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(iErrno));
57320e80e509Sdrh   return TCL_OK;
57330e80e509Sdrh }
57340e80e509Sdrh 
57350e80e509Sdrh /*
5736283829cbSdrh ** Usage:  sqlite3_db_filename DB DBNAME
5737283829cbSdrh **
5738283829cbSdrh ** Return the name of a file associated with a database.
5739283829cbSdrh */
test_db_filename(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])57407617e4a8Smistachkin static int SQLITE_TCLAPI test_db_filename(
5741283829cbSdrh   void * clientData,
5742283829cbSdrh   Tcl_Interp *interp,
5743283829cbSdrh   int objc,
5744283829cbSdrh   Tcl_Obj *CONST objv[]
5745283829cbSdrh ){
5746283829cbSdrh   sqlite3 *db;
5747283829cbSdrh   const char *zDbName;
5748283829cbSdrh   if( objc!=3 ){
5749283829cbSdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
5750283829cbSdrh     return TCL_ERROR;
5751283829cbSdrh   }
5752283829cbSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
5753283829cbSdrh   zDbName = Tcl_GetString(objv[2]);
5754283829cbSdrh   Tcl_AppendResult(interp, sqlite3_db_filename(db, zDbName), (void*)0);
5755283829cbSdrh   return TCL_OK;
5756283829cbSdrh }
5757283829cbSdrh 
5758283829cbSdrh /*
5759421377e6Sdrh ** Usage:  sqlite3_db_readonly DB DBNAME
5760421377e6Sdrh **
5761421377e6Sdrh ** Return 1 or 0 if DBNAME is readonly or not.  Return -1 if DBNAME does
5762421377e6Sdrh ** not exist.
5763421377e6Sdrh */
test_db_readonly(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])57647617e4a8Smistachkin static int SQLITE_TCLAPI test_db_readonly(
5765421377e6Sdrh   void * clientData,
5766421377e6Sdrh   Tcl_Interp *interp,
5767421377e6Sdrh   int objc,
5768421377e6Sdrh   Tcl_Obj *CONST objv[]
5769421377e6Sdrh ){
5770421377e6Sdrh   sqlite3 *db;
5771421377e6Sdrh   const char *zDbName;
5772421377e6Sdrh   if( objc!=3 ){
5773421377e6Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME");
5774421377e6Sdrh     return TCL_ERROR;
5775421377e6Sdrh   }
5776421377e6Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
5777421377e6Sdrh   zDbName = Tcl_GetString(objv[2]);
5778421377e6Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_db_readonly(db, zDbName)));
5779421377e6Sdrh   return TCL_OK;
5780421377e6Sdrh }
5781421377e6Sdrh 
5782421377e6Sdrh /*
57836aafc29bSdrh ** Usage:  sqlite3_soft_heap_limit ?N?
57846aafc29bSdrh **
57856aafc29bSdrh ** Query or set the soft heap limit for the current thread.  The
57866aafc29bSdrh ** limit is only changed if the N is present.  The previous limit
57876aafc29bSdrh ** is returned.
57886aafc29bSdrh */
test_soft_heap_limit(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])57897617e4a8Smistachkin static int SQLITE_TCLAPI test_soft_heap_limit(
57906aafc29bSdrh   void * clientData,
57916aafc29bSdrh   Tcl_Interp *interp,
57926aafc29bSdrh   int objc,
57936aafc29bSdrh   Tcl_Obj *CONST objv[]
57946aafc29bSdrh ){
5795f82ccf64Sdrh   sqlite3_int64 amt;
5796b3f787f4Sdrh   Tcl_WideInt N = -1;
57976aafc29bSdrh   if( objc!=1 && objc!=2 ){
57986aafc29bSdrh     Tcl_WrongNumArgs(interp, 1, objv, "?N?");
57996aafc29bSdrh     return TCL_ERROR;
58006aafc29bSdrh   }
58016aafc29bSdrh   if( objc==2 ){
5802f82ccf64Sdrh     if( Tcl_GetWideIntFromObj(interp, objv[1], &N) ) return TCL_ERROR;
58036aafc29bSdrh   }
5804f82ccf64Sdrh   amt = sqlite3_soft_heap_limit64(N);
5805f82ccf64Sdrh   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(amt));
58066aafc29bSdrh   return TCL_OK;
58076aafc29bSdrh }
58086aafc29bSdrh 
58096aafc29bSdrh /*
581010c0e711Sdrh ** Usage:  sqlite3_hard_heap_limit ?N?
581110c0e711Sdrh **
581210c0e711Sdrh ** Query or set the hard heap limit for the current thread.  The
581310c0e711Sdrh ** limit is only changed if the N is present.  The previous limit
581410c0e711Sdrh ** is returned.
581510c0e711Sdrh */
test_hard_heap_limit(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])581610c0e711Sdrh static int SQLITE_TCLAPI test_hard_heap_limit(
581710c0e711Sdrh   void * clientData,
581810c0e711Sdrh   Tcl_Interp *interp,
581910c0e711Sdrh   int objc,
582010c0e711Sdrh   Tcl_Obj *CONST objv[]
582110c0e711Sdrh ){
582210c0e711Sdrh   sqlite3_int64 amt;
582310c0e711Sdrh   Tcl_WideInt N = -1;
582410c0e711Sdrh   if( objc!=1 && objc!=2 ){
582510c0e711Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "?N?");
582610c0e711Sdrh     return TCL_ERROR;
582710c0e711Sdrh   }
582810c0e711Sdrh   if( objc==2 ){
582910c0e711Sdrh     if( Tcl_GetWideIntFromObj(interp, objv[1], &N) ) return TCL_ERROR;
583010c0e711Sdrh   }
583110c0e711Sdrh   amt = sqlite3_hard_heap_limit64(N);
583210c0e711Sdrh   Tcl_SetObjResult(interp, Tcl_NewWideIntObj(amt));
583310c0e711Sdrh   return TCL_OK;
583410c0e711Sdrh }
583510c0e711Sdrh 
583610c0e711Sdrh /*
5837b4bc7057Sdrh ** Usage:   sqlite3_thread_cleanup
5838b4bc7057Sdrh **
5839b4bc7057Sdrh ** Call the sqlite3_thread_cleanup API.
5840b4bc7057Sdrh */
test_thread_cleanup(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])58417617e4a8Smistachkin static int SQLITE_TCLAPI test_thread_cleanup(
5842b4bc7057Sdrh   void * clientData,
5843b4bc7057Sdrh   Tcl_Interp *interp,
5844b4bc7057Sdrh   int objc,
5845b4bc7057Sdrh   Tcl_Obj *CONST objv[]
5846b4bc7057Sdrh ){
5847eec556d3Sshane #ifndef SQLITE_OMIT_DEPRECATED
5848b4bc7057Sdrh   sqlite3_thread_cleanup();
5849eec556d3Sshane #endif
5850b4bc7057Sdrh   return TCL_OK;
5851b4bc7057Sdrh }
5852b4bc7057Sdrh 
5853b4bc7057Sdrh /*
5854c6ba55f4Sdrh ** Usage:   sqlite3_pager_refcounts  DB
5855c6ba55f4Sdrh **
5856f5345443Sdrh ** Return a list of numbers which are the PagerRefcount for all
5857f5345443Sdrh ** pagers on each database connection.
5858c6ba55f4Sdrh */
test_pager_refcounts(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])58597617e4a8Smistachkin static int SQLITE_TCLAPI test_pager_refcounts(
5860c6ba55f4Sdrh   void * clientData,
5861c6ba55f4Sdrh   Tcl_Interp *interp,
5862c6ba55f4Sdrh   int objc,
5863c6ba55f4Sdrh   Tcl_Obj *CONST objv[]
5864c6ba55f4Sdrh ){
5865c6ba55f4Sdrh   sqlite3 *db;
5866c6ba55f4Sdrh   int i;
5867c6ba55f4Sdrh   int v, *a;
5868c6ba55f4Sdrh   Tcl_Obj *pResult;
5869c6ba55f4Sdrh 
5870c6ba55f4Sdrh   if( objc!=2 ){
5871c6ba55f4Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
5872f5345443Sdrh         Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
5873c6ba55f4Sdrh     return TCL_ERROR;
5874c6ba55f4Sdrh   }
5875c6ba55f4Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
5876c6ba55f4Sdrh   pResult = Tcl_NewObj();
5877c6ba55f4Sdrh   for(i=0; i<db->nDb; i++){
5878c6ba55f4Sdrh     if( db->aDb[i].pBt==0 ){
5879c6ba55f4Sdrh       v = -1;
5880c6ba55f4Sdrh     }else{
588127641703Sdrh       sqlite3_mutex_enter(db->mutex);
5882c6ba55f4Sdrh       a = sqlite3PagerStats(sqlite3BtreePager(db->aDb[i].pBt));
5883c6ba55f4Sdrh       v = a[0];
588427641703Sdrh       sqlite3_mutex_leave(db->mutex);
5885c6ba55f4Sdrh     }
5886c6ba55f4Sdrh     Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(v));
5887c6ba55f4Sdrh   }
5888c6ba55f4Sdrh   Tcl_SetObjResult(interp, pResult);
5889c6ba55f4Sdrh   return TCL_OK;
5890c6ba55f4Sdrh }
5891c6ba55f4Sdrh 
5892c6ba55f4Sdrh 
5893c6ba55f4Sdrh /*
589480788d8bSdrh ** tclcmd:   working_64bit_int
589580788d8bSdrh **
589680788d8bSdrh ** Some TCL builds (ex: cygwin) do not support 64-bit integers.  This
589780788d8bSdrh ** leads to a number of test failures.  The present command checks the
589880788d8bSdrh ** TCL build to see whether or not it supports 64-bit integers.  It
589980788d8bSdrh ** returns TRUE if it does and FALSE if not.
590080788d8bSdrh **
590180788d8bSdrh ** This command is used to warn users that their TCL build is defective
590280788d8bSdrh ** and that the errors they are seeing in the test scripts might be
590380788d8bSdrh ** a result of their defective TCL rather than problems in SQLite.
590480788d8bSdrh */
working_64bit_int(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])59057617e4a8Smistachkin static int SQLITE_TCLAPI working_64bit_int(
590680788d8bSdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
590780788d8bSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
590880788d8bSdrh   int objc,              /* Number of arguments */
590980788d8bSdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
591080788d8bSdrh ){
591180788d8bSdrh   Tcl_Obj *pTestObj;
591280788d8bSdrh   int working = 0;
591380788d8bSdrh 
591480788d8bSdrh   pTestObj = Tcl_NewWideIntObj(1000000*(i64)1234567890);
591580788d8bSdrh   working = strcmp(Tcl_GetString(pTestObj), "1234567890000000")==0;
591680788d8bSdrh   Tcl_DecrRefCount(pTestObj);
591780788d8bSdrh   Tcl_SetObjResult(interp, Tcl_NewBooleanObj(working));
591880788d8bSdrh   return TCL_OK;
591980788d8bSdrh }
592080788d8bSdrh 
592180788d8bSdrh 
592280788d8bSdrh /*
59239bc5449fSdrh ** tclcmd:   vfs_unlink_test
59249bc5449fSdrh **
59259bc5449fSdrh ** This TCL command unregisters the primary VFS and then registers
59269bc5449fSdrh ** it back again.  This is used to test the ability to register a
59279bc5449fSdrh ** VFS when none are previously registered, and the ability to
59289bc5449fSdrh ** unregister the only available VFS.  Ticket #2738
59299bc5449fSdrh */
vfs_unlink_test(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])59307617e4a8Smistachkin static int SQLITE_TCLAPI vfs_unlink_test(
59319bc5449fSdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
59329bc5449fSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
59339bc5449fSdrh   int objc,              /* Number of arguments */
59349bc5449fSdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
59359bc5449fSdrh ){
59369bc5449fSdrh   int i;
593791fd4d46Sdrh   sqlite3_vfs *pMain;
59389bc5449fSdrh   sqlite3_vfs *apVfs[20];
593991fd4d46Sdrh   sqlite3_vfs one, two;
59409bc5449fSdrh 
594191fd4d46Sdrh   sqlite3_vfs_unregister(0);   /* Unregister of NULL is harmless */
594291fd4d46Sdrh   one.zName = "__one";
594391fd4d46Sdrh   two.zName = "__two";
594491fd4d46Sdrh 
594591fd4d46Sdrh   /* Calling sqlite3_vfs_register with 2nd argument of 0 does not
594691fd4d46Sdrh   ** change the default VFS
594791fd4d46Sdrh   */
594891fd4d46Sdrh   pMain = sqlite3_vfs_find(0);
594991fd4d46Sdrh   sqlite3_vfs_register(&one, 0);
595091fd4d46Sdrh   assert( pMain==0 || pMain==sqlite3_vfs_find(0) );
595191fd4d46Sdrh   sqlite3_vfs_register(&two, 0);
595291fd4d46Sdrh   assert( pMain==0 || pMain==sqlite3_vfs_find(0) );
595391fd4d46Sdrh 
595491fd4d46Sdrh   /* We can find a VFS by its name */
595591fd4d46Sdrh   assert( sqlite3_vfs_find("__one")==&one );
595691fd4d46Sdrh   assert( sqlite3_vfs_find("__two")==&two );
595791fd4d46Sdrh 
595891fd4d46Sdrh   /* Calling sqlite_vfs_register with non-zero second parameter changes the
595991fd4d46Sdrh   ** default VFS, even if the 1st parameter is an existig VFS that is
596091fd4d46Sdrh   ** previously registered as the non-default.
596191fd4d46Sdrh   */
596291fd4d46Sdrh   sqlite3_vfs_register(&one, 1);
596391fd4d46Sdrh   assert( sqlite3_vfs_find("__one")==&one );
596491fd4d46Sdrh   assert( sqlite3_vfs_find("__two")==&two );
596591fd4d46Sdrh   assert( sqlite3_vfs_find(0)==&one );
596691fd4d46Sdrh   sqlite3_vfs_register(&two, 1);
596791fd4d46Sdrh   assert( sqlite3_vfs_find("__one")==&one );
596891fd4d46Sdrh   assert( sqlite3_vfs_find("__two")==&two );
596991fd4d46Sdrh   assert( sqlite3_vfs_find(0)==&two );
597091fd4d46Sdrh   if( pMain ){
597191fd4d46Sdrh     sqlite3_vfs_register(pMain, 1);
597291fd4d46Sdrh     assert( sqlite3_vfs_find("__one")==&one );
597391fd4d46Sdrh     assert( sqlite3_vfs_find("__two")==&two );
597491fd4d46Sdrh     assert( sqlite3_vfs_find(0)==pMain );
597591fd4d46Sdrh   }
597691fd4d46Sdrh 
597791fd4d46Sdrh   /* Unlink the default VFS.  Repeat until there are no more VFSes
597891fd4d46Sdrh   ** registered.
597991fd4d46Sdrh   */
59809bc5449fSdrh   for(i=0; i<sizeof(apVfs)/sizeof(apVfs[0]); i++){
59819bc5449fSdrh     apVfs[i] = sqlite3_vfs_find(0);
59829bc5449fSdrh     if( apVfs[i] ){
59839bc5449fSdrh       assert( apVfs[i]==sqlite3_vfs_find(apVfs[i]->zName) );
59849bc5449fSdrh       sqlite3_vfs_unregister(apVfs[i]);
59859bc5449fSdrh       assert( 0==sqlite3_vfs_find(apVfs[i]->zName) );
59869bc5449fSdrh     }
59879bc5449fSdrh   }
59889bc5449fSdrh   assert( 0==sqlite3_vfs_find(0) );
598991fd4d46Sdrh 
59901f045330Smlcreech   /* Register the main VFS as non-default (will be made default, since
59911f045330Smlcreech   ** it'll be the only one in existence).
59921f045330Smlcreech   */
59931f045330Smlcreech   sqlite3_vfs_register(pMain, 0);
59941f045330Smlcreech   assert( sqlite3_vfs_find(0)==pMain );
59951f045330Smlcreech 
59961f045330Smlcreech   /* Un-register the main VFS again to restore an empty VFS list */
59971f045330Smlcreech   sqlite3_vfs_unregister(pMain);
59981f045330Smlcreech   assert( 0==sqlite3_vfs_find(0) );
59991f045330Smlcreech 
600091fd4d46Sdrh   /* Relink all VFSes in reverse order. */
60019bc5449fSdrh   for(i=sizeof(apVfs)/sizeof(apVfs[0])-1; i>=0; i--){
60029bc5449fSdrh     if( apVfs[i] ){
60039bc5449fSdrh       sqlite3_vfs_register(apVfs[i], 1);
60049bc5449fSdrh       assert( apVfs[i]==sqlite3_vfs_find(0) );
60059bc5449fSdrh       assert( apVfs[i]==sqlite3_vfs_find(apVfs[i]->zName) );
60069bc5449fSdrh     }
60079bc5449fSdrh   }
600891fd4d46Sdrh 
600991fd4d46Sdrh   /* Unregister out sample VFSes. */
601091fd4d46Sdrh   sqlite3_vfs_unregister(&one);
601191fd4d46Sdrh   sqlite3_vfs_unregister(&two);
601291fd4d46Sdrh 
601391fd4d46Sdrh   /* Unregistering a VFS that is not currently registered is harmless */
601491fd4d46Sdrh   sqlite3_vfs_unregister(&one);
601591fd4d46Sdrh   sqlite3_vfs_unregister(&two);
601691fd4d46Sdrh   assert( sqlite3_vfs_find("__one")==0 );
601791fd4d46Sdrh   assert( sqlite3_vfs_find("__two")==0 );
601891fd4d46Sdrh 
601991fd4d46Sdrh   /* We should be left with the original default VFS back as the
602091fd4d46Sdrh   ** original */
602191fd4d46Sdrh   assert( sqlite3_vfs_find(0)==pMain );
602291fd4d46Sdrh 
60239bc5449fSdrh   return TCL_OK;
60249bc5449fSdrh }
60259bc5449fSdrh 
602693aed5a1Sdrh /*
6027c8d75674Sdrh ** tclcmd:   vfs_initfail_test
6028c8d75674Sdrh **
6029c8d75674Sdrh ** This TCL command attempts to vfs_find and vfs_register when the
6030c8d75674Sdrh ** sqlite3_initialize() interface is failing.  All calls should fail.
6031c8d75674Sdrh */
vfs_initfail_test(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])60327617e4a8Smistachkin static int SQLITE_TCLAPI vfs_initfail_test(
6033c8d75674Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6034c8d75674Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6035c8d75674Sdrh   int objc,              /* Number of arguments */
6036c8d75674Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
6037c8d75674Sdrh ){
6038c8d75674Sdrh   sqlite3_vfs one;
6039c8d75674Sdrh   one.zName = "__one";
6040c8d75674Sdrh 
6041c8d75674Sdrh   if( sqlite3_vfs_find(0) ) return TCL_ERROR;
6042c8d75674Sdrh   sqlite3_vfs_register(&one, 0);
6043c8d75674Sdrh   if( sqlite3_vfs_find(0) ) return TCL_ERROR;
6044c8d75674Sdrh   sqlite3_vfs_register(&one, 1);
6045c8d75674Sdrh   if( sqlite3_vfs_find(0) ) return TCL_ERROR;
6046c8d75674Sdrh   return TCL_OK;
6047c8d75674Sdrh }
6048c8d75674Sdrh 
6049c8d75674Sdrh /*
6050a2820970Sdrh ** Saved VFSes
6051a2820970Sdrh */
6052a2820970Sdrh static sqlite3_vfs *apVfs[20];
6053a2820970Sdrh static int nVfs = 0;
6054a2820970Sdrh 
6055a2820970Sdrh /*
6056a2820970Sdrh ** tclcmd:   vfs_unregister_all
6057a2820970Sdrh **
6058a2820970Sdrh ** Unregister all VFSes.
6059a2820970Sdrh */
vfs_unregister_all(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])60607617e4a8Smistachkin static int SQLITE_TCLAPI vfs_unregister_all(
6061a2820970Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6062a2820970Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6063a2820970Sdrh   int objc,              /* Number of arguments */
6064a2820970Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
6065a2820970Sdrh ){
6066a2820970Sdrh   int i;
6067a2820970Sdrh   for(i=0; i<ArraySize(apVfs); i++){
6068a2820970Sdrh     apVfs[i] = sqlite3_vfs_find(0);
6069a2820970Sdrh     if( apVfs[i]==0 ) break;
6070a2820970Sdrh     sqlite3_vfs_unregister(apVfs[i]);
6071a2820970Sdrh   }
6072a2820970Sdrh   nVfs = i;
6073a2820970Sdrh   return TCL_OK;
6074a2820970Sdrh }
6075a2820970Sdrh /*
6076a2820970Sdrh ** tclcmd:   vfs_reregister_all
6077a2820970Sdrh **
607805accd22Sdan ** Restore all VFSes that were removed using vfs_unregister_all. Taking
607905accd22Sdan ** care to put the linked list back together in the same order as it was
608005accd22Sdan ** in before vfs_unregister_all was invoked.
6081a2820970Sdrh */
vfs_reregister_all(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])60827617e4a8Smistachkin static int SQLITE_TCLAPI vfs_reregister_all(
6083a2820970Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6084a2820970Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6085a2820970Sdrh   int objc,              /* Number of arguments */
6086a2820970Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
6087a2820970Sdrh ){
6088a2820970Sdrh   int i;
608905accd22Sdan   for(i=nVfs-1; i>=0; i--){
609005accd22Sdan     sqlite3_vfs_register(apVfs[i], 1);
6091a2820970Sdrh   }
6092a2820970Sdrh   return TCL_OK;
6093a2820970Sdrh }
6094a2820970Sdrh 
6095a2820970Sdrh 
6096a2820970Sdrh /*
609755176259Sdrh ** tclcmd:   file_control_test DB
609855176259Sdrh **
609955176259Sdrh ** This TCL command runs the sqlite3_file_control interface and
610055176259Sdrh ** verifies correct operation of the same.
610155176259Sdrh */
file_control_test(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])61027617e4a8Smistachkin static int SQLITE_TCLAPI file_control_test(
610355176259Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
610455176259Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
610555176259Sdrh   int objc,              /* Number of arguments */
610655176259Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
610755176259Sdrh ){
610855176259Sdrh   int iArg = 0;
610955176259Sdrh   sqlite3 *db;
611055176259Sdrh   int rc;
611155176259Sdrh 
611255176259Sdrh   if( objc!=2 ){
611355176259Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
611455176259Sdrh         Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
611555176259Sdrh     return TCL_ERROR;
611655176259Sdrh   }
611755176259Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
611855176259Sdrh   rc = sqlite3_file_control(db, 0, 0, &iArg);
61190b52b7d0Sdrh   assert( rc==SQLITE_NOTFOUND );
612055176259Sdrh   rc = sqlite3_file_control(db, "notadatabase", SQLITE_FCNTL_LOCKSTATE, &iArg);
612155176259Sdrh   assert( rc==SQLITE_ERROR );
612255176259Sdrh   rc = sqlite3_file_control(db, "main", -1, &iArg);
61230b52b7d0Sdrh   assert( rc==SQLITE_NOTFOUND );
612455176259Sdrh   rc = sqlite3_file_control(db, "temp", -1, &iArg);
61250b52b7d0Sdrh   assert( rc==SQLITE_NOTFOUND || rc==SQLITE_ERROR );
6126aebf413dSaswift 
612755176259Sdrh   return TCL_OK;
612855176259Sdrh }
612955176259Sdrh 
6130aebf413dSaswift 
6131aebf413dSaswift /*
6132aebf413dSaswift ** tclcmd:   file_control_lasterrno_test DB
6133aebf413dSaswift **
6134aebf413dSaswift ** This TCL command runs the sqlite3_file_control interface and
6135aebf413dSaswift ** verifies correct operation of the SQLITE_LAST_ERRNO verb.
6136aebf413dSaswift */
file_control_lasterrno_test(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])61377617e4a8Smistachkin static int SQLITE_TCLAPI file_control_lasterrno_test(
6138aebf413dSaswift   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6139aebf413dSaswift   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6140aebf413dSaswift   int objc,              /* Number of arguments */
6141aebf413dSaswift   Tcl_Obj *CONST objv[]  /* Command arguments */
6142aebf413dSaswift ){
6143aebf413dSaswift   int iArg = 0;
6144aebf413dSaswift   sqlite3 *db;
6145aebf413dSaswift   int rc;
6146aebf413dSaswift 
6147aebf413dSaswift   if( objc!=2 ){
6148aebf413dSaswift     Tcl_AppendResult(interp, "wrong # args: should be \"",
6149aebf413dSaswift         Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
6150aebf413dSaswift     return TCL_ERROR;
6151aebf413dSaswift   }
61529db299fbSshane   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
61539db299fbSshane     return TCL_ERROR;
61549db299fbSshane   }
6155aebf413dSaswift   rc = sqlite3_file_control(db, NULL, SQLITE_LAST_ERRNO, &iArg);
61569db299fbSshane   if( rc ){
61579db299fbSshane     Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
61589db299fbSshane     return TCL_ERROR;
61599db299fbSshane   }
6160aebf413dSaswift   if( iArg!=0 ) {
6161aebf413dSaswift     Tcl_AppendResult(interp, "Unexpected non-zero errno: ",
6162aebf413dSaswift                      Tcl_GetStringFromObj(Tcl_NewIntObj(iArg), 0), " ", 0);
6163aebf413dSaswift     return TCL_ERROR;
6164aebf413dSaswift   }
6165aebf413dSaswift   return TCL_OK;
6166aebf413dSaswift }
6167aebf413dSaswift 
6168aebf413dSaswift /*
6169ea99a31cSdrh ** tclcmd:   file_control_data_version DB DBNAME
6170ea99a31cSdrh **
6171ea99a31cSdrh ** This TCL command runs the sqlite3_file_control with the
6172ea99a31cSdrh ** SQLITE_FCNTL_DATA_VERSION opcode, returning the result.
6173ea99a31cSdrh */
file_control_data_version(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])6174ea99a31cSdrh static int SQLITE_TCLAPI file_control_data_version(
6175ea99a31cSdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6176ea99a31cSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6177ea99a31cSdrh   int objc,              /* Number of arguments */
6178ea99a31cSdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
6179ea99a31cSdrh ){
6180ea99a31cSdrh   unsigned int iVers;             /* data version */
6181ea99a31cSdrh   char *zDb;                      /* Db name ("main", "temp" etc.) */
6182ea99a31cSdrh   sqlite3 *db;                    /* Database handle */
6183ea99a31cSdrh   int rc;                         /* file_control() return code */
6184ea99a31cSdrh   char zBuf[100];
6185ea99a31cSdrh 
6186ea99a31cSdrh   if( objc!=3 && objc!=2 ){
6187ea99a31cSdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB [DBNAME]");
6188ea99a31cSdrh     return TCL_ERROR;
6189ea99a31cSdrh   }
6190ea99a31cSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
6191ea99a31cSdrh    return TCL_ERROR;
6192ea99a31cSdrh   }
6193ea99a31cSdrh   zDb = objc==3 ? Tcl_GetString(objv[2]) : NULL;
6194ea99a31cSdrh 
6195ea99a31cSdrh   rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_DATA_VERSION, (void *)&iVers);
6196ea99a31cSdrh   if( rc ){
6197ea99a31cSdrh     Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
6198ea99a31cSdrh     return TCL_ERROR;
6199ea99a31cSdrh   }else{
6200ea99a31cSdrh     sqlite3_snprintf(sizeof(zBuf),zBuf,"%u",iVers);
6201ea99a31cSdrh     Tcl_SetResult(interp, (char *)zBuf, TCL_VOLATILE);
6202ea99a31cSdrh     return TCL_OK;
6203ea99a31cSdrh   }
6204ea99a31cSdrh }
6205ea99a31cSdrh 
6206ea99a31cSdrh /*
62076e09d69cSdan ** tclcmd:   file_control_chunksize_test DB DBNAME SIZE
62086e09d69cSdan **
62096e09d69cSdan ** This TCL command runs the sqlite3_file_control interface and
62106e09d69cSdan ** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and
62116e09d69cSdan ** SQLITE_SET_LOCKPROXYFILE verbs.
62126e09d69cSdan */
file_control_chunksize_test(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])62137617e4a8Smistachkin static int SQLITE_TCLAPI file_control_chunksize_test(
62146e09d69cSdan   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
62156e09d69cSdan   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
62166e09d69cSdan   int objc,              /* Number of arguments */
62176e09d69cSdan   Tcl_Obj *CONST objv[]  /* Command arguments */
62186e09d69cSdan ){
62196e09d69cSdan   int nSize;                      /* New chunk size */
62206e09d69cSdan   char *zDb;                      /* Db name ("main", "temp" etc.) */
62216e09d69cSdan   sqlite3 *db;                    /* Database handle */
62226e09d69cSdan   int rc;                         /* file_control() return code */
62236e09d69cSdan 
62246e09d69cSdan   if( objc!=4 ){
62256e09d69cSdan     Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SIZE");
62266e09d69cSdan     return TCL_ERROR;
62276e09d69cSdan   }
62286e09d69cSdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db)
62296e09d69cSdan    || Tcl_GetIntFromObj(interp, objv[3], &nSize)
62306e09d69cSdan   ){
62316e09d69cSdan    return TCL_ERROR;
62326e09d69cSdan   }
62336e09d69cSdan   zDb = Tcl_GetString(objv[2]);
62346e09d69cSdan   if( zDb[0]=='\0' ) zDb = NULL;
62356e09d69cSdan 
62366e09d69cSdan   rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_CHUNK_SIZE, (void *)&nSize);
62376e09d69cSdan   if( rc ){
6238e84d8d32Smistachkin     Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
62396e09d69cSdan     return TCL_ERROR;
62406e09d69cSdan   }
62416e09d69cSdan   return TCL_OK;
62426e09d69cSdan }
62436e09d69cSdan 
62446e09d69cSdan /*
6245661d71afSdan ** tclcmd:   file_control_sizehint_test DB DBNAME SIZE
6246661d71afSdan **
6247fdd7f71eSdrh ** This TCL command runs the sqlite3_file_control interface
6248fdd7f71eSdrh ** with SQLITE_FCNTL_SIZE_HINT
6249661d71afSdan */
file_control_sizehint_test(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])62507617e4a8Smistachkin static int SQLITE_TCLAPI file_control_sizehint_test(
6251661d71afSdan   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6252661d71afSdan   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6253661d71afSdan   int objc,              /* Number of arguments */
6254661d71afSdan   Tcl_Obj *CONST objv[]  /* Command arguments */
6255661d71afSdan ){
6256b3f787f4Sdrh   Tcl_WideInt nSize;              /* Hinted size */
6257661d71afSdan   char *zDb;                      /* Db name ("main", "temp" etc.) */
6258661d71afSdan   sqlite3 *db;                    /* Database handle */
6259661d71afSdan   int rc;                         /* file_control() return code */
6260661d71afSdan 
6261661d71afSdan   if( objc!=4 ){
6262661d71afSdan     Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SIZE");
6263661d71afSdan     return TCL_ERROR;
6264661d71afSdan   }
6265661d71afSdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db)
6266661d71afSdan    || Tcl_GetWideIntFromObj(interp, objv[3], &nSize)
6267661d71afSdan   ){
6268661d71afSdan    return TCL_ERROR;
6269661d71afSdan   }
6270661d71afSdan   zDb = Tcl_GetString(objv[2]);
6271661d71afSdan   if( zDb[0]=='\0' ) zDb = NULL;
6272661d71afSdan 
6273661d71afSdan   rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_SIZE_HINT, (void *)&nSize);
6274661d71afSdan   if( rc ){
6275e84d8d32Smistachkin     Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_STATIC);
6276661d71afSdan     return TCL_ERROR;
6277661d71afSdan   }
6278661d71afSdan   return TCL_OK;
6279661d71afSdan }
6280661d71afSdan 
6281661d71afSdan /*
6282ad24581eSdrh ** tclcmd:   file_control_lockproxy_test DB PWD
6283aebf413dSaswift **
6284aebf413dSaswift ** This TCL command runs the sqlite3_file_control interface and
6285aebf413dSaswift ** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and
6286aebf413dSaswift ** SQLITE_SET_LOCKPROXYFILE verbs.
6287aebf413dSaswift */
file_control_lockproxy_test(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])62887617e4a8Smistachkin static int SQLITE_TCLAPI file_control_lockproxy_test(
6289aebf413dSaswift   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6290aebf413dSaswift   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6291aebf413dSaswift   int objc,              /* Number of arguments */
6292aebf413dSaswift   Tcl_Obj *CONST objv[]  /* Command arguments */
6293aebf413dSaswift ){
6294aebf413dSaswift   sqlite3 *db;
6295aebf413dSaswift 
6296ad24581eSdrh   if( objc!=3 ){
6297aebf413dSaswift     Tcl_AppendResult(interp, "wrong # args: should be \"",
6298ad24581eSdrh                      Tcl_GetStringFromObj(objv[0], 0), " DB PWD", 0);
6299aebf413dSaswift     return TCL_ERROR;
6300aebf413dSaswift   }
63019db299fbSshane   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
63029db299fbSshane    return TCL_ERROR;
63039db299fbSshane   }
6304aebf413dSaswift 
63059b35ea62Sdrh #if !defined(SQLITE_ENABLE_LOCKING_STYLE)
6306d2cb50b7Sdrh #  if defined(__APPLE__)
63079b35ea62Sdrh #    define SQLITE_ENABLE_LOCKING_STYLE 1
63089b35ea62Sdrh #  else
63099b35ea62Sdrh #    define SQLITE_ENABLE_LOCKING_STYLE 0
63109b35ea62Sdrh #  endif
63119b35ea62Sdrh #endif
6312d2cb50b7Sdrh #if SQLITE_ENABLE_LOCKING_STYLE && defined(__APPLE__)
6313aebf413dSaswift   {
6314aebf413dSaswift     char *testPath;
6315103fe743Sdrh     int rc;
6316caffb1a5Sdrh     int nPwd;
6317caffb1a5Sdrh     const char *zPwd;
6318ad24581eSdrh     char proxyPath[400];
6319ad24581eSdrh 
6320caffb1a5Sdrh     zPwd = Tcl_GetStringFromObj(objv[2], &nPwd);
6321ad24581eSdrh     if( sizeof(proxyPath)<nPwd+20 ){
6322ad24581eSdrh       Tcl_AppendResult(interp, "PWD too big", (void*)0);
6323ad24581eSdrh       return TCL_ERROR;
6324ad24581eSdrh     }
632565545b59Sdrh     sqlite3_snprintf(sizeof(proxyPath), proxyPath, "%s/test.proxy", zPwd);
6326aebf413dSaswift     rc = sqlite3_file_control(db, NULL, SQLITE_SET_LOCKPROXYFILE, proxyPath);
63277708e972Sdrh     if( rc ){
63289db299fbSshane       Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
63299db299fbSshane       return TCL_ERROR;
63307708e972Sdrh     }
6331aebf413dSaswift     rc = sqlite3_file_control(db, NULL, SQLITE_GET_LOCKPROXYFILE, &testPath);
6332aebf413dSaswift     if( strncmp(proxyPath,testPath,11) ){
63337708e972Sdrh       Tcl_AppendResult(interp, "Lock proxy file did not match the "
63347708e972Sdrh                                "previously assigned value", 0);
6335aebf413dSaswift       return TCL_ERROR;
6336aebf413dSaswift     }
63377708e972Sdrh     if( rc ){
63387708e972Sdrh       Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
63397708e972Sdrh       return TCL_ERROR;
63407708e972Sdrh     }
6341aebf413dSaswift     rc = sqlite3_file_control(db, NULL, SQLITE_SET_LOCKPROXYFILE, proxyPath);
63427708e972Sdrh     if( rc ){
63437708e972Sdrh       Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
63447708e972Sdrh       return TCL_ERROR;
63457708e972Sdrh     }
6346aebf413dSaswift   }
6347aebf413dSaswift #endif
6348aebf413dSaswift   return TCL_OK;
6349aebf413dSaswift }
6350aebf413dSaswift 
63516b98d67bSmistachkin #if SQLITE_OS_WIN
6352d0cdf012Sdrh /*
6353d0cdf012Sdrh ** tclcmd:   file_control_win32_av_retry DB  NRETRY  DELAY
6354d0cdf012Sdrh **
6355d0cdf012Sdrh ** This TCL command runs the sqlite3_file_control interface with
6356d0cdf012Sdrh ** the SQLITE_FCNTL_WIN32_AV_RETRY opcode.
6357d0cdf012Sdrh */
file_control_win32_av_retry(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])63587617e4a8Smistachkin static int SQLITE_TCLAPI file_control_win32_av_retry(
6359d0cdf012Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6360d0cdf012Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6361d0cdf012Sdrh   int objc,              /* Number of arguments */
6362d0cdf012Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
6363d0cdf012Sdrh ){
6364d0cdf012Sdrh   sqlite3 *db;
6365d0cdf012Sdrh   int rc;
6366d0cdf012Sdrh   int a[2];
6367d0cdf012Sdrh   char z[100];
6368d0cdf012Sdrh 
6369d0cdf012Sdrh   if( objc!=4 ){
6370d0cdf012Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
6371d0cdf012Sdrh         Tcl_GetStringFromObj(objv[0], 0), " DB NRETRY DELAY", 0);
6372d0cdf012Sdrh     return TCL_ERROR;
6373d0cdf012Sdrh   }
6374d0cdf012Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
6375d0cdf012Sdrh     return TCL_ERROR;
6376d0cdf012Sdrh   }
6377d0cdf012Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &a[0]) ) return TCL_ERROR;
6378d0cdf012Sdrh   if( Tcl_GetIntFromObj(interp, objv[3], &a[1]) ) return TCL_ERROR;
6379d0cdf012Sdrh   rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_WIN32_AV_RETRY, (void*)a);
6380d0cdf012Sdrh   sqlite3_snprintf(sizeof(z), z, "%d %d %d", rc, a[0], a[1]);
6381d0cdf012Sdrh   Tcl_AppendResult(interp, z, (char*)0);
6382d0cdf012Sdrh   return TCL_OK;
6383d0cdf012Sdrh }
6384d0cdf012Sdrh 
6385253cea5cSdrh /*
63861b361ff3Smistachkin ** tclcmd:   file_control_win32_get_handle DB
63871b361ff3Smistachkin **
63881b361ff3Smistachkin ** This TCL command runs the sqlite3_file_control interface with
63891b361ff3Smistachkin ** the SQLITE_FCNTL_WIN32_GET_HANDLE opcode.
63901b361ff3Smistachkin */
file_control_win32_get_handle(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])63911b361ff3Smistachkin static int file_control_win32_get_handle(
63921b361ff3Smistachkin   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
63931b361ff3Smistachkin   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
63941b361ff3Smistachkin   int objc,              /* Number of arguments */
63951b361ff3Smistachkin   Tcl_Obj *CONST objv[]  /* Command arguments */
63961b361ff3Smistachkin ){
63971b361ff3Smistachkin   sqlite3 *db;
63981b361ff3Smistachkin   int rc;
63991b361ff3Smistachkin   HANDLE hFile = NULL;
64001b361ff3Smistachkin   char z[100];
64011b361ff3Smistachkin 
64021b361ff3Smistachkin   if( objc!=2 ){
64031b361ff3Smistachkin     Tcl_AppendResult(interp, "wrong # args: should be \"",
64041b361ff3Smistachkin         Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
64051b361ff3Smistachkin     return TCL_ERROR;
64061b361ff3Smistachkin   }
64071b361ff3Smistachkin   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
64081b361ff3Smistachkin     return TCL_ERROR;
64091b361ff3Smistachkin   }
64101b361ff3Smistachkin   rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_WIN32_GET_HANDLE,
64111b361ff3Smistachkin                             (void*)&hFile);
64121b361ff3Smistachkin   sqlite3_snprintf(sizeof(z), z, "%d %p", rc, (void*)hFile);
64131b361ff3Smistachkin   Tcl_AppendResult(interp, z, (char*)0);
64141b361ff3Smistachkin   return TCL_OK;
64151b361ff3Smistachkin }
64161b361ff3Smistachkin 
64171b361ff3Smistachkin /*
64186b98d67bSmistachkin ** tclcmd:   file_control_win32_set_handle DB HANDLE
64196b98d67bSmistachkin **
64206b98d67bSmistachkin ** This TCL command runs the sqlite3_file_control interface with
64216b98d67bSmistachkin ** the SQLITE_FCNTL_WIN32_SET_HANDLE opcode.
64226b98d67bSmistachkin */
file_control_win32_set_handle(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])64237617e4a8Smistachkin static int SQLITE_TCLAPI file_control_win32_set_handle(
64246b98d67bSmistachkin   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
64256b98d67bSmistachkin   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
64266b98d67bSmistachkin   int objc,              /* Number of arguments */
64276b98d67bSmistachkin   Tcl_Obj *CONST objv[]  /* Command arguments */
64286b98d67bSmistachkin ){
64296b98d67bSmistachkin   sqlite3 *db;
64306b98d67bSmistachkin   int rc;
64316b98d67bSmistachkin   HANDLE hFile = NULL;
64326b98d67bSmistachkin   char z[100];
64336b98d67bSmistachkin 
64346b98d67bSmistachkin   if( objc!=3 ){
64356b98d67bSmistachkin     Tcl_AppendResult(interp, "wrong # args: should be \"",
64366b98d67bSmistachkin         Tcl_GetStringFromObj(objv[0], 0), " DB HANDLE", 0);
64376b98d67bSmistachkin     return TCL_ERROR;
64386b98d67bSmistachkin   }
64396b98d67bSmistachkin   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
64406b98d67bSmistachkin     return TCL_ERROR;
64416b98d67bSmistachkin   }
64426b98d67bSmistachkin   if( getWin32Handle(interp, Tcl_GetString(objv[2]), &hFile) ){
64436b98d67bSmistachkin     return TCL_ERROR;
64446b98d67bSmistachkin   }
64456b98d67bSmistachkin   rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_WIN32_SET_HANDLE,
64466b98d67bSmistachkin                             (void*)&hFile);
64476b98d67bSmistachkin   sqlite3_snprintf(sizeof(z), z, "%d %p", rc, (void*)hFile);
64486b98d67bSmistachkin   Tcl_AppendResult(interp, z, (char*)0);
64496b98d67bSmistachkin   return TCL_OK;
64506b98d67bSmistachkin }
64516b98d67bSmistachkin #endif
64526b98d67bSmistachkin 
64536b98d67bSmistachkin /*
6454253cea5cSdrh ** tclcmd:   file_control_persist_wal DB PERSIST-FLAG
6455253cea5cSdrh **
6456253cea5cSdrh ** This TCL command runs the sqlite3_file_control interface with
6457253cea5cSdrh ** the SQLITE_FCNTL_PERSIST_WAL opcode.
6458253cea5cSdrh */
file_control_persist_wal(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])64597617e4a8Smistachkin static int SQLITE_TCLAPI file_control_persist_wal(
6460253cea5cSdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6461253cea5cSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6462253cea5cSdrh   int objc,              /* Number of arguments */
6463253cea5cSdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
6464253cea5cSdrh ){
6465253cea5cSdrh   sqlite3 *db;
6466253cea5cSdrh   int rc;
6467253cea5cSdrh   int bPersist;
6468253cea5cSdrh   char z[100];
6469253cea5cSdrh 
6470253cea5cSdrh   if( objc!=3 ){
6471253cea5cSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
6472253cea5cSdrh         Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", 0);
6473253cea5cSdrh     return TCL_ERROR;
6474253cea5cSdrh   }
6475253cea5cSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
6476253cea5cSdrh     return TCL_ERROR;
6477253cea5cSdrh   }
6478253cea5cSdrh   if( Tcl_GetIntFromObj(interp, objv[2], &bPersist) ) return TCL_ERROR;
6479253cea5cSdrh   rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_PERSIST_WAL, (void*)&bPersist);
6480253cea5cSdrh   sqlite3_snprintf(sizeof(z), z, "%d %d", rc, bPersist);
6481253cea5cSdrh   Tcl_AppendResult(interp, z, (char*)0);
6482253cea5cSdrh   return TCL_OK;
6483253cea5cSdrh }
6484253cea5cSdrh 
6485f12b3f60Sdrh /*
6486cb15f35fSdrh ** tclcmd:   file_control_powersafe_overwrite DB PSOW-FLAG
6487f12b3f60Sdrh **
6488f12b3f60Sdrh ** This TCL command runs the sqlite3_file_control interface with
6489cb15f35fSdrh ** the SQLITE_FCNTL_POWERSAFE_OVERWRITE opcode.
6490f12b3f60Sdrh */
file_control_powersafe_overwrite(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])64917617e4a8Smistachkin static int SQLITE_TCLAPI file_control_powersafe_overwrite(
6492f12b3f60Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6493f12b3f60Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6494f12b3f60Sdrh   int objc,              /* Number of arguments */
6495f12b3f60Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
6496f12b3f60Sdrh ){
6497f12b3f60Sdrh   sqlite3 *db;
6498f12b3f60Sdrh   int rc;
6499cb15f35fSdrh   int b;
6500f12b3f60Sdrh   char z[100];
6501f12b3f60Sdrh 
6502f12b3f60Sdrh   if( objc!=3 ){
6503f12b3f60Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
6504f12b3f60Sdrh         Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", 0);
6505f12b3f60Sdrh     return TCL_ERROR;
6506f12b3f60Sdrh   }
6507f12b3f60Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
6508f12b3f60Sdrh     return TCL_ERROR;
6509f12b3f60Sdrh   }
6510cb15f35fSdrh   if( Tcl_GetIntFromObj(interp, objv[2], &b) ) return TCL_ERROR;
6511cb15f35fSdrh   rc = sqlite3_file_control(db,NULL,SQLITE_FCNTL_POWERSAFE_OVERWRITE,(void*)&b);
6512cb15f35fSdrh   sqlite3_snprintf(sizeof(z), z, "%d %d", rc, b);
6513f12b3f60Sdrh   Tcl_AppendResult(interp, z, (char*)0);
6514f12b3f60Sdrh   return TCL_OK;
6515f12b3f60Sdrh }
6516f12b3f60Sdrh 
6517aebf413dSaswift 
651855176259Sdrh /*
6519de60fc2dSdrh ** tclcmd:   file_control_vfsname DB ?AUXDB?
6520de60fc2dSdrh **
6521de60fc2dSdrh ** Return a string that describes the stack of VFSes.
6522de60fc2dSdrh */
file_control_vfsname(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])65237617e4a8Smistachkin static int SQLITE_TCLAPI file_control_vfsname(
6524de60fc2dSdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6525de60fc2dSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6526de60fc2dSdrh   int objc,              /* Number of arguments */
6527de60fc2dSdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
6528de60fc2dSdrh ){
6529de60fc2dSdrh   sqlite3 *db;
6530de60fc2dSdrh   const char *zDbName = "main";
6531de60fc2dSdrh   char *zVfsName = 0;
6532de60fc2dSdrh 
6533de60fc2dSdrh   if( objc!=2 && objc!=3 ){
6534de60fc2dSdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
6535de60fc2dSdrh         Tcl_GetStringFromObj(objv[0], 0), " DB ?AUXDB?", 0);
6536de60fc2dSdrh     return TCL_ERROR;
6537de60fc2dSdrh   }
6538de60fc2dSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
6539de60fc2dSdrh     return TCL_ERROR;
6540de60fc2dSdrh   }
6541de60fc2dSdrh   if( objc==3 ){
6542de60fc2dSdrh     zDbName = Tcl_GetString(objv[2]);
6543de60fc2dSdrh   }
6544de60fc2dSdrh   sqlite3_file_control(db, zDbName, SQLITE_FCNTL_VFSNAME,(void*)&zVfsName);
6545de60fc2dSdrh   Tcl_AppendResult(interp, zVfsName, (char*)0);
6546de60fc2dSdrh   sqlite3_free(zVfsName);
6547de60fc2dSdrh   return TCL_OK;
6548de60fc2dSdrh }
6549de60fc2dSdrh 
6550696b33e6Sdrh /*
6551c30b78f6Sdan ** tclcmd:   file_control_reservebytes DB N
6552c30b78f6Sdan */
file_control_reservebytes(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])6553c30b78f6Sdan static int SQLITE_TCLAPI file_control_reservebytes(
6554c30b78f6Sdan   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6555c30b78f6Sdan   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6556c30b78f6Sdan   int objc,              /* Number of arguments */
6557c30b78f6Sdan   Tcl_Obj *CONST objv[]  /* Command arguments */
6558c30b78f6Sdan ){
6559c30b78f6Sdan   sqlite3 *db;
6560c30b78f6Sdan   const char *zDbName = "main";
6561c30b78f6Sdan   int n = 0;
6562c30b78f6Sdan   int rc;
6563c30b78f6Sdan 
6564c30b78f6Sdan   if( objc!=3 ){
6565c30b78f6Sdan     Tcl_WrongNumArgs(interp, 1, objv, "DB N");
6566c30b78f6Sdan     return TCL_ERROR;
6567c30b78f6Sdan   }
6568c30b78f6Sdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db)
6569c30b78f6Sdan    || Tcl_GetIntFromObj(interp, objv[2], &n)
6570c30b78f6Sdan   ){
6571c30b78f6Sdan     return TCL_ERROR;
6572c30b78f6Sdan   }
6573c30b78f6Sdan 
6574c30b78f6Sdan   rc = sqlite3_file_control(db, zDbName, SQLITE_FCNTL_RESERVE_BYTES, (void*)&n);
6575c30b78f6Sdan   Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
6576c30b78f6Sdan   return TCL_OK;
6577c30b78f6Sdan }
6578c30b78f6Sdan 
6579c30b78f6Sdan 
6580c30b78f6Sdan /*
6581696b33e6Sdrh ** tclcmd:   file_control_tempfilename DB ?AUXDB?
6582696b33e6Sdrh **
6583696b33e6Sdrh ** Return a string that is a temporary filename
6584696b33e6Sdrh */
file_control_tempfilename(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])65857617e4a8Smistachkin static int SQLITE_TCLAPI file_control_tempfilename(
6586696b33e6Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6587696b33e6Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6588696b33e6Sdrh   int objc,              /* Number of arguments */
6589696b33e6Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
6590696b33e6Sdrh ){
6591696b33e6Sdrh   sqlite3 *db;
6592696b33e6Sdrh   const char *zDbName = "main";
6593696b33e6Sdrh   char *zTName = 0;
6594696b33e6Sdrh 
6595696b33e6Sdrh   if( objc!=2 && objc!=3 ){
6596696b33e6Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
6597696b33e6Sdrh         Tcl_GetStringFromObj(objv[0], 0), " DB ?AUXDB?", 0);
6598696b33e6Sdrh     return TCL_ERROR;
6599696b33e6Sdrh   }
6600696b33e6Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
6601696b33e6Sdrh     return TCL_ERROR;
6602696b33e6Sdrh   }
6603696b33e6Sdrh   if( objc==3 ){
6604696b33e6Sdrh     zDbName = Tcl_GetString(objv[2]);
6605696b33e6Sdrh   }
6606696b33e6Sdrh   sqlite3_file_control(db, zDbName, SQLITE_FCNTL_TEMPFILENAME, (void*)&zTName);
6607696b33e6Sdrh   Tcl_AppendResult(interp, zTName, (char*)0);
6608696b33e6Sdrh   sqlite3_free(zTName);
6609696b33e6Sdrh   return TCL_OK;
6610696b33e6Sdrh }
6611696b33e6Sdrh 
6612aecc04d6Sdan /*
6613aecc04d6Sdan ** tclcmd:   file_control_external_reader DB ?AUXDB?
6614aecc04d6Sdan **
6615aecc04d6Sdan ** Return a string that is a temporary filename
6616aecc04d6Sdan */
file_control_external_reader(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])6617aecc04d6Sdan static int SQLITE_TCLAPI file_control_external_reader(
6618aecc04d6Sdan   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6619aecc04d6Sdan   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6620aecc04d6Sdan   int objc,              /* Number of arguments */
6621aecc04d6Sdan   Tcl_Obj *CONST objv[]  /* Command arguments */
6622aecc04d6Sdan ){
6623aecc04d6Sdan   sqlite3 *db;
6624aecc04d6Sdan   const char *zName = "main";
6625aecc04d6Sdan   int iRes = 0;
6626aecc04d6Sdan   int rc = SQLITE_OK;
6627aecc04d6Sdan 
6628aecc04d6Sdan   if( objc!=2 && objc!=3 ){
6629aecc04d6Sdan     Tcl_AppendResult(interp, "wrong # args: should be \"",
6630aecc04d6Sdan         Tcl_GetStringFromObj(objv[0], 0), " DB ?AUXDB?", 0);
6631aecc04d6Sdan     return TCL_ERROR;
6632aecc04d6Sdan   }
6633aecc04d6Sdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
6634aecc04d6Sdan     return TCL_ERROR;
6635aecc04d6Sdan   }
6636aecc04d6Sdan   if( objc==3 ){
6637aecc04d6Sdan     zName = Tcl_GetString(objv[2]);
6638aecc04d6Sdan   }
6639aecc04d6Sdan   rc = sqlite3_file_control(db, zName, SQLITE_FCNTL_EXTERNAL_READER, &iRes);
6640aecc04d6Sdan   if( rc!=SQLITE_OK ){
6641aecc04d6Sdan     Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
6642aecc04d6Sdan     return TCL_ERROR;
6643aecc04d6Sdan   }
6644aecc04d6Sdan   Tcl_SetObjResult(interp, Tcl_NewIntObj(iRes));
6645aecc04d6Sdan   return TCL_OK;
6646aecc04d6Sdan }
6647aecc04d6Sdan 
6648de60fc2dSdrh 
6649de60fc2dSdrh /*
6650e339d65aSdanielk1977 ** tclcmd:   sqlite3_vfs_list
6651e339d65aSdanielk1977 **
6652e339d65aSdanielk1977 **   Return a tcl list containing the names of all registered vfs's.
6653e339d65aSdanielk1977 */
vfs_list(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])66547617e4a8Smistachkin static int SQLITE_TCLAPI vfs_list(
6655e339d65aSdanielk1977   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6656e339d65aSdanielk1977   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6657e339d65aSdanielk1977   int objc,              /* Number of arguments */
6658e339d65aSdanielk1977   Tcl_Obj *CONST objv[]  /* Command arguments */
6659e339d65aSdanielk1977 ){
6660e339d65aSdanielk1977   sqlite3_vfs *pVfs;
6661e339d65aSdanielk1977   Tcl_Obj *pRet = Tcl_NewObj();
6662e339d65aSdanielk1977   if( objc!=1 ){
6663e339d65aSdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "");
6664e339d65aSdanielk1977     return TCL_ERROR;
6665e339d65aSdanielk1977   }
6666e339d65aSdanielk1977   for(pVfs=sqlite3_vfs_find(0); pVfs; pVfs=pVfs->pNext){
6667e339d65aSdanielk1977     Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(pVfs->zName, -1));
6668e339d65aSdanielk1977   }
6669e339d65aSdanielk1977   Tcl_SetObjResult(interp, pRet);
6670e339d65aSdanielk1977   return TCL_OK;
6671e339d65aSdanielk1977 }
6672e339d65aSdanielk1977 
6673e339d65aSdanielk1977 /*
6674b1a6c3c1Sdrh ** tclcmd:   sqlite3_limit DB ID VALUE
6675b1a6c3c1Sdrh **
6676b1a6c3c1Sdrh ** This TCL command runs the sqlite3_limit interface and
6677b1a6c3c1Sdrh ** verifies correct operation of the same.
6678b1a6c3c1Sdrh */
test_limit(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])66797617e4a8Smistachkin static int SQLITE_TCLAPI test_limit(
6680b1a6c3c1Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6681b1a6c3c1Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6682b1a6c3c1Sdrh   int objc,              /* Number of arguments */
6683b1a6c3c1Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
6684b1a6c3c1Sdrh ){
6685b1a6c3c1Sdrh   sqlite3 *db;
6686b1a6c3c1Sdrh   int rc;
6687b1a6c3c1Sdrh   static const struct {
6688b1a6c3c1Sdrh      char *zName;
6689b1a6c3c1Sdrh      int id;
6690b1a6c3c1Sdrh   } aId[] = {
6691b1a6c3c1Sdrh     { "SQLITE_LIMIT_LENGTH",              SQLITE_LIMIT_LENGTH               },
6692b1a6c3c1Sdrh     { "SQLITE_LIMIT_SQL_LENGTH",          SQLITE_LIMIT_SQL_LENGTH           },
6693b1a6c3c1Sdrh     { "SQLITE_LIMIT_COLUMN",              SQLITE_LIMIT_COLUMN               },
6694b1a6c3c1Sdrh     { "SQLITE_LIMIT_EXPR_DEPTH",          SQLITE_LIMIT_EXPR_DEPTH           },
6695b1a6c3c1Sdrh     { "SQLITE_LIMIT_COMPOUND_SELECT",     SQLITE_LIMIT_COMPOUND_SELECT      },
6696b1a6c3c1Sdrh     { "SQLITE_LIMIT_VDBE_OP",             SQLITE_LIMIT_VDBE_OP              },
6697b1a6c3c1Sdrh     { "SQLITE_LIMIT_FUNCTION_ARG",        SQLITE_LIMIT_FUNCTION_ARG         },
6698b1a6c3c1Sdrh     { "SQLITE_LIMIT_ATTACHED",            SQLITE_LIMIT_ATTACHED             },
6699b1a6c3c1Sdrh     { "SQLITE_LIMIT_LIKE_PATTERN_LENGTH", SQLITE_LIMIT_LIKE_PATTERN_LENGTH  },
6700b1a6c3c1Sdrh     { "SQLITE_LIMIT_VARIABLE_NUMBER",     SQLITE_LIMIT_VARIABLE_NUMBER      },
6701417168adSdrh     { "SQLITE_LIMIT_TRIGGER_DEPTH",       SQLITE_LIMIT_TRIGGER_DEPTH        },
67023705ef6aSdrh     { "SQLITE_LIMIT_WORKER_THREADS",      SQLITE_LIMIT_WORKER_THREADS       },
6703521cc849Sdrh 
6704521cc849Sdrh     /* Out of range test cases */
6705521cc849Sdrh     { "SQLITE_LIMIT_TOOSMALL",            -1,                               },
67063705ef6aSdrh     { "SQLITE_LIMIT_TOOBIG",              SQLITE_LIMIT_WORKER_THREADS+1     },
6707b1a6c3c1Sdrh   };
670827b2f053Smistachkin   int i, id = 0;
6709b1a6c3c1Sdrh   int val;
6710b1a6c3c1Sdrh   const char *zId;
6711b1a6c3c1Sdrh 
6712b1a6c3c1Sdrh   if( objc!=4 ){
6713b1a6c3c1Sdrh     Tcl_AppendResult(interp, "wrong # args: should be \"",
6714b1a6c3c1Sdrh         Tcl_GetStringFromObj(objv[0], 0), " DB ID VALUE", 0);
6715b1a6c3c1Sdrh     return TCL_ERROR;
6716b1a6c3c1Sdrh   }
6717b1a6c3c1Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
6718b1a6c3c1Sdrh   zId = Tcl_GetString(objv[2]);
6719b1a6c3c1Sdrh   for(i=0; i<sizeof(aId)/sizeof(aId[0]); i++){
6720b1a6c3c1Sdrh     if( strcmp(zId, aId[i].zName)==0 ){
6721b1a6c3c1Sdrh       id = aId[i].id;
6722b1a6c3c1Sdrh       break;
6723b1a6c3c1Sdrh     }
6724b1a6c3c1Sdrh   }
6725b1a6c3c1Sdrh   if( i>=sizeof(aId)/sizeof(aId[0]) ){
6726b1a6c3c1Sdrh     Tcl_AppendResult(interp, "unknown limit type: ", zId, (char*)0);
6727b1a6c3c1Sdrh     return TCL_ERROR;
6728b1a6c3c1Sdrh   }
6729b1a6c3c1Sdrh   if( Tcl_GetIntFromObj(interp, objv[3], &val) ) return TCL_ERROR;
6730b1a6c3c1Sdrh   rc = sqlite3_limit(db, id, val);
6731b1a6c3c1Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
6732b1a6c3c1Sdrh   return TCL_OK;
6733b1a6c3c1Sdrh }
6734b1a6c3c1Sdrh 
6735b1a6c3c1Sdrh /*
673693aed5a1Sdrh ** tclcmd:  save_prng_state
6737a2820970Sdrh **
6738a2820970Sdrh ** Save the state of the pseudo-random number generator.
6739a2820970Sdrh ** At the same time, verify that sqlite3_test_control works even when
6740a2820970Sdrh ** called with an out-of-range opcode.
674193aed5a1Sdrh */
save_prng_state(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])67427617e4a8Smistachkin static int SQLITE_TCLAPI save_prng_state(
674393aed5a1Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
674493aed5a1Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
674593aed5a1Sdrh   int objc,              /* Number of arguments */
674693aed5a1Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
674793aed5a1Sdrh ){
6748a2820970Sdrh   int rc = sqlite3_test_control(9999);
6749a2820970Sdrh   assert( rc==0 );
6750a2820970Sdrh   rc = sqlite3_test_control(-1);
6751a2820970Sdrh   assert( rc==0 );
67522fa1868fSdrh   sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SAVE);
675393aed5a1Sdrh   return TCL_OK;
675493aed5a1Sdrh }
675593aed5a1Sdrh /*
675693aed5a1Sdrh ** tclcmd:  restore_prng_state
675793aed5a1Sdrh */
restore_prng_state(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])67587617e4a8Smistachkin static int SQLITE_TCLAPI restore_prng_state(
675993aed5a1Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
676093aed5a1Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
676193aed5a1Sdrh   int objc,              /* Number of arguments */
676293aed5a1Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
676393aed5a1Sdrh ){
67642fa1868fSdrh   sqlite3_test_control(SQLITE_TESTCTRL_PRNG_RESTORE);
676593aed5a1Sdrh   return TCL_OK;
676693aed5a1Sdrh }
676793aed5a1Sdrh /*
676893aed5a1Sdrh ** tclcmd:  reset_prng_state
676993aed5a1Sdrh */
reset_prng_state(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])67707617e4a8Smistachkin static int SQLITE_TCLAPI reset_prng_state(
677193aed5a1Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
677293aed5a1Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
677393aed5a1Sdrh   int objc,              /* Number of arguments */
677493aed5a1Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
677593aed5a1Sdrh ){
6776ade54d68Sdrh   sqlite3_randomness(0,0);
6777ade54d68Sdrh   return TCL_OK;
6778ade54d68Sdrh }
6779ade54d68Sdrh /*
67802e6d83bcSdrh ** tclcmd:  prng_seed INT ?DB?
6781ade54d68Sdrh **
67822e6d83bcSdrh ** Set up the SQLITE_TESTCTRL_PRNG_SEED pragma with parameter INT and DB.
67832e6d83bcSdrh ** INT is an integer.  DB is a database connection, or a NULL pointer if
67842e6d83bcSdrh ** omitted.
67852e6d83bcSdrh **
67862e6d83bcSdrh ** When INT!=0 and DB!=0, set the PRNG seed to the value of the schema
67872e6d83bcSdrh ** cookie for DB, or to INT if the schema cookie happens to be zero.
67882e6d83bcSdrh **
67892e6d83bcSdrh ** When INT!=0 and DB==0, set the PRNG seed to just INT.
67902e6d83bcSdrh **
67912e6d83bcSdrh ** If INT==0 and DB==0 then use the default procedure of calling the
67922e6d83bcSdrh ** xRandomness method on the default VFS to get the PRNG seed.
6793ade54d68Sdrh */
prng_seed(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])6794ade54d68Sdrh static int SQLITE_TCLAPI prng_seed(
6795ade54d68Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6796ade54d68Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6797ade54d68Sdrh   int objc,              /* Number of arguments */
6798ade54d68Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
6799ade54d68Sdrh ){
68002e6d83bcSdrh   int i = 0;
68012e6d83bcSdrh   sqlite3 *db = 0;
68022e6d83bcSdrh   if( objc!=2 && objc!=3 ){
68032e6d83bcSdrh     Tcl_WrongNumArgs(interp, 1, objv, "SEED ?DB?");
6804ade54d68Sdrh     return TCL_ERROR;
6805ade54d68Sdrh   }
68068718f0b6Sdan   if( Tcl_GetIntFromObj(interp,objv[1],&i) ) return TCL_ERROR;
68072e6d83bcSdrh   if( objc==3 && getDbPointer(interp, Tcl_GetString(objv[2]), &db) ){
68082e6d83bcSdrh     return TCL_ERROR;
68092e6d83bcSdrh   }
68102e6d83bcSdrh   sqlite3_test_control(SQLITE_TESTCTRL_PRNG_SEED, i, db);
681193aed5a1Sdrh   return TCL_OK;
681293aed5a1Sdrh }
681393aed5a1Sdrh 
6814062d4cb0Sdanielk1977 /*
6815ca439a49Sdrh ** tclcmd:  extra_schema_checks BOOLEAN
6816ca439a49Sdrh **
6817ca439a49Sdrh ** Enable or disable schema checks when parsing the sqlite_schema file.
6818ca439a49Sdrh ** This is always enabled in production, but it is sometimes useful to
6819ca439a49Sdrh ** disable the checks in order to make some internal error states reachable
6820ca439a49Sdrh ** for testing.
6821ca439a49Sdrh */
extra_schema_checks(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])6822ca439a49Sdrh static int SQLITE_TCLAPI extra_schema_checks(
6823ca439a49Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6824ca439a49Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6825ca439a49Sdrh   int objc,              /* Number of arguments */
6826ca439a49Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
6827ca439a49Sdrh ){
6828ca439a49Sdrh   int i = 0;
6829ca439a49Sdrh   if( objc!=2 ){
6830ca439a49Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "BOOLEAN");
6831ca439a49Sdrh     return TCL_ERROR;
6832ca439a49Sdrh   }
6833ca439a49Sdrh   if( Tcl_GetBooleanFromObj(interp,objv[1],&i) ) return TCL_ERROR;
6834ca439a49Sdrh   sqlite3_test_control(SQLITE_TESTCTRL_EXTRA_SCHEMA_CHECKS, i);
6835ca439a49Sdrh   return TCL_OK;
6836ca439a49Sdrh }
6837ca439a49Sdrh 
6838ca439a49Sdrh /*
683909fe6143Sdrh ** tclcmd:  database_may_be_corrupt
684009fe6143Sdrh **
684109fe6143Sdrh ** Indicate that database files might be corrupt. In other words, set the normal
684209fe6143Sdrh ** state of operation.
684309fe6143Sdrh */
database_may_be_corrupt(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])68447617e4a8Smistachkin static int SQLITE_TCLAPI database_may_be_corrupt(
684509fe6143Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
684609fe6143Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
684709fe6143Sdrh   int objc,              /* Number of arguments */
684809fe6143Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
684909fe6143Sdrh ){
685009fe6143Sdrh   sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, 0);
685109fe6143Sdrh   return TCL_OK;
685209fe6143Sdrh }
685309fe6143Sdrh /*
685409fe6143Sdrh ** tclcmd:  database_never_corrupt
685509fe6143Sdrh **
6856eea8eb6dSdrh ** Indicate that database files are always well-formed. This enables
6857eea8eb6dSdrh ** extra assert() statements that test conditions that are always true
6858eea8eb6dSdrh ** for well-formed databases.
685909fe6143Sdrh */
database_never_corrupt(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])68607617e4a8Smistachkin static int SQLITE_TCLAPI database_never_corrupt(
686109fe6143Sdrh   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
686209fe6143Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
686309fe6143Sdrh   int objc,              /* Number of arguments */
686409fe6143Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
686509fe6143Sdrh ){
686609fe6143Sdrh   sqlite3_test_control(SQLITE_TESTCTRL_NEVER_CORRUPT, 1);
686709fe6143Sdrh   return TCL_OK;
686809fe6143Sdrh }
686909fe6143Sdrh 
687009fe6143Sdrh /*
6871062d4cb0Sdanielk1977 ** tclcmd:  pcache_stats
6872062d4cb0Sdanielk1977 */
test_pcache_stats(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])68737617e4a8Smistachkin static int SQLITE_TCLAPI test_pcache_stats(
6874062d4cb0Sdanielk1977   ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
6875062d4cb0Sdanielk1977   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6876062d4cb0Sdanielk1977   int objc,              /* Number of arguments */
6877062d4cb0Sdanielk1977   Tcl_Obj *CONST objv[]  /* Command arguments */
6878062d4cb0Sdanielk1977 ){
6879062d4cb0Sdanielk1977   int nMin;
6880062d4cb0Sdanielk1977   int nMax;
6881062d4cb0Sdanielk1977   int nCurrent;
6882062d4cb0Sdanielk1977   int nRecyclable;
6883062d4cb0Sdanielk1977   Tcl_Obj *pRet;
6884062d4cb0Sdanielk1977 
6885062d4cb0Sdanielk1977   sqlite3PcacheStats(&nCurrent, &nMax, &nMin, &nRecyclable);
6886062d4cb0Sdanielk1977 
6887062d4cb0Sdanielk1977   pRet = Tcl_NewObj();
6888062d4cb0Sdanielk1977   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("current", -1));
6889062d4cb0Sdanielk1977   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nCurrent));
6890062d4cb0Sdanielk1977   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("max", -1));
6891062d4cb0Sdanielk1977   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nMax));
6892062d4cb0Sdanielk1977   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("min", -1));
6893062d4cb0Sdanielk1977   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nMin));
6894062d4cb0Sdanielk1977   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj("recyclable", -1));
6895062d4cb0Sdanielk1977   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nRecyclable));
6896062d4cb0Sdanielk1977 
6897062d4cb0Sdanielk1977   Tcl_SetObjResult(interp, pRet);
6898062d4cb0Sdanielk1977 
6899062d4cb0Sdanielk1977   return TCL_OK;
6900062d4cb0Sdanielk1977 }
6901062d4cb0Sdanielk1977 
690269910da9Sdrh #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
test_unlock_notify_cb(void ** aArg,int nArg)6903404ca075Sdanielk1977 static void test_unlock_notify_cb(void **aArg, int nArg){
6904404ca075Sdanielk1977   int ii;
6905404ca075Sdanielk1977   for(ii=0; ii<nArg; ii++){
6906404ca075Sdanielk1977     Tcl_EvalEx((Tcl_Interp *)aArg[ii], "unlock_notify", -1, TCL_EVAL_GLOBAL);
6907404ca075Sdanielk1977   }
6908404ca075Sdanielk1977 }
690969910da9Sdrh #endif /* SQLITE_ENABLE_UNLOCK_NOTIFY */
6910404ca075Sdanielk1977 
6911404ca075Sdanielk1977 /*
6912404ca075Sdanielk1977 ** tclcmd:  sqlite3_unlock_notify db
6913404ca075Sdanielk1977 */
6914404ca075Sdanielk1977 #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
test_unlock_notify(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])69157617e4a8Smistachkin static int SQLITE_TCLAPI test_unlock_notify(
6916404ca075Sdanielk1977   ClientData clientData, /* Unused */
6917404ca075Sdanielk1977   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6918404ca075Sdanielk1977   int objc,              /* Number of arguments */
6919404ca075Sdanielk1977   Tcl_Obj *CONST objv[]  /* Command arguments */
6920404ca075Sdanielk1977 ){
6921404ca075Sdanielk1977   sqlite3 *db;
6922404ca075Sdanielk1977   int rc;
6923404ca075Sdanielk1977 
6924404ca075Sdanielk1977   if( objc!=2 ){
6925404ca075Sdanielk1977     Tcl_WrongNumArgs(interp, 1, objv, "DB");
6926404ca075Sdanielk1977     return TCL_ERROR;
6927404ca075Sdanielk1977   }
6928404ca075Sdanielk1977 
6929404ca075Sdanielk1977   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
6930404ca075Sdanielk1977     return TCL_ERROR;
6931404ca075Sdanielk1977   }
6932404ca075Sdanielk1977   rc = sqlite3_unlock_notify(db, test_unlock_notify_cb, (void *)interp);
6933404ca075Sdanielk1977   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
6934404ca075Sdanielk1977   return TCL_OK;
6935404ca075Sdanielk1977 }
6936404ca075Sdanielk1977 #endif
6937404ca075Sdanielk1977 
693887c1fe1bSdan /*
693987c1fe1bSdan ** tclcmd:  sqlite3_wal_checkpoint db ?NAME?
694087c1fe1bSdan */
test_wal_checkpoint(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])69417617e4a8Smistachkin static int SQLITE_TCLAPI test_wal_checkpoint(
694287c1fe1bSdan   ClientData clientData, /* Unused */
694387c1fe1bSdan   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
694487c1fe1bSdan   int objc,              /* Number of arguments */
694587c1fe1bSdan   Tcl_Obj *CONST objv[]  /* Command arguments */
694687c1fe1bSdan ){
694787c1fe1bSdan   char *zDb = 0;
694887c1fe1bSdan   sqlite3 *db;
694987c1fe1bSdan   int rc;
695087c1fe1bSdan 
695187c1fe1bSdan   if( objc!=3 && objc!=2 ){
695287c1fe1bSdan     Tcl_WrongNumArgs(interp, 1, objv, "DB ?NAME?");
695387c1fe1bSdan     return TCL_ERROR;
695487c1fe1bSdan   }
695587c1fe1bSdan 
695687c1fe1bSdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
695787c1fe1bSdan     return TCL_ERROR;
695887c1fe1bSdan   }
695987c1fe1bSdan   if( objc==3 ){
696087c1fe1bSdan     zDb = Tcl_GetString(objv[2]);
696187c1fe1bSdan   }
696287c1fe1bSdan   rc = sqlite3_wal_checkpoint(db, zDb);
696387c1fe1bSdan   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
696487c1fe1bSdan   return TCL_OK;
696587c1fe1bSdan }
696687c1fe1bSdan 
6967eb8763d7Sdan /*
69689c5e3680Sdan ** tclcmd:  sqlite3_wal_checkpoint_v2 db MODE ?NAME?
69699c5e3680Sdan **
69709c5e3680Sdan ** This command calls the wal_checkpoint_v2() function with the specified
69719c5e3680Sdan ** mode argument (passive, full or restart). If present, the database name
69729c5e3680Sdan ** NAME is passed as the second argument to wal_checkpoint_v2(). If it the
69739c5e3680Sdan ** NAME argument is not present, a NULL pointer is passed instead.
69749c5e3680Sdan **
69759c5e3680Sdan ** If wal_checkpoint_v2() returns any value other than SQLITE_BUSY or
69769c5e3680Sdan ** SQLITE_OK, then this command returns TCL_ERROR. The Tcl result is set
69779c5e3680Sdan ** to the error message obtained from sqlite3_errmsg().
69789c5e3680Sdan **
69799c5e3680Sdan ** Otherwise, this command returns a list of three integers. The first integer
69809c5e3680Sdan ** is 1 if SQLITE_BUSY was returned, or 0 otherwise. The following two integers
6981f7b5496eSdrh ** are the values returned via the output parameters by wal_checkpoint_v2() -
69829c5e3680Sdan ** the number of frames in the log and the number of frames in the log
69839c5e3680Sdan ** that have been checkpointed.
69849c5e3680Sdan */
test_wal_checkpoint_v2(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])69857617e4a8Smistachkin static int SQLITE_TCLAPI test_wal_checkpoint_v2(
69869c5e3680Sdan   ClientData clientData, /* Unused */
69879c5e3680Sdan   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
69889c5e3680Sdan   int objc,              /* Number of arguments */
69899c5e3680Sdan   Tcl_Obj *CONST objv[]  /* Command arguments */
69909c5e3680Sdan ){
69919c5e3680Sdan   char *zDb = 0;
69929c5e3680Sdan   sqlite3 *db;
69939c5e3680Sdan   int rc;
69949c5e3680Sdan 
69959c5e3680Sdan   int eMode;
69969c5e3680Sdan   int nLog = -555;
69979c5e3680Sdan   int nCkpt = -555;
69989c5e3680Sdan   Tcl_Obj *pRet;
69999c5e3680Sdan 
7000f26a1549Sdan   const char * aMode[] = { "passive", "full", "restart", "truncate", 0 };
70019c5e3680Sdan   assert( SQLITE_CHECKPOINT_PASSIVE==0 );
70029c5e3680Sdan   assert( SQLITE_CHECKPOINT_FULL==1 );
70039c5e3680Sdan   assert( SQLITE_CHECKPOINT_RESTART==2 );
7004f26a1549Sdan   assert( SQLITE_CHECKPOINT_TRUNCATE==3 );
70059c5e3680Sdan 
70069c5e3680Sdan   if( objc!=3 && objc!=4 ){
70079c5e3680Sdan     Tcl_WrongNumArgs(interp, 1, objv, "DB MODE ?NAME?");
70089c5e3680Sdan     return TCL_ERROR;
70099c5e3680Sdan   }
70109c5e3680Sdan 
70119c5e3680Sdan   if( objc==4 ){
70129c5e3680Sdan     zDb = Tcl_GetString(objv[3]);
70139c5e3680Sdan   }
70142928d327Sdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) || (
70152928d327Sdan       TCL_OK!=Tcl_GetIntFromObj(0, objv[2], &eMode)
70162928d327Sdan    && TCL_OK!=Tcl_GetIndexFromObj(interp, objv[2], aMode, "mode", 0, &eMode)
70172928d327Sdan   )){
70189c5e3680Sdan     return TCL_ERROR;
70199c5e3680Sdan   }
70209c5e3680Sdan 
70219c5e3680Sdan   rc = sqlite3_wal_checkpoint_v2(db, zDb, eMode, &nLog, &nCkpt);
70229c5e3680Sdan   if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){
70232928d327Sdan     const char *zErrCode = sqlite3ErrName(rc);
70249778bd72Sdan     Tcl_ResetResult(interp);
70252928d327Sdan     Tcl_AppendResult(interp, zErrCode, " - ", (char *)sqlite3_errmsg(db), 0);
70269c5e3680Sdan     return TCL_ERROR;
70279c5e3680Sdan   }
70289c5e3680Sdan 
70299c5e3680Sdan   pRet = Tcl_NewObj();
70309c5e3680Sdan   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(rc==SQLITE_BUSY?1:0));
70319c5e3680Sdan   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nLog));
70329c5e3680Sdan   Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nCkpt));
70339c5e3680Sdan   Tcl_SetObjResult(interp, pRet);
70349c5e3680Sdan 
70359c5e3680Sdan   return TCL_OK;
70369c5e3680Sdan }
70379c5e3680Sdan 
70389c5e3680Sdan /*
70399af10620Sdan ** tclcmd:  sqlite3_wal_autocheckpoint db VALUE
70409af10620Sdan */
test_wal_autocheckpoint(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])70417617e4a8Smistachkin static int SQLITE_TCLAPI test_wal_autocheckpoint(
70429af10620Sdan   ClientData clientData, /* Unused */
70439af10620Sdan   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
70449af10620Sdan   int objc,              /* Number of arguments */
70459af10620Sdan   Tcl_Obj *CONST objv[]  /* Command arguments */
70469af10620Sdan ){
70479af10620Sdan   sqlite3 *db;
70489af10620Sdan   int rc;
70499af10620Sdan   int iVal;
70509af10620Sdan 
70519af10620Sdan 
70529af10620Sdan   if( objc!=3 ){
70539af10620Sdan     Tcl_WrongNumArgs(interp, 1, objv, "DB VALUE");
70549af10620Sdan     return TCL_ERROR;
70559af10620Sdan   }
70569af10620Sdan 
70579af10620Sdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db)
70589af10620Sdan    || Tcl_GetIntFromObj(0, objv[2], &iVal)
70599af10620Sdan   ){
70609af10620Sdan     return TCL_ERROR;
70619af10620Sdan   }
70629af10620Sdan 
70639af10620Sdan   rc = sqlite3_wal_autocheckpoint(db, iVal);
70649af10620Sdan   Tcl_ResetResult(interp);
70659af10620Sdan   if( rc!=SQLITE_OK ){
70669af10620Sdan     const char *zErrCode = sqlite3ErrName(rc);
70679af10620Sdan     Tcl_SetObjResult(interp, Tcl_NewStringObj(zErrCode, -1));
70689af10620Sdan     return TCL_ERROR;
70699af10620Sdan   }
70709af10620Sdan 
70719af10620Sdan   return TCL_OK;
70729af10620Sdan }
70739af10620Sdan 
70749af10620Sdan 
70759af10620Sdan /*
7076eb8763d7Sdan ** tclcmd:  test_sqlite3_log ?SCRIPT?
7077eb8763d7Sdan */
7078eb8763d7Sdan static struct LogCallback {
7079eb8763d7Sdan   Tcl_Interp *pInterp;
7080eb8763d7Sdan   Tcl_Obj *pObj;
7081eb8763d7Sdan } logcallback = {0, 0};
xLogcallback(void * unused,int err,char * zMsg)7082eb8763d7Sdan static void xLogcallback(void *unused, int err, char *zMsg){
7083eb8763d7Sdan   Tcl_Obj *pNew = Tcl_DuplicateObj(logcallback.pObj);
7084eb8763d7Sdan   Tcl_IncrRefCount(pNew);
7085eb8763d7Sdan   Tcl_ListObjAppendElement(
7086e84d8d32Smistachkin       0, pNew, Tcl_NewStringObj(sqlite3ErrName(err), -1)
7087eb8763d7Sdan   );
7088eb8763d7Sdan   Tcl_ListObjAppendElement(0, pNew, Tcl_NewStringObj(zMsg, -1));
7089eb8763d7Sdan   Tcl_EvalObjEx(logcallback.pInterp, pNew, TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT);
7090eb8763d7Sdan   Tcl_DecrRefCount(pNew);
7091eb8763d7Sdan }
test_sqlite3_log(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])70927617e4a8Smistachkin static int SQLITE_TCLAPI test_sqlite3_log(
7093eb8763d7Sdan   ClientData clientData,
7094eb8763d7Sdan   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
7095eb8763d7Sdan   int objc,              /* Number of arguments */
7096eb8763d7Sdan   Tcl_Obj *CONST objv[]  /* Command arguments */
7097eb8763d7Sdan ){
7098eb8763d7Sdan   if( objc>2 ){
7099eb8763d7Sdan     Tcl_WrongNumArgs(interp, 1, objv, "SCRIPT");
7100eb8763d7Sdan     return TCL_ERROR;
7101eb8763d7Sdan   }
7102eb8763d7Sdan   if( logcallback.pObj ){
7103eb8763d7Sdan     Tcl_DecrRefCount(logcallback.pObj);
7104eb8763d7Sdan     logcallback.pObj = 0;
7105eb8763d7Sdan     logcallback.pInterp = 0;
7106d797a9b5Sdrh     sqlite3_config(SQLITE_CONFIG_LOG, (void*)0, (void*)0);
7107eb8763d7Sdan   }
7108eb8763d7Sdan   if( objc>1 ){
7109eb8763d7Sdan     logcallback.pObj = objv[1];
7110eb8763d7Sdan     Tcl_IncrRefCount(logcallback.pObj);
7111eb8763d7Sdan     logcallback.pInterp = interp;
7112d797a9b5Sdrh     sqlite3_config(SQLITE_CONFIG_LOG, xLogcallback, (void*)0);
7113eb8763d7Sdan   }
7114eb8763d7Sdan   return TCL_OK;
7115eb8763d7Sdan }
71169bc5449fSdrh 
71179bc5449fSdrh /*
7118a2c8a95bSdrh **     tcl_objproc COMMANDNAME ARGS...
7119a2c8a95bSdrh **
7120a2c8a95bSdrh ** Run a TCL command using its objProc interface.  Throw an error if
7121a2c8a95bSdrh ** the command has no objProc interface.
7122a2c8a95bSdrh */
runAsObjProc(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])71237617e4a8Smistachkin static int SQLITE_TCLAPI runAsObjProc(
7124a2c8a95bSdrh   void * clientData,
7125a2c8a95bSdrh   Tcl_Interp *interp,
7126a2c8a95bSdrh   int objc,
7127a2c8a95bSdrh   Tcl_Obj *CONST objv[]
7128a2c8a95bSdrh ){
7129a2c8a95bSdrh   Tcl_CmdInfo cmdInfo;
7130a2c8a95bSdrh   if( objc<2 ){
7131a2c8a95bSdrh     Tcl_WrongNumArgs(interp, 1, objv, "COMMAND ...");
7132a2c8a95bSdrh     return TCL_ERROR;
7133a2c8a95bSdrh   }
7134a2c8a95bSdrh   if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){
7135a2c8a95bSdrh     Tcl_AppendResult(interp, "command not found: ",
7136a2c8a95bSdrh            Tcl_GetString(objv[1]), (char*)0);
7137a2c8a95bSdrh     return TCL_ERROR;
7138a2c8a95bSdrh   }
7139a2c8a95bSdrh   if( cmdInfo.objProc==0 ){
7140a2c8a95bSdrh     Tcl_AppendResult(interp, "command has no objProc: ",
7141a2c8a95bSdrh            Tcl_GetString(objv[1]), (char*)0);
7142a2c8a95bSdrh     return TCL_ERROR;
7143a2c8a95bSdrh   }
7144a2c8a95bSdrh   return cmdInfo.objProc(cmdInfo.objClientData, interp, objc-1, objv+1);
7145a2c8a95bSdrh }
7146a2c8a95bSdrh 
714791da6b83Sdan #ifndef SQLITE_OMIT_EXPLAIN
714891da6b83Sdan /*
714991da6b83Sdan ** WARNING: The following function, printExplainQueryPlan() is an exact
715091da6b83Sdan ** copy of example code from eqp.in (eqp.html). If this code is modified,
715191da6b83Sdan ** then the documentation copy needs to be modified as well.
715291da6b83Sdan */
715391da6b83Sdan /*
715491da6b83Sdan ** Argument pStmt is a prepared SQL statement. This function compiles
715591da6b83Sdan ** an EXPLAIN QUERY PLAN command to report on the prepared statement,
715691da6b83Sdan ** and prints the report to stdout using printf().
715791da6b83Sdan */
printExplainQueryPlan(sqlite3_stmt * pStmt)715891da6b83Sdan int printExplainQueryPlan(sqlite3_stmt *pStmt){
715991da6b83Sdan   const char *zSql;               /* Input SQL */
716091da6b83Sdan   char *zExplain;                 /* SQL with EXPLAIN QUERY PLAN prepended */
716191da6b83Sdan   sqlite3_stmt *pExplain;         /* Compiled EXPLAIN QUERY PLAN command */
716291da6b83Sdan   int rc;                         /* Return code from sqlite3_prepare_v2() */
716391da6b83Sdan 
716491da6b83Sdan   zSql = sqlite3_sql(pStmt);
716591da6b83Sdan   if( zSql==0 ) return SQLITE_ERROR;
716691da6b83Sdan 
716791da6b83Sdan   zExplain = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zSql);
716891da6b83Sdan   if( zExplain==0 ) return SQLITE_NOMEM;
716991da6b83Sdan 
717091da6b83Sdan   rc = sqlite3_prepare_v2(sqlite3_db_handle(pStmt), zExplain, -1, &pExplain, 0);
717191da6b83Sdan   sqlite3_free(zExplain);
717291da6b83Sdan   if( rc!=SQLITE_OK ) return rc;
717391da6b83Sdan 
717491da6b83Sdan   while( SQLITE_ROW==sqlite3_step(pExplain) ){
717591da6b83Sdan     int iSelectid = sqlite3_column_int(pExplain, 0);
717691da6b83Sdan     int iOrder = sqlite3_column_int(pExplain, 1);
717791da6b83Sdan     int iFrom = sqlite3_column_int(pExplain, 2);
717891da6b83Sdan     const char *zDetail = (const char *)sqlite3_column_text(pExplain, 3);
717991da6b83Sdan 
718091da6b83Sdan     printf("%d %d %d %s\n", iSelectid, iOrder, iFrom, zDetail);
718191da6b83Sdan   }
718291da6b83Sdan 
718391da6b83Sdan   return sqlite3_finalize(pExplain);
718491da6b83Sdan }
718591da6b83Sdan 
test_print_eqp(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])71867617e4a8Smistachkin static int SQLITE_TCLAPI test_print_eqp(
718791da6b83Sdan   void * clientData,
718891da6b83Sdan   Tcl_Interp *interp,
718991da6b83Sdan   int objc,
719091da6b83Sdan   Tcl_Obj *CONST objv[]
719191da6b83Sdan ){
719291da6b83Sdan   int rc;
719391da6b83Sdan   sqlite3_stmt *pStmt;
719491da6b83Sdan 
719591da6b83Sdan   if( objc!=2 ){
719691da6b83Sdan     Tcl_WrongNumArgs(interp, 1, objv, "STMT");
719791da6b83Sdan     return TCL_ERROR;
719891da6b83Sdan   }
719991da6b83Sdan   if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
720091da6b83Sdan   rc = printExplainQueryPlan(pStmt);
72017c5d8fb7Sshaneh   /* This is needed on Windows so that a test case using this
72027c5d8fb7Sshaneh   ** function can open a read pipe and get the output of
72037c5d8fb7Sshaneh   ** printExplainQueryPlan() immediately.
72047c5d8fb7Sshaneh   */
72057c5d8fb7Sshaneh   fflush(stdout);
720691da6b83Sdan   Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
720791da6b83Sdan   return TCL_OK;
720891da6b83Sdan }
720991da6b83Sdan #endif /* SQLITE_OMIT_EXPLAIN */
7210a2c8a95bSdrh 
721185548facSdrh #include <time.h>
721285548facSdrh /*
721385548facSdrh ** This is an alternative localtime_r() implementation used for testing
721485548facSdrh ** the 'localtime' and 'utc' modifiers of date-time functions.  Because
721585548facSdrh ** the OS-supplied localtime_r() is locale-dependent, this alternative is
721685548facSdrh ** provided as a stable test platform.
721785548facSdrh **
721885548facSdrh ** Operation:
721985548facSdrh **
722085548facSdrh **     (1)  Localtime is 30 minutes earlier than (west of) UTC on
722185548facSdrh **          even days (counting from 1970-01-01)
722285548facSdrh **
722385548facSdrh **     (2)  Localtime is 30 minutes later than (east of) UTC on odd days.
722485548facSdrh **
722585548facSdrh **     (3)  The function fails for the specific date/time value
722685548facSdrh **          of 2000-05-29 14:16:00 in order to test the ability of
722785548facSdrh **          SQLite to deal with localtime_r() failures.
722885548facSdrh */
testLocaltime(const void * aliasT,void * aliasTM)722985548facSdrh static int testLocaltime(const void *aliasT, void *aliasTM){
723085548facSdrh   const time_t t = *(const time_t*)aliasT;
723185548facSdrh   struct tm *pTm = (struct tm *)aliasTM;
723285548facSdrh   time_t altT;
723385548facSdrh   sqlite3_int64 iJD;
723485548facSdrh   int Z, A, B, C, D, E, X1, S;
723585548facSdrh 
723685548facSdrh   if( (t/86400) & 1 ){
723785548facSdrh     altT = t + 1800;  /* 30 minutes later on odd days */
723885548facSdrh   }else{
723985548facSdrh     altT = t - 1800;  /* 30 minutes earlier on even days */
724085548facSdrh   }
724185548facSdrh   iJD = (sqlite3_int64)(altT + 210866760000);
724285548facSdrh   Z = (int)((iJD + 43200)/86400);
724385548facSdrh   A = (int)((Z - 1867216.25)/36524.25);
724485548facSdrh   A = Z + 1 + A - (A/4);
724585548facSdrh   B = A + 1524;
724685548facSdrh   C = (int)((B - 122.1)/365.25);
724785548facSdrh   D = (36525*(C&32767))/100;
724885548facSdrh   E = (int)((B-D)/30.6001);
724985548facSdrh   X1 = (int)(30.6001*E);
725085548facSdrh   pTm->tm_mday = B - D - X1;
725185548facSdrh   pTm->tm_mon = E<14 ? E-2 : E-14;
725285548facSdrh   pTm->tm_year = (pTm->tm_mon>1 ? C - 4716 : C - 4715) - 1900;
725385548facSdrh   S = (int)((iJD + 43200)%86400);
725485548facSdrh   pTm->tm_hour = S/3600;
725585548facSdrh   pTm->tm_min = (S/60)%60;
725685548facSdrh   pTm->tm_sec = S % 60;
725785548facSdrh   return t==959609760; /* Special case: 2000-05-29 14:16:00 fails */
725885548facSdrh }
725985548facSdrh 
7260a2c8a95bSdrh /*
7261c17d696cSdan ** sqlite3_test_control VERB ARGS...
7262c17d696cSdan */
test_test_control(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])72637617e4a8Smistachkin static int SQLITE_TCLAPI test_test_control(
7264c17d696cSdan   void * clientData,
7265c17d696cSdan   Tcl_Interp *interp,
7266c17d696cSdan   int objc,
7267c17d696cSdan   Tcl_Obj *CONST objv[]
7268c17d696cSdan ){
7269c17d696cSdan   struct Verb {
7270c17d696cSdan     const char *zName;
7271c17d696cSdan     int i;
7272c17d696cSdan   } aVerb[] = {
7273c17d696cSdan     { "SQLITE_TESTCTRL_LOCALTIME_FAULT",    SQLITE_TESTCTRL_LOCALTIME_FAULT },
72748930c2abSdan     { "SQLITE_TESTCTRL_SORTER_MMAP",        SQLITE_TESTCTRL_SORTER_MMAP     },
72751ffede8cSdrh     { "SQLITE_TESTCTRL_IMPOSTER",           SQLITE_TESTCTRL_IMPOSTER        },
7276eea8eb6dSdrh     { "SQLITE_TESTCTRL_INTERNAL_FUNCTIONS", SQLITE_TESTCTRL_INTERNAL_FUNCTIONS},
72779b6a2833Sdan     { 0, 0 }
7278c17d696cSdan   };
7279c17d696cSdan   int iVerb;
7280c17d696cSdan   int iFlag;
7281c17d696cSdan   int rc;
7282c17d696cSdan 
7283c17d696cSdan   if( objc<2 ){
7284c17d696cSdan     Tcl_WrongNumArgs(interp, 1, objv, "VERB ARGS...");
7285c17d696cSdan     return TCL_ERROR;
7286c17d696cSdan   }
7287c17d696cSdan 
7288c17d696cSdan   rc = Tcl_GetIndexFromObjStruct(
7289c17d696cSdan       interp, objv[1], aVerb, sizeof(aVerb[0]), "VERB", 0, &iVerb
7290c17d696cSdan   );
7291c17d696cSdan   if( rc!=TCL_OK ) return rc;
7292c17d696cSdan 
7293c17d696cSdan   iFlag = aVerb[iVerb].i;
7294c17d696cSdan   switch( iFlag ){
7295171c50ecSdrh     case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS: {
7296171c50ecSdrh       sqlite3 *db = 0;
7297171c50ecSdrh       if( objc!=3 ){
7298171c50ecSdrh         Tcl_WrongNumArgs(interp, 2, objv, "DB");
7299171c50ecSdrh         return TCL_ERROR;
7300171c50ecSdrh       }
7301171c50ecSdrh       if( getDbPointer(interp, Tcl_GetString(objv[2]), &db) ) return TCL_ERROR;
7302171c50ecSdrh       sqlite3_test_control(SQLITE_TESTCTRL_INTERNAL_FUNCTIONS, db);
7303171c50ecSdrh       break;
7304171c50ecSdrh     }
7305c17d696cSdan     case SQLITE_TESTCTRL_LOCALTIME_FAULT: {
7306c17d696cSdan       int val;
7307c17d696cSdan       if( objc!=3 ){
730885548facSdrh         Tcl_WrongNumArgs(interp, 2, objv, "0|1|2");
7309c17d696cSdan         return TCL_ERROR;
7310c17d696cSdan       }
731185548facSdrh       if( Tcl_GetIntFromObj(interp, objv[2], &val) ) return TCL_ERROR;
731285548facSdrh       sqlite3_test_control(iFlag, val, testLocaltime);
7313c17d696cSdan       break;
7314c17d696cSdan     }
73158930c2abSdan 
73168930c2abSdan     case SQLITE_TESTCTRL_SORTER_MMAP: {
73178930c2abSdan       int val;
73188930c2abSdan       sqlite3 *db;
73198930c2abSdan       if( objc!=4 ){
73208930c2abSdan         Tcl_WrongNumArgs(interp, 2, objv, "DB LIMIT");
73218930c2abSdan         return TCL_ERROR;
73228930c2abSdan       }
73238930c2abSdan       if( getDbPointer(interp, Tcl_GetString(objv[2]), &db) ) return TCL_ERROR;
73248930c2abSdan       if( Tcl_GetIntFromObj(interp, objv[3], &val) ) return TCL_ERROR;
73258930c2abSdan       sqlite3_test_control(SQLITE_TESTCTRL_SORTER_MMAP, db, val);
73268930c2abSdan       break;
73278930c2abSdan     }
7328917682a4Sdrh 
73291ffede8cSdrh     case SQLITE_TESTCTRL_IMPOSTER: {
73301ffede8cSdrh       int onOff, tnum;
73311ffede8cSdrh       const char *zDbName;
7332917682a4Sdrh       sqlite3 *db;
7333917682a4Sdrh       if( objc!=6 ){
73341ffede8cSdrh         Tcl_WrongNumArgs(interp, 2, objv, "DB dbName onOff tnum");
7335917682a4Sdrh         return TCL_ERROR;
7336917682a4Sdrh       }
7337917682a4Sdrh       if( getDbPointer(interp, Tcl_GetString(objv[2]), &db) ) return TCL_ERROR;
73381ffede8cSdrh       zDbName = Tcl_GetString(objv[3]);
73391ffede8cSdrh       if( Tcl_GetIntFromObj(interp, objv[4], &onOff) ) return TCL_ERROR;
73401ffede8cSdrh       if( Tcl_GetIntFromObj(interp, objv[5], &tnum) ) return TCL_ERROR;
73411ffede8cSdrh       sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, db, zDbName, onOff, tnum);
7342917682a4Sdrh       break;
7343917682a4Sdrh     }
7344c17d696cSdan   }
7345c17d696cSdan 
7346c17d696cSdan   Tcl_ResetResult(interp);
7347c17d696cSdan   return TCL_OK;
7348c17d696cSdan }
7349c17d696cSdan 
7350daf9a5a4Smistachkin #if SQLITE_OS_UNIX
7351a72014faSdan #include <sys/time.h>
7352a72014faSdan #include <sys/resource.h>
7353a72014faSdan 
test_getrusage(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])73547617e4a8Smistachkin static int SQLITE_TCLAPI test_getrusage(
7355a72014faSdan   void * clientData,
7356a72014faSdan   Tcl_Interp *interp,
7357a72014faSdan   int objc,
7358a72014faSdan   Tcl_Obj *CONST objv[]
7359a72014faSdan ){
7360a72014faSdan   char buf[1024];
7361a72014faSdan   struct rusage r;
7362a72014faSdan   memset(&r, 0, sizeof(r));
7363a72014faSdan   getrusage(RUSAGE_SELF, &r);
7364a72014faSdan 
736565545b59Sdrh   sqlite3_snprintf(sizeof(buf), buf,
736665545b59Sdrh     "ru_utime=%d.%06d ru_stime=%d.%06d ru_minflt=%d ru_majflt=%d",
73675d8a1372Sdan     (int)r.ru_utime.tv_sec, (int)r.ru_utime.tv_usec,
73685d8a1372Sdan     (int)r.ru_stime.tv_sec, (int)r.ru_stime.tv_usec,
73695d8a1372Sdan     (int)r.ru_minflt, (int)r.ru_majflt
7370a72014faSdan   );
7371a72014faSdan   Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, -1));
7372a72014faSdan   return TCL_OK;
7373a72014faSdan }
7374daf9a5a4Smistachkin #endif
7375a72014faSdan 
737680084ca8Sdrh #if SQLITE_OS_WIN
737780084ca8Sdrh /*
737880084ca8Sdrh ** Information passed from the main thread into the windows file locker
737980084ca8Sdrh ** background thread.
738080084ca8Sdrh */
738180084ca8Sdrh struct win32FileLocker {
7382176f1b47Smistachkin   char *evName;       /* Name of event to signal thread startup */
738380084ca8Sdrh   HANDLE h;           /* Handle of the file to be locked */
738480084ca8Sdrh   int delay1;         /* Delay before locking */
738580084ca8Sdrh   int delay2;         /* Delay before unlocking */
738680084ca8Sdrh   int ok;             /* Finished ok */
738780084ca8Sdrh   int err;            /* True if an error occurs */
738880084ca8Sdrh };
738980084ca8Sdrh #endif
739080084ca8Sdrh 
739180084ca8Sdrh 
739280084ca8Sdrh #if SQLITE_OS_WIN
73937da5fcb0Sdrh #include <process.h>
739480084ca8Sdrh /*
739580084ca8Sdrh ** The background thread that does file locking.
739680084ca8Sdrh */
win32_file_locker(void * pAppData)739769def7ffSmistachkin static void SQLITE_CDECL win32_file_locker(void *pAppData){
739880084ca8Sdrh   struct win32FileLocker *p = (struct win32FileLocker*)pAppData;
7399176f1b47Smistachkin   if( p->evName ){
7400176f1b47Smistachkin     HANDLE ev = OpenEvent(EVENT_MODIFY_STATE, FALSE, p->evName);
7401176f1b47Smistachkin     if ( ev ){
7402176f1b47Smistachkin       SetEvent(ev);
7403176f1b47Smistachkin       CloseHandle(ev);
7404176f1b47Smistachkin     }
7405176f1b47Smistachkin   }
740680084ca8Sdrh   if( p->delay1 ) Sleep(p->delay1);
740780084ca8Sdrh   if( LockFile(p->h, 0, 0, 100000000, 0) ){
740880084ca8Sdrh     Sleep(p->delay2);
740980084ca8Sdrh     UnlockFile(p->h, 0, 0, 100000000, 0);
741080084ca8Sdrh     p->ok = 1;
741180084ca8Sdrh   }else{
741280084ca8Sdrh     p->err = 1;
741380084ca8Sdrh   }
741480084ca8Sdrh   CloseHandle(p->h);
741580084ca8Sdrh   p->h = 0;
741680084ca8Sdrh   p->delay1 = 0;
741780084ca8Sdrh   p->delay2 = 0;
741880084ca8Sdrh }
741980084ca8Sdrh #endif
742080084ca8Sdrh 
742180084ca8Sdrh #if SQLITE_OS_WIN
742280084ca8Sdrh /*
742380084ca8Sdrh **      lock_win32_file FILENAME DELAY1 DELAY2
742480084ca8Sdrh **
742580084ca8Sdrh ** Get an exclusive manditory lock on file for DELAY2 milliseconds.
742680084ca8Sdrh ** Wait DELAY1 milliseconds before acquiring the lock.
742780084ca8Sdrh */
win32_file_lock(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])74287617e4a8Smistachkin static int SQLITE_TCLAPI win32_file_lock(
742980084ca8Sdrh   void * clientData,
743080084ca8Sdrh   Tcl_Interp *interp,
743180084ca8Sdrh   int objc,
743280084ca8Sdrh   Tcl_Obj *CONST objv[]
743380084ca8Sdrh ){
7434176f1b47Smistachkin   static struct win32FileLocker x = { "win32_file_lock", 0, 0, 0, 0, 0 };
743580084ca8Sdrh   const char *zFilename;
7436176f1b47Smistachkin   char zBuf[200];
743780084ca8Sdrh   int retry = 0;
7438176f1b47Smistachkin   HANDLE ev;
7439176f1b47Smistachkin   DWORD wResult;
744080084ca8Sdrh 
744180084ca8Sdrh   if( objc!=4 && objc!=1 ){
744280084ca8Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME DELAY1 DELAY2");
744380084ca8Sdrh     return TCL_ERROR;
744480084ca8Sdrh   }
744580084ca8Sdrh   if( objc==1 ){
744680084ca8Sdrh     sqlite3_snprintf(sizeof(zBuf), zBuf, "%d %d %d %d %d",
744780084ca8Sdrh                      x.ok, x.err, x.delay1, x.delay2, x.h);
744880084ca8Sdrh     Tcl_AppendResult(interp, zBuf, (char*)0);
744980084ca8Sdrh     return TCL_OK;
745080084ca8Sdrh   }
7451d0cdf012Sdrh   while( x.h && retry<30 ){
745280084ca8Sdrh     retry++;
745380084ca8Sdrh     Sleep(100);
745480084ca8Sdrh   }
745580084ca8Sdrh   if( x.h ){
745680084ca8Sdrh     Tcl_AppendResult(interp, "busy", (char*)0);
745780084ca8Sdrh     return TCL_ERROR;
745880084ca8Sdrh   }
745980084ca8Sdrh   if( Tcl_GetIntFromObj(interp, objv[2], &x.delay1) ) return TCL_ERROR;
746080084ca8Sdrh   if( Tcl_GetIntFromObj(interp, objv[3], &x.delay2) ) return TCL_ERROR;
746180084ca8Sdrh   zFilename = Tcl_GetString(objv[1]);
746280084ca8Sdrh   x.h = CreateFile(zFilename, GENERIC_READ|GENERIC_WRITE,
746380084ca8Sdrh               FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_ALWAYS,
746480084ca8Sdrh               FILE_ATTRIBUTE_NORMAL, 0);
746580084ca8Sdrh   if( !x.h ){
746680084ca8Sdrh     Tcl_AppendResult(interp, "cannot open file: ", zFilename, (char*)0);
746780084ca8Sdrh     return TCL_ERROR;
746880084ca8Sdrh   }
7469176f1b47Smistachkin   ev = CreateEvent(NULL, TRUE, FALSE, x.evName);
7470176f1b47Smistachkin   if ( !ev ){
7471176f1b47Smistachkin     Tcl_AppendResult(interp, "cannot create event: ", x.evName, (char*)0);
7472176f1b47Smistachkin     return TCL_ERROR;
7473176f1b47Smistachkin   }
747480084ca8Sdrh   _beginthread(win32_file_locker, 0, (void*)&x);
747580084ca8Sdrh   Sleep(0);
7476176f1b47Smistachkin   if ( (wResult = WaitForSingleObject(ev, 10000))!=WAIT_OBJECT_0 ){
7477176f1b47Smistachkin     sqlite3_snprintf(sizeof(zBuf), zBuf, "0x%x", wResult);
7478176f1b47Smistachkin     Tcl_AppendResult(interp, "wait failed: ", zBuf, (char*)0);
7479176f1b47Smistachkin     CloseHandle(ev);
7480176f1b47Smistachkin     return TCL_ERROR;
7481176f1b47Smistachkin   }
7482176f1b47Smistachkin   CloseHandle(ev);
748380084ca8Sdrh   return TCL_OK;
748480084ca8Sdrh }
74853741827eSmistachkin 
74863741827eSmistachkin /*
74873741827eSmistachkin **      exists_win32_path PATH
74883741827eSmistachkin **
74893741827eSmistachkin ** Returns non-zero if the specified path exists, whose fully qualified name
74903259fe79Smistachkin ** may exceed 260 characters if it is prefixed with "\\?\".
74913741827eSmistachkin */
win32_exists_path(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])74927617e4a8Smistachkin static int SQLITE_TCLAPI win32_exists_path(
74933741827eSmistachkin   void *clientData,
74943741827eSmistachkin   Tcl_Interp *interp,
74953741827eSmistachkin   int objc,
74963741827eSmistachkin   Tcl_Obj *CONST objv[]
74973741827eSmistachkin ){
74983741827eSmistachkin   if( objc!=2 ){
74993741827eSmistachkin     Tcl_WrongNumArgs(interp, 1, objv, "PATH");
75003741827eSmistachkin     return TCL_ERROR;
75013741827eSmistachkin   }
75023741827eSmistachkin   Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
75033741827eSmistachkin       GetFileAttributesW( Tcl_GetUnicode(objv[1]))!=INVALID_FILE_ATTRIBUTES ));
75043741827eSmistachkin   return TCL_OK;
75053741827eSmistachkin }
75063741827eSmistachkin 
75073741827eSmistachkin /*
75083741827eSmistachkin **      find_win32_file PATTERN
75093741827eSmistachkin **
75103741827eSmistachkin ** Returns a list of entries in a directory that match the specified pattern,
75113741827eSmistachkin ** whose fully qualified name may exceed 248 characters if it is prefixed with
75123741827eSmistachkin ** "\\?\".
75133741827eSmistachkin */
win32_find_file(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])75147617e4a8Smistachkin static int SQLITE_TCLAPI win32_find_file(
75153741827eSmistachkin   void *clientData,
75163741827eSmistachkin   Tcl_Interp *interp,
75173741827eSmistachkin   int objc,
75183741827eSmistachkin   Tcl_Obj *CONST objv[]
75193741827eSmistachkin ){
75203741827eSmistachkin   HANDLE hFindFile = INVALID_HANDLE_VALUE;
75213741827eSmistachkin   WIN32_FIND_DATAW findData;
75223741827eSmistachkin   Tcl_Obj *listObj;
75233741827eSmistachkin   DWORD lastErrno;
75243741827eSmistachkin   if( objc!=2 ){
75253741827eSmistachkin     Tcl_WrongNumArgs(interp, 1, objv, "PATTERN");
75263741827eSmistachkin     return TCL_ERROR;
75273741827eSmistachkin   }
75283741827eSmistachkin   hFindFile = FindFirstFileW(Tcl_GetUnicode(objv[1]), &findData);
75293741827eSmistachkin   if( hFindFile==INVALID_HANDLE_VALUE ){
75303741827eSmistachkin     Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
75313741827eSmistachkin     return TCL_ERROR;
75323741827eSmistachkin   }
75333741827eSmistachkin   listObj = Tcl_NewObj();
75343741827eSmistachkin   Tcl_IncrRefCount(listObj);
75353741827eSmistachkin   do {
75363741827eSmistachkin     Tcl_ListObjAppendElement(interp, listObj, Tcl_NewUnicodeObj(
75373741827eSmistachkin         findData.cFileName, -1));
75383741827eSmistachkin     Tcl_ListObjAppendElement(interp, listObj, Tcl_NewWideIntObj(
75393741827eSmistachkin         findData.dwFileAttributes));
75403741827eSmistachkin   } while( FindNextFileW(hFindFile, &findData) );
75413741827eSmistachkin   lastErrno = GetLastError();
75423741827eSmistachkin   if( lastErrno!=NO_ERROR && lastErrno!=ERROR_NO_MORE_FILES ){
75433741827eSmistachkin     FindClose(hFindFile);
75443741827eSmistachkin     Tcl_DecrRefCount(listObj);
75453741827eSmistachkin     Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
75463741827eSmistachkin     return TCL_ERROR;
75473741827eSmistachkin   }
75483741827eSmistachkin   FindClose(hFindFile);
75493741827eSmistachkin   Tcl_SetObjResult(interp, listObj);
75503741827eSmistachkin   return TCL_OK;
75513741827eSmistachkin }
75523741827eSmistachkin 
75533741827eSmistachkin /*
75543741827eSmistachkin **      delete_win32_file FILENAME
75553741827eSmistachkin **
75563259fe79Smistachkin ** Deletes the specified file, whose fully qualified name may exceed 260
75573741827eSmistachkin ** characters if it is prefixed with "\\?\".
75583741827eSmistachkin */
win32_delete_file(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])75597617e4a8Smistachkin static int SQLITE_TCLAPI win32_delete_file(
75603741827eSmistachkin   void *clientData,
75613741827eSmistachkin   Tcl_Interp *interp,
75623741827eSmistachkin   int objc,
75633741827eSmistachkin   Tcl_Obj *CONST objv[]
75643741827eSmistachkin ){
75653741827eSmistachkin   if( objc!=2 ){
75663741827eSmistachkin     Tcl_WrongNumArgs(interp, 1, objv, "FILENAME");
75673741827eSmistachkin     return TCL_ERROR;
75683741827eSmistachkin   }
75693741827eSmistachkin   if( !DeleteFileW(Tcl_GetUnicode(objv[1])) ){
75703741827eSmistachkin     Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
75713741827eSmistachkin     return TCL_ERROR;
75723741827eSmistachkin   }
75733741827eSmistachkin   Tcl_ResetResult(interp);
75743741827eSmistachkin   return TCL_OK;
75753741827eSmistachkin }
75763741827eSmistachkin 
75773741827eSmistachkin /*
75783741827eSmistachkin **      make_win32_dir DIRECTORY
75793741827eSmistachkin **
75803741827eSmistachkin ** Creates the specified directory, whose fully qualified name may exceed 248
75813741827eSmistachkin ** characters if it is prefixed with "\\?\".
75823741827eSmistachkin */
win32_mkdir(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])75837617e4a8Smistachkin static int SQLITE_TCLAPI win32_mkdir(
75843741827eSmistachkin   void *clientData,
75853741827eSmistachkin   Tcl_Interp *interp,
75863741827eSmistachkin   int objc,
75873741827eSmistachkin   Tcl_Obj *CONST objv[]
75883741827eSmistachkin ){
75893741827eSmistachkin   if( objc!=2 ){
75903741827eSmistachkin     Tcl_WrongNumArgs(interp, 1, objv, "DIRECTORY");
75913741827eSmistachkin     return TCL_ERROR;
75923741827eSmistachkin   }
75933741827eSmistachkin   if( !CreateDirectoryW(Tcl_GetUnicode(objv[1]), NULL) ){
75943741827eSmistachkin     Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
75953741827eSmistachkin     return TCL_ERROR;
75963741827eSmistachkin   }
75973741827eSmistachkin   Tcl_ResetResult(interp);
75983741827eSmistachkin   return TCL_OK;
75993741827eSmistachkin }
76003741827eSmistachkin 
76013741827eSmistachkin /*
76023741827eSmistachkin **      remove_win32_dir DIRECTORY
76033741827eSmistachkin **
76043741827eSmistachkin ** Removes the specified directory, whose fully qualified name may exceed 248
76053741827eSmistachkin ** characters if it is prefixed with "\\?\".
76063741827eSmistachkin */
win32_rmdir(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])76077617e4a8Smistachkin static int SQLITE_TCLAPI win32_rmdir(
76083741827eSmistachkin   void *clientData,
76093741827eSmistachkin   Tcl_Interp *interp,
76103741827eSmistachkin   int objc,
76113741827eSmistachkin   Tcl_Obj *CONST objv[]
76123741827eSmistachkin ){
76133741827eSmistachkin   if( objc!=2 ){
76143741827eSmistachkin     Tcl_WrongNumArgs(interp, 1, objv, "DIRECTORY");
76153741827eSmistachkin     return TCL_ERROR;
76163741827eSmistachkin   }
76173741827eSmistachkin   if( !RemoveDirectoryW(Tcl_GetUnicode(objv[1])) ){
76183741827eSmistachkin     Tcl_SetObjResult(interp, Tcl_NewWideIntObj(GetLastError()));
76193741827eSmistachkin     return TCL_ERROR;
76203741827eSmistachkin   }
76213741827eSmistachkin   Tcl_ResetResult(interp);
76223741827eSmistachkin   return TCL_OK;
76233741827eSmistachkin }
762480084ca8Sdrh #endif
7625c17d696cSdan 
7626d0cdf012Sdrh 
7627c17d696cSdan /*
7628f58ee7f1Sdrh **      optimization_control DB OPT BOOLEAN
7629f58ee7f1Sdrh **
7630f58ee7f1Sdrh ** Enable or disable query optimizations using the sqlite3_test_control()
7631f58ee7f1Sdrh ** interface.  Disable if BOOLEAN is false and enable if BOOLEAN is true.
7632*dc5e8c63Sdrh ** OPT is the name of the optimization to be disabled.  OPT can also be a
7633*dc5e8c63Sdrh ** list or optimizations names, in which case all optimizations named are
7634*dc5e8c63Sdrh ** enabled or disabled.
7635*dc5e8c63Sdrh **
7636*dc5e8c63Sdrh ** Each invocation of this control overrides all prior invocations.  The
7637*dc5e8c63Sdrh ** changes are not cumulative.
7638f58ee7f1Sdrh */
optimization_control(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])76397617e4a8Smistachkin static int SQLITE_TCLAPI optimization_control(
7640f58ee7f1Sdrh   void * clientData,
7641f58ee7f1Sdrh   Tcl_Interp *interp,
7642f58ee7f1Sdrh   int objc,
7643f58ee7f1Sdrh   Tcl_Obj *CONST objv[]
7644f58ee7f1Sdrh ){
7645f58ee7f1Sdrh   int i;
7646f58ee7f1Sdrh   sqlite3 *db;
7647f58ee7f1Sdrh   const char *zOpt;
7648f58ee7f1Sdrh   int onoff;
7649fc30b042Sdrh   int mask = 0;
7650b6d91679Sdrh   int cnt = 0;
7651f58ee7f1Sdrh   static const struct {
7652f58ee7f1Sdrh     const char *zOptName;
7653f58ee7f1Sdrh     int mask;
7654f58ee7f1Sdrh   } aOpt[] = {
76557e5418e4Sdrh     { "all",                 SQLITE_AllOpts        },
76569d5a579cSdrh     { "none",                0                     },
7657f58ee7f1Sdrh     { "query-flattener",     SQLITE_QueryFlattener },
7658f58ee7f1Sdrh     { "groupby-order",       SQLITE_GroupByOrder   },
7659f58ee7f1Sdrh     { "factor-constants",    SQLITE_FactorOutConst },
7660f4af1089Sdrh     { "distinct-opt",        SQLITE_DistinctOpt    },
7661de9a7b8aSdrh     { "cover-idx-scan",      SQLITE_CoverIdxScan   },
76627e5418e4Sdrh     { "order-by-idx-join",   SQLITE_OrderByIdxJoin },
76639d5a579cSdrh     { "transitive",          SQLITE_Transitive     },
76649d5a579cSdrh     { "omit-noop-join",      SQLITE_OmitNoopJoin   },
76655eae1d1bSdrh     { "stat4",               SQLITE_Stat4          },
7666e8825519Sdan     { "skip-scan",           SQLITE_SkipScan       },
7667fa508349Sdan     { "push-down",           SQLITE_PushDown       },
766838cebe07Sdrh     { "balanced-merge",      SQLITE_BalancedMerge  },
76699b6a2833Sdan     { "propagate-const",     SQLITE_PropagateConst },
7670f58ee7f1Sdrh   };
7671f58ee7f1Sdrh 
7672f58ee7f1Sdrh   if( objc!=4 ){
7673f58ee7f1Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB OPT BOOLEAN");
7674f58ee7f1Sdrh     return TCL_ERROR;
7675f58ee7f1Sdrh   }
7676f58ee7f1Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
7677f58ee7f1Sdrh   if( Tcl_GetBooleanFromObj(interp, objv[3], &onoff) ) return TCL_ERROR;
7678f58ee7f1Sdrh   zOpt = Tcl_GetString(objv[2]);
7679f58ee7f1Sdrh   for(i=0; i<sizeof(aOpt)/sizeof(aOpt[0]); i++){
7680b6d91679Sdrh     if( strstr(zOpt, aOpt[i].zOptName)!=0 ){
7681b6d91679Sdrh       mask |= aOpt[i].mask;
7682b6d91679Sdrh       cnt++;
7683f58ee7f1Sdrh     }
7684f58ee7f1Sdrh   }
7685f58ee7f1Sdrh   if( onoff ) mask = ~mask;
7686b6d91679Sdrh   if( cnt==0 ){
7687f58ee7f1Sdrh     Tcl_AppendResult(interp, "unknown optimization - should be one of:",
7688f58ee7f1Sdrh                      (char*)0);
7689f58ee7f1Sdrh     for(i=0; i<sizeof(aOpt)/sizeof(aOpt[0]); i++){
76909d5a579cSdrh       Tcl_AppendResult(interp, " ", aOpt[i].zOptName, (char*)0);
7691f58ee7f1Sdrh     }
7692f58ee7f1Sdrh     return TCL_ERROR;
7693f58ee7f1Sdrh   }
7694f58ee7f1Sdrh   sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, db, mask);
7695*dc5e8c63Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(mask));
7696f58ee7f1Sdrh   return TCL_OK;
7697f58ee7f1Sdrh }
7698f58ee7f1Sdrh 
7699248f2be9Sdrh /*
7700ea41dc44Sdrh **     load_static_extension DB NAME ...
7701248f2be9Sdrh **
7702ea41dc44Sdrh ** Load one or more statically linked extensions.
7703248f2be9Sdrh */
tclLoadStaticExtensionCmd(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])77047617e4a8Smistachkin static int SQLITE_TCLAPI tclLoadStaticExtensionCmd(
7705248f2be9Sdrh   void * clientData,
7706248f2be9Sdrh   Tcl_Interp *interp,
7707248f2be9Sdrh   int objc,
7708248f2be9Sdrh   Tcl_Obj *CONST objv[]
7709248f2be9Sdrh ){
77108416fc7fSdrh   extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*);
77111b22ad8aSlarrybr   extern int sqlite3_appendvfs_init(sqlite3*,char**,const sqlite3_api_routines*);
77122e3f87aeSdrh   extern int sqlite3_carray_init(sqlite3*,char**,const sqlite3_api_routines*);
77138416fc7fSdrh   extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*);
771435db31b2Sdrh   extern int sqlite3_csv_init(sqlite3*,char**,const sqlite3_api_routines*);
77151728bcb0Sdrh   extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*);
77169b84f035Sdrh   extern int sqlite3_explain_init(sqlite3*,char**,const sqlite3_api_routines*);
771751ed2983Sdrh   extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*);
7718beb9def0Sdrh   extern int sqlite3_decimal_init(sqlite3*,char**,const sqlite3_api_routines*);
7719e50db1c5Sdrh   extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*);
77208416fc7fSdrh   extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*);
7721ea41dc44Sdrh   extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*);
7722def3367eSdrh   extern int sqlite3_percentile_init(sqlite3*,char**,const sqlite3_api_routines*);
7723871b1349Sdan #ifndef SQLITE_OMIT_VIRTUALTABLE
77249c039d9fSdan   extern int sqlite3_prefixes_init(sqlite3*,char**,const sqlite3_api_routines*);
7725871b1349Sdan #endif
772682801a5bSdrh   extern int sqlite3_qpvtab_init(sqlite3*,char**,const sqlite3_api_routines*);
7727248f2be9Sdrh   extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*);
77286bada272Sdrh   extern int sqlite3_remember_init(sqlite3*,char**,const sqlite3_api_routines*);
7729398f872dSdrh   extern int sqlite3_series_init(sqlite3*,char**,const sqlite3_api_routines*);
7730b7045ab2Sdrh   extern int sqlite3_spellfix_init(sqlite3*,char**,const sqlite3_api_routines*);
77315f8cdac6Sdrh   extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*);
773224b6422dSdrh   extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*);
7733d8ecefa5Sdan   extern int sqlite3_unionvtab_init(sqlite3*,char**,const sqlite3_api_routines*);
773491f7211cSmistachkin #ifdef SQLITE_HAVE_ZLIB
7735373dc3bbSdan   extern int sqlite3_zipfile_init(sqlite3*,char**,const sqlite3_api_routines*);
773691f7211cSmistachkin #endif
7737248f2be9Sdrh   static const struct {
7738248f2be9Sdrh     const char *zExtName;
7739248f2be9Sdrh     int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*);
7740248f2be9Sdrh   } aExtension[] = {
77418416fc7fSdrh     { "amatch",                sqlite3_amatch_init               },
77421b22ad8aSlarrybr     { "appendvfs",             sqlite3_appendvfs_init            },
77432e3f87aeSdrh     { "carray",                sqlite3_carray_init               },
77448416fc7fSdrh     { "closure",               sqlite3_closure_init              },
774535db31b2Sdrh     { "csv",                   sqlite3_csv_init                  },
7746beb9def0Sdrh     { "decimal",               sqlite3_decimal_init              },
77471728bcb0Sdrh     { "eval",                  sqlite3_eval_init                 },
77489b84f035Sdrh     { "explain",               sqlite3_explain_init              },
774951ed2983Sdrh     { "fileio",                sqlite3_fileio_init               },
7750e50db1c5Sdrh     { "fuzzer",                sqlite3_fuzzer_init               },
77518416fc7fSdrh     { "ieee754",               sqlite3_ieee_init                 },
7752ea41dc44Sdrh     { "nextchar",              sqlite3_nextchar_init             },
7753def3367eSdrh     { "percentile",            sqlite3_percentile_init           },
7754871b1349Sdan #ifndef SQLITE_OMIT_VIRTUALTABLE
77559c039d9fSdan     { "prefixes",              sqlite3_prefixes_init             },
7756871b1349Sdan #endif
775782801a5bSdrh     { "qpvtab",                sqlite3_qpvtab_init               },
7758248f2be9Sdrh     { "regexp",                sqlite3_regexp_init               },
77596bada272Sdrh     { "remember",              sqlite3_remember_init             },
7760398f872dSdrh     { "series",                sqlite3_series_init               },
7761b7045ab2Sdrh     { "spellfix",              sqlite3_spellfix_init             },
77625f8cdac6Sdrh     { "totype",                sqlite3_totype_init               },
7763d8ecefa5Sdan     { "unionvtab",             sqlite3_unionvtab_init            },
776424b6422dSdrh     { "wholenumber",           sqlite3_wholenumber_init          },
776591f7211cSmistachkin #ifdef SQLITE_HAVE_ZLIB
7766373dc3bbSdan     { "zipfile",               sqlite3_zipfile_init              },
776791f7211cSmistachkin #endif
7768248f2be9Sdrh   };
7769248f2be9Sdrh   sqlite3 *db;
7770248f2be9Sdrh   const char *zName;
7771ea41dc44Sdrh   int i, j, rc;
7772248f2be9Sdrh   char *zErrMsg = 0;
7773ea41dc44Sdrh   if( objc<3 ){
7774ea41dc44Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB NAME ...");
7775248f2be9Sdrh     return TCL_ERROR;
7776248f2be9Sdrh   }
7777248f2be9Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
7778ea41dc44Sdrh   for(j=2; j<objc; j++){
7779ea41dc44Sdrh     zName = Tcl_GetString(objv[j]);
7780248f2be9Sdrh     for(i=0; i<ArraySize(aExtension); i++){
7781248f2be9Sdrh       if( strcmp(zName, aExtension[i].zExtName)==0 ) break;
7782248f2be9Sdrh     }
7783248f2be9Sdrh     if( i>=ArraySize(aExtension) ){
7784248f2be9Sdrh       Tcl_AppendResult(interp, "no such extension: ", zName, (char*)0);
7785248f2be9Sdrh       return TCL_ERROR;
7786248f2be9Sdrh     }
7787c306e08aSdrh     if( aExtension[i].pInit ){
7788248f2be9Sdrh       rc = aExtension[i].pInit(db, &zErrMsg, 0);
7789c306e08aSdrh     }else{
7790c306e08aSdrh       rc = SQLITE_OK;
7791c306e08aSdrh     }
77921b22ad8aSlarrybr     if( (rc!=SQLITE_OK && rc!=SQLITE_OK_LOAD_PERMANENTLY) || zErrMsg ){
7793248f2be9Sdrh       Tcl_AppendResult(interp, "initialization of ", zName, " failed: ", zErrMsg,
7794248f2be9Sdrh                        (char*)0);
7795248f2be9Sdrh       sqlite3_free(zErrMsg);
7796248f2be9Sdrh       return TCL_ERROR;
7797248f2be9Sdrh     }
7798ea41dc44Sdrh   }
7799248f2be9Sdrh   return TCL_OK;
7800248f2be9Sdrh }
7801248f2be9Sdrh 
78020d51def2Sdan /*
78030d51def2Sdan **     sorter_test_fakeheap BOOL
78040d51def2Sdan **
78050d51def2Sdan */
sorter_test_fakeheap(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])78067617e4a8Smistachkin static int SQLITE_TCLAPI sorter_test_fakeheap(
78070d51def2Sdan   void * clientData,
78080d51def2Sdan   Tcl_Interp *interp,
78090d51def2Sdan   int objc,
78100d51def2Sdan   Tcl_Obj *CONST objv[]
78110d51def2Sdan ){
78120d51def2Sdan   int bArg;
78130d51def2Sdan   if( objc!=2 ){
78140d51def2Sdan     Tcl_WrongNumArgs(interp, 1, objv, "BOOL");
78150d51def2Sdan     return TCL_ERROR;
78160d51def2Sdan   }
78170d51def2Sdan 
78180d51def2Sdan   if( Tcl_GetBooleanFromObj(interp, objv[1], &bArg) ){
78190d51def2Sdan     return TCL_ERROR;
78200d51def2Sdan   }
78210d51def2Sdan 
78220d51def2Sdan   if( bArg ){
78230d51def2Sdan     if( sqlite3GlobalConfig.pHeap==0 ){
78240d51def2Sdan       sqlite3GlobalConfig.pHeap = SQLITE_INT_TO_PTR(-1);
78250d51def2Sdan     }
78260d51def2Sdan   }else{
78270d51def2Sdan     if( sqlite3GlobalConfig.pHeap==SQLITE_INT_TO_PTR(-1) ){
78280d51def2Sdan       sqlite3GlobalConfig.pHeap = 0;
78290d51def2Sdan     }
78300d51def2Sdan   }
78310d51def2Sdan 
78320d51def2Sdan   Tcl_ResetResult(interp);
78330d51def2Sdan   return TCL_OK;
78340d51def2Sdan }
78350d51def2Sdan 
7836dfea4533Sdan /*
7837dfea4533Sdan **     sorter_test_sort4_helper DB SQL1 NSTEP SQL2
7838dfea4533Sdan **
7839dfea4533Sdan ** Compile SQL statement $SQL1 and step it $NSTEP times. For each row,
7840dfea4533Sdan ** check that the leftmost and rightmost columns returned are both integers,
7841dfea4533Sdan ** and that both contain the same value.
7842dfea4533Sdan **
7843dfea4533Sdan ** Then execute statement $SQL2. Check that the statement returns the same
7844dfea4533Sdan ** set of integers in the same order as in the previous step (using $SQL1).
7845dfea4533Sdan */
sorter_test_sort4_helper(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])78467617e4a8Smistachkin static int SQLITE_TCLAPI sorter_test_sort4_helper(
7847dfea4533Sdan   void * clientData,
7848dfea4533Sdan   Tcl_Interp *interp,
7849dfea4533Sdan   int objc,
7850dfea4533Sdan   Tcl_Obj *CONST objv[]
7851dfea4533Sdan ){
7852dfea4533Sdan   const char *zSql1;
7853dfea4533Sdan   const char *zSql2;
7854dfea4533Sdan   int nStep;
7855dfea4533Sdan   int iStep;
785648cd59a5Sdrh   unsigned int iCksum1 = 0;
785748cd59a5Sdrh   unsigned int iCksum2 = 0;
7858dfea4533Sdan   int rc;
7859dfea4533Sdan   int iB;
7860dfea4533Sdan   sqlite3 *db;
7861dfea4533Sdan   sqlite3_stmt *pStmt;
7862dfea4533Sdan 
7863dfea4533Sdan   if( objc!=5 ){
7864dfea4533Sdan     Tcl_WrongNumArgs(interp, 1, objv, "DB SQL1 NSTEP SQL2");
7865dfea4533Sdan     return TCL_ERROR;
7866dfea4533Sdan   }
7867dfea4533Sdan 
7868dfea4533Sdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
7869dfea4533Sdan   zSql1 = Tcl_GetString(objv[2]);
7870dfea4533Sdan   if( Tcl_GetIntFromObj(interp, objv[3], &nStep) ) return TCL_ERROR;
7871dfea4533Sdan   zSql2 = Tcl_GetString(objv[4]);
7872dfea4533Sdan 
7873dfea4533Sdan   rc = sqlite3_prepare_v2(db, zSql1, -1, &pStmt, 0);
7874dfea4533Sdan   if( rc!=SQLITE_OK ) goto sql_error;
7875dfea4533Sdan 
7876dfea4533Sdan   iB = sqlite3_column_count(pStmt)-1;
7877dfea4533Sdan   for(iStep=0; iStep<nStep && SQLITE_ROW==sqlite3_step(pStmt); iStep++){
7878dfea4533Sdan     int a = sqlite3_column_int(pStmt, 0);
7879dfea4533Sdan     if( a!=sqlite3_column_int(pStmt, iB) ){
7880dfea4533Sdan       Tcl_AppendResult(interp, "data error: (a!=b)", 0);
7881dfea4533Sdan       return TCL_ERROR;
7882dfea4533Sdan     }
7883dfea4533Sdan 
788448cd59a5Sdrh     iCksum1 += (iCksum1 << 3) + (unsigned int)a;
7885dfea4533Sdan   }
7886dfea4533Sdan   rc = sqlite3_finalize(pStmt);
7887dfea4533Sdan   if( rc!=SQLITE_OK ) goto sql_error;
7888dfea4533Sdan 
7889dfea4533Sdan   rc = sqlite3_prepare_v2(db, zSql2, -1, &pStmt, 0);
7890dfea4533Sdan   if( rc!=SQLITE_OK ) goto sql_error;
7891dfea4533Sdan   for(iStep=0; SQLITE_ROW==sqlite3_step(pStmt); iStep++){
7892dfea4533Sdan     int a = sqlite3_column_int(pStmt, 0);
789348cd59a5Sdrh     iCksum2 += (iCksum2 << 3) + (unsigned int)a;
7894dfea4533Sdan   }
7895dfea4533Sdan   rc = sqlite3_finalize(pStmt);
7896dfea4533Sdan   if( rc!=SQLITE_OK ) goto sql_error;
7897dfea4533Sdan 
7898dfea4533Sdan   if( iCksum1!=iCksum2 ){
7899dfea4533Sdan     Tcl_AppendResult(interp, "checksum mismatch", 0);
7900dfea4533Sdan     return TCL_ERROR;
7901dfea4533Sdan   }
7902dfea4533Sdan 
7903dfea4533Sdan   return TCL_OK;
7904dfea4533Sdan  sql_error:
7905dfea4533Sdan   Tcl_AppendResult(interp, "sql error: ", sqlite3_errmsg(db), 0);
7906dfea4533Sdan   return TCL_ERROR;
7907dfea4533Sdan }
7908dfea4533Sdan 
7909248f2be9Sdrh 
7910d39c40ffSdrh #ifdef SQLITE_USER_AUTHENTICATION
7911d39c40ffSdrh #include "sqlite3userauth.h"
7912d39c40ffSdrh /*
7913d39c40ffSdrh ** tclcmd:  sqlite3_user_authenticate DB USERNAME PASSWORD
7914d39c40ffSdrh */
test_user_authenticate(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])79157617e4a8Smistachkin static int SQLITE_TCLAPI test_user_authenticate(
7916d39c40ffSdrh   ClientData clientData, /* Unused */
7917d39c40ffSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
7918d39c40ffSdrh   int objc,              /* Number of arguments */
7919d39c40ffSdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
7920d39c40ffSdrh ){
7921d39c40ffSdrh   char *zUser = 0;
7922d39c40ffSdrh   char *zPasswd = 0;
7923d39c40ffSdrh   int nPasswd = 0;
7924d39c40ffSdrh   sqlite3 *db;
7925d39c40ffSdrh   int rc;
7926d39c40ffSdrh 
7927d39c40ffSdrh   if( objc!=4 ){
7928d39c40ffSdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD");
7929d39c40ffSdrh     return TCL_ERROR;
7930d39c40ffSdrh   }
7931d39c40ffSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
7932d39c40ffSdrh     return TCL_ERROR;
7933d39c40ffSdrh   }
7934d39c40ffSdrh   zUser = Tcl_GetString(objv[2]);
7935d39c40ffSdrh   zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd);
7936d39c40ffSdrh   rc = sqlite3_user_authenticate(db, zUser, zPasswd, nPasswd);
7937d39c40ffSdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
7938d39c40ffSdrh   return TCL_OK;
7939d39c40ffSdrh }
7940d39c40ffSdrh #endif /* SQLITE_USER_AUTHENTICATION */
7941d39c40ffSdrh 
7942d39c40ffSdrh #ifdef SQLITE_USER_AUTHENTICATION
7943d39c40ffSdrh /*
7944d39c40ffSdrh ** tclcmd:  sqlite3_user_add DB USERNAME PASSWORD ISADMIN
7945d39c40ffSdrh */
test_user_add(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])79467617e4a8Smistachkin static int SQLITE_TCLAPI test_user_add(
7947d39c40ffSdrh   ClientData clientData, /* Unused */
7948d39c40ffSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
7949d39c40ffSdrh   int objc,              /* Number of arguments */
7950d39c40ffSdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
7951d39c40ffSdrh ){
7952d39c40ffSdrh   char *zUser = 0;
7953d39c40ffSdrh   char *zPasswd = 0;
7954d39c40ffSdrh   int nPasswd = 0;
7955d39c40ffSdrh   int isAdmin = 0;
7956d39c40ffSdrh   sqlite3 *db;
7957d39c40ffSdrh   int rc;
7958d39c40ffSdrh 
7959d39c40ffSdrh   if( objc!=5 ){
7960d39c40ffSdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD ISADMIN");
7961d39c40ffSdrh     return TCL_ERROR;
7962d39c40ffSdrh   }
7963d39c40ffSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
7964d39c40ffSdrh     return TCL_ERROR;
7965d39c40ffSdrh   }
7966d39c40ffSdrh   zUser = Tcl_GetString(objv[2]);
7967d39c40ffSdrh   zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd);
7968d39c40ffSdrh   Tcl_GetBooleanFromObj(interp, objv[4], &isAdmin);
7969d39c40ffSdrh   rc = sqlite3_user_add(db, zUser, zPasswd, nPasswd, isAdmin);
7970d39c40ffSdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
7971d39c40ffSdrh   return TCL_OK;
7972d39c40ffSdrh }
7973d39c40ffSdrh #endif /* SQLITE_USER_AUTHENTICATION */
7974d39c40ffSdrh 
7975d39c40ffSdrh #ifdef SQLITE_USER_AUTHENTICATION
7976d39c40ffSdrh /*
7977d39c40ffSdrh ** tclcmd:  sqlite3_user_change DB USERNAME PASSWORD ISADMIN
7978d39c40ffSdrh */
test_user_change(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])79797617e4a8Smistachkin static int SQLITE_TCLAPI test_user_change(
7980d39c40ffSdrh   ClientData clientData, /* Unused */
7981d39c40ffSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
7982d39c40ffSdrh   int objc,              /* Number of arguments */
7983d39c40ffSdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
7984d39c40ffSdrh ){
7985d39c40ffSdrh   char *zUser = 0;
7986d39c40ffSdrh   char *zPasswd = 0;
7987d39c40ffSdrh   int nPasswd = 0;
7988d39c40ffSdrh   int isAdmin = 0;
7989d39c40ffSdrh   sqlite3 *db;
7990d39c40ffSdrh   int rc;
7991d39c40ffSdrh 
7992d39c40ffSdrh   if( objc!=5 ){
7993d39c40ffSdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME PASSWORD ISADMIN");
7994d39c40ffSdrh     return TCL_ERROR;
7995d39c40ffSdrh   }
7996d39c40ffSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
7997d39c40ffSdrh     return TCL_ERROR;
7998d39c40ffSdrh   }
7999d39c40ffSdrh   zUser = Tcl_GetString(objv[2]);
8000d39c40ffSdrh   zPasswd = Tcl_GetStringFromObj(objv[3], &nPasswd);
8001d39c40ffSdrh   Tcl_GetBooleanFromObj(interp, objv[4], &isAdmin);
8002d39c40ffSdrh   rc = sqlite3_user_change(db, zUser, zPasswd, nPasswd, isAdmin);
8003d39c40ffSdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
8004d39c40ffSdrh   return TCL_OK;
8005d39c40ffSdrh }
8006d39c40ffSdrh #endif /* SQLITE_USER_AUTHENTICATION */
8007d39c40ffSdrh 
8008d39c40ffSdrh #ifdef SQLITE_USER_AUTHENTICATION
8009d39c40ffSdrh /*
8010d39c40ffSdrh ** tclcmd:  sqlite3_user_delete DB USERNAME
8011d39c40ffSdrh */
test_user_delete(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])80127617e4a8Smistachkin static int SQLITE_TCLAPI test_user_delete(
8013d39c40ffSdrh   ClientData clientData, /* Unused */
8014d39c40ffSdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
8015d39c40ffSdrh   int objc,              /* Number of arguments */
8016d39c40ffSdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
8017d39c40ffSdrh ){
8018d39c40ffSdrh   char *zUser = 0;
8019d39c40ffSdrh   sqlite3 *db;
8020d39c40ffSdrh   int rc;
8021d39c40ffSdrh 
8022d39c40ffSdrh   if( objc!=3 ){
8023d39c40ffSdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB USERNAME");
8024d39c40ffSdrh     return TCL_ERROR;
8025d39c40ffSdrh   }
8026d39c40ffSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
8027d39c40ffSdrh     return TCL_ERROR;
8028d39c40ffSdrh   }
8029d39c40ffSdrh   zUser = Tcl_GetString(objv[2]);
8030d39c40ffSdrh   rc = sqlite3_user_delete(db, zUser);
8031d39c40ffSdrh   Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
8032d39c40ffSdrh   return TCL_OK;
8033d39c40ffSdrh }
8034d39c40ffSdrh #endif /* SQLITE_USER_AUTHENTICATION */
8035d39c40ffSdrh 
8036f58ee7f1Sdrh /*
8037edb31cd1Sdrh ** tclcmd: bad_behavior TYPE
8038edb31cd1Sdrh **
8039edb31cd1Sdrh ** Do some things that should trigger a valgrind or -fsanitize=undefined
8040edb31cd1Sdrh ** warning.  This is used to verify that errors and warnings output by those
8041edb31cd1Sdrh ** tools are detected by the test scripts.
8042edb31cd1Sdrh **
8043edb31cd1Sdrh **       TYPE       BEHAVIOR
8044edb31cd1Sdrh **       1          Overflow a signed integer
8045edb31cd1Sdrh **       2          Jump based on an uninitialized variable
8046edb31cd1Sdrh **       3          Read after free
8047db6bafaeSdrh **       4          Panic
8048edb31cd1Sdrh */
test_bad_behavior(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])80497617e4a8Smistachkin static int SQLITE_TCLAPI test_bad_behavior(
8050edb31cd1Sdrh   ClientData clientData, /* Pointer to an integer containing zero */
8051edb31cd1Sdrh   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
8052edb31cd1Sdrh   int objc,              /* Number of arguments */
8053edb31cd1Sdrh   Tcl_Obj *CONST objv[]  /* Command arguments */
8054edb31cd1Sdrh ){
8055edb31cd1Sdrh   int iType;
8056edb31cd1Sdrh   int xyz;
8057edb31cd1Sdrh   int i = *(int*)clientData;
8058edb31cd1Sdrh   int j;
8059edb31cd1Sdrh   int w[10];
8060edb31cd1Sdrh   int *a;
8061edb31cd1Sdrh   if( objc!=2 ){
8062edb31cd1Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "TYPE");
8063edb31cd1Sdrh     return TCL_ERROR;
8064edb31cd1Sdrh   }
8065edb31cd1Sdrh   if( Tcl_GetIntFromObj(interp, objv[1], &iType) ) return TCL_ERROR;
8066edb31cd1Sdrh   switch( iType ){
8067edb31cd1Sdrh     case 1: {
8068edb31cd1Sdrh       xyz = 0x7fffff00 - i;
8069edb31cd1Sdrh       xyz += 0x100;
8070edb31cd1Sdrh       Tcl_SetObjResult(interp, Tcl_NewIntObj(xyz));
8071edb31cd1Sdrh       break;
8072edb31cd1Sdrh     }
8073edb31cd1Sdrh     case 2: {
8074edb31cd1Sdrh       w[1] = 5;
8075edb31cd1Sdrh       if( w[i]>0 ) w[1]++;
8076edb31cd1Sdrh       Tcl_SetObjResult(interp, Tcl_NewIntObj(w[1]));
8077edb31cd1Sdrh       break;
8078edb31cd1Sdrh     }
8079edb31cd1Sdrh     case 3: {
8080edb31cd1Sdrh       a = malloc( sizeof(int)*10 );
8081edb31cd1Sdrh       for(j=0; j<10; j++) a[j] = j;
8082edb31cd1Sdrh       free(a);
8083edb31cd1Sdrh       Tcl_SetObjResult(interp, Tcl_NewIntObj(a[i]));
8084edb31cd1Sdrh       break;
8085edb31cd1Sdrh     }
8086db6bafaeSdrh     case 4: {
8087db6bafaeSdrh       Tcl_Panic("Deliberate panic");
8088db6bafaeSdrh       break;
8089db6bafaeSdrh     }
8090edb31cd1Sdrh   }
8091edb31cd1Sdrh   return TCL_OK;
8092edb31cd1Sdrh }
8093edb31cd1Sdrh 
80943e0327d5Sdrh /*
80953e0327d5Sdrh ** tclcmd:   register_dbstat_vtab DB
80963e0327d5Sdrh **
80973e0327d5Sdrh ** Cause the dbstat virtual table to be available on the connection DB
80983e0327d5Sdrh */
test_register_dbstat_vtab(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])80997617e4a8Smistachkin static int SQLITE_TCLAPI test_register_dbstat_vtab(
81003e0327d5Sdrh   void *clientData,
81013e0327d5Sdrh   Tcl_Interp *interp,
81023e0327d5Sdrh   int objc,
81033e0327d5Sdrh   Tcl_Obj *CONST objv[]
81043e0327d5Sdrh ){
81053e0327d5Sdrh #ifdef SQLITE_OMIT_VIRTUALTABLE
81063e0327d5Sdrh   Tcl_AppendResult(interp, "dbstat not available because of "
81073e0327d5Sdrh                            "SQLITE_OMIT_VIRTUALTABLE", (void*)0);
81083e0327d5Sdrh   return TCL_ERROR;
81093e0327d5Sdrh #else
81103e0327d5Sdrh   struct SqliteDb { sqlite3 *db; };
81113e0327d5Sdrh   char *zDb;
81123e0327d5Sdrh   Tcl_CmdInfo cmdInfo;
81133e0327d5Sdrh 
81143e0327d5Sdrh   if( objc!=2 ){
81153e0327d5Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB");
81163e0327d5Sdrh     return TCL_ERROR;
81173e0327d5Sdrh   }
81183e0327d5Sdrh 
81193e0327d5Sdrh   zDb = Tcl_GetString(objv[1]);
81203e0327d5Sdrh   if( Tcl_GetCommandInfo(interp, zDb, &cmdInfo) ){
81213e0327d5Sdrh     sqlite3* db = ((struct SqliteDb*)cmdInfo.objClientData)->db;
81223e0327d5Sdrh     sqlite3DbstatRegister(db);
81233e0327d5Sdrh   }
81243e0327d5Sdrh   return TCL_OK;
81253e0327d5Sdrh #endif /* SQLITE_OMIT_VIRTUALTABLE */
81263e0327d5Sdrh }
8127edb31cd1Sdrh 
8128edb31cd1Sdrh /*
8129d42908fbSdrh ** tclcmd:   sqlite3_db_config DB SETTING VALUE
8130d42908fbSdrh **
8131d42908fbSdrh ** Invoke sqlite3_db_config() for one of the setting values.
8132d42908fbSdrh */
test_sqlite3_db_config(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])81337617e4a8Smistachkin static int SQLITE_TCLAPI test_sqlite3_db_config(
8134d42908fbSdrh   void *clientData,
8135d42908fbSdrh   Tcl_Interp *interp,
8136d42908fbSdrh   int objc,
8137d42908fbSdrh   Tcl_Obj *CONST objv[]
8138d42908fbSdrh ){
8139d42908fbSdrh   static const struct {
8140d42908fbSdrh     const char *zName;
8141d42908fbSdrh     int eVal;
8142d42908fbSdrh   } aSetting[] = {
8143d42908fbSdrh     { "FKEY",               SQLITE_DBCONFIG_ENABLE_FKEY },
8144d42908fbSdrh     { "TRIGGER",            SQLITE_DBCONFIG_ENABLE_TRIGGER },
8145d42908fbSdrh     { "FTS3_TOKENIZER",     SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER },
8146191dd061Sdrh     { "LOAD_EXTENSION",     SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION },
8147298af023Sdan     { "NO_CKPT_ON_CLOSE",   SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE },
8148169dd928Sdrh     { "QPSG",               SQLITE_DBCONFIG_ENABLE_QPSG },
81497df01196Sdrh     { "TRIGGER_EQP",        SQLITE_DBCONFIG_TRIGGER_EQP },
81507df01196Sdrh     { "RESET_DB",           SQLITE_DBCONFIG_RESET_DATABASE },
81510f1c2eb5Sdrh     { "DEFENSIVE",          SQLITE_DBCONFIG_DEFENSIVE },
81520a6873bfSdrh     { "WRITABLE_SCHEMA",    SQLITE_DBCONFIG_WRITABLE_SCHEMA },
81530a6873bfSdrh     { "LEGACY_ALTER_TABLE", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE },
8154d0ff601cSdrh     { "DQS_DML",            SQLITE_DBCONFIG_DQS_DML },
8155d0ff601cSdrh     { "DQS_DDL",            SQLITE_DBCONFIG_DQS_DDL },
815666c48907Sdrh     { "LEGACY_FILE_FORMAT", SQLITE_DBCONFIG_LEGACY_FILE_FORMAT },
8157d42908fbSdrh   };
8158d42908fbSdrh   int i;
815966c48907Sdrh   int v = 0;
8160d42908fbSdrh   const char *zSetting;
8161d42908fbSdrh   sqlite3 *db;
8162d42908fbSdrh 
816366c48907Sdrh   if( objc!=4 && objc!=3 ){
816466c48907Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB SETTING [VALUE]");
8165d42908fbSdrh     return TCL_ERROR;
8166d42908fbSdrh   }
8167d42908fbSdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
8168d42908fbSdrh   zSetting = Tcl_GetString(objv[2]);
8169d42908fbSdrh   if( sqlite3_strglob("SQLITE_*", zSetting)==0 ) zSetting += 7;
8170d42908fbSdrh   if( sqlite3_strglob("DBCONFIG_*", zSetting)==0 ) zSetting += 9;
8171d42908fbSdrh   if( sqlite3_strglob("ENABLE_*", zSetting)==0 ) zSetting += 7;
8172d42908fbSdrh   for(i=0; i<ArraySize(aSetting); i++){
8173d42908fbSdrh     if( strcmp(zSetting, aSetting[i].zName)==0 ) break;
8174d42908fbSdrh   }
8175d42908fbSdrh   if( i>=ArraySize(aSetting) ){
8176d42908fbSdrh     Tcl_SetObjResult(interp,
8177d42908fbSdrh       Tcl_NewStringObj("unknown sqlite3_db_config setting", -1));
8178d42908fbSdrh     return TCL_ERROR;
8179d42908fbSdrh   }
818066c48907Sdrh   if( objc==4 ){
8181d42908fbSdrh     if( Tcl_GetIntFromObj(interp, objv[3], &v) ) return TCL_ERROR;
818266c48907Sdrh   }else{
818366c48907Sdrh     v = -1;
818466c48907Sdrh   }
8185d42908fbSdrh   sqlite3_db_config(db, aSetting[i].eVal, v, &v);
8186d42908fbSdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(v));
8187d42908fbSdrh   return TCL_OK;
8188d42908fbSdrh }
818999744fa4Sdrh /*
819099744fa4Sdrh ** tclcmd:   sqlite3_txn_state DB ?SCHEMA?
819199744fa4Sdrh **
819299744fa4Sdrh ** Invoke sqlite3_txn_state(DB,SCHEMA) and return the
819399744fa4Sdrh ** numeric value that results.  Use NULL for SCHEMA if the 3 argument
819499744fa4Sdrh ** is omitted.
819599744fa4Sdrh */
test_sqlite3_txn_state(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])819699744fa4Sdrh static int SQLITE_TCLAPI test_sqlite3_txn_state(
819799744fa4Sdrh   void *clientData,
819899744fa4Sdrh   Tcl_Interp *interp,
819999744fa4Sdrh   int objc,
820099744fa4Sdrh   Tcl_Obj *CONST objv[]
820199744fa4Sdrh ){
820299744fa4Sdrh   sqlite3 *db;
820399744fa4Sdrh   const char *zSchema;
820499744fa4Sdrh   int iTxn;
820599744fa4Sdrh 
820699744fa4Sdrh   if( objc!=2 && objc!=3 ){
820799744fa4Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB ?SCHEMA?");
820899744fa4Sdrh     return TCL_ERROR;
820999744fa4Sdrh   }
821099744fa4Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
821199744fa4Sdrh   zSchema = objc==3 ? Tcl_GetString(objv[2]) : 0;
821299744fa4Sdrh   iTxn = sqlite3_txn_state(db, zSchema);
821399744fa4Sdrh   Tcl_SetObjResult(interp, Tcl_NewIntObj(iTxn));
821499744fa4Sdrh   return TCL_OK;
821599744fa4Sdrh }
8216d42908fbSdrh 
8217d42908fbSdrh /*
8218da84dcaeSdrh ** Change the name of the main database schema from "main" to "icecube".
8219da84dcaeSdrh */
test_dbconfig_maindbname_icecube(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])8220da84dcaeSdrh static int SQLITE_TCLAPI test_dbconfig_maindbname_icecube(
8221da84dcaeSdrh   void * clientData,
8222da84dcaeSdrh   Tcl_Interp *interp,
8223da84dcaeSdrh   int objc,
8224da84dcaeSdrh   Tcl_Obj *CONST objv[]
8225da84dcaeSdrh ){
8226da84dcaeSdrh   int rc;
8227da84dcaeSdrh   sqlite3 *db;
8228da84dcaeSdrh   extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
8229da84dcaeSdrh   if( objc!=2 ){
8230da84dcaeSdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB");
8231da84dcaeSdrh     return TCL_ERROR;
8232da84dcaeSdrh   }else{
8233da84dcaeSdrh     if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
8234da84dcaeSdrh     rc = sqlite3_db_config(db, SQLITE_DBCONFIG_MAINDBNAME, "icecube");
8235da84dcaeSdrh     Tcl_SetObjResult(interp, Tcl_NewIntObj(rc));
8236da84dcaeSdrh     return TCL_OK;
8237da84dcaeSdrh   }
8238da84dcaeSdrh }
8239da84dcaeSdrh 
8240da84dcaeSdrh /*
8241460f1fa5Sdan ** Usage: sqlite3_mmap_warm DB DBNAME
8242460f1fa5Sdan */
test_mmap_warm(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])8243460f1fa5Sdan static int SQLITE_TCLAPI test_mmap_warm(
8244460f1fa5Sdan   void * clientData,
8245460f1fa5Sdan   Tcl_Interp *interp,
8246460f1fa5Sdan   int objc,
8247460f1fa5Sdan   Tcl_Obj *CONST objv[]
8248460f1fa5Sdan ){
8249460f1fa5Sdan   extern int getDbPointer(Tcl_Interp*, const char*, sqlite3**);
8250460f1fa5Sdan   extern int sqlite3_mmap_warm(sqlite3 *db, const char *);
8251460f1fa5Sdan 
8252460f1fa5Sdan   if( objc!=2 && objc!=3 ){
8253460f1fa5Sdan     Tcl_WrongNumArgs(interp, 1, objv, "DB ?DBNAME?");
8254460f1fa5Sdan     return TCL_ERROR;
8255460f1fa5Sdan   }else{
8256460f1fa5Sdan     int rc;
8257460f1fa5Sdan     sqlite3 *db;
8258460f1fa5Sdan     const char *zDb = 0;
8259460f1fa5Sdan     if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
8260460f1fa5Sdan     if( objc==3 ){
8261460f1fa5Sdan       zDb = Tcl_GetString(objv[2]);
8262460f1fa5Sdan     }
8263460f1fa5Sdan     rc = sqlite3_mmap_warm(db, zDb);
8264460f1fa5Sdan     Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
8265460f1fa5Sdan     return TCL_OK;
8266460f1fa5Sdan   }
8267460f1fa5Sdan }
8268460f1fa5Sdan 
8269460f1fa5Sdan /*
827091faeec8Sdan ** Usage:  test_write_db DB OFFSET DATA
827191faeec8Sdan **
827291faeec8Sdan ** Obtain the sqlite3_file* object for the database file for the "main" db
827391faeec8Sdan ** of handle DB. Then invoke its xWrite method to write data DATA to offset
827491faeec8Sdan ** OFFSET.
827591faeec8Sdan */
test_write_db(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])827691faeec8Sdan static int SQLITE_TCLAPI test_write_db(
827791faeec8Sdan   void * clientData,
827891faeec8Sdan   Tcl_Interp *interp,
827991faeec8Sdan   int objc,
828091faeec8Sdan   Tcl_Obj *CONST objv[]
828191faeec8Sdan ){
828291faeec8Sdan   sqlite3 *db = 0;
828391faeec8Sdan   Tcl_WideInt iOff = 0;
828491faeec8Sdan   const unsigned char *aData = 0;
828591faeec8Sdan   int nData = 0;
828691faeec8Sdan   sqlite3_file *pFile = 0;
828791faeec8Sdan   int rc;
828891faeec8Sdan 
828991faeec8Sdan   if( objc!=4 ){
829091faeec8Sdan     Tcl_WrongNumArgs(interp, 1, objv, "DB OFFSET DATA");
829191faeec8Sdan     return TCL_ERROR;
829291faeec8Sdan   }
829391faeec8Sdan   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
829491faeec8Sdan   if( Tcl_GetWideIntFromObj(interp, objv[2], &iOff) ) return TCL_ERROR;
829591faeec8Sdan   aData = Tcl_GetByteArrayFromObj(objv[3], &nData);
829691faeec8Sdan 
829791faeec8Sdan   sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void*)&pFile);
829891faeec8Sdan   rc = pFile->pMethods->xWrite(pFile, aData, nData, iOff);
829991faeec8Sdan 
830091faeec8Sdan   Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
830191faeec8Sdan   return TCL_OK;
830291faeec8Sdan }
830391faeec8Sdan 
830491faeec8Sdan /*
8305c30b78f6Sdan ** Usage:  sqlite3_register_cksumvfs
8306c30b78f6Sdan **
8307c30b78f6Sdan */
test_register_cksumvfs(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])8308c30b78f6Sdan static int SQLITE_TCLAPI test_register_cksumvfs(
8309c30b78f6Sdan   void * clientData,
8310c30b78f6Sdan   Tcl_Interp *interp,
8311c30b78f6Sdan   int objc,
8312c30b78f6Sdan   Tcl_Obj *CONST objv[]
8313c30b78f6Sdan ){
8314c30b78f6Sdan   if( objc!=1 ){
8315c30b78f6Sdan     Tcl_WrongNumArgs(interp, 1, objv, "");
8316c30b78f6Sdan     return TCL_ERROR;
8317c30b78f6Sdan   }else{
8318c30b78f6Sdan     extern int sqlite3_register_cksumvfs(const char*);
8319c30b78f6Sdan     int rc = sqlite3_register_cksumvfs(0);
8320c30b78f6Sdan     Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
8321c30b78f6Sdan   }
8322c30b78f6Sdan   return TCL_OK;
8323c30b78f6Sdan }
8324c30b78f6Sdan 
8325c30b78f6Sdan /*
8326c30b78f6Sdan ** Usage:  sqlite3_unregister_cksumvfs
8327c30b78f6Sdan **
8328c30b78f6Sdan */
test_unregister_cksumvfs(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])8329c30b78f6Sdan static int SQLITE_TCLAPI test_unregister_cksumvfs(
8330c30b78f6Sdan   void * clientData,
8331c30b78f6Sdan   Tcl_Interp *interp,
8332c30b78f6Sdan   int objc,
8333c30b78f6Sdan   Tcl_Obj *CONST objv[]
8334c30b78f6Sdan ){
8335c30b78f6Sdan   if( objc!=1 ){
8336c30b78f6Sdan     Tcl_WrongNumArgs(interp, 1, objv, "");
8337c30b78f6Sdan     return TCL_ERROR;
8338c30b78f6Sdan   }else{
8339c30b78f6Sdan     extern int sqlite3_unregister_cksumvfs(void);
8340c30b78f6Sdan     int rc = sqlite3_unregister_cksumvfs();
8341c30b78f6Sdan     Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
8342c30b78f6Sdan   }
8343c30b78f6Sdan   return TCL_OK;
8344c30b78f6Sdan }
8345c30b78f6Sdan 
8346c30b78f6Sdan /*
8347f7e74904Sdrh ** Usage:  decode_hexdb TEXT
8348f7e74904Sdrh **
8349f7e74904Sdrh ** Example:   db deserialize [decode_hexdb $output_of_dbtotxt]
8350f7e74904Sdrh **
8351f7e74904Sdrh ** This routine returns a byte-array for an SQLite database file that
8352f7e74904Sdrh ** is constructed from a text input which is the output of the "dbtotxt"
8353f7e74904Sdrh ** utility.
8354f7e74904Sdrh */
test_decode_hexdb(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])8355f7e74904Sdrh static int SQLITE_TCLAPI test_decode_hexdb(
8356f7e74904Sdrh   void * clientData,
8357f7e74904Sdrh   Tcl_Interp *interp,
8358f7e74904Sdrh   int objc,
8359f7e74904Sdrh   Tcl_Obj *CONST objv[]
8360f7e74904Sdrh ){
8361f7e74904Sdrh   const char *zIn = 0;
8362f7e74904Sdrh   unsigned char *a = 0;
8363f7e74904Sdrh   int n = 0;
8364f7e74904Sdrh   int lineno = 0;
8365f7e74904Sdrh   int i, iNext;
8366f7e74904Sdrh   int iOffset = 0;
8367f7e74904Sdrh   int j, k;
8368f7e74904Sdrh   int rc;
83693ea557e0Sdrh   unsigned int x[16];
8370f7e74904Sdrh   if( objc!=2 ){
8371f7e74904Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "HEXDB");
8372f7e74904Sdrh     return TCL_ERROR;
8373f7e74904Sdrh   }
8374f7e74904Sdrh   zIn = Tcl_GetString(objv[1]);
8375f7e74904Sdrh   for(i=0; zIn[i]; i=iNext){
8376f7e74904Sdrh     lineno++;
8377f7e74904Sdrh     for(iNext=i; zIn[iNext] && zIn[iNext]!='\n'; iNext++){}
8378f7e74904Sdrh     if( zIn[iNext]=='\n' ) iNext++;
8379f7e74904Sdrh     while( zIn[i]==' ' || zIn[i]=='\t' ){ i++; }
8380f7e74904Sdrh     if( a==0 ){
8381f7e74904Sdrh       int pgsz;
8382f7e74904Sdrh       rc = sscanf(zIn+i, "| size %d pagesize %d", &n, &pgsz);
8383f7e74904Sdrh       if( rc!=2 ) continue;
838409ea1256Sdrh       if( pgsz<512 || pgsz>65536 || (pgsz&(pgsz-1))!=0 ){
838509ea1256Sdrh         Tcl_AppendResult(interp, "bad 'pagesize' field", (void*)0);
838609ea1256Sdrh         return TCL_ERROR;
838709ea1256Sdrh       }
838809ea1256Sdrh       n = (n+pgsz-1)&~(pgsz-1);  /* Round n up to the next multiple of pgsz */
8389f7e74904Sdrh       if( n<512 ){
8390f7e74904Sdrh         Tcl_AppendResult(interp, "bad 'size' field", (void*)0);
8391f7e74904Sdrh         return TCL_ERROR;
8392f7e74904Sdrh       }
8393f7e74904Sdrh       a = malloc( n );
8394f7e74904Sdrh       if( a==0 ){
8395f7e74904Sdrh         Tcl_AppendResult(interp, "out of memory", (void*)0);
8396f7e74904Sdrh         return TCL_ERROR;
8397f7e74904Sdrh       }
8398f7e74904Sdrh       memset(a, 0, n);
8399f7e74904Sdrh       continue;
8400f7e74904Sdrh     }
8401f7e74904Sdrh     rc = sscanf(zIn+i, "| page %d offset %d", &j, &k);
8402f7e74904Sdrh     if( rc==2 ){
8403f7e74904Sdrh       iOffset = k;
8404f7e74904Sdrh       continue;
8405f7e74904Sdrh     }
84063ea557e0Sdrh     rc = sscanf(zIn+i,"| %d: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
8407f7e74904Sdrh                 &j, &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
8408f7e74904Sdrh                 &x[8], &x[9], &x[10], &x[11], &x[12], &x[13], &x[14], &x[15]);
8409f7e74904Sdrh     if( rc==17 ){
8410f7e74904Sdrh       k = iOffset+j;
8411f7e74904Sdrh       if( k+16<=n ){
84123ea557e0Sdrh         int ii;
84133ea557e0Sdrh         for(ii=0; ii<16; ii++) a[k+ii] = x[ii]&0xff;
8414f7e74904Sdrh       }
8415f7e74904Sdrh       continue;
8416f7e74904Sdrh     }
8417f7e74904Sdrh   }
8418f7e74904Sdrh   Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(a, n));
8419f7e74904Sdrh   free(a);
8420f7e74904Sdrh   return TCL_OK;
8421f7e74904Sdrh }
8422f7e74904Sdrh 
84231bbfc674Sdrh /*
84241bbfc674Sdrh ** Client data for the autovacuum_pages callback.
84251bbfc674Sdrh */
84261bbfc674Sdrh struct AutovacPageData {
84271bbfc674Sdrh   Tcl_Interp *interp;
84281bbfc674Sdrh   char *zScript;
84291bbfc674Sdrh };
84301bbfc674Sdrh typedef struct AutovacPageData AutovacPageData;
84311bbfc674Sdrh 
84321bbfc674Sdrh /*
84331bbfc674Sdrh ** Callback functions for sqlite3_autovacuum_pages
84341bbfc674Sdrh */
test_autovacuum_pages_callback(void * pClientData,const char * zSchema,unsigned int nFilePages,unsigned int nFreePages,unsigned int nBytePerPage)84351bbfc674Sdrh static unsigned int test_autovacuum_pages_callback(
84361bbfc674Sdrh   void *pClientData,
84371bbfc674Sdrh   const char *zSchema,
84381bbfc674Sdrh   unsigned int nFilePages,
84391bbfc674Sdrh   unsigned int nFreePages,
84401bbfc674Sdrh   unsigned int nBytePerPage
84411bbfc674Sdrh ){
84421bbfc674Sdrh   AutovacPageData *pData = (AutovacPageData*)pClientData;
84431bbfc674Sdrh   Tcl_DString str;
84441bbfc674Sdrh   unsigned int x;
84451bbfc674Sdrh   char zBuf[100];
84461bbfc674Sdrh   Tcl_DStringInit(&str);
84471bbfc674Sdrh   Tcl_DStringAppend(&str, pData->zScript, -1);
84481bbfc674Sdrh   Tcl_DStringAppendElement(&str, zSchema);
84491bbfc674Sdrh   sqlite3_snprintf(sizeof(zBuf), zBuf, "%u", nFilePages);
84501bbfc674Sdrh   Tcl_DStringAppendElement(&str, zBuf);
84511bbfc674Sdrh   sqlite3_snprintf(sizeof(zBuf), zBuf, "%u", nFreePages);
84521bbfc674Sdrh   Tcl_DStringAppendElement(&str, zBuf);
84531bbfc674Sdrh   sqlite3_snprintf(sizeof(zBuf), zBuf, "%u", nBytePerPage);
84541bbfc674Sdrh   Tcl_DStringAppendElement(&str, zBuf);
84551bbfc674Sdrh   Tcl_ResetResult(pData->interp);
84561bbfc674Sdrh   Tcl_Eval(pData->interp, Tcl_DStringValue(&str));
84571bbfc674Sdrh   Tcl_DStringFree(&str);
84581bbfc674Sdrh   x = nFreePages;
84591bbfc674Sdrh   (void)Tcl_GetIntFromObj(0, Tcl_GetObjResult(pData->interp), (int*)&x);
84601bbfc674Sdrh   return x;
84611bbfc674Sdrh }
84621bbfc674Sdrh 
84631bbfc674Sdrh /*
84641bbfc674Sdrh ** Usage:  sqlite3_autovacuum_pages DB SCRIPT
84651bbfc674Sdrh **
84661bbfc674Sdrh ** Add an autovacuum-pages callback to database connection DB.  The callback
84671bbfc674Sdrh ** will invoke SCRIPT, after appending parameters.
84681bbfc674Sdrh **
84691bbfc674Sdrh ** If SCRIPT is an empty string or is omitted, then the callback is
84701bbfc674Sdrh ** cancelled.
84711bbfc674Sdrh */
test_autovacuum_pages(void * clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])84721bbfc674Sdrh static int SQLITE_TCLAPI test_autovacuum_pages(
84731bbfc674Sdrh   void * clientData,
84741bbfc674Sdrh   Tcl_Interp *interp,
84751bbfc674Sdrh   int objc,
84761bbfc674Sdrh   Tcl_Obj *CONST objv[]
84771bbfc674Sdrh ){
84781bbfc674Sdrh   AutovacPageData *pData;
84791bbfc674Sdrh   sqlite3 *db;
84801bbfc674Sdrh   int rc;
84811bbfc674Sdrh   const char *zScript;
84821bbfc674Sdrh   if( objc!=2 && objc!=3 ){
84831bbfc674Sdrh     Tcl_WrongNumArgs(interp, 1, objv, "DB ?SCRIPT?");
84841bbfc674Sdrh     return TCL_ERROR;
84851bbfc674Sdrh   }
84861bbfc674Sdrh   if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
84871bbfc674Sdrh   zScript = objc==3 ? Tcl_GetString(objv[2]) : 0;
848821b1c6ddSdan   if( zScript ){
848921b1c6ddSdan     size_t nScript = strlen(zScript);
84901bbfc674Sdrh     pData = sqlite3_malloc64( sizeof(*pData) + nScript + 1 );
84911bbfc674Sdrh     if( pData==0 ){
84921bbfc674Sdrh       Tcl_AppendResult(interp, "out of memory", (void*)0);
84931bbfc674Sdrh       return TCL_ERROR;
84941bbfc674Sdrh     }
84951bbfc674Sdrh     pData->interp = interp;
84961bbfc674Sdrh     pData->zScript = (char*)&pData[1];
84971bbfc674Sdrh     memcpy(pData->zScript, zScript, nScript+1);
84981bbfc674Sdrh     rc = sqlite3_autovacuum_pages(db,test_autovacuum_pages_callback,
84991bbfc674Sdrh                                   pData, sqlite3_free);
85001bbfc674Sdrh   }else{
85011bbfc674Sdrh     rc = sqlite3_autovacuum_pages(db, 0, 0, 0);
85021bbfc674Sdrh   }
85031bbfc674Sdrh   if( rc ){
85041bbfc674Sdrh     char zBuf[1000];
85051bbfc674Sdrh     sqlite3_snprintf(sizeof(zBuf), zBuf,
85061bbfc674Sdrh        "sqlite3_autovacuum_pages() returns %d", rc);
85071bbfc674Sdrh     Tcl_AppendResult(interp, zBuf, (void*)0);
85081bbfc674Sdrh     return TCL_ERROR;
85091bbfc674Sdrh   }
85101bbfc674Sdrh   return TCL_OK;
85111bbfc674Sdrh }
85121bbfc674Sdrh 
8513f7e74904Sdrh 
8514f7e74904Sdrh /*
8515d1bf3512Sdrh ** Register commands with the TCL interpreter.
8516d1bf3512Sdrh */
Sqlitetest1_Init(Tcl_Interp * interp)8517d1bf3512Sdrh int Sqlitetest1_Init(Tcl_Interp *interp){
85186f8a503dSdanielk1977   extern int sqlite3_search_count;
85190ff297eaSdan   extern int sqlite3_found_count;
85206f8a503dSdanielk1977   extern int sqlite3_interrupt_count;
85216f8a503dSdanielk1977   extern int sqlite3_open_file_count;
85226bf89570Sdrh   extern int sqlite3_sort_count;
85236f8a503dSdanielk1977   extern int sqlite3_current_time;
852484a2bf67Sdrh #if SQLITE_OS_UNIX && defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
8525aebf413dSaswift   extern int sqlite3_hostid_num;
8526aabbed22Spweilbacher #endif
8527ae7e151aSdrh   extern int sqlite3_max_blobsize;
85287617e4a8Smistachkin   extern int SQLITE_TCLAPI sqlite3BtreeSharedCacheReport(void*,
852916a9b836Sdrh                                           Tcl_Interp*,int,Tcl_Obj*CONST*);
8530edb31cd1Sdrh   static int iZero = 0;
8531c2eef3b3Sdrh   static struct {
8532c2eef3b3Sdrh      char *zName;
8533c2eef3b3Sdrh      Tcl_CmdProc *xProc;
8534c2eef3b3Sdrh   } aCmd[] = {
853527641703Sdrh      { "db_enter",                      (Tcl_CmdProc*)db_enter               },
853627641703Sdrh      { "db_leave",                      (Tcl_CmdProc*)db_leave               },
85376f8a503dSdanielk1977      { "sqlite3_mprintf_int",           (Tcl_CmdProc*)sqlite3_mprintf_int    },
8538e9707671Sdrh      { "sqlite3_mprintf_int64",         (Tcl_CmdProc*)sqlite3_mprintf_int64  },
8539c5cad1e3Sdrh      { "sqlite3_mprintf_long",          (Tcl_CmdProc*)sqlite3_mprintf_long   },
85406f8a503dSdanielk1977      { "sqlite3_mprintf_str",           (Tcl_CmdProc*)sqlite3_mprintf_str    },
8541b3738b6cSdrh      { "sqlite3_snprintf_str",          (Tcl_CmdProc*)sqlite3_snprintf_str   },
8542e29b1a05Sdrh      { "sqlite3_mprintf_stronly",       (Tcl_CmdProc*)sqlite3_mprintf_stronly},
85436f8a503dSdanielk1977      { "sqlite3_mprintf_double",        (Tcl_CmdProc*)sqlite3_mprintf_double },
85446f8a503dSdanielk1977      { "sqlite3_mprintf_scaled",        (Tcl_CmdProc*)sqlite3_mprintf_scaled },
854563782855Sdrh      { "sqlite3_mprintf_hexdouble",   (Tcl_CmdProc*)sqlite3_mprintf_hexdouble},
85466f8a503dSdanielk1977      { "sqlite3_mprintf_z_test",        (Tcl_CmdProc*)test_mprintf_z        },
854705a82983Sdrh      { "sqlite3_mprintf_n_test",        (Tcl_CmdProc*)test_mprintf_n        },
854868853907Sdrh      { "sqlite3_snprintf_int",          (Tcl_CmdProc*)test_snprintf_int     },
85496f8a503dSdanielk1977      { "sqlite3_last_insert_rowid",     (Tcl_CmdProc*)test_last_rowid       },
85506f8a503dSdanielk1977      { "sqlite3_exec_printf",           (Tcl_CmdProc*)test_exec_printf      },
85515bd98aefSdrh      { "sqlite3_exec_hex",              (Tcl_CmdProc*)test_exec_hex         },
8552b62c335eSdrh      { "sqlite3_exec",                  (Tcl_CmdProc*)test_exec             },
8553b62c335eSdrh      { "sqlite3_exec_nr",               (Tcl_CmdProc*)test_exec_nr          },
85548225f5acSshane #ifndef SQLITE_OMIT_GET_TABLE
85556f8a503dSdanielk1977      { "sqlite3_get_table_printf",      (Tcl_CmdProc*)test_get_table_printf },
85568225f5acSshane #endif
85576f8a503dSdanielk1977      { "sqlite3_close",                 (Tcl_CmdProc*)sqlite_test_close     },
8558617dc860Sdan      { "sqlite3_close_v2",              (Tcl_CmdProc*)sqlite_test_close_v2  },
85596f8a503dSdanielk1977      { "sqlite3_create_function",       (Tcl_CmdProc*)test_create_function  },
85606f8a503dSdanielk1977      { "sqlite3_create_aggregate",      (Tcl_CmdProc*)test_create_aggregate },
85618c754a36Sdrh      { "sqlite3_drop_modules",          (Tcl_CmdProc*)test_drop_modules     },
8562c2eef3b3Sdrh      { "sqlite_register_test_function", (Tcl_CmdProc*)test_register_func    },
8563c2eef3b3Sdrh      { "sqlite_abort",                  (Tcl_CmdProc*)sqlite_abort          },
856496fc5fe6Sdanielk1977      { "sqlite_bind",                   (Tcl_CmdProc*)test_bind             },
856599ee3600Sdrh      { "breakpoint",                    (Tcl_CmdProc*)test_breakpoint       },
856625d6543dSdrh      { "sqlite3_key",                   (Tcl_CmdProc*)test_key              },
856725d6543dSdrh      { "sqlite3_rekey",                 (Tcl_CmdProc*)test_rekey            },
8568c5cdca61Sdrh      { "sqlite3_interrupt",             (Tcl_CmdProc*)test_interrupt        },
85699636c4e1Sdanielk1977      { "sqlite_delete_function",        (Tcl_CmdProc*)delete_function       },
85703e1d8e63Sdrh      { "sqlite_delete_collation",       (Tcl_CmdProc*)delete_collation      },
85713e1d8e63Sdrh      { "sqlite3_get_autocommit",        (Tcl_CmdProc*)get_autocommit        },
85723086765bSdrh      { "sqlite3_busy_timeout",          (Tcl_CmdProc*)test_busy_timeout     },
85733c23a885Sdrh      { "printf",                        (Tcl_CmdProc*)test_printf           },
85743a00f907Smlcreech      { "sqlite3IoTrace",              (Tcl_CmdProc*)test_io_trace         },
8575afcf9bd8Sdan      { "clang_sanitize_address",        (Tcl_CmdProc*)clang_sanitize_address },
8576c2eef3b3Sdrh   };
857751e3d8e2Sdanielk1977   static struct {
857851e3d8e2Sdanielk1977      char *zName;
857951e3d8e2Sdanielk1977      Tcl_ObjCmdProc *xProc;
858004f2e68dSdanielk1977      void *clientData;
858151e3d8e2Sdanielk1977   } aObjCmd[] = {
8582d42908fbSdrh      { "sqlite3_db_config",             test_sqlite3_db_config, 0 },
858399744fa4Sdrh      { "sqlite3_txn_state",             test_sqlite3_txn_state, 0 },
8584edb31cd1Sdrh      { "bad_behavior",                  test_bad_behavior,  (void*)&iZero },
85853e0327d5Sdrh      { "register_dbstat_vtab",          test_register_dbstat_vtab  },
8586dddca286Sdrh      { "sqlite3_connection_pointer",    get_sqlite_pointer, 0 },
85872e3f87aeSdrh      { "intarray_addr",                 test_intarray_addr, 0 },
85882e3f87aeSdrh      { "int64array_addr",               test_int64array_addr, 0 },
85892e3f87aeSdrh      { "doublearray_addr",              test_doublearray_addr, 0 },
85902e3f87aeSdrh      { "textarray_addr",                test_textarray_addr, 0 },
8591241db313Sdrh      { "sqlite3_bind_int",              test_bind_int,      0 },
8592b026e05eSdrh      { "sqlite3_bind_zeroblob",         test_bind_zeroblob, 0 },
859380c03022Sdan      { "sqlite3_bind_zeroblob64",       test_bind_zeroblob64, 0 },
859404f2e68dSdanielk1977      { "sqlite3_bind_int64",            test_bind_int64,    0 },
859504f2e68dSdanielk1977      { "sqlite3_bind_double",           test_bind_double,   0 },
859604f2e68dSdanielk1977      { "sqlite3_bind_null",             test_bind_null     ,0 },
859704f2e68dSdanielk1977      { "sqlite3_bind_text",             test_bind_text     ,0 },
859804f2e68dSdanielk1977      { "sqlite3_bind_text16",           test_bind_text16   ,0 },
859904f2e68dSdanielk1977      { "sqlite3_bind_blob",             test_bind_blob     ,0 },
8600252fe67bSdan      { "sqlite3_bind_value_from_select",test_bind_value_from_select ,0 },
8601252fe67bSdan      { "sqlite3_bind_value_from_preupdate",test_bind_value_from_preupdate ,0 },
86025011bb8dSdan #ifndef SQLITE_OMIT_VIRTUALTABLE
8603ea847f1bSdrh      { "sqlite3_carray_bind",           test_carray_bind   ,0 },
86045011bb8dSdan #endif
860575f6a032Sdrh      { "sqlite3_bind_parameter_count",  test_bind_parameter_count, 0},
8606895d7472Sdrh      { "sqlite3_bind_parameter_name",   test_bind_parameter_name,  0},
8607fa6bc000Sdrh      { "sqlite3_bind_parameter_index",  test_bind_parameter_index, 0},
8608600dd0baSdanielk1977      { "sqlite3_clear_bindings",        test_clear_bindings, 0},
8609f9cb7f58Sdrh      { "sqlite3_sleep",                 test_sleep,          0},
861004f2e68dSdanielk1977      { "sqlite3_errcode",               test_errcode       ,0 },
861199dfe5ebSdrh      { "sqlite3_extended_errcode",      test_ex_errcode    ,0 },
861204f2e68dSdanielk1977      { "sqlite3_errmsg",                test_errmsg        ,0 },
8613f62641e9Sdrh      { "sqlite3_error_offset",          test_error_offset  ,0 },
861404f2e68dSdanielk1977      { "sqlite3_errmsg16",              test_errmsg16      ,0 },
861504f2e68dSdanielk1977      { "sqlite3_open",                  test_open          ,0 },
861604f2e68dSdanielk1977      { "sqlite3_open16",                test_open16        ,0 },
8617286ab7c2Sdan      { "sqlite3_open_v2",               test_open_v2       ,0 },
8618bc6ada41Sdanielk1977      { "sqlite3_complete16",            test_complete16    ,0 },
861991694dbdSdrh      { "sqlite3_normalize",             test_normalize     ,0 },
862004f2e68dSdanielk1977 
862104f2e68dSdanielk1977      { "sqlite3_prepare",               test_prepare       ,0 },
862204f2e68dSdanielk1977      { "sqlite3_prepare16",             test_prepare16     ,0 },
8623b900aaf3Sdrh      { "sqlite3_prepare_v2",            test_prepare_v2    ,0 },
86248bee11a4Smistachkin      { "sqlite3_prepare_v3",            test_prepare_v3    ,0 },
86254837f531Sdrh      { "sqlite3_prepare_tkt3134",       test_prepare_tkt3134, 0},
8626b900aaf3Sdrh      { "sqlite3_prepare16_v2",          test_prepare16_v2  ,0 },
862704f2e68dSdanielk1977      { "sqlite3_finalize",              test_finalize      ,0 },
8628d1d38488Sdrh      { "sqlite3_stmt_status",           test_stmt_status   ,0 },
862904f2e68dSdanielk1977      { "sqlite3_reset",                 test_reset         ,0 },
8630d89bd007Sdrh      { "sqlite3_expired",               test_expired       ,0 },
8631f8db1bc0Sdrh      { "sqlite3_transfer_bindings",     test_transfer_bind ,0 },
8632fbcd585fSdanielk1977      { "sqlite3_changes",               test_changes       ,0 },
863304f2e68dSdanielk1977      { "sqlite3_step",                  test_step          ,0 },
8634404ca075Sdanielk1977      { "sqlite3_sql",                   test_sql           ,0 },
8635fca760c8Sdrh      { "sqlite3_expanded_sql",          test_ex_sql        ,0 },
86368bee11a4Smistachkin #ifdef SQLITE_ENABLE_NORMALIZE
86378bee11a4Smistachkin      { "sqlite3_normalized_sql",        test_norm_sql      ,0 },
86388bee11a4Smistachkin #endif
8639bb5a9c3eSdrh      { "sqlite3_next_stmt",             test_next_stmt     ,0 },
8640f03d9cccSdrh      { "sqlite3_stmt_readonly",         test_stmt_readonly ,0 },
864139c5c4aeSdrh      { "sqlite3_stmt_isexplain",        test_stmt_isexplain,0 },
86422fb6693eSdrh      { "sqlite3_stmt_busy",             test_stmt_busy     ,0 },
8643d9495cd0Sdan      { "uses_stmt_journal",             uses_stmt_journal ,0 },
864404f2e68dSdanielk1977 
86456aafc29bSdrh      { "sqlite3_release_memory",        test_release_memory,     0},
864609419b4bSdrh      { "sqlite3_db_release_memory",     test_db_release_memory,  0},
86476fa255fdSdan      { "sqlite3_db_cacheflush",         test_db_cacheflush,      0},
86480e80e509Sdrh      { "sqlite3_system_errno",          test_system_errno,       0},
8649283829cbSdrh      { "sqlite3_db_filename",           test_db_filename,        0},
8650421377e6Sdrh      { "sqlite3_db_readonly",           test_db_readonly,        0},
86516aafc29bSdrh      { "sqlite3_soft_heap_limit",       test_soft_heap_limit,    0},
865210c0e711Sdrh      { "sqlite3_soft_heap_limit64",     test_soft_heap_limit,    0},
865310c0e711Sdrh      { "sqlite3_hard_heap_limit64",     test_hard_heap_limit,    0},
8654b4bc7057Sdrh      { "sqlite3_thread_cleanup",        test_thread_cleanup,     0},
8655c6ba55f4Sdrh      { "sqlite3_pager_refcounts",       test_pager_refcounts,    0},
86566aafc29bSdrh 
8657c2e87a3eSdrh      { "sqlite3_load_extension",        test_load_extension,     0},
8658c2e87a3eSdrh      { "sqlite3_enable_load_extension", test_enable_load,        0},
86594ac285a1Sdrh      { "sqlite3_extended_result_codes", test_extended_result_codes, 0},
8660b1a6c3c1Sdrh      { "sqlite3_limit",                 test_limit,                 0},
8661da84dcaeSdrh      { "dbconfig_maindbname_icecube",   test_dbconfig_maindbname_icecube },
8662c2e87a3eSdrh 
866393aed5a1Sdrh      { "save_prng_state",               save_prng_state,    0 },
866493aed5a1Sdrh      { "restore_prng_state",            restore_prng_state, 0 },
866593aed5a1Sdrh      { "reset_prng_state",              reset_prng_state,   0 },
8666ade54d68Sdrh      { "prng_seed",                     prng_seed,          0 },
8667ca439a49Sdrh      { "extra_schema_checks",           extra_schema_checks,    0},
866809fe6143Sdrh      { "database_never_corrupt",        database_never_corrupt, 0},
866909fe6143Sdrh      { "database_may_be_corrupt",       database_may_be_corrupt, 0},
8670f58ee7f1Sdrh      { "optimization_control",          optimization_control,0},
867180084ca8Sdrh #if SQLITE_OS_WIN
867280084ca8Sdrh      { "lock_win32_file",               win32_file_lock,    0 },
86733741827eSmistachkin      { "exists_win32_path",             win32_exists_path,  0 },
86743741827eSmistachkin      { "find_win32_file",               win32_find_file,    0 },
86753741827eSmistachkin      { "delete_win32_file",             win32_delete_file,  0 },
86763741827eSmistachkin      { "make_win32_dir",                win32_mkdir,        0 },
86773741827eSmistachkin      { "remove_win32_dir",              win32_rmdir,        0 },
867880084ca8Sdrh #endif
8679a2c8a95bSdrh      { "tcl_objproc",                   runAsObjProc,       0 },
868093aed5a1Sdrh 
868104f2e68dSdanielk1977      /* sqlite3_column_*() API */
868204f2e68dSdanielk1977      { "sqlite3_column_count",          test_column_count  ,0 },
868304f2e68dSdanielk1977      { "sqlite3_data_count",            test_data_count    ,0 },
868404f2e68dSdanielk1977      { "sqlite3_column_type",           test_column_type   ,0 },
8685ea61b2c4Sdanielk1977      { "sqlite3_column_blob",           test_column_blob   ,0 },
868604f2e68dSdanielk1977      { "sqlite3_column_double",         test_column_double ,0 },
868704f2e68dSdanielk1977      { "sqlite3_column_int64",          test_column_int64  ,0 },
868844a376f6Sdanielk1977      { "sqlite3_column_text",   test_stmt_utf8,  (void*)sqlite3_column_text },
868944a376f6Sdanielk1977      { "sqlite3_column_name",   test_stmt_utf8,  (void*)sqlite3_column_name },
869044a376f6Sdanielk1977      { "sqlite3_column_int",    test_stmt_int,   (void*)sqlite3_column_int  },
869144a376f6Sdanielk1977      { "sqlite3_column_bytes",  test_stmt_int,   (void*)sqlite3_column_bytes},
86923f913576Sdrh #ifndef SQLITE_OMIT_DECLTYPE
869344a376f6Sdanielk1977      { "sqlite3_column_decltype",test_stmt_utf8,(void*)sqlite3_column_decltype},
86943f913576Sdrh #endif
86954b1ae99dSdanielk1977 #ifdef SQLITE_ENABLE_COLUMN_METADATA
869644a376f6Sdanielk1977 { "sqlite3_column_database_name",test_stmt_utf8,(void*)sqlite3_column_database_name},
869744a376f6Sdanielk1977 { "sqlite3_column_table_name",test_stmt_utf8,(void*)sqlite3_column_table_name},
869844a376f6Sdanielk1977 { "sqlite3_column_origin_name",test_stmt_utf8,(void*)sqlite3_column_origin_name},
86994b1ae99dSdanielk1977 #endif
8700955de52cSdanielk1977 
87016c62608fSdrh #ifndef SQLITE_OMIT_UTF16
870244a376f6Sdanielk1977      { "sqlite3_column_bytes16", test_stmt_int, (void*)sqlite3_column_bytes16 },
870344a376f6Sdanielk1977      { "sqlite3_column_text16",  test_stmt_utf16, (void*)sqlite3_column_text16},
870444a376f6Sdanielk1977      { "sqlite3_column_name16",  test_stmt_utf16, (void*)sqlite3_column_name16},
87057d9bd4e1Sdrh      { "add_alignment_test_collations", add_alignment_test_collations, 0      },
87063f913576Sdrh #ifndef SQLITE_OMIT_DECLTYPE
870744a376f6Sdanielk1977      { "sqlite3_column_decltype16",test_stmt_utf16,(void*)sqlite3_column_decltype16},
87083f913576Sdrh #endif
87094b1ae99dSdanielk1977 #ifdef SQLITE_ENABLE_COLUMN_METADATA
8710955de52cSdanielk1977 {"sqlite3_column_database_name16",
87117da5fcb0Sdrh   test_stmt_utf16, (void*)sqlite3_column_database_name16},
871244a376f6Sdanielk1977 {"sqlite3_column_table_name16", test_stmt_utf16, (void*)sqlite3_column_table_name16},
871344a376f6Sdanielk1977 {"sqlite3_column_origin_name16", test_stmt_utf16, (void*)sqlite3_column_origin_name16},
87146c62608fSdrh #endif
87154b1ae99dSdanielk1977 #endif
8716a393c036Sdanielk1977      { "sqlite3_create_collation_v2", test_create_collation_v2, 0 },
87176b456a2bSdanielk1977      { "sqlite3_global_recover",     test_global_recover, 0   },
871880788d8bSdrh      { "working_64bit_int",          working_64bit_int,   0   },
87199bc5449fSdrh      { "vfs_unlink_test",            vfs_unlink_test,     0   },
8720c8d75674Sdrh      { "vfs_initfail_test",          vfs_initfail_test,   0   },
8721a2820970Sdrh      { "vfs_unregister_all",         vfs_unregister_all,  0   },
8722a2820970Sdrh      { "vfs_reregister_all",         vfs_reregister_all,  0   },
872355176259Sdrh      { "file_control_test",          file_control_test,   0   },
8724aebf413dSaswift      { "file_control_lasterrno_test", file_control_lasterrno_test,  0   },
8725aebf413dSaswift      { "file_control_lockproxy_test", file_control_lockproxy_test,  0   },
87266e09d69cSdan      { "file_control_chunksize_test", file_control_chunksize_test,  0   },
8727661d71afSdan      { "file_control_sizehint_test",  file_control_sizehint_test,   0   },
8728ea99a31cSdrh      { "file_control_data_version",   file_control_data_version,    0   },
87296b98d67bSmistachkin #if SQLITE_OS_WIN
8730d0cdf012Sdrh      { "file_control_win32_av_retry", file_control_win32_av_retry,  0   },
87311b361ff3Smistachkin      { "file_control_win32_get_handle", file_control_win32_get_handle, 0  },
87326b98d67bSmistachkin      { "file_control_win32_set_handle", file_control_win32_set_handle, 0  },
87336b98d67bSmistachkin #endif
8734253cea5cSdrh      { "file_control_persist_wal",    file_control_persist_wal,     0   },
8735cb15f35fSdrh      { "file_control_powersafe_overwrite",file_control_powersafe_overwrite,0},
8736de60fc2dSdrh      { "file_control_vfsname",        file_control_vfsname,         0   },
8737c30b78f6Sdan      { "file_control_reservebytes",   file_control_reservebytes,    0   },
8738696b33e6Sdrh      { "file_control_tempfilename",   file_control_tempfilename,    0   },
8739aecc04d6Sdan      { "file_control_external_reader",   file_control_external_reader,    0   },
8740e339d65aSdanielk1977      { "sqlite3_vfs_list",           vfs_list,     0   },
8741d2199f0fSdan      { "sqlite3_create_function_v2", test_create_function_v2, 0 },
874204f2e68dSdanielk1977 
87439a1d0abeSdanielk1977      /* Functions from os.h */
87445436dc2dSdrh #ifndef SQLITE_OMIT_UTF16
87454e6af134Sdanielk1977      { "add_test_collate",        test_collate, 0            },
8746312d6b36Sdanielk1977      { "add_test_collate_needed", test_collate_needed, 0     },
8747c8e9a2dfSdanielk1977      { "add_test_function",       test_function, 0           },
874838fdead8Sdan      { "add_test_utf16bin_collate",    test_utf16bin_collate, 0        },
87495436dc2dSdrh #endif
8750312d6b36Sdanielk1977      { "sqlite3_test_errstr",     test_errstr, 0             },
875192febd92Sdrh      { "tcl_variable_type",       tcl_variable_type, 0       },
8752aef0bf64Sdanielk1977 #ifndef SQLITE_OMIT_SHARED_CACHE
87536f7adc8aSdrh      { "sqlite3_enable_shared_cache", test_enable_shared, 0  },
875416a9b836Sdrh      { "sqlite3_shared_cache_report", sqlite3BtreeSharedCacheReport, 0},
8755aef0bf64Sdanielk1977 #endif
8756161fb796Sdanielk1977      { "sqlite3_libversion_number", test_libversion_number, 0  },
8757deb802cdSdanielk1977      { "sqlite3_table_column_metadata", test_table_column_metadata, 0  },
8758dcbb5d3fSdanielk1977 #ifndef SQLITE_OMIT_INCRBLOB
87594e76cc36Sdan      { "sqlite3_blob_reopen", test_blob_reopen, 0  },
8760dcbb5d3fSdanielk1977 #endif
8761062d4cb0Sdanielk1977      { "pcache_stats",       test_pcache_stats, 0  },
8762404ca075Sdanielk1977 #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
8763404ca075Sdanielk1977      { "sqlite3_unlock_notify", test_unlock_notify, 0  },
8764404ca075Sdanielk1977 #endif
876587c1fe1bSdan      { "sqlite3_wal_checkpoint",   test_wal_checkpoint, 0  },
87669c5e3680Sdan      { "sqlite3_wal_checkpoint_v2",test_wal_checkpoint_v2, 0  },
87679af10620Sdan      { "sqlite3_wal_autocheckpoint",test_wal_autocheckpoint, 0  },
8768eb8763d7Sdan      { "test_sqlite3_log",         test_sqlite3_log, 0  },
8769bb201344Sshaneh #ifndef SQLITE_OMIT_EXPLAIN
877091da6b83Sdan      { "print_explain_query_plan", test_print_eqp, 0  },
8771bb201344Sshaneh #endif
8772c17d696cSdan      { "sqlite3_test_control", test_test_control },
8773daf9a5a4Smistachkin #if SQLITE_OS_UNIX
8774a72014faSdan      { "getrusage", test_getrusage },
8775daf9a5a4Smistachkin #endif
8776248f2be9Sdrh      { "load_static_extension", tclLoadStaticExtensionCmd },
87770d51def2Sdan      { "sorter_test_fakeheap", sorter_test_fakeheap },
8778dfea4533Sdan      { "sorter_test_sort4_helper", sorter_test_sort4_helper },
8779d39c40ffSdrh #ifdef SQLITE_USER_AUTHENTICATION
8780d39c40ffSdrh      { "sqlite3_user_authenticate", test_user_authenticate, 0 },
8781d39c40ffSdrh      { "sqlite3_user_add",          test_user_add,          0 },
8782d39c40ffSdrh      { "sqlite3_user_change",       test_user_change,       0 },
8783d39c40ffSdrh      { "sqlite3_user_delete",       test_user_delete,       0 },
8784d39c40ffSdrh #endif
878504489b6dSdan #ifdef SQLITE_ENABLE_STMT_SCANSTATUS
878604489b6dSdan      { "sqlite3_stmt_scanstatus",       test_stmt_scanstatus,   0 },
878704489b6dSdan      { "sqlite3_stmt_scanstatus_reset", test_stmt_scanstatus_reset,   0 },
878804489b6dSdan #endif
8789d83f7ca1Sdan #ifdef SQLITE_ENABLE_SQLLOG
8790d83f7ca1Sdan      { "sqlite3_config_sqllog",         test_config_sqllog,   0 },
8791d83f7ca1Sdan #endif
8792e4e416e8Sdan      { "vfs_current_time_int64",           vfsCurrentTimeInt64,   0 },
8793fc1acf33Sdan #ifdef SQLITE_ENABLE_SNAPSHOT
8794fc1acf33Sdan      { "sqlite3_snapshot_get", test_snapshot_get, 0 },
8795fc1acf33Sdan      { "sqlite3_snapshot_open", test_snapshot_open, 0 },
8796fc1acf33Sdan      { "sqlite3_snapshot_free", test_snapshot_free, 0 },
8797ad2d5bafSdan      { "sqlite3_snapshot_cmp", test_snapshot_cmp, 0 },
87981158498dSdan      { "sqlite3_snapshot_recover", test_snapshot_recover, 0 },
879925accbcaSdan      { "sqlite3_snapshot_get_blob", test_snapshot_get_blob, 0 },
880025accbcaSdan      { "sqlite3_snapshot_open_blob", test_snapshot_open_blob, 0 },
880125accbcaSdan      { "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 },
8802fc1acf33Sdan #endif
8803000f95b1Sdan      { "sqlite3_delete_database", test_delete_database,    0 },
88044da30f88Sdan      { "atomic_batch_write",      test_atomic_batch_write, 0 },
8805460f1fa5Sdan      { "sqlite3_mmap_warm",       test_mmap_warm,          0 },
88062e3a5a81Sdan      { "sqlite3_config_sorterref", test_config_sorterref,   0 },
88071bbfc674Sdrh      { "sqlite3_autovacuum_pages", test_autovacuum_pages,   0 },
8808f7e74904Sdrh      { "decode_hexdb",             test_decode_hexdb,       0 },
880991faeec8Sdan      { "test_write_db",            test_write_db,           0 },
8810c30b78f6Sdan      { "sqlite3_register_cksumvfs", test_register_cksumvfs,  0 },
8811c30b78f6Sdan      { "sqlite3_unregister_cksumvfs", test_unregister_cksumvfs,  0 },
881251e3d8e2Sdanielk1977   };
88131398ad36Sdrh   static int bitmask_size = sizeof(Bitmask)*8;
88142ab410aaSdrh   static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
8815c2eef3b3Sdrh   int i;
8816b851b2c9Sdrh   extern int sqlite3_sync_count, sqlite3_fullsync_count;
8817af6df11fSdrh   extern int sqlite3_opentemp_count;
881855ef4d97Sdrh   extern int sqlite3_like_count;
8819dd73521bSdrh   extern int sqlite3_xferopt_count;
8820538f570cSdrh   extern int sqlite3_pager_readdb_count;
8821538f570cSdrh   extern int sqlite3_pager_writedb_count;
8822538f570cSdrh   extern int sqlite3_pager_writej_count;
882329bafeabSdanielk1977 #if SQLITE_OS_WIN
8824202cb641Smistachkin   extern LONG volatile sqlite3_os_type;
8825c0929987Sdrh #endif
88268b3d990bSdrh #ifdef SQLITE_DEBUG
88277b0ab210Sdrh   extern u32 sqlite3WhereTrace;
88283a00f907Smlcreech   extern int sqlite3OSTrace;
8829c74c3334Sdrh   extern int sqlite3WalTrace;
8830549c8b68Sdrh #endif
8831549c8b68Sdrh #ifdef SQLITE_TEST
883233e89035Sdanielk1977 #ifdef SQLITE_ENABLE_FTS3
883333e89035Sdanielk1977   extern int sqlite3_fts3_enable_parentheses;
883433e89035Sdanielk1977 #endif
883548083ceeSdrh #endif
8836c2eef3b3Sdrh 
8837c2eef3b3Sdrh   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
8838c2eef3b3Sdrh     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
8839c2eef3b3Sdrh   }
884051e3d8e2Sdanielk1977   for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
8841c572ef7fSdanielk1977     Tcl_CreateObjCommand(interp, aObjCmd[i].zName,
8842c572ef7fSdanielk1977         aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
884351e3d8e2Sdanielk1977   }
88446490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_search_count",
88456f8a503dSdanielk1977       (char*)&sqlite3_search_count, TCL_LINK_INT);
88460ff297eaSdan   Tcl_LinkVar(interp, "sqlite_found_count",
88470ff297eaSdan       (char*)&sqlite3_found_count, TCL_LINK_INT);
88486bf89570Sdrh   Tcl_LinkVar(interp, "sqlite_sort_count",
88496bf89570Sdrh       (char*)&sqlite3_sort_count, TCL_LINK_INT);
8850ae7e151aSdrh   Tcl_LinkVar(interp, "sqlite3_max_blobsize",
8851ae7e151aSdrh       (char*)&sqlite3_max_blobsize, TCL_LINK_INT);
885255ef4d97Sdrh   Tcl_LinkVar(interp, "sqlite_like_count",
885355ef4d97Sdrh       (char*)&sqlite3_like_count, TCL_LINK_INT);
88546490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_interrupt_count",
88556f8a503dSdanielk1977       (char*)&sqlite3_interrupt_count, TCL_LINK_INT);
88566490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_open_file_count",
88576f8a503dSdanielk1977       (char*)&sqlite3_open_file_count, TCL_LINK_INT);
88586490bebdSdanielk1977   Tcl_LinkVar(interp, "sqlite_current_time",
88596f8a503dSdanielk1977       (char*)&sqlite3_current_time, TCL_LINK_INT);
886084a2bf67Sdrh #if SQLITE_OS_UNIX && defined(__APPLE__) && SQLITE_ENABLE_LOCKING_STYLE
8861aebf413dSaswift   Tcl_LinkVar(interp, "sqlite_hostid_num",
8862aebf413dSaswift       (char*)&sqlite3_hostid_num, TCL_LINK_INT);
8863aabbed22Spweilbacher #endif
8864dd73521bSdrh   Tcl_LinkVar(interp, "sqlite3_xferopt_count",
8865dd73521bSdrh       (char*)&sqlite3_xferopt_count, TCL_LINK_INT);
8866538f570cSdrh   Tcl_LinkVar(interp, "sqlite3_pager_readdb_count",
8867538f570cSdrh       (char*)&sqlite3_pager_readdb_count, TCL_LINK_INT);
8868538f570cSdrh   Tcl_LinkVar(interp, "sqlite3_pager_writedb_count",
8869538f570cSdrh       (char*)&sqlite3_pager_writedb_count, TCL_LINK_INT);
8870538f570cSdrh   Tcl_LinkVar(interp, "sqlite3_pager_writej_count",
8871538f570cSdrh       (char*)&sqlite3_pager_writej_count, TCL_LINK_INT);
88724b2688abSdanielk1977 #ifndef SQLITE_OMIT_UTF16
88737d9bd4e1Sdrh   Tcl_LinkVar(interp, "unaligned_string_counter",
88747d9bd4e1Sdrh       (char*)&unaligned_string_counter, TCL_LINK_INT);
88754b2688abSdanielk1977 #endif
8876268803a9Sdrh #ifndef SQLITE_OMIT_UTF16
8877268803a9Sdrh   Tcl_LinkVar(interp, "sqlite_last_needed_collation",
8878268803a9Sdrh       (char*)&pzNeededCollation, TCL_LINK_STRING|TCL_LINK_READ_ONLY);
8879268803a9Sdrh #endif
888029bafeabSdanielk1977 #if SQLITE_OS_WIN
8881c0929987Sdrh   Tcl_LinkVar(interp, "sqlite_os_type",
8882202cb641Smistachkin       (char*)&sqlite3_os_type, TCL_LINK_LONG);
8883c0929987Sdrh #endif
8884549c8b68Sdrh #ifdef SQLITE_TEST
88856fa978daSdrh   {
88866fa978daSdrh     static const char *query_plan = "*** OBSOLETE VARIABLE ***";
8887549c8b68Sdrh     Tcl_LinkVar(interp, "sqlite_query_plan",
8888549c8b68Sdrh        (char*)&query_plan, TCL_LINK_STRING|TCL_LINK_READ_ONLY);
88896fa978daSdrh   }
8890549c8b68Sdrh #endif
88918b3d990bSdrh #ifdef SQLITE_DEBUG
889248083ceeSdrh   Tcl_LinkVar(interp, "sqlite_where_trace",
88933a00f907Smlcreech       (char*)&sqlite3WhereTrace, TCL_LINK_INT);
889473be5013Sdrh   Tcl_LinkVar(interp, "sqlite_os_trace",
88953a00f907Smlcreech       (char*)&sqlite3OSTrace, TCL_LINK_INT);
889638e1a279Sdan #ifndef SQLITE_OMIT_WAL
8897c74c3334Sdrh   Tcl_LinkVar(interp, "sqlite_wal_trace",
8898c74c3334Sdrh       (char*)&sqlite3WalTrace, TCL_LINK_INT);
88998b3d990bSdrh #endif
890038e1a279Sdan #endif
8901cbe21be3Sdanielk1977 #ifndef SQLITE_OMIT_DISKIO
8902af6df11fSdrh   Tcl_LinkVar(interp, "sqlite_opentemp_count",
8903af6df11fSdrh       (char*)&sqlite3_opentemp_count, TCL_LINK_INT);
8904cbe21be3Sdanielk1977 #endif
89057c972decSdrh   Tcl_LinkVar(interp, "sqlite_static_bind_value",
89067c972decSdrh       (char*)&sqlite_static_bind_value, TCL_LINK_STRING);
8907f0313813Sdrh   Tcl_LinkVar(interp, "sqlite_static_bind_nbyte",
8908f0313813Sdrh       (char*)&sqlite_static_bind_nbyte, TCL_LINK_INT);
8909ab3f9feaSdrh   Tcl_LinkVar(interp, "sqlite_temp_directory",
8910effd02bcSdrh       (char*)&sqlite3_temp_directory, TCL_LINK_STRING);
8911a112d140Smistachkin   Tcl_LinkVar(interp, "sqlite_data_directory",
8912a112d140Smistachkin       (char*)&sqlite3_data_directory, TCL_LINK_STRING);
89131398ad36Sdrh   Tcl_LinkVar(interp, "bitmask_size",
89141398ad36Sdrh       (char*)&bitmask_size, TCL_LINK_INT|TCL_LINK_READ_ONLY);
89152ab410aaSdrh   Tcl_LinkVar(interp, "longdouble_size",
89162ab410aaSdrh       (char*)&longdouble_size, TCL_LINK_INT|TCL_LINK_READ_ONLY);
8917b851b2c9Sdrh   Tcl_LinkVar(interp, "sqlite_sync_count",
8918b851b2c9Sdrh       (char*)&sqlite3_sync_count, TCL_LINK_INT);
8919b851b2c9Sdrh   Tcl_LinkVar(interp, "sqlite_fullsync_count",
8920b851b2c9Sdrh       (char*)&sqlite3_fullsync_count, TCL_LINK_INT);
89215e431beaSdrh #if defined(SQLITE_ENABLE_TREETRACE)
89225e431beaSdrh   Tcl_LinkVar(interp, "sqlite3_unsupported_treetrace",
89235e431beaSdrh       (char*)&sqlite3TreeTrace, TCL_LINK_INT);
892486fb6e17Sdan #endif
8925d1fa7bcaSdrh #if defined(SQLITE_ENABLE_FTS3) && defined(SQLITE_TEST)
892633e89035Sdanielk1977   Tcl_LinkVar(interp, "sqlite_fts3_enable_parentheses",
892733e89035Sdanielk1977       (char*)&sqlite3_fts3_enable_parentheses, TCL_LINK_INT);
892833e89035Sdanielk1977 #endif
8929d1bf3512Sdrh   return TCL_OK;
8930d1bf3512Sdrh }
8931