/*
* Check that a relation's relkind and access method are both supported.
*/
- if (ctx.rel->rd_rel->relkind != RELKIND_RELATION &&
- ctx.rel->rd_rel->relkind != RELKIND_MATVIEW &&
- ctx.rel->rd_rel->relkind != RELKIND_TOASTVALUE &&
+ if (!RELKIND_HAS_TABLE_AM(ctx.rel->rd_rel->relkind) &&
ctx.rel->rd_rel->relkind != RELKIND_SEQUENCE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
/*
* Check target relation.
*/
- if (rel->rd_rel->relkind != RELKIND_RELATION &&
- rel->rd_rel->relkind != RELKIND_MATVIEW &&
- rel->rd_rel->relkind != RELKIND_TOASTVALUE)
+ if (!RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cannot operate on relation \"%s\"",
static void
check_relation_relkind(Relation rel)
{
- if (rel->rd_rel->relkind != RELKIND_RELATION &&
- rel->rd_rel->relkind != RELKIND_MATVIEW &&
- rel->rd_rel->relkind != RELKIND_TOASTVALUE)
+ if (!RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("relation \"%s\" is of wrong relation kind",
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot access temporary tables of other sessions")));
- switch (rel->rd_rel->relkind)
+ if (RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind) ||
+ rel->rd_rel->relkind == RELKIND_SEQUENCE)
{
- case RELKIND_RELATION:
- case RELKIND_MATVIEW:
- case RELKIND_TOASTVALUE:
- case RELKIND_SEQUENCE:
return pgstat_heap(rel, fcinfo);
- case RELKIND_INDEX:
+ }
+ else if (rel->rd_rel->relkind == RELKIND_INDEX)
+ {
switch (rel->rd_rel->relam)
{
case BTREE_AM_OID:
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("index \"%s\" (%s) is not supported",
RelationGetRelationName(rel), err)));
- break;
-
- default:
+ }
+ else
+ {
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot get tuple-level statistics for relation \"%s\"",
*relfrozenxid = InvalidTransactionId;
*relminmxid = InvalidMultiXactId;
- /* Handle reltablespace for specific relkinds. */
- switch (relkind)
- {
- case RELKIND_VIEW:
- case RELKIND_COMPOSITE_TYPE:
- case RELKIND_FOREIGN_TABLE:
-
- /*
- * Force reltablespace to zero if the relation has no physical
- * storage. This is mainly just for cleanliness' sake.
- *
- * Partitioned tables and indexes don't have physical storage
- * either, but we want to keep their tablespace settings so that
- * their children can inherit it.
- */
- reltablespace = InvalidOid;
- break;
-
- case RELKIND_SEQUENCE:
-
- /*
- * Force reltablespace to zero for sequences, since we don't
- * support moving them around into different tablespaces.
- */
- reltablespace = InvalidOid;
- break;
- default:
- break;
- }
+ /*
+ * Force reltablespace to zero if the relation kind does not support
+ * tablespaces. This is mainly just for cleanliness' sake.
+ */
+ if (!RELKIND_HAS_TABLESPACE(relkind))
+ reltablespace = InvalidOid;
/*
* Decide whether to create storage. If caller passed a valid relfilenode,
/*
* Have the storage manager create the relation's disk file, if needed.
*
- * For relations the callback creates both the main and the init fork, for
- * indexes only the main fork is created. The other forks will be created
- * on demand.
+ * For tables, the AM callback creates both the main and the init fork.
+ * For others, only the main fork is created; the other forks will be
+ * created on demand.
*/
if (create_storage)
{
- switch (rel->rd_rel->relkind)
- {
- case RELKIND_VIEW:
- case RELKIND_COMPOSITE_TYPE:
- case RELKIND_FOREIGN_TABLE:
- case RELKIND_PARTITIONED_TABLE:
- case RELKIND_PARTITIONED_INDEX:
- Assert(false);
- break;
-
- case RELKIND_INDEX:
- case RELKIND_SEQUENCE:
- RelationCreateStorage(rel->rd_node, relpersistence);
- break;
-
- case RELKIND_RELATION:
- case RELKIND_TOASTVALUE:
- case RELKIND_MATVIEW:
- table_relation_set_new_filenode(rel, &rel->rd_node,
- relpersistence,
- relfrozenxid, relminmxid);
- break;
- }
+ if (RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind))
+ table_relation_set_new_filenode(rel, &rel->rd_node,
+ relpersistence,
+ relfrozenxid, relminmxid);
+ else if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
+ RelationCreateStorage(rel->rd_node, relpersistence);
+ else
+ Assert(false);
}
/*
*/
new_rel_reltup = new_rel_desc->rd_rel;
- switch (relkind)
+ /* The relation is empty */
+ new_rel_reltup->relpages = 0;
+ new_rel_reltup->reltuples = -1;
+ new_rel_reltup->relallvisible = 0;
+
+ /* Sequences always have a known size */
+ if (relkind == RELKIND_SEQUENCE)
{
- case RELKIND_RELATION:
- case RELKIND_MATVIEW:
- case RELKIND_INDEX:
- case RELKIND_TOASTVALUE:
- /* The relation is real, but as yet empty */
- new_rel_reltup->relpages = 0;
- new_rel_reltup->reltuples = -1;
- new_rel_reltup->relallvisible = 0;
- break;
- case RELKIND_SEQUENCE:
- /* Sequences always have a known size */
- new_rel_reltup->relpages = 1;
- new_rel_reltup->reltuples = 1;
- new_rel_reltup->relallvisible = 0;
- break;
- default:
- /* Views, etc, have no disk storage */
- new_rel_reltup->relpages = 0;
- new_rel_reltup->reltuples = -1;
- new_rel_reltup->relallvisible = 0;
- break;
+ new_rel_reltup->relpages = 1;
+ new_rel_reltup->reltuples = 1;
}
new_rel_reltup->relfrozenxid = relfrozenxid;
if (!OidIsValid(relid))
{
/* Use binary-upgrade override for pg_class.oid/relfilenode? */
- if (IsBinaryUpgrade &&
- (relkind == RELKIND_RELATION || relkind == RELKIND_SEQUENCE ||
- relkind == RELKIND_VIEW || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_COMPOSITE_TYPE || relkind == RELKIND_FOREIGN_TABLE ||
- relkind == RELKIND_PARTITIONED_TABLE))
+ if (IsBinaryUpgrade)
{
- if (!OidIsValid(binary_upgrade_next_heap_pg_class_oid))
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("pg_class heap OID value not set when in binary upgrade mode")));
+ /*
+ * Indexes are not supported here; they use
+ * binary_upgrade_next_index_pg_class_oid.
+ */
+ Assert(relkind != RELKIND_INDEX);
+ Assert(relkind != RELKIND_PARTITIONED_INDEX);
- relid = binary_upgrade_next_heap_pg_class_oid;
- binary_upgrade_next_heap_pg_class_oid = InvalidOid;
- }
- /* There might be no TOAST table, so we have to test for it. */
- else if (IsBinaryUpgrade &&
- OidIsValid(binary_upgrade_next_toast_pg_class_oid) &&
- relkind == RELKIND_TOASTVALUE)
- {
- relid = binary_upgrade_next_toast_pg_class_oid;
- binary_upgrade_next_toast_pg_class_oid = InvalidOid;
+ if (relkind == RELKIND_TOASTVALUE)
+ {
+ /* There might be no TOAST table, so we have to test for it. */
+ if (OidIsValid(binary_upgrade_next_toast_pg_class_oid))
+ {
+ relid = binary_upgrade_next_toast_pg_class_oid;
+ binary_upgrade_next_toast_pg_class_oid = InvalidOid;
+ }
+ }
+ else
+ {
+ if (!OidIsValid(binary_upgrade_next_heap_pg_class_oid))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("pg_class heap OID value not set when in binary upgrade mode")));
+
+ relid = binary_upgrade_next_heap_pg_class_oid;
+ binary_upgrade_next_heap_pg_class_oid = InvalidOid;
+ }
}
- else
+
+ if (!OidIsValid(relid))
relid = GetNewRelFileNode(reltablespace, pg_class_desc,
relpersistence);
}
/*
* Make a dependency link to force the relation to be deleted if its
- * access method is. Do this only for relation and materialized views.
+ * access method is.
*
* No need to add an explicit dependency for the toast table, as the
* main table depends on it.
*/
- if (relkind == RELKIND_RELATION ||
- relkind == RELKIND_MATVIEW)
+ if (RELKIND_HAS_TABLE_AM(relkind) && relkind != RELKIND_TOASTVALUE)
{
ObjectAddressSet(referenced, AccessMethodRelationId, accessmtd);
add_exact_object_address(&referenced, addrs);
/*
* Schedule physical removal of the files (if any)
*/
- if (userIndexRelation->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
+ if (RELKIND_HAS_STORAGE(userIndexRelation->rd_rel->relkind))
RelationDropStorage(userIndexRelation);
/*
{
ReindexErrorInfo *errinfo = (ReindexErrorInfo *) arg;
- Assert(errinfo->relkind == RELKIND_PARTITIONED_INDEX ||
- errinfo->relkind == RELKIND_PARTITIONED_TABLE);
+ Assert(RELKIND_HAS_PARTITIONS(errinfo->relkind));
if (errinfo->relkind == RELKIND_PARTITIONED_TABLE)
errcontext("while reindexing partitioned table \"%s.%s\"",
ErrorContextCallback errcallback;
ReindexErrorInfo errinfo;
- Assert(relkind == RELKIND_PARTITIONED_INDEX ||
- relkind == RELKIND_PARTITIONED_TABLE);
+ Assert(RELKIND_HAS_PARTITIONS(relkind));
/*
* Check if this runs in a transaction block, with an error callback to
* Partitioned tables and indexes can never be processed directly, and
* a list of their leaves should be built first.
*/
- Assert(relkind != RELKIND_PARTITIONED_INDEX &&
- relkind != RELKIND_PARTITIONED_TABLE);
+ Assert(!RELKIND_HAS_PARTITIONS(relkind));
if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
relpersistence != RELPERSISTENCE_TEMP)
errmsg("specifying a table access method is not supported on a partitioned table")));
}
- else if (relkind == RELKIND_RELATION ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_MATVIEW)
+ else if (RELKIND_HAS_TABLE_AM(relkind))
accessMethod = default_table_access_method;
/* look up the access method, verify it is for a table */
}
else
{
- Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
- rel->rd_rel->relkind == RELKIND_MATVIEW ||
- rel->rd_rel->relkind == RELKIND_TOASTVALUE);
+ Assert(RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind));
table_relation_copy_data(rel, &newrnode);
}
BlockNumber relallvisible;
double density;
- switch (rel->rd_rel->relkind)
+ if (RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind))
{
- case RELKIND_RELATION:
- case RELKIND_MATVIEW:
- case RELKIND_TOASTVALUE:
table_relation_estimate_size(rel, attr_widths, pages, tuples,
allvisfrac);
- break;
-
- case RELKIND_INDEX:
-
+ }
+ else if (rel->rd_rel->relkind == RELKIND_INDEX)
+ {
/*
* XXX: It'd probably be good to move this into a callback,
* individual index types e.g. know if they have a metapage.
{
*tuples = 0;
*allvisfrac = 0;
- break;
+ return;
}
/* coerce values in pg_class to more desirable types */
*allvisfrac = 1;
else
*allvisfrac = (double) relallvisible / curpages;
- break;
-
- case RELKIND_SEQUENCE:
- /* Sequences always have a known size */
- *pages = 1;
- *tuples = 1;
- *allvisfrac = 0;
- break;
- case RELKIND_FOREIGN_TABLE:
- /* Just use whatever's in pg_class */
- /* Note that FDW must cope if reltuples is -1! */
+ }
+ else
+ {
+ /*
+ * Just use whatever's in pg_class. This covers foreign tables,
+ * sequences, and also relkinds without storage (shouldn't get
+ * here?); see initializations in AddNewRelationTuple(). Note
+ * that FDW must cope if reltuples is -1!
+ */
*pages = rel->rd_rel->relpages;
*tuples = rel->rd_rel->reltuples;
*allvisfrac = 0;
- break;
- default:
- /* else it has no disk storage; probably shouldn't get here? */
- *pages = 0;
- *tuples = 0;
- *allvisfrac = 0;
- break;
}
}
BlockNumber
RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum)
{
- switch (relation->rd_rel->relkind)
+ if (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind))
{
- case RELKIND_SEQUENCE:
- case RELKIND_INDEX:
- return smgrnblocks(RelationGetSmgr(relation), forkNum);
-
- case RELKIND_RELATION:
- case RELKIND_TOASTVALUE:
- case RELKIND_MATVIEW:
- {
- /*
- * Not every table AM uses BLCKSZ wide fixed size blocks.
- * Therefore tableam returns the size in bytes - but for the
- * purpose of this routine, we want the number of blocks.
- * Therefore divide, rounding up.
- */
- uint64 szbytes;
+ /*
+ * Not every table AM uses BLCKSZ wide fixed size blocks.
+ * Therefore tableam returns the size in bytes - but for the
+ * purpose of this routine, we want the number of blocks.
+ * Therefore divide, rounding up.
+ */
+ uint64 szbytes;
- szbytes = table_relation_size(relation, forkNum);
+ szbytes = table_relation_size(relation, forkNum);
- return (szbytes + (BLCKSZ - 1)) / BLCKSZ;
- }
- case RELKIND_VIEW:
- case RELKIND_COMPOSITE_TYPE:
- case RELKIND_FOREIGN_TABLE:
- case RELKIND_PARTITIONED_INDEX:
- case RELKIND_PARTITIONED_TABLE:
- default:
- Assert(false);
- break;
+ return (szbytes + (BLCKSZ - 1)) / BLCKSZ;
+ }
+ else if (RELKIND_HAS_STORAGE(relation->rd_rel->relkind))
+ {
+ return smgrnblocks(RelationGetSmgr(relation), forkNum);
}
+ else
+ Assert(false);
return 0; /* keep compiler quiet */
}
relispartition = get_rel_relispartition(relid);
/* Only allow relation types that can appear in partition trees. */
- if (!relispartition &&
- relkind != RELKIND_PARTITIONED_TABLE &&
- relkind != RELKIND_PARTITIONED_INDEX)
+ if (!relispartition && !RELKIND_HAS_PARTITIONS(relkind))
return false;
return true;
nulls[1] = true;
/* isleaf */
- values[2] = BoolGetDatum(relkind != RELKIND_PARTITIONED_TABLE &&
- relkind != RELKIND_PARTITIONED_INDEX);
+ values[2] = BoolGetDatum(!RELKIND_HAS_PARTITIONS(relkind));
/* level */
if (relid != rootrelid)
/*
* initialize access method information
*/
- 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;
- }
+ if (relation->rd_rel->relkind == RELKIND_INDEX ||
+ relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
+ RelationInitIndexAccessInfo(relation);
+ else if (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind) ||
+ relation->rd_rel->relkind == RELKIND_SEQUENCE)
+ RelationInitTableAccessMethod(relation);
+ else
+ Assert(relation->rd_rel->relam == InvalidOid);
/* extract reloptions if any */
RelationParseRelOptions(relation, pg_class_tuple);
/*
* Look up the index's 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",
* seem prudent to show that in the catalog. So just overwrite it
* here.
*/
+ Assert(relation->rd_rel->relam == InvalidOid);
relation->rd_amhandler = F_HEAP_TABLEAM_HANDLER;
}
else if (IsCatalogRelation(relation))
*/
MemoryContextSwitchTo(oldcxt);
- if (relkind == RELKIND_RELATION ||
- relkind == RELKIND_SEQUENCE ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_MATVIEW)
+ if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_SEQUENCE)
RelationInitTableAccessMethod(rel);
/*
newrnode = relation->rd_node;
newrnode.relNode = newrelfilenode;
- switch (relation->rd_rel->relkind)
+ if (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind))
{
- case RELKIND_INDEX:
- case RELKIND_SEQUENCE:
- {
- /* handle these directly, at least for now */
- SMgrRelation srel;
-
- srel = RelationCreateStorage(newrnode, persistence);
- smgrclose(srel);
- }
- break;
-
- case RELKIND_RELATION:
- case RELKIND_TOASTVALUE:
- case RELKIND_MATVIEW:
- table_relation_set_new_filenode(relation, &newrnode,
- persistence,
- &freezeXid, &minmulti);
- break;
+ table_relation_set_new_filenode(relation, &newrnode,
+ persistence,
+ &freezeXid, &minmulti);
+ }
+ else if (RELKIND_HAS_STORAGE(relation->rd_rel->relkind))
+ {
+ /* handle these directly, at least for now */
+ SMgrRelation srel;
- default:
- /* we shouldn't be called for anything else */
- elog(ERROR, "relation \"%s\" does not have storage",
- RelationGetRelationName(relation));
- break;
+ srel = RelationCreateStorage(newrnode, persistence);
+ smgrclose(srel);
+ }
+ else
+ {
+ /* we shouldn't be called for anything else */
+ elog(ERROR, "relation \"%s\" does not have storage",
+ RelationGetRelationName(relation));
}
/*
/* Reload tableam data if needed */
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))
+ (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind) || relation->rd_rel->relkind == RELKIND_SEQUENCE))
{
RelationInitTableAccessMethod(relation);
Assert(relation->rd_tableam != NULL);
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)
+ if (RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind) || rel->rd_rel->relkind == RELKIND_SEQUENCE)
RelationInitTableAccessMethod(rel);
Assert(rel->rd_index == NULL);
if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
{
+ char *tablespace = NULL;
char *tableam = NULL;
- if (tbinfo->relkind == RELKIND_RELATION ||
- tbinfo->relkind == RELKIND_MATVIEW)
+ /*
+ * _selectTablespace() relies on tablespace-enabled objects in the
+ * default tablespace to have a tablespace of "" (empty string) versus
+ * non-tablespace-enabled objects to have a tablespace of NULL.
+ * getTables() sets tbinfo->reltablespace to "" for the default
+ * tablespace (not NULL).
+ */
+ if (RELKIND_HAS_TABLESPACE(tbinfo->relkind))
+ tablespace = tbinfo->reltablespace;
+
+ if (RELKIND_HAS_TABLE_AM(tbinfo->relkind))
tableam = tbinfo->amname;
ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
ARCHIVE_OPTS(.tag = tbinfo->dobj.name,
.namespace = tbinfo->dobj.namespace->dobj.name,
- .tablespace = (tbinfo->relkind == RELKIND_VIEW) ?
- NULL : tbinfo->reltablespace,
+ .tablespace = tablespace,
.tableam = tableam,
.owner = tbinfo->rolname,
.description = reltypename,
(relkind) == RELKIND_TOASTVALUE || \
(relkind) == RELKIND_MATVIEW)
+#define RELKIND_HAS_PARTITIONS(relkind) \
+ ((relkind) == RELKIND_PARTITIONED_TABLE || \
+ (relkind) == RELKIND_PARTITIONED_INDEX)
+
+/*
+ * Relation kinds that support tablespaces: All relation kinds with storage
+ * support tablespaces, except that we don't support moving sequences around
+ * into different tablespaces. Partitioned tables and indexes don't have
+ * physical storage, but they have a tablespace settings so that their
+ * children can inherit it.
+ */
+#define RELKIND_HAS_TABLESPACE(relkind) \
+ ((RELKIND_HAS_STORAGE(relkind) || RELKIND_HAS_PARTITIONS(relkind)) \
+ && (relkind) != RELKIND_SEQUENCE)
+
+/*
+ * Relation kinds with a table access method (rd_tableam). Although sequences
+ * use the heap table AM, they are enough of a special case in most uses that
+ * they are not included here.
+ */
+#define RELKIND_HAS_TABLE_AM(relkind) \
+ ((relkind) == RELKIND_RELATION || \
+ (relkind) == RELKIND_TOASTVALUE || \
+ (relkind) == RELKIND_MATVIEW)
+
extern int errdetail_relkind_not_supported(char relkind);
#endif /* EXPOSE_TO_CLIENT_CODE */