Impressum lsyscache.c
Interaktion und PortierbarkeitC
/*-------------------------------------------------------------------------
*
* lsyscache . c
* Convenience routines for common queries in the system catalog cache .
*
* Portions Copyright ( c ) 1996 - 2025 , PostgreSQL Global Development Group
* Portions Copyright ( c ) 1994 , Regents of the University of California
*
* IDENTIFICATION
* src / backend / utils / cache / lsyscache . c
*
* NOTES
* Eventually , the index information should go through here , too .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
#include "postgres.h"
#include "access/hash.h"
#include "access/htup_details.h"
#include "bootstrap/bootstrap.h"
#include "catalog/namespace.h"
#include "catalog/pg_am.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_class.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_index.h"
#include "catalog/pg_language.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_publication.h"
#include "catalog/pg_range.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_subscription.h"
#include "catalog/pg_transform.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/catcache.h"
#include "utils/datum.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.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 SearchSysCacheExists3(AMOPOPID,
ObjectIdGetDatum(opno),
CharGetDatum(AMOP_SEARCH),
ObjectIdGetDatum(opfamily));
}
/*
* get_op_opfamily_strategy
*
* 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)
{
HeapTuple tp;
Form_pg_amop amop_tup;
int result;
tp = SearchSysCache3(AMOPOPID,
ObjectIdGetDatum(opno),
CharGetDatum(AMOP_SEARCH),
ObjectIdGetDatum(opfamily));
if (!HeapTupleIsValid(tp))
return 0 ;
amop_tup = (Form_pg_amop) GETSTRUCT(tp);
result = amop_tup->amopstrategy;
ReleaseSysCache(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 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, bool ordering_op,
int *strategy,
Oid *lefttype,
Oid *righttype)
{
HeapTuple tp;
Form_pg_amop amop_tup;
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);
amop_tup = (Form_pg_amop) GETSTRUCT(tp);
*strategy = amop_tup->amopstrategy;
*lefttype = amop_tup->amoplefttype;
*righttype = amop_tup->amoprighttype;
ReleaseSysCache(tp);
}
/*
* get_opfamily_member
* 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 = SearchSysCache4(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_opfamily_member_for_cmptype
* Get the OID of the operator that implements the specified comparison
* type with the specified datatypes for the specified opfamily .
*
* Returns InvalidOid if there is no mapping for the comparison type or no
* pg_amop entry for the given keys .
*/
Oid
get_opfamily_member_for_cmptype(Oid opfamily, Oid lefttype, Oid righttype,
CompareType cmptype)
{
Oid opmethod;
StrategyNumber strategy;
opmethod = get_opfamily_method(opfamily);
strategy = IndexAmTranslateCompareType(cmptype, opmethod, opfamily, true );
if (!strategy)
return InvalidOid;
return get_opfamily_member(opfamily, lefttype, righttype, strategy);
}
/*
* get_opmethod_canorder
* Return amcanorder field for given index AM .
*
* To speed things up in the common cases , we ' re hardcoding the results from
* the built - in index types . Note that we also need to hardcode the negative
* results from the built - in non - btree index types , since you ' ll usually get a
* few hits for those as well . It would be nice to organize and cache this a
* bit differently to avoid the hardcoding .
*/
static bool
get_opmethod_canorder(Oid amoid)
{
switch (amoid)
{
case BTREE_AM_OID:
return true ;
case HASH_AM_OID:
case GIST_AM_OID:
case GIN_AM_OID:
case SPGIST_AM_OID:
case BRIN_AM_OID:
return false ;
default :
{
bool result;
IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(amoid, false );
result = amroutine->amcanorder;
pfree(amroutine);
return result;
}
}
}
/*
* get_ordering_op_properties
* Given the OID of an ordering operator ( a " < " or " > " operator ) ,
* determine its opfamily , its declared input datatype , and its
* comparison type .
*
* Returns true if successful , false if no matching pg_amop entry exists .
* ( This indicates that the operator is not a valid ordering operator . )
*
* 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 .
*/
bool
get_ordering_op_properties(Oid opno,
Oid *opfamily, Oid *opcintype, CompareType *cmptype)
{
bool result = false ;
CatCList *catlist;
int i;
/* ensure outputs are initialized on failure */
*opfamily = InvalidOid;
*opcintype = InvalidOid;
*cmptype = COMPARE_INVALID;
/*
* Search pg_amop to see if the target operator is registered as the " < "
* or " > " 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);
CompareType am_cmptype;
/* must be ordering index */
if (!get_opmethod_canorder(aform->amopmethod))
continue ;
am_cmptype = IndexAmTranslateStrategy(aform->amopstrategy,
aform->amopmethod,
aform->amopfamily,
true );
if (am_cmptype == COMPARE_LT || am_cmptype == COMPARE_GT)
{
/* Found it ... should have consistent input types */
if (aform->amoplefttype == aform->amoprighttype)
{
/* Found a suitable opfamily, return info */
*opfamily = aform->amopfamily;
*opcintype = aform->amoplefttype;
*cmptype = am_cmptype;
result = true ;
break ;
}
}
}
ReleaseSysCacheList(catlist);
return result;
}
/*
* get_equality_op_for_ordering_op
* Get the OID of the datatype - specific 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, bool *reverse)
{
Oid result = InvalidOid;
Oid opfamily;
Oid opcintype;
CompareType cmptype;
/* Find the operator in pg_amop */
if (get_ordering_op_properties(opno,
&opfamily, &opcintype, &cmptype))
{
/* Found a suitable opfamily, get matching equality operator */
result = get_opfamily_member_for_cmptype(opfamily,
opcintype,
opcintype,
COMPARE_EQ);
if (reverse)
*reverse = (cmptype == COMPARE_GT);
}
return result;
}
/*
* get_ordering_op_for_equality_op
* Get the OID of a datatype - specific " less than " 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 = 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);
CompareType cmptype;
/* must be ordering index */
if (!get_opmethod_canorder(aform->amopmethod))
continue ;
cmptype = IndexAmTranslateStrategy(aform->amopstrategy,
aform->amopmethod,
aform->amopfamily,
true );
if (cmptype == COMPARE_EQ)
{
/* Found a suitable opfamily, get matching ordering operator */
Oid typid;
typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
result = get_opfamily_member_for_cmptype(aform->amopfamily,
typid, typid,
COMPARE_LT);
if (OidIsValid(result))
break ;
/* failure probably shouldn't happen, but keep looking if so */
}
}
ReleaseSysCacheList(catlist);
return result;
}
/*
* get_mergejoin_opfamilies
* Given a putatively mergejoinable operator , return a list of the OIDs
* of the amcanorder opfamilies in which it represents equality .
*
* 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 .
*
* 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 .
*/
List *
get_mergejoin_opfamilies(Oid opno)
{
List *result = NIL;
CatCList *catlist;
int i;
/*
* Search pg_amop to see if the target operator is registered as the " = "
* operator of any opfamily of an ordering index type .
*/
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 ordering index equality */
if (get_opmethod_canorder(aform->amopmethod) &&
IndexAmTranslateStrategy(aform->amopstrategy,
aform->amopmethod,
aform->amopfamily,
true ) == COMPARE_EQ)
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 = 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);
if (aform->amopmethod == HASH_AM_OID &&
aform->amopstrategy == HTEqualStrategyNumber)
{
/* No extra lookup needed if given operator is single-type */
if (aform->amoplefttype == aform->amoprighttype)
{
if (lhs_opno)
*lhs_opno = opno;
if (rhs_opno)
*rhs_opno = opno;
result = true ;
break ;
}
/*
* 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 ;
}
}
}
ReleaseSysCacheList(catlist);
return result;
}
/*
* get_op_hash_functions
* Get the OID ( s ) of the standard 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 .
*
* 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 true if able to find the requested function ( s ) , false if not .
* ( This indicates that the operator should not have been marked oprcanhash . )
*/
bool
get_op_hash_functions(Oid opno,
RegProcedure *lhs_procno, RegProcedure *rhs_procno)
{
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 any one .
*/
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);
if (aform->amopmethod == HASH_AM_OID &&
aform->amopstrategy == HTEqualStrategyNumber)
{
/*
* 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,
HASHSTANDARD_PROC);
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,
HASHSTANDARD_PROC);
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 ;
}
}
}
ReleaseSysCacheList(catlist);
return result;
}
/*
* get_op_index_interpretation
* Given an operator ' s OID , find out which amcanorder opfamilies it belongs to ,
* and what properties it has within each one . The results are returned
* as a palloc ' d list of OpIndexInterpretation 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 . COMPARE_NE is returned as the strategy number for this case .
*/
List *
get_op_index_interpretation(Oid opno)
{
List *result = NIL;
OpIndexInterpretation *thisresult;
CatCList *catlist;
int i;
/*
* Find all the pg_amop entries containing the operator .
*/
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);
CompareType cmptype;
/* must be ordering index */
if (!get_opmethod_canorder(op_form->amopmethod))
continue ;
/* Get the operator's comparision type */
cmptype = IndexAmTranslateStrategy(op_form->amopstrategy,
op_form->amopmethod,
op_form->amopfamily,
true );
/* should not happen */
if (cmptype == COMPARE_INVALID)
continue ;
thisresult = (OpIndexInterpretation *)
palloc(sizeof (OpIndexInterpretation));
thisresult->opfamily_id = op_form->amopfamily;
thisresult->cmptype = cmptype;
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))
{
catlist = SearchSysCacheList1(AMOPOPID,
ObjectIdGetDatum(op_negator));
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);
IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(op_form->amopmethod, false );
CompareType cmptype;
/* must be ordering index */
if (!amroutine->amcanorder)
continue ;
/* Get the operator's comparision type */
cmptype = IndexAmTranslateStrategy(op_form->amopstrategy,
op_form->amopmethod,
op_form->amopfamily,
true );
/* Only consider negators that are = */
if (cmptype != COMPARE_EQ)
continue ;
/* OK, report it as COMPARE_NE */
thisresult = (OpIndexInterpretation *)
palloc(sizeof (OpIndexInterpretation));
thisresult->opfamily_id = op_form->amopfamily;
thisresult->cmptype = COMPARE_NE;
thisresult->oplefttype = op_form->amoplefttype;
thisresult->oprighttype = op_form->amoprighttype;
result = lappend(result, thisresult);
}
ReleaseSysCacheList(catlist);
}
}
return result;
}
/*
* 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 ,
* Otherwise , we look to see if they both belong to an opfamily that
* guarantees compatible semantics for equality . 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
equality_ops_are_compatible(Oid opno1, Oid opno2)
{
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 = 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);
/*
* op_in_opfamily ( ) is cheaper than GetIndexAmRoutineByAmId ( ) , so
* check it first
*/
if (op_in_opfamily(opno2, op_form->amopfamily))
{
IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(op_form->amopmethod, false );
if (amroutine->amconsistentequality)
{
result = true ;
break ;
}
}
}
ReleaseSysCacheList(catlist);
return result;
}
/*
* comparison_ops_are_compatible
* Return true if the two given comparison operators have compatible
* semantics .
*
* This is trivially true if they are the same operator . Otherwise , we look
* to see if they both belong to an opfamily that guarantees compatible
* semantics for ordering . ( For example , for btree , ' < ' and ' > = ' ops match if
* they belong to the same family . )
*
* ( This is identical to equality_ops_are_compatible ( ) , except that we check
* amconsistentordering instead of amconsistentequality . )
*/
bool
comparison_ops_are_compatible(Oid opno1, Oid opno2)
{
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 = 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);
/*
* op_in_opfamily ( ) is cheaper than GetIndexAmRoutineByAmId ( ) , so
* check it first
*/
if (op_in_opfamily(opno2, op_form->amopfamily))
{
IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(op_form->amopmethod, false );
if (amroutine->amconsistentordering)
{
result = true ;
break ;
}
}
}
ReleaseSysCacheList(catlist);
return result;
}
/*
* collations_agree_on_equality
* Return true if the two collations have equivalent notions of equality ,
* so that a uniqueness or equality proof established under one side
* carries over to a comparison performed under the other side .
*
* Note : this is equality compatibility only . Do NOT use this to reason
* about ordering .
*
* An InvalidOid on either side denotes the absence of a collation - - that
* side ' s operation is not collation - sensitive ( e . g . a non - collatable column
* type ) . Absence of a collation cannot conflict with the other side ' s
* collation , so we treat such pairs as agreeing on equality . This generalizes
* the asymmetric treatment in IndexCollMatchesExprColl ( ) .
*
* Otherwise the collations have equivalent equality if they match , or if both
* are deterministic : by definition a deterministic collation treats two
* strings as equal iff they are byte - wise equal ( see CREATE COLLATION ) , so any
* two deterministic collations share the same equality relation . A mismatch
* involving a nondeterministic collation , however , may mean the two equality
* relations disagree , and the proof is unsound .
*/
bool
collations_agree_on_equality(Oid coll1, Oid coll2)
{
if (!OidIsValid(coll1) || !OidIsValid(coll2))
return true ;
if (coll1 == coll2)
return true ;
if (!get_collation_isdeterministic(coll1) ||
!get_collation_isdeterministic(coll2))
return false ;
return true ;
}
/* ---------- AMPROC CACHES ---------- */
/*
* get_opfamily_proc
* 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 = SearchSysCache4(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 ---------- */
/*
* get_attname
* Given the relation id and the attribute number , return the " attname "
* field from the attribute relation as a palloc ' ed string .
*
* If no such attribute exists and missing_ok is true , NULL is returned ;
* otherwise a not - intended - for - user - consumption error is thrown .
*/
char *
get_attname(Oid relid, AttrNumber attnum, bool missing_ok)
{
HeapTuple tp;
tp = SearchSysCache2(ATTNUM,
ObjectIdGetDatum(relid), Int16GetDatum(attnum));
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;
}
if (!missing_ok)
elog(ERROR, "cache lookup failed for attribute %d of relation %u" ,
attnum, relid);
return NULL;
}
/*
* get_attnum
*
* Given the relation id and the attribute name ,
* return the " attnum " field from the attribute relation .
*
* Returns InvalidAttrNumber if the attr doesn ' t exist ( or is dropped ) .
*/
AttrNumber
get_attnum(Oid relid, const char *attname)
{
HeapTuple tp;
tp = SearchSysCacheAttName(relid, attname);
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
AttrNumber result;
result = att_tup->attnum;
ReleaseSysCache(tp);
return result;
}
else
return InvalidAttrNumber;
}
/*
* get_attgenerated
*
* Given the relation id and the attribute number ,
* return the " attgenerated " field from the attribute relation .
*
* Errors if not found .
*
* Since not generated is represented by ' \ 0 ' , this can also be used as a
* Boolean test .
*/
char
get_attgenerated(Oid relid, AttrNumber attnum)
{
HeapTuple tp;
Form_pg_attribute att_tup;
char result;
tp = SearchSysCache2(ATTNUM,
ObjectIdGetDatum(relid),
Int16GetDatum(attnum));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for attribute %d of relation %u" ,
attnum, relid);
att_tup = (Form_pg_attribute) GETSTRUCT(tp);
result = att_tup->attgenerated;
ReleaseSysCache(tp);
return result;
}
/*
* get_atttype
*
* Given the relation OID and the attribute number with the relation ,
* return the attribute type OID .
*/
Oid
get_atttype(Oid relid, AttrNumber attnum)
{
HeapTuple tp;
tp = SearchSysCache2(ATTNUM,
ObjectIdGetDatum(relid),
Int16GetDatum(attnum));
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 InvalidOid;
}
/*
* get_atttypetypmodcoll
*
* 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 , this routine
* raises an error if it can ' t obtain the information .
*/
void
get_atttypetypmodcoll(Oid relid, AttrNumber attnum,
Oid *typid, int32 *typmod, Oid *collid)
{
HeapTuple tp;
Form_pg_attribute att_tup;
tp = SearchSysCache2(ATTNUM,
ObjectIdGetDatum(relid),
Int16GetDatum(attnum));
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;
*collid = att_tup->attcollation;
ReleaseSysCache(tp);
}
/*
* get_attoptions
*
* Given the relation id and the attribute number ,
* return the attribute options text [ ] datum , if any .
*/
Datum
get_attoptions(Oid relid, int16 attnum)
{
HeapTuple tuple;
Datum attopts;
Datum result;
bool isnull;
tuple = SearchSysCache2(ATTNUM,
ObjectIdGetDatum(relid),
Int16GetDatum(attnum));
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for attribute %d of relation %u" ,
attnum, relid);
attopts = SysCacheGetAttr(ATTNAME, tuple, Anum_pg_attribute_attoptions,
&isnull);
if (isnull)
result = (Datum) 0 ;
else
result = datumCopy(attopts, false , -1 ); /* text[] */
ReleaseSysCache(tuple);
return result;
}
/* ---------- PG_CAST CACHE ---------- */
/*
* get_cast_oid - given two type OIDs , look up a cast OID
*
* If missing_ok is false , throw an error if the cast is not found . If
* true , just return InvalidOid .
*/
Oid
get_cast_oid(Oid sourcetypeid, Oid targettypeid, bool missing_ok)
{
Oid oid;
oid = GetSysCacheOid2(CASTSOURCETARGET, Anum_pg_cast_oid,
ObjectIdGetDatum(sourcetypeid),
ObjectIdGetDatum(targettypeid));
if (!OidIsValid(oid) && !missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("cast from type %s to type %s does not exist" ,
format_type_be(sourcetypeid),
format_type_be(targettypeid))));
return oid;
}
/* ---------- 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 collation .
*
* 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;
}
bool
get_collation_isdeterministic(Oid colloid)
{
HeapTuple tp;
Form_pg_collation colltup;
bool result;
tp = SearchSysCache1(COLLOID, ObjectIdGetDatum(colloid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for collation %u" , colloid);
colltup = (Form_pg_collation) GETSTRUCT(tp);
result = colltup->collisdeterministic;
ReleaseSysCache(tp);
return result;
}
/* ---------- CONSTRAINT CACHE ---------- */
/*
* 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;
}
/*
* get_constraint_index
* Given the OID of a unique , primary - key , or exclusion constraint ,
* return the OID of the underlying index .
*
* Returns InvalidOid if the constraint could not be found or is of
* the wrong type .
*
* The intent of this function is to return the index " owned " by the
* specified constraint . Therefore we must check contype , since some
* pg_constraint entries ( e . g . for foreign - key constraints ) store the
* OID of an index that is referenced but not owned by the constraint .
*/
Oid
get_constraint_index(Oid conoid)
{
HeapTuple tp;
tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conoid));
if (HeapTupleIsValid(tp))
{
Form_pg_constraint contup = (Form_pg_constraint) GETSTRUCT(tp);
Oid result;
if (contup->contype == CONSTRAINT_UNIQUE ||
contup->contype == CONSTRAINT_PRIMARY ||
contup->contype == CONSTRAINT_EXCLUSION)
result = contup->conindid;
else
result = InvalidOid;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
/*
* get_constraint_type
* Return the pg_constraint . contype value for the given constraint .
*
* No frills .
*/
char
get_constraint_type(Oid conoid)
{
HeapTuple tp;
char contype;
tp = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conoid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for constraint %u" , conoid);
contype = ((Form_pg_constraint) GETSTRUCT(tp))->contype;
ReleaseSysCache(tp);
return contype;
}
/* ---------- LANGUAGE CACHE ---------- */
char *
get_language_name(Oid langoid, bool missing_ok)
{
HeapTuple tp;
tp = SearchSysCache1(LANGOID, ObjectIdGetDatum(langoid));
if (HeapTupleIsValid(tp))
{
Form_pg_language lantup = (Form_pg_language) GETSTRUCT(tp);
char *result;
result = pstrdup(NameStr(lantup->lanname));
ReleaseSysCache(tp);
return result;
}
if (!missing_ok)
elog(ERROR, "cache lookup failed for language %u" ,
langoid);
return NULL;
}
/* ---------- OPCLASS CACHE ---------- */
/*
* get_opclass_family
*
* Returns the OID of the operator family the opclass belongs to .
*/
Oid
get_opclass_family(Oid opclass)
{
HeapTuple tp;
Form_pg_opclass cla_tup;
Oid result;
tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for opclass %u" , opclass);
cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
result = cla_tup->opcfamily;
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 = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
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);
return result;
}
/*
* get_opclass_opfamily_and_input_type
*
* Returns the OID of the operator family the opclass belongs to ,
* the OID of the datatype the opclass indexes
*/
bool
get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
{
HeapTuple tp;
Form_pg_opclass cla_tup;
tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
if (!HeapTupleIsValid(tp))
return false ;
cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
*opfamily = cla_tup->opcfamily;
*opcintype = cla_tup->opcintype;
ReleaseSysCache(tp);
return true ;
}
/*
* get_opclass_method
*
* Returns the OID of the index access method the opclass belongs to .
*/
Oid
get_opclass_method(Oid opclass)
{
HeapTuple tp;
Form_pg_opclass cla_tup;
Oid result;
tp = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for opclass %u" , opclass);
cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
result = cla_tup->opcmethod;
ReleaseSysCache(tp);
return result;
}
/* ---------- OPFAMILY CACHE ---------- */
/*
* get_opfamily_method
*
* Returns the OID of the index access method the opfamily is for .
*/
Oid
get_opfamily_method(Oid opfid)
{
HeapTuple tp;
Form_pg_opfamily opfform;
Oid result;
tp = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for operator family %u" , opfid);
opfform = (Form_pg_opfamily) GETSTRUCT(tp);
result = opfform->opfmethod;
ReleaseSysCache(tp);
return result;
}
char *
get_opfamily_name(Oid opfid, bool missing_ok)
{
HeapTuple tup;
char *opfname;
Form_pg_opfamily opfform;
tup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
if (!HeapTupleIsValid(tup))
{
if (!missing_ok)
elog(ERROR, "cache lookup failed for operator family %u" , opfid);
return NULL;
}
opfform = (Form_pg_opfamily) GETSTRUCT(tup);
opfname = pstrdup(NameStr(opfform->opfname));
ReleaseSysCache(tup);
return opfname;
}
/* ---------- OPERATOR CACHE ---------- */
/*
* get_opcode
*
* Returns the regproc id of the routine used to implement an
* operator given the operator oid .
*/
RegProcedure
get_opcode(Oid opno)
{
HeapTuple tp;
tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
RegProcedure result;
result = optup->oprcode;
ReleaseSysCache(tp);
return result;
}
else
return (RegProcedure) InvalidOid;
}
/*
* get_opname
* returns the name of the operator with the given opno
*
* Note : returns a palloc ' d copy of the string , or NULL if no such operator .
*/
char *
get_opname(Oid opno)
{
HeapTuple tp;
tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
char *result;
result = pstrdup(NameStr(optup->oprname));
ReleaseSysCache(tp);
return result;
}
else
return NULL;
}
/*
* get_op_rettype
* Given operator oid , return the operator ' s result type .
*/
Oid
get_op_rettype(Oid opno)
{
HeapTuple tp;
tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
Oid result;
result = optup->oprresult;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
/*
* op_input_types
*
* Returns the left and right input datatypes for an operator
* ( InvalidOid if not relevant ) .
*/
void
op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
{
HeapTuple tp;
Form_pg_operator optup;
tp = 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);
*lefttype = optup->oprleft;
*righttype = optup->oprright;
ReleaseSysCache(tp);
}
/*
* op_mergejoinable
*
* Returns true if the operator is potentially mergejoinable . ( The planner
* 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, Oid inputtype)
{
bool result = false ;
HeapTuple tp;
TypeCacheEntry *typentry;
/*
* 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)
{
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);
}
}
return result;
}
/*
* op_hashjoinable
*
* 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, Oid inputtype)
{
bool result = false ;
HeapTuple tp;
TypeCacheEntry *typentry;
/* As in op_mergejoinable, let the typcache handle the hard cases */
if (opno == ARRAY_EQ_OP)
{
typentry = lookup_type_cache(inputtype, TYPECACHE_HASH_PROC);
if (typentry->hash_proc == F_HASH_ARRAY)
result = true ;
}
else if (opno == RECORD_EQ_OP)
{
typentry = lookup_type_cache(inputtype, TYPECACHE_HASH_PROC);
if (typentry->hash_proc == F_HASH_RECORD)
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);
}
}
return result;
}
/*
* op_strict
*
* Get the proisstrict flag for the operator ' s underlying function .
*/
bool
op_strict(Oid opno)
{
RegProcedure funcid = get_opcode(opno);
if (funcid == (RegProcedure) InvalidOid)
elog(ERROR, "operator %u does not exist" , opno);
return func_strict((Oid) funcid);
}
/*
* op_volatile
*
* Get the provolatile flag for the operator ' s underlying function .
*/
char
op_volatile(Oid opno)
{
RegProcedure funcid = get_opcode(opno);
if (funcid == (RegProcedure) InvalidOid)
elog(ERROR, "operator %u does not exist" , opno);
return func_volatile((Oid) funcid);
}
/*
* get_commutator
*
* Returns the corresponding commutator of an operator .
*/
Oid
get_commutator(Oid opno)
{
HeapTuple tp;
tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
Oid result;
result = optup->oprcom;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
/*
* get_negator
*
* Returns the corresponding negator of an operator .
*/
Oid
get_negator(Oid opno)
{
HeapTuple tp;
tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
Oid result;
result = optup->oprnegate;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
/*
* get_oprrest
*
* Returns procedure id for computing selectivity of an operator .
*/
RegProcedure
get_oprrest(Oid opno)
{
HeapTuple tp;
tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
RegProcedure result;
result = optup->oprrest;
ReleaseSysCache(tp);
return result;
}
else
return (RegProcedure) InvalidOid;
}
/*
* get_oprjoin
*
* Returns procedure id for computing selectivity of a join .
*/
RegProcedure
get_oprjoin(Oid opno)
{
HeapTuple tp;
tp = SearchSysCache1(OPEROID, ObjectIdGetDatum(opno));
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
RegProcedure result;
result = optup->oprjoin;
ReleaseSysCache(tp);
return result;
}
else
return (RegProcedure) InvalidOid;
}
/* ---------- FUNCTION CACHE ---------- */
/*
* get_func_name
* returns the name of the function with the given funcid
*
* Note : returns a palloc ' d copy of the string , or NULL if no such function .
*/
char *
get_func_name(Oid funcid)
{
HeapTuple tp;
tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (HeapTupleIsValid(tp))
{
Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
char *result;
result = pstrdup(NameStr(functup->proname));
ReleaseSysCache(tp);
return result;
}
else
return NULL;
}
/*
* get_func_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 .
*/
Oid
get_func_rettype(Oid funcid)
{
HeapTuple tp;
Oid result;
tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u" , funcid);
result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype;
ReleaseSysCache(tp);
return result;
}
/*
* get_func_nargs
* Given procedure id , return the number of arguments .
*/
int
get_func_nargs(Oid funcid)
{
HeapTuple tp;
int result;
tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u" , funcid);
result = ((Form_pg_proc) GETSTRUCT(tp))->pronargs;
ReleaseSysCache(tp);
return result;
}
/*
* get_func_signature
* Given procedure id , return the function ' s argument and result types .
* ( The return value is the result type . )
*
* The arguments are returned as a palloc ' d array .
*/
Oid
get_func_signature(Oid funcid, Oid **argtypes, int *nargs)
{
HeapTuple tp;
Form_pg_proc procstruct;
Oid result;
tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u" , funcid);
procstruct = (Form_pg_proc) GETSTRUCT(tp);
result = procstruct->prorettype;
*nargs = (int ) procstruct->pronargs;
Assert(*nargs == procstruct->proargtypes.dim1);
*argtypes = (Oid *) palloc(*nargs * sizeof (Oid));
memcpy(*argtypes, procstruct->proargtypes.values, *nargs * sizeof (Oid));
ReleaseSysCache(tp);
return result;
}
/*
* get_func_variadictype
* Given procedure id , return the function ' s provariadic field .
*/
Oid
get_func_variadictype(Oid funcid)
{
HeapTuple tp;
Oid result;
tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u" , funcid);
result = ((Form_pg_proc) GETSTRUCT(tp))->provariadic;
ReleaseSysCache(tp);
return result;
}
/*
* get_func_retset
* Given procedure id , return the function ' s proretset flag .
*/
bool
get_func_retset(Oid funcid)
{
HeapTuple tp;
bool result;
tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u" , funcid);
result = ((Form_pg_proc) GETSTRUCT(tp))->proretset;
ReleaseSysCache(tp);
return result;
}
/*
* func_strict
* Given procedure id , return the function ' s proisstrict flag .
*/
bool
func_strict(Oid funcid)
{
HeapTuple tp;
bool result;
tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u" , funcid);
result = ((Form_pg_proc) GETSTRUCT(tp))->proisstrict;
ReleaseSysCache(tp);
return result;
}
/*
* func_volatile
* Given procedure id , return the function ' s provolatile flag .
*/
char
func_volatile(Oid funcid)
{
HeapTuple tp;
char result;
tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u" , funcid);
result = ((Form_pg_proc) GETSTRUCT(tp))->provolatile;
ReleaseSysCache(tp);
return result;
}
/*
* func_parallel
* Given procedure id , return the function ' s proparallel flag .
*/
char
func_parallel(Oid funcid)
{
HeapTuple tp;
char result;
tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u" , funcid);
result = ((Form_pg_proc) GETSTRUCT(tp))->proparallel;
ReleaseSysCache(tp);
return result;
}
/*
* get_func_prokind
* Given procedure id , return the routine kind .
*/
char
get_func_prokind(Oid funcid)
{
HeapTuple tp;
char result;
tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u" , funcid);
result = ((Form_pg_proc) GETSTRUCT(tp))->prokind;
ReleaseSysCache(tp);
return result;
}
/*
* get_func_leakproof
* Given procedure id , return the function ' s leakproof field .
*/
bool
get_func_leakproof(Oid funcid)
{
HeapTuple tp;
bool result;
tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u" , funcid);
result = ((Form_pg_proc) GETSTRUCT(tp))->proleakproof;
ReleaseSysCache(tp);
return result;
}
/*
* get_func_support
*
* Returns the support function OID associated with a given function ,
* or InvalidOid if there is none .
*/
RegProcedure
get_func_support(Oid funcid)
{
HeapTuple tp;
tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (HeapTupleIsValid(tp))
{
Form_pg_proc functup = (Form_pg_proc) GETSTRUCT(tp);
RegProcedure result;
result = functup->prosupport;
ReleaseSysCache(tp);
return result;
}
else
return (RegProcedure) InvalidOid;
}
/* ---------- RELATION CACHE ---------- */
/*
* get_relname_relid
* Given name and namespace of a relation , look up the OID .
*
* Returns InvalidOid if there is no such relation .
*/
Oid
get_relname_relid(const char *relname, Oid relnamespace)
{
return GetSysCacheOid2(RELNAMENSP, Anum_pg_class_oid,
PointerGetDatum(relname),
ObjectIdGetDatum(relnamespace));
}
#ifdef NOT_USED
/*
* get_relnatts
*
* Returns the number of attributes for a given relation .
*/
int
get_relnatts(Oid relid)
{
HeapTuple tp;
tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
int result;
result = reltup->relnatts;
ReleaseSysCache(tp);
return result;
}
else
return InvalidAttrNumber;
}
#endif
/*
* get_rel_name
* Returns the name of a given relation .
*
* Returns a palloc ' d copy of the string , or NULL if no such relation .
*
* NOTE : since relation name is not unique , be wary of code that uses this
* for anything except preparing error messages .
*/
char *
get_rel_name(Oid relid)
{
HeapTuple tp;
tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
char *result;
result = pstrdup(NameStr(reltup->relname));
ReleaseSysCache(tp);
return result;
}
else
return NULL;
}
/*
* get_rel_namespace
*
* Returns the pg_namespace OID associated with a given relation .
*/
Oid
get_rel_namespace(Oid relid)
{
HeapTuple tp;
tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
Oid result;
result = reltup->relnamespace;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
/*
* get_rel_type_id
*
* Returns the pg_type OID associated with a given relation .
*
* Note : not all pg_class entries have associated pg_type OIDs ; so be
* careful to check for InvalidOid result .
*/
Oid
get_rel_type_id(Oid relid)
{
HeapTuple tp;
tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
Oid result;
result = reltup->reltype;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
/*
* get_rel_relkind
*
* Returns the relkind associated with a given relation .
*/
char
get_rel_relkind(Oid relid)
{
HeapTuple tp;
tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
char result;
result = reltup->relkind;
ReleaseSysCache(tp);
return result;
}
else
return '\0' ;
}
/*
* get_rel_relispartition
*
* Returns the relispartition flag associated with a given relation .
*/
bool
get_rel_relispartition(Oid relid)
{
HeapTuple tp;
tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
bool result;
result = reltup->relispartition;
ReleaseSysCache(tp);
return result;
}
else
return false ;
}
/*
* 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;
}
/*
* get_rel_persistence
*
* Returns the relpersistence associated with a given relation .
*/
char
get_rel_persistence(Oid relid)
{
HeapTuple tp;
Form_pg_class reltup;
char result;
tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for relation %u" , relid);
reltup = (Form_pg_class) GETSTRUCT(tp);
result = reltup->relpersistence;
ReleaseSysCache(tp);
return result;
}
/*
* get_rel_relam
*
* Returns the relam associated with a given relation .
*/
Oid
get_rel_relam(Oid relid)
{
HeapTuple tp;
Form_pg_class reltup;
Oid result;
tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for relation %u" , relid);
reltup = (Form_pg_class) GETSTRUCT(tp);
result = reltup->relam;
ReleaseSysCache(tp);
return result;
}
/* ---------- TRANSFORM CACHE ---------- */
Oid
get_transform_fromsql(Oid typid, Oid langid, List *trftypes)
{
HeapTuple tup;
if (!list_member_oid(trftypes, typid))
return InvalidOid;
tup = SearchSysCache2(TRFTYPELANG, ObjectIdGetDatum(typid),
ObjectIdGetDatum(langid));
if (HeapTupleIsValid(tup))
{
Oid funcid;
funcid = ((Form_pg_transform) GETSTRUCT(tup))->trffromsql;
ReleaseSysCache(tup);
return funcid;
}
else
return InvalidOid;
}
Oid
get_transform_tosql(Oid typid, Oid langid, List *trftypes)
{
HeapTuple tup;
if (!list_member_oid(trftypes, typid))
return InvalidOid;
tup = SearchSysCache2(TRFTYPELANG, ObjectIdGetDatum(typid),
ObjectIdGetDatum(langid));
if (HeapTupleIsValid(tup))
{
Oid funcid;
funcid = ((Form_pg_transform) GETSTRUCT(tup))->trftosql;
ReleaseSysCache(tup);
return funcid;
}
else
return InvalidOid;
}
/* ---------- TYPE CACHE ---------- */
/*
* get_typisdefined
*
* Given the type OID , determine whether the type is defined
* ( if not , it ' s only a shell ) .
*/
bool
get_typisdefined(Oid typid)
{
HeapTuple tp;
tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
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)
{
HeapTuple tp;
tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
int16 result;
result = typtup->typlen;
ReleaseSysCache(tp);
return result;
}
else
return 0 ;
}
/*
* get_typbyval
*
* Given the type OID , determine whether the type is returned by value or
* not . Returns true if by value , false if by reference .
*/
bool
get_typbyval(Oid typid)
{
HeapTuple tp;
tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
bool result;
result = typtup->typbyval;
ReleaseSysCache(tp);
return result;
}
else
return false ;
}
/*
* get_typlenbyval
*
* A two - fer : given the type OID , return both typlen and typbyval .
*
* Since both pieces of info are needed to know how to copy a Datum ,
* many places need both . Might as well get them with one cache lookup
* instead of two . Also , this routine raises an error instead of
* returning a bogus value when given a bad type OID .
*/
void
get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval)
{
HeapTuple tp;
Form_pg_type typtup;
tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for type %u" , typid);
typtup = (Form_pg_type) GETSTRUCT(tp);
*typlen = typtup->typlen;
*typbyval = typtup->typbyval;
ReleaseSysCache(tp);
}
/*
* get_typlenbyvalalign
*
* A three - fer : given the type OID , return typlen , typbyval , typalign .
*/
void
get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval,
char *typalign)
{
HeapTuple tp;
Form_pg_type typtup;
tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for type %u" , typid);
typtup = (Form_pg_type) GETSTRUCT(tp);
*typlen = typtup->typlen;
*typbyval = typtup->typbyval;
*typalign = typtup->typalign;
ReleaseSysCache(tp);
}
/*
* getTypeIOParam
* Given a pg_type row , select the type OID to pass to I / O functions
*
* Formerly , all I / O functions were passed pg_type . typelem as their second
* parameter , but we now have a more complex rule about what to pass .
* This knowledge is intended to be centralized here - - - direct references
* to typelem elsewhere in the code are wrong , if they are associated with
* I / O calls and not with actual subscripting operations ! ( But see
* bootstrap . c ' s boot_get_type_io_data ( ) if you need to change this . )
*
* As of PostgreSQL 8 . 1 , output functions receive only the value itself
* and not any auxiliary parameters , so the name of this routine is now
* a bit of a misnomer . . . it should be getTypeInputParam .
*/
Oid
getTypeIOParam(HeapTuple typeTuple)
{
Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
/*
* Array types get their typelem as parameter ; everybody else gets their
* own type OID as parameter .
*/
if (OidIsValid(typeStruct->typelem))
return typeStruct->typelem;
else
return typeStruct->oid;
}
/*
* get_type_io_data
*
* A six - fer : given the type OID , return typlen , typbyval , typalign ,
* typdelim , typioparam , and IO function OID . The IO function
* returned is controlled by IOFuncSelector
*/
void
get_type_io_data(Oid typid,
IOFuncSelector which_func,
int16 *typlen,
bool *typbyval,
char *typalign,
char *typdelim,
Oid *typioparam,
Oid *func)
{
HeapTuple typeTuple;
Form_pg_type typeStruct;
/*
* In bootstrap mode , pass it off to bootstrap . c . This hack allows us to
* use array_in and array_out during bootstrap .
*/
if (IsBootstrapProcessingMode())
{
Oid typinput;
Oid typoutput;
boot_get_type_io_data(typid,
typlen,
typbyval,
typalign,
typdelim,
typioparam,
&typinput,
&typoutput);
switch (which_func)
{
case IOFunc_input:
*func = typinput;
break ;
case IOFunc_output:
*func = typoutput;
break ;
default :
elog(ERROR, "binary I/O not supported during bootstrap" );
break ;
}
return ;
}
typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (!HeapTupleIsValid(typeTuple))
elog(ERROR, "cache lookup failed for type %u" , typid);
typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
*typlen = typeStruct->typlen;
*typbyval = typeStruct->typbyval;
*typalign = typeStruct->typalign;
*typdelim = typeStruct->typdelim;
*typioparam = getTypeIOParam(typeTuple);
switch (which_func)
{
case IOFunc_input:
*func = typeStruct->typinput;
break ;
case IOFunc_output:
*func = typeStruct->typoutput;
break ;
case IOFunc_receive:
*func = typeStruct->typreceive;
break ;
case IOFunc_send:
*func = typeStruct->typsend;
break ;
}
ReleaseSysCache(typeTuple);
}
#ifdef NOT_USED
char
get_typalign(Oid typid)
{
HeapTuple tp;
tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
char result;
result = typtup->typalign;
ReleaseSysCache(tp);
return result;
}
else
return TYPALIGN_INT;
}
#endif
char
get_typstorage(Oid typid)
{
HeapTuple tp;
tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
char result;
result = typtup->typstorage;
ReleaseSysCache(tp);
return result;
}
else
return TYPSTORAGE_PLAIN;
}
/*
* get_typdefault
* Given a type OID , return the type ' s default value , if any .
*
* The result is a palloc ' d expression node tree , or NULL if there
* is no defined default for the datatype .
*
* NB : caller should be prepared to coerce result to correct datatype ;
* the returned expression tree might produce something of the wrong type .
*/
Node *
get_typdefault(Oid typid)
{
HeapTuple typeTuple;
Form_pg_type type;
Datum datum;
bool isNull;
Node *expr;
typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (!HeapTupleIsValid(typeTuple))
elog(ERROR, "cache lookup failed for 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(TextDatumGetCString(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 = 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 ,
type->typbyval);
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)
{
int32 typmod = -1 ;
return getBaseTypeAndTypmod(typid, &typmod);
}
/*
* getBaseTypeAndTypmod
* If the given type is a domain , return its base type and typmod ;
* otherwise return the type ' s own OID , and leave * typmod unchanged .
*
* Note that the " applied typmod " should be - 1 for every domain level
* above the bottommost ; therefore , if the passed - in typid is indeed
* a domain , * typmod should be - 1 .
*/
Oid
getBaseTypeAndTypmod(Oid typid, int32 *typmod)
{
/*
* We loop to find the bottom base type in a stack of domains .
*/
for (;;)
{
HeapTuple tup;
Form_pg_type typTup;
tup = 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 != TYPTYPE_DOMAIN)
{
/* Not a domain, so done */
ReleaseSysCache(tup);
break ;
}
Assert(*typmod == -1 );
typid = typTup->typbasetype;
*typmod = typTup->typtypmod;
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;
/*
* 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 ;
}
/*
* Oops , we have no idea . . . wild guess time .
*/
return 32 ;
}
/*
* get_typtype
*
* Given the type OID , find if it is a basic type , a complex type , etc .
* It returns the null char if the cache lookup fails . . .
*/
char
get_typtype(Oid typid)
{
HeapTuple tp;
tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
char result;
result = typtup->typtype;
ReleaseSysCache(tp);
return result;
}
else
return '\0' ;
}
/*
* type_is_rowtype
*
* Convenience function to determine whether a type OID represents
* a " rowtype " type - - - either RECORD or a named composite type
* ( including a domain over a named composite type ) .
*/
bool
type_is_rowtype(Oid typid)
{
if (typid == RECORDOID)
return true ; /* easy case */
switch (get_typtype(typid))
{
case TYPTYPE_COMPOSITE:
return true ;
case TYPTYPE_DOMAIN:
if (get_typtype(getBaseType(typid)) == TYPTYPE_COMPOSITE)
return true ;
break ;
default :
break ;
}
return false ;
}
/*
* 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);
}
/*
* type_is_multirange
* Returns true if the given type is a multirange type .
*/
bool
type_is_multirange(Oid typid)
{
return (get_typtype(typid) == TYPTYPE_MULTIRANGE);
}
/*
* 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);
}
/*
* get_typ_typrelid
*
* Given the type OID , get the typrelid ( InvalidOid if not a complex
* type ) .
*/
Oid
get_typ_typrelid(Oid typid)
{
HeapTuple tp;
tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
Oid result;
result = typtup->typrelid;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
/*
* get_element_type
*
* Given the type OID , get the typelem ( InvalidOid if not an array type ) .
*
* NB : this only succeeds for " true " arrays having array_subscript_handler
* as typsubscript . For other types , InvalidOid is returned independently
* of whether they have typelem or typsubscript set .
*/
Oid
get_element_type(Oid typid)
{
HeapTuple tp;
tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (HeapTupleIsValid(tp))
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
Oid result;
if (IsTrueArrayType(typtup))
result = typtup->typelem;
else
result = InvalidOid;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
/*
* get_array_type
*
* Given the type OID , get the corresponding " true " array type .
* Returns InvalidOid if no array type can be found .
*/
Oid
get_array_type(Oid typid)
{
HeapTuple tp;
Oid result = InvalidOid;
tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (HeapTupleIsValid(tp))
{
result = ((Form_pg_type) GETSTRUCT(tp))->typarray;
ReleaseSysCache(tp);
}
return result;
}
/*
* get_promoted_array_type
*
* The " promoted " type is what you ' d get from an ARRAY ( SELECT . . . )
* construct , that is , either the corresponding " true " array type
* if the input is a scalar type that has such an array type ,
* or the same type if the input is already a " true " array type .
* Returns InvalidOid if neither rule is satisfied .
*/
Oid
get_promoted_array_type(Oid typid)
{
Oid array_type = get_array_type(typid);
if (OidIsValid(array_type))
return array_type;
if (OidIsValid(get_element_type(typid)))
return typid;
return InvalidOid;
}
/*
* 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;
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;
/* This test must match get_element_type */
if (IsTrueArrayType(typTup))
result = typTup->typelem;
else
result = InvalidOid;
ReleaseSysCache(tup);
return result;
}
typid = typTup->typbasetype;
ReleaseSysCache(tup);
}
/* Like get_element_type, silently return InvalidOid for bogus input */
return InvalidOid;
}
/*
* getTypeInputInfo
*
* Get info needed for converting values of a type to internal form
*/
void
getTypeInputInfo(Oid type, Oid *typInput, Oid *typIOParam)
{
HeapTuple typeTuple;
Form_pg_type pt;
typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
if (!HeapTupleIsValid(typeTuple))
elog(ERROR, "cache lookup failed for type %u" , type);
pt = (Form_pg_type) GETSTRUCT(typeTuple);
if (!pt->typisdefined)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type %s is only a shell" ,
format_type_be(type))));
if (!OidIsValid(pt->typinput))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("no input function available for type %s" ,
format_type_be(type))));
*typInput = pt->typinput;
*typIOParam = getTypeIOParam(typeTuple);
ReleaseSysCache(typeTuple);
}
/*
* getTypeOutputInfo
*
* Get info needed for printing values of a type
*/
void
getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
{
HeapTuple typeTuple;
Form_pg_type pt;
typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
if (!HeapTupleIsValid(typeTuple))
elog(ERROR, "cache lookup failed for type %u" , type);
pt = (Form_pg_type) GETSTRUCT(typeTuple);
if (!pt->typisdefined)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type %s is only a shell" ,
format_type_be(type))));
if (!OidIsValid(pt->typoutput))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("no output function available for type %s" ,
format_type_be(type))));
*typOutput = pt->typoutput;
*typIsVarlena = (!pt->typbyval) && (pt->typlen == -1 );
ReleaseSysCache(typeTuple);
}
/*
* getTypeBinaryInputInfo
*
* Get info needed for binary input of values of a type
*/
void
getTypeBinaryInputInfo(Oid type, Oid *typReceive, Oid *typIOParam)
{
HeapTuple typeTuple;
Form_pg_type pt;
typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
if (!HeapTupleIsValid(typeTuple))
elog(ERROR, "cache lookup failed for type %u" , type);
pt = (Form_pg_type) GETSTRUCT(typeTuple);
if (!pt->typisdefined)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type %s is only a shell" ,
format_type_be(type))));
if (!OidIsValid(pt->typreceive))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("no binary input function available for type %s" ,
format_type_be(type))));
*typReceive = pt->typreceive;
*typIOParam = getTypeIOParam(typeTuple);
ReleaseSysCache(typeTuple);
}
/*
* getTypeBinaryOutputInfo
*
* Get info needed for binary output of values of a type
*/
void
getTypeBinaryOutputInfo(Oid type, Oid *typSend, bool *typIsVarlena)
{
HeapTuple typeTuple;
Form_pg_type pt;
typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type));
if (!HeapTupleIsValid(typeTuple))
elog(ERROR, "cache lookup failed for type %u" , type);
pt = (Form_pg_type) GETSTRUCT(typeTuple);
if (!pt->typisdefined)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type %s is only a shell" ,
format_type_be(type))));
if (!OidIsValid(pt->typsend))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("no binary output function available for type %s" ,
format_type_be(type))));
*typSend = pt->typsend;
*typIsVarlena = (!pt->typbyval) && (pt->typlen == -1 );
ReleaseSysCache(typeTuple);
}
/*
* get_typmodin
*
* Given the type OID , return the type ' s typmodin procedure , if any .
*/
Oid
get_typmodin(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->typmodin;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
#ifdef NOT_USED
/*
* get_typmodout
*
* Given the type OID , return the type ' s typmodout procedure , if any .
*/
Oid
get_typmodout(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->typmodout;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
#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));
}
/*
* get_typsubscript
*
* Given the type OID , return the type ' s subscripting handler ' s OID ,
* if it has one .
*
* If typelemp isn ' t NULL , we also store the type ' s typelem value there .
* This saves some callers an extra catalog lookup .
*/
RegProcedure
get_typsubscript(Oid typid, Oid *typelemp)
{
HeapTuple tp;
tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (HeapTupleIsValid(tp))
{
Form_pg_type typform = (Form_pg_type) GETSTRUCT(tp);
RegProcedure handler = typform->typsubscript;
if (typelemp)
*typelemp = typform->typelem;
ReleaseSysCache(tp);
return handler;
}
else
{
if (typelemp)
*typelemp = InvalidOid;
return InvalidOid;
}
}
/*
* getSubscriptingRoutines
*
* Given the type OID , fetch the type ' s subscripting methods struct .
* Return NULL if type is not subscriptable .
*
* If typelemp isn ' t NULL , we also store the type ' s typelem value there .
* This saves some callers an extra catalog lookup .
*/
const struct SubscriptRoutines *
getSubscriptingRoutines(Oid typid, Oid *typelemp)
{
RegProcedure typsubscript = get_typsubscript(typid, typelemp);
if (!OidIsValid(typsubscript))
return NULL;
return (const struct SubscriptRoutines *)
DatumGetPointer(OidFunctionCall0(typsubscript));
}
/* ---------- 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 .
*
* 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;
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))
{
stawidth = ((Form_pg_statistic) GETSTRUCT(tp))->stawidth;
ReleaseSysCache(tp);
if (stawidth > 0 )
return stawidth;
}
return 0 ;
}
/*
* get_attstatsslot
*
* Extract the contents of a " slot " of a pg_statistic tuple .
* Returns true if requested slot type was found , else false .
*
* Unlike other routines in this file , this takes a pointer to an
* already - looked - up tuple in the pg_statistic cache . We do this since
* most callers will want to extract more than one value from the cache
* entry , and we don ' t want to repeat the cache lookup unnecessarily .
* 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 .
*
* sslot : pointer to output area ( typically , a local variable in the caller ) .
* statstuple : pg_statistic tuple to be examined .
* reqkind : STAKIND code for desired statistics slot kind .
* reqop : STAOP value wanted , or InvalidOid if don ' t care .
* flags : bitmask of ATTSTATSSLOT_VALUES and / or ATTSTATSSLOT_NUMBERS .
*
* If a matching slot is found , true is returned , and * sslot is filled thus :
* staop : receives the actual STAOP value .
* stacoll : receives the actual STACOLL value .
* valuetype : receives actual datatype of the elements of stavalues .
* values : receives pointer to an array of the slot ' s stavalues .
* nvalues : receives number of stavalues .
* numbers : receives pointer to an array of the slot ' s stanumbers ( as float4 ) .
* nnumbers : receives number of stanumbers .
*
* valuetype / values / nvalues are InvalidOid / NULL / 0 if ATTSTATSSLOT_VALUES
* wasn ' t specified . Likewise , numbers / nnumbers are NULL / 0 if
* ATTSTATSSLOT_NUMBERS wasn ' t specified .
*
* If no matching slot is found , false is returned , and * sslot is zeroed .
*
* Note that the current API doesn ' t allow for searching for a slot with
* a particular collation . If we ever actually support recording more than
* one collation , we ' ll have to extend the API , but for now simple is good .
*
* The data referred to by the fields of sslot is locally palloc ' d and
* is independent of the original pg_statistic tuple . When the caller
* is done with it , call free_attstatsslot to release the palloc ' d data .
*
* If it ' s desirable to call free_attstatsslot when get_attstatsslot might
* not have been called , memset ' ing sslot to zeroes will allow that .
*
* Passing flags = 0 can be useful to quickly check if the requested slot type
* exists . In this case no arrays are extracted , so free_attstatsslot need
* not be called .
*/
bool
get_attstatsslot(AttStatsSlot *sslot, HeapTuple statstuple,
int reqkind, Oid reqop, int flags)
{
Form_pg_statistic stats = (Form_pg_statistic) GETSTRUCT(statstuple);
int i;
Datum val;
ArrayType *statarray;
Oid arrayelemtype;
int narrayelem;
HeapTuple typeTuple;
Form_pg_type typeForm;
/* initialize *sslot properly */
memset(sslot, 0 , sizeof (AttStatsSlot));
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 */
sslot->staop = (&stats->staop1)[i];
sslot->stacoll = (&stats->stacoll1)[i];
if (flags & ATTSTATSSLOT_VALUES)
{
val = SysCacheGetAttrNotNull(STATRELATTINH, statstuple,
Anum_pg_statistic_stavalues1 + i);
/*
* Detoast the array if needed , and in any case make a copy that ' s
* under control of this AttStatsSlot .
*/
statarray = DatumGetArrayTypePCopy(val);
/*
* Extract the actual array element type , and pass it back in case the
* caller needs it .
*/
sslot->valuetype = arrayelemtype = ARR_ELEMTYPE(statarray);
/* Need info about element type */
typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(arrayelemtype));
if (!HeapTupleIsValid(typeTuple))
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,
arrayelemtype,
typeForm->typlen,
typeForm->typbyval,
typeForm->typalign,
&sslot->values, NULL, &sslot->nvalues);
/*
* If the element type is pass - by - reference , we now have a bunch of
* Datums that are pointers into the statarray , so we need to keep
* that until free_attstatsslot . Otherwise , all the useful info is in
* sslot - > values [ ] , so we can free the array object immediately .
*/
if (!typeForm->typbyval)
sslot->values_arr = statarray;
else
pfree(statarray);
ReleaseSysCache(typeTuple);
}
if (flags & ATTSTATSSLOT_NUMBERS)
{
val = SysCacheGetAttrNotNull(STATRELATTINH, statstuple,
Anum_pg_statistic_stanumbers1 + i);
/*
* Detoast the array if needed , and in any case make a copy that ' s
* under control of this AttStatsSlot .
*/
statarray = DatumGetArrayTypePCopy(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_HASNULL(statarray) ||
ARR_ELEMTYPE(statarray) != FLOAT4OID)
elog(ERROR, "stanumbers is not a 1-D float4 array" );
/* Give caller a pointer directly into the statarray */
sslot->numbers = (float4 *) ARR_DATA_PTR(statarray);
sslot->nnumbers = narrayelem;
/* We'll free the statarray in free_attstatsslot */
sslot->numbers_arr = statarray;
}
return true ;
}
/*
* free_attstatsslot
* Free data allocated by get_attstatsslot
*/
void
free_attstatsslot(AttStatsSlot *sslot)
{
/* The values[] array was separately palloc'd by deconstruct_array */
if (sslot->values)
pfree(sslot->values);
/* The numbers[] array points into numbers_arr, do not pfree it */
/* Free the detoasted array objects, if any */
if (sslot->values_arr)
pfree(sslot->values_arr);
if (sslot->numbers_arr)
pfree(sslot->numbers_arr);
}
/* ---------- PG_NAMESPACE CACHE ---------- */
/*
* get_namespace_name
* Returns the name of a given namespace
*
* Returns a palloc ' d copy of the string , or NULL if no such namespace .
*/
char *
get_namespace_name(Oid nspid)
{
HeapTuple tp;
tp = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nspid));
if (HeapTupleIsValid(tp))
{
Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp);
char *result;
result = pstrdup(NameStr(nsptup->nspname));
ReleaseSysCache(tp);
return result;
}
else
return NULL;
}
/*
* get_namespace_name_or_temp
* As above , but if it is this backend ' s temporary namespace , return
* " pg_temp " instead .
*/
char *
get_namespace_name_or_temp(Oid nspid)
{
if (isTempNamespace(nspid))
return pstrdup("pg_temp" );
else
return get_namespace_name(nspid);
}
/* ---------- PG_RANGE CACHES ---------- */
/*
* get_range_subtype
* Returns the subtype of a given range type
*
* Returns InvalidOid if the type is not a range type .
*/
Oid
get_range_subtype(Oid rangeOid)
{
HeapTuple tp;
tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
if (HeapTupleIsValid(tp))
{
Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
Oid result;
result = rngtup->rngsubtype;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
/*
* get_range_collation
* Returns the collation of a given range type
*
* Returns InvalidOid if the type is not a range type ,
* or if its subtype is not collatable .
*/
Oid
get_range_collation(Oid rangeOid)
{
HeapTuple tp;
tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
if (HeapTupleIsValid(tp))
{
Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
Oid result;
result = rngtup->rngcollation;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
/*
* get_range_multirange
* Returns the multirange type of a given range type
*
* Returns InvalidOid if the type is not a range type .
*/
Oid
get_range_multirange(Oid rangeOid)
{
HeapTuple tp;
tp = SearchSysCache1(RANGETYPE, ObjectIdGetDatum(rangeOid));
if (HeapTupleIsValid(tp))
{
Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
Oid result;
result = rngtup->rngmultitypid;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
/*
* get_multirange_range
* Returns the range type of a given multirange
*
* Returns InvalidOid if the type is not a multirange .
*/
Oid
get_multirange_range(Oid multirangeOid)
{
HeapTuple tp;
tp = SearchSysCache1(RANGEMULTIRANGE, ObjectIdGetDatum(multirangeOid));
if (HeapTupleIsValid(tp))
{
Form_pg_range rngtup = (Form_pg_range) GETSTRUCT(tp);
Oid result;
result = rngtup->rngtypid;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
/* ---------- PG_INDEX CACHE ---------- */
/*
* get_index_column_opclass
*
* Given the index OID and column number ,
* return opclass of the index column
* or InvalidOid if the index was not found
* or column is non - key one .
*/
Oid
get_index_column_opclass(Oid index_oid, int attno)
{
HeapTuple tuple;
Form_pg_index rd_index;
Datum datum;
oidvector *indclass;
Oid opclass;
/* First we need to know the column's opclass. */
tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
if (!HeapTupleIsValid(tuple))
return InvalidOid;
rd_index = (Form_pg_index) GETSTRUCT(tuple);
/* caller is supposed to guarantee this */
Assert(attno > 0 && attno <= rd_index->indnatts);
/* Non-key attributes don't have an opclass */
if (attno > rd_index->indnkeyatts)
{
ReleaseSysCache(tuple);
return InvalidOid;
}
datum = SysCacheGetAttrNotNull(INDEXRELID, tuple, Anum_pg_index_indclass);
indclass = ((oidvector *) DatumGetPointer(datum));
Assert(attno <= indclass->dim1);
opclass = indclass->values[attno - 1 ];
ReleaseSysCache(tuple);
return opclass;
}
/*
* get_index_isreplident
*
* Given the index OID , return pg_index . indisreplident .
*/
bool
get_index_isreplident(Oid index_oid)
{
HeapTuple tuple;
Form_pg_index rd_index;
bool result;
tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
if (!HeapTupleIsValid(tuple))
return false ;
rd_index = (Form_pg_index) GETSTRUCT(tuple);
result = rd_index->indisreplident;
ReleaseSysCache(tuple);
return result;
}
/*
* get_index_isvalid
*
* Given the index OID , return pg_index . indisvalid .
*/
bool
get_index_isvalid(Oid index_oid)
{
bool isvalid;
HeapTuple tuple;
Form_pg_index rd_index;
tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for index %u" , index_oid);
rd_index = (Form_pg_index) GETSTRUCT(tuple);
isvalid = rd_index->indisvalid;
ReleaseSysCache(tuple);
return isvalid;
}
/*
* get_index_isclustered
*
* Given the index OID , return pg_index . indisclustered .
*/
bool
get_index_isclustered(Oid index_oid)
{
bool isclustered;
HeapTuple tuple;
Form_pg_index rd_index;
tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for index %u" , index_oid);
rd_index = (Form_pg_index) GETSTRUCT(tuple);
isclustered = rd_index->indisclustered;
ReleaseSysCache(tuple);
return isclustered;
}
/*
* get_publication_oid - given a publication name , look up the OID
*
* If missing_ok is false , throw an error if name not found . If true , just
* return InvalidOid .
*/
Oid
get_publication_oid(const char *pubname, bool missing_ok)
{
Oid oid;
oid = GetSysCacheOid1(PUBLICATIONNAME, Anum_pg_publication_oid,
CStringGetDatum(pubname));
if (!OidIsValid(oid) && !missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("publication \" %s\" does not exist" , pubname)));
return oid;
}
/*
* get_publication_name - given a publication Oid , look up the name
*
* If missing_ok is false , throw an error if name not found . If true , just
* return NULL .
*/
char *
get_publication_name(Oid pubid, bool missing_ok)
{
HeapTuple tup;
char *pubname;
Form_pg_publication pubform;
tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
if (!HeapTupleIsValid(tup))
{
if (!missing_ok)
elog(ERROR, "cache lookup failed for publication %u" , pubid);
return NULL;
}
pubform = (Form_pg_publication) GETSTRUCT(tup);
pubname = pstrdup(NameStr(pubform->pubname));
ReleaseSysCache(tup);
return pubname;
}
/*
* get_subscription_oid - given a subscription name , look up the OID
*
* If missing_ok is false , throw an error if name not found . If true , just
* return InvalidOid .
*/
Oid
get_subscription_oid(const char *subname, bool missing_ok)
{
Oid oid;
oid = GetSysCacheOid2(SUBSCRIPTIONNAME, Anum_pg_subscription_oid,
MyDatabaseId, CStringGetDatum(subname));
if (!OidIsValid(oid) && !missing_ok)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("subscription \" %s\" does not exist" , subname)));
return oid;
}
/*
* get_subscription_name - given a subscription OID , look up the name
*
* If missing_ok is false , throw an error if name not found . If true , just
* return NULL .
*/
char *
get_subscription_name(Oid subid, bool missing_ok)
{
HeapTuple tup;
char *subname;
Form_pg_subscription subform;
tup = SearchSysCache1(SUBSCRIPTIONOID, ObjectIdGetDatum(subid));
if (!HeapTupleIsValid(tup))
{
if (!missing_ok)
elog(ERROR, "cache lookup failed for subscription %u" , subid);
return NULL;
}
subform = (Form_pg_subscription) GETSTRUCT(tup);
subname = pstrdup(NameStr(subform->subname));
ReleaseSysCache(tup);
return subname;
}
Messung V0.5 in Prozent C=96 H=95 G=95
¤ Dauer der Verarbeitung: 0.163 Sekunden
¤
*© Formatika GbR, Deutschland
2026-10-11
Neuigkeiten
Aktuelles
Motto des Tages
Open Source Software
Jenseits des Üblichen ....
Besucherstatistik
Statistik
#Sources=1127926
#Domains=2039723