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

Commit 980c6a8

Browse files
author
Nikita Glukhov
committed
Add JSON_ARRAY(subquery) transformation
1 parent 93cf46c commit 980c6a8

File tree

4 files changed

+146
-0
lines changed

4 files changed

+146
-0
lines changed

src/backend/nodes/copyfuncs.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2207,6 +2207,23 @@ _copyJsonArrayAgg(const JsonArrayAgg *from)
22072207
return newnode;
22082208
}
22092209

2210+
/*
2211+
* _copyJsonArrayQueryCtor
2212+
*/
2213+
static JsonArrayQueryCtor *
2214+
_copyJsonArrayQueryCtor(const JsonArrayQueryCtor *from)
2215+
{
2216+
JsonArrayQueryCtor *newnode = makeNode(JsonArrayQueryCtor);
2217+
2218+
COPY_NODE_FIELD(query);
2219+
COPY_NODE_FIELD(output);
2220+
COPY_SCALAR_FIELD(format);
2221+
COPY_SCALAR_FIELD(absent_on_null);
2222+
COPY_LOCATION_FIELD(location);
2223+
2224+
return newnode;
2225+
}
2226+
22102227
/* ****************************************************************
22112228
* relation.h copy functions
22122229
*
@@ -5071,6 +5088,9 @@ copyObjectImpl(const void *from)
50715088
case T_JsonArrayCtor:
50725089
retval = _copyJsonArrayCtor(from);
50735090
break;
5091+
case T_JsonArrayQueryCtor:
5092+
retval = _copyJsonArrayQueryCtor(from);
5093+
break;
50745094
case T_JsonArrayAgg:
50755095
retval = _copyJsonArrayAgg(from);
50765096
break;

src/backend/parser/parse_expr.c

Lines changed: 74 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;
@@ -3740,6 +3746,74 @@ transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor)
37403746
return coerceJsonFuncExpr(pstate, (Node *) fexpr, ctor->output);
37413747
}
37423748

3749+
/* Transform JSON_ARRAY(query [FORMAT] [RETURNING] [ON NULL]) into
3750+
* (SELECT JSON_ARRAYAGG(a [FORMAT] [RETURNING] [ON NULL]) FROM (query) q(a))
3751+
*/
3752+
static Node *
3753+
transformJsonArrayQueryCtor(ParseState *pstate, JsonArrayQueryCtor *ctor)
3754+
{
3755+
SubLink *sublink = makeNode(SubLink);
3756+
SelectStmt *select = makeNode(SelectStmt);
3757+
RangeSubselect *range = makeNode(RangeSubselect);
3758+
Alias *alias = makeNode(Alias);
3759+
ResTarget *target = makeNode(ResTarget);
3760+
JsonArrayAgg *agg = makeNode(JsonArrayAgg);
3761+
JsonValueExpr *jsexpr = makeNode(JsonValueExpr);
3762+
ColumnRef *colref = makeNode(ColumnRef);
3763+
Query *query;
3764+
ParseState *qpstate;
3765+
3766+
/* Transform query only for counting target list entries. */
3767+
qpstate = make_parsestate(pstate);
3768+
3769+
query = transformStmt(qpstate, ctor->query);
3770+
3771+
if (count_nonjunk_tlist_entries(query->targetList) != 1)
3772+
ereport(ERROR,
3773+
(errcode(ERRCODE_SYNTAX_ERROR),
3774+
errmsg("subquery must return only one column"),
3775+
parser_errposition(pstate, ctor->location)));
3776+
3777+
free_parsestate(qpstate);
3778+
3779+
colref->fields = list_make2(makeString(pstrdup("q")),
3780+
makeString(pstrdup("a")));
3781+
colref->location = ctor->location;
3782+
3783+
jsexpr->expr = (Expr *) colref;
3784+
jsexpr->format = ctor->format;
3785+
3786+
agg->arg = jsexpr;
3787+
agg->ctor.agg_order = NIL;
3788+
agg->ctor.output = ctor->output;
3789+
agg->absent_on_null = ctor->absent_on_null;
3790+
agg->ctor.location = ctor->location;
3791+
3792+
target->name = NULL;
3793+
target->indirection = NIL;
3794+
target->val = (Node *) agg;
3795+
target->location = ctor->location;
3796+
3797+
alias->aliasname = pstrdup("q");
3798+
alias->colnames = list_make1(makeString(pstrdup("a")));
3799+
3800+
range->lateral = false;
3801+
range->subquery = ctor->query;
3802+
range->alias = alias;
3803+
3804+
select->targetList = list_make1(target);
3805+
select->fromClause = list_make1(range);
3806+
3807+
sublink->subLinkType = EXPR_SUBLINK;
3808+
sublink->subLinkId = 0;
3809+
sublink->testexpr = NULL;
3810+
sublink->operName = NIL;
3811+
sublink->subselect = (Node *) select;
3812+
sublink->location = ctor->location;
3813+
3814+
return transformExprRecurse(pstate, (Node *) sublink);
3815+
}
3816+
37433817
static Node *
37443818
transformJsonAggCtor(ParseState *pstate, JsonAggCtor *agg_ctor, List *args,
37453819
Oid aggfnoid, Oid aggtype)

src/test/regress/expected/sqljson.out

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,46 @@ SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' FORMAT JSON RETURNING bytea FORMAT
471471
[[{"a": 123}]]
472472
(1 row)
473473

474+
SELECT JSON_ARRAY(SELECT i FROM (VALUES (1), (2), (NULL), (4)) foo(i));
475+
?column?
476+
-----------
477+
[1, 2, 4]
478+
(1 row)
479+
480+
SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i));
481+
?column?
482+
----------
483+
[[1,2], +
484+
[3,4]]
485+
(1 row)
486+
487+
SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) RETURNING jsonb);
488+
?column?
489+
------------------
490+
[[1, 2], [3, 4]]
491+
(1 row)
492+
493+
--SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) NULL ON NULL);
494+
--SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) NULL ON NULL RETURNING jsonb);
495+
SELECT JSON_ARRAY(SELECT i FROM (VALUES (3), (1), (NULL), (2)) foo(i) ORDER BY i);
496+
?column?
497+
-----------
498+
[1, 2, 3]
499+
(1 row)
500+
501+
-- Should fail
502+
SELECT JSON_ARRAY(SELECT FROM (VALUES (1)) foo(i));
503+
ERROR: subquery must return only one column
504+
LINE 1: SELECT JSON_ARRAY(SELECT FROM (VALUES (1)) foo(i));
505+
^
506+
SELECT JSON_ARRAY(SELECT i, i FROM (VALUES (1)) foo(i));
507+
ERROR: subquery must return only one column
508+
LINE 1: SELECT JSON_ARRAY(SELECT i, i FROM (VALUES (1)) foo(i));
509+
^
510+
SELECT JSON_ARRAY(SELECT * FROM (VALUES (1, 2)) foo(i, j));
511+
ERROR: subquery must return only one column
512+
LINE 1: SELECT JSON_ARRAY(SELECT * FROM (VALUES (1, 2)) foo(i, j));
513+
^
474514
-- JSON_ARRAYAGG()
475515
SELECT JSON_ARRAYAGG(i) IS NULL,
476516
JSON_ARRAYAGG(i RETURNING jsonb) IS NULL

src/test/regress/sql/sqljson.sql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,18 @@ SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' FORMAT JSON RETURNING text) FORMAT
125125
SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' FORMAT JSON RETURNING text) FORMAT JSONB);
126126
SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' FORMAT JSON RETURNING bytea FORMAT JSONB));
127127
SELECT JSON_ARRAY(JSON_ARRAY('{ "a" : 123 }' FORMAT JSON RETURNING bytea FORMAT JSONB) FORMAT JSONB);
128+
129+
SELECT JSON_ARRAY(SELECT i FROM (VALUES (1), (2), (NULL), (4)) foo(i));
130+
SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i));
131+
SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) RETURNING jsonb);
132+
--SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) NULL ON NULL);
133+
--SELECT JSON_ARRAY(SELECT i FROM (VALUES (NULL::int[]), ('{1,2}'), (NULL), (NULL), ('{3,4}'), (NULL)) foo(i) NULL ON NULL RETURNING jsonb);
134+
SELECT JSON_ARRAY(SELECT i FROM (VALUES (3), (1), (NULL), (2)) foo(i) ORDER BY i);
135+
-- Should fail
136+
SELECT JSON_ARRAY(SELECT FROM (VALUES (1)) foo(i));
137+
SELECT JSON_ARRAY(SELECT i, i FROM (VALUES (1)) foo(i));
138+
SELECT JSON_ARRAY(SELECT * FROM (VALUES (1, 2)) foo(i, j));
139+
128140
-- JSON_ARRAYAGG()
129141
SELECT JSON_ARRAYAGG(i) IS NULL,
130142
JSON_ARRAYAGG(i RETURNING jsonb) IS NULL

0 commit comments

Comments
 (0)