diff options
Diffstat (limited to 'ext/misc/json1.c')
-rw-r--r-- | ext/misc/json1.c | 362 |
1 files changed, 217 insertions, 145 deletions
diff --git a/ext/misc/json1.c b/ext/misc/json1.c index ca6021733..89b70f083 100644 --- a/ext/misc/json1.c +++ b/ext/misc/json1.c @@ -33,6 +33,38 @@ SQLITE_EXTENSION_INIT1 #define UNUSED_PARAM(X) (void)(X) +/* +** Versions of isspace(), isalnum() and isdigit() to which it is safe +** to pass signed char values. +*/ +#define safe_isdigit(x) isdigit((unsigned char)(x)) +#define safe_isalnum(x) isalnum((unsigned char)(x)) + +/* +** Growing our own isspace() routine this way is twice as fast as +** the library isspace() function, resulting in a 7% overall performance +** increase for the parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os). +*/ +static const char jsonIsSpace[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +#define safe_isspace(x) (jsonIsSpace[(unsigned char)x]) + /* Unsigned integer types */ typedef sqlite3_uint64 u64; typedef unsigned int u32; @@ -148,11 +180,9 @@ static void jsonReset(JsonString *p){ /* Report an out-of-memory (OOM) condition */ static void jsonOom(JsonString *p){ - if( !p->bErr ){ - p->bErr = 1; - sqlite3_result_error_nomem(p->pCtx); - jsonReset(p); - } + p->bErr = 1; + sqlite3_result_error_nomem(p->pCtx); + jsonReset(p); } /* Enlarge pJson->zBuf so that it can hold at least N more bytes. @@ -231,12 +261,13 @@ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){ for(i=0; i<N; i++){ char c = zIn[i]; if( c=='"' || c=='\\' ){ - if( (p->nUsed+N+1-i > p->nAlloc) && jsonGrow(p,N+1-i)!=0 ) return; + if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return; p->zBuf[p->nUsed++] = '\\'; } p->zBuf[p->nUsed++] = c; } p->zBuf[p->nUsed++] = '"'; + assert( p->nUsed<p->nAlloc ); } /* @@ -334,7 +365,8 @@ static void jsonRenderNode( sqlite3_value **aReplace /* Replacement values */ ){ switch( pNode->eType ){ - case JSON_NULL: { + default: { + assert( pNode->eType==JSON_NULL ); jsonAppendRaw(pOut, "null", 4); break; } @@ -432,7 +464,8 @@ static void jsonReturn( sqlite3_value **aReplace /* Array of replacement values */ ){ switch( pNode->eType ){ - case JSON_NULL: { + default: { + assert( pNode->eType==JSON_NULL ); sqlite3_result_null(pCtx); break; } @@ -459,10 +492,16 @@ static void jsonReturn( break; } case JSON_STRING: { +#if 0 /* Never happens because JNODE_RAW is only set by json_set(), + ** json_insert() and json_replace() and those routines do not + ** call jsonReturn() */ if( pNode->jnFlags & JNODE_RAW ){ sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n, SQLITE_TRANSIENT); - }else if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){ + }else +#endif + assert( (pNode->jnFlags & JNODE_RAW)==0 ); + if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){ /* JSON formatted without any backslash-escapes */ sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2, SQLITE_TRANSIENT); @@ -533,6 +572,44 @@ static void jsonReturn( } } +/* Forward reference */ +static int jsonParseAddNode(JsonParse*,u32,u32,const char*); + +/* +** A macro to hint to the compiler that a function should not be +** inlined. +*/ +#if defined(__GNUC__) +# define JSON_NOINLINE __attribute__((noinline)) +#elif defined(_MSC_VER) && _MSC_VER>=1310 +# define JSON_NOINLINE __declspec(noinline) +#else +# define JSON_NOINLINE +#endif + + +static JSON_NOINLINE int jsonParseAddNodeExpand( + JsonParse *pParse, /* Append the node to this object */ + u32 eType, /* Node type */ + u32 n, /* Content size or sub-node count */ + const char *zContent /* Content */ +){ + u32 nNew; + JsonNode *pNew; + assert( pParse->nNode>=pParse->nAlloc ); + if( pParse->oom ) return -1; + nNew = pParse->nAlloc*2 + 10; + pNew = sqlite3_realloc(pParse->aNode, sizeof(JsonNode)*nNew); + if( pNew==0 ){ + pParse->oom = 1; + return -1; + } + pParse->nAlloc = nNew; + pParse->aNode = pNew; + assert( pParse->nNode<pParse->nAlloc ); + return jsonParseAddNode(pParse, eType, n, zContent); +} + /* ** Create a new JsonNode instance based on the arguments and append that ** instance to the JsonParse. Return the index in pParse->aNode[] of the @@ -546,21 +623,7 @@ static int jsonParseAddNode( ){ JsonNode *p; if( pParse->nNode>=pParse->nAlloc ){ - u32 nNew; - JsonNode *pNew; - if( pParse->oom ) return -1; - nNew = pParse->nAlloc*2 + 10; - if( nNew<=pParse->nNode ){ - pParse->oom = 1; - return -1; - } - pNew = sqlite3_realloc(pParse->aNode, sizeof(JsonNode)*nNew); - if( pNew==0 ){ - pParse->oom = 1; - return -1; - } - pParse->nAlloc = nNew; - pParse->aNode = pNew; + return jsonParseAddNodeExpand(pParse, eType, n, zContent); } p = &pParse->aNode[pParse->nNode]; p->eType = (u8)eType; @@ -585,14 +648,13 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ int iThis; int x; JsonNode *pNode; - while( isspace(pParse->zJson[i]) ){ i++; } - if( (c = pParse->zJson[i])==0 ) return 0; - if( c=='{' ){ + while( safe_isspace(pParse->zJson[i]) ){ i++; } + if( (c = pParse->zJson[i])=='{' ){ /* Parse object */ iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); if( iThis<0 ) return -1; for(j=i+1;;j++){ - while( isspace(pParse->zJson[j]) ){ j++; } + while( safe_isspace(pParse->zJson[j]) ){ j++; } x = jsonParseValue(pParse, j); if( x<0 ){ if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1; @@ -603,13 +665,13 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ if( pNode->eType!=JSON_STRING ) return -1; pNode->jnFlags |= JNODE_LABEL; j = x; - while( isspace(pParse->zJson[j]) ){ j++; } + while( safe_isspace(pParse->zJson[j]) ){ j++; } if( pParse->zJson[j]!=':' ) return -1; j++; x = jsonParseValue(pParse, j); if( x<0 ) return -1; j = x; - while( isspace(pParse->zJson[j]) ){ j++; } + while( safe_isspace(pParse->zJson[j]) ){ j++; } c = pParse->zJson[j]; if( c==',' ) continue; if( c!='}' ) return -1; @@ -622,14 +684,14 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); if( iThis<0 ) return -1; for(j=i+1;;j++){ - while( isspace(pParse->zJson[j]) ){ j++; } + while( safe_isspace(pParse->zJson[j]) ){ j++; } x = jsonParseValue(pParse, j); if( x<0 ){ if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1; return -1; } j = x; - while( isspace(pParse->zJson[j]) ){ j++; } + while( safe_isspace(pParse->zJson[j]) ){ j++; } c = pParse->zJson[j]; if( c==',' ) continue; if( c!=']' ) return -1; @@ -658,17 +720,17 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ return j+1; }else if( c=='n' && strncmp(pParse->zJson+i,"null",4)==0 - && !isalnum(pParse->zJson[i+4]) ){ + && !safe_isalnum(pParse->zJson[i+4]) ){ jsonParseAddNode(pParse, JSON_NULL, 0, 0); return i+4; }else if( c=='t' && strncmp(pParse->zJson+i,"true",4)==0 - && !isalnum(pParse->zJson[i+4]) ){ + && !safe_isalnum(pParse->zJson[i+4]) ){ jsonParseAddNode(pParse, JSON_TRUE, 0, 0); return i+4; }else if( c=='f' && strncmp(pParse->zJson+i,"false",5)==0 - && !isalnum(pParse->zJson[i+5]) ){ + && !safe_isalnum(pParse->zJson[i+5]) ){ jsonParseAddNode(pParse, JSON_FALSE, 0, 0); return i+5; }else if( c=='-' || (c>='0' && c<='9') ){ @@ -707,6 +769,8 @@ static int jsonParseValue(JsonParse *pParse, u32 i){ return -2; /* End of {...} */ }else if( c==']' ){ return -3; /* End of [...] */ + }else if( c==0 ){ + return 0; /* End of file */ }else{ return -1; /* Syntax error */ } @@ -731,7 +795,7 @@ static int jsonParse( i = jsonParseValue(pParse, 0); if( pParse->oom ) i = -1; if( i>0 ){ - while( isspace(zJson[i]) ) i++; + while( safe_isspace(zJson[i]) ) i++; if( zJson[i] ) i = -1; } if( i<=0 ){ @@ -790,6 +854,20 @@ static int jsonParseFindParents(JsonParse *pParse){ return SQLITE_OK; } +/* +** Compare the OBJECT label at pNode against zKey,nKey. Return true on +** a match. +*/ +static int jsonLabelCompare(JsonNode *pNode, const char *zKey, int nKey){ + 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; + } +} + /* forward declaration */ static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**); @@ -820,7 +898,12 @@ static JsonNode *jsonLookupStep( zKey = zPath + 1; for(i=1; zPath[i] && zPath[i]!='"'; i++){} nKey = i-1; - if( zPath[i] ) i++; + if( zPath[i] ){ + i++; + }else{ + *pzErr = zPath; + return 0; + } }else{ zKey = zPath; for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){} @@ -833,9 +916,7 @@ static JsonNode *jsonLookupStep( j = 1; for(;;){ while( j<=pRoot->n ){ - if( pRoot[j].n==nKey+2 - && strncmp(&pRoot[j].u.zJContent[1],zKey,nKey)==0 - ){ + if( jsonLabelCompare(pRoot+j, zKey, nKey) ){ return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr); } j++; @@ -862,19 +943,19 @@ static JsonNode *jsonLookupStep( } return pNode; } - }else if( zPath[0]=='[' && isdigit(zPath[1]) ){ + }else if( zPath[0]=='[' && safe_isdigit(zPath[1]) ){ if( pRoot->eType!=JSON_ARRAY ) return 0; i = 0; - zPath++; - while( isdigit(zPath[0]) ){ - i = i*10 + zPath[0] - '0'; - zPath++; + j = 1; + while( safe_isdigit(zPath[j]) ){ + i = i*10 + zPath[j] - '0'; + j++; } - if( zPath[0]!=']' ){ + if( zPath[j]!=']' ){ *pzErr = zPath; return 0; } - zPath++; + zPath += j + 1; j = 1; for(;;){ while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){ @@ -902,7 +983,7 @@ static JsonNode *jsonLookupStep( } return pNode; } - }else if( zPath[0]!=0 ){ + }else{ *pzErr = zPath; } return 0; @@ -960,6 +1041,7 @@ static JsonNode *jsonLookup( ){ const char *zErr = 0; JsonNode *pNode = 0; + char *zMsg; if( zPath==0 ) return 0; if( zPath[0]!='$' ){ @@ -968,18 +1050,17 @@ static JsonNode *jsonLookup( } zPath++; pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr); - return pNode; + if( zErr==0 ) return pNode; lookup_err: pParse->nErr++; - if( zErr!=0 && pCtx!=0 ){ - char *z = jsonPathSyntaxError(zErr); - if( z ){ - sqlite3_result_error(pCtx, z, -1); - sqlite3_free(z); - }else{ - sqlite3_result_error_nomem(pCtx); - } + 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; } @@ -1102,23 +1183,22 @@ static void jsonArrayLengthFunc( JsonParse x; /* The parse */ sqlite3_int64 n = 0; u32 i; + JsonNode *pNode; if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - if( x.nNode ){ - JsonNode *pNode; - if( argc==2 ){ - const char *zPath = (const char*)sqlite3_value_text(argv[1]); - pNode = jsonLookup(&x, zPath, 0, ctx); - }else{ - pNode = x.aNode; - } - if( pNode==0 ){ - x.nErr = 1; - }else if( pNode->eType==JSON_ARRAY ){ - assert( (pNode->jnFlags & JNODE_APPEND)==0 ); - for(i=1; i<=pNode->n; n++){ - i += jsonNodeSize(&pNode[i]); - } + assert( x.nNode ); + if( argc==2 ){ + const char *zPath = (const char*)sqlite3_value_text(argv[1]); + pNode = jsonLookup(&x, zPath, 0, ctx); + }else{ + pNode = x.aNode; + } + if( pNode==0 ){ + x.nErr = 1; + }else if( pNode->eType==JSON_ARRAY ){ + assert( (pNode->jnFlags & JNODE_APPEND)==0 ); + for(i=1; i<=pNode->n; n++){ + i += jsonNodeSize(&pNode[i]); } } if( x.nErr==0 ) sqlite3_result_int64(ctx, n); @@ -1197,7 +1277,7 @@ static void jsonObjectFunc( for(i=0; i<argc; i+=2){ if( sqlite3_value_type(argv[i])!=SQLITE_TEXT ){ sqlite3_result_error(ctx, "json_object() labels must be TEXT", -1); - jsonZero(&jx); + jsonReset(&jx); return; } jsonAppendSeparator(&jx); @@ -1231,17 +1311,16 @@ static void jsonRemoveFunc( if( argc<1 ) return; if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - if( x.nNode ){ - for(i=1; i<(u32)argc; i++){ - zPath = (const char*)sqlite3_value_text(argv[i]); - if( zPath==0 ) goto remove_done; - pNode = jsonLookup(&x, zPath, 0, ctx); - if( x.nErr ) goto remove_done; - if( pNode ) pNode->jnFlags |= JNODE_REMOVE; - } - if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){ - jsonReturnJson(x.aNode, ctx, 0); - } + assert( x.nNode ); + for(i=1; i<(u32)argc; i++){ + zPath = (const char*)sqlite3_value_text(argv[i]); + if( zPath==0 ) goto remove_done; + pNode = jsonLookup(&x, zPath, 0, ctx); + if( x.nErr ) goto remove_done; + if( pNode ) pNode->jnFlags |= JNODE_REMOVE; + } + if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){ + jsonReturnJson(x.aNode, ctx, 0); } remove_done: jsonParseReset(&x); @@ -1269,22 +1348,21 @@ static void jsonReplaceFunc( return; } if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - if( x.nNode ){ - for(i=1; i<(u32)argc; i+=2){ - zPath = (const char*)sqlite3_value_text(argv[i]); - pNode = jsonLookup(&x, zPath, 0, ctx); - if( x.nErr ) goto replace_err; - if( pNode ){ - pNode->jnFlags |= (u8)JNODE_REPLACE; - pNode->iVal = (u8)(i+1); - } - } - if( x.aNode[0].jnFlags & JNODE_REPLACE ){ - sqlite3_result_value(ctx, argv[x.aNode[0].iVal]); - }else{ - jsonReturnJson(x.aNode, ctx, argv); + assert( x.nNode ); + for(i=1; i<(u32)argc; i+=2){ + zPath = (const char*)sqlite3_value_text(argv[i]); + pNode = jsonLookup(&x, zPath, 0, ctx); + if( x.nErr ) goto replace_err; + if( pNode ){ + pNode->jnFlags |= (u8)JNODE_REPLACE; + pNode->iVal = (u8)(i+1); } } + if( x.aNode[0].jnFlags & JNODE_REPLACE ){ + sqlite3_result_value(ctx, argv[x.aNode[0].iVal]); + }else{ + jsonReturnJson(x.aNode, ctx, argv); + } replace_err: jsonParseReset(&x); } @@ -1319,27 +1397,26 @@ static void jsonSetFunc( return; } if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - if( x.nNode ){ - for(i=1; i<(u32)argc; i+=2){ - zPath = (const char*)sqlite3_value_text(argv[i]); - bApnd = 0; - pNode = jsonLookup(&x, zPath, &bApnd, ctx); - if( x.oom ){ - sqlite3_result_error_nomem(ctx); - goto jsonSetDone; - }else if( x.nErr ){ - goto jsonSetDone; - }else if( pNode && (bApnd || bIsSet) ){ - pNode->jnFlags |= (u8)JNODE_REPLACE; - pNode->iVal = (u8)(i+1); - } - } - if( x.aNode[0].jnFlags & JNODE_REPLACE ){ - sqlite3_result_value(ctx, argv[x.aNode[0].iVal]); - }else{ - jsonReturnJson(x.aNode, ctx, argv); + assert( x.nNode ); + for(i=1; i<(u32)argc; i+=2){ + zPath = (const char*)sqlite3_value_text(argv[i]); + bApnd = 0; + pNode = jsonLookup(&x, zPath, &bApnd, ctx); + if( x.oom ){ + sqlite3_result_error_nomem(ctx); + goto jsonSetDone; + }else if( x.nErr ){ + goto jsonSetDone; + }else if( pNode && (bApnd || bIsSet) ){ + pNode->jnFlags |= (u8)JNODE_REPLACE; + pNode->iVal = (u8)(i+1); } } + if( x.aNode[0].jnFlags & JNODE_REPLACE ){ + sqlite3_result_value(ctx, argv[x.aNode[0].iVal]); + }else{ + jsonReturnJson(x.aNode, ctx, argv); + } jsonSetDone: jsonParseReset(&x); } @@ -1358,19 +1435,18 @@ static void jsonTypeFunc( ){ JsonParse x; /* The parse */ const char *zPath; + JsonNode *pNode; if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - if( x.nNode ){ - JsonNode *pNode; - if( argc==2 ){ - zPath = (const char*)sqlite3_value_text(argv[1]); - pNode = jsonLookup(&x, zPath, 0, ctx); - }else{ - pNode = x.aNode; - } - if( pNode ){ - sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC); - } + assert( x.nNode ); + if( argc==2 ){ + zPath = (const char*)sqlite3_value_text(argv[1]); + pNode = jsonLookup(&x, zPath, 0, ctx); + }else{ + pNode = x.aNode; + } + if( pNode ){ + sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC); } jsonParseReset(&x); } @@ -1390,9 +1466,7 @@ static void jsonValidFunc( int rc = 0; UNUSED_PARAM(argc); - if( jsonParse(&x, 0, (const char*)sqlite3_value_text(argv[0]))==0 - && x.nNode>0 - ){ + if( jsonParse(&x, 0, (const char*)sqlite3_value_text(argv[0]))==0 ){ rc = 1; } jsonParseReset(&x); @@ -1669,7 +1743,7 @@ static int jsonEachColumn( sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC); break; } - default: { + case JEACH_JSON: { assert( i==JEACH_JSON ); sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC); break; @@ -1745,15 +1819,6 @@ static int jsonEachFilter( if( idxNum==0 ) return SQLITE_OK; z = (const char*)sqlite3_value_text(argv[0]); if( z==0 ) return SQLITE_OK; - if( idxNum&2 ){ - 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); - return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM; - } - } n = sqlite3_value_bytes(argv[0]); p->zJson = sqlite3_malloc64( n+1 ); if( p->zJson==0 ) return SQLITE_NOMEM; @@ -1771,15 +1836,21 @@ static int jsonEachFilter( jsonEachCursorReset(p); return SQLITE_NOMEM; }else{ - JsonNode *pNode; + 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); - pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr); - if( p->sParse.nErr ){ + 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); jsonEachCursorReset(p); @@ -1796,6 +1867,7 @@ static int jsonEachFilter( 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--; } @@ -1806,7 +1878,7 @@ static int jsonEachFilter( p->iEnd = p->i+1; } } - return p->sParse.oom ? SQLITE_NOMEM : SQLITE_OK; + return SQLITE_OK; } /* The methods of the json_each virtual table */ |