Cache the JSON parse used by json_extract().
FossilOrigin-Name: 44ca6c2c4639f3c50ae9233ee299ff0fc4566462c31f28d8676f8de7ffdcd7f0
This commit is contained in:
parent
f7fa4e71f4
commit
3fb153cb29
@ -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 */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -413,6 +414,14 @@ static void jsonParseReset(JsonParse *pParse){
|
||||
pParse->aUp = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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
|
||||
@ -964,6 +973,49 @@ static int jsonParseFindParents(JsonParse *pParse){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** 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.
|
||||
|
15
manifest
15
manifest
@ -1,5 +1,5 @@
|
||||
C Negative\sN\svalues\sin\ssqlite3_get_auxdata()\sand\ssqlite3_set_auxdata()\scan\sbe\nused\sto\saccess\san\sauxiliary\sdata\scache\sover\sall\sfunctions\sin\sa\ssingle\sprepared\s\nstatement.
|
||||
D 2017-05-11T15:20:18.112
|
||||
C Cache\sthe\sJSON\sparse\sused\sby\sjson_extract().
|
||||
D 2017-05-11T16:49:59.245
|
||||
F Makefile.in 1cc758ce3374a32425e4d130c2fe7b026b20de5b8843243de75f087c0a2661fb
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc 6a8c838220f7c00820e1fc0ac1bccaaa8e5676067e1dbfa1bafa7a4ffecf8ae6
|
||||
@ -219,7 +219,7 @@ F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2
|
||||
F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f
|
||||
F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25
|
||||
F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c
|
||||
F ext/misc/json1.c bd3bbdefb6024c5e40287d61cdf876587c18a6e60fbe8cd6bcdde10eefd14bb1
|
||||
F ext/misc/json1.c dbe086615b9546c156bf32b9378fc09383b58bd17513b866cfd24c1e15281984
|
||||
F ext/misc/memvfs.c e5225bc22e79dde6b28380f3a068ddf600683a33
|
||||
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
|
||||
F ext/misc/percentile.c 92699c8cd7d517ff610e6037e56506f8904dae2e
|
||||
@ -1579,10 +1579,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 3980ea0911b3ad3f86d7a7bdc6503f233315c274f473e18831e13eda2c238eeb
|
||||
R dd46ebd5214a15a152d68d903a52e3e5
|
||||
T *branch * auxdata-cache
|
||||
T *sym-auxdata-cache *
|
||||
T -sym-trunk *
|
||||
P ff5306752e83e760255a10f20168c0f090929a4fee2a5f720dfab36f0ee72fae
|
||||
R cae1848a63e8e13e207beadd6dc14b62
|
||||
U drh
|
||||
Z 41e6a797cec545b1cb4bc140fa542902
|
||||
Z e9ec1c79d7987d6b2eda6f4466e2dc4b
|
||||
|
@ -1 +1 @@
|
||||
ff5306752e83e760255a10f20168c0f090929a4fee2a5f720dfab36f0ee72fae
|
||||
44ca6c2c4639f3c50ae9233ee299ff0fc4566462c31f28d8676f8de7ffdcd7f0
|
Loading…
Reference in New Issue
Block a user