From dcdf4d107dc1d062f54e91abfac7099956b17988 Mon Sep 17 00:00:00 2001
From: Yuki Fujii <Fujii.Yuki@df.MitsubishiElectric.co.jp>
Date: Sat, 19 Nov 2022 18:00:01 +0900
Subject: [PATCH] Partial aggregates push down v11

---
 contrib/postgres_fdw/deparse.c                |  91 ++++-
 .../postgres_fdw/expected/postgres_fdw.out    | 246 +++++++++++-
 contrib/postgres_fdw/option.c                 |  24 ++
 contrib/postgres_fdw/postgres_fdw.c           |  25 +-
 contrib/postgres_fdw/postgres_fdw.h           |   3 +
 contrib/postgres_fdw/sql/postgres_fdw.sql     |  54 ++-
 src/backend/catalog/pg_aggregate.c            |  50 ++-
 src/backend/commands/aggregatecmds.c          |   8 +
 src/bin/pg_dump/pg_dump.c                     |  25 +-
 src/include/catalog/pg_aggregate.dat          | 367 +++++++++++++++---
 src/include/catalog/pg_aggregate.h            |  11 +
 src/include/catalog/pg_proc.dat               | 207 ++++++++++
 src/test/regress/expected/oidjoins.out        |   1 +
 src/test/regress/expected/opr_sanity.out      | 120 +++++-
 14 files changed, 1117 insertions(+), 115 deletions(-)

diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c
index 9524765650..3341615737 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. */
@@ -3448,14 +3449,33 @@ 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)) {
+		appendFunctionName(node->aggfnoid, context);
+	}
+	else {
+		HeapTuple         aggtup;
+		Form_pg_aggregate aggform;
+
+		/* Find aggregate name from aggfnoid which is a pg_proc entry */
+		aggtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(node->aggfnoid));
+		if (!HeapTupleIsValid(aggtup))
+			elog(ERROR, "cache lookup failed for function %u", node->aggfnoid);
+		aggform = (Form_pg_aggregate)GETSTRUCT(aggtup);
+		if (aggform->partialaggfn) {
+			appendFunctionName((Oid)(aggform->partialaggfn), context);
+		} else {
+			elog(ERROR, "there in no partialaggfn %u", node->aggfnoid);
+		}
+		ReleaseSysCache(aggtup);
+	}
+
 	appendStringInfoChar(buf, '(');
 
 	/* Add DISTINCT */
@@ -3961,3 +3981,60 @@ get_relation_column_alias_ids(Var *node, RelOptInfo *foreignrel,
 	/* Shouldn't get here */
 	elog(ERROR, "unexpected expression in subquery output");
 }
+
+/*
+ * Check that partial aggregate agg has compatibility
+ */
+static bool
+partial_agg_compatible(Form_pg_aggregate aggform, PgFdwRelationInfo *fpinfo)
+{
+	bool   compatible = false;
+	int32  partialagg_minversion = PG_VERSION_NUM;
+	if (aggform->partialagg_minversion == PARTIALAGG_MINVERSION_DEFAULT) {
+		partialagg_minversion = PG_VERSION_NUM;
+	}
+	else {
+		partialagg_minversion = aggform->partialagg_minversion;
+	}
+	/* the option value of serverversion is in compatibleversonrange */
+	if ((fpinfo->server_version >= partialagg_minversion)) {
+		compatible = true;
+	}
+	return compatible;
+}
+/*
+ * Check that partial aggregate agg is fine to push down
+ *
+ * Check that it's AGGKIND_NORMAL aggregate without
+ * distinct or order by clauses, which has valid partialaggfn
+ * and partialagg_minversion <= server_version
+ */
+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 function %u", agg->aggfnoid);
+	aggform = (Form_pg_aggregate)GETSTRUCT(aggtup);
+
+	/* Only aggregates which has partialaggfn, are allowed */
+	if (!aggform->partialaggfn)
+	{
+		partial_agg_ok = false;
+	} else if(!partial_agg_compatible(aggform, 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 558e94b845..cf0f270946 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -9645,13 +9645,34 @@ RESET enable_partitionwise_join;
 -- ===================================================================
 -- test partitionwise aggregates
 -- ===================================================================
-CREATE TABLE pagg_tab (a int, b int, c text) PARTITION BY RANGE(a);
+CREATE OR REPLACE FUNCTION f_server_version_lag(version_offset int4) RETURNS name AS $$
+    SELECT (setting::int4 + version_offset)::name FROM pg_settings WHERE name = 'server_version_num';
+$$ LANGUAGE sql;
+CREATE OR REPLACE FUNCTION f_alter_server_version(server_name name, operation text, version_offset int4) RETURNS void AS $$
+    DECLARE
+        version_num name;
+    BEGIN
+        EXECUTE 'SELECT f_server_version_lag($1) '
+            INTO version_num
+            USING version_offset;
+        EXECUTE format('ALTER SERVER %I OPTIONS (%I server_version %L)',
+            server_name, operation, version_num);
+        RETURN;
+    END;
+$$ LANGUAGE plpgsql;
+SELECT f_alter_server_version('loopback', 'add', 0);
+ f_alter_server_version 
+------------------------
+ 
+(1 row)
+
+CREATE TABLE pagg_tab (a int, b int, c text, d int4) 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 % 40 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 % 40 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 % 40 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');
@@ -9710,8 +9731,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
@@ -9722,21 +9743,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, d 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, d 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, d 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;
@@ -9772,6 +9793,213 @@ SELECT b, avg(a), max(a), count(*) FROM pagg_tab GROUP BY b HAVING sum(a) < 700
                      ->  Foreign Scan on fpagg_tab_p3 pagg_tab_2
 (15 rows)
 
+-- It's unsafe to push down having clause when there are partial aggregates
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT b, max(a), count(*) FROM pagg_tab GROUP BY b HAVING sum(a) < 700 ORDER BY 1;
+                                                    QUERY PLAN                                                    
+------------------------------------------------------------------------------------------------------------------
+ Sort
+   Output: pagg_tab.b, (max(pagg_tab.a)), (count(*))
+   Sort Key: pagg_tab.b
+   ->  Finalize HashAggregate
+         Output: pagg_tab.b, max(pagg_tab.a), count(*)
+         Group Key: pagg_tab.b
+         Filter: (sum(pagg_tab.a) < 700)
+         ->  Append
+               ->  Partial HashAggregate
+                     Output: pagg_tab.b, PARTIAL max(pagg_tab.a), PARTIAL count(*), PARTIAL sum(pagg_tab.a)
+                     Group Key: pagg_tab.b
+                     ->  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 max(pagg_tab_1.a), PARTIAL count(*), PARTIAL sum(pagg_tab_1.a)
+                     Group Key: pagg_tab_1.b
+                     ->  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 max(pagg_tab_2.a), PARTIAL count(*), PARTIAL sum(pagg_tab_2.a)
+                     Group Key: pagg_tab_2.b
+                     ->  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)
+
+-- Partial aggregates are fine to push down without having clause
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT b, min(a), max(a), count(*), sum(d), avg(d), avg(d::int8) FROM pagg_tab GROUP BY b ORDER BY 1;
+                                                                                                       QUERY PLAN                                                                                                        
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Sort
+   Output: pagg_tab.b, (min(pagg_tab.a)), (max(pagg_tab.a)), (count(*)), (sum(pagg_tab.d)), (avg(pagg_tab.d)), (avg((pagg_tab.d)::bigint))
+   Sort Key: pagg_tab.b
+   ->  Finalize HashAggregate
+         Output: pagg_tab.b, min(pagg_tab.a), max(pagg_tab.a), count(*), sum(pagg_tab.d), avg(pagg_tab.d), avg((pagg_tab.d)::bigint)
+         Group Key: pagg_tab.b
+         ->  Append
+               ->  Foreign Scan
+                     Output: pagg_tab.b, (PARTIAL min(pagg_tab.a)), (PARTIAL max(pagg_tab.a)), (PARTIAL count(*)), (PARTIAL sum(pagg_tab.d)), (PARTIAL avg(pagg_tab.d)), (PARTIAL avg((pagg_tab.d)::bigint))
+                     Relations: Aggregate on (public.fpagg_tab_p1 pagg_tab)
+                     Remote SQL: SELECT b, min_p_int4(a), max_p_int4(a), count_p(*), sum_p_int4(d), avg_p_int4(d), avg_p_int8(d::bigint) FROM public.pagg_tab_p1 GROUP BY 1
+               ->  Foreign Scan
+                     Output: pagg_tab_1.b, (PARTIAL min(pagg_tab_1.a)), (PARTIAL max(pagg_tab_1.a)), (PARTIAL count(*)), (PARTIAL sum(pagg_tab_1.d)), (PARTIAL avg(pagg_tab_1.d)), (PARTIAL avg((pagg_tab_1.d)::bigint))
+                     Relations: Aggregate on (public.fpagg_tab_p2 pagg_tab_1)
+                     Remote SQL: SELECT b, min_p_int4(a), max_p_int4(a), count_p(*), sum_p_int4(d), avg_p_int4(d), avg_p_int8(d::bigint) FROM public.pagg_tab_p2 GROUP BY 1
+               ->  Foreign Scan
+                     Output: pagg_tab_2.b, (PARTIAL min(pagg_tab_2.a)), (PARTIAL max(pagg_tab_2.a)), (PARTIAL count(*)), (PARTIAL sum(pagg_tab_2.d)), (PARTIAL avg(pagg_tab_2.d)), (PARTIAL avg((pagg_tab_2.d)::bigint))
+                     Relations: Aggregate on (public.fpagg_tab_p3 pagg_tab_2)
+                     Remote SQL: SELECT b, min_p_int4(a), max_p_int4(a), count_p(*), sum_p_int4(d), avg_p_int4(d), avg_p_int8(d::bigint) FROM public.pagg_tab_p3 GROUP BY 1
+(19 rows)
+
+SELECT b, min(a), max(a), count(*), sum(d), avg(d), avg(d::int8) FROM pagg_tab GROUP BY b ORDER BY 1;
+ b  | min | max | count | sum  |         avg         |         avg         
+----+-----+-----+-------+------+---------------------+---------------------
+  0 |   0 |  20 |    60 |  900 | 15.0000000000000000 | 15.0000000000000000
+  1 |   1 |  21 |    60 |  960 | 16.0000000000000000 | 16.0000000000000000
+  2 |   2 |  22 |    60 | 1020 | 17.0000000000000000 | 17.0000000000000000
+  3 |   3 |  23 |    60 | 1080 | 18.0000000000000000 | 18.0000000000000000
+  4 |   4 |  24 |    60 | 1140 | 19.0000000000000000 | 19.0000000000000000
+  5 |   5 |  25 |    60 | 1200 | 20.0000000000000000 | 20.0000000000000000
+  6 |   6 |  26 |    60 | 1260 | 21.0000000000000000 | 21.0000000000000000
+  7 |   7 |  27 |    60 | 1320 | 22.0000000000000000 | 22.0000000000000000
+  8 |   8 |  28 |    60 | 1380 | 23.0000000000000000 | 23.0000000000000000
+  9 |   9 |  29 |    60 | 1440 | 24.0000000000000000 | 24.0000000000000000
+ 10 |   0 |  20 |    60 |  900 | 15.0000000000000000 | 15.0000000000000000
+ 11 |   1 |  21 |    60 |  960 | 16.0000000000000000 | 16.0000000000000000
+ 12 |   2 |  22 |    60 | 1020 | 17.0000000000000000 | 17.0000000000000000
+ 13 |   3 |  23 |    60 | 1080 | 18.0000000000000000 | 18.0000000000000000
+ 14 |   4 |  24 |    60 | 1140 | 19.0000000000000000 | 19.0000000000000000
+ 15 |   5 |  25 |    60 | 1200 | 20.0000000000000000 | 20.0000000000000000
+ 16 |   6 |  26 |    60 | 1260 | 21.0000000000000000 | 21.0000000000000000
+ 17 |   7 |  27 |    60 | 1320 | 22.0000000000000000 | 22.0000000000000000
+ 18 |   8 |  28 |    60 | 1380 | 23.0000000000000000 | 23.0000000000000000
+ 19 |   9 |  29 |    60 | 1440 | 24.0000000000000000 | 24.0000000000000000
+ 20 |   0 |  20 |    60 |  900 | 15.0000000000000000 | 15.0000000000000000
+ 21 |   1 |  21 |    60 |  960 | 16.0000000000000000 | 16.0000000000000000
+ 22 |   2 |  22 |    60 | 1020 | 17.0000000000000000 | 17.0000000000000000
+ 23 |   3 |  23 |    60 | 1080 | 18.0000000000000000 | 18.0000000000000000
+ 24 |   4 |  24 |    60 | 1140 | 19.0000000000000000 | 19.0000000000000000
+ 25 |   5 |  25 |    60 | 1200 | 20.0000000000000000 | 20.0000000000000000
+ 26 |   6 |  26 |    60 | 1260 | 21.0000000000000000 | 21.0000000000000000
+ 27 |   7 |  27 |    60 | 1320 | 22.0000000000000000 | 22.0000000000000000
+ 28 |   8 |  28 |    60 | 1380 | 23.0000000000000000 | 23.0000000000000000
+ 29 |   9 |  29 |    60 | 1440 | 24.0000000000000000 | 24.0000000000000000
+ 30 |   0 |  20 |    60 |  900 | 15.0000000000000000 | 15.0000000000000000
+ 31 |   1 |  21 |    60 |  960 | 16.0000000000000000 | 16.0000000000000000
+ 32 |   2 |  22 |    60 | 1020 | 17.0000000000000000 | 17.0000000000000000
+ 33 |   3 |  23 |    60 | 1080 | 18.0000000000000000 | 18.0000000000000000
+ 34 |   4 |  24 |    60 | 1140 | 19.0000000000000000 | 19.0000000000000000
+ 35 |   5 |  25 |    60 | 1200 | 20.0000000000000000 | 20.0000000000000000
+ 36 |   6 |  26 |    60 | 1260 | 21.0000000000000000 | 21.0000000000000000
+ 37 |   7 |  27 |    60 | 1320 | 22.0000000000000000 | 22.0000000000000000
+ 38 |   8 |  28 |    60 | 1380 | 23.0000000000000000 | 23.0000000000000000
+ 39 |   9 |  29 |    60 | 1440 | 24.0000000000000000 | 24.0000000000000000
+ 40 |   0 |  20 |    60 |  900 | 15.0000000000000000 | 15.0000000000000000
+ 41 |   1 |  21 |    60 |  960 | 16.0000000000000000 | 16.0000000000000000
+ 42 |   2 |  22 |    60 | 1020 | 17.0000000000000000 | 17.0000000000000000
+ 43 |   3 |  23 |    60 | 1080 | 18.0000000000000000 | 18.0000000000000000
+ 44 |   4 |  24 |    60 | 1140 | 19.0000000000000000 | 19.0000000000000000
+ 45 |   5 |  25 |    60 | 1200 | 20.0000000000000000 | 20.0000000000000000
+ 46 |   6 |  26 |    60 | 1260 | 21.0000000000000000 | 21.0000000000000000
+ 47 |   7 |  27 |    60 | 1320 | 22.0000000000000000 | 22.0000000000000000
+ 48 |   8 |  28 |    60 | 1380 | 23.0000000000000000 | 23.0000000000000000
+ 49 |   9 |  29 |    60 | 1440 | 24.0000000000000000 | 24.0000000000000000
+(50 rows)
+
+-- Partial aggregates are fine to push down
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT min(a), max(a), count(*), sum(d), avg(d), avg(d::int8) FROM pagg_tab;
+                                                                                             QUERY PLAN                                                                                              
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Finalize Aggregate
+   Output: min(pagg_tab.a), max(pagg_tab.a), count(*), sum(pagg_tab.d), avg(pagg_tab.d), avg((pagg_tab.d)::bigint)
+   ->  Append
+         ->  Foreign Scan
+               Output: (PARTIAL min(pagg_tab.a)), (PARTIAL max(pagg_tab.a)), (PARTIAL count(*)), (PARTIAL sum(pagg_tab.d)), (PARTIAL avg(pagg_tab.d)), (PARTIAL avg((pagg_tab.d)::bigint))
+               Relations: Aggregate on (public.fpagg_tab_p1 pagg_tab)
+               Remote SQL: SELECT min_p_int4(a), max_p_int4(a), count_p(*), sum_p_int4(d), avg_p_int4(d), avg_p_int8(d::bigint) FROM public.pagg_tab_p1
+         ->  Foreign Scan
+               Output: (PARTIAL min(pagg_tab_1.a)), (PARTIAL max(pagg_tab_1.a)), (PARTIAL count(*)), (PARTIAL sum(pagg_tab_1.d)), (PARTIAL avg(pagg_tab_1.d)), (PARTIAL avg((pagg_tab_1.d)::bigint))
+               Relations: Aggregate on (public.fpagg_tab_p2 pagg_tab_1)
+               Remote SQL: SELECT min_p_int4(a), max_p_int4(a), count_p(*), sum_p_int4(d), avg_p_int4(d), avg_p_int8(d::bigint) FROM public.pagg_tab_p2
+         ->  Foreign Scan
+               Output: (PARTIAL min(pagg_tab_2.a)), (PARTIAL max(pagg_tab_2.a)), (PARTIAL count(*)), (PARTIAL sum(pagg_tab_2.d)), (PARTIAL avg(pagg_tab_2.d)), (PARTIAL avg((pagg_tab_2.d)::bigint))
+               Relations: Aggregate on (public.fpagg_tab_p3 pagg_tab_2)
+               Remote SQL: SELECT min_p_int4(a), max_p_int4(a), count_p(*), sum_p_int4(d), avg_p_int4(d), avg_p_int8(d::bigint) FROM public.pagg_tab_p3
+(15 rows)
+
+SELECT min(a), max(a), count(*), sum(d), avg(d), avg(d::int8) FROM pagg_tab;
+ min | max | count |  sum  |         avg         |         avg         
+-----+-----+-------+-------+---------------------+---------------------
+   0 |  29 |  3000 | 58500 | 19.5000000000000000 | 19.5000000000000000
+(1 row)
+
+-- It's unsafe to push down partial aggregates with distinct option
+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 with distinct
+SELECT f_alter_server_version('loopback', 'set', -1);
+ f_alter_server_version 
+------------------------
+ 
+(1 row)
+
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT avg(d) FROM pagg_tab;
+                            QUERY PLAN                            
+------------------------------------------------------------------
+ Finalize Aggregate
+   Output: avg(pagg_tab.d)
+   ->  Append
+         ->  Partial Aggregate
+               Output: PARTIAL avg(pagg_tab.d)
+               ->  Foreign Scan on public.fpagg_tab_p1 pagg_tab
+                     Output: pagg_tab.d
+                     Remote SQL: SELECT d FROM public.pagg_tab_p1
+         ->  Partial Aggregate
+               Output: PARTIAL avg(pagg_tab_1.d)
+               ->  Foreign Scan on public.fpagg_tab_p2 pagg_tab_1
+                     Output: pagg_tab_1.d
+                     Remote SQL: SELECT d FROM public.pagg_tab_p2
+         ->  Partial Aggregate
+               Output: PARTIAL avg(pagg_tab_2.d)
+               ->  Foreign Scan on public.fpagg_tab_p3 pagg_tab_2
+                     Output: pagg_tab_2.d
+                     Remote SQL: SELECT d FROM public.pagg_tab_p3
+(18 rows)
+
+SELECT avg(d) FROM pagg_tab;
+         avg         
+---------------------
+ 19.5000000000000000
+(1 row)
+
+DROP FUNCTION f_server_version_lag(int4);
+DROP FUNCTION f_alter_server_version(name, text, int4);
 -- ===================================================================
 -- access rights and superuser
 -- ===================================================================
diff --git a/contrib/postgres_fdw/option.c b/contrib/postgres_fdw/option.c
index fa80ee2a55..cb1b28baf2 100644
--- a/contrib/postgres_fdw/option.c
+++ b/contrib/postgres_fdw/option.c
@@ -210,6 +210,27 @@ postgres_fdw_validator(PG_FUNCTION_ARGS)
 						 errmsg("sslcert and sslkey are superuser-only"),
 						 errhint("User mappings with the sslcert or sslkey options set may only be created or modified by the superuser.")));
 		}
