diff --git a/manifest b/manifest index d7aead42bc..f526ac24ae 100644 --- a/manifest +++ b/manifest @@ -1,8 +1,8 @@ -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 -C Simplifications\sto\sthe\sexpression\scode\sgenerator.\s\sRemove\sabout\s80\slines\sof\nolder\sand\sobsolete\scode. -D 2010-09-27T18:14:12 +C Merge\sfixes\sfor\sticket\s[b351d95f9cd5ef17e9d9dbae18f5ca8611190001]\sinto\s\nthe\strunk. +D 2010-09-28T07:14:03 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in c599a15d268b1db2aeadea19df2adc3bf2eb6bee F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -130,9 +130,9 @@ F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 4f3aadad62c6c9f0d4e5a96718516ac4e3c598df F src/date.c 5dd8448a0bfea8d31fb14cff487d0c06ff8c8b20 F src/delete.c 7ed8a8c8b5f748ece92df173d7e0f7810c899ebd -F src/expr.c d2ffe8ed8eed8208c3e550cfba98a2a301a64108 +F src/expr.c 1caa723c3ab7a7e35952bc85a6f4a7da3632308f F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb -F src/fkey.c 58bbf52c6ddd3f64ca40a3230f9e548a83a5cb16 +F src/fkey.c 17950a28f28b23e8ad3feaac5fc88c324d2f600a F src/func.c caa6c5134106d95cced4db80ce3fdcdde4f6c8d4 F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3 F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af @@ -176,7 +176,7 @@ F src/printf.c 8ae5082dd38a1b5456030c3755ec3a392cd51506 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 -F src/select.c b0b124781474e4e0c8f64022875e5e2009e13443 +F src/select.c cf3013b1953348c7c6ff9636342e87b9fda68466 F src/shell.c 8517fc1f9c59ae4007e6cc8b9af91ab231ea2056 F src/sqlite.h.in dae3f74d7b2b516967ede39b8e503718b571d9da F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89 @@ -228,13 +228,13 @@ F src/update.c 227e6cd512108b84f69421fc6c7aa1b83d60d6e0 F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685 F src/util.c 5f5f4db4e799224713582bb49124827b16aa8e54 F src/vacuum.c 924bd1bcee2dfb05376f79845bd3b4cec7b54b2f -F src/vdbe.c 1373d40f5985577a30350bfa78ebd8e1d905ee89 +F src/vdbe.c 69812aabf486a2d6a5b0960ffd9a47d141442735 F src/vdbe.h 4de0efb4b0fdaaa900cf419b35c458933ef1c6d2 -F src/vdbeInt.h a247bd5448039e83394bf4179975b2ae0092874c +F src/vdbeInt.h 7f4cf1b2b69bef3a432b1f23dfebef57275436b4 F src/vdbeapi.c 14040ffad59a9961468a457754d30266e71ebb2d F src/vdbeaux.c de0b06b11a25293e820a49159eca9f1c51a64716 F src/vdbeblob.c 258a6010ba7a82b72b327fb24c55790655689256 -F src/vdbemem.c 2b8210992499e8b846f49fa4b0035bbc2cda0ee0 +F src/vdbemem.c 8ff4f80a35d51f3690c191ec44778ef4bf949ac0 F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2 F src/vtab.c 0e8e0cb30dffb078367e843e84e37ef99236c7e4 F src/wal.c 7081f148cb52b0cf2280e6384196402dc58130a3 @@ -670,6 +670,7 @@ F test/tkt-78e04e52ea.test fb5430c675e708f5cbafdf3e7e5593da5145a527 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 @@ -870,14 +871,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P a7645d293801da64a7579737d0a8b48117af2e2c -R 31b9d8f725b1355a3ecd589f9c768e32 +P 53f5cfe11516d0496c7760378b6305c3088d479f 88b84bf18a4b27626f8a0a2d313706ddd4f13749 +R 37b3df62f8033aa4a27c3e8908502e88 U drh -Z da56ebaf0e041408b3401a85ccd2b2a6 +Z 5aec910a47bbe2ec6ed86e77486c7a25 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) -iD8DBQFMoN73oxKgR168RlERAqBjAJ4/xTLrVYlxWxhlWBOiHhf+ogrH4gCdGQFv -0abukVW0mExAm/y5XFe9a7M= -=VfNl +iD8DBQFMoZXEoxKgR168RlERAhhPAJ4jyC+TGxv3hBPL9D1deKDUOxZxAwCeMIr1 +zHDW5Z+/417ZSlRcozRFPLA= +=wL0e -----END PGP SIGNATURE----- diff --git a/manifest.uuid b/manifest.uuid index b42edba870..497e13b8ba 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -53f5cfe11516d0496c7760378b6305c3088d479f \ No newline at end of file +1f7ef0af8d9e41cd41f9046d198132eabd89ab18 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index f972bd517b..2474635218 100644 --- a/src/expr.c +++ b/src/expr.c @@ -2774,6 +2774,11 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){ 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; i0 && 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; } @@ -3043,12 +3052,12 @@ int sqlite3ExprCodeExprList( 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; ipExpr; int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i); - assert( pParse->pVdbe || pParse->db->mallocFailed ); - if( inReg!=target+i && pParse->pVdbe ){ + if( inReg!=target+i ){ sqlite3VdbeAddOp2(pParse->pVdbe, doHardCopy ? OP_Copy : OP_SCopy, inReg, target+i); } diff --git a/src/fkey.c b/src/fkey.c index f0ad40d837..a385b814ec 100644 --- a/src/fkey.c +++ b/src/fkey.c @@ -380,7 +380,7 @@ static void fkLookupParent( sqlite3VdbeAddOp3(v, OP_OpenRead, iCur, pIdx->tnum, iDb); sqlite3VdbeChangeP4(v, -1, (char*)pKey, P4_KEYINFO_HANDOFF); for(i=0; inExpr; regAgg = sqlite3GetTempRange(pParse, nArg); - sqlite3ExprCodeExprList(pParse, pList, regAgg, 0); + sqlite3ExprCodeExprList(pParse, pList, regAgg, 1); }else{ nArg = 0; regAgg = 0; diff --git a/src/vdbe.c b/src/vdbe.c index a416020984..90312cac72 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -46,6 +46,17 @@ #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 @@ -667,6 +678,7 @@ int sqlite3VdbeExec( assert( pOp->p2>0 ); assert( pOp->p2<=p->nMem ); pOut = &aMem[pOp->p2]; + memAboutToChange(p, pOut); sqlite3VdbeMemReleaseExternal(pOut); pOut->flags = MEM_Int; } @@ -676,25 +688,30 @@ int sqlite3VdbeExec( 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 @@ -756,6 +773,7 @@ case OP_Goto: { /* jump */ 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); @@ -1015,6 +1033,8 @@ case OP_Move: { 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); @@ -1060,6 +1080,9 @@ case OP_SCopy: { /* in1, out2 */ 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; } @@ -1118,6 +1141,10 @@ case OP_ResultRow: { */ pMem = p->pResultSet = &aMem[pOp->p1]; for(i=0; ip2; 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]); @@ -1343,12 +1370,17 @@ case OP_Function: { 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->p3p2 || pOp->p3>=pOp->p2+n ); pArg = &aMem[pOp->p2]; for(i=0; ip2+i, pArg); } @@ -1362,8 +1394,6 @@ case OP_Function: { 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; @@ -1483,6 +1513,7 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, in1, in2, out3 */ */ case OP_AddImm: { /* in1 */ pIn1 = &aMem[pOp->p1]; + memAboutToChange(p, pIn1); sqlite3VdbeMemIntegerify(pIn1); pIn1->u.i += pOp->p2; break; @@ -1497,6 +1528,7 @@ case OP_AddImm: { /* in1 */ */ 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 ){ @@ -1523,6 +1555,7 @@ case OP_MustBeInt: { /* jump, in1 */ */ case OP_RealAffinity: { /* in1 */ pIn1 = &aMem[pOp->p1]; + memAboutToChange(p, pIn1); if( pIn1->flags & MEM_Int ){ sqlite3VdbeMemRealify(pIn1); } @@ -1542,6 +1575,7 @@ case OP_RealAffinity: { /* in1 */ */ 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; @@ -1564,6 +1598,7 @@ case OP_ToText: { /* same as TK_TO_TEXT, in1 */ */ 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); @@ -1588,6 +1623,7 @@ case OP_ToBlob: { /* same as TK_TO_BLOB, in1 */ */ 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); } @@ -1606,6 +1642,7 @@ case OP_ToNumeric: { /* same as TK_TO_NUMERIC, in1 */ */ case OP_ToInt: { /* same as TK_TO_INT, in1 */ pIn1 = &aMem[pOp->p1]; + memAboutToChange(p, pIn1); if( (pIn1->flags & MEM_Null)==0 ){ sqlite3VdbeMemIntegerify(pIn1); } @@ -1624,6 +1661,7 @@ case OP_ToInt: { /* same as TK_TO_INT, in1 */ */ case OP_ToReal: { /* same as TK_TO_REAL, in1 */ pIn1 = &aMem[pOp->p1]; + memAboutToChange(p, pIn1); if( (pIn1->flags & MEM_Null)==0 ){ sqlite3VdbeMemRealify(pIn1); } @@ -1716,6 +1754,8 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ 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 ){ @@ -1766,6 +1806,7 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ 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); @@ -1838,6 +1879,8 @@ case OP_Compare: { #endif /* SQLITE_DEBUG */ for(i=0; inField ); @@ -2063,6 +2106,7 @@ case OP_Column: { assert( p1nCursor ); assert( pOp->p3>0 && pOp->p3<=p->nMem ); pDest = &aMem[pOp->p3]; + memAboutToChange(p, pDest); MemSetTypeFlag(pDest, MEM_Null); zRec = 0; @@ -2110,6 +2154,7 @@ case OP_Column: { }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; @@ -2332,6 +2377,8 @@ case OP_Affinity: { 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++; @@ -2398,11 +2445,18 @@ case OP_MakeRecord: { pLast = &pData0[nField-1]; file_format = p->minWriteFileFormat; + /* Identify the output register */ + assert( pOp->p3p1 || 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 ){ @@ -2436,8 +2490,6 @@ case OP_MakeRecord: { ** be one of the input registers (because the following call to ** sqlite3VdbeMemGrow() could clobber the value before it is used). */ - assert( pOp->p3p1 || pOp->p3>=pOp->p1+pOp->p2 ); - pOut = &aMem[pOp->p3]; if( sqlite3VdbeMemGrow(pOut, (int)nByte, 0) ){ goto no_mem; } @@ -2985,6 +3037,8 @@ case OP_OpenWrite: { 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 @@ -3296,6 +3350,9 @@ case OP_SeekGt: { /* jump, in3 */ assert( oc!=OP_SeekLt || r.flags==0 ); r.aMem = &aMem[pOp->p3]; +#ifdef SQLITE_DEBUG + { int i; for(i=0; ipCursor, &r, 0, 0, &res); if( rc!=SQLITE_OK ){ @@ -3420,11 +3477,14 @@ case OP_Found: { /* jump, in3 */ r.pKeyInfo = pC->pKeyInfo; r.nField = (u16)pOp->p4.i; r.aMem = pIn3; +#ifdef SQLITE_DEBUG + { int i; for(i=0; iflags & 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 ){ @@ -3517,6 +3577,9 @@ case OP_IsUnique: { /* jump, in3 */ r.nField = nField + 1; r.flags = UNPACKED_PREFIX_SEARCH; r.aMem = aMx; +#ifdef SQLITE_DEBUG + { int i; for(i=0; ip3<=p->nMem ); pMem = &aMem[pOp->p3]; + memAboutToChange(p, pMem); } + assert( memIsValid(pMem) ); REGISTER_TRACE(pOp->p3, pMem); sqlite3VdbeMemIntegerify(pMem); @@ -3809,6 +3874,7 @@ case OP_InsertInt: { pData = &aMem[pOp->p2]; assert( pOp->p1>=0 && pOp->p1nCursor ); + assert( memIsValid(pData) ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->pCursor!=0 ); @@ -3819,6 +3885,7 @@ case OP_InsertInt: { 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{ @@ -3966,6 +4033,7 @@ case OP_RowData: { 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->p1nCursor ); @@ -4294,6 +4362,9 @@ case OP_IdxDelete: { r.nField = (u16)pOp->p3; r.flags = 0; r.aMem = &aMem[pOp->p2]; +#ifdef SQLITE_DEBUG + { int i; for(i=0; ip3]; +#ifdef SQLITE_DEBUG + { int i; for(i=0; iopcode==OP_IdxLT ){ res = -res; @@ -4486,6 +4560,8 @@ case OP_Clear: { 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; } } @@ -4848,6 +4924,7 @@ case OP_Program: { /* jump */ 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 @@ -5017,6 +5094,7 @@ case OP_MemMax: { /* in2 */ }else{ pIn1 = &aMem[pOp->p1]; } + assert( memIsValid(pIn1) ); sqlite3VdbeMemIntegerify(pIn1); pIn2 = &aMem[pOp->p2]; sqlite3VdbeMemIntegerify(pIn2); @@ -5101,7 +5179,9 @@ case OP_AggStep: { apVal = p->apArg; assert( apVal || n==0 ); for(i=0; ip4.pFunc; @@ -5496,6 +5576,7 @@ case OP_VFilter: { /* jump */ 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; @@ -5551,6 +5632,7 @@ case OP_VColumn: { assert( pCur->pVtabCursor ); assert( pOp->p3>0 && pOp->p3<=p->nMem ); pDest = &aMem[pOp->p3]; + memAboutToChange(p, pDest); if( pCur->nullRow ){ sqlite3VdbeMemSetNull(pDest); break; @@ -5649,6 +5731,7 @@ case OP_VRename: { 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); @@ -5700,6 +5783,8 @@ case OP_VUpdate: { apArg = p->apArg; pX = &aMem[pOp->p3]; for(i=0; iflags = ((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 @@ -392,6 +403,10 @@ void sqlite3VdbeFrameDelete(VdbeFrame*); 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 diff --git a/src/vdbemem.c b/src/vdbemem.c index da57438a0d..0b7c70d3bd 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -132,6 +132,9 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){ 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; @@ -593,6 +596,28 @@ int sqlite3VdbeMemTooBig(Mem *p){ 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. */ diff --git a/test/tkt-b351d95f9.test b/test/tkt-b351d95f9.test new file mode 100644 index 0000000000..5bd5ee4865 --- /dev/null +++ b/test/tkt-b351d95f9.test @@ -0,0 +1,47 @@ +# 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