Index: src/attach.c ================================================================== --- src/attach.c +++ src/attach.c @@ -9,11 +9,11 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the ATTACH and DETACH commands. ** -** $Id: attach.c,v 1.71 2008/02/06 14:11:35 drh Exp $ +** $Id: attach.c,v 1.72 2008/02/13 18:25:27 danielk1977 Exp $ */ #include "sqliteInt.h" #ifndef SQLITE_OMIT_ATTACH /* @@ -326,18 +326,18 @@ pParse->nErr++; goto attach_end; } v = sqlite3GetVdbe(pParse); - regArgs = sqlite3GetTempRange(pParse, 3); + regArgs = sqlite3GetTempRange(pParse, 4); sqlite3ExprCode(pParse, pFilename, regArgs); sqlite3ExprCode(pParse, pDbname, regArgs+1); sqlite3ExprCode(pParse, pKey, regArgs+2); assert( v || db->mallocFailed ); if( v ){ - sqlite3VdbeAddOp3(v, OP_Function, 0, regArgs+3-nFunc, regArgs); + sqlite3VdbeAddOp3(v, OP_Function, 0, regArgs+3-nFunc, regArgs+3); sqlite3VdbeChangeP5(v, nFunc); pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0); sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF); /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this Index: src/insert.c ================================================================== --- src/insert.c +++ src/insert.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.228 2008/01/25 15:04:50 drh Exp $ +** $Id: insert.c,v 1.229 2008/02/13 18:25:27 danielk1977 Exp $ */ #include "sqliteInt.h" /* ** Set P4 of the most recently inserted opcode to a column affinity @@ -216,18 +216,19 @@ if( pTab->autoInc ){ int iCur = pParse->nTab; Vdbe *v = pParse->pVdbe; Db *pDb = &pParse->db->aDb[iDb]; int j1; + int iRec = ++pParse->nMem; /* Memory cell used for record */ assert( v ); sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite); j1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); sqlite3VdbeAddOp2(v, OP_NewRowid, iCur, memId+1); sqlite3VdbeJumpHere(v, j1); - sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, memId-1); - sqlite3VdbeAddOp3(v, OP_Insert, iCur, memId-1, memId+1); + sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, iRec); + sqlite3VdbeAddOp3(v, OP_Insert, iCur, iRec, memId+1); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3VdbeAddOp1(v, OP_Close, iCur); } } #else Index: src/legacy.c ================================================================== --- src/legacy.c +++ src/legacy.c @@ -12,11 +12,11 @@ ** Main file for the SQLite library. The routines in this file ** implement the programmer interface to the library. Routines in ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: legacy.c,v 1.22 2007/08/29 12:31:26 danielk1977 Exp $ +** $Id: legacy.c,v 1.23 2008/02/13 18:25:27 danielk1977 Exp $ */ #include "sqliteInt.h" #include @@ -80,17 +80,25 @@ if( xCallback && (SQLITE_ROW==rc || (SQLITE_DONE==rc && !nCallback && db->flags&SQLITE_NullCallback)) ){ if( 0==nCallback ){ for(i=0; imallocFailed = 1; + goto exec_out; + } } nCallback++; } if( rc==SQLITE_ROW ){ azVals = &azCols[nCol]; for(i=0; imallocFailed = 1; + goto exec_out; + } } } if( xCallback(pArg, nCol, azVals, azCols) ){ rc = SQLITE_ABORT; goto exec_out; Index: src/mem1.c ================================================================== --- src/mem1.c +++ src/mem1.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains the C functions that implement a memory ** allocation subsystem for use by SQLite. ** -** $Id: mem1.c,v 1.14 2007/11/29 18:36:49 drh Exp $ +** $Id: mem1.c,v 1.15 2008/02/13 18:25:27 danielk1977 Exp $ */ /* ** This version of the memory allocator is the default. It is ** used when no other memory allocator is specified using compile-time @@ -186,10 +186,20 @@ sqlite3_mutex_enter(mem.mutex); mem.nowUsed -= nByte; free(p); sqlite3_mutex_leave(mem.mutex); } + +/* +** Return the number of bytes allocated at p. +*/ +int sqlite3MallocSize(void *p){ + sqlite3_int64 *pInt; + if( !p ) return 0; + pInt = p; + return pInt[-1]; +} /* ** Change the size of an existing memory allocation */ void *sqlite3_realloc(void *pPrior, int nBytes){ Index: src/mem2.c ================================================================== --- src/mem2.c +++ src/mem2.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains the C functions that implement a memory ** allocation subsystem for use by SQLite. ** -** $Id: mem2.c,v 1.19 2008/01/22 21:30:53 drh Exp $ +** $Id: mem2.c,v 1.20 2008/02/13 18:25:27 danielk1977 Exp $ */ /* ** This version of the memory allocator is used only if the ** SQLITE_MEMDEBUG macro is defined and SQLITE_OMIT_MEMORY_ALLOCATION @@ -240,10 +240,22 @@ assert( (p->iSize & 3)==0 ); pInt = (int*)pAllocation; assert( pInt[p->iSize/sizeof(int)]==REARGUARD ); return p; } + +/* +** Return the number of bytes currently allocated at address p. +*/ +int sqlite3MallocSize(void *p){ + struct MemBlockHdr *pHdr; + if( !p ){ + return 0; + } + pHdr = sqlite3MemsysGetHeader(p); + return pHdr->iSize; +} /* ** Allocate nByte bytes of memory. */ void *sqlite3_malloc(int nByte){ @@ -449,8 +461,20 @@ if( mem.sizeCnt[NCSIZE-1] ){ fprintf(out, " >%3d: %d\n", NCSIZE*8, mem.sizeCnt[NCSIZE-1]); } fclose(out); } + +/* +** Return the number of times sqlite3_malloc() has been called. +*/ +int sqlite3_memdebug_malloc_count(){ + int i; + int nTotal = 0; + for(i=0; i=nOld-128 ){ return pPrior; } sqlite3_mutex_enter(mem.mutex); p = memsys3Malloc(nBytes); Index: src/os.c ================================================================== --- src/os.c +++ src/os.c @@ -1,6 +1,6 @@ - /* +/* ** 2005 November 29 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** Index: src/pragma.c ================================================================== --- src/pragma.c +++ src/pragma.c @@ -9,11 +9,11 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the PRAGMA command. ** -** $Id: pragma.c,v 1.169 2008/01/22 01:48:09 drh Exp $ +** $Id: pragma.c,v 1.170 2008/02/13 18:25:27 danielk1977 Exp $ */ #include "sqliteInt.h" #include /* Ignore this whole file if pragmas are disabled @@ -892,22 +892,23 @@ } } if( cnt==0 ) continue; /* Make sure sufficient number of registers have been allocated */ - if( pParse->nMem < cnt+3 ){ - pParse->nMem = cnt+3; + if( pParse->nMem < cnt+4 ){ + pParse->nMem = cnt+4; } /* Do the b-tree integrity checks */ sqlite3VdbeAddOp3(v, OP_IntegrityCk, 2, cnt, 1); sqlite3VdbeChangeP5(v, i); addr = sqlite3VdbeAddOp1(v, OP_IsNull, 2); sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, sqlite3MPrintf(db, "*** in database %s ***\n", db->aDb[i].zName), P4_DYNAMIC); - sqlite3VdbeAddOp3(v, OP_Concat, 2, 3, 2); + sqlite3VdbeAddOp2(v, OP_Move, 2, 4); + sqlite3VdbeAddOp3(v, OP_Concat, 4, 3, 2); sqlite3VdbeAddOp2(v, OP_ResultRow, 2, 1); sqlite3VdbeJumpHere(v, addr); /* Make sure all the indices are constructed correctly. */ Index: src/select.c ================================================================== --- src/select.c +++ src/select.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.412 2008/02/06 23:52:37 drh Exp $ +** $Id: select.c,v 1.413 2008/02/13 18:25:27 danielk1977 Exp $ */ #include "sqliteInt.h" /* @@ -808,12 +808,12 @@ #ifndef SQLITE_OMIT_SUBQUERY case SRT_Set: { int j1; assert( nColumn==1 ); j1 = sqlite3VdbeAddOp1(v, OP_IsNull, regRow); - sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, 1, regRow, &p->affinity, 1); - sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRow); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, 1, regRowid, &p->affinity, 1); + sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRowid); sqlite3VdbeJumpHere(v, j1); break; } case SRT_Mem: { assert( nColumn==1 ); 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.660 2008/02/12 16:52:14 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.661 2008/02/13 18:25:27 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* @@ -1681,10 +1681,11 @@ char *sqlite3StrNDup(const char*, int); char *sqlite3DbStrDup(sqlite3*,const char*); char *sqlite3DbStrNDup(sqlite3*,const char*, int); void *sqlite3DbReallocOrFree(sqlite3 *, void *, int); void *sqlite3DbRealloc(sqlite3 *, void *, int); +int sqlite3MallocSize(void *); char *sqlite3MPrintf(sqlite3*,const char*, ...); char *sqlite3VMPrintf(sqlite3*,const char*, va_list); #if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) void sqlite3DebugPrintf(const char*, ...); Index: src/tclsqlite.c ================================================================== --- src/tclsqlite.c +++ src/tclsqlite.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** A TCL Interface to SQLite. Append this file to sqlite3.c and ** compile the whole thing to build a TCL-enabled version of SQLite. ** -** $Id: tclsqlite.c,v 1.207 2007/11/14 06:48:48 danielk1977 Exp $ +** $Id: tclsqlite.c,v 1.208 2008/02/13 18:25:27 danielk1977 Exp $ */ #include "tcl.h" #include /* @@ -1700,11 +1700,13 @@ /* Set pVal to contain the i'th column of this row. */ switch( sqlite3_column_type(pStmt, i) ){ case SQLITE_BLOB: { int bytes = sqlite3_column_bytes(pStmt, i); - pVal = Tcl_NewByteArrayObj(sqlite3_column_blob(pStmt, i), bytes); + char *zBlob = sqlite3_column_blob(pStmt, i); + if( !zBlob ) bytes = 0; + pVal = Tcl_NewByteArrayObj(zBlob, bytes); break; } case SQLITE_INTEGER: { sqlite_int64 v = sqlite3_column_int64(pStmt, i); if( v>=-2147483647 && v<=2147483647 ){ Index: src/test1.c ================================================================== --- src/test1.c +++ src/test1.c @@ -11,11 +11,11 @@ ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.287 2008/01/23 14:51:50 drh Exp $ +** $Id: test1.c,v 1.288 2008/02/13 18:25:27 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" #include #include @@ -952,20 +952,21 @@ #ifndef SQLITE_OMIT_UTF16 /* Use the sqlite3_create_function16() API here. Mainly for fun, but also ** because it is not tested anywhere else. */ if( rc==SQLITE_OK ){ + void *zUtf16; sqlite3_value *pVal; sqlite3_mutex_enter(db->mutex); pVal = sqlite3ValueNew(db); sqlite3ValueSetStr(pVal, -1, "x_sqlite_exec", SQLITE_UTF8, SQLITE_STATIC); + zUtf16 = sqlite3ValueText(pVal, SQLITE_UTF16NATIVE); if( db->mallocFailed ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_create_function16(db, - sqlite3ValueText(pVal, SQLITE_UTF16NATIVE), - 1, SQLITE_UTF16, db, sqlite3ExecFunc, 0, 0); + rc = sqlite3_create_function16(db, zUtf16, + 1, SQLITE_UTF16, db, sqlite3ExecFunc, 0, 0); } sqlite3ValueFree(pVal); sqlite3_mutex_leave(db->mutex); } #endif @@ -2150,10 +2151,11 @@ if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[2], &val) ) return TCL_ERROR; rc = sqlite3_create_collation(db, "test_collate", SQLITE_UTF8, (void *)SQLITE_UTF8, val?test_collate_func:0); if( rc==SQLITE_OK ){ + void *zUtf16; if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[3], &val) ) return TCL_ERROR; rc = sqlite3_create_collation(db, "test_collate", SQLITE_UTF16LE, (void *)SQLITE_UTF16LE, val?test_collate_func:0); if( TCL_OK!=Tcl_GetBooleanFromObj(interp, objv[4], &val) ) return TCL_ERROR; @@ -2163,15 +2165,15 @@ } #endif sqlite3_mutex_enter(db->mutex); pVal = sqlite3ValueNew(db); sqlite3ValueSetStr(pVal, -1, "test_collate", SQLITE_UTF8, SQLITE_STATIC); + zUtf16 = sqlite3ValueText(pVal, SQLITE_UTF16NATIVE); if( db->mallocFailed ){ rc = SQLITE_NOMEM; }else{ - rc = sqlite3_create_collation16(db, - sqlite3ValueText(pVal, SQLITE_UTF16NATIVE), SQLITE_UTF16BE, + rc = sqlite3_create_collation16(db, zUtf16, SQLITE_UTF16BE, (void *)SQLITE_UTF16BE, val?test_collate_func:0); } sqlite3ValueFree(pVal); sqlite3_mutex_leave(db->mutex); } Index: src/test8.c ================================================================== --- src/test8.c +++ src/test8.c @@ -11,11 +11,11 @@ ************************************************************************* ** Code for testing the virtual table interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test8.c,v 1.59 2008/01/22 21:30:53 drh Exp $ +** $Id: test8.c,v 1.60 2008/02/13 18:25:27 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" #include #include @@ -158,11 +158,16 @@ /* Figure out how much space to allocate for the array of column names ** (including space for the strings themselves). Then allocate it. */ nBytes = sizeof(char *) * nCol; for(ii=0; ii #include @@ -341,10 +341,36 @@ } #endif return TCL_OK; } +/* +** Usage: sqlite3_memdebug_malloc_count +** +** Return the total number of times malloc() has been called. +*/ +static int test_memdebug_malloc_count( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + int nMalloc = -1; + if( objc!=1 ){ + Tcl_WrongNumArgs(interp, 1, objv, ""); + return TCL_ERROR; + } +#if defined(SQLITE_MEMDEBUG) + { + extern int sqlite3_memdebug_malloc_count(); + nMalloc = sqlite3_memdebug_malloc_count(); + } +#endif + Tcl_SetObjResult(interp, Tcl_NewIntObj(nMalloc)); + return TCL_OK; +} + /* ** Usage: sqlite3_memdebug_fail COUNTER ?OPTIONS? ** ** where options are: @@ -502,12 +528,13 @@ { "sqlite3_memdebug_backtrace", test_memdebug_backtrace }, { "sqlite3_memdebug_dump", test_memdebug_dump }, { "sqlite3_memdebug_fail", test_memdebug_fail }, { "sqlite3_memdebug_pending", test_memdebug_pending }, { "sqlite3_memdebug_settitle", test_memdebug_settitle }, + { "sqlite3_memdebug_malloc_count", test_memdebug_malloc_count }, }; int i; for(i=0; iz; zTerm = &zIn[pMem->n]; - if( len>NBFS ){ - zOut = sqlite3DbMallocRaw(pMem->db, len); - if( !zOut ){ - return SQLITE_NOMEM; - } - }else{ - zOut = zShort; + zOut = sqlite3DbMallocRaw(pMem->db, len); + if( !zOut ){ + return SQLITE_NOMEM; } z = zOut; if( pMem->enc==SQLITE_UTF8 ){ if( desiredEnc==SQLITE_UTF16LE ){ @@ -306,19 +300,13 @@ } *z = 0; assert( (pMem->n+(desiredEnc==SQLITE_UTF8?1:2))<=len ); sqlite3VdbeMemRelease(pMem); - pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short); + pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem); pMem->enc = desiredEnc; - if( zOut==zShort ){ - memcpy(pMem->zShort, zOut, len); - zOut = (u8*)pMem->zShort; - pMem->flags |= (MEM_Term|MEM_Short); - }else{ - pMem->flags |= (MEM_Term|MEM_Dyn); - } + pMem->flags |= (MEM_Term|MEM_Dyn); pMem->z = (char*)zOut; translate_out: #if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG) { @@ -353,28 +341,18 @@ bom = SQLITE_UTF16LE; } } if( bom ){ - /* This function is called as soon as a string is stored in a Mem*, - ** from within sqlite3VdbeMemSetStr(). At that point it is not possible - ** for the string to be stored in Mem.zShort, or for it to be stored - ** in dynamic memory with no destructor. - */ - assert( !(pMem->flags&MEM_Short) ); - assert( !(pMem->flags&MEM_Dyn) || pMem->xDel ); - if( pMem->flags & MEM_Dyn ){ - void (*xDel)(void*) = pMem->xDel; - char *z = pMem->z; - pMem->z = 0; - pMem->xDel = 0; - rc = sqlite3VdbeMemSetStr(pMem, &z[2], pMem->n-2, bom, - SQLITE_TRANSIENT); - xDel(z); - }else{ - rc = sqlite3VdbeMemSetStr(pMem, &pMem->z[2], pMem->n-2, bom, - SQLITE_TRANSIENT); + rc = sqlite3VdbeMemMakeWriteable(pMem); + if( rc==SQLITE_OK ){ + pMem->n -= 2; + memmove(pMem->z, &pMem->z[2], pMem->n); + pMem->z[pMem->n] = '\0'; + pMem->z[pMem->n+1] = '\0'; + pMem->flags |= MEM_Term; + pMem->enc = bom; } } return rc; } #endif /* SQLITE_OMIT_UTF16 */ 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.708 2008/02/06 14:11:35 drh Exp $ +** $Id: vdbe.c,v 1.709 2008/02/13 18:25:27 danielk1977 Exp $ */ #include "sqliteInt.h" #include #include "vdbeInt.h" @@ -234,13 +234,12 @@ if( (pRec->flags&MEM_Str) && sqlite3IsNumber(pRec->z, &realnum, pRec->enc) ){ i64 value; sqlite3VdbeChangeEncoding(pRec, SQLITE_UTF8); if( !realnum && sqlite3Atoi64(pRec->z, &value) ){ - sqlite3VdbeMemRelease(pRec); pRec->u.i = value; - pRec->flags = MEM_Int; + MemSetTypeFlag(pRec, MEM_Int); }else{ sqlite3VdbeMemRealify(pRec); } } } @@ -998,18 +997,23 @@ /* Opcode: Concat P1 P2 P3 * * ** ** Add the text in register P1 onto the end of the text in ** register P2 and store the result in register P3. ** If either the P1 or P2 text are NULL then store NULL in P3. +** +** P3 = P2 || P1 +** +** It is illegal for P1 and P3 to be the same register. Sometimes, +** if P3 is the same register as P2, the implementation is able +** to avoid a memcpy(). */ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ - char *zNew; i64 nByte; + assert( pIn1!=pOut ); if( (pIn1->flags | pIn2->flags) & MEM_Null ){ - Release(pOut); - pOut->flags = MEM_Null; + sqlite3VdbeMemSetNull(pOut); break; } ExpandBlob(pIn1); Stringify(pIn1, encoding); ExpandBlob(pIn2); @@ -1016,24 +1020,23 @@ Stringify(pIn2, encoding); nByte = pIn1->n + pIn2->n; if( nByte>SQLITE_MAX_LENGTH ){ goto too_big; } - zNew = sqlite3DbMallocRaw(db, nByte+2); - if( zNew==0 ){ + MemSetTypeFlag(pOut, MEM_Str); + if( sqlite3VdbeMemGrow(pOut, nByte+2, pOut==pIn2) ){ goto no_mem; } - memcpy(zNew, pIn2->z, pIn2->n); - memcpy(&zNew[pIn2->n], pIn1->z, pIn1->n); - zNew[nByte] = 0; - zNew[nByte+1] = 0; - Release(pOut); + if( pOut!=pIn2 ){ + memcpy(pOut->z, pIn2->z, pIn2->n); + } + memcpy(&pOut->z[pIn2->n], pIn1->z, pIn1->n); + pOut->z[nByte] = 0; + pOut->z[nByte+1] = 0; + pOut->flags |= MEM_Term; pOut->n = nByte; - pOut->flags = MEM_Str|MEM_Dyn|MEM_Term; - pOut->xDel = 0; pOut->enc = encoding; - pOut->z = zNew; UPDATE_MAX_BLOBSIZE(pOut); break; } /* Opcode: Add P1 P2 P3 * * @@ -1103,13 +1106,12 @@ if( a==-1 ) a = 1; b %= a; break; } } - Release(pOut); pOut->u.i = b; - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); }else{ double a, b; a = sqlite3VdbeRealValue(pIn1); b = sqlite3VdbeRealValue(pIn2); switch( pOp->opcode ){ @@ -1131,13 +1133,12 @@ } } if( sqlite3_isnan(b) ){ goto arithmetic_result_is_null; } - Release(pOut); pOut->r = b; - pOut->flags = MEM_Real; + MemSetTypeFlag(pOut, MEM_Real); if( (flags & MEM_Real)==0 ){ sqlite3VdbeIntegerAffinity(pOut); } } break; @@ -1166,10 +1167,11 @@ /* Opcode: Function P1 P2 P3 P4 P5 ** ** Invoke a user function (P4 is a pointer to a Function structure that ** defines the function) with P5 arguments taken from register P2 and ** successors. The result of the function is stored in register P3. +** Register P3 must not be one of the function inputs. ** ** P1 is a 32-bit bitmask indicating whether or not each argument to the ** function was determined to be constant at compile time. If the first ** argument was constant then bit 0 of P1 is set. This is used to determine ** whether meta data associated with a user function argument using the @@ -1187,10 +1189,11 @@ apVal = p->apArg; assert( apVal || n==0 ); assert( n==0 || (pOp->p2>0 && pOp->p2+n<=p->nMem) ); + assert( pOp->p3p2 || pOp->p3>=pOp->p2+n ); pArg = &p->aMem[pOp->p2]; for(i=0; ip2, pArg); @@ -1203,14 +1206,22 @@ }else{ ctx.pVdbeFunc = (VdbeFunc*)pOp->p4.pVdbeFunc; ctx.pFunc = ctx.pVdbeFunc->pFunc; } + assert( pOp->p3>0 && pOp->p3<=p->nMem ); + pOut = &p->aMem[pOp->p3]; ctx.s.flags = MEM_Null; - ctx.s.z = 0; - ctx.s.xDel = 0; - ctx.s.db = db; + ctx.s.db = 0; + + /* The output cell may already have a buffer allocated. Move + ** the pointer to ctx.s so in case the user-function can use + ** the already allocated buffer instead of allocating a new one. + */ + sqlite3VdbeMemMove(&ctx.s, pOut); + MemSetTypeFlag(&ctx.s, MEM_Null); + ctx.isError = 0; if( ctx.pFunc->needCollSeq ){ assert( pOp>p->aOp ); assert( pOp[-1].p4type==P4_COLLSEQ ); assert( pOp[-1].opcode==OP_CollSeq ); @@ -1248,12 +1259,10 @@ rc = ctx.isError; } /* Copy the result of the function into register P3 */ sqlite3VdbeChangeEncoding(&ctx.s, encoding); - assert( pOp->p3>0 && pOp->p3<=p->nMem ); - pOut = &p->aMem[pOp->p3]; sqlite3VdbeMemMove(pOut, &ctx.s); if( sqlite3VdbeMemTooBig(pOut) ){ goto too_big; } REGISTER_TRACE(pOp->p3, pOut); @@ -1304,13 +1313,12 @@ case OP_BitOr: a |= b; break; case OP_ShiftLeft: a <<= b; break; default: assert( pOp->opcode==OP_ShiftRight ); a >>= b; break; } - Release(pOut); pOut->u.i = a; - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); break; } /* Opcode: AddImm P1 P2 * * * ** @@ -1348,13 +1356,12 @@ assert( pIn1->flags & MEM_Real ); v = (sqlite3_int64)pIn1->r; if( pIn1->r>(double)v ) v++; if( pOp->p3 && pIn1->r==(double)v ) v++; } - Release(pIn1); pIn1->u.i = v; - pIn1->flags = MEM_Int; + MemSetTypeFlag(pIn1, MEM_Int); break; } /* Opcode: MustBeInt P1 P2 * * * ** @@ -1371,12 +1378,11 @@ goto abort_due_to_error; }else{ pc = pOp->p2 - 1; } }else{ - Release(pIn1); - pIn1->flags = MEM_Int; + MemSetTypeFlag(pIn1, MEM_Int); } break; } /* Opcode: RealAffinity P1 * * * * @@ -1409,11 +1415,11 @@ if( pIn1->flags & MEM_Null ) break; assert( MEM_Str==(MEM_Blob>>3) ); pIn1->flags |= (pIn1->flags&MEM_Blob)>>3; applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding); rc = ExpandBlob(pIn1); - assert( pIn1->flags & MEM_Str ); + assert( pIn1->flags & MEM_Str || db->mallocFailed ); pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_Blob); UPDATE_MAX_BLOBSIZE(pIn1); break; } @@ -1428,14 +1434,13 @@ */ case OP_ToBlob: { /* same as TK_TO_BLOB, in1 */ if( pIn1->flags & MEM_Null ) break; if( (pIn1->flags & MEM_Blob)==0 ){ applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding); - assert( pIn1->flags & MEM_Str ); - pIn1->flags |= MEM_Blob; + assert( pIn1->flags & MEM_Str || db->mallocFailed ); } - pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_Str); + MemSetTypeFlag(pIn1, MEM_Blob); UPDATE_MAX_BLOBSIZE(pIn1); break; } /* Opcode: ToNumeric P1 * * * * @@ -1589,12 +1594,11 @@ ** the result is always NULL. The jump is taken if the ** SQLITE_JUMPIFNULL bit is set. */ if( pOp->p5 & SQLITE_STOREP2 ){ pOut = &p->aMem[pOp->p2]; - Release(pOut); - pOut->flags = MEM_Null; + MemSetTypeFlag(pOut, MEM_Null); REGISTER_TRACE(pOp->p2, pOut); }else if( pOp->p5 & SQLITE_JUMPIFNULL ){ pc = pOp->p2-1; } break; @@ -1620,12 +1624,11 @@ default: res = res>=0; break; } if( pOp->p5 & SQLITE_STOREP2 ){ pOut = &p->aMem[pOp->p2]; - Release(pOut); - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); pOut->u.i = res; REGISTER_TRACE(pOp->p2, pOut); }else if( res ){ pc = pOp->p2-1; } @@ -1669,16 +1672,15 @@ v1 = and_logic[v1*3+v2]; }else{ static const unsigned char or_logic[] = { 0, 1, 2, 1, 1, 1, 2, 1, 2 }; v1 = or_logic[v1*3+v2]; } - Release(pOut); if( v1==2 ){ - pOut->flags = MEM_Null; + MemSetTypeFlag(pOut, MEM_Null); }else{ pOut->u.i = v1; - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); } break; } /* Opcode: Not P1 * * * * @@ -1689,11 +1691,11 @@ */ case OP_Not: { /* same as TK_NOT, in1 */ if( pIn1->flags & MEM_Null ) break; /* Do nothing to NULLs */ sqlite3VdbeMemIntegerify(pIn1); pIn1->u.i = !pIn1->u.i; - assert( pIn1->flags==MEM_Int ); + assert( pIn1->flags&MEM_Int ); break; } /* Opcode: BitNot P1 * * * * ** @@ -1703,11 +1705,11 @@ */ case OP_BitNot: { /* same as TK_BITNOT, in1 */ if( pIn1->flags & MEM_Null ) break; /* Do nothing to NULLs */ sqlite3VdbeMemIntegerify(pIn1); pIn1->u.i = ~pIn1->u.i; - assert( pIn1->flags==MEM_Int ); + assert( pIn1->flags&MEM_Int ); break; } /* Opcode: If P1 P2 P3 * * ** @@ -1821,14 +1823,15 @@ char *zData; /* Part of the record being decoded */ Mem *pDest; /* Where to write the extracted value */ Mem sMem; /* For storing the record being decoded */ sMem.flags = 0; + sMem.db = 0; assert( p1nCursor ); assert( pOp->p3>0 && pOp->p3<=p->nMem ); pDest = &p->aMem[pOp->p3]; - sqlite3VdbeMemSetNull(pDest); + MemSetTypeFlag(pDest, MEM_Null); /* This block sets the variable payloadSize to be the total number of ** bytes in the record. ** ** zRec is set to be the complete text of the record if it is available. @@ -1875,11 +1878,11 @@ pCrsr = 0; } /* If payloadSize is 0, then just store a NULL */ if( payloadSize==0 ){ - assert( pDest->flags==MEM_Null ); + assert( pDest->flags&MEM_Null ); goto op_column_out; } if( payloadSize>SQLITE_MAX_LENGTH ){ goto too_big; } @@ -1941,10 +1944,12 @@ ** record header if the record header does not fit on a single page ** in the B-Tree. When that happens, use sqlite3VdbeMemFromBtree() to ** acquire the complete header text. */ if( !zRec && availisIndex, &sMem); if( rc!=SQLITE_OK ){ goto op_column_out; } zData = sMem.z; @@ -1992,45 +1997,51 @@ ** a pointer to a Mem object. */ if( aOffset[p2] ){ assert( rc==SQLITE_OK ); if( zRec ){ - zData = &zRec[aOffset[p2]]; + if( pDest->flags&MEM_Dyn ){ + sqlite3VdbeSerialGet((u8 *)&zRec[aOffset[p2]], aType[p2], &sMem); + sMem.db = db; + sqlite3VdbeMemCopy(pDest, &sMem); + assert( !(sMem.flags&MEM_Dyn) ); + }else{ + sqlite3VdbeSerialGet((u8 *)&zRec[aOffset[p2]], aType[p2], pDest); + } }else{ len = sqlite3VdbeSerialTypeLen(aType[p2]); + sqlite3VdbeMemMove(&sMem, pDest); rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->isIndex, &sMem); if( rc!=SQLITE_OK ){ goto op_column_out; } zData = sMem.z; + sqlite3VdbeSerialGet((u8*)zData, aType[p2], pDest); } - sqlite3VdbeSerialGet((u8*)zData, aType[p2], pDest); pDest->enc = encoding; }else{ if( pOp->p4type==P4_MEM ){ sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static); }else{ - assert( pDest->flags==MEM_Null ); + assert( pDest->flags&MEM_Null ); } } /* 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 pDest structure. ** This prevents a memory copy. */ if( (sMem.flags & MEM_Dyn)!=0 ){ - assert( pDest->flags & MEM_Ephem ); - assert( pDest->flags & (MEM_Str|MEM_Blob) ); - assert( pDest->z==sMem.z ); - assert( sMem.flags & MEM_Term ); - pDest->flags &= ~MEM_Ephem; + assert( !sMem.xDel ); + assert( !(pDest->flags & MEM_Dyn) ); + assert( !(pDest->flags & (MEM_Blob|MEM_Str)) || pDest->z==sMem.z ); + pDest->flags &= ~(MEM_Ephem|MEM_Static); pDest->flags |= MEM_Dyn|MEM_Term; + pDest->z = sMem.z; } - /* pDest->z might be pointing to sMem.zShort[]. Fix that so that we - ** can abandon sMem */ rc = sqlite3VdbeMemMakeWriteable(pDest); op_column_out: UPDATE_MAX_BLOBSIZE(pDest); REGISTER_TRACE(pOp->p3, pDest); @@ -2084,11 +2095,10 @@ Mem *pLast; /* Last field of the record */ int nField; /* Number of fields in the record */ char *zAffinity; /* The affinity string for the record */ int file_format; /* File format to use for encoding */ int i; /* Space used in zNewRecord[] */ - char zTemp[NBFS]; /* Space to hold small records */ nField = pOp->p1; zAffinity = pOp->p4.z; assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem ); pData0 = &p->aMem[nField]; @@ -2128,19 +2138,21 @@ nByte = nHdr+nData-nZero; if( nByte>SQLITE_MAX_LENGTH ){ goto too_big; } - /* Allocate space for the new record. */ - if( nByte>sizeof(zTemp) ){ - zNewRecord = sqlite3DbMallocRaw(db, nByte); - if( !zNewRecord ){ - goto no_mem; - } - }else{ - zNewRecord = (u8*)zTemp; - } + /* Make sure the output register has a buffer large enough to store + ** the new record. The output register (pOp->p3) is not allowed to + ** 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 = &p->aMem[pOp->p3]; + if( sqlite3VdbeMemGrow(pOut, nByte, 0) ){ + goto no_mem; + } + zNewRecord = (u8 *)pOut->z; /* Write the record */ i = sqlite3PutVarint(zNewRecord, nHdr); for(pRec=pData0; pRec<=pLast; pRec++){ serial_type = sqlite3VdbeSerialType(pRec, file_format); @@ -2150,24 +2162,13 @@ i += sqlite3VdbeSerialPut(&zNewRecord[i], nByte-i, pRec, file_format); } assert( i==nByte ); assert( pOp->p3>0 && pOp->p3<=p->nMem ); - pOut = &p->aMem[pOp->p3]; - Release(pOut); pOut->n = nByte; - if( nByte<=sizeof(zTemp) ){ - assert( zNewRecord==(unsigned char *)zTemp ); - pOut->z = pOut->zShort; - memcpy(pOut->zShort, zTemp, nByte); - pOut->flags = MEM_Blob | MEM_Short; - }else{ - assert( zNewRecord!=(unsigned char *)zTemp ); - pOut->z = (char*)zNewRecord; - pOut->flags = MEM_Blob | MEM_Dyn; - pOut->xDel = 0; - } + pOut->flags = MEM_Blob | MEM_Dyn; + pOut->xDel = 0; if( nZero ){ pOut->u.i = nZero; pOut->flags |= MEM_Zero; } pOut->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */ @@ -2341,11 +2342,11 @@ ** meta[1] to be the schema cookie. So we have to shift the index ** by one in the following statement. */ rc = sqlite3BtreeGetMeta(db->aDb[iDb].pBt, 1 + iCookie, (u32 *)&iMeta); pOut->u.i = iMeta; - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); break; } /* Opcode: SetCookie P1 P2 P3 * * ** @@ -2894,11 +2895,10 @@ assert( pOp->p4type==P4_INT32 ); assert( pOp->p4.i>0 && pOp->p4.i<=p->nMem ); pK = &p->aMem[pOp->p4.i]; sqlite3VdbeMemIntegerify(pIn3); R = pIn3->u.i; - assert( (pIn3->flags & MEM_Dyn)==0 ); assert( i>=0 && inCursor ); pCx = p->apCsr[i]; assert( pCx!=0 ); pCrsr = pCx->pCursor; if( pCrsr!=0 ){ @@ -2958,11 +2958,11 @@ /* The final varint of the key is different from R. Store it back ** into register R3. (The record number of an entry that violates ** a UNIQUE constraint.) */ pIn3->u.i = v; - assert( pIn3->flags==MEM_Int ); + assert( pIn3->flags&MEM_Int ); } break; } /* Opcode: NotExists P1 P2 P3 * * @@ -3019,11 +3019,11 @@ case OP_Sequence: { /* out2-prerelease */ int i = pOp->p1; assert( i>=0 && inCursor ); assert( p->apCsr[i]!=0 ); pOut->u.i = p->apCsr[i]->seqCount++; - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); break; } /* Opcode: NewRowid P1 P2 P3 * * @@ -3172,11 +3172,11 @@ } pC->rowidIsValid = 0; pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; } - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); pOut->u.i = v; break; } /* Opcode: Insert P1 P2 P3 P4 P5 @@ -3366,16 +3366,18 @@ ** it is found in the database file. ** ** If the P1 cursor must be pointing to a valid row (not a NULL row) ** of a real table, not a pseudo-table. */ -case OP_RowKey: /* out2-prerelease */ -case OP_RowData: { /* out2-prerelease */ +case OP_RowKey: +case OP_RowData: { int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; u32 n; + + pOut = &p->aMem[pOp->p2]; /* Note that RowKey and RowData are really exactly the same instruction */ assert( i>=0 && inCursor ); pC = p->apCsr[i]; assert( pC->isTable || pOp->opcode==OP_RowKey ); @@ -3399,21 +3401,15 @@ sqlite3BtreeDataSize(pCrsr, &n); if( n>SQLITE_MAX_LENGTH ){ goto too_big; } } + if( sqlite3VdbeMemGrow(pOut, n, 0) ){ + goto no_mem; + } pOut->n = n; - if( n<=NBFS ){ - pOut->flags = MEM_Blob | MEM_Short; - pOut->z = pOut->zShort; - }else{ - char *z = sqlite3_malloc( n ); - if( z==0 ) goto no_mem; - pOut->flags = MEM_Blob | MEM_Dyn; - pOut->xDel = 0; - pOut->z = z; - } + MemSetTypeFlag(pOut, MEM_Blob); if( pC->isIndex ){ rc = sqlite3BtreeKey(pCrsr, 0, n, pOut->z); }else{ rc = sqlite3BtreeData(pCrsr, 0, n, pOut->z); } @@ -3448,11 +3444,11 @@ assert( pC->pCursor!=0 ); sqlite3BtreeKeySize(pC->pCursor, &v); v = keyToInt(v); } pOut->u.i = v; - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); break; } /* Opcode: NullRow P1 * * * * ** @@ -3640,12 +3636,13 @@ break; } /* Opcode: IdxDelete P1 P2 * * * ** -** The content of register P2 is an index key built using the either the -** MakeIdxRec opcode. Removes that entry from the index. +** The content of register P2 is an index key built using the +** MakeIdxRec opcode. This opcode removes that entry from the +** index opened by cursor P1. */ case OP_IdxDelete: { /* in2 */ int i = pOp->p1; Cursor *pC; BtCursor *pCrsr; @@ -3687,11 +3684,11 @@ if( !pC->nullRow ){ rc = sqlite3VdbeIdxRowid(pCrsr, &rowid); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); pOut->u.i = rowid; } } break; } @@ -3799,11 +3796,11 @@ }else{ int iDb = pOp->p3; assert( iCnt==1 ); assert( (p->btreeMask & (1<aDb[iDb].pBt, pOp->p1, &iMoved); - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); pOut->u.i = iMoved; #ifndef SQLITE_OMIT_AUTOVACUUM if( rc==SQLITE_OK && iMoved!=0 ){ sqlite3RootPageMoved(&db->aDb[iDb], iMoved, pOp->p1); } @@ -3868,11 +3865,11 @@ flags = BTREE_ZERODATA; } rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags); if( rc==SQLITE_OK ){ pOut->u.i = pgno; - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); } break; } /* Opcode: ParseSchema P1 P2 * P4 * @@ -4021,16 +4018,12 @@ pnErr->u.i -= nErr; sqlite3VdbeMemSetNull(pIn1); if( nErr==0 ){ assert( z==0 ); }else{ - pIn1->z = z; - pIn1->n = strlen(z); - pIn1->flags = MEM_Str | MEM_Dyn | MEM_Term; - pIn1->xDel = 0; + sqlite3VdbeMemSetStr(pIn1, z, -1, SQLITE_UTF8, sqlite3_free); } - pIn1->enc = SQLITE_UTF8; UPDATE_MAX_BLOBSIZE(pIn1); sqlite3VdbeChangeEncoding(pIn1, encoding); sqlite3_free(aRoot); break; } @@ -4056,12 +4049,11 @@ */ case OP_FifoRead: { /* jump */ CHECK_FOR_INTERRUPT; assert( pOp->p1>0 && pOp->p1<=p->nMem ); pOut = &p->aMem[pOp->p1]; - Release(pOut); - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); if( sqlite3VdbeFifoPop(&p->sFifo, &pOut->u.i)==SQLITE_DONE ){ pc = pOp->p2 - 1; } break; } @@ -4135,11 +4127,11 @@ ** ** It is illegal to use this instruction on a register that does ** not contain an integer. An assertion fault will result if you try. */ case OP_IfPos: { /* jump, in1 */ - assert( pIn1->flags==MEM_Int ); + assert( pIn1->flags&MEM_Int ); if( pIn1->u.i>0 ){ pc = pOp->p2 - 1; } break; } @@ -4150,11 +4142,11 @@ ** ** It is illegal to use this instruction on a register that does ** not contain an integer. An assertion fault will result if you try. */ case OP_IfNeg: { /* jump, in1 */ - assert( pIn1->flags==MEM_Int ); + assert( pIn1->flags&MEM_Int ); if( pIn1->u.i<0 ){ pc = pOp->p2 - 1; } break; } @@ -4165,11 +4157,11 @@ ** ** It is illegal to use this instruction on a register that does ** not contain an integer. An assertion fault will result if you try. */ case OP_IfZero: { /* jump, in1 */ - assert( pIn1->flags==MEM_Int ); + assert( pIn1->flags&MEM_Int ); if( pIn1->u.i==0 ){ pc = pOp->p2 - 1; } break; } @@ -4500,11 +4492,11 @@ pModule = pCur->pVtabCursor->pVtab->pModule; assert( pModule->xRowid ); if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; rc = pModule->xRowid(pCur->pVtabCursor, &iRow); if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; - pOut->flags = MEM_Int; + MemSetTypeFlag(pOut, MEM_Int); pOut->u.i = iRow; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ @@ -4529,12 +4521,19 @@ break; } pModule = pCur->pVtabCursor->pVtab->pModule; assert( pModule->xColumn ); memset(&sContext, 0, sizeof(sContext)); - sContext.s.flags = MEM_Null; - sContext.s.db = db; + + /* The output cell may already have a buffer allocated. Move + ** the current contents to sContext.s so in case the user-function + ** can use the already allocated buffer instead of allocating a + ** new one. + */ + sqlite3VdbeMemMove(&sContext.s, pDest); + MemSetTypeFlag(&sContext.s, MEM_Null); + if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2); /* Copy the result of the function to the P3 register. We ** do this regardless of whether or not an error occured to ensure any Index: src/vdbeInt.h ================================================================== --- src/vdbeInt.h +++ src/vdbeInt.h @@ -92,17 +92,10 @@ u32 *aOffset; /* Cached offsets to the start of each columns data */ u8 *aRow; /* Data for the current row, if all on one page */ }; typedef struct Cursor Cursor; -/* -** Number of bytes of string storage space available to each stack -** layer without having to malloc. NBFS is short for Number of Bytes -** For Strings. -*/ -#define NBFS 32 - /* ** A value for Cursor.cacheValid that means the cache is always invalid. */ #define CACHE_STALE 0 @@ -128,11 +121,10 @@ int n; /* Number of characters in string value, excluding '\0' */ 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 */ void (*xDel)(void *); /* If not null, call this function to delete Mem.z */ - char zShort[NBFS]; /* Space for short strings */ }; /* One or more of the following flags are set to indicate the validOK ** representations of the value stored in the Mem struct. ** @@ -152,20 +144,22 @@ #define MEM_Str 0x0002 /* Value is a string */ #define MEM_Int 0x0004 /* Value is an integer */ #define MEM_Real 0x0008 /* Value is a real number */ #define MEM_Blob 0x0010 /* Value is a BLOB */ +#define MemSetTypeFlag(p, f) \ + ((p)->flags = ((p)->flags&~(MEM_Int|MEM_Real|MEM_Null|MEM_Blob|MEM_Str))|f) + /* Whenever Mem contains a valid string or blob representation, one of ** the following flags must be set to determine the memory management ** policy for Mem.z. The MEM_Term flag tells us whether or not the ** string is \000 or \u0000 terminated */ #define MEM_Term 0x0020 /* String rep is nul terminated */ #define MEM_Dyn 0x0040 /* Need to call sqliteFree() on Mem.z */ #define MEM_Static 0x0080 /* Mem.z points to a static string */ #define MEM_Ephem 0x0100 /* Mem.z points to an ephemeral string */ -#define MEM_Short 0x0200 /* Mem.z points to Mem.zShort */ #define MEM_Agg 0x0400 /* Mem.z points to an agg function context */ #define MEM_Zero 0x0800 /* Mem.i contains count of 0s appended to blob */ #ifdef SQLITE_OMIT_INCRBLOB #undef MEM_Zero @@ -396,10 +390,11 @@ int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*); void sqlite3VdbeMemRelease(Mem *p); int sqlite3VdbeMemFinalize(Mem*, FuncDef*); const char *sqlite3OpcodeName(int); int sqlite3VdbeOpcodeHasProperty(int, int); +int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); #ifndef NDEBUG void sqlite3VdbeMemSanity(Mem*); #endif int sqlite3VdbeMemTranslate(Mem*, u8); Index: src/vdbeapi.c ================================================================== --- src/vdbeapi.c +++ src/vdbeapi.c @@ -942,10 +942,11 @@ sqlite3_mutex_enter(p->db->mutex); rc = vdbeUnbind(p, i); if( rc==SQLITE_OK ){ rc = sqlite3VdbeMemCopy(&p->aVar[i-1], pValue); } + rc = sqlite3ApiExit(p->db, rc); sqlite3_mutex_leave(p->db->mutex); return rc; } int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){ int rc; Index: src/vdbeaux.c ================================================================== --- src/vdbeaux.c +++ src/vdbeaux.c @@ -733,15 +733,19 @@ /* ** Release an array of N Mem elements */ static void releaseMemArray(Mem *p, int N){ - if( p ){ + if( p && N ){ + sqlite3 *db = p->db; + int malloc_failed = db->mallocFailed; while( N-->0 ){ assert( N<2 || p[0].db==p[1].db ); - sqlite3VdbeMemSetNull(p++); + sqlite3VdbeMemRelease(p); + p++->flags = MEM_Null; } + db->mallocFailed = malloc_failed; } } #ifndef SQLITE_OMIT_EXPLAIN /* @@ -784,10 +788,11 @@ }else if( db->u1.isInterrupted ){ p->rc = SQLITE_INTERRUPT; rc = SQLITE_ERROR; sqlite3SetString(&p->zErrMsg, sqlite3ErrStr(p->rc), (char*)0); }else{ + char *z; Op *pOp = &p->aOp[i]; if( p->explain==1 ){ pMem->flags = MEM_Int; pMem->type = SQLITE_INTEGER; pMem->u.i = i; /* Program counter */ @@ -817,22 +822,33 @@ pMem->u.i = pOp->p3; /* P3 */ pMem->type = SQLITE_INTEGER; pMem++; } - pMem->flags = MEM_Ephem|MEM_Str|MEM_Term; /* P4 */ - pMem->z = displayP4(pOp, pMem->zShort, sizeof(pMem->zShort)); - assert( pMem->z!=0 ); - pMem->n = strlen(pMem->z); + if( sqlite3VdbeMemGrow(pMem, 32, 0) ){ /* P4 */ + p->db->mallocFailed = 1; + return SQLITE_NOMEM; + } + pMem->flags = MEM_Dyn|MEM_Str|MEM_Term; + z = displayP4(pOp, pMem->z, 32); + if( z!=pMem->z ){ + sqlite3VdbeMemSetStr(pMem, z, -1, SQLITE_UTF8, 0); + }else{ + assert( pMem->z!=0 ); + pMem->n = strlen(pMem->z); + pMem->enc = SQLITE_UTF8; + } pMem->type = SQLITE_TEXT; - pMem->enc = SQLITE_UTF8; pMem++; if( p->explain==1 ){ - pMem->flags = MEM_Str|MEM_Term|MEM_Short; - pMem->n = sprintf(pMem->zShort, "%.2x", pOp->p5); /* P5 */ - pMem->z = pMem->zShort; + if( sqlite3VdbeMemGrow(pMem, 32, 0) ){ + p->db->mallocFailed = 1; + return SQLITE_NOMEM; + } + pMem->flags = MEM_Dyn|MEM_Str|MEM_Term; + pMem->n = sprintf(pMem->z, "%.2x", pOp->p5); /* P5 */ pMem->type = SQLITE_TEXT; pMem->enc = SQLITE_UTF8; pMem++; pMem->flags = MEM_Null; /* Comment */ @@ -1056,10 +1072,13 @@ ** variables in the aVar[] array. */ static void Cleanup(Vdbe *p){ int i; closeAllCursorsExceptActiveVtabs(p); + for(i=1; i<=p->nMem; i++){ + MemSetTypeFlag(&p->aMem[i], MEM_Null); + } releaseMemArray(&p->aMem[1], p->nMem); sqlite3VdbeFifoClear(&p->sFifo); if( p->contextStack ){ for(i=0; icontextStackTop; i++){ sqlite3VdbeFifoClear(&p->contextStack[i].sFifo); @@ -2131,12 +2150,14 @@ Mem mem1; Mem mem2; mem1.enc = pKeyInfo->enc; mem1.db = pKeyInfo->db; + mem1.flags = 0; mem2.enc = pKeyInfo->enc; mem2.db = pKeyInfo->db; + mem2.flags = 0; idx1 = GetVarint(aKey1, szHdr1); d1 = szHdr1; idx2 = GetVarint(aKey2, szHdr2); d2 = szHdr2; @@ -2157,12 +2178,12 @@ d2 += sqlite3VdbeSerialGet(&aKey2[d2], serial_type2, &mem2); /* Do the comparison */ rc = sqlite3MemCompare(&mem1, &mem2, iaColl[i] : 0); - if( mem1.flags & MEM_Dyn ) sqlite3VdbeMemRelease(&mem1); - if( mem2.flags & MEM_Dyn ) sqlite3VdbeMemRelease(&mem2); + if( mem1.flags&MEM_Dyn ) sqlite3VdbeMemRelease(&mem1); + if( mem2.flags&MEM_Dyn ) sqlite3VdbeMemRelease(&mem2); if( rc!=0 ){ break; } i++; } @@ -2220,10 +2241,12 @@ sqlite3BtreeKeySize(pCur, &nCellKey); if( nCellKey<=0 ){ return SQLITE_CORRUPT_BKPT; } + m.flags = 0; + m.db = 0; rc = sqlite3VdbeMemFromBtree(pCur, 0, nCellKey, 1, &m); if( rc ){ return rc; } sqlite3GetVarint32((u8*)m.z, &szHdr); @@ -2259,10 +2282,12 @@ sqlite3BtreeKeySize(pCur, &nCellKey); if( nCellKey<=0 ){ *res = 0; return SQLITE_OK; } + m.db = 0; + m.flags = 0; rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, nCellKey, 1, &m); if( rc ){ return rc; } lenRowid = sqlite3VdbeIdxRowidLen((u8*)m.z); Index: src/vdbemem.c ================================================================== --- src/vdbemem.c +++ src/vdbemem.c @@ -56,38 +56,88 @@ assert(rc==SQLITE_OK || pMem->enc!=desiredEnc); assert(rc==SQLITE_NOMEM || pMem->enc==desiredEnc); return rc; #endif } + +/* +** Make sure pMem->z points to a writable allocation of at least +** n bytes. +** +** If the memory cell currently contains string or blob data +** and the third argument passed to this function is true, the +** current content of the cell is preserved. Otherwise, it may +** be discarded. +** +** This function sets the MEM_Dyn flag and clears any xDel callback. +** It also clears MEM_Ephem and MEM_Static. If the preserve flag is +** not set, Mem.n is zeroed. +*/ +int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve){ + int f = pMem->flags; + + assert( (f & (MEM_Dyn|MEM_Static|MEM_Ephem))==0 + || (f & (MEM_Dyn|MEM_Static|MEM_Ephem))==MEM_Dyn + || (f & (MEM_Dyn|MEM_Static|MEM_Ephem))==MEM_Ephem + || (f & (MEM_Dyn|MEM_Static|MEM_Ephem))==MEM_Static + ); + + if( ((f&MEM_Dyn)==0 || pMem->xDel || sqlite3MallocSize(pMem->z)0 ){ + if( preserve && (f&MEM_Dyn) && !pMem->xDel ){ + z = sqlite3DbReallocOrFree(pMem->db, pMem->z, n); + pMem->z = 0; + preserve = 0; + }else{ + z = sqlite3DbMallocRaw(pMem->db, (n>32?n:32)); + } + if( !z ){ + return SQLITE_NOMEM; + } + } + + /* If the value is currently a string or blob and the preserve flag + ** is true, copy the content to the new buffer. + */ + if( pMem->flags&(MEM_Blob|MEM_Str) && preserve ){ + int nCopy = (pMem->n>n?n:pMem->n); + memcpy(z, pMem->z, nCopy); + } + + /* Release the old buffer. */ + sqlite3VdbeMemRelease(pMem); + + pMem->z = z; + pMem->flags |= MEM_Dyn; + pMem->flags &= ~(MEM_Ephem|MEM_Static); + pMem->xDel = 0; + } + return SQLITE_OK; +} /* ** Make the given Mem object MEM_Dyn. ** ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. */ int sqlite3VdbeMemDynamicify(Mem *pMem){ - int n; - u8 *z; + int f; assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); expandBlob(pMem); - if( (pMem->flags & (MEM_Ephem|MEM_Static|MEM_Short))==0 ){ - return SQLITE_OK; - } - assert( (pMem->flags & MEM_Dyn)==0 ); - n = pMem->n; - assert( pMem->flags & (MEM_Str|MEM_Blob) ); - z = sqlite3DbMallocRaw(pMem->db, n+2 ); - if( z==0 ){ - return SQLITE_NOMEM; - } - pMem->flags |= MEM_Dyn|MEM_Term; - pMem->xDel = 0; - memcpy(z, pMem->z, n ); - z[n] = 0; - z[n+1] = 0; - pMem->z = (char*)z; - pMem->flags &= ~(MEM_Ephem|MEM_Static|MEM_Short); + f = pMem->flags; + if( (f&(MEM_Str|MEM_Blob)) && ((f&MEM_Dyn)==0 || pMem->xDel) ){ + if( sqlite3VdbeMemGrow(pMem, pMem->n + 2, 1) ){ + return SQLITE_NOMEM; + } + pMem->z[pMem->n] = 0; + pMem->z[pMem->n+1] = 0; + pMem->flags |= MEM_Term; + } + return SQLITE_OK; } /* ** If the given Mem* has a zero-filled tail, turn it into an ordinary @@ -94,28 +144,26 @@ ** blob stored in dynamically allocated space. */ #ifndef SQLITE_OMIT_INCRBLOB int sqlite3VdbeMemExpandBlob(Mem *pMem){ if( pMem->flags & MEM_Zero ){ - char *pNew; int nByte; - assert( (pMem->flags & MEM_Blob)!=0 ); + assert( pMem->flags&MEM_Blob ); + assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + + /* Set nByte to the number of bytes required to store the expanded blob. */ nByte = pMem->n + pMem->u.i; - if( nByte<=0 ) nByte = 1; - assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - pNew = sqlite3DbMallocRaw(pMem->db, nByte); - if( pNew==0 ){ + if( nByte<=0 ){ + nByte = 1; + } + if( sqlite3VdbeMemGrow(pMem, nByte, 1) ){ return SQLITE_NOMEM; } - memcpy(pNew, pMem->z, pMem->n); - memset(&pNew[pMem->n], 0, pMem->u.i); - sqlite3VdbeMemRelease(pMem); - pMem->z = pNew; + + memset(&pMem->z[pMem->n], 0, pMem->u.i); pMem->n += pMem->u.i; - pMem->u.i = 0; - pMem->flags &= ~(MEM_Zero|MEM_Static|MEM_Ephem|MEM_Short|MEM_Term); - pMem->flags |= MEM_Dyn; + pMem->flags &= ~(MEM_Zero|MEM_Term); } return SQLITE_OK; } #endif @@ -125,37 +173,11 @@ ** of the Mem.z[] array can be modified. ** ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. */ int sqlite3VdbeMemMakeWriteable(Mem *pMem){ - int n; - u8 *z; - assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - 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) ); - if( (n = pMem->n)+2zShort) ){ - z = (u8*)pMem->zShort; - pMem->flags |= MEM_Short|MEM_Term; - }else{ - z = sqlite3DbMallocRaw(pMem->db, n+2 ); - if( z==0 ){ - return SQLITE_NOMEM; - } - pMem->flags |= MEM_Dyn|MEM_Term; - pMem->xDel = 0; - } - memcpy(z, pMem->z, n ); - z[n] = 0; - z[n+1] = 0; - pMem->z = (char*)z; - pMem->flags &= ~(MEM_Ephem|MEM_Static); - assert(0==(1&(int)pMem->z)); - return SQLITE_OK; + return sqlite3VdbeMemDynamicify(pMem); } /* ** Make sure the given Mem is \u0000 terminated. */ @@ -162,31 +184,16 @@ int sqlite3VdbeMemNulTerminate(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); if( (pMem->flags & MEM_Term)!=0 || (pMem->flags & MEM_Str)==0 ){ return SQLITE_OK; /* Nothing to do */ } - if( pMem->flags & (MEM_Static|MEM_Ephem) ){ - return sqlite3VdbeMemMakeWriteable(pMem); - }else{ - char *z; - sqlite3VdbeMemExpandBlob(pMem); - z = sqlite3DbMallocRaw(pMem->db, pMem->n+2); - if( !z ){ - return SQLITE_NOMEM; - } - memcpy(z, pMem->z, pMem->n); - z[pMem->n] = 0; - z[pMem->n+1] = 0; - if( pMem->xDel ){ - pMem->xDel(pMem->z); - }else{ - sqlite3_free(pMem->z); - } - pMem->xDel = 0; - pMem->z = z; - pMem->flags |= MEM_Term; - } + if( sqlite3VdbeMemGrow(pMem, pMem->n+2, 1) ){ + return SQLITE_NOMEM; + } + pMem->z[pMem->n] = 0; + pMem->z[pMem->n+1] = 0; + pMem->flags |= MEM_Term; return SQLITE_OK; } /* ** Add MEM_Str to the set of representations for the given Mem. Numbers @@ -202,33 +209,36 @@ ** user and the later is an internal programming error. */ int sqlite3VdbeMemStringify(Mem *pMem, int enc){ int rc = SQLITE_OK; int fg = pMem->flags; - char *z = pMem->zShort; + const int nByte = 32; assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( !(fg&MEM_Zero) ); assert( !(fg&(MEM_Str|MEM_Blob)) ); assert( fg&(MEM_Int|MEM_Real) ); - /* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8 + if( sqlite3VdbeMemGrow(pMem, nByte, 0) ){ + return SQLITE_NOMEM; + } + + /* For a Real or Integer, use sqlite3_mprintf() to produce the UTF-8 ** string representation of the value. Then, if the required encoding ** is UTF-16le or UTF-16be do a translation. ** ** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16. */ if( fg & MEM_Int ){ - sqlite3_snprintf(NBFS, z, "%lld", pMem->u.i); + sqlite3_snprintf(nByte, pMem->z, "%lld", pMem->u.i); }else{ assert( fg & MEM_Real ); - sqlite3_snprintf(NBFS, z, "%!.15g", pMem->r); + sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->r); } - pMem->n = strlen(z); - pMem->z = z; + pMem->n = strlen(pMem->z); pMem->enc = SQLITE_UTF8; - pMem->flags |= MEM_Str | MEM_Short | MEM_Term; + pMem->flags |= MEM_Str|MEM_Term; sqlite3VdbeChangeEncoding(pMem, enc); return rc; } /* @@ -244,23 +254,19 @@ if( pFunc && pFunc->xFinalize ){ sqlite3_context ctx; assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); ctx.s.flags = MEM_Null; - ctx.s.z = pMem->zShort; ctx.s.db = pMem->db; ctx.pMem = pMem; ctx.pFunc = pFunc; ctx.isError = 0; pFunc->xFinalize(&ctx); - if( pMem->z && pMem->z!=pMem->zShort ){ + if( pMem->z ){ sqlite3_free( pMem->z ); } *pMem = ctx.s; - if( pMem->flags & MEM_Short ){ - pMem->z = pMem->zShort; - } rc = (ctx.isError?SQLITE_ERROR:SQLITE_OK); } return rc; } @@ -391,19 +397,22 @@ pMem->u.i = doubleToInt64(pMem->r); if( pMem->r==(double)pMem->u.i ){ pMem->flags |= MEM_Int; } } + +static void setTypeFlag(Mem *pMem, int f){ + MemSetTypeFlag(pMem, f); +} /* ** Convert pMem to type integer. Invalidate any prior representations. */ int sqlite3VdbeMemIntegerify(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); pMem->u.i = sqlite3VdbeIntValue(pMem); - sqlite3VdbeMemRelease(pMem); - pMem->flags = MEM_Int; + setTypeFlag(pMem, MEM_Int); return SQLITE_OK; } /* ** Convert pMem so that it is of type MEM_Real. @@ -410,12 +419,11 @@ ** Invalidate any prior representations. */ int sqlite3VdbeMemRealify(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); pMem->r = sqlite3VdbeRealValue(pMem); - sqlite3VdbeMemRelease(pMem); - pMem->flags = MEM_Real; + setTypeFlag(pMem, MEM_Real); return SQLITE_OK; } /* ** Convert pMem so that it has types MEM_Real or MEM_Int or both. @@ -432,38 +440,35 @@ r2 = (double)i; if( r1==r2 ){ sqlite3VdbeMemIntegerify(pMem); }else{ pMem->r = r1; - pMem->flags = MEM_Real; - sqlite3VdbeMemRelease(pMem); + setTypeFlag(pMem, MEM_Real); } return SQLITE_OK; } /* ** Delete any previous value and set the value stored in *pMem to NULL. */ void sqlite3VdbeMemSetNull(Mem *pMem){ - sqlite3VdbeMemRelease(pMem); - pMem->flags = MEM_Null; + setTypeFlag(pMem, MEM_Null); pMem->type = SQLITE_NULL; - pMem->n = 0; } /* ** Delete any previous value and set the value to be a BLOB of length ** n containing all zeros. */ void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ sqlite3VdbeMemRelease(pMem); - pMem->flags = MEM_Blob|MEM_Zero|MEM_Short; + setTypeFlag(pMem, MEM_Blob); + pMem->flags = MEM_Blob|MEM_Zero; pMem->type = SQLITE_BLOB; pMem->n = 0; if( n<0 ) n = 0; pMem->u.i = n; - pMem->z = pMem->zShort; pMem->enc = SQLITE_UTF8; } /* ** Delete any previous value and set the value stored in *pMem to val, @@ -512,14 +517,14 @@ ** 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). */ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ sqlite3VdbeMemRelease(pTo); - memcpy(pTo, pFrom, sizeof(*pFrom)-sizeof(pFrom->zShort)); + memcpy(pTo, pFrom, sizeof(*pFrom)); pTo->xDel = 0; - if( pTo->flags & (MEM_Str|MEM_Blob) ){ - pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short|MEM_Ephem); + if( pTo->flags&MEM_Dyn ){ + pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Ephem); assert( srcType==MEM_Ephem || srcType==MEM_Static ); pTo->flags |= srcType; } } @@ -526,16 +531,50 @@ /* ** 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; - sqlite3VdbeMemShallowCopy(pTo, pFrom, MEM_Ephem); - if( pTo->flags & MEM_Ephem ){ - rc = sqlite3VdbeMemMakeWriteable(pTo); + int rc = SQLITE_OK; + char *zBuf = 0; + + /* If cell pTo currently has a reusable buffer, save a pointer to it + ** in local variable zBuf. This function attempts to avoid freeing + ** this buffer. + */ + if( pTo->xDel ){ + sqlite3VdbeMemRelease(pTo); + }else if( pTo->flags&MEM_Dyn ){ + zBuf = pTo->z; + } + + /* Copy the contents of *pFrom to *pTo */ + memcpy(pTo, pFrom, sizeof(*pFrom)); + + if( pTo->flags&(MEM_Str|MEM_Blob) && pTo->flags&MEM_Static ){ + /* pFrom contained a pointer to a static string. In this case, + ** free any dynamically allocated buffer associated with pTo. + */ + sqlite3_free(zBuf); }else{ - rc = SQLITE_OK; + char *zData = pTo->z; + + pTo->z = zBuf; + pTo->flags &= ~(MEM_Static|MEM_Ephem); + pTo->flags |= MEM_Dyn; + pTo->xDel = 0; + + if( pTo->flags&(MEM_Str|MEM_Blob) ){ + if( sqlite3VdbeMemGrow(pTo, pTo->n+2, 0) ){ + pTo->n = 0; + rc = SQLITE_NOMEM; + }else{ + memcpy(pTo->z, zData, pTo->n); + pTo->z[pTo->n] = '\0'; + pTo->z[pTo->n+1] = '\0'; + pTo->flags |= MEM_Term; + } + } } return rc; } /* @@ -550,80 +589,80 @@ assert( pFrom->db==0 || pTo->db==0 || pFrom->db==pTo->db ); 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; } /* ** Change the value of a Mem to be a string or a BLOB. +** +** The memory management strategy depends on the value of the xDel +** parameter. If the value passed is SQLITE_TRANSIENT, then the +** string is copied into a (possibly existing) buffer managed by the +** Mem structure. Otherwise, any existing buffer is freed and the +** pointer copied. */ int sqlite3VdbeMemSetStr( Mem *pMem, /* Memory cell to set to string value */ const char *z, /* String pointer */ int n, /* Bytes in string, or negative */ u8 enc, /* Encoding of z. 0 for BLOBs */ void (*xDel)(void*) /* Destructor function */ ){ + int nByte = n; /* New value for pMem->n */ + int flags = 0; /* New value for pMem->flags */ + assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - sqlite3VdbeMemRelease(pMem); + + /* If z is a NULL pointer, set pMem to contain an SQL NULL. */ if( !z ){ - pMem->flags = MEM_Null; - pMem->type = SQLITE_NULL; + sqlite3VdbeMemSetNull(pMem); return SQLITE_OK; } - pMem->z = (char *)z; - if( xDel==SQLITE_STATIC ){ - pMem->flags = MEM_Static; - }else if( xDel==SQLITE_TRANSIENT ){ - pMem->flags = MEM_Ephem; + + flags = (enc==0?MEM_Blob:MEM_Str); + if( nByte<0 ){ + assert( enc!=0 ); + nByte = ((enc==SQLITE_UTF8)?strlen(z):sqlite3Utf16ByteLen(z, -1)); + flags |= MEM_Term; + } + + /* The following block sets the new values of Mem.z and Mem.xDel. It + ** also sets a flag in local variable "flags" to indicate the memory + ** management (one of MEM_Dyn or MEM_Static). + */ + if( xDel==SQLITE_TRANSIENT ){ + int nAlloc = nByte; + if( flags&MEM_Term ){ + nAlloc += (enc==SQLITE_UTF8?1:2); + } + if( sqlite3VdbeMemGrow(pMem, nAlloc, 0) ){ + return SQLITE_NOMEM; + } + memcpy(pMem->z, z, nAlloc); + flags |= MEM_Dyn; }else{ - pMem->flags = MEM_Dyn; + sqlite3VdbeMemRelease(pMem); + pMem->z = (char *)z; pMem->xDel = xDel; - } - - pMem->enc = enc; - pMem->type = enc==0 ? SQLITE_BLOB : SQLITE_TEXT; - pMem->n = n; - - assert( enc==0 || enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE - || enc==SQLITE_UTF16BE ); - switch( enc ){ - case 0: - pMem->flags |= MEM_Blob; - pMem->enc = SQLITE_UTF8; - break; - - case SQLITE_UTF8: - pMem->flags |= MEM_Str; - if( n<0 ){ - pMem->n = strlen(z); - pMem->flags |= MEM_Term; - } - break; + flags |= ((xDel==SQLITE_STATIC)?MEM_Static:MEM_Dyn); + } + + pMem->n = nByte; + pMem->flags = flags; + pMem->enc = (enc==0 ? SQLITE_UTF8 : enc); + pMem->type = (enc==0 ? SQLITE_BLOB : SQLITE_TEXT); #ifndef SQLITE_OMIT_UTF16 - case SQLITE_UTF16LE: - case SQLITE_UTF16BE: - pMem->flags |= MEM_Str; - if( pMem->n<0 ){ - pMem->n = sqlite3Utf16ByteLen(pMem->z,-1); - pMem->flags |= MEM_Term; - } - if( sqlite3VdbeMemHandleBom(pMem) ){ - return SQLITE_NOMEM; - } -#endif /* SQLITE_OMIT_UTF16 */ - } - if( pMem->flags&MEM_Ephem ){ - return sqlite3VdbeMemMakeWriteable(pMem); - } + if( pMem->enc!=SQLITE_UTF8 && sqlite3VdbeMemHandleBom(pMem) ){ + return SQLITE_NOMEM; + } +#endif + return SQLITE_OK; } /* ** Compare the values contained by the two memory cells, returning @@ -767,10 +806,11 @@ Mem *pMem /* OUT: Return data in this Mem structure. */ ){ char *zData; /* Data from the btree layer */ int available = 0; /* Number of bytes available on the local btree page */ sqlite3 *db; /* Database connection */ + int rc = SQLITE_OK; db = sqlite3BtreeCursorDb(pCur); assert( sqlite3_mutex_held(db->mutex) ); if( key ){ zData = (char *)sqlite3BtreeKeyFetch(pCur, &available); @@ -777,53 +817,32 @@ }else{ zData = (char *)sqlite3BtreeDataFetch(pCur, &available); } assert( zData!=0 ); - pMem->db = db; - pMem->n = amt; - if( offset+amt<=available ){ + if( offset+amt<=available && ((pMem->flags&MEM_Dyn)==0 || pMem->xDel) ){ + sqlite3VdbeMemRelease(pMem); pMem->z = &zData[offset]; pMem->flags = MEM_Blob|MEM_Ephem; - }else{ - int rc; - if( amt>NBFS-2 ){ - zData = (char *)sqlite3DbMallocRaw(db, amt+2); - if( !zData ){ - return SQLITE_NOMEM; - } - pMem->flags = MEM_Blob|MEM_Dyn|MEM_Term; - pMem->xDel = 0; - }else{ - zData = &(pMem->zShort[0]); - pMem->flags = MEM_Blob|MEM_Short|MEM_Term; - } - pMem->z = zData; + }else if( SQLITE_OK==(rc = sqlite3VdbeMemGrow(pMem, amt+2, 0)) ){ + pMem->flags = MEM_Blob|MEM_Dyn|MEM_Term; pMem->enc = 0; pMem->type = SQLITE_BLOB; - - if( key ){ - rc = sqlite3BtreeKey(pCur, offset, amt, zData); - }else{ - rc = sqlite3BtreeData(pCur, offset, amt, zData); - } - zData[amt] = 0; - zData[amt+1] = 0; - if( rc!=SQLITE_OK ){ - if( amt>NBFS-2 ){ - assert( zData!=pMem->zShort ); - assert( pMem->flags & MEM_Dyn ); - sqlite3_free(zData); - } else { - assert( zData==pMem->zShort ); - assert( pMem->flags & MEM_Short ); - } - return rc; - } - } - - return SQLITE_OK; + if( key ){ + rc = sqlite3BtreeKey(pCur, offset, amt, pMem->z); + }else{ + rc = sqlite3BtreeData(pCur, offset, amt, pMem->z); + } + pMem->z[amt] = 0; + pMem->z[amt+1] = 0; + if( rc!=SQLITE_OK ){ + sqlite3VdbeMemRelease(pMem); + } + } + pMem->n = amt; + + return rc; } #if 0 /* ** Perform various checks on the memory cell pMem. An assert() will @@ -1017,11 +1036,11 @@ /* ** Free an sqlite3_value object */ void sqlite3ValueFree(sqlite3_value *v){ if( !v ) return; - sqlite3ValueSetStr(v, 0, 0, SQLITE_UTF8, SQLITE_STATIC); + sqlite3VdbeMemRelease((Mem *)v); sqlite3_free(v); } /* ** Return the number of bytes in the sqlite3_value object assuming Index: test/mallocB.test ================================================================== --- test/mallocB.test +++ test/mallocB.test @@ -11,11 +11,11 @@ # This file contains additional out-of-memory checks (see malloc.tcl). # These were all discovered by fuzzy generation of SQL. Apart from # that they have little in common. # # -# $Id: mallocB.test,v 1.7 2008/01/17 20:26:47 drh Exp $ +# $Id: mallocB.test,v 1.8 2008/02/13 18:25:27 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl @@ -29,11 +29,11 @@ source $testdir/malloc_common.tcl do_malloc_test mallocB-1 -sqlbody {SELECT - 456} do_malloc_test mallocB-2 -sqlbody {SELECT - 456.1} do_malloc_test mallocB-3 -sqlbody {SELECT random()} -do_malloc_test mallocB-4 -sqlbody {SELECT zeroblob(1000)} +do_malloc_test mallocB-4 -sqlbody {SELECT length(zeroblob(1000))} ifcapable subquery { do_malloc_test mallocB-5 -sqlbody {SELECT * FROM (SELECT 1) GROUP BY 1;} } # The following test checks that there are no resource leaks following a Index: test/ptrchng.test ================================================================== --- test/ptrchng.test +++ test/ptrchng.test @@ -19,11 +19,11 @@ # sqlite3_value_text16() # sqlite3_value_blob() # sqlite3_value_bytes() # sqlite3_value_bytes16() # -# $Id: ptrchng.test,v 1.2 2007/09/12 17:01:45 danielk1977 Exp $ +# $Id: ptrchng.test,v 1.3 2008/02/13 18:25:27 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !bloblit { @@ -50,41 +50,43 @@ } {4} # For the short entries that fit in the Mem.zBuf[], the pointer should # never change regardless of what type conversions occur. # +# UPDATE: No longer true, as Mem.zBuf[] has been removed. +# do_test ptrchng-2.1 { execsql { SELECT pointer_change(y, 'text', 'noop', 'blob') FROM t1 WHERE x=1 } } {0} do_test ptrchng-2.2 { execsql { SELECT pointer_change(y, 'blob', 'noop', 'text') FROM t1 WHERE x=1 } -} {0} +} {1} ifcapable utf16 { do_test ptrchng-2.3 { execsql { SELECT pointer_change(y, 'text', 'noop', 'text16') FROM t1 WHERE x=1 } - } {0} + } {1} do_test ptrchng-2.4 { execsql { SELECT pointer_change(y, 'blob', 'noop', 'text16') FROM t1 WHERE x=1 } - } {0} + } {1} do_test ptrchng-2.5 { execsql { SELECT pointer_change(y, 'text16', 'noop', 'blob') FROM t1 WHERE x=1 } } {0} do_test ptrchng-2.6 { execsql { SELECT pointer_change(y, 'text16', 'noop', 'text') FROM t1 WHERE x=1 } - } {0} + } {1} } do_test ptrchng-2.11 { execsql { SELECT pointer_change(y, 'text', 'noop', 'blob') FROM t1 WHERE x=3 } @@ -91,22 +93,22 @@ } {0} do_test ptrchng-2.12 { execsql { SELECT pointer_change(y, 'blob', 'noop', 'text') FROM t1 WHERE x=3 } -} {0} +} {1} ifcapable utf16 { do_test ptrchng-2.13 { execsql { SELECT pointer_change(y, 'text', 'noop', 'text16') FROM t1 WHERE x=3 } - } {0} + } {1} do_test ptrchng-2.14 { execsql { SELECT pointer_change(y, 'blob', 'noop', 'text16') FROM t1 WHERE x=3 } - } {0} + } {1} do_test ptrchng-2.15 { execsql { SELECT pointer_change(y, 'text16', 'noop', 'blob') FROM t1 WHERE x=3 } } {0} @@ -113,11 +115,11 @@ do_test ptrchng-2.16 { btree_breakpoint execsql { SELECT pointer_change(y, 'text16', 'noop', 'text') FROM t1 WHERE x=3 } - } {0} + } {1} } # For the long entries that do not fit in the Mem.zBuf[], the pointer # should change sometimes. # @@ -128,11 +130,11 @@ } {0} do_test ptrchng-3.2 { execsql { SELECT pointer_change(y, 'blob', 'noop', 'text') FROM t1 WHERE x=2 } -} {0} +} {1} ifcapable utf16 { do_test ptrchng-3.3 { execsql { SELECT pointer_change(y, 'text', 'noop', 'text16') FROM t1 WHERE x=2 } @@ -160,11 +162,11 @@ } {0} do_test ptrchng-3.12 { execsql { SELECT pointer_change(y, 'blob', 'noop', 'text') FROM t1 WHERE x=4 } -} {0} +} {1} ifcapable utf16 { do_test ptrchng-3.13 { execsql { SELECT pointer_change(y, 'text', 'noop', 'text16') FROM t1 WHERE x=4 } Index: test/tester.tcl ================================================================== --- test/tester.tcl +++ test/tester.tcl @@ -9,11 +9,11 @@ # #*********************************************************************** # This file implements some common TCL routines used for regression # testing the SQLite library # -# $Id: tester.tcl,v 1.103 2008/02/08 18:25:30 danielk1977 Exp $ +# $Id: tester.tcl,v 1.104 2008/02/13 18:25:27 danielk1977 Exp $ set tcl_precision 15 set sqlite_pending_byte 0x0010000 @@ -225,10 +225,13 @@ sqlite3_memdebug_dump ./memusage.txt } } puts "Maximum memory usage: [sqlite3_memory_highwater 1] bytes" puts "Current memory usage: [sqlite3_memory_highwater] bytes" + if {[info commands sqlite3_memdebug_malloc_count] ne ""} { + puts "Number of malloc() : [sqlite3_memdebug_malloc_count] calls" + } foreach f [glob -nocomplain test.db-*-journal] { file delete -force $f } foreach f [glob -nocomplain test.db-mj*] { file delete -force $f