]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Make sure that sqlite3_stmt_readonly reports false for
authordrh <drh@noemail.net>
Thu, 27 Jun 2013 17:40:30 +0000 (17:40 +0000)
committerdrh <drh@noemail.net>
Thu, 27 Jun 2013 17:40:30 +0000 (17:40 +0000)
PRAGMA journal_mode and PRAGMA wal_checkpoint.  Ticket [a589ec069e3].
Also keep track of whether a prepared statement does no reading or
writing.

FossilOrigin-Name: 1937fd8eec2c1da95a782d9dc63926d846b06bdc

manifest
manifest.uuid
src/sqliteInt.h
src/vdbe.c
src/vdbeInt.h
src/vdbeapi.c
src/vdbeaux.c
test/capi3d.test

index db6e3038a928bef443f87c287356d656623e2265..06ae3bdb2ca27211ead09e9677064c115167fd31 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sa\stest\sto\sensure\sthat\sif\sBEGIN\sIMMEDIATE\sfails\swith\sSQLITE_BUSY,\sit\sdoes\snot\sleave\sthe\suser\swith\san\sopen\sread\stransaction\s(unless\sone\swas\salready\sopen).
-D 2013-06-27T14:24:15.136
+C Make\ssure\sthat\ssqlite3_stmt_readonly\sreports\sfalse\sfor\nPRAGMA\sjournal_mode\sand\sPRAGMA\swal_checkpoint.\s\sTicket\s[a589ec069e3].\nAlso\skeep\strack\sof\swhether\sa\sprepared\sstatement\sdoes\sno\sreading\sor\nwriting.
+D 2013-06-27T17:40:30.228
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -221,7 +221,7 @@ F src/shell.c c0f38cee126d1ea82275195933359e91d90196a0
 F src/sqlite.h.in 9e8d57aa4d2fdc181dc25e9aa295f5ecec7e184a
 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
 F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5
-F src/sqliteInt.h e6f069b07fdef1ab54034940b7a6e7be2b4efd57
+F src/sqliteInt.h e8d5ed8a3a1d6be304c3ac7c72b5bd5f4b62a1b0
 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -277,11 +277,11 @@ F src/update.c 8e76c3d03e4b7b21cb250bd2df0c05e12993e577
 F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f
 F src/util.c f566b5138099a2df8533b190d0dcc74b7dfbe0c9
 F src/vacuum.c ddf21cc9577c4cb459d08bee9863a78ec000c5bb
-F src/vdbe.c af2bc360189ce8eaed47133037e082a1652bc4a0
+F src/vdbe.c f678101139d174e92eec1cb21201646ee3ee3383
 F src/vdbe.h b52887278cb173e66188da84dfab216bea61119d
-F src/vdbeInt.h b8a76f7b7304abfdb8e6bd286eba954ecfe73863
-F src/vdbeapi.c 0b2c78797058c6c9bfa1687977de039566e22877
-F src/vdbeaux.c af9cd9372c7ab82294b9645723e652c2d4213b95
+F src/vdbeInt.h 9735fdf28b8d250e001e5b406f7011a40888c739
+F src/vdbeapi.c be5e9ebd51621571225c54516eb09d97569ff2ff
+F src/vdbeaux.c 727ad6060db0e0d3c06581281d8637ed24ba5647
 F src/vdbeblob.c 5dc79627775bd9a9b494dd956e26297946417d69
 F src/vdbemem.c 833005f1cbbf447289f1973dba2a0c2228c7b8ab
 F src/vdbesort.c 3937e06b2a0e354500e17dc206ef4c35770a5017
@@ -359,7 +359,7 @@ F test/capi2.test e8b18cc61090b6e5e388f54d6b125d711d1b265a
 F test/capi3.test 56ab450125ead38846cbae7e5b6a216686c3cffa
 F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
 F test/capi3c.test 93d24621c9ff84da9da060f30431e0453db1cdb0
-F test/capi3d.test 17b57ca28be3e37e14c2ba8f787d292d84b724a1
+F test/capi3d.test 6d0fc0a86d73f42dd19a7d8b7761ab9bc02277d0
 F test/capi3e.test ad90088b18b0367125ff2d4b5400153fd2f99aab
 F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3
 F test/check.test 2eb93611139a7dfaed3be80067c7dc5ceb5fb287
@@ -1098,7 +1098,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae
 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
