1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Begin adding the zeroblob API to support incremental blob i/o. (CVS 3894)

FossilOrigin-Name: 7a01836dde45098796693bc6cb6045c4059adf1a
This commit is contained in:
drh
2007-05-02 01:34:31 +00:00
parent 290283fe69
commit b026e05eb2
12 changed files with 216 additions and 48 deletions

View File

@@ -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) C Begin\sadding\sthe\szeroblob\sAPI\sto\ssupport\sincremental\sblob\si/o.\s(CVS\s3894)
D 2007-05-01T18:25:53 D 2007-05-02T01:34:31
F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62 F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -59,8 +59,8 @@ F src/alter.c 2c79ec40f65e33deaf90ca493422c74586e481a3
F src/analyze.c 4bbf5ddf9680587c6d4917e02e378b6037be3651 F src/analyze.c 4bbf5ddf9680587c6d4917e02e378b6037be3651
F src/attach.c a16ada4a4654a0d126b8223ec9494ebb81bc5c3c F src/attach.c a16ada4a4654a0d126b8223ec9494ebb81bc5c3c
F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f
F src/btree.c 80814622b3e3d6b71e53a9286e1a8a2ea486da11 F src/btree.c 4e0735d1826a8cefb5ee25aa9615d43860881f10
F src/btree.h 9a219f01b732c8be4b3ccd8143881204da63e80f F src/btree.h b2ef1ccc337fd37c58c8c17189a237aea341fb48
F src/build.c 02e01ec7907c7d947ab3041fda0e81eaed05db42 F src/build.c 02e01ec7907c7d947ab3041fda0e81eaed05db42
F src/callback.c 6414ed32d55859d0f65067aa5b88d2da27b3af9e F src/callback.c 6414ed32d55859d0f65067aa5b88d2da27b3af9e
F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675 F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675
@@ -97,14 +97,14 @@ F src/random.c 6119474a6f6917f708c1dee25b9a8e519a620e88
F src/select.c b914abca0ba28893e7fb7c7fb97a05e240e2ce8b F src/select.c b914abca0ba28893e7fb7c7fb97a05e240e2ce8b
F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
F src/shell.c 3ae4654560e91220a95738a73d135d91d937cda1 F src/shell.c 3ae4654560e91220a95738a73d135d91d937cda1
F src/sqlite.h.in 2dd7d439a1b991043388c7c37eb7db957d7276ff F src/sqlite.h.in 1e053c58fd4df28c38ffdca2443b16d5f76f6f1e
F src/sqlite3ext.h 7d0d363ea7327e817ef0dfe1b7eee1f171b72890 F src/sqlite3ext.h 7d0d363ea7327e817ef0dfe1b7eee1f171b72890
F src/sqliteInt.h 0b14d0eae083aafca0562d2261a404e5e5abc5f0 F src/sqliteInt.h 0b14d0eae083aafca0562d2261a404e5e5abc5f0
F src/table.c 6d0da66dde26ee75614ed8f584a1996467088d06 F src/table.c 6d0da66dde26ee75614ed8f584a1996467088d06
F src/tclsqlite.c 82f7be1e8015ef224e2a9410a8f98dd6f61d64e9 F src/tclsqlite.c 82f7be1e8015ef224e2a9410a8f98dd6f61d64e9
F src/test1.c f1271d41719d05348e6dc39722260e17b8d7ddc1 F src/test1.c bf70db366aa28b813810f63fc48fec424034502d
F src/test2.c 24458b17ab2f3c90cbc1c8446bd7ffe69be62f88 F src/test2.c 24458b17ab2f3c90cbc1c8446bd7ffe69be62f88
F src/test3.c 65f92247cf8592854e9bf5115b3fb711f8b33280 F src/test3.c 946ea9d1a8c928656e3c70f0a2fcb8e733a15e86
F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25 F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25
F src/test5.c 7162f8526affb771c4ed256826eee7bb9eca265f F src/test5.c 7162f8526affb771c4ed256826eee7bb9eca265f
F src/test6.c 5957d249d437e4db74045ce2f1f661648d94bf94 F src/test6.c 5957d249d437e4db74045ce2f1f661648d94bf94
@@ -125,14 +125,14 @@ F src/update.c 3359041db390a8f856d67272f299600e2104f350
F src/utf.c e64a48bc21aa973eb622dd47da87d56a4cdcf528 F src/utf.c e64a48bc21aa973eb622dd47da87d56a4cdcf528
F src/util.c b6344325378e75b9e18175d8b6aed1723d73dad9 F src/util.c b6344325378e75b9e18175d8b6aed1723d73dad9
F src/vacuum.c 8bd895d29e7074e78d4e80f948e35ddc9cf2beef F src/vacuum.c 8bd895d29e7074e78d4e80f948e35ddc9cf2beef
F src/vdbe.c a3cf3792fdbd382f756eb7eb50006b2f3f8d4283 F src/vdbe.c 8cc851ca1d6d849586eb0c5359c492685c285c97
F src/vdbe.h 0025259af1939fb264a545816c69e4b5b8d52691 F src/vdbe.h 0025259af1939fb264a545816c69e4b5b8d52691
F src/vdbeInt.h 4b19fd8febad3fd14c4c97adaefc06754d323132 F src/vdbeInt.h 016c808478bce04e071c38fa506e05763e8a54b9
F src/vdbeapi.c 37fc2818bec64b361af73f3935699107bab0e625 F src/vdbeapi.c 37d793559390bec8a00c556f651f21b5f9e589af
F src/vdbeaux.c ef59545f53f90394283f2fd003375d3ebbf0bd6e F src/vdbeaux.c ef59545f53f90394283f2fd003375d3ebbf0bd6e
F src/vdbeblob.c 6d3128c71d5a6b8db627ea3052ed5aaaaf26e672 F src/vdbeblob.c 6d3128c71d5a6b8db627ea3052ed5aaaaf26e672
F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f
F src/vdbemem.c 981a113405bd9b80aeb71fe246a2f01708e8a8f7 F src/vdbemem.c 02ffe06f967a23a66b72e48a1773153b417fad04
F src/vtab.c 89a0d5f39c1beba65a77fdb4d507b831fc5e6baf F src/vtab.c 89a0d5f39c1beba65a77fdb4d507b831fc5e6baf
F src/where.c 0f17b7bed2ce50ba450e8f436d5ec8b420c4ab3f F src/where.c 0f17b7bed2ce50ba450e8f436d5ec8b420c4ab3f
F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42 F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
@@ -170,6 +170,7 @@ F test/btree5.test 8e5ff32c02e685d36516c6499add9375fe1377f2
F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027 F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027
F test/btree7.test a6d3b842db22af97dd14b989e90a2fd96066b72f F test/btree7.test a6d3b842db22af97dd14b989e90a2fd96066b72f
F test/btree8.test fadc112bcbd6a0c622d34c813fc8a648eacf8804 F test/btree8.test fadc112bcbd6a0c622d34c813fc8a648eacf8804
F test/btree9.test 5d8711b241145b90f65dd1795d5dd8290846fa5e
F test/busy.test 0271c854738e23ad76e10d4096a698e5af29d211 F test/busy.test 0271c854738e23ad76e10d4096a698e5af29d211
F test/cache.test 9e530b55ba016ca17439f728a06898f0ade5f1da F test/cache.test 9e530b55ba016ca17439f728a06898f0ade5f1da
F test/capi2.test 7ecc9b342cc9ec27b53bbf95724cf2e5874fd496 F test/capi2.test 7ecc9b342cc9ec27b53bbf95724cf2e5874fd496
@@ -469,7 +470,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
P c444836e7b690c16dd6acff571c613a23beb42dc P 7c4c65924035d9f260f6b64eb92c5c6cf6c04b7b
R 15961852c9b829c1a838faae38aeed43 R ab7ef76e7fb4aa900cb531034d51122a
U shess U drh
Z c808046b1e2602c778234ecda5713f7c Z 29f62b2ce72d241a227558f749482713

