]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Generate the fullkey and path columns of json_tree().
authordrh <>
Sat, 25 Nov 2023 18:11:11 +0000 (18:11 +0000)
committerdrh <>
Sat, 25 Nov 2023 18:11:11 +0000 (18:11 +0000)
FossilOrigin-Name: ffaa468ab8871906121df9ee5ef3dc00129a0086ed9c18831ecda69bf7f71455

manifest
manifest.uuid
src/json.c

index b7f38de8534313a29990a588168e00965406bd0c..af86c512c2a24e8abb2b7bae2a350c3a5a2d9be3 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Handle\sthe\spath\sargument\sto\sjson_tree()\sand\sjson_each().
-D 2023-11-25T13:40:19.363
+C Generate\sthe\sfullkey\sand\spath\scolumns\sof\sjson_tree().
+D 2023-11-25T18:11:11.468
 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 ff48d52463493f5f40d6e1e14ac3dc9277c40290df140a52bd17e7a562f766ea
+F src/json.c 9a5ff28f7b55e83b92eeab9285eb4b0132f11526620565e2d5b81fb84d4e8611
 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 3df891cb11feee65e239ee2506eda34a9688341f05210d7c2e25a05338cb71ad
-R 86973d4c807995bd645f2f5dbc7eac48
+P fded888469565b2a4687185a926bd23fccfbf167c8bebe6c10696fc7f972f41e
+R 90c664426338898baffedf8dcba41bea
 U drh
-Z e2d0e1a86b5ddc3117954e8a28079ed7
+Z e9b6e925dfee6d388855b55f2b458a4c
 # Remove this line to create a well-formed Fossil manifest.
index 555d0938d3da92d086e39dd6fb17108fd0fb9674..acd1f46af163c7fa70c7be0fe18de8f2ba5fad50 100644 (file)
@@ -1 +1 @@
-fded888469565b2a4687185a926bd23fccfbf167c8bebe6c10696fc7f972f41e
\ No newline at end of file
+ffaa468ab8871906121df9ee5ef3dc00129a0086ed9c18831ecda69bf7f71455
\ No newline at end of file
index 503fff93682b435d82029eae620c8acb44506ff3..c8269436eb7c8c83ea6b4cd9b0761697c1bb2e0d 100644 (file)
@@ -796,7 +796,6 @@ static void jsonAppendSqlValue(
   }
 }
 
-
 /* Make the text in p (which is probably a generated JSON text string)
 ** the result of the SQL function.
 **
@@ -5580,6 +5579,7 @@ struct JsonParent {
   u32 iHead;                 /* Start of object or array */
   u32 iValue;                /* Start of the value */
   u32 iEnd;                  /* First byte past the end */
+  u32 nPath;                 /* Length of path */
   i64 iKey;                  /* Key for JSONB_ARRAY */
 };
 
@@ -5598,6 +5598,7 @@ struct JsonEachCursor {
   char *zJson;               /* Input JSON */
   char *zRoot;               /* Path by which to filter zJson */
   sqlite3 *db;               /* Database connection */
+  JsonString path;           /* Current path */
   JsonParse sParse;          /* Parse of the input JSON */
 };
 typedef struct JsonEachConnection JsonEachConnection;
@@ -5666,6 +5667,7 @@ static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
   if( pCur==0 ) return SQLITE_NOMEM;
   memset(pCur, 0, sizeof(*pCur));
   pCur->db = pVtab->db;
+  jsonStringZero(&pCur->path);
   *ppCursor = &pCur->base;
   return SQLITE_OK;
 }
