]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Code and comment cleanup. Everything should work the same.
authordrh <>
Sat, 2 Dec 2023 20:25:36 +0000 (20:25 +0000)
committerdrh <>
Sat, 2 Dec 2023 20:25:36 +0000 (20:25 +0000)
FossilOrigin-Name: c640754df0d3ffdad994745f0d0e10c8f19f424b87f6a6e6e269491a0350b950

manifest
manifest.uuid
src/json.c

index 6f7377cfb857ce60808d8ab21f037cb3bcc99cf1..6e1a782d3161bb6dea5596d2eff532af8406392f 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sharmless\scompiler\swarnings.\s\sRefactor\ssome\sidentifier\snames\sfor\nclearer\spresentation.
-D 2023-12-02T18:17:38.516
+C Code\sand\scomment\scleanup.\s\sEverything\sshould\swork\sthe\ssame.
+D 2023-12-02T20:25:36.578
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -688,7 +688,7 @@ 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 b67328611c8ebc5aca49e2d73b1bad9962948aa5c952f3d96c44eb74ee3d0010
+F src/json.c 5ad1a1be6199359b09bb4eca690789b77375e00f17c55697b6288f1b0fbbe8b0
 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
 F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
 F src/main.c 1b89f3de98d1b59fec5bac1d66d6ece21f703821b8eaa0d53d9604c35309f6f9
@@ -2145,8 +2145,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 1304534001e9ef66c6b12752b69d790bfa3427cc803f87cc48ca22ae12df0fdf
-R 1b492fad564bbccdff370d30a804d641
+P 7e3941502789c5afaf19b08112f464abf5e3cba7f92fc9290af2a0f96127ad9a
+R 9f984966a856d28c36c8f0d6d69732a4
 U drh
-Z f1274565e5b6e1f5da018a4ab14dfe40
+Z ea3e13091dceb571341f1dccf0e97828
 # Remove this line to create a well-formed Fossil manifest.
index 05b1875e6c83a17a60d5a72fd4bc7361ff137d87..9a68b3807a169aac8c7bc735dfc5f2e30a6cc19c 100644 (file)
@@ -1 +1 @@
-7e3941502789c5afaf19b08112f464abf5e3cba7f92fc9290af2a0f96127ad9a
\ No newline at end of file
+c640754df0d3ffdad994745f0d0e10c8f19f424b87f6a6e6e269491a0350b950
\ No newline at end of file
index 064d9457ce92f5ce16947622fa289bea22b3eee2..9356bfa8d5e7b5b4bd6fe3e98c02ef7a0ce62f31 100644 (file)
 #define JSONB_ARRAY   11   /* An array */
 #define JSONB_OBJECT  12   /* An object */
 
