]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Reorganize the code to put the new JSONB routines together, for easier editing.
authordrh <>
Thu, 21 Sep 2023 18:16:35 +0000 (18:16 +0000)
committerdrh <>
Thu, 21 Sep 2023 18:16:35 +0000 (18:16 +0000)
FossilOrigin-Name: dc23e783d4147d363856abe109586fc79a5b535b492beee0cf7a0234c0210667

manifest
manifest.uuid
src/json.c

index 78b4dedcd2ef1d0f03b212b53a0b63ac4ab2c1e0..00ee965eeaef94b726937a05d163a92c7eadf361 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Initial\sdevelopment\scode\sfor\san\sexperimental\sbinary\sBLOB\sencoding\sfor\sJSON.
-D 2023-09-21T17:51:39.740
+C Reorganize\sthe\scode\sto\sput\sthe\snew\sJSONB\sroutines\stogether,\sfor\seasier\sediting.
+D 2023-09-21T18:16:35.240
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -670,7 +670,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 aa191fb04ff8b3857c2e05a51b347a23992807a2c12cda5247286ba4768075e7
+F src/json.c 909c1ed65cdff9745534ae31783b394c0412307af67392202c38eb4a5a051682
 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
 F src/loadext.c 98cfba10989b3da6f1807ad42444017742db7f100a54f1032af7a8b1295912c0
 F src/main.c 618aeb399e993cf561864f4b0cf6a331ee4f355cf663635f8d9da3193a46aa40
@@ -2121,11 +2121,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 f9d62b853ce8bfbfdc9f137e984e7a1b51d70e88c38b136b4fad1e8ae6ee8913
-R 707eaf997af5bd7aea243a294bfb17a0
-T *branch * jsonb
-T *sym-jsonb *
-T -sym-trunk *
+P 8131b3c272f47db2618886046a9713285ce120cb87d721484ee7444273290681
+R f3c29be4023c5b4b5aa9f93c4ce8cc1a
 U drh
-Z b6e8348ea42422278215287176b59cff
+Z 6a7efc86b292f902336443f2d5840fea
 # Remove this line to create a well-formed Fossil manifest.
index 37c7ebe3124484ea3a227487102240cc62cc6b22..00f1a8286b051a63bff2cb29420873b229096e35 100644 (file)
@@ -1 +1 @@
-8131b3c272f47db2618886046a9713285ce120cb87d721484ee7444273290681
\ No newline at end of file
+dc23e783d4147d363856abe109586fc79a5b535b492beee0cf7a0234c0210667
\ No newline at end of file
index c7c6becbd4fbf24ce16c943e6294556b20d5a7a1..9ea085753bfcaa747d029326045ffdbb4c32441e 100644 (file)
@@ -1779,6 +1779,33 @@ json_parse_restart:
   } /* End switch(z[i]) */
 }
 
+/* Mark node i of pParse as being a child of iParent.  Call recursively
+** to fill in all the descendants of node i.
+*/
+static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){
+  JsonNode *pNode = &pParse->aNode[i];
+  u32 j;
+  pParse->aUp[i] = iParent;
+  switch( pNode->eType ){
+    case JSON_ARRAY: {
+      for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){
+        jsonParseFillInParentage(pParse, i+j, i);
+      }
+      break;
+    }
+    case JSON_OBJECT: {
+      for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){
+        pParse->aUp[i+j] = i;
+        jsonParseFillInParentage(pParse, i+j+1, i);
+      }
+      break;
+    }
+    default: {
+      break;
+    }
+  }
+}
+
 /*
 ** Parse a complete JSON string.  Return 0 on success or non-zero if there
 ** are any errors.  If an error occurs, free all memory held by pParse,
@@ -1822,1120 +1849,1097 @@ static int jsonParse(
 }
 
 /*
-** Expand pParse->aBlob so that it holds at least N bytes.
-**
-** Return the number of errors.
+** Compute the parentage of all nodes in a completed parse.
 */
