diff options
Diffstat (limited to 'src/backend/utils/adt/ri_triggers.c')
-rw-r--r-- | src/backend/utils/adt/ri_triggers.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index 5e6a5bd0053..4e5dd4b772d 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -32,6 +32,7 @@ #include "access/xact.h" #include "access/sysattr.h" +#include "catalog/pg_collation.h" #include "catalog/pg_constraint.h" #include "catalog/pg_operator.h" #include "catalog/pg_type.h" @@ -82,6 +83,7 @@ #define RIAttName(rel, attnum) NameStr(*attnumAttName(rel, attnum)) #define RIAttType(rel, attnum) attnumTypeId(rel, attnum) +#define RIAttCollation(rel, attnum) attnumCollationId(rel, attnum) #define RI_TRIGTYPE_INSERT 1 #define RI_TRIGTYPE_UPDATE 2 @@ -194,6 +196,7 @@ static void ri_GenerateQual(StringInfo buf, Oid opoid, const char *rightop, Oid rightoptype); static void ri_add_cast_to(StringInfo buf, Oid typid); +static void ri_GenerateQualCollation(StringInfo buf, Oid collation); static int ri_NullCheck(Relation rel, HeapTuple tup, RI_QueryKey *key, int pairidx); static void ri_BuildQueryKeyFull(RI_QueryKey *key, @@ -2681,6 +2684,9 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel) * (fk.keycol1 IS NOT NULL [AND ...]) * For MATCH FULL: * (fk.keycol1 IS NOT NULL [OR ...]) + * + * We attach COLLATE clauses to the operators when comparing columns + * that have different collations. *---------- */ initStringInfo(&querybuf); @@ -2707,6 +2713,8 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel) { Oid pk_type = RIAttType(pk_rel, riinfo.pk_attnums[i]); Oid fk_type = RIAttType(fk_rel, riinfo.fk_attnums[i]); + Oid pk_coll = RIAttCollation(pk_rel, riinfo.pk_attnums[i]); + Oid fk_coll = RIAttCollation(fk_rel, riinfo.fk_attnums[i]); quoteOneName(pkattname + 3, RIAttName(pk_rel, riinfo.pk_attnums[i])); @@ -2716,6 +2724,8 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel) pkattname, pk_type, riinfo.pf_eq_oprs[i], fkattname, fk_type); + if (pk_coll != fk_coll) + ri_GenerateQualCollation(&querybuf, pk_coll); sep = "AND"; } @@ -2978,6 +2988,53 @@ ri_add_cast_to(StringInfo buf, Oid typid) ReleaseSysCache(typetup); } +/* + * ri_GenerateQualCollation --- add a COLLATE spec to a WHERE clause + * + * At present, we intentionally do not use this function for RI queries that + * compare a variable to a $n parameter. Since parameter symbols always have + * default collation, the effect will be to use the variable's collation. + * Now that is only strictly correct when testing the referenced column, since + * the SQL standard specifies that RI comparisons should use the referenced + * column's collation. However, so long as all collations have the same + * notion of equality (which they do, because texteq reduces to bitwise + * equality), there's no visible semantic impact from using the referencing + * column's collation when testing it, and this is a good thing to do because + * it lets us use a normal index on the referencing column. However, we do + * have to use this function when directly comparing the referencing and + * referenced columns, if they are of different collations; else the parser + * will fail to resolve the collation to use. + */ +static void +ri_GenerateQualCollation(StringInfo buf, Oid collation) +{ + HeapTuple tp; + Form_pg_collation colltup; + char *collname; + char onename[MAX_QUOTED_NAME_LEN]; + + /* Nothing to do if it's a noncollatable data type */ + if (!OidIsValid(collation)) + return; + + tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(collation)); + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for collation %u", collation); + colltup = (Form_pg_collation) GETSTRUCT(tp); + collname = NameStr(colltup->collname); + + /* + * We qualify the name always, for simplicity and to ensure the query + * is not search-path-dependent. + */ + quoteOneName(onename, get_namespace_name(colltup->collnamespace)); + appendStringInfo(buf, " COLLATE %s", onename); + quoteOneName(onename, collname); + appendStringInfo(buf, ".%s", onename); + + ReleaseSysCache(tp); +} + /* ---------- * ri_BuildQueryKeyFull - * |