Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 1110934

Browse files
author
Nikita Glukhov
committed
Add jsonpath items with external execution
1 parent b2a8f46 commit 1110934

File tree

3 files changed

+110
-20
lines changed

3 files changed

+110
-20
lines changed

src/backend/utils/adt/jsonpath.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ typedef struct JsonPathContext
7575
{
7676
StringInfo buf;
7777
Jsonb *vars;
78+
int32 id;
7879
} JsonPathContext;
7980

8081
static Datum jsonPathFromCstring(char *in, int len);
@@ -210,13 +211,16 @@ encodeJsonPath(JsonPathParseItem *item, bool lax, int32 sizeEstimation,
210211

211212
cxt.buf = &buf;
212213
cxt.vars = vars;
214+
cxt.id = 0;
215+
213216
flattenJsonPathParseItem(&cxt, item, 0, false);
214217

215218
res = (JsonPath *) buf.data;
216219
SET_VARSIZE(res, buf.len);
217220
res->header = JSONPATH_VERSION;
218221
if (lax)
219222
res->header |= JSONPATH_LAX;
223+
res->ext_items_count = cxt.id;
220224

221225
return res;
222226
}

src/backend/utils/adt/jsonpath_exec.c

Lines changed: 105 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ typedef struct JsonPathExecContext
144144
* evaluation */
145145
int lastGeneratedObjectId; /* "id" counter for .keyvalue()
146146
* evaluation */
147+
void **cache;
148+
MemoryContext cache_mcxt;
147149
int innermostArraySize; /* for LAST array index evaluation */
148150
bool laxMode; /* true for "lax" mode, false for "strict"
149151
* mode */
@@ -211,6 +213,12 @@ typedef struct JsonPathUserFuncContext
211213
bool silent; /* error suppression flag */
212214
} JsonPathUserFuncContext;
213215

216+
typedef struct JsonpathQueryContext
217+
{
218+
void *cache; /* jsonpath executor cache */
219+
FuncCallContext *srfcxt; /* SRF context */
220+
} JsonpathQueryContext;
221+
214222
/* Structures for JSON_TABLE execution */
215223
typedef struct JsonTableScanState JsonTableScanState;
216224
typedef struct JsonTableJoinState JsonTableJoinState;
@@ -297,13 +305,16 @@ static float8 float8_mod_error(float8 val1, float8 val2, bool *error);
297305

298306
static void freeUserFuncContext(JsonPathUserFuncContext *cxt);
299307
static JsonPathExecResult executeUserFunc(FunctionCallInfo fcinfo,
300-
JsonPathUserFuncContext *cxt, bool isJsonb, bool copy);
308+
JsonPathUserFuncContext *cxt, bool isJsonb, bool copy,
309+
void **fn_extra);
301310

