Skip to content

Commit c10d946

Browse files
author
Nikita Glukhov
committed
Allow jsonpath $ everywhere
1 parent 8e961d3 commit c10d946

File tree

6 files changed

+39
-23
lines changed

6 files changed

+39
-23
lines changed

src/backend/utils/adt/jsonpath.c

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
*/
2626
static int
2727
flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
28-
bool forbiddenRoot, bool insideArraySubscript)
28+
bool allowCurrent, bool insideArraySubscript)
2929
{
3030
/* position from begining of jsonpath data */
3131
int32 pos = buf->len - JSONPATH_HDRSZ;
@@ -90,11 +90,11 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
9090
appendBinaryStringInfo(buf, (char*)&right /* fake value */, sizeof(right));
9191

9292
chld = flattenJsonPathParseItem(buf, item->value.args.left,
93-
forbiddenRoot,
93+
allowCurrent,
9494
insideArraySubscript);
9595
*(int32*)(buf->data + left) = chld;
9696
chld = flattenJsonPathParseItem(buf, item->value.args.right,
97-
forbiddenRoot,
97+
allowCurrent,
9898
insideArraySubscript);
9999
*(int32*)(buf->data + right) = chld;
100100
}
@@ -122,24 +122,20 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
122122

123123
chld = flattenJsonPathParseItem(buf, item->value.arg,
124124
item->type == jpiFilter ||
125-
forbiddenRoot,
125+
allowCurrent,
126126
insideArraySubscript);
127127
*(int32*)(buf->data + arg) = chld;
128128
}
129129
break;
130130
case jpiNull:
131131
break;
132132
case jpiRoot:
133-
if (forbiddenRoot)
134-
ereport(ERROR,
135-
(errcode(ERRCODE_SYNTAX_ERROR),
136-
errmsg("root is not allowed in expression")));
137133
break;
138134
case jpiAnyArray:
139135
case jpiAnyKey:
140136
break;
141137
case jpiCurrent:
142-
if (!forbiddenRoot)
138+
if (!allowCurrent)
143139
ereport(ERROR,
144140
(errcode(ERRCODE_SYNTAX_ERROR),
145141
errmsg("@ is not allowed in root expressions")));
@@ -207,7 +203,7 @@ flattenJsonPathParseItem(StringInfo buf, JsonPathParseItem *item,
207203

208204
if (item->next)
209205
*(int32*)(buf->data + next) =
210-
flattenJsonPathParseItem(buf, item->next, forbiddenRoot,
206+
flattenJsonPathParseItem(buf, item->next, allowCurrent,
211207
insideArraySubscript);
212208

213209
return pos;

src/backend/utils/adt/jsonpath_exec.c

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ typedef struct JsonPathExecContext
2626
{
2727
List *vars;
2828
bool lax;
29+
JsonbValue *root; /* for $ evaluation */
2930
int innermostArraySize; /* for LAST array index evaluation */
3031
} JsonPathExecContext;
3132

@@ -1059,6 +1060,9 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
10591060
else if (!cxt->lax && found) /* XXX deviation from standard */
10601061
res = jperMakeError(ERRCODE_JSON_MEMBER_NOT_FOUND);
10611062
break;
1063+
case jpiRoot:
1064+
jb = cxt->root;
1065+
/* fall through */
10621066
case jpiCurrent:
10631067
if (!jspGetNext(jsp, &elem))
10641068
{
@@ -1318,19 +1322,6 @@ recursiveExecuteNoUnwrap(JsonPathExecContext *cxt, JsonPathItem *jsp,
13181322
case jpiPlus:
13191323
case jpiMinus:
13201324
res = executeUnaryArithmExpr(cxt, jsp, jb, found);
1321-
break;
1322-
case jpiRoot:
1323-
if (jspGetNext(jsp, &elem))
1324-
{
1325-
res = recursiveExecute(cxt, &elem, jb, found);
1326-
}
1327-
else
1328-
{
1329-
res = jperOk;
1330-
if (found)
1331-
*found = lappend(*found, copyJsonbValue(jb));
1332-
}
1333-
13341325
break;
13351326
case jpiFilter:
13361327
jspGetArg(jsp, &elem);
@@ -1852,6 +1843,7 @@ executeJsonPath(JsonPath *path, List *vars, Jsonb *json, List **foundJson)
18521843

18531844
cxt.vars = vars;
18541845
cxt.lax = (path->header & JSONPATH_LAX) != 0;
1846+
cxt.root = &jbv;
18551847
cxt.innermostArraySize = -1;
18561848

18571849
return recursiveExecute(&cxt, &jsp, &jbv, foundJson);

src/test/regress/expected/jsonb_jsonpath.out

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,12 @@ select _jsonpath_exists(jsonb '{"c": {"a": 1, "b":1}}', '$.c ? (.a == .b)');
634634
t
635635
(1 row)
636636

637+
select _jsonpath_exists(jsonb '{"c": {"a": 1, "b":1}}', '$.c ? ($.c.a == .b)');
638+
_jsonpath_exists
639+
------------------
640+
t
641+
(1 row)
642+
637643
select _jsonpath_exists(jsonb '{"c": {"a": 1, "b":1}}', '$.* ? (.a == .b)');
638644
_jsonpath_exists
639645
------------------
@@ -742,6 +748,12 @@ select _jsonpath_exists(jsonb '[1,2,3]', '$ ? (-@[*] < -3)');
742748
f
743749
(1 row)
744750

751+
select _jsonpath_exists(jsonb '1', '$ ? ($ > 0)');
752+
_jsonpath_exists
753+
------------------
754+
t
755+
(1 row)
756+
745757
-- unwrapping of operator arguments in lax mode
746758
select _jsonpath_query(jsonb '{"a": [2]}', 'lax $.a * 3');
747759
_jsonpath_query

src/test/regress/expected/jsonpath.out

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,12 @@ select '$.a/+-1'::jsonpath;
173173
($."a" / -1)
174174
(1 row)
175175

176+
select '$.g ? ($.a == 1)'::jsonpath;
177+
jsonpath
178+
--------------------
179+
$."g"?($."a" == 1)
180+
(1 row)
181+
176182
select '$.g ? (@ == 1)'::jsonpath;
177183
jsonpath
178184
----------------
@@ -311,6 +317,12 @@ select '$.a[$a + 1, ($b[*]) to -(@[0] * 2)]'::jsonpath;
311317
$."a"[$"a" + 1,$"b"[*] to -(@[0] * 2)]
312318
(1 row)
313319

320+
select '$.a[$.a.size() - 3]'::jsonpath;
321+
jsonpath
322+
-------------------------
323+
$."a"[$."a".size() - 3]
324+
(1 row)
325+
314326
select 'last'::jsonpath;
315327
ERROR: LAST is allowed only in array subscripts
316328
LINE 1: select 'last'::jsonpath;

src/test/regress/sql/jsonb_jsonpath.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ from
131131
select _jsonpath_exists(jsonb '{"a": 1, "b":1}', '$ ? (.a == .b)');
132132
select _jsonpath_exists(jsonb '{"c": {"a": 1, "b":1}}', '$ ? (.a == .b)');
133133
select _jsonpath_exists(jsonb '{"c": {"a": 1, "b":1}}', '$.c ? (.a == .b)');
134+
select _jsonpath_exists(jsonb '{"c": {"a": 1, "b":1}}', '$.c ? ($.c.a == .b)');
134135
select _jsonpath_exists(jsonb '{"c": {"a": 1, "b":1}}', '$.* ? (.a == .b)');
135136
select _jsonpath_exists(jsonb '{"a": 1, "b":1}', '$.** ? (.a == .b)');
136137
select _jsonpath_exists(jsonb '{"c": {"a": 1, "b":1}}', '$.** ? (.a == .b)');
@@ -150,6 +151,7 @@ select _jsonpath_exists(jsonb '[1,2,3]', '$ ? (+@[*] > +2)');
150151
select _jsonpath_exists(jsonb '[1,2,3]', '$ ? (+@[*] > +3)');
151152
select _jsonpath_exists(jsonb '[1,2,3]', '$ ? (-@[*] < -2)');
152153
select _jsonpath_exists(jsonb '[1,2,3]', '$ ? (-@[*] < -3)');
154+
select _jsonpath_exists(jsonb '1', '$ ? ($ > 0)');
153155

154156
-- unwrapping of operator arguments in lax mode
155157
select _jsonpath_query(jsonb '{"a": [2]}', 'lax $.a * 3');

src/test/regress/sql/jsonpath.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ select '$-1'::jsonpath;
3030
select '$--+1'::jsonpath;
3131
select '$.a/+-1'::jsonpath;
3232

33+
select '$.g ? ($.a == 1)'::jsonpath;
3334
select '$.g ? (@ == 1)'::jsonpath;
3435
select '$.g ? (a == 1)'::jsonpath;
3536
select '$.g ? (.a == 1)'::jsonpath;
@@ -54,6 +55,7 @@ select '$.g ? (zip == $zip)'::jsonpath;
5455
select '$.a.[1,2, 3 to 16]'::jsonpath;
5556
select '$.a[1,2, 3 to 16]'::jsonpath;
5657
select '$.a[$a + 1, ($b[*]) to -(@[0] * 2)]'::jsonpath;
58+
select '$.a[$.a.size() - 3]'::jsonpath;
5759
select 'last'::jsonpath;
5860
select '"last"'::jsonpath;
5961
select '$.last'::jsonpath;

0 commit comments

Comments
 (0)