From: drh Date: Sat, 28 Aug 2004 18:17:48 +0000 (+0000) Subject: Memory handling fixes and optimizations in the VDBE. Ticket #862. (CVS 1909) X-Git-Tag: version-3.6.10~4237 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=febe1060f956be8d06bf906df3b8ab18fd2d89dd;p=thirdparty%2Fsqlite.git Memory handling fixes and optimizations in the VDBE. Ticket #862. (CVS 1909) FossilOrigin-Name: 5f8d246852c7cefd5941b8c7bb22177dfc7157c5 --- diff --git a/manifest b/manifest index 404c3299dd..3f24c7ac6f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\ssqlite3_libversion()\sAPI\s(ticket\s#834).\s\sFix\sthe\sbuild\sscripts\sto\ncorrectly\sbuild\sthe\sshared\slibraries\swith\sversion\s8.4\sof\sTcl.\s(CVS\s1908) -D 2004-08-28T16:19:01 +C Memory\shandling\sfixes\sand\soptimizations\sin\sthe\sVDBE.\s\sTicket\s#862.\s(CVS\s1909) +D 2004-08-28T18:17:48 F Makefile.in 65a7c43fcaf9a710d62f120b11b6e435eeb4a450 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -75,12 +75,12 @@ F src/update.c 151f1869ce532ed883f1ce26306f0b0fa7b2589a F src/utf.c 3d8f7bffcbefcced69a436c9e0a1c7eb9e0bb4fa F src/util.c e2c631849cc9e035f6fd387f507ad8886f77cedd F src/vacuum.c 9978a5760c2c430bc5b5e66505a02dad76f25813 -F src/vdbe.c ea662188cc489934a567d1eaa3fb6754d5b92b7d +F src/vdbe.c 28a48fcee38d2601cb00adc02bdac475bd43e176 F src/vdbe.h e081c72cd0f7c19d49b1927460aeefcf0fbc85ac -F src/vdbeInt.h 16322cbfccf0b05631fcf0df68b115c46584d6c9 +F src/vdbeInt.h aadadddc8cfad6aa5a5445c849f70d881276fe34 F src/vdbeapi.c 854732720c2cfc6ff76b28eef6253ac84a5408bc F src/vdbeaux.c 022c484dba235d2dcbb1faca0f1943702f4232ed -F src/vdbemem.c 68fefaf83adb48fe44135da01502c9327f6172b0 +F src/vdbemem.c 8971ecc9e56f8b7dbde865906753dbd7812a4f8f F src/where.c a84eee276cd072158224da6b5f30733df2d56027 F test/all.test 3b692eb43583b52c99c344b2fa8934512d179016 F test/attach.test feb2ce54e78688df4c84553416d5aec3b2a0112e @@ -244,7 +244,7 @@ F www/tclsqlite.tcl 560ecd6a916b320e59f2917317398f3d59b7cc25 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P 6ef1f662d71c75bdb7f61b2fff03f5b1b41e5586 -R 5b251c944f99c3bf147bc10eb4f70f96 +P 6db26a19ea7ac77be41a7416dedaef1b9dfd9e16 +R 99e5b852a5fab1a5e5963194c447eb34 U drh -Z 5c52cbb1dda1a18b82f5188a439efbf0 +Z b40cbed2b276adf8c405b360bef48d5f diff --git a/manifest.uuid b/manifest.uuid index 78ab67cc41..d1b0dcbf2e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6db26a19ea7ac77be41a7416dedaef1b9dfd9e16 \ No newline at end of file +5f8d246852c7cefd5941b8c7bb22177dfc7157c5 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 5a92c9b078..81e3b6ab6e 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.409 2004/08/21 17:54:45 drh Exp $ +** $Id: vdbe.c,v 1.410 2004/08/28 18:17:48 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -792,12 +792,7 @@ case OP_Variable: { assert( j>=0 && jnVar ); pTos++; - memcpy(pTos, &p->aVar[j], sizeof(*pTos)-NBFS); - pTos->xDel = 0; - if( pTos->flags&(MEM_Str|MEM_Blob) ){ - pTos->flags &= ~(MEM_Dyn|MEM_Ephem|MEM_Short); - pTos->flags |= MEM_Static; - } + sqlite3VdbeMemShallowCopy(pTos, &p->aVar[j], MEM_Static); break; } @@ -831,23 +826,9 @@ case OP_Dup: { Mem *pFrom = &pTos[-pOp->p1]; assert( pFrom<=pTos && pFrom>=p->aStack ); pTos++; - memcpy(pTos, pFrom, sizeof(*pFrom)-NBFS); - pTos->xDel = 0; - if( pTos->flags & (MEM_Str|MEM_Blob) ){ - if( pOp->p2 && (pTos->flags & (MEM_Dyn|MEM_Ephem)) ){ - pTos->flags &= ~MEM_Dyn; - pTos->flags |= MEM_Ephem; - }else if( pTos->flags & MEM_Short ){ - memcpy(pTos->zShort, pFrom->zShort, pTos->n+2); - pTos->z = pTos->zShort; - }else if( (pTos->flags & MEM_Static)==0 ){ - pTos->z = sqliteMallocRaw(pFrom->n+2); - if( sqlite3_malloc_failed ) goto no_mem; - memcpy(pTos->z, pFrom->z, pFrom->n); - memcpy(&pTos->z[pTos->n], "\0", 2); - pTos->flags &= ~(MEM_Static|MEM_Ephem|MEM_Short); - pTos->flags |= MEM_Dyn|MEM_Term; - } + sqlite3VdbeMemShallowCopy(pTos, pFrom, MEM_Ephem); + if( pOp->p2 ){ + Deephemeralize(pTos); } break; } @@ -898,13 +879,7 @@ case OP_Push: { Mem *pTo = &pTos[-pOp->p1]; assert( pTo>=p->aStack ); - Deephemeralize(pTos); - Release(pTo); - *pTo = *pTos; - if( pTo->flags & MEM_Short ){ - assert( pTo->z==pTos->zShort ); - pTo->z = pTo->zShort; - } + sqlite3VdbeMemMove(pTo, pTos); pTos--; break; } @@ -1240,12 +1215,11 @@ case OP_Function: { } /* Copy the result of the function to the top of the stack */ - pTos++; sqlite3VdbeChangeEncoding(&ctx.s, db->enc); - *pTos = ctx.s; - if( pTos->flags & MEM_Short ){ - pTos->z = pTos->zShort; - } + pTos++; + pTos->flags = 0; + sqlite3VdbeMemMove(pTos, &ctx.s); + /* If the function returned an error, throw an exception */ if( ctx.isError ){ if( !(pTos->flags&MEM_Str) ){ @@ -1773,6 +1747,7 @@ case OP_Column: { sMem.flags = 0; assert( p1nCursor ); pTos++; + pTos->flags = MEM_Null; /* This block sets the variable payloadSize to be the total number of ** bytes in the record. @@ -1937,6 +1912,9 @@ case OP_Column: { /* Get the column information. */ + if( rc!=SQLITE_OK ){ + goto abort_due_to_error; + } if( zRec ){ zData = &zRec[aOffset[p2]]; }else{ @@ -1945,14 +1923,25 @@ case OP_Column: { zData = sMem.z; } sqlite3VdbeSerialGet(zData, aType[p2], pTos); - if( sqlite3VdbeMemMakeWriteable(pTos)==SQLITE_NOMEM ){ - goto no_mem; - } pTos->enc = db->enc; - if( rc!=SQLITE_OK ){ - goto abort_due_to_error; + + /* If we dynamically allocated space to hold the data (in the + ** sqlite3VdbeMemFromBtree() call above) then transfer control of that + ** dynamically allocated space over to the pTos structure rather. + ** This prevents a memory copy. + */ + if( (sMem.flags & MEM_Dyn)!=0 ){ + assert( pTos->flags & MEM_Ephem ); + assert( pTos->flags & (MEM_Str|MEM_Blob) ); + assert( pTos->z==sMem.z ); + assert( sMem.flags & MEM_Term ); + pTos->flags &= ~MEM_Ephem; + pTos->flags |= MEM_Dyn|MEM_Term; } - Release(&sMem); + + /* pTos->z might be pointing to sMem.zShort[]. Fix that so that we + ** can abandon sMem */ + rc = sqlite3VdbeMemMakeWriteable(pTos); /* Release the aType[] memory if we are not dealing with cursor */ if( !pC ){ @@ -3250,6 +3239,7 @@ case OP_FullKey: { assert( p->apCsr[i]->keyAsData ); assert( !p->apCsr[i]->pseudoTable ); pTos++; + pTos->flags = MEM_Null; if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ i64 amt; char *z; @@ -3506,6 +3496,7 @@ case OP_IdxRecno: { assert( i>=0 && inCursor ); assert( p->apCsr[i]!=0 ); pTos++; + pTos->flags = MEM_Null; if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ i64 rowid; @@ -3521,8 +3512,6 @@ case OP_IdxRecno: { pTos->flags = MEM_Int; pTos->i = rowid; } - }else{ - pTos->flags = MEM_Null; } break; } @@ -4019,8 +4008,6 @@ case OP_SortPut: { pSorter->zKey = pTos->z; pSorter->data.flags = MEM_Null; rc = sqlite3VdbeMemMove(&pSorter->data, pNos); - if( rc!=SQLITE_OK ) goto abort_due_to_error; - Deephemeralize(&pSorter->data); pTos -= 2; break; } @@ -4080,7 +4067,6 @@ case OP_SortNext: { pTos++; pTos->flags = MEM_Null; rc = sqlite3VdbeMemMove(pTos, &pSorter->data); - assert( rc==SQLITE_OK ); sqliteFree(pSorter->zKey); sqliteFree(pSorter); }else{ @@ -4109,18 +4095,9 @@ case OP_SortReset: { ** the original data remains on the stack. */ case OP_MemStore: { - int i = pOp->p1; - Mem *pMem; assert( pTos>=p->aStack ); - assert( inMem ); - Deephemeralize(pTos); - pMem = &p->aMem[i]; - Release(pMem); - *pMem = *pTos; - pTos->flags = MEM_Null; - if( pMem->flags & MEM_Short ){ - pMem->z = pMem->zShort; - } + assert( pOp->p1>=0 && pOp->p1nMem ); + rc = sqlite3VdbeMemMove(&p->aMem[pOp->p1], pTos); pTos--; /* If P2 is 0 then fall thru to the next opcode, OP_MemLoad, that will @@ -4143,12 +4120,7 @@ case OP_MemLoad: { int i = pOp->p1; assert( i>=0 && inMem ); pTos++; - memcpy(pTos, &p->aMem[i], sizeof(pTos[0])-NBFS);; - pTos->xDel = 0; - if( pTos->flags & (MEM_Str|MEM_Blob) ){ - pTos->flags |= MEM_Ephem; - pTos->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short); - } + sqlite3VdbeMemShallowCopy(pTos, &p->aMem[i], MEM_Ephem); break; } @@ -4322,20 +4294,12 @@ case OP_AggFocus: { case OP_AggSet: { AggElem *pFocus; int i = pOp->p2; - Mem *pMem; rc = AggInFocus(&p->agg, &pFocus); if( rc!=SQLITE_OK ) goto abort_due_to_error; assert( pTos>=p->aStack ); if( pFocus==0 ) goto no_mem; assert( i>=0 && iagg.nMem ); - Deephemeralize(pTos); - pMem = &pFocus->aMem[i]; - Release(pMem); - *pMem = *pTos; - pTos->flags = MEM_Null; - if( pMem->flags & MEM_Short ){ - pMem->z = pMem->zShort; - } + rc = sqlite3VdbeMemMove(&pFocus->aMem[i], pTos); pTos--; break; } @@ -4348,23 +4312,19 @@ case OP_AggSet: { */ case OP_AggGet: { AggElem *pFocus; - Mem *pMem; int i = pOp->p2; rc = AggInFocus(&p->agg, &pFocus); if( rc!=SQLITE_OK ) goto abort_due_to_error; if( pFocus==0 ) goto no_mem; assert( i>=0 && iagg.nMem ); pTos++; - pMem = &pFocus->aMem[i]; - *pTos = *pMem; - pTos->xDel = 0; - if( pTos->flags & (MEM_Str|MEM_Blob) ){ - pTos->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short); - pTos->flags |= MEM_Ephem; - } + sqlite3VdbeMemShallowCopy(pTos, &pFocus->aMem[i], MEM_Ephem); + assert( (pTos->flags & MEM_Str)==0 || pTos->enc==db->enc ); +#if 0 if( pTos->flags&MEM_Str ){ sqlite3VdbeChangeEncoding(pTos, db->enc); } +#endif break; } diff --git a/src/vdbeInt.h b/src/vdbeInt.h index af6667a9f1..c16c261367 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -381,6 +381,7 @@ int sqlite3VdbeExec(Vdbe*); int sqlite3VdbeList(Vdbe*); int sqlite3VdbeChangeEncoding(Mem *, int); int sqlite3VdbeMemCopy(Mem*, const Mem*); +void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int); int sqlite3VdbeMemMove(Mem*, Mem*); int sqlite3VdbeMemNulTerminate(Mem*); int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*)); diff --git a/src/vdbemem.c b/src/vdbemem.c index b842fc775d..434ec4daa1 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -299,16 +299,32 @@ void sqlite3VdbeMemSetDouble(Mem *pMem, double val){ } /* -** Copy the contents of memory cell pFrom into pTo. +** Make an shallow copy of pFrom into pTo. Prior contents of +** pTo are overwritten. The pFrom->z field is not duplicated. If +** pFrom->z is used, then pTo->z points to the same thing as pFrom->z +** and flags gets srcType (either MEM_Ephem or MEM_Static). */ -int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ - int rc; - sqlite3VdbeMemRelease(pTo); +void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ memcpy(pTo, pFrom, sizeof(*pFrom)-sizeof(pFrom->zShort)); pTo->xDel = 0; if( pTo->flags & (MEM_Str|MEM_Blob) ){ - pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short); - pTo->flags |= MEM_Ephem; + pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short|MEM_Ephem); + assert( srcType==MEM_Ephem || srcType==MEM_Static ); + pTo->flags |= srcType; + } +} + +/* +** Make a full copy of pFrom into pTo. Prior contents of pTo are +** freed before the copy is made. +*/ +int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ + int rc; + if( pTo->flags & MEM_Dyn ){ + sqlite3VdbeMemRelease(pTo); + } + sqlite3VdbeMemShallowCopy(pTo, pFrom, MEM_Ephem); + if( pTo->flags & MEM_Ephem ){ rc = sqlite3VdbeMemMakeWriteable(pTo); }else{ rc = SQLITE_OK; @@ -318,16 +334,29 @@ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ /* ** Transfer the contents of pFrom to pTo. Any existing value in pTo is -** deleted. pFrom contains an SQL NULL when this routine returns. +** freed. If pFrom contains ephemeral data, a copy is made. +** +** pFrom contains an SQL NULL when this routine returns. SQLITE_NOMEM +** might be returned if pFrom held ephemeral data and we were unable +** to allocate enough space to make a copy. */ int sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){ + int rc; + if( pTo->flags & MEM_Dyn ){ + sqlite3VdbeMemRelease(pTo); + } memcpy(pTo, pFrom, sizeof(Mem)); if( pFrom->flags & MEM_Short ){ pTo->z = pTo->zShort; } pFrom->flags = MEM_Null; pFrom->xDel = 0; - return SQLITE_OK; + if( pTo->flags & MEM_Ephem ){ + rc = sqlite3VdbeMemMakeWriteable(pTo); + }else{ + rc = SQLITE_OK; + } + return rc; } /*