Skip to content
Snippets Groups Projects
lsyscache.c 58.8 KiB
Newer Older
/*-------------------------------------------------------------------------
 *
 *	  Convenience routines for common queries in the system catalog cache.
 * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
Bruce Momjian's avatar
Bruce Momjian committed
 * Portions Copyright (c) 1994, Regents of the University of California
 *	  $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.143 2007/01/10 18:06:04 tgl Exp $
 *	  Eventually, the index information should go through here, too.
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "bootstrap/bootstrap.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
Tom Lane's avatar
Tom Lane committed
#include "nodes/makefuncs.h"
#include "utils/array.h"
#include "utils/builtins.h"
Bruce Momjian's avatar
Bruce Momjian committed
#include "utils/lsyscache.h"
#include "utils/syscache.h"
/*				---------- AMOP CACHES ----------						 */
 *		Return t iff operator 'opno' is in operator family 'opfamily'.
op_in_opfamily(Oid opno, Oid opfamily)
	return SearchSysCacheExists(AMOPOPID,
								ObjectIdGetDatum(opno),
 *		Get the operator's strategy number within the specified opfamily,
 *		or 0 if it's not a member of the opfamily.
get_op_opfamily_strategy(Oid opno, Oid opfamily)
{
	HeapTuple	tp;
	Form_pg_amop amop_tup;
	int			result;

	tp = SearchSysCache(AMOPOPID,
						ObjectIdGetDatum(opno),
						0, 0);
	if (!HeapTupleIsValid(tp))
		return 0;
	amop_tup = (Form_pg_amop) GETSTRUCT(tp);
	result = amop_tup->amopstrategy;
	ReleaseSysCache(tp);
	return result;
}

 *		Get the operator's strategy number, input types, and recheck (lossy)
 *		flag within the specified opfamily.
 * Caller should already have verified that opno is a member of opfamily,
 * therefore we raise an error if the tuple is not found.
 */
get_op_opfamily_properties(Oid opno, Oid opfamily,
						   int *strategy,
						   Oid *lefttype,
						   Oid *righttype,
						   bool *recheck)
{
	HeapTuple	tp;
	Form_pg_amop amop_tup;

	tp = SearchSysCache(AMOPOPID,
						ObjectIdGetDatum(opno),
		elog(ERROR, "operator %u is not a member of opfamily %u",
			 opno, opfamily);
	amop_tup = (Form_pg_amop) GETSTRUCT(tp);
	*strategy = amop_tup->amopstrategy;
	*lefttype = amop_tup->amoplefttype;
	*righttype = amop_tup->amoprighttype;
	*recheck = amop_tup->amopreqcheck;
 *		Get the OID of the operator that implements the specified strategy
 *		with the specified datatypes for the specified opfamily.
 *
 * Returns InvalidOid if there is no pg_amop entry for the given keys.
 */
Oid
get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype,
					int16 strategy)
{
	HeapTuple	tp;
	Form_pg_amop amop_tup;
	Oid			result;

	tp = SearchSysCache(AMOPSTRATEGY,
						ObjectIdGetDatum(opfamily),
						ObjectIdGetDatum(lefttype),
						ObjectIdGetDatum(righttype),
						Int16GetDatum(strategy));
	if (!HeapTupleIsValid(tp))
		return InvalidOid;
	amop_tup = (Form_pg_amop) GETSTRUCT(tp);
	result = amop_tup->amopopr;
	ReleaseSysCache(tp);
	return result;
}

/*
 * get_op_mergejoin_info
 *		Given the OIDs of a (putatively) mergejoinable equality operator
 *		and a sortop defining the sort ordering of the lefthand input of
 *		the merge clause, determine whether this sort ordering is actually
 *		usable for merging.  If so, return the required sort ordering op
 *		for the righthand input, as well as the btree opfamily OID containing
 *		these operators and the operator strategy number of the two sortops
 *		(either BTLessStrategyNumber or BTGreaterStrategyNumber).
 *
 * We can mergejoin if we find the two operators in the same opfamily as
 * equality and either less-than or greater-than respectively.  If there
 * are multiple such opfamilies, assume we can use any one.
 */
#ifdef NOT_YET
/* eventually should look like this */
bool
get_op_mergejoin_info(Oid eq_op, Oid left_sortop,
					  Oid *right_sortop, Oid *opfamily, int *opstrategy)
{
	bool		result = false;
	Oid			lefttype;
	Oid			righttype;
	CatCList   *catlist;
	int			i;

	/* Make sure output args are initialized even on failure */
	*right_sortop = InvalidOid;
	*opfamily = InvalidOid;
	*opstrategy = 0;

	/* Need the righthand input datatype */
	op_input_types(eq_op, &lefttype, &righttype);

	/*
	 * Search through all the pg_amop entries containing the equality operator
	 */
	catlist = SearchSysCacheList(AMOPOPID, 1,
								 ObjectIdGetDatum(eq_op),
								 0, 0, 0);

	for (i = 0; i < catlist->n_members; i++)
	{
		HeapTuple	op_tuple = &catlist->members[i]->tuple;
		Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
		Oid			opfamily_id;
		StrategyNumber op_strategy;

		/* must be btree */
		if (op_form->amopmethod != BTREE_AM_OID)
			continue;
		/* must use the operator as equality */
		if (op_form->amopstrategy != BTEqualStrategyNumber)
			continue;

		/* See if sort operator is also in this opfamily with OK semantics */
		opfamily_id = op_form->amopfamily;
		op_strategy = get_op_opfamily_strategy(left_sortop, opfamily_id);
		if (op_strategy == BTLessStrategyNumber ||
			op_strategy == BTGreaterStrategyNumber)
		{
			/* Yes, so find the corresponding righthand sortop */
			*right_sortop = get_opfamily_member(opfamily_id,
												righttype,
												righttype,
												op_strategy);
			if (OidIsValid(*right_sortop))
			{
				/* Found a workable mergejoin semantics */
				*opfamily = opfamily_id;
				*opstrategy = op_strategy;
				result = true;
				break;
			}
		}
	}

	ReleaseSysCacheList(catlist);

	return result;
}
#else
/* temp implementation until planner gets smarter: left_sortop is output */
bool
get_op_mergejoin_info(Oid eq_op, Oid *left_sortop,
					  Oid *right_sortop, Oid *opfamily)
{
	bool		result = false;
	Oid			lefttype;
	Oid			righttype;
	CatCList   *catlist;
	int			i;

	/* Make sure output args are initialized even on failure */
	*left_sortop = InvalidOid;
	*right_sortop = InvalidOid;
	*opfamily = InvalidOid;

	/* Need the input datatypes */
	op_input_types(eq_op, &lefttype, &righttype);

	/*
	 * Search through all the pg_amop entries containing the equality operator
	 */
	catlist = SearchSysCacheList(AMOPOPID, 1,
								 ObjectIdGetDatum(eq_op),
								 0, 0, 0);

	for (i = 0; i < catlist->n_members; i++)
	{
		HeapTuple	op_tuple = &catlist->members[i]->tuple;
		Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
		Oid			opfamily_id;

		/* must be btree */
		if (op_form->amopmethod != BTREE_AM_OID)
			continue;
		/* must use the operator as equality */
		if (op_form->amopstrategy != BTEqualStrategyNumber)
			continue;

		opfamily_id = op_form->amopfamily;

		/* Find the matching sortops */
		*left_sortop = get_opfamily_member(opfamily_id,
										   lefttype,
										   lefttype,
										   BTLessStrategyNumber);
		*right_sortop = get_opfamily_member(opfamily_id,
											righttype,
											righttype,
											BTLessStrategyNumber);
		if (OidIsValid(*left_sortop) && OidIsValid(*right_sortop))
		{
			/* Found a workable mergejoin semantics */
			*opfamily = opfamily_id;
			result = true;
			break;
		}
	}

	ReleaseSysCacheList(catlist);

	return result;
}
#endif

 * get_compare_function_for_ordering_op
 *		Get the OID of the datatype-specific btree comparison function
 *		associated with an ordering operator (a "<" or ">" operator).
 *
 * *cmpfunc receives the comparison function OID.
 * *reverse is set FALSE if the operator is "<", TRUE if it's ">"
 * (indicating the comparison result must be negated before use).
 *
 * Returns TRUE if successful, FALSE if no btree function can be found.
 * (This indicates that the operator is not a valid ordering operator.)
 */
bool
get_compare_function_for_ordering_op(Oid opno, Oid *cmpfunc, bool *reverse)
{
	bool		result = false;
	CatCList   *catlist;
	int			i;

	/* ensure outputs are set on failure */
	*cmpfunc = InvalidOid;
	*reverse = false;

	/*
	 * Search pg_amop to see if the target operator is registered as the "<"
	 * or ">" operator of any btree opfamily.  It's possible that it might be
	 * registered both ways (if someone were to build a "reverse sort"
	 * opfamily); assume we can use either interpretation.  (Note: the
	 * existence of a reverse-sort opfamily would result in uncertainty as
	 * to whether "ORDER BY USING op" would default to NULLS FIRST or NULLS
	 * LAST.  Since there is no longer any particularly good reason to build
	 * reverse-sort opfamilies, we don't bother expending any extra work to
	 * make this more determinate.  In practice, because of the way the
	 * syscache search works, we'll use the interpretation associated with
	 * the opfamily with smallest OID, which is probably determinate enough.)
	 */
	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);

		/* must be btree */
		if (aform->amopmethod != BTREE_AM_OID)
			continue;

		if (aform->amopstrategy == BTLessStrategyNumber ||
			aform->amopstrategy == BTGreaterStrategyNumber)
		{
			/* Found a suitable opfamily, get matching support function */
			*reverse = (aform->amopstrategy == BTGreaterStrategyNumber);
			*cmpfunc = get_opfamily_proc(aform->amopfamily,
										 aform->amoplefttype,
										 aform->amoprighttype,
										 BTORDER_PROC);
			if (!OidIsValid(*cmpfunc))				/* should not happen */
				elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
					 BTORDER_PROC, aform->amoplefttype, aform->amoprighttype,
					 aform->amopfamily);
			result = true;
			break;
		}
	}

	ReleaseSysCacheList(catlist);

	return result;
}

