Begin adding the zeroblob API to support incremental blob i/o. (CVS 3894)
FossilOrigin-Name: 7a01836dde45098796693bc6cb6045c4059adf1a
This commit is contained in:
+18
-12
@@ -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);
|
||||
|
||||
+3
-2
@@ -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);
|
||||
|
||||
+3
-1
@@ -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
|
||||
|
||||
+39
-1
@@ -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 },
|
||||
|
||||
+12
-6
@@ -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);
|
||||
|
||||
+9
-3
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
+51
-7
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user