public inbox for [email protected]
help / color / mirror / Atom feedFrom: [email protected] <[email protected]>
To: Alexander Pyhalov <[email protected]>
To: Tomas Vondra <[email protected]>
To: PostgreSQL-development <[email protected]>
Cc: Andres Freund <[email protected]>
Cc: Zhihong Yu <[email protected]>
Cc: Julien Rouhaud <[email protected]>
Cc: Daniel Gustafsson <[email protected]>
Cc: Ilya Gladyshev <[email protected]>
Cc: [email protected] <[email protected]>
Subject: RE: Partial aggregates pushdown
Date: Tue, 22 Nov 2022 01:01:55 +0000
Message-ID: <OS3PR01MB66607C2ABBDAEE150F32E24C950D9@OS3PR01MB6660.jpnprd01.prod.outlook.com> (raw)
In-Reply-To: <OS3PR01MB66604C11E390FECBAA1B6518959A9@OS3PR01MB6660.jpnprd01.prod.outlook.com>
References: <[email protected]>
<[email protected]>
<[email protected]>
<[email protected]>
<[email protected]>
<20220114121653.mjzqelwgnzwqhkoa@jrouhaud>
<[email protected]>
<CALNJ-vSm6z6Lg1CgxbGUG6=xP3n+tYC_XGGUm33b9g98Z3bF-g@mail.gmail.com>
<[email protected]>
<[email protected]>
<[email protected]>
<[email protected]>
<[email protected]>
<OS3PR01MB66604C11E390FECBAA1B6518959A9@OS3PR01MB6660.jpnprd01.prod.outlook.com>
Hi Mr.Vondra, Mr.Pyhalov, Everyone.
I discussed with Mr.Pyhalov about the above draft by directly sending mail to
him(outside of pgsql-hackers). Mr.Pyhalov allowed me to update his patch
along with the above draft. So I update Mr.Pyhalov's patch v10.
I wrote my patch for discussion.
My patch passes regression tests which contains additional basic postgres_fdw tests
for my patch's feature. But my patch doesn't contain sufficient documents and tests.
If reviewers accept my approach, I will add documents and tests to my patch.
The following is a my patch's readme.
# I simplified the above draft.
--readme of my patch
1. interface
1) pg_aggregate
There are the following additional columns.
a) partialaggfn
data type : regproc.
default value: zero(means invalid).
description : This field refers to the special aggregate function(then we call
this partialaggfunc)
corresponding to aggregation function(then we call src) which has aggfnoid.
partialaggfunc is used for partial aggregation pushdown by postgres_fdw.
The followings are differences between the src and the special aggregate function.
difference1) result type
The result type is same as the src's transtype if the src's transtype
is not internal.
Otherwise the result type is bytea.
difference2) final func
The final func does not exist if the src's transtype is not internal.
Otherwize the final func returns serialized value.
For example, there is a partialaggfunc avg_p_int4 which corresponds to avg(int4)
whose aggtranstype is _int4.
The result value of avg_p_int4 is a float8 array which consists of count and
summation. avg_p_int4 does not have finalfunc.
For another example, there is a partialaggfunc avg_p_int8 which corresponds to
avg(int8) whose aggtranstype is internal.
The result value of avg_p_int8 is a bytea serialized array which consists of count
and summation. avg_p_int8 has finalfunc int8_avg_serialize which is serialize function
of avg(int8). This field is zero if there is no partialaggfunc.
b) partialagg_minversion
data type : int4.
default value: zero(means current version).
description : This field is the minimum PostgreSQL server version which has
partialaggfunc. This field is used for checking compatibility of partialaggfunc.
The above fields are valid in tuples for builtin avg, sum, min, max, count.
There are additional records which correspond to partialaggfunc for avg, sum, min, max,
count.
2) pg_proc
There are additional records which correspond to partialaggfunc for avg, sum, min, max,
count.
3) postgres_fdw
postgres_fdw has an additional foreign server option server_version. server_version is
integer value which means remote server version number. Default value of server_version
is zero. server_version is used for checking compatibility of partialaggfunc.
2. feature
postgres_fdw can pushdown partial aggregation of avg, sum, min, max, count.
Partial aggregation pushdown is fine when the following two conditions are both true.
condition1) partialaggfn is valid.
condition2) server_version is not less than partialagg_minversion
postgres_fdw executes pushdown the patialaggfunc instead of a src.
For example, we issue "select avg_p_int4(c) from t" instead of "select avg(c) from t"
in the above example.
postgres_fdw can pushdown every aggregate function which supports partial aggregation
if you add a partialaggfunc corresponding to the aggregate function by create aggregate
command.
3. difference between my patch and Mr.Pyhalov's v10 patch.
1) In my patch postgres_fdw can pushdown partial aggregation of avg
2) In my patch postgres_fdw can pushdown every aggregate function which supports partial
aggregation if you add a partialaggfunc corresponding to the aggregate function.
4. sample commands in psql
\c postgres
drop database tmp;
create database tmp;
\c tmp
create extension postgres_fdw;
create server server_01 foreign data wrapper postgres_fdw options(host 'localhost', dbname 'tmp', server_version '160000', async_capable 'true');
create user mapping for postgres server server_01 options(user 'postgres', password 'postgres');
create server server_02 foreign data wrapper postgres_fdw options(host 'localhost', dbname 'tmp', server_version '160000', async_capable 'true');
create user mapping for postgres server server_02 options(user 'postgres', password 'postgres');
create table t(dt timestamp, id int4, name text, total int4, val float4, type int4, span interval) partition by list (type);
create table t1(dt timestamp, id int4, name text, total int4, val float4, type int4, span interval);
create table t2(dt timestamp, id int4, name text, total int4, val float4, type int4, span interval);
truncate table t1;
truncate table t2;
insert into t1 select timestamp'2020-01-01' + cast(t || ' seconds' as interval), t % 100, 'hoge' || t, 1, 1.1, 1, cast('1 seconds' as interval) from generate_series(1, 100000, 1) t;
insert into t1 select timestamp'2020-01-01' + cast(t || ' seconds' as interval), t % 100, 'hoge' || t, 2, 2.1, 1, cast('2 seconds' as interval) from generate_series(1, 100000, 1) t;
insert into t2 select timestamp'2020-01-01' + cast(t || ' seconds' as interval), t % 100, 'hoge' || t, 1, 1.1, 2, cast('1 seconds' as interval) from generate_series(1, 100000, 1) t;
insert into t2 select timestamp'2020-01-01' + cast(t || ' seconds' as interval), t % 100, 'hoge' || t, 2, 2.1, 2, cast('2 seconds' as interval) from generate_series(1, 100000, 1) t;
create foreign table f_t1 partition of t for values in (1) server server_01 options(table_name 't1');
create foreign table f_t2 partition of t for values in (2) server server_02 options(table_name 't2');
set enable_partitionwise_aggregate = on;
explain (verbose, costs off) select avg(total::int4), avg(total::int8) from t;
select avg(total::int4), avg(total::int8) from t;
Sincerely yours,
Yuuki Fujii
--
Yuuki Fujii
Information Technology R&D Center Mitsubishi Electric Corporation
Attachments:
[application/octet-stream] 0001-Partial-aggregates-push-down-v11.patch (107.1K, ../OS3PR01MB66607C2ABBDAEE150F32E24C950D9@OS3PR01MB6660.jpnprd01.prod.outlook.com/2-0001-Partial-aggregates-push-down-v11.patch)
download | inline diff:
From dcdf4d107dc1d062f54e91abfac7099956b17988 Mon Sep 17 00:00:00 2001
From: Yuki Fujii <[email protected]>
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
view thread (46+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]
Subject: RE: Partial aggregates pushdown
In-Reply-To: <OS3PR01MB66607C2ABBDAEE150F32E24C950D9@OS3PR01MB6660.jpnprd01.prod.outlook.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox