diff options
author | drh <> | 2023-07-28 13:52:08 +0000 |
---|---|---|
committer | drh <> | 2023-07-28 13:52:08 +0000 |
commit | 859dd4fc2f09ba63bbf403d399e89baa1be60c26 (patch) | |
tree | da7c065a5729abee8620b2968db37bb9d589982d /src/json.c | |
parent | ab12b750ded006bbbbc6aaea7655faadff3bec3a (diff) | |
parent | b1926192fa1a8c0cdb3faf9dbe111a57b4ab9e5a (diff) | |
download | sqlite-859dd4fc2f09ba63bbf403d399e89baa1be60c26.tar.gz sqlite-859dd4fc2f09ba63bbf403d399e89baa1be60c26.zip |
JSON performance improvements: (1) Add a cache for large string values
on OP_Column to avoid having to extract the string multiple times.
(2) Internal JSON caching improvements.
FossilOrigin-Name: 771fe35074b50b8d4a6583e61c53871b2445f7a58c82f3fc3bf6776e562e63af
Diffstat (limited to 'src/json.c')
-rw-r--r-- | src/json.c | 93 |
1 files changed, 50 insertions, 43 deletions
diff --git a/src/json.c b/src/json.c index 493a1b99c..cc39264c0 100644 --- a/src/json.c +++ b/src/json.c @@ -174,6 +174,7 @@ struct JsonParse { u16 iDepth; /* Nesting depth */ u8 nErr; /* Number of errors seen */ u8 oom; /* Set to true if out of memory */ + u8 bJsonIsRCStr; /* True if zJson is an RCStr */ u8 hasNonstd; /* True if input uses non-standard features like JSON5 */ u8 useMod; /* Actually use the edits contain inside aNode */ u8 hasMod; /* aNode contains edits from the original zJson */ @@ -619,6 +620,11 @@ static void jsonParseReset(JsonParse *pParse){ sqlite3_free(pParse->aUp); pParse->aUp = 0; } + if( pParse->bJsonIsRCStr ){ + sqlite3RCStrUnref(pParse->zJson); + pParse->zJson = 0; + pParse->bJsonIsRCStr = 0; + } if( pParse->zAlt ){ sqlite3RCStrUnref(pParse->zAlt); pParse->zAlt = 0; @@ -1745,26 +1751,15 @@ json_parse_restart: ** are any errors. If an error occurs, free all memory held by pParse, ** but not pParse itself. ** -** pParse is uninitialized when this routine is called. -** -** pParse->nJPRef set to 1. The caller becomes the owner of the -** the JsonParse object. -** -** pParse->bOwnsJson is set to bTakeJson. If bTakeJson is 1, the newly -** initialized JsonParse object will become the owner of the zJson input -** string. If bTakeJson is 0, then the caller is responsible for -** preserving zJson for the lifetime of the JsonParse object. +** pParse must be initialized to an empty parse object prior to calling +** this routine. */ static int jsonParse( JsonParse *pParse, /* Initialize and fill this JsonParse object */ - sqlite3_context *pCtx, /* Report errors here */ - char *zJson /* Input JSON text to be parsed */ + sqlite3_context *pCtx /* Report errors here */ ){ int i; - memset(pParse, 0, sizeof(*pParse)); - if( zJson==0 ) return 1; - pParse->zJson = zJson; - pParse->nJPRef = 1; + const char *zJson = pParse->zJson; i = jsonParseValue(pParse, 0); if( pParse->oom ) i = -1; if( i>0 ){ @@ -1884,6 +1879,7 @@ static JsonParse *jsonParseCached( int iMinKey = 0; u32 iMinHold = 0xffffffff; u32 iMaxHold = 0; + int bJsonRCStr; if( zJson==0 ) return 0; for(iKey=0; iKey<JSON_CACHE_SZ; iKey++){ @@ -1895,7 +1891,7 @@ static JsonParse *jsonParseCached( if( pMatch==0 && p->nJson==nJson && (p->hasMod==0 || bUnedited==0) - && memcmp(p->zJson,zJson,nJson)==0 + && (p->zJson==zJson || memcmp(p->zJson,zJson,nJson)==0) ){ p->nErr = 0; p->useMod = 0; @@ -1930,16 +1926,22 @@ static JsonParse *jsonParseCached( /* The input JSON was not found anywhere in the cache. We will need ** to parse it ourselves and generate a new JsonParse object. */ - p = sqlite3_malloc64( sizeof(*p) + nJson + 1 ); + 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)); - p->zJson = (char*)&p[1]; - memcpy(p->zJson, zJson, nJson); - p->zJson[nJson] = 0; - if( jsonParse(p, pErrCtx, p->zJson) ){ + 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 */ @@ -2663,29 +2665,27 @@ static void jsonPatchFunc( int argc, sqlite3_value **argv ){ - JsonParse x; /* The JSON that is being patched */ - JsonParse y; /* The patch */ + JsonParse *pX; /* The JSON that is being patched */ + JsonParse *pY; /* The patch */ JsonNode *pResult; /* The result of the merge */ UNUSED_PARAMETER(argc); - if( jsonParse(&x, ctx, (char*)sqlite3_value_text(argv[0])) ) return; - if( jsonParse(&y, ctx, (char*)sqlite3_value_text(argv[1])) ){ - jsonParseReset(&x); - return; - } - x.useMod = 1; - y.useMod = 1; - pResult = jsonMergePatch(&x, 0, y.aNode); - assert( pResult!=0 || x.oom ); - if( pResult && x.oom==0 ){ - jsonDebugPrintParse(&x); + pX = jsonParseCached(ctx, argv[0], ctx, 1); + if( pX==0 ) return; + pY = jsonParseCached(ctx, argv[1], ctx, 1); + if( pY==0 ) return; + pX->useMod = 1; + pX->hasMod = 1; + pY->useMod = 1; + pResult = jsonMergePatch(pX, 0, pY->aNode); + assert( pResult!=0 || pX->oom ); + if( pResult && pX->oom==0 ){ + jsonDebugPrintParse(pX); jsonDebugPrintNode(pResult); - jsonReturnJson(&x, pResult, ctx, 0); + jsonReturnJson(pX, pResult, ctx, 0); }else{ sqlite3_result_error_nomem(ctx); } - jsonParseReset(&x); - jsonParseReset(&y); } @@ -3312,7 +3312,6 @@ static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ /* Reset a JsonEachCursor back to its original state. Free any memory ** held. */ static void jsonEachCursorReset(JsonEachCursor *p){ - sqlite3_free(p->zJson); sqlite3_free(p->zRoot); jsonParseReset(&p->sParse); p->iRowid = 0; @@ -3632,11 +3631,19 @@ static int jsonEachFilter( if( idxNum==0 ) return SQLITE_OK; z = (const char*)sqlite3_value_text(argv[0]); if( z==0 ) return SQLITE_OK; - n = sqlite3_value_bytes(argv[0]); - p->zJson = sqlite3_malloc64( n+1 ); - if( p->zJson==0 ) return SQLITE_NOMEM; - memcpy(p->zJson, z, (size_t)n+1); - if( jsonParse(&p->sParse, 0, p->zJson) ){ + memset(&p->sParse, 0, sizeof(p->sParse)); + p->sParse.nJPRef = 1; + if( sqlite3ValueIsOfClass(argv[0], (void(*)(void*))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+1); + } + p->sParse.bJsonIsRCStr = 1; + p->zJson = p->sParse.zJson; + if( jsonParse(&p->sParse, 0) ){ int rc = SQLITE_NOMEM; if( p->sParse.oom==0 ){ sqlite3_free(cur->pVtab->zErrMsg); |