diff options
author | Andres Freund <andres@anarazel.de> | 2019-03-06 09:54:38 -0800 |
---|---|---|
committer | Andres Freund <andres@anarazel.de> | 2019-03-06 09:54:38 -0800 |
commit | 8586bf7ed8889f39a59dd99b292014b73be85342 (patch) | |
tree | 95910aef0fd4f0d271e31e03ba717184166f7c3d /src/backend/utils/cache/relcache.c | |
parent | f21776185648537a7bb82dfdf89991fb2e0b9ca5 (diff) | |
download | postgresql-8586bf7ed8889f39a59dd99b292014b73be85342.tar.gz postgresql-8586bf7ed8889f39a59dd99b292014b73be85342.zip |
tableam: introduce table AM infrastructure.
This introduces the concept of table access methods, i.e. CREATE
ACCESS METHOD ... TYPE TABLE and
CREATE TABLE ... USING (storage-engine).
No table access functionality is delegated to table AMs as of this
commit, that'll be done in following commits.
Subsequent commits will incrementally abstract table access
functionality to be routed through table access methods. That change
is too large to be reviewed & committed at once, so it'll be done
incrementally.
Docs will be updated at the end, as adding them incrementally would
likely make them less coherent, and definitely is a lot more work,
without a lot of benefit.
Table access methods are specified similar to index access methods,
i.e. pg_am.amhandler returns, as INTERNAL, a pointer to a struct with
callbacks. In contrast to index AMs that struct needs to live as long
as a backend, typically that's achieved by just returning a pointer to
a constant struct.
Psql's \d+ now displays a table's access method. That can be disabled
with HIDE_TABLEAM=true, which is mainly useful so regression tests can
be run against different AMs. It's quite possible that this behaviour
still needs to be fine tuned.
For now it's not allowed to set a table AM for a partitioned table, as
we've not resolved how partitions would inherit that. Disallowing
allows us to introduce, if we decide that's the way forward, such a
behaviour without a compatibility break.
Catversion bumped, to add the heap table AM and references to it.
Author: Haribabu Kommi, Andres Freund, Alvaro Herrera, Dimitri Golgov and others
Discussion:
https://postgr.es/m/20180703070645.wchpu5muyto5n647@alap3.anarazel.de
https://postgr.es/m/20160812231527.GA690404@alvherre.pgsql
https://postgr.es/m/20190107235616.6lur25ph22u5u5av@alap3.anarazel.de
https://postgr.es/m/20190304234700.w5tmhducs5wxgzls@alap3.anarazel.de
Diffstat (limited to 'src/backend/utils/cache/relcache.c')
-rw-r--r-- | src/backend/utils/cache/relcache.c | 123 |
1 files changed, 120 insertions, 3 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 54a40ef00bd..0b0508c01d8 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -37,6 +37,7 @@ #include "access/reloptions.h" #include "access/sysattr.h" #include "access/table.h" +#include "access/tableam.h" #include "access/tupdesc_details.h" #include "access/xact.h" #include "access/xlog.h" @@ -1137,10 +1138,32 @@ RelationBuildDesc(Oid targetRelId, bool insertIt) } /* - * if it's an index, initialize index-related information + * initialize access method information */ - if (OidIsValid(relation->rd_rel->relam)) - RelationInitIndexAccessInfo(relation); + switch (relation->rd_rel->relkind) + { + case RELKIND_INDEX: + case RELKIND_PARTITIONED_INDEX: + Assert(relation->rd_rel->relam != InvalidOid); + RelationInitIndexAccessInfo(relation); + break; + case RELKIND_RELATION: + case RELKIND_TOASTVALUE: + case RELKIND_MATVIEW: + Assert(relation->rd_rel->relam != InvalidOid); + RelationInitTableAccessMethod(relation); + break; + case RELKIND_SEQUENCE: + Assert(relation->rd_rel->relam == InvalidOid); + RelationInitTableAccessMethod(relation); + break; + case RELKIND_VIEW: + case RELKIND_COMPOSITE_TYPE: + case RELKIND_FOREIGN_TABLE: + case RELKIND_PARTITIONED_TABLE: + Assert(relation->rd_rel->relam == InvalidOid); + break; + } /* extract reloptions if any */ RelationParseRelOptions(relation, pg_class_tuple); @@ -1646,6 +1669,65 @@ LookupOpclassInfo(Oid operatorClassOid, return opcentry; } +/* + * Fill in the TableAmRoutine for a relation + * + * relation's rd_amhandler must be valid already. + */ +static void +InitTableAmRoutine(Relation relation) +{ + relation->rd_tableam = GetTableAmRoutine(relation->rd_amhandler); +} + +/* + * Initialize table access method support for a table like relation relation + */ +void +RelationInitTableAccessMethod(Relation relation) +{ + HeapTuple tuple; + Form_pg_am aform; + + if (relation->rd_rel->relkind == RELKIND_SEQUENCE) + { + /* + * Sequences are currently accessed like heap tables, but it doesn't + * seem prudent to show that in the catalog. So just overwrite it + * here. + */ + relation->rd_amhandler = HEAP_TABLE_AM_HANDLER_OID; + } + else if (IsCatalogRelation(relation)) + { + /* + * Avoid doing a syscache lookup for catalog tables. + */ + Assert(relation->rd_rel->relam == HEAP_TABLE_AM_OID); + relation->rd_amhandler = HEAP_TABLE_AM_HANDLER_OID; + } + else + { + /* + * Look up the table access method, save the OID of its handler + * function. + */ + Assert(relation->rd_rel->relam != InvalidOid); + tuple = SearchSysCache1(AMOID, + ObjectIdGetDatum(relation->rd_rel->relam)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for access method %u", + relation->rd_rel->relam); + aform = (Form_pg_am) GETSTRUCT(tuple); + relation->rd_amhandler = aform->amhandler; + ReleaseSysCache(tuple); + } + + /* + * Now we can fetch the table AM's API struct + */ + InitTableAmRoutine(relation); +} /* * formrdesc @@ -1732,6 +1814,7 @@ formrdesc(const char *relationName, Oid relationReltype, relation->rd_rel->relallvisible = 0; relation->rd_rel->relkind = RELKIND_RELATION; relation->rd_rel->relnatts = (int16) natts; + relation->rd_rel->relam = HEAP_TABLE_AM_OID; /* * initialize attribute tuple form @@ -1800,6 +1883,12 @@ formrdesc(const char *relationName, Oid relationReltype, RelationInitPhysicalAddr(relation); /* + * initialize the table am handler + */ + relation->rd_rel->relam = HEAP_TABLE_AM_OID; + relation->rd_tableam = GetHeapamTableAmRoutine(); + + /* * initialize the rel-has-index flag, using hardwired knowledge */ if (IsBootstrapProcessingMode()) @@ -3032,6 +3121,7 @@ RelationBuildLocalRelation(const char *relname, Oid relnamespace, TupleDesc tupDesc, Oid relid, + Oid accessmtd, Oid relfilenode, Oid reltablespace, bool shared_relation, @@ -3211,6 +3301,14 @@ RelationBuildLocalRelation(const char *relname, RelationInitPhysicalAddr(rel); + rel->rd_rel->relam = accessmtd; + + if (relkind == RELKIND_RELATION || + relkind == RELKIND_SEQUENCE || + relkind == RELKIND_TOASTVALUE || + relkind == RELKIND_MATVIEW) + RelationInitTableAccessMethod(rel); + /* * Okay to insert into the relcache hash table. * @@ -3731,6 +3829,18 @@ RelationCacheInitializePhase3(void) restart = true; } + if (relation->rd_tableam == NULL && + (relation->rd_rel->relkind == RELKIND_RELATION || + relation->rd_rel->relkind == RELKIND_SEQUENCE || + relation->rd_rel->relkind == RELKIND_TOASTVALUE || + relation->rd_rel->relkind == RELKIND_MATVIEW)) + { + RelationInitTableAccessMethod(relation); + Assert(relation->rd_tableam != NULL); + + restart = true; + } + /* Release hold on the relation */ RelationDecrementReferenceCount(relation); @@ -5380,6 +5490,13 @@ load_relcache_init_file(bool shared) if (rel->rd_isnailed) nailed_rels++; + /* Load table AM data */ + if (rel->rd_rel->relkind == RELKIND_RELATION || + rel->rd_rel->relkind == RELKIND_SEQUENCE || + rel->rd_rel->relkind == RELKIND_TOASTVALUE || + rel->rd_rel->relkind == RELKIND_MATVIEW) + RelationInitTableAccessMethod(rel); + Assert(rel->rd_index == NULL); Assert(rel->rd_indextuple == NULL); Assert(rel->rd_indexcxt == NULL); |