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

Commit df1bf8f

Browse files
author
Nikita Glukhov
committed
Add JSON_ARRAY(subquery) transformation
1 parent cb6ae67 commit df1bf8f

File tree

6 files changed

+153
-0
lines changed

6 files changed

+153
-0
lines changed

src/backend/nodes/copyfuncs.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2325,6 +2325,23 @@ _copyJsonArrayAgg(const JsonArrayAgg *from)
23252325
return newnode;
23262326
}
23272327

2328+
/*
2329+
* _copyJsonArrayQueryCtor
2330+
*/
2331+
static JsonArrayQueryCtor *
2332+
_copyJsonArrayQueryCtor(const JsonArrayQueryCtor *from)
2333+
{
2334+
JsonArrayQueryCtor *newnode = makeNode(JsonArrayQueryCtor);
2335+
2336+
COPY_NODE_FIELD(query);
2337+
COPY_NODE_FIELD(output);
2338+
COPY_SCALAR_FIELD(format);
2339+
COPY_SCALAR_FIELD(absent_on_null);
2340+
COPY_LOCATION_FIELD(location);
2341+
2342+
return newnode;
2343+
}
2344+
23282345
/* ****************************************************************
23292346
* relation.h copy functions
23302347
*
@@ -5233,6 +5250,9 @@ copyObjectImpl(const void *from)
52335250
case T_JsonArrayCtor:
52345251
retval = _copyJsonArrayCtor(from);
52355252
break;
5253+
case T_JsonArrayQueryCtor:
5254+
retval = _copyJsonArrayQueryCtor(from);
5255+
break;
52365256
case T_JsonArrayAgg:
52375257
retval = _copyJsonArrayAgg(from);
52385258
break;

src/backend/nodes/nodeFuncs.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3797,6 +3797,16 @@ raw_expression_tree_walker(Node *node,
37973797
return true;
37983798
}
37993799
break;
3800+
case T_JsonArrayQueryCtor:
3801+
{
3802+
JsonArrayQueryCtor *jaqc = (JsonArrayQueryCtor *) node;
3803+
3804+
if (walker(jaqc->output, context))
3805+
return true;
3806+
if (walker(jaqc->query, context))
3807+
return true;
3808+
}
3809+
break;
38003810
default:
38013811
elog(ERROR, "unrecognized node type: %d",
38023812
(int) nodeTag(node));

src/backend/parser/parse_expr.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ static Node *transformTypeCast(ParseState *pstate, TypeCast *tc);
126126
static Node *transformCollateClause(ParseState *pstate, CollateClause *c);
127127
static Node *transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor);
128128
static Node *transformJsonArrayCtor(ParseState *pstate, JsonArrayCtor *ctor);
129+
static Node *transformJsonArrayQueryCtor(ParseState *pstate,
130+
JsonArrayQueryCtor *ctor);
129131
static Node *transformJsonObjectAgg(ParseState *pstate, JsonObjectAgg *agg);
130132
static Node *transformJsonArrayAgg(ParseState *pstate, JsonArrayAgg *agg);
131133
static Node *make_row_comparison_op(ParseState *pstate, List *opname,
@@ -384,6 +386,10 @@ transformExprRecurse(ParseState *pstate, Node *expr)
384386
result = transformJsonArrayCtor(pstate, (JsonArrayCtor *) expr);
385387
break;
386388

389+
case T_JsonArrayQueryCtor:
390+
result = transformJsonArrayQueryCtor(pstate, (JsonArrayQueryCtor *) expr);
391+
break;
392+
387393
case T_JsonObjectAgg:
388394
result = transformJsonObjectAgg(pstate, (JsonObjectAgg *) expr);
389395
break;
@@ -3882,6 +3888,71 @@ transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor)
38823888
return coerceJsonFuncExpr(pstate, (Node *) fexpr, &returning, true);
38833889
}
38843890

3891+
/*
3892+
* Transform JSON_ARRAY(query [FORMAT] [RETURNING] [ON NULL]) into
3893+
* (SELECT JSON_ARRAYAGG(a [FORMAT] [RETURNING] [ON NULL]) FROM (query) q(a))
3894+
*/
3895+
static Node *
3896+
transformJsonArrayQueryCtor(ParseState *pstate, JsonArrayQueryCtor *ctor)
3897+
{
3898+
SubLink *sublink = makeNode(SubLink);
3899+
SelectStmt *select = makeNode(SelectStmt);
3900+
RangeSubselect *range = makeNode(RangeSubselect);
3901+
Alias *alias = makeNode(Alias);
3902+
ResTarget *target = makeNode(ResTarget);
3903+
JsonArrayAgg *agg = makeNode(JsonArrayAgg);
3904+
ColumnRef *colref = makeNode(ColumnRef);
3905+
Query *query;
3906+
ParseState *qpstate;
3907+
3908+
/* Transform query only for counting target list entries. */
3909+
qpstate = make_parsestate(pstate);
3910+
3911+
query = transformStmt(qpstate, ctor->query);
3912+
3913+
if (count_nonjunk_tlist_entries(query->targetList) != 1)
3914+
ereport(ERROR,
3915+
(errcode(ERRCODE_SYNTAX_ERROR),
3916+
errmsg("subquery must return only one column"),
3917+
parser_errposition(pstate, ctor->location)));
3918+
3919+
free_parsestate(qpstate);
3920+
3921+
colref->fields = list_make2(makeString(pstrdup("q")),
3922+
makeString(pstrdup("a")));
3923+
colref->location = ctor->location;
3924+
3925+
agg->arg = makeJsonValueExpr((Expr *) colref, ctor->format);
3926+
agg->ctor.agg_order = NIL;
3927+
agg->ctor.output = ctor->output;
3928+
agg->absent_on_null = ctor->absent_on_null;
3929+
agg->ctor.location = ctor->location;
3930+
3931+
target->name = NULL;
3932+
target->indirection = NIL;
3933+
target->val = (Node *) agg;
3934+
target->location = ctor->location;
3935+
3936+
alias->aliasname = pstrdup("q");
3937+
alias->colnames = list_make1(makeString(pstrdup("a")));
3938+
3939+
range->lateral = false;
3940+
range->subquery = ctor->query;
3941+
range->alias = alias;
3942+
3943+
select->targetList = list_make1(target);
3944+
select->fromClause = list_make1(range);
3945+
3946+
sublink->subLinkType = EXPR_SUBLINK;
3947+
sublink->subLinkId = 0;
3948+
sublink->testexpr = NULL;
3949+
sublink->operName = NIL;
3950+
sublink->subselect = (Node *) select;
3951+
sublink->location = ctor->location;
3952+
3953+
return transformExprRecurse(pstate, (Node *) sublink);
3954+
}
3955+
38853956
/*
38863957
* Common code for JSON_OBJECTAGG and JSON_ARRAYAGG transformation.
38873958
*/

