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

Commit c11d2d8

Browse files
feodorNikita Glukhov
authored and
Nikita Glukhov
committed
add array indexes to jsonpath
1 parent 9497bee commit c11d2d8

File tree

8 files changed

+193
-34
lines changed

8 files changed

+193
-34
lines changed

src/backend/utils/adt/jsonpath.c

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,14 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item)
8686
case jpiRoot:
8787
case jpiNull:
8888
break;
89+
case jpiIndexArray:
90+
appendBinaryStringInfo(buf,
91+
(char*)&item->array.nelems,
92+
sizeof(item->array.nelems));
93+
appendBinaryStringInfo(buf,
94+
(char*)item->array.elems,
95+
item->array.nelems * sizeof(item->array.elems[0]));
96+
break;
8997
default:
9098
elog(ERROR, "Unknown jsonpath item type: %d", item->type);
9199
}
@@ -151,6 +159,7 @@ static void
151159
printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey, bool printBracketes)
152160
{
153161
JsonPathItem elem;
162+
int i;
154163

155164
check_stack_depth();
156165

@@ -229,6 +238,16 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey, bool printBracket
229238
appendStringInfoChar(buf, '.');
230239
appendStringInfoChar(buf, '*');
231240
break;
241+
case jpiIndexArray:
242+
appendStringInfoChar(buf, '[');
243+
for(i = 0; i< v->array.nelems; i++)
244+
{
245+
if (i)
246+
appendStringInfoChar(buf, ',');
247+
appendStringInfo(buf, "%d", v->array.elems[i]);
248+
}
249+
appendStringInfoChar(buf, ']');
250+
break;
232251
default:
233252
elog(ERROR, "Unknown jsonpath item type: %d", v->type);
234253
}
@@ -256,15 +275,20 @@ jsonpath_out(PG_FUNCTION_ARGS)
256275
/*
257276
* Support functions for JsonPath
258277
*/
259-
#define read_byte(v, b, p) do { \
260-
(v) = *(uint8*)((b) + (p)); \
261-
(p) += 1; \
262-
} while(0) \
278+
#define read_byte(v, b, p) do { \
279+
(v) = *(uint8*)((b) + (p)); \
280+
(p) += 1; \
281+
} while(0) \
282+
283+
#define read_int32(v, b, p) do { \
284+
(v) = *(uint32*)((b) + (p)); \
285+
(p) += sizeof(int32); \
286+
} while(0) \
263287

264-
#define read_int32(v, b, p) do { \
265-
(v) = *(uint32*)((b) + (p)); \
266-
(p) += sizeof(int32); \
267-
} while(0) \
288+
#define read_int32_n(v, b, p, n) do { \
289+
(v) = (int32*)((b) + (p)); \
290+
(p) += sizeof(int32) * (n); \
291+
} while(0) \
268292

269293
void
270294
jspInit(JsonPathItem *v, JsonPath *js)
@@ -320,6 +344,10 @@ jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
320344
case jpiExpression:
321345
read_int32(v->arg, base, pos);
322346
break;
347+
case jpiIndexArray:
348+
read_int32(v->array.nelems, base, pos);
349+
read_int32_n(v->array.elems, base, pos, v->array.nelems);
350+
break;
323351
default:
324352
elog(ERROR, "Unknown jsonpath item type: %d", v->type);
325353
}
@@ -350,6 +378,7 @@ jspGetNext(JsonPathItem *v, JsonPathItem *a)
350378
v->type == jpiKey ||
351379
v->type == jpiAnyArray ||
352380
v->type == jpiAnyKey ||
381+
v->type == jpiIndexArray ||
353382
v->type == jpiCurrent ||
354383
v->type == jpiRoot
355384
);

src/backend/utils/adt/jsonpath_exec.c

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,10 @@ recursiveExecute(JsonPathItem *jsp, JsonbValue *jb, List **found)
246246
{
247247
res = recursiveExecute(&elem, &v, found);
248248

249-
if (res == jperError || found == NULL)
249+
if (res == jperError)
250+
break;
251+
252+
if (res == jperOk && found == NULL)
250253
break;
251254
}
252255
else
@@ -264,21 +267,47 @@ recursiveExecute(JsonPathItem *jsp, JsonbValue *jb, List **found)
264267
}
265268
}
266269
break;
267-
/*
270+
268271
case jpiIndexArray:
269272
if (JsonbType(jb) == jbvArray)
270273
{
271274
JsonbValue *v;
275+
bool hasNext;
276+
int i;
277+
278+
hasNext = jspGetNext(jsp, &elem);
279+
280+
for(i=0; i<jsp->array.nelems; i++)
281+
{
282+
/* TODO for future: array index can be expression */
283+
v = getIthJsonbValueFromContainer(jb->val.binary.data,
284+
jsp->array.elems[i]);
285+
286+
if (v == NULL)
287+
continue;
288+
289+
if (hasNext == true)
290+
{
291+
res = recursiveExecute(&elem, v, found);
272292

273-
jspGetNext(jsp, &elem);
293+
if (res == jperError || found == NULL)
294+
break;
274295

275-
v = getIthJsonbValueFromContainer(jb->val.binary.data,
276-
jsp->arrayIndex);
296+
if (res == jperOk && found == NULL)
297+
break;
298+
}
299+
else
300+
{
301+
res = jperOk;
277302

278-
res = v && recursiveExecute(&elem, v, found);
303+
if (found == NULL)
304+
break;
305+
306+
*found = lappend(*found, v);
307+
}
308+
}
279309
}
280310
break;
281-
*/
282311
case jpiAnyKey:
283312
if (JsonbType(jb) == jbvObject)
284313
{
@@ -298,7 +327,10 @@ recursiveExecute(JsonPathItem *jsp, JsonbValue *jb, List **found)
298327
{
299328
res = recursiveExecute(&elem, &v, found);
300329

301-
if (res == jperError || found == NULL)
330+
if (res == jperError)
331+
break;
332+
333+
if (res == jperOk && found == NULL)
302334
break;
303335
}
304336
else

src/backend/utils/adt/jsonpath_gram.y

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
/*-------------------------------------------------------------------------
22
*
33
* jsonpath_gram.y
4-
* Grammar definitions for jsonpath datatype
4+
* Grammar definitions for jsonpath datatype
55
*
66
* Copyright (c) 2017, PostgreSQL Global Development Group
77
*
88
* IDENTIFICATION
9-
* src/backend/utils/adt/jsonpath_gram.y
9+
* src/backend/utils/adt/jsonpath_gram.y
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -155,6 +155,24 @@ makeItemExpression(List *path, JsonPathParseItem *right_expr)
155155
return makeItemList(lappend(path, expr));
156156
}
157157

158+
static JsonPathParseItem*
159+
makeIndexArray(List *list)
160+
{
161+
JsonPathParseItem *v = makeItemType(jpiIndexArray);
162+
ListCell *cell;
163+
int i = 0;
164+
165+
Assert(list_length(list) > 0);
166+
v->array.nelems = list_length(list);
167+
168+
v->array.elems = palloc(sizeof(v->array.elems[0]) * v->array.nelems);
169+
170+
foreach(cell, list)
171+
v->array.elems[i++] = lfirst_int(cell);
172+
173+
return v;
174+
}
175+
158176
%}
159177

160178
/* BISON Declarations */
@@ -167,30 +185,33 @@ makeItemExpression(List *path, JsonPathParseItem *right_expr)
167185
%union {
168186
string str;
169187
List *elems; /* list of JsonPathParseItem */
188+
List *indexs;
170189
JsonPathParseItem *value;
171190
}
172191

173-
%token <str> TO_P NULL_P TRUE_P FALSE_P
192+
%token <str> TO_P NULL_P TRUE_P FALSE_P
174193
%token <str> STRING_P NUMERIC_P INT_P
175194

176195
%token <str> OR_P AND_P NOT_P
177196

178-
%type <value> result scalar_value
197+
%type <value> result scalar_value
179198

180199
%type <elems> joined_key path absolute_path relative_path
181200

182201
%type <value> key any_key right_expr expr jsonpath numeric
183202

184-
%left OR_P
203+
%type <indexs> index_elem index_list
204+
205+
%left OR_P
185206
%left AND_P
186207
%right NOT_P
187208
%nonassoc '(' ')'
188209

189210
/* Grammar follows */
190211
%%
191212

192-
result:
193-
jsonpath { *result = $1; }
213+
result:
214+
jsonpath { *result = $1; }
194215
| /* EMPTY */ { *result = NULL; }
195216
;
196217

@@ -206,9 +227,9 @@ scalar_value:
206227
;
207228

208229
numeric:
209-
NUMERIC_P { $$ = makeItemNumeric(&$1); }
210-
| INT_P { $$ = makeItemNumeric(&$1); }
211-
| '$' STRING_P { $$ = makeItemVariable(&$2); }
230+
NUMERIC_P { $$ = makeItemNumeric(&$1); }
231+
| INT_P { $$ = makeItemNumeric(&$1); }
232+
| '$' STRING_P { $$ = makeItemVariable(&$2); }
212233
;
213234

214235
right_expr:
@@ -239,15 +260,36 @@ expr:
239260
| NOT_P expr { $$ = makeItemUnary(jpiNot, $2); }
240261
;
241262

263+
index_elem:
264+
INT_P { $$ = list_make1_int(pg_atoi($1.val, 4, 0)); }
265+
| INT_P TO_P INT_P {
266+
int start = pg_atoi($1.val, 4, 0),
267+
stop = pg_atoi($3.val, 4, 0),
268+
i;
269+
270+
$$ = NIL;
271+
272+
for(i=start; i<= stop; i++)
273+
$$ = lappend_int($$, i);
274+
}
275+
;
276+
277+
index_list:
278+
index_elem { $$ = $1; }
279+
| index_list ',' index_elem { $$ = list_concat($1, $3); }
280+
;
281+
242282
any_key:
243283
key { $$ = $1; }
244284
| '*' { $$ = makeItemType(jpiAnyKey); }
245285
| '[' '*' ']' { $$ = makeItemType(jpiAnyArray); }
286+
| '[' index_list ']' { $$ = makeIndexArray($2); }
246287
;
247288

248289
joined_key:
249290
any_key { $$ = list_make1($1); }
250291
| joined_key '[' '*' ']' { $$ = lappend($1, makeItemType(jpiAnyArray)); }
292+
| joined_key '[' index_list ']' { $$ = lappend($1, makeIndexArray($3)); }
251293
;
252294
key:
253295
STRING_P { $$ = makeItemKey(&$1); }

src/include/utils/jsonpath.h

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ typedef enum JsonPathItemType {
4444
jpiGreaterOrEqual,
4545
jpiAnyArray,
4646
jpiAnyKey,
47+
jpiIndexArray,
4748
//jpiAny,
4849
//jpiAll,
4950
//jpiAllArray,
@@ -85,11 +86,8 @@ typedef struct JsonPathItem {
8586

8687
struct {
8788
int nelems;
88-
int current;
89-
int32 *arrayPtr;
89+
int32 *elems;
9090
} array;
91-
92-
uint32 arrayIndex;
9391
};
9492
} JsonPathItem;
9593

@@ -120,7 +118,6 @@ struct JsonPathParseItem {
120118
} args;
121119

122120
JsonPathParseItem *arg;
123-
int8 isType; /* jbv* values */
124121

125122
Numeric numeric;
126123
bool boolean;
@@ -131,10 +128,8 @@ struct JsonPathParseItem {
131128

132129
struct {
133130
int nelems;
134-
JsonPathParseItem **elems;
131+
int32 *elems;
135132
} array;
136-
137-
uint32 arrayIndex;
138133
};
139134
};
140135

