Skip to content

Commit aada0a7

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 17083ab commit aada0a7

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
@@ -459,8 +459,9 @@ canonicalize_ec_expression(Expr *expr, Oid req_type, Oid req_collation)
459459

460460
/*
461461
* For a polymorphic-input-type opclass, just keep the same exposed type.
462+
* RECORD opclasses work like polymorphic-type ones for this purpose.
462463
*/
463-
if (IsPolymorphicType(req_type))
464+
if (IsPolymorphicType(req_type) || req_type == RECORDOID)
464465
req_type = expr_type;
465466

466467
/*

src/test/regress/expected/join.out

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

2653+
rollback;
2654+
--
2655+
-- test handling of merge clauses using record_ops
2656+
--
2657+
begin;
2658+
create type mycomptype as (id int, v bigint);
2659+
create temp table tidv (idv mycomptype);
2660+
create index on tidv (idv);
2661+
explain (costs off)
2662+
select a.idv, b.idv from tidv a, tidv b where a.idv = b.idv;
2663+
QUERY PLAN
2664+
----------------------------------------------------------
2665+
Merge Join
2666+
Merge Cond: (a.idv = b.idv)
2667+
-> Index Only Scan using tidv_idv_idx on tidv a
2668+
-> Materialize
2669+
-> Index Only Scan using tidv_idv_idx on tidv b
2670+
(5 rows)
2671+
2672+
set enable_mergejoin = 0;
2673+
explain (costs off)
2674+
select a.idv, b.idv from tidv a, tidv b where a.idv = b.idv;
2675+
QUERY PLAN
2676+
----------------------------------------------------
2677+
Nested Loop
2678+
-> Seq Scan on tidv a
2679+
-> Index Only Scan using tidv_idv_idx on tidv b
2680+
Index Cond: (idv = a.idv)
2681+
(4 rows)
2682+
26532683
rollback;
26542684
--
26552685
-- 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
@@ -664,6 +664,26 @@ select * from a left join b on i = x and i = y and x = i;
664664

665665
rollback;
666666

667+
--
668+
-- test handling of merge clauses using record_ops
669+
--
670+
begin;
671+
672+
create type mycomptype as (id int, v bigint);
673+
674+
create temp table tidv (idv mycomptype);
675+
create index on tidv (idv);
676+
677+
explain (costs off)
678+
select a.idv, b.idv from tidv a, tidv b where a.idv = b.idv;
679+
680+
set enable_mergejoin = 0;
681+
682+
explain (costs off)
683+
select a.idv, b.idv from tidv a, tidv b where a.idv = b.idv;
684+
685+
rollback;
686+
667687
--
668688
-- test NULL behavior of whole-row Vars, per bug #5025
669689
--

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