88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.214 2007/02/14 01:58:56 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.215 2007/02/16 22:04:02 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -3943,11 +3943,10 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
39433943 /*
39443944 * Look up the equality operators to use in the constraint.
39453945 *
3946- * Note that we look for operator(s) with the PK type on the left; when
3947- * the types are different this is the right choice because the PK index
3948- * will need operators with the indexkey on the left. Also, we take the
3949- * PK type as being the declared input type of the opclass, which might be
3950- * binary-compatible but not identical to the PK column type.
3946+ * Note that we have to be careful about the difference between the actual
3947+ * PK column type and the opclass' declared input type, which might be
3948+ * only binary-compatible with it. The declared opcintype is the right
3949+ * thing to probe pg_amop with.
39513950 */
39523951 if (numfks != numpks )
39533952 ereport (ERROR ,
@@ -3956,12 +3955,14 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
39563955
39573956 for (i = 0 ; i < numpks ; i ++ )
39583957 {
3958+ Oid pktype = pktypoid [i ];
3959+ Oid fktype = fktypoid [i ];
3960+ Oid fktyped ;
39593961 HeapTuple cla_ht ;
39603962 Form_pg_opclass cla_tup ;
39613963 Oid amid ;
39623964 Oid opfamily ;
3963- Oid pktype ;
3964- Oid fktype ;
3965+ Oid opcintype ;
39653966 Oid pfeqop ;
39663967 Oid ppeqop ;
39673968 Oid ffeqop ;
@@ -3976,7 +3977,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
39763977 cla_tup = (Form_pg_opclass ) GETSTRUCT (cla_ht );
39773978 amid = cla_tup -> opcmethod ;
39783979 opfamily = cla_tup -> opcfamily ;
3979- pktype = cla_tup -> opcintype ;
3980+ opcintype = cla_tup -> opcintype ;
39803981 ReleaseSysCache (cla_ht );
39813982
39823983 /*
@@ -3991,30 +3992,50 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
39913992 eqstrategy = BTEqualStrategyNumber ;
39923993
39933994 /*
3994- * There had better be a PK = PK operator for the index.
3995+ * There had better be a primary equality operator for the index.
3996+ * We'll use it for PK = PK comparisons.
39953997 */
3996- ppeqop = get_opfamily_member (opfamily , pktype , pktype , eqstrategy );
3998+ ppeqop = get_opfamily_member (opfamily , opcintype , opcintype ,
3999+ eqstrategy );
39974000
39984001 if (!OidIsValid (ppeqop ))
39994002 elog (ERROR , "missing operator %d(%u,%u) in opfamily %u" ,
4000- eqstrategy , pktype , pktype , opfamily );
4003+ eqstrategy , opcintype , opcintype , opfamily );
40014004
40024005 /*
40034006 * Are there equality operators that take exactly the FK type?
40044007 * Assume we should look through any domain here.
40054008 */
4006- fktype = getBaseType (fktypoid [ i ] );
4009+ fktyped = getBaseType (fktype );
40074010
4008- pfeqop = get_opfamily_member (opfamily , pktype , fktype , eqstrategy );
4009- ffeqop = get_opfamily_member (opfamily , fktype , fktype , eqstrategy );
4011+ pfeqop = get_opfamily_member (opfamily , opcintype , fktyped ,
4012+ eqstrategy );
4013+ if (OidIsValid (pfeqop ))
4014+ ffeqop = get_opfamily_member (opfamily , fktyped , fktyped ,
4015+ eqstrategy );
4016+ else
4017+ ffeqop = InvalidOid ; /* keep compiler quiet */
40104018
40114019 if (!(OidIsValid (pfeqop ) && OidIsValid (ffeqop )))
40124020 {
40134021 /*
40144022 * Otherwise, look for an implicit cast from the FK type to
4015- * the PK type, and if found, use the PK type's equality operator.
4023+ * the opcintype, and if found, use the primary equality operator.
4024+ * This is a bit tricky because opcintype might be a generic type
4025+ * such as ANYARRAY, and so what we have to test is whether the
4026+ * two actual column types can be concurrently cast to that type.
4027+ * (Otherwise, we'd fail to reject combinations such as int[] and
4028+ * point[].)
40164029 */
4017- if (can_coerce_type (1 , & fktype , & pktype , COERCION_IMPLICIT ))
4030+ Oid input_typeids [2 ];
4031+ Oid target_typeids [2 ];
4032+
4033+ input_typeids [0 ] = pktype ;
4034+ input_typeids [1 ] = fktype ;
4035+ target_typeids [0 ] = opcintype ;
4036+ target_typeids [1 ] = opcintype ;
4037+ if (can_coerce_type (2 , input_typeids , target_typeids ,
4038+ COERCION_IMPLICIT ))
40184039 pfeqop = ffeqop = ppeqop ;
40194040 }
40204041
@@ -4028,8 +4049,8 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
40284049 "are of incompatible types: %s and %s." ,
40294050 strVal (list_nth (fkconstraint -> fk_attrs , i )),
40304051 strVal (list_nth (fkconstraint -> pk_attrs , i )),
4031- format_type_be (fktypoid [ i ] ),
4032- format_type_be (pktypoid [ i ] ))));
4052+ format_type_be (fktype ),
4053+ format_type_be (pktype ))));
40334054
40344055 pfeqoperators [i ] = pfeqop ;
40354056 ppeqoperators [i ] = ppeqop ;
0 commit comments