diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/sqlite.h.in | 41 | ||||
-rw-r--r-- | src/sqlite3ext.h | 4 | ||||
-rw-r--r-- | src/vdbeInt.h | 15 | ||||
-rw-r--r-- | src/vdbeapi.c | 28 | ||||
-rw-r--r-- | src/vdbemem.c | 54 |
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 |