]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add support for zero-blobs to the OP_MakeRecord opcode.
authordrh <drh@noemail.net>
Wed, 2 May 2007 13:30:27 +0000 (13:30 +0000)
committerdrh <drh@noemail.net>
Wed, 2 May 2007 13:30:27 +0000 (13:30 +0000)
First test cases of zeroblob functionality. (CVS 3897)

FossilOrigin-Name: e6d560ddeeb48fb0cbd9f5a10612280b055baef7

manifest
manifest.uuid
src/vdbe.c
src/vdbeInt.h
src/vdbeaux.c
src/vdbemem.c
test/zeroblob.test [new file with mode: 0644]

index 76faeb3de1b088862b9d49c999caa2c67a42707f..c29b3a2ba76659f270ee470ab5e279db3f3b14d4 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Use\sthe\spointer-map\spages\sto\smake\sthe\sincremental\sblob\sAPI\smore\sefficient.\s(CVS\s3896)
-D 2007-05-02T13:16:30
+C Add\ssupport\sfor\szero-blobs\sto\sthe\sOP_MakeRecord\sopcode.\r\nFirst\stest\scases\sof\szeroblob\sfunctionality.\s(CVS\s3897)
+D 2007-05-02T13:30:27
 F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62
 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -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 8cc851ca1d6d849586eb0c5359c492685c285c97
+F src/vdbe.c bb1baa9a357b14f28ddfd0a896f60c6ef82dfd33
 F src/vdbe.h 0025259af1939fb264a545816c69e4b5b8d52691
-F src/vdbeInt.h 10ff7c35f790d48f51317af4e5833d4d4cb5da34
+F src/vdbeInt.h cb02cbbceddf3b40d49012e9f41576f17bcbec97
 F src/vdbeapi.c 37d793559390bec8a00c556f651f21b5f9e589af
-F src/vdbeaux.c ef59545f53f90394283f2fd003375d3ebbf0bd6e
+F src/vdbeaux.c 8c7f22e22d1ea578971f5a3fcd3a56a6882ced64
 F src/vdbeblob.c 6d3128c71d5a6b8db627ea3052ed5aaaaf26e672
 F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f
-F src/vdbemem.c 02ffe06f967a23a66b72e48a1773153b417fad04
+F src/vdbemem.c ba98f8572ec4609846b368fa7580db178022f1bb
 F src/vtab.c 89a0d5f39c1beba65a77fdb4d507b831fc5e6baf
 F src/where.c 0f17b7bed2ce50ba450e8f436d5ec8b420c4ab3f
 F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42
@@ -395,6 +395,7 @@ F test/where.test 1d020f50c77f37b2dbab9766ca959e6e3278ecdb
 F test/where2.test 3249d426b3fc7a106713d784e1628307fc308d2e
 F test/where3.test 0a30fe9808b0fa01c46d0fcf4fac0bf6cf75bb30
 F test/where4.test b68496500bff496e83e76ae4ffb493b99064eac6
+F test/zeroblob.test 76efa0e1b8116037e009b38a060033ea77526437
 F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
 F tool/fragck.tcl 5265a95126abcf6ab357f7efa544787e5963f439
 F tool/lemon.c c8c8b25ab1ac8156b3ad83ba4ea1bf00d5e07f5a
@@ -470,7 +471,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
 F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P 6f4f8ba7ec15f214f36fa78e593dd4522ab717f5
-R 89ce3536d9d902e9d75a561e20ef3775
-U danielk1977
-Z 5170bc200f54fb706f822cc7c0bea383
+P 93a3bf71d576096f4b5a3db256ca6f9b5521d137
+R fa4803e6928e32943334bc2c675198a5
+U drh
+Z ea8ec33f5bc91d3f655c1cd7ff5d5d75
index 2903a5e5973fc59f8ba6a454810a76e9068c1196..4e16b92621b518fba0a6f8d196e562630210d5ea 100644 (file)
@@ -1 +1 @@
-93a3bf71d576096f4b5a3db256ca6f9b5521d137
\ No newline at end of file
+e6d560ddeeb48fb0cbd9f5a10612280b055baef7
\ No newline at end of file
index 4207cf3e3fa8d0f0ea5c53fe722394a6916b22b8..072375ac1c9d1ef7345ee063f7cd067345618cc6 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.603 2007/05/02 01:34:32 drh Exp $
+** $Id: vdbe.c,v 1.604 2007/05/02 13:30:27 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -311,7 +311,7 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
     zCsr += sprintf(zCsr, "%c", c);
     zCsr += sprintf(zCsr, "%d[", pMem->n);
     for(i=0; i<16 && i<pMem->n; i++){
-      zCsr += sprintf(zCsr, "%02X ", ((int)pMem->z[i] & 0xFF));
+      zCsr += sprintf(zCsr, "%02X", ((int)pMem->z[i] & 0xFF));
     }
     for(i=0; i<16 && i<pMem->n; i++){
       char z = pMem->z[i];
@@ -320,6 +320,9 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
     }
 
     zCsr += sprintf(zCsr, "]");
