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

Commit cd4b585

Browse files
author
Nikita Glukhov
committed
Add JSON_OBJECTAGG() and JSON_ARRAYAGG() transformation
1 parent 1233b33 commit cd4b585

File tree

15 files changed

+853
-76
lines changed

15 files changed

+853
-76
lines changed

src/backend/executor/execExpr.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2138,6 +2138,12 @@ ExecInitExprRec(Expr *node, ExprState *state,
21382138
int nargs = list_length(args);
21392139
int argno = 0;
21402140

2141+
if (ctor->func)
2142+
{
2143+
ExecInitExprRec(ctor->func, state, resv, resnull);
2144+
break;
2145+
}
2146+
21412147
scratch.opcode = EEOP_JSON_CTOR;
21422148
scratch.d.json_ctor.ctor = ctor;
21432149
scratch.d.json_ctor.arg_values = palloc(sizeof(Datum) * nargs);

src/backend/nodes/copyfuncs.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2344,6 +2344,26 @@ _copyJsonObjectCtor(const JsonObjectCtor *from)
23442344
return newnode;
23452345
}
23462346

2347+
/*
2348+
* _copyJsonObjectAgg
2349+
*/
2350+
static JsonObjectAgg *
2351+
_copyJsonObjectAgg(const JsonObjectAgg *from)
2352+
{
2353+
JsonObjectAgg *newnode = makeNode(JsonObjectAgg);
2354+
2355+
COPY_NODE_FIELD(ctor.output);
2356+
COPY_NODE_FIELD(ctor.agg_filter);
2357+
COPY_NODE_FIELD(ctor.agg_order);
2358+
COPY_NODE_FIELD(ctor.over);
2359+
COPY_LOCATION_FIELD(ctor.location);
2360+
COPY_NODE_FIELD(arg);
2361+
COPY_SCALAR_FIELD(absent_on_null);
2362+
COPY_SCALAR_FIELD(unique);
2363+
2364+
return newnode;
2365+
}
2366+
23472367
/*
23482368
* _copyJsonOutput
23492369
*/
@@ -2374,6 +2394,25 @@ _copyJsonArrayCtor(const JsonArrayCtor *from)
23742394
return newnode;
23752395
}
23762396

