]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Change search for default operator classes so that it examines all opclasses
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 10 Feb 2006 19:01:33 +0000 (19:01 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 10 Feb 2006 19:01:33 +0000 (19:01 +0000)
regardless of the current schema search path.  Since CREATE OPERATOR CLASS
only allows one default opclass per datatype regardless of schemas, this
should have minimal impact, and it fixes problems with failure to find a
desired opclass while restoring dump files.  Per discussion at
http://archives.postgresql.org/pgsql-hackers/2006-02/msg00284.php.
Remove now-redundant-or-unused code in typcache.c and namespace.c,
and backpatch as far as 8.0.

src/backend/catalog/namespace.c
src/backend/commands/indexcmds.c
src/backend/utils/cache/typcache.c
src/include/catalog/namespace.h
src/include/commands/defrem.h

index e7960b38458d3ceefb2d69e9bcbd959749886d6f..3753753ce3b78c7a09d2618eccef03c1d4e8c115 100644 (file)
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.73 2004/12/31 21:59:38 pgsql Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.73.4.1 2006/02/10 19:01:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -879,119 +879,6 @@ OperatorIsVisible(Oid oprid)
 }
 
 
-/*
- * OpclassGetCandidates
- *             Given an index access method OID, retrieve a list of all the
- *             opclasses for that AM that are visible in the search path.
- *
- * NOTE: the opcname_tmp field in the returned structs should not be used
- * by callers, because it points at syscache entries that we release at
- * the end of this routine.  If any callers needed the name information,
- * we could pstrdup() the names ... but at present it'd be wasteful.
- */
-OpclassCandidateList
-OpclassGetCandidates(Oid amid)
-{
-       OpclassCandidateList resultList = NULL;
-       CatCList   *catlist;
-       int                     i;
-
-       /* Search syscache by AM OID only */
-       catlist = SearchSysCacheList(CLAAMNAMENSP, 1,
-                                                                ObjectIdGetDatum(amid),
-                                                                0, 0, 0);
-
-       recomputeNamespacePath();
-
-       for (i = 0; i < catlist->n_members; i++)
-       {
-               HeapTuple       opctup = &catlist->members[i]->tuple;
-               Form_pg_opclass opcform = (Form_pg_opclass) GETSTRUCT(opctup);
-               int                     pathpos = 0;
-               OpclassCandidateList newResult;
-               ListCell   *nsp;
-
-               /* Consider only opclasses that are in the search path */
-               foreach(nsp, namespaceSearchPath)
-               {
-                       if (opcform->opcnamespace == lfirst_oid(nsp))
-                               break;
-                       pathpos++;
-               }
-               if (nsp == NULL)
-                       continue;                       /* opclass is not in search path */
-
-               /*
-                * Okay, it's in the search path, but does it have the same name
-                * as something we already accepted?  If so, keep only the one
-                * that appears earlier in the search path.
-                *
-                * If we have an ordered list from SearchSysCacheList (the normal
-                * case), then any conflicting opclass must immediately adjoin
-                * this one in the list, so we only need to look at the newest
-                * result item.  If we have an unordered list, we have to scan the
-                * whole result list.
-                */
-               if (resultList)
-               {
-                       OpclassCandidateList prevResult;
-
-                       if (catlist->ordered)
-                       {
-                               if (strcmp(NameStr(opcform->opcname),
-                                                  resultList->opcname_tmp) == 0)
-                                       prevResult = resultList;
-                               else
-                                       prevResult = NULL;
-                       }
-                       else
-                       {
-                               for (prevResult = resultList;
-                                        prevResult;
-                                        prevResult = prevResult->next)
-                               {
-                                       if (strcmp(NameStr(opcform->opcname),
-                                                          prevResult->opcname_tmp) == 0)
-                                               break;
-                               }
-                       }
-                       if (prevResult)
-                       {
-                               /* We have a match with a previous result */
-                               Assert(pathpos != prevResult->pathpos);
-                               if (pathpos > prevResult->pathpos)
-                                       continue;       /* keep previous result */
-                               /* replace previous result */
-                               prevResult->opcname_tmp = NameStr(opcform->opcname);
-                               prevResult->pathpos = pathpos;
-                               prevResult->oid = HeapTupleGetOid(opctup);
-                               prevResult->opcintype = opcform->opcintype;
-                               prevResult->opcdefault = opcform->opcdefault;
-                               prevResult->opckeytype = opcform->opckeytype;
-                               continue;
-                       }
-               }
-
-               /*
-                * Okay to add it to result list
-                */
-               newResult = (OpclassCandidateList)
-                       palloc(sizeof(struct _OpclassCandidateList));
-               newResult->opcname_tmp = NameStr(opcform->opcname);
-               newResult->pathpos = pathpos;
-               newResult->oid = HeapTupleGetOid(opctup);
-               newResult->opcintype = opcform->opcintype;
-               newResult->opcdefault = opcform->opcdefault;
-               newResult->opckeytype = opcform->opckeytype;
-               newResult->next = resultList;
-               resultList = newResult;
-       }
-
-       ReleaseSysCacheList(catlist);
-
-       return resultList;
-}
-
 /*
  * OpclassnameGetOpcid
  *             Try to resolve an unqualified index opclass name.
index 469e7b3f02bded3dc97bdcb0239cf70c49cf69e7..87a29339a7c18eadf527705def163ab35f61e23b 100644 (file)
@@ -8,38 +8,37 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.128 2004/12/31 21:59:41 pgsql Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.128.4.1 2006/02/10 19:01:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
 
+#include "access/genam.h"
 #include "access/heapam.h"
 #include "catalog/catalog.h"
 #include "catalog/catname.h"
 #include "catalog/dependency.h"
 #include "catalog/heap.h"
 #include "catalog/index.h"
-#include "catalog/namespace.h"
+#include "catalog/indexing.h"
 #include "catalog/pg_opclass.h"
-#include "catalog/pg_proc.h"
 #include "catalog/pg_tablespace.h"
 #include "commands/dbcommands.h"
 #include "commands/defrem.h"
 #include "commands/tablecmds.h"
 #include "commands/tablespace.h"
-#include "executor/executor.h"
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "optimizer/clauses.h"
-#include "optimizer/prep.h"
 #include "parser/parsetree.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_func.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
+#include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
 #include "utils/relcache.h"
 #include "utils/syscache.h"
@@ -54,7 +53,6 @@ static void ComputeIndexAttrs(IndexInfo *indexInfo, Oid *classOidP,
                                  bool isconstraint);
 static Oid GetIndexOpClass(List *opclass, Oid attrType,
                                char *accessMethodName, Oid accessMethodId);
-static Oid     GetDefaultOpClass(Oid attrType, Oid accessMethodId);
 static bool relationHasPrimaryKey(Relation rel);
 
 
@@ -642,17 +640,26 @@ GetIndexOpClass(List *opclass, Oid attrType,
        return opClassId;
 }
 
-static Oid
-GetDefaultOpClass(Oid attrType, Oid accessMethodId)
+/*
+ * GetDefaultOpClass
+ *
+ * Given the OIDs of a datatype and an access method, find the default
+ * operator class, if any.     Returns InvalidOid if there is none.
+ */
+Oid
+GetDefaultOpClass(Oid type_id, Oid am_id)
 {
-       OpclassCandidateList opclass;
        int                     nexact = 0;
        int                     ncompatible = 0;
        Oid                     exactOid = InvalidOid;
        Oid                     compatibleOid = InvalidOid;
+       Relation        rel;
+       ScanKeyData skey[1];
+       SysScanDesc scan;
+       HeapTuple       tup;
 
        /* If it's a domain, look at the base type instead */
-       attrType = getBaseType(attrType);
+       type_id = getBaseType(type_id);
 
        /*
         * We scan through all the opclasses available for the access method,
@@ -660,39 +667,49 @@ GetDefaultOpClass(Oid attrType, Oid accessMethodId)
         * (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.
-        *
-        * The initial search is done by namespace.c so that we only consider
-        * opclasses visible in the current namespace search path.      (See also
-        * typcache.c, which applies the same logic, but over all opclasses.)
+        * 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.
         */
-       for (opclass = OpclassGetCandidates(accessMethodId);
-                opclass != NULL;
-                opclass = opclass->next)
+       rel = heap_openr(OperatorClassRelationName, AccessShareLock);
+
+       ScanKeyInit(&skey[0],
+                               Anum_pg_opclass_opcamid,
+                               BTEqualStrategyNumber, F_OIDEQ,
+                               ObjectIdGetDatum(am_id));
+
+       scan = systable_beginscan(rel, OpclassAmNameNspIndex, true,
+                                                         SnapshotNow, 1, skey);
+
+       while (HeapTupleIsValid(tup = systable_getnext(scan)))
        {
+               Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
+
                if (opclass->opcdefault)
                {
-                       if (opclass->opcintype == attrType)
+                       if (opclass->opcintype == type_id)
                        {
                                nexact++;
-                               exactOid = opclass->oid;
+                               exactOid = HeapTupleGetOid(tup);
                        }
-                       else if (IsBinaryCoercible(attrType, opclass->opcintype))
+                       else if (IsBinaryCoercible(type_id, opclass->opcintype))
                        {
                                ncompatible++;
-                               compatibleOid = opclass->oid;
+                               compatibleOid = HeapTupleGetOid(tup);
                        }
                }
        }
 
+       systable_endscan(scan);
+
+       heap_close(rel, AccessShareLock);
+
        if (nexact == 1)
                return exactOid;
        if (nexact != 0)
                ereport(ERROR,
                                (errcode(ERRCODE_DUPLICATE_OBJECT),
-                                errmsg("there are multiple default operator classes for data type %s",
-                                               format_type_be(attrType))));
+               errmsg("there are multiple default operator classes for data type %s",
+                          format_type_be(type_id))));
        if (ncompatible == 1)
                return compatibleOid;
 
