1
0
mirror of https://github.com/postgres/postgres.git synced 2025-09-03 15:22:11 +03:00

Disable anonymous record hash support except in special cases

Commit 01e658fa74 added hash support for row types.  This also added
support for hashing anonymous record types, using the same approach
that the type cache uses for comparison support for record types: It
just reports that it works, but it might fail at run time if a
component type doesn't actually support the operation.  We get away
with that for comparison because most types support that.  But some
types don't support hashing, so the current state can result in
failures at run time where the planner chooses hashing over sorting,
whereas that previously worked if only sorting was an option.

We do, however, want the record hashing support for path tracking in
recursive unions, and the SEARCH and CYCLE clauses built on that.  In
that case, hashing is the only plan option.  So enable that, this
commit implements the following approach: The type cache does not
report that hashing is available for the record type.  This undoes
that part of 01e658fa74.  Instead, callers that require hashing no
matter what can override that result themselves.  This patch only
touches the callers to make the aforementioned recursive query cases
work, namely the parse analysis of unions, as well as the hash_array()
function.

Reported-by: Sait Talha Nisanci <sait.nisanci@microsoft.com>
Bug: #17158
Discussion: https://www.postgresql.org/message-id/flat/17158-8a2ba823982537a4%40postgresql.org
This commit is contained in:
Peter Eisentraut
2021-09-08 09:25:46 +02:00
parent 8db27fbc11
commit 054adca641
7 changed files with 117 additions and 55 deletions

View File

@@ -648,34 +648,37 @@ reset enable_hashagg;
set enable_hashagg to on;
explain (costs off)
select x from (values (row(1, 2)), (row(1, 3))) _(x) union select x from (values (row(1, 2)), (row(1, 4))) _(x);
QUERY PLAN
-----------------------------------------
HashAggregate
Group Key: "*VALUES*".column1
-> Append
-> Values Scan on "*VALUES*"
-> Values Scan on "*VALUES*_1"
(5 rows)
QUERY PLAN
-----------------------------------------------
Unique
-> Sort
Sort Key: "*VALUES*".column1
-> Append
-> Values Scan on "*VALUES*"
-> Values Scan on "*VALUES*_1"
(6 rows)
select x from (values (row(1, 2)), (row(1, 3))) _(x) union select x from (values (row(1, 2)), (row(1, 4))) _(x);
x
-------
(1,4)
(1,3)
(1,2)
(1,3)
(1,4)
(3 rows)
explain (costs off)
select x from (values (row(1, 2)), (row(1, 3))) _(x) intersect select x from (values (row(1, 2)), (row(1, 4))) _(x);
QUERY PLAN
-----------------------------------------------
HashSetOp Intersect
-> Append
-> Subquery Scan on "*SELECT* 1"
-> Values Scan on "*VALUES*"
-> Subquery Scan on "*SELECT* 2"
-> Values Scan on "*VALUES*_1"
(6 rows)
QUERY PLAN
-----------------------------------------------------
SetOp Intersect
-> Sort
Sort Key: "*SELECT* 1".x
-> Append
-> Subquery Scan on "*SELECT* 1"
-> Values Scan on "*VALUES*"
-> Subquery Scan on "*SELECT* 2"
-> Values Scan on "*VALUES*_1"
(8 rows)
select x from (values (row(1, 2)), (row(1, 3))) _(x) intersect select x from (values (row(1, 2)), (row(1, 4))) _(x);
x
@@ -685,15 +688,17 @@ select x from (values (row(1, 2)), (row(1, 3))) _(x) intersect select x from (va
explain (costs off)
select x from (values (row(1, 2)), (row(1, 3))) _(x) except select x from (values (row(1, 2)), (row(1, 4))) _(x);
QUERY PLAN
-----------------------------------------------
HashSetOp Except
-> Append
-> Subquery Scan on "*SELECT* 1"
-> Values Scan on "*VALUES*"
-> Subquery Scan on "*SELECT* 2"
-> Values Scan on "*VALUES*_1"
(6 rows)
QUERY PLAN
-----------------------------------------------------
SetOp Except
-> Sort
Sort Key: "*SELECT* 1".x
-> Append
-> Subquery Scan on "*SELECT* 1"
-> Values Scan on "*VALUES*"
-> Subquery Scan on "*SELECT* 2"
-> Values Scan on "*VALUES*_1"
(8 rows)
select x from (values (row(1, 2)), (row(1, 3))) _(x) except select x from (values (row(1, 2)), (row(1, 4))) _(x);
x
@@ -702,21 +707,28 @@ select x from (values (row(1, 2)), (row(1, 3))) _(x) except select x from (value
(1 row)
-- non-hashable type
-- With an anonymous row type, the typcache reports that the type is
-- hashable, but then it will fail at run time.
-- With an anonymous row type, the typcache does not report that the
-- type is hashable. (Otherwise, this would fail at execution time.)
explain (costs off)
select x from (values (row(100::money)), (row(200::money))) _(x) union select x from (values (row(100::money)), (row(300::money))) _(x);
QUERY PLAN
-----------------------------------------
HashAggregate
Group Key: "*VALUES*".column1
-> Append
-> Values Scan on "*VALUES*"
-> Values Scan on "*VALUES*_1"
(5 rows)
QUERY PLAN
-----------------------------------------------
Unique
-> Sort
Sort Key: "*VALUES*".column1
-> Append
-> Values Scan on "*VALUES*"
-> Values Scan on "*VALUES*_1"
(6 rows)
select x from (values (row(100::money)), (row(200::money))) _(x) union select x from (values (row(100::money)), (row(300::money))) _(x);
ERROR: could not identify a hash function for type money
x
-----------
($100.00)
($200.00)
($300.00)
(3 rows)
-- With a defined row type, the typcache can inspect the type's fields
-- for hashability.
create type ct1 as (f1 money);

View File

@@ -218,8 +218,8 @@ select x from (values (row(1, 2)), (row(1, 3))) _(x) except select x from (value
-- non-hashable type
-- With an anonymous row type, the typcache reports that the type is
-- hashable, but then it will fail at run time.
-- With an anonymous row type, the typcache does not report that the
-- type is hashable. (Otherwise, this would fail at execution time.)
explain (costs off)
select x from (values (row(100::money)), (row(200::money))) _(x) union select x from (values (row(100::money)), (row(300::money))) _(x);
select x from (values (row(100::money)), (row(200::money))) _(x) union select x from (values (row(100::money)), (row(300::money))) _(x);