]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/cache/lsyscache.c
Create the planner mechanism for optimizing simple MIN and MAX queries
[postgresql] / src / backend / utils / cache / lsyscache.c
index be59004441883860e87f16944af613ffafd55f86..2c4d20576a5552da22c9e6912c261d646a711798 100644 (file)
 /*-------------------------------------------------------------------------
  *
  * lsyscache.c
- *       Routines to access information within system caches
- *
- * Copyright (c) 1994, Regents of the University of California
+ *       Convenience routines for common queries in the system catalog cache.
  *
+ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.27 1999/05/29 01:45:21 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.123 2005/04/11 23:06:56 tgl Exp $
  *
  * NOTES
  *       Eventually, the index information should go through here, too.
  *-------------------------------------------------------------------------
  */
-#include <string.h>
 #include "postgres.h"
+#include "miscadmin.h"
 
-#include "nodes/pg_list.h"
-#include "utils/syscache.h"
-#include "utils/lsyscache.h"
+#include "access/hash.h"
 #include "access/tupmacs.h"
-#include "utils/rel.h"
-#include "utils/palloc.h"
-#include "utils/elog.h"
-#include "access/attnum.h"
-#include "access/heapam.h"
-
 #include "catalog/pg_amop.h"
+#include "catalog/pg_amproc.h"
+#include "catalog/pg_namespace.h"
+#include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
+#include "catalog/pg_proc.h"
+#include "catalog/pg_shadow.h"
+#include "catalog/pg_group.h"
+#include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
+#include "nodes/makefuncs.h"
+#include "utils/array.h"
+#include "utils/builtins.h"
+#include "utils/catcache.h"
+#include "utils/datum.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
+
 
 /*                             ---------- AMOP CACHES ----------                                                */
 
 /*
- * op_class -
+ * op_in_opclass
  *
  *             Return t iff operator 'opno' is in operator class 'opclass'.
- *
  */
 bool
-op_class(Oid oprno, int32 opclass, Oid amopid)
-{
-       if (HeapTupleIsValid(SearchSysCacheTuple(AMOPOPID,
-                                                                                        ObjectIdGetDatum(opclass),
-                                                                                        ObjectIdGetDatum(oprno),
-                                                                                        ObjectIdGetDatum(amopid),
-                                                                                        0)))
-               return true;
-       else
-               return false;
+op_in_opclass(Oid opno, Oid opclass)
+{
+       return SearchSysCacheExists(AMOPOPID,
+                                                               ObjectIdGetDatum(opno),
+                                                               ObjectIdGetDatum(opclass),
+                                                               0, 0);
 }
 
-/*                             ---------- ATTRIBUTE CACHES ----------                                   */
+/*
+ * get_op_opclass_strategy
+ *
+ *             Get the operator's strategy number within the specified opclass,
+ *             or 0 if it's not a member of the opclass.
+ */
+int
+get_op_opclass_strategy(Oid opno, Oid opclass)
+{
+       HeapTuple       tp;
+       Form_pg_amop amop_tup;
+       int                     result;
+
+       tp = SearchSysCache(AMOPOPID,
+                                               ObjectIdGetDatum(opno),
+                                               ObjectIdGetDatum(opclass),
+                                               0, 0);
+       if (!HeapTupleIsValid(tp))
+               return 0;
+       amop_tup = (Form_pg_amop) GETSTRUCT(tp);
+       result = amop_tup->amopstrategy;
+       ReleaseSysCache(tp);
+       return result;
+}
+
+/*
+ * get_op_opclass_properties
+ *
+ *             Get the operator's strategy number, subtype, and recheck (lossy) flag
+ *             within the specified opclass.
+ *
+ * Caller should already have verified that opno is a member of opclass,
+ * therefore we raise an error if the tuple is not found.
+ */
+void
+get_op_opclass_properties(Oid opno, Oid opclass,
+                                                 int *strategy, Oid *subtype, bool *recheck)
+{
+       HeapTuple       tp;
+       Form_pg_amop amop_tup;
+
+       tp = SearchSysCache(AMOPOPID,
+                                               ObjectIdGetDatum(opno),
+                                               ObjectIdGetDatum(opclass),
+                                               0, 0);
+       if (!HeapTupleIsValid(tp))
+               elog(ERROR, "operator %u is not a member of opclass %u",
+                        opno, opclass);
+       amop_tup = (Form_pg_amop) GETSTRUCT(tp);
+       *strategy = amop_tup->amopstrategy;
+       *subtype = amop_tup->amopsubtype;
+       *recheck = amop_tup->amopreqcheck;
+       ReleaseSysCache(tp);
+}
+
+/*
+ * get_opclass_member
+ *             Get the OID of the operator that implements the specified strategy
+ *             with the specified subtype for the specified opclass.
+ *
+ * Returns InvalidOid if there is no pg_amop entry for the given keys.
+ */
+Oid
+get_opclass_member(Oid opclass, Oid subtype, int16 strategy)
+{
+       HeapTuple       tp;
+       Form_pg_amop amop_tup;
+       Oid                     result;
+
+       tp = SearchSysCache(AMOPSTRATEGY,
+                                               ObjectIdGetDatum(opclass),
+                                               ObjectIdGetDatum(subtype),
+                                               Int16GetDatum(strategy),
+                                               0);
+       if (!HeapTupleIsValid(tp))
+               return InvalidOid;
+       amop_tup = (Form_pg_amop) GETSTRUCT(tp);
+       result = amop_tup->amopopr;
+       ReleaseSysCache(tp);
+       return result;
+}
+
+/*
+ * get_op_hash_function
+ *             Get the OID of the datatype-specific hash function associated with
+ *             a hashable equality operator.
+ *
+ * Returns InvalidOid if no hash function can be found.  (This indicates
+ * that the operator should not have been marked oprcanhash.)
+ */
+Oid
+get_op_hash_function(Oid opno)
+{
+       CatCList   *catlist;
+       int                     i;
+       Oid                     opclass = InvalidOid;
+
+       /*
+        * Search pg_amop to see if the target operator is registered as the
+        * "=" operator of any hash opclass.  If the operator is registered in
+        * multiple opclasses, assume we can use the associated hash function
+        * from 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->amopstrategy == HTEqualStrategyNumber &&
+                       opclass_is_hash(aform->amopclaid))
+               {
+                       opclass = aform->amopclaid;
+                       break;
+               }
+       }
+
+       ReleaseSysCacheList(catlist);
+
+       if (OidIsValid(opclass))
+       {
+               /* Found a suitable opclass, get its default hash support function */
+               return get_opclass_proc(opclass, InvalidOid, HASHPROC);
+       }
+
+       /* Didn't find a match... */
+       return InvalidOid;
+}
+
+
+/*                             ---------- AMPROC CACHES ----------                                              */
 
 /*
- * get_attname -
+ * get_opclass_proc
+ *             Get the OID of the specified support function
+ *             for the specified opclass and subtype.
  *
+ * Returns InvalidOid if there is no pg_amproc entry for the given keys.
+ */
+Oid
+get_opclass_proc(Oid opclass, Oid subtype, int16 procnum)
+{
+       HeapTuple       tp;
+       Form_pg_amproc amproc_tup;
+       RegProcedure result;
+
+       tp = SearchSysCache(AMPROCNUM,
+                                               ObjectIdGetDatum(opclass),
+                                               ObjectIdGetDatum(subtype),
+                                               Int16GetDatum(procnum),
+                                               0);
+       if (!HeapTupleIsValid(tp))
+               return InvalidOid;
+       amproc_tup = (Form_pg_amproc) GETSTRUCT(tp);
+       result = amproc_tup->amproc;
+       ReleaseSysCache(tp);
+       return result;
+}
+
+
+/*                             ---------- ATTRIBUTE CACHES ----------                                   */
+
+/*
+ * get_attname
  *             Given the relation id and the attribute number,
  *             return the "attname" field from the attribute relation.
  *
+ * Note: returns a palloc'd copy of the string, or NULL if no such attribute.
  */
 char *
 get_attname(Oid relid, AttrNumber attnum)
 {
        HeapTuple       tp;
 
-       tp = SearchSysCacheTuple(ATTNUM,
-                                                        ObjectIdGetDatum(relid),
-                                                        UInt16GetDatum(attnum),
-                                                        0, 0);
+       tp = SearchSysCache(ATTNUM,
+                                               ObjectIdGetDatum(relid),
+                                               Int16GetDatum(attnum),
+                                               0, 0);
        if (HeapTupleIsValid(tp))
        {
                Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
-               return pstrdup(att_tup->attname.data);
+               char       *result;
+
+               result = pstrdup(NameStr(att_tup->attname));
+               ReleaseSysCache(tp);
+               return result;
        }
        else
                return NULL;
 }
 
 /*
- * get_attnum -
+ * get_relid_attribute_name
+ *
+ * Same as above routine get_attname(), except that error
+ * is handled by elog() instead of returning NULL.
+ */
+char *
+get_relid_attribute_name(Oid relid, AttrNumber attnum)
+{
+       char       *attname;
+
+       attname = get_attname(relid, attnum);
+       if (attname == NULL)
+               elog(ERROR, "cache lookup failed for attribute %d of relation %u",
+                        attnum, relid);
+       return attname;
+}
+
+/*
+ * get_attnum
  *
  *             Given the relation id and the attribute name,
  *             return the "attnum" field from the attribute relation.
  *
+ *             Returns InvalidAttrNumber if the attr doesn't exist (or is dropped).
  */
 AttrNumber
