/ 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 Unified Diffs Ignore Whitespace Patch

Changes to src/vdbe.c.

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
...
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322



323
324
325
326
327
328
329
....
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194

2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206


2207
2208
2209
2210
2211
2212
2213
....
2225
2226
2227
2228
2229
2230
2231







2232
2233

2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244

2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275

2276
2277
2278
2279
2280

2281
2282
2283
2284
2285
2286
2287
....
2292
2293
2294
2295
2296
2297
2298




2299
2300
2301
2302
2303
2304
2305
....
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** 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 $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
................................................................................
    }else{
      c = 's';
    }

    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));
    }
    for(i=0; i<16 && i<pMem->n; i++){
      char z = pMem->z[i];
      if( z<32 || z>126 ) *zCsr++ = '.';
      else *zCsr++ = z;
    }

    zCsr += sprintf(zCsr, "]");



    *zCsr = '\0';
  }else if( f & MEM_Str ){
    int j, k;
    zBuf[0] = ' ';
    if( f & MEM_Dyn ){
      zBuf[1] = 'z';
      assert( (f & (MEM_Static|MEM_Ephem))==0 );
................................................................................
  ** the top of the stack.
  **
  ** Each type field is a varint representing the serial type of the 
  ** corresponding data element (see sqlite3VdbeSerialType()). The
  ** 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;
  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 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;

  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 */



  leaveOnStack = ((pOp->p1<0)?1:0);
  nField = pOp->p1 * (leaveOnStack?-1:1);
  jumpIfNull = pOp->p2;
  addRowid = pOp->opcode==OP_MakeIdxRec;
  zAffinity = pOp->p3;

................................................................................
    }
    if( pRec->flags&MEM_Null ){
      containsNull = 1;
    }
    serial_type = sqlite3VdbeSerialType(pRec, file_format);
    nData += sqlite3VdbeSerialTypeLen(serial_type);
    nHdr += sqlite3VarintLen(serial_type);







  }


  /* If we have to append a varint rowid to this record, set 'rowid'
  ** to the value of the rowid and increase nByte by the amount of space
  ** required to store it and the 0x00 seperator byte.
  */
  if( addRowid ){
    pRowid = &pTos[0-nField];
    assert( pRowid>=p->aStack );
    sqlite3VdbeMemIntegerify(pRowid);
    serial_type = sqlite3VdbeSerialType(pRowid, 0);
    nData += sqlite3VdbeSerialTypeLen(serial_type);
    nHdr += sqlite3VarintLen(serial_type);

  }

  /* Add the initial header varint and total the size */
  nHdr += nVarint = sqlite3VarintLen(nHdr);
  if( nVarint<sqlite3VarintLen(nHdr) ){
    nHdr++;
  }
  nByte = nHdr+nData;

  /* Allocate space for the new record. */
  if( nByte>sizeof(zTemp) ){
    zNewRecord = sqliteMallocRaw(nByte);
    if( !zNewRecord ){
      goto no_mem;
    }
  }else{
    zNewRecord = (u8*)zTemp;
  }

  /* Write the record */
  zCsr = zNewRecord;
  zCsr += sqlite3PutVarint(zCsr, nHdr);
  for(pRec=pData0; pRec<=pTos; pRec++){
    serial_type = sqlite3VdbeSerialType(pRec, file_format);
    zCsr += sqlite3PutVarint(zCsr, serial_type);      /* serial type */
  }
  if( addRowid ){
    zCsr += sqlite3PutVarint(zCsr, sqlite3VdbeSerialType(pRowid, 0));
  }
  for(pRec=pData0; pRec<=pTos; pRec++){
    zCsr += sqlite3VdbeSerialPut(zCsr, pRec, file_format);  /* serial data */

  }
  if( addRowid ){
    zCsr += sqlite3VdbeSerialPut(zCsr, pRowid, 0);
  }
  assert( zCsr==(zNewRecord+nByte) );


  /* Pop entries off the stack if required. Push the new record on. */
  if( !leaveOnStack ){
    popStack(&pTos, nField+addRowid);
  }
  pTos++;
  pTos->n = nByte;
................................................................................
    pTos->flags = MEM_Blob | MEM_Short;
  }else{
    assert( zNewRecord!=(unsigned char *)zTemp );
    pTos->z = (char*)zNewRecord;
    pTos->flags = MEM_Blob | MEM_Dyn;
    pTos->xDel = 0;
  }




  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. */
  if( jumpIfNull && containsNull ){
    pc = jumpIfNull - 1;
  }
  break;
