-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
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
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
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
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
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
-793e942205a12eedb7ecc5ad8a27e3e52bbd4e1d50a0d1453d04a83ba728884e
\ No newline at end of file
+b37614a3670770919a7c7f8157c5fd6578d736447998640b52e5cef8174cadc2
\ No newline at end of file
}
#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;
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;
}
}
# 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.
*/
# 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
}
#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
# 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 */
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
};
/*
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*);
/*
** 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];
}
}
pMem->pScopyFrom = 0;
+#ifdef SQLITE_DEBUG_COLUMN_CACHE
+ pMem->iTabColHash = 0;
+#endif
}
#endif /* SQLITE_DEBUG */
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 );
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) ){
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.
){
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;
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
}
}