From: drh <> Date: Fri, 28 Jul 2023 12:59:10 +0000 (+0000) Subject: A failed attempt to add a new sqlite3_result_zeroterminated() interface that X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fheads%2Fsqlite3_result_zeroterminated;p=thirdparty%2Fsqlite.git A failed attempt to add a new sqlite3_result_zeroterminated() interface that is a hint to SQLite that a TEXT result does have a zero terminator. The idea is to avoid unnecessary copying of TEXT values. This seems like an unnecessary complication at the moment, but maybe I'll return to this later. Note that this check-in does not work - it is a proof of concept only. FossilOrigin-Name: a0de01108c4b462f8e79bc58fbfe40dec562bbec682679fd0479c79a3c415578 --- diff --git a/manifest b/manifest index a1ea1f26ec..65d8008bd3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\scouple\sof\scompiler\swarnings\sin\sfts5_index.c. -D 2023-07-27T20:08:44.624 +C A\sfailed\sattempt\sto\sadd\sa\snew\ssqlite3_result_zeroterminated()\sinterface\sthat\nis\sa\shint\sto\sSQLite\sthat\sa\sTEXT\sresult\sdoes\shave\sa\szero\sterminator.\s\sThe\sidea\nis\sto\savoid\sunnecessary\scopying\sof\sTEXT\svalues.\sThis\sseems\slike\san\nunnecessary\scomplication\sat\sthe\smoment,\sbut\smaybe\sI'll\sreturn\sto\sthis\slater.\nNote\sthat\sthis\scheck-in\sdoes\snot\swork\s-\sit\sis\sa\sproof\sof\sconcept\sonly. +D 2023-07-28T12:59:10.672 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -596,16 +596,16 @@ F src/delete.c cd5f5cd06ed0b6a882ec1a8c2a0d73b3cecb28479ad19e9931c4706c5e2182be F src/expr.c ef4a81822da6f767696bd7f4b9983328af061158958138540142285a5b1181b7 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c a7fcbf7e66d14dbb73cf49f31489ebf66d0e6006c62b95246924a3bae9f37b36 -F src/func.c cc1da67fd643a43cfe691784158ec656d8ec6d13bb17e67018b01b38b3e4f5ab +F src/func.c c1511ca3ab74a02a6b04bab0e7c6ff2ebf49ca3a5a1ed892f1fa231cb6fc1a03 F src/global.c 29f56a330ed9d1b5cd9b79ac0ca36f97ac3afc730ff8bfa987b0db9e559d684d F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220 F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51 F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276 -F src/json.c c992d2a87a6888bf16a5c7270ef523eb838cf49e6643420c3cf917124f41f97f +F src/json.c b3d1811118a140febeda3b6be96abbb4e8545c3d6d8f26ba8ca2dfb6a8a8edde F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa -F src/loadext.c 176d6b2cb18a6ad73b133db17f6fc351c4d9a2d510deebdb76c22bde9cfd1465 +F src/loadext.c e389600cd7e6581b486a00fcc4cbff833a9ad186d9ab1aca3bb5974a38e37e8c F src/main.c 512b1d45bc556edf4471a845afb7ba79e64bd5b832ab222dc195c469534cd002 F src/malloc.c 47b82c5daad557d9b963e3873e99c22570fb470719082c6658bf64e3012f7d23 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 @@ -639,15 +639,15 @@ F src/pcache1.c 602acb23c471bb8d557a6f0083cc2be641d6cafcafa19e481eba7ef4c9ca0f00 F src/pragma.c 37b8fb02d090262280c86e1e2654bf59d8dbfbfe8dc6733f2b968a11374c095a F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7 F src/prepare.c d6c4354f8ea0dc06962fbabc4b68c4471a45276a2918c929be00f9f537f69eb1 -F src/printf.c e3ba080e2f409f9bfcc8d34724e6fc160e9c718dc92d0548f6b71b8b6f860ce2 +F src/printf.c be332893e1daebbc0638aa16cfb2a7daf7613e8ae7b72352e01afbda6a4b5ad3 F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 37953a5f36c60bea413c3c04efcd433b6177009f508ef2ace0494728912fe2e9 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 3ab1186290a311a8ceed1286c0e286209f7fe97b2d02c7593258004ce295dd88 F src/shell.c.in 62b58d7be1e44ec3eb729411278b079c39949e683853445323fd3f250b674a29 -F src/sqlite.h.in f999ef3642f381d69679b2516b430dbcb6c5a2a951b7f5e43dc4751b474a5774 +F src/sqlite.h.in f6891cc5e6ffaa4a16ff46c2b5fed53653034e58d9eecca972efc5f913d8c183 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 -F src/sqlite3ext.h da473ce2b3d0ae407a6300c4a164589b9a6bfdbec9462688a8593ff16f3bb6e4 +F src/sqlite3ext.h a2d57a373740a2a19052a85da26e0cbfb8d58eadcd65b7af3be8ed66f1201031 F src/sqliteInt.h 30d7b0d586a4d03a384dcb60088c81b6fc6f74ce85cc3a0b3242eedc3cc24dbd F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6 F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749 @@ -716,7 +716,7 @@ F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104 F src/vdbe.c 4cda877d413a18fa07346b08d6959b3d18ce982357921e7acb9649fca2534a12 F src/vdbe.h 41485521f68e9437fdb7ec4a90f9d86ab294e9bb8281e33b235915e29122cfc0 F src/vdbeInt.h 401813862f9d75af01bdb2ab99253ad019e9d6ddcc8058e4fa61a43e9a60d1f7 -F src/vdbeapi.c dde6c4d0f87486f056b9db4d1ea185bb1d84a6839102b86e76316ba590d07cc7 +F src/vdbeapi.c 5bf0376376e7b7f284d81436b471ef76f0b210ce64a5988d875c3b502db888df F src/vdbeaux.c b5e3f7e158518b4eca6f166ac43900640a3fe9735c710e12bfa119af21059339 F src/vdbeblob.c 2516697b3ee8154eb8915f29466fb5d4f1ae39ee8b755ea909cefaf57ec5e2ce F src/vdbemem.c 33da4f30ddba2670bc1e617c3262b66aef2a8039043d4ff93e5c97974991089d @@ -2049,8 +2049,12 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P d66b182d2bc6ce0772e69401b7affe1adbc1b128c4631cb3c17f98dde72af00a -R 67e5566856c21efabeaa9f30d61da2e8 -U dan -Z 82b2d14bd5c4ac2218712be1054b30ff +P bf71faa2a1d29ea762c4d2485522d6f4f8a5a7166981a92d3ba9c96ccbbe1213 +R eb8bcba9b38858125330a6f1f21381a9 +T *branch * sqlite3_result_zeroterminated +T *sym-sqlite3_result_zeroterminated * +T +closed * +T -sym-trunk * +U drh +Z 3eed865c1f50875c4bb3e8a707d0d1f4 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c1365ea15a..80070b8450 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -bf71faa2a1d29ea762c4d2485522d6f4f8a5a7166981a92d3ba9c96ccbbe1213 \ No newline at end of file +a0de01108c4b462f8e79bc58fbfe40dec562bbec682679fd0479c79a3c415578 \ No newline at end of file diff --git a/src/func.c b/src/func.c index ef06a79fb9..683f98e5d9 100644 --- a/src/func.c +++ b/src/func.c @@ -329,6 +329,7 @@ static void printfFunc( n = str.nChar; sqlite3_result_text(context, sqlite3StrAccumFinish(&str), n, SQLITE_DYNAMIC); + sqlite3_result_zeroterminated(context); } } @@ -516,7 +517,9 @@ static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ for(i=0; ipCtx, p->zBuf, p->nUsed, (void(*)(void*))sqlite3RCStrUnref, SQLITE_UTF8); + sqlite3_result_zeroterminated(p->pCtx); } } if( p->bErr==1 ){ @@ -993,6 +994,7 @@ static void jsonReturn( } /* end for() */ zOut[j] = 0; sqlite3_result_text(pCtx, zOut, j, sqlite3_free); + sqlite3_result_zeroterminated(pCtx); } break; } @@ -3086,17 +3088,19 @@ static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){ if( pStr ){ pStr->pCtx = ctx; jsonAppendChar(pStr, ']'); + jsonAppendChar(pStr, 0); if( pStr->bErr ){ if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); assert( pStr->bStatic ); }else if( isFinal ){ - sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, + sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed-1, pStr->bStatic ? SQLITE_TRANSIENT : (void(*)(void*))sqlite3RCStrUnref); + sqlite3_result_zeroterminated(ctx); pStr->bStatic = 1; }else{ - sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); - pStr->nUsed--; + sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed-1,SQLITE_TRANSIENT); + pStr->nUsed -= 2; } }else{ sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC); @@ -3195,17 +3199,19 @@ static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){ pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0); if( pStr ){ jsonAppendChar(pStr, '}'); + jsonAppendChar(pStr, 0); if( pStr->bErr ){ if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx); assert( pStr->bStatic ); }else if( isFinal ){ - sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, + sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed-1, pStr->bStatic ? SQLITE_TRANSIENT : (void(*)(void*))sqlite3RCStrUnref); + sqlite3_result_zeroterminated(ctx); pStr->bStatic = 1; }else{ - sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT); - pStr->nUsed--; + sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed-1,SQLITE_TRANSIENT); + pStr->nUsed -= 2; } }else{ sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC); diff --git a/src/loadext.c b/src/loadext.c index 4fc1352e03..77798514d7 100644 --- a/src/loadext.c +++ b/src/loadext.c @@ -512,7 +512,9 @@ static const sqlite3_api_routines sqlite3Apis = { /* Version 3.40.0 and later */ sqlite3_value_encoding, /* Version 3.41.0 and later */ - sqlite3_is_interrupted + sqlite3_is_interrupted, + /* Version 3.43.0 and later */ + sqlite3_result_zeroterminated }; /* True if x is the directory separator character diff --git a/src/printf.c b/src/printf.c index 87ad91f795..78c9e73daa 100644 --- a/src/printf.c +++ b/src/printf.c @@ -1076,7 +1076,9 @@ void sqlite3ResultStrAccum(sqlite3_context *pCtx, StrAccum *p){ sqlite3_result_error_code(pCtx, p->accError); sqlite3_str_reset(p); }else if( isMalloced(p) ){ + p->zText[p->nChar] = 0; sqlite3_result_text(pCtx, p->zText, p->nChar, SQLITE_DYNAMIC); + sqlite3_result_zeroterminated(pCtx); }else{ sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC); sqlite3_str_reset(p); diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 59d9986c52..038151837a 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -6102,6 +6102,55 @@ int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n); */ void sqlite3_result_subtype(sqlite3_context*,unsigned int); +/* +** CAPI3REF: Indicate That A Text Result Is Zero-Terminated +** METHOD: sqlite3_context +** +** There are five interfaces that can be used by an +** [application-defined SQL function] or [virtual table] to indicate that +** a result value returned to SQLite is TEXT. Specifically: +** +** +** +** In all cases, the N parameter is the size of the TEXT value in bytes. +** +** The sqlite3_result_zeroterminated(C) indicates to SQLite that the TEXT +** value passed in the previous call to one or the sqlite3_result_text() +** interfaces contains one additional zero character (either a single 0x00 +** bytes for UTF-8 or two 0x00 bytes for UTF-16) following the N bytes +** specified. Knowing this can sometimes help SQLite avoid having to +** make copies of the TEXT value. +** +** This interface is an optimization. Application-defined functions and +** virtual tables can use this interface to help SQLite run faster by +** avoiding unnecessary copying of TEXT values. But the same result should +** be obtained regardless of whether or not this function is used. +** +** If the N argument to the prior sqlite3_result_text() method is negative, +** then it is pointless (though harmless) to call sqlite3_result_zeroterminated() +** because in that case SQLite already knows that the TEXT result is +** zero terminated. (NB: Negative N values are not allowed for +** sqlite3_result_text64().) Likewise, if the D argument to the prior +** sqlite3_result_text() method is SQLITE_TRANSIENT, then SQLite has already +** made a copy of the TEXT value and inserted its own zero terminator in +** that copy, so a call to sqlite3_result_zeroterminated() is pointless. +** +** It is a harmless no-op to invoke the sqlite3_result_zeroterminated(C) +** method if the result of the SQL function or virtual table is something +** other than TEXT. +** +** Note that sqlite3_result_zeroterminated() must be call after the call +** the sqlite3_result_text() method. If sqlite3_result_zeroterminated() +** is called before the sqlite3_result_text() method, it will have no effect. +*/ +void sqlite3_result_zeroterminated(sqlite3_context*); + /* ** CAPI3REF: Define New Collating Sequences ** METHOD: sqlite3 diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h index 19e030028a..3d873de0ec 100644 --- a/src/sqlite3ext.h +++ b/src/sqlite3ext.h @@ -361,6 +361,8 @@ struct sqlite3_api_routines { int (*value_encoding)(sqlite3_value*); /* Version 3.41.0 and later */ int (*is_interrupted)(sqlite3*); + /* Version 3.43.0 and later */ + void (*result_zeroterminated)(sqlite3_context*); }; /* @@ -689,6 +691,8 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_value_encoding sqlite3_api->value_encoding /* Version 3.41.0 and later */ #define sqlite3_is_interrupted sqlite3_api->is_interrupted +/* Version 3.43.0 and later */ +#define sqlite3_result_zeroterminated sqlite3_api->result_zeroterminated #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 92bf38160f..f6662a93e5 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -546,6 +546,11 @@ void sqlite3_result_text16le( setResultStrOrError(pCtx, z, n & ~(u64)1, SQLITE_UTF16LE, xDel); } #endif /* SQLITE_OMIT_UTF16 */ +void sqlite3_result_zeroterminated(sqlite3_context *pCtx){ + assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); + assert( (pCtx->pOut->flags & MEM_Str)==0 || pCtx->pOut->z[pCtx->pOut->n]==0 ); + pCtx->pOut->flags |= MEM_Term; +} void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){ Mem *pOut = pCtx->pOut; assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );