Skip to content

Commit a11b3bd

Browse files
committed
Fix misprocessing of equivalence classes involving record_eq().
canonicalize_ec_expression() is supposed to agree with coerce_type() as to whether a RelabelType should be inserted to make a subexpression be valid input for the operators of a given opclass. However, it did the wrong thing with named-composite-type inputs to record_eq(): it put in a RelabelType to RECORDOID, which the parser doesn't. In some cases this was harmless because all code paths involving a particular equivalence class did the same thing, but in other cases this would result in failing to recognize a composite-type expression as being a member of an equivalence class that it actually is a member of. The most obvious bad effect was to fail to recognize that an index on a composite column could provide the sort order needed for a mergejoin on that column, as reported by Teodor Sigaev. I think there might be other, subtler, cases that result in misoptimization. It also seems possible that an unwanted RelabelType would sometimes get into an emitted plan --- but because record_eq and friends don't examine the declared type of their input expressions, that would not create any visible problems. To fix, just treat RECORDOID as if it were a polymorphic type, which in some sense it is. We might want to consider formalizing that a bit more someday, but for the moment this seems to be the only place where an IsPolymorphicType() test ought to include RECORDOID as well. This has been broken for a long time, so back-patch to all supported branches. Discussion: https://postgr.es/m/a6b22369-e3bf-4d49-f59d-0c41d3551e81@sigaev.ru
1 parent 7fc7dac commit a11b3bd

File tree

3 files changed

+52
-1
lines changed

3 files changed

+52
-1
lines changed

src/backend/optimizer/path/equivclass.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,8 +497,9 @@ canonicalize_ec_expression(Expr *expr, Oid req_type, Oid req_collation)
497497

498498
/*
499499
* For a polymorphic-input-type opclass, just keep the same exposed type.
500+
* RECORD opclasses work like polymorphic-type ones for this purpose.
500501
*/
501-
if (IsPolymorphicType(req_type))
502+
if (IsPolymorphicType(req_type) || req_type == RECORDOID)
502503
req_type = expr_type;
503504

504505
/*

src/test/regress/expected/join.out

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2672,6 +2672,36 @@ select * from a left join b on i = x and i = y and x = i;
26722672
---+---+---
26732673
(0 rows)
26742674

2675+
rollback;
2676+
--
2677+
-- test handling of merge clauses using record_ops
2678+
--
2679+
begin;
2680+
create type mycomptype as (id int, v bigint);
2681+
create temp table tidv (idv mycomptype);
2682+
create index on tidv (idv);
2683+
explain (costs off)
2684+
select a.idv, b.idv from tidv a, tidv b where a.idv = b.idv;
2685+
QUERY PLAN
2686+
----------------------------------------------------------
2687+
Merge Join
2688+
Merge Cond: (a.idv = b.idv)
2689+
-> Index Only Scan using tidv_idv_idx on tidv a
2690+
-> Materialize
2691+
-> Index Only Scan using tidv_idv_idx on tidv b
2692+
(5 rows)
2693+
2694+
set enable_mergejoin = 0;
2695+
explain (costs off)
2696+
select a.idv, b.idv from tidv a, tidv b where a.idv = b.idv;
2697+
QUERY PLAN
2698+
----------------------------------------------------
2699+
Nested Loop
2700+
-> Seq Scan on tidv a
2701+
-> Index Only Scan using tidv_idv_idx on tidv b
2702+
Index Cond: (idv = a.idv)
2703+
(4 rows)
2704+
26752705
rollback;
26762706
--
26772707
-- test NULL behavior of whole-row Vars, per bug #5025

src/test/regress/sql/join.sql

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,26 @@ select * from a left join b on i = x and i = y and x = i;
673673

674674
rollback;
675675

676+
--
677+
-- test handling of merge clauses using record_ops
678+
--
679+
begin;
680+
681+
create type mycomptype as (id int, v bigint);
682+
683+
create temp table tidv (idv mycomptype);
684+
create index on tidv (idv);
685+
686+
explain (costs off)
687+
select a.idv, b.idv from tidv a, tidv b where a.idv = b.idv;
688+
689+
set enable_mergejoin = 0;
690+
691+
explain (costs off)
692+
select a.idv, b.idv from tidv a, tidv b where a.idv = b.idv;
693+
694+
rollback;
695+
676696
--
677697
-- test NULL behavior of whole-row Vars, per bug #5025
678698
--

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy