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

Commit 59bc00f

Browse files
author
Nikita Glukhov
committed
Add JSON_OBJECTAGG() and JSON_ARRAYAGG() transformation
1 parent 621d6a4 commit 59bc00f

File tree

13 files changed

+773
-38
lines changed

13 files changed

+773
-38
lines changed

src/backend/nodes/copyfuncs.c

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2271,6 +2271,26 @@ _copyJsonCtorOpts(const JsonCtorOpts *from)
22712271
return newnode;
22722272
}
22732273

2274+
/*
2275+
* _copyJsonObjectAgg
2276+
*/
2277+
static JsonObjectAgg *
2278+
_copyJsonObjectAgg(const JsonObjectAgg *from)
2279+
{
2280+
JsonObjectAgg *newnode = makeNode(JsonObjectAgg);
2281+
2282+
COPY_NODE_FIELD(ctor.output);
2283+
COPY_NODE_FIELD(ctor.agg_filter);
2284+
COPY_NODE_FIELD(ctor.agg_order);
2285+
COPY_NODE_FIELD(ctor.over);
2286+
COPY_LOCATION_FIELD(ctor.location);
2287+
COPY_NODE_FIELD(arg);
2288+
COPY_SCALAR_FIELD(absent_on_null);
2289+
COPY_SCALAR_FIELD(unique);
2290+
2291+
return newnode;
2292+
}
2293+
22742294
/*
22752295
* _copyJsonOutput
22762296
*/
@@ -2279,7 +2299,7 @@ _copyJsonOutput(const JsonOutput *from)
22792299
{
22802300
JsonOutput *newnode = makeNode(JsonOutput);
22812301

2282-
COPY_NODE_FIELD(typename);
2302+
COPY_NODE_FIELD(typeName);
22832303
COPY_SCALAR_FIELD(returning);
22842304

22852305
return newnode;
@@ -2301,6 +2321,25 @@ _copyJsonArrayCtor(const JsonArrayCtor *from)
23012321
return newnode;
23022322
}
23032323

2324+
/*
2325+
* _copyJsonArrayAgg
2326+
*/
2327+
static JsonArrayAgg *
2328+
_copyJsonArrayAgg(const JsonArrayAgg *from)
2329+
{
2330+
JsonArrayAgg *newnode = makeNode(JsonArrayAgg);
2331+
2332+
COPY_NODE_FIELD(ctor.output);
2333+
COPY_NODE_FIELD(ctor.agg_filter);
2334+
COPY_NODE_FIELD(ctor.agg_order);
2335+
COPY_NODE_FIELD(ctor.over);
2336+
COPY_LOCATION_FIELD(ctor.location);
2337+
COPY_NODE_FIELD(arg);
2338+
COPY_SCALAR_FIELD(absent_on_null);
2339+
2340+
return newnode;
2341+
}
2342+
23042343
/* ****************************************************************
23052344
* pathnodes.h copy functions
23062345
*
@@ -5214,12 +5253,18 @@ copyObjectImpl(const void *from)
52145253
case T_JsonObjectCtor:
52155254
retval = _copyJsonObjectCtor(from);
52165255
break;
5256+
case T_JsonObjectAgg:
5257+
retval = _copyJsonObjectAgg(from);
5258+
break;
52175259
case T_JsonOutput:
52185260
retval = _copyJsonOutput(from);
52195261
break;
52205262
case T_JsonArrayCtor:
52215263
retval = _copyJsonArrayCtor(from);
52225264
break;
5265+
case T_JsonArrayAgg:
5266+
retval = _copyJsonArrayAgg(from);
5267+
break;
52235268

52245269
/*
52255270
* RELATION NODES

src/backend/nodes/nodeFuncs.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3805,6 +3805,38 @@ raw_expression_tree_walker(Node *node,
38053805
return true;
38063806
}
38073807
break;
3808+
case T_JsonObjectAgg:
3809+
{
3810+
JsonObjectAgg *joa = (JsonObjectAgg *) node;
3811+
3812+
if (walker(joa->ctor.output, context))
3813+
return true;
3814+
if (walker(joa->ctor.agg_order, context))
3815+
return true;
3816+
if (walker(joa->ctor.agg_filter, context))
3817+
return true;
3818+
if (walker(joa->ctor.over, context))
3819+
return true;
3820+
if (walker(joa->arg, context))
3821+
return true;
3822+
}
3823+
break;
3824+
case T_JsonArrayAgg:
3825+
{
3826+
JsonArrayAgg *jaa = (JsonArrayAgg *) node;
3827+
3828+
if (walker(jaa->ctor.output, context))
3829+
return true;
3830+
if (walker(jaa->ctor.agg_order, context))
3831+
return true;
3832+
if (walker(jaa->ctor.agg_filter, context))
3833+
return true;
3834+
if (walker(jaa->ctor.over, context))
3835+
return true;
3836+
if (walker(jaa->arg, context))
3837+
return true;
3838+
}
3839+
break;
38083840
default:
38093841
elog(ERROR, "unrecognized node type: %d",
38103842
(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"
@@ -123,6 +125,8 @@ static Node *transformTypeCast(ParseState *pstate, TypeCast *tc);
123125
static Node *transformCollateClause(ParseState *pstate, CollateClause *c);
124126
static Node *transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor);
125127
static Node *transformJsonArrayCtor(ParseState *pstate, JsonArrayCtor *ctor);
128+
static Node *transformJsonObjectAgg(ParseState *pstate, JsonObjectAgg *agg);
129+
static Node *transformJsonArrayAgg(ParseState *pstate, JsonArrayAgg *agg);
126130
static Node *make_row_comparison_op(ParseState *pstate, List *opname,
127131
List *largs, List *rargs, int location);
128132
static Node *make_row_distinct_op(ParseState *pstate, List *opname,
@@ -379,6 +383,14 @@ transformExprRecurse(ParseState *pstate, Node *expr)
379383
result = transformJsonArrayCtor(pstate, (JsonArrayCtor *) expr);
380384
break;
381385

386+
case T_JsonObjectAgg:
387+
result = transformJsonObjectAgg(pstate, (JsonObjectAgg *) expr);
388+
break;
389+
390+
case T_JsonArrayAgg:
391+
result = transformJsonArrayAgg(pstate, (JsonArrayAgg *) expr);
392+
break;
393+
382394
default:
383395
/* should not reach here */
384396
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
@@ -3958,6 +3970,168 @@ transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor)
39583970
return coerceJsonFuncExpr(pstate, (Node *) fexpr, &returning, true);
39593971
}
39603972

