]> 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 26d06c440fe5336d557598c035d39c7ec7777e35..2c4d20576a5552da22c9e6912c261d646a711798 100644 (file)
@@ -3,11 +3,11 @@
  * 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-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.92 2003/04/08 23:20:02 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 "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"
 #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"
@@ -44,51 +48,182 @@ bool
 op_in_opclass(Oid opno, Oid opclass)
 {
        return SearchSysCacheExists(AMOPOPID,
-                                                               ObjectIdGetDatum(opclass),
                                                                ObjectIdGetDatum(opno),
+                                                               ObjectIdGetDatum(opclass),
                                                                0, 0);
 }
 
 /*
- * op_requires_recheck
+ * 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
  *
- *             Return t if operator 'opno' requires a recheck when used as a
- *             member of opclass 'opclass' (ie, this opclass is lossy for this
- *             operator).
+ *             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.
  */
-bool
-op_requires_recheck(Oid opno, Oid opclass)
+void
+get_op_opclass_properties(Oid opno, Oid opclass,
+                                                 int *strategy, Oid *subtype, bool *recheck)
 {
        HeapTuple       tp;
        Form_pg_amop amop_tup;
-       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);
+       *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;
 
-       result = amop_tup->amopreqcheck;
+       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_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 operator.
+ * Note: returns a palloc'd copy of the string, or NULL if no such attribute.
  */
 char *
 get_attname(Oid relid, AttrNumber attnum)
@@ -112,6 +247,24 @@ 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
  *
@@ -216,8 +369,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;
@@ -257,6 +410,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 ----------                                     */
 
 /*
@@ -313,6 +491,29 @@ get_opname(Oid opno)
                return NULL;
 }
 
+/*
+ * op_input_types
+ *
+ *             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
  *
@@ -366,7 +567,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;
@@ -374,14 +575,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);
@@ -422,7 +623,7 @@ op_strict(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_strict((Oid) funcid);
 }
@@ -438,7 +639,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);
 }
@@ -590,13 +791,66 @@ 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_nargs
+ *             Given procedure id, return the number of arguments.
+ */
+int
+get_func_nargs(Oid funcid)
+{
+       HeapTuple       tp;
+       int                     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))->pronargs;
+       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.)
+ *
+ * The arguments are returned as a palloc'd array.
+ */
+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;
+       *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;
+}
+
 /*
  * get_func_retset
  *             Given procedure id, return the function's proretset flag.
@@ -611,7 +865,7 @@ 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);
@@ -632,7 +886,7 @@ func_strict(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))->proisstrict;
        ReleaseSysCache(tp);
@@ -653,7 +907,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);
@@ -691,7 +945,7 @@ get_system_catalog_relid(const char *catname)
                                                   ObjectIdGetDatum(PG_CATALOG_NAMESPACE),
                                                   0, 0);
        if (!OidIsValid(relid))
-               elog(ERROR, "get_system_catalog_relid: cannot find %s", catname);
+               elog(ERROR, "cache lookup failed for system relation %s", catname);
 
        return relid;
 }
@@ -969,6 +1223,82 @@ get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
        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_typalign(Oid typid)
@@ -1063,7 +1393,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);
 
        /*
@@ -1100,7 +1430,7 @@ get_typdefault(Oid typid)
                        /* Convert C string to a value of the given type */
                        datum = OidFunctionCall3(type->typinput,
                                                                         CStringGetDatum(strDefaultVal),
-                                                                        ObjectIdGetDatum(type->typelem),
+                                                        ObjectIdGetDatum(getTypeIOParam(typeTuple)),
                                                                         Int32GetDatum(-1));
                        /* Build a Const node containing the value */
                        expr = (Node *) makeConst(typid,
@@ -1142,7 +1472,7 @@ getBaseType(Oid typid)
                                                         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')
                {
@@ -1352,7 +1682,7 @@ get_array_type(Oid typid)
  *             Get info needed for converting values of a type to internal form
  */
 void
-getTypeInputInfo(Oid type, Oid *typInput, Oid *typElem)
+getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
 {
        HeapTuple       typeTuple;
        Form_pg_type pt;
@@ -1361,14 +1691,22 @@ getTypeInputInfo(Oid type, Oid *typInput, Oid *typElem)
                                                           ObjectIdGetDatum(type),
                                                           0, 0, 0);
        if (!HeapTupleIsValid(typeTuple))
-               elog(ERROR, "getTypeInputInfo: Cache lookup of type %u failed", type);
+               elog(ERROR, "cache lookup failed for type %u", type);
        pt = (Form_pg_type) GETSTRUCT(typeTuple);
 
        if (!pt->typisdefined)
-               elog(ERROR, "Type \"%s\" is only a shell", NameStr(pt->typname));
+               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;
+       *typIOParam = getTypeIOParam(typeTuple);
 
        ReleaseSysCache(typeTuple);
 }
@@ -1377,11 +1715,9 @@ getTypeInputInfo(Oid type, Oid *typInput, Oid *typElem)
  * getTypeOutputInfo
  *
  *             Get info needed for printing values of a type
- *
- * Returns true if data valid (a false result probably means it's a shell type)
  */
-bool
-getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typElem,
+void
+getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typIOParam,
                                  bool *typIsVarlena)
 {
        HeapTuple       typeTuple;
@@ -1391,14 +1727,97 @@ getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typElem,
                                                           ObjectIdGetDatum(type),
                                                           0, 0, 0);
        if (!HeapTupleIsValid(typeTuple))
-               elog(ERROR, "getTypeOutputInfo: Cache lookup of type %u failed", type);
+               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;
+       *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);
-       return OidIsValid(*typOutput);
 }
 
 
@@ -1486,7 +1905,7 @@ 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);
 
                /* Need to get info about the array element type */
@@ -1494,8 +1913,7 @@ get_attstatsslot(HeapTuple statstuple,
                                                                   ObjectIdGetDatum(atttype),
                                                                   0, 0, 0);
                if (!HeapTupleIsValid(typeTuple))
-                       elog(ERROR, "get_attstatsslot: Cache lookup failed for type %u",
-                                atttype);
+                       elog(ERROR, "cache lookup failed for type %u", atttype);
                typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
 
                /* Deconstruct array into Datum elements */
@@ -1536,7 +1954,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);
 
                /*
@@ -1547,7 +1965,7 @@ get_attstatsslot(HeapTuple statstuple,
                narrayelem = ARR_DIMS(statarray)[0];
                if (ARR_NDIM(statarray) != 1 || narrayelem <= 0 ||
                        ARR_ELEMTYPE(statarray) != FLOAT4OID)
-                       elog(ERROR, "get_attstatsslot: stanumbers is not a 1-D float4 array");
+                       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;
@@ -1627,18 +2045,50 @@ get_namespace_name(Oid nspid)
 AclId
 get_usesysid(const char *username)
 {
-       int32           result;
+       AclId           userId;
        HeapTuple       userTup;
 
        userTup = SearchSysCache(SHADOWNAME,
                                                         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;
+       userId = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;
 
        ReleaseSysCache(userTup);
 
-       return result;
+       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;
+}
+