................................................................................
        }else if( (pTos[i].flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){
          fprintf(p->trace, " si:%lld", pTos[i].u.i);
        }else if( pTos[i].flags & MEM_Int ){
          fprintf(p->trace, " i:%lld", pTos[i].u.i);
        }else if( pTos[i].flags & MEM_Real ){
          fprintf(p->trace, " r:%g", pTos[i].r);
        }else{
          char zBuf[100];
          sqlite3VdbeMemPrettyPrint(&pTos[i], zBuf);
          fprintf(p->trace, " ");
          fprintf(p->trace, "%s", zBuf);
        }
      }
      if( rc!=0 ) fprintf(p->trace," rc=%d",rc);
      fprintf(p->trace,"\n");







|







 







|








>
>
>







 







|
<
|
|


|
>



<
|
<






>
>







 







>
>
>
>
>
>
>
|
|
>
|

|








>







|












<
|


|


|

|
<
>


|

<
>







 







>
>
>
>







 







|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
...
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
....
2184
2185
2186
2187
2188
2189
2190
2191

2192
2193
2194
2195
2196
2197
2198
2199
2200

2201

2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
....
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276

2277
2278
2279
2280
2281
2282
2283
2284
2285

2286
2287
2288
2289
2290

2291
2292
2293
2294
2295
2296
2297
2298
....
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
....
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** 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.604 2007/05/02 13:30:27 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
................................................................................
    }else{
      c = 's';
    }

    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));
    }
    for(i=0; i<16 && i<pMem->n; i++){
      char z = pMem->z[i];
      if( z<32 || z>126 ) *zCsr++ = '.';
      else *zCsr++ = z;
    }

    zCsr += sprintf(zCsr, "]");
    if( f & MEM_Zero ){
      zCsr += sprintf(zCsr,"+%lldz",pMem->u.i);
    }
    *zCsr = '\0';
  }else if( f & MEM_Str ){
    int j, k;
    zBuf[0] = ' ';
    if( f & MEM_Dyn ){
      zBuf[1] = 'z';
      assert( (f & (MEM_Static|MEM_Ephem))==0 );
................................................................................
  ** the top of the stack.
  **
  ** Each type field is a varint representing the serial type of the 
  ** corresponding data element (see sqlite3VdbeSerialType()). The
  ** hdr-size field is also a varint which is the offset from the beginning
  ** of the record to data0.
  */
  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;         /* 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 */

  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);
  jumpIfNull = pOp->p2;
  addRowid = pOp->opcode==OP_MakeIdxRec;
  zAffinity = pOp->p3;

................................................................................
    }
    if( pRec->flags&MEM_Null ){
      containsNull = 1;
    }
    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 pRowid
  ** to the value of the rowid and increase nByte by the amount of space
  ** required to store it.
  */
  if( addRowid ){
    pRowid = &pTos[0-nField];
    assert( pRowid>=p->aStack );
    sqlite3VdbeMemIntegerify(pRowid);
    serial_type = sqlite3VdbeSerialType(pRowid, 0);
    nData += sqlite3VdbeSerialTypeLen(serial_type);
    nHdr += sqlite3VarintLen(serial_type);
    nZero = 0;
  }

  /* Add the initial header varint and total the size */
  nHdr += nVarint = sqlite3VarintLen(nHdr);
  if( nVarint<sqlite3VarintLen(nHdr) ){
    nHdr++;
  }
  nByte = nHdr+nData-nZero;

  /* Allocate space for the new record. */
  if( nByte>sizeof(zTemp) ){
    zNewRecord = sqliteMallocRaw(nByte);
    if( !zNewRecord ){
      goto no_mem;
    }
  }else{
    zNewRecord = (u8*)zTemp;
  }

  /* Write the record */

  i = sqlite3PutVarint(zNewRecord, nHdr);
  for(pRec=pData0; pRec<=pTos; pRec++){
    serial_type = sqlite3VdbeSerialType(pRec, file_format);
    i += sqlite3PutVarint(&zNewRecord[i], serial_type);      /* serial type */
  }
  if( addRowid ){
    i += sqlite3PutVarint(&zNewRecord[i], sqlite3VdbeSerialType(pRowid, 0));
  }
  for(pRec=pData0; pRec<=pTos; pRec++){  /* serial data */

    i += sqlite3VdbeSerialPut(&zNewRecord[i], nByte-i, pRec, file_format);
  }
  if( addRowid ){
    i += sqlite3VdbeSerialPut(&zNewRecord[i], nByte-i, pRowid, 0);
  }

  assert( i==nByte );

  /* Pop entries off the stack if required. Push the new record on. */
  if( !leaveOnStack ){
    popStack(&pTos, nField+addRowid);
  }
  pTos++;
  pTos->n = nByte;
