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

Commit 5a330db

Browse files
feodorNikita Glukhov
authored and
Nikita Glukhov
committed
implement **{} path opt in jsonpath
1 parent 3661998 commit 5a330db

File tree

9 files changed

+449
-12
lines changed

9 files changed

+449
-12
lines changed

src/backend/utils/adt/jsonpath.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,14 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item)
9595
(char*)item->array.elems,
9696
item->array.nelems * sizeof(item->array.elems[0]));
9797
break;
98+
case jpiAny:
99+
appendBinaryStringInfo(buf,
100+
(char*)&item->anybounds.first,
101+
sizeof(item->anybounds.first));
102+
appendBinaryStringInfo(buf,
103+
(char*)&item->anybounds.last,
104+
sizeof(item->anybounds.last));
105+
break;
98106
default:
99107
elog(ERROR, "Unknown jsonpath item type: %d", item->type);
100108
}
@@ -249,6 +257,23 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey, bool printBracket
249257
}
250258
appendStringInfoChar(buf, ']');
251259
break;
260+
case jpiAny:
261+
if (inKey)
262+
appendStringInfoChar(buf, '.');
263+
264+
if (v->anybounds.first == 0 &&
265+
v->anybounds.last == PG_UINT32_MAX)
266+
appendBinaryStringInfo(buf, "**", 2);
267+
else if (v->anybounds.first == 0)
268+
appendStringInfo(buf, "**{,%u}", v->anybounds.last);
269+
else if (v->anybounds.last == PG_UINT32_MAX)
270+
appendStringInfo(buf, "**{%u,}", v->anybounds.first);
271+
else if (v->anybounds.first == v->anybounds.last)
272+
appendStringInfo(buf, "**{%u}", v->anybounds.first);
273+
else
274+
appendStringInfo(buf, "**{%u,%u}", v->anybounds.first,
275+
v->anybounds.last);
276+
break;
252277
default:
253278
elog(ERROR, "Unknown jsonpath item type: %d", v->type);
254279
}
@@ -348,6 +373,10 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
348373
read_int32(v->array.nelems, base, pos);
349374
read_int32_n(v->array.elems, base, pos, v->array.nelems);
350375
break;
376+
case jpiAny:
377+
read_int32(v->anybounds.first, base, pos);
378+
read_int32(v->anybounds.last, base, pos);
379+
break;
351380
default:
352381
elog(ERROR, "Unknown jsonpath item type: %d", v->type);
353382
}
@@ -376,6 +405,7 @@ jspGetNext(JsonPathItem *v, JsonPathItem *a)
376405
{
377406
Assert(
378407
v->type == jpiKey ||
408+
v->type == jpiAny ||
379409
v->type == jpiAnyArray ||
380410
v->type == jpiAnyKey ||
381411
v->type == jpiIndexArray ||

src/backend/utils/adt/jsonpath_exec.c

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,67 @@ copyJsonbValue(JsonbValue *src)
292292
return dst;
293293
}
294294

295+
static JsonPathExecResult
296+
recursiveExecute(JsonPathItem *jsp, List *vars, JsonbValue *jb, List **found);
297+
298+
static JsonPathExecResult
299+
recursiveAny(JsonPathItem *jsp, List *vars, JsonbValue *jb,
300+
List **found, uint32 level, uint32 first, uint32 last)
301+
{
302+
JsonPathExecResult res = jperNotFound;
303+
JsonbIterator *it;
304+
int32 r;
305+
JsonbValue v;
306+
307+
check_stack_depth();
308+
309+
if (level > last)
310+
return res;
311+
312+
it = JsonbIteratorInit(jb->val.binary.data);
313+
314+
while((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
315+
{
316+
if (r == WJB_KEY)
317+
{
318+
r = JsonbIteratorNext(&it, &v, true);
319+
Assert(r == WJB_VALUE);
320+
}
321+
322+
if (r == WJB_VALUE || r == WJB_ELEM)
323+
{
324+
325+
if (level >= first)
326+
{
327+
/* check expression */
328+
if (jsp)
329+
{
330+
res = recursiveExecute(jsp, vars, &v, found);
331+
if (res == jperOk && !found)
332+
break;
333+
}
334+
else
335+
{
336+
res = jperOk;
337+
if (!found)
338+
break;
339+
*found = lappend(*found, copyJsonbValue(&v));
340+
}
341+
}
342+
343+
if (level < last && v.type == jbvBinary)
344+
{
345+
res = recursiveAny(jsp, vars, &v, found, level + 1, first, last);
346+
347+
if (res == jperOk && found == NULL)
348+
break;
349+
}
350+
}
351+
}
352+
353+
return res;
354+
}
355+
295356
static JsonPathExecResult
296357
recursiveExecute(JsonPathItem *jsp, List *vars, JsonbValue *jb, List **found)
297358
{
@@ -521,6 +582,35 @@ recursiveExecute(JsonPathItem *jsp, List *vars, JsonbValue *jb, List **found)
521582
if (res == jperOk && found)
522583
*found = lappend(*found, copyJsonbValue(jb));
523584
break;
585+
case jpiAny:
586+
{
587+
bool hasNext = jspGetNext(jsp, &elem);
588+
589+
/* first try without any intermediate steps */
590+
if (jsp->anybounds.first == 0)
591+
{
592+
if (hasNext)
593+
{
594+
res = recursiveExecute(&elem, vars, jb, found);
595+
if (res == jperOk && !found)
596+
break;
597+
}
598+
else
599+
{
600+
res = jperOk;
601+
if (!found)
602+
break;
603+
*found = lappend(*found, copyJsonbValue(jb));
604+
}
605+
}
606+
607+
if (jb->type == jbvBinary)
608+
res = recursiveAny(hasNext ? &elem : NULL, vars, jb, found,
609+
1,
610+
jsp->anybounds.first,
611+
jsp->anybounds.last);
612+
break;
613+
}
524614
default:
525615
elog(ERROR,"Wrong state: %d", jsp->type);
526616
}

src/backend/utils/adt/jsonpath_gram.y

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,17 @@ makeIndexArray(List *list)
173173
return v;
174174
}
175175

176+
static JsonPathParseItem*
177+
makeAny(int first, int last)
178+
{
179+
JsonPathParseItem *v = makeItemType(jpiAny);
180+
181+
v->anybounds.first = (first > 0) ? first : 0;
182+
v->anybounds.last = (last >= 0) ? last : PG_UINT32_MAX;
183+
184+
return v;
185+
}
186+
176187
%}
177188

178189
/* BISON Declarations */
@@ -289,9 +300,16 @@ array_accessors:
289300
;
290301

291302
any_key:
292-
key { $$ = $1; }
293-
| array_accessor { $$ = $1; }
294-
| '*' { $$ = makeItemType(jpiAnyKey); }
303+
key { $$ = $1; }
304+
| array_accessor { $$ = $1; }
305+
| '*' { $$ = makeItemType(jpiAnyKey); }
306+
| '*' '*' { $$ = makeAny(-1, -1); }
307+
| '*' '*' '{' INT_P '}' { $$ = makeAny(pg_atoi($4.val, 4, 0),
308+
pg_atoi($4.val, 4, 0)); }
309+
| '*' '*' '{' ',' INT_P '}' { $$ = makeAny(-1, pg_atoi($5.val, 4, 0)); }
310+
| '*' '*' '{' INT_P ',' '}' { $$ = makeAny(pg_atoi($4.val, 4, 0), -1); }
311+
| '*' '*' '{' INT_P ',' INT_P '}' { $$ = makeAny(pg_atoi($4.val, 4, 0),
312+
pg_atoi($6.val, 4, 0)); }
295313
;
296314

297315
joined_key:

src/backend/utils/adt/jsonpath_scan.l

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ fprintf_to_ereport(const char *fmt, const char *msg)
6464
%x xVARQUOTED
6565
%x xCOMMENT
6666

67-
special [\?\%\$\.\[\]\(\)\|\&\!\=\<\>\@\#\,\*:\-\+\/]
68-
any [^\?\%\$\.\[\]\(\)\|\&\!\=\<\>\@\#\,\*:\-\+\/\\\" \t\n\r\f]
67+
special [\?\%\$\.\[\]\{\}\(\)\|\&\!\=\<\>\@\#\,\*:\-\+\/]
68+
any [^\?\%\$\.\[\]\{\}\(\)\|\&\!\=\<\>\@\#\,\*:\-\+\/\\\" \t\n\r\f]
6969
blank [ \t\n\r\f]
7070
unicode \\u[0-9A-Fa-f]{4}
7171

src/include/utils/jsonpath.h

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ typedef enum JsonPathItemType {
4545
jpiAnyArray,
4646
jpiAnyKey,
4747
jpiIndexArray,
48-
//jpiAny,
48+
jpiAny,
4949
//jpiAll,
5050
//jpiAllArray,
5151
//jpiAllKey,
@@ -74,7 +74,7 @@ typedef struct JsonPathItem {
7474
union {
7575
struct {
7676
char *data; /* for bool, numeric and string/key */
77-
int datalen; /* filled only for string/key */
77+
int32 datalen; /* filled only for string/key */
7878
} value;
7979

8080
struct {
@@ -85,9 +85,14 @@ typedef struct JsonPathItem {
8585
int32 arg;
8686

8787
struct {
88-
int nelems;
88+
int32 nelems;
8989
int32 *elems;
9090
} array;
91+
92+
struct {
93+
uint32 first;
94+
uint32 last;
95+
} anybounds;
9196
};
9297
} JsonPathItem;
9398

@@ -122,14 +127,19 @@ struct JsonPathParseItem {
122127
Numeric numeric;
123128
bool boolean;
124129
struct {
125-
uint32 len;
126-
char *val; /* could not be not null-terminated */
130+
uint32 len;
131+
char *val; /* could not be not null-terminated */
127132
} string;
128133

129134
struct {
130-
int nelems;
131-
int32 *elems;
135+
int nelems;
136+
int32 *elems;
132137
} array;
138+
139+
struct {
140+
uint32 first;
141+
uint32 last;
142+
} anybounds;
133143
};
134144
};
135145

0 commit comments

Comments
 (0)