xref: /sqlite-3.40.0/src/tclsqlite.c (revision 7cedc8d4)
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*7cedc8d4Sdanielk1977 ** $Id: tclsqlite.c,v 1.83 2004/06/10 10:50:38 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 /*
460202b29eSdanielk1977 ** New collation sequences function can be created as TCL scripts.  Each such
470202b29eSdanielk1977 ** function is described by an instance of the following structure.
480202b29eSdanielk1977 */
490202b29eSdanielk1977 typedef struct SqlCollate SqlCollate;
500202b29eSdanielk1977 struct SqlCollate {
510202b29eSdanielk1977   Tcl_Interp *interp;   /* The TCL interpret to execute the function */
520202b29eSdanielk1977   char *zScript;        /* The script to be run */
530202b29eSdanielk1977   SqlCollate *pNext;       /* Next function on the list of them all */
540202b29eSdanielk1977 };
550202b29eSdanielk1977 
560202b29eSdanielk1977 /*
57bec3f402Sdrh ** There is one instance of this structure for each SQLite database
58bec3f402Sdrh ** that has been opened by the SQLite TCL interface.
59bec3f402Sdrh */
60bec3f402Sdrh typedef struct SqliteDb SqliteDb;
61bec3f402Sdrh struct SqliteDb {
62bec3f402Sdrh   sqlite *db;           /* The "real" database structure */
63bec3f402Sdrh   Tcl_Interp *interp;   /* The interpreter used for this database */
646d31316cSdrh   char *zBusy;          /* The busy callback routine */
65aa940eacSdrh   char *zCommit;        /* The commit hook callback routine */
66b5a20d3cSdrh   char *zTrace;         /* The trace callback routine */
67348bb5d6Sdanielk1977   char *zProgress;      /* The progress callback routine */
68e22a334bSdrh   char *zAuth;          /* The authorization callback routine */
69cabb0819Sdrh   SqlFunc *pFunc;       /* List of SQL functions */
700202b29eSdanielk1977   SqlCollate *pCollate; /* List of SQL collation functions */
716f8a503dSdanielk1977   int rc;               /* Return code of most recent sqlite3_exec() */
7230ccda10Sdanielk1977   int nChange;          /* Database changes for the most recent eval */
73*7cedc8d4Sdanielk1977   Tcl_Obj *pCollateNeeded;  /* Collation needed script */
74bec3f402Sdrh };
75bec3f402Sdrh 
76bec3f402Sdrh /*
7775897234Sdrh ** An instance of this structure passes information thru the sqlite
7875897234Sdrh ** logic from the original TCL command into the callback routine.
7975897234Sdrh */
8075897234Sdrh typedef struct CallbackData CallbackData;
8175897234Sdrh struct CallbackData {
8275897234Sdrh   Tcl_Interp *interp;       /* The TCL interpreter */
8375897234Sdrh   char *zArray;             /* The array into which data is written */
846d31316cSdrh   Tcl_Obj *pCode;           /* The code to execute for each row */
85ce927065Sdrh   int once;                 /* Set for first callback only */
86960e8c63Sdrh   int tcl_rc;               /* Return code from TCL script */
8798808babSdrh   int nColName;             /* Number of entries in the azColName[] array */
8898808babSdrh   char **azColName;         /* Column names translated to UTF-8 */
8998808babSdrh };
90297ecf14Sdrh 
916d31316cSdrh /*
925d9d7576Sdrh ** This is a second alternative callback for database queries.  A the
935d9d7576Sdrh ** first column of the first row of the result is made the TCL result.
945d9d7576Sdrh */
955d9d7576Sdrh static int DbEvalCallback3(
965d9d7576Sdrh   void *clientData,      /* An instance of CallbackData */
975d9d7576Sdrh   int nCol,              /* Number of columns in the result */
985d9d7576Sdrh   char ** azCol,         /* Data for each column */
995d9d7576Sdrh   char ** azN            /* Name for each column */
1005d9d7576Sdrh ){
1015d9d7576Sdrh   Tcl_Interp *interp = (Tcl_Interp*)clientData;
1025d9d7576Sdrh   Tcl_Obj *pElem;
1035d9d7576Sdrh   if( azCol==0 ) return 1;
1045d9d7576Sdrh   if( nCol==0 ) return 1;
1055d9d7576Sdrh #ifdef UTF_TRANSLATION_NEEDED
1065d9d7576Sdrh   {
1075d9d7576Sdrh     Tcl_DString dCol;
1085d9d7576Sdrh     Tcl_DStringInit(&dCol);
1095d9d7576Sdrh     Tcl_ExternalToUtfDString(NULL, azCol[0], -1, &dCol);
1105d9d7576Sdrh     pElem = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1);
1115d9d7576Sdrh     Tcl_DStringFree(&dCol);
1125d9d7576Sdrh   }
1135d9d7576Sdrh #else
1145d9d7576Sdrh   pElem = Tcl_NewStringObj(azCol[0], -1);
1155d9d7576Sdrh #endif
1165d9d7576Sdrh   Tcl_SetObjResult(interp, pElem);
1175d9d7576Sdrh   return 1;
1185d9d7576Sdrh }
1195d9d7576Sdrh 
1205d9d7576Sdrh /*
12175897234Sdrh ** Called when the command is deleted.
12275897234Sdrh */
12375897234Sdrh static void DbDeleteCmd(void *db){
124bec3f402Sdrh   SqliteDb *pDb = (SqliteDb*)db;
1256f8a503dSdanielk1977   sqlite3_close(pDb->db);
126cabb0819Sdrh   while( pDb->pFunc ){
127cabb0819Sdrh     SqlFunc *pFunc = pDb->pFunc;
128cabb0819Sdrh     pDb->pFunc = pFunc->pNext;
129cabb0819Sdrh     Tcl_Free((char*)pFunc);
130cabb0819Sdrh   }
1310202b29eSdanielk1977   while( pDb->pCollate ){
1320202b29eSdanielk1977     SqlCollate *pCollate = pDb->pCollate;
1330202b29eSdanielk1977     pDb->pCollate = pCollate->pNext;
1340202b29eSdanielk1977     Tcl_Free((char*)pCollate);
1350202b29eSdanielk1977   }
136bec3f402Sdrh   if( pDb->zBusy ){
137bec3f402Sdrh     Tcl_Free(pDb->zBusy);
138bec3f402Sdrh   }
139b5a20d3cSdrh   if( pDb->zTrace ){
140b5a20d3cSdrh     Tcl_Free(pDb->zTrace);
1410d1a643aSdrh   }
142e22a334bSdrh   if( pDb->zAuth ){
143e22a334bSdrh     Tcl_Free(pDb->zAuth);
144e22a334bSdrh   }
145bec3f402Sdrh   Tcl_Free((char*)pDb);
146bec3f402Sdrh }
147bec3f402Sdrh 
148bec3f402Sdrh /*
149bec3f402Sdrh ** This routine is called when a database file is locked while trying
150bec3f402Sdrh ** to execute SQL.
151bec3f402Sdrh */
152bec3f402Sdrh static int DbBusyHandler(void *cd, const char *zTable, int nTries){
153bec3f402Sdrh   SqliteDb *pDb = (SqliteDb*)cd;
154bec3f402Sdrh   int rc;
155bec3f402Sdrh   char zVal[30];
156bec3f402Sdrh   char *zCmd;
157bec3f402Sdrh   Tcl_DString cmd;
158bec3f402Sdrh 
159bec3f402Sdrh   Tcl_DStringInit(&cmd);
160bec3f402Sdrh   Tcl_DStringAppend(&cmd, pDb->zBusy, -1);
161bec3f402Sdrh   Tcl_DStringAppendElement(&cmd, zTable);
162bec3f402Sdrh   sprintf(zVal, " %d", nTries);
163bec3f402Sdrh   Tcl_DStringAppend(&cmd, zVal, -1);
164bec3f402Sdrh   zCmd = Tcl_DStringValue(&cmd);
165bec3f402Sdrh   rc = Tcl_Eval(pDb->interp, zCmd);
166bec3f402Sdrh   Tcl_DStringFree(&cmd);
167bec3f402Sdrh   if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
168bec3f402Sdrh     return 0;
169bec3f402Sdrh   }
170bec3f402Sdrh   return 1;
17175897234Sdrh }
17275897234Sdrh 
17375897234Sdrh /*
174348bb5d6Sdanielk1977 ** This routine is invoked as the 'progress callback' for the database.
175348bb5d6Sdanielk1977 */
176348bb5d6Sdanielk1977 static int DbProgressHandler(void *cd){
177348bb5d6Sdanielk1977   SqliteDb *pDb = (SqliteDb*)cd;
178348bb5d6Sdanielk1977   int rc;
179348bb5d6Sdanielk1977 
180348bb5d6Sdanielk1977   assert( pDb->zProgress );
181348bb5d6Sdanielk1977   rc = Tcl_Eval(pDb->interp, pDb->zProgress);
182348bb5d6Sdanielk1977   if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
183348bb5d6Sdanielk1977     return 1;
184348bb5d6Sdanielk1977   }
185348bb5d6Sdanielk1977   return 0;
186348bb5d6Sdanielk1977 }
187348bb5d6Sdanielk1977 
188348bb5d6Sdanielk1977 /*
189b5a20d3cSdrh ** This routine is called by the SQLite trace handler whenever a new
190b5a20d3cSdrh ** block of SQL is executed.  The TCL script in pDb->zTrace is executed.
1910d1a643aSdrh */
192b5a20d3cSdrh static void DbTraceHandler(void *cd, const char *zSql){
1930d1a643aSdrh   SqliteDb *pDb = (SqliteDb*)cd;
194b5a20d3cSdrh   Tcl_DString str;
1950d1a643aSdrh 
196b5a20d3cSdrh   Tcl_DStringInit(&str);
197b5a20d3cSdrh   Tcl_DStringAppend(&str, pDb->zTrace, -1);
198b5a20d3cSdrh   Tcl_DStringAppendElement(&str, zSql);
199b5a20d3cSdrh   Tcl_Eval(pDb->interp, Tcl_DStringValue(&str));
200b5a20d3cSdrh   Tcl_DStringFree(&str);
201b5a20d3cSdrh   Tcl_ResetResult(pDb->interp);
2020d1a643aSdrh }
2030d1a643aSdrh 
2040d1a643aSdrh /*
205aa940eacSdrh ** This routine is called when a transaction is committed.  The
206aa940eacSdrh ** TCL script in pDb->zCommit is executed.  If it returns non-zero or
207aa940eacSdrh ** if it throws an exception, the transaction is rolled back instead
208aa940eacSdrh ** of being committed.
209aa940eacSdrh */
210aa940eacSdrh static int DbCommitHandler(void *cd){
211aa940eacSdrh   SqliteDb *pDb = (SqliteDb*)cd;
212aa940eacSdrh   int rc;
213aa940eacSdrh 
214aa940eacSdrh   rc = Tcl_Eval(pDb->interp, pDb->zCommit);
215aa940eacSdrh   if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
216aa940eacSdrh     return 1;
217aa940eacSdrh   }
218aa940eacSdrh   return 0;
219aa940eacSdrh }
220aa940eacSdrh 
221*7cedc8d4Sdanielk1977 static void tclCollateNeeded(
222*7cedc8d4Sdanielk1977   void *pCtx,
223*7cedc8d4Sdanielk1977   sqlite *db,
224*7cedc8d4Sdanielk1977   int enc,
225*7cedc8d4Sdanielk1977   const char *zName
226*7cedc8d4Sdanielk1977 ){
227*7cedc8d4Sdanielk1977   SqliteDb *pDb = (SqliteDb *)pCtx;
228*7cedc8d4Sdanielk1977   Tcl_Obj *pScript = Tcl_DuplicateObj(pDb->pCollateNeeded);
229*7cedc8d4Sdanielk1977   Tcl_IncrRefCount(pScript);
230*7cedc8d4Sdanielk1977   Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj(zName, -1));
231*7cedc8d4Sdanielk1977   Tcl_EvalObjEx(pDb->interp, pScript, 0);
232*7cedc8d4Sdanielk1977   Tcl_DecrRefCount(pScript);
233*7cedc8d4Sdanielk1977 }
234*7cedc8d4Sdanielk1977 
235aa940eacSdrh /*
2360202b29eSdanielk1977 ** This routine is called to evaluate an SQL collation function implemented
2370202b29eSdanielk1977 ** using TCL script.
2380202b29eSdanielk1977 */
2390202b29eSdanielk1977 static int tclSqlCollate(
2400202b29eSdanielk1977   void *pCtx,
2410202b29eSdanielk1977   int nA,
2420202b29eSdanielk1977   const void *zA,
2430202b29eSdanielk1977   int nB,
2440202b29eSdanielk1977   const void *zB
2450202b29eSdanielk1977 ){
2460202b29eSdanielk1977   SqlCollate *p = (SqlCollate *)pCtx;
2470202b29eSdanielk1977   Tcl_Obj *pCmd;
2480202b29eSdanielk1977 
2490202b29eSdanielk1977   pCmd = Tcl_NewStringObj(p->zScript, -1);
2500202b29eSdanielk1977   Tcl_IncrRefCount(pCmd);
2510202b29eSdanielk1977   Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zA, nA));
2520202b29eSdanielk1977   Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zB, nB));
2530202b29eSdanielk1977   Tcl_EvalObjEx(p->interp, pCmd, 0);
2540202b29eSdanielk1977   Tcl_DecrRefCount(pCmd);
2550202b29eSdanielk1977   return (atoi(Tcl_GetStringResult(p->interp)));
2560202b29eSdanielk1977 }
2570202b29eSdanielk1977 
2580202b29eSdanielk1977 /*
259cabb0819Sdrh ** This routine is called to evaluate an SQL function implemented
260cabb0819Sdrh ** using TCL script.
261cabb0819Sdrh */
2620ae8b831Sdanielk1977 static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
2636f8a503dSdanielk1977   SqlFunc *p = sqlite3_user_data(context);
264cabb0819Sdrh   Tcl_DString cmd;
265cabb0819Sdrh   int i;
266cabb0819Sdrh   int rc;
267cabb0819Sdrh 
268cabb0819Sdrh   Tcl_DStringInit(&cmd);
269cabb0819Sdrh   Tcl_DStringAppend(&cmd, p->zScript, -1);
270cabb0819Sdrh   for(i=0; i<argc; i++){
2719c054830Sdrh     if( SQLITE_NULL==sqlite3_value_type(argv[i]) ){
27251ad0ecdSdanielk1977       Tcl_DStringAppendElement(&cmd, "");
27351ad0ecdSdanielk1977     }else{
2744f26d6c4Sdrh       Tcl_DStringAppendElement(&cmd, sqlite3_value_text(argv[i]));
27551ad0ecdSdanielk1977     }
276cabb0819Sdrh   }
277cabb0819Sdrh   rc = Tcl_Eval(p->interp, Tcl_DStringValue(&cmd));
278cabb0819Sdrh   if( rc ){
2797e18c259Sdanielk1977     sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
280cabb0819Sdrh   }else{
2817e18c259Sdanielk1977     sqlite3_result_text(context, Tcl_GetStringResult(p->interp), -1, 1);
282cabb0819Sdrh   }
283cabb0819Sdrh }
284e22a334bSdrh #ifndef SQLITE_OMIT_AUTHORIZATION
285e22a334bSdrh /*
286e22a334bSdrh ** This is the authentication function.  It appends the authentication
287e22a334bSdrh ** type code and the two arguments to zCmd[] then invokes the result
288e22a334bSdrh ** on the interpreter.  The reply is examined to determine if the
289e22a334bSdrh ** authentication fails or succeeds.
290e22a334bSdrh */
291e22a334bSdrh static int auth_callback(
292e22a334bSdrh   void *pArg,
293e22a334bSdrh   int code,
294e22a334bSdrh   const char *zArg1,
295e22a334bSdrh   const char *zArg2,
296e22a334bSdrh   const char *zArg3,
297e22a334bSdrh   const char *zArg4
298e22a334bSdrh ){
299e22a334bSdrh   char *zCode;
300e22a334bSdrh   Tcl_DString str;
301e22a334bSdrh   int rc;
302e22a334bSdrh   const char *zReply;
303e22a334bSdrh   SqliteDb *pDb = (SqliteDb*)pArg;
304e22a334bSdrh 
305e22a334bSdrh   switch( code ){
306e22a334bSdrh     case SQLITE_COPY              : zCode="SQLITE_COPY"; break;
307e22a334bSdrh     case SQLITE_CREATE_INDEX      : zCode="SQLITE_CREATE_INDEX"; break;
308e22a334bSdrh     case SQLITE_CREATE_TABLE      : zCode="SQLITE_CREATE_TABLE"; break;
309e22a334bSdrh     case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break;
310e22a334bSdrh     case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break;
311e22a334bSdrh     case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break;
312e22a334bSdrh     case SQLITE_CREATE_TEMP_VIEW  : zCode="SQLITE_CREATE_TEMP_VIEW"; break;
313e22a334bSdrh     case SQLITE_CREATE_TRIGGER    : zCode="SQLITE_CREATE_TRIGGER"; break;
314e22a334bSdrh     case SQLITE_CREATE_VIEW       : zCode="SQLITE_CREATE_VIEW"; break;
315e22a334bSdrh     case SQLITE_DELETE            : zCode="SQLITE_DELETE"; break;
316e22a334bSdrh     case SQLITE_DROP_INDEX        : zCode="SQLITE_DROP_INDEX"; break;
317e22a334bSdrh     case SQLITE_DROP_TABLE        : zCode="SQLITE_DROP_TABLE"; break;
318e22a334bSdrh     case SQLITE_DROP_TEMP_INDEX   : zCode="SQLITE_DROP_TEMP_INDEX"; break;
319e22a334bSdrh     case SQLITE_DROP_TEMP_TABLE   : zCode="SQLITE_DROP_TEMP_TABLE"; break;
320e22a334bSdrh     case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break;
321e22a334bSdrh     case SQLITE_DROP_TEMP_VIEW    : zCode="SQLITE_DROP_TEMP_VIEW"; break;
322e22a334bSdrh     case SQLITE_DROP_TRIGGER      : zCode="SQLITE_DROP_TRIGGER"; break;
323e22a334bSdrh     case SQLITE_DROP_VIEW         : zCode="SQLITE_DROP_VIEW"; break;
324e22a334bSdrh     case SQLITE_INSERT            : zCode="SQLITE_INSERT"; break;
325e22a334bSdrh     case SQLITE_PRAGMA            : zCode="SQLITE_PRAGMA"; break;
326e22a334bSdrh     case SQLITE_READ              : zCode="SQLITE_READ"; break;
327e22a334bSdrh     case SQLITE_SELECT            : zCode="SQLITE_SELECT"; break;
328e22a334bSdrh     case SQLITE_TRANSACTION       : zCode="SQLITE_TRANSACTION"; break;
329e22a334bSdrh     case SQLITE_UPDATE            : zCode="SQLITE_UPDATE"; break;
33081e293b4Sdrh     case SQLITE_ATTACH            : zCode="SQLITE_ATTACH"; break;
33181e293b4Sdrh     case SQLITE_DETACH            : zCode="SQLITE_DETACH"; break;
332e22a334bSdrh     default                       : zCode="????"; break;
333e22a334bSdrh   }
334e22a334bSdrh   Tcl_DStringInit(&str);
335e22a334bSdrh   Tcl_DStringAppend(&str, pDb->zAuth, -1);
336e22a334bSdrh   Tcl_DStringAppendElement(&str, zCode);
337e22a334bSdrh   Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : "");
338e22a334bSdrh   Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : "");
339e22a334bSdrh   Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : "");
340e22a334bSdrh   Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : "");
341e22a334bSdrh   rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str));
342e22a334bSdrh   Tcl_DStringFree(&str);
343e22a334bSdrh   zReply = Tcl_GetStringResult(pDb->interp);
344e22a334bSdrh   if( strcmp(zReply,"SQLITE_OK")==0 ){
345e22a334bSdrh     rc = SQLITE_OK;
346e22a334bSdrh   }else if( strcmp(zReply,"SQLITE_DENY")==0 ){
347e22a334bSdrh     rc = SQLITE_DENY;
348e22a334bSdrh   }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){
349e22a334bSdrh     rc = SQLITE_IGNORE;
350e22a334bSdrh   }else{
351e22a334bSdrh     rc = 999;
352e22a334bSdrh   }
353e22a334bSdrh   return rc;
354e22a334bSdrh }
355e22a334bSdrh #endif /* SQLITE_OMIT_AUTHORIZATION */
356cabb0819Sdrh 
357cabb0819Sdrh /*
358ef2cb63eSdanielk1977 ** zText is a pointer to text obtained via an sqlite3_result_text()
359ef2cb63eSdanielk1977 ** or similar interface. This routine returns a Tcl string object,
360ef2cb63eSdanielk1977 ** reference count set to 0, containing the text. If a translation
361ef2cb63eSdanielk1977 ** between iso8859 and UTF-8 is required, it is preformed.
362ef2cb63eSdanielk1977 */
363ef2cb63eSdanielk1977 static Tcl_Obj *dbTextToObj(char const *zText){
364ef2cb63eSdanielk1977   Tcl_Obj *pVal;
365ef2cb63eSdanielk1977 #ifdef UTF_TRANSLATION_NEEDED
366ef2cb63eSdanielk1977   Tcl_DString dCol;
367ef2cb63eSdanielk1977   Tcl_DStringInit(&dCol);
368ef2cb63eSdanielk1977   Tcl_ExternalToUtfDString(NULL, zText, -1, &dCol);
369ef2cb63eSdanielk1977   pVal = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1);
370ef2cb63eSdanielk1977   Tcl_DStringFree(&dCol);
371ef2cb63eSdanielk1977 #else
372ef2cb63eSdanielk1977   pVal = Tcl_NewStringObj(zText, -1);
373ef2cb63eSdanielk1977 #endif
374ef2cb63eSdanielk1977   return pVal;
375ef2cb63eSdanielk1977 }
376ef2cb63eSdanielk1977 
377ef2cb63eSdanielk1977 /*
37875897234Sdrh ** The "sqlite" command below creates a new Tcl command for each
37975897234Sdrh ** connection it opens to an SQLite database.  This routine is invoked
38075897234Sdrh ** whenever one of those connection-specific commands is executed
38175897234Sdrh ** in Tcl.  For example, if you run Tcl code like this:
38275897234Sdrh **
38375897234Sdrh **       sqlite db1  "my_database"
38475897234Sdrh **       db1 close
38575897234Sdrh **
38675897234Sdrh ** The first command opens a connection to the "my_database" database
38775897234Sdrh ** and calls that connection "db1".  The second command causes this
38875897234Sdrh ** subroutine to be invoked.
38975897234Sdrh */
3906d31316cSdrh static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
391bec3f402Sdrh   SqliteDb *pDb = (SqliteDb*)cd;
3926d31316cSdrh   int choice;
39322fbcb8dSdrh   int rc = TCL_OK;
3940de8c112Sdrh   static const char *DB_strs[] = {
395b5a20d3cSdrh     "authorizer",         "busy",                   "changes",
396aa940eacSdrh     "close",              "commit_hook",            "complete",
397aa940eacSdrh     "errorcode",          "eval",                   "function",
398f146a776Srdc     "last_insert_rowid",  "last_statement_changes", "onecolumn",
399f146a776Srdc     "progress",           "rekey",                  "timeout",
400*7cedc8d4Sdanielk1977     "trace",              "collate",                "collation_needed",
40122fbcb8dSdrh     0
4026d31316cSdrh   };
403411995dcSdrh   enum DB_enum {
404b5a20d3cSdrh     DB_AUTHORIZER,        DB_BUSY,                   DB_CHANGES,
405aa940eacSdrh     DB_CLOSE,             DB_COMMIT_HOOK,            DB_COMPLETE,
406aa940eacSdrh     DB_ERRORCODE,         DB_EVAL,                   DB_FUNCTION,
407f146a776Srdc     DB_LAST_INSERT_ROWID, DB_LAST_STATEMENT_CHANGES, DB_ONECOLUMN,
408f146a776Srdc     DB_PROGRESS,          DB_REKEY,                  DB_TIMEOUT,
409*7cedc8d4Sdanielk1977     DB_TRACE,             DB_COLLATE,                DB_COLLATION_NEEDED
4106d31316cSdrh   };
4116d31316cSdrh 
4126d31316cSdrh   if( objc<2 ){
4136d31316cSdrh     Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
41475897234Sdrh     return TCL_ERROR;
41575897234Sdrh   }
416411995dcSdrh   if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){
4176d31316cSdrh     return TCL_ERROR;
4186d31316cSdrh   }
4196d31316cSdrh 
420411995dcSdrh   switch( (enum DB_enum)choice ){
42175897234Sdrh 
422e22a334bSdrh   /*    $db authorizer ?CALLBACK?
423e22a334bSdrh   **
424e22a334bSdrh   ** Invoke the given callback to authorize each SQL operation as it is
425e22a334bSdrh   ** compiled.  5 arguments are appended to the callback before it is
426e22a334bSdrh   ** invoked:
427e22a334bSdrh   **
428e22a334bSdrh   **   (1) The authorization type (ex: SQLITE_CREATE_TABLE, SQLITE_INSERT, ...)
429e22a334bSdrh   **   (2) First descriptive name (depends on authorization type)
430e22a334bSdrh   **   (3) Second descriptive name
431e22a334bSdrh   **   (4) Name of the database (ex: "main", "temp")
432e22a334bSdrh   **   (5) Name of trigger that is doing the access
433e22a334bSdrh   **
434e22a334bSdrh   ** The callback should return on of the following strings: SQLITE_OK,
435e22a334bSdrh   ** SQLITE_IGNORE, or SQLITE_DENY.  Any other return value is an error.
436e22a334bSdrh   **
437e22a334bSdrh   ** If this method is invoked with no arguments, the current authorization
438e22a334bSdrh   ** callback string is returned.
439e22a334bSdrh   */
440e22a334bSdrh   case DB_AUTHORIZER: {
441e22a334bSdrh     if( objc>3 ){
442e22a334bSdrh       Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
443e22a334bSdrh     }else if( objc==2 ){
444b5a20d3cSdrh       if( pDb->zAuth ){
445e22a334bSdrh         Tcl_AppendResult(interp, pDb->zAuth, 0);
446e22a334bSdrh       }
447e22a334bSdrh     }else{
448e22a334bSdrh       char *zAuth;
449e22a334bSdrh       int len;
450e22a334bSdrh       if( pDb->zAuth ){
451e22a334bSdrh         Tcl_Free(pDb->zAuth);
452e22a334bSdrh       }
453e22a334bSdrh       zAuth = Tcl_GetStringFromObj(objv[2], &len);
454e22a334bSdrh       if( zAuth && len>0 ){
455e22a334bSdrh         pDb->zAuth = Tcl_Alloc( len + 1 );
456e22a334bSdrh         strcpy(pDb->zAuth, zAuth);
457e22a334bSdrh       }else{
458e22a334bSdrh         pDb->zAuth = 0;
459e22a334bSdrh       }
460e22a334bSdrh #ifndef SQLITE_OMIT_AUTHORIZATION
461e22a334bSdrh       if( pDb->zAuth ){
462e22a334bSdrh         pDb->interp = interp;
4636f8a503dSdanielk1977         sqlite3_set_authorizer(pDb->db, auth_callback, pDb);
464e22a334bSdrh       }else{
4656f8a503dSdanielk1977         sqlite3_set_authorizer(pDb->db, 0, 0);
466e22a334bSdrh       }
467e22a334bSdrh #endif
468e22a334bSdrh     }
469e22a334bSdrh     break;
470e22a334bSdrh   }
471e22a334bSdrh 
472bec3f402Sdrh   /*    $db busy ?CALLBACK?
473bec3f402Sdrh   **
474bec3f402Sdrh   ** Invoke the given callback if an SQL statement attempts to open
475bec3f402Sdrh   ** a locked database file.
476bec3f402Sdrh   */
4776d31316cSdrh   case DB_BUSY: {
4786d31316cSdrh     if( objc>3 ){
4796d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "CALLBACK");
480bec3f402Sdrh       return TCL_ERROR;
4816d31316cSdrh     }else if( objc==2 ){
482bec3f402Sdrh       if( pDb->zBusy ){
483bec3f402Sdrh         Tcl_AppendResult(interp, pDb->zBusy, 0);
484bec3f402Sdrh       }
485bec3f402Sdrh     }else{
4866d31316cSdrh       char *zBusy;
4876d31316cSdrh       int len;
488bec3f402Sdrh       if( pDb->zBusy ){
489bec3f402Sdrh         Tcl_Free(pDb->zBusy);
4906d31316cSdrh       }
4916d31316cSdrh       zBusy = Tcl_GetStringFromObj(objv[2], &len);
4926d31316cSdrh       if( zBusy && len>0 ){
4936d31316cSdrh         pDb->zBusy = Tcl_Alloc( len + 1 );
4946d31316cSdrh         strcpy(pDb->zBusy, zBusy);
4956d31316cSdrh       }else{
496bec3f402Sdrh         pDb->zBusy = 0;
497bec3f402Sdrh       }
498bec3f402Sdrh       if( pDb->zBusy ){
499bec3f402Sdrh         pDb->interp = interp;
5006f8a503dSdanielk1977         sqlite3_busy_handler(pDb->db, DbBusyHandler, pDb);
5016d31316cSdrh       }else{
5026f8a503dSdanielk1977         sqlite3_busy_handler(pDb->db, 0, 0);
503bec3f402Sdrh       }
504bec3f402Sdrh     }
5056d31316cSdrh     break;
5066d31316cSdrh   }
507bec3f402Sdrh 
508348bb5d6Sdanielk1977   /*    $db progress ?N CALLBACK?
509348bb5d6Sdanielk1977   **
510348bb5d6Sdanielk1977   ** Invoke the given callback every N virtual machine opcodes while executing
511348bb5d6Sdanielk1977   ** queries.
512348bb5d6Sdanielk1977   */
513348bb5d6Sdanielk1977   case DB_PROGRESS: {
514348bb5d6Sdanielk1977     if( objc==2 ){
515348bb5d6Sdanielk1977       if( pDb->zProgress ){
516348bb5d6Sdanielk1977         Tcl_AppendResult(interp, pDb->zProgress, 0);
517348bb5d6Sdanielk1977       }
518348bb5d6Sdanielk1977     }else if( objc==4 ){
519348bb5d6Sdanielk1977       char *zProgress;
520348bb5d6Sdanielk1977       int len;
521348bb5d6Sdanielk1977       int N;
522348bb5d6Sdanielk1977       if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){
523348bb5d6Sdanielk1977 	return TCL_ERROR;
524348bb5d6Sdanielk1977       };
525348bb5d6Sdanielk1977       if( pDb->zProgress ){
526348bb5d6Sdanielk1977         Tcl_Free(pDb->zProgress);
527348bb5d6Sdanielk1977       }
528348bb5d6Sdanielk1977       zProgress = Tcl_GetStringFromObj(objv[3], &len);
529348bb5d6Sdanielk1977       if( zProgress && len>0 ){
530348bb5d6Sdanielk1977         pDb->zProgress = Tcl_Alloc( len + 1 );
531348bb5d6Sdanielk1977         strcpy(pDb->zProgress, zProgress);
532348bb5d6Sdanielk1977       }else{
533348bb5d6Sdanielk1977         pDb->zProgress = 0;
534348bb5d6Sdanielk1977       }
535348bb5d6Sdanielk1977 #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
536348bb5d6Sdanielk1977       if( pDb->zProgress ){
537348bb5d6Sdanielk1977         pDb->interp = interp;
5386f8a503dSdanielk1977         sqlite3_progress_handler(pDb->db, N, DbProgressHandler, pDb);
539348bb5d6Sdanielk1977       }else{
5406f8a503dSdanielk1977         sqlite3_progress_handler(pDb->db, 0, 0, 0);
541348bb5d6Sdanielk1977       }
542348bb5d6Sdanielk1977 #endif
543348bb5d6Sdanielk1977     }else{
544348bb5d6Sdanielk1977       Tcl_WrongNumArgs(interp, 2, objv, "N CALLBACK");
545348bb5d6Sdanielk1977       return TCL_ERROR;
546348bb5d6Sdanielk1977     }
547348bb5d6Sdanielk1977     break;
548348bb5d6Sdanielk1977   }
549348bb5d6Sdanielk1977 
550c8d30ac1Sdrh   /*
551c8d30ac1Sdrh   **     $db changes
552c8d30ac1Sdrh   **
553c8d30ac1Sdrh   ** Return the number of rows that were modified, inserted, or deleted by
554c8d30ac1Sdrh   ** the most recent "eval".
555c8d30ac1Sdrh   */
556c8d30ac1Sdrh   case DB_CHANGES: {
557c8d30ac1Sdrh     Tcl_Obj *pResult;
558c8d30ac1Sdrh     int nChange;
559c8d30ac1Sdrh     if( objc!=2 ){
560c8d30ac1Sdrh       Tcl_WrongNumArgs(interp, 2, objv, "");
561c8d30ac1Sdrh       return TCL_ERROR;
562c8d30ac1Sdrh     }
56330ccda10Sdanielk1977     /* nChange = sqlite3_changes(pDb->db); */
56430ccda10Sdanielk1977     nChange = pDb->nChange;
565c8d30ac1Sdrh     pResult = Tcl_GetObjResult(interp);
566c8d30ac1Sdrh     Tcl_SetIntObj(pResult, nChange);
567c8d30ac1Sdrh     break;
568c8d30ac1Sdrh   }
569c8d30ac1Sdrh 
570f146a776Srdc   /*
571f146a776Srdc   **     $db last_statement_changes
572f146a776Srdc   **
573f146a776Srdc   ** Return the number of rows that were modified, inserted, or deleted by
574f146a776Srdc   ** the last statment to complete execution (excluding changes due to
575f146a776Srdc   ** triggers)
576f146a776Srdc   */
577f146a776Srdc   case DB_LAST_STATEMENT_CHANGES: {
578f146a776Srdc     Tcl_Obj *pResult;
579f146a776Srdc     int lsChange;
580f146a776Srdc     if( objc!=2 ){
581f146a776Srdc       Tcl_WrongNumArgs(interp, 2, objv, "");
582f146a776Srdc       return TCL_ERROR;
583f146a776Srdc     }
5846f8a503dSdanielk1977     lsChange = sqlite3_last_statement_changes(pDb->db);
585f146a776Srdc     pResult = Tcl_GetObjResult(interp);
586f146a776Srdc     Tcl_SetIntObj(pResult, lsChange);
587f146a776Srdc     break;
588f146a776Srdc   }
589f146a776Srdc 
59075897234Sdrh   /*    $db close
59175897234Sdrh   **
59275897234Sdrh   ** Shutdown the database
59375897234Sdrh   */
5946d31316cSdrh   case DB_CLOSE: {
5956d31316cSdrh     Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0));
5966d31316cSdrh     break;
5976d31316cSdrh   }
59875897234Sdrh 
599aa940eacSdrh   /*    $db commit_hook ?CALLBACK?
600aa940eacSdrh   **
601aa940eacSdrh   ** Invoke the given callback just before committing every SQL transaction.
602aa940eacSdrh   ** If the callback throws an exception or returns non-zero, then the
603aa940eacSdrh   ** transaction is aborted.  If CALLBACK is an empty string, the callback
604aa940eacSdrh   ** is disabled.
605aa940eacSdrh   */
606aa940eacSdrh   case DB_COMMIT_HOOK: {
607aa940eacSdrh     if( objc>3 ){
608aa940eacSdrh       Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
609aa940eacSdrh     }else if( objc==2 ){
610aa940eacSdrh       if( pDb->zCommit ){
611aa940eacSdrh         Tcl_AppendResult(interp, pDb->zCommit, 0);
612aa940eacSdrh       }
613aa940eacSdrh     }else{
614aa940eacSdrh       char *zCommit;
615aa940eacSdrh       int len;
616aa940eacSdrh       if( pDb->zCommit ){
617aa940eacSdrh         Tcl_Free(pDb->zCommit);
618aa940eacSdrh       }
619aa940eacSdrh       zCommit = Tcl_GetStringFromObj(objv[2], &len);
620aa940eacSdrh       if( zCommit && len>0 ){
621aa940eacSdrh         pDb->zCommit = Tcl_Alloc( len + 1 );
622aa940eacSdrh         strcpy(pDb->zCommit, zCommit);
623aa940eacSdrh       }else{
624aa940eacSdrh         pDb->zCommit = 0;
625aa940eacSdrh       }
626aa940eacSdrh       if( pDb->zCommit ){
627aa940eacSdrh         pDb->interp = interp;
6286f8a503dSdanielk1977         sqlite3_commit_hook(pDb->db, DbCommitHandler, pDb);
629aa940eacSdrh       }else{
6306f8a503dSdanielk1977         sqlite3_commit_hook(pDb->db, 0, 0);
631aa940eacSdrh       }
632aa940eacSdrh     }
633aa940eacSdrh     break;
634aa940eacSdrh   }
635aa940eacSdrh 
63675897234Sdrh   /*    $db complete SQL
63775897234Sdrh   **
63875897234Sdrh   ** Return TRUE if SQL is a complete SQL statement.  Return FALSE if
63975897234Sdrh   ** additional lines of input are needed.  This is similar to the
64075897234Sdrh   ** built-in "info complete" command of Tcl.
64175897234Sdrh   */
6426d31316cSdrh   case DB_COMPLETE: {
6436d31316cSdrh     Tcl_Obj *pResult;
6446d31316cSdrh     int isComplete;
6456d31316cSdrh     if( objc!=3 ){
6466d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "SQL");
64775897234Sdrh       return TCL_ERROR;
64875897234Sdrh     }
6496f8a503dSdanielk1977     isComplete = sqlite3_complete( Tcl_GetStringFromObj(objv[2], 0) );
6506d31316cSdrh     pResult = Tcl_GetObjResult(interp);
6516d31316cSdrh     Tcl_SetBooleanObj(pResult, isComplete);
6526d31316cSdrh     break;
6536d31316cSdrh   }
65475897234Sdrh 
65575897234Sdrh   /*
656dcd997eaSdrh   **    $db errorcode
657dcd997eaSdrh   **
658dcd997eaSdrh   ** Return the numeric error code that was returned by the most recent
6596f8a503dSdanielk1977   ** call to sqlite3_exec().
660dcd997eaSdrh   */
661dcd997eaSdrh   case DB_ERRORCODE: {
662dcd997eaSdrh     Tcl_SetObjResult(interp, Tcl_NewIntObj(pDb->rc));
663dcd997eaSdrh     break;
664dcd997eaSdrh   }
665dcd997eaSdrh 
666dcd997eaSdrh   /*
66775897234Sdrh   **    $db eval $sql ?array {  ...code... }?
66875897234Sdrh   **
66975897234Sdrh   ** The SQL statement in $sql is evaluated.  For each row, the values are
670bec3f402Sdrh   ** placed in elements of the array named "array" and ...code... is executed.
67175897234Sdrh   ** If "array" and "code" are omitted, then no callback is every invoked.
67275897234Sdrh   ** If "array" is an empty string, then the values are placed in variables
67375897234Sdrh   ** that have the same name as the fields extracted by the query.
67475897234Sdrh   */
6756d31316cSdrh   case DB_EVAL: {
67630ccda10Sdanielk1977     char const *zSql;
67730ccda10Sdanielk1977     char const *zLeft;
67830ccda10Sdanielk1977     sqlite3_stmt *pStmt;
679ef2cb63eSdanielk1977 
680ef2cb63eSdanielk1977     Tcl_Obj *pRet = Tcl_NewObj();
681ef2cb63eSdanielk1977     Tcl_IncrRefCount(pRet);
68230ccda10Sdanielk1977 
68330ccda10Sdanielk1977     if( objc!=5 && objc!=3 ){
68430ccda10Sdanielk1977       Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME CODE?");
68530ccda10Sdanielk1977       return TCL_ERROR;
68630ccda10Sdanielk1977     }
68730ccda10Sdanielk1977 
68830ccda10Sdanielk1977     pDb->nChange = 0;
68930ccda10Sdanielk1977     zSql = Tcl_GetStringFromObj(objv[2], 0);
69030ccda10Sdanielk1977     while( zSql[0] ){
69130ccda10Sdanielk1977       int i;
69230ccda10Sdanielk1977 
69330ccda10Sdanielk1977       if( SQLITE_OK!=sqlite3_prepare(pDb->db, zSql, -1, &pStmt, &zLeft) ){
694ef2cb63eSdanielk1977         Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
69530ccda10Sdanielk1977         rc = TCL_ERROR;
69630ccda10Sdanielk1977         break;
69730ccda10Sdanielk1977       }
69830ccda10Sdanielk1977 
69930ccda10Sdanielk1977       if( pStmt && objc==5 ){
70030ccda10Sdanielk1977         Tcl_Obj *pColList = Tcl_NewObj();
70130ccda10Sdanielk1977         Tcl_IncrRefCount(pColList);
70230ccda10Sdanielk1977 
70330ccda10Sdanielk1977         for(i=0; i<sqlite3_column_count(pStmt); i++){
70430ccda10Sdanielk1977           Tcl_ListObjAppendElement(interp, pColList,
705ef2cb63eSdanielk1977               dbTextToObj(sqlite3_column_name(pStmt, i))
70630ccda10Sdanielk1977           );
70730ccda10Sdanielk1977         }
70830ccda10Sdanielk1977         Tcl_ObjSetVar2(interp,objv[3],Tcl_NewStringObj("*",-1),pColList,0);
70930ccda10Sdanielk1977       }
71030ccda10Sdanielk1977 
71130ccda10Sdanielk1977       while( pStmt && SQLITE_ROW==sqlite3_step(pStmt) ){
71230ccda10Sdanielk1977         for(i=0; i<sqlite3_column_count(pStmt); i++){
71330ccda10Sdanielk1977           Tcl_Obj *pVal;
71430ccda10Sdanielk1977 
71530ccda10Sdanielk1977           /* Set pVal to contain the i'th column of this row. */
7169c054830Sdrh           if( SQLITE_BLOB!=sqlite3_column_type(pStmt, i) ){
717ef2cb63eSdanielk1977             pVal = dbTextToObj(sqlite3_column_text(pStmt, i));
71830ccda10Sdanielk1977           }else{
7193fd0a736Sdanielk1977             int bytes = sqlite3_column_bytes(pStmt, i);
7203fd0a736Sdanielk1977             pVal = Tcl_NewByteArrayObj(sqlite3_column_blob(pStmt, i), bytes);
72130ccda10Sdanielk1977           }
72230ccda10Sdanielk1977 
72330ccda10Sdanielk1977           if( objc==5 ){
724ef2cb63eSdanielk1977             Tcl_Obj *pName = dbTextToObj(sqlite3_column_name(pStmt, i));
72530ccda10Sdanielk1977             Tcl_IncrRefCount(pName);
72630ccda10Sdanielk1977             if( !strcmp("", Tcl_GetString(objv[3])) ){
72730ccda10Sdanielk1977               Tcl_ObjSetVar2(interp, pName, 0, pVal, 0);
72830ccda10Sdanielk1977             }else{
72930ccda10Sdanielk1977               Tcl_ObjSetVar2(interp, objv[3], pName, pVal, 0);
73030ccda10Sdanielk1977             }
73130ccda10Sdanielk1977             Tcl_DecrRefCount(pName);
73230ccda10Sdanielk1977           }else{
73330ccda10Sdanielk1977             Tcl_ListObjAppendElement(interp, pRet, pVal);
73430ccda10Sdanielk1977           }
73530ccda10Sdanielk1977         }
73630ccda10Sdanielk1977 
73730ccda10Sdanielk1977         if( objc==5 ){
73830ccda10Sdanielk1977           rc = Tcl_EvalObjEx(interp, objv[4], 0);
73930ccda10Sdanielk1977           if( rc!=TCL_ERROR ) rc = TCL_OK;
74030ccda10Sdanielk1977         }
74130ccda10Sdanielk1977       }
74230ccda10Sdanielk1977 
74330ccda10Sdanielk1977       if( pStmt && SQLITE_SCHEMA==sqlite3_finalize(pStmt) ){
74430ccda10Sdanielk1977         continue;
74530ccda10Sdanielk1977       }
74630ccda10Sdanielk1977 
74730ccda10Sdanielk1977       if( pStmt && SQLITE_OK!=sqlite3_errcode(pDb->db) ){
748ef2cb63eSdanielk1977         Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
74930ccda10Sdanielk1977         rc = TCL_ERROR;
75030ccda10Sdanielk1977         break;
75130ccda10Sdanielk1977       }
75230ccda10Sdanielk1977 
75330ccda10Sdanielk1977       pDb->nChange += sqlite3_changes(pDb->db);
75430ccda10Sdanielk1977       zSql = zLeft;
75530ccda10Sdanielk1977     }
75630ccda10Sdanielk1977 
757ef2cb63eSdanielk1977     if( rc==TCL_OK ){
75830ccda10Sdanielk1977       Tcl_SetObjResult(interp, pRet);
75930ccda10Sdanielk1977     }
760ef2cb63eSdanielk1977     Tcl_DecrRefCount(pRet);
76130ccda10Sdanielk1977 
76230ccda10Sdanielk1977     break;
76330ccda10Sdanielk1977   }
764bec3f402Sdrh 
765bec3f402Sdrh   /*
766cabb0819Sdrh   **     $db function NAME SCRIPT
767cabb0819Sdrh   **
768cabb0819Sdrh   ** Create a new SQL function called NAME.  Whenever that function is
769cabb0819Sdrh   ** called, invoke SCRIPT to evaluate the function.
770cabb0819Sdrh   */
771cabb0819Sdrh   case DB_FUNCTION: {
772cabb0819Sdrh     SqlFunc *pFunc;
773cabb0819Sdrh     char *zName;
774cabb0819Sdrh     char *zScript;
775cabb0819Sdrh     int nScript;
776cabb0819Sdrh     if( objc!=4 ){
777cabb0819Sdrh       Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT");
778cabb0819Sdrh       return TCL_ERROR;
779cabb0819Sdrh     }
780cabb0819Sdrh     zName = Tcl_GetStringFromObj(objv[2], 0);
781cabb0819Sdrh     zScript = Tcl_GetStringFromObj(objv[3], &nScript);
782cabb0819Sdrh     pFunc = (SqlFunc*)Tcl_Alloc( sizeof(*pFunc) + nScript + 1 );
783cabb0819Sdrh     if( pFunc==0 ) return TCL_ERROR;
784cabb0819Sdrh     pFunc->interp = interp;
785cabb0819Sdrh     pFunc->pNext = pDb->pFunc;
786cabb0819Sdrh     pFunc->zScript = (char*)&pFunc[1];
787cabb0819Sdrh     strcpy(pFunc->zScript, zScript);
7886590493dSdanielk1977     sqlite3_create_function(pDb->db, zName, -1, 0, 0, pFunc, tclSqlFunc, 0, 0);
789cabb0819Sdrh     break;
790cabb0819Sdrh   }
791cabb0819Sdrh 
792cabb0819Sdrh   /*
793af9ff33aSdrh   **     $db last_insert_rowid
794af9ff33aSdrh   **
795af9ff33aSdrh   ** Return an integer which is the ROWID for the most recent insert.
796af9ff33aSdrh   */
797af9ff33aSdrh   case DB_LAST_INSERT_ROWID: {
798af9ff33aSdrh     Tcl_Obj *pResult;
799af9ff33aSdrh     int rowid;
800af9ff33aSdrh     if( objc!=2 ){
801af9ff33aSdrh       Tcl_WrongNumArgs(interp, 2, objv, "");
802af9ff33aSdrh       return TCL_ERROR;
803af9ff33aSdrh     }
8046f8a503dSdanielk1977     rowid = sqlite3_last_insert_rowid(pDb->db);
805af9ff33aSdrh     pResult = Tcl_GetObjResult(interp);
806af9ff33aSdrh     Tcl_SetIntObj(pResult, rowid);
807af9ff33aSdrh     break;
808af9ff33aSdrh   }
809af9ff33aSdrh 
810af9ff33aSdrh   /*
8115d9d7576Sdrh   **     $db onecolumn SQL
8125d9d7576Sdrh   **
8135d9d7576Sdrh   ** Return a single column from a single row of the given SQL query.
8145d9d7576Sdrh   */
8155d9d7576Sdrh   case DB_ONECOLUMN: {
8165d9d7576Sdrh     char *zSql;
8175d9d7576Sdrh     char *zErrMsg = 0;
8185d9d7576Sdrh     if( objc!=3 ){
8195d9d7576Sdrh       Tcl_WrongNumArgs(interp, 2, objv, "SQL");
8205d9d7576Sdrh       return TCL_ERROR;
8215d9d7576Sdrh     }
8225d9d7576Sdrh     zSql = Tcl_GetStringFromObj(objv[2], 0);
8236f8a503dSdanielk1977     rc = sqlite3_exec(pDb->db, zSql, DbEvalCallback3, interp, &zErrMsg);
8245d9d7576Sdrh     if( rc==SQLITE_ABORT ){
82522fbcb8dSdrh       rc = SQLITE_OK;
8265d9d7576Sdrh     }else if( zErrMsg ){
8275d9d7576Sdrh       Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
8285d9d7576Sdrh       free(zErrMsg);
8295d9d7576Sdrh       rc = TCL_ERROR;
8305d9d7576Sdrh     }else if( rc!=SQLITE_OK ){
831f20b21c8Sdanielk1977       Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);
8325d9d7576Sdrh       rc = TCL_ERROR;
8335d9d7576Sdrh     }
8345d9d7576Sdrh     break;
8355d9d7576Sdrh   }
8365d9d7576Sdrh 
8375d9d7576Sdrh   /*
83822fbcb8dSdrh   **     $db rekey KEY
83922fbcb8dSdrh   **
84022fbcb8dSdrh   ** Change the encryption key on the currently open database.
84122fbcb8dSdrh   */
84222fbcb8dSdrh   case DB_REKEY: {
84322fbcb8dSdrh     int nKey;
84422fbcb8dSdrh     void *pKey;
84522fbcb8dSdrh     if( objc!=3 ){
84622fbcb8dSdrh       Tcl_WrongNumArgs(interp, 2, objv, "KEY");
84722fbcb8dSdrh       return TCL_ERROR;
84822fbcb8dSdrh     }
84922fbcb8dSdrh     pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey);
8509eb9e26bSdrh #ifdef SQLITE_HAS_CODEC
85122fbcb8dSdrh     rc = sqlite_rekey(pDb->db, pKey, nKey);
85222fbcb8dSdrh     if( rc ){
853f20b21c8Sdanielk1977       Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);
85422fbcb8dSdrh       rc = TCL_ERROR;
85522fbcb8dSdrh     }
85622fbcb8dSdrh #endif
85722fbcb8dSdrh     break;
85822fbcb8dSdrh   }
85922fbcb8dSdrh 
86022fbcb8dSdrh   /*
861bec3f402Sdrh   **     $db timeout MILLESECONDS
862bec3f402Sdrh   **
863bec3f402Sdrh   ** Delay for the number of milliseconds specified when a file is locked.
864bec3f402Sdrh   */
8656d31316cSdrh   case DB_TIMEOUT: {
866bec3f402Sdrh     int ms;
8676d31316cSdrh     if( objc!=3 ){
8686d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "MILLISECONDS");
869bec3f402Sdrh       return TCL_ERROR;
87075897234Sdrh     }
8716d31316cSdrh     if( Tcl_GetIntFromObj(interp, objv[2], &ms) ) return TCL_ERROR;
8726f8a503dSdanielk1977     sqlite3_busy_timeout(pDb->db, ms);
8736d31316cSdrh     break;
87475897234Sdrh   }
875b5a20d3cSdrh 
876b5a20d3cSdrh   /*    $db trace ?CALLBACK?
877b5a20d3cSdrh   **
878b5a20d3cSdrh   ** Make arrangements to invoke the CALLBACK routine for each SQL statement
879b5a20d3cSdrh   ** that is executed.  The text of the SQL is appended to CALLBACK before
880b5a20d3cSdrh   ** it is executed.
881b5a20d3cSdrh   */
882b5a20d3cSdrh   case DB_TRACE: {
883b5a20d3cSdrh     if( objc>3 ){
884b5a20d3cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
885b5a20d3cSdrh     }else if( objc==2 ){
886b5a20d3cSdrh       if( pDb->zTrace ){
887b5a20d3cSdrh         Tcl_AppendResult(interp, pDb->zTrace, 0);
888b5a20d3cSdrh       }
889b5a20d3cSdrh     }else{
890b5a20d3cSdrh       char *zTrace;
891b5a20d3cSdrh       int len;
892b5a20d3cSdrh       if( pDb->zTrace ){
893b5a20d3cSdrh         Tcl_Free(pDb->zTrace);
894b5a20d3cSdrh       }
895b5a20d3cSdrh       zTrace = Tcl_GetStringFromObj(objv[2], &len);
896b5a20d3cSdrh       if( zTrace && len>0 ){
897b5a20d3cSdrh         pDb->zTrace = Tcl_Alloc( len + 1 );
898b5a20d3cSdrh         strcpy(pDb->zTrace, zTrace);
899b5a20d3cSdrh       }else{
900b5a20d3cSdrh         pDb->zTrace = 0;
901b5a20d3cSdrh       }
902b5a20d3cSdrh       if( pDb->zTrace ){
903b5a20d3cSdrh         pDb->interp = interp;
9046f8a503dSdanielk1977         sqlite3_trace(pDb->db, DbTraceHandler, pDb);
905b5a20d3cSdrh       }else{
9066f8a503dSdanielk1977         sqlite3_trace(pDb->db, 0, 0);
907b5a20d3cSdrh       }
908b5a20d3cSdrh     }
909b5a20d3cSdrh     break;
910b5a20d3cSdrh   }
911b5a20d3cSdrh 
9120202b29eSdanielk1977   /*
9130202b29eSdanielk1977   **     $db collate NAME SCRIPT
9140202b29eSdanielk1977   **
9150202b29eSdanielk1977   ** Create a new SQL collation function called NAME.  Whenever
9160202b29eSdanielk1977   ** that function is called, invoke SCRIPT to evaluate the function.
9170202b29eSdanielk1977   */
9180202b29eSdanielk1977   case DB_COLLATE: {
9190202b29eSdanielk1977     SqlCollate *pCollate;
9200202b29eSdanielk1977     char *zName;
9210202b29eSdanielk1977     char *zScript;
9220202b29eSdanielk1977     int nScript;
9230202b29eSdanielk1977     if( objc!=4 ){
9240202b29eSdanielk1977       Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT");
9250202b29eSdanielk1977       return TCL_ERROR;
9260202b29eSdanielk1977     }
9270202b29eSdanielk1977     zName = Tcl_GetStringFromObj(objv[2], 0);
9280202b29eSdanielk1977     zScript = Tcl_GetStringFromObj(objv[3], &nScript);
9290202b29eSdanielk1977     pCollate = (SqlCollate*)Tcl_Alloc( sizeof(*pCollate) + nScript + 1 );
9300202b29eSdanielk1977     if( pCollate==0 ) return TCL_ERROR;
9310202b29eSdanielk1977     pCollate->interp = interp;
9320202b29eSdanielk1977     pCollate->pNext = pDb->pCollate;
9330202b29eSdanielk1977     pCollate->zScript = (char*)&pCollate[1];
9340202b29eSdanielk1977     strcpy(pCollate->zScript, zScript);
935466be56bSdanielk1977     if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8,
936466be56bSdanielk1977         pCollate, tclSqlCollate) ){
9370202b29eSdanielk1977       return TCL_ERROR;
9380202b29eSdanielk1977     }
9390202b29eSdanielk1977     break;
9400202b29eSdanielk1977   }
9410202b29eSdanielk1977 
942*7cedc8d4Sdanielk1977   /*
943*7cedc8d4Sdanielk1977   **     $db collate_needed SCRIPT
944*7cedc8d4Sdanielk1977   **
945*7cedc8d4Sdanielk1977   ** Create a new SQL collation function called NAME.  Whenever
946*7cedc8d4Sdanielk1977   ** that function is called, invoke SCRIPT to evaluate the function.
947*7cedc8d4Sdanielk1977   */
948*7cedc8d4Sdanielk1977   case DB_COLLATION_NEEDED: {
949*7cedc8d4Sdanielk1977     if( objc!=3 ){
950*7cedc8d4Sdanielk1977       Tcl_WrongNumArgs(interp, 2, objv, "SCRIPT");
951*7cedc8d4Sdanielk1977       return TCL_ERROR;
952*7cedc8d4Sdanielk1977     }
953*7cedc8d4Sdanielk1977     if( pDb->pCollateNeeded ){
954*7cedc8d4Sdanielk1977       Tcl_DecrRefCount(pDb->pCollateNeeded);
955*7cedc8d4Sdanielk1977     }
956*7cedc8d4Sdanielk1977     pDb->pCollateNeeded = Tcl_DuplicateObj(objv[2]);
957*7cedc8d4Sdanielk1977     Tcl_IncrRefCount(pDb->pCollateNeeded);
958*7cedc8d4Sdanielk1977     sqlite3_collation_needed(pDb->db, pDb, tclCollateNeeded);
959*7cedc8d4Sdanielk1977     break;
960*7cedc8d4Sdanielk1977   }
961*7cedc8d4Sdanielk1977 
9626d31316cSdrh   } /* End of the SWITCH statement */
96322fbcb8dSdrh   return rc;
96475897234Sdrh }
96575897234Sdrh 
96675897234Sdrh /*
96722fbcb8dSdrh **   sqlite DBNAME FILENAME ?MODE? ?-key KEY?
96875897234Sdrh **
96975897234Sdrh ** This is the main Tcl command.  When the "sqlite" Tcl command is
97075897234Sdrh ** invoked, this routine runs to process that command.
97175897234Sdrh **
97275897234Sdrh ** The first argument, DBNAME, is an arbitrary name for a new
97375897234Sdrh ** database connection.  This command creates a new command named
97475897234Sdrh ** DBNAME that is used to control that connection.  The database
97575897234Sdrh ** connection is deleted when the DBNAME command is deleted.
97675897234Sdrh **
97775897234Sdrh ** The second argument is the name of the directory that contains
97875897234Sdrh ** the sqlite database that is to be accessed.
979fbc3eab8Sdrh **
980fbc3eab8Sdrh ** For testing purposes, we also support the following:
981fbc3eab8Sdrh **
982fbc3eab8Sdrh **  sqlite -encoding
983fbc3eab8Sdrh **
984fbc3eab8Sdrh **       Return the encoding used by LIKE and GLOB operators.  Choices
985fbc3eab8Sdrh **       are UTF-8 and iso8859.
986fbc3eab8Sdrh **
987647cb0e1Sdrh **  sqlite -version
988647cb0e1Sdrh **
989647cb0e1Sdrh **       Return the version number of the SQLite library.
990647cb0e1Sdrh **
991fbc3eab8Sdrh **  sqlite -tcl-uses-utf
992fbc3eab8Sdrh **
993fbc3eab8Sdrh **       Return "1" if compiled with a Tcl uses UTF-8.  Return "0" if
994fbc3eab8Sdrh **       not.  Used by tests to make sure the library was compiled
995fbc3eab8Sdrh **       correctly.
99675897234Sdrh */
99722fbcb8dSdrh static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
998bec3f402Sdrh   SqliteDb *p;
99922fbcb8dSdrh   void *pKey = 0;
100022fbcb8dSdrh   int nKey = 0;
100122fbcb8dSdrh   const char *zArg;
100275897234Sdrh   char *zErrMsg;
100322fbcb8dSdrh   const char *zFile;
100406b2718aSdrh   char zBuf[80];
100522fbcb8dSdrh   if( objc==2 ){
100622fbcb8dSdrh     zArg = Tcl_GetStringFromObj(objv[1], 0);
100722fbcb8dSdrh     if( strcmp(zArg,"-version")==0 ){
10086f8a503dSdanielk1977       Tcl_AppendResult(interp,sqlite3_version,0);
1009647cb0e1Sdrh       return TCL_OK;
1010647cb0e1Sdrh     }
10119eb9e26bSdrh     if( strcmp(zArg,"-has-codec")==0 ){
10129eb9e26bSdrh #ifdef SQLITE_HAS_CODEC
101322fbcb8dSdrh       Tcl_AppendResult(interp,"1",0);
101422fbcb8dSdrh #else
101522fbcb8dSdrh       Tcl_AppendResult(interp,"0",0);
101622fbcb8dSdrh #endif
101722fbcb8dSdrh       return TCL_OK;
101822fbcb8dSdrh     }
101922fbcb8dSdrh     if( strcmp(zArg,"-tcl-uses-utf")==0 ){
1020fbc3eab8Sdrh #ifdef TCL_UTF_MAX
1021fbc3eab8Sdrh       Tcl_AppendResult(interp,"1",0);
1022fbc3eab8Sdrh #else
1023fbc3eab8Sdrh       Tcl_AppendResult(interp,"0",0);
1024fbc3eab8Sdrh #endif
1025fbc3eab8Sdrh       return TCL_OK;
1026fbc3eab8Sdrh     }
1027fbc3eab8Sdrh   }
102822fbcb8dSdrh   if( objc==5 || objc==6 ){
102922fbcb8dSdrh     zArg = Tcl_GetStringFromObj(objv[objc-2], 0);
103022fbcb8dSdrh     if( strcmp(zArg,"-key")==0 ){
103122fbcb8dSdrh       pKey = Tcl_GetByteArrayFromObj(objv[objc-1], &nKey);
103222fbcb8dSdrh       objc -= 2;
103322fbcb8dSdrh     }
103422fbcb8dSdrh   }
103522fbcb8dSdrh   if( objc!=3 && objc!=4 ){
103622fbcb8dSdrh     Tcl_WrongNumArgs(interp, 1, objv,
10379eb9e26bSdrh #ifdef SQLITE_HAS_CODEC
10389eb9e26bSdrh       "HANDLE FILENAME ?-key CODEC-KEY?"
103922fbcb8dSdrh #else
104022fbcb8dSdrh       "HANDLE FILENAME ?MODE?"
104122fbcb8dSdrh #endif
104222fbcb8dSdrh     );
104375897234Sdrh     return TCL_ERROR;
104475897234Sdrh   }
104575897234Sdrh   zErrMsg = 0;
10464cdc9e84Sdrh   p = (SqliteDb*)Tcl_Alloc( sizeof(*p) );
104775897234Sdrh   if( p==0 ){
1048bec3f402Sdrh     Tcl_SetResult(interp, "malloc failed", TCL_STATIC);
1049bec3f402Sdrh     return TCL_ERROR;
1050bec3f402Sdrh   }
1051bec3f402Sdrh   memset(p, 0, sizeof(*p));
105222fbcb8dSdrh   zFile = Tcl_GetStringFromObj(objv[2], 0);
10539eb9e26bSdrh #ifdef SQLITE_HAS_CODEC
10546f8a503dSdanielk1977   p->db = sqlite3_open_encrypted(zFile, pKey, nKey, 0, &zErrMsg);
1055eb8ed70dSdrh #else
10564f057f90Sdanielk1977   sqlite3_open(zFile, &p->db);
105780290863Sdanielk1977   if( SQLITE_OK!=sqlite3_errcode(p->db) ){
105880290863Sdanielk1977     zErrMsg = strdup(sqlite3_errmsg(p->db));
105980290863Sdanielk1977     sqlite3_close(p->db);
106080290863Sdanielk1977     p->db = 0;
106180290863Sdanielk1977   }
1062eb8ed70dSdrh #endif
1063bec3f402Sdrh   if( p->db==0 ){
106475897234Sdrh     Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
1065bec3f402Sdrh     Tcl_Free((char*)p);
106675897234Sdrh     free(zErrMsg);
106775897234Sdrh     return TCL_ERROR;
106875897234Sdrh   }
106922fbcb8dSdrh   zArg = Tcl_GetStringFromObj(objv[1], 0);
107022fbcb8dSdrh   Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd);
1071c22bd47dSdrh 
107206b2718aSdrh   /* The return value is the value of the sqlite* pointer
107306b2718aSdrh   */
107406b2718aSdrh   sprintf(zBuf, "%p", p->db);
10755e5377fbSdrh   if( strncmp(zBuf,"0x",2) ){
10765e5377fbSdrh     sprintf(zBuf, "0x%p", p->db);
10775e5377fbSdrh   }
107806b2718aSdrh   Tcl_AppendResult(interp, zBuf, 0);
107906b2718aSdrh 
1080c22bd47dSdrh   /* If compiled with SQLITE_TEST turned on, then register the "md5sum"
108106b2718aSdrh   ** SQL function.
1082c22bd47dSdrh   */
108328b4e489Sdrh #ifdef SQLITE_TEST
108428b4e489Sdrh   {
108528b4e489Sdrh     extern void Md5_Register(sqlite*);
108628b4e489Sdrh     Md5_Register(p->db);
108728b4e489Sdrh    }
108828b4e489Sdrh #endif
1089*7cedc8d4Sdanielk1977   p->interp = interp;
109075897234Sdrh   return TCL_OK;
109175897234Sdrh }
109275897234Sdrh 
109375897234Sdrh /*
109490ca9753Sdrh ** Provide a dummy Tcl_InitStubs if we are using this as a static
109590ca9753Sdrh ** library.
109690ca9753Sdrh */
109790ca9753Sdrh #ifndef USE_TCL_STUBS
109890ca9753Sdrh # undef  Tcl_InitStubs
109990ca9753Sdrh # define Tcl_InitStubs(a,b,c)
110090ca9753Sdrh #endif
110190ca9753Sdrh 
110290ca9753Sdrh /*
110375897234Sdrh ** Initialize this module.
110475897234Sdrh **
110575897234Sdrh ** This Tcl module contains only a single new Tcl command named "sqlite".
110675897234Sdrh ** (Hence there is no namespace.  There is no point in using a namespace
110775897234Sdrh ** if the extension only supplies one new name!)  The "sqlite" command is
110875897234Sdrh ** used to open a new SQLite database.  See the DbMain() routine above
110975897234Sdrh ** for additional information.
111075897234Sdrh */
111175897234Sdrh int Sqlite_Init(Tcl_Interp *interp){
111290ca9753Sdrh   Tcl_InitStubs(interp, "8.0", 0);
111322fbcb8dSdrh   Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0);
11146d4abfbeSdrh   Tcl_PkgProvide(interp, "sqlite", "2.0");
111590ca9753Sdrh   return TCL_OK;
111690ca9753Sdrh }
111790ca9753Sdrh int Tclsqlite_Init(Tcl_Interp *interp){
111890ca9753Sdrh   Tcl_InitStubs(interp, "8.0", 0);
111922fbcb8dSdrh   Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0);
11206d4abfbeSdrh   Tcl_PkgProvide(interp, "sqlite", "2.0");
112175897234Sdrh   return TCL_OK;
112275897234Sdrh }
112375897234Sdrh int Sqlite_SafeInit(Tcl_Interp *interp){
112475897234Sdrh   return TCL_OK;
112575897234Sdrh }
112690ca9753Sdrh int Tclsqlite_SafeInit(Tcl_Interp *interp){
112790ca9753Sdrh   return TCL_OK;
112890ca9753Sdrh }
112975897234Sdrh 
11303cebbde3Sdrh #if 0
113175897234Sdrh /*
113275897234Sdrh ** If compiled using mktclapp, this routine runs to initialize
113375897234Sdrh ** everything.
113475897234Sdrh */
113575897234Sdrh int Et_AppInit(Tcl_Interp *interp){
113675897234Sdrh   return Sqlite_Init(interp);
113775897234Sdrh }
11383cebbde3Sdrh #endif
1139348784efSdrh 
1140348784efSdrh /*
1141348784efSdrh ** If the macro TCLSH is defined and is one, then put in code for the
1142348784efSdrh ** "main" routine that will initialize Tcl.
1143348784efSdrh */
1144348784efSdrh #if defined(TCLSH) && TCLSH==1
1145348784efSdrh static char zMainloop[] =
1146348784efSdrh   "set line {}\n"
1147348784efSdrh   "while {![eof stdin]} {\n"
1148348784efSdrh     "if {$line!=\"\"} {\n"
1149348784efSdrh       "puts -nonewline \"> \"\n"
1150348784efSdrh     "} else {\n"
1151348784efSdrh       "puts -nonewline \"% \"\n"
1152348784efSdrh     "}\n"
1153348784efSdrh     "flush stdout\n"
1154348784efSdrh     "append line [gets stdin]\n"
1155348784efSdrh     "if {[info complete $line]} {\n"
1156348784efSdrh       "if {[catch {uplevel #0 $line} result]} {\n"
1157348784efSdrh         "puts stderr \"Error: $result\"\n"
1158348784efSdrh       "} elseif {$result!=\"\"} {\n"
1159348784efSdrh         "puts $result\n"
1160348784efSdrh       "}\n"
1161348784efSdrh       "set line {}\n"
1162348784efSdrh     "} else {\n"
1163348784efSdrh       "append line \\n\n"
1164348784efSdrh     "}\n"
1165348784efSdrh   "}\n"
1166348784efSdrh ;
1167348784efSdrh 
1168348784efSdrh #define TCLSH_MAIN main   /* Needed to fake out mktclapp */
1169348784efSdrh int TCLSH_MAIN(int argc, char **argv){
1170348784efSdrh   Tcl_Interp *interp;
1171297ecf14Sdrh   Tcl_FindExecutable(argv[0]);
1172348784efSdrh   interp = Tcl_CreateInterp();
11734adee20fSdanielk1977   Sqlite_Init(interp);
1174d9b0257aSdrh #ifdef SQLITE_TEST
1175d1bf3512Sdrh   {
1176d1bf3512Sdrh     extern int Sqlitetest1_Init(Tcl_Interp*);
11775c4d9703Sdrh     extern int Sqlitetest2_Init(Tcl_Interp*);
11785c4d9703Sdrh     extern int Sqlitetest3_Init(Tcl_Interp*);
1179a6064dcfSdrh     extern int Sqlitetest4_Init(Tcl_Interp*);
1180998b56c3Sdanielk1977     extern int Sqlitetest5_Init(Tcl_Interp*);
1181efc251daSdrh     extern int Md5_Init(Tcl_Interp*);
11826490bebdSdanielk1977     Sqlitetest1_Init(interp);
11835c4d9703Sdrh     Sqlitetest2_Init(interp);
1184de647130Sdrh     Sqlitetest3_Init(interp);
1185fc57d7bfSdanielk1977     Sqlitetest4_Init(interp);
1186998b56c3Sdanielk1977     Sqlitetest5_Init(interp);
1187efc251daSdrh     Md5_Init(interp);
1188d1bf3512Sdrh   }
1189d1bf3512Sdrh #endif
1190348784efSdrh   if( argc>=2 ){
1191348784efSdrh     int i;
1192348784efSdrh     Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY);
1193348784efSdrh     Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
1194348784efSdrh     for(i=2; i<argc; i++){
1195348784efSdrh       Tcl_SetVar(interp, "argv", argv[i],
1196348784efSdrh           TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
1197348784efSdrh     }
1198348784efSdrh     if( Tcl_EvalFile(interp, argv[1])!=TCL_OK ){
11990de8c112Sdrh       const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
1200c61053b7Sdrh       if( zInfo==0 ) zInfo = interp->result;
1201c61053b7Sdrh       fprintf(stderr,"%s: %s\n", *argv, zInfo);
1202348784efSdrh       return 1;
1203348784efSdrh     }
1204348784efSdrh   }else{
1205348784efSdrh     Tcl_GlobalEval(interp, zMainloop);
1206348784efSdrh   }
1207348784efSdrh   return 0;
1208348784efSdrh }
1209348784efSdrh #endif /* TCLSH */
12106d31316cSdrh 
12116d31316cSdrh #endif /* !defined(NO_TCL) */
1212