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

Commit 62141b4

Browse files
author
Nikita Glukhov
committed
Add JSON_ARRAY(subquery) transformation
1 parent dd4ee04 commit 62141b4

File tree

5 files changed

+156
-0
lines changed

5 files changed

+156
-0
lines changed

src/backend/nodes/copyfuncs.c

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

2211+
/*
2212+
* _copyJsonArrayQueryCtor
2213+
*/
2214+
static JsonArrayQueryCtor *
2215+
_copyJsonArrayQueryCtor(const JsonArrayQueryCtor *from)
2216+
{
2217+
JsonArrayQueryCtor *newnode = makeNode(JsonArrayQueryCtor);
2218+
2219+
COPY_NODE_FIELD(query);
2220+
COPY_NODE_FIELD(output);
2221+
COPY_SCALAR_FIELD(format);
2222+
COPY_SCALAR_FIELD(absent_on_null);
2223+
COPY_LOCATION_FIELD(location);
2224+
2225+
return newnode;
2226+
}
2227+
22112228
/* ****************************************************************
22122229
* relation.h copy functions
22132230
*
@@ -5087,6 +5104,9 @@ copyObjectImpl(const void *from)
50875104
case T_JsonArrayCtor:
50885105
retval = _copyJsonArrayCtor(from);
50895106
break;
5107+
case T_JsonArrayQueryCtor:
5108+
retval = _copyJsonArrayQueryCtor(from);
5109+
break;
50905110
case T_JsonArrayAgg:
50915111
retval = _copyJsonArrayAgg(from);
50925112
break;

src/backend/nodes/nodeFuncs.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3745,6 +3745,16 @@ raw_expression_tree_walker(Node *node,
37453745
return true;
37463746
}
37473747
break;
3748+
case T_JsonArrayQueryCtor:
3749+
{
3750+
JsonArrayQueryCtor *jaqc = (JsonArrayQueryCtor *) node;
3751+
3752+
if (walker(jaqc->output, context))
3753+
return true;
3754+
if (walker(jaqc->query, context))
3755+
return true;
3756+
}
3757+
break;
37483758
default:
37493759
elog(ERROR, "unrecognized node type: %d",
37503760
(int) nodeTag(node));

src/backend/parser/parse_expr.c

Lines changed: 75 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;
@@ -3851,6 +3857,75 @@ transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor)
38513857
true);
38523858
}
38533859

3860+
/*
3861+
* Transform JSON_ARRAY(query [FORMAT] [RETURNING] [ON NULL]) into
3862+
* (SELECT JSON_ARRAYAGG(a [FORMAT] [RETURNING] [ON NULL]) FROM (query) q(a))
3863+
*/
3864+
static Node *
3865+
transformJsonArrayQueryCtor(ParseState *pstate, JsonArrayQueryCtor *ctor)
3866+
{
3867+
SubLink *sublink = makeNode(SubLink);
3868+
SelectStmt *select = makeNode(SelectStmt);
3869+
RangeSubselect *range = makeNode(RangeSubselect);
3870+
Alias *alias = makeNode(Alias);
3871+
ResTarget *target = makeNode(ResTarget);
3872+
JsonArrayAgg *agg = makeNode(JsonArrayAgg);
3873+
JsonValueExpr *jsexpr = makeNode(JsonValueExpr);
3874+
ColumnRef *colref = makeNode(ColumnRef);
3875+
Query *query;
3876+
ParseState *qpstate;
3877+
3878+
/* Transform query only for counting target list entries. */
3879+
qpstate = make_parsestate(pstate);
3880+
3881+
query = transformStmt(qpstate, ctor->query);
3882+
3883+
if (count_nonjunk_tlist_entries(query->targetList) != 1)
3884+
ereport(ERROR,
3885+
(errcode(ERRCODE_SYNTAX_ERROR),
3886+
errmsg("subquery must return only one column"),
3887+
parser_errposition(pstate, ctor->location)));
3888+
3889+
free_parsestate(qpstate);
3890+
3891+
colref->fields = list_make2(makeString(pstrdup("q")),
3892+
makeString(pstrdup("a")));
3893+
colref->location = ctor->location;
3894+
3895+
jsexpr->expr = (Expr *) colref;
3896+
jsexpr->format = ctor->format;
3897+
3898+
agg->arg = jsexpr;
3899+
agg->ctor.agg_order = NIL;
3900+
agg->ctor.output = ctor->output;
3901+
agg->absent_on_null = ctor->absent_on_null;
3902+
agg->ctor.location = ctor->location;
3903+
3904+
target->name = NULL;
3905+
target->indirection = NIL;
3906+
target->val = (Node *) agg;
3907+
target->location = ctor->location;
3908+
3909+
alias->aliasname = pstrdup("q");
3910+
alias->colnames = list_make1(makeString(pstrdup("a")));
3911+
3912+
range->lateral = false;
3913+
range->subquery = ctor->query;
3914+
range->alias = alias;
3915+
3916+
select->targetList = list_make1(target);
3917+
select->fromClause = list_make1(range);
3918+
3919+
sublink->subLinkType = EXPR_SUBLINK;
3920+
sublink->subLinkId = 0;
3921+
sublink->testexpr = NULL;
3922+
sublink->operName = NIL;
3923+
sublink->subselect = (Node *) select;
3924+
sublink->location = ctor->location;
3925+
3926+
return transformExprRecurse(pstate, (Node *) sublink);
3927+
}
3928+
38543929
/*
38553930
* Common code for JSON_OBJECTAGG and JSON_ARRAYAGG transformation.
38563931
*/

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)