xref: /sqlite-3.40.0/src/tclsqlite.c (revision a6064dcf)
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*a6064dcfSdrh ** $Id: tclsqlite.c,v 1.52 2003/12/19 02:52:09 drh 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 */
54b5a20d3cSdrh   char *zTrace;         /* The trace callback routine */
55348bb5d6Sdanielk1977   char *zProgress;      /* The progress callback routine */
56e22a334bSdrh   char *zAuth;          /* The authorization callback routine */
57cabb0819Sdrh   SqlFunc *pFunc;       /* List of SQL functions */
58dcd997eaSdrh   int rc;               /* Return code of most recent sqlite_exec() */
59bec3f402Sdrh };
60bec3f402Sdrh 
61bec3f402Sdrh /*
6275897234Sdrh ** An instance of this structure passes information thru the sqlite
6375897234Sdrh ** logic from the original TCL command into the callback routine.
6475897234Sdrh */
6575897234Sdrh typedef struct CallbackData CallbackData;
6675897234Sdrh struct CallbackData {
6775897234Sdrh   Tcl_Interp *interp;       /* The TCL interpreter */
6875897234Sdrh   char *zArray;             /* The array into which data is written */
696d31316cSdrh   Tcl_Obj *pCode;           /* The code to execute for each row */
70ce927065Sdrh   int once;                 /* Set for first callback only */
71960e8c63Sdrh   int tcl_rc;               /* Return code from TCL script */
7298808babSdrh   int nColName;             /* Number of entries in the azColName[] array */
7398808babSdrh   char **azColName;         /* Column names translated to UTF-8 */
7498808babSdrh };
75297ecf14Sdrh 
766d4abfbeSdrh #ifdef UTF_TRANSLATION_NEEDED
77297ecf14Sdrh /*
7875897234Sdrh ** Called for each row of the result.
796d4abfbeSdrh **
806d4abfbeSdrh ** This version is used when TCL expects UTF-8 data but the database
816d4abfbeSdrh ** uses the ISO8859 format.  A translation must occur from ISO8859 into
826d4abfbeSdrh ** UTF-8.
8375897234Sdrh */
8475897234Sdrh static int DbEvalCallback(
8575897234Sdrh   void *clientData,      /* An instance of CallbackData */
8675897234Sdrh   int nCol,              /* Number of columns in the result */
8775897234Sdrh   char ** azCol,         /* Data for each column */
8875897234Sdrh   char ** azN            /* Name for each column */
8975897234Sdrh ){
9075897234Sdrh   CallbackData *cbData = (CallbackData*)clientData;
9175897234Sdrh   int i, rc;
92297ecf14Sdrh   Tcl_DString dCol;
936d4abfbeSdrh   Tcl_DStringInit(&dCol);
94ce927065Sdrh   if( cbData->azColName==0 ){
95ce927065Sdrh     assert( cbData->once );
96ce927065Sdrh     cbData->once = 0;
97ce927065Sdrh     if( cbData->zArray[0] ){
986d4abfbeSdrh       Tcl_SetVar2(cbData->interp, cbData->zArray, "*", "", 0);
99ce927065Sdrh     }
1006d4abfbeSdrh     cbData->azColName = malloc( nCol*sizeof(char*) );
1016d4abfbeSdrh     if( cbData->azColName==0 ){ return 1; }
1026d4abfbeSdrh     cbData->nColName = nCol;
1036d4abfbeSdrh     for(i=0; i<nCol; i++){
1046d4abfbeSdrh       Tcl_ExternalToUtfDString(NULL, azN[i], -1, &dCol);
1056d4abfbeSdrh       cbData->azColName[i] = malloc( Tcl_DStringLength(&dCol) + 1 );
1066d4abfbeSdrh       if( cbData->azColName[i] ){
1076d4abfbeSdrh         strcpy(cbData->azColName[i], Tcl_DStringValue(&dCol));
108ce927065Sdrh       }else{
109ce927065Sdrh         return 1;
1106d4abfbeSdrh       }
111ce927065Sdrh       if( cbData->zArray[0] ){
112ce927065Sdrh         Tcl_SetVar2(cbData->interp, cbData->zArray, "*",
113ce927065Sdrh              Tcl_DStringValue(&dCol), TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
114704027f1Sdrh         if( azN[nCol]!=0 ){
1155080aaa7Sdrh           Tcl_DString dType;
1165080aaa7Sdrh           Tcl_DStringInit(&dType);
117fa173a76Sdrh           Tcl_DStringAppend(&dType, "typeof:", -1);
118fa173a76Sdrh           Tcl_DStringAppend(&dType, Tcl_DStringValue(&dCol), -1);
119fa173a76Sdrh           Tcl_DStringFree(&dCol);
1205080aaa7Sdrh           Tcl_ExternalToUtfDString(NULL, azN[i+nCol], -1, &dCol);
121fa173a76Sdrh           Tcl_SetVar2(cbData->interp, cbData->zArray,
122fa173a76Sdrh                Tcl_DStringValue(&dType), Tcl_DStringValue(&dCol),
123fa173a76Sdrh                TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
124fa173a76Sdrh           Tcl_DStringFree(&dType);
1256d4abfbeSdrh         }
1265080aaa7Sdrh       }
127fa173a76Sdrh 
1286d4abfbeSdrh       Tcl_DStringFree(&dCol);
1296d4abfbeSdrh     }
1306d4abfbeSdrh   }
1316d4abfbeSdrh   if( azCol!=0 ){
1326d4abfbeSdrh     if( cbData->zArray[0] ){
1336d4abfbeSdrh       for(i=0; i<nCol; i++){
1346d4abfbeSdrh         char *z = azCol[i];
1356d4abfbeSdrh         if( z==0 ) z = "";
1366d4abfbeSdrh         Tcl_DStringInit(&dCol);
1376d4abfbeSdrh         Tcl_ExternalToUtfDString(NULL, z, -1, &dCol);
1386d4abfbeSdrh         Tcl_SetVar2(cbData->interp, cbData->zArray, cbData->azColName[i],
1396d4abfbeSdrh               Tcl_DStringValue(&dCol), 0);
1406d4abfbeSdrh         Tcl_DStringFree(&dCol);
1416d4abfbeSdrh       }
1426d4abfbeSdrh     }else{
1436d4abfbeSdrh       for(i=0; i<nCol; i++){
1446d4abfbeSdrh         char *z = azCol[i];
1456d4abfbeSdrh         if( z==0 ) z = "";
1466d4abfbeSdrh         Tcl_DStringInit(&dCol);
1476d4abfbeSdrh         Tcl_ExternalToUtfDString(NULL, z, -1, &dCol);
1486d4abfbeSdrh         Tcl_SetVar(cbData->interp, cbData->azColName[i],
1496d4abfbeSdrh                    Tcl_DStringValue(&dCol), 0);
1506d4abfbeSdrh         Tcl_DStringFree(&dCol);
1516d4abfbeSdrh       }
1526d4abfbeSdrh     }
1536d4abfbeSdrh   }
1546d4abfbeSdrh   rc = Tcl_EvalObj(cbData->interp, cbData->pCode);
1556d4abfbeSdrh   if( rc==TCL_CONTINUE ) rc = TCL_OK;
1566d4abfbeSdrh   cbData->tcl_rc = rc;
1576d4abfbeSdrh   return rc!=TCL_OK;
1586d4abfbeSdrh }
1596d4abfbeSdrh #endif /* UTF_TRANSLATION_NEEDED */
1606d4abfbeSdrh 
1616d4abfbeSdrh #ifndef UTF_TRANSLATION_NEEDED
1626d4abfbeSdrh /*
1636d4abfbeSdrh ** Called for each row of the result.
1646d4abfbeSdrh **
1656d4abfbeSdrh ** This version is used when either of the following is true:
1666d4abfbeSdrh **
1676d4abfbeSdrh **    (1) This version of TCL uses UTF-8 and the data in the
1686d4abfbeSdrh **        SQLite database is already in the UTF-8 format.
1696d4abfbeSdrh **
1706d4abfbeSdrh **    (2) This version of TCL uses ISO8859 and the data in the
1716d4abfbeSdrh **        SQLite database is already in the ISO8859 format.
1726d4abfbeSdrh */
1736d4abfbeSdrh static int DbEvalCallback(
1746d4abfbeSdrh   void *clientData,      /* An instance of CallbackData */
1756d4abfbeSdrh   int nCol,              /* Number of columns in the result */
1766d4abfbeSdrh   char ** azCol,         /* Data for each column */
1776d4abfbeSdrh   char ** azN            /* Name for each column */
1786d4abfbeSdrh ){
1796d4abfbeSdrh   CallbackData *cbData = (CallbackData*)clientData;
1806d4abfbeSdrh   int i, rc;
1816a535340Sdrh   if( azCol==0 || (cbData->once && cbData->zArray[0]) ){
1829b0d0a8bSdrh     Tcl_SetVar2(cbData->interp, cbData->zArray, "*", "", 0);
18375897234Sdrh     for(i=0; i<nCol; i++){
18475897234Sdrh       Tcl_SetVar2(cbData->interp, cbData->zArray, "*", azN[i],
18575897234Sdrh          TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
1865080aaa7Sdrh       if( azN[nCol] ){
1875080aaa7Sdrh         char *z = sqlite_mprintf("typeof:%s", azN[i]);
1885080aaa7Sdrh         Tcl_SetVar2(cbData->interp, cbData->zArray, z, azN[i+nCol],
189fa173a76Sdrh            TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
190fa173a76Sdrh         sqlite_freemem(z);
19175897234Sdrh       }
1925080aaa7Sdrh     }
1936a535340Sdrh     cbData->once = 0;
19475897234Sdrh   }
1956a535340Sdrh   if( azCol!=0 ){
1966a535340Sdrh     if( cbData->zArray[0] ){
19775897234Sdrh       for(i=0; i<nCol; i++){
198c61053b7Sdrh         char *z = azCol[i];
199c61053b7Sdrh         if( z==0 ) z = "";
200c61053b7Sdrh         Tcl_SetVar2(cbData->interp, cbData->zArray, azN[i], z, 0);
20175897234Sdrh       }
20275897234Sdrh     }else{
20375897234Sdrh       for(i=0; i<nCol; i++){
204c61053b7Sdrh         char *z = azCol[i];
205c61053b7Sdrh         if( z==0 ) z = "";
206c61053b7Sdrh         Tcl_SetVar(cbData->interp, azN[i], z, 0);
20775897234Sdrh       }
20875897234Sdrh     }
2096a535340Sdrh   }
2106d31316cSdrh   rc = Tcl_EvalObj(cbData->interp, cbData->pCode);
211960e8c63Sdrh   if( rc==TCL_CONTINUE ) rc = TCL_OK;
212960e8c63Sdrh   cbData->tcl_rc = rc;
213960e8c63Sdrh   return rc!=TCL_OK;
21475897234Sdrh }
2156d4abfbeSdrh #endif
21675897234Sdrh 
21775897234Sdrh /*
2186d31316cSdrh ** This is an alternative callback for database queries.  Instead
2196d31316cSdrh ** of invoking a TCL script to handle the result, this callback just
2206d31316cSdrh ** appends each column of the result to a list.  After the query
2216d31316cSdrh ** is complete, the list is returned.
2226d31316cSdrh */
2236d31316cSdrh static int DbEvalCallback2(
2246d31316cSdrh   void *clientData,      /* An instance of CallbackData */
2256d31316cSdrh   int nCol,              /* Number of columns in the result */
2266d31316cSdrh   char ** azCol,         /* Data for each column */
2276d31316cSdrh   char ** azN            /* Name for each column */
2286d31316cSdrh ){
2296d31316cSdrh   Tcl_Obj *pList = (Tcl_Obj*)clientData;
2306d31316cSdrh   int i;
2316a535340Sdrh   if( azCol==0 ) return 0;
2326d31316cSdrh   for(i=0; i<nCol; i++){
2336d31316cSdrh     Tcl_Obj *pElem;
2346d31316cSdrh     if( azCol[i] && *azCol[i] ){
235297ecf14Sdrh #ifdef UTF_TRANSLATION_NEEDED
236297ecf14Sdrh       Tcl_DString dCol;
237297ecf14Sdrh       Tcl_DStringInit(&dCol);
238297ecf14Sdrh       Tcl_ExternalToUtfDString(NULL, azCol[i], -1, &dCol);
239297ecf14Sdrh       pElem = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1);
240297ecf14Sdrh       Tcl_DStringFree(&dCol);
241297ecf14Sdrh #else
2426d31316cSdrh       pElem = Tcl_NewStringObj(azCol[i], -1);
243297ecf14Sdrh #endif
2446d31316cSdrh     }else{
2456d31316cSdrh       pElem = Tcl_NewObj();
2466d31316cSdrh     }
2476d31316cSdrh     Tcl_ListObjAppendElement(0, pList, pElem);
2486d31316cSdrh   }
2496d31316cSdrh   return 0;
2506d31316cSdrh }
2516d31316cSdrh 
2526d31316cSdrh /*
2535d9d7576Sdrh ** This is a second alternative callback for database queries.  A the
2545d9d7576Sdrh ** first column of the first row of the result is made the TCL result.
2555d9d7576Sdrh */
2565d9d7576Sdrh static int DbEvalCallback3(
2575d9d7576Sdrh   void *clientData,      /* An instance of CallbackData */
2585d9d7576Sdrh   int nCol,              /* Number of columns in the result */
2595d9d7576Sdrh   char ** azCol,         /* Data for each column */
2605d9d7576Sdrh   char ** azN            /* Name for each column */
2615d9d7576Sdrh ){
2625d9d7576Sdrh   Tcl_Interp *interp = (Tcl_Interp*)clientData;
2635d9d7576Sdrh   Tcl_Obj *pElem;
2645d9d7576Sdrh   if( azCol==0 ) return 1;
2655d9d7576Sdrh   if( nCol==0 ) return 1;
2665d9d7576Sdrh #ifdef UTF_TRANSLATION_NEEDED
2675d9d7576Sdrh   {
2685d9d7576Sdrh     Tcl_DString dCol;
2695d9d7576Sdrh     Tcl_DStringInit(&dCol);
2705d9d7576Sdrh     Tcl_ExternalToUtfDString(NULL, azCol[0], -1, &dCol);
2715d9d7576Sdrh     pElem = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1);
2725d9d7576Sdrh     Tcl_DStringFree(&dCol);
2735d9d7576Sdrh   }
2745d9d7576Sdrh #else
2755d9d7576Sdrh   pElem = Tcl_NewStringObj(azCol[0], -1);
2765d9d7576Sdrh #endif
2775d9d7576Sdrh   Tcl_SetObjResult(interp, pElem);
2785d9d7576Sdrh   return 1;
2795d9d7576Sdrh }
2805d9d7576Sdrh 
2815d9d7576Sdrh /*
28275897234Sdrh ** Called when the command is deleted.
28375897234Sdrh */
28475897234Sdrh static void DbDeleteCmd(void *db){
285bec3f402Sdrh   SqliteDb *pDb = (SqliteDb*)db;
286bec3f402Sdrh   sqlite_close(pDb->db);
287cabb0819Sdrh   while( pDb->pFunc ){
288cabb0819Sdrh     SqlFunc *pFunc = pDb->pFunc;
289cabb0819Sdrh     pDb->pFunc = pFunc->pNext;
290cabb0819Sdrh     Tcl_Free((char*)pFunc);
291cabb0819Sdrh   }
292bec3f402Sdrh   if( pDb->zBusy ){
293bec3f402Sdrh     Tcl_Free(pDb->zBusy);
294bec3f402Sdrh   }
295b5a20d3cSdrh   if( pDb->zTrace ){
296b5a20d3cSdrh     Tcl_Free(pDb->zTrace);
2970d1a643aSdrh   }
298e22a334bSdrh   if( pDb->zAuth ){
299e22a334bSdrh     Tcl_Free(pDb->zAuth);
300e22a334bSdrh   }
301bec3f402Sdrh   Tcl_Free((char*)pDb);
302bec3f402Sdrh }
303bec3f402Sdrh 
304bec3f402Sdrh /*
305bec3f402Sdrh ** This routine is called when a database file is locked while trying
306bec3f402Sdrh ** to execute SQL.
307bec3f402Sdrh */
308bec3f402Sdrh static int DbBusyHandler(void *cd, const char *zTable, int nTries){
309bec3f402Sdrh   SqliteDb *pDb = (SqliteDb*)cd;
310bec3f402Sdrh   int rc;
311bec3f402Sdrh   char zVal[30];
312bec3f402Sdrh   char *zCmd;
313bec3f402Sdrh   Tcl_DString cmd;
314bec3f402Sdrh 
315bec3f402Sdrh   Tcl_DStringInit(&cmd);
316bec3f402Sdrh   Tcl_DStringAppend(&cmd, pDb->zBusy, -1);
317bec3f402Sdrh   Tcl_DStringAppendElement(&cmd, zTable);
318bec3f402Sdrh   sprintf(zVal, " %d", nTries);
319bec3f402Sdrh   Tcl_DStringAppend(&cmd, zVal, -1);
320bec3f402Sdrh   zCmd = Tcl_DStringValue(&cmd);
321bec3f402Sdrh   rc = Tcl_Eval(pDb->interp, zCmd);
322bec3f402Sdrh   Tcl_DStringFree(&cmd);
323bec3f402Sdrh   if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
324bec3f402Sdrh     return 0;
325bec3f402Sdrh   }
326bec3f402Sdrh   return 1;
32775897234Sdrh }
32875897234Sdrh 
32975897234Sdrh /*
330348bb5d6Sdanielk1977 ** This routine is invoked as the 'progress callback' for the database.
331348bb5d6Sdanielk1977 */
332348bb5d6Sdanielk1977 static int DbProgressHandler(void *cd){
333348bb5d6Sdanielk1977   SqliteDb *pDb = (SqliteDb*)cd;
334348bb5d6Sdanielk1977   int rc;
335348bb5d6Sdanielk1977 
336348bb5d6Sdanielk1977   assert( pDb->zProgress );
337348bb5d6Sdanielk1977   rc = Tcl_Eval(pDb->interp, pDb->zProgress);
338348bb5d6Sdanielk1977   if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
339348bb5d6Sdanielk1977     return 1;
340348bb5d6Sdanielk1977   }
341348bb5d6Sdanielk1977   return 0;
342348bb5d6Sdanielk1977 }
343348bb5d6Sdanielk1977 
344348bb5d6Sdanielk1977 /*
345b5a20d3cSdrh ** This routine is called by the SQLite trace handler whenever a new
346b5a20d3cSdrh ** block of SQL is executed.  The TCL script in pDb->zTrace is executed.
3470d1a643aSdrh */
348b5a20d3cSdrh static void DbTraceHandler(void *cd, const char *zSql){
3490d1a643aSdrh   SqliteDb *pDb = (SqliteDb*)cd;
350b5a20d3cSdrh   Tcl_DString str;
3510d1a643aSdrh 
352b5a20d3cSdrh   Tcl_DStringInit(&str);
353b5a20d3cSdrh   Tcl_DStringAppend(&str, pDb->zTrace, -1);
354b5a20d3cSdrh   Tcl_DStringAppendElement(&str, zSql);
355b5a20d3cSdrh   Tcl_Eval(pDb->interp, Tcl_DStringValue(&str));
356b5a20d3cSdrh   Tcl_DStringFree(&str);
357b5a20d3cSdrh   Tcl_ResetResult(pDb->interp);
3580d1a643aSdrh }
3590d1a643aSdrh 
3600d1a643aSdrh /*
361cabb0819Sdrh ** This routine is called to evaluate an SQL function implemented
362cabb0819Sdrh ** using TCL script.
363cabb0819Sdrh */
364cabb0819Sdrh static void tclSqlFunc(sqlite_func *context, int argc, const char **argv){
365cabb0819Sdrh   SqlFunc *p = sqlite_user_data(context);
366cabb0819Sdrh   Tcl_DString cmd;
367cabb0819Sdrh   int i;
368cabb0819Sdrh   int rc;
369cabb0819Sdrh 
370cabb0819Sdrh   Tcl_DStringInit(&cmd);
371cabb0819Sdrh   Tcl_DStringAppend(&cmd, p->zScript, -1);
372cabb0819Sdrh   for(i=0; i<argc; i++){
373cabb0819Sdrh     Tcl_DStringAppendElement(&cmd, argv[i] ? argv[i] : "");
374cabb0819Sdrh   }
375cabb0819Sdrh   rc = Tcl_Eval(p->interp, Tcl_DStringValue(&cmd));
376cabb0819Sdrh   if( rc ){
377cabb0819Sdrh     sqlite_set_result_error(context, Tcl_GetStringResult(p->interp), -1);
378cabb0819Sdrh   }else{
379cabb0819Sdrh     sqlite_set_result_string(context, Tcl_GetStringResult(p->interp), -1);
380cabb0819Sdrh   }
381cabb0819Sdrh }
382e22a334bSdrh #ifndef SQLITE_OMIT_AUTHORIZATION
383e22a334bSdrh /*
384e22a334bSdrh ** This is the authentication function.  It appends the authentication
385e22a334bSdrh ** type code and the two arguments to zCmd[] then invokes the result
386e22a334bSdrh ** on the interpreter.  The reply is examined to determine if the
387e22a334bSdrh ** authentication fails or succeeds.
388e22a334bSdrh */
389e22a334bSdrh static int auth_callback(
390e22a334bSdrh   void *pArg,
391e22a334bSdrh   int code,
392e22a334bSdrh   const char *zArg1,
393e22a334bSdrh   const char *zArg2,
394e22a334bSdrh   const char *zArg3,
395e22a334bSdrh   const char *zArg4
396e22a334bSdrh ){
397e22a334bSdrh   char *zCode;
398e22a334bSdrh   Tcl_DString str;
399e22a334bSdrh   int rc;
400e22a334bSdrh   const char *zReply;
401e22a334bSdrh   SqliteDb *pDb = (SqliteDb*)pArg;
402e22a334bSdrh 
403e22a334bSdrh   switch( code ){
404e22a334bSdrh     case SQLITE_COPY              : zCode="SQLITE_COPY"; break;
405e22a334bSdrh     case SQLITE_CREATE_INDEX      : zCode="SQLITE_CREATE_INDEX"; break;
406e22a334bSdrh     case SQLITE_CREATE_TABLE      : zCode="SQLITE_CREATE_TABLE"; break;
407e22a334bSdrh     case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break;
408e22a334bSdrh     case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break;
409e22a334bSdrh     case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break;
410e22a334bSdrh     case SQLITE_CREATE_TEMP_VIEW  : zCode="SQLITE_CREATE_TEMP_VIEW"; break;
411e22a334bSdrh     case SQLITE_CREATE_TRIGGER    : zCode="SQLITE_CREATE_TRIGGER"; break;
412e22a334bSdrh     case SQLITE_CREATE_VIEW       : zCode="SQLITE_CREATE_VIEW"; break;
413e22a334bSdrh     case SQLITE_DELETE            : zCode="SQLITE_DELETE"; break;
414e22a334bSdrh     case SQLITE_DROP_INDEX        : zCode="SQLITE_DROP_INDEX"; break;
415e22a334bSdrh     case SQLITE_DROP_TABLE        : zCode="SQLITE_DROP_TABLE"; break;
416e22a334bSdrh     case SQLITE_DROP_TEMP_INDEX   : zCode="SQLITE_DROP_TEMP_INDEX"; break;
417e22a334bSdrh     case SQLITE_DROP_TEMP_TABLE   : zCode="SQLITE_DROP_TEMP_TABLE"; break;
418e22a334bSdrh     case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break;
419e22a334bSdrh     case SQLITE_DROP_TEMP_VIEW    : zCode="SQLITE_DROP_TEMP_VIEW"; break;
420e22a334bSdrh     case SQLITE_DROP_TRIGGER      : zCode="SQLITE_DROP_TRIGGER"; break;
421e22a334bSdrh     case SQLITE_DROP_VIEW         : zCode="SQLITE_DROP_VIEW"; break;
422e22a334bSdrh     case SQLITE_INSERT            : zCode="SQLITE_INSERT"; break;
423e22a334bSdrh     case SQLITE_PRAGMA            : zCode="SQLITE_PRAGMA"; break;
424e22a334bSdrh     case SQLITE_READ              : zCode="SQLITE_READ"; break;
425e22a334bSdrh     case SQLITE_SELECT            : zCode="SQLITE_SELECT"; break;
426e22a334bSdrh     case SQLITE_TRANSACTION       : zCode="SQLITE_TRANSACTION"; break;
427e22a334bSdrh     case SQLITE_UPDATE            : zCode="SQLITE_UPDATE"; break;
42881e293b4Sdrh     case SQLITE_ATTACH            : zCode="SQLITE_ATTACH"; break;
42981e293b4Sdrh     case SQLITE_DETACH            : zCode="SQLITE_DETACH"; break;
430e22a334bSdrh     default                       : zCode="????"; break;
431e22a334bSdrh   }
432e22a334bSdrh   Tcl_DStringInit(&str);
433e22a334bSdrh   Tcl_DStringAppend(&str, pDb->zAuth, -1);
434e22a334bSdrh   Tcl_DStringAppendElement(&str, zCode);
435e22a334bSdrh   Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : "");
436e22a334bSdrh   Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : "");
437e22a334bSdrh   Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : "");
438e22a334bSdrh   Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : "");
439e22a334bSdrh   rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str));
440e22a334bSdrh   Tcl_DStringFree(&str);
441e22a334bSdrh   zReply = Tcl_GetStringResult(pDb->interp);
442e22a334bSdrh   if( strcmp(zReply,"SQLITE_OK")==0 ){
443e22a334bSdrh     rc = SQLITE_OK;
444e22a334bSdrh   }else if( strcmp(zReply,"SQLITE_DENY")==0 ){
445e22a334bSdrh     rc = SQLITE_DENY;
446e22a334bSdrh   }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){
447e22a334bSdrh     rc = SQLITE_IGNORE;
448e22a334bSdrh   }else{
449e22a334bSdrh     rc = 999;
450e22a334bSdrh   }
451e22a334bSdrh   return rc;
452e22a334bSdrh }
453e22a334bSdrh #endif /* SQLITE_OMIT_AUTHORIZATION */
454cabb0819Sdrh 
455cabb0819Sdrh /*
45675897234Sdrh ** The "sqlite" command below creates a new Tcl command for each
45775897234Sdrh ** connection it opens to an SQLite database.  This routine is invoked
45875897234Sdrh ** whenever one of those connection-specific commands is executed
45975897234Sdrh ** in Tcl.  For example, if you run Tcl code like this:
46075897234Sdrh **
46175897234Sdrh **       sqlite db1  "my_database"
46275897234Sdrh **       db1 close
46375897234Sdrh **
46475897234Sdrh ** The first command opens a connection to the "my_database" database
46575897234Sdrh ** and calls that connection "db1".  The second command causes this
46675897234Sdrh ** subroutine to be invoked.
46775897234Sdrh */
4686d31316cSdrh static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
469bec3f402Sdrh   SqliteDb *pDb = (SqliteDb*)cd;
4706d31316cSdrh   int choice;
4710de8c112Sdrh   static const char *DB_strs[] = {
472b5a20d3cSdrh     "authorizer",         "busy",              "changes",
473b5a20d3cSdrh     "close",              "complete",          "errorcode",
474b5a20d3cSdrh     "eval",               "function",          "last_insert_rowid",
4755d9d7576Sdrh     "onecolumn",          "timeout",            "trace",
476348bb5d6Sdanielk1977     "progress",           0
4776d31316cSdrh   };
478411995dcSdrh   enum DB_enum {
479b5a20d3cSdrh     DB_AUTHORIZER,        DB_BUSY,             DB_CHANGES,
480b5a20d3cSdrh     DB_CLOSE,             DB_COMPLETE,         DB_ERRORCODE,
481b5a20d3cSdrh     DB_EVAL,              DB_FUNCTION,         DB_LAST_INSERT_ROWID,
4825d9d7576Sdrh     DB_ONECOLUMN,         DB_TIMEOUT,          DB_TRACE,
483348bb5d6Sdanielk1977     DB_PROGRESS,
4846d31316cSdrh   };
4856d31316cSdrh 
4866d31316cSdrh   if( objc<2 ){
4876d31316cSdrh     Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
48875897234Sdrh     return TCL_ERROR;
48975897234Sdrh   }
490411995dcSdrh   if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){
4916d31316cSdrh     return TCL_ERROR;
4926d31316cSdrh   }
4936d31316cSdrh 
494411995dcSdrh   switch( (enum DB_enum)choice ){
49575897234Sdrh 
496e22a334bSdrh   /*    $db authorizer ?CALLBACK?
497e22a334bSdrh   **
498e22a334bSdrh   ** Invoke the given callback to authorize each SQL operation as it is
499e22a334bSdrh   ** compiled.  5 arguments are appended to the callback before it is
500e22a334bSdrh   ** invoked:
501e22a334bSdrh   **
502e22a334bSdrh   **   (1) The authorization type (ex: SQLITE_CREATE_TABLE, SQLITE_INSERT, ...)
503e22a334bSdrh   **   (2) First descriptive name (depends on authorization type)
504e22a334bSdrh   **   (3) Second descriptive name
505e22a334bSdrh   **   (4) Name of the database (ex: "main", "temp")
506e22a334bSdrh   **   (5) Name of trigger that is doing the access
507e22a334bSdrh   **
508e22a334bSdrh   ** The callback should return on of the following strings: SQLITE_OK,
509e22a334bSdrh   ** SQLITE_IGNORE, or SQLITE_DENY.  Any other return value is an error.
510e22a334bSdrh   **
511e22a334bSdrh   ** If this method is invoked with no arguments, the current authorization
512e22a334bSdrh   ** callback string is returned.
513e22a334bSdrh   */
514e22a334bSdrh   case DB_AUTHORIZER: {
515e22a334bSdrh     if( objc>3 ){
516e22a334bSdrh       Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
517e22a334bSdrh     }else if( objc==2 ){
518b5a20d3cSdrh       if( pDb->zAuth ){
519e22a334bSdrh         Tcl_AppendResult(interp, pDb->zAuth, 0);
520e22a334bSdrh       }
521e22a334bSdrh     }else{
522e22a334bSdrh       char *zAuth;
523e22a334bSdrh       int len;
524e22a334bSdrh       if( pDb->zAuth ){
525e22a334bSdrh         Tcl_Free(pDb->zAuth);
526e22a334bSdrh       }
527e22a334bSdrh       zAuth = Tcl_GetStringFromObj(objv[2], &len);
528e22a334bSdrh       if( zAuth && len>0 ){
529e22a334bSdrh         pDb->zAuth = Tcl_Alloc( len + 1 );
530e22a334bSdrh         strcpy(pDb->zAuth, zAuth);
531e22a334bSdrh       }else{
532e22a334bSdrh         pDb->zAuth = 0;
533e22a334bSdrh       }
534e22a334bSdrh #ifndef SQLITE_OMIT_AUTHORIZATION
535e22a334bSdrh       if( pDb->zAuth ){
536e22a334bSdrh         pDb->interp = interp;
537e22a334bSdrh         sqlite_set_authorizer(pDb->db, auth_callback, pDb);
538e22a334bSdrh       }else{
539e22a334bSdrh         sqlite_set_authorizer(pDb->db, 0, 0);
540e22a334bSdrh       }
541e22a334bSdrh #endif
542e22a334bSdrh     }
543e22a334bSdrh     break;
544e22a334bSdrh   }
545e22a334bSdrh 
546bec3f402Sdrh   /*    $db busy ?CALLBACK?
547bec3f402Sdrh   **
548bec3f402Sdrh   ** Invoke the given callback if an SQL statement attempts to open
549bec3f402Sdrh   ** a locked database file.
550bec3f402Sdrh   */
5516d31316cSdrh   case DB_BUSY: {
5526d31316cSdrh     if( objc>3 ){
5536d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "CALLBACK");
554bec3f402Sdrh       return TCL_ERROR;
5556d31316cSdrh     }else if( objc==2 ){
556bec3f402Sdrh       if( pDb->zBusy ){
557bec3f402Sdrh         Tcl_AppendResult(interp, pDb->zBusy, 0);
558bec3f402Sdrh       }
559bec3f402Sdrh     }else{
5606d31316cSdrh       char *zBusy;
5616d31316cSdrh       int len;
562bec3f402Sdrh       if( pDb->zBusy ){
563bec3f402Sdrh         Tcl_Free(pDb->zBusy);
5646d31316cSdrh       }
5656d31316cSdrh       zBusy = Tcl_GetStringFromObj(objv[2], &len);
5666d31316cSdrh       if( zBusy && len>0 ){
5676d31316cSdrh         pDb->zBusy = Tcl_Alloc( len + 1 );
5686d31316cSdrh         strcpy(pDb->zBusy, zBusy);
5696d31316cSdrh       }else{
570bec3f402Sdrh         pDb->zBusy = 0;
571bec3f402Sdrh       }
572bec3f402Sdrh       if( pDb->zBusy ){
573bec3f402Sdrh         pDb->interp = interp;
574bec3f402Sdrh         sqlite_busy_handler(pDb->db, DbBusyHandler, pDb);
5756d31316cSdrh       }else{
5766d31316cSdrh         sqlite_busy_handler(pDb->db, 0, 0);
577bec3f402Sdrh       }
578bec3f402Sdrh     }
5796d31316cSdrh     break;
5806d31316cSdrh   }
581bec3f402Sdrh 
582348bb5d6Sdanielk1977   /*    $db progress ?N CALLBACK?
583348bb5d6Sdanielk1977   **
584348bb5d6Sdanielk1977   ** Invoke the given callback every N virtual machine opcodes while executing
585348bb5d6Sdanielk1977   ** queries.
586348bb5d6Sdanielk1977   */
587348bb5d6Sdanielk1977   case DB_PROGRESS: {
588348bb5d6Sdanielk1977     if( objc==2 ){
589348bb5d6Sdanielk1977       if( pDb->zProgress ){
590348bb5d6Sdanielk1977         Tcl_AppendResult(interp, pDb->zProgress, 0);
591348bb5d6Sdanielk1977       }
592348bb5d6Sdanielk1977     }else if( objc==4 ){
593348bb5d6Sdanielk1977       char *zProgress;
594348bb5d6Sdanielk1977       int len;
595348bb5d6Sdanielk1977       int N;
596348bb5d6Sdanielk1977       if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){
597348bb5d6Sdanielk1977 	return TCL_ERROR;
598348bb5d6Sdanielk1977       };
599348bb5d6Sdanielk1977       if( pDb->zProgress ){
600348bb5d6Sdanielk1977         Tcl_Free(pDb->zProgress);
601348bb5d6Sdanielk1977       }
602348bb5d6Sdanielk1977       zProgress = Tcl_GetStringFromObj(objv[3], &len);
603348bb5d6Sdanielk1977       if( zProgress && len>0 ){
604348bb5d6Sdanielk1977         pDb->zProgress = Tcl_Alloc( len + 1 );
605348bb5d6Sdanielk1977         strcpy(pDb->zProgress, zProgress);
606348bb5d6Sdanielk1977       }else{
607348bb5d6Sdanielk1977         pDb->zProgress = 0;
608348bb5d6Sdanielk1977       }
609348bb5d6Sdanielk1977 #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
610348bb5d6Sdanielk1977       if( pDb->zProgress ){
611348bb5d6Sdanielk1977         pDb->interp = interp;
612348bb5d6Sdanielk1977         sqlite_progress_handler(pDb->db, N, DbProgressHandler, pDb);
613348bb5d6Sdanielk1977       }else{
614348bb5d6Sdanielk1977         sqlite_progress_handler(pDb->db, 0, 0, 0);
615348bb5d6Sdanielk1977       }
616348bb5d6Sdanielk1977 #endif
617348bb5d6Sdanielk1977     }else{
618348bb5d6Sdanielk1977       Tcl_WrongNumArgs(interp, 2, objv, "N CALLBACK");
619348bb5d6Sdanielk1977       return TCL_ERROR;
620348bb5d6Sdanielk1977     }
621348bb5d6Sdanielk1977     break;
622348bb5d6Sdanielk1977   }
623348bb5d6Sdanielk1977 
624c8d30ac1Sdrh   /*
625c8d30ac1Sdrh   **     $db changes
626c8d30ac1Sdrh   **
627c8d30ac1Sdrh   ** Return the number of rows that were modified, inserted, or deleted by
628c8d30ac1Sdrh   ** the most recent "eval".
629c8d30ac1Sdrh   */
630c8d30ac1Sdrh   case DB_CHANGES: {
631c8d30ac1Sdrh     Tcl_Obj *pResult;
632c8d30ac1Sdrh     int nChange;
633c8d30ac1Sdrh     if( objc!=2 ){
634c8d30ac1Sdrh       Tcl_WrongNumArgs(interp, 2, objv, "");
635c8d30ac1Sdrh       return TCL_ERROR;
636c8d30ac1Sdrh     }
637c8d30ac1Sdrh     nChange = sqlite_changes(pDb->db);
638c8d30ac1Sdrh     pResult = Tcl_GetObjResult(interp);
639c8d30ac1Sdrh     Tcl_SetIntObj(pResult, nChange);
640c8d30ac1Sdrh     break;
641c8d30ac1Sdrh   }
642c8d30ac1Sdrh 
64375897234Sdrh   /*    $db close
64475897234Sdrh   **
64575897234Sdrh   ** Shutdown the database
64675897234Sdrh   */
6476d31316cSdrh   case DB_CLOSE: {
6486d31316cSdrh     Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0));
6496d31316cSdrh     break;
6506d31316cSdrh   }
65175897234Sdrh 
65275897234Sdrh   /*    $db complete SQL
65375897234Sdrh   **
65475897234Sdrh   ** Return TRUE if SQL is a complete SQL statement.  Return FALSE if
65575897234Sdrh   ** additional lines of input are needed.  This is similar to the
65675897234Sdrh   ** built-in "info complete" command of Tcl.
65775897234Sdrh   */
6586d31316cSdrh   case DB_COMPLETE: {
6596d31316cSdrh     Tcl_Obj *pResult;
6606d31316cSdrh     int isComplete;
6616d31316cSdrh     if( objc!=3 ){
6626d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "SQL");
66375897234Sdrh       return TCL_ERROR;
66475897234Sdrh     }
6656d31316cSdrh     isComplete = sqlite_complete( Tcl_GetStringFromObj(objv[2], 0) );
6666d31316cSdrh     pResult = Tcl_GetObjResult(interp);
6676d31316cSdrh     Tcl_SetBooleanObj(pResult, isComplete);
6686d31316cSdrh     break;
6696d31316cSdrh   }
67075897234Sdrh 
67175897234Sdrh   /*
672dcd997eaSdrh   **    $db errorcode
673dcd997eaSdrh   **
674dcd997eaSdrh   ** Return the numeric error code that was returned by the most recent
675dcd997eaSdrh   ** call to sqlite_exec().
676dcd997eaSdrh   */
677dcd997eaSdrh   case DB_ERRORCODE: {
678dcd997eaSdrh     Tcl_SetObjResult(interp, Tcl_NewIntObj(pDb->rc));
679dcd997eaSdrh     break;
680dcd997eaSdrh   }
681dcd997eaSdrh 
682dcd997eaSdrh   /*
68375897234Sdrh   **    $db eval $sql ?array {  ...code... }?
68475897234Sdrh   **
68575897234Sdrh   ** The SQL statement in $sql is evaluated.  For each row, the values are
686bec3f402Sdrh   ** placed in elements of the array named "array" and ...code... is executed.
68775897234Sdrh   ** If "array" and "code" are omitted, then no callback is every invoked.
68875897234Sdrh   ** If "array" is an empty string, then the values are placed in variables
68975897234Sdrh   ** that have the same name as the fields extracted by the query.
69075897234Sdrh   */
6916d31316cSdrh   case DB_EVAL: {
69275897234Sdrh     CallbackData cbData;
69375897234Sdrh     char *zErrMsg;
6946d31316cSdrh     char *zSql;
69575897234Sdrh     int rc;
696297ecf14Sdrh #ifdef UTF_TRANSLATION_NEEDED
697297ecf14Sdrh     Tcl_DString dSql;
6986d4abfbeSdrh     int i;
699297ecf14Sdrh #endif
70075897234Sdrh 
7016d31316cSdrh     if( objc!=5 && objc!=3 ){
7026d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME CODE?");
70375897234Sdrh       return TCL_ERROR;
70475897234Sdrh     }
705bec3f402Sdrh     pDb->interp = interp;
7066d31316cSdrh     zSql = Tcl_GetStringFromObj(objv[2], 0);
707297ecf14Sdrh #ifdef UTF_TRANSLATION_NEEDED
708297ecf14Sdrh     Tcl_DStringInit(&dSql);
709297ecf14Sdrh     Tcl_UtfToExternalDString(NULL, zSql, -1, &dSql);
710297ecf14Sdrh     zSql = Tcl_DStringValue(&dSql);
711297ecf14Sdrh #endif
7126d31316cSdrh     Tcl_IncrRefCount(objv[2]);
7136d31316cSdrh     if( objc==5 ){
71475897234Sdrh       cbData.interp = interp;
715dcc581ccSdrh       cbData.once = 1;
7166d31316cSdrh       cbData.zArray = Tcl_GetStringFromObj(objv[3], 0);
7176d31316cSdrh       cbData.pCode = objv[4];
718960e8c63Sdrh       cbData.tcl_rc = TCL_OK;
7196d4abfbeSdrh       cbData.nColName = 0;
7206d4abfbeSdrh       cbData.azColName = 0;
72175897234Sdrh       zErrMsg = 0;
7226d31316cSdrh       Tcl_IncrRefCount(objv[3]);
7236d31316cSdrh       Tcl_IncrRefCount(objv[4]);
7246d31316cSdrh       rc = sqlite_exec(pDb->db, zSql, DbEvalCallback, &cbData, &zErrMsg);
7256d31316cSdrh       Tcl_DecrRefCount(objv[4]);
7266d31316cSdrh       Tcl_DecrRefCount(objv[3]);
727960e8c63Sdrh       if( cbData.tcl_rc==TCL_BREAK ){ cbData.tcl_rc = TCL_OK; }
72875897234Sdrh     }else{
7296d31316cSdrh       Tcl_Obj *pList = Tcl_NewObj();
730960e8c63Sdrh       cbData.tcl_rc = TCL_OK;
7316d31316cSdrh       rc = sqlite_exec(pDb->db, zSql, DbEvalCallback2, pList, &zErrMsg);
7326d31316cSdrh       Tcl_SetObjResult(interp, pList);
73375897234Sdrh     }
734dcd997eaSdrh     pDb->rc = rc;
735b798fa64Sdrh     if( rc==SQLITE_ABORT ){
736b798fa64Sdrh       if( zErrMsg ) free(zErrMsg);
737b798fa64Sdrh       rc = cbData.tcl_rc;
738b798fa64Sdrh     }else if( zErrMsg ){
73975897234Sdrh       Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
74075897234Sdrh       free(zErrMsg);
741960e8c63Sdrh       rc = TCL_ERROR;
742b798fa64Sdrh     }else if( rc!=SQLITE_OK ){
7436d4abfbeSdrh       Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
7446d4abfbeSdrh       rc = TCL_ERROR;
745960e8c63Sdrh     }else{
74675897234Sdrh     }
7476d31316cSdrh     Tcl_DecrRefCount(objv[2]);
748297ecf14Sdrh #ifdef UTF_TRANSLATION_NEEDED
749297ecf14Sdrh     Tcl_DStringFree(&dSql);
7506d4abfbeSdrh     if( objc==5 && cbData.azColName ){
7516d4abfbeSdrh       for(i=0; i<cbData.nColName; i++){
7526d4abfbeSdrh         if( cbData.azColName[i] ) free(cbData.azColName[i]);
7536d4abfbeSdrh       }
7546d4abfbeSdrh       free(cbData.azColName);
755ce927065Sdrh       cbData.azColName = 0;
7566d4abfbeSdrh     }
757297ecf14Sdrh #endif
75875897234Sdrh     return rc;
7596d31316cSdrh   }
760bec3f402Sdrh 
761bec3f402Sdrh   /*
762cabb0819Sdrh   **     $db function NAME SCRIPT
763cabb0819Sdrh   **
764cabb0819Sdrh   ** Create a new SQL function called NAME.  Whenever that function is
765cabb0819Sdrh   ** called, invoke SCRIPT to evaluate the function.
766cabb0819Sdrh   */
767cabb0819Sdrh   case DB_FUNCTION: {
768cabb0819Sdrh     SqlFunc *pFunc;
769cabb0819Sdrh     char *zName;
770cabb0819Sdrh     char *zScript;
771cabb0819Sdrh     int nScript;
772cabb0819Sdrh     if( objc!=4 ){
773cabb0819Sdrh       Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT");
774cabb0819Sdrh       return TCL_ERROR;
775cabb0819Sdrh     }
776cabb0819Sdrh     zName = Tcl_GetStringFromObj(objv[2], 0);
777cabb0819Sdrh     zScript = Tcl_GetStringFromObj(objv[3], &nScript);
778cabb0819Sdrh     pFunc = (SqlFunc*)Tcl_Alloc( sizeof(*pFunc) + nScript + 1 );
779cabb0819Sdrh     if( pFunc==0 ) return TCL_ERROR;
780cabb0819Sdrh     pFunc->interp = interp;
781cabb0819Sdrh     pFunc->pNext = pDb->pFunc;
782cabb0819Sdrh     pFunc->zScript = (char*)&pFunc[1];
783cabb0819Sdrh     strcpy(pFunc->zScript, zScript);
784cabb0819Sdrh     sqlite_create_function(pDb->db, zName, -1, tclSqlFunc, pFunc);
785cabb0819Sdrh     sqlite_function_type(pDb->db, zName, SQLITE_NUMERIC);
786cabb0819Sdrh     break;
787cabb0819Sdrh   }
788cabb0819Sdrh 
789cabb0819Sdrh   /*
790af9ff33aSdrh   **     $db last_insert_rowid
791af9ff33aSdrh   **
792af9ff33aSdrh   ** Return an integer which is the ROWID for the most recent insert.
793af9ff33aSdrh   */
794af9ff33aSdrh   case DB_LAST_INSERT_ROWID: {
795af9ff33aSdrh     Tcl_Obj *pResult;
796af9ff33aSdrh     int rowid;
797af9ff33aSdrh     if( objc!=2 ){
798af9ff33aSdrh       Tcl_WrongNumArgs(interp, 2, objv, "");
799af9ff33aSdrh       return TCL_ERROR;
800af9ff33aSdrh     }
801af9ff33aSdrh     rowid = sqlite_last_insert_rowid(pDb->db);
802af9ff33aSdrh     pResult = Tcl_GetObjResult(interp);
803af9ff33aSdrh     Tcl_SetIntObj(pResult, rowid);
804af9ff33aSdrh     break;
805af9ff33aSdrh   }
806af9ff33aSdrh 
807af9ff33aSdrh   /*
8085d9d7576Sdrh   **     $db onecolumn SQL
8095d9d7576Sdrh   **
8105d9d7576Sdrh   ** Return a single column from a single row of the given SQL query.
8115d9d7576Sdrh   */
8125d9d7576Sdrh   case DB_ONECOLUMN: {
8135d9d7576Sdrh     int rc;
8145d9d7576Sdrh     char *zSql;
8155d9d7576Sdrh     char *zErrMsg = 0;
8165d9d7576Sdrh     if( objc!=3 ){
8175d9d7576Sdrh       Tcl_WrongNumArgs(interp, 2, objv, "SQL");
8185d9d7576Sdrh       return TCL_ERROR;
8195d9d7576Sdrh     }
8205d9d7576Sdrh     zSql = Tcl_GetStringFromObj(objv[2], 0);
8215d9d7576Sdrh     rc = sqlite_exec(pDb->db, zSql, DbEvalCallback3, interp, &zErrMsg);
8225d9d7576Sdrh     if( rc==SQLITE_ABORT ){
8235d9d7576Sdrh       /* Do nothing.  This is normal. */
8245d9d7576Sdrh     }else if( zErrMsg ){
8255d9d7576Sdrh       Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
8265d9d7576Sdrh       free(zErrMsg);
8275d9d7576Sdrh       rc = TCL_ERROR;
8285d9d7576Sdrh     }else if( rc!=SQLITE_OK ){
8295d9d7576Sdrh       Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
8305d9d7576Sdrh       rc = TCL_ERROR;
8315d9d7576Sdrh     }
8325d9d7576Sdrh     break;
8335d9d7576Sdrh   }
8345d9d7576Sdrh 
8355d9d7576Sdrh   /*
836bec3f402Sdrh   **     $db timeout MILLESECONDS
837bec3f402Sdrh   **
838bec3f402Sdrh   ** Delay for the number of milliseconds specified when a file is locked.
839bec3f402Sdrh   */
8406d31316cSdrh   case DB_TIMEOUT: {
841bec3f402Sdrh     int ms;
8426d31316cSdrh     if( objc!=3 ){
8436d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "MILLISECONDS");
844bec3f402Sdrh       return TCL_ERROR;
84575897234Sdrh     }
8466d31316cSdrh     if( Tcl_GetIntFromObj(interp, objv[2], &ms) ) return TCL_ERROR;
847bec3f402Sdrh     sqlite_busy_timeout(pDb->db, ms);
8486d31316cSdrh     break;
84975897234Sdrh   }
850b5a20d3cSdrh 
851b5a20d3cSdrh   /*    $db trace ?CALLBACK?
852b5a20d3cSdrh   **
853b5a20d3cSdrh   ** Make arrangements to invoke the CALLBACK routine for each SQL statement
854b5a20d3cSdrh   ** that is executed.  The text of the SQL is appended to CALLBACK before
855b5a20d3cSdrh   ** it is executed.
856b5a20d3cSdrh   */
857b5a20d3cSdrh   case DB_TRACE: {
858b5a20d3cSdrh     if( objc>3 ){
859b5a20d3cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
860b5a20d3cSdrh     }else if( objc==2 ){
861b5a20d3cSdrh       if( pDb->zTrace ){
862b5a20d3cSdrh         Tcl_AppendResult(interp, pDb->zTrace, 0);
863b5a20d3cSdrh       }
864b5a20d3cSdrh     }else{
865b5a20d3cSdrh       char *zTrace;
866b5a20d3cSdrh       int len;
867b5a20d3cSdrh       if( pDb->zTrace ){
868b5a20d3cSdrh         Tcl_Free(pDb->zTrace);
869b5a20d3cSdrh       }
870b5a20d3cSdrh       zTrace = Tcl_GetStringFromObj(objv[2], &len);
871b5a20d3cSdrh       if( zTrace && len>0 ){
872b5a20d3cSdrh         pDb->zTrace = Tcl_Alloc( len + 1 );
873b5a20d3cSdrh         strcpy(pDb->zTrace, zTrace);
874b5a20d3cSdrh       }else{
875b5a20d3cSdrh         pDb->zTrace = 0;
876b5a20d3cSdrh       }
877b5a20d3cSdrh       if( pDb->zTrace ){
878b5a20d3cSdrh         pDb->interp = interp;
879b5a20d3cSdrh         sqlite_trace(pDb->db, DbTraceHandler, pDb);
880b5a20d3cSdrh       }else{
881b5a20d3cSdrh         sqlite_trace(pDb->db, 0, 0);
882b5a20d3cSdrh       }
883b5a20d3cSdrh     }
884b5a20d3cSdrh     break;
885b5a20d3cSdrh   }
886b5a20d3cSdrh 
8876d31316cSdrh   } /* End of the SWITCH statement */
88875897234Sdrh   return TCL_OK;
88975897234Sdrh }
89075897234Sdrh 
89175897234Sdrh /*
89275897234Sdrh **   sqlite DBNAME FILENAME ?MODE?
89375897234Sdrh **
89475897234Sdrh ** This is the main Tcl command.  When the "sqlite" Tcl command is
89575897234Sdrh ** invoked, this routine runs to process that command.
89675897234Sdrh **
89775897234Sdrh ** The first argument, DBNAME, is an arbitrary name for a new
89875897234Sdrh ** database connection.  This command creates a new command named
89975897234Sdrh ** DBNAME that is used to control that connection.  The database
90075897234Sdrh ** connection is deleted when the DBNAME command is deleted.
90175897234Sdrh **
90275897234Sdrh ** The second argument is the name of the directory that contains
90375897234Sdrh ** the sqlite database that is to be accessed.
904fbc3eab8Sdrh **
905fbc3eab8Sdrh ** For testing purposes, we also support the following:
906fbc3eab8Sdrh **
907fbc3eab8Sdrh **  sqlite -encoding
908fbc3eab8Sdrh **
909fbc3eab8Sdrh **       Return the encoding used by LIKE and GLOB operators.  Choices
910fbc3eab8Sdrh **       are UTF-8 and iso8859.
911fbc3eab8Sdrh **
912647cb0e1Sdrh **  sqlite -version
913647cb0e1Sdrh **
914647cb0e1Sdrh **       Return the version number of the SQLite library.
915647cb0e1Sdrh **
916fbc3eab8Sdrh **  sqlite -tcl-uses-utf
917fbc3eab8Sdrh **
918fbc3eab8Sdrh **       Return "1" if compiled with a Tcl uses UTF-8.  Return "0" if
919fbc3eab8Sdrh **       not.  Used by tests to make sure the library was compiled
920fbc3eab8Sdrh **       correctly.
92175897234Sdrh */
92275897234Sdrh static int DbMain(void *cd, Tcl_Interp *interp, int argc, char **argv){
92375897234Sdrh   int mode;
924bec3f402Sdrh   SqliteDb *p;
92575897234Sdrh   char *zErrMsg;
92606b2718aSdrh   char zBuf[80];
927fbc3eab8Sdrh   if( argc==2 ){
928fbc3eab8Sdrh     if( strcmp(argv[1],"-encoding")==0 ){
929fbc3eab8Sdrh       Tcl_AppendResult(interp,sqlite_encoding,0);
930fbc3eab8Sdrh       return TCL_OK;
931fbc3eab8Sdrh     }
932647cb0e1Sdrh     if( strcmp(argv[1],"-version")==0 ){
933647cb0e1Sdrh       Tcl_AppendResult(interp,sqlite_version,0);
934647cb0e1Sdrh       return TCL_OK;
935647cb0e1Sdrh     }
936fbc3eab8Sdrh     if( strcmp(argv[1],"-tcl-uses-utf")==0 ){
937fbc3eab8Sdrh #ifdef TCL_UTF_MAX
938fbc3eab8Sdrh       Tcl_AppendResult(interp,"1",0);
939fbc3eab8Sdrh #else
940fbc3eab8Sdrh       Tcl_AppendResult(interp,"0",0);
941fbc3eab8Sdrh #endif
942fbc3eab8Sdrh       return TCL_OK;
943fbc3eab8Sdrh     }
944fbc3eab8Sdrh   }
94575897234Sdrh   if( argc!=3 && argc!=4 ){
94675897234Sdrh     Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
94775897234Sdrh        " HANDLE FILENAME ?MODE?\"", 0);
94875897234Sdrh     return TCL_ERROR;
94975897234Sdrh   }
95075897234Sdrh   if( argc==3 ){
95158b9576bSdrh     mode = 0666;
95275897234Sdrh   }else if( Tcl_GetInt(interp, argv[3], &mode)!=TCL_OK ){
95375897234Sdrh     return TCL_ERROR;
95475897234Sdrh   }
95575897234Sdrh   zErrMsg = 0;
9564cdc9e84Sdrh   p = (SqliteDb*)Tcl_Alloc( sizeof(*p) );
95775897234Sdrh   if( p==0 ){
958bec3f402Sdrh     Tcl_SetResult(interp, "malloc failed", TCL_STATIC);
959bec3f402Sdrh     return TCL_ERROR;
960bec3f402Sdrh   }
961bec3f402Sdrh   memset(p, 0, sizeof(*p));
962bec3f402Sdrh   p->db = sqlite_open(argv[2], mode, &zErrMsg);
963bec3f402Sdrh   if( p->db==0 ){
96475897234Sdrh     Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
965bec3f402Sdrh     Tcl_Free((char*)p);
96675897234Sdrh     free(zErrMsg);
96775897234Sdrh     return TCL_ERROR;
96875897234Sdrh   }
9696d31316cSdrh   Tcl_CreateObjCommand(interp, argv[1], DbObjCmd, (char*)p, DbDeleteCmd);
970c22bd47dSdrh 
97106b2718aSdrh   /* The return value is the value of the sqlite* pointer
97206b2718aSdrh   */
97306b2718aSdrh   sprintf(zBuf, "%p", p->db);
9745e5377fbSdrh   if( strncmp(zBuf,"0x",2) ){
9755e5377fbSdrh     sprintf(zBuf, "0x%p", p->db);
9765e5377fbSdrh   }
97706b2718aSdrh   Tcl_AppendResult(interp, zBuf, 0);
97806b2718aSdrh 
979c22bd47dSdrh   /* If compiled with SQLITE_TEST turned on, then register the "md5sum"
98006b2718aSdrh   ** SQL function.
981c22bd47dSdrh   */
98228b4e489Sdrh #ifdef SQLITE_TEST
98328b4e489Sdrh   {
98428b4e489Sdrh     extern void Md5_Register(sqlite*);
98528b4e489Sdrh     Md5_Register(p->db);
98628b4e489Sdrh    }
98728b4e489Sdrh #endif
98875897234Sdrh   return TCL_OK;
98975897234Sdrh }
99075897234Sdrh 
99175897234Sdrh /*
99290ca9753Sdrh ** Provide a dummy Tcl_InitStubs if we are using this as a static
99390ca9753Sdrh ** library.
99490ca9753Sdrh */
99590ca9753Sdrh #ifndef USE_TCL_STUBS
99690ca9753Sdrh # undef  Tcl_InitStubs
99790ca9753Sdrh # define Tcl_InitStubs(a,b,c)
99890ca9753Sdrh #endif
99990ca9753Sdrh 
100090ca9753Sdrh /*
100175897234Sdrh ** Initialize this module.
100275897234Sdrh **
100375897234Sdrh ** This Tcl module contains only a single new Tcl command named "sqlite".
100475897234Sdrh ** (Hence there is no namespace.  There is no point in using a namespace
100575897234Sdrh ** if the extension only supplies one new name!)  The "sqlite" command is
100675897234Sdrh ** used to open a new SQLite database.  See the DbMain() routine above
100775897234Sdrh ** for additional information.
100875897234Sdrh */
100975897234Sdrh int Sqlite_Init(Tcl_Interp *interp){
101090ca9753Sdrh   Tcl_InitStubs(interp, "8.0", 0);
1011c2eef3b3Sdrh   Tcl_CreateCommand(interp, "sqlite", (Tcl_CmdProc*)DbMain, 0, 0);
10126d4abfbeSdrh   Tcl_PkgProvide(interp, "sqlite", "2.0");
101390ca9753Sdrh   return TCL_OK;
101490ca9753Sdrh }
101590ca9753Sdrh int Tclsqlite_Init(Tcl_Interp *interp){
101690ca9753Sdrh   Tcl_InitStubs(interp, "8.0", 0);
1017c2eef3b3Sdrh   Tcl_CreateCommand(interp, "sqlite", (Tcl_CmdProc*)DbMain, 0, 0);
10186d4abfbeSdrh   Tcl_PkgProvide(interp, "sqlite", "2.0");
101975897234Sdrh   return TCL_OK;
102075897234Sdrh }
102175897234Sdrh int Sqlite_SafeInit(Tcl_Interp *interp){
102275897234Sdrh   return TCL_OK;
102375897234Sdrh }
102490ca9753Sdrh int Tclsqlite_SafeInit(Tcl_Interp *interp){
102590ca9753Sdrh   return TCL_OK;
102690ca9753Sdrh }
102775897234Sdrh 
10283cebbde3Sdrh #if 0
102975897234Sdrh /*
103075897234Sdrh ** If compiled using mktclapp, this routine runs to initialize
103175897234Sdrh ** everything.
103275897234Sdrh */
103375897234Sdrh int Et_AppInit(Tcl_Interp *interp){
103475897234Sdrh   return Sqlite_Init(interp);
103575897234Sdrh }
10363cebbde3Sdrh #endif
1037348784efSdrh 
1038348784efSdrh /*
1039348784efSdrh ** If the macro TCLSH is defined and is one, then put in code for the
1040348784efSdrh ** "main" routine that will initialize Tcl.
1041348784efSdrh */
1042348784efSdrh #if defined(TCLSH) && TCLSH==1
1043348784efSdrh static char zMainloop[] =
1044348784efSdrh   "set line {}\n"
1045348784efSdrh   "while {![eof stdin]} {\n"
1046348784efSdrh     "if {$line!=\"\"} {\n"
1047348784efSdrh       "puts -nonewline \"> \"\n"
1048348784efSdrh     "} else {\n"
1049348784efSdrh       "puts -nonewline \"% \"\n"
1050348784efSdrh     "}\n"
1051348784efSdrh     "flush stdout\n"
1052348784efSdrh     "append line [gets stdin]\n"
1053348784efSdrh     "if {[info complete $line]} {\n"
1054348784efSdrh       "if {[catch {uplevel #0 $line} result]} {\n"
1055348784efSdrh         "puts stderr \"Error: $result\"\n"
1056348784efSdrh       "} elseif {$result!=\"\"} {\n"
1057348784efSdrh         "puts $result\n"
1058348784efSdrh       "}\n"
1059348784efSdrh       "set line {}\n"
1060348784efSdrh     "} else {\n"
1061348784efSdrh       "append line \\n\n"
1062348784efSdrh     "}\n"
1063348784efSdrh   "}\n"
1064348784efSdrh ;
1065348784efSdrh 
1066348784efSdrh #define TCLSH_MAIN main   /* Needed to fake out mktclapp */
1067348784efSdrh int TCLSH_MAIN(int argc, char **argv){
1068348784efSdrh   Tcl_Interp *interp;
1069297ecf14Sdrh   Tcl_FindExecutable(argv[0]);
1070348784efSdrh   interp = Tcl_CreateInterp();
1071348784efSdrh   Sqlite_Init(interp);
1072d9b0257aSdrh #ifdef SQLITE_TEST
1073d1bf3512Sdrh   {
1074d1bf3512Sdrh     extern int Sqlitetest1_Init(Tcl_Interp*);
10755c4d9703Sdrh     extern int Sqlitetest2_Init(Tcl_Interp*);
10765c4d9703Sdrh     extern int Sqlitetest3_Init(Tcl_Interp*);
1077*a6064dcfSdrh     extern int Sqlitetest4_Init(Tcl_Interp*);
1078efc251daSdrh     extern int Md5_Init(Tcl_Interp*);
1079d1bf3512Sdrh     Sqlitetest1_Init(interp);
10805c4d9703Sdrh     Sqlitetest2_Init(interp);
10815c4d9703Sdrh     Sqlitetest3_Init(interp);
1082*a6064dcfSdrh     Sqlitetest4_Init(interp);
1083efc251daSdrh     Md5_Init(interp);
1084d1bf3512Sdrh   }
1085d1bf3512Sdrh #endif
1086348784efSdrh   if( argc>=2 ){
1087348784efSdrh     int i;
1088348784efSdrh     Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY);
1089348784efSdrh     Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
1090348784efSdrh     for(i=2; i<argc; i++){
1091348784efSdrh       Tcl_SetVar(interp, "argv", argv[i],
1092348784efSdrh           TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
1093348784efSdrh     }
1094348784efSdrh     if( Tcl_EvalFile(interp, argv[1])!=TCL_OK ){
10950de8c112Sdrh       const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
1096c61053b7Sdrh       if( zInfo==0 ) zInfo = interp->result;
1097c61053b7Sdrh       fprintf(stderr,"%s: %s\n", *argv, zInfo);
1098348784efSdrh       return 1;
1099348784efSdrh     }
1100348784efSdrh   }else{
1101348784efSdrh     Tcl_GlobalEval(interp, zMainloop);
1102348784efSdrh   }
1103348784efSdrh   return 0;
1104348784efSdrh }
1105348784efSdrh #endif /* TCLSH */
11066d31316cSdrh 
11076d31316cSdrh #endif /* !defined(NO_TCL) */
1108