]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
A failed attempt to add a new sqlite3_result_zeroterminated() interface that sqlite3_result_zeroterminated
authordrh <>
Fri, 28 Jul 2023 12:59:10 +0000 (12:59 +0000)
committerdrh <>
Fri, 28 Jul 2023 12:59:10 +0000 (12:59 +0000)
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

manifest
manifest.uuid
src/func.c
src/json.c
src/loadext.c
src/printf.c
src/sqlite.h.in
src/sqlite3ext.h
src/vdbeapi.c

index a1ea1f26ecba7b74990a0eeaedabec1eb5bc38b0..65d8008bd3b879c210087e371d1acb99875fb8a2 100644 (file)
--- 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.
index c1365ea15a8eb190fefd4d6969a6c2cab9f561e5..80070b845023a9633d7fedd52cf44901090fa4b4 100644 (file)
@@ -1 +1 @@
-bf71faa2a1d29ea762c4d2485522d6f4f8a5a7166981a92d3ba9c96ccbbe1213
\ No newline at end of file
+a0de01108c4b462f8e79bc58fbfe40dec562bbec682679fd0479c79a3c415578
\ No newline at end of file
index ef06a79fb9adfa10f6acdb019c5767ad9eb0925a..683f98e5d91a4feeb3af1a5a5d63865d06784c2d 100644 (file)
@@ -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; i<n; i++){
         z1[i] = (char)sqlite3Toupper(z2[i]);
       }
+      z1[i] = 0;
       sqlite3_result_text(context, z1, n, sqlite3_free);
+      sqlite3_result_zeroterminated(context);
     }
   }
 }
@@ -535,7 +538,9 @@ static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
       for(i=0; i<n; i++){
         z1[i] = sqlite3Tolower(z2[i]);
       }
+      z1[i] = 0;
       sqlite3_result_text(context, z1, n, sqlite3_free);
+      sqlite3_result_zeroterminated(context);
     }
   }
 }
@@ -1168,6 +1173,7 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
   sqlite3QuoteValue(&str,argv[0]);
   sqlite3_result_text(context, sqlite3StrAccumFinish(&str), str.nChar,
                       SQLITE_DYNAMIC);
+  sqlite3_result_zeroterminated(context);
   if( str.accError!=SQLITE_OK ){
     sqlite3_result_null(context);
     sqlite3_result_error_code(context, str.accError);
@@ -1229,6 +1235,7 @@ static void charFunc(
   }
   *zOut = 0;
   sqlite3_result_text64(context, (char*)z, zOut-z, sqlite3_free, SQLITE_UTF8);
+  sqlite3_result_zeroterminated(context);
 }
 
 /*
@@ -1257,6 +1264,7 @@ static void hexFunc(
     }
     *z = 0;
     sqlite3_result_text(context, zHex, n*2, sqlite3_free);
+    sqlite3_result_zeroterminated(context);
   }
 }
 
@@ -1463,6 +1471,7 @@ static void replaceFunc(
   assert( j<=nOut );
   zOut[j] = 0;
   sqlite3_result_text(context, (char*)zOut, j, sqlite3_free);
+  sqlite3_result_zeroterminated(context);
 }
 
 /*
index 493a1b99c477631e0f4b87226291497c9a62e008..4b08bf6de03eb9120f9673e6121968c7d7ea1a9c 100644 (file)
@@ -572,6 +572,7 @@ static void jsonResult(JsonString *p){
       sqlite3_result_text64(p->pCtx, 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->nUsedSQLITE_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->nUsedSQLITE_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);
index 4fc1352e03e4a416a0acbb8202dd1662309ad151..77798514d7e3ec8d40385d51a4cba755e49db5e5 100644 (file)
@@ -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
index 87ad91f7953007420492b2accdb89afa77bf2d41..78c9e73daab0830c84e6a1c75f94bfccdcab859d 100644 (file)
@@ -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);
index 59d9986c5210844b38b444661ef78cd3917c5b12..038151837af72f65ad86d0d387f3f2b3837137e0 100644 (file)
@@ -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:
+**
+** <ul>
+** <li> [sqlite3_result_text(C,P,N,D)]
+** <li> [sqlite3_result_text64(C,P,N,D,E)]
+** <li> [sqlite3_result_text16(C,P,N,D)]
+** <li> [sqlite3_result_text16le(C,P,N,D)]
+** <li> [sqlite3_result_text16be(C,P,N,D)]
+** </ul>
+**
+** 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
index 19e030028adfeb18e524dc4ad7cae3f294a8db81..3d873de0ec02820995a4edb17cff5e3e4fc79f11 100644 (file)
@@ -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)
index 92bf38160f62b6011934fa2bbb786ea07c44cc47..f6662a93e5b7892d4f61fc2bb0f2cd6c9110e2a9 100644 (file)
@@ -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) );