2397+
/*
2398+
* _copyJsonArrayAgg
2399+
*/
2400+
static JsonArrayAgg *
2401+
_copyJsonArrayAgg(const JsonArrayAgg *from)
2402+
{
2403+
JsonArrayAgg *newnode = makeNode(JsonArrayAgg);
2404+
2405+
COPY_NODE_FIELD(ctor.output);
2406+
COPY_NODE_FIELD(ctor.agg_filter);
2407+
COPY_NODE_FIELD(ctor.agg_order);
2408+
COPY_NODE_FIELD(ctor.over);
2409+
COPY_LOCATION_FIELD(ctor.location);
2410+
COPY_NODE_FIELD(arg);
2411+
COPY_SCALAR_FIELD(absent_on_null);
2412+
2413+
return newnode;
2414+
}
2415+
23772416
/* ****************************************************************
23782417
* pathnodes.h copy functions
23792418
*
@@ -5289,12 +5328,18 @@ copyObjectImpl(const void *from)
52895328
case T_JsonObjectCtor:
52905329
retval = _copyJsonObjectCtor(from);
52915330
break;
5331+
case T_JsonObjectAgg:
5332+
retval = _copyJsonObjectAgg(from);
5333+
break;
52925334
case T_JsonOutput:
52935335
retval = _copyJsonOutput(from);
52945336
break;
52955337
case T_JsonArrayCtor:
52965338
retval = _copyJsonArrayCtor(from);
52975339
break;
5340+
case T_JsonArrayAgg:
5341+
retval = _copyJsonArrayAgg(from);
5342+
break;
52985343

52995344
/*
53005345
* RELATION NODES

src/backend/nodes/nodeFuncs.c

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3254,7 +3254,7 @@ expression_tree_mutator(Node *node,
32543254

32553255
FLATCOPY(newnode, jve, JsonCtorExpr);
32563256
MUTATE(newnode->args, jve->args, List *);
3257-
MUTATE(newnode->func, jve->func, FuncExpr *);
3257+
MUTATE(newnode->func, jve->func, Expr *);
32583258
MUTATE(newnode->returning, jve->returning, JsonReturning *);
32593259

32603260
return (Node *) newnode;
@@ -4020,6 +4020,38 @@ raw_expression_tree_walker(Node *node,
40204020
return true;
40214021
}
40224022
break;
4023+
case T_JsonObjectAgg:
4024+
{
4025+
JsonObjectAgg *joa = (JsonObjectAgg *) node;
4026+
4027+
if (walker(joa->ctor.output, context))
4028+
return true;
4029+
if (walker(joa->ctor.agg_order, context))
4030+
return true;
4031+
if (walker(joa->ctor.agg_filter, context))
4032+
return true;
4033+
if (walker(joa->ctor.over, context))
4034+
return true;
4035+
if (walker(joa->arg, context))
4036+
return true;
4037+
}
4038+
break;
4039+
case T_JsonArrayAgg:
4040+
{
4041+
JsonArrayAgg *jaa = (JsonArrayAgg *) node;
4042+
4043+
if (walker(jaa->ctor.output, context))
4044+
return true;
4045+
if (walker(jaa->ctor.agg_order, context))
4046+
return true;
4047+
if (walker(jaa->ctor.agg_filter, context))
4048+
return true;
4049+
if (walker(jaa->ctor.over, context))
4050+
return true;
4051+
if (walker(jaa->arg, context))
4052+
return true;
4053+
}
4054+
break;
40234055
default:
40244056
elog(ERROR, "unrecognized node type: %d",
40254057
(int) nodeTag(node));

src/backend/parser/parse_expr.c

Lines changed: 177 additions & 1 deletion
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));
@@ -3991,7 +4003,6 @@ transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor)
39914003

39924004
jsctor = makeNode(JsonCtorExpr);
39934005
jsctor->args = args;
3994-
jsctor->func = NULL;
39954006
jsctor->type = JSCTOR_JSON_OBJECT;
39964007
jsctor->returning = transformJsonCtorOutput(pstate, ctor->output, args);
39974008
jsctor->unique = ctor->unique;
@@ -4001,6 +4012,171 @@ transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor)
40014012
return coerceJsonFuncExpr(pstate, (Node *) jsctor, jsctor->returning, true);
40024013
}
40034014

4015+
/*
4016+
* Common code for JSON_OBJECTAGG and JSON_ARRAYAGG transformation.
4017+
*/
4018+
static Node *
4019+
transformJsonAggCtor(ParseState *pstate, JsonAggCtor *agg_ctor,
4020+
JsonReturning *returning, List *args, const char *aggfn,
4021+
Oid aggtype, JsonCtorType ctor_type,
4022+
bool unique, bool absent_on_null)
4023+
{
4024+
Oid aggfnoid;
4025+
JsonCtorExpr *jsctor;
4026+
Node *node;
4027+
Expr *aggfilter = agg_ctor->agg_filter ? (Expr *)
4028+
transformWhereClause(pstate, agg_ctor->agg_filter,
4029+
EXPR_KIND_FILTER, "FILTER") : NULL;
4030+
4031+
aggfnoid = DatumGetInt32(DirectFunctionCall1(regprocin,
4032+
CStringGetDatum(aggfn)));
4033+
4034+
if (agg_ctor->over)
4035+
{
4036+
/* window function */
4037+
WindowFunc *wfunc = makeNode(WindowFunc);
4038+
4039+
wfunc->winfnoid = aggfnoid;
4040+
wfunc->wintype = aggtype;
4041+
/* wincollid and inputcollid will be set by parse_collate.c */
4042+
wfunc->args = args;
4043+
/* winref will be set by transformWindowFuncCall */
4044+
wfunc->winstar = false;
4045+
wfunc->winagg = true;
4046+
wfunc->aggfilter = aggfilter;
4047+
wfunc->location = agg_ctor->location;
4048+
4049+
/*
4050+
* ordered aggs not allowed in windows yet
4051+
*/
4052+
if (agg_ctor->agg_order != NIL)
4053+
ereport(ERROR,
4054+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4055+
errmsg("aggregate ORDER BY is not implemented for window functions"),
4056+
parser_errposition(pstate, agg_ctor->location)));
4057+
4058+
/* parse_agg.c does additional window-func-specific processing */
4059+
transformWindowFuncCall(pstate, wfunc, agg_ctor->over);
4060+
4061+
node = (Node *) wfunc;
4062+
}
4063+
else
4064+
{
4065+
Aggref *aggref = makeNode(Aggref);
4066+
4067+
aggref->aggfnoid = aggfnoid;
4068+
aggref->aggtype = aggtype;
4069+
4070+
/* aggcollid and inputcollid will be set by parse_collate.c */
4071+
aggref->aggtranstype = InvalidOid; /* will be set by planner */
4072+
/* aggargtypes will be set by transformAggregateCall */
4073+
/* aggdirectargs and args will be set by transformAggregateCall */
4074+
/* aggorder and aggdistinct will be set by transformAggregateCall */
4075+
aggref->aggfilter = aggfilter;
4076+
aggref->aggstar = false;
4077+
aggref->aggvariadic = false;
4078+
aggref->aggkind = AGGKIND_NORMAL;
4079+
/* agglevelsup will be set by transformAggregateCall */
4080+
aggref->aggsplit = AGGSPLIT_SIMPLE; /* planner might change this */
4081+
aggref->location = agg_ctor->location;
4082+
4083+
transformAggregateCall(pstate, aggref, args, agg_ctor->agg_order, false);
4084+
4085+
node = (Node *) aggref;
4086+
}
4087+
4088+
jsctor = makeNode(JsonCtorExpr);
4089+
jsctor->func = (Expr *) node;
4090+
jsctor->type = ctor_type;
4091+
jsctor->returning = *returning;
4092+
jsctor->unique = unique;
4093+
jsctor->absent_on_null = absent_on_null;
4094+
jsctor->location = agg_ctor->location;
4095+
4096+
return coerceJsonFuncExpr(pstate, (Node *) jsctor, returning, true);
4097+
}
4098+
4099+
/*
4100+
* Transform JSON_OBJECTAGG() aggregate function.
4101+
*
4102+
* JSON_OBJECTAGG() is transformed into
4103+
* json[b]_objectagg(key, value, absent_on_null, check_unique) call depending on
4104+
* the output JSON format. Then the function call result is coerced to the
4105+
* target output type.
4106+
*/
4107+
static Node *
4108+
transformJsonObjectAgg(ParseState *pstate, JsonObjectAgg *agg)
4109+
{
4110+
JsonReturning returning;
4111+
Node *key;
4112+
Node *val;
4113+
List *args;
4114+
const char *aggfnname;
4115+
Oid aggtype;
4116+
4117+
transformJsonOutput(pstate, agg->ctor.output, true, &returning);
4118+
4119+
key = transformExprRecurse(pstate, (Node *) agg->arg->key);
4120+
val = transformJsonValueExpr(pstate, agg->arg->value, JS_FORMAT_DEFAULT);
4121+
4122+
args = list_make4(key,
4123+
val,
4124+
makeBoolConst(agg->absent_on_null, false),
4125+
makeBoolConst(agg->unique, false));
4126+
4127+
if (returning.format.type == JS_FORMAT_JSONB)
4128+
{
4129+
aggfnname = "pg_catalog.jsonb_objectagg"; /* F_JSONB_OBJECTAGG */
4130+
aggtype = JSONBOID;
4131+
}
4132+
else
4133+
{
4134+
aggfnname = "pg_catalog.json_objectagg"; /* F_JSON_OBJECTAGG; */
4135+
aggtype = JSONOID;
4136+
}
4137+
4138+
return transformJsonAggCtor(pstate, &agg->ctor, &returning, args, aggfnname,
4139+
aggtype, JSCTOR_JSON_OBJECTAGG,
4140+
agg->unique, agg->absent_on_null);
4141+
}
4142+
4143+
/*
4144+
* Transform JSON_ARRAYAGG() aggregate function.
4145+
*
4146+
* JSON_ARRAYAGG() is transformed into json[b]_agg[_strict]() call depending
4147+
* on the output JSON format and absent_on_null. Then the function call result
4148+
* is coerced to the target output type.
4149+
*/
4150+
static Node *
4151+
transformJsonArrayAgg(ParseState *pstate, JsonArrayAgg *agg)
4152+
{
4153+
JsonReturning returning;
4154+
Node *arg;
4155+
const char *aggfnname;
4156+
Oid aggtype;
4157+
4158+
transformJsonOutput(pstate, agg->ctor.output, true, &returning);
4159+
4160+
arg = transformJsonValueExpr(pstate, agg->arg, JS_FORMAT_DEFAULT);
4161+
4162+
if (returning.format.type == JS_FORMAT_JSONB)
4163+
{
4164+
aggfnname = agg->absent_on_null ?
4165+
"pg_catalog.jsonb_agg_strict" : "pg_catalog.jsonb_agg";
4166+
aggtype = JSONBOID;
4167+
}
4168+
else
4169+
{
4170+
aggfnname = agg->absent_on_null ?
4171+
"pg_catalog.json_agg_strict" : "pg_catalog.json_agg";
4172+
aggtype = JSONOID;
4173+
}
4174+
4175+
return transformJsonAggCtor(pstate, &agg->ctor, &returning, list_make1(arg),
4176+
aggfnname, aggtype, JSCTOR_JSON_ARRAYAGG,
4177+
false, agg->absent_on_null);
4178+
}
4179+
40044180
/*
40054181
* Transform JSON_ARRAY() constructor.
40064182
*

src/backend/parser/parse_target.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1937,6 +1937,12 @@ FigureColnameInternal(Node *node, char **name)
19371937
case T_JsonArrayCtor:
19381938
*name = "json_array";
19391939
return 2;
1940+
case T_JsonObjectAgg:
1941+
*name = "json_objectagg";
1942+
return 2;
1943+
case T_JsonArrayAgg:
1944+
*name = "json_arrayagg";
1945+
return 2;
19401946
default:
19411947
break;
19421948
}

0 commit comments

Comments
 (0)