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: Thu, 26 Oct 2023 11:11:09 +0000
Message-ID: <TYTPR01MB10954D890D8F729E1BCE42D4F95DDA@TYTPR01MB10954.jpnprd01.prod.outlook.com> (raw)
In-Reply-To: <[email protected]>
References: <OS3PR01MB6660CF2F3643AE7B7C8F797495C3A@OS3PR01MB6660.jpnprd01.prod.outlook.com>
<[email protected]>
<OS3PR01MB66608567A5DE381D99BEE1A395C3A@OS3PR01MB6660.jpnprd01.prod.outlook.com>
<[email protected]>
<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]>
Hi Mr.Momjian
> From: Bruce Momjian <[email protected]>
> Sent: Thursday, October 26, 2023 7:08 AM
> I am almost done updating the patch, but I got stuck on how the feature is supposed to work. This documentation
> sentence is where I got
> confused:
>
> <varlistentry>
> <term><literal>check_partial_aggregate_support</literal> (<type>boolean</type>)</term>
> <listitem>
> <para>
> If this option is false, <filename>postgres_fdw</filename> assumes
> that for each built-in aggregate function,
> the partial aggregate function is defined on the remote server
> without checking the remote server version.
> If this option is true, during query planning,
> <filename>postgres_fdw</filename> connects to the remote server
> and checks if the remote server version is older than the local server version.
> If so,
> <filename>postgres_fdw</filename>
> --> assumes that for each built-in aggregate function, the partial aggregate function is not defined
> --> on the remote server unless the partial aggregate function and the aggregate
> --> function match.
> Otherwise <filename>postgres_fdw</filename> assumes that for each built-in aggregate function,
> the partial aggregate function is defined on the remote server.
> The default is <literal>false</literal>.
> </para>
> </listitem>
> </varlistentry>
>
> What does that marked sentence mean? What is match? Are one or both of these remote? It sounds like you are
> checking the local aggregate against the remote partial aggregate, but I don't see any code that does this in the patch.
This sentence means that
"If the partial aggregate function has the same OID as the aggregate function,
then postgres_fdw assumes that for each built-in aggregate function, the partial aggregate function is not defined
on the remote server."
"Match" means that the partial aggregate function has the same OID as the aggregate function in local server.
But, in v30, there is no code which checks the partial aggregate function has the same OID as the aggregate function in local server.
So I modified the code of is_builtin_aggpartialfunc_shippable().
Also, I modified wording postgres-fdw.sgml.
Sincerely yours,
Yuuki Fujii
--
Yuuki Fujii
Information Technology R&D Center Mitsubishi Electric Corporation
Attachments:
[application/octet-stream] 0001-Partial-aggregates-push-down-v31.patch (267.1K, ../TYTPR01MB10954D890D8F729E1BCE42D4F95DDA@TYTPR01MB10954.jpnprd01.prod.outlook.com/2-0001-Partial-aggregates-push-down-v31.patch)
download | inline diff:
From 9c06e338a2142f5371f3292789deb5e88ea2fcd0 Mon Sep 17 00:00:00 2001
From: Yuki Fujii <[email protected]>
Date: Thu, 26 Oct 2023 13:32:16 -0400
Subject: [PATCH] Partial aggregates push down v31
---
contrib/postgres_fdw/deparse.c | 104 ++-
.../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 | 13 +
doc/src/sgml/postgres-fdw.sgml | 139 ++-
doc/src/sgml/ref/create_aggregate.sgml | 42 +
doc/src/sgml/xaggr.sgml | 15 +-
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, 2838 insertions(+), 222 deletions(-)
diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c
index 09d6dd60dd..fbeed33da2 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,69 @@ get_relation_column_alias_ids(Var *node, RelOptInfo *foreignrel,
/* Shouldn't get here */
elog(ERROR, "unexpected expression in subquery output");
}
+
+/*
+ * Check that a buit-in aggpartialfunc exists on the remote server. If
+ * check_partial_aggregate_support is false or the aggpartialfunc has
+ * the same OID as the aggregate function, we assume the partial aggregate
+ * function exsits on the remote server. Otherwise we assume the partial
+ * aggregate function exsits on the remote server only if the remote server
+ * version is not less than the local server version.
+ */
+static bool
+is_builtin_aggpartialfunc_shippable(Form_pg_aggregate aggform, PgFdwRelationInfo *fpinfo)
+{
+ bool shippable = true;
+
+ 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.
+ * condition1) agg is AGGKIND_NORMAL aggregate which contains no distinct or
+ * order by clauses condition2) there is an aggregate function for partial
+ * aggregation (call it aggpartialfunc) corresponding to agg and
+ * aggpartialfunc exists 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..986af1634a 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's unsafe to push down partial aggregates which contain distinct clause
+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's unsafe to push down partial aggregates which contain order by clause
+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 aggregate for user-defined aggregate
+-- when it belongs to an extension that's listed in extensions set
+-- and when its aggpartialfunc belongs to an extension that's listed
+-- in extensions set.
+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's unsafe to push down partial aggregate for user-defined aggregate
+-- when it has 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's unsafe to push down partial aggregate for user-defined aggregate
+-- when itself is aggpartialfunc and when it belongs to an extension
+-- that's listed in extensions set 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's unsafe to push down partial aggregate for user-defined aggregate
+-- when it doesn't belong to an extension that's listed in extensions set
+-- and when its aggpartialfunc belongs to an extension that's listed
+-- in extensions set.
+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 aggregate for user-defined aggregate
+-- whose stype is not internal
+-- when it belongs to an extension that's listed in extensions set
+-- and when its aggpartialfunc belongs to an extension that's listed
+-- in extensions set.
+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 aggregate for user-defined aggregate
+-- when itself is aggpartialfunc and when it belongs to an extension
+-- that's listed in extensions set 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 1393716587..8a905ad8c4 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's 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 02c1152319..c60f3f5465 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, then that means the remote server version is
+ * unacquired.
+ */
+ 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..1aabeac274 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's unsafe to push down partial aggregates which contain distinct clause
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT max(a), count(distinct b) FROM pagg_tab;
+SELECT max(a), count(distinct b) FROM pagg_tab;
+
+-- It's unsafe to push down partial aggregates which contain order by clause
+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 aggregate for user-defined aggregate
+-- when it belongs to an extension that's listed in extensions set
+-- and when its aggpartialfunc belongs to an extension that's listed
+-- in extensions set.
+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's unsafe to push down partial aggregate for user-defined aggregate
+-- when it has 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's unsafe to push down partial aggregate for user-defined aggregate
+-- when itself is aggpartialfunc and when it belongs to an extension
+-- that's listed in extensions set 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's unsafe to push down partial aggregate for user-defined aggregate
+-- when it doesn't belong to an extension that's listed in extensions set
+-- and when its aggpartialfunc belongs to an extension that's listed
+-- in extensions set.
+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 aggregate for user-defined aggregate
+-- whose stype is not internal
+-- when it belongs to an extension that's listed in extensions set
+-- and when its aggpartialfunc belongs to an extension that's listed
+-- in extensions set.
+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 aggregate for user-defined aggregate
+-- when itself is aggpartialfunc and when it belongs to an extension
+-- that's listed in extensions set 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..c5d826c585 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -644,6 +644,19 @@
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..d9b3238d8b 100644
--- a/doc/src/sgml/postgres-fdw.sgml
+++ b/doc/src/sgml/postgres-fdw.sgml
@@ -451,6 +451,44 @@ 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 for each built-in aggregate
+ function, the partial aggregate function is defined on the remote server. See
+ <xref linkend="partial-aggregate-pushdown"/> for the definition of the partial aggregate
+ function. This may be overridden using the following option:
+ </para>
+
+ <variablelist>
+
+ <varlistentry>
+ <term><literal>check_partial_aggregate_support</literal> (<type>boolean</type>)</term>
+ <listitem>
+ <para>
+ For each built-in aggregate function,
+ if this option is false or the partial aggregate function
+ has the same OID as the aggregate function,
+ <filename>postgres_fdw</filename> assumes that
+ the partial aggregate function is defined on the remote server
+ without checking the remote server version.
+ If this option is true, during query planning,
+ <filename>postgres_fdw</filename> connects to the remote server
+ and checks if the remote server version is older than the local server version.
+ If so,
+ <filename>postgres_fdw</filename>
+ assumes that the partial aggregate function is not defined on the remote server.
+ Otherwise <filename>postgres_fdw</filename> assumes that
+ the partial aggregate function is defined on the remote server.
+ The default is <literal>false</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </sect3>
+
<sect3 id="postgres-fdw-options-asynchronous-execution">
<title>Asynchronous Execution Options</title>
@@ -929,13 +967,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
+ 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 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.
For an <command>UPDATE</command> or <command>DELETE</command> query,
<filename>postgres_fdw</filename> attempts to optimize the query execution by
@@ -966,6 +1006,70 @@ 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 a query that contains aggregate
+ expressions for a partitioned table across one or more remote servers. If the multiple
+ conditions are true for a remote server, an aggregate expression is sent to that
+ remote server and the aggregate is a partial aggregate on the local server.
+ The conditions under which this sending is active are as follows.
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ An aggregate function, called the partial aggregate function for partial aggregate
+ that corresponding to the aggregate expression, is defined on the local server and
+ 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 don't contain
+ a <literal>DISTINCT</literal> or <literal>ORDER BY</literal> clause.
+ </para>
+ </listitem>
+ </itemizedlist>
+ When this sending is active for aggregate expressions, any aggregate
+ function is replaced by the partial aggregate function in the remote query.
+ If the data type of the state value is not internal, the partial aggregate
+ function has no final function.
+ Otherwise, the partial aggregate function must have the same final function
+ as the aggregate function's serialization function.
+ 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 with the corresponding members in the
+ aggregate function.
+ For all built-in aggregate functions that support partial aggregation, the partial
+ aggregate function that corresponds to this function is defined as a built-in
+ aggregate function.
+ By default, <filename>postgres_fdw</filename> assumes that for each built-in
+ aggregate function, the partial aggregate function is defined on the local server
+ and the remote server.
+ If the partial aggregate function does not have the same OID as the aggregate function
+ and <literal>check_partial_aggregate_support</literal> is true,
+ <filename>postgres_fdw</filename> checks if the remote server version is
+ older than the local server version.
+ If so, <filename>postgres_fdw</filename> does not assume
+ that the partial aggregate function is on the remote server.
+ <filename>postgres_fdw</filename> assumes that a user-defined aggregate
+ function has its partial aggregate function on the remote server
+ only if both belong to an extension that is 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,14 +1135,27 @@ 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>.
+ A similar problem occurs when using the partial aggregate pushdown feature.
+ When using the partial aggregate pushdown feature,
+ the partial aggregate function of the aggregate function is sent to
+ the remote server if the conditions in
+ <xref linkend="partial-aggregate-pushdown"/> are met.
+ A limitation is that by default, <filename>postgres_fdw</filename> assumes that
+ for each built-in aggregate function, the partial aggregate function is defined
+ on the remote server.
+ This limitation might cause <quote>function does not exist</quote>
+ or a similar error if the remote server version is older than the local server version.
+ This problem can be worked around by setting
+ <literal>check_partial_aggregate_support</literal> to <literal>true</literal>
+ or similar query rewriting as above.
</para>
</sect2>
diff --git a/doc/src/sgml/ref/create_aggregate.sgml b/doc/src/sgml/ref/create_aggregate.sgml
index 222e0aa5c9..2875734dea 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,18 @@ CREATE [ OR REPLACE ] AGGREGATE <replaceable class="parameter">name</replaceable
marked <literal>PARALLEL SAFE</literal> to enable parallel aggregation.
</para>
+ <para>
+ <filename>postgres_fdw</filename> can optimize a query containing aggregate
+ expressions for a partitioned table across one or more remote servers.
+ This optimization sends an aggregate expression to a remote server and the
+ aggregate is a partial aggregate on the local server. This optimization
+ requires an aggregate function called a <firstterm>partial aggregate
+ function</firstterm>. See
+ <xref linkend="partial-aggregate-pushdown"/> for the definition of
+ partial aggregate function. <literal>AGGPARTIALFUNC</literal> is a parameter
+ of the partial aggregate function.
+ </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 +667,34 @@ SELECT col FROM tab ORDER BY col USING sortop LIMIT 1;
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">aggpartialfunc</replaceable></term>
+ <listitem>
+ <para>
+ The name of the partial aggregate function.
+ If the <replaceable class="parameter">name</replaceable> and the
+ <replaceable class="parameter">aggpartialfunc</replaceable> are the same,
+ then the aggregate function must be the partial aggregate function.
+ If the <replaceable class="parameter">aggpartialfunc</replaceable>
+ is specified, the <replaceable class="parameter">combinefunc</replaceable>
+ must be specified.
+ If the <replaceable class="parameter">state_data_type</replaceable> is not
+ <type>internal</type>, then the partial aggregate function must not have
+ the <replaceable class="parameter">ffunc</replaceable>.
+ If the <replaceable class="parameter">state_data_type</replaceable> is
+ <type>internal</type>, the partial aggregate function must have the same
+ final function as the <replaceable class="parameter">serialfunc</replaceable>.
+ The partial aggregate function and the aggregate function 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..607c859974 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,18 @@ 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 a query containing
+ aggregate expressions for a partitioned table across one or more
+ remote servers. This optimization sends an aggregate expression to
+ a remote server and the aggregate is a partial aggregate on the
+ local server. This optimization requires an aggregate function
+ called the <firstterm>partial aggregate function</firstterm>.
+ See
+ <xref linkend="partial-aggregate-pushdown"/> for the
+ definition of the partial aggregate function.
+ </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 83aeef2751..b23d4f7994 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 06435e8b92..b2f676fdc5 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',
@@ -6606,36 +6621,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' },
@@ -6658,6 +6698,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' },
@@ -6816,153 +6859,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',
@@ -6973,52 +7124,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 2027265b31..f97a70bf1a 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: <TYTPR01MB10954D890D8F729E1BCE42D4F95DDA@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