................................................................................
    pTos->flags = MEM_Blob | MEM_Short;
  }else{
    assert( zNewRecord!=(unsigned char *)zTemp );
    pTos->z = (char*)zNewRecord;
    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. */
  if( jumpIfNull && containsNull ){
    pc = jumpIfNull - 1;
  }
  break;
................................................................................
        }else if( (pTos[i].flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){
          fprintf(p->trace, " si:%lld", pTos[i].u.i);
        }else if( pTos[i].flags & MEM_Int ){
          fprintf(p->trace, " i:%lld", pTos[i].u.i);
        }else if( pTos[i].flags & MEM_Real ){
          fprintf(p->trace, " r:%g", pTos[i].r);
        }else{
          char zBuf[200];
          sqlite3VdbeMemPrettyPrint(&pTos[i], zBuf);
          fprintf(p->trace, " ");
          fprintf(p->trace, "%s", zBuf);
        }
      }
      if( rc!=0 ) fprintf(p->trace," rc=%d",rc);
      fprintf(p->trace,"\n");

Changes to src/vdbeInt.h.

129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
    i64 i;              /* Integer value. Or FuncDef* when flags==MEM_Agg */
    FuncDef *pDef;      /* Used only when flags==MEM_Agg */
  } u;
  double r;           /* Real value */
  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 */
  void (*xDel)(void *);  /* If not null, call this function to delete Mem.z */
  char zShort[NBFS];  /* Space for short strings */
};
typedef struct Mem Mem;

/* One or more of the following flags are set to indicate the validOK
** representations of the value stored in the Mem struct.
................................................................................
void sqlite3VdbePrintOp(FILE*, int, Op*);
#endif
#ifdef SQLITE_DEBUG
void sqlite3VdbePrintSql(Vdbe*);
#endif
int sqlite3VdbeSerialTypeLen(u32);
u32 sqlite3VdbeSerialType(Mem*, int);
int sqlite3VdbeSerialPut(unsigned char*, Mem*, int);
int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);

int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
int sqlite3VdbeIdxKeyCompare(Cursor*, int , const unsigned char*, int*);
int sqlite3VdbeIdxRowid(BtCursor *, i64 *);
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);







|
|







 







|







129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
    i64 i;              /* Integer value. Or FuncDef* when flags==MEM_Agg */
    FuncDef *pDef;      /* Used only when flags==MEM_Agg */
  } u;
  double r;           /* Real value */
  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 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 */
};
typedef struct Mem Mem;

/* One or more of the following flags are set to indicate the validOK
** representations of the value stored in the Mem struct.
................................................................................
void sqlite3VdbePrintOp(FILE*, int, Op*);
#endif
#ifdef SQLITE_DEBUG
void sqlite3VdbePrintSql(Vdbe*);
#endif
int sqlite3VdbeSerialTypeLen(u32);
u32 sqlite3VdbeSerialType(Mem*, int);
int sqlite3VdbeSerialPut(unsigned char*, int, Mem*, int);
int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*);
void sqlite3VdbeDeleteAuxData(VdbeFunc*, int);

int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *);
int sqlite3VdbeIdxKeyCompare(Cursor*, int , const unsigned char*, int*);
int sqlite3VdbeIdxRowid(BtCursor *, i64 *);
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);

Changes to src/vdbeaux.c.

1718
1719
1720
1721
1722
1723
1724

1725
1726
1727
1728
1729
1730
1731
....
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
....
1766
1767
1768
1769
1770
1771
1772













1773
1774
1775
1776
1777
1778
1779
1780
1781
....
1782
1783
1784
1785
1786
1787
1788

1789
1790
1791
1792
1793
1794
1795
1796
1797

1798


1799







1800
1801
1802
1803
1804
1805
1806
*/

/*
** Return the serial-type for the value stored in pMem.
*/
u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
  int flags = pMem->flags;


  if( flags&MEM_Null ){
    return 0;
  }
  if( flags&MEM_Int ){
    /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */
#   define MAX_6BYTE ((((i64)0x00001000)<<32)-1)
................................................................................
    if( u<=2147483647 ) return 4;
    if( u<=MAX_6BYTE ) return 5;
    return 6;
  }
  if( flags&MEM_Real ){
    return 7;
  }
  if( flags&MEM_Str ){
    int n = pMem->n;
    assert( n>=0 );
    return ((n*2) + 13);
  }
  assert( (flags & MEM_Blob)!=0 );
  return (pMem->n*2 + 12);
}

/*
** Return the length of the data corresponding to the supplied serial-type.
*/
int sqlite3VdbeSerialTypeLen(u32 serial_type){
  if( serial_type>=12 ){
................................................................................
  }
}

