]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/cache/lsyscache.c
Create a 'type cache' that keeps track of the data needed for any particular
[postgresql] / src / backend / utils / cache / lsyscache.c
index 5063225afce29cd00eaad96f08248726d850d54c..3864a2fa52b4f1bdc5bfeeff45cb02169bc9e746 100644 (file)
@@ -3,20 +3,23 @@
  * lsyscache.c
  *       Convenience routines for common queries in the system catalog cache.
  *
- * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2003, 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.75 2002/07/06 20:16:36 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.107 2003/08/17 19:58:06 tgl Exp $
  *
  * NOTES
  *       Eventually, the index information should go through here, too.
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
+#include "miscadmin.h"
 
+#include "access/hash.h"
 #include "access/tupmacs.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"
@@ -27,6 +30,8 @@
 #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"
 
@@ -42,8 +47,8 @@ bool
 op_in_opclass(Oid opno, Oid opclass)
 {
        return SearchSysCacheExists(AMOPOPID,
-                                                               ObjectIdGetDatum(opclass),
                                                                ObjectIdGetDatum(opno),
+                                                               ObjectIdGetDatum(opclass),
                                                                0, 0);
 }
 
@@ -65,11 +70,11 @@ op_requires_recheck(Oid opno, Oid opclass)
        bool            result;
 
        tp = SearchSysCache(AMOPOPID,
-                                               ObjectIdGetDatum(opclass),
                                                ObjectIdGetDatum(opno),
+                                               ObjectIdGetDatum(opclass),
                                                0, 0);
        if (!HeapTupleIsValid(tp))
-               elog(ERROR, "op_requires_recheck: op %u is not a member of opclass %u",
+               elog(ERROR, "operator %u is not a member of opclass %u",
                         opno, opclass);
        amop_tup = (Form_pg_amop) GETSTRUCT(tp);
 
@@ -78,15 +83,120 @@ op_requires_recheck(Oid opno, Oid opclass)
        return result;
 }
 
+/*
+ * get_opclass_member
+ *             Get the OID of the operator that implements the specified strategy
+ *             for the specified opclass.
+ *
+ * Returns InvalidOid if there is no pg_amop entry for the given keys.
+ */
+Oid
+get_opclass_member(Oid opclass, int16 strategy)
+{
+       HeapTuple       tp;
+       Form_pg_amop amop_tup;
+       Oid                     result;
+
+       tp = SearchSysCache(AMOPSTRATEGY,
+                                               ObjectIdGetDatum(opclass),
+                                               Int16GetDatum(strategy),
+                                               0, 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 hash support function */
+               return get_opclass_proc(opclass, HASHPROC);
+       }
+
+       /* Didn't find a match... */
+       return InvalidOid;
+}
+
+
+/*                             ---------- AMPROC CACHES ----------                                              */
+
+/*
+ * get_opclass_proc
+ *             Get the OID of the specified support function
+ *             for the specified opclass.
+ *
+ * Returns InvalidOid if there is no pg_amproc entry for the given keys.
+ */
+Oid
+get_opclass_proc(Oid opclass, int16 procnum)
+{
+       HeapTuple       tp;
+       Form_pg_amproc amproc_tup;
+       RegProcedure result;
+
+       tp = SearchSysCache(AMPROCNUM,
+                                               ObjectIdGetDatum(opclass),
+                                               Int16GetDatum(procnum),
+                                               0, 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 operator.
+ * Note: returns a palloc'd copy of the string, or NULL if no such attribute.
  */
 char *
 get_attname(Oid relid, AttrNumber attnum)
@@ -110,21 +220,38 @@ get_attname(Oid relid, AttrNumber attnum)
                return NULL;
 }
 
+/*
+ * 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 = SearchSysCache(ATTNAME,
-                                               ObjectIdGetDatum(relid),
-                                               PointerGetDatum(attname),
-                                               0, 0);
+       tp = SearchSysCacheAttName(relid, attname);
        if (HeapTupleIsValid(tp))
        {
                Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
@@ -166,32 +293,6 @@ get_atttype(Oid relid, AttrNumber attnum)
                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.
- */
-bool
-get_attisset(Oid relid, char *attname)
-{
-       HeapTuple       tp;
-
-       tp = SearchSysCache(ATTNAME,
-                                               ObjectIdGetDatum(relid),
-                                               PointerGetDatum(attname),
-                                               0, 0);
-       if (HeapTupleIsValid(tp))
-       {
-               Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
-               bool            result;
-
-               result = att_tup->attisset;
-               ReleaseSysCache(tp);
-               return result;
-       }
-       else
-               return false;
-}
-
 /*
  * get_atttypmod
  *
@@ -241,8 +342,8 @@ get_atttypetypmod(Oid relid, AttrNumber attnum,
                                                Int16GetDatum(attnum),
                                                0, 0);
        if (!HeapTupleIsValid(tp))
-               elog(ERROR, "cache lookup failed for relation %u attribute %d",
-                        relid, attnum);
+               elog(ERROR, "cache lookup failed for attribute %d of relation %u",
+                        attnum, relid);
        att_tup = (Form_pg_attribute) GETSTRUCT(tp);
 
        *typid = att_tup->atttypid;
@@ -282,6 +383,31 @@ opclass_is_btree(Oid opclass)
        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 ----------                                     */
 
 /*
@@ -341,11 +467,11 @@ get_opname(Oid opno)
 /*
  * op_mergejoinable
  *
- *             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 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;
@@ -358,9 +484,7 @@ op_mergejoinable(Oid opno, Oid ltype, Oid rtype, Oid *leftOp, Oid *rightOp)
                Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
 
                if (optup->oprlsortop &&
-                       optup->oprrsortop &&
-                       optup->oprleft == ltype &&
-                       optup->oprright == rtype)
+                       optup->oprrsortop)
                {
                        *leftOp = optup->oprlsortop;
                        *rightOp = optup->oprrsortop;
@@ -376,7 +500,7 @@ op_mergejoinable(Oid opno, Oid ltype, Oid rtype, Oid *leftOp, Oid *rightOp)
  *
  *             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
+ *             mergejoinable.  Optionally, fetches the regproc ids of these
  *             operators, as well as their operator OIDs.
  */
 void
@@ -393,7 +517,7 @@ op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
                                                ObjectIdGetDatum(opno),
                                                0, 0, 0);
        if (!HeapTupleIsValid(tp))      /* shouldn't happen */
-               elog(ERROR, "op_mergejoin_crossops: operator %u not found", opno);
+               elog(ERROR, "cache lookup failed for operator %u", opno);
        optup = (Form_pg_operator) GETSTRUCT(tp);
        *ltop = optup->oprltcmpop;
        *gtop = optup->oprgtcmpop;
@@ -401,14 +525,14 @@ op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
 
        /* Check < op provided */
        if (!OidIsValid(*ltop))
