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.108 2003/10/04 18:22:59 tgl 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;
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
* 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++)
{
HeapTuple tuple = &catlist->members[i]->tuple;
Form_pg_amop 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 */
return get_opclass_proc(opclass, HASHPROC);
}
/* Didn't find a match... */
return InvalidOid;
}
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/* ---------- AMPROC CACHES ---------- */
/*
* get_opclass_proc
* Get the OID of the specified support function
* for the specified opclass.
*
* Returns InvalidOid if there is no pg_amproc entry for the given keys.
*/
Oid
get_opclass_proc(Oid opclass, int16 procnum)
{
HeapTuple tp;
Form_pg_amproc amproc_tup;
RegProcedure result;
tp = SearchSysCache(AMPROCNUM,
ObjectIdGetDatum(opclass),
Int16GetDatum(procnum),
0, 0);
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 = 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_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 = 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...
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
/* ---------- 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 ---------- */
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
/*
* 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;
}