/*
** 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.













*/ 
int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem, int file_format){
  u32 serial_type = sqlite3VdbeSerialType(pMem, file_format);
  int len;

  /* Integer and Real */
  if( serial_type<=7 && serial_type>0 ){
    u64 v;
    int i;
................................................................................
    if( serial_type==7 ){
      assert( sizeof(v)==sizeof(pMem->r) );
      memcpy(&v, &pMem->r, sizeof(v));
    }else{
      v = pMem->u.i;
    }
    len = i = sqlite3VdbeSerialTypeLen(serial_type);

    while( i-- ){
      buf[i] = (v&0xFF);
      v >>= 8;
    }
    return len;
  }

  /* String or blob */
  if( serial_type>=12 ){

    len = sqlite3VdbeSerialTypeLen(serial_type);


    memcpy(buf, pMem->z, len);







    return len;
  }

  /* NULL or constants 0 or 1 */
  return 0;
}








>







 







|
|
|
|

|
|







 







>
>
>
>
>
>
>
>
>
>
>
>
>

|







 







>









>
|
>
>

>
>
>
>
>
>
>







1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
....
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
....
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
....
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
*/

/*
** Return the serial-type for the value stored in pMem.
*/
u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
  int flags = pMem->flags;
  int n;

  if( flags&MEM_Null ){
    return 0;
  }
  if( flags&MEM_Int ){
    /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */
#   define MAX_6BYTE ((((i64)0x00001000)<<32)-1)
................................................................................
    if( u<=2147483647 ) return 4;
    if( u<=MAX_6BYTE ) return 5;
    return 6;
  }
  if( flags&MEM_Real ){
    return 7;
  }
  assert( flags&(MEM_Str|MEM_Blob) );
  n = pMem->n;
  if( flags & MEM_Zero ){
    n += pMem->u.i;
  }
  assert( n>=0 );
  return ((n*2) + 12 + ((flags&MEM_Str)!=0));
}

/*
** Return the length of the data corresponding to the supplied serial-type.
*/
int sqlite3VdbeSerialTypeLen(u32 serial_type){
  if( serial_type>=12 ){
................................................................................
  }
}

/*
** 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(u8 *buf, int nBuf, Mem *pMem, int file_format){
  u32 serial_type = sqlite3VdbeSerialType(pMem, file_format);
  int len;

  /* Integer and Real */
  if( serial_type<=7 && serial_type>0 ){
    u64 v;
    int i;
................................................................................
    if( serial_type==7 ){
      assert( sizeof(v)==sizeof(pMem->r) );
      memcpy(&v, &pMem->r, sizeof(v));
    }else{
      v = pMem->u.i;
    }
    len = i = sqlite3VdbeSerialTypeLen(serial_type);
    assert( len<=nBuf );
    while( i-- ){
      buf[i] = (v&0xFF);
      v >>= 8;
    }
    return len;
  }

  /* String or blob */
  if( serial_type>=12 ){
    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;
  }

  /* NULL or constants 0 or 1 */
  return 0;
}

Changes to src/vdbemem.c.

80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

102
103
104
105
106
107
108
...
376
377
378
379
380
381
382
383
384
385
386

387
388
389
390
391
392
393
...
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
  z[n+1] = 0;
  pMem->z = (char*)z;
  pMem->flags &= ~(MEM_Ephem|MEM_Static|MEM_Short);
  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;
}

................................................................................

/*
** 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.
*/
void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
................................................................................
void sqlite3VdbeMemSanity(Mem *pMem){
  int flags = pMem->flags;
  assert( flags!=0 );  /* Must define some type */
  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 || x==MEM_Zero );      /* 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 );
    /* No destructor unless there is MEM_Dyn */
    assert( pMem->xDel==0 || (pMem->flags & MEM_Dyn)!=0 );

    if( (flags & MEM_Str) ){







|






|




|


>







 







|



>







 







|







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
...
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
...
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
  z[n+1] = 0;
  pMem->z = (char*)z;
  pMem->flags &= ~(MEM_Ephem|MEM_Static|MEM_Short);
  return SQLITE_OK;
}

/*
** 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);
    if( pNew==0 ){ 
      return SQLITE_NOMEM;
    }
    memcpy(pNew, pMem->z, pMem->n);
    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;
  }
  return SQLITE_OK;
}

................................................................................

/*
** 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|MEM_Short;
  pMem->type = SQLITE_BLOB;
  pMem->n = 0;
  pMem->u.i = n;
  pMem->z = pMem->zShort;
}

/*
** Delete any previous value and set the value stored in *pMem to val,
** manifest type INTEGER.
*/
void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
................................................................................
void sqlite3VdbeMemSanity(Mem *pMem){
  int flags = pMem->flags;
  assert( flags!=0 );  /* Must define some type */
  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 */
    /* 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 );
    /* No destructor unless there is MEM_Dyn */
    assert( pMem->xDel==0 || (pMem->flags & MEM_Dyn)!=0 );

    if( (flags & MEM_Str) ){

Added test/zeroblob.test.





















































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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