Add destructor functions for the pointer argument (NB: not the type string)

to the sqlite3_bind_pointer() and sqlite3_result_pointer() interfaces.  Use
this new capability to resolve a pointer leak in the custom geometry function
mechanism of the RTREE extension.

FossilOrigin-Name: 5a2340b81faf0a29deb5b7c9a2ba6a7697d646de6cc4e9b2e6e5e6463fa394bd
This commit is contained in:
drh 2017-07-27 17:45:08 +00:00
commit 05cccc2848
12 changed files with 118 additions and 93 deletions

View File

@ -3353,7 +3353,7 @@ static int fts3ColumnMethod(
switch( iCol-p->nColumn ){
case 0:
/* The special 'table-name' column */
sqlite3_result_pointer(pCtx, pCsr, "fts3cursor");
sqlite3_result_pointer(pCtx, pCsr, "fts3cursor", 0);
break;
case 1:

View File

@ -104,7 +104,7 @@ static int SQLITE_TCLAPI f5tDbAndApi(
Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
return TCL_ERROR;
}
sqlite3_bind_pointer(pStmt, 1, (void*)&pApi, "fts5_api_ptr");
sqlite3_bind_pointer(pStmt, 1, (void*)&pApi, "fts5_api_ptr", 0);
sqlite3_step(pStmt);
if( sqlite3_finalize(pStmt)!=SQLITE_OK ){

View File

@ -75,7 +75,7 @@ static int fts5_api_from_db(sqlite3 *db, fts5_api **ppApi){
*ppApi = 0;
rc = sqlite3_prepare(db, "SELECT fts5(?1)", -1, &pStmt, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_pointer(pStmt, 1, (void*)ppApi, "fts5_api_ptr");
sqlite3_bind_pointer(pStmt, 1, (void*)ppApi, "fts5_api_ptr", 0);
(void)sqlite3_step(pStmt);
rc = sqlite3_finalize(pStmt);
}

View File

@ -24,7 +24,7 @@
**
** static int aX[] = { 53, 9, 17, 2231, 4, 99 };
** int i = sqlite3_bind_parameter_index(pStmt, "$ptr");
** sqlite3_bind_value(pStmt, i, aX, "carray");
** sqlite3_bind_value(pStmt, i, aX, "carray", 0);
**
** There is an optional third parameter to determine the datatype of
** the C-language array. Allowed values of the third parameter are
@ -377,7 +377,7 @@ static void inttoptrFunc(
int i32 = i64 & 0xffffffff;
memcpy(&p, &i32, sizeof(p));
}
sqlite3_result_pointer(context, p, "carray");
sqlite3_result_pointer(context, p, "carray", 0);
}
#endif /* SQLITE_TEST */

View File

@ -339,14 +339,6 @@ struct RtreeGeomCallback {
void *pContext;
};
/*
** Value for the first field of every RtreeMatchArg object. The MATCH
** operator tests that the first field of a blob operand matches this
** value to avoid operating on invalid blobs (which could cause a segfault).
*/
#define RTREE_GEOMETRY_MAGIC 0x891245AB
/*
** An instance of this structure (in the form of a BLOB) is returned by
** the SQL functions that sqlite3_rtree_geometry_callback() and
@ -354,7 +346,7 @@ struct RtreeGeomCallback {
** operand to the MATCH operator of an R-Tree.
*/
struct RtreeMatchArg {
u32 magic; /* Always RTREE_GEOMETRY_MAGIC */
u32 iSize; /* Size of this object */
RtreeGeomCallback cb; /* Info about the callback functions */
int nParam; /* Number of parameters to the SQL function */
sqlite3_value **apSqlParam; /* Original SQL parameter values */
@ -1649,33 +1641,17 @@ static int findLeafNode(
** operator.
*/
static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){
RtreeMatchArg *pBlob; /* BLOB returned by geometry function */
RtreeMatchArg *pBlob, *pSrc; /* BLOB returned by geometry function */
sqlite3_rtree_query_info *pInfo; /* Callback information */
int nBlob; /* Size of the geometry function blob */
int nExpected; /* Expected size of the BLOB */
/* Check that value is actually a blob. */
if( sqlite3_value_type(pValue)!=SQLITE_BLOB ) return SQLITE_ERROR;
/* Check that the blob is roughly the right size. */
nBlob = sqlite3_value_bytes(pValue);
if( nBlob<(int)sizeof(RtreeMatchArg) ){
return SQLITE_ERROR;
}
pInfo = (sqlite3_rtree_query_info*)sqlite3_malloc( sizeof(*pInfo)+nBlob );
pSrc = sqlite3_value_pointer(pValue, "RtreeMatchArg");
if( pSrc==0 ) return SQLITE_ERROR;
pInfo = (sqlite3_rtree_query_info*)
sqlite3_malloc64( sizeof(*pInfo)+pSrc->iSize );
if( !pInfo ) return SQLITE_NOMEM;
memset(pInfo, 0, sizeof(*pInfo));
pBlob = (RtreeMatchArg*)&pInfo[1];
memcpy(pBlob, sqlite3_value_blob(pValue), nBlob);
nExpected = (int)(sizeof(RtreeMatchArg) +
pBlob->nParam*sizeof(sqlite3_value*) +
(pBlob->nParam-1)*sizeof(RtreeDValue));
if( pBlob->magic!=RTREE_GEOMETRY_MAGIC || nBlob!=nExpected ){
sqlite3_free(pInfo);
return SQLITE_ERROR;
}
memcpy(pBlob, pSrc, pSrc->iSize);
pInfo->pContext = pBlob->cb.pContext;
pInfo->nParam = pBlob->nParam;
pInfo->aParam = pBlob->aParam;
@ -3713,7 +3689,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
sqlite3_result_error_nomem(ctx);
}else{
int i;
pBlob->magic = RTREE_GEOMETRY_MAGIC;
pBlob->iSize = nBlob;
pBlob->cb = pGeomCtx[0];
pBlob->apSqlParam = (sqlite3_value**)&pBlob->aParam[nArg];
pBlob->nParam = nArg;
@ -3730,7 +3706,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
sqlite3_result_error_nomem(ctx);
rtreeMatchArgFree(pBlob);
}else{
sqlite3_result_blob(ctx, pBlob, nBlob, rtreeMatchArgFree);
sqlite3_result_pointer(ctx, pBlob, "RtreeMatchArg", rtreeMatchArgFree);
}
}
}

View File

@ -1,5 +1,5 @@
C Release\scandidate\s2\sfor\s3.20.0.
D 2017-07-25T15:12:01.300
C Add\sdestructor\sfunctions\sfor\sthe\spointer\sargument\s(NB:\snot\sthe\stype\sstring)\nto\sthe\ssqlite3_bind_pointer()\sand\ssqlite3_result_pointer()\sinterfaces.\s\sUse\nthis\snew\scapability\sto\sresolve\sa\spointer\sleak\sin\sthe\scustom\sgeometry\sfunction\nmechanism\sof\sthe\sRTREE\sextension.
D 2017-07-27T17:45:08.840
F Makefile.in d9873c9925917cca9990ee24be17eb9613a668012c85a343aef7e5536ae266e8
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc 02b469e9dcd5b7ee63fc1fb05babc174260ee4cfa4e0ef2e48c3c6801567a016
@ -70,7 +70,7 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
F ext/fts3/fts3.c dfda8bb464d229785e0528fcf7017b4f8e95656d40d28333dfc3f3363bbe229e
F ext/fts3/fts3.c f1c58503bc81c3dab1a70b25e146878ae40fccc716fd7c9b817995b661bc896f
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
F ext/fts3/fts3Int.h eb2502000148e80913b965db3e59f29251266d0a
F ext/fts3/fts3_aux.c 9edc3655fcb287f0467d0a4b886a01c6185fe9f1
@ -108,8 +108,8 @@ F ext/fts5/fts5_hash.c 32be400cf761868c9db33efe81a06eb19a17c5402ad477ee9efb51301
F ext/fts5/fts5_index.c 2ce9d50ec5508b8205615aad69e1c9b2c77f017f21d4479e1fb2079c01fdd017
F ext/fts5/fts5_main.c 24868f88ab2a865defbba7a92eebeb726cc991eb092b71b5f5508f180c72605b
F ext/fts5/fts5_storage.c fb5ef3c27073f67ade2e1bea08405f9e43f68f5f3676ed0ab7013bce5ba10be6
F ext/fts5/fts5_tcl.c 4fab0eaba3d8a82c36195c9268e68e64c9b7acbd9e6b054e84fcf2ee97672714
F ext/fts5/fts5_test_mi.c 03cfc256bb2dfe0d0f9516daea894ea651a7105cd3bdcfbd6c1f4d3145634931
F ext/fts5/fts5_tcl.c a7df39442ae674dde877cf06fe02ebb7658e69c179a4d223241c90df4f14b54e
F ext/fts5/fts5_test_mi.c 65864ba1e5c34a61d409c4c587e0bbe0466eb4f8f478d85dc42a92caad1338e6
F ext/fts5/fts5_test_tok.c ffd657dd67e7fcdb31bf63fb60b6d867299a581d0f46e97086abacd66c2a9b26
F ext/fts5/fts5_tokenize.c 2ce7b44183538ec46b7907726262ee43ffdd39a8
F ext/fts5/fts5_unicode2.c b450b209b157d598f7b9df9f837afb75a14c24bf
@ -256,7 +256,7 @@ F ext/lsm1/test/lsm1_simple.test 3bb38951450cd1f12a6c294949334d6fbb109a3da38c48e
F ext/misc/README.md 8e008c8d2b02e09096b31dfba033253ac27c6c06a18aa5826e299fa7601d90b2
F ext/misc/amatch.c 6db4607cb17c54b853a2d7c7c36046d004853f65b9b733e6f019d543d5dfae87
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
F ext/misc/carray.c 880684b2796ef6ad915094093297eede40db6c07f280c7f491c8eff72ea03ec7
F ext/misc/carray.c ed96c218ea940b85c9a274c4d9c59fe9491c299147a38a8bba537687bd6c6005
F ext/misc/closure.c 0d2a038df8fbae7f19de42e7c7d71f2e4dc88704
F ext/misc/completion.c 52c3f01523e3e387eb321b4739a89d1fe47cbe6025aa1f2d8d3685e9e365df0f
F ext/misc/compress.c 122faa92d25033d6c3f07c39231de074ab3d2e83
@ -321,7 +321,7 @@ F ext/rbu/sqlite3rbu.c d1438580a451eebda3bfd42ef69b677512f00125285e0e4e789b6131a
F ext/rbu/sqlite3rbu.h fc25e1fcd99b5c6d32b1b5b1c73122632e873ac89bd0be9bf646db362b7ce02c
F ext/rbu/test_rbu.c ec18cfc69a104309df23c359e3c80306c9a6bdd1d2c53c8b70ae158e9832dcd6
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
F ext/rtree/rtree.c c5886d4ba7e7c66d0f9ee0b788d5532f8537ca04db19cec7f2f64dcf46e9be37
F ext/rtree/rtree.c 4f1804b80ae06ddf7ff69192aacdceee283646dc6a328acb951f116147445212
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
F ext/rtree/rtree1.test 4fdd60ae034e43f2fefc26492032d02e742e8b14d468b7c51d95a1e2fa47cf00
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
@ -455,9 +455,9 @@ F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c c6bf96a7f9d7d68f929de84738c599a30d0a725ab0b54420e70545743cd5ee7b
F src/shell.c bd6a37cbe8bf64ef6a6a74fdc50f067d3148149b4ce2b4d03154663e66ded55f
F src/shell.c.in b5725acacba95ccefa57b6d068f710e29ba8239c3aa704628a1902a1f729c175
F src/sqlite.h.in 6832630003ce858f55c750181488f30aa167870110d843035e501729a6a1c4cf
F src/sqlite.h.in 86a14aab0f03021bdc71e8a78091ca52931cdc3dc69633dacf9a511dfe9ee993
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 967154985ed2ae62f90d9029bb5b5071793d847f1696a2ebe9e8cc0b042ae60b
F src/sqlite3ext.h 0f9f72b86a3792314f5db7a1dfbc2c82376bcd8d0919ceb80637bca126ec3c68
F src/sqliteInt.h bd6be75bc43d38ada272ef0b3472bc44ef0cc15536bea22c349ca1a2812a19ce
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
@ -522,11 +522,11 @@ F src/util.c fc081ec6f63448dcd80d3dfad35baecfa104823254a815b081a4d9fe76e1db23
F src/vacuum.c 874c0f2f15ab2908748297d587d22d485ea96d55aaec91d4775dddb2e24d2ecf
F src/vdbe.c 1e541ec7ff409bbabcc6b4f154957296fff5827c16c2ab0056348acae75685bf
F src/vdbe.h d50cadf12bcf9fb99117ef392ce1ea283aa429270481426b6e8b0280c101fd97
F src/vdbeInt.h 19bd04a4211fe56c712ab35b48be77fd5a0579b851e9dea2cb8deade359b72b9
F src/vdbeapi.c 52844a5a71712197be45f1c63d730c48a745c7457c959465cfb2b969af40a266
F src/vdbeInt.h ff2b7db0968d20e6184aee256d2e535d565f5a172e3588a78adb166a41fc4911
F src/vdbeapi.c 0823531191f9d5588a245ed5b39306798681814e9e8099d54a3213a13a28fbe7
F src/vdbeaux.c 3fe68bad02b33b09e08bdc0ad90d6b92b3d571f7864c3d047abca1bde050751c
F src/vdbeblob.c 359891617358deefc85bef7bcf787fa6b77facb9
F src/vdbemem.c fe8fce1cdc258320b465934039fe4b1230d63f81d6b81b1eac775b6eec00af0d
F src/vdbemem.c 9ca2854976f35db40341977e688a08204c96427505f5b90215dc7970f6ea42c4
F src/vdbesort.c f512c68d0bf7e0105316a5594c4329358c8ee9cae3b25138df041d97516c0372
F src/vdbetrace.c 41963d5376f0349842b5fc4aaaaacd7d9cdc0834
F src/vtab.c 35b9bdc2b41de32a417141d12097bcc4e29a77ed7cdb8f836d1d2305d946b61b
@ -1637,10 +1637,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 1ca707a4fb8db7aa85430413164265607ce727fc8a5afc3424b3abfb59921b39
R 8215cf089e6d9a2d7dcbd4ee22b67db3
T *branch * branch-3.20
T *sym-branch-3.20 *
T -sym-trunk *
P f39cb76b3347baba22f2c329e74036710b64620414433a952de8d44da79ba8d9 d6684d2a744e6e04b8796c3b5ecb81c6577728b698c1ab5f4a828b2ac114b8a2
R 94d2d6800509c651201392a359c9b77e
T +closed d6684d2a744e6e04b8796c3b5ecb81c6577728b698c1ab5f4a828b2ac114b8a2
U drh
Z b5d895badf8b9b6a24951d6f900b8c5d
Z 1a620a1987be7e7a32507ea55728d87e

View File

@ -1 +1 @@
f39cb76b3347baba22f2c329e74036710b64620414433a952de8d44da79ba8d9
5a2340b81faf0a29deb5b7c9a2ba6a7697d646de6cc4e9b2e6e5e6463fa394bd

View File

@ -3883,17 +3883,18 @@ 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.
** associated with the pointer P of type T. ^D is either a NULL pointer or
** a pointer to a destructor function that is called when P goes out of scope.
** ^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
** sqlite3_bind_pointer(S,I,P,T,D) owns the T string and
** must guarantee that it remains valid and unchanged 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.
**
@ -3930,7 +3931,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,7 +4764,7 @@ 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.
@ -5101,13 +5102,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()].
** ^If the D parameter is not NULL, then it is a pointer to a destructor
** for the P parameter. ^The destructor D is invoked on P when the result
** value goes out of scope.
** The T parameter should be a static string and preferably a string
** literal. The procedure that invokes sqlite3_result_pointer(C,P,T)
** literal. The procedure that invokes sqlite3_result_pointer(C,P,T,D)
** 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
@ -5136,7 +5140,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);

View File

@ -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*);
};

View File

@ -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);

View File

@ -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;
}

View File

@ -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