+		else if (strcmp(def->defname, "server_version") == 0)
+		{
+			char* value;
+			int			int_val;
+			bool		is_parsed;
+
+			value = defGetString(def);
+			is_parsed = parse_int(value, &int_val, 0, NULL);
+
+			if (!is_parsed)
+				ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						errmsg("invalid value for integer option \"%s\": %s",
+							def->defname, value)));
+
+			if (int_val <= 0)
+				ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						errmsg("\"%s\" must be an integer value greater than zero",
+							def->defname)));
+		}
 	}
 
 	PG_RETURN_VOID();
@@ -265,6 +286,9 @@ InitPgFdwOptions(void)
 		{"sslcert", UserMappingRelationId, true},
 		{"sslkey", UserMappingRelationId, true},
 
+		/* options for partial aggregation pushdown */
+		{"server_version", ForeignServerRelationId, false},
+
 		{NULL, InvalidOid, false}
 	};
 
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 8d7500abfb..c8efdfefb7 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -518,7 +518,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);
+								Node *havingQual, bool partial);
 static List *get_useful_pathkeys_for_relation(PlannerInfo *root,
 											  RelOptInfo *rel);
 static List *get_useful_ecs_for_relation(PlannerInfo *root, RelOptInfo *rel);
@@ -527,7 +527,7 @@ static void add_paths_with_pathkeys_for_rel(PlannerInfo *root, RelOptInfo *rel,
 static void add_foreign_grouping_paths(PlannerInfo *root,
 									   RelOptInfo *input_rel,
 									   RelOptInfo *grouped_rel,
-									   GroupPathExtraData *extra);
+									   GroupPathExtraData *extra, bool partial);
 static void add_foreign_ordered_paths(PlannerInfo *root,
 									  RelOptInfo *input_rel,
 									  RelOptInfo *ordered_rel);
@@ -651,6 +651,7 @@ postgresGetForeignRelSize(PlannerInfo *root,
 	fpinfo->shippable_extensions = NIL;
 	fpinfo->fetch_size = 100;
 	fpinfo->async_capable = false;
+	fpinfo->server_version = 0;
 
 	apply_server_options(fpinfo);
 	apply_table_options(fpinfo);
@@ -5922,6 +5923,8 @@ apply_server_options(PgFdwRelationInfo *fpinfo)
 			(void) parse_int(defGetString(def), &fpinfo->fetch_size, 0, NULL);
 		else if (strcmp(def->defname, "async_capable") == 0)
 			fpinfo->async_capable = defGetBoolean(def);
+		else if (strcmp(def->defname, "server_version") == 0)
+			(void)parse_int(defGetString(def), &fpinfo->server_version, 0, NULL);
 	}
 }
 
@@ -6159,7 +6162,7 @@ postgresGetForeignJoinPaths(PlannerInfo *root,
  */
 static bool
 foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel,
-					Node *havingQual)
+					Node *havingQual, bool partial)
 {
 	Query	   *query = root->parse;
 	PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) grouped_rel->fdw_private;
@@ -6173,6 +6176,10 @@ foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel,
 	if (query->groupingSets)
 		return false;
 
+	/* It's unsafe to push having statements with partial aggregates */
+	if (partial && havingQual)
+		return false;
+
 	/* Get the fpinfo of the underlying scan relation. */
 	ofpinfo = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private;
 
