Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitbbb1f1e

Browse files
author
Nikita Glukhov
committed
Add jsonpath sequence constructors
1 parent0abe1a1 commitbbb1f1e

File tree

9 files changed

+264
-7
lines changed

9 files changed

+264
-7
lines changed

‎doc/src/sgml/func.sgml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13687,6 +13687,13 @@ table2-mapping
1368713687
</row>
1368813688
</thead>
1368913689
<tbody>
13690+
<row>
13691+
<entry>Sequence constructor</entry>
13692+
<entry>Construct a JSON sequence from a list of comma-separated expressions</entry>
13693+
<entry><literal>[1, 2, 3]</literal></entry>
13694+
<entry><literal>pg $[*], 4, 5</literal></entry>
13695+
<entry><literal>1, 2, 3, 4, 5</literal></entry>
13696+
</row>
1369013697
</tbody>
1369113698
</tgroup>
1369213699
</table>

‎src/backend/utils/adt/jsonpath.c

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ jsonPathToCstring(StringInfo out, JsonPath *in, int estimated_len)
233233
appendBinaryStringInfo(out,"strict ",7);
234234

235235
jspInit(&v,in);
236-
printJsonPathItem(out,&v, false,true);
236+
printJsonPathItem(out,&v, false,v.type!=jpiSequence);
237237

238238
returnout->data;
239239
}
@@ -448,6 +448,31 @@ flattenJsonPathParseItem(JsonPathEncodingContext *cxt, JsonPathParseItem *item,
448448
casejpiDouble:
449449
casejpiKeyValue:
450450
break;
451+
casejpiSequence:
452+
{
453+
int32nelems=list_length(item->value.sequence.elems);
454+
ListCell*lc;
455+
intoffset;
456+
457+
checkJsonPathExtensionsEnabled(cxt,item->type);
458+
459+
appendBinaryStringInfo(buf, (char*)&nelems,sizeof(nelems));
460+
461+
offset=buf->len;
462+
463+
appendStringInfoSpaces(buf,sizeof(int32)*nelems);
464+
465+
foreach(lc,item->value.sequence.elems)
466+
{
467+
int32elempos=
468+
flattenJsonPathParseItem(cxt,lfirst(lc),nestingLevel,
469+
insideArraySubscript);
470+
471+
*(int32*)&buf->data[offset]=elempos-pos;
472+
offset+=sizeof(int32);
473+
}
474+
}
475+
break;
451476
default:
452477
elog(ERROR,"unrecognized jsonpath item type: %d",item->type);
453478
}
@@ -670,12 +695,12 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
670695
if (i)
671696
appendStringInfoChar(buf,',');
672697

673-
printJsonPathItem(buf,&from, false,false);
698+
printJsonPathItem(buf,&from, false,from.type==jpiSequence);
674699

675700
if (range)
676701
{
677702
appendBinaryStringInfo(buf," to ",4);
678-
printJsonPathItem(buf,&to, false,false);
703+
printJsonPathItem(buf,&to, false,to.type==jpiSequence);
679704
}
680705
}
681706
appendStringInfoChar(buf,']');
@@ -736,6 +761,25 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
736761
casejpiKeyValue:
737762
appendBinaryStringInfo(buf,".keyvalue()",11);
738763
break;
764+
casejpiSequence:
765+
if (printBracketes||jspHasNext(v))
766+
appendStringInfoChar(buf,'(');
767+
768+
for (i=0;i<v->content.sequence.nelems;i++)
769+
{
770+
JsonPathItemelem;
771+
772+
if (i)
773+
appendBinaryStringInfo(buf,", ",2);
774+
775+
jspGetSequenceElement(v,i,&elem);
776+
777+
printJsonPathItem(buf,&elem, false,elem.type==jpiSequence);
778+
}
779+
780+
if (printBracketes||jspHasNext(v))
781+
appendStringInfoChar(buf,')');
782+
break;
739783
default:
740784
elog(ERROR,"unrecognized jsonpath item type: %d",v->type);
741785
}
@@ -808,6 +852,8 @@ operationPriority(JsonPathItemType op)
808852
{
809853
switch (op)
810854
{
855+
casejpiSequence:
856+
return-1;
811857
casejpiOr:
812858
return0;
813859
casejpiAnd:
@@ -944,6 +990,11 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
944990
read_int32(v->content.anybounds.first,base,pos);
945991
read_int32(v->content.anybounds.last,base,pos);
946992
break;
993+
casejpiSequence:
994+
read_int32(v->content.sequence.nelems,base,pos);
995+
read_int32_n(v->content.sequence.elems,base,pos,
996+
v->content.sequence.nelems);
997+
break;
947998
default:
948999
elog(ERROR,"unrecognized jsonpath item type: %d",v->type);
9491000
}
@@ -1008,7 +1059,8 @@ jspGetNext(JsonPathItem *v, JsonPathItem *a)
10081059
v->type==jpiDouble||
10091060
v->type==jpiDatetime||
10101061
v->type==jpiKeyValue||
1011-
v->type==jpiStartsWith);
1062+
v->type==jpiStartsWith||
1063+
v->type==jpiSequence);
10121064

10131065
if (a)
10141066
jspInitByBuffer(a,v->base,v->nextPos);
@@ -1103,3 +1155,11 @@ jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from, JsonPathItem *to,
11031155

11041156
return true;
11051157
}
1158+
1159+
void
1160+
jspGetSequenceElement(JsonPathItem*v,inti,JsonPathItem*elem)
1161+
{
1162+
Assert(v->type==jpiSequence);
1163+
1164+
jspInitByBuffer(elem,v->base,v->content.sequence.elems[i]);
1165+
}

‎src/backend/utils/adt/jsonpath_exec.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,52 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
11291129

11301130
returnexecuteKeyValueMethod(cxt,jsp,jb,found);
11311131

1132+
casejpiSequence:
1133+
{
1134+
JsonPathItemnext;
1135+
boolhasNext=jspGetNext(jsp,&next);
1136+
JsonValueListlist;
1137+
JsonValueList*plist=hasNext ?&list :found;
1138+
JsonValueListIteratorit;
1139+
inti;
1140+
1141+
for (i=0;i<jsp->content.sequence.nelems;i++)
1142+
{
1143+
JsonbValue*v;
1144+
1145+
if (hasNext)
1146+
memset(&list,0,sizeof(list));
1147+
1148+
jspGetSequenceElement(jsp,i,&elem);
1149+
res=executeItem(cxt,&elem,jb,plist);
1150+
1151+
if (jperIsError(res))
1152+
break;
1153+
1154+
if (!hasNext)
1155+
{
1156+
if (!found&&res==jperOk)
1157+
break;
1158+
continue;
1159+
}
1160+
1161+
JsonValueListInitIterator(&list,&it);
1162+
1163+
while ((v=JsonValueListNext(&list,&it)))
1164+
{
1165+
res=executeItem(cxt,&next,v,found);
1166+
1167+
if (jperIsError(res)|| (!found&&res==jperOk))
1168+
{
1169+
i=jsp->content.sequence.nelems;
1170+
break;
1171+
}
1172+
}
1173+
}
1174+
1175+
break;
1176+
}
1177+
11321178
default:
11331179
elog(ERROR,"unrecognized jsonpath item type: %d",jsp->type);
11341180
}

‎src/backend/utils/adt/jsonpath_gram.y

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ static JsonPathParseItem *makeAny(int first, int last);
5656
static JsonPathParseItem *makeItemLikeRegex(JsonPathParseItem *expr,
5757
JsonPathString *pattern,
5858
JsonPathString *flags);
59+
static JsonPathParseItem *makeItemSequence(List *elems);
5960

6061
/*
6162
* Bison doesn't allocate anything that needs to live across parser calls,
@@ -101,9 +102,9 @@ static JsonPathParseItem *makeItemLikeRegex(JsonPathParseItem *expr,
101102
%type<value>scalar_valuepath_primaryexprarray_accessor
102103
any_pathaccessor_opkeypredicatedelimited_predicate
103104
index_elemstarts_with_initialexpr_or_predicate
104-
datetime_templateopt_datetime_template
105+
datetime_templateopt_datetime_templateexpr_seqexpr_or_seq
105106

106-
%type<elems>accessor_expr
107+
%type<elems>accessor_exprexpr_list
107108

108109
%type<indexs>index_list
109110

@@ -127,7 +128,7 @@ static JsonPathParseItem *makeItemLikeRegex(JsonPathParseItem *expr,
127128
%%
128129

129130
result:
130-
pg_optmodeexpr_or_predicate{
131+
pg_optmodeexpr_or_seq{
131132
*result = palloc(sizeof(JsonPathParseResult));
132133
(*result)->expr =$3;
133134
(*result)->lax =$2;
@@ -146,6 +147,20 @@ pg_opt:
146147
|/* EMPTY*/{$$ =false; }
147148
;
148149

150+
expr_or_seq:
151+
expr_or_predicate{$$ =$1; }
152+
|expr_seq{$$ =$1; }
153+
;
154+
155+
expr_seq:
156+
expr_list{$$ = makeItemSequence($1); }
157+
;
158+
159+
expr_list:
160+
expr_or_predicate','expr_or_predicate{$$ = list_make2($1,$3); }
161+
|expr_list','expr_or_predicate{$$ = lappend($1,$3); }
162+
;
163+
149164
mode:
150165
STRICT_P{$$ =false; }
151166
|LAX_P{$$ =true; }
@@ -201,6 +216,7 @@ path_primary:
201216
|'$'{$$ = makeItemType(jpiRoot); }
202217
|'@'{$$ = makeItemType(jpiCurrent); }
203218
|LAST_P{$$ = makeItemType(jpiLast); }
219+
|'('expr_seq')'{$$ =$2; }
204220
;
205221

206222
accessor_expr:
@@ -550,6 +566,16 @@ makeItemLikeRegex(JsonPathParseItem *expr, JsonPathString *pattern,
550566
return v;
551567
}
552568

569+
static JsonPathParseItem *
570+
makeItemSequence(List *elems)
571+
{
572+
JsonPathParseItem *v =makeItemType(jpiSequence);
573+
574+
v->value.sequence.elems = elems;
575+
576+
return v;
577+
}
578+
553579
/*
554580
* Convert from XQuery regex flags to those recognized by our regex library.
555581
*/

‎src/include/utils/jsonpath.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ typedef enum JsonPathItemType
8787
jpiLast,/* LAST array subscript */
8888
jpiStartsWith,/* STARTS WITH predicate */
8989
jpiLikeRegex,/* LIKE_REGEX predicate */
90+
jpiSequence,/* sequence constructor: 'expr, ...' */
9091
}JsonPathItemType;
9192

9293
/* XQuery regex mode flags for LIKE_REGEX predicate */
@@ -147,6 +148,12 @@ typedef struct JsonPathItem
147148
uint32last;
148149
}anybounds;
149150

151+
struct
152+
{
153+
int32nelems;
154+
int32*elems;
155+
}sequence;
156+
150157
struct
151158
{
152159
char*data;/* for bool, numeric and string/key */
@@ -176,6 +183,7 @@ extern bool jspGetBool(JsonPathItem *v);
176183
externchar*jspGetString(JsonPathItem*v,int32*len);
177184
externbooljspGetArraySubscript(JsonPathItem*v,JsonPathItem*from,
178185
JsonPathItem*to,inti);
186+
externvoidjspGetSequenceElement(JsonPathItem*v,inti,JsonPathItem*elem);
179187

180188
externconstchar*jspOperationName(JsonPathItemTypetype);
181189

@@ -229,6 +237,10 @@ struct JsonPathParseItem
229237
uint32flags;
230238
}like_regex;
231239

240+
struct {
241+
List*elems;
242+
}sequence;
243+
232244
/* scalars */
233245
Numericnumeric;
234246
boolboolean;

‎src/test/regress/expected/jsonb_jsonpath.out

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2524,3 +2524,57 @@ ORDER BY s1.num, s2.num;
25242524
{"s": "B"} | {"s": "B"} | false | true | true | true | false
25252525
(144 rows)
25262526

2527+
-- extension: path sequences
2528+
select jsonb_path_query('[1,2,3,4,5]', 'pg 10, 20, $[*], 30');
2529+
jsonb_path_query
2530+
------------------
2531+
10
2532+
20
2533+
1
2534+
2
2535+
3
2536+
4
2537+
5
2538+
30
2539+
(8 rows)
2540+
2541+
select jsonb_path_query('[1,2,3,4,5]', 'pg lax 10, 20, $[*].a, 30');
2542+
jsonb_path_query
2543+
------------------
2544+
10
2545+
20
2546+
30
2547+
(3 rows)
2548+
2549+
select jsonb_path_query('[1,2,3,4,5]', 'pg strict 10, 20, $[*].a, 30');
2550+
ERROR: jsonpath member accessor can only be applied to an object
2551+
select jsonb_path_query('[1,2,3,4,5]', 'pg -(10, 20, $[1 to 3], 30)');
2552+
jsonb_path_query
2553+
------------------
2554+
-10
2555+
-20
2556+
-2
2557+
-3
2558+
-4
2559+
-30
2560+
(6 rows)
2561+
2562+
select jsonb_path_query('[1,2,3,4,5]', 'pg lax (10, 20.5, $[1 to 3], "30").double()');
2563+
jsonb_path_query
2564+
------------------
2565+
10
2566+
20.5
2567+
2
2568+
3
2569+
4
2570+
30
2571+
(6 rows)
2572+
2573+
select jsonb_path_query('[1,2,3,4,5]', 'pg $[(0, $[*], 5) ? (@ == 3)]');
2574+
jsonb_path_query
2575+
------------------
2576+
4
2577+
(1 row)
2578+
2579+
select jsonb_path_query('[1,2,3,4,5]', 'pg $[(0, $[*], 3) ? (@ == 3)]');
2580+
ERROR: jsonpath array subscript is not a single numeric value

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp