Remove the vestigal JsonNode logic from json_tree() and json_each().

FossilOrigin-Name: 66c2ab9ebbf90477742e6be0d30e061d827c409de038f2a5b73479ed9448c4a6
This commit is contained in:
drh
2023-11-25 20:59:03 +00:00
parent aea2d23121
commit 796abda538
3 changed files with 124 additions and 442 deletions
+6 -6
View File
@@ -1,5 +1,5 @@
C Almost\sworking.\s\sPath\sis\sstill\snot\sexactly\sright\swhen\sRoot\sis\sdefined\son\njson_tree().
D 2023-11-25T19:28:44.393
C Remove\sthe\svestigal\sJsonNode\slogic\sfrom\sjson_tree()\sand\sjson_each().
D 2023-11-25T20:59:03.008
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 617eaedbe44c139f0144f04ecbfa240721462f45d76e715eaacc99e172bf43b0
F src/json.c 211c4e1b8fd886c97d3224105bfef9d4cc04db2e3f1daca1e95c52343df4e85c
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 ffaa468ab8871906121df9ee5ef3dc00129a0086ed9c18831ecda69bf7f71455
R b82a578143acb9c5e1a084b85e2e99b7
P 92258246916a9c0d72785964513113848a850dec78bdade8b3f274e410df4e7e
R 43fba60a847876455ec8abde78205ef3
U drh
Z 1f6ed13fcc3b9ce0d1d8c376c125c482
Z d0660c039b12ecd1fe4ffd828711a405
# Remove this line to create a well-formed Fossil manifest.
+1 -1
View File
@@ -1 +1 @@
92258246916a9c0d72785964513113848a850dec78bdade8b3f274e410df4e7e
66c2ab9ebbf90477742e6be0d30e061d827c409de038f2a5b73479ed9448c4a6
+117 -435
View File
@@ -329,7 +329,6 @@ struct JsonParse {
JsonNode *aNode; /* Array of nodes containing the parse */
char *zJson; /* Original JSON string (before edits) */
char *zAlt; /* Revised and/or mimified JSON */
u32 *aUp; /* Index of parent of each node */
JsonCleanup *pClup;/* Cleanup operations prior to freeing this object */
u16 iDepth; /* Nesting depth */
u8 nErr; /* Number of errors seen */
@@ -860,10 +859,6 @@ static void jsonParseReset(JsonParse *pParse){
}
pParse->nNode = 0;
pParse->nAlloc = 0;
if( pParse->aUp ){
sqlite3_free(pParse->aUp);
pParse->aUp = 0;
}
if( pParse->bJsonIsRCStr ){
sqlite3RCStrUnref(pParse->zJson);
pParse->zJson = 0;
@@ -2013,33 +2008,6 @@ 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 JSON (either pure RFC-8259 JSON text, or JSON-5 text, or a JSONB
** blob) into the JsonNode representation.
@@ -2090,21 +2058,6 @@ static int jsonParse(
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()
*/
@@ -3257,7 +3210,7 @@ static int jsonConvertTextToBlob(
}
}
if( i<=0 ){
if( ALWAYS(pCtx!=0) ){
if( pCtx!=0 ){
if( pParse->oom ){
sqlite3_result_error_nomem(pCtx);
}else{
@@ -5767,47 +5720,7 @@ static void jsonAppendPathName(JsonEachCursor *p){
/* Advance the cursor to the next element for json_tree() */
static int jsonEachNext(sqlite3_vtab_cursor *cur){
JsonEachCursor *p = (JsonEachCursor*)cur;
if( p->sParse.aNode ){
/* LEGACY */
if( p->bRecursive ){
if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++;
p->i++;
p->iRowid++;
if( p->i<p->iEnd ){
u32 iUp = p->sParse.aUp[p->i];
JsonNode *pUp = &p->sParse.aNode[iUp];
p->eType = pUp->eType;
if( pUp->eType==JSON_ARRAY ){
assert( pUp->eU==0 || pUp->eU==3 );
testcase( pUp->eU==3 );
JSON_VVA( pUp->eU = 3 );
if( iUp==p->i-1 ){
pUp->u.iKey = 0;
}else{
pUp->u.iKey++;
}
}
}
}else{
switch( p->eType ){
case JSON_ARRAY: {
p->i += jsonNodeSize(&p->sParse.aNode[p->i]);
p->iRowid++;
break;
}
case JSON_OBJECT: {
p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]);
p->iRowid++;
break;
}
default: {
p->i = p->iEnd;
break;
}
}
}
return SQLITE_OK;
}else if( p->bRecursive ){
if( p->bRecursive ){
u8 x;
u8 levelChange = 0;
u32 n, sz = 0;
@@ -5866,70 +5779,6 @@ static int jsonEachNext(sqlite3_vtab_cursor *cur){
return SQLITE_OK;
}
/* Append an object label to the JSON Path being constructed
** in pStr.
*/
static void jsonAppendObjectPathElementOfNode(
JsonString *pStr,
JsonNode *pNode
){
int nn;
const char *z;
int bNeedQuote = 0;
assert( pNode->eType==JSON_STRING );
assert( pNode->jnFlags & JNODE_LABEL );
assert( pNode->eU==1 );
z = pNode->u.zJContent;
nn = pNode->n;
if( pNode->jnFlags & JNODE_RAW ){
/* no-op */
}else if( nn==0 || !sqlite3Isalpha(z[0]) ){
bNeedQuote = 1;
}else{
int jj;
for(jj=1; jj<nn && sqlite3Isalnum(z[jj]); jj++){}
bNeedQuote = jj<nn;
}
if( bNeedQuote ){
jsonPrintf(nn+4, pStr, ".\"%.*s\"", nn, z);
}else{
jsonPrintf(nn+2, pStr, ".%.*s", nn, z);
}
}
/* Append the name of the path for element i to pStr
*/
static void jsonEachComputePath(
JsonEachCursor *p, /* The cursor */
JsonString *pStr, /* Write the path here */
u32 i /* Path to this element */
){
JsonNode *pNode, *pUp;
u32 iUp;
if( i==0 ){
jsonAppendChar(pStr, '$');
return;
}
if( p->sParse.aNode ){
/* LEGACY */
assert( p->sParse.aUp );
iUp = p->sParse.aUp[i];
jsonEachComputePath(p, pStr, iUp);
pNode = &p->sParse.aNode[i];
pUp = &p->sParse.aNode[iUp];
if( pUp->eType==JSON_ARRAY ){
assert( pUp->eU==3 || (pUp->eU==0 && pUp->u.iKey==0) );
testcase( pUp->eU==0 );
jsonPrintf(30, pStr, "[%d]", pUp->u.iKey);
}else{
assert( pUp->eType==JSON_OBJECT );
if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--;
jsonAppendObjectPathElementOfNode(pStr, pNode);
}
return;
}
}
/* Return the value of a column */
static int jsonEachColumn(
sqlite3_vtab_cursor *cur, /* The cursor */
@@ -5937,173 +5786,73 @@ static int jsonEachColumn(
int iColumn /* Which column to return */
){
JsonEachCursor *p = (JsonEachCursor*)cur;
if( p->sParse.aNode!=0 ){
/* LEGACY */
JsonNode *pThis = &p->sParse.aNode[p->i];
switch( iColumn ){
case JEACH_KEY: {
if( p->i==0 ) break;
if( p->eType==JSON_OBJECT ){
jsonReturnFromNode(&p->sParse, pThis, ctx, 0);
}else if( p->eType==JSON_ARRAY ){
u32 iKey;
if( p->bRecursive ){
if( p->iRowid==0 ) break;
assert( p->sParse.aNode[p->sParse.aUp[p->i]].eU==3 );
iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey;
}else{
iKey = p->iRowid;
}
sqlite3_result_int64(ctx, (sqlite3_int64)iKey);
}
break;
}
case JEACH_VALUE: {
if( pThis->jnFlags & JNODE_LABEL ) pThis++;
jsonReturnFromNode(&p->sParse, pThis, ctx, 0);
break;
}
case JEACH_TYPE: {
if( pThis->jnFlags & JNODE_LABEL ) pThis++;
sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC);
break;
}
case JEACH_ATOM: {
if( pThis->jnFlags & JNODE_LABEL ) pThis++;
if( pThis->eType>=JSON_ARRAY ) break;
jsonReturnFromNode(&p->sParse, pThis, ctx, 0);
break;
}
case JEACH_ID: {
sqlite3_result_int64(ctx,
(sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0));
break;
}
case JEACH_PARENT: {
if( p->i>p->iBegin && p->bRecursive ){
sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]);
}
break;
}
case JEACH_FULLKEY: {
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);
break;
}
case JEACH_PATH: {
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
}
default: {
const char *zRoot = p->zRoot;
if( zRoot==0 ) zRoot = "$";
sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
break;
}
case JEACH_JSON: {
if( p->sParse.isBinary ){
sqlite3_result_blob(ctx, p->sParse.aBlob, p->sParse.nBlob,
SQLITE_STATIC);
}else{
sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC);
}
break;
switch( iColumn ){
case JEACH_KEY: {
if( p->nParent==0 ) break;
if( p->eType==JSONB_OBJECT ){
jsonReturnFromBlob(&p->sParse, p->i, ctx, 1);
}else{
assert( p->eType==JSONB_ARRAY );
sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iKey);
}
break;
}
}else{
/* Blob scan */
switch( iColumn ){
case JEACH_KEY: {
if( p->nParent==0 ) break;
if( p->eType==JSONB_OBJECT ){
jsonReturnFromBlob(&p->sParse, p->i, ctx, 1);
}else{
assert( p->eType==JSONB_ARRAY );
sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iKey);
}
break;
}
case JEACH_VALUE: {
u32 i = jsonSkipLabel(p);
case JEACH_VALUE: {
u32 i = jsonSkipLabel(p);
jsonReturnFromBlob(&p->sParse, i, ctx, 1);
break;
}
case JEACH_TYPE: {
u32 i = jsonSkipLabel(p);
u8 eType = eType = p->sParse.aBlob[i] & 0x0f;
sqlite3_result_text(ctx, jsonbType[eType], -1, SQLITE_STATIC);
break;
}
case JEACH_ATOM: {
u32 i = jsonSkipLabel(p);
if( (p->sParse.aBlob[i] & 0x0f)<JSONB_ARRAY ){
jsonReturnFromBlob(&p->sParse, i, ctx, 1);
break;
}
case JEACH_TYPE: {
u32 i = jsonSkipLabel(p);
u8 eType = eType = p->sParse.aBlob[i] & 0x0f;
sqlite3_result_text(ctx, jsonbType[eType], -1, SQLITE_STATIC);
break;
}
case JEACH_ATOM: {
u32 i = jsonSkipLabel(p);
if( (p->sParse.aBlob[i] & 0x0f)<JSONB_ARRAY ){
jsonReturnFromBlob(&p->sParse, i, ctx, 1);
}
break;
}
case JEACH_ID: {
sqlite3_result_int64(ctx, (sqlite3_int64)p->i);
break;
}
case JEACH_PARENT: {
if( p->nParent>0 ){
sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iHead);
}
break;
}
case JEACH_FULLKEY: {
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: {
sqlite3_result_text64(ctx, p->path.zBuf, p->path.nUsed,
SQLITE_TRANSIENT, SQLITE_UTF8);
break;
}
default: {
const char *zRoot = p->zRoot;
if( zRoot==0 ) zRoot = "$";
sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
break;
}
case JEACH_JSON: {
if( p->sParse.isBinary ){
sqlite3_result_blob(ctx, p->sParse.aBlob, p->sParse.nBlob,
SQLITE_STATIC);
}else{
sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC);
}
break;
}
break;
}
case JEACH_ID: {
sqlite3_result_int64(ctx, (sqlite3_int64)p->i);
break;
}
case JEACH_PARENT: {
if( p->nParent>0 ){
sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iHead);
}
break;
}
case JEACH_FULLKEY: {
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: {
sqlite3_result_text64(ctx, p->path.zBuf, p->path.nUsed,
SQLITE_TRANSIENT, SQLITE_UTF8);
break;
}
default: {
const char *zRoot = p->zRoot;
if( zRoot==0 ) zRoot = "$";
sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
break;
}
case JEACH_JSON: {
if( p->sParse.isBinary ){
sqlite3_result_blob(ctx, p->sParse.aBlob, p->sParse.nBlob,
SQLITE_STATIC);
}else{
sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC);
}
break;
}
}
return SQLITE_OK;
}
@@ -6192,10 +5941,8 @@ static int jsonEachFilter(
int argc, sqlite3_value **argv
){
JsonEachCursor *p = (JsonEachCursor*)cur;
const char *z;
const char *zRoot = 0;
sqlite3_int64 n;
int isBinary;
u32 i, n, sz;
UNUSED_PARAMETER(idxStr);
UNUSED_PARAMETER(argc);
@@ -6204,136 +5951,71 @@ static int jsonEachFilter(
memset(&p->sParse, 0, sizeof(p->sParse));
p->sParse.nJPRef = 1;
if( jsonFuncArgMightBeBinary(argv[0]) ){
u32 i, n, sz;
p->sParse.nBlob = sqlite3_value_bytes(argv[0]);
p->sParse.aBlob = (u8*)sqlite3_value_blob(argv[0]);
if( p->sParse.aBlob==0 ){
return SQLITE_NOMEM;
}
if( idxNum==3 ){
zRoot = (const char*)sqlite3_value_text(argv[1]);
if( zRoot==0 ) return SQLITE_OK;
if( zRoot[0]!='$' ){
sqlite3_free(cur->pVtab->zErrMsg);
cur->pVtab->zErrMsg = jsonPathSyntaxError(zRoot, 0);
jsonEachCursorReset(p);
return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
}else{
p->sParse.zJson = (char*)sqlite3_value_text(argv[0]);
p->sParse.nJson = sqlite3_value_bytes(argv[0]);
if( p->sParse.zJson==0 || jsonConvertTextToBlob(&p->sParse, 0) ){
if( p->sParse.oom ){
return SQLITE_NOMEM;
}
if( zRoot[1]==0 ){
i = p->i = 0;
p->eType = 0;
}else{
i = jsonLookupBlobStep(&p->sParse, 0, zRoot+1, 0);
if( JSON_BLOB_ISERROR(i) ){
p->i = 0;
p->eType = 0;
p->iEnd = 0;
return SQLITE_OK;
}
if( p->sParse.iLabel ){
p->i = p->sParse.iLabel;
p->eType = JSONB_OBJECT;
}else{
p->i = i;
p->eType = JSONB_ARRAY;
}
}
jsonAppendRaw(&p->path, zRoot, sqlite3Strlen30(zRoot));
}else{
p->i = p->iEnd = 0;
return SQLITE_OK;
}
}
if( idxNum==3 ){
zRoot = (const char*)sqlite3_value_text(argv[1]);
if( zRoot==0 ) return SQLITE_OK;
if( zRoot[0]!='$' ){
sqlite3_free(cur->pVtab->zErrMsg);
cur->pVtab->zErrMsg = jsonPathSyntaxError(zRoot, 0);
jsonEachCursorReset(p);
return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
}
if( zRoot[1]==0 ){
i = p->i = 0;
p->eType = 0;
jsonAppendRaw(&p->path, "$", 1);
}
p->nParent = 0;
p->sParse.isBinary = 1;
n = jsonbPayloadSize(&p->sParse, i, &sz);
p->iEnd = i+n+sz;
if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY && !p->bRecursive ){
p->i = i + n;
p->eType = p->sParse.aBlob[i] & 0x0f;
p->aParent = sqlite3DbMallocZero(p->db, sizeof(JsonParent));
if( p->aParent==0 ) return SQLITE_NOMEM;
p->nParent = 1;
p->nParentAlloc = 1;
p->aParent[0].iKey = 0;
p->aParent[0].iEnd = p->iEnd;
p->aParent[0].iHead = p->i;
p->aParent[0].iValue = i;
}
return SQLITE_OK;
}else{
z = (const char*)sqlite3_value_text(argv[0]);
isBinary = 0;
}
if( z==0 ) return SQLITE_OK;
if( sqlite3ValueIsOfClass(argv[0], sqlite3RCStrUnref) ){
p->sParse.zJson = sqlite3RCStrRef((char*)z);
}else{
n = sqlite3_value_bytes(argv[0]);
p->sParse.zJson = sqlite3RCStrNew( n+1 );
if( p->sParse.zJson==0 ) return SQLITE_NOMEM;
memcpy(p->sParse.zJson, z, (size_t)n+(isBinary==0));
p->sParse.nJson = n;
}
p->sParse.bJsonIsRCStr = 1;
p->sParse.isBinary = isBinary;
p->zJson = p->sParse.zJson;
if( jsonParse(&p->sParse, 0) ){
int rc = SQLITE_NOMEM;
if( p->sParse.oom==0 ){
sqlite3_free(cur->pVtab->zErrMsg);
cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON");
if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR;
}
jsonEachCursorReset(p);
return rc;
}else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){
jsonEachCursorReset(p);
return SQLITE_NOMEM;
}else{
JsonNode *pNode = 0;
if( idxNum==3 ){
const char *zErr = 0;
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]!='$' ){
zErr = zRoot;
}else{
pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr);
}
if( zErr ){
sqlite3_free(cur->pVtab->zErrMsg);
cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr, 0);
jsonEachCursorReset(p);
return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
}else if( pNode==0 ){
}else{
i = jsonLookupBlobStep(&p->sParse, 0, zRoot+1, 0);
if( JSON_BLOB_ISERROR(i) ){
p->i = 0;
p->eType = 0;
p->iEnd = 0;
return SQLITE_OK;
}
}else{
pNode = p->sParse.aNode;
}
p->iBegin = p->i = (int)(pNode - p->sParse.aNode);
p->eType = pNode->eType;
if( p->eType>=JSON_ARRAY ){
assert( pNode->eU==0 );
JSON_VVA( pNode->eU = 3 );
pNode->u.iKey = 0;
p->iEnd = p->i + pNode->n + 1;
if( p->bRecursive ){
p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType;
if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){
p->i--;
}
if( p->sParse.iLabel ){
p->i = p->sParse.iLabel;
p->eType = JSONB_OBJECT;
}else{
p->i++;
p->i = i;
p->eType = JSONB_ARRAY;
}
}else{
p->iEnd = p->i+1;
}
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;
n = jsonbPayloadSize(&p->sParse, i, &sz);
p->iEnd = i+n+sz;
if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY && !p->bRecursive ){
p->i = i + n;
p->eType = p->sParse.aBlob[i] & 0x0f;
p->aParent = sqlite3DbMallocZero(p->db, sizeof(JsonParent));
if( p->aParent==0 ) return SQLITE_NOMEM;
p->nParent = 1;
p->nParentAlloc = 1;
p->aParent[0].iKey = 0;
p->aParent[0].iEnd = p->iEnd;
p->aParent[0].iHead = p->i;
p->aParent[0].iValue = i;
}
return SQLITE_OK;
}