-get_attnum(Oid relid, char *attname)
+get_attnum(Oid relid, const char *attname)
 {
        HeapTuple       tp;
 
-       tp = SearchSysCacheTuple(ATTNAME,
-                                                        ObjectIdGetDatum(relid),
-                                                        PointerGetDatum(attname),
-                                                        0, 0);
+       tp = SearchSysCacheAttName(relid, attname);
        if (HeapTupleIsValid(tp))
        {
                Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
-               return att_tup->attnum;
+               AttrNumber      result;
+
+               result = att_tup->attnum;
+               ReleaseSysCache(tp);
+               return result;
        }
        else
                return InvalidAttrNumber;
 }
 
 /*
- * get_atttype -
+ * get_atttype
  *
  *             Given the relation OID and the attribute number with the relation,
  *             return the attribute type OID.
- *
  */
 Oid
 get_atttype(Oid relid, AttrNumber attnum)
 {
        HeapTuple       tp;
 
-       tp = SearchSysCacheTuple(ATTNUM,
-                                                        ObjectIdGetDatum(relid),
-                                                        UInt16GetDatum(attnum),
-                                                        0, 0);
+       tp = SearchSysCache(ATTNUM,
+                                               ObjectIdGetDatum(relid),
+                                               Int16GetDatum(attnum),
+                                               0, 0);
        if (HeapTupleIsValid(tp))
        {
                Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
-               return att_tup->atttypid;
+               Oid                     result;
+
+               result = att_tup->atttypid;
+               ReleaseSysCache(tp);
+               return result;
        }
        else
                return InvalidOid;
 }
 
-/* This routine uses the attname instead of the attnum because it
- * replaces the routine find_atttype, which is called sometimes when
- * only the attname, not the attno, is available.
+/*
+ * get_atttypmod
+ *
+ *             Given the relation id and the attribute number,
+ *             return the "atttypmod" field from the attribute relation.
  */
-bool
-get_attisset(Oid relid, char *attname)
+int32
+get_atttypmod(Oid relid, AttrNumber attnum)
 {
        HeapTuple       tp;
 
-       tp = SearchSysCacheTuple(ATTNAME,
-                                                        ObjectIdGetDatum(relid),
-                                                        PointerGetDatum(attname),
-                                                        0, 0);
+       tp = SearchSysCache(ATTNUM,
+                                               ObjectIdGetDatum(relid),
+                                               Int16GetDatum(attnum),
+                                               0, 0);
        if (HeapTupleIsValid(tp))
        {
                Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
-               return att_tup->attisset;
+               int32           result;
+
+               result = att_tup->atttypmod;
+               ReleaseSysCache(tp);
+               return result;
        }
        else
-               return false;
+               return -1;
 }
 
 /*
- * get_atttypmod -
+ * get_atttypetypmod
  *
- *             Given the relation id and the attribute number,
- *             return the "atttypmod" field from the attribute relation.
+ *             A two-fer: given the relation id and the attribute number,
+ *             fetch both type OID and atttypmod in a single cache lookup.
  *
+ * Unlike the otherwise-similar get_atttype/get_atttypmod, this routine
+ * raises an error if it can't obtain the information.
  */
-int32
-get_atttypmod(Oid relid, AttrNumber attnum)
+void
+get_atttypetypmod(Oid relid, AttrNumber attnum,
+                                 Oid *typid, int32 *typmod)
 {
        HeapTuple       tp;
+       Form_pg_attribute att_tup;
 
-       tp = SearchSysCacheTuple(ATTNUM,
-                                                        ObjectIdGetDatum(relid),
-                                                        UInt16GetDatum(attnum),
-                                                        0, 0);
-       if (HeapTupleIsValid(tp))
-       {
-               Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
-               return att_tup->atttypmod;
-       }
-       else
-               return -1;
+       tp = SearchSysCache(ATTNUM,
+                                               ObjectIdGetDatum(relid),
+                                               Int16GetDatum(attnum),
+                                               0, 0);
+       if (!HeapTupleIsValid(tp))
+               elog(ERROR, "cache lookup failed for attribute %d of relation %u",
+                        attnum, relid);
+       att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+
+       *typid = att_tup->atttypid;
+       *typmod = att_tup->atttypmod;
+       ReleaseSysCache(tp);
 }
 
 /*                             ---------- INDEX CACHE ----------                                                */
@@ -180,34 +383,89 @@ get_atttypmod(Oid relid, AttrNumber attnum)
 /*             watch this space...
  */
 
