/*-------------------------------------------------------------------------
*
- * lsyscache.c--
- * Routines to access information within system caches
- *
- * Copyright (c) 1994, Regents of the University of California
+ * lsyscache.c
+ * Convenience routines for common queries in the system catalog cache.
*
+ * Portions Copyright (c) 1996-2001, 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.6 1997/09/08 21:48:51 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.67 2002/03/29 19:06:15 tgl Exp $
*
* NOTES
* Eventually, the index information should go through here, too.
- *
- * Most of these routines call SearchSysCacheStruct() and thus simply
- * (1) allocate some space for the return struct and (2) call it.
- *
*-------------------------------------------------------------------------
*/
-#include <string.h>
#include "postgres.h"
-#include "nodes/pg_list.h"
-#include "utils/syscache.h"
-#include "utils/lsyscache.h"
#include "access/tupmacs.h"
-#include "utils/rel.h"
-#include "utils/palloc.h"
-#include "utils/elog.h"
-#include "access/attnum.h"
-#include "access/heapam.h"
-
#include "catalog/pg_amop.h"
+#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
+#include "catalog/pg_proc.h"
+#include "catalog/pg_shadow.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/lsyscache.h"
+#include "utils/syscache.h"
+
/* ---------- AMOP CACHES ---------- */
/*
- * op_class -
+ * op_in_opclass
*
* Return t iff operator 'opno' is in operator class 'opclass'.
+ */
+bool
+op_in_opclass(Oid opno, Oid opclass)
+{
+ return SearchSysCacheExists(AMOPOPID,
+ ObjectIdGetDatum(opclass),
+ ObjectIdGetDatum(opno),
+ 0, 0);
+}
+
+/*
+ * op_requires_recheck
*
+ * Return t if operator 'opno' requires a recheck when used as a
+ * member of opclass 'opclass' (ie, this opclass is lossy for this
+ * operator).
+ *
+ * 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_class(Oid opno, int32 opclass, Oid amopid)
+op_requires_recheck(Oid opno, Oid opclass)
{
- FormData_pg_amop amoptup;
+ HeapTuple tp;
+ Form_pg_amop amop_tup;
+ bool result;
- if (SearchSysCacheStruct(AMOPOPID,
- (char *) &amoptup,
- ObjectIdGetDatum(opclass),
- ObjectIdGetDatum(opno),
- ObjectIdGetDatum(amopid),
- 0))
- return (true);
- else
- return (false);
+ tp = SearchSysCache(AMOPOPID,
+ ObjectIdGetDatum(opclass),
+ ObjectIdGetDatum(opno),
+ 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "op_requires_recheck: op %u is not a member of opclass %u",
+ opno, opclass);
+ amop_tup = (Form_pg_amop) GETSTRUCT(tp);
+
+ result = amop_tup->amopreqcheck;
+ ReleaseSysCache(tp);
+ return result;
}
/* ---------- ATTRIBUTE CACHES ---------- */
/*
- * get_attname -
+ * 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.
*/
-char *
+char *
get_attname(Oid relid, AttrNumber attnum)
{
- FormData_pg_attribute att_tup;
- char *retval;
+ HeapTuple tp;
- if (SearchSysCacheStruct(ATTNUM,
- (char *) &att_tup,
- ObjectIdGetDatum(relid),
- UInt16GetDatum(attnum),
- 0, 0))
+ tp = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum),
+ 0, 0);
+ if (HeapTupleIsValid(tp))
{
- retval = pstrdup(att_tup.attname.data);
+ Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+ char *result;
- return (retval);
+ result = pstrdup(NameStr(att_tup->attname));
+ ReleaseSysCache(tp);
+ return result;
}
else
- return (NULL);
+ return NULL;
}
/*
- * get_attnum -
+ * get_attnum
*
* Given the relation id and the attribute name,
* return the "attnum" field from the attribute relation.
- *
*/
AttrNumber
get_attnum(Oid relid, char *attname)
{
- FormData_pg_attribute att_tup;
+ HeapTuple tp;
+
+ tp = SearchSysCache(ATTNAME,
+ ObjectIdGetDatum(relid),
+ PointerGetDatum(attname),
+ 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+ AttrNumber result;
- if (SearchSysCacheStruct(ATTNAME, (char *) &att_tup,
- ObjectIdGetDatum(relid),
- PointerGetDatum(attname),
- 0, 0))
- return (att_tup.attnum);
+ result = att_tup->attnum;
+ ReleaseSysCache(tp);
+ return result;
+ }
else
- return (InvalidAttrNumber);
+ 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)
{
- AttributeTupleForm att_tup = (AttributeTupleForm) palloc(sizeof(*att_tup));
+ HeapTuple tp;
- if (SearchSysCacheStruct(ATTNUM,
- (char *) att_tup,
- ObjectIdGetDatum(relid),
- UInt16GetDatum(attnum),
- 0, 0))
- return (att_tup->atttypid);
+ tp = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum),
+ 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+ Oid result;
+
+ result = att_tup->atttypid;
+ ReleaseSysCache(tp);
+ return result;
+ }
else
- return ((Oid) NULL);
+ return InvalidOid;
}
/* This routine uses the attname instead of the attnum because it
bool
get_attisset(Oid relid, char *attname)
{
- HeapTuple htup;
- AttrNumber attno;
- AttributeTupleForm att_tup;
-
- attno = get_attnum(relid, attname);
-
- htup = SearchSysCacheTuple(ATTNAME,
- ObjectIdGetDatum(relid),
- PointerGetDatum(attname),
- 0, 0);
- if (!HeapTupleIsValid(htup))
- elog(WARN, "get_attisset: no attribute %.16s in relation %d",
- attname, relid);
- if (heap_attisnull(htup, attno))
- return (false);
+ HeapTuple tp;
+
+ tp = SearchSysCache(ATTNAME,
+ ObjectIdGetDatum(relid),
+ PointerGetDatum(attname),
+ 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+ bool result;
+
+ result = att_tup->attisset;
+ ReleaseSysCache(tp);
+ return result;
+ }
else
+ return false;
+}
+
+/*
+ * get_atttypmod
+ *
+ * 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 = SearchSysCache(ATTNUM,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum),
+ 0, 0);
+ if (HeapTupleIsValid(tp))
{
- att_tup = (AttributeTupleForm) GETSTRUCT(htup);
- return (att_tup->attisset);
+ Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+ int32 result;
+
+ result = att_tup->atttypmod;
+ ReleaseSysCache(tp);
+ return result;
}
+ else
+ return -1;
+}
+
+/*
+ * get_atttypetypmod
+ *
+ * A two-fer: given the relation id and the attribute number,
+ * fetch both type OID and atttypmod in a single cache lookup.
+ *
+ * Unlike the otherwise-similar get_atttype/get_atttypmod, this routine
+ * raises an error if it can't obtain the information.
+ */
+void
+get_atttypetypmod(Oid relid, AttrNumber attnum,
+ Oid *typid, int32 *typmod)
+{
+ 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 relation %u attribute %d",
+ relid, attnum);
+ att_tup = (Form_pg_attribute) GETSTRUCT(tp);
+
+ *typid = att_tup->atttypid;
+ *typmod = att_tup->atttypmod;
+ ReleaseSysCache(tp);
}
/* ---------- INDEX CACHE ---------- */
/* watch this space...
*/
+/* ---------- OPCLASS CACHE ---------- */
+
+/*
+ * opclass_is_btree
+ *
+ * Returns TRUE iff the specified opclass is associated with the
+ * btree index access method.
+ */
+bool
+opclass_is_btree(Oid opclass)
+{
+ HeapTuple tp;
+ Form_pg_opclass cla_tup;
+ bool result;
+
+ tp = SearchSysCache(CLAOID,
+ ObjectIdGetDatum(opclass),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for opclass %u", opclass);
+ cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
+
+ result = (cla_tup->opcamid == BTREE_AM_OID);
+ ReleaseSysCache(tp);
+ return result;
+}
+
/* ---------- OPERATOR CACHE ---------- */
/*
- * get_opcode -
+ * get_opcode
*
* Returns the regproc id of the routine used to implement an
- * operator given the operator uid.
- *
+ * operator given the operator oid.
*/
RegProcedure
get_opcode(Oid opno)
{
- FormData_pg_operator optup;
+ HeapTuple tp;
- if (SearchSysCacheStruct(OPROID, (char *) &optup,
- ObjectIdGetDatum(opno),
- 0, 0, 0))
- return (optup.oprcode);
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
+ 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: return the struct so that it gets copied.
+ * Note: returns a palloc'd copy of the string, or NULL if no such operator.
*/
-char *
+char *
get_opname(Oid opno)
{
- FormData_pg_operator optup;
+ HeapTuple tp;
- if (SearchSysCacheStruct(OPROID, (char *) &optup,
- ObjectIdGetDatum(opno),
- 0, 0, 0))
- return (pstrdup(optup.oprname.data));
- else
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
{
- elog(WARN, "can't look up operator %d\n", opno);
- return NULL;
+ Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
+ char *result;
+
+ result = pstrdup(NameStr(optup->oprname));
+ ReleaseSysCache(tp);
+ return result;
}
+ else
+ return NULL;
}
/*
- * op_mergesortable -
+ * op_mergejoinable
*
* Returns the left and right sort operators and types corresponding to a
- * mergesortable operator, or nil if the operator is not mergesortable.
- *
+ * mergejoinable operator, or nil if the operator is not mergejoinable.
*/
bool
-op_mergesortable(Oid opno, Oid ltype, Oid rtype, Oid *leftOp, Oid *rightOp)
+op_mergejoinable(Oid opno, Oid ltype, Oid rtype, Oid *leftOp, Oid *rightOp)
{
- FormData_pg_operator optup;
+ HeapTuple tp;
+ bool result = false;
- if (SearchSysCacheStruct(OPROID, (char *) &optup,
- ObjectIdGetDatum(opno),
- 0, 0, 0) &&
- optup.oprlsortop &&
- optup.oprrsortop &&
- optup.oprleft == ltype &&
- optup.oprright == rtype)
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
{
+ Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
- *leftOp = ObjectIdGetDatum(optup.oprlsortop);
- *rightOp = ObjectIdGetDatum(optup.oprrsortop);
- return TRUE;
- }
- else
- {
- return FALSE;
+ if (optup->oprlsortop &&
+ optup->oprrsortop &&
+ optup->oprleft == ltype &&
+ optup->oprright == rtype)
+ {
+ *leftOp = optup->oprlsortop;
+ *rightOp = optup->oprrsortop;
+ result = true;
+ }
+ ReleaseSysCache(tp);
}
+ 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.
*
+ * Raises error if operators cannot be found. Assuming that the operator
+ * had indeed been marked mergejoinable, this indicates that whoever marked
+ * it so was mistaken.
+ */
+void
+op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
+ RegProcedure *ltproc, RegProcedure *gtproc)
+{
+ HeapTuple tp;
+ Form_pg_operator optup;
+ Oid oprleft,
+ oprright;
+
+ /*
+ * Get the declared left and right operand types of the operator.
+ */
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp)) /* shouldn't happen */
+ elog(ERROR, "op_mergejoin_crossops: operator %u not found", opno);
+ optup = (Form_pg_operator) GETSTRUCT(tp);
+ oprleft = optup->oprleft;
+ oprright = optup->oprright;
+ ReleaseSysCache(tp);
+
+ /*
+ * Look up the "<" operator with the same input types. If there isn't
+ * one, whoever marked the "=" operator mergejoinable was a loser.
+ */
+ tp = SearchSysCache(OPERNAME,
+ PointerGetDatum("<"),
+ ObjectIdGetDatum(oprleft),
+ ObjectIdGetDatum(oprright),
+ CharGetDatum('b'));
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "op_mergejoin_crossops: mergejoin operator %u has no matching < operator",
+ opno);
+ optup = (Form_pg_operator) GETSTRUCT(tp);
+ *ltop = tp->t_data->t_oid;
+ if (ltproc)
+ *ltproc = optup->oprcode;
+ ReleaseSysCache(tp);
+
+ /*
+ * And the same for the ">" operator.
+ */
+ tp = SearchSysCache(OPERNAME,
+ PointerGetDatum(">"),
+ ObjectIdGetDatum(oprleft),
+ ObjectIdGetDatum(oprright),
+ CharGetDatum('b'));
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "op_mergejoin_crossops: mergejoin operator %u has no matching > operator",
+ opno);
+ optup = (Form_pg_operator) GETSTRUCT(tp);
+ *gtop = tp->t_data->t_oid;
+ if (gtproc)
+ *gtproc = optup->oprcode;
+ ReleaseSysCache(tp);
+}
+
+/*
+ * op_hashjoinable
+ *
+ * Returns the hash operator corresponding to a hashjoinable operator,
+ * or InvalidOid if the operator is not hashjoinable.
*/
Oid
op_hashjoinable(Oid opno, Oid ltype, Oid rtype)
{
- FormData_pg_operator optup;
+ HeapTuple tp;
+ Oid result = InvalidOid;
- if (SearchSysCacheStruct(OPROID, (char *) &optup,
- ObjectIdGetDatum(opno),
- 0, 0, 0) &&
- optup.oprcanhash &&
- optup.oprleft == ltype &&
- optup.oprright == rtype)
- return (opno);
- else
- return (InvalidOid);
+ 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)
+ result = opno;
+ ReleaseSysCache(tp);
+ }
+ return result;
}
/*
- * get_commutator -
- *
- * Returns the corresponding commutator of an operator.
+ * op_iscachable
*
+ * Get the proiscachable flag for the operator's underlying function.
*/
-Oid
-get_commutator(Oid opno)
+bool
+op_iscachable(Oid opno)
{
- FormData_pg_operator optup;
+ RegProcedure funcid = get_opcode(opno);
- if (SearchSysCacheStruct(OPROID, (char *) &optup,
- ObjectIdGetDatum(opno),
- 0, 0, 0))
- return (optup.oprcom);
- else
- return ((Oid) NULL);
+ if (funcid == (RegProcedure) InvalidOid)
+ elog(ERROR, "Operator OID %u does not exist", opno);
+
+ return func_iscachable((Oid) funcid);
}
-HeapTuple
-get_operator_tuple(Oid opno)
+/*
+ * get_commutator
+ *
+ * Returns the corresponding commutator of an operator.
+ */
+Oid
+get_commutator(Oid opno)
{
- HeapTuple optup;
+ HeapTuple tp;
+
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
+ Oid result;
- if ((optup = SearchSysCacheTuple(OPROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0)))
- return (optup);
+ result = optup->oprcom;
+ ReleaseSysCache(tp);
+ return result;
+ }
else
- return ((HeapTuple) NULL);
+ return InvalidOid;
}
/*
- * get_negator -
+ * get_negator
*
* Returns the corresponding negator of an operator.
- *
*/
Oid
get_negator(Oid opno)
{
- FormData_pg_operator optup;
+ HeapTuple tp;
- if (SearchSysCacheStruct(OPROID, (char *) &optup,
- ObjectIdGetDatum(opno),
- 0, 0, 0))
- return (optup.oprnegate);
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
+ Oid result;
+
+ result = optup->oprnegate;
+ ReleaseSysCache(tp);
+ return result;
+ }
else
- return ((Oid) NULL);
+ return InvalidOid;
}
/*
- * get_oprrest -
+ * get_oprrest
*
* Returns procedure id for computing selectivity of an operator.
- *
*/
RegProcedure
get_oprrest(Oid opno)
{
- FormData_pg_operator optup;
+ HeapTuple tp;
+
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
+ RegProcedure result;
- if (SearchSysCacheStruct(OPROID, (char *) &optup,
- ObjectIdGetDatum(opno),
- 0, 0, 0))
- return (optup.oprrest);
+ 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)
{
- FormData_pg_operator optup;
+ HeapTuple tp;
+
+ tp = SearchSysCache(OPEROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
+ RegProcedure result;
- if (SearchSysCacheStruct(OPROID, (char *) &optup,
- ObjectIdGetDatum(opno),
- 0, 0, 0))
- return (optup.oprjoin);
+ result = optup->oprjoin;
+ ReleaseSysCache(tp);
+ return result;
+ }
else
- return ((RegProcedure) NULL);
+ return (RegProcedure) InvalidOid;
+}
+
+/* ---------- FUNCTION CACHE ---------- */
+
+/*
+ * get_func_rettype
+ * Given procedure id, return the function's result type.
+ */
+Oid
+get_func_rettype(Oid funcid)
+{
+ HeapTuple tp;
+ Oid result;
+
+ tp = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(funcid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "Function OID %u does not exist", funcid);
+
+ result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype;
+ ReleaseSysCache(tp);
+ return result;
+}
+
+/*
+ * func_iscachable
+ * Given procedure id, return the function's proiscachable flag.
+ */
+bool
+func_iscachable(Oid funcid)
+{
+ HeapTuple tp;
+ bool result;
+
+ tp = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(funcid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "Function OID %u does not exist", funcid);
+
+ result = ((Form_pg_proc) GETSTRUCT(tp))->proiscachable;
+ ReleaseSysCache(tp);
+ return result;
}
/* ---------- RELATION CACHE ---------- */
/*
- * get_relnatts -
+ * get_relname_relid
+ * Given name and namespace of a relation, look up the OID.
*
- * Returns the number of attributes for a given relation.
+ * 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);
+}
+
+#ifdef NOT_USED
+/*
+ * get_relnatts
*
+ * Returns the number of attributes for a given relation.
*/
int
get_relnatts(Oid relid)
{
- FormData_pg_class reltup;
+ HeapTuple tp;
- if (SearchSysCacheStruct(RELOID, (char *) &reltup,
- ObjectIdGetDatum(relid),
- 0, 0, 0))
- return (reltup.relnatts);
+ 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);
+ return InvalidAttrNumber;
}
+#endif
/*
- * get_rel_name -
- *
+ * 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 *
+char *
get_rel_name(Oid relid)
{
- FormData_pg_class reltup;
+ HeapTuple tp;
- if ((SearchSysCacheStruct(RELOID,
- (char *) &reltup,
- ObjectIdGetDatum(relid),
- 0, 0, 0)))
+ tp = SearchSysCache(RELOID,
+ ObjectIdGetDatum(relid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
{
- return (pstrdup(reltup.relname.data));
+ Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
+ char *result;
+
+ result = pstrdup(NameStr(reltup->relname));
+ ReleaseSysCache(tp);
+ return result;
}
else
- return (NULL);
+ return NULL;
+}
+
+/*
+ * 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;
}
/* ---------- TYPE CACHE ---------- */
/*
- * get_typlen -
+ * get_typisdefined
*
- * Given the type OID, return the length of the type.
+ * Given the type OID, determine whether the type is defined
+ * (if not, it's only a shell).
+ */
+bool
+get_typisdefined(Oid typid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+ bool result;
+
+ result = typtup->typisdefined;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return false;
+}
+
+/*
+ * get_typlen
*
+ * Given the type OID, return the length of the type.
*/
int16
get_typlen(Oid typid)
{
- TypeTupleFormData typtup;
+ HeapTuple tp;
- if (SearchSysCacheStruct(TYPOID, (char *) &typtup,
- ObjectIdGetDatum(typid),
- 0, 0, 0))
- return (typtup.typlen);
+ 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 ((int16) NULL);
+ return 0;
}
/*
- * get_typbyval -
+ * 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.
- *
+ * not. Returns true if by value, false if by reference.
*/
bool
get_typbyval(Oid typid)
{
- TypeTupleFormData typtup;
+ HeapTuple tp;
- if (SearchSysCacheStruct(TYPOID, (char *) &typtup,
- ObjectIdGetDatum(typid),
- 0, 0, 0))
- return ((bool) typtup.typbyval);
+ 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);
+ return false;
}
/*
- * get_typbyval -
+ * get_typlenbyval
*
- * Given the type OID, determine whether the type is returned by value or
- * not. Returns 1 if by value, 0 if by reference.
+ * 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);
+}
+
#ifdef NOT_USED
char
get_typalign(Oid typid)
{
- TypeTupleFormData typtup;
+ HeapTuple tp;
- if (SearchSysCacheStruct(TYPOID, (char *) &typtup,
- ObjectIdGetDatum(typid),
- 0, 0, 0))
- return (typtup.typalign);
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+ char result;
+
+ result = typtup->typalign;
+ ReleaseSysCache(tp);
+ return result;
+ }
else
- return ('i');
+ 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_typdefault
+ * Given a type OID, return the type's default value, if any.
*
- * Given the type OID, return the default value of the ADT.
+ * The result is a palloc'd expression node tree, or NULL if there
+ * is no defined default for the datatype.
*
+ * NB: caller should be prepared to coerce result to correct datatype;
+ * the returned expression tree might produce something of the wrong type.
*/
-struct varlena *
+Node *
get_typdefault(Oid typid)
{
- struct varlena *typdefault =
- (struct varlena *) TypeDefaultRetrieve(typid);
+ HeapTuple typeTuple;
+ Form_pg_type type;
+ Datum datum;
+ bool isNull;
+ Node *expr;
+
+ typeTuple = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(typeTuple))
+ elog(ERROR, "get_typdefault: failed to lookup type %u", typid);
+ type = (Form_pg_type) GETSTRUCT(typeTuple);
+
+ /*
+ * typdefault and typdefaultbin are potentially null, so don't try to
+ * access 'em as struct fields. Must do it the hard way with
+ * SysCacheGetAttr.
+ */
+ datum = SysCacheGetAttr(TYPEOID,
+ typeTuple,
+ Anum_pg_type_typdefaultbin,
+ &isNull);
+
+ if (!isNull)
+ {
+ /* We have an expression default */
+ expr = stringToNode(DatumGetCString(DirectFunctionCall1(textout,
+ datum)));
+ }
+ else
+ {
+ /* Perhaps we have a plain literal default */
+ datum = SysCacheGetAttr(TYPEOID,
+ typeTuple,
+ Anum_pg_type_typdefault,
+ &isNull);
+
+ if (!isNull)
+ {
+ char *strDefaultVal;
+
+ /* Convert text datum to C string */
+ strDefaultVal = DatumGetCString(DirectFunctionCall1(textout,
+ datum));
+ /* Convert C string to a value of the given type */
+ datum = OidFunctionCall3(type->typinput,
+ CStringGetDatum(strDefaultVal),
+ ObjectIdGetDatum(type->typelem),
+ Int32GetDatum(-1));
+ /* Build a Const node containing the value */
+ expr = (Node *) makeConst(typid,
+ type->typlen,
+ datum,
+ false,
+ type->typbyval,
+ false, /* not a set */
+ false);
+ pfree(strDefaultVal);
+ }
+ else
+ {
+ /* No default */
+ expr = NULL;
+ }
+ }
+
+ ReleaseSysCache(typeTuple);
+
+ return expr;
+}
+
+/*
+ * getBaseType
+ * If the given type is a domain, return its base type;
+ * otherwise return the type's own OID.
+ */
+Oid
+getBaseType(Oid typid)
+{
+ /*
+ * We loop to find the bottom base type in a stack of domains.
+ */
+ for (;;)
+ {
+ HeapTuple tup;
+ Form_pg_type typTup;
+
+ tup = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "getBaseType: failed to lookup type %u", typid);
+ typTup = (Form_pg_type) GETSTRUCT(tup);
+ if (typTup->typtype != 'd')
+ {
+ /* Not a domain, so done */
+ ReleaseSysCache(tup);
+ break;
+ }
+
+ typid = typTup->typbasetype;
+ ReleaseSysCache(tup);
+ }
+
+ return typid;
+}
+
+/*
+ * get_typavgwidth
+ *
+ * Given a type OID and a typmod value (pass -1 if typmod is unknown),
+ * estimate the average width of values of the type. This is used by
+ * the planner, which doesn't require absolutely correct results;
+ * it's OK (and expected) to guess if we don't know for sure.
+ */
+int32
+get_typavgwidth(Oid typid, int32 typmod)
+{
+ int typlen = get_typlen(typid);
+ int32 maxwidth;
+
+ /*
+ * Easy if it's a fixed-width type
+ */
+ if (typlen > 0)
+ return typlen;
- return (typdefault);
+ /*
+ * 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 -
+ * get_typtype
*
* 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...
- *
*/
#ifdef NOT_USED
char
get_typtype(Oid typid)
{
- TypeTupleFormData typtup;
+ HeapTuple tp;
- if (SearchSysCacheStruct(TYPOID, (char *) &typtup,
- ObjectIdGetDatum(typid),
- 0, 0, 0))
+ tp = SearchSysCache(TYPEOID,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(tp))
{
- return (typtup.typtype);
+ Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+ char result;
+
+ result = typtup->typtype;
+ ReleaseSysCache(tp);
+ return result;
}
else
+ return '\0';
+}
+#endif
+
+/* ---------- 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))
{
- return ('\0');
+ int32 stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
+
+ ReleaseSysCache(tp);
+ if (stawidth > 0)
+ return stawidth;
}
+ return 0;
}
-#endif
+/*
+ * 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;
+ FmgrInfo inputproc;
+ Oid typelem;
+
+ 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, "get_attstatsslot: stavalues is null");
+ statarray = DatumGetArrayTypeP(val);
+
+ /*
+ * Do initial examination of the array. This produces a list of
+ * text Datums --- ie, pointers into the text array value.
+ */
+ deconstruct_array(statarray, false, -1, 'i', values, nvalues);
+ narrayelem = *nvalues;
+
+ /*
+ * We now need to replace each text Datum by its internal
+ * equivalent.
+ *
+ * Get the type input proc and typelem for the column datatype.
+ */
+ 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);
+
+ /*
+ * Do the conversions. The palloc'd array of Datums is reused in
+ * place.
+ */
+ for (j = 0; j < narrayelem; j++)
+ {
+ char *strval;
+
+ strval = DatumGetCString(DirectFunctionCall1(textout,
+ (*values)[j]));
+ (*values)[j] = FunctionCall3(&inputproc,
+ CStringGetDatum(strval),
+ ObjectIdGetDatum(typelem),
+ Int32GetDatum(atttypmod));
+ pfree(strval);
+ }
+
+ /*
+ * 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, "get_attstatsslot: 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_SIZE(statarray) != (ARR_OVERHEAD(1) + narrayelem * sizeof(float4)))
+ elog(ERROR, "get_attstatsslot: stanumbers is bogus");
+ *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_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 ...
+ */
+int32
+get_usesysid(const char *username)
+{
+ int32 result;
+ HeapTuple userTup;
+
+ userTup = SearchSysCache(SHADOWNAME,
+ PointerGetDatum(username),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(userTup))
+ elog(ERROR, "user \"%s\" does not exist", username);
+
+ result = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid;
+
+ ReleaseSysCache(userTup);
+
+ return result;
+}