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

Commit 6ab06ce

Browse files
author
Nikita Glukhov
committed
Add JSON_ARRAY(subquery) transformation
1 parent 59bc00f commit 6ab06ce

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
@@ -2340,6 +2340,23 @@ _copyJsonArrayAgg(const JsonArrayAgg *from)
23402340
return newnode;
23412341
}
23422342

2343+
/*
2344+
* _copyJsonArrayQueryCtor
2345+
*/
2346+
static JsonArrayQueryCtor *
2347+
_copyJsonArrayQueryCtor(const JsonArrayQueryCtor *from)
2348+
{
2349+
JsonArrayQueryCtor *newnode = makeNode(JsonArrayQueryCtor);
2350+
2351+
COPY_NODE_FIELD(query);
2352+
COPY_NODE_FIELD(output);
2353+
COPY_SCALAR_FIELD(format);
2354+
COPY_SCALAR_FIELD(absent_on_null);
2355+
COPY_LOCATION_FIELD(location);
2356+
2357+
return newnode;
2358+
}
2359+
23432360
/* ****************************************************************
23442361
* pathnodes.h copy functions
23452362
*
@@ -5262,6 +5279,9 @@ copyObjectImpl(const void *from)
52625279
case T_JsonArrayCtor:
52635280
retval = _copyJsonArrayCtor(from);
52645281
break;
5282+
case T_JsonArrayQueryCtor:
5283+
retval = _copyJsonArrayQueryCtor(from);
5284+
break;
52655285
case T_JsonArrayAgg:
52665286
retval = _copyJsonArrayAgg(from);
52675287
break;

src/backend/nodes/nodeFuncs.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3837,6 +3837,16 @@ raw_expression_tree_walker(Node *node,
38373837
return true;
38383838
}
38393839
break;
3840+
case T_JsonArrayQueryCtor:
3841+
{
3842+
JsonArrayQueryCtor *jaqc = (JsonArrayQueryCtor *) node;
3843+
3844+
if (walker(jaqc->output, context))
3845+
return true;
3846+
if (walker(jaqc->query, context))
3847+
return true;
3848+
}
3849+
break;
38403850
default:
38413851
elog(ERROR, "unrecognized node type: %d",
38423852
(int) nodeTag(node));

src/backend/parser/parse_expr.c

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

388+
case T_JsonArrayQueryCtor:
389+
result = transformJsonArrayQueryCtor(pstate, (JsonArrayQueryCtor *) expr);
390+
break;
391+
386392
case T_JsonObjectAgg:
387393
result = transformJsonObjectAgg(pstate, (JsonObjectAgg *) expr);
388394
break;
@@ -3970,6 +3976,71 @@ transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor)
39703976
return coerceJsonFuncExpr(pstate, (Node *) fexpr, &returning, true);
39713977
}
39723978

3979+
/*
3980+
* Transform JSON_ARRAY(query [FORMAT] [RETURNING] [ON NULL]) into
3981+
* (SELECT JSON_ARRAYAGG(a [FORMAT] [RETURNING] [ON NULL]) FROM (query) q(a))
3982+
*/
3983+
static Node *
3984+
transformJsonArrayQueryCtor(ParseState *pstate, JsonArrayQueryCtor *ctor)
3985+
{
3986+
SubLink *sublink = makeNode(SubLink);
3987+
SelectStmt *select = makeNode(SelectStmt);
3988+
RangeSubselect *range = makeNode(RangeSubselect);
3989+
Alias *alias = makeNode(Alias);
3990+
ResTarget *target = makeNode(ResTarget);
3991+
JsonArrayAgg *agg = makeNode(JsonArrayAgg);
3992+
ColumnRef *colref = makeNode(ColumnRef);
3993+
Query *query;
3994+
ParseState *qpstate;
3995+
3996+
/* Transform query only for counting target list entries. */
3997+
qpstate = make_parsestate(pstate);
3998+
3999+
query = transformStmt(qpstate, ctor->query);
4000+
4001+
if (count_nonjunk_tlist_entries(query->targetList) != 1)
4002+
ereport(ERROR,
4003+
(errcode(ERRCODE_SYNTAX_ERROR),
4004+
errmsg("subquery must return only one column"),
4005+
parser_errposition(pstate, ctor->location)));
4006+
4007+
free_parsestate(qpstate);
4008+
4009+
colref->fields = list_make2(makeString(pstrdup("q")),
4010+
makeString(pstrdup("a")));
4011+
colref->location = ctor->location;
4012+
4013+
agg->arg = makeJsonValueExpr((Expr *) colref, ctor->format);
4014+
agg->ctor.agg_order = NIL;
4015+
agg->ctor.output = ctor->output;
4016+
agg->absent_on_null = ctor->absent_on_null;
4017+
agg->ctor.location = ctor->location;
4018+
4019+
target->name = NULL;
4020+
target->indirection = NIL;
4021+
target->val = (Node *) agg;
4022+
target->location = ctor->location;
4023+
4024+
alias->aliasname = pstrdup("q");
4025+
alias->colnames = list_make1(makeString(pstrdup("a")));
4026+
4027+
range->lateral = false;
4028+
range->subquery = ctor->query;
4029+
range->alias = alias;
4030+
4031+
select->targetList = list_make1(target);
4032+
select->fromClause = list_make1(range);
4033+
4034+
sublink->subLinkType = EXPR_SUBLINK;
4035+
sublink->subLinkId = 0;
4036+
sublink->testexpr = NULL;
4037+
sublink->operName = NIL;
4038+
sublink->subselect = (Node *) select;
4039+
sublink->location = ctor->location;
4040+
4041+
return transformExprRecurse(pstate, (Node *) sublink);
4042+
}
4043+
39734044
/*
39744045
* Common code for JSON_OBJECTAGG and JSON_ARRAYAGG transformation.
39754046
*/

src/backend/parser/parse_target.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1930,6 +1930,7 @@ FigureColnameInternal(Node *node, char **name)
19301930
*name = "json_object";
19311931
return 2;
19321932
case T_JsonArrayCtor:
1933+
case T_JsonArrayQueryCtor:
19331934
*name = "json_array";
19341935
return 2;
19351936
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)