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*55c45f2eSdanielk1977 ** $Id: tclsqlite.c,v 1.121 2005/04/03 23:54:44 danielk1977 Exp $ 1575897234Sdrh */ 166d31316cSdrh #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ 176d31316cSdrh 1806b2718aSdrh #include "sqliteInt.h" 19895d7472Sdrh #include "hash.h" 2017a68934Sdrh #include "tcl.h" 2175897234Sdrh #include <stdlib.h> 2275897234Sdrh #include <string.h> 23ce927065Sdrh #include <assert.h> 2475897234Sdrh 25a21c6b6fSdanielk1977 #define NUM_PREPARED_STMTS 10 26fb7e7651Sdrh #define MAX_PREPARED_STMTS 100 27fb7e7651Sdrh 2875897234Sdrh /* 2998808babSdrh ** If TCL uses UTF-8 and SQLite is configured to use iso8859, then we 3098808babSdrh ** have to do a translation when going between the two. Set the 3198808babSdrh ** UTF_TRANSLATION_NEEDED macro to indicate that we need to do 3298808babSdrh ** this translation. 3398808babSdrh */ 3498808babSdrh #if defined(TCL_UTF_MAX) && !defined(SQLITE_UTF8) 3598808babSdrh # define UTF_TRANSLATION_NEEDED 1 3698808babSdrh #endif 3798808babSdrh 3898808babSdrh /* 39cabb0819Sdrh ** New SQL functions can be created as TCL scripts. Each such function 40cabb0819Sdrh ** is described by an instance of the following structure. 41cabb0819Sdrh */ 42cabb0819Sdrh typedef struct SqlFunc SqlFunc; 43cabb0819Sdrh struct SqlFunc { 44cabb0819Sdrh Tcl_Interp *interp; /* The TCL interpret to execute the function */ 45cabb0819Sdrh char *zScript; /* The script to be run */ 46cabb0819Sdrh SqlFunc *pNext; /* Next function on the list of them all */ 47cabb0819Sdrh }; 48cabb0819Sdrh 49cabb0819Sdrh /* 500202b29eSdanielk1977 ** New collation sequences function can be created as TCL scripts. Each such 510202b29eSdanielk1977 ** function is described by an instance of the following structure. 520202b29eSdanielk1977 */ 530202b29eSdanielk1977 typedef struct SqlCollate SqlCollate; 540202b29eSdanielk1977 struct SqlCollate { 550202b29eSdanielk1977 Tcl_Interp *interp; /* The TCL interpret to execute the function */ 560202b29eSdanielk1977 char *zScript; /* The script to be run */ 570202b29eSdanielk1977 SqlCollate *pNext; /* Next function on the list of them all */ 580202b29eSdanielk1977 }; 590202b29eSdanielk1977 600202b29eSdanielk1977 /* 61fb7e7651Sdrh ** Prepared statements are cached for faster execution. Each prepared 62fb7e7651Sdrh ** statement is described by an instance of the following structure. 63fb7e7651Sdrh */ 64fb7e7651Sdrh typedef struct SqlPreparedStmt SqlPreparedStmt; 65fb7e7651Sdrh struct SqlPreparedStmt { 66fb7e7651Sdrh SqlPreparedStmt *pNext; /* Next in linked list */ 67fb7e7651Sdrh SqlPreparedStmt *pPrev; /* Previous on the list */ 68fb7e7651Sdrh sqlite3_stmt *pStmt; /* The prepared statement */ 69fb7e7651Sdrh int nSql; /* chars in zSql[] */ 70fb7e7651Sdrh char zSql[1]; /* Text of the SQL statement */ 71fb7e7651Sdrh }; 72fb7e7651Sdrh 73fb7e7651Sdrh /* 74bec3f402Sdrh ** There is one instance of this structure for each SQLite database 75bec3f402Sdrh ** that has been opened by the SQLite TCL interface. 76bec3f402Sdrh */ 77bec3f402Sdrh typedef struct SqliteDb SqliteDb; 78bec3f402Sdrh struct SqliteDb { 79895d7472Sdrh sqlite3 *db; /* The "real" database structure */ 80bec3f402Sdrh Tcl_Interp *interp; /* The interpreter used for this database */ 816d31316cSdrh char *zBusy; /* The busy callback routine */ 82aa940eacSdrh char *zCommit; /* The commit hook callback routine */ 83b5a20d3cSdrh char *zTrace; /* The trace callback routine */ 84348bb5d6Sdanielk1977 char *zProgress; /* The progress callback routine */ 85e22a334bSdrh char *zAuth; /* The authorization callback routine */ 86*55c45f2eSdanielk1977 char *zNull; /* Text to substitute for an SQL NULL value */ 87cabb0819Sdrh SqlFunc *pFunc; /* List of SQL functions */ 880202b29eSdanielk1977 SqlCollate *pCollate; /* List of SQL collation functions */ 896f8a503dSdanielk1977 int rc; /* Return code of most recent sqlite3_exec() */ 907cedc8d4Sdanielk1977 Tcl_Obj *pCollateNeeded; /* Collation needed script */ 91fb7e7651Sdrh SqlPreparedStmt *stmtList; /* List of prepared statements*/ 92fb7e7651Sdrh SqlPreparedStmt *stmtLast; /* Last statement in the list */ 93fb7e7651Sdrh int maxStmt; /* The next maximum number of stmtList */ 94fb7e7651Sdrh int nStmt; /* Number of statements in stmtList */ 9598808babSdrh }; 96297ecf14Sdrh 976d31316cSdrh /* 98fb7e7651Sdrh ** Finalize and free a list of prepared statements 99fb7e7651Sdrh */ 100fb7e7651Sdrh static void flushStmtCache( SqliteDb *pDb ){ 101fb7e7651Sdrh SqlPreparedStmt *pPreStmt; 102fb7e7651Sdrh 103fb7e7651Sdrh while( pDb->stmtList ){ 104fb7e7651Sdrh sqlite3_finalize( pDb->stmtList->pStmt ); 105fb7e7651Sdrh pPreStmt = pDb->stmtList; 106fb7e7651Sdrh pDb->stmtList = pDb->stmtList->pNext; 107fb7e7651Sdrh Tcl_Free( (char*)pPreStmt ); 108fb7e7651Sdrh } 109fb7e7651Sdrh pDb->nStmt = 0; 110fb7e7651Sdrh pDb->stmtLast = 0; 111fb7e7651Sdrh } 112fb7e7651Sdrh 113fb7e7651Sdrh /* 114895d7472Sdrh ** TCL calls this procedure when an sqlite3 database command is 115895d7472Sdrh ** deleted. 11675897234Sdrh */ 11775897234Sdrh static void DbDeleteCmd(void *db){ 118bec3f402Sdrh SqliteDb *pDb = (SqliteDb*)db; 119fb7e7651Sdrh flushStmtCache(pDb); 1206f8a503dSdanielk1977 sqlite3_close(pDb->db); 121cabb0819Sdrh while( pDb->pFunc ){ 122cabb0819Sdrh SqlFunc *pFunc = pDb->pFunc; 123cabb0819Sdrh pDb->pFunc = pFunc->pNext; 124cabb0819Sdrh Tcl_Free((char*)pFunc); 125cabb0819Sdrh } 1260202b29eSdanielk1977 while( pDb->pCollate ){ 1270202b29eSdanielk1977 SqlCollate *pCollate = pDb->pCollate; 1280202b29eSdanielk1977 pDb->pCollate = pCollate->pNext; 1290202b29eSdanielk1977 Tcl_Free((char*)pCollate); 1300202b29eSdanielk1977 } 131bec3f402Sdrh if( pDb->zBusy ){ 132bec3f402Sdrh Tcl_Free(pDb->zBusy); 133bec3f402Sdrh } 134b5a20d3cSdrh if( pDb->zTrace ){ 135b5a20d3cSdrh Tcl_Free(pDb->zTrace); 1360d1a643aSdrh } 137e22a334bSdrh if( pDb->zAuth ){ 138e22a334bSdrh Tcl_Free(pDb->zAuth); 139e22a334bSdrh } 140*55c45f2eSdanielk1977 if( pDb->zNull ){ 141*55c45f2eSdanielk1977 Tcl_Free(pDb->zNull); 142*55c45f2eSdanielk1977 } 143bec3f402Sdrh Tcl_Free((char*)pDb); 144bec3f402Sdrh } 145bec3f402Sdrh 146bec3f402Sdrh /* 147bec3f402Sdrh ** This routine is called when a database file is locked while trying 148bec3f402Sdrh ** to execute SQL. 149bec3f402Sdrh */ 1502a764eb0Sdanielk1977 static int DbBusyHandler(void *cd, int nTries){ 151bec3f402Sdrh SqliteDb *pDb = (SqliteDb*)cd; 152bec3f402Sdrh int rc; 153bec3f402Sdrh char zVal[30]; 154bec3f402Sdrh char *zCmd; 155bec3f402Sdrh Tcl_DString cmd; 156bec3f402Sdrh 157bec3f402Sdrh Tcl_DStringInit(&cmd); 158bec3f402Sdrh Tcl_DStringAppend(&cmd, pDb->zBusy, -1); 159bec3f402Sdrh sprintf(zVal, "%d", nTries); 1602a764eb0Sdanielk1977 Tcl_DStringAppendElement(&cmd, zVal); 161bec3f402Sdrh zCmd = Tcl_DStringValue(&cmd); 162bec3f402Sdrh rc = Tcl_Eval(pDb->interp, zCmd); 163bec3f402Sdrh Tcl_DStringFree(&cmd); 164bec3f402Sdrh if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ 165bec3f402Sdrh return 0; 166bec3f402Sdrh } 167bec3f402Sdrh return 1; 16875897234Sdrh } 16975897234Sdrh 17075897234Sdrh /* 171348bb5d6Sdanielk1977 ** This routine is invoked as the 'progress callback' for the database. 172348bb5d6Sdanielk1977 */ 173348bb5d6Sdanielk1977 static int DbProgressHandler(void *cd){ 174348bb5d6Sdanielk1977 SqliteDb *pDb = (SqliteDb*)cd; 175348bb5d6Sdanielk1977 int rc; 176348bb5d6Sdanielk1977 177348bb5d6Sdanielk1977 assert( pDb->zProgress ); 178348bb5d6Sdanielk1977 rc = Tcl_Eval(pDb->interp, pDb->zProgress); 179348bb5d6Sdanielk1977 if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ 180348bb5d6Sdanielk1977 return 1; 181348bb5d6Sdanielk1977 } 182348bb5d6Sdanielk1977 return 0; 183348bb5d6Sdanielk1977 } 184348bb5d6Sdanielk1977 185348bb5d6Sdanielk1977 /* 186b5a20d3cSdrh ** This routine is called by the SQLite trace handler whenever a new 187b5a20d3cSdrh ** block of SQL is executed. The TCL script in pDb->zTrace is executed. 1880d1a643aSdrh */ 189b5a20d3cSdrh static void DbTraceHandler(void *cd, const char *zSql){ 1900d1a643aSdrh SqliteDb *pDb = (SqliteDb*)cd; 191b5a20d3cSdrh Tcl_DString str; 1920d1a643aSdrh 193b5a20d3cSdrh Tcl_DStringInit(&str); 194b5a20d3cSdrh Tcl_DStringAppend(&str, pDb->zTrace, -1); 195b5a20d3cSdrh Tcl_DStringAppendElement(&str, zSql); 196b5a20d3cSdrh Tcl_Eval(pDb->interp, Tcl_DStringValue(&str)); 197b5a20d3cSdrh Tcl_DStringFree(&str); 198b5a20d3cSdrh Tcl_ResetResult(pDb->interp); 1990d1a643aSdrh } 2000d1a643aSdrh 2010d1a643aSdrh /* 202aa940eacSdrh ** This routine is called when a transaction is committed. The 203aa940eacSdrh ** TCL script in pDb->zCommit is executed. If it returns non-zero or 204aa940eacSdrh ** if it throws an exception, the transaction is rolled back instead 205aa940eacSdrh ** of being committed. 206aa940eacSdrh */ 207aa940eacSdrh static int DbCommitHandler(void *cd){ 208aa940eacSdrh SqliteDb *pDb = (SqliteDb*)cd; 209aa940eacSdrh int rc; 210aa940eacSdrh 211aa940eacSdrh rc = Tcl_Eval(pDb->interp, pDb->zCommit); 212aa940eacSdrh if( rc!=TCL_OK || atoi(Tcl_GetStringResult(pDb->interp)) ){ 213aa940eacSdrh return 1; 214aa940eacSdrh } 215aa940eacSdrh return 0; 216aa940eacSdrh } 217aa940eacSdrh 2187cedc8d4Sdanielk1977 static void tclCollateNeeded( 2197cedc8d4Sdanielk1977 void *pCtx, 2209bb575fdSdrh sqlite3 *db, 2217cedc8d4Sdanielk1977 int enc, 2227cedc8d4Sdanielk1977 const char *zName 2237cedc8d4Sdanielk1977 ){ 2247cedc8d4Sdanielk1977 SqliteDb *pDb = (SqliteDb *)pCtx; 2257cedc8d4Sdanielk1977 Tcl_Obj *pScript = Tcl_DuplicateObj(pDb->pCollateNeeded); 2267cedc8d4Sdanielk1977 Tcl_IncrRefCount(pScript); 2277cedc8d4Sdanielk1977 Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj(zName, -1)); 2287cedc8d4Sdanielk1977 Tcl_EvalObjEx(pDb->interp, pScript, 0); 2297cedc8d4Sdanielk1977 Tcl_DecrRefCount(pScript); 2307cedc8d4Sdanielk1977 } 2317cedc8d4Sdanielk1977 232aa940eacSdrh /* 2330202b29eSdanielk1977 ** This routine is called to evaluate an SQL collation function implemented 2340202b29eSdanielk1977 ** using TCL script. 2350202b29eSdanielk1977 */ 2360202b29eSdanielk1977 static int tclSqlCollate( 2370202b29eSdanielk1977 void *pCtx, 2380202b29eSdanielk1977 int nA, 2390202b29eSdanielk1977 const void *zA, 2400202b29eSdanielk1977 int nB, 2410202b29eSdanielk1977 const void *zB 2420202b29eSdanielk1977 ){ 2430202b29eSdanielk1977 SqlCollate *p = (SqlCollate *)pCtx; 2440202b29eSdanielk1977 Tcl_Obj *pCmd; 2450202b29eSdanielk1977 2460202b29eSdanielk1977 pCmd = Tcl_NewStringObj(p->zScript, -1); 2470202b29eSdanielk1977 Tcl_IncrRefCount(pCmd); 2480202b29eSdanielk1977 Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zA, nA)); 2490202b29eSdanielk1977 Tcl_ListObjAppendElement(p->interp, pCmd, Tcl_NewStringObj(zB, nB)); 2500202b29eSdanielk1977 Tcl_EvalObjEx(p->interp, pCmd, 0); 2510202b29eSdanielk1977 Tcl_DecrRefCount(pCmd); 2520202b29eSdanielk1977 return (atoi(Tcl_GetStringResult(p->interp))); 2530202b29eSdanielk1977 } 2540202b29eSdanielk1977 2550202b29eSdanielk1977 /* 256cabb0819Sdrh ** This routine is called to evaluate an SQL function implemented 257cabb0819Sdrh ** using TCL script. 258cabb0819Sdrh */ 2590ae8b831Sdanielk1977 static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){ 2606f8a503dSdanielk1977 SqlFunc *p = sqlite3_user_data(context); 261cabb0819Sdrh Tcl_DString cmd; 262cabb0819Sdrh int i; 263cabb0819Sdrh int rc; 264cabb0819Sdrh 265cabb0819Sdrh Tcl_DStringInit(&cmd); 266cabb0819Sdrh Tcl_DStringAppend(&cmd, p->zScript, -1); 267cabb0819Sdrh for(i=0; i<argc; i++){ 2689c054830Sdrh if( SQLITE_NULL==sqlite3_value_type(argv[i]) ){ 26951ad0ecdSdanielk1977 Tcl_DStringAppendElement(&cmd, ""); 27051ad0ecdSdanielk1977 }else{ 2714f26d6c4Sdrh Tcl_DStringAppendElement(&cmd, sqlite3_value_text(argv[i])); 27251ad0ecdSdanielk1977 } 273cabb0819Sdrh } 274cabb0819Sdrh rc = Tcl_Eval(p->interp, Tcl_DStringValue(&cmd)); 275cabb0819Sdrh if( rc ){ 2767e18c259Sdanielk1977 sqlite3_result_error(context, Tcl_GetStringResult(p->interp), -1); 277cabb0819Sdrh }else{ 278d8123366Sdanielk1977 sqlite3_result_text(context, Tcl_GetStringResult(p->interp), -1, 279d8123366Sdanielk1977 SQLITE_TRANSIENT); 280cabb0819Sdrh } 281cabb0819Sdrh } 282895d7472Sdrh 283e22a334bSdrh #ifndef SQLITE_OMIT_AUTHORIZATION 284e22a334bSdrh /* 285e22a334bSdrh ** This is the authentication function. It appends the authentication 286e22a334bSdrh ** type code and the two arguments to zCmd[] then invokes the result 287e22a334bSdrh ** on the interpreter. The reply is examined to determine if the 288e22a334bSdrh ** authentication fails or succeeds. 289e22a334bSdrh */ 290e22a334bSdrh static int auth_callback( 291e22a334bSdrh void *pArg, 292e22a334bSdrh int code, 293e22a334bSdrh const char *zArg1, 294e22a334bSdrh const char *zArg2, 295e22a334bSdrh const char *zArg3, 296e22a334bSdrh const char *zArg4 297e22a334bSdrh ){ 298e22a334bSdrh char *zCode; 299e22a334bSdrh Tcl_DString str; 300e22a334bSdrh int rc; 301e22a334bSdrh const char *zReply; 302e22a334bSdrh SqliteDb *pDb = (SqliteDb*)pArg; 303e22a334bSdrh 304e22a334bSdrh switch( code ){ 305e22a334bSdrh case SQLITE_COPY : zCode="SQLITE_COPY"; break; 306e22a334bSdrh case SQLITE_CREATE_INDEX : zCode="SQLITE_CREATE_INDEX"; break; 307e22a334bSdrh case SQLITE_CREATE_TABLE : zCode="SQLITE_CREATE_TABLE"; break; 308e22a334bSdrh case SQLITE_CREATE_TEMP_INDEX : zCode="SQLITE_CREATE_TEMP_INDEX"; break; 309e22a334bSdrh case SQLITE_CREATE_TEMP_TABLE : zCode="SQLITE_CREATE_TEMP_TABLE"; break; 310e22a334bSdrh case SQLITE_CREATE_TEMP_TRIGGER: zCode="SQLITE_CREATE_TEMP_TRIGGER"; break; 311e22a334bSdrh case SQLITE_CREATE_TEMP_VIEW : zCode="SQLITE_CREATE_TEMP_VIEW"; break; 312e22a334bSdrh case SQLITE_CREATE_TRIGGER : zCode="SQLITE_CREATE_TRIGGER"; break; 313e22a334bSdrh case SQLITE_CREATE_VIEW : zCode="SQLITE_CREATE_VIEW"; break; 314e22a334bSdrh case SQLITE_DELETE : zCode="SQLITE_DELETE"; break; 315e22a334bSdrh case SQLITE_DROP_INDEX : zCode="SQLITE_DROP_INDEX"; break; 316e22a334bSdrh case SQLITE_DROP_TABLE : zCode="SQLITE_DROP_TABLE"; break; 317e22a334bSdrh case SQLITE_DROP_TEMP_INDEX : zCode="SQLITE_DROP_TEMP_INDEX"; break; 318e22a334bSdrh case SQLITE_DROP_TEMP_TABLE : zCode="SQLITE_DROP_TEMP_TABLE"; break; 319e22a334bSdrh case SQLITE_DROP_TEMP_TRIGGER : zCode="SQLITE_DROP_TEMP_TRIGGER"; break; 320e22a334bSdrh case SQLITE_DROP_TEMP_VIEW : zCode="SQLITE_DROP_TEMP_VIEW"; break; 321e22a334bSdrh case SQLITE_DROP_TRIGGER : zCode="SQLITE_DROP_TRIGGER"; break; 322e22a334bSdrh case SQLITE_DROP_VIEW : zCode="SQLITE_DROP_VIEW"; break; 323e22a334bSdrh case SQLITE_INSERT : zCode="SQLITE_INSERT"; break; 324e22a334bSdrh case SQLITE_PRAGMA : zCode="SQLITE_PRAGMA"; break; 325e22a334bSdrh case SQLITE_READ : zCode="SQLITE_READ"; break; 326e22a334bSdrh case SQLITE_SELECT : zCode="SQLITE_SELECT"; break; 327e22a334bSdrh case SQLITE_TRANSACTION : zCode="SQLITE_TRANSACTION"; break; 328e22a334bSdrh case SQLITE_UPDATE : zCode="SQLITE_UPDATE"; break; 32981e293b4Sdrh case SQLITE_ATTACH : zCode="SQLITE_ATTACH"; break; 33081e293b4Sdrh case SQLITE_DETACH : zCode="SQLITE_DETACH"; break; 3311c8c23ccSdanielk1977 case SQLITE_ALTER_TABLE : zCode="SQLITE_ALTER_TABLE"; break; 3321d54df88Sdanielk1977 case SQLITE_REINDEX : zCode="SQLITE_REINDEX"; break; 333e22a334bSdrh default : zCode="????"; break; 334e22a334bSdrh } 335e22a334bSdrh Tcl_DStringInit(&str); 336e22a334bSdrh Tcl_DStringAppend(&str, pDb->zAuth, -1); 337e22a334bSdrh Tcl_DStringAppendElement(&str, zCode); 338e22a334bSdrh Tcl_DStringAppendElement(&str, zArg1 ? zArg1 : ""); 339e22a334bSdrh Tcl_DStringAppendElement(&str, zArg2 ? zArg2 : ""); 340e22a334bSdrh Tcl_DStringAppendElement(&str, zArg3 ? zArg3 : ""); 341e22a334bSdrh Tcl_DStringAppendElement(&str, zArg4 ? zArg4 : ""); 342e22a334bSdrh rc = Tcl_GlobalEval(pDb->interp, Tcl_DStringValue(&str)); 343e22a334bSdrh Tcl_DStringFree(&str); 344e22a334bSdrh zReply = Tcl_GetStringResult(pDb->interp); 345e22a334bSdrh if( strcmp(zReply,"SQLITE_OK")==0 ){ 346e22a334bSdrh rc = SQLITE_OK; 347e22a334bSdrh }else if( strcmp(zReply,"SQLITE_DENY")==0 ){ 348e22a334bSdrh rc = SQLITE_DENY; 349e22a334bSdrh }else if( strcmp(zReply,"SQLITE_IGNORE")==0 ){ 350e22a334bSdrh rc = SQLITE_IGNORE; 351e22a334bSdrh }else{ 352e22a334bSdrh rc = 999; 353e22a334bSdrh } 354e22a334bSdrh return rc; 355e22a334bSdrh } 356e22a334bSdrh #endif /* SQLITE_OMIT_AUTHORIZATION */ 357cabb0819Sdrh 358cabb0819Sdrh /* 359ef2cb63eSdanielk1977 ** zText is a pointer to text obtained via an sqlite3_result_text() 360ef2cb63eSdanielk1977 ** or similar interface. This routine returns a Tcl string object, 361ef2cb63eSdanielk1977 ** reference count set to 0, containing the text. If a translation 362ef2cb63eSdanielk1977 ** between iso8859 and UTF-8 is required, it is preformed. 363ef2cb63eSdanielk1977 */ 364ef2cb63eSdanielk1977 static Tcl_Obj *dbTextToObj(char const *zText){ 365ef2cb63eSdanielk1977 Tcl_Obj *pVal; 366ef2cb63eSdanielk1977 #ifdef UTF_TRANSLATION_NEEDED 367ef2cb63eSdanielk1977 Tcl_DString dCol; 368ef2cb63eSdanielk1977 Tcl_DStringInit(&dCol); 369ef2cb63eSdanielk1977 Tcl_ExternalToUtfDString(NULL, zText, -1, &dCol); 370ef2cb63eSdanielk1977 pVal = Tcl_NewStringObj(Tcl_DStringValue(&dCol), -1); 371ef2cb63eSdanielk1977 Tcl_DStringFree(&dCol); 372ef2cb63eSdanielk1977 #else 373ef2cb63eSdanielk1977 pVal = Tcl_NewStringObj(zText, -1); 374ef2cb63eSdanielk1977 #endif 375ef2cb63eSdanielk1977 return pVal; 376ef2cb63eSdanielk1977 } 377ef2cb63eSdanielk1977 378ef2cb63eSdanielk1977 /* 3791067fe11Stpoindex ** This routine reads a line of text from FILE in, stores 3801067fe11Stpoindex ** the text in memory obtained from malloc() and returns a pointer 3811067fe11Stpoindex ** to the text. NULL is returned at end of file, or if malloc() 3821067fe11Stpoindex ** fails. 3831067fe11Stpoindex ** 3841067fe11Stpoindex ** The interface is like "readline" but no command-line editing 3851067fe11Stpoindex ** is done. 3861067fe11Stpoindex ** 3871067fe11Stpoindex ** copied from shell.c from '.import' command 3881067fe11Stpoindex */ 3891067fe11Stpoindex static char *local_getline(char *zPrompt, FILE *in){ 3901067fe11Stpoindex char *zLine; 3911067fe11Stpoindex int nLine; 3921067fe11Stpoindex int n; 3931067fe11Stpoindex int eol; 3941067fe11Stpoindex 3951067fe11Stpoindex nLine = 100; 3961067fe11Stpoindex zLine = malloc( nLine ); 3971067fe11Stpoindex if( zLine==0 ) return 0; 3981067fe11Stpoindex n = 0; 3991067fe11Stpoindex eol = 0; 4001067fe11Stpoindex while( !eol ){ 4011067fe11Stpoindex if( n+100>nLine ){ 4021067fe11Stpoindex nLine = nLine*2 + 100; 4031067fe11Stpoindex zLine = realloc(zLine, nLine); 4041067fe11Stpoindex if( zLine==0 ) return 0; 4051067fe11Stpoindex } 4061067fe11Stpoindex if( fgets(&zLine[n], nLine - n, in)==0 ){ 4071067fe11Stpoindex if( n==0 ){ 4081067fe11Stpoindex free(zLine); 4091067fe11Stpoindex return 0; 4101067fe11Stpoindex } 4111067fe11Stpoindex zLine[n] = 0; 4121067fe11Stpoindex eol = 1; 4131067fe11Stpoindex break; 4141067fe11Stpoindex } 4151067fe11Stpoindex while( zLine[n] ){ n++; } 4161067fe11Stpoindex if( n>0 && zLine[n-1]=='\n' ){ 4171067fe11Stpoindex n--; 4181067fe11Stpoindex zLine[n] = 0; 4191067fe11Stpoindex eol = 1; 4201067fe11Stpoindex } 4211067fe11Stpoindex } 4221067fe11Stpoindex zLine = realloc( zLine, n+1 ); 4231067fe11Stpoindex return zLine; 4241067fe11Stpoindex } 4251067fe11Stpoindex 4261067fe11Stpoindex /* 42775897234Sdrh ** The "sqlite" command below creates a new Tcl command for each 42875897234Sdrh ** connection it opens to an SQLite database. This routine is invoked 42975897234Sdrh ** whenever one of those connection-specific commands is executed 43075897234Sdrh ** in Tcl. For example, if you run Tcl code like this: 43175897234Sdrh ** 4329bb575fdSdrh ** sqlite3 db1 "my_database" 43375897234Sdrh ** db1 close 43475897234Sdrh ** 43575897234Sdrh ** The first command opens a connection to the "my_database" database 43675897234Sdrh ** and calls that connection "db1". The second command causes this 43775897234Sdrh ** subroutine to be invoked. 43875897234Sdrh */ 4396d31316cSdrh static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ 440bec3f402Sdrh SqliteDb *pDb = (SqliteDb*)cd; 4416d31316cSdrh int choice; 44222fbcb8dSdrh int rc = TCL_OK; 4430de8c112Sdrh static const char *DB_strs[] = { 444fb7e7651Sdrh "authorizer", "busy", "cache", 445fb7e7651Sdrh "changes", "close", "collate", 446fb7e7651Sdrh "collation_needed", "commit_hook", "complete", 447fb7e7651Sdrh "copy", "errorcode", "eval", 448*55c45f2eSdanielk1977 "function", "last_insert_rowid", "nullvalue", 449*55c45f2eSdanielk1977 "onecolumn", "progress", "rekey", 450*55c45f2eSdanielk1977 "timeout", "total_changes", "trace", 451*55c45f2eSdanielk1977 "version", 4520f14e2ebSdrh 0 4536d31316cSdrh }; 454411995dcSdrh enum DB_enum { 455fb7e7651Sdrh DB_AUTHORIZER, DB_BUSY, DB_CACHE, 456fb7e7651Sdrh DB_CHANGES, DB_CLOSE, DB_COLLATE, 457fb7e7651Sdrh DB_COLLATION_NEEDED, DB_COMMIT_HOOK, DB_COMPLETE, 458fb7e7651Sdrh DB_COPY, DB_ERRORCODE, DB_EVAL, 459*55c45f2eSdanielk1977 DB_FUNCTION, DB_LAST_INSERT_ROWID,DB_NULLVALUE, 460*55c45f2eSdanielk1977 DB_ONECOLUMN, DB_PROGRESS, DB_REKEY, 461*55c45f2eSdanielk1977 DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE, 462*55c45f2eSdanielk1977 DB_VERSION 4636d31316cSdrh }; 4641067fe11Stpoindex /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */ 4656d31316cSdrh 4666d31316cSdrh if( objc<2 ){ 4676d31316cSdrh Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); 46875897234Sdrh return TCL_ERROR; 46975897234Sdrh } 470411995dcSdrh if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){ 4716d31316cSdrh return TCL_ERROR; 4726d31316cSdrh } 4736d31316cSdrh 474411995dcSdrh switch( (enum DB_enum)choice ){ 47575897234Sdrh 476e22a334bSdrh /* $db authorizer ?CALLBACK? 477e22a334bSdrh ** 478e22a334bSdrh ** Invoke the given callback to authorize each SQL operation as it is 479e22a334bSdrh ** compiled. 5 arguments are appended to the callback before it is 480e22a334bSdrh ** invoked: 481e22a334bSdrh ** 482e22a334bSdrh ** (1) The authorization type (ex: SQLITE_CREATE_TABLE, SQLITE_INSERT, ...) 483e22a334bSdrh ** (2) First descriptive name (depends on authorization type) 484e22a334bSdrh ** (3) Second descriptive name 485e22a334bSdrh ** (4) Name of the database (ex: "main", "temp") 486e22a334bSdrh ** (5) Name of trigger that is doing the access 487e22a334bSdrh ** 488e22a334bSdrh ** The callback should return on of the following strings: SQLITE_OK, 489e22a334bSdrh ** SQLITE_IGNORE, or SQLITE_DENY. Any other return value is an error. 490e22a334bSdrh ** 491e22a334bSdrh ** If this method is invoked with no arguments, the current authorization 492e22a334bSdrh ** callback string is returned. 493e22a334bSdrh */ 494e22a334bSdrh case DB_AUTHORIZER: { 4951211de37Sdrh #ifdef SQLITE_OMIT_AUTHORIZATION 4961211de37Sdrh Tcl_AppendResult(interp, "authorization not available in this build", 0); 4971211de37Sdrh return TCL_ERROR; 4981211de37Sdrh #else 499e22a334bSdrh if( objc>3 ){ 500e22a334bSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 5010f14e2ebSdrh return TCL_ERROR; 502e22a334bSdrh }else if( objc==2 ){ 503b5a20d3cSdrh if( pDb->zAuth ){ 504e22a334bSdrh Tcl_AppendResult(interp, pDb->zAuth, 0); 505e22a334bSdrh } 506e22a334bSdrh }else{ 507e22a334bSdrh char *zAuth; 508e22a334bSdrh int len; 509e22a334bSdrh if( pDb->zAuth ){ 510e22a334bSdrh Tcl_Free(pDb->zAuth); 511e22a334bSdrh } 512e22a334bSdrh zAuth = Tcl_GetStringFromObj(objv[2], &len); 513e22a334bSdrh if( zAuth && len>0 ){ 514e22a334bSdrh pDb->zAuth = Tcl_Alloc( len + 1 ); 515e22a334bSdrh strcpy(pDb->zAuth, zAuth); 516e22a334bSdrh }else{ 517e22a334bSdrh pDb->zAuth = 0; 518e22a334bSdrh } 519e22a334bSdrh if( pDb->zAuth ){ 520e22a334bSdrh pDb->interp = interp; 5216f8a503dSdanielk1977 sqlite3_set_authorizer(pDb->db, auth_callback, pDb); 522e22a334bSdrh }else{ 5236f8a503dSdanielk1977 sqlite3_set_authorizer(pDb->db, 0, 0); 524e22a334bSdrh } 525e22a334bSdrh } 5261211de37Sdrh #endif 527e22a334bSdrh break; 528e22a334bSdrh } 529e22a334bSdrh 530bec3f402Sdrh /* $db busy ?CALLBACK? 531bec3f402Sdrh ** 532bec3f402Sdrh ** Invoke the given callback if an SQL statement attempts to open 533bec3f402Sdrh ** a locked database file. 534bec3f402Sdrh */ 5356d31316cSdrh case DB_BUSY: { 5366d31316cSdrh if( objc>3 ){ 5376d31316cSdrh Tcl_WrongNumArgs(interp, 2, objv, "CALLBACK"); 538bec3f402Sdrh return TCL_ERROR; 5396d31316cSdrh }else if( objc==2 ){ 540bec3f402Sdrh if( pDb->zBusy ){ 541bec3f402Sdrh Tcl_AppendResult(interp, pDb->zBusy, 0); 542bec3f402Sdrh } 543bec3f402Sdrh }else{ 5446d31316cSdrh char *zBusy; 5456d31316cSdrh int len; 546bec3f402Sdrh if( pDb->zBusy ){ 547bec3f402Sdrh Tcl_Free(pDb->zBusy); 5486d31316cSdrh } 5496d31316cSdrh zBusy = Tcl_GetStringFromObj(objv[2], &len); 5506d31316cSdrh if( zBusy && len>0 ){ 5516d31316cSdrh pDb->zBusy = Tcl_Alloc( len + 1 ); 5526d31316cSdrh strcpy(pDb->zBusy, zBusy); 5536d31316cSdrh }else{ 554bec3f402Sdrh pDb->zBusy = 0; 555bec3f402Sdrh } 556bec3f402Sdrh if( pDb->zBusy ){ 557bec3f402Sdrh pDb->interp = interp; 5586f8a503dSdanielk1977 sqlite3_busy_handler(pDb->db, DbBusyHandler, pDb); 5596d31316cSdrh }else{ 5606f8a503dSdanielk1977 sqlite3_busy_handler(pDb->db, 0, 0); 561bec3f402Sdrh } 562bec3f402Sdrh } 5636d31316cSdrh break; 5646d31316cSdrh } 565bec3f402Sdrh 566fb7e7651Sdrh /* $db cache flush 567fb7e7651Sdrh ** $db cache size n 568fb7e7651Sdrh ** 569fb7e7651Sdrh ** Flush the prepared statement cache, or set the maximum number of 570fb7e7651Sdrh ** cached statements. 571fb7e7651Sdrh */ 572fb7e7651Sdrh case DB_CACHE: { 573fb7e7651Sdrh char *subCmd; 574fb7e7651Sdrh int n; 575fb7e7651Sdrh 576fb7e7651Sdrh if( objc<=2 ){ 577fb7e7651Sdrh Tcl_WrongNumArgs(interp, 1, objv, "cache option ?arg?"); 578fb7e7651Sdrh return TCL_ERROR; 579fb7e7651Sdrh } 580fb7e7651Sdrh subCmd = Tcl_GetStringFromObj( objv[2], 0 ); 581fb7e7651Sdrh if( *subCmd=='f' && strcmp(subCmd,"flush")==0 ){ 582fb7e7651Sdrh if( objc!=3 ){ 583fb7e7651Sdrh Tcl_WrongNumArgs(interp, 2, objv, "flush"); 584fb7e7651Sdrh return TCL_ERROR; 585fb7e7651Sdrh }else{ 586fb7e7651Sdrh flushStmtCache( pDb ); 587fb7e7651Sdrh } 588fb7e7651Sdrh }else if( *subCmd=='s' && strcmp(subCmd,"size")==0 ){ 589fb7e7651Sdrh if( objc!=4 ){ 590fb7e7651Sdrh Tcl_WrongNumArgs(interp, 2, objv, "size n"); 591fb7e7651Sdrh return TCL_ERROR; 592fb7e7651Sdrh }else{ 593fb7e7651Sdrh if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){ 594fb7e7651Sdrh Tcl_AppendResult( interp, "cannot convert \"", 595fb7e7651Sdrh Tcl_GetStringFromObj(objv[3],0), "\" to integer", 0); 596fb7e7651Sdrh return TCL_ERROR; 597fb7e7651Sdrh }else{ 598fb7e7651Sdrh if( n<0 ){ 599fb7e7651Sdrh flushStmtCache( pDb ); 600fb7e7651Sdrh n = 0; 601fb7e7651Sdrh }else if( n>MAX_PREPARED_STMTS ){ 602fb7e7651Sdrh n = MAX_PREPARED_STMTS; 603fb7e7651Sdrh } 604fb7e7651Sdrh pDb->maxStmt = n; 605fb7e7651Sdrh } 606fb7e7651Sdrh } 607fb7e7651Sdrh }else{ 608fb7e7651Sdrh Tcl_AppendResult( interp, "bad option \"", 609fb7e7651Sdrh Tcl_GetStringFromObj(objv[0],0), "\": must be flush or size", 0); 610fb7e7651Sdrh return TCL_ERROR; 611fb7e7651Sdrh } 612fb7e7651Sdrh break; 613fb7e7651Sdrh } 614fb7e7651Sdrh 615b28af71aSdanielk1977 /* $db changes 616c8d30ac1Sdrh ** 617c8d30ac1Sdrh ** Return the number of rows that were modified, inserted, or deleted by 618b28af71aSdanielk1977 ** the most recent INSERT, UPDATE or DELETE statement, not including 619b28af71aSdanielk1977 ** any changes made by trigger programs. 620c8d30ac1Sdrh */ 621c8d30ac1Sdrh case DB_CHANGES: { 622c8d30ac1Sdrh Tcl_Obj *pResult; 623c8d30ac1Sdrh if( objc!=2 ){ 624c8d30ac1Sdrh Tcl_WrongNumArgs(interp, 2, objv, ""); 625c8d30ac1Sdrh return TCL_ERROR; 626c8d30ac1Sdrh } 627c8d30ac1Sdrh pResult = Tcl_GetObjResult(interp); 628b28af71aSdanielk1977 Tcl_SetIntObj(pResult, sqlite3_changes(pDb->db)); 629f146a776Srdc break; 630f146a776Srdc } 631f146a776Srdc 63275897234Sdrh /* $db close 63375897234Sdrh ** 63475897234Sdrh ** Shutdown the database 63575897234Sdrh */ 6366d31316cSdrh case DB_CLOSE: { 6376d31316cSdrh Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0)); 6386d31316cSdrh break; 6396d31316cSdrh } 64075897234Sdrh 641aa940eacSdrh /* $db commit_hook ?CALLBACK? 642aa940eacSdrh ** 643aa940eacSdrh ** Invoke the given callback just before committing every SQL transaction. 644aa940eacSdrh ** If the callback throws an exception or returns non-zero, then the 645aa940eacSdrh ** transaction is aborted. If CALLBACK is an empty string, the callback 646aa940eacSdrh ** is disabled. 647aa940eacSdrh */ 648aa940eacSdrh case DB_COMMIT_HOOK: { 649aa940eacSdrh if( objc>3 ){ 650aa940eacSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 6510f14e2ebSdrh return TCL_ERROR; 652aa940eacSdrh }else if( objc==2 ){ 653aa940eacSdrh if( pDb->zCommit ){ 654aa940eacSdrh Tcl_AppendResult(interp, pDb->zCommit, 0); 655aa940eacSdrh } 656aa940eacSdrh }else{ 657aa940eacSdrh char *zCommit; 658aa940eacSdrh int len; 659aa940eacSdrh if( pDb->zCommit ){ 660aa940eacSdrh Tcl_Free(pDb->zCommit); 661aa940eacSdrh } 662aa940eacSdrh zCommit = Tcl_GetStringFromObj(objv[2], &len); 663aa940eacSdrh if( zCommit && len>0 ){ 664aa940eacSdrh pDb->zCommit = Tcl_Alloc( len + 1 ); 665aa940eacSdrh strcpy(pDb->zCommit, zCommit); 666aa940eacSdrh }else{ 667aa940eacSdrh pDb->zCommit = 0; 668aa940eacSdrh } 669aa940eacSdrh if( pDb->zCommit ){ 670aa940eacSdrh pDb->interp = interp; 6716f8a503dSdanielk1977 sqlite3_commit_hook(pDb->db, DbCommitHandler, pDb); 672aa940eacSdrh }else{ 6736f8a503dSdanielk1977 sqlite3_commit_hook(pDb->db, 0, 0); 674aa940eacSdrh } 675aa940eacSdrh } 676aa940eacSdrh break; 677aa940eacSdrh } 678aa940eacSdrh 6790f14e2ebSdrh /* 6800f14e2ebSdrh ** $db collate NAME SCRIPT 6810f14e2ebSdrh ** 6820f14e2ebSdrh ** Create a new SQL collation function called NAME. Whenever 6830f14e2ebSdrh ** that function is called, invoke SCRIPT to evaluate the function. 6840f14e2ebSdrh */ 6850f14e2ebSdrh case DB_COLLATE: { 6860f14e2ebSdrh SqlCollate *pCollate; 6870f14e2ebSdrh char *zName; 6880f14e2ebSdrh char *zScript; 6890f14e2ebSdrh int nScript; 6900f14e2ebSdrh if( objc!=4 ){ 6910f14e2ebSdrh Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT"); 6920f14e2ebSdrh return TCL_ERROR; 6930f14e2ebSdrh } 6940f14e2ebSdrh zName = Tcl_GetStringFromObj(objv[2], 0); 6950f14e2ebSdrh zScript = Tcl_GetStringFromObj(objv[3], &nScript); 6960f14e2ebSdrh pCollate = (SqlCollate*)Tcl_Alloc( sizeof(*pCollate) + nScript + 1 ); 6970f14e2ebSdrh if( pCollate==0 ) return TCL_ERROR; 6980f14e2ebSdrh pCollate->interp = interp; 6990f14e2ebSdrh pCollate->pNext = pDb->pCollate; 7000f14e2ebSdrh pCollate->zScript = (char*)&pCollate[1]; 7010f14e2ebSdrh pDb->pCollate = pCollate; 7020f14e2ebSdrh strcpy(pCollate->zScript, zScript); 7030f14e2ebSdrh if( sqlite3_create_collation(pDb->db, zName, SQLITE_UTF8, 7040f14e2ebSdrh pCollate, tclSqlCollate) ){ 7059636c4e1Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); 7060f14e2ebSdrh return TCL_ERROR; 7070f14e2ebSdrh } 7080f14e2ebSdrh break; 7090f14e2ebSdrh } 7100f14e2ebSdrh 7110f14e2ebSdrh /* 7120f14e2ebSdrh ** $db collation_needed SCRIPT 7130f14e2ebSdrh ** 7140f14e2ebSdrh ** Create a new SQL collation function called NAME. Whenever 7150f14e2ebSdrh ** that function is called, invoke SCRIPT to evaluate the function. 7160f14e2ebSdrh */ 7170f14e2ebSdrh case DB_COLLATION_NEEDED: { 7180f14e2ebSdrh if( objc!=3 ){ 7190f14e2ebSdrh Tcl_WrongNumArgs(interp, 2, objv, "SCRIPT"); 7200f14e2ebSdrh return TCL_ERROR; 7210f14e2ebSdrh } 7220f14e2ebSdrh if( pDb->pCollateNeeded ){ 7230f14e2ebSdrh Tcl_DecrRefCount(pDb->pCollateNeeded); 7240f14e2ebSdrh } 7250f14e2ebSdrh pDb->pCollateNeeded = Tcl_DuplicateObj(objv[2]); 7260f14e2ebSdrh Tcl_IncrRefCount(pDb->pCollateNeeded); 7270f14e2ebSdrh sqlite3_collation_needed(pDb->db, pDb, tclCollateNeeded); 7280f14e2ebSdrh break; 7290f14e2ebSdrh } 7300f14e2ebSdrh 73175897234Sdrh /* $db complete SQL 73275897234Sdrh ** 73375897234Sdrh ** Return TRUE if SQL is a complete SQL statement. Return FALSE if 73475897234Sdrh ** additional lines of input are needed. This is similar to the 73575897234Sdrh ** built-in "info complete" command of Tcl. 73675897234Sdrh */ 7376d31316cSdrh case DB_COMPLETE: { 738ccae6026Sdrh #ifndef SQLITE_OMIT_COMPLETE 7396d31316cSdrh Tcl_Obj *pResult; 7406d31316cSdrh int isComplete; 7416d31316cSdrh if( objc!=3 ){ 7426d31316cSdrh Tcl_WrongNumArgs(interp, 2, objv, "SQL"); 74375897234Sdrh return TCL_ERROR; 74475897234Sdrh } 7456f8a503dSdanielk1977 isComplete = sqlite3_complete( Tcl_GetStringFromObj(objv[2], 0) ); 7466d31316cSdrh pResult = Tcl_GetObjResult(interp); 7476d31316cSdrh Tcl_SetBooleanObj(pResult, isComplete); 748ccae6026Sdrh #endif 7496d31316cSdrh break; 7506d31316cSdrh } 75175897234Sdrh 75275897234Sdrh /* 753dcd997eaSdrh ** $db errorcode 754dcd997eaSdrh ** 755dcd997eaSdrh ** Return the numeric error code that was returned by the most recent 7566f8a503dSdanielk1977 ** call to sqlite3_exec(). 757dcd997eaSdrh */ 758dcd997eaSdrh case DB_ERRORCODE: { 759f3ce83f5Sdanielk1977 Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_errcode(pDb->db))); 760dcd997eaSdrh break; 761dcd997eaSdrh } 762dcd997eaSdrh 763dcd997eaSdrh /* 764895d7472Sdrh ** $db eval $sql ?array? ?{ ...code... }? 7651807ce37Sdrh ** $db onecolumn $sql 76675897234Sdrh ** 76775897234Sdrh ** The SQL statement in $sql is evaluated. For each row, the values are 768bec3f402Sdrh ** placed in elements of the array named "array" and ...code... is executed. 76975897234Sdrh ** If "array" and "code" are omitted, then no callback is every invoked. 77075897234Sdrh ** If "array" is an empty string, then the values are placed in variables 77175897234Sdrh ** that have the same name as the fields extracted by the query. 7721807ce37Sdrh ** 7731807ce37Sdrh ** The onecolumn method is the equivalent of: 7741807ce37Sdrh ** lindex [$db eval $sql] 0 77575897234Sdrh */ 7761807ce37Sdrh case DB_ONECOLUMN: 7776d31316cSdrh case DB_EVAL: { 7789d74b4c5Sdrh char const *zSql; /* Next SQL statement to execute */ 7799d74b4c5Sdrh char const *zLeft; /* What is left after first stmt in zSql */ 7809d74b4c5Sdrh sqlite3_stmt *pStmt; /* Compiled SQL statment */ 78192febd92Sdrh Tcl_Obj *pArray; /* Name of array into which results are written */ 78292febd92Sdrh Tcl_Obj *pScript; /* Script to run for each result set */ 7831d895039Sdrh Tcl_Obj **apParm; /* Parameters that need a Tcl_DecrRefCount() */ 7841d895039Sdrh int nParm; /* Number of entries used in apParm[] */ 7851d895039Sdrh Tcl_Obj *aParm[10]; /* Static space for apParm[] in the common case */ 7861807ce37Sdrh Tcl_Obj *pRet; /* Value to be returned */ 787fb7e7651Sdrh SqlPreparedStmt *pPreStmt; /* Pointer to a prepared statement */ 788fb7e7651Sdrh int rc2; 789ef2cb63eSdanielk1977 7901807ce37Sdrh if( choice==DB_ONECOLUMN ){ 7911807ce37Sdrh if( objc!=3 ){ 7921807ce37Sdrh Tcl_WrongNumArgs(interp, 2, objv, "SQL"); 7931807ce37Sdrh return TCL_ERROR; 7941807ce37Sdrh } 7951807ce37Sdrh pRet = 0; 7961807ce37Sdrh }else{ 79792febd92Sdrh if( objc<3 || objc>5 ){ 798895d7472Sdrh Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME? ?SCRIPT?"); 79930ccda10Sdanielk1977 return TCL_ERROR; 80030ccda10Sdanielk1977 } 8011807ce37Sdrh pRet = Tcl_NewObj(); 8021807ce37Sdrh Tcl_IncrRefCount(pRet); 8031807ce37Sdrh } 80492febd92Sdrh if( objc==3 ){ 80592febd92Sdrh pArray = pScript = 0; 80692febd92Sdrh }else if( objc==4 ){ 80792febd92Sdrh pArray = 0; 80892febd92Sdrh pScript = objv[3]; 80992febd92Sdrh }else{ 81092febd92Sdrh pArray = objv[3]; 81192febd92Sdrh if( Tcl_GetString(pArray)[0]==0 ) pArray = 0; 81292febd92Sdrh pScript = objv[4]; 81392febd92Sdrh } 81430ccda10Sdanielk1977 8151d895039Sdrh Tcl_IncrRefCount(objv[2]); 81630ccda10Sdanielk1977 zSql = Tcl_GetStringFromObj(objv[2], 0); 81790b6bb19Sdrh while( rc==TCL_OK && zSql[0] ){ 81892febd92Sdrh int i; /* Loop counter */ 819fb7e7651Sdrh int nVar; /* Number of bind parameters in the pStmt */ 82092febd92Sdrh int nCol; /* Number of columns in the result set */ 82192febd92Sdrh Tcl_Obj **apColName = 0; /* Array of column names */ 822fb7e7651Sdrh int len; /* String length of zSql */ 82330ccda10Sdanielk1977 824fb7e7651Sdrh /* Try to find a SQL statement that has already been compiled and 825fb7e7651Sdrh ** which matches the next sequence of SQL. 826fb7e7651Sdrh */ 827fb7e7651Sdrh pStmt = 0; 828fb7e7651Sdrh pPreStmt = pDb->stmtList; 829fb7e7651Sdrh len = strlen(zSql); 830fb7e7651Sdrh if( pPreStmt && sqlite3_expired(pPreStmt->pStmt) ){ 831fb7e7651Sdrh flushStmtCache(pDb); 832fb7e7651Sdrh pPreStmt = 0; 833fb7e7651Sdrh } 834fb7e7651Sdrh for(; pPreStmt; pPreStmt=pPreStmt->pNext){ 835fb7e7651Sdrh int n = pPreStmt->nSql; 836fb7e7651Sdrh if( len>=n 837fb7e7651Sdrh && memcmp(pPreStmt->zSql, zSql, n)==0 838fb7e7651Sdrh && (zSql[n]==0 || zSql[n-1]==';') 839fb7e7651Sdrh ){ 840fb7e7651Sdrh pStmt = pPreStmt->pStmt; 841fb7e7651Sdrh zLeft = &zSql[pPreStmt->nSql]; 842fb7e7651Sdrh 843fb7e7651Sdrh /* When a prepared statement is found, unlink it from the 844fb7e7651Sdrh ** cache list. It will later be added back to the beginning 845fb7e7651Sdrh ** of the cache list in order to implement LRU replacement. 846fb7e7651Sdrh */ 847fb7e7651Sdrh if( pPreStmt->pPrev ){ 848fb7e7651Sdrh pPreStmt->pPrev->pNext = pPreStmt->pNext; 849fb7e7651Sdrh }else{ 850fb7e7651Sdrh pDb->stmtList = pPreStmt->pNext; 851fb7e7651Sdrh } 852fb7e7651Sdrh if( pPreStmt->pNext ){ 853fb7e7651Sdrh pPreStmt->pNext->pPrev = pPreStmt->pPrev; 854fb7e7651Sdrh }else{ 855fb7e7651Sdrh pDb->stmtLast = pPreStmt->pPrev; 856fb7e7651Sdrh } 857fb7e7651Sdrh pDb->nStmt--; 858fb7e7651Sdrh break; 859fb7e7651Sdrh } 860fb7e7651Sdrh } 861fb7e7651Sdrh 862fb7e7651Sdrh /* If no prepared statement was found. Compile the SQL text 863fb7e7651Sdrh */ 864fb7e7651Sdrh if( pStmt==0 ){ 86530ccda10Sdanielk1977 if( SQLITE_OK!=sqlite3_prepare(pDb->db, zSql, -1, &pStmt, &zLeft) ){ 866ef2cb63eSdanielk1977 Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db))); 86730ccda10Sdanielk1977 rc = TCL_ERROR; 86830ccda10Sdanielk1977 break; 86930ccda10Sdanielk1977 } 87092febd92Sdrh if( pStmt==0 ){ 87192febd92Sdrh if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){ 872fb7e7651Sdrh /* A compile-time error in the statement 873fb7e7651Sdrh */ 87492febd92Sdrh Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db))); 87592febd92Sdrh rc = TCL_ERROR; 87692febd92Sdrh break; 87792febd92Sdrh }else{ 878fb7e7651Sdrh /* The statement was a no-op. Continue to the next statement 879fb7e7651Sdrh ** in the SQL string. 880fb7e7651Sdrh */ 88192febd92Sdrh zSql = zLeft; 88292febd92Sdrh continue; 88392febd92Sdrh } 88492febd92Sdrh } 885fb7e7651Sdrh assert( pPreStmt==0 ); 886fb7e7651Sdrh } 88730ccda10Sdanielk1977 888fb7e7651Sdrh /* Bind values to parameters that begin with $ or : 889fb7e7651Sdrh */ 89092febd92Sdrh nVar = sqlite3_bind_parameter_count(pStmt); 8911d895039Sdrh nParm = 0; 8921d895039Sdrh if( nVar>sizeof(aParm)/sizeof(aParm[0]) ){ 8931d895039Sdrh apParm = (Tcl_Obj**)Tcl_Alloc(nVar*sizeof(apParm[0])); 8941d895039Sdrh }else{ 8951d895039Sdrh apParm = aParm; 8961d895039Sdrh } 89792febd92Sdrh for(i=1; i<=nVar; i++){ 89892febd92Sdrh const char *zVar = sqlite3_bind_parameter_name(pStmt, i); 899c8f9079cSdrh if( zVar!=0 && (zVar[0]=='$' || zVar[0]==':') ){ 90092febd92Sdrh Tcl_Obj *pVar = Tcl_GetVar2Ex(interp, &zVar[1], 0, 0); 90192febd92Sdrh if( pVar ){ 90292febd92Sdrh int n; 90392febd92Sdrh u8 *data; 90492febd92Sdrh char *zType = pVar->typePtr ? pVar->typePtr->name : ""; 90592febd92Sdrh char c = zType[0]; 90692febd92Sdrh if( c=='b' && strcmp(zType,"bytearray")==0 ){ 90792febd92Sdrh data = Tcl_GetByteArrayFromObj(pVar, &n); 90892febd92Sdrh sqlite3_bind_blob(pStmt, i, data, n, SQLITE_STATIC); 9091d895039Sdrh Tcl_IncrRefCount(pVar); 9101d895039Sdrh apParm[nParm++] = pVar; 91192febd92Sdrh }else if( (c=='b' && strcmp(zType,"boolean")==0) || 91292febd92Sdrh (c=='i' && strcmp(zType,"int")==0) ){ 91392febd92Sdrh Tcl_GetIntFromObj(interp, pVar, &n); 91492febd92Sdrh sqlite3_bind_int(pStmt, i, n); 91592febd92Sdrh }else if( c=='d' && strcmp(zType,"double")==0 ){ 91692febd92Sdrh double r; 91792febd92Sdrh Tcl_GetDoubleFromObj(interp, pVar, &r); 91892febd92Sdrh sqlite3_bind_double(pStmt, i, r); 91992febd92Sdrh }else{ 92092febd92Sdrh data = Tcl_GetStringFromObj(pVar, &n); 92192febd92Sdrh sqlite3_bind_text(pStmt, i, data, n, SQLITE_STATIC); 9221d895039Sdrh Tcl_IncrRefCount(pVar); 9231d895039Sdrh apParm[nParm++] = pVar; 92492febd92Sdrh } 925fb7e7651Sdrh }else{ 926fb7e7651Sdrh sqlite3_bind_null( pStmt, i ); 92792febd92Sdrh } 92892febd92Sdrh } 92992febd92Sdrh } 93092febd92Sdrh 93192febd92Sdrh /* Compute column names */ 93292febd92Sdrh nCol = sqlite3_column_count(pStmt); 93392febd92Sdrh if( pScript ){ 93492febd92Sdrh apColName = (Tcl_Obj**)Tcl_Alloc( sizeof(Tcl_Obj*)*nCol ); 93592febd92Sdrh if( apColName==0 ) break; 93692febd92Sdrh for(i=0; i<nCol; i++){ 93792febd92Sdrh apColName[i] = dbTextToObj(sqlite3_column_name(pStmt,i)); 93892febd92Sdrh Tcl_IncrRefCount(apColName[i]); 93992febd92Sdrh } 94092febd92Sdrh } 94192febd92Sdrh 94292febd92Sdrh /* If results are being stored in an array variable, then create 94392febd92Sdrh ** the array(*) entry for that array 94492febd92Sdrh */ 94592febd92Sdrh if( pArray ){ 94630ccda10Sdanielk1977 Tcl_Obj *pColList = Tcl_NewObj(); 9473ced14a6Sdrh Tcl_Obj *pStar = Tcl_NewStringObj("*", -1); 94830ccda10Sdanielk1977 Tcl_IncrRefCount(pColList); 94992febd92Sdrh for(i=0; i<nCol; i++){ 95092febd92Sdrh Tcl_ListObjAppendElement(interp, pColList, apColName[i]); 95130ccda10Sdanielk1977 } 9523ced14a6Sdrh Tcl_ObjSetVar2(interp, pArray, pStar, pColList,0); 9533ced14a6Sdrh Tcl_DecrRefCount(pColList); 9543ced14a6Sdrh Tcl_DecrRefCount(pStar); 95530ccda10Sdanielk1977 } 95630ccda10Sdanielk1977 95792febd92Sdrh /* Execute the SQL 95892febd92Sdrh */ 95990b6bb19Sdrh while( rc==TCL_OK && pStmt && SQLITE_ROW==sqlite3_step(pStmt) ){ 96092febd92Sdrh for(i=0; i<nCol; i++){ 96130ccda10Sdanielk1977 Tcl_Obj *pVal; 96230ccda10Sdanielk1977 96330ccda10Sdanielk1977 /* Set pVal to contain the i'th column of this row. */ 96492febd92Sdrh switch( sqlite3_column_type(pStmt, i) ){ 96592febd92Sdrh case SQLITE_BLOB: { 9663fd0a736Sdanielk1977 int bytes = sqlite3_column_bytes(pStmt, i); 9673fd0a736Sdanielk1977 pVal = Tcl_NewByteArrayObj(sqlite3_column_blob(pStmt, i), bytes); 96892febd92Sdrh break; 96992febd92Sdrh } 97092febd92Sdrh case SQLITE_INTEGER: { 97192febd92Sdrh sqlite_int64 v = sqlite3_column_int64(pStmt, i); 97292febd92Sdrh if( v>=-2147483647 && v<=2147483647 ){ 97392febd92Sdrh pVal = Tcl_NewIntObj(v); 97492febd92Sdrh }else{ 97592febd92Sdrh pVal = Tcl_NewWideIntObj(v); 97692febd92Sdrh } 97792febd92Sdrh break; 97892febd92Sdrh } 97992febd92Sdrh case SQLITE_FLOAT: { 98092febd92Sdrh double r = sqlite3_column_double(pStmt, i); 98192febd92Sdrh pVal = Tcl_NewDoubleObj(r); 98292febd92Sdrh break; 98392febd92Sdrh } 984*55c45f2eSdanielk1977 case SQLITE_NULL: { 985*55c45f2eSdanielk1977 pVal = dbTextToObj(pDb->zNull); 986*55c45f2eSdanielk1977 break; 987*55c45f2eSdanielk1977 } 98892febd92Sdrh default: { 98992febd92Sdrh pVal = dbTextToObj(sqlite3_column_text(pStmt, i)); 99092febd92Sdrh break; 99192febd92Sdrh } 99230ccda10Sdanielk1977 } 99330ccda10Sdanielk1977 99492febd92Sdrh if( pScript ){ 99592febd92Sdrh if( pArray==0 ){ 99692febd92Sdrh Tcl_ObjSetVar2(interp, apColName[i], 0, pVal, 0); 99730ccda10Sdanielk1977 }else{ 99892febd92Sdrh Tcl_ObjSetVar2(interp, pArray, apColName[i], pVal, 0); 99930ccda10Sdanielk1977 } 10001807ce37Sdrh }else if( choice==DB_ONECOLUMN ){ 10011807ce37Sdrh if( pRet==0 ){ 10021807ce37Sdrh pRet = pVal; 10031807ce37Sdrh Tcl_IncrRefCount(pRet); 10041807ce37Sdrh } 100590b6bb19Sdrh rc = TCL_BREAK; 100630ccda10Sdanielk1977 }else{ 100730ccda10Sdanielk1977 Tcl_ListObjAppendElement(interp, pRet, pVal); 100830ccda10Sdanielk1977 } 100930ccda10Sdanielk1977 } 101030ccda10Sdanielk1977 101192febd92Sdrh if( pScript ){ 101292febd92Sdrh rc = Tcl_EvalObjEx(interp, pScript, 0); 101390b6bb19Sdrh if( rc==TCL_CONTINUE ){ 101490b6bb19Sdrh rc = TCL_OK; 101530ccda10Sdanielk1977 } 101630ccda10Sdanielk1977 } 101790b6bb19Sdrh } 101890b6bb19Sdrh if( rc==TCL_BREAK ){ 101990b6bb19Sdrh rc = TCL_OK; 102090b6bb19Sdrh } 102130ccda10Sdanielk1977 102292febd92Sdrh /* Free the column name objects */ 102392febd92Sdrh if( pScript ){ 102492febd92Sdrh for(i=0; i<nCol; i++){ 102592febd92Sdrh Tcl_DecrRefCount(apColName[i]); 102692febd92Sdrh } 102792febd92Sdrh Tcl_Free((char*)apColName); 102892febd92Sdrh } 102992febd92Sdrh 10301d895039Sdrh /* Free the bound string and blob parameters */ 10311d895039Sdrh for(i=0; i<nParm; i++){ 10321d895039Sdrh Tcl_DecrRefCount(apParm[i]); 10331d895039Sdrh } 10341d895039Sdrh if( apParm!=aParm ){ 10351d895039Sdrh Tcl_Free((char*)apParm); 10361d895039Sdrh } 10371d895039Sdrh 1038fb7e7651Sdrh /* Reset the statement. If the result code is SQLITE_SCHEMA, then 1039fb7e7651Sdrh ** flush the statement cache and try the statement again. 104092febd92Sdrh */ 1041fb7e7651Sdrh rc2 = sqlite3_reset(pStmt); 1042fb7e7651Sdrh if( SQLITE_SCHEMA==rc2 ){ 1043fb7e7651Sdrh /* After a schema change, flush the cache and try to run the 1044fb7e7651Sdrh ** statement again 1045fb7e7651Sdrh */ 1046fb7e7651Sdrh flushStmtCache( pDb ); 1047fb7e7651Sdrh sqlite3_finalize(pStmt); 1048fb7e7651Sdrh if( pPreStmt ) Tcl_Free((char*)pPreStmt); 104930ccda10Sdanielk1977 continue; 1050fb7e7651Sdrh }else if( SQLITE_OK!=rc2 ){ 1051fb7e7651Sdrh /* If a run-time error occurs, report the error and stop reading 1052fb7e7651Sdrh ** the SQL 1053fb7e7651Sdrh */ 1054ef2cb63eSdanielk1977 Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db))); 1055fb7e7651Sdrh sqlite3_finalize(pStmt); 105630ccda10Sdanielk1977 rc = TCL_ERROR; 1057fb7e7651Sdrh if( pPreStmt ) Tcl_Free((char*)pPreStmt); 105830ccda10Sdanielk1977 break; 1059fb7e7651Sdrh }else if( pDb->maxStmt<=0 ){ 1060fb7e7651Sdrh /* If the cache is turned off, deallocated the statement */ 1061fb7e7651Sdrh if( pPreStmt ) Tcl_Free((char*)pPreStmt); 1062fb7e7651Sdrh sqlite3_finalize(pStmt); 1063fb7e7651Sdrh }else{ 1064fb7e7651Sdrh /* Everything worked and the cache is operational. 1065fb7e7651Sdrh ** Create a new SqlPreparedStmt structure if we need one. 1066fb7e7651Sdrh ** (If we already have one we can just reuse it.) 1067fb7e7651Sdrh */ 1068fb7e7651Sdrh if( pPreStmt==0 ){ 1069fb7e7651Sdrh len = zLeft - zSql; 1070fb7e7651Sdrh pPreStmt = (SqlPreparedStmt*)Tcl_Alloc( sizeof(*pPreStmt) + len ); 1071fb7e7651Sdrh if( pPreStmt==0 ) return TCL_ERROR; 1072fb7e7651Sdrh pPreStmt->pStmt = pStmt; 1073fb7e7651Sdrh pPreStmt->nSql = len; 1074fb7e7651Sdrh memcpy(pPreStmt->zSql, zSql, len); 1075fb7e7651Sdrh pPreStmt->zSql[len] = 0; 107630ccda10Sdanielk1977 } 107730ccda10Sdanielk1977 1078fb7e7651Sdrh /* Add the prepared statement to the beginning of the cache list 1079fb7e7651Sdrh */ 1080fb7e7651Sdrh pPreStmt->pNext = pDb->stmtList; 1081fb7e7651Sdrh pPreStmt->pPrev = 0; 1082fb7e7651Sdrh if( pDb->stmtList ){ 1083fb7e7651Sdrh pDb->stmtList->pPrev = pPreStmt; 1084fb7e7651Sdrh } 1085fb7e7651Sdrh pDb->stmtList = pPreStmt; 1086fb7e7651Sdrh if( pDb->stmtLast==0 ){ 1087fb7e7651Sdrh assert( pDb->nStmt==0 ); 1088fb7e7651Sdrh pDb->stmtLast = pPreStmt; 1089fb7e7651Sdrh }else{ 1090fb7e7651Sdrh assert( pDb->nStmt>0 ); 1091fb7e7651Sdrh } 1092fb7e7651Sdrh pDb->nStmt++; 1093fb7e7651Sdrh 1094fb7e7651Sdrh /* If we have too many statement in cache, remove the surplus from the 1095fb7e7651Sdrh ** end of the cache list. 1096fb7e7651Sdrh */ 1097fb7e7651Sdrh while( pDb->nStmt>pDb->maxStmt ){ 1098fb7e7651Sdrh sqlite3_finalize(pDb->stmtLast->pStmt); 1099fb7e7651Sdrh pDb->stmtLast = pDb->stmtLast->pPrev; 1100fb7e7651Sdrh Tcl_Free((char*)pDb->stmtLast->pNext); 1101fb7e7651Sdrh pDb->stmtLast->pNext = 0; 1102fb7e7651Sdrh pDb->nStmt--; 1103fb7e7651Sdrh } 1104fb7e7651Sdrh } 1105fb7e7651Sdrh 1106fb7e7651Sdrh /* Proceed to the next statement */ 110730ccda10Sdanielk1977 zSql = zLeft; 110830ccda10Sdanielk1977 } 11091d895039Sdrh Tcl_DecrRefCount(objv[2]); 111030ccda10Sdanielk1977 11111807ce37Sdrh if( pRet ){ 1112ef2cb63eSdanielk1977 if( rc==TCL_OK ){ 111330ccda10Sdanielk1977 Tcl_SetObjResult(interp, pRet); 111430ccda10Sdanielk1977 } 1115ef2cb63eSdanielk1977 Tcl_DecrRefCount(pRet); 11161807ce37Sdrh } 111730ccda10Sdanielk1977 break; 111830ccda10Sdanielk1977 } 1119bec3f402Sdrh 1120bec3f402Sdrh /* 1121cabb0819Sdrh ** $db function NAME SCRIPT 1122cabb0819Sdrh ** 1123cabb0819Sdrh ** Create a new SQL function called NAME. Whenever that function is 1124cabb0819Sdrh ** called, invoke SCRIPT to evaluate the function. 1125cabb0819Sdrh */ 1126cabb0819Sdrh case DB_FUNCTION: { 1127cabb0819Sdrh SqlFunc *pFunc; 1128cabb0819Sdrh char *zName; 1129cabb0819Sdrh char *zScript; 1130cabb0819Sdrh int nScript; 1131cabb0819Sdrh if( objc!=4 ){ 1132cabb0819Sdrh Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT"); 1133cabb0819Sdrh return TCL_ERROR; 1134cabb0819Sdrh } 1135cabb0819Sdrh zName = Tcl_GetStringFromObj(objv[2], 0); 1136cabb0819Sdrh zScript = Tcl_GetStringFromObj(objv[3], &nScript); 1137cabb0819Sdrh pFunc = (SqlFunc*)Tcl_Alloc( sizeof(*pFunc) + nScript + 1 ); 1138cabb0819Sdrh if( pFunc==0 ) return TCL_ERROR; 1139cabb0819Sdrh pFunc->interp = interp; 1140cabb0819Sdrh pFunc->pNext = pDb->pFunc; 1141cabb0819Sdrh pFunc->zScript = (char*)&pFunc[1]; 11420f14e2ebSdrh pDb->pFunc = pFunc; 1143cabb0819Sdrh strcpy(pFunc->zScript, zScript); 1144c8c1158bSdanielk1977 rc = sqlite3_create_function(pDb->db, zName, -1, SQLITE_UTF8, 1145d8123366Sdanielk1977 pFunc, tclSqlFunc, 0, 0); 1146fb7e7651Sdrh if( rc!=SQLITE_OK ){ 1147fb7e7651Sdrh rc = TCL_ERROR; 11489636c4e1Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_errmsg(pDb->db), TCL_VOLATILE); 1149fb7e7651Sdrh }else{ 1150fb7e7651Sdrh /* Must flush any cached statements */ 1151fb7e7651Sdrh flushStmtCache( pDb ); 1152fb7e7651Sdrh } 1153cabb0819Sdrh break; 1154cabb0819Sdrh } 1155cabb0819Sdrh 1156cabb0819Sdrh /* 1157af9ff33aSdrh ** $db last_insert_rowid 1158af9ff33aSdrh ** 1159af9ff33aSdrh ** Return an integer which is the ROWID for the most recent insert. 1160af9ff33aSdrh */ 1161af9ff33aSdrh case DB_LAST_INSERT_ROWID: { 1162af9ff33aSdrh Tcl_Obj *pResult; 1163af9ff33aSdrh int rowid; 1164af9ff33aSdrh if( objc!=2 ){ 1165af9ff33aSdrh Tcl_WrongNumArgs(interp, 2, objv, ""); 1166af9ff33aSdrh return TCL_ERROR; 1167af9ff33aSdrh } 11686f8a503dSdanielk1977 rowid = sqlite3_last_insert_rowid(pDb->db); 1169af9ff33aSdrh pResult = Tcl_GetObjResult(interp); 1170af9ff33aSdrh Tcl_SetIntObj(pResult, rowid); 1171af9ff33aSdrh break; 1172af9ff33aSdrh } 1173af9ff33aSdrh 1174af9ff33aSdrh /* 11751807ce37Sdrh ** The DB_ONECOLUMN method is implemented together with DB_EVAL. 11765d9d7576Sdrh */ 11771807ce37Sdrh 11781807ce37Sdrh /* $db progress ?N CALLBACK? 11791807ce37Sdrh ** 11801807ce37Sdrh ** Invoke the given callback every N virtual machine opcodes while executing 11811807ce37Sdrh ** queries. 11821807ce37Sdrh */ 11831807ce37Sdrh case DB_PROGRESS: { 11841807ce37Sdrh if( objc==2 ){ 11851807ce37Sdrh if( pDb->zProgress ){ 11861807ce37Sdrh Tcl_AppendResult(interp, pDb->zProgress, 0); 11875d9d7576Sdrh } 11881807ce37Sdrh }else if( objc==4 ){ 11891807ce37Sdrh char *zProgress; 11901807ce37Sdrh int len; 11911807ce37Sdrh int N; 11921807ce37Sdrh if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){ 11931807ce37Sdrh return TCL_ERROR; 11941807ce37Sdrh }; 11951807ce37Sdrh if( pDb->zProgress ){ 11961807ce37Sdrh Tcl_Free(pDb->zProgress); 11971807ce37Sdrh } 11981807ce37Sdrh zProgress = Tcl_GetStringFromObj(objv[3], &len); 11991807ce37Sdrh if( zProgress && len>0 ){ 12001807ce37Sdrh pDb->zProgress = Tcl_Alloc( len + 1 ); 12011807ce37Sdrh strcpy(pDb->zProgress, zProgress); 12021807ce37Sdrh }else{ 12031807ce37Sdrh pDb->zProgress = 0; 12041807ce37Sdrh } 12051807ce37Sdrh #ifndef SQLITE_OMIT_PROGRESS_CALLBACK 12061807ce37Sdrh if( pDb->zProgress ){ 12071807ce37Sdrh pDb->interp = interp; 12081807ce37Sdrh sqlite3_progress_handler(pDb->db, N, DbProgressHandler, pDb); 12091807ce37Sdrh }else{ 12101807ce37Sdrh sqlite3_progress_handler(pDb->db, 0, 0, 0); 12111807ce37Sdrh } 12121807ce37Sdrh #endif 12131807ce37Sdrh }else{ 12141807ce37Sdrh Tcl_WrongNumArgs(interp, 2, objv, "N CALLBACK"); 12151807ce37Sdrh return TCL_ERROR; 12165d9d7576Sdrh } 12175d9d7576Sdrh break; 12185d9d7576Sdrh } 12195d9d7576Sdrh 12205d9d7576Sdrh /* 122122fbcb8dSdrh ** $db rekey KEY 122222fbcb8dSdrh ** 122322fbcb8dSdrh ** Change the encryption key on the currently open database. 122422fbcb8dSdrh */ 122522fbcb8dSdrh case DB_REKEY: { 122622fbcb8dSdrh int nKey; 122722fbcb8dSdrh void *pKey; 122822fbcb8dSdrh if( objc!=3 ){ 122922fbcb8dSdrh Tcl_WrongNumArgs(interp, 2, objv, "KEY"); 123022fbcb8dSdrh return TCL_ERROR; 123122fbcb8dSdrh } 123222fbcb8dSdrh pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey); 12339eb9e26bSdrh #ifdef SQLITE_HAS_CODEC 12342011d5f5Sdrh rc = sqlite3_rekey(pDb->db, pKey, nKey); 123522fbcb8dSdrh if( rc ){ 1236f20b21c8Sdanielk1977 Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0); 123722fbcb8dSdrh rc = TCL_ERROR; 123822fbcb8dSdrh } 123922fbcb8dSdrh #endif 124022fbcb8dSdrh break; 124122fbcb8dSdrh } 124222fbcb8dSdrh 124322fbcb8dSdrh /* 1244bec3f402Sdrh ** $db timeout MILLESECONDS 1245bec3f402Sdrh ** 1246bec3f402Sdrh ** Delay for the number of milliseconds specified when a file is locked. 1247bec3f402Sdrh */ 12486d31316cSdrh case DB_TIMEOUT: { 1249bec3f402Sdrh int ms; 12506d31316cSdrh if( objc!=3 ){ 12516d31316cSdrh Tcl_WrongNumArgs(interp, 2, objv, "MILLISECONDS"); 1252bec3f402Sdrh return TCL_ERROR; 125375897234Sdrh } 12546d31316cSdrh if( Tcl_GetIntFromObj(interp, objv[2], &ms) ) return TCL_ERROR; 12556f8a503dSdanielk1977 sqlite3_busy_timeout(pDb->db, ms); 12566d31316cSdrh break; 125775897234Sdrh } 1258b5a20d3cSdrh 12590f14e2ebSdrh /* 1260*55c45f2eSdanielk1977 ** $db nullvalue ?STRING? 1261*55c45f2eSdanielk1977 ** 1262*55c45f2eSdanielk1977 ** Change text used when a NULL comes back from the database. If ?STRING? 1263*55c45f2eSdanielk1977 ** is not present, then the current string used for NULL is returned. 1264*55c45f2eSdanielk1977 ** If STRING is present, then STRING is returned. 1265*55c45f2eSdanielk1977 ** 1266*55c45f2eSdanielk1977 */ 1267*55c45f2eSdanielk1977 case DB_NULLVALUE: { 1268*55c45f2eSdanielk1977 if( objc!=2 && objc!=3 ){ 1269*55c45f2eSdanielk1977 Tcl_WrongNumArgs(interp, 2, objv, "NULLVALUE"); 1270*55c45f2eSdanielk1977 return TCL_ERROR; 1271*55c45f2eSdanielk1977 } 1272*55c45f2eSdanielk1977 if( objc==3 ){ 1273*55c45f2eSdanielk1977 int len; 1274*55c45f2eSdanielk1977 char *zNull = Tcl_GetStringFromObj(objv[2], &len); 1275*55c45f2eSdanielk1977 if( pDb->zNull ){ 1276*55c45f2eSdanielk1977 Tcl_Free(pDb->zNull); 1277*55c45f2eSdanielk1977 } 1278*55c45f2eSdanielk1977 if( zNull && len>0 ){ 1279*55c45f2eSdanielk1977 pDb->zNull = Tcl_Alloc( len + 1 ); 1280*55c45f2eSdanielk1977 strncpy(pDb->zNull, zNull, len); 1281*55c45f2eSdanielk1977 pDb->zNull[len] = '\0'; 1282*55c45f2eSdanielk1977 }else{ 1283*55c45f2eSdanielk1977 pDb->zNull = 0; 1284*55c45f2eSdanielk1977 } 1285*55c45f2eSdanielk1977 } 1286*55c45f2eSdanielk1977 Tcl_SetObjResult(interp, dbTextToObj(pDb->zNull)); 1287*55c45f2eSdanielk1977 break; 1288*55c45f2eSdanielk1977 } 1289*55c45f2eSdanielk1977 1290*55c45f2eSdanielk1977 /* 12910f14e2ebSdrh ** $db total_changes 12920f14e2ebSdrh ** 12930f14e2ebSdrh ** Return the number of rows that were modified, inserted, or deleted 12940f14e2ebSdrh ** since the database handle was created. 12950f14e2ebSdrh */ 12960f14e2ebSdrh case DB_TOTAL_CHANGES: { 12970f14e2ebSdrh Tcl_Obj *pResult; 12980f14e2ebSdrh if( objc!=2 ){ 12990f14e2ebSdrh Tcl_WrongNumArgs(interp, 2, objv, ""); 13000f14e2ebSdrh return TCL_ERROR; 13010f14e2ebSdrh } 13020f14e2ebSdrh pResult = Tcl_GetObjResult(interp); 13030f14e2ebSdrh Tcl_SetIntObj(pResult, sqlite3_total_changes(pDb->db)); 13040f14e2ebSdrh break; 13050f14e2ebSdrh } 13060f14e2ebSdrh 1307b5a20d3cSdrh /* $db trace ?CALLBACK? 1308b5a20d3cSdrh ** 1309b5a20d3cSdrh ** Make arrangements to invoke the CALLBACK routine for each SQL statement 1310b5a20d3cSdrh ** that is executed. The text of the SQL is appended to CALLBACK before 1311b5a20d3cSdrh ** it is executed. 1312b5a20d3cSdrh */ 1313b5a20d3cSdrh case DB_TRACE: { 1314b5a20d3cSdrh if( objc>3 ){ 1315b5a20d3cSdrh Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); 1316b97759edSdrh return TCL_ERROR; 1317b5a20d3cSdrh }else if( objc==2 ){ 1318b5a20d3cSdrh if( pDb->zTrace ){ 1319b5a20d3cSdrh Tcl_AppendResult(interp, pDb->zTrace, 0); 1320b5a20d3cSdrh } 1321b5a20d3cSdrh }else{ 1322b5a20d3cSdrh char *zTrace; 1323b5a20d3cSdrh int len; 1324b5a20d3cSdrh if( pDb->zTrace ){ 1325b5a20d3cSdrh Tcl_Free(pDb->zTrace); 1326b5a20d3cSdrh } 1327b5a20d3cSdrh zTrace = Tcl_GetStringFromObj(objv[2], &len); 1328b5a20d3cSdrh if( zTrace && len>0 ){ 1329b5a20d3cSdrh pDb->zTrace = Tcl_Alloc( len + 1 ); 1330b5a20d3cSdrh strcpy(pDb->zTrace, zTrace); 1331b5a20d3cSdrh }else{ 1332b5a20d3cSdrh pDb->zTrace = 0; 1333b5a20d3cSdrh } 1334b5a20d3cSdrh if( pDb->zTrace ){ 1335b5a20d3cSdrh pDb->interp = interp; 13366f8a503dSdanielk1977 sqlite3_trace(pDb->db, DbTraceHandler, pDb); 1337b5a20d3cSdrh }else{ 13386f8a503dSdanielk1977 sqlite3_trace(pDb->db, 0, 0); 1339b5a20d3cSdrh } 1340b5a20d3cSdrh } 1341b5a20d3cSdrh break; 1342b5a20d3cSdrh } 1343b5a20d3cSdrh 13441067fe11Stpoindex /* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR? 13451067fe11Stpoindex ** 13461067fe11Stpoindex ** Copy data into table from filename, optionally using SEPARATOR 13471067fe11Stpoindex ** as column separators. If a column contains a null string, or the 13481067fe11Stpoindex ** value of NULLINDICATOR, a NULL is inserted for the column. 13491067fe11Stpoindex ** conflict-algorithm is one of the sqlite conflict algorithms: 13501067fe11Stpoindex ** rollback, abort, fail, ignore, replace 13511067fe11Stpoindex ** On success, return the number of lines processed, not necessarily same 13521067fe11Stpoindex ** as 'db changes' due to conflict-algorithm selected. 13531067fe11Stpoindex ** 13541067fe11Stpoindex ** This code is basically an implementation/enhancement of 13551067fe11Stpoindex ** the sqlite3 shell.c ".import" command. 13561067fe11Stpoindex ** 13571067fe11Stpoindex ** This command usage is equivalent to the sqlite2.x COPY statement, 13581067fe11Stpoindex ** which imports file data into a table using the PostgreSQL COPY file format: 13591067fe11Stpoindex ** $db copy $conflit_algo $table_name $filename \t \\N 13601067fe11Stpoindex */ 13611067fe11Stpoindex case DB_COPY: { 13621067fe11Stpoindex char *zTable; /* Insert data into this table */ 13631067fe11Stpoindex char *zFile; /* The file from which to extract data */ 13641067fe11Stpoindex char *zConflict; /* The conflict algorithm to use */ 13651067fe11Stpoindex sqlite3_stmt *pStmt; /* A statement */ 13661067fe11Stpoindex int rc; /* Result code */ 13671067fe11Stpoindex int nCol; /* Number of columns in the table */ 13681067fe11Stpoindex int nByte; /* Number of bytes in an SQL string */ 13691067fe11Stpoindex int i, j; /* Loop counters */ 13701067fe11Stpoindex int nSep; /* Number of bytes in zSep[] */ 13711067fe11Stpoindex int nNull; /* Number of bytes in zNull[] */ 13721067fe11Stpoindex char *zSql; /* An SQL statement */ 13731067fe11Stpoindex char *zLine; /* A single line of input from the file */ 13741067fe11Stpoindex char **azCol; /* zLine[] broken up into columns */ 13751067fe11Stpoindex char *zCommit; /* How to commit changes */ 13761067fe11Stpoindex FILE *in; /* The input file */ 13771067fe11Stpoindex int lineno = 0; /* Line number of input file */ 13781067fe11Stpoindex char zLineNum[80]; /* Line number print buffer */ 13791067fe11Stpoindex Tcl_Obj *pResult; /* interp result */ 13801067fe11Stpoindex 13819ee3cdcbSdrh char *zSep; 13829ee3cdcbSdrh char *zNull; 13839ee3cdcbSdrh if( objc<5 || objc>7 ){ 13849ee3cdcbSdrh Tcl_WrongNumArgs(interp, 2, objv, 13859ee3cdcbSdrh "CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?"); 13869ee3cdcbSdrh return TCL_ERROR; 13879ee3cdcbSdrh } 13889ee3cdcbSdrh if( objc>=6 ){ 13899ee3cdcbSdrh zSep = Tcl_GetStringFromObj(objv[5], 0); 13909ee3cdcbSdrh }else{ 13919ee3cdcbSdrh zSep = "\t"; 13929ee3cdcbSdrh } 13939ee3cdcbSdrh if( objc>=7 ){ 13949ee3cdcbSdrh zNull = Tcl_GetStringFromObj(objv[6], 0); 13959ee3cdcbSdrh }else{ 13969ee3cdcbSdrh zNull = ""; 13979ee3cdcbSdrh } 13981067fe11Stpoindex zConflict = Tcl_GetStringFromObj(objv[2], 0); 13991067fe11Stpoindex zTable = Tcl_GetStringFromObj(objv[3], 0); 14001067fe11Stpoindex zFile = Tcl_GetStringFromObj(objv[4], 0); 14011067fe11Stpoindex nSep = strlen(zSep); 14021067fe11Stpoindex nNull = strlen(zNull); 14031067fe11Stpoindex if( nSep==0 ){ 14041067fe11Stpoindex Tcl_AppendResult(interp, "Error: non-null separator required for copy", 0); 14051067fe11Stpoindex return TCL_ERROR; 14061067fe11Stpoindex } 14071067fe11Stpoindex if(sqlite3StrICmp(zConflict, "rollback") != 0 && 14081067fe11Stpoindex sqlite3StrICmp(zConflict, "abort" ) != 0 && 14091067fe11Stpoindex sqlite3StrICmp(zConflict, "fail" ) != 0 && 14101067fe11Stpoindex sqlite3StrICmp(zConflict, "ignore" ) != 0 && 14111067fe11Stpoindex sqlite3StrICmp(zConflict, "replace" ) != 0 ) { 14129ee3cdcbSdrh Tcl_AppendResult(interp, "Error: \"", zConflict, 14139ee3cdcbSdrh "\", conflict-algorithm must be one of: rollback, " 14149ee3cdcbSdrh "abort, fail, ignore, or replace", 0); 14151067fe11Stpoindex return TCL_ERROR; 14161067fe11Stpoindex } 14171067fe11Stpoindex zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable); 14181067fe11Stpoindex if( zSql==0 ){ 14191067fe11Stpoindex Tcl_AppendResult(interp, "Error: no such table: ", zTable, 0); 14201067fe11Stpoindex return TCL_ERROR; 14211067fe11Stpoindex } 14221067fe11Stpoindex nByte = strlen(zSql); 14231067fe11Stpoindex rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0); 14241067fe11Stpoindex sqlite3_free(zSql); 14251067fe11Stpoindex if( rc ){ 14261067fe11Stpoindex Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0); 14271067fe11Stpoindex nCol = 0; 14281067fe11Stpoindex }else{ 14291067fe11Stpoindex nCol = sqlite3_column_count(pStmt); 14301067fe11Stpoindex } 14311067fe11Stpoindex sqlite3_finalize(pStmt); 14321067fe11Stpoindex if( nCol==0 ) { 14331067fe11Stpoindex return TCL_ERROR; 14341067fe11Stpoindex } 14351067fe11Stpoindex zSql = malloc( nByte + 50 + nCol*2 ); 14361067fe11Stpoindex if( zSql==0 ) { 14371067fe11Stpoindex Tcl_AppendResult(interp, "Error: can't malloc()", 0); 14381067fe11Stpoindex return TCL_ERROR; 14391067fe11Stpoindex } 14409ee3cdcbSdrh sqlite3_snprintf(nByte+50, zSql, "INSERT OR %q INTO '%q' VALUES(?", 14419ee3cdcbSdrh zConflict, zTable); 14421067fe11Stpoindex j = strlen(zSql); 14431067fe11Stpoindex for(i=1; i<nCol; i++){ 14441067fe11Stpoindex zSql[j++] = ','; 14451067fe11Stpoindex zSql[j++] = '?'; 14461067fe11Stpoindex } 14471067fe11Stpoindex zSql[j++] = ')'; 14481067fe11Stpoindex zSql[j] = 0; 14491067fe11Stpoindex rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0); 14501067fe11Stpoindex free(zSql); 14511067fe11Stpoindex if( rc ){ 14521067fe11Stpoindex Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0); 14531067fe11Stpoindex sqlite3_finalize(pStmt); 14541067fe11Stpoindex return TCL_ERROR; 14551067fe11Stpoindex } 14561067fe11Stpoindex in = fopen(zFile, "rb"); 14571067fe11Stpoindex if( in==0 ){ 14581067fe11Stpoindex Tcl_AppendResult(interp, "Error: cannot open file: ", zFile, NULL); 14591067fe11Stpoindex sqlite3_finalize(pStmt); 14601067fe11Stpoindex return TCL_ERROR; 14611067fe11Stpoindex } 14621067fe11Stpoindex azCol = malloc( sizeof(azCol[0])*(nCol+1) ); 14631067fe11Stpoindex if( azCol==0 ) { 14641067fe11Stpoindex Tcl_AppendResult(interp, "Error: can't malloc()", 0); 14651067fe11Stpoindex return TCL_ERROR; 14661067fe11Stpoindex } 14671067fe11Stpoindex sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0); 14681067fe11Stpoindex zCommit = "COMMIT"; 14691067fe11Stpoindex while( (zLine = local_getline(0, in))!=0 ){ 14701067fe11Stpoindex char *z; 14711067fe11Stpoindex i = 0; 14721067fe11Stpoindex lineno++; 14731067fe11Stpoindex azCol[0] = zLine; 14741067fe11Stpoindex for(i=0, z=zLine; *z; z++){ 14751067fe11Stpoindex if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){ 14761067fe11Stpoindex *z = 0; 14771067fe11Stpoindex i++; 14781067fe11Stpoindex if( i<nCol ){ 14791067fe11Stpoindex azCol[i] = &z[nSep]; 14801067fe11Stpoindex z += nSep-1; 14811067fe11Stpoindex } 14821067fe11Stpoindex } 14831067fe11Stpoindex } 14841067fe11Stpoindex if( i+1!=nCol ){ 14851067fe11Stpoindex char *zErr; 14861067fe11Stpoindex zErr = malloc(200 + strlen(zFile)); 14871067fe11Stpoindex sprintf(zErr,"Error: %s line %d: expected %d columns of data but found %d", 14881067fe11Stpoindex zFile, lineno, nCol, i+1); 14891067fe11Stpoindex Tcl_AppendResult(interp, zErr, 0); 14901067fe11Stpoindex free(zErr); 14911067fe11Stpoindex zCommit = "ROLLBACK"; 14921067fe11Stpoindex break; 14931067fe11Stpoindex } 14941067fe11Stpoindex for(i=0; i<nCol; i++){ 14951067fe11Stpoindex /* check for null data, if so, bind as null */ 14961067fe11Stpoindex if ((nNull>0 && strcmp(azCol[i], zNull)==0) || strlen(azCol[i])==0) { 14971067fe11Stpoindex sqlite3_bind_null(pStmt, i+1); 14981067fe11Stpoindex }else{ 14991067fe11Stpoindex sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC); 15001067fe11Stpoindex } 15011067fe11Stpoindex } 15021067fe11Stpoindex sqlite3_step(pStmt); 15031067fe11Stpoindex rc = sqlite3_reset(pStmt); 15041067fe11Stpoindex free(zLine); 15051067fe11Stpoindex if( rc!=SQLITE_OK ){ 15061067fe11Stpoindex Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), 0); 15071067fe11Stpoindex zCommit = "ROLLBACK"; 15081067fe11Stpoindex break; 15091067fe11Stpoindex } 15101067fe11Stpoindex } 15111067fe11Stpoindex free(azCol); 15121067fe11Stpoindex fclose(in); 15131067fe11Stpoindex sqlite3_finalize(pStmt); 15141067fe11Stpoindex sqlite3_exec(pDb->db, zCommit, 0, 0, 0); 15151067fe11Stpoindex 15161067fe11Stpoindex if( zCommit[0] == 'C' ){ 15171067fe11Stpoindex /* success, set result as number of lines processed */ 15181067fe11Stpoindex pResult = Tcl_GetObjResult(interp); 15191067fe11Stpoindex Tcl_SetIntObj(pResult, lineno); 15201067fe11Stpoindex rc = TCL_OK; 15211067fe11Stpoindex }else{ 15221067fe11Stpoindex /* failure, append lineno where failed */ 15231067fe11Stpoindex sprintf(zLineNum,"%d",lineno); 15241067fe11Stpoindex Tcl_AppendResult(interp,", failed while processing line: ",zLineNum,0); 15251067fe11Stpoindex rc = TCL_ERROR; 15261067fe11Stpoindex } 15271067fe11Stpoindex break; 15281067fe11Stpoindex } 15291067fe11Stpoindex 15304397de57Sdanielk1977 /* $db version 15314397de57Sdanielk1977 ** 15324397de57Sdanielk1977 ** Return the version string for this database. 15334397de57Sdanielk1977 */ 15344397de57Sdanielk1977 case DB_VERSION: { 15354397de57Sdanielk1977 Tcl_SetResult(interp, (char *)sqlite3_libversion(), TCL_STATIC); 15364397de57Sdanielk1977 break; 15374397de57Sdanielk1977 } 15384397de57Sdanielk1977 15391067fe11Stpoindex 15406d31316cSdrh } /* End of the SWITCH statement */ 154122fbcb8dSdrh return rc; 154275897234Sdrh } 154375897234Sdrh 154475897234Sdrh /* 15459bb575fdSdrh ** sqlite3 DBNAME FILENAME ?MODE? ?-key KEY? 154675897234Sdrh ** 154775897234Sdrh ** This is the main Tcl command. When the "sqlite" Tcl command is 154875897234Sdrh ** invoked, this routine runs to process that command. 154975897234Sdrh ** 155075897234Sdrh ** The first argument, DBNAME, is an arbitrary name for a new 155175897234Sdrh ** database connection. This command creates a new command named 155275897234Sdrh ** DBNAME that is used to control that connection. The database 155375897234Sdrh ** connection is deleted when the DBNAME command is deleted. 155475897234Sdrh ** 155575897234Sdrh ** The second argument is the name of the directory that contains 155675897234Sdrh ** the sqlite database that is to be accessed. 1557fbc3eab8Sdrh ** 1558fbc3eab8Sdrh ** For testing purposes, we also support the following: 1559fbc3eab8Sdrh ** 15609bb575fdSdrh ** sqlite3 -encoding 1561fbc3eab8Sdrh ** 1562fbc3eab8Sdrh ** Return the encoding used by LIKE and GLOB operators. Choices 1563fbc3eab8Sdrh ** are UTF-8 and iso8859. 1564fbc3eab8Sdrh ** 15659bb575fdSdrh ** sqlite3 -version 1566647cb0e1Sdrh ** 1567647cb0e1Sdrh ** Return the version number of the SQLite library. 1568647cb0e1Sdrh ** 15699bb575fdSdrh ** sqlite3 -tcl-uses-utf 1570fbc3eab8Sdrh ** 1571fbc3eab8Sdrh ** Return "1" if compiled with a Tcl uses UTF-8. Return "0" if 1572fbc3eab8Sdrh ** not. Used by tests to make sure the library was compiled 1573fbc3eab8Sdrh ** correctly. 157475897234Sdrh */ 157522fbcb8dSdrh static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ 1576bec3f402Sdrh SqliteDb *p; 157722fbcb8dSdrh void *pKey = 0; 157822fbcb8dSdrh int nKey = 0; 157922fbcb8dSdrh const char *zArg; 158075897234Sdrh char *zErrMsg; 158122fbcb8dSdrh const char *zFile; 158206b2718aSdrh char zBuf[80]; 158322fbcb8dSdrh if( objc==2 ){ 158422fbcb8dSdrh zArg = Tcl_GetStringFromObj(objv[1], 0); 158522fbcb8dSdrh if( strcmp(zArg,"-version")==0 ){ 15866f8a503dSdanielk1977 Tcl_AppendResult(interp,sqlite3_version,0); 1587647cb0e1Sdrh return TCL_OK; 1588647cb0e1Sdrh } 15899eb9e26bSdrh if( strcmp(zArg,"-has-codec")==0 ){ 15909eb9e26bSdrh #ifdef SQLITE_HAS_CODEC 159122fbcb8dSdrh Tcl_AppendResult(interp,"1",0); 159222fbcb8dSdrh #else 159322fbcb8dSdrh Tcl_AppendResult(interp,"0",0); 159422fbcb8dSdrh #endif 159522fbcb8dSdrh return TCL_OK; 159622fbcb8dSdrh } 159722fbcb8dSdrh if( strcmp(zArg,"-tcl-uses-utf")==0 ){ 1598fbc3eab8Sdrh #ifdef TCL_UTF_MAX 1599fbc3eab8Sdrh Tcl_AppendResult(interp,"1",0); 1600fbc3eab8Sdrh #else 1601fbc3eab8Sdrh Tcl_AppendResult(interp,"0",0); 1602fbc3eab8Sdrh #endif 1603fbc3eab8Sdrh return TCL_OK; 1604fbc3eab8Sdrh } 1605fbc3eab8Sdrh } 160622fbcb8dSdrh if( objc==5 || objc==6 ){ 160722fbcb8dSdrh zArg = Tcl_GetStringFromObj(objv[objc-2], 0); 160822fbcb8dSdrh if( strcmp(zArg,"-key")==0 ){ 160922fbcb8dSdrh pKey = Tcl_GetByteArrayFromObj(objv[objc-1], &nKey); 161022fbcb8dSdrh objc -= 2; 161122fbcb8dSdrh } 161222fbcb8dSdrh } 161322fbcb8dSdrh if( objc!=3 && objc!=4 ){ 161422fbcb8dSdrh Tcl_WrongNumArgs(interp, 1, objv, 16159eb9e26bSdrh #ifdef SQLITE_HAS_CODEC 16169eb9e26bSdrh "HANDLE FILENAME ?-key CODEC-KEY?" 161722fbcb8dSdrh #else 161822fbcb8dSdrh "HANDLE FILENAME ?MODE?" 161922fbcb8dSdrh #endif 162022fbcb8dSdrh ); 162175897234Sdrh return TCL_ERROR; 162275897234Sdrh } 162375897234Sdrh zErrMsg = 0; 16244cdc9e84Sdrh p = (SqliteDb*)Tcl_Alloc( sizeof(*p) ); 162575897234Sdrh if( p==0 ){ 1626bec3f402Sdrh Tcl_SetResult(interp, "malloc failed", TCL_STATIC); 1627bec3f402Sdrh return TCL_ERROR; 1628bec3f402Sdrh } 1629bec3f402Sdrh memset(p, 0, sizeof(*p)); 163022fbcb8dSdrh zFile = Tcl_GetStringFromObj(objv[2], 0); 16314f057f90Sdanielk1977 sqlite3_open(zFile, &p->db); 163280290863Sdanielk1977 if( SQLITE_OK!=sqlite3_errcode(p->db) ){ 163380290863Sdanielk1977 zErrMsg = strdup(sqlite3_errmsg(p->db)); 163480290863Sdanielk1977 sqlite3_close(p->db); 163580290863Sdanielk1977 p->db = 0; 163680290863Sdanielk1977 } 16372011d5f5Sdrh #ifdef SQLITE_HAS_CODEC 16382011d5f5Sdrh sqlite3_key(p->db, pKey, nKey); 1639eb8ed70dSdrh #endif 1640bec3f402Sdrh if( p->db==0 ){ 164175897234Sdrh Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE); 1642bec3f402Sdrh Tcl_Free((char*)p); 164375897234Sdrh free(zErrMsg); 164475897234Sdrh return TCL_ERROR; 164575897234Sdrh } 1646fb7e7651Sdrh p->maxStmt = NUM_PREPARED_STMTS; 164722fbcb8dSdrh zArg = Tcl_GetStringFromObj(objv[1], 0); 164822fbcb8dSdrh Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd); 1649c22bd47dSdrh 165006b2718aSdrh /* The return value is the value of the sqlite* pointer 165106b2718aSdrh */ 165206b2718aSdrh sprintf(zBuf, "%p", p->db); 16535e5377fbSdrh if( strncmp(zBuf,"0x",2) ){ 16545e5377fbSdrh sprintf(zBuf, "0x%p", p->db); 16555e5377fbSdrh } 165606b2718aSdrh Tcl_AppendResult(interp, zBuf, 0); 165706b2718aSdrh 1658c22bd47dSdrh /* If compiled with SQLITE_TEST turned on, then register the "md5sum" 165906b2718aSdrh ** SQL function. 1660c22bd47dSdrh */ 166128b4e489Sdrh #ifdef SQLITE_TEST 166228b4e489Sdrh { 16639bb575fdSdrh extern void Md5_Register(sqlite3*); 16643b93bc8cSdrh #ifdef SQLITE_MEMDEBUG 166513073931Sdanielk1977 int mallocfail = sqlite3_iMallocFail; 166613073931Sdanielk1977 sqlite3_iMallocFail = 0; 16675b59af85Sdanielk1977 #endif 166828b4e489Sdrh Md5_Register(p->db); 16693b93bc8cSdrh #ifdef SQLITE_MEMDEBUG 167013073931Sdanielk1977 sqlite3_iMallocFail = mallocfail; 16715b59af85Sdanielk1977 #endif 167228b4e489Sdrh } 167328b4e489Sdrh #endif 16747cedc8d4Sdanielk1977 p->interp = interp; 167575897234Sdrh return TCL_OK; 167675897234Sdrh } 167775897234Sdrh 167875897234Sdrh /* 167990ca9753Sdrh ** Provide a dummy Tcl_InitStubs if we are using this as a static 168090ca9753Sdrh ** library. 168190ca9753Sdrh */ 168290ca9753Sdrh #ifndef USE_TCL_STUBS 168390ca9753Sdrh # undef Tcl_InitStubs 168490ca9753Sdrh # define Tcl_InitStubs(a,b,c) 168590ca9753Sdrh #endif 168690ca9753Sdrh 168790ca9753Sdrh /* 168875897234Sdrh ** Initialize this module. 168975897234Sdrh ** 169075897234Sdrh ** This Tcl module contains only a single new Tcl command named "sqlite". 169175897234Sdrh ** (Hence there is no namespace. There is no point in using a namespace 169275897234Sdrh ** if the extension only supplies one new name!) The "sqlite" command is 169375897234Sdrh ** used to open a new SQLite database. See the DbMain() routine above 169475897234Sdrh ** for additional information. 169575897234Sdrh */ 169638f8271fSdrh int Sqlite3_Init(Tcl_Interp *interp){ 169792febd92Sdrh Tcl_InitStubs(interp, "8.4", 0); 1698ef4ac8f9Sdrh Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0); 1699ef4ac8f9Sdrh Tcl_PkgProvide(interp, "sqlite3", "3.0"); 170049766d6cSdrh Tcl_CreateObjCommand(interp, "sqlite", (Tcl_ObjCmdProc*)DbMain, 0, 0); 170149766d6cSdrh Tcl_PkgProvide(interp, "sqlite", "3.0"); 170290ca9753Sdrh return TCL_OK; 170390ca9753Sdrh } 170449766d6cSdrh int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } 170549766d6cSdrh int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; } 170649766d6cSdrh int Tclsqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; } 170749766d6cSdrh 170849766d6cSdrh #ifndef SQLITE_3_SUFFIX_ONLY 170949766d6cSdrh int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } 171049766d6cSdrh int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); } 171149766d6cSdrh int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; } 171249766d6cSdrh int Tclsqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; } 171349766d6cSdrh #endif 171475897234Sdrh 17153e27c026Sdrh #ifdef TCLSH 17163e27c026Sdrh /***************************************************************************** 17173e27c026Sdrh ** The code that follows is used to build standalone TCL interpreters 171875897234Sdrh */ 1719348784efSdrh 1720348784efSdrh /* 17213e27c026Sdrh ** If the macro TCLSH is one, then put in code this for the 17223e27c026Sdrh ** "main" routine that will initialize Tcl and take input from 17233e27c026Sdrh ** standard input. 1724348784efSdrh */ 17253e27c026Sdrh #if TCLSH==1 1726348784efSdrh static char zMainloop[] = 1727348784efSdrh "set line {}\n" 1728348784efSdrh "while {![eof stdin]} {\n" 1729348784efSdrh "if {$line!=\"\"} {\n" 1730348784efSdrh "puts -nonewline \"> \"\n" 1731348784efSdrh "} else {\n" 1732348784efSdrh "puts -nonewline \"% \"\n" 1733348784efSdrh "}\n" 1734348784efSdrh "flush stdout\n" 1735348784efSdrh "append line [gets stdin]\n" 1736348784efSdrh "if {[info complete $line]} {\n" 1737348784efSdrh "if {[catch {uplevel #0 $line} result]} {\n" 1738348784efSdrh "puts stderr \"Error: $result\"\n" 1739348784efSdrh "} elseif {$result!=\"\"} {\n" 1740348784efSdrh "puts $result\n" 1741348784efSdrh "}\n" 1742348784efSdrh "set line {}\n" 1743348784efSdrh "} else {\n" 1744348784efSdrh "append line \\n\n" 1745348784efSdrh "}\n" 1746348784efSdrh "}\n" 1747348784efSdrh ; 17483e27c026Sdrh #endif 17493e27c026Sdrh 17503e27c026Sdrh /* 17513e27c026Sdrh ** If the macro TCLSH is two, then get the main loop code out of 17523e27c026Sdrh ** the separate file "spaceanal_tcl.h". 17533e27c026Sdrh */ 17543e27c026Sdrh #if TCLSH==2 17553e27c026Sdrh static char zMainloop[] = 17563e27c026Sdrh #include "spaceanal_tcl.h" 17573e27c026Sdrh ; 17583e27c026Sdrh #endif 1759348784efSdrh 1760348784efSdrh #define TCLSH_MAIN main /* Needed to fake out mktclapp */ 1761348784efSdrh int TCLSH_MAIN(int argc, char **argv){ 1762348784efSdrh Tcl_Interp *interp; 1763297ecf14Sdrh Tcl_FindExecutable(argv[0]); 1764348784efSdrh interp = Tcl_CreateInterp(); 176538f8271fSdrh Sqlite3_Init(interp); 1766d9b0257aSdrh #ifdef SQLITE_TEST 1767d1bf3512Sdrh { 1768d1bf3512Sdrh extern int Sqlitetest1_Init(Tcl_Interp*); 17695c4d9703Sdrh extern int Sqlitetest2_Init(Tcl_Interp*); 17705c4d9703Sdrh extern int Sqlitetest3_Init(Tcl_Interp*); 1771a6064dcfSdrh extern int Sqlitetest4_Init(Tcl_Interp*); 1772998b56c3Sdanielk1977 extern int Sqlitetest5_Init(Tcl_Interp*); 1773efc251daSdrh extern int Md5_Init(Tcl_Interp*); 17746490bebdSdanielk1977 Sqlitetest1_Init(interp); 17755c4d9703Sdrh Sqlitetest2_Init(interp); 1776de647130Sdrh Sqlitetest3_Init(interp); 1777fc57d7bfSdanielk1977 Sqlitetest4_Init(interp); 1778998b56c3Sdanielk1977 Sqlitetest5_Init(interp); 1779efc251daSdrh Md5_Init(interp); 1780d1bf3512Sdrh } 1781d1bf3512Sdrh #endif 17823e27c026Sdrh if( argc>=2 || TCLSH==2 ){ 1783348784efSdrh int i; 1784348784efSdrh Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY); 1785348784efSdrh Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY); 178661212b69Sdrh for(i=3-TCLSH; i<argc; i++){ 1787348784efSdrh Tcl_SetVar(interp, "argv", argv[i], 1788348784efSdrh TCL_GLOBAL_ONLY | TCL_LIST_ELEMENT | TCL_APPEND_VALUE); 1789348784efSdrh } 17903e27c026Sdrh if( TCLSH==1 && Tcl_EvalFile(interp, argv[1])!=TCL_OK ){ 17910de8c112Sdrh const char *zInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); 1792c61053b7Sdrh if( zInfo==0 ) zInfo = interp->result; 1793c61053b7Sdrh fprintf(stderr,"%s: %s\n", *argv, zInfo); 1794348784efSdrh return 1; 1795348784efSdrh } 17963e27c026Sdrh } 17973e27c026Sdrh if( argc<=1 || TCLSH==2 ){ 1798348784efSdrh Tcl_GlobalEval(interp, zMainloop); 1799348784efSdrh } 1800348784efSdrh return 0; 1801348784efSdrh } 1802348784efSdrh #endif /* TCLSH */ 18036d31316cSdrh 18046d31316cSdrh #endif /* !defined(NO_TCL) */ 1805