-               elog(ERROR, "op_mergejoin_crossops: mergejoin operator %u has no matching < operator",
+               elog(ERROR, "mergejoin operator %u has no matching < operator",
                         opno);
        if (ltproc)
                *ltproc = get_opcode(*ltop);
 
        /* Check > op provided */
        if (!OidIsValid(*gtop))
-               elog(ERROR, "op_mergejoin_crossops: mergejoin operator %u has no matching > operator",
+               elog(ERROR, "mergejoin operator %u has no matching > operator",
                         opno);
        if (gtproc)
                *gtproc = get_opcode(*gtop);
@@ -417,14 +541,13 @@ op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
 /*
  * op_hashjoinable
  *
- * Returns the hash operator corresponding to a hashjoinable operator,
- * or InvalidOid if the operator is not hashjoinable.
+ * Returns true if the operator is hashjoinable.
  */
-Oid
-op_hashjoinable(Oid opno, Oid ltype, Oid rtype)
+bool
+op_hashjoinable(Oid opno)
 {
        HeapTuple       tp;
-       Oid                     result = InvalidOid;
+       bool            result = false;
 
        tp = SearchSysCache(OPEROID,
                                                ObjectIdGetDatum(opno),
@@ -433,15 +556,28 @@ op_hashjoinable(Oid opno, Oid ltype, Oid rtype)
        {
                Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
 
-               if (optup->oprcanhash &&
-                       optup->oprleft == ltype &&
-                       optup->oprright == rtype)
-                       result = opno;
+               result = optup->oprcanhash;
                ReleaseSysCache(tp);
        }
        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);
+}
+
 /*
  * op_volatile
  *
@@ -453,7 +589,7 @@ op_volatile(Oid opno)
        RegProcedure funcid = get_opcode(opno);
 
        if (funcid == (RegProcedure) InvalidOid)
-               elog(ERROR, "Operator OID %u does not exist", opno);
+               elog(ERROR, "operator %u does not exist", opno);
 
        return func_volatile((Oid) funcid);
 }
@@ -605,13 +741,43 @@ get_func_rettype(Oid funcid)
                                                ObjectIdGetDatum(funcid),
                                                0, 0, 0);
        if (!HeapTupleIsValid(tp))
-               elog(ERROR, "Function OID %u does not exist", funcid);
+               elog(ERROR, "cache lookup failed for function %u", funcid);
 
        result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype;
        ReleaseSysCache(tp);
        return result;
 }
 
+/*
+ * get_func_signature
+ *             Given procedure id, return the function's argument and result types.
+ *             (The return value is the result type.)
+ *
+ * argtypes must point to a vector of size FUNC_MAX_ARGS.
+ */
+Oid
+get_func_signature(Oid funcid, Oid *argtypes, int *nargs)
+{
+       HeapTuple       tp;
+       Form_pg_proc procstruct;
+       Oid                     result;
+
+       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;
+       memcpy(argtypes, procstruct->proargtypes, FUNC_MAX_ARGS * sizeof(Oid));
+       *nargs = (int) procstruct->pronargs;
+
+       ReleaseSysCache(tp);
+       return result;
+}
+
 /*
  * get_func_retset
  *             Given procedure id, return the function's proretset flag.
@@ -626,13 +792,34 @@ get_func_retset(Oid funcid)
                                                ObjectIdGetDatum(funcid),
                                                0, 0, 0);
        if (!HeapTupleIsValid(tp))
-               elog(ERROR, "Function OID %u does not exist", funcid);
+               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.
@@ -647,7 +834,7 @@ func_volatile(Oid funcid)
                                                ObjectIdGetDatum(funcid),
                                                0, 0, 0);
        if (!HeapTupleIsValid(tp))
-               elog(ERROR, "Function OID %u does not exist", funcid);
+               elog(ERROR, "cache lookup failed for function %u", funcid);
 
        result = ((Form_pg_proc) GETSTRUCT(tp))->provolatile;
        ReleaseSysCache(tp);
@@ -671,6 +858,25 @@ get_relname_relid(const char *relname, Oid 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
@@ -745,7 +951,7 @@ get_rel_namespace(Oid relid)
        if (HeapTupleIsValid(tp))
        {
                Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
-               Oid             result;
+               Oid                     result;
 
                result = reltup->relnamespace;
                ReleaseSysCache(tp);
@@ -774,7 +980,7 @@ get_rel_type_id(Oid relid)
        if (HeapTupleIsValid(tp))
        {
                Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
-               Oid             result;
+               Oid                     result;
 
                result = reltup->reltype;
                ReleaseSysCache(tp);
@@ -784,6 +990,33 @@ get_rel_type_id(Oid relid)
                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 ----------                                                 */
 
 /*
@@ -893,6 +1126,80 @@ get_typlenbyval(Oid typid, int16 *typlen, bool *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);
+}
+
+/*
+ * get_type_io_data
+ *
+ *             A six-fer:      given the type OID, return typlen, typbyval, typalign,
+ *                                     typdelim, typelem, 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 *typelem,
+                                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;
+       *typelem = typeStruct->typelem;
+       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_typalign(Oid typid)
@@ -937,6 +1244,33 @@ get_typstorage(Oid typid)
                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.
@@ -960,7 +1294,7 @@ get_typdefault(Oid typid)
                                                           ObjectIdGetDatum(typid),
                                                           0, 0, 0);
        if (!HeapTupleIsValid(typeTuple))
-               elog(ERROR, "get_typdefault: failed to lookup type %u", typid);
+               elog(ERROR, "cache lookup failed for type %u", typid);
        type = (Form_pg_type) GETSTRUCT(typeTuple);
 
        /*
@@ -1004,9 +1338,7 @@ get_typdefault(Oid typid)
                                                                          type->typlen,
                                                                          datum,
                                                                          false,
-                                                                         type->typbyval,
-                                                                         false,        /* not a set */
-                                                                         false);
+                                                                         type->typbyval);
                        pfree(strDefaultVal);
                }
                else
