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

Commit 93cf46c

Browse files
author
Nikita Glukhov
committed
Add JSON_OBJECTAGG() and JSON_ARRAYAGG() transformation
1 parent d0c1cce commit 93cf46c

File tree

8 files changed

+615
-19
lines changed

8 files changed

+615
-19
lines changed

src/backend/nodes/copyfuncs.c

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

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

2191+
/*
2192+
* _copyJsonArrayAgg
2193+
*/
2194+
static JsonArrayAgg *
2195+
_copyJsonArrayAgg(const JsonArrayAgg *from)
2196+
{
2197+
JsonArrayAgg *newnode = makeNode(JsonArrayAgg);
2198+
2199+
COPY_NODE_FIELD(ctor.output);
2200+
COPY_NODE_FIELD(ctor.agg_filter);
2201+
COPY_NODE_FIELD(ctor.agg_order);
2202+
COPY_NODE_FIELD(ctor.over);
2203+
COPY_LOCATION_FIELD(ctor.location);
2204+
COPY_NODE_FIELD(arg);
2205+
COPY_SCALAR_FIELD(absent_on_null);
2206+
2207+
return newnode;
2208+
}
2209+
21712210
/* ****************************************************************
21722211
* relation.h copy functions
21732212
*
@@ -5026,9 +5065,15 @@ copyObjectImpl(const void *from)
50265065
case T_JsonObjectCtor:
50275066
retval = _copyJsonObjectCtor(from);
50285067
break;
5068+
case T_JsonObjectAgg:
5069+
retval = _copyJsonObjectAgg(from);
5070+
break;
50295071
case T_JsonArrayCtor:
50305072
retval = _copyJsonArrayCtor(from);
50315073
break;
5074+
case T_JsonArrayAgg:
5075+
retval = _copyJsonArrayAgg(from);
5076+
break;
50325077

50335078
/*
50345079
* RELATION NODES

src/backend/parser/parse_expr.c

Lines changed: 136 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));
@@ -3728,6 +3740,130 @@ transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor)
37283740
return coerceJsonFuncExpr(pstate, (Node *) fexpr, ctor->output);
37293741
}
37303742

3743+
static Node *
3744+
transformJsonAggCtor(ParseState *pstate, JsonAggCtor *agg_ctor, List *args,
3745+
Oid aggfnoid, Oid aggtype)
3746+
{
3747+
Node *node;
3748+
Expr *aggfilter = agg_ctor->agg_filter ? (Expr *)
3749+
transformWhereClause(pstate, agg_ctor->agg_filter,
3750+
EXPR_KIND_FILTER, "FILTER") : NULL;
3751+
3752+
if (agg_ctor->over)
3753+
{
3754+
/* window function */
3755+
WindowFunc *wfunc = makeNode(WindowFunc);
3756+
3757+
wfunc->winfnoid = aggfnoid;
3758+
wfunc->wintype = aggtype;
3759+
/* wincollid and inputcollid will be set by parse_collate.c */
3760+
wfunc->args = args;
3761+
/* winref will be set by transformWindowFuncCall */
3762+
wfunc->winstar = false;
3763+
wfunc->winagg = true;
3764+
wfunc->aggfilter = aggfilter;
3765+
wfunc->location = agg_ctor->location;
3766+
3767+
/*
3768+
* ordered aggs not allowed in windows yet
3769+
*/
3770+
if (agg_ctor->agg_order != NIL)
3771+
ereport(ERROR,
3772+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3773+
errmsg("aggregate ORDER BY is not implemented for window functions"),
3774+
parser_errposition(pstate, agg_ctor->location)));
3775+
3776+
/* parse_agg.c does additional window-func-specific processing */
3777+
transformWindowFuncCall(pstate, wfunc, agg_ctor->over);
3778+
3779+
node = (Node *) wfunc;
3780+
}
3781+
else
3782+
{
3783+
Aggref *aggref = makeNode(Aggref);
3784+
3785+
aggref->aggfnoid = aggfnoid;
3786+
aggref->aggtype = aggtype;
3787+
3788+
/* aggcollid and inputcollid will be set by parse_collate.c */
3789+
aggref->aggtranstype = InvalidOid; /* will be set by planner */
3790+
/* aggargtypes will be set by transformAggregateCall */
3791+
/* aggdirectargs and args will be set by transformAggregateCall */
3792+
/* aggorder and aggdistinct will be set by transformAggregateCall */
3793+
aggref->aggfilter = aggfilter;
3794+
aggref->aggstar = false;
3795+
aggref->aggvariadic = false;
3796+
aggref->aggkind = AGGKIND_NORMAL;
3797+
/* agglevelsup will be set by transformAggregateCall */
3798+
aggref->aggsplit = AGGSPLIT_SIMPLE; /* planner might change this */
3799+
aggref->location = agg_ctor->location;
3800+
3801+
transformAggregateCall(pstate, aggref, args, agg_ctor->agg_order, false);
3802+
3803+
node = (Node *) aggref;
3804+
}
3805+
3806+
return coerceJsonFuncExpr(pstate, node, agg_ctor->output);
3807+
}
3808+
3809+
static Node *
3810+
transformJsonObjectAgg(ParseState *pstate, JsonObjectAgg *agg)
3811+
{
3812+
Node *key;
3813+
Node *val;
3814+
List *args;
3815+
Oid aggfnoid;
3816+
Oid aggtype;
3817+
3818+
transformJsonOutput(pstate, &agg->ctor.output);
3819+
3820+
key = transformExprRecurse(pstate, (Node *) agg->arg->key);
3821+
val = transformJsonValueExpr(pstate, agg->arg->value, JS_FORMAT_DEFAULT);
3822+
args = list_make4(key,
3823+
val,
3824+
makeBoolConst(agg->absent_on_null, false),
3825+
makeBoolConst(agg->unique, false));
3826+
3827+
if (agg->ctor.output->format.type == JS_FORMAT_JSONB)
3828+
{
3829+
aggfnoid = F_JSONB_OBJECTAGG;
3830+
aggtype = JSONBOID;
3831+
}
3832+
else
3833+
{
3834+
aggfnoid = F_JSON_OBJECTAGG;
3835+
aggtype = JSONOID;
3836+
}
3837+
3838+
return transformJsonAggCtor(pstate, &agg->ctor, args, aggfnoid, aggtype);
3839+
}
3840+
3841+
static Node *
3842+
transformJsonArrayAgg(ParseState *pstate, JsonArrayAgg *agg)
3843+
{
3844+
Node *arg;
3845+
Oid aggfnoid;
3846+
Oid aggtype;
3847+
3848+
transformJsonOutput(pstate, &agg->ctor.output);
3849+
3850+
arg = transformJsonValueExpr(pstate, agg->arg, JS_FORMAT_DEFAULT);
3851+
3852+
if (agg->ctor.output->format.type == JS_FORMAT_JSONB)
3853+
{
3854+
aggfnoid = agg->absent_on_null ? F_JSONB_AGG_STRICT : F_JSONB_AGG;
3855+
aggtype = JSONBOID;
3856+
}
3857+
else
3858+
{
3859+
aggfnoid = agg->absent_on_null ? F_JSON_AGG_STRICT : F_JSON_AGG;
3860+
aggtype = JSONOID;
3861+
}
3862+
3863+
return transformJsonAggCtor(pstate, &agg->ctor, list_make1(arg),
3864+
aggfnoid, aggtype);
3865+
}
3866+
37313867
static Node *
37323868
transformJsonArrayCtor(ParseState *pstate, JsonArrayCtor *ctor)
37333869
{

0 commit comments

Comments
 (0)