mirror of https://github.com/postgres/postgres
access/heapam contains functions that are very storage specific (say heap_insert() and a lot of lower level functions), and fairly generic infrastructure like relation_open(), heap_open() etc. In the upcoming pluggable storage work we're introducing a layer between table accesses in general and heapam, to allow for different storage methods. For a bit cleaner separation it thus seems advantageous to move generic functions like the aforementioned to their own headers. access/relation.h will contain relation_open() etc, and access/table.h will contain table_open() (formerly known as heap_open()). I've decided for table.h not to include relation.h, but we might change that at a later stage. relation.h already exists in another directory, but the other plausible name (rel.h) also conflicts. It'd be nice if there were a non-conflicting name, but nobody came up with a suggestion. It's possible that the appropriate way to address the naming conflict would be to rename nodes/relation.h, which isn't particularly well named. To avoid breaking a lot of extensions that just use heap_open() etc, table.h has macros mapping the old names to the new ones, and heapam.h includes relation, table.h. That also allows to keep the bulk renaming of existing callers in a separate commit. Author: Andres Freund Discussion: https://postgr.es/m/20190111000539.xbv7s6w7ilcvm7dp@alap3.anarazel.depull/37/head
parent
f1ad067fc3
commit
4b21acf522
@ -0,0 +1,217 @@ |
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* |
||||||
|
* relation.c |
||||||
|
* Generic relation related routines. |
||||||
|
* |
||||||
|
* Portions Copyright (c) 1996-2019, 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_ACCESSEDTEMPREL; |
||||||
|
|
||||||
|
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_ACCESSEDTEMPREL; |
||||||
|
|
||||||
|
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); |
||||||
|
} |
@ -0,0 +1,17 @@ |
|||||||
|
#-------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Makefile--
|
||||||
|
# Makefile for access/table
|
||||||
|
#
|
||||||
|
# IDENTIFICATION
|
||||||
|
# src/backend/access/table/Makefile
|
||||||
|
#
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
subdir = src/backend/access/table
|
||||||
|
top_builddir = ../../../..
|
||||||
|
include $(top_builddir)/src/Makefile.global |
||||||
|
|
||||||
|
OBJS = table.o
|
||||||
|
|
||||||
|
include $(top_srcdir)/src/backend/common.mk |
@ -0,0 +1,136 @@ |
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* |
||||||
|
* table.c |
||||||
|
* Generic routines for table related code. |
||||||
|
* |
||||||
|
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
||||||
|
* Portions Copyright (c) 1994, Regents of the University of California |
||||||
|
* |
||||||
|
* |
||||||
|
* IDENTIFICATION |
||||||
|
* src/backend/access/table/table.c |
||||||
|
* |
||||||
|
* |
||||||
|
* NOTES |
||||||
|
* This file contains table_ routines that implement access to tables (in |
||||||
|
* contrast to other relation types like indexes) that are independent of |
||||||
|
* individual table access methods. |
||||||
|
* |
||||||
|
*------------------------------------------------------------------------- |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "postgres.h" |
||||||
|
|
||||||
|
#include "access/relation.h" |
||||||
|
#include "access/table.h" |
||||||
|
#include "storage/lmgr.h" |
||||||
|
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* table_open - open a table relation by relation OID |
||||||
|
* |
||||||
|
* This is essentially relation_open plus check that the relation |
||||||
|
* is not an index nor a composite type. (The caller should also |
||||||
|
* check that it's not a view or foreign table before assuming it has |
||||||
|
* storage.) |
||||||
|
* ---------------- |
||||||
|
*/ |
||||||
|
Relation |
||||||
|
table_open(Oid relationId, LOCKMODE lockmode) |
||||||
|
{ |
||||||
|
Relation r; |
||||||
|
|
||||||
|
r = relation_open(relationId, lockmode); |
||||||
|
|
||||||
|
if (r->rd_rel->relkind == RELKIND_INDEX || |
||||||
|
r->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) |
||||||
|
ereport(ERROR, |
||||||
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE), |
||||||
|
errmsg("\"%s\" is an index", |
||||||
|
RelationGetRelationName(r)))); |
||||||
|
else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE) |
||||||
|
ereport(ERROR, |
||||||
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE), |
||||||
|
errmsg("\"%s\" is a composite type", |
||||||
|
RelationGetRelationName(r)))); |
||||||
|
|
||||||
|
return r; |
||||||
|
} |
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* table_openrv - open a table relation specified |
||||||
|
* by a RangeVar node |
||||||
|
* |
||||||
|
* As above, but relation is specified by a RangeVar. |
||||||
|
* ---------------- |
||||||
|
*/ |
||||||
|
Relation |
||||||
|
table_openrv(const RangeVar *relation, LOCKMODE lockmode) |
||||||
|
{ |
||||||
|
Relation r; |
||||||
|
|
||||||
|
r = relation_openrv(relation, lockmode); |
||||||
|
|
||||||
|
if (r->rd_rel->relkind == RELKIND_INDEX || |
||||||
|
r->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) |
||||||
|
ereport(ERROR, |
||||||
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE), |
||||||
|
errmsg("\"%s\" is an index", |
||||||
|
RelationGetRelationName(r)))); |
||||||
|
else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE) |
||||||
|
ereport(ERROR, |
||||||
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE), |
||||||
|
errmsg("\"%s\" is a composite type", |
||||||
|
RelationGetRelationName(r)))); |
||||||
|
|
||||||
|
return r; |
||||||
|
} |
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* table_openrv_extended - open a table relation specified |
||||||
|
* by a RangeVar node |
||||||
|
* |
||||||
|
* As above, but optionally return NULL instead of failing for |
||||||
|
* relation-not-found. |
||||||
|
* ---------------- |
||||||
|
*/ |
||||||
|
Relation |
||||||
|
table_openrv_extended(const RangeVar *relation, LOCKMODE lockmode, |
||||||
|
bool missing_ok) |
||||||
|
{ |
||||||
|
Relation r; |
||||||
|
|
||||||
|
r = relation_openrv_extended(relation, lockmode, missing_ok); |
||||||
|
|
||||||
|
if (r) |
||||||
|
{ |
||||||
|
if (r->rd_rel->relkind == RELKIND_INDEX || |
||||||
|
r->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) |
||||||
|
ereport(ERROR, |
||||||
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE), |
||||||
|
errmsg("\"%s\" is an index", |
||||||
|
RelationGetRelationName(r)))); |
||||||
|
else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE) |
||||||
|
ereport(ERROR, |
||||||
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE), |
||||||
|
errmsg("\"%s\" is a composite type", |
||||||
|
RelationGetRelationName(r)))); |
||||||
|
} |
||||||
|
|
||||||
|
return r; |
||||||
|
} |
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* table_close - close a table |
||||||
|
* |
||||||
|
* 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 |
||||||
|
table_close(Relation relation, LOCKMODE lockmode) |
||||||
|
{ |
||||||
|
relation_close(relation, lockmode); |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* |
||||||
|
* relation.h |
||||||
|
* Generic relation related routines. |
||||||
|
* |
||||||
|
* |
||||||
|
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
||||||
|
* Portions Copyright (c) 1994, Regents of the University of California |
||||||
|
* |
||||||
|
* src/include/access/relation.h |
||||||
|
* |
||||||
|
*------------------------------------------------------------------------- |
||||||
|
*/ |
||||||
|
#ifndef ACCESS_RELATION_H |
||||||
|
#define ACCESS_RELATION_H |
||||||
|
|
||||||
|
#include "nodes/primnodes.h" |
||||||
|
#include "utils/relcache.h" |
||||||
|
#include "storage/lockdefs.h" |
||||||
|
|
||||||
|
|
||||||
|
extern Relation relation_open(Oid relationId, LOCKMODE lockmode); |
||||||
|
extern Relation try_relation_open(Oid relationId, LOCKMODE lockmode); |
||||||
|
extern Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode); |
||||||
|
extern Relation relation_openrv_extended(const RangeVar *relation, |
||||||
|
LOCKMODE lockmode, bool missing_ok); |
||||||
|
extern void relation_close(Relation relation, LOCKMODE lockmode); |
||||||
|
|
||||||
|
#endif /* ACCESS_RELATION_H */ |
@ -0,0 +1,38 @@ |
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* |
||||||
|
* table.h |
||||||
|
* Generic routines for table related code. |
||||||
|
* |
||||||
|
* |
||||||
|
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
||||||
|
* Portions Copyright (c) 1994, Regents of the University of California |
||||||
|
* |
||||||
|
* src/include/access/table.h |
||||||
|
* |
||||||
|
*------------------------------------------------------------------------- |
||||||
|
*/ |
||||||
|
#ifndef TABLE_H |
||||||
|
#define TABLE_H |
||||||
|
|
||||||
|
#include "nodes/primnodes.h" |
||||||
|
#include "utils/relcache.h" |
||||||
|
#include "storage/lockdefs.h" |
||||||
|
|
||||||
|
|
||||||
|
extern Relation table_open(Oid relationId, LOCKMODE lockmode); |
||||||
|
extern Relation table_openrv(const RangeVar *relation, LOCKMODE lockmode); |
||||||
|
extern Relation table_openrv_extended(const RangeVar *relation, |
||||||
|
LOCKMODE lockmode, bool missing_ok); |
||||||
|
extern void table_close(Relation relation, LOCKMODE lockmode); |
||||||
|
|
||||||
|
/*
|
||||||
|
* heap_ used to be the prefix for these routines, and a lot of code will just |
||||||
|
* continue to work without adaptions after the introduction of pluggable |
||||||
|
* storage, therefore just map these names. |
||||||
|
*/ |
||||||
|
#define heap_open(r, l) table_open(r, l) |
||||||
|
#define heap_openrv(r, l) table_openrv(r, l) |
||||||
|
#define heap_openrv_extended(r, l, m) table_openrv_extended(r, l, m) |
||||||
|
#define heap_close(r, l) table_close(r, l) |
||||||
|
|
||||||
|
#endif /* TABLE_H */ |
Loading…
Reference in new issue