index b719f99d82dffd659be244311ac23b1bd7605ed5..776b101b69e3d3552b464d68815326ef7eaec636 100644 (file)
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/cache/typcache.c,v 1.11.4.1 2006/01/17 17:33:35 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/cache/typcache.c,v 1.11.4.2 2006/02/10 19:01:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
-#include "access/genam.h"
 #include "access/heapam.h"
 #include "access/hash.h"
 #include "access/nbtree.h"
 #include "catalog/catname.h"
-#include "catalog/indexing.h"
-#include "catalog/pg_am.h"
-#include "catalog/pg_opclass.h"
-#include "parser/parse_coerce.h"
+#include "catalog/pg_type.h"
+#include "commands/defrem.h"
 #include "utils/builtins.h"
 #include "utils/catcache.h"
-#include "utils/fmgroids.h"
 #include "utils/hsearch.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
@@ -93,9 +89,6 @@ static int32 RecordCacheArrayLen = 0; /* allocated length of array */
 static int32 NextRecordTypmod = 0;             /* number of entries used */
 
 
-static Oid     lookup_default_opclass(Oid type_id, Oid am_id);
-
-
 /*
  * lookup_type_cache
  *
@@ -182,14 +175,14 @@ lookup_type_cache(Oid type_id, int flags)
                                  TYPECACHE_EQ_OPR_FINFO | TYPECACHE_CMP_PROC_FINFO)) &&
                typentry->btree_opc == InvalidOid)
        {
-               typentry->btree_opc = lookup_default_opclass(type_id,
-                                                                                                        BTREE_AM_OID);
+               typentry->btree_opc = GetDefaultOpClass(type_id,
+                                                                                               BTREE_AM_OID);
                /* Only care about hash opclass if no btree opclass... */
                if (typentry->btree_opc == InvalidOid)
                {
                        if (typentry->hash_opc == InvalidOid)
-                               typentry->hash_opc = lookup_default_opclass(type_id,
-                                                                                                                       HASH_AM_OID);
+                               typentry->hash_opc = GetDefaultOpClass(type_id,
+                                                                                                          HASH_AM_OID);
                }
                else
                {
@@ -294,87 +287,6 @@ lookup_type_cache(Oid type_id, int flags)
        return typentry;
 }
 