src/backend/parser/parse_target.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1922,6 +1922,7 @@ FigureColnameInternal(Node *node, char **name)
19221922
*name = "json_object";
19231923
return 2;
19241924
case T_JsonArrayCtor:
1925+
case T_JsonArrayQueryCtor:
19251926
*name = "json_array";
19261927
return 2;
19271928
case T_JsonObjectAgg:

src/test/regress/expected/sqljson.out

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,46 @@ SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' FORMAT JSON RETURNING text) FORMAT
419419
[[{ "a" : 123 }]]
420420
(1 row)
421421

422+
SELECT JSON_ARRAY(SELECT i FROM (VALUES (1), (2), (NULL), (4)) foo(i));
423+
json_array
424+
------------
425+
[1, 2, 4]
426+
(1 row)
427+
428+
SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i));
429+
json_array
430+
------------
431+
[[1,2], +
432+
[3,4]]
433+
(1 row)
434+
435+
SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) RETURNING jsonb);
436+
json_array
437+
------------------
438+
[[1, 2], [3, 4]]
439+
(1 row)
440+
441+
--SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) NULL ON NULL);
442+
--SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) NULL ON NULL RETURNING jsonb);
443+
SELECT JSON_ARRAY(SELECT i FROM (VALUES (3), (1), (NULL), (2)) foo(i) ORDER BY i);
444+
json_array
445+
------------
446+
[1, 2, 3]
447+
(1 row)
448+
449+
-- Should fail
450+
SELECT JSON_ARRAY(SELECT FROM (VALUES (1)) foo(i));
451+
ERROR: subquery must return only one column
452+
LINE 1: SELECT JSON_ARRAY(SELECT FROM (VALUES (1)) foo(i));
453+
^
454+
SELECT JSON_ARRAY(SELECT i, i FROM (VALUES (1)) foo(i));
455+
ERROR: subquery must return only one column
456+
LINE 1: SELECT JSON_ARRAY(SELECT i, i FROM (VALUES (1)) foo(i));
457+
^
458+
SELECT JSON_ARRAY(SELECT * FROM (VALUES (1, 2)) foo(i, j));
459+
ERROR: subquery must return only one column
460+
LINE 1: SELECT JSON_ARRAY(SELECT * FROM (VALUES (1, 2)) foo(i, j));
461+
^
422462
-- JSON_ARRAYAGG()
423463
SELECT JSON_ARRAYAGG(i) IS NULL,
424464
JSON_ARRAYAGG(i RETURNING jsonb) IS NULL

src/test/regress/sql/sqljson.sql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,17 @@ SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' RETURNING text));
116116
SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' FORMAT JSON RETURNING text));
117117
SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' FORMAT JSON RETURNING text) FORMAT JSON);
118118

119+
SELECT JSON_ARRAY(SELECT i FROM (VALUES (1), (2), (NULL), (4)) foo(i));
120+
SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i));
121+
SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) RETURNING jsonb);
122+
--SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) NULL ON NULL);
123+
--SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) NULL ON NULL RETURNING jsonb);
124+
SELECT JSON_ARRAY(SELECT i FROM (VALUES (3), (1), (NULL), (2)) foo(i) ORDER BY i);
125+
-- Should fail
126+
SELECT JSON_ARRAY(SELECT FROM (VALUES (1)) foo(i));
127+
SELECT JSON_ARRAY(SELECT i, i FROM (VALUES (1)) foo(i));
128+
SELECT JSON_ARRAY(SELECT * FROM (VALUES (1, 2)) foo(i, j));
129+
119130
-- JSON_ARRAYAGG()
120131
SELECT JSON_ARRAYAGG(i) IS NULL,
121132
JSON_ARRAYAGG(i RETURNING jsonb) IS NULL

0 commit comments

Comments
 (0)