-P 4c02b344f5c6f6fb1c61b79d51063a1e0e2d75c0
-R f7e72c4156e7c539662844a39b9e3b02
-U dan
-Z d4c7b57dd14fca50abddc9b4b3e495d3
+P 22bced36f0f121f29d94f1f9eab45c8731517a53
+R 182a3fd649ef7d4b97150fcbb047e7a6
+U drh
+Z aa0f35d707430a5d3fece648b987ad5a
index deb56ed74353f2e7027106e8e9ca696d74127227..304991bfea1d005b2818044a107b818f680b258f 100644 (file)
@@ -1 +1 @@
-22bced36f0f121f29d94f1f9eab45c8731517a53
\ No newline at end of file
+1937fd8eec2c1da95a782d9dc63926d846b06bdc
\ No newline at end of file
index 0a661937ff8246e5846e10bb02925bbc024f55c7..dd626303f7b1403ff9cb3f6447ce1c0d18634e9e 100644 (file)
@@ -898,6 +898,7 @@ struct sqlite3 {
     u8 orphanTrigger;           /* Last statement is orphaned TEMP trigger */
   } init;
   int activeVdbeCnt;            /* Number of VDBEs currently executing */
+  int noIOVdbeCnt;              /* Nr of active VDBEs with no FROM clause */
   int writeVdbeCnt;             /* Number of active VDBEs that are writing */
   int vdbeExecCnt;              /* Number of nested calls to VdbeExec() */
   int nExtension;               /* Number of loaded extensions */
index 81b40628e1b2ae2d53c926f736554d82802099ae..e211ecec9209757c0725b495f9d97af00da1daed 100644 (file)
@@ -579,6 +579,7 @@ int sqlite3VdbeExec(
     goto no_mem;
   }
   assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY );
+  assert( p->noIO==0 || p->readOnly!=0 );
   p->rc = SQLITE_OK;
   assert( p->explain==0 );
   p->pResultSet = 0;
@@ -2934,6 +2935,8 @@ case OP_AutoCommit: {
 case OP_Transaction: {
   Btree *pBt;
 
+  assert( p->noIO==0 );
+  assert( p->readOnly==0 || pOp->p2==0 );
   assert( pOp->p1>=0 && pOp->p1<db->nDb );
   assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
   pBt = db->aDb[pOp->p1].pBt;
@@ -2990,6 +2993,7 @@ case OP_ReadCookie: {               /* out2-prerelease */
   int iDb;
   int iCookie;
 
+  assert( p->noIO==0 );
   iDb = pOp->p1;
   iCookie = pOp->p3;
   assert( pOp->p3<SQLITE_N_BTREE_META );
@@ -3017,6 +3021,7 @@ case OP_SetCookie: {       /* in3 */
   assert( pOp->p2<SQLITE_N_BTREE_META );
   assert( pOp->p1>=0 && pOp->p1<db->nDb );
   assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
+  assert( p->readOnly==0 );
   pDb = &db->aDb[pOp->p1];
   assert( pDb->pBt!=0 );
   assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) );
@@ -3067,6 +3072,7 @@ case OP_VerifyCookie: {
   assert( pOp->p1>=0 && pOp->p1<db->nDb );
   assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
   assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) );
+  assert( p->noIO==0 );
   pBt = db->aDb[pOp->p1].pBt;
   if( pBt ){
     sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta);
@@ -3162,6 +3168,8 @@ case OP_OpenWrite: {
 
   assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR))==pOp->p5 );
   assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 );