-/*
- * lookup_default_opclass
- *
- * Given the OIDs of a datatype and an access method, find the default
- * operator class, if any.     Returns InvalidOid if there is none.
- */
-static Oid
-lookup_default_opclass(Oid type_id, Oid am_id)
-{
-       int                     nexact = 0;
-       int                     ncompatible = 0;
-       Oid                     exactOid = InvalidOid;
-       Oid                     compatibleOid = InvalidOid;
-       Relation        rel;
-       ScanKeyData skey[1];
-       SysScanDesc scan;
-       HeapTuple       tup;
-
-       /* If it's a domain, look at the base type instead */
-       type_id = getBaseType(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.
-        *
-        * This is the same logic as GetDefaultOpClass() in indexcmds.c, except
-        * that we consider all opclasses, regardless of the current search
-        * path.
-        */
-       rel = heap_openr(OperatorClassRelationName, AccessShareLock);
-
-       ScanKeyInit(&skey[0],
-                               Anum_pg_opclass_opcamid,
-                               BTEqualStrategyNumber, F_OIDEQ,
-                               ObjectIdGetDatum(am_id));
-
-       scan = systable_beginscan(rel, OpclassAmNameNspIndex, true,
-                                                         SnapshotNow, 1, skey);
-
-       while (HeapTupleIsValid(tup = systable_getnext(scan)))
-       {
-               Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
-
-               if (opclass->opcdefault)
-               {
-                       if (opclass->opcintype == type_id)
-                       {
-                               nexact++;
-                               exactOid = HeapTupleGetOid(tup);
-                       }
-                       else if (IsBinaryCoercible(type_id, opclass->opcintype))
-                       {
-                               ncompatible++;
-                               compatibleOid = HeapTupleGetOid(tup);
-                       }
-               }
-       }
-
-       systable_endscan(scan);
-
-       heap_close(rel, AccessShareLock);
-
-       if (nexact == 1)
-               return exactOid;
-       if (nexact != 0)
-               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;
-
-       return InvalidOid;
-}
-
-
 /*
  * lookup_rowtype_tupdesc
  *
index 4176f2c218d91986dbb0e58331f89632cc0a07d3..90cffa09d01690de9af1714de0c7f0b1f4d1cdd7 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/namespace.h,v 1.35 2004/12/31 22:03:24 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/namespace.h,v 1.35.4.1 2006/02/10 19:01:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -32,21 +32,6 @@ typedef struct _FuncCandidateList
        Oid                     args[1];                /* arg types --- VARIABLE LENGTH ARRAY */
 }      *FuncCandidateList;     /* VARIABLE LENGTH STRUCT */
 