+/*                             ---------- OPCLASS CACHE ----------                                              */
+
+/*
+ * opclass_is_btree
+ *
+ *             Returns TRUE iff the specified opclass is associated with the
+ *             btree index access method.
+ */
+bool
+opclass_is_btree(Oid opclass)
+{
+       HeapTuple       tp;
+       Form_pg_opclass cla_tup;
+       bool            result;
+
+       tp = SearchSysCache(CLAOID,
+                                               ObjectIdGetDatum(opclass),
+                                               0, 0, 0);
+       if (!HeapTupleIsValid(tp))
+               elog(ERROR, "cache lookup failed for opclass %u", opclass);
+       cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
+
+       result = (cla_tup->opcamid == BTREE_AM_OID);
+       ReleaseSysCache(tp);
+       return result;
+}
+
+/*
+ * opclass_is_hash
+ *
+ *             Returns TRUE iff the specified opclass is associated with the
+ *             hash index access method.
+ */
+bool
+opclass_is_hash(Oid opclass)
+{
+       HeapTuple       tp;
+       Form_pg_opclass cla_tup;
+       bool            result;
+
+       tp = SearchSysCache(CLAOID,
+                                               ObjectIdGetDatum(opclass),
+                                               0, 0, 0);
+       if (!HeapTupleIsValid(tp))
+               elog(ERROR, "cache lookup failed for opclass %u", opclass);
+       cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
+
+       result = (cla_tup->opcamid == HASH_AM_OID);
+       ReleaseSysCache(tp);
+       return result;
+}
+
 /*                             ---------- OPERATOR CACHE ----------                                     */
 
 /*
- * get_opcode -
+ * get_opcode
  *
  *             Returns the regproc id of the routine used to implement an
  *             operator given the operator oid.
- *
  */
 RegProcedure
 get_opcode(Oid opno)
 {
        HeapTuple       tp;
 
-       tp = SearchSysCacheTuple(OPROID,
-                                                        ObjectIdGetDatum(opno),
-                                                        0, 0, 0);
+       tp = SearchSysCache(OPEROID,
+                                               ObjectIdGetDatum(opno),
+                                               0, 0, 0);
        if (HeapTupleIsValid(tp))
        {
                Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
-               return optup->oprcode;
+               RegProcedure result;
+
+               result = optup->oprcode;
+               ReleaseSysCache(tp);
+               return result;
        }
        else
-               return (RegProcedure) NULL;
+               return (RegProcedure) InvalidOid;
 }
 
 /*
- * get_opname -
+ * get_opname
  *       returns the name of the operator with the given opno
  *
  * Note: returns a palloc'd copy of the string, or NULL if no such operator.
@@ -217,337 +475,1620 @@ get_opname(Oid opno)
 {
        HeapTuple       tp;
 
-       tp = SearchSysCacheTuple(OPROID,
-                                                        ObjectIdGetDatum(opno),
-                                                        0, 0, 0);
+       tp = SearchSysCache(OPEROID,
+                                               ObjectIdGetDatum(opno),
+                                               0, 0, 0);
        if (HeapTupleIsValid(tp))
        {
                Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
-               return pstrdup(optup->oprname.data);
+               char       *result;
+
+               result = pstrdup(NameStr(optup->oprname));
+               ReleaseSysCache(tp);
+               return result;
        }
        else
                return NULL;
 }
 
 /*
- * op_mergejoinable -
+ * op_input_types
  *
- *             Returns the left and right sort operators and types corresponding to a
- *             mergejoinable operator, or nil if the operator is not mergejoinable.
+ *             Returns the left and right input datatypes for an operator
+ *             (InvalidOid if not relevant).
+ */
+void
+op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
+{
+       HeapTuple       tp;
+       Form_pg_operator optup;
+
+       tp = SearchSysCache(OPEROID,
+                                               ObjectIdGetDatum(opno),
+                                               0, 0, 0);
+       if (!HeapTupleIsValid(tp))      /* shouldn't happen */
+               elog(ERROR, "cache lookup failed for operator %u", opno);
+       optup = (Form_pg_operator) GETSTRUCT(tp);
+       *lefttype = optup->oprleft;
+       *righttype = optup->oprright;
+       ReleaseSysCache(tp);
+}
+
+/*
+ * op_mergejoinable
  *
+ *             Returns the left and right sort operators corresponding to a
+ *             mergejoinable operator, or false if the operator is not mergejoinable.
  */
 bool
-op_mergejoinable(Oid opno, Oid ltype, Oid rtype, Oid *leftOp, Oid *rightOp)
+op_mergejoinable(Oid opno, Oid *leftOp, Oid *rightOp)
 {
        HeapTuple       tp;
+       bool            result = false;
 
-       tp = SearchSysCacheTuple(OPROID,
-                                                        ObjectIdGetDatum(opno),
-                                                        0, 0, 0);
+       tp = SearchSysCache(OPEROID,
+                                               ObjectIdGetDatum(opno),
+                                               0, 0, 0);
        if (HeapTupleIsValid(tp))
        {
                Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
 
                if (optup->oprlsortop &&
-                       optup->oprrsortop &&
-                       optup->oprleft == ltype &&
-                       optup->oprright == rtype)
+                       optup->oprrsortop)
                {
-                       *leftOp = ObjectIdGetDatum(optup->oprlsortop);
-                       *rightOp = ObjectIdGetDatum(optup->oprrsortop);
-                       return true;
+                       *leftOp = optup->oprlsortop;
+                       *rightOp = optup->oprrsortop;
+                       result = true;
                }
+               ReleaseSysCache(tp);
        }
-       return false;
+       return result;
 }
 
 /*
- * op_hashjoinable
+ * op_mergejoin_crossops
  *
- * Returns the hash operator corresponding to a hashjoinable operator,
- * or nil if the operator is not hashjoinable.
+ *             Returns the cross-type comparison operators (ltype "<" rtype and
+ *             ltype ">" rtype) for an operator previously determined to be
+ *             mergejoinable.  Optionally, fetches the regproc ids of these
+ *             operators, as well as their operator OIDs.
+ */
+void
+op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
+                                         RegProcedure *ltproc, RegProcedure *gtproc)
+{
+       HeapTuple       tp;
+       Form_pg_operator optup;
+
+       /*
+        * Get the declared comparison operators of the operator.
+        */
+       tp = SearchSysCache(OPEROID,
+                                               ObjectIdGetDatum(opno),
+                                               0, 0, 0);
+       if (!HeapTupleIsValid(tp))      /* shouldn't happen */
+               elog(ERROR, "cache lookup failed for operator %u", opno);
+       optup = (Form_pg_operator) GETSTRUCT(tp);
+       *ltop = optup->oprltcmpop;
+       *gtop = optup->oprgtcmpop;
+       ReleaseSysCache(tp);
+
+       /* Check < op provided */
+       if (!OidIsValid(*ltop))
+               elog(ERROR, "mergejoin operator %u has no matching < operator",
+                        opno);
+       if (ltproc)
+               *ltproc = get_opcode(*ltop);
+
+       /* Check > op provided */
+       if (!OidIsValid(*gtop))
+               elog(ERROR, "mergejoin operator %u has no matching > operator",
+                        opno);
+       if (gtproc)
+               *gtproc = get_opcode(*gtop);
+}
+
+/*
+ * op_hashjoinable
  *
+ * Returns true if the operator is hashjoinable.
  */
-Oid
-op_hashjoinable(Oid opno, Oid ltype, Oid rtype)
+bool
+op_hashjoinable(Oid opno)
 {
        HeapTuple       tp;
+       bool            result = false;
 
-       tp = SearchSysCacheTuple(OPROID,
-                                                        ObjectIdGetDatum(opno),
-                                                        0, 0, 0);
+       tp = SearchSysCache(OPEROID,
+                                               ObjectIdGetDatum(opno),
+                                               0, 0, 0);
        if (HeapTupleIsValid(tp))
        {
                Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
 
-               if (optup->oprcanhash &&
-                       optup->oprleft == ltype &&
-                       optup->oprright == rtype)
-                       return opno;
+               result = optup->oprcanhash;
+               ReleaseSysCache(tp);
        }
-       return InvalidOid;
+       return result;
+}
+
+/*
+ * op_strict
+ *
+ * Get the proisstrict flag for the operator's underlying function.
+ */
+bool
+op_strict(Oid opno)
+{
+       RegProcedure funcid = get_opcode(opno);
+
+       if (funcid == (RegProcedure) InvalidOid)
+               elog(ERROR, "operator %u does not exist", opno);
+
+       return func_strict((Oid) funcid);
 }
 