@@ -1041,43 +1373,7 @@ getBaseType(Oid typid)
                                                         ObjectIdGetDatum(typid),
                                                         0, 0, 0);
                if (!HeapTupleIsValid(tup))
-                       elog(ERROR, "getBaseType: failed to lookup 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;
-}
-
-/*
- * getBaseTypeTypeMod
- *             If the given type is a domain, return its base type;
- *             otherwise return the type's own OID.
- */
-Oid
-getBaseTypeTypeMod(Oid typid, int32 *typmod)
-{
-       /*
-        * 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, "getBaseType: failed to lookup type %u", typid);
+                       elog(ERROR, "cache lookup failed for type %u", typid);
                typTup = (Form_pg_type) GETSTRUCT(tup);
                if (typTup->typtype != 'd')
                {
@@ -1087,7 +1383,6 @@ getBaseTypeTypeMod(Oid typid, int32 *typmod)
                }
 
                typid = typTup->typbasetype;
-               *typmod = typTup->typtypmod;
                ReleaseSysCache(tup);
        }
 
@@ -1150,11 +1445,9 @@ get_typavgwidth(Oid typid, int32 typmod)
 /*
  * get_typtype
  *
- *             Given the type OID, find if it is a basic type, a named relation
- *             or the generic type 'relation'.
+ *             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...
  */
-#ifdef NOT_USED
 char
 get_typtype(Oid typid)
 {
@@ -1175,7 +1468,290 @@ get_typtype(Oid typid)
        else
                return '\0';
 }
-#endif
+
+/*
+ * get_typname
+ *             Returns the name of a given type.
+ *
+ * Returns a palloc'd copy of the string, or NULL if no such type.
+ *
+ * NOTE: since type name is not unique, be wary of code that uses this
+ * for anything except preparing error messages.
+ */
+char *
+get_typname(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 = pstrdup(NameStr(typtup->typname));
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return NULL;
+}
+
+
+/*
+ * 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 *typElem)
+{
+       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;
+       *typElem = pt->typelem;
+
+       ReleaseSysCache(typeTuple);
+}
+
+/*
+ * getTypeOutputInfo
+ *
+ *             Get info needed for printing values of a type
+ */
+void
+getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typElem,
+                                 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;
+       *typElem = pt->typelem;
+       *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 *typElem)
+{
+       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;
+       *typElem = pt->typelem;
+
+       ReleaseSysCache(typeTuple);
+}
+
+/*
+ * getTypeBinaryOutputInfo
+ *
+ *             Get info needed for binary output of values of a type
+ */
+void
+getTypeBinaryOutputInfo(Oid type, Oid *typSend, Oid *typElem,
+                                               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;
+       *typElem = pt->typelem;
+       *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
+
+       ReleaseSysCache(typeTuple);
+}
+
 
 /*                             ---------- STATISTICS CACHE ----------                                   */
 
@@ -1244,8 +1820,7 @@ get_attstatsslot(HeapTuple statstuple,
        ArrayType  *statarray;
        int                     narrayelem;
        HeapTuple       typeTuple;
-       FmgrInfo        inputproc;
-       Oid                     typelem;
+       Form_pg_type typeForm;
 
        for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
        {
@@ -1262,49 +1837,42 @@ get_attstatsslot(HeapTuple statstuple,
                                                          Anum_pg_statistic_stavalues1 + i,
                                                          &isnull);
                if (isnull)
-                       elog(ERROR, "get_attstatsslot: stavalues is null");
+                       elog(ERROR, "stavalues is null");
                statarray = DatumGetArrayTypeP(val);
 
-               /*
-                * Do initial examination of the array.  This produces a list of
-                * text Datums --- ie, pointers into the text array value.
-                */
-               deconstruct_array(statarray, false, -1, 'i', values, nvalues);
-               narrayelem = *nvalues;
-
-               /*
-                * We now need to replace each text Datum by its internal
-                * equivalent.
-                *
-                * Get the type input proc and typelem for the column datatype.
-                */
+               /* Need to get info about the array element type */
                typeTuple = SearchSysCache(TYPEOID,
                                                                   ObjectIdGetDatum(atttype),
                                                                   0, 0, 0);
                if (!HeapTupleIsValid(typeTuple))
-                       elog(ERROR, "get_attstatsslot: Cache lookup failed for type %u",
-                                atttype);
-               fmgr_info(((Form_pg_type) GETSTRUCT(typeTuple))->typinput, &inputproc);
-               typelem = ((Form_pg_type) GETSTRUCT(typeTuple))->typelem;
-               ReleaseSysCache(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);
 
                /*
-                * Do the conversions.  The palloc'd array of Datums is reused in
-                * place.
+                * 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.
                 */
-               for (j = 0; j < narrayelem; j++)
+               if (!typeForm->typbyval)
                {
-                       char       *strval;
-
-                       strval = DatumGetCString(DirectFunctionCall1(textout,
-                                                                                                                (*values)[j]));
-                       (*values)[j] = FunctionCall3(&inputproc,
-                                                                                CStringGetDatum(strval),
-                                                                                ObjectIdGetDatum(typelem),
-                                                                                Int32GetDatum(atttypmod));
-                       pfree(strval);
+                       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.
                 */
@@ -1318,7 +1886,7 @@ get_attstatsslot(HeapTuple statstuple,
                                                          Anum_pg_statistic_stanumbers1 + i,
                                                          &isnull);
                if (isnull)
-                       elog(ERROR, "get_attstatsslot: stanumbers is null");
+                       elog(ERROR, "stanumbers is null");
                statarray = DatumGetArrayTypeP(val);
 
                /*
@@ -1328,8 +1896,8 @@ get_attstatsslot(HeapTuple statstuple,
                 */
                narrayelem = ARR_DIMS(statarray)[0];
                if (ARR_NDIM(statarray) != 1 || narrayelem <= 0 ||
-                       ARR_SIZE(statarray) != (ARR_OVERHEAD(1) + narrayelem * sizeof(float4)))
-                       elog(ERROR, "get_attstatsslot: stanumbers is bogus");
+                       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;
@@ -1406,7 +1974,7 @@ get_namespace_name(Oid nspid)
  * someday.  It'd be reasonable to return zero on failure if we were
  * using Oid ...
  */
-int32
+AclId
 get_usesysid(const char *username)
 {
        int32           result;
@@ -1416,7 +1984,9 @@ get_usesysid(const char *username)
                                                         PointerGetDatum(username),
                                                         0, 0, 0);
        if (!HeapTupleIsValid(userTup))
-               elog(ERROR, "user \"%s\" does not exist", username);
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                errmsg("user \"%s\" does not exist", username)));
 
        result = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;