* 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.81 2002/08/29 00:17:05 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"
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;
+
+ 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);
- result = amop_tup->amopreqcheck;
+ 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)
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
*
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;
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 ---------- */
/*
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
*
- * 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;
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;
*
* 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
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;
/* 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);
/*
* 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),
{
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
*
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);
}
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.
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.
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);
Oid
get_system_catalog_relid(const char *catname)
{
- Oid relid;
+ Oid relid;
relid = GetSysCacheOid(RELNAMENSP,
PointerGetDatum(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;
}
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
- Oid result;
+ Oid result;
result = reltup->relnamespace;
ReleaseSysCache(tp);
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
- Oid result;
+ Oid result;
result = reltup->reltype;
ReleaseSysCache(tp);
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 ---------- */
/*
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)
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.
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);
/*
/* 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,
type->typlen,
datum,
false,
- type->typbyval,
- false, /* not a set */
- false);
+ type->typbyval);
pfree(strDefaultVal);
}
else
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')
{
return typid;
}
-/*
- * getBaseTypeTypeMod
- * If the given type is a domain, return its base type;
- * otherwise return the type's own OID. Also return base typmod.
- */
-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, "getBaseTypeTypeMod: 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;
- *typmod = typTup->typtypmod;
- ReleaseSysCache(tup);
- }
-
- return typid;
-}
-
/*
* get_typavgwidth
*
return '\0';
}
+/*
+ * 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)
+getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
{
HeapTuple typeTuple;
Form_pg_type pt;
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);
}
* 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;
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);
}
ArrayType *statarray;
int narrayelem;
HeapTuple typeTuple;
- FmgrInfo inputproc;
- Oid typelem;
+ Form_pg_type typeForm;
for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
{
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,
- TEXTOID, -1, false, '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.
*/
Anum_pg_statistic_stanumbers1 + i,
&isnull);
if (isnull)
- elog(ERROR, "get_attstatsslot: stanumbers is null");
+ elog(ERROR, "stanumbers is null");
statarray = DatumGetArrayTypeP(val);
/*
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;
* someday. It'd be reasonable to return zero on failure if we were
* using Oid ...
*/
-int32
+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;
+}
+