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

Commit cb6ae67

Browse files
author
Nikita Glukhov
committed
Add JSON_OBJECTAGG() and JSON_ARRAYAGG() transformation
1 parent 40fa70f commit cb6ae67

File tree

11 files changed

+770
-33
lines changed

11 files changed

+770
-33
lines changed

src/backend/nodes/copyfuncs.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2256,6 +2256,26 @@ _copyJsonCtorOpts(const JsonCtorOpts *from)
22562256
return newnode;
22572257
}
22582258

2259+
/*
2260+
* _copyJsonObjectAgg
2261+
*/
2262+
static JsonObjectAgg *
2263+
_copyJsonObjectAgg(const JsonObjectAgg *from)
2264+
{
2265+
JsonObjectAgg *newnode = makeNode(JsonObjectAgg);
2266+
2267+
COPY_NODE_FIELD(ctor.output);
2268+
COPY_NODE_FIELD(ctor.agg_filter);
2269+
COPY_NODE_FIELD(ctor.agg_order);
2270+
COPY_NODE_FIELD(ctor.over);
2271+
COPY_LOCATION_FIELD(ctor.location);
2272+
COPY_NODE_FIELD(arg);
2273+
COPY_SCALAR_FIELD(absent_on_null);
2274+
COPY_SCALAR_FIELD(unique);
2275+
2276+
return newnode;
2277+
}
2278+
22592279
/*
22602280
* _copyJsonOutput
22612281
*/
@@ -2286,6 +2306,25 @@ _copyJsonArrayCtor(const JsonArrayCtor *from)
22862306
return newnode;
22872307
}
22882308

2309+
/*
2310+
* _copyJsonArrayAgg
2311+
*/
2312+
static JsonArrayAgg *
2313+
_copyJsonArrayAgg(const JsonArrayAgg *from)
2314+
{
2315+
JsonArrayAgg *newnode = makeNode(JsonArrayAgg);
2316+
2317+
COPY_NODE_FIELD(ctor.output);
2318+
COPY_NODE_FIELD(ctor.agg_filter);
2319+
COPY_NODE_FIELD(ctor.agg_order);
2320+
COPY_NODE_FIELD(ctor.over);
2321+
COPY_LOCATION_FIELD(ctor.location);
2322+
COPY_NODE_FIELD(arg);
2323+
COPY_SCALAR_FIELD(absent_on_null);
2324+
2325+
return newnode;
2326+
}
2327+
22892328
/* ****************************************************************
22902329
* relation.h copy functions
22912330
*
@@ -5185,12 +5224,18 @@ copyObjectImpl(const void *from)
51855224
case T_JsonObjectCtor:
51865225
retval = _copyJsonObjectCtor(from);
51875226
break;
5227+
case T_JsonObjectAgg:
5228+
retval = _copyJsonObjectAgg(from);
5229+
break;
51885230
case T_JsonOutput:
51895231
retval = _copyJsonOutput(from);
51905232
break;
51915233
case T_JsonArrayCtor:
51925234
retval = _copyJsonArrayCtor(from);
51935235
break;
5236+
case T_JsonArrayAgg:
5237+
retval = _copyJsonArrayAgg(from);
5238+
break;
51945239

51955240
/*
51965241
* RELATION NODES

src/backend/nodes/nodeFuncs.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3765,6 +3765,38 @@ raw_expression_tree_walker(Node *node,
37653765
return true;
37663766
}
37673767
break;
3768+
case T_JsonObjectAgg:
3769+
{
3770+
JsonObjectAgg *joa = (JsonObjectAgg *) node;
3771+
3772+
if (walker(joa->ctor.output, context))
3773+
return true;
3774+
if (walker(joa->ctor.agg_order, context))
3775+
return true;
3776+
if (walker(joa->ctor.agg_filter, context))
3777+
return true;
3778+
if (walker(joa->ctor.over, context))
3779+
return true;
3780+
if (walker(joa->arg, context))
3781+
return true;
3782+
}
3783+
break;
3784+
case T_JsonArrayAgg:
3785+
{
3786+
JsonArrayAgg *jaa = (JsonArrayAgg *) node;
3787+
3788+
if (walker(jaa->ctor.output, context))
3789+
return true;
3790+
if (walker(jaa->ctor.agg_order, context))
3791+
return true;
3792+
if (walker(jaa->ctor.agg_filter, context))
3793+
return true;
3794+
if (walker(jaa->ctor.over, context))
3795+
return true;
3796+
if (walker(jaa->arg, context))
3797+
return true;
3798+
}
3799+
break;
37683800
default:
37693801
elog(ERROR, "unrecognized node type: %d",
37703802
(int) nodeTag(node));

src/backend/parser/parse_expr.c

Lines changed: 174 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));
@@ -3870,6 +3882,168 @@ transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor)
38703882
return coerceJsonFuncExpr(pstate, (Node *) fexpr, &returning, true);
38713883
}
38723884

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

src/backend/parser/parse_target.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1924,6 +1924,12 @@ FigureColnameInternal(Node *node, char **name)
19241924
case T_JsonArrayCtor:
19251925
*name = "json_array";
19261926
return 2;
1927+
case T_JsonObjectAgg:
1928+
*name = "json_objectagg";
1929+
return 2;
1930+
case T_JsonArrayAgg:
1931+
*name = "json_arrayagg";
1932+
return 2;
19271933
default:
19281934
break;
19291935
}

0 commit comments

Comments
 (0)