xref: /sqlite-3.40.0/src/tclsqlite.c (revision 3fd0a736)
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*3fd0a736Sdanielk1977 ** $Id: tclsqlite.c,v 1.75 2004/05/27 13:35:20 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 
786d4abfbeSdrh #ifdef UTF_TRANSLATION_NEEDED
79297ecf14Sdrh /*
8075897234Sdrh ** Called for each row of the result.
816d4abfbeSdrh **
826d4abfbeSdrh ** This version is used when TCL expects UTF-8 data but the database
836d4abfbeSdrh ** uses the ISO8859 format.  A translation must occur from ISO8859 into
846d4abfbeSdrh ** UTF-8.
8575897234Sdrh */
8675897234Sdrh static int DbEvalCallback(
8775897234Sdrh   void *clientData,      /* An instance of CallbackData */
8875897234Sdrh   int nCol,              /* Number of columns in the result */
8975897234Sdrh   char ** azCol,         /* Data for each column */
9075897234Sdrh   char ** azN            /* Name for each column */
9175897234Sdrh ){
9275897234Sdrh   CallbackData *cbData = (CallbackData*)clientData;
9375897234Sdrh   int i, rc;
94297ecf14Sdrh   Tcl_DString dCol;
956d4abfbeSdrh   Tcl_DStringInit(&dCol);
96ce927065Sdrh   if( cbData->azColName==0 ){
97ce927065Sdrh     assert( cbData->once );
98ce927065Sdrh     cbData->once = 0;
99ce927065Sdrh     if( cbData->zArray[0] ){
1006d4abfbeSdrh       Tcl_SetVar2(cbData->interp, cbData->zArray, "*", "", 0);
101ce927065Sdrh     }
1026d4abfbeSdrh     cbData->azColName = malloc( nCol*sizeof(char*) );
1036d4abfbeSdrh     if( cbData->azColName==0 ){ return 1; }
1046d4abfbeSdrh     cbData->nColName = nCol;
1056d4abfbeSdrh     for(i=0; i<nCol; i++){
1066d4abfbeSdrh       Tcl_ExternalToUtfDString(NULL, azN[i], -1, &dCol);
1076d4abfbeSdrh       cbData->azColName[i] = malloc( Tcl_DStringLength(&dCol) + 1 );
1086d4abfbeSdrh       if( cbData->azColName[i] ){
1096d4abfbeSdrh         strcpy(cbData->azColName[i], Tcl_DStringValue(&dCol));
110ce927065Sdrh       }else{
111ce927065Sdrh         return 1;
1126d4abfbeSdrh       }
113ce927065Sdrh       if( cbData->zArray[0] ){
114ce927065Sdrh         Tcl_SetVar2(cbData->interp, cbData->zArray, "*",
115ce927065Sdrh              Tcl_DStringValue(&dCol), TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
116704027f1Sdrh         if( azN[nCol]!=0 ){
1175080aaa7Sdrh           Tcl_DString dType;
1185080aaa7Sdrh           Tcl_DStringInit(&dType);
119fa173a76Sdrh           Tcl_DStringAppend(&dType, "typeof:", -1);
120fa173a76Sdrh           Tcl_DStringAppend(&dType, Tcl_DStringValue(&dCol), -1);
121fa173a76Sdrh           Tcl_DStringFree(&dCol);
1225080aaa7Sdrh           Tcl_ExternalToUtfDString(NULL, azN[i+nCol], -1, &dCol);
123fa173a76Sdrh           Tcl_SetVar2(cbData->interp, cbData->zArray,
124fa173a76Sdrh                Tcl_DStringValue(&dType), Tcl_DStringValue(&dCol),
125fa173a76Sdrh                TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
126fa173a76Sdrh           Tcl_DStringFree(&dType);
1276d4abfbeSdrh         }
1285080aaa7Sdrh       }
129fa173a76Sdrh 
1306d4abfbeSdrh       Tcl_DStringFree(&dCol);
1316d4abfbeSdrh     }
1326d4abfbeSdrh   }
1336d4abfbeSdrh   if( azCol!=0 ){
1346d4abfbeSdrh     if( cbData->zArray[0] ){
1356d4abfbeSdrh       for(i=0; i<nCol; i++){
1366d4abfbeSdrh         char *z = azCol[i];
1376d4abfbeSdrh         if( z==0 ) z = "";
1386d4abfbeSdrh         Tcl_DStringInit(&dCol);
1396d4abfbeSdrh         Tcl_ExternalToUtfDString(NULL, z, -1, &dCol);
1406d4abfbeSdrh         Tcl_SetVar2(cbData->interp, cbData->zArray, cbData->azColName[i],
1416d4abfbeSdrh               Tcl_DStringValue(&dCol), 0);
1426d4abfbeSdrh         Tcl_DStringFree(&dCol);
1436d4abfbeSdrh       }
1446d4abfbeSdrh     }else{
1456d4abfbeSdrh       for(i=0; i<nCol; i++){
1466d4abfbeSdrh         char *z = azCol[i];
1476d4abfbeSdrh         if( z==0 ) z = "";
1486d4abfbeSdrh         Tcl_DStringInit(&dCol);
1496d4abfbeSdrh         Tcl_ExternalToUtfDString(NULL, z, -1, &dCol);
1506d4abfbeSdrh         Tcl_SetVar(cbData->interp, cbData->azColName[i],
1516d4abfbeSdrh                    Tcl_DStringValue(&dCol), 0);
1526d4abfbeSdrh         Tcl_DStringFree(&dCol);
1536d4abfbeSdrh       }
1546d4abfbeSdrh     }
1556d4abfbeSdrh   }
1566d4abfbeSdrh   rc = Tcl_EvalObj(cbData->interp, cbData->pCode);
1576d4abfbeSdrh   if( rc==TCL_CONTINUE ) rc = TCL_OK;
1586d4abfbeSdrh   cbData->tcl_rc = rc;
1596d4abfbeSdrh   return rc!=TCL_OK;
1606d4abfbeSdrh }
1616d4abfbeSdrh #endif /* UTF_TRANSLATION_NEEDED */
1626d4abfbeSdrh 
1636d4abfbeSdrh #ifndef UTF_TRANSLATION_NEEDED
1646d4abfbeSdrh /*
1656d4abfbeSdrh ** Called for each row of the result.
1666d4abfbeSdrh **
1676d4abfbeSdrh ** This version is used when either of the following is true:
1686d4abfbeSdrh **
1696d4abfbeSdrh **    (1) This version of TCL uses UTF-8 and the data in the
1706d4abfbeSdrh **        SQLite database is already in the UTF-8 format.
1716d4abfbeSdrh **
1726d4abfbeSdrh **    (2) This version of TCL uses ISO8859 and the data in the
1736d4abfbeSdrh **        SQLite database is already in the ISO8859 format.
1746d4abfbeSdrh */
1756d4abfbeSdrh static int DbEvalCallback(
1766d4abfbeSdrh   void *clientData,      /* An instance of CallbackData */
1776d4abfbeSdrh   int nCol,              /* Number of columns in the result */
1786d4abfbeSdrh   char ** azCol,         /* Data for each column */
1796d4abfbeSdrh   char ** azN            /* Name for each column */
1806d4abfbeSdrh ){
1816d4abfbeSdrh   CallbackData *cbData = (CallbackData*)clientData;
1826d4abfbeSdrh   int i, rc;
1836a535340Sdrh   if( azCol==0 || (cbData->once && cbData->zArray[0]) ){
1849b0d0a8bSdrh     Tcl_SetVar2(cbData->interp, cbData->zArray, "*", "", 0);
18575897234Sdrh     for(i=0; i<nCol; i++){
18675897234Sdrh       Tcl_SetVar2(cbData->interp, cbData->zArray, "*", azN[i],
18775897234Sdrh          TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
1885080aaa7Sdrh       if( azN[nCol] ){
1896f8a503dSdanielk1977         char *z = sqlite3_mprintf("typeof:%s", azN[i]);
1905080aaa7Sdrh         Tcl_SetVar2(cbData->interp, cbData->zArray, z, azN[i+nCol],
191fa173a76Sdrh            TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
1926f8a503dSdanielk1977         sqlite3_freemem(z);
19375897234Sdrh       }
1945080aaa7Sdrh     }
1956a535340Sdrh     cbData->once = 0;
19675897234Sdrh   }
1976a535340Sdrh   if( azCol!=0 ){
1986a535340Sdrh     if( cbData->zArray[0] ){
19975897234Sdrh       for(i=0; i<nCol; i++){
200c61053b7Sdrh         char *z = azCol[i];
201c61053b7Sdrh         if( z==0 ) z = "";
202c61053b7Sdrh         Tcl_SetVar2(cbData->interp, cbData->zArray, azN[i], z, 0);
20375897234Sdrh       }
20475897234Sdrh     }else{
20575897234Sdrh       for(i=0; i<nCol; i++){
206c61053b7Sdrh         char *z = azCol[i];
207c61053b7Sdrh         if( z==0 ) z = "";
208c61053b7Sdrh         Tcl_SetVar(cbData->interp, azN[i], z, 0);
20975897234Sdrh       }
21075897234Sdrh     }
2116a535340Sdrh   }
2126d31316cSdrh   rc = Tcl_EvalObj(cbData->interp, cbData->pCode);
213960e8c63Sdrh   if( rc==TCL_CONTINUE ) rc = TCL_OK;
214960e8c63Sdrh   cbData->tcl_rc = rc;
215960e8c63Sdrh   return rc!=TCL_OK;
21675897234Sdrh }
2176d4abfbeSdrh #endif
21875897234Sdrh 
21975897234Sdrh /*
2206d31316cSdrh ** This is an alternative callback for database queries.  Instead
2216d31316cSdrh ** of invoking a TCL script to handle the result, this callback just
2226d31316cSdrh ** appends each column of the result to a list.  After the query
2236d31316cSdrh ** is complete, the list is returned.
2246d31316cSdrh */
2256d31316cSdrh static int DbEvalCallback2(
2266d31316cSdrh   void *clientData,      /* An instance of CallbackData */
2276d31316cSdrh   int nCol,              /* Number of columns in the result */
2286d31316cSdrh   char ** azCol,         /* Data for each column */
2296d31316cSdrh   char ** azN            /* Name for each column */
2306d31316cSdrh ){
2316d31316cSdrh   Tcl_Obj *pList = (Tcl_Obj*)clientData;
2326d31316cSdrh   int i;
2336a535340Sdrh   if( azCol==0 ) return 0;
2346d31316cSdrh   for(i=0; i<nCol; i++){
2356d31316cSdrh     Tcl_Obj *pElem;
2366d31316cSdrh     if( azCol[i] && *azCol[i] ){
237297ecf14Sdrh #ifdef UTF_TRANSLATION_NEEDED
238297ecf14Sdrh       Tcl_DString dCol;
239297ecf14Sdrh       Tcl_DStringInit(&dCol);
240297ecf14Sdrh       Tcl_ExternalToUtfDString(NULL, azCol[i], -1, &dCol);
241297ecf14Sdrh       pElem = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1);
242297ecf14Sdrh       Tcl_DStringFree(&dCol);
243297ecf14Sdrh #else
2446d31316cSdrh       pElem = Tcl_NewStringObj(azCol[i], -1);
245297ecf14Sdrh #endif
2466d31316cSdrh     }else{
2476d31316cSdrh       pElem = Tcl_NewObj();
2486d31316cSdrh     }
2496d31316cSdrh     Tcl_ListObjAppendElement(0, pList, pElem);
2506d31316cSdrh   }
2516d31316cSdrh   return 0;
2526d31316cSdrh }
2536d31316cSdrh 
2546d31316cSdrh /*
2555d9d7576Sdrh ** This is a second alternative callback for database queries.  A the
2565d9d7576Sdrh ** first column of the first row of the result is made the TCL result.
2575d9d7576Sdrh */
2585d9d7576Sdrh static int DbEvalCallback3(
2595d9d7576Sdrh   void *clientData,      /* An instance of CallbackData */
2605d9d7576Sdrh   int nCol,              /* Number of columns in the result */
2615d9d7576Sdrh   char ** azCol,         /* Data for each column */
2625d9d7576Sdrh   char ** azN            /* Name for each column */
2635d9d7576Sdrh ){
2645d9d7576Sdrh   Tcl_Interp *interp = (Tcl_Interp*)clientData;
2655d9d7576Sdrh   Tcl_Obj *pElem;
2665d9d7576Sdrh   if( azCol==0 ) return 1;
2675d9d7576Sdrh   if( nCol==0 ) return 1;
2685d9d7576Sdrh #ifdef UTF_TRANSLATION_NEEDED
2695d9d7576Sdrh   {
2705d9d7576Sdrh     Tcl_DString dCol;
2715d9d7576Sdrh     Tcl_DStringInit(&dCol);
2725d9d7576Sdrh     Tcl_ExternalToUtfDString(NULL, azCol[0], -1, &dCol);
2735d9d7576Sdrh     pElem = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1);
2745d9d7576Sdrh     Tcl_DStringFree(&dCol);
2755d9d7576Sdrh   }
2765d9d7576Sdrh #else
2775d9d7576Sdrh   pElem = Tcl_NewStringObj(azCol[0], -1);
2785d9d7576Sdrh #endif
2795d9d7576Sdrh   Tcl_SetObjResult(interp, pElem);
2805d9d7576Sdrh   return 1;
2815d9d7576Sdrh }
2825d9d7576Sdrh 
2835d9d7576Sdrh /*
28475897234Sdrh ** Called when the command is deleted.
28575897234Sdrh */
28675897234Sdrh static void DbDeleteCmd(void *db){
287bec3f402Sdrh   SqliteDb *pDb = (SqliteDb*)db;
2886f8a503dSdanielk1977   sqlite3_close(pDb->db);
289cabb0819Sdrh   while( pDb->pFunc ){
290cabb0819Sdrh     SqlFunc *pFunc = pDb->pFunc;
291cabb0819Sdrh     pDb->pFunc = pFunc->pNext;
292cabb0819Sdrh     Tcl_Free((char*)pFunc);
293cabb0819Sdrh   }
294bec3f402Sdrh   if( pDb->zBusy ){
295bec3f402Sdrh     Tcl_Free(pDb->zBusy);
296bec3f402Sdrh   }
297b5a20d3cSdrh   if( pDb->zTrace ){
298b5a20d3cSdrh     Tcl_Free(pDb->zTrace);
2990d1a643aSdrh   }
300e22a334bSdrh   if( pDb->zAuth ){
301e22a334bSdrh     Tcl_Free(pDb->zAuth);
302e22a334bSdrh   }
303bec3f402Sdrh   Tcl_Free((char*)pDb);
304bec3f402Sdrh }
305bec3f402Sdrh 
306bec3f402Sdrh /*
307bec3f402Sdrh ** This routine is called when a database file is locked while trying
308bec3f402Sdrh ** to execute SQL.
309bec3f402Sdrh */
310bec3f402Sdrh static int DbBusyHandler(void *cd, const char *zTable, int nTries){
311bec3f402Sdrh   SqliteDb *pDb = (SqliteDb*)cd;
312bec3f402Sdrh   int rc;
313bec3f402Sdrh   char zVal[30];
314bec3f402Sdrh   char *zCmd;
315bec3f402Sdrh   Tcl_DString cmd;
316bec3f402Sdrh 
317bec3f402Sdrh   Tcl_DStringInit(&cmd);
318bec3f402Sdrh   Tcl_DStringAppend(&cmd, pDb->zBusy, -1);
319bec3f402Sdrh   Tcl_DStringAppendElement(&cmd, zTable);
320bec3f402Sdrh   sprintf(zVal, " %d", nTries);
321bec3f402Sdrh   Tcl_DStringAppend(&cmd, zVal, -1);
322bec3f402Sdrh   zCmd = Tcl_DStringValue(&cmd);
323bec3f402Sdrh   rc = Tcl_Eval(pDb->interp, zCmd);
324bec3f402Sdrh   Tcl_DStringFree(&cmd);
325bec3f402Sdrh   if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
326bec3f402Sdrh     return 0;
327bec3f402Sdrh   }
328bec3f402Sdrh   return 1;
32975897234Sdrh }
33075897234Sdrh 
33175897234Sdrh /*
332348bb5d6Sdanielk1977 ** This routine is invoked as the 'progress callback' for the database.
333348bb5d6Sdanielk1977 */
334348bb5d6Sdanielk1977 static int DbProgressHandler(void *cd){
335348bb5d6Sdanielk1977   SqliteDb *pDb = (SqliteDb*)cd;
336348bb5d6Sdanielk1977   int rc;
337348bb5d6Sdanielk1977 
338348bb5d6Sdanielk1977   assert( pDb->zProgress );
339348bb5d6Sdanielk1977   rc = Tcl_Eval(pDb->interp, pDb->zProgress);
340348bb5d6Sdanielk1977   if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
341348bb5d6Sdanielk1977     return 1;
342348bb5d6Sdanielk1977   }
343348bb5d6Sdanielk1977   return 0;
344348bb5d6Sdanielk1977 }
345348bb5d6Sdanielk1977 
346348bb5d6Sdanielk1977 /*
347b5a20d3cSdrh ** This routine is called by the SQLite trace handler whenever a new
348b5a20d3cSdrh ** block of SQL is executed.  The TCL script in pDb->zTrace is executed.
3490d1a643aSdrh */
350b5a20d3cSdrh static void DbTraceHandler(void *cd, const char *zSql){
3510d1a643aSdrh   SqliteDb *pDb = (SqliteDb*)cd;
352b5a20d3cSdrh   Tcl_DString str;
3530d1a643aSdrh 
354b5a20d3cSdrh   Tcl_DStringInit(&str);
355b5a20d3cSdrh   Tcl_DStringAppend(&str, pDb->zTrace, -1);
356b5a20d3cSdrh   Tcl_DStringAppendElement(&str, zSql);
357b5a20d3cSdrh   Tcl_Eval(pDb->interp, Tcl_DStringValue(&str));
358b5a20d3cSdrh   Tcl_DStringFree(&str);
359b5a20d3cSdrh   Tcl_ResetResult(pDb->interp);
3600d1a643aSdrh }
3610d1a643aSdrh 
3620d1a643aSdrh /*
363aa940eacSdrh ** This routine is called when a transaction is committed.  The
364aa940eacSdrh ** TCL script in pDb->zCommit is executed.  If it returns non-zero or
365aa940eacSdrh ** if it throws an exception, the transaction is rolled back instead
366aa940eacSdrh ** of being committed.
367aa940eacSdrh */
368aa940eacSdrh static int DbCommitHandler(void *cd){
369aa940eacSdrh   SqliteDb *pDb = (SqliteDb*)cd;
370aa940eacSdrh   int rc;
371aa940eacSdrh 
372aa940eacSdrh   rc = Tcl_Eval(pDb->interp, pDb->zCommit);
373aa940eacSdrh   if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
374aa940eacSdrh     return 1;
375aa940eacSdrh   }
376aa940eacSdrh   return 0;
377aa940eacSdrh }
378aa940eacSdrh 
379aa940eacSdrh /*
380cabb0819Sdrh ** This routine is called to evaluate an SQL function implemented
381cabb0819Sdrh ** using TCL script.
382cabb0819Sdrh */
3830ae8b831Sdanielk1977 static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
3846f8a503dSdanielk1977   SqlFunc *p = sqlite3_user_data(context);
385cabb0819Sdrh   Tcl_DString cmd;
386cabb0819Sdrh   int i;
387cabb0819Sdrh   int rc;
388cabb0819Sdrh 
389cabb0819Sdrh   Tcl_DStringInit(&cmd);
390cabb0819Sdrh   Tcl_DStringAppend(&cmd, p->zScript, -1);
391cabb0819Sdrh   for(i=0; i<argc; i++){
39251ad0ecdSdanielk1977     if( SQLITE3_NULL==sqlite3_value_type(argv[i]) ){
39351ad0ecdSdanielk1977       Tcl_DStringAppendElement(&cmd, "");
39451ad0ecdSdanielk1977     }else{
3954f26d6c4Sdrh       Tcl_DStringAppendElement(&cmd, sqlite3_value_text(argv[i]));
39651ad0ecdSdanielk1977     }
397cabb0819Sdrh   }
398cabb0819Sdrh   rc = Tcl_Eval(p->interp, Tcl_DStringValue(&cmd));
399cabb0819Sdrh   if( rc ){
4007e18c259Sdanielk1977     sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1);
401cabb0819Sdrh   }else{
4027e18c259Sdanielk1977     sqlite3_result_text(context, Tcl_GetStringResult(p->interp), -1, 1);
403cabb0819Sdrh   }
404cabb0819Sdrh }
405e22a334bSdrh #ifndef SQLITE_OMIT_AUTHORIZATION
406e22a334bSdrh /*
407e22a334bSdrh ** This is the authentication function.  It appends the authentication
408e22a334bSdrh ** type code and the two arguments to zCmd[] then invokes the result
409e22a334bSdrh ** on the interpreter.  The reply is examined to determine if the
410e22a334bSdrh ** authentication fails or succeeds.
411e22a334bSdrh */
412e22a334bSdrh static int auth_callback(
413e22a334bSdrh   void *pArg,
414e22a334bSdrh   int code,
415e22a334bSdrh   const char *zArg1,
416e22a334bSdrh   const char *zArg2,
417e22a334bSdrh   const char *zArg3,
418e22a334bSdrh   const char *zArg4
419e22a334bSdrh ){
420e22a334bSdrh   char *zCode;
421e22a334bSdrh   Tcl_DString str;
422e22a334bSdrh   int rc;
423e22a334bSdrh   const char *zReply;
424e22a334bSdrh   SqliteDb *pDb = (SqliteDb*)pArg;
425e22a334bSdrh 
426e22a334bSdrh   switch( code ){
427e22a334bSdrh     case SQLITE_COPY              : zCode="SQLITE_COPY"; break;
428e22a334bSdrh     case SQLITE_CREATE_INDEX      : zCode="SQLITE_CREATE_INDEX"; break;
429e22a334bSdrh     case SQLITE_CREATE_TABLE      : zCode="SQLITE_CREATE_TABLE"; break;
430e22a334bSdrh     case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break;
431e22a334bSdrh     case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break;
432e22a334bSdrh     case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break;
433e22a334bSdrh     case SQLITE_CREATE_TEMP_VIEW  : zCode="SQLITE_CREATE_TEMP_VIEW"; break;
434e22a334bSdrh     case SQLITE_CREATE_TRIGGER    : zCode="SQLITE_CREATE_TRIGGER"; break;
435e22a334bSdrh     case SQLITE_CREATE_VIEW       : zCode="SQLITE_CREATE_VIEW"; break;
436e22a334bSdrh     case SQLITE_DELETE            : zCode="SQLITE_DELETE"; break;
437e22a334bSdrh     case SQLITE_DROP_INDEX        : zCode="SQLITE_DROP_INDEX"; break;
438e22a334bSdrh     case SQLITE_DROP_TABLE        : zCode="SQLITE_DROP_TABLE"; break;
439e22a334bSdrh     case SQLITE_DROP_TEMP_INDEX   : zCode="SQLITE_DROP_TEMP_INDEX"; break;
440e22a334bSdrh     case SQLITE_DROP_TEMP_TABLE   : zCode="SQLITE_DROP_TEMP_TABLE"; break;
441e22a334bSdrh     case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break;
442e22a334bSdrh     case SQLITE_DROP_TEMP_VIEW    : zCode="SQLITE_DROP_TEMP_VIEW"; break;
443e22a334bSdrh     case SQLITE_DROP_TRIGGER      : zCode="SQLITE_DROP_TRIGGER"; break;
444e22a334bSdrh     case SQLITE_DROP_VIEW         : zCode="SQLITE_DROP_VIEW"; break;
445e22a334bSdrh     case SQLITE_INSERT            : zCode="SQLITE_INSERT"; break;
446e22a334bSdrh     case SQLITE_PRAGMA            : zCode="SQLITE_PRAGMA"; break;
447e22a334bSdrh     case SQLITE_READ              : zCode="SQLITE_READ"; break;
448e22a334bSdrh     case SQLITE_SELECT            : zCode="SQLITE_SELECT"; break;
449e22a334bSdrh     case SQLITE_TRANSACTION       : zCode="SQLITE_TRANSACTION"; break;
450e22a334bSdrh     case SQLITE_UPDATE            : zCode="SQLITE_UPDATE"; break;
45181e293b4Sdrh     case SQLITE_ATTACH            : zCode="SQLITE_ATTACH"; break;
45281e293b4Sdrh     case SQLITE_DETACH            : zCode="SQLITE_DETACH"; break;
453e22a334bSdrh     default                       : zCode="????"; break;
454e22a334bSdrh   }
455e22a334bSdrh   Tcl_DStringInit(&str);
456e22a334bSdrh   Tcl_DStringAppend(&str, pDb->zAuth, -1);
457e22a334bSdrh   Tcl_DStringAppendElement(&str, zCode);
458e22a334bSdrh   Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : "");
459e22a334bSdrh   Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : "");
460e22a334bSdrh   Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : "");
461e22a334bSdrh   Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : "");
462e22a334bSdrh   rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str));
463e22a334bSdrh   Tcl_DStringFree(&str);
464e22a334bSdrh   zReply = Tcl_GetStringResult(pDb->interp);
465e22a334bSdrh   if( strcmp(zReply,"SQLITE_OK")==0 ){
466e22a334bSdrh     rc = SQLITE_OK;
467e22a334bSdrh   }else if( strcmp(zReply,"SQLITE_DENY")==0 ){
468e22a334bSdrh     rc = SQLITE_DENY;
469e22a334bSdrh   }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){
470e22a334bSdrh     rc = SQLITE_IGNORE;
471e22a334bSdrh   }else{
472e22a334bSdrh     rc = 999;
473e22a334bSdrh   }
474e22a334bSdrh   return rc;
475e22a334bSdrh }
476e22a334bSdrh #endif /* SQLITE_OMIT_AUTHORIZATION */
477cabb0819Sdrh 
478cabb0819Sdrh /*
47975897234Sdrh ** The "sqlite" command below creates a new Tcl command for each
48075897234Sdrh ** connection it opens to an SQLite database.  This routine is invoked
48175897234Sdrh ** whenever one of those connection-specific commands is executed
48275897234Sdrh ** in Tcl.  For example, if you run Tcl code like this:
48375897234Sdrh **
48475897234Sdrh **       sqlite db1  "my_database"
48575897234Sdrh **       db1 close
48675897234Sdrh **
48775897234Sdrh ** The first command opens a connection to the "my_database" database
48875897234Sdrh ** and calls that connection "db1".  The second command causes this
48975897234Sdrh ** subroutine to be invoked.
49075897234Sdrh */
4916d31316cSdrh static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
492bec3f402Sdrh   SqliteDb *pDb = (SqliteDb*)cd;
4936d31316cSdrh   int choice;
49422fbcb8dSdrh   int rc = TCL_OK;
4950de8c112Sdrh   static const char *DB_strs[] = {
496b5a20d3cSdrh     "authorizer",         "busy",                   "changes",
497aa940eacSdrh     "close",              "commit_hook",            "complete",
498aa940eacSdrh     "errorcode",          "eval",                   "function",
499f146a776Srdc     "last_insert_rowid",  "last_statement_changes", "onecolumn",
500f146a776Srdc     "progress",           "rekey",                  "timeout",
501f146a776Srdc     "trace",
50222fbcb8dSdrh     0
5036d31316cSdrh   };
504411995dcSdrh   enum DB_enum {
505b5a20d3cSdrh     DB_AUTHORIZER,        DB_BUSY,                   DB_CHANGES,
506aa940eacSdrh     DB_CLOSE,             DB_COMMIT_HOOK,            DB_COMPLETE,
507aa940eacSdrh     DB_ERRORCODE,         DB_EVAL,                   DB_FUNCTION,
508f146a776Srdc     DB_LAST_INSERT_ROWID, DB_LAST_STATEMENT_CHANGES, DB_ONECOLUMN,
509f146a776Srdc     DB_PROGRESS,          DB_REKEY,                  DB_TIMEOUT,
510f146a776Srdc     DB_TRACE
5116d31316cSdrh   };
5126d31316cSdrh 
5136d31316cSdrh   if( objc<2 ){
5146d31316cSdrh     Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
51575897234Sdrh     return TCL_ERROR;
51675897234Sdrh   }
517411995dcSdrh   if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){
5186d31316cSdrh     return TCL_ERROR;
5196d31316cSdrh   }
5206d31316cSdrh 
521411995dcSdrh   switch( (enum DB_enum)choice ){
52275897234Sdrh 
523e22a334bSdrh   /*    $db authorizer ?CALLBACK?
524e22a334bSdrh   **
525e22a334bSdrh   ** Invoke the given callback to authorize each SQL operation as it is
526e22a334bSdrh   ** compiled.  5 arguments are appended to the callback before it is
527e22a334bSdrh   ** invoked:
528e22a334bSdrh   **
529e22a334bSdrh   **   (1) The authorization type (ex: SQLITE_CREATE_TABLE, SQLITE_INSERT, ...)
530e22a334bSdrh   **   (2) First descriptive name (depends on authorization type)
531e22a334bSdrh   **   (3) Second descriptive name
532e22a334bSdrh   **   (4) Name of the database (ex: "main", "temp")
533e22a334bSdrh   **   (5) Name of trigger that is doing the access
534e22a334bSdrh   **
535e22a334bSdrh   ** The callback should return on of the following strings: SQLITE_OK,
536e22a334bSdrh   ** SQLITE_IGNORE, or SQLITE_DENY.  Any other return value is an error.
537e22a334bSdrh   **
538e22a334bSdrh   ** If this method is invoked with no arguments, the current authorization
539e22a334bSdrh   ** callback string is returned.
540e22a334bSdrh   */
541e22a334bSdrh   case DB_AUTHORIZER: {
542e22a334bSdrh     if( objc>3 ){
543e22a334bSdrh       Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
544e22a334bSdrh     }else if( objc==2 ){
545b5a20d3cSdrh       if( pDb->zAuth ){
546e22a334bSdrh         Tcl_AppendResult(interp, pDb->zAuth, 0);
547e22a334bSdrh       }
548e22a334bSdrh     }else{
549e22a334bSdrh       char *zAuth;
550e22a334bSdrh       int len;
551e22a334bSdrh       if( pDb->zAuth ){
552e22a334bSdrh         Tcl_Free(pDb->zAuth);
553e22a334bSdrh       }
554e22a334bSdrh       zAuth = Tcl_GetStringFromObj(objv[2], &len);
555e22a334bSdrh       if( zAuth && len>0 ){
556e22a334bSdrh         pDb->zAuth = Tcl_Alloc( len + 1 );
557e22a334bSdrh         strcpy(pDb->zAuth, zAuth);
558e22a334bSdrh       }else{
559e22a334bSdrh         pDb->zAuth = 0;
560e22a334bSdrh       }
561e22a334bSdrh #ifndef SQLITE_OMIT_AUTHORIZATION
562e22a334bSdrh       if( pDb->zAuth ){
563e22a334bSdrh         pDb->interp = interp;
5646f8a503dSdanielk1977         sqlite3_set_authorizer(pDb->db, auth_callback, pDb);
565e22a334bSdrh       }else{
5666f8a503dSdanielk1977         sqlite3_set_authorizer(pDb->db, 0, 0);
567e22a334bSdrh       }
568e22a334bSdrh #endif
569e22a334bSdrh     }
570e22a334bSdrh     break;
571e22a334bSdrh   }
572e22a334bSdrh 
573bec3f402Sdrh   /*    $db busy ?CALLBACK?
574bec3f402Sdrh   **
575bec3f402Sdrh   ** Invoke the given callback if an SQL statement attempts to open
576bec3f402Sdrh   ** a locked database file.
577bec3f402Sdrh   */
5786d31316cSdrh   case DB_BUSY: {
5796d31316cSdrh     if( objc>3 ){
5806d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "CALLBACK");
581bec3f402Sdrh       return TCL_ERROR;
5826d31316cSdrh     }else if( objc==2 ){
583bec3f402Sdrh       if( pDb->zBusy ){
584bec3f402Sdrh         Tcl_AppendResult(interp, pDb->zBusy, 0);
585bec3f402Sdrh       }
586bec3f402Sdrh     }else{
5876d31316cSdrh       char *zBusy;
5886d31316cSdrh       int len;
589bec3f402Sdrh       if( pDb->zBusy ){
590bec3f402Sdrh         Tcl_Free(pDb->zBusy);
5916d31316cSdrh       }
5926d31316cSdrh       zBusy = Tcl_GetStringFromObj(objv[2], &len);
5936d31316cSdrh       if( zBusy && len>0 ){
5946d31316cSdrh         pDb->zBusy = Tcl_Alloc( len + 1 );
5956d31316cSdrh         strcpy(pDb->zBusy, zBusy);
5966d31316cSdrh       }else{
597bec3f402Sdrh         pDb->zBusy = 0;
598bec3f402Sdrh       }
599bec3f402Sdrh       if( pDb->zBusy ){
600bec3f402Sdrh         pDb->interp = interp;
6016f8a503dSdanielk1977         sqlite3_busy_handler(pDb->db, DbBusyHandler, pDb);
6026d31316cSdrh       }else{
6036f8a503dSdanielk1977         sqlite3_busy_handler(pDb->db, 0, 0);
604bec3f402Sdrh       }
605bec3f402Sdrh     }
6066d31316cSdrh     break;
6076d31316cSdrh   }
608bec3f402Sdrh 
609348bb5d6Sdanielk1977   /*    $db progress ?N CALLBACK?
610348bb5d6Sdanielk1977   **
611348bb5d6Sdanielk1977   ** Invoke the given callback every N virtual machine opcodes while executing
612348bb5d6Sdanielk1977   ** queries.
613348bb5d6Sdanielk1977   */
614348bb5d6Sdanielk1977   case DB_PROGRESS: {
615348bb5d6Sdanielk1977     if( objc==2 ){
616348bb5d6Sdanielk1977       if( pDb->zProgress ){
617348bb5d6Sdanielk1977         Tcl_AppendResult(interp, pDb->zProgress, 0);
618348bb5d6Sdanielk1977       }
619348bb5d6Sdanielk1977     }else if( objc==4 ){
620348bb5d6Sdanielk1977       char *zProgress;
621348bb5d6Sdanielk1977       int len;
622348bb5d6Sdanielk1977       int N;
623348bb5d6Sdanielk1977       if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){
624348bb5d6Sdanielk1977 	return TCL_ERROR;
625348bb5d6Sdanielk1977       };
626348bb5d6Sdanielk1977       if( pDb->zProgress ){
627348bb5d6Sdanielk1977         Tcl_Free(pDb->zProgress);
628348bb5d6Sdanielk1977       }
629348bb5d6Sdanielk1977       zProgress = Tcl_GetStringFromObj(objv[3], &len);
630348bb5d6Sdanielk1977       if( zProgress && len>0 ){
631348bb5d6Sdanielk1977         pDb->zProgress = Tcl_Alloc( len + 1 );
632348bb5d6Sdanielk1977         strcpy(pDb->zProgress, zProgress);
633348bb5d6Sdanielk1977       }else{
634348bb5d6Sdanielk1977         pDb->zProgress = 0;
635348bb5d6Sdanielk1977       }
636348bb5d6Sdanielk1977 #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
637348bb5d6Sdanielk1977       if( pDb->zProgress ){
638348bb5d6Sdanielk1977         pDb->interp = interp;
6396f8a503dSdanielk1977         sqlite3_progress_handler(pDb->db, N, DbProgressHandler, pDb);
640348bb5d6Sdanielk1977       }else{
6416f8a503dSdanielk1977         sqlite3_progress_handler(pDb->db, 0, 0, 0);
642348bb5d6Sdanielk1977       }
643348bb5d6Sdanielk1977 #endif
644348bb5d6Sdanielk1977     }else{
645348bb5d6Sdanielk1977       Tcl_WrongNumArgs(interp, 2, objv, "N CALLBACK");
646348bb5d6Sdanielk1977       return TCL_ERROR;
647348bb5d6Sdanielk1977     }
648348bb5d6Sdanielk1977     break;
649348bb5d6Sdanielk1977   }
650348bb5d6Sdanielk1977 
651c8d30ac1Sdrh   /*
652c8d30ac1Sdrh   **     $db changes
653c8d30ac1Sdrh   **
654c8d30ac1Sdrh   ** Return the number of rows that were modified, inserted, or deleted by
655c8d30ac1Sdrh   ** the most recent "eval".
656c8d30ac1Sdrh   */
657c8d30ac1Sdrh   case DB_CHANGES: {
658c8d30ac1Sdrh     Tcl_Obj *pResult;
659c8d30ac1Sdrh     int nChange;
660c8d30ac1Sdrh     if( objc!=2 ){
661c8d30ac1Sdrh       Tcl_WrongNumArgs(interp, 2, objv, "");
662c8d30ac1Sdrh       return TCL_ERROR;
663c8d30ac1Sdrh     }
66430ccda10Sdanielk1977     /* nChange = sqlite3_changes(pDb->db); */
66530ccda10Sdanielk1977     nChange = pDb->nChange;
666c8d30ac1Sdrh     pResult = Tcl_GetObjResult(interp);
667c8d30ac1Sdrh     Tcl_SetIntObj(pResult, nChange);
668c8d30ac1Sdrh     break;
669c8d30ac1Sdrh   }
670c8d30ac1Sdrh 
671f146a776Srdc   /*
672f146a776Srdc   **     $db last_statement_changes
673f146a776Srdc   **
674f146a776Srdc   ** Return the number of rows that were modified, inserted, or deleted by
675f146a776Srdc   ** the last statment to complete execution (excluding changes due to
676f146a776Srdc   ** triggers)
677f146a776Srdc   */
678f146a776Srdc   case DB_LAST_STATEMENT_CHANGES: {
679f146a776Srdc     Tcl_Obj *pResult;
680f146a776Srdc     int lsChange;
681f146a776Srdc     if( objc!=2 ){
682f146a776Srdc       Tcl_WrongNumArgs(interp, 2, objv, "");
683f146a776Srdc       return TCL_ERROR;
684f146a776Srdc     }
6856f8a503dSdanielk1977     lsChange = sqlite3_last_statement_changes(pDb->db);
686f146a776Srdc     pResult = Tcl_GetObjResult(interp);
687f146a776Srdc     Tcl_SetIntObj(pResult, lsChange);
688f146a776Srdc     break;
689f146a776Srdc   }
690f146a776Srdc 
69175897234Sdrh   /*    $db close
69275897234Sdrh   **
69375897234Sdrh   ** Shutdown the database
69475897234Sdrh   */
6956d31316cSdrh   case DB_CLOSE: {
6966d31316cSdrh     Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0));
6976d31316cSdrh     break;
6986d31316cSdrh   }
69975897234Sdrh 
700aa940eacSdrh   /*    $db commit_hook ?CALLBACK?
701aa940eacSdrh   **
702aa940eacSdrh   ** Invoke the given callback just before committing every SQL transaction.
703aa940eacSdrh   ** If the callback throws an exception or returns non-zero, then the
704aa940eacSdrh   ** transaction is aborted.  If CALLBACK is an empty string, the callback
705aa940eacSdrh   ** is disabled.
706aa940eacSdrh   */
707aa940eacSdrh   case DB_COMMIT_HOOK: {
708aa940eacSdrh     if( objc>3 ){
709aa940eacSdrh       Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
710aa940eacSdrh     }else if( objc==2 ){
711aa940eacSdrh       if( pDb->zCommit ){
712aa940eacSdrh         Tcl_AppendResult(interp, pDb->zCommit, 0);
713aa940eacSdrh       }
714aa940eacSdrh     }else{
715aa940eacSdrh       char *zCommit;
716aa940eacSdrh       int len;
717aa940eacSdrh       if( pDb->zCommit ){
718aa940eacSdrh         Tcl_Free(pDb->zCommit);
719aa940eacSdrh       }
720aa940eacSdrh       zCommit = Tcl_GetStringFromObj(objv[2], &len);
721aa940eacSdrh       if( zCommit && len>0 ){
722aa940eacSdrh         pDb->zCommit = Tcl_Alloc( len + 1 );
723aa940eacSdrh         strcpy(pDb->zCommit, zCommit);
724aa940eacSdrh       }else{
725aa940eacSdrh         pDb->zCommit = 0;
726aa940eacSdrh       }
727aa940eacSdrh       if( pDb->zCommit ){
728aa940eacSdrh         pDb->interp = interp;
7296f8a503dSdanielk1977         sqlite3_commit_hook(pDb->db, DbCommitHandler, pDb);
730aa940eacSdrh       }else{
7316f8a503dSdanielk1977         sqlite3_commit_hook(pDb->db, 0, 0);
732aa940eacSdrh       }
733aa940eacSdrh     }
734aa940eacSdrh     break;
735aa940eacSdrh   }
736aa940eacSdrh 
73775897234Sdrh   /*    $db complete SQL
73875897234Sdrh   **
73975897234Sdrh   ** Return TRUE if SQL is a complete SQL statement.  Return FALSE if
74075897234Sdrh   ** additional lines of input are needed.  This is similar to the
74175897234Sdrh   ** built-in "info complete" command of Tcl.
74275897234Sdrh   */
7436d31316cSdrh   case DB_COMPLETE: {
7446d31316cSdrh     Tcl_Obj *pResult;
7456d31316cSdrh     int isComplete;
7466d31316cSdrh     if( objc!=3 ){
7476d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "SQL");
74875897234Sdrh       return TCL_ERROR;
74975897234Sdrh     }
7506f8a503dSdanielk1977     isComplete = sqlite3_complete( Tcl_GetStringFromObj(objv[2], 0) );
7516d31316cSdrh     pResult = Tcl_GetObjResult(interp);
7526d31316cSdrh     Tcl_SetBooleanObj(pResult, isComplete);
7536d31316cSdrh     break;
7546d31316cSdrh   }
75575897234Sdrh 
75675897234Sdrh   /*
757dcd997eaSdrh   **    $db errorcode
758dcd997eaSdrh   **
759dcd997eaSdrh   ** Return the numeric error code that was returned by the most recent
7606f8a503dSdanielk1977   ** call to sqlite3_exec().
761dcd997eaSdrh   */
762dcd997eaSdrh   case DB_ERRORCODE: {
763dcd997eaSdrh     Tcl_SetObjResult(interp, Tcl_NewIntObj(pDb->rc));
764dcd997eaSdrh     break;
765dcd997eaSdrh   }
766dcd997eaSdrh 
767dcd997eaSdrh   /*
76875897234Sdrh   **    $db eval $sql ?array {  ...code... }?
76975897234Sdrh   **
77075897234Sdrh   ** The SQL statement in $sql is evaluated.  For each row, the values are
771bec3f402Sdrh   ** placed in elements of the array named "array" and ...code... is executed.
77275897234Sdrh   ** If "array" and "code" are omitted, then no callback is every invoked.
77375897234Sdrh   ** If "array" is an empty string, then the values are placed in variables
77475897234Sdrh   ** that have the same name as the fields extracted by the query.
77575897234Sdrh   */
7766d31316cSdrh   case DB_EVAL: {
77730ccda10Sdanielk1977     char const *zSql;
77830ccda10Sdanielk1977     char const *zLeft;
77930ccda10Sdanielk1977     sqlite3_stmt *pStmt;
78030ccda10Sdanielk1977     Tcl_Obj *pRet = 0;
78130ccda10Sdanielk1977 
78230ccda10Sdanielk1977     if( objc!=5 && objc!=3 ){
78330ccda10Sdanielk1977       Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME CODE?");
78430ccda10Sdanielk1977       return TCL_ERROR;
78530ccda10Sdanielk1977     }
78630ccda10Sdanielk1977 
78730ccda10Sdanielk1977     pDb->nChange = 0;
78830ccda10Sdanielk1977     zSql = Tcl_GetStringFromObj(objv[2], 0);
78930ccda10Sdanielk1977     while( zSql[0] ){
79030ccda10Sdanielk1977       int i;
79130ccda10Sdanielk1977 
79230ccda10Sdanielk1977       if( SQLITE_OK!=sqlite3_prepare(pDb->db, zSql, -1, &pStmt, &zLeft) ){
79330ccda10Sdanielk1977         Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_STATIC);
79430ccda10Sdanielk1977         rc = TCL_ERROR;
79530ccda10Sdanielk1977         break;
79630ccda10Sdanielk1977       }
79730ccda10Sdanielk1977 
79830ccda10Sdanielk1977       if( pStmt && objc==5 ){
79930ccda10Sdanielk1977         Tcl_Obj *pColList = Tcl_NewObj();
80030ccda10Sdanielk1977         Tcl_IncrRefCount(pColList);
80130ccda10Sdanielk1977 
80230ccda10Sdanielk1977         for(i=0; i<sqlite3_column_count(pStmt); i++){
80330ccda10Sdanielk1977           Tcl_ListObjAppendElement(interp, pColList,
80430ccda10Sdanielk1977               Tcl_NewStringObj(sqlite3_column_name(pStmt, i), -1)
80530ccda10Sdanielk1977           );
80630ccda10Sdanielk1977         }
80730ccda10Sdanielk1977         Tcl_ObjSetVar2(interp,objv[3],Tcl_NewStringObj("*",-1),pColList,0);
80830ccda10Sdanielk1977       }
80930ccda10Sdanielk1977 
81030ccda10Sdanielk1977       while( pStmt && SQLITE_ROW==sqlite3_step(pStmt) ){
81130ccda10Sdanielk1977         for(i=0; i<sqlite3_column_count(pStmt); i++){
81230ccda10Sdanielk1977           Tcl_Obj *pVal;
81330ccda10Sdanielk1977 
81430ccda10Sdanielk1977           /* Set pVal to contain the i'th column of this row. */
81530ccda10Sdanielk1977           if( SQLITE3_BLOB!=sqlite3_column_type(pStmt, i) ){
81630ccda10Sdanielk1977             pVal = Tcl_NewStringObj(sqlite3_column_text(pStmt, i), -1);
81730ccda10Sdanielk1977           }else{
818*3fd0a736Sdanielk1977             int bytes = sqlite3_column_bytes(pStmt, i);
819*3fd0a736Sdanielk1977             pVal = Tcl_NewByteArrayObj(sqlite3_column_blob(pStmt, i), bytes);
82030ccda10Sdanielk1977           }
82130ccda10Sdanielk1977 
82230ccda10Sdanielk1977           if( objc==5 ){
82330ccda10Sdanielk1977             Tcl_Obj *pName = Tcl_NewStringObj(sqlite3_column_name(pStmt, i), -1);
82430ccda10Sdanielk1977             Tcl_IncrRefCount(pName);
82530ccda10Sdanielk1977             if( !strcmp("", Tcl_GetString(objv[3])) ){
82630ccda10Sdanielk1977               Tcl_ObjSetVar2(interp, pName, 0, pVal, 0);
82730ccda10Sdanielk1977             }else{
82830ccda10Sdanielk1977               Tcl_ObjSetVar2(interp, objv[3], pName, pVal, 0);
82930ccda10Sdanielk1977             }
83030ccda10Sdanielk1977             Tcl_DecrRefCount(pName);
83130ccda10Sdanielk1977           }else{
83230ccda10Sdanielk1977             if( !pRet ){
83330ccda10Sdanielk1977               pRet = Tcl_NewObj();
83430ccda10Sdanielk1977               Tcl_IncrRefCount(pRet);
83530ccda10Sdanielk1977             }
83630ccda10Sdanielk1977             Tcl_ListObjAppendElement(interp, pRet, pVal);
83730ccda10Sdanielk1977           }
83830ccda10Sdanielk1977         }
83930ccda10Sdanielk1977 
84030ccda10Sdanielk1977         if( objc==5 ){
84130ccda10Sdanielk1977           rc = Tcl_EvalObjEx(interp, objv[4], 0);
84230ccda10Sdanielk1977           if( rc!=TCL_ERROR ) rc = TCL_OK;
84330ccda10Sdanielk1977         }
84430ccda10Sdanielk1977       }
84530ccda10Sdanielk1977 
84630ccda10Sdanielk1977       if( pStmt && SQLITE_SCHEMA==sqlite3_finalize(pStmt) ){
84730ccda10Sdanielk1977         continue;
84830ccda10Sdanielk1977       }
84930ccda10Sdanielk1977 
85030ccda10Sdanielk1977       if( pStmt && SQLITE_OK!=sqlite3_errcode(pDb->db) ){
85130ccda10Sdanielk1977         Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_STATIC);
85230ccda10Sdanielk1977         rc = TCL_ERROR;
85330ccda10Sdanielk1977         break;
85430ccda10Sdanielk1977       }
85530ccda10Sdanielk1977 
85630ccda10Sdanielk1977       pDb->nChange += sqlite3_changes(pDb->db);
85730ccda10Sdanielk1977       zSql = zLeft;
85830ccda10Sdanielk1977     }
85930ccda10Sdanielk1977 
86030ccda10Sdanielk1977     if( rc==TCL_OK && pRet ){
86130ccda10Sdanielk1977       Tcl_SetObjResult(interp, pRet);
86230ccda10Sdanielk1977       Tcl_DecrRefCount(pRet);
86330ccda10Sdanielk1977     }
86430ccda10Sdanielk1977 
86530ccda10Sdanielk1977     break;
86630ccda10Sdanielk1977   }
86730ccda10Sdanielk1977 #if 0
86830ccda10Sdanielk1977   case DB_EVAL: {
86975897234Sdrh     CallbackData cbData;
87075897234Sdrh     char *zErrMsg;
8716d31316cSdrh     char *zSql;
872297ecf14Sdrh #ifdef UTF_TRANSLATION_NEEDED
873297ecf14Sdrh     Tcl_DString dSql;
8746d4abfbeSdrh     int i;
875297ecf14Sdrh #endif
87675897234Sdrh 
8776d31316cSdrh     if( objc!=5 && objc!=3 ){
8786d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME CODE?");
87975897234Sdrh       return TCL_ERROR;
88075897234Sdrh     }
881bec3f402Sdrh     pDb->interp = interp;
8826d31316cSdrh     zSql = Tcl_GetStringFromObj(objv[2], 0);
883297ecf14Sdrh #ifdef UTF_TRANSLATION_NEEDED
884297ecf14Sdrh     Tcl_DStringInit(&dSql);
885297ecf14Sdrh     Tcl_UtfToExternalDString(NULL, zSql, -1, &dSql);
886297ecf14Sdrh     zSql = Tcl_DStringValue(&dSql);
887297ecf14Sdrh #endif
8886d31316cSdrh     Tcl_IncrRefCount(objv[2]);
8896d31316cSdrh     if( objc==5 ){
89075897234Sdrh       cbData.interp = interp;
891dcc581ccSdrh       cbData.once = 1;
8926d31316cSdrh       cbData.zArray = Tcl_GetStringFromObj(objv[3], 0);
8936d31316cSdrh       cbData.pCode = objv[4];
894960e8c63Sdrh       cbData.tcl_rc = TCL_OK;
8956d4abfbeSdrh       cbData.nColName = 0;
8966d4abfbeSdrh       cbData.azColName = 0;
89775897234Sdrh       zErrMsg = 0;
8986d31316cSdrh       Tcl_IncrRefCount(objv[3]);
8996d31316cSdrh       Tcl_IncrRefCount(objv[4]);
9006f8a503dSdanielk1977       rc = sqlite3_exec(pDb->db, zSql, DbEvalCallback, &cbData, &zErrMsg);
9016d31316cSdrh       Tcl_DecrRefCount(objv[4]);
9026d31316cSdrh       Tcl_DecrRefCount(objv[3]);
903960e8c63Sdrh       if( cbData.tcl_rc==TCL_BREAK ){ cbData.tcl_rc = TCL_OK; }
90475897234Sdrh     }else{
9056d31316cSdrh       Tcl_Obj *pList = Tcl_NewObj();
906960e8c63Sdrh       cbData.tcl_rc = TCL_OK;
9076f8a503dSdanielk1977       rc = sqlite3_exec(pDb->db, zSql, DbEvalCallback2, pList, &zErrMsg);
9086d31316cSdrh       Tcl_SetObjResult(interp, pList);
90975897234Sdrh     }
910dcd997eaSdrh     pDb->rc = rc;
911b798fa64Sdrh     if( rc==SQLITE_ABORT ){
912b798fa64Sdrh       if( zErrMsg ) free(zErrMsg);
913b798fa64Sdrh       rc = cbData.tcl_rc;
914b798fa64Sdrh     }else if( zErrMsg ){
91575897234Sdrh       Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
91675897234Sdrh       free(zErrMsg);
917960e8c63Sdrh       rc = TCL_ERROR;
918b798fa64Sdrh     }else if( rc!=SQLITE_OK ){
9196f8a503dSdanielk1977       Tcl_AppendResult(interp, sqlite3_error_string(rc), 0);
9206d4abfbeSdrh       rc = TCL_ERROR;
921960e8c63Sdrh     }else{
92275897234Sdrh     }
9236d31316cSdrh     Tcl_DecrRefCount(objv[2]);
924297ecf14Sdrh #ifdef UTF_TRANSLATION_NEEDED
925297ecf14Sdrh     Tcl_DStringFree(&dSql);
9266d4abfbeSdrh     if( objc==5 && cbData.azColName ){
9276d4abfbeSdrh       for(i=0; i<cbData.nColName; i++){
9286d4abfbeSdrh         if( cbData.azColName[i] ) free(cbData.azColName[i]);
9296d4abfbeSdrh       }
9306d4abfbeSdrh       free(cbData.azColName);
931ce927065Sdrh       cbData.azColName = 0;
9326d4abfbeSdrh     }
933297ecf14Sdrh #endif
93475897234Sdrh     return rc;
9356d31316cSdrh   }
93630ccda10Sdanielk1977 #endif
937bec3f402Sdrh 
938bec3f402Sdrh   /*
939cabb0819Sdrh   **     $db function NAME SCRIPT
940cabb0819Sdrh   **
941cabb0819Sdrh   ** Create a new SQL function called NAME.  Whenever that function is
942cabb0819Sdrh   ** called, invoke SCRIPT to evaluate the function.
943cabb0819Sdrh   */
944cabb0819Sdrh   case DB_FUNCTION: {
945cabb0819Sdrh     SqlFunc *pFunc;
946cabb0819Sdrh     char *zName;
947cabb0819Sdrh     char *zScript;
948cabb0819Sdrh     int nScript;
949cabb0819Sdrh     if( objc!=4 ){
950cabb0819Sdrh       Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT");
951cabb0819Sdrh       return TCL_ERROR;
952cabb0819Sdrh     }
953cabb0819Sdrh     zName = Tcl_GetStringFromObj(objv[2], 0);
954cabb0819Sdrh     zScript = Tcl_GetStringFromObj(objv[3], &nScript);
955cabb0819Sdrh     pFunc = (SqlFunc*)Tcl_Alloc( sizeof(*pFunc) + nScript + 1 );
956cabb0819Sdrh     if( pFunc==0 ) return TCL_ERROR;
957cabb0819Sdrh     pFunc->interp = interp;
958cabb0819Sdrh     pFunc->pNext = pDb->pFunc;
959cabb0819Sdrh     pFunc->zScript = (char*)&pFunc[1];
960cabb0819Sdrh     strcpy(pFunc->zScript, zScript);
9616590493dSdanielk1977     sqlite3_create_function(pDb->db, zName, -1, 0, 0, pFunc, tclSqlFunc, 0, 0);
962cabb0819Sdrh     break;
963cabb0819Sdrh   }
964cabb0819Sdrh 
965cabb0819Sdrh   /*
966af9ff33aSdrh   **     $db last_insert_rowid
967af9ff33aSdrh   **
968af9ff33aSdrh   ** Return an integer which is the ROWID for the most recent insert.
969af9ff33aSdrh   */
970af9ff33aSdrh   case DB_LAST_INSERT_ROWID: {
971af9ff33aSdrh     Tcl_Obj *pResult;
972af9ff33aSdrh     int rowid;
973af9ff33aSdrh     if( objc!=2 ){
974af9ff33aSdrh       Tcl_WrongNumArgs(interp, 2, objv, "");
975af9ff33aSdrh       return TCL_ERROR;
976af9ff33aSdrh     }
9776f8a503dSdanielk1977     rowid = sqlite3_last_insert_rowid(pDb->db);
978af9ff33aSdrh     pResult = Tcl_GetObjResult(interp);
979af9ff33aSdrh     Tcl_SetIntObj(pResult, rowid);
980af9ff33aSdrh     break;
981af9ff33aSdrh   }
982af9ff33aSdrh 
983af9ff33aSdrh   /*
9845d9d7576Sdrh   **     $db onecolumn SQL
9855d9d7576Sdrh   **
9865d9d7576Sdrh   ** Return a single column from a single row of the given SQL query.
9875d9d7576Sdrh   */
9885d9d7576Sdrh   case DB_ONECOLUMN: {
9895d9d7576Sdrh     char *zSql;
9905d9d7576Sdrh     char *zErrMsg = 0;
9915d9d7576Sdrh     if( objc!=3 ){
9925d9d7576Sdrh       Tcl_WrongNumArgs(interp, 2, objv, "SQL");
9935d9d7576Sdrh       return TCL_ERROR;
9945d9d7576Sdrh     }
9955d9d7576Sdrh     zSql = Tcl_GetStringFromObj(objv[2], 0);
9966f8a503dSdanielk1977     rc = sqlite3_exec(pDb->db, zSql, DbEvalCallback3, interp, &zErrMsg);
9975d9d7576Sdrh     if( rc==SQLITE_ABORT ){
99822fbcb8dSdrh       rc = SQLITE_OK;
9995d9d7576Sdrh     }else if( zErrMsg ){
10005d9d7576Sdrh       Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
10015d9d7576Sdrh       free(zErrMsg);
10025d9d7576Sdrh       rc = TCL_ERROR;
10035d9d7576Sdrh     }else if( rc!=SQLITE_OK ){
10046f8a503dSdanielk1977       Tcl_AppendResult(interp, sqlite3_error_string(rc), 0);
10055d9d7576Sdrh       rc = TCL_ERROR;
10065d9d7576Sdrh     }
10075d9d7576Sdrh     break;
10085d9d7576Sdrh   }
10095d9d7576Sdrh 
10105d9d7576Sdrh   /*
101122fbcb8dSdrh   **     $db rekey KEY
101222fbcb8dSdrh   **
101322fbcb8dSdrh   ** Change the encryption key on the currently open database.
101422fbcb8dSdrh   */
101522fbcb8dSdrh   case DB_REKEY: {
101622fbcb8dSdrh     int nKey;
101722fbcb8dSdrh     void *pKey;
101822fbcb8dSdrh     if( objc!=3 ){
101922fbcb8dSdrh       Tcl_WrongNumArgs(interp, 2, objv, "KEY");
102022fbcb8dSdrh       return TCL_ERROR;
102122fbcb8dSdrh     }
102222fbcb8dSdrh     pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey);
10239eb9e26bSdrh #ifdef SQLITE_HAS_CODEC
102422fbcb8dSdrh     rc = sqlite_rekey(pDb->db, pKey, nKey);
102522fbcb8dSdrh     if( rc ){
10266f8a503dSdanielk1977       Tcl_AppendResult(interp, sqlite3_error_string(rc), 0);
102722fbcb8dSdrh       rc = TCL_ERROR;
102822fbcb8dSdrh     }
102922fbcb8dSdrh #endif
103022fbcb8dSdrh     break;
103122fbcb8dSdrh   }
103222fbcb8dSdrh 
103322fbcb8dSdrh   /*
1034bec3f402Sdrh   **     $db timeout MILLESECONDS
1035bec3f402Sdrh   **
1036bec3f402Sdrh   ** Delay for the number of milliseconds specified when a file is locked.
1037bec3f402Sdrh   */
10386d31316cSdrh   case DB_TIMEOUT: {
1039bec3f402Sdrh     int ms;
10406d31316cSdrh     if( objc!=3 ){
10416d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "MILLISECONDS");
1042bec3f402Sdrh       return TCL_ERROR;
104375897234Sdrh     }
10446d31316cSdrh     if( Tcl_GetIntFromObj(interp, objv[2], &ms) ) return TCL_ERROR;
10456f8a503dSdanielk1977     sqlite3_busy_timeout(pDb->db, ms);
10466d31316cSdrh     break;
104775897234Sdrh   }
1048b5a20d3cSdrh 
1049b5a20d3cSdrh   /*    $db trace ?CALLBACK?
1050b5a20d3cSdrh   **
1051b5a20d3cSdrh   ** Make arrangements to invoke the CALLBACK routine for each SQL statement
1052b5a20d3cSdrh   ** that is executed.  The text of the SQL is appended to CALLBACK before
1053b5a20d3cSdrh   ** it is executed.
1054b5a20d3cSdrh   */
1055b5a20d3cSdrh   case DB_TRACE: {
1056b5a20d3cSdrh     if( objc>3 ){
1057b5a20d3cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
1058b5a20d3cSdrh     }else if( objc==2 ){
1059b5a20d3cSdrh       if( pDb->zTrace ){
1060b5a20d3cSdrh         Tcl_AppendResult(interp, pDb->zTrace, 0);
1061b5a20d3cSdrh       }
1062b5a20d3cSdrh     }else{
1063b5a20d3cSdrh       char *zTrace;
1064b5a20d3cSdrh       int len;
1065b5a20d3cSdrh       if( pDb->zTrace ){
1066b5a20d3cSdrh         Tcl_Free(pDb->zTrace);
1067b5a20d3cSdrh       }
1068b5a20d3cSdrh       zTrace = Tcl_GetStringFromObj(objv[2], &len);
1069b5a20d3cSdrh       if( zTrace && len>0 ){
1070b5a20d3cSdrh         pDb->zTrace = Tcl_Alloc( len + 1 );
1071b5a20d3cSdrh         strcpy(pDb->zTrace, zTrace);
1072b5a20d3cSdrh       }else{
1073b5a20d3cSdrh         pDb->zTrace = 0;
1074b5a20d3cSdrh       }
1075b5a20d3cSdrh       if( pDb->zTrace ){
1076b5a20d3cSdrh         pDb->interp = interp;
10776f8a503dSdanielk1977         sqlite3_trace(pDb->db, DbTraceHandler, pDb);
1078b5a20d3cSdrh       }else{
10796f8a503dSdanielk1977         sqlite3_trace(pDb->db, 0, 0);
1080b5a20d3cSdrh       }
1081b5a20d3cSdrh     }
1082b5a20d3cSdrh     break;
1083b5a20d3cSdrh   }
1084b5a20d3cSdrh 
10856d31316cSdrh   } /* End of the SWITCH statement */
108622fbcb8dSdrh   return rc;
108775897234Sdrh }
108875897234Sdrh 
108975897234Sdrh /*
109022fbcb8dSdrh **   sqlite DBNAME FILENAME ?MODE? ?-key KEY?
109175897234Sdrh **
109275897234Sdrh ** This is the main Tcl command.  When the "sqlite" Tcl command is
109375897234Sdrh ** invoked, this routine runs to process that command.
109475897234Sdrh **
109575897234Sdrh ** The first argument, DBNAME, is an arbitrary name for a new
109675897234Sdrh ** database connection.  This command creates a new command named
109775897234Sdrh ** DBNAME that is used to control that connection.  The database
109875897234Sdrh ** connection is deleted when the DBNAME command is deleted.
109975897234Sdrh **
110075897234Sdrh ** The second argument is the name of the directory that contains
110175897234Sdrh ** the sqlite database that is to be accessed.
1102fbc3eab8Sdrh **
1103fbc3eab8Sdrh ** For testing purposes, we also support the following:
1104fbc3eab8Sdrh **
1105fbc3eab8Sdrh **  sqlite -encoding
1106fbc3eab8Sdrh **
1107fbc3eab8Sdrh **       Return the encoding used by LIKE and GLOB operators.  Choices
1108fbc3eab8Sdrh **       are UTF-8 and iso8859.
1109fbc3eab8Sdrh **
1110647cb0e1Sdrh **  sqlite -version
1111647cb0e1Sdrh **
1112647cb0e1Sdrh **       Return the version number of the SQLite library.
1113647cb0e1Sdrh **
1114fbc3eab8Sdrh **  sqlite -tcl-uses-utf
1115fbc3eab8Sdrh **
1116fbc3eab8Sdrh **       Return "1" if compiled with a Tcl uses UTF-8.  Return "0" if
1117fbc3eab8Sdrh **       not.  Used by tests to make sure the library was compiled
1118fbc3eab8Sdrh **       correctly.
111975897234Sdrh */
112022fbcb8dSdrh static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
1121bec3f402Sdrh   SqliteDb *p;
112222fbcb8dSdrh   void *pKey = 0;
112322fbcb8dSdrh   int nKey = 0;
112422fbcb8dSdrh   const char *zArg;
112575897234Sdrh   char *zErrMsg;
112622fbcb8dSdrh   const char *zFile;
112780290863Sdanielk1977   const char *zOpts[2] = {0, 0};
112806b2718aSdrh   char zBuf[80];
112922fbcb8dSdrh   if( objc==2 ){
113022fbcb8dSdrh     zArg = Tcl_GetStringFromObj(objv[1], 0);
113122fbcb8dSdrh     if( strcmp(zArg,"-encoding")==0 ){
11326f8a503dSdanielk1977       Tcl_AppendResult(interp,sqlite3_encoding,0);
1133fbc3eab8Sdrh       return TCL_OK;
1134fbc3eab8Sdrh     }
113522fbcb8dSdrh     if( strcmp(zArg,"-version")==0 ){
11366f8a503dSdanielk1977       Tcl_AppendResult(interp,sqlite3_version,0);
1137647cb0e1Sdrh       return TCL_OK;
1138647cb0e1Sdrh     }
11399eb9e26bSdrh     if( strcmp(zArg,"-has-codec")==0 ){
11409eb9e26bSdrh #ifdef SQLITE_HAS_CODEC
114122fbcb8dSdrh       Tcl_AppendResult(interp,"1",0);
114222fbcb8dSdrh #else
114322fbcb8dSdrh       Tcl_AppendResult(interp,"0",0);
114422fbcb8dSdrh #endif
114522fbcb8dSdrh       return TCL_OK;
114622fbcb8dSdrh     }
114722fbcb8dSdrh     if( strcmp(zArg,"-tcl-uses-utf")==0 ){
1148fbc3eab8Sdrh #ifdef TCL_UTF_MAX
1149fbc3eab8Sdrh       Tcl_AppendResult(interp,"1",0);
1150fbc3eab8Sdrh #else
1151fbc3eab8Sdrh       Tcl_AppendResult(interp,"0",0);
1152fbc3eab8Sdrh #endif
1153fbc3eab8Sdrh       return TCL_OK;
1154fbc3eab8Sdrh     }
1155fbc3eab8Sdrh   }
115622fbcb8dSdrh   if( objc==5 || objc==6 ){
115722fbcb8dSdrh     zArg = Tcl_GetStringFromObj(objv[objc-2], 0);
115822fbcb8dSdrh     if( strcmp(zArg,"-key")==0 ){
115922fbcb8dSdrh       pKey = Tcl_GetByteArrayFromObj(objv[objc-1], &nKey);
116022fbcb8dSdrh       objc -= 2;
116122fbcb8dSdrh     }
116222fbcb8dSdrh   }
116322fbcb8dSdrh   if( objc!=3 && objc!=4 ){
116422fbcb8dSdrh     Tcl_WrongNumArgs(interp, 1, objv,
11659eb9e26bSdrh #ifdef SQLITE_HAS_CODEC
11669eb9e26bSdrh       "HANDLE FILENAME ?-key CODEC-KEY?"
116722fbcb8dSdrh #else
116822fbcb8dSdrh       "HANDLE FILENAME ?MODE?"
116922fbcb8dSdrh #endif
117022fbcb8dSdrh     );
117175897234Sdrh     return TCL_ERROR;
117275897234Sdrh   }
117375897234Sdrh   zErrMsg = 0;
11744cdc9e84Sdrh   p = (SqliteDb*)Tcl_Alloc( sizeof(*p) );
117575897234Sdrh   if( p==0 ){
1176bec3f402Sdrh     Tcl_SetResult(interp, "malloc failed", TCL_STATIC);
1177bec3f402Sdrh     return TCL_ERROR;
1178bec3f402Sdrh   }
1179bec3f402Sdrh   memset(p, 0, sizeof(*p));
118022fbcb8dSdrh   zFile = Tcl_GetStringFromObj(objv[2], 0);
11819eb9e26bSdrh #ifdef SQLITE_HAS_CODEC
11826f8a503dSdanielk1977   p->db = sqlite3_open_encrypted(zFile, pKey, nKey, 0, &zErrMsg);
1183eb8ed70dSdrh #else
118480290863Sdanielk1977   if( objc>3 ){
118580290863Sdanielk1977     zOpts[0] = Tcl_GetString(objv[3]);
118680290863Sdanielk1977   }
118780290863Sdanielk1977   sqlite3_open(zFile, &p->db, zOpts);
118880290863Sdanielk1977   if( SQLITE_OK!=sqlite3_errcode(p->db) ){
118980290863Sdanielk1977     zErrMsg = strdup(sqlite3_errmsg(p->db));
119080290863Sdanielk1977     sqlite3_close(p->db);
119180290863Sdanielk1977     p->db = 0;
119280290863Sdanielk1977   }
1193eb8ed70dSdrh #endif
1194bec3f402Sdrh   if( p->db==0 ){
119575897234Sdrh     Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
1196bec3f402Sdrh     Tcl_Free((char*)p);
119775897234Sdrh     free(zErrMsg);
119875897234Sdrh     return TCL_ERROR;
119975897234Sdrh   }
120022fbcb8dSdrh   zArg = Tcl_GetStringFromObj(objv[1], 0);
120122fbcb8dSdrh   Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd);
1202c22bd47dSdrh 
120306b2718aSdrh   /* The return value is the value of the sqlite* pointer
120406b2718aSdrh   */
120506b2718aSdrh   sprintf(zBuf, "%p", p->db);
12065e5377fbSdrh   if( strncmp(zBuf,"0x",2) ){
12075e5377fbSdrh     sprintf(zBuf, "0x%p", p->db);
12085e5377fbSdrh   }
120906b2718aSdrh   Tcl_AppendResult(interp, zBuf, 0);
121006b2718aSdrh 
1211c22bd47dSdrh   /* If compiled with SQLITE_TEST turned on, then register the "md5sum"
121206b2718aSdrh   ** SQL function.
1213c22bd47dSdrh   */
121428b4e489Sdrh #ifdef SQLITE_TEST
121528b4e489Sdrh   {
121628b4e489Sdrh     extern void Md5_Register(sqlite*);
121728b4e489Sdrh     Md5_Register(p->db);
121828b4e489Sdrh    }
121928b4e489Sdrh #endif
122075897234Sdrh   return TCL_OK;
122175897234Sdrh }
122275897234Sdrh 
122375897234Sdrh /*
122490ca9753Sdrh ** Provide a dummy Tcl_InitStubs if we are using this as a static
122590ca9753Sdrh ** library.
122690ca9753Sdrh */
122790ca9753Sdrh #ifndef USE_TCL_STUBS
122890ca9753Sdrh # undef  Tcl_InitStubs
122990ca9753Sdrh # define Tcl_InitStubs(a,b,c)
123090ca9753Sdrh #endif
123190ca9753Sdrh 
123290ca9753Sdrh /*
123375897234Sdrh ** Initialize this module.
123475897234Sdrh **
123575897234Sdrh ** This Tcl module contains only a single new Tcl command named "sqlite".
123675897234Sdrh ** (Hence there is no namespace.  There is no point in using a namespace
123775897234Sdrh ** if the extension only supplies one new name!)  The "sqlite" command is
123875897234Sdrh ** used to open a new SQLite database.  See the DbMain() routine above
123975897234Sdrh ** for additional information.
124075897234Sdrh */
124175897234Sdrh int Sqlite_Init(Tcl_Interp *interp){
124290ca9753Sdrh   Tcl_InitStubs(interp, "8.0", 0);
124322fbcb8dSdrh   Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0);
12446d4abfbeSdrh   Tcl_PkgProvide(interp, "sqlite", "2.0");
124590ca9753Sdrh   return TCL_OK;
124690ca9753Sdrh }
124790ca9753Sdrh int Tclsqlite_Init(Tcl_Interp *interp){
124890ca9753Sdrh   Tcl_InitStubs(interp, "8.0", 0);
124922fbcb8dSdrh   Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0);
12506d4abfbeSdrh   Tcl_PkgProvide(interp, "sqlite", "2.0");
125175897234Sdrh   return TCL_OK;
125275897234Sdrh }
125375897234Sdrh int Sqlite_SafeInit(Tcl_Interp *interp){
125475897234Sdrh   return TCL_OK;
125575897234Sdrh }
125690ca9753Sdrh int Tclsqlite_SafeInit(Tcl_Interp *interp){
125790ca9753Sdrh   return TCL_OK;
125890ca9753Sdrh }
125975897234Sdrh 
12603cebbde3Sdrh #if 0
126175897234Sdrh /*
126275897234Sdrh ** If compiled using mktclapp, this routine runs to initialize
126375897234Sdrh ** everything.
126475897234Sdrh */
126575897234Sdrh int Et_AppInit(Tcl_Interp *interp){
126675897234Sdrh   return Sqlite_Init(interp);
126775897234Sdrh }
12683cebbde3Sdrh #endif
1269348784efSdrh 
1270348784efSdrh /*
1271348784efSdrh ** If the macro TCLSH is defined and is one, then put in code for the
1272348784efSdrh ** "main" routine that will initialize Tcl.
1273348784efSdrh */
1274348784efSdrh #if defined(TCLSH) && TCLSH==1
1275348784efSdrh static char zMainloop[] =
1276348784efSdrh   "set line {}\n"
1277348784efSdrh   "while {![eof stdin]} {\n"
1278348784efSdrh     "if {$line!=\"\"} {\n"
1279348784efSdrh       "puts -nonewline \"> \"\n"
1280348784efSdrh     "} else {\n"
1281348784efSdrh       "puts -nonewline \"% \"\n"
1282348784efSdrh     "}\n"
1283348784efSdrh     "flush stdout\n"
1284348784efSdrh     "append line [gets stdin]\n"
1285348784efSdrh     "if {[info complete $line]} {\n"
1286348784efSdrh       "if {[catch {uplevel #0 $line} result]} {\n"
1287348784efSdrh         "puts stderr \"Error: $result\"\n"
1288348784efSdrh       "} elseif {$result!=\"\"} {\n"
1289348784efSdrh         "puts $result\n"
1290348784efSdrh       "}\n"
1291348784efSdrh       "set line {}\n"
1292348784efSdrh     "} else {\n"
1293348784efSdrh       "append line \\n\n"
1294348784efSdrh     "}\n"
1295348784efSdrh   "}\n"
1296348784efSdrh ;
1297348784efSdrh 
1298348784efSdrh #define TCLSH_MAIN main   /* Needed to fake out mktclapp */
1299348784efSdrh int TCLSH_MAIN(int argc, char **argv){
1300348784efSdrh   Tcl_Interp *interp;
1301297ecf14Sdrh   Tcl_FindExecutable(argv[0]);
1302348784efSdrh   interp = Tcl_CreateInterp();
13034adee20fSdanielk1977   Sqlite_Init(interp);
1304d9b0257aSdrh #ifdef SQLITE_TEST
1305d1bf3512Sdrh   {
1306d1bf3512Sdrh     extern int Sqlitetest1_Init(Tcl_Interp*);
13075c4d9703Sdrh     extern int Sqlitetest2_Init(Tcl_Interp*);
13085c4d9703Sdrh     extern int Sqlitetest3_Init(Tcl_Interp*);
1309a6064dcfSdrh     extern int Sqlitetest4_Init(Tcl_Interp*);
1310998b56c3Sdanielk1977     extern int Sqlitetest5_Init(Tcl_Interp*);
1311efc251daSdrh     extern int Md5_Init(Tcl_Interp*);
13126490bebdSdanielk1977     Sqlitetest1_Init(interp);
13135c4d9703Sdrh     Sqlitetest2_Init(interp);
1314de647130Sdrh     Sqlitetest3_Init(interp);
1315fc57d7bfSdanielk1977     Sqlitetest4_Init(interp);
1316998b56c3Sdanielk1977     Sqlitetest5_Init(interp);
1317efc251daSdrh     Md5_Init(interp);
1318d1bf3512Sdrh   }
1319d1bf3512Sdrh #endif
1320348784efSdrh   if( argc>=2 ){
1321348784efSdrh     int i;
1322348784efSdrh     Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY);
1323348784efSdrh     Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
1324348784efSdrh     for(i=2; i<argc; i++){
1325348784efSdrh       Tcl_SetVar(interp, "argv", argv[i],
1326348784efSdrh           TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
1327348784efSdrh     }
1328348784efSdrh     if( Tcl_EvalFile(interp, argv[1])!=TCL_OK ){
13290de8c112Sdrh       const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
1330c61053b7Sdrh       if( zInfo==0 ) zInfo = interp->result;
1331c61053b7Sdrh       fprintf(stderr,"%s: %s\n", *argv, zInfo);
1332348784efSdrh       return 1;
1333348784efSdrh     }
1334348784efSdrh   }else{
1335348784efSdrh     Tcl_GlobalEval(interp, zMainloop);
1336348784efSdrh   }
1337348784efSdrh   return 0;
1338348784efSdrh }
1339348784efSdrh #endif /* TCLSH */
13406d31316cSdrh 
13416d31316cSdrh #endif /* !defined(NO_TCL) */
1342