3973+
/*
3974+
* Common code for JSON_OBJECTAGG and JSON_ARRAYAGG transformation.
3975+
*/
3976+
static Node *
3977+
transformJsonAggCtor(ParseState *pstate, JsonAggCtor *agg_ctor,
3978+
JsonReturning *returning, List *args, const char *aggfn,
3979+
Oid aggtype, FuncFormat format, JsonCtorOpts *formatopts)
3980+
{
3981+
Oid aggfnoid;
3982+
Node *node;
3983+
Expr *aggfilter = agg_ctor->agg_filter ? (Expr *)
3984+
transformWhereClause(pstate, agg_ctor->agg_filter,
3985+
EXPR_KIND_FILTER, "FILTER") : NULL;
3986+
3987+
aggfnoid = DatumGetInt32(DirectFunctionCall1(regprocin,
3988+
CStringGetDatum(aggfn)));
3989+
3990+
if (agg_ctor->over)
3991+
{
3992+
/* window function */
3993+
WindowFunc *wfunc = makeNode(WindowFunc);
3994+
3995+
wfunc->winfnoid = aggfnoid;
3996+
wfunc->wintype = aggtype;
3997+
/* wincollid and inputcollid will be set by parse_collate.c */
3998+
wfunc->args = args;
3999+
/* winref will be set by transformWindowFuncCall */
4000+
wfunc->winstar = false;
4001+
wfunc->winagg = true;
4002+
wfunc->aggfilter = aggfilter;
4003+
wfunc->winformat = format;
4004+
wfunc->winformatopts = (Node *) formatopts;
4005+
wfunc->location = agg_ctor->location;
4006+
4007+
/*
4008+
* ordered aggs not allowed in windows yet
4009+
*/
4010+
if (agg_ctor->agg_order != NIL)
4011+
ereport(ERROR,
4012+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4013+
errmsg("aggregate ORDER BY is not implemented for window functions"),
4014+
parser_errposition(pstate, agg_ctor->location)));
4015+
4016+
/* parse_agg.c does additional window-func-specific processing */
4017+
transformWindowFuncCall(pstate, wfunc, agg_ctor->over);
4018+
4019+
node = (Node *) wfunc;
4020+
}
4021+
else
4022+
{
4023+
Aggref *aggref = makeNode(Aggref);
4024+
4025+
aggref->aggfnoid = aggfnoid;
4026+
aggref->aggtype = aggtype;
4027+
4028+
/* aggcollid and inputcollid will be set by parse_collate.c */
4029+
aggref->aggtranstype = InvalidOid; /* will be set by planner */
4030+
/* aggargtypes will be set by transformAggregateCall */
4031+
/* aggdirectargs and args will be set by transformAggregateCall */
4032+
/* aggorder and aggdistinct will be set by transformAggregateCall */
4033+
aggref->aggfilter = aggfilter;
4034+
aggref->aggstar = false;
4035+
aggref->aggvariadic = false;
4036+
aggref->aggkind = AGGKIND_NORMAL;
4037+
/* agglevelsup will be set by transformAggregateCall */
4038+
aggref->aggsplit = AGGSPLIT_SIMPLE; /* planner might change this */
4039+
aggref->aggformat = format;
4040+
aggref->aggformatopts = (Node *) formatopts;
4041+
aggref->location = agg_ctor->location;
4042+
4043+
transformAggregateCall(pstate, aggref, args, agg_ctor->agg_order, false);
4044+
4045+
node = (Node *) aggref;
4046+
}
4047+
4048+
return coerceJsonFuncExpr(pstate, node, returning, true);
4049+
}
4050+
4051+
/*
4052+
* Transform JSON_OBJECTAGG() aggregate function.
4053+
*
4054+
* JSON_OBJECTAGG() is transformed into
4055+
* json[b]_objectagg(key, value, absent_on_null, check_unique) call depending on
4056+
* the output JSON format. Then the function call result is coerced to the
4057+
* target output type.
4058+
*/
4059+
static Node *
4060+
transformJsonObjectAgg(ParseState *pstate, JsonObjectAgg *agg)
4061+
{
4062+
JsonReturning returning;
4063+
Node *key;
4064+
Node *val;
4065+
List *args;
4066+
const char *aggfnname;
4067+
Oid aggtype;
4068+
4069+
transformJsonOutput(pstate, agg->ctor.output, true, &returning);
4070+
4071+
key = transformExprRecurse(pstate, (Node *) agg->arg->key);
4072+
val = transformJsonValueExpr(pstate, agg->arg->value, JS_FORMAT_DEFAULT);
4073+
4074+
args = list_make4(key,
4075+
val,
4076+
makeBoolConst(agg->absent_on_null, false),
4077+
makeBoolConst(agg->unique, false));
4078+
4079+
if (returning.format.type == JS_FORMAT_JSONB)
4080+
{
4081+
aggfnname = "pg_catalog.jsonb_objectagg"; /* F_JSONB_OBJECTAGG */
4082+
aggtype = JSONBOID;
4083+
}
4084+
else
4085+
{
4086+
aggfnname = "pg_catalog.json_objectagg"; /* F_JSON_OBJECTAGG; */
4087+
aggtype = JSONOID;
4088+
}
4089+
4090+
return transformJsonAggCtor(pstate, &agg->ctor, &returning, args, aggfnname,
4091+
aggtype, FUNCFMT_JSON_OBJECTAGG,
4092+
makeJsonCtorOpts(&returning,
4093+
agg->unique,
4094+
agg->absent_on_null));
4095+
}
4096+
4097+
/*
4098+
* Transform JSON_ARRAYAGG() aggregate function.
4099+
*
4100+
* JSON_ARRAYAGG() is transformed into json[b]_agg[_strict]() call depending
4101+
* on the output JSON format and absent_on_null. Then the function call result
4102+
* is coerced to the target output type.
4103+
*/
4104+
static Node *
4105+
transformJsonArrayAgg(ParseState *pstate, JsonArrayAgg *agg)
4106+
{
4107+
JsonReturning returning;
4108+
Node *arg;
4109+
const char *aggfnname;
4110+
Oid aggtype;
4111+
4112+
transformJsonOutput(pstate, agg->ctor.output, true, &returning);
4113+
4114+
arg = transformJsonValueExpr(pstate, agg->arg, JS_FORMAT_DEFAULT);
4115+
4116+
if (returning.format.type == JS_FORMAT_JSONB)
4117+
{
4118+
aggfnname = agg->absent_on_null ?
4119+
"pg_catalog.jsonb_agg_strict" : "pg_catalog.jsonb_agg";
4120+
aggtype = JSONBOID;
4121+
}
4122+
else
4123+
{
4124+
aggfnname = agg->absent_on_null ?
4125+
"pg_catalog.json_agg_strict" : "pg_catalog.json_agg";
4126+
aggtype = JSONOID;
4127+
}
4128+
4129+
return transformJsonAggCtor(pstate, &agg->ctor, &returning, list_make1(arg),
4130+
aggfnname, aggtype, FUNCFMT_JSON_ARRAYAGG,
4131+
makeJsonCtorOpts(&returning,
4132+
false, agg->absent_on_null));
4133+
}
4134+
39614135
/*
39624136
* Transform JSON_ARRAY() constructor.
39634137
*

src/backend/parser/parse_target.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1932,6 +1932,12 @@ FigureColnameInternal(Node *node, char **name)
19321932
case T_JsonArrayCtor:
19331933
*name = "json_array";
19341934
return 2;
1935+
case T_JsonObjectAgg:
1936+
*name = "json_objectagg";
1937+
return 2;
1938+
case T_JsonArrayAgg:
1939+
*name = "json_arrayagg";
1940+
return 2;
19351941
default:
19361942
break;
19371943
}

0 commit comments

Comments
 (0)