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

Commit dd4ee04

Browse files
author
Nikita Glukhov
committed
Add JSON_OBJECTAGG() and JSON_ARRAYAGG() transformation
1 parent d602634 commit dd4ee04

File tree

9 files changed

+666
-19
lines changed

9 files changed

+666
-19
lines changed

src/backend/nodes/copyfuncs.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2153,6 +2153,26 @@ _copyJsonObjectCtor(const JsonObjectCtor *from)
21532153
return newnode;
21542154
}
21552155

2156+
/*
2157+
* _copyJsonObjectAgg
2158+
*/
2159+
static JsonObjectAgg *
2160+
_copyJsonObjectAgg(const JsonObjectAgg *from)
2161+
{
2162+
JsonObjectAgg *newnode = makeNode(JsonObjectAgg);
2163+
2164+
COPY_NODE_FIELD(ctor.output);
2165+
COPY_NODE_FIELD(ctor.agg_filter);
2166+
COPY_NODE_FIELD(ctor.agg_order);
2167+
COPY_NODE_FIELD(ctor.over);
2168+
COPY_LOCATION_FIELD(ctor.location);
2169+
COPY_NODE_FIELD(arg);
2170+
COPY_SCALAR_FIELD(absent_on_null);
2171+
COPY_SCALAR_FIELD(unique);
2172+
2173+
return newnode;
2174+
}
2175+
21562176
/*
21572177
* _copyJsonArrayCtor
21582178
*/
@@ -2169,6 +2189,25 @@ _copyJsonArrayCtor(const JsonArrayCtor *from)
21692189
return newnode;
21702190
}
21712191

2192+
/*
2193+
* _copyJsonArrayAgg
2194+
*/
2195+
static JsonArrayAgg *
2196+
_copyJsonArrayAgg(const JsonArrayAgg *from)
2197+
{
2198+
JsonArrayAgg *newnode = makeNode(JsonArrayAgg);
2199+
2200+
COPY_NODE_FIELD(ctor.output);
2201+
COPY_NODE_FIELD(ctor.agg_filter);
2202+
COPY_NODE_FIELD(ctor.agg_order);
2203+
COPY_NODE_FIELD(ctor.over);
2204+
COPY_LOCATION_FIELD(ctor.location);
2205+
COPY_NODE_FIELD(arg);
2206+
COPY_SCALAR_FIELD(absent_on_null);
2207+
2208+
return newnode;
2209+
}
2210+
21722211
/* ****************************************************************
21732212
* relation.h copy functions
21742213
*
@@ -5042,9 +5081,15 @@ copyObjectImpl(const void *from)
50425081
case T_JsonObjectCtor:
50435082
retval = _copyJsonObjectCtor(from);
50445083
break;
5084+
case T_JsonObjectAgg:
5085+
retval = _copyJsonObjectAgg(from);
5086+
break;
50455087
case T_JsonArrayCtor:
50465088
retval = _copyJsonArrayCtor(from);
50475089
break;
5090+
case T_JsonArrayAgg:
5091+
retval = _copyJsonArrayAgg(from);
5092+
break;
50485093

50495094
/*
50505095
* RELATION NODES

src/backend/nodes/nodeFuncs.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3713,6 +3713,38 @@ raw_expression_tree_walker(Node *node,
37133713
return true;
37143714
}
37153715
break;
3716+
case T_JsonObjectAgg:
3717+
{
3718+
JsonObjectAgg *joa = (JsonObjectAgg *) node;
3719+
3720+
if (walker(joa->ctor.output, context))
3721+
return true;
3722+
if (walker(joa->ctor.agg_order, context))
3723+
return true;
3724+
if (walker(joa->ctor.agg_filter, context))
3725+
return true;
3726+
if (walker(joa->ctor.over, context))
3727+
return true;
3728+
if (walker(joa->arg, context))
3729+
return true;
3730+
}
3731+
break;
3732+
case T_JsonArrayAgg:
3733+
{
3734+
JsonArrayAgg *jaa = (JsonArrayAgg *) node;
3735+
3736+
if (walker(jaa->ctor.output, context))
3737+
return true;
3738+
if (walker(jaa->ctor.agg_order, context))
3739+
return true;
3740+
if (walker(jaa->ctor.agg_filter, context))
3741+
return true;
3742+
if (walker(jaa->ctor.over, context))
3743+
return true;
3744+
if (walker(jaa->arg, context))
3745+
return true;
3746+
}
3747+
break;
37163748
default:
37173749
elog(ERROR, "unrecognized node type: %d",
37183750
(int) nodeTag(node));

src/backend/parser/parse_expr.c

Lines changed: 154 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));
@@ -3839,6 +3851,148 @@ transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor)
38393851
true);
38403852
}
38413853

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

0 commit comments

Comments
 (0)