public inbox for [email protected]
help / color / mirror / Atom feedFrom: [email protected] <[email protected]>
To: Bruce Momjian <[email protected]>
Cc: PostgreSQL-development <[email protected]>
Cc: Finnerty, Jim <[email protected]>
Cc: Andres Freund <[email protected]>
Cc: Tom Lane <[email protected]>
Cc: Tomas Vondra <[email protected]>
Cc: Julien Rouhaud <[email protected]>
Cc: Daniel Gustafsson <[email protected]>
Cc: Alexander Pyhalov <[email protected]>
Cc: [email protected] <[email protected]>
Subject: RE: Partial aggregates pushdown
Date: Fri, 27 Oct 2023 05:32:48 +0000
Message-ID: <TYTPR01MB10954B96601911FE868BF88E895DCA@TYTPR01MB10954.jpnprd01.prod.outlook.com> (raw)
In-Reply-To: <[email protected]>
References: <OS3PR01MB6660E61EB659850022B9607195C1A@OS3PR01MB6660.jpnprd01.prod.outlook.com>
<[email protected]>
<OS3PR01MB66601F4809974F6A8275131195C1A@OS3PR01MB6660.jpnprd01.prod.outlook.com>
<TY3PR01MB10956C71BF25436F242C9829795D5A@TY3PR01MB10956.jpnprd01.prod.outlook.com>
<[email protected]>
<TYTPR01MB1095486F5E3103D783AF4748995DFA@TYTPR01MB10954.jpnprd01.prod.outlook.com>
<[email protected]>
<TYTPR01MB10954D890D8F729E1BCE42D4F95DDA@TYTPR01MB10954.jpnprd01.prod.outlook.com>
<[email protected]>
<TYTPR01MB10954B4C9A791FA9D2BF692F095DCA@TYTPR01MB10954.jpnprd01.prod.outlook.com>
<[email protected]>
Hi Mr.Momjian.
> From: Bruce Momjian <[email protected]>
> Sent: Friday, October 27, 2023 12:06 PM
> > Thank you for your improvement.
> > As a matter of detail, I think that the areas marked below are erroneous.
> >
> > --
> > + Pushdown causes aggregate function cals to send partial aggregate
> > ^
> > + function calls to the remote server. If the partial aggregate
> > + function doesn't doesn't exist on the remote server, it causes
> > ^^^^^^^
> > --
>
> Agreed. Do you want to fix that on your vesion? I don't have any more improvements to make.
Yes, I have fixed that in v32(Attached).
> > > What else needs to be done before committers start to review this?
> > There are no others. May I make a new version of v31 with your
> > suggested improvements for the committer's review?
>
> Yes, please. I think the updated docs will help people understand how the patch works.
Thank you. v32(Attached) is tha updated version.
Sincerely yours,
Yuuki Fujii
--
Yuuki Fujii
Information Technology R&D Center Mitsubishi Electric Corporation
Attachments:
[application/octet-stream] 0001-Partial-aggregates-push-down-v32.patch (265.9K, ../TYTPR01MB10954B96601911FE868BF88E895DCA@TYTPR01MB10954.jpnprd01.prod.outlook.com/2-0001-Partial-aggregates-push-down-v32.patch)
download | inline diff:
From 44915ac8f5b56b0ef5cdba217e727e2c729aa64a Mon Sep 17 00:00:00 2001
From: Yuki Fujii <[email protected]>
Date: Fri, 27 Oct 2023 09:47:28 -0400
Subject: [PATCH] Partial aggregates push down v32
---
contrib/postgres_fdw/deparse.c | 113 ++-
.../postgres_fdw/expected/postgres_fdw.out | 868 +++++++++++++++++-
contrib/postgres_fdw/option.c | 4 +-
contrib/postgres_fdw/postgres_fdw.c | 47 +-
contrib/postgres_fdw/postgres_fdw.h | 10 +
contrib/postgres_fdw/sql/postgres_fdw.sql | 311 ++++++-
doc/src/sgml/catalogs.sgml | 12 +
doc/src/sgml/postgres-fdw.sgml | 130 ++-
doc/src/sgml/ref/create_aggregate.sgml | 34 +
doc/src/sgml/xaggr.sgml | 11 +-
src/backend/catalog/pg_aggregate.c | 101 ++
src/backend/commands/aggregatecmds.c | 4 +
src/backend/optimizer/plan/planner.c | 133 ++-
src/bin/pg_dump/pg_dump.c | 16 +-
src/include/catalog/pg_aggregate.dat | 680 +++++++++++---
src/include/catalog/pg_aggregate.h | 4 +
src/include/catalog/pg_proc.dat | 196 ++++
src/include/nodes/pathnodes.h | 5 +
.../regress/expected/create_aggregate.out | 184 ++++
src/test/regress/expected/oidjoins.out | 1 +
src/test/regress/sql/create_aggregate.sql | 183 ++++
21 files changed, 2824 insertions(+), 223 deletions(-)
diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c
index 09fd489a90..c443f8974a 100644
--- a/contrib/postgres_fdw/deparse.c
+++ b/contrib/postgres_fdw/deparse.c
@@ -202,7 +202,7 @@ static bool is_subquery_var(Var *node, RelOptInfo *foreignrel,
int *relno, int *colno);
static void get_relation_column_alias_ids(Var *node, RelOptInfo *foreignrel,
int *relno, int *colno);
-
+static bool partial_agg_ok(Aggref *agg, PgFdwRelationInfo *fpinfo);
/*
* Examine each qual clause in input_conds, and classify them into two groups,
@@ -907,8 +907,9 @@ foreign_expr_walker(Node *node,
if (!IS_UPPER_REL(glob_cxt->foreignrel))
return false;
- /* Only non-split aggregates are pushable. */
- if (agg->aggsplit != AGGSPLIT_SIMPLE)
+ if (agg->aggsplit != AGGSPLIT_SIMPLE && agg->aggsplit != AGGSPLIT_INITIAL_SERIAL)
+ return false;
+ if (agg->aggsplit == AGGSPLIT_INITIAL_SERIAL && !partial_agg_ok(agg, fpinfo))
return false;
/* As usual, it must be shippable. */
@@ -3517,14 +3518,34 @@ deparseAggref(Aggref *node, deparse_expr_cxt *context)
StringInfo buf = context->buf;
bool use_variadic;
- /* Only basic, non-split aggregation accepted. */
- Assert(node->aggsplit == AGGSPLIT_SIMPLE);
+
+ Assert((node->aggsplit == AGGSPLIT_SIMPLE) ||
+ (node->aggsplit == AGGSPLIT_INITIAL_SERIAL));
/* Check if need to print VARIADIC (cf. ruleutils.c) */
use_variadic = node->aggvariadic;
- /* Find aggregate name from aggfnoid which is a pg_proc entry */
- appendFunctionName(node->aggfnoid, context);
+ if (node->aggsplit == AGGSPLIT_SIMPLE)
+ /* Find aggregate name from aggfnoid which is a pg_proc entry */
+ appendFunctionName(node->aggfnoid, context);
+ else
+ {
+ HeapTuple aggtup;
+ Form_pg_aggregate aggform;
+
+ /* Find aggregate name from aggfnoid and aggpartialfn */
+ aggtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(node->aggfnoid));
+ if (!HeapTupleIsValid(aggtup))
+ elog(ERROR, "cache lookup failed for aggregate %u", node->aggfnoid);
+ aggform = (Form_pg_aggregate) GETSTRUCT(aggtup);
+
+ if (aggform->aggpartialfn)
+ appendFunctionName(aggform->aggpartialfn, context);
+ else
+ elog(ERROR, "there is no aggpartialfn %u", node->aggfnoid);
+ ReleaseSysCache(aggtup);
+ }
+
appendStringInfoChar(buf, '(');
/* Add DISTINCT */
@@ -3723,6 +3744,7 @@ appendGroupByClause(List *tlist, deparse_expr_cxt *context)
Query *query = context->root->parse;
ListCell *lc;
bool first = true;
+ PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) context->foreignrel->fdw_private;
/* Nothing to be done, if there's no GROUP BY clause in the query. */
if (!query->groupClause)
@@ -3743,7 +3765,7 @@ appendGroupByClause(List *tlist, deparse_expr_cxt *context)
* to empty, and in any case the redundancy situation on the remote might
* be different than what we think here.
*/
- foreach(lc, query->groupClause)
+ foreach(lc, fpinfo->group_clause)
{
SortGroupClause *grp = (SortGroupClause *) lfirst(lc);
@@ -4047,3 +4069,78 @@ get_relation_column_alias_ids(Var *node, RelOptInfo *foreignrel,
/* Shouldn't get here */
elog(ERROR, "unexpected expression in subquery output");
}
+
+/*
+ * Can we assume a buit-in aggpartialfunc exists on the remote server? If
+ * check_partial_aggregate_support is false, we assume the partial aggregate
+ * function exists on the remote server. If true, we assume the partial
+ * aggregate function exists on the remote server if the aggregate is so
+ * simple that the local aggregate's OID and its partial aggregate function
+ * OID are the same. If not, we check the remote server version and assume
+ * the remote partial aggregate function exists if the remote server version
+ * is equal to or greater than the local server version.
+ */
+static bool
+is_builtin_aggpartialfunc_shippable(Form_pg_aggregate aggform,
+ PgFdwRelationInfo *fpinfo)
+{
+ bool shippable = true;
+
+ /* So simple, we assume it exists. */
+ if (aggform->aggfnoid != aggform->aggpartialfn &&
+ fpinfo->check_partial_aggregate_support)
+ {
+ if (fpinfo->remoteversion == 0)
+ {
+ PGconn *conn = GetConnection(fpinfo->user, false, NULL);
+
+ fpinfo->remoteversion = PQserverVersion(conn);
+ }
+
+ if (fpinfo->remoteversion < PG_VERSION_NUM)
+ shippable = false;
+ }
+
+ return shippable;
+}
+
+/*
+ * ----------
+ * Check that partial aggregate "agg" is safe to push down.
+ *
+ * It is pushdown-safe when all of the following conditions are true:
+ *
+ * * agg is an AGGKIND_NORMAL aggregate which contains no DISTINCT or
+ * ORDER BY clauses
+ * * There is a local aggregate function for partial aggregation
+ * (aggpartialfunc) and it is assumed to exist on the remote server
+ * ----------
+ */
+static bool
+partial_agg_ok(Aggref *agg, PgFdwRelationInfo *fpinfo)
+{
+ HeapTuple aggtup;
+ Form_pg_aggregate aggform;
+ bool partial_agg_ok = true;
+
+ Assert(agg->aggsplit == AGGSPLIT_INITIAL_SERIAL);
+
+ /* We don't support complex partial aggregates */
+ if (agg->aggdistinct || agg->aggkind != AGGKIND_NORMAL || agg->aggorder != NIL)
+ return false;
+
+ aggtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(agg->aggfnoid));
+ if (!HeapTupleIsValid(aggtup))
+ elog(ERROR, "cache lookup failed for aggregate %u", agg->aggfnoid);
+ aggform = (Form_pg_aggregate) GETSTRUCT(aggtup);
+
+ if (!aggform->aggpartialfn)
+ partial_agg_ok = false;
+ else if (is_builtin(aggform->aggpartialfn))
+ partial_agg_ok = is_builtin_aggpartialfunc_shippable(aggform, fpinfo);
+ else if (!is_shippable(aggform->aggpartialfn, ProcedureRelationId, fpinfo))
+ partial_agg_ok = false;
+
+ ReleaseSysCache(aggtup);
+ return partial_agg_ok;
+}
diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 144c114d0f..d9febca7a0 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -9758,18 +9758,35 @@ RESET enable_partitionwise_join;
-- ===================================================================
-- test partitionwise aggregates
-- ===================================================================
-CREATE TABLE pagg_tab (a int, b int, c text) PARTITION BY RANGE(a);
+ALTER SERVER loopback OPTIONS (ADD fdw_tuple_cost '0.1');
+CREATE TYPE mood AS enum ('sad', 'ok', 'happy');
+ALTER EXTENSION postgres_fdw ADD TYPE mood;
+CREATE TABLE pagg_tab (a int, b int, c text, c_serial int4,
+ c_int4array _int4, c_interval interval,
+ c_money money, c_1c text, c_1b bytea,
+ c_bit bit(2), c_1or3int2 int2,
+ c_1or3int4 int4, c_1or3int8 int8,
+ c_bool bool, c_enum mood, c_pg_lsn pg_lsn,
+ c_tid tid, c_int4range int4range,
+ c_int4multirange int4multirange,
+ c_time time, c_timetz timetz,
+ c_timestamp timestamp, c_timestamptz timestamptz,
+ c_xid8 xid8)
+ PARTITION BY RANGE(a);
CREATE TABLE pagg_tab_p1 (LIKE pagg_tab);
CREATE TABLE pagg_tab_p2 (LIKE pagg_tab);
CREATE TABLE pagg_tab_p3 (LIKE pagg_tab);
-INSERT INTO pagg_tab_p1 SELECT i % 30, i % 50, to_char(i/30, 'FM0000') FROM generate_series(1, 3000) i WHERE (i % 30) < 10;
-INSERT INTO pagg_tab_p2 SELECT i % 30, i % 50, to_char(i/30, 'FM0000') FROM generate_series(1, 3000) i WHERE (i % 30) < 20 and (i % 30) >= 10;
-INSERT INTO pagg_tab_p3 SELECT i % 30, i % 50, to_char(i/30, 'FM0000') FROM generate_series(1, 3000) i WHERE (i % 30) < 30 and (i % 30) >= 20;
+INSERT INTO pagg_tab_p1 SELECT i % 30, i % 50, to_char(i/30, 'FM0000'), i, array[(i % 2), 0], ((i % 2) || ' seconds')::interval, (i % 2)::money, ((i - 1) % 10)::text, (((i - 1) % 10)::text)::bytea, case when (i % 2) = 0 then B'01' else B'11' end, case when (i % 2) = 0 then 1 else 3 end, case when (i % 2) = 0 then 1 else 3 end, case when (i % 2) = 0 then 1 else 3 end, case when (i % 2) = 0 then true else false end, (case when (i % 2) = 0 then 'sad' else 'happy' end)::mood, ('0/' || i)::pg_lsn, ('(0,' || i || ')')::tid, int4range(0, i), int4multirange(int4range(0, i), int4range(100, 100 + i)), '00:00:00'::time + (i || ' seconds')::interval, '00:00:00'::timetz + (i || ' seconds')::interval, '2000-01-01'::timestamp + (i || ' seconds')::interval, '2000-01-01'::timestamptz + (i || ' seconds')::interval, ((i % 10)::text)::xid8 FROM generate_series(1, 3000) i WHERE (i % 30) < 10;
+INSERT INTO pagg_tab_p2 SELECT i % 30, i % 50, to_char(i/30, 'FM0000'), i, array[(i % 2), 0], ((i % 2) || ' seconds')::interval, (i % 2)::money, ((i - 1) % 10)::text, (((i - 1) % 10)::text)::bytea, case when (i % 2) = 0 then B'01' else B'11' end, case when (i % 2) = 0 then 1 else 3 end, case when (i % 2) = 0 then 1 else 3 end, case when (i % 2) = 0 then 1 else 3 end, case when (i % 2) = 0 then true else false end, (case when (i % 2) = 0 then 'sad' else 'happy' end)::mood, ('0/' || i)::pg_lsn, ('(0,' || i || ')')::tid, int4range(0, i), int4multirange(int4range(0, i), int4range(100, 100 + i)), '00:00:00'::time + (i || ' seconds')::interval, '00:00:00'::timetz + (i || ' seconds')::interval, '2000-01-01'::timestamp + (i || ' seconds')::interval, '2000-01-01'::timestamptz + (i || ' seconds')::interval, ((i % 10)::text)::xid8 FROM generate_series(1, 3000) i WHERE (i % 30) < 20 and (i % 30) >= 10;
+INSERT INTO pagg_tab_p3 SELECT i % 30, i % 50, to_char(i/30, 'FM0000'), i, array[(i % 2), 0], ((i % 2) || ' seconds')::interval, (i % 2)::money, ((i - 1) % 10)::text, (((i - 1) % 10)::text)::bytea, case when (i % 2) = 0 then B'01' else B'11' end, case when (i % 2) = 0 then 1 else 3 end, case when (i % 2) = 0 then 1 else 3 end, case when (i % 2) = 0 then 1 else 3 end, case when (i % 2) = 0 then true else false end, (case when (i % 2) = 0 then 'sad' else 'happy' end)::mood, ('0/' || i)::pg_lsn, ('(0,' || i || ')')::tid, int4range(0, i), int4multirange(int4range(0, i), int4range(100, 100 + i)), '00:00:00'::time + (i || ' seconds')::interval, '00:00:00'::timetz + (i || ' seconds')::interval, '2000-01-01'::timestamp + (i || ' seconds')::interval, '2000-01-01'::timestamptz + (i || ' seconds')::interval, ((i % 10)::text)::xid8 FROM generate_series(1, 3000) i WHERE (i % 30) < 30 and (i % 30) >= 20;
-- Create foreign partitions
CREATE FOREIGN TABLE fpagg_tab_p1 PARTITION OF pagg_tab FOR VALUES FROM (0) TO (10) SERVER loopback OPTIONS (table_name 'pagg_tab_p1');
CREATE FOREIGN TABLE fpagg_tab_p2 PARTITION OF pagg_tab FOR VALUES FROM (10) TO (20) SERVER loopback OPTIONS (table_name 'pagg_tab_p2');
CREATE FOREIGN TABLE fpagg_tab_p3 PARTITION OF pagg_tab FOR VALUES FROM (20) TO (30) SERVER loopback OPTIONS (table_name 'pagg_tab_p3');
ANALYZE pagg_tab;
+ANALYZE pagg_tab_p1;
+ANALYZE pagg_tab_p2;
+ANALYZE pagg_tab_p3;
ANALYZE fpagg_tab_p1;
ANALYZE fpagg_tab_p2;
ANALYZE fpagg_tab_p3;
@@ -9823,8 +9840,8 @@ SELECT a, sum(b), min(b), count(*) FROM pagg_tab GROUP BY a HAVING avg(b) < 22 O
-- Should have all the columns in the target list for the given relation
EXPLAIN (VERBOSE, COSTS OFF)
SELECT a, count(t1) FROM pagg_tab t1 GROUP BY a HAVING avg(b) < 22 ORDER BY 1;
- QUERY PLAN
-------------------------------------------------------------------------
+ QUERY PLAN
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Sort
Output: t1.a, (count(((t1.*)::pagg_tab)))
Sort Key: t1.a
@@ -9835,21 +9852,21 @@ SELECT a, count(t1) FROM pagg_tab t1 GROUP BY a HAVING avg(b) < 22 ORDER BY 1;
Filter: (avg(t1.b) < '22'::numeric)
-> Foreign Scan on public.fpagg_tab_p1 t1
Output: t1.a, t1.*, t1.b
- Remote SQL: SELECT a, b, c FROM public.pagg_tab_p1
+ Remote SQL: SELECT a, b, c, c_serial, c_int4array, c_interval, c_money, c_1c, c_1b, c_bit, c_1or3int2, c_1or3int4, c_1or3int8, c_bool, c_enum, c_pg_lsn, c_tid, c_int4range, c_int4multirange, c_time, c_timetz, c_timestamp, c_timestamptz, c_xid8 FROM public.pagg_tab_p1
-> HashAggregate
Output: t1_1.a, count(((t1_1.*)::pagg_tab))
Group Key: t1_1.a
Filter: (avg(t1_1.b) < '22'::numeric)
-> Foreign Scan on public.fpagg_tab_p2 t1_1
Output: t1_1.a, t1_1.*, t1_1.b
- Remote SQL: SELECT a, b, c FROM public.pagg_tab_p2
+ Remote SQL: SELECT a, b, c, c_serial, c_int4array, c_interval, c_money, c_1c, c_1b, c_bit, c_1or3int2, c_1or3int4, c_1or3int8, c_bool, c_enum, c_pg_lsn, c_tid, c_int4range, c_int4multirange, c_time, c_timetz, c_timestamp, c_timestamptz, c_xid8 FROM public.pagg_tab_p2
-> HashAggregate
Output: t1_2.a, count(((t1_2.*)::pagg_tab))
Group Key: t1_2.a
Filter: (avg(t1_2.b) < '22'::numeric)
-> Foreign Scan on public.fpagg_tab_p3 t1_2
Output: t1_2.a, t1_2.*, t1_2.b
- Remote SQL: SELECT a, b, c FROM public.pagg_tab_p3
+ Remote SQL: SELECT a, b, c, c_serial, c_int4array, c_interval, c_money, c_1c, c_1b, c_bit, c_1or3int2, c_1or3int4, c_1or3int8, c_bool, c_enum, c_pg_lsn, c_tid, c_int4range, c_int4multirange, c_time, c_timetz, c_timestamp, c_timestamptz, c_xid8 FROM public.pagg_tab_p3
(25 rows)
SELECT a, count(t1) FROM pagg_tab t1 GROUP BY a HAVING avg(b) < 22 ORDER BY 1;
@@ -9863,28 +9880,837 @@ SELECT a, count(t1) FROM pagg_tab t1 GROUP BY a HAVING avg(b) < 22 ORDER BY 1;
21 | 100
(6 rows)
--- When GROUP BY clause does not match with PARTITION KEY.
-EXPLAIN (COSTS OFF)
+-- Partial aggregates are unsafe to push down when there is a HAVING clause
+EXPLAIN (VERBOSE, COSTS OFF)
SELECT b, avg(a), max(a), count(*) FROM pagg_tab GROUP BY b HAVING sum(a) < 700 ORDER BY 1;
- QUERY PLAN
------------------------------------------------------------------
- Sort
- Sort Key: pagg_tab.b
- -> Finalize HashAggregate
- Group Key: pagg_tab.b
- Filter: (sum(pagg_tab.a) < 700)
+ QUERY PLAN
+---------------------------------------------------------------------------------------------------------------------------------------------
+ Finalize GroupAggregate
+ Output: pagg_tab.b, avg(pagg_tab.a), max(pagg_tab.a), count(*)
+ Group Key: pagg_tab.b
+ Filter: (sum(pagg_tab.a) < 700)
+ -> Sort
+ Output: pagg_tab.b, (PARTIAL avg(pagg_tab.a)), (PARTIAL max(pagg_tab.a)), (PARTIAL count(*)), (PARTIAL sum(pagg_tab.a))
+ Sort Key: pagg_tab.b
-> Append
-> Partial HashAggregate
+ Output: pagg_tab.b, PARTIAL avg(pagg_tab.a), PARTIAL max(pagg_tab.a), PARTIAL count(*), PARTIAL sum(pagg_tab.a)
Group Key: pagg_tab.b
- -> Foreign Scan on fpagg_tab_p1 pagg_tab
+ -> Foreign Scan on public.fpagg_tab_p1 pagg_tab
+ Output: pagg_tab.b, pagg_tab.a
+ Remote SQL: SELECT a, b FROM public.pagg_tab_p1
-> Partial HashAggregate
+ Output: pagg_tab_1.b, PARTIAL avg(pagg_tab_1.a), PARTIAL max(pagg_tab_1.a), PARTIAL count(*), PARTIAL sum(pagg_tab_1.a)
Group Key: pagg_tab_1.b
- -> Foreign Scan on fpagg_tab_p2 pagg_tab_1
+ -> Foreign Scan on public.fpagg_tab_p2 pagg_tab_1
+ Output: pagg_tab_1.b, pagg_tab_1.a
+ Remote SQL: SELECT a, b FROM public.pagg_tab_p2
-> Partial HashAggregate
+ Output: pagg_tab_2.b, PARTIAL avg(pagg_tab_2.a), PARTIAL max(pagg_tab_2.a), PARTIAL count(*), PARTIAL sum(pagg_tab_2.a)
Group Key: pagg_tab_2.b
- -> Foreign Scan on fpagg_tab_p3 pagg_tab_2
+ -> Foreign Scan on public.fpagg_tab_p3 pagg_tab_2
+ Output: pagg_tab_2.b, pagg_tab_2.a
+ Remote SQL: SELECT a, b FROM public.pagg_tab_p3
+(26 rows)
+
+SELECT b, avg(a), max(a), count(*) FROM pagg_tab GROUP BY b HAVING sum(a) < 700 ORDER BY 1;
+ b | avg | max | count
+----+---------------------+-----+-------
+ 0 | 10.0000000000000000 | 20 | 60
+ 1 | 11.0000000000000000 | 21 | 60
+ 10 | 10.0000000000000000 | 20 | 60
+ 11 | 11.0000000000000000 | 21 | 60
+ 20 | 10.0000000000000000 | 20 | 60
+ 21 | 11.0000000000000000 | 21 | 60
+ 30 | 10.0000000000000000 | 20 | 60
+ 31 | 11.0000000000000000 | 21 | 60
+ 40 | 10.0000000000000000 | 20 | 60
+ 41 | 11.0000000000000000 | 21 | 60
+(10 rows)
+
+-- Partial aggregates are safe to push down without having clause
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT b, avg(a), max(a), count(*) FROM pagg_tab GROUP BY b ORDER BY 1;
+ QUERY PLAN
+------------------------------------------------------------------------------------------------------------------------
+ Sort
+ Output: pagg_tab.b, (avg(pagg_tab.a)), (max(pagg_tab.a)), (count(*))
+ Sort Key: pagg_tab.b
+ -> Finalize HashAggregate
+ Output: pagg_tab.b, avg(pagg_tab.a), max(pagg_tab.a), count(*)
+ Group Key: pagg_tab.b
+ -> Append
+ -> Foreign Scan
+ Output: pagg_tab.b, (PARTIAL avg(pagg_tab.a)), (PARTIAL max(pagg_tab.a)), (PARTIAL count(*))
+ Relations: Aggregate on (public.fpagg_tab_p1 pagg_tab)
+ Remote SQL: SELECT b, avg_p_int4(a), max(a), count(*) FROM public.pagg_tab_p1 GROUP BY 1
+ -> Foreign Scan
+ Output: pagg_tab_1.b, (PARTIAL avg(pagg_tab_1.a)), (PARTIAL max(pagg_tab_1.a)), (PARTIAL count(*))
+ Relations: Aggregate on (public.fpagg_tab_p2 pagg_tab_1)
+ Remote SQL: SELECT b, avg_p_int4(a), max(a), count(*) FROM public.pagg_tab_p2 GROUP BY 1
+ -> Foreign Scan
+ Output: pagg_tab_2.b, (PARTIAL avg(pagg_tab_2.a)), (PARTIAL max(pagg_tab_2.a)), (PARTIAL count(*))
+ Relations: Aggregate on (public.fpagg_tab_p3 pagg_tab_2)
+ Remote SQL: SELECT b, avg_p_int4(a), max(a), count(*) FROM public.pagg_tab_p3 GROUP BY 1
+(19 rows)
+
+SELECT b, avg(a), max(a), count(*) FROM pagg_tab GROUP BY b ORDER BY 1;
+ b | avg | max | count
+----+---------------------+-----+-------
+ 0 | 10.0000000000000000 | 20 | 60
+ 1 | 11.0000000000000000 | 21 | 60
+ 2 | 12.0000000000000000 | 22 | 60
+ 3 | 13.0000000000000000 | 23 | 60
+ 4 | 14.0000000000000000 | 24 | 60
+ 5 | 15.0000000000000000 | 25 | 60
+ 6 | 16.0000000000000000 | 26 | 60
+ 7 | 17.0000000000000000 | 27 | 60
+ 8 | 18.0000000000000000 | 28 | 60
+ 9 | 19.0000000000000000 | 29 | 60
+ 10 | 10.0000000000000000 | 20 | 60
+ 11 | 11.0000000000000000 | 21 | 60
+ 12 | 12.0000000000000000 | 22 | 60
+ 13 | 13.0000000000000000 | 23 | 60
+ 14 | 14.0000000000000000 | 24 | 60
+ 15 | 15.0000000000000000 | 25 | 60
+ 16 | 16.0000000000000000 | 26 | 60
+ 17 | 17.0000000000000000 | 27 | 60
+ 18 | 18.0000000000000000 | 28 | 60
+ 19 | 19.0000000000000000 | 29 | 60
+ 20 | 10.0000000000000000 | 20 | 60
+ 21 | 11.0000000000000000 | 21 | 60
+ 22 | 12.0000000000000000 | 22 | 60
+ 23 | 13.0000000000000000 | 23 | 60
+ 24 | 14.0000000000000000 | 24 | 60
+ 25 | 15.0000000000000000 | 25 | 60
+ 26 | 16.0000000000000000 | 26 | 60
+ 27 | 17.0000000000000000 | 27 | 60
+ 28 | 18.0000000000000000 | 28 | 60
+ 29 | 19.0000000000000000 | 29 | 60
+ 30 | 10.0000000000000000 | 20 | 60
+ 31 | 11.0000000000000000 | 21 | 60
+ 32 | 12.0000000000000000 | 22 | 60
+ 33 | 13.0000000000000000 | 23 | 60
+ 34 | 14.0000000000000000 | 24 | 60
+ 35 | 15.0000000000000000 | 25 | 60
+ 36 | 16.0000000000000000 | 26 | 60
+ 37 | 17.0000000000000000 | 27 | 60
+ 38 | 18.0000000000000000 | 28 | 60
+ 39 | 19.0000000000000000 | 29 | 60
+ 40 | 10.0000000000000000 | 20 | 60
+ 41 | 11.0000000000000000 | 21 | 60
+ 42 | 12.0000000000000000 | 22 | 60
+ 43 | 13.0000000000000000 | 23 | 60
+ 44 | 14.0000000000000000 | 24 | 60
+ 45 | 15.0000000000000000 | 25 | 60
+ 46 | 16.0000000000000000 | 26 | 60
+ 47 | 17.0000000000000000 | 27 | 60
+ 48 | 18.0000000000000000 | 28 | 60
+ 49 | 19.0000000000000000 | 29 | 60
+(50 rows)
+
+-- Partial aggregates are safe to push down even if we need both variable and variable-based expression
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT avg(a), max(a), count(*), (b/2)::numeric FROM pagg_tab GROUP BY b/2 ORDER BY 4;
+ QUERY PLAN
+----------------------------------------------------------------------------------------------------------------------------------------------
+ Sort
+ Output: (avg(pagg_tab.a)), (max(pagg_tab.a)), (count(*)), ((((pagg_tab.b / 2)))::numeric), ((pagg_tab.b / 2))
+ Sort Key: ((((pagg_tab.b / 2)))::numeric)
+ -> Finalize HashAggregate
+ Output: avg(pagg_tab.a), max(pagg_tab.a), count(*), (((pagg_tab.b / 2)))::numeric, ((pagg_tab.b / 2))
+ Group Key: ((pagg_tab.b / 2))
+ -> Append
+ -> Foreign Scan
+ Output: ((pagg_tab.b / 2)), (PARTIAL avg(pagg_tab.a)), (PARTIAL max(pagg_tab.a)), (PARTIAL count(*)), pagg_tab.b
+ Relations: Aggregate on (public.fpagg_tab_p1 pagg_tab)
+ Remote SQL: SELECT (b / 2), b, avg_p_int4(a), max(a), count(*) FROM public.pagg_tab_p1 GROUP BY 1, 2
+ -> Foreign Scan
+ Output: ((pagg_tab_1.b / 2)), (PARTIAL avg(pagg_tab_1.a)), (PARTIAL max(pagg_tab_1.a)), (PARTIAL count(*)), pagg_tab_1.b
+ Relations: Aggregate on (public.fpagg_tab_p2 pagg_tab_1)
+ Remote SQL: SELECT (b / 2), b, avg_p_int4(a), max(a), count(*) FROM public.pagg_tab_p2 GROUP BY 1, 2
+ -> Foreign Scan
+ Output: ((pagg_tab_2.b / 2)), (PARTIAL avg(pagg_tab_2.a)), (PARTIAL max(pagg_tab_2.a)), (PARTIAL count(*)), pagg_tab_2.b
+ Relations: Aggregate on (public.fpagg_tab_p3 pagg_tab_2)
+ Remote SQL: SELECT (b / 2), b, avg_p_int4(a), max(a), count(*) FROM public.pagg_tab_p3 GROUP BY 1, 2
+(19 rows)
+
+SELECT avg(a), max(a), count(*), (b/2)::numeric FROM pagg_tab GROUP BY b/2 ORDER BY 4;
+ avg | max | count | numeric
+---------------------+-----+-------+---------
+ 10.5000000000000000 | 21 | 120 | 0
+ 12.5000000000000000 | 23 | 120 | 1
+ 14.5000000000000000 | 25 | 120 | 2
+ 16.5000000000000000 | 27 | 120 | 3
+ 18.5000000000000000 | 29 | 120 | 4
+ 10.5000000000000000 | 21 | 120 | 5
+ 12.5000000000000000 | 23 | 120 | 6
+ 14.5000000000000000 | 25 | 120 | 7
+ 16.5000000000000000 | 27 | 120 | 8
+ 18.5000000000000000 | 29 | 120 | 9
+ 10.5000000000000000 | 21 | 120 | 10
+ 12.5000000000000000 | 23 | 120 | 11
+ 14.5000000000000000 | 25 | 120 | 12
+ 16.5000000000000000 | 27 | 120 | 13
+ 18.5000000000000000 | 29 | 120 | 14
+ 10.5000000000000000 | 21 | 120 | 15
+ 12.5000000000000000 | 23 | 120 | 16
+ 14.5000000000000000 | 25 | 120 | 17
+ 16.5000000000000000 | 27 | 120 | 18
+ 18.5000000000000000 | 29 | 120 | 19
+ 10.5000000000000000 | 21 | 120 | 20
+ 12.5000000000000000 | 23 | 120 | 21
+ 14.5000000000000000 | 25 | 120 | 22
+ 16.5000000000000000 | 27 | 120 | 23
+ 18.5000000000000000 | 29 | 120 | 24
+(25 rows)
+
+-- Partial aggregates are safe to push down for all built-in aggregates
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT /* aggregate function <> aggpartialfunc */
+ array_agg(c_int4array), array_agg(b),
+ avg(b::int2), avg(b::int4), avg(b::int8), avg(c_interval), avg(b::float4), avg(b::float8), avg(b::numeric),
+ corr(b::float8, (b * b)::float8),
+ covar_pop(b::float8, (b * b)::float8),
+ covar_samp(b::float8, (b * b)::float8),
+ regr_avgx((2 * b)::float8, b::float8),
+ regr_avgy((2 * b)::float8, b::float8),
+ regr_intercept((2 * b + 3)::float8, b::float8),
+ regr_r2((b * b)::float8, b::float8),
+ regr_slope((2 * b + 3)::float8, b::float8),
+ regr_sxx((2 * b + 3)::float8, b::float8),
+ regr_sxy((b * b)::float8, b::float8),
+ regr_syy((2 * b + 3)::float8, b::float8),
+ stddev(b::float4), stddev(b::float8), stddev(b::int2), stddev(b::int4), stddev(b::int8), stddev(b::numeric),
+ stddev_pop(b::float4), stddev_pop(b::float8), stddev_pop(b::int2), stddev_pop(b::int4), stddev_pop(b::int8), stddev_pop(b::numeric),
+ stddev_samp(b::float4), stddev_samp(b::float8), stddev_samp(b::int2), stddev_samp(b::int4), stddev_samp(b::int8), stddev_samp(b::numeric),
+ string_agg(c_1c, ','), string_agg(c_1b, ','),
+ sum(b::int8), sum(b::numeric),
+ variance(b::float4), variance(b::float8), variance(b::int2), variance(b::int4), variance(b::int8), variance(b::numeric),
+ var_pop(b::float4), var_pop(b::float8), var_pop(b::int2), var_pop(b::int4), var_pop(b::int8), var_pop(b::numeric),
+ var_samp(b::float4), var_samp(b::float8), var_samp(b::int2), var_samp(b::int4), var_samp(b::int8), var_samp(b::numeric),
+ /* aggregate function = aggpartialfunc */
+ any_value(b * 0),
+ bit_and(c_bit), bit_and(c_1or3int2), bit_and(c_1or3int4), bit_and(c_1or3int8),
+ bit_or(c_bit), bit_or(c_1or3int2), bit_or(c_1or3int4), bit_or(c_1or3int8),
+ bit_xor(c_bit), bit_xor(c_1or3int2), bit_xor(c_1or3int4), bit_xor(c_1or3int8),
+ bool_and(c_bool),
+ bool_or(c_bool),
+ count(b), count(*),
+ every(c_bool),
+ max(c_int4array), max(c_enum), max(c_1c::char(1)), max('2000-01-01'::date + b), max('0.0.0.0'::inet + b), max(b::float4), max(b::float8), max(b::int2), max(b::int4), max(b::int8), max(c_interval), max(c_money), max(b::numeric), max(b::oid), max(c_pg_lsn), max(c_tid), max(c_1c), max(c_time), max(c_timetz), max(c_timestamp), max(c_timestamptz), max(c_xid8),
+ min(c_int4array), min(c_enum), min(c_1c::char(1)), min('2000-01-01'::date + b), min('0.0.0.0'::inet + b), min(b::float4), min(b::float8), min(b::int2), min(b::int4), min(b::int8), min(c_interval), min(c_money), min(b::numeric), min(b::oid), min(c_pg_lsn), min(c_tid), min(c_1c), min(c_time), min(c_timetz), min(c_timestamp), min(c_timestamptz), min(c_xid8),
+ range_intersect_agg(c_int4range), range_intersect_agg(c_int4multirange),
+ regr_count((2 * b + 3)::float8, b::float8),
+ sum(b::float4), sum(b::float8), sum(b::int2), sum(b::int4), sum(c_interval), sum(c_money)
+ FROM pagg_tab WHERE c_serial between 1 and 30;
+ QUERY PLAN
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Finalize Aggregate
+ Output: array_agg(pagg_tab.c_int4array), array_agg(pagg_tab.b), avg((pagg_tab.b)::smallint), avg(pagg_tab.b), avg((pagg_tab.b)::bigint), avg(pagg_tab.c_interval), avg((pagg_tab.b)::real), avg((pagg_tab.b)::double precision), avg((pagg_tab.b)::numeric), corr((pagg_tab.b)::double precision, ((pagg_tab.b * pagg_tab.b))::double precision), covar_pop((pagg_tab.b)::double precision, ((pagg_tab.b * pagg_tab.b))::double precision), covar_samp((pagg_tab.b)::double precision, ((pagg_tab.b * pagg_tab.b))::double precision), regr_avgx(((2 * pagg_tab.b))::double precision, (pagg_tab.b)::double precision), regr_avgy(((2 * pagg_tab.b))::double precision, (pagg_tab.b)::double precision), regr_intercept((((2 * pagg_tab.b) + 3))::double precision, (pagg_tab.b)::double precision), regr_r2(((pagg_tab.b * pagg_tab.b))::double precision, (pagg_tab.b)::double precision), regr_slope((((2 * pagg_tab.b) + 3))::double precision, (pagg_tab.b)::double precision), regr_sxx((((2 * pagg_tab.b) + 3))::double precision, (pagg_tab.b)::double precision), regr_sxy(((pagg_tab.b * pagg_tab.b))::double precision, (pagg_tab.b)::double precision), regr_syy((((2 * pagg_tab.b) + 3))::double precision, (pagg_tab.b)::double precision), stddev((pagg_tab.b)::real), stddev((pagg_tab.b)::double precision), stddev((pagg_tab.b)::smallint), stddev(pagg_tab.b), stddev((pagg_tab.b)::bigint), stddev((pagg_tab.b)::numeric), stddev_pop((pagg_tab.b)::real), stddev_pop((pagg_tab.b)::double precision), stddev_pop((pagg_tab.b)::smallint), stddev_pop(pagg_tab.b), stddev_pop((pagg_tab.b)::bigint), stddev_pop((pagg_tab.b)::numeric), stddev_samp((pagg_tab.b)::real), stddev_samp((pagg_tab.b)::double precision), stddev_samp((pagg_tab.b)::smallint), stddev_samp(pagg_tab.b), stddev_samp((pagg_tab.b)::bigint), stddev_samp((pagg_tab.b)::numeric), string_agg(pagg_tab.c_1c, ','::text), string_agg(pagg_tab.c_1b, '\x2c'::bytea), sum((pagg_tab.b)::bigint), sum((pagg_tab.b)::numeric), variance((pagg_tab.b)::real), variance((pagg_tab.b)::double precision), variance((pagg_tab.b)::smallint), variance(pagg_tab.b), variance((pagg_tab.b)::bigint), variance((pagg_tab.b)::numeric), var_pop((pagg_tab.b)::real), var_pop((pagg_tab.b)::double precision), var_pop((pagg_tab.b)::smallint), var_pop(pagg_tab.b), var_pop((pagg_tab.b)::bigint), var_pop((pagg_tab.b)::numeric), var_samp((pagg_tab.b)::real), var_samp((pagg_tab.b)::double precision), var_samp((pagg_tab.b)::smallint), var_samp(pagg_tab.b), var_samp((pagg_tab.b)::bigint), var_samp((pagg_tab.b)::numeric), any_value((pagg_tab.b * 0)), bit_and(pagg_tab.c_bit), bit_and(pagg_tab.c_1or3int2), bit_and(pagg_tab.c_1or3int4), bit_and(pagg_tab.c_1or3int8), bit_or(pagg_tab.c_bit), bit_or(pagg_tab.c_1or3int2), bit_or(pagg_tab.c_1or3int4), bit_or(pagg_tab.c_1or3int8), bit_xor(pagg_tab.c_bit), bit_xor(pagg_tab.c_1or3int2), bit_xor(pagg_tab.c_1or3int4), bit_xor(pagg_tab.c_1or3int8), bool_and(pagg_tab.c_bool), bool_or(pagg_tab.c_bool), count(pagg_tab.b), count(*), every(pagg_tab.c_bool), max(pagg_tab.c_int4array), max(pagg_tab.c_enum), max((pagg_tab.c_1c)::character(1)), max(('01-01-2000'::date + pagg_tab.b)), max(('0.0.0.0'::inet + (pagg_tab.b)::bigint)), max((pagg_tab.b)::real), max((pagg_tab.b)::double precision), max((pagg_tab.b)::smallint), max(pagg_tab.b), max((pagg_tab.b)::bigint), max(pagg_tab.c_interval), max(pagg_tab.c_money), max((pagg_tab.b)::numeric), max((pagg_tab.b)::oid), max(pagg_tab.c_pg_lsn), max(pagg_tab.c_tid), max(pagg_tab.c_1c), max(pagg_tab.c_time), max(pagg_tab.c_timetz), max(pagg_tab.c_timestamp), max(pagg_tab.c_timestamptz), max(pagg_tab.c_xid8), min(pagg_tab.c_int4array), min(pagg_tab.c_enum), min((pagg_tab.c_1c)::character(1)), min(('01-01-2000'::date + pagg_tab.b)), min(('0.0.0.0'::inet + (pagg_tab.b)::bigint)), min((pagg_tab.b)::real), min((pagg_tab.b)::double precision), min((pagg_tab.b)::smallint), min(pagg_tab.b), min((pagg_tab.b)::bigint), min(pagg_tab.c_interval), min(pagg_tab.c_money), min((pagg_tab.b)::numeric), min((pagg_tab.b)::oid), min(pagg_tab.c_pg_lsn), min(pagg_tab.c_tid), min(pagg_tab.c_1c), min(pagg_tab.c_time), min(pagg_tab.c_timetz), min(pagg_tab.c_timestamp), min(pagg_tab.c_timestamptz), min(pagg_tab.c_xid8), range_intersect_agg(pagg_tab.c_int4range), range_intersect_agg(pagg_tab.c_int4multirange), regr_count((((2 * pagg_tab.b) + 3))::double precision, (pagg_tab.b)::double precision), sum((pagg_tab.b)::real), sum((pagg_tab.b)::double precision), sum((pagg_tab.b)::smallint), sum(pagg_tab.b), sum(pagg_tab.c_interval), sum(pagg_tab.c_money)
+ -> Append
+ -> Foreign Scan
+ Output: (PARTIAL array_agg(pagg_tab.c_int4array)), (PARTIAL array_agg(pagg_tab.b)), (PARTIAL avg((pagg_tab.b)::smallint)), (PARTIAL avg(pagg_tab.b)), (PARTIAL avg((pagg_tab.b)::bigint)), (PARTIAL avg(pagg_tab.c_interval)), (PARTIAL avg((pagg_tab.b)::real)), (PARTIAL avg((pagg_tab.b)::double precision)), (PARTIAL avg((pagg_tab.b)::numeric)), (PARTIAL corr((pagg_tab.b)::double precision, ((pagg_tab.b * pagg_tab.b))::double precision)), (PARTIAL covar_pop((pagg_tab.b)::double precision, ((pagg_tab.b * pagg_tab.b))::double precision)), (PARTIAL covar_samp((pagg_tab.b)::double precision, ((pagg_tab.b * pagg_tab.b))::double precision)), (PARTIAL regr_avgx(((2 * pagg_tab.b))::double precision, (pagg_tab.b)::double precision)), (PARTIAL regr_avgy(((2 * pagg_tab.b))::double precision, (pagg_tab.b)::double precision)), (PARTIAL regr_intercept((((2 * pagg_tab.b) + 3))::double precision, (pagg_tab.b)::double precision)), (PARTIAL regr_r2(((pagg_tab.b * pagg_tab.b))::double precision, (pagg_tab.b)::double precision)), (PARTIAL regr_slope((((2 * pagg_tab.b) + 3))::double precision, (pagg_tab.b)::double precision)), (PARTIAL regr_sxx((((2 * pagg_tab.b) + 3))::double precision, (pagg_tab.b)::double precision)), (PARTIAL regr_sxy(((pagg_tab.b * pagg_tab.b))::double precision, (pagg_tab.b)::double precision)), (PARTIAL regr_syy((((2 * pagg_tab.b) + 3))::double precision, (pagg_tab.b)::double precision)), (PARTIAL stddev((pagg_tab.b)::real)), (PARTIAL stddev((pagg_tab.b)::double precision)), (PARTIAL stddev((pagg_tab.b)::smallint)), (PARTIAL stddev(pagg_tab.b)), (PARTIAL stddev((pagg_tab.b)::bigint)), (PARTIAL stddev((pagg_tab.b)::numeric)), (PARTIAL stddev_pop((pagg_tab.b)::real)), (PARTIAL stddev_pop((pagg_tab.b)::double precision)), (PARTIAL stddev_pop((pagg_tab.b)::smallint)), (PARTIAL stddev_pop(pagg_tab.b)), (PARTIAL stddev_pop((pagg_tab.b)::bigint)), (PARTIAL stddev_pop((pagg_tab.b)::numeric)), (PARTIAL stddev_samp((pagg_tab.b)::real)), (PARTIAL stddev_samp((pagg_tab.b)::double precision)), (PARTIAL stddev_samp((pagg_tab.b)::smallint)), (PARTIAL stddev_samp(pagg_tab.b)), (PARTIAL stddev_samp((pagg_tab.b)::bigint)), (PARTIAL stddev_samp((pagg_tab.b)::numeric)), (PARTIAL string_agg(pagg_tab.c_1c, ','::text)), (PARTIAL string_agg(pagg_tab.c_1b, '\x2c'::bytea)), (PARTIAL sum((pagg_tab.b)::bigint)), (PARTIAL sum((pagg_tab.b)::numeric)), (PARTIAL variance((pagg_tab.b)::real)), (PARTIAL variance((pagg_tab.b)::double precision)), (PARTIAL variance((pagg_tab.b)::smallint)), (PARTIAL variance(pagg_tab.b)), (PARTIAL variance((pagg_tab.b)::bigint)), (PARTIAL variance((pagg_tab.b)::numeric)), (PARTIAL var_pop((pagg_tab.b)::real)), (PARTIAL var_pop((pagg_tab.b)::double precision)), (PARTIAL var_pop((pagg_tab.b)::smallint)), (PARTIAL var_pop(pagg_tab.b)), (PARTIAL var_pop((pagg_tab.b)::bigint)), (PARTIAL var_pop((pagg_tab.b)::numeric)), (PARTIAL var_samp((pagg_tab.b)::real)), (PARTIAL var_samp((pagg_tab.b)::double precision)), (PARTIAL var_samp((pagg_tab.b)::smallint)), (PARTIAL var_samp(pagg_tab.b)), (PARTIAL var_samp((pagg_tab.b)::bigint)), (PARTIAL var_samp((pagg_tab.b)::numeric)), (PARTIAL any_value((pagg_tab.b * 0))), (PARTIAL bit_and(pagg_tab.c_bit)), (PARTIAL bit_and(pagg_tab.c_1or3int2)), (PARTIAL bit_and(pagg_tab.c_1or3int4)), (PARTIAL bit_and(pagg_tab.c_1or3int8)), (PARTIAL bit_or(pagg_tab.c_bit)), (PARTIAL bit_or(pagg_tab.c_1or3int2)), (PARTIAL bit_or(pagg_tab.c_1or3int4)), (PARTIAL bit_or(pagg_tab.c_1or3int8)), (PARTIAL bit_xor(pagg_tab.c_bit)), (PARTIAL bit_xor(pagg_tab.c_1or3int2)), (PARTIAL bit_xor(pagg_tab.c_1or3int4)), (PARTIAL bit_xor(pagg_tab.c_1or3int8)), (PARTIAL bool_and(pagg_tab.c_bool)), (PARTIAL bool_or(pagg_tab.c_bool)), (PARTIAL count(pagg_tab.b)), (PARTIAL count(*)), (PARTIAL every(pagg_tab.c_bool)), (PARTIAL max(pagg_tab.c_int4array)), (PARTIAL max(pagg_tab.c_enum)), (PARTIAL max((pagg_tab.c_1c)::character(1))), (PARTIAL max(('01-01-2000'::date + pagg_tab.b))), (PARTIAL max(('0.0.0.0'::inet + (pagg_tab.b)::bigint))), (PARTIAL max((pagg_tab.b)::real)), (PARTIAL max((pagg_tab.b)::double precision)), (PARTIAL max((pagg_tab.b)::smallint)), (PARTIAL max(pagg_tab.b)), (PARTIAL max((pagg_tab.b)::bigint)), (PARTIAL max(pagg_tab.c_interval)), (PARTIAL max(pagg_tab.c_money)), (PARTIAL max((pagg_tab.b)::numeric)), (PARTIAL max((pagg_tab.b)::oid)), (PARTIAL max(pagg_tab.c_pg_lsn)), (PARTIAL max(pagg_tab.c_tid)), (PARTIAL max(pagg_tab.c_1c)), (PARTIAL max(pagg_tab.c_time)), (PARTIAL max(pagg_tab.c_timetz)), (PARTIAL max(pagg_tab.c_timestamp)), (PARTIAL max(pagg_tab.c_timestamptz)), (PARTIAL max(pagg_tab.c_xid8)), (PARTIAL min(pagg_tab.c_int4array)), (PARTIAL min(pagg_tab.c_enum)), (PARTIAL min((pagg_tab.c_1c)::character(1))), (PARTIAL min(('01-01-2000'::date + pagg_tab.b))), (PARTIAL min(('0.0.0.0'::inet + (pagg_tab.b)::bigint))), (PARTIAL min((pagg_tab.b)::real)), (PARTIAL min((pagg_tab.b)::double precision)), (PARTIAL min((pagg_tab.b)::smallint)), (PARTIAL min(pagg_tab.b)), (PARTIAL min((pagg_tab.b)::bigint)), (PARTIAL min(pagg_tab.c_interval)), (PARTIAL min(pagg_tab.c_money)), (PARTIAL min((pagg_tab.b)::numeric)), (PARTIAL min((pagg_tab.b)::oid)), (PARTIAL min(pagg_tab.c_pg_lsn)), (PARTIAL min(pagg_tab.c_tid)), (PARTIAL min(pagg_tab.c_1c)), (PARTIAL min(pagg_tab.c_time)), (PARTIAL min(pagg_tab.c_timetz)), (PARTIAL min(pagg_tab.c_timestamp)), (PARTIAL min(pagg_tab.c_timestamptz)), (PARTIAL min(pagg_tab.c_xid8)), (PARTIAL range_intersect_agg(pagg_tab.c_int4range)), (PARTIAL range_intersect_agg(pagg_tab.c_int4multirange)), (PARTIAL regr_count((((2 * pagg_tab.b) + 3))::double precision, (pagg_tab.b)::double precision)), (PARTIAL sum((pagg_tab.b)::real)), (PARTIAL sum((pagg_tab.b)::double precision)), (PARTIAL sum((pagg_tab.b)::smallint)), (PARTIAL sum(pagg_tab.b)), (PARTIAL sum(pagg_tab.c_interval)), (PARTIAL sum(pagg_tab.c_money))
+ Relations: Aggregate on (public.fpagg_tab_p1 pagg_tab)
+ Remote SQL: SELECT array_agg_p_anyarray(c_int4array), array_agg_p_anynonarray(b), avg_p_int2(b::smallint), avg_p_int4(b), avg_p_int8(b::bigint), avg_p_interval(c_interval), avg_p_float4(b::real), avg_p_float8(b::double precision), avg_p_numeric(b::numeric), corr_p(b::double precision, (b * b)::double precision), covar_pop_p(b::double precision, (b * b)::double precision), covar_samp_p(b::double precision, (b * b)::double precision), regr_avgx_p((2 * b)::double precision, b::double precision), regr_avgy_p((2 * b)::double precision, b::double precision), regr_intercept_p(((2 * b) + 3)::double precision, b::double precision), regr_r2_p((b * b)::double precision, b::double precision), regr_slope_p(((2 * b) + 3)::double precision, b::double precision), regr_sxx_p(((2 * b) + 3)::double precision, b::double precision), regr_sxy_p((b * b)::double precision, b::double precision), regr_syy_p(((2 * b) + 3)::double precision, b::double precision), stddev_p_float4(b::real), stddev_p_float8(b::double precision), stddev_p_int2(b::smallint), stddev_p_int4(b), stddev_p_int8(b::bigint), stddev_p_numeric(b::numeric), stddev_pop_p_float4(b::real), stddev_pop_p_float8(b::double precision), stddev_pop_p_int2(b::smallint), stddev_pop_p_int4(b), stddev_pop_p_int8(b::bigint), stddev_pop_p_numeric(b::numeric), stddev_samp_p_float4(b::real), stddev_samp_p_float8(b::double precision), stddev_samp_p_int2(b::smallint), stddev_samp_p_int4(b), stddev_samp_p_int8(b::bigint), stddev_samp_p_numeric(b::numeric), string_agg_p_text_text(c_1c, ','::text), string_agg_p_bytea_bytea(c_1b, E'\\x2c'::bytea), sum_p_int8(b::bigint), sum_p_numeric(b::numeric), variance_p_float4(b::real), variance_p_float8(b::double precision), variance_p_int2(b::smallint), variance_p_int4(b), variance_p_int8(b::bigint), variance_p_numeric(b::numeric), var_pop_p_float4(b::real), var_pop_p_float8(b::double precision), var_pop_p_int2(b::smallint), var_pop_p_int4(b), var_pop_p_int8(b::bigint), var_pop_p_numeric(b::numeric), var_samp_p_float4(b::real), var_samp_p_float8(b::double precision), var_samp_p_int2(b::smallint), var_samp_p_int4(b), var_samp_p_int8(b::bigint), var_samp_p_numeric(b::numeric), any_value((b * 0)), bit_and(c_bit), bit_and(c_1or3int2), bit_and(c_1or3int4), bit_and(c_1or3int8), bit_or(c_bit), bit_or(c_1or3int2), bit_or(c_1or3int4), bit_or(c_1or3int8), bit_xor(c_bit), bit_xor(c_1or3int2), bit_xor(c_1or3int4), bit_xor(c_1or3int8), bool_and(c_bool), bool_or(c_bool), count(b), count(*), every(c_bool), max(c_int4array), max(c_enum), max(c_1c::character(1)), max(('01-01-2000'::date + b)), max(('0.0.0.0'::inet + b)), max(b::real), max(b::double precision), max(b::smallint), max(b), max(b::bigint), max(c_interval), max(c_money), max(b::numeric), max(b::oid), max(c_pg_lsn), max(c_tid), max(c_1c), max(c_time), max(c_timetz), max(c_timestamp), max(c_timestamptz), max(c_xid8), min(c_int4array), min(c_enum), min(c_1c::character(1)), min(('01-01-2000'::date + b)), min(('0.0.0.0'::inet + b)), min(b::real), min(b::double precision), min(b::smallint), min(b), min(b::bigint), min(c_interval), min(c_money), min(b::numeric), min(b::oid), min(c_pg_lsn), min(c_tid), min(c_1c), min(c_time), min(c_timetz), min(c_timestamp), min(c_timestamptz), min(c_xid8), range_intersect_agg(c_int4range), range_intersect_agg(c_int4multirange), regr_count(((2 * b) + 3)::double precision, b::double precision), sum(b::real), sum(b::double precision), sum(b::smallint), sum(b), sum(c_interval), sum(c_money) FROM public.pagg_tab_p1 WHERE ((c_serial >= 1)) AND ((c_serial <= 30))
+ -> Foreign Scan
+ Output: (PARTIAL array_agg(pagg_tab_1.c_int4array)), (PARTIAL array_agg(pagg_tab_1.b)), (PARTIAL avg((pagg_tab_1.b)::smallint)), (PARTIAL avg(pagg_tab_1.b)), (PARTIAL avg((pagg_tab_1.b)::bigint)), (PARTIAL avg(pagg_tab_1.c_interval)), (PARTIAL avg((pagg_tab_1.b)::real)), (PARTIAL avg((pagg_tab_1.b)::double precision)), (PARTIAL avg((pagg_tab_1.b)::numeric)), (PARTIAL corr((pagg_tab_1.b)::double precision, ((pagg_tab_1.b * pagg_tab_1.b))::double precision)), (PARTIAL covar_pop((pagg_tab_1.b)::double precision, ((pagg_tab_1.b * pagg_tab_1.b))::double precision)), (PARTIAL covar_samp((pagg_tab_1.b)::double precision, ((pagg_tab_1.b * pagg_tab_1.b))::double precision)), (PARTIAL regr_avgx(((2 * pagg_tab_1.b))::double precision, (pagg_tab_1.b)::double precision)), (PARTIAL regr_avgy(((2 * pagg_tab_1.b))::double precision, (pagg_tab_1.b)::double precision)), (PARTIAL regr_intercept((((2 * pagg_tab_1.b) + 3))::double precision, (pagg_tab_1.b)::double precision)), (PARTIAL regr_r2(((pagg_tab_1.b * pagg_tab_1.b))::double precision, (pagg_tab_1.b)::double precision)), (PARTIAL regr_slope((((2 * pagg_tab_1.b) + 3))::double precision, (pagg_tab_1.b)::double precision)), (PARTIAL regr_sxx((((2 * pagg_tab_1.b) + 3))::double precision, (pagg_tab_1.b)::double precision)), (PARTIAL regr_sxy(((pagg_tab_1.b * pagg_tab_1.b))::double precision, (pagg_tab_1.b)::double precision)), (PARTIAL regr_syy((((2 * pagg_tab_1.b) + 3))::double precision, (pagg_tab_1.b)::double precision)), (PARTIAL stddev((pagg_tab_1.b)::real)), (PARTIAL stddev((pagg_tab_1.b)::double precision)), (PARTIAL stddev((pagg_tab_1.b)::smallint)), (PARTIAL stddev(pagg_tab_1.b)), (PARTIAL stddev((pagg_tab_1.b)::bigint)), (PARTIAL stddev((pagg_tab_1.b)::numeric)), (PARTIAL stddev_pop((pagg_tab_1.b)::real)), (PARTIAL stddev_pop((pagg_tab_1.b)::double precision)), (PARTIAL stddev_pop((pagg_tab_1.b)::smallint)), (PARTIAL stddev_pop(pagg_tab_1.b)), (PARTIAL stddev_pop((pagg_tab_1.b)::bigint)), (PARTIAL stddev_pop((pagg_tab_1.b)::numeric)), (PARTIAL stddev_samp((pagg_tab_1.b)::real)), (PARTIAL stddev_samp((pagg_tab_1.b)::double precision)), (PARTIAL stddev_samp((pagg_tab_1.b)::smallint)), (PARTIAL stddev_samp(pagg_tab_1.b)), (PARTIAL stddev_samp((pagg_tab_1.b)::bigint)), (PARTIAL stddev_samp((pagg_tab_1.b)::numeric)), (PARTIAL string_agg(pagg_tab_1.c_1c, ','::text)), (PARTIAL string_agg(pagg_tab_1.c_1b, '\x2c'::bytea)), (PARTIAL sum((pagg_tab_1.b)::bigint)), (PARTIAL sum((pagg_tab_1.b)::numeric)), (PARTIAL variance((pagg_tab_1.b)::real)), (PARTIAL variance((pagg_tab_1.b)::double precision)), (PARTIAL variance((pagg_tab_1.b)::smallint)), (PARTIAL variance(pagg_tab_1.b)), (PARTIAL variance((pagg_tab_1.b)::bigint)), (PARTIAL variance((pagg_tab_1.b)::numeric)), (PARTIAL var_pop((pagg_tab_1.b)::real)), (PARTIAL var_pop((pagg_tab_1.b)::double precision)), (PARTIAL var_pop((pagg_tab_1.b)::smallint)), (PARTIAL var_pop(pagg_tab_1.b)), (PARTIAL var_pop((pagg_tab_1.b)::bigint)), (PARTIAL var_pop((pagg_tab_1.b)::numeric)), (PARTIAL var_samp((pagg_tab_1.b)::real)), (PARTIAL var_samp((pagg_tab_1.b)::double precision)), (PARTIAL var_samp((pagg_tab_1.b)::smallint)), (PARTIAL var_samp(pagg_tab_1.b)), (PARTIAL var_samp((pagg_tab_1.b)::bigint)), (PARTIAL var_samp((pagg_tab_1.b)::numeric)), (PARTIAL any_value((pagg_tab_1.b * 0))), (PARTIAL bit_and(pagg_tab_1.c_bit)), (PARTIAL bit_and(pagg_tab_1.c_1or3int2)), (PARTIAL bit_and(pagg_tab_1.c_1or3int4)), (PARTIAL bit_and(pagg_tab_1.c_1or3int8)), (PARTIAL bit_or(pagg_tab_1.c_bit)), (PARTIAL bit_or(pagg_tab_1.c_1or3int2)), (PARTIAL bit_or(pagg_tab_1.c_1or3int4)), (PARTIAL bit_or(pagg_tab_1.c_1or3int8)), (PARTIAL bit_xor(pagg_tab_1.c_bit)), (PARTIAL bit_xor(pagg_tab_1.c_1or3int2)), (PARTIAL bit_xor(pagg_tab_1.c_1or3int4)), (PARTIAL bit_xor(pagg_tab_1.c_1or3int8)), (PARTIAL bool_and(pagg_tab_1.c_bool)), (PARTIAL bool_or(pagg_tab_1.c_bool)), (PARTIAL count(pagg_tab_1.b)), (PARTIAL count(*)), (PARTIAL every(pagg_tab_1.c_bool)), (PARTIAL max(pagg_tab_1.c_int4array)), (PARTIAL max(pagg_tab_1.c_enum)), (PARTIAL max((pagg_tab_1.c_1c)::character(1))), (PARTIAL max(('01-01-2000'::date + pagg_tab_1.b))), (PARTIAL max(('0.0.0.0'::inet + (pagg_tab_1.b)::bigint))), (PARTIAL max((pagg_tab_1.b)::real)), (PARTIAL max((pagg_tab_1.b)::double precision)), (PARTIAL max((pagg_tab_1.b)::smallint)), (PARTIAL max(pagg_tab_1.b)), (PARTIAL max((pagg_tab_1.b)::bigint)), (PARTIAL max(pagg_tab_1.c_interval)), (PARTIAL max(pagg_tab_1.c_money)), (PARTIAL max((pagg_tab_1.b)::numeric)), (PARTIAL max((pagg_tab_1.b)::oid)), (PARTIAL max(pagg_tab_1.c_pg_lsn)), (PARTIAL max(pagg_tab_1.c_tid)), (PARTIAL max(pagg_tab_1.c_1c)), (PARTIAL max(pagg_tab_1.c_time)), (PARTIAL max(pagg_tab_1.c_timetz)), (PARTIAL max(pagg_tab_1.c_timestamp)), (PARTIAL max(pagg_tab_1.c_timestamptz)), (PARTIAL max(pagg_tab_1.c_xid8)), (PARTIAL min(pagg_tab_1.c_int4array)), (PARTIAL min(pagg_tab_1.c_enum)), (PARTIAL min((pagg_tab_1.c_1c)::character(1))), (PARTIAL min(('01-01-2000'::date + pagg_tab_1.b))), (PARTIAL min(('0.0.0.0'::inet + (pagg_tab_1.b)::bigint))), (PARTIAL min((pagg_tab_1.b)::real)), (PARTIAL min((pagg_tab_1.b)::double precision)), (PARTIAL min((pagg_tab_1.b)::smallint)), (PARTIAL min(pagg_tab_1.b)), (PARTIAL min((pagg_tab_1.b)::bigint)), (PARTIAL min(pagg_tab_1.c_interval)), (PARTIAL min(pagg_tab_1.c_money)), (PARTIAL min((pagg_tab_1.b)::numeric)), (PARTIAL min((pagg_tab_1.b)::oid)), (PARTIAL min(pagg_tab_1.c_pg_lsn)), (PARTIAL min(pagg_tab_1.c_tid)), (PARTIAL min(pagg_tab_1.c_1c)), (PARTIAL min(pagg_tab_1.c_time)), (PARTIAL min(pagg_tab_1.c_timetz)), (PARTIAL min(pagg_tab_1.c_timestamp)), (PARTIAL min(pagg_tab_1.c_timestamptz)), (PARTIAL min(pagg_tab_1.c_xid8)), (PARTIAL range_intersect_agg(pagg_tab_1.c_int4range)), (PARTIAL range_intersect_agg(pagg_tab_1.c_int4multirange)), (PARTIAL regr_count((((2 * pagg_tab_1.b) + 3))::double precision, (pagg_tab_1.b)::double precision)), (PARTIAL sum((pagg_tab_1.b)::real)), (PARTIAL sum((pagg_tab_1.b)::double precision)), (PARTIAL sum((pagg_tab_1.b)::smallint)), (PARTIAL sum(pagg_tab_1.b)), (PARTIAL sum(pagg_tab_1.c_interval)), (PARTIAL sum(pagg_tab_1.c_money))
+ Relations: Aggregate on (public.fpagg_tab_p2 pagg_tab_1)
+ Remote SQL: SELECT array_agg_p_anyarray(c_int4array), array_agg_p_anynonarray(b), avg_p_int2(b::smallint), avg_p_int4(b), avg_p_int8(b::bigint), avg_p_interval(c_interval), avg_p_float4(b::real), avg_p_float8(b::double precision), avg_p_numeric(b::numeric), corr_p(b::double precision, (b * b)::double precision), covar_pop_p(b::double precision, (b * b)::double precision), covar_samp_p(b::double precision, (b * b)::double precision), regr_avgx_p((2 * b)::double precision, b::double precision), regr_avgy_p((2 * b)::double precision, b::double precision), regr_intercept_p(((2 * b) + 3)::double precision, b::double precision), regr_r2_p((b * b)::double precision, b::double precision), regr_slope_p(((2 * b) + 3)::double precision, b::double precision), regr_sxx_p(((2 * b) + 3)::double precision, b::double precision), regr_sxy_p((b * b)::double precision, b::double precision), regr_syy_p(((2 * b) + 3)::double precision, b::double precision), stddev_p_float4(b::real), stddev_p_float8(b::double precision), stddev_p_int2(b::smallint), stddev_p_int4(b), stddev_p_int8(b::bigint), stddev_p_numeric(b::numeric), stddev_pop_p_float4(b::real), stddev_pop_p_float8(b::double precision), stddev_pop_p_int2(b::smallint), stddev_pop_p_int4(b), stddev_pop_p_int8(b::bigint), stddev_pop_p_numeric(b::numeric), stddev_samp_p_float4(b::real), stddev_samp_p_float8(b::double precision), stddev_samp_p_int2(b::smallint), stddev_samp_p_int4(b), stddev_samp_p_int8(b::bigint), stddev_samp_p_numeric(b::numeric), string_agg_p_text_text(c_1c, ','::text), string_agg_p_bytea_bytea(c_1b, E'\\x2c'::bytea), sum_p_int8(b::bigint), sum_p_numeric(b::numeric), variance_p_float4(b::real), variance_p_float8(b::double precision), variance_p_int2(b::smallint), variance_p_int4(b), variance_p_int8(b::bigint), variance_p_numeric(b::numeric), var_pop_p_float4(b::real), var_pop_p_float8(b::double precision), var_pop_p_int2(b::smallint), var_pop_p_int4(b), var_pop_p_int8(b::bigint), var_pop_p_numeric(b::numeric), var_samp_p_float4(b::real), var_samp_p_float8(b::double precision), var_samp_p_int2(b::smallint), var_samp_p_int4(b), var_samp_p_int8(b::bigint), var_samp_p_numeric(b::numeric), any_value((b * 0)), bit_and(c_bit), bit_and(c_1or3int2), bit_and(c_1or3int4), bit_and(c_1or3int8), bit_or(c_bit), bit_or(c_1or3int2), bit_or(c_1or3int4), bit_or(c_1or3int8), bit_xor(c_bit), bit_xor(c_1or3int2), bit_xor(c_1or3int4), bit_xor(c_1or3int8), bool_and(c_bool), bool_or(c_bool), count(b), count(*), every(c_bool), max(c_int4array), max(c_enum), max(c_1c::character(1)), max(('01-01-2000'::date + b)), max(('0.0.0.0'::inet + b)), max(b::real), max(b::double precision), max(b::smallint), max(b), max(b::bigint), max(c_interval), max(c_money), max(b::numeric), max(b::oid), max(c_pg_lsn), max(c_tid), max(c_1c), max(c_time), max(c_timetz), max(c_timestamp), max(c_timestamptz), max(c_xid8), min(c_int4array), min(c_enum), min(c_1c::character(1)), min(('01-01-2000'::date + b)), min(('0.0.0.0'::inet + b)), min(b::real), min(b::double precision), min(b::smallint), min(b), min(b::bigint), min(c_interval), min(c_money), min(b::numeric), min(b::oid), min(c_pg_lsn), min(c_tid), min(c_1c), min(c_time), min(c_timetz), min(c_timestamp), min(c_timestamptz), min(c_xid8), range_intersect_agg(c_int4range), range_intersect_agg(c_int4multirange), regr_count(((2 * b) + 3)::double precision, b::double precision), sum(b::real), sum(b::double precision), sum(b::smallint), sum(b), sum(c_interval), sum(c_money) FROM public.pagg_tab_p2 WHERE ((c_serial >= 1)) AND ((c_serial <= 30))
+ -> Foreign Scan
+ Output: (PARTIAL array_agg(pagg_tab_2.c_int4array)), (PARTIAL array_agg(pagg_tab_2.b)), (PARTIAL avg((pagg_tab_2.b)::smallint)), (PARTIAL avg(pagg_tab_2.b)), (PARTIAL avg((pagg_tab_2.b)::bigint)), (PARTIAL avg(pagg_tab_2.c_interval)), (PARTIAL avg((pagg_tab_2.b)::real)), (PARTIAL avg((pagg_tab_2.b)::double precision)), (PARTIAL avg((pagg_tab_2.b)::numeric)), (PARTIAL corr((pagg_tab_2.b)::double precision, ((pagg_tab_2.b * pagg_tab_2.b))::double precision)), (PARTIAL covar_pop((pagg_tab_2.b)::double precision, ((pagg_tab_2.b * pagg_tab_2.b))::double precision)), (PARTIAL covar_samp((pagg_tab_2.b)::double precision, ((pagg_tab_2.b * pagg_tab_2.b))::double precision)), (PARTIAL regr_avgx(((2 * pagg_tab_2.b))::double precision, (pagg_tab_2.b)::double precision)), (PARTIAL regr_avgy(((2 * pagg_tab_2.b))::double precision, (pagg_tab_2.b)::double precision)), (PARTIAL regr_intercept((((2 * pagg_tab_2.b) + 3))::double precision, (pagg_tab_2.b)::double precision)), (PARTIAL regr_r2(((pagg_tab_2.b * pagg_tab_2.b))::double precision, (pagg_tab_2.b)::double precision)), (PARTIAL regr_slope((((2 * pagg_tab_2.b) + 3))::double precision, (pagg_tab_2.b)::double precision)), (PARTIAL regr_sxx((((2 * pagg_tab_2.b) + 3))::double precision, (pagg_tab_2.b)::double precision)), (PARTIAL regr_sxy(((pagg_tab_2.b * pagg_tab_2.b))::double precision, (pagg_tab_2.b)::double precision)), (PARTIAL regr_syy((((2 * pagg_tab_2.b) + 3))::double precision, (pagg_tab_2.b)::double precision)), (PARTIAL stddev((pagg_tab_2.b)::real)), (PARTIAL stddev((pagg_tab_2.b)::double precision)), (PARTIAL stddev((pagg_tab_2.b)::smallint)), (PARTIAL stddev(pagg_tab_2.b)), (PARTIAL stddev((pagg_tab_2.b)::bigint)), (PARTIAL stddev((pagg_tab_2.b)::numeric)), (PARTIAL stddev_pop((pagg_tab_2.b)::real)), (PARTIAL stddev_pop((pagg_tab_2.b)::double precision)), (PARTIAL stddev_pop((pagg_tab_2.b)::smallint)), (PARTIAL stddev_pop(pagg_tab_2.b)), (PARTIAL stddev_pop((pagg_tab_2.b)::bigint)), (PARTIAL stddev_pop((pagg_tab_2.b)::numeric)), (PARTIAL stddev_samp((pagg_tab_2.b)::real)), (PARTIAL stddev_samp((pagg_tab_2.b)::double precision)), (PARTIAL stddev_samp((pagg_tab_2.b)::smallint)), (PARTIAL stddev_samp(pagg_tab_2.b)), (PARTIAL stddev_samp((pagg_tab_2.b)::bigint)), (PARTIAL stddev_samp((pagg_tab_2.b)::numeric)), (PARTIAL string_agg(pagg_tab_2.c_1c, ','::text)), (PARTIAL string_agg(pagg_tab_2.c_1b, '\x2c'::bytea)), (PARTIAL sum((pagg_tab_2.b)::bigint)), (PARTIAL sum((pagg_tab_2.b)::numeric)), (PARTIAL variance((pagg_tab_2.b)::real)), (PARTIAL variance((pagg_tab_2.b)::double precision)), (PARTIAL variance((pagg_tab_2.b)::smallint)), (PARTIAL variance(pagg_tab_2.b)), (PARTIAL variance((pagg_tab_2.b)::bigint)), (PARTIAL variance((pagg_tab_2.b)::numeric)), (PARTIAL var_pop((pagg_tab_2.b)::real)), (PARTIAL var_pop((pagg_tab_2.b)::double precision)), (PARTIAL var_pop((pagg_tab_2.b)::smallint)), (PARTIAL var_pop(pagg_tab_2.b)), (PARTIAL var_pop((pagg_tab_2.b)::bigint)), (PARTIAL var_pop((pagg_tab_2.b)::numeric)), (PARTIAL var_samp((pagg_tab_2.b)::real)), (PARTIAL var_samp((pagg_tab_2.b)::double precision)), (PARTIAL var_samp((pagg_tab_2.b)::smallint)), (PARTIAL var_samp(pagg_tab_2.b)), (PARTIAL var_samp((pagg_tab_2.b)::bigint)), (PARTIAL var_samp((pagg_tab_2.b)::numeric)), (PARTIAL any_value((pagg_tab_2.b * 0))), (PARTIAL bit_and(pagg_tab_2.c_bit)), (PARTIAL bit_and(pagg_tab_2.c_1or3int2)), (PARTIAL bit_and(pagg_tab_2.c_1or3int4)), (PARTIAL bit_and(pagg_tab_2.c_1or3int8)), (PARTIAL bit_or(pagg_tab_2.c_bit)), (PARTIAL bit_or(pagg_tab_2.c_1or3int2)), (PARTIAL bit_or(pagg_tab_2.c_1or3int4)), (PARTIAL bit_or(pagg_tab_2.c_1or3int8)), (PARTIAL bit_xor(pagg_tab_2.c_bit)), (PARTIAL bit_xor(pagg_tab_2.c_1or3int2)), (PARTIAL bit_xor(pagg_tab_2.c_1or3int4)), (PARTIAL bit_xor(pagg_tab_2.c_1or3int8)), (PARTIAL bool_and(pagg_tab_2.c_bool)), (PARTIAL bool_or(pagg_tab_2.c_bool)), (PARTIAL count(pagg_tab_2.b)), (PARTIAL count(*)), (PARTIAL every(pagg_tab_2.c_bool)), (PARTIAL max(pagg_tab_2.c_int4array)), (PARTIAL max(pagg_tab_2.c_enum)), (PARTIAL max((pagg_tab_2.c_1c)::character(1))), (PARTIAL max(('01-01-2000'::date + pagg_tab_2.b))), (PARTIAL max(('0.0.0.0'::inet + (pagg_tab_2.b)::bigint))), (PARTIAL max((pagg_tab_2.b)::real)), (PARTIAL max((pagg_tab_2.b)::double precision)), (PARTIAL max((pagg_tab_2.b)::smallint)), (PARTIAL max(pagg_tab_2.b)), (PARTIAL max((pagg_tab_2.b)::bigint)), (PARTIAL max(pagg_tab_2.c_interval)), (PARTIAL max(pagg_tab_2.c_money)), (PARTIAL max((pagg_tab_2.b)::numeric)), (PARTIAL max((pagg_tab_2.b)::oid)), (PARTIAL max(pagg_tab_2.c_pg_lsn)), (PARTIAL max(pagg_tab_2.c_tid)), (PARTIAL max(pagg_tab_2.c_1c)), (PARTIAL max(pagg_tab_2.c_time)), (PARTIAL max(pagg_tab_2.c_timetz)), (PARTIAL max(pagg_tab_2.c_timestamp)), (PARTIAL max(pagg_tab_2.c_timestamptz)), (PARTIAL max(pagg_tab_2.c_xid8)), (PARTIAL min(pagg_tab_2.c_int4array)), (PARTIAL min(pagg_tab_2.c_enum)), (PARTIAL min((pagg_tab_2.c_1c)::character(1))), (PARTIAL min(('01-01-2000'::date + pagg_tab_2.b))), (PARTIAL min(('0.0.0.0'::inet + (pagg_tab_2.b)::bigint))), (PARTIAL min((pagg_tab_2.b)::real)), (PARTIAL min((pagg_tab_2.b)::double precision)), (PARTIAL min((pagg_tab_2.b)::smallint)), (PARTIAL min(pagg_tab_2.b)), (PARTIAL min((pagg_tab_2.b)::bigint)), (PARTIAL min(pagg_tab_2.c_interval)), (PARTIAL min(pagg_tab_2.c_money)), (PARTIAL min((pagg_tab_2.b)::numeric)), (PARTIAL min((pagg_tab_2.b)::oid)), (PARTIAL min(pagg_tab_2.c_pg_lsn)), (PARTIAL min(pagg_tab_2.c_tid)), (PARTIAL min(pagg_tab_2.c_1c)), (PARTIAL min(pagg_tab_2.c_time)), (PARTIAL min(pagg_tab_2.c_timetz)), (PARTIAL min(pagg_tab_2.c_timestamp)), (PARTIAL min(pagg_tab_2.c_timestamptz)), (PARTIAL min(pagg_tab_2.c_xid8)), (PARTIAL range_intersect_agg(pagg_tab_2.c_int4range)), (PARTIAL range_intersect_agg(pagg_tab_2.c_int4multirange)), (PARTIAL regr_count((((2 * pagg_tab_2.b) + 3))::double precision, (pagg_tab_2.b)::double precision)), (PARTIAL sum((pagg_tab_2.b)::real)), (PARTIAL sum((pagg_tab_2.b)::double precision)), (PARTIAL sum((pagg_tab_2.b)::smallint)), (PARTIAL sum(pagg_tab_2.b)), (PARTIAL sum(pagg_tab_2.c_interval)), (PARTIAL sum(pagg_tab_2.c_money))
+ Relations: Aggregate on (public.fpagg_tab_p3 pagg_tab_2)
+ Remote SQL: SELECT array_agg_p_anyarray(c_int4array), array_agg_p_anynonarray(b), avg_p_int2(b::smallint), avg_p_int4(b), avg_p_int8(b::bigint), avg_p_interval(c_interval), avg_p_float4(b::real), avg_p_float8(b::double precision), avg_p_numeric(b::numeric), corr_p(b::double precision, (b * b)::double precision), covar_pop_p(b::double precision, (b * b)::double precision), covar_samp_p(b::double precision, (b * b)::double precision), regr_avgx_p((2 * b)::double precision, b::double precision), regr_avgy_p((2 * b)::double precision, b::double precision), regr_intercept_p(((2 * b) + 3)::double precision, b::double precision), regr_r2_p((b * b)::double precision, b::double precision), regr_slope_p(((2 * b) + 3)::double precision, b::double precision), regr_sxx_p(((2 * b) + 3)::double precision, b::double precision), regr_sxy_p((b * b)::double precision, b::double precision), regr_syy_p(((2 * b) + 3)::double precision, b::double precision), stddev_p_float4(b::real), stddev_p_float8(b::double precision), stddev_p_int2(b::smallint), stddev_p_int4(b), stddev_p_int8(b::bigint), stddev_p_numeric(b::numeric), stddev_pop_p_float4(b::real), stddev_pop_p_float8(b::double precision), stddev_pop_p_int2(b::smallint), stddev_pop_p_int4(b), stddev_pop_p_int8(b::bigint), stddev_pop_p_numeric(b::numeric), stddev_samp_p_float4(b::real), stddev_samp_p_float8(b::double precision), stddev_samp_p_int2(b::smallint), stddev_samp_p_int4(b), stddev_samp_p_int8(b::bigint), stddev_samp_p_numeric(b::numeric), string_agg_p_text_text(c_1c, ','::text), string_agg_p_bytea_bytea(c_1b, E'\\x2c'::bytea), sum_p_int8(b::bigint), sum_p_numeric(b::numeric), variance_p_float4(b::real), variance_p_float8(b::double precision), variance_p_int2(b::smallint), variance_p_int4(b), variance_p_int8(b::bigint), variance_p_numeric(b::numeric), var_pop_p_float4(b::real), var_pop_p_float8(b::double precision), var_pop_p_int2(b::smallint), var_pop_p_int4(b), var_pop_p_int8(b::bigint), var_pop_p_numeric(b::numeric), var_samp_p_float4(b::real), var_samp_p_float8(b::double precision), var_samp_p_int2(b::smallint), var_samp_p_int4(b), var_samp_p_int8(b::bigint), var_samp_p_numeric(b::numeric), any_value((b * 0)), bit_and(c_bit), bit_and(c_1or3int2), bit_and(c_1or3int4), bit_and(c_1or3int8), bit_or(c_bit), bit_or(c_1or3int2), bit_or(c_1or3int4), bit_or(c_1or3int8), bit_xor(c_bit), bit_xor(c_1or3int2), bit_xor(c_1or3int4), bit_xor(c_1or3int8), bool_and(c_bool), bool_or(c_bool), count(b), count(*), every(c_bool), max(c_int4array), max(c_enum), max(c_1c::character(1)), max(('01-01-2000'::date + b)), max(('0.0.0.0'::inet + b)), max(b::real), max(b::double precision), max(b::smallint), max(b), max(b::bigint), max(c_interval), max(c_money), max(b::numeric), max(b::oid), max(c_pg_lsn), max(c_tid), max(c_1c), max(c_time), max(c_timetz), max(c_timestamp), max(c_timestamptz), max(c_xid8), min(c_int4array), min(c_enum), min(c_1c::character(1)), min(('01-01-2000'::date + b)), min(('0.0.0.0'::inet + b)), min(b::real), min(b::double precision), min(b::smallint), min(b), min(b::bigint), min(c_interval), min(c_money), min(b::numeric), min(b::oid), min(c_pg_lsn), min(c_tid), min(c_1c), min(c_time), min(c_timetz), min(c_timestamp), min(c_timestamptz), min(c_xid8), range_intersect_agg(c_int4range), range_intersect_agg(c_int4multirange), regr_count(((2 * b) + 3)::double precision, b::double precision), sum(b::real), sum(b::double precision), sum(b::smallint), sum(b), sum(c_interval), sum(c_money) FROM public.pagg_tab_p3 WHERE ((c_serial >= 1)) AND ((c_serial <= 30))
+(15 rows)
+
+SELECT /* aggregate function <> aggpartialfunc */
+ array_agg(c_int4array), array_agg(b),
+ avg(b::int2), avg(b::int4), avg(b::int8), avg(c_interval),
+ avg(b::float4), avg(b::float8),
+ corr(b::float8, (b * b)::float8),
+ covar_pop(b::float8, (b * b)::float8),
+ covar_samp(b::float8, (b * b)::float8),
+ regr_avgx((2 * b)::float8, b::float8),
+ regr_avgy((2 * b)::float8, b::float8),
+ regr_intercept((2 * b + 3)::float8, b::float8),
+ regr_r2((b * b)::float8, b::float8),
+ regr_slope((2 * b + 3)::float8, b::float8),
+ regr_sxx((2 * b + 3)::float8, b::float8),
+ regr_sxy((b * b)::float8, b::float8),
+ regr_syy((2 * b + 3)::float8, b::float8),
+ stddev(b::float4), stddev(b::float8), stddev(b::int2), stddev(b::int4), stddev(b::int8), stddev(b::numeric),
+ stddev_pop(b::float4), stddev_pop(b::float8), stddev_pop(b::int2), stddev_pop(b::int4), stddev_pop(b::int8), stddev_pop(b::numeric),
+ stddev_samp(b::float4), stddev_samp(b::float8), stddev_samp(b::int2), stddev_samp(b::int4), stddev_samp(b::int8), stddev_samp(b::numeric),
+ string_agg(c_1c, ','), string_agg(c_1b, ','),
+ sum(b::int8), sum(b::numeric),
+ variance(b::float4), variance(b::float8), variance(b::int2), variance(b::int4), variance(b::int8), variance(b::numeric),
+ var_pop(b::float4), var_pop(b::float8), var_pop(b::int2), var_pop(b::int4), var_pop(b::int8), var_pop(b::numeric),
+ var_samp(b::float4), var_samp(b::float8), var_samp(b::int2), var_samp(b::int4), var_samp(b::int8), var_samp(b::numeric),
+ /* aggregate function = aggpartialfunc */
+ any_value(b * 0),
+ bit_and(c_bit), bit_and(c_1or3int2), bit_and(c_1or3int4), bit_and(c_1or3int8),
+ bit_or(c_bit), bit_or(c_1or3int2), bit_or(c_1or3int4), bit_or(c_1or3int8),
+ bit_xor(c_bit), bit_xor(c_1or3int2), bit_xor(c_1or3int4), bit_xor(c_1or3int8),
+ bool_and(c_bool),
+ bool_or(c_bool),
+ count(b), count(*),
+ every(c_bool),
+ max(c_int4array), max(c_enum), max(c_1c::char(1)), max('2000-01-01'::date + b), max('0.0.0.0'::inet + b), max(b::float4), max(b::float8), max(b::int2), max(b::int4), max(b::int8), max(c_interval), max(c_money), max(b::numeric), max(b::oid), max(c_pg_lsn), max(c_tid), max(c_1c), max(c_time), max(c_timetz), max(c_timestamp), max(c_timestamptz), max(c_xid8),
+ min(c_int4array), min(c_enum), min(c_1c::char(1)), min('2000-01-01'::date + b), min('0.0.0.0'::inet + b), min(b::float4), min(b::float8), min(b::int2), min(b::int4), min(b::int8), min(c_interval), min(c_money), min(b::numeric), min(b::oid), min(c_pg_lsn), min(c_tid), min(c_1c), min(c_time), min(c_timetz), min(c_timestamp), min(c_timestamptz), min(c_xid8),
+ range_intersect_agg(c_int4range), range_intersect_agg(c_int4multirange),
+ regr_count((2 * b + 3)::float8, b::float8),
+ sum(b::float4), sum(b::float8), sum(b::int2), sum(b::int4), sum(c_interval), sum(c_money)
+ FROM pagg_tab WHERE c_serial between 1 and 30;
+ array_agg | array_agg | avg | avg | avg | avg | avg | avg | corr | covar_pop | covar_samp | regr_avgx | regr_avgy | regr_intercept | regr_r2 | regr_slope | regr_sxx | regr_sxy | regr_syy | stddev | stddev | stddev | stddev | stddev | stddev | stddev_pop | stddev_pop | stddev_pop | stddev_pop | stddev_pop | stddev_pop | stddev_samp | stddev_samp | stddev_samp | stddev_samp | stddev_samp | stddev_samp | string_agg | string_agg | sum | sum | variance | variance | variance | variance | variance | variance | var_pop | var_pop | var_pop | var_pop | var_pop | var_pop | var_samp | var_samp | var_samp | var_samp | var_samp | var_samp | any_value | bit_and | bit_and | bit_and | bit_and | bit_or | bit_or | bit_or | bit_or | bit_xor | bit_xor | bit_xor | bit_xor | bool_and | bool_or | count | count | every | max | max | max | max | max | max | max | max | max | max | max | max | max | max | max | max | max | max | max | max | max | max | min | min | min | min | min | min | min | min | min | min | min | min | min | min | min | min | min | min | min | min | min | min | range_intersect_agg | range_intersect_agg | regr_count | sum | sum | sum | sum | sum | sum
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------+---------------------+---------------------+---------------------+------------+------+------+--------------------+--------------------+------------+-----------+-----------+----------------+--------------------+------------+----------+----------+----------+-------------------+-------------------+--------------------+--------------------+--------------------+--------------------+------------------+------------------+--------------------+--------------------+--------------------+--------------------+-------------------+-------------------+--------------------+--------------------+--------------------+--------------------+-------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------+-----+-----+----------+----------+---------------------+---------------------+---------------------+---------------------+-------------------+-------------------+---------------------+---------------------+---------------------+---------------------+----------+----------+---------------------+---------------------+---------------------+---------------------+-----------+---------+---------+---------+---------+--------+--------+--------+--------+---------+---------+---------+---------+----------+---------+-------+-------+-------+-------+-------+-----+------------+----------+-----+-----+-----+-----+-----+---------+-------+-----+-----+------+--------+-----+----------+-------------+--------------------------+------------------------------+-----+-------+-----+-----+------------+---------+-----+-----+-----+-----+-----+-----+-------+-----+-----+-----+-------+-----+----------+-------------+--------------------------+------------------------------+-----+---------------------+---------------------+------------+-----+-----+-----+-----+-----------+--------
+ {{1,0},{0,0},{1,0},{0,0},{1,0},{0,0},{1,0},{0,0},{1,0},{0,0},{0,0},{1,0},{0,0},{1,0},{0,0},{1,0},{0,0},{1,0},{0,0},{1,0},{0,0},{1,0},{0,0},{1,0},{0,0},{1,0},{0,0},{1,0},{0,0},{1,0}} | {1,2,3,4,5,6,7,8,9,30,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29} | 15.5000000000000000 | 15.5000000000000000 | 15.5000000000000000 | @ 0.5 secs | 15.5 | 15.5 | 0.9702989135892578 | 2322.4166666666665 | 2402.5 | 15.5 | 31 | 3 | 0.9414799817124941 | 2 | 2247.5 | 69672.5 | 8990 | 8.803408430829505 | 8.803408430829505 | 8.8034084308295046 | 8.8034084308295046 | 8.8034084308295046 | 8.8034084308295046 | 8.65544144839919 | 8.65544144839919 | 8.6554414483991899 | 8.6554414483991899 | 8.6554414483991899 | 8.6554414483991899 | 8.803408430829505 | 8.803408430829505 | 8.8034084308295046 | 8.8034084308295046 | 8.8034084308295046 | 8.8034084308295046 | 0,1,2,3,4,5,6,7,8,9,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8 | \x302c312c322c332c342c352c362c372c382c392c392c302c312c322c332c342c352c362c372c382c392c302c312c322c332c342c352c362c372c38 | 465 | 465 | 77.5 | 77.5 | 77.5000000000000000 | 77.5000000000000000 | 77.5000000000000000 | 77.5000000000000000 | 74.91666666666667 | 74.91666666666667 | 74.9166666666666667 | 74.9166666666666667 | 74.9166666666666667 | 74.9166666666666667 | 77.5 | 77.5 | 77.5000000000000000 | 77.5000000000000000 | 77.5000000000000000 | 77.5000000000000000 | 0 | 01 | 1 | 1 | 1 | 11 | 3 | 3 | 3 | 10 | 2 | 2 | 2 | f | t | 30 | 30 | f | {1,0} | happy | 9 | 01-31-2000 | 0.0.0.30 | 30 | 30 | 30 | 30 | 30 | @ 1 sec | $1.00 | 30 | 30 | 0/30 | (0,30) | 9 | 00:00:30 | 00:00:30-07 | Sat Jan 01 00:00:30 2000 | Sat Jan 01 00:00:30 2000 PST | 9 | {0,0} | sad | 0 | 01-02-2000 | 0.0.0.1 | 1 | 1 | 1 | 1 | 1 | @ 0 | $0.00 | 1 | 1 | 0/1 | (0,1) | 0 | 00:00:01 | 00:00:01-07 | Sat Jan 01 00:00:01 2000 | Sat Jan 01 00:00:01 2000 PST | 0 | [0,1) | {[0,1),[100,101)} | 30 | 465 | 465 | 465 | 465 | @ 15 secs | $15.00
+(1 row)
+
+-- Tests for backward compatibility
+ALTER SERVER loopback OPTIONS (ADD check_partial_aggregate_support 'false');
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT b, avg(a), max(a), count(*) FROM pagg_tab GROUP BY b ORDER BY 1;
+ QUERY PLAN
+------------------------------------------------------------------------------------------------------------------------
+ Sort
+ Output: pagg_tab.b, (avg(pagg_tab.a)), (max(pagg_tab.a)), (count(*))
+ Sort Key: pagg_tab.b
+ -> Finalize HashAggregate
+ Output: pagg_tab.b, avg(pagg_tab.a), max(pagg_tab.a), count(*)
+ Group Key: pagg_tab.b
+ -> Append
+ -> Foreign Scan
+ Output: pagg_tab.b, (PARTIAL avg(pagg_tab.a)), (PARTIAL max(pagg_tab.a)), (PARTIAL count(*))
+ Relations: Aggregate on (public.fpagg_tab_p1 pagg_tab)
+ Remote SQL: SELECT b, avg_p_int4(a), max(a), count(*) FROM public.pagg_tab_p1 GROUP BY 1
+ -> Foreign Scan
+ Output: pagg_tab_1.b, (PARTIAL avg(pagg_tab_1.a)), (PARTIAL max(pagg_tab_1.a)), (PARTIAL count(*))
+ Relations: Aggregate on (public.fpagg_tab_p2 pagg_tab_1)
+ Remote SQL: SELECT b, avg_p_int4(a), max(a), count(*) FROM public.pagg_tab_p2 GROUP BY 1
+ -> Foreign Scan
+ Output: pagg_tab_2.b, (PARTIAL avg(pagg_tab_2.a)), (PARTIAL max(pagg_tab_2.a)), (PARTIAL count(*))
+ Relations: Aggregate on (public.fpagg_tab_p3 pagg_tab_2)
+ Remote SQL: SELECT b, avg_p_int4(a), max(a), count(*) FROM public.pagg_tab_p3 GROUP BY 1
+(19 rows)
+
+SELECT b, avg(a), max(a), count(*) FROM pagg_tab GROUP BY b ORDER BY 1;
+ b | avg | max | count
+----+---------------------+-----+-------
+ 0 | 10.0000000000000000 | 20 | 60
+ 1 | 11.0000000000000000 | 21 | 60
+ 2 | 12.0000000000000000 | 22 | 60
+ 3 | 13.0000000000000000 | 23 | 60
+ 4 | 14.0000000000000000 | 24 | 60
+ 5 | 15.0000000000000000 | 25 | 60
+ 6 | 16.0000000000000000 | 26 | 60
+ 7 | 17.0000000000000000 | 27 | 60
+ 8 | 18.0000000000000000 | 28 | 60
+ 9 | 19.0000000000000000 | 29 | 60
+ 10 | 10.0000000000000000 | 20 | 60
+ 11 | 11.0000000000000000 | 21 | 60
+ 12 | 12.0000000000000000 | 22 | 60
+ 13 | 13.0000000000000000 | 23 | 60
+ 14 | 14.0000000000000000 | 24 | 60
+ 15 | 15.0000000000000000 | 25 | 60
+ 16 | 16.0000000000000000 | 26 | 60
+ 17 | 17.0000000000000000 | 27 | 60
+ 18 | 18.0000000000000000 | 28 | 60
+ 19 | 19.0000000000000000 | 29 | 60
+ 20 | 10.0000000000000000 | 20 | 60
+ 21 | 11.0000000000000000 | 21 | 60
+ 22 | 12.0000000000000000 | 22 | 60
+ 23 | 13.0000000000000000 | 23 | 60
+ 24 | 14.0000000000000000 | 24 | 60
+ 25 | 15.0000000000000000 | 25 | 60
+ 26 | 16.0000000000000000 | 26 | 60
+ 27 | 17.0000000000000000 | 27 | 60
+ 28 | 18.0000000000000000 | 28 | 60
+ 29 | 19.0000000000000000 | 29 | 60
+ 30 | 10.0000000000000000 | 20 | 60
+ 31 | 11.0000000000000000 | 21 | 60
+ 32 | 12.0000000000000000 | 22 | 60
+ 33 | 13.0000000000000000 | 23 | 60
+ 34 | 14.0000000000000000 | 24 | 60
+ 35 | 15.0000000000000000 | 25 | 60
+ 36 | 16.0000000000000000 | 26 | 60
+ 37 | 17.0000000000000000 | 27 | 60
+ 38 | 18.0000000000000000 | 28 | 60
+ 39 | 19.0000000000000000 | 29 | 60
+ 40 | 10.0000000000000000 | 20 | 60
+ 41 | 11.0000000000000000 | 21 | 60
+ 42 | 12.0000000000000000 | 22 | 60
+ 43 | 13.0000000000000000 | 23 | 60
+ 44 | 14.0000000000000000 | 24 | 60
+ 45 | 15.0000000000000000 | 25 | 60
+ 46 | 16.0000000000000000 | 26 | 60
+ 47 | 17.0000000000000000 | 27 | 60
+ 48 | 18.0000000000000000 | 28 | 60
+ 49 | 19.0000000000000000 | 29 | 60
+(50 rows)
+
+ALTER SERVER loopback OPTIONS (SET check_partial_aggregate_support 'true');
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT b, avg(a), max(a), count(*) FROM pagg_tab GROUP BY b ORDER BY 1;
+ QUERY PLAN
+------------------------------------------------------------------------------------------------------------------------
+ Sort
+ Output: pagg_tab.b, (avg(pagg_tab.a)), (max(pagg_tab.a)), (count(*))
+ Sort Key: pagg_tab.b
+ -> Finalize HashAggregate
+ Output: pagg_tab.b, avg(pagg_tab.a), max(pagg_tab.a), count(*)
+ Group Key: pagg_tab.b
+ -> Append
+ -> Foreign Scan
+ Output: pagg_tab.b, (PARTIAL avg(pagg_tab.a)), (PARTIAL max(pagg_tab.a)), (PARTIAL count(*))
+ Relations: Aggregate on (public.fpagg_tab_p1 pagg_tab)
+ Remote SQL: SELECT b, avg_p_int4(a), max(a), count(*) FROM public.pagg_tab_p1 GROUP BY 1
+ -> Foreign Scan
+ Output: pagg_tab_1.b, (PARTIAL avg(pagg_tab_1.a)), (PARTIAL max(pagg_tab_1.a)), (PARTIAL count(*))
+ Relations: Aggregate on (public.fpagg_tab_p2 pagg_tab_1)
+ Remote SQL: SELECT b, avg_p_int4(a), max(a), count(*) FROM public.pagg_tab_p2 GROUP BY 1
+ -> Foreign Scan
+ Output: pagg_tab_2.b, (PARTIAL avg(pagg_tab_2.a)), (PARTIAL max(pagg_tab_2.a)), (PARTIAL count(*))
+ Relations: Aggregate on (public.fpagg_tab_p3 pagg_tab_2)
+ Remote SQL: SELECT b, avg_p_int4(a), max(a), count(*) FROM public.pagg_tab_p3 GROUP BY 1
+(19 rows)
+
+SELECT b, avg(a), max(a), count(*) FROM pagg_tab GROUP BY b ORDER BY 1;
+ b | avg | max | count
+----+---------------------+-----+-------
+ 0 | 10.0000000000000000 | 20 | 60
+ 1 | 11.0000000000000000 | 21 | 60
+ 2 | 12.0000000000000000 | 22 | 60
+ 3 | 13.0000000000000000 | 23 | 60
+ 4 | 14.0000000000000000 | 24 | 60
+ 5 | 15.0000000000000000 | 25 | 60
+ 6 | 16.0000000000000000 | 26 | 60
+ 7 | 17.0000000000000000 | 27 | 60
+ 8 | 18.0000000000000000 | 28 | 60
+ 9 | 19.0000000000000000 | 29 | 60
+ 10 | 10.0000000000000000 | 20 | 60
+ 11 | 11.0000000000000000 | 21 | 60
+ 12 | 12.0000000000000000 | 22 | 60
+ 13 | 13.0000000000000000 | 23 | 60
+ 14 | 14.0000000000000000 | 24 | 60
+ 15 | 15.0000000000000000 | 25 | 60
+ 16 | 16.0000000000000000 | 26 | 60
+ 17 | 17.0000000000000000 | 27 | 60
+ 18 | 18.0000000000000000 | 28 | 60
+ 19 | 19.0000000000000000 | 29 | 60
+ 20 | 10.0000000000000000 | 20 | 60
+ 21 | 11.0000000000000000 | 21 | 60
+ 22 | 12.0000000000000000 | 22 | 60
+ 23 | 13.0000000000000000 | 23 | 60
+ 24 | 14.0000000000000000 | 24 | 60
+ 25 | 15.0000000000000000 | 25 | 60
+ 26 | 16.0000000000000000 | 26 | 60
+ 27 | 17.0000000000000000 | 27 | 60
+ 28 | 18.0000000000000000 | 28 | 60
+ 29 | 19.0000000000000000 | 29 | 60
+ 30 | 10.0000000000000000 | 20 | 60
+ 31 | 11.0000000000000000 | 21 | 60
+ 32 | 12.0000000000000000 | 22 | 60
+ 33 | 13.0000000000000000 | 23 | 60
+ 34 | 14.0000000000000000 | 24 | 60
+ 35 | 15.0000000000000000 | 25 | 60
+ 36 | 16.0000000000000000 | 26 | 60
+ 37 | 17.0000000000000000 | 27 | 60
+ 38 | 18.0000000000000000 | 28 | 60
+ 39 | 19.0000000000000000 | 29 | 60
+ 40 | 10.0000000000000000 | 20 | 60
+ 41 | 11.0000000000000000 | 21 | 60
+ 42 | 12.0000000000000000 | 22 | 60
+ 43 | 13.0000000000000000 | 23 | 60
+ 44 | 14.0000000000000000 | 24 | 60
+ 45 | 15.0000000000000000 | 25 | 60
+ 46 | 16.0000000000000000 | 26 | 60
+ 47 | 17.0000000000000000 | 27 | 60
+ 48 | 18.0000000000000000 | 28 | 60
+ 49 | 19.0000000000000000 | 29 | 60
+(50 rows)
+
+ALTER SERVER loopback OPTIONS (SET fdw_tuple_cost '1.0');
+SET enable_partitionwise_join=on;
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT avg(t1.b), avg(t1.b::int8) FROM pagg_tab t1 JOIN pagg_tab t2 USING(a);
+ QUERY PLAN
+----------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Finalize Aggregate
+ Output: avg(t1.b), avg((t1.b)::bigint)
+ -> Append
+ -> Foreign Scan
+ Output: (PARTIAL avg(t1.b)), (PARTIAL avg((t1.b)::bigint))
+ Relations: Aggregate on ((public.fpagg_tab_p1 t1) INNER JOIN (public.fpagg_tab_p1 t2))
+ Remote SQL: SELECT avg_p_int4(r4.b), avg_p_int8(r4.b::bigint) FROM (public.pagg_tab_p1 r4 INNER JOIN public.pagg_tab_p1 r7 ON (((r4.a = r7.a))))
+ -> Foreign Scan
+ Output: (PARTIAL avg(t1_1.b)), (PARTIAL avg((t1_1.b)::bigint))
+ Relations: Aggregate on ((public.fpagg_tab_p2 t1_1) INNER JOIN (public.fpagg_tab_p2 t2_1))
+ Remote SQL: SELECT avg_p_int4(r5.b), avg_p_int8(r5.b::bigint) FROM (public.pagg_tab_p2 r5 INNER JOIN public.pagg_tab_p2 r8 ON (((r5.a = r8.a))))
+ -> Foreign Scan
+ Output: (PARTIAL avg(t1_2.b)), (PARTIAL avg((t1_2.b)::bigint))
+ Relations: Aggregate on ((public.fpagg_tab_p3 t1_2) INNER JOIN (public.fpagg_tab_p3 t2_2))
+ Remote SQL: SELECT avg_p_int4(r6.b), avg_p_int8(r6.b::bigint) FROM (public.pagg_tab_p3 r6 INNER JOIN public.pagg_tab_p3 r9 ON (((r6.a = r9.a))))
(15 rows)
+SELECT avg(t1.b), avg(t1.b::int8) FROM pagg_tab t1 JOIN pagg_tab t2 USING(a);
+ avg | avg
+---------------------+---------------------
+ 24.5000000000000000 | 24.5000000000000000
+(1 row)
+
+RESET enable_partitionwise_join;
+ALTER SERVER loopback OPTIONS (SET fdw_tuple_cost '0.1');
+ALTER SERVER loopback OPTIONS (DROP check_partial_aggregate_support);
+-- List of aggregate functions such that the aggregate function supports partial aggregate
+-- and aggpartialfn field of the aggregate function is invalid
+SELECT aggfnoid::text
+ FROM pg_aggregate a JOIN pg_type b ON a.aggtranstype = b.oid
+ WHERE (aggcombinefn::text <> '-') AND (aggpartialfn::text = '-')
+ ORDER BY 1;
+ aggfnoid
+----------
+(0 rows)
+
+-- List of aggregate functions which have incorrect aggpartialfunc
+SELECT a.aggfnoid
+ FROM pg_aggregate a JOIN pg_type b ON a.aggtranstype = b.oid
+ JOIN pg_aggregate c on a.aggpartialfn = c.aggfnoid
+ WHERE (a.aggcombinefn::text <> '-')
+ AND (a.aggpartialfn::text <> '-')
+ AND (a.aggtransfn <> c.aggtransfn
+ OR (c.aggcombinefn::text <> '-'
+ AND a.aggcombinefn <> c.aggcombinefn)
+ OR (a.agginitval IS NOT NULL
+ AND c.agginitval IS NOT NULL
+ AND a.agginitval <> c.agginitval)
+ OR (b.typname = 'internal'
+ AND c.aggserialfn::text <> '-'
+ AND a.aggserialfn <> c.aggserialfn)
+ OR (b.typname = 'internal'
+ AND c.aggdeserialfn::text <> '-'
+ AND a.aggdeserialfn <> c.aggdeserialfn)
+ OR (b.typname = 'internal'
+ AND a.aggserialfn <> c.aggfinalfn)
+ OR (b.typname <> 'internal'
+ AND c.aggfinalfn::text <> '-'))
+ ORDER BY 1;
+ aggfnoid
+----------
+(0 rows)
+
+-- It is unsafe to push down partial aggregates which contain DISTINCT clauses
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT max(a), count(distinct b) FROM pagg_tab;
+ QUERY PLAN
+-----------------------------------------------------------------------------------------
+ Aggregate
+ Output: max(pagg_tab.a), count(DISTINCT pagg_tab.b)
+ -> Merge Append
+ Sort Key: pagg_tab.b
+ -> Foreign Scan on public.fpagg_tab_p1 pagg_tab_1
+ Output: pagg_tab_1.a, pagg_tab_1.b
+ Remote SQL: SELECT a, b FROM public.pagg_tab_p1 ORDER BY b ASC NULLS LAST
+ -> Foreign Scan on public.fpagg_tab_p2 pagg_tab_2
+ Output: pagg_tab_2.a, pagg_tab_2.b
+ Remote SQL: SELECT a, b FROM public.pagg_tab_p2 ORDER BY b ASC NULLS LAST
+ -> Foreign Scan on public.fpagg_tab_p3 pagg_tab_3
+ Output: pagg_tab_3.a, pagg_tab_3.b
+ Remote SQL: SELECT a, b FROM public.pagg_tab_p3 ORDER BY b ASC NULLS LAST
+(13 rows)
+
+SELECT max(a), count(distinct b) FROM pagg_tab;
+ max | count
+-----+-------
+ 29 | 50
+(1 row)
+
+-- It is unsafe to push down partial aggregates which contain ORDER BY clauses
+EXPLAIN (VERBOSE, COSTS OFF) SELECT array_agg(b order by b) FROM pagg_tab WHERE c_serial between 1 and 30;
+ QUERY PLAN
+-----------------------------------------------------------------------------------------------------------------
+ Aggregate
+ Output: array_agg(pagg_tab.b ORDER BY pagg_tab.b)
+ -> Sort
+ Output: pagg_tab.b
+ Sort Key: pagg_tab.b
+ -> Append
+ -> Foreign Scan on public.fpagg_tab_p1 pagg_tab_1
+ Output: pagg_tab_1.b
+ Remote SQL: SELECT b FROM public.pagg_tab_p1 WHERE ((c_serial >= 1)) AND ((c_serial <= 30))
+ -> Foreign Scan on public.fpagg_tab_p2 pagg_tab_2
+ Output: pagg_tab_2.b
+ Remote SQL: SELECT b FROM public.pagg_tab_p2 WHERE ((c_serial >= 1)) AND ((c_serial <= 30))
+ -> Foreign Scan on public.fpagg_tab_p3 pagg_tab_3
+ Output: pagg_tab_3.b
+ Remote SQL: SELECT b FROM public.pagg_tab_p3 WHERE ((c_serial >= 1)) AND ((c_serial <= 30))
+(15 rows)
+
+SELECT array_agg(b order by b) FROM pagg_tab WHERE c_serial between 1 and 30;
+ array_agg
+------------------------------------------------------------------------------------
+ {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30}
+(1 row)
+
+-- Create user-defined aggregates whose stype is internal
+CREATE SCHEMA postgres_fdw_test;
+CREATE AGGREGATE postgres_fdw_test.postgres_fdw_sum_p_int8(int8) (
+ SFUNC = int8_avg_accum,
+ STYPE = internal,
+ COMBINEFUNC = int8_avg_combine,
+ FINALFUNC = int8_avg_serialize,
+ SERIALFUNC = int8_avg_serialize,
+ DESERIALFUNC = int8_avg_deserialize,
+ AGGPARTIALFUNC = postgres_fdw_test.postgres_fdw_sum_p_int8
+);
+CREATE AGGREGATE postgres_fdw_sum(int8) (
+ SFUNC = int8_avg_accum,
+ STYPE = internal,
+ COMBINEFUNC = int8_avg_combine,
+ FINALFUNC = numeric_poly_sum,
+ SERIALFUNC = int8_avg_serialize,
+ DESERIALFUNC = int8_avg_deserialize,
+ AGGPARTIALFUNC = postgres_fdw_test.postgres_fdw_sum_p_int8
+);
+-- Create user-defined aggregates whose stype is not internal
+CREATE AGGREGATE postgres_fdw_avg_p_int4(int4) (
+ SFUNC = int4_avg_accum,
+ STYPE = _int8,
+ COMBINEFUNC = int4_avg_combine,
+ INITCOND = '{0,0}',
+ AGGPARTIALFUNC = postgres_fdw_avg_p_int4
+);
+CREATE AGGREGATE postgres_fdw_avg(int4) (
+ SFUNC = int4_avg_accum,
+ STYPE = _int8,
+ COMBINEFUNC = int4_avg_combine,
+ FINALFUNC = int8_avg,
+ INITCOND = '{0,0}',
+ AGGPARTIALFUNC = postgres_fdw_avg_p_int4
+);
+CREATE AGGREGATE postgres_fdw_sum_noaggpartialfunc(int8) (
+ SFUNC = int8_avg_accum,
+ STYPE = internal,
+ COMBINEFUNC = int8_avg_combine,
+ FINALFUNC = numeric_poly_sum,
+ SERIALFUNC = int8_avg_serialize,
+ DESERIALFUNC = int8_avg_deserialize
+);
+-- It's safe to push down partial aggregates for user-defined aggregate
+-- when it belongs to an extension that is listed in the extension setting
+-- and when its aggpartialfunc belongs to an extension that is listed
+-- in the extension setting.
+ALTER EXTENSION postgres_fdw ADD FUNCTION postgres_fdw_sum(int8);
+ALTER EXTENSION postgres_fdw ADD FUNCTION postgres_fdw_test.postgres_fdw_sum_p_int8(int8);
+ALTER EXTENSION postgres_fdw ADD FUNCTION postgres_fdw_avg(int4);
+ALTER EXTENSION postgres_fdw ADD FUNCTION postgres_fdw_avg_p_int4(int4);
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT postgres_fdw_sum(b::int8) FROM pagg_tab;
+ QUERY PLAN
+---------------------------------------------------------------------------------------------------------------
+ Finalize Aggregate
+ Output: postgres_fdw_sum((pagg_tab.b)::bigint)
+ -> Append
+ -> Foreign Scan
+ Output: (PARTIAL postgres_fdw_sum((pagg_tab.b)::bigint))
+ Relations: Aggregate on (public.fpagg_tab_p1 pagg_tab)
+ Remote SQL: SELECT postgres_fdw_test.postgres_fdw_sum_p_int8(b::bigint) FROM public.pagg_tab_p1
+ -> Foreign Scan
+ Output: (PARTIAL postgres_fdw_sum((pagg_tab_1.b)::bigint))
+ Relations: Aggregate on (public.fpagg_tab_p2 pagg_tab_1)
+ Remote SQL: SELECT postgres_fdw_test.postgres_fdw_sum_p_int8(b::bigint) FROM public.pagg_tab_p2
+ -> Foreign Scan
+ Output: (PARTIAL postgres_fdw_sum((pagg_tab_2.b)::bigint))
+ Relations: Aggregate on (public.fpagg_tab_p3 pagg_tab_2)
+ Remote SQL: SELECT postgres_fdw_test.postgres_fdw_sum_p_int8(b::bigint) FROM public.pagg_tab_p3
+(15 rows)
+
+SELECT postgres_fdw_sum(b::int8) FROM pagg_tab;
+ postgres_fdw_sum
+------------------
+ 73500
+(1 row)
+
+-- It is unsafe to push down partial aggregates for user-defined aggregates
+-- when they have no aggpartialfunc.
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT postgres_fdw_sum_noaggpartialfunc(b::int8) FROM pagg_tab;
+ QUERY PLAN
+-----------------------------------------------------------------------------------------
+ Finalize Aggregate
+ Output: postgres_fdw_sum_noaggpartialfunc((pagg_tab.b)::bigint)
+ -> Append
+ -> Partial Aggregate
+ Output: PARTIAL postgres_fdw_sum_noaggpartialfunc((pagg_tab.b)::bigint)
+ -> Foreign Scan on public.fpagg_tab_p1 pagg_tab
+ Output: pagg_tab.b
+ Remote SQL: SELECT b FROM public.pagg_tab_p1
+ -> Partial Aggregate
+ Output: PARTIAL postgres_fdw_sum_noaggpartialfunc((pagg_tab_1.b)::bigint)
+ -> Foreign Scan on public.fpagg_tab_p2 pagg_tab_1
+ Output: pagg_tab_1.b
+ Remote SQL: SELECT b FROM public.pagg_tab_p2
+ -> Partial Aggregate
+ Output: PARTIAL postgres_fdw_sum_noaggpartialfunc((pagg_tab_2.b)::bigint)
+ -> Foreign Scan on public.fpagg_tab_p3 pagg_tab_2
+ Output: pagg_tab_2.b
+ Remote SQL: SELECT b FROM public.pagg_tab_p3
+(18 rows)
+
+SELECT postgres_fdw_sum_noaggpartialfunc(b::int8) FROM pagg_tab;
+ postgres_fdw_sum_noaggpartialfunc
+-----------------------------------
+ 73500
+(1 row)
+
+ALTER EXTENSION postgres_fdw DROP FUNCTION postgres_fdw_test.postgres_fdw_sum_p_int8(int8);
+-- Reconnect for flushing the shippability cache
+\c -
+SET enable_partitionwise_aggregate TO true;
+-- It is unsafe to push down partial aggregates for user-defined aggregates
+-- when itself is aggpartialfunc and when it belongs to an extension
+-- that's listed in the extension setting and when stype is internal.
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT postgres_fdw_test.postgres_fdw_sum_p_int8(b::int8) FROM pagg_tab;
+ QUERY PLAN
+-------------------------------------------------------------------------------------------------
+ Finalize Aggregate
+ Output: postgres_fdw_test.postgres_fdw_sum_p_int8((pagg_tab.b)::bigint)
+ -> Append
+ -> Partial Aggregate
+ Output: PARTIAL postgres_fdw_test.postgres_fdw_sum_p_int8((pagg_tab.b)::bigint)
+ -> Foreign Scan on public.fpagg_tab_p1 pagg_tab
+ Output: pagg_tab.b
+ Remote SQL: SELECT b FROM public.pagg_tab_p1
+ -> Partial Aggregate
+ Output: PARTIAL postgres_fdw_test.postgres_fdw_sum_p_int8((pagg_tab_1.b)::bigint)
+ -> Foreign Scan on public.fpagg_tab_p2 pagg_tab_1
+ Output: pagg_tab_1.b
+ Remote SQL: SELECT b FROM public.pagg_tab_p2
+ -> Partial Aggregate
+ Output: PARTIAL postgres_fdw_test.postgres_fdw_sum_p_int8((pagg_tab_2.b)::bigint)
+ -> Foreign Scan on public.fpagg_tab_p3 pagg_tab_2
+ Output: pagg_tab_2.b
+ Remote SQL: SELECT b FROM public.pagg_tab_p3
+(18 rows)
+
+SELECT postgres_fdw_test.postgres_fdw_sum_p_int8(b::int8) FROM pagg_tab;
+ postgres_fdw_sum_p_int8
+------------------------------------------------------------
+ \x0000000000000bb80000000200000001000000000000000000070dac
+(1 row)
+
+ALTER EXTENSION postgres_fdw DROP FUNCTION postgres_fdw_sum(int8);
+ALTER EXTENSION postgres_fdw ADD FUNCTION postgres_fdw_test.postgres_fdw_sum_p_int8(int8);
+-- Reconnect for flushing the shippability cache
+\c -
+SET enable_partitionwise_aggregate TO true;
+-- It is unsafe to push down partial aggregates for user-defined aggregates
+-- when it doesn't belong to an extension that is listed in the extension setting
+-- and when its aggpartialfunc belongs to an extension that is listed
+-- in the extension setting.
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT postgres_fdw_sum(b::int8) FROM pagg_tab;
+ QUERY PLAN
+------------------------------------------------------------------------
+ Finalize Aggregate
+ Output: postgres_fdw_sum((pagg_tab.b)::bigint)
+ -> Append
+ -> Partial Aggregate
+ Output: PARTIAL postgres_fdw_sum((pagg_tab.b)::bigint)
+ -> Foreign Scan on public.fpagg_tab_p1 pagg_tab
+ Output: pagg_tab.b
+ Remote SQL: SELECT b FROM public.pagg_tab_p1
+ -> Partial Aggregate
+ Output: PARTIAL postgres_fdw_sum((pagg_tab_1.b)::bigint)
+ -> Foreign Scan on public.fpagg_tab_p2 pagg_tab_1
+ Output: pagg_tab_1.b
+ Remote SQL: SELECT b FROM public.pagg_tab_p2
+ -> Partial Aggregate
+ Output: PARTIAL postgres_fdw_sum((pagg_tab_2.b)::bigint)
+ -> Foreign Scan on public.fpagg_tab_p3 pagg_tab_2
+ Output: pagg_tab_2.b
+ Remote SQL: SELECT b FROM public.pagg_tab_p3
+(18 rows)
+
+SELECT postgres_fdw_sum(b::int8) FROM pagg_tab;
+ postgres_fdw_sum
+------------------
+ 73500
+(1 row)
+
+-- It's safe to push down partial aggregates for user-defined aggregate
+-- whose stype is not internal
+-- when it belongs to an extension that is listed in the extension setting
+-- and when its aggpartialfunc belongs to an extension that is listed
+-- in the extension setting.
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT postgres_fdw_avg(b) FROM pagg_tab;
+ QUERY PLAN
+--------------------------------------------------------------------------------------------
+ Finalize Aggregate
+ Output: postgres_fdw_avg(pagg_tab.b)
+ -> Append
+ -> Foreign Scan
+ Output: (PARTIAL postgres_fdw_avg(pagg_tab.b))
+ Relations: Aggregate on (public.fpagg_tab_p1 pagg_tab)
+ Remote SQL: SELECT public.postgres_fdw_avg_p_int4(b) FROM public.pagg_tab_p1
+ -> Foreign Scan
+ Output: (PARTIAL postgres_fdw_avg(pagg_tab_1.b))
+ Relations: Aggregate on (public.fpagg_tab_p2 pagg_tab_1)
+ Remote SQL: SELECT public.postgres_fdw_avg_p_int4(b) FROM public.pagg_tab_p2
+ -> Foreign Scan
+ Output: (PARTIAL postgres_fdw_avg(pagg_tab_2.b))
+ Relations: Aggregate on (public.fpagg_tab_p3 pagg_tab_2)
+ Remote SQL: SELECT public.postgres_fdw_avg_p_int4(b) FROM public.pagg_tab_p3
+(15 rows)
+
+SELECT postgres_fdw_avg(b) FROM pagg_tab;
+ postgres_fdw_avg
+---------------------
+ 24.5000000000000000
+(1 row)
+
+-- It's safe to push down partial aggregates for user-defined aggregate
+-- when itself is aggpartialfunc and when it belongs to an extension
+-- that's listed in the extension setting and when stype is not internal.
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT postgres_fdw_avg_p_int4(b) FROM pagg_tab;
+ QUERY PLAN
+--------------------------------------------------------------------------------------------
+ Finalize Aggregate
+ Output: postgres_fdw_avg_p_int4(pagg_tab.b)
+ -> Append
+ -> Foreign Scan
+ Output: (PARTIAL postgres_fdw_avg_p_int4(pagg_tab.b))
+ Relations: Aggregate on (public.fpagg_tab_p1 pagg_tab)
+ Remote SQL: SELECT public.postgres_fdw_avg_p_int4(b) FROM public.pagg_tab_p1
+ -> Foreign Scan
+ Output: (PARTIAL postgres_fdw_avg_p_int4(pagg_tab_1.b))
+ Relations: Aggregate on (public.fpagg_tab_p2 pagg_tab_1)
+ Remote SQL: SELECT public.postgres_fdw_avg_p_int4(b) FROM public.pagg_tab_p2
+ -> Foreign Scan
+ Output: (PARTIAL postgres_fdw_avg_p_int4(pagg_tab_2.b))
+ Relations: Aggregate on (public.fpagg_tab_p3 pagg_tab_2)
+ Remote SQL: SELECT public.postgres_fdw_avg_p_int4(b) FROM public.pagg_tab_p3
+(15 rows)
+
+SELECT postgres_fdw_avg_p_int4(b) FROM pagg_tab;
+ postgres_fdw_avg_p_int4
+-------------------------
+ {3000,73500}
+(1 row)
+
+ALTER EXTENSION postgres_fdw DROP TYPE mood;
+ALTER EXTENSION postgres_fdw DROP FUNCTION postgres_fdw_test.postgres_fdw_sum_p_int8(int8);
+ALTER EXTENSION postgres_fdw DROP FUNCTION postgres_fdw_avg_p_int4(int4);
+ALTER EXTENSION postgres_fdw DROP FUNCTION postgres_fdw_avg(int4);
+DROP AGGREGATE postgres_fdw_sum(int8);
+DROP AGGREGATE postgres_fdw_test.postgres_fdw_sum_p_int8(int8);
+DROP SCHEMA postgres_fdw_test;
+DROP AGGREGATE postgres_fdw_avg(int4);
+DROP AGGREGATE postgres_fdw_avg_p_int4(int4);
+DROP AGGREGATE postgres_fdw_sum_noaggpartialfunc(int8);
+ALTER SERVER loopback OPTIONS (DROP fdw_tuple_cost);
-- ===================================================================
-- access rights and superuser
-- ===================================================================
diff --git a/contrib/postgres_fdw/option.c b/contrib/postgres_fdw/option.c
index 8c822f4ef9..67e15c8bb9 100644
--- a/contrib/postgres_fdw/option.c
+++ b/contrib/postgres_fdw/option.c
@@ -126,7 +126,8 @@ postgres_fdw_validator(PG_FUNCTION_ARGS)
strcmp(def->defname, "async_capable") == 0 ||
strcmp(def->defname, "parallel_commit") == 0 ||
strcmp(def->defname, "parallel_abort") == 0 ||
- strcmp(def->defname, "keep_connections") == 0)
+ strcmp(def->defname, "keep_connections") == 0 ||
+ strcmp(def->defname, "check_partial_aggregate_support") == 0)
{
/* these accept only boolean values */
(void) defGetBoolean(def);
@@ -268,6 +269,7 @@ InitPgFdwOptions(void)
/* batch_size is available on both server and table */
{"batch_size", ForeignServerRelationId, false},
{"batch_size", ForeignTableRelationId, false},
+ {"check_partial_aggregate_support", ForeignServerRelationId, false},
/* async_capable is available on both server and table */
{"async_capable", ForeignServerRelationId, false},
{"async_capable", ForeignTableRelationId, false},
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 8b3206ceaa..20e2bfa2d7 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -36,6 +36,7 @@
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/planmain.h"
+#include "optimizer/planner.h"
#include "optimizer/prep.h"
#include "optimizer/restrictinfo.h"
#include "optimizer/tlist.h"
@@ -519,7 +520,7 @@ static bool foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel,
JoinType jointype, RelOptInfo *outerrel, RelOptInfo *innerrel,
JoinPathExtraData *extra);
static bool foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel,
- Node *havingQual);
+ GroupPathExtraData *extra);
static List *get_useful_pathkeys_for_relation(PlannerInfo *root,
RelOptInfo *rel);
static List *get_useful_ecs_for_relation(PlannerInfo *root, RelOptInfo *rel);
@@ -650,6 +651,8 @@ postgresGetForeignRelSize(PlannerInfo *root,
fpinfo->fdw_tuple_cost = DEFAULT_FDW_TUPLE_COST;
fpinfo->shippable_extensions = NIL;
fpinfo->fetch_size = 100;
+ fpinfo->check_partial_aggregate_support = false;
+ fpinfo->remoteversion = 0;
fpinfo->async_capable = false;
apply_server_options(fpinfo);
@@ -661,7 +664,7 @@ postgresGetForeignRelSize(PlannerInfo *root,
* should match what ExecCheckPermissions() does. If we fail due to lack
* of permissions, the query would have failed at runtime anyway.
*/
- if (fpinfo->use_remote_estimate)
+ if (fpinfo->use_remote_estimate || fpinfo->check_partial_aggregate_support)
{
Oid userid;
@@ -5948,9 +5951,10 @@ foreign_join_ok(PlannerInfo *root, RelOptInfo *joinrel, JoinType jointype,
fpinfo->pushdown_safe = true;
/* Get user mapping */
- if (fpinfo->use_remote_estimate)
+ if (fpinfo->use_remote_estimate || fpinfo->check_partial_aggregate_support)
{
- if (fpinfo_o->use_remote_estimate)
+ if (fpinfo_o->use_remote_estimate ||
+ fpinfo_o->check_partial_aggregate_support)
fpinfo->user = fpinfo_o->user;
else
fpinfo->user = fpinfo_i->user;
@@ -6132,6 +6136,8 @@ apply_server_options(PgFdwRelationInfo *fpinfo)
ExtractExtensionList(defGetString(def), false);
else if (strcmp(def->defname, "fetch_size") == 0)
(void) parse_int(defGetString(def), &fpinfo->fetch_size, 0, NULL);
+ else if (strcmp(def->defname, "check_partial_aggregate_support") == 0)
+ fpinfo->check_partial_aggregate_support = defGetBoolean(def);
else if (strcmp(def->defname, "async_capable") == 0)
fpinfo->async_capable = defGetBoolean(def);
}
@@ -6191,6 +6197,8 @@ merge_fdw_options(PgFdwRelationInfo *fpinfo,
fpinfo->shippable_extensions = fpinfo_o->shippable_extensions;
fpinfo->use_remote_estimate = fpinfo_o->use_remote_estimate;
fpinfo->fetch_size = fpinfo_o->fetch_size;
+ fpinfo->check_partial_aggregate_support = fpinfo_o->check_partial_aggregate_support;
+ fpinfo->remoteversion = fpinfo_o->remoteversion;
fpinfo->async_capable = fpinfo_o->async_capable;
/* Merge the table level options from either side of the join. */
@@ -6373,7 +6381,7 @@ postgresGetForeignJoinPaths(PlannerInfo *root,
*/
static bool
foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel,
- Node *havingQual)
+ GroupPathExtraData *extra)
{
Query *query = root->parse;
PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) grouped_rel->fdw_private;
@@ -6382,11 +6390,16 @@ foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel,
ListCell *lc;
int i;
List *tlist = NIL;
+ bool partial = extra->patype == PARTITIONWISE_AGGREGATE_PARTIAL;
/* We currently don't support pushing Grouping Sets. */
if (query->groupingSets)
return false;
+ /* It is unsafe to push HAVING statements with partial aggregates */
+ if ((extra->patype == PARTITIONWISE_AGGREGATE_PARTIAL) && extra->havingQual)
+ return false;
+
/* Get the fpinfo of the underlying scan relation. */
ofpinfo = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private;
@@ -6415,6 +6428,12 @@ foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel,
* a node, as long as it's not at top level; then no match is possible.
*/
i = 0;
+ fpinfo->group_clause = query->groupClause;
+ if (partial)
+ {
+ fpinfo->group_clause = extra->groupClausePartial;
+ grouping_target = extra->partial_target;
+ }
foreach(lc, grouping_target->exprs)
{
Expr *expr = (Expr *) lfirst(lc);
@@ -6426,7 +6445,7 @@ foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel,
* check the whole GROUP BY clause not just processed_groupClause,
* because we will ship all of it, cf. appendGroupByClause.
*/
- if (sgref && get_sortgroupref_clause_noerr(sgref, query->groupClause))
+ if (sgref && get_sortgroupref_clause_noerr(sgref, fpinfo->group_clause))
{
TargetEntry *tle;
@@ -6512,9 +6531,9 @@ foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel,
* Classify the pushable and non-pushable HAVING clauses and save them in
* remote_conds and local_conds of the grouped rel's fpinfo.
*/
- if (havingQual)
+ if (extra->havingQual)
{
- foreach(lc, (List *) havingQual)
+ foreach(lc, (List *) extra->havingQual)
{
Expr *expr = (Expr *) lfirst(lc);
RestrictInfo *rinfo;
@@ -6534,7 +6553,7 @@ foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel,
grouped_rel->relids,
NULL,
NULL);
- if (is_foreign_expr(root, grouped_rel, expr))
+ if (is_foreign_expr(root, grouped_rel, expr) && !partial)
fpinfo->remote_conds = lappend(fpinfo->remote_conds, rinfo);
else
fpinfo->local_conds = lappend(fpinfo->local_conds, rinfo);
@@ -6628,6 +6647,7 @@ postgresGetForeignUpperPaths(PlannerInfo *root, UpperRelationKind stage,
/* Ignore stages we don't support; and skip any duplicate calls. */
if ((stage != UPPERREL_GROUP_AGG &&
+ stage != UPPERREL_PARTIAL_GROUP_AGG &&
stage != UPPERREL_ORDERED &&
stage != UPPERREL_FINAL) ||
output_rel->fdw_private)
@@ -6644,6 +6664,10 @@ postgresGetForeignUpperPaths(PlannerInfo *root, UpperRelationKind stage,
add_foreign_grouping_paths(root, input_rel, output_rel,
(GroupPathExtraData *) extra);
break;
+ case UPPERREL_PARTIAL_GROUP_AGG:
+ add_foreign_grouping_paths(root, input_rel, output_rel,
+ (GroupPathExtraData *) extra);
+ break;
case UPPERREL_ORDERED:
add_foreign_ordered_paths(root, input_rel, output_rel);
break;
@@ -6684,7 +6708,8 @@ add_foreign_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
return;
Assert(extra->patype == PARTITIONWISE_AGGREGATE_NONE ||
- extra->patype == PARTITIONWISE_AGGREGATE_FULL);
+ extra->patype == PARTITIONWISE_AGGREGATE_FULL ||
+ extra->patype == PARTITIONWISE_AGGREGATE_PARTIAL);
/* save the input_rel as outerrel in fpinfo */
fpinfo->outerrel = input_rel;
@@ -6704,7 +6729,7 @@ add_foreign_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
* Use HAVING qual from extra. In case of child partition, it will have
* translated Vars.
*/
- if (!foreign_grouping_ok(root, grouped_rel, extra->havingQual))
+ if (!foreign_grouping_ok(root, grouped_rel, extra))
return;
/*
diff --git a/contrib/postgres_fdw/postgres_fdw.h b/contrib/postgres_fdw/postgres_fdw.h
index 47157ac887..a1a9688c9f 100644
--- a/contrib/postgres_fdw/postgres_fdw.h
+++ b/contrib/postgres_fdw/postgres_fdw.h
@@ -86,6 +86,15 @@ typedef struct PgFdwRelationInfo
ForeignServer *server;
UserMapping *user; /* only set in use_remote_estimate mode */
+ /* for partial aggregate pushdown */
+ bool check_partial_aggregate_support;
+
+ /*
+ * If remoteversion is zero, it means the remote server version has not
+ * been acquired.
+ */
+ int remoteversion;
+
int fetch_size; /* fetch size for this remote table */
/*
@@ -110,6 +119,7 @@ typedef struct PgFdwRelationInfo
/* Grouping information */
List *grouped_tlist;
+ List *group_clause;
/* Subquery information */
bool make_outerrel_subquery; /* do we deparse outerrel as a
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index a303bfb322..92326c07eb 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -2989,16 +2989,31 @@ RESET enable_partitionwise_join;
-- ===================================================================
-- test partitionwise aggregates
-- ===================================================================
-
-CREATE TABLE pagg_tab (a int, b int, c text) PARTITION BY RANGE(a);
+ALTER SERVER loopback OPTIONS (ADD fdw_tuple_cost '0.1');
+
+CREATE TYPE mood AS enum ('sad', 'ok', 'happy');
+ALTER EXTENSION postgres_fdw ADD TYPE mood;
+
+CREATE TABLE pagg_tab (a int, b int, c text, c_serial int4,
+ c_int4array _int4, c_interval interval,
+ c_money money, c_1c text, c_1b bytea,
+ c_bit bit(2), c_1or3int2 int2,
+ c_1or3int4 int4, c_1or3int8 int8,
+ c_bool bool, c_enum mood, c_pg_lsn pg_lsn,
+ c_tid tid, c_int4range int4range,
+ c_int4multirange int4multirange,
+ c_time time, c_timetz timetz,
+ c_timestamp timestamp, c_timestamptz timestamptz,
+ c_xid8 xid8)
+ PARTITION BY RANGE(a);
CREATE TABLE pagg_tab_p1 (LIKE pagg_tab);
CREATE TABLE pagg_tab_p2 (LIKE pagg_tab);
CREATE TABLE pagg_tab_p3 (LIKE pagg_tab);
-INSERT INTO pagg_tab_p1 SELECT i % 30, i % 50, to_char(i/30, 'FM0000') FROM generate_series(1, 3000) i WHERE (i % 30) < 10;
-INSERT INTO pagg_tab_p2 SELECT i % 30, i % 50, to_char(i/30, 'FM0000') FROM generate_series(1, 3000) i WHERE (i % 30) < 20 and (i % 30) >= 10;
-INSERT INTO pagg_tab_p3 SELECT i % 30, i % 50, to_char(i/30, 'FM0000') FROM generate_series(1, 3000) i WHERE (i % 30) < 30 and (i % 30) >= 20;
+INSERT INTO pagg_tab_p1 SELECT i % 30, i % 50, to_char(i/30, 'FM0000'), i, array[(i % 2), 0], ((i % 2) || ' seconds')::interval, (i % 2)::money, ((i - 1) % 10)::text, (((i - 1) % 10)::text)::bytea, case when (i % 2) = 0 then B'01' else B'11' end, case when (i % 2) = 0 then 1 else 3 end, case when (i % 2) = 0 then 1 else 3 end, case when (i % 2) = 0 then 1 else 3 end, case when (i % 2) = 0 then true else false end, (case when (i % 2) = 0 then 'sad' else 'happy' end)::mood, ('0/' || i)::pg_lsn, ('(0,' || i || ')')::tid, int4range(0, i), int4multirange(int4range(0, i), int4range(100, 100 + i)), '00:00:00'::time + (i || ' seconds')::interval, '00:00:00'::timetz + (i || ' seconds')::interval, '2000-01-01'::timestamp + (i || ' seconds')::interval, '2000-01-01'::timestamptz + (i || ' seconds')::interval, ((i % 10)::text)::xid8 FROM generate_series(1, 3000) i WHERE (i % 30) < 10;
+INSERT INTO pagg_tab_p2 SELECT i % 30, i % 50, to_char(i/30, 'FM0000'), i, array[(i % 2), 0], ((i % 2) || ' seconds')::interval, (i % 2)::money, ((i - 1) % 10)::text, (((i - 1) % 10)::text)::bytea, case when (i % 2) = 0 then B'01' else B'11' end, case when (i % 2) = 0 then 1 else 3 end, case when (i % 2) = 0 then 1 else 3 end, case when (i % 2) = 0 then 1 else 3 end, case when (i % 2) = 0 then true else false end, (case when (i % 2) = 0 then 'sad' else 'happy' end)::mood, ('0/' || i)::pg_lsn, ('(0,' || i || ')')::tid, int4range(0, i), int4multirange(int4range(0, i), int4range(100, 100 + i)), '00:00:00'::time + (i || ' seconds')::interval, '00:00:00'::timetz + (i || ' seconds')::interval, '2000-01-01'::timestamp + (i || ' seconds')::interval, '2000-01-01'::timestamptz + (i || ' seconds')::interval, ((i % 10)::text)::xid8 FROM generate_series(1, 3000) i WHERE (i % 30) < 20 and (i % 30) >= 10;
+INSERT INTO pagg_tab_p3 SELECT i % 30, i % 50, to_char(i/30, 'FM0000'), i, array[(i % 2), 0], ((i % 2) || ' seconds')::interval, (i % 2)::money, ((i - 1) % 10)::text, (((i - 1) % 10)::text)::bytea, case when (i % 2) = 0 then B'01' else B'11' end, case when (i % 2) = 0 then 1 else 3 end, case when (i % 2) = 0 then 1 else 3 end, case when (i % 2) = 0 then 1 else 3 end, case when (i % 2) = 0 then true else false end, (case when (i % 2) = 0 then 'sad' else 'happy' end)::mood, ('0/' || i)::pg_lsn, ('(0,' || i || ')')::tid, int4range(0, i), int4multirange(int4range(0, i), int4range(100, 100 + i)), '00:00:00'::time + (i || ' seconds')::interval, '00:00:00'::timetz + (i || ' seconds')::interval, '2000-01-01'::timestamp + (i || ' seconds')::interval, '2000-01-01'::timestamptz + (i || ' seconds')::interval, ((i % 10)::text)::xid8 FROM generate_series(1, 3000) i WHERE (i % 30) < 30 and (i % 30) >= 20;
-- Create foreign partitions
CREATE FOREIGN TABLE fpagg_tab_p1 PARTITION OF pagg_tab FOR VALUES FROM (0) TO (10) SERVER loopback OPTIONS (table_name 'pagg_tab_p1');
@@ -3006,6 +3021,9 @@ CREATE FOREIGN TABLE fpagg_tab_p2 PARTITION OF pagg_tab FOR VALUES FROM (10) TO
CREATE FOREIGN TABLE fpagg_tab_p3 PARTITION OF pagg_tab FOR VALUES FROM (20) TO (30) SERVER loopback OPTIONS (table_name 'pagg_tab_p3');
ANALYZE pagg_tab;
+ANALYZE pagg_tab_p1;
+ANALYZE pagg_tab_p2;
+ANALYZE pagg_tab_p3;
ANALYZE fpagg_tab_p1;
ANALYZE fpagg_tab_p2;
ANALYZE fpagg_tab_p3;
@@ -3028,10 +3046,289 @@ EXPLAIN (VERBOSE, COSTS OFF)
SELECT a, count(t1) FROM pagg_tab t1 GROUP BY a HAVING avg(b) < 22 ORDER BY 1;
SELECT a, count(t1) FROM pagg_tab t1 GROUP BY a HAVING avg(b) < 22 ORDER BY 1;
--- When GROUP BY clause does not match with PARTITION KEY.
-EXPLAIN (COSTS OFF)
+-- Partial aggregates are unsafe to push down when there is a HAVING clause
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT b, avg(a), max(a), count(*) FROM pagg_tab GROUP BY b HAVING sum(a) < 700 ORDER BY 1;
SELECT b, avg(a), max(a), count(*) FROM pagg_tab GROUP BY b HAVING sum(a) < 700 ORDER BY 1;
+-- Partial aggregates are safe to push down without having clause
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT b, avg(a), max(a), count(*) FROM pagg_tab GROUP BY b ORDER BY 1;
+SELECT b, avg(a), max(a), count(*) FROM pagg_tab GROUP BY b ORDER BY 1;
+
+-- Partial aggregates are safe to push down even if we need both variable and variable-based expression
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT avg(a), max(a), count(*), (b/2)::numeric FROM pagg_tab GROUP BY b/2 ORDER BY 4;
+SELECT avg(a), max(a), count(*), (b/2)::numeric FROM pagg_tab GROUP BY b/2 ORDER BY 4;
+
+-- Partial aggregates are safe to push down for all built-in aggregates
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT /* aggregate function <> aggpartialfunc */
+ array_agg(c_int4array), array_agg(b),
+ avg(b::int2), avg(b::int4), avg(b::int8), avg(c_interval), avg(b::float4), avg(b::float8), avg(b::numeric),
+ corr(b::float8, (b * b)::float8),
+ covar_pop(b::float8, (b * b)::float8),
+ covar_samp(b::float8, (b * b)::float8),
+ regr_avgx((2 * b)::float8, b::float8),
+ regr_avgy((2 * b)::float8, b::float8),
+ regr_intercept((2 * b + 3)::float8, b::float8),
+ regr_r2((b * b)::float8, b::float8),
+ regr_slope((2 * b + 3)::float8, b::float8),
+ regr_sxx((2 * b + 3)::float8, b::float8),
+ regr_sxy((b * b)::float8, b::float8),
+ regr_syy((2 * b + 3)::float8, b::float8),
+ stddev(b::float4), stddev(b::float8), stddev(b::int2), stddev(b::int4), stddev(b::int8), stddev(b::numeric),
+ stddev_pop(b::float4), stddev_pop(b::float8), stddev_pop(b::int2), stddev_pop(b::int4), stddev_pop(b::int8), stddev_pop(b::numeric),
+ stddev_samp(b::float4), stddev_samp(b::float8), stddev_samp(b::int2), stddev_samp(b::int4), stddev_samp(b::int8), stddev_samp(b::numeric),
+ string_agg(c_1c, ','), string_agg(c_1b, ','),
+ sum(b::int8), sum(b::numeric),
+ variance(b::float4), variance(b::float8), variance(b::int2), variance(b::int4), variance(b::int8), variance(b::numeric),
+ var_pop(b::float4), var_pop(b::float8), var_pop(b::int2), var_pop(b::int4), var_pop(b::int8), var_pop(b::numeric),
+ var_samp(b::float4), var_samp(b::float8), var_samp(b::int2), var_samp(b::int4), var_samp(b::int8), var_samp(b::numeric),
+ /* aggregate function = aggpartialfunc */
+ any_value(b * 0),
+ bit_and(c_bit), bit_and(c_1or3int2), bit_and(c_1or3int4), bit_and(c_1or3int8),
+ bit_or(c_bit), bit_or(c_1or3int2), bit_or(c_1or3int4), bit_or(c_1or3int8),
+ bit_xor(c_bit), bit_xor(c_1or3int2), bit_xor(c_1or3int4), bit_xor(c_1or3int8),
+ bool_and(c_bool),
+ bool_or(c_bool),
+ count(b), count(*),
+ every(c_bool),
+ max(c_int4array), max(c_enum), max(c_1c::char(1)), max('2000-01-01'::date + b), max('0.0.0.0'::inet + b), max(b::float4), max(b::float8), max(b::int2), max(b::int4), max(b::int8), max(c_interval), max(c_money), max(b::numeric), max(b::oid), max(c_pg_lsn), max(c_tid), max(c_1c), max(c_time), max(c_timetz), max(c_timestamp), max(c_timestamptz), max(c_xid8),
+ min(c_int4array), min(c_enum), min(c_1c::char(1)), min('2000-01-01'::date + b), min('0.0.0.0'::inet + b), min(b::float4), min(b::float8), min(b::int2), min(b::int4), min(b::int8), min(c_interval), min(c_money), min(b::numeric), min(b::oid), min(c_pg_lsn), min(c_tid), min(c_1c), min(c_time), min(c_timetz), min(c_timestamp), min(c_timestamptz), min(c_xid8),
+ range_intersect_agg(c_int4range), range_intersect_agg(c_int4multirange),
+ regr_count((2 * b + 3)::float8, b::float8),
+ sum(b::float4), sum(b::float8), sum(b::int2), sum(b::int4), sum(c_interval), sum(c_money)
+ FROM pagg_tab WHERE c_serial between 1 and 30;
+
+SELECT /* aggregate function <> aggpartialfunc */
+ array_agg(c_int4array), array_agg(b),
+ avg(b::int2), avg(b::int4), avg(b::int8), avg(c_interval),
+ avg(b::float4), avg(b::float8),
+ corr(b::float8, (b * b)::float8),
+ covar_pop(b::float8, (b * b)::float8),
+ covar_samp(b::float8, (b * b)::float8),
+ regr_avgx((2 * b)::float8, b::float8),
+ regr_avgy((2 * b)::float8, b::float8),
+ regr_intercept((2 * b + 3)::float8, b::float8),
+ regr_r2((b * b)::float8, b::float8),
+ regr_slope((2 * b + 3)::float8, b::float8),
+ regr_sxx((2 * b + 3)::float8, b::float8),
+ regr_sxy((b * b)::float8, b::float8),
+ regr_syy((2 * b + 3)::float8, b::float8),
+ stddev(b::float4), stddev(b::float8), stddev(b::int2), stddev(b::int4), stddev(b::int8), stddev(b::numeric),
+ stddev_pop(b::float4), stddev_pop(b::float8), stddev_pop(b::int2), stddev_pop(b::int4), stddev_pop(b::int8), stddev_pop(b::numeric),
+ stddev_samp(b::float4), stddev_samp(b::float8), stddev_samp(b::int2), stddev_samp(b::int4), stddev_samp(b::int8), stddev_samp(b::numeric),
+ string_agg(c_1c, ','), string_agg(c_1b, ','),
+ sum(b::int8), sum(b::numeric),
+ variance(b::float4), variance(b::float8), variance(b::int2), variance(b::int4), variance(b::int8), variance(b::numeric),
+ var_pop(b::float4), var_pop(b::float8), var_pop(b::int2), var_pop(b::int4), var_pop(b::int8), var_pop(b::numeric),
+ var_samp(b::float4), var_samp(b::float8), var_samp(b::int2), var_samp(b::int4), var_samp(b::int8), var_samp(b::numeric),
+ /* aggregate function = aggpartialfunc */
+ any_value(b * 0),
+ bit_and(c_bit), bit_and(c_1or3int2), bit_and(c_1or3int4), bit_and(c_1or3int8),
+ bit_or(c_bit), bit_or(c_1or3int2), bit_or(c_1or3int4), bit_or(c_1or3int8),
+ bit_xor(c_bit), bit_xor(c_1or3int2), bit_xor(c_1or3int4), bit_xor(c_1or3int8),
+ bool_and(c_bool),
+ bool_or(c_bool),
+ count(b), count(*),
+ every(c_bool),
+ max(c_int4array), max(c_enum), max(c_1c::char(1)), max('2000-01-01'::date + b), max('0.0.0.0'::inet + b), max(b::float4), max(b::float8), max(b::int2), max(b::int4), max(b::int8), max(c_interval), max(c_money), max(b::numeric), max(b::oid), max(c_pg_lsn), max(c_tid), max(c_1c), max(c_time), max(c_timetz), max(c_timestamp), max(c_timestamptz), max(c_xid8),
+ min(c_int4array), min(c_enum), min(c_1c::char(1)), min('2000-01-01'::date + b), min('0.0.0.0'::inet + b), min(b::float4), min(b::float8), min(b::int2), min(b::int4), min(b::int8), min(c_interval), min(c_money), min(b::numeric), min(b::oid), min(c_pg_lsn), min(c_tid), min(c_1c), min(c_time), min(c_timetz), min(c_timestamp), min(c_timestamptz), min(c_xid8),
+ range_intersect_agg(c_int4range), range_intersect_agg(c_int4multirange),
+ regr_count((2 * b + 3)::float8, b::float8),
+ sum(b::float4), sum(b::float8), sum(b::int2), sum(b::int4), sum(c_interval), sum(c_money)
+ FROM pagg_tab WHERE c_serial between 1 and 30;
+
+-- Tests for backward compatibility
+ALTER SERVER loopback OPTIONS (ADD check_partial_aggregate_support 'false');
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT b, avg(a), max(a), count(*) FROM pagg_tab GROUP BY b ORDER BY 1;
+SELECT b, avg(a), max(a), count(*) FROM pagg_tab GROUP BY b ORDER BY 1;
+
+ALTER SERVER loopback OPTIONS (SET check_partial_aggregate_support 'true');
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT b, avg(a), max(a), count(*) FROM pagg_tab GROUP BY b ORDER BY 1;
+SELECT b, avg(a), max(a), count(*) FROM pagg_tab GROUP BY b ORDER BY 1;
+
+ALTER SERVER loopback OPTIONS (SET fdw_tuple_cost '1.0');
+SET enable_partitionwise_join=on;
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT avg(t1.b), avg(t1.b::int8) FROM pagg_tab t1 JOIN pagg_tab t2 USING(a);
+SELECT avg(t1.b), avg(t1.b::int8) FROM pagg_tab t1 JOIN pagg_tab t2 USING(a);
+RESET enable_partitionwise_join;
+ALTER SERVER loopback OPTIONS (SET fdw_tuple_cost '0.1');
+
+ALTER SERVER loopback OPTIONS (DROP check_partial_aggregate_support);
+
+-- List of aggregate functions such that the aggregate function supports partial aggregate
+-- and aggpartialfn field of the aggregate function is invalid
+SELECT aggfnoid::text
+ FROM pg_aggregate a JOIN pg_type b ON a.aggtranstype = b.oid
+ WHERE (aggcombinefn::text <> '-') AND (aggpartialfn::text = '-')
+ ORDER BY 1;
+
+-- List of aggregate functions which have incorrect aggpartialfunc
+SELECT a.aggfnoid
+ FROM pg_aggregate a JOIN pg_type b ON a.aggtranstype = b.oid
+ JOIN pg_aggregate c on a.aggpartialfn = c.aggfnoid
+ WHERE (a.aggcombinefn::text <> '-')
+ AND (a.aggpartialfn::text <> '-')
+ AND (a.aggtransfn <> c.aggtransfn
+ OR (c.aggcombinefn::text <> '-'
+ AND a.aggcombinefn <> c.aggcombinefn)
+ OR (a.agginitval IS NOT NULL
+ AND c.agginitval IS NOT NULL
+ AND a.agginitval <> c.agginitval)
+ OR (b.typname = 'internal'
+ AND c.aggserialfn::text <> '-'
+ AND a.aggserialfn <> c.aggserialfn)
+ OR (b.typname = 'internal'
+ AND c.aggdeserialfn::text <> '-'
+ AND a.aggdeserialfn <> c.aggdeserialfn)
+ OR (b.typname = 'internal'
+ AND a.aggserialfn <> c.aggfinalfn)
+ OR (b.typname <> 'internal'
+ AND c.aggfinalfn::text <> '-'))
+ ORDER BY 1;
+
+-- It is unsafe to push down partial aggregates which contain DISTINCT clauses
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT max(a), count(distinct b) FROM pagg_tab;
+SELECT max(a), count(distinct b) FROM pagg_tab;
+
+-- It is unsafe to push down partial aggregates which contain ORDER BY clauses
+EXPLAIN (VERBOSE, COSTS OFF) SELECT array_agg(b order by b) FROM pagg_tab WHERE c_serial between 1 and 30;
+SELECT array_agg(b order by b) FROM pagg_tab WHERE c_serial between 1 and 30;
+
+-- Create user-defined aggregates whose stype is internal
+CREATE SCHEMA postgres_fdw_test;
+CREATE AGGREGATE postgres_fdw_test.postgres_fdw_sum_p_int8(int8) (
+ SFUNC = int8_avg_accum,
+ STYPE = internal,
+ COMBINEFUNC = int8_avg_combine,
+ FINALFUNC = int8_avg_serialize,
+ SERIALFUNC = int8_avg_serialize,
+ DESERIALFUNC = int8_avg_deserialize,
+ AGGPARTIALFUNC = postgres_fdw_test.postgres_fdw_sum_p_int8
+);
+
+CREATE AGGREGATE postgres_fdw_sum(int8) (
+ SFUNC = int8_avg_accum,
+ STYPE = internal,
+ COMBINEFUNC = int8_avg_combine,
+ FINALFUNC = numeric_poly_sum,
+ SERIALFUNC = int8_avg_serialize,
+ DESERIALFUNC = int8_avg_deserialize,
+ AGGPARTIALFUNC = postgres_fdw_test.postgres_fdw_sum_p_int8
+);
+
+-- Create user-defined aggregates whose stype is not internal
+CREATE AGGREGATE postgres_fdw_avg_p_int4(int4) (
+ SFUNC = int4_avg_accum,
+ STYPE = _int8,
+ COMBINEFUNC = int4_avg_combine,
+ INITCOND = '{0,0}',
+ AGGPARTIALFUNC = postgres_fdw_avg_p_int4
+);
+
+CREATE AGGREGATE postgres_fdw_avg(int4) (
+ SFUNC = int4_avg_accum,
+ STYPE = _int8,
+ COMBINEFUNC = int4_avg_combine,
+ FINALFUNC = int8_avg,
+ INITCOND = '{0,0}',
+ AGGPARTIALFUNC = postgres_fdw_avg_p_int4
+);
+
+CREATE AGGREGATE postgres_fdw_sum_noaggpartialfunc(int8) (
+ SFUNC = int8_avg_accum,
+ STYPE = internal,
+ COMBINEFUNC = int8_avg_combine,
+ FINALFUNC = numeric_poly_sum,
+ SERIALFUNC = int8_avg_serialize,
+ DESERIALFUNC = int8_avg_deserialize
+);
+
+-- It's safe to push down partial aggregates for user-defined aggregate
+-- when it belongs to an extension that is listed in the extension setting
+-- and when its aggpartialfunc belongs to an extension that is listed
+-- in the extension setting.
+ALTER EXTENSION postgres_fdw ADD FUNCTION postgres_fdw_sum(int8);
+ALTER EXTENSION postgres_fdw ADD FUNCTION postgres_fdw_test.postgres_fdw_sum_p_int8(int8);
+
+ALTER EXTENSION postgres_fdw ADD FUNCTION postgres_fdw_avg(int4);
+ALTER EXTENSION postgres_fdw ADD FUNCTION postgres_fdw_avg_p_int4(int4);
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT postgres_fdw_sum(b::int8) FROM pagg_tab;
+SELECT postgres_fdw_sum(b::int8) FROM pagg_tab;
+
+-- It is unsafe to push down partial aggregates for user-defined aggregates
+-- when they have no aggpartialfunc.
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT postgres_fdw_sum_noaggpartialfunc(b::int8) FROM pagg_tab;
+SELECT postgres_fdw_sum_noaggpartialfunc(b::int8) FROM pagg_tab;
+
+ALTER EXTENSION postgres_fdw DROP FUNCTION postgres_fdw_test.postgres_fdw_sum_p_int8(int8);
+
+-- Reconnect for flushing the shippability cache
+\c -
+SET enable_partitionwise_aggregate TO true;
+
+-- It is unsafe to push down partial aggregates for user-defined aggregates
+-- when itself is aggpartialfunc and when it belongs to an extension
+-- that's listed in the extension setting and when stype is internal.
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT postgres_fdw_test.postgres_fdw_sum_p_int8(b::int8) FROM pagg_tab;
+SELECT postgres_fdw_test.postgres_fdw_sum_p_int8(b::int8) FROM pagg_tab;
+
+ALTER EXTENSION postgres_fdw DROP FUNCTION postgres_fdw_sum(int8);
+ALTER EXTENSION postgres_fdw ADD FUNCTION postgres_fdw_test.postgres_fdw_sum_p_int8(int8);
+
+-- Reconnect for flushing the shippability cache
+\c -
+SET enable_partitionwise_aggregate TO true;
+
+-- It is unsafe to push down partial aggregates for user-defined aggregates
+-- when it doesn't belong to an extension that is listed in the extension setting
+-- and when its aggpartialfunc belongs to an extension that is listed
+-- in the extension setting.
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT postgres_fdw_sum(b::int8) FROM pagg_tab;
+SELECT postgres_fdw_sum(b::int8) FROM pagg_tab;
+
+-- It's safe to push down partial aggregates for user-defined aggregate
+-- whose stype is not internal
+-- when it belongs to an extension that is listed in the extension setting
+-- and when its aggpartialfunc belongs to an extension that is listed
+-- in the extension setting.
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT postgres_fdw_avg(b) FROM pagg_tab;
+SELECT postgres_fdw_avg(b) FROM pagg_tab;
+
+-- It's safe to push down partial aggregates for user-defined aggregate
+-- when itself is aggpartialfunc and when it belongs to an extension
+-- that's listed in the extension setting and when stype is not internal.
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT postgres_fdw_avg_p_int4(b) FROM pagg_tab;
+SELECT postgres_fdw_avg_p_int4(b) FROM pagg_tab;
+
+ALTER EXTENSION postgres_fdw DROP TYPE mood;
+
+ALTER EXTENSION postgres_fdw DROP FUNCTION postgres_fdw_test.postgres_fdw_sum_p_int8(int8);
+
+ALTER EXTENSION postgres_fdw DROP FUNCTION postgres_fdw_avg_p_int4(int4);
+ALTER EXTENSION postgres_fdw DROP FUNCTION postgres_fdw_avg(int4);
+
+DROP AGGREGATE postgres_fdw_sum(int8);
+DROP AGGREGATE postgres_fdw_test.postgres_fdw_sum_p_int8(int8);
+DROP SCHEMA postgres_fdw_test;
+DROP AGGREGATE postgres_fdw_avg(int4);
+DROP AGGREGATE postgres_fdw_avg_p_int4(int4);
+DROP AGGREGATE postgres_fdw_sum_noaggpartialfunc(int8);
+ALTER SERVER loopback OPTIONS (DROP fdw_tuple_cost);
+
-- ===================================================================
-- access rights and superuser
-- ===================================================================
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 3ec7391ec5..a6dc334726 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -644,6 +644,18 @@
value starts out null.
</para></entry>
</row>
+
+ <row>
+ <entry role="catalog_table_entry"><para role="column_definition">
+ <structfield>aggpartialfn</structfield> <type>regproc</type>
+ (references <link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.<structfield>oid</structfield>)
+ </para>
+ <para>
+ Partial aggregate function (zero if none).
+ See <xref linkend="partial-aggregate-pushdown"/> for the definition
+ of partial aggregate function.
+ </para></entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/doc/src/sgml/postgres-fdw.sgml b/doc/src/sgml/postgres-fdw.sgml
index 33cc6e07b7..1623e46054 100644
--- a/doc/src/sgml/postgres-fdw.sgml
+++ b/doc/src/sgml/postgres-fdw.sgml
@@ -451,6 +451,43 @@ OPTIONS (ADD password_required 'false');
</sect3>
+ <sect3 id="postgres-fdw-options-partial-aggregate-pushdown">
+ <title>Partial Aggregate Pushdown Options</title>
+
+ <para>
+ By default, <filename>postgres_fdw</filename> assumes that each
+ built-in aggregate function has a partial aggregate function defined on
+ the remote server; see <xref linkend="partial-aggregate-pushdown"/>
+ for a definition of the partial aggregate functions. This may be
+ overridden using the following option:
+ </para>
+
+ <variablelist>
+
+ <varlistentry>
+ <term><literal>check_partial_aggregate_support</literal> (<type>boolean</type>)</term>
+ <listitem>
+ <para>
+ If this option is false, <filename>postgres_fdw</filename> always
+ uses partial aggregate pushdown by assuming that each built-in
+ aggregate function has a partial aggregate function defined on
+ the remote server. If this option is true, local aggregates
+ whose partial computation function references itself are assumed
+ to exist on the remote server. If not, during query planning,
+ <filename>postgres_fdw</filename> will connect to the remote
+ server and retrieve the remote server version. If the remote
+ version is the same or newer, partial aggregate functions will be
+ assumed to exist. If older, <filename>postgres_fdw</filename>
+ checks that the remote server has a matching partial aggregate
+ function before performing partial aggregate pushdown. The default
+ is <literal>false</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </sect3>
+
<sect3 id="postgres-fdw-options-asynchronous-execution">
<title>Asynchronous Execution Options</title>
@@ -929,14 +966,15 @@ postgres=# SELECT postgres_fdw_disconnect_all();
<para>
<filename>postgres_fdw</filename> attempts to optimize remote queries to reduce
the amount of data transferred from foreign servers. This is done by
- sending query <literal>WHERE</literal> clauses to the remote server for
- execution, and by not retrieving table columns that are not needed for
- the current query. To reduce the risk of misexecution of queries,
- <literal>WHERE</literal> clauses are not sent to the remote server unless they use
- only data types, operators, and functions that are built-in or belong to an
- extension that's listed in the foreign server's <literal>extensions</literal>
- option. Operators and functions in such clauses must
- be <literal>IMMUTABLE</literal> as well.
+ sending query <literal>WHERE</literal> clauses and aggregate expressions
+ to the remote server for execution, and by not retrieving table
+ columns that are not needed for the current query. To reduce the
+ risk of misexecution of queries, <literal>WHERE</literal> clauses
+ and aggregate expressions are not sent to the remote server unless
+ they only use data types, operators, and functions that are built-in
+ or belong to an extension that is listed in the foreign server's
+ <literal>extensions</literal> option. Operators and functions in such
+ clauses must be <literal>IMMUTABLE</literal> as well.
For an <command>UPDATE</command> or <command>DELETE</command> query,
<filename>postgres_fdw</filename> attempts to optimize the query execution by
sending the whole query to the remote server if there are no query
@@ -966,6 +1004,64 @@ postgres=# SELECT postgres_fdw_disconnect_all();
</para>
</sect2>
+ <sect2 id="partial-aggregate-pushdown">
+ <title>Partial aggregate pushdown</title>
+ <para>
+ Partial aggregate pushdown is an optimization for queries that contains
+ aggregate expressions for a partitioned table across one or more remote
+ servers. If multiple conditions are met, partial aggregate function
+ calls are sent to the remote servers. The conditions under which this
+ sending is active are as follows.
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ A partial aggregate function which corresponds to the aggregate
+ expression is defined on the local server and assumed to exist on
+ the remote server
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The conditions in <xref linkend="postgres-fdw-remote-query-optimization"/> are true
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The query doesn't contain a <literal>HAVING</literal> clause
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The aggregate expressions in the query do not contain
+ <literal>DISTINCT</literal> or <literal>ORDER BY</literal> clauses
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ When partial aggregate pushdown is used for aggregate expressions,
+ remote queries replace aggregate function calls with partial
+ aggregate function calls. If the data type of the state value is not
+ <type>internal</type>, the partial aggregate function must not have
+ a final function. If <type>internal</type>, the partial aggregate
+ function must have the same final function as the aggregate function's
+ serialization function, and the partial aggregate function and the
+ aggregate function have the same transition function and data type
+ of the state value. If the partial aggregate function has any of the
+ following members: initial state, combine function, serialization
+ function, or deserialization function, the members must match the
+ corresponding members in the aggregate function. Built-in aggregate
+ functions that support partial aggregation must also have their
+ partial aggregate functions defined as built-in aggregates. See <xref
+ linkend="postgres-fdw-options-partial-aggregate-pushdown"/> for details
+ on how the existance of remote-server partial aggregates are checked.
+ <filename>postgres_fdw</filename> assumes user-defined aggregate
+ functions have partial aggregate functions on the remote server only
+ if both belong to extensions listed in the foreign server's extensions
+ option.
+ </para>
+ </sect2>
+
<sect2 id="postgres-fdw-remote-query-execution-environment">
<title>Remote Query Execution Environment</title>
@@ -1031,15 +1127,25 @@ postgres=# SELECT postgres_fdw_disconnect_all();
back to 8.1. A limitation however is that <filename>postgres_fdw</filename>
generally assumes that immutable built-in functions and operators are
safe to send to the remote server for execution, if they appear in a
- <literal>WHERE</literal> clause for a foreign table. Thus, a built-in
- function that was added since the remote server's release might be sent
- to it for execution, resulting in <quote>function does not exist</quote> or
- a similar error. This type of failure can be worked around by
+ <literal>WHERE</literal> clause or aggregate expressions for a foreign table.
+ Thus, a built-in function that was added since the remote server's release
+ might be sent to it for execution, resulting in <quote>function does not
+ exist</quote> or a similar error. This type of failure can be worked around by
rewriting the query, for example by embedding the foreign table
reference in a sub-<literal>SELECT</literal> with <literal>OFFSET 0</literal> as an
optimization fence, and placing the problematic function or operator
outside the sub-<literal>SELECT</literal>.
</para>
+
+ <para>
+ A similar problem can occur with partial aggregate pushdown.
+ Pushdown causes aggregate function calls to send partial aggregate
+ function calls to the remote server. If the partial aggregate
+ function doesn't exist on the remote server, it causes
+ <quote>function does not exist</quote> or a similar error; see
+ <xref linkend="postgres-fdw-options-partial-aggregate-pushdown"/>
+ on how to enable remote server checks.
+ </para>
</sect2>
<sect2 id="postgres-fdw-wait-events">
diff --git a/doc/src/sgml/ref/create_aggregate.sgml b/doc/src/sgml/ref/create_aggregate.sgml
index 222e0aa5c9..12beb79dc7 100644
--- a/doc/src/sgml/ref/create_aggregate.sgml
+++ b/doc/src/sgml/ref/create_aggregate.sgml
@@ -42,6 +42,7 @@ CREATE [ OR REPLACE ] AGGREGATE <replaceable class="parameter">name</replaceable
[ , MINITCOND = <replaceable class="parameter">minitial_condition</replaceable> ]
[ , SORTOP = <replaceable class="parameter">sort_operator</replaceable> ]
[ , PARALLEL = { SAFE | RESTRICTED | UNSAFE } ]
+ [ , AGGPARTIALFUNC = <replaceable class="parameter">aggpartialfunc</replaceable> ]
)
CREATE [ OR REPLACE ] AGGREGATE <replaceable class="parameter">name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">arg_data_type</replaceable> [ , ... ] ]
@@ -80,6 +81,7 @@ CREATE [ OR REPLACE ] AGGREGATE <replaceable class="parameter">name</replaceable
[ , MFINALFUNC_MODIFY = { READ_ONLY | SHAREABLE | READ_WRITE } ]
[ , MINITCOND = <replaceable class="parameter">minitial_condition</replaceable> ]
[ , SORTOP = <replaceable class="parameter">sort_operator</replaceable> ]
+ [ , AGGPARTIALFUNC = <replaceable class="parameter">aggpartialfunc</replaceable> ]
)
</synopsis>
</refsynopsisdiv>
@@ -246,6 +248,12 @@ CREATE [ OR REPLACE ] AGGREGATE <replaceable class="parameter">name</replaceable
marked <literal>PARALLEL SAFE</literal> to enable parallel aggregation.
</para>
+ <para>
+ Paraemter <literal>AGGPARTIALFUNC</literal> optionally defines a
+ partial aggregate function used for partial aggregate pushdown; see
+ <xref linkend="xaggr-partial-aggregates"/> for details.
+ </para>
+
<para>
Aggregates that behave like <function>MIN</function> or <function>MAX</function> can
sometimes be optimized by looking into an index instead of scanning every
@@ -653,6 +661,32 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">aggpartialfunc</replaceable></term>
+ <listitem>
+ <para>
+ Parameter <replaceable class="parameter">aggpartialfunc</replaceable>
+ reprsents the name of this aggregate function's
+ partial aggregate function. If specified, <replaceable
+ class="parameter">combinefunc</replaceable> must also be specified.
+ If <replaceable class="parameter">state_data_type</replaceable>
+ is not <type>internal</type>, the partial aggregate function must
+ not have the <replaceable class="parameter">ffunc</replaceable>.
+ If <replaceable class="parameter">state_data_type</replaceable>
+ is <type>internal</type>, the partial aggregate function
+ must have the same final function as <replaceable
+ class="parameter">serialfunc</replaceable>. The partial
+ aggregate function and the aggregate function must have the same
+ <replaceable class="parameter">sfunc</replaceable> and <replaceable
+ class="parameter">state_data_type</replaceable>. If the partial
+ aggregate function has any of the following members: initial
+ state, combine function, serialization function, or deserialization
+ function, the members must match with the corresponding members in
+ the aggregate function.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
<para>
diff --git a/doc/src/sgml/xaggr.sgml b/doc/src/sgml/xaggr.sgml
index bdad8d3dc2..2863731d00 100644
--- a/doc/src/sgml/xaggr.sgml
+++ b/doc/src/sgml/xaggr.sgml
@@ -536,9 +536,6 @@ SELECT percentile_disc(0.5) WITHIN GROUP (ORDER BY income) FROM households;
parallel aggregation by having different worker processes scan different
portions of a table. Each worker produces a partial state value, and at
the end those state values are combined to produce a final state value.
- (In the future this mode might also be used for purposes such as combining
- aggregations over local and remote tables; but that is not implemented
- yet.)
</para>
<para>
@@ -612,6 +609,14 @@ SELECT percentile_disc(0.5) WITHIN GROUP (ORDER BY income) FROM households;
parallel-safety markings on its support functions are not consulted.
</para>
+ <para>
+ <filename>postgres_fdw</filename> can optimize queries containing
+ aggregate expressions on partitioned tables that span multiple
+ remote servers. This optimization sends <firstterm>partial
+ aggregate functions</firstterm> to remote servers; see <xref
+ linkend="partial-aggregate-pushdown"/> for details.
+ </para>
+
</sect2>
<sect2 id="xaggr-support-functions">
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index ebc4454743..aaf1e62762 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -63,6 +63,7 @@ AggregateCreate(const char *aggName,
List *aggmtransfnName,
List *aggminvtransfnName,
List *aggmfinalfnName,
+ List *aggpartialfnName,
bool finalfnExtraArgs,
bool mfinalfnExtraArgs,
char finalfnModify,
@@ -91,6 +92,8 @@ AggregateCreate(const char *aggName,
Oid mtransfn = InvalidOid; /* can be omitted */
Oid minvtransfn = InvalidOid; /* can be omitted */
Oid mfinalfn = InvalidOid; /* can be omitted */
+ bool isaggpartialfn = false;
+ Oid aggpartialfn = InvalidOid; /* can be omitted */
Oid sortop = InvalidOid; /* can be omitted */
Oid *aggArgTypes = parameterTypes->values;
bool mtransIsStrict = false;
@@ -569,6 +572,94 @@ AggregateCreate(const char *aggName,
format_type_be(finaltype))));
}
+ /*
+ * Validate the aggpartialfunc, if present.
+ */
+ if (aggpartialfnName)
+ {
+ char *aggpartialName;
+ Oid aggpartialNamespace;
+
+ if (!aggcombinefnName)
+ elog(ERROR, "aggcombinefnName must be supplied if aggpartialfnName is supplied");
+
+ /* Convert list of names to a name and namespace */
+ aggpartialNamespace = QualifiedNameGetCreationNamespace(aggpartialfnName,
+ &aggpartialName);
+
+ if ((aggNamespace == aggpartialNamespace)
+ && (strcmp(aggName, aggpartialName) == 0))
+ {
+ if (((aggTransType != INTERNALOID) && (finalfn != InvalidOid))
+ || ((aggTransType == INTERNALOID) && (finalfn != serialfn)))
+ elog(ERROR, "%s is not its own aggpartialfunc", aggName);
+ isaggpartialfn = true;
+ }
+ else
+ {
+ HeapTuple aggtup;
+ Form_pg_aggregate aggpartialform;
+ Datum textInitVal;
+ char *strInitVal;
+ bool initValueIsNull;
+
+ aggpartialfn = LookupFuncName(aggpartialfnName, numArgs, aggArgTypes, false);
+
+ /* Check aggregate creator has permission to call the function */
+ aclresult = object_aclcheck(ProcedureRelationId, aggpartialfn,
+ GetUserId(), ACL_EXECUTE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, OBJECT_FUNCTION, get_func_name(aggpartialfn));
+
+ rettype = get_func_rettype(aggpartialfn);
+
+ aggtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(aggpartialfn));
+ if (!HeapTupleIsValid(aggtup))
+ elog(ERROR, "cache lookup failed for aggpartialfunc %u", aggpartialfn);
+
+ aggpartialform = (Form_pg_aggregate) GETSTRUCT(aggtup);
+
+ if ((aggpartialform->aggcombinefn != InvalidOid) &&
+ (aggpartialform->aggcombinefn != combinefn))
+ elog(ERROR, "%s in aggregate and %s in its aggpartialfunc must match",
+ "combinefunc", "combinefunc");
+
+ if (aggpartialform->aggtransfn != transfn)
+ elog(ERROR, "%s in aggregate and its aggpartialfunc must match", "sfunc");
+
+ textInitVal = SysCacheGetAttr(AGGFNOID, aggtup,
+ Anum_pg_aggregate_agginitval, &initValueIsNull);
+
+ if (!initValueIsNull && (agginitval != NULL))
+ {
+ strInitVal = TextDatumGetCString(textInitVal);
+ if (strcmp(strInitVal, agginitval) != 0)
+ elog(ERROR, "%s in aggregate and %s in its aggpartialfunc must match",
+ "initcond", "initcond");
+ }
+
+ if (aggTransType == INTERNALOID)
+ {
+ if (aggpartialform->aggcombinefn != InvalidOid)
+ {
+ if (aggpartialform->aggserialfn != serialfn)
+ elog(ERROR, "%s in aggregate and %s in its aggpartialfunc must match",
+ "serialfunc", "serialfunc");
+
+ if (aggpartialform->aggdeserialfn != deserialfn)
+ elog(ERROR, "%s in aggregate and %s in its aggpartialfunc must match",
+ "deserialfunc", "deserialfunc");
+ }
+ if (aggpartialform->aggfinalfn != serialfn)
+ elog(ERROR, "finalfunc of aggpartialfunc must match serialfunc of aggregate when stype is internal");
+ }
+ else if (aggpartialform->aggfinalfn != InvalidOid)
+ elog(ERROR, "finalfunc of aggpartialfunc must not be supplied when stype isn't internal");
+
+ ReleaseSysCache(aggtup);
+ }
+ }
+
/* handle sortop, if supplied */
if (aggsortopName)
{
@@ -684,6 +775,9 @@ AggregateCreate(const char *aggName,
values[Anum_pg_aggregate_aggminitval - 1] = CStringGetTextDatum(aggminitval);
else
nulls[Anum_pg_aggregate_aggminitval - 1] = true;
+ if (isaggpartialfn)
+ aggpartialfn = procOid;
+ values[Anum_pg_aggregate_aggpartialfn - 1] = ObjectIdGetDatum(aggpartialfn);
if (replace)
oldtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(procOid));
@@ -805,6 +899,13 @@ AggregateCreate(const char *aggName,
add_exact_object_address(&referenced, addrs);
}
+ /* Depends on aggpartialfunc, if any */
+ if (OidIsValid(aggpartialfn) && (aggpartialfn != procOid))
+ {
+ ObjectAddressSet(referenced, ProcedureRelationId, aggpartialfn);
+ add_exact_object_address(&referenced, addrs);
+ }
+
record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
free_object_addresses(addrs);
return myself;
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index fda9d1aa77..8c8f1789e9 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -70,6 +70,7 @@ DefineAggregate(ParseState *pstate,
List *combinefuncName = NIL;
List *serialfuncName = NIL;
List *deserialfuncName = NIL;
+ List *aggpartialfuncName = NIL;
List *mtransfuncName = NIL;
List *minvtransfuncName = NIL;
List *mfinalfuncName = NIL;
@@ -143,6 +144,8 @@ DefineAggregate(ParseState *pstate,
serialfuncName = defGetQualifiedName(defel);
else if (strcmp(defel->defname, "deserialfunc") == 0)
deserialfuncName = defGetQualifiedName(defel);
+ else if (strcmp(defel->defname, "aggpartialfunc") == 0)
+ aggpartialfuncName = defGetQualifiedName(defel);
else if (strcmp(defel->defname, "msfunc") == 0)
mtransfuncName = defGetQualifiedName(defel);
else if (strcmp(defel->defname, "minvfunc") == 0)
@@ -461,6 +464,7 @@ DefineAggregate(ParseState *pstate,
mtransfuncName, /* fwd trans function name */
minvtransfuncName, /* inv trans function name */
mfinalfuncName, /* final function name */
+ aggpartialfuncName,
finalfuncExtraArgs,
mfinalfuncExtraArgs,
finalfuncModify,
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index a8cea5efe1..f195970967 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -206,7 +206,7 @@ static PathTarget *make_group_input_target(PlannerInfo *root,
PathTarget *final_target);
static PathTarget *make_partial_grouping_target(PlannerInfo *root,
PathTarget *grouping_target,
- Node *havingQual);
+ GroupPathExtraData *extra);
static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist);
static void optimize_window_clauses(PlannerInfo *root,
WindowFuncLists *wflists);
@@ -5415,6 +5415,99 @@ make_group_input_target(PlannerInfo *root, PathTarget *final_target)
return set_pathtarget_cost_width(root, input_target);
}
+/*
+ * setGroupClausePartial
+ * Generate a groupClause and a pathtarget for partial aggregate
+ * pushdown by FDW and set them to GroupPathExtraData.
+ */
+static void
+setGroupClausePartial(PathTarget *partial_target, List *non_group_exprs,
+ List *groupClause, GroupPathExtraData *extra)
+{
+ int exprno,
+ refno;
+ ListCell *lc;
+ Index maxRef = 0;
+ List *exprs_processed = NIL;
+ int exprs_num = 0;
+
+ foreach(lc, groupClause)
+ {
+ SortGroupClause *sgc = (SortGroupClause *) lfirst(lc);
+
+ if (sgc->tleSortGroupRef > maxRef)
+ maxRef = sgc->tleSortGroupRef;
+ }
+ maxRef++;
+
+ extra->groupClausePartial = list_copy_deep(groupClause);
+ extra->partial_target = copy_pathtarget(partial_target);
+
+ if (partial_target->exprs)
+ exprs_num = partial_target->exprs->length;
+
+ foreach(lc, non_group_exprs)
+ {
+ Expr *expr = (Expr *) lfirst(lc);
+
+ refno = -1;
+ if (list_member(exprs_processed, expr) ||
+ (!IsA(expr, Var) && !IsA(expr, PlaceHolderVar)))
+ continue;
+ exprs_processed = lappend(exprs_processed, expr);
+ for (exprno = 0; exprno < exprs_num; exprno++)
+ {
+ Expr *target_expr = (Expr *) list_nth(partial_target->exprs, exprno);
+
+ if (equal(target_expr, expr))
+ {
+ refno = exprno;
+ break;
+ }
+ }
+ if (refno < 0)
+ {
+ SortGroupClause *grpcl = makeNode(SortGroupClause);
+
+ grpcl->tleSortGroupRef = maxRef++;
+ extra->groupClausePartial = lappend(extra->groupClausePartial, grpcl);
+ add_column_to_pathtarget(extra->partial_target, expr, grpcl->tleSortGroupRef);
+ }
+ }
+}
+
+/*
+ * adjustAggrefForPartial
+ * Adjust Aggrefs to put them in partial mode
+ */
+static void
+adjustAggrefForPartial(List *exprs)
+{
+ ListCell *lc;
+
+ foreach(lc, exprs)
+ {
+ Aggref *aggref = (Aggref *) lfirst(lc);
+
+ if (IsA(aggref, Aggref))
+ {
+ Aggref *newaggref;
+
+ /*
+ * We shouldn't need to copy the substructure of the Aggref node,
+ * but flat-copy the node itself to avoid damaging other trees.
+ */
+ newaggref = makeNode(Aggref);
+ memcpy(newaggref, aggref, sizeof(Aggref));
+
+ /* For now, assume serialization is required */
+ mark_partial_aggref(newaggref, AGGSPLIT_INITIAL_SERIAL);
+
+ lfirst(lc) = newaggref;
+ }
+ }
+}
+
/*
* make_partial_grouping_target
* Generate appropriate PathTarget for output of partial aggregate
@@ -5430,11 +5523,15 @@ make_group_input_target(PlannerInfo *root, PathTarget *final_target)
*
* grouping_target is the tlist to be emitted by the topmost aggregation step.
* havingQual represents the HAVING clause.
+ *
+ * Modified PathTarget cannot be used by FDW as-is to deparse this statement.
+ * So, before modifying PathTarget, setGroupClausePartial generates
+ * another Pathtarget and another list of SortGroupClauses.
*/
static PathTarget *
make_partial_grouping_target(PlannerInfo *root,
PathTarget *grouping_target,
- Node *havingQual)
+ GroupPathExtraData *extra)
{
PathTarget *partial_target;
List *non_group_cols;
@@ -5476,8 +5573,8 @@ make_partial_grouping_target(PlannerInfo *root,
/*
* If there's a HAVING clause, we'll need the Vars/Aggrefs it uses, too.
*/
- if (havingQual)
- non_group_cols = lappend(non_group_cols, havingQual);
+ if (extra->havingQual)
+ non_group_cols = lappend(non_group_cols, extra->havingQual);
/*
* Pull out all the Vars, PlaceHolderVars, and Aggrefs mentioned in
@@ -5490,35 +5587,17 @@ make_partial_grouping_target(PlannerInfo *root,
PVC_INCLUDE_AGGREGATES |
PVC_RECURSE_WINDOWFUNCS |
PVC_INCLUDE_PLACEHOLDERS);
-
+ setGroupClausePartial(partial_target, non_group_exprs, root->parse->groupClause, extra);
add_new_columns_to_pathtarget(partial_target, non_group_exprs);
+ add_new_columns_to_pathtarget(extra->partial_target, non_group_exprs);
/*
* Adjust Aggrefs to put them in partial mode. At this point all Aggrefs
* are at the top level of the target list, so we can just scan the list
* rather than recursing through the expression trees.
*/
- foreach(lc, partial_target->exprs)
- {
- Aggref *aggref = (Aggref *) lfirst(lc);
-
- if (IsA(aggref, Aggref))
- {
- Aggref *newaggref;
-
- /*
- * We shouldn't need to copy the substructure of the Aggref node,
- * but flat-copy the node itself to avoid damaging other trees.
- */
- newaggref = makeNode(Aggref);
- memcpy(newaggref, aggref, sizeof(Aggref));
-
- /* For now, assume serialization is required */
- mark_partial_aggref(newaggref, AGGSPLIT_INITIAL_SERIAL);
-
- lfirst(lc) = newaggref;
- }
- }
+ adjustAggrefForPartial(partial_target->exprs);
+ adjustAggrefForPartial(extra->partial_target->exprs);
/* clean up cruft */
list_free(non_group_exprs);
@@ -7148,7 +7227,7 @@ create_partial_grouping_paths(PlannerInfo *root,
*/
partially_grouped_rel->reltarget =
make_partial_grouping_target(root, grouped_rel->reltarget,
- extra->havingQual);
+ extra);
if (!extra->partial_costs_set)
{
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 7afdbf4d9d..ec9ca8e7f4 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -13909,6 +13909,7 @@ dumpAgg(Archive *fout, const AggInfo *agginfo)
const char *aggmtransfn;
const char *aggminvtransfn;
const char *aggmfinalfn;
+ const char *aggpartialfn;
bool aggfinalextra;
bool aggmfinalextra;
char aggfinalmodify;
@@ -13991,11 +13992,18 @@ dumpAgg(Archive *fout, const AggInfo *agginfo)
if (fout->remoteVersion >= 110000)
appendPQExpBufferStr(query,
"aggfinalmodify,\n"
- "aggmfinalmodify\n");
+ "aggmfinalmodify,\n");
else
appendPQExpBufferStr(query,
"'0' AS aggfinalmodify,\n"
- "'0' AS aggmfinalmodify\n");
+ "'0' AS aggmfinalmodify,\n");
+
+ if (fout->remoteVersion >= 170000)
+ appendPQExpBufferStr(query,
+ "aggpartialfn\n");
+ else
+ appendPQExpBufferStr(query,
+ "'-' AS aggpartialfn\n");
appendPQExpBufferStr(query,
"FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
@@ -14021,6 +14029,7 @@ dumpAgg(Archive *fout, const AggInfo *agginfo)
aggcombinefn = PQgetvalue(res, 0, PQfnumber(res, "aggcombinefn"));
aggserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggserialfn"));
aggdeserialfn = PQgetvalue(res, 0, PQfnumber(res, "aggdeserialfn"));
+ aggpartialfn = PQgetvalue(res, 0, PQfnumber(res, "aggpartialfn"));
aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
@@ -14110,6 +14119,9 @@ dumpAgg(Archive *fout, const AggInfo *agginfo)
if (strcmp(aggdeserialfn, "-") != 0)
appendPQExpBuffer(details, ",\n DESERIALFUNC = %s", aggdeserialfn);
+ if (strcmp(aggpartialfn, "-") != 0)
+ appendPQExpBuffer(details, ",\n AGGPARTIALFUNC = %s", aggpartialfn);
+
if (strcmp(aggmtransfn, "-") != 0)
{
appendPQExpBuffer(details, ",\n MSFUNC = %s,\n MINVFUNC = %s,\n MSTYPE = %s",
diff --git a/src/include/catalog/pg_aggregate.dat b/src/include/catalog/pg_aggregate.dat
index 1bc1d97d74..dd97b4dc34 100644
--- a/src/include/catalog/pg_aggregate.dat
+++ b/src/include/catalog/pg_aggregate.dat
@@ -13,22 +13,44 @@
[
# avg
+{ aggfnoid => 'avg_p_int8', aggtransfn => 'int8_avg_accum',
+ aggfinalfn => 'int8_avg_serialize', aggcombinefn => 'int8_avg_combine',
+ aggserialfn => 'int8_avg_serialize', aggdeserialfn => 'int8_avg_deserialize',
+ aggtranstype => 'internal', aggtransspace => '48',
+ aggpartialfn => 'avg_p_int8' },
{ aggfnoid => 'avg(int8)', aggtransfn => 'int8_avg_accum',
aggfinalfn => 'numeric_poly_avg', aggcombinefn => 'int8_avg_combine',
aggserialfn => 'int8_avg_serialize', aggdeserialfn => 'int8_avg_deserialize',
aggmtransfn => 'int8_avg_accum', aggminvtransfn => 'int8_avg_accum_inv',
aggmfinalfn => 'numeric_poly_avg', aggtranstype => 'internal',
- aggtransspace => '48', aggmtranstype => 'internal', aggmtransspace => '48' },
+ aggtransspace => '48', aggmtranstype => 'internal', aggmtransspace => '48',
+ aggpartialfn => 'avg_p_int8' },
+{ aggfnoid => 'avg_p_int4', aggtransfn => 'int4_avg_accum',
+ aggcombinefn => 'int4_avg_combine', aggtranstype => '_int8',
+ agginitval => '{0,0}',
+ aggpartialfn => 'avg_p_int4' },
{ aggfnoid => 'avg(int4)', aggtransfn => 'int4_avg_accum',
aggfinalfn => 'int8_avg', aggcombinefn => 'int4_avg_combine',
aggmtransfn => 'int4_avg_accum', aggminvtransfn => 'int4_avg_accum_inv',
aggmfinalfn => 'int8_avg', aggtranstype => '_int8', aggmtranstype => '_int8',
- agginitval => '{0,0}', aggminitval => '{0,0}' },
+ agginitval => '{0,0}', aggminitval => '{0,0}',
+ aggpartialfn => 'avg_p_int4' },
+{ aggfnoid => 'avg_p_int2', aggtransfn => 'int2_avg_accum',
+ aggcombinefn => 'int4_avg_combine', aggtranstype => '_int8',
+ agginitval => '{0,0}',
+ aggpartialfn => 'avg_p_int2' },
{ aggfnoid => 'avg(int2)', aggtransfn => 'int2_avg_accum',
aggfinalfn => 'int8_avg', aggcombinefn => 'int4_avg_combine',
aggmtransfn => 'int2_avg_accum', aggminvtransfn => 'int2_avg_accum_inv',
aggmfinalfn => 'int8_avg', aggtranstype => '_int8', aggmtranstype => '_int8',
- agginitval => '{0,0}', aggminitval => '{0,0}' },
+ agginitval => '{0,0}', aggminitval => '{0,0}',
+ aggpartialfn => 'avg_p_int2' },
+{ aggfnoid => 'avg_p_numeric', aggtransfn => 'numeric_avg_accum',
+ aggfinalfn => 'numeric_avg_serialize', aggcombinefn => 'numeric_avg_combine',
+ aggserialfn => 'numeric_avg_serialize',
+ aggdeserialfn => 'numeric_avg_deserialize', aggtranstype => 'internal',
+ aggtransspace => '128',
+ aggpartialfn => 'avg_p_numeric' },
{ aggfnoid => 'avg(numeric)', aggtransfn => 'numeric_avg_accum',
aggfinalfn => 'numeric_avg', aggcombinefn => 'numeric_avg_combine',
aggserialfn => 'numeric_avg_serialize',
@@ -36,46 +58,80 @@
aggmtransfn => 'numeric_avg_accum', aggminvtransfn => 'numeric_accum_inv',
aggmfinalfn => 'numeric_avg', aggtranstype => 'internal',
aggtransspace => '128', aggmtranstype => 'internal',
- aggmtransspace => '128' },
+ aggmtransspace => '128',
+ aggpartialfn => 'avg_p_numeric' },
+{ aggfnoid => 'avg_p_float4', aggtransfn => 'float4_accum',
+ aggcombinefn => 'float8_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0}',
+ aggpartialfn => 'avg_p_float4' },
{ aggfnoid => 'avg(float4)', aggtransfn => 'float4_accum',
aggfinalfn => 'float8_avg', aggcombinefn => 'float8_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0}',
+ aggpartialfn => 'avg_p_float4' },
+{ aggfnoid => 'avg_p_float8', aggtransfn => 'float8_accum',
+ aggcombinefn => 'float8_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0}',
+ aggpartialfn => 'avg_p_float8' },
{ aggfnoid => 'avg(float8)', aggtransfn => 'float8_accum',
aggfinalfn => 'float8_avg', aggcombinefn => 'float8_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0}',
+ aggpartialfn => 'avg_p_float8' },
+{ aggfnoid => 'avg_p_interval', aggtransfn => 'interval_accum',
+ aggcombinefn => 'interval_combine', aggtranstype => '_interval',
+ agginitval => '{0 second,0 second}',
+ aggpartialfn => 'avg_p_interval' },
{ aggfnoid => 'avg(interval)', aggtransfn => 'interval_accum',
aggfinalfn => 'interval_avg', aggcombinefn => 'interval_combine',
aggmtransfn => 'interval_accum', aggminvtransfn => 'interval_accum_inv',
aggmfinalfn => 'interval_avg', aggtranstype => '_interval',
aggmtranstype => '_interval', agginitval => '{0 second,0 second}',
- aggminitval => '{0 second,0 second}' },
+ aggminitval => '{0 second,0 second}',
+ aggpartialfn => 'avg_p_interval' },
# sum
+{ aggfnoid => 'sum_p_int8', aggtransfn => 'int8_avg_accum',
+ aggfinalfn => 'int8_avg_serialize', aggcombinefn => 'int8_avg_combine',
+ aggserialfn => 'int8_avg_serialize', aggdeserialfn => 'int8_avg_deserialize',
+ aggtranstype => 'internal', aggtransspace => '48',
+ aggpartialfn => 'sum_p_int8' },
{ aggfnoid => 'sum(int8)', aggtransfn => 'int8_avg_accum',
aggfinalfn => 'numeric_poly_sum', aggcombinefn => 'int8_avg_combine',
aggserialfn => 'int8_avg_serialize', aggdeserialfn => 'int8_avg_deserialize',
aggmtransfn => 'int8_avg_accum', aggminvtransfn => 'int8_avg_accum_inv',
aggmfinalfn => 'numeric_poly_sum', aggtranstype => 'internal',
- aggtransspace => '48', aggmtranstype => 'internal', aggmtransspace => '48' },
+ aggtransspace => '48', aggmtranstype => 'internal', aggmtransspace => '48',
+ aggpartialfn => 'sum_p_int8' },
{ aggfnoid => 'sum(int4)', aggtransfn => 'int4_sum', aggcombinefn => 'int8pl',
aggmtransfn => 'int4_avg_accum', aggminvtransfn => 'int4_avg_accum_inv',
aggmfinalfn => 'int2int4_sum', aggtranstype => 'int8',
- aggmtranstype => '_int8', aggminitval => '{0,0}' },
+ aggmtranstype => '_int8', aggminitval => '{0,0}',
+ aggpartialfn => 'sum(int4)' },
{ aggfnoid => 'sum(int2)', aggtransfn => 'int2_sum', aggcombinefn => 'int8pl',
aggmtransfn => 'int2_avg_accum', aggminvtransfn => 'int2_avg_accum_inv',
aggmfinalfn => 'int2int4_sum', aggtranstype => 'int8',
- aggmtranstype => '_int8', aggminitval => '{0,0}' },
+ aggmtranstype => '_int8', aggminitval => '{0,0}',
+ aggpartialfn => 'sum(int2)' },
{ aggfnoid => 'sum(float4)', aggtransfn => 'float4pl',
- aggcombinefn => 'float4pl', aggtranstype => 'float4' },
+ aggcombinefn => 'float4pl', aggtranstype => 'float4',
+ aggpartialfn => 'sum(float4)' },
{ aggfnoid => 'sum(float8)', aggtransfn => 'float8pl',
- aggcombinefn => 'float8pl', aggtranstype => 'float8' },
+ aggcombinefn => 'float8pl', aggtranstype => 'float8',
+ aggpartialfn => 'sum(float8)' },
{ aggfnoid => 'sum(money)', aggtransfn => 'cash_pl', aggcombinefn => 'cash_pl',
aggmtransfn => 'cash_pl', aggminvtransfn => 'cash_mi',
- aggtranstype => 'money', aggmtranstype => 'money' },
+ aggtranstype => 'money', aggmtranstype => 'money',
+ aggpartialfn => 'sum(money)' },
{ aggfnoid => 'sum(interval)', aggtransfn => 'interval_pl',
aggcombinefn => 'interval_pl', aggmtransfn => 'interval_pl',
aggminvtransfn => 'interval_mi', aggtranstype => 'interval',
- aggmtranstype => 'interval' },
+ aggmtranstype => 'interval',
+ aggpartialfn => 'sum(interval)' },
+{ aggfnoid => 'sum_p_numeric', aggtransfn => 'numeric_avg_accum',
+ aggfinalfn => 'numeric_avg_serialize', aggcombinefn => 'numeric_avg_combine',
+ aggserialfn => 'numeric_avg_serialize',
+ aggdeserialfn => 'numeric_avg_deserialize', aggtranstype => 'internal',
+ aggtransspace => '128',
+ aggpartialfn => 'sum_p_numeric' },
{ aggfnoid => 'sum(numeric)', aggtransfn => 'numeric_avg_accum',
aggfinalfn => 'numeric_sum', aggcombinefn => 'numeric_avg_combine',
aggserialfn => 'numeric_avg_serialize',
@@ -83,269 +139,436 @@
aggmtransfn => 'numeric_avg_accum', aggminvtransfn => 'numeric_accum_inv',
aggmfinalfn => 'numeric_sum', aggtranstype => 'internal',
aggtransspace => '128', aggmtranstype => 'internal',
- aggmtransspace => '128' },
+ aggmtransspace => '128',
+ aggpartialfn => 'sum_p_numeric' },
# max
{ aggfnoid => 'max(int8)', aggtransfn => 'int8larger',
aggcombinefn => 'int8larger', aggsortop => '>(int8,int8)',
- aggtranstype => 'int8' },
+ aggtranstype => 'int8',
+ aggpartialfn => 'max(int8)' },
{ aggfnoid => 'max(int4)', aggtransfn => 'int4larger',
aggcombinefn => 'int4larger', aggsortop => '>(int4,int4)',
- aggtranstype => 'int4' },
+ aggtranstype => 'int4',
+ aggpartialfn => 'max(int4)' },
{ aggfnoid => 'max(int2)', aggtransfn => 'int2larger',
aggcombinefn => 'int2larger', aggsortop => '>(int2,int2)',
- aggtranstype => 'int2' },
+ aggtranstype => 'int2',
+ aggpartialfn => 'max(int2)' },
{ aggfnoid => 'max(oid)', aggtransfn => 'oidlarger',
aggcombinefn => 'oidlarger', aggsortop => '>(oid,oid)',
- aggtranstype => 'oid' },
+ aggtranstype => 'oid',
+ aggpartialfn => 'max(oid)' },
{ aggfnoid => 'max(float4)', aggtransfn => 'float4larger',
aggcombinefn => 'float4larger', aggsortop => '>(float4,float4)',
- aggtranstype => 'float4' },
+ aggtranstype => 'float4',
+ aggpartialfn => 'max(float4)' },
{ aggfnoid => 'max(float8)', aggtransfn => 'float8larger',
aggcombinefn => 'float8larger', aggsortop => '>(float8,float8)',
- aggtranstype => 'float8' },
+ aggtranstype => 'float8',
+ aggpartialfn => 'max(float8)' },
{ aggfnoid => 'max(date)', aggtransfn => 'date_larger',
aggcombinefn => 'date_larger', aggsortop => '>(date,date)',
- aggtranstype => 'date' },
+ aggtranstype => 'date',
+ aggpartialfn => 'max(date)' },
{ aggfnoid => 'max(time)', aggtransfn => 'time_larger',
aggcombinefn => 'time_larger', aggsortop => '>(time,time)',
- aggtranstype => 'time' },
+ aggtranstype => 'time',
+ aggpartialfn => 'max(time)' },
{ aggfnoid => 'max(timetz)', aggtransfn => 'timetz_larger',
aggcombinefn => 'timetz_larger', aggsortop => '>(timetz,timetz)',
- aggtranstype => 'timetz' },
+ aggtranstype => 'timetz',
+ aggpartialfn => 'max(timetz)' },
{ aggfnoid => 'max(money)', aggtransfn => 'cashlarger',
aggcombinefn => 'cashlarger', aggsortop => '>(money,money)',
- aggtranstype => 'money' },
+ aggtranstype => 'money',
+ aggpartialfn => 'max(money)' },
{ aggfnoid => 'max(timestamp)', aggtransfn => 'timestamp_larger',
aggcombinefn => 'timestamp_larger', aggsortop => '>(timestamp,timestamp)',
- aggtranstype => 'timestamp' },
+ aggtranstype => 'timestamp',
+ aggpartialfn => 'max(timestamp)' },
{ aggfnoid => 'max(timestamptz)', aggtransfn => 'timestamptz_larger',
aggcombinefn => 'timestamptz_larger',
- aggsortop => '>(timestamptz,timestamptz)', aggtranstype => 'timestamptz' },
+ aggsortop => '>(timestamptz,timestamptz)', aggtranstype => 'timestamptz',
+ aggpartialfn => 'max(timestamptz)' },
{ aggfnoid => 'max(interval)', aggtransfn => 'interval_larger',
aggcombinefn => 'interval_larger', aggsortop => '>(interval,interval)',
- aggtranstype => 'interval' },
+ aggtranstype => 'interval',
+ aggpartialfn => 'max(interval)' },
{ aggfnoid => 'max(text)', aggtransfn => 'text_larger',
aggcombinefn => 'text_larger', aggsortop => '>(text,text)',
- aggtranstype => 'text' },
+ aggtranstype => 'text',
+ aggpartialfn => 'max(text)' },
{ aggfnoid => 'max(numeric)', aggtransfn => 'numeric_larger',
aggcombinefn => 'numeric_larger', aggsortop => '>(numeric,numeric)',
- aggtranstype => 'numeric' },
+ aggtranstype => 'numeric',
+ aggpartialfn => 'max(numeric)' },
{ aggfnoid => 'max(anyarray)', aggtransfn => 'array_larger',
aggcombinefn => 'array_larger', aggsortop => '>(anyarray,anyarray)',
- aggtranstype => 'anyarray' },
+ aggtranstype => 'anyarray',
+ aggpartialfn => 'max(anyarray)' },
{ aggfnoid => 'max(bpchar)', aggtransfn => 'bpchar_larger',
aggcombinefn => 'bpchar_larger', aggsortop => '>(bpchar,bpchar)',
- aggtranstype => 'bpchar' },
+ aggtranstype => 'bpchar',
+ aggpartialfn => 'max(bpchar)' },
{ aggfnoid => 'max(tid)', aggtransfn => 'tidlarger',
aggcombinefn => 'tidlarger', aggsortop => '>(tid,tid)',
- aggtranstype => 'tid' },
+ aggtranstype => 'tid',
+ aggpartialfn => 'max(tid)' },
{ aggfnoid => 'max(anyenum)', aggtransfn => 'enum_larger',
aggcombinefn => 'enum_larger', aggsortop => '>(anyenum,anyenum)',
- aggtranstype => 'anyenum' },
+ aggtranstype => 'anyenum',
+ aggpartialfn => 'max(anyenum)' },
{ aggfnoid => 'max(inet)', aggtransfn => 'network_larger',
aggcombinefn => 'network_larger', aggsortop => '>(inet,inet)',
- aggtranstype => 'inet' },
+ aggtranstype => 'inet',
+ aggpartialfn => 'max(inet)' },
{ aggfnoid => 'max(pg_lsn)', aggtransfn => 'pg_lsn_larger',
aggcombinefn => 'pg_lsn_larger', aggsortop => '>(pg_lsn,pg_lsn)',
- aggtranstype => 'pg_lsn' },
+ aggtranstype => 'pg_lsn',
+ aggpartialfn => 'max(pg_lsn)' },
{ aggfnoid => 'max(xid8)', aggtransfn => 'xid8_larger',
aggcombinefn => 'xid8_larger', aggsortop => '>(xid8,xid8)',
- aggtranstype => 'xid8' },
+ aggtranstype => 'xid8',
+ aggpartialfn => 'max(xid8)' },
# min
{ aggfnoid => 'min(int8)', aggtransfn => 'int8smaller',
aggcombinefn => 'int8smaller', aggsortop => '<(int8,int8)',
- aggtranstype => 'int8' },
+ aggtranstype => 'int8',
+ aggpartialfn => 'min(int8)' },
{ aggfnoid => 'min(int4)', aggtransfn => 'int4smaller',
aggcombinefn => 'int4smaller', aggsortop => '<(int4,int4)',
- aggtranstype => 'int4' },
+ aggtranstype => 'int4',
+ aggpartialfn => 'min(int4)' },
{ aggfnoid => 'min(int2)', aggtransfn => 'int2smaller',
aggcombinefn => 'int2smaller', aggsortop => '<(int2,int2)',
- aggtranstype => 'int2' },
+ aggtranstype => 'int2',
+ aggpartialfn => 'min(int2)' },
{ aggfnoid => 'min(oid)', aggtransfn => 'oidsmaller',
aggcombinefn => 'oidsmaller', aggsortop => '<(oid,oid)',
- aggtranstype => 'oid' },
+ aggtranstype => 'oid',
+ aggpartialfn => 'min(oid)' },
{ aggfnoid => 'min(float4)', aggtransfn => 'float4smaller',
aggcombinefn => 'float4smaller', aggsortop => '<(float4,float4)',
- aggtranstype => 'float4' },
+ aggtranstype => 'float4',
+ aggpartialfn => 'min(float4)' },
{ aggfnoid => 'min(float8)', aggtransfn => 'float8smaller',
aggcombinefn => 'float8smaller', aggsortop => '<(float8,float8)',
- aggtranstype => 'float8' },
+ aggtranstype => 'float8',
+ aggpartialfn => 'min(float8)' },
{ aggfnoid => 'min(date)', aggtransfn => 'date_smaller',
aggcombinefn => 'date_smaller', aggsortop => '<(date,date)',
- aggtranstype => 'date' },
+ aggtranstype => 'date',
+ aggpartialfn => 'min(date)' },
{ aggfnoid => 'min(time)', aggtransfn => 'time_smaller',
aggcombinefn => 'time_smaller', aggsortop => '<(time,time)',
- aggtranstype => 'time' },
+ aggtranstype => 'time',
+ aggpartialfn => 'min(time)' },
{ aggfnoid => 'min(timetz)', aggtransfn => 'timetz_smaller',
aggcombinefn => 'timetz_smaller', aggsortop => '<(timetz,timetz)',
- aggtranstype => 'timetz' },
+ aggtranstype => 'timetz',
+ aggpartialfn => 'min(timetz)' },
{ aggfnoid => 'min(money)', aggtransfn => 'cashsmaller',
aggcombinefn => 'cashsmaller', aggsortop => '<(money,money)',
- aggtranstype => 'money' },
+ aggtranstype => 'money',
+ aggpartialfn => 'min(money)' },
{ aggfnoid => 'min(timestamp)', aggtransfn => 'timestamp_smaller',
aggcombinefn => 'timestamp_smaller', aggsortop => '<(timestamp,timestamp)',
- aggtranstype => 'timestamp' },
+ aggtranstype => 'timestamp',
+ aggpartialfn => 'min(timestamp)' },
{ aggfnoid => 'min(timestamptz)', aggtransfn => 'timestamptz_smaller',
aggcombinefn => 'timestamptz_smaller',
- aggsortop => '<(timestamptz,timestamptz)', aggtranstype => 'timestamptz' },
+ aggsortop => '<(timestamptz,timestamptz)', aggtranstype => 'timestamptz',
+ aggpartialfn => 'min(timestamptz)' },
{ aggfnoid => 'min(interval)', aggtransfn => 'interval_smaller',
aggcombinefn => 'interval_smaller', aggsortop => '<(interval,interval)',
- aggtranstype => 'interval' },
+ aggtranstype => 'interval',
+ aggpartialfn => 'min(interval)' },
{ aggfnoid => 'min(text)', aggtransfn => 'text_smaller',
aggcombinefn => 'text_smaller', aggsortop => '<(text,text)',
- aggtranstype => 'text' },
+ aggtranstype => 'text',
+ aggpartialfn => 'min(text)' },
{ aggfnoid => 'min(numeric)', aggtransfn => 'numeric_smaller',
aggcombinefn => 'numeric_smaller', aggsortop => '<(numeric,numeric)',
- aggtranstype => 'numeric' },
+ aggtranstype => 'numeric',
+ aggpartialfn => 'min(numeric)' },
{ aggfnoid => 'min(anyarray)', aggtransfn => 'array_smaller',
aggcombinefn => 'array_smaller', aggsortop => '<(anyarray,anyarray)',
- aggtranstype => 'anyarray' },
+ aggtranstype => 'anyarray',
+ aggpartialfn => 'min(anyarray)' },
{ aggfnoid => 'min(bpchar)', aggtransfn => 'bpchar_smaller',
aggcombinefn => 'bpchar_smaller', aggsortop => '<(bpchar,bpchar)',
- aggtranstype => 'bpchar' },
+ aggtranstype => 'bpchar',
+ aggpartialfn => 'min(bpchar)' },
{ aggfnoid => 'min(tid)', aggtransfn => 'tidsmaller',
aggcombinefn => 'tidsmaller', aggsortop => '<(tid,tid)',
- aggtranstype => 'tid' },
+ aggtranstype => 'tid',
+ aggpartialfn => 'min(tid)' },
{ aggfnoid => 'min(anyenum)', aggtransfn => 'enum_smaller',
aggcombinefn => 'enum_smaller', aggsortop => '<(anyenum,anyenum)',
- aggtranstype => 'anyenum' },
+ aggtranstype => 'anyenum',
+ aggpartialfn => 'min(anyenum)' },
{ aggfnoid => 'min(inet)', aggtransfn => 'network_smaller',
aggcombinefn => 'network_smaller', aggsortop => '<(inet,inet)',
- aggtranstype => 'inet' },
+ aggtranstype => 'inet',
+ aggpartialfn => 'min(inet)' },
{ aggfnoid => 'min(pg_lsn)', aggtransfn => 'pg_lsn_smaller',
aggcombinefn => 'pg_lsn_smaller', aggsortop => '<(pg_lsn,pg_lsn)',
- aggtranstype => 'pg_lsn' },
+ aggtranstype => 'pg_lsn',
+ aggpartialfn => 'min(pg_lsn)' },
{ aggfnoid => 'min(xid8)', aggtransfn => 'xid8_smaller',
aggcombinefn => 'xid8_smaller', aggsortop => '<(xid8,xid8)',
- aggtranstype => 'xid8' },
+ aggtranstype => 'xid8',
+ aggpartialfn => 'min(xid8)' },
# count
{ aggfnoid => 'count(any)', aggtransfn => 'int8inc_any',
aggcombinefn => 'int8pl', aggmtransfn => 'int8inc_any',
aggminvtransfn => 'int8dec_any', aggtranstype => 'int8',
- aggmtranstype => 'int8', agginitval => '0', aggminitval => '0' },
+ aggmtranstype => 'int8', agginitval => '0', aggminitval => '0',
+ aggpartialfn => 'count(any)' },
{ aggfnoid => 'count()', aggtransfn => 'int8inc', aggcombinefn => 'int8pl',
aggmtransfn => 'int8inc', aggminvtransfn => 'int8dec', aggtranstype => 'int8',
- aggmtranstype => 'int8', agginitval => '0', aggminitval => '0' },
+ aggmtranstype => 'int8', agginitval => '0', aggminitval => '0',
+ aggpartialfn => 'count()' },
# var_pop
+{ aggfnoid => 'var_pop_p_int8', aggtransfn => 'int8_accum',
+ aggfinalfn => 'numeric_serialize', aggcombinefn => 'numeric_combine',
+ aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
+ aggtranstype => 'internal', aggtransspace => '128',
+ aggpartialfn => 'var_pop_p_int8' },
{ aggfnoid => 'var_pop(int8)', aggtransfn => 'int8_accum',
aggfinalfn => 'numeric_var_pop', aggcombinefn => 'numeric_combine',
aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
aggmtransfn => 'int8_accum', aggminvtransfn => 'int8_accum_inv',
aggmfinalfn => 'numeric_var_pop', aggtranstype => 'internal',
aggtransspace => '128', aggmtranstype => 'internal',
- aggmtransspace => '128' },
+ aggmtransspace => '128',
+ aggpartialfn => 'var_pop_p_int8' },
+{ aggfnoid => 'var_pop_p_int4', aggtransfn => 'int4_accum',
+ aggfinalfn => 'numeric_poly_serialize', aggcombinefn => 'numeric_poly_combine',
+ aggserialfn => 'numeric_poly_serialize',
+ aggdeserialfn => 'numeric_poly_deserialize', aggtranstype => 'internal',
+ aggtransspace => '48',
+ aggpartialfn => 'var_pop_p_int4' },
{ aggfnoid => 'var_pop(int4)', aggtransfn => 'int4_accum',
aggfinalfn => 'numeric_poly_var_pop', aggcombinefn => 'numeric_poly_combine',
aggserialfn => 'numeric_poly_serialize',
aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int4_accum',
aggminvtransfn => 'int4_accum_inv', aggmfinalfn => 'numeric_poly_var_pop',
aggtranstype => 'internal', aggtransspace => '48',
- aggmtranstype => 'internal', aggmtransspace => '48' },
+ aggmtranstype => 'internal', aggmtransspace => '48',
+ aggpartialfn => 'var_pop_p_int4' },
+{ aggfnoid => 'var_pop_p_int2', aggtransfn => 'int2_accum',
+ aggfinalfn => 'numeric_poly_serialize', aggcombinefn => 'numeric_poly_combine',
+ aggserialfn => 'numeric_poly_serialize',
+ aggdeserialfn => 'numeric_poly_deserialize', aggtranstype => 'internal',
+ aggtransspace => '48',
+ aggpartialfn => 'var_pop_p_int2' },
{ aggfnoid => 'var_pop(int2)', aggtransfn => 'int2_accum',
aggfinalfn => 'numeric_poly_var_pop', aggcombinefn => 'numeric_poly_combine',
aggserialfn => 'numeric_poly_serialize',
aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int2_accum',
aggminvtransfn => 'int2_accum_inv', aggmfinalfn => 'numeric_poly_var_pop',
aggtranstype => 'internal', aggtransspace => '48',
- aggmtranstype => 'internal', aggmtransspace => '48' },
+ aggmtranstype => 'internal', aggmtransspace => '48',
+ aggpartialfn => 'var_pop_p_int2' },
+{ aggfnoid => 'var_pop_p_float4', aggtransfn => 'float4_accum',
+ aggcombinefn => 'float8_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0}',
+ aggpartialfn => 'var_pop_p_float4' },
{ aggfnoid => 'var_pop(float4)', aggtransfn => 'float4_accum',
aggfinalfn => 'float8_var_pop', aggcombinefn => 'float8_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0}',
+ aggpartialfn => 'var_pop_p_float4' },
+{ aggfnoid => 'var_pop_p_float8', aggtransfn => 'float8_accum',
+ aggcombinefn => 'float8_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0}',
+ aggpartialfn => 'var_pop_p_float8' },
{ aggfnoid => 'var_pop(float8)', aggtransfn => 'float8_accum',
aggfinalfn => 'float8_var_pop', aggcombinefn => 'float8_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0}',
+ aggpartialfn => 'var_pop_p_float8' },
+{ aggfnoid => 'var_pop_p_numeric', aggtransfn => 'numeric_accum',
+ aggfinalfn => 'numeric_serialize', aggcombinefn => 'numeric_combine',
+ aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
+ aggtranstype => 'internal', aggtransspace => '128',
+ aggpartialfn => 'var_pop_p_numeric' },
{ aggfnoid => 'var_pop(numeric)', aggtransfn => 'numeric_accum',
aggfinalfn => 'numeric_var_pop', aggcombinefn => 'numeric_combine',
aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
aggmtransfn => 'numeric_accum', aggminvtransfn => 'numeric_accum_inv',
aggmfinalfn => 'numeric_var_pop', aggtranstype => 'internal',
aggtransspace => '128', aggmtranstype => 'internal',
- aggmtransspace => '128' },
+ aggmtransspace => '128',
+ aggpartialfn => 'var_pop_p_numeric' },
# var_samp
+{ aggfnoid => 'var_samp_p_int8', aggtransfn => 'int8_accum',
+ aggfinalfn => 'numeric_serialize', aggcombinefn => 'numeric_combine',
+ aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
+ aggtranstype => 'internal', aggtransspace => '128',
+ aggpartialfn => 'var_samp_p_int8' },
{ aggfnoid => 'var_samp(int8)', aggtransfn => 'int8_accum',
aggfinalfn => 'numeric_var_samp', aggcombinefn => 'numeric_combine',
aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
aggmtransfn => 'int8_accum', aggminvtransfn => 'int8_accum_inv',
aggmfinalfn => 'numeric_var_samp', aggtranstype => 'internal',
aggtransspace => '128', aggmtranstype => 'internal',
- aggmtransspace => '128' },
+ aggmtransspace => '128',
+ aggpartialfn => 'var_samp_p_int8' },
+{ aggfnoid => 'var_samp_p_int4', aggtransfn => 'int4_accum',
+ aggfinalfn => 'numeric_poly_serialize', aggcombinefn => 'numeric_poly_combine',
+ aggserialfn => 'numeric_poly_serialize',
+ aggdeserialfn => 'numeric_poly_deserialize', aggtranstype => 'internal',
+ aggtransspace => '48',
+ aggpartialfn => 'var_samp_p_int4' },
{ aggfnoid => 'var_samp(int4)', aggtransfn => 'int4_accum',
aggfinalfn => 'numeric_poly_var_samp', aggcombinefn => 'numeric_poly_combine',
aggserialfn => 'numeric_poly_serialize',
aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int4_accum',
aggminvtransfn => 'int4_accum_inv', aggmfinalfn => 'numeric_poly_var_samp',
aggtranstype => 'internal', aggtransspace => '48',
- aggmtranstype => 'internal', aggmtransspace => '48' },
+ aggmtranstype => 'internal', aggmtransspace => '48',
+ aggpartialfn => 'var_samp_p_int4' },
+{ aggfnoid => 'var_samp_p_int2', aggtransfn => 'int2_accum',
+ aggfinalfn => 'numeric_poly_serialize', aggcombinefn => 'numeric_poly_combine',
+ aggserialfn => 'numeric_poly_serialize',
+ aggdeserialfn => 'numeric_poly_deserialize', aggtranstype => 'internal',
+ aggtransspace => '48',
+ aggpartialfn => 'var_samp_p_int2' },
{ aggfnoid => 'var_samp(int2)', aggtransfn => 'int2_accum',
aggfinalfn => 'numeric_poly_var_samp', aggcombinefn => 'numeric_poly_combine',
aggserialfn => 'numeric_poly_serialize',
aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int2_accum',
aggminvtransfn => 'int2_accum_inv', aggmfinalfn => 'numeric_poly_var_samp',
aggtranstype => 'internal', aggtransspace => '48',
- aggmtranstype => 'internal', aggmtransspace => '48' },
+ aggmtranstype => 'internal', aggmtransspace => '48',
+ aggpartialfn => 'var_samp_p_int2' },
+{ aggfnoid => 'var_samp_p_float4', aggtransfn => 'float4_accum',
+ aggcombinefn => 'float8_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0}',
+ aggpartialfn => 'var_samp_p_float4' },
{ aggfnoid => 'var_samp(float4)', aggtransfn => 'float4_accum',
aggfinalfn => 'float8_var_samp', aggcombinefn => 'float8_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0}',
+ aggpartialfn => 'var_samp_p_float4' },
+{ aggfnoid => 'var_samp_p_float8', aggtransfn => 'float8_accum',
+ aggcombinefn => 'float8_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0}',
+ aggpartialfn => 'var_samp_p_float8' },
{ aggfnoid => 'var_samp(float8)', aggtransfn => 'float8_accum',
aggfinalfn => 'float8_var_samp', aggcombinefn => 'float8_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0}',
+ aggpartialfn => 'var_samp_p_float8' },
+{ aggfnoid => 'var_samp_p_numeric', aggtransfn => 'numeric_accum',
+ aggfinalfn => 'numeric_serialize', aggcombinefn => 'numeric_combine',
+ aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
+ aggtranstype => 'internal', aggtransspace => '128',
+ aggpartialfn => 'var_samp_p_numeric' },
{ aggfnoid => 'var_samp(numeric)', aggtransfn => 'numeric_accum',
aggfinalfn => 'numeric_var_samp', aggcombinefn => 'numeric_combine',
aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
aggmtransfn => 'numeric_accum', aggminvtransfn => 'numeric_accum_inv',
aggmfinalfn => 'numeric_var_samp', aggtranstype => 'internal',
aggtransspace => '128', aggmtranstype => 'internal',
- aggmtransspace => '128' },
+ aggmtransspace => '128',
+ aggpartialfn => 'var_samp_p_numeric' },
# variance: historical Postgres syntax for var_samp
+{ aggfnoid => 'variance_p_int8', aggtransfn => 'int8_accum',
+ aggfinalfn => 'numeric_serialize', aggcombinefn => 'numeric_combine',
+ aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
+ aggtranstype => 'internal', aggtransspace => '128',
+ aggpartialfn => 'variance_p_int8' },
{ aggfnoid => 'variance(int8)', aggtransfn => 'int8_accum',
aggfinalfn => 'numeric_var_samp', aggcombinefn => 'numeric_combine',
aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
aggmtransfn => 'int8_accum', aggminvtransfn => 'int8_accum_inv',
aggmfinalfn => 'numeric_var_samp', aggtranstype => 'internal',
aggtransspace => '128', aggmtranstype => 'internal',
- aggmtransspace => '128' },
+ aggmtransspace => '128',
+ aggpartialfn => 'variance_p_int8' },
+{ aggfnoid => 'variance_p_int4', aggtransfn => 'int4_accum',
+ aggfinalfn => 'numeric_poly_serialize', aggcombinefn => 'numeric_poly_combine',
+ aggserialfn => 'numeric_poly_serialize',
+ aggdeserialfn => 'numeric_poly_deserialize', aggtranstype => 'internal',
+ aggtransspace => '48',
+ aggpartialfn => 'variance_p_int4' },
{ aggfnoid => 'variance(int4)', aggtransfn => 'int4_accum',
aggfinalfn => 'numeric_poly_var_samp', aggcombinefn => 'numeric_poly_combine',
aggserialfn => 'numeric_poly_serialize',
aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int4_accum',
aggminvtransfn => 'int4_accum_inv', aggmfinalfn => 'numeric_poly_var_samp',
aggtranstype => 'internal', aggtransspace => '48',
- aggmtranstype => 'internal', aggmtransspace => '48' },
+ aggmtranstype => 'internal', aggmtransspace => '48',
+ aggpartialfn => 'variance_p_int4' },
+{ aggfnoid => 'variance_p_int2', aggtransfn => 'int2_accum',
+ aggfinalfn => 'numeric_poly_serialize', aggcombinefn => 'numeric_poly_combine',
+ aggserialfn => 'numeric_poly_serialize',
+ aggdeserialfn => 'numeric_poly_deserialize', aggtranstype => 'internal',
+ aggtransspace => '48',
+ aggpartialfn => 'variance_p_int2' },
{ aggfnoid => 'variance(int2)', aggtransfn => 'int2_accum',
aggfinalfn => 'numeric_poly_var_samp', aggcombinefn => 'numeric_poly_combine',
aggserialfn => 'numeric_poly_serialize',
aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int2_accum',
aggminvtransfn => 'int2_accum_inv', aggmfinalfn => 'numeric_poly_var_samp',
aggtranstype => 'internal', aggtransspace => '48',
- aggmtranstype => 'internal', aggmtransspace => '48' },
+ aggmtranstype => 'internal', aggmtransspace => '48',
+ aggpartialfn => 'variance_p_int2' },
+{ aggfnoid => 'variance_p_float4', aggtransfn => 'float4_accum',
+ aggcombinefn => 'float8_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0}',
+ aggpartialfn => 'variance_p_float4' },
{ aggfnoid => 'variance(float4)', aggtransfn => 'float4_accum',
aggfinalfn => 'float8_var_samp', aggcombinefn => 'float8_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0}',
+ aggpartialfn => 'variance_p_float4' },
+{ aggfnoid => 'variance_p_float8', aggtransfn => 'float8_accum',
+ aggcombinefn => 'float8_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0}',
+ aggpartialfn => 'variance_p_float8' },
{ aggfnoid => 'variance(float8)', aggtransfn => 'float8_accum',
aggfinalfn => 'float8_var_samp', aggcombinefn => 'float8_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0}',
+ aggpartialfn => 'variance_p_float8' },
+{ aggfnoid => 'variance_p_numeric', aggtransfn => 'numeric_accum',
+ aggfinalfn => 'numeric_serialize', aggcombinefn => 'numeric_combine',
+ aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
+ aggtranstype => 'internal', aggtransspace => '128',
+ aggpartialfn => 'variance_p_numeric' },
{ aggfnoid => 'variance(numeric)', aggtransfn => 'numeric_accum',
aggfinalfn => 'numeric_var_samp', aggcombinefn => 'numeric_combine',
aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
aggmtransfn => 'numeric_accum', aggminvtransfn => 'numeric_accum_inv',
aggmfinalfn => 'numeric_var_samp', aggtranstype => 'internal',
aggtransspace => '128', aggmtranstype => 'internal',
- aggmtransspace => '128' },
+ aggmtransspace => '128',
+ aggpartialfn => 'variance_p_numeric' },
# stddev_pop
+{ aggfnoid => 'stddev_pop_p_int8', aggtransfn => 'int8_accum',
+ aggfinalfn => 'numeric_serialize', aggcombinefn => 'numeric_combine',
+ aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
+ aggtranstype => 'internal', aggtransspace => '128',
+ aggpartialfn => 'stddev_pop_p_int8' },
{ aggfnoid => 'stddev_pop(int8)', aggtransfn => 'int8_accum',
aggfinalfn => 'numeric_stddev_pop', aggcombinefn => 'numeric_combine',
aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
aggmtransfn => 'int8_accum', aggminvtransfn => 'int8_accum_inv',
aggmfinalfn => 'numeric_stddev_pop', aggtranstype => 'internal',
aggtransspace => '128', aggmtranstype => 'internal',
- aggmtransspace => '128' },
+ aggmtransspace => '128',
+ aggpartialfn => 'stddev_pop_p_int8' },
+{ aggfnoid => 'stddev_pop_p_int4', aggtransfn => 'int4_accum',
+ aggfinalfn => 'numeric_poly_serialize', aggcombinefn => 'numeric_poly_combine',
+ aggserialfn => 'numeric_poly_serialize',
+ aggdeserialfn => 'numeric_poly_deserialize', aggtranstype => 'internal',
+ aggtransspace => '48',
+ aggpartialfn => 'stddev_pop_p_int4' },
{ aggfnoid => 'stddev_pop(int4)', aggtransfn => 'int4_accum',
aggfinalfn => 'numeric_poly_stddev_pop',
aggcombinefn => 'numeric_poly_combine',
@@ -353,7 +576,14 @@
aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int4_accum',
aggminvtransfn => 'int4_accum_inv', aggmfinalfn => 'numeric_poly_stddev_pop',
aggtranstype => 'internal', aggtransspace => '48',
- aggmtranstype => 'internal', aggmtransspace => '48' },
+ aggmtranstype => 'internal', aggmtransspace => '48',
+ aggpartialfn => 'stddev_pop_p_int4' },
+{ aggfnoid => 'stddev_pop_p_int2', aggtransfn => 'int2_accum',
+ aggfinalfn => 'numeric_poly_serialize', aggcombinefn => 'numeric_poly_combine',
+ aggserialfn => 'numeric_poly_serialize',
+ aggdeserialfn => 'numeric_poly_deserialize', aggtranstype => 'internal',
+ aggtransspace => '48',
+ aggpartialfn => 'stddev_pop_p_int2' },
{ aggfnoid => 'stddev_pop(int2)', aggtransfn => 'int2_accum',
aggfinalfn => 'numeric_poly_stddev_pop',
aggcombinefn => 'numeric_poly_combine',
@@ -361,29 +591,58 @@
aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int2_accum',
aggminvtransfn => 'int2_accum_inv', aggmfinalfn => 'numeric_poly_stddev_pop',
aggtranstype => 'internal', aggtransspace => '48',
- aggmtranstype => 'internal', aggmtransspace => '48' },
+ aggmtranstype => 'internal', aggmtransspace => '48',
+ aggpartialfn => 'stddev_pop_p_int2' },
+{ aggfnoid => 'stddev_pop_p_float4', aggtransfn => 'float4_accum',
+ aggcombinefn => 'float8_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0}',
+ aggpartialfn => 'stddev_pop_p_float4' },
{ aggfnoid => 'stddev_pop(float4)', aggtransfn => 'float4_accum',
aggfinalfn => 'float8_stddev_pop', aggcombinefn => 'float8_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0}',
+ aggpartialfn => 'stddev_pop_p_float4' },
+{ aggfnoid => 'stddev_pop_p_float8', aggtransfn => 'float8_accum',
+ aggcombinefn => 'float8_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0}',
+ aggpartialfn => 'stddev_pop_p_float8' },
{ aggfnoid => 'stddev_pop(float8)', aggtransfn => 'float8_accum',
aggfinalfn => 'float8_stddev_pop', aggcombinefn => 'float8_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0}',
+ aggpartialfn => 'stddev_pop_p_float8' },
+{ aggfnoid => 'stddev_pop_p_numeric', aggtransfn => 'numeric_accum',
+ aggfinalfn => 'numeric_serialize', aggcombinefn => 'numeric_combine',
+ aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
+ aggtranstype => 'internal', aggtransspace => '128',
+ aggpartialfn => 'stddev_pop_p_numeric' },
{ aggfnoid => 'stddev_pop(numeric)', aggtransfn => 'numeric_accum',
aggfinalfn => 'numeric_stddev_pop', aggcombinefn => 'numeric_combine',
aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
aggmtransfn => 'numeric_accum', aggminvtransfn => 'numeric_accum_inv',
aggmfinalfn => 'numeric_stddev_pop', aggtranstype => 'internal',
aggtransspace => '128', aggmtranstype => 'internal',
- aggmtransspace => '128' },
+ aggmtransspace => '128',
+ aggpartialfn => 'stddev_pop_p_numeric' },
# stddev_samp
+{ aggfnoid => 'stddev_samp_p_int8', aggtransfn => 'int8_accum',
+ aggfinalfn => 'numeric_serialize', aggcombinefn => 'numeric_combine',
+ aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
+ aggtranstype => 'internal', aggtransspace => '128',
+ aggpartialfn => 'stddev_samp_p_int8' },
{ aggfnoid => 'stddev_samp(int8)', aggtransfn => 'int8_accum',
aggfinalfn => 'numeric_stddev_samp', aggcombinefn => 'numeric_combine',
aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
aggmtransfn => 'int8_accum', aggminvtransfn => 'int8_accum_inv',
aggmfinalfn => 'numeric_stddev_samp', aggtranstype => 'internal',
aggtransspace => '128', aggmtranstype => 'internal',
- aggmtransspace => '128' },
+ aggmtransspace => '128',
+ aggpartialfn => 'stddev_samp_p_int8' },
+{ aggfnoid => 'stddev_samp_p_int4', aggtransfn => 'int4_accum',
+ aggfinalfn => 'numeric_poly_serialize', aggcombinefn => 'numeric_poly_combine',
+ aggserialfn => 'numeric_poly_serialize',
+ aggdeserialfn => 'numeric_poly_deserialize', aggtranstype => 'internal',
+ aggtransspace => '48',
+ aggpartialfn => 'stddev_samp_p_int4' },
{ aggfnoid => 'stddev_samp(int4)', aggtransfn => 'int4_accum',
aggfinalfn => 'numeric_poly_stddev_samp',
aggcombinefn => 'numeric_poly_combine',
@@ -391,7 +650,14 @@
aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int4_accum',
aggminvtransfn => 'int4_accum_inv', aggmfinalfn => 'numeric_poly_stddev_samp',
aggtranstype => 'internal', aggtransspace => '48',
- aggmtranstype => 'internal', aggmtransspace => '48' },
+ aggmtranstype => 'internal', aggmtransspace => '48',
+ aggpartialfn => 'stddev_samp_p_int4' },
+{ aggfnoid => 'stddev_samp_p_int2', aggtransfn => 'int2_accum',
+ aggfinalfn => 'numeric_poly_serialize', aggcombinefn => 'numeric_poly_combine',
+ aggserialfn => 'numeric_poly_serialize',
+ aggdeserialfn => 'numeric_poly_deserialize', aggtranstype => 'internal',
+ aggtransspace => '48',
+ aggpartialfn => 'stddev_samp_p_int2' },
{ aggfnoid => 'stddev_samp(int2)', aggtransfn => 'int2_accum',
aggfinalfn => 'numeric_poly_stddev_samp',
aggcombinefn => 'numeric_poly_combine',
@@ -399,29 +665,58 @@
aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int2_accum',
aggminvtransfn => 'int2_accum_inv', aggmfinalfn => 'numeric_poly_stddev_samp',
aggtranstype => 'internal', aggtransspace => '48',
- aggmtranstype => 'internal', aggmtransspace => '48' },
+ aggmtranstype => 'internal', aggmtransspace => '48',
+ aggpartialfn => 'stddev_samp_p_int2' },
+{ aggfnoid => 'stddev_samp_p_float4', aggtransfn => 'float4_accum',
+ aggcombinefn => 'float8_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0}',
+ aggpartialfn => 'stddev_samp_p_float4' },
{ aggfnoid => 'stddev_samp(float4)', aggtransfn => 'float4_accum',
aggfinalfn => 'float8_stddev_samp', aggcombinefn => 'float8_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0}',
+ aggpartialfn => 'stddev_samp_p_float4' },
+{ aggfnoid => 'stddev_samp_p_float8', aggtransfn => 'float8_accum',
+ aggcombinefn => 'float8_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0}',
+ aggpartialfn => 'stddev_samp_p_float8' },
{ aggfnoid => 'stddev_samp(float8)', aggtransfn => 'float8_accum',
aggfinalfn => 'float8_stddev_samp', aggcombinefn => 'float8_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0}',
+ aggpartialfn => 'stddev_samp_p_float8' },
+{ aggfnoid => 'stddev_samp_p_numeric', aggtransfn => 'numeric_accum',
+ aggfinalfn => 'numeric_serialize', aggcombinefn => 'numeric_combine',
+ aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
+ aggtranstype => 'internal', aggtransspace => '128',
+ aggpartialfn => 'stddev_samp_p_numeric' },
{ aggfnoid => 'stddev_samp(numeric)', aggtransfn => 'numeric_accum',
aggfinalfn => 'numeric_stddev_samp', aggcombinefn => 'numeric_combine',
aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
aggmtransfn => 'numeric_accum', aggminvtransfn => 'numeric_accum_inv',
aggmfinalfn => 'numeric_stddev_samp', aggtranstype => 'internal',
aggtransspace => '128', aggmtranstype => 'internal',
- aggmtransspace => '128' },
+ aggmtransspace => '128',
+ aggpartialfn => 'stddev_samp_p_numeric' },
# stddev: historical Postgres syntax for stddev_samp
+{ aggfnoid => 'stddev_p_int8', aggtransfn => 'int8_accum',
+ aggfinalfn => 'numeric_serialize', aggcombinefn => 'numeric_combine',
+ aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
+ aggtranstype => 'internal', aggtransspace => '128',
+ aggpartialfn => 'stddev_p_int8' },
{ aggfnoid => 'stddev(int8)', aggtransfn => 'int8_accum',
aggfinalfn => 'numeric_stddev_samp', aggcombinefn => 'numeric_combine',
aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
aggmtransfn => 'int8_accum', aggminvtransfn => 'int8_accum_inv',
aggmfinalfn => 'numeric_stddev_samp', aggtranstype => 'internal',
aggtransspace => '128', aggmtranstype => 'internal',
- aggmtransspace => '128' },
+ aggmtransspace => '128',
+ aggpartialfn => 'stddev_p_int8' },
+{ aggfnoid => 'stddev_p_int4', aggtransfn => 'int4_accum',
+ aggfinalfn => 'numeric_poly_serialize', aggcombinefn => 'numeric_poly_combine',
+ aggserialfn => 'numeric_poly_serialize',
+ aggdeserialfn => 'numeric_poly_deserialize', aggtranstype => 'internal',
+ aggtransspace => '48',
+ aggpartialfn => 'stddev_p_int4' },
{ aggfnoid => 'stddev(int4)', aggtransfn => 'int4_accum',
aggfinalfn => 'numeric_poly_stddev_samp',
aggcombinefn => 'numeric_poly_combine',
@@ -429,7 +724,14 @@
aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int4_accum',
aggminvtransfn => 'int4_accum_inv', aggmfinalfn => 'numeric_poly_stddev_samp',
aggtranstype => 'internal', aggtransspace => '48',
- aggmtranstype => 'internal', aggmtransspace => '48' },
+ aggmtranstype => 'internal', aggmtransspace => '48',
+ aggpartialfn => 'stddev_p_int4' },
+{ aggfnoid => 'stddev_p_int2', aggtransfn => 'int2_accum',
+ aggfinalfn => 'numeric_poly_serialize', aggcombinefn => 'numeric_poly_combine',
+ aggserialfn => 'numeric_poly_serialize',
+ aggdeserialfn => 'numeric_poly_deserialize', aggtranstype => 'internal',
+ aggtransspace => '48',
+ aggpartialfn => 'stddev_p_int2' },
{ aggfnoid => 'stddev(int2)', aggtransfn => 'int2_accum',
aggfinalfn => 'numeric_poly_stddev_samp',
aggcombinefn => 'numeric_poly_combine',
@@ -437,138 +739,253 @@
aggdeserialfn => 'numeric_poly_deserialize', aggmtransfn => 'int2_accum',
aggminvtransfn => 'int2_accum_inv', aggmfinalfn => 'numeric_poly_stddev_samp',
aggtranstype => 'internal', aggtransspace => '48',
- aggmtranstype => 'internal', aggmtransspace => '48' },
+ aggmtranstype => 'internal', aggmtransspace => '48',
+ aggpartialfn => 'stddev_p_int2' },
+{ aggfnoid => 'stddev_p_float4', aggtransfn => 'float4_accum',
+ aggcombinefn => 'float8_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0}',
+ aggpartialfn => 'stddev_p_float4' },
{ aggfnoid => 'stddev(float4)', aggtransfn => 'float4_accum',
aggfinalfn => 'float8_stddev_samp', aggcombinefn => 'float8_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0}',
+ aggpartialfn => 'stddev_p_float4' },
+{ aggfnoid => 'stddev_p_float8', aggtransfn => 'float8_accum',
+ aggcombinefn => 'float8_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0}',
+ aggpartialfn => 'stddev_p_float8' },
{ aggfnoid => 'stddev(float8)', aggtransfn => 'float8_accum',
aggfinalfn => 'float8_stddev_samp', aggcombinefn => 'float8_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0}',
+ aggpartialfn => 'stddev_p_float8' },
+{ aggfnoid => 'stddev_p_numeric', aggtransfn => 'numeric_accum',
+ aggfinalfn => 'numeric_serialize', aggcombinefn => 'numeric_combine',
+ aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
+ aggtranstype => 'internal', aggtransspace => '128',
+ aggpartialfn => 'stddev_p_numeric' },
{ aggfnoid => 'stddev(numeric)', aggtransfn => 'numeric_accum',
aggfinalfn => 'numeric_stddev_samp', aggcombinefn => 'numeric_combine',
aggserialfn => 'numeric_serialize', aggdeserialfn => 'numeric_deserialize',
aggmtransfn => 'numeric_accum', aggminvtransfn => 'numeric_accum_inv',
aggmfinalfn => 'numeric_stddev_samp', aggtranstype => 'internal',
aggtransspace => '128', aggmtranstype => 'internal',
- aggmtransspace => '128' },
+ aggmtransspace => '128',
+ aggpartialfn => 'stddev_p_numeric' },
# SQL2003 binary regression aggregates
{ aggfnoid => 'regr_count', aggtransfn => 'int8inc_float8_float8',
- aggcombinefn => 'int8pl', aggtranstype => 'int8', agginitval => '0' },
+ aggcombinefn => 'int8pl', aggtranstype => 'int8', agginitval => '0',
+ aggpartialfn => 'regr_count' },
+{ aggfnoid => 'regr_sxx_p', aggtransfn => 'float8_regr_accum',
+ aggcombinefn => 'float8_regr_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'regr_sxx_p' },
{ aggfnoid => 'regr_sxx', aggtransfn => 'float8_regr_accum',
aggfinalfn => 'float8_regr_sxx', aggcombinefn => 'float8_regr_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'regr_sxx_p' },
+{ aggfnoid => 'regr_syy_p', aggtransfn => 'float8_regr_accum',
+ aggcombinefn => 'float8_regr_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'regr_syy_p' },
{ aggfnoid => 'regr_syy', aggtransfn => 'float8_regr_accum',
aggfinalfn => 'float8_regr_syy', aggcombinefn => 'float8_regr_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'regr_syy_p' },
+{ aggfnoid => 'regr_sxy_p', aggtransfn => 'float8_regr_accum',
+ aggcombinefn => 'float8_regr_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'regr_sxy_p' },
{ aggfnoid => 'regr_sxy', aggtransfn => 'float8_regr_accum',
aggfinalfn => 'float8_regr_sxy', aggcombinefn => 'float8_regr_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'regr_sxy_p' },
+{ aggfnoid => 'regr_avgx_p', aggtransfn => 'float8_regr_accum',
+ aggcombinefn => 'float8_regr_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'regr_avgx_p' },
{ aggfnoid => 'regr_avgx', aggtransfn => 'float8_regr_accum',
aggfinalfn => 'float8_regr_avgx', aggcombinefn => 'float8_regr_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'regr_avgx_p' },
+{ aggfnoid => 'regr_avgy_p', aggtransfn => 'float8_regr_accum',
+ aggcombinefn => 'float8_regr_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'regr_avgy_p' },
{ aggfnoid => 'regr_avgy', aggtransfn => 'float8_regr_accum',
aggfinalfn => 'float8_regr_avgy', aggcombinefn => 'float8_regr_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'regr_avgy_p' },
+{ aggfnoid => 'regr_r2_p', aggtransfn => 'float8_regr_accum',
+ aggcombinefn => 'float8_regr_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'regr_r2_p' },
{ aggfnoid => 'regr_r2', aggtransfn => 'float8_regr_accum',
aggfinalfn => 'float8_regr_r2', aggcombinefn => 'float8_regr_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'regr_r2_p' },
+{ aggfnoid => 'regr_slope_p', aggtransfn => 'float8_regr_accum',
+ aggcombinefn => 'float8_regr_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'regr_slope_p' },
{ aggfnoid => 'regr_slope', aggtransfn => 'float8_regr_accum',
aggfinalfn => 'float8_regr_slope', aggcombinefn => 'float8_regr_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'regr_slope_p' },
+{ aggfnoid => 'regr_intercept_p', aggtransfn => 'float8_regr_accum',
+ aggcombinefn => 'float8_regr_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'regr_intercept_p' },
{ aggfnoid => 'regr_intercept', aggtransfn => 'float8_regr_accum',
aggfinalfn => 'float8_regr_intercept', aggcombinefn => 'float8_regr_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'regr_intercept_p' },
+{ aggfnoid => 'covar_pop_p', aggtransfn => 'float8_regr_accum',
+ aggcombinefn => 'float8_regr_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'covar_pop_p' },
{ aggfnoid => 'covar_pop', aggtransfn => 'float8_regr_accum',
aggfinalfn => 'float8_covar_pop', aggcombinefn => 'float8_regr_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'covar_pop_p' },
+{ aggfnoid => 'covar_samp_p', aggtransfn => 'float8_regr_accum',
+ aggcombinefn => 'float8_regr_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'covar_samp_p' },
{ aggfnoid => 'covar_samp', aggtransfn => 'float8_regr_accum',
aggfinalfn => 'float8_covar_samp', aggcombinefn => 'float8_regr_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'covar_samp_p' },
+{ aggfnoid => 'corr_p', aggtransfn => 'float8_regr_accum',
+ aggcombinefn => 'float8_regr_combine', aggtranstype => '_float8',
+ agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'corr_p' },
{ aggfnoid => 'corr', aggtransfn => 'float8_regr_accum',
aggfinalfn => 'float8_corr', aggcombinefn => 'float8_regr_combine',
- aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}' },
+ aggtranstype => '_float8', agginitval => '{0,0,0,0,0,0}',
+ aggpartialfn => 'corr_p' },
# boolean-and and boolean-or
{ aggfnoid => 'bool_and', aggtransfn => 'booland_statefunc',
aggcombinefn => 'booland_statefunc', aggmtransfn => 'bool_accum',
aggminvtransfn => 'bool_accum_inv', aggmfinalfn => 'bool_alltrue',
aggsortop => '<(bool,bool)', aggtranstype => 'bool',
- aggmtranstype => 'internal', aggmtransspace => '16' },
+ aggmtranstype => 'internal', aggmtransspace => '16',
+ aggpartialfn => 'bool_and' },
{ aggfnoid => 'bool_or', aggtransfn => 'boolor_statefunc',
aggcombinefn => 'boolor_statefunc', aggmtransfn => 'bool_accum',
aggminvtransfn => 'bool_accum_inv', aggmfinalfn => 'bool_anytrue',
aggsortop => '>(bool,bool)', aggtranstype => 'bool',
- aggmtranstype => 'internal', aggmtransspace => '16' },
+ aggmtranstype => 'internal', aggmtransspace => '16',
+ aggpartialfn => 'bool_or' },
{ aggfnoid => 'every', aggtransfn => 'booland_statefunc',
aggcombinefn => 'booland_statefunc', aggmtransfn => 'bool_accum',
aggminvtransfn => 'bool_accum_inv', aggmfinalfn => 'bool_alltrue',
aggsortop => '<(bool,bool)', aggtranstype => 'bool',
- aggmtranstype => 'internal', aggmtransspace => '16' },
+ aggmtranstype => 'internal', aggmtransspace => '16',
+ aggpartialfn => 'every' },
# bitwise integer
{ aggfnoid => 'bit_and(int2)', aggtransfn => 'int2and',
- aggcombinefn => 'int2and', aggtranstype => 'int2' },
+ aggcombinefn => 'int2and', aggtranstype => 'int2',
+ aggpartialfn => 'bit_and(int2)' },
{ aggfnoid => 'bit_or(int2)', aggtransfn => 'int2or', aggcombinefn => 'int2or',
- aggtranstype => 'int2' },
+ aggtranstype => 'int2',
+ aggpartialfn => 'bit_or(int2)' },
{ aggfnoid => 'bit_xor(int2)', aggtransfn => 'int2xor',
- aggcombinefn => 'int2xor', aggtranstype => 'int2' },
+ aggcombinefn => 'int2xor', aggtranstype => 'int2',
+ aggpartialfn => 'bit_xor(int2)' },
{ aggfnoid => 'bit_and(int4)', aggtransfn => 'int4and',
- aggcombinefn => 'int4and', aggtranstype => 'int4' },
+ aggcombinefn => 'int4and', aggtranstype => 'int4',
+ aggpartialfn => 'bit_and(int4)' },
{ aggfnoid => 'bit_or(int4)', aggtransfn => 'int4or', aggcombinefn => 'int4or',
- aggtranstype => 'int4' },
+ aggtranstype => 'int4',
+ aggpartialfn => 'bit_or(int4)' },
{ aggfnoid => 'bit_xor(int4)', aggtransfn => 'int4xor',
- aggcombinefn => 'int4xor', aggtranstype => 'int4' },
+ aggcombinefn => 'int4xor', aggtranstype => 'int4',
+ aggpartialfn => 'bit_xor(int4)' },
{ aggfnoid => 'bit_and(int8)', aggtransfn => 'int8and',
- aggcombinefn => 'int8and', aggtranstype => 'int8' },
+ aggcombinefn => 'int8and', aggtranstype => 'int8',
+ aggpartialfn => 'bit_and(int8)' },
{ aggfnoid => 'bit_or(int8)', aggtransfn => 'int8or', aggcombinefn => 'int8or',
- aggtranstype => 'int8' },
+ aggtranstype => 'int8',
+ aggpartialfn => 'bit_or(int8)' },
{ aggfnoid => 'bit_xor(int8)', aggtransfn => 'int8xor',
- aggcombinefn => 'int8xor', aggtranstype => 'int8' },
+ aggcombinefn => 'int8xor', aggtranstype => 'int8',
+ aggpartialfn => 'bit_xor(int8)' },
{ aggfnoid => 'bit_and(bit)', aggtransfn => 'bitand', aggcombinefn => 'bitand',
- aggtranstype => 'bit' },
+ aggtranstype => 'bit',
+ aggpartialfn => 'bit_and(bit)' },
{ aggfnoid => 'bit_or(bit)', aggtransfn => 'bitor', aggcombinefn => 'bitor',
- aggtranstype => 'bit' },
+ aggtranstype => 'bit',
+ aggpartialfn => 'bit_or(bit)' },
{ aggfnoid => 'bit_xor(bit)', aggtransfn => 'bitxor', aggcombinefn => 'bitxor',
- aggtranstype => 'bit' },
+ aggtranstype => 'bit',
+ aggpartialfn => 'bit_xor(bit)' },
# xml
{ aggfnoid => 'xmlagg', aggtransfn => 'xmlconcat2', aggtranstype => 'xml' },
# array
+{ aggfnoid => 'array_agg_p_anynonarray', aggtransfn => 'array_agg_transfn',
+ aggfinalfn => 'array_agg_serialize', aggcombinefn => 'array_agg_combine',
+ aggserialfn => 'array_agg_serialize', aggdeserialfn => 'array_agg_deserialize',
+ aggtranstype => 'internal',
+ aggpartialfn => 'array_agg_p_anynonarray' },
{ aggfnoid => 'array_agg(anynonarray)', aggtransfn => 'array_agg_transfn',
aggfinalfn => 'array_agg_finalfn', aggcombinefn => 'array_agg_combine',
aggserialfn => 'array_agg_serialize',
aggdeserialfn => 'array_agg_deserialize', aggfinalextra => 't',
- aggtranstype => 'internal' },
+ aggtranstype => 'internal',
+ aggpartialfn => 'array_agg_p_anynonarray' },
+{ aggfnoid => 'array_agg_p_anyarray', aggtransfn => 'array_agg_array_transfn',
+ aggfinalfn => 'array_agg_array_serialize',
+ aggcombinefn => 'array_agg_array_combine',
+ aggserialfn => 'array_agg_array_serialize',
+ aggdeserialfn => 'array_agg_array_deserialize', aggtranstype => 'internal',
+ aggpartialfn => 'array_agg_p_anyarray' },
{ aggfnoid => 'array_agg(anyarray)', aggtransfn => 'array_agg_array_transfn',
aggfinalfn => 'array_agg_array_finalfn',
aggcombinefn => 'array_agg_array_combine',
aggserialfn => 'array_agg_array_serialize',
aggdeserialfn => 'array_agg_array_deserialize', aggfinalextra => 't',
- aggtranstype => 'internal' },
+ aggtranstype => 'internal',
+ aggpartialfn => 'array_agg_p_anyarray' },
# text
+{ aggfnoid => 'string_agg_p_text_text', aggtransfn => 'string_agg_transfn',
+ aggfinalfn => 'string_agg_serialize', aggcombinefn => 'string_agg_combine',
+ aggserialfn => 'string_agg_serialize',
+ aggdeserialfn => 'string_agg_deserialize', aggtranstype => 'internal',
+ aggpartialfn => 'string_agg_p_text_text' },
{ aggfnoid => 'string_agg(text,text)', aggtransfn => 'string_agg_transfn',
aggfinalfn => 'string_agg_finalfn', aggcombinefn => 'string_agg_combine',
aggserialfn => 'string_agg_serialize',
- aggdeserialfn => 'string_agg_deserialize', aggtranstype => 'internal' },
+ aggdeserialfn => 'string_agg_deserialize', aggtranstype => 'internal',
+ aggpartialfn => 'string_agg_p_text_text' },
# bytea
+{ aggfnoid => 'string_agg_p_bytea_bytea',
+ aggtransfn => 'bytea_string_agg_transfn', aggfinalfn => 'string_agg_serialize',
+ aggcombinefn => 'string_agg_combine', aggserialfn => 'string_agg_serialize',
+ aggdeserialfn => 'string_agg_deserialize', aggtranstype => 'internal',
+ aggpartialfn => 'string_agg_p_bytea_bytea' },
{ aggfnoid => 'string_agg(bytea,bytea)',
aggtransfn => 'bytea_string_agg_transfn',
aggfinalfn => 'bytea_string_agg_finalfn',
aggcombinefn => 'string_agg_combine', aggserialfn => 'string_agg_serialize',
- aggdeserialfn => 'string_agg_deserialize', aggtranstype => 'internal' },
+ aggdeserialfn => 'string_agg_deserialize', aggtranstype => 'internal',
+ aggpartialfn => 'string_agg_p_bytea_bytea' },
# range
{ aggfnoid => 'range_intersect_agg(anyrange)',
aggtransfn => 'range_intersect_agg_transfn',
- aggcombinefn => 'range_intersect_agg_transfn', aggtranstype => 'anyrange' },
+ aggcombinefn => 'range_intersect_agg_transfn', aggtranstype => 'anyrange',
+ aggpartialfn => 'range_intersect_agg(anyrange)' },
{ aggfnoid => 'range_intersect_agg(anymultirange)',
aggtransfn => 'multirange_intersect_agg_transfn',
aggcombinefn => 'multirange_intersect_agg_transfn',
- aggtranstype => 'anymultirange' },
+ aggtranstype => 'anymultirange',
+ aggpartialfn => 'range_intersect_agg(anymultirange)' },
{ aggfnoid => 'range_agg(anyrange)', aggtransfn => 'range_agg_transfn',
aggfinalfn => 'range_agg_finalfn', aggfinalextra => 't',
aggtranstype => 'internal' },
@@ -658,6 +1075,7 @@
# any_value
{ aggfnoid => 'any_value(anyelement)', aggtransfn => 'any_value_transfn',
- aggcombinefn => 'any_value_transfn', aggtranstype => 'anyelement' },
+ aggcombinefn => 'any_value_transfn', aggtranstype => 'anyelement',
+ aggpartialfn => 'any_value(anyelement)' },
]
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 085149e258..3e4f8331ee 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -55,6 +55,9 @@ CATALOG(pg_aggregate,2600,AggregateRelationId)
/* function to convert bytea to transtype (0 if none) */
regproc aggdeserialfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
+ /* special aggregate function for partial aggregation (0 if none) */
+ regproc aggpartialfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
+
/* forward function for moving-aggregate mode (0 if none) */
regproc aggmtransfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
@@ -164,6 +167,7 @@ extern ObjectAddress AggregateCreate(const char *aggName,
List *aggmtransfnName,
List *aggminvtransfnName,
List *aggmfinalfnName,
+ List *aggpartialfnName,
bool finalfnExtraArgs,
bool mfinalfnExtraArgs,
char finalfnModify,
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index bc41e92677..7b27e8cebf 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -1658,6 +1658,10 @@
{ oid => '2334', descr => 'aggregate final function',
proname => 'array_agg_finalfn', proisstrict => 'f', prorettype => 'anyarray',
proargtypes => 'internal anynonarray', prosrc => 'array_agg_finalfn' },
+{ oid => '6', descr => 'partial aggregation for array_agg(anynonarray)',
+ proname => 'array_agg_p_anynonarray', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'anynonarray',
+ prosrc => 'aggregate_dummy' },
{ oid => '2335', descr => 'concatenate aggregate input into an array',
proname => 'array_agg', prokind => 'a', proisstrict => 'f',
prorettype => 'anyarray', proargtypes => 'anynonarray',
@@ -1680,6 +1684,9 @@
proname => 'array_agg_array_finalfn', proisstrict => 'f',
prorettype => 'anyarray', proargtypes => 'internal anyarray',
prosrc => 'array_agg_array_finalfn' },
+{ oid => '7', descr => 'partial aggregation for array_agg(anyarray)',
+ proname => 'array_agg_p_anyarray', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'anyarray', prosrc => 'aggregate_dummy' },
{ oid => '4053', descr => 'concatenate aggregate input into an array',
proname => 'array_agg', prokind => 'a', proisstrict => 'f',
prorettype => 'anyarray', proargtypes => 'anyarray',
@@ -5004,6 +5011,10 @@
{ oid => '3536', descr => 'aggregate final function',
proname => 'string_agg_finalfn', proisstrict => 'f', prorettype => 'text',
proargtypes => 'internal', prosrc => 'string_agg_finalfn' },
+{ oid => '8', descr => 'partial aggregation for string_agg(text, text)',
+ proname => 'string_agg_p_text_text', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'text text',
+ prosrc => 'aggregate_dummy' },
{ oid => '3538', descr => 'concatenate aggregate input into a string',
proname => 'string_agg', prokind => 'a', proisstrict => 'f',
prorettype => 'text', proargtypes => 'text text',
@@ -5016,6 +5027,10 @@
proname => 'bytea_string_agg_finalfn', proisstrict => 'f',
prorettype => 'bytea', proargtypes => 'internal',
prosrc => 'bytea_string_agg_finalfn' },
+{ oid => '9', descr => 'partial aggregation for string_agg(bytea, bytea)',
+ proname => 'string_agg_p_bytea_bytea', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'bytea bytea',
+ prosrc => 'aggregate_dummy' },
{ oid => '3545', descr => 'concatenate aggregate input into a bytea',
proname => 'string_agg', prokind => 'a', proisstrict => 'f',
prorettype => 'bytea', proargtypes => 'bytea bytea',
@@ -6597,36 +6612,61 @@
# Aggregates (moved here from pg_aggregate for 7.3)
+{ oid => '111', descr => 'partial aggregation for avg(int8)',
+ proname => 'avg_p_int8', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'int8', prosrc => 'aggregate_dummy' },
{ oid => '2100',
descr => 'the average (arithmetic mean) as numeric of all bigint values',
proname => 'avg', prokind => 'a', proisstrict => 'f', prorettype => 'numeric',
proargtypes => 'int8', prosrc => 'aggregate_dummy' },
+{ oid => '226', descr => 'partial aggregation for avg(int4)',
+ proname => 'avg_p_int4', prokind => 'a', proisstrict => 'f',
+ prorettype => '_int8', proargtypes => 'int4', prosrc => 'aggregate_dummy' },
{ oid => '2101',
descr => 'the average (arithmetic mean) as numeric of all integer values',
proname => 'avg', prokind => 'a', proisstrict => 'f', prorettype => 'numeric',
proargtypes => 'int4', prosrc => 'aggregate_dummy' },
+{ oid => '388', descr => 'partial aggregation for avg(int2)',
+ proname => 'avg_p_int2', prokind => 'a', proisstrict => 'f',
+ prorettype => '_int8', proargtypes => 'int2', prosrc => 'aggregate_dummy' },
{ oid => '2102',
descr => 'the average (arithmetic mean) as numeric of all smallint values',
proname => 'avg', prokind => 'a', proisstrict => 'f', prorettype => 'numeric',
proargtypes => 'int2', prosrc => 'aggregate_dummy' },
+{ oid => '389', descr => 'partial aggregation for avg(numeric)',
+ proname => 'avg_p_numeric', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'numeric', prosrc => 'aggregate_dummy' },
{ oid => '2103',
descr => 'the average (arithmetic mean) as numeric of all numeric values',
proname => 'avg', prokind => 'a', proisstrict => 'f', prorettype => 'numeric',
proargtypes => 'numeric', prosrc => 'aggregate_dummy' },
+{ oid => '560', descr => 'partial aggregation for avg(float4)',
+ proname => 'avg_p_float4', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float4', prosrc => 'aggregate_dummy' },
{ oid => '2104',
descr => 'the average (arithmetic mean) as float8 of all float4 values',
proname => 'avg', prokind => 'a', proisstrict => 'f', prorettype => 'float8',
proargtypes => 'float4', prosrc => 'aggregate_dummy' },
+{ oid => '561', descr => 'partial aggregation for avg(float8)',
+ proname => 'avg_p_float8', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float8', prosrc => 'aggregate_dummy' },
{ oid => '2105',
descr => 'the average (arithmetic mean) as float8 of all float8 values',
proname => 'avg', prokind => 'a', proisstrict => 'f', prorettype => 'float8',
proargtypes => 'float8', prosrc => 'aggregate_dummy' },
+{ oid => '562', descr => 'partial aggregation for avg(interval)',
+ proname => 'avg_p_interval', prokind => 'a', proisstrict => 'f',
+ prorettype => '_interval', proargtypes => 'interval',
+ prosrc => 'aggregate_dummy' },
{ oid => '2106',
descr => 'the average (arithmetic mean) as interval of all interval values',
proname => 'avg', prokind => 'a', proisstrict => 'f',
prorettype => 'interval', proargtypes => 'interval',
prosrc => 'aggregate_dummy' },
+{ oid => '563', descr => 'partial aggregation for sum(int8)',
+ proname => 'sum_p_int8', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'int8', prosrc => 'aggregate_dummy' },
{ oid => '2107', descr => 'sum as numeric across all bigint input values',
proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'numeric',
proargtypes => 'int8', prosrc => 'aggregate_dummy' },
@@ -6649,6 +6689,9 @@
proname => 'sum', prokind => 'a', proisstrict => 'f',
prorettype => 'interval', proargtypes => 'interval',
prosrc => 'aggregate_dummy' },
+{ oid => '564', descr => 'partial aggregation for sum(numeric)',
+ proname => 'sum_p_numeric', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'numeric', prosrc => 'aggregate_dummy' },
{ oid => '2114', descr => 'sum as numeric across all numeric input values',
proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'numeric',
proargtypes => 'numeric', prosrc => 'aggregate_dummy' },
@@ -6807,153 +6850,261 @@
proname => 'int8inc_support', prorettype => 'internal',
proargtypes => 'internal', prosrc => 'int8inc_support' },
+{ oid => '565', descr => 'partial aggregation for var_pop(int8)',
+ proname => 'var_pop_p_int8', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'int8', prosrc => 'aggregate_dummy' },
{ oid => '2718',
descr => 'population variance of bigint input values (square of the population standard deviation)',
proname => 'var_pop', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'int8', prosrc => 'aggregate_dummy' },
+{ oid => '566', descr => 'partial aggregation for var_pop(int4)',
+ proname => 'var_pop_p_int4', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'int4', prosrc => 'aggregate_dummy' },
{ oid => '2719',
descr => 'population variance of integer input values (square of the population standard deviation)',
proname => 'var_pop', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'int4', prosrc => 'aggregate_dummy' },
+{ oid => '567', descr => 'partial aggregation for var_pop(int2)',
+ proname => 'var_pop_p_int2', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'int2', prosrc => 'aggregate_dummy' },
{ oid => '2720',
descr => 'population variance of smallint input values (square of the population standard deviation)',
proname => 'var_pop', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'int2', prosrc => 'aggregate_dummy' },
+{ oid => '568', descr => 'partial aggregation for var_pop(float4)',
+ proname => 'var_pop_p_float4', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float4', prosrc => 'aggregate_dummy' },
{ oid => '2721',
descr => 'population variance of float4 input values (square of the population standard deviation)',
proname => 'var_pop', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float4',
prosrc => 'aggregate_dummy' },
+{ oid => '569', descr => 'partial aggregation for var_pop(float8)',
+ proname => 'var_pop_p_float8', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float8', prosrc => 'aggregate_dummy' },
{ oid => '2722',
descr => 'population variance of float8 input values (square of the population standard deviation)',
proname => 'var_pop', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float8',
prosrc => 'aggregate_dummy' },
+{ oid => '570', descr => 'partial aggregation for var_pop(numeric)',
+ proname => 'var_pop_p_numeric', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'numeric', prosrc => 'aggregate_dummy' },
{ oid => '2723',
descr => 'population variance of numeric input values (square of the population standard deviation)',
proname => 'var_pop', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'numeric',
prosrc => 'aggregate_dummy' },
+{ oid => '571', descr => 'partial aggregation for var_samp(int8)',
+ proname => 'var_samp_p_int8', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'int8', prosrc => 'aggregate_dummy' },
{ oid => '2641',
descr => 'sample variance of bigint input values (square of the sample standard deviation)',
proname => 'var_samp', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'int8', prosrc => 'aggregate_dummy' },
+{ oid => '572', descr => 'partial aggregation for var_samp(int4)',
+ proname => 'var_samp_p_int4', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'int4', prosrc => 'aggregate_dummy' },
{ oid => '2642',
descr => 'sample variance of integer input values (square of the sample standard deviation)',
proname => 'var_samp', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'int4', prosrc => 'aggregate_dummy' },
+{ oid => '573', descr => 'partial aggregation for var_samp(int2)',
+ proname => 'var_samp_p_int2', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'int2', prosrc => 'aggregate_dummy' },
{ oid => '2643',
descr => 'sample variance of smallint input values (square of the sample standard deviation)',
proname => 'var_samp', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'int2', prosrc => 'aggregate_dummy' },
+{ oid => '574', descr => 'partial aggregation for var_samp(float4)',
+ proname => 'var_samp_p_float4', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float4', prosrc => 'aggregate_dummy' },
{ oid => '2644',
descr => 'sample variance of float4 input values (square of the sample standard deviation)',
proname => 'var_samp', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float4',
prosrc => 'aggregate_dummy' },
+{ oid => '575', descr => 'partial aggregation for var_samp(float8)',
+ proname => 'var_samp_p_float8', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float8', prosrc => 'aggregate_dummy' },
{ oid => '2645',
descr => 'sample variance of float8 input values (square of the sample standard deviation)',
proname => 'var_samp', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float8',
prosrc => 'aggregate_dummy' },
+{ oid => '576', descr => 'partial aggregation for var_samp(numeric)',
+ proname => 'var_samp_p_numeric', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'numeric', prosrc => 'aggregate_dummy' },
{ oid => '2646',
descr => 'sample variance of numeric input values (square of the sample standard deviation)',
proname => 'var_samp', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'numeric',
prosrc => 'aggregate_dummy' },
+{ oid => '577', descr => 'partial aggregation for variance(int8)',
+ proname => 'variance_p_int8', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'int8', prosrc => 'aggregate_dummy' },
{ oid => '2148', descr => 'historical alias for var_samp',
proname => 'variance', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'int8', prosrc => 'aggregate_dummy' },
+{ oid => '578', descr => 'partial aggregation for variance(int4)',
+ proname => 'variance_p_int4', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'int4', prosrc => 'aggregate_dummy' },
{ oid => '2149', descr => 'historical alias for var_samp',
proname => 'variance', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'int4', prosrc => 'aggregate_dummy' },
+{ oid => '579', descr => 'partial aggregation for variance(int2)',
+ proname => 'variance_p_int2', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'int2', prosrc => 'aggregate_dummy' },
{ oid => '2150', descr => 'historical alias for var_samp',
proname => 'variance', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'int2', prosrc => 'aggregate_dummy' },
+{ oid => '580', descr => 'partial aggregation for variance(float4)',
+ proname => 'variance_p_float4', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float4', prosrc => 'aggregate_dummy' },
{ oid => '2151', descr => 'historical alias for var_samp',
proname => 'variance', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float4',
prosrc => 'aggregate_dummy' },
+{ oid => '581', descr => 'partial aggregation for variance(float8)',
+ proname => 'variance_p_float8', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float8', prosrc => 'aggregate_dummy' },
{ oid => '2152', descr => 'historical alias for var_samp',
proname => 'variance', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float8',
prosrc => 'aggregate_dummy' },
+{ oid => '582', descr => 'partial aggregation for variance(numeric)',
+ proname => 'variance_p_numeric', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'numeric', prosrc => 'aggregate_dummy' },
{ oid => '2153', descr => 'historical alias for var_samp',
proname => 'variance', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'numeric',
prosrc => 'aggregate_dummy' },
+{ oid => '583', descr => 'partial aggregation for stddev_pop(int8)',
+ proname => 'stddev_pop_p_int8', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'int8', prosrc => 'aggregate_dummy' },
{ oid => '2724',
descr => 'population standard deviation of bigint input values',
proname => 'stddev_pop', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'int8', prosrc => 'aggregate_dummy' },
+{ oid => '703', descr => 'partial aggregation for stddev_pop(int4)',
+ proname => 'stddev_pop_p_int4', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'int4', prosrc => 'aggregate_dummy' },
{ oid => '2725',
descr => 'population standard deviation of integer input values',
proname => 'stddev_pop', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'int4', prosrc => 'aggregate_dummy' },
+{ oid => '726', descr => 'partial aggregation for stddev_pop(int2)',
+ proname => 'stddev_pop_p_int2', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'int2', prosrc => 'aggregate_dummy' },
{ oid => '2726',
descr => 'population standard deviation of smallint input values',
proname => 'stddev_pop', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'int2', prosrc => 'aggregate_dummy' },
+{ oid => '786', descr => 'partial aggregation for stddev_pop(float4)',
+ proname => 'stddev_pop_p_float4', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float4', prosrc => 'aggregate_dummy' },
{ oid => '2727',
descr => 'population standard deviation of float4 input values',
proname => 'stddev_pop', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float4',
prosrc => 'aggregate_dummy' },
+{ oid => '787', descr => 'partial aggregation for stddev_pop(float8)',
+ proname => 'stddev_pop_p_float8', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float8', prosrc => 'aggregate_dummy' },
{ oid => '2728',
descr => 'population standard deviation of float8 input values',
proname => 'stddev_pop', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float8',
prosrc => 'aggregate_dummy' },
+{ oid => '788', descr => 'partial aggregation for stddev_pop(numeric)',
+ proname => 'stddev_pop_p_numeric', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'numeric', prosrc => 'aggregate_dummy' },
{ oid => '2729',
descr => 'population standard deviation of numeric input values',
proname => 'stddev_pop', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'numeric',
prosrc => 'aggregate_dummy' },
+{ oid => '789', descr => 'partial aggregation for stddev_samp(int8)',
+ proname => 'stddev_samp_p_int8', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'int8', prosrc => 'aggregate_dummy' },
{ oid => '2712', descr => 'sample standard deviation of bigint input values',
proname => 'stddev_samp', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'int8', prosrc => 'aggregate_dummy' },
+{ oid => '811', descr => 'partial aggregation for stddev_samp(int4)',
+ proname => 'stddev_samp_p_int4', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'int4', prosrc => 'aggregate_dummy' },
{ oid => '2713', descr => 'sample standard deviation of integer input values',
proname => 'stddev_samp', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'int4', prosrc => 'aggregate_dummy' },
+{ oid => '812', descr => 'partial aggregation for stddev_samp(int2)',
+ proname => 'stddev_samp_p_int2', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'int2', prosrc => 'aggregate_dummy' },
{ oid => '2714',
descr => 'sample standard deviation of smallint input values',
proname => 'stddev_samp', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'int2', prosrc => 'aggregate_dummy' },
+{ oid => '813', descr => 'partial aggregation for stddev_samp(float4)',
+ proname => 'stddev_samp_p_float4', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float4', prosrc => 'aggregate_dummy' },
{ oid => '2715', descr => 'sample standard deviation of float4 input values',
proname => 'stddev_samp', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float4',
prosrc => 'aggregate_dummy' },
+{ oid => '814', descr => 'partial aggregation for stddev_samp(float8)',
+ proname => 'stddev_samp_p_float8', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float8', prosrc => 'aggregate_dummy' },
{ oid => '2716', descr => 'sample standard deviation of float8 input values',
proname => 'stddev_samp', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float8',
prosrc => 'aggregate_dummy' },
+{ oid => '815', descr => 'partial aggregation for stddev_samp(numeric)',
+ proname => 'stddev_samp_p_numeric', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'numeric', prosrc => 'aggregate_dummy' },
{ oid => '2717', descr => 'sample standard deviation of numeric input values',
proname => 'stddev_samp', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'numeric',
prosrc => 'aggregate_dummy' },
+{ oid => '816', descr => 'partial aggregation for stddev(int8)',
+ proname => 'stddev_p_int8', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'int8', prosrc => 'aggregate_dummy' },
{ oid => '2154', descr => 'historical alias for stddev_samp',
proname => 'stddev', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'int8', prosrc => 'aggregate_dummy' },
+{ oid => '970', descr => 'partial aggregation for stddev(int4)',
+ proname => 'stddev_p_int4', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'int4', prosrc => 'aggregate_dummy' },
{ oid => '2155', descr => 'historical alias for stddev_samp',
proname => 'stddev', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'int4', prosrc => 'aggregate_dummy' },
+{ oid => '1382', descr => 'partial aggregation for stddev(int2)',
+ proname => 'stddev_p_int2', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'int2', prosrc => 'aggregate_dummy' },
{ oid => '2156', descr => 'historical alias for stddev_samp',
proname => 'stddev', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'int2', prosrc => 'aggregate_dummy' },
+{ oid => '1524', descr => 'partial aggregation for stddev(float4)',
+ proname => 'stddev_p_float4', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float4', prosrc => 'aggregate_dummy' },
{ oid => '2157', descr => 'historical alias for stddev_samp',
proname => 'stddev', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float4',
prosrc => 'aggregate_dummy' },
+{ oid => '1533', descr => 'partial aggregation for stddev(float8)',
+ proname => 'stddev_p_float8', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float8', prosrc => 'aggregate_dummy' },
{ oid => '2158', descr => 'historical alias for stddev_samp',
proname => 'stddev', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float8',
prosrc => 'aggregate_dummy' },
+{ oid => '1566', descr => 'partial aggregation for stddev(numeric)',
+ proname => 'stddev_p_numeric', prokind => 'a', proisstrict => 'f',
+ prorettype => 'bytea', proargtypes => 'numeric', prosrc => 'aggregate_dummy' },
{ oid => '2159', descr => 'historical alias for stddev_samp',
proname => 'stddev', prokind => 'a', proisstrict => 'f',
prorettype => 'numeric', proargtypes => 'numeric',
@@ -6964,52 +7115,97 @@
proname => 'regr_count', prokind => 'a', proisstrict => 'f',
prorettype => 'int8', proargtypes => 'float8 float8',
prosrc => 'aggregate_dummy' },
+{ oid => '1568', descr => 'partial aggregation for regr_sxx(float8, float8)',
+ proname => 'regr_sxx_p', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float8 float8',
+ prosrc => 'aggregate_dummy' },
{ oid => '2819',
descr => 'sum of squares of the independent variable (sum(X^2) - sum(X)^2/N)',
proname => 'regr_sxx', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float8 float8',
prosrc => 'aggregate_dummy' },
+{ oid => '2173', descr => 'partial aggregation for regr_syy(float8, float8)',
+ proname => 'regr_syy_p', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float8 float8',
+ prosrc => 'aggregate_dummy' },
{ oid => '2820',
descr => 'sum of squares of the dependent variable (sum(Y^2) - sum(Y)^2/N)',
proname => 'regr_syy', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float8 float8',
prosrc => 'aggregate_dummy' },
+{ oid => '3813', descr => 'partial aggregation for regr_sxy(float8, float8)',
+ proname => 'regr_sxy_p', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float8 float8',
+ prosrc => 'aggregate_dummy' },
{ oid => '2821',
descr => 'sum of products of independent times dependent variable (sum(X*Y) - sum(X) * sum(Y)/N)',
proname => 'regr_sxy', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float8 float8',
prosrc => 'aggregate_dummy' },
+{ oid => '3814', descr => 'partial aggregation for regr_avgx(float8, float8)',
+ proname => 'regr_avgx_p', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float8 float8',
+ prosrc => 'aggregate_dummy' },
{ oid => '2822', descr => 'average of the independent variable (sum(X)/N)',
proname => 'regr_avgx', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float8 float8',
prosrc => 'aggregate_dummy' },
+{ oid => '4551', descr => 'partial aggregation for regr_avgy(float8, float8)',
+ proname => 'regr_avgy_p', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float8 float8',
+ prosrc => 'aggregate_dummy' },
{ oid => '2823', descr => 'average of the dependent variable (sum(Y)/N)',
proname => 'regr_avgy', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float8 float8',
prosrc => 'aggregate_dummy' },
+{ oid => '4552', descr => 'partial aggregation for regr_r2(float8, float8)',
+ proname => 'regr_r2_p', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float8 float8',
+ prosrc => 'aggregate_dummy' },
{ oid => '2824', descr => 'square of the correlation coefficient',
proname => 'regr_r2', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float8 float8',
prosrc => 'aggregate_dummy' },
+{ oid => '4553', descr => 'partial aggregation for regr_slope(float8, float8)',
+ proname => 'regr_slope_p', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float8 float8',
+ prosrc => 'aggregate_dummy' },
{ oid => '2825',
descr => 'slope of the least-squares-fit linear equation determined by the (X, Y) pairs',
proname => 'regr_slope', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float8 float8',
prosrc => 'aggregate_dummy' },
+{ oid => '4554',
+ descr => 'partial aggregation for regr_intercept(float8, float8)',
+ proname => 'regr_intercept_p', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float8 float8',
+ prosrc => 'aggregate_dummy' },
{ oid => '2826',
descr => 'y-intercept of the least-squares-fit linear equation determined by the (X, Y) pairs',
proname => 'regr_intercept', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float8 float8',
prosrc => 'aggregate_dummy' },
+{ oid => '4555', descr => 'partial aggregation for covar_pop(float8, float8)',
+ proname => 'covar_pop_p', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float8 float8',
+ prosrc => 'aggregate_dummy' },
{ oid => '2827', descr => 'population covariance',
proname => 'covar_pop', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float8 float8',
prosrc => 'aggregate_dummy' },
+{ oid => '4556', descr => 'partial aggregation for covar_samp(float8, float8)',
+ proname => 'covar_samp_p', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float8 float8',
+ prosrc => 'aggregate_dummy' },
{ oid => '2828', descr => 'sample covariance',
proname => 'covar_samp', prokind => 'a', proisstrict => 'f',
prorettype => 'float8', proargtypes => 'float8 float8',
prosrc => 'aggregate_dummy' },
+{ oid => '4557', descr => 'partial aggregation for corr(float8, float8)',
+ proname => 'corr_p', prokind => 'a', proisstrict => 'f',
+ prorettype => '_float8', proargtypes => 'float8 float8',
+ prosrc => 'aggregate_dummy' },
{ oid => '2829', descr => 'correlation coefficient',
proname => 'corr', prokind => 'a', proisstrict => 'f', prorettype => 'float8',
proargtypes => 'float8 float8', prosrc => 'aggregate_dummy' },
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index ed85dc7414..411a249482 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -3243,6 +3243,9 @@ typedef enum
* havingQual gives list of quals to be applied after aggregation.
* targetList gives list of columns to be projected.
* patype is the type of partitionwise aggregation that is being performed.
+ * groupClausePartial is List of SortGroupClauses for partial aggregate
+ * pushdown by FDW
+ * partial_target is PathTarget for partial aggregate pushdown by FDW
*/
typedef struct
{
@@ -3257,6 +3260,8 @@ typedef struct
Node *havingQual;
List *targetList;
PartitionwiseAggregateType patype;
+ List *groupClausePartial;
+ PathTarget *partial_target;
} GroupPathExtraData;
/*
diff --git a/src/test/regress/expected/create_aggregate.out b/src/test/regress/expected/create_aggregate.out
index dcf6909423..73e4cfde0f 100644
--- a/src/test/regress/expected/create_aggregate.out
+++ b/src/test/regress/expected/create_aggregate.out
@@ -322,3 +322,187 @@ WARNING: aggregate attribute "Finalfunc_extra" not recognized
WARNING: aggregate attribute "Finalfunc_modify" not recognized
WARNING: aggregate attribute "Parallel" not recognized
ERROR: aggregate stype must be specified
+-- invalid: finalfunc is specified and stype is not internal
+-- even though aggpartialfunc is equal to the aggregate name
+CREATE AGGREGATE udf_avg_int4_invalid(int4) (
+ sfunc = int4_avg_accum,
+ stype = _int8,
+ finalfunc = int8_avg,
+ combinefunc = int4_avg_combine,
+ initcond = '{0,0}',
+ aggpartialfunc = udf_avg_int4_invalid
+);
+ERROR: udf_avg_int4_invalid is not its own aggpartialfunc
+-- invalid: finalfunc is not equal to serialfunc and stype is internal
+-- even though aggpartialfunc is equal to the aggregate name
+CREATE AGGREGATE udf_avg_int8_invalid(int8) (
+ sfunc = int8_avg_accum,
+ stype = internal,
+ finalfunc = numeric_poly_avg,
+ combinefunc = int8_avg_combine,
+ serialfunc = int8_avg_serialize,
+ deserialfunc = int8_avg_deserialize,
+ aggpartialfunc = udf_avg_int8_invalid
+);
+ERROR: udf_avg_int8_invalid is not its own aggpartialfunc
+-- invalid: aggpartialfunc which doesn't exist
+CREATE AGGREGATE nonexistent_aggpartial_agg(int8) (
+ sfunc = int8_avg_accum,
+ stype = internal,
+ finalfunc = numeric_poly_sum,
+ combinefunc = int8_avg_combine,
+ serialfunc = int8_avg_serialize,
+ deserialfunc = int8_avg_deserialize,
+ aggpartialfunc = aggpartial_foo
+);
+ERROR: function aggpartial_foo(bigint) does not exist
+-- invalid: aggpartialfunc is specified and combinefunc isn't specified
+CREATE AGGREGATE nocombinefunc_agg(int8) (
+ sfunc = int8_avg_accum,
+ stype = internal,
+ finalfunc = numeric_poly_avg,
+ serialfunc = int8_avg_serialize,
+ deserialfunc = int8_avg_deserialize,
+ aggpartialfunc = avg_p_int8
+);
+ERROR: aggcombinefnName must be supplied if aggpartialfnName is supplied
+-- invalid: combinefunc in agg and combinefunc in aggpartialfunc don't match
+CREATE AGGREGATE udf_avg_invalid_combinefunc(int8) (
+ sfunc = int8_avg_accum,
+ stype = internal,
+ finalfunc = numeric_poly_avg,
+ combinefunc = numeric_avg_combine,
+ serialfunc = int8_avg_serialize,
+ deserialfunc = int8_avg_deserialize,
+ aggpartialfunc = avg_p_int8
+);
+ERROR: combinefunc in aggregate and combinefunc in its aggpartialfunc must match
+CREATE FUNCTION udf_float8_accum(_float8, float8) RETURNS _float8 AS
+$$ SELECT float8_accum($1, $2) $$
+LANGUAGE SQL;
+-- invalid: sfunc in agg and sfunc in aggpartialfunc don't match
+CREATE AGGREGATE udf_avg_invalid_sfunc(float8) (
+ sfunc = udf_float8_accum,
+ stype = _float8,
+ finalfunc = float8_avg,
+ combinefunc = float8_combine,
+ initcond = '{0,0,0}',
+ aggpartialfunc = avg_p_float8
+);
+ERROR: sfunc in aggregate and its aggpartialfunc must match
+DROP FUNCTION udf_float8_accum(_float8, float8);
+-- invalid: initcond in agg and initcond in aggpartialfunc don't match
+CREATE AGGREGATE udf_avg_invalid_initcond(int4) (
+ sfunc = int4_avg_accum,
+ stype = _int8,
+ initcond = '{1,0}',
+ finalfunc = int8_avg,
+ combinefunc = int4_avg_combine,
+ aggpartialfunc = avg_p_int4
+);
+ERROR: initcond in aggregate and initcond in its aggpartialfunc must match
+-- invalid: aggserialfn in agg and aggserialfn in aggpartialfunc don't match
+CREATE AGGREGATE udf_avg_invalid_aggserialfn(int8) (
+ sfunc = int8_avg_accum,
+ stype = internal,
+ finalfunc = numeric_poly_avg,
+ combinefunc = int8_avg_combine,
+ serialfunc = numeric_avg_serialize,
+ deserialfunc = int8_avg_deserialize,
+ aggpartialfunc = avg_p_int8
+);
+ERROR: serialfunc in aggregate and serialfunc in its aggpartialfunc must match
+-- invalid: aggdeserialfn in agg and aggdeserialfn in aggpartialfunc don't match
+CREATE AGGREGATE udf_avg_invalid_aggdeserialfn(int8) (
+ sfunc = int8_avg_accum,
+ stype = internal,
+ finalfunc = numeric_poly_avg,
+ combinefunc = int8_avg_combine,
+ serialfunc = int8_avg_serialize,
+ deserialfunc = numeric_avg_deserialize,
+ aggpartialfunc = avg_p_int8
+);
+ERROR: deserialfunc in aggregate and deserialfunc in its aggpartialfunc must match
+-- invalid: stype is internal and aggpartialfunc's finalfunc
+-- isn't serialfunc of agg
+CREATE AGGREGATE udf_avg_p_int8(int8) (
+ sfunc = int8_avg_accum,
+ stype = internal,
+ finalfunc = numeric_avg_serialize,
+ combinefunc = int8_avg_combine,
+ serialfunc = int8_avg_serialize,
+ deserialfunc = int8_avg_deserialize
+);
+CREATE AGGREGATE udf_avg(int8) (
+ sfunc = int8_avg_accum,
+ stype = internal,
+ finalfunc = numeric_poly_avg,
+ combinefunc = int8_avg_combine,
+ serialfunc = int8_avg_serialize,
+ deserialfunc = int8_avg_deserialize,
+ aggpartialfunc = udf_avg_p_int8
+);
+ERROR: finalfunc of aggpartialfunc must match serialfunc of aggregate when stype is internal
+-- invalid: stype is not internal and aggpartialfunc has finalfunc
+CREATE AGGREGATE udf_avg_p_int4_hasfinal(int4) (
+ sfunc = int4_avg_accum,
+ stype = _int8,
+ finalfunc = int8_avg,
+ combinefunc = int4_avg_combine,
+ initcond = '{0,0}'
+);
+CREATE AGGREGATE udf_avg(int4) (
+ sfunc = int4_avg_accum,
+ stype = _int8,
+ finalfunc = int8_avg,
+ combinefunc = int4_avg_combine,
+ initcond = '{0,0}',
+ aggpartialfunc = udf_avg_p_int4_hasfinal
+);
+ERROR: finalfunc of aggpartialfunc must not be supplied when stype isn't internal
+-- invalid: current user doesn't have execute privilege on aggpartialfunc
+CREATE AGGREGATE udf_avg_p_int4(int4) (
+ sfunc = int4_avg_accum,
+ stype = _int8,
+ combinefunc = int4_avg_combine,
+ initcond = '{0,0}'
+);
+CREATE USER regress_priv_user1;
+GRANT ALL ON SCHEMA public TO regress_priv_user1;
+REVOKE EXECUTE ON FUNCTION udf_avg_p_int4 FROM public;
+SET SESSION AUTHORIZATION regress_priv_user1;
+CREATE AGGREGATE udf_avg_noprivilege(int4) (
+ sfunc = int4_avg_accum,
+ stype = _int8,
+ finalfunc = int8_avg,
+ combinefunc = int4_avg_combine,
+ initcond = '{0,0}',
+ aggpartialfunc = udf_avg_p_int4
+);
+ERROR: permission denied for function udf_avg_p_int4
+SET SESSION AUTHORIZATION DEFAULT;
+REVOKE ALL ON SCHEMA public FROM regress_priv_user1;
+DROP USER regress_priv_user1;
+-- An aggregate function that is aggpartialfunc
+-- of another aggregate cannot be deleted.
+CREATE AGGREGATE udf_avg_int4_p(int4) (
+ sfunc = int4_avg_accum,
+ stype = _int8,
+ combinefunc = int4_avg_combine,
+ initcond = '{0,0}',
+ aggpartialfunc = udf_avg_int4_p
+);
+CREATE AGGREGATE udf_avg_int4(int4) (
+ sfunc = int4_avg_accum,
+ stype = _int8,
+ finalfunc = int8_avg,
+ combinefunc = int4_avg_combine,
+ initcond = '{0,0}',
+ aggpartialfunc = udf_avg_int4_p
+);
+DROP AGGREGATE udf_avg_int4_p(int4);
+ERROR: cannot drop function udf_avg_int4_p(integer) because other objects depend on it
+DETAIL: function udf_avg_int4(integer) depends on function udf_avg_int4_p(integer)
+HINT: Use DROP ... CASCADE to drop the dependent objects too.
+DROP AGGREGATE udf_avg_int4_p(int4) CASCADE;
+NOTICE: drop cascades to function udf_avg_int4(integer)
diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out
index 215eb899be..6c80efa7eb 100644
--- a/src/test/regress/expected/oidjoins.out
+++ b/src/test/regress/expected/oidjoins.out
@@ -145,6 +145,7 @@ NOTICE: checking pg_aggregate {aggfinalfn} => pg_proc {oid}
NOTICE: checking pg_aggregate {aggcombinefn} => pg_proc {oid}
NOTICE: checking pg_aggregate {aggserialfn} => pg_proc {oid}
NOTICE: checking pg_aggregate {aggdeserialfn} => pg_proc {oid}
+NOTICE: checking pg_aggregate {aggpartialfn} => pg_proc {oid}
NOTICE: checking pg_aggregate {aggmtransfn} => pg_proc {oid}
NOTICE: checking pg_aggregate {aggminvtransfn} => pg_proc {oid}
NOTICE: checking pg_aggregate {aggmfinalfn} => pg_proc {oid}
diff --git a/src/test/regress/sql/create_aggregate.sql b/src/test/regress/sql/create_aggregate.sql
index d4b4036fd7..e90e0ad2d6 100644
--- a/src/test/regress/sql/create_aggregate.sql
+++ b/src/test/regress/sql/create_aggregate.sql
@@ -328,3 +328,186 @@ CREATE AGGREGATE case_agg(float8)
"Finalfunc_modify" = read_write,
"Parallel" = safe
);
+
+-- invalid: finalfunc is specified and stype is not internal
+-- even though aggpartialfunc is equal to the aggregate name
+CREATE AGGREGATE udf_avg_int4_invalid(int4) (
+ sfunc = int4_avg_accum,
+ stype = _int8,
+ finalfunc = int8_avg,
+ combinefunc = int4_avg_combine,
+ initcond = '{0,0}',
+ aggpartialfunc = udf_avg_int4_invalid
+);
+
+-- invalid: finalfunc is not equal to serialfunc and stype is internal
+-- even though aggpartialfunc is equal to the aggregate name
+CREATE AGGREGATE udf_avg_int8_invalid(int8) (
+ sfunc = int8_avg_accum,
+ stype = internal,
+ finalfunc = numeric_poly_avg,
+ combinefunc = int8_avg_combine,
+ serialfunc = int8_avg_serialize,
+ deserialfunc = int8_avg_deserialize,
+ aggpartialfunc = udf_avg_int8_invalid
+);
+
+-- invalid: aggpartialfunc which doesn't exist
+CREATE AGGREGATE nonexistent_aggpartial_agg(int8) (
+ sfunc = int8_avg_accum,
+ stype = internal,
+ finalfunc = numeric_poly_sum,
+ combinefunc = int8_avg_combine,
+ serialfunc = int8_avg_serialize,
+ deserialfunc = int8_avg_deserialize,
+ aggpartialfunc = aggpartial_foo
+);
+
+-- invalid: aggpartialfunc is specified and combinefunc isn't specified
+CREATE AGGREGATE nocombinefunc_agg(int8) (
+ sfunc = int8_avg_accum,
+ stype = internal,
+ finalfunc = numeric_poly_avg,
+ serialfunc = int8_avg_serialize,
+ deserialfunc = int8_avg_deserialize,
+ aggpartialfunc = avg_p_int8
+);
+
+-- invalid: combinefunc in agg and combinefunc in aggpartialfunc don't match
+CREATE AGGREGATE udf_avg_invalid_combinefunc(int8) (
+ sfunc = int8_avg_accum,
+ stype = internal,
+ finalfunc = numeric_poly_avg,
+ combinefunc = numeric_avg_combine,
+ serialfunc = int8_avg_serialize,
+ deserialfunc = int8_avg_deserialize,
+ aggpartialfunc = avg_p_int8
+);
+
+CREATE FUNCTION udf_float8_accum(_float8, float8) RETURNS _float8 AS
+$$ SELECT float8_accum($1, $2) $$
+LANGUAGE SQL;
+
+-- invalid: sfunc in agg and sfunc in aggpartialfunc don't match
+CREATE AGGREGATE udf_avg_invalid_sfunc(float8) (
+ sfunc = udf_float8_accum,
+ stype = _float8,
+ finalfunc = float8_avg,
+ combinefunc = float8_combine,
+ initcond = '{0,0,0}',
+ aggpartialfunc = avg_p_float8
+);
+DROP FUNCTION udf_float8_accum(_float8, float8);
+
+-- invalid: initcond in agg and initcond in aggpartialfunc don't match
+CREATE AGGREGATE udf_avg_invalid_initcond(int4) (
+ sfunc = int4_avg_accum,
+ stype = _int8,
+ initcond = '{1,0}',
+ finalfunc = int8_avg,
+ combinefunc = int4_avg_combine,
+ aggpartialfunc = avg_p_int4
+);
+
+-- invalid: aggserialfn in agg and aggserialfn in aggpartialfunc don't match
+CREATE AGGREGATE udf_avg_invalid_aggserialfn(int8) (
+ sfunc = int8_avg_accum,
+ stype = internal,
+ finalfunc = numeric_poly_avg,
+ combinefunc = int8_avg_combine,
+ serialfunc = numeric_avg_serialize,
+ deserialfunc = int8_avg_deserialize,
+ aggpartialfunc = avg_p_int8
+);
+
+-- invalid: aggdeserialfn in agg and aggdeserialfn in aggpartialfunc don't match
+CREATE AGGREGATE udf_avg_invalid_aggdeserialfn(int8) (
+ sfunc = int8_avg_accum,
+ stype = internal,
+ finalfunc = numeric_poly_avg,
+ combinefunc = int8_avg_combine,
+ serialfunc = int8_avg_serialize,
+ deserialfunc = numeric_avg_deserialize,
+ aggpartialfunc = avg_p_int8
+);
+
+-- invalid: stype is internal and aggpartialfunc's finalfunc
+-- isn't serialfunc of agg
+CREATE AGGREGATE udf_avg_p_int8(int8) (
+ sfunc = int8_avg_accum,
+ stype = internal,
+ finalfunc = numeric_avg_serialize,
+ combinefunc = int8_avg_combine,
+ serialfunc = int8_avg_serialize,
+ deserialfunc = int8_avg_deserialize
+);
+CREATE AGGREGATE udf_avg(int8) (
+ sfunc = int8_avg_accum,
+ stype = internal,
+ finalfunc = numeric_poly_avg,
+ combinefunc = int8_avg_combine,
+ serialfunc = int8_avg_serialize,
+ deserialfunc = int8_avg_deserialize,
+ aggpartialfunc = udf_avg_p_int8
+);
+
+-- invalid: stype is not internal and aggpartialfunc has finalfunc
+CREATE AGGREGATE udf_avg_p_int4_hasfinal(int4) (
+ sfunc = int4_avg_accum,
+ stype = _int8,
+ finalfunc = int8_avg,
+ combinefunc = int4_avg_combine,
+ initcond = '{0,0}'
+);
+CREATE AGGREGATE udf_avg(int4) (
+ sfunc = int4_avg_accum,
+ stype = _int8,
+ finalfunc = int8_avg,
+ combinefunc = int4_avg_combine,
+ initcond = '{0,0}',
+ aggpartialfunc = udf_avg_p_int4_hasfinal
+);
+
+-- invalid: current user doesn't have execute privilege on aggpartialfunc
+CREATE AGGREGATE udf_avg_p_int4(int4) (
+ sfunc = int4_avg_accum,
+ stype = _int8,
+ combinefunc = int4_avg_combine,
+ initcond = '{0,0}'
+);
+CREATE USER regress_priv_user1;
+GRANT ALL ON SCHEMA public TO regress_priv_user1;
+REVOKE EXECUTE ON FUNCTION udf_avg_p_int4 FROM public;
+SET SESSION AUTHORIZATION regress_priv_user1;
+
+CREATE AGGREGATE udf_avg_noprivilege(int4) (
+ sfunc = int4_avg_accum,
+ stype = _int8,
+ finalfunc = int8_avg,
+ combinefunc = int4_avg_combine,
+ initcond = '{0,0}',
+ aggpartialfunc = udf_avg_p_int4
+);
+SET SESSION AUTHORIZATION DEFAULT;
+REVOKE ALL ON SCHEMA public FROM regress_priv_user1;
+DROP USER regress_priv_user1;
+
+-- An aggregate function that is aggpartialfunc
+-- of another aggregate cannot be deleted.
+CREATE AGGREGATE udf_avg_int4_p(int4) (
+ sfunc = int4_avg_accum,
+ stype = _int8,
+ combinefunc = int4_avg_combine,
+ initcond = '{0,0}',
+ aggpartialfunc = udf_avg_int4_p
+);
+CREATE AGGREGATE udf_avg_int4(int4) (
+ sfunc = int4_avg_accum,
+ stype = _int8,
+ finalfunc = int8_avg,
+ combinefunc = int4_avg_combine,
+ initcond = '{0,0}',
+ aggpartialfunc = udf_avg_int4_p
+);
+DROP AGGREGATE udf_avg_int4_p(int4);
+DROP AGGREGATE udf_avg_int4_p(int4) CASCADE;
--
2.39.3
view thread (38+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]
Subject: RE: Partial aggregates pushdown
In-Reply-To: <TYTPR01MB10954B96601911FE868BF88E895DCA@TYTPR01MB10954.jpnprd01.prod.outlook.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox