Index: src/btree.c ================================================================== --- src/btree.c +++ src/btree.c @@ -7,11 +7,11 @@ ** 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. ** ************************************************************************* -** $Id: btree.c,v 1.381 2007/05/12 10:41:48 danielk1977 Exp $ +** $Id: btree.c,v 1.382 2007/05/16 17:28:43 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. ** Including a description of file format and an overview of operation. */ @@ -417,15 +417,17 @@ ** the page, 1 means the second cell, and so forth) return a pointer ** to the cell content. ** ** This routine works only for pages that do not contain overflow cells. */ +#define findCell(pPage, iCell) \ + ((pPage)->aData + get2byte(&(pPage)->aData[(pPage)->cellOffset+2*(iCell)])) u8 *sqlite3BtreeFindCell(MemPage *pPage, int iCell){ u8 *data = pPage->aData; assert( iCell>=0 ); assert( iCellhdrOffset+3]) ); - return data + get2byte(&data[pPage->cellOffset+2*iCell]); + return findCell(pPage, iCell); } /* ** This a more complex version of sqlite3BtreeFindCell() that works for ** pages that do contain overflow cells. See insert @@ -442,18 +444,21 @@ return pOvfl->pCell; } iCell--; } } - return sqlite3BtreeFindCell(pPage, iCell); + return findCell(pPage, iCell); } /* ** Parse a cell content block and fill in the CellInfo structure. There ** are two versions of this function. sqlite3BtreeParseCell() takes a ** cell index as the second argument and sqlite3BtreeParseCellPtr() ** takes a pointer to the body of the cell as its second argument. +** +** Within this file, the parseCell() macro can be called instead of +** sqlite3BtreeParseCellPtr(). Using some compilers, this will be faster. */ void sqlite3BtreeParseCellPtr( MemPage *pPage, /* Page containing the cell */ u8 *pCell, /* Pointer to the cell text. */ CellInfo *pInfo /* Fill in this structure */ @@ -517,16 +522,18 @@ } pInfo->iOverflow = pInfo->nLocal + n; pInfo->nSize = pInfo->iOverflow + 4; } } +#define parseCell(pPage, iCell, pInfo) \ + sqlite3BtreeParseCellPtr((pPage), findCell((pPage), (iCell)), (pInfo)) void sqlite3BtreeParseCell( MemPage *pPage, /* Page containing the cell */ int iCell, /* The cell index. First cell is 0 */ CellInfo *pInfo /* Fill in this structure */ ){ - sqlite3BtreeParseCellPtr(pPage, sqlite3BtreeFindCell(pPage, iCell), pInfo); + parseCell(pPage, iCell, pInfo); } /* ** Compute the total number of bytes that a Cell needs in the cell ** data area of the btree-page. The return number includes the cell @@ -1659,11 +1666,11 @@ sqlite3BtreeInitPage(pPage, 0); nCell = pPage->nCell; for(i=0; inCell; for(i=0; ipPage->pDbPage); } } /* -** Make sure the BtCursor.info field of the given cursor is valid. -** If it is not already valid, call sqlite3BtreeParseCell() to fill it in. +** The GET_CELL_INFO() macro. Takes one argument, a pointer to a valid +** btree cursor (type BtCursor*). This macro makes sure the BtCursor.info +** field of the given cursor is valid. If it is not already valid, call +** sqlite3BtreeParseCell() to fill it in. ** ** BtCursor.info is a cache of the information in the current cell. ** Using this cache reduces the number of calls to sqlite3BtreeParseCell(). */ -static void getCellInfo(BtCursor *pCur){ - if( pCur->info.nSize==0 ){ - sqlite3BtreeParseCell(pCur->pPage, pCur->idx, &pCur->info); - }else{ #ifndef NDEBUG + static void assertCellInfo(BtCursor *pCur){ CellInfo info; memset(&info, 0, sizeof(info)); sqlite3BtreeParseCell(pCur->pPage, pCur->idx, &info); assert( memcmp(&info, &pCur->info, sizeof(info))==0 ); + } +#else + #define assertCellInfo(x) #endif - } -} + +#define GET_CELL_INFO(pCur) \ + if( pCur->info.nSize==0 ) \ + sqlite3BtreeParseCell(pCur->pPage, pCur->idx, &pCur->info); \ + else \ + assertCellInfo(pCur); + /* ** Set *pSize to the size of the buffer needed to hold the value of ** the key for the current entry. If the cursor is not pointing ** to a valid entry, *pSize is set to 0. @@ -2487,11 +2501,11 @@ if( rc==SQLITE_OK ){ assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID ); if( pCur->eState==CURSOR_INVALID ){ *pSize = 0; }else{ - getCellInfo(pCur); + GET_CELL_INFO(pCur); *pSize = pCur->info.nKey; } } return rc; } @@ -2509,11 +2523,11 @@ assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID ); if( pCur->eState==CURSOR_INVALID ){ /* Not pointing at a valid entry - set *pSize to 0. */ *pSize = 0; }else{ - getCellInfo(pCur); + GET_CELL_INFO(pCur); *pSize = pCur->info.nData; } } return rc; } @@ -2682,11 +2696,11 @@ assert( pPage ); assert( pCur->eState==CURSOR_VALID ); assert( pCur->idx>=0 && pCur->idxnCell ); assert( offset>=0 ); - getCellInfo(pCur); + GET_CELL_INFO(pCur); aPayload = pCur->info.pCell + pCur->info.nHeader; nKey = (pPage->intKey ? 0 : pCur->info.nKey); if( skipKey ){ offset += nKey; @@ -2872,11 +2886,11 @@ assert( pCur!=0 && pCur->pPage!=0 ); assert( pCur->eState==CURSOR_VALID ); pPage = pCur->pPage; assert( pCur->idx>=0 && pCur->idxnCell ); - getCellInfo(pCur); + GET_CELL_INFO(pCur); aPayload = pCur->info.pCell; aPayload += pCur->info.nHeader; if( pPage->intKey ){ nKey = 0; }else{ @@ -3043,11 +3057,11 @@ MemPage *pPage; assert( pCur->eState==CURSOR_VALID ); while( !(pPage = pCur->pPage)->leaf ){ assert( pCur->idx>=0 && pCur->idxnCell ); - pgno = get4byte(sqlite3BtreeFindCell(pPage, pCur->idx)); + pgno = get4byte(findCell(pPage, pCur->idx)); rc = moveToChild(pCur, pgno); if( rc ) return rc; } return SQLITE_OK; } @@ -3180,11 +3194,11 @@ void *pCellKey; i64 nCellKey; pCur->info.nSize = 0; if( pPage->intKey ){ u8 *pCell; - pCell = sqlite3BtreeFindCell(pPage, pCur->idx) + pPage->childPtrSize; + pCell = findCell(pPage, pCur->idx) + pPage->childPtrSize; if( pPage->hasData ){ u32 dummy; pCell += getVarint32(pCell, &dummy); } getVarint(pCell, (u64 *)&nCellKey); @@ -3235,11 +3249,11 @@ if( pPage->leaf ){ chldPg = 0; }else if( lwr>=pPage->nCell ){ chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]); }else{ - chldPg = get4byte(sqlite3BtreeFindCell(pPage, lwr)); + chldPg = get4byte(findCell(pPage, lwr)); } if( chldPg==0 ){ assert( pCur->idx>=0 && pCur->idxpPage->nCell ); if( pRes ) *pRes = c; return SQLITE_OK; @@ -3362,11 +3376,11 @@ pPage = pCur->pPage; assert( pPage->isInit ); assert( pCur->idx>=0 ); if( !pPage->leaf ){ - pgno = get4byte( sqlite3BtreeFindCell(pPage, pCur->idx) ); + pgno = get4byte( findCell(pPage, pCur->idx) ); rc = moveToChild(pCur, pgno); if( rc ) return rc; rc = moveToRightmost(pCur); }else{ while( pCur->idx==0 ){ @@ -3931,11 +3945,11 @@ int rc = SQLITE_OK; if( pPage->leaf ) return SQLITE_OK; for(i=0; inCell; i++){ - u8 *pCell = sqlite3BtreeFindCell(pPage, i); + u8 *pCell = findCell(pPage, i); if( !pPage->leaf ){ rc = reparentPage(pBt, get4byte(pCell), pPage, i); if( rc!=SQLITE_OK ) return rc; } } @@ -4185,11 +4199,11 @@ /* pPage is currently the right-child of pParent. Change this ** so that the right-child is the new page allocated above and ** pPage is the next-to-right child. */ assert( pPage->nCell>0 ); - pCell = sqlite3BtreeFindCell(pPage, pPage->nCell-1); + pCell = findCell(pPage, pPage->nCell-1); sqlite3BtreeParseCellPtr(pPage, pCell, &info); rc = fillInCell(pParent, parentCell, 0, info.nKey, 0, 0, 0, &parentSize); if( rc!=SQLITE_OK ){ return rc; } @@ -4335,11 +4349,11 @@ if( pParent->idxShift ){ Pgno pgno; pgno = pPage->pgno; assert( pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); for(idx=0; idxnCell; idx++){ - if( get4byte(sqlite3BtreeFindCell(pParent, idx))==pgno ){ + if( get4byte(findCell(pParent, idx))==pgno ){ break; } } assert( idxnCell || get4byte(&pParent->aData[pParent->hdrOffset+8])==pgno ); @@ -4369,11 +4383,11 @@ nxDiv = 0; } nDiv = 0; for(i=0, k=nxDiv; inCell ){ - apDiv[i] = sqlite3BtreeFindCell(pParent, k); + apDiv[i] = findCell(pParent, k); nDiv++; assert( !pParent->leaf ); pgnoOld[i] = get4byte(apDiv[i]); }else if( k==pParent->nCell ){ pgnoOld[i] = get4byte(&pParent->aData[pParent->hdrOffset+8]); @@ -4870,11 +4884,11 @@ /* The child information will fit on the root page, so do the ** copy */ int i; zeroPage(pPage, pChild->aData[0]); for(i=0; inCell; i++){ - apCell[i] = sqlite3BtreeFindCell(pChild,i); + apCell[i] = findCell(pChild,i); szCell[i] = cellSizePtr(pChild, apCell[i]); } assemblePage(pPage, pChild->nCell, apCell, szCell); /* Copy the right-pointer of the child to the parent. */ put4byte(&pPage->aData[pPage->hdrOffset+8], @@ -5103,11 +5117,11 @@ assert( szNew==cellSizePtr(pPage, newCell) ); assert( szNew<=MX_CELL_SIZE(pBt) ); if( loc==0 && CURSOR_VALID==pCur->eState ){ int szOld; assert( pCur->idx>=0 && pCur->idxnCell ); - oldCell = sqlite3BtreeFindCell(pPage, pCur->idx); + oldCell = findCell(pPage, pCur->idx); if( !pPage->leaf ){ memcpy(newCell, oldCell, 4); } szOld = cellSizePtr(pPage, oldCell); rc = clearCell(pPage, oldCell); @@ -5175,11 +5189,11 @@ /* Locate the cell within it's page and leave pCell pointing to the ** data. The clearCell() call frees any overflow pages associated with the ** cell. The cell itself is still intact. */ - pCell = sqlite3BtreeFindCell(pPage, pCur->idx); + pCell = findCell(pPage, pCur->idx); if( !pPage->leaf ){ pgnoChild = get4byte(pCell); } rc = clearCell(pPage, pCell); if( rc ) return rc; @@ -5207,11 +5221,11 @@ } if( rc==SQLITE_OK ){ TRACE(("DELETE: table=%d delete internal from %d replace from leaf %d\n", pCur->pgnoRoot, pPage->pgno, leafCur.pPage->pgno)); dropCell(pPage, pCur->idx, cellSizePtr(pPage, pCell)); - pNext = sqlite3BtreeFindCell(leafCur.pPage, leafCur.idx); + pNext = findCell(leafCur.pPage, leafCur.idx); szNext = cellSizePtr(leafCur.pPage, pNext); assert( MX_CELL_SIZE(pBt)>=szNext+4 ); tempCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) ); if( tempCell==0 ){ rc = SQLITE_NOMEM; @@ -5398,11 +5412,11 @@ } rc = getAndInitPage(pBt, pgno, &pPage, pParent); if( rc ) goto cleardatabasepage_out; for(i=0; inCell; i++){ - pCell = sqlite3BtreeFindCell(pPage, i); + pCell = findCell(pPage, i); if( !pPage->leaf ){ rc = clearDatabasePage(pBt, get4byte(pCell), pPage->pParent, 1); if( rc ) goto cleardatabasepage_out; } rc = clearCell(pPage, pCell); @@ -5885,11 +5899,11 @@ /* Check payload overflow pages */ sqlite3_snprintf(sizeof(zContext), zContext, "On tree page %d cell %d: ", iPage, i); - pCell = sqlite3BtreeFindCell(pPage,i); + pCell = findCell(pPage,i); sqlite3BtreeParseCellPtr(pPage, pCell, &info); sz = info.nData; if( !pPage->intKey ) sz += info.nKey; assert( sz==info.nPayload ); if( sz>info.nLocal ){ Index: src/btreeInt.h ================================================================== --- src/btreeInt.h +++ src/btreeInt.h @@ -7,11 +7,11 @@ ** 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. ** ************************************************************************* -** $Id: btreeInt.h,v 1.3 2007/05/16 14:23:00 danielk1977 Exp $ +** $Id: btreeInt.h,v 1.4 2007/05/16 17:28:43 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to ** ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: @@ -568,13 +568,13 @@ }; /* ** Read or write a two- and four-byte big-endian integer values. */ -#define get2byte(x) ((x)[0]<<8 | (x)[1]) +#define get2byte(x) ((x)[0]<<8 | (x)[1]) +#define put2byte(p,v) ((p)[0] = (v)>>8, (p)[1] = (v)) #define get4byte sqlite3Get4byte -#define put2byte sqlite3Put2byte #define put4byte sqlite3Put4byte /* ** Internal routines that should be accessed by the btree layer only. */ Index: src/malloc.c ================================================================== --- src/malloc.c +++ src/malloc.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** Memory allocation functions used throughout sqlite. ** ** -** $Id: malloc.c,v 1.1 2007/05/05 11:48:54 drh Exp $ +** $Id: malloc.c,v 1.2 2007/05/16 17:28:43 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" #include #include @@ -786,37 +786,29 @@ ** ** If the first argument, db, is not NULL and a malloc() error has occured, ** then the connection error-code (the value returned by sqlite3_errcode()) ** is set to SQLITE_NOMEM. */ -static int mallocHasFailed = 0; +int sqlite3_mallocHasFailed = 0; int sqlite3ApiExit(sqlite3* db, int rc){ if( sqlite3MallocFailed() ){ - mallocHasFailed = 0; + sqlite3_mallocHasFailed = 0; sqlite3OsLeaveMutex(); sqlite3Error(db, SQLITE_NOMEM, 0); rc = SQLITE_NOMEM; } return rc & (db ? db->errMask : 0xff); } -/* -** Return true is a malloc has failed in this thread since the last call -** to sqlite3ApiExit(), or false otherwise. -*/ -int sqlite3MallocFailed(){ - return (mallocHasFailed && sqlite3OsInMutex(1)); -} - /* ** Set the "malloc has failed" condition to true for this thread. */ void sqlite3FailedMalloc(){ if( !sqlite3MallocFailed() ){ sqlite3OsEnterMutex(); - assert( mallocHasFailed==0 ); - mallocHasFailed = 1; + assert( sqlite3_mallocHasFailed==0 ); + sqlite3_mallocHasFailed = 1; } } #ifdef SQLITE_MEMDEBUG /* Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -9,11 +9,11 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.568 2007/05/15 16:51:37 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.569 2007/05/16 17:28:43 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ #include "limits.h" @@ -252,13 +252,22 @@ #define sqliteStrNDup(x,y) sqlite3StrNDup(x,y) #define sqliteReallocOrFree(x,y) sqlite3ReallocOrFree(x,y) #endif +/* Variable sqlite3_mallocHasFailed is set to true after a malloc() +** failure occurs. +** +** The sqlite3MallocFailed() macro returns true if a malloc has failed +** in this thread since the last call to sqlite3ApiExit(), or false +** otherwise. +*/ +extern int sqlite3_mallocHasFailed; +#define sqlite3MallocFailed() (sqlite3_mallocHasFailed && sqlite3OsInMutex(1)) + #define sqliteFree(x) sqlite3FreeX(x) #define sqliteAllocSize(x) sqlite3AllocSize(x) - /* ** An instance of this structure might be allocated to store information ** specific to a single thread. */ @@ -330,10 +339,12 @@ typedef struct TriggerStack TriggerStack; typedef struct TriggerStep TriggerStep; typedef struct Trigger Trigger; typedef struct WhereInfo WhereInfo; typedef struct WhereLevel WhereLevel; + +#include "os.h" /* ** Each database file to be accessed by the system is an instance ** of the following structure. There are normally two of these structures ** in the sqlite.aDb[] array. aDb[0] is the main database file and @@ -1876,11 +1887,10 @@ KeyInfo *sqlite3IndexKeyinfo(Parse *, Index *); int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*)); int sqlite3ApiExit(sqlite3 *db, int); -int sqlite3MallocFailed(void); void sqlite3FailedMalloc(void); void sqlite3AbortOtherActiveVdbes(sqlite3 *, Vdbe *); int sqlite3OpenTempDatabase(Parse *); #ifndef SQLITE_OMIT_LOAD_EXTENSION Index: src/util.c ================================================================== --- src/util.c +++ src/util.c @@ -12,11 +12,11 @@ ** Utility functions used throughout sqlite. ** ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** -** $Id: util.c,v 1.203 2007/05/15 16:51:37 drh Exp $ +** $Id: util.c,v 1.204 2007/05/16 17:28:43 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" #include #include @@ -535,22 +535,15 @@ return i; } /* -** Read or write a two- and four-byte big-endian integer values. +** Read or write a four-byte big-endian integer value. */ -u32 sqlite3Get2byte(const u8 *p){ - return (p[0]<<8) | p[1]; -} u32 sqlite3Get4byte(const u8 *p){ return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; } -void sqlite3Put2byte(unsigned char *p, u32 v){ - p[0] = v>>8; - p[1] = v; -} void sqlite3Put4byte(unsigned char *p, u32 v){ p[0] = v>>24; p[1] = v>>16; p[2] = v>>8; p[3] = v; Index: src/vdbe.c ================================================================== --- src/vdbe.c +++ src/vdbe.c @@ -41,11 +41,11 @@ ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** 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.620 2007/05/16 14:23:00 danielk1977 Exp $ +** $Id: vdbe.c,v 1.621 2007/05/16 17:28:43 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" #include #include @@ -149,10 +149,16 @@ */ #define Deephemeralize(P) \ if( ((P)->flags&MEM_Ephem)!=0 \ && sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;} +/* +** Call sqlite3VdbeMemExpandBlob() on the supplied value (type Mem*) +** P if required. +*/ +#define ExpandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0) + /* ** Argument pMem points at a memory cell that will be passed to a ** user-defined function or returned to the user as the result of a query. ** The second argument, 'db_enc' is the text encoding used by the vdbe for ** stack variables. This routine sets the pMem->enc and pMem->type @@ -1468,11 +1474,11 @@ assert( pTos>=p->aStack ); if( pTos->flags & MEM_Null ) break; assert( MEM_Str==(MEM_Blob>>3) ); pTos->flags |= (pTos->flags&MEM_Blob)>>3; applyAffinity(pTos, SQLITE_AFF_TEXT, encoding); - rc = sqlite3VdbeMemExpandBlob(pTos); + rc = ExpandBlob(pTos); assert( pTos->flags & MEM_Str ); pTos->flags &= ~(MEM_Int|MEM_Real|MEM_Blob); break; } @@ -1673,12 +1679,12 @@ applyAffinity(pNos, affinity, encoding); applyAffinity(pTos, affinity, encoding); } assert( pOp->p3type==P3_COLLSEQ || pOp->p3==0 ); - sqlite3VdbeMemExpandBlob(pNos); - sqlite3VdbeMemExpandBlob(pTos); + ExpandBlob(pNos); + ExpandBlob(pTos); res = sqlite3MemCompare(pNos, pTos, (CollSeq*)pOp->p3); switch( pOp->opcode ){ case OP_Eq: res = res==0; break; case OP_Ne: res = res!=0; break; case OP_Lt: res = res<0; break; @@ -2273,11 +2279,11 @@ } if( pRec->flags&MEM_Null ){ containsNull = 1; } if( pRec->flags&MEM_Zero && pRec->n>0 ){ - sqlite3VdbeMemExpandBlob(pRec); + ExpandBlob(pRec); } serial_type = sqlite3VdbeSerialType(pRec, file_format); len = sqlite3VdbeSerialTypeLen(serial_type); nData += len; nHdr += sqlite3VarintLen(serial_type); @@ -2926,11 +2932,11 @@ } pC->lastRowid = pTos->u.i; pC->rowidIsValid = res==0; }else{ assert( pTos->flags & MEM_Blob ); - sqlite3VdbeMemExpandBlob(pTos); + ExpandBlob(pTos); rc = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, 0, &res); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } pC->rowidIsValid = 0; @@ -3829,11 +3835,11 @@ assert( i>=0 && inCursor ); assert( p->apCsr[i]!=0 ); assert( pTos->flags & MEM_Blob ); if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ assert( pC->isTable==0 ); - rc = sqlite3VdbeMemExpandBlob(pTos); + rc = ExpandBlob(pTos); if( rc==SQLITE_OK ){ int nKey = pTos->n; const char *zKey = pTos->z; rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0, 0, pOp->p2); assert( pC->deferredMoveto==0 ); @@ -3965,11 +3971,11 @@ if( (pC = p->apCsr[i])->pCursor!=0 ){ int res; assert( pTos->flags & MEM_Blob ); /* Created using OP_MakeRecord */ assert( pC->deferredMoveto==0 ); - sqlite3VdbeMemExpandBlob(pTos); + ExpandBlob(pTos); *pC->pIncrKey = pOp->p3!=0; assert( pOp->p3==0 || pOp->opcode!=OP_IdxGT ); rc = sqlite3VdbeIdxKeyCompare(pC, pTos->n, (u8*)pTos->z, &res); *pC->pIncrKey = 0; if( rc!=SQLITE_OK ){ Index: src/vdbemem.c ================================================================== --- src/vdbemem.c +++ src/vdbemem.c @@ -19,10 +19,16 @@ #include "os.h" #include #include #include "vdbeInt.h" +/* +** Call sqlite3VdbeMemExpandBlob() on the supplied value (type Mem*) +** P if required. +*/ +#define expandBlob(P) (((P)->flags&MEM_Zero)?sqlite3VdbeMemExpandBlob(P):0) + /* ** If pMem is an object with a valid string representation, this routine ** ensures the internal encoding for the string representation is ** 'desiredEnc', one of SQLITE_UTF8, SQLITE_UTF16LE or SQLITE_UTF16BE. ** @@ -61,11 +67,11 @@ ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. */ int sqlite3VdbeMemDynamicify(Mem *pMem){ int n; u8 *z; - sqlite3VdbeMemExpandBlob(pMem); + expandBlob(pMem); if( (pMem->flags & (MEM_Ephem|MEM_Static|MEM_Short))==0 ){ return SQLITE_OK; } assert( (pMem->flags & MEM_Dyn)==0 ); n = pMem->n; @@ -118,11 +124,11 @@ ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. */ int sqlite3VdbeMemMakeWriteable(Mem *pMem){ int n; u8 *z; - sqlite3VdbeMemExpandBlob(pMem); + expandBlob(pMem); if( (pMem->flags & (MEM_Ephem|MEM_Static))==0 ){ return SQLITE_OK; } assert( (pMem->flags & MEM_Dyn)==0 ); assert( pMem->flags & (MEM_Str|MEM_Blob) ); @@ -834,11 +840,11 @@ if( pVal->flags&MEM_Null ){ return 0; } assert( (MEM_Blob>>3) == MEM_Str ); pVal->flags |= (pVal->flags & MEM_Blob)>>3; - sqlite3VdbeMemExpandBlob(pVal); + expandBlob(pVal); if( pVal->flags&MEM_Str ){ sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED); if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&(int)pVal->z) ){ assert( (pVal->flags & (MEM_Ephem|MEM_Static))!=0 ); if( sqlite3VdbeMemMakeWriteable(pVal)!=SQLITE_OK ){