-static int jsonBlobExpand(JsonParse *pParse, u32 N){
-  u8 *aNew;
-  u32 t;
-  if( N<=pParse->nBlobAlloc ) return 0;
-  if( pParse->nBlobAlloc==0 ){
-    t = 100;
-  }else{
-    t = pParse->nBlobAlloc*2;
+static int jsonParseFindParents(JsonParse *pParse){
+  u32 *aUp;
+  assert( pParse->aUp==0 );
+  aUp = pParse->aUp = sqlite3_malloc64( sizeof(u32)*pParse->nNode );
+  if( aUp==0 ){
+    pParse->oom = 1;
+    return SQLITE_NOMEM;
   }
-  if( t<N ) t = N+100;
-  aNew = sqlite3_realloc64( pParse->aBlob, t );
-  if( aNew==0 ){ pParse->oom = 1; return 1; }
-  pParse->aBlob = aNew;
-  pParse->nBlobAlloc = t;
-  return 0;
+  jsonParseFillInParentage(pParse, 0, 0);
+  return SQLITE_OK;
 }
 
-/* Expand pParse->aBlob and append N bytes.
+/*
+** Magic number used for the JSON parse cache in sqlite3_get_auxdata()
+*/
+#define JSON_CACHE_ID  (-429938)  /* First cache entry */
+#define JSON_CACHE_SZ  4          /* Max number of cache entries */
+
+/*
+** Obtain a complete parse of the JSON found in the pJson argument
 **
-** Return the number of errors.
+** Use the sqlite3_get_auxdata() cache to find a preexisting parse
+** if it is available.  If the cache is not available or if it
+** is no longer valid, parse the JSON again and return the new parse.
+** Also register the new parse so that it will be available for
+** future sqlite3_get_auxdata() calls.
+**
+** If an error occurs and pErrCtx!=0 then report the error on pErrCtx
+** and return NULL.
+**
+** The returned pointer (if it is not NULL) is owned by the cache in
+** most cases, not the caller.  The caller does NOT need to invoke
+** jsonParseFree(), in most cases.
+**
+** Except, if an error occurs and pErrCtx==0 then return the JsonParse
+** object with JsonParse.nErr non-zero and the caller will own the JsonParse
+** object.  In that case, it will be the responsibility of the caller to
+** invoke jsonParseFree().  To summarize:
+**
+**   pErrCtx!=0 || p->nErr==0      ==>   Return value p is owned by the
+**                                       cache.  Call does not need to
+**                                       free it.
+**
+**   pErrCtx==0 && p->nErr!=0      ==>   Return value is owned by the caller
+**                                       and so the caller must free it.
 */
-static SQLITE_NOINLINE int jsonBlobExpandAndAppend(
-  JsonParse *pParse,
-  const u8 *aData,
-  u32 N
+static JsonParse *jsonParseCached(
+  sqlite3_context *pCtx,         /* Context to use for cache search */
+  sqlite3_value *pJson,          /* Function param containing JSON text */
+  sqlite3_context *pErrCtx,      /* Write parse errors here if not NULL */
+  int bUnedited                  /* No prior edits allowed */
 ){
-  if( jsonBlobExpand(pParse, pParse->nBlob+N) ) return 1;
-  memcpy(&pParse->aBlob[pParse->nBlob], aData, N);
-  pParse->nBlob += N;
-  return 0;
-}
+  char *zJson = (char*)sqlite3_value_text(pJson);
+  int nJson = sqlite3_value_bytes(pJson);
+  JsonParse *p;
+  JsonParse *pMatch = 0;
+  int iKey;
+  int iMinKey = 0;
+  u32 iMinHold = 0xffffffff;
+  u32 iMaxHold = 0;
+  int bJsonRCStr;
 
-/* Append a single character.  Return 1 if an error occurs.
-*/
-static int jsonBlobAppendOneByte(JsonParse *pParse, u8 c){
-  if( pParse->nBlob >= pParse->nBlobAlloc ){
-    return jsonBlobExpandAndAppend(pParse, &c, 1);
+  if( zJson==0 ) return 0;
+  for(iKey=0; iKey<JSON_CACHE_SZ; iKey++){
+    p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iKey);
+    if( p==0 ){
+      iMinKey = iKey;
+      break;
+    }
+    if( pMatch==0
+     && p->nJson==nJson
+     && (p->hasMod==0 || bUnedited==0)
+     && (p->zJson==zJson || memcmp(p->zJson,zJson,nJson)==0)
+    ){
+      p->nErr = 0;
+      p->useMod = 0;
+      pMatch = p;
+    }else
+    if( pMatch==0
+     && p->zAlt!=0
+     && bUnedited==0
+     && p->nAlt==nJson
+     && memcmp(p->zAlt, zJson, nJson)==0
+    ){
+      p->nErr = 0;
+      p->useMod = 1;
+      pMatch = p;
+    }else if( p->iHold<iMinHold ){
+      iMinHold = p->iHold;
+      iMinKey = iKey;
+    }
+    if( p->iHold>iMaxHold ){
+      iMaxHold = p->iHold;
+    }
+  }
+  if( pMatch ){
+    /* The input JSON text was found in the cache.  Use the preexisting
+    ** parse of this JSON */
+    pMatch->nErr = 0;
+    pMatch->iHold = iMaxHold+1;
+    assert( pMatch->nJPRef>0 ); /* pMatch is owned by the cache */
+    return pMatch;
   }
-  pParse->aBlob[pParse->nBlob++] = c;
-  return 0;
-}
 
-/* Append bytes.  Return 1 if an error occurs.
-*/
-static int jsonBlobAppendNBytes(JsonParse *pParse, const u8 *aData, u32 N){
-  if( pParse->nBlob+N > pParse->nBlobAlloc ){
-    return jsonBlobExpandAndAppend(pParse, aData, N);
+  /* The input JSON was not found anywhere in the cache.  We will need
+  ** to parse it ourselves and generate a new JsonParse object.
+  */
+  bJsonRCStr = sqlite3ValueIsOfClass(pJson,(void(*)(void*))sqlite3RCStrUnref);
+  p = sqlite3_malloc64( sizeof(*p) + (bJsonRCStr ? 0 : nJson+1) );
+  if( p==0 ){
+    sqlite3_result_error_nomem(pCtx);
+    return 0;
   }
-  memcpy(&pParse->aBlob[pParse->nBlob], aData, N);
-  pParse->nBlob += N;
-  return 0;
+  memset(p, 0, sizeof(*p));
+  if( bJsonRCStr ){
+    p->zJson = sqlite3RCStrRef(zJson);
+    p->bJsonIsRCStr = 1;
+  }else{
+    p->zJson = (char*)&p[1];
+    memcpy(p->zJson, zJson, nJson+1);
+  }
+  p->nJPRef = 1;
+  if( jsonParse(p, pErrCtx) ){
+    if( pErrCtx==0 ){
+      p->nErr = 1;
+      assert( p->nJPRef==1 ); /* Caller will own the new JsonParse object p */
+      return p;
+    }
+    jsonParseFree(p);
+    return 0;
+  }
+  p->nJson = nJson;
+  p->iHold = iMaxHold+1;
+  /* Transfer ownership of the new JsonParse to the cache */
+  sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p,
+                      (void(*)(void*))jsonParseFree);
+  return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey);
 }
 
-/* Append a u32.  Return 1 if an error occurs.
+/*
+** Compare the OBJECT label at pNode against zKey,nKey.  Return true on
+** a match.
 */
-static int jsonBlobAppendU32(JsonParse *pParse, u32 x){
-  u8 a[4];
-  a[3] = x & 0xff;
-  x >>= 8;
-  a[2] = x & 0xff;
-  x >>= 8;
-  a[1] = x & 0xff;
-  x >>= 8;
-  a[0] = x & 0xff;
-  return jsonBlobAppendNBytes(pParse, a, 4);
+static int jsonLabelCompare(const JsonNode *pNode, const char *zKey, u32 nKey){
+  assert( pNode->eU==1 );
+  if( pNode->jnFlags & JNODE_RAW ){
+    if( pNode->n!=nKey ) return 0;
+    return strncmp(pNode->u.zJContent, zKey, nKey)==0;
+  }else{
+    if( pNode->n!=nKey+2 ) return 0;
+    return strncmp(pNode->u.zJContent+1, zKey, nKey)==0;
+  }
 }
-
-/* Write a u32 and offset i.
-*/
-static int jsonBlobWriteU32(JsonParse *pParse, u32 x, u32 i){
-  u8 *a = &pParse->aBlob[i];
-  a[3] = x & 0xff;
-  x >>= 8;
-  a[2] = x & 0xff;
-  x >>= 8;
-  a[1] = x & 0xff;
-  x >>= 8;
-  a[0] = x & 0xff;
-  return 0;
+static int jsonSameLabel(const JsonNode *p1, const JsonNode *p2){
+  if( p1->jnFlags & JNODE_RAW ){
+    return jsonLabelCompare(p2, p1->u.zJContent, p1->n);
+  }else if( p2->jnFlags & JNODE_RAW ){
+    return jsonLabelCompare(p1, p2->u.zJContent, p2->n);
+  }else{
+    return p1->n==p2->n && strncmp(p1->u.zJContent,p2->u.zJContent,p1->n)==0;
+  }
 }
 
-/* Append a VarInt.  Return 1 if an error occurs.
+/* forward declaration */
+static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**);
+
+/*
+** Search along zPath to find the node specified.  Return a pointer
+** to that node, or NULL if zPath is malformed or if there is no such
+** node.
+**
+** If pApnd!=0, then try to append new nodes to complete zPath if it is
+** possible to do so and if no existing node corresponds to zPath.  If
+** new nodes are appended *pApnd is set to 1.
 */
-static int jsonBlobAppendVarint(JsonParse *pParse, u32 x){
-  u8 a[5];
-  if( x<=0x7f ) return jsonBlobAppendOneByte(pParse, x & 0x7f);
-  a[0] = 0x80 | (x & 0x7f);
-  x >>= 7;
-  a[1] = x & 0x7f;
-  x >>= 7;
-  if( x==0 ) return jsonBlobAppendNBytes(pParse, a, 2);
-  a[1] |= 0x80;
-  a[2] = x & 0x7f;
-  x >>= 7;
-  if( x==0 ) return jsonBlobAppendNBytes(pParse, a, 3);
-  a[2] |= 0x80;
-  a[3] = x & 0x7f;
-  x >>= 7;
-  if( x==0 ) return jsonBlobAppendNBytes(pParse, a, 4);
-  a[3] |= 0x80;
-  a[4] = x & 0x7f;
-  return jsonBlobAppendNBytes(pParse, a, 5);
-}
-
-/*
-** Parse a single JSON text value which begins at pParse->zJson[i] into
-** its equivalent BLOB representation in pParse->aBlob[].  The parse is
-** appended to pParse->aBlob[] beginning at pParse->nBlob.  The size of
-** pParse->aBlob[] is increased as necessary.
-**
-** Return the index of the first character past the end of the value parsed,
-** or one of the following special result codes:
-**
-**      0    End of input
-**     -1    Syntax error
-**     -2    '}' seen
-**     -3    ']' seen
-**     -4    ',' seen
-**     -5    ':' seen
-*/
-static int jsonParseValueB(JsonParse *pParse, u32 i){
-  char c;
-  u32 j;
-  int iThis;
-  int x;
-  u8 t;
-  const char *z = pParse->zJson;
-json_parse_restart:
-  switch( (u8)z[i] ){
-  case '{': {
-    /* Parse object */
-    jsonBlobAppendOneByte(pParse, JSONB_OBJECT);
-    iThis = pParse->nBlob;
-    jsonBlobAppendU32(pParse, 0);
-    if( ++pParse->iDepth > JSON_MAX_DEPTH ){
-      pParse->iErr = i;
-      return -1;
-    }
-    for(j=i+1;;j++){
-      u32 iBlob = pParse->nBlob;
-      x = jsonParseValueB(pParse, j);
-      if( x<=0 ){
-        if( x==(-2) ){
-          j = pParse->iErr;
-          if( pParse->nBlob!=(u32)iThis+1 ) pParse->hasNonstd = 1;
+static JsonNode *jsonLookupStep(
+  JsonParse *pParse,      /* The JSON to search */
+  u32 iRoot,              /* Begin the search at this node */
+  const char *zPath,      /* The path to search */
+  int *pApnd,             /* Append nodes to complete path if not NULL */
+  const char **pzErr      /* Make *pzErr point to any syntax error in zPath */
+){
+  u32 i, j, nKey;
+  const char *zKey;
+  JsonNode *pRoot;
+  if( pParse->oom ) return 0;
+  pRoot = &pParse->aNode[iRoot];
+  if( pRoot->jnFlags & (JNODE_REPLACE|JNODE_REMOVE) && pParse->useMod ){
+    while( (pRoot->jnFlags & JNODE_REPLACE)!=0 ){
+      u32 idx = (u32)(pRoot - pParse->aNode);
+      i = pParse->iSubst;
+      while( 1 /*exit-by-break*/ ){
+        assert( i<pParse->nNode );
+        assert( pParse->aNode[i].eType==JSON_SUBST );
+        assert( pParse->aNode[i].eU==4 );
+        assert( pParse->aNode[i].u.iPrev<i );
+        if( pParse->aNode[i].n==idx ){
+          pRoot = &pParse->aNode[i+1];
+          iRoot = i+1;
           break;
         }
-        j += json5Whitespace(&z[j]);
-        if( sqlite3JsonId1(z[j])
-         || (z[j]=='\\' && z[j+1]=='u' && jsonIs4Hex(&z[j+2]))
-        ){
-          int k = j+1;
-          while( (sqlite3JsonId2(z[k]) && json5Whitespace(&z[k])==0)
-            || (z[k]=='\\' && z[k+1]=='u' && jsonIs4Hex(&z[k+2]))
-          ){
-            k++;
-          }
-          assert( iBlob==pParse->nBlob );
-          jsonBlobAppendOneByte(pParse, JSONB_TEXT5);
-          jsonBlobAppendVarint(pParse, k-j);
-          jsonBlobAppendNBytes(pParse, (const u8*)&z[j], k-j);
-          pParse->hasNonstd = 1;
-          x = k;
-        }else{
-          if( x!=-1 ) pParse->iErr = j;
-          return -1;
-        }
-      }
-      if( pParse->oom ) return -1;
-      t = pParse->aBlob[iBlob];
-      if( t<JSONB_TEXT || t>JSONB_TEXT5 ){
-        pParse->iErr = j;
-        return -1;
+        i = pParse->aNode[i].u.iPrev;
       }
-      j = x;
-      if( z[j]==':' ){
-        j++;
+    }
+    if( pRoot->jnFlags & JNODE_REMOVE ){
+      return 0;
+    }
+  }
+  if( zPath[0]==0 ) return pRoot;
+  if( zPath[0]=='.' ){
+    if( pRoot->eType!=JSON_OBJECT ) return 0;
+    zPath++;
+    if( zPath[0]=='"' ){
+      zKey = zPath + 1;
+      for(i=1; zPath[i] && zPath[i]!='"'; i++){}
+      nKey = i-1;
+      if( zPath[i] ){
+        i++;
       }else{
-        if( fast_isspace(z[j]) ){
-          do{ j++; }while( fast_isspace(z[j]) );
-          if( z[j]==':' ){
-            j++;
-            goto parse_object_value;
-          }
-        }
-        x = jsonParseValueB(pParse, j);
-        if( x!=(-5) ){
-          if( x!=(-1) ) pParse->iErr = j;
-          return -1;
+        *pzErr = zPath;
+        return 0;
+      }
+      testcase( nKey==0 );
+    }else{
+      zKey = zPath;
+      for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){}
+      nKey = i;
+      if( nKey==0 ){
+        *pzErr = zPath;
+        return 0;
+      }
+    }
+    j = 1;
+    for(;;){
+      while( j<=pRoot->n ){
+        if( jsonLabelCompare(pRoot+j, zKey, nKey) ){
+          return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr);
         }
-        j = pParse->iErr+1;
+        j++;
+        j += jsonNodeSize(&pRoot[j]);
       }
-    parse_object_value:
-      x = jsonParseValueB(pParse, j);
-      if( x<=0 ){
-        if( x!=(-1) ) pParse->iErr = j;
-        return -1;
+      if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
+      if( pParse->useMod==0 ) break;
+      assert( pRoot->eU==2 );
+      iRoot = pRoot->u.iAppend;
+      pRoot = &pParse->aNode[iRoot];
+      j = 1;
+    }
+    if( pApnd ){
+      u32 iStart, iLabel;
+      JsonNode *pNode;
+      assert( pParse->useMod );
+      iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
+      iLabel = jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
+      zPath += i;
+      pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
+      if( pParse->oom ) return 0;
+      if( pNode ){
+        pRoot = &pParse->aNode[iRoot];
+        assert( pRoot->eU==0 );
+        pRoot->u.iAppend = iStart;
+        pRoot->jnFlags |= JNODE_APPEND;
+        VVA( pRoot->eU = 2 );
+        pParse->aNode[iLabel].jnFlags |= JNODE_RAW;
       }
-      j = x;
-      if( z[j]==',' ){
-        continue;
-      }else if( z[j]=='}' ){
-        break;
-      }else{
-        if( fast_isspace(z[j]) ){
-          do{ j++; }while( fast_isspace(z[j]) );
-          if( z[j]==',' ){
-            continue;
-          }else if( z[j]=='}' ){
-            break;
+      return pNode;
+    }
+  }else if( zPath[0]=='[' ){
+    i = 0;
+    j = 1;
+    while( sqlite3Isdigit(zPath[j]) ){
+      i = i*10 + zPath[j] - '0';
+      j++;
+    }
+    if( j<2 || zPath[j]!=']' ){
+      if( zPath[1]=='#' ){
+        JsonNode *pBase = pRoot;
+        int iBase = iRoot;
+        if( pRoot->eType!=JSON_ARRAY ) return 0;
+        for(;;){
+          while( j<=pBase->n ){
+            if( (pBase[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ) i++;
+            j += jsonNodeSize(&pBase[j]);
           }
+          if( (pBase->jnFlags & JNODE_APPEND)==0 ) break;
+          if( pParse->useMod==0 ) break;
+          assert( pBase->eU==2 );
+          iBase = pBase->u.iAppend;
+          pBase = &pParse->aNode[iBase];
+          j = 1;
         }
-        x = jsonParseValueB(pParse, j);
-        if( x==(-4) ){
-          j = pParse->iErr;
-          continue;
+        j = 2;
+        if( zPath[2]=='-' && sqlite3Isdigit(zPath[3]) ){
+          unsigned int x = 0;
+          j = 3;
+          do{
+            x = x*10 + zPath[j] - '0';
+            j++;
+          }while( sqlite3Isdigit(zPath[j]) );
+          if( x>i ) return 0;
+          i -= x;
         }
-        if( x==(-2) ){
-          j = pParse->iErr;
-          break;
+        if( zPath[j]!=']' ){
+          *pzErr = zPath;
+          return 0;
         }
+      }else{
+        *pzErr = zPath;
+        return 0;
       }
-      pParse->iErr = j;
-      return -1;
     }
-    jsonBlobWriteU32(pParse, pParse->nBlob - iThis, iThis);
-    pParse->iDepth--;
-    return j+1;
-  }
-  case '[': {
-    /* Parse array */
-    jsonBlobAppendOneByte(pParse, JSONB_ARRAY);
-    iThis = pParse->nBlob;
-    jsonBlobAppendU32(pParse, 0);
-    if( pParse->oom ) return -1;
-    if( ++pParse->iDepth > JSON_MAX_DEPTH ){
-      pParse->iErr = i;
-      return -1;
-    }
-    for(j=i+1;;j++){
-      x = jsonParseValueB(pParse, j);
-      if( x<=0 ){
-        if( x==(-3) ){
-          j = pParse->iErr;
-          if( pParse->nBlob!=iThis+4 ) pParse->hasNonstd = 1;
-          break;
-        }
-        if( x!=(-1) ) pParse->iErr = j;
-        return -1;
-      }
-      j = x;
-      if( z[j]==',' ){
-        continue;
-      }else if( z[j]==']' ){
-        break;
-      }else{
-        if( fast_isspace(z[j]) ){
-          do{ j++; }while( fast_isspace(z[j]) );
-          if( z[j]==',' ){
-            continue;
-          }else if( z[j]==']' ){
-            break;
-          }
-        }
-        x = jsonParseValueB(pParse, j);
-        if( x==(-4) ){
-          j = pParse->iErr;
-          continue;
-        }
-        if( x==(-3) ){
-          j = pParse->iErr;
-          break;
-        }
+    if( pRoot->eType!=JSON_ARRAY ) return 0;
+    zPath += j + 1;
+    j = 1;
+    for(;;){
+      while( j<=pRoot->n
+         && (i>0 || ((pRoot[j].jnFlags & JNODE_REMOVE)!=0 && pParse->useMod))
+      ){
+        if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ) i--;
+        j += jsonNodeSize(&pRoot[j]);
       }
-      pParse->iErr = j;
-      return -1;
+      if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
+      if( pParse->useMod==0 ) break;
+      assert( pRoot->eU==2 );
+      iRoot = pRoot->u.iAppend;
+      pRoot = &pParse->aNode[iRoot];
+      j = 1;
     }
-    jsonBlobWriteU32(pParse, pParse->nBlob - iThis, iThis);
-    pParse->iDepth--;
-    return j+1;
-  }
-  case '\'': {
-    u8 opcode;
-    char cDelim;
-    pParse->hasNonstd = 1;
-    opcode = JNODE_JSON5;
-    goto parse_string;
-  case '"':
-    /* Parse string */
-    opcode = JSONB_TEXT;
-  parse_string:
-    cDelim = z[i];
-    for(j=i+1; 1; j++){
-      if( jsonIsOk[(unsigned char)z[j]] ) continue;
-      c = z[j];
-      if( c==cDelim ){
-        break;
-      }else if( c=='\\' ){
-        c = z[++j];
-        if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
-           || c=='n' || c=='r' || c=='t'
-           || (c=='u' && jsonIs4Hex(&z[j+1])) ){
-          if( opcode==JSONB_TEXT ) opcode = JSONB_TEXTJ;
-        }else if( c=='\'' || c=='0' || c=='v' || c=='\n'
-           || (0xe2==(u8)c && 0x80==(u8)z[j+1]
-                && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2]))
-           || (c=='x' && jsonIs2Hex(&z[j+1])) ){
-          opcode = JSONB_TEXT5;
-          pParse->hasNonstd = 1;
-        }else if( c=='\r' ){
-          if( z[j+1]=='\n' ) j++;
-          opcode = JSONB_TEXT5;
-          pParse->hasNonstd = 1;
-        }else{
-          pParse->iErr = j;
-          return -1;
-        }
-      }else if( c<=0x1f ){
-        /* Control characters are not allowed in strings */
-        pParse->iErr = j;
-        return -1;
+    if( j<=pRoot->n ){
+      return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr);
+    }
+    if( i==0 && pApnd ){
+      u32 iStart;
+      JsonNode *pNode;
+      assert( pParse->useMod );
+      iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0);
+      pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
+      if( pParse->oom ) return 0;
+      if( pNode ){
+        pRoot = &pParse->aNode[iRoot];
+        assert( pRoot->eU==0 );
+        pRoot->u.iAppend = iStart;
+        pRoot->jnFlags |= JNODE_APPEND;
+        VVA( pRoot->eU = 2 );
       }
+      return pNode;
     }
-    jsonBlobAppendOneByte(pParse, opcode);
-    jsonBlobAppendVarint(pParse, j+1-i);
-    jsonBlobAppendNBytes(pParse, (const u8*)&z[i], j+1-i);
-    return j+1;
+  }else{
+    *pzErr = zPath;
   }
-  case 't': {
-    if( strncmp(z+i,"true",4)==0 && !sqlite3Isalnum(z[i+4]) ){
-      jsonBlobAppendOneByte(pParse, JSONB_TRUE);
-      return i+4;
-    }
-    pParse->iErr = i;
-    return -1;
+  return 0;
+}
+
+/*
+** Append content to pParse that will complete zPath.  Return a pointer
+** to the inserted node, or return NULL if the append fails.
+*/
+static JsonNode *jsonLookupAppend(
+  JsonParse *pParse,     /* Append content to the JSON parse */
+  const char *zPath,     /* Description of content to append */
+  int *pApnd,            /* Set this flag to 1 */
+  const char **pzErr     /* Make this point to any syntax error */
+){
+  *pApnd = 1;
+  if( zPath[0]==0 ){
+    jsonParseAddNode(pParse, JSON_NULL, 0, 0);
+    return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1];
   }
-  case 'f': {
-    if( strncmp(z+i,"false",5)==0 && !sqlite3Isalnum(z[i+5]) ){
-      jsonBlobAppendOneByte(pParse, JSONB_FALSE);
-      return i+5;
-    }
-    pParse->iErr = i;
-    return -1;
+  if( zPath[0]=='.' ){
+    jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
+  }else if( strncmp(zPath,"[0]",3)==0 ){
+    jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
+  }else{
+    return 0;
   }
-  case '+': {
-    u8 seenDP, seenE, jnFlags;
-    pParse->hasNonstd = 1;
-    jnFlags = 0;
-    goto parse_number;
-  case '.':
-    if( sqlite3Isdigit(z[i+1]) ){
-      pParse->hasNonstd = 1;
-      jnFlags = JNODE_JSON5;
-      seenE = 0;
-      seenDP = JSON_REAL;
-      goto parse_number_2;
-    }
-    pParse->iErr = i;
-    return -1;
-  case '-':
-  case '0':
-  case '1':
-  case '2':
-  case '3':
-  case '4':
-  case '5':
-  case '6':
-  case '7':
-  case '8':
-  case '9':
-    /* Parse number */
-    jnFlags = 0;
-  parse_number:
-    seenDP = JSON_INT;
-    seenE = 0;
-    assert( '-' < '0' );
-    assert( '+' < '0' );
-    assert( '.' < '0' );
-    c = z[i];
+  if( pParse->oom ) return 0;
+  return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr);
+}
 
-    if( c<='0' ){
-      if( c=='0' ){
-        if( (z[i+1]=='x' || z[i+1]=='X') && sqlite3Isxdigit(z[i+2]) ){
-          assert( seenDP==JSON_INT );
-          pParse->hasNonstd = 1;
-          jnFlags |= JNODE_JSON5;
-          for(j=i+3; sqlite3Isxdigit(z[j]); j++){}
-          goto parse_number_finish;
-        }else if( sqlite3Isdigit(z[i+1]) ){
-          pParse->iErr = i+1;
-          return -1;
-        }
-      }else{
-        if( !sqlite3Isdigit(z[i+1]) ){
-          /* JSON5 allows for "+Infinity" and "-Infinity" using exactly
-          ** that case.  SQLite also allows these in any case and it allows
-          ** "+inf" and "-inf". */
-          if( (z[i+1]=='I' || z[i+1]=='i')
-           && sqlite3StrNICmp(&z[i+1], "inf",3)==0
-          ){
-            pParse->hasNonstd = 1;
-            jsonBlobAppendOneByte(pParse, JSONB_NUMBER5);
-            if( z[i]=='-' ){
-              jsonBlobAppendVarint(pParse, 8);
-              jsonBlobAppendNBytes(pParse, (const u8*)"-9.0e999", 8);
-            }else{
-              jsonBlobAppendVarint(pParse, 7);
-              jsonBlobAppendNBytes(pParse, (const u8*)"9.0e999", 7);
-            }
-            return i + (sqlite3StrNICmp(&z[i+4],"inity",5)==0 ? 9 : 4);
-          }
-          if( z[i+1]=='.' ){
-            pParse->hasNonstd = 1;
-            jnFlags |= JNODE_JSON5;
-            goto parse_number_2;
-          }
-          pParse->iErr = i;
-          return -1;
-        }
-        if( z[i+1]=='0' ){
-          if( sqlite3Isdigit(z[i+2]) ){
-            pParse->iErr = i+1;
-            return -1;
-          }else if( (z[i+2]=='x' || z[i+2]=='X') && sqlite3Isxdigit(z[i+3]) ){
-            pParse->hasNonstd = 1;
-            jnFlags |= JNODE_JSON5;
-            for(j=i+4; sqlite3Isxdigit(z[j]); j++){}
-            goto parse_number_finish;
-          }
-        }
-      }
-    }
-  parse_number_2:
-    for(j=i+1;; j++){
-      c = z[j];
-      if( sqlite3Isdigit(c) ) continue;
-      if( c=='.' ){
-        if( seenDP==JSON_REAL ){
-          pParse->iErr = j;
-          return -1;
-        }
-        seenDP = JSON_REAL;
-        continue;
-      }
-      if( c=='e' || c=='E' ){
-        if( z[j-1]<'0' ){
-          if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){
-            pParse->hasNonstd = 1;
-            jnFlags |= JNODE_JSON5;
-          }else{
-            pParse->iErr = j;
-            return -1;
-          }
-        }
-        if( seenE ){
-          pParse->iErr = j;
-          return -1;
-        }
-        seenDP = JSON_REAL;
-        seenE = 1;
-        c = z[j+1];
-        if( c=='+' || c=='-' ){
-          j++;
-          c = z[j+1];
-        }
-        if( c<'0' || c>'9' ){
-          pParse->iErr = j;
-          return -1;
-        }
-        continue;
-      }
-      break;
-    }
-    if( z[j-1]<'0' ){
-      if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){
-        pParse->hasNonstd = 1;
-        jnFlags |= JNODE_JSON5;
-      }else{
-        pParse->iErr = j;
-        return -1;
-      }
-    }
-  parse_number_finish:
-    if( jnFlags & JNODE_JSON5 ){
-      jsonBlobAppendOneByte(pParse, JSONB_NUMBER5);
-    }else{
-      jsonBlobAppendOneByte(pParse, JSONB_NUMBER);
-    }
-    jsonBlobAppendVarint(pParse, j-i);
-    jsonBlobAppendNBytes(pParse, (const u8*)&z[i], j-i);
-    return j;
-  }
-  case '}': {
-    pParse->iErr = i;
-    return -2;  /* End of {...} */
-  }
-  case ']': {
-    pParse->iErr = i;
-    return -3;  /* End of [...] */
-  }
-  case ',': {
-    pParse->iErr = i;
-    return -4;  /* List separator */
-  }
-  case ':': {
-    pParse->iErr = i;
-    return -5;  /* Object label/value separator */
-  }
-  case 0: {
-    return 0;   /* End of file */
-  }
-  case 0x09:
-  case 0x0a:
-  case 0x0d:
-  case 0x20: {
-    do{
-      i++;
-    }while( fast_isspace(z[i]) );
-    goto json_parse_restart;
-  }
-  case 0x0b:
-  case 0x0c:
-  case '/':
-  case 0xc2:
-  case 0xe1:
-  case 0xe2:
-  case 0xe3:
-  case 0xef: {
-    j = json5Whitespace(&z[i]);
-    if( j>0 ){
-      i += j;
-      pParse->hasNonstd = 1;
-      goto json_parse_restart;
-    }
-    pParse->iErr = i;
-    return -1;
-  }
-  case 'n': {
-    if( strncmp(z+i,"null",4)==0 && !sqlite3Isalnum(z[i+4]) ){
-      jsonBlobAppendOneByte(pParse, JSONB_NULL);
-      return i+4;
-    }
-    /* fall-through into the default case that checks for NaN */
-  }
-  default: {
-    u32 k;
-    int nn;
-    c = z[i];
-    for(k=0; k<sizeof(aNanInfName)/sizeof(aNanInfName[0]); k++){
-      if( c!=aNanInfName[k].c1 && c!=aNanInfName[k].c2 ) continue;
-      nn = aNanInfName[k].n;
-      if( sqlite3StrNICmp(&z[i], aNanInfName[k].zMatch, nn)!=0 ){
-        continue;
-      }
-      if( sqlite3Isalnum(z[i+nn]) ) continue;
-      if( aNanInfName[k].eType==JSON_REAL ){
-        jsonBlobAppendOneByte(pParse, JSONB_NUMBER);
-        jsonBlobAppendOneByte(pParse, 7);
-        jsonBlobAppendNBytes(pParse, (const u8*)"9.0e999", 7);
-      }else{
-        jsonBlobAppendOneByte(pParse, JSONB_NULL);
-      }
-      pParse->hasNonstd = 1;
-      return i + nn;
-    }
-    pParse->iErr = i;
-    return -1;  /* Syntax error */
-  }
-  } /* End switch(z[i]) */
-}
-
-
-/* Mark node i of pParse as being a child of iParent.  Call recursively
-** to fill in all the descendants of node i.
+/*
+** Return the text of a syntax error message on a JSON path.  Space is
+** obtained from sqlite3_malloc().
 */
-static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){
-  JsonNode *pNode = &pParse->aNode[i];
-  u32 j;
-  pParse->aUp[i] = iParent;
-  switch( pNode->eType ){
-    case JSON_ARRAY: {
-      for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){
-        jsonParseFillInParentage(pParse, i+j, i);
-      }
-      break;
-    }
-    case JSON_OBJECT: {
-      for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){
-        pParse->aUp[i+j] = i;
-        jsonParseFillInParentage(pParse, i+j+1, i);
-      }
-      break;
-    }
-    default: {
-      break;
-    }
-  }
+static char *jsonPathSyntaxError(const char *zErr){
+  return sqlite3_mprintf("JSON path error near '%q'", zErr);
 }
 
 /*
-** Parse a complete JSON string.  Return 0 on success or non-zero if there
-** are any errors.  If an error occurs, free all memory held by pParse,
-** but not pParse itself.
+** Do a node lookup using zPath.  Return a pointer to the node on success.
+** Return NULL if not found or if there is an error.
 **
-** pParse must be initialized to an empty parse object prior to calling
-** this routine.
+** On an error, write an error message into pCtx and increment the
+** pParse->nErr counter.
+**
+** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if
+** nodes are appended.
 */
-static int jsonParseB(
-  JsonParse *pParse,           /* Initialize and fill this JsonParse object */
-  sqlite3_context *pCtx        /* Report errors here */
+static JsonNode *jsonLookup(
+  JsonParse *pParse,      /* The JSON to search */
+  const char *zPath,      /* The path to search */
+  int *pApnd,             /* Append nodes to complete path if not NULL */
+  sqlite3_context *pCtx   /* Report errors here, if not NULL */
 ){
-  int i;
-  const char *zJson = pParse->zJson;
-  jsonBlobAppendOneByte(pParse, 0x4a);
-  jsonBlobAppendOneByte(pParse, 0x01);
-  i = jsonParseValueB(pParse, 0);
-  if( pParse->oom ) i = -1;
-  if( i>0 ){
-    assert( pParse->iDepth==0 );
-    while( fast_isspace(zJson[i]) ) i++;
-    if( zJson[i] ){
-      i += json5Whitespace(&zJson[i]);
-      if( zJson[i] ){
-        jsonParseReset(pParse);
-        return 1;
-      }
-      pParse->hasNonstd = 1;
-    }
+  const char *zErr = 0;
+  JsonNode *pNode = 0;
+  char *zMsg;
+
+  if( zPath==0 ) return 0;
+  if( zPath[0]!='$' ){
+    zErr = zPath;
+    goto lookup_err;
   }
-  if( i<=0 ){
-    if( pCtx!=0 ){
-      if( pParse->oom ){
-        sqlite3_result_error_nomem(pCtx);
-      }else{
-        sqlite3_result_error(pCtx, "malformed JSON", -1);
-      }
-    }
-    jsonParseReset(pParse);
-    return 1;
+  zPath++;
+  pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr);
+  if( zErr==0 ) return pNode;
+
+lookup_err:
+  pParse->nErr++;
+  assert( zErr!=0 && pCtx!=0 );
+  zMsg = jsonPathSyntaxError(zErr);
+  if( zMsg ){
+    sqlite3_result_error(pCtx, zMsg, -1);
+    sqlite3_free(zMsg);
+  }else{
+    sqlite3_result_error_nomem(pCtx);
   }
   return 0;
 }
 
-/*
-** Compute the parentage of all nodes in a completed parse.
-*/
-static int jsonParseFindParents(JsonParse *pParse){
-  u32 *aUp;
-  assert( pParse->aUp==0 );
-  aUp = pParse->aUp = sqlite3_malloc64( sizeof(u32)*pParse->nNode );
-  if( aUp==0 ){
-    pParse->oom = 1;
-    return SQLITE_NOMEM;
-  }
-  jsonParseFillInParentage(pParse, 0, 0);
-  return SQLITE_OK;
-}
 
 /*
-** Magic number used for the JSON parse cache in sqlite3_get_auxdata()
+** Report the wrong number of arguments for json_insert(), json_replace()
+** or json_set().
 */
-#define JSON_CACHE_ID  (-429938)  /* First cache entry */
-#define JSON_CACHE_SZ  4          /* Max number of cache entries */
-
-/*
-** Obtain a complete parse of the JSON found in the pJson argument
-**
-** Use the sqlite3_get_auxdata() cache to find a preexisting parse
-** if it is available.  If the cache is not available or if it
-** is no longer valid, parse the JSON again and return the new parse.
-** Also register the new parse so that it will be available for
-** future sqlite3_get_auxdata() calls.
-**
-** If an error occurs and pErrCtx!=0 then report the error on pErrCtx
-** and return NULL.
-**
-** The returned pointer (if it is not NULL) is owned by the cache in
-** most cases, not the caller.  The caller does NOT need to invoke
-** jsonParseFree(), in most cases.
-**
-** Except, if an error occurs and pErrCtx==0 then return the JsonParse
-** object with JsonParse.nErr non-zero and the caller will own the JsonParse
-** object.  In that case, it will be the responsibility of the caller to
-** invoke jsonParseFree().  To summarize:
-**
-**   pErrCtx!=0 || p->nErr==0      ==>   Return value p is owned by the
-**                                       cache.  Call does not need to
-**                                       free it.
-**
-**   pErrCtx==0 && p->nErr!=0      ==>   Return value is owned by the caller
-**                                       and so the caller must free it.
-*/
-static JsonParse *jsonParseCached(
-  sqlite3_context *pCtx,         /* Context to use for cache search */
-  sqlite3_value *pJson,          /* Function param containing JSON text */
-  sqlite3_context *pErrCtx,      /* Write parse errors here if not NULL */
-  int bUnedited                  /* No prior edits allowed */
+static void jsonWrongNumArgs(
+  sqlite3_context *pCtx,
+  const char *zFuncName
 ){
-  char *zJson = (char*)sqlite3_value_text(pJson);
-  int nJson = sqlite3_value_bytes(pJson);
-  JsonParse *p;
-  JsonParse *pMatch = 0;
-  int iKey;
-  int iMinKey = 0;
-  u32 iMinHold = 0xffffffff;
-  u32 iMaxHold = 0;
-  int bJsonRCStr;
+  char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments",
+                               zFuncName);
+  sqlite3_result_error(pCtx, zMsg, -1);
+  sqlite3_free(zMsg);
+}
 
-  if( zJson==0 ) return 0;
-  for(iKey=0; iKey<JSON_CACHE_SZ; iKey++){
-    p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iKey);
-    if( p==0 ){
-      iMinKey = iKey;
-      break;
-    }
-    if( pMatch==0
-     && p->nJson==nJson
-     && (p->hasMod==0 || bUnedited==0)
-     && (p->zJson==zJson || memcmp(p->zJson,zJson,nJson)==0)
-    ){
-      p->nErr = 0;
-      p->useMod = 0;
-      pMatch = p;
-    }else
-    if( pMatch==0
-     && p->zAlt!=0
-     && bUnedited==0
-     && p->nAlt==nJson
-     && memcmp(p->zAlt, zJson, nJson)==0
-    ){
-      p->nErr = 0;
-      p->useMod = 1;
-      pMatch = p;
-    }else if( p->iHold<iMinHold ){
-      iMinHold = p->iHold;
-      iMinKey = iKey;
-    }
-    if( p->iHold>iMaxHold ){
-      iMaxHold = p->iHold;
+/*
+** Mark all NULL entries in the Object passed in as JNODE_REMOVE.
+*/
+static void jsonRemoveAllNulls(JsonNode *pNode){
+  int i, n;
+  assert( pNode->eType==JSON_OBJECT );
+  n = pNode->n;
+  for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){
+    switch( pNode[i].eType ){
+      case JSON_NULL:
+        pNode[i].jnFlags |= JNODE_REMOVE;
+        break;
+      case JSON_OBJECT:
+        jsonRemoveAllNulls(&pNode[i]);
+        break;
     }
   }
-  if( pMatch ){
-    /* The input JSON text was found in the cache.  Use the preexisting
-    ** parse of this JSON */
-    pMatch->nErr = 0;
-    pMatch->iHold = iMaxHold+1;
-    assert( pMatch->nJPRef>0 ); /* pMatch is owned by the cache */
-    return pMatch;
-  }
+}
 
-  /* The input JSON was not found anywhere in the cache.  We will need
-  ** to parse it ourselves and generate a new JsonParse object.
-  */
-  bJsonRCStr = sqlite3ValueIsOfClass(pJson,(void(*)(void*))sqlite3RCStrUnref);
-  p = sqlite3_malloc64( sizeof(*p) + (bJsonRCStr ? 0 : nJson+1) );
-  if( p==0 ){
-    sqlite3_result_error_nomem(pCtx);
-    return 0;
-  }
-  memset(p, 0, sizeof(*p));
-  if( bJsonRCStr ){
-    p->zJson = sqlite3RCStrRef(zJson);
-    p->bJsonIsRCStr = 1;
+/****************************************************************************
+** Utility routines for dealing with the binary BLOB representation of JSON
+****************************************************************************/
+
+
+/*
+** Expand pParse->aBlob so that it holds at least N bytes.
+**
+** Return the number of errors.
+*/
+static int jsonBlobExpand(JsonParse *pParse, u32 N){
+  u8 *aNew;
+  u32 t;
+  if( N<=pParse->nBlobAlloc ) return 0;
+  if( pParse->nBlobAlloc==0 ){
+    t = 100;
   }else{
-    p->zJson = (char*)&p[1];
-    memcpy(p->zJson, zJson, nJson+1);
-  }
-  p->nJPRef = 1;
-  if( jsonParse(p, pErrCtx) ){
-    if( pErrCtx==0 ){
-      p->nErr = 1;
-      assert( p->nJPRef==1 ); /* Caller will own the new JsonParse object p */
-      return p;
-    }
-    jsonParseFree(p);
-    return 0;
+    t = pParse->nBlobAlloc*2;
   }
-  p->nJson = nJson;
-  p->iHold = iMaxHold+1;
-  /* Transfer ownership of the new JsonParse to the cache */
-  sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p,
-                      (void(*)(void*))jsonParseFree);
-  return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey);
+  if( t<N ) t = N+100;
+  aNew = sqlite3_realloc64( pParse->aBlob, t );
+  if( aNew==0 ){ pParse->oom = 1; return 1; }
+  pParse->aBlob = aNew;
+  pParse->nBlobAlloc = t;
+  return 0;
 }
 
-/*
-** Compare the OBJECT label at pNode against zKey,nKey.  Return true on
-** a match.
+/* Expand pParse->aBlob and append N bytes.
+**
+** Return the number of errors.
 */
-static int jsonLabelCompare(const JsonNode *pNode, const char *zKey, u32 nKey){
-  assert( pNode->eU==1 );
-  if( pNode->jnFlags & JNODE_RAW ){
-    if( pNode->n!=nKey ) return 0;
-    return strncmp(pNode->u.zJContent, zKey, nKey)==0;
-  }else{
-    if( pNode->n!=nKey+2 ) return 0;
-    return strncmp(pNode->u.zJContent+1, zKey, nKey)==0;
+static SQLITE_NOINLINE int jsonBlobExpandAndAppend(
+  JsonParse *pParse,
+  const u8 *aData,
+  u32 N
+){
+  if( jsonBlobExpand(pParse, pParse->nBlob+N) ) return 1;
+  memcpy(&pParse->aBlob[pParse->nBlob], aData, N);
+  pParse->nBlob += N;
+  return 0;
+}
+
+/* Append a single character.  Return 1 if an error occurs.
+*/
+static int jsonBlobAppendOneByte(JsonParse *pParse, u8 c){
+  if( pParse->nBlob >= pParse->nBlobAlloc ){
+    return jsonBlobExpandAndAppend(pParse, &c, 1);
   }
+  pParse->aBlob[pParse->nBlob++] = c;
+  return 0;
 }
-static int jsonSameLabel(const JsonNode *p1, const JsonNode *p2){
-  if( p1->jnFlags & JNODE_RAW ){
-    return jsonLabelCompare(p2, p1->u.zJContent, p1->n);
-  }else if( p2->jnFlags & JNODE_RAW ){
-    return jsonLabelCompare(p1, p2->u.zJContent, p2->n);
-  }else{
-    return p1->n==p2->n && strncmp(p1->u.zJContent,p2->u.zJContent,p1->n)==0;
+
+/* Append bytes.  Return 1 if an error occurs.
+*/
+static int jsonBlobAppendNBytes(JsonParse *pParse, const u8 *aData, u32 N){
+  if( pParse->nBlob+N > pParse->nBlobAlloc ){
+    return jsonBlobExpandAndAppend(pParse, aData, N);
   }
+  memcpy(&pParse->aBlob[pParse->nBlob], aData, N);
+  pParse->nBlob += N;
+  return 0;
 }
 
-/* forward declaration */
-static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**);
+/* Append a u32.  Return 1 if an error occurs.
+*/
+static int jsonBlobAppendU32(JsonParse *pParse, u32 x){
+  u8 a[4];
+  a[3] = x & 0xff;
+  x >>= 8;
+  a[2] = x & 0xff;
+  x >>= 8;
+  a[1] = x & 0xff;
+  x >>= 8;
+  a[0] = x & 0xff;
+  return jsonBlobAppendNBytes(pParse, a, 4);
+}
+
+/* Write a u32 and offset i.
+*/
+static int jsonBlobWriteU32(JsonParse *pParse, u32 x, u32 i){
+  u8 *a = &pParse->aBlob[i];
+  a[3] = x & 0xff;
+  x >>= 8;
+  a[2] = x & 0xff;
+  x >>= 8;
+  a[1] = x & 0xff;
+  x >>= 8;
+  a[0] = x & 0xff;
+  return 0;
+}
+
+/* Append a VarInt.  Return 1 if an error occurs.
+*/
+static int jsonBlobAppendVarint(JsonParse *pParse, u32 x){
+  u8 a[5];
+  if( x<=0x7f ) return jsonBlobAppendOneByte(pParse, x & 0x7f);
+  a[0] = 0x80 | (x & 0x7f);
+  x >>= 7;
+  a[1] = x & 0x7f;
+  x >>= 7;
+  if( x==0 ) return jsonBlobAppendNBytes(pParse, a, 2);
+  a[1] |= 0x80;
+  a[2] = x & 0x7f;
+  x >>= 7;
+  if( x==0 ) return jsonBlobAppendNBytes(pParse, a, 3);
+  a[2] |= 0x80;
+  a[3] = x & 0x7f;
+  x >>= 7;
+  if( x==0 ) return jsonBlobAppendNBytes(pParse, a, 4);
+  a[3] |= 0x80;
+  a[4] = x & 0x7f;
+  return jsonBlobAppendNBytes(pParse, a, 5);
+}
 
 /*
-** Search along zPath to find the node specified.  Return a pointer
-** to that node, or NULL if zPath is malformed or if there is no such
-** node.
+** Parse a single JSON text value which begins at pParse->zJson[i] into
+** its equivalent BLOB representation in pParse->aBlob[].  The parse is
+** appended to pParse->aBlob[] beginning at pParse->nBlob.  The size of
+** pParse->aBlob[] is increased as necessary.
 **
-** If pApnd!=0, then try to append new nodes to complete zPath if it is
-** possible to do so and if no existing node corresponds to zPath.  If
-** new nodes are appended *pApnd is set to 1.
+** Return the index of the first character past the end of the value parsed,
+** or one of the following special result codes:
+**
+**      0    End of input
+**     -1    Syntax error
+**     -2    '}' seen
+**     -3    ']' seen
+**     -4    ',' seen
+**     -5    ':' seen
 */
-static JsonNode *jsonLookupStep(
-  JsonParse *pParse,      /* The JSON to search */
-  u32 iRoot,              /* Begin the search at this node */
-  const char *zPath,      /* The path to search */
-  int *pApnd,             /* Append nodes to complete path if not NULL */
-  const char **pzErr      /* Make *pzErr point to any syntax error in zPath */
-){
-  u32 i, j, nKey;
-  const char *zKey;
-  JsonNode *pRoot;
-  if( pParse->oom ) return 0;
-  pRoot = &pParse->aNode[iRoot];
-  if( pRoot->jnFlags & (JNODE_REPLACE|JNODE_REMOVE) && pParse->useMod ){
-    while( (pRoot->jnFlags & JNODE_REPLACE)!=0 ){
-      u32 idx = (u32)(pRoot - pParse->aNode);
-      i = pParse->iSubst;
-      while( 1 /*exit-by-break*/ ){
-        assert( i<pParse->nNode );
-        assert( pParse->aNode[i].eType==JSON_SUBST );
-        assert( pParse->aNode[i].eU==4 );
-        assert( pParse->aNode[i].u.iPrev<i );
-        if( pParse->aNode[i].n==idx ){
-          pRoot = &pParse->aNode[i+1];
-          iRoot = i+1;
+static int jsonParseValueB(JsonParse *pParse, u32 i){
+  char c;
+  u32 j;
+  int iThis;
+  int x;
+  u8 t;
+  const char *z = pParse->zJson;
+json_parse_restart:
+  switch( (u8)z[i] ){
+  case '{': {
+    /* Parse object */
+    jsonBlobAppendOneByte(pParse, JSONB_OBJECT);
+    iThis = pParse->nBlob;
+    jsonBlobAppendU32(pParse, 0);
+    if( ++pParse->iDepth > JSON_MAX_DEPTH ){
+      pParse->iErr = i;
+      return -1;
+    }
+    for(j=i+1;;j++){
+      u32 iBlob = pParse->nBlob;
+      x = jsonParseValueB(pParse, j);
+      if( x<=0 ){
+        if( x==(-2) ){
+          j = pParse->iErr;
+          if( pParse->nBlob!=(u32)iThis+1 ) pParse->hasNonstd = 1;
+          break;
+        }
+        j += json5Whitespace(&z[j]);
+        if( sqlite3JsonId1(z[j])
+         || (z[j]=='\\' && z[j+1]=='u' && jsonIs4Hex(&z[j+2]))
+        ){
+          int k = j+1;
+          while( (sqlite3JsonId2(z[k]) && json5Whitespace(&z[k])==0)
+            || (z[k]=='\\' && z[k+1]=='u' && jsonIs4Hex(&z[k+2]))
+          ){
+            k++;
+          }
+          assert( iBlob==pParse->nBlob );
+          jsonBlobAppendOneByte(pParse, JSONB_TEXT5);
+          jsonBlobAppendVarint(pParse, k-j);
+          jsonBlobAppendNBytes(pParse, (const u8*)&z[j], k-j);
+          pParse->hasNonstd = 1;
+          x = k;
+        }else{
+          if( x!=-1 ) pParse->iErr = j;
+          return -1;
+        }
+      }
+      if( pParse->oom ) return -1;
+      t = pParse->aBlob[iBlob];
+      if( t<JSONB_TEXT || t>JSONB_TEXT5 ){
+        pParse->iErr = j;
+        return -1;
+      }
+      j = x;
+      if( z[j]==':' ){
+        j++;
+      }else{
+        if( fast_isspace(z[j]) ){
+          do{ j++; }while( fast_isspace(z[j]) );
+          if( z[j]==':' ){
+            j++;
+            goto parse_object_value;
+          }
+        }
+        x = jsonParseValueB(pParse, j);
+        if( x!=(-5) ){
+          if( x!=(-1) ) pParse->iErr = j;
+          return -1;
+        }
+        j = pParse->iErr+1;
+      }
+    parse_object_value:
+      x = jsonParseValueB(pParse, j);
+      if( x<=0 ){
+        if( x!=(-1) ) pParse->iErr = j;
+        return -1;
+      }
+      j = x;
+      if( z[j]==',' ){
+        continue;
+      }else if( z[j]=='}' ){
+        break;
+      }else{
+        if( fast_isspace(z[j]) ){
+          do{ j++; }while( fast_isspace(z[j]) );
+          if( z[j]==',' ){
+            continue;
+          }else if( z[j]=='}' ){
+            break;
+          }
+        }
+        x = jsonParseValueB(pParse, j);
+        if( x==(-4) ){
+          j = pParse->iErr;
+          continue;
+        }
+        if( x==(-2) ){
+          j = pParse->iErr;
+          break;
+        }
+      }
+      pParse->iErr = j;
+      return -1;
+    }
+    jsonBlobWriteU32(pParse, pParse->nBlob - iThis, iThis);
+    pParse->iDepth--;
+    return j+1;
+  }
+  case '[': {
+    /* Parse array */
+    jsonBlobAppendOneByte(pParse, JSONB_ARRAY);
+    iThis = pParse->nBlob;
+    jsonBlobAppendU32(pParse, 0);
+    if( pParse->oom ) return -1;
+    if( ++pParse->iDepth > JSON_MAX_DEPTH ){
+      pParse->iErr = i;
+      return -1;
+    }
+    for(j=i+1;;j++){
+      x = jsonParseValueB(pParse, j);
+      if( x<=0 ){
+        if( x==(-3) ){
+          j = pParse->iErr;
+          if( pParse->nBlob!=iThis+4 ) pParse->hasNonstd = 1;
+          break;
+        }
+        if( x!=(-1) ) pParse->iErr = j;
+        return -1;
+      }
+      j = x;
+      if( z[j]==',' ){
+        continue;
+      }else if( z[j]==']' ){
+        break;
+      }else{
+        if( fast_isspace(z[j]) ){
+          do{ j++; }while( fast_isspace(z[j]) );
+          if( z[j]==',' ){
+            continue;
+          }else if( z[j]==']' ){
+            break;
+          }
+        }
+        x = jsonParseValueB(pParse, j);
+        if( x==(-4) ){
+          j = pParse->iErr;
+          continue;
+        }
+        if( x==(-3) ){
+          j = pParse->iErr;
           break;
         }
-        i = pParse->aNode[i].u.iPrev;
+      }
+      pParse->iErr = j;
+      return -1;
+    }
+    jsonBlobWriteU32(pParse, pParse->nBlob - iThis, iThis);
+    pParse->iDepth--;
+    return j+1;
+  }
+  case '\'': {
+    u8 opcode;
+    char cDelim;
+    pParse->hasNonstd = 1;
+    opcode = JNODE_JSON5;
+    goto parse_string;
+  case '"':
+    /* Parse string */
+    opcode = JSONB_TEXT;
+  parse_string:
+    cDelim = z[i];
+    for(j=i+1; 1; j++){
+      if( jsonIsOk[(unsigned char)z[j]] ) continue;
+      c = z[j];
+      if( c==cDelim ){
+        break;
+      }else if( c=='\\' ){
+        c = z[++j];
+        if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
+           || c=='n' || c=='r' || c=='t'
+           || (c=='u' && jsonIs4Hex(&z[j+1])) ){
+          if( opcode==JSONB_TEXT ) opcode = JSONB_TEXTJ;
+        }else if( c=='\'' || c=='0' || c=='v' || c=='\n'
+           || (0xe2==(u8)c && 0x80==(u8)z[j+1]
+                && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2]))
+           || (c=='x' && jsonIs2Hex(&z[j+1])) ){
+          opcode = JSONB_TEXT5;
+          pParse->hasNonstd = 1;
+        }else if( c=='\r' ){
+          if( z[j+1]=='\n' ) j++;
+          opcode = JSONB_TEXT5;
+          pParse->hasNonstd = 1;
+        }else{
+          pParse->iErr = j;
+          return -1;
+        }
+      }else if( c<=0x1f ){
+        /* Control characters are not allowed in strings */
+        pParse->iErr = j;
+        return -1;
       }
     }
-    if( pRoot->jnFlags & JNODE_REMOVE ){
-      return 0;
+    jsonBlobAppendOneByte(pParse, opcode);
+    jsonBlobAppendVarint(pParse, j+1-i);
+    jsonBlobAppendNBytes(pParse, (const u8*)&z[i], j+1-i);
+    return j+1;
+  }
+  case 't': {
+    if( strncmp(z+i,"true",4)==0 && !sqlite3Isalnum(z[i+4]) ){
+      jsonBlobAppendOneByte(pParse, JSONB_TRUE);
+      return i+4;
     }
+    pParse->iErr = i;
+    return -1;
   }
-  if( zPath[0]==0 ) return pRoot;
-  if( zPath[0]=='.' ){
-    if( pRoot->eType!=JSON_OBJECT ) return 0;
-    zPath++;
-    if( zPath[0]=='"' ){
-      zKey = zPath + 1;
-      for(i=1; zPath[i] && zPath[i]!='"'; i++){}
-      nKey = i-1;
-      if( zPath[i] ){
-        i++;
-      }else{
-        *pzErr = zPath;
-        return 0;
-      }
-      testcase( nKey==0 );
-    }else{
-      zKey = zPath;
-      for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){}
-      nKey = i;
-      if( nKey==0 ){
-        *pzErr = zPath;
-        return 0;
-      }
+  case 'f': {
+    if( strncmp(z+i,"false",5)==0 && !sqlite3Isalnum(z[i+5]) ){
+      jsonBlobAppendOneByte(pParse, JSONB_FALSE);
+      return i+5;
     }
-    j = 1;
-    for(;;){
-      while( j<=pRoot->n ){
-        if( jsonLabelCompare(pRoot+j, zKey, nKey) ){
-          return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr);
+    pParse->iErr = i;
+    return -1;
+  }
+  case '+': {
+    u8 seenDP, seenE, jnFlags;
+    pParse->hasNonstd = 1;
+    jnFlags = 0;
+    goto parse_number;
+  case '.':
+    if( sqlite3Isdigit(z[i+1]) ){
+      pParse->hasNonstd = 1;
+      jnFlags = JNODE_JSON5;
+      seenE = 0;
+      seenDP = JSON_REAL;
+      goto parse_number_2;
+    }
+    pParse->iErr = i;
+    return -1;
+  case '-':
+  case '0':
+  case '1':
+  case '2':
+  case '3':
+  case '4':
+  case '5':
+  case '6':
+  case '7':
+  case '8':
+  case '9':
+    /* Parse number */
+    jnFlags = 0;
+  parse_number:
+    seenDP = JSON_INT;
+    seenE = 0;
+    assert( '-' < '0' );
+    assert( '+' < '0' );
+    assert( '.' < '0' );
+    c = z[i];
+
+    if( c<='0' ){
+      if( c=='0' ){
+        if( (z[i+1]=='x' || z[i+1]=='X') && sqlite3Isxdigit(z[i+2]) ){
+          assert( seenDP==JSON_INT );
+          pParse->hasNonstd = 1;
+          jnFlags |= JNODE_JSON5;
+          for(j=i+3; sqlite3Isxdigit(z[j]); j++){}
+          goto parse_number_finish;
+        }else if( sqlite3Isdigit(z[i+1]) ){
+          pParse->iErr = i+1;
+          return -1;
+        }
+      }else{
+        if( !sqlite3Isdigit(z[i+1]) ){
+          /* JSON5 allows for "+Infinity" and "-Infinity" using exactly
+          ** that case.  SQLite also allows these in any case and it allows
+          ** "+inf" and "-inf". */
+          if( (z[i+1]=='I' || z[i+1]=='i')
+           && sqlite3StrNICmp(&z[i+1], "inf",3)==0
+          ){
+            pParse->hasNonstd = 1;
+            jsonBlobAppendOneByte(pParse, JSONB_NUMBER5);
+            if( z[i]=='-' ){
+              jsonBlobAppendVarint(pParse, 8);
+              jsonBlobAppendNBytes(pParse, (const u8*)"-9.0e999", 8);
+            }else{
+              jsonBlobAppendVarint(pParse, 7);
+              jsonBlobAppendNBytes(pParse, (const u8*)"9.0e999", 7);
+            }
+            return i + (sqlite3StrNICmp(&z[i+4],"inity",5)==0 ? 9 : 4);
+          }
+          if( z[i+1]=='.' ){
+            pParse->hasNonstd = 1;
+            jnFlags |= JNODE_JSON5;
+            goto parse_number_2;
+          }
+          pParse->iErr = i;
+          return -1;
+        }
+        if( z[i+1]=='0' ){
+          if( sqlite3Isdigit(z[i+2]) ){
+            pParse->iErr = i+1;
+            return -1;
+          }else if( (z[i+2]=='x' || z[i+2]=='X') && sqlite3Isxdigit(z[i+3]) ){
+            pParse->hasNonstd = 1;
+            jnFlags |= JNODE_JSON5;
+            for(j=i+4; sqlite3Isxdigit(z[j]); j++){}
+            goto parse_number_finish;
+          }
         }
-        j++;
-        j += jsonNodeSize(&pRoot[j]);
       }
-      if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
-      if( pParse->useMod==0 ) break;
-      assert( pRoot->eU==2 );
-      iRoot = pRoot->u.iAppend;
-      pRoot = &pParse->aNode[iRoot];
-      j = 1;
     }
-    if( pApnd ){
-      u32 iStart, iLabel;
-      JsonNode *pNode;
-      assert( pParse->useMod );
-      iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
-      iLabel = jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
-      zPath += i;
-      pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
-      if( pParse->oom ) return 0;
-      if( pNode ){
-        pRoot = &pParse->aNode[iRoot];
-        assert( pRoot->eU==0 );
-        pRoot->u.iAppend = iStart;
-        pRoot->jnFlags |= JNODE_APPEND;
-        VVA( pRoot->eU = 2 );
-        pParse->aNode[iLabel].jnFlags |= JNODE_RAW;
+  parse_number_2:
+    for(j=i+1;; j++){
+      c = z[j];
+      if( sqlite3Isdigit(c) ) continue;
+      if( c=='.' ){
+        if( seenDP==JSON_REAL ){
+          pParse->iErr = j;
+          return -1;
+        }
+        seenDP = JSON_REAL;
+        continue;
       }
-      return pNode;
-    }
-  }else if( zPath[0]=='[' ){
-    i = 0;
-    j = 1;
-    while( sqlite3Isdigit(zPath[j]) ){
-      i = i*10 + zPath[j] - '0';
-      j++;
-    }
-    if( j<2 || zPath[j]!=']' ){
-      if( zPath[1]=='#' ){
-        JsonNode *pBase = pRoot;
-        int iBase = iRoot;
-        if( pRoot->eType!=JSON_ARRAY ) return 0;
-        for(;;){
-          while( j<=pBase->n ){
-            if( (pBase[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ) i++;
-            j += jsonNodeSize(&pBase[j]);
+      if( c=='e' || c=='E' ){
+        if( z[j-1]<'0' ){
+          if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){
+            pParse->hasNonstd = 1;
+            jnFlags |= JNODE_JSON5;
+          }else{
+            pParse->iErr = j;
+            return -1;
           }
-          if( (pBase->jnFlags & JNODE_APPEND)==0 ) break;
-          if( pParse->useMod==0 ) break;
-          assert( pBase->eU==2 );
-          iBase = pBase->u.iAppend;
-          pBase = &pParse->aNode[iBase];
-          j = 1;
         }
-        j = 2;
-        if( zPath[2]=='-' && sqlite3Isdigit(zPath[3]) ){
-          unsigned int x = 0;
-          j = 3;
-          do{
-            x = x*10 + zPath[j] - '0';
-            j++;
-          }while( sqlite3Isdigit(zPath[j]) );
-          if( x>i ) return 0;
-          i -= x;
+        if( seenE ){
+          pParse->iErr = j;
+          return -1;
         }
-        if( zPath[j]!=']' ){
-          *pzErr = zPath;
-          return 0;
+        seenDP = JSON_REAL;
+        seenE = 1;
+        c = z[j+1];
+        if( c=='+' || c=='-' ){
+          j++;
+          c = z[j+1];
         }
-      }else{
-        *pzErr = zPath;
-        return 0;
-      }
-    }
-    if( pRoot->eType!=JSON_ARRAY ) return 0;
-    zPath += j + 1;
-    j = 1;
-    for(;;){
-      while( j<=pRoot->n
-         && (i>0 || ((pRoot[j].jnFlags & JNODE_REMOVE)!=0 && pParse->useMod))
-      ){
-        if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 || pParse->useMod==0 ) i--;
-        j += jsonNodeSize(&pRoot[j]);
+        if( c<'0' || c>'9' ){
+          pParse->iErr = j;
+          return -1;
+        }
+        continue;
       }
-      if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
-      if( pParse->useMod==0 ) break;
-      assert( pRoot->eU==2 );
-      iRoot = pRoot->u.iAppend;
-      pRoot = &pParse->aNode[iRoot];
-      j = 1;
-    }
-    if( j<=pRoot->n ){
-      return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr);
+      break;
     }
-    if( i==0 && pApnd ){
-      u32 iStart;
-      JsonNode *pNode;
-      assert( pParse->useMod );
-      iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0);
-      pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
-      if( pParse->oom ) return 0;
-      if( pNode ){
-        pRoot = &pParse->aNode[iRoot];
-        assert( pRoot->eU==0 );
-        pRoot->u.iAppend = iStart;
-        pRoot->jnFlags |= JNODE_APPEND;
-        VVA( pRoot->eU = 2 );
+    if( z[j-1]<'0' ){
+      if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){
+        pParse->hasNonstd = 1;
+        jnFlags |= JNODE_JSON5;
+      }else{
+        pParse->iErr = j;
+        return -1;
       }
-      return pNode;
     }
-  }else{
-    *pzErr = zPath;
+  parse_number_finish:
+    if( jnFlags & JNODE_JSON5 ){
+      jsonBlobAppendOneByte(pParse, JSONB_NUMBER5);
+    }else{
+      jsonBlobAppendOneByte(pParse, JSONB_NUMBER);
+    }
+    jsonBlobAppendVarint(pParse, j-i);
+    jsonBlobAppendNBytes(pParse, (const u8*)&z[i], j-i);
+    return j;
   }
-  return 0;
-}
-
-/*
-** Append content to pParse that will complete zPath.  Return a pointer
-** to the inserted node, or return NULL if the append fails.
-*/
-static JsonNode *jsonLookupAppend(
-  JsonParse *pParse,     /* Append content to the JSON parse */
-  const char *zPath,     /* Description of content to append */
-  int *pApnd,            /* Set this flag to 1 */
-  const char **pzErr     /* Make this point to any syntax error */
-){
-  *pApnd = 1;
-  if( zPath[0]==0 ){
-    jsonParseAddNode(pParse, JSON_NULL, 0, 0);
-    return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1];
+  case '}': {
+    pParse->iErr = i;
+    return -2;  /* End of {...} */
   }
-  if( zPath[0]=='.' ){
-    jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
-  }else if( strncmp(zPath,"[0]",3)==0 ){
-    jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
-  }else{
-    return 0;
+  case ']': {
+    pParse->iErr = i;
+    return -3;  /* End of [...] */
   }
-  if( pParse->oom ) return 0;
-  return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr);
-}
-
-/*
-** Return the text of a syntax error message on a JSON path.  Space is
-** obtained from sqlite3_malloc().
-*/
-static char *jsonPathSyntaxError(const char *zErr){
-  return sqlite3_mprintf("JSON path error near '%q'", zErr);
-}
-
-/*
-** Do a node lookup using zPath.  Return a pointer to the node on success.
-** Return NULL if not found or if there is an error.
-**
-** On an error, write an error message into pCtx and increment the
-** pParse->nErr counter.
-**
-** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if
-** nodes are appended.
-*/
-static JsonNode *jsonLookup(
-  JsonParse *pParse,      /* The JSON to search */
-  const char *zPath,      /* The path to search */
-  int *pApnd,             /* Append nodes to complete path if not NULL */
-  sqlite3_context *pCtx   /* Report errors here, if not NULL */
-){
-  const char *zErr = 0;
-  JsonNode *pNode = 0;
-  char *zMsg;
-
-  if( zPath==0 ) return 0;
-  if( zPath[0]!='$' ){
-    zErr = zPath;
-    goto lookup_err;
+  case ',': {
+    pParse->iErr = i;
+    return -4;  /* List separator */
   }
-  zPath++;
-  pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr);
-  if( zErr==0 ) return pNode;
-
-lookup_err:
-  pParse->nErr++;
-  assert( zErr!=0 && pCtx!=0 );
-  zMsg = jsonPathSyntaxError(zErr);
-  if( zMsg ){
-    sqlite3_result_error(pCtx, zMsg, -1);
-    sqlite3_free(zMsg);
-  }else{
-    sqlite3_result_error_nomem(pCtx);
+  case ':': {
+    pParse->iErr = i;
+    return -5;  /* Object label/value separator */
   }
-  return 0;
+  case 0: {
+    return 0;   /* End of file */
+  }
+  case 0x09:
+  case 0x0a:
+  case 0x0d:
+  case 0x20: {
+    do{
+      i++;
+    }while( fast_isspace(z[i]) );
+    goto json_parse_restart;
+  }
+  case 0x0b:
+  case 0x0c:
+  case '/':
+  case 0xc2:
+  case 0xe1:
+  case 0xe2:
+  case 0xe3:
+  case 0xef: {
+    j = json5Whitespace(&z[i]);
+    if( j>0 ){
+      i += j;
+      pParse->hasNonstd = 1;
+      goto json_parse_restart;
+    }
+    pParse->iErr = i;
+    return -1;
+  }
+  case 'n': {
+    if( strncmp(z+i,"null",4)==0 && !sqlite3Isalnum(z[i+4]) ){
+      jsonBlobAppendOneByte(pParse, JSONB_NULL);
+      return i+4;
+    }
+    /* fall-through into the default case that checks for NaN */
+  }
+  default: {
+    u32 k;
+    int nn;
+    c = z[i];
+    for(k=0; k<sizeof(aNanInfName)/sizeof(aNanInfName[0]); k++){
+      if( c!=aNanInfName[k].c1 && c!=aNanInfName[k].c2 ) continue;
+      nn = aNanInfName[k].n;
+      if( sqlite3StrNICmp(&z[i], aNanInfName[k].zMatch, nn)!=0 ){
+        continue;
+      }
+      if( sqlite3Isalnum(z[i+nn]) ) continue;
+      if( aNanInfName[k].eType==JSON_REAL ){
+        jsonBlobAppendOneByte(pParse, JSONB_NUMBER);
+        jsonBlobAppendOneByte(pParse, 7);
+        jsonBlobAppendNBytes(pParse, (const u8*)"9.0e999", 7);
+      }else{
+        jsonBlobAppendOneByte(pParse, JSONB_NULL);
+      }
+      pParse->hasNonstd = 1;
+      return i + nn;
+    }
+    pParse->iErr = i;
+    return -1;  /* Syntax error */
+  }
+  } /* End switch(z[i]) */
 }
 
 
 /*
-** Report the wrong number of arguments for json_insert(), json_replace()
-** or json_set().
+** Parse a complete JSON string.  Return 0 on success or non-zero if there
+** are any errors.  If an error occurs, free all memory held by pParse,
+** but not pParse itself.
+**
+** pParse must be initialized to an empty parse object prior to calling
+** this routine.
 */
-static void jsonWrongNumArgs(
-  sqlite3_context *pCtx,
-  const char *zFuncName
+static int jsonParseB(
+  JsonParse *pParse,           /* Initialize and fill this JsonParse object */
+  sqlite3_context *pCtx        /* Report errors here */
 ){
-  char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments",
-                               zFuncName);
-  sqlite3_result_error(pCtx, zMsg, -1);
-  sqlite3_free(zMsg);
-}
-
-/*
-** Mark all NULL entries in the Object passed in as JNODE_REMOVE.
-*/
-static void jsonRemoveAllNulls(JsonNode *pNode){
-  int i, n;
-  assert( pNode->eType==JSON_OBJECT );
-  n = pNode->n;
-  for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){
-    switch( pNode[i].eType ){
-      case JSON_NULL:
-        pNode[i].jnFlags |= JNODE_REMOVE;
-        break;
-      case JSON_OBJECT:
-        jsonRemoveAllNulls(&pNode[i]);
-        break;
+  int i;
+  const char *zJson = pParse->zJson;
+  jsonBlobAppendOneByte(pParse, 0x4a);
+  jsonBlobAppendOneByte(pParse, 0x01);
+  i = jsonParseValueB(pParse, 0);
+  if( pParse->oom ) i = -1;
+  if( i>0 ){
+    assert( pParse->iDepth==0 );
+    while( fast_isspace(zJson[i]) ) i++;
+    if( zJson[i] ){
+      i += json5Whitespace(&zJson[i]);
+      if( zJson[i] ){
+        jsonParseReset(pParse);
+        return 1;
+      }
+      pParse->hasNonstd = 1;
+    }
+  }
+  if( i<=0 ){
+    if( pCtx!=0 ){
+      if( pParse->oom ){
+        sqlite3_result_error_nomem(pCtx);
+      }else{
+        sqlite3_result_error(pCtx, "malformed JSON", -1);
+      }
     }
+    jsonParseReset(pParse);
+    return 1;
   }
+  return 0;
 }
 
-
 /****************************************************************************
 ** SQL functions used for testing and debugging
 ****************************************************************************/