]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the OP_SetTabCol and OP_VerifyTabCol opcodes, only when compiling with
authordrh <drh@noemail.net>
Mon, 11 Jun 2018 17:35:02 +0000 (17:35 +0000)
committerdrh <drh@noemail.net>
Mon, 11 Jun 2018 17:35:02 +0000 (17:35 +0000)
SQLITE_DEBUG, to do run-time verification of the column cache.

FossilOrigin-Name: b37614a3670770919a7c7f8157c5fd6578d736447998640b52e5cef8174cadc2

manifest
manifest.uuid
src/expr.c
src/sqliteInt.h
src/vdbe.c
src/vdbe.h
src/vdbeInt.h
src/vdbeaux.c
src/vdbemem.c
src/where.c

index 6170904da34ed5a3c039a8afacafcfcbe8693464..3228fbdad9256d402346f02fed622ebe9817d8cc 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Strengthen\sthe\ssqlite3VdbeMemAboutToChange()\srun-time\sverification\smechanism\nto\sbetter\sdetect\smissed\scalls\sto\sAboutToChange().
-D 2018-06-11T13:10:45.872
+C Add\sthe\sOP_SetTabCol\sand\sOP_VerifyTabCol\sopcodes,\sonly\swhen\scompiling\swith\nSQLITE_DEBUG,\sto\sdo\srun-time\sverification\sof\sthe\scolumn\scache.
+D 2018-06-11T17:35:02.447
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F Makefile.in bfc40f350586923e0419d2ea4b559c37ec10ee4b6e210e08c14401f8e340f0da
@@ -447,7 +447,7 @@ F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
 F src/dbpage.c 4aa7f26198934dbd002e69418220eae3dbc71b010bbac32bd78faf86b52ce6c3
 F src/dbstat.c edabb82611143727511a45ca0859b8cd037851ebe756ae3db289859dd18b6f91
 F src/delete.c 4c8c7604277a2041647f96b78f4b9a47858e9217e4fb333d35e7b5ab32c5b57f
-F src/expr.c 16f90ae2af2a100bc430a89184afde54878d82f18267e8d00bc4f33e695a7c57
+F src/expr.c 3ab855fb882d8758220edaf261d8d56ad2cb3736f92c818f4ae250ac4a2752a4
 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
 F src/fkey.c b1da9ef8dc834603bb0d28972378a7ce65897847f9a1e89ab800bbdf24c788ee
 F src/func.c e2e3c02621a528a472933fd4733a5da635676f1461be73293f6e9f62f18d4eaa
@@ -500,7 +500,7 @@ F src/shell.c.in 4d0ddf10c403710d241bf920163dcf032c21119aebb61e70840942c0eafecdf
 F src/sqlite.h.in 63b07f76731f2b1e55c48fdb9f0508dcc6fbe3971010b8612ffd847c3c56d9a1
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7
-F src/sqliteInt.h 9332b820382288dde7d6ea712bbcd34380bbbeb44f6f7032710bd5240fd4067d
+F src/sqliteInt.h c8d304712b6b4e2150cbb5355b1a80427eee7b3ea1a6b5827afadf557360d7fe
 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
 F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
 F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
@@ -565,13 +565,13 @@ F src/upsert.c 47edd408cc73f8d3c00a140550d1ad180b407c146285947969dd09874802bf88
 F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
 F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
 F src/vacuum.c 36e7d21a20c0bf6ef4ef7c399d192b5239410b7c4d3c1070fba4e30810d0b855
-F src/vdbe.c d7a475cec51c83daf0d348301a1aec77f535832ea946632b5738ff9f087c0edb
-F src/vdbe.h c58fa2d8fff2a235a685687340ee555269f5421e4ec2ee758a5550961d3b25a4
-F src/vdbeInt.h d299d7a19853463dac418de0d97f2dd9cb4ddb495a45c93364e2daee109ba0ef
+F src/vdbe.c e0ac1d7cff72b4e8b250c5e698f0fc43f0c8b5a8f35654716d8ab1fa89db669e
+F src/vdbe.h 9c8c245fa3785266c269ab02c135c836ff49a307612186686bcdae500f409945
+F src/vdbeInt.h 8ebc37ead2cfde92a63d74e3940fe0a94d456078c77e6cefbc2ecf15630f9fda
 F src/vdbeapi.c 765a0bbe01311626417de6cb743f7f25f9f98435c98a9df4bb0714d11014633d
