xref: /illumos-gate/usr/src/lib/libsqlite/src/test1.c (revision 1da57d55)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate ** 2001 September 15
37c478bd9Sstevel@tonic-gate **
47c478bd9Sstevel@tonic-gate ** The author disclaims copyright to this source code.  In place of
57c478bd9Sstevel@tonic-gate ** a legal notice, here is a blessing:
67c478bd9Sstevel@tonic-gate **
77c478bd9Sstevel@tonic-gate **    May you do good and not evil.
87c478bd9Sstevel@tonic-gate **    May you find forgiveness for yourself and forgive others.
97c478bd9Sstevel@tonic-gate **    May you share freely, never taking more than you give.
107c478bd9Sstevel@tonic-gate **
117c478bd9Sstevel@tonic-gate *************************************************************************
127c478bd9Sstevel@tonic-gate ** Code for testing the printf() interface to SQLite.  This code
137c478bd9Sstevel@tonic-gate ** is not included in the SQLite library.  It is used for automated
147c478bd9Sstevel@tonic-gate ** testing of the SQLite library.
157c478bd9Sstevel@tonic-gate **
167c478bd9Sstevel@tonic-gate ** $Id: test1.c,v 1.36.2.1 2004/05/07 00:57:06 drh Exp $
177c478bd9Sstevel@tonic-gate */
187c478bd9Sstevel@tonic-gate #include "sqliteInt.h"
197c478bd9Sstevel@tonic-gate #include "tcl.h"
207c478bd9Sstevel@tonic-gate #include "os.h"
217c478bd9Sstevel@tonic-gate #include <stdlib.h>
227c478bd9Sstevel@tonic-gate #include <string.h>
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate #if OS_WIN
257c478bd9Sstevel@tonic-gate # define PTR_FMT "%x"
267c478bd9Sstevel@tonic-gate #else
277c478bd9Sstevel@tonic-gate # define PTR_FMT "%p"
287c478bd9Sstevel@tonic-gate #endif
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate ** Decode a pointer to an sqlite object.
327c478bd9Sstevel@tonic-gate */
getDbPointer(Tcl_Interp * interp,const char * zA,sqlite ** ppDb)337c478bd9Sstevel@tonic-gate static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite **ppDb){
34*48bbca81SDaniel Hoffman   if( sscanf(zA, PTR_FMT, (void**)ppDb)!=1 &&
357c478bd9Sstevel@tonic-gate       (zA[0]!='0' || zA[1]!='x' || sscanf(&zA[2], PTR_FMT, (void**)ppDb)!=1)
367c478bd9Sstevel@tonic-gate   ){
377c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, "\"", zA, "\" is not a valid pointer value", 0);
387c478bd9Sstevel@tonic-gate     return TCL_ERROR;
397c478bd9Sstevel@tonic-gate   }
407c478bd9Sstevel@tonic-gate   return TCL_OK;
417c478bd9Sstevel@tonic-gate }
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /*
447c478bd9Sstevel@tonic-gate ** Decode a pointer to an sqlite_vm object.
457c478bd9Sstevel@tonic-gate */
getVmPointer(Tcl_Interp * interp,const char * zArg,sqlite_vm ** ppVm)467c478bd9Sstevel@tonic-gate static int getVmPointer(Tcl_Interp *interp, const char *zArg, sqlite_vm **ppVm){
477c478bd9Sstevel@tonic-gate   if( sscanf(zArg, PTR_FMT, (void**)ppVm)!=1 ){
487c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, "\"", zArg, "\" is not a valid pointer value", 0);
497c478bd9Sstevel@tonic-gate     return TCL_ERROR;
507c478bd9Sstevel@tonic-gate   }
517c478bd9Sstevel@tonic-gate   return TCL_OK;
527c478bd9Sstevel@tonic-gate }
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate /*
557c478bd9Sstevel@tonic-gate ** Generate a text representation of a pointer that can be understood
567c478bd9Sstevel@tonic-gate ** by the getDbPointer and getVmPointer routines above.
577c478bd9Sstevel@tonic-gate **
587c478bd9Sstevel@tonic-gate ** The problem is, on some machines (Solaris) if you do a printf with
597c478bd9Sstevel@tonic-gate ** "%p" you cannot turn around and do a scanf with the same "%p" and
607c478bd9Sstevel@tonic-gate ** get your pointer back.  You have to prepend a "0x" before it will
617c478bd9Sstevel@tonic-gate ** work.  Or at least that is what is reported to me (drh).  But this
62*48bbca81SDaniel Hoffman ** behavior varies from machine to machine.  The solution used here is
637c478bd9Sstevel@tonic-gate ** to test the string right after it is generated to see if it can be
647c478bd9Sstevel@tonic-gate ** understood by scanf, and if not, try prepending an "0x" to see if
657c478bd9Sstevel@tonic-gate ** that helps.  If nothing works, a fatal error is generated.
667c478bd9Sstevel@tonic-gate */
makePointerStr(Tcl_Interp * interp,char * zPtr,void * p)677c478bd9Sstevel@tonic-gate static int makePointerStr(Tcl_Interp *interp, char *zPtr, void *p){
687c478bd9Sstevel@tonic-gate   void *p2;
697c478bd9Sstevel@tonic-gate   sprintf(zPtr, PTR_FMT, p);
707c478bd9Sstevel@tonic-gate   if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){
717c478bd9Sstevel@tonic-gate     sprintf(zPtr, "0x" PTR_FMT, p);
727c478bd9Sstevel@tonic-gate     if( sscanf(zPtr, PTR_FMT, &p2)!=1 || p2!=p ){
737c478bd9Sstevel@tonic-gate       Tcl_AppendResult(interp, "unable to convert a pointer to a string "
747c478bd9Sstevel@tonic-gate          "in the file " __FILE__ " in function makePointerStr().  Please "
757c478bd9Sstevel@tonic-gate          "report this problem to the SQLite mailing list or as a new but "
767c478bd9Sstevel@tonic-gate          "report.  Please provide detailed information about how you compiled "
777c478bd9Sstevel@tonic-gate          "SQLite and what computer you are running on.", 0);
787c478bd9Sstevel@tonic-gate       return TCL_ERROR;
797c478bd9Sstevel@tonic-gate     }
807c478bd9Sstevel@tonic-gate   }
817c478bd9Sstevel@tonic-gate   return TCL_OK;
827c478bd9Sstevel@tonic-gate }
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate ** Usage:   sqlite_open filename
867c478bd9Sstevel@tonic-gate **
877c478bd9Sstevel@tonic-gate ** Returns:  The name of an open database.
887c478bd9Sstevel@tonic-gate */
sqlite_test_open(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)897c478bd9Sstevel@tonic-gate static int sqlite_test_open(
907c478bd9Sstevel@tonic-gate   void *NotUsed,
917c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
927c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
937c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
947c478bd9Sstevel@tonic-gate ){
957c478bd9Sstevel@tonic-gate   sqlite *db;
967c478bd9Sstevel@tonic-gate   char *zErr = 0;
977c478bd9Sstevel@tonic-gate   char zBuf[100];
987c478bd9Sstevel@tonic-gate   if( argc!=2 ){
997c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1007c478bd9Sstevel@tonic-gate        " FILENAME\"", 0);
1017c478bd9Sstevel@tonic-gate     return TCL_ERROR;
1027c478bd9Sstevel@tonic-gate   }
1037c478bd9Sstevel@tonic-gate   db = sqlite_open(argv[1], 0666, &zErr);
1047c478bd9Sstevel@tonic-gate   if( db==0 ){
1057c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, zErr, 0);
1067c478bd9Sstevel@tonic-gate     free(zErr);
1077c478bd9Sstevel@tonic-gate     return TCL_ERROR;
1087c478bd9Sstevel@tonic-gate   }
1097c478bd9Sstevel@tonic-gate   if( makePointerStr(interp, zBuf, db) ) return TCL_ERROR;
1107c478bd9Sstevel@tonic-gate   Tcl_AppendResult(interp, zBuf, 0);
1117c478bd9Sstevel@tonic-gate   return TCL_OK;
1127c478bd9Sstevel@tonic-gate }
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /*
1157c478bd9Sstevel@tonic-gate ** The callback routine for sqlite_exec_printf().
1167c478bd9Sstevel@tonic-gate */
exec_printf_cb(void * pArg,int argc,char ** argv,char ** name)1177c478bd9Sstevel@tonic-gate static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){
1187c478bd9Sstevel@tonic-gate   Tcl_DString *str = (Tcl_DString*)pArg;
1197c478bd9Sstevel@tonic-gate   int i;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate   if( Tcl_DStringLength(str)==0 ){
1227c478bd9Sstevel@tonic-gate     for(i=0; i<argc; i++){
1237c478bd9Sstevel@tonic-gate       Tcl_DStringAppendElement(str, name[i] ? name[i] : "NULL");
1247c478bd9Sstevel@tonic-gate     }
1257c478bd9Sstevel@tonic-gate   }
1267c478bd9Sstevel@tonic-gate   for(i=0; i<argc; i++){
1277c478bd9Sstevel@tonic-gate     Tcl_DStringAppendElement(str, argv[i] ? argv[i] : "NULL");
1287c478bd9Sstevel@tonic-gate   }
1297c478bd9Sstevel@tonic-gate   return 0;
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate /*
1337c478bd9Sstevel@tonic-gate ** Usage:  sqlite_exec_printf  DB  FORMAT  STRING
1347c478bd9Sstevel@tonic-gate **
1357c478bd9Sstevel@tonic-gate ** Invoke the sqlite_exec_printf() interface using the open database
1367c478bd9Sstevel@tonic-gate ** DB.  The SQL is the string FORMAT.  The format string should contain
1377c478bd9Sstevel@tonic-gate ** one %s or %q.  STRING is the value inserted into %s or %q.
1387c478bd9Sstevel@tonic-gate */
test_exec_printf(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)1397c478bd9Sstevel@tonic-gate static int test_exec_printf(
1407c478bd9Sstevel@tonic-gate   void *NotUsed,
1417c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1427c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
1437c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
1447c478bd9Sstevel@tonic-gate ){
1457c478bd9Sstevel@tonic-gate   sqlite *db;
1467c478bd9Sstevel@tonic-gate   Tcl_DString str;
1477c478bd9Sstevel@tonic-gate   int rc;
1487c478bd9Sstevel@tonic-gate   char *zErr = 0;
1497c478bd9Sstevel@tonic-gate   char zBuf[30];
1507c478bd9Sstevel@tonic-gate   if( argc!=4 ){
151*48bbca81SDaniel Hoffman     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1527c478bd9Sstevel@tonic-gate        " DB FORMAT STRING", 0);
1537c478bd9Sstevel@tonic-gate     return TCL_ERROR;
1547c478bd9Sstevel@tonic-gate   }
1557c478bd9Sstevel@tonic-gate   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
1567c478bd9Sstevel@tonic-gate   Tcl_DStringInit(&str);
1577c478bd9Sstevel@tonic-gate   rc = sqlite_exec_printf(db, argv[2], exec_printf_cb, &str, &zErr, argv[3]);
1587c478bd9Sstevel@tonic-gate   sprintf(zBuf, "%d", rc);
1597c478bd9Sstevel@tonic-gate   Tcl_AppendElement(interp, zBuf);
1607c478bd9Sstevel@tonic-gate   Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
1617c478bd9Sstevel@tonic-gate   Tcl_DStringFree(&str);
1627c478bd9Sstevel@tonic-gate   if( zErr ) free(zErr);
1637c478bd9Sstevel@tonic-gate   return TCL_OK;
1647c478bd9Sstevel@tonic-gate }
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate /*
1677c478bd9Sstevel@tonic-gate ** Usage:  sqlite_mprintf_z_test  SEPARATOR  ARG0  ARG1 ...
1687c478bd9Sstevel@tonic-gate **
169*48bbca81SDaniel Hoffman ** Test the %z format of mprintf().  Use multiple mprintf() calls to
1707c478bd9Sstevel@tonic-gate ** concatenate arg0 through argn using separator as the separator.
1717c478bd9Sstevel@tonic-gate ** Return the result.
1727c478bd9Sstevel@tonic-gate */
test_mprintf_z(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)1737c478bd9Sstevel@tonic-gate static int test_mprintf_z(
1747c478bd9Sstevel@tonic-gate   void *NotUsed,
1757c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1767c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
1777c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
1787c478bd9Sstevel@tonic-gate ){
1797c478bd9Sstevel@tonic-gate   char *zResult = 0;
1807c478bd9Sstevel@tonic-gate   int i;
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate   for(i=2; i<argc; i++){
1837c478bd9Sstevel@tonic-gate     zResult = sqliteMPrintf("%z%s%s", zResult, argv[1], argv[i]);
1847c478bd9Sstevel@tonic-gate   }
1857c478bd9Sstevel@tonic-gate   Tcl_AppendResult(interp, zResult, 0);
1867c478bd9Sstevel@tonic-gate   sqliteFree(zResult);
1877c478bd9Sstevel@tonic-gate   return TCL_OK;
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate /*
1917c478bd9Sstevel@tonic-gate ** Usage:  sqlite_get_table_printf  DB  FORMAT  STRING
1927c478bd9Sstevel@tonic-gate **
1937c478bd9Sstevel@tonic-gate ** Invoke the sqlite_get_table_printf() interface using the open database
1947c478bd9Sstevel@tonic-gate ** DB.  The SQL is the string FORMAT.  The format string should contain
1957c478bd9Sstevel@tonic-gate ** one %s or %q.  STRING is the value inserted into %s or %q.
1967c478bd9Sstevel@tonic-gate */
test_get_table_printf(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)1977c478bd9Sstevel@tonic-gate static int test_get_table_printf(
1987c478bd9Sstevel@tonic-gate   void *NotUsed,
1997c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
2007c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
2017c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
2027c478bd9Sstevel@tonic-gate ){
2037c478bd9Sstevel@tonic-gate   sqlite *db;
2047c478bd9Sstevel@tonic-gate   Tcl_DString str;
2057c478bd9Sstevel@tonic-gate   int rc;
2067c478bd9Sstevel@tonic-gate   char *zErr = 0;
2077c478bd9Sstevel@tonic-gate   int nRow, nCol;
2087c478bd9Sstevel@tonic-gate   char **aResult;
2097c478bd9Sstevel@tonic-gate   int i;
2107c478bd9Sstevel@tonic-gate   char zBuf[30];
2117c478bd9Sstevel@tonic-gate   if( argc!=4 ){
212*48bbca81SDaniel Hoffman     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2137c478bd9Sstevel@tonic-gate        " DB FORMAT STRING", 0);
2147c478bd9Sstevel@tonic-gate     return TCL_ERROR;
2157c478bd9Sstevel@tonic-gate   }
2167c478bd9Sstevel@tonic-gate   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
2177c478bd9Sstevel@tonic-gate   Tcl_DStringInit(&str);
218*48bbca81SDaniel Hoffman   rc = sqlite_get_table_printf(db, argv[2], &aResult, &nRow, &nCol,
2197c478bd9Sstevel@tonic-gate                &zErr, argv[3]);
2207c478bd9Sstevel@tonic-gate   sprintf(zBuf, "%d", rc);
2217c478bd9Sstevel@tonic-gate   Tcl_AppendElement(interp, zBuf);
2227c478bd9Sstevel@tonic-gate   if( rc==SQLITE_OK ){
2237c478bd9Sstevel@tonic-gate     sprintf(zBuf, "%d", nRow);
2247c478bd9Sstevel@tonic-gate     Tcl_AppendElement(interp, zBuf);
2257c478bd9Sstevel@tonic-gate     sprintf(zBuf, "%d", nCol);
2267c478bd9Sstevel@tonic-gate     Tcl_AppendElement(interp, zBuf);
2277c478bd9Sstevel@tonic-gate     for(i=0; i<(nRow+1)*nCol; i++){
2287c478bd9Sstevel@tonic-gate       Tcl_AppendElement(interp, aResult[i] ? aResult[i] : "NULL");
2297c478bd9Sstevel@tonic-gate     }
2307c478bd9Sstevel@tonic-gate   }else{
2317c478bd9Sstevel@tonic-gate     Tcl_AppendElement(interp, zErr);
2327c478bd9Sstevel@tonic-gate   }
2337c478bd9Sstevel@tonic-gate   sqlite_free_table(aResult);
2347c478bd9Sstevel@tonic-gate   if( zErr ) free(zErr);
2357c478bd9Sstevel@tonic-gate   return TCL_OK;
2367c478bd9Sstevel@tonic-gate }
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate /*
2407c478bd9Sstevel@tonic-gate ** Usage:  sqlite_last_insert_rowid DB
2417c478bd9Sstevel@tonic-gate **
2427c478bd9Sstevel@tonic-gate ** Returns the integer ROWID of the most recent insert.
2437c478bd9Sstevel@tonic-gate */
test_last_rowid(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)2447c478bd9Sstevel@tonic-gate static int test_last_rowid(
2457c478bd9Sstevel@tonic-gate   void *NotUsed,
2467c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
2477c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
2487c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
2497c478bd9Sstevel@tonic-gate ){
2507c478bd9Sstevel@tonic-gate   sqlite *db;
2517c478bd9Sstevel@tonic-gate   char zBuf[30];
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate   if( argc!=2 ){
2547c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB\"", 0);
2557c478bd9Sstevel@tonic-gate     return TCL_ERROR;
2567c478bd9Sstevel@tonic-gate   }
2577c478bd9Sstevel@tonic-gate   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
2587c478bd9Sstevel@tonic-gate   sprintf(zBuf, "%d", sqlite_last_insert_rowid(db));
2597c478bd9Sstevel@tonic-gate   Tcl_AppendResult(interp, zBuf, 0);
2607c478bd9Sstevel@tonic-gate   return SQLITE_OK;
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate /*
2647c478bd9Sstevel@tonic-gate ** Usage:  sqlite_close DB
2657c478bd9Sstevel@tonic-gate **
2667c478bd9Sstevel@tonic-gate ** Closes the database opened by sqlite_open.
2677c478bd9Sstevel@tonic-gate */
sqlite_test_close(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)2687c478bd9Sstevel@tonic-gate static int sqlite_test_close(
2697c478bd9Sstevel@tonic-gate   void *NotUsed,
2707c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
2717c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
2727c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
2737c478bd9Sstevel@tonic-gate ){
2747c478bd9Sstevel@tonic-gate   sqlite *db;
2757c478bd9Sstevel@tonic-gate   if( argc!=2 ){
2767c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
2777c478bd9Sstevel@tonic-gate        " FILENAME\"", 0);
2787c478bd9Sstevel@tonic-gate     return TCL_ERROR;
2797c478bd9Sstevel@tonic-gate   }
2807c478bd9Sstevel@tonic-gate   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
2817c478bd9Sstevel@tonic-gate   sqlite_close(db);
2827c478bd9Sstevel@tonic-gate   return TCL_OK;
2837c478bd9Sstevel@tonic-gate }
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate /*
2867c478bd9Sstevel@tonic-gate ** Implementation of the x_coalesce() function.
2877c478bd9Sstevel@tonic-gate ** Return the first argument non-NULL argument.
2887c478bd9Sstevel@tonic-gate */
ifnullFunc(sqlite_func * context,int argc,const char ** argv)2897c478bd9Sstevel@tonic-gate static void ifnullFunc(sqlite_func *context, int argc, const char **argv){
2907c478bd9Sstevel@tonic-gate   int i;
2917c478bd9Sstevel@tonic-gate   for(i=0; i<argc; i++){
2927c478bd9Sstevel@tonic-gate     if( argv[i] ){
2937c478bd9Sstevel@tonic-gate       sqlite_set_result_string(context, argv[i], -1);
2947c478bd9Sstevel@tonic-gate       break;
2957c478bd9Sstevel@tonic-gate     }
2967c478bd9Sstevel@tonic-gate   }
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate /*
3007c478bd9Sstevel@tonic-gate ** A structure into which to accumulate text.
3017c478bd9Sstevel@tonic-gate */
3027c478bd9Sstevel@tonic-gate struct dstr {
3037c478bd9Sstevel@tonic-gate   int nAlloc;  /* Space allocated */
3047c478bd9Sstevel@tonic-gate   int nUsed;   /* Space used */
3057c478bd9Sstevel@tonic-gate   char *z;     /* The space */
3067c478bd9Sstevel@tonic-gate };
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate /*
3097c478bd9Sstevel@tonic-gate ** Append text to a dstr
3107c478bd9Sstevel@tonic-gate */
dstrAppend(struct dstr * p,const char * z,int divider)3117c478bd9Sstevel@tonic-gate static void dstrAppend(struct dstr *p, const char *z, int divider){
3127c478bd9Sstevel@tonic-gate   int n = strlen(z);
3137c478bd9Sstevel@tonic-gate   if( p->nUsed + n + 2 > p->nAlloc ){
3147c478bd9Sstevel@tonic-gate     char *zNew;
3157c478bd9Sstevel@tonic-gate     p->nAlloc = p->nAlloc*2 + n + 200;
3167c478bd9Sstevel@tonic-gate     zNew = sqliteRealloc(p->z, p->nAlloc);
3177c478bd9Sstevel@tonic-gate     if( zNew==0 ){
3187c478bd9Sstevel@tonic-gate       sqliteFree(p->z);
3197c478bd9Sstevel@tonic-gate       memset(p, 0, sizeof(*p));
3207c478bd9Sstevel@tonic-gate       return;
3217c478bd9Sstevel@tonic-gate     }
3227c478bd9Sstevel@tonic-gate     p->z = zNew;
3237c478bd9Sstevel@tonic-gate   }
3247c478bd9Sstevel@tonic-gate   if( divider && p->nUsed>0 ){
3257c478bd9Sstevel@tonic-gate     p->z[p->nUsed++] = divider;
3267c478bd9Sstevel@tonic-gate   }
3277c478bd9Sstevel@tonic-gate   memcpy(&p->z[p->nUsed], z, n+1);
3287c478bd9Sstevel@tonic-gate   p->nUsed += n;
3297c478bd9Sstevel@tonic-gate }
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate /*
3327c478bd9Sstevel@tonic-gate ** Invoked for each callback from sqliteExecFunc
3337c478bd9Sstevel@tonic-gate */
execFuncCallback(void * pData,int argc,char ** argv,char ** NotUsed)3347c478bd9Sstevel@tonic-gate static int execFuncCallback(void *pData, int argc, char **argv, char **NotUsed){
3357c478bd9Sstevel@tonic-gate   struct dstr *p = (struct dstr*)pData;
3367c478bd9Sstevel@tonic-gate   int i;
3377c478bd9Sstevel@tonic-gate   for(i=0; i<argc; i++){
3387c478bd9Sstevel@tonic-gate     if( argv[i]==0 ){
3397c478bd9Sstevel@tonic-gate       dstrAppend(p, "NULL", ' ');
3407c478bd9Sstevel@tonic-gate     }else{
3417c478bd9Sstevel@tonic-gate       dstrAppend(p, argv[i], ' ');
3427c478bd9Sstevel@tonic-gate     }
3437c478bd9Sstevel@tonic-gate   }
3447c478bd9Sstevel@tonic-gate   return 0;
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate /*
3487c478bd9Sstevel@tonic-gate ** Implementation of the x_sqlite_exec() function.  This function takes
3497c478bd9Sstevel@tonic-gate ** a single argument and attempts to execute that argument as SQL code.
3507c478bd9Sstevel@tonic-gate ** This is illegal and should set the SQLITE_MISUSE flag on the database.
3517c478bd9Sstevel@tonic-gate **
3527c478bd9Sstevel@tonic-gate ** 2004-Jan-07:  We have changed this to make it legal to call sqlite_exec()
353*48bbca81SDaniel Hoffman ** from within a function call.
354*48bbca81SDaniel Hoffman **
3557c478bd9Sstevel@tonic-gate ** This routine simulates the effect of having two threads attempt to
3567c478bd9Sstevel@tonic-gate ** use the same database at the same time.
3577c478bd9Sstevel@tonic-gate */
sqliteExecFunc(sqlite_func * context,int argc,const char ** argv)3587c478bd9Sstevel@tonic-gate static void sqliteExecFunc(sqlite_func *context, int argc, const char **argv){
3597c478bd9Sstevel@tonic-gate   struct dstr x;
3607c478bd9Sstevel@tonic-gate   memset(&x, 0, sizeof(x));
361*48bbca81SDaniel Hoffman   sqlite_exec((sqlite*)sqlite_user_data(context), argv[0],
3627c478bd9Sstevel@tonic-gate       execFuncCallback, &x, 0);
3637c478bd9Sstevel@tonic-gate   sqlite_set_result_string(context, x.z, x.nUsed);
3647c478bd9Sstevel@tonic-gate   sqliteFree(x.z);
3657c478bd9Sstevel@tonic-gate }
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate /*
3687c478bd9Sstevel@tonic-gate ** Usage:  sqlite_test_create_function DB
3697c478bd9Sstevel@tonic-gate **
3707c478bd9Sstevel@tonic-gate ** Call the sqlite_create_function API on the given database in order
3717c478bd9Sstevel@tonic-gate ** to create a function named "x_coalesce".  This function does the same thing
3727c478bd9Sstevel@tonic-gate ** as the "coalesce" function.  This function also registers an SQL function
3737c478bd9Sstevel@tonic-gate ** named "x_sqlite_exec" that invokes sqlite_exec().  Invoking sqlite_exec()
3747c478bd9Sstevel@tonic-gate ** in this way is illegal recursion and should raise an SQLITE_MISUSE error.
3757c478bd9Sstevel@tonic-gate ** The effect is similar to trying to use the same database connection from
3767c478bd9Sstevel@tonic-gate ** two threads at the same time.
3777c478bd9Sstevel@tonic-gate **
3787c478bd9Sstevel@tonic-gate ** The original motivation for this routine was to be able to call the
3797c478bd9Sstevel@tonic-gate ** sqlite_create_function function while a query is in progress in order
3807c478bd9Sstevel@tonic-gate ** to test the SQLITE_MISUSE detection logic.
3817c478bd9Sstevel@tonic-gate */
test_create_function(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)3827c478bd9Sstevel@tonic-gate static int test_create_function(
3837c478bd9Sstevel@tonic-gate   void *NotUsed,
3847c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
3857c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
3867c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
3877c478bd9Sstevel@tonic-gate ){
3887c478bd9Sstevel@tonic-gate   sqlite *db;
3897c478bd9Sstevel@tonic-gate   extern void Md5_Register(sqlite*);
3907c478bd9Sstevel@tonic-gate   if( argc!=2 ){
3917c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
3927c478bd9Sstevel@tonic-gate        " FILENAME\"", 0);
3937c478bd9Sstevel@tonic-gate     return TCL_ERROR;
3947c478bd9Sstevel@tonic-gate   }
3957c478bd9Sstevel@tonic-gate   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
3967c478bd9Sstevel@tonic-gate   sqlite_create_function(db, "x_coalesce", -1, ifnullFunc, 0);
3977c478bd9Sstevel@tonic-gate   sqlite_create_function(db, "x_sqlite_exec", 1, sqliteExecFunc, db);
3987c478bd9Sstevel@tonic-gate   return TCL_OK;
3997c478bd9Sstevel@tonic-gate }
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate /*
4027c478bd9Sstevel@tonic-gate ** Routines to implement the x_count() aggregate function.
4037c478bd9Sstevel@tonic-gate */
4047c478bd9Sstevel@tonic-gate typedef struct CountCtx CountCtx;
4057c478bd9Sstevel@tonic-gate struct CountCtx {
4067c478bd9Sstevel@tonic-gate   int n;
4077c478bd9Sstevel@tonic-gate };
countStep(sqlite_func * context,int argc,const char ** argv)4087c478bd9Sstevel@tonic-gate static void countStep(sqlite_func *context, int argc, const char **argv){
4097c478bd9Sstevel@tonic-gate   CountCtx *p;
4107c478bd9Sstevel@tonic-gate   p = sqlite_aggregate_context(context, sizeof(*p));
4117c478bd9Sstevel@tonic-gate   if( (argc==0 || argv[0]) && p ){
4127c478bd9Sstevel@tonic-gate     p->n++;
4137c478bd9Sstevel@tonic-gate   }
414*48bbca81SDaniel Hoffman }
countFinalize(sqlite_func * context)4157c478bd9Sstevel@tonic-gate static void countFinalize(sqlite_func *context){
4167c478bd9Sstevel@tonic-gate   CountCtx *p;
4177c478bd9Sstevel@tonic-gate   p = sqlite_aggregate_context(context, sizeof(*p));
4187c478bd9Sstevel@tonic-gate   sqlite_set_result_int(context, p ? p->n : 0);
4197c478bd9Sstevel@tonic-gate }
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate /*
4227c478bd9Sstevel@tonic-gate ** Usage:  sqlite_test_create_aggregate DB
4237c478bd9Sstevel@tonic-gate **
4247c478bd9Sstevel@tonic-gate ** Call the sqlite_create_function API on the given database in order
4257c478bd9Sstevel@tonic-gate ** to create a function named "x_count".  This function does the same thing
4267c478bd9Sstevel@tonic-gate ** as the "md5sum" function.
4277c478bd9Sstevel@tonic-gate **
4287c478bd9Sstevel@tonic-gate ** The original motivation for this routine was to be able to call the
4297c478bd9Sstevel@tonic-gate ** sqlite_create_aggregate function while a query is in progress in order
4307c478bd9Sstevel@tonic-gate ** to test the SQLITE_MISUSE detection logic.
4317c478bd9Sstevel@tonic-gate */
test_create_aggregate(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)4327c478bd9Sstevel@tonic-gate static int test_create_aggregate(
4337c478bd9Sstevel@tonic-gate   void *NotUsed,
4347c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
4357c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
4367c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
4377c478bd9Sstevel@tonic-gate ){
4387c478bd9Sstevel@tonic-gate   sqlite *db;
4397c478bd9Sstevel@tonic-gate   if( argc!=2 ){
4407c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
4417c478bd9Sstevel@tonic-gate        " FILENAME\"", 0);
4427c478bd9Sstevel@tonic-gate     return TCL_ERROR;
4437c478bd9Sstevel@tonic-gate   }
4447c478bd9Sstevel@tonic-gate   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
4457c478bd9Sstevel@tonic-gate   sqlite_create_aggregate(db, "x_count", 0, countStep, countFinalize, 0);
4467c478bd9Sstevel@tonic-gate   sqlite_create_aggregate(db, "x_count", 1, countStep, countFinalize, 0);
4477c478bd9Sstevel@tonic-gate   return TCL_OK;
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate /*
4537c478bd9Sstevel@tonic-gate ** Usage:  sqlite_mprintf_int FORMAT INTEGER INTEGER INTEGER
4547c478bd9Sstevel@tonic-gate **
4557c478bd9Sstevel@tonic-gate ** Call mprintf with three integer arguments
4567c478bd9Sstevel@tonic-gate */
sqlite_mprintf_int(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)4577c478bd9Sstevel@tonic-gate static int sqlite_mprintf_int(
4587c478bd9Sstevel@tonic-gate   void *NotUsed,
4597c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
4607c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
4617c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
4627c478bd9Sstevel@tonic-gate ){
4637c478bd9Sstevel@tonic-gate   int a[3], i;
4647c478bd9Sstevel@tonic-gate   char *z;
4657c478bd9Sstevel@tonic-gate   if( argc!=5 ){
4667c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
4677c478bd9Sstevel@tonic-gate        " FORMAT INT INT INT\"", 0);
4687c478bd9Sstevel@tonic-gate     return TCL_ERROR;
4697c478bd9Sstevel@tonic-gate   }
4707c478bd9Sstevel@tonic-gate   for(i=2; i<5; i++){
4717c478bd9Sstevel@tonic-gate     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
4727c478bd9Sstevel@tonic-gate   }
4737c478bd9Sstevel@tonic-gate   z = sqlite_mprintf(argv[1], a[0], a[1], a[2]);
4747c478bd9Sstevel@tonic-gate   Tcl_AppendResult(interp, z, 0);
4757c478bd9Sstevel@tonic-gate   sqlite_freemem(z);
4767c478bd9Sstevel@tonic-gate   return TCL_OK;
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate /*
4807c478bd9Sstevel@tonic-gate ** Usage:  sqlite_mprintf_str FORMAT INTEGER INTEGER STRING
4817c478bd9Sstevel@tonic-gate **
4827c478bd9Sstevel@tonic-gate ** Call mprintf with two integer arguments and one string argument
4837c478bd9Sstevel@tonic-gate */
sqlite_mprintf_str(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)4847c478bd9Sstevel@tonic-gate static int sqlite_mprintf_str(
4857c478bd9Sstevel@tonic-gate   void *NotUsed,
4867c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
4877c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
4887c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
4897c478bd9Sstevel@tonic-gate ){
4907c478bd9Sstevel@tonic-gate   int a[3], i;
4917c478bd9Sstevel@tonic-gate   char *z;
4927c478bd9Sstevel@tonic-gate   if( argc<4 || argc>5 ){
4937c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
4947c478bd9Sstevel@tonic-gate        " FORMAT INT INT ?STRING?\"", 0);
4957c478bd9Sstevel@tonic-gate     return TCL_ERROR;
4967c478bd9Sstevel@tonic-gate   }
4977c478bd9Sstevel@tonic-gate   for(i=2; i<4; i++){
4987c478bd9Sstevel@tonic-gate     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
4997c478bd9Sstevel@tonic-gate   }
5007c478bd9Sstevel@tonic-gate   z = sqlite_mprintf(argv[1], a[0], a[1], argc>4 ? argv[4] : NULL);
5017c478bd9Sstevel@tonic-gate   Tcl_AppendResult(interp, z, 0);
5027c478bd9Sstevel@tonic-gate   sqlite_freemem(z);
5037c478bd9Sstevel@tonic-gate   return TCL_OK;
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate /*
5077c478bd9Sstevel@tonic-gate ** Usage:  sqlite_mprintf_str FORMAT INTEGER INTEGER DOUBLE
5087c478bd9Sstevel@tonic-gate **
5097c478bd9Sstevel@tonic-gate ** Call mprintf with two integer arguments and one double argument
5107c478bd9Sstevel@tonic-gate */
sqlite_mprintf_double(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)5117c478bd9Sstevel@tonic-gate static int sqlite_mprintf_double(
5127c478bd9Sstevel@tonic-gate   void *NotUsed,
5137c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
5147c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
5157c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
5167c478bd9Sstevel@tonic-gate ){
5177c478bd9Sstevel@tonic-gate   int a[3], i;
5187c478bd9Sstevel@tonic-gate   double r;
5197c478bd9Sstevel@tonic-gate   char *z;
5207c478bd9Sstevel@tonic-gate   if( argc!=5 ){
5217c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
5227c478bd9Sstevel@tonic-gate        " FORMAT INT INT STRING\"", 0);
5237c478bd9Sstevel@tonic-gate     return TCL_ERROR;
5247c478bd9Sstevel@tonic-gate   }
5257c478bd9Sstevel@tonic-gate   for(i=2; i<4; i++){
5267c478bd9Sstevel@tonic-gate     if( Tcl_GetInt(interp, argv[i], &a[i-2]) ) return TCL_ERROR;
5277c478bd9Sstevel@tonic-gate   }
5287c478bd9Sstevel@tonic-gate   if( Tcl_GetDouble(interp, argv[4], &r) ) return TCL_ERROR;
5297c478bd9Sstevel@tonic-gate   z = sqlite_mprintf(argv[1], a[0], a[1], r);
5307c478bd9Sstevel@tonic-gate   Tcl_AppendResult(interp, z, 0);
5317c478bd9Sstevel@tonic-gate   sqlite_freemem(z);
5327c478bd9Sstevel@tonic-gate   return TCL_OK;
5337c478bd9Sstevel@tonic-gate }
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate /*
5367c478bd9Sstevel@tonic-gate ** Usage:  sqlite_mprintf_str FORMAT DOUBLE DOUBLE
5377c478bd9Sstevel@tonic-gate **
5387c478bd9Sstevel@tonic-gate ** Call mprintf with a single double argument which is the product of the
5397c478bd9Sstevel@tonic-gate ** two arguments given above.  This is used to generate overflow and underflow
5407c478bd9Sstevel@tonic-gate ** doubles to test that they are converted properly.
5417c478bd9Sstevel@tonic-gate */
sqlite_mprintf_scaled(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)5427c478bd9Sstevel@tonic-gate static int sqlite_mprintf_scaled(
5437c478bd9Sstevel@tonic-gate   void *NotUsed,
5447c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
5457c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
5467c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
5477c478bd9Sstevel@tonic-gate ){
5487c478bd9Sstevel@tonic-gate   int i;
5497c478bd9Sstevel@tonic-gate   double r[2];
5507c478bd9Sstevel@tonic-gate   char *z;
5517c478bd9Sstevel@tonic-gate   if( argc!=4 ){
5527c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
5537c478bd9Sstevel@tonic-gate        " FORMAT DOUBLE DOUBLE\"", 0);
5547c478bd9Sstevel@tonic-gate     return TCL_ERROR;
5557c478bd9Sstevel@tonic-gate   }
5567c478bd9Sstevel@tonic-gate   for(i=2; i<4; i++){
5577c478bd9Sstevel@tonic-gate     if( Tcl_GetDouble(interp, argv[i], &r[i-2]) ) return TCL_ERROR;
5587c478bd9Sstevel@tonic-gate   }
5597c478bd9Sstevel@tonic-gate   z = sqlite_mprintf(argv[1], r[0]*r[1]);
5607c478bd9Sstevel@tonic-gate   Tcl_AppendResult(interp, z, 0);
5617c478bd9Sstevel@tonic-gate   sqlite_freemem(z);
5627c478bd9Sstevel@tonic-gate   return TCL_OK;
5637c478bd9Sstevel@tonic-gate }
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate /*
5667c478bd9Sstevel@tonic-gate ** Usage: sqlite_malloc_fail N
5677c478bd9Sstevel@tonic-gate **
5687c478bd9Sstevel@tonic-gate ** Rig sqliteMalloc() to fail on the N-th call.  Turn off this mechanism
5697c478bd9Sstevel@tonic-gate ** and reset the sqlite_malloc_failed variable is N==0.
5707c478bd9Sstevel@tonic-gate */
5717c478bd9Sstevel@tonic-gate #ifdef MEMORY_DEBUG
sqlite_malloc_fail(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)5727c478bd9Sstevel@tonic-gate static int sqlite_malloc_fail(
5737c478bd9Sstevel@tonic-gate   void *NotUsed,
5747c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
5757c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
5767c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
5777c478bd9Sstevel@tonic-gate ){
5787c478bd9Sstevel@tonic-gate   int n;
5797c478bd9Sstevel@tonic-gate   if( argc!=2 ){
5807c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N\"", 0);
5817c478bd9Sstevel@tonic-gate     return TCL_ERROR;
5827c478bd9Sstevel@tonic-gate   }
5837c478bd9Sstevel@tonic-gate   if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
5847c478bd9Sstevel@tonic-gate   sqlite_iMallocFail = n;
5857c478bd9Sstevel@tonic-gate   sqlite_malloc_failed = 0;
5867c478bd9Sstevel@tonic-gate   return TCL_OK;
5877c478bd9Sstevel@tonic-gate }
5887c478bd9Sstevel@tonic-gate #endif
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate /*
5917c478bd9Sstevel@tonic-gate ** Usage: sqlite_malloc_stat
5927c478bd9Sstevel@tonic-gate **
5937c478bd9Sstevel@tonic-gate ** Return the number of prior calls to sqliteMalloc() and sqliteFree().
5947c478bd9Sstevel@tonic-gate */
5957c478bd9Sstevel@tonic-gate #ifdef MEMORY_DEBUG
sqlite_malloc_stat(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)5967c478bd9Sstevel@tonic-gate static int sqlite_malloc_stat(
5977c478bd9Sstevel@tonic-gate   void *NotUsed,
5987c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
5997c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
6007c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
6017c478bd9Sstevel@tonic-gate ){
6027c478bd9Sstevel@tonic-gate   char zBuf[200];
6037c478bd9Sstevel@tonic-gate   sprintf(zBuf, "%d %d %d", sqlite_nMalloc, sqlite_nFree, sqlite_iMallocFail);
6047c478bd9Sstevel@tonic-gate   Tcl_AppendResult(interp, zBuf, 0);
6057c478bd9Sstevel@tonic-gate   return TCL_OK;
6067c478bd9Sstevel@tonic-gate }
6077c478bd9Sstevel@tonic-gate #endif
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate /*
6107c478bd9Sstevel@tonic-gate ** Usage:  sqlite_abort
6117c478bd9Sstevel@tonic-gate **
6127c478bd9Sstevel@tonic-gate ** Shutdown the process immediately.  This is not a clean shutdown.
6137c478bd9Sstevel@tonic-gate ** This command is used to test the recoverability of a database in
6147c478bd9Sstevel@tonic-gate ** the event of a program crash.
6157c478bd9Sstevel@tonic-gate */
sqlite_abort(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)6167c478bd9Sstevel@tonic-gate static int sqlite_abort(
6177c478bd9Sstevel@tonic-gate   void *NotUsed,
6187c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6197c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
6207c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
6217c478bd9Sstevel@tonic-gate ){
6227c478bd9Sstevel@tonic-gate   assert( interp==0 );   /* This will always fail */
6237c478bd9Sstevel@tonic-gate   return TCL_OK;
6247c478bd9Sstevel@tonic-gate }
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate /*
6277c478bd9Sstevel@tonic-gate ** The following routine is a user-defined SQL function whose purpose
6287c478bd9Sstevel@tonic-gate ** is to test the sqlite_set_result() API.
6297c478bd9Sstevel@tonic-gate */
testFunc(sqlite_func * context,int argc,const char ** argv)6307c478bd9Sstevel@tonic-gate static void testFunc(sqlite_func *context, int argc, const char **argv){
6317c478bd9Sstevel@tonic-gate   while( argc>=2 ){
6327c478bd9Sstevel@tonic-gate     if( argv[0]==0 ){
6337c478bd9Sstevel@tonic-gate       sqlite_set_result_error(context, "first argument to test function "
6347c478bd9Sstevel@tonic-gate          "may not be NULL", -1);
6357c478bd9Sstevel@tonic-gate     }else if( sqliteStrICmp(argv[0],"string")==0 ){
6367c478bd9Sstevel@tonic-gate       sqlite_set_result_string(context, argv[1], -1);
6377c478bd9Sstevel@tonic-gate     }else if( argv[1]==0 ){
6387c478bd9Sstevel@tonic-gate       sqlite_set_result_error(context, "2nd argument may not be NULL if the "
6397c478bd9Sstevel@tonic-gate          "first argument is not \"string\"", -1);
6407c478bd9Sstevel@tonic-gate     }else if( sqliteStrICmp(argv[0],"int")==0 ){
6417c478bd9Sstevel@tonic-gate       sqlite_set_result_int(context, atoi(argv[1]));
6427c478bd9Sstevel@tonic-gate     }else if( sqliteStrICmp(argv[0],"double")==0 ){
6437c478bd9Sstevel@tonic-gate       sqlite_set_result_double(context, sqliteAtoF(argv[1], 0));
6447c478bd9Sstevel@tonic-gate     }else{
6457c478bd9Sstevel@tonic-gate       sqlite_set_result_error(context,"first argument should be one of: "
6467c478bd9Sstevel@tonic-gate           "string int double", -1);
6477c478bd9Sstevel@tonic-gate     }
6487c478bd9Sstevel@tonic-gate     argc -= 2;
6497c478bd9Sstevel@tonic-gate     argv += 2;
6507c478bd9Sstevel@tonic-gate   }
6517c478bd9Sstevel@tonic-gate }
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate /*
6547c478bd9Sstevel@tonic-gate ** Usage:   sqlite_register_test_function  DB  NAME
6557c478bd9Sstevel@tonic-gate **
6567c478bd9Sstevel@tonic-gate ** Register the test SQL function on the database DB under the name NAME.
6577c478bd9Sstevel@tonic-gate */
test_register_func(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)6587c478bd9Sstevel@tonic-gate static int test_register_func(
6597c478bd9Sstevel@tonic-gate   void *NotUsed,
6607c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
6617c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
6627c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
6637c478bd9Sstevel@tonic-gate ){
6647c478bd9Sstevel@tonic-gate   sqlite *db;
6657c478bd9Sstevel@tonic-gate   int rc;
6667c478bd9Sstevel@tonic-gate   if( argc!=3 ){
667*48bbca81SDaniel Hoffman     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
6687c478bd9Sstevel@tonic-gate        " DB FUNCTION-NAME", 0);
6697c478bd9Sstevel@tonic-gate     return TCL_ERROR;
6707c478bd9Sstevel@tonic-gate   }
6717c478bd9Sstevel@tonic-gate   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
6727c478bd9Sstevel@tonic-gate   rc = sqlite_create_function(db, argv[2], -1, testFunc, 0);
6737c478bd9Sstevel@tonic-gate   if( rc!=0 ){
6747c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
6757c478bd9Sstevel@tonic-gate     return TCL_ERROR;
6767c478bd9Sstevel@tonic-gate   }
6777c478bd9Sstevel@tonic-gate   return TCL_OK;
6787c478bd9Sstevel@tonic-gate }
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate /*
6817c478bd9Sstevel@tonic-gate ** This SQLite callback records the datatype of all columns.
6827c478bd9Sstevel@tonic-gate **
6837c478bd9Sstevel@tonic-gate ** The pArg argument is really a pointer to a TCL interpreter.  The
6847c478bd9Sstevel@tonic-gate ** column names are inserted as the result of this interpreter.
6857c478bd9Sstevel@tonic-gate **
6867c478bd9Sstevel@tonic-gate ** This routine returns non-zero which causes the query to abort.
6877c478bd9Sstevel@tonic-gate */
rememberDataTypes(void * pArg,int nCol,char ** argv,char ** colv)6887c478bd9Sstevel@tonic-gate static int rememberDataTypes(void *pArg, int nCol, char **argv, char **colv){
6897c478bd9Sstevel@tonic-gate   int i;
6907c478bd9Sstevel@tonic-gate   Tcl_Interp *interp = (Tcl_Interp*)pArg;
6917c478bd9Sstevel@tonic-gate   Tcl_Obj *pList, *pElem;
6927c478bd9Sstevel@tonic-gate   if( colv[nCol+1]==0 ){
6937c478bd9Sstevel@tonic-gate     return 1;
6947c478bd9Sstevel@tonic-gate   }
6957c478bd9Sstevel@tonic-gate   pList = Tcl_NewObj();
6967c478bd9Sstevel@tonic-gate   for(i=0; i<nCol; i++){
6977c478bd9Sstevel@tonic-gate     pElem = Tcl_NewStringObj(colv[i+nCol] ? colv[i+nCol] : "NULL", -1);
6987c478bd9Sstevel@tonic-gate     Tcl_ListObjAppendElement(interp, pList, pElem);
6997c478bd9Sstevel@tonic-gate   }
7007c478bd9Sstevel@tonic-gate   Tcl_SetObjResult(interp, pList);
7017c478bd9Sstevel@tonic-gate   return 1;
7027c478bd9Sstevel@tonic-gate }
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate /*
7057c478bd9Sstevel@tonic-gate ** Invoke an SQL statement but ignore all the data in the result.  Instead,
7067c478bd9Sstevel@tonic-gate ** return a list that consists of the datatypes of the various columns.
7077c478bd9Sstevel@tonic-gate **
7087c478bd9Sstevel@tonic-gate ** This only works if "PRAGMA show_datatypes=on" has been executed against
7097c478bd9Sstevel@tonic-gate ** the database connection.
7107c478bd9Sstevel@tonic-gate */
sqlite_datatypes(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)7117c478bd9Sstevel@tonic-gate static int sqlite_datatypes(
7127c478bd9Sstevel@tonic-gate   void *NotUsed,
7137c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
7147c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
7157c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
7167c478bd9Sstevel@tonic-gate ){
7177c478bd9Sstevel@tonic-gate   sqlite *db;
7187c478bd9Sstevel@tonic-gate   int rc;
7197c478bd9Sstevel@tonic-gate   if( argc!=3 ){
720*48bbca81SDaniel Hoffman     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
7217c478bd9Sstevel@tonic-gate        " DB SQL", 0);
7227c478bd9Sstevel@tonic-gate     return TCL_ERROR;
7237c478bd9Sstevel@tonic-gate   }
7247c478bd9Sstevel@tonic-gate   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
7257c478bd9Sstevel@tonic-gate   rc = sqlite_exec(db, argv[2], rememberDataTypes, interp, 0);
7267c478bd9Sstevel@tonic-gate   if( rc!=0 && rc!=SQLITE_ABORT ){
7277c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
7287c478bd9Sstevel@tonic-gate     return TCL_ERROR;
7297c478bd9Sstevel@tonic-gate   }
7307c478bd9Sstevel@tonic-gate   return TCL_OK;
7317c478bd9Sstevel@tonic-gate }
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate /*
7347c478bd9Sstevel@tonic-gate ** Usage:  sqlite_compile  DB  SQL  ?TAILVAR?
7357c478bd9Sstevel@tonic-gate **
7367c478bd9Sstevel@tonic-gate ** Attempt to compile an SQL statement.  Return a pointer to the virtual
7377c478bd9Sstevel@tonic-gate ** machine used to execute that statement.  Unprocessed SQL is written
7387c478bd9Sstevel@tonic-gate ** into TAILVAR.
7397c478bd9Sstevel@tonic-gate */
test_compile(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)7407c478bd9Sstevel@tonic-gate static int test_compile(
7417c478bd9Sstevel@tonic-gate   void *NotUsed,
7427c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
7437c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
7447c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
7457c478bd9Sstevel@tonic-gate ){
7467c478bd9Sstevel@tonic-gate   sqlite *db;
7477c478bd9Sstevel@tonic-gate   sqlite_vm *vm;
7487c478bd9Sstevel@tonic-gate   int rc;
7497c478bd9Sstevel@tonic-gate   char *zErr = 0;
7507c478bd9Sstevel@tonic-gate   const char *zTail;
7517c478bd9Sstevel@tonic-gate   char zBuf[50];
7527c478bd9Sstevel@tonic-gate   if( argc!=3 && argc!=4 ){
753*48bbca81SDaniel Hoffman     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
7547c478bd9Sstevel@tonic-gate        " DB SQL TAILVAR", 0);
7557c478bd9Sstevel@tonic-gate     return TCL_ERROR;
7567c478bd9Sstevel@tonic-gate   }
7577c478bd9Sstevel@tonic-gate   if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
7587c478bd9Sstevel@tonic-gate   rc = sqlite_compile(db, argv[2], argc==4 ? &zTail : 0, &vm, &zErr);
7597c478bd9Sstevel@tonic-gate   if( argc==4 ) Tcl_SetVar(interp, argv[3], zTail, 0);
7607c478bd9Sstevel@tonic-gate   if( rc ){
7617c478bd9Sstevel@tonic-gate     assert( vm==0 );
7627c478bd9Sstevel@tonic-gate     sprintf(zBuf, "(%d) ", rc);
7637c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, zBuf, zErr, 0);
7647c478bd9Sstevel@tonic-gate     sqlite_freemem(zErr);
7657c478bd9Sstevel@tonic-gate     return TCL_ERROR;
7667c478bd9Sstevel@tonic-gate   }
7677c478bd9Sstevel@tonic-gate   if( vm ){
7687c478bd9Sstevel@tonic-gate     if( makePointerStr(interp, zBuf, vm) ) return TCL_ERROR;
7697c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, zBuf, 0);
7707c478bd9Sstevel@tonic-gate   }
7717c478bd9Sstevel@tonic-gate   return TCL_OK;
7727c478bd9Sstevel@tonic-gate }
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate /*
7757c478bd9Sstevel@tonic-gate ** Usage:  sqlite_step  VM  ?NVAR?  ?VALUEVAR?  ?COLNAMEVAR?
7767c478bd9Sstevel@tonic-gate **
7777c478bd9Sstevel@tonic-gate ** Step a virtual machine.  Return a the result code as a string.
7787c478bd9Sstevel@tonic-gate ** Column results are written into three variables.
7797c478bd9Sstevel@tonic-gate */
test_step(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)7807c478bd9Sstevel@tonic-gate static int test_step(
7817c478bd9Sstevel@tonic-gate   void *NotUsed,
7827c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
7837c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
7847c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
7857c478bd9Sstevel@tonic-gate ){
7867c478bd9Sstevel@tonic-gate   sqlite_vm *vm;
7877c478bd9Sstevel@tonic-gate   int rc, i;
7887c478bd9Sstevel@tonic-gate   const char **azValue = 0;
7897c478bd9Sstevel@tonic-gate   const char **azColName = 0;
7907c478bd9Sstevel@tonic-gate   int N = 0;
7917c478bd9Sstevel@tonic-gate   char *zRc;
7927c478bd9Sstevel@tonic-gate   char zBuf[50];
7937c478bd9Sstevel@tonic-gate   if( argc<2 || argc>5 ){
794*48bbca81SDaniel Hoffman     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
7957c478bd9Sstevel@tonic-gate        " VM NVAR VALUEVAR COLNAMEVAR", 0);
7967c478bd9Sstevel@tonic-gate     return TCL_ERROR;
7977c478bd9Sstevel@tonic-gate   }
7987c478bd9Sstevel@tonic-gate   if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
7997c478bd9Sstevel@tonic-gate   rc = sqlite_step(vm, argc>=3?&N:0, argc>=4?&azValue:0, argc==5?&azColName:0);
8007c478bd9Sstevel@tonic-gate   if( argc>=3 ){
8017c478bd9Sstevel@tonic-gate     sprintf(zBuf, "%d", N);
8027c478bd9Sstevel@tonic-gate     Tcl_SetVar(interp, argv[2], zBuf, 0);
8037c478bd9Sstevel@tonic-gate   }
8047c478bd9Sstevel@tonic-gate   if( argc>=4 ){
8057c478bd9Sstevel@tonic-gate     Tcl_SetVar(interp, argv[3], "", 0);
8067c478bd9Sstevel@tonic-gate     if( azValue ){
8077c478bd9Sstevel@tonic-gate       for(i=0; i<N; i++){
8087c478bd9Sstevel@tonic-gate         Tcl_SetVar(interp, argv[3], azValue[i] ? azValue[i] : "",
8097c478bd9Sstevel@tonic-gate             TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
8107c478bd9Sstevel@tonic-gate       }
8117c478bd9Sstevel@tonic-gate     }
8127c478bd9Sstevel@tonic-gate   }
8137c478bd9Sstevel@tonic-gate   if( argc==5 ){
8147c478bd9Sstevel@tonic-gate     Tcl_SetVar(interp, argv[4], "", 0);
8157c478bd9Sstevel@tonic-gate     if( azColName ){
8167c478bd9Sstevel@tonic-gate       for(i=0; i<N*2; i++){
8177c478bd9Sstevel@tonic-gate         Tcl_SetVar(interp, argv[4], azColName[i] ? azColName[i] : "",
8187c478bd9Sstevel@tonic-gate             TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
8197c478bd9Sstevel@tonic-gate       }
8207c478bd9Sstevel@tonic-gate     }
8217c478bd9Sstevel@tonic-gate   }
8227c478bd9Sstevel@tonic-gate   switch( rc ){
8237c478bd9Sstevel@tonic-gate     case SQLITE_DONE:   zRc = "SQLITE_DONE";    break;
8247c478bd9Sstevel@tonic-gate     case SQLITE_BUSY:   zRc = "SQLITE_BUSY";    break;
8257c478bd9Sstevel@tonic-gate     case SQLITE_ROW:    zRc = "SQLITE_ROW";     break;
8267c478bd9Sstevel@tonic-gate     case SQLITE_ERROR:  zRc = "SQLITE_ERROR";   break;
8277c478bd9Sstevel@tonic-gate     case SQLITE_MISUSE: zRc = "SQLITE_MISUSE";  break;
8287c478bd9Sstevel@tonic-gate     default:            zRc = "unknown";        break;
8297c478bd9Sstevel@tonic-gate   }
8307c478bd9Sstevel@tonic-gate   Tcl_AppendResult(interp, zRc, 0);
8317c478bd9Sstevel@tonic-gate   return TCL_OK;
8327c478bd9Sstevel@tonic-gate }
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate /*
835*48bbca81SDaniel Hoffman ** Usage:  sqlite_finalize  VM
8367c478bd9Sstevel@tonic-gate **
8377c478bd9Sstevel@tonic-gate ** Shutdown a virtual machine.
8387c478bd9Sstevel@tonic-gate */
test_finalize(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)8397c478bd9Sstevel@tonic-gate static int test_finalize(
8407c478bd9Sstevel@tonic-gate   void *NotUsed,
8417c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
8427c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
8437c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
8447c478bd9Sstevel@tonic-gate ){
8457c478bd9Sstevel@tonic-gate   sqlite_vm *vm;
8467c478bd9Sstevel@tonic-gate   int rc;
8477c478bd9Sstevel@tonic-gate   char *zErrMsg = 0;
8487c478bd9Sstevel@tonic-gate   if( argc!=2 ){
849*48bbca81SDaniel Hoffman     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
8507c478bd9Sstevel@tonic-gate        " VM\"", 0);
8517c478bd9Sstevel@tonic-gate     return TCL_ERROR;
8527c478bd9Sstevel@tonic-gate   }
8537c478bd9Sstevel@tonic-gate   if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
8547c478bd9Sstevel@tonic-gate   rc = sqlite_finalize(vm, &zErrMsg);
8557c478bd9Sstevel@tonic-gate   if( rc ){
8567c478bd9Sstevel@tonic-gate     char zBuf[50];
8577c478bd9Sstevel@tonic-gate     sprintf(zBuf, "(%d) ", rc);
8587c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, zBuf, zErrMsg, 0);
8597c478bd9Sstevel@tonic-gate     sqlite_freemem(zErrMsg);
8607c478bd9Sstevel@tonic-gate     return TCL_ERROR;
8617c478bd9Sstevel@tonic-gate   }
8627c478bd9Sstevel@tonic-gate   return TCL_OK;
8637c478bd9Sstevel@tonic-gate }
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate /*
866*48bbca81SDaniel Hoffman ** Usage:  sqlite_reset   VM
8677c478bd9Sstevel@tonic-gate **
8687c478bd9Sstevel@tonic-gate ** Reset a virtual machine and prepare it to be run again.
8697c478bd9Sstevel@tonic-gate */
test_reset(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)8707c478bd9Sstevel@tonic-gate static int test_reset(
8717c478bd9Sstevel@tonic-gate   void *NotUsed,
8727c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
8737c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
8747c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
8757c478bd9Sstevel@tonic-gate ){
8767c478bd9Sstevel@tonic-gate   sqlite_vm *vm;
8777c478bd9Sstevel@tonic-gate   int rc;
8787c478bd9Sstevel@tonic-gate   char *zErrMsg = 0;
8797c478bd9Sstevel@tonic-gate   if( argc!=2 ){
880*48bbca81SDaniel Hoffman     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
8817c478bd9Sstevel@tonic-gate        " VM\"", 0);
8827c478bd9Sstevel@tonic-gate     return TCL_ERROR;
8837c478bd9Sstevel@tonic-gate   }
8847c478bd9Sstevel@tonic-gate   if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
8857c478bd9Sstevel@tonic-gate   rc = sqlite_reset(vm, &zErrMsg);
8867c478bd9Sstevel@tonic-gate   if( rc ){
8877c478bd9Sstevel@tonic-gate     char zBuf[50];
8887c478bd9Sstevel@tonic-gate     sprintf(zBuf, "(%d) ", rc);
8897c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, zBuf, zErrMsg, 0);
8907c478bd9Sstevel@tonic-gate     sqlite_freemem(zErrMsg);
8917c478bd9Sstevel@tonic-gate     return TCL_ERROR;
8927c478bd9Sstevel@tonic-gate   }
8937c478bd9Sstevel@tonic-gate   return TCL_OK;
8947c478bd9Sstevel@tonic-gate }
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate /*
8977c478bd9Sstevel@tonic-gate ** This is the "static_bind_value" that variables are bound to when
8987c478bd9Sstevel@tonic-gate ** the FLAG option of sqlite_bind is "static"
8997c478bd9Sstevel@tonic-gate */
9007c478bd9Sstevel@tonic-gate static char *sqlite_static_bind_value = 0;
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate /*
9037c478bd9Sstevel@tonic-gate ** Usage:  sqlite_bind  VM  IDX  VALUE  FLAGS
9047c478bd9Sstevel@tonic-gate **
9057c478bd9Sstevel@tonic-gate ** Sets the value of the IDX-th occurance of "?" in the original SQL
9067c478bd9Sstevel@tonic-gate ** string.  VALUE is the new value.  If FLAGS=="null" then VALUE is
9077c478bd9Sstevel@tonic-gate ** ignored and the value is set to NULL.  If FLAGS=="static" then
9087c478bd9Sstevel@tonic-gate ** the value is set to the value of a static variable named
9097c478bd9Sstevel@tonic-gate ** "sqlite_static_bind_value".  If FLAGS=="normal" then a copy
9107c478bd9Sstevel@tonic-gate ** of the VALUE is made.
9117c478bd9Sstevel@tonic-gate */
test_bind(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)9127c478bd9Sstevel@tonic-gate static int test_bind(
9137c478bd9Sstevel@tonic-gate   void *NotUsed,
9147c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
9157c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
9167c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
9177c478bd9Sstevel@tonic-gate ){
9187c478bd9Sstevel@tonic-gate   sqlite_vm *vm;
9197c478bd9Sstevel@tonic-gate   int rc;
9207c478bd9Sstevel@tonic-gate   int idx;
9217c478bd9Sstevel@tonic-gate   if( argc!=5 ){
922*48bbca81SDaniel Hoffman     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
9237c478bd9Sstevel@tonic-gate        " VM IDX VALUE (null|static|normal)\"", 0);
9247c478bd9Sstevel@tonic-gate     return TCL_ERROR;
9257c478bd9Sstevel@tonic-gate   }
9267c478bd9Sstevel@tonic-gate   if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR;
9277c478bd9Sstevel@tonic-gate   if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR;
9287c478bd9Sstevel@tonic-gate   if( strcmp(argv[4],"null")==0 ){
9297c478bd9Sstevel@tonic-gate     rc = sqlite_bind(vm, idx, 0, 0, 0);
9307c478bd9Sstevel@tonic-gate   }else if( strcmp(argv[4],"static")==0 ){
9317c478bd9Sstevel@tonic-gate     rc = sqlite_bind(vm, idx, sqlite_static_bind_value, -1, 0);
9327c478bd9Sstevel@tonic-gate   }else if( strcmp(argv[4],"normal")==0 ){
9337c478bd9Sstevel@tonic-gate     rc = sqlite_bind(vm, idx, argv[3], -1, 1);
9347c478bd9Sstevel@tonic-gate   }else{
9357c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, "4th argument should be "
9367c478bd9Sstevel@tonic-gate         "\"null\" or \"static\" or \"normal\"", 0);
9377c478bd9Sstevel@tonic-gate     return TCL_ERROR;
9387c478bd9Sstevel@tonic-gate   }
9397c478bd9Sstevel@tonic-gate   if( rc ){
9407c478bd9Sstevel@tonic-gate     char zBuf[50];
9417c478bd9Sstevel@tonic-gate     sprintf(zBuf, "(%d) ", rc);
9427c478bd9Sstevel@tonic-gate     Tcl_AppendResult(interp, zBuf, sqlite_error_string(rc), 0);
9437c478bd9Sstevel@tonic-gate     return TCL_ERROR;
9447c478bd9Sstevel@tonic-gate   }
9457c478bd9Sstevel@tonic-gate   return TCL_OK;
9467c478bd9Sstevel@tonic-gate }
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate /*
9497c478bd9Sstevel@tonic-gate ** Usage:    breakpoint
9507c478bd9Sstevel@tonic-gate **
9517c478bd9Sstevel@tonic-gate ** This routine exists for one purpose - to provide a place to put a
9527c478bd9Sstevel@tonic-gate ** breakpoint with GDB that can be triggered using TCL code.  The use
9537c478bd9Sstevel@tonic-gate ** for this is when a particular test fails on (say) the 1485th iteration.
9547c478bd9Sstevel@tonic-gate ** In the TCL test script, we can add code like this:
9557c478bd9Sstevel@tonic-gate **
9567c478bd9Sstevel@tonic-gate **     if {$i==1485} breakpoint
9577c478bd9Sstevel@tonic-gate **
9587c478bd9Sstevel@tonic-gate ** Then run testfixture in the debugger and wait for the breakpoint to
9597c478bd9Sstevel@tonic-gate ** fire.  Then additional breakpoints can be set to trace down the bug.
9607c478bd9Sstevel@tonic-gate */
test_breakpoint(void * NotUsed,Tcl_Interp * interp,int argc,char ** argv)9617c478bd9Sstevel@tonic-gate static int test_breakpoint(
9627c478bd9Sstevel@tonic-gate   void *NotUsed,
9637c478bd9Sstevel@tonic-gate   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
9647c478bd9Sstevel@tonic-gate   int argc,              /* Number of arguments */
9657c478bd9Sstevel@tonic-gate   char **argv            /* Text of each argument */
9667c478bd9Sstevel@tonic-gate ){
9677c478bd9Sstevel@tonic-gate   return TCL_OK;         /* Do nothing */
9687c478bd9Sstevel@tonic-gate }
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate /*
9717c478bd9Sstevel@tonic-gate ** Register commands with the TCL interpreter.
9727c478bd9Sstevel@tonic-gate */
Sqlitetest1_Init(Tcl_Interp * interp)9737c478bd9Sstevel@tonic-gate int Sqlitetest1_Init(Tcl_Interp *interp){
9747c478bd9Sstevel@tonic-gate   extern int sqlite_search_count;
9757c478bd9Sstevel@tonic-gate   extern int sqlite_interrupt_count;
9767c478bd9Sstevel@tonic-gate   extern int sqlite_open_file_count;
9777c478bd9Sstevel@tonic-gate   extern int sqlite_current_time;
9787c478bd9Sstevel@tonic-gate   extern int sqlite_temp_directory;
9797c478bd9Sstevel@tonic-gate   static struct {
9807c478bd9Sstevel@tonic-gate      char *zName;
9817c478bd9Sstevel@tonic-gate      Tcl_CmdProc *xProc;
9827c478bd9Sstevel@tonic-gate   } aCmd[] = {
9837c478bd9Sstevel@tonic-gate      { "sqlite_mprintf_int",             (Tcl_CmdProc*)sqlite_mprintf_int    },
9847c478bd9Sstevel@tonic-gate      { "sqlite_mprintf_str",             (Tcl_CmdProc*)sqlite_mprintf_str    },
9857c478bd9Sstevel@tonic-gate      { "sqlite_mprintf_double",          (Tcl_CmdProc*)sqlite_mprintf_double },
9867c478bd9Sstevel@tonic-gate      { "sqlite_mprintf_scaled",          (Tcl_CmdProc*)sqlite_mprintf_scaled },
9877c478bd9Sstevel@tonic-gate      { "sqlite_mprintf_z_test",          (Tcl_CmdProc*)test_mprintf_z        },
9887c478bd9Sstevel@tonic-gate      { "sqlite_open",                    (Tcl_CmdProc*)sqlite_test_open      },
9897c478bd9Sstevel@tonic-gate      { "sqlite_last_insert_rowid",       (Tcl_CmdProc*)test_last_rowid       },
9907c478bd9Sstevel@tonic-gate      { "sqlite_exec_printf",             (Tcl_CmdProc*)test_exec_printf      },
9917c478bd9Sstevel@tonic-gate      { "sqlite_get_table_printf",        (Tcl_CmdProc*)test_get_table_printf },
9927c478bd9Sstevel@tonic-gate      { "sqlite_close",                   (Tcl_CmdProc*)sqlite_test_close     },
9937c478bd9Sstevel@tonic-gate      { "sqlite_create_function",         (Tcl_CmdProc*)test_create_function  },
9947c478bd9Sstevel@tonic-gate      { "sqlite_create_aggregate",        (Tcl_CmdProc*)test_create_aggregate },
9957c478bd9Sstevel@tonic-gate      { "sqlite_register_test_function",  (Tcl_CmdProc*)test_register_func    },
9967c478bd9Sstevel@tonic-gate      { "sqlite_abort",                   (Tcl_CmdProc*)sqlite_abort          },
9977c478bd9Sstevel@tonic-gate      { "sqlite_datatypes",               (Tcl_CmdProc*)sqlite_datatypes      },
9987c478bd9Sstevel@tonic-gate #ifdef MEMORY_DEBUG
9997c478bd9Sstevel@tonic-gate      { "sqlite_malloc_fail",             (Tcl_CmdProc*)sqlite_malloc_fail    },
10007c478bd9Sstevel@tonic-gate      { "sqlite_malloc_stat",             (Tcl_CmdProc*)sqlite_malloc_stat    },
10017c478bd9Sstevel@tonic-gate #endif
10027c478bd9Sstevel@tonic-gate      { "sqlite_compile",                 (Tcl_CmdProc*)test_compile          },
10037c478bd9Sstevel@tonic-gate      { "sqlite_step",                    (Tcl_CmdProc*)test_step             },
10047c478bd9Sstevel@tonic-gate      { "sqlite_finalize",                (Tcl_CmdProc*)test_finalize         },
10057c478bd9Sstevel@tonic-gate      { "sqlite_bind",                    (Tcl_CmdProc*)test_bind             },
10067c478bd9Sstevel@tonic-gate      { "sqlite_reset",                   (Tcl_CmdProc*)test_reset            },
10077c478bd9Sstevel@tonic-gate      { "breakpoint",                     (Tcl_CmdProc*)test_breakpoint       },
10087c478bd9Sstevel@tonic-gate   };
10097c478bd9Sstevel@tonic-gate   int i;
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
10127c478bd9Sstevel@tonic-gate     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
10137c478bd9Sstevel@tonic-gate   }
1014*48bbca81SDaniel Hoffman   Tcl_LinkVar(interp, "sqlite_search_count",
10157c478bd9Sstevel@tonic-gate       (char*)&sqlite_search_count, TCL_LINK_INT);
1016*48bbca81SDaniel Hoffman   Tcl_LinkVar(interp, "sqlite_interrupt_count",
10177c478bd9Sstevel@tonic-gate       (char*)&sqlite_interrupt_count, TCL_LINK_INT);
1018*48bbca81SDaniel Hoffman   Tcl_LinkVar(interp, "sqlite_open_file_count",
10197c478bd9Sstevel@tonic-gate       (char*)&sqlite_open_file_count, TCL_LINK_INT);
1020*48bbca81SDaniel Hoffman   Tcl_LinkVar(interp, "sqlite_current_time",
10217c478bd9Sstevel@tonic-gate       (char*)&sqlite_current_time, TCL_LINK_INT);
10227c478bd9Sstevel@tonic-gate   Tcl_LinkVar(interp, "sqlite_static_bind_value",
10237c478bd9Sstevel@tonic-gate       (char*)&sqlite_static_bind_value, TCL_LINK_STRING);
10247c478bd9Sstevel@tonic-gate   Tcl_LinkVar(interp, "sqlite_temp_directory",
10257c478bd9Sstevel@tonic-gate       (char*)&sqlite_temp_directory, TCL_LINK_STRING);
10267c478bd9Sstevel@tonic-gate   return TCL_OK;
10277c478bd9Sstevel@tonic-gate }
1028