diff --git a/manifest b/manifest index cabd8f7348..9de3ea99eb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enable\sprefix-search\sin\squery-parsing\sand\ssnippet\sgeneration.\s\sIf\sthe\ncharacter\simmediately\safter\sthe\send\sof\sa\sterm\sis\s'*',\sthat\sterm\sis\nmarked\sfor\sprefix\smatching.\s\sModify\sterm\scomparison\sin\nsnippetOffsetsOfColumn()\sto\srespect\sisPrefix.\s\sfts2n.test\sruns\sprefix\nsearching\sthrough\ssome\sobvious\stest\scases.\s(CVS\s3893) -D 2007-05-01T18:25:53 +C Begin\sadding\sthe\szeroblob\sAPI\sto\ssupport\sincremental\sblob\si/o.\s(CVS\s3894) +D 2007-05-02T01:34:31 F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -59,8 +59,8 @@ F src/alter.c 2c79ec40f65e33deaf90ca493422c74586e481a3 F src/analyze.c 4bbf5ddf9680587c6d4917e02e378b6037be3651 F src/attach.c a16ada4a4654a0d126b8223ec9494ebb81bc5c3c F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f -F src/btree.c 80814622b3e3d6b71e53a9286e1a8a2ea486da11 -F src/btree.h 9a219f01b732c8be4b3ccd8143881204da63e80f +F src/btree.c 4e0735d1826a8cefb5ee25aa9615d43860881f10 +F src/btree.h b2ef1ccc337fd37c58c8c17189a237aea341fb48 F src/build.c 02e01ec7907c7d947ab3041fda0e81eaed05db42 F src/callback.c 6414ed32d55859d0f65067aa5b88d2da27b3af9e F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675 @@ -97,14 +97,14 @@ F src/random.c 6119474a6f6917f708c1dee25b9a8e519a620e88 F src/select.c b914abca0ba28893e7fb7c7fb97a05e240e2ce8b F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c 3ae4654560e91220a95738a73d135d91d937cda1 -F src/sqlite.h.in 2dd7d439a1b991043388c7c37eb7db957d7276ff +F src/sqlite.h.in 1e053c58fd4df28c38ffdca2443b16d5f76f6f1e F src/sqlite3ext.h 7d0d363ea7327e817ef0dfe1b7eee1f171b72890 F src/sqliteInt.h 0b14d0eae083aafca0562d2261a404e5e5abc5f0 F src/table.c 6d0da66dde26ee75614ed8f584a1996467088d06 F src/tclsqlite.c 82f7be1e8015ef224e2a9410a8f98dd6f61d64e9 -F src/test1.c f1271d41719d05348e6dc39722260e17b8d7ddc1 +F src/test1.c bf70db366aa28b813810f63fc48fec424034502d F src/test2.c 24458b17ab2f3c90cbc1c8446bd7ffe69be62f88 -F src/test3.c 65f92247cf8592854e9bf5115b3fb711f8b33280 +F src/test3.c 946ea9d1a8c928656e3c70f0a2fcb8e733a15e86 F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25 F src/test5.c 7162f8526affb771c4ed256826eee7bb9eca265f F src/test6.c 5957d249d437e4db74045ce2f1f661648d94bf94 @@ -125,14 +125,14 @@ F src/update.c 3359041db390a8f856d67272f299600e2104f350 F src/utf.c e64a48bc21aa973eb622dd47da87d56a4cdcf528 F src/util.c b6344325378e75b9e18175d8b6aed1723d73dad9 F src/vacuum.c 8bd895d29e7074e78d4e80f948e35ddc9cf2beef -F src/vdbe.c a3cf3792fdbd382f756eb7eb50006b2f3f8d4283 +F src/vdbe.c 8cc851ca1d6d849586eb0c5359c492685c285c97 F src/vdbe.h 0025259af1939fb264a545816c69e4b5b8d52691 -F src/vdbeInt.h 4b19fd8febad3fd14c4c97adaefc06754d323132 -F src/vdbeapi.c 37fc2818bec64b361af73f3935699107bab0e625 +F src/vdbeInt.h 016c808478bce04e071c38fa506e05763e8a54b9 +F src/vdbeapi.c 37d793559390bec8a00c556f651f21b5f9e589af F src/vdbeaux.c ef59545f53f90394283f2fd003375d3ebbf0bd6e F src/vdbeblob.c 6d3128c71d5a6b8db627ea3052ed5aaaaf26e672 F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f -F src/vdbemem.c 981a113405bd9b80aeb71fe246a2f01708e8a8f7 +F src/vdbemem.c 02ffe06f967a23a66b72e48a1773153b417fad04 F src/vtab.c 89a0d5f39c1beba65a77fdb4d507b831fc5e6baf F src/where.c 0f17b7bed2ce50ba450e8f436d5ec8b420c4ab3f F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42 @@ -170,6 +170,7 @@ F test/btree5.test 8e5ff32c02e685d36516c6499add9375fe1377f2 F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027 F test/btree7.test a6d3b842db22af97dd14b989e90a2fd96066b72f F test/btree8.test fadc112bcbd6a0c622d34c813fc8a648eacf8804 +F test/btree9.test 5d8711b241145b90f65dd1795d5dd8290846fa5e F test/busy.test 0271c854738e23ad76e10d4096a698e5af29d211 F test/cache.test 9e530b55ba016ca17439f728a06898f0ade5f1da F test/capi2.test 7ecc9b342cc9ec27b53bbf95724cf2e5874fd496 @@ -469,7 +470,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P c444836e7b690c16dd6acff571c613a23beb42dc -R 15961852c9b829c1a838faae38aeed43 -U shess -Z c808046b1e2602c778234ecda5713f7c +P 7c4c65924035d9f260f6b64eb92c5c6cf6c04b7b +R ab7ef76e7fb4aa900cb531034d51122a +U drh +Z 29f62b2ce72d241a227558f749482713 diff --git a/manifest.uuid b/manifest.uuid index 657800ab3f..d51270c01f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7c4c65924035d9f260f6b64eb92c5c6cf6c04b7b \ No newline at end of file +7a01836dde45098796693bc6cb6045c4059adf1a \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index b253395d97..2ad7358055 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.363 2007/05/01 17:49:49 danielk1977 Exp $ +** $Id: btree.c,v 1.364 2007/05/02 01:34:31 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -4151,6 +4151,7 @@ static int fillInCell( unsigned char *pCell, /* Complete text of the cell */ const void *pKey, i64 nKey, /* The key */ const void *pData,int nData, /* The data */ + int nZero, /* Extra zero bytes to append to pData */ int *pnSize /* Write cell size here */ ){ int nPayload; @@ -4172,18 +4173,18 @@ static int fillInCell( nHeader += 4; } if( pPage->hasData ){ - nHeader += putVarint(&pCell[nHeader], nData); + nHeader += putVarint(&pCell[nHeader], nData+nZero); }else{ - nData = 0; + nData = nZero = 0; } nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey); parseCellPtr(pPage, pCell, &info); assert( info.nHeader==nHeader ); assert( info.nKey==nKey ); - assert( info.nData==nData ); + assert( info.nData==nData+nZero ); /* Fill in the payload */ - nPayload = nData; + nPayload = nData + nZero; if( pPage->intKey ){ pSrc = pData; nSrc = nData; @@ -4228,9 +4229,13 @@ static int fillInCell( } n = nPayload; if( n>spaceLeft ) n = spaceLeft; - if( n>nSrc ) n = nSrc; - assert( pSrc ); - memcpy(pPayload, pSrc, n); + if( nSrc>0 ){ + if( n>nSrc ) n = nSrc; + assert( pSrc ); + memcpy(pPayload, pSrc, n); + }else{ + memset(pPayload, 0, n); + } nPayload -= n; pPayload += n; pSrc += n; @@ -4555,7 +4560,7 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){ */ assert( pPage->nCell>0 ); parseCellPtr(pPage, findCell(pPage, pPage->nCell-1), &info); - rc = fillInCell(pParent, parentCell, 0, info.nKey, 0, 0, &parentSize); + rc = fillInCell(pParent, parentCell, 0, info.nKey, 0, 0, 0, &parentSize); if( rc!=SQLITE_OK ){ return rc; } @@ -5101,7 +5106,7 @@ static int balance_nonroot(MemPage *pPage){ j--; parseCellPtr(pNew, apCell[j], &info); pCell = &aSpace[iSpace]; - fillInCell(pParent, pCell, 0, info.nKey, 0, 0, &sz); + fillInCell(pParent, pCell, 0, info.nKey, 0, 0, 0, &sz); iSpace += sz; assert( iSpace<=pBt->pageSize*5 ); pTemp = 0; @@ -5415,6 +5420,7 @@ int sqlite3BtreeInsert( BtCursor *pCur, /* Insert data into the table of this cursor */ const void *pKey, i64 nKey, /* The key of the new record */ const void *pData, int nData, /* The data of the new record */ + int nZero, /* Number of extra 0 bytes to append to data */ int appendBias /* True if this is likely an append */ ){ int rc; @@ -5457,7 +5463,7 @@ int sqlite3BtreeInsert( if( rc ) return rc; newCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) ); if( newCell==0 ) return SQLITE_NOMEM; - rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, &szNew); + rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, nZero, &szNew); if( rc ) goto end_insert; assert( szNew==cellSizePtr(pPage, newCell) ); assert( szNew<=MX_CELL_SIZE(pBt) ); @@ -6857,7 +6863,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, const void *z){ } if( nCopy>0 ){ memcpy(&zData[offset], z, amt); - rc = sqlite3BtreeInsert(pCsr, 0, iKey, zData, nData, 0); + rc = sqlite3BtreeInsert(pCsr, 0, iKey, zData, nData, 0, 0); } sqliteFree(zData); diff --git a/src/btree.h b/src/btree.h index 40a885f51b..b3cd585644 100644 --- a/src/btree.h +++ b/src/btree.h @@ -13,7 +13,7 @@ ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** -** @(#) $Id: btree.h,v 1.76 2007/05/01 17:49:49 danielk1977 Exp $ +** @(#) $Id: btree.h,v 1.77 2007/05/02 01:34:31 drh Exp $ */ #ifndef _BTREE_H_ #define _BTREE_H_ @@ -124,7 +124,8 @@ int sqlite3BtreeCloseCursor(BtCursor*); int sqlite3BtreeMoveto(BtCursor*,const void *pKey,i64 nKey,int bias,int *pRes); int sqlite3BtreeDelete(BtCursor*); int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey, - const void *pData, int nData, int bias); + const void *pData, int nData, + int nZero, int bias); int sqlite3BtreeFirst(BtCursor*, int *pRes); int sqlite3BtreeLast(BtCursor*, int *pRes); int sqlite3BtreeNext(BtCursor*, int *pRes); diff --git a/src/sqlite.h.in b/src/sqlite.h.in index c229a10434..17a0a14d5b 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -12,7 +12,7 @@ ** This header file defines the interface that the SQLite library ** presents to client programs. ** -** @(#) $Id: sqlite.h.in,v 1.202 2007/05/01 17:49:49 danielk1977 Exp $ +** @(#) $Id: sqlite.h.in,v 1.203 2007/05/02 01:34:31 drh Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ @@ -790,6 +790,7 @@ int sqlite3_bind_null(sqlite3_stmt*, int); int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*)); int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); +int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); /* ** Return the number of host parameters in a compiled SQL statement. This @@ -1222,6 +1223,7 @@ void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); void sqlite3_result_value(sqlite3_context*, sqlite3_value*); +void sqlite3_result_zeroblob(sqlite3_context*, int n); /* ** These are the allowed values for the eTextRep argument to diff --git a/src/test1.c b/src/test1.c index 1d765b1efc..409f4c2124 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.240 2007/04/27 17:16:20 drh Exp $ +** $Id: test1.c,v 1.241 2007/05/02 01:34:31 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" @@ -2257,6 +2257,43 @@ static int test_breakpoint( return TCL_OK; /* Do nothing */ } +/* +** Usage: sqlite3_bind_zeroblob STMT IDX N +** +** Test the sqlite3_bind_zeroblob interface. STMT is a prepared statement. +** IDX is the index of a wildcard in the prepared statement. This command +** binds a N-byte zero-filled BLOB to the wildcard. +*/ +static int test_bind_zeroblob( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + sqlite3_stmt *pStmt; + int idx; + int n; + int rc; + + if( objc!=4 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", + Tcl_GetStringFromObj(objv[0], 0), " STMT N VALUE", 0); + return TCL_ERROR; + } + + if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; + if( Tcl_GetIntFromObj(interp, objv[2], &idx) ) return TCL_ERROR; + if( Tcl_GetIntFromObj(interp, objv[3], &n) ) return TCL_ERROR; + + rc = sqlite3_bind_zeroblob(pStmt, idx, n); + if( sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ) return TCL_ERROR; + if( rc!=SQLITE_OK ){ + return TCL_ERROR; + } + + return TCL_OK; +} + /* ** Usage: sqlite3_bind_int STMT N VALUE ** @@ -4361,6 +4398,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ } aObjCmd[] = { { "sqlite3_connection_pointer", get_sqlite_pointer, 0 }, { "sqlite3_bind_int", test_bind_int, 0 }, + { "sqlite3_bind_zeroblob", test_bind_zeroblob, 0 }, { "sqlite3_bind_int64", test_bind_int64, 0 }, { "sqlite3_bind_double", test_bind_double, 0 }, { "sqlite3_bind_null", test_bind_null ,0 }, diff --git a/src/test3.c b/src/test3.c index fba3fa2eca..4fb878fb57 100644 --- a/src/test3.c +++ b/src/test3.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test3.c,v 1.73 2007/03/29 05:51:49 drh Exp $ +** $Id: test3.c,v 1.74 2007/05/02 01:34:32 drh Exp $ */ #include "sqliteInt.h" #include "pager.h" @@ -750,7 +750,7 @@ static int btree_delete( } /* -** Usage: btree_insert ID KEY DATA +** Usage: btree_insert ID KEY DATA ?NZERO? ** ** Create a new entry with the given key and data. If an entry already ** exists with the same key the old entry is overwritten. @@ -763,19 +763,25 @@ static int btree_insert( ){ BtCursor *pCur; int rc; + int nZero; - if( objc!=4 ){ - Tcl_WrongNumArgs(interp, 1, objv, "ID KEY DATA"); + if( objc!=4 && objc!=5 ){ + Tcl_WrongNumArgs(interp, 1, objv, "ID KEY DATA ?NZERO?"); return TCL_ERROR; } pCur = sqlite3TextToPtr(Tcl_GetString(objv[1])); + if( objc==5 ){ + if( Tcl_GetIntFromObj(interp, objv[4], &nZero) ) return TCL_ERROR; + }else{ + nZero = 0; + } if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ i64 iKey; int len; unsigned char *pBuf; if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ) return TCL_ERROR; pBuf = Tcl_GetByteArrayFromObj(objv[3], &len); - rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len, 0); + rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len, nZero, 0); }else{ int keylen; int dlen; @@ -783,7 +789,7 @@ static int btree_insert( unsigned char *pDBuf; pKBuf = Tcl_GetByteArrayFromObj(objv[2], &keylen); pDBuf = Tcl_GetByteArrayFromObj(objv[3], &dlen); - rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen, 0); + rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen, nZero, 0); } if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); diff --git a/src/vdbe.c b/src/vdbe.c index eeb0847fd3..4207cf3e3f 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.602 2007/04/26 14:42:36 danielk1977 Exp $ +** $Id: vdbe.c,v 1.603 2007/05/02 01:34:32 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -3372,8 +3372,14 @@ case OP_Insert: { /* no-push */ } pC->nullRow = 0; }else{ + int nZero; + if( pTos->flags & MEM_Zero ){ + nZero = pTos->u.i; + }else{ + nZero = 0; + } rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey, - pTos->z, pTos->n, + pTos->z, pTos->n, nZero, pOp->p2 & OPFLAG_APPEND); } @@ -3752,7 +3758,7 @@ case OP_IdxInsert: { /* no-push */ int nKey = pTos->n; const char *zKey = pTos->z; assert( pC->isTable==0 ); - rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0, pOp->p2); + rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0, 0, pOp->p2); assert( pC->deferredMoveto==0 ); pC->cacheStatus = CACHE_STALE; } diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 11c906100c..88ea6c72d0 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -172,6 +172,7 @@ typedef struct Mem Mem; #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 */ /* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains @@ -385,6 +386,7 @@ int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*)); void sqlite3VdbeMemSetInt64(Mem*, i64); void sqlite3VdbeMemSetDouble(Mem*, double); void sqlite3VdbeMemSetNull(Mem*); +void sqlite3VdbeMemSetZeroBlob(Mem*,int); int sqlite3VdbeMemMakeWriteable(Mem*); int sqlite3VdbeMemDynamicify(Mem*); int sqlite3VdbeMemStringify(Mem*, int); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index bd6d1d4102..4e121059f8 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -37,6 +37,7 @@ int sqlite3_expired(sqlite3_stmt *pStmt){ const void *sqlite3_value_blob(sqlite3_value *pVal){ Mem *p = (Mem*)pVal; if( p->flags & (MEM_Blob|MEM_Str) ){ + sqlite3VdbeMemExpandBlob(p); if( (p->flags & MEM_Term)==0 ){ p->flags &= ~MEM_Str; } @@ -151,6 +152,9 @@ void sqlite3_result_text16le( void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){ sqlite3VdbeMemCopy(&pCtx->s, pValue); } +void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){ + sqlite3VdbeMemSetZeroBlob(&pCtx->s, n); +} /* @@ -790,6 +794,15 @@ int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){ } return rc; } +int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){ + int rc; + Vdbe *p = (Vdbe *)pStmt; + rc = vdbeUnbind(p, i); + if( rc==SQLITE_OK ){ + sqlite3VdbeMemSetZeroBlob(&p->aVar[i-1], n); + } + return rc; +} /* ** Return the number of wildcards that can be potentially bound to. diff --git a/src/vdbemem.c b/src/vdbemem.c index 5aed1df3db..52b4a5feb2 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -60,12 +60,14 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. */ int sqlite3VdbeMemDynamicify(Mem *pMem){ - int n = pMem->n; + int n; u8 *z; + sqlite3VdbeMemExpandBlob(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 = sqliteMallocRaw( n+2 ); if( z==0 ){ @@ -81,6 +83,30 @@ int sqlite3VdbeMemDynamicify(Mem *pMem){ return SQLITE_OK; } +/* +** If the given Mem* is a zero-filled blob, turn it into an ordinary +** blob stored in dynamically allocated space. +*/ +int sqlite3VdbeMemExpandBlob(Mem *pMem){ + if( pMem->flags & MEM_Zero ){ + char *pNew; + assert( (pMem->flags & MEM_Blob)!=0 ); + pNew = sqliteMalloc(pMem->n+pMem->u.i+1); + if( pNew==0 ){ + return SQLITE_NOMEM; + } + memcpy(pNew, pMem->z, pMem->n); + memset(&pNew[pMem->n], 0, pMem->u.i+1); + sqlite3VdbeMemRelease(pMem); + pMem->z = pNew; + pMem->u.i = 0; + pMem->flags &= MEM_Zero|MEM_Static|MEM_Ephem|MEM_Short; + pMem->flags |= MEM_Term|MEM_Dyn; + } + return SQLITE_OK; +} + + /* ** Make the given Mem object either MEM_Short or MEM_Dyn so that bytes ** of the Mem.z[] array can be modified. @@ -90,6 +116,7 @@ int sqlite3VdbeMemDynamicify(Mem *pMem){ int sqlite3VdbeMemMakeWriteable(Mem *pMem){ int n; u8 *z; + sqlite3VdbeMemExpandBlob(pMem); if( (pMem->flags & (MEM_Ephem|MEM_Static))==0 ){ return SQLITE_OK; } @@ -347,6 +374,18 @@ void sqlite3VdbeMemSetNull(Mem *pMem){ 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; + pMem->type = SQLITE_BLOB; + pMem->n = 0; + pMem->u.i = n; +} + /* ** Delete any previous value and set the value stored in *pMem to val, ** manifest type INTEGER. @@ -699,14 +738,14 @@ int sqlite3VdbeMemFromBtree( void sqlite3VdbeMemSanity(Mem *pMem){ int flags = pMem->flags; assert( flags!=0 ); /* Must define some type */ - if( pMem->flags & (MEM_Str|MEM_Blob) ){ - int x = pMem->flags & (MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short); + if( flags & (MEM_Str|MEM_Blob) ){ + int x = flags & (MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short); assert( x!=0 ); /* Strings must define a string subtype */ assert( (x & (x-1))==0 ); /* Only one string subtype can be defined */ - assert( pMem->z!=0 ); /* Strings must have a value */ + assert( pMem->z!=0 || x==MEM_Zero ); /* Strings must have a value */ /* Mem.z points to Mem.zShort iff the subtype is MEM_Short */ - assert( (pMem->flags & MEM_Short)==0 || pMem->z==pMem->zShort ); - assert( (pMem->flags & MEM_Short)!=0 || pMem->z!=pMem->zShort ); + assert( (x & MEM_Short)==0 || pMem->z==pMem->zShort ); + assert( (x & MEM_Short)!=0 || pMem->z!=pMem->zShort ); /* No destructor unless there is MEM_Dyn */ assert( pMem->xDel==0 || (pMem->flags & MEM_Dyn)!=0 ); @@ -759,6 +798,7 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){ } assert( (MEM_Blob>>3) == MEM_Str ); pVal->flags |= (pVal->flags & MEM_Blob)>>3; + sqlite3VdbeMemExpandBlob(pVal); if( pVal->flags&MEM_Str ){ sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED); if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&(int)pVal->z) ){ @@ -888,7 +928,11 @@ void sqlite3ValueFree(sqlite3_value *v){ int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){ Mem *p = (Mem*)pVal; if( (p->flags & MEM_Blob)!=0 || sqlite3ValueText(pVal, enc) ){ - return p->n; + if( p->flags & MEM_Zero ){ + return p->n+p->u.i; + }else{ + return p->n; + } } return 0; } diff --git a/test/btree9.test b/test/btree9.test new file mode 100644 index 0000000000..678a12c91f --- /dev/null +++ b/test/btree9.test @@ -0,0 +1,49 @@ +# 2007 May 01 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this script is btree database backend. +# +# $Id: btree9.test,v 1.1 2007/05/02 01:34:32 drh Exp $ + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +# The sqlite3BtreeInsert() API now has an additional "nZero" parameter +# which specifies the number of zero bytes to append to the end of the +# data. This feature allows large zero-filled BLOBs to be created without +# having to allocate a big chunk of memory to instantiate the blob. +# +# The following code tests the new feature. +# + +# Create the database +# +do_test btree9-1.1 { + file delete -force test1.bt + file delete -force test1.bt-journal + set b1 [btree_open test1.bt 2000 0] + btree_begin_transaction $b1 + set t1 [btree_create_table $b1 5] + set c1 [btree_cursor $b1 $t1 1] + btree_insert $c1 1 data-for-1 20000 + btree_move_to $c1 1 + btree_key $c1 +} {1} +do_test btree9-1.2 { + btree_payload_size $c1 +} {20010} + + +btree_close_cursor $c1 +btree_commit $b1 +btree_close $b1 + +finish_test