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

Commit 171cf7b

Browse files
author
Nikita Glukhov
committed
Add JSON_OBJECTAGG() and JSON_ARRAYAGG() transformation
1 parent b47bb7b commit 171cf7b

File tree

10 files changed

+738
-33
lines changed

10 files changed

+738
-33
lines changed

src/backend/nodes/copyfuncs.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2193,6 +2193,26 @@ _copyJsonCtorOpts(const JsonCtorOpts *from)
21932193
return newnode;
21942194
}
21952195

2196+
/*
2197+
* _copyJsonObjectAgg
2198+
*/
2199+
static JsonObjectAgg *
2200+
_copyJsonObjectAgg(const JsonObjectAgg *from)
2201+
{
2202+
JsonObjectAgg *newnode = makeNode(JsonObjectAgg);
2203+
2204+
COPY_NODE_FIELD(ctor.output);
2205+
COPY_NODE_FIELD(ctor.agg_filter);
2206+
COPY_NODE_FIELD(ctor.agg_order);
2207+
COPY_NODE_FIELD(ctor.over);
2208+
COPY_LOCATION_FIELD(ctor.location);
2209+
COPY_NODE_FIELD(arg);
2210+
COPY_SCALAR_FIELD(absent_on_null);
2211+
COPY_SCALAR_FIELD(unique);
2212+
2213+
return newnode;
2214+
}
2215+
21962216
/*
21972217
* _copyJsonArrayCtor
21982218
*/
@@ -2209,6 +2229,25 @@ _copyJsonArrayCtor(const JsonArrayCtor *from)
22092229
return newnode;
22102230
}
22112231

2232+
/*
2233+
* _copyJsonArrayAgg
2234+
*/
2235+
static JsonArrayAgg *
2236+
_copyJsonArrayAgg(const JsonArrayAgg *from)
2237+
{
2238+
JsonArrayAgg *newnode = makeNode(JsonArrayAgg);
2239+
2240+
COPY_NODE_FIELD(ctor.output);
2241+
COPY_NODE_FIELD(ctor.agg_filter);
2242+
COPY_NODE_FIELD(ctor.agg_order);
2243+
COPY_NODE_FIELD(ctor.over);
2244+
COPY_LOCATION_FIELD(ctor.location);
2245+
COPY_NODE_FIELD(arg);
2246+
COPY_SCALAR_FIELD(absent_on_null);
2247+
2248+
return newnode;
2249+
}
2250+
22122251
/* ****************************************************************
22132252
* relation.h copy functions
22142253
*
@@ -5073,9 +5112,15 @@ copyObjectImpl(const void *from)
50735112
case T_JsonObjectCtor:
50745113
retval = _copyJsonObjectCtor(from);
50755114
break;
5115+
case T_JsonObjectAgg:
5116+
retval = _copyJsonObjectAgg(from);
5117+
break;
50765118
case T_JsonArrayCtor:
50775119
retval = _copyJsonArrayCtor(from);
50785120
break;
5121+
case T_JsonArrayAgg:
5122+
retval = _copyJsonArrayAgg(from);
5123+
break;
50795124

50805125
/*
50815126
* RELATION NODES

src/backend/nodes/nodeFuncs.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3740,6 +3740,38 @@ raw_expression_tree_walker(Node *node,
37403740
return true;
37413741
}
37423742
break;
3743+
case T_JsonObjectAgg:
3744+
{
3745+
JsonObjectAgg *joa = (JsonObjectAgg *) node;
3746+
3747+
if (walker(joa->ctor.output, context))
3748+
return true;
3749+
if (walker(joa->ctor.agg_order, context))
3750+
return true;
3751+
if (walker(joa->ctor.agg_filter, context))
3752+
return true;
3753+
if (walker(joa->ctor.over, context))
3754+
return true;
3755+
if (walker(joa->arg, context))
3756+
return true;
3757+
}
3758+
break;
3759+
case T_JsonArrayAgg:
3760+
{
3761+
JsonArrayAgg *jaa = (JsonArrayAgg *) node;
3762+
3763+
if (walker(jaa->ctor.output, context))
3764+
return true;
3765+
if (walker(jaa->ctor.agg_order, context))
3766+
return true;
3767+
if (walker(jaa->ctor.agg_filter, context))
3768+
return true;
3769+
if (walker(jaa->ctor.over, context))
3770+
return true;
3771+
if (walker(jaa->arg, context))
3772+
return true;
3773+
}
3774+
break;
37433775
default:
37443776
elog(ERROR, "unrecognized node type: %d",
37453777
(int) nodeTag(node));

src/backend/parser/parse_expr.c

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
#include "postgres.h"
1717

18+
#include "catalog/pg_aggregate.h"
19+
#include "catalog/pg_proc.h"
1820
#include "catalog/pg_type.h"
1921
#include "commands/dbcommands.h"
2022
#include "miscadmin.h"
@@ -124,6 +126,8 @@ static Node *transformTypeCast(ParseState *pstate, TypeCast *tc);
124126
static Node *transformCollateClause(ParseState *pstate, CollateClause *c);
125127
static Node *transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor);
126128
static Node *transformJsonArrayCtor(ParseState *pstate, JsonArrayCtor *ctor);
129+
static Node *transformJsonObjectAgg(ParseState *pstate, JsonObjectAgg *agg);
130+
static Node *transformJsonArrayAgg(ParseState *pstate, JsonArrayAgg *agg);
127131
static Node *make_row_comparison_op(ParseState *pstate, List *opname,
128132
List *largs, List *rargs, int location);
129133
static Node *make_row_distinct_op(ParseState *pstate, List *opname,
@@ -380,6 +384,14 @@ transformExprRecurse(ParseState *pstate, Node *expr)
380384
result = transformJsonArrayCtor(pstate, (JsonArrayCtor *) expr);
381385
break;
382386

387+
case T_JsonObjectAgg:
388+
result = transformJsonObjectAgg(pstate, (JsonObjectAgg *) expr);
389+
break;
390+
391+
case T_JsonArrayAgg:
392+
result = transformJsonArrayAgg(pstate, (JsonArrayAgg *) expr);
393+
break;
394+
383395
default:
384396
/* should not reach here */
385397
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
@@ -3857,6 +3869,162 @@ transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor)
38573869
return coerceJsonFuncExpr(pstate, (Node *) fexpr, &returning, true);
38583870
}
38593871

