mirror of
https://github.com/postgres/postgres.git
synced 2026-10-23 13:29:09 +03:00
Fix RI fast-path for domain-typed FK columns
The RI fast path is the first caller to pass a cross-type pf_eq_oprs
operator to ri_HashCompareOp(). Its test for whether a cast can be
skipped, "typeid == righttype", failed when the FK column was a domain,
since typeid is then the domain OID rather than its base type. The code
concluded no usable conversion existed and threw "no conversion function
from <domain> to <type>" for every valid row.
Look through the domain to its base type. When pfeqop comes directly
from the index opfamily its right-hand input is getBaseType(fktype), so
getBaseType(typeid) == righttype is the correct test; the PK = PK
fallback (right-hand input opcintype) still fails that test and falls
through to the existing cast lookup unchanged.
Oversight in commit 2da86c1.
Reported-by: Ewan Young <kdbase.hack@gmail.com>
Author: Ewan Young <kdbase.hack@gmail.com>
Reviewed-by: Amit Langote <amitlangote09@gmail.com>
Discussion: https://postgr.es/m/CAON2xHNDFC4cX2atvTpMuC=cK9y7q4J+n3+15w4148AohXEc1w@mail.gmail.com
This commit is contained in:
@@ -4113,10 +4113,11 @@ ri_HashCompareOp(Oid eq_opr, Oid typeid)
|
||||
/*
|
||||
* pf_eq_oprs (used by the fast path) can be cross-type when the FK
|
||||
* and PK columns differ in type, e.g. int48eq for int4 PK / int8 FK.
|
||||
* If the FK column's type already matches what the operator expects
|
||||
* as its right-hand input, no cast is needed.
|
||||
* If the FK column's type, or the base type of a domain over it,
|
||||
* already matches what the operator expects as its right-hand input,
|
||||
* no cast is needed.
|
||||
*/
|
||||
if (typeid == righttype)
|
||||
if (getBaseType(typeid) == righttype)
|
||||
castfunc = InvalidOid; /* simplest case */
|
||||
else
|
||||
{
|
||||
|
||||
@@ -3705,6 +3705,21 @@ INSERT INTO fp_fk_cross VALUES (999);
|
||||
ERROR: insert or update on table "fp_fk_cross" violates foreign key constraint "fp_fk_cross_a_fkey"
|
||||
DETAIL: Key (a)=(999) is not present in table "fp_pk_cross".
|
||||
DROP TABLE fp_fk_cross, fp_pk_cross;
|
||||
-- Domain-typed FK column whose base type differs from the PK type: the
|
||||
-- fast path must look through the domain to its base type when deciding
|
||||
-- whether the cross-type comparison needs a cast. Otherwise valid rows
|
||||
-- were wrongly rejected with "no conversion function from ... to ...".
|
||||
CREATE DOMAIN fp_int8dom AS int8;
|
||||
CREATE TABLE fp_pk_dom (a int4 PRIMARY KEY);
|
||||
INSERT INTO fp_pk_dom SELECT generate_series(1, 200);
|
||||
CREATE TABLE fp_fk_dom (a fp_int8dom REFERENCES fp_pk_dom);
|
||||
INSERT INTO fp_fk_dom SELECT generate_series(1, 200);
|
||||
INSERT INTO fp_fk_dom VALUES (999);
|
||||
ERROR: insert or update on table "fp_fk_dom" violates foreign key constraint "fp_fk_dom_a_fkey"
|
||||
DETAIL: Key (a)=(999) is not present in table "fp_pk_dom".
|
||||
INSERT INTO fp_fk_dom VALUES (NULL);
|
||||
DROP TABLE fp_fk_dom, fp_pk_dom;
|
||||
DROP DOMAIN fp_int8dom;
|
||||
-- Duplicate FK values: when using the batched SAOP path, every
|
||||
-- row must be recognized as satisfied, not just the first match
|
||||
CREATE TABLE fp_pk_dup (a int PRIMARY KEY);
|
||||
|
||||
@@ -2673,6 +2673,20 @@ INSERT INTO fp_fk_cross SELECT generate_series(1, 200);
|
||||
INSERT INTO fp_fk_cross VALUES (999);
|
||||
DROP TABLE fp_fk_cross, fp_pk_cross;
|
||||
|
||||
-- Domain-typed FK column whose base type differs from the PK type: the
|
||||
-- fast path must look through the domain to its base type when deciding
|
||||
-- whether the cross-type comparison needs a cast. Otherwise valid rows
|
||||
-- were wrongly rejected with "no conversion function from ... to ...".
|
||||
CREATE DOMAIN fp_int8dom AS int8;
|
||||
CREATE TABLE fp_pk_dom (a int4 PRIMARY KEY);
|
||||
INSERT INTO fp_pk_dom SELECT generate_series(1, 200);
|
||||
CREATE TABLE fp_fk_dom (a fp_int8dom REFERENCES fp_pk_dom);
|
||||
INSERT INTO fp_fk_dom SELECT generate_series(1, 200);
|
||||
INSERT INTO fp_fk_dom VALUES (999);
|
||||
INSERT INTO fp_fk_dom VALUES (NULL);
|
||||
DROP TABLE fp_fk_dom, fp_pk_dom;
|
||||
DROP DOMAIN fp_int8dom;
|
||||
|
||||
-- Duplicate FK values: when using the batched SAOP path, every
|
||||
-- row must be recognized as satisfied, not just the first match
|
||||
CREATE TABLE fp_pk_dup (a int PRIMARY KEY);
|
||||
|
||||
Reference in New Issue
Block a user