/ Check-in [8db6bfef]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Change the TCL interface so that it can cache VMs and reuse them without recompiling. But for now leave the cache turned off by default. (CVS 2269)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 8db6bfef52c1f35afdb8b60cba34f6807a5917f4
User & Date: drh 2005-01-24 00:28:43
Context
2005-01-24
01:38
Flush the TCL statement cache before each lock_status pragma. (CVS 2270) check-in: 8beae3ff user: drh tags: trunk
00:28
Change the TCL interface so that it can cache VMs and reuse them without recompiling. But for now leave the cache turned off by default. (CVS 2269) check-in: 8db6bfef user: drh tags: trunk
2005-01-23
23:43
Modification to shell.c to avoid a compiler warning on some compilers. (CVS 2268) check-in: 0778383b user: danielk1977 tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/tclsqlite.c.

     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** A TCL Interface to SQLite
    13     13   **
    14         -** $Id: tclsqlite.c,v 1.115 2005/01/13 23:54:32 drh Exp $
           14  +** $Id: tclsqlite.c,v 1.116 2005/01/24 00:28:43 drh Exp $
    15     15   */
    16     16   #ifndef NO_TCL     /* Omit this whole file if TCL is unavailable */
    17     17   
    18     18   #include "sqliteInt.h"
    19     19   #include "hash.h"
    20     20   #include "tcl.h"
    21     21   #include <stdlib.h>
    22     22   #include <string.h>
    23     23   #include <assert.h>
    24     24   
           25  +#define NUM_PREPARED_STMTS 0
           26  +#define MAX_PREPARED_STMTS 100
           27  +
    25     28   /*
    26     29   ** If TCL uses UTF-8 and SQLite is configured to use iso8859, then we
    27     30   ** have to do a translation when going between the two.  Set the 
    28     31   ** UTF_TRANSLATION_NEEDED macro to indicate that we need to do
    29     32   ** this translation.  
    30     33   */
    31     34   #if defined(TCL_UTF_MAX) && !defined(SQLITE_UTF8)
................................................................................
    50     53   typedef struct SqlCollate SqlCollate;
    51     54   struct SqlCollate {
    52     55     Tcl_Interp *interp;   /* The TCL interpret to execute the function */
    53     56     char *zScript;        /* The script to be run */
    54     57     SqlCollate *pNext;       /* Next function on the list of them all */
    55     58   };
    56     59   
           60  +/*
           61  +** Prepared statements are cached for faster execution.  Each prepared
           62  +** statement is described by an instance of the following structure.
           63  +*/
           64  +typedef struct SqlPreparedStmt SqlPreparedStmt;
           65  +struct SqlPreparedStmt {
           66  +  SqlPreparedStmt *pNext;  /* Next in linked list */
           67  +  SqlPreparedStmt *pPrev;  /* Previous on the list */
           68  +  sqlite3_stmt *pStmt;     /* The prepared statement */
           69  +  int nSql;                /* chars in zSql[] */
           70  +  char zSql[1];            /* Text of the SQL statement */
           71  +};
           72  +
    57     73   /*
    58     74   ** There is one instance of this structure for each SQLite database
    59     75   ** that has been opened by the SQLite TCL interface.
    60     76   */
    61     77   typedef struct SqliteDb SqliteDb;
    62     78   struct SqliteDb {
    63     79     sqlite3 *db;          /* The "real" database structure */
................................................................................
    67     83     char *zTrace;         /* The trace callback routine */
    68     84     char *zProgress;      /* The progress callback routine */
    69     85     char *zAuth;          /* The authorization callback routine */
    70     86     SqlFunc *pFunc;       /* List of SQL functions */
    71     87     SqlCollate *pCollate; /* List of SQL collation functions */
    72     88     int rc;               /* Return code of most recent sqlite3_exec() */
    73     89     Tcl_Obj *pCollateNeeded;  /* Collation needed script */
           90  +  SqlPreparedStmt *stmtList; /* List of prepared statements*/
           91  +  SqlPreparedStmt *stmtLast; /* Last statement in the list */
           92  +  int maxStmt;               /* The next maximum number of stmtList */
           93  +  int nStmt;                 /* Number of statements in stmtList */
    74     94   };
           95  +
           96  +/*
           97  +** Finalize and free a list of prepared statements
           98  +*/
           99  +static void flushStmtCache( SqliteDb *pDb ){
          100  +  SqlPreparedStmt *pPreStmt;
          101  +
          102  +  while(  pDb->stmtList ){
          103  +    sqlite3_finalize( pDb->stmtList->pStmt );
          104  +    pPreStmt = pDb->stmtList;
          105  +    pDb->stmtList = pDb->stmtList->pNext;
          106  +    Tcl_Free( (char*)pPreStmt );
          107  +  }
          108  +  pDb->nStmt = 0;
          109  +  pDb->stmtLast = 0;
          110  +}
    75    111   
    76    112   /*
    77    113   ** TCL calls this procedure when an sqlite3 database command is
    78    114   ** deleted.
    79    115   */
    80    116   static void DbDeleteCmd(void *db){
    81    117     SqliteDb *pDb = (SqliteDb*)db;
          118  +  flushStmtCache(pDb);
    82    119     sqlite3_close(pDb->db);
    83    120     while( pDb->pFunc ){
    84    121       SqlFunc *pFunc = pDb->pFunc;
    85    122       pDb->pFunc = pFunc->pNext;
    86    123       Tcl_Free((char*)pFunc);
    87    124     }
    88    125     while( pDb->pCollate ){
................................................................................
   211    248     return (atoi(Tcl_GetStringResult(p->interp)));
   212    249   }
   213    250   
   214    251   /*
   215    252   ** This routine is called to evaluate an SQL function implemented
   216    253   ** using TCL script.
   217    254   */
   218         -static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
          255  +static void tclSqlFunc(sqlite3_context *context, int argc, sqlite3_value**argv){
   219    256     SqlFunc *p = sqlite3_user_data(context);
   220    257     Tcl_DString cmd;
   221    258     int i;
   222    259     int rc;
   223    260   
   224    261     Tcl_DStringInit(&cmd);
   225    262     Tcl_DStringAppend(&cmd, p->zScript, -1);
................................................................................
   396    433   ** subroutine to be invoked.
   397    434   */
   398    435   static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
   399    436     SqliteDb *pDb = (SqliteDb*)cd;
   400    437     int choice;
   401    438     int rc = TCL_OK;
   402    439     static const char *DB_strs[] = {
   403         -    "authorizer",         "busy",              "changes",
   404         -    "close",              "collate",           "collation_needed",
   405         -    "commit_hook",        "complete",          "copy",
   406         -    "errorcode",          "eval",              "function",
   407         -    "last_insert_rowid",  "onecolumn",         "progress",
   408         -    "rekey",              "timeout",           "total_changes",
   409         -    "trace",              "version",
          440  +    "authorizer",         "busy",              "cache",
          441  +    "changes",            "close",             "collate",
          442  +    "collation_needed",   "commit_hook",       "complete",
          443  +    "copy",               "errorcode",         "eval",
          444  +    "function",           "last_insert_rowid", "onecolumn",
          445  +    "progress",           "rekey",             "timeout",
          446  +    "total_changes",      "trace",             "version",
   410    447       0                    
   411    448     };
   412    449     enum DB_enum {
   413         -    DB_AUTHORIZER,        DB_BUSY,             DB_CHANGES,
   414         -    DB_CLOSE,             DB_COLLATE,          DB_COLLATION_NEEDED,
   415         -    DB_COMMIT_HOOK,       DB_COMPLETE,         DB_COPY,
   416         -    DB_ERRORCODE,         DB_EVAL,             DB_FUNCTION,
   417         -    DB_LAST_INSERT_ROWID, DB_ONECOLUMN,        DB_PROGRESS,
   418         -    DB_REKEY,             DB_TIMEOUT,          DB_TOTAL_CHANGES,
   419         -    DB_TRACE,             DB_VERSION
          450  +    DB_AUTHORIZER,        DB_BUSY,             DB_CACHE,
          451  +    DB_CHANGES,           DB_CLOSE,            DB_COLLATE,
          452  +    DB_COLLATION_NEEDED,  DB_COMMIT_HOOK,      DB_COMPLETE,
          453  +    DB_COPY,              DB_ERRORCODE,        DB_EVAL,
          454  +    DB_FUNCTION,          DB_LAST_INSERT_ROWID,DB_ONECOLUMN,
          455  +    DB_PROGRESS,          DB_REKEY,            DB_TIMEOUT,
          456  +    DB_TOTAL_CHANGES,     DB_TRACE,            DB_VERSION
   420    457     };
   421    458     /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
   422    459   
   423    460     if( objc<2 ){
   424    461       Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ...");
   425    462       return TCL_ERROR;
   426    463     }
................................................................................
   515    552           sqlite3_busy_handler(pDb->db, DbBusyHandler, pDb);
   516    553         }else{
   517    554           sqlite3_busy_handler(pDb->db, 0, 0);
   518    555         }
   519    556       }
   520    557       break;
   521    558     }
          559  +
          560  +  /*     $db cache flush
          561  +  **     $db cache size n
          562  +  **
          563  +  ** Flush the prepared statement cache, or set the maximum number of
          564  +  ** cached statements.
          565  +  */
          566  +  case DB_CACHE: {
          567  +    char *subCmd;
          568  +    int n;
          569  +
          570  +    if( objc<=2 ){
          571  +      Tcl_WrongNumArgs(interp, 1, objv, "cache option ?arg?");
          572  +      return TCL_ERROR;
          573  +    }
          574  +    subCmd = Tcl_GetStringFromObj( objv[2], 0 );
          575  +    if( *subCmd=='f' && strcmp(subCmd,"flush")==0 ){
          576  +      if( objc!=3 ){
          577  +        Tcl_WrongNumArgs(interp, 2, objv, "flush");
          578  +        return TCL_ERROR;
          579  +      }else{
          580  +        flushStmtCache( pDb );
          581  +      }
          582  +    }else if( *subCmd=='s' && strcmp(subCmd,"size")==0 ){
          583  +      if( objc!=4 ){
          584  +        Tcl_WrongNumArgs(interp, 2, objv, "size n");
          585  +        return TCL_ERROR;
          586  +      }else{
          587  +        if( TCL_ERROR==Tcl_GetIntFromObj(interp, objv[3], &n) ){
          588  +          Tcl_AppendResult( interp, "cannot convert \"", 
          589  +               Tcl_GetStringFromObj(objv[3],0), "\" to integer", 0);
          590  +          return TCL_ERROR;
          591  +        }else{
          592  +          if( n<0 ){
          593  +            flushStmtCache( pDb );
          594  +            n = 0;
          595  +          }else if( n>MAX_PREPARED_STMTS ){
          596  +            n = MAX_PREPARED_STMTS;
          597  +          }
          598  +          pDb->maxStmt = n;
          599  +        }
          600  +      }
          601  +    }else{
          602  +      Tcl_AppendResult( interp, "bad option \"", 
          603  +          Tcl_GetStringFromObj(objv[0],0), "\": must be flush or size", 0);
          604  +      return TCL_ERROR;
          605  +    }
          606  +    break;
          607  +  }
   522    608   
   523    609     /*     $db changes
   524    610     **
   525    611     ** Return the number of rows that were modified, inserted, or deleted by
   526    612     ** the most recent INSERT, UPDATE or DELETE statement, not including 
   527    613     ** any changes made by trigger programs.
   528    614     */
