218 lines
6.1 KiB
C
218 lines
6.1 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* relation.c
|
|
* Generic relation related routines.
|
|
*
|
|
* Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
*
|
|
* IDENTIFICATION
|
|
* src/backend/access/common/relation.c
|
|
*
|
|
* NOTES
|
|
* This file contains relation_ routines that implement access to relations
|
|
* (tables, indexes, etc). Support that's specific to subtypes of relations
|
|
* should go into their respective files, not here.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
#include "access/relation.h"
|
|
#include "access/xact.h"
|
|
#include "catalog/namespace.h"
|
|
#include "miscadmin.h"
|
|
#include "pgstat.h"
|
|
#include "storage/lmgr.h"
|
|
#include "utils/inval.h"
|
|
#include "utils/syscache.h"
|
|
|
|
|
|
/* ----------------
|
|
* relation_open - open any relation by relation OID
|
|
*
|
|
* If lockmode is not "NoLock", the specified kind of lock is
|
|
* obtained on the relation. (Generally, NoLock should only be
|
|
* used if the caller knows it has some appropriate lock on the
|
|
* relation already.)
|
|
*
|
|
* An error is raised if the relation does not exist.
|
|
*
|
|
* NB: a "relation" is anything with a pg_class entry. The caller is
|
|
* expected to check whether the relkind is something it can handle.
|
|
* ----------------
|
|
*/
|
|
Relation
|
|
relation_open(Oid relationId, LOCKMODE lockmode)
|
|
{
|
|
Relation r;
|
|
|
|
Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
|
|
|
|
/* Get the lock before trying to open the relcache entry */
|
|
if (lockmode != NoLock)
|
|
LockRelationOid(relationId, lockmode);
|
|
|
|
/* The relcache does all the real work... */
|
|
r = RelationIdGetRelation(relationId);
|
|
|
|
if (!RelationIsValid(r))
|
|
elog(ERROR, "could not open relation with OID %u", relationId);
|
|
|
|
/*
|
|
* If we didn't get the lock ourselves, assert that caller holds one,
|
|
* except in bootstrap mode where no locks are used.
|
|
*/
|
|
Assert(lockmode != NoLock ||
|
|
IsBootstrapProcessingMode() ||
|
|
CheckRelationLockedByMe(r, AccessShareLock, true));
|
|
|
|
/* Make note that we've accessed a temporary relation */
|
|
if (RelationUsesLocalBuffers(r))
|
|
MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
|
|
|
|
pgstat_initstats(r);
|
|
|
|
return r;
|
|
}
|
|
|
|
/* ----------------
|
|
* try_relation_open - open any relation by relation OID
|
|
*
|
|
* Same as relation_open, except return NULL instead of failing
|
|
* if the relation does not exist.
|
|
* ----------------
|
|
*/
|
|
Relation
|
|
try_relation_open(Oid relationId, LOCKMODE lockmode)
|
|
{
|
|
Relation r;
|
|
|
|
Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
|
|
|
|
/* Get the lock first */
|
|
if (lockmode != NoLock)
|
|
LockRelationOid(relationId, lockmode);
|
|
|
|
/*
|
|
* Now that we have the lock, probe to see if the relation really exists
|
|
* or not.
|
|
*/
|
|
if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(relationId)))
|
|
{
|
|
/* Release useless lock */
|
|
if (lockmode != NoLock)
|
|
UnlockRelationOid(relationId, lockmode);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* Should be safe to do a relcache load */
|
|
r = RelationIdGetRelation(relationId);
|
|
|
|
if (!RelationIsValid(r))
|
|
elog(ERROR, "could not open relation with OID %u", relationId);
|
|
|
|
/* If we didn't get the lock ourselves, assert that caller holds one */
|
|
Assert(lockmode != NoLock ||
|
|
CheckRelationLockedByMe(r, AccessShareLock, true));
|
|
|
|
/* Make note that we've accessed a temporary relation */
|
|
if (RelationUsesLocalBuffers(r))
|
|
MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
|
|
|
|
pgstat_initstats(r);
|
|
|
|
return r;
|
|
}
|
|
|
|
/* ----------------
|
|
* relation_openrv - open any relation specified by a RangeVar
|
|
*
|
|
* Same as relation_open, but the relation is specified by a RangeVar.
|
|
* ----------------
|
|
*/
|
|
Relation
|
|
relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
|
|
{
|
|
Oid relOid;
|
|
|
|
/*
|
|
* Check for shared-cache-inval messages before trying to open the
|
|
* relation. This is needed even if we already hold a lock on the
|
|
* relation, because GRANT/REVOKE are executed without taking any lock on
|
|
* the target relation, and we want to be sure we see current ACL
|
|
* information. We can skip this if asked for NoLock, on the assumption
|
|
* that such a call is not the first one in the current command, and so we
|
|
* should be reasonably up-to-date already. (XXX this all could stand to
|
|
* be redesigned, but for the moment we'll keep doing this like it's been
|
|
* done historically.)
|
|
*/
|
|
if (lockmode != NoLock)
|
|
AcceptInvalidationMessages();
|
|
|
|
/* Look up and lock the appropriate relation using namespace search */
|
|
relOid = RangeVarGetRelid(relation, lockmode, false);
|
|
|
|
/* Let relation_open do the rest */
|
|
return relation_open(relOid, NoLock);
|
|
}
|
|
|
|
/* ----------------
|
|
* relation_openrv_extended - open any relation specified by a RangeVar
|
|
*
|
|
* Same as relation_openrv, but with an additional missing_ok argument
|
|
* allowing a NULL return rather than an error if the relation is not
|
|
* found. (Note that some other causes, such as permissions problems,
|
|
* will still result in an ereport.)
|
|
* ----------------
|
|
*/
|
|
Relation
|
|
relation_openrv_extended(const RangeVar *relation, LOCKMODE lockmode,
|
|
bool missing_ok)
|
|
{
|
|
Oid relOid;
|
|
|
|
/*
|
|
* Check for shared-cache-inval messages before trying to open the
|
|
* relation. See comments in relation_openrv().
|
|
*/
|
|
if (lockmode != NoLock)
|
|
AcceptInvalidationMessages();
|
|
|
|
/* Look up and lock the appropriate relation using namespace search */
|
|
relOid = RangeVarGetRelid(relation, lockmode, missing_ok);
|
|
|
|
/* Return NULL on not-found */
|
|
if (!OidIsValid(relOid))
|
|
return NULL;
|
|
|
|
/* Let relation_open do the rest */
|
|
return relation_open(relOid, NoLock);
|
|
}
|
|
|
|
/* ----------------
|
|
* relation_close - close any relation
|
|
*
|
|
* If lockmode is not "NoLock", we then release the specified lock.
|
|
*
|
|
* Note that it is often sensible to hold a lock beyond relation_close;
|
|
* in that case, the lock is released automatically at xact end.
|
|
* ----------------
|
|
*/
|
|
void
|
|
relation_close(Relation relation, LOCKMODE lockmode)
|
|
{
|
|
LockRelId relid = relation->rd_lockInfo.lockRelId;
|
|
|
|
Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
|
|
|
|
/* The relcache does the real work... */
|
|
RelationClose(relation);
|
|
|
|
if (lockmode != NoLock)
|
|
UnlockRelationId(&relid, lockmode);
|
|
}
|