Newer
Older
/*-------------------------------------------------------------------------
*
* lsyscache.c
* Convenience routines for common queries in the system catalog cache.
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.105 2003/08/04 02:40:06 momjian Exp $
* Eventually, the index information should go through here, too.
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "miscadmin.h"
#include "access/hash.h"
#include "access/tupmacs.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_shadow.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/catcache.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
/* ---------- AMOP CACHES ---------- */
* op_in_opclass
* Return t iff operator 'opno' is in operator class 'opclass'.
op_in_opclass(Oid opno, Oid opclass)
return SearchSysCacheExists(AMOPOPID,
ObjectIdGetDatum(opno),
ObjectIdGetDatum(opclass),
0, 0);
}
/*
* op_requires_recheck
*
* Return t if operator 'opno' requires a recheck when used as a
* member of opclass 'opclass' (ie, this opclass is lossy for this
* operator).
*
* Caller should already have verified that opno is a member of opclass,
* therefore we raise an error if the tuple is not found.
*/
bool
op_requires_recheck(Oid opno, Oid opclass)
{
HeapTuple tp;
Form_pg_amop amop_tup;
bool result;
tp = SearchSysCache(AMOPOPID,
ObjectIdGetDatum(opno),
ObjectIdGetDatum(opclass),
0, 0);
if (!HeapTupleIsValid(tp))
elog(ERROR, "operator %u is not a member of opclass %u",
opno, opclass);
amop_tup = (Form_pg_amop) GETSTRUCT(tp);
result = amop_tup->amopreqcheck;
ReleaseSysCache(tp);
return result;
/*
* get_opclass_member
* Get the OID of the operator that implements the specified strategy
* for the specified opclass.
*
* Returns InvalidOid if there is no pg_amop entry for the given keys.
*/
Oid
get_opclass_member(Oid opclass, int16 strategy)
{
HeapTuple tp;
Form_pg_amop amop_tup;
Oid result;
tp = SearchSysCache(AMOPSTRATEGY,
ObjectIdGetDatum(opclass),
Int16GetDatum(strategy),
0, 0);
if (!HeapTupleIsValid(tp))
return InvalidOid;
amop_tup = (Form_pg_amop) GETSTRUCT(tp);
result = amop_tup->amopopr;
ReleaseSysCache(tp);
return result;
}
/*
* get_op_hash_function
* Get the OID of the datatype-specific hash function associated with
* a hashable equality operator.
*
* Returns InvalidOid if no hash function can be found. (This indicates
* that the operator should not have been marked oprcanhash.)
*/
Oid
get_op_hash_function(Oid opno)
{
CatCList *catlist;
int i;
HeapTuple tuple;
Oid opclass = InvalidOid;
/*
* Search pg_amop to see if the target operator is registered as the
* "=" operator of any hash opclass. If the operator is registered in
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
* multiple opclasses, assume we can use the associated hash function
* from any one.
*/
catlist = SearchSysCacheList(AMOPOPID, 1,
ObjectIdGetDatum(opno),
0, 0, 0);
for (i = 0; i < catlist->n_members; i++)
{
Form_pg_amop aform;
tuple = &catlist->members[i]->tuple;
aform = (Form_pg_amop) GETSTRUCT(tuple);
if (aform->amopstrategy == HTEqualStrategyNumber &&
opclass_is_hash(aform->amopclaid))
{
opclass = aform->amopclaid;
break;
}
}
ReleaseSysCacheList(catlist);
if (OidIsValid(opclass))
{
/* Found a suitable opclass, get its hash support function */
tuple = SearchSysCache(AMPROCNUM,
ObjectIdGetDatum(opclass),
Int16GetDatum(HASHPROC),
0, 0);
if (HeapTupleIsValid(tuple))
{
Form_pg_amproc aform = (Form_pg_amproc) GETSTRUCT(tuple);
RegProcedure result;
result = aform->amproc;
ReleaseSysCache(tuple);
Assert(RegProcedureIsValid(result));
return result;
}
}
/* Didn't find a match... */
return InvalidOid;
}
/* ---------- 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 operator.
get_attname(Oid relid, AttrNumber attnum)
{
tp = SearchSysCache(ATTNUM,
ObjectIdGetDatum(relid),
Int16GetDatum(attnum),
0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
result = pstrdup(NameStr(att_tup->attname));
ReleaseSysCache(tp);
return result;
* 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 = SearchSysCache(ATTNUM,
ObjectIdGetDatum(relid),
Int16GetDatum(attnum),
0, 0);
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 = SearchSysCache(ATTNUM,
ObjectIdGetDatum(relid),
Int16GetDatum(attnum),
0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
result = att_tup->atttypmod;
ReleaseSysCache(tp);
return result;
/*
* get_atttypetypmod
*
* A two-fer: given the relation id and the attribute number,
* fetch both type OID and atttypmod in a single cache lookup.
*
* Unlike the otherwise-similar get_atttype/get_atttypmod, this routine
* raises an error if it can't obtain the information.
*/
void
get_atttypetypmod(Oid relid, AttrNumber attnum,
Oid *typid, int32 *typmod)
{
HeapTuple tp;
Form_pg_attribute att_tup;
tp = SearchSysCache(ATTNUM,
ObjectIdGetDatum(relid),
Int16GetDatum(attnum),
0, 0);
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
attnum, relid);
att_tup = (Form_pg_attribute) GETSTRUCT(tp);
*typid = att_tup->atttypid;
*typmod = att_tup->atttypmod;
ReleaseSysCache(tp);
}
/* ---------- INDEX CACHE ---------- */
/* watch this space...
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
/* ---------- OPCLASS CACHE ---------- */
/*
* opclass_is_btree
*
* Returns TRUE iff the specified opclass is associated with the
* btree index access method.
*/
bool
opclass_is_btree(Oid opclass)
{
HeapTuple tp;
Form_pg_opclass cla_tup;
bool result;
tp = SearchSysCache(CLAOID,
ObjectIdGetDatum(opclass),
0, 0, 0);
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for opclass %u", opclass);
cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
result = (cla_tup->opcamid == BTREE_AM_OID);
ReleaseSysCache(tp);
return result;
}
/*
* opclass_is_hash
*
* Returns TRUE iff the specified opclass is associated with the
* hash index access method.
*/
bool
opclass_is_hash(Oid opclass)
{
HeapTuple tp;
Form_pg_opclass cla_tup;
bool result;
tp = SearchSysCache(CLAOID,
ObjectIdGetDatum(opclass),
0, 0, 0);
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for opclass %u", opclass);
cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
result = (cla_tup->opcamid == HASH_AM_OID);
ReleaseSysCache(tp);
return result;
}
/* ---------- 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)
{
tp = SearchSysCache(OPEROID,
ObjectIdGetDatum(opno),
0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
result = optup->oprcode;
ReleaseSysCache(tp);
return result;
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.
get_opname(Oid opno)
{
tp = SearchSysCache(OPEROID,
ObjectIdGetDatum(opno),
0, 0, 0);
if (HeapTupleIsValid(tp))
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
result = pstrdup(NameStr(optup->oprname));
ReleaseSysCache(tp);
return result;
else
return NULL;
* op_mergejoinable
* Returns the left and right sort operators corresponding to a
* mergejoinable operator, or false if the operator is not mergejoinable.
op_mergejoinable(Oid opno, Oid *leftOp, Oid *rightOp)
bool result = false;
tp = SearchSysCache(OPEROID,
ObjectIdGetDatum(opno),
0, 0, 0);
if (HeapTupleIsValid(tp))
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
if (optup->oprlsortop &&
optup->oprrsortop)
*leftOp = optup->oprlsortop;
*rightOp = optup->oprrsortop;
result = true;
ReleaseSysCache(tp);
return result;
/*
* op_mergejoin_crossops
*
* Returns the cross-type comparison operators (ltype "<" rtype and
* ltype ">" rtype) for an operator previously determined to be
* mergejoinable. Optionally, fetches the regproc ids of these
* operators, as well as their operator OIDs.
*/
void
op_mergejoin_crossops(Oid opno, Oid *ltop, Oid *gtop,
RegProcedure *ltproc, RegProcedure *gtproc)
{
HeapTuple tp;
Form_pg_operator optup;
/*
* Get the declared comparison operators of the operator.
*/
tp = SearchSysCache(OPEROID,
ObjectIdGetDatum(opno),
0, 0, 0);
if (!HeapTupleIsValid(tp)) /* shouldn't happen */
elog(ERROR, "cache lookup failed for operator %u", opno);
optup = (Form_pg_operator) GETSTRUCT(tp);
*ltop = optup->oprltcmpop;
*gtop = optup->oprgtcmpop;
ReleaseSysCache(tp);
/* Check < op provided */
if (!OidIsValid(*ltop))
elog(ERROR, "mergejoin operator %u has no matching < operator",
opno);
if (ltproc)
*ltproc = get_opcode(*ltop);
/* Check > op provided */
if (!OidIsValid(*gtop))
elog(ERROR, "mergejoin operator %u has no matching > operator",
opno);
if (gtproc)
*gtproc = get_opcode(*gtop);
* op_hashjoinable
* Returns true if the operator is hashjoinable.
bool
op_hashjoinable(Oid opno)
bool result = false;
tp = SearchSysCache(OPEROID,
ObjectIdGetDatum(opno),
0, 0, 0);
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)
{
tp = SearchSysCache(OPEROID,
ObjectIdGetDatum(opno),
0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
result = optup->oprcom;
ReleaseSysCache(tp);
return result;
return InvalidOid;
* get_negator
*
* Returns the corresponding negator of an operator.
*/
Oid
get_negator(Oid opno)
{
tp = SearchSysCache(OPEROID,
ObjectIdGetDatum(opno),
0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
result = optup->oprnegate;
ReleaseSysCache(tp);
return result;
return InvalidOid;
* get_oprrest
*
* Returns procedure id for computing selectivity of an operator.
*/
RegProcedure
get_oprrest(Oid opno)
{
tp = SearchSysCache(OPEROID,
ObjectIdGetDatum(opno),
0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
result = optup->oprrest;
ReleaseSysCache(tp);
return result;
return (RegProcedure) InvalidOid;
* get_oprjoin
*
* Returns procedure id for computing selectivity of a join.
*/
RegProcedure
get_oprjoin(Oid opno)
{
tp = SearchSysCache(OPEROID,
ObjectIdGetDatum(opno),
0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_operator optup = (Form_pg_operator) GETSTRUCT(tp);
result = optup->oprjoin;
ReleaseSysCache(tp);
return result;
return (RegProcedure) InvalidOid;
/* ---------- FUNCTION CACHE ---------- */
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
/*
* 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 = SearchSysCache(PROCOID,
ObjectIdGetDatum(funcid),
0, 0, 0);
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_rettype
* Given procedure id, return the function's result type.
*/
Oid
get_func_rettype(Oid funcid)
{
HeapTuple tp;
Oid result;
tp = SearchSysCache(PROCOID,
ObjectIdGetDatum(funcid),
0, 0, 0);
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u", funcid);
result = ((Form_pg_proc) GETSTRUCT(tp))->prorettype;
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.)
*
* argtypes must point to a vector of size FUNC_MAX_ARGS.
*/
Oid
get_func_signature(Oid funcid, Oid *argtypes, int *nargs)
{
Oid result;
tp = SearchSysCache(PROCOID,
ObjectIdGetDatum(funcid),
0, 0, 0);
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u", funcid);
procstruct = (Form_pg_proc) GETSTRUCT(tp);
result = procstruct->prorettype;
memcpy(argtypes, procstruct->proargtypes, FUNC_MAX_ARGS * sizeof(Oid));
*nargs = (int) procstruct->pronargs;
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 = SearchSysCache(PROCOID,
ObjectIdGetDatum(funcid),
0, 0, 0);
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 = SearchSysCache(PROCOID,
ObjectIdGetDatum(funcid),
0, 0, 0);
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 = SearchSysCache(PROCOID,
ObjectIdGetDatum(funcid),
0, 0, 0);
if (!HeapTupleIsValid(tp))
elog(ERROR, "cache lookup failed for function %u", funcid);
result = ((Form_pg_proc) GETSTRUCT(tp))->provolatile;
ReleaseSysCache(tp);
return result;
/* ---------- 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 GetSysCacheOid(RELNAMENSP,
PointerGetDatum(relname),
ObjectIdGetDatum(relnamespace),
0, 0);
}
/*
* get_system_catalog_relid
* Get the OID of a system catalog identified by name.
*/
Oid
get_system_catalog_relid(const char *catname)
{
relid = GetSysCacheOid(RELNAMENSP,
PointerGetDatum(catname),
ObjectIdGetDatum(PG_CATALOG_NAMESPACE),
0, 0);
if (!OidIsValid(relid))
elog(ERROR, "cache lookup failed for system relation %s", catname);
return relid;
}
#ifdef NOT_USED
* get_relnatts
*
* Returns the number of attributes for a given relation.
*/
int
get_relnatts(Oid relid)
{
tp = SearchSysCache(RELOID,
ObjectIdGetDatum(relid),
0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
result = reltup->relnatts;
ReleaseSysCache(tp);
return result;
* 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.
get_rel_name(Oid relid)
{
tp = SearchSysCache(RELOID,
ObjectIdGetDatum(relid),
0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
result = pstrdup(NameStr(reltup->relname));
ReleaseSysCache(tp);
return result;
/*
* get_rel_namespace
*
* Returns the pg_namespace OID associated with a given relation.
*/
Oid
get_rel_namespace(Oid relid)
{
HeapTuple tp;
tp = SearchSysCache(RELOID,
ObjectIdGetDatum(relid),
0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
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 = SearchSysCache(RELOID,
ObjectIdGetDatum(relid),
0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
result = reltup->reltype;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
/*
* get_rel_relkind
*
* Returns the relkind associated with a given relation.
*/
char
get_rel_relkind(Oid relid)
{
HeapTuple tp;
tp = SearchSysCache(RELOID,
ObjectIdGetDatum(relid),
0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
char result;
result = reltup->relkind;
ReleaseSysCache(tp);
return result;
}
else
return '\0';
}
/* ---------- TYPE CACHE ---------- */