* lsyscache.c
* Convenience routines for common queries in the system catalog cache.
*
- * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.143 2007/01/10 18:06:04 tgl Exp $
+ * src/backend/utils/cache/lsyscache.c
*
* NOTES
* Eventually, the index information should go through here, too.
#include "bootstrap/bootstrap.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
+#include "catalog/pg_collation.h"
+#include "catalog/pg_constraint.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
+#include "catalog/pg_range.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/datum.h"
+#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
+#include "utils/rel.h"
#include "utils/syscache.h"
+#include "utils/typcache.h"
+
+/* Hook for plugins to get control in get_attavgwidth() */
+get_attavgwidth_hook_type get_attavgwidth_hook = NULL;
/* ---------- AMOP CACHES ---------- */
* op_in_opfamily
*
* Return t iff operator 'opno' is in operator family 'opfamily'.
+ *
+ * This function only considers search operators, not ordering operators.
*/
bool
op_in_opfamily(Oid opno, Oid opfamily)
{
- return SearchSysCacheExists(AMOPOPID,
- ObjectIdGetDatum(opno),
- ObjectIdGetDatum(opfamily),
- 0, 0);
+ return SearchSysCacheExists3(AMOPOPID,
+ ObjectIdGetDatum(opno),
+ CharGetDatum(AMOP_SEARCH),
+ ObjectIdGetDatum(opfamily));
}
/*
*
* Get the operator's strategy number within the specified opfamily,
* or 0 if it's not a member of the opfamily.
+ *
+ * This function only considers search operators, not ordering operators.
*/
int
get_op_opfamily_strategy(Oid opno, Oid opfamily)
Form_pg_amop amop_tup;
int result;
- tp = SearchSysCache(AMOPOPID,
- ObjectIdGetDatum(opno),
- ObjectIdGetDatum(opfamily),
- 0, 0);
+ tp = SearchSysCache3(AMOPOPID,
+ ObjectIdGetDatum(opno),
+ CharGetDatum(AMOP_SEARCH),
+ ObjectIdGetDatum(opfamily));
if (!HeapTupleIsValid(tp))
return 0;
amop_tup = (Form_pg_amop) GETSTRUCT(tp);
return result;
}
+/*
+ * get_op_opfamily_sortfamily
+ *
+ * If the operator is an ordering operator within the specified opfamily,
+ * return its amopsortfamily OID; else return InvalidOid.
+ */
+Oid
+get_op_opfamily_sortfamily(Oid opno, Oid opfamily)
+{
+ HeapTuple tp;
+ Form_pg_amop amop_tup;
+ Oid result;
+
+ tp = SearchSysCache3(AMOPOPID,
+ ObjectIdGetDatum(opno),
+ CharGetDatum(AMOP_ORDER),
+ ObjectIdGetDatum(opfamily));
+ if (!HeapTupleIsValid(tp))
+ return InvalidOid;
+ amop_tup = (Form_pg_amop) GETSTRUCT(tp);
+ result = amop_tup->amopsortfamily;
+ ReleaseSysCache(tp);
+ return result;
+}
+
/*
* get_op_opfamily_properties
*
- * Get the operator's strategy number, input types, and recheck (lossy)
- * flag within the specified opfamily.
+ * Get the operator's strategy number and declared input data types
+ * 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.
*/
void
-get_op_opfamily_properties(Oid opno, Oid opfamily,
+get_op_opfamily_properties(Oid opno, Oid opfamily, bool ordering_op,
int *strategy,
Oid *lefttype,
- Oid *righttype,
- bool *recheck)
+ Oid *righttype)
{
HeapTuple tp;
Form_pg_amop amop_tup;
- tp = SearchSysCache(AMOPOPID,
- ObjectIdGetDatum(opno),
- ObjectIdGetDatum(opfamily),
- 0, 0);
+ tp = SearchSysCache3(AMOPOPID,
+ ObjectIdGetDatum(opno),
+ CharGetDatum(ordering_op ? AMOP_ORDER : AMOP_SEARCH),
+ ObjectIdGetDatum(opfamily));
if (!HeapTupleIsValid(tp))
elog(ERROR, "operator %u is not a member of opfamily %u",
opno, opfamily);
*strategy = amop_tup->amopstrategy;
*lefttype = amop_tup->amoplefttype;
*righttype = amop_tup->amoprighttype;
- *recheck = amop_tup->amopreqcheck;
ReleaseSysCache(tp);
}
Form_pg_amop amop_tup;
Oid result;
- tp = SearchSysCache(AMOPSTRATEGY,
- ObjectIdGetDatum(opfamily),
- ObjectIdGetDatum(lefttype),
- ObjectIdGetDatum(righttype),
- Int16GetDatum(strategy));
+ tp = SearchSysCache4(AMOPSTRATEGY,
+ ObjectIdGetDatum(opfamily),
+ ObjectIdGetDatum(lefttype),
+ ObjectIdGetDatum(righttype),
+ Int16GetDatum(strategy));
if (!HeapTupleIsValid(tp))
return InvalidOid;
amop_tup = (Form_pg_amop) GETSTRUCT(tp);
}
/*
- * 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).
+ * get_ordering_op_properties
+ * Given the OID of an ordering operator (a btree "<" or ">" operator),
+ * determine its opfamily, its declared input datatype, and its
+ * strategy number (BTLessStrategyNumber or BTGreaterStrategyNumber).
+ *
+ * Returns TRUE if successful, FALSE if no matching pg_amop entry exists.
+ * (This indicates that the operator is not a valid ordering operator.)
*
- * 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.
+ * Note: the operator could be registered in multiple families, for example
+ * if someone were to build a "reverse sort" opfamily. This would result in
+ * uncertainty as to whether "ORDER BY USING op" would default to NULLS FIRST
+ * or NULLS LAST, as well as inefficient planning due to failure to match up
+ * pathkeys that should be the same. So we want a determinate result here.
+ * 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. Since there is no longer any particularly good reason
+ * to build reverse-sort opfamilies, it doesn't seem worth expending any
+ * additional effort on ensuring consistency.
*/
-#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)
+get_ordering_op_properties(Oid opno,
+ Oid *opfamily, Oid *opcintype, int16 *strategy)
{
bool result = false;
- Oid lefttype;
- Oid righttype;
CatCList *catlist;
int i;
- /* Make sure output args are initialized even on failure */
- *right_sortop = InvalidOid;
+ /* ensure outputs are initialized on failure */
*opfamily = InvalidOid;
- *opstrategy = 0;
-
- /* Need the righthand input datatype */
- op_input_types(eq_op, &lefttype, &righttype);
+ *opcintype = InvalidOid;
+ *strategy = 0;
/*
- * Search through all the pg_amop entries containing the equality operator
+ * Search pg_amop to see if the target operator is registered as the "<"
+ * or ">" operator of any btree opfamily.
*/
- catlist = SearchSysCacheList(AMOPOPID, 1,
- ObjectIdGetDatum(eq_op),
- 0, 0, 0);
+ catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
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;
+ HeapTuple tuple = &catlist->members[i]->tuple;
+ Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
/* must be btree */
- if (op_form->amopmethod != BTREE_AM_OID)
- continue;
- /* must use the operator as equality */
- if (op_form->amopstrategy != BTEqualStrategyNumber)
+ if (aform->amopmethod != BTREE_AM_OID)
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)
+ if (aform->amopstrategy == BTLessStrategyNumber ||
+ aform->amopstrategy == BTGreaterStrategyNumber)
{
- /* Yes, so find the corresponding righthand sortop */
- *right_sortop = get_opfamily_member(opfamily_id,
- righttype,
- righttype,
- op_strategy);
- if (OidIsValid(*right_sortop))
+ /* Found it ... should have consistent input types */
+ if (aform->amoplefttype == aform->amoprighttype)
{
- /* Found a workable mergejoin semantics */
- *opfamily = opfamily_id;
- *opstrategy = op_strategy;
+ /* Found a suitable opfamily, return info */
+ *opfamily = aform->amopfamily;
+ *opcintype = aform->amoplefttype;
+ *strategy = aform->amopstrategy;
result = true;
break;
}
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
+ * get_sort_function_for_ordering_op
+ * Get the OID of the datatype-specific btree sort support function,
+ * or if there is none, the btree comparison function,
* associated with an ordering operator (a "<" or ">" operator).
*
- * *cmpfunc receives the comparison function OID.
+ * *sortfunc receives the support or comparison function OID.
+ * *issupport is set TRUE if it's a support func, FALSE if a comparison func.
* *reverse is set FALSE if the operator is "<", TRUE if it's ">"
- * (indicating the comparison result must be negated before use).
+ * (indicating that comparison results 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)
+get_sort_function_for_ordering_op(Oid opno, Oid *sortfunc,
+ bool *issupport, 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);
+ Oid opfamily;
+ Oid opcintype;
+ int16 strategy;
- for (i = 0; i < catlist->n_members; i++)
+ /* Find the operator in pg_amop */
+ if (get_ordering_op_properties(opno,
+ &opfamily, &opcintype, &strategy))
{
- 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 */
+ *sortfunc = get_opfamily_proc(opfamily,
+ opcintype,
+ opcintype,
+ BTSORTSUPPORT_PROC);
+ if (OidIsValid(*sortfunc))
+ *issupport = true;
+ else
{
- /* 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 */
+ /* opfamily doesn't provide sort support, get comparison func */
+ *sortfunc = get_opfamily_proc(opfamily,
+ opcintype,
+ opcintype,
+ BTORDER_PROC);
+ if (!OidIsValid(*sortfunc)) /* 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;
+ BTORDER_PROC, opcintype, opcintype, opfamily);
+ *issupport = false;
}
+ *reverse = (strategy == BTGreaterStrategyNumber);
+ return true;
}
- ReleaseSysCacheList(catlist);
-
- return result;
+ /* ensure outputs are set on failure */
+ *sortfunc = InvalidOid;
+ *issupport = false;
+ *reverse = false;
+ return false;
}
/*
* Get the OID of the datatype-specific btree equality operator
* associated with an ordering operator (a "<" or ">" operator).
*
+ * If "reverse" isn't NULL, also set *reverse to FALSE if the operator is "<",
+ * TRUE if it's ">"
+ *
* 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)
+get_equality_op_for_ordering_op(Oid opno, bool *reverse)
{
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);
+ Oid opfamily;
+ Oid opcintype;
+ int16 strategy;
- for (i = 0; i < catlist->n_members; i++)
+ /* Find the operator in pg_amop */
+ if (get_ordering_op_properties(opno,
+ &opfamily, &opcintype, &strategy))
{
- 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 */
- }
+ /* Found a suitable opfamily, get matching equality operator */
+ result = get_opfamily_member(opfamily,
+ opcintype,
+ opcintype,
+ BTEqualStrategyNumber);
+ if (reverse)
+ *reverse = (strategy == BTGreaterStrategyNumber);
}
- ReleaseSysCacheList(catlist);
-
return result;
}
* 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);
+ catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
for (i = 0; i < catlist->n_members; i++)
{
if (aform->amopstrategy == BTEqualStrategyNumber)
{
/* Found a suitable opfamily, get matching ordering operator */
- Oid typid;
+ Oid typid;
typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
result = get_opfamily_member(aform->amopfamily,
}
/*
- * 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.
+ * get_mergejoin_opfamilies
+ * Given a putatively mergejoinable operator, return a list of the OIDs
+ * of the btree opfamilies in which it represents equality.
*
- * If the given operator is not cross-type, the result should be the same
- * operator, but in cross-type situations it is different.
+ * It is possible (though at present unusual) for an operator to be equality
+ * in more than one opfamily, hence the result is a list. This also lets us
+ * return NIL if the operator is not found in any opfamilies.
*
- * Returns InvalidOid if no compatible operator can be found. (This indicates
- * that the operator should not have been marked oprcanhash.)
+ * The planner currently uses simple equal() tests to compare the lists
+ * returned by this function, which makes the list order relevant, though
+ * strictly speaking it should not be. Because of the way syscache list
+ * searches are handled, in normal operation the result will be sorted by OID
+ * so everything works fine. If running with system index usage disabled,
+ * the result ordering is unspecified and hence the planner might fail to
+ * recognize optimization opportunities ... but that's hardly a scenario in
+ * which performance is good anyway, so there's no point in expending code
+ * or cycles here to guarantee the ordering in that case.
*/
-Oid
-get_compatible_hash_operator(Oid opno, bool use_lhs_type)
+List *
+get_mergejoin_opfamilies(Oid opno)
{
- Oid result = InvalidOid;
+ List *result = NIL;
+ CatCList *catlist;
+ int i;
+
+ /*
+ * Search pg_amop to see if the target operator is registered as the "="
+ * operator of any btree opfamily.
+ */
+ catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
+
+ 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 equality */
+ if (aform->amopmethod == BTREE_AM_OID &&
+ aform->amopstrategy == BTEqualStrategyNumber)
+ result = lappend_oid(result, aform->amopfamily);
+ }
+
+ ReleaseSysCacheList(catlist);
+
+ return result;
+}
+
+/*
+ * get_compatible_hash_operators
+ * Get the OID(s) of hash equality operator(s) compatible with the given
+ * operator, but operating on its LHS and/or RHS datatype.
+ *
+ * An operator for the LHS type is sought and returned into *lhs_opno if
+ * lhs_opno isn't NULL. Similarly, an operator for the RHS type is sought
+ * and returned into *rhs_opno if rhs_opno isn't NULL.
+ *
+ * If the given operator is not cross-type, the results should be the same
+ * operator, but in cross-type situations they will be different.
+ *
+ * Returns true if able to find the requested operator(s), false if not.
+ * (This indicates that the operator should not have been marked oprcanhash.)
+ */
+bool
+get_compatible_hash_operators(Oid opno,
+ Oid *lhs_opno, Oid *rhs_opno)
+{
+ bool result = false;
CatCList *catlist;
int i;
+ /* Ensure output args are initialized on failure */
+ if (lhs_opno)
+ *lhs_opno = InvalidOid;
+ if (rhs_opno)
+ *rhs_opno = InvalidOid;
+
/*
* 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);
+ catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
for (i = 0; i < catlist->n_members; i++)
{
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;
+ if (lhs_opno)
+ *lhs_opno = opno;
+ if (rhs_opno)
+ *rhs_opno = opno;
+ result = true;
break;
}
- typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
- result = get_opfamily_member(aform->amopfamily,
- typid, typid,
- HTEqualStrategyNumber);
- if (OidIsValid(result))
+
+ /*
+ * Get the matching single-type operator(s). Failure probably
+ * shouldn't happen --- it implies a bogus opfamily --- but
+ * continue looking if so.
+ */
+ if (lhs_opno)
+ {
+ *lhs_opno = get_opfamily_member(aform->amopfamily,
+ aform->amoplefttype,
+ aform->amoplefttype,
+ HTEqualStrategyNumber);
+ if (!OidIsValid(*lhs_opno))
+ continue;
+ /* Matching LHS found, done if caller doesn't want RHS */
+ if (!rhs_opno)
+ {
+ result = true;
+ break;
+ }
+ }
+ if (rhs_opno)
+ {
+ *rhs_opno = get_opfamily_member(aform->amopfamily,
+ aform->amoprighttype,
+ aform->amoprighttype,
+ HTEqualStrategyNumber);
+ if (!OidIsValid(*rhs_opno))
+ {
+ /* Forget any LHS operator from this opfamily */
+ if (lhs_opno)
+ *lhs_opno = InvalidOid;
+ continue;
+ }
+ /* Matching RHS found, so done */
+ result = true;
break;
- /* failure probably shouldn't happen, but keep looking if so */
+ }
}
}
}
/*
- * get_op_hash_function
- * Get the OID of the datatype-specific hash function associated with
- * a hashable equality operator.
+ * get_op_hash_functions
+ * Get the OID(s) of hash support function(s) compatible with the given
+ * operator, operating on its LHS and/or RHS datatype as required.
+ *
+ * A function for the LHS type is sought and returned into *lhs_procno if
+ * lhs_procno isn't NULL. Similarly, a function for the RHS type is sought
+ * and returned into *rhs_procno if rhs_procno isn't NULL.
*
- * XXX API needs to be generalized for the case of different left and right
- * datatypes.
+ * If the given operator is not cross-type, the results should be the same
+ * function, but in cross-type situations they will be different.
*
- * Returns InvalidOid if no hash function can be found. (This indicates
- * that the operator should not have been marked oprcanhash.)
+ * Returns true if able to find the requested function(s), false if not.
+ * (This indicates that the operator should not have been marked oprcanhash.)
*/
-Oid
-get_op_hash_function(Oid opno)
+bool
+get_op_hash_functions(Oid opno,
+ RegProcedure *lhs_procno, RegProcedure *rhs_procno)
{
- Oid result = InvalidOid;
+ bool result = false;
CatCList *catlist;
int i;
+ /* Ensure output args are initialized on failure */
+ if (lhs_procno)
+ *lhs_procno = InvalidOid;
+ if (rhs_procno)
+ *rhs_procno = InvalidOid;
+
/*
* 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.
+ * multiple opfamilies, assume we can use any one.
*/
- catlist = SearchSysCacheList(AMOPOPID, 1,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
for (i = 0; i < catlist->n_members; i++)
{
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);
- break;
+ /*
+ * Get the matching support function(s). Failure probably
+ * shouldn't happen --- it implies a bogus opfamily --- but
+ * continue looking if so.
+ */
+ if (lhs_procno)
+ {
+ *lhs_procno = get_opfamily_proc(aform->amopfamily,
+ aform->amoplefttype,
+ aform->amoplefttype,
+ HASHPROC);
+ if (!OidIsValid(*lhs_procno))
+ continue;
+ /* Matching LHS found, done if caller doesn't want RHS */
+ if (!rhs_procno)
+ {
+ result = true;
+ break;
+ }
+ /* Only one lookup needed if given operator is single-type */
+ if (aform->amoplefttype == aform->amoprighttype)
+ {
+ *rhs_procno = *lhs_procno;
+ result = true;
+ break;
+ }
+ }
+ if (rhs_procno)
+ {
+ *rhs_procno = get_opfamily_proc(aform->amopfamily,
+ aform->amoprighttype,
+ aform->amoprighttype,
+ HASHPROC);
+ if (!OidIsValid(*rhs_procno))
+ {
+ /* Forget any LHS function from this opfamily */
+ if (lhs_procno)
+ *lhs_procno = InvalidOid;
+ continue;
+ }
+ /* Matching RHS found, so done */
+ result = true;
+ break;
+ }
}
}
/*
* get_op_btree_interpretation
* 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.
+ * and what properties it has within each one. The results are returned
+ * as a palloc'd list of OpBtreeInterpretation structs.
*
* 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.
*/
-void
-get_op_btree_interpretation(Oid opno, List **opfamilies, List **opstrats)
+List *
+get_op_btree_interpretation(Oid opno)
{
+ List *result = NIL;
+ OpBtreeInterpretation *thisresult;
CatCList *catlist;
- bool op_negated;
int i;
- *opfamilies = NIL;
- *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)
- {
- 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);
- }
- }
+ catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
- /* Now search the opfamilies */
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 */
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)
+ thisresult = (OpBtreeInterpretation *)
+ palloc(sizeof(OpBtreeInterpretation));
+ thisresult->opfamily_id = op_form->amopfamily;
+ thisresult->strategy = op_strategy;
+ thisresult->oplefttype = op_form->amoplefttype;
+ thisresult->oprighttype = op_form->amoprighttype;
+ result = lappend(result, thisresult);
+ }
+
+ ReleaseSysCacheList(catlist);
+
+ /*
+ * If we didn't find any btree opfamily containing the operator, perhaps
+ * it is a <> operator. See if it has a negator that is in an opfamily.
+ */
+ if (result == NIL)
+ {
+ Oid op_negator = get_negator(opno);
+
+ if (OidIsValid(op_negator))
{
- /* Only consider negators that are = */
- if (op_strategy != BTEqualStrategyNumber)
- continue;
- op_strategy = ROWCOMPARE_NE;
- }
+ catlist = SearchSysCacheList1(AMOPOPID,
+ ObjectIdGetDatum(op_negator));
- *opfamilies = lappend_oid(*opfamilies, opfamily_id);
- *opstrats = lappend_int(*opstrats, op_strategy);
+ 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 */
+ op_strategy = (StrategyNumber) op_form->amopstrategy;
+ Assert(op_strategy >= 1 && op_strategy <= 5);
+
+ /* Only consider negators that are = */
+ if (op_strategy != BTEqualStrategyNumber)
+ continue;
+
+ /* OK, report it with "strategy" ROWCOMPARE_NE */
+ thisresult = (OpBtreeInterpretation *)
+ palloc(sizeof(OpBtreeInterpretation));
+ thisresult->opfamily_id = op_form->amopfamily;
+ thisresult->strategy = ROWCOMPARE_NE;
+ thisresult->oplefttype = op_form->amoplefttype;
+ thisresult->oprighttype = op_form->amoprighttype;
+ result = lappend(result, thisresult);
+ }
+
+ ReleaseSysCacheList(catlist);
+ }
}
- ReleaseSysCacheList(catlist);
+ return result;
}
/*
- * 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.)
+ * equality_ops_are_compatible
+ * Return TRUE if the two given equality operators have compatible
+ * semantics.
+ *
+ * This is trivially true if they are the same operator. Otherwise,
+ * we look to see if they can be found in the same btree or hash opfamily.
+ * Either finding allows us to assume that they have compatible notions
+ * of equality. (The reason we need to do these pushups is that one might
+ * be a cross-type operator; for instance int24eq vs int4eq.)
*/
bool
-ops_in_same_btree_opfamily(Oid opno1, Oid opno2)
+equality_ops_are_compatible(Oid opno1, Oid opno2)
{
- bool result = false;
+ bool result;
CatCList *catlist;
int i;
+ /* Easy if they're the same operator */
+ if (opno1 == opno2)
+ return true;
+
/*
* We search through all the pg_amop entries for opno1.
*/
- catlist = SearchSysCacheList(AMOPOPID, 1,
- ObjectIdGetDatum(opno1),
- 0, 0, 0);
+ catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno1));
+
+ result = false;
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))
+ /* must be btree or hash */
+ if (op_form->amopmethod == BTREE_AM_OID ||
+ op_form->amopmethod == HASH_AM_OID)
{
- result = true;
- break;
+ if (op_in_opfamily(opno2, op_form->amopfamily))
+ {
+ result = true;
+ break;
+ }
}
}
Form_pg_amproc amproc_tup;
RegProcedure result;
- tp = SearchSysCache(AMPROCNUM,
- ObjectIdGetDatum(opfamily),
- ObjectIdGetDatum(lefttype),
- ObjectIdGetDatum(righttype),
- Int16GetDatum(procnum));
+ tp = SearchSysCache4(AMPROCNUM,
+ ObjectIdGetDatum(opfamily),
+ ObjectIdGetDatum(lefttype),
+ ObjectIdGetDatum(righttype),
+ Int16GetDatum(procnum));
if (!HeapTupleIsValid(tp))
return InvalidOid;
amproc_tup = (Form_pg_amproc) GETSTRUCT(tp);
{
HeapTuple tp;
- tp = SearchSysCache(ATTNUM,
- ObjectIdGetDatum(relid),
- Int16GetDatum(attnum),
- 0, 0);
+ tp = SearchSysCache2(ATTNUM,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum));
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
{
HeapTuple tp;
- tp = SearchSysCache(ATTNUM,
- ObjectIdGetDatum(relid),
- Int16GetDatum(attnum),
- 0, 0);
+ tp = SearchSysCache2(ATTNUM,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum));
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
{
HeapTuple tp;
- tp = SearchSysCache(ATTNUM,
- ObjectIdGetDatum(relid),
- Int16GetDatum(attnum),
- 0, 0);
+ tp = SearchSysCache2(ATTNUM,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum));
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
}
/*
- * get_atttypetypmod
+ * get_atttypetypmodcoll
*
- * A two-fer: given the relation id and the attribute number,
- * fetch both type OID and atttypmod in a single cache lookup.
+ * A three-fer: given the relation id and the attribute number,
+ * fetch atttypid, atttypmod, and attcollation 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)
+get_atttypetypmodcoll(Oid relid, AttrNumber attnum,
+ Oid *typid, int32 *typmod, Oid *collid)
{
HeapTuple tp;
Form_pg_attribute att_tup;
- tp = SearchSysCache(ATTNUM,
- ObjectIdGetDatum(relid),
- Int16GetDatum(attnum),
- 0, 0);
+ tp = SearchSysCache2(ATTNUM,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
attnum, relid);
*typid = att_tup->atttypid;
*typmod = att_tup->atttypmod;
+ *collid = att_tup->attcollation;
ReleaseSysCache(tp);
}
-/* ---------- INDEX CACHE ---------- */
+/* ---------- COLLATION CACHE ---------- */
+
+/*
+ * get_collation_name
+ * Returns the name of a given pg_collation entry.
+ *
+ * Returns a palloc'd copy of the string, or NULL if no such constraint.
+ *
+ * NOTE: since collation name is not unique, be wary of code that uses this
+ * for anything except preparing error messages.
+ */
+char *
+get_collation_name(Oid colloid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(colloid));
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_collation colltup = (Form_pg_collation) GETSTRUCT(tp);
+ char *result;
+
+ result = pstrdup(NameStr(colltup->collname));
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return NULL;
+}
+
+/* ---------- CONSTRAINT CACHE ---------- */
-/* watch this space...
+/*
+ * get_constraint_name
+ * Returns the name of a given pg_constraint entry.
+ *
+ * Returns a palloc'd copy of the string, or NULL if no such constraint.
+ *
+ * NOTE: since constraint name is not unique, be wary of code that uses this
+ * for anything except preparing error messages.
*/
+char *
+get_constraint_name(Oid conoid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conoid));
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_constraint contup = (Form_pg_constraint) GETSTRUCT(tp);
+ char *result;
+
+ result = pstrdup(NameStr(contup->conname));
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return NULL;
+}
/* ---------- OPCLASS CACHE ---------- */
Form_pg_opclass cla_tup;
Oid result;
- tp = SearchSysCache(CLAOID,
- ObjectIdGetDatum(opclass),
- 0, 0, 0);
+ tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for opclass %u", opclass);
cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
Form_pg_opclass cla_tup;
Oid result;
- tp = SearchSysCache(CLAOID,
- ObjectIdGetDatum(opclass),
- 0, 0, 0);
+ tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for opclass %u", opclass);
cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
{
HeapTuple tp;
- tp = SearchSysCache(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
{
HeapTuple tp;
- tp = SearchSysCache(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
HeapTuple tp;
Form_pg_operator optup;
- tp = SearchSysCache(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
if (!HeapTupleIsValid(tp)) /* shouldn't happen */
elog(ERROR, "cache lookup failed for operator %u", opno);
optup = (Form_pg_operator) GETSTRUCT(tp);
* will fail to find any mergejoin plans unless there are suitable btree
* opfamily entries for this operator and associated sortops. The pg_operator
* flag is just a hint to tell the planner whether to bother looking.)
+ *
+ * In some cases (currently only array_eq and record_eq), mergejoinability
+ * depends on the specific input data type the operator is invoked for, so
+ * that must be passed as well. We currently assume that only one input's type
+ * is needed to check this --- by convention, pass the left input's data type.
*/
bool
-op_mergejoinable(Oid opno)
+op_mergejoinable(Oid opno, Oid inputtype)
{
- HeapTuple tp;
bool result = false;
+ HeapTuple tp;
+ TypeCacheEntry *typentry;
- tp = SearchSysCache(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
- if (HeapTupleIsValid(tp))
+ /*
+ * For array_eq or record_eq, we can sort if the element or field types
+ * are all sortable. We could implement all the checks for that here, but
+ * the typcache already does that and caches the results too, so let's
+ * rely on the typcache.
+ */
+ if (opno == ARRAY_EQ_OP)
{
- Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
+ typentry = lookup_type_cache(inputtype, TYPECACHE_CMP_PROC);
+ if (typentry->cmp_proc == F_BTARRAYCMP)
+ result = true;
+ }
+ else if (opno == RECORD_EQ_OP)
+ {
+ typentry = lookup_type_cache(inputtype, TYPECACHE_CMP_PROC);
+ if (typentry->cmp_proc == F_BTRECORDCMP)
+ result = true;
+ }
+ else
+ {
+ /* For all other operators, rely on pg_operator.oprcanmerge */
+ tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
- result = optup->oprcanmerge;
- ReleaseSysCache(tp);
+ result = optup->oprcanmerge;
+ ReleaseSysCache(tp);
+ }
}
return result;
}
*
* Returns true if the operator is hashjoinable. (There must be a suitable
* hash opfamily entry for this operator if it is so marked.)
+ *
+ * In some cases (currently only array_eq), hashjoinability depends on the
+ * specific input data type the operator is invoked for, so that must be
+ * passed as well. We currently assume that only one input's type is needed
+ * to check this --- by convention, pass the left input's data type.
*/
bool
-op_hashjoinable(Oid opno)
+op_hashjoinable(Oid opno, Oid inputtype)
{
- HeapTuple tp;
bool result = false;
+ HeapTuple tp;
+ TypeCacheEntry *typentry;
- tp = SearchSysCache(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
- if (HeapTupleIsValid(tp))
+ /* As in op_mergejoinable, let the typcache handle the hard cases */
+ /* Eventually we'll need a similar case for record_eq ... */
+ if (opno == ARRAY_EQ_OP)
{
- Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
+ typentry = lookup_type_cache(inputtype, TYPECACHE_HASH_PROC);
+ if (typentry->hash_proc == F_HASH_ARRAY)
+ result = true;
+ }
+ else
+ {
+ /* For all other operators, rely on pg_operator.oprcanhash */
+ tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
- result = optup->oprcanhash;
- ReleaseSysCache(tp);
+ result = optup->oprcanhash;
+ ReleaseSysCache(tp);
+ }
}
return result;
}
{
HeapTuple tp;
- tp = SearchSysCache(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
{
HeapTuple tp;
- tp = SearchSysCache(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
{
HeapTuple tp;
- tp = SearchSysCache(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
{
HeapTuple tp;
- tp = SearchSysCache(OPEROID,
- ObjectIdGetDatum(opno),
- 0, 0, 0);
+ tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
{
HeapTuple tp;
- tp = SearchSysCache(PROCOID,
- ObjectIdGetDatum(funcid),
- 0, 0, 0);
+ tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (HeapTupleIsValid(tp))
{
Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
return NULL;
}
+/*
+ * get_func_namespace
+ *
+ * Returns the pg_namespace OID associated with a given function.
+ */
+Oid
+get_func_namespace(Oid funcid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
+ Oid result;
+
+ result = functup->pronamespace;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return InvalidOid;
+}
+
/*
* get_func_rettype
* Given procedure id, return the function's result type.
HeapTuple tp;
Oid result;
- tp = SearchSysCache(PROCOID,
- ObjectIdGetDatum(funcid),
- 0, 0, 0);
+ tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u", funcid);
HeapTuple tp;
int result;
- tp = SearchSysCache(PROCOID,
- ObjectIdGetDatum(funcid),
- 0, 0, 0);
+ tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u", funcid);
Form_pg_proc procstruct;
Oid result;
- tp = SearchSysCache(PROCOID,
- ObjectIdGetDatum(funcid),
- 0, 0, 0);
+ tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u", funcid);
HeapTuple tp;
bool result;
- tp = SearchSysCache(PROCOID,
- ObjectIdGetDatum(funcid),
- 0, 0, 0);
+ tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u", funcid);
HeapTuple tp;
bool result;
- tp = SearchSysCache(PROCOID,
- ObjectIdGetDatum(funcid),
- 0, 0, 0);
+ tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u", funcid);
HeapTuple tp;
char result;
- tp = SearchSysCache(PROCOID,
- ObjectIdGetDatum(funcid),
- 0, 0, 0);
+ tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u", funcid);
return result;
}
+/*
+ * get_func_cost
+ * Given procedure id, return the function's procost field.
+ */
+float4
+get_func_cost(Oid funcid)
+{
+ HeapTuple tp;
+ float4 result;
+
+ tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for function %u", funcid);
+
+ result = ((Form_pg_proc) GETSTRUCT(tp))->procost;
+ ReleaseSysCache(tp);
+ return result;
+}
+
+/*
+ * get_func_rows
+ * Given procedure id, return the function's prorows field.
+ */
+float4
+get_func_rows(Oid funcid)
+{
+ HeapTuple tp;
+ float4 result;
+
+ tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for function %u", funcid);
+
+ result = ((Form_pg_proc) GETSTRUCT(tp))->prorows;
+ ReleaseSysCache(tp);
+ return result;
+}
+
/* ---------- RELATION CACHE ---------- */
/*
Oid
get_relname_relid(const char *relname, Oid relnamespace)
{
- return GetSysCacheOid(RELNAMENSP,
- PointerGetDatum(relname),
- ObjectIdGetDatum(relnamespace),
- 0, 0);
+ return GetSysCacheOid2(RELNAMENSP,
+ PointerGetDatum(relname),
+ ObjectIdGetDatum(relnamespace));
}
#ifdef NOT_USED
{
HeapTuple tp;
- tp = SearchSysCache(RELOID,
- ObjectIdGetDatum(relid),
- 0, 0, 0);
+ tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
{
HeapTuple tp;
- tp = SearchSysCache(RELOID,
- ObjectIdGetDatum(relid),
- 0, 0, 0);
+ tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
{
HeapTuple tp;
- tp = SearchSysCache(RELOID,
- ObjectIdGetDatum(relid),
- 0, 0, 0);
+ tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
{
HeapTuple tp;
- tp = SearchSysCache(RELOID,
- ObjectIdGetDatum(relid),
- 0, 0, 0);
+ tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
{
HeapTuple tp;
- tp = SearchSysCache(RELOID,
- ObjectIdGetDatum(relid),
- 0, 0, 0);
+ tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
return '\0';
}
+/*
+ * get_rel_tablespace
+ *
+ * Returns the pg_tablespace OID associated with a given relation.
+ *
+ * Note: InvalidOid might mean either that we couldn't find the relation,
+ * or that it is in the database's default tablespace.
+ */
+Oid
+get_rel_tablespace(Oid relid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
+ Oid result;
+
+ result = reltup->reltablespace;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return InvalidOid;
+}
+
/* ---------- TYPE CACHE ---------- */
{
HeapTuple tp;
- tp = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
{
HeapTuple tp;
- tp = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
{
HeapTuple tp;
- tp = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
HeapTuple tp;
Form_pg_type typtup;
- tp = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for type %u", typid);
typtup = (Form_pg_type) GETSTRUCT(tp);
HeapTuple tp;
Form_pg_type typtup;
- tp = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for type %u", typid);
typtup = (Form_pg_type) GETSTRUCT(tp);
/*
* Array types get their typelem as parameter; everybody else gets their
- * own type OID as parameter. (This is a change from 8.0, in which only
- * composite types got their own OID as parameter.)
+ * own type OID as parameter.
*/
if (OidIsValid(typeStruct->typelem))
return typeStruct->typelem;
return;
}
- typeTuple = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (!HeapTupleIsValid(typeTuple))
elog(ERROR, "cache lookup failed for type %u", typid);
typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
{
HeapTuple tp;
- tp = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
{
HeapTuple tp;
- tp = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
bool isNull;
Node *expr;
- typeTuple = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (!HeapTupleIsValid(typeTuple))
elog(ERROR, "cache lookup failed for type %u", typid);
type = (Form_pg_type) GETSTRUCT(typeTuple);
if (!isNull)
{
/* We have an expression default */
- expr = stringToNode(DatumGetCString(DirectFunctionCall1(textout,
- datum)));
+ expr = stringToNode(TextDatumGetCString(datum));
}
else
{
char *strDefaultVal;
/* Convert text datum to C string */
- strDefaultVal = DatumGetCString(DirectFunctionCall1(textout,
- datum));
+ strDefaultVal = TextDatumGetCString(datum);
/* Convert C string to a value of the given type */
datum = OidInputFunctionCall(type->typinput, strDefaultVal,
getTypeIOParam(typeTuple), -1);
/* Build a Const node containing the value */
expr = (Node *) makeConst(typid,
+ -1,
+ type->typcollation,
type->typlen,
datum,
false,
HeapTuple tup;
Form_pg_type typTup;
- tup = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for type %u", typid);
typTup = (Form_pg_type) GETSTRUCT(tup);
- if (typTup->typtype != 'd')
+ if (typTup->typtype != TYPTYPE_DOMAIN)
{
/* Not a domain, so done */
ReleaseSysCache(tup);
{
HeapTuple tp;
- tp = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
bool
type_is_rowtype(Oid typid)
{
- return (typid == RECORDOID || get_typtype(typid) == 'c');
+ return (typid == RECORDOID || get_typtype(typid) == TYPTYPE_COMPOSITE);
+}
+
+/*
+ * type_is_enum
+ * Returns true if the given type is an enum type.
+ */
+bool
+type_is_enum(Oid typid)
+{
+ return (get_typtype(typid) == TYPTYPE_ENUM);
+}
+
+/*
+ * type_is_range
+ * Returns true if the given type is a range type.
+ */
+bool
+type_is_range(Oid typid)
+{
+ return (get_typtype(typid) == TYPTYPE_RANGE);
+}
+
+/*
+ * get_type_category_preferred
+ *
+ * Given the type OID, fetch its category and preferred-type status.
+ * Throws error on failure.
+ */
+void
+get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred)
+{
+ HeapTuple tp;
+ Form_pg_type typtup;
+
+ tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for type %u", typid);
+ typtup = (Form_pg_type) GETSTRUCT(tp);
+ *typcategory = typtup->typcategory;
+ *typispreferred = typtup->typispreferred;
+ ReleaseSysCache(tp);
}
/*
{
HeapTuple tp;
- tp = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
{
HeapTuple tp;
- tp = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
/*
* get_array_type
*
- * Given the type OID, get the corresponding array type.
+ * Given the type OID, get the corresponding "true" 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;
+ Oid result = InvalidOid;
- tp = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
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;
+ result = ((Form_pg_type) GETSTRUCT(tp))->typarray;
ReleaseSysCache(tp);
+ }
+ return result;
+}
- tp = SearchSysCache(TYPENAMENSP,
- PointerGetDatum(array_typename),
- ObjectIdGetDatum(namespaceId),
- 0, 0);
-
- pfree(array_typename);
+/*
+ * get_base_element_type
+ * Given the type OID, get the typelem, looking "through" any domain
+ * to its underlying array type.
+ *
+ * This is equivalent to get_element_type(getBaseType(typid)), but avoids
+ * an extra cache lookup. Note that it fails to provide any information
+ * about the typmod of the array.
+ */
+Oid
+get_base_element_type(Oid typid)
+{
+ /*
+ * We loop to find the bottom base type in a stack of domains.
+ */
+ for (;;)
+ {
+ HeapTuple tup;
+ Form_pg_type typTup;
- if (HeapTupleIsValid(tp))
+ tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
+ if (!HeapTupleIsValid(tup))
+ break;
+ typTup = (Form_pg_type) GETSTRUCT(tup);
+ if (typTup->typtype != TYPTYPE_DOMAIN)
{
+ /* Not a domain, so stop descending */
Oid result;
- typtup = (Form_pg_type) GETSTRUCT(tp);
- if (typtup->typlen == -1 && typtup->typelem == typid)
- result = HeapTupleGetOid(tp);
+ /* This test must match get_element_type */
+ if (typTup->typlen == -1)
+ result = typTup->typelem;
else
result = InvalidOid;
- ReleaseSysCache(tp);
+ ReleaseSysCache(tup);
return result;
}
+
+ typid = typTup->typbasetype;
+ ReleaseSysCache(tup);
}
+
+ /* Like get_element_type, silently return InvalidOid for bogus input */
return InvalidOid;
}
HeapTuple typeTuple;
Form_pg_type pt;
- typeTuple = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(type),
- 0, 0, 0);
+ typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
if (!HeapTupleIsValid(typeTuple))
elog(ERROR, "cache lookup failed for type %u", type);
pt = (Form_pg_type) GETSTRUCT(typeTuple);
HeapTuple typeTuple;
Form_pg_type pt;
- typeTuple = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(type),
- 0, 0, 0);
+ typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
if (!HeapTupleIsValid(typeTuple))
elog(ERROR, "cache lookup failed for type %u", type);
pt = (Form_pg_type) GETSTRUCT(typeTuple);
HeapTuple typeTuple;
Form_pg_type pt;
- typeTuple = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(type),
- 0, 0, 0);
+ typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
if (!HeapTupleIsValid(typeTuple))
elog(ERROR, "cache lookup failed for type %u", type);
pt = (Form_pg_type) GETSTRUCT(typeTuple);
HeapTuple typeTuple;
Form_pg_type pt;
- typeTuple = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(type),
- 0, 0, 0);
+ typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
if (!HeapTupleIsValid(typeTuple))
elog(ERROR, "cache lookup failed for type %u", type);
pt = (Form_pg_type) GETSTRUCT(typeTuple);
{
HeapTuple tp;
- tp = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
{
HeapTuple tp;
- tp = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
+ tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
else
return InvalidOid;
}
-#endif /* NOT_USED */
+#endif /* NOT_USED */
+
+/*
+ * get_typcollation
+ *
+ * Given the type OID, return the type's typcollation attribute.
+ */
+Oid
+get_typcollation(Oid typid)
+{
+ HeapTuple tp;
+
+ tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+ Oid result;
+
+ result = typtup->typcollation;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return InvalidOid;
+}
+
+
+/*
+ * type_is_collatable
+ *
+ * Return whether the type cares about collations
+ */
+bool
+type_is_collatable(Oid typid)
+{
+ return OidIsValid(get_typcollation(typid));
+}
/* ---------- STATISTICS CACHE ---------- */
*
* Given the table and attribute number of a column, get the average
* width of entries in the column. Return zero if no data available.
+ *
+ * Currently this is only consulted for individual tables, not for inheritance
+ * trees, so we don't need an "inh" parameter.
+ *
+ * Calling a hook at this point looks somewhat strange, but is required
+ * because the optimizer calls this function without any other way for
+ * plug-ins to control the result.
*/
int32
get_attavgwidth(Oid relid, AttrNumber attnum)
{
HeapTuple tp;
+ int32 stawidth;
- tp = SearchSysCache(STATRELATT,
- ObjectIdGetDatum(relid),
- Int16GetDatum(attnum),
- 0, 0);
+ if (get_attavgwidth_hook)
+ {
+ stawidth = (*get_attavgwidth_hook) (relid, attnum);
+ if (stawidth > 0)
+ return stawidth;
+ }
+ tp = SearchSysCache3(STATRELATTINH,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum),
+ BoolGetDatum(false));
if (HeapTupleIsValid(tp))
{
- int32 stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
-
+ stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
ReleaseSysCache(tp);
if (stawidth > 0)
return stawidth;
* 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.
+ * Also, this API allows this routine to be used with statistics tuples
+ * that have been provided by a stats hook and didn't really come from
+ * pg_statistic.
*
* statstuple: pg_statistics tuple to be examined.
* atttype: type OID of attribute (can be InvalidOid if values == NULL).
* atttypmod: typmod of attribute (can be 0 if values == NULL).
* reqkind: STAKIND code for desired statistics slot kind.
* reqop: STAOP value wanted, or InvalidOid if don't care.
+ * actualop: if not NULL, *actualop receives the actual STAOP value.
* values, nvalues: if not NULL, the slot's stavalues are extracted.
* numbers, nnumbers: if not NULL, the slot's stanumbers are extracted.
*
* 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.
+ *
+ * Note: at present, atttype/atttypmod aren't actually used here at all.
+ * But the caller must have the correct (or at least binary-compatible)
+ * type ID to pass to free_attstatsslot later.
*/
bool
get_attstatsslot(HeapTuple statstuple,
Oid atttype, int32 atttypmod,
int reqkind, Oid reqop,
+ Oid *actualop,
Datum **values, int *nvalues,
float4 **numbers, int *nnumbers)
{
Datum val;
bool isnull;
ArrayType *statarray;
+ Oid arrayelemtype;
int narrayelem;
HeapTuple typeTuple;
Form_pg_type typeForm;
if (i >= STATISTIC_NUM_SLOTS)
return false; /* not there */
+ if (actualop)
+ *actualop = (&stats->staop1)[i];
+
if (values)
{
- val = SysCacheGetAttr(STATRELATT, statstuple,
+ val = SysCacheGetAttr(STATRELATTINH, 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);
+ /*
+ * Need to get info about the array element type. We look at the
+ * actual element type embedded in the array, which might be only
+ * binary-compatible with the passed-in atttype. The info we extract
+ * here should be the same either way, but deconstruct_array is picky
+ * about having an exact type OID match.
+ */
+ arrayelemtype = ARR_ELEMTYPE(statarray);
+ typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(arrayelemtype));
if (!HeapTupleIsValid(typeTuple))
- elog(ERROR, "cache lookup failed for type %u", atttype);
+ elog(ERROR, "cache lookup failed for type %u", arrayelemtype);
typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
/* Deconstruct array into Datum elements; NULLs not expected */
deconstruct_array(statarray,
- atttype,
+ arrayelemtype,
typeForm->typlen,
typeForm->typbyval,
typeForm->typalign,
if (numbers)
{
- val = SysCacheGetAttr(STATRELATT, statstuple,
+ val = SysCacheGetAttr(STATRELATTINH, statstuple,
Anum_pg_statistic_stanumbers1 + i,
&isnull);
if (isnull)
{
HeapTuple tp;
- tp = SearchSysCache(NAMESPACEOID,
- ObjectIdGetDatum(nspid),
- 0, 0, 0);
+ tp = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nspid));
if (HeapTupleIsValid(tp))
{
Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp);
return NULL;
}
-/* ---------- PG_AUTHID CACHE ---------- */
+/* ---------- PG_RANGE CACHE ---------- */
/*
- * get_roleid
- * Given a role name, look up the role's OID.
- * Returns InvalidOid if no such role.
+ * get_range_subtype
+ * Returns the subtype of a given range type
+ *
+ * Returns InvalidOid if the type is not a range type.
*/
Oid
-get_roleid(const char *rolname)
+get_range_subtype(Oid rangeOid)
{
- return GetSysCacheOid(AUTHNAME,
- PointerGetDatum(rolname),
- 0, 0, 0);
-}
+ HeapTuple tp;
-/*
- * get_roleid_checked
- * Given a role name, look up the role's OID.
- * ereports if no such role.
- */
-Oid
-get_roleid_checked(const char *rolname)
-{
- Oid roleid;
+ tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
+ if (HeapTupleIsValid(tp))
+ {
+ Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
+ Oid result;
- roleid = get_roleid(rolname);
- if (!OidIsValid(roleid))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", rolname)));
- return roleid;
+ result = rngtup->rngsubtype;
+ ReleaseSysCache(tp);
+ return result;
+ }
+ else
+ return InvalidOid;
}