aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/sqlite.h.in41
-rw-r--r--src/sqlite3ext.h4
-rw-r--r--src/vdbeInt.h15
-rw-r--r--src/vdbeapi.c28
-rw-r--r--src/vdbemem.c54
5 files changed, 92 insertions, 50 deletions
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index ea002b720..e8f34e4ab 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -3883,19 +3883,14 @@ typedef struct sqlite3_context sqlite3_context;
** [sqlite3_blob_open | incremental BLOB I/O] routines.
** ^A negative value for the zeroblob results in a zero-length BLOB.
**
-** ^The sqlite3_bind_pointer(S,I,P,T) routine causes the I-th parameter in
+** ^The sqlite3_bind_pointer(S,I,P,T,D) routine causes the I-th parameter in
** [prepared statement] S to have an SQL value of NULL, but to also be
-** associated with the pointer P of type T.
-** ^The sqlite3_bind_pointer() routine can be used to pass
-** host-language pointers into [application-defined SQL functions].
-** ^A parameter that is initialized using [sqlite3_bind_pointer()] appears
-** to be an ordinary SQL NULL value to everything other than
-** [sqlite3_value_pointer()]. The T parameter should be a static string,
-** preferably a string literal. The procedure that invokes
-** sqlite3_bind_pointer(S,I,P,T) continues to own the P and T pointers and
-** must guarantee that those pointers remain valid until after the last
-** access via [sqlite3_value_pointer()]. The sqlite3_bind_pointer() routine
-** is part of the [pointer passing interface] added for SQLite 3.20.0.
+** associated with the pointer P of type T. ^D is either a NULL pointer or
+** a pointer to a destructor function for P. ^SQLite will invoke the
+** destructor D with a single argument of P when it is finished using
+** P. The T parameter should be a static string, preferably a string
+** literal. The sqlite3_bind_pointer() routine is part of the
+** [pointer passing interface] added for SQLite 3.20.0.
**
** ^If any of the sqlite3_bind_*() routines are called with a NULL pointer
** for the [prepared statement] or with a prepared statement for which
@@ -3930,7 +3925,7 @@ 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_value(sqlite3_stmt*, int, const sqlite3_value*);
-int sqlite3_bind_pointer(sqlite3_stmt*, int, void*, const char*);
+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);
@@ -4763,10 +4758,11 @@ SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
** extract UTF-16 strings as big-endian and little-endian respectively.
**
** ^If [sqlite3_value] object V was initialized
-** using [sqlite3_bind_pointer(S,I,P,X)] or [sqlite3_result_pointer(C,P,X)]
+** using [sqlite3_bind_pointer(S,I,P,X,D)] or [sqlite3_result_pointer(C,P,X,D)]
** and if X and Y are strings that compare equal according to strcmp(X,Y),
** then sqlite3_value_pointer(V,Y) will return the pointer P. ^Otherwise,
-** sqlite3_value_pointer(V,Y) returns a NULL.
+** sqlite3_value_pointer(V,Y) returns a NULL. The sqlite3_bind_pointer()
+** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
**
** ^(The sqlite3_value_type(V) interface returns the
** [SQLITE_INTEGER | datatype code] for the initial datatype of the
@@ -5101,17 +5097,16 @@ typedef void (*sqlite3_destructor_type)(void*);
** [unprotected sqlite3_value] object is required, so either
** kind of [sqlite3_value] object can be used with this interface.
**
-** ^The sqlite3_result_pointer(C,P,T) interface sets the result to an
+** ^The sqlite3_result_pointer(C,P,T,D) interface sets the result to an
** SQL NULL value, just like [sqlite3_result_null(C)], except that it
** also associates the host-language pointer P or type T with that
** NULL value such that the pointer can be retrieved within an
** [application-defined SQL function] using [sqlite3_value_pointer()].
-** The T parameter should be a static string and preferably a string
-** literal. The procedure that invokes sqlite3_result_pointer(C,P,T)
-** continues to own the P and T pointers and must guarantee that
-** those pointers remain valid until after the last access via
-** [sqlite3_value_pointer()]. The sqlite3_result_pointer() routine
-** is part of the [pointer passing interface] added for SQLite 3.20.0.
+** ^If the D parameter is not NULL, then it is a pointer to a destructor
+** for the P parameter. ^SQLite invokes D with P as its only argument
+** when SQLite is finished with P. The T parameter should be a static
+** string and preferably a string literal. The sqlite3_result_pointer()
+** routine is part of the [pointer passing interface] added for SQLite 3.20.0.
**
** If these routines are called from within the different thread
** than the one containing the application-defined function that received
@@ -5136,7 +5131,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_pointer(sqlite3_context*, void*, const char*);
+void sqlite3_result_pointer(sqlite3_context*, void*,const char*,void(*)(void*));
void sqlite3_result_zeroblob(sqlite3_context*, int n);
int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h
index c585f17f2..0f1712bee 100644
--- a/src/sqlite3ext.h
+++ b/src/sqlite3ext.h
@@ -289,8 +289,8 @@ struct sqlite3_api_routines {
sqlite3_stmt**,const char**);
int (*prepare16_v3)(sqlite3*,const void*,int,unsigned int,
sqlite3_stmt**,const void**);
- int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*);
- void (*result_pointer)(sqlite3_context*,void*,const char*);
+ int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
+ void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
void *(*value_pointer)(sqlite3_value*,const char*);
};
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index 599fe7041..d8e47be50 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -189,8 +189,8 @@ struct sqlite3_value {
union MemValue {
double r; /* Real value used when MEM_Real is set in flags */
i64 i; /* Integer value used when MEM_Int is set in flags */
- int nZero; /* Used when bit MEM_Zero is set in flags */
- void *pPtr; /* Pointer when flags=MEM_NULL and eSubtype='p' */
+ int nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */
+ const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */
FuncDef *pDef; /* Used only when flags==MEM_Agg */
RowSet *pRowSet; /* Used only when flags==MEM_RowSet */
VdbeFrame *pFrame; /* Used when flags==MEM_Frame */
@@ -222,7 +222,8 @@ struct sqlite3_value {
** representations of the value stored in the Mem struct.
**
** If the MEM_Null flag is set, then the value is an SQL NULL value.
-** No other flags may be set in this case.
+** For a pointer type created using sqlite3_bind_pointer() or
+** sqlite3_result_pointer() the MEM_Term and MEM_Subtype flags are also set.
**
** If the MEM_Str flag is set then Mem.z points at a string representation.
** Usually this is encoded in the same unicode encoding as the main
@@ -230,7 +231,7 @@ struct sqlite3_value {
** set, then the string is nul terminated. The MEM_Int and MEM_Real
** flags may coexist with the MEM_Str flag.
*/
-#define MEM_Null 0x0001 /* Value is NULL */
+#define MEM_Null 0x0001 /* Value is NULL (or a pointer) */
#define MEM_Str 0x0002 /* Value is a string */
#define MEM_Int 0x0004 /* Value is an integer */
#define MEM_Real 0x0008 /* Value is a real number */
@@ -240,7 +241,7 @@ struct sqlite3_value {
#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */
#define MEM_Undefined 0x0080 /* Value is undefined */
#define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */
-#define MEM_TypeMask 0x81ff /* Mask of type bits */
+#define MEM_TypeMask 0xc1ff /* Mask of type bits */
/* Whenever Mem contains a valid string or blob representation, one of
@@ -248,7 +249,7 @@ struct sqlite3_value {
** policy for Mem.z. The MEM_Term flag tells us whether or not the
** string is \000 or \u0000 terminated
*/
-#define MEM_Term 0x0200 /* String rep is nul terminated */
+#define MEM_Term 0x0200 /* String in Mem.z is zero terminated */
#define MEM_Dyn 0x0400 /* Need to call Mem.xDel() on Mem.z */
#define MEM_Static 0x0800 /* Mem.z points to a static string */
#define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */
@@ -476,7 +477,7 @@ void sqlite3VdbeMemSetInt64(Mem*, i64);
#else
void sqlite3VdbeMemSetDouble(Mem*, double);
#endif
-void sqlite3VdbeMemSetPointer(Mem*, void*, const char*);
+void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(void*));
void sqlite3VdbeMemInit(Mem*,sqlite3*,u16);
void sqlite3VdbeMemSetNull(Mem*);
void sqlite3VdbeMemSetZeroBlob(Mem*,int);
diff --git a/src/vdbeapi.c b/src/vdbeapi.c
index 35b194fff..24545e4f1 100644
--- a/src/vdbeapi.c
+++ b/src/vdbeapi.c
@@ -201,12 +201,13 @@ unsigned int sqlite3_value_subtype(sqlite3_value *pVal){
}
void *sqlite3_value_pointer(sqlite3_value *pVal, const char *zPType){
Mem *p = (Mem*)pVal;
- if( p->flags==(MEM_Null|MEM_Subtype|MEM_Term|MEM_Static)
+ if( (p->flags&(MEM_TypeMask|MEM_Term|MEM_Subtype)) ==
+ (MEM_Null|MEM_Term|MEM_Subtype)
&& zPType!=0
&& p->eSubtype=='p'
- && strcmp(p->z, zPType)==0
+ && strcmp(p->u.zPType, zPType)==0
){
- return p->u.pPtr;
+ return (void*)p->z;
}else{
return 0;
}
@@ -389,11 +390,16 @@ void sqlite3_result_null(sqlite3_context *pCtx){
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetNull(pCtx->pOut);
}
-void sqlite3_result_pointer(sqlite3_context *pCtx, void *pPtr, const char *zPT){
+void sqlite3_result_pointer(
+ sqlite3_context *pCtx,
+ void *pPtr,
+ const char *zPType,
+ void (*xDestructor)(void*)
+){
Mem *pOut = pCtx->pOut;
assert( sqlite3_mutex_held(pOut->db->mutex) );
sqlite3VdbeMemSetNull(pOut);
- sqlite3VdbeMemSetPointer(pOut, pPtr, zPT);
+ sqlite3VdbeMemSetPointer(pOut, pPtr, zPType, xDestructor);
}
void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){
Mem *pOut = pCtx->pOut;
@@ -1398,13 +1404,21 @@ int sqlite3_bind_null(sqlite3_stmt *pStmt, int i){
}
return rc;
}
-int sqlite3_bind_pointer(sqlite3_stmt *pStmt, int i, void *pPtr,const char *zT){
+int sqlite3_bind_pointer(
+ sqlite3_stmt *pStmt,
+ int i,
+ void *pPtr,
+ const char *zPTtype,
+ void (*xDestructor)(void*)
+){
int rc;
Vdbe *p = (Vdbe*)pStmt;
rc = vdbeUnbind(p, i);
if( rc==SQLITE_OK ){
- sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zT);
+ sqlite3VdbeMemSetPointer(&p->aVar[i-1], pPtr, zPTtype, xDestructor);
sqlite3_mutex_leave(p->db->mutex);
+ }else if( xDestructor ){
+ xDestructor(pPtr);
}
return rc;
}
diff --git a/src/vdbemem.c b/src/vdbemem.c
index eac3b9ed3..45b0b38c1 100644
--- a/src/vdbemem.c
+++ b/src/vdbemem.c
@@ -27,7 +27,7 @@
*/
int sqlite3VdbeCheckMemInvariants(Mem *p){
/* If MEM_Dyn is set then Mem.xDel!=0.
- ** Mem.xDel is might not be initialized if MEM_Dyn is clear.
+ ** Mem.xDel might not be initialized if MEM_Dyn is clear.
*/
assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 );
@@ -40,9 +40,34 @@ int sqlite3VdbeCheckMemInvariants(Mem *p){
/* Cannot be both MEM_Int and MEM_Real at the same time */
assert( (p->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real) );
- /* Cannot be both MEM_Null and some other type */
- assert( (p->flags & MEM_Null)==0 ||
- (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob))==0 );
+ if( p->flags & MEM_Null ){
+ /* Cannot be both MEM_Null and some other type */
+ assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob
+ |MEM_RowSet|MEM_Frame|MEM_Agg|MEM_Zero))==0 );
+
+ /* If MEM_Null is set, then either the value is a pure NULL (the usual
+ ** case) or it is a pointer set using sqlite3_bind_pointer() or
+ ** sqlite3_result_pointer(). If a pointer, then MEM_Term must also be
+ ** set.
+ */
+ if( (p->flags & (MEM_Term|MEM_Subtype))==(MEM_Term|MEM_Subtype) ){
+ /* This is a pointer type. There may be a flag to indicate what to
+ ** do with the pointer. */
+ assert( ((p->flags&MEM_Dyn)!=0 ? 1 : 0) +
+ ((p->flags&MEM_Ephem)!=0 ? 1 : 0) +
+ ((p->flags&MEM_Static)!=0 ? 1 : 0) <= 1 );
+
+ /* No other bits set */
+ assert( (p->flags & ~(MEM_Null|MEM_Term|MEM_Subtype
+ |MEM_Dyn|MEM_Ephem|MEM_Static))==0 );
+ }else{
+ /* A pure NULL might have other flags, such as MEM_Static, MEM_Dyn,
+ ** MEM_Ephem, MEM_Cleared, or MEM_Subtype */
+ }
+ }else{
+ /* The MEM_Cleared bit is only allowed on NULLs */
+ assert( (p->flags & MEM_Cleared)==0 );
+ }
/* The szMalloc field holds the correct memory allocation size */
assert( p->szMalloc==0
@@ -705,18 +730,25 @@ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
}
}
+/* A no-op destructor */
+static void sqlite3NoopDestructor(void *p){ UNUSED_PARAMETER(p); }
+
/*
** Set the value stored in *pMem should already be a NULL.
** Also store a pointer to go with it.
*/
-void sqlite3VdbeMemSetPointer(Mem *pMem, void *pPtr, const char *zPType){
+void sqlite3VdbeMemSetPointer(
+ Mem *pMem,
+ void *pPtr,
+ const char *zPType,
+ void (*xDestructor)(void*)
+){
assert( pMem->flags==MEM_Null );
- if( zPType ){
- pMem->flags = MEM_Null|MEM_Subtype|MEM_Term|MEM_Static;
- pMem->u.pPtr = pPtr;
- pMem->eSubtype = 'p';
- pMem->z = (char*)zPType;
- }
+ 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;
}
#ifndef SQLITE_OMIT_FLOATING_POINT