@@ -6409,6 +6416,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)
@@ -6423,7 +6431,11 @@ postgresGetForeignUpperPaths(PlannerInfo *root, UpperRelationKind stage,
 	{
 		case UPPERREL_GROUP_AGG:
 			add_foreign_grouping_paths(root, input_rel, output_rel,
-									   (GroupPathExtraData *) extra);
+									   (GroupPathExtraData *) extra, false);
+			break;
+		case UPPERREL_PARTIAL_GROUP_AGG:
+			add_foreign_grouping_paths(root, input_rel, output_rel,
+				(GroupPathExtraData*)extra, true);
 			break;
 		case UPPERREL_ORDERED:
 			add_foreign_ordered_paths(root, input_rel, output_rel);
@@ -6448,7 +6460,7 @@ postgresGetForeignUpperPaths(PlannerInfo *root, UpperRelationKind stage,
 static void
 add_foreign_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
 						   RelOptInfo *grouped_rel,
-						   GroupPathExtraData *extra)
+						   GroupPathExtraData *extra, bool partial)
 {
 	Query	   *parse = root->parse;
 	PgFdwRelationInfo *ifpinfo = input_rel->fdw_private;
@@ -6477,6 +6489,7 @@ add_foreign_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
 	fpinfo->table = ifpinfo->table;
 	fpinfo->server = ifpinfo->server;
 	fpinfo->user = ifpinfo->user;
+	fpinfo->server_version = ifpinfo->server_version;
 	merge_fdw_options(fpinfo, ifpinfo, NULL);
 
 	/*
@@ -6485,7 +6498,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->havingQual, partial))
 		return;
 
 	/*
diff --git a/contrib/postgres_fdw/postgres_fdw.h b/contrib/postgres_fdw/postgres_fdw.h
index a11d45bedf..5bb35d9743 100644
--- a/contrib/postgres_fdw/postgres_fdw.h
+++ b/contrib/postgres_fdw/postgres_fdw.h
@@ -88,6 +88,9 @@ typedef struct PgFdwRelationInfo
 
 	int			fetch_size;		/* fetch size for this remote table */
 
+	/* Options for check compatibility of partial aggregation */
+	int			server_version;
+
 	/*
 	 * Name of the relation, for use while EXPLAINing ForeignScan.  It is used
 	 * for join and upper relations but is set for all relations.  For a base
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index b0dbb41fb5..9176337420 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -2919,16 +2919,34 @@ RESET enable_partitionwise_join;
 -- ===================================================================
 -- test partitionwise aggregates
 -- ===================================================================
+CREATE OR REPLACE FUNCTION f_server_version_lag(version_offset int4) RETURNS name AS $$
+    SELECT (setting::int4 + version_offset)::name FROM pg_settings WHERE name = 'server_version_num';
+$$ LANGUAGE sql;
 
-CREATE TABLE pagg_tab (a int, b int, c text) PARTITION BY RANGE(a);
+CREATE OR REPLACE FUNCTION f_alter_server_version(server_name name, operation text, version_offset int4) RETURNS void AS $$
+    DECLARE
+        version_num name;
+    BEGIN
+        EXECUTE 'SELECT f_server_version_lag($1) '
+            INTO version_num
+            USING version_offset;
+        EXECUTE format('ALTER SERVER %I OPTIONS (%I server_version %L)',
+            server_name, operation, version_num);
+        RETURN;
+    END;
+$$ LANGUAGE plpgsql;
+
+SELECT f_alter_server_version('loopback', 'add', 0);
+
+CREATE TABLE pagg_tab (a int, b int, c text, d int4) 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 % 40 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 % 40 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 % 40 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');
@@ -2962,6 +2980,34 @@ SELECT a, count(t1) FROM pagg_tab t1 GROUP BY a HAVING avg(b) < 22 ORDER BY 1;
 EXPLAIN (COSTS OFF)
 SELECT b, avg(a), max(a), count(*) FROM pagg_tab GROUP BY b HAVING sum(a) < 700 ORDER BY 1;
 
+-- It's unsafe to push down having clause when there are partial aggregates
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT b, max(a), count(*) FROM pagg_tab GROUP BY b HAVING sum(a) < 700 ORDER BY 1;
+
+-- Partial aggregates are fine to push down without having clause
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT b, min(a), max(a), count(*), sum(d), avg(d), avg(d::int8) FROM pagg_tab GROUP BY b ORDER BY 1;
+SELECT b, min(a), max(a), count(*), sum(d), avg(d), avg(d::int8) FROM pagg_tab GROUP BY b ORDER BY 1;
+
+-- Partial aggregates are fine to push down
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT min(a), max(a), count(*), sum(d), avg(d), avg(d::int8) FROM pagg_tab;
+SELECT min(a), max(a), count(*), sum(d), avg(d), avg(d::int8) FROM pagg_tab;
+
+-- It's unsafe to push down partial aggregates with distinct option
+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 with distinct
+SELECT f_alter_server_version('loopback', 'set', -1);
+EXPLAIN (VERBOSE, COSTS OFF)
+SELECT avg(d) FROM pagg_tab;
+SELECT avg(d) FROM pagg_tab;
+
+DROP FUNCTION f_server_version_lag(int4);
+DROP FUNCTION f_alter_server_version(name, text, int4);
+
 -- ===================================================================
 -- access rights and superuser
 -- ===================================================================
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index a98445b741..9f8a326cec 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -36,7 +36,8 @@
 
 static Oid	lookup_agg_function(List *fnName, int nargs, Oid *input_types,
 								Oid variadicArgType,
-								Oid *rettype);
+								Oid *rettype,
+								bool only_normal);
 
 
 /*
@@ -63,6 +64,7 @@ AggregateCreate(const char *aggName,
 				List *aggmtransfnName,
 				List *aggminvtransfnName,
 				List *aggmfinalfnName,
+				List *partialaggfnName,
 				bool finalfnExtraArgs,
 				bool mfinalfnExtraArgs,
 				char finalfnModify,
@@ -72,6 +74,7 @@ AggregateCreate(const char *aggName,
 				int32 aggTransSpace,
 				Oid aggmTransType,
 				int32 aggmTransSpace,
+				int32 partialaggMinversion,
 				const char *agginitval,
 				const char *aggminitval,
 				char proparallel)
@@ -91,6 +94,7 @@ AggregateCreate(const char *aggName,
 	Oid			mtransfn = InvalidOid;	/* can be omitted */
 	Oid			minvtransfn = InvalidOid;	/* can be omitted */
 	Oid			mfinalfn = InvalidOid;	/* can be omitted */
+	Oid			partialaggfn = InvalidOid;	/* can be omitted */
 	Oid			sortop = InvalidOid;	/* can be omitted */
 	Oid		   *aggArgTypes = parameterTypes->values;
 	bool		mtransIsStrict = false;
@@ -228,7 +232,7 @@ AggregateCreate(const char *aggName,
 	}
 	transfn = lookup_agg_function(aggtransfnName, nargs_transfn,
 								  fnArgs, variadicArgType,
-								  &rettype);
+								  &rettype, true);
 
 	/*
 	 * Return type of transfn (possibly after refinement by
@@ -281,7 +285,7 @@ AggregateCreate(const char *aggName,
 
 		mtransfn = lookup_agg_function(aggmtransfnName, nargs_transfn,
 									   fnArgs, variadicArgType,
-									   &rettype);
+									   &rettype, true);
 
 		/* As above, return type must exactly match declared mtranstype. */
 		if (rettype != aggmTransType)
@@ -326,7 +330,7 @@ AggregateCreate(const char *aggName,
 
 		minvtransfn = lookup_agg_function(aggminvtransfnName, nargs_transfn,
 										  fnArgs, variadicArgType,
-										  &rettype);
+										  &rettype, true);
 
 		/* As above, return type must exactly match declared mtranstype. */
 		if (rettype != aggmTransType)
@@ -382,7 +386,7 @@ AggregateCreate(const char *aggName,
 
 		finalfn = lookup_agg_function(aggfinalfnName, nargs_finalfn,
 									  fnArgs, ffnVariadicArgType,
-									  &finaltype);
+									  &finaltype, true);
 
 		/*
 		 * When finalfnExtraArgs is specified, the finalfn will certainly be
@@ -418,7 +422,7 @@ AggregateCreate(const char *aggName,
 
 		combinefn = lookup_agg_function(aggcombinefnName, 2,
 										fnArgs, InvalidOid,
-										&combineType);
+										&combineType, true);
 
 		/* Ensure the return type matches the aggregate's trans type */
 		if (combineType != aggTransType)
@@ -450,7 +454,7 @@ AggregateCreate(const char *aggName,
 
 		serialfn = lookup_agg_function(aggserialfnName, 1,
 									   fnArgs, InvalidOid,
-									   &rettype);
+									   &rettype, true);
 
 		if (rettype != BYTEAOID)
 			ereport(ERROR,
@@ -471,7 +475,7 @@ AggregateCreate(const char *aggName,
 
 		deserialfn = lookup_agg_function(aggdeserialfnName, 2,
 										 fnArgs, InvalidOid,
-										 &rettype);
+										 &rettype, true);
 
 		if (rettype != INTERNALOID)
 			ereport(ERROR,
@@ -545,7 +549,7 @@ AggregateCreate(const char *aggName,
 
 			mfinalfn = lookup_agg_function(aggmfinalfnName, nargs_finalfn,
 										   fnArgs, ffnVariadicArgType,
-										   &rettype);
+										   &rettype, true);
 
 			/* As above, check strictness if mfinalfnExtraArgs is given */
 			if (mfinalfnExtraArgs && func_strict(mfinalfn))
@@ -569,6 +573,27 @@ AggregateCreate(const char *aggName,
 							format_type_be(finaltype))));
 	}
 
+	/*
+	 * Validate the partial aggregate function, if present.
+	 */
+	if (partialaggfnName)
+	{
+		HeapTuple aggtup;
+		partialaggfn = lookup_agg_function(partialaggfnName, numArgs,
+			aggArgTypes, variadicArgType, &rettype, false);
+
+		if (((aggTransType == INTERNALOID) && (rettype != BYTEAOID))
+			|| ((aggTransType != INTERNALOID) && (rettype != aggTransType)))
+			ereport(ERROR,
+				(errcode(ERRCODE_DATATYPE_MISMATCH),
+					errmsg("return type of partial aggregation function %s is not stype",
+						NameListToString(partialaggfnName))));
+		aggtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(partialaggfn));
+		if (!HeapTupleIsValid(aggtup))
+			elog(ERROR, "cache lookup failed for function %u", partialaggfn);
+		ReleaseSysCache(aggtup);
+	}
+
 	/* handle sortop, if supplied */
 	if (aggsortopName)
 	{
@@ -684,6 +709,8 @@ AggregateCreate(const char *aggName,
 		values[Anum_pg_aggregate_aggminitval - 1] = CStringGetTextDatum(aggminitval);
 	else
 		nulls[Anum_pg_aggregate_aggminitval - 1] = true;
+	values[Anum_pg_aggregate_partialaggfn - 1] = ObjectIdGetDatum(partialaggfn);
+	values[Anum_pg_aggregate_partialagg_minversion - 1] = Int32GetDatum(partialaggMinversion);
 
 	if (replace)
 		oldtup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(procOid));
@@ -827,7 +854,8 @@ lookup_agg_function(List *fnName,
 					int nargs,
 					Oid *input_types,
 					Oid variadicArgType,
-					Oid *rettype)
+					Oid *rettype,
+					bool only_normal)
 {
 	Oid			fnOid;
 	bool		retset;
@@ -852,7 +880,7 @@ lookup_agg_function(List *fnName,
 							   &true_oid_array, NULL);
 
 	/* only valid case is a normal function not returning a set */
-	if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))
+	if ((fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid)) && only_normal)
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_FUNCTION),
 				 errmsg("function %s does not exist",
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index a9339e40b3..87b21ee1ee 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	   *partialaggfuncName = NIL;
 	List	   *mtransfuncName = NIL;
 	List	   *minvtransfuncName = NIL;
 	List	   *mfinalfuncName = NIL;
@@ -83,6 +84,7 @@ DefineAggregate(ParseState *pstate,
 	TypeName   *mtransType = NULL;
 	int32		transSpace = 0;
 	int32		mtransSpace = 0;
+	int32		partialaggMinversion = 0;
 	char	   *initval = NULL;
 	char	   *minitval = NULL;
 	char	   *parallel = NULL;
@@ -143,6 +145,8 @@ DefineAggregate(ParseState *pstate,
 			serialfuncName = defGetQualifiedName(defel);
 		else if (strcmp(defel->defname, "deserialfunc") == 0)
 			deserialfuncName = defGetQualifiedName(defel);
+		else if (strcmp(defel->defname, "partialaggfunc") == 0)
+			partialaggfuncName = defGetQualifiedName(defel);
 		else if (strcmp(defel->defname, "msfunc") == 0)
 			mtransfuncName = defGetQualifiedName(defel);
 		else if (strcmp(defel->defname, "minvfunc") == 0)
@@ -182,6 +186,8 @@ DefineAggregate(ParseState *pstate,
 			mtransType = defGetTypeName(defel);
 		else if (strcmp(defel->defname, "msspace") == 0)
 			mtransSpace = defGetInt32(defel);
+		else if (strcmp(defel->defname, "partialagg_minversion") == 0)
+			partialaggMinversion = defGetInt32(defel);
 		else if (strcmp(defel->defname, "initcond") == 0)
 			initval = defGetString(defel);
 		else if (strcmp(defel->defname, "initcond1") == 0)
@@ -461,6 +467,7 @@ DefineAggregate(ParseState *pstate,
 						   mtransfuncName,	/* fwd trans function name */
 						   minvtransfuncName,	/* inv trans function name */
 						   mfinalfuncName,	/* final function name */
+						   partialaggfuncName,
 						   finalfuncExtraArgs,
 						   mfinalfuncExtraArgs,
 						   finalfuncModify,
@@ -470,6 +477,7 @@ DefineAggregate(ParseState *pstate,
 						   transSpace,	/* transition space */
 						   mtransTypeId,	/* transition data type */
 						   mtransSpace, /* transition space */
+						   partialaggMinversion,
 						   initval, /* initial condition */
 						   minitval,	/* initial condition */
 						   proparallel);	/* parallel safe? */
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index da427f4d4a..2e2d38b25b 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -13406,6 +13406,8 @@ dumpAgg(Archive *fout, const AggInfo *agginfo)
 	const char *aggmtransfn;
 	const char *aggminvtransfn;
 	const char *aggmfinalfn;
+	const char *partialaggfn;
+	const char *partialagg_minversion;
 	bool		aggfinalextra;
 	bool		aggmfinalextra;
 	char		aggfinalmodify;
@@ -13488,11 +13490,19 @@ 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 >= 160000)
+			appendPQExpBufferStr(query,
+								"partialaggfn,\n"
+								"partialagg_minversion\n");
+		else
+			appendPQExpBufferStr(query,
+								"'-' AS partialaggfn,\n"
+								"0 AS partialagg_minversion\n");
 
 		appendPQExpBufferStr(query,
 							 "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
@@ -13518,6 +13528,8 @@ 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"));
+	partialaggfn = PQgetvalue(res, 0, PQfnumber(res, "partialaggfn"));
+	partialagg_minversion = PQgetvalue(res, 0, PQfnumber(res, "partialagg_minversion"));
 	aggmtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggmtransfn"));
 	aggminvtransfn = PQgetvalue(res, 0, PQfnumber(res, "aggminvtransfn"));
 	aggmfinalfn = PQgetvalue(res, 0, PQfnumber(res, "aggmfinalfn"));
@@ -13607,6 +13619,15 @@ dumpAgg(Archive *fout, const AggInfo *agginfo)
 	if (strcmp(aggdeserialfn, "-") != 0)
 		appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
 
+	if (strcmp(partialaggfn, "-") != 0)
+		appendPQExpBuffer(details, ",\n    PARTIALAGGFUNC = %s", partialaggfn);
+
+	if (strcmp(partialagg_minversion, "0") != 0)
+	{
+		appendPQExpBuffer(details, ",\n    PARTIALAGG_MINVERSION = %s",
+						  partialagg_minversion);
+	}
+
 	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 b9110a5298..fb1cceeb62 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' },
 { 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',
+  partialaggfn => 'avg_p_int8', partialagg_minversion => '160000' },
+{ aggfnoid => 'avg_p_int4', aggtransfn => 'int4_avg_accum',
+  aggcombinefn => 'int4_avg_combine',
+  aggtranstype => '_int8',
+  agginitval => '{0,0}' },
 { 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}',
+  partialaggfn => 'avg_p_int4', partialagg_minversion => '160000' },
+{ aggfnoid => 'avg_p_int2', aggtransfn => 'int2_avg_accum',
+  aggcombinefn => 'int4_avg_combine',
+  aggtranstype => '_int8',
+  agginitval => '{0,0}'  },
 { 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}',
+  partialaggfn => 'avg_p_int2', partialagg_minversion => '160000'  },
+{ 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',
+  partialaggfn => 'avg_p_numeric', partialagg_minversion => '160000' },
 { aggfnoid => 'avg(numeric)', aggtransfn => 'numeric_avg_accum',
   aggfinalfn => 'numeric_avg', aggcombinefn => 'numeric_avg_combine',
   aggserialfn => 'numeric_avg_serialize',
@@ -36,46 +58,87 @@
   aggmtransfn => 'numeric_avg_accum', aggminvtransfn => 'numeric_accum_inv',
   aggmfinalfn => 'numeric_avg', aggtranstype => 'internal',
   aggtransspace => '128', aggmtranstype => 'internal',
-  aggmtransspace => '128' },
+  aggmtransspace => '128',
+  partialaggfn => 'avg_p_numeric', partialagg_minversion => '160000' },
+{ aggfnoid => 'avg_p_float4', aggtransfn => 'float4_accum',
+  aggcombinefn => 'float8_combine',
+  aggtranstype => '_float8', agginitval => '{0,0,0}' },
 { aggfnoid => 'avg(float4)', aggtransfn => 'float4_accum',
   aggfinalfn => 'float8_avg', aggcombinefn => 'float8_combine',
+  aggtranstype => '_float8', agginitval => '{0,0,0}',
+  partialaggfn => 'avg_p_float4', partialagg_minversion => '160000' },
+{ aggfnoid => 'avg_p_float8', aggtransfn => 'float8_accum',
+  aggcombinefn => 'float8_combine',
   aggtranstype => '_float8', agginitval => '{0,0,0}' },
 { aggfnoid => 'avg(float8)', aggtransfn => 'float8_accum',
   aggfinalfn => 'float8_avg', aggcombinefn => 'float8_combine',
-  aggtranstype => '_float8', agginitval => '{0,0,0}' },
+  aggtranstype => '_float8', agginitval => '{0,0,0}',
+  partialaggfn => 'avg_p_float8', partialagg_minversion => '160000'  },
+{ aggfnoid => 'avg_p_interval', aggtransfn => 'interval_accum',
+  aggcombinefn => 'interval_combine',
+  aggtranstype => '_interval', agginitval => '{0 second,0 second}'  },
 { 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}',
+  partialaggfn => 'avg_p_interval', partialagg_minversion => '160000'  },
 
 # 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' },
 { 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',
+  partialaggfn => 'sum_p_int8', partialagg_minversion => '160000' },
+{ aggfnoid => 'sum_p_int4', aggtransfn => 'int4_sum', aggcombinefn => 'int8pl',
+  aggtranstype => '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}',
+  partialaggfn => 'sum_p_int4', partialagg_minversion => '160000' },
+{ aggfnoid => 'sum_p_int2', aggtransfn => 'int2_sum', aggcombinefn => 'int8pl',
+  aggtranstype => 'int8' },
 { 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}' },