................................................................................
   685    771       sqlite3_stmt *pStmt;   /* Compiled SQL statment */
   686    772       Tcl_Obj *pArray;       /* Name of array into which results are written */
   687    773       Tcl_Obj *pScript;      /* Script to run for each result set */
   688    774       Tcl_Obj **apParm;      /* Parameters that need a Tcl_DecrRefCount() */
   689    775       int nParm;             /* Number of entries used in apParm[] */
   690    776       Tcl_Obj *aParm[10];    /* Static space for apParm[] in the common case */
   691    777       Tcl_Obj *pRet;         /* Value to be returned */
          778  +    SqlPreparedStmt *pPreStmt;  /* Pointer to a prepared statement */
          779  +    int rc2;
   692    780   
   693    781       if( choice==DB_ONECOLUMN ){
   694    782         if( objc!=3 ){
   695    783           Tcl_WrongNumArgs(interp, 2, objv, "SQL");
   696    784           return TCL_ERROR;
   697    785         }
   698    786         pRet = 0;
................................................................................
   714    802         if( Tcl_GetString(pArray)[0]==0 ) pArray = 0;
   715    803         pScript = objv[4];
   716    804       }
   717    805   
   718    806       Tcl_IncrRefCount(objv[2]);
   719    807       zSql = Tcl_GetStringFromObj(objv[2], 0);
   720    808       while( rc==TCL_OK && zSql[0] ){
   721         -      int i;      /* Loop counter */
   722         -      int nVar;   /* Number of wildcards in the SQL */
   723         -      int nCol;   /* Number of columns in the result set */
          809  +      int i;                     /* Loop counter */
          810  +      int nVar;                  /* Number of bind parameters in the pStmt */
          811  +      int nCol;                  /* Number of columns in the result set */
   724    812         Tcl_Obj **apColName = 0;   /* Array of column names */
          813  +      int len;                   /* String length of zSql */
          814  +  
          815  +      /* Try to find a SQL statement that has already been compiled and
          816  +      ** which matches the next sequence of SQL.
          817  +      */
          818  +      pStmt = 0;
          819  +      pPreStmt = pDb->stmtList;
          820  +      len = strlen(zSql);
          821  +      if( pPreStmt && sqlite3_expired(pPreStmt->pStmt) ){
          822  +        flushStmtCache(pDb);
          823  +        pPreStmt = 0;
          824  +      }
          825  +      for(; pPreStmt; pPreStmt=pPreStmt->pNext){
          826  +        int n = pPreStmt->nSql;
          827  +        if( len>=n 
          828  +            && memcmp(pPreStmt->zSql, zSql, n)==0
          829  +            && (zSql[n]==0 || zSql[n-1]==';')
          830  +        ){
          831  +          pStmt = pPreStmt->pStmt;
          832  +          zLeft = &zSql[pPreStmt->nSql];
          833  +
          834  +          /* When a prepared statement is found, unlink it from the
          835  +          ** cache list.  It will later be added back to the beginning
          836  +          ** of the cache list in order to implement LRU replacement.
          837  +          */
          838  +          if( pPreStmt->pPrev ){
          839  +            pPreStmt->pPrev->pNext = pPreStmt->pNext;
          840  +          }else{
          841  +            pDb->stmtList = pPreStmt->pNext;
          842  +          }
          843  +          if( pPreStmt->pNext ){
          844  +            pPreStmt->pNext->pPrev = pPreStmt->pPrev;
          845  +          }else{
          846  +            pDb->stmtLast = pPreStmt->pPrev;
          847  +          }
          848  +          pDb->nStmt--;
          849  +          break;
          850  +        }
          851  +      }
   725    852     
   726         -      /* Compile a single SQL statement */
   727         -      if( SQLITE_OK!=sqlite3_prepare(pDb->db, zSql, -1, &pStmt, &zLeft) ){
   728         -        Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
   729         -        rc = TCL_ERROR;
   730         -        break;
   731         -      }
          853  +      /* If no prepared statement was found.  Compile the SQL text
          854  +      */
   732    855         if( pStmt==0 ){
   733         -        if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){
          856  +        if( SQLITE_OK!=sqlite3_prepare(pDb->db, zSql, -1, &pStmt, &zLeft) ){
   734    857             Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
   735    858             rc = TCL_ERROR;
   736    859             break;
   737         -        }else{
   738         -          zSql = zLeft;
   739         -          continue;
   740    860           }
          861  +        if( pStmt==0 ){
          862  +          if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){
          863  +            /* A compile-time error in the statement
          864  +            */
          865  +            Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
          866  +            rc = TCL_ERROR;
          867  +            break;
          868  +          }else{
          869  +            /* The statement was a no-op.  Continue to the next statement
          870  +            ** in the SQL string.
          871  +            */
          872  +            zSql = zLeft;
          873  +            continue;
          874  +          }
          875  +        }
          876  +        assert( pPreStmt==0 );
   741    877         }
   742    878   
   743         -      /* Bind values to wildcards that begin with $ or : */  
          879  +      /* Bind values to parameters that begin with $ or :
          880  +      */  
   744    881         nVar = sqlite3_bind_parameter_count(pStmt);
   745    882         nParm = 0;
   746    883         if( nVar>sizeof(aParm)/sizeof(aParm[0]) ){
   747    884           apParm = (Tcl_Obj**)Tcl_Alloc(nVar*sizeof(apParm[0]));
   748    885         }else{
   749    886           apParm = aParm;
   750    887         }