+  assert( p->noIO==0 );
+  assert( pOp->opcode==OP_OpenRead || p->readOnly==0 );
 
   if( p->expired ){
     rc = SQLITE_ABORT;
@@ -4732,6 +4740,7 @@ case OP_Destroy: {     /* out2-prerelease */
   Vdbe *pVdbe;
   int iDb;
 
+  assert( p->readOnly==0 );
 #ifndef SQLITE_OMIT_VIRTUALTABLE
   iCnt = 0;
   for(pVdbe=db->pVdbe; pVdbe; pVdbe = pVdbe->pNext){
@@ -4787,6 +4796,7 @@ case OP_Clear: {
   int nChange;
  
   nChange = 0;
+  assert( p->readOnly==0 );
   assert( (p->btreeMask & (((yDbMask)1)<<pOp->p2))!=0 );
   rc = sqlite3BtreeClearTable(
       db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0)
@@ -4833,6 +4843,7 @@ case OP_CreateTable: {          /* out2-prerelease */
   pgno = 0;
   assert( pOp->p1>=0 && pOp->p1<db->nDb );
   assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
+  assert( p->readOnly==0 );
   pDb = &db->aDb[pOp->p1];
   assert( pDb->pBt!=0 );
   if( pOp->opcode==OP_CreateTable ){
@@ -4980,7 +4991,8 @@ case OP_IntegrityCk: {
   int nErr;       /* Number of errors reported */
   char *z;        /* Text of the error report */
   Mem *pnErr;     /* Register keeping track of errors remaining */
-  
+
+  assert( p->noIO==0 );
   nRoot = pOp->p2;
   assert( nRoot>0 );
   aRoot = sqlite3DbMallocRaw(db, sizeof(int)*(nRoot+1) );
@@ -5486,6 +5498,7 @@ case OP_Checkpoint: {
   int aRes[3];                    /* Results */
   Mem *pMem;                      /* Write results here */
 
+  assert( p->readOnly==0 );
   aRes[0] = 0;
   aRes[1] = aRes[2] = -1;
   assert( pOp->p2==SQLITE_CHECKPOINT_PASSIVE
@@ -5535,6 +5548,7 @@ case OP_JournalMode: {    /* out2-prerelease */
        || eNew==PAGER_JOURNALMODE_QUERY
   );
   assert( pOp->p1>=0 && pOp->p1<db->nDb );
+  assert( p->readOnly==0 );
 
   pBt = db->aDb[pOp->p1].pBt;
   pPager = sqlite3BtreePager(pBt);
@@ -5617,6 +5631,7 @@ case OP_JournalMode: {    /* out2-prerelease */
 ** a transaction.
 */
 case OP_Vacuum: {
+  assert( p->readOnly==0 );
   rc = sqlite3RunVacuum(&p->zErrMsg, db);
   break;
 }
@@ -5634,6 +5649,7 @@ case OP_IncrVacuum: {        /* jump */
 
   assert( pOp->p1>=0 && pOp->p1<db->nDb );
   assert( (p->btreeMask & (((yDbMask)1)<<pOp->p1))!=0 );
+  assert( p->readOnly==0 );
   pBt = db->aDb[pOp->p1].pBt;
   rc = sqlite3BtreeIncrVacuum(pBt);
   if( rc==SQLITE_DONE ){
@@ -5752,6 +5768,7 @@ case OP_VOpen: {
   sqlite3_vtab *pVtab;
   sqlite3_module *pModule;
 
+  assert( p->noIO==0 );
   pCur = 0;
   pVtabCursor = 0;
   pVtab = pOp->p4.pVtab->pVtab;
@@ -5968,6 +5985,7 @@ case OP_VRename: {
   pName = &aMem[pOp->p1];
   assert( pVtab->pModule->xRename );
   assert( memIsValid(pName) );
+  assert( p->readOnly==0 );
   REGISTER_TRACE(pOp->p1, pName);
   assert( pName->flags & MEM_Str );
   testcase( pName->enc==SQLITE_UTF8 );
@@ -6019,6 +6037,7 @@ case OP_VUpdate: {
   assert( pOp->p2==1        || pOp->p5==OE_Fail   || pOp->p5==OE_Rollback 
        || pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace
   );
+  assert( p->readOnly==0 );
   pVtab = pOp->p4.pVtab->pVtab;
   pModule = (sqlite3_module *)pVtab->pModule;
   nArg = pOp->p2;
index dc42187f068a13df217a94ac8909e5a33df1f36c..7b66742063e502cdb3b3ad1fdb163a62a38bdf25 100644 (file)
@@ -337,7 +337,8 @@ struct Vdbe {
   bft expired:1;          /* True if the VM needs to be recompiled */
   bft runOnlyOnce:1;      /* Automatically expire on reset */
   bft usesStmtJournal:1;  /* True if uses a statement journal */
-  bft readOnly:1;         /* True for read-only statements */
+  bft readOnly:1;         /* True for statements that do not write */
+  bft noIO:1;             /* True for SELECTs with no FROM clause */
   bft isPrepareV2:1;      /* True if prepared with prepare_v2() */
   bft doingRerun:1;       /* True if rerunning after an auto-reprepare */
   int nChange;            /* Number of db changes made since last reset */
index 426b72c5ccfbc57bc4dfb300d52dc0c7970d53a9..0f3df2e0df9ae6a494601a9b96fee9e7b9787b49 100644 (file)
@@ -396,6 +396,7 @@ static int sqlite3Step(Vdbe *p){
 
     db->activeVdbeCnt++;
     if( p->readOnly==0 ) db->writeVdbeCnt++;
+    if( p->noIO ) db->noIOVdbeCnt++;
     p->pc = 0;
   }
 #ifndef SQLITE_OMIT_EXPLAIN
index e32f2db0648565508d569f9314a2d2f628805d1a..3bfaa8ca40351830782febbf0e4cfdb1ffa9b16c 100644 (file)
@@ -403,14 +403,24 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
   Op *pOp;
   int *aLabel = p->aLabel;
   p->readOnly = 1;
+  p->noIO = 1;
   for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){
     u8 opcode = pOp->opcode;
 
     pOp->opflags = sqlite3OpcodeProperty[opcode];
     if( opcode==OP_Function || opcode==OP_AggStep ){
       if( pOp->p5>nMaxArgs ) nMaxArgs = pOp->p5;
-    }else if( (opcode==OP_Transaction && pOp->p2!=0) || opcode==OP_Vacuum ){
+    }else if( opcode==OP_Transaction ){
+      if( pOp->p2!=0 ) p->readOnly = 0;
+      p->noIO = 0;
+    }else if( opcode==OP_Vacuum
+           || opcode==OP_JournalMode
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+           || opcode==OP_Checkpoint
+#endif
+    ){
       p->readOnly = 0;
+      p->noIO = 0;
 #ifndef SQLITE_OMIT_VIRTUALTABLE
     }else if( opcode==OP_VUpdate ){
       if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
@@ -436,7 +446,6 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
   }
   sqlite3DbFree(p->db, p->aLabel);
   p->aLabel = 0;
-
   *pMaxFuncArgs = nMaxArgs;
 }
 
@@ -1976,16 +1985,19 @@ static void checkActiveVdbeCnt(sqlite3 *db){
   Vdbe *p;
   int cnt = 0;
   int nWrite = 0;
+  int nNoIO = 0;
   p = db->pVdbe;
   while( p ){
     if( p->magic==VDBE_MAGIC_RUN && p->pc>=0 ){
       cnt++;
       if( p->readOnly==0 ) nWrite++;
+      if( p->noIO ) nNoIO++;
     }
     p = p->pNext;
   }
   assert( cnt==db->activeVdbeCnt );
   assert( nWrite==db->writeVdbeCnt );
+  assert( nNoIO==db->noIOVdbeCnt );
 }
 #else
 #define checkActiveVdbeCnt(x)
@@ -2257,10 +2269,10 @@ int sqlite3VdbeHalt(Vdbe *p){
   /* We have successfully halted and closed the VM.  Record this fact. */
   if( p->pc>=0 ){
     db->activeVdbeCnt--;
-    if( !p->readOnly ){
-      db->writeVdbeCnt--;
-    }
+    if( !p->readOnly ) db->writeVdbeCnt--;
+    if( p->noIO ) db->noIOVdbeCnt--;
     assert( db->activeVdbeCnt>=db->writeVdbeCnt );
+    assert( db->activeVdbeCnt>=db->noIOVdbeCnt );
   }
   p->magic = VDBE_MAGIC_HALT;
   checkActiveVdbeCnt(db);
index 746ec20b25b09d181b5857ee94bc1cbcc6f90643..ed3765b05194193cc78d4df24facaa1bd2409975 100644 (file)
@@ -108,6 +108,13 @@ db eval {CREATE TABLE t1(x)}
 test_is_readonly capi3d-2.3 {INSERT INTO t1 VALUES(5)} 0
 test_is_readonly capi3d-2.4 {UPDATE t1 SET x=x+1 WHERE x<0} 0
 test_is_readonly capi3d-2.5 {SELECT * FROM t1} 1
+ifcapable wal {
+  test_is_readonly capi3d-2.6 {PRAGMA journal_mode=WAL} 0
+  test_is_readonly capi3d-2.7 {PRAGMA wal_checkpoint} 0
+}
+test_is_readonly capi3d-2.8 {PRAGMA application_id=1234} 0
+test_is_readonly capi3d-2.9 {VACUUM} 0
+test_is_readonly capi3d-2.10 {PRAGMA integrity_check} 1
 do_test capi3-2.99 {
   sqlite3_stmt_readonly 0
 } 1