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

Commit 6662a63

Browse files
author
Nikita Glukhov
committed
Jsonpath syntax extensions
1 parent 75a9fca commit 6662a63

File tree

10 files changed

+1242
-91
lines changed

10 files changed

+1242
-91
lines changed

src/backend/utils/adt/jsonpath.c

Lines changed: 146 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,12 +136,15 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
136136
case jpiPlus:
137137
case jpiMinus:
138138
case jpiExists:
139+
case jpiArray:
139140
{
140-
int32 arg;
141+
int32 arg = item->value.arg ? buf->len : 0;
141142

142-
arg = buf->len;
143143
appendBinaryStringInfo(buf, (char*)&arg /* fake value */, sizeof(arg));
144144

145+
if (!item->value.arg)
146+
break;
147+
145148
chld = flattenJsonPathParseItem(buf, item->value.arg,
146149
nestingLevel + argNestingLevel,
147150
insideArraySubscript);
@@ -218,6 +221,61 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
218221
case jpiDouble:
219222
case jpiKeyValue:
220223
break;
224+
case jpiSequence:
225+
{
226+
int32 nelems = list_length(item->value.sequence.elems);
227+
ListCell *lc;
228+
int offset;
229+
230+
appendBinaryStringInfo(buf, (char *) &nelems, sizeof(nelems));
231+
232+
offset = buf->len;
233+
234+
appendStringInfoSpaces(buf, sizeof(int32) * nelems);
235+
236+
foreach(lc, item->value.sequence.elems)
237+
{
238+
int32 elempos =
239+
flattenJsonPathParseItem(buf, lfirst(lc), nestingLevel,
240+
insideArraySubscript);
241+
242+
*(int32 *) &buf->data[offset] = elempos - pos;
243+
offset += sizeof(int32);
244+
}
245+
}
246+
break;
247+
case jpiObject:
248+
{
249+
int32 nfields = list_length(item->value.object.fields);
250+
ListCell *lc;
251+
int offset;
252+
253+
appendBinaryStringInfo(buf, (char *) &nfields, sizeof(nfields));
254+
255+
offset = buf->len;
256+
257+
appendStringInfoSpaces(buf, sizeof(int32) * 2 * nfields);
258+
259+
foreach(lc, item->value.object.fields)
260+
{
261+
JsonPathParseItem *field = lfirst(lc);
262+
int32 keypos =
263+
flattenJsonPathParseItem(buf, field->value.args.left,
264+
nestingLevel,
265+
insideArraySubscript);
266+
int32 valpos =
267+
flattenJsonPathParseItem(buf, field->value.args.right,
268+
nestingLevel,
269+
insideArraySubscript);
270+
int32 *ppos = (int32 *) &buf->data[offset];
271+
272+
ppos[0] = keypos - pos;
273+
ppos[1] = valpos - pos;
274+
275+
offset += 2 * sizeof(int32);
276+
}
277+
}
278+
break;
221279
default:
222280
elog(ERROR, "Unknown jsonpath item type: %d", item->type);
223281
}
@@ -305,6 +363,8 @@ operationPriority(JsonPathItemType op)
305363
{
306364
switch (op)
307365
{
366+
case jpiSequence:
367+
return -1;
308368
case jpiOr:
309369
return 0;
310370
case jpiAnd:
@@ -494,12 +554,12 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey, bool printBracket
494554
if (i)
495555
appendStringInfoChar(buf, ',');
496556

497-
printJsonPathItem(buf, &from, false, false);
557+
printJsonPathItem(buf, &from, false, from.type == jpiSequence);
498558

499559
if (range)
500560
{
501561
appendBinaryStringInfo(buf, " to ", 4);
502-
printJsonPathItem(buf, &to, false, false);
562+
printJsonPathItem(buf, &to, false, to.type == jpiSequence);
503563
}
504564
}
505565
appendStringInfoChar(buf, ']');
@@ -563,6 +623,54 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey, bool printBracket
563623
case jpiKeyValue:
564624
appendBinaryStringInfo(buf, ".keyvalue()", 11);
565625
break;
626+
case jpiSequence:
627+
if (printBracketes || jspHasNext(v))
628+
appendStringInfoChar(buf, '(');
629+
630+
for (i = 0; i < v->content.sequence.nelems; i++)
631+
{
632+
JsonPathItem elem;
633+
634+
if (i)
635+
appendBinaryStringInfo(buf, ", ", 2);
636+
637+
jspGetSequenceElement(v, i, &elem);
638+
639+
printJsonPathItem(buf, &elem, false, elem.type == jpiSequence);
640+
}
641+
642+
if (printBracketes || jspHasNext(v))
643+
appendStringInfoChar(buf, ')');
644+
break;
645+
case jpiArray:
646+
appendStringInfoChar(buf, '[');
647+
if (v->content.arg)
648+
{
649+
jspGetArg(v, &elem);
650+
printJsonPathItem(buf, &elem, false, false);
651+
}
652+
appendStringInfoChar(buf, ']');
653+
break;
654+
case jpiObject:
655+
appendStringInfoChar(buf, '{');
656+
657+
for (i = 0; i < v->content.object.nfields; i++)
658+
{
659+
JsonPathItem key;
660+
JsonPathItem val;
661+
662+
jspGetObjectField(v, i, &key, &val);
663+
664+
if (i)
665+
appendBinaryStringInfo(buf, ", ", 2);
666+
667+
printJsonPathItem(buf, &key, false, false);
668+
appendBinaryStringInfo(buf, ": ", 2);
669+
printJsonPathItem(buf, &val, false, val.type == jpiSequence);
670+
}
671+
672+
appendStringInfoChar(buf, '}');
673+
break;
566674
default:
567675
elog(ERROR, "Unknown jsonpath item type: %d", v->type);
568676
}
@@ -585,7 +693,7 @@ jsonpath_out(PG_FUNCTION_ARGS)
585693
appendBinaryStringInfo(&buf, "strict ", 7);
586694

587695
jspInit(&v, in);
588-
printJsonPathItem(&buf, &v, false, true);
696+
printJsonPathItem(&buf, &v, false, v.type != jpiSequence);
589697

590698
PG_RETURN_CSTRING(buf.data);
591699
}
@@ -688,6 +796,7 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
688796
case jpiPlus:
689797
case jpiMinus:
690798
case jpiFilter:
799+
case jpiArray:
691800
read_int32(v->content.arg, base, pos);
692801
break;
693802
case jpiIndexArray:
@@ -699,6 +808,16 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
699808
read_int32(v->content.anybounds.first, base, pos);
700809
read_int32(v->content.anybounds.last, base, pos);
701810
break;
811+
case jpiSequence:
812+
read_int32(v->content.sequence.nelems, base, pos);
813+
read_int32_n(v->content.sequence.elems, base, pos,
814+
v->content.sequence.nelems);
815+
break;
816+
case jpiObject:
817+
read_int32(v->content.object.nfields, base, pos);
818+
read_int32_n(v->content.object.fields, base, pos,
819+
v->content.object.nfields * 2);
820+
break;
702821
default:
703822
elog(ERROR, "Unknown jsonpath item type: %d", v->type);
704823
}
@@ -713,7 +832,8 @@ jspGetArg(JsonPathItem *v, JsonPathItem *a)
713832
v->type == jpiIsUnknown ||
714833
v->type == jpiExists ||
715834
v->type == jpiPlus ||
716-
v->type == jpiMinus
835+
v->type == jpiMinus ||
836+
v->type == jpiArray
717837
);
718838

719839
jspInitByBuffer(a, v->base, v->content.arg);
@@ -765,7 +885,10 @@ jspGetNext(JsonPathItem *v, JsonPathItem *a)
765885
v->type == jpiDouble ||
766886
v->type == jpiDatetime ||
767887
v->type == jpiKeyValue ||
768-
v->type == jpiStartsWith
888+
v->type == jpiStartsWith ||
889+
v->type == jpiSequence ||
890+
v->type == jpiArray ||
891+
v->type == jpiObject
769892
);
770893

771894
if (a)
@@ -869,3 +992,19 @@ jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from, JsonPathItem *to,
869992

870993
return true;
871994
}
995+
996+
void
997+
jspGetSequenceElement(JsonPathItem *v, int i, JsonPathItem *elem)
998+
{
999+
Assert(v->type == jpiSequence);
1000+
1001+
jspInitByBuffer(elem, v->base, v->content.sequence.elems[i]);
1002+
}
1003+
1004+
void
1005+
jspGetObjectField(JsonPathItem *v, int i, JsonPathItem *key, JsonPathItem *val)
1006+
{
1007+
Assert(v->type == jpiObject);
1008+
jspInitByBuffer(key, v->base, v->content.object.fields[i].key);
1009+
jspInitByBuffer(val, v->base, v->content.object.fields[i].val);
1010+
}

0 commit comments

Comments
 (0)