|
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"
|
@@ -124,6 +126,8 @@ static Node *transformTypeCast(ParseState *pstate, TypeCast *tc);
|
124 | 126 | static Node *transformCollateClause(ParseState *pstate, CollateClause *c);
|
125 | 127 | static Node *transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor);
|
126 | 128 | static Node *transformJsonArrayCtor(ParseState *pstate, JsonArrayCtor *ctor);
|
| 129 | +static Node *transformJsonObjectAgg(ParseState *pstate, JsonObjectAgg *agg); |
| 130 | +static Node *transformJsonArrayAgg(ParseState *pstate, JsonArrayAgg *agg); |
127 | 131 | static Node *make_row_comparison_op(ParseState *pstate, List *opname,
|
128 | 132 | List *largs, List *rargs, int location);
|
129 | 133 | static Node *make_row_distinct_op(ParseState *pstate, List *opname,
|
@@ -380,6 +384,14 @@ transformExprRecurse(ParseState *pstate, Node *expr)
|
380 | 384 | result = transformJsonArrayCtor(pstate, (JsonArrayCtor *) expr);
|
381 | 385 | break;
|
382 | 386 |
|
| 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 | + |
383 | 395 | default:
|
384 | 396 | /* should not reach here */
|
385 | 397 | elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
|
@@ -3870,6 +3882,168 @@ transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor)
|
3870 | 3882 | return coerceJsonFuncExpr(pstate, (Node *) fexpr, &returning, true);
|
3871 | 3883 | }
|
3872 | 3884 |
|
| 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 | + |
3873 | 4047 | /*
|
3874 | 4048 | * Transform JSON_ARRAY() constructor.
|
3875 | 4049 | *
|
|
0 commit comments