/ Check-in [d9f7993b]
Login

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

Overview
Comment:Add a case to permutations.test to run the veryquick test suite using sqlite3_prepare() instead of sqlite3_prepare_v2(). This helps to test the fix for bug [25ee812710].
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: d9f7993bfa2ecb30c44455de538eb6f8a4a59087
User & Date: dan 2011-06-27 16:55:50
Context
2011-06-27
19:37
Remove an unnecessary assignment from vdbeapi.c. check-in: 6c871ac1 user: dan tags: trunk
19:25
Merge latest trunk changes. check-in: 11ea98e4 user: dan tags: fts3-changes
16:55
Add a case to permutations.test to run the veryquick test suite using sqlite3_prepare() instead of sqlite3_prepare_v2(). This helps to test the fix for bug [25ee812710]. check-in: d9f7993b user: dan tags: trunk
00:01
Make sure all new statements begin life unexpired, even if they registered functions or did other actions during preparation that would have expired all statements. Fix for ticket [25ee81271091] check-in: faa38c87 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/tclsqlite.c.

   103    103   };
   104    104   
   105    105   typedef struct IncrblobChannel IncrblobChannel;
   106    106   
   107    107   /*
   108    108   ** There is one instance of this structure for each SQLite database
   109    109   ** that has been opened by the SQLite TCL interface.
          110  +**
          111  +** If this module is built with SQLITE_TEST defined (to create the SQLite
          112  +** testfixture executable), then it may be configured to use either
          113  +** sqlite3_prepare_v2() or sqlite3_prepare() to prepare SQL statements.
          114  +** If SqliteDb.bLegacyPrepare is true, sqlite3_prepare() is used.
   110    115   */
   111    116   typedef struct SqliteDb SqliteDb;
   112    117   struct SqliteDb {
   113    118     sqlite3 *db;               /* The "real" database structure. MUST BE FIRST */
   114    119     Tcl_Interp *interp;        /* The interpreter used for this database */
   115    120     char *zBusy;               /* The busy callback routine */
   116    121     char *zCommit;             /* The commit hook callback routine */
................................................................................
   131    136     SqlPreparedStmt *stmtList; /* List of prepared statements*/
   132    137     SqlPreparedStmt *stmtLast; /* Last statement in the list */
   133    138     int maxStmt;               /* The next maximum number of stmtList */
   134    139     int nStmt;                 /* Number of statements in stmtList */
   135    140     IncrblobChannel *pIncrblob;/* Linked list of open incrblob channels */
   136    141     int nStep, nSort, nIndex;  /* Statistics for most recent operation */
   137    142     int nTransaction;          /* Number of nested [transaction] methods */
          143  +#ifdef SQLITE_TEST
          144  +  int bLegacyPrepare;        /* True to use sqlite3_prepare() */
          145  +#endif
   138    146   };
   139    147   
   140    148   struct IncrblobChannel {
   141    149     sqlite3_blob *pBlob;      /* sqlite3 blob handle */
   142    150     SqliteDb *pDb;            /* Associated database connection */
   143    151     int iSeek;                /* Current seek offset */
   144    152     Tcl_Channel channel;      /* Channel identifier */
................................................................................
   424    432     }
   425    433     pNew->interp = pDb->interp;
   426    434     pNew->pScript = 0;
   427    435     pNew->pNext = pDb->pFunc;
   428    436     pDb->pFunc = pNew;
   429    437     return pNew;
   430    438   }
          439  +
          440  +/*
          441  +** Free a single SqlPreparedStmt object.
          442  +*/
          443  +static void dbFreeStmt(SqlPreparedStmt *pStmt){
          444  +#ifdef SQLITE_TEST
          445  +  if( sqlite3_sql(pStmt->pStmt)==0 ){
          446  +    Tcl_Free((char *)pStmt->zSql);
          447  +  }
          448  +#endif
          449  +  sqlite3_finalize(pStmt->pStmt);
          450  +  Tcl_Free((char *)pStmt);
          451  +}
   431    452   
   432    453   /*
   433    454   ** Finalize and free a list of prepared statements
   434    455   */
   435         -static void flushStmtCache( SqliteDb *pDb ){
          456  +static void flushStmtCache(SqliteDb *pDb){
   436    457     SqlPreparedStmt *pPreStmt;
          458  +  SqlPreparedStmt *pNext;
   437    459   
   438         -  while(  pDb->stmtList ){
   439         -    sqlite3_finalize( pDb->stmtList->pStmt );
   440         -    pPreStmt = pDb->stmtList;
   441         -    pDb->stmtList = pDb->stmtList->pNext;
   442         -    Tcl_Free( (char*)pPreStmt );
          460  +  for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pNext){
          461  +    pNext = pPreStmt->pNext;
          462  +    dbFreeStmt(pPreStmt);
   443    463     }
   444    464     pDb->nStmt = 0;
   445    465     pDb->stmtLast = 0;
          466  +  pDb->stmtList = 0;
   446    467   }
   447    468   
   448    469   /*
   449    470   ** TCL calls this procedure when an sqlite3 database command is
   450    471   ** deleted.
   451    472   */
   452    473   static void DbDeleteCmd(void *db){
................................................................................
  1025   1046       }
  1026   1047       sqlite3_exec(pDb->db, "ROLLBACK", 0, 0, 0);
  1027   1048     }
  1028   1049     pDb->disableAuth--;
  1029   1050   
  1030   1051     return rc;
  1031   1052   }
         1053  +
         1054  +/*
         1055  +** Unless SQLITE_TEST is defined, this function is a simple wrapper around
         1056  +** sqlite3_prepare_v2(). If SQLITE_TEST is defined, then it uses either
         1057  +** sqlite3_prepare_v2() or legacy interface sqlite3_prepare(), depending
         1058  +** on whether or not the [db_use_legacy_prepare] command has been used to 
         1059  +** configure the connection.
         1060  +*/
         1061  +static int dbPrepare(
         1062  +  SqliteDb *pDb,                  /* Database object */
         1063  +  const char *zSql,               /* SQL to compile */
         1064  +  sqlite3_stmt **ppStmt,          /* OUT: Prepared statement */
         1065  +  const char **pzOut              /* OUT: Pointer to next SQL statement */
         1066  +){
         1067  +#ifdef SQLITE_TEST
         1068  +  if( pDb->bLegacyPrepare ){
         1069  +    return sqlite3_prepare(pDb->db, zSql, -1, ppStmt, pzOut);
         1070  +  }
         1071  +#endif
         1072  +  return sqlite3_prepare_v2(pDb->db, zSql, -1, ppStmt, pzOut);
         1073  +}
  1032   1074   
  1033   1075   /*
  1034   1076   ** Search the cache for a prepared-statement object that implements the
  1035   1077   ** first SQL statement in the buffer pointed to by parameter zIn. If
  1036   1078   ** no such prepared-statement can be found, allocate and prepare a new
  1037   1079   ** one. In either case, bind the current values of the relevant Tcl
  1038   1080   ** variables to any $var, :var or @var variables in the statement. Before
................................................................................
  1096   1138     }
  1097   1139     
  1098   1140     /* If no prepared statement was found. Compile the SQL text. Also allocate
  1099   1141     ** a new SqlPreparedStmt structure.  */
  1100   1142     if( pPreStmt==0 ){
  1101   1143       int nByte;
  1102   1144   
  1103         -    if( SQLITE_OK!=sqlite3_prepare_v2(pDb->db, zSql, -1, &pStmt, pzOut) ){
         1145  +    if( SQLITE_OK!=dbPrepare(pDb, zSql, &pStmt, pzOut) ){
  1104   1146         Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
  1105   1147         return TCL_ERROR;
  1106   1148       }
  1107   1149       if( pStmt==0 ){
  1108   1150         if( SQLITE_OK!=sqlite3_errcode(pDb->db) ){
  1109   1151           /* A compile-time error in the statement. */
  1110   1152           Tcl_SetObjResult(interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
................................................................................
  1123   1165       pPreStmt = (SqlPreparedStmt*)Tcl_Alloc(nByte);
  1124   1166       memset(pPreStmt, 0, nByte);
  1125   1167   
  1126   1168       pPreStmt->pStmt = pStmt;
  1127   1169       pPreStmt->nSql = (*pzOut - zSql);
  1128   1170       pPreStmt->zSql = sqlite3_sql(pStmt);
  1129   1171       pPreStmt->apParm = (Tcl_Obj **)&pPreStmt[1];
         1172  +#ifdef SQLITE_TEST
         1173  +    if( pPreStmt->zSql==0 ){
         1174  +      char *zCopy = Tcl_Alloc(pPreStmt->nSql + 1);
         1175  +      memcpy(zCopy, zSql, pPreStmt->nSql);
         1176  +      zCopy[pPreStmt->nSql] = '\0';
         1177  +      pPreStmt->zSql = zCopy;
         1178  +    }
         1179  +#endif
  1130   1180     }
  1131   1181     assert( pPreStmt );
  1132   1182     assert( strlen30(pPreStmt->zSql)==pPreStmt->nSql );
  1133   1183     assert( 0==memcmp(pPreStmt->zSql, zSql, pPreStmt->nSql) );
  1134   1184   
  1135   1185     /* Bind values to parameters that begin with $ or : */  
  1136   1186     for(i=1; i<=nVar; i++){
................................................................................
  1176   1226     }
  1177   1227     pPreStmt->nParm = iParm;
  1178   1228     *ppPreStmt = pPreStmt;
  1179   1229   
  1180   1230     return TCL_OK;
  1181   1231   }
  1182   1232   
  1183         -
  1184   1233   /*
  1185   1234   ** Release a statement reference obtained by calling dbPrepareAndBind().
  1186   1235   ** There should be exactly one call to this function for each call to
  1187   1236   ** dbPrepareAndBind().
  1188   1237   **
  1189   1238   ** If the discard parameter is non-zero, then the statement is deleted
  1190   1239   ** immediately. Otherwise it is added to the LRU list and may be returned
................................................................................
  1201   1250     for(i=0; i<pPreStmt->nParm; i++){
  1202   1251       Tcl_DecrRefCount(pPreStmt->apParm[i]);
  1203   1252     }
  1204   1253     pPreStmt->nParm = 0;
  1205   1254   
  1206   1255     if( pDb->maxStmt<=0 || discard ){
  1207   1256       /* If the cache is turned off, deallocated the statement */
  1208         -    sqlite3_finalize(pPreStmt->pStmt);
  1209         -    Tcl_Free((char *)pPreStmt);
         1257  +    dbFreeStmt(pPreStmt);
  1210   1258     }else{
  1211   1259       /* Add the prepared statement to the beginning of the cache list. */
  1212   1260       pPreStmt->pNext = pDb->stmtList;
  1213   1261       pPreStmt->pPrev = 0;
  1214   1262       if( pDb->stmtList ){
  1215   1263        pDb->stmtList->pPrev = pPreStmt;
  1216   1264       }
................................................................................
  1222   1270         assert( pDb->nStmt>0 );
  1223   1271       }
  1224   1272       pDb->nStmt++;
  1225   1273      
  1226   1274       /* If we have too many statement in cache, remove the surplus from 
  1227   1275       ** the end of the cache list.  */
  1228   1276       while( pDb->nStmt>pDb->maxStmt ){
  1229         -      sqlite3_finalize(pDb->stmtLast->pStmt);
  1230         -      pDb->stmtLast = pDb->stmtLast->pPrev;
  1231         -      Tcl_Free((char*)pDb->stmtLast->pNext);
         1277  +      SqlPreparedStmt *pLast = pDb->stmtLast;
         1278  +      pDb->stmtLast = pLast->pPrev;
  1232   1279         pDb->stmtLast->pNext = 0;
  1233   1280         pDb->nStmt--;
         1281  +      dbFreeStmt(pLast);
  1234   1282       }
  1235   1283     }
  1236   1284   }
  1237   1285   
  1238   1286   /*
  1239   1287   ** Structure used with dbEvalXXX() functions:
  1240   1288   **
................................................................................
  1359   1407   ** A return value of TCL_OK means there is a row of data available. The
  1360   1408   ** data may be accessed using dbEvalRowInfo() and dbEvalColumnValue(). This
  1361   1409   ** is analogous to a return of SQLITE_ROW from sqlite3_step(). If TCL_BREAK
  1362   1410   ** is returned, then the SQL script has finished executing and there are
  1363   1411   ** no further rows available. This is similar to SQLITE_DONE.
  1364   1412   */
  1365   1413   static int dbEvalStep(DbEvalContext *p){
         1414  +  const char *zPrevSql = 0;       /* Previous value of p->zSql */
         1415  +
  1366   1416     while( p->zSql[0] || p->pPreStmt ){
  1367   1417       int rc;
  1368   1418       if( p->pPreStmt==0 ){
         1419  +      zPrevSql = (p->zSql==zPrevSql ? 0 : p->zSql);
  1369   1420         rc = dbPrepareAndBind(p->pDb, p->zSql, &p->zSql, &p->pPreStmt);
  1370   1421         if( rc!=TCL_OK ) return rc;
  1371   1422       }else{
  1372   1423         int rcs;
  1373   1424         SqliteDb *pDb = p->pDb;
  1374   1425         SqlPreparedStmt *pPreStmt = p->pPreStmt;
  1375   1426         sqlite3_stmt *pStmt = pPreStmt->pStmt;
................................................................................
  1388   1439         pDb->nIndex = sqlite3_stmt_status(pStmt,SQLITE_STMTSTATUS_AUTOINDEX,1);
  1389   1440         dbReleaseColumnNames(p);
  1390   1441         p->pPreStmt = 0;
  1391   1442   
  1392   1443         if( rcs!=SQLITE_OK ){
  1393   1444           /* If a run-time error occurs, report the error and stop reading
  1394   1445           ** the SQL.  */
  1395         -        Tcl_SetObjResult(pDb->interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
  1396   1446           dbReleaseStmt(pDb, pPreStmt, 1);
         1447  +#if SQLITE_TEST
         1448  +        if( p->pDb->bLegacyPrepare && rcs==SQLITE_SCHEMA && zPrevSql ){
         1449  +          /* If the runtime error was an SQLITE_SCHEMA, and the database
         1450  +          ** handle is configured to use the legacy sqlite3_prepare() 
         1451  +          ** interface, retry prepare()/step() on the same SQL statement.
         1452  +          ** This only happens once. If there is a second SQLITE_SCHEMA
         1453  +          ** error, the error will be returned to the caller. */
         1454  +          p->zSql = zPrevSql;
         1455  +          continue;
         1456  +        }
         1457  +#endif
         1458  +        Tcl_SetObjResult(pDb->interp, dbTextToObj(sqlite3_errmsg(pDb->db)));
  1397   1459           return TCL_ERROR;
  1398   1460         }else{
  1399   1461           dbReleaseStmt(pDb, pPreStmt, 0);
  1400   1462         }
  1401   1463       }
  1402   1464     }
  1403   1465   
................................................................................
  2922   2984         if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
  2923   2985         if( b ){
  2924   2986           flags |= SQLITE_OPEN_NOMUTEX;
  2925   2987           flags &= ~SQLITE_OPEN_FULLMUTEX;
  2926   2988         }else{
  2927   2989           flags &= ~SQLITE_OPEN_NOMUTEX;
  2928   2990         }
  2929         -   }else if( strcmp(zArg, "-fullmutex")==0 ){
         2991  +    }else if( strcmp(zArg, "-fullmutex")==0 ){
  2930   2992         int b;
  2931   2993         if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
  2932   2994         if( b ){
  2933   2995           flags |= SQLITE_OPEN_FULLMUTEX;
  2934   2996           flags &= ~SQLITE_OPEN_NOMUTEX;
  2935   2997         }else{
  2936   2998           flags &= ~SQLITE_OPEN_FULLMUTEX;
................................................................................
  3523   3585     if( !slave ){
  3524   3586       return TCL_ERROR;
  3525   3587     }
  3526   3588   
  3527   3589     init_all(slave);
  3528   3590     return TCL_OK;
  3529   3591   }
         3592  +
         3593  +/*
         3594  +** Tclcmd: db_use_legacy_prepare DB BOOLEAN
         3595  +**
         3596  +**   The first argument to this command must be a database command created by
         3597  +**   [sqlite3]. If the second argument is true, then the handle is configured
         3598  +**   to use the sqlite3_prepare_v2() function to prepare statements. If it
         3599  +**   is false, sqlite3_prepare().
         3600  +*/
         3601  +static int db_use_legacy_prepare_cmd(
         3602  +  ClientData cd,
         3603  +  Tcl_Interp *interp,
         3604  +  int objc,
         3605  +  Tcl_Obj *CONST objv[]
         3606  +){
         3607  +  Tcl_CmdInfo cmdInfo;
         3608  +  SqliteDb *pDb;
         3609  +  int bPrepare;
         3610  +
         3611  +  if( objc!=3 ){
         3612  +    Tcl_WrongNumArgs(interp, 1, objv, "DB BOOLEAN");
         3613  +    return TCL_ERROR;
         3614  +  }
         3615  +
         3616  +  if( !Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &cmdInfo) ){
         3617  +    Tcl_AppendResult(interp, "no such db: ", Tcl_GetString(objv[1]), (char*)0);
         3618  +    return TCL_ERROR;
         3619  +  }
         3620  +  pDb = (SqliteDb*)cmdInfo.objClientData;
         3621  +  if( Tcl_GetBooleanFromObj(interp, objv[2], &bPrepare) ){
         3622  +    return TCL_ERROR;
         3623  +  }
         3624  +
         3625  +  pDb->bLegacyPrepare = bPrepare;
         3626  +
         3627  +  Tcl_ResetResult(interp);
         3628  +  return TCL_OK;
         3629  +}
  3530   3630   #endif
  3531   3631   
  3532   3632   /*
  3533   3633   ** Configure the interpreter passed as the first argument to have access
  3534   3634   ** to the commands and linked variables that make up:
  3535   3635   **
  3536   3636   **   * the [sqlite3] extension itself, 
................................................................................
  3629   3729       Sqlitetestfuzzer_Init(interp);
  3630   3730       Sqlitetestwholenumber_Init(interp);
  3631   3731   
  3632   3732   #if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
  3633   3733       Sqlitetestfts3_Init(interp);
  3634   3734   #endif
  3635   3735   
  3636         -    Tcl_CreateObjCommand(interp,"load_testfixture_extensions",init_all_cmd,0,0);
         3736  +    Tcl_CreateObjCommand(
         3737  +        interp, "load_testfixture_extensions", init_all_cmd, 0, 0
         3738  +    );
         3739  +    Tcl_CreateObjCommand(
         3740  +        interp, "db_use_legacy_prepare", db_use_legacy_prepare_cmd, 0, 0
         3741  +    );
  3637   3742   
  3638   3743   #ifdef SQLITE_SSE
  3639   3744       Sqlitetestsse_Init(interp);
  3640   3745   #endif
  3641   3746     }
  3642   3747   #endif
  3643   3748   }

Changes to test/all.test.

    34     34   run_test_suite journaltest 
    35     35   run_test_suite inmemory_journal
    36     36   run_test_suite pcache0 
    37     37   run_test_suite pcache10 
    38     38   run_test_suite pcache50 
    39     39   run_test_suite pcache90 
    40     40   run_test_suite pcache100
           41  +run_test_suite prepare
    41     42   
    42     43   if {$::tcl_platform(platform)=="unix"} {
    43     44     ifcapable !default_autovacuum {
    44     45       run_test_suite autovacuum_crash
    45     46     }
    46     47   }
    47     48   
    48     49   finish_test
    49     50   
    50     51   

Changes to test/alter2.test.

   133    133     execsql {
   134    134       SELECT sum(a), c FROM abc GROUP BY c;
   135    135     }
   136    136   } {8 {} 1 10}
   137    137   do_test alter2-1.9 {
   138    138     # ALTER TABLE abc ADD COLUMN d;
   139    139     alter_table abc {CREATE TABLE abc(a, b, c, d);}
          140  +  if {[permutation] == "prepare"} { db cache flush }
   140    141     execsql { SELECT * FROM abc; }
   141    142     execsql {
   142    143       UPDATE abc SET d = 11 WHERE c IS NULL AND a<4;
   143    144       SELECT * FROM abc;
   144    145     }
   145    146   } {1 2 10 {} 3 4 {} 11 5 6 {} {}}
   146    147   do_test alter2-1.10 {

Changes to test/exists.test.

   155    155         sql1 { DROP INDEX IF EXISTS aux.i2 }
   156    156         sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'index' }
   157    157       } {}
   158    158       do_test 3.$tn.2.2 {
   159    159         sql1 { DROP INDEX IF EXISTS i2 }
   160    160         sql2 { CREATE INDEX aux.i2 ON t2(x) }
   161    161         sql1 { DROP INDEX IF EXISTS i2 }
   162         -      sql2 { SELECT name FROM aux.sqlite_master WHERE type = 'index' }
          162  +      sql2 { SELECT * FROM aux.sqlite_master WHERE type = 'index' }
   163    163       } {}
   164    164   
   165    165       # VIEW objects.
   166    166       #
   167    167       do_test 3.$tn.3.1 {
   168    168         sql1 { DROP VIEW IF EXISTS aux.v1 }
   169    169         sql2 { CREATE VIEW aux.v1 AS SELECT * FROM t2 }

Changes to test/permutations.test.

   771    771     where6.test where7.test where8.test where9.test
   772    772     whereA.test whereB.test wherelimit.test
   773    773     select1.test select2.test select3.test select4.test select5.test
   774    774     select7.test select8.test selectA.test selectC.test
   775    775   } -dbconfig {
   776    776     optimization_control $::dbhandle all 0
   777    777   }
          778  +
          779  +test_suite "prepare" -description {
          780  +  Run tests with the db connection using sqlite3_prepare() instead of _v2().
          781  +} -dbconfig {
          782  +  db_use_legacy_prepare $::dbhandle 1
          783  +  #$::dbhandle cache size 0
          784  +} -files [
          785  +  test_set $allquicktests -exclude *malloc* *ioerr* *fault*
          786  +]
   778    787   
   779    788   # End of tests
   780    789   #############################################################################
   781    790   
   782    791   # run_tests NAME OPTIONS
   783    792   #
   784    793   # where available options are:  

Changes to test/temptable.test.

   288    288   # but the permanent index should still be accessible and should still
   289    289   # be updated when its corresponding table changes.
   290    290   #
   291    291   do_test temptable-5.1 {
   292    292     execsql {
   293    293       CREATE TEMP TABLE mask(a,b,c)
   294    294     } db2
          295  +  if {[permutation]=="prepare"} { db2 cache flush }
   295    296     execsql {
   296    297       CREATE INDEX mask ON t2(x);
   297    298       SELECT * FROM t2;
   298    299     }
   299    300   } {3 4}
   300    301   #do_test temptable-5.2 {
   301    302   #  catchsql {