xref: /sqlite-3.40.0/src/tclsqlite.c (revision ef2cb63e)
175897234Sdrh /*
2b19a2bc6Sdrh ** 2001 September 15
375897234Sdrh **
4b19a2bc6Sdrh ** The author disclaims copyright to this source code.  In place of
5b19a2bc6Sdrh ** a legal notice, here is a blessing:
675897234Sdrh **
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.
1075897234Sdrh **
1175897234Sdrh *************************************************************************
1275897234Sdrh ** A TCL Interface to SQLite
1375897234Sdrh **
14*ef2cb63eSdanielk1977 ** $Id: tclsqlite.c,v 1.76 2004/05/29 02:37:19 danielk1977 Exp $
1575897234Sdrh */
166d31316cSdrh #ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */
176d31316cSdrh 
1806b2718aSdrh #include "sqliteInt.h"
1917a68934Sdrh #include "tcl.h"
2075897234Sdrh #include <stdlib.h>
2175897234Sdrh #include <string.h>
22ce927065Sdrh #include <assert.h>
2375897234Sdrh 
2475897234Sdrh /*
2598808babSdrh ** If TCL uses UTF-8 and SQLite is configured to use iso8859, then we
2698808babSdrh ** have to do a translation when going between the two.  Set the
2798808babSdrh ** UTF_TRANSLATION_NEEDED macro to indicate that we need to do
2898808babSdrh ** this translation.
2998808babSdrh */
3098808babSdrh #if defined(TCL_UTF_MAX) && !defined(SQLITE_UTF8)
3198808babSdrh # define UTF_TRANSLATION_NEEDED 1
3298808babSdrh #endif
3398808babSdrh 
3498808babSdrh /*
35cabb0819Sdrh ** New SQL functions can be created as TCL scripts.  Each such function
36cabb0819Sdrh ** is described by an instance of the following structure.
37cabb0819Sdrh */
38cabb0819Sdrh typedef struct SqlFunc SqlFunc;
39cabb0819Sdrh struct SqlFunc {
40cabb0819Sdrh   Tcl_Interp *interp;   /* The TCL interpret to execute the function */
41cabb0819Sdrh   char *zScript;        /* The script to be run */
42cabb0819Sdrh   SqlFunc *pNext;       /* Next function on the list of them all */
43cabb0819Sdrh };
44cabb0819Sdrh 
45cabb0819Sdrh /*
46bec3f402Sdrh ** There is one instance of this structure for each SQLite database
47bec3f402Sdrh ** that has been opened by the SQLite TCL interface.
48bec3f402Sdrh */
49bec3f402Sdrh typedef struct SqliteDb SqliteDb;
50bec3f402Sdrh struct SqliteDb {
51bec3f402Sdrh   sqlite *db;           /* The "real" database structure */
52bec3f402Sdrh   Tcl_Interp *interp;   /* The interpreter used for this database */
536d31316cSdrh   char *zBusy;          /* The busy callback routine */
54aa940eacSdrh   char *zCommit;        /* The commit hook callback routine */
55b5a20d3cSdrh   char *zTrace;         /* The trace callback routine */
56348bb5d6Sdanielk1977   char *zProgress;      /* The progress callback routine */
57e22a334bSdrh   char *zAuth;          /* The authorization callback routine */
58cabb0819Sdrh   SqlFunc *pFunc;       /* List of SQL functions */
596f8a503dSdanielk1977   int rc;               /* Return code of most recent sqlite3_exec() */
6030ccda10Sdanielk1977   int nChange;         /* Database changes for the most recent eval */
61bec3f402Sdrh };
62bec3f402Sdrh 
63bec3f402Sdrh /*
6475897234Sdrh ** An instance of this structure passes information thru the sqlite
6575897234Sdrh ** logic from the original TCL command into the callback routine.
6675897234Sdrh */
6775897234Sdrh typedef struct CallbackData CallbackData;
6875897234Sdrh struct CallbackData {
6975897234Sdrh   Tcl_Interp *interp;       /* The TCL interpreter */
7075897234Sdrh   char *zArray;             /* The array into which data is written */
716d31316cSdrh   Tcl_Obj *pCode;           /* The code to execute for each row */
72ce927065Sdrh   int once;                 /* Set for first callback only */
73960e8c63Sdrh   int tcl_rc;               /* Return code from TCL script */
7498808babSdrh   int nColName;             /* Number of entries in the azColName[] array */
7598808babSdrh   char **azColName;         /* Column names translated to UTF-8 */
7698808babSdrh };
77297ecf14Sdrh 
786d31316cSdrh /*
795d9d7576Sdrh ** This is a second alternative callback for database queries.  A the
805d9d7576Sdrh ** first column of the first row of the result is made the TCL result.
815d9d7576Sdrh */
825d9d7576Sdrh static int DbEvalCallback3(
835d9d7576Sdrh   void *clientData,      /* An instance of CallbackData */
845d9d7576Sdrh   int nCol,              /* Number of columns in the result */
855d9d7576Sdrh   char ** azCol,         /* Data for each column */
865d9d7576Sdrh   char ** azN            /* Name for each column */
875d9d7576Sdrh ){
885d9d7576Sdrh   Tcl_Interp *interp = (Tcl_Interp*)clientData;
895d9d7576Sdrh   Tcl_Obj *pElem;
905d9d7576Sdrh   if( azCol==0 ) return 1;
915d9d7576Sdrh   if( nCol==0 ) return 1;
925d9d7576Sdrh #ifdef UTF_TRANSLATION_NEEDED
935d9d7576Sdrh   {
945d9d7576Sdrh     Tcl_DString dCol;
955d9d7576Sdrh     Tcl_DStringInit(&dCol);
965d9d7576Sdrh     Tcl_ExternalToUtfDString(NULL, azCol[0], -1, &dCol);
975d9d7576Sdrh     pElem = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1);
985d9d7576Sdrh     Tcl_DStringFree(&dCol);
995d9d7576Sdrh   }
1005d9d7576Sdrh #else
1015d9d7576Sdrh   pElem = Tcl_NewStringObj(azCol[0], -1);
1025d9d7576Sdrh #endif
1035d9d7576Sdrh   Tcl_SetObjResult(interp, pElem);
1045d9d7576Sdrh   return 1;
1055d9d7576Sdrh }
1065d9d7576Sdrh 
1075d9d7576Sdrh /*
10875897234Sdrh ** Called when the command is deleted.
10975897234Sdrh */
11075897234Sdrh static void DbDeleteCmd(void *db){
111bec3f402Sdrh   SqliteDb *pDb = (SqliteDb*)db;
1126f8a503dSdanielk1977   sqlite3_close(pDb->db);
113cabb0819Sdrh   while( pDb->pFunc ){
114cabb0819Sdrh     SqlFunc *pFunc = pDb->pFunc;
115cabb0819Sdrh     pDb->pFunc = pFunc->pNext;
116cabb0819Sdrh     Tcl_Free((char*)pFunc);
117cabb0819Sdrh   }
118bec3f402Sdrh   if( pDb->zBusy ){
119bec3f402Sdrh     Tcl_Free(pDb->zBusy);
120bec3f402Sdrh   }
121b5a20d3cSdrh   if( pDb->zTrace ){
122b5a20d3cSdrh     Tcl_Free(pDb->zTrace);
1230d1a643aSdrh   }
124e22a334bSdrh   if( pDb->zAuth ){
125e22a334bSdrh     Tcl_Free(pDb->zAuth);
126e22a334bSdrh   }
127bec3f402Sdrh   Tcl_Free((char*)pDb);
128bec3f402Sdrh }
129bec3f402Sdrh 
130bec3f402Sdrh /*
131bec3f402Sdrh ** This routine is called when a database file is locked while trying
132bec3f402Sdrh ** to execute SQL.
133bec3f402Sdrh */
134bec3f402Sdrh static int DbBusyHandler(void *cd, const char *zTable, int nTries){
135bec3f402Sdrh   SqliteDb *pDb = (SqliteDb*)cd;
136bec3f402Sdrh   int rc;
137bec3f402Sdrh   char zVal[30];
138bec3f402Sdrh   char *zCmd;
139bec3f402Sdrh   Tcl_DString cmd;
140bec3f402Sdrh 
141bec3f402Sdrh   Tcl_DStringInit(&cmd);
142bec3f402Sdrh   Tcl_DStringAppend(&cmd, pDb->zBusy, -1);
143bec3f402Sdrh   Tcl_DStringAppendElement(&cmd, zTable);
144bec3f402Sdrh   sprintf(zVal, " %d", nTries);
145bec3f402Sdrh   Tcl_DStringAppend(&cmd, zVal, -1);
146bec3f402Sdrh   zCmd = Tcl_DStringValue(&cmd);
147bec3f402Sdrh   rc = Tcl_Eval(pDb->interp, zCmd);
148bec3f402Sdrh   Tcl_DStringFree(&cmd);
149bec3f402Sdrh   if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
150bec3f402Sdrh     return 0;
151bec3f402Sdrh   }
152bec3f402Sdrh   return 1;
15375897234Sdrh }
15475897234Sdrh 
15575897234Sdrh /*
156348bb5d6Sdanielk1977 ** This routine is invoked as the 'progress callback' for the database.
157348bb5d6Sdanielk1977 */
158348bb5d6Sdanielk1977 static int DbProgressHandler(void *cd){
159348bb5d6Sdanielk1977   SqliteDb *pDb = (SqliteDb*)cd;
160348bb5d6Sdanielk1977   int rc;
161348bb5d6Sdanielk1977 
162348bb5d6Sdanielk1977   assert( pDb->zProgress );
163348bb5d6Sdanielk1977   rc = Tcl_Eval(pDb->interp, pDb->zProgress);
164348bb5d6Sdanielk1977   if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
165348bb5d6Sdanielk1977     return 1;
166348bb5d6Sdanielk1977   }
167348bb5d6Sdanielk1977   return 0;
168348bb5d6Sdanielk1977 }
169348bb5d6Sdanielk1977 
170348bb5d6Sdanielk1977 /*
171b5a20d3cSdrh ** This routine is called by the SQLite trace handler whenever a new
172b5a20d3cSdrh ** block of SQL is executed.  The TCL script in pDb->zTrace is executed.
1730d1a643aSdrh */
174b5a20d3cSdrh static void DbTraceHandler(void *cd, const char *zSql){
1750d1a643aSdrh   SqliteDb *pDb = (SqliteDb*)cd;
176b5a20d3cSdrh   Tcl_DString str;
1770d1a643aSdrh 
178b5a20d3cSdrh   Tcl_DStringInit(&str);
179b5a20d3cSdrh   Tcl_DStringAppend(&str, pDb->zTrace, -1);
180b5a20d3cSdrh   Tcl_DStringAppendElement(&str, zSql);
181b5a20d3cSdrh   Tcl_Eval(pDb->interp, Tcl_DStringValue(&str));
182b5a20d3cSdrh   Tcl_DStringFree(&str);
183b5a20d3cSdrh   Tcl_ResetResult(pDb->interp);
1840d1a643aSdrh }
1850d1a643aSdrh 
1860d1a643aSdrh /*
187aa940eacSdrh ** This routine is called when a transaction is committed.  The
188aa940eacSdrh ** TCL script in pDb->zCommit is executed.  If it returns non-zero or
189aa940eacSdrh ** if it throws an exception, the transaction is rolled back instead
190aa940eacSdrh ** of being committed.
191aa940eacSdrh */
192aa940eacSdrh static int DbCommitHandler(void *cd){
193aa940eacSdrh   SqliteDb *pDb = (SqliteDb*)cd;
194aa940eacSdrh   int rc;
195aa940eacSdrh 
196aa940eacSdrh   rc = Tcl_Eval(pDb->interp, pDb->zCommit);
197aa940eacSdrh   if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
198aa940eacSdrh     return 1;
199aa940eacSdrh   }
200aa940eacSdrh   return 0;
201aa940eacSdrh }
202aa940eacSdrh 
203aa940eacSdrh /*
204cabb0819Sdrh ** This routine is called to evaluate an SQL function implemented
205cabb0819Sdrh ** using TCL script.
206cabb0819Sdrh */
2070ae8b831Sdanielk1977 static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
2086f8a503dSdanielk1977   SqlFunc *p = sqlite3_user_data(context);
209cabb0819Sdrh   Tcl_DString cmd;
210cabb0819Sdrh   int i;
211cabb0819Sdrh   int rc;
212cabb0819Sdrh 
213cabb0819Sdrh   Tcl_DStringInit(&cmd);
214cabb0819Sdrh   Tcl_DStringAppend(&cmd, p->zScript, -1);
215cabb0819Sdrh   for(i=0; i<argc; i++){
21651ad0ecdSdanielk1977     if( SQLITE3_NULL==sqlite3_value_type(argv[i]) ){
21751ad0ecdSdanielk1977       Tcl_DStringAppendElement(&cmd, "");
21851ad0ecdSdanielk1977     }else{
2194f26d6c4Sdrh       Tcl_DStringAppendElement(&cmd, sqlite3_value_text(argv[i]));
22051ad0ecdSdanielk1977     }
221cabb0819Sdrh   }
222cabb0819Sdrh   rc = Tcl_Eval(p->interp, Tcl_DStringValue(&cmd));
223cabb0819Sdrh   if( rc ){
2247e18c259Sdanielk1977     sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
225cabb0819Sdrh   }else{
2267e18c259Sdanielk1977     sqlite3_result_text(context, Tcl_GetStringResult(p->interp), -1, 1);
227cabb0819Sdrh   }
228cabb0819Sdrh }
229e22a334bSdrh #ifndef SQLITE_OMIT_AUTHORIZATION
230e22a334bSdrh /*
231e22a334bSdrh ** This is the authentication function.  It appends the authentication
232e22a334bSdrh ** type code and the two arguments to zCmd[] then invokes the result
233e22a334bSdrh ** on the interpreter.  The reply is examined to determine if the
234e22a334bSdrh ** authentication fails or succeeds.
235e22a334bSdrh */
236e22a334bSdrh static int auth_callback(
237e22a334bSdrh   void *pArg,
238e22a334bSdrh   int code,
239e22a334bSdrh   const char *zArg1,
240e22a334bSdrh   const char *zArg2,
241e22a334bSdrh   const char *zArg3,
242e22a334bSdrh   const char *zArg4
243e22a334bSdrh ){
244e22a334bSdrh   char *zCode;
245e22a334bSdrh   Tcl_DString str;
246e22a334bSdrh   int rc;
247e22a334bSdrh   const char *zReply;
248e22a334bSdrh   SqliteDb *pDb = (SqliteDb*)pArg;
249e22a334bSdrh 
250e22a334bSdrh   switch( code ){
251e22a334bSdrh     case SQLITE_COPY              : zCode="SQLITE_COPY"; break;
252e22a334bSdrh     case SQLITE_CREATE_INDEX      : zCode="SQLITE_CREATE_INDEX"; break;
253e22a334bSdrh     case SQLITE_CREATE_TABLE      : zCode="SQLITE_CREATE_TABLE"; break;
254e22a334bSdrh     case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break;
255e22a334bSdrh     case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break;
256e22a334bSdrh     case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break;
257e22a334bSdrh     case SQLITE_CREATE_TEMP_VIEW  : zCode="SQLITE_CREATE_TEMP_VIEW"; break;
258e22a334bSdrh     case SQLITE_CREATE_TRIGGER    : zCode="SQLITE_CREATE_TRIGGER"; break;
259e22a334bSdrh     case SQLITE_CREATE_VIEW       : zCode="SQLITE_CREATE_VIEW"; break;
260e22a334bSdrh     case SQLITE_DELETE            : zCode="SQLITE_DELETE"; break;
261e22a334bSdrh     case SQLITE_DROP_INDEX        : zCode="SQLITE_DROP_INDEX"; break;
262e22a334bSdrh     case SQLITE_DROP_TABLE        : zCode="SQLITE_DROP_TABLE"; break;
263e22a334bSdrh     case SQLITE_DROP_TEMP_INDEX   : zCode="SQLITE_DROP_TEMP_INDEX"; break;
264e22a334bSdrh     case SQLITE_DROP_TEMP_TABLE   : zCode="SQLITE_DROP_TEMP_TABLE"; break;
265e22a334bSdrh     case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break;
266e22a334bSdrh     case SQLITE_DROP_TEMP_VIEW    : zCode="SQLITE_DROP_TEMP_VIEW"; break;
267e22a334bSdrh     case SQLITE_DROP_TRIGGER      : zCode="SQLITE_DROP_TRIGGER"; break;
268e22a334bSdrh     case SQLITE_DROP_VIEW         : zCode="SQLITE_DROP_VIEW"; break;
269e22a334bSdrh     case SQLITE_INSERT            : zCode="SQLITE_INSERT"; break;
270e22a334bSdrh     case SQLITE_PRAGMA            : zCode="SQLITE_PRAGMA"; break;
271e22a334bSdrh     case SQLITE_READ              : zCode="SQLITE_READ"; break;
272e22a334bSdrh     case SQLITE_SELECT            : zCode="SQLITE_SELECT"; break;
273e22a334bSdrh     case SQLITE_TRANSACTION       : zCode="SQLITE_TRANSACTION"; break;
274e22a334bSdrh     case SQLITE_UPDATE            : zCode="SQLITE_UPDATE"; break;
27581e293b4Sdrh     case SQLITE_ATTACH            : zCode="SQLITE_ATTACH"; break;
27681e293b4Sdrh     case SQLITE_DETACH            : zCode="SQLITE_DETACH"; break;
277e22a334bSdrh     default                       : zCode="????"; break;
278e22a334bSdrh   }
279e22a334bSdrh   Tcl_DStringInit(&str);
280e22a334bSdrh   Tcl_DStringAppend(&str, pDb->zAuth, -1);
281e22a334bSdrh   Tcl_DStringAppendElement(&str, zCode);
282e22a334bSdrh   Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : "");
283e22a334bSdrh   Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : "");
284e22a334bSdrh   Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : "");
285e22a334bSdrh   Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : "");
286e22a334bSdrh   rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str));
287e22a334bSdrh   Tcl_DStringFree(&str);
288e22a334bSdrh   zReply = Tcl_GetStringResult(pDb->interp);
289e22a334bSdrh   if( strcmp(zReply,"SQLITE_OK")==0 ){
290e22a334bSdrh     rc = SQLITE_OK;
291e22a334bSdrh   }else if( strcmp(zReply,"SQLITE_DENY")==0 ){
292e22a334bSdrh     rc = SQLITE_DENY;
293e22a334bSdrh   }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){
294e22a334bSdrh     rc = SQLITE_IGNORE;
295e22a334bSdrh   }else{
296e22a334bSdrh     rc = 999;
297e22a334bSdrh   }
298e22a334bSdrh   return rc;
299e22a334bSdrh }
300e22a334bSdrh #endif /* SQLITE_OMIT_AUTHORIZATION */
301cabb0819Sdrh 
302cabb0819Sdrh /*
303*ef2cb63eSdanielk1977 ** zText is a pointer to text obtained via an sqlite3_result_text()
304*ef2cb63eSdanielk1977 ** or similar interface. This routine returns a Tcl string object,
305*ef2cb63eSdanielk1977 ** reference count set to 0, containing the text. If a translation
306*ef2cb63eSdanielk1977 ** between iso8859 and UTF-8 is required, it is preformed.
307*ef2cb63eSdanielk1977 */
308*ef2cb63eSdanielk1977 static Tcl_Obj *dbTextToObj(char const *zText){
309*ef2cb63eSdanielk1977   Tcl_Obj *pVal;
310*ef2cb63eSdanielk1977 #ifdef UTF_TRANSLATION_NEEDED
311*ef2cb63eSdanielk1977   Tcl_DString dCol;
312*ef2cb63eSdanielk1977   Tcl_DStringInit(&dCol);
313*ef2cb63eSdanielk1977   Tcl_ExternalToUtfDString(NULL, zText, -1, &dCol);
314*ef2cb63eSdanielk1977   pVal = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1);
315*ef2cb63eSdanielk1977   Tcl_DStringFree(&dCol);
316*ef2cb63eSdanielk1977 #else
317*ef2cb63eSdanielk1977   pVal = Tcl_NewStringObj(zText, -1);
318*ef2cb63eSdanielk1977 #endif
319*ef2cb63eSdanielk1977   return pVal;
320*ef2cb63eSdanielk1977 }
321*ef2cb63eSdanielk1977 
322*ef2cb63eSdanielk1977 /*
32375897234Sdrh ** The "sqlite" command below creates a new Tcl command for each
32475897234Sdrh ** connection it opens to an SQLite database.  This routine is invoked
32575897234Sdrh ** whenever one of those connection-specific commands is executed
32675897234Sdrh ** in Tcl.  For example, if you run Tcl code like this:
32775897234Sdrh **
32875897234Sdrh **       sqlite db1  "my_database"
32975897234Sdrh **       db1 close
33075897234Sdrh **
33175897234Sdrh ** The first command opens a connection to the "my_database" database
33275897234Sdrh ** and calls that connection "db1".  The second command causes this
33375897234Sdrh ** subroutine to be invoked.
33475897234Sdrh */
3356d31316cSdrh static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
336bec3f402Sdrh   SqliteDb *pDb = (SqliteDb*)cd;
3376d31316cSdrh   int choice;
33822fbcb8dSdrh   int rc = TCL_OK;
3390de8c112Sdrh   static const char *DB_strs[] = {
340b5a20d3cSdrh     "authorizer",         "busy",                   "changes",
341aa940eacSdrh     "close",              "commit_hook",            "complete",
342aa940eacSdrh     "errorcode",          "eval",                   "function",
343f146a776Srdc     "last_insert_rowid",  "last_statement_changes", "onecolumn",
344f146a776Srdc     "progress",           "rekey",                  "timeout",
345f146a776Srdc     "trace",
34622fbcb8dSdrh     0
3476d31316cSdrh   };
348411995dcSdrh   enum DB_enum {
349b5a20d3cSdrh     DB_AUTHORIZER,        DB_BUSY,                   DB_CHANGES,
350aa940eacSdrh     DB_CLOSE,             DB_COMMIT_HOOK,            DB_COMPLETE,
351aa940eacSdrh     DB_ERRORCODE,         DB_EVAL,                   DB_FUNCTION,
352f146a776Srdc     DB_LAST_INSERT_ROWID, DB_LAST_STATEMENT_CHANGES, DB_ONECOLUMN,
353f146a776Srdc     DB_PROGRESS,          DB_REKEY,                  DB_TIMEOUT,
354f146a776Srdc     DB_TRACE
3556d31316cSdrh   };
3566d31316cSdrh 
3576d31316cSdrh   if( objc<2 ){
3586d31316cSdrh     Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
35975897234Sdrh     return TCL_ERROR;
36075897234Sdrh   }
361411995dcSdrh   if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){
3626d31316cSdrh     return TCL_ERROR;
3636d31316cSdrh   }
3646d31316cSdrh 
365411995dcSdrh   switch( (enum DB_enum)choice ){
36675897234Sdrh 
367e22a334bSdrh   /*    $db authorizer ?CALLBACK?
368e22a334bSdrh   **
369e22a334bSdrh   ** Invoke the given callback to authorize each SQL operation as it is
370e22a334bSdrh   ** compiled.  5 arguments are appended to the callback before it is
371e22a334bSdrh   ** invoked:
372e22a334bSdrh   **
373e22a334bSdrh   **   (1) The authorization type (ex: SQLITE_CREATE_TABLE, SQLITE_INSERT, ...)
374e22a334bSdrh   **   (2) First descriptive name (depends on authorization type)
375e22a334bSdrh   **   (3) Second descriptive name
376e22a334bSdrh   **   (4) Name of the database (ex: "main", "temp")
377e22a334bSdrh   **   (5) Name of trigger that is doing the access
378e22a334bSdrh   **
379e22a334bSdrh   ** The callback should return on of the following strings: SQLITE_OK,
380e22a334bSdrh   ** SQLITE_IGNORE, or SQLITE_DENY.  Any other return value is an error.
381e22a334bSdrh   **
382e22a334bSdrh   ** If this method is invoked with no arguments, the current authorization
383e22a334bSdrh   ** callback string is returned.
384e22a334bSdrh   */
385e22a334bSdrh   case DB_AUTHORIZER: {
386e22a334bSdrh     if( objc>3 ){
387e22a334bSdrh       Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
388e22a334bSdrh     }else if( objc==2 ){
389b5a20d3cSdrh       if( pDb->zAuth ){
390e22a334bSdrh         Tcl_AppendResult(interp, pDb->zAuth, 0);
391e22a334bSdrh       }
392e22a334bSdrh     }else{
393e22a334bSdrh       char *zAuth;
394e22a334bSdrh       int len;
395e22a334bSdrh       if( pDb->zAuth ){
396e22a334bSdrh         Tcl_Free(pDb->zAuth);
397e22a334bSdrh       }
398e22a334bSdrh       zAuth = Tcl_GetStringFromObj(objv[2], &len);
399e22a334bSdrh       if( zAuth && len>0 ){
400e22a334bSdrh         pDb->zAuth = Tcl_Alloc( len + 1 );
401e22a334bSdrh         strcpy(pDb->zAuth, zAuth);
402e22a334bSdrh       }else{
403e22a334bSdrh         pDb->zAuth = 0;
404e22a334bSdrh       }
405e22a334bSdrh #ifndef SQLITE_OMIT_AUTHORIZATION
406e22a334bSdrh       if( pDb->zAuth ){
407e22a334bSdrh         pDb->interp = interp;
4086f8a503dSdanielk1977         sqlite3_set_authorizer(pDb->db, auth_callback, pDb);
409e22a334bSdrh       }else{
4106f8a503dSdanielk1977         sqlite3_set_authorizer(pDb->db, 0, 0);
411e22a334bSdrh       }
412e22a334bSdrh #endif
413e22a334bSdrh     }
414e22a334bSdrh     break;
415e22a334bSdrh   }
416e22a334bSdrh 
417bec3f402Sdrh   /*    $db busy ?CALLBACK?
418bec3f402Sdrh   **
419bec3f402Sdrh   ** Invoke the given callback if an SQL statement attempts to open
420bec3f402Sdrh   ** a locked database file.
421bec3f402Sdrh   */
4226d31316cSdrh   case DB_BUSY: {
4236d31316cSdrh     if( objc>3 ){
4246d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "CALLBACK");
425bec3f402Sdrh       return TCL_ERROR;
4266d31316cSdrh     }else if( objc==2 ){
427bec3f402Sdrh       if( pDb->zBusy ){
428bec3f402Sdrh         Tcl_AppendResult(interp, pDb->zBusy, 0);
429bec3f402Sdrh       }
430bec3f402Sdrh     }else{
4316d31316cSdrh       char *zBusy;
4326d31316cSdrh       int len;
433bec3f402Sdrh       if( pDb->zBusy ){
434bec3f402Sdrh         Tcl_Free(pDb->zBusy);
4356d31316cSdrh       }
4366d31316cSdrh       zBusy = Tcl_GetStringFromObj(objv[2], &len);
4376d31316cSdrh       if( zBusy && len>0 ){
4386d31316cSdrh         pDb->zBusy = Tcl_Alloc( len + 1 );
4396d31316cSdrh         strcpy(pDb->zBusy, zBusy);
4406d31316cSdrh       }else{
441bec3f402Sdrh         pDb->zBusy = 0;
442bec3f402Sdrh       }
443bec3f402Sdrh       if( pDb->zBusy ){
444bec3f402Sdrh         pDb->interp = interp;
4456f8a503dSdanielk1977         sqlite3_busy_handler(pDb->db, DbBusyHandler, pDb);
4466d31316cSdrh       }else{
4476f8a503dSdanielk1977         sqlite3_busy_handler(pDb->db, 0, 0);
448bec3f402Sdrh       }
449bec3f402Sdrh     }
4506d31316cSdrh     break;
4516d31316cSdrh   }
452bec3f402Sdrh 
453348bb5d6Sdanielk1977   /*    $db progress ?N CALLBACK?
454348bb5d6Sdanielk1977   **
455348bb5d6Sdanielk1977   ** Invoke the given callback every N virtual machine opcodes while executing
456348bb5d6Sdanielk1977   ** queries.
457348bb5d6Sdanielk1977   */
458348bb5d6Sdanielk1977   case DB_PROGRESS: {
459348bb5d6Sdanielk1977     if( objc==2 ){
460348bb5d6Sdanielk1977       if( pDb->zProgress ){
461348bb5d6Sdanielk1977         Tcl_AppendResult(interp, pDb->zProgress, 0);
462348bb5d6Sdanielk1977       }
463348bb5d6Sdanielk1977     }else if( objc==4 ){
464348bb5d6Sdanielk1977       char *zProgress;
465348bb5d6Sdanielk1977       int len;
466348bb5d6Sdanielk1977       int N;
467348bb5d6Sdanielk1977       if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){
468348bb5d6Sdanielk1977 	return TCL_ERROR;
469348bb5d6Sdanielk1977       };
470348bb5d6Sdanielk1977       if( pDb->zProgress ){
471348bb5d6Sdanielk1977         Tcl_Free(pDb->zProgress);
472348bb5d6Sdanielk1977       }
473348bb5d6Sdanielk1977       zProgress = Tcl_GetStringFromObj(objv[3], &len);
474348bb5d6Sdanielk1977       if( zProgress && len>0 ){
475348bb5d6Sdanielk1977         pDb->zProgress = Tcl_Alloc( len + 1 );
476348bb5d6Sdanielk1977         strcpy(pDb->zProgress, zProgress);
477348bb5d6Sdanielk1977       }else{
478348bb5d6Sdanielk1977         pDb->zProgress = 0;
479348bb5d6Sdanielk1977       }
480348bb5d6Sdanielk1977 #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
481348bb5d6Sdanielk1977       if( pDb->zProgress ){
482348bb5d6Sdanielk1977         pDb->interp = interp;
4836f8a503dSdanielk1977         sqlite3_progress_handler(pDb->db, N, DbProgressHandler, pDb);
484348bb5d6Sdanielk1977       }else{
4856f8a503dSdanielk1977         sqlite3_progress_handler(pDb->db, 0, 0, 0);
486348bb5d6Sdanielk1977       }
487348bb5d6Sdanielk1977 #endif
488348bb5d6Sdanielk1977     }else{
489348bb5d6Sdanielk1977       Tcl_WrongNumArgs(interp, 2, objv, "N CALLBACK");
490348bb5d6Sdanielk1977       return TCL_ERROR;
491348bb5d6Sdanielk1977     }
492348bb5d6Sdanielk1977     break;
493348bb5d6Sdanielk1977   }
494348bb5d6Sdanielk1977 
495c8d30ac1Sdrh   /*
496c8d30ac1Sdrh   **     $db changes
497c8d30ac1Sdrh   **
498c8d30ac1Sdrh   ** Return the number of rows that were modified, inserted, or deleted by
499c8d30ac1Sdrh   ** the most recent "eval".
500c8d30ac1Sdrh   */
501c8d30ac1Sdrh   case DB_CHANGES: {
502c8d30ac1Sdrh     Tcl_Obj *pResult;
503c8d30ac1Sdrh     int nChange;
504c8d30ac1Sdrh     if( objc!=2 ){
505c8d30ac1Sdrh       Tcl_WrongNumArgs(interp, 2, objv, "");
506c8d30ac1Sdrh       return TCL_ERROR;
507c8d30ac1Sdrh     }
50830ccda10Sdanielk1977     /* nChange = sqlite3_changes(pDb->db); */
50930ccda10Sdanielk1977     nChange = pDb->nChange;
510c8d30ac1Sdrh     pResult = Tcl_GetObjResult(interp);
511c8d30ac1Sdrh     Tcl_SetIntObj(pResult, nChange);
512c8d30ac1Sdrh     break;
513c8d30ac1Sdrh   }
514c8d30ac1Sdrh 
515f146a776Srdc   /*
516f146a776Srdc   **     $db last_statement_changes
517f146a776Srdc   **
518f146a776Srdc   ** Return the number of rows that were modified, inserted, or deleted by
519f146a776Srdc   ** the last statment to complete execution (excluding changes due to
520f146a776Srdc   ** triggers)
521f146a776Srdc   */
522f146a776Srdc   case DB_LAST_STATEMENT_CHANGES: {
523f146a776Srdc     Tcl_Obj *pResult;
524f146a776Srdc     int lsChange;
525f146a776Srdc     if( objc!=2 ){
526f146a776Srdc       Tcl_WrongNumArgs(interp, 2, objv, "");
527f146a776Srdc       return TCL_ERROR;
528f146a776Srdc     }
5296f8a503dSdanielk1977     lsChange = sqlite3_last_statement_changes(pDb->db);
530f146a776Srdc     pResult = Tcl_GetObjResult(interp);
531f146a776Srdc     Tcl_SetIntObj(pResult, lsChange);
532f146a776Srdc     break;
533f146a776Srdc   }
534f146a776Srdc 
53575897234Sdrh   /*    $db close
53675897234Sdrh   **
53775897234Sdrh   ** Shutdown the database
53875897234Sdrh   */
5396d31316cSdrh   case DB_CLOSE: {
5406d31316cSdrh     Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0));
5416d31316cSdrh     break;
5426d31316cSdrh   }
54375897234Sdrh 
544aa940eacSdrh   /*    $db commit_hook ?CALLBACK?
545aa940eacSdrh   **
546aa940eacSdrh   ** Invoke the given callback just before committing every SQL transaction.
547aa940eacSdrh   ** If the callback throws an exception or returns non-zero, then the
548aa940eacSdrh   ** transaction is aborted.  If CALLBACK is an empty string, the callback
549aa940eacSdrh   ** is disabled.
550aa940eacSdrh   */
551aa940eacSdrh   case DB_COMMIT_HOOK: {
552aa940eacSdrh     if( objc>3 ){
553aa940eacSdrh       Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
554aa940eacSdrh     }else if( objc==2 ){
555aa940eacSdrh       if( pDb->zCommit ){
556aa940eacSdrh         Tcl_AppendResult(interp, pDb->zCommit, 0);
557aa940eacSdrh       }
558aa940eacSdrh     }else{
559aa940eacSdrh       char *zCommit;
560aa940eacSdrh       int len;
561aa940eacSdrh       if( pDb->zCommit ){
562aa940eacSdrh         Tcl_Free(pDb->zCommit);
563aa940eacSdrh       }
564aa940eacSdrh       zCommit = Tcl_GetStringFromObj(objv[2], &len);
565aa940eacSdrh       if( zCommit && len>0 ){
566aa940eacSdrh         pDb->zCommit = Tcl_Alloc( len + 1 );
567aa940eacSdrh         strcpy(pDb->zCommit, zCommit);
568aa940eacSdrh       }else{
569aa940eacSdrh         pDb->zCommit = 0;
570aa940eacSdrh       }
571aa940eacSdrh       if( pDb->zCommit ){
572aa940eacSdrh         pDb->interp = interp;
5736f8a503dSdanielk1977         sqlite3_commit_hook(pDb->db, DbCommitHandler, pDb);
574aa940eacSdrh       }else{
5756f8a503dSdanielk1977         sqlite3_commit_hook(pDb->db, 0, 0);
576aa940eacSdrh       }
577aa940eacSdrh     }
578aa940eacSdrh     break;
579aa940eacSdrh   }
580aa940eacSdrh 
58175897234Sdrh   /*    $db complete SQL
58275897234Sdrh   **
58375897234Sdrh   ** Return TRUE if SQL is a complete SQL statement.  Return FALSE if
58475897234Sdrh   ** additional lines of input are needed.  This is similar to the
58575897234Sdrh   ** built-in "info complete" command of Tcl.
58675897234Sdrh   */
5876d31316cSdrh   case DB_COMPLETE: {
5886d31316cSdrh     Tcl_Obj *pResult;
5896d31316cSdrh     int isComplete;
5906d31316cSdrh     if( objc!=3 ){
5916d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "SQL");
59275897234Sdrh       return TCL_ERROR;
59375897234Sdrh     }
5946f8a503dSdanielk1977     isComplete = sqlite3_complete( Tcl_GetStringFromObj(objv[2], 0) );
5956d31316cSdrh     pResult = Tcl_GetObjResult(interp);
5966d31316cSdrh     Tcl_SetBooleanObj(pResult, isComplete);
5976d31316cSdrh     break;
5986d31316cSdrh   }
59975897234Sdrh 
60075897234Sdrh   /*
601dcd997eaSdrh   **    $db errorcode
602dcd997eaSdrh   **
603dcd997eaSdrh   ** Return the numeric error code that was returned by the most recent
6046f8a503dSdanielk1977   ** call to sqlite3_exec().
605dcd997eaSdrh   */
606dcd997eaSdrh   case DB_ERRORCODE: {
607dcd997eaSdrh     Tcl_SetObjResult(interp, Tcl_NewIntObj(pDb->rc));
608dcd997eaSdrh     break;
609dcd997eaSdrh   }
610dcd997eaSdrh 
611dcd997eaSdrh   /*
61275897234Sdrh   **    $db eval $sql ?array {  ...code... }?
61375897234Sdrh   **
61475897234Sdrh   ** The SQL statement in $sql is evaluated.  For each row, the values are
615bec3f402Sdrh   ** placed in elements of the array named "array" and ...code... is executed.
61675897234Sdrh   ** If "array" and "code" are omitted, then no callback is every invoked.
61775897234Sdrh   ** If "array" is an empty string, then the values are placed in variables
61875897234Sdrh   ** that have the same name as the fields extracted by the query.
61975897234Sdrh   */
6206d31316cSdrh   case DB_EVAL: {
62130ccda10Sdanielk1977     char const *zSql;
62230ccda10Sdanielk1977     char const *zLeft;
62330ccda10Sdanielk1977     sqlite3_stmt *pStmt;
624*ef2cb63eSdanielk1977 
625*ef2cb63eSdanielk1977     Tcl_Obj *pRet = Tcl_NewObj();
626*ef2cb63eSdanielk1977     Tcl_IncrRefCount(pRet);
62730ccda10Sdanielk1977 
62830ccda10Sdanielk1977     if( objc!=5 && objc!=3 ){
62930ccda10Sdanielk1977       Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME CODE?");
63030ccda10Sdanielk1977       return TCL_ERROR;
63130ccda10Sdanielk1977     }
63230ccda10Sdanielk1977 
63330ccda10Sdanielk1977     pDb->nChange = 0;
63430ccda10Sdanielk1977     zSql = Tcl_GetStringFromObj(objv[2], 0);
63530ccda10Sdanielk1977     while( zSql[0] ){
63630ccda10Sdanielk1977       int i;
63730ccda10Sdanielk1977 
63830ccda10Sdanielk1977       if( SQLITE_OK!=sqlite3_prepare(pDb->db, zSql, -1, &pStmt, &zLeft) ){
639*ef2cb63eSdanielk1977         Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
64030ccda10Sdanielk1977         rc = TCL_ERROR;
64130ccda10Sdanielk1977         break;
64230ccda10Sdanielk1977       }
64330ccda10Sdanielk1977 
64430ccda10Sdanielk1977       if( pStmt && objc==5 ){
64530ccda10Sdanielk1977         Tcl_Obj *pColList = Tcl_NewObj();
64630ccda10Sdanielk1977         Tcl_IncrRefCount(pColList);
64730ccda10Sdanielk1977 
64830ccda10Sdanielk1977         for(i=0; i<sqlite3_column_count(pStmt); i++){
64930ccda10Sdanielk1977           Tcl_ListObjAppendElement(interp, pColList,
650*ef2cb63eSdanielk1977               dbTextToObj(sqlite3_column_name(pStmt, i))
65130ccda10Sdanielk1977           );
65230ccda10Sdanielk1977         }
65330ccda10Sdanielk1977         Tcl_ObjSetVar2(interp,objv[3],Tcl_NewStringObj("*",-1),pColList,0);
65430ccda10Sdanielk1977       }
65530ccda10Sdanielk1977 
65630ccda10Sdanielk1977       while( pStmt && SQLITE_ROW==sqlite3_step(pStmt) ){
65730ccda10Sdanielk1977         for(i=0; i<sqlite3_column_count(pStmt); i++){
65830ccda10Sdanielk1977           Tcl_Obj *pVal;
65930ccda10Sdanielk1977 
66030ccda10Sdanielk1977           /* Set pVal to contain the i'th column of this row. */
66130ccda10Sdanielk1977           if( SQLITE3_BLOB!=sqlite3_column_type(pStmt, i) ){
662*ef2cb63eSdanielk1977             pVal = dbTextToObj(sqlite3_column_text(pStmt, i));
66330ccda10Sdanielk1977           }else{
6643fd0a736Sdanielk1977             int bytes = sqlite3_column_bytes(pStmt, i);
6653fd0a736Sdanielk1977             pVal = Tcl_NewByteArrayObj(sqlite3_column_blob(pStmt, i), bytes);
66630ccda10Sdanielk1977           }
66730ccda10Sdanielk1977 
66830ccda10Sdanielk1977           if( objc==5 ){
669*ef2cb63eSdanielk1977             Tcl_Obj *pName = dbTextToObj(sqlite3_column_name(pStmt, i));
67030ccda10Sdanielk1977             Tcl_IncrRefCount(pName);
67130ccda10Sdanielk1977             if( !strcmp("", Tcl_GetString(objv[3])) ){
67230ccda10Sdanielk1977               Tcl_ObjSetVar2(interp, pName, 0, pVal, 0);
67330ccda10Sdanielk1977             }else{
67430ccda10Sdanielk1977               Tcl_ObjSetVar2(interp, objv[3], pName, pVal, 0);
67530ccda10Sdanielk1977             }
67630ccda10Sdanielk1977             Tcl_DecrRefCount(pName);
67730ccda10Sdanielk1977           }else{
67830ccda10Sdanielk1977             Tcl_ListObjAppendElement(interp, pRet, pVal);
67930ccda10Sdanielk1977           }
68030ccda10Sdanielk1977         }
68130ccda10Sdanielk1977 
68230ccda10Sdanielk1977         if( objc==5 ){
68330ccda10Sdanielk1977           rc = Tcl_EvalObjEx(interp, objv[4], 0);
68430ccda10Sdanielk1977           if( rc!=TCL_ERROR ) rc = TCL_OK;
68530ccda10Sdanielk1977         }
68630ccda10Sdanielk1977       }
68730ccda10Sdanielk1977 
68830ccda10Sdanielk1977       if( pStmt && SQLITE_SCHEMA==sqlite3_finalize(pStmt) ){
68930ccda10Sdanielk1977         continue;
69030ccda10Sdanielk1977       }
69130ccda10Sdanielk1977 
69230ccda10Sdanielk1977       if( pStmt && SQLITE_OK!=sqlite3_errcode(pDb->db) ){
693*ef2cb63eSdanielk1977         Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
69430ccda10Sdanielk1977         rc = TCL_ERROR;
69530ccda10Sdanielk1977         break;
69630ccda10Sdanielk1977       }
69730ccda10Sdanielk1977 
69830ccda10Sdanielk1977       pDb->nChange += sqlite3_changes(pDb->db);
69930ccda10Sdanielk1977       zSql = zLeft;
70030ccda10Sdanielk1977     }
70130ccda10Sdanielk1977 
702*ef2cb63eSdanielk1977     if( rc==TCL_OK ){
70330ccda10Sdanielk1977       Tcl_SetObjResult(interp, pRet);
70430ccda10Sdanielk1977     }
705*ef2cb63eSdanielk1977     Tcl_DecrRefCount(pRet);
70630ccda10Sdanielk1977 
70730ccda10Sdanielk1977     break;
70830ccda10Sdanielk1977   }
709bec3f402Sdrh 
710bec3f402Sdrh   /*
711cabb0819Sdrh   **     $db function NAME SCRIPT
712cabb0819Sdrh   **
713cabb0819Sdrh   ** Create a new SQL function called NAME.  Whenever that function is
714cabb0819Sdrh   ** called, invoke SCRIPT to evaluate the function.
715cabb0819Sdrh   */
716cabb0819Sdrh   case DB_FUNCTION: {
717cabb0819Sdrh     SqlFunc *pFunc;
718cabb0819Sdrh     char *zName;
719cabb0819Sdrh     char *zScript;
720cabb0819Sdrh     int nScript;
721cabb0819Sdrh     if( objc!=4 ){
722cabb0819Sdrh       Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT");
723cabb0819Sdrh       return TCL_ERROR;
724cabb0819Sdrh     }
725cabb0819Sdrh     zName = Tcl_GetStringFromObj(objv[2], 0);
726cabb0819Sdrh     zScript = Tcl_GetStringFromObj(objv[3], &nScript);
727cabb0819Sdrh     pFunc = (SqlFunc*)Tcl_Alloc( sizeof(*pFunc) + nScript + 1 );
728cabb0819Sdrh     if( pFunc==0 ) return TCL_ERROR;
729cabb0819Sdrh     pFunc->interp = interp;
730cabb0819Sdrh     pFunc->pNext = pDb->pFunc;
731cabb0819Sdrh     pFunc->zScript = (char*)&pFunc[1];
732cabb0819Sdrh     strcpy(pFunc->zScript, zScript);
7336590493dSdanielk1977     sqlite3_create_function(pDb->db, zName, -1, 0, 0, pFunc, tclSqlFunc, 0, 0);
734cabb0819Sdrh     break;
735cabb0819Sdrh   }
736cabb0819Sdrh 
737cabb0819Sdrh   /*
738af9ff33aSdrh   **     $db last_insert_rowid
739af9ff33aSdrh   **
740af9ff33aSdrh   ** Return an integer which is the ROWID for the most recent insert.
741af9ff33aSdrh   */
742af9ff33aSdrh   case DB_LAST_INSERT_ROWID: {
743af9ff33aSdrh     Tcl_Obj *pResult;
744af9ff33aSdrh     int rowid;
745af9ff33aSdrh     if( objc!=2 ){
746af9ff33aSdrh       Tcl_WrongNumArgs(interp, 2, objv, "");
747af9ff33aSdrh       return TCL_ERROR;
748af9ff33aSdrh     }
7496f8a503dSdanielk1977     rowid = sqlite3_last_insert_rowid(pDb->db);
750af9ff33aSdrh     pResult = Tcl_GetObjResult(interp);
751af9ff33aSdrh     Tcl_SetIntObj(pResult, rowid);
752af9ff33aSdrh     break;
753af9ff33aSdrh   }
754af9ff33aSdrh 
755af9ff33aSdrh   /*
7565d9d7576Sdrh   **     $db onecolumn SQL
7575d9d7576Sdrh   **
7585d9d7576Sdrh   ** Return a single column from a single row of the given SQL query.
7595d9d7576Sdrh   */
7605d9d7576Sdrh   case DB_ONECOLUMN: {
7615d9d7576Sdrh     char *zSql;
7625d9d7576Sdrh     char *zErrMsg = 0;
7635d9d7576Sdrh     if( objc!=3 ){
7645d9d7576Sdrh       Tcl_WrongNumArgs(interp, 2, objv, "SQL");
7655d9d7576Sdrh       return TCL_ERROR;
7665d9d7576Sdrh     }
7675d9d7576Sdrh     zSql = Tcl_GetStringFromObj(objv[2], 0);
7686f8a503dSdanielk1977     rc = sqlite3_exec(pDb->db, zSql, DbEvalCallback3, interp, &zErrMsg);
7695d9d7576Sdrh     if( rc==SQLITE_ABORT ){
77022fbcb8dSdrh       rc = SQLITE_OK;
7715d9d7576Sdrh     }else if( zErrMsg ){
7725d9d7576Sdrh       Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
7735d9d7576Sdrh       free(zErrMsg);
7745d9d7576Sdrh       rc = TCL_ERROR;
7755d9d7576Sdrh     }else if( rc!=SQLITE_OK ){
7766f8a503dSdanielk1977       Tcl_AppendResult(interp, sqlite3_error_string(rc), 0);
7775d9d7576Sdrh       rc = TCL_ERROR;
7785d9d7576Sdrh     }
7795d9d7576Sdrh     break;
7805d9d7576Sdrh   }
7815d9d7576Sdrh 
7825d9d7576Sdrh   /*
78322fbcb8dSdrh   **     $db rekey KEY
78422fbcb8dSdrh   **
78522fbcb8dSdrh   ** Change the encryption key on the currently open database.
78622fbcb8dSdrh   */
78722fbcb8dSdrh   case DB_REKEY: {
78822fbcb8dSdrh     int nKey;
78922fbcb8dSdrh     void *pKey;
79022fbcb8dSdrh     if( objc!=3 ){
79122fbcb8dSdrh       Tcl_WrongNumArgs(interp, 2, objv, "KEY");
79222fbcb8dSdrh       return TCL_ERROR;
79322fbcb8dSdrh     }
79422fbcb8dSdrh     pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey);
7959eb9e26bSdrh #ifdef SQLITE_HAS_CODEC
79622fbcb8dSdrh     rc = sqlite_rekey(pDb->db, pKey, nKey);
79722fbcb8dSdrh     if( rc ){
7986f8a503dSdanielk1977       Tcl_AppendResult(interp, sqlite3_error_string(rc), 0);
79922fbcb8dSdrh       rc = TCL_ERROR;
80022fbcb8dSdrh     }
80122fbcb8dSdrh #endif
80222fbcb8dSdrh     break;
80322fbcb8dSdrh   }
80422fbcb8dSdrh 
80522fbcb8dSdrh   /*
806bec3f402Sdrh   **     $db timeout MILLESECONDS
807bec3f402Sdrh   **
808bec3f402Sdrh   ** Delay for the number of milliseconds specified when a file is locked.
809bec3f402Sdrh   */
8106d31316cSdrh   case DB_TIMEOUT: {
811bec3f402Sdrh     int ms;
8126d31316cSdrh     if( objc!=3 ){
8136d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "MILLISECONDS");
814bec3f402Sdrh       return TCL_ERROR;
81575897234Sdrh     }
8166d31316cSdrh     if( Tcl_GetIntFromObj(interp, objv[2], &ms) ) return TCL_ERROR;
8176f8a503dSdanielk1977     sqlite3_busy_timeout(pDb->db, ms);
8186d31316cSdrh     break;
81975897234Sdrh   }
820b5a20d3cSdrh 
821b5a20d3cSdrh   /*    $db trace ?CALLBACK?
822b5a20d3cSdrh   **
823b5a20d3cSdrh   ** Make arrangements to invoke the CALLBACK routine for each SQL statement
824b5a20d3cSdrh   ** that is executed.  The text of the SQL is appended to CALLBACK before
825b5a20d3cSdrh   ** it is executed.
826b5a20d3cSdrh   */
827b5a20d3cSdrh   case DB_TRACE: {
828b5a20d3cSdrh     if( objc>3 ){
829b5a20d3cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
830b5a20d3cSdrh     }else if( objc==2 ){
831b5a20d3cSdrh       if( pDb->zTrace ){
832b5a20d3cSdrh         Tcl_AppendResult(interp, pDb->zTrace, 0);
833b5a20d3cSdrh       }
834b5a20d3cSdrh     }else{
835b5a20d3cSdrh       char *zTrace;
836b5a20d3cSdrh       int len;
837b5a20d3cSdrh       if( pDb->zTrace ){
838b5a20d3cSdrh         Tcl_Free(pDb->zTrace);
839b5a20d3cSdrh       }
840b5a20d3cSdrh       zTrace = Tcl_GetStringFromObj(objv[2], &len);
841b5a20d3cSdrh       if( zTrace && len>0 ){
842b5a20d3cSdrh         pDb->zTrace = Tcl_Alloc( len + 1 );
843b5a20d3cSdrh         strcpy(pDb->zTrace, zTrace);
844b5a20d3cSdrh       }else{
845b5a20d3cSdrh         pDb->zTrace = 0;
846b5a20d3cSdrh       }
847b5a20d3cSdrh       if( pDb->zTrace ){
848b5a20d3cSdrh         pDb->interp = interp;
8496f8a503dSdanielk1977         sqlite3_trace(pDb->db, DbTraceHandler, pDb);
850b5a20d3cSdrh       }else{
8516f8a503dSdanielk1977         sqlite3_trace(pDb->db, 0, 0);
852b5a20d3cSdrh       }
853b5a20d3cSdrh     }
854b5a20d3cSdrh     break;
855b5a20d3cSdrh   }
856b5a20d3cSdrh 
8576d31316cSdrh   } /* End of the SWITCH statement */
85822fbcb8dSdrh   return rc;
85975897234Sdrh }
86075897234Sdrh 
86175897234Sdrh /*
86222fbcb8dSdrh **   sqlite DBNAME FILENAME ?MODE? ?-key KEY?
86375897234Sdrh **
86475897234Sdrh ** This is the main Tcl command.  When the "sqlite" Tcl command is
86575897234Sdrh ** invoked, this routine runs to process that command.
86675897234Sdrh **
86775897234Sdrh ** The first argument, DBNAME, is an arbitrary name for a new
86875897234Sdrh ** database connection.  This command creates a new command named
86975897234Sdrh ** DBNAME that is used to control that connection.  The database
87075897234Sdrh ** connection is deleted when the DBNAME command is deleted.
87175897234Sdrh **
87275897234Sdrh ** The second argument is the name of the directory that contains
87375897234Sdrh ** the sqlite database that is to be accessed.
874fbc3eab8Sdrh **
875fbc3eab8Sdrh ** For testing purposes, we also support the following:
876fbc3eab8Sdrh **
877fbc3eab8Sdrh **  sqlite -encoding
878fbc3eab8Sdrh **
879fbc3eab8Sdrh **       Return the encoding used by LIKE and GLOB operators.  Choices
880fbc3eab8Sdrh **       are UTF-8 and iso8859.
881fbc3eab8Sdrh **
882647cb0e1Sdrh **  sqlite -version
883647cb0e1Sdrh **
884647cb0e1Sdrh **       Return the version number of the SQLite library.
885647cb0e1Sdrh **
886fbc3eab8Sdrh **  sqlite -tcl-uses-utf
887fbc3eab8Sdrh **
888fbc3eab8Sdrh **       Return "1" if compiled with a Tcl uses UTF-8.  Return "0" if
889fbc3eab8Sdrh **       not.  Used by tests to make sure the library was compiled
890fbc3eab8Sdrh **       correctly.
89175897234Sdrh */
89222fbcb8dSdrh static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
893bec3f402Sdrh   SqliteDb *p;
89422fbcb8dSdrh   void *pKey = 0;
89522fbcb8dSdrh   int nKey = 0;
89622fbcb8dSdrh   const char *zArg;
89775897234Sdrh   char *zErrMsg;
89822fbcb8dSdrh   const char *zFile;
89980290863Sdanielk1977   const char *zOpts[2] = {0, 0};
90006b2718aSdrh   char zBuf[80];
90122fbcb8dSdrh   if( objc==2 ){
90222fbcb8dSdrh     zArg = Tcl_GetStringFromObj(objv[1], 0);
90322fbcb8dSdrh     if( strcmp(zArg,"-encoding")==0 ){
9046f8a503dSdanielk1977       Tcl_AppendResult(interp,sqlite3_encoding,0);
905fbc3eab8Sdrh       return TCL_OK;
906fbc3eab8Sdrh     }
90722fbcb8dSdrh     if( strcmp(zArg,"-version")==0 ){
9086f8a503dSdanielk1977       Tcl_AppendResult(interp,sqlite3_version,0);
909647cb0e1Sdrh       return TCL_OK;
910647cb0e1Sdrh     }
9119eb9e26bSdrh     if( strcmp(zArg,"-has-codec")==0 ){
9129eb9e26bSdrh #ifdef SQLITE_HAS_CODEC
91322fbcb8dSdrh       Tcl_AppendResult(interp,"1",0);
91422fbcb8dSdrh #else
91522fbcb8dSdrh       Tcl_AppendResult(interp,"0",0);
91622fbcb8dSdrh #endif
91722fbcb8dSdrh       return TCL_OK;
91822fbcb8dSdrh     }
91922fbcb8dSdrh     if( strcmp(zArg,"-tcl-uses-utf")==0 ){
920fbc3eab8Sdrh #ifdef TCL_UTF_MAX
921fbc3eab8Sdrh       Tcl_AppendResult(interp,"1",0);
922fbc3eab8Sdrh #else
923fbc3eab8Sdrh       Tcl_AppendResult(interp,"0",0);
924fbc3eab8Sdrh #endif
925fbc3eab8Sdrh       return TCL_OK;
926fbc3eab8Sdrh     }
927fbc3eab8Sdrh   }
92822fbcb8dSdrh   if( objc==5 || objc==6 ){
92922fbcb8dSdrh     zArg = Tcl_GetStringFromObj(objv[objc-2], 0);
93022fbcb8dSdrh     if( strcmp(zArg,"-key")==0 ){
93122fbcb8dSdrh       pKey = Tcl_GetByteArrayFromObj(objv[objc-1], &nKey);
93222fbcb8dSdrh       objc -= 2;
93322fbcb8dSdrh     }
93422fbcb8dSdrh   }
93522fbcb8dSdrh   if( objc!=3 && objc!=4 ){
93622fbcb8dSdrh     Tcl_WrongNumArgs(interp, 1, objv,
9379eb9e26bSdrh #ifdef SQLITE_HAS_CODEC
9389eb9e26bSdrh       "HANDLE FILENAME ?-key CODEC-KEY?"
93922fbcb8dSdrh #else
94022fbcb8dSdrh       "HANDLE FILENAME ?MODE?"
94122fbcb8dSdrh #endif
94222fbcb8dSdrh     );
94375897234Sdrh     return TCL_ERROR;
94475897234Sdrh   }
94575897234Sdrh   zErrMsg = 0;
9464cdc9e84Sdrh   p = (SqliteDb*)Tcl_Alloc( sizeof(*p) );
94775897234Sdrh   if( p==0 ){
948bec3f402Sdrh     Tcl_SetResult(interp, "malloc failed", TCL_STATIC);
949bec3f402Sdrh     return TCL_ERROR;
950bec3f402Sdrh   }
951bec3f402Sdrh   memset(p, 0, sizeof(*p));
95222fbcb8dSdrh   zFile = Tcl_GetStringFromObj(objv[2], 0);
9539eb9e26bSdrh #ifdef SQLITE_HAS_CODEC
9546f8a503dSdanielk1977   p->db = sqlite3_open_encrypted(zFile, pKey, nKey, 0, &zErrMsg);
955eb8ed70dSdrh #else
95680290863Sdanielk1977   if( objc>3 ){
95780290863Sdanielk1977     zOpts[0] = Tcl_GetString(objv[3]);
95880290863Sdanielk1977   }
95980290863Sdanielk1977   sqlite3_open(zFile, &p->db, zOpts);
96080290863Sdanielk1977   if( SQLITE_OK!=sqlite3_errcode(p->db) ){
96180290863Sdanielk1977     zErrMsg = strdup(sqlite3_errmsg(p->db));
96280290863Sdanielk1977     sqlite3_close(p->db);
96380290863Sdanielk1977     p->db = 0;
96480290863Sdanielk1977   }
965eb8ed70dSdrh #endif
966bec3f402Sdrh   if( p->db==0 ){
96775897234Sdrh     Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
968bec3f402Sdrh     Tcl_Free((char*)p);
96975897234Sdrh     free(zErrMsg);
97075897234Sdrh     return TCL_ERROR;
97175897234Sdrh   }
97222fbcb8dSdrh   zArg = Tcl_GetStringFromObj(objv[1], 0);
97322fbcb8dSdrh   Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd);
974c22bd47dSdrh 
97506b2718aSdrh   /* The return value is the value of the sqlite* pointer
97606b2718aSdrh   */
97706b2718aSdrh   sprintf(zBuf, "%p", p->db);
9785e5377fbSdrh   if( strncmp(zBuf,"0x",2) ){
9795e5377fbSdrh     sprintf(zBuf, "0x%p", p->db);
9805e5377fbSdrh   }
98106b2718aSdrh   Tcl_AppendResult(interp, zBuf, 0);
98206b2718aSdrh 
983c22bd47dSdrh   /* If compiled with SQLITE_TEST turned on, then register the "md5sum"
98406b2718aSdrh   ** SQL function.
985c22bd47dSdrh   */
98628b4e489Sdrh #ifdef SQLITE_TEST
98728b4e489Sdrh   {
98828b4e489Sdrh     extern void Md5_Register(sqlite*);
98928b4e489Sdrh     Md5_Register(p->db);
99028b4e489Sdrh    }
99128b4e489Sdrh #endif
99275897234Sdrh   return TCL_OK;
99375897234Sdrh }
99475897234Sdrh 
99575897234Sdrh /*
99690ca9753Sdrh ** Provide a dummy Tcl_InitStubs if we are using this as a static
99790ca9753Sdrh ** library.
99890ca9753Sdrh */
99990ca9753Sdrh #ifndef USE_TCL_STUBS
100090ca9753Sdrh # undef  Tcl_InitStubs
100190ca9753Sdrh # define Tcl_InitStubs(a,b,c)
100290ca9753Sdrh #endif
100390ca9753Sdrh 
100490ca9753Sdrh /*
100575897234Sdrh ** Initialize this module.
100675897234Sdrh **
100775897234Sdrh ** This Tcl module contains only a single new Tcl command named "sqlite".
100875897234Sdrh ** (Hence there is no namespace.  There is no point in using a namespace
100975897234Sdrh ** if the extension only supplies one new name!)  The "sqlite" command is
101075897234Sdrh ** used to open a new SQLite database.  See the DbMain() routine above
101175897234Sdrh ** for additional information.
101275897234Sdrh */
101375897234Sdrh int Sqlite_Init(Tcl_Interp *interp){
101490ca9753Sdrh   Tcl_InitStubs(interp, "8.0", 0);
101522fbcb8dSdrh   Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0);
10166d4abfbeSdrh   Tcl_PkgProvide(interp, "sqlite", "2.0");
101790ca9753Sdrh   return TCL_OK;
101890ca9753Sdrh }
101990ca9753Sdrh int Tclsqlite_Init(Tcl_Interp *interp){
102090ca9753Sdrh   Tcl_InitStubs(interp, "8.0", 0);
102122fbcb8dSdrh   Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0);
10226d4abfbeSdrh   Tcl_PkgProvide(interp, "sqlite", "2.0");
102375897234Sdrh   return TCL_OK;
102475897234Sdrh }
102575897234Sdrh int Sqlite_SafeInit(Tcl_Interp *interp){
102675897234Sdrh   return TCL_OK;
102775897234Sdrh }
102890ca9753Sdrh int Tclsqlite_SafeInit(Tcl_Interp *interp){
102990ca9753Sdrh   return TCL_OK;
103090ca9753Sdrh }
103175897234Sdrh 
10323cebbde3Sdrh #if 0
103375897234Sdrh /*
103475897234Sdrh ** If compiled using mktclapp, this routine runs to initialize
103575897234Sdrh ** everything.
103675897234Sdrh */
103775897234Sdrh int Et_AppInit(Tcl_Interp *interp){
103875897234Sdrh   return Sqlite_Init(interp);
103975897234Sdrh }
10403cebbde3Sdrh #endif
1041348784efSdrh 
1042348784efSdrh /*
1043348784efSdrh ** If the macro TCLSH is defined and is one, then put in code for the
1044348784efSdrh ** "main" routine that will initialize Tcl.
1045348784efSdrh */
1046348784efSdrh #if defined(TCLSH) && TCLSH==1
1047348784efSdrh static char zMainloop[] =
1048348784efSdrh   "set line {}\n"
1049348784efSdrh   "while {![eof stdin]} {\n"
1050348784efSdrh     "if {$line!=\"\"} {\n"
1051348784efSdrh       "puts -nonewline \"> \"\n"
1052348784efSdrh     "} else {\n"
1053348784efSdrh       "puts -nonewline \"% \"\n"
1054348784efSdrh     "}\n"
1055348784efSdrh     "flush stdout\n"
1056348784efSdrh     "append line [gets stdin]\n"
1057348784efSdrh     "if {[info complete $line]} {\n"
1058348784efSdrh       "if {[catch {uplevel #0 $line} result]} {\n"
1059348784efSdrh         "puts stderr \"Error: $result\"\n"
1060348784efSdrh       "} elseif {$result!=\"\"} {\n"
1061348784efSdrh         "puts $result\n"
1062348784efSdrh       "}\n"
1063348784efSdrh       "set line {}\n"
1064348784efSdrh     "} else {\n"
1065348784efSdrh       "append line \\n\n"
1066348784efSdrh     "}\n"
1067348784efSdrh   "}\n"
1068348784efSdrh ;
1069348784efSdrh 
1070348784efSdrh #define TCLSH_MAIN main   /* Needed to fake out mktclapp */
1071348784efSdrh int TCLSH_MAIN(int argc, char **argv){
1072348784efSdrh   Tcl_Interp *interp;
1073297ecf14Sdrh   Tcl_FindExecutable(argv[0]);
1074348784efSdrh   interp = Tcl_CreateInterp();
10754adee20fSdanielk1977   Sqlite_Init(interp);
1076d9b0257aSdrh #ifdef SQLITE_TEST
1077d1bf3512Sdrh   {
1078d1bf3512Sdrh     extern int Sqlitetest1_Init(Tcl_Interp*);
10795c4d9703Sdrh     extern int Sqlitetest2_Init(Tcl_Interp*);
10805c4d9703Sdrh     extern int Sqlitetest3_Init(Tcl_Interp*);
1081a6064dcfSdrh     extern int Sqlitetest4_Init(Tcl_Interp*);
1082998b56c3Sdanielk1977     extern int Sqlitetest5_Init(Tcl_Interp*);
1083efc251daSdrh     extern int Md5_Init(Tcl_Interp*);
10846490bebdSdanielk1977     Sqlitetest1_Init(interp);
10855c4d9703Sdrh     Sqlitetest2_Init(interp);
1086de647130Sdrh     Sqlitetest3_Init(interp);
1087fc57d7bfSdanielk1977     Sqlitetest4_Init(interp);
1088998b56c3Sdanielk1977     Sqlitetest5_Init(interp);
1089efc251daSdrh     Md5_Init(interp);
1090d1bf3512Sdrh   }
1091d1bf3512Sdrh #endif
1092348784efSdrh   if( argc>=2 ){
1093348784efSdrh     int i;
1094348784efSdrh     Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY);
1095348784efSdrh     Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
1096348784efSdrh     for(i=2; i<argc; i++){
1097348784efSdrh       Tcl_SetVar(interp, "argv", argv[i],
1098348784efSdrh           TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
1099348784efSdrh     }
1100348784efSdrh     if( Tcl_EvalFile(interp, argv[1])!=TCL_OK ){
11010de8c112Sdrh       const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
1102c61053b7Sdrh       if( zInfo==0 ) zInfo = interp->result;
1103c61053b7Sdrh       fprintf(stderr,"%s: %s\n", *argv, zInfo);
1104348784efSdrh       return 1;
1105348784efSdrh     }
1106348784efSdrh   }else{
1107348784efSdrh     Tcl_GlobalEval(interp, zMainloop);
1108348784efSdrh   }
1109348784efSdrh   return 0;
1110348784efSdrh }
1111348784efSdrh #endif /* TCLSH */
11126d31316cSdrh 
11136d31316cSdrh #endif /* !defined(NO_TCL) */
1114