summaryrefslogtreecommitdiff
path: root/src/test/regress/sql/opr_sanity.sql
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2014-04-12 11:58:53 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2014-04-12 12:03:30 -0400
commita9d9acbf219b9e96585779cd5f99d674d4ccba74 (patch)
tree4bd26a78fa7f6f0bc558c611278e42a9f41d4875 /src/test/regress/sql/opr_sanity.sql
parent3c41b812c5578fd7bd5c2de42941012d7d56dde2 (diff)
downloadpostgresql-a9d9acbf219b9e96585779cd5f99d674d4ccba74.tar.gz
Create infrastructure for moving-aggregate optimization.
Until now, when executing an aggregate function as a window function within a window with moving frame start (that is, any frame start mode except UNBOUNDED PRECEDING), we had to recalculate the aggregate from scratch each time the frame head moved. This patch allows an aggregate definition to include an alternate "moving aggregate" implementation that includes an inverse transition function for removing rows from the aggregate's running state. As long as this can be done successfully, runtime is proportional to the total number of input rows, rather than to the number of input rows times the average frame length. This commit includes the core infrastructure, documentation, and regression tests using user-defined aggregates. Follow-on commits will update some of the built-in aggregates to use this feature. David Rowley and Florian Pflug, reviewed by Dean Rasheed; additional hacking by me
Diffstat (limited to 'src/test/regress/sql/opr_sanity.sql')
-rw-r--r--src/test/regress/sql/opr_sanity.sql103
1 files changed, 102 insertions, 1 deletions
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index ad37178924..22998a553c 100644
--- a/src/test/regress/sql/opr_sanity.sql
+++ b/src/test/regress/sql/opr_sanity.sql
@@ -592,7 +592,7 @@ WHERE aggfnoid = 0 OR aggtransfn = 0 OR
aggkind NOT IN ('n', 'o', 'h') OR
aggnumdirectargs < 0 OR
(aggkind = 'n' AND aggnumdirectargs > 0) OR
- aggtranstype = 0 OR aggtransspace < 0;
+ aggtranstype = 0 OR aggtransspace < 0 OR aggmtransspace < 0;
-- Make sure the matching pg_proc entry is sensible, too.
@@ -668,6 +668,107 @@ WHERE a.aggfnoid = p.oid AND
a.agginitval IS NULL AND
NOT binary_coercible(p.proargtypes[0], a.aggtranstype);
+-- Check for inconsistent specifications of moving-aggregate columns.
+
+SELECT ctid, aggfnoid::oid
+FROM pg_aggregate as p1
+WHERE aggmtranstype != 0 AND
+ (aggmtransfn = 0 OR aggminvtransfn = 0);
+
+SELECT ctid, aggfnoid::oid
+FROM pg_aggregate as p1
+WHERE aggmtranstype = 0 AND
+ (aggmtransfn != 0 OR aggminvtransfn != 0 OR aggmfinalfn != 0 OR
+ aggmtransspace != 0 OR aggminitval IS NOT NULL);
+
+-- If there is no mfinalfn then the output type must be the mtranstype.
+
+SELECT a.aggfnoid::oid, p.proname
+FROM pg_aggregate as a, pg_proc as p
+WHERE a.aggfnoid = p.oid AND
+ a.aggmtransfn != 0 AND
+ a.aggmfinalfn = 0 AND p.prorettype != a.aggmtranstype;
+
+-- Cross-check mtransfn (if present) against its entry in pg_proc.
+SELECT a.aggfnoid::oid, p.proname, ptr.oid, ptr.proname
+FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS ptr
+WHERE a.aggfnoid = p.oid AND
+ a.aggmtransfn = ptr.oid AND
+ (ptr.proretset
+ OR NOT (ptr.pronargs =
+ CASE WHEN a.aggkind = 'n' THEN p.pronargs + 1
+ ELSE greatest(p.pronargs - a.aggnumdirectargs, 1) + 1 END)
+ OR NOT physically_coercible(ptr.prorettype, a.aggmtranstype)
+ OR NOT physically_coercible(a.aggmtranstype, ptr.proargtypes[0])
+ OR (p.pronargs > 0 AND
+ NOT physically_coercible(p.proargtypes[0], ptr.proargtypes[1]))
+ OR (p.pronargs > 1 AND
+ NOT physically_coercible(p.proargtypes[1], ptr.proargtypes[2]))
+ OR (p.pronargs > 2 AND
+ NOT physically_coercible(p.proargtypes[2], ptr.proargtypes[3]))
+ -- we could carry the check further, but 3 args is enough for now
+ );
+
+-- Cross-check minvtransfn (if present) against its entry in pg_proc.
+SELECT a.aggfnoid::oid, p.proname, ptr.oid, ptr.proname
+FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS ptr
+WHERE a.aggfnoid = p.oid AND
+ a.aggminvtransfn = ptr.oid AND
+ (ptr.proretset
+ OR NOT (ptr.pronargs =
+ CASE WHEN a.aggkind = 'n' THEN p.pronargs + 1
+ ELSE greatest(p.pronargs - a.aggnumdirectargs, 1) + 1 END)
+ OR NOT physically_coercible(ptr.prorettype, a.aggmtranstype)
+ OR NOT physically_coercible(a.aggmtranstype, ptr.proargtypes[0])
+ OR (p.pronargs > 0 AND
+ NOT physically_coercible(p.proargtypes[0], ptr.proargtypes[1]))
+ OR (p.pronargs > 1 AND
+ NOT physically_coercible(p.proargtypes[1], ptr.proargtypes[2]))
+ OR (p.pronargs > 2 AND
+ NOT physically_coercible(p.proargtypes[2], ptr.proargtypes[3]))
+ -- we could carry the check further, but 3 args is enough for now
+ );
+
+-- Cross-check mfinalfn (if present) against its entry in pg_proc.
+
+SELECT a.aggfnoid::oid, p.proname, pfn.oid, pfn.proname
+FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS pfn
+WHERE a.aggfnoid = p.oid AND
+ a.aggmfinalfn = pfn.oid AND
+ (pfn.proretset OR
+ NOT binary_coercible(pfn.prorettype, p.prorettype) OR
+ NOT binary_coercible(a.aggmtranstype, pfn.proargtypes[0]) OR
+ CASE WHEN a.aggkind = 'n' THEN pfn.pronargs != 1
+ ELSE pfn.pronargs != p.pronargs + 1
+ OR (p.pronargs > 0 AND
+ NOT binary_coercible(p.proargtypes[0], pfn.proargtypes[1]))
+ OR (p.pronargs > 1 AND
+ NOT binary_coercible(p.proargtypes[1], pfn.proargtypes[2]))
+ OR (p.pronargs > 2 AND
+ NOT binary_coercible(p.proargtypes[2], pfn.proargtypes[3]))
+ -- we could carry the check further, but 3 args is enough for now
+ END);
+
+-- If mtransfn is strict then either minitval should be non-NULL, or
+-- input type should match mtranstype so that the first non-null input
+-- can be assigned as the state value.
+
+SELECT a.aggfnoid::oid, p.proname, ptr.oid, ptr.proname
+FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS ptr
+WHERE a.aggfnoid = p.oid AND
+ a.aggmtransfn = ptr.oid AND ptr.proisstrict AND
+ a.aggminitval IS NULL AND
+ NOT binary_coercible(p.proargtypes[0], a.aggmtranstype);
+
+-- transfn and mtransfn should have same strictness setting.
+
+SELECT a.aggfnoid::oid, p.proname, ptr.oid, ptr.proname, mptr.oid, mptr.proname
+FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS ptr, pg_proc AS mptr
+WHERE a.aggfnoid = p.oid AND
+ a.aggtransfn = ptr.oid AND
+ a.aggmtransfn = mptr.oid AND
+ ptr.proisstrict != mptr.proisstrict;
+
-- Cross-check aggsortop (if present) against pg_operator.
-- We expect to find entries for bool_and, bool_or, every, max, and min.