3872+
/*
3873+
* Common code for JSON_OBJECTAGG and JSON_ARRAYAGG transformation.
3874+
*/
3875+
static Node *
3876+
transformJsonAggCtor(ParseState *pstate, JsonAggCtor *agg_ctor,
3877+
JsonReturning *returning, List *args, Oid aggfnoid,
3878+
Oid aggtype, FuncFormat format, JsonCtorOpts *formatopts)
3879+
{
3880+
Node *node;
3881+
Expr *aggfilter = agg_ctor->agg_filter ? (Expr *)
3882+
transformWhereClause(pstate, agg_ctor->agg_filter,
3883+
EXPR_KIND_FILTER, "FILTER") : NULL;
3884+
3885+
if (agg_ctor->over)
3886+
{
3887+
/* window function */
3888+
WindowFunc *wfunc = makeNode(WindowFunc);
3889+
3890+
wfunc->winfnoid = aggfnoid;
3891+
wfunc->wintype = aggtype;
3892+
/* wincollid and inputcollid will be set by parse_collate.c */
3893+
wfunc->args = args;
3894+
/* winref will be set by transformWindowFuncCall */
3895+
wfunc->winstar = false;
3896+
wfunc->winagg = true;
3897+
wfunc->aggfilter = aggfilter;
3898+
wfunc->winformat = format;
3899+
wfunc->winformatopts = (Node *) formatopts;
3900+
wfunc->location = agg_ctor->location;
3901+
3902+
/*
3903+
* ordered aggs not allowed in windows yet
3904+
*/
3905+
if (agg_ctor->agg_order != NIL)
3906+
ereport(ERROR,
3907+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3908+
errmsg("aggregate ORDER BY is not implemented for window functions"),
3909+
parser_errposition(pstate, agg_ctor->location)));
3910+
3911+
/* parse_agg.c does additional window-func-specific processing */
3912+
transformWindowFuncCall(pstate, wfunc, agg_ctor->over);
3913+
3914+
node = (Node *) wfunc;
3915+
}
3916+
else
3917+
{
3918+
Aggref *aggref = makeNode(Aggref);
3919+
3920+
aggref->aggfnoid = aggfnoid;
3921+
aggref->aggtype = aggtype;
3922+
3923+
/* aggcollid and inputcollid will be set by parse_collate.c */
3924+
aggref->aggtranstype = InvalidOid; /* will be set by planner */
3925+
/* aggargtypes will be set by transformAggregateCall */
3926+
/* aggdirectargs and args will be set by transformAggregateCall */
3927+
/* aggorder and aggdistinct will be set by transformAggregateCall */
3928+
aggref->aggfilter = aggfilter;
3929+
aggref->aggstar = false;
3930+
aggref->aggvariadic = false;
3931+
aggref->aggkind = AGGKIND_NORMAL;
3932+
/* agglevelsup will be set by transformAggregateCall */
3933+
aggref->aggsplit = AGGSPLIT_SIMPLE; /* planner might change this */
3934+
aggref->aggformat = format;
3935+
aggref->aggformatopts = (Node *) formatopts;
3936+
aggref->location = agg_ctor->location;
3937+
3938+
transformAggregateCall(pstate, aggref, args, agg_ctor->agg_order, false);
3939+
3940+
node = (Node *) aggref;
3941+
}
3942+
3943+
return coerceJsonFuncExpr(pstate, node, returning, true);
3944+
}
3945+
3946+
/*
3947+
* Transform JSON_OBJECTAGG() aggregate function.
3948+
*
3949+
* JSON_OBJECTAGG() is transformed into
3950+
* json[b]_objectagg(key, value, absent_on_null, check_unique) call depending on
3951+
* the output JSON format. Then the function call result is coerced to the
3952+
* target output type.
3953+
*/
3954+
static Node *
3955+
transformJsonObjectAgg(ParseState *pstate, JsonObjectAgg *agg)
3956+
{
3957+
JsonReturning returning;
3958+
Node *key;
3959+
Node *val;
3960+
List *args;
3961+
Oid aggfnoid;
3962+
Oid aggtype;
3963+
3964+
transformJsonOutput(pstate, agg->ctor.output, true, &returning);
3965+
3966+
key = transformExprRecurse(pstate, (Node *) agg->arg->key);
3967+
val = transformJsonValueExpr(pstate, agg->arg->value, JS_FORMAT_DEFAULT);
3968+
3969+
args = list_make4(key,
3970+
val,
3971+
makeBoolConst(agg->absent_on_null, false),
3972+
makeBoolConst(agg->unique, false));
3973+
3974+
if (returning.format.type == JS_FORMAT_JSONB)
3975+
{
3976+
aggfnoid = F_JSONB_OBJECTAGG;
3977+
aggtype = JSONBOID;
3978+
}
3979+
else
3980+
{
3981+
aggfnoid = F_JSON_OBJECTAGG;
3982+
aggtype = JSONOID;
3983+
}
3984+
3985+
return transformJsonAggCtor(pstate, &agg->ctor, &returning, args, aggfnoid,
3986+
aggtype, FUNCFMT_JSON_OBJECTAGG,
3987+
makeJsonCtorOpts(&returning,
3988+
agg->unique,
3989+
agg->absent_on_null));
3990+
}
3991+
3992+
/*
3993+
* Transform JSON_ARRAYAGG() aggregate function.
3994+
*
3995+
* JSON_ARRAYAGG() is transformed into json[b]_agg[_strict]() call depending
3996+
* on the output JSON format and absent_on_null. Then the function call result
3997+
* is coerced to the target output type.
3998+
*/
3999+
static Node *
4000+
transformJsonArrayAgg(ParseState *pstate, JsonArrayAgg *agg)
4001+
{
4002+
JsonReturning returning;
4003+
Node *arg;
4004+
Oid aggfnoid;
4005+
Oid aggtype;
4006+
4007+
transformJsonOutput(pstate, agg->ctor.output, true, &returning);
4008+
4009+
arg = transformJsonValueExpr(pstate, agg->arg, JS_FORMAT_DEFAULT);
4010+
4011+
if (returning.format.type == JS_FORMAT_JSONB)
4012+
{
4013+
aggfnoid = agg->absent_on_null ? F_JSONB_AGG_STRICT : F_JSONB_AGG;
4014+
aggtype = JSONBOID;
4015+
}
4016+
else
4017+
{
4018+
aggfnoid = agg->absent_on_null ? F_JSON_AGG_STRICT : F_JSON_AGG;
4019+
aggtype = JSONOID;
4020+
}
4021+
4022+
return transformJsonAggCtor(pstate, &agg->ctor, &returning, list_make1(arg),
4023+
aggfnoid, aggtype, FUNCFMT_JSON_ARRAYAGG,
4024+
makeJsonCtorOpts(&returning,
4025+
false, agg->absent_on_null));
4026+
}
4027+
38604028
/*
38614029
* Transform JSON_ARRAY() constructor.
38624030
*

0 commit comments

Comments
 (0)