diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index ca17888276..f5145426e0 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -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: diff --git a/ext/fts5/fts5_tcl.c b/ext/fts5/fts5_tcl.c index 99120e3d27..e8d4c32a46 100644 --- a/ext/fts5/fts5_tcl.c +++ b/ext/fts5/fts5_tcl.c @@ -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 ){ diff --git a/ext/fts5/fts5_test_mi.c b/ext/fts5/fts5_test_mi.c index 49220b6410..481d09b2ca 100644 --- a/ext/fts5/fts5_test_mi.c +++ b/ext/fts5/fts5_test_mi.c @@ -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); } diff --git a/ext/misc/carray.c b/ext/misc/carray.c index b182ea1bcf..b39904ae15 100644 --- a/ext/misc/carray.c +++ b/ext/misc/carray.c @@ -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 */ diff --git a/ext/rtree/rtree.c b/ext/rtree/rtree.c index 9f7d528f64..d97cb45491 100644 --- a/ext/rtree/rtree.c +++ b/ext/rtree/rtree.c @@ -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); } } } diff --git a/manifest b/manifest index 7615139f58..bb604c33be 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Release\scandidate\s2\sfor\s3.20.0. -D 2017-07-25T15:12:01.300 +C Add\sa\sdestructor\sargument\sto\ssqlite3_bind_pointer()\s\nand\ssqlite3_result_pointer(). +D 2017-07-27T03:48:02.500 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 @@ -520,13 +520,13 @@ F src/update.c c443935c652af9365e033f756550b5032d02e1b06eb2cb890ed7511ae0c051dc F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5 F src/util.c fc081ec6f63448dcd80d3dfad35baecfa104823254a815b081a4d9fe76e1db23 F src/vacuum.c 874c0f2f15ab2908748297d587d22d485ea96d55aaec91d4775dddb2e24d2ecf -F src/vdbe.c 1e541ec7ff409bbabcc6b4f154957296fff5827c16c2ab0056348acae75685bf +F src/vdbe.c d8437d81958fb9d1f3382586e5a2736258e72dc981631853ecfb66f5091ad90c F src/vdbe.h d50cadf12bcf9fb99117ef392ce1ea283aa429270481426b6e8b0280c101fd97 -F src/vdbeInt.h 19bd04a4211fe56c712ab35b48be77fd5a0579b851e9dea2cb8deade359b72b9 -F src/vdbeapi.c 52844a5a71712197be45f1c63d730c48a745c7457c959465cfb2b969af40a266 -F src/vdbeaux.c 3fe68bad02b33b09e08bdc0ad90d6b92b3d571f7864c3d047abca1bde050751c +F src/vdbeInt.h 4f7034052871f5b358b8c733163505c2820868112494c73294084b20876591cd +F src/vdbeapi.c 7fd45f2470bfc3b02313b4500c965b1848b827b736e3ff754b14861c9c13417f +F src/vdbeaux.c 986c5cae1dcfda124e871a016274589f6b87ddfe4625f60ddf6a5cdb94f64517 F src/vdbeblob.c 359891617358deefc85bef7bcf787fa6b77facb9 -F src/vdbemem.c fe8fce1cdc258320b465934039fe4b1230d63f81d6b81b1eac775b6eec00af0d +F src/vdbemem.c 9d1dde677986b68a25b0f30190325ae173fa51d2991ccc7cffda984407cfc5d7 F src/vdbesort.c f512c68d0bf7e0105316a5594c4329358c8ee9cae3b25138df041d97516c0372 F src/vdbetrace.c 41963d5376f0349842b5fc4aaaaacd7d9cdc0834 F src/vtab.c 35b9bdc2b41de32a417141d12097bcc4e29a77ed7cdb8f836d1d2305d946b61b @@ -1637,10 +1637,10 @@ 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 +R f73e68c37e03cf44fd4c91b4fa2d5350 +T *branch * pointer-with-destructor +T *sym-pointer-with-destructor * +T -sym-branch-3.20 * U drh -Z b5d895badf8b9b6a24951d6f900b8c5d +Z d38f5fd0f536ce6fac398141bc9e08dd diff --git a/manifest.uuid b/manifest.uuid index 1b810724b2..5c8402edf9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f39cb76b3347baba22f2c329e74036710b64620414433a952de8d44da79ba8d9 \ No newline at end of file +3d9e841f6011480ebb8a6d860da72af7fa545983e08835ddef2cac96e5f5cd4b \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index ea002b7206..93410d523f 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -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); diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h index c585f17f2f..0f1712beed 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/vdbe.c b/src/vdbe.c index 3e6231e0d8..7e105940f4 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -416,7 +416,7 @@ void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){ else *zCsr++ = z; } *(zCsr++) = ']'; - if( f & MEM_Zero ){ + if( (f & (MEM_Zero|MEM_Blob))==(MEM_Zero|MEM_Blob) ){ sqlite3_snprintf(100, zCsr,"+%dz",pMem->u.nZero); zCsr += sqlite3Strlen30(zCsr); } @@ -2735,7 +2735,7 @@ case OP_MakeRecord: { do{ assert( memIsValid(pRec) ); pRec->uTemp = serial_type = sqlite3VdbeSerialType(pRec, file_format, &len); - if( pRec->flags & MEM_Zero ){ + if( (pRec->flags & MEM_Zero)!=0 && (pRec->flags & MEM_Blob)!=0 ){ if( nData ){ if( sqlite3VdbeMemExpandBlob(pRec) ) goto no_mem; }else{ @@ -4411,7 +4411,7 @@ case OP_InsertInt: { x.nData = pData->n; } seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0); - if( pData->flags & MEM_Zero ){ + if( (pData->flags & MEM_Zero)!=0 && (pData->flags & MEM_Blob)!=0 ){ x.nZero = pData->u.nZero; }else{ x.nZero = 0; diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 599fe70414..366496bf6a 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_Pointer and MEM_Null set */ FuncDef *pDef; /* Used only when flags==MEM_Agg */ RowSet *pRowSet; /* Used only when flags==MEM_RowSet */ VdbeFrame *pFrame; /* Used when flags==MEM_Frame */ @@ -240,13 +240,17 @@ 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 ** the following flags must be set to determine the memory management ** policy for Mem.z. The MEM_Term flag tells us whether or not the ** string is \000 or \u0000 terminated +** +** NB: MEM_Zero and MEM_Pointer are the same value. But MEM_Zero is +** only value if MEM_Blob is also set, and MEM_Pointer is only valid +** if MEM_Null is also set. */ #define MEM_Term 0x0200 /* String rep is nul terminated */ #define MEM_Dyn 0x0400 /* Need to call Mem.xDel() on Mem.z */ @@ -254,6 +258,7 @@ struct sqlite3_value { #define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */ #define MEM_Agg 0x2000 /* Mem.z points to an agg function context */ #define MEM_Zero 0x4000 /* Mem.i contains count of 0s appended to blob */ +#define MEM_Pointer 0x4000 /* Mem.z is an extension pointer */ #define MEM_Subtype 0x8000 /* Mem.eSubtype is valid */ #ifdef SQLITE_OMIT_INCRBLOB #undef MEM_Zero @@ -476,7 +481,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 35b194fffe..e82b12b71a 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -201,12 +201,11 @@ 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_AffMask|MEM_Pointer))==(MEM_Null|MEM_Pointer) && 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 +388,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,12 +1402,18 @@ 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); } return rc; diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 7c2bd87ef7..82d59c5e61 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -3224,7 +3224,7 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format, u32 *pLen){ assert( pMem->db->mallocFailed || flags&(MEM_Str|MEM_Blob) ); assert( pMem->n>=0 ); n = (u32)pMem->n; - if( flags & MEM_Zero ){ + if( (flags & MEM_Zero)!=0 && (flags & MEM_Blob)!=0 ){ n += pMem->u.nZero; } *pLen = n; diff --git a/src/vdbemem.c b/src/vdbemem.c index eac3b9ed3e..451e06f410 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -220,9 +220,9 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){ int sqlite3VdbeMemExpandBlob(Mem *pMem){ int nByte; assert( pMem->flags & MEM_Zero ); - assert( pMem->flags&MEM_Blob ); assert( (pMem->flags&MEM_RowSet)==0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); + if( (pMem->flags & MEM_Blob)==0 ) return SQLITE_OK; /* Set nByte to the number of bytes required to store the expanded blob. */ nByte = pMem->n + pMem->u.nZero; @@ -709,13 +709,21 @@ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ ** 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 ); + pMem->u.zPType = zPType; + pMem->z = pPtr; if( zPType ){ - pMem->flags = MEM_Null|MEM_Subtype|MEM_Term|MEM_Static; - pMem->u.pPtr = pPtr; - pMem->eSubtype = 'p'; - pMem->z = (char*)zPType; + pMem->flags = MEM_Null|MEM_Pointer; + } + if( xDestructor ){ + pMem->xDel = xDestructor; + pMem->flags |= MEM_Dyn; } }