302311
static JsonPathExecResult executeJsonPath(JsonPath *path, void *vars,
303312
JsonPathVarCallback getVar,
304313
Jsonx *json, bool isJsonb,
305314
bool throwErrors,
306-
JsonValueList *result);
315+
JsonValueList *result,
316+
void **pCache,
317+
MemoryContext cacheCxt);
307318
static JsonPathExecResult executeItem(JsonPathExecContext *cxt,
308319
JsonPathItem *jsp, JsonItem *jb,
309320
JsonValueList *found);
@@ -475,7 +486,8 @@ static bool JsonTableNextRow(JsonTableScanState *scan, bool isJsonb);
475486
static Datum
476487
jsonx_path_exists(PG_FUNCTION_ARGS, bool isJsonb)
477488
{
478-
JsonPathExecResult res = executeUserFunc(fcinfo, NULL, isJsonb, false);
489+
JsonPathExecResult res = executeUserFunc(fcinfo, NULL, isJsonb, false,
490+
&fcinfo->flinfo->fn_extra);
479491

480492
if (jperIsError(res))
481493
PG_RETURN_NULL();
@@ -522,7 +534,8 @@ jsonx_path_match(PG_FUNCTION_ARGS, bool isJsonb)
522534
{
523535
JsonPathUserFuncContext cxt;
524536

525-
(void) executeUserFunc(fcinfo, &cxt, isJsonb, false);
537+
(void) executeUserFunc(fcinfo, &cxt, isJsonb, false,
538+
&fcinfo->flinfo->fn_extra);
526539

527540
freeUserFuncContext(&cxt);
528541

@@ -584,22 +597,27 @@ json_path_match_opr(PG_FUNCTION_ARGS)
584597
static Datum
585598
jsonx_path_query(PG_FUNCTION_ARGS, bool isJsonb)
586599
{
600+
JsonpathQueryContext *cxt = fcinfo->flinfo->fn_extra;
587601
FuncCallContext *funcctx;
588602
List *found;
589603
JsonItem *v;
590604
ListCell *c;
591605
Datum res;
592606

593-
if (SRF_IS_FIRSTCALL())
607+
if (!cxt)
608+
cxt = fcinfo->flinfo->fn_extra =
609+
MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt, sizeof(*cxt));
610+
611+
if (SRF_IS_FIRSTCALL_EXT(&cxt->srfcxt))
594612
{
595613
JsonPathUserFuncContext jspcxt;
596614
MemoryContext oldcontext;
597615

598-
funcctx = SRF_FIRSTCALL_INIT();
616+
funcctx = SRF_FIRSTCALL_INIT_EXT(&cxt->srfcxt);
599617
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
600618

601619
/* jsonb and jsonpath arguments are copied into SRF context. */
602-
(void) executeUserFunc(fcinfo, &jspcxt, isJsonb, true);
620+
(void) executeUserFunc(fcinfo, &jspcxt, isJsonb, true, &cxt->cache);
603621

604622
/*
605623
* Don't free jspcxt because items in jspcxt.found can reference
@@ -610,13 +628,13 @@ jsonx_path_query(PG_FUNCTION_ARGS, bool isJsonb)
610628
MemoryContextSwitchTo(oldcontext);
611629
}
612630

613-
funcctx = SRF_PERCALL_SETUP();
631+
funcctx = SRF_PERCALL_SETUP_EXT(&cxt->srfcxt);
614632
found = funcctx->user_fctx;
615633

616634
c = list_head(found);
617635

618636
if (c == NULL)
619-
SRF_RETURN_DONE(funcctx);
637+
SRF_RETURN_DONE_EXT(funcctx, &cxt->srfcxt);
620638

621639
v = lfirst(c);
622640
funcctx->user_fctx = list_delete_first(found);
@@ -651,7 +669,8 @@ jsonx_path_query_array(PG_FUNCTION_ARGS, bool isJsonb)
651669
JsonPathUserFuncContext cxt;
652670
Datum res;
653671

654-
(void) executeUserFunc(fcinfo, &cxt, isJsonb, false);
672+
(void) executeUserFunc(fcinfo, &cxt, isJsonb, false,
673+
&fcinfo->flinfo->fn_extra);
655674

656675
res = JsonbValueToJsonxDatum(wrapItemsInArray(&cxt.found, isJsonb), isJsonb);
657676

@@ -683,7 +702,8 @@ jsonx_path_query_first(PG_FUNCTION_ARGS, bool isJsonb)
683702
JsonPathUserFuncContext cxt;
684703
Datum res;
685704

686-
(void) executeUserFunc(fcinfo, &cxt, isJsonb, false);
705+
(void) executeUserFunc(fcinfo, &cxt, isJsonb, false,
706+
&fcinfo->flinfo->fn_extra);
687707

688708
if (JsonValueListLength(&cxt.found) >= 1)
689709
res = JsonItemToJsonxDatum(JsonValueListHead(&cxt.found), isJsonb);
@@ -721,7 +741,8 @@ jsonx_path_query_first_text(PG_FUNCTION_ARGS, bool isJsonb)
721741
JsonPathUserFuncContext cxt;
722742
text *txt;
723743

724-
(void) executeUserFunc(fcinfo, &cxt, isJsonb, false);
744+
(void) executeUserFunc(fcinfo, &cxt, isJsonb, false,
745+
&fcinfo->flinfo->fn_extra);
725746

726747
if (JsonValueListLength(&cxt.found) >= 1)
727748
txt = JsonItemUnquoteText(JsonValueListHead(&cxt.found), isJsonb);
@@ -771,7 +792,7 @@ freeUserFuncContext(JsonPathUserFuncContext *cxt)
771792
*/
772793
static JsonPathExecResult
773794
executeUserFunc(FunctionCallInfo fcinfo, JsonPathUserFuncContext *cxt,
774-
bool isJsonb, bool copy)
795+
bool isJsonb, bool copy, void **fn_extra)
775796
{
776797
Datum js_toasted = PG_GETARG_DATUM(0);
777798
struct varlena *js_detoasted = copy ?
@@ -809,7 +830,8 @@ executeUserFunc(FunctionCallInfo fcinfo, JsonPathUserFuncContext *cxt,
809830
}
810831

811832
res = executeJsonPath(jp, vars, getJsonPathVariableFromJsonx,
812-
js, isJsonb, !silent, cxt ? &cxt->found : NULL);
833+
js, isJsonb, !silent, cxt ? &cxt->found : NULL,
834+
fn_extra, fcinfo->flinfo->fn_mcxt);
813835

814836
if (!cxt && !copy)
815837
{
@@ -854,7 +876,7 @@ executeUserFunc(FunctionCallInfo fcinfo, JsonPathUserFuncContext *cxt,
854876
static JsonPathExecResult
855877
executeJsonPath(JsonPath *path, void *vars, JsonPathVarCallback getVar,
856878
Jsonx *json, bool isJsonb, bool throwErrors,
857-
JsonValueList *result)
879+
JsonValueList *result, void **pCache, MemoryContext cacheCxt)
858880
{
859881
JsonPathExecContext cxt;
860882
JsonPathExecResult res;
@@ -863,6 +885,66 @@ executeJsonPath(JsonPath *path, void *vars, JsonPathVarCallback getVar,
863885
JsonbValue *jbv = JsonItemJbv(&jsi);
864886
JsonItemStackEntry root;
865887

888+
if (path->ext_items_count)
889+
{
890+
if (pCache)
891+
{
892+
struct
893+
{
894+
JsonPath *path;
895+
void **cache;
896+
} *cache = *pCache;
897+
898+
if (!cache)
899+
cache = *pCache = MemoryContextAllocZero(cacheCxt, sizeof(*cache));
900+
901+
if (cache->path &&
902+
(VARSIZE(path) != VARSIZE(cache->path) ||
903+
memcmp(path, cache->path, VARSIZE(path))))
904+
{
905+
/* invalidate cache TODO optimize */
906+
cache->path = NULL;
907+
908+
if (cache->cache)
909+
{
910+
pfree(cache->cache);
911+
cache->cache = NULL;
912+
}
913+
}
914+
915+
if (cache->path)
916+
{
917+
Assert(cache->cache);
918+
}
919+
else
920+
{
921+
Assert(!cache->cache);
922+
923+
cache->path = MemoryContextAlloc(cacheCxt, VARSIZE(path));
924+
memcpy(cache->path, path, VARSIZE(path));
925+
926+
cache->cache = MemoryContextAllocZero(cacheCxt,
927+
sizeof(cxt.cache[0]) *
928+
path->ext_items_count);
929+
}
930+
931+
cxt.cache = cache->cache;
932+
cxt.cache_mcxt = cacheCxt;
933+
934+
path = cache->path; /* use cached jsonpath value */
935+
}
936+
else
937+
{
938+
cxt.cache = palloc0(sizeof(cxt.cache[0]) * path->ext_items_count);
939+
cxt.cache_mcxt = CurrentMemoryContext;
940+
}
941+
}
942+
else
943+
{
944+
cxt.cache = NULL;
945+
cxt.cache_mcxt = NULL;
946+
}
947+
866948
jspInit(&jsp, path);
867949

868950
if (isJsonb)
@@ -4169,7 +4251,8 @@ JsonPathExists(Datum jb, JsonPath *jp, List *vars, bool isJsonb,
41694251
{
41704252
Jsonx *js = DatumGetJsonxP(jb, isJsonb);
41714253
JsonPathExecResult res = executeJsonPath(jp, vars, EvalJsonPathVar,
4172-
js, isJsonb, !error, NULL);
4254+
js, isJsonb, !error,
4255+
NULL, NULL, NULL);
41734256

41744257
Assert(error || !jperIsError(res));
41754258

@@ -4190,7 +4273,8 @@ JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper, bool *empty,
41904273
JsonPathExecResult res PG_USED_FOR_ASSERTS_ONLY;
41914274
int count;
41924275

4193-
res = executeJsonPath(jp, vars, EvalJsonPathVar, js, isJsonb, !error, &found);
4276+
res = executeJsonPath(jp, vars, EvalJsonPathVar, js, isJsonb, !error,
4277+
&found, NULL, NULL);
41944278

41954279
Assert(error || !jperIsError(res));
41964280

@@ -4259,11 +4343,11 @@ JsonPathValue(Datum jb, JsonPath *jp, bool *empty, bool *error, List *vars,
42594343
Jsonx *js = DatumGetJsonxP(jb, isJsonb);
42604344
JsonItem *res;
42614345
JsonValueList found = { 0 };
4262-
JsonPathExecResult jper PG_USED_FOR_ASSERTS_ONLY;
4346+
JsonPathExecResult jper;
42634347
int count;
42644348

42654349
jper = executeJsonPath(jp, vars, EvalJsonPathVar, js, isJsonb, !error,
4266-
&found);
4350+
&found, NULL, NULL);
42674351

42684352
Assert(error || !jperIsError(jper));
42694353

@@ -4615,7 +4699,8 @@ JsonTableResetContextItem(JsonTableScanState *scan, Datum item, bool isJsonb)
46154699
oldcxt = MemoryContextSwitchTo(scan->mcxt);
46164700

46174701
res = executeJsonPath(scan->path, scan->args, EvalJsonPathVar, js, isJsonb,
4618-
scan->errorOnError, &scan->found);
4702+
scan->errorOnError, &scan->found,
4703+
NULL /* FIXME */, NULL);
46194704

46204705
MemoryContextSwitchTo(oldcxt);
46214706

src/include/utils/jsonpath.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ typedef struct
2626
{
2727
int32 vl_len_; /* varlena header (do not touch directly!) */
2828
uint32 header; /* version and flags (see below) */
29+
uint32 ext_items_count; /* number of items that need cache for external execution */
2930
char data[FLEXIBLE_ARRAY_MEMBER];
3031
} JsonPath;
3132

0 commit comments

Comments
 (0)