@@ -5685,6 +5687,7 @@ static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
 static void jsonEachCursorReset(JsonEachCursor *p){
   sqlite3_free(p->zRoot);
   jsonParseReset(&p->sParse);
+  jsonStringReset(&p->path);
   sqlite3DbFree(p->db, p->aParent);
   p->iRowid = 0;
   p->i = 0;
@@ -5701,6 +5704,7 @@ static void jsonEachCursorReset(JsonEachCursor *p){
 static int jsonEachClose(sqlite3_vtab_cursor *cur){
   JsonEachCursor *p = (JsonEachCursor*)cur;
   jsonEachCursorReset(p);
+  
   sqlite3_free(cur);
   return SQLITE_OK;
 }
@@ -5727,6 +5731,39 @@ static int jsonSkipLabel(JsonEachCursor *p){
   }
 }
 
+/*
+** Append the path name for the current element.
+*/
+static void jsonAppendPathName(JsonEachCursor *p){
+  assert( p->nParent>0 );
+  assert( p->eType==JSONB_ARRAY || p->eType==JSONB_OBJECT );
+  if( p->eType==JSONB_ARRAY ){
+    jsonPrintf(30, &p->path, "[%lld]", p->aParent[p->nParent-1].iKey);
+  }else{
+    u32 n, sz = 0, k, i;
+    const char *z;
+    int needQuote = 0;
+    n = jsonbPayloadSize(&p->sParse, p->i, &sz);
+    k = p->i + n;
+    z = (const char*)&p->sParse.aBlob[k];
+    if( sz==0 || !sqlite3Isalpha(z[0]) ){
+      needQuote = 1;
+    }else{
+      for(i=0; i<sz; i++){
+        if( !sqlite3Isalnum(z[i]) ){
+          needQuote = 1;
+          break;
+        }
+      }
+    }
+    if( needQuote ){
+      jsonPrintf(sz+4,&p->path,".\"%.*s\"", sz, z);
+    }else{
+      jsonPrintf(sz+2,&p->path,".%.*s", sz, z);
+    }
+  }
+}
+
 /* Advance the cursor to the next element for json_tree() */
 static int jsonEachNext(sqlite3_vtab_cursor *cur){
   JsonEachCursor *p = (JsonEachCursor*)cur;
@@ -5789,17 +5826,21 @@ static int jsonEachNext(sqlite3_vtab_cursor *cur){
         p->aParent = pNew;
       }
       levelChange = 1;
-      pParent = &p->aParent[p->nParent++];
+      pParent = &p->aParent[p->nParent];
       pParent->iHead = p->i;
       pParent->iValue = i;
       pParent->iEnd = i + n + sz;
       pParent->iKey = -1;
+      pParent->nPath = (u32)p->path.nUsed;
+      if( p->eType && p->nParent ) jsonAppendPathName(p);
+      p->nParent++;
       p->i = i + n;
     }else{
       p->i = i + n + sz;
     }
     while( p->nParent>0 && p->i >= p->aParent[p->nParent-1].iEnd ){
       p->nParent--;
+      p->path.nUsed = p->aParent[p->nParent].nPath;
       levelChange = 1;
     }
     if( levelChange ){
@@ -6034,53 +6075,16 @@ static int jsonEachColumn(
         break;
       }
       case JEACH_FULLKEY: {
-#if 0
-        u32 i;
-        JsonString x;
-        jsonStringInit(&x, ctx);
-        for(i=0; i<p->nParent; i++){
-          jsonPrintf(200,&x,"(%u,%u,%u,%lld)",
-             p->aParent[i].iHead,
-             p->aParent[i].iValue,
-             p->aParent[i].iEnd,
-             p->aParent[i].iKey);
-        }
-        jsonReturnString(&x);
-#endif
-#if 0
-        JsonString x;
-        jsonStringInit(&x, ctx);
-        if( p->bRecursive ){
-          jsonEachComputePath(p, &x, p->i);
-        }else{
-          if( p->zRoot ){
-            jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot));
-          }else{
-            jsonAppendChar(&x, '$');
-          }
-          if( p->eType==JSON_ARRAY ){
-            jsonPrintf(30, &x, "[%d]", p->iRowid);
-          }else if( p->eType==JSON_OBJECT ){
-            jsonAppendObjectPathElementOfNode(&x, pThis);
-          }
-        }
-        jsonReturnString(&x);
-#endif
+        u64 nBase = p->path.nUsed;
+        if( p->nParent ) jsonAppendPathName(p);
+        sqlite3_result_text64(ctx, p->path.zBuf, p->path.nUsed,
+                              SQLITE_TRANSIENT, SQLITE_UTF8);
+        p->path.nUsed = nBase;
         break;
       }
       case JEACH_PATH: {
-#if 0
-        if( p->bRecursive ){
-          JsonString x;
-          jsonStringInit(&x, ctx);
-          jsonEachComputePath(p, &x, p->sParse.aUp[p->i]);
-          jsonReturnString(&x);
-          break;
-        }
-        /* For json_each() path and root are the same so fall through
-        ** into the root case */
-        /* no break */ deliberate_fall_through
-#endif
+        sqlite3_result_text64(ctx, p->path.zBuf, p->path.nUsed,
+                              SQLITE_TRANSIENT, SQLITE_UTF8);
         break;
       }
       default: {
@@ -6209,10 +6213,6 @@ static int jsonEachFilter(
     if( idxNum==3 ){
       zRoot = (const char*)sqlite3_value_text(argv[1]);
       if( zRoot==0 ) return SQLITE_OK;
-      n = sqlite3_value_bytes(argv[1]);
-      p->zRoot = sqlite3_malloc64( n+1 );
-      if( p->zRoot==0 ) return SQLITE_NOMEM;
-      memcpy(p->zRoot, zRoot, (size_t)n+1);
       if( zRoot[0]!='$' ){
         sqlite3_free(cur->pVtab->zErrMsg);
         cur->pVtab->zErrMsg = jsonPathSyntaxError(zRoot, 0);
@@ -6223,7 +6223,7 @@ static int jsonEachFilter(
         i = p->i = 0;
         p->eType = 0;
       }else{
-        i = jsonLookupBlobStep(&p->sParse, 0, p->zRoot+1, 0);
+        i = jsonLookupBlobStep(&p->sParse, 0, zRoot+1, 0);
         if( JSON_BLOB_ISERROR(i) ){
           p->i = 0;
           p->eType = 0;
@@ -6238,9 +6238,11 @@ static int jsonEachFilter(
           p->eType = JSONB_ARRAY;
         }
       }
+      jsonAppendRaw(&p->path, zRoot, sqlite3Strlen30(zRoot));
     }else{
       i = p->i = 0;
       p->eType = 0;
+      jsonAppendRaw(&p->path, "$", 1);
     }
     p->nParent = 0;
     p->sParse.isBinary = 1;