|
15 | 15 |
|
16 | 16 | #include "postgres.h"
|
17 | 17 |
|
| 18 | +#include "catalog/pg_aggregate.h" |
| 19 | +#include "catalog/pg_proc.h" |
18 | 20 | #include "catalog/pg_type.h"
|
19 | 21 | #include "commands/dbcommands.h"
|
20 | 22 | #include "miscadmin.h"
|
@@ -123,6 +125,8 @@ static Node *transformTypeCast(ParseState *pstate, TypeCast *tc);
|
123 | 125 | static Node *transformCollateClause(ParseState *pstate, CollateClause *c);
|
124 | 126 | static Node *transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor);
|
125 | 127 | static Node *transformJsonArrayCtor(ParseState *pstate, JsonArrayCtor *ctor);
|
| 128 | +static Node *transformJsonObjectAgg(ParseState *pstate, JsonObjectAgg *agg); |
| 129 | +static Node *transformJsonArrayAgg(ParseState *pstate, JsonArrayAgg *agg); |
126 | 130 | static Node *make_row_comparison_op(ParseState *pstate, List *opname,
|
127 | 131 | List *largs, List *rargs, int location);
|
128 | 132 | static Node *make_row_distinct_op(ParseState *pstate, List *opname,
|
@@ -379,6 +383,14 @@ transformExprRecurse(ParseState *pstate, Node *expr)
|
379 | 383 | result = transformJsonArrayCtor(pstate, (JsonArrayCtor *) expr);
|
380 | 384 | break;
|
381 | 385 |
|
| 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 | + |
382 | 394 | default:
|
383 | 395 | /* should not reach here */
|
384 | 396 | elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
|
@@ -3958,6 +3970,168 @@ transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor)
|
3958 | 3970 | return coerceJsonFuncExpr(pstate, (Node *) fexpr, &returning, true);
|
3959 | 3971 | }
|
3960 | 3972 |
|
| 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 | + |
3961 | 4135 | /*
|
3962 | 4136 | * Transform JSON_ARRAY() constructor.
|
3963 | 4137 | *
|
|
0 commit comments