]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/cache/lsyscache.c
Fix ALTER COLUMN TYPE to preserve the tablespace and reloptions of indexes
[postgresql] / src / backend / utils / cache / lsyscache.c
index 8c4cbef66cb375311dc63dec266a104f097a9ed7..d82e7debf5302bf527f4cb7f0e333015d3d18ecf 100644 (file)
@@ -3,11 +3,11 @@
  * lsyscache.c
  *       Convenience routines for common queries in the system catalog cache.
  *
- * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.140 2006/12/30 21:21:54 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.153 2007/10/13 15:55:40 tgl Exp $
  *
  * NOTES
  *       Eventually, the index information should go through here, too.
 #include "postgres.h"
 
 #include "access/hash.h"
+#include "access/nbtree.h"
 #include "bootstrap/bootstrap.h"
 #include "catalog/pg_amop.h"
 #include "catalog/pg_amproc.h"
+#include "catalog/pg_constraint.h"
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
@@ -138,76 +140,65 @@ get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
 }
 
 /*
- * get_op_mergejoin_info
- *             Given the OIDs of a (putatively) mergejoinable equality operator
- *             and a sortop defining the sort ordering of the lefthand input of
- *             the merge clause, determine whether this sort ordering is actually
- *             usable for merging.  If so, return the required sort ordering op
- *             for the righthand input, as well as the btree opfamily OID containing
- *             these operators and the operator strategy number of the two sortops
- *             (either BTLessStrategyNumber or BTGreaterStrategyNumber).
+ * get_ordering_op_properties
+ *             Given the OID of an ordering operator (a btree "<" or ">" operator),
+ *             determine its opfamily, its declared input datatype, and its
+ *             strategy number (BTLessStrategyNumber or BTGreaterStrategyNumber).
  *
- * We can mergejoin if we find the two operators in the same opfamily as
- * equality and either less-than or greater-than respectively.  If there
- * are multiple such opfamilies, assume we can use any one.
+ * Returns TRUE if successful, FALSE if no matching pg_amop entry exists.
+ * (This indicates that the operator is not a valid ordering operator.)
+ *
+ * Note: the operator could be registered in multiple families, for example
+ * if someone were to build a "reverse sort" opfamily.  This would result in
+ * uncertainty as to whether "ORDER BY USING op" would default to NULLS FIRST
+ * or NULLS LAST, as well as inefficient planning due to failure to match up
+ * pathkeys that should be the same.  So we want a determinate result here.
+ * Because of the way the syscache search works, we'll use the interpretation
+ * associated with the opfamily with smallest OID, which is probably
+ * determinate enough.  Since there is no longer any particularly good reason
+ * to build reverse-sort opfamilies, it doesn't seem worth expending any
+ * additional effort on ensuring consistency.
  */
-#ifdef NOT_YET
-/* eventually should look like this */
 bool
-get_op_mergejoin_info(Oid eq_op, Oid left_sortop,
-                                         Oid *right_sortop, Oid *opfamily, int *opstrategy)
+get_ordering_op_properties(Oid opno,
+                                                  Oid *opfamily, Oid *opcintype, int16 *strategy)
 {
        bool            result = false;
-       Oid                     lefttype;
-       Oid                     righttype;
        CatCList   *catlist;
        int                     i;
 
-       /* Make sure output args are initialized even on failure */
-       *right_sortop = InvalidOid;
+       /* ensure outputs are initialized on failure */
        *opfamily = InvalidOid;
-       *opstrategy = 0;
-
-       /* Need the righthand input datatype */
-       op_input_types(eq_op, &lefttype, &righttype);
+       *opcintype = InvalidOid;
+       *strategy = 0;
 
        /*
-        * Search through all the pg_amop entries containing the equality operator
+        * Search pg_amop to see if the target operator is registered as the "<"
+        * or ">" operator of any btree opfamily.
         */
        catlist = SearchSysCacheList(AMOPOPID, 1,
-                                                                ObjectIdGetDatum(eq_op),
+                                                                ObjectIdGetDatum(opno),
                                                                 0, 0, 0);
 
        for (i = 0; i < catlist->n_members; i++)
        {
-               HeapTuple       op_tuple = &catlist->members[i]->tuple;
-               Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
-               Oid                     opfamily_id;
-               StrategyNumber op_strategy;
+               HeapTuple       tuple = &catlist->members[i]->tuple;
+               Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
 
                /* must be btree */
-               if (op_form->amopmethod != BTREE_AM_OID)
-                       continue;
-               /* must use the operator as equality */
-               if (op_form->amopstrategy != BTEqualStrategyNumber)
+               if (aform->amopmethod != BTREE_AM_OID)
                        continue;
 
-               /* See if sort operator is also in this opclass with OK semantics */
-               opfamily_id = op_form->amopfamily;
-               op_strategy = get_op_opfamily_strategy(left_sortop, opfamily_id);
-               if (op_strategy == BTLessStrategyNumber ||
-                       op_strategy == BTGreaterStrategyNumber)
+               if (aform->amopstrategy == BTLessStrategyNumber ||
+                       aform->amopstrategy == BTGreaterStrategyNumber)
                {
-                       /* Yes, so find the corresponding righthand sortop */
-                       *right_sortop = get_opfamily_member(opfamily_id,
-                                                                                               righttype,
-                                                                                               righttype,
-                                                                                               op_strategy);
-                       if (OidIsValid(*right_sortop))
+                       /* Found it ... should have consistent input types */
+                       if (aform->amoplefttype == aform->amoprighttype)
                        {
-                               /* Found a workable mergejoin semantics */
-                               *opfamily = opfamily_id;
-                               *opstrategy = op_strategy;
+                               /* Found a suitable opfamily, return info */
+                               *opfamily = aform->amopfamily;
+                               *opcintype = aform->amoplefttype;
+                               *strategy = aform->amopstrategy;
                                result = true;
                                break;
                        }
@@ -218,63 +209,279 @@ get_op_mergejoin_info(Oid eq_op, Oid left_sortop,
 
        return result;
 }
-#else
-/* temp implementation until planner gets smarter: left_sortop is output */
+
+/*
+ * get_compare_function_for_ordering_op
+ *             Get the OID of the datatype-specific btree comparison function
+ *             associated with an ordering operator (a "<" or ">" operator).
+ *
+ * *cmpfunc receives the comparison function OID.
+ * *reverse is set FALSE if the operator is "<", TRUE if it's ">"
+ * (indicating the comparison result must be negated before use).
+ *
+ * Returns TRUE if successful, FALSE if no btree function can be found.
+ * (This indicates that the operator is not a valid ordering operator.)
+ */
 bool
-get_op_mergejoin_info(Oid eq_op, Oid *left_sortop,
-                                         Oid *right_sortop, Oid *opfamily)
+get_compare_function_for_ordering_op(Oid opno, Oid *cmpfunc, bool *reverse)
 {
-       bool            result = false;
-       Oid                     lefttype;
-       Oid                     righttype;
-       CatCList   *catlist;
-       int                     i;
+       Oid                     opfamily;
+       Oid                     opcintype;
+       int16           strategy;
 
-       /* Make sure output args are initialized even on failure */
-       *left_sortop = InvalidOid;
-       *right_sortop = InvalidOid;
-       *opfamily = InvalidOid;
+       /* Find the operator in pg_amop */
+       if (get_ordering_op_properties(opno,
+                                                                  &opfamily, &opcintype, &strategy))
+       {
+               /* Found a suitable opfamily, get matching support function */
+               *cmpfunc = get_opfamily_proc(opfamily,
+                                                                        opcintype,
+                                                                        opcintype,
+                                                                        BTORDER_PROC);
+               if (!OidIsValid(*cmpfunc))                              /* should not happen */
+                       elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
+                                BTORDER_PROC, opcintype, opcintype, opfamily);
+               *reverse = (strategy == BTGreaterStrategyNumber);
+               return true;
+       }
+
+       /* ensure outputs are set on failure */
+       *cmpfunc = InvalidOid;
+       *reverse = false;
+       return false;
+}
 
-       /* Need the input datatypes */
-       op_input_types(eq_op, &lefttype, &righttype);
+/*
+ * get_equality_op_for_ordering_op
+ *             Get the OID of the datatype-specific btree equality operator
+ *             associated with an ordering operator (a "<" or ">" operator).
+ *
+ * Returns InvalidOid if no matching equality operator can be found.
+ * (This indicates that the operator is not a valid ordering operator.)
+ */
+Oid
+get_equality_op_for_ordering_op(Oid opno)
+{
+       Oid                     result = InvalidOid;
+       Oid                     opfamily;
+       Oid                     opcintype;
+       int16           strategy;
+
+       /* Find the operator in pg_amop */
+       if (get_ordering_op_properties(opno,
+                                                                  &opfamily, &opcintype, &strategy))
+       {
+               /* Found a suitable opfamily, get matching equality operator */
+               result = get_opfamily_member(opfamily,
+                                                                        opcintype,
+                                                                        opcintype,
+                                                                        BTEqualStrategyNumber);
+       }
+
+       return result;
+}
+
+/*
+ * get_ordering_op_for_equality_op
+ *             Get the OID of a datatype-specific btree ordering operator
+ *             associated with an equality operator.  (If there are multiple
+ *             possibilities, assume any one will do.)
+ *
+ * This function is used when we have to sort data before unique-ifying,
+ * and don't much care which sorting op is used as long as it's compatible
+ * with the intended equality operator.  Since we need a sorting operator,
+ * it should be single-data-type even if the given operator is cross-type.
+ * The caller specifies whether to find an op for the LHS or RHS data type.
+ *
+ * Returns InvalidOid if no matching ordering operator can be found.
+ */
+Oid
+get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type)
+{
+       Oid                     result = InvalidOid;
+       CatCList   *catlist;
+       int                     i;
 
        /*
-        * Search through all the pg_amop entries containing the equality operator
+        * Search pg_amop to see if the target operator is registered as the "="
+        * operator of any btree opfamily.
         */
        catlist = SearchSysCacheList(AMOPOPID, 1,
-                                                                ObjectIdGetDatum(eq_op),
+                                                                ObjectIdGetDatum(opno),
                                                                 0, 0, 0);
 
        for (i = 0; i < catlist->n_members; i++)
        {
-               HeapTuple       op_tuple = &catlist->members[i]->tuple;
-               Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
-               Oid                     opfamily_id;
+               HeapTuple       tuple = &catlist->members[i]->tuple;
+               Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
 
                /* must be btree */
-               if (op_form->amopmethod != BTREE_AM_OID)
-                       continue;
-               /* must use the operator as equality */
-               if (op_form->amopstrategy != BTEqualStrategyNumber)
+               if (aform->amopmethod != BTREE_AM_OID)
                        continue;
 
-               opfamily_id = op_form->amopfamily;
+               if (aform->amopstrategy == BTEqualStrategyNumber)
+               {
+                       /* Found a suitable opfamily, get matching ordering operator */
+                       Oid             typid;
+
+                       typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
+                       result = get_opfamily_member(aform->amopfamily,
+                                                                                typid, typid,
+                                                                                BTLessStrategyNumber);
+                       if (OidIsValid(result))
+                               break;
+                       /* failure probably shouldn't happen, but keep looking if so */
+               }
+       }
+
+       ReleaseSysCacheList(catlist);
 
-               /* Find the matching sortops */
-               *left_sortop = get_opfamily_member(opfamily_id,
-                                                                                  lefttype,
-                                                                                  lefttype,
-                                                                                  BTLessStrategyNumber);
-               *right_sortop = get_opfamily_member(opfamily_id,
-                                                                                       righttype,
-                                                                                       righttype,
-                                                                                       BTLessStrategyNumber);
-               if (OidIsValid(*left_sortop) && OidIsValid(*right_sortop))
+       return result;
+}
+
+/*
+ * get_mergejoin_opfamilies
+ *             Given a putatively mergejoinable operator, return a list of the OIDs
+ *             of the btree opfamilies in which it represents equality.
+ *
+ * It is possible (though at present unusual) for an operator to be equality
+ * in more than one opfamily, hence the result is a list.  This also lets us
+ * return NIL if the operator is not found in any opfamilies.
+ *
+ * The planner currently uses simple equal() tests to compare the lists
+ * returned by this function, which makes the list order relevant, though
+ * strictly speaking it should not be.  Because of the way syscache list
+ * searches are handled, in normal operation the result will be sorted by OID
+ * so everything works fine.  If running with system index usage disabled,
+ * the result ordering is unspecified and hence the planner might fail to
+ * recognize optimization opportunities ... but that's hardly a scenario in
+ * which performance is good anyway, so there's no point in expending code
+ * or cycles here to guarantee the ordering in that case.
+ */
+List *
+get_mergejoin_opfamilies(Oid opno)
+{
+       List       *result = NIL;
+       CatCList   *catlist;
+       int                     i;
+
+       /*
+        * Search pg_amop to see if the target operator is registered as the "="
+        * operator of any btree opfamily.
+        */
+       catlist = SearchSysCacheList(AMOPOPID, 1,
+                                                                ObjectIdGetDatum(opno),
+                                                                0, 0, 0);
+
+       for (i = 0; i < catlist->n_members; i++)
+       {
+               HeapTuple       tuple = &catlist->members[i]->tuple;
+               Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
+
+               /* must be btree equality */
+               if (aform->amopmethod == BTREE_AM_OID &&
+                       aform->amopstrategy == BTEqualStrategyNumber)
+                       result = lappend_oid(result, aform->amopfamily);
+       }
+
+       ReleaseSysCacheList(catlist);
+
+       return result;
+}
+
+/*
+ * get_compatible_hash_operators
+ *             Get the OID(s) of hash equality operator(s) compatible with the given
+ *             operator, but operating on its LHS and/or RHS datatype.
+ *
+ * An operator for the LHS type is sought and returned into *lhs_opno if
+ * lhs_opno isn't NULL.  Similarly, an operator for the RHS type is sought
+ * and returned into *rhs_opno if rhs_opno isn't NULL.
+ *
+ * If the given operator is not cross-type, the results should be the same
+ * operator, but in cross-type situations they will be different.
+ *
+ * Returns true if able to find the requested operator(s), false if not.
+ * (This indicates that the operator should not have been marked oprcanhash.)
+ */
+bool
+get_compatible_hash_operators(Oid opno,
+                                                         Oid *lhs_opno, Oid *rhs_opno)
+{
+       bool            result = false;
+       CatCList   *catlist;
+       int                     i;
+
+       /* Ensure output args are initialized on failure */
+       if (lhs_opno)
+               *lhs_opno = InvalidOid;
+       if (rhs_opno)
+               *rhs_opno = InvalidOid;
+
+       /*
+        * Search pg_amop to see if the target operator is registered as the "="
+        * operator of any hash opfamily.  If the operator is registered in
+        * multiple opfamilies, assume we can use any one.
+        */
+       catlist = SearchSysCacheList(AMOPOPID, 1,
+                                                                ObjectIdGetDatum(opno),
+                                                                0, 0, 0);
+
+       for (i = 0; i < catlist->n_members; i++)
+       {
+               HeapTuple       tuple = &catlist->members[i]->tuple;
+               Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
+
+               if (aform->amopmethod == HASH_AM_OID &&
+                       aform->amopstrategy == HTEqualStrategyNumber)
                {
-                       /* Found a workable mergejoin semantics */
-                       *opfamily = opfamily_id;
-                       result = true;
-                       break;
+                       /* No extra lookup needed if given operator is single-type */
+                       if (aform->amoplefttype == aform->amoprighttype)
+                       {
+                               if (lhs_opno)
+                                       *lhs_opno = opno;
+                               if (rhs_opno)
+                                       *rhs_opno = opno;
+                               result = true;
+                               break;
+                       }
+                       /*
+                        * Get the matching single-type operator(s).  Failure probably
+                        * shouldn't happen --- it implies a bogus opfamily --- but
+                        * continue looking if so.
+                        */
+                       if (lhs_opno)
+                       {
+                               *lhs_opno = get_opfamily_member(aform->amopfamily,
+                                                                                               aform->amoplefttype,
+                                                                                               aform->amoplefttype,
+                                                                                               HTEqualStrategyNumber);
+                               if (!OidIsValid(*lhs_opno))
+                                       continue;
+                               /* Matching LHS found, done if caller doesn't want RHS */
+                               if (!rhs_opno)
+                               {
+                                       result = true;
+                                       break;
+                               }
+                       }
+                       if (rhs_opno)
+                       {
+                               *rhs_opno = get_opfamily_member(aform->amopfamily,
+                                                                                               aform->amoprighttype,
+                                                                                               aform->amoprighttype,
+                                                                                               HTEqualStrategyNumber);
+                               if (!OidIsValid(*rhs_opno))
+                               {
+                                       /* Forget any LHS operator from this opfamily */
+                                       if (lhs_opno)
+                                               *lhs_opno = InvalidOid;
+                                       continue;
+                               }
+                               /* Matching RHS found, so done */
+                               result = true;
+                               break;
+                       }
                }
        }
 
@@ -282,31 +489,40 @@ get_op_mergejoin_info(Oid eq_op, Oid *left_sortop,
 
        return result;
 }
-#endif
 
 /*
- * get_op_hash_function
- *             Get the OID of the datatype-specific hash function associated with
- *             a hashable equality operator.
+ * get_op_hash_functions
+ *             Get the OID(s) of hash support function(s) compatible with the given
+ *             operator, operating on its LHS and/or RHS datatype as required.
  *
- * XXX API needs to be generalized for the case of different left and right
- * datatypes.
+ * A function for the LHS type is sought and returned into *lhs_procno if
+ * lhs_procno isn't NULL.  Similarly, a function for the RHS type is sought
+ * and returned into *rhs_procno if rhs_procno isn't NULL.
  *
- * Returns InvalidOid if no hash function can be found.  (This indicates
- * that the operator should not have been marked oprcanhash.)
+ * If the given operator is not cross-type, the results should be the same
+ * function, but in cross-type situations they will be different.
+ *
+ * Returns true if able to find the requested function(s), false if not.
+ * (This indicates that the operator should not have been marked oprcanhash.)
  */
-Oid
-get_op_hash_function(Oid opno)
+bool
+get_op_hash_functions(Oid opno,
+                                         RegProcedure *lhs_procno, RegProcedure *rhs_procno)
 {
+       bool            result = false;
        CatCList   *catlist;
        int                     i;
-       Oid                     result = InvalidOid;
+
+       /* Ensure output args are initialized on failure */
+       if (lhs_procno)
+               *lhs_procno = InvalidOid;
+       if (rhs_procno)
+               *rhs_procno = InvalidOid;
 
        /*
         * Search pg_amop to see if the target operator is registered as the "="
         * operator of any hash opfamily.  If the operator is registered in
-        * multiple opfamilies, assume we can use the associated hash function from
-        * any one.
+        * multiple opfamilies, assume we can use any one.
         */
        catlist = SearchSysCacheList(AMOPOPID, 1,
                                                                 ObjectIdGetDatum(opno),
@@ -320,12 +536,50 @@ get_op_hash_function(Oid opno)
                if (aform->amopmethod == HASH_AM_OID &&
                        aform->amopstrategy == HTEqualStrategyNumber)
                {
-                       /* Found a suitable opfamily, get matching hash support function */
-                       result = get_opfamily_proc(aform->amopfamily,
-                                                                          aform->amoplefttype,
-                                                                          aform->amoprighttype,
-                                                                          HASHPROC);
-                       break;
+                       /*
+                        * Get the matching support function(s).  Failure probably
+                        * shouldn't happen --- it implies a bogus opfamily --- but
+                        * continue looking if so.
+                        */
+                       if (lhs_procno)
+                       {
+                               *lhs_procno = get_opfamily_proc(aform->amopfamily,
+                                                                                               aform->amoplefttype,
+                                                                                               aform->amoplefttype,
+                                                                                               HASHPROC);
+                               if (!OidIsValid(*lhs_procno))
+                                       continue;
+                               /* Matching LHS found, done if caller doesn't want RHS */
+                               if (!rhs_procno)
+                               {
+                                       result = true;
+                                       break;
+                               }
+                               /* Only one lookup needed if given operator is single-type */
+                               if (aform->amoplefttype == aform->amoprighttype)
+                               {
+                                       *rhs_procno = *lhs_procno;
+                                       result = true;
+                                       break;
+                               }
+                       }
+                       if (rhs_procno)
+                       {
+                               *rhs_procno = get_opfamily_proc(aform->amopfamily,
+                                                                                               aform->amoprighttype,
+                                                                                               aform->amoprighttype,
+                                                                                               HASHPROC);
+                               if (!OidIsValid(*rhs_procno))
+                               {
+                                       /* Forget any LHS function from this opfamily */
+                                       if (lhs_procno)
+                                               *lhs_procno = InvalidOid;
+                                       continue;
+                               }
+                               /* Matching RHS found, so done */
+                               result = true;
+                               break;
+                       }
                }
        }
 
@@ -412,6 +666,45 @@ get_op_btree_interpretation(Oid opno, List **opfamilies, List **opstrats)
        ReleaseSysCacheList(catlist);
 }
 
+/*
+ * ops_in_same_btree_opfamily
+ *             Return TRUE if there exists a btree opfamily containing both operators.
+ *             (This implies that they have compatible notions of equality.)
+ */
+bool
+ops_in_same_btree_opfamily(Oid opno1, Oid opno2)
+{
+       bool            result = false;
+       CatCList   *catlist;
+       int                     i;
+
+       /*
+        * We search through all the pg_amop entries for opno1.
+        */
+       catlist = SearchSysCacheList(AMOPOPID, 1,
+                                                                ObjectIdGetDatum(opno1),
+                                                                0, 0, 0);
+       for (i = 0; i < catlist->n_members; i++)
+       {
+               HeapTuple       op_tuple = &catlist->members[i]->tuple;
+               Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
+
+               /* must be btree */
+               if (op_form->amopmethod != BTREE_AM_OID)
+                       continue;
+
+               if (op_in_opfamily(opno2, op_form->amopfamily))
+               {
+                       result = true;
+                       break;
+               }
+       }
+
+       ReleaseSysCacheList(catlist);
+
+       return result;
+}
+
 
 /*                             ---------- AMPROC CACHES ----------                                              */
 
@@ -605,10 +898,37 @@ get_atttypetypmod(Oid relid, AttrNumber attnum,
        ReleaseSysCache(tp);
 }
 
-/*                             ---------- INDEX CACHE ----------                                                */
+/*                             ---------- CONSTRAINT CACHE ----------                                   */
 
-/*             watch this space...
+/*
+ * get_constraint_name
+ *             Returns the name of a given pg_constraint entry.
+ *
+ * Returns a palloc'd copy of the string, or NULL if no such constraint.
+ *
+ * NOTE: since constraint name is not unique, be wary of code that uses this
+ * for anything except preparing error messages.
  */
+char *
+get_constraint_name(Oid conoid)
+{
+       HeapTuple       tp;
+
+       tp = SearchSysCache(CONSTROID,
+                                               ObjectIdGetDatum(conoid),
+                                               0, 0, 0);
+       if (HeapTupleIsValid(tp))
+       {
+               Form_pg_constraint contup = (Form_pg_constraint) GETSTRUCT(tp);
+               char       *result;
+
+               result = pstrdup(NameStr(contup->conname));
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return NULL;
+}
 
 /*                             ---------- OPCLASS CACHE ----------                                              */
 
@@ -1093,6 +1413,48 @@ func_volatile(Oid funcid)
        return result;
 }
 
+/*
+ * get_func_cost
+ *             Given procedure id, return the function's procost field.
+ */
+float4
+get_func_cost(Oid funcid)
+{
+       HeapTuple       tp;
+       float4          result;
+
+       tp = SearchSysCache(PROCOID,
+                                               ObjectIdGetDatum(funcid),
+                                               0, 0, 0);
+       if (!HeapTupleIsValid(tp))
+               elog(ERROR, "cache lookup failed for function %u", funcid);
+
+       result = ((Form_pg_proc) GETSTRUCT(tp))->procost;
+       ReleaseSysCache(tp);
+       return result;
+}
+
+/*
+ * get_func_rows
+ *             Given procedure id, return the function's prorows field.
+ */
+float4
+get_func_rows(Oid funcid)
+{
+       HeapTuple       tp;
+       float4          result;
+
+       tp = SearchSysCache(PROCOID,
+                                               ObjectIdGetDatum(funcid),
+                                               0, 0, 0);
+       if (!HeapTupleIsValid(tp))
+               elog(ERROR, "cache lookup failed for function %u", funcid);
+
+       result = ((Form_pg_proc) GETSTRUCT(tp))->prorows;
+       ReleaseSysCache(tp);
+       return result;
+}
+
 /*                             ---------- RELATION CACHE ----------                                     */
 
 /*
@@ -1249,6 +1611,35 @@ get_rel_relkind(Oid relid)
                return '\0';
 }
 
+/*
+ * get_rel_tablespace
+ *
+ *             Returns the pg_tablespace OID associated with a given relation.
+ *
+ * Note: InvalidOid might mean either that we couldn't find the relation,
+ * or that it is in the database's default tablespace.
+ */
+Oid
+get_rel_tablespace(Oid relid)
+{
+       HeapTuple       tp;
+
+       tp = SearchSysCache(RELOID,
+                                               ObjectIdGetDatum(relid),
+                                               0, 0, 0);
+       if (HeapTupleIsValid(tp))
+       {
+               Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
+               Oid                     result;
+
+               result = reltup->reltablespace;
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return InvalidOid;
+}
+
 
 /*                             ---------- TYPE CACHE ----------                                                 */
 
@@ -1405,10 +1796,10 @@ getTypeIOParam(HeapTuple typeTuple)
 
        /*
         * Array types get their typelem as parameter; everybody else gets their
-        * own type OID as parameter.  (This is a change from 8.0, in which only
-        * composite types got their own OID as parameter.)
+        * own type OID as parameter.  (As of 8.2, domains must get their own OID
+        * even if their base type is an array.)
         */
-       if (OidIsValid(typeStruct->typelem))
+       if (typeStruct->typtype == TYPTYPE_BASE && OidIsValid(typeStruct->typelem))
                return typeStruct->typelem;
        else
                return HeapTupleGetOid(typeTuple);
@@ -1602,6 +1993,7 @@ get_typdefault(Oid typid)
                                                                                 getTypeIOParam(typeTuple), -1);
                        /* Build a Const node containing the value */
                        expr = (Node *) makeConst(typid,
+                                                                         -1,
                                                                          type->typlen,
                                                                          datum,
                                                                          false,
@@ -1659,7 +2051,7 @@ getBaseTypeAndTypmod(Oid typid, int32 *typmod)
                if (!HeapTupleIsValid(tup))
                        elog(ERROR, "cache lookup failed for type %u", typid);
                typTup = (Form_pg_type) GETSTRUCT(tup);
-               if (typTup->typtype != 'd')
+               if (typTup->typtype != TYPTYPE_DOMAIN)
                {
                        /* Not a domain, so done */
                        ReleaseSysCache(tup);
@@ -1765,7 +2157,17 @@ get_typtype(Oid typid)
 bool
 type_is_rowtype(Oid typid)
 {
-       return (typid == RECORDOID || get_typtype(typid) == 'c');
+       return (typid == RECORDOID || get_typtype(typid) == TYPTYPE_COMPOSITE);
+}
+
+/*
+ * type_is_enum
+ *    Returns true if the given type is an enum type.
+ */
+bool
+type_is_enum(Oid typid)
+{
+       return (get_typtype(typid) == TYPTYPE_ENUM);
 }
 
 /*
@@ -1830,50 +2232,24 @@ get_element_type(Oid typid)
 /*
  * get_array_type
  *
- *             Given the type OID, get the corresponding array type.
+ *             Given the type OID, get the corresponding "true" array type.
  *             Returns InvalidOid if no array type can be found.
- *
- * NB: this only considers varlena arrays to be true arrays.
  */
 Oid
 get_array_type(Oid typid)
 {
        HeapTuple       tp;
+       Oid result = InvalidOid;
 
        tp = SearchSysCache(TYPEOID,
                                                ObjectIdGetDatum(typid),
                                                0, 0, 0);
        if (HeapTupleIsValid(tp))
        {
-               Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
-               char       *array_typename;
-               Oid                     namespaceId;
-
-               array_typename = makeArrayTypeName(NameStr(typtup->typname));
-               namespaceId = typtup->typnamespace;
+               result = ((Form_pg_type) GETSTRUCT(tp))->typarray;
                ReleaseSysCache(tp);
-
-               tp = SearchSysCache(TYPENAMENSP,
-                                                       PointerGetDatum(array_typename),
-                                                       ObjectIdGetDatum(namespaceId),
-                                                       0, 0);
-
-               pfree(array_typename);
-
-               if (HeapTupleIsValid(tp))
-               {
-                       Oid                     result;
-
-                       typtup = (Form_pg_type) GETSTRUCT(tp);
-                       if (typtup->typlen == -1 && typtup->typelem == typid)
-                               result = HeapTupleGetOid(tp);
-                       else
-                               result = InvalidOid;
-                       ReleaseSysCache(tp);
-                       return result;
-               }
        }
-       return InvalidOid;
+       return result;
 }
 
 /*