mirror of
https://github.com/sqlite/sqlite.git
synced 2025-10-24 09:53:10 +03:00
Add support for zero-blobs to the OP_MakeRecord opcode.
First test cases of zeroblob functionality. (CVS 3897) FossilOrigin-Name: e6d560ddeeb48fb0cbd9f5a10612280b055baef7
This commit is contained in:
59
src/vdbe.c
59
src/vdbe.c
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 );
|
||||
|
||||
Reference in New Issue
Block a user