/*
 * get_equality_op_for_ordering_op
 *		Get the OID of the datatype-specific btree equality operator
 *		associated with an ordering operator (a "<" or ">" operator).
 *
 * Returns InvalidOid if no matching equality operator can be found.
 * (This indicates that the operator is not a valid ordering operator.)
 */
Oid
get_equality_op_for_ordering_op(Oid opno)
{
	Oid			result = InvalidOid;
	CatCList   *catlist;
	int			i;

	/*
	 * Search pg_amop to see if the target operator is registered as the "<"
	 * or ">" operator of any btree opfamily.  This is exactly like
	 * get_compare_function_for_ordering_op except we don't care whether the
	 * ordering op is "<" or ">" ... the equality operator will be the same
	 * either way.
	 */
	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);

		/* must be btree */
		if (aform->amopmethod != BTREE_AM_OID)
			continue;

		if (aform->amopstrategy == BTLessStrategyNumber ||
			aform->amopstrategy == BTGreaterStrategyNumber)
		{
			/* Found a suitable opfamily, get matching equality operator */
			result = get_opfamily_member(aform->amopfamily,
										 aform->amoplefttype,
										 aform->amoprighttype,
										 BTEqualStrategyNumber);
			if (OidIsValid(result))
				break;
			/* failure probably shouldn't happen, but keep looking if so */
		}
	}

	ReleaseSysCacheList(catlist);

	return result;
}

/*
 * get_ordering_op_for_equality_op
 *		Get the OID of a datatype-specific btree ordering operator
 *		associated with an equality operator.  (If there are multiple
 *		possibilities, assume any one will do.)
 *
 * This function is used when we have to sort data before unique-ifying,
 * and don't much care which sorting op is used as long as it's compatible
 * with the intended equality operator.  Since we need a sorting operator,
 * it should be single-data-type even if the given operator is cross-type.
 * The caller specifies whether to find an op for the LHS or RHS data type.
 *
 * Returns InvalidOid if no matching ordering operator can be found.
 */
Oid
get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type)
{
	Oid			result = InvalidOid;
	CatCList   *catlist;
	int			i;

	/*
	 * Search pg_amop to see if the target operator is registered as the "="
	 * operator of any btree opfamily.
	 */
	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);

		/* must be btree */
		if (aform->amopmethod != BTREE_AM_OID)
			continue;

		if (aform->amopstrategy == BTEqualStrategyNumber)
		{
			/* Found a suitable opfamily, get matching ordering operator */
			Oid		typid;

			typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
			result = get_opfamily_member(aform->amopfamily,
										 typid, typid,
										 BTLessStrategyNumber);
			if (OidIsValid(result))
				break;
			/* failure probably shouldn't happen, but keep looking if so */
		}
	}

	ReleaseSysCacheList(catlist);

	return result;
}

/*
 * get_compatible_hash_operator
 *		Get the OID of a hash equality operator compatible with the given
 *		operator, but operating on its LHS or RHS datatype as specified.
 *
 * If the given operator is not cross-type, the result should be the same
 * operator, but in cross-type situations it is different.
 *
 * Returns InvalidOid if no compatible operator can be found.  (This indicates
 * that the operator should not have been marked oprcanhash.)
 */