-{ aggfnoid => 'sum(float4)', aggtransfn => 'float4pl',
+  aggmtranstype => '_int8', aggminitval => '{0,0}',
+  partialaggfn => 'sum_p_int2', partialagg_minversion => '160000' },
+{ aggfnoid => 'sum_p_float4', aggtransfn => 'float4pl',
   aggcombinefn => 'float4pl', aggtranstype => 'float4' },
-{ aggfnoid => 'sum(float8)', aggtransfn => 'float8pl',
+{ aggfnoid => 'sum(float4)', aggtransfn => 'float4pl',
+  aggcombinefn => 'float4pl', aggtranstype => 'float4',
+  partialaggfn => 'sum_p_float4', partialagg_minversion => '160000' },
+{ aggfnoid => 'sum_p_float8', aggtransfn => 'float8pl',
   aggcombinefn => 'float8pl', aggtranstype => 'float8' },
+{ aggfnoid => 'sum(float8)', aggtransfn => 'float8pl',
+  aggcombinefn => 'float8pl', aggtranstype => 'float8',
+  partialaggfn => 'sum_p_float8', partialagg_minversion => '160000' },
+{ aggfnoid => 'sum_p_money', aggtransfn => 'cash_pl', aggcombinefn => 'cash_pl',
+  aggtranstype => 'money' },
 { aggfnoid => 'sum(money)', aggtransfn => 'cash_pl', aggcombinefn => 'cash_pl',
   aggmtransfn => 'cash_pl', aggminvtransfn => 'cash_mi',
-  aggtranstype => 'money', aggmtranstype => 'money' },
+  aggtranstype => 'money', aggmtranstype => 'money',
+  partialaggfn => 'sum_p_money', partialagg_minversion => '160000' },
+{ aggfnoid => 'sum_p_interval', aggtransfn => 'interval_pl',
+  aggcombinefn => 'interval_pl', aggtranstype => 'interval' },
 { aggfnoid => 'sum(interval)', aggtransfn => 'interval_pl',
   aggcombinefn => 'interval_pl', aggmtransfn => 'interval_pl',
   aggminvtransfn => 'interval_mi', aggtranstype => 'interval',
-  aggmtranstype => 'interval' },
+  aggmtranstype => 'interval',
+  partialaggfn => 'sum_p_interval', partialagg_minversion => '160000' },
+{ 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' },
 { aggfnoid => 'sum(numeric)', aggtransfn => 'numeric_avg_accum',
   aggfinalfn => 'numeric_sum', aggcombinefn => 'numeric_avg_combine',
   aggserialfn => 'numeric_avg_serialize',
@@ -83,152 +146,336 @@
   aggmtransfn => 'numeric_avg_accum', aggminvtransfn => 'numeric_accum_inv',
   aggmfinalfn => 'numeric_sum', aggtranstype => 'internal',
   aggtransspace => '128', aggmtranstype => 'internal',
-  aggmtransspace => '128' },
+  aggmtransspace => '128',
+  partialaggfn => 'sum_p_numeric', partialagg_minversion => '160000' },
 
 # max