-HeapTuple
-get_operator_tuple(Oid opno)
+/*
+ * op_volatile
+ *
+ * Get the provolatile flag for the operator's underlying function.
+ */
+char
+op_volatile(Oid opno)
 {
-       HeapTuple       optup;
+       RegProcedure funcid = get_opcode(opno);
 
-       if ((optup = SearchSysCacheTuple(OPROID,
-                                                                        ObjectIdGetDatum(opno),
-                                                                        0, 0, 0)))
-               return optup;
-       else
-               return (HeapTuple) NULL;
+       if (funcid == (RegProcedure) InvalidOid)
+               elog(ERROR, "operator %u does not exist", opno);
+
+       return func_volatile((Oid) funcid);
 }
 
 /*
- * get_commutator -
+ * get_commutator
  *
  *             Returns the corresponding commutator of an operator.
- *
  */
 Oid
 get_commutator(Oid opno)
 {
        HeapTuple       tp;
 
-       tp = SearchSysCacheTuple(OPROID,
-                                                        ObjectIdGetDatum(opno),
-                                                        0, 0, 0);
+       tp = SearchSysCache(OPEROID,
+                                               ObjectIdGetDatum(opno),
+                                               0, 0, 0);
        if (HeapTupleIsValid(tp))
        {
                Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
-               return optup->oprcom;
+               Oid                     result;
+
+               result = optup->oprcom;
+               ReleaseSysCache(tp);
+               return result;
        }
        else
                return InvalidOid;
 }
 
 /*
- * get_negator -
+ * get_negator
  *
  *             Returns the corresponding negator of an operator.
- *
  */
 Oid
 get_negator(Oid opno)
 {
        HeapTuple       tp;
 
-       tp = SearchSysCacheTuple(OPROID,
-                                                        ObjectIdGetDatum(opno),
-                                                        0, 0, 0);
+       tp = SearchSysCache(OPEROID,
+                                               ObjectIdGetDatum(opno),
+                                               0, 0, 0);
        if (HeapTupleIsValid(tp))
        {
                Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
-               return optup->oprnegate;
+               Oid                     result;
+
+               result = optup->oprnegate;
+               ReleaseSysCache(tp);
+               return result;
        }
        else
                return InvalidOid;
 }
 
 /*
- * get_oprrest -
+ * get_oprrest
  *
  *             Returns procedure id for computing selectivity of an operator.
- *
  */
 RegProcedure
 get_oprrest(Oid opno)
 {
        HeapTuple       tp;
 
-       tp = SearchSysCacheTuple(OPROID,
-                                                        ObjectIdGetDatum(opno),
-                                                        0, 0, 0);
+       tp = SearchSysCache(OPEROID,
+                                               ObjectIdGetDatum(opno),
+                                               0, 0, 0);
        if (HeapTupleIsValid(tp))
        {
                Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
-               return optup->oprrest;
+               RegProcedure result;
+
+               result = optup->oprrest;
+               ReleaseSysCache(tp);
+               return result;
        }
        else
-               return (RegProcedure) NULL;
+               return (RegProcedure) InvalidOid;
 }
 
 /*
- * get_oprjoin -
+ * get_oprjoin
  *
  *             Returns procedure id for computing selectivity of a join.
- *
  */
 RegProcedure
 get_oprjoin(Oid opno)
 {
        HeapTuple       tp;
 
-       tp = SearchSysCacheTuple(OPROID,
-                                                        ObjectIdGetDatum(opno),
-                                                        0, 0, 0);
+       tp = SearchSysCache(OPEROID,
+                                               ObjectIdGetDatum(opno),
+                                               0, 0, 0);
        if (HeapTupleIsValid(tp))
        {
                Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
-               return optup->oprjoin;
+               RegProcedure result;
+
+               result = optup->oprjoin;
+               ReleaseSysCache(tp);
+               return result;
        }
        else
-               return (RegProcedure) NULL;
+               return (RegProcedure) InvalidOid;
 }
 
-/*                             ---------- RELATION CACHE ----------                                     */
+/*                             ---------- FUNCTION CACHE ----------                                     */
 
 /*
- * get_relnatts -
- *
- *             Returns the number of attributes for a given relation.
+ * get_func_name
+ *       returns the name of the function with the given funcid
  *
+ * Note: returns a palloc'd copy of the string, or NULL if no such function.
  */
-int
-get_relnatts(Oid relid)
+char *
+get_func_name(Oid funcid)
 {
        HeapTuple       tp;
 
-       tp = SearchSysCacheTuple(RELOID,
-                                                        ObjectIdGetDatum(relid),
-                                                        0, 0, 0);
+       tp = SearchSysCache(PROCOID,
+                                               ObjectIdGetDatum(funcid),
+                                               0, 0, 0);
        if (HeapTupleIsValid(tp))
        {
-               Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
-               return reltup->relnatts;
+               Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
+               char       *result;
+
+               result = pstrdup(NameStr(functup->proname));
+               ReleaseSysCache(tp);
+               return result;
        }
        else
-               return InvalidAttrNumber;
+               return NULL;
 }
 
 /*
- * get_rel_name -
- *
- *             Returns the name of a given relation.
- *
+ * get_func_rettype
+ *             Given procedure id, return the function's result type.
  */
-char *
-get_rel_name(Oid relid)
+Oid
+get_func_rettype(Oid funcid)
 {
        HeapTuple       tp;
+       Oid                     result;
 
-       tp = SearchSysCacheTuple(RELOID,
-                                                        ObjectIdGetDatum(relid),
-                                                        0, 0, 0);
-       if (HeapTupleIsValid(tp))
-       {
-               Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
-               return pstrdup(reltup->relname.data);
-       }
-       else
-               return NULL;
-}
+       tp = SearchSysCache(PROCOID,
+                                               ObjectIdGetDatum(funcid),
+                                               0, 0, 0);
+       if (!HeapTupleIsValid(tp))
+               elog(ERROR, "cache lookup failed for function %u", funcid);
 
-/*                             ---------- TYPE CACHE ----------                                                 */
+       result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype;
+       ReleaseSysCache(tp);
+       return result;
+}
 
 /*
- * get_typlen -
- *
- *             Given the type OID, return the length of the type.
- *
+ * get_func_nargs
+ *             Given procedure id, return the number of arguments.
  */
-int16
-get_typlen(Oid typid)
+int
+get_func_nargs(Oid funcid)
 {
        HeapTuple       tp;
+       int                     result;
 
-       tp = SearchSysCacheTuple(TYPOID,
-                                                        ObjectIdGetDatum(typid),
-                                                        0, 0, 0);
-       if (HeapTupleIsValid(tp))
-       {
-               Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
-               return typtup->typlen;
-       }
-       else
-               return 0;
+       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))->pronargs;
+       ReleaseSysCache(tp);
+       return result;
 }
 
 /*
- * get_typbyval -
- *
- *             Given the type OID, determine whether the type is returned by value or
- *             not.  Returns 1 if by value, 0 if by reference.
+ * get_func_signature
+ *             Given procedure id, return the function's argument and result types.
+ *             (The return value is the result type.)
  *
+ * The arguments are returned as a palloc'd array.
  */
-bool
-get_typbyval(Oid typid)
+Oid
+get_func_signature(Oid funcid, Oid **argtypes, int *nargs)
 {
        HeapTuple       tp;
+       Form_pg_proc procstruct;
+       Oid                     result;
 
-       tp = SearchSysCacheTuple(TYPOID,
-                                                        ObjectIdGetDatum(typid),
-                                                        0, 0, 0);
-       if (HeapTupleIsValid(tp))
-       {
-               Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
-               return (bool) typtup->typbyval;
-       }
-       else
-               return false;
+       tp = SearchSysCache(PROCOID,
+                                               ObjectIdGetDatum(funcid),
+                                               0, 0, 0);
+       if (!HeapTupleIsValid(tp))
+               elog(ERROR, "cache lookup failed for function %u", funcid);
+
+       procstruct = (Form_pg_proc) GETSTRUCT(tp);
+
+       result = procstruct->prorettype;
+       *nargs = (int) procstruct->pronargs;
+       Assert(*nargs == procstruct->proargtypes.dim1);
+       *argtypes = (Oid *) palloc(*nargs * sizeof(Oid));
+       memcpy(*argtypes, procstruct->proargtypes.values, *nargs * sizeof(Oid));
+
+       ReleaseSysCache(tp);
+       return result;
 }
 
-#ifdef NOT_USED
-char
-get_typalign(Oid typid)
+/*
+ * get_func_retset
+ *             Given procedure id, return the function's proretset flag.
+ */
+bool
+get_func_retset(Oid funcid)
 {
        HeapTuple       tp;
+       bool            result;
 
-       tp = SearchSysCacheTuple(TYPOID,
-                                                        ObjectIdGetDatum(typid),
-                                                        0, 0, 0);
-       if (HeapTupleIsValid(tp))
-       {
-               Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
-               return typtup->typalign;
-       }
-       else
-               return 'i';
+       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))->proretset;
+       ReleaseSysCache(tp);
+       return result;
 }
 
