|
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));
|
@@ -3839,6 +3851,148 @@ transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor)
|
3839 | 3851 | true);
|
3840 | 3852 | }
|
3841 | 3853 |
|
| 3854 | +/* |
| 3855 | + * Common code for JSON_OBJECTAGG and JSON_ARRAYAGG transformation. |
| 3856 | + */ |
| 3857 | +static Node * |
| 3858 | +transformJsonAggCtor(ParseState *pstate, JsonAggCtor *agg_ctor, List *args, |
| 3859 | + Oid aggfnoid, Oid aggtype) |
| 3860 | +{ |
| 3861 | + Node *node; |
| 3862 | + Expr *aggfilter = agg_ctor->agg_filter ? (Expr *) |
| 3863 | + transformWhereClause(pstate, agg_ctor->agg_filter, |
| 3864 | + EXPR_KIND_FILTER, "FILTER") : NULL; |
| 3865 | + |
| 3866 | + if (agg_ctor->over) |
| 3867 | + { |
| 3868 | + /* window function */ |
| 3869 | + WindowFunc *wfunc = makeNode(WindowFunc); |
| 3870 | + |
| 3871 | + wfunc->winfnoid = aggfnoid; |
| 3872 | + wfunc->wintype = aggtype; |
| 3873 | + /* wincollid and inputcollid will be set by parse_collate.c */ |
| 3874 | + wfunc->args = args; |
| 3875 | + /* winref will be set by transformWindowFuncCall */ |
| 3876 | + wfunc->winstar = false; |
| 3877 | + wfunc->winagg = true; |
| 3878 | + wfunc->aggfilter = aggfilter; |
| 3879 | + wfunc->location = agg_ctor->location; |
| 3880 | + |
| 3881 | + /* |
| 3882 | + * ordered aggs not allowed in windows yet |
| 3883 | + */ |
| 3884 | + if (agg_ctor->agg_order != NIL) |
| 3885 | + ereport(ERROR, |
| 3886 | + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 3887 | + errmsg("aggregate ORDER BY is not implemented for window functions"), |
| 3888 | + parser_errposition(pstate, agg_ctor->location))); |
| 3889 | + |
| 3890 | + /* parse_agg.c does additional window-func-specific processing */ |
| 3891 | + transformWindowFuncCall(pstate, wfunc, agg_ctor->over); |
| 3892 | + |
| 3893 | + node = (Node *) wfunc; |
| 3894 | + } |
| 3895 | + else |
| 3896 | + { |
| 3897 | + Aggref *aggref = makeNode(Aggref); |
| 3898 | + |
| 3899 | + aggref->aggfnoid = aggfnoid; |
| 3900 | + aggref->aggtype = aggtype; |
| 3901 | + |
| 3902 | + /* aggcollid and inputcollid will be set by parse_collate.c */ |
| 3903 | + aggref->aggtranstype = InvalidOid; /* will be set by planner */ |
| 3904 | + /* aggargtypes will be set by transformAggregateCall */ |
| 3905 | + /* aggdirectargs and args will be set by transformAggregateCall */ |
| 3906 | + /* aggorder and aggdistinct will be set by transformAggregateCall */ |
| 3907 | + aggref->aggfilter = aggfilter; |
| 3908 | + aggref->aggstar = false; |
| 3909 | + aggref->aggvariadic = false; |
| 3910 | + aggref->aggkind = AGGKIND_NORMAL; |
| 3911 | + /* agglevelsup will be set by transformAggregateCall */ |
| 3912 | + aggref->aggsplit = AGGSPLIT_SIMPLE; /* planner might change this */ |
| 3913 | + aggref->location = agg_ctor->location; |
| 3914 | + |
| 3915 | + transformAggregateCall(pstate, aggref, args, agg_ctor->agg_order, false); |
| 3916 | + |
| 3917 | + node = (Node *) aggref; |
| 3918 | + } |
| 3919 | + |
| 3920 | + return coerceJsonFuncExpr(pstate, node, &agg_ctor->output->returning, true); |
| 3921 | +} |
| 3922 | + |
| 3923 | +/* |
| 3924 | + * Transform JSON_OBJECTAGG() aggregate function. |
| 3925 | + * |
| 3926 | + * JSON_OBJECTAGG() is transformed into |
| 3927 | + * json[b]_objectagg(key, value, absent_on_null, check_unique) call depending on |
| 3928 | + * the output JSON format. Then the function call result is coerced to the |
| 3929 | + * target output type. |
| 3930 | + */ |
| 3931 | +static Node * |
| 3932 | +transformJsonObjectAgg(ParseState *pstate, JsonObjectAgg *agg) |
| 3933 | +{ |
| 3934 | + Node *key; |
| 3935 | + Node *val; |
| 3936 | + List *args; |
| 3937 | + Oid aggfnoid; |
| 3938 | + Oid aggtype; |
| 3939 | + |
| 3940 | + transformJsonOutput(pstate, &agg->ctor.output, true); |
| 3941 | + |
| 3942 | + key = transformExprRecurse(pstate, (Node *) agg->arg->key); |
| 3943 | + val = transformJsonValueExpr(pstate, agg->arg->value, JS_FORMAT_DEFAULT); |
| 3944 | + args = list_make4(key, |
| 3945 | + val, |
| 3946 | + makeBoolConst(agg->absent_on_null, false), |
| 3947 | + makeBoolConst(agg->unique, false)); |
| 3948 | + |
| 3949 | + if (agg->ctor.output->returning.format.type == JS_FORMAT_JSONB) |
| 3950 | + { |
| 3951 | + aggfnoid = F_JSONB_OBJECTAGG; |
| 3952 | + aggtype = JSONBOID; |
| 3953 | + } |
| 3954 | + else |
| 3955 | + { |
| 3956 | + aggfnoid = F_JSON_OBJECTAGG; |
| 3957 | + aggtype = JSONOID; |
| 3958 | + } |
| 3959 | + |
| 3960 | + return transformJsonAggCtor(pstate, &agg->ctor, args, aggfnoid, aggtype); |
| 3961 | +} |
| 3962 | + |
| 3963 | +/* |
| 3964 | + * Transform JSON_ARRAYAGG() aggregate function. |
| 3965 | + * |
| 3966 | + * JSON_ARRAYAGG() is transformed into json[b]_agg[_strict]() call depending |
| 3967 | + * on the output JSON format and absent_on_null. Then the function call result |
| 3968 | + * is coerced to the target output type. |
| 3969 | + */ |
| 3970 | +static Node * |
| 3971 | +transformJsonArrayAgg(ParseState *pstate, JsonArrayAgg *agg) |
| 3972 | +{ |
| 3973 | + Node *arg; |
| 3974 | + Oid aggfnoid; |
| 3975 | + Oid aggtype; |
| 3976 | + |
| 3977 | + transformJsonOutput(pstate, &agg->ctor.output, true); |
| 3978 | + |
| 3979 | + arg = transformJsonValueExpr(pstate, agg->arg, JS_FORMAT_DEFAULT); |
| 3980 | + |
| 3981 | + if (agg->ctor.output->returning.format.type == JS_FORMAT_JSONB) |
| 3982 | + { |
| 3983 | + aggfnoid = agg->absent_on_null ? F_JSONB_AGG_STRICT : F_JSONB_AGG; |
| 3984 | + aggtype = JSONBOID; |
| 3985 | + } |
| 3986 | + else |
| 3987 | + { |
| 3988 | + aggfnoid = agg->absent_on_null ? F_JSON_AGG_STRICT : F_JSON_AGG; |
| 3989 | + aggtype = JSONOID; |
| 3990 | + } |
| 3991 | + |
| 3992 | + return transformJsonAggCtor(pstate, &agg->ctor, list_make1(arg), |
| 3993 | + aggfnoid, aggtype); |
| 3994 | +} |
| 3995 | + |
3842 | 3996 | /*
|
3843 | 3997 | * Transform JSON_ARRAY() constructor.
|
3844 | 3998 | *
|
|
0 commit comments