-{ aggfnoid => 'max(int8)', aggtransfn => 'int8larger',
+{ aggfnoid => 'max_p_int8', aggtransfn => 'int8larger',
   aggcombinefn => 'int8larger', aggsortop => '>(int8,int8)',
   aggtranstype => 'int8' },
-{ aggfnoid => 'max(int4)', aggtransfn => 'int4larger',
+{ aggfnoid => 'max(int8)', aggtransfn => 'int8larger',
+  aggcombinefn => 'int8larger', aggsortop => '>(int8,int8)',
+  aggtranstype => 'int8',
+  partialaggfn => 'max_p_int8', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_int4', aggtransfn => 'int4larger',
   aggcombinefn => 'int4larger', aggsortop => '>(int4,int4)',
   aggtranstype => 'int4' },
-{ aggfnoid => 'max(int2)', aggtransfn => 'int2larger',
+{ aggfnoid => 'max(int4)', aggtransfn => 'int4larger',
+  aggcombinefn => 'int4larger', aggsortop => '>(int4,int4)',
+  aggtranstype => 'int4',
+  partialaggfn => 'max_p_int4', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_int2', aggtransfn => 'int2larger',
   aggcombinefn => 'int2larger', aggsortop => '>(int2,int2)',
   aggtranstype => 'int2' },
-{ aggfnoid => 'max(oid)', aggtransfn => 'oidlarger',
+{ aggfnoid => 'max(int2)', aggtransfn => 'int2larger',
+  aggcombinefn => 'int2larger', aggsortop => '>(int2,int2)',
+  aggtranstype => 'int2',
+  partialaggfn => 'max_p_int2', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_oid', aggtransfn => 'oidlarger',
   aggcombinefn => 'oidlarger', aggsortop => '>(oid,oid)',
   aggtranstype => 'oid' },
-{ aggfnoid => 'max(float4)', aggtransfn => 'float4larger',
+{ aggfnoid => 'max(oid)', aggtransfn => 'oidlarger',
+  aggcombinefn => 'oidlarger', aggsortop => '>(oid,oid)',
+  aggtranstype => 'oid',
+  partialaggfn => 'max_p_oid', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_float4', aggtransfn => 'float4larger',
   aggcombinefn => 'float4larger', aggsortop => '>(float4,float4)',
   aggtranstype => 'float4' },
-{ aggfnoid => 'max(float8)', aggtransfn => 'float8larger',
+{ aggfnoid => 'max(float4)', aggtransfn => 'float4larger',
+  aggcombinefn => 'float4larger', aggsortop => '>(float4,float4)',
+  aggtranstype => 'float4',
+  partialaggfn => 'max_p_float4', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_floa8', aggtransfn => 'float8larger',
   aggcombinefn => 'float8larger', aggsortop => '>(float8,float8)',
   aggtranstype => 'float8' },
-{ aggfnoid => 'max(date)', aggtransfn => 'date_larger',
+{ aggfnoid => 'max(float8)', aggtransfn => 'float8larger',
+  aggcombinefn => 'float8larger', aggsortop => '>(float8,float8)',
+  aggtranstype => 'float8',
+  partialaggfn => 'max_p_floa8', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_date', aggtransfn => 'date_larger',
   aggcombinefn => 'date_larger', aggsortop => '>(date,date)',
   aggtranstype => 'date' },
-{ aggfnoid => 'max(time)', aggtransfn => 'time_larger',
+{ aggfnoid => 'max(date)', aggtransfn => 'date_larger',
+  aggcombinefn => 'date_larger', aggsortop => '>(date,date)',
+  aggtranstype => 'date',
+  partialaggfn => 'max_p_date', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_time', aggtransfn => 'time_larger',
   aggcombinefn => 'time_larger', aggsortop => '>(time,time)',
   aggtranstype => 'time' },
-{ aggfnoid => 'max(timetz)', aggtransfn => 'timetz_larger',
+{ aggfnoid => 'max(time)', aggtransfn => 'time_larger',
+  aggcombinefn => 'time_larger', aggsortop => '>(time,time)',
+  aggtranstype => 'time',
+  partialaggfn => 'max_p_time', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_timetz', aggtransfn => 'timetz_larger',
   aggcombinefn => 'timetz_larger', aggsortop => '>(timetz,timetz)',
   aggtranstype => 'timetz' },
-{ aggfnoid => 'max(money)', aggtransfn => 'cashlarger',
+{ aggfnoid => 'max(timetz)', aggtransfn => 'timetz_larger',
+  aggcombinefn => 'timetz_larger', aggsortop => '>(timetz,timetz)',
+  aggtranstype => 'timetz',
+  partialaggfn => 'max_p_timetz', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_money', aggtransfn => 'cashlarger',
   aggcombinefn => 'cashlarger', aggsortop => '>(money,money)',
   aggtranstype => 'money' },
-{ aggfnoid => 'max(timestamp)', aggtransfn => 'timestamp_larger',
+{ aggfnoid => 'max(money)', aggtransfn => 'cashlarger',
+  aggcombinefn => 'cashlarger', aggsortop => '>(money,money)',
+  aggtranstype => 'money',
+  partialaggfn => 'max_p_money', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_timestamp', aggtransfn => 'timestamp_larger',
   aggcombinefn => 'timestamp_larger', aggsortop => '>(timestamp,timestamp)',
   aggtranstype => 'timestamp' },
-{ aggfnoid => 'max(timestamptz)', aggtransfn => 'timestamptz_larger',
+{ aggfnoid => 'max(timestamp)', aggtransfn => 'timestamp_larger',
+  aggcombinefn => 'timestamp_larger', aggsortop => '>(timestamp,timestamp)',
+  aggtranstype => 'timestamp',
+  partialaggfn => 'max_p_timestamp', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_timestamptz', aggtransfn => 'timestamptz_larger',
   aggcombinefn => 'timestamptz_larger',
   aggsortop => '>(timestamptz,timestamptz)', aggtranstype => 'timestamptz' },
-{ aggfnoid => 'max(interval)', aggtransfn => 'interval_larger',
+{ aggfnoid => 'max(timestamptz)', aggtransfn => 'timestamptz_larger',
+  aggcombinefn => 'timestamptz_larger',
+  aggsortop => '>(timestamptz,timestamptz)', aggtranstype => 'timestamptz',
+  partialaggfn => 'max_p_timestamptz', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_interval', aggtransfn => 'interval_larger',
   aggcombinefn => 'interval_larger', aggsortop => '>(interval,interval)',
   aggtranstype => 'interval' },
-{ aggfnoid => 'max(text)', aggtransfn => 'text_larger',
+{ aggfnoid => 'max(interval)', aggtransfn => 'interval_larger',
+  aggcombinefn => 'interval_larger', aggsortop => '>(interval,interval)',
+  aggtranstype => 'interval',
+  partialaggfn => 'max_p_interval', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_text', aggtransfn => 'text_larger',
   aggcombinefn => 'text_larger', aggsortop => '>(text,text)',
   aggtranstype => 'text' },
-{ aggfnoid => 'max(numeric)', aggtransfn => 'numeric_larger',
+{ aggfnoid => 'max(text)', aggtransfn => 'text_larger',
+  aggcombinefn => 'text_larger', aggsortop => '>(text,text)',
+  aggtranstype => 'text',
+  partialaggfn => 'max_p_text', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_numeric', aggtransfn => 'numeric_larger',
   aggcombinefn => 'numeric_larger', aggsortop => '>(numeric,numeric)',
   aggtranstype => 'numeric' },
-{ aggfnoid => 'max(anyarray)', aggtransfn => 'array_larger',
+{ aggfnoid => 'max(numeric)', aggtransfn => 'numeric_larger',
+  aggcombinefn => 'numeric_larger', aggsortop => '>(numeric,numeric)',
+  aggtranstype => 'numeric',
+  partialaggfn => 'max_p_numeric', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_anyarray', aggtransfn => 'array_larger',
   aggcombinefn => 'array_larger', aggsortop => '>(anyarray,anyarray)',
   aggtranstype => 'anyarray' },
-{ aggfnoid => 'max(bpchar)', aggtransfn => 'bpchar_larger',
+{ aggfnoid => 'max(anyarray)', aggtransfn => 'array_larger',
+  aggcombinefn => 'array_larger', aggsortop => '>(anyarray,anyarray)',
+  aggtranstype => 'anyarray',
+  partialaggfn => 'max_p_anyarray', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_bpchar', aggtransfn => 'bpchar_larger',
   aggcombinefn => 'bpchar_larger', aggsortop => '>(bpchar,bpchar)',
   aggtranstype => 'bpchar' },
-{ aggfnoid => 'max(tid)', aggtransfn => 'tidlarger',
+{ aggfnoid => 'max(bpchar)', aggtransfn => 'bpchar_larger',
+  aggcombinefn => 'bpchar_larger', aggsortop => '>(bpchar,bpchar)',
+  aggtranstype => 'bpchar',
+  partialaggfn => 'max_p_bpchar', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_tid', aggtransfn => 'tidlarger',
   aggcombinefn => 'tidlarger', aggsortop => '>(tid,tid)',
   aggtranstype => 'tid' },
-{ aggfnoid => 'max(anyenum)', aggtransfn => 'enum_larger',
+{ aggfnoid => 'max(tid)', aggtransfn => 'tidlarger',
+  aggcombinefn => 'tidlarger', aggsortop => '>(tid,tid)',
+  aggtranstype => 'tid',
+  partialaggfn => 'max_p_tid', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_anyenum', aggtransfn => 'enum_larger',
   aggcombinefn => 'enum_larger', aggsortop => '>(anyenum,anyenum)',
   aggtranstype => 'anyenum' },
-{ aggfnoid => 'max(inet)', aggtransfn => 'network_larger',
+{ aggfnoid => 'max(anyenum)', aggtransfn => 'enum_larger',
+  aggcombinefn => 'enum_larger', aggsortop => '>(anyenum,anyenum)',
+  aggtranstype => 'anyenum',
+  partialaggfn => 'max_p_anyenum', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_inet', aggtransfn => 'network_larger',
   aggcombinefn => 'network_larger', aggsortop => '>(inet,inet)',
   aggtranstype => 'inet' },
-{ aggfnoid => 'max(pg_lsn)', aggtransfn => 'pg_lsn_larger',
+{ aggfnoid => 'max(inet)', aggtransfn => 'network_larger',
+  aggcombinefn => 'network_larger', aggsortop => '>(inet,inet)',
+  aggtranstype => 'inet',
+  partialaggfn => 'max_p_inet', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_pg_lsn', aggtransfn => 'pg_lsn_larger',
   aggcombinefn => 'pg_lsn_larger', aggsortop => '>(pg_lsn,pg_lsn)',
   aggtranstype => 'pg_lsn' },
-{ aggfnoid => 'max(xid8)', aggtransfn => 'xid8_larger',
+{ aggfnoid => 'max(pg_lsn)', aggtransfn => 'pg_lsn_larger',
+  aggcombinefn => 'pg_lsn_larger', aggsortop => '>(pg_lsn,pg_lsn)',
+  aggtranstype => 'pg_lsn',
+  partialaggfn => 'max_p_pg_lsn', partialagg_minversion => '160000' },
+{ aggfnoid => 'max_p_xid8', aggtransfn => 'xid8_larger',
   aggcombinefn => 'xid8_larger', aggsortop => '>(xid8,xid8)',
   aggtranstype => 'xid8' },
+{ aggfnoid => 'max(xid8)', aggtransfn => 'xid8_larger',
+  aggcombinefn => 'xid8_larger', aggsortop => '>(xid8,xid8)',
+  aggtranstype => 'xid8',
+  partialaggfn => 'max_p_xid8', partialagg_minversion => '160000' },
 
 # min
-{ aggfnoid => 'min(int8)', aggtransfn => 'int8smaller',
+{ aggfnoid => 'min_p_int8', aggtransfn => 'int8smaller',
   aggcombinefn => 'int8smaller', aggsortop => '<(int8,int8)',
   aggtranstype => 'int8' },
-{ aggfnoid => 'min(int4)', aggtransfn => 'int4smaller',
+{ aggfnoid => 'min(int8)', aggtransfn => 'int8smaller',
+  aggcombinefn => 'int8smaller', aggsortop => '<(int8,int8)',
+  aggtranstype => 'int8',
+  partialaggfn => 'min_p_int8', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_int4', aggtransfn => 'int4smaller',
   aggcombinefn => 'int4smaller', aggsortop => '<(int4,int4)',
   aggtranstype => 'int4' },
-{ aggfnoid => 'min(int2)', aggtransfn => 'int2smaller',
+{ aggfnoid => 'min(int4)', aggtransfn => 'int4smaller',
+  aggcombinefn => 'int4smaller', aggsortop => '<(int4,int4)',
+  aggtranstype => 'int4',
+  partialaggfn => 'min_p_int4', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_int2', aggtransfn => 'int2smaller',
   aggcombinefn => 'int2smaller', aggsortop => '<(int2,int2)',
   aggtranstype => 'int2' },
-{ aggfnoid => 'min(oid)', aggtransfn => 'oidsmaller',
+{ aggfnoid => 'min(int2)', aggtransfn => 'int2smaller',
+  aggcombinefn => 'int2smaller', aggsortop => '<(int2,int2)',
+  aggtranstype => 'int2',
+  partialaggfn => 'min_p_int2', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_oid', aggtransfn => 'oidsmaller',
   aggcombinefn => 'oidsmaller', aggsortop => '<(oid,oid)',
   aggtranstype => 'oid' },
-{ aggfnoid => 'min(float4)', aggtransfn => 'float4smaller',
+{ aggfnoid => 'min(oid)', aggtransfn => 'oidsmaller',
+  aggcombinefn => 'oidsmaller', aggsortop => '<(oid,oid)',
+  aggtranstype => 'oid',
+  partialaggfn => 'min_p_oid', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_float4', aggtransfn => 'float4smaller',
   aggcombinefn => 'float4smaller', aggsortop => '<(float4,float4)',
   aggtranstype => 'float4' },
-{ aggfnoid => 'min(float8)', aggtransfn => 'float8smaller',
+{ aggfnoid => 'min(float4)', aggtransfn => 'float4smaller',
+  aggcombinefn => 'float4smaller', aggsortop => '<(float4,float4)',
+  aggtranstype => 'float4',
+  partialaggfn => 'min_p_float4', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_float8', aggtransfn => 'float8smaller',
   aggcombinefn => 'float8smaller', aggsortop => '<(float8,float8)',
   aggtranstype => 'float8' },
-{ aggfnoid => 'min(date)', aggtransfn => 'date_smaller',
+{ aggfnoid => 'min(float8)', aggtransfn => 'float8smaller',
+  aggcombinefn => 'float8smaller', aggsortop => '<(float8,float8)',
+  aggtranstype => 'float8',
+  partialaggfn => 'min_p_float8', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_date', aggtransfn => 'date_smaller',
   aggcombinefn => 'date_smaller', aggsortop => '<(date,date)',
   aggtranstype => 'date' },
-{ aggfnoid => 'min(time)', aggtransfn => 'time_smaller',
+{ aggfnoid => 'min(date)', aggtransfn => 'date_smaller',
+  aggcombinefn => 'date_smaller', aggsortop => '<(date,date)',
+  aggtranstype => 'date',
+  partialaggfn => 'min_p_date', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_time', aggtransfn => 'time_smaller',
   aggcombinefn => 'time_smaller', aggsortop => '<(time,time)',
   aggtranstype => 'time' },
-{ aggfnoid => 'min(timetz)', aggtransfn => 'timetz_smaller',
+{ aggfnoid => 'min(time)', aggtransfn => 'time_smaller',
+  aggcombinefn => 'time_smaller', aggsortop => '<(time,time)',
+  aggtranstype => 'time',
+  partialaggfn => 'min_p_time', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_timetz', aggtransfn => 'timetz_smaller',
   aggcombinefn => 'timetz_smaller', aggsortop => '<(timetz,timetz)',
   aggtranstype => 'timetz' },
-{ aggfnoid => 'min(money)', aggtransfn => 'cashsmaller',
+{ aggfnoid => 'min(timetz)', aggtransfn => 'timetz_smaller',
+  aggcombinefn => 'timetz_smaller', aggsortop => '<(timetz,timetz)',
+  aggtranstype => 'timetz',
+  partialaggfn => 'min_p_timetz', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_money', aggtransfn => 'cashsmaller',
   aggcombinefn => 'cashsmaller', aggsortop => '<(money,money)',
   aggtranstype => 'money' },
-{ aggfnoid => 'min(timestamp)', aggtransfn => 'timestamp_smaller',
+{ aggfnoid => 'min(money)', aggtransfn => 'cashsmaller',
+  aggcombinefn => 'cashsmaller', aggsortop => '<(money,money)',
+  aggtranstype => 'money',
+  partialaggfn => 'min_p_money', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_timestamp', aggtransfn => 'timestamp_smaller',
   aggcombinefn => 'timestamp_smaller', aggsortop => '<(timestamp,timestamp)',
   aggtranstype => 'timestamp' },
-{ aggfnoid => 'min(timestamptz)', aggtransfn => 'timestamptz_smaller',
+{ aggfnoid => 'min(timestamp)', aggtransfn => 'timestamp_smaller',
+  aggcombinefn => 'timestamp_smaller', aggsortop => '<(timestamp,timestamp)',
+  aggtranstype => 'timestamp',
+  partialaggfn => 'min_p_timestamp', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_timestamptz', aggtransfn => 'timestamptz_smaller',
   aggcombinefn => 'timestamptz_smaller',
   aggsortop => '<(timestamptz,timestamptz)', aggtranstype => 'timestamptz' },
-{ aggfnoid => 'min(interval)', aggtransfn => 'interval_smaller',
+{ aggfnoid => 'min(timestamptz)', aggtransfn => 'timestamptz_smaller',
+  aggcombinefn => 'timestamptz_smaller',
+  aggsortop => '<(timestamptz,timestamptz)', aggtranstype => 'timestamptz',
+  partialaggfn => 'min_p_timestamptz', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_interval', aggtransfn => 'interval_smaller',
   aggcombinefn => 'interval_smaller', aggsortop => '<(interval,interval)',
   aggtranstype => 'interval' },
-{ aggfnoid => 'min(text)', aggtransfn => 'text_smaller',
+{ aggfnoid => 'min(interval)', aggtransfn => 'interval_smaller',
+  aggcombinefn => 'interval_smaller', aggsortop => '<(interval,interval)',
+  aggtranstype => 'interval',
+  partialaggfn => 'min_p_interval', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_text', aggtransfn => 'text_smaller',
   aggcombinefn => 'text_smaller', aggsortop => '<(text,text)',
   aggtranstype => 'text' },
-{ aggfnoid => 'min(numeric)', aggtransfn => 'numeric_smaller',
+{ aggfnoid => 'min(text)', aggtransfn => 'text_smaller',
+  aggcombinefn => 'text_smaller', aggsortop => '<(text,text)',
+  aggtranstype => 'text',
+  partialaggfn => 'min_p_text', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_numeric', aggtransfn => 'numeric_smaller',
   aggcombinefn => 'numeric_smaller', aggsortop => '<(numeric,numeric)',
   aggtranstype => 'numeric' },
-{ aggfnoid => 'min(anyarray)', aggtransfn => 'array_smaller',
+{ aggfnoid => 'min(numeric)', aggtransfn => 'numeric_smaller',
+  aggcombinefn => 'numeric_smaller', aggsortop => '<(numeric,numeric)',
+  aggtranstype => 'numeric',
+  partialaggfn => 'min_p_numeric', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_anyarray', aggtransfn => 'array_smaller',
   aggcombinefn => 'array_smaller', aggsortop => '<(anyarray,anyarray)',
   aggtranstype => 'anyarray' },
-{ aggfnoid => 'min(bpchar)', aggtransfn => 'bpchar_smaller',
+{ aggfnoid => 'min(anyarray)', aggtransfn => 'array_smaller',
+  aggcombinefn => 'array_smaller', aggsortop => '<(anyarray,anyarray)',
+  aggtranstype => 'anyarray',
+  partialaggfn => 'min_p_anyarray', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_bpchar', aggtransfn => 'bpchar_smaller',
   aggcombinefn => 'bpchar_smaller', aggsortop => '<(bpchar,bpchar)',
   aggtranstype => 'bpchar' },
+{ aggfnoid => 'min(bpchar)', aggtransfn => 'bpchar_smaller',
+  aggcombinefn => 'bpchar_smaller', aggsortop => '<(bpchar,bpchar)',
+  aggtranstype => 'bpchar',
+  partialaggfn => 'min_p_bpchar', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_tid', aggtransfn => 'tidsmaller',
+  aggcombinefn => 'tidsmaller', aggsortop => '<(tid,tid)',
+  aggtranstype => 'tid'},
 { aggfnoid => 'min(tid)', aggtransfn => 'tidsmaller',
   aggcombinefn => 'tidsmaller', aggsortop => '<(tid,tid)',
-  aggtranstype => 'tid' },
-{ aggfnoid => 'min(anyenum)', aggtransfn => 'enum_smaller',
+  aggtranstype => 'tid',
+  partialaggfn => 'min_p_tid', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_anyenum', aggtransfn => 'enum_smaller',
   aggcombinefn => 'enum_smaller', aggsortop => '<(anyenum,anyenum)',
   aggtranstype => 'anyenum' },
-{ aggfnoid => 'min(inet)', aggtransfn => 'network_smaller',
+{ aggfnoid => 'min(anyenum)', aggtransfn => 'enum_smaller',
+  aggcombinefn => 'enum_smaller', aggsortop => '<(anyenum,anyenum)',
+  aggtranstype => 'anyenum',
+  partialaggfn => 'min_p_anyenum', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_inet', aggtransfn => 'network_smaller',
   aggcombinefn => 'network_smaller', aggsortop => '<(inet,inet)',
   aggtranstype => 'inet' },
-{ aggfnoid => 'min(pg_lsn)', aggtransfn => 'pg_lsn_smaller',
+{ aggfnoid => 'min(inet)', aggtransfn => 'network_smaller',
+  aggcombinefn => 'network_smaller', aggsortop => '<(inet,inet)',
+  aggtranstype => 'inet',
+  partialaggfn => 'min_p_inet', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_pg_lsn', aggtransfn => 'pg_lsn_smaller',
   aggcombinefn => 'pg_lsn_smaller', aggsortop => '<(pg_lsn,pg_lsn)',
   aggtranstype => 'pg_lsn' },
-{ aggfnoid => 'min(xid8)', aggtransfn => 'xid8_smaller',
+{ aggfnoid => 'min(pg_lsn)', aggtransfn => 'pg_lsn_smaller',
+  aggcombinefn => 'pg_lsn_smaller', aggsortop => '<(pg_lsn,pg_lsn)',
+  aggtranstype => 'pg_lsn',
+  partialaggfn => 'min_p_pg_lsn', partialagg_minversion => '160000' },
+{ aggfnoid => 'min_p_xid8', aggtransfn => 'xid8_smaller',
   aggcombinefn => 'xid8_smaller', aggsortop => '<(xid8,xid8)',
   aggtranstype => 'xid8' },
+{ aggfnoid => 'min(xid8)', aggtransfn => 'xid8_smaller',
+  aggcombinefn => 'xid8_smaller', aggsortop => '<(xid8,xid8)',
+  aggtranstype => 'xid8',
+  partialaggfn => 'min_p_xid8', partialagg_minversion => '160000' },
 
 # count
+{ aggfnoid => 'count_p_any', aggtransfn => 'int8inc_any',
+  aggcombinefn => 'int8pl', aggtranstype => 'int8',
+  agginitval => '0' },
 { 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',
+  partialaggfn => 'count_p_any', partialagg_minversion => '160000' },
+{ aggfnoid => 'count_p', aggtransfn => 'int8inc', aggcombinefn => 'int8pl',
+  aggtranstype => 'int8', agginitval => '0' },
 { aggfnoid => 'count()', aggtransfn => 'int8inc', aggcombinefn => 'int8pl',
   aggmtransfn => 'int8inc', aggminvtransfn => 'int8dec', aggtranstype => 'int8',
-  aggmtranstype => 'int8', agginitval => '0', aggminitval => '0' },
+  aggmtranstype => 'int8', agginitval => '0', aggminitval => '0',
+  partialaggfn => 'count_p', partialagg_minversion => '160000' },
 
 # var_pop
 { aggfnoid => 'var_pop(int8)', aggtransfn => 'int8_accum',
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 593da9f76a..1b7bac0fa6 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -55,6 +55,12 @@ 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		partialaggfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
+
+	/* minimum PostgreSQL's version which has compatible partialaggfn */
+	int32		partialagg_minversion BKI_DEFAULT(0);
+
 	/* forward function for moving-aggregate mode (0 if none) */
 	regproc		aggmtransfn BKI_DEFAULT(-) BKI_LOOKUP_OPT(pg_proc);
 
@@ -141,6 +147,9 @@ DECLARE_UNIQUE_INDEX_PKEY(pg_aggregate_fnoid_index, 2650, AggregateFnoidIndexId,
 #define AGGMODIFY_SHAREABLE			's'
 #define AGGMODIFY_READ_WRITE		'w'
 
+/* Symbolic value for default partialagg_minversion */
+#define	PARTIALAGG_MINVERSION_DEFAULT	0
+
 #endif							/* EXPOSE_TO_CLIENT_CODE */
 
 
@@ -164,6 +173,7 @@ extern ObjectAddress AggregateCreate(const char *aggName,
 									 List *aggmtransfnName,
 									 List *aggminvtransfnName,
 									 List *aggmfinalfnName,
+									 List *aggpartialfnName,
 									 bool finalfnExtraArgs,
 									 bool mfinalfnExtraArgs,
 									 char finalfnModify,
@@ -173,6 +183,7 @@ extern ObjectAddress AggregateCreate(const char *aggName,
 									 int32 aggTransSpace,
 									 Oid aggmTransType,
 									 int32 aggmTransSpace,
+									 int32 partialaggMinversion,
 									 const char *agginitval,
 									 const char *aggminitval,
 									 char proparallel);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index fd2559442e..92c5bf6a82 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6490,197 +6490,389 @@
   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 => '13500',
+  descr => 'the partial average (arithmetic mean) as numeric of all bigint values',
+  proname => 'avg_p_int8', prokind => 'a', proisstrict => 'f', prorettype => 'bytea',
+  proargtypes => 'int8', 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 => '13501',
+  descr => 'the partial average (arithmetic mean) as numeric of all integer values',
+  proname => 'avg_p_int4', prokind => 'a', proisstrict => 'f', prorettype => '_int8',
+  proargtypes => 'int4', 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 => '13502',
+  descr => 'the partial average (arithmetic mean) as numeric of all smallint values',
+  proname => 'avg_p_int2', prokind => 'a', proisstrict => 'f', prorettype => '_int8',
+  proargtypes => 'int2', 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 => '13503',
+  descr => 'the partial average (arithmetic mean) as numeric of all numeric values',
+  proname => 'avg_p_numeric', prokind => 'a', proisstrict => 'f', prorettype => 'bytea',
+  proargtypes => 'numeric', 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 => '13504',
+  descr => 'the partial average (arithmetic mean) as float8 of all float4 values',
+  proname => 'avg_p_float4', prokind => 'a', proisstrict => 'f', prorettype => '_float8',
+  proargtypes => 'float4', 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 => '13505',
+  descr => 'the partial average (arithmetic mean) as float8 of all float8 values',
+  proname => 'avg_p_float8', prokind => 'a', proisstrict => 'f', prorettype => '_float8',
+  proargtypes => 'float8', 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 => '13506',
+  descr => 'the partial average (arithmetic mean) as interval of all interval values',
+  proname => 'avg_p_interval', prokind => 'a', proisstrict => 'f',
+  prorettype => '_interval', proargtypes => 'interval',
+  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' },
+{ oid => '13507', descr => 'partial sum as numeric across all bigint input values',
+  proname => 'sum_p_int8', prokind => 'a', proisstrict => 'f', prorettype => 'bytea',
+  proargtypes => 'int8', prosrc => 'aggregate_dummy' },
 { oid => '2108', descr => 'sum as bigint across all integer input values',
   proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'int8',
   proargtypes => 'int4', prosrc => 'aggregate_dummy' },
+{ oid => '13508', descr => 'partial sum as bigint across all integer input values',
+  proname => 'sum_p_int4', prokind => 'a', proisstrict => 'f', prorettype => 'int8',
+  proargtypes => 'int4', prosrc => 'aggregate_dummy' },
 { oid => '2109', descr => 'sum as bigint across all smallint input values',
   proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'int8',
   proargtypes => 'int2', prosrc => 'aggregate_dummy' },
+{ oid => '13509', descr => 'partial sum as bigint across all smallint input values',
+  proname => 'sum_p_int2', prokind => 'a', proisstrict => 'f', prorettype => 'int8',
+  proargtypes => 'int2', prosrc => 'aggregate_dummy' },
 { oid => '2110', descr => 'sum as float4 across all float4 input values',
   proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'float4',
   proargtypes => 'float4', prosrc => 'aggregate_dummy' },
+{ oid => '13510', descr => 'partial sum as float4 across all float4 input values',
+  proname => 'sum_p_float4', prokind => 'a', proisstrict => 'f', prorettype => 'float4',
+  proargtypes => 'float4', prosrc => 'aggregate_dummy' },
 { oid => '2111', descr => 'sum as float8 across all float8 input values',
   proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'float8',
   proargtypes => 'float8', prosrc => 'aggregate_dummy' },
+{ oid => '13511', descr => 'partial sum as float8 across all float8 input values',
+  proname => 'sum_p_float8', prokind => 'a', proisstrict => 'f', prorettype => 'float8',
+  proargtypes => 'float8', prosrc => 'aggregate_dummy' },
 { oid => '2112', descr => 'sum as money across all money input values',
   proname => 'sum', prokind => 'a', proisstrict => 'f', prorettype => 'money',
   proargtypes => 'money', prosrc => 'aggregate_dummy' },
+{ oid => '13512', descr => 'partial sum as money across all money input values',
+  proname => 'sum_p_money', prokind => 'a', proisstrict => 'f', prorettype => 'money',
+  proargtypes => 'money', prosrc => 'aggregate_dummy' },
 { oid => '2113', descr => 'sum as interval across all interval input values',
   proname => 'sum', prokind => 'a', proisstrict => 'f',
   prorettype => 'interval', proargtypes => 'interval',
   prosrc => 'aggregate_dummy' },
+{ oid => '13513', descr => 'partial sum as interval across all interval input values',
+  proname => 'sum_p_interval', prokind => 'a', proisstrict => 'f',
+  prorettype => 'interval', proargtypes => 'interval',
+  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' },
+{ oid => '13514', descr => 'partial sum as numeric across all numeric input values',
+  proname => 'sum_p_numeric', prokind => 'a', proisstrict => 'f', prorettype => 'bytea',
+  proargtypes => 'numeric', prosrc => 'aggregate_dummy' },
 
 { oid => '2115', descr => 'maximum value of all bigint input values',
   proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'int8',
   proargtypes => 'int8', prosrc => 'aggregate_dummy' },
+{ oid => '13515', descr => 'maximum value of all bigint input values',
+  proname => 'max_p_int8', prokind => 'a', proisstrict => 'f', prorettype => 'int8',
+  proargtypes => 'int8', prosrc => 'aggregate_dummy' },
 { oid => '2116', descr => 'maximum value of all integer input values',
   proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'int4',
   proargtypes => 'int4', prosrc => 'aggregate_dummy' },
+{ oid => '13516', descr => 'maximum value of all integer input values',
+  proname => 'max_p_int4', prokind => 'a', proisstrict => 'f', prorettype => 'int4',
+  proargtypes => 'int4', prosrc => 'aggregate_dummy' },
 { oid => '2117', descr => 'maximum value of all smallint input values',
   proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'int2',
   proargtypes => 'int2', prosrc => 'aggregate_dummy' },
+{ oid => '13517', descr => 'maximum value of all smallint input values',
+  proname => 'max_p_int2', prokind => 'a', proisstrict => 'f', prorettype => 'int2',
+  proargtypes => 'int2', prosrc => 'aggregate_dummy' },
 { oid => '2118', descr => 'maximum value of all oid input values',
   proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'oid',
   proargtypes => 'oid', prosrc => 'aggregate_dummy' },
+{ oid => '13518', descr => 'maximum value of all oid input values',
+  proname => 'max_p_oid', prokind => 'a', proisstrict => 'f', prorettype => 'oid',
+  proargtypes => 'oid', prosrc => 'aggregate_dummy' },
 { oid => '2119', descr => 'maximum value of all float4 input values',
   proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'float4',
   proargtypes => 'float4', prosrc => 'aggregate_dummy' },
+{ oid => '13519', descr => 'maximum value of all float4 input values',
+  proname => 'max_p_float4', prokind => 'a', proisstrict => 'f', prorettype => 'float4',
+  proargtypes => 'float4', prosrc => 'aggregate_dummy' },
 { oid => '2120', descr => 'maximum value of all float8 input values',
   proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'float8',
   proargtypes => 'float8', prosrc => 'aggregate_dummy' },
+{ oid => '13520', descr => 'maximum value of all float8 input values',
+  proname => 'max_p_floa8', prokind => 'a', proisstrict => 'f', prorettype => 'float8',
+  proargtypes => 'float8', prosrc => 'aggregate_dummy' },
 { oid => '2122', descr => 'maximum value of all date input values',
   proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'date',
   proargtypes => 'date', prosrc => 'aggregate_dummy' },
+{ oid => '13521', descr => 'maximum value of all date input values',
+  proname => 'max_p_date', prokind => 'a', proisstrict => 'f', prorettype => 'date',
+  proargtypes => 'date', prosrc => 'aggregate_dummy' },
 { oid => '2123', descr => 'maximum value of all time input values',
   proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'time',
   proargtypes => 'time', prosrc => 'aggregate_dummy' },
+{ oid => '13522', descr => 'maximum value of all time input values',
+  proname => 'max_p_time', prokind => 'a', proisstrict => 'f', prorettype => 'time',
+  proargtypes => 'time', prosrc => 'aggregate_dummy' },
 { oid => '2124',
   descr => 'maximum value of all time with time zone input values',
   proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'timetz',
   proargtypes => 'timetz', prosrc => 'aggregate_dummy' },
+{ oid => '13523',
+  descr => 'maximum value of all time with time zone input values',
+  proname => 'max_p_timetz', prokind => 'a', proisstrict => 'f', prorettype => 'timetz',
+  proargtypes => 'timetz', prosrc => 'aggregate_dummy' },
 { oid => '2125', descr => 'maximum value of all money input values',
   proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'money',
   proargtypes => 'money', prosrc => 'aggregate_dummy' },
+{ oid => '13524', descr => 'maximum value of all money input values',
+  proname => 'max_p_money', prokind => 'a', proisstrict => 'f', prorettype => 'money',
+  proargtypes => 'money', prosrc => 'aggregate_dummy' },
 { oid => '2126', descr => 'maximum value of all timestamp input values',
   proname => 'max', prokind => 'a', proisstrict => 'f',
   prorettype => 'timestamp', proargtypes => 'timestamp',
   prosrc => 'aggregate_dummy' },
+{ oid => '13525', descr => 'maximum value of all timestamp input values',
+  proname => 'max_p_timestamp', prokind => 'a', proisstrict => 'f',
+  prorettype => 'timestamp', proargtypes => 'timestamp',
+  prosrc => 'aggregate_dummy' },
 { oid => '2127',
   descr => 'maximum value of all timestamp with time zone input values',
   proname => 'max', prokind => 'a', proisstrict => 'f',
   prorettype => 'timestamptz', proargtypes => 'timestamptz',
   prosrc => 'aggregate_dummy' },
+{ oid => '13526',
+  descr => 'maximum value of all timestamp with time zone input values',
+  proname => 'max_p_timestamptz', prokind => 'a', proisstrict => 'f',
+  prorettype => 'timestamptz', proargtypes => 'timestamptz',
+  prosrc => 'aggregate_dummy' },
 { oid => '2128', descr => 'maximum value of all interval input values',
   proname => 'max', prokind => 'a', proisstrict => 'f',
   prorettype => 'interval', proargtypes => 'interval',
   prosrc => 'aggregate_dummy' },
+{ oid => '13527', descr => 'maximum value of all interval input values',
+  proname => 'max_p_interval', prokind => 'a', proisstrict => 'f',
+  prorettype => 'interval', proargtypes => 'interval',
+  prosrc => 'aggregate_dummy' },
 { oid => '2129', descr => 'maximum value of all text input values',
   proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'text',
   proargtypes => 'text', prosrc => 'aggregate_dummy' },
+{ oid => '13528', descr => 'maximum value of all text input values',
+  proname => 'max_p_text', prokind => 'a', proisstrict => 'f', prorettype => 'text',
+  proargtypes => 'text', prosrc => 'aggregate_dummy' },
 { oid => '2130', descr => 'maximum value of all numeric input values',
   proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'numeric',
   proargtypes => 'numeric', prosrc => 'aggregate_dummy' },
+{ oid => '13529', descr => 'maximum value of all numeric input values',
+  proname => 'max_p_numeric', prokind => 'a', proisstrict => 'f', prorettype => 'numeric',
+  proargtypes => 'numeric', prosrc => 'aggregate_dummy' },
 { oid => '2050', descr => 'maximum value of all anyarray input values',
   proname => 'max', prokind => 'a', proisstrict => 'f',
   prorettype => 'anyarray', proargtypes => 'anyarray',
   prosrc => 'aggregate_dummy' },
+{ oid => '13530', descr => 'maximum value of all anyarray input values',
+  proname => 'max_p_anyarray', prokind => 'a', proisstrict => 'f',
+  prorettype => 'anyarray', proargtypes => 'anyarray',
+  prosrc => 'aggregate_dummy' },
 { oid => '2244', descr => 'maximum value of all bpchar input values',
   proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'bpchar',
   proargtypes => 'bpchar', prosrc => 'aggregate_dummy' },
+{ oid => '13531', descr => 'maximum value of all bpchar input values',
+  proname => 'max_p_bpchar', prokind => 'a', proisstrict => 'f', prorettype => 'bpchar',
+  proargtypes => 'bpchar', prosrc => 'aggregate_dummy' },
 { oid => '2797', descr => 'maximum value of all tid input values',
   proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'tid',
   proargtypes => 'tid', prosrc => 'aggregate_dummy' },
+{ oid => '13532', descr => 'maximum value of all tid input values',
+  proname => 'max_p_tid', prokind => 'a', proisstrict => 'f', prorettype => 'tid',
+  proargtypes => 'tid', prosrc => 'aggregate_dummy' },
 { oid => '3564', descr => 'maximum value of all inet input values',
   proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'inet',
   proargtypes => 'inet', prosrc => 'aggregate_dummy' },
+{ oid => '13533', descr => 'maximum value of all inet input values',
+  proname => 'max_p_inet', prokind => 'a', proisstrict => 'f', prorettype => 'inet',
+  proargtypes => 'inet', prosrc => 'aggregate_dummy' },
 { oid => '4189', descr => 'maximum value of all pg_lsn input values',
   proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'pg_lsn',
   proargtypes => 'pg_lsn', prosrc => 'aggregate_dummy' },
+{ oid => '13534', descr => 'maximum value of all pg_lsn input values',
+  proname => 'max_p_pg_lsn', prokind => 'a', proisstrict => 'f', prorettype => 'pg_lsn',
+  proargtypes => 'pg_lsn', prosrc => 'aggregate_dummy' },
 { oid => '5099', descr => 'maximum value of all xid8 input values',
   proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'xid8',
   proargtypes => 'xid8', prosrc => 'aggregate_dummy' },
+{ oid => '13535', descr => 'maximum value of all xid8 input values',
+  proname => 'max_p_xid8', prokind => 'a', proisstrict => 'f', prorettype => 'xid8',
+  proargtypes => 'xid8', prosrc => 'aggregate_dummy' },
 
 { oid => '2131', descr => 'minimum value of all bigint input values',
   proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'int8',
   proargtypes => 'int8', prosrc => 'aggregate_dummy' },
+{ oid => '13536', descr => 'minimum value of all bigint input values',
+  proname => 'min_p_int8', prokind => 'a', proisstrict => 'f', prorettype => 'int8',
+  proargtypes => 'int8', prosrc => 'aggregate_dummy' },
 { oid => '2132', descr => 'minimum value of all integer input values',
   proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'int4',
   proargtypes => 'int4', prosrc => 'aggregate_dummy' },
+{ oid => '13537', descr => 'minimum value of all integer input values',
+  proname => 'min_p_int4', prokind => 'a', proisstrict => 'f', prorettype => 'int4',
+  proargtypes => 'int4', prosrc => 'aggregate_dummy' },
 { oid => '2133', descr => 'minimum value of all smallint input values',
   proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'int2',
   proargtypes => 'int2', prosrc => 'aggregate_dummy' },
+{ oid => '13538', descr => 'minimum value of all smallint input values',
+  proname => 'min_p_int2', prokind => 'a', proisstrict => 'f', prorettype => 'int2',
+  proargtypes => 'int2', prosrc => 'aggregate_dummy' },
 { oid => '2134', descr => 'minimum value of all oid input values',
   proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'oid',
   proargtypes => 'oid', prosrc => 'aggregate_dummy' },
+{ oid => '13539', descr => 'minimum value of all oid input values',
+  proname => 'min_p_oid', prokind => 'a', proisstrict => 'f', prorettype => 'oid',
+  proargtypes => 'oid', prosrc => 'aggregate_dummy' },
 { oid => '2135', descr => 'minimum value of all float4 input values',
   proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'float4',
   proargtypes => 'float4', prosrc => 'aggregate_dummy' },
+{ oid => '13540', descr => 'minimum value of all float4 input values',
+  proname => 'min_p_float4', prokind => 'a', proisstrict => 'f', prorettype => 'float4',
+  proargtypes => 'float4', prosrc => 'aggregate_dummy' },
 { oid => '2136', descr => 'minimum value of all float8 input values',
   proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'float8',
   proargtypes => 'float8', prosrc => 'aggregate_dummy' },
+{ oid => '13541', descr => 'minimum value of all float8 input values',
+  proname => 'min_p_float8', prokind => 'a', proisstrict => 'f', prorettype => 'float8',
+  proargtypes => 'float8', prosrc => 'aggregate_dummy' },
 { oid => '2138', descr => 'minimum value of all date input values',
   proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'date',
   proargtypes => 'date', prosrc => 'aggregate_dummy' },
+{ oid => '13542', descr => 'minimum value of all date input values',
+  proname => 'min_p_date', prokind => 'a', proisstrict => 'f', prorettype => 'date',
+  proargtypes => 'date', prosrc => 'aggregate_dummy' },
 { oid => '2139', descr => 'minimum value of all time input values',
   proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'time',
   proargtypes => 'time', prosrc => 'aggregate_dummy' },
+{ oid => '13543', descr => 'minimum value of all time input values',
+  proname => 'min_p_time', prokind => 'a', proisstrict => 'f', prorettype => 'time',
+  proargtypes => 'time', prosrc => 'aggregate_dummy' },
 { oid => '2140',
   descr => 'minimum value of all time with time zone input values',
   proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'timetz',
   proargtypes => 'timetz', prosrc => 'aggregate_dummy' },
+{ oid => '13544',
+  descr => 'minimum value of all time with time zone input values',
+  proname => 'min_p_timetz', prokind => 'a', proisstrict => 'f', prorettype => 'timetz',
+  proargtypes => 'timetz', prosrc => 'aggregate_dummy' },
 { oid => '2141', descr => 'minimum value of all money input values',
   proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'money',
   proargtypes => 'money', prosrc => 'aggregate_dummy' },
+{ oid => '13545', descr => 'minimum value of all money input values',
+  proname => 'min_p_money', prokind => 'a', proisstrict => 'f', prorettype => 'money',
+  proargtypes => 'money', prosrc => 'aggregate_dummy' },
 { oid => '2142', descr => 'minimum value of all timestamp input values',
   proname => 'min', prokind => 'a', proisstrict => 'f',
   prorettype => 'timestamp', proargtypes => 'timestamp',
   prosrc => 'aggregate_dummy' },
+{ oid => '13546', descr => 'minimum value of all timestamp input values',
+  proname => 'min_p_timestamp', prokind => 'a', proisstrict => 'f',
+  prorettype => 'timestamp', proargtypes => 'timestamp',
+  prosrc => 'aggregate_dummy' },
 { oid => '2143',
   descr => 'minimum value of all timestamp with time zone input values',
   proname => 'min', prokind => 'a', proisstrict => 'f',
   prorettype => 'timestamptz', proargtypes => 'timestamptz',
   prosrc => 'aggregate_dummy' },
+{ oid => '13547',
+  descr => 'minimum value of all timestamp with time zone input values',
+  proname => 'min_p_timestamptz', prokind => 'a', proisstrict => 'f',
+  prorettype => 'timestamptz', proargtypes => 'timestamptz',
+  prosrc => 'aggregate_dummy' },
 { oid => '2144', descr => 'minimum value of all interval input values',
   proname => 'min', prokind => 'a', proisstrict => 'f',
   prorettype => 'interval', proargtypes => 'interval',
   prosrc => 'aggregate_dummy' },
+{ oid => '13548', descr => 'minimum value of all interval input values',
+  proname => 'min_p_interval', prokind => 'a', proisstrict => 'f',
+  prorettype => 'interval', proargtypes => 'interval',
+  prosrc => 'aggregate_dummy' },
 { oid => '2145', descr => 'minimum value of all text values',
   proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'text',
   proargtypes => 'text', prosrc => 'aggregate_dummy' },
+{ oid => '13549', descr => 'minimum value of all text values',
+  proname => 'min_p_text', prokind => 'a', proisstrict => 'f', prorettype => 'text',
+  proargtypes => 'text', prosrc => 'aggregate_dummy' },
 { oid => '2146', descr => 'minimum value of all numeric input values',
   proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'numeric',
   proargtypes => 'numeric', prosrc => 'aggregate_dummy' },
+{ oid => '13550', descr => 'minimum value of all numeric input values',
+  proname => 'min_p_numeric', prokind => 'a', proisstrict => 'f', prorettype => 'numeric',
+  proargtypes => 'numeric', prosrc => 'aggregate_dummy' },
 { oid => '2051', descr => 'minimum value of all anyarray input values',
   proname => 'min', prokind => 'a', proisstrict => 'f',
   prorettype => 'anyarray', proargtypes => 'anyarray',
   prosrc => 'aggregate_dummy' },
+{ oid => '13551', descr => 'minimum value of all anyarray input values',
+  proname => 'min_p_anyarray', prokind => 'a', proisstrict => 'f',
+  prorettype => 'anyarray', proargtypes => 'anyarray',
+  prosrc => 'aggregate_dummy' },
 { oid => '2245', descr => 'minimum value of all bpchar input values',
   proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'bpchar',
   proargtypes => 'bpchar', prosrc => 'aggregate_dummy' },
+{ oid => '13552', descr => 'minimum value of all bpchar input values',
+  proname => 'min_p_bpchar', prokind => 'a', proisstrict => 'f', prorettype => 'bpchar',
+  proargtypes => 'bpchar', prosrc => 'aggregate_dummy' },
 { oid => '2798', descr => 'minimum value of all tid input values',
   proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'tid',
   proargtypes => 'tid', prosrc => 'aggregate_dummy' },
+{ oid => '13553', descr => 'minimum value of all tid input values',
+  proname => 'min_p_tid', prokind => 'a', proisstrict => 'f', prorettype => 'tid',
+  proargtypes => 'tid', prosrc => 'aggregate_dummy' },
 { oid => '3565', descr => 'minimum value of all inet input values',
   proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'inet',
   proargtypes => 'inet', prosrc => 'aggregate_dummy' },
+{ oid => '13554', descr => 'minimum value of all inet input values',
+  proname => 'min_p_inet', prokind => 'a', proisstrict => 'f', prorettype => 'inet',
+  proargtypes => 'inet', prosrc => 'aggregate_dummy' },
 { oid => '4190', descr => 'minimum value of all pg_lsn input values',
   proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'pg_lsn',
   proargtypes => 'pg_lsn', prosrc => 'aggregate_dummy' },
+{ oid => '13555', descr => 'minimum value of all pg_lsn input values',
+  proname => 'min_p_pg_lsn', prokind => 'a', proisstrict => 'f', prorettype => 'pg_lsn',
+  proargtypes => 'pg_lsn', prosrc => 'aggregate_dummy' },
 { oid => '5100', descr => 'minimum value of all xid8 input values',
   proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'xid8',
   proargtypes => 'xid8', prosrc => 'aggregate_dummy' },
+{ oid => '13556', descr => 'minimum value of all xid8 input values',
+  proname => 'min_p_xid8', prokind => 'a', proisstrict => 'f', prorettype => 'xid8',
+  proargtypes => 'xid8', prosrc => 'aggregate_dummy' },
 
 # count has two forms: count(any) and count(*)
 { oid => '2147',
@@ -6688,10 +6880,19 @@
   proname => 'count', prosupport => 'int8inc_support', prokind => 'a',
   proisstrict => 'f', prorettype => 'int8', proargtypes => 'any',
   prosrc => 'aggregate_dummy' },
+{ oid => '13557',
+  descr => 'partial number of input rows for which the input expression is not null',
+  proname => 'count_p_any', prosupport => 'int8inc_support', prokind => 'a',
+  proisstrict => 'f', prorettype => 'int8', proargtypes => 'any',
+  prosrc => 'aggregate_dummy' },
 { oid => '2803', descr => 'number of input rows',
   proname => 'count', prosupport => 'int8inc_support', prokind => 'a',
   proisstrict => 'f', prorettype => 'int8', proargtypes => '',
   prosrc => 'aggregate_dummy' },
+{ oid => '13558', descr => 'partial number of input rows',
+  proname => 'count_p', prosupport => 'int8inc_support', prokind => 'a',
+  proisstrict => 'f', prorettype => 'int8', proargtypes => '',
+  prosrc => 'aggregate_dummy' },
 { oid => '6236', descr => 'planner support for count run condition',
   proname => 'int8inc_support', prorettype => 'internal',
   proargtypes => 'internal', prosrc => 'int8inc_support' },
@@ -9081,9 +9282,15 @@
 { oid => '3526', descr => 'maximum value of all enum input values',
   proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'anyenum',
   proargtypes => 'anyenum', prosrc => 'aggregate_dummy' },
+{ oid => '13559', descr => 'maximum value of all enum input values',
+  proname => 'max_p_anyenum', prokind => 'a', proisstrict => 'f', prorettype => 'anyenum',
+  proargtypes => 'anyenum', prosrc => 'aggregate_dummy' },
 { oid => '3527', descr => 'minimum value of all enum input values',
   proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'anyenum',
   proargtypes => 'anyenum', prosrc => 'aggregate_dummy' },
+{ oid => '13560', descr => 'minimum value of all enum input values',
+  proname => 'min_p_anyenum', prokind => 'a', proisstrict => 'f', prorettype => 'anyenum',
+  proargtypes => 'anyenum', prosrc => 'aggregate_dummy' },
 { oid => '3528', descr => 'first value of the input enum type',
   proname => 'enum_first', proisstrict => 'f', provolatile => 's',
   prorettype => 'anyenum', proargtypes => 'anyenum', prosrc => 'enum_first' },
diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out
index 215eb899be..49f2c9bc35 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 {partialaggfn} => 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/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 330eb0f765..a3ddf2ff84 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -1722,14 +1722,58 @@ SELECT DISTINCT proname, oprname
 FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p
 WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid
 ORDER BY 1, 2;
- proname  | oprname 
-----------+---------
- bool_and | <
- bool_or  | >
- every    | <
- max      | >
- min      | <
-(5 rows)
+      proname      | oprname 
+-------------------+---------
+ bool_and          | <
+ bool_or           | >
+ every             | <
+ max               | >
+ max_p_anyarray    | >
+ max_p_anyenum     | >
+ max_p_bpchar      | >
+ max_p_date        | >
+ max_p_floa8       | >
+ max_p_float4      | >
+ max_p_inet        | >
+ max_p_int2        | >
+ max_p_int4        | >
+ max_p_int8        | >
+ max_p_interval    | >
+ max_p_money       | >
+ max_p_numeric     | >
+ max_p_oid         | >
+ max_p_pg_lsn      | >
+ max_p_text        | >
+ max_p_tid         | >
+ max_p_time        | >
+ max_p_timestamp   | >
+ max_p_timestamptz | >
+ max_p_timetz      | >
+ max_p_xid8        | >
+ min               | <
+ min_p_anyarray    | <
+ min_p_anyenum     | <
+ min_p_bpchar      | <
+ min_p_date        | <
+ min_p_float4      | <
+ min_p_float8      | <
+ min_p_inet        | <
+ min_p_int2        | <
+ min_p_int4        | <
+ min_p_int8        | <
+ min_p_interval    | <
+ min_p_money       | <
+ min_p_numeric     | <
+ min_p_oid         | <
+ min_p_pg_lsn      | <
+ min_p_text        | <
+ min_p_tid         | <
+ min_p_time        | <
+ min_p_timestamp   | <
+ min_p_timestamptz | <
+ min_p_timetz      | <
+ min_p_xid8        | <
+(49 rows)
 
 -- Check datatypes match
 SELECT a.aggfnoid::oid, o.oid
@@ -1762,14 +1806,58 @@ WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND
     amopopr = o.oid AND
     amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree')
 ORDER BY 1, 2;
- proname  | oprname | amopstrategy 
-----------+---------+--------------
- bool_and | <       |            1
- bool_or  | >       |            5
- every    | <       |            1
- max      | >       |            5
- min      | <       |            1
-(5 rows)
+      proname      | oprname | amopstrategy 
+-------------------+---------+--------------
+ bool_and          | <       |            1
+ bool_or           | >       |            5
+ every             | <       |            1
+ max               | >       |            5
+ max_p_anyarray    | >       |            5
+ max_p_anyenum     | >       |            5
+ max_p_bpchar      | >       |            5
+ max_p_date        | >       |            5
+ max_p_floa8       | >       |            5
+ max_p_float4      | >       |            5
+ max_p_inet        | >       |            5
+ max_p_int2        | >       |            5
+ max_p_int4        | >       |            5
+ max_p_int8        | >       |            5
+ max_p_interval    | >       |            5
+ max_p_money       | >       |            5
+ max_p_numeric     | >       |            5
+ max_p_oid         | >       |            5
+ max_p_pg_lsn      | >       |            5
+ max_p_text        | >       |            5
+ max_p_tid         | >       |            5
+ max_p_time        | >       |            5
+ max_p_timestamp   | >       |            5
+ max_p_timestamptz | >       |            5
+ max_p_timetz      | >       |            5
+ max_p_xid8        | >       |            5
+ min               | <       |            1
+ min_p_anyarray    | <       |            1
+ min_p_anyenum     | <       |            1
+ min_p_bpchar      | <       |            1
+ min_p_date        | <       |            1
+ min_p_float4      | <       |            1
+ min_p_float8      | <       |            1
+ min_p_inet        | <       |            1
+ min_p_int2        | <       |            1
+ min_p_int4        | <       |            1
+ min_p_int8        | <       |            1
+ min_p_interval    | <       |            1
+ min_p_money       | <       |            1
+ min_p_numeric     | <       |            1
+ min_p_oid         | <       |            1
+ min_p_pg_lsn      | <       |            1
+ min_p_text        | <       |            1
+ min_p_tid         | <       |            1
+ min_p_time        | <       |            1
+ min_p_timestamp   | <       |            1
+ min_p_timestamptz | <       |            1
+ min_p_timetz      | <       |            1
+ min_p_xid8        | <       |            1
+(49 rows)
 
 -- Check that there are not aggregates with the same name and different
 -- numbers of arguments.  While not technically wrong, we have a project policy
-- 
2.30.1

