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

Commit 00d982a

Browse files
author
Nikita Glukhov
committed
WIP: Add jsonpath branch returning
1 parent 5d44780 commit 00d982a

File tree

6 files changed

+225
-19
lines changed

6 files changed

+225
-19
lines changed

src/backend/utils/adt/jsonpath.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,13 @@ static bool replaceVariableReference(JsonPathContext *cxt, JsonPathItem *var,
3131
/*****************************INPUT/OUTPUT************************************/
3232

3333
static inline int32
34-
appendJsonPathItemHeader(StringInfo buf, JsonPathItemType type)
34+
appendJsonPathItemHeader(StringInfo buf, JsonPathItemType type, char flags)
3535
{
3636
int32 nextPos = 0; /* fake value */
3737
int32 nextOffs;
3838

3939
appendStringInfoChar(buf, (char) type);
40+
appendStringInfoChar(buf, (char) flags);
4041
alignStringInfoInt(buf);
4142

4243
nextOffs = buf->len;
@@ -63,7 +64,7 @@ copyJsonPathItem(JsonPathContext *cxt, JsonPathItem *item, int level,
6364

6465
check_stack_depth();
6566

66-
nextOffs = appendJsonPathItemHeader(buf, item->type);
67+
nextOffs = appendJsonPathItemHeader(buf, item->type, item->flags);
6768

6869
switch (item->type)
6970
{
@@ -384,7 +385,7 @@ flattenJsonPathParseItem(JsonPathContext *cxt, JsonPathParseItem *item,
384385
pos = copyJsonPath(cxt, item->value.binary, nestingLevel, &last, &next);
385386
else
386387
{
387-
next = appendJsonPathItemHeader(buf, item->type);
388+
next = appendJsonPathItemHeader(buf, item->type, item->flags);
388389
last = pos;
389390
}
390391

@@ -1142,6 +1143,7 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
11421143
v->base = base + pos;
11431144

11441145
read_byte(v->type, base, pos);
1146+
read_byte(v->flags, base, pos);
11451147
pos = INTALIGN((uintptr_t)(base + pos)) - (uintptr_t) base;
11461148
read_int32(v->nextPos, base, pos);
11471149

@@ -1456,6 +1458,7 @@ jspInitParseItem(JsonPathParseItem *item, JsonPathItemType type,
14561458
item = palloc(sizeof(*item));
14571459

14581460
item->type = type;
1461+
item->flags = 0;
14591462
item->next = next;
14601463

14611464
return item;

src/backend/utils/adt/jsonpath_exec.c

Lines changed: 117 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,43 +1090,84 @@ executeUnaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
10901090
return jper;
10911091
}
10921092

1093+
static JsonValueList
1094+
prependKey(JsonbValue *key, const JsonValueList *items)
1095+
{
1096+
JsonValueList objs = { 0 };
1097+
JsonValueListIterator it = { 0 };
1098+
JsonbValue *val;
1099+
1100+
while ((val = JsonValueListNext(items, &it)))
1101+
{
1102+
JsonbValue *obj;
1103+
JsonbValue bin;
1104+
JsonbParseState *ps = NULL;
1105+
1106+
if (val->type == jbvObject || val->type == jbvArray)
1107+
val = JsonbWrapInBinary(val, &bin);
1108+
1109+
pushJsonbValue(&ps, WJB_BEGIN_OBJECT, NULL);
1110+
pushJsonbValue(&ps, WJB_KEY, key);
1111+
pushJsonbValue(&ps, WJB_VALUE, val);
1112+
obj = pushJsonbValue(&ps, WJB_END_OBJECT, NULL);
1113+
1114+
JsonValueListAppend(&objs, obj);
1115+
}
1116+
1117+
return objs;
1118+
}
1119+
10931120
/*
10941121
* implements jpiAny node (** operator)
10951122
*/
10961123
static JsonPathExecResult
10971124
recursiveAny(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
1098-
JsonValueList *found, uint32 level, uint32 first, uint32 last)
1125+
JsonValueList *found, bool outPath,
1126+
uint32 level, uint32 first, uint32 last)
10991127
{
11001128
JsonPathExecResult res = jperNotFound;
11011129
JsonbIterator *it;
11021130
int32 r;
11031131
JsonbValue v;
1132+
bool isObject;
1133+
JsonValueList items = { 0 };
1134+
JsonValueList *pitems = found;
11041135

11051136
check_stack_depth();
11061137

11071138
if (level > last)
11081139
return res;
11091140

1141+
if (pitems && outPath)
1142+
pitems = &items;
1143+
1144+
isObject = JsonContainerIsObject(jb->val.binary.data);
1145+
11101146
it = JsonbIteratorInit(jb->val.binary.data);
11111147

11121148
/*
11131149
* Recursivly iterate over jsonb objects/arrays
11141150
*/
11151151
while((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
11161152
{
1153+
JsonbValue key;
1154+
11171155
if (r == WJB_KEY)
11181156
{
1157+
key = v;
11191158
r = JsonbIteratorNext(&it, &v, true);
11201159
Assert(r == WJB_VALUE);
1160+
1161+
if (pitems == &items)
1162+
JsonValueListClear(pitems);
11211163
}
11221164

11231165
if (r == WJB_VALUE || r == WJB_ELEM)
11241166
{
1125-
11261167
if (level >= first)
11271168
{
11281169
/* check expression */
1129-
res = recursiveExecuteNext(cxt, NULL, jsp, &v, found, true);
1170+
res = recursiveExecuteNext(cxt, NULL, jsp, &v, pitems, true);
11301171

11311172
if (jperIsError(res))
11321173
break;
@@ -1137,17 +1178,24 @@ recursiveAny(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
11371178

11381179
if (level < last && v.type == jbvBinary)
11391180
{
1140-
res = recursiveAny(cxt, jsp, &v, found, level + 1, first, last);
1181+
res = recursiveAny(cxt, jsp, &v, pitems, outPath,
1182+
level + 1, first, last);
11411183

11421184
if (jperIsError(res))
11431185
break;
11441186

11451187
if (res == jperOk && found == NULL)
11461188
break;
11471189
}
1190+
1191+
if (isObject && !JsonValueListIsEmpty(&items) && !jperIsError(res))
1192+
JsonValueListConcat(found, prependKey(&key, &items));
11481193
}
11491194
}
11501195

1196+
if (!isObject && !JsonValueListIsEmpty(&items) && !jperIsError(res))
1197+
JsonValueListAppend(found, wrapItemsInArray(&items));
1198+
11511199
return res;
11521200
}
11531201

@@ -1469,7 +1517,8 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
14691517
case jpiKey:
14701518
if (JsonbType(jb) == jbvObject)
14711519
{
1472-
JsonbValue *v, key;
1520+
JsonbValue *v;
1521+
JsonbValue key;
14731522
JsonbValue obj;
14741523

14751524
if (jb->type == jbvObject)
@@ -1482,10 +1531,19 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
14821531

14831532
if (v != NULL)
14841533
{
1485-
res = recursiveExecuteNext(cxt, jsp, NULL, v, found, false);
1534+
JsonValueList items = { 0 };
1535+
JsonValueList *pitems = found;
1536+
1537+
if (pitems && jspOutPath(jsp))
1538+
pitems = &items;
1539+
1540+
res = recursiveExecuteNext(cxt, jsp, NULL, v, pitems, false);
14861541

14871542
if (jspHasNext(jsp) || !found)
14881543
pfree(v); /* free value if it was not added to found list */
1544+
1545+
if (!JsonValueListIsEmpty(&items) && !jperIsError(res))
1546+
JsonValueListConcat(found, prependKey(&key, &items));
14891547
}
14901548
else if (!cxt->lax)
14911549
{
@@ -1547,6 +1605,13 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
15471605
case jpiAnyArray:
15481606
if (JsonbType(jb) == jbvArray)
15491607
{
1608+
JsonValueList items = { 0 };
1609+
JsonValueList *pitems = found;
1610+
bool wrap = pitems && jspOutPath(jsp);
1611+
1612+
if (wrap)
1613+
pitems = &items;
1614+
15501615
hasNext = jspGetNext(jsp, &elem);
15511616

15521617
if (jb->type == jbvArray)
@@ -1556,7 +1621,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
15561621

15571622
for (; el < last_el; el++)
15581623
{
1559-
res = recursiveExecuteNext(cxt, jsp, &elem, el, found, true);
1624+
res = recursiveExecuteNext(cxt, jsp, &elem, el, pitems, true);
15601625

15611626
if (jperIsError(res))
15621627
break;
@@ -1577,7 +1642,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
15771642
{
15781643
if (r == WJB_ELEM)
15791644
{
1580-
res = recursiveExecuteNext(cxt, jsp, &elem, &v, found, true);
1645+
res = recursiveExecuteNext(cxt, jsp, &elem, &v, pitems, true);
15811646

15821647
if (jperIsError(res))
15831648
break;
@@ -1587,6 +1652,9 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
15871652
}
15881653
}
15891654
}
1655+
1656+
if (wrap && !jperIsError(res))
1657+
JsonValueListAppend(found, wrapItemsInArray(&items));
15901658
}
15911659
else
15921660
res = jperMakeError(ERRCODE_JSON_ARRAY_NOT_FOUND);
@@ -1599,6 +1667,12 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
15991667
int i;
16001668
int size = JsonbArraySize(jb);
16011669
bool binary = jb->type == jbvBinary;
1670+
JsonValueList items = { 0 };
1671+
JsonValueList *pitems = found;
1672+
bool wrap = pitems && jspOutPath(jsp);
1673+
1674+
if (wrap)
1675+
pitems = &items;
16021676

16031677
cxt->innermostArraySize = size; /* for LAST evaluation */
16041678

@@ -1655,7 +1729,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
16551729
if (v == NULL)
16561730
continue;
16571731

1658-
res = recursiveExecuteNext(cxt, jsp, &elem, v, found,
1732+
res = recursiveExecuteNext(cxt, jsp, &elem, v, pitems,
16591733
!binary);
16601734

16611735
if (jperIsError(res))
@@ -1673,13 +1747,22 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
16731747
}
16741748

16751749
cxt->innermostArraySize = innermostArraySize;
1750+
1751+
if (wrap && !jperIsError(res))
1752+
JsonValueListAppend(found, wrapItemsInArray(&items));
16761753
}
16771754
else if (JsonbType(jb) == jbvObject)
16781755
{
16791756
int innermostArraySize = cxt->innermostArraySize;
16801757
int i;
16811758
JsonbValue bin;
16821759
JsonbValue *wrapped = NULL;
1760+
JsonValueList items = { 0 };
1761+
JsonValueList *pitems = found;
1762+
bool wrap = pitems && jspOutPath(jsp);
1763+
1764+
if (wrap)
1765+
pitems = &items;
16831766

16841767
if (jb->type != jbvBinary)
16851768
jb = JsonbWrapInBinary(jb, &bin);
@@ -1719,7 +1802,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
17191802
if (index_from <= 0 && index_to >= 0)
17201803
{
17211804
res = recursiveExecuteNext(cxt, jsp, NULL, jb,
1722-
found, true);
1805+
pitems, true);
17231806
if (jperIsError(res))
17241807
return res;
17251808

@@ -1757,7 +1840,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
17571840
if (!index)
17581841
{
17591842
res = recursiveExecuteNext(cxt, jsp, NULL, jb,
1760-
found, true);
1843+
pitems, true);
17611844
if (jperIsError(res))
17621845
return res;
17631846
}
@@ -1770,7 +1853,7 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
17701853
if (key)
17711854
{
17721855
res = recursiveExecuteNext(cxt, jsp, NULL, key,
1773-
found, false);
1856+
pitems, false);
17741857
if (jperIsError(res))
17751858
return res;
17761859
}
@@ -1785,6 +1868,9 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
17851868
}
17861869

17871870
cxt->innermostArraySize = innermostArraySize;
1871+
1872+
if (wrap && !jperIsError(res))
1873+
JsonValueListAppend(found, wrapItemsInArray(&items));
17881874
}
17891875
else
17901876
{
@@ -1842,15 +1928,31 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
18421928

18431929
while((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
18441930
{
1931+
JsonbValue key;
1932+
JsonValueList items = { 0 };
1933+
JsonValueList *pitems = found;
1934+
1935+
if (r == WJB_KEY && jspOutPath(jsp))
1936+
{
1937+
key = v;
1938+
r = JsonbIteratorNext(&it, &v, true);
1939+
1940+
if (pitems)
1941+
pitems = &items;
1942+
}
1943+
18451944
if (r == WJB_VALUE)
18461945
{
1847-
res = recursiveExecuteNext(cxt, jsp, &elem, &v, found, true);
1946+
res = recursiveExecuteNext(cxt, jsp, &elem, &v, pitems, true);
18481947

18491948
if (jperIsError(res))
18501949
break;
18511950

18521951
if (res == jperOk && !found)
18531952
break;
1953+
1954+
if (!JsonValueListIsEmpty(&items) && !jperIsError(res))
1955+
JsonValueListConcat(found, prependKey(&key, &items));
18541956
}
18551957
}
18561958
}
@@ -1900,15 +2002,15 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
19002002
res = recursiveExecuteNext(cxt, jsp, &elem, jb, found, true);
19012003

19022004
if (res == jperOk && !found)
1903-
break;
2005+
break;
19042006
}
19052007

19062008
if (jb->type == jbvArray || jb->type == jbvObject)
19072009
jb = JsonbWrapInBinary(jb, &jbvbuf);
19082010

19092011
if (jb->type == jbvBinary)
19102012
res = recursiveAny(cxt, hasNext ? &elem : NULL, jb, found,
1911-
1,
2013+
jspOutPath(jsp), 1,
19122014
jsp->content.anybounds.first,
19132015
jsp->content.anybounds.last);
19142016
break;

0 commit comments

Comments
 (0)