View File

@@ -1 +1 @@
7c4c65924035d9f260f6b64eb92c5c6cf6c04b7b 7a01836dde45098796693bc6cb6045c4059adf1a

View File

@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give. ** 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. ** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to ** For a detailed discussion of BTrees, refer to
@@ -4151,6 +4151,7 @@ static int fillInCell(
unsigned char *pCell, /* Complete text of the cell */ unsigned char *pCell, /* Complete text of the cell */
const void *pKey, i64 nKey, /* The key */ const void *pKey, i64 nKey, /* The key */
const void *pData,int nData, /* The data */ const void *pData,int nData, /* The data */
int nZero, /* Extra zero bytes to append to pData */
int *pnSize /* Write cell size here */ int *pnSize /* Write cell size here */
){ ){
int nPayload; int nPayload;
@@ -4172,18 +4173,18 @@ static int fillInCell(
nHeader += 4; nHeader += 4;
} }
if( pPage->hasData ){ if( pPage->hasData ){
nHeader += putVarint(&pCell[nHeader], nData); nHeader += putVarint(&pCell[nHeader], nData+nZero);
}else{ }else{
nData = 0; nData = nZero = 0;
} }
nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey); nHeader += putVarint(&pCell[nHeader], *(u64*)&nKey);
parseCellPtr(pPage, pCell, &info); parseCellPtr(pPage, pCell, &info);
assert( info.nHeader==nHeader ); assert( info.nHeader==nHeader );
assert( info.nKey==nKey ); assert( info.nKey==nKey );
assert( info.nData==nData ); assert( info.nData==nData+nZero );
/* Fill in the payload */ /* Fill in the payload */
nPayload = nData; nPayload = nData + nZero;
if( pPage->intKey ){ if( pPage->intKey ){
pSrc = pData; pSrc = pData;
nSrc = nData; nSrc = nData;
@@ -4228,9 +4229,13 @@ static int fillInCell(
} }
n = nPayload; n = nPayload;
if( n>spaceLeft ) n = spaceLeft; if( n>spaceLeft ) n = spaceLeft;
if( n>nSrc ) n = nSrc; if( nSrc>0 ){
assert( pSrc ); if( n>nSrc ) n = nSrc;
memcpy(pPayload, pSrc, n); assert( pSrc );
memcpy(pPayload, pSrc, n);
}else{
memset(pPayload, 0, n);
}
nPayload -= n; nPayload -= n;
pPayload += n; pPayload += n;
pSrc += n; pSrc += n;
@@ -4555,7 +4560,7 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){
*/ */
assert( pPage->nCell>0 ); assert( pPage->nCell>0 );
parseCellPtr(pPage, findCell(pPage, pPage->nCell-1), &info); 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 ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
@@ -5101,7 +5106,7 @@ static int balance_nonroot(MemPage *pPage){
j--; j--;
parseCellPtr(pNew, apCell[j], &info); parseCellPtr(pNew, apCell[j], &info);
pCell = &aSpace[iSpace]; pCell = &aSpace[iSpace];
fillInCell(pParent, pCell, 0, info.nKey, 0, 0, &sz); fillInCell(pParent, pCell, 0, info.nKey, 0, 0, 0, &sz);
iSpace += sz; iSpace += sz;
assert( iSpace<=pBt->pageSize*5 ); assert( iSpace<=pBt->pageSize*5 );
pTemp = 0; pTemp = 0;
@@ -5415,6 +5420,7 @@ int sqlite3BtreeInsert(
BtCursor *pCur, /* Insert data into the table of this cursor */ BtCursor *pCur, /* Insert data into the table of this cursor */
const void *pKey, i64 nKey, /* The key of the new record */ const void *pKey, i64 nKey, /* The key of the new record */
const void *pData, int nData, /* The data 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 appendBias /* True if this is likely an append */
){ ){
int rc; int rc;
@@ -5457,7 +5463,7 @@ int sqlite3BtreeInsert(
if( rc ) return rc; if( rc ) return rc;
newCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) ); newCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) );
if( newCell==0 ) return SQLITE_NOMEM; 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; if( rc ) goto end_insert;
assert( szNew==cellSizePtr(pPage, newCell) ); assert( szNew==cellSizePtr(pPage, newCell) );
assert( szNew<=MX_CELL_SIZE(pBt) ); assert( szNew<=MX_CELL_SIZE(pBt) );
@@ -6857,7 +6863,7 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, const void *z){
} }
if( nCopy>0 ){ if( nCopy>0 ){
memcpy(&zData[offset], z, amt); memcpy(&zData[offset], z, amt);
rc = sqlite3BtreeInsert(pCsr, 0, iKey, zData, nData, 0); rc = sqlite3BtreeInsert(pCsr, 0, iKey, zData, nData, 0, 0);
} }
sqliteFree(zData); sqliteFree(zData);

