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

Commit 3713047

Browse files
author
Nikita Glukhov
committed
Add JSON_ARRAY(subquery) transformation
1 parent f334a88 commit 3713047

File tree

5 files changed

+152
-0
lines changed

5 files changed

+152
-0
lines changed

src/backend/nodes/copyfuncs.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2247,6 +2247,23 @@ _copyJsonArrayAgg(const JsonArrayAgg *from)
22472247
return newnode;
22482248
}
22492249

2250+
/*
2251+
* _copyJsonArrayQueryCtor
2252+
*/
2253+
static JsonArrayQueryCtor *
2254+
_copyJsonArrayQueryCtor(const JsonArrayQueryCtor *from)
2255+
{
2256+
JsonArrayQueryCtor *newnode = makeNode(JsonArrayQueryCtor);
2257+
2258+
COPY_NODE_FIELD(query);
2259+
COPY_NODE_FIELD(output);
2260+
COPY_SCALAR_FIELD(format);
2261+
COPY_SCALAR_FIELD(absent_on_null);
2262+
COPY_LOCATION_FIELD(location);
2263+
2264+
return newnode;
2265+
}
2266+
22502267
/* ****************************************************************
22512268
* relation.h copy functions
22522269
*
@@ -5134,6 +5151,9 @@ copyObjectImpl(const void *from)
51345151
case T_JsonArrayCtor:
51355152
retval = _copyJsonArrayCtor(from);
51365153
break;
5154+
case T_JsonArrayQueryCtor:
5155+
retval = _copyJsonArrayQueryCtor(from);
5156+
break;
51375157
case T_JsonArrayAgg:
51385158
retval = _copyJsonArrayAgg(from);
51395159
break;

src/backend/nodes/nodeFuncs.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3772,6 +3772,16 @@ raw_expression_tree_walker(Node *node,
37723772
return true;
37733773
}
37743774
break;
3775+
case T_JsonArrayQueryCtor:
3776+
{
3777+
JsonArrayQueryCtor *jaqc = (JsonArrayQueryCtor *) node;
3778+
3779+
if (walker(jaqc->output, context))
3780+
return true;
3781+
if (walker(jaqc->query, context))
3782+
return true;
3783+
}
3784+
break;
37753785
default:
37763786
elog(ERROR, "unrecognized node type: %d",
37773787
(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;
@@ -3869,6 +3875,71 @@ transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor)
38693875
return coerceJsonFuncExpr(pstate, (Node *) fexpr, &returning, true);
38703876
}
38713877

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

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+
?column?
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+
?column?
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+
?column?
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+
?column?
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)