From acd602598192b1a0b6c7cd7c77c2a16597f7af99 Mon Sep 17 00:00:00 2001 From: reshke kirill Date: Sat, 11 Jun 2022 11:54:10 +0300 Subject: [PATCH v1] Add create storage manager ddl and routines add create storage manager ddl and support pass smgr routines to smgropen boostrap now work post boostrap ok initdb ok fixes regression passed with 8 failed tests add smgr extension and fixes --- contrib/rsmgr/Makefile | 9 + contrib/rsmgr/proxy_smgr--1.0.sql | 12 ++ contrib/rsmgr/proxy_smgr.c | 123 +++++++++++ contrib/rsmgr/proxy_smgr.control | 5 + src/backend/access/heap/heapam_handler.c | 2 + src/backend/access/rmgrdesc/heapdesc.c | 3 +- src/backend/access/rmgrdesc/xlogdesc.c | 4 +- src/backend/access/transam/xlogrecovery.c | 4 +- src/backend/bootstrap/bootparse.y | 3 + src/backend/catalog/Makefile | 4 +- src/backend/catalog/aclchk.c | 6 +- src/backend/catalog/catalog.c | 4 +- src/backend/catalog/dependency.c | 6 + src/backend/catalog/heap.c | 10 +- src/backend/catalog/index.c | 7 +- src/backend/catalog/objectaddress.c | 66 ++++++ src/backend/catalog/toasting.c | 2 + src/backend/commands/Makefile | 1 + src/backend/commands/alter.c | 1 + src/backend/commands/cluster.c | 6 +- src/backend/commands/dbcommands.c | 3 + src/backend/commands/event_trigger.c | 4 + src/backend/commands/matview.c | 2 +- src/backend/commands/smgrcmds.c | 197 ++++++++++++++++++ src/backend/commands/tablecmds.c | 29 ++- src/backend/nodes/equalfuncs.c | 13 ++ src/backend/parser/gram.y | 51 ++++- src/backend/storage/smgr/Makefile | 4 +- src/backend/storage/smgr/smgr.c | 84 ++------ src/backend/storage/smgr/smgr_handler.c | 75 +++++++ src/backend/storage/smgr/smgrapi.c | 96 +++++++++ src/backend/tcop/utility.c | 15 ++ src/backend/utils/adt/pseudotypes.c | 1 + src/backend/utils/cache/relcache.c | 59 +++++- src/backend/utils/cache/syscache.c | 23 ++ src/bin/psql/describe.c | 1 + src/include/catalog/catalog.h | 2 +- src/include/catalog/dependency.h | 1 + src/include/catalog/heap.h | 2 + src/include/catalog/pg_class.h | 3 + src/include/catalog/pg_proc.dat | 13 ++ src/include/catalog/pg_smgr.dat | 17 ++ src/include/catalog/pg_smgr.h | 52 +++++ src/include/catalog/pg_type.dat | 5 + src/include/commands/cluster.h | 2 +- src/include/commands/defrem.h | 5 + src/include/nodes/nodes.h | 2 + src/include/nodes/parsenodes.h | 14 ++ src/include/parser/kwlist.h | 1 + src/include/storage/md.h | 3 + src/include/storage/relfilenode.h | 1 + src/include/storage/smgr.h | 35 ++-- src/include/tcop/cmdtaglist.h | 2 + src/include/utils/rel.h | 7 + src/include/utils/relcache.h | 2 + src/include/utils/syscache.h | 2 + .../modules/test_oat_hooks/test_oat_hooks.c | 6 + 57 files changed, 998 insertions(+), 114 deletions(-) create mode 100644 contrib/rsmgr/Makefile create mode 100644 contrib/rsmgr/proxy_smgr--1.0.sql create mode 100644 contrib/rsmgr/proxy_smgr.c create mode 100644 contrib/rsmgr/proxy_smgr.control create mode 100644 src/backend/commands/smgrcmds.c create mode 100644 src/backend/storage/smgr/smgr_handler.c create mode 100644 src/backend/storage/smgr/smgrapi.c create mode 100644 src/include/catalog/pg_smgr.dat create mode 100644 src/include/catalog/pg_smgr.h diff --git a/contrib/rsmgr/Makefile b/contrib/rsmgr/Makefile new file mode 100644 index 0000000000..d065209bdf --- /dev/null +++ b/contrib/rsmgr/Makefile @@ -0,0 +1,9 @@ +MODULES = proxy_smgr + +EXTENSION = proxy_smgr +DATA = proxy_smgr--1.0.sql +PGFILEDESC = "proxy_smgr - template table smgra" + +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) diff --git a/contrib/rsmgr/proxy_smgr--1.0.sql b/contrib/rsmgr/proxy_smgr--1.0.sql new file mode 100644 index 0000000000..11e743c3dd --- /dev/null +++ b/contrib/rsmgr/proxy_smgr--1.0.sql @@ -0,0 +1,12 @@ +/* proxy_smgr/proxy_smgr--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION proxy_smgr" to load this file. \quit + +CREATE FUNCTION proxy_smgr_handler(internal) +RETURNS table_smgr_handler +AS 'MODULE_PATHNAME' +LANGUAGE C; + +-- Storage manager +CREATE STORAGE MANAGER proxy_smgr HANDLER proxy_smgr_handler; diff --git a/contrib/rsmgr/proxy_smgr.c b/contrib/rsmgr/proxy_smgr.c new file mode 100644 index 0000000000..955dbd1aea --- /dev/null +++ b/contrib/rsmgr/proxy_smgr.c @@ -0,0 +1,123 @@ + +#include "postgres.h" + +#include + +#include "miscadmin.h" + +#include "access/tableam.h" +#include "access/heapam.h" +#include "access/amapi.h" +#include "catalog/index.h" +#include "commands/vacuum.h" +#include "storage/smgr.h" +#include "storage/md.h" +#include "utils/elog.h" + +PG_MODULE_MAGIC; + +PG_FUNCTION_INFO_V1(proxy_smgr_handler); + + +/* ------------------------------------------------------------------------ + * Definition of the blackhole table access method. + * ------------------------------------------------------------------------ + */ + +void proxyinit(void) { + elog(INFO, "proxy init"); + mdinit(); +} + +void proxyopen(SMgrRelation reln) { + elog(INFO, "proxy open %d %d %d", reln->smgr_rnode.node.spcNode, reln->smgr_rnode.node.dbNode, reln->smgr_rnode.node.relNode); + mdopen(reln); +} + +void proxyclose(SMgrRelation reln, ForkNumber forknum) { + elog(INFO, "proxy close, %d", reln->smgr_rnode.node.relNode); + mdclose(reln, forknum); +} + +void proxycreate(SMgrRelation reln, ForkNumber forknum, bool isRedo) { + elog(INFO, "proxy create %d", reln->smgr_rnode.node.relNode); + + mdcreate(reln, forknum, isRedo); +} + +bool proxyexists(SMgrRelation reln, ForkNumber forknum) { + elog(INFO, "proxy exists %d", reln->smgr_rnode.node.relNode); + return mdexists(reln, forknum); +} + +void proxyunlink(RelFileNodeBackend rnode, ForkNumber forknum, bool isRedo) { + elog(INFO, "proxy unlink %d", rnode.node.relNode); + mdunlink(rnode, forknum, isRedo); +} + +void proxyextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync) { + elog(INFO, "proxcy extend %d", reln->smgr_rnode.node.relNode); + mdextend(reln, forknum, blocknum, buffer, skipFsync); +} + +bool proxyprefetch(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum) { + elog(INFO, "proxy prefecth %d", reln->smgr_rnode.node.relNode); + mdprefetch(reln, forknum, blocknum); +} + +void proxyread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer) { + elog(INFO, "proxy read %d", reln->smgr_rnode.node.relSmgr); + mdread(reln, forknum, blocknum, buffer); +} + +void proxywrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync) { + elog(INFO, "proxy write %d", reln->smgr_rnode.node.relNode); + mdwrite(reln, forknum, blocknum, buffer, skipFsync); +} + +void proxywriteback(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, BlockNumber nblocks) { + elog(INFO, "proxy writeback %d", reln->smgr_rnode.node.relNode); + mdwriteback(reln, forknum, blocknum, nblocks); +} + +BlockNumber proxynblocks(SMgrRelation reln, ForkNumber forknum) { + elog(INFO, "proxy nblocks %d", reln->smgr_rnode.node.relNode); + return mdnblocks(reln, forknum); +} + +void proxytruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks) { + elog(INFO, "proxy truncate %d", reln->smgr_rnode.node.relNode); + return mdtruncate(reln, forknum, nblocks); +} + +void proxyimmedsync(SMgrRelation reln, ForkNumber forknum) { + elog(INFO, "proxy immedsync %d", reln->smgr_rnode.node.relNode); + return mdnblocks(reln, forknum); +} + +static const TableSmgr proxy_smgr_methods = { + .type = T_TableSmgr, + + .smgr_init = proxyinit, + .smgr_shutdown = NULL, + .smgr_open = proxyopen, + .smgr_close = proxyclose, + .smgr_create = proxycreate, + .smgr_exists = proxyexists, + .smgr_unlink = proxyunlink, + .smgr_extend = proxyextend, + .smgr_prefetch = proxyprefetch, + .smgr_read = proxyread, + .smgr_write = proxywrite, + .smgr_writeback = proxywriteback, + .smgr_nblocks = proxynblocks, + .smgr_truncate = proxytruncate, + .smgr_immedsync = proxyimmedsync, +}; + + +Datum +proxy_smgr_handler(PG_FUNCTION_ARGS) +{ + PG_RETURN_POINTER(&proxy_smgr_methods); +} diff --git a/contrib/rsmgr/proxy_smgr.control b/contrib/rsmgr/proxy_smgr.control new file mode 100644 index 0000000000..053d67d74a --- /dev/null +++ b/contrib/rsmgr/proxy_smgr.control @@ -0,0 +1,5 @@ +# proxy_smgr extension +comment = 'template table SMGR' +default_version = '1.0' +module_pathname = '$libdir/proxy_smgr' +relocatable = true diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index 444f027149..bad035f39e 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -1190,6 +1190,7 @@ heapam_index_build_range_scan(Relation heapRelation, * sanity checks */ Assert(OidIsValid(indexRelation->rd_rel->relam)); + Assert(OidIsValid(indexRelation->rd_rel->relsmgr)); /* Remember if it's a system catalog */ is_system_catalog = IsSystemRelation(heapRelation); @@ -1760,6 +1761,7 @@ heapam_index_validate_scan(Relation heapRelation, * sanity checks */ Assert(OidIsValid(indexRelation->rd_rel->relam)); + Assert(OidIsValid(indexRelation->rd_rel->relsmgr)); /* * Need an EState for evaluation of index expressions and partial-index diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c index 6238085d65..2af6d3e544 100644 --- a/src/backend/access/rmgrdesc/heapdesc.c +++ b/src/backend/access/rmgrdesc/heapdesc.c @@ -169,10 +169,11 @@ heap2_desc(StringInfo buf, XLogReaderState *record) { xl_heap_new_cid *xlrec = (xl_heap_new_cid *) rec; - appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u", + appendStringInfo(buf, "rel %u/%u/%u/%u; tid %u/%u", xlrec->target_node.spcNode, xlrec->target_node.dbNode, xlrec->target_node.relNode, + xlrec->target_node.relSmgr, ItemPointerGetBlockNumber(&(xlrec->target_tid)), ItemPointerGetOffsetNumber(&(xlrec->target_tid))); appendStringInfo(buf, "; cmin: %u, cmax: %u, combo: %u", diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c index fefc563323..18f0da9aa1 100644 --- a/src/backend/access/rmgrdesc/xlogdesc.c +++ b/src/backend/access/rmgrdesc/xlogdesc.c @@ -306,9 +306,9 @@ XLogRecGetBlockRefInfo(XLogReaderState *record, bool pretty, else { appendStringInfo(buf, - ", blkref #%d: rel %u/%u/%u blk %u", + ", blkref #%d: rel %u/%u/%u/%u blk %u", block_id, - rnode.spcNode, rnode.dbNode, rnode.relNode, + rnode.spcNode, rnode.dbNode, rnode.relNode, rnode.relSmgr, blk); } diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c index 6eba626420..11a6adda17 100644 --- a/src/backend/access/transam/xlogrecovery.c +++ b/src/backend/access/transam/xlogrecovery.c @@ -2181,9 +2181,9 @@ xlog_block_info(StringInfo buf, XLogReaderState *record) forknum, blk); else - appendStringInfo(buf, "; blkref #%d: rel %u/%u/%u, blk %u", + appendStringInfo(buf, "; blkref #%d: rel %u/%u/%u/%u, blk %u", block_id, - rnode.spcNode, rnode.dbNode, rnode.relNode, + rnode.spcNode, rnode.dbNode, rnode.relNode, rnode.relSmgr, blk); if (XLogRecHasBlockImage(record, block_id)) appendStringInfoString(buf, " FPW"); diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y index e5cf1b3d43..3a49595fdd 100644 --- a/src/backend/bootstrap/bootparse.y +++ b/src/backend/bootstrap/bootparse.y @@ -25,6 +25,7 @@ #include "catalog/pg_authid.h" #include "catalog/pg_class.h" #include "catalog/pg_namespace.h" +#include "catalog/pg_smgr.h" #include "catalog/pg_tablespace.h" #include "catalog/toasting.h" #include "commands/defrem.h" @@ -205,6 +206,7 @@ Boot_CreateStmt: $3, InvalidOid, HEAP_TABLE_AM_OID, + SMGR_MD_OID, tupdesc, RELKIND_RELATION, RELPERSISTENCE_PERMANENT, @@ -228,6 +230,7 @@ Boot_CreateStmt: InvalidOid, BOOTSTRAP_SUPERUSERID, HEAP_TABLE_AM_OID, + SMGR_MD_OID, tupdesc, NIL, RELKIND_RELATION, diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index 89a0221ec9..8869bc9961 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -72,7 +72,7 @@ CATALOG_HEADERS := \ pg_collation.h pg_parameter_acl.h pg_partitioned_table.h \ pg_range.h pg_transform.h \ pg_sequence.h pg_publication.h pg_publication_namespace.h \ - pg_publication_rel.h pg_subscription.h pg_subscription_rel.h + pg_publication_rel.h pg_subscription.h pg_subscription_rel.h pg_smgr.h GENERATED_HEADERS := $(CATALOG_HEADERS:%.h=%_d.h) schemapg.h system_fk_info.h @@ -86,7 +86,7 @@ POSTGRES_BKI_DATA = $(addprefix $(top_srcdir)/src/include/catalog/,\ pg_namespace.dat pg_opclass.dat pg_operator.dat pg_opfamily.dat \ pg_proc.dat pg_range.dat pg_tablespace.dat \ pg_ts_config.dat pg_ts_config_map.dat pg_ts_dict.dat pg_ts_parser.dat \ - pg_ts_template.dat pg_type.dat \ + pg_ts_template.dat pg_type.dat pg_smgr.dat \ ) all: distprep generated-header-symlinks diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index 5f1726c095..ba727d0b2d 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -51,6 +51,7 @@ #include "catalog/pg_parameter_acl.h" #include "catalog/pg_proc.h" #include "catalog/pg_statistic_ext.h" +#include "catalog/pg_smgr.h" #include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_transform.h" @@ -3638,6 +3639,7 @@ aclcheck_error(AclResult aclerr, ObjectType objtype, case OBJECT_PUBLICATION_REL: case OBJECT_ROLE: case OBJECT_RULE: + case OBJECT_STORAGE_MANAGER: case OBJECT_TABCONSTRAINT: case OBJECT_TRANSFORM: case OBJECT_TRIGGER: @@ -3778,6 +3780,7 @@ aclcheck_error(AclResult aclerr, ObjectType objtype, case OBJECT_PUBLICATION_NAMESPACE: case OBJECT_PUBLICATION_REL: case OBJECT_ROLE: + case OBJECT_STORAGE_MANAGER: case OBJECT_TRANSFORM: case OBJECT_TSPARSER: case OBJECT_TSTEMPLATE: @@ -6254,7 +6257,8 @@ recordExtObjInitPriv(Oid objoid, Oid classoid) classoid == TSDictionaryRelationId || classoid == TSParserRelationId || classoid == TSTemplateRelationId || - classoid == TransformRelationId + classoid == TransformRelationId || + classoid == StorageManagerRelationId ) { /* no ACL for these object types, so do nothing. */ diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c index e784538aae..9029ecf756 100644 --- a/src/backend/catalog/catalog.c +++ b/src/backend/catalog/catalog.c @@ -497,7 +497,7 @@ GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn) * created by bootstrap have preassigned OIDs, so there's no need. */ Oid -GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence) +GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence, Oid relsmgr) { RelFileNodeBackend rnode; char *rpath; @@ -536,6 +536,8 @@ GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence) */ rnode.backend = backend; + rnode.node.relSmgr = relsmgr; + do { CHECK_FOR_INTERRUPTS(); diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index de10923391..285a728ad0 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -54,6 +54,7 @@ #include "catalog/pg_publication_rel.h" #include "catalog/pg_rewrite.h" #include "catalog/pg_statistic_ext.h" +#include "catalog/pg_smgr.h" #include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_transform.h" @@ -185,6 +186,7 @@ static const Oid object_classes[] = { PublicationRelationId, /* OCLASS_PUBLICATION */ PublicationRelRelationId, /* OCLASS_PUBLICATION_REL */ SubscriptionRelationId, /* OCLASS_SUBSCRIPTION */ + StorageManagerRelationId, /* OCLASS_SMGR */ TransformRelationId /* OCLASS_TRANSFORM */ }; @@ -1490,6 +1492,7 @@ doDeletion(const ObjectAddress *object, int flags) case OCLASS_AMOP: case OCLASS_AMPROC: case OCLASS_SCHEMA: + case OCLASS_SMGR: case OCLASS_TSPARSER: case OCLASS_TSDICT: case OCLASS_TSTEMPLATE: @@ -2882,6 +2885,9 @@ getObjectClass(const ObjectAddress *object) case SubscriptionRelationId: return OCLASS_SUBSCRIPTION; + case StorageManagerRelationId: + return OCLASS_SMGR; + case TransformRelationId: return OCLASS_TRANSFORM; } diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 1803194db9..0ad8f31f4f 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -50,6 +50,7 @@ #include "catalog/pg_opclass.h" #include "catalog/pg_partitioned_table.h" #include "catalog/pg_statistic.h" +#include "catalog/pg_smgr.h" #include "catalog/pg_subscription_rel.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_type.h" @@ -291,6 +292,7 @@ heap_create(const char *relname, Oid relid, Oid relfilenode, Oid accessmtd, + Oid smgrid, TupleDesc tupDesc, char relkind, char relpersistence, @@ -368,6 +370,7 @@ heap_create(const char *relname, tupDesc, relid, accessmtd, + smgrid, relfilenode, reltablespace, shared_relation, @@ -898,6 +901,7 @@ InsertPgClassTuple(Relation pg_class_desc, values[Anum_pg_class_reloftype - 1] = ObjectIdGetDatum(rd_rel->reloftype); values[Anum_pg_class_relowner - 1] = ObjectIdGetDatum(rd_rel->relowner); values[Anum_pg_class_relam - 1] = ObjectIdGetDatum(rd_rel->relam); + values[Anum_pg_class_relsmgr - 1] = ObjectIdGetDatum(rd_rel->relsmgr); values[Anum_pg_class_relfilenode - 1] = ObjectIdGetDatum(rd_rel->relfilenode); values[Anum_pg_class_reltablespace - 1] = ObjectIdGetDatum(rd_rel->reltablespace); values[Anum_pg_class_relpages - 1] = Int32GetDatum(rd_rel->relpages); @@ -1093,6 +1097,7 @@ heap_create_with_catalog(const char *relname, Oid reloftypeid, Oid ownerid, Oid accessmtd, + Oid smgrid, TupleDesc tupdesc, List *cooked_constraints, char relkind, @@ -1230,7 +1235,7 @@ heap_create_with_catalog(const char *relname, if (!OidIsValid(relid)) relid = GetNewRelFileNode(reltablespace, pg_class_desc, - relpersistence); + relpersistence, smgrid); } /* @@ -1275,6 +1280,7 @@ heap_create_with_catalog(const char *relname, relid, relfilenode, accessmtd, + smgrid, tupdesc, relkind, relpersistence, @@ -1455,6 +1461,8 @@ heap_create_with_catalog(const char *relname, add_exact_object_address(&referenced, addrs); } + ObjectAddressSet(referenced, StorageManagerRelationId, smgrid); + record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL); free_object_addresses(addrs); } diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index bdd3c34841..45459d8fe7 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -50,6 +50,7 @@ #include "catalog/pg_inherits.h" #include "catalog/pg_opclass.h" #include "catalog/pg_operator.h" +#include "catalog/pg_smgr.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_trigger.h" #include "catalog/pg_type.h" @@ -728,6 +729,7 @@ index_create(Relation heapRelation, Oid namespaceId; int i; char relpersistence; + Oid relsmgr; bool isprimary = (flags & INDEX_CREATE_IS_PRIMARY) != 0; bool invalid = (flags & INDEX_CREATE_INVALID) != 0; bool concurrent = (flags & INDEX_CREATE_CONCURRENT) != 0; @@ -758,6 +760,7 @@ index_create(Relation heapRelation, shared_relation = heapRelation->rd_rel->relisshared; mapped_relation = RelationIsMapped(heapRelation); relpersistence = heapRelation->rd_rel->relpersistence; + relsmgr = heapRelation->rd_rel->relsmgr; /* * check parameters @@ -937,7 +940,7 @@ index_create(Relation heapRelation, else { indexRelationId = - GetNewRelFileNode(tableSpaceId, pg_class, relpersistence); + GetNewRelFileNode(tableSpaceId, pg_class, relpersistence, relsmgr); } } @@ -952,6 +955,7 @@ index_create(Relation heapRelation, indexRelationId, relFileNode, accessMethodObjectId, + SMGR_MD_OID, indexTupDesc, relkind, relpersistence, @@ -981,6 +985,7 @@ index_create(Relation heapRelation, */ indexRelation->rd_rel->relowner = heapRelation->rd_rel->relowner; indexRelation->rd_rel->relam = accessMethodObjectId; + indexRelation->rd_rel->relsmgr = relsmgr; indexRelation->rd_rel->relispartition = OidIsValid(parentIndexRelid); /* diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 8377b4f7d4..5c39309aa2 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -53,6 +53,7 @@ #include "catalog/pg_publication_rel.h" #include "catalog/pg_rewrite.h" #include "catalog/pg_statistic_ext.h" +#include "catalog/pg_smgr.h" #include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_transform.h" @@ -414,6 +415,20 @@ static const ObjectPropertyType ObjectProperty[] = OBJECT_SCHEMA, true }, + { + "storage manager", + StorageManagerRelationId, + SmgrOidIndexId, + SMGROID, + SMGRNAME, + Anum_pg_smgr_oid, + Anum_pg_smgr_smgrname, + InvalidAttrNumber, + InvalidAttrNumber, + InvalidAttrNumber, + -1, + true + }, { "relation", RelationRelationId, @@ -843,6 +858,10 @@ static const struct object_type_map { "subscription", OBJECT_SUBSCRIPTION }, + /* OCLASS_SMGR */ + { + "storage manager", OBJECT_STORAGE_MANAGER + }, /* OCLASS_TRANSFORM */ { "transform", OBJECT_TRANSFORM @@ -1335,6 +1354,11 @@ get_object_address_unqualified(ObjectType objtype, address.objectId = get_subscription_oid(name, missing_ok); address.objectSubId = 0; break; + case OBJECT_STORAGE_MANAGER: + address.classId = StorageManagerRelationId; + address.objectId = get_smgr_oid(name, missing_ok); + address.objectSubId = 0; + break; default: elog(ERROR, "unrecognized objtype: %d", (int) objtype); /* placate compiler, which doesn't know elog won't return */ @@ -2318,6 +2342,7 @@ pg_get_object_address(PG_FUNCTION_ARGS) case OBJECT_ROLE: case OBJECT_SCHEMA: case OBJECT_SUBSCRIPTION: + case OBJECT_STORAGE_MANAGER: case OBJECT_TABLESPACE: if (list_length(name) != 1) ereport(ERROR, @@ -3261,6 +3286,26 @@ getObjectDescription(const ObjectAddress *object, bool missing_ok) break; } + case OCLASS_SMGR: + { + HeapTuple tup; + + tup = SearchSysCache1(SMGROID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "cache lookup failed for storage manager %u", + object->objectId); + break; + } + + appendStringInfo(&buffer, _("storage manager %s"), + NameStr(((Form_pg_smgr) GETSTRUCT(tup))->smgrname)); + ReleaseSysCache(tup); + break; + } + case OCLASS_AMOP: { Relation amopDesc; @@ -4493,6 +4538,10 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "access method"); break; + case OCLASS_SMGR: + appendStringInfoString(&buffer, "storage manager"); + break; + case OCLASS_AMOP: appendStringInfoString(&buffer, "operator of access method"); break; @@ -5121,6 +5170,23 @@ getObjectIdentityParts(const ObjectAddress *object, *objname = list_make1(amname); } break; + case OCLASS_SMGR: + { + char *smgrname; + + smgrname = get_smgr_name(object->objectId); + if (!smgrname) + { + if (!missing_ok) + elog(ERROR, "cache lookup failed for storage mamnager %u", + object->objectId); + break; + } + appendStringInfoString(&buffer, quote_identifier(smgrname)); + if (objname) + *objname = list_make1(smgrname); + } + break; case OCLASS_AMOP: { diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c index 9bc10729b0..99763185ac 100644 --- a/src/backend/catalog/toasting.c +++ b/src/backend/catalog/toasting.c @@ -27,6 +27,7 @@ #include "catalog/pg_namespace.h" #include "catalog/pg_opclass.h" #include "catalog/pg_type.h" +#include "catalog/pg_smgr.h" #include "catalog/toasting.h" #include "miscadmin.h" #include "nodes/makefuncs.h" @@ -254,6 +255,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, InvalidOid, rel->rd_rel->relowner, table_relation_toast_am(rel), + SMGR_MD_OID, tupdesc, NIL, RELKIND_TOASTVALUE, diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile index 48f7348f91..8f0c71f8d7 100644 --- a/src/backend/commands/Makefile +++ b/src/backend/commands/Makefile @@ -51,6 +51,7 @@ OBJS = \ seclabel.o \ sequence.o \ statscmds.o \ + smgrcmds.o \ subscriptioncmds.o \ tablecmds.o \ tablespace.o \ diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index 5456b8222b..e29a3bd20e 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -663,6 +663,7 @@ AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid, case OCLASS_PUBLICATION: case OCLASS_PUBLICATION_NAMESPACE: case OCLASS_PUBLICATION_REL: + case OCLASS_SMGR: case OCLASS_SUBSCRIPTION: case OCLASS_TRANSFORM: /* ignore object types that don't have schema-qualified names */ diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index cea2c8be80..7ab7160e06 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -632,6 +632,7 @@ rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose) { Oid tableOid = RelationGetRelid(OldHeap); Oid accessMethod = OldHeap->rd_rel->relam; + Oid storageMethod = OldHeap->rd_rel->relsmgr; Oid tableSpace = OldHeap->rd_rel->reltablespace; Oid OIDNewHeap; char relpersistence; @@ -654,7 +655,7 @@ rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose) /* Create the transient table that will receive the re-ordered data */ OIDNewHeap = make_new_heap(tableOid, tableSpace, accessMethod, - relpersistence, + relpersistence, storageMethod, AccessExclusiveLock); /* Copy the heap data into the new table in the desired order */ @@ -683,7 +684,7 @@ rebuild_relation(Relation OldHeap, Oid indexOid, bool verbose) * data, then call finish_heap_swap to complete the operation. */ Oid -make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewAccessMethod, +make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewAccessMethod, Oid NewStorageMethod, char relpersistence, LOCKMODE lockmode) { TupleDesc OldHeapDesc; @@ -744,6 +745,7 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewAccessMethod, InvalidOid, OldHeap->rd_rel->relowner, NewAccessMethod, + NewStorageMethod, OldHeapDesc, NIL, RELKIND_RELATION, diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index f269168401..81e5bbe5b9 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -195,6 +195,7 @@ CreateDatabaseUsingWalLog(Oid src_dboid, Oid dst_dboid, dstrnode.dbNode = dst_dboid; dstrnode.relNode = srcrnode.relNode; + dstrnode.relSmgr = srcrnode.relSmgr; /* * Acquire locks on source and target relations before copying. @@ -271,6 +272,7 @@ ScanSourceDatabasePgClass(Oid tbid, Oid dbid, char *srcpath) rnode.spcNode = tbid; rnode.dbNode = dbid; rnode.relNode = relfilenode; + rnode.relSmgr = F_SMGR_MD_HANDLER; /* * We can't use a real relcache entry for a relation in some other @@ -441,6 +443,7 @@ ScanSourceDatabasePgClassTuple(HeapTupleData *tuple, Oid tbid, Oid dbid, relinfo->rnode.dbNode = dbid; relinfo->rnode.relNode = relfilenode; + relinfo->rnode.relSmgr = F_SMGR_MD_HANDLER; relinfo->reloid = classForm->oid; /* Temporary relations were rejected above. */ diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 4642527881..6bfed2d6dd 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -982,6 +982,7 @@ EventTriggerSupportsObjectType(ObjectType obtype) case OBJECT_SEQUENCE: case OBJECT_SUBSCRIPTION: case OBJECT_STATISTIC_EXT: + case OBJECT_STORAGE_MANAGER: case OBJECT_TABCONSTRAINT: case OBJECT_TABLE: case OBJECT_TRANSFORM: @@ -1042,6 +1043,7 @@ EventTriggerSupportsObjectClass(ObjectClass objclass) case OCLASS_TRIGGER: case OCLASS_SCHEMA: case OCLASS_STATISTIC_EXT: + case OCLASS_SMGR: case OCLASS_TSPARSER: case OCLASS_TSDICT: case OCLASS_TSTEMPLATE: @@ -2080,6 +2082,7 @@ stringify_grant_objtype(ObjectType objtype) case OBJECT_PUBLICATION_REL: case OBJECT_ROLE: case OBJECT_RULE: + case OBJECT_STORAGE_MANAGER: case OBJECT_STATISTIC_EXT: case OBJECT_SUBSCRIPTION: case OBJECT_TABCONSTRAINT: @@ -2164,6 +2167,7 @@ stringify_adefprivs_objtype(ObjectType objtype) case OBJECT_PUBLICATION_REL: case OBJECT_ROLE: case OBJECT_RULE: + case OBJECT_STORAGE_MANAGER: case OBJECT_STATISTIC_EXT: case OBJECT_SUBSCRIPTION: case OBJECT_TABCONSTRAINT: diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c index d1ee106465..d3ae12c835 100644 --- a/src/backend/commands/matview.c +++ b/src/backend/commands/matview.c @@ -298,7 +298,7 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString, * will be gone). */ OIDNewHeap = make_new_heap(matviewOid, tableSpace, - matviewRel->rd_rel->relam, + matviewRel->rd_rel->relam, matviewRel->rd_rel->relsmgr, relpersistence, ExclusiveLock); LockRelationOid(OIDNewHeap, AccessExclusiveLock); dest = CreateTransientRelDestReceiver(OIDNewHeap); diff --git a/src/backend/commands/smgrcmds.c b/src/backend/commands/smgrcmds.c new file mode 100644 index 0000000000..becfab4cfa --- /dev/null +++ b/src/backend/commands/smgrcmds.c @@ -0,0 +1,197 @@ + +/*------------------------------------------------------------------------- + * + * smgrcmds.c + * Routines for SQL commands that manipulate storage managers. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/commands/smgrcmds.c + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/heapam.h" +#include "access/htup_details.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/pg_smgr.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_type.h" +#include "commands/defrem.h" +#include "miscadmin.h" +#include "parser/parse_func.h" +#include "utils/builtins.h" +#include "utils/lsyscache.h" +#include "utils/rel.h" +#include "utils/syscache.h" +#include "catalog/objectaccess.h" + + + +/* + * Convert a handler function name to an Oid. + * + * This function either return valid function Oid or throw an error. + */ +static Oid +lookup_smgr_handler_func(List *handler_name) +{ + Oid handlerOid; + Oid funcargtypes[1] = {INTERNALOID}; + Oid expectedType = TABLE_SMGR_HANDLEROID; + + if (handler_name == NIL) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("handler function is not specified"))); + + /* handlers have one argument of type internal */ + handlerOid = LookupFuncName(handler_name, 1, funcargtypes, false); + + if (get_func_rettype(handlerOid) != expectedType) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("function %s must return type %s", + get_func_name(handlerOid), + format_type_extended(expectedType, -1, 0)))); + + return handlerOid; +} + +/* + * CreateStorageManager + * Registers a new storage manager. + */ +ObjectAddress +CreateStorageManager(CreateSmgrStmt *stmt) { + + Relation rel; + ObjectAddress retval; + ObjectAddress referenced; + Oid smgroid; + Oid smgrhandler; + bool nulls[Natts_pg_smgr]; + Datum values[Natts_pg_smgr]; + HeapTuple tup; + + rel = table_open(StorageManagerRelationId, RowExclusiveLock); + + /* Must be superuser */ + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied to create storage manager \"%s\"", + stmt->smgrname), + errhint("Must be superuser to create an storage manager."))); + + /* Check if name is used */ + smgroid = GetSysCacheOid1(SMGRNAME, Anum_pg_smgr_oid, + CStringGetDatum(stmt->smgrname)); + if (OidIsValid(smgroid)) + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("storage manager \"%s\" already exists", + stmt->smgrname))); + } + + /* + * Get the handler function oid. + */ + smgrhandler = lookup_smgr_handler_func(stmt->handler_name); + + /* + * Insert tuple into pg_am. + */ + memset(values, 0, sizeof(values)); + memset(nulls, false, sizeof(nulls)); + + smgroid = GetNewOidWithIndex(rel, SmgrOidIndexId, Anum_pg_smgr_oid); + values[Anum_pg_smgr_oid - 1] = ObjectIdGetDatum(smgroid); + values[Anum_pg_smgr_smgrname - 1] = + DirectFunctionCall1(namein, CStringGetDatum(stmt->smgrname)); + values[Anum_pg_smgr_smgrhandler - 1] = ObjectIdGetDatum(smgrhandler); + tup = heap_form_tuple(RelationGetDescr(rel), values, nulls); + + CatalogTupleInsert(rel, tup); + heap_freetuple(tup); + + retval.classId = StorageManagerRelationId; + retval.objectId = smgroid; + retval.objectSubId = 0; + + /* Record dependency on handler function */ + referenced.classId = ProcedureRelationId; + referenced.objectId = smgrhandler; + referenced.objectSubId = 0; + + recordDependencyOn(&retval, &referenced, DEPENDENCY_NORMAL); + + recordDependencyOnCurrentExtension(&retval, false); + + InvokeObjectPostCreateHook(StorageManagerRelationId, smgroid, 0); + + table_close(rel, RowExclusiveLock); + + return retval; +} + + + +/* + * get_am_type_oid + * Worker for various get_am_*_oid variants + * + * If missing_ok is false, throw an error if access method not found. If + * true, just return InvalidOid. + * + * If amtype is not '\0', an error is raised if the AM found is not of the + * given type. + */ +Oid +get_smgr_oid(const char *smgrname, bool missing_ok) +{ + HeapTuple tup; + Oid oid = InvalidOid; + + tup = SearchSysCache1(SMGRNAME, CStringGetDatum(smgrname)); + if (HeapTupleIsValid(tup)) + { + Form_pg_smgr smgrform = (Form_pg_smgr) GETSTRUCT(tup); + oid = smgrform->oid; + ReleaseSysCache(tup); + } + + if (!OidIsValid(oid) && !missing_ok) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("storage manager \"%s\" does not exist", smgrname))); + return oid; +} + + + +/* + * get_smgr_name - given an storage manager OID, look up its name. + */ +char * +get_smgr_name(Oid amOid) +{ + HeapTuple tup; + char *result = NULL; + + tup = SearchSysCache1(SMGROID, ObjectIdGetDatum(amOid)); + if (HeapTupleIsValid(tup)) + { + Form_pg_smgr smgrform = (Form_pg_smgr) GETSTRUCT(tup); + + result = pstrdup(NameStr(smgrform->smgrname)); + ReleaseSysCache(tup); + } + return result; +} diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 2de0ebacec..70712e5308 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -43,6 +43,7 @@ #include "catalog/pg_namespace.h" #include "catalog/pg_opclass.h" #include "catalog/pg_statistic_ext.h" +#include "catalog/pg_smgr.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_trigger.h" #include "catalog/pg_type.h" @@ -179,6 +180,7 @@ typedef struct AlteredTableInfo bool verify_new_notnull; /* T if we should recheck NOT NULL */ int rewrite; /* Reason for forced rewrite, if any */ Oid newAccessMethod; /* new access method; 0 means no change */ + Oid newStorageManager; /* new storage manager; 0 means no change */ Oid newTableSpace; /* new tablespace; 0 means no change */ bool chgPersistence; /* T if SET LOGGED/UNLOGGED is used */ char newrelpersistence; /* if above is true */ @@ -678,6 +680,8 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, LOCKMODE parentLockmode; const char *accessMethod = NULL; Oid accessMethodId = InvalidOid; + const char *storageManager = NULL; + Oid smgrOid = SMGR_MD_OID; /* * Truncate relname to appropriate length (probably a waste of time, as @@ -953,6 +957,14 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, if (accessMethod != NULL) accessMethodId = get_table_am_oid(accessMethod, false); + if (stmt->storageManager != NULL) { + storageManager = stmt->storageManager; + } + + if (storageManager) { + smgrOid = get_smgr_oid(storageManager, false); + } + /* * Create the relation. Inherited defaults and constraints are passed in * for immediate handling --- since they don't need parsing, they can be @@ -966,6 +978,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, ofTypeId, ownerId, accessMethodId, + smgrOid, descriptor, list_concat(cookedDefaults, old_constraints), @@ -5429,6 +5442,7 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, Relation OldHeap; Oid OIDNewHeap; Oid NewAccessMethod; + Oid NewStorageManager; Oid NewTableSpace; char persistence; @@ -5478,6 +5492,16 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, else NewAccessMethod = OldHeap->rd_rel->relam; + /* + * Select destination storage manager (same as original unless user + * requested a change) + */ + if (OidIsValid(tab->newStorageManager)) + NewStorageManager = tab->newStorageManager; + else + NewStorageManager = OldHeap->rd_rel->relsmgr; + + /* * Select persistence of transient table (same as original unless * user requested a change) @@ -5517,7 +5541,7 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, * persistence. That wouldn't work for pg_class, but that can't be * unlogged anyway. */ - OIDNewHeap = make_new_heap(tab->relid, NewTableSpace, NewAccessMethod, + OIDNewHeap = make_new_heap(tab->relid, NewTableSpace, NewAccessMethod, NewStorageManager, persistence, lockmode); /* @@ -12683,6 +12707,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, case OCLASS_PUBLICATION: case OCLASS_PUBLICATION_NAMESPACE: case OCLASS_PUBLICATION_REL: + case OCLASS_SMGR: case OCLASS_SUBSCRIPTION: case OCLASS_TRANSFORM: @@ -14374,7 +14399,7 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode) * to allocate a new one in the new tablespace. */ newrelfilenode = GetNewRelFileNode(newTableSpace, NULL, - rel->rd_rel->relpersistence); + rel->rd_rel->relpersistence, rel->rd_rel->relsmgr); /* Open old and new relation */ newrnode = rel->rd_node; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index e747e1667d..88ff3c8fc5 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -2433,6 +2433,16 @@ _equalCreateAmStmt(const CreateAmStmt *a, const CreateAmStmt *b) return true; } + +static bool +_equalCreateSmgrStmt(const CreateSmgrStmt *a, const CreateSmgrStmt *b) +{ + COMPARE_STRING_FIELD(smgrname); + COMPARE_NODE_FIELD(handler_name); + + return true; +} + static bool _equalCreateTrigStmt(const CreateTrigStmt *a, const CreateTrigStmt *b) { @@ -4120,6 +4130,9 @@ equal(const void *a, const void *b) case T_CreateAmStmt: retval = _equalCreateAmStmt(a, b); break; + case T_CreateSmgrStmt: + retval = _equalCreateSmgrStmt(a, b); + break; case T_CreateTrigStmt: retval = _equalCreateTrigStmt(a, b); break; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 969c9c158f..77038e33d4 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -328,7 +328,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); AlterTSConfigurationStmt AlterTSDictionaryStmt CreateMatViewStmt RefreshMatViewStmt CreateAmStmt CreatePublicationStmt AlterPublicationStmt - CreateSubscriptionStmt AlterSubscriptionStmt DropSubscriptionStmt + CreateSubscriptionStmt AlterSubscriptionStmt DropSubscriptionStmt CreateSmgrStmt %type select_no_parens select_with_parens select_clause simple_select values_clause @@ -606,7 +606,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type constraints_set_list %type constraints_set_mode -%type OptTableSpace OptConsTableSpace +%type OptTableSpace OptConsTableSpace OptStorageManager %type OptTableSpaceOwner %type opt_check_option @@ -814,7 +814,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); LEADING LEAKPROOF LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P LOCKED LOGGED - MAPPING MATCH MATCHED MATERIALIZED MAXVALUE MERGE METHOD + MANAGER MAPPING MATCH MATCHED MATERIALIZED MAXVALUE MERGE METHOD MINUTE_P MINVALUE MODE MONTH_P MOVE NAME_P NAMES NATIONAL NATURAL NCHAR NESTED NEW NEXT NFC NFD NFKC NFKD NO @@ -1112,6 +1112,7 @@ stmt: | CreatePLangStmt | CreateSchemaStmt | CreateSeqStmt + | CreateSmgrStmt | CreateStmt | CreateSubscriptionStmt | CreateStatsStmt @@ -3578,7 +3579,7 @@ copy_generic_opt_arg_list_item: CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' OptInherit OptPartitionSpec table_access_method_clause OptWith - OnCommitOption OptTableSpace + OnCommitOption OptTableSpace OptStorageManager { CreateStmt *n = makeNode(CreateStmt); @@ -3593,12 +3594,13 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->options = $11; n->oncommit = $12; n->tablespacename = $13; + n->storageManager = $14; n->if_not_exists = false; $$ = (Node *) n; } | CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name '(' OptTableElementList ')' OptInherit OptPartitionSpec table_access_method_clause - OptWith OnCommitOption OptTableSpace + OptWith OnCommitOption OptTableSpace OptStorageManager { CreateStmt *n = makeNode(CreateStmt); @@ -3613,12 +3615,13 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->options = $14; n->oncommit = $15; n->tablespacename = $16; + n->storageManager = $17; n->if_not_exists = true; $$ = (Node *) n; } | CREATE OptTemp TABLE qualified_name OF any_name OptTypedTableElementList OptPartitionSpec table_access_method_clause - OptWith OnCommitOption OptTableSpace + OptWith OnCommitOption OptTableSpace OptStorageManager { CreateStmt *n = makeNode(CreateStmt); @@ -3634,12 +3637,13 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->options = $10; n->oncommit = $11; n->tablespacename = $12; + n->storageManager = $13; n->if_not_exists = false; $$ = (Node *) n; } | CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name OF any_name OptTypedTableElementList OptPartitionSpec table_access_method_clause - OptWith OnCommitOption OptTableSpace + OptWith OnCommitOption OptTableSpace OptStorageManager { CreateStmt *n = makeNode(CreateStmt); @@ -3655,12 +3659,13 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->options = $13; n->oncommit = $14; n->tablespacename = $15; + n->storageManager = $16; n->if_not_exists = true; $$ = (Node *) n; } | CREATE OptTemp TABLE qualified_name PARTITION OF qualified_name OptTypedTableElementList PartitionBoundSpec OptPartitionSpec - table_access_method_clause OptWith OnCommitOption OptTableSpace + table_access_method_clause OptWith OnCommitOption OptTableSpace OptStorageManager { CreateStmt *n = makeNode(CreateStmt); @@ -3676,12 +3681,13 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->options = $12; n->oncommit = $13; n->tablespacename = $14; + n->storageManager = $15; n->if_not_exists = false; $$ = (Node *) n; } | CREATE OptTemp TABLE IF_P NOT EXISTS qualified_name PARTITION OF qualified_name OptTypedTableElementList PartitionBoundSpec OptPartitionSpec - table_access_method_clause OptWith OnCommitOption OptTableSpace + table_access_method_clause OptWith OnCommitOption OptTableSpace OptStorageManager { CreateStmt *n = makeNode(CreateStmt); @@ -3697,6 +3703,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->options = $15; n->oncommit = $16; n->tablespacename = $17; + n->storageManager = $18; n->if_not_exists = true; $$ = (Node *) n; } @@ -4513,6 +4520,11 @@ OptTableSpace: TABLESPACE name { $$ = $2; } | /*EMPTY*/ { $$ = NULL; } ; +OptStorageManager: STORAGE MANAGER name { $$ = $3; } + | /*EMPTY*/ { $$ = NULL; } + ; + + OptConsTableSpace: USING INDEX TABLESPACE name { $$ = $4; } | /*EMPTY*/ { $$ = NULL; } ; @@ -5827,6 +5839,24 @@ am_type: | TABLE { $$ = AMTYPE_TABLE; } ; + +/***************************************************************************** + * + * QUERY: + * CREATE STORAGE MANAGER name HANDLER handler_name + * + *****************************************************************************/ + +CreateSmgrStmt: CREATE STORAGE MANAGER name HANDLER handler_name + { + CreateSmgrStmt *n = makeNode(CreateSmgrStmt); + + n->smgrname = $4; + n->handler_name = $6; + $$ = (Node *) n; + } + ; + /***************************************************************************** * * QUERIES : @@ -6896,6 +6926,7 @@ drop_type_name: | PUBLICATION { $$ = OBJECT_PUBLICATION; } | SCHEMA { $$ = OBJECT_SCHEMA; } | SERVER { $$ = OBJECT_FOREIGN_SERVER; } + | STORAGE MANAGER { $$ = OBJECT_STORAGE_MANAGER; } ; /* object types attached to a table */ @@ -17815,6 +17846,7 @@ unreserved_keyword: | LOCK_P | LOCKED | LOGGED + | MANAGER | MAPPING | MATCH | MATCHED @@ -18422,6 +18454,7 @@ bare_label_keyword: | LOCK_P | LOCKED | LOGGED + | MANAGER | MAPPING | MATCH | MATCHED diff --git a/src/backend/storage/smgr/Makefile b/src/backend/storage/smgr/Makefile index 596b564656..929ee45435 100644 --- a/src/backend/storage/smgr/Makefile +++ b/src/backend/storage/smgr/Makefile @@ -14,6 +14,8 @@ include $(top_builddir)/src/Makefile.global OBJS = \ md.o \ - smgr.o + smgr.o \ + smgrapi.o \ + smgr_handler.o include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c index b3cf942d51..5f870e0309 100644 --- a/src/backend/storage/smgr/smgr.c +++ b/src/backend/storage/smgr/smgr.c @@ -23,27 +23,10 @@ #include "storage/ipc.h" #include "storage/md.h" #include "storage/smgr.h" +#include "catalog/pg_smgr.h" #include "utils/hsearch.h" #include "utils/inval.h" -static const f_smgr smgr_md = { - /* magnetic disk */ - .smgr_init = mdinit, - .smgr_shutdown = NULL, - .smgr_open = mdopen, - .smgr_close = mdclose, - .smgr_create = mdcreate, - .smgr_exists = mdexists, - .smgr_unlink = mdunlink, - .smgr_extend = mdextend, - .smgr_prefetch = mdprefetch, - .smgr_read = mdread, - .smgr_write = mdwrite, - .smgr_writeback = mdwriteback, - .smgr_nblocks = mdnblocks, - .smgr_truncate = mdtruncate, - .smgr_immedsync = mdimmedsync, -}; /* * Each backend has a hashtable that stores all extant SMgrRelation objects. @@ -68,11 +51,8 @@ static void smgrshutdown(int code, Datum arg); void smgrinit(void) { - if (smgr_init_hook) - (*smgr_init_hook)(); - - smgr_init_standard(); - + // init other smgrs in pg_init + mdinit(); /* register the shutdown proc */ on_proc_exit(smgrshutdown, 0); } @@ -82,51 +62,8 @@ smgrinit(void) */ static void smgrshutdown(int code, Datum arg) -{ - if (smgr_shutdown_hook) - (*smgr_shutdown_hook)(); - - smgr_shutdown_standard(); -} - -/* Hooks for plugins to get control in smgr */ -smgr_hook_type smgr_hook = NULL; -smgr_init_hook_type smgr_init_hook = NULL; -smgr_shutdown_hook_type smgr_shutdown_hook = NULL; - -const f_smgr * -smgr_standard(BackendId backend, RelFileNode rnode) -{ - return &smgr_md; -} - -void -smgr_init_standard(void) -{ - mdinit(); -} - -void -smgr_shutdown_standard(void) { } - -const f_smgr * -smgr(BackendId backend, RelFileNode rnode) -{ - const f_smgr *result; - - if (smgr_hook) - { - result = (*smgr_hook)(backend, rnode); - } - else - result = smgr_standard(backend, rnode); - - return result; -} - - /* * smgropen() -- Return an SMgrRelation object, creating it if need be. * @@ -167,14 +104,25 @@ smgropen(RelFileNode rnode, BackendId backend) for (int i = 0; i <= MAX_FORKNUM; ++i) reln->smgr_cached_nblocks[i] = InvalidBlockNumber; - reln->smgr = smgr(backend, rnode); + if (rnode.relSmgr == SMGR_MD_OID) + { + /* + * Avoid doing a syscache lookup for catalog tables. + */ + reln->smgr = &smgr_md; + } else { + Assert(rnode.relSmgr != 0); + reln->smgr = GetTableSmgr(rnode.relSmgr); + } + Assert(reln->smgr != NULL); /* implementation-specific initialization */ - (*reln->smgr).smgr_open(reln); + reln->smgr->smgr_open(reln); /* it has no owner yet */ dlist_push_tail(&unowned_relns, &reln->node); } + Assert(reln->smgr != NULL); return reln; } diff --git a/src/backend/storage/smgr/smgr_handler.c b/src/backend/storage/smgr/smgr_handler.c new file mode 100644 index 0000000000..4b99d5744f --- /dev/null +++ b/src/backend/storage/smgr/smgr_handler.c @@ -0,0 +1,75 @@ +/*------------------------------------------------------------------------- + * + * smgr_md_handler.c + * md table access method code + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/storage/smgr/smgr_md_handler.c + * + * + * NOTES + * This files wires up the lower level heapam.c et al routines with the + * tableam abstraction. + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" +#include "storage/smgr.h" +#include "storage/md.h" + +#include "access/genam.h" +#include "access/heapam.h" +#include "access/heaptoast.h" +#include "access/multixact.h" +#include "access/rewriteheap.h" +#include "access/syncscan.h" +#include "access/tableam.h" +#include "access/tsmapi.h" +#include "access/xact.h" +#include "catalog/catalog.h" +#include "catalog/index.h" +#include "catalog/storage.h" +#include "catalog/storage_xlog.h" +#include "commands/progress.h" +#include "executor/executor.h" +#include "miscadmin.h" +#include "pgstat.h" +#include "storage/bufmgr.h" +#include "storage/bufpage.h" +#include "storage/lmgr.h" +#include "storage/predicate.h" +#include "storage/procarray.h" +#include "storage/smgr.h" +#include "utils/builtins.h" +#include "utils/rel.h" + +const TableSmgr smgr_md = { + /* magnetic disk */ + .type = T_TableSmgr, + .smgr_init = mdinit, + .smgr_shutdown = NULL, + .smgr_open = mdopen, + .smgr_close = mdclose, + .smgr_create = mdcreate, + .smgr_exists = mdexists, + .smgr_unlink = mdunlink, + .smgr_extend = mdextend, + .smgr_prefetch = mdprefetch, + .smgr_read = mdread, + .smgr_write = mdwrite, + .smgr_writeback = mdwriteback, + .smgr_nblocks = mdnblocks, + .smgr_truncate = mdtruncate, + .smgr_immedsync = mdimmedsync, +}; + +Datum +smgr_md_handler(PG_FUNCTION_ARGS) +{ + PG_RETURN_POINTER(&smgr_md); +} diff --git a/src/backend/storage/smgr/smgrapi.c b/src/backend/storage/smgr/smgrapi.c new file mode 100644 index 0000000000..dde65dc773 --- /dev/null +++ b/src/backend/storage/smgr/smgrapi.c @@ -0,0 +1,96 @@ + +/* + * GetTableAmRoutine + * Call the specified access method handler routine to get its + * TableAmRoutine struct, which will be palloc'd in the caller's + * memory context. + */ + +#include "postgres.h" + + +#include "storage/smgr.h" +#include "catalog/pg_smgr.h" +#include "catalog/pg_proc.h" +#include "commands/defrem.h" +#include "miscadmin.h" +#include "utils/fmgroids.h" +#include "utils/elog.h" +#include "utils/memutils.h" +#include "utils/syscache.h" + +TableSmgr * +GetTableSmgr(Oid smgrhandler) +{ + Datum datum; + TableSmgr *routine; + + datum = OidFunctionCall0(smgrhandler); + routine = (TableSmgr *) DatumGetPointer(datum); + + if (routine == NULL || !IsA(routine, TableSmgr)) + elog(ERROR, "table storage manage handler %u did not return a f_smgr struct", + smgrhandler); + + /* + * Assert that all required callbacks are present. That makes it a bit + * easier to keep AMs up to date, e.g. when forward porting them to a new + * major version. + */ + // Assert(routine->scan_begin != NULL); + // Assert(routine->scan_end != NULL); + // Assert(routine->scan_rescan != NULL); + // Assert(routine->scan_getnextslot != NULL); + + // Assert(routine->parallelscan_estimate != NULL); + // Assert(routine->parallelscan_initialize != NULL); + // Assert(routine->parallelscan_reinitialize != NULL); + + // Assert(routine->index_fetch_begin != NULL); + // Assert(routine->index_fetch_reset != NULL); + // Assert(routine->index_fetch_end != NULL); + // Assert(routine->index_fetch_tuple != NULL); + + // Assert(routine->tuple_fetch_row_version != NULL); + // Assert(routine->tuple_tid_valid != NULL); + // Assert(routine->tuple_get_latest_tid != NULL); + // Assert(routine->tuple_satisfies_snapshot != NULL); + // Assert(routine->index_delete_tuples != NULL); + + // Assert(routine->tuple_insert != NULL); + + /* + * Could be made optional, but would require throwing error during + * parse-analysis. + // */ + // Assert(routine->tuple_insert_speculative != NULL); + // Assert(routine->tuple_complete_speculative != NULL); + + // Assert(routine->multi_insert != NULL); + // Assert(routine->tuple_delete != NULL); + // Assert(routine->tuple_update != NULL); + // Assert(routine->tuple_lock != NULL); + + // Assert(routine->relation_set_new_filenode != NULL); + // Assert(routine->relation_nontransactional_truncate != NULL); + // Assert(routine->relation_copy_data != NULL); + // Assert(routine->relation_copy_for_cluster != NULL); + // Assert(routine->relation_vacuum != NULL); + // Assert(routine->scan_analyze_next_block != NULL); + // Assert(routine->scan_analyze_next_tuple != NULL); + // Assert(routine->index_build_range_scan != NULL); + // Assert(routine->index_validate_scan != NULL); + + // Assert(routine->relation_size != NULL); + // Assert(routine->relation_needs_toast_table != NULL); + + // Assert(routine->relation_estimate_size != NULL); + + // /* optional, but one callback implies presence of the other */ + // Assert((routine->scan_bitmap_next_block == NULL) == + // (routine->scan_bitmap_next_tuple == NULL)); + // Assert(routine->scan_sample_next_block != NULL); + // Assert(routine->scan_sample_next_tuple != NULL); + + return routine; +} \ No newline at end of file diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 6a5bcded55..bb91383a03 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -192,6 +192,7 @@ ClassifyUtilityCommandAsReadOnly(Node *parsetree) case T_CreateSeqStmt: case T_CreateStatsStmt: case T_CreateStmt: + case T_CreateSmgrStmt: case T_CreateSubscriptionStmt: case T_CreateTableAsStmt: case T_CreateTableSpaceStmt: @@ -1903,6 +1904,10 @@ ProcessUtilitySlow(ParseState *pstate, address = AlterCollation((AlterCollationStmt *) parsetree); break; + + case T_CreateSmgrStmt: + address = CreateStorageManager((CreateSmgrStmt *) parsetree); + break; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(parsetree)); @@ -2640,6 +2645,9 @@ CreateCommandTag(Node *parsetree) case OBJECT_STATISTIC_EXT: tag = CMDTAG_DROP_STATISTICS; break; + case OBJECT_STORAGE_MANAGER: + tag = CMDTAG_DROP_STORAGE_MANAGER; + break; default: tag = CMDTAG_UNKNOWN; } @@ -3075,6 +3083,10 @@ CreateCommandTag(Node *parsetree) tag = CMDTAG_CREATE_STATISTICS; break; + case T_CreateSmgrStmt: + tag = CMDTAG_CREATE_STORAGE_MANAGER; + break; + case T_AlterStatsStmt: tag = CMDTAG_ALTER_STATISTICS; break; @@ -3656,6 +3668,9 @@ GetCommandLogLevel(Node *parsetree) lev = LOGSTMT_DDL; break; + case T_CreateSmgrStmt: + lev = LOGSTMT_DDL; + break; case T_CreatePublicationStmt: lev = LOGSTMT_DDL; break; diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c index c8202502c9..01ef244a80 100644 --- a/src/backend/utils/adt/pseudotypes.c +++ b/src/backend/utils/adt/pseudotypes.c @@ -389,3 +389,4 @@ PSEUDOTYPE_DUMMY_IO_FUNCS(anyelement); PSEUDOTYPE_DUMMY_IO_FUNCS(anynonarray); PSEUDOTYPE_DUMMY_IO_FUNCS(anycompatible); PSEUDOTYPE_DUMMY_IO_FUNCS(anycompatiblenonarray); +PSEUDOTYPE_DUMMY_IO_FUNCS(table_smgr_handler); diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 60e72f9e8b..6038a975ef 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -59,6 +59,7 @@ #include "catalog/pg_rewrite.h" #include "catalog/pg_shseclabel.h" #include "catalog/pg_statistic_ext.h" +#include "catalog/pg_smgr.h" #include "catalog/pg_subscription.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_trigger.h" @@ -77,6 +78,7 @@ #include "rewrite/rowsecurity.h" #include "storage/lmgr.h" #include "storage/smgr.h" +#include "storage/md.h" #include "utils/array.h" #include "utils/builtins.h" #include "utils/datum.h" @@ -1209,6 +1211,8 @@ retry: else Assert(relation->rd_rel->relam == InvalidOid); + RelationInitSmgrHandler(relation); + /* extract reloptions if any */ RelationParseRelOptions(relation, pg_class_tuple); @@ -1843,6 +1847,51 @@ RelationInitTableAccessMethod(Relation relation) InitTableAmRoutine(relation); } + +static void +InitTableSmgr(Relation relation) +{ + if (IsCatalogRelation(relation)) + { + /* + * Avoid doing a syscache lookup for catalog tables. + */ + Assert(relation->rd_rel->relsmgr == SMGR_MD_OID); + relation->rd_f_smgr = &smgr_md; + } else { + relation->rd_f_smgr = GetTableSmgr(relation->rd_smgrhandler); + } +} + +void RelationInitSmgrHandler(Relation relation) { + HeapTuple tuple; + Form_pg_smgr smgrform; + + /* + * Look up the table storage manager, save the OID of its handler + * function. + */ + + if (IsCatalogRelation(relation)) { + relation->rd_smgrhandler = F_SMGR_MD_HANDLER; + relation->rd_rel->relsmgr = SMGR_MD_OID; + } else { + tuple = SearchSysCache1(SMGROID, + ObjectIdGetDatum(relation->rd_rel->relsmgr)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for storage manager %u" , + relation->rd_rel->relsmgr); + smgrform = (Form_pg_smgr) GETSTRUCT(tuple); + relation->rd_smgrhandler = smgrform->smgrhandler; + ReleaseSysCache(tuple); + } + + Assert(relation->rd_rel->relsmgr != InvalidOid); + relation->rd_node.relSmgr = relation->rd_smgrhandler; + InitTableSmgr(relation); +} + + /* * formrdesc * @@ -1931,6 +1980,8 @@ formrdesc(const char *relationName, Oid relationReltype, relation->rd_rel->relkind = RELKIND_RELATION; relation->rd_rel->relnatts = (int16) natts; relation->rd_rel->relam = HEAP_TABLE_AM_OID; + relation->rd_rel->relsmgr = SMGR_MD_OID; + relation->rd_node.relSmgr = F_SMGR_MD_HANDLER; /* * initialize attribute tuple form @@ -1983,6 +2034,7 @@ formrdesc(const char *relationName, Oid relationReltype, * specifying that the initial filenode is the same as the OID. */ relation->rd_rel->relfilenode = InvalidOid; + relation->rd_node.relSmgr = F_SMGR_MD_HANDLER; if (IsBootstrapProcessingMode()) RelationMapUpdateMap(RelationGetRelid(relation), RelationGetRelid(relation), @@ -3459,6 +3511,7 @@ RelationBuildLocalRelation(const char *relname, TupleDesc tupDesc, Oid relid, Oid accessmtd, + Oid smgrid, Oid relfilenode, Oid reltablespace, bool shared_relation, @@ -3642,6 +3695,7 @@ RelationBuildLocalRelation(const char *relname, RelationInitPhysicalAddr(rel); rel->rd_rel->relam = accessmtd; + rel->rd_rel->relsmgr = smgrid; /* * RelationInitTableAccessMethod will do syscache lookups, so we mustn't @@ -3653,6 +3707,9 @@ RelationBuildLocalRelation(const char *relname, if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_SEQUENCE) RelationInitTableAccessMethod(rel); + rel->rd_rel->relsmgr = smgrid; + RelationInitSmgrHandler(rel); + /* * Okay to insert into the relcache hash table. * @@ -3709,7 +3766,7 @@ RelationSetNewRelfilenode(Relation relation, char persistence) /* Allocate a new relfilenode */ newrelfilenode = GetNewRelFileNode(relation->rd_rel->reltablespace, NULL, - persistence); + persistence, relation->rd_rel->relsmgr); /* * Get a writable copy of the pg_class tuple for the given relation. diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index 1912b12146..7c8de8e2db 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -64,6 +64,7 @@ #include "catalog/pg_statistic.h" #include "catalog/pg_statistic_ext.h" #include "catalog/pg_statistic_ext_data.h" +#include "catalog/pg_smgr.h" #include "catalog/pg_subscription.h" #include "catalog/pg_subscription_rel.h" #include "catalog/pg_tablespace.h" @@ -829,6 +830,28 @@ static const struct cachedesc cacheinfo[] = { }, 128 }, + {StorageManagerRelationId, /* STORANGE MANAGER OID */ + SmgrOidIndexId, + 1, + { + Anum_pg_smgr_oid, + 0, + 0, + 0, + }, + 4 + }, + {StorageManagerRelationId, /* STORANGE MANAGER NAME*/ + SmgrNameIndexId, + 1, + { + Anum_pg_smgr_smgrname, + 0, + 0, + 0, + }, + 4 + }, {SubscriptionRelationId, /* SUBSCRIPTIONNAME */ SubscriptionNameIndexId, 2, diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 1a5d924a23..5e5cb9f1f7 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -1534,6 +1534,7 @@ describeOneTableDetails(const char *schemaname, char relpersistence; char relreplident; char *relam; + char *relsmgr; } tableinfo; bool show_column_details = false; diff --git a/src/include/catalog/catalog.h b/src/include/catalog/catalog.h index 60c1215362..afdc7fe0c7 100644 --- a/src/include/catalog/catalog.h +++ b/src/include/catalog/catalog.h @@ -39,6 +39,6 @@ extern bool IsPinnedObject(Oid classId, Oid objectId); extern Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn); extern Oid GetNewRelFileNode(Oid reltablespace, Relation pg_class, - char relpersistence); + char relpersistence, Oid relsmgr); #endif /* CATALOG_H */ diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index d027075a4c..d57459226a 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -126,6 +126,7 @@ typedef enum ObjectClass OCLASS_PUBLICATION_NAMESPACE, /* pg_publication_namespace */ OCLASS_PUBLICATION_REL, /* pg_publication_rel */ OCLASS_SUBSCRIPTION, /* pg_subscription */ + OCLASS_SMGR, /* pg_smgr */ OCLASS_TRANSFORM /* pg_transform */ } ObjectClass; diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h index 07c5b88f0e..41e7e84fda 100644 --- a/src/include/catalog/heap.h +++ b/src/include/catalog/heap.h @@ -52,6 +52,7 @@ extern Relation heap_create(const char *relname, Oid relid, Oid relfilenode, Oid accessmtd, + Oid smgrid, TupleDesc tupDesc, char relkind, char relpersistence, @@ -70,6 +71,7 @@ extern Oid heap_create_with_catalog(const char *relname, Oid reloftypeid, Oid ownerid, Oid accessmtd, + Oid smgrid, TupleDesc tupdesc, List *cooked_constraints, char relkind, diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index e1f4eefa22..a6a669e655 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -52,6 +52,9 @@ CATALOG(pg_class,1259,RelationRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83,Relat /* access method; 0 if not a table / index */ Oid relam BKI_DEFAULT(heap) BKI_LOOKUP_OPT(pg_am); + /* stogare manager; */ + Oid relsmgr BKI_DEFAULT(4646); + /* identifier of physical storage file */ /* relfilenode == 0 means it is a "mapped" relation, see relmapper.c */ Oid relfilenode BKI_DEFAULT(0); diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 87aa571a33..c2469e6fc2 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -7443,6 +7443,13 @@ { oid => '268', descr => 'I/O', proname => 'table_am_handler_out', prorettype => 'cstring', proargtypes => 'table_am_handler', prosrc => 'table_am_handler_out' }, +{ oid => '4648', descr => 'I/O', + proname => 'table_smgr_handler_in', proisstrict => 'f', + prorettype => 'table_smgr_handler', proargtypes => 'cstring', + prosrc => 'table_smgr_handler_in' }, +{ oid => '4649', descr => 'I/O', + proname => 'table_smgr_handler_out', prorettype => 'cstring', + proargtypes => 'table_smgr_handler', prosrc => 'table_smgr_handler_out' }, { oid => '5086', descr => 'I/O', proname => 'anycompatible_in', prorettype => 'anycompatible', proargtypes => 'cstring', prosrc => 'anycompatible_in' }, @@ -11885,4 +11892,10 @@ prorettype => 'bytea', proargtypes => 'pg_brin_minmax_multi_summary', prosrc => 'brin_minmax_multi_summary_send' }, +# Storage access method handlers +{ oid => '4642', descr => 'md storage manager handler', + proname => 'smgr_md_handler', provolatile => 'v', + prorettype => 'table_smgr_handler', proargtypes => 'internal', + prosrc => 'smgr_md_handler' }, + ] diff --git a/src/include/catalog/pg_smgr.dat b/src/include/catalog/pg_smgr.dat new file mode 100644 index 0000000000..ee7dea1087 --- /dev/null +++ b/src/include/catalog/pg_smgr.dat @@ -0,0 +1,17 @@ +#---------------------------------------------------------------------- +# +# pg_smgr.dat +# Initial contents of the pg_smgr system catalog. +# +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/include/catalog/pg_smgr.dat +# +#---------------------------------------------------------------------- + +[ +{ oid => '4646', oid_symbol => 'SMGR_MD_OID', + descr => 'md storage manager', + smgrname => 'md', smgrhandler => 'smgr_md_handler' }, +] diff --git a/src/include/catalog/pg_smgr.h b/src/include/catalog/pg_smgr.h new file mode 100644 index 0000000000..c2152cd844 --- /dev/null +++ b/src/include/catalog/pg_smgr.h @@ -0,0 +1,52 @@ +/*------------------------------------------------------------------------- + * + * pg_smgr.h + * definition of the "storage manager" system catalog (pg_smgr) + * + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_smgr.h + * + * NOTES + * The Catalog.pm module reads this file and derives schema + * information. + * + *------------------------------------------------------------------------- + */ +/* ---------------- + * pg_smgr definition. cpp turns this into + * typedef struct FormData_pg_smgr + * ---------------- + */ + + +#ifndef PG_SMGR_H +#define PG_SMGR_H + +#include "catalog/genbki.h" +#include "catalog/pg_smgr_d.h" + +CATALOG(pg_smgr,4643,StorageManagerRelationId) +{ + Oid oid; /* oid */ + + /* storage manager name */ + NameData smgrname; + + /* handler function */ + regproc smgrhandler BKI_LOOKUP(pg_proc); +} FormData_pg_smgr; + +/* ---------------- + * Form_pg_smgr corresponds to a pointer to a tuple with + * the format of pg_smgr relation. + * ---------------- + */ +typedef FormData_pg_smgr *Form_pg_smgr; + +DECLARE_UNIQUE_INDEX(pg_smgr_name_index, 4644, SmgrNameIndexId, on pg_smgr using btree(smgrname name_ops)); +DECLARE_UNIQUE_INDEX_PKEY(pg_smgr_oid_index, 4645, SmgrOidIndexId, on pg_smgr using btree(oid oid_ops)); + +#endif /* PG_SMGR_H */ \ No newline at end of file diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat index df45879463..446c3f1c55 100644 --- a/src/include/catalog/pg_type.dat +++ b/src/include/catalog/pg_type.dat @@ -637,6 +637,11 @@ typcategory => 'P', typinput => 'table_am_handler_in', typoutput => 'table_am_handler_out', typreceive => '-', typsend => '-', typalign => 'i' }, +{ oid => '4647', + typname => 'table_smgr_handler', typlen => '4', typbyval => 't', typtype => 'p', + typcategory => 'P', typinput => 'table_smgr_handler_in', + typoutput => 'table_smgr_handler_out', typreceive => '-', typsend => '-', + typalign => 'i' }, { oid => '3831', descr => 'pseudo-type representing a range over a polymorphic base type', typname => 'anyrange', typlen => '-1', typbyval => 'f', typtype => 'p', diff --git a/src/include/commands/cluster.h b/src/include/commands/cluster.h index df8e73af40..64535486a2 100644 --- a/src/include/commands/cluster.h +++ b/src/include/commands/cluster.h @@ -37,7 +37,7 @@ extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid, LOCKMODE lockmode); extern void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal); -extern Oid make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewAccessMethod, +extern Oid make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewAccessMethod, Oid NewStorageMethod, char relpersistence, LOCKMODE lockmode); extern void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, bool is_system_catalog, diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index 56d2bb6616..99b27164dd 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -143,6 +143,11 @@ extern Oid get_table_am_oid(const char *amname, bool missing_ok); extern Oid get_am_oid(const char *amname, bool missing_ok); extern char *get_am_name(Oid amOid); +/* commands/smgrcmds.c */ +extern Oid get_smgr_oid(const char *smgrname, bool missing_ok); +extern ObjectAddress CreateStorageManager(CreateSmgrStmt *stmt); +extern char *get_smgr_name(Oid amOid); + /* support routines in commands/define.c */ extern char *defGetString(DefElem *def); diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index b3b407579b..0622739a79 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -437,6 +437,7 @@ typedef enum NodeTag T_AlterPolicyStmt, T_CreateTransformStmt, T_CreateAmStmt, + T_CreateSmgrStmt, T_CreatePublicationStmt, T_AlterPublicationStmt, T_CreateSubscriptionStmt, @@ -553,6 +554,7 @@ typedef enum NodeTag T_FdwRoutine, /* in foreign/fdwapi.h */ T_IndexAmRoutine, /* in access/amapi.h */ T_TableAmRoutine, /* in access/tableam.h */ + T_TableSmgr, /* in storage/smgr.h */ T_TsmRoutine, /* in access/tsmapi.h */ T_ForeignKeyCacheInfo, /* in utils/rel.h */ T_CallContext, /* in nodes/parsenodes.h */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 73f635b455..ac1f49422f 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -2172,6 +2172,7 @@ typedef enum ObjectType OBJECT_SEQUENCE, OBJECT_SUBSCRIPTION, OBJECT_STATISTIC_EXT, + OBJECT_STORAGE_MANAGER, OBJECT_TABCONSTRAINT, OBJECT_TABLE, OBJECT_TABLESPACE, @@ -2540,6 +2541,7 @@ typedef struct CreateStmt OnCommitAction oncommit; /* what do we do at COMMIT? */ char *tablespacename; /* table space to use, or NULL */ char *accessMethod; /* table access method */ + char *storageManager; /* table access method */ bool if_not_exists; /* just do nothing if it already exists? */ } CreateStmt; @@ -2881,6 +2883,18 @@ typedef struct CreateAmStmt char amtype; /* type of access method */ } CreateAmStmt; + +/*---------------------- + * Create STORAGE MANAGER Statement + *---------------------- + */ +typedef struct CreateSmgrStmt +{ + NodeTag type; + char *smgrname; /* access method name */ + List *handler_name; /* handler function name */ +} CreateSmgrStmt; + /* ---------------------- * Create TRIGGER Statement * ---------------------- diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index ae35f03251..0fa6186f90 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -267,6 +267,7 @@ PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("logged", LOGGED, UNRESERVED_KEYWORD, BARE_LABEL) +PG_KEYWORD("manager", MANAGER, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD, BARE_LABEL) PG_KEYWORD("matched", MATCHED, UNRESERVED_KEYWORD, BARE_LABEL) diff --git a/src/include/storage/md.h b/src/include/storage/md.h index ffffa40db7..f3b6f5942c 100644 --- a/src/include/storage/md.h +++ b/src/include/storage/md.h @@ -49,4 +49,7 @@ extern int mdsyncfiletag(const FileTag *ftag, char *path); extern int mdunlinkfiletag(const FileTag *ftag, char *path); extern bool mdfiletagmatches(const FileTag *ftag, const FileTag *candidate); + +const TableSmgr smgr_md; + #endif /* MD_H */ diff --git a/src/include/storage/relfilenode.h b/src/include/storage/relfilenode.h index 4fdc606cc3..e1d51ebc6e 100644 --- a/src/include/storage/relfilenode.h +++ b/src/include/storage/relfilenode.h @@ -59,6 +59,7 @@ typedef struct RelFileNode Oid spcNode; /* tablespace */ Oid dbNode; /* database */ Oid relNode; /* relation */ + Oid relSmgr; /* smgr handler */ } RelFileNode; /* diff --git a/src/include/storage/smgr.h b/src/include/storage/smgr.h index 7aca0d5ca5..30778c23df 100644 --- a/src/include/storage/smgr.h +++ b/src/include/storage/smgr.h @@ -14,9 +14,13 @@ #ifndef SMGR_H #define SMGR_H +#include "postgres.h" + #include "lib/ilist.h" #include "storage/block.h" #include "storage/relfilenode.h" +#include "utils/snapshot.h" +#include "nodes/nodes.h" struct f_smgr; @@ -61,8 +65,11 @@ typedef struct SMgrRelationData * Fields below here are intended to be private to smgr.c and its * submodules. Do not touch them from elsewhere. */ - const struct f_smgr *smgr; /* storage manager selector */ + /* + * Storage manager. + */ + const struct TableSmgr *smgr; /* * for md.c; per-fork arrays of the number of open segments * (md_num_open_segs) and the segments themselves (md_seg_fds). @@ -90,8 +97,12 @@ typedef SMgrRelationData *SMgrRelation; * would normally be errors should be allowed during bootstrap and/or WAL * recovery --- see comments in md.c for details. */ -typedef struct f_smgr +typedef struct TableSmgr { + /* this must be set to T_TableSmgr */ + NodeTag type; + + void (*smgr_init) (void); /* may be NULL */ void (*smgr_shutdown) (void); /* may be NULL */ void (*smgr_open) (SMgrRelation reln); @@ -115,21 +126,7 @@ typedef struct f_smgr void (*smgr_truncate) (SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks); void (*smgr_immedsync) (SMgrRelation reln, ForkNumber forknum); -} f_smgr; - -typedef void (*smgr_init_hook_type) (void); -typedef void (*smgr_shutdown_hook_type) (void); -extern PGDLLIMPORT smgr_init_hook_type smgr_init_hook; -extern PGDLLIMPORT smgr_shutdown_hook_type smgr_shutdown_hook; -extern void smgr_init_standard(void); -extern void smgr_shutdown_standard(void); - - -typedef const f_smgr *(*smgr_hook_type) (BackendId backend, RelFileNode rnode); -extern PGDLLIMPORT smgr_hook_type smgr_hook; -extern const f_smgr *smgr_standard(BackendId backend, RelFileNode rnode); - -extern const f_smgr *smgr(BackendId backend, RelFileNode rnode); +} TableSmgr; extern void smgrinit(void); extern SMgrRelation smgropen(RelFileNode rnode, BackendId backend); @@ -162,4 +159,8 @@ extern void smgrimmedsync(SMgrRelation reln, ForkNumber forknum); extern void AtEOXact_SMgr(void); extern bool ProcessBarrierSmgrRelease(void); + +TableSmgr * +GetTableSmgr(Oid smgrhandler); + #endif /* SMGR_H */ diff --git a/src/include/tcop/cmdtaglist.h b/src/include/tcop/cmdtaglist.h index 2b1163ce33..28dff1f8ad 100644 --- a/src/include/tcop/cmdtaglist.h +++ b/src/include/tcop/cmdtaglist.h @@ -111,6 +111,7 @@ PG_CMDTAG(CMDTAG_CREATE_SCHEMA, "CREATE SCHEMA", true, false, false) PG_CMDTAG(CMDTAG_CREATE_SEQUENCE, "CREATE SEQUENCE", true, false, false) PG_CMDTAG(CMDTAG_CREATE_SERVER, "CREATE SERVER", true, false, false) PG_CMDTAG(CMDTAG_CREATE_STATISTICS, "CREATE STATISTICS", true, false, false) +PG_CMDTAG(CMDTAG_CREATE_STORAGE_MANAGER, "CREATE STORAGE MANAGER", true, false, false) PG_CMDTAG(CMDTAG_CREATE_SUBSCRIPTION, "CREATE SUBSCRIPTION", true, false, false) PG_CMDTAG(CMDTAG_CREATE_TABLE, "CREATE TABLE", true, false, false) PG_CMDTAG(CMDTAG_CREATE_TABLE_AS, "CREATE TABLE AS", true, false, false) @@ -164,6 +165,7 @@ PG_CMDTAG(CMDTAG_DROP_SCHEMA, "DROP SCHEMA", true, false, false) PG_CMDTAG(CMDTAG_DROP_SEQUENCE, "DROP SEQUENCE", true, false, false) PG_CMDTAG(CMDTAG_DROP_SERVER, "DROP SERVER", true, false, false) PG_CMDTAG(CMDTAG_DROP_STATISTICS, "DROP STATISTICS", true, false, false) +PG_CMDTAG(CMDTAG_DROP_STORAGE_MANAGER, "DROP STORAGE MANAGER", false, false, false) PG_CMDTAG(CMDTAG_DROP_SUBSCRIPTION, "DROP SUBSCRIPTION", true, false, false) PG_CMDTAG(CMDTAG_DROP_TABLE, "DROP TABLE", true, false, false) PG_CMDTAG(CMDTAG_DROP_TABLESPACE, "DROP TABLESPACE", false, false, false) diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 90b3c49bc1..7fa646fe0a 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -184,6 +184,13 @@ typedef struct RelationData */ const struct TableAmRoutine *rd_tableam; + + Oid rd_smgrhandler; /* OID of index smgr handler function */ + /* + * Storage manager. + */ + const struct TableSmgr *rd_f_smgr; + /* These are non-NULL only for an index relation: */ Form_pg_index rd_index; /* pg_index tuple describing this index */ /* use "struct" here to avoid needing to include htup.h: */ diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h index 86dddbd975..2c95debeb7 100644 --- a/src/include/utils/relcache.h +++ b/src/include/utils/relcache.h @@ -79,6 +79,7 @@ extern void RelationBuildPublicationDesc(Relation relation, struct PublicationDesc *pubdesc); extern void RelationInitTableAccessMethod(Relation relation); +extern void RelationInitSmgrHandler(Relation relation); /* * Routines to support ereport() reports of relation-related errors @@ -103,6 +104,7 @@ extern Relation RelationBuildLocalRelation(const char *relname, TupleDesc tupDesc, Oid relid, Oid accessmtd, + Oid smgrid, Oid relfilenode, Oid reltablespace, bool shared_relation, diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h index 4463ea66be..8ac7e10760 100644 --- a/src/include/utils/syscache.h +++ b/src/include/utils/syscache.h @@ -95,6 +95,8 @@ enum SysCacheIdentifier STATEXTNAMENSP, STATEXTOID, STATRELATTINH, + SMGROID, + SMGRNAME, SUBSCRIPTIONNAME, SUBSCRIPTIONOID, SUBSCRIPTIONRELMAP, diff --git a/src/test/modules/test_oat_hooks/test_oat_hooks.c b/src/test/modules/test_oat_hooks/test_oat_hooks.c index 7ef272cc7a..44f8fd3131 100644 --- a/src/test/modules/test_oat_hooks/test_oat_hooks.c +++ b/src/test/modules/test_oat_hooks/test_oat_hooks.c @@ -1485,6 +1485,9 @@ nodetag_to_string(NodeTag tag) case T_CreateStatsStmt: return "CreateStatsStmt"; break; + case T_CreateSmgrStmt: + return "CreateSmgrStmt"; + break; case T_AlterCollationStmt: return "AlterCollationStmt"; break; @@ -1713,6 +1716,9 @@ nodetag_to_string(NodeTag tag) case T_TableAmRoutine: return "TableAmRoutine"; break; + case T_TableSmgr: + return "TableSmgr"; + break; case T_TsmRoutine: return "TsmRoutine"; break; -- 2.25.1