Oid
get_compatible_hash_operator(Oid opno, bool use_lhs_type)
{
	Oid			result = InvalidOid;
	CatCList   *catlist;
	int			i;

	/*
	 * Search pg_amop to see if the target operator is registered as the "="
	 * operator of any hash opfamily.  If the operator is registered in
	 * multiple opfamilies, assume we can use 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->amopmethod == HASH_AM_OID &&
			aform->amopstrategy == HTEqualStrategyNumber)
		{
			/* Found a suitable opfamily, get matching single-type operator */
			Oid		typid;

			/* No extra lookup needed if given operator is single-type */
			if (aform->amoplefttype == aform->amoprighttype)
			{
				result = opno;
				break;
			}
			typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
			result = get_opfamily_member(aform->amopfamily,
										 typid, typid,
										 HTEqualStrategyNumber);
			if (OidIsValid(result))
				break;
			/* failure probably shouldn't happen, but keep looking if so */
		}
	}

	ReleaseSysCacheList(catlist);

	return result;
}

/*
 * get_op_hash_function
 *		Get the OID of the datatype-specific hash function associated with
 *		a hashable equality operator.
 *
 * XXX API needs to be generalized for the case of different left and right
 * datatypes.
 *
 * 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)
{
	 * Search pg_amop to see if the target operator is registered as the "="
	 * operator of any hash opfamily.  If the operator is registered in
	 * multiple opfamilies, 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->amopmethod == HASH_AM_OID &&
			aform->amopstrategy == HTEqualStrategyNumber)
			/* Found a suitable opfamily, get matching hash support function */
			result = get_opfamily_proc(aform->amopfamily,
									   aform->amoplefttype,
									   aform->amoprighttype,
									   HASHPROC);
 *		Given an operator's OID, find out which btree opfamilies it belongs to,
 *		and what strategy number it has within each one.  The results are
 *		returned as an OID list and a parallel integer list.
 *
 * In addition to the normal btree operators, we consider a <> operator to be
 * a "member" of an opfamily if its negator is an equality operator of the
 * opfamily.  ROWCOMPARE_NE is returned as the strategy number for this case.
get_op_btree_interpretation(Oid opno, List **opfamilies, List **opstrats)
	*opstrats = NIL;

	/*
	 * Find all the pg_amop entries containing the operator.
	 */
	catlist = SearchSysCacheList(AMOPOPID, 1,
								 ObjectIdGetDatum(opno),
								 0, 0, 0);
	 * If we can't find any opfamily containing the op, perhaps it is a <>
	 * operator.  See if it has a negator that is in an opfamily.
	 */
	op_negated = false;
	if (catlist->n_members == 0)
	{
Bruce Momjian's avatar
Bruce Momjian committed
		Oid			op_negator = get_negator(opno);

		if (OidIsValid(op_negator))
		{
			op_negated = true;
			ReleaseSysCacheList(catlist);
			catlist = SearchSysCacheList(AMOPOPID, 1,
										 ObjectIdGetDatum(op_negator),
										 0, 0, 0);
		}
	}

	for (i = 0; i < catlist->n_members; i++)
	{
		HeapTuple	op_tuple = &catlist->members[i]->tuple;
		Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
		StrategyNumber op_strategy;

		/* must be btree */
		if (op_form->amopmethod != BTREE_AM_OID)
			continue;

		/* Get the operator's btree strategy number */
		opfamily_id = op_form->amopfamily;
		op_strategy = (StrategyNumber) op_form->amopstrategy;
		Assert(op_strategy >= 1 && op_strategy <= 5);

		if (op_negated)
		{
			/* Only consider negators that are = */
			if (op_strategy != BTEqualStrategyNumber)
				continue;
			op_strategy = ROWCOMPARE_NE;
		}

		*opfamilies = lappend_oid(*opfamilies, opfamily_id);
		*opstrats = lappend_int(*opstrats, op_strategy);
	}

	ReleaseSysCacheList(catlist);
}

/*
 * ops_in_same_btree_opfamily
 *		Return TRUE if there exists a btree opfamily containing both operators.
 *		(This implies that they have compatible notions of equality.)
 */
bool
ops_in_same_btree_opfamily(Oid opno1, Oid opno2)
{
	bool		result = false;
	CatCList   *catlist;
	int			i;

	/*
	 * We search through all the pg_amop entries for opno1.
	 */
	catlist = SearchSysCacheList(AMOPOPID, 1,
								 ObjectIdGetDatum(opno1),
								 0, 0, 0);
	for (i = 0; i < catlist->n_members; i++)
	{
		HeapTuple	op_tuple = &catlist->members[i]->tuple;
		Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);

		/* must be btree */
		if (op_form->amopmethod != BTREE_AM_OID)
			continue;

		if (op_in_opfamily(opno2, op_form->amopfamily))
		{
			result = true;
			break;
		}
	}

	ReleaseSysCacheList(catlist);

	return result;
}

/*				---------- AMPROC CACHES ----------						 */

/*
 *		Get the OID of the specified support function
 *		for the specified opfamily and datatypes.
 *
 * Returns InvalidOid if there is no pg_amproc entry for the given keys.
 */
Oid
get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
{
	HeapTuple	tp;
	Form_pg_amproc amproc_tup;
	RegProcedure result;

	tp = SearchSysCache(AMPROCNUM,
						ObjectIdGetDatum(opfamily),
						ObjectIdGetDatum(lefttype),
						ObjectIdGetDatum(righttype),
						Int16GetDatum(procnum));
	if (!HeapTupleIsValid(tp))
		return InvalidOid;
	amproc_tup = (Form_pg_amproc) GETSTRUCT(tp);
	result = amproc_tup->amproc;
	ReleaseSysCache(tp);
	return result;
}


/*				---------- ATTRIBUTE CACHES ----------					 */
 *		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.
get_attname(Oid relid, AttrNumber attnum)
{
	tp = SearchSysCache(ATTNUM,
						ObjectIdGetDatum(relid),
						Int16GetDatum(attnum),
						0, 0);
	if (HeapTupleIsValid(tp))
	{
		Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
		char	   *result;
		result = pstrdup(NameStr(att_tup->attname));
		ReleaseSysCache(tp);
		return result;
Bruce Momjian's avatar
Bruce Momjian committed
		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;
}

 *
 *		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).
get_attnum(Oid relid, const char *attname)
	tp = SearchSysCacheAttName(relid, attname);
	if (HeapTupleIsValid(tp))
	{
		Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
		result = att_tup->attnum;
		ReleaseSysCache(tp);
		return result;
Bruce Momjian's avatar
Bruce Momjian committed
		return InvalidAttrNumber;
 *
 *		Given the relation OID and the attribute number with the relation,
 *		return the attribute type OID.
 */
Oid
get_atttype(Oid relid, AttrNumber attnum)
{
	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;
Bruce Momjian's avatar
Bruce Momjian committed
/*
Bruce Momjian's avatar
Bruce Momjian committed
 *
 *		Given the relation id and the attribute number,
 *		return the "atttypmod" field from the attribute relation.
 */
Bruce Momjian's avatar
Bruce Momjian committed
get_atttypmod(Oid relid, AttrNumber attnum)
{
Bruce Momjian's avatar
Bruce Momjian committed

	tp = SearchSysCache(ATTNUM,
						ObjectIdGetDatum(relid),
						Int16GetDatum(attnum),
						0, 0);
	if (HeapTupleIsValid(tp))
	{
		Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
		int32		result;
		result = att_tup->atttypmod;
		ReleaseSysCache(tp);
		return result;
Bruce Momjian's avatar
Bruce Momjian committed
	else
Bruce Momjian's avatar
Bruce Momjian committed
}

/*
 * 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 attribute %d of relation %u",
			 attnum, relid);
	att_tup = (Form_pg_attribute) GETSTRUCT(tp);

	*typid = att_tup->atttypid;
	*typmod = att_tup->atttypmod;
	ReleaseSysCache(tp);
}

/*				---------- INDEX CACHE ----------						 */
/*				---------- OPCLASS CACHE ----------						 */

/*
 *		Returns the OID of the operator family the opclass belongs to.
{
	HeapTuple	tp;
	Form_pg_opclass cla_tup;

	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);

	ReleaseSysCache(tp);
	return result;
}

/*
 * get_opclass_input_type
 *
 *		Returns the OID of the datatype the opclass indexes.
 */
Oid
get_opclass_input_type(Oid opclass)
{
	HeapTuple	tp;
	Form_pg_opclass cla_tup;
	Oid			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->opcintype;
	ReleaseSysCache(tp);
/*				---------- OPERATOR CACHE ----------					 */
 *
 *		Returns the regproc id of the routine used to implement an
 *		operator given the operator oid.
 */
RegProcedure
get_opcode(Oid opno)
{
	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;
		return (RegProcedure) InvalidOid;
 *	  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.
	tp = SearchSysCache(OPEROID,
						ObjectIdGetDatum(opno),
						0, 0, 0);
	if (HeapTupleIsValid(tp))
		Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
		char	   *result;
		result = pstrdup(NameStr(optup->oprname));
		ReleaseSysCache(tp);
		return result;