-/* Human-readable names for the JSONB values:
+/* Human-readable names for the JSONB values.  The index for each
+** string must correspond to the JSONB_* integer above.
 */
 static const char * const jsonbType[] = {
   "null", "true", "false", "integer", "integer", 
   "real", "real", "text",  "text",    "text",
-  "text", "array", "object"
+  "text", "array", "object", "", "", "", ""
 };
 
 /*
@@ -168,7 +169,7 @@ static const char jsonIsSpace[] = {
 #define jsonIsspace(x) (jsonIsSpace[(unsigned char)x])
 
 /*
-** Characters that are special to JSON.  Control charaters,
+** Characters that are special to JSON.  Control characters,
 ** '"' and '\\'.
 */
 static const char jsonIsOk[256] = {
@@ -204,7 +205,6 @@ typedef struct JsonCache JsonCache;
 typedef struct JsonString JsonString;
 typedef struct JsonParse JsonParse;
 
-
 /*
 ** Magic number used for the JSON parse cache in sqlite3_get_auxdata()
 */
@@ -213,8 +213,14 @@ typedef struct JsonParse JsonParse;
 
 /* A cache mapping JSON text into JSONB blobs.
 **
-** All content, both JSON text and the JSONB blobs, is stored as RCStr
-** objects.
+** Each cache entry is a JsonParse object with the following restrictions:
+**
+**    *   The bReadOnly flag must be set
+**
+**    *   The aBlob[] array must be owned by the JsonParse object.  In other
+**        words, nBlobAlloc must be non-zero.
+**
+**    *   zJson must be an RCStr.  In other words bJsonIsRCStr must be true.
 */
 struct JsonCache {
   sqlite3 *db;                    /* Database connection */
@@ -225,6 +231,10 @@ struct JsonCache {
 /* An instance of this object represents a JSON string
 ** under construction.  Really, this is a generic string accumulator
 ** that can be and is used to create strings other than JSON.
+**
+** If the generated string is longer than will fit into the zSpace[] buffer,
+** then it will be an RCStr string.  This aids with caching of large
+** JSON strings.
 */
 struct JsonString {
   sqlite3_context *pCtx;   /* Function context - put error messages here */
@@ -260,18 +270,17 @@ struct JsonString {
 /* A parsed JSON value.  Lifecycle:
 **
 **   1.  JSON comes in and is parsed into a JSONB value in aBlob.  The
-**       original text is stored in zJson.
+**       original text is stored in zJson.  This step is skipped if the
+**       input is JSONB instead of text JSON.
 **
-**   2.  The aBlob is searched using the JSON path notation, if needed.
+**   2.  The aBlob[] array is searched using the JSON path notation, if needed.
 **       
-**   3.  Zero or more changes are made to aBlob (via json_remove() or
-**       json_replace() or similar).
+**   3.  Zero or more changes are made to aBlob[] (via json_remove() or
+**       json_replace() or json_patch() or similar).
 **
-**   4.  New JSON text is generated from the aBlob for output.
-**
-** Step 1 is omitted if the input is a BLOB in the JSONB format.  Step 4
-** is omitted if the output is JSONB or some other value that is not
-** JSON text.
+**   4.  New JSON text is generated from the aBlob[] for output.  This step
+**       is skipped the function is one of the jsonb_* functions that returns
+**       JSONB instead of text JSON.
 */
 struct JsonParse {
   u8 *aBlob;         /* JSONB representation of JSON value */
@@ -326,7 +335,6 @@ static void jsonReturnParse(sqlite3_context*,JsonParse*);
 static JsonParse *jsonParseFuncArg(sqlite3_context*,sqlite3_value*,u32);
 static void jsonParseFree(JsonParse*);
 
-
 /**************************************************************************
 ** Utility routines for dealing with JsonCache objects
 **************************************************************************/
@@ -346,11 +354,11 @@ static void jsonCacheDeleteGeneric(void *p){
 }
 
 /*
-** Insert a new entry into the cache.  If the cache is full, expell
+** Insert a new entry into the cache.  If the cache is full, expel
 ** the least recently used entry.  Return SQLITE_OK on success or a
 ** result code otherwise.
 **
-** Both the input JSON and JSONB must be RCStr objects.
+** Cache entries are stored in age order, oldest first.
 */
 static int jsonCacheInsert(
   sqlite3_context *ctx,   /* The SQL statement context holding the cache */
@@ -386,7 +394,14 @@ static int jsonCacheInsert(
 
 /*
 ** Search for a cached translation the json text supplied by pArg.  Return
-** the JsonParse object if found.
+** the JsonParse object if found.  Return NULL if not found.
+**
+** When a match if found, the matching entry is moved to become the
+** most-recently used entry if it isn't so already.
+**
+** The JsonParse object returned still belongs to the Cache and might
+** be deleted at any moment.  If the caller whants the JsonParse to
+** linger, it needs to increment the nPJRef reference counter.
 */
 static JsonParse *jsonCacheSearch(
   sqlite3_context *ctx,    /* The SQL statement context holding the cache */
@@ -419,6 +434,7 @@ static JsonParse *jsonCacheSearch(
   }
   if( i<p->nUsed ){
     if( i<p->nUsed-1 ){
+      /* Make the matching entry the most recently used entry */
       JsonParse *tmp = p->a[i];
       memmove(&p->a[i], &p->a[i+1], (p->nUsed-i-1)*sizeof(tmp));
       p->a[p->nUsed-1] = tmp;
@@ -561,7 +577,9 @@ static void jsonStringTerminate(JsonString *p){
   }   
 }
 
-/* Try to force the string to be a zero-terminated RCStr string.
+/* Try to force the string to be a zero-terminated RCStr string.  In other
+** words, make sure it is not still using the internal zSpace[] static
+** buffer.
 **
 ** Return true on success.  Return false if an OOM prevents this
 ** from happening.
@@ -591,9 +609,12 @@ static void jsonAppendSeparator(JsonString *p){
 }
 
 /* Append the N-byte string in zIn to the end of the JsonString string
-** under construction.  Enclose the string in "..." and escape
-** any double-quotes or backslash characters contained within the
+** under construction.  Enclose the string in double-quotes ("...") and
+** escape any double-quotes or backslash characters contained within the
 ** string.
+**
+** This routine is a high-runner.  There is a measurable performance
+** increase associated with unwinding the jsonIsOk[] loop.
 */
 static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
   u32 k;
@@ -604,8 +625,8 @@ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
   p->zBuf[p->nUsed++] = '"';
   while( 1 /*exit-by-break*/ ){
     k = 0;
-    while( k+1<N && jsonIsOk[z[k]] && jsonIsOk[z[k+1]] ){ k += 2; }
-    while( k<N && jsonIsOk[z[k]] ){ k++; }
+    while( k+1<N && jsonIsOk[z[k]] && jsonIsOk[z[k+1]] ){ k += 2; } /* <--, */
+    while( k<N && jsonIsOk[z[k]] ){ k++; }    /* <-- loop unwound for speed  */
     if( k>=N ){
       if( k>0 ){
         memcpy(&p->zBuf[p->nUsed], z, k);
@@ -783,12 +804,8 @@ static void jsonParseReset(JsonParse *pParse){
 }
 
 /*
-** Free a JsonParse object that was obtained from sqlite3_malloc().
-**
-** Note that destroying JsonParse might call sqlite3RCStrUnref() to
-** destroy the zJson value.  The RCStr object might recursively invoke
-** JsonParse to destroy this pParse object again.  Take care to ensure
-** that this recursive destructor sequence terminates harmlessly.
+** Decrement the reference count on the JsonParse object.  When the
+** count reaches zero, free the object.
 */
 static void jsonParseFree(JsonParse *pParse){
   if( pParse ){
@@ -1010,7 +1027,6 @@ static void jsonWrongNumArgs(
 ** Utility routines for dealing with the binary BLOB representation of JSON
 ****************************************************************************/
 
-
 /*
 ** Expand pParse->aBlob so that it holds at least N bytes.
 **
@@ -2068,7 +2084,8 @@ static u32 jsonbArrayCount(JsonParse *pParse, u32 iRoot){
 }
 
 /*
-** Edit the size of the element at iRoot by the amount in pParse->delta.
+** Edit the payload size of the element at iRoot by the amount in
+** pParse->delta.
 */
 static void jsonAfterEditSizeAdjust(JsonParse *pParse, u32 iRoot){
   u32 sz = 0;
@@ -2126,6 +2143,55 @@ static void jsonBlobEdit(
 #define JSON_LOOKUP_PATHERROR  0xfffffffd
 #define JSON_LOOKUP_ISERROR(x) ((x)>=JSON_LOOKUP_PATHERROR)
 
+/* Forward declaration */
+static u32 jsonLookupStep(JsonParse*,u32,const char*,u32);
+
+
+/* This helper routine for jsonLookupStep() populates pIns with
+** binary data that is to be inserted into pParse.
+**
+** In the common case, pIns just points to pParse->aIns and pParse->nIns.
+** But if the zPath of the original edit operation includes path elements
+** that go deeper, additional substructure must be created.
+**
+** For example:
+**
+**     json_insert('{}', '$.a.b.c', 123);
+**
+** The search stops at '$.a'  But additional substructure must be
+** created for the ".b.c" part of the patch so that the final result
+** is:  {"a":{"b":{"c"::123}}}.  This routine populates pIns with
+** the binary equivalent of {"b":{"c":123}} so that it can be inserted.
+**
+** The caller is responsible for resetting pIns when it has finished
+** using the substructure.
+*/
+static u32 jsonCreateEditSubstructure(
+  JsonParse *pParse,  /* The original JSONB that is being edited */
+  JsonParse *pIns,    /* Populate this with the blob data to insert */
+  const char *zTail   /* Tail of the path that determins substructure */
+){
+  static const u8 emptyObject[] = { JSONB_ARRAY, JSONB_OBJECT };
+  int rc;
+  memset(pIns, 0, sizeof(*pIns));
+  if( zTail[0]==0 ){
+    /* No substructure.  Just insert what is given in pParse. */
+    pIns->aBlob = pParse->aIns;
+    pIns->nBlob = pParse->nIns;
+    rc = 0;
+  }else{
+    /* Construct the binary substructure */
+    pIns->nBlob = 1;
+    pIns->aBlob = (u8*)&emptyObject[zTail[0]=='.'];
+    pIns->eEdit = pParse->eEdit;
+    pIns->nIns = pParse->nIns;
+    pIns->aIns = pParse->aIns;
+    rc = jsonLookupStep(pIns, 0, zTail, 0);
+    pParse->oom |= pIns->oom;
+  }
+  return rc;  /* Error code only */
+}
+
 /*
 ** Search along zPath to find the Json element specified.  Return an
 ** index into pParse->aBlob[] for the start of that element's value.
@@ -2135,6 +2201,13 @@ static void jsonBlobEdit(
 ** label, before returning.
 **
 ** Return one of the JSON_LOOKUP error codes if problems are seen.
+**
+** This routine will also modify the blob.  If pParse->eEdit is one of
+** JEDIT_DEL, JEDIT_REPL, JEDIT_INS, or JEDIT_SET, then changes might be
+** made to the selected value.  If an edit is performed, then the return
+** value does not necessarily point to the select element.  If an edit
+** is performed, the return value is only useful for detecting error
+** conditions.
 */
 static u32 jsonLookupStep(
   JsonParse *pParse,      /* The JSON to search */
@@ -2145,7 +2218,6 @@ static u32 jsonLookupStep(
   u32 i, j, k, nKey, sz, n, iEnd, rc;
   const char *zKey;
   u8 x;
-  static const u8 emptyObject[] = { JSONB_ARRAY, JSONB_OBJECT };
 
   if( zPath[0]==0 ){
     if( pParse->eEdit && jsonBlobMakeEditable(pParse, pParse->nIns) ){
@@ -2224,26 +2296,12 @@ static u32 jsonLookupStep(
       testcase( pParse->eEdit==JEDIT_SET );
       memset(&ix, 0, sizeof(ix));
       jsonBlobAppendNode(&ix,JSONB_TEXTRAW, nKey, 0);
-      memset(&v, 0, sizeof(v));
-      if( zPath[i]==0 ){
-        v.nBlob = pParse->nIns;
-        v.aBlob = pParse->aIns;
-      }else{
-        v.nBlob = 1;
-        v.aBlob = (u8*)&emptyObject[zPath[i]=='.'];
-        v.eEdit = pParse->eEdit;
-        v.nIns = pParse->nIns;
-        v.aIns = pParse->aIns;
-        rc = jsonLookupStep(&v, 0, &zPath[i], 0);
-        if( JSON_LOOKUP_ISERROR(rc) || v.oom ){
-          pParse->oom |= v.oom;
-          jsonParseReset(&v);
-          jsonParseReset(&ix);
-          return rc;
-        }
-      }
       pParse->oom |= ix.oom;
-      if( jsonBlobMakeEditable(pParse, ix.nBlob+nKey+v.nBlob) ){
+      rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i]);
+      if( !JSON_LOOKUP_ISERROR(rc)
+       && jsonBlobMakeEditable(pParse, ix.nBlob+nKey+v.nBlob)
+      ){
+        assert( !pParse->oom );
         nIns = ix.nBlob + nKey + v.nBlob;
         jsonBlobEdit(pParse, j, 0, 0, nIns);
         if( !pParse->oom ){
@@ -2257,7 +2315,7 @@ static u32 jsonLookupStep(
       }
       jsonParseReset(&v);
       jsonParseReset(&ix);
-      return j;
+      return rc;
     }
   }else if( zPath[0]=='[' ){
     x = pParse->aBlob[iRoot] & 0x0f;
@@ -2309,29 +2367,16 @@ static u32 jsonLookupStep(
       JsonParse v;
       testcase( pParse->eEdit==JEDIT_INS );
       testcase( pParse->eEdit==JEDIT_SET );
-      memset(&v, 0, sizeof(v));
-      if( zPath[i+1]==0 ){
-        v.aBlob = pParse->aIns;
-        v.nBlob = pParse->nIns;
-      }else{
-        v.nBlob = 1;
-        v.aBlob = (u8*)&emptyObject[zPath[i+1]=='.'];
-        v.eEdit = pParse->eEdit;
-        v.nIns = pParse->nIns;
-        v.aIns = pParse->aIns;
-        rc = jsonLookupStep(&v, 0, &zPath[i+1], 0);
-        if( JSON_LOOKUP_ISERROR(rc) || v.oom ){
-          pParse->oom |= v.oom;
-          jsonParseReset(&v);
-          return rc;
-        }
-      }
-      if( jsonBlobMakeEditable(pParse, v.nBlob) ){
+      rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i+1]);
+      if( !JSON_LOOKUP_ISERROR(rc)
+       && jsonBlobMakeEditable(pParse, v.nBlob)
+      ){
+        assert( !pParse->oom );
         jsonBlobEdit(pParse, j, 0, v.aBlob, v.nBlob);
       }
       jsonParseReset(&v);
       if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
-      return j;
+      return rc;
     }
   }else{
     return JSON_LOOKUP_PATHERROR; 
@@ -3169,17 +3214,7 @@ static void jsonArrayLengthFunc(
     i = 0;
   }
   if( (p->aBlob[i] & 0x0f)==JSONB_ARRAY ){
-    u32 n, sz = 0, iEnd;
-    n = jsonbPayloadSize(p, i, &sz);
-    if( n==0 ) eErr = 2;
-    iEnd = i+n+sz;
-    i += n;
-    while( eErr==0 && i<iEnd ){
-      cnt++;
-      n = jsonbPayloadSize(p, i, &sz);
-      if( n==0 ) eErr = 2;
-      i += n+sz;
-    }
+    cnt = jsonbArrayCount(p, i);
   }
   if( eErr ){
     if( eErr==2 ) sqlite3_result_error(ctx, "malformed JSON", -1);