diff options
author | drh <drh@noemail.net> | 2017-05-11 16:49:59 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2017-05-11 16:49:59 +0000 |
commit | 3fb153cb297158830ce49edcbb0ccdd5a84179d5 (patch) | |
tree | e4b94ff731524f8ce0efdb840e5ad76ca0b03ca4 /ext/misc/json1.c | |
parent | f7fa4e71f4ec1b14768fcda2ab3a7df909a738b4 (diff) | |
download | sqlite-3fb153cb297158830ce49edcbb0ccdd5a84179d5.tar.gz sqlite-3fb153cb297158830ce49edcbb0ccdd5a84179d5.zip |
Cache the JSON parse used by json_extract().
FossilOrigin-Name: 44ca6c2c4639f3c50ae9233ee299ff0fc4566462c31f28d8676f8de7ffdcd7f0
Diffstat (limited to 'ext/misc/json1.c')
-rw-r--r-- | ext/misc/json1.c | 81 |
1 files changed, 67 insertions, 14 deletions
diff --git a/ext/misc/json1.c b/ext/misc/json1.c index 2ef6e128e..c1d2334a1 100644 --- a/ext/misc/json1.c +++ b/ext/misc/json1.c @@ -171,6 +171,7 @@ struct JsonParse { u8 oom; /* Set to true if out of memory */ u8 nErr; /* Number of errors seen */ u16 iDepth; /* Nesting depth */ + int nJson; /* Length of the zJson string in bytes */ }; /* @@ -414,6 +415,14 @@ static void jsonParseReset(JsonParse *pParse){ } /* +** Free a JsonParse object that was obtained from sqlite3_malloc(). +*/ +static void jsonParseFree(JsonParse *pParse){ + jsonParseReset(pParse); + sqlite3_free(pParse); +} + +/* ** Convert the JsonNode pNode into a pure JSON string and ** append to pOut. Subsubstructure is also included. Return ** the number of JsonNode objects that are encoded. @@ -965,6 +974,49 @@ static int jsonParseFindParents(JsonParse *pParse){ } /* +** Magic number used for the JSON parse cache in sqlite3_get_auxdata() +*/ +#define JSON_CACHE_ID (-429938) + +/* +** Obtain a complete parse of the JSON found in the first argument +** of the argv array. Use the sqlite3_get_auxdata() cache for this +** 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, +** and also register the new parse so that it will be available for +** future sqlite3_get_auxdata() calls. +*/ +static JsonParse *jsonParseCached( + sqlite3_context *pCtx, + sqlite3_value **argv +){ + const char *zJson = (const char*)sqlite3_value_text(argv[0]); + int nJson = sqlite3_value_bytes(argv[0]); + JsonParse *p; + if( zJson==0 ) return 0; + p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID); + if( p && p->nJson==nJson && memcmp(p->zJson,zJson,nJson)==0 ){ + p->nErr = 0; + return p; /* The cached entry matches, so return it */ + } + p = sqlite3_malloc( sizeof(*p) + nJson + 1 ); + if( p==0 ){ + sqlite3_result_error_nomem(pCtx); + return 0; + } + memset(p, 0, sizeof(*p)); + p->zJson = (char*)&p[1]; + memcpy((char*)p->zJson, zJson, nJson+1); + if( jsonParse(p, pCtx, p->zJson) ){ + sqlite3_free(p); + return 0; + } + p->nJson = nJson; + sqlite3_set_auxdata(pCtx, JSON_CACHE_ID, p, (void(*)(void*))jsonParseFree); + return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID); +} + +/* ** Compare the OBJECT label at pNode against zKey,nKey. Return true on ** a match. */ @@ -1329,29 +1381,30 @@ static void jsonArrayLengthFunc( int argc, sqlite3_value **argv ){ - JsonParse x; /* The parse */ + JsonParse *p; /* The parse */ sqlite3_int64 n = 0; u32 i; JsonNode *pNode; - if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - assert( x.nNode ); + p = jsonParseCached(ctx, argv); + if( p==0 ) return; + assert( p->nNode ); if( argc==2 ){ const char *zPath = (const char*)sqlite3_value_text(argv[1]); - pNode = jsonLookup(&x, zPath, 0, ctx); + pNode = jsonLookup(p, zPath, 0, ctx); }else{ - pNode = x.aNode; + pNode = p->aNode; } if( pNode==0 ){ - x.nErr = 1; - }else if( pNode->eType==JSON_ARRAY ){ + return; + } + 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); - jsonParseReset(&x); + sqlite3_result_int64(ctx, n); } /* @@ -1367,20 +1420,21 @@ static void jsonExtractFunc( int argc, sqlite3_value **argv ){ - JsonParse x; /* The parse */ + JsonParse *p; /* The parse */ JsonNode *pNode; const char *zPath; JsonString jx; int i; if( argc<2 ) return; - if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; + p = jsonParseCached(ctx, argv); + if( p==0 ) return; jsonInit(&jx, ctx); jsonAppendChar(&jx, '['); for(i=1; i<argc; i++){ zPath = (const char*)sqlite3_value_text(argv[i]); - pNode = jsonLookup(&x, zPath, 0, ctx); - if( x.nErr ) break; + pNode = jsonLookup(p, zPath, 0, ctx); + if( p->nErr ) break; if( argc>2 ){ jsonAppendSeparator(&jx); if( pNode ){ @@ -1398,7 +1452,6 @@ static void jsonExtractFunc( sqlite3_result_subtype(ctx, JSON_SUBTYPE); } jsonReset(&jx); - jsonParseReset(&x); } /* This is the RFC 7396 MergePatch algorithm. |