]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Begin adding the zeroblob API to support incremental blob i/o. (CVS 3894)
authordrh <drh@noemail.net>
Wed, 2 May 2007 01:34:31 +0000 (01:34 +0000)
committerdrh <drh@noemail.net>
Wed, 2 May 2007 01:34:31 +0000 (01:34 +0000)
FossilOrigin-Name: 7a01836dde45098796693bc6cb6045c4059adf1a

12 files changed:
manifest
manifest.uuid
src/btree.c
src/btree.h
src/sqlite.h.in
src/test1.c
src/test3.c
src/vdbe.c
src/vdbeInt.h
src/vdbeapi.c
src/vdbemem.c
test/btree9.test [new file with mode: 0644]

index cabd8f7348e432db4d7da81088108e1b1b348c28..9de3ea99eb2642613b022d461fbfeae978daa617 100644 (file)
--- 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
index 657800ab3f6b4853d58291c5e0682aa450a17711..d51270c01f700385472b0f197478a4dfef221fe1 100644 (file)
@@ -1 +1 @@
-7c4c65924035d9f260f6b64eb92c5c6cf6c04b7b
\ No newline at end of file
+7a01836dde45098796693bc6cb6045c4059adf1a
\ No newline at end of file
index b253395d971780e9d6d19c8502275071597b57c8..2ad7358055467b3e3da16cf9dd0d5f024e40a258 100644 (file)
@@ -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);
index 40a885f51bedb686966460433c90f905966f42df..b3cd5856448de4af0b5d384f303b177ac557d34a 100644 (file)
@@ -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);
index c229a10434960f0ef12f868bc009f695d02eaf8a..17a0a14d5b6160161e5fdbc9a017af16b78d0d89 100644 (file)
@@ -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
index 1d765b1efc6962aefc92dd0c3a7cde84368fabe2..409f4c212445b544c556d69501db9f137e7137c1 100644 (file)
@@ -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 },
index fba3fa2ecac3c574e8b659bfe76dc53384f3c0a1..4fb878fb570d43da67fc4358ef0caa0538159ed3 100644 (file)
@@ -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);
index eeb0847fd3c79d54fb1610fbd741e43260e53eca..4207cf3e3fa8d0f0ea5c53fe722394a6916b22b8 100644 (file)
@@ -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;
   }
index 11c906100c1f2fd300d2316e178f666ab752e9db..88ea6c72d03bda01b1bff90dd9599cf744f034c5 100644 (file)
@@ -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);
index bd6d1d41020bf493d81ad38ff33ae4d4e29d85b3..4e121059f83b98bdbae8faf1f95c2c952ddc8d44 100644 (file)
@@ -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.
index 5aed1df3dbc9f7598ef7be4c603cd090895dea10..52b4a5feb26b07ab8ff5b08e9f2854d93196b260 100644 (file)
@@ -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 (file)
index 0000000..678a12c
--- /dev/null
@@ -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