-/*
- *     This structure holds a list of opclass candidates found by namespace
- *     lookup.
- */
-typedef struct _OpclassCandidateList
-{
-       struct _OpclassCandidateList *next;
-       char       *opcname_tmp;        /* for internal use of namespace lookup */
-       int                     pathpos;                /* for internal use of namespace lookup */
-       Oid                     oid;                    /* the opclass's OID */
-       Oid                     opcintype;              /* type of data indexed by opclass */
-       bool            opcdefault;             /* T if opclass is default for opcintype */
-       Oid                     opckeytype;             /* type of data in index, or InvalidOid */
-}      *OpclassCandidateList;
-
 
 extern Oid     RangeVarGetRelid(const RangeVar *relation, bool failOK);
 extern Oid     RangeVarGetCreationNamespace(const RangeVar *newRelation);
@@ -62,7 +47,6 @@ extern bool FunctionIsVisible(Oid funcid);
 extern FuncCandidateList OpernameGetCandidates(List *names, char oprkind);
 extern bool OperatorIsVisible(Oid oprid);
 
-extern OpclassCandidateList OpclassGetCandidates(Oid amid);
 extern Oid     OpclassnameGetOpcid(Oid amid, const char *opcname);
 extern bool OpclassIsVisible(Oid opcid);
 
index 30f576d78119afb30e84e5da7920fa0ee0525224..8469fc226cec68f5fd3c853ff5e679b8aac01f4b 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.62 2004/12/31 22:03:28 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.62.4.1 2006/02/10 19:01:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -40,6 +40,7 @@ extern char *makeObjectName(const char *name1, const char *name2,
                           const char *label);
 extern char *ChooseRelationName(const char *name1, const char *name2,
                                   const char *label, Oid namespace);
+extern Oid     GetDefaultOpClass(Oid type_id, Oid am_id);
 
 /* commands/functioncmds.c */
 extern void CreateFunction(CreateFunctionStmt *stmt);