Index: src/sqlite.h.in ================================================================== --- src/sqlite.h.in +++ src/sqlite.h.in @@ -4058,18 +4058,22 @@ ** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()]. */ int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64, void(*)(void*)); +int sqlite3_bind_blob64dx(sqlite3_stmt*, int, const void*, sqlite3_uint64, + void(*)(void*,void*),void*); int sqlite3_bind_double(sqlite3_stmt*, int, double); int sqlite3_bind_int(sqlite3_stmt*, int, int); int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); int sqlite3_bind_null(sqlite3_stmt*, int); int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*)); int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64, void(*)(void*), unsigned char encoding); +int sqlite3_bind_text64dx(sqlite3_stmt*, int, const char*, sqlite3_uint64, + void(*)(void*,void*),void*,unsigned char encoding); int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*,void(*)(void*)); int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); int sqlite3_bind_zeroblob64(sqlite3_stmt*, int, sqlite3_uint64); @@ -5334,10 +5338,12 @@ ** the [sqlite3_context] pointer, the results are undefined. */ void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); void sqlite3_result_blob64(sqlite3_context*,const void*, sqlite3_uint64,void(*)(void*)); +void sqlite3_result_blob64dx(sqlite3_context*,const void*, + sqlite3_uint64,void(*)(void*,void*),void*); void sqlite3_result_double(sqlite3_context*, double); void sqlite3_result_error(sqlite3_context*, const char*, int); void sqlite3_result_error16(sqlite3_context*, const void*, int); void sqlite3_result_error_toobig(sqlite3_context*); void sqlite3_result_error_nomem(sqlite3_context*); @@ -5346,10 +5352,12 @@ void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); void sqlite3_result_null(sqlite3_context*); void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64, void(*)(void*), unsigned char encoding); +void sqlite3_result_text64dx(sqlite3_context*, const char*,sqlite3_uint64, + void(*)(void*,void*),void*,unsigned char encoding); 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_pointer(sqlite3_context*, void*,const char*,void(*)(void*)); Index: src/vdbe.c ================================================================== --- src/vdbe.c +++ src/vdbe.c @@ -6090,10 +6090,11 @@ sqlite3VdbeMemRelease(pRt); pRt->flags = MEM_Blob|MEM_Dyn; pRt->z = (char*)pFrame; pRt->n = nByte; pRt->xDel = sqlite3VdbeFrameMemDel; + pRt->pDelPtr = 0; pFrame->v = p; pFrame->nChildMem = nMem; pFrame->nChildCsr = pProgram->nCsr; pFrame->pc = (int)(pOp - aOp); Index: src/vdbeInt.h ================================================================== --- src/vdbeInt.h +++ src/vdbeInt.h @@ -213,10 +213,11 @@ char *zMalloc; /* Space to hold MEM_Str or MEM_Blob if szMalloc>0 */ int szMalloc; /* Size of the zMalloc allocation */ u32 uTemp; /* Transient storage for serial_type in OP_MakeRecord */ sqlite3 *db; /* The associated database connection */ void (*xDel)(void*);/* Destructor for Mem.z - only valid if MEM_Dyn */ + void *pDelPtr; /* Context information for the delete */ #ifdef SQLITE_DEBUG Mem *pScopyFrom; /* This Mem is a shallow copy of pScopyFrom */ u16 mScopyFlags; /* flags value immediately after the shallow copy */ #endif }; Index: src/vdbeapi.c ================================================================== --- src/vdbeapi.c +++ src/vdbeapi.c @@ -319,26 +319,32 @@ static void setResultStrOrError( sqlite3_context *pCtx, /* Function context */ const char *z, /* String pointer */ int n, /* Bytes in string, or negative */ u8 enc, /* Encoding of z. 0 for BLOBs */ - void (*xDel)(void*) /* Destructor function */ + void (*xDel)(void*), /* Destructor function */ + void *pDelPtr /* Context for the destructor */ ){ if( sqlite3VdbeMemSetStr(pCtx->pOut, z, n, enc, xDel)==SQLITE_TOOBIG ){ sqlite3_result_error_toobig(pCtx); + }else{ + pCtx->pOut->pDelPtr = pDelPtr; } } static int invokeValueDestructor( const void *p, /* Value to destroy */ void (*xDel)(void*), /* The destructor */ + void *pDelPtr, /* Destructor context */ sqlite3_context *pCtx /* Set a SQLITE_TOOBIG error if no NULL */ ){ assert( xDel!=SQLITE_DYNAMIC ); if( xDel==0 ){ /* noop */ }else if( xDel==SQLITE_TRANSIENT ){ /* noop */ + }else if( pDelPtr ){ + (*(void(*)(void*,void*))xDel)(pDelPtr,(void*)p); }else{ xDel((void*)p); } if( pCtx ) sqlite3_result_error_toobig(pCtx); return SQLITE_TOOBIG; @@ -349,11 +355,11 @@ int n, void (*xDel)(void *) ){ assert( n>=0 ); assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); - setResultStrOrError(pCtx, z, n, 0, xDel); + setResultStrOrError(pCtx, z, n, 0, xDel, 0); } void sqlite3_result_blob64( sqlite3_context *pCtx, const void *z, sqlite3_uint64 n, @@ -360,13 +366,29 @@ void (*xDel)(void *) ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); assert( xDel!=SQLITE_DYNAMIC ); if( n>0x7fffffff ){ - (void)invokeValueDestructor(z, xDel, pCtx); + (void)invokeValueDestructor(z, xDel, 0, pCtx); + }else{ + setResultStrOrError(pCtx, z, (int)n, 0, xDel, 0); + } +} +void sqlite3_result_blob64dx( + sqlite3_context *pCtx, + const void *z, + sqlite3_uint64 n, + void (*xDel)(void*,void*), + void *pDelPtr +){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + assert( ((void(*)(void*))xDel)!=SQLITE_DYNAMIC ); + if( n>0x7fffffff ){ + (void)invokeValueDestructor(z, (void(*)(void*))xDel, pDelPtr, pCtx); }else{ - setResultStrOrError(pCtx, z, (int)n, 0, xDel); + setResultStrOrError(pCtx, z, (int)n, 0, + (void(*)(void*))xDel, pDelPtr); } } void sqlite3_result_double(sqlite3_context *pCtx, double rVal){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemSetDouble(pCtx->pOut, rVal); @@ -418,11 +440,11 @@ const char *z, int n, void (*xDel)(void *) ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); - setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel); + setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel, 0); } void sqlite3_result_text64( sqlite3_context *pCtx, const char *z, sqlite3_uint64 n, @@ -431,13 +453,13 @@ ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); assert( xDel!=SQLITE_DYNAMIC ); if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; if( n>0x7fffffff ){ - (void)invokeValueDestructor(z, xDel, pCtx); + (void)invokeValueDestructor(z, xDel, 0, pCtx); }else{ - setResultStrOrError(pCtx, z, (int)n, enc, xDel); + setResultStrOrError(pCtx, z, (int)n, enc, xDel, 0); } } #ifndef SQLITE_OMIT_UTF16 void sqlite3_result_text16( sqlite3_context *pCtx, @@ -444,29 +466,29 @@ const void *z, int n, void (*xDel)(void *) ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); - setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel); + setResultStrOrError(pCtx, z, n, SQLITE_UTF16NATIVE, xDel, 0); } void sqlite3_result_text16be( sqlite3_context *pCtx, const void *z, int n, void (*xDel)(void *) ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); - setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel); + setResultStrOrError(pCtx, z, n, SQLITE_UTF16BE, xDel, 0); } void sqlite3_result_text16le( sqlite3_context *pCtx, const void *z, int n, void (*xDel)(void *) ){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); - setResultStrOrError(pCtx, z, n, SQLITE_UTF16LE, xDel); + setResultStrOrError(pCtx, z, n, SQLITE_UTF16LE, xDel, 0); } #endif /* SQLITE_OMIT_UTF16 */ void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); sqlite3VdbeMemCopy(pCtx->pOut, pValue); @@ -970,10 +992,11 @@ /* .zMalloc = */ (char*)0, /* .szMalloc = */ (int)0, /* .uTemp = */ (u32)0, /* .db = */ (sqlite3*)0, /* .xDel = */ (void(*)(void*))0, + /* .pDelPtr = */ (void*)0, #ifdef SQLITE_DEBUG /* .pScopyFrom = */ (Mem*)0, /* .mScopyFlags= */ 0, #endif }; @@ -1311,10 +1334,11 @@ sqlite3_stmt *pStmt, /* The statement to bind against */ int i, /* Index of the parameter to bind */ const void *zData, /* Pointer to the data to be bound */ int nData, /* Number of bytes of data to be bound */ void (*xDel)(void*), /* Destructor for the data */ + void *pDelPtr, /* Destructor context */ u8 encoding /* Encoding for the data */ ){ Vdbe *p = (Vdbe *)pStmt; Mem *pVar; int rc; @@ -1322,12 +1346,15 @@ rc = vdbeUnbind(p, i); if( rc==SQLITE_OK ){ if( zData!=0 ){ pVar = &p->aVar[i-1]; rc = sqlite3VdbeMemSetStr(pVar, zData, nData, encoding, xDel); - if( rc==SQLITE_OK && encoding!=0 ){ - rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db)); + if( rc==SQLITE_OK ){ + pVar->pDelPtr = pDelPtr; + if( encoding!=0 ){ + rc = sqlite3VdbeChangeEncoding(pVar, ENC(p->db)); + } } if( rc ){ sqlite3Error(p->db, rc); rc = sqlite3ApiExit(p->db, rc); } @@ -1351,11 +1378,11 @@ void (*xDel)(void*) ){ #ifdef SQLITE_ENABLE_API_ARMOR if( nData<0 ) return SQLITE_MISUSE_BKPT; #endif - return bindText(pStmt, i, zData, nData, xDel, 0); + return bindText(pStmt, i, zData, nData, xDel, 0, 0); } int sqlite3_bind_blob64( sqlite3_stmt *pStmt, int i, const void *zData, @@ -1362,13 +1389,29 @@ sqlite3_uint64 nData, void (*xDel)(void*) ){ assert( xDel!=SQLITE_DYNAMIC ); if( nData>0x7fffffff ){ - return invokeValueDestructor(zData, xDel, 0); + return invokeValueDestructor(zData, xDel, 0, 0); + }else{ + return bindText(pStmt, i, zData, (int)nData, xDel, 0, 0); + } +} +int sqlite3_bind_blob64dx( + sqlite3_stmt *pStmt, + int i, + const void *zData, + sqlite3_uint64 nData, + void (*xDel)(void*,void*), + void *pDelPtr +){ + assert( (void(*)(void*))xDel!=SQLITE_DYNAMIC ); + if( nData>0x7fffffff ){ + return invokeValueDestructor(zData, (void(*)(void*))xDel, pDelPtr, 0); }else{ - return bindText(pStmt, i, zData, (int)nData, xDel, 0); + return bindText(pStmt, i, zData, (int)nData, + (void(*)(void*))xDel, pDelPtr, 0); } } int sqlite3_bind_double(sqlite3_stmt *pStmt, int i, double rValue){ int rc; Vdbe *p = (Vdbe *)pStmt; @@ -1424,11 +1467,11 @@ int i, const char *zData, int nData, void (*xDel)(void*) ){ - return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF8); + return bindText(pStmt, i, zData, nData, xDel, 0, SQLITE_UTF8); } int sqlite3_bind_text64( sqlite3_stmt *pStmt, int i, const char *zData, @@ -1436,14 +1479,32 @@ void (*xDel)(void*), unsigned char enc ){ assert( xDel!=SQLITE_DYNAMIC ); if( nData>0x7fffffff ){ - return invokeValueDestructor(zData, xDel, 0); + return invokeValueDestructor(zData, xDel, 0, 0); + }else{ + if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; + return bindText(pStmt, i, zData, (int)nData, xDel, 0, enc); + } +} +int sqlite3_bind_text64dx( + sqlite3_stmt *pStmt, + int i, + const char *zData, + sqlite3_uint64 nData, + void (*xDel)(void*,void*), + void *pDelPtr, + unsigned char enc +){ + assert( (void(*)(void*))xDel!=SQLITE_DYNAMIC ); + if( nData>0x7fffffff ){ + return invokeValueDestructor(zData, (void(*)(void*))xDel, pDelPtr, 0); }else{ if( enc==SQLITE_UTF16 ) enc = SQLITE_UTF16NATIVE; - return bindText(pStmt, i, zData, (int)nData, xDel, enc); + return bindText(pStmt, i, zData, (int)nData, + (void(*)(void*))xDel, pDelPtr, enc); } } #ifndef SQLITE_OMIT_UTF16 int sqlite3_bind_text16( sqlite3_stmt *pStmt, @@ -1450,11 +1511,11 @@ int i, const void *zData, int nData, void (*xDel)(void*) ){ - return bindText(pStmt, i, zData, nData, xDel, SQLITE_UTF16NATIVE); + return bindText(pStmt, i, zData, nData, xDel, 0, SQLITE_UTF16NATIVE); } #endif /* SQLITE_OMIT_UTF16 */ int sqlite3_bind_value(sqlite3_stmt *pStmt, int i, const sqlite3_value *pValue){ int rc; switch( sqlite3_value_type((sqlite3_value*)pValue) ){ @@ -1473,11 +1534,11 @@ rc = sqlite3_bind_blob(pStmt, i, pValue->z, pValue->n,SQLITE_TRANSIENT); } break; } case SQLITE_TEXT: { - rc = bindText(pStmt,i, pValue->z, pValue->n, SQLITE_TRANSIENT, + rc = bindText(pStmt,i, pValue->z, pValue->n, SQLITE_TRANSIENT, 0, pValue->enc); break; } default: { rc = sqlite3_bind_null(pStmt, i); Index: src/vdbemem.c ================================================================== --- src/vdbemem.c +++ src/vdbemem.c @@ -174,10 +174,22 @@ assert(rc==SQLITE_OK || pMem->enc!=desiredEnc); assert(rc==SQLITE_NOMEM || pMem->enc==desiredEnc); return rc; #endif } + +/* +** Invoke the destructor +*/ +void sqlite3VdbeDestructor(Mem *pMem){ + assert( pMem->xDel!=0 ); + if( pMem->pDelPtr==0 ){ + pMem->xDel((void*)(pMem->z)); + }else{ + ((void(*)(void*,void*))(pMem->xDel))(pMem->pDelPtr, (void*)pMem->z); + } +} /* ** Make sure pMem->z points to a writable allocation of at least ** min(n,32) bytes. ** @@ -219,11 +231,11 @@ assert( pMem->z!=pMem->zMalloc ); memcpy(pMem->zMalloc, pMem->z, pMem->n); } if( (pMem->flags&MEM_Dyn)!=0 ){ assert( pMem->xDel!=0 && pMem->xDel!=SQLITE_DYNAMIC ); - pMem->xDel((void *)(pMem->z)); + sqlite3VdbeDestructor(pMem); } pMem->z = pMem->zMalloc; pMem->flags &= ~(MEM_Dyn|MEM_Ephem|MEM_Static); return SQLITE_OK; @@ -461,11 +473,11 @@ assert( (p->flags & MEM_Agg)==0 ); testcase( p->flags & MEM_Dyn ); } if( p->flags&MEM_Dyn ){ assert( p->xDel!=SQLITE_DYNAMIC && p->xDel!=0 ); - p->xDel((void *)p->z); + sqlite3VdbeDestructor(p); } p->flags = MEM_Null; } /* @@ -838,10 +850,11 @@ pMem->u.zPType = zPType ? zPType : ""; pMem->z = pPtr; pMem->flags = MEM_Null|MEM_Dyn|MEM_Subtype|MEM_Term; pMem->eSubtype = 'p'; pMem->xDel = xDestructor ? xDestructor : sqlite3NoopDestructor; + pMem->pDelPtr = 0; } #ifndef SQLITE_OMIT_FLOATING_POINT /* ** Delete any previous value and set the value stored in *pMem to val, @@ -883,10 +896,11 @@ p = sqlite3RowSetInit(db); if( p==0 ) return SQLITE_NOMEM; pMem->z = (char*)p; pMem->flags = MEM_Blob|MEM_Dyn; pMem->xDel = sqlite3RowSetDelete; + pMem->pDelPtr = 0; return SQLITE_OK; } /* ** Return true if the Mem object contains a TEXT or BLOB that is @@ -1079,10 +1093,11 @@ pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc); }else{ sqlite3VdbeMemRelease(pMem); pMem->z = (char *)z; pMem->xDel = xDel; + pMem->pDelPtr = 0; flags |= ((xDel==SQLITE_STATIC)?MEM_Static:MEM_Dyn); } pMem->n = nByte; pMem->flags = flags;