+/*
+ * func_strict
+ *             Given procedure id, return the function's proisstrict flag.
+ */
+bool
+func_strict(Oid funcid)
+{
+       HeapTuple       tp;
+       bool            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))->proisstrict;
+       ReleaseSysCache(tp);
+       return result;
+}
+
+/*
+ * func_volatile
+ *             Given procedure id, return the function's provolatile flag.
+ */
+char
+func_volatile(Oid funcid)
+{
+       HeapTuple       tp;
+       char            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))->provolatile;
+       ReleaseSysCache(tp);
+       return result;
+}
+
+/*                             ---------- RELATION CACHE ----------                                     */
+
+/*
+ * get_relname_relid
+ *             Given name and namespace of a relation, look up the OID.
+ *
+ * Returns InvalidOid if there is no such relation.
+ */
+Oid
+get_relname_relid(const char *relname, Oid relnamespace)
+{
+       return GetSysCacheOid(RELNAMENSP,
+                                                 PointerGetDatum(relname),
+                                                 ObjectIdGetDatum(relnamespace),
+                                                 0, 0);
+}
+
+/*
+ * get_system_catalog_relid
+ *             Get the OID of a system catalog identified by name.
+ */
+Oid
+get_system_catalog_relid(const char *catname)
+{
+       Oid                     relid;
+
+       relid = GetSysCacheOid(RELNAMENSP,
+                                                  PointerGetDatum(catname),
+                                                  ObjectIdGetDatum(PG_CATALOG_NAMESPACE),
+                                                  0, 0);
+       if (!OidIsValid(relid))
+               elog(ERROR, "cache lookup failed for system relation %s", catname);
+
+       return relid;
+}
+
+#ifdef NOT_USED
+/*
+ * get_relnatts
+ *
+ *             Returns the number of attributes for a given relation.
+ */
+int
+get_relnatts(Oid relid)
+{
+       HeapTuple       tp;
+
+       tp = SearchSysCache(RELOID,
+                                               ObjectIdGetDatum(relid),
+                                               0, 0, 0);
+       if (HeapTupleIsValid(tp))
+       {
+               Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
+               int                     result;
+
+               result = reltup->relnatts;
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return InvalidAttrNumber;
+}
 #endif
 
 /*
- * get_typdefault -
+ * get_rel_name
+ *             Returns the name of a given relation.
  *
- *             Given the type OID, return the default value of the ADT.
+ * Returns a palloc'd copy of the string, or NULL if no such relation.
  *
+ * NOTE: since relation name is not unique, be wary of code that uses this
+ * for anything except preparing error messages.
  */
-struct varlena *
-get_typdefault(Oid typid)
+char *
+get_rel_name(Oid relid)
 {
-       struct varlena *typdefault = (struct varlena *) TypeDefaultRetrieve(typid);
+       HeapTuple       tp;
+
+       tp = SearchSysCache(RELOID,
+                                               ObjectIdGetDatum(relid),
+                                               0, 0, 0);
+       if (HeapTupleIsValid(tp))
+       {
+               Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
+               char       *result;
 
-       return typdefault;
+               result = pstrdup(NameStr(reltup->relname));
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return NULL;
 }
 
 /*
- * get_typtype -
+ * get_rel_namespace
  *
- *             Given the type OID, find if it is a basic type, a named relation
- *             or the generic type 'relation'.
- *             It returns the null char if the cache lookup fails...
+ *             Returns the pg_namespace OID associated with a given relation.
+ */
+Oid
+get_rel_namespace(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->relnamespace;
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return InvalidOid;
+}
+
+/*
+ * get_rel_type_id
+ *
+ *             Returns the pg_type OID associated with a given relation.
  *
+ * Note: not all pg_class entries have associated pg_type OIDs; so be
+ * careful to check for InvalidOid result.
  */
+Oid
+get_rel_type_id(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->reltype;
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return InvalidOid;
+}
+
+/*
+ * get_rel_relkind
+ *
+ *             Returns the relkind associated with a given relation.
+ */
+char
+get_rel_relkind(Oid relid)
+{
+       HeapTuple       tp;
+
+       tp = SearchSysCache(RELOID,
+                                               ObjectIdGetDatum(relid),
+                                               0, 0, 0);
+       if (HeapTupleIsValid(tp))
+       {
+               Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
+               char            result;
+
+               result = reltup->relkind;
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return '\0';
+}
+
+
+/*                             ---------- TYPE CACHE ----------                                                 */
+
+/*
+ * get_typisdefined
+ *
+ *             Given the type OID, determine whether the type is defined
+ *             (if not, it's only a shell).
+ */
+bool
+get_typisdefined(Oid typid)
+{
+       HeapTuple       tp;
+
+       tp = SearchSysCache(TYPEOID,
+                                               ObjectIdGetDatum(typid),
+                                               0, 0, 0);
+       if (HeapTupleIsValid(tp))
+       {
+               Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+               bool            result;
+
+               result = typtup->typisdefined;
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return false;
+}
+
+/*
+ * get_typlen
+ *
+ *             Given the type OID, return the length of the type.
+ */
+int16
+get_typlen(Oid typid)
+{
+       HeapTuple       tp;
+
+       tp = SearchSysCache(TYPEOID,
+                                               ObjectIdGetDatum(typid),
+                                               0, 0, 0);
+       if (HeapTupleIsValid(tp))
+       {
+               Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+               int16           result;
+
+               result = typtup->typlen;
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return 0;
+}
+
+/*
+ * get_typbyval
+ *
+ *             Given the type OID, determine whether the type is returned by value or
+ *             not.  Returns true if by value, false if by reference.
+ */
+bool
+get_typbyval(Oid typid)
+{
+       HeapTuple       tp;
+
+       tp = SearchSysCache(TYPEOID,
+                                               ObjectIdGetDatum(typid),
+                                               0, 0, 0);
+       if (HeapTupleIsValid(tp))
+       {
+               Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+               bool            result;
+
+               result = typtup->typbyval;
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return false;
+}
+
+/*
+ * get_typlenbyval
+ *
+ *             A two-fer: given the type OID, return both typlen and typbyval.
+ *
+ *             Since both pieces of info are needed to know how to copy a Datum,
+ *             many places need both.  Might as well get them with one cache lookup
+ *             instead of two.  Also, this routine raises an error instead of
+ *             returning a bogus value when given a bad type OID.
+ */
+void
+get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
+{
+       HeapTuple       tp;
+       Form_pg_type typtup;
+
+       tp = SearchSysCache(TYPEOID,
+                                               ObjectIdGetDatum(typid),
+                                               0, 0, 0);
+       if (!HeapTupleIsValid(tp))
+               elog(ERROR, "cache lookup failed for type %u", typid);
+       typtup = (Form_pg_type) GETSTRUCT(tp);
+       *typlen = typtup->typlen;
+       *typbyval = typtup->typbyval;
+       ReleaseSysCache(tp);
+}
+
+/*
+ * get_typlenbyvalalign
+ *
+ *             A three-fer: given the type OID, return typlen, typbyval, typalign.
+ */
+void
+get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
+                                        char *typalign)
+{
+       HeapTuple       tp;
+       Form_pg_type typtup;
+
+       tp = SearchSysCache(TYPEOID,
+                                               ObjectIdGetDatum(typid),
+                                               0, 0, 0);
+       if (!HeapTupleIsValid(tp))
+               elog(ERROR, "cache lookup failed for type %u", typid);
+       typtup = (Form_pg_type) GETSTRUCT(tp);
+       *typlen = typtup->typlen;
+       *typbyval = typtup->typbyval;
+       *typalign = typtup->typalign;
+       ReleaseSysCache(tp);
+}
+
+/*
+ * getTypeIOParam
+ *             Given a pg_type row, select the type OID to pass to I/O functions
+ *
+ * Formerly, all I/O functions were passed pg_type.typelem as their second
+ * parameter, but we now have a more complex rule about what to pass.
+ * This knowledge is intended to be centralized here --- direct references
+ * to typelem elsewhere in the code are wrong, if they are associated with
+ * I/O calls and not with actual subscripting operations!  (But see
+ * bootstrap.c, which can't conveniently use this routine.)
+ */
+Oid
+getTypeIOParam(HeapTuple typeTuple)
+{
+       Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
+
+       /*
+        * Composite types get their own OID as parameter; array types get
+        * their typelem as parameter; everybody else gets zero.
+        */
+       if (typeStruct->typtype == 'c')
+               return HeapTupleGetOid(typeTuple);
+       else
+               return typeStruct->typelem;
+}
+
+/*
+ * get_type_io_data
+ *
+ *             A six-fer:      given the type OID, return typlen, typbyval, typalign,
+ *                                     typdelim, typioparam, and IO function OID. The IO function
+ *                                     returned is controlled by IOFuncSelector
+ */
+void
+get_type_io_data(Oid typid,
+                                IOFuncSelector which_func,
+                                int16 *typlen,
+                                bool *typbyval,
+                                char *typalign,
+                                char *typdelim,
+                                Oid *typioparam,
+                                Oid *func)
+{
+       HeapTuple       typeTuple;
+       Form_pg_type typeStruct;
+
+       typeTuple = SearchSysCache(TYPEOID,
+                                                          ObjectIdGetDatum(typid),
+                                                          0, 0, 0);
+       if (!HeapTupleIsValid(typeTuple))
+               elog(ERROR, "cache lookup failed for type %u", typid);
+       typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
+
+       *typlen = typeStruct->typlen;
+       *typbyval = typeStruct->typbyval;
+       *typalign = typeStruct->typalign;
+       *typdelim = typeStruct->typdelim;
+       *typioparam = getTypeIOParam(typeTuple);
+       switch (which_func)
+       {
+               case IOFunc_input:
+                       *func = typeStruct->typinput;
+                       break;
+               case IOFunc_output:
+                       *func = typeStruct->typoutput;
+                       break;
+               case IOFunc_receive:
+                       *func = typeStruct->typreceive;
+                       break;
+               case IOFunc_send:
+                       *func = typeStruct->typsend;
+                       break;
+       }
+       ReleaseSysCache(typeTuple);
+}
+
 #ifdef NOT_USED
 char
-get_typtype(Oid typid)
+get_typalign(Oid typid)
 {
        HeapTuple       tp;
 
-       tp = SearchSysCacheTuple(TYPOID,
+       tp = SearchSysCache(TYPEOID,
+                                               ObjectIdGetDatum(typid),
+                                               0, 0, 0);
+       if (HeapTupleIsValid(tp))
+       {
+               Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+               char            result;
+
+               result = typtup->typalign;
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return 'i';
+}
+#endif
+
+char
+get_typstorage(Oid typid)
+{
+       HeapTuple       tp;
+
+       tp = SearchSysCache(TYPEOID,
+                                               ObjectIdGetDatum(typid),
+                                               0, 0, 0);
+       if (HeapTupleIsValid(tp))
+       {
+               Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+               char            result;
+
+               result = typtup->typstorage;
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return 'p';
+}
+
+/*
+ * get_typtypmod
+ *
+ *             Given the type OID, return the typtypmod field (domain's typmod
+ *             for base type)
+ */
+int32
+get_typtypmod(Oid typid)
+{
+       HeapTuple       tp;
+
+       tp = SearchSysCache(TYPEOID,
+                                               ObjectIdGetDatum(typid),
+                                               0, 0, 0);
+       if (HeapTupleIsValid(tp))
+       {
+               Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+               int32           result;
+
+               result = typtup->typtypmod;
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return -1;
+}
+
+/*
+ * get_typdefault
+ *       Given a type OID, return the type's default value, if any.
+ *
+ *       The result is a palloc'd expression node tree, or NULL if there
+ *       is no defined default for the datatype.
+ *
+ * NB: caller should be prepared to coerce result to correct datatype;
+ * the returned expression tree might produce something of the wrong type.
+ */
+Node *
+get_typdefault(Oid typid)
+{
+       HeapTuple       typeTuple;
+       Form_pg_type type;
+       Datum           datum;
+       bool            isNull;
+       Node       *expr;
+
+       typeTuple = SearchSysCache(TYPEOID,
+                                                          ObjectIdGetDatum(typid),
+                                                          0, 0, 0);
+       if (!HeapTupleIsValid(typeTuple))
+               elog(ERROR, "cache lookup failed for type %u", typid);
+       type = (Form_pg_type) GETSTRUCT(typeTuple);
+
+       /*
+        * typdefault and typdefaultbin are potentially null, so don't try to
+        * access 'em as struct fields. Must do it the hard way with
+        * SysCacheGetAttr.
+        */
+       datum = SysCacheGetAttr(TYPEOID,
+                                                       typeTuple,
+                                                       Anum_pg_type_typdefaultbin,
+                                                       &isNull);
+
+       if (!isNull)
+       {
+               /* We have an expression default */
+               expr = stringToNode(DatumGetCString(DirectFunctionCall1(textout,
+                                                                                                                               datum)));
+       }
+       else
+       {
+               /* Perhaps we have a plain literal default */
+               datum = SysCacheGetAttr(TYPEOID,
+                                                               typeTuple,
+                                                               Anum_pg_type_typdefault,
+                                                               &isNull);
+
+               if (!isNull)
+               {
+                       char       *strDefaultVal;
+
+                       /* Convert text datum to C string */
+                       strDefaultVal = DatumGetCString(DirectFunctionCall1(textout,
+                                                                                                                               datum));
+                       /* Convert C string to a value of the given type */
+                       datum = OidFunctionCall3(type->typinput,
+                                                                        CStringGetDatum(strDefaultVal),
+                                                        ObjectIdGetDatum(getTypeIOParam(typeTuple)),
+                                                                        Int32GetDatum(-1));
+                       /* Build a Const node containing the value */
+                       expr = (Node *) makeConst(typid,
+                                                                         type->typlen,
+                                                                         datum,
+                                                                         false,
+                                                                         type->typbyval);
+                       pfree(strDefaultVal);
+               }
+               else
+               {
+                       /* No default */
+                       expr = NULL;
+               }
+       }
+
+       ReleaseSysCache(typeTuple);
+
+       return expr;
+}
+
+/*
+ * getBaseType
+ *             If the given type is a domain, return its base type;
+ *             otherwise return the type's own OID.
+ */
+Oid
+getBaseType(Oid typid)
+{
+       /*
+        * We loop to find the bottom base type in a stack of domains.
+        */
+       for (;;)
+       {
+               HeapTuple       tup;
+               Form_pg_type typTup;
+
+               tup = SearchSysCache(TYPEOID,
                                                         ObjectIdGetDatum(typid),
                                                         0, 0, 0);
+               if (!HeapTupleIsValid(tup))
+                       elog(ERROR, "cache lookup failed for type %u", typid);
+               typTup = (Form_pg_type) GETSTRUCT(tup);
+               if (typTup->typtype != 'd')
+               {
+                       /* Not a domain, so done */
+                       ReleaseSysCache(tup);
+                       break;
+               }
+
+               typid = typTup->typbasetype;
+               ReleaseSysCache(tup);
+       }
+
+       return typid;
+}
+
+/*
+ * get_typavgwidth
+ *
+ *       Given a type OID and a typmod value (pass -1 if typmod is unknown),
+ *       estimate the average width of values of the type.  This is used by
+ *       the planner, which doesn't require absolutely correct results;
+ *       it's OK (and expected) to guess if we don't know for sure.
+ */
+int32
+get_typavgwidth(Oid typid, int32 typmod)
+{
+       int                     typlen = get_typlen(typid);
+       int32           maxwidth;
+
+       /*
+        * Easy if it's a fixed-width type
+        */
+       if (typlen > 0)
+               return typlen;
+
+       /*
+        * type_maximum_size knows the encoding of typmod for some datatypes;
+        * don't duplicate that knowledge here.
+        */
+       maxwidth = type_maximum_size(typid, typmod);
+       if (maxwidth > 0)
+       {
+               /*
+                * For BPCHAR, the max width is also the only width.  Otherwise we
+                * need to guess about the typical data width given the max. A
+                * sliding scale for percentage of max width seems reasonable.
+                */
+               if (typid == BPCHAROID)
+                       return maxwidth;
+               if (maxwidth <= 32)
+                       return maxwidth;        /* assume full width */
+               if (maxwidth < 1000)
+                       return 32 + (maxwidth - 32) / 2;        /* assume 50% */
+
+               /*
+                * Beyond 1000, assume we're looking at something like
+                * "varchar(10000)" where the limit isn't actually reached often,
+                * and use a fixed estimate.
+                */
+               return 32 + (1000 - 32) / 2;
+       }
+
+       /*
+        * Ooops, we have no idea ... wild guess time.
+        */
+       return 32;
+}
+
+/*
+ * get_typtype
+ *
+ *             Given the type OID, find if it is a basic type, a complex type, etc.
+ *             It returns the null char if the cache lookup fails...
+ */
+char
+get_typtype(Oid typid)
+{
+       HeapTuple       tp;
+
+       tp = SearchSysCache(TYPEOID,
+                                               ObjectIdGetDatum(typid),
+                                               0, 0, 0);
        if (HeapTupleIsValid(tp))
        {
                Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
-               return typtup->typtype;
+               char            result;
+
+               result = typtup->typtype;
+               ReleaseSysCache(tp);
+               return result;
        }
        else
                return '\0';
 }
 
-#endif
+/*
+ * get_typ_typrelid
+ *
+ *             Given the type OID, get the typrelid (InvalidOid if not a complex
+ *             type).
+ */
+Oid
+get_typ_typrelid(Oid typid)
+{
+       HeapTuple       tp;
+
+       tp = SearchSysCache(TYPEOID,
+                                               ObjectIdGetDatum(typid),
+                                               0, 0, 0);
+       if (HeapTupleIsValid(tp))
+       {
+               Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+               Oid                     result;
+
+               result = typtup->typrelid;
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return InvalidOid;
+}
+
+/*
+ * get_element_type
+ *
+ *             Given the type OID, get the typelem (InvalidOid if not an array type).
+ *
+ * NB: this only considers varlena arrays to be true arrays; InvalidOid is
+ * returned if the input is a fixed-length array type.
+ */
+Oid
+get_element_type(Oid typid)
+{
+       HeapTuple       tp;
+
+       tp = SearchSysCache(TYPEOID,
+                                               ObjectIdGetDatum(typid),
+                                               0, 0, 0);
+       if (HeapTupleIsValid(tp))
+       {
+               Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+               Oid                     result;
+
+               if (typtup->typlen == -1)
+                       result = typtup->typelem;
+               else
+                       result = InvalidOid;
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return InvalidOid;
+}
+
+/*
+ * get_array_type
+ *
+ *             Given the type OID, get the corresponding 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;
+
+       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;
+               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;
+}
+
+/*
+ * getTypeInputInfo
+ *
+ *             Get info needed for converting values of a type to internal form
+ */
+void
+getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
+{
+       HeapTuple       typeTuple;
+       Form_pg_type pt;
+
+       typeTuple = SearchSysCache(TYPEOID,
+                                                          ObjectIdGetDatum(type),
+                                                          0, 0, 0);
+       if (!HeapTupleIsValid(typeTuple))
+               elog(ERROR, "cache lookup failed for type %u", type);
+       pt = (Form_pg_type) GETSTRUCT(typeTuple);
+
+       if (!pt->typisdefined)
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                errmsg("type %s is only a shell",
+                                               format_type_be(type))));
+       if (!OidIsValid(pt->typinput))
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_FUNCTION),
+                                errmsg("no input function available for type %s",
+                                               format_type_be(type))));
+
+       *typInput = pt->typinput;
+       *typIOParam = getTypeIOParam(typeTuple);
+
+       ReleaseSysCache(typeTuple);
+}
+
+/*
+ * getTypeOutputInfo
+ *
+ *             Get info needed for printing values of a type
+ */
+void
+getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typIOParam,
+                                 bool *typIsVarlena)
+{
+       HeapTuple       typeTuple;
+       Form_pg_type pt;
+
+       typeTuple = SearchSysCache(TYPEOID,
+                                                          ObjectIdGetDatum(type),
+                                                          0, 0, 0);
+       if (!HeapTupleIsValid(typeTuple))
+               elog(ERROR, "cache lookup failed for type %u", type);
+       pt = (Form_pg_type) GETSTRUCT(typeTuple);
+
+       if (!pt->typisdefined)
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                errmsg("type %s is only a shell",
+                                               format_type_be(type))));
+       if (!OidIsValid(pt->typoutput))
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_FUNCTION),
+                                errmsg("no output function available for type %s",
+                                               format_type_be(type))));
+
+       *typOutput = pt->typoutput;
+       *typIOParam = getTypeIOParam(typeTuple);
+       *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
+
+       ReleaseSysCache(typeTuple);
+}
+
+/*
+ * getTypeBinaryInputInfo
+ *
+ *             Get info needed for binary input of values of a type
+ */
+void
+getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam)
+{
+       HeapTuple       typeTuple;
+       Form_pg_type pt;
+
+       typeTuple = SearchSysCache(TYPEOID,
+                                                          ObjectIdGetDatum(type),
+                                                          0, 0, 0);
+       if (!HeapTupleIsValid(typeTuple))
+               elog(ERROR, "cache lookup failed for type %u", type);
+       pt = (Form_pg_type) GETSTRUCT(typeTuple);
+
+       if (!pt->typisdefined)
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                errmsg("type %s is only a shell",
+                                               format_type_be(type))));
+       if (!OidIsValid(pt->typreceive))
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_FUNCTION),
+                                errmsg("no binary input function available for type %s",
+                                               format_type_be(type))));
+
+       *typReceive = pt->typreceive;
+       *typIOParam = getTypeIOParam(typeTuple);
+
+       ReleaseSysCache(typeTuple);
+}
+
+/*
+ * getTypeBinaryOutputInfo
+ *
+ *             Get info needed for binary output of values of a type
+ */
+void
+getTypeBinaryOutputInfo(Oid type, Oid *typSend, Oid *typIOParam,
+                                               bool *typIsVarlena)
+{
+       HeapTuple       typeTuple;
+       Form_pg_type pt;
+
+       typeTuple = SearchSysCache(TYPEOID,
+                                                          ObjectIdGetDatum(type),
+                                                          0, 0, 0);
+       if (!HeapTupleIsValid(typeTuple))
+               elog(ERROR, "cache lookup failed for type %u", type);
+       pt = (Form_pg_type) GETSTRUCT(typeTuple);
+
+       if (!pt->typisdefined)
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                errmsg("type %s is only a shell",
+                                               format_type_be(type))));
+       if (!OidIsValid(pt->typsend))
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_FUNCTION),
+                                errmsg("no binary output function available for type %s",
+                                               format_type_be(type))));
+
+       *typSend = pt->typsend;
+       *typIOParam = getTypeIOParam(typeTuple);
+       *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
+
+       ReleaseSysCache(typeTuple);
+}
+
+
+/*                             ---------- STATISTICS CACHE ----------                                   */
+
+/*
+ * get_attavgwidth
+ *
+ *       Given the table and attribute number of a column, get the average
+ *       width of entries in the column.  Return zero if no data available.
+ */
+int32
+get_attavgwidth(Oid relid, AttrNumber attnum)
+{
+       HeapTuple       tp;
+
+       tp = SearchSysCache(STATRELATT,
+                                               ObjectIdGetDatum(relid),
+                                               Int16GetDatum(attnum),
+                                               0, 0);
+       if (HeapTupleIsValid(tp))
+       {
+               int32           stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
+
+               ReleaseSysCache(tp);
+               if (stawidth > 0)
+                       return stawidth;
+       }
+       return 0;
+}
+
+/*
+ * get_attstatsslot
+ *
+ *             Extract the contents of a "slot" of a pg_statistic tuple.
+ *             Returns TRUE if requested slot type was found, else FALSE.
+ *
+ * Unlike other routines in this file, this takes a pointer to an
+ * already-looked-up tuple in the pg_statistic cache.  We do this since
+ * most callers will want to extract more than one value from the cache
+ * entry, and we don't want to repeat the cache lookup unnecessarily.
+ *
+ * statstuple: pg_statistics tuple to be examined.
+ * atttype: type OID of attribute.
+ * atttypmod: typmod of attribute.
+ * reqkind: STAKIND code for desired statistics slot kind.
+ * reqop: STAOP value wanted, or InvalidOid if don't care.
+ * values, nvalues: if not NULL, the slot's stavalues are extracted.
+ * numbers, nnumbers: if not NULL, the slot's stanumbers are extracted.
+ *
+ * If assigned, values and numbers are set to point to palloc'd arrays.
+ * If the attribute type is pass-by-reference, the values referenced by
+ * the values array are themselves palloc'd.  The palloc'd stuff can be
+ * freed by calling free_attstatsslot.
+ */
+bool
+get_attstatsslot(HeapTuple statstuple,
+                                Oid atttype, int32 atttypmod,
+                                int reqkind, Oid reqop,
+                                Datum **values, int *nvalues,
+                                float4 **numbers, int *nnumbers)
+{
+       Form_pg_statistic stats = (Form_pg_statistic) GETSTRUCT(statstuple);
+       int                     i,
+                               j;
+       Datum           val;
+       bool            isnull;
+       ArrayType  *statarray;
+       int                     narrayelem;
+       HeapTuple       typeTuple;
+       Form_pg_type typeForm;
+
+       for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
+       {
+               if ((&stats->stakind1)[i] == reqkind &&
+                       (reqop == InvalidOid || (&stats->staop1)[i] == reqop))
+                       break;
+       }
+       if (i >= STATISTIC_NUM_SLOTS)
+               return false;                   /* not there */
+
+       if (values)
+       {
+               val = SysCacheGetAttr(STATRELATT, statstuple,
+                                                         Anum_pg_statistic_stavalues1 + i,
+                                                         &isnull);
+               if (isnull)
+                       elog(ERROR, "stavalues is null");
+               statarray = DatumGetArrayTypeP(val);
+
+               /* Need to get info about the array element type */
+               typeTuple = SearchSysCache(TYPEOID,
+                                                                  ObjectIdGetDatum(atttype),
+                                                                  0, 0, 0);
+               if (!HeapTupleIsValid(typeTuple))
+                       elog(ERROR, "cache lookup failed for type %u", atttype);
+               typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
+
+               /* Deconstruct array into Datum elements */
+               deconstruct_array(statarray,
+                                                 atttype,
+                                                 typeForm->typlen,
+                                                 typeForm->typbyval,
+                                                 typeForm->typalign,
+                                                 values, nvalues);
+
+               /*
+                * If the element type is pass-by-reference, we now have a bunch
+                * of Datums that are pointers into the syscache value.  Copy them
+                * to avoid problems if syscache decides to drop the entry.
+                */
+               if (!typeForm->typbyval)
+               {
+                       for (j = 0; j < *nvalues; j++)
+                       {
+                               (*values)[j] = datumCopy((*values)[j],
+                                                                                typeForm->typbyval,
+                                                                                typeForm->typlen);
+                       }
+               }
+
+               ReleaseSysCache(typeTuple);
+
+               /*
+                * Free statarray if it's a detoasted copy.
+                */
+               if ((Pointer) statarray != DatumGetPointer(val))
+                       pfree(statarray);
+       }
+
+       if (numbers)
+       {
+               val = SysCacheGetAttr(STATRELATT, statstuple,
+                                                         Anum_pg_statistic_stanumbers1 + i,
+                                                         &isnull);
+               if (isnull)
+                       elog(ERROR, "stanumbers is null");
+               statarray = DatumGetArrayTypeP(val);
+
+               /*
+                * We expect the array to be a 1-D float4 array; verify that. We
+                * don't need to use deconstruct_array() since the array data is
+                * just going to look like a C array of float4 values.
+                */
+               narrayelem = ARR_DIMS(statarray)[0];
+               if (ARR_NDIM(statarray) != 1 || narrayelem <= 0 ||
+                       ARR_ELEMTYPE(statarray) != FLOAT4OID)
+                       elog(ERROR, "stanumbers is not a 1-D float4 array");
+               *numbers = (float4 *) palloc(narrayelem * sizeof(float4));
+               memcpy(*numbers, ARR_DATA_PTR(statarray), narrayelem * sizeof(float4));
+               *nnumbers = narrayelem;
+
+               /*
+                * Free statarray if it's a detoasted copy.
+                */
+               if ((Pointer) statarray != DatumGetPointer(val))
+                       pfree(statarray);
+       }
+
+       return true;
+}
+
+void
+free_attstatsslot(Oid atttype,
+                                 Datum *values, int nvalues,
+                                 float4 *numbers, int nnumbers)
+{
+       if (values)
+       {
+               if (!get_typbyval(atttype))
+               {
+                       int                     i;
+
+                       for (i = 0; i < nvalues; i++)
+                               pfree(DatumGetPointer(values[i]));
+               }
+               pfree(values);
+       }
+       if (numbers)
+               pfree(numbers);
+}
+
+/*                             ---------- PG_NAMESPACE CACHE ----------                                 */
+
+/*
+ * get_namespace_name
+ *             Returns the name of a given namespace
+ *
+ * Returns a palloc'd copy of the string, or NULL if no such namespace.
+ */
+char *
+get_namespace_name(Oid nspid)
+{
+       HeapTuple       tp;
+
+       tp = SearchSysCache(NAMESPACEOID,
+                                               ObjectIdGetDatum(nspid),
+                                               0, 0, 0);
+       if (HeapTupleIsValid(tp))
+       {
+               Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp);
+               char       *result;
+
+               result = pstrdup(NameStr(nsptup->nspname));
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return NULL;
+}
+
+/*                             ---------- PG_SHADOW CACHE ----------                                    */
+
+/*
+ * get_usesysid
+ *
+ *       Given a user name, look up the user's sysid.
+ *       Raises an error if no such user (rather than returning zero,
+ *       which might possibly be a valid usesysid).
+ *
+ * Note: the type of usesysid is currently int4, but may change to Oid
+ * someday.  It'd be reasonable to return zero on failure if we were
+ * using Oid ...
+ */
+AclId
+get_usesysid(const char *username)
+{
+       AclId           userId;
+       HeapTuple       userTup;
+
+       userTup = SearchSysCache(SHADOWNAME,
+                                                        PointerGetDatum(username),
+                                                        0, 0, 0);
+       if (!HeapTupleIsValid(userTup))
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                errmsg("user \"%s\" does not exist", username)));
+
+       userId = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;
+
+       ReleaseSysCache(userTup);
+
+       return userId;
+}
+
+/*
+ * get_grosysid
+ *
+ *       Given a group name, look up the group's sysid.
+ *       Raises an error if no such group (rather than returning zero,
+ *       which might possibly be a valid grosysid).
+ *
+ */
+AclId
+get_grosysid(char *groname)
+{
+       AclId           groupId;
+       HeapTuple       groupTup;
+
+       groupTup = SearchSysCache(GRONAME,
+                                                  PointerGetDatum(groname),
+                                                  0, 0, 0);
+       if (!HeapTupleIsValid(groupTup))
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                errmsg("group \"%s\" does not exist", groname)));
+
+       groupId = ((Form_pg_group) GETSTRUCT(groupTup))->grosysid;
+
+       ReleaseSysCache(groupTup);
+
+       return groupId;
+}
+