+    if( f & MEM_Zero ){
+      zCsr += sprintf(zCsr,"+%lldz",pMem->u.i);
+    }
     *zCsr = '\0';
   }else if( f & MEM_Str ){
     int j, k;
@@ -2185,25 +2188,25 @@ case OP_MakeRecord: {
   ** hdr-size field is also a varint which is the offset from the beginning
   ** of the record to data0.
   */
-  unsigned char *zNewRecord;
-  unsigned char *zCsr;
-  Mem *pRec;
-  Mem *pRowid = 0;
+  u8 *zNewRecord;        /* A buffer to hold the data for the new record */
+  Mem *pRec;             /* The new record */
+  Mem *pRowid = 0;       /* Rowid appended to the new record */
   int nData = 0;         /* Number of bytes of data space */
   int nHdr = 0;          /* Number of bytes of header space */
-  int nByte = 0;         /* Space required for this record */
+  int nByte = 0;         /* Data space required for this record */
+  int nZero = 0;         /* Number of zero bytes at the end of the record */
   int nVarint;           /* Number of bytes in a varint */
   u32 serial_type;       /* Type field */
   int containsNull = 0;  /* True if any of the data fields are NULL */
-  char zTemp[NBFS];      /* Space to hold small records */
-  Mem *pData0;
-
+  Mem *pData0;           /* Bottom of the stack */
   int leaveOnStack;      /* If true, leave the entries on the stack */
   int nField;            /* Number of fields in the record */
   int jumpIfNull;        /* Jump here if non-zero and any entries are NULL. */
   int addRowid;          /* True to append a rowid column at the end */
   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 */
 
   leaveOnStack = ((pOp->p1<0)?1:0);
   nField = pOp->p1 * (leaveOnStack?-1:1);
@@ -2229,11 +2232,19 @@ case OP_MakeRecord: {
     serial_type = sqlite3VdbeSerialType(pRec, file_format);
     nData += sqlite3VdbeSerialTypeLen(serial_type);
     nHdr += sqlite3VarintLen(serial_type);
+    if( pRec->flags & MEM_Zero ){
+      /* Only pure zero-filled BLOBs can be input to this Opcode.
+      ** We do not allow blobs with a prefix and a zero-filled tail. */
+      assert( pRec->n==0 );
+      nZero += pRec->u.i;
+    }else{
+      nZero = 0;
+    }
   }
 
-  /* If we have to append a varint rowid to this record, set 'rowid'
+  /* If we have to append a varint rowid to this record, set pRowid
   ** to the value of the rowid and increase nByte by the amount of space
-  ** required to store it and the 0x00 seperator byte.
+  ** required to store it.
   */
   if( addRowid ){
     pRowid = &pTos[0-nField];
@@ -2242,6 +2253,7 @@ case OP_MakeRecord: {
     serial_type = sqlite3VdbeSerialType(pRowid, 0);
     nData += sqlite3VdbeSerialTypeLen(serial_type);
     nHdr += sqlite3VarintLen(serial_type);
+    nZero = 0;
   }
 
   /* Add the initial header varint and total the size */
@@ -2249,7 +2261,7 @@ case OP_MakeRecord: {
   if( nVarint<sqlite3VarintLen(nHdr) ){
     nHdr++;
   }
-  nByte = nHdr+nData;
+  nByte = nHdr+nData-nZero;
 
   /* Allocate space for the new record. */
   if( nByte>sizeof(zTemp) ){
@@ -2262,22 +2274,21 @@ case OP_MakeRecord: {
   }
 
   /* Write the record */
-  zCsr = zNewRecord;
-  zCsr += sqlite3PutVarint(zCsr, nHdr);
+  i = sqlite3PutVarint(zNewRecord, nHdr);
   for(pRec=pData0; pRec<=pTos; pRec++){
     serial_type = sqlite3VdbeSerialType(pRec, file_format);
-    zCsr += sqlite3PutVarint(zCsr, serial_type);      /* serial type */
+    i += sqlite3PutVarint(&zNewRecord[i], serial_type);      /* serial type */
   }
   if( addRowid ){
-    zCsr += sqlite3PutVarint(zCsr, sqlite3VdbeSerialType(pRowid, 0));
+    i += sqlite3PutVarint(&zNewRecord[i], sqlite3VdbeSerialType(pRowid, 0));
   }
-  for(pRec=pData0; pRec<=pTos; pRec++){
-    zCsr += sqlite3VdbeSerialPut(zCsr, pRec, file_format);  /* serial data */
+  for(pRec=pData0; pRec<=pTos; pRec++){  /* serial data */
+    i += sqlite3VdbeSerialPut(&zNewRecord[i], nByte-i, pRec, file_format);
   }
   if( addRowid ){
-    zCsr += sqlite3VdbeSerialPut(zCsr, pRowid, 0);
+    i += sqlite3VdbeSerialPut(&zNewRecord[i], nByte-i, pRowid, 0);
   }
-  assert( zCsr==(zNewRecord+nByte) );
+  assert( i==nByte );
 
   /* Pop entries off the stack if required. Push the new record on. */
   if( !leaveOnStack ){
@@ -2296,6 +2307,10 @@ case OP_MakeRecord: {
     pTos->flags = MEM_Blob | MEM_Dyn;
     pTos->xDel = 0;
   }
+  if( nZero ){
+    pTos->u.i = nZero;
+    pTos->flags |= MEM_Zero;
+  }
   pTos->enc = SQLITE_UTF8;  /* In case the blob is ever converted to text */
 
   /* If a NULL was encountered and jumpIfNull is non-zero, take the jump. */
@@ -4997,7 +5012,7 @@ default: {
         }else if( pTos[i].flags & MEM_Real ){
           fprintf(p->trace, " r:%g", pTos[i].r);
         }else{
-          char zBuf[100];
+          char zBuf[200];
           sqlite3VdbeMemPrettyPrint(&pTos[i], zBuf);
           fprintf(p->trace, " ");
           fprintf(p->trace, "%s", zBuf);
index f00e7b5a4048937966f0385fe6feec0567902f9f..545079d578b88b5490cbde02e39f28fe854c8c76 100644 (file)
@@ -133,8 +133,8 @@ struct Mem {
   char *z;            /* String or BLOB value */
   int n;              /* Number of characters in string value, including '\0' */
   u16 flags;          /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
-  u8  type;           /* One of MEM_Null, MEM_Str, etc. */
-  u8  enc;            /* TEXT_Utf8, TEXT_Utf16le, or TEXT_Utf16be */
+  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 */
 };
@@ -364,7 +364,7 @@ void sqlite3VdbePrintSql(Vdbe*);
 #endif
 int sqlite3VdbeSerialTypeLen(u32);
 u32 sqlite3VdbeSerialType(Mem*, int);
-int sqlite3VdbeSerialPut(unsigned char*, Mem*, int);
+int sqlite3VdbeSerialPut(unsigned char*, int, Mem*, int);
 int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
 void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);
 
index 6c1af395a0671dd82c69528d992952153e17c213..b3f903c34cb09c49993f1258f54d6b546ca409d1 100644 (file)
@@ -1722,6 +1722,7 @@ int sqlite3VdbeCursorMoveto(Cursor *p){
 */
 u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
   int flags = pMem->flags;
+  int n;
 
   if( flags&MEM_Null ){
     return 0;
@@ -1745,13 +1746,13 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
   if( flags&MEM_Real ){
     return 7;
   }
-  if( flags&MEM_Str ){
-    int n = pMem->n;
-    assert( n>=0 );
-    return ((n*2) + 13);
+  assert( flags&(MEM_Str|MEM_Blob) );
+  n = pMem->n;
+  if( flags & MEM_Zero ){
+    n += pMem->u.i;
   }
-  assert( (flags & MEM_Blob)!=0 );
-  return (pMem->n*2 + 12);
+  assert( n>=0 );
+  return ((n*2) + 12 + ((flags&MEM_Str)!=0));
 }
 
 /*
@@ -1770,8 +1771,21 @@ int sqlite3VdbeSerialTypeLen(u32 serial_type){
 ** Write the serialized data blob for the value stored in pMem into 
 ** buf. It is assumed that the caller has allocated sufficient space.
 ** Return the number of bytes written.
+**
+** nBuf is the amount of space left in buf[].  nBuf must always be
+** large enough to hold the entire field.  Except, if the field is
+** a blob with a zero-filled tail, then buf[] might be just the right
+** size to hold everything except for the zero-filled tail.  If buf[]
+** is only big enough to hold the non-zero prefix, then only write that
+** prefix into buf[].  But if buf[] is large enough to hold both the
+** prefix and the tail then write the prefix and set the tail to all
+** zeros.
+**
+** Return the number of bytes actually written into buf[].  The number
+** of bytes in the zero-filled tail is included in the return value only
+** if those bytes were zeroed in buf[].
 */ 
-int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem, int file_format){
+int sqlite3VdbeSerialPut(u8 *buf, int nBuf, Mem *pMem, int file_format){
   u32 serial_type = sqlite3VdbeSerialType(pMem, file_format);
   int len;
 
@@ -1786,6 +1800,7 @@ int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem, int file_format){
       v = pMem->u.i;
     }
     len = i = sqlite3VdbeSerialTypeLen(serial_type);
+    assert( len<=nBuf );
     while( i-- ){
       buf[i] = (v&0xFF);
       v >>= 8;
@@ -1795,8 +1810,18 @@ int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem, int file_format){
 
   /* String or blob */
   if( serial_type>=12 ){
-    len = sqlite3VdbeSerialTypeLen(serial_type);
+    assert( pMem->n + ((pMem->flags & MEM_Zero)?pMem->u.i:0)
+             == sqlite3VdbeSerialTypeLen(serial_type) );
+    assert( pMem->n<=nBuf );
+    len = pMem->n;
     memcpy(buf, pMem->z, len);
+    if( pMem->flags & MEM_Zero ){
+      len += pMem->u.i;
+      if( len>nBuf ){
+        len = nBuf;
+      }
+      memset(&buf[pMem->n], 0, len-pMem->n);
+    }
     return len;
   }
 
index 52b4a5feb26b07ab8ff5b08e9f2854d93196b260..9772b415d5a140d0bab180fdd19584ed027d684c 100644 (file)
@@ -84,21 +84,22 @@ int sqlite3VdbeMemDynamicify(Mem *pMem){
 }
 
 /*
-** If the given Mem* is a zero-filled blob, turn it into an ordinary
+** If the given Mem* has a zero-filled tail, 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);
+    pNew = sqliteMalloc(pMem->n+pMem->u.i);
     if( pNew==0 ){ 
       return SQLITE_NOMEM;
     }
     memcpy(pNew, pMem->z, pMem->n);
-    memset(&pNew[pMem->n], 0, pMem->u.i+1);
+    memset(&pNew[pMem->n], 0, pMem->u.i);
     sqlite3VdbeMemRelease(pMem);
     pMem->z = pNew;
+    pMem->n += pMem->u.i;
     pMem->u.i = 0;
     pMem->flags &= MEM_Zero|MEM_Static|MEM_Ephem|MEM_Short;
     pMem->flags |= MEM_Term|MEM_Dyn;
@@ -380,10 +381,11 @@ void sqlite3VdbeMemSetNull(Mem *pMem){
 */
 void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){
   sqlite3VdbeMemRelease(pMem);
-  pMem->flags = MEM_Blob|MEM_Zero;
+  pMem->flags = MEM_Blob|MEM_Zero|MEM_Short;
   pMem->type = SQLITE_BLOB;
   pMem->n = 0;
   pMem->u.i = n;
+  pMem->z = pMem->zShort;
 }
 
 /*
@@ -742,7 +744,7 @@ void sqlite3VdbeMemSanity(Mem *pMem){
     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 || x==MEM_Zero );      /* Strings must have a value */
+    assert( pMem->z!=0 );      /* Strings must have a value */
     /* Mem.z points to Mem.zShort iff the subtype is MEM_Short */
     assert( (x & MEM_Short)==0 || pMem->z==pMem->zShort );
     assert( (x & MEM_Short)!=0 || pMem->z!=pMem->zShort );
diff --git a/test/zeroblob.test b/test/zeroblob.test
new file mode 100644 (file)
index 0000000..07ac0d7
--- /dev/null
@@ -0,0 +1,58 @@
+# 2007 May 02
+#
+# 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 file is testing of the zero-filled blob functionality
+# including the sqlite3_bind_zeroblob(), sqlite3_result_zeroblob(),
+# and the built-in zeroblob() SQL function.
+#
+# $Id: zeroblob.test,v 1.1 2007/05/02 13:30:27 drh Exp $
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+# Create the database
+#
+do_test zeroblob-1.1 {
+  execsql {
+    CREATE TABLE t1(a,b,c,d);
+    INSERT INTO t1 VALUES(1,2,3,zeroblob(10000));
+    SELECT count(*) FROM t1;
+  }
+} {1}
+do_test zeroblob-1.2 {
+  execsql {
+    SELECT length(d) FROM t1
+  }
+} {10000}
+do_test zeroblob-1.3 {
+  execsql {
+    INSERT INTO t1 VALUES(2,3,zeroblob(10000),4);
+    SELECT count(*) FROM t1;
+  }
+} {2}
+do_test zeroblob-1.4 {
+  execsql {
+    SELECT length(c), length(d) FROM t1
+  }
+} {1 10000 10000 1}
+do_test zeroblob-1.5 {
+  execsql {
+    INSERT INTO t1 VALUES(3,4,zeroblob(10000),zeroblob(10000));
+    SELECT count(*) FROM t1;
+  }
+} {3}
+do_test zeroblob-1.6 {
+  execsql {
+    SELECT length(c), length(d) FROM t1
+  }
+} {1 10000 10000 1 10000 10000}
+
+finish_test