aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/indexcmds.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/indexcmds.c')
-rw-r--r--src/backend/commands/indexcmds.c53
1 files changed, 35 insertions, 18 deletions
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 5f54f66f591..a5cc047c69b 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.149 2006/10/04 00:29:51 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.150 2006/12/23 00:43:09 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -802,31 +802,37 @@ GetIndexOpClass(List *opclass, Oid attrType,
Oid
GetDefaultOpClass(Oid type_id, Oid am_id)
{
+ Oid result = InvalidOid;
int nexact = 0;
int ncompatible = 0;
- Oid exactOid = InvalidOid;
- Oid compatibleOid = InvalidOid;
+ int ncompatiblepreferred = 0;
Relation rel;
ScanKeyData skey[1];
SysScanDesc scan;
HeapTuple tup;
+ CATEGORY tcategory;
/* If it's a domain, look at the base type instead */
type_id = getBaseType(type_id);
+ tcategory = TypeCategory(type_id);
+
/*
* We scan through all the opclasses available for the access method,
* looking for one that is marked default and matches the target type
* (either exactly or binary-compatibly, but prefer an exact match).
*
- * We could find more than one binary-compatible match, in which case we
- * require the user to specify which one he wants. If we find more than
- * one exact match, then someone put bogus entries in pg_opclass.
+ * We could find more than one binary-compatible match. If just one is
+ * for a preferred type, use that one; otherwise we fail, forcing the user
+ * to specify which one he wants. (The preferred-type special case is a
+ * kluge for varchar: it's binary-compatible to both text and bpchar, so
+ * we need a tiebreaker.) If we find more than one exact match, then
+ * someone put bogus entries in pg_opclass.
*/
rel = heap_open(OperatorClassRelationId, AccessShareLock);
ScanKeyInit(&skey[0],
- Anum_pg_opclass_opcamid,
+ Anum_pg_opclass_opcmethod,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(am_id));
@@ -837,17 +843,26 @@ GetDefaultOpClass(Oid type_id, Oid am_id)
{
Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
- if (opclass->opcdefault)
+ /* ignore altogether if not a default opclass */
+ if (!opclass->opcdefault)
+ continue;
+ if (opclass->opcintype == type_id)
{
- if (opclass->opcintype == type_id)
+ nexact++;
+ result = HeapTupleGetOid(tup);
+ }
+ else if (nexact == 0 &&
+ IsBinaryCoercible(type_id, opclass->opcintype))
+ {
+ if (IsPreferredType(tcategory, opclass->opcintype))
{
- nexact++;
- exactOid = HeapTupleGetOid(tup);
+ ncompatiblepreferred++;
+ result = HeapTupleGetOid(tup);
}
- else if (IsBinaryCoercible(type_id, opclass->opcintype))
+ else if (ncompatiblepreferred == 0)
{
ncompatible++;
- compatibleOid = HeapTupleGetOid(tup);
+ result = HeapTupleGetOid(tup);
}
}
}
@@ -856,15 +871,17 @@ GetDefaultOpClass(Oid type_id, Oid am_id)
heap_close(rel, AccessShareLock);
- if (nexact == 1)
- return exactOid;
- if (nexact != 0)
+ /* raise error if pg_opclass contains inconsistent data */
+ if (nexact > 1)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("there are multiple default operator classes for data type %s",
format_type_be(type_id))));
- if (ncompatible == 1)
- return compatibleOid;
+
+ if (nexact == 1 ||
+ ncompatiblepreferred == 1 ||
+ (ncompatiblepreferred == 0 && ncompatible == 1))
+ return result;
return InvalidOid;
}