................................................................................
   772    909                 sqlite3_bind_double(pStmt, i, r);
   773    910               }else{
   774    911                 data = Tcl_GetStringFromObj(pVar, &n);
   775    912                 sqlite3_bind_text(pStmt, i, data, n, SQLITE_STATIC);
   776    913                 Tcl_IncrRefCount(pVar);
   777    914                 apParm[nParm++] = pVar;
   778    915               }
          916  +          }else{
          917  +            sqlite3_bind_null( pStmt, i );
   779    918             }
   780    919           }
   781    920         }
   782    921   
   783    922         /* Compute column names */
   784    923         nCol = sqlite3_column_count(pStmt);
   785    924         if( pScript ){
................................................................................
   876   1015         for(i=0; i<nParm; i++){
   877   1016           Tcl_DecrRefCount(apParm[i]);
   878   1017         }
   879   1018         if( apParm!=aParm ){
   880   1019           Tcl_Free((char*)apParm);
   881   1020         }
   882   1021   
   883         -      /* Finalize the statement.  If the result code is SQLITE_SCHEMA, then
   884         -      ** try again to execute the same statement
         1022  +      /* Reset the statement.  If the result code is SQLITE_SCHEMA, then
         1023  +      ** flush the statement cache and try the statement again.
   885   1024         */
   886         -      if( SQLITE_SCHEMA==sqlite3_finalize(pStmt) ){
         1025  +      rc2 = sqlite3_reset(pStmt);
         1026  +      if( SQLITE_SCHEMA==rc2 ){
         1027  +        /* After a schema change, flush the cache and try to run the
         1028  +        ** statement again
         1029  +        */
         1030  +        flushStmtCache( pDb );
         1031  +        sqlite3_finalize(pStmt);
         1032  +        if( pPreStmt ) Tcl_Free((char*)pPreStmt);
   887   1033           continue;
   888         -      }
   889         -  
   890         -      if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){
         1034  +      }else if( SQLITE_OK!=rc2 ){
         1035  +        /* If a run-time error occurs, report the error and stop reading
         1036  +        ** the SQL
         1037  +        */
   891   1038           Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
         1039  +        sqlite3_finalize(pStmt);
   892   1040           rc = TCL_ERROR;
         1041  +        if( pPreStmt ) Tcl_Free((char*)pPreStmt);
   893   1042           break;
         1043  +      }else if( pDb->maxStmt<=0 ){
         1044  +        /* If the cache is turned off, deallocated the statement */
         1045  +        if( pPreStmt ) Tcl_Free((char*)pPreStmt);
         1046  +        sqlite3_finalize(pStmt);
         1047  +      }else{
         1048  +        /* Everything worked and the cache is operational.
         1049  +        ** Create a new SqlPreparedStmt structure if we need one.
         1050  +        ** (If we already have one we can just reuse it.)
         1051  +        */
         1052  +        if( pPreStmt==0 ){
         1053  +          len = zLeft - zSql;
         1054  +          pPreStmt = (SqlPreparedStmt*)Tcl_Alloc( sizeof(*pPreStmt) + len );
         1055  +          if( pPreStmt==0 ) return TCL_ERROR;
         1056  +          pPreStmt->pStmt = pStmt;
         1057  +          pPreStmt->nSql = len;
         1058  +          memcpy(pPreStmt->zSql, zSql, len);
         1059  +          pPreStmt->zSql[len] = 0;
         1060  +        }
         1061  +
         1062  +        /* Add the prepared statement to the beginning of the cache list
         1063  +        */
         1064  +        pPreStmt->pNext = pDb->stmtList;
         1065  +        pPreStmt->pPrev = 0;
         1066  +        if( pDb->stmtList ){
         1067  +         pDb->stmtList->pPrev = pPreStmt;
         1068  +        }
         1069  +        pDb->stmtList = pPreStmt;
         1070  +        if( pDb->stmtLast==0 ){
         1071  +          assert( pDb->nStmt==0 );
         1072  +          pDb->stmtLast = pPreStmt;
         1073  +        }else{
         1074  +          assert( pDb->nStmt>0 );
         1075  +        }
         1076  +        pDb->nStmt++;
         1077  +   
         1078  +        /* If we have too many statement in cache, remove the surplus from the
         1079  +        ** end of the cache list.
         1080  +        */
         1081  +        while( pDb->nStmt>pDb->maxStmt ){
         1082  +          sqlite3_finalize(pDb->stmtLast->pStmt);
         1083  +          pDb->stmtLast = pDb->stmtLast->pPrev;
         1084  +          Tcl_Free((char*)pDb->stmtLast->pNext);
         1085  +          pDb->stmtLast->pNext = 0;
         1086  +          pDb->nStmt--;
         1087  +        }
   894   1088         }
   895   1089   
         1090  +      /* Proceed to the next statement */
   896   1091         zSql = zLeft;
   897   1092       }
   898   1093       Tcl_DecrRefCount(objv[2]);
   899   1094   
   900   1095       if( pRet ){
   901   1096         if( rc==TCL_OK ){
   902   1097           Tcl_SetObjResult(interp, pRet);
................................................................................
   928   1123       pFunc->interp = interp;
   929   1124       pFunc->pNext = pDb->pFunc;
   930   1125       pFunc->zScript = (char*)&pFunc[1];
   931   1126       pDb->pFunc = pFunc;
   932   1127       strcpy(pFunc->zScript, zScript);
   933   1128       rc = sqlite3_create_function(pDb->db, zName, -1, SQLITE_UTF8,
   934   1129           pFunc, tclSqlFunc, 0, 0);
   935         -    if( rc!=SQLITE_OK ) rc = TCL_ERROR;
         1130  +    if( rc!=SQLITE_OK ){
         1131  +       rc = TCL_ERROR;
         1132  +    }else{
         1133  +      /* Must flush any cached statements */
         1134  +      flushStmtCache( pDb );
         1135  +    }
   936   1136       break;
   937   1137     }
   938   1138   
   939   1139     /*
   940   1140     **     $db last_insert_rowid 
   941   1141     **
   942   1142     ** Return an integer which is the ROWID for the most recent insert.
................................................................................
  1391   1591   #endif
  1392   1592     if( p->db==0 ){
  1393   1593       Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
  1394   1594       Tcl_Free((char*)p);
  1395   1595       free(zErrMsg);
  1396   1596       return TCL_ERROR;
  1397   1597     }
         1598  +  p->maxStmt = NUM_PREPARED_STMTS;
  1398   1599     zArg = Tcl_GetStringFromObj(objv[1], 0);
  1399   1600     Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd);
  1400   1601   
  1401   1602     /* The return value is the value of the sqlite* pointer
  1402   1603     */
  1403   1604     sprintf(zBuf, "%p", p->db);
  1404   1605     if( strncmp(zBuf,"0x",2) ){

Changes to src/vdbeaux.c.

  1283   1283   
  1284   1284     /* If the VM did not run to completion or if it encountered an
  1285   1285     ** error, then it might not have been halted properly.  So halt
  1286   1286     ** it now.
  1287   1287     */
  1288   1288     sqlite3VdbeHalt(p);
  1289   1289   
  1290         -  /* Transfer the error code and error message from the VDBE into the
  1291         -  ** main database structure.
         1290  +  /* If the VDBE has be run even partially, then transfer the error code
         1291  +  ** and error message from the VDBE into the main database structure.  But
         1292  +  ** if the VDBE has just been set to run but has not actually executed any
         1293  +  ** instructions yet, leave the main database error information unchanged.
  1292   1294     */
  1293         -  if( p->zErrMsg ){
  1294         -    sqlite3Error(p->db, p->rc, "%s", p->zErrMsg);
  1295         -    sqliteFree(p->zErrMsg);
  1296         -    p->zErrMsg = 0;
  1297         -  }else if( p->rc ){
  1298         -    sqlite3Error(p->db, p->rc, 0);
  1299         -  }else{
  1300         -    sqlite3Error(p->db, SQLITE_OK, 0);
         1295  +  if( p->pc>=0 ){
         1296  +    if( p->zErrMsg ){
         1297  +      sqlite3Error(p->db, p->rc, "%s", p->zErrMsg);
         1298  +      sqliteFree(p->zErrMsg);
         1299  +      p->zErrMsg = 0;
         1300  +    }else if( p->rc ){
         1301  +      sqlite3Error(p->db, p->rc, 0);
         1302  +    }else{
         1303  +      sqlite3Error(p->db, SQLITE_OK, 0);
         1304  +    }
  1301   1305     }
  1302   1306   
  1303   1307     /* Reclaim all memory used by the VDBE
  1304   1308     */
  1305   1309     Cleanup(p);
  1306   1310   
  1307   1311     /* Save profiling information from this VDBE run.

Changes to test/tclsqlite.test.

    11     11   # This file implements regression tests for TCL interface to the
    12     12   # SQLite library. 
    13     13   #
    14     14   # Actually, all tests are based on the TCL interface, so the main
    15     15   # interface is pretty well tested.  This file contains some addition
    16     16   # tests for fringe issues that the main test suite does not cover.
    17     17   #
    18         -# $Id: tclsqlite.test,v 1.36 2005/01/12 12:44:04 danielk1977 Exp $
           18  +# $Id: tclsqlite.test,v 1.37 2005/01/24 00:28:43 drh Exp $
    19     19   
    20     20   set testdir [file dirname $argv0]
    21     21   source $testdir/tester.tcl
    22     22   
    23     23   # Check the error messages generated by tclsqlite
    24     24   #
    25     25   if {[sqlite3 -has-codec]} {
................................................................................
    30     30   do_test tcl-1.1 {
    31     31     set v [catch {sqlite3 bogus} msg]
    32     32     lappend v $msg
    33     33   } [list 1 "wrong # args: should be \"$r\""]
    34     34   do_test tcl-1.2 {
    35     35     set v [catch {db bogus} msg]
    36     36     lappend v $msg
    37         -} {1 {bad option "bogus": must be authorizer, busy, changes, close, collate, collation_needed, commit_hook, complete, copy, errorcode, eval, function, last_insert_rowid, onecolumn, progress, rekey, timeout, total_changes, trace, or version}}
           37  +} {1 {bad option "bogus": must be authorizer, busy, cache, changes, close, collate, collation_needed, commit_hook, complete, copy, errorcode, eval, function, last_insert_rowid, onecolumn, progress, rekey, timeout, total_changes, trace, or version}}
    38     38   do_test tcl-1.3 {
    39     39     execsql {CREATE TABLE t1(a int, b int)}
    40     40     execsql {INSERT INTO t1 VALUES(10,20)}
    41     41     set v [catch {
    42     42       db eval {SELECT * FROM t1} data {
    43     43         error "The error message"
    44     44       }