Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit59b71c6

Browse files
committed
Fix handling of NULLs returned by aggregate combine functions.
When strict aggregate combine functions, used in multi-stage/parallelaggregation, returned NULL, we didn't check for that, invoking thecombine function with NULL the next round, despite it being strict.The equivalent code invoking normal transition functions has a checkfor that situation, which did not get copied ina7de3dc. Fix thebug by adding the equivalent check.Based on a quick look I could not find any strict combine functions incore actually returning NULL, and it doesn't seem very likely externalusers have done so. So this isn't likely to have caused issues inpractice.Add tests verifying transition / combine functions returning NULL istested.Reported-By: Andres FreundAuthor: Andres FreundDiscussion:https://postgr.es/m/20171121033642.7xvmjqrl4jdaaat3@alap3.anarazel.deBackpatch: 9.6, where parallel aggregation was introduced
1 parent07bd77b commit59b71c6

File tree

3 files changed

+145
-0
lines changed

3 files changed

+145
-0
lines changed

‎src/backend/executor/nodeAgg.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,6 +1246,17 @@ advance_combine_function(AggState *aggstate,
12461246
pergroupstate->noTransValue= false;
12471247
return;
12481248
}
1249+
1250+
if (pergroupstate->transValueIsNull)
1251+
{
1252+
/*
1253+
* Don't call a strict function with NULL inputs. Note it is
1254+
* possible to get here despite the above tests, if the combinefn
1255+
* is strict *and* returned a NULL on a prior cycle. If that
1256+
* happens we will propagate the NULL all the way to the end.
1257+
*/
1258+
return;
1259+
}
12491260
}
12501261

12511262
/* We run the combine functions in per-input-tuple memory context */

‎src/test/regress/expected/aggregates.out

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1993,3 +1993,74 @@ NOTICE: sum_transfn called with 4
19931993
(1 row)
19941994

19951995
rollback;
1996+
-- test that the aggregate transition logic correctly handles
1997+
-- transition / combine functions returning NULL
1998+
-- First test the case of a normal transition function returning NULL
1999+
BEGIN;
2000+
CREATE FUNCTION balkifnull(int8, int4)
2001+
RETURNS int8
2002+
STRICT
2003+
LANGUAGE plpgsql AS $$
2004+
BEGIN
2005+
IF $1 IS NULL THEN
2006+
RAISE 'erroneously called with NULL argument';
2007+
END IF;
2008+
RETURN NULL;
2009+
END$$;
2010+
CREATE AGGREGATE balk(
2011+
BASETYPE = int4,
2012+
SFUNC = balkifnull(int8, int4),
2013+
STYPE = int8,
2014+
"PARALLEL" = SAFE,
2015+
INITCOND = '0');
2016+
SELECT balk(1) FROM tenk1;
2017+
balk
2018+
------
2019+
2020+
(1 row)
2021+
2022+
ROLLBACK;
2023+
-- Secondly test the case of a parallel aggregate combiner function
2024+
-- returning NULL. For that use normal transition function, but a
2025+
-- combiner function returning NULL.
2026+
BEGIN ISOLATION LEVEL REPEATABLE READ;
2027+
CREATE FUNCTION balkifnull(int8, int8)
2028+
RETURNS int8
2029+
PARALLEL SAFE
2030+
STRICT
2031+
LANGUAGE plpgsql AS $$
2032+
BEGIN
2033+
IF $1 IS NULL THEN
2034+
RAISE 'erroneously called with NULL argument';
2035+
END IF;
2036+
RETURN NULL;
2037+
END$$;
2038+
CREATE AGGREGATE balk(
2039+
BASETYPE = int4,
2040+
SFUNC = int4_sum(int8, int4),
2041+
STYPE = int8,
2042+
COMBINEFUNC = balkifnull(int8, int8),
2043+
"PARALLEL" = SAFE,
2044+
INITCOND = '0'
2045+
);
2046+
-- force use of parallelism
2047+
ALTER TABLE tenk1 set (parallel_workers = 4);
2048+
SET LOCAL parallel_setup_cost=0;
2049+
SET LOCAL max_parallel_workers_per_gather=4;
2050+
EXPLAIN (COSTS OFF) SELECT balk(1) FROM tenk1;
2051+
QUERY PLAN
2052+
--------------------------------------------------------------------------------
2053+
Finalize Aggregate
2054+
-> Gather
2055+
Workers Planned: 4
2056+
-> Partial Aggregate
2057+
-> Parallel Index Only Scan using tenk1_thous_tenthous on tenk1
2058+
(5 rows)
2059+
2060+
SELECT balk(1) FROM tenk1;
2061+
balk
2062+
------
2063+
2064+
(1 row)
2065+
2066+
ROLLBACK;

‎src/test/regress/sql/aggregates.sql

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -843,3 +843,66 @@ create aggregate my_half_sum(int4)
843843
select my_sum(one),my_half_sum(one)from (values(1),(2),(3),(4)) t(one);
844844

845845
rollback;
846+
847+
848+
-- test that the aggregate transition logic correctly handles
849+
-- transition / combine functions returning NULL
850+
851+
-- First test the case of a normal transition function returning NULL
852+
BEGIN;
853+
CREATEFUNCTIONbalkifnull(int8, int4)
854+
RETURNS int8
855+
STRICT
856+
LANGUAGE plpgsqlAS $$
857+
BEGIN
858+
IF $1 ISNULL THEN
859+
RAISE'erroneously called with NULL argument';
860+
END IF;
861+
RETURNNULL;
862+
END$$;
863+
864+
CREATEAGGREGATEbalk(
865+
BASETYPE= int4,
866+
SFUNC= balkifnull(int8, int4),
867+
STYPE= int8,
868+
"PARALLEL"= SAFE,
869+
INITCOND='0');
870+
871+
SELECT balk(1)FROM tenk1;
872+
873+
ROLLBACK;
874+
875+
-- Secondly test the case of a parallel aggregate combiner function
876+
-- returning NULL. For that use normal transition function, but a
877+
-- combiner function returning NULL.
878+
BEGIN ISOLATION LEVEL REPEATABLE READ;
879+
CREATEFUNCTIONbalkifnull(int8, int8)
880+
RETURNS int8
881+
PARALLEL SAFE
882+
STRICT
883+
LANGUAGE plpgsqlAS $$
884+
BEGIN
885+
IF $1 ISNULL THEN
886+
RAISE'erroneously called with NULL argument';
887+
END IF;
888+
RETURNNULL;
889+
END$$;
890+
891+
CREATEAGGREGATEbalk(
892+
BASETYPE= int4,
893+
SFUNC= int4_sum(int8, int4),
894+
STYPE= int8,
895+
COMBINEFUNC= balkifnull(int8, int8),
896+
"PARALLEL"= SAFE,
897+
INITCOND='0'
898+
);
899+
900+
-- force use of parallelism
901+
ALTERTABLE tenk1set (parallel_workers=4);
902+
SET LOCAL parallel_setup_cost=0;
903+
SET LOCAL max_parallel_workers_per_gather=4;
904+
905+
EXPLAIN (COSTS OFF)SELECT balk(1)FROM tenk1;
906+
SELECT balk(1)FROM tenk1;
907+
908+
ROLLBACK;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp