xref: /sqlite-3.40.0/src/tclsqlite.c (revision 5080aaa7)
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*5080aaa7Sdrh ** $Id: tclsqlite.c,v 1.38 2002/07/11 12:18:17 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 /*
35bec3f402Sdrh ** There is one instance of this structure for each SQLite database
36bec3f402Sdrh ** that has been opened by the SQLite TCL interface.
37bec3f402Sdrh */
38bec3f402Sdrh typedef struct SqliteDb SqliteDb;
39bec3f402Sdrh struct SqliteDb {
40bec3f402Sdrh   sqlite *db;           /* The "real" database structure */
41bec3f402Sdrh   Tcl_Interp *interp;   /* The interpreter used for this database */
426d31316cSdrh   char *zBusy;          /* The busy callback routine */
43bec3f402Sdrh };
44bec3f402Sdrh 
45bec3f402Sdrh /*
4675897234Sdrh ** An instance of this structure passes information thru the sqlite
4775897234Sdrh ** logic from the original TCL command into the callback routine.
4875897234Sdrh */
4975897234Sdrh typedef struct CallbackData CallbackData;
5075897234Sdrh struct CallbackData {
5175897234Sdrh   Tcl_Interp *interp;       /* The TCL interpreter */
5275897234Sdrh   char *zArray;             /* The array into which data is written */
536d31316cSdrh   Tcl_Obj *pCode;           /* The code to execute for each row */
54ce927065Sdrh   int once;                 /* Set for first callback only */
55960e8c63Sdrh   int tcl_rc;               /* Return code from TCL script */
5698808babSdrh   int nColName;             /* Number of entries in the azColName[] array */
5798808babSdrh   char **azColName;         /* Column names translated to UTF-8 */
5898808babSdrh };
59297ecf14Sdrh 
606d4abfbeSdrh #ifdef UTF_TRANSLATION_NEEDED
61297ecf14Sdrh /*
6275897234Sdrh ** Called for each row of the result.
636d4abfbeSdrh **
646d4abfbeSdrh ** This version is used when TCL expects UTF-8 data but the database
656d4abfbeSdrh ** uses the ISO8859 format.  A translation must occur from ISO8859 into
666d4abfbeSdrh ** UTF-8.
6775897234Sdrh */
6875897234Sdrh static int DbEvalCallback(
6975897234Sdrh   void *clientData,      /* An instance of CallbackData */
7075897234Sdrh   int nCol,              /* Number of columns in the result */
7175897234Sdrh   char ** azCol,         /* Data for each column */
7275897234Sdrh   char ** azN            /* Name for each column */
7375897234Sdrh ){
7475897234Sdrh   CallbackData *cbData = (CallbackData*)clientData;
7575897234Sdrh   int i, rc;
76297ecf14Sdrh   Tcl_DString dCol;
776d4abfbeSdrh   Tcl_DStringInit(&dCol);
78ce927065Sdrh   if( cbData->azColName==0 ){
79ce927065Sdrh     assert( cbData->once );
80ce927065Sdrh     cbData->once = 0;
81ce927065Sdrh     if( cbData->zArray[0] ){
826d4abfbeSdrh       Tcl_SetVar2(cbData->interp, cbData->zArray, "*", "", 0);
83ce927065Sdrh     }
846d4abfbeSdrh     cbData->azColName = malloc( nCol*sizeof(char*) );
856d4abfbeSdrh     if( cbData->azColName==0 ){ return 1; }
866d4abfbeSdrh     cbData->nColName = nCol;
876d4abfbeSdrh     for(i=0; i<nCol; i++){
886d4abfbeSdrh       Tcl_ExternalToUtfDString(NULL, azN[i], -1, &dCol);
896d4abfbeSdrh       cbData->azColName[i] = malloc( Tcl_DStringLength(&dCol) + 1 );
906d4abfbeSdrh       if( cbData->azColName[i] ){
916d4abfbeSdrh         strcpy(cbData->azColName[i], Tcl_DStringValue(&dCol));
92ce927065Sdrh       }else{
93ce927065Sdrh         return 1;
946d4abfbeSdrh       }
95ce927065Sdrh       if( cbData->zArray[0] ){
96ce927065Sdrh         Tcl_SetVar2(cbData->interp, cbData->zArray, "*",
97ce927065Sdrh              Tcl_DStringValue(&dCol), TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
98*5080aaa7Sdrh         if( azN[nCol]!=0 } {
99*5080aaa7Sdrh           Tcl_DString dType;
100*5080aaa7Sdrh           Tcl_DStringInit(&dType);
101fa173a76Sdrh           Tcl_DStringAppend(&dType, "typeof:", -1);
102fa173a76Sdrh           Tcl_DStringAppend(&dType, Tcl_DStringValue(&dCol), -1);
103fa173a76Sdrh           Tcl_DStringFree(&dCol);
104*5080aaa7Sdrh           Tcl_ExternalToUtfDString(NULL, azN[i+nCol], -1, &dCol);
105fa173a76Sdrh           Tcl_SetVar2(cbData->interp, cbData->zArray,
106fa173a76Sdrh                Tcl_DStringValue(&dType), Tcl_DStringValue(&dCol),
107fa173a76Sdrh                TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
108fa173a76Sdrh           Tcl_DStringFree(&dType);
1096d4abfbeSdrh         }
110*5080aaa7Sdrh       }
111fa173a76Sdrh 
1126d4abfbeSdrh       Tcl_DStringFree(&dCol);
1136d4abfbeSdrh     }
1146d4abfbeSdrh   }
1156d4abfbeSdrh   if( azCol!=0 ){
1166d4abfbeSdrh     if( cbData->zArray[0] ){
1176d4abfbeSdrh       for(i=0; i<nCol; i++){
1186d4abfbeSdrh         char *z = azCol[i];
1196d4abfbeSdrh         if( z==0 ) z = "";
1206d4abfbeSdrh         Tcl_DStringInit(&dCol);
1216d4abfbeSdrh         Tcl_ExternalToUtfDString(NULL, z, -1, &dCol);
1226d4abfbeSdrh         Tcl_SetVar2(cbData->interp, cbData->zArray, cbData->azColName[i],
1236d4abfbeSdrh               Tcl_DStringValue(&dCol), 0);
1246d4abfbeSdrh         Tcl_DStringFree(&dCol);
1256d4abfbeSdrh       }
1266d4abfbeSdrh     }else{
1276d4abfbeSdrh       for(i=0; i<nCol; i++){
1286d4abfbeSdrh         char *z = azCol[i];
1296d4abfbeSdrh         if( z==0 ) z = "";
1306d4abfbeSdrh         Tcl_DStringInit(&dCol);
1316d4abfbeSdrh         Tcl_ExternalToUtfDString(NULL, z, -1, &dCol);
1326d4abfbeSdrh         Tcl_SetVar(cbData->interp, cbData->azColName[i],
1336d4abfbeSdrh                    Tcl_DStringValue(&dCol), 0);
1346d4abfbeSdrh         Tcl_DStringFree(&dCol);
1356d4abfbeSdrh       }
1366d4abfbeSdrh     }
1376d4abfbeSdrh   }
1386d4abfbeSdrh   rc = Tcl_EvalObj(cbData->interp, cbData->pCode);
1396d4abfbeSdrh   if( rc==TCL_CONTINUE ) rc = TCL_OK;
1406d4abfbeSdrh   cbData->tcl_rc = rc;
1416d4abfbeSdrh   return rc!=TCL_OK;
1426d4abfbeSdrh }
1436d4abfbeSdrh #endif /* UTF_TRANSLATION_NEEDED */
1446d4abfbeSdrh 
1456d4abfbeSdrh #ifndef UTF_TRANSLATION_NEEDED
1466d4abfbeSdrh /*
1476d4abfbeSdrh ** Called for each row of the result.
1486d4abfbeSdrh **
1496d4abfbeSdrh ** This version is used when either of the following is true:
1506d4abfbeSdrh **
1516d4abfbeSdrh **    (1) This version of TCL uses UTF-8 and the data in the
1526d4abfbeSdrh **        SQLite database is already in the UTF-8 format.
1536d4abfbeSdrh **
1546d4abfbeSdrh **    (2) This version of TCL uses ISO8859 and the data in the
1556d4abfbeSdrh **        SQLite database is already in the ISO8859 format.
1566d4abfbeSdrh */
1576d4abfbeSdrh static int DbEvalCallback(
1586d4abfbeSdrh   void *clientData,      /* An instance of CallbackData */
1596d4abfbeSdrh   int nCol,              /* Number of columns in the result */
1606d4abfbeSdrh   char ** azCol,         /* Data for each column */
1616d4abfbeSdrh   char ** azN            /* Name for each column */
1626d4abfbeSdrh ){
1636d4abfbeSdrh   CallbackData *cbData = (CallbackData*)clientData;
1646d4abfbeSdrh   int i, rc;
1656a535340Sdrh   if( azCol==0 || (cbData->once && cbData->zArray[0]) ){
1669b0d0a8bSdrh     Tcl_SetVar2(cbData->interp, cbData->zArray, "*", "", 0);
16775897234Sdrh     for(i=0; i<nCol; i++){
16875897234Sdrh       Tcl_SetVar2(cbData->interp, cbData->zArray, "*", azN[i],
16975897234Sdrh          TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
170*5080aaa7Sdrh       if( azN[nCol] ){
171*5080aaa7Sdrh         char *z = sqlite_mprintf("typeof:%s", azN[i]);
172*5080aaa7Sdrh         Tcl_SetVar2(cbData->interp, cbData->zArray, z, azN[i+nCol],
173fa173a76Sdrh            TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
174fa173a76Sdrh         sqlite_freemem(z);
17575897234Sdrh       }
176*5080aaa7Sdrh     }
1776a535340Sdrh     cbData->once = 0;
17875897234Sdrh   }
1796a535340Sdrh   if( azCol!=0 ){
1806a535340Sdrh     if( cbData->zArray[0] ){
18175897234Sdrh       for(i=0; i<nCol; i++){
182c61053b7Sdrh         char *z = azCol[i];
183c61053b7Sdrh         if( z==0 ) z = "";
184c61053b7Sdrh         Tcl_SetVar2(cbData->interp, cbData->zArray, azN[i], z, 0);
18575897234Sdrh       }
18675897234Sdrh     }else{
18775897234Sdrh       for(i=0; i<nCol; i++){
188c61053b7Sdrh         char *z = azCol[i];
189c61053b7Sdrh         if( z==0 ) z = "";
190c61053b7Sdrh         Tcl_SetVar(cbData->interp, azN[i], z, 0);
19175897234Sdrh       }
19275897234Sdrh     }
1936a535340Sdrh   }
1946d31316cSdrh   rc = Tcl_EvalObj(cbData->interp, cbData->pCode);
195960e8c63Sdrh   if( rc==TCL_CONTINUE ) rc = TCL_OK;
196960e8c63Sdrh   cbData->tcl_rc = rc;
197960e8c63Sdrh   return rc!=TCL_OK;
19875897234Sdrh }
1996d4abfbeSdrh #endif
20075897234Sdrh 
20175897234Sdrh /*
2026d31316cSdrh ** This is an alternative callback for database queries.  Instead
2036d31316cSdrh ** of invoking a TCL script to handle the result, this callback just
2046d31316cSdrh ** appends each column of the result to a list.  After the query
2056d31316cSdrh ** is complete, the list is returned.
2066d31316cSdrh */
2076d31316cSdrh static int DbEvalCallback2(
2086d31316cSdrh   void *clientData,      /* An instance of CallbackData */
2096d31316cSdrh   int nCol,              /* Number of columns in the result */
2106d31316cSdrh   char ** azCol,         /* Data for each column */
2116d31316cSdrh   char ** azN            /* Name for each column */
2126d31316cSdrh ){
2136d31316cSdrh   Tcl_Obj *pList = (Tcl_Obj*)clientData;
2146d31316cSdrh   int i;
2156a535340Sdrh   if( azCol==0 ) return 0;
2166d31316cSdrh   for(i=0; i<nCol; i++){
2176d31316cSdrh     Tcl_Obj *pElem;
2186d31316cSdrh     if( azCol[i] && *azCol[i] ){
219297ecf14Sdrh #ifdef UTF_TRANSLATION_NEEDED
220297ecf14Sdrh       Tcl_DString dCol;
221297ecf14Sdrh       Tcl_DStringInit(&dCol);
222297ecf14Sdrh       Tcl_ExternalToUtfDString(NULL, azCol[i], -1, &dCol);
223297ecf14Sdrh       pElem = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1);
224297ecf14Sdrh       Tcl_DStringFree(&dCol);
225297ecf14Sdrh #else
2266d31316cSdrh       pElem = Tcl_NewStringObj(azCol[i], -1);
227297ecf14Sdrh #endif
2286d31316cSdrh     }else{
2296d31316cSdrh       pElem = Tcl_NewObj();
2306d31316cSdrh     }
2316d31316cSdrh     Tcl_ListObjAppendElement(0, pList, pElem);
2326d31316cSdrh   }
2336d31316cSdrh   return 0;
2346d31316cSdrh }
2356d31316cSdrh 
2366d31316cSdrh /*
23775897234Sdrh ** Called when the command is deleted.
23875897234Sdrh */
23975897234Sdrh static void DbDeleteCmd(void *db){
240bec3f402Sdrh   SqliteDb *pDb = (SqliteDb*)db;
241bec3f402Sdrh   sqlite_close(pDb->db);
242bec3f402Sdrh   if( pDb->zBusy ){
243bec3f402Sdrh     Tcl_Free(pDb->zBusy);
244bec3f402Sdrh   }
245bec3f402Sdrh   Tcl_Free((char*)pDb);
246bec3f402Sdrh }
247bec3f402Sdrh 
248bec3f402Sdrh /*
249bec3f402Sdrh ** This routine is called when a database file is locked while trying
250bec3f402Sdrh ** to execute SQL.
251bec3f402Sdrh */
252bec3f402Sdrh static int DbBusyHandler(void *cd, const char *zTable, int nTries){
253bec3f402Sdrh   SqliteDb *pDb = (SqliteDb*)cd;
254bec3f402Sdrh   int rc;
255bec3f402Sdrh   char zVal[30];
256bec3f402Sdrh   char *zCmd;
257bec3f402Sdrh   Tcl_DString cmd;
258bec3f402Sdrh 
259bec3f402Sdrh   Tcl_DStringInit(&cmd);
260bec3f402Sdrh   Tcl_DStringAppend(&cmd, pDb->zBusy, -1);
261bec3f402Sdrh   Tcl_DStringAppendElement(&cmd, zTable);
262bec3f402Sdrh   sprintf(zVal, " %d", nTries);
263bec3f402Sdrh   Tcl_DStringAppend(&cmd, zVal, -1);
264bec3f402Sdrh   zCmd = Tcl_DStringValue(&cmd);
265bec3f402Sdrh   rc = Tcl_Eval(pDb->interp, zCmd);
266bec3f402Sdrh   Tcl_DStringFree(&cmd);
267bec3f402Sdrh   if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){
268bec3f402Sdrh     return 0;
269bec3f402Sdrh   }
270bec3f402Sdrh   return 1;
27175897234Sdrh }
27275897234Sdrh 
27375897234Sdrh /*
27475897234Sdrh ** The "sqlite" command below creates a new Tcl command for each
27575897234Sdrh ** connection it opens to an SQLite database.  This routine is invoked
27675897234Sdrh ** whenever one of those connection-specific commands is executed
27775897234Sdrh ** in Tcl.  For example, if you run Tcl code like this:
27875897234Sdrh **
27975897234Sdrh **       sqlite db1  "my_database"
28075897234Sdrh **       db1 close
28175897234Sdrh **
28275897234Sdrh ** The first command opens a connection to the "my_database" database
28375897234Sdrh ** and calls that connection "db1".  The second command causes this
28475897234Sdrh ** subroutine to be invoked.
28575897234Sdrh */
2866d31316cSdrh static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
287bec3f402Sdrh   SqliteDb *pDb = (SqliteDb*)cd;
2886d31316cSdrh   int choice;
2890de8c112Sdrh   static const char *DB_strs[] = {
290411995dcSdrh     "busy",               "changes",           "close",
291411995dcSdrh     "complete",           "eval",              "last_insert_rowid",
292411995dcSdrh     "open_aux_file",      "timeout",           0
2936d31316cSdrh   };
294411995dcSdrh   enum DB_enum {
295411995dcSdrh     DB_BUSY,              DB_CHANGES,          DB_CLOSE,
296411995dcSdrh     DB_COMPLETE,          DB_EVAL,             DB_LAST_INSERT_ROWID,
297411995dcSdrh     DB_OPEN_AUX_FILE,     DB_TIMEOUT,
2986d31316cSdrh   };
2996d31316cSdrh 
3006d31316cSdrh   if( objc<2 ){
3016d31316cSdrh     Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
30275897234Sdrh     return TCL_ERROR;
30375897234Sdrh   }
304411995dcSdrh   if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){
3056d31316cSdrh     return TCL_ERROR;
3066d31316cSdrh   }
3076d31316cSdrh 
308411995dcSdrh   switch( (enum DB_enum)choice ){
30975897234Sdrh 
310bec3f402Sdrh   /*    $db busy ?CALLBACK?
311bec3f402Sdrh   **
312bec3f402Sdrh   ** Invoke the given callback if an SQL statement attempts to open
313bec3f402Sdrh   ** a locked database file.
314bec3f402Sdrh   */
3156d31316cSdrh   case DB_BUSY: {
3166d31316cSdrh     if( objc>3 ){
3176d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "CALLBACK");
318bec3f402Sdrh       return TCL_ERROR;
3196d31316cSdrh     }else if( objc==2 ){
320bec3f402Sdrh       if( pDb->zBusy ){
321bec3f402Sdrh         Tcl_AppendResult(interp, pDb->zBusy, 0);
322bec3f402Sdrh       }
323bec3f402Sdrh     }else{
3246d31316cSdrh       char *zBusy;
3256d31316cSdrh       int len;
326bec3f402Sdrh       if( pDb->zBusy ){
327bec3f402Sdrh         Tcl_Free(pDb->zBusy);
3286d31316cSdrh       }
3296d31316cSdrh       zBusy = Tcl_GetStringFromObj(objv[2], &len);
3306d31316cSdrh       if( zBusy && len>0 ){
3316d31316cSdrh         pDb->zBusy = Tcl_Alloc( len + 1 );
3326d31316cSdrh         strcpy(pDb->zBusy, zBusy);
3336d31316cSdrh       }else{
334bec3f402Sdrh         pDb->zBusy = 0;
335bec3f402Sdrh       }
336bec3f402Sdrh       if( pDb->zBusy ){
337bec3f402Sdrh         pDb->interp = interp;
338bec3f402Sdrh         sqlite_busy_handler(pDb->db, DbBusyHandler, pDb);
3396d31316cSdrh       }else{
3406d31316cSdrh         sqlite_busy_handler(pDb->db, 0, 0);
341bec3f402Sdrh       }
342bec3f402Sdrh     }
3436d31316cSdrh     break;
3446d31316cSdrh   }
345bec3f402Sdrh 
346c8d30ac1Sdrh   /*
347c8d30ac1Sdrh   **     $db changes
348c8d30ac1Sdrh   **
349c8d30ac1Sdrh   ** Return the number of rows that were modified, inserted, or deleted by
350c8d30ac1Sdrh   ** the most recent "eval".
351c8d30ac1Sdrh   */
352c8d30ac1Sdrh   case DB_CHANGES: {
353c8d30ac1Sdrh     Tcl_Obj *pResult;
354c8d30ac1Sdrh     int nChange;
355c8d30ac1Sdrh     if( objc!=2 ){
356c8d30ac1Sdrh       Tcl_WrongNumArgs(interp, 2, objv, "");
357c8d30ac1Sdrh       return TCL_ERROR;
358c8d30ac1Sdrh     }
359c8d30ac1Sdrh     nChange = sqlite_changes(pDb->db);
360c8d30ac1Sdrh     pResult = Tcl_GetObjResult(interp);
361c8d30ac1Sdrh     Tcl_SetIntObj(pResult, nChange);
362c8d30ac1Sdrh     break;
363c8d30ac1Sdrh   }
364c8d30ac1Sdrh 
36575897234Sdrh   /*    $db close
36675897234Sdrh   **
36775897234Sdrh   ** Shutdown the database
36875897234Sdrh   */
3696d31316cSdrh   case DB_CLOSE: {
3706d31316cSdrh     Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0));
3716d31316cSdrh     break;
3726d31316cSdrh   }
37375897234Sdrh 
37475897234Sdrh   /*    $db complete SQL
37575897234Sdrh   **
37675897234Sdrh   ** Return TRUE if SQL is a complete SQL statement.  Return FALSE if
37775897234Sdrh   ** additional lines of input are needed.  This is similar to the
37875897234Sdrh   ** built-in "info complete" command of Tcl.
37975897234Sdrh   */
3806d31316cSdrh   case DB_COMPLETE: {
3816d31316cSdrh     Tcl_Obj *pResult;
3826d31316cSdrh     int isComplete;
3836d31316cSdrh     if( objc!=3 ){
3846d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "SQL");
38575897234Sdrh       return TCL_ERROR;
38675897234Sdrh     }
3876d31316cSdrh     isComplete = sqlite_complete( Tcl_GetStringFromObj(objv[2], 0) );
3886d31316cSdrh     pResult = Tcl_GetObjResult(interp);
3896d31316cSdrh     Tcl_SetBooleanObj(pResult, isComplete);
3906d31316cSdrh     break;
3916d31316cSdrh   }
39275897234Sdrh 
39375897234Sdrh   /*
39475897234Sdrh   **    $db eval $sql ?array {  ...code... }?
39575897234Sdrh   **
39675897234Sdrh   ** The SQL statement in $sql is evaluated.  For each row, the values are
397bec3f402Sdrh   ** placed in elements of the array named "array" and ...code... is executed.
39875897234Sdrh   ** If "array" and "code" are omitted, then no callback is every invoked.
39975897234Sdrh   ** If "array" is an empty string, then the values are placed in variables
40075897234Sdrh   ** that have the same name as the fields extracted by the query.
40175897234Sdrh   */
4026d31316cSdrh   case DB_EVAL: {
40375897234Sdrh     CallbackData cbData;
40475897234Sdrh     char *zErrMsg;
4056d31316cSdrh     char *zSql;
40675897234Sdrh     int rc;
407297ecf14Sdrh #ifdef UTF_TRANSLATION_NEEDED
408297ecf14Sdrh     Tcl_DString dSql;
4096d4abfbeSdrh     int i;
410297ecf14Sdrh #endif
41175897234Sdrh 
4126d31316cSdrh     if( objc!=5 && objc!=3 ){
4136d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME CODE?");
41475897234Sdrh       return TCL_ERROR;
41575897234Sdrh     }
416bec3f402Sdrh     pDb->interp = interp;
4176d31316cSdrh     zSql = Tcl_GetStringFromObj(objv[2], 0);
418297ecf14Sdrh #ifdef UTF_TRANSLATION_NEEDED
419297ecf14Sdrh     Tcl_DStringInit(&dSql);
420297ecf14Sdrh     Tcl_UtfToExternalDString(NULL, zSql, -1, &dSql);
421297ecf14Sdrh     zSql = Tcl_DStringValue(&dSql);
422297ecf14Sdrh #endif
4236d31316cSdrh     Tcl_IncrRefCount(objv[2]);
4246d31316cSdrh     if( objc==5 ){
42575897234Sdrh       cbData.interp = interp;
426dcc581ccSdrh       cbData.once = 1;
4276d31316cSdrh       cbData.zArray = Tcl_GetStringFromObj(objv[3], 0);
4286d31316cSdrh       cbData.pCode = objv[4];
429960e8c63Sdrh       cbData.tcl_rc = TCL_OK;
4306d4abfbeSdrh       cbData.nColName = 0;
4316d4abfbeSdrh       cbData.azColName = 0;
43275897234Sdrh       zErrMsg = 0;
4336d31316cSdrh       Tcl_IncrRefCount(objv[3]);
4346d31316cSdrh       Tcl_IncrRefCount(objv[4]);
4356d31316cSdrh       rc = sqlite_exec(pDb->db, zSql, DbEvalCallback, &cbData, &zErrMsg);
4366d31316cSdrh       Tcl_DecrRefCount(objv[4]);
4376d31316cSdrh       Tcl_DecrRefCount(objv[3]);
438960e8c63Sdrh       if( cbData.tcl_rc==TCL_BREAK ){ cbData.tcl_rc = TCL_OK; }
43975897234Sdrh     }else{
4406d31316cSdrh       Tcl_Obj *pList = Tcl_NewObj();
441960e8c63Sdrh       cbData.tcl_rc = TCL_OK;
4426d31316cSdrh       rc = sqlite_exec(pDb->db, zSql, DbEvalCallback2, pList, &zErrMsg);
4436d31316cSdrh       Tcl_SetObjResult(interp, pList);
44475897234Sdrh     }
44575897234Sdrh     if( zErrMsg ){
44675897234Sdrh       Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
44775897234Sdrh       free(zErrMsg);
448960e8c63Sdrh       rc = TCL_ERROR;
4496d4abfbeSdrh     }else if( rc!=SQLITE_OK && rc!=SQLITE_ABORT ){
4506d4abfbeSdrh       Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
4516d4abfbeSdrh       rc = TCL_ERROR;
452960e8c63Sdrh     }else{
453960e8c63Sdrh       rc = cbData.tcl_rc;
45475897234Sdrh     }
4556d31316cSdrh     Tcl_DecrRefCount(objv[2]);
456297ecf14Sdrh #ifdef UTF_TRANSLATION_NEEDED
457297ecf14Sdrh     Tcl_DStringFree(&dSql);
4586d4abfbeSdrh     if( objc==5 && cbData.azColName ){
4596d4abfbeSdrh       for(i=0; i<cbData.nColName; i++){
4606d4abfbeSdrh         if( cbData.azColName[i] ) free(cbData.azColName[i]);
4616d4abfbeSdrh       }
4626d4abfbeSdrh       free(cbData.azColName);
463ce927065Sdrh       cbData.azColName = 0;
4646d4abfbeSdrh     }
465297ecf14Sdrh #endif
46675897234Sdrh     return rc;
4676d31316cSdrh   }
468bec3f402Sdrh 
469bec3f402Sdrh   /*
470af9ff33aSdrh   **     $db last_insert_rowid
471af9ff33aSdrh   **
472af9ff33aSdrh   ** Return an integer which is the ROWID for the most recent insert.
473af9ff33aSdrh   */
474af9ff33aSdrh   case DB_LAST_INSERT_ROWID: {
475af9ff33aSdrh     Tcl_Obj *pResult;
476af9ff33aSdrh     int rowid;
477af9ff33aSdrh     if( objc!=2 ){
478af9ff33aSdrh       Tcl_WrongNumArgs(interp, 2, objv, "");
479af9ff33aSdrh       return TCL_ERROR;
480af9ff33aSdrh     }
481af9ff33aSdrh     rowid = sqlite_last_insert_rowid(pDb->db);
482af9ff33aSdrh     pResult = Tcl_GetObjResult(interp);
483af9ff33aSdrh     Tcl_SetIntObj(pResult, rowid);
484af9ff33aSdrh     break;
485af9ff33aSdrh   }
486af9ff33aSdrh 
487af9ff33aSdrh   /*
488411995dcSdrh   **     $db open_aux_file  FILENAME
489411995dcSdrh   **
490411995dcSdrh   ** Begin using FILENAME as the database file used to store temporary
491411995dcSdrh   ** tables.
492411995dcSdrh   */
493411995dcSdrh   case DB_OPEN_AUX_FILE: {
494411995dcSdrh     const char *zFilename;
495411995dcSdrh     char *zErrMsg = 0;
496411995dcSdrh     int rc;
497411995dcSdrh     if( objc!=3 ){
498411995dcSdrh       Tcl_WrongNumArgs(interp, 2, objv, "FILENAME");
499411995dcSdrh       return TCL_ERROR;
500411995dcSdrh     }
501411995dcSdrh     zFilename = Tcl_GetStringFromObj(objv[2], 0);
502411995dcSdrh     rc = sqlite_open_aux_file(pDb->db, zFilename, &zErrMsg);
503411995dcSdrh     if( rc!=0 ){
504411995dcSdrh       if( zErrMsg ){
505411995dcSdrh         Tcl_AppendResult(interp, zErrMsg, 0);
506411995dcSdrh         free(zErrMsg);
507411995dcSdrh       }else{
508411995dcSdrh         Tcl_AppendResult(interp, sqlite_error_string(rc), 0);
509411995dcSdrh       }
510411995dcSdrh       return TCL_ERROR;
511411995dcSdrh     }
512411995dcSdrh     break;
513411995dcSdrh   }
514411995dcSdrh 
515411995dcSdrh   /*
516bec3f402Sdrh   **     $db timeout MILLESECONDS
517bec3f402Sdrh   **
518bec3f402Sdrh   ** Delay for the number of milliseconds specified when a file is locked.
519bec3f402Sdrh   */
5206d31316cSdrh   case DB_TIMEOUT: {
521bec3f402Sdrh     int ms;
5226d31316cSdrh     if( objc!=3 ){
5236d31316cSdrh       Tcl_WrongNumArgs(interp, 2, objv, "MILLISECONDS");
524bec3f402Sdrh       return TCL_ERROR;
52575897234Sdrh     }
5266d31316cSdrh     if( Tcl_GetIntFromObj(interp, objv[2], &ms) ) return TCL_ERROR;
527bec3f402Sdrh     sqlite_busy_timeout(pDb->db, ms);
5286d31316cSdrh     break;
52975897234Sdrh   }
5306d31316cSdrh   } /* End of the SWITCH statement */
53175897234Sdrh   return TCL_OK;
53275897234Sdrh }
53375897234Sdrh 
53475897234Sdrh /*
53575897234Sdrh **   sqlite DBNAME FILENAME ?MODE?
53675897234Sdrh **
53775897234Sdrh ** This is the main Tcl command.  When the "sqlite" Tcl command is
53875897234Sdrh ** invoked, this routine runs to process that command.
53975897234Sdrh **
54075897234Sdrh ** The first argument, DBNAME, is an arbitrary name for a new
54175897234Sdrh ** database connection.  This command creates a new command named
54275897234Sdrh ** DBNAME that is used to control that connection.  The database
54375897234Sdrh ** connection is deleted when the DBNAME command is deleted.
54475897234Sdrh **
54575897234Sdrh ** The second argument is the name of the directory that contains
54675897234Sdrh ** the sqlite database that is to be accessed.
547fbc3eab8Sdrh **
548fbc3eab8Sdrh ** For testing purposes, we also support the following:
549fbc3eab8Sdrh **
550fbc3eab8Sdrh **  sqlite -encoding
551fbc3eab8Sdrh **
552fbc3eab8Sdrh **       Return the encoding used by LIKE and GLOB operators.  Choices
553fbc3eab8Sdrh **       are UTF-8 and iso8859.
554fbc3eab8Sdrh **
555fbc3eab8Sdrh **  sqlite -tcl-uses-utf
556fbc3eab8Sdrh **
557fbc3eab8Sdrh **       Return "1" if compiled with a Tcl uses UTF-8.  Return "0" if
558fbc3eab8Sdrh **       not.  Used by tests to make sure the library was compiled
559fbc3eab8Sdrh **       correctly.
56075897234Sdrh */
56175897234Sdrh static int DbMain(void *cd, Tcl_Interp *interp, int argc, char **argv){
56275897234Sdrh   int mode;
563bec3f402Sdrh   SqliteDb *p;
56475897234Sdrh   char *zErrMsg;
56506b2718aSdrh   char zBuf[80];
566fbc3eab8Sdrh   if( argc==2 ){
567fbc3eab8Sdrh     if( strcmp(argv[1],"-encoding")==0 ){
568fbc3eab8Sdrh       Tcl_AppendResult(interp,sqlite_encoding,0);
569fbc3eab8Sdrh       return TCL_OK;
570fbc3eab8Sdrh     }
571fbc3eab8Sdrh     if( strcmp(argv[1],"-tcl-uses-utf")==0 ){
572fbc3eab8Sdrh #ifdef TCL_UTF_MAX
573fbc3eab8Sdrh       Tcl_AppendResult(interp,"1",0);
574fbc3eab8Sdrh #else
575fbc3eab8Sdrh       Tcl_AppendResult(interp,"0",0);
576fbc3eab8Sdrh #endif
577fbc3eab8Sdrh       return TCL_OK;
578fbc3eab8Sdrh     }
579fbc3eab8Sdrh   }
58075897234Sdrh   if( argc!=3 && argc!=4 ){
58175897234Sdrh     Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
58275897234Sdrh        " HANDLE FILENAME ?MODE?\"", 0);
58375897234Sdrh     return TCL_ERROR;
58475897234Sdrh   }
58575897234Sdrh   if( argc==3 ){
58658b9576bSdrh     mode = 0666;
58775897234Sdrh   }else if( Tcl_GetInt(interp, argv[3], &mode)!=TCL_OK ){
58875897234Sdrh     return TCL_ERROR;
58975897234Sdrh   }
59075897234Sdrh   zErrMsg = 0;
5914cdc9e84Sdrh   p = (SqliteDb*)Tcl_Alloc( sizeof(*p) );
59275897234Sdrh   if( p==0 ){
593bec3f402Sdrh     Tcl_SetResult(interp, "malloc failed", TCL_STATIC);
594bec3f402Sdrh     return TCL_ERROR;
595bec3f402Sdrh   }
596bec3f402Sdrh   memset(p, 0, sizeof(*p));
597bec3f402Sdrh   p->db = sqlite_open(argv[2], mode, &zErrMsg);
598bec3f402Sdrh   if( p->db==0 ){
59975897234Sdrh     Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
600bec3f402Sdrh     Tcl_Free((char*)p);
60175897234Sdrh     free(zErrMsg);
60275897234Sdrh     return TCL_ERROR;
60375897234Sdrh   }
6046d31316cSdrh   Tcl_CreateObjCommand(interp, argv[1], DbObjCmd, (char*)p, DbDeleteCmd);
605c22bd47dSdrh 
60606b2718aSdrh   /* The return value is the value of the sqlite* pointer
60706b2718aSdrh   */
60806b2718aSdrh   sprintf(zBuf, "%p", p->db);
6095e5377fbSdrh   if( strncmp(zBuf,"0x",2) ){
6105e5377fbSdrh     sprintf(zBuf, "0x%p", p->db);
6115e5377fbSdrh   }
61206b2718aSdrh   Tcl_AppendResult(interp, zBuf, 0);
61306b2718aSdrh 
614c22bd47dSdrh   /* If compiled with SQLITE_TEST turned on, then register the "md5sum"
61506b2718aSdrh   ** SQL function.
616c22bd47dSdrh   */
61728b4e489Sdrh #ifdef SQLITE_TEST
61828b4e489Sdrh   {
61928b4e489Sdrh     extern void Md5_Register(sqlite*);
62028b4e489Sdrh     Md5_Register(p->db);
62128b4e489Sdrh    }
62228b4e489Sdrh #endif
62375897234Sdrh   return TCL_OK;
62475897234Sdrh }
62575897234Sdrh 
62675897234Sdrh /*
62790ca9753Sdrh ** Provide a dummy Tcl_InitStubs if we are using this as a static
62890ca9753Sdrh ** library.
62990ca9753Sdrh */
63090ca9753Sdrh #ifndef USE_TCL_STUBS
63190ca9753Sdrh # undef  Tcl_InitStubs
63290ca9753Sdrh # define Tcl_InitStubs(a,b,c)
63390ca9753Sdrh #endif
63490ca9753Sdrh 
63590ca9753Sdrh /*
63675897234Sdrh ** Initialize this module.
63775897234Sdrh **
63875897234Sdrh ** This Tcl module contains only a single new Tcl command named "sqlite".
63975897234Sdrh ** (Hence there is no namespace.  There is no point in using a namespace
64075897234Sdrh ** if the extension only supplies one new name!)  The "sqlite" command is
64175897234Sdrh ** used to open a new SQLite database.  See the DbMain() routine above
64275897234Sdrh ** for additional information.
64375897234Sdrh */
64475897234Sdrh int Sqlite_Init(Tcl_Interp *interp){
64590ca9753Sdrh   Tcl_InitStubs(interp, "8.0", 0);
64690ca9753Sdrh   Tcl_CreateCommand(interp, "sqlite", DbMain, 0, 0);
6476d4abfbeSdrh   Tcl_PkgProvide(interp, "sqlite", "2.0");
64890ca9753Sdrh   return TCL_OK;
64990ca9753Sdrh }
65090ca9753Sdrh int Tclsqlite_Init(Tcl_Interp *interp){
65190ca9753Sdrh   Tcl_InitStubs(interp, "8.0", 0);
65275897234Sdrh   Tcl_CreateCommand(interp, "sqlite", DbMain, 0, 0);
6536d4abfbeSdrh   Tcl_PkgProvide(interp, "sqlite", "2.0");
65475897234Sdrh   return TCL_OK;
65575897234Sdrh }
65675897234Sdrh int Sqlite_SafeInit(Tcl_Interp *interp){
65775897234Sdrh   return TCL_OK;
65875897234Sdrh }
65990ca9753Sdrh int Tclsqlite_SafeInit(Tcl_Interp *interp){
66090ca9753Sdrh   return TCL_OK;
66190ca9753Sdrh }
66275897234Sdrh 
6633cebbde3Sdrh #if 0
66475897234Sdrh /*
66575897234Sdrh ** If compiled using mktclapp, this routine runs to initialize
66675897234Sdrh ** everything.
66775897234Sdrh */
66875897234Sdrh int Et_AppInit(Tcl_Interp *interp){
66975897234Sdrh   return Sqlite_Init(interp);
67075897234Sdrh }
6713cebbde3Sdrh #endif
672348784efSdrh 
673348784efSdrh /*
674348784efSdrh ** If the macro TCLSH is defined and is one, then put in code for the
675348784efSdrh ** "main" routine that will initialize Tcl.
676348784efSdrh */
677348784efSdrh #if defined(TCLSH) && TCLSH==1
678348784efSdrh static char zMainloop[] =
679348784efSdrh   "set line {}\n"
680348784efSdrh   "while {![eof stdin]} {\n"
681348784efSdrh     "if {$line!=\"\"} {\n"
682348784efSdrh       "puts -nonewline \"> \"\n"
683348784efSdrh     "} else {\n"
684348784efSdrh       "puts -nonewline \"% \"\n"
685348784efSdrh     "}\n"
686348784efSdrh     "flush stdout\n"
687348784efSdrh     "append line [gets stdin]\n"
688348784efSdrh     "if {[info complete $line]} {\n"
689348784efSdrh       "if {[catch {uplevel #0 $line} result]} {\n"
690348784efSdrh         "puts stderr \"Error: $result\"\n"
691348784efSdrh       "} elseif {$result!=\"\"} {\n"
692348784efSdrh         "puts $result\n"
693348784efSdrh       "}\n"
694348784efSdrh       "set line {}\n"
695348784efSdrh     "} else {\n"
696348784efSdrh       "append line \\n\n"
697348784efSdrh     "}\n"
698348784efSdrh   "}\n"
699348784efSdrh ;
700348784efSdrh 
701348784efSdrh #define TCLSH_MAIN main   /* Needed to fake out mktclapp */
702348784efSdrh int TCLSH_MAIN(int argc, char **argv){
703348784efSdrh   Tcl_Interp *interp;
704297ecf14Sdrh   Tcl_FindExecutable(argv[0]);
705348784efSdrh   interp = Tcl_CreateInterp();
706348784efSdrh   Sqlite_Init(interp);
707d9b0257aSdrh #ifdef SQLITE_TEST
708d1bf3512Sdrh   {
709d1bf3512Sdrh     extern int Sqlitetest1_Init(Tcl_Interp*);
7105c4d9703Sdrh     extern int Sqlitetest2_Init(Tcl_Interp*);
7115c4d9703Sdrh     extern int Sqlitetest3_Init(Tcl_Interp*);
712efc251daSdrh     extern int Md5_Init(Tcl_Interp*);
713d1bf3512Sdrh     Sqlitetest1_Init(interp);
7145c4d9703Sdrh     Sqlitetest2_Init(interp);
7155c4d9703Sdrh     Sqlitetest3_Init(interp);
716efc251daSdrh     Md5_Init(interp);
717d1bf3512Sdrh   }
718d1bf3512Sdrh #endif
719348784efSdrh   if( argc>=2 ){
720348784efSdrh     int i;
721348784efSdrh     Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY);
722348784efSdrh     Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
723348784efSdrh     for(i=2; i<argc; i++){
724348784efSdrh       Tcl_SetVar(interp, "argv", argv[i],
725348784efSdrh           TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE);
726348784efSdrh     }
727348784efSdrh     if( Tcl_EvalFile(interp, argv[1])!=TCL_OK ){
7280de8c112Sdrh       const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
729c61053b7Sdrh       if( zInfo==0 ) zInfo = interp->result;
730c61053b7Sdrh       fprintf(stderr,"%s: %s\n", *argv, zInfo);
731348784efSdrh       return 1;
732348784efSdrh     }
733348784efSdrh   }else{
734348784efSdrh     Tcl_GlobalEval(interp, zMainloop);
735348784efSdrh   }
736348784efSdrh   return 0;
737348784efSdrh }
738348784efSdrh #endif /* TCLSH */
7396d31316cSdrh 
7406d31316cSdrh #endif /* !defined(NO_TCL) */
741