-F src/vdbeaux.c ea0b7821dd74068cb8b232d1ba3dc457ecaca302d2cf67e1f24ff3bcc7d94c52
+F src/vdbeaux.c 0e7af8614c87dd25bc2395d22c847deba96ff87d19758d5cd7f459a466f14cbb
 F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
-F src/vdbemem.c 8f5cd24151c87294c2fb31c9e9353b074786c10cb9e7ef74d93c2e1ec85d1ee1
+F src/vdbemem.c 613cbbcca8d21c66df311fc17f9460180abcf7a909e12493618fd570f9858036
 F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2f
 F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392
 F src/vtab.c 10ea07dec111de6fb0a4fc87a7ffa4c65fdc088a19dbfaf7d6f2b128f2e8eb7b
@@ -579,7 +579,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
 F src/wal.c d44a0811afd2155b1157c38b33141d4ac028fda6232485bed664015bb05819ca
 F src/wal.h 8de5d2d3de0956d6f6cb48c83a4012d5f227b8fe940f3a349a4b7e85ebcb492a
 F src/walker.c da987a20d40145c0a03c07d8fefcb2ed363becc7680d0500d9c79915591f5b1f
-F src/where.c fe1a6f97c12cc9472ccce86166ba3f827cf61d6ae770c036a6396b63863baac4
+F src/where.c 0bcbf9e191ca07f9ea2008aa80e70ded46bcdffd26560c83397da501f00aece6
 F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4
 F src/wherecode.c 3317f2b083a66d3e65a03edf316ade4ccb0a99c9956273282ebb579b95d4ba96
 F src/whereexpr.c 19cf35cdd9bf6d5589d8a5c960d99259761136187a2319a6e14d11cf1abe14c2
@@ -1731,7 +1731,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 9faf41713e865f26485d9e90918d77c25be211384941eadda6a36237f52c25de
-R 846e9acb3549bc01ad42c2408534b9d1
+P 793e942205a12eedb7ecc5ad8a27e3e52bbd4e1d50a0d1453d04a83ba728884e
+R e32799ffc139aea23a34579bcd80eade
 U drh
-Z 5f45d155d5f89ae268c81c641f0e97a0
+Z 5651f63d60929e8aa5ef5f44ca04cc41
index 5504e2c63e88dc8510a3dc7c0750c90e292cb43b..b1328ceffbcadb209d0508959a36085aff8dc5cd 100644 (file)
@@ -1 +1 @@
-793e942205a12eedb7ecc5ad8a27e3e52bbd4e1d50a0d1453d04a83ba728884e
\ No newline at end of file
+b37614a3670770919a7c7f8157c5fd6578d736447998640b52e5cef8174cadc2
\ No newline at end of file
index 91eb44b8eba9ae61ec0c9bc9f5fe9269d6eaed31..1ddcca819fd3a519100b5596796c3ea7039ce3d6 100644 (file)
@@ -3200,6 +3200,13 @@ void sqlite3ExprCacheStore(Parse *pParse, int iTab, int iCol, int iReg){
   }
 #endif
 
