Newer
Older
/*-------------------------------------------------------------------------
*
* lsyscache.c
* Convenience routines for common queries in the system catalog cache.
* Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
* src/backend/utils/cache/lsyscache.c
* Eventually, the index information should go through here, too.
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/hash.h"
#include "access/nbtree.h"
#include "bootstrap/bootstrap.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_proc.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/syscache.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.
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.
*/
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_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.)
*
* 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, int16 *strategy)
{
bool result = false;
CatCList *catlist;
int i;
/* ensure outputs are initialized on failure */
*opfamily = InvalidOid;
*opcintype = InvalidOid;
*strategy = 0;
/*
* 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);
/* must be btree */
if (aform->amopmethod != BTREE_AM_OID)
continue;
if (aform->amopstrategy == BTLessStrategyNumber ||
aform->amopstrategy == BTGreaterStrategyNumber)
{
/* Found it ... should have consistent input types */
if (aform->amoplefttype == aform->amoprighttype)
{
/* Found a suitable opfamily, return info */
*opfamily = aform->amopfamily;
*opcintype = aform->amoplefttype;
*strategy = aform->amopstrategy;
result = true;
break;
}
}
}
ReleaseSysCacheList(catlist);
return result;
}
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
/*
* get_compare_function_for_ordering_op
* Get the OID of the datatype-specific btree comparison function
* associated with an ordering operator (a "<" or ">" operator).
*
* *cmpfunc receives the comparison function OID.
* *reverse is set FALSE if the operator is "<", TRUE if it's ">"
* (indicating the comparison result must be negated before use).
*
* Returns TRUE if successful, FALSE if no btree function can be found.
* (This indicates that the operator is not a valid ordering operator.)
*/
bool
get_compare_function_for_ordering_op(Oid opno, Oid *cmpfunc, bool *reverse)
{
Oid opfamily;
Oid opcintype;
int16 strategy;
/* Find the operator in pg_amop */
if (get_ordering_op_properties(opno,
&opfamily, &opcintype, &strategy))
{
/* Found a suitable opfamily, get matching support function */
*cmpfunc = get_opfamily_proc(opfamily,
opcintype,
opcintype,
BTORDER_PROC);
if (!OidIsValid(*cmpfunc)) /* should not happen */
elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
BTORDER_PROC, opcintype, opcintype, opfamily);
*reverse = (strategy == BTGreaterStrategyNumber);
return true;
}
/* ensure outputs are set on failure */
*cmpfunc = InvalidOid;
*reverse = false;
return false;
}
/*
* get_equality_op_for_ordering_op
* 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, bool *reverse)
{
Oid result = InvalidOid;
Oid opfamily;
Oid opcintype;
int16 strategy;
/* Find the operator in pg_amop */
if (get_ordering_op_properties(opno,
&opfamily, &opcintype, &strategy))
/* Found a suitable opfamily, get matching equality operator */
result = get_opfamily_member(opfamily,
opcintype,
opcintype,
BTEqualStrategyNumber);
if (reverse)
*reverse = (strategy == BTGreaterStrategyNumber);
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
}
return result;
}
/*
* get_ordering_op_for_equality_op
* Get the OID of a datatype-specific btree ordering operator
* associated with an equality operator. (If there are multiple
* possibilities, assume any one will do.)
*
* This function is used when we have to sort data before unique-ifying,
* and don't much care which sorting op is used as long as it's compatible
* with the intended equality operator. Since we need a sorting operator,
* it should be single-data-type even if the given operator is cross-type.
* The caller specifies whether to find an op for the LHS or RHS data type.
*
* Returns InvalidOid if no matching ordering operator can be found.
*/
Oid
get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type)
{
Oid result = InvalidOid;
CatCList *catlist;
int i;
/*
* Search pg_amop to see if the target operator is registered as the "="
* operator of any btree opfamily.
*/
catlist = 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 */
if (aform->amopmethod != BTREE_AM_OID)
continue;
if (aform->amopstrategy == BTEqualStrategyNumber)
{
/* Found a suitable opfamily, get matching ordering operator */
typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
result = get_opfamily_member(aform->amopfamily,
typid, typid,
BTLessStrategyNumber);
if (OidIsValid(result))
break;
/* failure probably shouldn't happen, but keep looking if so */
}
}
ReleaseSysCacheList(catlist);
return result;
}
/*
* get_mergejoin_opfamilies
* Given a putatively mergejoinable operator, return a list of the OIDs
* of the btree 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 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 = 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;
}
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
/*
* 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 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)
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
/*
* 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;
}
}
}
ReleaseSysCacheList(catlist);
return result;
/*
* 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.
*
* 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)
{
CatCList *catlist;
bool op_negated;
int i;
*opfamilies = NIL;
*opstrats = NIL;
/*
* Find all the pg_amop entries containing the operator.
*/
catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
* 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)
{
if (OidIsValid(op_negator))
{
op_negated = true;
ReleaseSysCacheList(catlist);
ObjectIdGetDatum(op_negator));
}
}
/* 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 */
if (op_form->amopmethod != BTREE_AM_OID)
continue;
/* Get the operator's btree strategy number */
opfamily_id = op_form->amopfamily;
op_strategy = (StrategyNumber) op_form->amopstrategy;
Assert(op_strategy >= 1 && op_strategy <= 5);
if (op_negated)
{
/* Only consider negators that are = */
if (op_strategy != BTEqualStrategyNumber)
continue;
op_strategy = ROWCOMPARE_NE;
}
*opfamilies = lappend_oid(*opfamilies, opfamily_id);
*opstrats = lappend_int(*opstrats, op_strategy);
}
ReleaseSysCacheList(catlist);
}
* 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
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);
/* must be btree or hash */
if (op_form->amopmethod == BTREE_AM_OID ||
op_form->amopmethod == HASH_AM_OID)
if (op_in_opfamily(opno2, op_form->amopfamily))
{
result = true;
break;
}
}
}
ReleaseSysCacheList(catlist);
return result;
}
/* ---------- 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.
* Note: returns a palloc'd copy of the string, or NULL if no such attribute.
get_attname(Oid relid, AttrNumber attnum)
{
tp = SearchSysCache2(ATTNUM,
ObjectIdGetDatum(relid),
Int16GetDatum(attnum));
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
result = pstrdup(NameStr(att_tup->attname));
ReleaseSysCache(tp);
return result;
/*
* get_relid_attribute_name
*
* Same as above routine get_attname(), except that error
* is handled by elog() instead of returning NULL.
*/
char *
get_relid_attribute_name(Oid relid, AttrNumber attnum)
{
char *attname;
attname = get_attname(relid, attnum);
if (attname == NULL)
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
attnum, relid);
return attname;
}
* get_attnum
*
* Given the relation id and the attribute name,
* return the "attnum" field from the attribute relation.
*
* Returns InvalidAttrNumber if the attr doesn't exist (or is dropped).
get_attnum(Oid relid, const char *attname)
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;
* 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)
{
tp = SearchSysCache2(ATTNUM,
ObjectIdGetDatum(relid),
Int16GetDatum(attnum));
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
result = att_tup->atttypid;
ReleaseSysCache(tp);
return result;
return InvalidOid;
* get_atttypmod
*
* Given the relation id and the attribute number,
* return the "atttypmod" field from the attribute relation.
*/
tp = SearchSysCache2(ATTNUM,
ObjectIdGetDatum(relid),
Int16GetDatum(attnum));
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
result = att_tup->atttypmod;
ReleaseSysCache(tp);
return result;
* 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/get_atttypmod, 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);
}
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
/* ---------- 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 ---------- */
/*
* 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 ---------- */
/*
* get_opclass_family