/ Check-in [e6d560dd]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add support for zero-blobs to the OP_MakeRecord opcode. First test cases of zeroblob functionality. (CVS 3897)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: e6d560ddeeb48fb0cbd9f5a10612280b055baef7
User & Date: drh 2007-05-02 13:30:27
Context
2007-05-02
15:36
Fix an invalid UTF8 encoding in the tests for the trim function. (CVS 3898) check-in: 4dbbfff4 user: drh tags: trunk
13:30
Add support for zero-blobs to the OP_MakeRecord opcode. First test cases of zeroblob functionality. (CVS 3897) check-in: e6d560dd user: drh tags: trunk
13:16
Use the pointer-map pages to make the incremental blob API more efficient. (CVS 3896) check-in: 93a3bf71 user: danielk1977 tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/vdbe.c.

    39     39   **
    40     40   ** Various scripts scan this source file in order to generate HTML
    41     41   ** documentation, headers files, or other derived files.  The formatting
    42     42   ** of the code in this file is, therefore, important.  See other comments
    43     43   ** in this file for details.  If in doubt, do not deviate from existing
    44     44   ** commenting and indentation practices when changing or adding code.
    45     45   **
    46         -** $Id: vdbe.c,v 1.603 2007/05/02 01:34:32 drh Exp $
           46  +** $Id: vdbe.c,v 1.604 2007/05/02 13:30:27 drh Exp $
    47     47   */
    48     48   #include "sqliteInt.h"
    49     49   #include "os.h"
    50     50   #include <ctype.h>
    51     51   #include "vdbeInt.h"
    52     52   
    53     53   /*
................................................................................
   307    307       }else{
   308    308         c = 's';
   309    309       }
   310    310   
   311    311       zCsr += sprintf(zCsr, "%c", c);
   312    312       zCsr += sprintf(zCsr, "%d[", pMem->n);
   313    313       for(i=0; i<16 && i<pMem->n; i++){
   314         -      zCsr += sprintf(zCsr, "%02X ", ((int)pMem->z[i] & 0xFF));
          314  +      zCsr += sprintf(zCsr, "%02X", ((int)pMem->z[i] & 0xFF));
   315    315       }
   316    316       for(i=0; i<16 && i<pMem->n; i++){
   317    317         char z = pMem->z[i];
   318    318         if( z<32 || z>126 ) *zCsr++ = '.';
   319    319         else *zCsr++ = z;
   320    320       }
   321    321   
   322    322       zCsr += sprintf(zCsr, "]");
          323  +    if( f & MEM_Zero ){
          324  +      zCsr += sprintf(zCsr,"+%lldz",pMem->u.i);
          325  +    }
   323    326       *zCsr = '\0';
   324    327     }else if( f & MEM_Str ){
   325    328       int j, k;
   326    329       zBuf[0] = ' ';
   327    330       if( f & MEM_Dyn ){
   328    331         zBuf[1] = 'z';
   329    332         assert( (f & (MEM_Static|MEM_Ephem))==0 );
................................................................................
  2181   2184     ** the top of the stack.
  2182   2185     **
  2183   2186     ** Each type field is a varint representing the serial type of the 
  2184   2187     ** corresponding data element (see sqlite3VdbeSerialType()). The
  2185   2188     ** hdr-size field is also a varint which is the offset from the beginning
  2186   2189     ** of the record to data0.
  2187   2190     */
  2188         -  unsigned char *zNewRecord;
  2189         -  unsigned char *zCsr;
  2190         -  Mem *pRec;
  2191         -  Mem *pRowid = 0;
         2191  +  u8 *zNewRecord;        /* A buffer to hold the data for the new record */
         2192  +  Mem *pRec;             /* The new record */
         2193  +  Mem *pRowid = 0;       /* Rowid appended to the new record */
  2192   2194     int nData = 0;         /* Number of bytes of data space */
  2193   2195     int nHdr = 0;          /* Number of bytes of header space */
  2194         -  int nByte = 0;         /* Space required for this record */
         2196  +  int nByte = 0;         /* Data space required for this record */
         2197  +  int nZero = 0;         /* Number of zero bytes at the end of the record */
  2195   2198     int nVarint;           /* Number of bytes in a varint */
  2196   2199     u32 serial_type;       /* Type field */
  2197   2200     int containsNull = 0;  /* True if any of the data fields are NULL */
  2198         -  char zTemp[NBFS];      /* Space to hold small records */
  2199         -  Mem *pData0;
  2200         -
         2201  +  Mem *pData0;           /* Bottom of the stack */
  2201   2202     int leaveOnStack;      /* If true, leave the entries on the stack */
  2202   2203     int nField;            /* Number of fields in the record */
  2203   2204     int jumpIfNull;        /* Jump here if non-zero and any entries are NULL. */
  2204   2205     int addRowid;          /* True to append a rowid column at the end */
  2205   2206     char *zAffinity;       /* The affinity string for the record */
  2206   2207     int file_format;       /* File format to use for encoding */
         2208  +  int i;                 /* Space used in zNewRecord[] */
         2209  +  char zTemp[NBFS];      /* Space to hold small records */
  2207   2210   
  2208   2211     leaveOnStack = ((pOp->p1<0)?1:0);
  2209   2212     nField = pOp->p1 * (leaveOnStack?-1:1);
  2210   2213     jumpIfNull = pOp->p2;
  2211   2214     addRowid = pOp->opcode==OP_MakeIdxRec;
  2212   2215     zAffinity = pOp->p3;
  2213   2216   