+#ifdef SQLITE_DEBUG_COLUMNCACHE
+  /* Add a SetTabCol opcode for run-time verification that the column
+  ** cache is working correctly.
+  */
+  sqlite3VdbeAddOp3(pParse->pVdbe, OP_SetTabCol, iTab, iCol, iReg);
+#endif
+
   /* If the cache is already full, delete the least recently used entry */
   if( pParse->nColCache>=SQLITE_N_COLCACHE ){
     minLru = 0x7fffffff;
@@ -3373,6 +3380,9 @@ int sqlite3ExprCodeGetColumn(
     if( p->iTable==iTable && p->iColumn==iColumn ){
       p->lru = pParse->iCacheCnt++;
       sqlite3ExprCachePinRegister(pParse, p->iReg);
+#ifdef SQLITE_DEBUG_COLUMNCACHE
+      sqlite3VdbeAddOp3(v, OP_VerifyTabCol, iTable, iColumn, p->iReg);
+#endif
       return p->iReg;
     }
   }  
index 98bd7e407908be954a91634693b479b40731f1cb..61804670057a28ff5a08ae6ed78289337342b7cf 100644 (file)
 # undef NDEBUG
 #endif
 
+/* SQLITE_DEBUG_COLUMNCACHE is synomous with SQLITE_DEBUG.  The 
+** SQLITE_DEBUG_COLUMNCACHE symbol only exists to provide a convenient
+** way to search for all code that deals with verifying correct behavior
+** of the column cache.
+*/
+#ifdef SQLITE_DEBUG
+# define SQLITE_DEBUG_COLUMNCACHE 1
+#else
+# undef SQLIT_DEBUG_COLUMNCACHE
+#endif
+
 /*
 ** Enable SQLITE_ENABLE_EXPLAIN_COMMENTS if SQLITE_DEBUG is turned on.
 */
index 243e4fe70a52d54aca5b4539c679510af5e9d247..f65068672cd050aa5635f740cd53d1fe3e63fc83 100644 (file)
 # define memAboutToChange(P,M)
 #endif
 
+/*
+** Given a cursor number and a column for a table or index, compute a
+** hash value for use in the Mem.iTabColHash value.  The iTabColHash
+** column is only used for verification - it is omitted from production
+** builds.  Collisions are harmless in the sense that the correct answer
+** still results.  The only harm of collisions is that they can potential
+** reduce column-cache error detection during SQLITE_DEBUG builds.
+**
+** No valid hash should be 0.
+*/
+#define TableColumnHash(T,C)  (((u32)(T)<<16)^(u32)(C+2))
+
 /*
 ** The following global variable is incremented every time a cursor
 ** moves, either by the OP_SeekXX, OP_Next, or OP_Prev opcodes.  The test
@@ -7318,6 +7330,34 @@ case OP_Abortable: {
 }
 #endif
 
+#ifdef SQLITE_DEBUG_COLUMNCACHE
+/* Opcode:  SetTabCol   P1 P2 P3 * *
+**
+** Set a flag in register REG[P3] indicating that it holds the value
+** of column P2 from the table on cursor P1.  This flag is checked
+** by a subsequent VerifyTabCol opcode.
+**
+** This opcode only appears SQLITE_DEBUG builds.  It is used to verify
+** that the expression table column cache is working correctly.
+*/
+case OP_SetTabCol: {
+  aMem[pOp->p3].iTabColHash = TableColumnHash(pOp->p1,pOp->p2);
+  break;
+}
+/* Opcode:  VerifyTabCol   P1 P2 P3 * *
+**
+** Verify that register REG[P3] contains the value of column P2 from
+** cursor P1.  Assert() if this is not the case.
+**
+** This opcode only appears SQLITE_DEBUG builds.  It is used to verify
+** that the expression table column cache is working correctly.
+*/
+case OP_VerifyTabCol: {
+  assert( aMem[pOp->p3].iTabColHash == TableColumnHash(pOp->p1,pOp->p2) );
+  break;
+}
+#endif
+
 /* Opcode: Noop * * * * *
 **
 ** Do nothing.  This instruction is often useful as a jump
index b7f960f766b16f735e7116e3bef91c55ba9a7be3..51995e384c38e558374af0bc16fac2b386430caa 100644 (file)
@@ -343,4 +343,8 @@ void sqlite3VdbeScanStatus(Vdbe*, int, int, int, LogEst, const char*);
 # define sqlite3VdbeScanStatus(a,b,c,d,e)
 #endif
 
+#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
+void sqlite3VdbePrintOp(FILE*, int, VdbeOp*);
+#endif
+
 #endif /* SQLITE_VDBE_H */
index dd8e29108a2058cc4027d1af9437cdcd5d140e42..c883ce8b506ed0e9c3faa783b7d55d10ce90c1c9 100644 (file)
@@ -211,6 +211,9 @@ struct sqlite3_value {
   Mem *pScopyFrom;    /* This Mem is a shallow copy of pScopyFrom */
   void *pFiller;      /* So that sizeof(Mem) is a multiple of 8 */
 #endif
+#ifdef SQLITE_DEBUG_COLUMNCACHE
+  u32 iTabColHash;    /* Hash of table.column that is origin of this value */
+#endif
 };
 
 /*
@@ -449,9 +452,6 @@ void sqlite3VdbeFreeCursor(Vdbe *, VdbeCursor*);
 void sqliteVdbePopStack(Vdbe*,int);
 int sqlite3VdbeCursorMoveto(VdbeCursor**, int*);
 int sqlite3VdbeCursorRestore(VdbeCursor*);
-#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
-void sqlite3VdbePrintOp(FILE*, int, Op*);
-#endif
 u32 sqlite3VdbeSerialTypeLen(u32);
 u8 sqlite3VdbeOneByteSerialTypeLen(u8);
 u32 sqlite3VdbeSerialType(Mem*, int, u32*);
index c0984317b9cda413f682dbe33166739914bc895e..856cad764932ea7bd7e923c510983e267993a621 100644 (file)
@@ -1613,7 +1613,7 @@ void sqlite3VdbeLeave(Vdbe *p){
 /*
 ** Print a single opcode.  This routine is used for debugging only.
 */
-void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){
+void sqlite3VdbePrintOp(FILE *pOut, int pc, VdbeOp *pOp){
   char *zP4;
   char zPtr[50];
   char zCom[100];
index 4759823417eaf9070acb2ff3a77c3fdf5966f323..5ce4bca79d41394426a1e9a89434f3e51052fd80 100644 (file)
@@ -905,6 +905,9 @@ void sqlite3VdbeMemAboutToChange(Vdbe *pVdbe, Mem *pMem){
     }
   }
   pMem->pScopyFrom = 0;
+#ifdef SQLITE_DEBUG_COLUMN_CACHE
+  pMem->iTabColHash = 0;
+#endif
 }
 #endif /* SQLITE_DEBUG */
 
@@ -925,6 +928,9 @@ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){
   assert( pTo->db==pFrom->db );
   if( VdbeMemDynamic(pTo) ){ vdbeClrCopy(pTo,pFrom,srcType); return; }
   memcpy(pTo, pFrom, MEMCELLSIZE);
+#ifdef SQLITE_DEBUG_COLUMNCACHE
+  pTo->iTabColHash = pFrom->iTabColHash;
+#endif
   if( (pFrom->flags&MEM_Static)==0 ){
     pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Ephem);
     assert( srcType==MEM_Ephem || srcType==MEM_Static );
@@ -942,6 +948,9 @@ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
   assert( (pFrom->flags & MEM_RowSet)==0 );
   if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo);
   memcpy(pTo, pFrom, MEMCELLSIZE);
+#ifdef SQLITE_DEBUG_COLUMNCACHE
+  pTo->iTabColHash = pFrom->iTabColHash;
+#endif
   pTo->flags &= ~MEM_Dyn;
   if( pTo->flags&(MEM_Str|MEM_Blob) ){
     if( 0==(pFrom->flags&MEM_Static) ){
index 0e47dbf7ee30fe9b442c8c99b3dff0a93ea903e6..7d537159236d2291c560c0787994a5c4c5af8c2a 100644 (file)
@@ -5033,6 +5033,26 @@ whereBeginError:
   return 0;
 }
 
+/*
+** Part of sqlite3WhereEnd() will rewrite opcodes to reference the
+** index rather than the main table.  In SQLITE_DEBUG mode, we want
+** to trace those changes if PRAGMA vdbe_addoptrace=on.  This routine
+** does that.
+*/
+#ifndef SQLITE_DEBUG
+# define OpcodeRewriteTrace(D,K,P) /* no-op */
+#else
+# define OpcodeRewriteTrace(D,K,P) sqlite3WhereOpcodeRewriteTrace(D,K,P)
+  static void sqlite3WhereOpcodeRewriteTrace(
+    sqlite3 *db,
+    int pc,
+    VdbeOp *pOp
+  ){
+    if( (db->flags & SQLITE_VdbeAddopTrace)==0 ) return;
+    sqlite3VdbePrintOp(0, pc, pOp);
+  }
+#endif
+
 /*
 ** Generate the end of the WHERE loop.  See comments on 
 ** sqlite3WhereBegin() for additional information.
@@ -5201,6 +5221,11 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
     ){
       last = sqlite3VdbeCurrentAddr(v);
       k = pLevel->addrBody;
+#ifdef SQLITE_DEBUG
+      if( db->flags & SQLITE_VdbeAddopTrace ){
+        printf("TRANSLATE opcodes in range %d..%d\n", k, last-1);
+      }
+#endif
       pOp = sqlite3VdbeGetOp(v, k);
       for(; k<last; k++, pOp++){
         if( pOp->p1!=pLevel->iTabCur ) continue;
@@ -5220,16 +5245,22 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
           if( x>=0 ){
             pOp->p2 = x;
             pOp->p1 = pLevel->iIdxCur;
+            OpcodeRewriteTrace(db, k, pOp);
           }
           assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 || x>=0 
               || pWInfo->eOnePass );
         }else if( pOp->opcode==OP_Rowid ){
           pOp->p1 = pLevel->iIdxCur;
           pOp->opcode = OP_IdxRowid;
+          OpcodeRewriteTrace(db, k, pOp);
         }else if( pOp->opcode==OP_IfNullRow ){
           pOp->p1 = pLevel->iIdxCur;
+          OpcodeRewriteTrace(db, k, pOp);
         }
       }
+#ifdef SQLITE_DEBUG
+      if( db->flags & SQLITE_VdbeAddopTrace ) printf("TRANSLATE complete\n");
+#endif
     }
   }