* lsyscache.c
* Convenience routines for common queries in the system catalog cache.
*
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
+ * 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.39 2000/01/26 05:57:17 momjian 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"
+
/* ---------- AMOP CACHES ---------- */
/*
- * op_class -
- *
- * Return t iff operator 'opid' is in operator class 'opclass' for
- * access method 'amopid'.
+ * op_in_opclass
*
+ * Return t iff operator 'opno' is in operator class 'opclass'.
*/
bool
-op_class(Oid opid, Oid opclass, Oid amopid)
-{
- if (HeapTupleIsValid(SearchSysCacheTuple(AMOPOPID,
- ObjectIdGetDatum(opclass),
- ObjectIdGetDatum(opid),
- ObjectIdGetDatum(amopid),
- 0)))
- return true;
- else
- return false;
+op_in_opclass(Oid opno, Oid opclass)
+{
+ return SearchSysCacheExists(AMOPOPID,
+ ObjectIdGetDatum(opno),
+ ObjectIdGetDatum(opclass),
+ 0, 0);
}
-/* ---------- ATTRIBUTE CACHES ---------- */
+/*
+ * get_op_opclass_strategy
+ *
+ * Get the operator's strategy number within the specified opclass,
+ * or 0 if it's not a member of the opclass.
+ */
+int
+get_op_opclass_strategy(Oid opno, Oid opclass)
+{
+ HeapTuple tp;
+ Form_pg_amop amop_tup;
+ int result;
+
+ tp = SearchSysCache(AMOPOPID,
+ ObjectIdGetDatum(opno),
+ ObjectIdGetDatum(opclass),
+ 0, 0);
+ if (!HeapTupleIsValid(tp))
+ return 0;
+ amop_tup = (Form_pg_amop) GETSTRUCT(tp);
+ result = amop_tup->amopstrategy;
+ ReleaseSysCache(tp);
+ return result;
+}
+
+/*
+ * get_op_opclass_properties
+ *
+ * Get the operator's strategy number, subtype, and recheck (lossy) flag
+ * within the specified opclass.
+ *
+ * Caller should already have verified that opno is a member of opclass,
+ * therefore we raise an error if the tuple is not found.
+ */
+void
+get_op_opclass_properties(Oid opno, Oid opclass,
+ int *strategy, Oid *subtype, bool *recheck)
+{
+ HeapTuple tp;
+ Form_pg_amop amop_tup;
+
+ tp = SearchSysCache(AMOPOPID,
+ ObjectIdGetDatum(opno),
+ ObjectIdGetDatum(opclass),
+ 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "operator %u is not a member of opclass %u",
+ opno, opclass);
+ amop_tup = (Form_pg_amop) GETSTRUCT(tp);
+ *strategy = amop_tup->amopstrategy;
+ *subtype = amop_tup->amopsubtype;
+ *recheck = amop_tup->amopreqcheck;
+ ReleaseSysCache(tp);
+}
+
+/*
+ * get_opclass_member
+ * Get the OID of the operator that implements the specified strategy
+ * with the specified subtype for the specified opclass.
+ *
+ * Returns InvalidOid if there is no pg_amop entry for the given keys.
+ */
+Oid
+get_opclass_member(Oid opclass, Oid subtype, int16 strategy)
+{
+ HeapTuple tp;
+ Form_pg_amop amop_tup;
+ Oid result;
+
+ tp = SearchSysCache(AMOPSTRATEGY,
+ ObjectIdGetDatum(opclass),
+ ObjectIdGetDatum(subtype),
+ Int16GetDatum(strategy),
+ 0);
+ if (!HeapTupleIsValid(tp))
+ return InvalidOid;
+ amop_tup = (Form_pg_amop) GETSTRUCT(tp);
+ result = amop_tup->amopopr;
+ ReleaseSysCache(tp);
+ return result;
+}
/*
- * get_attname -
+ * 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 attribute.
*/
char *
get_attname(Oid relid, AttrNumber attnum)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(ATTNUM,
- ObjectIdGetDatum(relid),
- UInt16GetDatum(attnum),
- 0, 0);
+ tp = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum),
+ 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
- return pstrdup(NameStr(att_tup->attname));
+ char *result;
+
+ result = pstrdup(NameStr(att_tup->attname));
+ ReleaseSysCache(tp);
+ return result;
}
else
return NULL;
}
/*
- * get_attnum -
+ * get_relid_attribute_name
+ *
+ * Same as above routine get_attname(), except that error
+ * is handled by elog() instead of returning NULL.
+ */
+char *
+get_relid_attribute_name(Oid relid, AttrNumber attnum)
+{
+ char *attname;
+
+ attname = get_attname(relid, attnum);
+ if (attname == NULL)
+ elog(ERROR, "cache lookup failed for attribute %d of relation %u",
+ attnum, relid);
+ return attname;
+}
+
+/*
+ * get_attnum
*
* Given the relation id and the attribute name,
* return the "attnum" field from the attribute relation.
*
+ * Returns InvalidAttrNumber if the attr doesn't exist (or is dropped).
*/
AttrNumber
-get_attnum(Oid relid, char *attname)
+get_attnum(Oid relid, const char *attname)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(ATTNAME,
- ObjectIdGetDatum(relid),
- PointerGetDatum(attname),
- 0, 0);
+ tp = SearchSysCacheAttName(relid, attname);
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
- return att_tup->attnum;
+ AttrNumber result;
+
+ result = att_tup->attnum;
+ ReleaseSysCache(tp);
+ return result;
}
else
return InvalidAttrNumber;
}
/*
- * get_atttype -
+ * get_atttype
*
* Given the relation OID and the attribute number with the relation,
* return the attribute type OID.
- *
*/
Oid
get_atttype(Oid relid, AttrNumber attnum)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(ATTNUM,
- ObjectIdGetDatum(relid),
- UInt16GetDatum(attnum),
- 0, 0);
+ tp = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum),
+ 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
- return att_tup->atttypid;
- }
- else
- return InvalidOid;
-}
-
-/* This routine uses the attname instead of the attnum because it
- * replaces the routine find_atttype, which is called sometimes when
- * only the attname, not the attno, is available.
- */
-bool
-get_attisset(Oid relid, char *attname)
-{
- HeapTuple tp;
+ Oid result;
- tp = SearchSysCacheTuple(ATTNAME,
- ObjectIdGetDatum(relid),
- PointerGetDatum(attname),
- 0, 0);
- if (HeapTupleIsValid(tp))
- {
- Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
- return att_tup->attisset;
+ result = att_tup->atttypid;
+ ReleaseSysCache(tp);
+ return result;
}
else
- return false;
+ return InvalidOid;
}
/*
- * get_atttypmod -
+ * get_atttypmod
*
* Given the relation id and the attribute number,
* return the "atttypmod" field from the attribute relation.
- *
*/
int32
get_atttypmod(Oid relid, AttrNumber attnum)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(ATTNUM,
- ObjectIdGetDatum(relid),
- UInt16GetDatum(attnum),
- 0, 0);
+ tp = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum),
+ 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
- return att_tup->atttypmod;
+ int32 result;
+
+ result = att_tup->atttypmod;
+ ReleaseSysCache(tp);
+ return result;
}
else
return -1;
}
/*
- * get_attdisbursion
+ * get_atttypetypmod
*
- * Retrieve the disbursion statistic for an attribute,
- * or produce an estimate if no info is available.
+ * A two-fer: given the relation id and the attribute number,
+ * fetch both type OID and atttypmod in a single cache lookup.
*
- * min_estimate is the minimum estimate to return if insufficient data
- * is available to produce a reliable value. This value may vary
- * depending on context. (For example, when deciding whether it is
- * safe to use a hashjoin, we want to be more conservative than when
- * estimating the number of tuples produced by an equijoin.)
+ * Unlike the otherwise-similar get_atttype/get_atttypmod, this routine
+ * raises an error if it can't obtain the information.
*/
-double
-get_attdisbursion(Oid relid, AttrNumber attnum, double min_estimate)
+void
+get_atttypetypmod(Oid relid, AttrNumber attnum,
+ Oid *typid, int32 *typmod)
{
- HeapTuple atp;
- double disbursion;
- int32 ntuples;
-
- atp = SearchSysCacheTuple(ATTNUM,
- ObjectIdGetDatum(relid),
- Int16GetDatum(attnum),
- 0, 0);
- if (!HeapTupleIsValid(atp))
- {
- /* this should not happen */
- elog(ERROR, "get_attdisbursion: no attribute tuple %u %d",
- relid, attnum);
- return min_estimate;
- }
-
- disbursion = ((Form_pg_attribute) GETSTRUCT(atp))->attdisbursion;
- if (disbursion > 0.0)
- return disbursion; /* we have a specific estimate */
-
- /*
- * Disbursion is either 0 (no data available) or -1 (disbursion
- * is 1/numtuples). Either way, we need the relation size.
- */
-
- atp = SearchSysCacheTuple(RELOID,
- ObjectIdGetDatum(relid),
- 0, 0, 0);
- if (!HeapTupleIsValid(atp))
- {
- /* this should not happen */
- elog(ERROR, "get_attdisbursion: no relation tuple %u", relid);
- return min_estimate;
- }
-
- ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
-
- if (ntuples == 0)
- return min_estimate; /* no data available */
+ HeapTuple tp;
+ Form_pg_attribute att_tup;
+
+ tp = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum),
+ 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for attribute %d of relation %u",
+ attnum, relid);
+ att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+
+ *typid = att_tup->atttypid;
+ *typmod = att_tup->atttypmod;
+ ReleaseSysCache(tp);
+}
- if (disbursion < 0.0) /* VACUUM thinks there are no duplicates */
- return 1.0 / (double) ntuples;
+/* ---------- INDEX CACHE ---------- */
- /*
- * VACUUM ANALYZE does not compute disbursion for system attributes,
- * but some of them can reasonably be assumed unique anyway.
- */
- if (attnum == ObjectIdAttributeNumber ||
- attnum == SelfItemPointerAttributeNumber)
- return 1.0 / (double) ntuples;
+/* watch this space...
+ */
- /*
- * VACUUM ANALYZE has not been run for this table.
- * Produce an estimate = 1/numtuples. This may produce
- * unreasonably small estimates for large tables, so limit
- * the estimate to no less than min_estimate.
- */
- disbursion = 1.0 / (double) ntuples;
- if (disbursion < min_estimate)
- disbursion = min_estimate;
+/* ---------- OPCLASS CACHE ---------- */
- return disbursion;
+/*
+ * opclass_is_btree
+ *
+ * Returns TRUE iff the specified opclass is associated with the
+ * btree index access method.
+ */
+bool
+opclass_is_btree(Oid opclass)
+{
+ HeapTuple tp;
+ Form_pg_opclass cla_tup;
+ bool result;
+
+ tp = SearchSysCache(CLAOID,
+ ObjectIdGetDatum(opclass),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for opclass %u", opclass);
+ cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
+
+ result = (cla_tup->opcamid == BTREE_AM_OID);
+ ReleaseSysCache(tp);
+ return result;
}
-/* ---------- INDEX CACHE ---------- */
-
-/* watch this space...
+/*
+ * opclass_is_hash
+ *
+ * Returns TRUE iff the specified opclass is associated with the
+ * hash index access method.
*/
+bool
+opclass_is_hash(Oid opclass)
+{
+ HeapTuple tp;
+ Form_pg_opclass cla_tup;
+ bool result;
+
+ tp = SearchSysCache(CLAOID,
+ ObjectIdGetDatum(opclass),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for opclass %u", opclass);
+ cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
+
+ result = (cla_tup->opcamid == HASH_AM_OID);
+ ReleaseSysCache(tp);
+ return result;
+}
/* ---------- OPERATOR CACHE ---------- */
/*
- * get_opcode -
+ * get_opcode
*
* Returns the regproc id of the routine used to implement an
* operator given the operator oid.
- *
*/
RegProcedure
get_opcode(Oid opno)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
- return optup->oprcode;
+ RegProcedure result;
+
+ result = optup->oprcode;
+ ReleaseSysCache(tp);
+ return result;
}
else
- return (RegProcedure) NULL;
+ return (RegProcedure) InvalidOid;
}
/*
- * get_opname -
+ * get_opname
* returns the name of the operator with the given opno
*
* Note: returns a palloc'd copy of the string, or NULL if no such operator.
{
HeapTuple tp;
- tp = SearchSysCacheTuple(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
- return pstrdup(NameStr(optup->oprname));
+ char *result;
+
+ result = pstrdup(NameStr(optup->oprname));
+ ReleaseSysCache(tp);
+ return result;
}
else
return NULL;
}
/*
- * op_mergejoinable -
+ * op_input_types
*
- * Returns the left and right sort operators and types corresponding to a
- * mergejoinable operator, or nil if the operator is not mergejoinable.
+ * Returns the left and right input datatypes for an operator
+ * (InvalidOid if not relevant).
+ */
+void
+op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
+{
+ HeapTuple tp;
+ Form_pg_operator optup;
+
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp)) /* shouldn't happen */
+ elog(ERROR, "cache lookup failed for operator %u", opno);
+ optup = (Form_pg_operator) GETSTRUCT(tp);
+ *lefttype = optup->oprleft;
+ *righttype = optup->oprright;
+ ReleaseSysCache(tp);
+}
+
+/*
+ * op_mergejoinable
*
+ * Returns the left and right sort operators corresponding to a
+ * mergejoinable operator, or false if the operator is not mergejoinable.
*/
bool
-op_mergejoinable(Oid opno, Oid ltype, Oid rtype, Oid *leftOp, Oid *rightOp)
+op_mergejoinable(Oid opno, Oid *leftOp, Oid *rightOp)
{
HeapTuple tp;
+ bool result = false;
- tp = SearchSysCacheTuple(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
if (optup->oprlsortop &&
- optup->oprrsortop &&
- optup->oprleft == ltype &&
- optup->oprright == rtype)
+ optup->oprrsortop)
{
- *leftOp = ObjectIdGetDatum(optup->oprlsortop);
- *rightOp = ObjectIdGetDatum(optup->oprrsortop);
- return true;
+ *leftOp = optup->oprlsortop;
+ *rightOp = optup->oprrsortop;
+ result = true;
}
+ ReleaseSysCache(tp);
}
- return false;
+ return result;
}
/*
- * op_hashjoinable
+ * op_mergejoin_crossops
*
- * Returns the hash operator corresponding to a hashjoinable operator,
- * or nil if the operator is not hashjoinable.
+ * Returns the cross-type comparison operators (ltype "<" rtype and
+ * ltype ">" rtype) for an operator previously determined to be
+ * mergejoinable. Optionally, fetches the regproc ids of these
+ * operators, as well as their operator OIDs.
+ */
+void
+op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
+ RegProcedure *ltproc, RegProcedure *gtproc)
+{
+ HeapTuple tp;
+ Form_pg_operator optup;
+
+ /*
+ * Get the declared comparison operators of the operator.
+ */
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp)) /* shouldn't happen */
+ elog(ERROR, "cache lookup failed for operator %u", opno);
+ optup = (Form_pg_operator) GETSTRUCT(tp);
+ *ltop = optup->oprltcmpop;
+ *gtop = optup->oprgtcmpop;
+ ReleaseSysCache(tp);
+
+ /* Check < op provided */
+ if (!OidIsValid(*ltop))
+ elog(ERROR, "mergejoin operator %u has no matching < operator",
+ opno);
+ if (ltproc)
+ *ltproc = get_opcode(*ltop);
+
+ /* Check > op provided */
+ if (!OidIsValid(*gtop))
+ elog(ERROR, "mergejoin operator %u has no matching > operator",
+ opno);
+ if (gtproc)
+ *gtproc = get_opcode(*gtop);
+}
+
+/*
+ * op_hashjoinable
*
+ * Returns true if the operator is hashjoinable.
*/
-Oid
-op_hashjoinable(Oid opno, Oid ltype, Oid rtype)
+bool
+op_hashjoinable(Oid opno)
{
HeapTuple tp;
+ bool result = false;
- tp = SearchSysCacheTuple(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
- if (optup->oprcanhash &&
- optup->oprleft == ltype &&
- optup->oprright == rtype)
- return opno;
+ result = optup->oprcanhash;
+ ReleaseSysCache(tp);
}
- return InvalidOid;
+ return result;
+}
+
+/*
+ * op_strict
+ *
+ * Get the proisstrict flag for the operator's underlying function.
+ */
+bool
+op_strict(Oid opno)
+{
+ RegProcedure funcid = get_opcode(opno);
+
+ if (funcid == (RegProcedure) InvalidOid)
+ elog(ERROR, "operator %u does not exist", opno);
+
+ return func_strict((Oid) funcid);
}
-HeapTuple
-get_operator_tuple(Oid opno)
+/*
+ * op_volatile
+ *
+ * Get the provolatile flag for the operator's underlying function.
+ */
+char
+op_volatile(Oid opno)
{
- HeapTuple optup;
+ RegProcedure funcid = get_opcode(opno);
- if ((optup = SearchSysCacheTuple(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0)))
- return optup;
- else
- return (HeapTuple) NULL;
+ if (funcid == (RegProcedure) InvalidOid)
+ elog(ERROR, "operator %u does not exist", opno);
+
+ return func_volatile((Oid) funcid);
}
/*
- * get_commutator -
+ * get_commutator
*
* Returns the corresponding commutator of an operator.
- *
*/
Oid
get_commutator(Oid opno)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
- return optup->oprcom;
+ Oid result;
+
+ result = optup->oprcom;
+ ReleaseSysCache(tp);
+ return result;
}
else
return InvalidOid;
}
/*
- * get_negator -
+ * get_negator
*
* Returns the corresponding negator of an operator.
- *
*/
Oid
get_negator(Oid opno)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
- return optup->oprnegate;
+ Oid result;
+
+ result = optup->oprnegate;
+ ReleaseSysCache(tp);
+ return result;
}
else
return InvalidOid;
}
/*
- * get_oprrest -
+ * get_oprrest
*
* Returns procedure id for computing selectivity of an operator.
- *
*/
RegProcedure
get_oprrest(Oid opno)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
- return optup->oprrest;
+ RegProcedure result;
+
+ result = optup->oprrest;
+ ReleaseSysCache(tp);
+ return result;
}
else
- return (RegProcedure) NULL;
+ return (RegProcedure) InvalidOid;
}
/*
- * get_oprjoin -
+ * get_oprjoin
*
* Returns procedure id for computing selectivity of a join.
- *
*/
RegProcedure
get_oprjoin(Oid opno)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
- return optup->oprjoin;
+ RegProcedure result;
+
+ result = optup->oprjoin;
+ ReleaseSysCache(tp);
+ return result;
}
else
- return (RegProcedure) NULL;
+ return (RegProcedure) InvalidOid;
}
/* ---------- FUNCTION CACHE ---------- */
+/*
+ * get_func_name
+ * returns the name of the function with the given funcid
+ *
+ * Note: returns a palloc'd copy of the string, or NULL if no such function.
+ */
+char *
+get_func_name(Oid funcid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(funcid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
+ char *result;
+
+ result = pstrdup(NameStr(functup->proname));
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return NULL;
+}
+
/*
* get_func_rettype
* Given procedure id, return the function's result type.
Oid
get_func_rettype(Oid funcid)
{
- HeapTuple func_tuple;
- Oid funcrettype;
-
- func_tuple = SearchSysCacheTuple(PROCOID,
- ObjectIdGetDatum(funcid),
- 0, 0, 0);
-
- if (!HeapTupleIsValid(func_tuple))
- elog(ERROR, "Function OID %u does not exist", funcid);
+ HeapTuple tp;
+ Oid result;
- funcrettype = (Oid)
- ((Form_pg_proc) GETSTRUCT(func_tuple))->prorettype;
+ tp = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(funcid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for function %u", funcid);
- return funcrettype;
+ result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype;
+ ReleaseSysCache(tp);
+ return result;
}
-/* ---------- RELATION CACHE ---------- */
-
/*
- * get_relnatts -
- *
- * Returns the number of attributes for a given relation.
- *
+ * get_func_nargs
+ * Given procedure id, return the number of arguments.
*/
int
-get_relnatts(Oid relid)
+get_func_nargs(Oid funcid)
{
HeapTuple tp;
+ int result;
- tp = SearchSysCacheTuple(RELOID,
- ObjectIdGetDatum(relid),
- 0, 0, 0);
- if (HeapTupleIsValid(tp))
- {
- Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
- return reltup->relnatts;
- }
- else
- return InvalidAttrNumber;
+ 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_rel_name -
- *
- * Returns the name of a given relation.
+ * 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.
*/
-char *
-get_rel_name(Oid relid)
+Oid
+get_func_signature(Oid funcid, Oid **argtypes, int *nargs)
{
HeapTuple tp;
+ Form_pg_proc procstruct;
+ Oid result;
- tp = SearchSysCacheTuple(RELOID,
- ObjectIdGetDatum(relid),
- 0, 0, 0);
- if (HeapTupleIsValid(tp))
- {
- Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
- return pstrdup(NameStr(reltup->relname));
- }
- else
- return NULL;
-}
+ tp = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(funcid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for function %u", funcid);
-/* ---------- TYPE CACHE ---------- */
+ 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_typlen -
- *
- * Given the type OID, return the length of the type.
- *
+ * get_func_retset
+ * Given procedure id, return the function's proretset flag.
*/
-int16
-get_typlen(Oid typid)
+bool
+get_func_retset(Oid funcid)
{
HeapTuple tp;
+ bool result;
- tp = SearchSysCacheTuple(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
- if (HeapTupleIsValid(tp))
- {
- Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
- return typtup->typlen;
- }
- else
- return 0;
+ tp = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(funcid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for function %u", funcid);
+
+ result = ((Form_pg_proc) GETSTRUCT(tp))->proretset;
+ ReleaseSysCache(tp);
+ return result;
}
/*
- * get_typbyval -
- *
- * Given the type OID, determine whether the type is returned by value or
- * not. Returns 1 if by value, 0 if by reference.
- *
+ * func_strict
+ * Given procedure id, return the function's proisstrict flag.
*/
bool
-get_typbyval(Oid typid)
+func_strict(Oid funcid)
{
HeapTuple tp;
+ bool result;
- tp = SearchSysCacheTuple(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
- if (HeapTupleIsValid(tp))
- {
+ tp = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(funcid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for function %u", funcid);
+
+ result = ((Form_pg_proc) GETSTRUCT(tp))->proisstrict;
+ ReleaseSysCache(tp);
+ return result;
+}
+
+/*
+ * func_volatile
+ * Given procedure id, return the function's provolatile flag.
+ */
+char
+func_volatile(Oid funcid)
+{
+ HeapTuple tp;
+ char result;
+
+ tp = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(funcid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for function %u", funcid);
+
+ result = ((Form_pg_proc) GETSTRUCT(tp))->provolatile;
+ ReleaseSysCache(tp);
+ return result;
+}
+
+/* ---------- RELATION CACHE ---------- */
+
+/*
+ * get_relname_relid
+ * Given name and namespace of a relation, look up the OID.
+ *
+ * Returns InvalidOid if there is no such relation.
+ */
+Oid
+get_relname_relid(const char *relname, Oid relnamespace)
+{
+ return GetSysCacheOid(RELNAMENSP,
+ PointerGetDatum(relname),
+ ObjectIdGetDatum(relnamespace),
+ 0, 0);
+}
+
+/*
+ * get_system_catalog_relid
+ * Get the OID of a system catalog identified by name.
+ */
+Oid
+get_system_catalog_relid(const char *catname)
+{
+ Oid relid;
+
+ relid = GetSysCacheOid(RELNAMENSP,
+ PointerGetDatum(catname),
+ ObjectIdGetDatum(PG_CATALOG_NAMESPACE),
+ 0, 0);
+ if (!OidIsValid(relid))
+ elog(ERROR, "cache lookup failed for system relation %s", catname);
+
+ return relid;
+}
+
+#ifdef NOT_USED
+/*
+ * get_relnatts
+ *
+ * Returns the number of attributes for a given relation.
+ */
+int
+get_relnatts(Oid relid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(RELOID,
+ ObjectIdGetDatum(relid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
+ int result;
+
+ result = reltup->relnatts;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return InvalidAttrNumber;
+}
+#endif
+
+/*
+ * get_rel_name
+ * Returns the name of a given relation.
+ *
+ * Returns a palloc'd copy of the string, or NULL if no such relation.
+ *
+ * NOTE: since relation name is not unique, be wary of code that uses this
+ * for anything except preparing error messages.
+ */
+char *
+get_rel_name(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 = pstrdup(NameStr(reltup->relname));
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return NULL;
+}
+
+/*
+ * get_rel_namespace
+ *
+ * Returns the pg_namespace OID associated with a given relation.
+ */
+Oid
+get_rel_namespace(Oid relid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(RELOID,
+ ObjectIdGetDatum(relid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
+ Oid result;
+
+ result = reltup->relnamespace;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return InvalidOid;
+}
+
+/*
+ * get_rel_type_id
+ *
+ * Returns the pg_type OID associated with a given relation.
+ *
+ * Note: not all pg_class entries have associated pg_type OIDs; so be
+ * careful to check for InvalidOid result.
+ */
+Oid
+get_rel_type_id(Oid relid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(RELOID,
+ ObjectIdGetDatum(relid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
+ Oid result;
+
+ result = reltup->reltype;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return InvalidOid;
+}
+
+/*
+ * get_rel_relkind
+ *
+ * Returns the relkind associated with a given relation.
+ */
+char
+get_rel_relkind(Oid relid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(RELOID,
+ ObjectIdGetDatum(relid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
+ char result;
+
+ result = reltup->relkind;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return '\0';
+}
+
+
+/* ---------- TYPE CACHE ---------- */
+
+/*
+ * get_typisdefined
+ *
+ * Given the type OID, determine whether the type is defined
+ * (if not, it's only a shell).
+ */
+bool
+get_typisdefined(Oid typid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
- return (bool) typtup->typbyval;
+ bool result;
+
+ result = typtup->typisdefined;
+ ReleaseSysCache(tp);
+ return result;
}
else
return false;
}
+/*
+ * get_typlen
+ *
+ * Given the type OID, return the length of the type.
+ */
+int16
+get_typlen(Oid typid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+ int16 result;
+
+ result = typtup->typlen;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return 0;
+}
+
+/*
+ * get_typbyval
+ *
+ * Given the type OID, determine whether the type is returned by value or
+ * not. Returns true if by value, false if by reference.
+ */
+bool
+get_typbyval(Oid typid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+ bool result;
+
+ result = typtup->typbyval;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return false;
+}
+
+/*
+ * get_typlenbyval
+ *
+ * A two-fer: given the type OID, return both typlen and typbyval.
+ *
+ * Since both pieces of info are needed to know how to copy a Datum,
+ * many places need both. Might as well get them with one cache lookup
+ * instead of two. Also, this routine raises an error instead of
+ * returning a bogus value when given a bad type OID.
+ */
+void
+get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
+{
+ HeapTuple tp;
+ Form_pg_type typtup;
+
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for type %u", typid);
+ typtup = (Form_pg_type) GETSTRUCT(tp);
+ *typlen = typtup->typlen;
+ *typbyval = typtup->typbyval;
+ ReleaseSysCache(tp);
+}
+
+/*
+ * get_typlenbyvalalign
+ *
+ * A three-fer: given the type OID, return typlen, typbyval, typalign.
+ */
+void
+get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
+ char *typalign)
+{
+ HeapTuple tp;
+ Form_pg_type typtup;
+
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for type %u", typid);
+ typtup = (Form_pg_type) GETSTRUCT(tp);
+ *typlen = typtup->typlen;
+ *typbyval = typtup->typbyval;
+ *typalign = typtup->typalign;
+ ReleaseSysCache(tp);
+}
+
+/*
+ * getTypeIOParam
+ * Given a pg_type row, select the type OID to pass to I/O functions
+ *
+ * Formerly, all I/O functions were passed pg_type.typelem as their second
+ * parameter, but we now have a more complex rule about what to pass.
+ * This knowledge is intended to be centralized here --- direct references
+ * to typelem elsewhere in the code are wrong, if they are associated with
+ * I/O calls and not with actual subscripting operations! (But see
+ * bootstrap.c, which can't conveniently use this routine.)
+ */
+Oid
+getTypeIOParam(HeapTuple typeTuple)
+{
+ Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
+
+ /*
+ * Composite types get their own OID as parameter; array types get
+ * their typelem as parameter; everybody else gets zero.
+ */
+ if (typeStruct->typtype == 'c')
+ return HeapTupleGetOid(typeTuple);
+ else
+ return typeStruct->typelem;
+}
+
+/*
+ * get_type_io_data
+ *
+ * A six-fer: given the type OID, return typlen, typbyval, typalign,
+ * typdelim, typioparam, and IO function OID. The IO function
+ * returned is controlled by IOFuncSelector
+ */
+void
+get_type_io_data(Oid typid,
+ IOFuncSelector which_func,
+ int16 *typlen,
+ bool *typbyval,
+ char *typalign,
+ char *typdelim,
+ Oid *typioparam,
+ Oid *func)
+{
+ HeapTuple typeTuple;
+ Form_pg_type typeStruct;
+
+ typeTuple = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(typeTuple))
+ elog(ERROR, "cache lookup failed for type %u", typid);
+ typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
+
+ *typlen = typeStruct->typlen;
+ *typbyval = typeStruct->typbyval;
+ *typalign = typeStruct->typalign;
+ *typdelim = typeStruct->typdelim;
+ *typioparam = getTypeIOParam(typeTuple);
+ switch (which_func)
+ {
+ case IOFunc_input:
+ *func = typeStruct->typinput;
+ break;
+ case IOFunc_output:
+ *func = typeStruct->typoutput;
+ break;
+ case IOFunc_receive:
+ *func = typeStruct->typreceive;
+ break;
+ case IOFunc_send:
+ *func = typeStruct->typsend;
+ break;
+ }
+ ReleaseSysCache(typeTuple);
+}
+
#ifdef NOT_USED
char
get_typalign(Oid typid)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
- return typtup->typalign;
+ char result;
+
+ result = typtup->typalign;
+ ReleaseSysCache(tp);
+ return result;
}
else
return 'i';
}
-
#endif
+char
+get_typstorage(Oid typid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+ char result;
+
+ result = typtup->typstorage;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return 'p';
+}
+
/*
- * get_typdefault -
+ * get_typtypmod
+ *
+ * Given the type OID, return the typtypmod field (domain's typmod
+ * for base type)
+ */
+int32
+get_typtypmod(Oid typid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+ int32 result;
+
+ result = typtup->typtypmod;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return -1;
+}
+
+/*
+ * get_typdefault
+ * Given a type OID, return the type's default value, if any.
+ *
+ * The result is a palloc'd expression node tree, or NULL if there
+ * is no defined default for the datatype.
*
- * Given a type OID, return the typdefault field associated with that
- * type, or Datum(NULL) if there is no typdefault. (This implies
- * that pass-by-value types can't have a default value that has
- * a representation of zero. Not worth fixing now.)
- * The result points to palloc'd storage for non-pass-by-value types.
+ * NB: caller should be prepared to coerce result to correct datatype;
+ * the returned expression tree might produce something of the wrong type.
*/
-Datum
+Node *
get_typdefault(Oid typid)
{
HeapTuple typeTuple;
Form_pg_type type;
- struct varlena *typDefault;
+ Datum datum;
bool isNull;
- int32 dataSize;
- int32 typLen;
- bool typByVal;
- Datum returnValue;
-
- typeTuple = SearchSysCacheTuple(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ Node *expr;
+ typeTuple = SearchSysCache(TYPEOID,
+ 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);
/*
- * First, see if there is a non-null typdefault field (usually there isn't)
- */
- typDefault = (struct varlena *) SysCacheGetAttr(TYPEOID,
- typeTuple,
- Anum_pg_type_typdefault,
- &isNull);
-
- if (isNull)
- return PointerGetDatum(NULL);
-
- /*
- * Otherwise, extract/copy the value.
+ * typdefault and typdefaultbin are potentially null, so don't try to
+ * access 'em as struct fields. Must do it the hard way with
+ * SysCacheGetAttr.
*/
- dataSize = VARSIZE(typDefault) - VARHDRSZ;
- typLen = type->typlen;
- typByVal = type->typbyval;
+ datum = SysCacheGetAttr(TYPEOID,
+ typeTuple,
+ Anum_pg_type_typdefaultbin,
+ &isNull);
- if (typByVal)
+ if (!isNull)
{
- int8 i8;
- int16 i16;
- int32 i32 = 0;
+ /* We have an expression default */
+ expr = stringToNode(DatumGetCString(DirectFunctionCall1(textout,
+ datum)));
+ }
+ else
+ {
+ /* Perhaps we have a plain literal default */
+ datum = SysCacheGetAttr(TYPEOID,
+ typeTuple,
+ Anum_pg_type_typdefault,
+ &isNull);
- if (dataSize == typLen)
+ if (!isNull)
{
- switch (typLen)
- {
- case sizeof(int8):
- memcpy((char *) &i8, VARDATA(typDefault), sizeof(int8));
- i32 = i8;
- break;
- case sizeof(int16):
- memcpy((char *) &i16, VARDATA(typDefault), sizeof(int16));
- i32 = i16;
- break;
- case sizeof(int32):
- memcpy((char *) &i32, VARDATA(typDefault), sizeof(int32));
- break;
- }
- returnValue = Int32GetDatum(i32);
+ char *strDefaultVal;
+
+ /* Convert text datum to C string */
+ strDefaultVal = DatumGetCString(DirectFunctionCall1(textout,
+ datum));
+ /* Convert C string to a value of the given type */
+ datum = OidFunctionCall3(type->typinput,
+ CStringGetDatum(strDefaultVal),
+ ObjectIdGetDatum(getTypeIOParam(typeTuple)),
+ Int32GetDatum(-1));
+ /* Build a Const node containing the value */
+ expr = (Node *) makeConst(typid,
+ type->typlen,
+ datum,
+ false,
+ type->typbyval);
+ pfree(strDefaultVal);
}
- else
- returnValue = PointerGetDatum(NULL);
- }
- else if (typLen < 0)
- {
- /* variable-size type */
- if (dataSize < 0)
- returnValue = PointerGetDatum(NULL);
else
{
- returnValue = PointerGetDatum(palloc(VARSIZE(typDefault)));
- memcpy((char *) DatumGetPointer(returnValue),
- (char *) typDefault,
- (int) VARSIZE(typDefault));
+ /* No default */
+ expr = NULL;
}
}
- else
+
+ ReleaseSysCache(typeTuple);
+
+ return expr;
+}
+
+/*
+ * getBaseType
+ * If the given type is a domain, return its base type;
+ * otherwise return the type's own OID.
+ */
+Oid
+getBaseType(Oid typid)
+{
+ /*
+ * We loop to find the bottom base type in a stack of domains.
+ */
+ for (;;)
{
- /* fixed-size pass-by-ref type */
- if (dataSize != typLen)
- returnValue = PointerGetDatum(NULL);
- else
+ HeapTuple tup;
+ Form_pg_type typTup;
+
+ tup = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for type %u", typid);
+ typTup = (Form_pg_type) GETSTRUCT(tup);
+ if (typTup->typtype != 'd')
{
- returnValue = PointerGetDatum(palloc(dataSize));
- memcpy((char *) DatumGetPointer(returnValue),
- VARDATA(typDefault),
- (int) dataSize);
+ /* Not a domain, so done */
+ ReleaseSysCache(tup);
+ break;
}
+
+ typid = typTup->typbasetype;
+ ReleaseSysCache(tup);
}
- return returnValue;
+ return typid;
}
/*
- * get_typtype -
+ * get_typavgwidth
*
- * Given the type OID, find if it is a basic type, a named relation
- * or the generic type 'relation'.
- * It returns the null char if the cache lookup fails...
+ * Given a type OID and a typmod value (pass -1 if typmod is unknown),
+ * estimate the average width of values of the type. This is used by
+ * the planner, which doesn't require absolutely correct results;
+ * it's OK (and expected) to guess if we don't know for sure.
+ */
+int32
+get_typavgwidth(Oid typid, int32 typmod)
+{
+ int typlen = get_typlen(typid);
+ int32 maxwidth;
+
+ /*
+ * Easy if it's a fixed-width type
+ */
+ if (typlen > 0)
+ return typlen;
+
+ /*
+ * type_maximum_size knows the encoding of typmod for some datatypes;
+ * don't duplicate that knowledge here.
+ */
+ maxwidth = type_maximum_size(typid, typmod);
+ if (maxwidth > 0)
+ {
+ /*
+ * For BPCHAR, the max width is also the only width. Otherwise we
+ * need to guess about the typical data width given the max. A
+ * sliding scale for percentage of max width seems reasonable.
+ */
+ if (typid == BPCHAROID)
+ return maxwidth;
+ if (maxwidth <= 32)
+ return maxwidth; /* assume full width */
+ if (maxwidth < 1000)
+ return 32 + (maxwidth - 32) / 2; /* assume 50% */
+
+ /*
+ * Beyond 1000, assume we're looking at something like
+ * "varchar(10000)" where the limit isn't actually reached often,
+ * and use a fixed estimate.
+ */
+ return 32 + (1000 - 32) / 2;
+ }
+
+ /*
+ * Ooops, we have no idea ... wild guess time.
+ */
+ return 32;
+}
+
+/*
+ * get_typtype
*
+ * Given the type OID, find if it is a basic type, a complex type, etc.
+ * It returns the null char if the cache lookup fails...
*/
-#ifdef NOT_USED
char
get_typtype(Oid typid)
{
HeapTuple tp;
- tp = SearchSysCacheTuple(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
- return typtup->typtype;
+ char result;
+
+ result = typtup->typtype;
+ ReleaseSysCache(tp);
+ return result;
}
else
return '\0';
}
-#endif
+/*
+ * get_typ_typrelid
+ *
+ * Given the type OID, get the typrelid (InvalidOid if not a complex
+ * type).
+ */
+Oid
+get_typ_typrelid(Oid typid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+ Oid result;
+
+ result = typtup->typrelid;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return InvalidOid;
+}
+
+/*
+ * get_element_type
+ *
+ * Given the type OID, get the typelem (InvalidOid if not an array type).
+ *
+ * NB: this only considers varlena arrays to be true arrays; InvalidOid is
+ * returned if the input is a fixed-length array type.
+ */
+Oid
+get_element_type(Oid typid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+ Oid result;
+
+ if (typtup->typlen == -1)
+ result = typtup->typelem;
+ else
+ result = InvalidOid;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return InvalidOid;
+}
+
+/*
+ * get_array_type
+ *
+ * Given the type OID, get the corresponding array type.
+ * Returns InvalidOid if no array type can be found.
+ *
+ * NB: this only considers varlena arrays to be true arrays.
+ */
+Oid
+get_array_type(Oid typid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+ char *array_typename;
+ Oid namespaceId;
+
+ array_typename = makeArrayTypeName(NameStr(typtup->typname));
+ namespaceId = typtup->typnamespace;
+ ReleaseSysCache(tp);
+
+ tp = SearchSysCache(TYPENAMENSP,
+ PointerGetDatum(array_typename),
+ ObjectIdGetDatum(namespaceId),
+ 0, 0);
+
+ pfree(array_typename);
+
+ if (HeapTupleIsValid(tp))
+ {
+ Oid result;
+
+ typtup = (Form_pg_type) GETSTRUCT(tp);
+ if (typtup->typlen == -1 && typtup->typelem == typid)
+ result = HeapTupleGetOid(tp);
+ else
+ result = InvalidOid;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ }
+ return InvalidOid;
+}
+
+/*
+ * getTypeInputInfo
+ *
+ * Get info needed for converting values of a type to internal form
+ */
+void
+getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
+{
+ HeapTuple typeTuple;
+ Form_pg_type pt;
+
+ typeTuple = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(type),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(typeTuple))
+ elog(ERROR, "cache lookup failed for type %u", type);
+ pt = (Form_pg_type) GETSTRUCT(typeTuple);
+
+ if (!pt->typisdefined)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("type %s is only a shell",
+ format_type_be(type))));
+ if (!OidIsValid(pt->typinput))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("no input function available for type %s",
+ format_type_be(type))));
+
+ *typInput = pt->typinput;
+ *typIOParam = getTypeIOParam(typeTuple);
+
+ ReleaseSysCache(typeTuple);
+}
+
+/*
+ * getTypeOutputInfo
+ *
+ * Get info needed for printing values of a type
+ */
+void
+getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typIOParam,
+ bool *typIsVarlena)
+{
+ HeapTuple typeTuple;
+ Form_pg_type pt;
+
+ typeTuple = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(type),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(typeTuple))
+ elog(ERROR, "cache lookup failed for type %u", type);
+ pt = (Form_pg_type) GETSTRUCT(typeTuple);
+
+ if (!pt->typisdefined)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("type %s is only a shell",
+ format_type_be(type))));
+ if (!OidIsValid(pt->typoutput))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("no output function available for type %s",
+ format_type_be(type))));
+
+ *typOutput = pt->typoutput;
+ *typIOParam = getTypeIOParam(typeTuple);
+ *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
+
+ ReleaseSysCache(typeTuple);
+}
+
+/*
+ * getTypeBinaryInputInfo
+ *
+ * Get info needed for binary input of values of a type
+ */
+void
+getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam)
+{
+ HeapTuple typeTuple;
+ Form_pg_type pt;
+
+ typeTuple = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(type),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(typeTuple))
+ elog(ERROR, "cache lookup failed for type %u", type);
+ pt = (Form_pg_type) GETSTRUCT(typeTuple);
+
+ if (!pt->typisdefined)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("type %s is only a shell",
+ format_type_be(type))));
+ if (!OidIsValid(pt->typreceive))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("no binary input function available for type %s",
+ format_type_be(type))));
+
+ *typReceive = pt->typreceive;
+ *typIOParam = getTypeIOParam(typeTuple);
+
+ ReleaseSysCache(typeTuple);
+}
+
+/*
+ * getTypeBinaryOutputInfo
+ *
+ * Get info needed for binary output of values of a type
+ */
+void
+getTypeBinaryOutputInfo(Oid type, Oid *typSend, Oid *typIOParam,
+ bool *typIsVarlena)
+{
+ HeapTuple typeTuple;
+ Form_pg_type pt;
+
+ typeTuple = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(type),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(typeTuple))
+ elog(ERROR, "cache lookup failed for type %u", type);
+ pt = (Form_pg_type) GETSTRUCT(typeTuple);
+
+ if (!pt->typisdefined)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("type %s is only a shell",
+ format_type_be(type))));
+ if (!OidIsValid(pt->typsend))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("no binary output function available for type %s",
+ format_type_be(type))));
+
+ *typSend = pt->typsend;
+ *typIOParam = getTypeIOParam(typeTuple);
+ *typIsVarlena = (!pt->typbyval) && (pt->typlen == -1);
+
+ ReleaseSysCache(typeTuple);
+}
+
+
+/* ---------- STATISTICS CACHE ---------- */
+
+/*
+ * get_attavgwidth
+ *
+ * Given the table and attribute number of a column, get the average
+ * width of entries in the column. Return zero if no data available.
+ */
+int32
+get_attavgwidth(Oid relid, AttrNumber attnum)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(STATRELATT,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum),
+ 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ int32 stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
+
+ ReleaseSysCache(tp);
+ if (stawidth > 0)
+ return stawidth;
+ }
+ return 0;
+}
+
+/*
+ * get_attstatsslot
+ *
+ * Extract the contents of a "slot" of a pg_statistic tuple.
+ * Returns TRUE if requested slot type was found, else FALSE.
+ *
+ * Unlike other routines in this file, this takes a pointer to an
+ * already-looked-up tuple in the pg_statistic cache. We do this since
+ * most callers will want to extract more than one value from the cache
+ * entry, and we don't want to repeat the cache lookup unnecessarily.
+ *
+ * statstuple: pg_statistics tuple to be examined.
+ * atttype: type OID of attribute.
+ * atttypmod: typmod of attribute.
+ * reqkind: STAKIND code for desired statistics slot kind.
+ * reqop: STAOP value wanted, or InvalidOid if don't care.
+ * values, nvalues: if not NULL, the slot's stavalues are extracted.
+ * numbers, nnumbers: if not NULL, the slot's stanumbers are extracted.
+ *
+ * If assigned, values and numbers are set to point to palloc'd arrays.
+ * If the attribute type is pass-by-reference, the values referenced by
+ * the values array are themselves palloc'd. The palloc'd stuff can be
+ * freed by calling free_attstatsslot.
+ */
+bool
+get_attstatsslot(HeapTuple statstuple,
+ Oid atttype, int32 atttypmod,
+ int reqkind, Oid reqop,
+ Datum **values, int *nvalues,
+ float4 **numbers, int *nnumbers)
+{
+ Form_pg_statistic stats = (Form_pg_statistic) GETSTRUCT(statstuple);
+ int i,
+ j;
+ Datum val;
+ bool isnull;
+ ArrayType *statarray;
+ int narrayelem;
+ HeapTuple typeTuple;
+ Form_pg_type typeForm;
+
+ for (i = 0; i < STATISTIC_NUM_SLOTS; i++)
+ {
+ if ((&stats->stakind1)[i] == reqkind &&
+ (reqop == InvalidOid || (&stats->staop1)[i] == reqop))
+ break;
+ }
+ if (i >= STATISTIC_NUM_SLOTS)
+ return false; /* not there */
+
+ if (values)
+ {
+ val = SysCacheGetAttr(STATRELATT, statstuple,
+ Anum_pg_statistic_stavalues1 + i,
+ &isnull);
+ if (isnull)
+ elog(ERROR, "stavalues is null");
+ statarray = DatumGetArrayTypeP(val);
+
+ /* Need to get info about the array element type */
+ typeTuple = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(atttype),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(typeTuple))
+ elog(ERROR, "cache lookup failed for type %u", atttype);
+ typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
+
+ /* Deconstruct array into Datum elements */
+ deconstruct_array(statarray,
+ atttype,
+ typeForm->typlen,
+ typeForm->typbyval,
+ typeForm->typalign,
+ values, nvalues);
+
+ /*
+ * If the element type is pass-by-reference, we now have a bunch
+ * of Datums that are pointers into the syscache value. Copy them
+ * to avoid problems if syscache decides to drop the entry.
+ */
+ if (!typeForm->typbyval)
+ {
+ for (j = 0; j < *nvalues; j++)
+ {
+ (*values)[j] = datumCopy((*values)[j],
+ typeForm->typbyval,
+ typeForm->typlen);
+ }
+ }
+
+ ReleaseSysCache(typeTuple);
+
+ /*
+ * Free statarray if it's a detoasted copy.
+ */
+ if ((Pointer) statarray != DatumGetPointer(val))
+ pfree(statarray);
+ }
+
+ if (numbers)
+ {
+ val = SysCacheGetAttr(STATRELATT, statstuple,
+ Anum_pg_statistic_stanumbers1 + i,
+ &isnull);
+ if (isnull)
+ elog(ERROR, "stanumbers is null");
+ statarray = DatumGetArrayTypeP(val);
+
+ /*
+ * We expect the array to be a 1-D float4 array; verify that. We
+ * don't need to use deconstruct_array() since the array data is
+ * just going to look like a C array of float4 values.
+ */
+ narrayelem = ARR_DIMS(statarray)[0];
+ if (ARR_NDIM(statarray) != 1 || narrayelem <= 0 ||
+ ARR_ELEMTYPE(statarray) != FLOAT4OID)
+ elog(ERROR, "stanumbers is not a 1-D float4 array");
+ *numbers = (float4 *) palloc(narrayelem * sizeof(float4));
+ memcpy(*numbers, ARR_DATA_PTR(statarray), narrayelem * sizeof(float4));
+ *nnumbers = narrayelem;
+
+ /*
+ * Free statarray if it's a detoasted copy.
+ */
+ if ((Pointer) statarray != DatumGetPointer(val))
+ pfree(statarray);
+ }
+
+ return true;
+}
+
+void
+free_attstatsslot(Oid atttype,
+ Datum *values, int nvalues,
+ float4 *numbers, int nnumbers)
+{
+ if (values)
+ {
+ if (!get_typbyval(atttype))
+ {
+ int i;
+
+ for (i = 0; i < nvalues; i++)
+ pfree(DatumGetPointer(values[i]));
+ }
+ pfree(values);
+ }
+ if (numbers)
+ pfree(numbers);
+}
+
+/* ---------- PG_NAMESPACE CACHE ---------- */
+
+/*
+ * get_namespace_name
+ * Returns the name of a given namespace
+ *
+ * Returns a palloc'd copy of the string, or NULL if no such namespace.
+ */
+char *
+get_namespace_name(Oid nspid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(NAMESPACEOID,
+ ObjectIdGetDatum(nspid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp);
+ char *result;
+
+ result = pstrdup(NameStr(nsptup->nspname));
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return NULL;
+}
+
+/* ---------- PG_SHADOW CACHE ---------- */
+
+/*
+ * get_usesysid
+ *
+ * Given a user name, look up the user's sysid.
+ * Raises an error if no such user (rather than returning zero,
+ * which might possibly be a valid usesysid).
+ *
+ * Note: the type of usesysid is currently int4, but may change to Oid
+ * someday. It'd be reasonable to return zero on failure if we were
+ * using Oid ...
+ */
+AclId
+get_usesysid(const char *username)
+{
+ AclId userId;
+ HeapTuple userTup;
+
+ userTup = SearchSysCache(SHADOWNAME,
+ PointerGetDatum(username),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(userTup))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("user \"%s\" does not exist", username)));
+
+ userId = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;
+
+ ReleaseSysCache(userTup);
+
+ return userId;
+}
+
+/*
+ * get_grosysid
+ *
+ * Given a group name, look up the group's sysid.
+ * Raises an error if no such group (rather than returning zero,
+ * which might possibly be a valid grosysid).
+ *
+ */
+AclId
+get_grosysid(char *groname)
+{
+ AclId groupId;
+ HeapTuple groupTup;
+
+ groupTup = SearchSysCache(GRONAME,
+ PointerGetDatum(groname),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(groupTup))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("group \"%s\" does not exist", groname)));
+
+ groupId = ((Form_pg_group) GETSTRUCT(groupTup))->grosysid;
+
+ ReleaseSysCache(groupTup);
+
+ return groupId;
+}
+