src/test/regress/expected/jsonb_jsonpath.out

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,18 @@ select _jsonpath_exists(jsonb '[1]', '$.[*]');
5252
t
5353
(1 row)
5454

55+
select _jsonpath_exists(jsonb '[1]', '$.[1]');
56+
_jsonpath_exists
57+
------------------
58+
f
59+
(1 row)
60+
61+
select _jsonpath_exists(jsonb '[1]', '$.[0]');
62+
_jsonpath_exists
63+
------------------
64+
t
65+
(1 row)
66+
5567
select * from _jsonpath_query(jsonb '{"a": 12, "b": {"a": 13}}', '$.a');
5668
_jsonpath_query
5769
-----------------
@@ -90,3 +102,31 @@ select * from _jsonpath_query(jsonb '[12, {"a": 13}, {"b": 14}]', '$.[*].*');
90102
14
91103
(2 rows)
92104

105+
select * from _jsonpath_query(jsonb '[12, {"a": 13}, {"b": 14}]', '$.[0].a');
106+
_jsonpath_query
107+
-----------------
108+
(0 rows)
109+
110+
select * from _jsonpath_query(jsonb '[12, {"a": 13}, {"b": 14}]', '$.[1].a');
111+
_jsonpath_query
112+
-----------------
113+
13
114+
(1 row)
115+
116+
select * from _jsonpath_query(jsonb '[12, {"a": 13}, {"b": 14}]', '$.[2].a');
117+
_jsonpath_query
118+
-----------------
119+
(0 rows)
120+
121+
select * from _jsonpath_query(jsonb '[12, {"a": 13}, {"b": 14}]', '$.[0,1].a');
122+
_jsonpath_query
123+
-----------------
124+
13
125+
(1 row)
126+
127+
select * from _jsonpath_query(jsonb '[12, {"a": 13}, {"b": 14}]', '$.[0 to 10].a');
128+
_jsonpath_query
129+
-----------------
130+
13
131+
(1 row)
132+

0 commit comments

Comments
 (0)