View File

@@ -13,7 +13,7 @@
** subsystem. See comments in the source code for a detailed description ** subsystem. See comments in the source code for a detailed description
** of what each interface routine does. ** 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_ #ifndef _BTREE_H_
#define _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 sqlite3BtreeMoveto(BtCursor*,const void *pKey,i64 nKey,int bias,int *pRes);
int sqlite3BtreeDelete(BtCursor*); int sqlite3BtreeDelete(BtCursor*);
int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey, 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 sqlite3BtreeFirst(BtCursor*, int *pRes);
int sqlite3BtreeLast(BtCursor*, int *pRes); int sqlite3BtreeLast(BtCursor*, int *pRes);
int sqlite3BtreeNext(BtCursor*, int *pRes); int sqlite3BtreeNext(BtCursor*, int *pRes);

View File

@@ -12,7 +12,7 @@
** This header file defines the interface that the SQLite library ** This header file defines the interface that the SQLite library
** presents to client programs. ** 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_ #ifndef _SQLITE3_H_
#define _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_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_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); 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 ** 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_text16le(sqlite3_context*, const void*, int,void(*)(void*));
void sqlite3_result_text16be(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_value(sqlite3_context*, sqlite3_value*);
void sqlite3_result_zeroblob(sqlite3_context*, int n);
/* /*
** These are the allowed values for the eTextRep argument to ** These are the allowed values for the eTextRep argument to

View File

@@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated ** is not included in the SQLite library. It is used for automated
** testing of the SQLite library. ** 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 "sqliteInt.h"
#include "tcl.h" #include "tcl.h"
@@ -2257,6 +2257,43 @@ static int test_breakpoint(
return TCL_OK; /* Do nothing */ 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 ** Usage: sqlite3_bind_int STMT N VALUE
** **
@@ -4361,6 +4398,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
} aObjCmd[] = { } aObjCmd[] = {
{ "sqlite3_connection_pointer", get_sqlite_pointer, 0 }, { "sqlite3_connection_pointer", get_sqlite_pointer, 0 },
{ "sqlite3_bind_int", test_bind_int, 0 }, { "sqlite3_bind_int", test_bind_int, 0 },
{ "sqlite3_bind_zeroblob", test_bind_zeroblob, 0 },
{ "sqlite3_bind_int64", test_bind_int64, 0 }, { "sqlite3_bind_int64", test_bind_int64, 0 },
{ "sqlite3_bind_double", test_bind_double, 0 }, { "sqlite3_bind_double", test_bind_double, 0 },
{ "sqlite3_bind_null", test_bind_null ,0 }, { "sqlite3_bind_null", test_bind_null ,0 },

View File

@@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated ** is not included in the SQLite library. It is used for automated
** testing of the SQLite library. ** 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 "sqliteInt.h"
#include "pager.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 ** Create a new entry with the given key and data. If an entry already
** exists with the same key the old entry is overwritten. ** exists with the same key the old entry is overwritten.
@@ -763,19 +763,25 @@ static int btree_insert(
){ ){
BtCursor *pCur; BtCursor *pCur;
int rc; int rc;
int nZero;
if( objc!=4 ){ if( objc!=4 && objc!=5 ){
Tcl_WrongNumArgs(interp, 1, objv, "ID KEY DATA"); Tcl_WrongNumArgs(interp, 1, objv, "ID KEY DATA ?NZERO?");
return TCL_ERROR; return TCL_ERROR;
} }
pCur = sqlite3TextToPtr(Tcl_GetString(objv[1])); 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 ){ if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
i64 iKey; i64 iKey;
int len; int len;
unsigned char *pBuf; unsigned char *pBuf;
if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ) return TCL_ERROR; if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ) return TCL_ERROR;
pBuf = Tcl_GetByteArrayFromObj(objv[3], &len); pBuf = Tcl_GetByteArrayFromObj(objv[3], &len);
rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len, 0); rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len, nZero, 0);
}else{ }else{
int keylen; int keylen;
int dlen; int dlen;
@@ -783,7 +789,7 @@ static int btree_insert(
unsigned char *pDBuf; unsigned char *pDBuf;
pKBuf = Tcl_GetByteArrayFromObj(objv[2], &keylen); pKBuf = Tcl_GetByteArrayFromObj(objv[2], &keylen);
pDBuf = Tcl_GetByteArrayFromObj(objv[3], &dlen); 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 ){ if( rc ){
Tcl_AppendResult(interp, errorName(rc), 0); Tcl_AppendResult(interp, errorName(rc), 0);

View File

@@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing ** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code. ** 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 "sqliteInt.h"
#include "os.h" #include "os.h"
@@ -3372,8 +3372,14 @@ case OP_Insert: { /* no-push */
} }
pC->nullRow = 0; pC->nullRow = 0;
}else{ }else{
int nZero;
if( pTos->flags & MEM_Zero ){
nZero = pTos->u.i;
}else{
nZero = 0;
}
rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey, rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey,
pTos->z, pTos->n, pTos->z, pTos->n, nZero,
pOp->p2 & OPFLAG_APPEND); pOp->p2 & OPFLAG_APPEND);
} }
@@ -3752,7 +3758,7 @@ case OP_IdxInsert: { /* no-push */
int nKey = pTos->n; int nKey = pTos->n;
const char *zKey = pTos->z; const char *zKey = pTos->z;
assert( pC->isTable==0 ); 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 ); assert( pC->deferredMoveto==0 );
pC->cacheStatus = CACHE_STALE; pC->cacheStatus = CACHE_STALE;
} }

