summaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2023-04-16 14:16:40 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2023-04-16 14:16:40 -0400
commit78d5952dd0e66afc4447eec07f770991fa406cce (patch)
treed2be84d4bcfb7230bc2957aa4b1daf3789a2cadb /src/test
parent1c54b93a8cf959a826dfabd6cae55dce255df2f5 (diff)
downloadpostgresql-78d5952dd0e66afc4447eec07f770991fa406cce.tar.gz
Ensure result of an aggregate's finalfunc is made read-only.
The finalfunc might return a read-write expanded object. If we de-duplicate multiple call sites for the aggregate, any function(s) receiving the aggregate result earlier could alter or destroy the value that reaches the ones called later. This is a brown-paper-bag bug in commit 42b746d4c, because we actually considered the need for read-only-ness but failed to realize that it applied to the case with a finalfunc as well as the case without. Per report from Justin Pryzby. New error in HEAD, no need for back-patch. Discussion: https://postgr.es/m/ZDm5TuKsh3tzoEjz@telsasoft.com
Diffstat (limited to 'src/test')
-rw-r--r--src/test/regress/expected/aggregates.out37
-rw-r--r--src/test/regress/sql/aggregates.sql39
2 files changed, 76 insertions, 0 deletions
diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out
index f0517f95b6..d8271da4d1 100644
--- a/src/test/regress/expected/aggregates.out
+++ b/src/test/regress/expected/aggregates.out
@@ -2759,6 +2759,43 @@ SELECT balk(hundred) FROM tenk1;
(1 row)
ROLLBACK;
+-- test multiple usage of an aggregate whose finalfn returns a R/W datum
+BEGIN;
+CREATE FUNCTION rwagg_sfunc(x anyarray, y anyarray) RETURNS anyarray
+LANGUAGE plpgsql IMMUTABLE AS $$
+BEGIN
+ RETURN array_fill(y[1], ARRAY[4]);
+END;
+$$;
+CREATE FUNCTION rwagg_finalfunc(x anyarray) RETURNS anyarray
+LANGUAGE plpgsql STRICT IMMUTABLE AS $$
+DECLARE
+ res x%TYPE;
+BEGIN
+ -- assignment is essential for this test, it expands the array to R/W
+ res := array_fill(x[1], ARRAY[4]);
+ RETURN res;
+END;
+$$;
+CREATE AGGREGATE rwagg(anyarray) (
+ STYPE = anyarray,
+ SFUNC = rwagg_sfunc,
+ FINALFUNC = rwagg_finalfunc
+);
+CREATE FUNCTION eatarray(x real[]) RETURNS real[]
+LANGUAGE plpgsql STRICT IMMUTABLE AS $$
+BEGIN
+ x[1] := x[1] + 1;
+ RETURN x;
+END;
+$$;
+SELECT eatarray(rwagg(ARRAY[1.0::real])), eatarray(rwagg(ARRAY[1.0::real]));
+ eatarray | eatarray
+-----------+-----------
+ {2,1,1,1} | {2,1,1,1}
+(1 row)
+
+ROLLBACK;
-- test coverage for aggregate combine/serial/deserial functions
BEGIN;
SET parallel_setup_cost = 0;
diff --git a/src/test/regress/sql/aggregates.sql b/src/test/regress/sql/aggregates.sql
index 1783d19bd5..75c78be640 100644
--- a/src/test/regress/sql/aggregates.sql
+++ b/src/test/regress/sql/aggregates.sql
@@ -1207,6 +1207,45 @@ SELECT balk(hundred) FROM tenk1;
ROLLBACK;
+-- test multiple usage of an aggregate whose finalfn returns a R/W datum
+BEGIN;
+
+CREATE FUNCTION rwagg_sfunc(x anyarray, y anyarray) RETURNS anyarray
+LANGUAGE plpgsql IMMUTABLE AS $$
+BEGIN
+ RETURN array_fill(y[1], ARRAY[4]);
+END;
+$$;
+
+CREATE FUNCTION rwagg_finalfunc(x anyarray) RETURNS anyarray
+LANGUAGE plpgsql STRICT IMMUTABLE AS $$
+DECLARE
+ res x%TYPE;
+BEGIN
+ -- assignment is essential for this test, it expands the array to R/W
+ res := array_fill(x[1], ARRAY[4]);
+ RETURN res;
+END;
+$$;
+
+CREATE AGGREGATE rwagg(anyarray) (
+ STYPE = anyarray,
+ SFUNC = rwagg_sfunc,
+ FINALFUNC = rwagg_finalfunc
+);
+
+CREATE FUNCTION eatarray(x real[]) RETURNS real[]
+LANGUAGE plpgsql STRICT IMMUTABLE AS $$
+BEGIN
+ x[1] := x[1] + 1;
+ RETURN x;
+END;
+$$;
+
+SELECT eatarray(rwagg(ARRAY[1.0::real])), eatarray(rwagg(ARRAY[1.0::real]));
+
+ROLLBACK;
+
-- test coverage for aggregate combine/serial/deserial functions
BEGIN;