................................................................................
  2225   2228       }
  2226   2229       if( pRec->flags&MEM_Null ){
  2227   2230         containsNull = 1;
  2228   2231       }
  2229   2232       serial_type = sqlite3VdbeSerialType(pRec, file_format);
  2230   2233       nData += sqlite3VdbeSerialTypeLen(serial_type);
  2231   2234       nHdr += sqlite3VarintLen(serial_type);
         2235  +    if( pRec->flags & MEM_Zero ){
         2236  +      /* Only pure zero-filled BLOBs can be input to this Opcode.
         2237  +      ** We do not allow blobs with a prefix and a zero-filled tail. */
         2238  +      assert( pRec->n==0 );
         2239  +      nZero += pRec->u.i;
         2240  +    }else{
         2241  +      nZero = 0;
         2242  +    }
  2232   2243     }
  2233   2244   
  2234         -  /* If we have to append a varint rowid to this record, set 'rowid'
         2245  +  /* If we have to append a varint rowid to this record, set pRowid
  2235   2246     ** to the value of the rowid and increase nByte by the amount of space
  2236         -  ** required to store it and the 0x00 seperator byte.
         2247  +  ** required to store it.
  2237   2248     */
  2238   2249     if( addRowid ){
  2239   2250       pRowid = &pTos[0-nField];
  2240   2251       assert( pRowid>=p->aStack );
  2241   2252       sqlite3VdbeMemIntegerify(pRowid);
  2242   2253       serial_type = sqlite3VdbeSerialType(pRowid, 0);
  2243   2254       nData += sqlite3VdbeSerialTypeLen(serial_type);
  2244   2255       nHdr += sqlite3VarintLen(serial_type);
         2256  +    nZero = 0;
  2245   2257     }
  2246   2258   
  2247   2259     /* Add the initial header varint and total the size */
  2248   2260     nHdr += nVarint = sqlite3VarintLen(nHdr);
  2249   2261     if( nVarint<sqlite3VarintLen(nHdr) ){
  2250   2262       nHdr++;
  2251   2263     }
  2252         -  nByte = nHdr+nData;
         2264  +  nByte = nHdr+nData-nZero;
  2253   2265   
  2254   2266     /* Allocate space for the new record. */
  2255   2267     if( nByte>sizeof(zTemp) ){
  2256   2268       zNewRecord = sqliteMallocRaw(nByte);
  2257   2269       if( !zNewRecord ){
  2258   2270         goto no_mem;
  2259   2271       }
  2260   2272     }else{
  2261   2273       zNewRecord = (u8*)zTemp;
  2262   2274     }
  2263   2275   
  2264   2276     /* Write the record */
  2265         -  zCsr = zNewRecord;
  2266         -  zCsr += sqlite3PutVarint(zCsr, nHdr);
         2277  +  i = sqlite3PutVarint(zNewRecord, nHdr);
  2267   2278     for(pRec=pData0; pRec<=pTos; pRec++){
  2268   2279       serial_type = sqlite3VdbeSerialType(pRec, file_format);
  2269         -    zCsr += sqlite3PutVarint(zCsr, serial_type);      /* serial type */
         2280  +    i += sqlite3PutVarint(&zNewRecord[i], serial_type);      /* serial type */
  2270   2281     }
  2271   2282     if( addRowid ){
  2272         -    zCsr += sqlite3PutVarint(zCsr, sqlite3VdbeSerialType(pRowid, 0));
         2283  +    i += sqlite3PutVarint(&zNewRecord[i], sqlite3VdbeSerialType(pRowid, 0));
  2273   2284     }
  2274         -  for(pRec=pData0; pRec<=pTos; pRec++){
  2275         -    zCsr += sqlite3VdbeSerialPut(zCsr, pRec, file_format);  /* serial data */
         2285  +  for(pRec=pData0; pRec<=pTos; pRec++){  /* serial data */
         2286  +    i += sqlite3VdbeSerialPut(&zNewRecord[i], nByte-i, pRec, file_format);
  2276   2287     }
  2277   2288     if( addRowid ){
  2278         -    zCsr += sqlite3VdbeSerialPut(zCsr, pRowid, 0);
         2289  +    i += sqlite3VdbeSerialPut(&zNewRecord[i], nByte-i, pRowid, 0);
  2279   2290     }
  2280         -  assert( zCsr==(zNewRecord+nByte) );
         2291  +  assert( i==nByte );
  2281   2292   
  2282   2293     /* Pop entries off the stack if required. Push the new record on. */
  2283   2294     if( !leaveOnStack ){
  2284   2295       popStack(&pTos, nField+addRowid);
  2285   2296     }
  2286   2297     pTos++;
  2287   2298     pTos->n = nByte;
................................................................................
  2292   2303       pTos->flags = MEM_Blob | MEM_Short;
  2293   2304     }else{
  2294   2305       assert( zNewRecord!=(unsigned char *)zTemp );
  2295   2306       pTos->z = (char*)zNewRecord;
  2296   2307       pTos->flags = MEM_Blob | MEM_Dyn;
  2297   2308       pTos->xDel = 0;
  2298   2309     }
         2310  +  if( nZero ){
         2311  +    pTos->u.i = nZero;
         2312  +    pTos->flags |= MEM_Zero;
         2313  +  }
  2299   2314     pTos->enc = SQLITE_UTF8;  /* In case the blob is ever converted to text */
  2300   2315   
  2301   2316     /* If a NULL was encountered and jumpIfNull is non-zero, take the jump. */
  2302   2317     if( jumpIfNull && containsNull ){
  2303   2318       pc = jumpIfNull - 1;
  2304   2319     }
  2305   2320     break;
................................................................................
  4993   5008           }else if( (pTos[i].flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){
  4994   5009             fprintf(p->trace, " si:%lld", pTos[i].u.i);
  4995   5010           }else if( pTos[i].flags & MEM_Int ){
  4996   5011             fprintf(p->trace, " i:%lld", pTos[i].u.i);
  4997   5012           }else if( pTos[i].flags & MEM_Real ){
  4998   5013             fprintf(p->trace, " r:%g", pTos[i].r);
  4999   5014           }else{
  5000         -          char zBuf[100];
         5015  +          char zBuf[200];
  5001   5016             sqlite3VdbeMemPrettyPrint(&pTos[i], zBuf);
  5002   5017             fprintf(p->trace, " ");
  5003   5018             fprintf(p->trace, "%s", zBuf);
  5004   5019           }
  5005   5020         }
  5006   5021         if( rc!=0 ) fprintf(p->trace," rc=%d",rc);
  5007   5022         fprintf(p->trace,"\n");

Changes to src/vdbeInt.h.

   129    129       i64 i;              /* Integer value. Or FuncDef* when flags==MEM_Agg */
   130    130       FuncDef *pDef;      /* Used only when flags==MEM_Agg */
   131    131     } u;
   132    132     double r;           /* Real value */
   133    133     char *z;            /* String or BLOB value */
   134    134     int n;              /* Number of characters in string value, including '\0' */
   135    135     u16 flags;          /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
   136         -  u8  type;           /* One of MEM_Null, MEM_Str, etc. */
   137         -  u8  enc;            /* TEXT_Utf8, TEXT_Utf16le, or TEXT_Utf16be */
          136  +  u8  type;           /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */
          137  +  u8  enc;            /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */
   138    138     void (*xDel)(void *);  /* If not null, call this function to delete Mem.z */
   139    139     char zShort[NBFS];  /* Space for short strings */
   140    140   };
   141    141   typedef struct Mem Mem;
   142    142   
   143    143   /* One or more of the following flags are set to indicate the validOK
   144    144   ** representations of the value stored in the Mem struct.
................................................................................
   360    360   void sqlite3VdbePrintOp(FILE*, int, Op*);
   361    361   #endif
   362    362   #ifdef SQLITE_DEBUG
   363    363   void sqlite3VdbePrintSql(Vdbe*);
   364    364   #endif
   365    365   int sqlite3VdbeSerialTypeLen(u32);
   366    366   u32 sqlite3VdbeSerialType(Mem*, int);
   367         -int sqlite3VdbeSerialPut(unsigned char*, Mem*, int);
          367  +int sqlite3VdbeSerialPut(unsigned char*, int, Mem*, int);
   368    368   int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
   369    369   void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);
   370    370   
   371    371   int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
   372    372   int sqlite3VdbeIdxKeyCompare(Cursor*, int , const unsigned char*, int*);
   373    373   int sqlite3VdbeIdxRowid(BtCursor *, i64 *);
   374    374   int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);

Changes to src/vdbeaux.c.

  1718   1718   */
  1719   1719   
  1720   1720   /*
  1721   1721   ** Return the serial-type for the value stored in pMem.
  1722   1722   */
  1723   1723   u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
  1724   1724     int flags = pMem->flags;
         1725  +  int n;
  1725   1726   
  1726   1727     if( flags&MEM_Null ){
  1727   1728       return 0;
  1728   1729     }
  1729   1730     if( flags&MEM_Int ){
  1730   1731       /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */
  1731   1732   #   define MAX_6BYTE ((((i64)0x00001000)<<32)-1)
................................................................................
  1741   1742       if( u<=2147483647 ) return 4;
  1742   1743       if( u<=MAX_6BYTE ) return 5;
  1743   1744       return 6;
  1744   1745     }
  1745   1746     if( flags&MEM_Real ){
  1746   1747       return 7;
  1747   1748     }
  1748         -  if( flags&MEM_Str ){
  1749         -    int n = pMem->n;
  1750         -    assert( n>=0 );
  1751         -    return ((n*2) + 13);
         1749  +  assert( flags&(MEM_Str|MEM_Blob) );
         1750  +  n = pMem->n;
         1751  +  if( flags & MEM_Zero ){
         1752  +    n += pMem->u.i;
  1752   1753     }
  1753         -  assert( (flags & MEM_Blob)!=0 );
  1754         -  return (pMem->n*2 + 12);
         1754  +  assert( n>=0 );
         1755  +  return ((n*2) + 12 + ((flags&MEM_Str)!=0));
  1755   1756   }
  1756   1757   
  1757   1758   /*
  1758   1759   ** Return the length of the data corresponding to the supplied serial-type.
  1759   1760   */
  1760   1761   int sqlite3VdbeSerialTypeLen(u32 serial_type){
  1761   1762     if( serial_type>=12 ){
................................................................................
  1766   1767     }
  1767   1768   }
  1768   1769   
  1769   1770   /*
  1770   1771   ** Write the serialized data blob for the value stored in pMem into 
  1771   1772   ** buf. It is assumed that the caller has allocated sufficient space.
  1772   1773   ** Return the number of bytes written.
         1774  +**
         1775  +** nBuf is the amount of space left in buf[].  nBuf must always be
         1776  +** large enough to hold the entire field.  Except, if the field is
         1777  +** a blob with a zero-filled tail, then buf[] might be just the right
         1778  +** size to hold everything except for the zero-filled tail.  If buf[]
         1779  +** is only big enough to hold the non-zero prefix, then only write that
         1780  +** prefix into buf[].  But if buf[] is large enough to hold both the
         1781  +** prefix and the tail then write the prefix and set the tail to all
         1782  +** zeros.
         1783  +**
         1784  +** Return the number of bytes actually written into buf[].  The number
         1785  +** of bytes in the zero-filled tail is included in the return value only
         1786  +** if those bytes were zeroed in buf[].
  1773   1787   */ 
  1774         -int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem, int file_format){
         1788  +int sqlite3VdbeSerialPut(u8 *buf, int nBuf, Mem *pMem, int file_format){
  1775   1789     u32 serial_type = sqlite3VdbeSerialType(pMem, file_format);
  1776   1790     int len;
  1777   1791   
  1778   1792     /* Integer and Real */
  1779   1793     if( serial_type<=7 && serial_type>0 ){
  1780   1794       u64 v;
  1781   1795       int i;
................................................................................
  1782   1796       if( serial_type==7 ){
  1783   1797         assert( sizeof(v)==sizeof(pMem->r) );
  1784   1798         memcpy(&v, &pMem->r, sizeof(v));
  1785   1799       }else{
  1786   1800         v = pMem->u.i;
  1787   1801       }
  1788   1802       len = i = sqlite3VdbeSerialTypeLen(serial_type);
         1803  +    assert( len<=nBuf );
  1789   1804       while( i-- ){
  1790   1805         buf[i] = (v&0xFF);
  1791   1806         v >>= 8;
  1792   1807       }
  1793   1808       return len;
  1794   1809     }
  1795   1810   
  1796   1811     /* String or blob */
  1797   1812     if( serial_type>=12 ){
  1798         -    len = sqlite3VdbeSerialTypeLen(serial_type);
         1813  +    assert( pMem->n + ((pMem->flags & MEM_Zero)?pMem->u.i:0)
         1814  +             == sqlite3VdbeSerialTypeLen(serial_type) );
         1815  +    assert( pMem->n<=nBuf );
         1816  +    len = pMem->n;
  1799   1817       memcpy(buf, pMem->z, len);
         1818  +    if( pMem->flags & MEM_Zero ){
         1819  +      len += pMem->u.i;
         1820  +      if( len>nBuf ){
         1821  +        len = nBuf;
         1822  +      }
         1823  +      memset(&buf[pMem->n], 0, len-pMem->n);
         1824  +    }
  1800   1825       return len;
  1801   1826     }
  1802   1827   
  1803   1828     /* NULL or constants 0 or 1 */
  1804   1829     return 0;
  1805   1830   }
  1806   1831   

Changes to src/vdbemem.c.

    80     80     z[n+1] = 0;
    81     81     pMem->z = (char*)z;
    82     82     pMem->flags &= ~(MEM_Ephem|MEM_Static|MEM_Short);
    83     83     return SQLITE_OK;
    84     84   }
    85     85   
    86     86   /*
    87         -** If the given Mem* is a zero-filled blob, turn it into an ordinary
           87  +** If the given Mem* has a zero-filled tail, turn it into an ordinary
    88     88   ** blob stored in dynamically allocated space.
    89     89   */
    90     90   int sqlite3VdbeMemExpandBlob(Mem *pMem){
    91     91     if( pMem->flags & MEM_Zero ){
    92     92       char *pNew;
    93     93       assert( (pMem->flags & MEM_Blob)!=0 );
    94         -    pNew = sqliteMalloc(pMem->n+pMem->u.i+1);
           94  +    pNew = sqliteMalloc(pMem->n+pMem->u.i);
    95     95       if( pNew==0 ){ 
    96     96         return SQLITE_NOMEM;
    97     97       }
    98     98       memcpy(pNew, pMem->z, pMem->n);
    99         -    memset(&pNew[pMem->n], 0, pMem->u.i+1);
           99  +    memset(&pNew[pMem->n], 0, pMem->u.i);
   100    100       sqlite3VdbeMemRelease(pMem);
   101    101       pMem->z = pNew;
          102  +    pMem->n += pMem->u.i;
   102    103       pMem->u.i = 0;
   103    104       pMem->flags &= MEM_Zero|MEM_Static|MEM_Ephem|MEM_Short;
   104    105       pMem->flags |= MEM_Term|MEM_Dyn;
   105    106     }
   106    107     return SQLITE_OK;
   107    108   }
   108    109   