View File

@@ -172,6 +172,7 @@ typedef struct Mem Mem;
#define MEM_Ephem 0x0100 /* Mem.z points to an ephemeral string */ #define MEM_Ephem 0x0100 /* Mem.z points to an ephemeral string */
#define MEM_Short 0x0200 /* Mem.z points to Mem.zShort */ #define MEM_Short 0x0200 /* Mem.z points to Mem.zShort */
#define MEM_Agg 0x0400 /* Mem.z points to an agg function context */ #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 /* 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 sqlite3VdbeMemSetInt64(Mem*, i64);
void sqlite3VdbeMemSetDouble(Mem*, double); void sqlite3VdbeMemSetDouble(Mem*, double);
void sqlite3VdbeMemSetNull(Mem*); void sqlite3VdbeMemSetNull(Mem*);
void sqlite3VdbeMemSetZeroBlob(Mem*,int);
int sqlite3VdbeMemMakeWriteable(Mem*); int sqlite3VdbeMemMakeWriteable(Mem*);
int sqlite3VdbeMemDynamicify(Mem*); int sqlite3VdbeMemDynamicify(Mem*);
int sqlite3VdbeMemStringify(Mem*, int); int sqlite3VdbeMemStringify(Mem*, int);

View File

@@ -37,6 +37,7 @@ int sqlite3_expired(sqlite3_stmt *pStmt){
const void *sqlite3_value_blob(sqlite3_value *pVal){ const void *sqlite3_value_blob(sqlite3_value *pVal){
Mem *p = (Mem*)pVal; Mem *p = (Mem*)pVal;
if( p->flags & (MEM_Blob|MEM_Str) ){ if( p->flags & (MEM_Blob|MEM_Str) ){
sqlite3VdbeMemExpandBlob(p);
if( (p->flags & MEM_Term)==0 ){ if( (p->flags & MEM_Term)==0 ){
p->flags &= ~MEM_Str; p->flags &= ~MEM_Str;
} }
@@ -151,6 +152,9 @@ void sqlite3_result_text16le(
void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){ void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
sqlite3VdbeMemCopy(&pCtx->s, 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; 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. ** Return the number of wildcards that can be potentially bound to.

View File

@@ -60,12 +60,14 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. ** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails.
*/ */
int sqlite3VdbeMemDynamicify(Mem *pMem){ int sqlite3VdbeMemDynamicify(Mem *pMem){
int n = pMem->n; int n;
u8 *z; u8 *z;
sqlite3VdbeMemExpandBlob(pMem);
if( (pMem->flags & (MEM_Ephem|MEM_Static|MEM_Short))==0 ){ if( (pMem->flags & (MEM_Ephem|MEM_Static|MEM_Short))==0 ){
return SQLITE_OK; return SQLITE_OK;
} }
assert( (pMem->flags & MEM_Dyn)==0 ); assert( (pMem->flags & MEM_Dyn)==0 );
n = pMem->n;
assert( pMem->flags & (MEM_Str|MEM_Blob) ); assert( pMem->flags & (MEM_Str|MEM_Blob) );
z = sqliteMallocRaw( n+2 ); z = sqliteMallocRaw( n+2 );
if( z==0 ){ if( z==0 ){
@@ -81,6 +83,30 @@ int sqlite3VdbeMemDynamicify(Mem *pMem){
return SQLITE_OK; 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 ** Make the given Mem object either MEM_Short or MEM_Dyn so that bytes
** of the Mem.z[] array can be modified. ** of the Mem.z[] array can be modified.
@@ -90,6 +116,7 @@ int sqlite3VdbeMemDynamicify(Mem *pMem){
int sqlite3VdbeMemMakeWriteable(Mem *pMem){ int sqlite3VdbeMemMakeWriteable(Mem *pMem){
int n; int n;
u8 *z; u8 *z;
sqlite3VdbeMemExpandBlob(pMem);
if( (pMem->flags & (MEM_Ephem|MEM_Static))==0 ){ if( (pMem->flags & (MEM_Ephem|MEM_Static))==0 ){
return SQLITE_OK; return SQLITE_OK;
} }
@@ -347,6 +374,18 @@ void sqlite3VdbeMemSetNull(Mem *pMem){
pMem->n = 0; 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, ** Delete any previous value and set the value stored in *pMem to val,
** manifest type INTEGER. ** manifest type INTEGER.
@@ -699,14 +738,14 @@ int sqlite3VdbeMemFromBtree(
void sqlite3VdbeMemSanity(Mem *pMem){ void sqlite3VdbeMemSanity(Mem *pMem){
int flags = pMem->flags; int flags = pMem->flags;
assert( flags!=0 ); /* Must define some type */ assert( flags!=0 ); /* Must define some type */
if( pMem->flags & (MEM_Str|MEM_Blob) ){ if( flags & (MEM_Str|MEM_Blob) ){
int x = pMem->flags & (MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short); int x = flags & (MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short);
assert( x!=0 ); /* Strings must define a string subtype */ assert( x!=0 ); /* Strings must define a string subtype */
assert( (x & (x-1))==0 ); /* Only one string subtype can be defined */ 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 */ /* Mem.z points to Mem.zShort iff the subtype is MEM_Short */
assert( (pMem->flags & MEM_Short)==0 || pMem->z==pMem->zShort ); assert( (x & 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 );
/* No destructor unless there is MEM_Dyn */ /* No destructor unless there is MEM_Dyn */
assert( pMem->xDel==0 || (pMem->flags & MEM_Dyn)!=0 ); 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 ); assert( (MEM_Blob>>3) == MEM_Str );
pVal->flags |= (pVal->flags & MEM_Blob)>>3; pVal->flags |= (pVal->flags & MEM_Blob)>>3;
sqlite3VdbeMemExpandBlob(pVal);
if( pVal->flags&MEM_Str ){ if( pVal->flags&MEM_Str ){
sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED); sqlite3VdbeChangeEncoding(pVal, enc & ~SQLITE_UTF16_ALIGNED);
if( (enc & SQLITE_UTF16_ALIGNED)!=0 && 1==(1&(int)pVal->z) ){ 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){ int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){
Mem *p = (Mem*)pVal; Mem *p = (Mem*)pVal;
if( (p->flags & MEM_Blob)!=0 || sqlite3ValueText(pVal, enc) ){ 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; return 0;
} }

49
test/btree9.test Normal file
View File

@@ -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