-C Cherrypick\sthe\srecursion\sfix\sto\stest_vfs.c\sfrom\s[065e5a5ea4f82].\nAlso\sfix\sthe\snan.test\smodule\sto\shandle\supper/lower\scase\schanges\sin\sTCL.
-D 2011-08-26T17:17:50.794
+C Cherrypick\schanges\s[53f5cfe115]\sand\s[1f7ef0af8d]\sin\sorder\sto\sfix\san\sissue\swith\sDISTINCT
+D 2011-10-25T20:36:39.155
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 543f91f24cd7fee774ecc0a61c19704c0c3e78fd
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F src/ctime.c 2e39d3374e785a63117e077bcba9d4a6656df363
F src/date.c 5dd8448a0bfea8d31fb14cff487d0c06ff8c8b20
F src/delete.c daff6cef77fe8ed57b8acfc5ecebce28244af2fa
-F src/expr.c c0d7088c13c9cee74043606a41dcc4696a9ea7cc
+F src/expr.c 9c8147b9c2ffcd792191bad51028bf11719bac09
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
-F src/fkey.c d56da9f698067e52a45736e97b17ee01cd849b78
+F src/fkey.c ca7cdb310a5095ce2b304c6524260595f73827dc
F src/func.c 464b0dc70618b896c402c574eb04bc5eacf35341
F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3
F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
F src/resolve.c 36368f44569208fa074e61f4dd0b6c4fb60ca2b4
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
-F src/select.c 27ceaf3ae2c493d299adec578bbc9e397ebf2806
+F src/select.c a9828845d04c1f583b9fb5260c0cab33da88d16e
F src/shell.c 8517fc1f9c59ae4007e6cc8b9af91ab231ea2056
F src/sqlite.h.in 2d72a6242df41c517e38eec8791abcf5484a36f1
F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
-F src/sqliteInt.h 0e4a570a645e4e9005ef44e5178ad59755e33623
+F src/sqliteInt.h e679eece2fb35bb324a56d614d91ccf961f70cf4
F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
F src/status.c 496913d4e8441195f6f2a75b1c95993a45b9b30b
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
F src/util.c 32aebf04c10e51ad3977a928b7416bed671b620b
F src/vacuum.c 241a8386727c1497eba4955933356dfba6ff8c9f
-F src/vdbe.c 67486fbf9c5b8bb5a43ed7b7075cbaf2443b5a98
+F src/vdbe.c 5fdbad94b51569c84189a6824ed98d1ec0695174
F src/vdbe.h 4de0efb4b0fdaaa900cf419b35c458933ef1c6d2
-F src/vdbeInt.h a247bd5448039e83394bf4179975b2ae0092874c
+F src/vdbeInt.h 7f4cf1b2b69bef3a432b1f23dfebef57275436b4
F src/vdbeapi.c d0f4407e465f261780ad725c1caece7d66a6aa35
F src/vdbeaux.c 157d62a6a8ca22c3792f5957e887df8bda2d58eb
F src/vdbeblob.c 258a6010ba7a82b72b327fb24c55790655689256
-F src/vdbemem.c c9f3bba5f81d3b4cbe9f8f7ed4fc7b9d50f3536e
+F src/vdbemem.c c9faa98e4127185b0b7be27d0fa79d802a0dc40e
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
F src/vtab.c 0e8e0cb30dffb078367e843e84e37ef99236c7e4
F src/wal.c 5ac2119e23ee4424599d4275b66dc88d612a0543
F test/tkt-80e031a00f.test 9a154173461a4dbe2de49cda73963e04842d52f7
F test/tkt-94c04eaadb.test be5ea61cb04dfdc047d19b5c5a9e75fa3da67a7f
F test/tkt-9d68c883.test 458f7d82a523d7644b54b497c986378a7d8c8b67
+F test/tkt-b351d95f9.test d14a503c414c5c58fdde3e80f9a3cfef986498c0
F test/tkt-cbd054fa6b.test f14f97ea43662e6f70c9e63287081e8be5d9d589
F test/tkt-d11f09d36e.test fb44f7961aa6d4b632fb7b9768239832210b5fc7
F test/tkt-d82e3f3721.test 731359dfdcdb36fea0559cd33fec39dd0ceae8e6
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P d55b64ef7e04e10a31360dea55751a33a0d591a4
-R 9b91be012c6fe7c568f3cf1c45e2011e
+P 41b5f86971ed9d7ddca31bd9b43d0a41f03f002b
+R 21abcfcc965121f7efbad8f281615142
U drh
-Z 5a1720d89ddb619a80580f5e81a47527
+Z 1aced37d95114768e299b980f9a55bae
-41b5f86971ed9d7ddca31bd9b43d0a41f03f002b
\ No newline at end of file
+14bc58ca70336aed62069f223324304835991c55
\ No newline at end of file
}
#endif /* SQLITE_DEBUG || SQLITE_COVERAGE_TEST */
-/*
-** If the last instruction coded is an ephemeral copy of any of
-** the registers in the nReg registers beginning with iReg, then
-** convert the last instruction from OP_SCopy to OP_Copy.
-*/
-void sqlite3ExprHardCopy(Parse *pParse, int iReg, int nReg){
- VdbeOp *pOp;
- Vdbe *v;
-
- assert( pParse->db->mallocFailed==0 );
- v = pParse->pVdbe;
- assert( v!=0 );
- pOp = sqlite3VdbeGetOp(v, -1);
- assert( pOp!=0 );
- if( pOp->opcode==OP_SCopy && pOp->p1>=iReg && pOp->p1<iReg+nReg ){
- pOp->opcode = OP_Copy;
- }
-}
-
-/*
-** Generate code to store the value of the iAlias-th alias in register
-** target. The first time this is called, pExpr is evaluated to compute
-** the value of the alias. The value is stored in an auxiliary register
-** and the number of that register is returned. On subsequent calls,
-** the register number is returned without generating any code.
-**
-** Note that in order for this to work, code must be generated in the
-** same order that it is executed.
-**
-** Aliases are numbered starting with 1. So iAlias is in the range
-** of 1 to pParse->nAlias inclusive.
-**
-** pParse->aAlias[iAlias-1] records the register number where the value
-** of the iAlias-th alias is stored. If zero, that means that the
-** alias has not yet been computed.
-*/
-static int codeAlias(Parse *pParse, int iAlias, Expr *pExpr, int target){
-#if 0
- sqlite3 *db = pParse->db;
- int iReg;
- if( pParse->nAliasAlloc<pParse->nAlias ){
- pParse->aAlias = sqlite3DbReallocOrFree(db, pParse->aAlias,
- sizeof(pParse->aAlias[0])*pParse->nAlias );
- testcase( db->mallocFailed && pParse->nAliasAlloc>0 );
- if( db->mallocFailed ) return 0;
- memset(&pParse->aAlias[pParse->nAliasAlloc], 0,
- (pParse->nAlias-pParse->nAliasAlloc)*sizeof(pParse->aAlias[0]));
- pParse->nAliasAlloc = pParse->nAlias;
- }
- assert( iAlias>0 && iAlias<=pParse->nAlias );
- iReg = pParse->aAlias[iAlias-1];
- if( iReg==0 ){
- if( pParse->iCacheLevel>0 ){
- iReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
- }else{
- iReg = ++pParse->nMem;
- sqlite3ExprCode(pParse, pExpr, iReg);
- pParse->aAlias[iAlias-1] = iReg;
- }
- }
- return iReg;
-#else
- UNUSED_PARAMETER(iAlias);
- return sqlite3ExprCodeTarget(pParse, pExpr, target);
-#endif
-}
-
/*
** Generate code into the current Vdbe to evaluate the given
** expression. Attempt to store the results in register "target".
break;
}
case TK_AS: {
- inReg = codeAlias(pParse, pExpr->iTable, pExpr->pLeft, target);
+ inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
break;
}
#ifndef SQLITE_OMIT_CAST
opCompare.op = TK_EQ;
opCompare.pLeft = &cacheX;
pTest = &opCompare;
+ /* Ticket b351d95f9cd5ef17e9d9dbae18f5ca8611190001:
+ ** The value in regFree1 might get SCopy-ed into the file result.
+ ** So make sure that the regFree1 register is not reused for other
+ ** purposes and possibly overwritten. */
+ regFree1 = 0;
}
for(i=0; i<nExpr; i=i+2){
sqlite3ExprCachePush(pParse);
int inReg;
assert( target>0 && target<=pParse->nMem );
- inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
- assert( pParse->pVdbe || pParse->db->mallocFailed );
- if( inReg!=target && pParse->pVdbe ){
- sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target);
+ if( pExpr && pExpr->op==TK_REGISTER ){
+ sqlite3VdbeAddOp2(pParse->pVdbe, OP_Copy, pExpr->iTable, target);
+ }else{
+ inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
+ assert( pParse->pVdbe || pParse->db->mallocFailed );
+ if( inReg!=target && pParse->pVdbe ){
+ sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, inReg, target);
+ }
}
return target;
}
int i, n;
assert( pList!=0 );
assert( target>0 );
+ assert( pParse->pVdbe!=0 ); /* Never gets this far otherwise */
n = pList->nExpr;
for(pItem=pList->a, i=0; i<n; i++, pItem++){
- if( pItem->iAlias ){
- int iReg = codeAlias(pParse, pItem->iAlias, pItem->pExpr, target+i);
- Vdbe *v = sqlite3GetVdbe(pParse);
- if( iReg!=target+i ){
- sqlite3VdbeAddOp2(v, OP_SCopy, iReg, target+i);
- }
- }else{
- sqlite3ExprCode(pParse, pItem->pExpr, target+i);
- }
- if( doHardCopy && !pParse->db->mallocFailed ){
- sqlite3ExprHardCopy(pParse, target, n);
+ Expr *pExpr = pItem->pExpr;
+ int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
+ if( inReg!=target+i ){
+ sqlite3VdbeAddOp2(pParse->pVdbe, doHardCopy ? OP_Copy : OP_SCopy,
+ inReg, target+i);
}
}
return n;
sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb);
sqlite3VdbeChangeP4(v, -1, (char*)pKey, P4_KEYINFO_HANDOFF);
for(i=0; i<nCol; i++){
- sqlite3VdbeAddOp2(v, OP_SCopy, aiCol[i]+1+regData, regTemp+i);
+ sqlite3VdbeAddOp2(v, OP_Copy, aiCol[i]+1+regData, regTemp+i);
}
/* If the parent table is the same as the child table, and we are about
if( pList ){
nArg = pList->nExpr;
regAgg = sqlite3GetTempRange(pParse, nArg);
- sqlite3ExprCodeExprList(pParse, pList, regAgg, 0);
+ sqlite3ExprCodeExprList(pParse, pList, regAgg, 1);
}else{
nArg = 0;
regAgg = 0;
void sqlite3ExprCacheRemove(Parse*, int, int);
void sqlite3ExprCacheClear(Parse*);
void sqlite3ExprCacheAffinityChange(Parse*, int, int);
-void sqlite3ExprHardCopy(Parse*,int,int);
int sqlite3ExprCode(Parse*, Expr*, int);
int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
int sqlite3ExprCodeTarget(Parse*, Expr*, int);
#include "sqliteInt.h"
#include "vdbeInt.h"
+/*
+** Invoke this macro on memory cells just prior to changing the
+** value of the cell. This macro verifies that shallow copies are
+** not misused.
+*/
+#ifdef SQLITE_DEBUG
+# define memAboutToChange(P,M) sqlite3VdbeMemPrepareToChange(P,M)
+#else
+# define memAboutToChange(P,M)
+#endif
+
/*
** The following global variable is incremented every time a cursor
** moves, either by the OP_SeekXX, OP_Next, or OP_Prev opcodes. The test
assert( pOp->p2>0 );
assert( pOp->p2<=p->nMem );
pOut = &aMem[pOp->p2];
+ memAboutToChange(p, pOut);
sqlite3VdbeMemReleaseExternal(pOut);
pOut->flags = MEM_Int;
}
if( (pOp->opflags & OPFLG_IN1)!=0 ){
assert( pOp->p1>0 );
assert( pOp->p1<=p->nMem );
+ assert( memIsValid(&aMem[pOp->p1]) );
REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]);
}
if( (pOp->opflags & OPFLG_IN2)!=0 ){
assert( pOp->p2>0 );
assert( pOp->p2<=p->nMem );
+ assert( memIsValid(&aMem[pOp->p2]) );
REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]);
}
if( (pOp->opflags & OPFLG_IN3)!=0 ){
assert( pOp->p3>0 );
assert( pOp->p3<=p->nMem );
+ assert( memIsValid(&aMem[pOp->p3]) );
REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]);
}
if( (pOp->opflags & OPFLG_OUT2)!=0 ){
assert( pOp->p2>0 );
assert( pOp->p2<=p->nMem );
+ memAboutToChange(p, &aMem[pOp->p2]);
}
if( (pOp->opflags & OPFLG_OUT3)!=0 ){
assert( pOp->p3>0 );
assert( pOp->p3<=p->nMem );
+ memAboutToChange(p, &aMem[pOp->p3]);
}
#endif
case OP_Gosub: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
assert( (pIn1->flags & MEM_Dyn)==0 );
+ memAboutToChange(p, pIn1);
pIn1->flags = MEM_Int;
pIn1->u.i = pc;
REGISTER_TRACE(pOp->p1, pIn1);
while( n-- ){
assert( pOut<=&aMem[p->nMem] );
assert( pIn1<=&aMem[p->nMem] );
+ assert( memIsValid(pIn1) );
+ memAboutToChange(p, pOut);
zMalloc = pOut->zMalloc;
pOut->zMalloc = 0;
sqlite3VdbeMemMove(pOut, pIn1);
pOut = &aMem[pOp->p2];
assert( pOut!=pIn1 );
sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem);
+#ifdef SQLITE_DEBUG
+ if( pOut->pScopyFrom==0 ) pOut->pScopyFrom = pIn1;
+#endif
REGISTER_TRACE(pOp->p2, pOut);
break;
}
*/
pMem = p->pResultSet = &aMem[pOp->p1];
for(i=0; i<pOp->p2; i++){
+ assert( memIsValid(&pMem[i]) );
+ Deephemeralize(&pMem[i]);
+ assert( (pMem[i].flags & MEM_Ephem)==0
+ || (pMem[i].flags & (MEM_Str|MEM_Blob))==0 );
sqlite3VdbeMemNulTerminate(&pMem[i]);
sqlite3VdbeMemStoreType(&pMem[i]);
REGISTER_TRACE(pOp->p1+i, &pMem[i]);
n = pOp->p5;
apVal = p->apArg;
assert( apVal || n==0 );
+ assert( pOp->p3>0 && pOp->p3<=p->nMem );
+ pOut = &aMem[pOp->p3];
+ memAboutToChange(p, pOut);
assert( n==0 || (pOp->p2>0 && pOp->p2+n<=p->nMem+1) );
assert( pOp->p3<pOp->p2 || pOp->p3>=pOp->p2+n );
pArg = &aMem[pOp->p2];
for(i=0; i<n; i++, pArg++){
+ assert( memIsValid(pArg) );
apVal[i] = pArg;
+ Deephemeralize(pArg);
sqlite3VdbeMemStoreType(pArg);
REGISTER_TRACE(pOp->p2+i, pArg);
}
ctx.pFunc = ctx.pVdbeFunc->pFunc;
}
- assert( pOp->p3>0 && pOp->p3<=p->nMem );
- pOut = &aMem[pOp->p3];
ctx.s.flags = MEM_Null;
ctx.s.db = db;
ctx.s.xDel = 0;
*/
case OP_AddImm: { /* in1 */
pIn1 = &aMem[pOp->p1];
+ memAboutToChange(p, pIn1);
sqlite3VdbeMemIntegerify(pIn1);
pIn1->u.i += pOp->p2;
break;
*/
case OP_MustBeInt: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
+ memAboutToChange(p, pIn1);
applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding);
if( (pIn1->flags & MEM_Int)==0 ){
if( pOp->p2==0 ){
*/
case OP_RealAffinity: { /* in1 */
pIn1 = &aMem[pOp->p1];
+ memAboutToChange(p, pIn1);
if( pIn1->flags & MEM_Int ){
sqlite3VdbeMemRealify(pIn1);
}
*/
case OP_ToText: { /* same as TK_TO_TEXT, in1 */
pIn1 = &aMem[pOp->p1];
+ memAboutToChange(p, pIn1);
if( pIn1->flags & MEM_Null ) break;
assert( MEM_Str==(MEM_Blob>>3) );
pIn1->flags |= (pIn1->flags&MEM_Blob)>>3;
*/
case OP_ToBlob: { /* same as TK_TO_BLOB, in1 */
pIn1 = &aMem[pOp->p1];
+ memAboutToChange(p, pIn1);
if( pIn1->flags & MEM_Null ) break;
if( (pIn1->flags & MEM_Blob)==0 ){
applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding);
*/
case OP_ToNumeric: { /* same as TK_TO_NUMERIC, in1 */
pIn1 = &aMem[pOp->p1];
+ memAboutToChange(p, pIn1);
if( (pIn1->flags & (MEM_Null|MEM_Int|MEM_Real))==0 ){
sqlite3VdbeMemNumerify(pIn1);
}
*/
case OP_ToInt: { /* same as TK_TO_INT, in1 */
pIn1 = &aMem[pOp->p1];
+ memAboutToChange(p, pIn1);
if( (pIn1->flags & MEM_Null)==0 ){
sqlite3VdbeMemIntegerify(pIn1);
}
*/
case OP_ToReal: { /* same as TK_TO_REAL, in1 */
pIn1 = &aMem[pOp->p1];
+ memAboutToChange(p, pIn1);
if( (pIn1->flags & MEM_Null)==0 ){
sqlite3VdbeMemRealify(pIn1);
}
pIn1 = &aMem[pOp->p1];
pIn3 = &aMem[pOp->p3];
+ memAboutToChange(p, pIn1);
+ memAboutToChange(p, pIn3);
flags1 = pIn1->flags;
flags3 = pIn3->flags;
if( (pIn1->flags | pIn3->flags)&MEM_Null ){
if( pOp->p5 & SQLITE_STOREP2 ){
pOut = &aMem[pOp->p2];
+ memAboutToChange(p, pOut);
MemSetTypeFlag(pOut, MEM_Int);
pOut->u.i = res;
REGISTER_TRACE(pOp->p2, pOut);
#endif /* SQLITE_DEBUG */
for(i=0; i<n; i++){
idx = aPermute ? aPermute[i] : i;
+ assert( memIsValid(&aMem[p1+idx]) );
+ assert( memIsValid(&aMem[p2+idx]) );
REGISTER_TRACE(p1+idx, &aMem[p1+idx]);
REGISTER_TRACE(p2+idx, &aMem[p2+idx]);
assert( i<pKeyInfo->nField );
assert( p1<p->nCursor );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
pDest = &aMem[pOp->p3];
+ memAboutToChange(p, pDest);
MemSetTypeFlag(pDest, MEM_Null);
zRec = 0;
}else if( pC->pseudoTableReg>0 ){
pReg = &aMem[pC->pseudoTableReg];
assert( pReg->flags & MEM_Blob );
+ assert( memIsValid(pReg) );
payloadSize = pReg->n;
zRec = pReg->z;
pC->cacheStatus = (pOp->p5&OPFLAG_CLEARCACHE) ? CACHE_STALE : p->cacheCtr;
pIn1 = &aMem[pOp->p1];
while( (cAff = *(zAffinity++))!=0 ){
assert( pIn1 <= &p->aMem[p->nMem] );
+ assert( memIsValid(pIn1) );
+ memAboutToChange(p, pIn1);
ExpandBlob(pIn1);
applyAffinity(pIn1, cAff, encoding);
pIn1++;
pLast = &pData0[nField-1];
file_format = p->minWriteFileFormat;
+ /* Identify the output register */
+ assert( pOp->p3<pOp->p1 || pOp->p3>=pOp->p1+pOp->p2 );
+ pOut = &aMem[pOp->p3];
+ memAboutToChange(p, pOut);
+
/* Loop through the elements that will make up the record to figure
** out how much space is required for the new record.
*/
for(pRec=pData0; pRec<=pLast; pRec++){
+ assert( memIsValid(pRec) );
if( zAffinity ){
+ memAboutToChange(p, pRec);
applyAffinity(pRec, zAffinity[pRec-pData0], encoding);
}
if( pRec->flags&MEM_Zero && pRec->n>0 ){
** be one of the input registers (because the following call to
** sqlite3VdbeMemGrow() could clobber the value before it is used).
*/
- assert( pOp->p3<pOp->p1 || pOp->p3>=pOp->p1+pOp->p2 );
- pOut = &aMem[pOp->p3];
if( sqlite3VdbeMemGrow(pOut, (int)nByte, 0) ){
goto no_mem;
}
assert( p2>0 );
assert( p2<=p->nMem );
pIn2 = &aMem[p2];
+ assert( memIsValid(pIn2) );
+ assert( (pIn2->flags & MEM_Int)!=0 );
sqlite3VdbeMemIntegerify(pIn2);
p2 = (int)pIn2->u.i;
/* The p2 value always comes from a prior OP_CreateTable opcode and
assert( oc!=OP_SeekLt || r.flags==0 );
r.aMem = &aMem[pOp->p3];
+#ifdef SQLITE_DEBUG
+ { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
+#endif
ExpandBlob(r.aMem);
rc = sqlite3BtreeMovetoUnpacked(pC->pCursor, &r, 0, 0, &res);
if( rc!=SQLITE_OK ){
r.pKeyInfo = pC->pKeyInfo;
r.nField = (u16)pOp->p4.i;
r.aMem = pIn3;
+#ifdef SQLITE_DEBUG
+ { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
+#endif
r.flags = UNPACKED_PREFIX_MATCH;
pIdxKey = &r;
}else{
assert( pIn3->flags & MEM_Blob );
- ExpandBlob(pIn3);
+ assert( (pIn3->flags & MEM_Zero)==0 ); /* zeroblobs already expanded */
pIdxKey = sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z,
aTempRec, sizeof(aTempRec));
if( pIdxKey==0 ){
r.nField = nField + 1;
r.flags = UNPACKED_PREFIX_SEARCH;
r.aMem = aMx;
+#ifdef SQLITE_DEBUG
+ { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
+#endif
/* Extract the value of R from register P3. */
sqlite3VdbeMemIntegerify(pIn3);
/* Assert that P3 is a valid memory cell. */
assert( pOp->p3<=p->nMem );
pMem = &aMem[pOp->p3];
+ memAboutToChange(p, pMem);
}
+ assert( memIsValid(pMem) );
REGISTER_TRACE(pOp->p3, pMem);
sqlite3VdbeMemIntegerify(pMem);
pData = &aMem[pOp->p2];
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ assert( memIsValid(pData) );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
assert( pC->pCursor!=0 );
if( pOp->opcode==OP_Insert ){
pKey = &aMem[pOp->p3];
assert( pKey->flags & MEM_Int );
+ assert( memIsValid(pKey) );
REGISTER_TRACE(pOp->p3, pKey);
iKey = pKey->u.i;
}else{
i64 n64;
pOut = &aMem[pOp->p2];
+ memAboutToChange(p, pOut);
/* Note that RowKey and RowData are really exactly the same instruction */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
r.nField = (u16)pOp->p3;
r.flags = 0;
r.aMem = &aMem[pOp->p2];
+#ifdef SQLITE_DEBUG
+ { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
+#endif
rc = sqlite3BtreeMovetoUnpacked(pCrsr, &r, 0, 0, &res);
if( rc==SQLITE_OK && res==0 ){
rc = sqlite3BtreeDelete(pCrsr);
r.flags = UNPACKED_IGNORE_ROWID;
}
r.aMem = &aMem[pOp->p3];
+#ifdef SQLITE_DEBUG
+ { int i; for(i=0; i<r.nField; i++) assert( memIsValid(&r.aMem[i]) ); }
+#endif
rc = sqlite3VdbeIdxKeyCompare(pC, &r, &res);
if( pOp->opcode==OP_IdxLT ){
res = -res;
if( pOp->p3 ){
p->nChange += nChange;
if( pOp->p3>0 ){
+ assert( memIsValid(&aMem[pOp->p3]) );
+ memAboutToChange(p, &aMem[pOp->p3]);
aMem[pOp->p3].u.i += nChange;
}
}
pProgram = pOp->p4.pProgram;
pRt = &aMem[pOp->p3];
+ assert( memIsValid(pRt) );
assert( pProgram->nOp>0 );
/* If the p5 flag is clear, then recursive invocation of triggers is
}else{
pIn1 = &aMem[pOp->p1];
}
+ assert( memIsValid(pIn1) );
sqlite3VdbeMemIntegerify(pIn1);
pIn2 = &aMem[pOp->p2];
sqlite3VdbeMemIntegerify(pIn2);
apVal = p->apArg;
assert( apVal || n==0 );
for(i=0; i<n; i++, pRec++){
+ assert( memIsValid(pRec) );
apVal[i] = pRec;
+ memAboutToChange(p, pRec);
sqlite3VdbeMemStoreType(pRec);
}
ctx.pFunc = pOp->p4.pFunc;
pQuery = &aMem[pOp->p3];
pArgc = &pQuery[1];
pCur = p->apCsr[pOp->p1];
+ assert( memIsValid(pQuery) );
REGISTER_TRACE(pOp->p3, pQuery);
assert( pCur->pVtabCursor );
pVtabCursor = pCur->pVtabCursor;
assert( pCur->pVtabCursor );
assert( pOp->p3>0 && pOp->p3<=p->nMem );
pDest = &aMem[pOp->p3];
+ memAboutToChange(p, pDest);
if( pCur->nullRow ){
sqlite3VdbeMemSetNull(pDest);
break;
pVtab = pOp->p4.pVtab->pVtab;
pName = &aMem[pOp->p1];
assert( pVtab->pModule->xRename );
+ assert( memIsValid(pName) );
REGISTER_TRACE(pOp->p1, pName);
assert( pName->flags & MEM_Str );
rc = pVtab->pModule->xRename(pVtab, pName->z);
apArg = p->apArg;
pX = &aMem[pOp->p3];
for(i=0; i<nArg; i++){
+ assert( memIsValid(pX) );
+ memAboutToChange(p, pX);
sqlite3VdbeMemStoreType(pX);
apArg[i] = pX;
pX++;
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
u8 type; /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */
u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
+#ifdef SQLITE_DEBUG
+ Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */
+ void *pFiller; /* So that sizeof(Mem) is a multiple of 8 */
+#endif
void (*xDel)(void *); /* If not null, call this function to delete Mem.z */
char *zMalloc; /* Dynamic buffer allocated by sqlite3_malloc() */
};
#define MEM_Blob 0x0010 /* Value is a BLOB */
#define MEM_RowSet 0x0020 /* Value is a RowSet object */
#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */
+#define MEM_Invalid 0x0080 /* Value is undefined */
#define MEM_TypeMask 0x00ff /* Mask of type bits */
/* Whenever Mem contains a valid string or blob representation, one of
#define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */
#define MEM_Agg 0x2000 /* Mem.z points to an agg function context */
#define MEM_Zero 0x4000 /* Mem.i contains count of 0s appended to blob */
-
#ifdef SQLITE_OMIT_INCRBLOB
#undef MEM_Zero
#define MEM_Zero 0x0000
#endif
-
/*
** Clear any existing type flags from a Mem and replace them with f
*/
#define MemSetTypeFlag(p, f) \
((p)->flags = ((p)->flags&~(MEM_TypeMask|MEM_Zero))|f)
+/*
+** Return true if a memory cell is not marked as invalid. This macro
+** is for use inside assert() statements only.
+*/
+#ifdef SQLITE_DEBUG
+#define memIsValid(M) ((M)->flags & MEM_Invalid)==0
+#endif
+
/* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains
** additional information about auxiliary information bound to arguments
int sqlite3VdbeFrameRestore(VdbeFrame *);
void sqlite3VdbeMemStoreType(Mem *pMem);
+#ifdef SQLITE_DEBUG
+void sqlite3VdbeMemPrepareToChange(Vdbe*,Mem*);
+#endif
+
#ifndef SQLITE_OMIT_FOREIGN_KEY
int sqlite3VdbeCheckFk(Vdbe *, int);
#else
pMem->z[pMem->n] = 0;
pMem->z[pMem->n+1] = 0;
pMem->flags |= MEM_Term;
+#ifdef SQLITE_DEBUG
+ pMem->pScopyFrom = 0;
+#endif
}
return SQLITE_OK;
return 0;
}
+#ifdef SQLITE_DEBUG
+/*
+** This routine prepares a memory cell for modication by breaking
+** its link to a shallow copy and by marking any current shallow
+** copies of this cell as invalid.
+**
+** This is used for testing and debugging only - to make sure shallow
+** copies are not misused.
+*/
+void sqlite3VdbeMemPrepareToChange(Vdbe *pVdbe, Mem *pMem){
+ int i;
+ Mem *pX;
+ for(i=1, pX=&pVdbe->aMem[1]; i<=pVdbe->nMem; i++, pX++){
+ if( pX->pScopyFrom==pMem ){
+ pX->flags |= MEM_Invalid;
+ pX->pScopyFrom = 0;
+ }
+ }
+ pMem->pScopyFrom = 0;
+}
+#endif /* SQLITE_DEBUG */
+
/*
** Size of struct Mem not including the Mem.zMalloc member.
*/
--- /dev/null
+# 2010 September 28
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library. Specifically,
+# it tests that ticket [b351d95f9cd5ef17e9d9dbae18f5ca8611190001] has been
+# resolved.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/lock_common.tcl
+source $testdir/malloc_common.tcl
+
+do_test tkt-b351d95.1 {
+ execsql {
+ CREATE table t1(a,b);
+ INSERT INTO t1 VALUES('name1','This is a test');
+ INSERT INTO t1 VALUES('name2','xyz');
+ CREATE TABLE t2(x,y);
+ INSERT INTO t2 SELECT a, CASE b WHEN 'xyz' THEN null ELSE b END FROM t1;
+ SELECT x, y FROM t2 ORDER BY x;
+ }
+} {name1 {This is a test} name2 {}}
+
+do_test tkt-b351d95.2 {
+ execsql {
+ DELETE FROM t2;
+ INSERT INTO t2 SELECT a, coalesce(b,a) FROM t1;
+ SELECT x, y FROM t2 ORDER BY x;
+ }
+} {name1 {This is a test} name2 xyz}
+do_test tkt-b351d95.3 {
+ execsql {
+ DELETE FROM t2;
+ INSERT INTO t2 SELECT a, coalesce(b,a) FROM t1;
+ SELECT x, y BETWEEN 'xy' AND 'xz' FROM t2 ORDER BY x;
+ }
+} {name1 0 name2 1}
+
+finish_test