................................................................................
   376    377   
   377    378   /*
   378    379   ** Delete any previous value and set the value to be a BLOB of length
   379    380   ** n containing all zeros.
   380    381   */
   381    382   void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){
   382    383     sqlite3VdbeMemRelease(pMem);
   383         -  pMem->flags = MEM_Blob|MEM_Zero;
          384  +  pMem->flags = MEM_Blob|MEM_Zero|MEM_Short;
   384    385     pMem->type = SQLITE_BLOB;
   385    386     pMem->n = 0;
   386    387     pMem->u.i = n;
          388  +  pMem->z = pMem->zShort;
   387    389   }
   388    390   
   389    391   /*
   390    392   ** Delete any previous value and set the value stored in *pMem to val,
   391    393   ** manifest type INTEGER.
   392    394   */
   393    395   void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
................................................................................
   738    740   void sqlite3VdbeMemSanity(Mem *pMem){
   739    741     int flags = pMem->flags;
   740    742     assert( flags!=0 );  /* Must define some type */
   741    743     if( flags & (MEM_Str|MEM_Blob) ){
   742    744       int x = flags & (MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short);
   743    745       assert( x!=0 );            /* Strings must define a string subtype */
   744    746       assert( (x & (x-1))==0 );  /* Only one string subtype can be defined */
   745         -    assert( pMem->z!=0 || x==MEM_Zero );      /* Strings must have a value */
          747  +    assert( pMem->z!=0 );      /* Strings must have a value */
   746    748       /* Mem.z points to Mem.zShort iff the subtype is MEM_Short */
   747    749       assert( (x & MEM_Short)==0 || pMem->z==pMem->zShort );
   748    750       assert( (x & MEM_Short)!=0 || pMem->z!=pMem->zShort );
   749    751       /* No destructor unless there is MEM_Dyn */
   750    752       assert( pMem->xDel==0 || (pMem->flags & MEM_Dyn)!=0 );
   751    753   
   752    754       if( (flags & MEM_Str) ){

Added test/zeroblob.test.

            1  +# 2007 May 02
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +# This file implements regression tests for SQLite library.  The
           12  +# focus of this file is testing of the zero-filled blob functionality
           13  +# including the sqlite3_bind_zeroblob(), sqlite3_result_zeroblob(),
           14  +# and the built-in zeroblob() SQL function.
           15  +#
           16  +# $Id: zeroblob.test,v 1.1 2007/05/02 13:30:27 drh Exp $
           17  +
           18  +set testdir [file dirname $argv0]
           19  +source $testdir/tester.tcl
           20  +
           21  +# Create the database
           22  +#
           23  +do_test zeroblob-1.1 {
           24  +  execsql {
           25  +    CREATE TABLE t1(a,b,c,d);
           26  +    INSERT INTO t1 VALUES(1,2,3,zeroblob(10000));
           27  +    SELECT count(*) FROM t1;
           28  +  }
           29  +} {1}
           30  +do_test zeroblob-1.2 {
           31  +  execsql {
           32  +    SELECT length(d) FROM t1
           33  +  }
           34  +} {10000}
           35  +do_test zeroblob-1.3 {
           36  +  execsql {
           37  +    INSERT INTO t1 VALUES(2,3,zeroblob(10000),4);
           38  +    SELECT count(*) FROM t1;
           39  +  }
           40  +} {2}
           41  +do_test zeroblob-1.4 {
           42  +  execsql {
           43  +    SELECT length(c), length(d) FROM t1
           44  +  }
           45  +} {1 10000 10000 1}
           46  +do_test zeroblob-1.5 {
           47  +  execsql {
           48  +    INSERT INTO t1 VALUES(3,4,zeroblob(10000),zeroblob(10000));
           49  +    SELECT count(*) FROM t1;
           50  +  }
           51  +} {3}
           52  +do_test zeroblob-1.6 {
           53  +  execsql {
           54  +    SELECT length(c), length(d) FROM t1
           55  +  }
           56  +} {1 10000 10000 1 10000 10000}
           57  +
           58  +finish_test