Towards easier AMs: Cleaning up inappropriate use of name "relkind"

Started by Mark Dilgerover 5 years ago15 messages
#1Mark Dilger
mark.dilger@enterprisedb.com
1 attachment(s)

Hackers,

The name "relkind" normally refers to a field of type 'char' with values like 'r' for "table" and 'i' for "index". In AlterTableStmt and CreateTableAsStmt, this naming convention was abused for a field of type enum ObjectType. Often, such fields are named "objtype", though also "kind", "removeType", "renameType", etc.

I don't care to debate those other names, though in passing I'll say that "kind" seems not great. The "relkind" name is particularly bad, though. It is confusing in functions that also operate on a RangeTblEntry object, which also has a field named "relkind", and is confusing in light of the function get_relkind_objtype() which maps from "relkind" to "objtype", implying quite correctly that those two things are distinct.

The attached patch cleans this up. How many toes am I stepping on here? Changing the names was straightforward and doesn't seem to cause any issues with 'make check-world'. Any objection?

For those interested in the larger context of this patch, I am trying to clean up any part of the code that makes it harder to write and test new access methods. When implementing a new AM, one currently needs to `grep -i relkind` to find a long list of files that need special treatment. One then needs to consider whether special logic for the new AM needs to be inserted into all these spots. As such, it is nice if these spots have as little confusing naming as possible. This patch makes that process a little easier. I have another patch (to be posted shortly) that cleans up the #define RELKIND_XXX stuff using a new RelKind enum and special macros while keeping the relkind fields as type 'char'. Along with converting code to use switch(relkind) rather than if (relkind...) statements, the compiler now warns on unhandled cases when you add a new RelKind to the list, making it easier to find all the places you need to update. I decided to keep that work independent of this patch, as the code is logically distinct.

Attachments:

v1-0001-Renaming-relkind-as-objtype-where-appropriate.patchapplication/octet-stream; name=v1-0001-Renaming-relkind-as-objtype-where-appropriate.patch; x-unix-mode=0644Download
From a6f1339490431e3ebae5fd98a74c33b84af12c97 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Wed, 3 Jun 2020 09:22:39 -0700
Subject: [PATCH v1] Renaming relkind as objtype where appropriate

"relkind" normally refers to a field of type 'char' with values
like 'r' for "relation" and 'i' for "index".  In AlterTableStmt
and CreateTableAsStmt, this naming convention was abused for a
field of type enum ObjectType.  Usually, such fields are named
"objtype".  This leads particularly to confusion in functions that
also operate on a RangeTableEntry object, which also has a field
named relkind.

The naming goes back to commit 09d4e96d7e9 from 2004.  That
commit message does not explain the choice, but the two ObjectType
enum values visible in the diffs are OBJECT_TABLE and OBJECT_INDEX,
which seems to explain the naming choice.
---
 src/backend/commands/tablecmds.c   |  4 +--
 src/backend/nodes/copyfuncs.c      |  4 +--
 src/backend/nodes/equalfuncs.c     |  4 +--
 src/backend/parser/analyze.c       |  4 +--
 src/backend/parser/gram.y          | 44 +++++++++++++++---------------
 src/backend/parser/parse_utilcmd.c |  6 ++--
 src/backend/tcop/utility.c         |  4 +--
 src/include/nodes/parsenodes.h     |  4 +--
 8 files changed, 37 insertions(+), 37 deletions(-)

diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 2ab02e01a0..4672986563 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -4709,7 +4709,7 @@ ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
 					 -1);
 	atstmt->relation->inh = recurse;
 	atstmt->cmds = list_make1(cmd);
-	atstmt->relkind = OBJECT_TABLE; /* needn't be picky here */
+	atstmt->objtype = OBJECT_TABLE; /* needn't be picky here */
 	atstmt->missing_ok = false;
 
 	/* Transform the AlterTableStmt */
@@ -15596,7 +15596,7 @@ RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid,
 		reltype = ((AlterObjectSchemaStmt *) stmt)->objectType;
 
 	else if (IsA(stmt, AlterTableStmt))
-		reltype = ((AlterTableStmt *) stmt)->relkind;
+		reltype = ((AlterTableStmt *) stmt)->objtype;
 	else
 	{
 		elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt));
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index d8cf87e6d0..89c409de66 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3204,7 +3204,7 @@ _copyAlterTableStmt(const AlterTableStmt *from)
 
 	COPY_NODE_FIELD(relation);
 	COPY_NODE_FIELD(cmds);
-	COPY_SCALAR_FIELD(relkind);
+	COPY_SCALAR_FIELD(objtype);
 	COPY_SCALAR_FIELD(missing_ok);
 
 	return newnode;
@@ -3980,7 +3980,7 @@ _copyCreateTableAsStmt(const CreateTableAsStmt *from)
 
 	COPY_NODE_FIELD(query);
 	COPY_NODE_FIELD(into);
-	COPY_SCALAR_FIELD(relkind);
+	COPY_SCALAR_FIELD(objtype);
 	COPY_SCALAR_FIELD(is_select_into);
 	COPY_SCALAR_FIELD(if_not_exists);
 
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 627b026b19..e3f33c40be 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1087,7 +1087,7 @@ _equalAlterTableStmt(const AlterTableStmt *a, const AlterTableStmt *b)
 {
 	COMPARE_NODE_FIELD(relation);
 	COMPARE_NODE_FIELD(cmds);
-	COMPARE_SCALAR_FIELD(relkind);
+	COMPARE_SCALAR_FIELD(objtype);
 	COMPARE_SCALAR_FIELD(missing_ok);
 
 	return true;
@@ -1735,7 +1735,7 @@ _equalCreateTableAsStmt(const CreateTableAsStmt *a, const CreateTableAsStmt *b)
 {
 	COMPARE_NODE_FIELD(query);
 	COMPARE_NODE_FIELD(into);
-	COMPARE_SCALAR_FIELD(relkind);
+	COMPARE_SCALAR_FIELD(objtype);
 	COMPARE_SCALAR_FIELD(is_select_into);
 	COMPARE_SCALAR_FIELD(if_not_exists);
 
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 401da5dedf..c159fb2957 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -229,7 +229,7 @@ transformOptionalSelectInto(ParseState *pstate, Node *parseTree)
 
 			ctas->query = parseTree;
 			ctas->into = stmt->intoClause;
-			ctas->relkind = OBJECT_TABLE;
+			ctas->objtype = OBJECT_TABLE;
 			ctas->is_select_into = true;
 
 			/*
@@ -2572,7 +2572,7 @@ transformCreateTableAsStmt(ParseState *pstate, CreateTableAsStmt *stmt)
 	stmt->query = (Node *) query;
 
 	/* additional work needed for CREATE MATERIALIZED VIEW */
-	if (stmt->relkind == OBJECT_MATVIEW)
+	if (stmt->objtype == OBJECT_MATVIEW)
 	{
 		/*
 		 * Prohibit a data-modifying CTE in the query used to create a
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index e66b850e1a..b9dd9fd036 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -1848,7 +1848,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $3;
 					n->cmds = $4;
-					n->relkind = OBJECT_TABLE;
+					n->objtype = OBJECT_TABLE;
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
@@ -1857,7 +1857,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $5;
 					n->cmds = $6;
-					n->relkind = OBJECT_TABLE;
+					n->objtype = OBJECT_TABLE;
 					n->missing_ok = true;
 					$$ = (Node *)n;
 				}
@@ -1866,7 +1866,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $3;
 					n->cmds = list_make1($4);
-					n->relkind = OBJECT_TABLE;
+					n->objtype = OBJECT_TABLE;
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
@@ -1875,7 +1875,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $5;
 					n->cmds = list_make1($6);
-					n->relkind = OBJECT_TABLE;
+					n->objtype = OBJECT_TABLE;
 					n->missing_ok = true;
 					$$ = (Node *)n;
 				}
@@ -1906,7 +1906,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $3;
 					n->cmds = $4;
-					n->relkind = OBJECT_INDEX;
+					n->objtype = OBJECT_INDEX;
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
@@ -1915,7 +1915,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $5;
 					n->cmds = $6;
-					n->relkind = OBJECT_INDEX;
+					n->objtype = OBJECT_INDEX;
 					n->missing_ok = true;
 					$$ = (Node *)n;
 				}
@@ -1924,7 +1924,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $3;
 					n->cmds = list_make1($4);
-					n->relkind = OBJECT_INDEX;
+					n->objtype = OBJECT_INDEX;
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
@@ -1955,7 +1955,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $3;
 					n->cmds = $4;
-					n->relkind = OBJECT_SEQUENCE;
+					n->objtype = OBJECT_SEQUENCE;
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
@@ -1964,7 +1964,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $5;
 					n->cmds = $6;
-					n->relkind = OBJECT_SEQUENCE;
+					n->objtype = OBJECT_SEQUENCE;
 					n->missing_ok = true;
 					$$ = (Node *)n;
 				}
@@ -1973,7 +1973,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $3;
 					n->cmds = $4;
-					n->relkind = OBJECT_VIEW;
+					n->objtype = OBJECT_VIEW;
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
@@ -1982,7 +1982,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $5;
 					n->cmds = $6;
-					n->relkind = OBJECT_VIEW;
+					n->objtype = OBJECT_VIEW;
 					n->missing_ok = true;
 					$$ = (Node *)n;
 				}
@@ -1991,7 +1991,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $4;
 					n->cmds = $5;
-					n->relkind = OBJECT_MATVIEW;
+					n->objtype = OBJECT_MATVIEW;
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
@@ -2000,7 +2000,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $6;
 					n->cmds = $7;
-					n->relkind = OBJECT_MATVIEW;
+					n->objtype = OBJECT_MATVIEW;
 					n->missing_ok = true;
 					$$ = (Node *)n;
 				}
@@ -2842,7 +2842,7 @@ AlterCompositeTypeStmt:
 					/* can't use qualified_name, sigh */
 					n->relation = makeRangeVarFromAnyName($3, @3, yyscanner);
 					n->cmds = $4;
-					n->relkind = OBJECT_TYPE;
+					n->objtype = OBJECT_TYPE;
 					$$ = (Node *)n;
 				}
 			;
@@ -4058,7 +4058,7 @@ CreateAsStmt:
 					CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
 					ctas->query = $6;
 					ctas->into = $4;
-					ctas->relkind = OBJECT_TABLE;
+					ctas->objtype = OBJECT_TABLE;
 					ctas->is_select_into = false;
 					ctas->if_not_exists = false;
 					/* cram additional flags into the IntoClause */
@@ -4071,7 +4071,7 @@ CreateAsStmt:
 					CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
 					ctas->query = $9;
 					ctas->into = $7;
-					ctas->relkind = OBJECT_TABLE;
+					ctas->objtype = OBJECT_TABLE;
 					ctas->is_select_into = false;
 					ctas->if_not_exists = true;
 					/* cram additional flags into the IntoClause */
@@ -4117,7 +4117,7 @@ CreateMatViewStmt:
 					CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
 					ctas->query = $7;
 					ctas->into = $5;
-					ctas->relkind = OBJECT_MATVIEW;
+					ctas->objtype = OBJECT_MATVIEW;
 					ctas->is_select_into = false;
 					ctas->if_not_exists = false;
 					/* cram additional flags into the IntoClause */
@@ -4130,7 +4130,7 @@ CreateMatViewStmt:
 					CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
 					ctas->query = $10;
 					ctas->into = $8;
-					ctas->relkind = OBJECT_MATVIEW;
+					ctas->objtype = OBJECT_MATVIEW;
 					ctas->is_select_into = false;
 					ctas->if_not_exists = true;
 					/* cram additional flags into the IntoClause */
@@ -5124,7 +5124,7 @@ AlterForeignTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $4;
 					n->cmds = $5;
-					n->relkind = OBJECT_FOREIGN_TABLE;
+					n->objtype = OBJECT_FOREIGN_TABLE;
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
@@ -5133,7 +5133,7 @@ AlterForeignTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $6;
 					n->cmds = $7;
-					n->relkind = OBJECT_FOREIGN_TABLE;
+					n->objtype = OBJECT_FOREIGN_TABLE;
 					n->missing_ok = true;
 					$$ = (Node *)n;
 				}
@@ -10931,7 +10931,7 @@ ExecuteStmt: EXECUTE name execute_param_clause
 					n->params = $8;
 					ctas->query = (Node *) n;
 					ctas->into = $4;
-					ctas->relkind = OBJECT_TABLE;
+					ctas->objtype = OBJECT_TABLE;
 					ctas->is_select_into = false;
 					ctas->if_not_exists = false;
 					/* cram additional flags into the IntoClause */
@@ -10948,7 +10948,7 @@ ExecuteStmt: EXECUTE name execute_param_clause
 					n->params = $11;
 					ctas->query = (Node *) n;
 					ctas->into = $7;
-					ctas->relkind = OBJECT_TABLE;
+					ctas->objtype = OBJECT_TABLE;
 					ctas->is_select_into = false;
 					ctas->if_not_exists = true;
 					/* cram additional flags into the IntoClause */
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 0e4caa6ad4..25abc544fc 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -829,7 +829,7 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
 		stmt = makeNode(AlterTableStmt);
 		stmt->relation = cxt->relation;
 		stmt->cmds = NIL;
-		stmt->relkind = OBJECT_FOREIGN_TABLE;
+		stmt->objtype = OBJECT_FOREIGN_TABLE;
 		stmt->cmds = lappend(stmt->cmds, cmd);
 
 		cxt->alist = lappend(cxt->alist, stmt);
@@ -2508,7 +2508,7 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
 
 		alterstmt->relation = copyObject(cxt->relation);
 		alterstmt->cmds = notnullcmds;
-		alterstmt->relkind = OBJECT_TABLE;
+		alterstmt->objtype = OBJECT_TABLE;
 		alterstmt->missing_ok = false;
 
 		cxt->alist = lappend(cxt->alist, alterstmt);
@@ -2610,7 +2610,7 @@ transformFKConstraints(CreateStmtContext *cxt,
 
 		alterstmt->relation = cxt->relation;
 		alterstmt->cmds = NIL;
-		alterstmt->relkind = OBJECT_TABLE;
+		alterstmt->objtype = OBJECT_TABLE;
 
 		foreach(fkclist, cxt->fkconstraints)
 		{
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 97cbaa3072..9b0c376c8c 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -2574,7 +2574,7 @@ CreateCommandTag(Node *parsetree)
 			break;
 
 		case T_AlterTableStmt:
-			tag = AlterObjectTypeCommandTag(((AlterTableStmt *) parsetree)->relkind);
+			tag = AlterObjectTypeCommandTag(((AlterTableStmt *) parsetree)->objtype);
 			break;
 
 		case T_AlterDomainStmt:
@@ -2752,7 +2752,7 @@ CreateCommandTag(Node *parsetree)
 			break;
 
 		case T_CreateTableAsStmt:
-			switch (((CreateTableAsStmt *) parsetree)->relkind)
+			switch (((CreateTableAsStmt *) parsetree)->objtype)
 			{
 				case OBJECT_TABLE:
 					if (((CreateTableAsStmt *) parsetree)->is_select_into)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 5e1ffafb91..151bcdb7ef 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1776,7 +1776,7 @@ typedef struct AlterTableStmt
 	NodeTag		type;
 	RangeVar   *relation;		/* table to work on */
 	List	   *cmds;			/* list of subcommands */
-	ObjectType	relkind;		/* type of object */
+	ObjectType	objtype;		/* type of object */
 	bool		missing_ok;		/* skip error if table missing */
 } AlterTableStmt;
 
@@ -3275,7 +3275,7 @@ typedef struct CreateTableAsStmt
 	NodeTag		type;
 	Node	   *query;			/* the query (see comments above) */
 	IntoClause *into;			/* destination table */
-	ObjectType	relkind;		/* OBJECT_TABLE or OBJECT_MATVIEW */
+	ObjectType	objtype;		/* OBJECT_TABLE or OBJECT_MATVIEW */
 	bool		is_select_into; /* it was written as SELECT INTO */
 	bool		if_not_exists;	/* just do nothing if it already exists? */
 } CreateTableAsStmt;
-- 
2.21.1 (Apple Git-122.3)

#2Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Mark Dilger (#1)
Re: Towards easier AMs: Cleaning up inappropriate use of name "relkind"

On 2020-Jun-03, Mark Dilger wrote:

The name "relkind" normally refers to a field of type 'char' with
values like 'r' for "table" and 'i' for "index". In AlterTableStmt
and CreateTableAsStmt, this naming convention was abused for a field
of type enum ObjectType.

I agree that "relkind" here is a misnomer, and I bet that what happened
here is that the original patch Gavin developed was using the relkind
enum from pg_class and was later changed to the OBJECT_ defines after
patch review, but the struct member name remained. I don't object to
the proposed renaming.

--
�lvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#3Daniel Gustafsson
daniel@yesql.se
In reply to: Mark Dilger (#1)
Re: Towards easier AMs: Cleaning up inappropriate use of name "relkind"

On 3 Jun 2020, at 19:05, Mark Dilger <mark.dilger@enterprisedb.com> wrote:

The attached patch cleans this up.

The gram.y hunks in this patch no longer applies, please submit a rebased
version. I'm marking the entry Waiting on Author in the meantime.

cheers ./daniel

#4Mark Dilger
mark.dilger@enterprisedb.com
In reply to: Daniel Gustafsson (#3)
1 attachment(s)
Re: Towards easier AMs: Cleaning up inappropriate use of name "relkind"

On Jul 1, 2020, at 2:45 AM, Daniel Gustafsson <daniel@yesql.se> wrote:

On 3 Jun 2020, at 19:05, Mark Dilger <mark.dilger@enterprisedb.com> wrote:

The attached patch cleans this up.

The gram.y hunks in this patch no longer applies, please submit a rebased
version. I'm marking the entry Waiting on Author in the meantime.

Rebased patch attached. Thanks for mentioning it!

Attachments:

v2-0001-Renaming-relkind-as-objtype-where-appropriate.patchapplication/octet-stream; name=v2-0001-Renaming-relkind-as-objtype-where-appropriate.patch; x-unix-mode=0644Download
From 77478ad014d0d99423ad53223e4db95dd0d58ced Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Wed, 1 Jul 2020 07:45:32 -0700
Subject: [PATCH v2] Renaming relkind as objtype where appropriate

"relkind" normally refers to a field of type 'char' with values
like 'r' for "relation" and 'i' for "index".  In AlterTableStmt
and CreateTableAsStmt, this naming convention was abused for a
field of type enum ObjectType.  Usually, such fields are named
"objtype".  This leads particularly to confusion in functions that
also operate on a RangeTableEntry object, which also has a field
named relkind.

The naming goes back to commit 09d4e96d7e9 from 2004.  That
commit message does not explain the choice, but the two ObjectType
enum values visible in the diffs are OBJECT_TABLE and OBJECT_INDEX,
which seems to explain the naming choice.
---
 src/backend/commands/tablecmds.c   |  4 +--
 src/backend/nodes/copyfuncs.c      |  4 +--
 src/backend/nodes/equalfuncs.c     |  4 +--
 src/backend/parser/analyze.c       |  4 +--
 src/backend/parser/gram.y          | 44 +++++++++++++++---------------
 src/backend/parser/parse_utilcmd.c |  6 ++--
 src/backend/tcop/utility.c         |  4 +--
 src/include/nodes/parsenodes.h     |  4 +--
 8 files changed, 37 insertions(+), 37 deletions(-)

diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index f79044f39f..1105c5b8ec 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -4709,7 +4709,7 @@ ATParseTransformCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
 					 -1);
 	atstmt->relation->inh = recurse;
 	atstmt->cmds = list_make1(cmd);
-	atstmt->relkind = OBJECT_TABLE; /* needn't be picky here */
+	atstmt->objtype = OBJECT_TABLE; /* needn't be picky here */
 	atstmt->missing_ok = false;
 
 	/* Transform the AlterTableStmt */
@@ -15594,7 +15594,7 @@ RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid,
 		reltype = ((AlterObjectSchemaStmt *) stmt)->objectType;
 
 	else if (IsA(stmt, AlterTableStmt))
-		reltype = ((AlterTableStmt *) stmt)->relkind;
+		reltype = ((AlterTableStmt *) stmt)->objtype;
 	else
 	{
 		elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt));
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index d8cf87e6d0..89c409de66 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3204,7 +3204,7 @@ _copyAlterTableStmt(const AlterTableStmt *from)
 
 	COPY_NODE_FIELD(relation);
 	COPY_NODE_FIELD(cmds);
-	COPY_SCALAR_FIELD(relkind);
+	COPY_SCALAR_FIELD(objtype);
 	COPY_SCALAR_FIELD(missing_ok);
 
 	return newnode;
@@ -3980,7 +3980,7 @@ _copyCreateTableAsStmt(const CreateTableAsStmt *from)
 
 	COPY_NODE_FIELD(query);
 	COPY_NODE_FIELD(into);
-	COPY_SCALAR_FIELD(relkind);
+	COPY_SCALAR_FIELD(objtype);
 	COPY_SCALAR_FIELD(is_select_into);
 	COPY_SCALAR_FIELD(if_not_exists);
 
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 627b026b19..e3f33c40be 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1087,7 +1087,7 @@ _equalAlterTableStmt(const AlterTableStmt *a, const AlterTableStmt *b)
 {
 	COMPARE_NODE_FIELD(relation);
 	COMPARE_NODE_FIELD(cmds);
-	COMPARE_SCALAR_FIELD(relkind);
+	COMPARE_SCALAR_FIELD(objtype);
 	COMPARE_SCALAR_FIELD(missing_ok);
 
 	return true;
@@ -1735,7 +1735,7 @@ _equalCreateTableAsStmt(const CreateTableAsStmt *a, const CreateTableAsStmt *b)
 {
 	COMPARE_NODE_FIELD(query);
 	COMPARE_NODE_FIELD(into);
-	COMPARE_SCALAR_FIELD(relkind);
+	COMPARE_SCALAR_FIELD(objtype);
 	COMPARE_SCALAR_FIELD(is_select_into);
 	COMPARE_SCALAR_FIELD(if_not_exists);
 
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 401da5dedf..c159fb2957 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -229,7 +229,7 @@ transformOptionalSelectInto(ParseState *pstate, Node *parseTree)
 
 			ctas->query = parseTree;
 			ctas->into = stmt->intoClause;
-			ctas->relkind = OBJECT_TABLE;
+			ctas->objtype = OBJECT_TABLE;
 			ctas->is_select_into = true;
 
 			/*
@@ -2572,7 +2572,7 @@ transformCreateTableAsStmt(ParseState *pstate, CreateTableAsStmt *stmt)
 	stmt->query = (Node *) query;
 
 	/* additional work needed for CREATE MATERIALIZED VIEW */
-	if (stmt->relkind == OBJECT_MATVIEW)
+	if (stmt->objtype == OBJECT_MATVIEW)
 	{
 		/*
 		 * Prohibit a data-modifying CTE in the query used to create a
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 4ff35095b8..73f8ea25d7 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -1844,7 +1844,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $3;
 					n->cmds = $4;
-					n->relkind = OBJECT_TABLE;
+					n->objtype = OBJECT_TABLE;
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
@@ -1853,7 +1853,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $5;
 					n->cmds = $6;
-					n->relkind = OBJECT_TABLE;
+					n->objtype = OBJECT_TABLE;
 					n->missing_ok = true;
 					$$ = (Node *)n;
 				}
@@ -1862,7 +1862,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $3;
 					n->cmds = list_make1($4);
-					n->relkind = OBJECT_TABLE;
+					n->objtype = OBJECT_TABLE;
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
@@ -1871,7 +1871,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $5;
 					n->cmds = list_make1($6);
-					n->relkind = OBJECT_TABLE;
+					n->objtype = OBJECT_TABLE;
 					n->missing_ok = true;
 					$$ = (Node *)n;
 				}
@@ -1902,7 +1902,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $3;
 					n->cmds = $4;
-					n->relkind = OBJECT_INDEX;
+					n->objtype = OBJECT_INDEX;
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
@@ -1911,7 +1911,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $5;
 					n->cmds = $6;
-					n->relkind = OBJECT_INDEX;
+					n->objtype = OBJECT_INDEX;
 					n->missing_ok = true;
 					$$ = (Node *)n;
 				}
@@ -1920,7 +1920,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $3;
 					n->cmds = list_make1($4);
-					n->relkind = OBJECT_INDEX;
+					n->objtype = OBJECT_INDEX;
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
@@ -1951,7 +1951,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $3;
 					n->cmds = $4;
-					n->relkind = OBJECT_SEQUENCE;
+					n->objtype = OBJECT_SEQUENCE;
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
@@ -1960,7 +1960,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $5;
 					n->cmds = $6;
-					n->relkind = OBJECT_SEQUENCE;
+					n->objtype = OBJECT_SEQUENCE;
 					n->missing_ok = true;
 					$$ = (Node *)n;
 				}
@@ -1969,7 +1969,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $3;
 					n->cmds = $4;
-					n->relkind = OBJECT_VIEW;
+					n->objtype = OBJECT_VIEW;
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
@@ -1978,7 +1978,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $5;
 					n->cmds = $6;
-					n->relkind = OBJECT_VIEW;
+					n->objtype = OBJECT_VIEW;
 					n->missing_ok = true;
 					$$ = (Node *)n;
 				}
@@ -1987,7 +1987,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $4;
 					n->cmds = $5;
-					n->relkind = OBJECT_MATVIEW;
+					n->objtype = OBJECT_MATVIEW;
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
@@ -1996,7 +1996,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $6;
 					n->cmds = $7;
-					n->relkind = OBJECT_MATVIEW;
+					n->objtype = OBJECT_MATVIEW;
 					n->missing_ok = true;
 					$$ = (Node *)n;
 				}
@@ -2027,7 +2027,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $4;
 					n->cmds = $5;
-					n->relkind = OBJECT_FOREIGN_TABLE;
+					n->objtype = OBJECT_FOREIGN_TABLE;
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
@@ -2036,7 +2036,7 @@ AlterTableStmt:
 					AlterTableStmt *n = makeNode(AlterTableStmt);
 					n->relation = $6;
 					n->cmds = $7;
-					n->relkind = OBJECT_FOREIGN_TABLE;
+					n->objtype = OBJECT_FOREIGN_TABLE;
 					n->missing_ok = true;
 					$$ = (Node *)n;
 				}
@@ -2856,7 +2856,7 @@ AlterCompositeTypeStmt:
 					/* can't use qualified_name, sigh */
 					n->relation = makeRangeVarFromAnyName($3, @3, yyscanner);
 					n->cmds = $4;
-					n->relkind = OBJECT_TYPE;
+					n->objtype = OBJECT_TYPE;
 					$$ = (Node *)n;
 				}
 			;
@@ -4072,7 +4072,7 @@ CreateAsStmt:
 					CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
 					ctas->query = $6;
 					ctas->into = $4;
-					ctas->relkind = OBJECT_TABLE;
+					ctas->objtype = OBJECT_TABLE;
 					ctas->is_select_into = false;
 					ctas->if_not_exists = false;
 					/* cram additional flags into the IntoClause */
@@ -4085,7 +4085,7 @@ CreateAsStmt:
 					CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
 					ctas->query = $9;
 					ctas->into = $7;
-					ctas->relkind = OBJECT_TABLE;
+					ctas->objtype = OBJECT_TABLE;
 					ctas->is_select_into = false;
 					ctas->if_not_exists = true;
 					/* cram additional flags into the IntoClause */
@@ -4131,7 +4131,7 @@ CreateMatViewStmt:
 					CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
 					ctas->query = $7;
 					ctas->into = $5;
-					ctas->relkind = OBJECT_MATVIEW;
+					ctas->objtype = OBJECT_MATVIEW;
 					ctas->is_select_into = false;
 					ctas->if_not_exists = false;
 					/* cram additional flags into the IntoClause */
@@ -4144,7 +4144,7 @@ CreateMatViewStmt:
 					CreateTableAsStmt *ctas = makeNode(CreateTableAsStmt);
 					ctas->query = $10;
 					ctas->into = $8;
-					ctas->relkind = OBJECT_MATVIEW;
+					ctas->objtype = OBJECT_MATVIEW;
 					ctas->is_select_into = false;
 					ctas->if_not_exists = true;
 					/* cram additional flags into the IntoClause */
@@ -10695,7 +10695,7 @@ ExecuteStmt: EXECUTE name execute_param_clause
 					n->params = $8;
 					ctas->query = (Node *) n;
 					ctas->into = $4;
-					ctas->relkind = OBJECT_TABLE;
+					ctas->objtype = OBJECT_TABLE;
 					ctas->is_select_into = false;
 					ctas->if_not_exists = false;
 					/* cram additional flags into the IntoClause */
@@ -10712,7 +10712,7 @@ ExecuteStmt: EXECUTE name execute_param_clause
 					n->params = $11;
 					ctas->query = (Node *) n;
 					ctas->into = $7;
-					ctas->relkind = OBJECT_TABLE;
+					ctas->objtype = OBJECT_TABLE;
 					ctas->is_select_into = false;
 					ctas->if_not_exists = true;
 					/* cram additional flags into the IntoClause */
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 0e4caa6ad4..25abc544fc 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -829,7 +829,7 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
 		stmt = makeNode(AlterTableStmt);
 		stmt->relation = cxt->relation;
 		stmt->cmds = NIL;
-		stmt->relkind = OBJECT_FOREIGN_TABLE;
+		stmt->objtype = OBJECT_FOREIGN_TABLE;
 		stmt->cmds = lappend(stmt->cmds, cmd);
 
 		cxt->alist = lappend(cxt->alist, stmt);
@@ -2508,7 +2508,7 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
 
 		alterstmt->relation = copyObject(cxt->relation);
 		alterstmt->cmds = notnullcmds;
-		alterstmt->relkind = OBJECT_TABLE;
+		alterstmt->objtype = OBJECT_TABLE;
 		alterstmt->missing_ok = false;
 
 		cxt->alist = lappend(cxt->alist, alterstmt);
@@ -2610,7 +2610,7 @@ transformFKConstraints(CreateStmtContext *cxt,
 
 		alterstmt->relation = cxt->relation;
 		alterstmt->cmds = NIL;
-		alterstmt->relkind = OBJECT_TABLE;
+		alterstmt->objtype = OBJECT_TABLE;
 
 		foreach(fkclist, cxt->fkconstraints)
 		{
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 97cbaa3072..9b0c376c8c 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -2574,7 +2574,7 @@ CreateCommandTag(Node *parsetree)
 			break;
 
 		case T_AlterTableStmt:
-			tag = AlterObjectTypeCommandTag(((AlterTableStmt *) parsetree)->relkind);
+			tag = AlterObjectTypeCommandTag(((AlterTableStmt *) parsetree)->objtype);
 			break;
 
 		case T_AlterDomainStmt:
@@ -2752,7 +2752,7 @@ CreateCommandTag(Node *parsetree)
 			break;
 
 		case T_CreateTableAsStmt:
-			switch (((CreateTableAsStmt *) parsetree)->relkind)
+			switch (((CreateTableAsStmt *) parsetree)->objtype)
 			{
 				case OBJECT_TABLE:
 					if (((CreateTableAsStmt *) parsetree)->is_select_into)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 5e1ffafb91..151bcdb7ef 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1776,7 +1776,7 @@ typedef struct AlterTableStmt
 	NodeTag		type;
 	RangeVar   *relation;		/* table to work on */
 	List	   *cmds;			/* list of subcommands */
-	ObjectType	relkind;		/* type of object */
+	ObjectType	objtype;		/* type of object */
 	bool		missing_ok;		/* skip error if table missing */
 } AlterTableStmt;
 
@@ -3275,7 +3275,7 @@ typedef struct CreateTableAsStmt
 	NodeTag		type;
 	Node	   *query;			/* the query (see comments above) */
 	IntoClause *into;			/* destination table */
-	ObjectType	relkind;		/* OBJECT_TABLE or OBJECT_MATVIEW */
+	ObjectType	objtype;		/* OBJECT_TABLE or OBJECT_MATVIEW */
 	bool		is_select_into; /* it was written as SELECT INTO */
 	bool		if_not_exists;	/* just do nothing if it already exists? */
 } CreateTableAsStmt;
-- 
2.21.1 (Apple Git-122.3)

#5Mark Dilger
mark.dilger@enterprisedb.com
In reply to: Mark Dilger (#1)
1 attachment(s)
Re: Towards easier AMs: Cleaning up inappropriate use of name "relkind"

On Jun 3, 2020, at 10:05 AM, Mark Dilger <mark.dilger@enterprisedb.com> wrote:

I have another patch (to be posted shortly) that cleans up the #define RELKIND_XXX stuff using a new RelKind enum and special macros while keeping the relkind fields as type 'char'. Along with converting code to use switch(relkind) rather than if (relkind...) statements, the compiler now warns on unhandled cases when you add a new RelKind to the list, making it easier to find all the places you need to update. I decided to keep that work independent of this patch, as the code is logically distinct.

Most of the work in this patch is mechanical replacement of if/else if/else statements which hinge on relkind to switch statements on relkind. The patch is not philosophically very interesting, but it is fairly long. Reviewers might start by scrolling down the patch to the changes in src/include/catalog/pg_class.h

There are no intentional behavioral changes in this patch.

Attachments:

v2-0002-Refactoring-relkind-handling.patchapplication/octet-stream; name=v2-0002-Refactoring-relkind-handling.patch; x-unix-mode=0644Download
From 41a970951670dd413c0e066512ae79c3c16533a6 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Wed, 1 Jul 2020 08:12:27 -0700
Subject: [PATCH v2 2/2] Refactoring relkind handling

Cleaning up the #define RELKIND_XXX stuff using a new RelKind enum
and special macros while keeping the relkind fields as type 'char'.
---
 contrib/oid2name/oid2name.c                   |   18 +-
 contrib/pageinspect/rawpage.c                 |   66 +-
 contrib/pg_visibility/pg_visibility.c         |   28 +-
 contrib/pgrowlocks/pgrowlocks.c               |   38 +-
 contrib/pgstattuple/pgstatapprox.c            |   28 +-
 contrib/pgstattuple/pgstatindex.c             |   30 +-
 contrib/pgstattuple/pgstattuple.c             |    3 +-
 contrib/postgres_fdw/postgres_fdw.c           |   10 +-
 contrib/sepgsql/dml.c                         |   53 +-
 contrib/sepgsql/label.c                       |   51 +-
 contrib/sepgsql/relation.c                    |  387 ++-
 contrib/vacuumlo/vacuumlo.c                   |    2 +-
 src/backend/access/common/reloptions.c        |   17 +-
 src/backend/access/heap/heapam.c              |   86 +-
 src/backend/access/heap/heapam_handler.c      |   27 +-
 src/backend/access/heap/heaptoast.c           |   40 +-
 src/backend/access/index/indexam.c            |   28 +-
 src/backend/access/table/table.c              |  111 +-
 src/backend/access/table/tableam.c            |   56 +-
 src/backend/catalog/aclchk.c                  |  411 ++-
 src/backend/catalog/dependency.c              |   46 +-
 src/backend/catalog/heap.c                    |  331 ++-
 src/backend/catalog/index.c                   |  110 +-
 src/backend/catalog/objectaddress.c           |  165 +-
 src/backend/catalog/partition.c               |   21 +-
 src/backend/catalog/pg_depend.c               |   51 +-
 src/backend/catalog/pg_publication.c          |   53 +-
 src/backend/catalog/pg_type.c                 |   23 +-
 src/backend/catalog/toasting.c                |   46 +-
 src/backend/commands/analyze.c                |  227 +-
 src/backend/commands/cluster.c                |  154 +-
 src/backend/commands/comment.c                |   31 +-
 src/backend/commands/copy.c                   |  211 +-
 src/backend/commands/extension.c              |    4 +-
 src/backend/commands/indexcmds.c              |  190 +-
 src/backend/commands/lockcmds.c               |  100 +-
 src/backend/commands/policy.c                 |   78 +-
 src/backend/commands/publicationcmds.c        |   68 +-
 src/backend/commands/seclabel.c               |   31 +-
 src/backend/commands/sequence.c               |   29 +-
 src/backend/commands/statscmds.c              |   29 +-
 src/backend/commands/tablecmds.c              | 2571 +++++++++++------
 src/backend/commands/trigger.c                |  449 ++-
 src/backend/commands/typecmds.c               |   23 +-
 src/backend/commands/vacuum.c                 |  107 +-
 src/backend/executor/execMain.c               |  119 +-
 src/backend/executor/execReplication.c        |   45 +-
 src/backend/executor/nodeModifyTable.c        |  168 +-
 src/backend/optimizer/path/allpaths.c         |  170 +-
 src/backend/optimizer/plan/planner.c          |  146 +-
 src/backend/optimizer/util/inherit.c          |  250 +-
 src/backend/optimizer/util/plancat.c          |   74 +-
 src/backend/parser/parse_utilcmd.c            |  187 +-
 src/backend/partitioning/partbounds.c         |   50 +-
 src/backend/postmaster/autovacuum.c           |   92 +-
 src/backend/replication/basebackup.c          |    6 +-
 .../replication/logical/reorderbuffer.c       |   19 +-
 src/backend/replication/logical/tablesync.c   |   48 +-
 src/backend/replication/logical/worker.c      |  165 +-
 src/backend/replication/slot.c                |   52 +-
 src/backend/rewrite/rewriteDefine.c           |  185 +-
 src/backend/rewrite/rewriteHandler.c          |  463 +--
 src/backend/rewrite/rowsecurity.c             |   20 +-
 src/backend/storage/buffer/bufmgr.c           |   11 +-
 src/backend/storage/lmgr/proc.c               |   27 +-
 src/backend/storage/lmgr/spin.c               |    2 +-
 src/backend/tcop/utility.c                    |   82 +-
 src/backend/utils/adt/amutils.c               |   21 +-
 src/backend/utils/adt/dbsize.c                |   14 +-
 src/backend/utils/adt/partitionfuncs.c        |   44 +-
 src/backend/utils/adt/tid.c                   |   38 +-
 src/backend/utils/adt/xml.c                   |   12 +-
 src/backend/utils/cache/partcache.c           |   19 +-
 src/backend/utils/cache/relcache.c            |  348 ++-
 src/bin/initdb/initdb.c                       |   20 +-
 src/bin/pg_dump/common.c                      |   42 +-
 src/bin/pg_dump/pg_backup_tar.c               |    2 +-
 src/bin/pg_dump/pg_dump.c                     |  194 +-
 src/bin/pg_dump/pg_dump_sort.c                |  169 +-
 src/bin/pg_upgrade/info.c                     |    4 +-
 src/bin/pg_upgrade/pg_upgrade.c               |   12 +-
 src/bin/pg_upgrade/version.c                  |    6 +-
 src/bin/psql/command.c                        |   19 +-
 src/bin/psql/describe.c                       | 2268 ++++++++-------
 src/bin/psql/tab-complete.c                   |   66 +-
 src/bin/scripts/reindexdb.c                   |    8 +-
 src/bin/scripts/vacuumdb.c                    |    4 +-
 src/include/catalog/pg_class.h                |   38 +-
 src/include/nodes/execnodes.h                 |    4 +-
 src/include/storage/proc.h                    |    2 +-
 src/include/utils/builtins.h                  |   10 +-
 src/pl/plpgsql/src/pl_comp.c                  |   25 +-
 src/test/regress/regress.c                    |   22 +-
 src/tools/findoidjoins/findoidjoins.c         |    6 +-
 94 files changed, 8280 insertions(+), 4156 deletions(-)

diff --git a/contrib/oid2name/oid2name.c b/contrib/oid2name/oid2name.c
index c7d0f9025a..cff14f7c47 100644
--- a/contrib/oid2name/oid2name.c
+++ b/contrib/oid2name/oid2name.c
@@ -481,8 +481,8 @@ sql_exec_dumpalltables(PGconn *conn, struct options *opts)
 			 "	LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace "
 			 "	LEFT JOIN pg_catalog.pg_database d ON d.datname = pg_catalog.current_database(),"
 			 "	pg_catalog.pg_tablespace t "
-			 "WHERE relkind IN (" CppAsString2(RELKIND_RELATION) ","
-			 CppAsString2(RELKIND_MATVIEW) "%s%s) AND "
+			 "WHERE relkind IN (" RelKindAsString(RELKIND_RELATION) ","
+			 RelKindAsString(RELKIND_MATVIEW) "%s%s) AND "
 			 "	%s"
 			 "		t.oid = CASE"
 			 "			WHEN reltablespace <> 0 THEN reltablespace"
@@ -490,8 +490,8 @@ sql_exec_dumpalltables(PGconn *conn, struct options *opts)
 			 "		END "
 			 "ORDER BY relname",
 			 opts->extended ? addfields : "",
-			 opts->indexes ? "," CppAsString2(RELKIND_INDEX) "," CppAsString2(RELKIND_SEQUENCE) : "",
-			 opts->systables ? "," CppAsString2(RELKIND_TOASTVALUE) : "",
+			 opts->indexes ? "," RelKindAsString(RELKIND_INDEX) "," RelKindAsString(RELKIND_SEQUENCE) : "",
+			 opts->systables ? "," RelKindAsString(RELKIND_TOASTVALUE) : "",
 			 opts->systables ? "" : "n.nspname NOT IN ('pg_catalog', 'information_schema') AND n.nspname !~ '^pg_toast' AND");
 
 	sql_exec(conn, todo, opts->quiet);
@@ -551,11 +551,11 @@ sql_exec_searchtables(PGconn *conn, struct options *opts)
 					"	LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
 					"	LEFT JOIN pg_catalog.pg_database d ON d.datname = pg_catalog.current_database(),\n"
 					"	pg_catalog.pg_tablespace t\n"
-					"WHERE relkind IN (" CppAsString2(RELKIND_RELATION) ","
-					CppAsString2(RELKIND_MATVIEW) ","
-					CppAsString2(RELKIND_INDEX) ","
-					CppAsString2(RELKIND_SEQUENCE) ","
-					CppAsString2(RELKIND_TOASTVALUE) ") AND\n"
+					"WHERE relkind IN (" RelKindAsString(RELKIND_RELATION) ","
+					RelKindAsString(RELKIND_MATVIEW) ","
+					RelKindAsString(RELKIND_INDEX) ","
+					RelKindAsString(RELKIND_SEQUENCE) ","
+					RelKindAsString(RELKIND_TOASTVALUE) ") AND\n"
 					"		t.oid = CASE\n"
 					"			WHEN reltablespace <> 0 THEN reltablespace\n"
 					"			ELSE dattablespace\n"
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index c0181506a5..b7082f5cdb 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -108,31 +108,47 @@ get_raw_page_internal(text *relname, ForkNumber forknum, BlockNumber blkno)
 	rel = relation_openrv(relrv, AccessShareLock);
 
 	/* Check that this relation has storage */
-	if (rel->rd_rel->relkind == RELKIND_VIEW)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot get raw page from view \"%s\"",
-						RelationGetRelationName(rel))));
-	if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot get raw page from composite type \"%s\"",
-						RelationGetRelationName(rel))));
-	if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot get raw page from foreign table \"%s\"",
-						RelationGetRelationName(rel))));
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot get raw page from partitioned table \"%s\"",
-						RelationGetRelationName(rel))));
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot get raw page from partitioned index \"%s\"",
-						RelationGetRelationName(rel))));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_VIEW:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot get raw page from view \"%s\"",
+							RelationGetRelationName(rel))));
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot get raw page from composite type \"%s\"",
+							RelationGetRelationName(rel))));
+			break;
+		case RELKIND_FOREIGN_TABLE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot get raw page from foreign table \"%s\"",
+							RelationGetRelationName(rel))));
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot get raw page from partitioned table \"%s\"",
+							RelationGetRelationName(rel))));
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot get raw page from partitioned index \"%s\"",
+							RelationGetRelationName(rel))));
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	/*
 	 * Reject attempts to read non-local temporary relations; we would be
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index 68d580ed1e..30bcf49379 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -778,11 +778,25 @@ tuple_all_visible(HeapTuple tup, TransactionId OldestXmin, Buffer buffer)
 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)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table, materialized view, or TOAST table",
-						RelationGetRelationName(rel))));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table, materialized view, or TOAST table",
+							RelationGetRelationName(rel))));
+			break;
+	}
 }
diff --git a/contrib/pgrowlocks/pgrowlocks.c b/contrib/pgrowlocks/pgrowlocks.c
index 714398831b..a5a123d421 100644
--- a/contrib/pgrowlocks/pgrowlocks.c
+++ b/contrib/pgrowlocks/pgrowlocks.c
@@ -111,17 +111,33 @@ pgrowlocks(PG_FUNCTION_ARGS)
 		ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 						errmsg("only heap AM is supported")));
 
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is a partitioned table",
-						RelationGetRelationName(rel)),
-				 errdetail("Partitioned tables do not contain rows.")));
-	else if (rel->rd_rel->relkind != RELKIND_RELATION)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table",
-						RelationGetRelationName(rel))));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is a partitioned table",
+							RelationGetRelationName(rel)),
+					 errdetail("Partitioned tables do not contain rows.")));
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table",
+							RelationGetRelationName(rel))));
+			break;
+	}
 
 	/*
 	 * check permissions: must have SELECT on table or be in
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index dbc0fa11f6..c14edf2aad 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -281,13 +281,27 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * We support only relation kinds with a visibility map and a free space
 	 * map.
 	 */
-	if (!(rel->rd_rel->relkind == RELKIND_RELATION ||
-		  rel->rd_rel->relkind == RELKIND_MATVIEW ||
-		  rel->rd_rel->relkind == RELKIND_TOASTVALUE))
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("\"%s\" is not a table, materialized view, or TOAST table",
-						RelationGetRelationName(rel))));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("\"%s\" is not a table, materialized view, or TOAST table",
+							RelationGetRelationName(rel))));
+			break;
+	}
 
 	if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
 		ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index b1ce0d77d7..b6c1a16d15 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -758,13 +758,25 @@ GetHashPageStats(Page page, HashIndexStat *stats)
 static void
 check_relation_relkind(Relation rel)
 {
-	if (rel->rd_rel->relkind != RELKIND_RELATION &&
-		rel->rd_rel->relkind != RELKIND_INDEX &&
-		rel->rd_rel->relkind != RELKIND_MATVIEW &&
-		rel->rd_rel->relkind != RELKIND_SEQUENCE &&
-		rel->rd_rel->relkind != RELKIND_TOASTVALUE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table, index, materialized view, sequence, or TOAST table",
-						RelationGetRelationName(rel))));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table, index, materialized view, sequence, or TOAST table",
+							RelationGetRelationName(rel))));
+			break;
+	}
 }
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 69179d4104..897805d575 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -252,7 +252,7 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo)
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("cannot access temporary tables of other sessions")));
 
-	switch (rel->rd_rel->relkind)
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_MATVIEW:
@@ -300,6 +300,7 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo)
 		case RELKIND_PARTITIONED_INDEX:
 			err = "partitioned index";
 			break;
+		case RELKIND_NULL:
 		default:
 			err = "unknown";
 			break;
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 9fc53cad68..77e28757ef 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -4842,11 +4842,11 @@ postgresImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
 
 		appendStringInfoString(&buf,
 							   "WHERE c.relkind IN ("
-							   CppAsString2(RELKIND_RELATION) ","
-							   CppAsString2(RELKIND_VIEW) ","
-							   CppAsString2(RELKIND_FOREIGN_TABLE) ","
-							   CppAsString2(RELKIND_MATVIEW) ","
-							   CppAsString2(RELKIND_PARTITIONED_TABLE) ") "
+							   RelKindAsString(RELKIND_RELATION) ","
+							   RelKindAsString(RELKIND_VIEW) ","
+							   RelKindAsString(RELKIND_FOREIGN_TABLE) ","
+							   RelKindAsString(RELKIND_MATVIEW) ","
+							   RelKindAsString(RELKIND_PARTITIONED_TABLE) ") "
 							   "  AND n.nspname = ");
 		deparseStringLiteral(&buf, stmt->remote_schema);
 
diff --git a/contrib/sepgsql/dml.c b/contrib/sepgsql/dml.c
index 53f6f41c5c..a1d5986619 100644
--- a/contrib/sepgsql/dml.c
+++ b/contrib/sepgsql/dml.c
@@ -167,10 +167,27 @@ check_relation_privileges(Oid relOid,
 					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 					 errmsg("SELinux: hardwired security policy violation")));
 
-		if (relkind == RELKIND_TOASTVALUE)
-			ereport(ERROR,
-					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-					 errmsg("SELinux: hardwired security policy violation")));
+		switch ((RelKind) relkind)
+		{
+			case RELKIND_TOASTVALUE:
+				ereport(ERROR,
+						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+						 errmsg("SELinux: hardwired security policy violation")));
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				break;
+		}
+
 	}
 
 	/*
@@ -180,7 +197,7 @@ check_relation_privileges(Oid relOid,
 	object.objectId = relOid;
 	object.objectSubId = 0;
 	audit_name = getObjectIdentity(&object);
-	switch (relkind)
+	switch ((RelKind) relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
@@ -210,6 +227,13 @@ check_relation_privileges(Oid relOid,
 											 abort_on_violation);
 			break;
 
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
 		default:
 			/* nothing to be checked */
 			break;
@@ -219,8 +243,23 @@ check_relation_privileges(Oid relOid,
 	/*
 	 * Only columns owned by relations shall be checked
 	 */
-	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
-		return true;
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			return true;
+	}
 
 	/*
 	 * Check permissions on the columns
diff --git a/contrib/sepgsql/label.c b/contrib/sepgsql/label.c
index 147ab67f32..697f556f58 100644
--- a/contrib/sepgsql/label.c
+++ b/contrib/sepgsql/label.c
@@ -763,15 +763,28 @@ exec_object_restorecon(struct selabel_handle *sehnd, Oid catalogId)
 			case RelationRelationId:
 				relForm = (Form_pg_class) GETSTRUCT(tuple);
 
-				if (relForm->relkind == RELKIND_RELATION ||
-					relForm->relkind == RELKIND_PARTITIONED_TABLE)
-					objtype = SELABEL_DB_TABLE;
-				else if (relForm->relkind == RELKIND_SEQUENCE)
-					objtype = SELABEL_DB_SEQUENCE;
-				else if (relForm->relkind == RELKIND_VIEW)
-					objtype = SELABEL_DB_VIEW;
-				else
-					continue;	/* no need to assign security label */
+				switch ((RelKind) relForm->relkind)
+				{
+					case RELKIND_RELATION:
+					case RELKIND_PARTITIONED_TABLE:
+						objtype = SELABEL_DB_TABLE;
+						break;
+					case RELKIND_SEQUENCE:
+						objtype = SELABEL_DB_SEQUENCE;
+						break;
+					case RELKIND_VIEW:
+						objtype = SELABEL_DB_VIEW;
+						break;
+					case RELKIND_PARTITIONED_INDEX:
+					case RELKIND_COMPOSITE_TYPE:
+					case RELKIND_FOREIGN_TABLE:
+					case RELKIND_INDEX:
+					case RELKIND_MATVIEW:
+					case RELKIND_TOASTVALUE:
+					case RELKIND_NULL:
+					default:
+						continue;	/* no need to assign security label */
+				}
 
 				namespace_name = get_namespace_name(relForm->relnamespace);
 				objname = quote_object_name(database_name,
@@ -788,9 +801,23 @@ exec_object_restorecon(struct selabel_handle *sehnd, Oid catalogId)
 			case AttributeRelationId:
 				attForm = (Form_pg_attribute) GETSTRUCT(tuple);
 
-				if (get_rel_relkind(attForm->attrelid) != RELKIND_RELATION &&
-					get_rel_relkind(attForm->attrelid) != RELKIND_PARTITIONED_TABLE)
-					continue;	/* no need to assign security label */
+				switch ((RelKind) get_rel_relkind(attForm->attrelid))
+				{
+					case RELKIND_RELATION:
+					case RELKIND_PARTITIONED_TABLE:
+						break;
+					case RELKIND_PARTITIONED_INDEX:
+					case RELKIND_SEQUENCE:
+					case RELKIND_COMPOSITE_TYPE:
+					case RELKIND_FOREIGN_TABLE:
+					case RELKIND_INDEX:
+					case RELKIND_MATVIEW:
+					case RELKIND_TOASTVALUE:
+					case RELKIND_VIEW:
+					case RELKIND_NULL:
+					default:
+						continue;	/* no need to assign security label */
+				}
 
 				objtype = SELABEL_DB_COLUMN;
 
diff --git a/contrib/sepgsql/relation.c b/contrib/sepgsql/relation.c
index 380bc6094d..27262f47c1 100644
--- a/contrib/sepgsql/relation.c
+++ b/contrib/sepgsql/relation.c
@@ -59,8 +59,23 @@ sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum)
 	 * Only attributes within regular relations or partition relations have
 	 * individual security labels.
 	 */
-	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
-		return;
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			return;
+	}
 
 	/*
 	 * Compute a default security label of the new column underlying the
@@ -137,8 +152,23 @@ sepgsql_attribute_drop(Oid relOid, AttrNumber attnum)
 	char	   *audit_name;
 	char		relkind = get_rel_relkind(relOid);
 
-	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
-		return;
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			return;
+	}
 
 	/*
 	 * check db_column:{drop} permission
@@ -170,10 +200,26 @@ sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
 	char	   *audit_name;
 	char		relkind = get_rel_relkind(relOid);
 
-	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot set security label on non-regular columns")));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot set security label on non-regular columns")));
+			break;
+	}
 
 	object.classId = RelationRelationId;
 	object.objectId = relOid;
@@ -213,8 +259,25 @@ sepgsql_attribute_setattr(Oid relOid, AttrNumber attnum)
 	char	   *audit_name;
 	char		relkind = get_rel_relkind(relOid);
 
-	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
-		return;
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			return;
+	}
 
 	/*
 	 * check db_column:{setattr} permission
@@ -275,9 +338,26 @@ sepgsql_relation_post_create(Oid relOid)
 	classForm = (Form_pg_class) GETSTRUCT(tuple);
 
 	/* ignore indexes on toast tables */
-	if (classForm->relkind == RELKIND_INDEX &&
-		classForm->relnamespace == PG_TOAST_NAMESPACE)
-		goto out;
+	switch ((RelKind) classForm->relkind)
+	{
+		case RELKIND_INDEX:
+			if (classForm->relnamespace == PG_TOAST_NAMESPACE)
+				goto out;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
+
 
 	/*
 	 * check db_schema:{add_name} permission of the namespace
@@ -291,7 +371,7 @@ sepgsql_relation_post_create(Oid relOid)
 							getObjectIdentity(&object),
 							true);
 
-	switch (classForm->relkind)
+	switch ((RelKind) classForm->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
@@ -307,6 +387,12 @@ sepgsql_relation_post_create(Oid relOid)
 			/* deal with indexes specially; no need for tclass */
 			sepgsql_index_modify(relOid);
 			goto out;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
 		default:
 			/* ignore other relkinds */
 			goto out;
@@ -348,59 +434,75 @@ sepgsql_relation_post_create(Oid relOid)
 	/*
 	 * We also assign a default security label on columns of a new table.
 	 */
-	if (classForm->relkind == RELKIND_RELATION ||
-		classForm->relkind == RELKIND_PARTITIONED_TABLE)
+	switch ((RelKind) classForm->relkind)
 	{
-		Relation	arel;
-		ScanKeyData akey;
-		SysScanDesc ascan;
-		HeapTuple	atup;
-		Form_pg_attribute attForm;
-
-		arel = table_open(AttributeRelationId, AccessShareLock);
-
-		ScanKeyInit(&akey,
-					Anum_pg_attribute_attrelid,
-					BTEqualStrategyNumber, F_OIDEQ,
-					ObjectIdGetDatum(relOid));
-
-		ascan = systable_beginscan(arel, AttributeRelidNumIndexId, true,
-								   SnapshotSelf, 1, &akey);
-
-		while (HeapTupleIsValid(atup = systable_getnext(ascan)))
-		{
-			attForm = (Form_pg_attribute) GETSTRUCT(atup);
-
-			resetStringInfo(&audit_name);
-			appendStringInfo(&audit_name, "%s.%s.%s",
-							 quote_identifier(nsp_name),
-							 quote_identifier(NameStr(classForm->relname)),
-							 quote_identifier(NameStr(attForm->attname)));
-
-			ccontext = sepgsql_compute_create(scontext,
-											  rcontext,
-											  SEPG_CLASS_DB_COLUMN,
-											  NameStr(attForm->attname));
-
-			/*
-			 * check db_column:{create} permission
-			 */
-			sepgsql_avc_check_perms_label(ccontext,
-										  SEPG_CLASS_DB_COLUMN,
-										  SEPG_DB_COLUMN__CREATE,
-										  audit_name.data,
-										  true);
-
-			object.classId = RelationRelationId;
-			object.objectId = relOid;
-			object.objectSubId = attForm->attnum;
-			SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ccontext);
-
-			pfree(ccontext);
-		}
-		systable_endscan(ascan);
-		table_close(arel, AccessShareLock);
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			{
+				Relation	arel;
+				ScanKeyData akey;
+				SysScanDesc ascan;
+				HeapTuple	atup;
+				Form_pg_attribute attForm;
+
+				arel = table_open(AttributeRelationId, AccessShareLock);
+
+				ScanKeyInit(&akey,
+							Anum_pg_attribute_attrelid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(relOid));
+
+				ascan = systable_beginscan(arel, AttributeRelidNumIndexId, true,
+										   SnapshotSelf, 1, &akey);
+
+				while (HeapTupleIsValid(atup = systable_getnext(ascan)))
+				{
+					attForm = (Form_pg_attribute) GETSTRUCT(atup);
+
+					resetStringInfo(&audit_name);
+					appendStringInfo(&audit_name, "%s.%s.%s",
+									 quote_identifier(nsp_name),
+									 quote_identifier(NameStr(classForm->relname)),
+									 quote_identifier(NameStr(attForm->attname)));
+
+					ccontext = sepgsql_compute_create(scontext,
+													  rcontext,
+													  SEPG_CLASS_DB_COLUMN,
+													  NameStr(attForm->attname));
+
+					/*
+					 * check db_column:{create} permission
+					 */
+					sepgsql_avc_check_perms_label(ccontext,
+												  SEPG_CLASS_DB_COLUMN,
+												  SEPG_DB_COLUMN__CREATE,
+												  audit_name.data,
+												  true);
+
+					object.classId = RelationRelationId;
+					object.objectId = relOid;
+					object.objectSubId = attForm->attnum;
+					SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ccontext);
+
+					pfree(ccontext);
+				}
+				systable_endscan(ascan);
+				table_close(arel, AccessShareLock);
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
+
 	pfree(rcontext);
 
 out:
@@ -421,7 +523,7 @@ sepgsql_relation_drop(Oid relOid)
 	uint16_t	tclass = 0;
 	char		relkind = get_rel_relkind(relOid);
 
-	switch (relkind)
+	switch ((RelKind) relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
@@ -439,6 +541,12 @@ sepgsql_relation_drop(Oid relOid)
 				return;
 			/* other indexes are handled specially below; no need for tclass */
 			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
 		default:
 			/* ignore other relkinds */
 			return;
@@ -460,10 +568,23 @@ sepgsql_relation_drop(Oid relOid)
 	pfree(audit_name);
 
 	/* deal with indexes specially */
-	if (relkind == RELKIND_INDEX)
+	switch ((RelKind) relkind)
 	{
-		sepgsql_index_modify(relOid);
-		return;
+		case RELKIND_INDEX:
+			sepgsql_index_modify(relOid);
+			return;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	/*
@@ -484,35 +605,51 @@ sepgsql_relation_drop(Oid relOid)
 	/*
 	 * check db_column:{drop} permission
 	 */
-	if (relkind == RELKIND_RELATION || relkind == RELKIND_PARTITIONED_TABLE)
+	switch ((RelKind) relkind)
 	{
-		Form_pg_attribute attForm;
-		CatCList   *attrList;
-		HeapTuple	atttup;
-		int			i;
-
-		attrList = SearchSysCacheList1(ATTNUM, ObjectIdGetDatum(relOid));
-		for (i = 0; i < attrList->n_members; i++)
-		{
-			atttup = &attrList->members[i]->tuple;
-			attForm = (Form_pg_attribute) GETSTRUCT(atttup);
-
-			if (attForm->attisdropped)
-				continue;
-
-			object.classId = RelationRelationId;
-			object.objectId = relOid;
-			object.objectSubId = attForm->attnum;
-			audit_name = getObjectIdentity(&object);
-
-			sepgsql_avc_check_perms(&object,
-									SEPG_CLASS_DB_COLUMN,
-									SEPG_DB_COLUMN__DROP,
-									audit_name,
-									true);
-			pfree(audit_name);
-		}
-		ReleaseCatCacheList(attrList);
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			{
+				Form_pg_attribute attForm;
+				CatCList   *attrList;
+				HeapTuple	atttup;
+				int			i;
+
+				attrList = SearchSysCacheList1(ATTNUM, ObjectIdGetDatum(relOid));
+				for (i = 0; i < attrList->n_members; i++)
+				{
+					atttup = &attrList->members[i]->tuple;
+					attForm = (Form_pg_attribute) GETSTRUCT(atttup);
+
+					if (attForm->attisdropped)
+						continue;
+
+					object.classId = RelationRelationId;
+					object.objectId = relOid;
+					object.objectSubId = attForm->attnum;
+					audit_name = getObjectIdentity(&object);
+
+					sepgsql_avc_check_perms(&object,
+											SEPG_CLASS_DB_COLUMN,
+											SEPG_DB_COLUMN__DROP,
+											audit_name,
+											true);
+					pfree(audit_name);
+				}
+				ReleaseCatCacheList(attrList);
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 }
 
@@ -529,12 +666,21 @@ sepgsql_relation_truncate(Oid relOid)
 	uint16_t	tclass = 0;
 	char		relkind = get_rel_relkind(relOid);
 
-	switch (relkind)
+	switch ((RelKind) relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
 			tclass = SEPG_CLASS_DB_TABLE;
 			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
 		default:
 			/* ignore other relkinds */
 			return;
@@ -569,17 +715,32 @@ sepgsql_relation_relabel(Oid relOid, const char *seclabel)
 	char		relkind = get_rel_relkind(relOid);
 	uint16_t	tclass = 0;
 
-	if (relkind == RELKIND_RELATION || relkind == RELKIND_PARTITIONED_TABLE)
-		tclass = SEPG_CLASS_DB_TABLE;
-	else if (relkind == RELKIND_SEQUENCE)
-		tclass = SEPG_CLASS_DB_SEQUENCE;
-	else if (relkind == RELKIND_VIEW)
-		tclass = SEPG_CLASS_DB_VIEW;
-	else
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot set security labels on relations except "
-						"for tables, sequences or views")));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			tclass = SEPG_CLASS_DB_TABLE;
+			break;
+		case RELKIND_SEQUENCE:
+			tclass = SEPG_CLASS_DB_SEQUENCE;
+			break;
+		case RELKIND_VIEW:
+			tclass = SEPG_CLASS_DB_VIEW;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot set security labels on relations except "
+							"for tables, sequences or views")));
+			break;
+	}
 
 	object.classId = RelationRelationId;
 	object.objectId = relOid;
@@ -626,7 +787,7 @@ sepgsql_relation_setattr(Oid relOid)
 	char	   *audit_name;
 	uint16_t	tclass;
 
-	switch (get_rel_relkind(relOid))
+	switch ((RelKind) get_rel_relkind(relOid))
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
@@ -642,6 +803,12 @@ sepgsql_relation_setattr(Oid relOid)
 			/* deal with indexes specially */
 			sepgsql_index_modify(relOid);
 			return;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
 		default:
 			/* other relkinds don't need additional work */
 			return;
diff --git a/contrib/vacuumlo/vacuumlo.c b/contrib/vacuumlo/vacuumlo.c
index 92bdf71356..e07f8be8e3 100644
--- a/contrib/vacuumlo/vacuumlo.c
+++ b/contrib/vacuumlo/vacuumlo.c
@@ -203,7 +203,7 @@ vacuumlo(const char *database, const struct _param *param)
 	strcat(buf, "      AND a.atttypid = t.oid ");
 	strcat(buf, "      AND c.relnamespace = s.oid ");
 	strcat(buf, "      AND t.typname in ('oid', 'lo') ");
-	strcat(buf, "      AND c.relkind in (" CppAsString2(RELKIND_RELATION) ", " CppAsString2(RELKIND_MATVIEW) ")");
+	strcat(buf, "      AND c.relkind in (" RelKindAsString(RELKIND_RELATION) ", " RelKindAsString(RELKIND_MATVIEW) ")");
 	strcat(buf, "      AND s.nspname !~ '^pg_'");
 	res = PQexec(conn, buf);
 	if (PQresultStatus(res) != PGRES_TUPLES_OK)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 8ccc228a8c..d16e401060 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -1372,7 +1372,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
 	classForm = (Form_pg_class) GETSTRUCT(tuple);
 
 	/* Parse into appropriate format; don't error out here */
-	switch (classForm->relkind)
+	switch ((RelKind) classForm->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_TOASTVALUE:
@@ -1392,6 +1392,9 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
 		case RELKIND_FOREIGN_TABLE:
 			options = NULL;
 			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_NULL:
 		default:
 			Assert(false);		/* can't get here */
 			options = NULL;		/* keep compiler quiet */
@@ -1997,7 +2000,7 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
 {
 	StdRdOptions *rdopts;
 
-	switch (relkind)
+	switch ((RelKind) relkind)
 	{
 		case RELKIND_TOASTVALUE:
 			rdopts = (StdRdOptions *)
@@ -2013,13 +2016,21 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
 		case RELKIND_RELATION:
 		case RELKIND_MATVIEW:
 			return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
 		default:
 			/* other relkinds are not supported */
 			return NULL;
 	}
+	return NULL;				/* keep compiler happy */
 }
 
-
 /*
  * Parse options for indexes.
  *
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 537913d1bb..d6f91d5f93 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2040,17 +2040,28 @@ heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 	 * If the new tuple is too big for storage or contains already toasted
 	 * out-of-line attributes from some other relation, invoke the toaster.
 	 */
-	if (relation->rd_rel->relkind != RELKIND_RELATION &&
-		relation->rd_rel->relkind != RELKIND_MATVIEW)
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
-		/* toast table entries should never be recursively toasted */
-		Assert(!HeapTupleHasExternal(tup));
-		return tup;
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+			if (HeapTupleHasExternal(tup) || tup->t_len > TOAST_TUPLE_THRESHOLD)
+				return heap_toast_insert_or_update(relation, tup, NULL, options);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			/* toast table entries should never be recursively toasted */
+			Assert(!HeapTupleHasExternal(tup));
+			break;
 	}
-	else if (HeapTupleHasExternal(tup) || tup->t_len > TOAST_TUPLE_THRESHOLD)
-		return heap_toast_insert_or_update(relation, tup, NULL, options);
-	else
-		return tup;
+	return tup;
 }
 
 /*
@@ -2773,14 +2784,27 @@ l1:
 	 * because we need to look at the contents of the tuple, but it's OK to
 	 * release the content lock on the buffer first.
 	 */
-	if (relation->rd_rel->relkind != RELKIND_RELATION &&
-		relation->rd_rel->relkind != RELKIND_MATVIEW)
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
-		/* toast table entries should never be recursively toasted */
-		Assert(!HeapTupleHasExternal(&tp));
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+			if (HeapTupleHasExternal(&tp))
+				heap_toast_delete(relation, &tp, false);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			/* toast table entries should never be recursively toasted */
+			Assert(!HeapTupleHasExternal(&tp));
+			break;
 	}
-	else if (HeapTupleHasExternal(&tp))
-		heap_toast_delete(relation, &tp, false);
 
 	/*
 	 * Mark tuple for invalidation from system caches at next command
@@ -3362,18 +3386,30 @@ l2:
 	 * We need to invoke the toaster if there are already any out-of-line
 	 * toasted values present, or if the new tuple is over-threshold.
 	 */
-	if (relation->rd_rel->relkind != RELKIND_RELATION &&
-		relation->rd_rel->relkind != RELKIND_MATVIEW)
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
-		/* toast table entries should never be recursively toasted */
-		Assert(!HeapTupleHasExternal(&oldtup));
-		Assert(!HeapTupleHasExternal(newtup));
-		need_toast = false;
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+			need_toast = (HeapTupleHasExternal(&oldtup) ||
+						  HeapTupleHasExternal(newtup) ||
+						  newtup->t_len > TOAST_TUPLE_THRESHOLD);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			/* toast table entries should never be recursively toasted */
+			Assert(!HeapTupleHasExternal(&oldtup));
+			Assert(!HeapTupleHasExternal(newtup));
+			need_toast = false;
+			break;
 	}
-	else
-		need_toast = (HeapTupleHasExternal(&oldtup) ||
-					  HeapTupleHasExternal(newtup) ||
-					  newtup->t_len > TOAST_TUPLE_THRESHOLD);
 
 	pagefree = PageGetHeapFreeSpace(page);
 
diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index 56b35622f1..ba2ef7d45d 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -600,12 +600,27 @@ heapam_relation_set_new_filenode(Relation rel,
 	 */
 	if (persistence == RELPERSISTENCE_UNLOGGED)
 	{
-		Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
-			   rel->rd_rel->relkind == RELKIND_MATVIEW ||
-			   rel->rd_rel->relkind == RELKIND_TOASTVALUE);
-		smgrcreate(srel, INIT_FORKNUM, false);
-		log_smgrcreate(newrnode, INIT_FORKNUM);
-		smgrimmedsync(srel, INIT_FORKNUM);
+		switch ((RelKind) rel->rd_rel->relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_MATVIEW:
+			case RELKIND_TOASTVALUE:
+				smgrcreate(srel, INIT_FORKNUM, false);
+				log_smgrcreate(newrnode, INIT_FORKNUM);
+				smgrimmedsync(srel, INIT_FORKNUM);
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				Assert(false);
+				break;
+		}
 	}
 
 	smgrclose(srel);
diff --git a/src/backend/access/heap/heaptoast.c b/src/backend/access/heap/heaptoast.c
index 584f101dd9..2d442aa2f0 100644
--- a/src/backend/access/heap/heaptoast.c
+++ b/src/backend/access/heap/heaptoast.c
@@ -50,8 +50,24 @@ heap_toast_delete(Relation rel, HeapTuple oldtup, bool is_speculative)
 	 * We should only ever be called for tuples of plain relations or
 	 * materialized views --- recursing on a toast rel is bad news.
 	 */
-	Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
-		   rel->rd_rel->relkind == RELKIND_MATVIEW);
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			Assert(false);
+			break;
+	}
 
 	/*
 	 * Get the tuple descriptor and break down the tuple into fields.
@@ -122,8 +138,24 @@ heap_toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
 	 * We should only ever be called for tuples of plain relations or
 	 * materialized views --- recursing on a toast rel is bad news.
 	 */
-	Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
-		   rel->rd_rel->relkind == RELKIND_MATVIEW);
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			Assert(false);
+			break;
+	}
 
 	/*
 	 * Get the tuple descriptor and break down the tuple(s) into fields.
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index 6b9750c244..f830ef7951 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -135,12 +135,28 @@ index_open(Oid relationId, LOCKMODE lockmode)
 
 	r = relation_open(relationId, lockmode);
 
-	if (r->rd_rel->relkind != RELKIND_INDEX &&
-		r->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not an index",
-						RelationGetRelationName(r))));
+	switch ((RelKind) r->rd_rel->relkind)
+	{
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			break;
+
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not an index",
+							RelationGetRelationName(r))));
+			break;
+	}
 
 	return r;
 }
diff --git a/src/backend/access/table/table.c b/src/backend/access/table/table.c
index 1aa01a54b3..fde36e8477 100644
--- a/src/backend/access/table/table.c
+++ b/src/backend/access/table/table.c
@@ -42,17 +42,32 @@ table_open(Oid relationId, LOCKMODE lockmode)
 
 	r = relation_open(relationId, lockmode);
 
-	if (r->rd_rel->relkind == RELKIND_INDEX ||
-		r->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is an index",
-						RelationGetRelationName(r))));
-	else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is a composite type",
-						RelationGetRelationName(r))));
+	switch ((RelKind) r->rd_rel->relkind)
+	{
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is an index",
+							RelationGetRelationName(r))));
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is a composite type",
+							RelationGetRelationName(r))));
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	return r;
 }
@@ -71,17 +86,32 @@ table_openrv(const RangeVar *relation, LOCKMODE lockmode)
 
 	r = relation_openrv(relation, lockmode);
 
-	if (r->rd_rel->relkind == RELKIND_INDEX ||
-		r->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is an index",
-						RelationGetRelationName(r))));
-	else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is a composite type",
-						RelationGetRelationName(r))));
+	switch ((RelKind) r->rd_rel->relkind)
+	{
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is an index",
+							RelationGetRelationName(r))));
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is a composite type",
+							RelationGetRelationName(r))));
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	return r;
 }
@@ -104,17 +134,32 @@ table_openrv_extended(const RangeVar *relation, LOCKMODE lockmode,
 
 	if (r)
 	{
-		if (r->rd_rel->relkind == RELKIND_INDEX ||
-			r->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is an index",
-							RelationGetRelationName(r))));
-		else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is a composite type",
-							RelationGetRelationName(r))));
+		switch ((RelKind) r->rd_rel->relkind)
+		{
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("\"%s\" is an index",
+								RelationGetRelationName(r))));
+				break;
+			case RELKIND_COMPOSITE_TYPE:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("\"%s\" is a composite type",
+								RelationGetRelationName(r))));
+				break;
+			case RELKIND_SEQUENCE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				break;
+		}
 	}
 
 	return r;
diff --git a/src/backend/access/table/tableam.c b/src/backend/access/table/tableam.c
index 4b2bb29559..e4a11ddd64 100644
--- a/src/backend/access/table/tableam.c
+++ b/src/backend/access/table/tableam.c
@@ -47,28 +47,42 @@ table_slot_callbacks(Relation relation)
 
 	if (relation->rd_tableam)
 		tts_cb = relation->rd_tableam->slot_callbacks(relation);
-	else if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-	{
-		/*
-		 * Historically FDWs expect to store heap tuples in slots. Continue
-		 * handing them one, to make it less painful to adapt FDWs to new
-		 * versions. The cost of a heap slot over a virtual slot is pretty
-		 * small.
-		 */
-		tts_cb = &TTSOpsHeapTuple;
-	}
 	else
-	{
-		/*
-		 * These need to be supported, as some parts of the code (like COPY)
-		 * need to create slots for such relations too. It seems better to
-		 * centralize the knowledge that a heap slot is the right thing in
-		 * that case here.
-		 */
-		Assert(relation->rd_rel->relkind == RELKIND_VIEW ||
-			   relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-		tts_cb = &TTSOpsVirtual;
-	}
+		switch ((RelKind) relation->rd_rel->relkind)
+		{
+			case RELKIND_FOREIGN_TABLE:
+
+				/*
+				 * Historically FDWs expect to store heap tuples in slots.
+				 * Continue handing them one, to make it less painful to adapt
+				 * FDWs to new versions. The cost of a heap slot over a
+				 * virtual slot is pretty small.
+				 */
+				tts_cb = &TTSOpsHeapTuple;
+				break;
+			case RELKIND_VIEW:
+			case RELKIND_PARTITIONED_TABLE:
+
+				/*
+				 * These need to be supported, as some parts of the code (like
+				 * COPY) need to create slots for such relations too. It seems
+				 * better to centralize the knowledge that a heap slot is the
+				 * right thing in that case here.
+				 */
+				tts_cb = &TTSOpsVirtual;
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				Assert(false);
+				break;
+		}
 
 	return tts_cb;
 }
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index c626161408..a80e759a80 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -1765,36 +1765,65 @@ ExecGrant_Relation(InternalGrant *istmt)
 			elog(ERROR, "cache lookup failed for relation %u", relOid);
 		pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
 
-		/* Not sensible to grant on an index */
-		if (pg_class_tuple->relkind == RELKIND_INDEX ||
-			pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is an index",
-							NameStr(pg_class_tuple->relname))));
+		switch ((RelKind) pg_class_tuple->relkind)
+		{
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+				/* Not sensible to grant on an index */
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("\"%s\" is an index",
+								NameStr(pg_class_tuple->relname))));
 
-		/* Composite types aren't tables either */
-		if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is a composite type",
-							NameStr(pg_class_tuple->relname))));
+			case RELKIND_COMPOSITE_TYPE:
+				/* Composite types aren't tables either */
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("\"%s\" is a composite type",
+								NameStr(pg_class_tuple->relname))));
+
+			case RELKIND_SEQUENCE:
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				/* Used GRANT SEQUENCE on a non-sequence? */
+				if (istmt->objtype == OBJECT_SEQUENCE)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is not a sequence",
+									NameStr(pg_class_tuple->relname))));
+				break;
+		}
 
-		/* Used GRANT SEQUENCE on a non-sequence? */
-		if (istmt->objtype == OBJECT_SEQUENCE &&
-			pg_class_tuple->relkind != RELKIND_SEQUENCE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is not a sequence",
-							NameStr(pg_class_tuple->relname))));
 
 		/* Adjust the default permissions based on object type */
 		if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
 		{
-			if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
-				this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
-			else
-				this_privileges = ACL_ALL_RIGHTS_RELATION;
+			switch ((RelKind) pg_class_tuple->relkind)
+			{
+				case RELKIND_SEQUENCE:
+					this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
+					break;
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+				case RELKIND_NULL:
+				default:
+					this_privileges = ACL_ALL_RIGHTS_RELATION;
+					break;
+			}
 		}
 		else
 			this_privileges = istmt->privileges;
@@ -1807,42 +1836,54 @@ ExecGrant_Relation(InternalGrant *istmt)
 		 */
 		if (istmt->objtype == OBJECT_TABLE)
 		{
-			if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
+			switch ((RelKind) pg_class_tuple->relkind)
 			{
-				/*
-				 * For backward compatibility, just throw a warning for
-				 * invalid sequence permissions when using the non-sequence
-				 * GRANT syntax.
-				 */
-				if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
-				{
-					/*
-					 * Mention the object name because the user needs to know
-					 * which operations succeeded.  This is required because
-					 * WARNING allows the command to continue.
-					 */
-					ereport(WARNING,
-							(errcode(ERRCODE_INVALID_GRANT_OPERATION),
-							 errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
-									NameStr(pg_class_tuple->relname))));
-					this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
-				}
-			}
-			else
-			{
-				if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
-				{
+				case RELKIND_SEQUENCE:
+
 					/*
-					 * USAGE is the only permission supported by sequences but
-					 * not by non-sequences.  Don't mention the object name
-					 * because we didn't in the combined TABLE | SEQUENCE
-					 * check.
+					 * For backward compatibility, just throw a warning for
+					 * invalid sequence permissions when using the
+					 * non-sequence GRANT syntax.
 					 */
-					ereport(ERROR,
-							(errcode(ERRCODE_INVALID_GRANT_OPERATION),
-							 errmsg("invalid privilege type %s for table",
-									"USAGE")));
-				}
+					if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
+					{
+						/*
+						 * Mention the object name because the user needs to
+						 * know which operations succeeded.  This is required
+						 * because WARNING allows the command to continue.
+						 */
+						ereport(WARNING,
+								(errcode(ERRCODE_INVALID_GRANT_OPERATION),
+								 errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
+										NameStr(pg_class_tuple->relname))));
+						this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
+					}
+					break;
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+				case RELKIND_NULL:
+				default:
+					if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
+					{
+						/*
+						 * USAGE is the only permission supported by sequences
+						 * but not by non-sequences.  Don't mention the object
+						 * name because we didn't in the combined TABLE |
+						 * SEQUENCE check.
+						 */
+						ereport(ERROR,
+								(errcode(ERRCODE_INVALID_GRANT_OPERATION),
+								 errmsg("invalid privilege type %s for table",
+										"USAGE")));
+					}
+					break;
 			}
 		}
 
@@ -1881,12 +1922,21 @@ ExecGrant_Relation(InternalGrant *istmt)
 								   &isNull);
 		if (isNull)
 		{
-			switch (pg_class_tuple->relkind)
+			switch ((RelKind) pg_class_tuple->relkind)
 			{
 				case RELKIND_SEQUENCE:
 					old_acl = acldefault(OBJECT_SEQUENCE, ownerId);
 					break;
-				default:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+				case RELKIND_NULL:
 					old_acl = acldefault(OBJECT_TABLE, ownerId);
 					break;
 			}
@@ -1925,11 +1975,21 @@ ExecGrant_Relation(InternalGrant *istmt)
 								old_acl, ownerId,
 								&grantorId, &avail_goptions);
 
-			switch (pg_class_tuple->relkind)
+			switch ((RelKind) pg_class_tuple->relkind)
 			{
 				case RELKIND_SEQUENCE:
 					objtype = OBJECT_SEQUENCE;
 					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+				case RELKIND_NULL:
 				default:
 					objtype = OBJECT_TABLE;
 					break;
@@ -2009,20 +2069,36 @@ ExecGrant_Relation(InternalGrant *istmt)
 						 errmsg("invalid privilege type %s for column",
 								privilege_to_string(this_privileges))));
 
-			if (pg_class_tuple->relkind == RELKIND_SEQUENCE &&
-				this_privileges & ~((AclMode) ACL_SELECT))
+			switch ((RelKind) pg_class_tuple->relkind)
 			{
-				/*
-				 * The only column privilege allowed on sequences is SELECT.
-				 * This is a warning not error because we do it that way for
-				 * relation-level privileges.
-				 */
-				ereport(WARNING,
-						(errcode(ERRCODE_INVALID_GRANT_OPERATION),
-						 errmsg("sequence \"%s\" only supports SELECT column privileges",
-								NameStr(pg_class_tuple->relname))));
+				case RELKIND_SEQUENCE:
+					if (this_privileges & ~((AclMode) ACL_SELECT))
+					{
+						/*
+						 * The only column privilege allowed on sequences is
+						 * SELECT. This is a warning not error because we do
+						 * it that way for relation-level privileges.
+						 */
+						ereport(WARNING,
+								(errcode(ERRCODE_INVALID_GRANT_OPERATION),
+								 errmsg("sequence \"%s\" only supports SELECT column privileges",
+										NameStr(pg_class_tuple->relname))));
 
-				this_privileges &= (AclMode) ACL_SELECT;
+						this_privileges &= (AclMode) ACL_SELECT;
+					}
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+				case RELKIND_NULL:
+				default:
+					break;
 			}
 
 			expand_col_privileges(col_privs->cols, relOid,
@@ -3824,11 +3900,21 @@ pg_class_aclmask(Oid table_oid, Oid roleid,
 	if (isNull)
 	{
 		/* No ACL, so build default ACL */
-		switch (classForm->relkind)
+		switch ((RelKind) classForm->relkind)
 		{
 			case RELKIND_SEQUENCE:
 				acl = acldefault(OBJECT_SEQUENCE, ownerId);
 				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
 			default:
 				acl = acldefault(OBJECT_TABLE, ownerId);
 				break;
@@ -5519,58 +5605,85 @@ recordExtObjInitPriv(Oid objoid, Oid classoid)
 		 * composite types.  (These cases are unreachable given the
 		 * restrictions in ALTER EXTENSION ADD, but let's check anyway.)
 		 */
-		if (pg_class_tuple->relkind == RELKIND_INDEX ||
-			pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
-			pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
+		switch ((RelKind) pg_class_tuple->relkind)
 		{
-			ReleaseSysCache(tuple);
-			return;
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+				ReleaseSysCache(tuple);
+				return;
+			case RELKIND_SEQUENCE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				break;
 		}
 
 		/*
 		 * If this isn't a sequence then it's possibly going to have
 		 * column-level ACLs associated with it.
 		 */
-		if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
+		switch ((RelKind) pg_class_tuple->relkind)
 		{
-			AttrNumber	curr_att;
-			AttrNumber	nattrs = pg_class_tuple->relnatts;
-
-			for (curr_att = 1; curr_att <= nattrs; curr_att++)
-			{
-				HeapTuple	attTuple;
-				Datum		attaclDatum;
-
-				attTuple = SearchSysCache2(ATTNUM,
-										   ObjectIdGetDatum(objoid),
-										   Int16GetDatum(curr_att));
-
-				if (!HeapTupleIsValid(attTuple))
-					continue;
-
-				/* ignore dropped columns */
-				if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
+			case RELKIND_SEQUENCE:
+				break;
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
 				{
-					ReleaseSysCache(attTuple);
-					continue;
-				}
-
-				attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
-											  Anum_pg_attribute_attacl,
-											  &isNull);
+					AttrNumber	curr_att;
+					AttrNumber	nattrs = pg_class_tuple->relnatts;
 
-				/* no need to do anything for a NULL ACL */
-				if (isNull)
-				{
-					ReleaseSysCache(attTuple);
-					continue;
+					for (curr_att = 1; curr_att <= nattrs; curr_att++)
+					{
+						HeapTuple	attTuple;
+						Datum		attaclDatum;
+
+						attTuple = SearchSysCache2(ATTNUM,
+												   ObjectIdGetDatum(objoid),
+												   Int16GetDatum(curr_att));
+
+						if (!HeapTupleIsValid(attTuple))
+							continue;
+
+						/* ignore dropped columns */
+						if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
+						{
+							ReleaseSysCache(attTuple);
+							continue;
+						}
+
+						attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
+													  Anum_pg_attribute_attacl,
+													  &isNull);
+
+						/* no need to do anything for a NULL ACL */
+						if (isNull)
+						{
+							ReleaseSysCache(attTuple);
+							continue;
+						}
+
+						recordExtensionInitPrivWorker(objoid, classoid, curr_att,
+													  DatumGetAclP(attaclDatum));
+
+						ReleaseSysCache(attTuple);
+					}
 				}
-
-				recordExtensionInitPrivWorker(objoid, classoid, curr_att,
-											  DatumGetAclP(attaclDatum));
-
-				ReleaseSysCache(attTuple);
-			}
+				break;
 		}
 
 		aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
@@ -5813,40 +5926,70 @@ removeExtObjInitPriv(Oid objoid, Oid classoid)
 		 * composite types.  (These cases are unreachable given the
 		 * restrictions in ALTER EXTENSION DROP, but let's check anyway.)
 		 */
-		if (pg_class_tuple->relkind == RELKIND_INDEX ||
-			pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
-			pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
+		switch ((RelKind) pg_class_tuple->relkind)
 		{
-			ReleaseSysCache(tuple);
-			return;
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+				ReleaseSysCache(tuple);
+				return;
+			case RELKIND_SEQUENCE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				break;
 		}
 
 		/*
 		 * If this isn't a sequence then it's possibly going to have
 		 * column-level ACLs associated with it.
 		 */
-		if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
+		switch ((RelKind) pg_class_tuple->relkind)
 		{
-			AttrNumber	curr_att;
-			AttrNumber	nattrs = pg_class_tuple->relnatts;
+			case RELKIND_SEQUENCE:
+				break;
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				{
+					AttrNumber	curr_att;
+					AttrNumber	nattrs = pg_class_tuple->relnatts;
 
-			for (curr_att = 1; curr_att <= nattrs; curr_att++)
-			{
-				HeapTuple	attTuple;
+					for (curr_att = 1; curr_att <= nattrs; curr_att++)
+					{
+						HeapTuple	attTuple;
 
-				attTuple = SearchSysCache2(ATTNUM,
-										   ObjectIdGetDatum(objoid),
-										   Int16GetDatum(curr_att));
+						attTuple = SearchSysCache2(ATTNUM,
+												   ObjectIdGetDatum(objoid),
+												   Int16GetDatum(curr_att));
 
-				if (!HeapTupleIsValid(attTuple))
-					continue;
+						if (!HeapTupleIsValid(attTuple))
+							continue;
 
-				/* when removing, remove all entries, even dropped columns */
+						/*
+						 * when removing, remove all entries, even dropped
+						 * columns
+						 */
 
-				recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
+						recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
 
-				ReleaseSysCache(attTuple);
-			}
+						ReleaseSysCache(attTuple);
+					}
+				}
+				break;
 		}
 
 		ReleaseSysCache(tuple);
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index b33a2f94af..51af304fa6 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -1395,22 +1395,36 @@ doDeletion(const ObjectAddress *object, int flags)
 			{
 				char		relKind = get_rel_relkind(object->objectId);
 
-				if (relKind == RELKIND_INDEX ||
-					relKind == RELKIND_PARTITIONED_INDEX)
+				switch ((RelKind) relKind)
 				{
-					bool		concurrent = ((flags & PERFORM_DELETION_CONCURRENTLY) != 0);
-					bool		concurrent_lock_mode = ((flags & PERFORM_DELETION_CONCURRENT_LOCK) != 0);
-
-					Assert(object->objectSubId == 0);
-					index_drop(object->objectId, concurrent, concurrent_lock_mode);
-				}
-				else
-				{
-					if (object->objectSubId != 0)
-						RemoveAttributeById(object->objectId,
-											object->objectSubId);
-					else
-						heap_drop_with_catalog(object->objectId);
+					case RELKIND_INDEX:
+					case RELKIND_PARTITIONED_INDEX:
+						{
+							bool		concurrent = ((flags & PERFORM_DELETION_CONCURRENTLY) != 0);
+							bool		concurrent_lock_mode = ((flags & PERFORM_DELETION_CONCURRENT_LOCK) != 0);
+
+							Assert(object->objectSubId == 0);
+							index_drop(object->objectId, concurrent, concurrent_lock_mode);
+						}
+						break;
+					case RELKIND_SEQUENCE:
+					case RELKIND_COMPOSITE_TYPE:
+					case RELKIND_FOREIGN_TABLE:
+					case RELKIND_MATVIEW:
+					case RELKIND_PARTITIONED_TABLE:
+					case RELKIND_RELATION:
+					case RELKIND_TOASTVALUE:
+					case RELKIND_VIEW:
+					case RELKIND_NULL:
+					default:
+						{
+							if (object->objectSubId != 0)
+								RemoveAttributeById(object->objectId,
+													object->objectSubId);
+							else
+								heap_drop_with_catalog(object->objectId);
+						}
+						break;
 				}
 
 				/*
@@ -1419,8 +1433,8 @@ doDeletion(const ObjectAddress *object, int flags)
 				 */
 				if (relKind == RELKIND_SEQUENCE)
 					DeleteSequenceTuple(object->objectId);
-				break;
 			}
+			break;
 
 		case OCLASS_PROC:
 			RemoveFunctionById(object->objectId);
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 3c83fe6bab..9af088b47c 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -335,7 +335,7 @@ heap_create(const char *relname,
 	*relminmxid = InvalidMultiXactId;
 
 	/* Handle reltablespace for specific relkinds. */
-	switch (relkind)
+	switch ((RelKind) relkind)
 	{
 		case RELKIND_VIEW:
 		case RELKIND_COMPOSITE_TYPE:
@@ -360,6 +360,14 @@ heap_create(const char *relname,
 			 */
 			reltablespace = InvalidOid;
 			break;
+
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
 		default:
 			break;
 	}
@@ -415,21 +423,12 @@ heap_create(const char *relname,
 	{
 		RelationOpenSmgr(rel);
 
-		switch (rel->rd_rel->relkind)
+		switch ((RelKind) 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:
@@ -437,6 +436,14 @@ heap_create(const char *relname,
 												relpersistence,
 												relfrozenxid, relminmxid);
 				break;
+			case RELKIND_VIEW:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_NULL:
+			default:
+				Assert(false);
 		}
 	}
 
@@ -506,18 +513,32 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
 	 * Skip this for a view or type relation, since those don't have system
 	 * attributes.
 	 */
-	if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
+	switch ((RelKind) relkind)
 	{
-		for (i = 0; i < natts; i++)
-		{
-			Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
+		case RELKIND_VIEW:
+		case RELKIND_COMPOSITE_TYPE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			for (i = 0; i < natts; i++)
+			{
+				Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
 
-			if (SystemAttributeByName(NameStr(attr->attname)) != NULL)
-				ereport(ERROR,
-						(errcode(ERRCODE_DUPLICATE_COLUMN),
-						 errmsg("column name \"%s\" conflicts with a system column name",
-								NameStr(attr->attname))));
-		}
+				if (SystemAttributeByName(NameStr(attr->attname)) != NULL)
+					ereport(ERROR,
+							(errcode(ERRCODE_DUPLICATE_COLUMN),
+							 errmsg("column name \"%s\" conflicts with a system column name",
+									NameStr(attr->attname))));
+			}
+			break;
 	}
 
 	/*
@@ -842,19 +863,33 @@ AddNewAttributeTuples(Oid new_rel_oid,
 	 * all for a view or type relation.  We don't bother with making datatype
 	 * dependencies here, since presumably all these types are pinned.
 	 */
-	if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
+	switch ((RelKind) relkind)
 	{
-		for (i = 0; i < (int) lengthof(SysAtt); i++)
-		{
-			FormData_pg_attribute attStruct;
+		case RELKIND_VIEW:
+		case RELKIND_COMPOSITE_TYPE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			for (i = 0; i < (int) lengthof(SysAtt); i++)
+			{
+				FormData_pg_attribute attStruct;
 
-			memcpy(&attStruct, SysAtt[i], sizeof(FormData_pg_attribute));
+				memcpy(&attStruct, SysAtt[i], sizeof(FormData_pg_attribute));
 
-			/* Fill in the correct relation OID in the copied tuple */
-			attStruct.attrelid = new_rel_oid;
+				/* Fill in the correct relation OID in the copied tuple */
+				attStruct.attrelid = new_rel_oid;
 
-			InsertPgAttributeTuple(rel, &attStruct, (Datum) 0, indstate);
-		}
+				InsertPgAttributeTuple(rel, &attStruct, (Datum) 0, indstate);
+			}
+			break;
 	}
 
 	/*
@@ -972,7 +1007,7 @@ AddNewRelationTuple(Relation pg_class_desc,
 	 */
 	new_rel_reltup = new_rel_desc->rd_rel;
 
-	switch (relkind)
+	switch ((RelKind) relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_MATVIEW:
@@ -989,6 +1024,12 @@ AddNewRelationTuple(Relation pg_class_desc,
 			new_rel_reltup->reltuples = 1;
 			new_rel_reltup->relallvisible = 0;
 			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
 		default:
 			/* Views, etc, have no disk storage */
 			new_rel_reltup->relpages = 0;
@@ -1221,7 +1262,7 @@ heap_create_with_catalog(const char *relname,
 	 */
 	if (use_user_acl)
 	{
-		switch (relkind)
+		switch ((RelKind) relkind)
 		{
 			case RELKIND_RELATION:
 			case RELKIND_VIEW:
@@ -1235,6 +1276,11 @@ heap_create_with_catalog(const char *relname,
 				relacl = get_user_default_acl(OBJECT_SEQUENCE, ownerid,
 											  relnamespace);
 				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
 			default:
 				relacl = NULL;
 				break;
@@ -1273,13 +1319,27 @@ heap_create_with_catalog(const char *relname,
 	 * during initdb). We do not create them where the use of a relation as
 	 * such is an implementation detail: toast tables, sequences and indexes.
 	 */
-	if (IsUnderPostmaster && (relkind == RELKIND_RELATION ||
-							  relkind == RELKIND_VIEW ||
-							  relkind == RELKIND_MATVIEW ||
-							  relkind == RELKIND_FOREIGN_TABLE ||
-							  relkind == RELKIND_COMPOSITE_TYPE ||
-							  relkind == RELKIND_PARTITIONED_TABLE))
-		new_array_oid = AssignTypeArrayOid();
+	if (IsUnderPostmaster)
+	{
+		switch ((RelKind) relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_VIEW:
+			case RELKIND_MATVIEW:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_PARTITIONED_TABLE:
+				new_array_oid = AssignTypeArrayOid();
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_INDEX:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				break;
+		}
+	}
 
 	/*
 	 * Since defining a relation also defines a complex type, we add a new
@@ -1385,51 +1445,67 @@ heap_create_with_catalog(const char *relname,
 	 * Also, skip this in bootstrap mode, since we don't make dependencies
 	 * while bootstrapping.
 	 */
-	if (relkind != RELKIND_COMPOSITE_TYPE &&
-		relkind != RELKIND_TOASTVALUE &&
-		!IsBootstrapProcessingMode())
+	switch ((RelKind) relkind)
 	{
-		ObjectAddress myself,
-					referenced;
-
-		myself.classId = RelationRelationId;
-		myself.objectId = relid;
-		myself.objectSubId = 0;
-
-		referenced.classId = NamespaceRelationId;
-		referenced.objectId = relnamespace;
-		referenced.objectSubId = 0;
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
-
-		recordDependencyOnOwner(RelationRelationId, relid, ownerid);
-
-		recordDependencyOnNewAcl(RelationRelationId, relid, 0, ownerid, relacl);
-
-		recordDependencyOnCurrentExtension(&myself, false);
-
-		if (reloftypeid)
-		{
-			referenced.classId = TypeRelationId;
-			referenced.objectId = reloftypeid;
-			referenced.objectSubId = 0;
-			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
-		}
-
-		/*
-		 * Make a dependency link to force the relation to be deleted if its
-		 * access method is. Do this only for relation and materialized views.
-		 *
-		 * 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)
-		{
-			referenced.classId = AccessMethodRelationId;
-			referenced.objectId = accessmtd;
-			referenced.objectSubId = 0;
-			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
-		}
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_TOASTVALUE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			if (!IsBootstrapProcessingMode())
+			{
+				ObjectAddress myself,
+							referenced;
+
+				myself.classId = RelationRelationId;
+				myself.objectId = relid;
+				myself.objectSubId = 0;
+
+				referenced.classId = NamespaceRelationId;
+				referenced.objectId = relnamespace;
+				referenced.objectSubId = 0;
+				recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+				recordDependencyOnOwner(RelationRelationId, relid, ownerid);
+
+				recordDependencyOnNewAcl(RelationRelationId, relid, 0, ownerid, relacl);
+
+				recordDependencyOnCurrentExtension(&myself, false);
+
+				if (reloftypeid)
+				{
+					referenced.classId = TypeRelationId;
+					referenced.objectId = reloftypeid;
+					referenced.objectSubId = 0;
+					recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+				}
+
+				/*
+				 * Make a dependency link to force the relation to be deleted
+				 * if its access method is. Do this only for relation and
+				 * materialized views.
+				 *
+				 * 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)
+				{
+					referenced.classId = AccessMethodRelationId;
+					referenced.objectId = accessmtd;
+					referenced.objectSubId = 0;
+					recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+				}
+			}
+			break;
 	}
 
 	/* Post creation hook for new relation */
@@ -2388,12 +2464,28 @@ StoreRelCheck(Relation rel, const char *ccname, Node *expr,
 	 * Partitioned tables do not contain any rows themselves, so a NO INHERIT
 	 * constraint makes no sense.
 	 */
-	if (is_no_inherit &&
-		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-				 errmsg("cannot add NO INHERIT constraint to partitioned table \"%s\"",
-						RelationGetRelationName(rel))));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			if (is_no_inherit)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+						 errmsg("cannot add NO INHERIT constraint to partitioned table \"%s\"",
+								RelationGetRelationName(rel))));
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	/*
 	 * Create the Check Constraint
@@ -3259,8 +3351,23 @@ heap_truncate_one_rel(Relation rel)
 	 * Truncate the relation.  Partitioned tables have no storage, so there is
 	 * nothing to do for them here.
 	 */
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		return;
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			return;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	/* Truncate the underlying relation */
 	table_relation_nontransactional_truncate(rel);
@@ -3313,9 +3420,26 @@ heap_truncate_check_FKs(List *relations, bool tempTables)
 	{
 		Relation	rel = lfirst(cell);
 
-		if (rel->rd_rel->relhastriggers ||
-			rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-			oids = lappend_oid(oids, RelationGetRelid(rel));
+		switch ((RelKind) rel->rd_rel->relkind)
+		{
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				if (!rel->rd_rel->relhastriggers)
+					break;
+				/* fallthrough */
+			case RELKIND_PARTITIONED_TABLE:
+				oids = lappend_oid(oids, RelationGetRelid(rel));
+				break;
+		}
 	}
 
 	/*
@@ -3538,7 +3662,24 @@ StorePartitionKey(Relation rel,
 	ObjectAddress myself;
 	ObjectAddress referenced;
 
-	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			Assert(false);
+			break;
+	}
 
 	/* Copy the partition attribute numbers, opclass OIDs into arrays */
 	partattrs_vec = buildint2vector(partattrs, partnatts);
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index cdc01c49c9..16b753258d 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -2220,8 +2220,24 @@ index_drop(Oid indexId, bool concurrent, bool concurrent_lock_mode)
 	/*
 	 * Schedule physical removal of the files (if any)
 	 */
-	if (userIndexRelation->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
-		RelationDropStorage(userIndexRelation);
+	switch ((RelKind) userIndexRelation->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_INDEX:
+			break;
+		case RELKIND_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			RelationDropStorage(userIndexRelation);
+			break;
+	}
 
 	/*
 	 * Close and flush the index's relcache entry, to ensure relcache doesn't
@@ -2748,7 +2764,23 @@ index_update_stats(Relation rel,
 	rd_rel = (Form_pg_class) GETSTRUCT(tuple);
 
 	/* Should this be a more comprehensive test? */
-	Assert(rd_rel->relkind != RELKIND_PARTITIONED_INDEX);
+	switch ((RelKind) rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_INDEX:
+			Assert(false);
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_INDEX:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	/* Apply required updates, if any, to copied tuple */
 
@@ -2764,10 +2796,25 @@ index_update_stats(Relation rel,
 		BlockNumber relpages = RelationGetNumberOfBlocks(rel);
 		BlockNumber relallvisible;
 
-		if (rd_rel->relkind != RELKIND_INDEX)
-			visibilitymap_count(rel, &relallvisible, NULL);
-		else					/* don't bother for indexes */
-			relallvisible = 0;
+		switch ((RelKind) rd_rel->relkind)
+		{
+			case RELKIND_INDEX:
+				relallvisible = 0;
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				visibilitymap_count(rel, &relallvisible, NULL);
+				break;
+		}
 
 		if (rd_rel->relpages != (int32) relpages)
 		{
@@ -3478,9 +3525,25 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 	 * The case of reindexing partitioned tables and indexes is handled
 	 * differently by upper layers, so this case shouldn't arise.
 	 */
-	if (iRel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
-		elog(ERROR, "unsupported relation kind for index \"%s\"",
-			 RelationGetRelationName(iRel));
+	switch ((RelKind) iRel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_INDEX:
+			elog(ERROR, "unsupported relation kind for index \"%s\"",
+				 RelationGetRelationName(iRel));
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	/*
 	 * Don't allow reindex on temp tables of other backends ... their local
@@ -3694,14 +3757,27 @@ reindex_relation(Oid relid, int flags, int options)
 	 * (REINDEX SCHEMA) and happen to come across a partitioned table.  The
 	 * partitions may be reindexed on their own anyway.
 	 */
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		ereport(WARNING,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("REINDEX of partitioned tables is not yet implemented, skipping \"%s\"",
-						RelationGetRelationName(rel))));
-		table_close(rel, ShareLock);
-		return false;
+		case RELKIND_PARTITIONED_TABLE:
+			ereport(WARNING,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("REINDEX of partitioned tables is not yet implemented, skipping \"%s\"",
+							RelationGetRelationName(rel))));
+			table_close(rel, ShareLock);
+			return false;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	toast_relid = rel->rd_rel->reltoastrelid;
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 534df8e802..4d8c1ca4c5 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -97,7 +97,8 @@
  */
 typedef struct
 {
-	const char *class_descr;	/* string describing the catalog, for internal error messages */
+	const char *class_descr;	/* string describing the catalog, for internal
+								 * error messages */
 	Oid			class_oid;		/* oid of catalog */
 	Oid			oid_index_oid;	/* oid of index on system oid column */
 	int			oid_catcache_id;	/* id of catcache on system oid column	*/
@@ -1342,48 +1343,136 @@ get_relation_by_qualified_name(ObjectType objtype, List *object,
 	switch (objtype)
 	{
 		case OBJECT_INDEX:
-			if (relation->rd_rel->relkind != RELKIND_INDEX &&
-				relation->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is not an index",
-								RelationGetRelationName(relation))));
+			switch ((RelKind) relation->rd_rel->relkind)
+			{
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+					break;
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+				case RELKIND_NULL:
+				default:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is not an index",
+									RelationGetRelationName(relation))));
+			}
 			break;
 		case OBJECT_SEQUENCE:
-			if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is not a sequence",
-								RelationGetRelationName(relation))));
+			switch ((RelKind) relation->rd_rel->relkind)
+			{
+				case RELKIND_SEQUENCE:
+					break;
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+				case RELKIND_NULL:
+				default:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is not a sequence",
+									RelationGetRelationName(relation))));
+			}
 			break;
 		case OBJECT_TABLE:
-			if (relation->rd_rel->relkind != RELKIND_RELATION &&
-				relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is not a table",
-								RelationGetRelationName(relation))));
+			switch ((RelKind) relation->rd_rel->relkind)
+			{
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+					break;
+				case RELKIND_SEQUENCE:
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_MATVIEW:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+				case RELKIND_NULL:
+				default:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is not a table",
+									RelationGetRelationName(relation))));
+			}
 			break;
 		case OBJECT_VIEW:
-			if (relation->rd_rel->relkind != RELKIND_VIEW)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is not a view",
-								RelationGetRelationName(relation))));
+			switch ((RelKind) relation->rd_rel->relkind)
+			{
+				case RELKIND_VIEW:
+					break;
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_SEQUENCE:
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_MATVIEW:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_NULL:
+				default:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is not a view",
+									RelationGetRelationName(relation))));
+			}
 			break;
 		case OBJECT_MATVIEW:
-			if (relation->rd_rel->relkind != RELKIND_MATVIEW)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is not a materialized view",
-								RelationGetRelationName(relation))));
+			switch ((RelKind) relation->rd_rel->relkind)
+			{
+				case RELKIND_MATVIEW:
+					break;
+				case RELKIND_VIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_SEQUENCE:
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_NULL:
+				default:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is not a materialized view",
+									RelationGetRelationName(relation))));
+			}
 			break;
 		case OBJECT_FOREIGN_TABLE:
-			if (relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is not a foreign table",
-								RelationGetRelationName(relation))));
+			switch ((RelKind) relation->rd_rel->relkind)
+			{
+				case RELKIND_FOREIGN_TABLE:
+					break;
+				case RELKIND_MATVIEW:
+				case RELKIND_VIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_SEQUENCE:
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_NULL:
+				default:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is not a foreign table",
+									RelationGetRelationName(relation))));
+			}
 			break;
 		default:
 			elog(ERROR, "unrecognized objtype: %d", (int) objtype);
@@ -3795,7 +3884,7 @@ getRelationDescription(StringInfo buffer, Oid relid)
 
 	relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
 
-	switch (relForm->relkind)
+	switch ((RelKind) relForm->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
@@ -3831,6 +3920,7 @@ getRelationDescription(StringInfo buffer, Oid relid)
 			appendStringInfo(buffer, _("foreign table %s"),
 							 relname);
 			break;
+		case RELKIND_NULL:
 		default:
 			/* shouldn't get here */
 			appendStringInfo(buffer, _("relation %s"),
@@ -4276,7 +4366,7 @@ getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId)
 		elog(ERROR, "cache lookup failed for relation %u", relid);
 	relForm = (Form_pg_class) GETSTRUCT(relTup);
 
-	switch (relForm->relkind)
+	switch ((RelKind) relForm->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
@@ -4304,6 +4394,7 @@ getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId)
 		case RELKIND_FOREIGN_TABLE:
 			appendStringInfoString(buffer, "foreign table");
 			break;
+		case RELKIND_NULL:
 		default:
 			/* shouldn't get here */
 			appendStringInfoString(buffer, "relation");
@@ -5451,7 +5542,7 @@ strlist_to_textarray(List *list)
 ObjectType
 get_relkind_objtype(char relkind)
 {
-	switch (relkind)
+	switch ((RelKind) relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
@@ -5469,6 +5560,8 @@ get_relkind_objtype(char relkind)
 			return OBJECT_FOREIGN_TABLE;
 		case RELKIND_TOASTVALUE:
 			return OBJECT_TABLE;
+		case RELKIND_NULL:
+		case RELKIND_COMPOSITE_TYPE:
 		default:
 			/* Per above, don't raise an error */
 			return OBJECT_TABLE;
diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 239ac017fa..65c4b96289 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -235,8 +235,25 @@ has_partition_attrs(Relation rel, Bitmapset *attnums, bool *used_in_expr)
 	ListCell   *partexprs_item;
 	int			i;
 
-	if (attnums == NULL || rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		return false;
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			if (attnums == NULL)
+				return false;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			return false;
+	}
 
 	key = RelationGetPartitionKey(rel);
 	partnatts = get_partition_natts(key);
diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c
index 21cfdcace9..2ba55bc6b3 100644
--- a/src/backend/catalog/pg_depend.c
+++ b/src/backend/catalog/pg_depend.c
@@ -837,14 +837,31 @@ getOwnedSequences_internal(Oid relid, AttrNumber attnum, char deptype)
 		 * must be what we are looking for.  (We need the relkind test because
 		 * indexes can also have auto dependencies on columns.)
 		 */
-		if (deprec->classid == RelationRelationId &&
-			deprec->objsubid == 0 &&
-			deprec->refobjsubid != 0 &&
-			(deprec->deptype == DEPENDENCY_AUTO || deprec->deptype == DEPENDENCY_INTERNAL) &&
-			get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
+		switch ((RelKind) get_rel_relkind(deprec->objid))
 		{
-			if (!deptype || deprec->deptype == deptype)
-				result = lappend_oid(result, deprec->objid);
+			case RELKIND_SEQUENCE:
+				if (deprec->classid == RelationRelationId &&
+					deprec->objsubid == 0 &&
+					deprec->refobjsubid != 0 &&
+					(deprec->deptype == DEPENDENCY_AUTO ||
+					 deprec->deptype == DEPENDENCY_INTERNAL) &&
+					(!deptype || deprec->deptype == deptype))
+				{
+					result = lappend_oid(result, deprec->objid);
+				}
+				break;
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				break;
 		}
 	}
 
@@ -940,9 +957,23 @@ get_constraint_index(Oid constraintId)
 			 * This is pure paranoia; there shouldn't be any other relkinds
 			 * dependent on a constraint.
 			 */
-			if (relkind != RELKIND_INDEX &&
-				relkind != RELKIND_PARTITIONED_INDEX)
-				continue;
+			switch ((RelKind) relkind)
+			{
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+					break;
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+				case RELKIND_NULL:
+				default:
+					continue;
+			}
 
 			indexId = deprec->objid;
 			break;
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 09946be788..336de8e97f 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -50,13 +50,27 @@ static void
 check_publication_add_relation(Relation targetrel)
 {
 	/* Must be a regular or partitioned table */
-	if (RelationGetForm(targetrel)->relkind != RELKIND_RELATION &&
-		RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("\"%s\" is not a table",
-						RelationGetRelationName(targetrel)),
-				 errdetail("Only tables can be added to publications.")));
+	switch ((RelKind) RelationGetForm(targetrel)->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("\"%s\" is not a table",
+							RelationGetRelationName(targetrel)),
+					 errdetail("Only tables can be added to publications.")));
+	}
 
 	/* Can't be system table */
 	if (IsCatalogRelation(targetrel))
@@ -97,11 +111,26 @@ check_publication_add_relation(Relation targetrel)
 static bool
 is_publishable_class(Oid relid, Form_pg_class reltuple)
 {
-	return (reltuple->relkind == RELKIND_RELATION ||
-			reltuple->relkind == RELKIND_PARTITIONED_TABLE) &&
-		!IsCatalogRelationOid(relid) &&
-		reltuple->relpersistence == RELPERSISTENCE_PERMANENT &&
-		relid >= FirstNormalObjectId;
+	switch ((RelKind) reltuple->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			return (!IsCatalogRelationOid(relid) &&
+					reltuple->relpersistence == RELPERSISTENCE_PERMANENT &&
+					relid >= FirstNormalObjectId);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			return false;
+	}
 }
 
 /*
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 79ffe317dd..bca5c5b1fa 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -658,10 +658,25 @@ GenerateTypeDependencies(HeapTuple typeTuple,
 	{
 		ObjectAddressSet(referenced, RelationRelationId, typeForm->typrelid);
 
-		if (relationKind != RELKIND_COMPOSITE_TYPE)
-			recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
-		else
-			recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
+		switch ((RelKind) relationKind)
+		{
+			case RELKIND_COMPOSITE_TYPE:
+				recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
+				break;
+		}
 	}
 
 	/*
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 3f7ab8d389..d878d07660 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -99,12 +99,27 @@ BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid)
 
 	rel = table_openrv(makeRangeVar(NULL, relName, -1), AccessExclusiveLock);
 
-	if (rel->rd_rel->relkind != RELKIND_RELATION &&
-		rel->rd_rel->relkind != RELKIND_MATVIEW)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table or materialized view",
-						relName)));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table or materialized view",
+							relName)));
+			break;
+	}
 
 	/* create_toast_table does all the work */
 	if (!create_toast_table(rel, toastOid, toastIndexOid, (Datum) 0,
@@ -394,8 +409,23 @@ needs_toast_table(Relation rel)
 	/*
 	 * No need to create a TOAST table for partitioned tables.
 	 */
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		return false;
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			return false;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	/*
 	 * We cannot allow toasting a shared relation after initdb (because
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 924ef37c81..1a64bc22e9 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -196,54 +196,75 @@ analyze_rel(Oid relid, RangeVar *relation,
 	/*
 	 * Check that it's of an analyzable relkind, and set up appropriately.
 	 */
-	if (onerel->rd_rel->relkind == RELKIND_RELATION ||
-		onerel->rd_rel->relkind == RELKIND_MATVIEW)
+	switch ((RelKind) onerel->rd_rel->relkind)
 	{
-		/* Regular table, so we'll use the regular row acquisition function */
-		acquirefunc = acquire_sample_rows;
-		/* Also get regular table's size */
-		relpages = RelationGetNumberOfBlocks(onerel);
-	}
-	else if (onerel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-	{
-		/*
-		 * For a foreign table, call the FDW's hook function to see whether it
-		 * supports analysis.
-		 */
-		FdwRoutine *fdwroutine;
-		bool		ok = false;
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+			{
+				/*
+				 * Regular table, so we'll use the regular row acquisition
+				 * function
+				 */
+				acquirefunc = acquire_sample_rows;
+				/* Also get regular table's size */
+				relpages = RelationGetNumberOfBlocks(onerel);
+			}
+			break;
+		case RELKIND_FOREIGN_TABLE:
+			{
+				/*
+				 * For a foreign table, call the FDW's hook function to see
+				 * whether it supports analysis.
+				 */
+				FdwRoutine *fdwroutine;
+				bool		ok = false;
 
-		fdwroutine = GetFdwRoutineForRelation(onerel, false);
+				fdwroutine = GetFdwRoutineForRelation(onerel, false);
 
-		if (fdwroutine->AnalyzeForeignTable != NULL)
-			ok = fdwroutine->AnalyzeForeignTable(onerel,
-												 &acquirefunc,
-												 &relpages);
+				if (fdwroutine->AnalyzeForeignTable != NULL)
+					ok = fdwroutine->AnalyzeForeignTable(onerel,
+														 &acquirefunc,
+														 &relpages);
 
-		if (!ok)
-		{
-			ereport(WARNING,
-					(errmsg("skipping \"%s\" --- cannot analyze this foreign table",
-							RelationGetRelationName(onerel))));
-			relation_close(onerel, ShareUpdateExclusiveLock);
-			return;
-		}
-	}
-	else if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-	{
-		/*
-		 * For partitioned tables, we want to do the recursive ANALYZE below.
-		 */
-	}
-	else
-	{
-		/* No need for a WARNING if we already complained during VACUUM */
-		if (!(params->options & VACOPT_VACUUM))
-			ereport(WARNING,
-					(errmsg("skipping \"%s\" --- cannot analyze non-tables or special system tables",
-							RelationGetRelationName(onerel))));
-		relation_close(onerel, ShareUpdateExclusiveLock);
-		return;
+				if (!ok)
+				{
+					ereport(WARNING,
+							(errmsg("skipping \"%s\" --- cannot analyze this foreign table",
+									RelationGetRelationName(onerel))));
+					relation_close(onerel, ShareUpdateExclusiveLock);
+					return;
+				}
+			}
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+			{
+				/*
+				 * For partitioned tables, we want to do the recursive ANALYZE
+				 * below.
+				 */
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			{
+				/*
+				 * No need for a WARNING if we already complained during
+				 * VACUUM
+				 */
+				if (!(params->options & VACOPT_VACUUM))
+					ereport(WARNING,
+							(errmsg("skipping \"%s\" --- cannot analyze non-tables or special system tables",
+									RelationGetRelationName(onerel))));
+				relation_close(onerel, ShareUpdateExclusiveLock);
+				return;
+			}
+			break;
 	}
 
 	/*
@@ -259,9 +280,25 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 * Do the normal non-recursive ANALYZE.  We can skip this for partitioned
 	 * tables, which don't contain any rows.
 	 */
-	if (onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		do_analyze_rel(onerel, params, va_cols, acquirefunc,
-					   relpages, false, in_outer_xact, elevel);
+	switch ((RelKind) onerel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			do_analyze_rel(onerel, params, va_cols, acquirefunc,
+						   relpages, false, in_outer_xact, elevel);
+			break;
+	}
 
 	/*
 	 * If there are child tables, do recursive ANALYZE.
@@ -1283,49 +1320,67 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
 		}
 
 		/* Check table type (MATVIEW can't happen, but might as well allow) */
-		if (childrel->rd_rel->relkind == RELKIND_RELATION ||
-			childrel->rd_rel->relkind == RELKIND_MATVIEW)
-		{
-			/* Regular table, so use the regular row acquisition function */
-			acquirefunc = acquire_sample_rows;
-			relpages = RelationGetNumberOfBlocks(childrel);
-		}
-		else if (childrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		switch ((RelKind) childrel->rd_rel->relkind)
 		{
-			/*
-			 * For a foreign table, call the FDW's hook function to see
-			 * whether it supports analysis.
-			 */
-			FdwRoutine *fdwroutine;
-			bool		ok = false;
+			case RELKIND_RELATION:
+			case RELKIND_MATVIEW:
+				{
+					/*
+					 * Regular table, so use the regular row acquisition
+					 * function
+					 */
+					acquirefunc = acquire_sample_rows;
+					relpages = RelationGetNumberOfBlocks(childrel);
+				}
+				break;
+			case RELKIND_FOREIGN_TABLE:
+				{
+					/*
+					 * For a foreign table, call the FDW's hook function to
+					 * see whether it supports analysis.
+					 */
+					FdwRoutine *fdwroutine;
+					bool		ok = false;
 
-			fdwroutine = GetFdwRoutineForRelation(childrel, false);
+					fdwroutine = GetFdwRoutineForRelation(childrel, false);
 
-			if (fdwroutine->AnalyzeForeignTable != NULL)
-				ok = fdwroutine->AnalyzeForeignTable(childrel,
-													 &acquirefunc,
-													 &relpages);
+					if (fdwroutine->AnalyzeForeignTable != NULL)
+						ok = fdwroutine->AnalyzeForeignTable(childrel,
+															 &acquirefunc,
+															 &relpages);
 
-			if (!ok)
-			{
-				/* ignore, but release the lock on it */
-				Assert(childrel != onerel);
-				table_close(childrel, AccessShareLock);
-				continue;
-			}
-		}
-		else
-		{
-			/*
-			 * ignore, but release the lock on it.  don't try to unlock the
-			 * passed-in relation
-			 */
-			Assert(childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-			if (childrel != onerel)
-				table_close(childrel, AccessShareLock);
-			else
-				table_close(childrel, NoLock);
-			continue;
+					if (!ok)
+					{
+						/* ignore, but release the lock on it */
+						Assert(childrel != onerel);
+						table_close(childrel, AccessShareLock);
+						continue;
+					}
+				}
+				break;
+			case RELKIND_PARTITIONED_TABLE:
+				{
+					/*
+					 * ignore, but release the lock on it.  don't try to
+					 * unlock the passed-in relation
+					 */
+					if (childrel != onerel)
+						table_close(childrel, AccessShareLock);
+					else
+						table_close(childrel, NoLock);
+					continue;
+				}
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				Assert(false);
+				break;
 		}
 
 		/* OK, we'll process this child */
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 04d12a7ece..d1ac9a51e4 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -127,10 +127,26 @@ cluster(ClusterStmt *stmt, bool isTopLevel)
 		/*
 		 * Reject clustering a partitioned table.
 		 */
-		if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-			ereport(ERROR,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("cannot cluster a partitioned table")));
+		switch ((RelKind) rel->rd_rel->relkind)
+		{
+			case RELKIND_PARTITIONED_TABLE:
+				ereport(ERROR,
+						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+						 errmsg("cannot cluster a partitioned table")));
+				break;
+			case RELKIND_RELATION:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				break;
+		}
 
 		if (stmt->indexname == NULL)
 		{
@@ -383,12 +399,28 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
 	 * multi-relation request -- for example, CLUSTER was run on the entire
 	 * database.
 	 */
-	if (OldHeap->rd_rel->relkind == RELKIND_MATVIEW &&
-		!RelationIsPopulated(OldHeap))
+	switch ((RelKind) OldHeap->rd_rel->relkind)
 	{
-		relation_close(OldHeap, AccessExclusiveLock);
-		pgstat_progress_end_command();
-		return;
+		case RELKIND_MATVIEW:
+			if (!RelationIsPopulated(OldHeap))
+			{
+				relation_close(OldHeap, AccessExclusiveLock);
+				pgstat_progress_end_command();
+				return;
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	/*
@@ -484,10 +516,26 @@ mark_index_clustered(Relation rel, Oid indexOid, bool is_internal)
 	ListCell   *index;
 
 	/* Disallow applying to a partitioned table */
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("cannot mark index clustered in partitioned table")));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			ereport(ERROR,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("cannot mark index clustered in partitioned table")));
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	/*
 	 * If the index is already marked clustered, no need to do anything.
@@ -1103,12 +1151,26 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 	 */
 
 	/* set rel1's frozen Xid and minimum MultiXid */
-	if (relform1->relkind != RELKIND_INDEX)
+	switch ((RelKind) relform1->relkind)
 	{
-		Assert(!TransactionIdIsValid(frozenXid) ||
-			   TransactionIdIsNormal(frozenXid));
-		relform1->relfrozenxid = frozenXid;
-		relform1->relminmxid = cutoffMulti;
+		case RELKIND_INDEX:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			Assert(!TransactionIdIsValid(frozenXid) ||
+				   TransactionIdIsNormal(frozenXid));
+			relform1->relfrozenxid = frozenXid;
+			relform1->relminmxid = cutoffMulti;
+			break;
 	}
 
 	/* swap size statistics too, since new rel has freshly-updated stats */
@@ -1267,27 +1329,43 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 	 * valid index. The swap can actually be safely done only if the relations
 	 * have indexes.
 	 */
-	if (swap_toast_by_content &&
-		relform1->relkind == RELKIND_TOASTVALUE &&
-		relform2->relkind == RELKIND_TOASTVALUE)
+	switch ((RelKind) relform1->relkind)
 	{
-		Oid			toastIndex1,
-					toastIndex2;
-
-		/* Get valid index for each relation */
-		toastIndex1 = toast_get_valid_index(r1,
-											AccessExclusiveLock);
-		toastIndex2 = toast_get_valid_index(r2,
-											AccessExclusiveLock);
-
-		swap_relation_files(toastIndex1,
-							toastIndex2,
-							target_is_pg_class,
-							swap_toast_by_content,
-							is_internal,
-							InvalidTransactionId,
-							InvalidMultiXactId,
-							mapped_tables);
+		case RELKIND_TOASTVALUE:
+			if (swap_toast_by_content &&
+				relform2->relkind == RELKIND_TOASTVALUE)
+			{
+				Oid			toastIndex1,
+							toastIndex2;
+
+				/* Get valid index for each relation */
+				toastIndex1 = toast_get_valid_index(r1,
+													AccessExclusiveLock);
+				toastIndex2 = toast_get_valid_index(r2,
+													AccessExclusiveLock);
+
+				swap_relation_files(toastIndex1,
+									toastIndex2,
+									target_is_pg_class,
+									swap_toast_by_content,
+									is_internal,
+									InvalidTransactionId,
+									InvalidMultiXactId,
+									mapped_tables);
+			}
+			break;
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	/* Clean up. */
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index 0ff9ca9f2c..400b14cc54 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -90,16 +90,27 @@ CommentObject(CommentStmt *stmt)
 			 * versions, so dumping per-column comments could create reload
 			 * failures.
 			 */
-			if (relation->rd_rel->relkind != RELKIND_RELATION &&
-				relation->rd_rel->relkind != RELKIND_VIEW &&
-				relation->rd_rel->relkind != RELKIND_MATVIEW &&
-				relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
-				relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
-				relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
-								RelationGetRelationName(relation))));
+			switch ((RelKind) relation->rd_rel->relkind)
+			{
+				case RELKIND_RELATION:
+				case RELKIND_VIEW:
+				case RELKIND_MATVIEW:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_PARTITIONED_TABLE:
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_SEQUENCE:
+				case RELKIND_INDEX:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_NULL:
+				default:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
+									RelationGetRelationName(relation))));
+					break;
+			}
 			break;
 		default:
 			break;
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 3e199bdfd0..01a5261506 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -1831,42 +1831,58 @@ BeginCopyTo(ParseState *pstate,
 	bool		pipe = (filename == NULL);
 	MemoryContext oldcontext;
 
-	if (rel != NULL && rel->rd_rel->relkind != RELKIND_RELATION)
+	if (rel != NULL)
 	{
-		if (rel->rd_rel->relkind == RELKIND_VIEW)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot copy from view \"%s\"",
-							RelationGetRelationName(rel)),
-					 errhint("Try the COPY (SELECT ...) TO variant.")));
-		else if (rel->rd_rel->relkind == RELKIND_MATVIEW)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot copy from materialized view \"%s\"",
-							RelationGetRelationName(rel)),
-					 errhint("Try the COPY (SELECT ...) TO variant.")));
-		else if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot copy from foreign table \"%s\"",
-							RelationGetRelationName(rel)),
-					 errhint("Try the COPY (SELECT ...) TO variant.")));
-		else if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot copy from sequence \"%s\"",
-							RelationGetRelationName(rel))));
-		else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot copy from partitioned table \"%s\"",
-							RelationGetRelationName(rel)),
-					 errhint("Try the COPY (SELECT ...) TO variant.")));
-		else
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot copy from non-table relation \"%s\"",
-							RelationGetRelationName(rel))));
+		switch ((RelKind) rel->rd_rel->relkind)
+		{
+			case RELKIND_RELATION:
+				break;
+			case RELKIND_SEQUENCE:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot copy from sequence \"%s\"",
+								RelationGetRelationName(rel))));
+				break;
+			case RELKIND_FOREIGN_TABLE:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot copy from foreign table \"%s\"",
+								RelationGetRelationName(rel)),
+						 errhint("Try the COPY (SELECT ...) TO variant.")));
+				break;
+			case RELKIND_MATVIEW:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot copy from materialized view \"%s\"",
+								RelationGetRelationName(rel)),
+						 errhint("Try the COPY (SELECT ...) TO variant.")));
+				break;
+			case RELKIND_PARTITIONED_TABLE:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot copy from partitioned table \"%s\"",
+								RelationGetRelationName(rel)),
+						 errhint("Try the COPY (SELECT ...) TO variant.")));
+				break;
+			case RELKIND_VIEW:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot copy from view \"%s\"",
+								RelationGetRelationName(rel)),
+						 errhint("Try the COPY (SELECT ...) TO variant.")));
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot copy from non-table relation \"%s\"",
+								RelationGetRelationName(rel))));
+				break;
+		}
 	}
 
 	cstate = BeginCopy(pstate, false, rel, query, queryRelId, attnamelist,
@@ -2390,8 +2406,24 @@ CopyMultiInsertInfoInit(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 	 * Buffers for partitioned tables will just be setup when we need to send
 	 * tuples their way for the first time.
 	 */
-	if (rri->ri_RelationDesc->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		CopyMultiInsertInfoSetupBuffer(miinfo, rri);
+	switch ((RelKind) rri->ri_RelationDesc->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			CopyMultiInsertInfoSetupBuffer(miinfo, rri);
+			break;
+	}
 }
 
 /*
@@ -2675,33 +2707,46 @@ CopyFrom(CopyState cstate)
 	 * an INSTEAD OF INSERT row trigger.  (Currently, such triggers are only
 	 * allowed on views, so we only hint about them in the view case.)
 	 */
-	if (cstate->rel->rd_rel->relkind != RELKIND_RELATION &&
-		cstate->rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
-		cstate->rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE &&
-		!(cstate->rel->trigdesc &&
+	if (!(cstate->rel->trigdesc &&
 		  cstate->rel->trigdesc->trig_insert_instead_row))
 	{
-		if (cstate->rel->rd_rel->relkind == RELKIND_VIEW)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot copy to view \"%s\"",
-							RelationGetRelationName(cstate->rel)),
-					 errhint("To enable copying to a view, provide an INSTEAD OF INSERT trigger.")));
-		else if (cstate->rel->rd_rel->relkind == RELKIND_MATVIEW)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot copy to materialized view \"%s\"",
-							RelationGetRelationName(cstate->rel))));
-		else if (cstate->rel->rd_rel->relkind == RELKIND_SEQUENCE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot copy to sequence \"%s\"",
-							RelationGetRelationName(cstate->rel))));
-		else
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot copy to non-table relation \"%s\"",
-							RelationGetRelationName(cstate->rel))));
+		switch ((RelKind) cstate->rel->rd_rel->relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_TABLE:
+				break;
+			case RELKIND_VIEW:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot copy to view \"%s\"",
+								RelationGetRelationName(cstate->rel)),
+						 errhint("To enable copying to a view, provide an INSTEAD OF INSERT trigger.")));
+				break;
+			case RELKIND_MATVIEW:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot copy to materialized view \"%s\"",
+								RelationGetRelationName(cstate->rel))));
+				break;
+			case RELKIND_SEQUENCE:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot copy to sequence \"%s\"",
+								RelationGetRelationName(cstate->rel))));
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot copy to non-table relation \"%s\"",
+								RelationGetRelationName(cstate->rel))));
+				break;
+		}
 	}
 
 	/*
@@ -2736,11 +2781,25 @@ CopyFrom(CopyState cstate)
 		 * tuples to a small number of partitions.  It seems better just to
 		 * raise an ERROR for partitioned tables.
 		 */
-		if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		switch ((RelKind) cstate->rel->rd_rel->relkind)
 		{
-			ereport(ERROR,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("cannot perform COPY FREEZE on a partitioned table")));
+			case RELKIND_PARTITIONED_TABLE:
+				ereport(ERROR,
+						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+						 errmsg("cannot perform COPY FREEZE on a partitioned table")));
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				break;
 		}
 
 		/*
@@ -2825,8 +2884,24 @@ CopyFrom(CopyState cstate)
 	 * If the named relation is a partitioned table, initialize state for
 	 * CopyFrom tuple routing.
 	 */
-	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		proute = ExecSetupPartitionTupleRouting(estate, NULL, cstate->rel);
+	switch ((RelKind) cstate->rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			proute = ExecSetupPartitionTupleRouting(estate, NULL, cstate->rel);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	if (cstate->whereClause)
 		cstate->qualexpr = ExecInitQual(castNode(List, cstate->whereClause),
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 472e69fdaf..a8375d3b5d 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -3280,8 +3280,8 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt,
 		case OBJECT_SUBSCRIPTION:
 		case OBJECT_TABLESPACE:
 			ereport(ERROR,
-				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-				 errmsg("cannot add an object of this type to an extension")));
+					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+					 errmsg("cannot add an object of this type to an extension")));
 			break;
 		default:
 			/* OK */
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 2baca12c5f..194e1836cb 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -615,7 +615,7 @@ DefineIndex(Oid relationId,
 	namespaceId = RelationGetNamespace(rel);
 
 	/* Ensure that it makes sense to index this kind of relation */
-	switch (rel->rd_rel->relkind)
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_MATVIEW:
@@ -633,6 +633,13 @@ DefineIndex(Oid relationId,
 					 errmsg("cannot create index on foreign table \"%s\"",
 							RelationGetRelationName(rel))));
 			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
 		default:
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
@@ -1190,18 +1197,33 @@ DefineIndex(Oid relationId,
 				 * those if a regular index, or fail if trying to create a
 				 * constraint index.
 				 */
-				if (childrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+				switch ((RelKind) childrel->rd_rel->relkind)
 				{
-					if (stmt->unique || stmt->primary)
-						ereport(ERROR,
-								(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-								 errmsg("cannot create unique index on partitioned table \"%s\"",
-										RelationGetRelationName(rel)),
-								 errdetail("Table \"%s\" contains partitions that are foreign tables.",
-										   RelationGetRelationName(rel))));
-
-					table_close(childrel, lockmode);
-					continue;
+					case RELKIND_FOREIGN_TABLE:
+						{
+							if (stmt->unique || stmt->primary)
+								ereport(ERROR,
+										(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+										 errmsg("cannot create unique index on partitioned table \"%s\"",
+												RelationGetRelationName(rel)),
+										 errdetail("Table \"%s\" contains partitions that are foreign tables.",
+												   RelationGetRelationName(rel))));
+
+							table_close(childrel, lockmode);
+							continue;
+						}
+						break;
+					case RELKIND_SEQUENCE:
+					case RELKIND_COMPOSITE_TYPE:
+					case RELKIND_INDEX:
+					case RELKIND_MATVIEW:
+					case RELKIND_PARTITIONED_TABLE:
+					case RELKIND_RELATION:
+					case RELKIND_TOASTVALUE:
+					case RELKIND_VIEW:
+					case RELKIND_NULL:
+					default:
+						break;
 				}
 
 				childidxs = RelationGetIndexList(childrel);
@@ -2451,10 +2473,23 @@ ReindexIndex(RangeVar *indexRelation, int options, bool concurrent)
 	 */
 	irel = index_open(indOid, NoLock);
 
-	if (irel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
+	switch ((RelKind) irel->rd_rel->relkind)
 	{
-		ReindexPartitionedIndex(irel);
-		return;
+		case RELKIND_PARTITIONED_INDEX:
+			ReindexPartitionedIndex(irel);
+			return;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	persistence = irel->rd_rel->relpersistence;
@@ -2510,11 +2545,25 @@ RangeVarCallbackForReindexIndex(const RangeVar *relation,
 	relkind = get_rel_relkind(relId);
 	if (!relkind)
 		return;
-	if (relkind != RELKIND_INDEX &&
-		relkind != RELKIND_PARTITIONED_INDEX)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not an index", relation->relname)));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not an index", relation->relname)));
+	}
 
 	/* Check permissions */
 	if (!pg_class_ownercheck(relId, GetUserId()))
@@ -2694,9 +2743,23 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
 		 * partitioned tables, and expand that afterwards into relids,
 		 * ignoring any duplicates.
 		 */
-		if (classtuple->relkind != RELKIND_RELATION &&
-			classtuple->relkind != RELKIND_MATVIEW)
-			continue;
+		switch ((RelKind) classtuple->relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_MATVIEW:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				continue;
+		}
 
 		/* Skip temp tables of other backends; we can't reindex them at all */
 		if (classtuple->relpersistence == RELPERSISTENCE_TEMP &&
@@ -2867,7 +2930,7 @@ ReindexRelationConcurrently(Oid relationOid, int options)
 	 * Extract the list of indexes that are going to be rebuilt based on the
 	 * relation Oid given by caller.
 	 */
-	switch (relkind)
+	switch ((RelKind) relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_MATVIEW:
@@ -3017,6 +3080,12 @@ ReindexRelationConcurrently(Oid relationOid, int options)
 					 errmsg("REINDEX of partitioned tables is not yet implemented, skipping \"%s\"",
 							get_rel_name(relationOid))));
 			return false;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
 		default:
 			/* Return error if type of relation is not supported */
 			ereport(ERROR,
@@ -3443,30 +3512,43 @@ ReindexRelationConcurrently(Oid relationOid, int options)
 	/* Log what we did */
 	if (options & REINDEXOPT_VERBOSE)
 	{
-		if (relkind == RELKIND_INDEX)
-			ereport(INFO,
-					(errmsg("index \"%s.%s\" was reindexed",
-							relationNamespace, relationName),
-					 errdetail("%s.",
-							   pg_rusage_show(&ru0))));
-		else
+		switch ((RelKind) relkind)
 		{
-			foreach(lc, newIndexIds)
-			{
-				Oid			indOid = lfirst_oid(lc);
-
+			case RELKIND_INDEX:
 				ereport(INFO,
 						(errmsg("index \"%s.%s\" was reindexed",
-								get_namespace_name(get_rel_namespace(indOid)),
-								get_rel_name(indOid))));
-				/* Don't show rusage here, since it's not per index. */
-			}
+								relationNamespace, relationName),
+						 errdetail("%s.",
+								   pg_rusage_show(&ru0))));
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				foreach(lc, newIndexIds)
+				{
+					Oid			indOid = lfirst_oid(lc);
+
+					ereport(INFO,
+							(errmsg("index \"%s.%s\" was reindexed",
+									get_namespace_name(get_rel_namespace(indOid)),
+									get_rel_name(indOid))));
+					/* Don't show rusage here, since it's not per index. */
+				}
 
-			ereport(INFO,
-					(errmsg("table \"%s.%s\" was reindexed",
-							relationNamespace, relationName),
-					 errdetail("%s.",
-							   pg_rusage_show(&ru0))));
+				ereport(INFO,
+						(errmsg("table \"%s.%s\" was reindexed",
+								relationNamespace, relationName),
+						 errdetail("%s.",
+								   pg_rusage_show(&ru0))));
+				break;
 		}
 	}
 
@@ -3508,8 +3590,24 @@ IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
 	bool		fix_dependencies;
 
 	/* Make sure this is an index */
-	Assert(partitionIdx->rd_rel->relkind == RELKIND_INDEX ||
-		   partitionIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
+	switch ((RelKind) partitionIdx->rd_rel->relkind)
+	{
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			break;				/* ok */
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			Assert(false);
+			break;
+	}
 
 	/*
 	 * Scan pg_inherits for rows linking our index to some parent.
diff --git a/src/backend/commands/lockcmds.c b/src/backend/commands/lockcmds.c
index d8cafc42bb..deb885adf8 100644
--- a/src/backend/commands/lockcmds.c
+++ b/src/backend/commands/lockcmds.c
@@ -56,10 +56,26 @@ LockTableCommand(LockStmt *lockstmt)
 										  RangeVarCallbackForLockTable,
 										  (void *) &lockstmt->mode);
 
-		if (get_rel_relkind(reloid) == RELKIND_VIEW)
-			LockViewRecurse(reloid, lockstmt->mode, lockstmt->nowait, NIL);
-		else if (recurse)
-			LockTableRecurse(reloid, lockstmt->mode, lockstmt->nowait);
+		switch ((RelKind) get_rel_relkind(reloid))
+		{
+			case RELKIND_VIEW:
+				LockViewRecurse(reloid, lockstmt->mode, lockstmt->nowait, NIL);
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				if (recurse)
+					LockTableRecurse(reloid, lockstmt->mode, lockstmt->nowait);
+				break;
+		}
 	}
 }
 
@@ -84,12 +100,27 @@ RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid,
 								 * check */
 
 	/* Currently, we only allow plain tables or views to be locked */
-	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE &&
-		relkind != RELKIND_VIEW)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table or view",
-						rv->relname)));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_VIEW:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table or view",
+							rv->relname)));
+			break;
+	}
 
 	/*
 	 * Make note if a temporary relation has been accessed in this
@@ -201,10 +232,27 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context)
 				 strcmp(rte->eref->aliasname, "new") == 0))
 				continue;
 
-			/* Currently, we only allow plain tables or views to be locked. */
-			if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE &&
-				relkind != RELKIND_VIEW)
-				continue;
+			switch ((RelKind) relkind)
+			{
+					/*
+					 * Currently, we only allow plain tables or views to be
+					 * locked.
+					 */
+				case RELKIND_RELATION:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_VIEW:
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_NULL:
+				default:
+					continue;
+			}
 
 			/* Check infinite recursion in the view definition. */
 			if (list_member_oid(context->ancestor_views, relid))
@@ -227,10 +275,26 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context)
 						 errmsg("could not obtain lock on relation \"%s\"",
 								relname)));
 
-			if (relkind == RELKIND_VIEW)
-				LockViewRecurse(relid, context->lockmode, context->nowait, context->ancestor_views);
-			else if (rte->inh)
-				LockTableRecurse(relid, context->lockmode, context->nowait);
+			switch ((RelKind) relkind)
+			{
+				case RELKIND_VIEW:
+					LockViewRecurse(relid, context->lockmode, context->nowait, context->ancestor_views);
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_NULL:
+				default:
+					if (rte->inh)
+						LockTableRecurse(relid, context->lockmode, context->nowait);
+					break;
+			}
 		}
 
 		return query_tree_walker(query,
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index 4b4e469493..f96459bc93 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -89,10 +89,26 @@ RangeVarCallbackForPolicy(const RangeVar *rv, Oid relid, Oid oldrelid,
 						rv->relname)));
 
 	/* Relation type MUST be a table. */
-	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table", rv->relname)));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table", rv->relname)));
+			break;
+	}
 
 	ReleaseSysCache(tuple);
 }
@@ -388,12 +404,27 @@ RemovePolicyById(Oid policy_id)
 	relid = ((Form_pg_policy) GETSTRUCT(tuple))->polrelid;
 
 	rel = table_open(relid, AccessExclusiveLock);
-	if (rel->rd_rel->relkind != RELKIND_RELATION &&
-		rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table",
-						RelationGetRelationName(rel))));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table",
+							RelationGetRelationName(rel))));
+			break;
+	}
 
 	if (!allowSystemTableMods && IsSystemRelation(rel))
 		ereport(ERROR,
@@ -478,12 +509,27 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
 
 	rel = relation_open(relid, AccessExclusiveLock);
 
-	if (rel->rd_rel->relkind != RELKIND_RELATION &&
-		rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table",
-						RelationGetRelationName(rel))));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table",
+							RelationGetRelationName(rel))));
+			break;
+	}
 
 	if (!allowSystemTableMods && IsSystemRelation(rel))
 		ereport(ERROR,
diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c
index eabbc7473b..b340fd9b9c 100644
--- a/src/backend/commands/publicationcmds.c
+++ b/src/backend/commands/publicationcmds.c
@@ -548,33 +548,49 @@ OpenTableList(List *tables)
 		 * children other than its partitions, which need not be explicitly
 		 * added to the publication.
 		 */
-		if (recurse && rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
+		switch ((RelKind) rel->rd_rel->relkind)
 		{
-			List	   *children;
-			ListCell   *child;
-
-			children = find_all_inheritors(myrelid, ShareUpdateExclusiveLock,
-										   NULL);
-
-			foreach(child, children)
-			{
-				Oid			childrelid = lfirst_oid(child);
-
-				/* Allow query cancel in case this takes a long time */
-				CHECK_FOR_INTERRUPTS();
-
-				/*
-				 * Skip duplicates if user specified both parent and child
-				 * tables.
-				 */
-				if (list_member_oid(relids, childrelid))
-					continue;
-
-				/* find_all_inheritors already got lock */
-				rel = table_open(childrelid, NoLock);
-				rels = lappend(rels, rel);
-				relids = lappend_oid(relids, childrelid);
-			}
+			case RELKIND_PARTITIONED_TABLE:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				if (recurse)
+				{
+					List	   *children;
+					ListCell   *child;
+
+					children = find_all_inheritors(myrelid, ShareUpdateExclusiveLock,
+												   NULL);
+
+					foreach(child, children)
+					{
+						Oid			childrelid = lfirst_oid(child);
+
+						/* Allow query cancel in case this takes a long time */
+						CHECK_FOR_INTERRUPTS();
+
+						/*
+						 * Skip duplicates if user specified both parent and
+						 * child tables.
+						 */
+						if (list_member_oid(relids, childrelid))
+							continue;
+
+						/* find_all_inheritors already got lock */
+						rel = table_open(childrelid, NoLock);
+						rels = lappend(rels, rel);
+						relids = lappend_oid(relids, childrelid);
+					}
+				}
 		}
 	}
 
diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c
index ee036e9087..77bd351b96 100644
--- a/src/backend/commands/seclabel.c
+++ b/src/backend/commands/seclabel.c
@@ -180,16 +180,27 @@ ExecSecLabelStmt(SecLabelStmt *stmt)
 			 * materialized views, composite types, and foreign tables (which
 			 * are the only relkinds for which pg_dump will dump labels).
 			 */
-			if (relation->rd_rel->relkind != RELKIND_RELATION &&
-				relation->rd_rel->relkind != RELKIND_VIEW &&
-				relation->rd_rel->relkind != RELKIND_MATVIEW &&
-				relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
-				relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
-				relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
-								RelationGetRelationName(relation))));
+			switch ((RelKind) relation->rd_rel->relkind)
+			{
+				case RELKIND_RELATION:
+				case RELKIND_VIEW:
+				case RELKIND_MATVIEW:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_PARTITIONED_TABLE:
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_SEQUENCE:
+				case RELKIND_INDEX:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_NULL:
+				default:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
+									RelationGetRelationName(relation))));
+					break;
+			}
 			break;
 		default:
 			break;
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 6aab73bfd4..6652bcff7f 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1675,14 +1675,27 @@ process_owned_by(Relation seqrel, List *owned_by, bool for_identity)
 		tablerel = relation_openrv(rel, AccessShareLock);
 
 		/* Must be a regular or foreign table */
-		if (!(tablerel->rd_rel->relkind == RELKIND_RELATION ||
-			  tablerel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
-			  tablerel->rd_rel->relkind == RELKIND_VIEW ||
-			  tablerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("referenced relation \"%s\" is not a table or foreign table",
-							RelationGetRelationName(tablerel))));
+		switch ((RelKind) tablerel->rd_rel->relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_VIEW:
+			case RELKIND_PARTITIONED_TABLE:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("referenced relation \"%s\" is not a table or foreign table",
+								RelationGetRelationName(tablerel))));
+				break;
+		}
 
 		/* We insist on same owner and schema */
 		if (seqrel->rd_rel->relowner != tablerel->rd_rel->relowner)
diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c
index 974828545c..d0976ae826 100644
--- a/src/backend/commands/statscmds.c
+++ b/src/backend/commands/statscmds.c
@@ -122,14 +122,27 @@ CreateStatistics(CreateStatsStmt *stmt)
 		rel = relation_openrv((RangeVar *) rln, ShareUpdateExclusiveLock);
 
 		/* Restrict to allowed relation types */
-		if (rel->rd_rel->relkind != RELKIND_RELATION &&
-			rel->rd_rel->relkind != RELKIND_MATVIEW &&
-			rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
-			rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("relation \"%s\" is not a table, foreign table, or materialized view",
-							RelationGetRelationName(rel))));
+		switch ((RelKind) rel->rd_rel->relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_MATVIEW:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_TABLE:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("relation \"%s\" is not a table, foreign table, or materialized view",
+								RelationGetRelationName(rel))));
+				break;
+		}
 
 		/* You must own the relation to create stats on it */
 		if (!pg_class_ownercheck(RelationGetRelid(rel), stxowner))
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 1105c5b8ec..0dd3b07c77 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -619,8 +619,24 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 
 	if (stmt->partspec != NULL)
 	{
-		if (relkind != RELKIND_RELATION)
-			elog(ERROR, "unexpected relkind: %d", (int) relkind);
+		switch ((RelKind) relkind)
+		{
+			case RELKIND_RELATION:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				elog(ERROR, "unexpected relkind: %d", (int) relkind);
+				break;
+		}
 
 		relkind = RELKIND_PARTITIONED_TABLE;
 		partitioned = true;
@@ -746,7 +762,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 	reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
 									 true, false);
 
-	switch (relkind)
+	switch ((RelKind) relkind)
 	{
 		case RELKIND_VIEW:
 			(void) view_reloptions(reloptions, true);
@@ -754,6 +770,15 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 		case RELKIND_PARTITIONED_TABLE:
 			(void) partitioned_table_reloptions(reloptions, true);
 			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
 		default:
 			(void) heap_reloptions(relkind, reloptions, true);
 	}
@@ -866,10 +891,25 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 					 errmsg("specifying a table access method is not supported on a partitioned table")));
 
 	}
-	else if (relkind == RELKIND_RELATION ||
-			 relkind == RELKIND_TOASTVALUE ||
-			 relkind == RELKIND_MATVIEW)
-		accessMethod = default_table_access_method;
+	else
+		switch ((RelKind) relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_MATVIEW:
+				accessMethod = default_table_access_method;
+				break;
+			case RELKIND_VIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_INDEX:
+			case RELKIND_NULL:
+			default:
+				break;
+		}
 
 	/* look up the access method, verify it is for a table */
 	if (accessMethod != NULL)
@@ -956,11 +996,26 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 		 * We are going to try to validate the partition bound specification
 		 * against the partition key of parentRel, so it better have one.
 		 */
-		if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-					 errmsg("\"%s\" is not partitioned",
-							RelationGetRelationName(parent))));
+		switch ((RelKind) parent->rd_rel->relkind)
+		{
+			case RELKIND_PARTITIONED_TABLE:
+				break;
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_INDEX:
+			case RELKIND_NULL:
+			default:
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+						 errmsg("\"%s\" is not partitioned",
+								RelationGetRelationName(parent))));
+		}
 
 		/*
 		 * The partition constraint of the default partition depends on the
@@ -1104,20 +1159,34 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 			IndexStmt  *idxstmt;
 			Oid			constraintOid;
 
-			if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+			switch ((RelKind) rel->rd_rel->relkind)
 			{
-				if (idxRel->rd_index->indisunique)
-					ereport(ERROR,
-							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-							 errmsg("cannot create foreign partition of partitioned table \"%s\"",
-									RelationGetRelationName(parent)),
-							 errdetail("Table \"%s\" contains indexes that are unique.",
-									   RelationGetRelationName(parent))));
-				else
-				{
-					index_close(idxRel, AccessShareLock);
-					continue;
-				}
+				case RELKIND_FOREIGN_TABLE:
+					if (idxRel->rd_index->indisunique)
+						ereport(ERROR,
+								(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+								 errmsg("cannot create foreign partition of partitioned table \"%s\"",
+										RelationGetRelationName(parent)),
+								 errdetail("Table \"%s\" contains indexes that are unique.",
+										   RelationGetRelationName(parent))));
+					else
+					{
+						index_close(idxRel, AccessShareLock);
+						continue;
+					}
+					break;
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_MATVIEW:
+				case RELKIND_VIEW:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_SEQUENCE:
+				case RELKIND_INDEX:
+				case RELKIND_NULL:
+				default:
+					break;
 			}
 
 			attmap = build_attrmap_by_name(RelationGetDescr(rel),
@@ -1448,12 +1517,27 @@ RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
 	 * the relation is RELKIND_PARTITIONED_TABLE.  An equivalent problem
 	 * exists with indexes.
 	 */
-	if (classform->relkind == RELKIND_PARTITIONED_TABLE)
-		expected_relkind = RELKIND_RELATION;
-	else if (classform->relkind == RELKIND_PARTITIONED_INDEX)
-		expected_relkind = RELKIND_INDEX;
-	else
-		expected_relkind = classform->relkind;
+	switch ((RelKind) classform->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			expected_relkind = RELKIND_RELATION;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+			expected_relkind = RELKIND_INDEX;
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_SEQUENCE:
+		case RELKIND_INDEX:
+		case RELKIND_NULL:
+		default:
+			expected_relkind = classform->relkind;
+			break;
+	}
 
 	if (relkind != expected_relkind)
 		DropErrorMsgWrongType(rel->relname, classform->relkind, relkind);
@@ -1470,26 +1554,43 @@ RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
 	 * only concerns indexes of toast relations that became invalid during a
 	 * REINDEX CONCURRENTLY process.
 	 */
-	if (IsSystemClass(relOid, classform) && relkind == RELKIND_INDEX)
+	switch ((RelKind) relkind)
 	{
-		HeapTuple	locTuple;
-		Form_pg_index indexform;
-		bool		indisvalid;
+		case RELKIND_INDEX:
+			if (IsSystemClass(relOid, classform))
+			{
+				HeapTuple	locTuple;
+				Form_pg_index indexform;
+				bool		indisvalid;
 
-		locTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(relOid));
-		if (!HeapTupleIsValid(locTuple))
-		{
-			ReleaseSysCache(tuple);
-			return;
-		}
+				locTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(relOid));
+				if (!HeapTupleIsValid(locTuple))
+				{
+					ReleaseSysCache(tuple);
+					return;
+				}
 
-		indexform = (Form_pg_index) GETSTRUCT(locTuple);
-		indisvalid = indexform->indisvalid;
-		ReleaseSysCache(locTuple);
+				indexform = (Form_pg_index) GETSTRUCT(locTuple);
+				indisvalid = indexform->indisvalid;
+				ReleaseSysCache(locTuple);
 
-		/* Mark object as being an invalid index of system catalogs */
-		if (!indisvalid)
-			invalid_system_index = true;
+				/* Mark object as being an invalid index of system catalogs */
+				if (!indisvalid)
+					invalid_system_index = true;
+			}
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_SEQUENCE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	/* In the case of an invalid index, it is fine to bypass this check */
@@ -1508,12 +1609,28 @@ RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
 	 * we do it the other way around.  No error if we don't find a pg_index
 	 * entry, though --- the relation may have been dropped.
 	 */
-	if ((relkind == RELKIND_INDEX || relkind == RELKIND_PARTITIONED_INDEX) &&
-		relOid != oldRelOid)
+	switch ((RelKind) relkind)
 	{
-		state->heapOid = IndexGetRelation(relOid, true);
-		if (OidIsValid(state->heapOid))
-			LockRelationOid(state->heapOid, heap_lockmode);
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			if (relOid != oldRelOid)
+			{
+				state->heapOid = IndexGetRelation(relOid, true);
+				if (OidIsValid(state->heapOid))
+					LockRelationOid(state->heapOid, heap_lockmode);
+			}
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_SEQUENCE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	/*
@@ -1635,11 +1752,28 @@ ExecuteTruncate(TruncateStmt *stmt)
 					relids_logged = lappend_oid(relids_logged, childrelid);
 			}
 		}
-		else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot truncate only a partitioned table"),
-					 errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
+		else
+			switch ((RelKind) rel->rd_rel->relkind)
+			{
+				case RELKIND_PARTITIONED_TABLE:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("cannot truncate only a partitioned table"),
+							 errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
+					break;
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_MATVIEW:
+				case RELKIND_VIEW:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_SEQUENCE:
+				case RELKIND_NULL:
+				default:
+					break;
+			}
 	}
 
 	ExecuteTruncateGuts(rels, relids, relids_logged,
@@ -1815,9 +1949,24 @@ ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged,
 	{
 		Relation	rel = (Relation) lfirst(cell);
 
-		/* Skip partitioned tables as there is nothing to do */
-		if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-			continue;
+		switch ((RelKind) rel->rd_rel->relkind)
+		{
+				/* Skip partitioned tables as there is nothing to do */
+			case RELKIND_PARTITIONED_TABLE:
+				continue;
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_SEQUENCE:
+			case RELKIND_NULL:
+			default:
+				break;
+		}
 
 		/*
 		 * Normally, we need a transaction-safe truncation here.  However, if
@@ -1969,11 +2118,25 @@ truncate_check_rel(Oid relid, Form_pg_class reltuple)
 	 * the latter are only being included here for the following checks; no
 	 * physical truncation will occur in their case.)
 	 */
-	if (reltuple->relkind != RELKIND_RELATION &&
-		reltuple->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table", relname)));
+	switch ((RelKind) reltuple->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_SEQUENCE:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table", relname)));
+	}
 
 	if (!allowSystemTableMods && IsSystemClass(relid, reltuple))
 		ereport(ERROR,
@@ -2235,26 +2398,39 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
 		 * We do not allow partitioned tables and partitions to participate in
 		 * regular inheritance.
 		 */
-		if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
-			!is_partition)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot inherit from partitioned table \"%s\"",
-							RelationGetRelationName(relation))));
+		switch ((RelKind) relation->rd_rel->relkind)
+		{
+			case RELKIND_PARTITIONED_TABLE:
+				if (!is_partition)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("cannot inherit from partitioned table \"%s\"",
+									RelationGetRelationName(relation))));
+				break;
+			case RELKIND_RELATION:
+			case RELKIND_FOREIGN_TABLE:
+				break;
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_SEQUENCE:
+			case RELKIND_NULL:
+			default:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("inherited relation \"%s\" is not a table or foreign table",
+								RelationGetRelationName(relation))));
+		}
+
 		if (relation->rd_rel->relispartition && !is_partition)
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("cannot inherit from partition \"%s\"",
 							RelationGetRelationName(relation))));
 
-		if (relation->rd_rel->relkind != RELKIND_RELATION &&
-			relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
-			relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("inherited relation \"%s\" is not a table or foreign table",
-							RelationGetRelationName(relation))));
-
 		/*
 		 * If the parent is permanent, so must be all of its partitions.  Note
 		 * that inheritance allows that case.
@@ -2996,18 +3172,26 @@ renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
 	 * change names that are hardcoded into the system, hence the following
 	 * restriction.
 	 */
-	if (relkind != RELKIND_RELATION &&
-		relkind != RELKIND_VIEW &&
-		relkind != RELKIND_MATVIEW &&
-		relkind != RELKIND_COMPOSITE_TYPE &&
-		relkind != RELKIND_INDEX &&
-		relkind != RELKIND_PARTITIONED_INDEX &&
-		relkind != RELKIND_FOREIGN_TABLE &&
-		relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table, view, materialized view, composite type, index, or foreign table",
-						NameStr(classform->relname))));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_TOASTVALUE:
+		case RELKIND_SEQUENCE:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table, view, materialized view, composite type, index, or foreign table",
+							NameStr(classform->relname))));
+	}
 
 	/*
 	 * permissions checking.  only the owner of a class can change its schema.
@@ -3105,17 +3289,33 @@ renameatt_internal(Oid myrelid,
 	}
 
 	/* rename attributes in typed tables of composite type */
-	if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
+	switch ((RelKind) targetrelation->rd_rel->relkind)
 	{
-		List	   *child_oids;
-		ListCell   *lo;
+		case RELKIND_COMPOSITE_TYPE:
+			{
+				List	   *child_oids;
+				ListCell   *lo;
 
-		child_oids = find_typed_table_dependencies(targetrelation->rd_rel->reltype,
-												   RelationGetRelationName(targetrelation),
-												   behavior);
+				child_oids = find_typed_table_dependencies(targetrelation->rd_rel->reltype,
+														   RelationGetRelationName(targetrelation),
+														   behavior);
 
-		foreach(lo, child_oids)
-			renameatt_internal(lfirst_oid(lo), oldattname, newattname, true, true, 0, behavior);
+				foreach(lo, child_oids)
+					renameatt_internal(lfirst_oid(lo), oldattname, newattname, true, true, 0, behavior);
+			}
+			break;
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_SEQUENCE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	attrelation = table_open(AttributeRelationId, RowExclusiveLock);
@@ -3489,13 +3689,28 @@ RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bo
 	/*
 	 * Also rename the associated constraint, if any.
 	 */
-	if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
-		targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
+	switch ((RelKind) targetrelation->rd_rel->relkind)
 	{
-		Oid			constraintId = get_index_constraint(myrelid);
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			{
+				Oid			constraintId = get_index_constraint(myrelid);
 
-		if (OidIsValid(constraintId))
-			RenameConstraintById(constraintId, newrelname);
+				if (OidIsValid(constraintId))
+					RenameConstraintById(constraintId, newrelname);
+			}
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_SEQUENCE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	/*
@@ -3542,14 +3757,29 @@ CheckTableNotInUse(Relation rel, const char *stmt)
 				 errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
 						stmt, RelationGetRelationName(rel))));
 
-	if (rel->rd_rel->relkind != RELKIND_INDEX &&
-		rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
-		AfterTriggerPendingOnRel(RelationGetRelid(rel)))
-		ereport(ERROR,
-				(errcode(ERRCODE_OBJECT_IN_USE),
-		/* translator: first %s is a SQL command, eg ALTER TABLE */
-				 errmsg("cannot %s \"%s\" because it has pending trigger events",
-						stmt, RelationGetRelationName(rel))));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_SEQUENCE:
+		case RELKIND_NULL:
+		default:
+			if (AfterTriggerPendingOnRel(RelationGetRelid(rel)))
+				ereport(ERROR,
+						(errcode(ERRCODE_OBJECT_IN_USE),
+				/* translator: first %s is a SQL command, eg ALTER TABLE */
+						 errmsg("cannot %s \"%s\" because it has pending trigger events",
+								stmt, RelationGetRelationName(rel))));
+			break;
+	}
 }
 
 /*
@@ -4364,11 +4594,27 @@ ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
 		 * not modify anything about it that will change its toasting
 		 * requirement, so no need to check.
 		 */
-		if (((tab->relkind == RELKIND_RELATION ||
-			  tab->relkind == RELKIND_PARTITIONED_TABLE) &&
-			 tab->partition_constraint == NULL) ||
-			tab->relkind == RELKIND_MATVIEW)
-			AlterTableCreateToastTable(tab->relid, (Datum) 0, lockmode);
+		switch ((RelKind) tab->relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_PARTITIONED_TABLE:
+				if (tab->partition_constraint != NULL)
+					break;
+				/* fallthrough */
+			case RELKIND_MATVIEW:
+				AlterTableCreateToastTable(tab->relid, (Datum) 0, lockmode);
+				break;
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_VIEW:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_SEQUENCE:
+			case RELKIND_NULL:
+			default:
+				break;
+		}
 	}
 }
 
@@ -4546,15 +4792,29 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
 			break;
 		case AT_SetTableSpace:	/* SET TABLESPACE */
 
-			/*
-			 * Only do this for partitioned tables and indexes, for which this
-			 * is just a catalog change.  Other relation types which have
-			 * storage are handled by Phase 3.
-			 */
-			if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
-				rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
-				ATExecSetTableSpaceNoStorage(rel, tab->newTableSpace);
-
+			switch ((RelKind) rel->rd_rel->relkind)
+			{
+					/*
+					 * Only do this for partitioned tables and indexes, for
+					 * which this is just a catalog change.  Other relation
+					 * types which have storage are handled by Phase 3.
+					 */
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_PARTITIONED_INDEX:
+					ATExecSetTableSpaceNoStorage(rel, tab->newTableSpace);
+					break;
+				case RELKIND_RELATION:
+				case RELKIND_MATVIEW:
+				case RELKIND_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_VIEW:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_SEQUENCE:
+				case RELKIND_NULL:
+				default:
+					break;
+			}
 			break;
 		case AT_SetRelOptions:	/* SET (...) */
 		case AT_ResetRelOptions:	/* RESET (...) */
@@ -4645,11 +4905,26 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
 			cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
 									  cur_pass, context);
 			Assert(cmd != NULL);
-			if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-				ATExecAttachPartition(wqueue, rel, (PartitionCmd *) cmd->def);
-			else
-				ATExecAttachPartitionIdx(wqueue, rel,
-										 ((PartitionCmd *) cmd->def)->name);
+			switch ((RelKind) rel->rd_rel->relkind)
+			{
+				case RELKIND_PARTITIONED_TABLE:
+					ATExecAttachPartition(wqueue, rel, (PartitionCmd *) cmd->def);
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_RELATION:
+				case RELKIND_MATVIEW:
+				case RELKIND_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_VIEW:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_SEQUENCE:
+				case RELKIND_NULL:
+				default:
+					ATExecAttachPartitionIdx(wqueue, rel,
+											 ((PartitionCmd *) cmd->def)->name);
+					break;
+			}
 			break;
 		case AT_DetachPartition:
 			cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
@@ -5477,7 +5752,7 @@ ATSimplePermissions(Relation rel, int allowed_targets)
 {
 	int			actual_target;
 
-	switch (rel->rd_rel->relkind)
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
@@ -5501,6 +5776,9 @@ ATSimplePermissions(Relation rel, int allowed_targets)
 		case RELKIND_FOREIGN_TABLE:
 			actual_target = ATT_FOREIGN_TABLE;
 			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
 		default:
 			actual_target = 0;
 			break;
@@ -5600,35 +5878,49 @@ ATSimpleRecursion(List **wqueue, Relation rel,
 	 * and partitioned tables have children, so no need to search for other
 	 * relkinds.
 	 */
-	if (recurse &&
-		(rel->rd_rel->relkind == RELKIND_RELATION ||
-		 rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
-		 rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		Oid			relid = RelationGetRelid(rel);
-		ListCell   *child;
-		List	   *children;
-
-		children = find_all_inheritors(relid, lockmode, NULL);
+		case RELKIND_RELATION:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+			if (recurse)
+			{
+				Oid			relid = RelationGetRelid(rel);
+				ListCell   *child;
+				List	   *children;
 
-		/*
-		 * find_all_inheritors does the recursive search of the inheritance
-		 * hierarchy, so all we have to do is process all of the relids in the
-		 * list that it returns.
-		 */
-		foreach(child, children)
-		{
-			Oid			childrelid = lfirst_oid(child);
-			Relation	childrel;
+				children = find_all_inheritors(relid, lockmode, NULL);
 
-			if (childrelid == relid)
-				continue;
-			/* find_all_inheritors already got lock */
-			childrel = relation_open(childrelid, NoLock);
-			CheckTableNotInUse(childrel, "ALTER TABLE");
-			ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
-			relation_close(childrel, NoLock);
-		}
+				/*
+				 * find_all_inheritors does the recursive search of the
+				 * inheritance hierarchy, so all we have to do is process all
+				 * of the relids in the list that it returns.
+				 */
+				foreach(child, children)
+				{
+					Oid			childrelid = lfirst_oid(child);
+					Relation	childrel;
+
+					if (childrelid == relid)
+						continue;
+					/* find_all_inheritors already got lock */
+					childrel = relation_open(childrelid, NoLock);
+					CheckTableNotInUse(childrel, "ALTER TABLE");
+					ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
+					relation_close(childrel, NoLock);
+				}
+			}
+			break;
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 }
 
@@ -5773,47 +6065,62 @@ find_composite_type_dependencies(Oid typeOid, Relation origRelation,
 		rel = relation_open(pg_depend->objid, AccessShareLock);
 		att = TupleDescAttr(rel->rd_att, pg_depend->objsubid - 1);
 
-		if (rel->rd_rel->relkind == RELKIND_RELATION ||
-			rel->rd_rel->relkind == RELKIND_MATVIEW ||
-			rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		{
-			if (origTypeName)
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
-								origTypeName,
-								RelationGetRelationName(rel),
-								NameStr(att->attname))));
-			else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
-								RelationGetRelationName(origRelation),
-								RelationGetRelationName(rel),
-								NameStr(att->attname))));
-			else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
-								RelationGetRelationName(origRelation),
-								RelationGetRelationName(rel),
-								NameStr(att->attname))));
-			else
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
-								RelationGetRelationName(origRelation),
-								RelationGetRelationName(rel),
-								NameStr(att->attname))));
-		}
-		else if (OidIsValid(rel->rd_rel->reltype))
+		switch ((RelKind) rel->rd_rel->relkind)
 		{
-			/*
-			 * A view or composite type itself isn't a problem, but we must
-			 * recursively check for indirect dependencies via its rowtype.
-			 */
-			find_composite_type_dependencies(rel->rd_rel->reltype,
-											 origRelation, origTypeName);
+			case RELKIND_RELATION:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+				{
+					if (origTypeName)
+						ereport(ERROR,
+								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+								 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
+										origTypeName,
+										RelationGetRelationName(rel),
+										NameStr(att->attname))));
+					else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
+						ereport(ERROR,
+								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+								 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
+										RelationGetRelationName(origRelation),
+										RelationGetRelationName(rel),
+										NameStr(att->attname))));
+					else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+						ereport(ERROR,
+								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+								 errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
+										RelationGetRelationName(origRelation),
+										RelationGetRelationName(rel),
+										NameStr(att->attname))));
+					else
+						ereport(ERROR,
+								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+								 errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
+										RelationGetRelationName(origRelation),
+										RelationGetRelationName(rel),
+										NameStr(att->attname))));
+				}
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_VIEW:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				if (OidIsValid(rel->rd_rel->reltype))
+				{
+					/*
+					 * A view or composite type itself isn't a problem, but we
+					 * must recursively check for indirect dependencies via
+					 * its rowtype.
+					 */
+					find_composite_type_dependencies(rel->rd_rel->reltype,
+													 origRelation, origTypeName);
+				}
+				break;
 		}
 
 		relation_close(rel, AccessShareLock);
@@ -5934,8 +6241,24 @@ ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot add column to typed table")));
 
-	if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-		ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_COMPOSITE_TYPE:
+			ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
+			break;
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	if (recurse && !is_view)
 		cmd->subtype = AT_AddColumnRecurse;
@@ -6455,16 +6778,32 @@ ATPrepDropNotNull(Relation rel, bool recurse, bool recursing)
 	 * If the parent is a partitioned table, like check constraints, we do not
 	 * support removing the NOT NULL while partitions exist.
 	 */
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		PartitionDesc partdesc = RelationGetPartitionDesc(rel);
+		case RELKIND_PARTITIONED_TABLE:
+			{
+				PartitionDesc partdesc = RelationGetPartitionDesc(rel);
 
-		Assert(partdesc != NULL);
-		if (partdesc->nparts > 0 && !recurse && !recursing)
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-					 errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
-					 errhint("Do not specify the ONLY keyword.")));
+				Assert(partdesc != NULL);
+				if (partdesc->nparts > 0 && !recurse && !recursing)
+					ereport(ERROR,
+							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+							 errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
+							 errhint("Do not specify the ONLY keyword.")));
+			}
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 }
 
@@ -6614,17 +6953,33 @@ ATPrepSetNotNull(List **wqueue, Relation rel,
 	 * apply ALTER TABLE ... CHECK NOT NULL to every child.  Otherwise, use
 	 * normal recursion logic.
 	 */
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
-		!recurse)
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		AlterTableCmd *newcmd = makeNode(AlterTableCmd);
+		case RELKIND_PARTITIONED_TABLE:
+			if (!recurse)
+			{
+				AlterTableCmd *newcmd = makeNode(AlterTableCmd);
 
-		newcmd->subtype = AT_CheckNotNull;
-		newcmd->name = pstrdup(cmd->name);
-		ATSimpleRecursion(wqueue, rel, newcmd, true, lockmode, context);
+				newcmd->subtype = AT_CheckNotNull;
+				newcmd->name = pstrdup(cmd->name);
+				ATSimpleRecursion(wqueue, rel, newcmd, true, lockmode, context);
+				break;
+			}
+			/* fallthrough */
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
+			break;
 	}
-	else
-		ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
 }
 
 /*
@@ -7249,12 +7604,27 @@ ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newVa
 	 * We allow referencing columns by numbers only for indexes, since table
 	 * column numbers could contain gaps if columns are later dropped.
 	 */
-	if (rel->rd_rel->relkind != RELKIND_INDEX &&
-		rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
-		!colName)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("cannot refer to non-index column by number")));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			if (!colName)
+				ereport(ERROR,
+						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+						 errmsg("cannot refer to non-index column by number")));
+			break;
+	}
 
 	Assert(IsA(newValue, Integer));
 	newtarget = intVal(newValue);
@@ -7310,20 +7680,35 @@ ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newVa
 				 errmsg("cannot alter system column \"%s\"",
 						colName)));
 
-	if (rel->rd_rel->relkind == RELKIND_INDEX ||
-		rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		if (attnum > rel->rd_index->indnkeyatts)
-			ereport(ERROR,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("cannot alter statistics on included column \"%s\" of index \"%s\"",
-							NameStr(attrtuple->attname), RelationGetRelationName(rel))));
-		else if (rel->rd_index->indkey.values[attnum - 1] != 0)
-			ereport(ERROR,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("cannot alter statistics on non-expression column \"%s\" of index \"%s\"",
-							NameStr(attrtuple->attname), RelationGetRelationName(rel)),
-					 errhint("Alter statistics on table column instead.")));
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			{
+				if (attnum > rel->rd_index->indnkeyatts)
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("cannot alter statistics on included column \"%s\" of index \"%s\"",
+									NameStr(attrtuple->attname), RelationGetRelationName(rel))));
+				else if (rel->rd_index->indkey.values[attnum - 1] != 0)
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("cannot alter statistics on non-expression column \"%s\" of index \"%s\"",
+									NameStr(attrtuple->attname), RelationGetRelationName(rel)),
+							 errhint("Alter statistics on table column instead.")));
+			}
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	attrtuple->attstattarget = newtarget;
@@ -7566,8 +7951,24 @@ ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot drop column from typed table")));
 
-	if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-		ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_COMPOSITE_TYPE:
+			ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
+			break;
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	if (recurse)
 		cmd->subtype = AT_DropColumnRecurse;
@@ -7676,15 +8077,32 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
 		Relation	attr_rel;
 		ListCell   *child;
 
-		/*
-		 * In case of a partitioned table, the column must be dropped from the
-		 * partitions as well.
-		 */
-		if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !recurse)
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-					 errmsg("cannot drop column from only the partitioned table when partitions exist"),
-					 errhint("Do not specify the ONLY keyword.")));
+		switch ((RelKind) rel->rd_rel->relkind)
+		{
+				/*
+				 * In case of a partitioned table, the column must be dropped
+				 * from the partitions as well.
+				 */
+			case RELKIND_PARTITIONED_TABLE:
+				if (!recurse)
+					ereport(ERROR,
+							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+							 errmsg("cannot drop column from only the partitioned table when partitions exist"),
+							 errhint("Do not specify the ONLY keyword.")));
+				break;
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_RELATION:
+			case RELKIND_MATVIEW:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				break;
+		}
 
 		attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
 		foreach(child, children)
@@ -7861,10 +8279,26 @@ ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
 	 * Doing this on partitioned tables is not a simple feature to implement,
 	 * so let's punt for now.
 	 */
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			ereport(ERROR,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	indexRel = index_open(index_oid, AccessShareLock);
 
@@ -8218,30 +8652,44 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
 	 * Validity checks (permission checks wait till we have the column
 	 * numbers)
 	 */
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		if (!recurse)
+		case RELKIND_PARTITIONED_TABLE:
+			{
+				if (!recurse)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
+									RelationGetRelationName(rel),
+									RelationGetRelationName(pkrel))));
+				if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
+									RelationGetRelationName(rel),
+									RelationGetRelationName(pkrel)),
+							 errdetail("This feature is not yet supported on partitioned tables.")));
+			}
+			break;
+		case RELKIND_RELATION:
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
-							RelationGetRelationName(rel),
+					 errmsg("referenced relation \"%s\" is not a table",
 							RelationGetRelationName(pkrel))));
-		if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
-							RelationGetRelationName(rel),
-							RelationGetRelationName(pkrel)),
-					 errdetail("This feature is not yet supported on partitioned tables.")));
+			break;
 	}
 
-	if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
-		pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("referenced relation \"%s\" is not a table",
-						RelationGetRelationName(pkrel))));
-
 	if (!allowSystemTableMods && IsSystemRelation(pkrel))
 		ereport(ERROR,
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
@@ -8640,12 +9088,26 @@ addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel,
 	 * Verify relkind for each referenced partition.  At the top level, this
 	 * is redundant with a previous check, but we need it when recursing.
 	 */
-	if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
-		pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("referenced relation \"%s\" is not a table",
-						RelationGetRelationName(pkrel))));
+	switch ((RelKind) pkrel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("referenced relation \"%s\" is not a table",
+							RelationGetRelationName(pkrel))));
+	}
 
 	/*
 	 * Caller supplies us with a constraint name; however, it may be used in
@@ -8675,7 +9137,23 @@ addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel,
 		/*
 		 * always inherit for partitioned tables, never for legacy inheritance
 		 */
-		connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
+		switch ((RelKind) rel->rd_rel->relkind)
+		{
+			case RELKIND_PARTITIONED_TABLE:
+				connoinherit = false;
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				connoinherit = true;
+		}
 	}
 
 	/*
@@ -8730,69 +9208,84 @@ addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel,
 	/* make new constraint visible, in case we add more */
 	CommandCounterIncrement();
 
-	/*
-	 * If the referenced table is a plain relation, create the action triggers
-	 * that enforce the constraint.
-	 */
-	if (pkrel->rd_rel->relkind == RELKIND_RELATION)
-	{
-		createForeignKeyActionTriggers(rel, RelationGetRelid(pkrel),
-									   fkconstraint,
-									   constrOid, indexOid);
-	}
-
-	/*
-	 * If the referenced table is partitioned, recurse on ourselves to handle
-	 * each partition.  We need one pg_constraint row created for each
-	 * partition in addition to the pg_constraint row for the parent table.
-	 */
-	if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	switch ((RelKind) pkrel->rd_rel->relkind)
 	{
-		PartitionDesc pd = RelationGetPartitionDesc(pkrel);
-
-		for (int i = 0; i < pd->nparts; i++)
-		{
-			Relation	partRel;
-			AttrMap    *map;
-			AttrNumber *mapped_pkattnum;
-			Oid			partIndexId;
-
-			partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
+			/*
+			 * If the referenced table is a plain relation, create the action
+			 * triggers that enforce the constraint.
+			 */
+		case RELKIND_RELATION:
+			createForeignKeyActionTriggers(rel, RelationGetRelid(pkrel),
+										   fkconstraint,
+										   constrOid, indexOid);
+			break;
 
 			/*
-			 * Map the attribute numbers in the referenced side of the FK
-			 * definition to match the partition's column layout.
+			 * If the referenced table is partitioned, recurse on ourselves to
+			 * handle each partition.  We need one pg_constraint row created
+			 * for each partition in addition to the pg_constraint row for the
+			 * parent table.
 			 */
-			map = build_attrmap_by_name_if_req(RelationGetDescr(partRel),
-											   RelationGetDescr(pkrel));
-			if (map)
-			{
-				mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
-				for (int j = 0; j < numfks; j++)
-					mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
-			}
-			else
-				mapped_pkattnum = pkattnum;
-
-			/* do the deed */
-			partIndexId = index_get_partition(partRel, indexOid);
-			if (!OidIsValid(partIndexId))
-				elog(ERROR, "index for %u not found in partition %s",
-					 indexOid, RelationGetRelationName(partRel));
-			addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
-								   partIndexId, constrOid, numfks,
-								   mapped_pkattnum, fkattnum,
-								   pfeqoperators, ppeqoperators, ffeqoperators,
-								   old_check_ok);
-
-			/* Done -- clean up (but keep the lock) */
-			table_close(partRel, NoLock);
-			if (map)
+		case RELKIND_PARTITIONED_TABLE:
 			{
-				pfree(mapped_pkattnum);
-				free_attrmap(map);
+				PartitionDesc pd = RelationGetPartitionDesc(pkrel);
+
+				for (int i = 0; i < pd->nparts; i++)
+				{
+					Relation	partRel;
+					AttrMap    *map;
+					AttrNumber *mapped_pkattnum;
+					Oid			partIndexId;
+
+					partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
+
+					/*
+					 * Map the attribute numbers in the referenced side of the
+					 * FK definition to match the partition's column layout.
+					 */
+					map = build_attrmap_by_name_if_req(RelationGetDescr(partRel),
+													   RelationGetDescr(pkrel));
+					if (map)
+					{
+						mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
+						for (int j = 0; j < numfks; j++)
+							mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
+					}
+					else
+						mapped_pkattnum = pkattnum;
+
+					/* do the deed */
+					partIndexId = index_get_partition(partRel, indexOid);
+					if (!OidIsValid(partIndexId))
+						elog(ERROR, "index for %u not found in partition %s",
+							 indexOid, RelationGetRelationName(partRel));
+					addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
+										   partIndexId, constrOid, numfks,
+										   mapped_pkattnum, fkattnum,
+										   pfeqoperators, ppeqoperators, ffeqoperators,
+										   old_check_ok);
+
+					/* Done -- clean up (but keep the lock) */
+					table_close(partRel, NoLock);
+					if (map)
+					{
+						pfree(mapped_pkattnum);
+						free_attrmap(map);
+					}
+				}
 			}
-		}
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	return address;
@@ -8836,177 +9329,196 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
 {
 	AssertArg(OidIsValid(parentConstr));
 
-	if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("foreign key constraints are not supported on foreign tables")));
-
-	/*
-	 * If the referencing relation is a plain table, add the check triggers to
-	 * it and, if necessary, schedule it to be checked in Phase 3.
-	 *
-	 * If the relation is partitioned, drill down to do it to its partitions.
-	 */
-	if (rel->rd_rel->relkind == RELKIND_RELATION)
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		createForeignKeyCheckTriggers(RelationGetRelid(rel),
-									  RelationGetRelid(pkrel),
-									  fkconstraint,
-									  parentConstr,
-									  indexOid);
-
-		/*
-		 * Tell Phase 3 to check that the constraint is satisfied by existing
-		 * rows. We can skip this during table creation, when requested
-		 * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
-		 * and when we're recreating a constraint following a SET DATA TYPE
-		 * operation that did not impugn its validity.
-		 */
-		if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
-		{
-			NewConstraint *newcon;
-			AlteredTableInfo *tab;
+			/*
+			 * If the referencing relation is a plain table, add the check
+			 * triggers to it and, if necessary, schedule it to be checked in
+			 * Phase 3.
+			 *
+			 * If the relation is partitioned, drill down to do it to its
+			 * partitions.
+			 */
+		case RELKIND_RELATION:
+			{
+				createForeignKeyCheckTriggers(RelationGetRelid(rel),
+											  RelationGetRelid(pkrel),
+											  fkconstraint,
+											  parentConstr,
+											  indexOid);
 
-			tab = ATGetQueueEntry(wqueue, rel);
+				/*
+				 * Tell Phase 3 to check that the constraint is satisfied by
+				 * existing rows. We can skip this during table creation, when
+				 * requested explicitly by specifying NOT VALID in an ADD
+				 * FOREIGN KEY command, and when we're recreating a constraint
+				 * following a SET DATA TYPE operation that did not impugn its
+				 * validity.
+				 */
+				if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
+				{
+					NewConstraint *newcon;
+					AlteredTableInfo *tab;
 
-			newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
-			newcon->name = get_constraint_name(parentConstr);
-			newcon->contype = CONSTR_FOREIGN;
-			newcon->refrelid = RelationGetRelid(pkrel);
-			newcon->refindid = indexOid;
-			newcon->conid = parentConstr;
-			newcon->qual = (Node *) fkconstraint;
+					tab = ATGetQueueEntry(wqueue, rel);
 
-			tab->constraints = lappend(tab->constraints, newcon);
-		}
-	}
-	else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-	{
-		PartitionDesc pd = RelationGetPartitionDesc(rel);
+					newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
+					newcon->name = get_constraint_name(parentConstr);
+					newcon->contype = CONSTR_FOREIGN;
+					newcon->refrelid = RelationGetRelid(pkrel);
+					newcon->refindid = indexOid;
+					newcon->conid = parentConstr;
+					newcon->qual = (Node *) fkconstraint;
 
-		/*
-		 * Recurse to take appropriate action on each partition; either we
-		 * find an existing constraint to reparent to ours, or we create a new
-		 * one.
-		 */
-		for (int i = 0; i < pd->nparts; i++)
-		{
-			Oid			partitionId = pd->oids[i];
-			Relation	partition = table_open(partitionId, lockmode);
-			List	   *partFKs;
-			AttrMap    *attmap;
-			AttrNumber	mapped_fkattnum[INDEX_MAX_KEYS];
-			bool		attached;
-			char	   *conname;
-			Oid			constrOid;
-			ObjectAddress address,
-						referenced;
-			ListCell   *cell;
-
-			CheckTableNotInUse(partition, "ALTER TABLE");
-
-			attmap = build_attrmap_by_name(RelationGetDescr(partition),
-										   RelationGetDescr(rel));
-			for (int j = 0; j < numfks; j++)
-				mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
-
-			/* Check whether an existing constraint can be repurposed */
-			partFKs = copyObject(RelationGetFKeyList(partition));
-			attached = false;
-			foreach(cell, partFKs)
-			{
-				ForeignKeyCacheInfo *fk;
-
-				fk = lfirst_node(ForeignKeyCacheInfo, cell);
-				if (tryAttachPartitionForeignKey(fk,
-												 partitionId,
-												 parentConstr,
-												 numfks,
-												 mapped_fkattnum,
-												 pkattnum,
-												 pfeqoperators))
-				{
-					attached = true;
-					break;
+					tab->constraints = lappend(tab->constraints, newcon);
 				}
 			}
-			if (attached)
+			break;
+		case RELKIND_PARTITIONED_TABLE:
 			{
-				table_close(partition, NoLock);
-				continue;
-			}
+				PartitionDesc pd = RelationGetPartitionDesc(rel);
 
-			/*
-			 * No luck finding a good constraint to reuse; create our own.
-			 */
-			if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
-									 RelationGetRelid(partition),
-									 fkconstraint->conname))
-				conname = ChooseConstraintName(RelationGetRelationName(partition),
-											   ChooseForeignKeyConstraintNameAddition(fkconstraint->fk_attrs),
-											   "fkey",
-											   RelationGetNamespace(partition), NIL);
-			else
-				conname = fkconstraint->conname;
-			constrOid =
-				CreateConstraintEntry(conname,
-									  RelationGetNamespace(partition),
-									  CONSTRAINT_FOREIGN,
-									  fkconstraint->deferrable,
-									  fkconstraint->initdeferred,
-									  fkconstraint->initially_valid,
-									  parentConstr,
-									  partitionId,
-									  mapped_fkattnum,
-									  numfks,
-									  numfks,
-									  InvalidOid,
-									  indexOid,
-									  RelationGetRelid(pkrel),
-									  pkattnum,
-									  pfeqoperators,
-									  ppeqoperators,
-									  ffeqoperators,
-									  numfks,
-									  fkconstraint->fk_upd_action,
-									  fkconstraint->fk_del_action,
-									  fkconstraint->fk_matchtype,
-									  NULL,
-									  NULL,
-									  NULL,
-									  false,
-									  1,
-									  false,
-									  false);
+				/*
+				 * Recurse to take appropriate action on each partition;
+				 * either we find an existing constraint to reparent to ours,
+				 * or we create a new one.
+				 */
+				for (int i = 0; i < pd->nparts; i++)
+				{
+					Oid			partitionId = pd->oids[i];
+					Relation	partition = table_open(partitionId, lockmode);
+					List	   *partFKs;
+					AttrMap    *attmap;
+					AttrNumber	mapped_fkattnum[INDEX_MAX_KEYS];
+					bool		attached;
+					char	   *conname;
+					Oid			constrOid;
+					ObjectAddress address,
+								referenced;
+					ListCell   *cell;
+
+					CheckTableNotInUse(partition, "ALTER TABLE");
+
+					attmap = build_attrmap_by_name(RelationGetDescr(partition),
+												   RelationGetDescr(rel));
+					for (int j = 0; j < numfks; j++)
+						mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
+
+					/* Check whether an existing constraint can be repurposed */
+					partFKs = copyObject(RelationGetFKeyList(partition));
+					attached = false;
+					foreach(cell, partFKs)
+					{
+						ForeignKeyCacheInfo *fk;
+
+						fk = lfirst_node(ForeignKeyCacheInfo, cell);
+						if (tryAttachPartitionForeignKey(fk,
+														 partitionId,
+														 parentConstr,
+														 numfks,
+														 mapped_fkattnum,
+														 pkattnum,
+														 pfeqoperators))
+						{
+							attached = true;
+							break;
+						}
+					}
+					if (attached)
+					{
+						table_close(partition, NoLock);
+						continue;
+					}
 
-			/*
-			 * Give this constraint partition-type dependencies on the parent
-			 * constraint as well as the table.
-			 */
-			ObjectAddressSet(address, ConstraintRelationId, constrOid);
-			ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
-			recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
-			ObjectAddressSet(referenced, RelationRelationId, partitionId);
-			recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
+					/*
+					 * No luck finding a good constraint to reuse; create our
+					 * own.
+					 */
+					if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
+											 RelationGetRelid(partition),
+											 fkconstraint->conname))
+						conname = ChooseConstraintName(RelationGetRelationName(partition),
+													   ChooseForeignKeyConstraintNameAddition(fkconstraint->fk_attrs),
+													   "fkey",
+													   RelationGetNamespace(partition), NIL);
+					else
+						conname = fkconstraint->conname;
+					constrOid =
+						CreateConstraintEntry(conname,
+											  RelationGetNamespace(partition),
+											  CONSTRAINT_FOREIGN,
+											  fkconstraint->deferrable,
+											  fkconstraint->initdeferred,
+											  fkconstraint->initially_valid,
+											  parentConstr,
+											  partitionId,
+											  mapped_fkattnum,
+											  numfks,
+											  numfks,
+											  InvalidOid,
+											  indexOid,
+											  RelationGetRelid(pkrel),
+											  pkattnum,
+											  pfeqoperators,
+											  ppeqoperators,
+											  ffeqoperators,
+											  numfks,
+											  fkconstraint->fk_upd_action,
+											  fkconstraint->fk_del_action,
+											  fkconstraint->fk_matchtype,
+											  NULL,
+											  NULL,
+											  NULL,
+											  false,
+											  1,
+											  false,
+											  false);
 
-			/* Make all this visible before recursing */
-			CommandCounterIncrement();
+					/*
+					 * Give this constraint partition-type dependencies on the
+					 * parent constraint as well as the table.
+					 */
+					ObjectAddressSet(address, ConstraintRelationId, constrOid);
+					ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
+					recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
+					ObjectAddressSet(referenced, RelationRelationId, partitionId);
+					recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
 
-			/* call ourselves to finalize the creation and we're done */
-			addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
-									indexOid,
-									constrOid,
-									numfks,
-									pkattnum,
-									mapped_fkattnum,
-									pfeqoperators,
-									ppeqoperators,
-									ffeqoperators,
-									old_check_ok,
-									lockmode);
-
-			table_close(partition, NoLock);
-		}
+					/* Make all this visible before recursing */
+					CommandCounterIncrement();
+
+					/* call ourselves to finalize the creation and we're done */
+					addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
+											indexOid,
+											constrOid,
+											numfks,
+											pkattnum,
+											mapped_fkattnum,
+											pfeqoperators,
+											ppeqoperators,
+											ffeqoperators,
+											old_check_ok,
+											lockmode);
+
+					table_close(partition, NoLock);
+				}
+			}
+			break;
+		case RELKIND_FOREIGN_TABLE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("foreign key constraints are not supported on foreign tables")));
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 }
 
@@ -9229,10 +9741,26 @@ CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
 	if (clone == NIL)
 		return;
 
-	if (partRel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("foreign key constraints are not supported on foreign tables")));
+	switch ((RelKind) partRel->rd_rel->relkind)
+	{
+		case RELKIND_FOREIGN_TABLE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("foreign key constraints are not supported on foreign tables")));
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	/*
 	 * The constraint key may differ, if the columns in the partition are
@@ -9282,9 +9810,25 @@ CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
 		 * relation, that means to lock all partitions.
 		 */
 		pkrel = table_open(constrForm->confrelid, ShareRowExclusiveLock);
-		if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-			(void) find_all_inheritors(RelationGetRelid(pkrel),
-									   ShareRowExclusiveLock, NULL);
+		switch ((RelKind) pkrel->rd_rel->relkind)
+		{
+			case RELKIND_PARTITIONED_TABLE:
+				(void) find_all_inheritors(RelationGetRelid(pkrel),
+										   ShareRowExclusiveLock, NULL);
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				break;
+		}
 
 		DeconstructFkConstraintRow(tuple, &numfks, conkey, confkey,
 								   conpfeqop, conppeqop, conffeqop);
@@ -10249,9 +10793,23 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup)
 	 * VALIDATE CONSTRAINT is a no-op for foreign tables and partitioned
 	 * tables.
 	 */
-	if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
-		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		return;
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+			return;
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	constrForm = (Form_pg_constraint) GETSTRUCT(constrtup);
 
@@ -10705,11 +11263,27 @@ ATExecDropConstraint(Relation rel, const char *constrName,
 	 * For partitioned tables, non-CHECK inherited constraints are dropped via
 	 * the dependency mechanism, so we're done here.
 	 */
-	if (contype != CONSTRAINT_CHECK &&
-		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		table_close(conrel, RowExclusiveLock);
-		return;
+		case RELKIND_PARTITIONED_TABLE:
+			if (contype != CONSTRAINT_CHECK)
+			{
+				table_close(conrel, RowExclusiveLock);
+				return;
+			}
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	/*
@@ -10727,12 +11301,28 @@ ATExecDropConstraint(Relation rel, const char *constrName,
 	 * recurse, it's a user error.  It doesn't make sense to have a constraint
 	 * be defined only on the parent, especially if it's a partitioned table.
 	 */
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
-		children != NIL && !recurse)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-				 errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
-				 errhint("Do not specify the ONLY keyword.")));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			if (children != NIL && !recurse)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+						 errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
+						 errhint("Do not specify the ONLY keyword.")));
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	foreach(child, children)
 	{
@@ -10924,87 +11514,106 @@ ATPrepAlterColumnType(List **wqueue,
 					   list_make1_oid(rel->rd_rel->reltype),
 					   0);
 
-	if (tab->relkind == RELKIND_RELATION ||
-		tab->relkind == RELKIND_PARTITIONED_TABLE)
+	switch ((RelKind) tab->relkind)
 	{
-		/*
-		 * Set up an expression to transform the old data value to the new
-		 * type. If a USING option was given, use the expression as
-		 * transformed by transformAlterTableStmt, else just take the old
-		 * value and try to coerce it.  We do this first so that type
-		 * incompatibility can be detected before we waste effort, and because
-		 * we need the expression to be parsed against the original table row
-		 * type.
-		 */
-		if (!transform)
-		{
-			transform = (Node *) makeVar(1, attnum,
-										 attTup->atttypid, attTup->atttypmod,
-										 attTup->attcollation,
-										 0);
-		}
-
-		transform = coerce_to_target_type(pstate,
-										  transform, exprType(transform),
-										  targettype, targettypmod,
-										  COERCION_ASSIGNMENT,
-										  COERCE_IMPLICIT_CAST,
-										  -1);
-		if (transform == NULL)
-		{
-			/* error text depends on whether USING was specified or not */
-			if (def->cooked_default != NULL)
-				ereport(ERROR,
-						(errcode(ERRCODE_DATATYPE_MISMATCH),
-						 errmsg("result of USING clause for column \"%s\""
-								" cannot be cast automatically to type %s",
-								colName, format_type_be(targettype)),
-						 errhint("You might need to add an explicit cast.")));
-			else
-				ereport(ERROR,
-						(errcode(ERRCODE_DATATYPE_MISMATCH),
-						 errmsg("column \"%s\" cannot be cast automatically to type %s",
-								colName, format_type_be(targettype)),
-				/* translator: USING is SQL, don't translate it */
-						 errhint("You might need to specify \"USING %s::%s\".",
-								 quote_identifier(colName),
-								 format_type_with_typemod(targettype,
-														  targettypmod))));
-		}
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			{
+				/*
+				 * Set up an expression to transform the old data value to the
+				 * new type. If a USING option was given, use the expression
+				 * as transformed by transformAlterTableStmt, else just take
+				 * the old value and try to coerce it.  We do this first so
+				 * that type incompatibility can be detected before we waste
+				 * effort, and because we need the expression to be parsed
+				 * against the original table row type.
+				 */
+				if (!transform)
+				{
+					transform = (Node *) makeVar(1, attnum,
+												 attTup->atttypid, attTup->atttypmod,
+												 attTup->attcollation,
+												 0);
+				}
 
-		/* Fix collations after all else */
-		assign_expr_collations(pstate, transform);
+				transform = coerce_to_target_type(pstate,
+												  transform, exprType(transform),
+												  targettype, targettypmod,
+												  COERCION_ASSIGNMENT,
+												  COERCE_IMPLICIT_CAST,
+												  -1);
+				if (transform == NULL)
+				{
+					/*
+					 * error text depends on whether USING was specified or
+					 * not
+					 */
+					if (def->cooked_default != NULL)
+						ereport(ERROR,
+								(errcode(ERRCODE_DATATYPE_MISMATCH),
+								 errmsg("result of USING clause for column \"%s\""
+										" cannot be cast automatically to type %s",
+										colName, format_type_be(targettype)),
+								 errhint("You might need to add an explicit cast.")));
+					else
+						ereport(ERROR,
+								(errcode(ERRCODE_DATATYPE_MISMATCH),
+								 errmsg("column \"%s\" cannot be cast automatically to type %s",
+										colName, format_type_be(targettype)),
+						/* translator: USING is SQL, don't translate it */
+								 errhint("You might need to specify \"USING %s::%s\".",
+										 quote_identifier(colName),
+										 format_type_with_typemod(targettype,
+																  targettypmod))));
+				}
 
-		/* Plan the expr now so we can accurately assess the need to rewrite. */
-		transform = (Node *) expression_planner((Expr *) transform);
+				/* Fix collations after all else */
+				assign_expr_collations(pstate, transform);
 
-		/*
-		 * Add a work queue item to make ATRewriteTable update the column
-		 * contents.
-		 */
-		newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
-		newval->attnum = attnum;
-		newval->expr = (Expr *) transform;
-		newval->is_generated = false;
+				/*
+				 * Plan the expr now so we can accurately assess the need to
+				 * rewrite.
+				 */
+				transform = (Node *) expression_planner((Expr *) transform);
 
-		tab->newvals = lappend(tab->newvals, newval);
-		if (ATColumnChangeRequiresRewrite(transform, attnum))
-			tab->rewrite |= AT_REWRITE_COLUMN_REWRITE;
-	}
-	else if (transform)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table",
-						RelationGetRelationName(rel))));
+				/*
+				 * Add a work queue item to make ATRewriteTable update the
+				 * column contents.
+				 */
+				newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
+				newval->attnum = attnum;
+				newval->expr = (Expr *) transform;
+				newval->is_generated = false;
+
+				tab->newvals = lappend(tab->newvals, newval);
+				if (ATColumnChangeRequiresRewrite(transform, attnum))
+					tab->rewrite |= AT_REWRITE_COLUMN_REWRITE;
+			}
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
 
-	if (tab->relkind == RELKIND_COMPOSITE_TYPE ||
-		tab->relkind == RELKIND_FOREIGN_TABLE)
-	{
-		/*
-		 * For composite types, do this check now.  Tables will check it later
-		 * when the table is being rewritten.
-		 */
-		find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
+			/*
+			 * For composite types, do this check now.  Tables will check it
+			 * later when the table is being rewritten.
+			 */
+			if (!transform)
+				find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
+			/* fallthrough */
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			if (transform)
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("\"%s\" is not a table",
+								RelationGetRelationName(rel))));
+			break;
 	}
 
 	ReleaseSysCache(tuple);
@@ -11108,8 +11717,24 @@ ATPrepAlterColumnType(List **wqueue,
 				 errmsg("type of inherited column \"%s\" must be changed in child tables too",
 						colName)));
 
-	if (tab->relkind == RELKIND_COMPOSITE_TYPE)
-		ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
+	switch ((RelKind) tab->relkind)
+	{
+		case RELKIND_COMPOSITE_TYPE:
+			ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 }
 
 /*
@@ -11326,44 +11951,53 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 				{
 					char		relKind = get_rel_relkind(foundObject.objectId);
 
-					if (relKind == RELKIND_INDEX ||
-						relKind == RELKIND_PARTITIONED_INDEX)
-					{
-						Assert(foundObject.objectSubId == 0);
-						RememberIndexForRebuilding(foundObject.objectId, tab);
-					}
-					else if (relKind == RELKIND_SEQUENCE)
-					{
-						/*
-						 * This must be a SERIAL column's sequence.  We need
-						 * not do anything to it.
-						 */
-						Assert(foundObject.objectSubId == 0);
-					}
-					else if (relKind == RELKIND_RELATION &&
-							 foundObject.objectSubId != 0 &&
-							 get_attgenerated(foundObject.objectId, foundObject.objectSubId))
-					{
-						/*
-						 * Changing the type of a column that is used by a
-						 * generated column is not allowed by SQL standard. It
-						 * might be doable with some thinking and effort.
-						 */
-						ereport(ERROR,
-								(errcode(ERRCODE_SYNTAX_ERROR),
-								 errmsg("cannot alter type of a column used by a generated column"),
-								 errdetail("Column \"%s\" is used by generated column \"%s\".",
-										   colName, get_attname(foundObject.objectId, foundObject.objectSubId, false))));
-					}
-					else
+					switch ((RelKind) relKind)
 					{
-						/* Not expecting any other direct dependencies... */
-						elog(ERROR, "unexpected object depending on column: %s",
-							 getObjectDescription(&foundObject));
+						case RELKIND_INDEX:
+						case RELKIND_PARTITIONED_INDEX:
+							Assert(foundObject.objectSubId == 0);
+							RememberIndexForRebuilding(foundObject.objectId, tab);
+							break;
+						case RELKIND_SEQUENCE:
+
+							/*
+							 * This must be a SERIAL column's sequence.  We
+							 * need not do anything to it.
+							 */
+							Assert(foundObject.objectSubId == 0);
+							break;
+						case RELKIND_RELATION:
+							if (foundObject.objectSubId != 0 &&
+								get_attgenerated(foundObject.objectId, foundObject.objectSubId))
+							{
+								/*
+								 * Changing the type of a column that is used
+								 * by a generated column is not allowed by SQL
+								 * standard. It might be doable with some
+								 * thinking and effort.
+								 */
+								ereport(ERROR,
+										(errcode(ERRCODE_SYNTAX_ERROR),
+										 errmsg("cannot alter type of a column used by a generated column"),
+										 errdetail("Column \"%s\" is used by generated column \"%s\".",
+												   colName, get_attname(foundObject.objectId, foundObject.objectSubId, false))));
+							}
+							break;
+						case RELKIND_FOREIGN_TABLE:
+						case RELKIND_PARTITIONED_TABLE:
+						case RELKIND_COMPOSITE_TYPE:
+						case RELKIND_MATVIEW:
+						case RELKIND_VIEW:
+						case RELKIND_TOASTVALUE:
+						case RELKIND_NULL:
+						default:
+							/* Not expecting any other direct dependencies... */
+							elog(ERROR, "unexpected object depending on column: %s",
+								 getObjectDescription(&foundObject));
+							break;
 					}
-					break;
 				}
-
+				break;
 			case OCLASS_CONSTRAINT:
 				Assert(foundObject.objectSubId == 0);
 				RememberConstraintForRebuilding(foundObject.objectId, tab);
@@ -12196,13 +12830,28 @@ TryReuseIndex(Oid oldId, IndexStmt *stmt)
 	{
 		Relation	irel = index_open(oldId, NoLock);
 
-		/* If it's a partitioned index, there is no storage to share. */
-		if (irel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
+		switch ((RelKind) irel->rd_rel->relkind)
 		{
-			stmt->oldNode = irel->rd_node.relNode;
-			stmt->oldCreateSubid = irel->rd_createSubid;
-			stmt->oldFirstRelfilenodeSubid = irel->rd_firstRelfilenodeSubid;
+			case RELKIND_PARTITIONED_INDEX:
+				/* If it's a partitioned index, there is no storage to share. */
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				stmt->oldNode = irel->rd_node.relNode;
+				stmt->oldCreateSubid = irel->rd_createSubid;
+				stmt->oldFirstRelfilenodeSubid = irel->rd_firstRelfilenodeSubid;
+				break;
 		}
+
 		index_close(irel, NoLock);
 	}
 }
@@ -12397,7 +13046,7 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock
 	tuple_class = (Form_pg_class) GETSTRUCT(tuple);
 
 	/* Can we change the ownership of this tuple? */
-	switch (tuple_class->relkind)
+	switch ((RelKind) tuple_class->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_VIEW:
@@ -12467,6 +13116,7 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock
 			if (recursing)
 				break;
 			/* FALL THRU */
+		case RELKIND_NULL:
 		default:
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
@@ -12554,41 +13204,82 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock
 		 * none, because it's tracked for the pg_type entry instead of here;
 		 * indexes and TOAST tables don't have their own entries either.
 		 */
-		if (tuple_class->relkind != RELKIND_COMPOSITE_TYPE &&
-			tuple_class->relkind != RELKIND_INDEX &&
-			tuple_class->relkind != RELKIND_PARTITIONED_INDEX &&
-			tuple_class->relkind != RELKIND_TOASTVALUE)
-			changeDependencyOnOwner(RelationRelationId, relationOid,
-									newOwnerId);
+		switch ((RelKind) tuple_class->relkind)
+		{
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_TOASTVALUE:
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_NULL:
+			default:
+				changeDependencyOnOwner(RelationRelationId, relationOid,
+										newOwnerId);
+				break;
+		}
 
 		/*
 		 * Also change the ownership of the table's row type, if it has one
 		 */
-		if (tuple_class->relkind != RELKIND_INDEX &&
-			tuple_class->relkind != RELKIND_PARTITIONED_INDEX)
-			AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
+		switch ((RelKind) tuple_class->relkind)
+		{
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				AlterTypeOwnerInternal(tuple_class->reltype, newOwnerId);
+				break;
+		}
 
 		/*
 		 * If we are operating on a table or materialized view, also change
 		 * the ownership of any indexes and sequences that belong to the
 		 * relation, as well as its toast table (if it has one).
 		 */
-		if (tuple_class->relkind == RELKIND_RELATION ||
-			tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
-			tuple_class->relkind == RELKIND_MATVIEW ||
-			tuple_class->relkind == RELKIND_TOASTVALUE)
+		switch ((RelKind) tuple_class->relkind)
 		{
-			List	   *index_oid_list;
-			ListCell   *i;
+			case RELKIND_RELATION:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_MATVIEW:
+			case RELKIND_TOASTVALUE:
+				{
+					List	   *index_oid_list;
+					ListCell   *i;
 
-			/* Find all the indexes belonging to this relation */
-			index_oid_list = RelationGetIndexList(target_rel);
+					/* Find all the indexes belonging to this relation */
+					index_oid_list = RelationGetIndexList(target_rel);
 
-			/* For each index, recursively change its ownership */
-			foreach(i, index_oid_list)
-				ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
+					/* For each index, recursively change its ownership */
+					foreach(i, index_oid_list)
+						ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
 
-			list_free(index_oid_list);
+					list_free(index_oid_list);
+				}
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_NULL:
+			default:
+				break;
 		}
 
 		/* If it has a toast table, recurse to change its ownership */
@@ -12721,11 +13412,24 @@ change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lock
 		seqRel = relation_open(depForm->objid, lockmode);
 
 		/* skip non-sequence relations */
-		if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
+		switch ((RelKind) RelationGetForm(seqRel)->relkind)
 		{
-			/* No need to keep the lock */
-			relation_close(seqRel, lockmode);
-			continue;
+			case RELKIND_SEQUENCE:
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				/* No need to keep the lock */
+				relation_close(seqRel, lockmode);
+				continue;
 		}
 
 		/* We don't need to close the sequence while we alter it. */
@@ -12867,7 +13571,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 									 operation == AT_ResetRelOptions);
 
 	/* Validate */
-	switch (rel->rd_rel->relkind)
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_TOASTVALUE:
@@ -12879,11 +13583,47 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 			break;
 		case RELKIND_VIEW:
 			(void) view_reloptions(newOptions, true);
+
+			/* Special-case validation of view options */
+			{
+				Query	   *view_query = get_view_query(rel);
+				List	   *view_options = untransformRelOptions(newOptions);
+				ListCell   *cell;
+				bool		check_option = false;
+
+				foreach(cell, view_options)
+				{
+					DefElem    *defel = (DefElem *) lfirst(cell);
+
+					if (strcmp(defel->defname, "check_option") == 0)
+						check_option = true;
+				}
+
+				/*
+				 * If the check option is specified, look to see if the view
+				 * is actually auto-updatable or not.
+				 */
+				if (check_option)
+				{
+					const char *view_updatable_error =
+					view_query_is_auto_updatable(view_query, true);
+
+					if (view_updatable_error)
+						ereport(ERROR,
+								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+								 errmsg("WITH CHECK OPTION is supported only on automatically updatable views"),
+								 errhint("%s", _(view_updatable_error))));
+				}
+			}
 			break;
 		case RELKIND_INDEX:
 		case RELKIND_PARTITIONED_INDEX:
 			(void) index_reloptions(rel->rd_indam->amoptions, newOptions, true);
 			break;
+		case RELKIND_NULL:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_SEQUENCE:
 		default:
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
@@ -12892,39 +13632,6 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 			break;
 	}
 
-	/* Special-case validation of view options */
-	if (rel->rd_rel->relkind == RELKIND_VIEW)
-	{
-		Query	   *view_query = get_view_query(rel);
-		List	   *view_options = untransformRelOptions(newOptions);
-		ListCell   *cell;
-		bool		check_option = false;
-
-		foreach(cell, view_options)
-		{
-			DefElem    *defel = (DefElem *) lfirst(cell);
-
-			if (strcmp(defel->defname, "check_option") == 0)
-				check_option = true;
-		}
-
-		/*
-		 * If the check option is specified, look to see if the view is
-		 * actually auto-updatable or not.
-		 */
-		if (check_option)
-		{
-			const char *view_updatable_error =
-			view_query_is_auto_updatable(view_query, true);
-
-			if (view_updatable_error)
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("WITH CHECK OPTION is supported only on automatically updatable views"),
-						 errhint("%s", _(view_updatable_error))));
-		}
-	}
-
 	/*
 	 * All we need do here is update the pg_class row; the new options will be
 	 * propagated into relcaches during post-commit cache inval.
@@ -13109,16 +13816,26 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
 	newrnode.spcNode = newTableSpace;
 
 	/* hand off to AM to actually create the new filenode and copy the data */
-	if (rel->rd_rel->relkind == RELKIND_INDEX)
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		index_copy_data(rel, newrnode);
-	}
-	else
-	{
-		Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
-			   rel->rd_rel->relkind == RELKIND_MATVIEW ||
-			   rel->rd_rel->relkind == RELKIND_TOASTVALUE);
-		table_relation_copy_data(rel, &newrnode);
+		case RELKIND_INDEX:
+			index_copy_data(rel, newrnode);
+			break;
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+			table_relation_copy_data(rel, &newrnode);
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_NULL:
+		default:
+			Assert(false);
+			break;
 	}
 
 	/*
@@ -13489,10 +14206,26 @@ ATPrepAddInherit(Relation child_rel)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot change inheritance of a partition")));
 
-	if (child_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot change inheritance of partitioned table")));
+	switch ((RelKind) child_rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot change inheritance of partitioned table")));
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 }
 
 /*
@@ -13541,11 +14274,27 @@ ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
 				 errmsg("cannot inherit to temporary relation of another session")));
 
 	/* Prevent partitioned tables from becoming inheritance parents */
-	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot inherit from partitioned table \"%s\"",
-						parent->relname)));
+	switch ((RelKind) parent_rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot inherit from partitioned table \"%s\"",
+							parent->relname)));
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	/* Likewise for partitions */
 	if (parent_rel->rd_rel->relispartition)
@@ -13749,8 +14498,24 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
 	parent_natts = tupleDesc->natts;
 
 	/* If parent_rel is a partitioned table, child_rel must be a partition */
-	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		child_is_partition = true;
+	switch ((RelKind) parent_rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			child_is_partition = true;
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	for (parent_attno = 1; parent_attno <= parent_natts; parent_attno++)
 	{
@@ -13858,8 +14623,24 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
 	tuple_desc = RelationGetDescr(catalog_relation);
 
 	/* If parent_rel is a partitioned table, child_rel must be a partition */
-	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		child_is_partition = true;
+	switch ((RelKind) parent_rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			child_is_partition = true;
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	/* Outer loop scans through the parent's constraint definitions */
 	ScanKeyInit(&parent_key,
@@ -14040,8 +14821,24 @@ RemoveInheritance(Relation child_rel, Relation parent_rel)
 	bool		child_is_partition = false;
 
 	/* If parent_rel is a partitioned table, child_rel must be a partition */
-	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		child_is_partition = true;
+	switch ((RelKind) parent_rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			child_is_partition = true;
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	found = DeleteInheritsTuple(RelationGetRelid(child_rel),
 								RelationGetRelid(parent_rel));
@@ -14952,20 +15749,36 @@ AlterTableNamespace(AlterObjectSchemaStmt *stmt, Oid *oldschema)
 
 	oldNspOid = RelationGetNamespace(rel);
 
-	/* If it's an owned sequence, disallow moving it by itself. */
-	if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		Oid			tableId;
-		int32		colId;
+			/* If it's an owned sequence, disallow moving it by itself. */
+		case RELKIND_SEQUENCE:
+			{
+				Oid			tableId;
+				int32		colId;
 
-		if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
-			sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
-			ereport(ERROR,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("cannot move an owned sequence into another schema"),
-					 errdetail("Sequence \"%s\" is linked to table \"%s\".",
-							   RelationGetRelationName(rel),
-							   get_rel_name(tableId))));
+				if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
+					sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("cannot move an owned sequence into another schema"),
+							 errdetail("Sequence \"%s\" is linked to table \"%s\".",
+									   RelationGetRelationName(rel),
+									   get_rel_name(tableId))));
+			}
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	/* Get and lock schema OID and check its permissions. */
@@ -15014,15 +15827,27 @@ AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid,
 							   nspOid, false, false, objsMoved);
 
 	/* Fix other dependent stuff */
-	if (rel->rd_rel->relkind == RELKIND_RELATION ||
-		rel->rd_rel->relkind == RELKIND_MATVIEW ||
-		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
-		AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
-						   objsMoved, AccessExclusiveLock);
-		AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
-								  false, objsMoved);
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+			AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
+			AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
+							   objsMoved, AccessExclusiveLock);
+			AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
+									  false, objsMoved);
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	table_close(classRel, RowExclusiveLock);
@@ -15193,11 +16018,24 @@ AlterSeqNamespaces(Relation classRel, Relation rel,
 		seqRel = relation_open(depForm->objid, lockmode);
 
 		/* skip non-sequence relations */
-		if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
+		switch ((RelKind) RelationGetForm(seqRel)->relkind)
 		{
-			/* No need to keep the lock */
-			relation_close(seqRel, lockmode);
-			continue;
+			case RELKIND_SEQUENCE:
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				/* No need to keep the lock */
+				relation_close(seqRel, lockmode);
+				continue;
 		}
 
 		/* Fix the pg_class and pg_depend entries */
@@ -15477,11 +16315,26 @@ RangeVarCallbackOwnsTable(const RangeVar *relation,
 	relkind = get_rel_relkind(relId);
 	if (!relkind)
 		return;
-	if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
-		relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table or materialized view", relation->relname)));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table or materialized view", relation->relname)));
+			break;
+	}
 
 	/* Check permissions */
 	if (!pg_class_ownercheck(relId, GetUserId()))
@@ -15654,17 +16507,28 @@ RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid,
 	 * Don't allow ALTER TABLE .. SET SCHEMA on relations that can't be moved
 	 * to a different schema, such as indexes and TOAST tables.
 	 */
-	if (IsA(stmt, AlterObjectSchemaStmt) &&
-		relkind != RELKIND_RELATION &&
-		relkind != RELKIND_VIEW &&
-		relkind != RELKIND_MATVIEW &&
-		relkind != RELKIND_SEQUENCE &&
-		relkind != RELKIND_FOREIGN_TABLE &&
-		relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table, view, materialized view, sequence, or foreign table",
-						rv->relname)));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			if (IsA(stmt, AlterObjectSchemaStmt))
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("\"%s\" is not a table, view, materialized view, sequence, or foreign table",
+								rv->relname)));
+			break;
+	}
 
 	ReleaseSysCache(tuple);
 }
@@ -16139,44 +17003,60 @@ QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
 	 * validation item now; for partitioned tables, recurse to process each
 	 * partition.
 	 */
-	if (scanrel->rd_rel->relkind == RELKIND_RELATION)
+	switch ((RelKind) scanrel->rd_rel->relkind)
 	{
-		AlteredTableInfo *tab;
+		case RELKIND_RELATION:
+			{
+				AlteredTableInfo *tab;
 
-		/* Grab a work queue entry. */
-		tab = ATGetQueueEntry(wqueue, scanrel);
-		Assert(tab->partition_constraint == NULL);
-		tab->partition_constraint = (Expr *) linitial(partConstraint);
-		tab->validate_default = validate_default;
-	}
-	else if (scanrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-	{
-		PartitionDesc partdesc = RelationGetPartitionDesc(scanrel);
-		int			i;
+				/* Grab a work queue entry. */
+				tab = ATGetQueueEntry(wqueue, scanrel);
+				Assert(tab->partition_constraint == NULL);
+				tab->partition_constraint = (Expr *) linitial(partConstraint);
+				tab->validate_default = validate_default;
+			}
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+			{
+				PartitionDesc partdesc = RelationGetPartitionDesc(scanrel);
+				int			i;
 
-		for (i = 0; i < partdesc->nparts; i++)
-		{
-			Relation	part_rel;
-			List	   *thisPartConstraint;
+				for (i = 0; i < partdesc->nparts; i++)
+				{
+					Relation	part_rel;
+					List	   *thisPartConstraint;
 
-			/*
-			 * This is the minimum lock we need to prevent deadlocks.
-			 */
-			part_rel = table_open(partdesc->oids[i], AccessExclusiveLock);
+					/*
+					 * This is the minimum lock we need to prevent deadlocks.
+					 */
+					part_rel = table_open(partdesc->oids[i], AccessExclusiveLock);
 
-			/*
-			 * Adjust the constraint for scanrel so that it matches this
-			 * partition's attribute numbers.
-			 */
-			thisPartConstraint =
-				map_partition_varattnos(partConstraint, 1,
-										part_rel, scanrel);
-
-			QueuePartitionConstraintValidation(wqueue, part_rel,
-											   thisPartConstraint,
-											   validate_default);
-			table_close(part_rel, NoLock);	/* keep lock till commit */
-		}
+					/*
+					 * Adjust the constraint for scanrel so that it matches
+					 * this partition's attribute numbers.
+					 */
+					thisPartConstraint =
+						map_partition_varattnos(partConstraint, 1,
+												part_rel, scanrel);
+
+					QueuePartitionConstraintValidation(wqueue, part_rel,
+													   thisPartConstraint,
+													   validate_default);
+					table_close(part_rel, NoLock);	/* keep lock till commit */
+				}
+			}
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 }
 
@@ -16260,11 +17140,29 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
 				ObjectIdGetDatum(RelationGetRelid(attachrel)));
 	scan = systable_beginscan(catalog, InheritsParentIndexId, true, NULL,
 							  1, &skey);
-	if (HeapTupleIsValid(systable_getnext(scan)) &&
-		attachrel->rd_rel->relkind == RELKIND_RELATION)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot attach inheritance parent as partition")));
+
+	switch ((RelKind) attachrel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+			if (HeapTupleIsValid(systable_getnext(scan)))
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot attach inheritance parent as partition")));
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
+
 	systable_endscan(scan);
 	table_close(catalog, AccessShareLock);
 
@@ -16510,26 +17408,38 @@ AttachPartitionEnsureIndexes(Relation rel, Relation attachrel)
 	 * before starting work, to avoid wasting the effort of building a few
 	 * non-unique indexes before coming across a unique one.
 	 */
-	if (attachrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+	switch ((RelKind) attachrel->rd_rel->relkind)
 	{
-		foreach(cell, idxes)
-		{
-			Oid			idx = lfirst_oid(cell);
-			Relation	idxRel = index_open(idx, AccessShareLock);
-
-			if (idxRel->rd_index->indisunique ||
-				idxRel->rd_index->indisprimary)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("cannot attach foreign table \"%s\" as partition of partitioned table \"%s\"",
-								RelationGetRelationName(attachrel),
-								RelationGetRelationName(rel)),
-						 errdetail("Table \"%s\" contains unique indexes.",
-								   RelationGetRelationName(rel))));
-			index_close(idxRel, AccessShareLock);
-		}
+		case RELKIND_FOREIGN_TABLE:
+			foreach(cell, idxes)
+			{
+				Oid			idx = lfirst_oid(cell);
+				Relation	idxRel = index_open(idx, AccessShareLock);
 
-		goto out;
+				if (idxRel->rd_index->indisunique ||
+					idxRel->rd_index->indisprimary)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("cannot attach foreign table \"%s\" as partition of partitioned table \"%s\"",
+									RelationGetRelationName(attachrel),
+									RelationGetRelationName(rel)),
+							 errdetail("Table \"%s\" contains unique indexes.",
+									   RelationGetRelationName(rel))));
+				index_close(idxRel, AccessShareLock);
+			}
+			goto out;
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	/*
@@ -16549,10 +17459,23 @@ AttachPartitionEnsureIndexes(Relation rel, Relation attachrel)
 		 * Ignore indexes in the partitioned table other than partitioned
 		 * indexes.
 		 */
-		if (idxRel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
+		switch ((RelKind) idxRel->rd_rel->relkind)
 		{
-			index_close(idxRel, AccessShareLock);
-			continue;
+			case RELKIND_PARTITIONED_INDEX:
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				index_close(idxRel, AccessShareLock);
+				continue;
 		}
 
 		/* construct an indexinfo to compare existing indexes against */
@@ -17089,11 +18012,27 @@ RangeVarCallbackForAttachIndex(const RangeVar *rv, Oid relOid, Oid oldRelOid,
 	if (!HeapTupleIsValid(tuple))
 		return;					/* concurrently dropped, so nothing to do */
 	classform = (Form_pg_class) GETSTRUCT(tuple);
-	if (classform->relkind != RELKIND_PARTITIONED_INDEX &&
-		classform->relkind != RELKIND_INDEX)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-				 errmsg("\"%s\" is not an index", rv->relname)));
+
+	switch ((RelKind) classform->relkind)
+	{
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+					 errmsg("\"%s\" is not an index", rv->relname)));
+			break;
+	}
 	ReleaseSysCache(tuple);
 
 	/*
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 672fccff5b..3920760e5a 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -194,106 +194,122 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 	 * Triggers must be on tables or views, and there are additional
 	 * relation-type-specific restrictions.
 	 */
-	if (rel->rd_rel->relkind == RELKIND_RELATION)
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		/* Tables can't have INSTEAD OF triggers */
-		if (stmt->timing != TRIGGER_TYPE_BEFORE &&
-			stmt->timing != TRIGGER_TYPE_AFTER)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is a table",
-							RelationGetRelationName(rel)),
-					 errdetail("Tables cannot have INSTEAD OF triggers.")));
-	}
-	else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-	{
-		/* Partitioned tables can't have INSTEAD OF triggers */
-		if (stmt->timing != TRIGGER_TYPE_BEFORE &&
-			stmt->timing != TRIGGER_TYPE_AFTER)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is a table",
-							RelationGetRelationName(rel)),
-					 errdetail("Tables cannot have INSTEAD OF triggers.")));
+		case RELKIND_RELATION:
+			{
+				/* Tables can't have INSTEAD OF triggers */
+				if (stmt->timing != TRIGGER_TYPE_BEFORE &&
+					stmt->timing != TRIGGER_TYPE_AFTER)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is a table",
+									RelationGetRelationName(rel)),
+							 errdetail("Tables cannot have INSTEAD OF triggers.")));
+			}
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+			{
+				/* Partitioned tables can't have INSTEAD OF triggers */
+				if (stmt->timing != TRIGGER_TYPE_BEFORE &&
+					stmt->timing != TRIGGER_TYPE_AFTER)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is a table",
+									RelationGetRelationName(rel)),
+							 errdetail("Tables cannot have INSTEAD OF triggers.")));
 
-		/*
-		 * FOR EACH ROW triggers have further restrictions
-		 */
-		if (stmt->row)
-		{
-			/*
-			 * Disallow use of transition tables.
-			 *
-			 * Note that we have another restriction about transition tables
-			 * in partitions; search for 'has_superclass' below for an
-			 * explanation.  The check here is just to protect from the fact
-			 * that if we allowed it here, the creation would succeed for a
-			 * partitioned table with no partitions, but would be blocked by
-			 * the other restriction when the first partition was created,
-			 * which is very unfriendly behavior.
-			 */
-			if (stmt->transitionRels != NIL)
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("\"%s\" is a partitioned table",
-								RelationGetRelationName(rel)),
-						 errdetail("Triggers on partitioned tables cannot have transition tables.")));
-		}
-	}
-	else if (rel->rd_rel->relkind == RELKIND_VIEW)
-	{
-		/*
-		 * Views can have INSTEAD OF triggers (which we check below are
-		 * row-level), or statement-level BEFORE/AFTER triggers.
-		 */
-		if (stmt->timing != TRIGGER_TYPE_INSTEAD && stmt->row)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is a view",
-							RelationGetRelationName(rel)),
-					 errdetail("Views cannot have row-level BEFORE or AFTER triggers.")));
-		/* Disallow TRUNCATE triggers on VIEWs */
-		if (TRIGGER_FOR_TRUNCATE(stmt->events))
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is a view",
-							RelationGetRelationName(rel)),
-					 errdetail("Views cannot have TRUNCATE triggers.")));
-	}
-	else if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-	{
-		if (stmt->timing != TRIGGER_TYPE_BEFORE &&
-			stmt->timing != TRIGGER_TYPE_AFTER)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is a foreign table",
-							RelationGetRelationName(rel)),
-					 errdetail("Foreign tables cannot have INSTEAD OF triggers.")));
+				/*
+				 * FOR EACH ROW triggers have further restrictions
+				 */
+				if (stmt->row)
+				{
+					/*
+					 * Disallow use of transition tables.
+					 *
+					 * Note that we have another restriction about transition
+					 * tables in partitions; search for 'has_superclass' below
+					 * for an explanation.  The check here is just to protect
+					 * from the fact that if we allowed it here, the creation
+					 * would succeed for a partitioned table with no
+					 * partitions, but would be blocked by the other
+					 * restriction when the first partition was created, which
+					 * is very unfriendly behavior.
+					 */
+					if (stmt->transitionRels != NIL)
+						ereport(ERROR,
+								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+								 errmsg("\"%s\" is a partitioned table",
+										RelationGetRelationName(rel)),
+								 errdetail("Triggers on partitioned tables cannot have transition tables.")));
+				}
+			}
+			break;
+		case RELKIND_VIEW:
+			{
+				/*
+				 * Views can have INSTEAD OF triggers (which we check below
+				 * are row-level), or statement-level BEFORE/AFTER triggers.
+				 */
+				if (stmt->timing != TRIGGER_TYPE_INSTEAD && stmt->row)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is a view",
+									RelationGetRelationName(rel)),
+							 errdetail("Views cannot have row-level BEFORE or AFTER triggers.")));
+				/* Disallow TRUNCATE triggers on VIEWs */
+				if (TRIGGER_FOR_TRUNCATE(stmt->events))
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is a view",
+									RelationGetRelationName(rel)),
+							 errdetail("Views cannot have TRUNCATE triggers.")));
+			}
+			break;
+		case RELKIND_FOREIGN_TABLE:
+			{
+				if (stmt->timing != TRIGGER_TYPE_BEFORE &&
+					stmt->timing != TRIGGER_TYPE_AFTER)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is a foreign table",
+									RelationGetRelationName(rel)),
+							 errdetail("Foreign tables cannot have INSTEAD OF triggers.")));
 
-		if (TRIGGER_FOR_TRUNCATE(stmt->events))
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is a foreign table",
-							RelationGetRelationName(rel)),
-					 errdetail("Foreign tables cannot have TRUNCATE triggers.")));
+				if (TRIGGER_FOR_TRUNCATE(stmt->events))
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is a foreign table",
+									RelationGetRelationName(rel)),
+							 errdetail("Foreign tables cannot have TRUNCATE triggers.")));
 
-		/*
-		 * We disallow constraint triggers to protect the assumption that
-		 * triggers on FKs can't be deferred.  See notes with AfterTriggers
-		 * data structures, below.
-		 */
-		if (stmt->isconstraint)
+				/*
+				 * We disallow constraint triggers to protect the assumption
+				 * that triggers on FKs can't be deferred.  See notes with
+				 * AfterTriggers data structures, below.
+				 */
+				if (stmt->isconstraint)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is a foreign table",
+									RelationGetRelationName(rel)),
+							 errdetail("Foreign tables cannot have constraint triggers.")));
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is a foreign table",
-							RelationGetRelationName(rel)),
-					 errdetail("Foreign tables cannot have constraint triggers.")));
+					 errmsg("\"%s\" is not a table or view",
+							RelationGetRelationName(rel))));
+			break;
 	}
-	else
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table or view",
-						RelationGetRelationName(rel))));
 
 	if (!allowSystemTableMods && IsSystemRelation(rel))
 		ereport(ERROR,
@@ -345,8 +361,26 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 	 *
 	 * For that, we'd better hold lock on all of them ahead of time.
 	 */
-	partition_recurse = !isInternal && stmt->row &&
-		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE;
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			partition_recurse = !isInternal && stmt->row;
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			partition_recurse = false;
+			break;
+	}
+
 	if (partition_recurse)
 		list_free(find_all_inheritors(RelationGetRelid(rel),
 									  ShareRowExclusiveLock, NULL));
@@ -416,19 +450,34 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 			 * adjustments will be needed below.
 			 */
 
-			if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is a foreign table",
-								RelationGetRelationName(rel)),
-						 errdetail("Triggers on foreign tables cannot have transition tables.")));
-
-			if (rel->rd_rel->relkind == RELKIND_VIEW)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is a view",
-								RelationGetRelationName(rel)),
-						 errdetail("Triggers on views cannot have transition tables.")));
+			switch ((RelKind) rel->rd_rel->relkind)
+			{
+				case RELKIND_FOREIGN_TABLE:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is a foreign table",
+									RelationGetRelationName(rel)),
+							 errdetail("Triggers on foreign tables cannot have transition tables.")));
+					break;
+				case RELKIND_VIEW:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is a view",
+									RelationGetRelationName(rel)),
+							 errdetail("Triggers on views cannot have transition tables.")));
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_NULL:
+				default:
+					break;
+			}
 
 			/*
 			 * We currently don't allow row-level triggers with transition
@@ -1191,14 +1240,27 @@ RemoveTriggerById(Oid trigOid)
 
 	rel = table_open(relid, AccessExclusiveLock);
 
-	if (rel->rd_rel->relkind != RELKIND_RELATION &&
-		rel->rd_rel->relkind != RELKIND_VIEW &&
-		rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
-		rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table, view, or foreign table",
-						RelationGetRelationName(rel))));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table, view, or foreign table",
+							RelationGetRelationName(rel))));
+			break;
+	}
 
 	if (!allowSystemTableMods && IsSystemRelation(rel))
 		ereport(ERROR,
@@ -1298,13 +1360,27 @@ RangeVarCallbackForRenameTrigger(const RangeVar *rv, Oid relid, Oid oldrelid,
 	form = (Form_pg_class) GETSTRUCT(tuple);
 
 	/* only tables and views can have triggers */
-	if (form->relkind != RELKIND_RELATION && form->relkind != RELKIND_VIEW &&
-		form->relkind != RELKIND_FOREIGN_TABLE &&
-		form->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table, view, or foreign table",
-						rv->relname)));
+	switch ((RelKind) form->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table, view, or foreign table",
+							rv->relname)));
+			break;
+	}
 
 	/* you must own the table to rename one of its triggers */
 	if (!pg_class_ownercheck(relid, GetUserId()))
@@ -1534,21 +1610,37 @@ EnableDisableTrigger(Relation rel, const char *tgname,
 			 * When altering FOR EACH ROW triggers on a partitioned table, do
 			 * the same on the partitions as well.
 			 */
-			if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
-				(TRIGGER_FOR_ROW(oldtrig->tgtype)))
+			switch ((RelKind) rel->rd_rel->relkind)
 			{
-				PartitionDesc partdesc = RelationGetPartitionDesc(rel);
-				int			i;
-
-				for (i = 0; i < partdesc->nparts; i++)
-				{
-					Relation	part;
-
-					part = relation_open(partdesc->oids[i], lockmode);
-					EnableDisableTrigger(part, NameStr(oldtrig->tgname),
-										 fires_when, skip_system, lockmode);
-					table_close(part, NoLock);	/* keep lock till commit */
-				}
+				case RELKIND_PARTITIONED_TABLE:
+					if (TRIGGER_FOR_ROW(oldtrig->tgtype))
+					{
+						PartitionDesc partdesc = RelationGetPartitionDesc(rel);
+						int			i;
+
+						for (i = 0; i < partdesc->nparts; i++)
+						{
+							Relation	part;
+
+							part = relation_open(partdesc->oids[i], lockmode);
+							EnableDisableTrigger(part, NameStr(oldtrig->tgname),
+												 fires_when, skip_system, lockmode);
+							table_close(part, NoLock);	/* keep lock till commit */
+						}
+					}
+					break;
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_VIEW:
+				case RELKIND_SEQUENCE:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_NULL:
+				default:
+					break;
 			}
 
 			changed = true;
@@ -4167,12 +4259,26 @@ afterTriggerInvokeEvents(AfterTriggerEventList *events,
 						ExecDropSingleTupleTableSlot(slot2);
 						slot1 = slot2 = NULL;
 					}
-					if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+					switch ((RelKind) rel->rd_rel->relkind)
 					{
-						slot1 = MakeSingleTupleTableSlot(rel->rd_att,
-														 &TTSOpsMinimalTuple);
-						slot2 = MakeSingleTupleTableSlot(rel->rd_att,
-														 &TTSOpsMinimalTuple);
+						case RELKIND_FOREIGN_TABLE:
+							slot1 = MakeSingleTupleTableSlot(rel->rd_att,
+															 &TTSOpsMinimalTuple);
+							slot2 = MakeSingleTupleTableSlot(rel->rd_att,
+															 &TTSOpsMinimalTuple);
+							break;
+						case RELKIND_PARTITIONED_TABLE:
+						case RELKIND_RELATION:
+						case RELKIND_COMPOSITE_TYPE:
+						case RELKIND_INDEX:
+						case RELKIND_PARTITIONED_INDEX:
+						case RELKIND_MATVIEW:
+						case RELKIND_VIEW:
+						case RELKIND_SEQUENCE:
+						case RELKIND_TOASTVALUE:
+						case RELKIND_NULL:
+						default:
+							break;
 					}
 					if (trigdesc == NULL)	/* should not happen */
 						elog(ERROR, "relation %u has no triggers",
@@ -5566,9 +5672,27 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
 			break;
 	}
 
-	if (!(relkind == RELKIND_FOREIGN_TABLE && row_trigger))
-		new_event.ate_flags = (row_trigger && event == TRIGGER_EVENT_UPDATE) ?
-			AFTER_TRIGGER_2CTID : AFTER_TRIGGER_1CTID;
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_FOREIGN_TABLE:
+			if (row_trigger)
+				break;
+			/* fallthrough */
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			new_event.ate_flags = (row_trigger && event == TRIGGER_EVENT_UPDATE) ?
+				AFTER_TRIGGER_2CTID : AFTER_TRIGGER_1CTID;
+			break;
+	}
 	/* else, we'll initialize ate_flags for each trigger */
 
 	tgtype_level = (row_trigger ? TRIGGER_TYPE_ROW : TRIGGER_TYPE_STATEMENT);
@@ -5586,16 +5710,33 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
 							modifiedCols, oldslot, newslot))
 			continue;
 
-		if (relkind == RELKIND_FOREIGN_TABLE && row_trigger)
+		switch ((RelKind) relkind)
 		{
-			if (fdw_tuplestore == NULL)
-			{
-				fdw_tuplestore = GetCurrentFDWTuplestore();
-				new_event.ate_flags = AFTER_TRIGGER_FDW_FETCH;
-			}
-			else
-				/* subsequent event for the same tuple */
-				new_event.ate_flags = AFTER_TRIGGER_FDW_REUSE;
+			case RELKIND_FOREIGN_TABLE:
+				if (row_trigger)
+				{
+					if (fdw_tuplestore == NULL)
+					{
+						fdw_tuplestore = GetCurrentFDWTuplestore();
+						new_event.ate_flags = AFTER_TRIGGER_FDW_FETCH;
+					}
+					else
+						/* subsequent event for the same tuple */
+						new_event.ate_flags = AFTER_TRIGGER_FDW_REUSE;
+				}
+				break;
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				break;
 		}
 
 		/*
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 9e5938b10e..4771b8517f 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -2918,11 +2918,26 @@ get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
 			 * a suitable expression index, this should also check expression
 			 * index columns.
 			 */
-			if (rel->rd_rel->relkind != RELKIND_RELATION &&
-				rel->rd_rel->relkind != RELKIND_MATVIEW)
+			switch ((RelKind) rel->rd_rel->relkind)
 			{
-				relation_close(rel, lockmode);
-				continue;
+				case RELKIND_RELATION:
+				case RELKIND_MATVIEW:
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+				case RELKIND_NULL:
+				default:
+					{
+						relation_close(rel, lockmode);
+						continue;
+					}
+					break;
 			}
 
 			/* Build the RelToCheck entry with enough space for all atts */
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index d32de23e62..15c9bcb142 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -881,10 +881,23 @@ get_all_vacuum_rels(int options)
 		 * to be performed, caller will decide whether to process or ignore
 		 * them.
 		 */
-		if (classForm->relkind != RELKIND_RELATION &&
-			classForm->relkind != RELKIND_MATVIEW &&
-			classForm->relkind != RELKIND_PARTITIONED_TABLE)
-			continue;
+		switch ((RelKind) classForm->relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				continue;
+		}
 
 		/*
 		 * Build VacuumRelation(s) specifying the table OIDs to be processed.
@@ -1383,13 +1396,27 @@ vac_update_datfrozenxid(void)
 		 * Only consider relations able to hold unfrozen XIDs (anything else
 		 * should have InvalidTransactionId in relfrozenxid anyway).
 		 */
-		if (classForm->relkind != RELKIND_RELATION &&
-			classForm->relkind != RELKIND_MATVIEW &&
-			classForm->relkind != RELKIND_TOASTVALUE)
+		switch ((RelKind) classForm->relkind)
 		{
-			Assert(!TransactionIdIsValid(classForm->relfrozenxid));
-			Assert(!MultiXactIdIsValid(classForm->relminmxid));
-			continue;
+			case RELKIND_RELATION:
+			case RELKIND_MATVIEW:
+			case RELKIND_TOASTVALUE:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				{
+					Assert(!TransactionIdIsValid(classForm->relfrozenxid));
+					Assert(!MultiXactIdIsValid(classForm->relminmxid));
+					continue;
+				}
+				break;
 		}
 
 		/*
@@ -1762,18 +1789,31 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
 	/*
 	 * Check that it's of a vacuumable relkind.
 	 */
-	if (onerel->rd_rel->relkind != RELKIND_RELATION &&
-		onerel->rd_rel->relkind != RELKIND_MATVIEW &&
-		onerel->rd_rel->relkind != RELKIND_TOASTVALUE &&
-		onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
+	switch ((RelKind) onerel->rd_rel->relkind)
 	{
-		ereport(WARNING,
-				(errmsg("skipping \"%s\" --- cannot vacuum non-tables or special system tables",
-						RelationGetRelationName(onerel))));
-		relation_close(onerel, lmode);
-		PopActiveSnapshot();
-		CommitTransactionCommand();
-		return false;
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			{
+				ereport(WARNING,
+						(errmsg("skipping \"%s\" --- cannot vacuum non-tables or special system tables",
+								RelationGetRelationName(onerel))));
+				relation_close(onerel, lmode);
+				PopActiveSnapshot();
+				CommitTransactionCommand();
+				return false;
+			}
+			break;
 	}
 
 	/*
@@ -1796,13 +1836,26 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
 	 * useful work is on their child partitions, which have been queued up for
 	 * us separately.
 	 */
-	if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	switch ((RelKind) onerel->rd_rel->relkind)
 	{
-		relation_close(onerel, lmode);
-		PopActiveSnapshot();
-		CommitTransactionCommand();
-		/* It's OK to proceed with ANALYZE on this table */
-		return true;
+		case RELKIND_PARTITIONED_TABLE:
+			relation_close(onerel, lmode);
+			PopActiveSnapshot();
+			CommitTransactionCommand();
+			/* It's OK to proceed with ANALYZE on this table */
+			return true;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	/*
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 4fdffad6f3..dc2f1908bb 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -1079,7 +1079,7 @@ CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
 	TriggerDesc *trigDesc = resultRel->trigdesc;
 	FdwRoutine *fdwroutine;
 
-	switch (resultRel->rd_rel->relkind)
+	switch ((RelKind) resultRel->rd_rel->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
@@ -1193,6 +1193,10 @@ CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
 					break;
 			}
 			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_NULL:
 		default:
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
@@ -1213,7 +1217,7 @@ CheckValidRowMarkRel(Relation rel, RowMarkType markType)
 {
 	FdwRoutine *fdwroutine;
 
-	switch (rel->rd_rel->relkind)
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
@@ -1257,6 +1261,10 @@ CheckValidRowMarkRel(Relation rel, RowMarkType markType)
 						 errmsg("cannot lock rows in foreign table \"%s\"",
 								RelationGetRelationName(rel))));
 			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_NULL:
 		default:
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
@@ -1308,10 +1316,26 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
 		resultRelInfo->ri_TrigWhenExprs = NULL;
 		resultRelInfo->ri_TrigInstrument = NULL;
 	}
-	if (resultRelationDesc->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-		resultRelInfo->ri_FdwRoutine = GetFdwRoutineForRelation(resultRelationDesc, true);
-	else
-		resultRelInfo->ri_FdwRoutine = NULL;
+
+	switch ((RelKind) resultRelationDesc->rd_rel->relkind)
+	{
+		case RELKIND_FOREIGN_TABLE:
+			resultRelInfo->ri_FdwRoutine = GetFdwRoutineForRelation(resultRelationDesc, true);
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			resultRelInfo->ri_FdwRoutine = NULL;
+			break;
+	}
 
 	/* The following fields are set later if needed */
 	resultRelInfo->ri_FdwState = NULL;
@@ -2614,42 +2638,61 @@ EvalPlanQualFetchRowMark(EPQState *epqstate, Index rti, TupleTableSlot *slot)
 			return false;
 
 		/* fetch requests on foreign tables must be passed to their FDW */
-		if (erm->relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		switch ((RelKind) erm->relation->rd_rel->relkind)
 		{
-			FdwRoutine *fdwroutine;
-			bool		updated = false;
+			case RELKIND_FOREIGN_TABLE:
+				{
+					FdwRoutine *fdwroutine;
+					bool		updated = false;
 
-			fdwroutine = GetFdwRoutineForRelation(erm->relation, false);
-			/* this should have been checked already, but let's be safe */
-			if (fdwroutine->RefetchForeignRow == NULL)
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("cannot lock rows in foreign table \"%s\"",
-								RelationGetRelationName(erm->relation))));
+					fdwroutine = GetFdwRoutineForRelation(erm->relation, false);
 
-			fdwroutine->RefetchForeignRow(epqstate->recheckestate,
-										  erm,
-										  datum,
-										  slot,
-										  &updated);
-			if (TupIsNull(slot))
-				elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
+					/*
+					 * this should have been checked already, but let's be
+					 * safe
+					 */
+					if (fdwroutine->RefetchForeignRow == NULL)
+						ereport(ERROR,
+								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+								 errmsg("cannot lock rows in foreign table \"%s\"",
+										RelationGetRelationName(erm->relation))));
 
-			/*
-			 * Ideally we'd insist on updated == false here, but that assumes
-			 * that FDWs can track that exactly, which they might not be able
-			 * to.  So just ignore the flag.
-			 */
-			return true;
-		}
-		else
-		{
-			/* ordinary table, fetch the tuple */
-			if (!table_tuple_fetch_row_version(erm->relation,
-											   (ItemPointer) DatumGetPointer(datum),
-											   SnapshotAny, slot))
-				elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
-			return true;
+					fdwroutine->RefetchForeignRow(epqstate->recheckestate,
+												  erm,
+												  datum,
+												  slot,
+												  &updated);
+					if (TupIsNull(slot))
+						elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
+
+					/*
+					 * Ideally we'd insist on updated == false here, but that
+					 * assumes that FDWs can track that exactly, which they
+					 * might not be able to.  So just ignore the flag.
+					 */
+					return true;
+				}
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				{
+					/* ordinary table, fetch the tuple */
+					if (!table_tuple_fetch_row_version(erm->relation,
+													   (ItemPointer) DatumGetPointer(datum),
+													   SnapshotAny, slot))
+						elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
+					return true;
+				}
+				break;
 		}
 	}
 	else
diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c
index 8f474faed0..7a56b2d282 100644
--- a/src/backend/executor/execReplication.c
+++ b/src/backend/executor/execReplication.c
@@ -607,19 +607,34 @@ CheckSubscriptionRelkind(char relkind, const char *nspname,
 	/*
 	 * Give a more specific error for foreign tables.
 	 */
-	if (relkind == RELKIND_FOREIGN_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot use relation \"%s.%s\" as logical replication target",
-						nspname, relname),
-				 errdetail("\"%s.%s\" is a foreign table.",
-						   nspname, relname)));
-
-	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot use relation \"%s.%s\" as logical replication target",
-						nspname, relname),
-				 errdetail("\"%s.%s\" is not a table.",
-						   nspname, relname)));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_FOREIGN_TABLE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot use relation \"%s.%s\" as logical replication target",
+							nspname, relname),
+					 errdetail("\"%s.%s\" is a foreign table.",
+							   nspname, relname)));
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot use relation \"%s.%s\" as logical replication target",
+							nspname, relname),
+					 errdetail("\"%s.%s\" is not a table.",
+							   nspname, relname)));
+			break;
+	}
 }
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 20a4c474cc..d22817c759 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2177,56 +2177,77 @@ ExecModifyTable(PlanState *pstate)
 				bool		isNull;
 
 				relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
-				if (relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW)
+				switch ((RelKind) relkind)
 				{
-					datum = ExecGetJunkAttribute(slot,
-												 junkfilter->jf_junkAttNo,
-												 &isNull);
-					/* shouldn't ever get a null result... */
-					if (isNull)
-						elog(ERROR, "ctid is NULL");
-
-					tupleid = (ItemPointer) DatumGetPointer(datum);
-					tuple_ctid = *tupleid;	/* be sure we don't free ctid!! */
-					tupleid = &tuple_ctid;
-				}
+					case RELKIND_RELATION:
+					case RELKIND_MATVIEW:
+						{
+							datum = ExecGetJunkAttribute(slot,
+														 junkfilter->jf_junkAttNo,
+														 &isNull);
+							/* shouldn't ever get a null result... */
+							if (isNull)
+								elog(ERROR, "ctid is NULL");
+
+							tupleid = (ItemPointer) DatumGetPointer(datum);
+							tuple_ctid = *tupleid;	/* be sure we don't free
+													 * ctid!! */
+							tupleid = &tuple_ctid;
+						}
+						break;
+					case RELKIND_PARTITIONED_INDEX:
+					case RELKIND_SEQUENCE:
+					case RELKIND_COMPOSITE_TYPE:
+					case RELKIND_FOREIGN_TABLE:
+					case RELKIND_INDEX:
+					case RELKIND_PARTITIONED_TABLE:
+					case RELKIND_TOASTVALUE:
+					case RELKIND_VIEW:
+					case RELKIND_NULL:
+					default:
 
-				/*
-				 * Use the wholerow attribute, when available, to reconstruct
-				 * the old relation tuple.
-				 *
-				 * Foreign table updates have a wholerow attribute when the
-				 * relation has a row-level trigger.  Note that the wholerow
-				 * attribute does not carry system columns.  Foreign table
-				 * triggers miss seeing those, except that we know enough here
-				 * to set t_tableOid.  Quite separately from this, the FDW may
-				 * fetch its own junk attrs to identify the row.
-				 *
-				 * Other relevant relkinds, currently limited to views, always
-				 * have a wholerow attribute.
-				 */
-				else if (AttributeNumberIsValid(junkfilter->jf_junkAttNo))
-				{
-					datum = ExecGetJunkAttribute(slot,
-												 junkfilter->jf_junkAttNo,
-												 &isNull);
-					/* shouldn't ever get a null result... */
-					if (isNull)
-						elog(ERROR, "wholerow is NULL");
-
-					oldtupdata.t_data = DatumGetHeapTupleHeader(datum);
-					oldtupdata.t_len =
-						HeapTupleHeaderGetDatumLength(oldtupdata.t_data);
-					ItemPointerSetInvalid(&(oldtupdata.t_self));
-					/* Historically, view triggers see invalid t_tableOid. */
-					oldtupdata.t_tableOid =
-						(relkind == RELKIND_VIEW) ? InvalidOid :
-						RelationGetRelid(resultRelInfo->ri_RelationDesc);
-
-					oldtuple = &oldtupdata;
+						/*
+						 * Use the wholerow attribute, when available, to
+						 * reconstruct the old relation tuple.
+						 *
+						 * Foreign table updates have a wholerow attribute
+						 * when the relation has a row-level trigger.  Note
+						 * that the wholerow attribute does not carry system
+						 * columns.  Foreign table triggers miss seeing those,
+						 * except that we know enough here to set t_tableOid.
+						 * Quite separately from this, the FDW may fetch its
+						 * own junk attrs to identify the row.
+						 *
+						 * Other relevant relkinds, currently limited to
+						 * views, always have a wholerow attribute.
+						 */
+						if (AttributeNumberIsValid(junkfilter->jf_junkAttNo))
+						{
+							datum = ExecGetJunkAttribute(slot,
+														 junkfilter->jf_junkAttNo,
+														 &isNull);
+							/* shouldn't ever get a null result... */
+							if (isNull)
+								elog(ERROR, "wholerow is NULL");
+
+							oldtupdata.t_data = DatumGetHeapTupleHeader(datum);
+							oldtupdata.t_len =
+								HeapTupleHeaderGetDatumLength(oldtupdata.t_data);
+							ItemPointerSetInvalid(&(oldtupdata.t_self));
+
+							/*
+							 * Historically, view triggers see invalid
+							 * t_tableOid.
+							 */
+							oldtupdata.t_tableOid =
+								(relkind == RELKIND_VIEW) ? InvalidOid :
+								RelationGetRelid(resultRelInfo->ri_RelationDesc);
+
+							oldtuple = &oldtupdata;
+						}
+						else
+							Assert(relkind == RELKIND_FOREIGN_TABLE);
 				}
-				else
-					Assert(relkind == RELKIND_FOREIGN_TABLE);
 			}
 
 			/*
@@ -2697,27 +2718,40 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
 					char		relkind;
 
 					relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
-					if (relkind == RELKIND_RELATION ||
-						relkind == RELKIND_MATVIEW ||
-						relkind == RELKIND_PARTITIONED_TABLE)
+					switch ((RelKind) relkind)
 					{
-						j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
-						if (!AttributeNumberIsValid(j->jf_junkAttNo))
-							elog(ERROR, "could not find junk ctid column");
-					}
-					else if (relkind == RELKIND_FOREIGN_TABLE)
-					{
-						/*
-						 * When there is a row-level trigger, there should be
-						 * a wholerow attribute.
-						 */
-						j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
-					}
-					else
-					{
-						j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
-						if (!AttributeNumberIsValid(j->jf_junkAttNo))
-							elog(ERROR, "could not find junk wholerow column");
+						case RELKIND_RELATION:
+						case RELKIND_MATVIEW:
+						case RELKIND_PARTITIONED_TABLE:
+							{
+								j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
+								if (!AttributeNumberIsValid(j->jf_junkAttNo))
+									elog(ERROR, "could not find junk ctid column");
+							}
+							break;
+						case RELKIND_FOREIGN_TABLE:
+							{
+								/*
+								 * When there is a row-level trigger, there
+								 * should be a wholerow attribute.
+								 */
+								j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
+							}
+							break;
+						case RELKIND_PARTITIONED_INDEX:
+						case RELKIND_SEQUENCE:
+						case RELKIND_COMPOSITE_TYPE:
+						case RELKIND_INDEX:
+						case RELKIND_TOASTVALUE:
+						case RELKIND_VIEW:
+						case RELKIND_NULL:
+						default:
+							{
+								j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
+								if (!AttributeNumberIsValid(j->jf_junkAttNo))
+									elog(ERROR, "could not find junk wholerow column");
+							}
+							break;
 					}
 				}
 
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d984da25d7..6d2b587153 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -387,29 +387,42 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
 		switch (rel->rtekind)
 		{
 			case RTE_RELATION:
-				if (rte->relkind == RELKIND_FOREIGN_TABLE)
+				switch ((RelKind) rte->relkind)
 				{
-					/* Foreign table */
-					set_foreign_size(root, rel, rte);
-				}
-				else if (rte->relkind == RELKIND_PARTITIONED_TABLE)
-				{
-					/*
-					 * We could get here if asked to scan a partitioned table
-					 * with ONLY.  In that case we shouldn't scan any of the
-					 * partitions, so mark it as a dummy rel.
-					 */
-					set_dummy_rel_pathlist(rel);
-				}
-				else if (rte->tablesample != NULL)
-				{
-					/* Sampled relation */
-					set_tablesample_rel_size(root, rel, rte);
-				}
-				else
-				{
-					/* Plain relation */
-					set_plain_rel_size(root, rel, rte);
+					case RELKIND_FOREIGN_TABLE:
+						/* Foreign table */
+						set_foreign_size(root, rel, rte);
+						break;
+					case RELKIND_PARTITIONED_TABLE:
+
+						/*
+						 * We could get here if asked to scan a partitioned
+						 * table with ONLY.  In that case we shouldn't scan
+						 * any of the partitions, so mark it as a dummy rel.
+						 */
+						set_dummy_rel_pathlist(rel);
+						break;
+					case RELKIND_PARTITIONED_INDEX:
+					case RELKIND_SEQUENCE:
+					case RELKIND_COMPOSITE_TYPE:
+					case RELKIND_INDEX:
+					case RELKIND_MATVIEW:
+					case RELKIND_RELATION:
+					case RELKIND_TOASTVALUE:
+					case RELKIND_VIEW:
+					case RELKIND_NULL:
+					default:
+						if (rte->tablesample != NULL)
+						{
+							/* Sampled relation */
+							set_tablesample_rel_size(root, rel, rte);
+						}
+						else
+						{
+							/* Plain relation */
+							set_plain_rel_size(root, rel, rte);
+						}
+						break;
 				}
 				break;
 			case RTE_SUBQUERY:
@@ -484,20 +497,34 @@ set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 		switch (rel->rtekind)
 		{
 			case RTE_RELATION:
-				if (rte->relkind == RELKIND_FOREIGN_TABLE)
-				{
-					/* Foreign table */
-					set_foreign_pathlist(root, rel, rte);
-				}
-				else if (rte->tablesample != NULL)
+				switch ((RelKind) rte->relkind)
 				{
-					/* Sampled relation */
-					set_tablesample_rel_pathlist(root, rel, rte);
-				}
-				else
-				{
-					/* Plain relation */
-					set_plain_rel_pathlist(root, rel, rte);
+					case RELKIND_FOREIGN_TABLE:
+						/* Foreign table */
+						set_foreign_pathlist(root, rel, rte);
+						break;
+					case RELKIND_PARTITIONED_INDEX:
+					case RELKIND_SEQUENCE:
+					case RELKIND_COMPOSITE_TYPE:
+					case RELKIND_INDEX:
+					case RELKIND_MATVIEW:
+					case RELKIND_PARTITIONED_TABLE:
+					case RELKIND_RELATION:
+					case RELKIND_TOASTVALUE:
+					case RELKIND_VIEW:
+					case RELKIND_NULL:
+					default:
+						if (rte->tablesample != NULL)
+						{
+							/* Sampled relation */
+							set_tablesample_rel_pathlist(root, rel, rte);
+						}
+						else
+						{
+							/* Plain relation */
+							set_plain_rel_pathlist(root, rel, rte);
+						}
+						break;
 				}
 				break;
 			case RTE_SUBQUERY:
@@ -643,13 +670,27 @@ set_rel_consider_parallel(PlannerInfo *root, RelOptInfo *rel,
 			 * up with a separate connection, and these connections might not
 			 * be appropriately coordinated between workers and the leader.
 			 */
-			if (rte->relkind == RELKIND_FOREIGN_TABLE)
+			switch ((RelKind) rte->relkind)
 			{
-				Assert(rel->fdwroutine);
-				if (!rel->fdwroutine->IsForeignScanParallelSafe)
-					return;
-				if (!rel->fdwroutine->IsForeignScanParallelSafe(root, rel, rte))
-					return;
+				case RELKIND_FOREIGN_TABLE:
+					Assert(rel->fdwroutine);
+					if (!rel->fdwroutine->IsForeignScanParallelSafe)
+						return;
+					if (!rel->fdwroutine->IsForeignScanParallelSafe(root, rel, rte))
+						return;
+					break;
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_VIEW:
+				case RELKIND_SEQUENCE:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_NULL:
+				default:
+					break;
 			}
 
 			/*
@@ -960,19 +1001,52 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
 	 * that when we've created Paths for all the children, the root
 	 * partitioned table's list will contain all such indexes.
 	 */
-	if (rte->relkind == RELKIND_PARTITIONED_TABLE)
-		rel->partitioned_child_rels = list_make1_int(rti);
+	switch ((RelKind) rte->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			rel->partitioned_child_rels = list_make1_int(rti);
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	/*
 	 * If this is a partitioned baserel, set the consider_partitionwise_join
 	 * flag; currently, we only consider partitionwise joins with the baserel
 	 * if its targetlist doesn't contain a whole-row Var.
 	 */
-	if (enable_partitionwise_join &&
-		rel->reloptkind == RELOPT_BASEREL &&
-		rte->relkind == RELKIND_PARTITIONED_TABLE &&
-		rel->attr_needed[InvalidAttrNumber - rel->min_attr] == NULL)
-		rel->consider_partitionwise_join = true;
+	switch ((RelKind) rte->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			if (enable_partitionwise_join &&
+				rel->reloptkind == RELOPT_BASEREL &&
+				rte->relkind == RELKIND_PARTITIONED_TABLE &&
+				rel->attr_needed[InvalidAttrNumber - rel->min_attr] == NULL)
+				rel->consider_partitionwise_join = true;
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	/*
 	 * Initialize to compute size estimates for whole append relation.
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 4131019fc9..de8c1073fa 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -1280,10 +1280,24 @@ inheritance_planner(PlannerInfo *root)
 	 */
 	parent_rte = rt_fetch(top_parentRTindex, parse->rtable);
 	Assert(parent_rte->inh);
-	if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+	switch ((RelKind) parent_rte->relkind)
 	{
-		nominalRelation = top_parentRTindex;
-		rootRelation = top_parentRTindex;
+		case RELKIND_PARTITIONED_TABLE:
+			nominalRelation = top_parentRTindex;
+			rootRelation = top_parentRTindex;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	/*
@@ -2338,11 +2352,25 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
 			 * If target is a partition root table, we need to mark the
 			 * ModifyTable node appropriately for that.
 			 */
-			if (rt_fetch(parse->resultRelation, parse->rtable)->relkind ==
-				RELKIND_PARTITIONED_TABLE)
-				rootRelation = parse->resultRelation;
-			else
-				rootRelation = 0;
+			switch ((RelKind) rt_fetch(parse->resultRelation, parse->rtable)->relkind)
+			{
+				case RELKIND_PARTITIONED_TABLE:
+					rootRelation = parse->resultRelation;
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+				case RELKIND_NULL:
+				default:
+					rootRelation = 0;
+					break;
+			}
 
 			/*
 			 * Set up the WITH CHECK OPTION and RETURNING lists-of-lists, if
@@ -2765,45 +2793,58 @@ select_rowmark_type(RangeTblEntry *rte, LockClauseStrength strength)
 		/* If it's not a table at all, use ROW_MARK_COPY */
 		return ROW_MARK_COPY;
 	}
-	else if (rte->relkind == RELKIND_FOREIGN_TABLE)
-	{
-		/* Let the FDW select the rowmark type, if it wants to */
-		FdwRoutine *fdwroutine = GetFdwRoutineByRelId(rte->relid);
-
-		if (fdwroutine->GetForeignRowMarkType != NULL)
-			return fdwroutine->GetForeignRowMarkType(rte, strength);
-		/* Otherwise, use ROW_MARK_COPY by default */
-		return ROW_MARK_COPY;
-	}
 	else
-	{
-		/* Regular table, apply the appropriate lock type */
-		switch (strength)
+		switch ((RelKind) rte->relkind)
 		{
-			case LCS_NONE:
+			case RELKIND_FOREIGN_TABLE:
+				{
+					/* Let the FDW select the rowmark type, if it wants to */
+					FdwRoutine *fdwroutine = GetFdwRoutineByRelId(rte->relid);
 
-				/*
-				 * We don't need a tuple lock, only the ability to re-fetch
-				 * the row.
-				 */
-				return ROW_MARK_REFERENCE;
-				break;
-			case LCS_FORKEYSHARE:
-				return ROW_MARK_KEYSHARE;
-				break;
-			case LCS_FORSHARE:
-				return ROW_MARK_SHARE;
-				break;
-			case LCS_FORNOKEYUPDATE:
-				return ROW_MARK_NOKEYEXCLUSIVE;
-				break;
-			case LCS_FORUPDATE:
-				return ROW_MARK_EXCLUSIVE;
+					if (fdwroutine->GetForeignRowMarkType != NULL)
+						return fdwroutine->GetForeignRowMarkType(rte, strength);
+					/* Otherwise, use ROW_MARK_COPY by default */
+					return ROW_MARK_COPY;
+				}
 				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				/* Regular table, apply the appropriate lock type */
+				switch (strength)
+				{
+					case LCS_NONE:
+
+						/*
+						 * We don't need a tuple lock, only the ability to
+						 * re-fetch the row.
+						 */
+						return ROW_MARK_REFERENCE;
+						break;
+					case LCS_FORKEYSHARE:
+						return ROW_MARK_KEYSHARE;
+						break;
+					case LCS_FORSHARE:
+						return ROW_MARK_SHARE;
+						break;
+					case LCS_FORNOKEYUPDATE:
+						return ROW_MARK_NOKEYEXCLUSIVE;
+						break;
+					case LCS_FORUPDATE:
+						return ROW_MARK_EXCLUSIVE;
+						break;
+				}
+				elog(ERROR, "unrecognized LockClauseStrength %d", (int) strength);
+				return ROW_MARK_EXCLUSIVE;	/* keep compiler quiet */
 		}
-		elog(ERROR, "unrecognized LockClauseStrength %d", (int) strength);
-		return ROW_MARK_EXCLUSIVE;	/* keep compiler quiet */
-	}
 }
 
 /*
@@ -3142,8 +3183,25 @@ remove_useless_groupby_columns(PlannerInfo *root)
 		 * may cause duplicate rows.  This cannot happen with partitioned
 		 * tables, however.
 		 */
-		if (rte->inh && rte->relkind != RELKIND_PARTITIONED_TABLE)
-			continue;
+		switch ((RelKind) rte->relkind)
+		{
+			case RELKIND_PARTITIONED_TABLE:
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				if (rte->inh)
+					continue;
+				break;
+		}
 
 		/* Nothing to do unless this rel has multiple Vars in GROUP BY */
 		relattnos = groupbyattnos[relid];
diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c
index 3132fd35a5..1199b21154 100644
--- a/src/backend/optimizer/util/inherit.c
+++ b/src/backend/optimizer/util/inherit.c
@@ -129,88 +129,113 @@ expand_inherited_rtentry(PlannerInfo *root, RelOptInfo *rel,
 	}
 
 	/* Scan the inheritance set and expand it */
-	if (oldrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	switch ((RelKind) oldrelation->rd_rel->relkind)
 	{
-		/*
-		 * Partitioned table, so set up for partitioning.
-		 */
-		Assert(rte->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * Recursively expand and lock the partitions.  While at it, also
-		 * extract the partition key columns of all the partitioned tables.
-		 */
-		expand_partitioned_rtentry(root, rel, rte, rti,
-								   oldrelation, oldrc, lockmode);
-	}
-	else
-	{
-		/*
-		 * Ordinary table, so process traditional-inheritance children.  (Note
-		 * that partitioned tables are not allowed to have inheritance
-		 * children, so it's not possible for both cases to apply.)
-		 */
-		List	   *inhOIDs;
-		ListCell   *l;
-
-		/* Scan for all members of inheritance set, acquire needed locks */
-		inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
-
-		/*
-		 * We used to special-case the situation where the table no longer has
-		 * any children, by clearing rte->inh and exiting.  That no longer
-		 * works, because this function doesn't get run until after decisions
-		 * have been made that depend on rte->inh.  We have to treat such
-		 * situations as normal inheritance.  The table itself should always
-		 * have been found, though.
-		 */
-		Assert(inhOIDs != NIL);
-		Assert(linitial_oid(inhOIDs) == parentOID);
-
-		/* Expand simple_rel_array and friends to hold child objects. */
-		expand_planner_arrays(root, list_length(inhOIDs));
-
-		/*
-		 * Expand inheritance children in the order the OIDs were returned by
-		 * find_all_inheritors.
-		 */
-		foreach(l, inhOIDs)
-		{
-			Oid			childOID = lfirst_oid(l);
-			Relation	newrelation;
-			RangeTblEntry *childrte;
-			Index		childRTindex;
-
-			/* Open rel if needed; we already have required locks */
-			if (childOID != parentOID)
-				newrelation = table_open(childOID, NoLock);
-			else
-				newrelation = oldrelation;
-
-			/*
-			 * It is possible that the parent table has children that are temp
-			 * tables of other backends.  We cannot safely access such tables
-			 * (because of buffering issues), and the best thing to do seems
-			 * to be to silently ignore them.
-			 */
-			if (childOID != parentOID && RELATION_IS_OTHER_TEMP(newrelation))
+		case RELKIND_PARTITIONED_TABLE:
 			{
-				table_close(newrelation, lockmode);
-				continue;
+				/*
+				 * Partitioned table, so set up for partitioning.
+				 */
+				Assert(rte->relkind == RELKIND_PARTITIONED_TABLE);
+
+				/*
+				 * Recursively expand and lock the partitions.  While at it,
+				 * also extract the partition key columns of all the
+				 * partitioned tables.
+				 */
+				expand_partitioned_rtentry(root, rel, rte, rti,
+										   oldrelation, oldrc, lockmode);
 			}
-
-			/* Create RTE and AppendRelInfo, plus PlanRowMark if needed. */
-			expand_single_inheritance_child(root, rte, rti, oldrelation,
-											oldrc, newrelation,
-											&childrte, &childRTindex);
-
-			/* Create the otherrel RelOptInfo too. */
-			(void) build_simple_rel(root, childRTindex, rel);
-
-			/* Close child relations, but keep locks */
-			if (childOID != parentOID)
-				table_close(newrelation, NoLock);
-		}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			{
+				/*
+				 * Ordinary table, so process traditional-inheritance
+				 * children.  (Note that partitioned tables are not allowed to
+				 * have inheritance children, so it's not possible for both
+				 * cases to apply.)
+				 */
+				List	   *inhOIDs;
+				ListCell   *l;
+
+				/*
+				 * Scan for all members of inheritance set, acquire needed
+				 * locks
+				 */
+				inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
+
+				/*
+				 * We used to special-case the situation where the table no
+				 * longer has any children, by clearing rte->inh and exiting.
+				 * That no longer works, because this function doesn't get run
+				 * until after decisions have been made that depend on
+				 * rte->inh.  We have to treat such situations as normal
+				 * inheritance.  The table itself should always have been
+				 * found, though.
+				 */
+				Assert(inhOIDs != NIL);
+				Assert(linitial_oid(inhOIDs) == parentOID);
+
+				/* Expand simple_rel_array and friends to hold child objects. */
+				expand_planner_arrays(root, list_length(inhOIDs));
+
+				/*
+				 * Expand inheritance children in the order the OIDs were
+				 * returned by find_all_inheritors.
+				 */
+				foreach(l, inhOIDs)
+				{
+					Oid			childOID = lfirst_oid(l);
+					Relation	newrelation;
+					RangeTblEntry *childrte;
+					Index		childRTindex;
+
+					/* Open rel if needed; we already have required locks */
+					if (childOID != parentOID)
+						newrelation = table_open(childOID, NoLock);
+					else
+						newrelation = oldrelation;
+
+					/*
+					 * It is possible that the parent table has children that
+					 * are temp tables of other backends.  We cannot safely
+					 * access such tables (because of buffering issues), and
+					 * the best thing to do seems to be to silently ignore
+					 * them.
+					 */
+					if (childOID != parentOID && RELATION_IS_OTHER_TEMP(newrelation))
+					{
+						table_close(newrelation, lockmode);
+						continue;
+					}
+
+					/*
+					 * Create RTE and AppendRelInfo, plus PlanRowMark if
+					 * needed.
+					 */
+					expand_single_inheritance_child(root, rte, rti, oldrelation,
+													oldrc, newrelation,
+													&childrte, &childRTindex);
+
+					/* Create the otherrel RelOptInfo too. */
+					(void) build_simple_rel(root, childRTindex, rel);
+
+					/* Close child relations, but keep locks */
+					if (childOID != parentOID)
+						table_close(newrelation, NoLock);
+				}
+			}
+			break;
 	}
 
 	/*
@@ -380,10 +405,26 @@ expand_partitioned_rtentry(PlannerInfo *root, RelOptInfo *relinfo,
 												childrelinfo->relids);
 
 		/* If this child is itself partitioned, recurse */
-		if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-			expand_partitioned_rtentry(root, childrelinfo,
-									   childrte, childRTindex,
-									   childrel, top_parentrc, lockmode);
+		switch ((RelKind) childrel->rd_rel->relkind)
+		{
+			case RELKIND_PARTITIONED_TABLE:
+				expand_partitioned_rtentry(root, childrelinfo,
+										   childrte, childRTindex,
+										   childrel, top_parentrc, lockmode);
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				break;
+		}
 
 		/* Close child relation, but keep locks */
 		table_close(childrel, NoLock);
@@ -448,13 +489,26 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
 	childrte->relid = childOID;
 	childrte->relkind = childrel->rd_rel->relkind;
 	/* A partitioned child will need to be expanded further. */
-	if (childrte->relkind == RELKIND_PARTITIONED_TABLE)
+	switch ((RelKind) childrte->relkind)
 	{
-		Assert(childOID != parentOID);
-		childrte->inh = true;
+		case RELKIND_PARTITIONED_TABLE:
+			Assert(childOID != parentOID);
+			childrte->inh = true;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			childrte->inh = false;
+			break;
 	}
-	else
-		childrte->inh = false;
 	childrte->requiredPerms = 0;
 	childrte->securityQuals = NIL;
 
@@ -578,7 +632,25 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
 		 * that the executor ignores them (except their existence means that
 		 * the child tables will be locked using the appropriate mode).
 		 */
-		childrc->isParent = (childrte->relkind == RELKIND_PARTITIONED_TABLE);
+		switch ((RelKind) childrte->relkind)
+		{
+			case RELKIND_PARTITIONED_TABLE:
+				childrc->isParent = true;
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				childrc->isParent = false;
+				break;
+		}
 
 		/* Include child's rowmark type in top parent's allMarkTypes */
 		top_parentrc->allMarkTypes |= childrc->allMarkTypes;
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..13232d797a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -215,10 +215,23 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 			 * Ignore partitioned indexes, since they are not usable for
 			 * queries.
 			 */
-			if (indexRelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
+			switch ((RelKind) indexRelation->rd_rel->relkind)
 			{
-				index_close(indexRelation, NoLock);
-				continue;
+				case RELKIND_PARTITIONED_INDEX:
+					index_close(indexRelation, NoLock);
+					continue;
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+				case RELKIND_NULL:
+				default:
+					break;
 			}
 
 			/*
@@ -442,15 +455,26 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 	rel->statlist = get_relation_statistics(rel, relation);
 
 	/* Grab foreign-table info using the relcache, while we have it */
-	if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
-		rel->serverid = GetForeignServerIdByRelId(RelationGetRelid(relation));
-		rel->fdwroutine = GetFdwRoutineForRelation(relation, true);
-	}
-	else
-	{
-		rel->serverid = InvalidOid;
-		rel->fdwroutine = NULL;
+		case RELKIND_FOREIGN_TABLE:
+			rel->serverid = GetForeignServerIdByRelId(RelationGetRelid(relation));
+			rel->fdwroutine = GetFdwRoutineForRelation(relation, true);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			rel->serverid = InvalidOid;
+			rel->fdwroutine = NULL;
+			break;
 	}
 
 	/* Collect info about relation's foreign keys, if relevant */
@@ -460,8 +484,25 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 	 * Collect info about relation's partitioning scheme, if any. Only
 	 * inheritance parents may be partitioned.
 	 */
-	if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		set_relation_partition_info(root, rel, relation);
+	switch ((RelKind) relation->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			if (inhparent)
+				set_relation_partition_info(root, rel, relation);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	table_close(relation, NoLock);
 
@@ -955,7 +996,7 @@ estimate_rel_size(Relation rel, int32 *attr_widths,
 	BlockNumber relallvisible;
 	double		density;
 
-	switch (rel->rd_rel->relkind)
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_MATVIEW:
@@ -1063,6 +1104,11 @@ estimate_rel_size(Relation rel, int32 *attr_widths,
 			*tuples = rel->rd_rel->reltuples;
 			*allvisfrac = 0;
 			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
 		default:
 			/* else it has no disk storage; probably shouldn't get here? */
 			*pages = 0;
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 25abc544fc..011f9829a9 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -944,37 +944,59 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
 
 	relation = relation_openrv(table_like_clause->relation, AccessShareLock);
 
-	if (relation->rd_rel->relkind != RELKIND_RELATION &&
-		relation->rd_rel->relkind != RELKIND_VIEW &&
-		relation->rd_rel->relkind != RELKIND_MATVIEW &&
-		relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
-		relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
-		relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
-						RelationGetRelationName(relation))));
+	switch ((RelKind) relation->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_INDEX:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
+							RelationGetRelationName(relation))));
+			break;
+	}
 
 	cancel_parser_errposition_callback(&pcbstate);
 
 	/*
 	 * Check for privileges
 	 */
-	if (relation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-	{
-		aclresult = pg_type_aclcheck(relation->rd_rel->reltype, GetUserId(),
-									 ACL_USAGE);
-		if (aclresult != ACLCHECK_OK)
-			aclcheck_error(aclresult, OBJECT_TYPE,
-						   RelationGetRelationName(relation));
-	}
-	else
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
-		aclresult = pg_class_aclcheck(RelationGetRelid(relation), GetUserId(),
-									  ACL_SELECT);
-		if (aclresult != ACLCHECK_OK)
-			aclcheck_error(aclresult, get_relkind_objtype(relation->rd_rel->relkind),
-						   RelationGetRelationName(relation));
+		case RELKIND_COMPOSITE_TYPE:
+			aclresult = pg_type_aclcheck(relation->rd_rel->reltype, GetUserId(),
+										 ACL_USAGE);
+			if (aclresult != ACLCHECK_OK)
+				aclcheck_error(aclresult, OBJECT_TYPE,
+							   RelationGetRelationName(relation));
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			aclresult = pg_class_aclcheck(RelationGetRelid(relation), GetUserId(),
+										  ACL_SELECT);
+			if (aclresult != ACLCHECK_OK)
+				aclcheck_error(aclresult, get_relkind_objtype(relation->rd_rel->relkind),
+							   RelationGetRelationName(relation));
+			break;
 	}
 
 	tupleDesc = RelationGetDescr(relation);
@@ -2306,13 +2328,27 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
 
 					rel = table_openrv(inh, AccessShareLock);
 					/* check user requested inheritance from valid relkind */
-					if (rel->rd_rel->relkind != RELKIND_RELATION &&
-						rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
-						rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-						ereport(ERROR,
-								(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-								 errmsg("inherited relation \"%s\" is not a table or foreign table",
-										inh->relname)));
+					switch ((RelKind) rel->rd_rel->relkind)
+					{
+						case RELKIND_RELATION:
+						case RELKIND_FOREIGN_TABLE:
+						case RELKIND_PARTITIONED_TABLE:
+							break;
+						case RELKIND_PARTITIONED_INDEX:
+						case RELKIND_SEQUENCE:
+						case RELKIND_COMPOSITE_TYPE:
+						case RELKIND_INDEX:
+						case RELKIND_MATVIEW:
+						case RELKIND_TOASTVALUE:
+						case RELKIND_VIEW:
+						case RELKIND_NULL:
+						default:
+							ereport(ERROR,
+									(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+									 errmsg("inherited relation \"%s\" is not a table or foreign table",
+											inh->relname)));
+							break;
+					}
 					for (count = 0; count < rel->rd_att->natts; count++)
 					{
 						Form_pg_attribute inhattr = TupleDescAttr(rel->rd_att,
@@ -2448,13 +2484,27 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
 
 					rel = table_openrv(inh, AccessShareLock);
 					/* check user requested inheritance from valid relkind */
-					if (rel->rd_rel->relkind != RELKIND_RELATION &&
-						rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
-						rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-						ereport(ERROR,
-								(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-								 errmsg("inherited relation \"%s\" is not a table or foreign table",
-										inh->relname)));
+					switch ((RelKind) rel->rd_rel->relkind)
+					{
+						case RELKIND_RELATION:
+						case RELKIND_FOREIGN_TABLE:
+						case RELKIND_PARTITIONED_TABLE:
+							break;
+						case RELKIND_PARTITIONED_INDEX:
+						case RELKIND_SEQUENCE:
+						case RELKIND_COMPOSITE_TYPE:
+						case RELKIND_INDEX:
+						case RELKIND_MATVIEW:
+						case RELKIND_TOASTVALUE:
+						case RELKIND_VIEW:
+						case RELKIND_NULL:
+						default:
+							ereport(ERROR,
+									(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+									 errmsg("inherited relation \"%s\" is not a table or foreign table",
+											inh->relname)));
+							break;
+					}
 					for (count = 0; count < rel->rd_att->natts; count++)
 					{
 						Form_pg_attribute inhattr = TupleDescAttr(rel->rd_att,
@@ -2763,10 +2813,27 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
 	 */
 	rel = table_openrv(stmt->relation, AccessExclusiveLock);
 
-	if (rel->rd_rel->relkind == RELKIND_MATVIEW)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("rules on materialized views are not supported")));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_MATVIEW:
+			ereport(ERROR,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("rules on materialized views are not supported")));
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
+
 
 	/* Set up pstate */
 	pstate = make_parsestate(NULL);
@@ -3097,15 +3164,26 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
 
 	/* Set up CreateStmtContext */
 	cxt.pstate = pstate;
-	if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		cxt.stmtType = "ALTER FOREIGN TABLE";
-		cxt.isforeign = true;
-	}
-	else
-	{
-		cxt.stmtType = "ALTER TABLE";
-		cxt.isforeign = false;
+		case RELKIND_FOREIGN_TABLE:
+			cxt.stmtType = "ALTER FOREIGN TABLE";
+			cxt.isforeign = true;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			cxt.stmtType = "ALTER TABLE";
+			cxt.isforeign = false;
+			break;
 	}
 	cxt.relation = stmt->relation;
 	cxt.rel = rel;
@@ -3722,7 +3800,7 @@ transformPartitionCmd(CreateStmtContext *cxt, PartitionCmd *cmd)
 {
 	Relation	parentRel = cxt->rel;
 
-	switch (parentRel->rd_rel->relkind)
+	switch ((RelKind) parentRel->rd_rel->relkind)
 	{
 		case RELKIND_PARTITIONED_TABLE:
 			/* transform the partition bound, if any */
@@ -3757,6 +3835,13 @@ transformPartitionCmd(CreateStmtContext *cxt, PartitionCmd *cmd)
 					 errmsg("index \"%s\" is not partitioned",
 							RelationGetRelationName(parentRel))));
 			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
 		default:
 			/* parser shouldn't let this case through */
 			elog(ERROR, "\"%s\" is not a partitioned table or index",
diff --git a/src/backend/partitioning/partbounds.c b/src/backend/partitioning/partbounds.c
index 7553d55987..c872ab1825 100644
--- a/src/backend/partitioning/partbounds.c
+++ b/src/backend/partitioning/partbounds.c
@@ -3137,11 +3137,26 @@ check_default_partition_contents(Relation parent, Relation default_rel,
 	 * Scan the default partition and its subpartitions, and check for rows
 	 * that do not satisfy the revised partition constraints.
 	 */
-	if (default_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		all_parts = find_all_inheritors(RelationGetRelid(default_rel),
-										AccessExclusiveLock, NULL);
-	else
-		all_parts = list_make1_oid(RelationGetRelid(default_rel));
+	switch ((RelKind) default_rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			all_parts = find_all_inheritors(RelationGetRelid(default_rel),
+											AccessExclusiveLock, NULL);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			all_parts = list_make1_oid(RelationGetRelid(default_rel));
+			break;
+	}
 
 	foreach(lc, all_parts)
 	{
@@ -3196,19 +3211,30 @@ check_default_partition_contents(Relation parent, Relation default_rel,
 		 * Only RELKIND_RELATION relations (i.e. leaf partitions) need to be
 		 * scanned.
 		 */
-		if (part_rel->rd_rel->relkind != RELKIND_RELATION)
+		switch ((RelKind) part_rel->rd_rel->relkind)
 		{
-			if (part_rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+			case RELKIND_RELATION:
+				break;
+			case RELKIND_FOREIGN_TABLE:
 				ereport(WARNING,
 						(errcode(ERRCODE_CHECK_VIOLATION),
 						 errmsg("skipped scanning foreign table \"%s\" which is a partition of default partition \"%s\"",
 								RelationGetRelationName(part_rel),
 								RelationGetRelationName(default_rel))));
-
-			if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
-				table_close(part_rel, NoLock);
-
-			continue;
+				/* fallthrough */
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
+					table_close(part_rel, NoLock);
+				continue;
 		}
 
 		estate = CreateExecutorState();
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 9c7d4b0c60..9b43c68ed6 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -2058,9 +2058,23 @@ do_autovacuum(void)
 		bool		doanalyze;
 		bool		wraparound;
 
-		if (classForm->relkind != RELKIND_RELATION &&
-			classForm->relkind != RELKIND_MATVIEW)
-			continue;
+		switch ((RelKind) classForm->relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_MATVIEW:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				continue;
+		}
 
 		relid = classForm->oid;
 
@@ -2720,9 +2734,24 @@ extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
 	bytea	   *relopts;
 	AutoVacOpts *av;
 
-	Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
-		   ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
-		   ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
+	switch ((RelKind) ((Form_pg_class) GETSTRUCT(tup))->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			Assert(false);
+			break;
+	}
 
 	relopts = extractRelOptions(tup, pg_class_desc, NULL);
 	if (relopts == NULL)
@@ -2800,17 +2829,34 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
 	 * main table reloptions if the toast table itself doesn't have.
 	 */
 	avopts = extract_autovac_opts(classTup, pg_class_desc);
-	if (classForm->relkind == RELKIND_TOASTVALUE &&
-		avopts == NULL && table_toast_map != NULL)
+	switch ((RelKind) classForm->relkind)
 	{
-		av_relation *hentry;
-		bool		found;
+		case RELKIND_TOASTVALUE:
+			if (avopts == NULL && table_toast_map != NULL)
+			{
+				av_relation *hentry;
+				bool		found;
 
-		hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
-		if (found && hentry->ar_hasrelopts)
-			avopts = &hentry->ar_reloptions;
+				hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
+				if (found && hentry->ar_hasrelopts)
+					avopts = &hentry->ar_reloptions;
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
+
 	/* fetch the pgstat table entry */
 	tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
 										 shared, dbentry);
@@ -2820,8 +2866,24 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
 							  &dovacuum, &doanalyze, &wraparound);
 
 	/* ignore ANALYZE for toast tables */
-	if (classForm->relkind == RELKIND_TOASTVALUE)
-		doanalyze = false;
+	switch ((RelKind) classForm->relkind)
+	{
+		case RELKIND_TOASTVALUE:
+			doanalyze = false;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	/* OK, it needs something done */
 	if (doanalyze || dovacuum)
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 096b0fcef0..fc9321c1ae 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -414,7 +414,7 @@ perform_base_backup(basebackup_options *opt)
 			if (ti->path == NULL)
 			{
 				struct stat statbuf;
-				bool	sendtblspclinks = true;
+				bool		sendtblspclinks = true;
 
 				/* In the main tar, include the backup_label first... */
 				sendFileWithContent(BACKUP_LABEL_FILE, labelfile->data,
@@ -1777,8 +1777,8 @@ sendFile(const char *readfilename, const char *tarfilename,
 	}
 
 	/*
-	 * Pad to a block boundary, per tar format requirements. (This small
-	 * piece of data is probably not worth throttling, and is not checksummed
+	 * Pad to a block boundary, per tar format requirements. (This small piece
+	 * of data is probably not worth throttling, and is not checksummed
 	 * because it's not actually part of the file.)
 	 */
 	pad = tarPaddingBytesRequired(len);
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index 642a1c767f..08310078c5 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -1643,8 +1643,23 @@ ReorderBufferCommit(ReorderBuffer *rb, TransactionId xid,
 					 * understand, so it doesn't make sense to handle the few
 					 * cases we do.
 					 */
-					if (relation->rd_rel->relkind == RELKIND_SEQUENCE)
-						goto change_done;
+					switch ((RelKind) relation->rd_rel->relkind)
+					{
+						case RELKIND_SEQUENCE:
+							goto change_done;
+						case RELKIND_PARTITIONED_INDEX:
+						case RELKIND_COMPOSITE_TYPE:
+						case RELKIND_FOREIGN_TABLE:
+						case RELKIND_INDEX:
+						case RELKIND_MATVIEW:
+						case RELKIND_PARTITIONED_TABLE:
+						case RELKIND_RELATION:
+						case RELKIND_TOASTVALUE:
+						case RELKIND_VIEW:
+						case RELKIND_NULL:
+						default:
+							break;
+					}
 
 					/* user-triggered change */
 					if (!IsToastRelation(relation))
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index c27d970589..f0419386d9 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -765,24 +765,38 @@ copy_table(Relation rel)
 
 	/* Start copy on the publisher. */
 	initStringInfo(&cmd);
-	if (lrel.relkind == RELKIND_RELATION)
-		appendStringInfo(&cmd, "COPY %s TO STDOUT",
-						 quote_qualified_identifier(lrel.nspname, lrel.relname));
-	else
+	switch ((RelKind) lrel.relkind)
 	{
-		/*
-		 * For non-tables, we need to do COPY (SELECT ...), but we can't just
-		 * do SELECT * because we need to not copy generated columns.
-		 */
-		appendStringInfo(&cmd, "COPY (SELECT ");
-		for (int i = 0; i < lrel.natts; i++)
-		{
-			appendStringInfoString(&cmd, quote_identifier(lrel.attnames[i]));
-			if (i < lrel.natts - 1)
-				appendStringInfoString(&cmd, ", ");
-		}
-		appendStringInfo(&cmd, " FROM %s) TO STDOUT",
-						 quote_qualified_identifier(lrel.nspname, lrel.relname));
+		case RELKIND_RELATION:
+			appendStringInfo(&cmd, "COPY %s TO STDOUT",
+							 quote_qualified_identifier(lrel.nspname, lrel.relname));
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+
+			/*
+			 * For non-tables, we need to do COPY (SELECT ...), but we can't
+			 * just do SELECT * because we need to not copy generated columns.
+			 */
+			appendStringInfo(&cmd, "COPY (SELECT ");
+			for (int i = 0; i < lrel.natts; i++)
+			{
+				appendStringInfoString(&cmd, quote_identifier(lrel.attnames[i]));
+				if (i < lrel.natts - 1)
+					appendStringInfoString(&cmd, ", ");
+			}
+			appendStringInfo(&cmd, " FROM %s) TO STDOUT",
+							 quote_qualified_identifier(lrel.nspname, lrel.relname));
+			break;
 	}
 	res = walrcv_exec(wrconn, cmd.data, 0, NULL);
 	pfree(cmd.data);
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index a752a1224d..bc047c0b1e 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -646,12 +646,27 @@ apply_handle_insert(StringInfo s)
 	MemoryContextSwitchTo(oldctx);
 
 	/* For a partitioned table, insert the tuple into a partition. */
-	if (rel->localrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		apply_handle_tuple_routing(estate->es_result_relation_info, estate,
-								   remoteslot, NULL, rel, CMD_INSERT);
-	else
-		apply_handle_insert_internal(estate->es_result_relation_info, estate,
-									 remoteslot);
+	switch ((RelKind) rel->localrel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			apply_handle_tuple_routing(estate->es_result_relation_info, estate,
+									   remoteslot, NULL, rel, CMD_INSERT);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			apply_handle_insert_internal(estate->es_result_relation_info, estate,
+										 remoteslot);
+			break;
+	}
 
 	PopActiveSnapshot();
 
@@ -781,12 +796,27 @@ apply_handle_update(StringInfo s)
 	MemoryContextSwitchTo(oldctx);
 
 	/* For a partitioned table, apply update to correct partition. */
-	if (rel->localrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		apply_handle_tuple_routing(estate->es_result_relation_info, estate,
-								   remoteslot, &newtup, rel, CMD_UPDATE);
-	else
-		apply_handle_update_internal(estate->es_result_relation_info, estate,
-									 remoteslot, &newtup, rel);
+	switch ((RelKind) rel->localrel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			apply_handle_tuple_routing(estate->es_result_relation_info, estate,
+									   remoteslot, &newtup, rel, CMD_UPDATE);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			apply_handle_update_internal(estate->es_result_relation_info, estate,
+										 remoteslot, &newtup, rel);
+			break;
+	}
 
 	PopActiveSnapshot();
 
@@ -904,12 +934,27 @@ apply_handle_delete(StringInfo s)
 	MemoryContextSwitchTo(oldctx);
 
 	/* For a partitioned table, apply delete to correct partition. */
-	if (rel->localrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		apply_handle_tuple_routing(estate->es_result_relation_info, estate,
-								   remoteslot, NULL, rel, CMD_DELETE);
-	else
-		apply_handle_delete_internal(estate->es_result_relation_info, estate,
-									 remoteslot, &rel->remoterel);
+	switch ((RelKind) rel->localrel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			apply_handle_tuple_routing(estate->es_result_relation_info, estate,
+									   remoteslot, NULL, rel, CMD_DELETE);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			apply_handle_delete_internal(estate->es_result_relation_info, estate,
+										 remoteslot, &rel->remoterel);
+			break;
+	}
 
 	PopActiveSnapshot();
 
@@ -1273,41 +1318,61 @@ apply_handle_truncate(StringInfo s)
 		 * Truncate partitions if we got a message to truncate a partitioned
 		 * table.
 		 */
-		if (rel->localrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		switch ((RelKind) rel->localrel->rd_rel->relkind)
 		{
-			ListCell   *child;
-			List	   *children = find_all_inheritors(rel->localreloid,
-													   RowExclusiveLock,
-													   NULL);
-
-			foreach(child, children)
-			{
-				Oid			childrelid = lfirst_oid(child);
-				Relation	childrel;
-
-				if (list_member_oid(relids, childrelid))
-					continue;
-
-				/* find_all_inheritors already got lock */
-				childrel = table_open(childrelid, NoLock);
-
-				/*
-				 * Ignore temp tables of other backends.  See similar code in
-				 * ExecuteTruncate().
-				 */
-				if (RELATION_IS_OTHER_TEMP(childrel))
+			case RELKIND_PARTITIONED_TABLE:
 				{
-					table_close(childrel, RowExclusiveLock);
-					continue;
-				}
+					ListCell   *child;
+					List	   *children = find_all_inheritors(rel->localreloid,
+															   RowExclusiveLock,
+															   NULL);
 
-				rels = lappend(rels, childrel);
-				part_rels = lappend(part_rels, childrel);
-				relids = lappend_oid(relids, childrelid);
-				/* Log this relation only if needed for logical decoding */
-				if (RelationIsLogicallyLogged(childrel))
-					relids_logged = lappend_oid(relids_logged, childrelid);
-			}
+					foreach(child, children)
+					{
+						Oid			childrelid = lfirst_oid(child);
+						Relation	childrel;
+
+						if (list_member_oid(relids, childrelid))
+							continue;
+
+						/* find_all_inheritors already got lock */
+						childrel = table_open(childrelid, NoLock);
+
+						/*
+						 * Ignore temp tables of other backends.  See similar
+						 * code in ExecuteTruncate().
+						 */
+						if (RELATION_IS_OTHER_TEMP(childrel))
+						{
+							table_close(childrel, RowExclusiveLock);
+							continue;
+						}
+
+						rels = lappend(rels, childrel);
+						part_rels = lappend(part_rels, childrel);
+						relids = lappend_oid(relids, childrelid);
+
+						/*
+						 * Log this relation only if needed for logical
+						 * decoding
+						 */
+						if (RelationIsLogicallyLogged(childrel))
+							relids_logged = lappend_oid(relids_logged, childrelid);
+					}
+				}
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				break;
 		}
 	}
 
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 57bbb6288c..54ae4af52b 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -100,8 +100,8 @@ int			max_replication_slots = 0;	/* the maximum number of replication
 										 * slots */
 
 static ReplicationSlot *SearchNamedReplicationSlot(const char *name);
-static int ReplicationSlotAcquireInternal(ReplicationSlot *slot,
-										  const char *name, SlotAcquireBehavior behavior);
+static int	ReplicationSlotAcquireInternal(ReplicationSlot *slot,
+										   const char *name, SlotAcquireBehavior behavior);
 static void ReplicationSlotDropAcquired(void);
 static void ReplicationSlotDropPtr(ReplicationSlot *slot);
 
@@ -335,7 +335,7 @@ static ReplicationSlot *
 SearchNamedReplicationSlot(const char *name)
 {
 	int			i;
-	ReplicationSlot	*slot = NULL;
+	ReplicationSlot *slot = NULL;
 
 	Assert(LWLockHeldByMeInMode(ReplicationSlotControlLock,
 								LW_SHARED));
@@ -434,8 +434,8 @@ retry:
 
 	/*
 	 * If we found the slot but it's already active in another process, we
-	 * either error out, return the PID of the owning process, or retry
-	 * after a short wait, as caller specified.
+	 * either error out, return the PID of the owning process, or retry after
+	 * a short wait, as caller specified.
 	 */
 	if (active_pid != MyProcPid)
 	{
@@ -454,7 +454,7 @@ retry:
 		goto retry;
 	}
 	else if (behavior == SAB_Block)
-		ConditionVariableCancelSleep();	/* no sleep needed after all */
+		ConditionVariableCancelSleep(); /* no sleep needed after all */
 
 	/* Let everybody know we've modified this slot */
 	ConditionVariableBroadcast(&s->active_cv);
@@ -1143,8 +1143,8 @@ restart:
 		ReplicationSlot *s = &ReplicationSlotCtl->replication_slots[i];
 		XLogRecPtr	restart_lsn = InvalidXLogRecPtr;
 		NameData	slotname;
-		int		wspid;
-		int		last_signaled_pid = 0;
+		int			wspid;
+		int			last_signaled_pid = 0;
 
 		if (!s->in_use)
 			continue;
@@ -1167,20 +1167,20 @@ restart:
 			/*
 			 * Try to mark this slot as used by this process.
 			 *
-			 * Note that ReplicationSlotAcquireInternal(SAB_Inquire)
-			 * should not cancel the prepared condition variable
-			 * if this slot is active in other process. Because in this case
-			 * we have to wait on that CV for the process owning
-			 * the slot to be terminated, later.
+			 * Note that ReplicationSlotAcquireInternal(SAB_Inquire) should
+			 * not cancel the prepared condition variable if this slot is
+			 * active in other process. Because in this case we have to wait
+			 * on that CV for the process owning the slot to be terminated,
+			 * later.
 			 */
 			wspid = ReplicationSlotAcquireInternal(s, NULL, SAB_Inquire);
 
 			/*
-			 * Exit the loop if we successfully acquired the slot or
-			 * the slot was dropped during waiting for the owning process
-			 * to be terminated. For example, the latter case is likely to
-			 * happen when the slot is temporary because it's automatically
-			 * dropped by the termination of the owning process.
+			 * Exit the loop if we successfully acquired the slot or the slot
+			 * was dropped during waiting for the owning process to be
+			 * terminated. For example, the latter case is likely to happen
+			 * when the slot is temporary because it's automatically dropped
+			 * by the termination of the owning process.
 			 */
 			if (wspid <= 0)
 				break;
@@ -1188,13 +1188,13 @@ restart:
 			/*
 			 * Signal to terminate the process that owns the slot.
 			 *
-			 * There is the race condition where other process may own
-			 * the slot after the process using it was terminated and before
-			 * this process owns it. To handle this case, we signal again
-			 * if the PID of the owning process is changed than the last.
+			 * There is the race condition where other process may own the
+			 * slot after the process using it was terminated and before this
+			 * process owns it. To handle this case, we signal again if the
+			 * PID of the owning process is changed than the last.
 			 *
-			 * XXX This logic assumes that the same PID is not reused
-			 * very quickly.
+			 * XXX This logic assumes that the same PID is not reused very
+			 * quickly.
 			 */
 			if (last_signaled_pid != wspid)
 			{
@@ -1211,8 +1211,8 @@ restart:
 		ConditionVariableCancelSleep();
 
 		/*
-		 * Do nothing here and start from scratch if the slot has
-		 * already been dropped.
+		 * Do nothing here and start from scratch if the slot has already been
+		 * dropped.
 		 */
 		if (wspid == -1)
 			goto restart;
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 9989df1107..93cde08936 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -262,14 +262,27 @@ DefineQueryRewrite(const char *rulename,
 	 * Internal callers can target materialized views, but transformRuleStmt()
 	 * blocks them for users.  Don't mention them in the error message.
 	 */
-	if (event_relation->rd_rel->relkind != RELKIND_RELATION &&
-		event_relation->rd_rel->relkind != RELKIND_MATVIEW &&
-		event_relation->rd_rel->relkind != RELKIND_VIEW &&
-		event_relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table or view",
-						RelationGetRelationName(event_relation))));
+	switch ((RelKind) event_relation->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table or view",
+							RelationGetRelationName(event_relation))));
+			break;
+	}
 
 	if (!allowSystemTableMods && IsSystemRelation(event_relation))
 		ereport(ERROR,
@@ -421,69 +434,83 @@ DefineQueryRewrite(const char *rulename,
 		 * views is just a kluge to allow dump/reload of views that
 		 * participate in circular dependencies.)
 		 */
-		if (event_relation->rd_rel->relkind != RELKIND_VIEW &&
-			event_relation->rd_rel->relkind != RELKIND_MATVIEW)
+		switch ((RelKind) event_relation->rd_rel->relkind)
 		{
-			TableScanDesc scanDesc;
-			Snapshot	snapshot;
-			TupleTableSlot *slot;
-
-			if (event_relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+			case RELKIND_VIEW:
+			case RELKIND_MATVIEW:
+				break;
+			case RELKIND_PARTITIONED_TABLE:
 				ereport(ERROR,
 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 						 errmsg("cannot convert partitioned table \"%s\" to a view",
 								RelationGetRelationName(event_relation))));
-
-			if (event_relation->rd_rel->relispartition)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("cannot convert partition \"%s\" to a view",
-								RelationGetRelationName(event_relation))));
-
-			snapshot = RegisterSnapshot(GetLatestSnapshot());
-			scanDesc = table_beginscan(event_relation, snapshot, 0, NULL);
-			slot = table_slot_create(event_relation, NULL);
-			if (table_scan_getnextslot(scanDesc, ForwardScanDirection, slot))
-				ereport(ERROR,
-						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-						 errmsg("could not convert table \"%s\" to a view because it is not empty",
-								RelationGetRelationName(event_relation))));
-			ExecDropSingleTupleTableSlot(slot);
-			table_endscan(scanDesc);
-			UnregisterSnapshot(snapshot);
-
-			if (event_relation->rd_rel->relhastriggers)
-				ereport(ERROR,
-						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-						 errmsg("could not convert table \"%s\" to a view because it has triggers",
-								RelationGetRelationName(event_relation)),
-						 errhint("In particular, the table cannot be involved in any foreign key relationships.")));
-
-			if (event_relation->rd_rel->relhasindex)
-				ereport(ERROR,
-						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-						 errmsg("could not convert table \"%s\" to a view because it has indexes",
-								RelationGetRelationName(event_relation))));
-
-			if (event_relation->rd_rel->relhassubclass)
-				ereport(ERROR,
-						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-						 errmsg("could not convert table \"%s\" to a view because it has child tables",
-								RelationGetRelationName(event_relation))));
-
-			if (event_relation->rd_rel->relrowsecurity)
-				ereport(ERROR,
-						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-						 errmsg("could not convert table \"%s\" to a view because it has row security enabled",
-								RelationGetRelationName(event_relation))));
-
-			if (relation_has_policies(event_relation))
-				ereport(ERROR,
-						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-						 errmsg("could not convert table \"%s\" to a view because it has row security policies",
-								RelationGetRelationName(event_relation))));
-
-			RelisBecomingView = true;
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				{
+					TableScanDesc scanDesc;
+					Snapshot	snapshot;
+					TupleTableSlot *slot;
+
+					if (event_relation->rd_rel->relispartition)
+						ereport(ERROR,
+								(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+								 errmsg("cannot convert partition \"%s\" to a view",
+										RelationGetRelationName(event_relation))));
+
+					snapshot = RegisterSnapshot(GetLatestSnapshot());
+					scanDesc = table_beginscan(event_relation, snapshot, 0, NULL);
+					slot = table_slot_create(event_relation, NULL);
+					if (table_scan_getnextslot(scanDesc, ForwardScanDirection, slot))
+						ereport(ERROR,
+								(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+								 errmsg("could not convert table \"%s\" to a view because it is not empty",
+										RelationGetRelationName(event_relation))));
+					ExecDropSingleTupleTableSlot(slot);
+					table_endscan(scanDesc);
+					UnregisterSnapshot(snapshot);
+
+					if (event_relation->rd_rel->relhastriggers)
+						ereport(ERROR,
+								(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+								 errmsg("could not convert table \"%s\" to a view because it has triggers",
+										RelationGetRelationName(event_relation)),
+								 errhint("In particular, the table cannot be involved in any foreign key relationships.")));
+
+					if (event_relation->rd_rel->relhasindex)
+						ereport(ERROR,
+								(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+								 errmsg("could not convert table \"%s\" to a view because it has indexes",
+										RelationGetRelationName(event_relation))));
+
+					if (event_relation->rd_rel->relhassubclass)
+						ereport(ERROR,
+								(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+								 errmsg("could not convert table \"%s\" to a view because it has child tables",
+										RelationGetRelationName(event_relation))));
+
+					if (event_relation->rd_rel->relrowsecurity)
+						ereport(ERROR,
+								(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+								 errmsg("could not convert table \"%s\" to a view because it has row security enabled",
+										RelationGetRelationName(event_relation))));
+
+					if (relation_has_policies(event_relation))
+						ereport(ERROR,
+								(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+								 errmsg("could not convert table \"%s\" to a view because it has row security policies",
+										RelationGetRelationName(event_relation))));
+
+					RelisBecomingView = true;
+				}
+				break;
 		}
 	}
 	else
@@ -920,12 +947,26 @@ RangeVarCallbackForRenameRule(const RangeVar *rv, Oid relid, Oid oldrelid,
 	form = (Form_pg_class) GETSTRUCT(tuple);
 
 	/* only tables and views can have rules */
-	if (form->relkind != RELKIND_RELATION &&
-		form->relkind != RELKIND_VIEW &&
-		form->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table or view", rv->relname)));
+	switch ((RelKind) form->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table or view", rv->relname)));
+			break;
+	}
 
 	if (!allowSystemTableMods && IsSystemClass(relid, form))
 		ereport(ERROR,
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index fe777c3103..76c0b40b79 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -902,25 +902,42 @@ rewriteTargetListIU(List *targetList,
 		 * For an UPDATE on a trigger-updatable view, provide a dummy entry
 		 * whenever there is no explicit assignment.
 		 */
-		if (new_tle == NULL && commandType == CMD_UPDATE &&
-			target_relation->rd_rel->relkind == RELKIND_VIEW &&
-			view_has_instead_trigger(target_relation, CMD_UPDATE))
+		switch ((RelKind) target_relation->rd_rel->relkind)
 		{
-			Node	   *new_expr;
-
-			new_expr = (Node *) makeVar(result_rti,
-										attrno,
-										att_tup->atttypid,
-										att_tup->atttypmod,
-										att_tup->attcollation,
-										0);
+			case RELKIND_VIEW:
+				if (new_tle == NULL && commandType == CMD_UPDATE &&
+					view_has_instead_trigger(target_relation, CMD_UPDATE))
+				{
+					Node	   *new_expr;
 
-			new_tle = makeTargetEntry((Expr *) new_expr,
-									  attrno,
-									  pstrdup(NameStr(att_tup->attname)),
-									  false);
+					new_expr = (Node *) makeVar(result_rti,
+												attrno,
+												att_tup->atttypid,
+												att_tup->atttypmod,
+												att_tup->attcollation,
+												0);
+
+					new_tle = makeTargetEntry((Expr *) new_expr,
+											  attrno,
+											  pstrdup(NameStr(att_tup->attname)),
+											  false);
+				}
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				break;
 		}
 
+
 		if (new_tle)
 			new_tlist = lappend(new_tlist, new_tle);
 	}
@@ -1316,39 +1333,54 @@ rewriteValuesRTE(Query *parsetree, RangeTblEntry *rte, int rti,
 	 * skip this check in that case --- it isn't an auto-updatable view.
 	 */
 	isAutoUpdatableView = false;
-	if (!force_nulls &&
-		target_relation->rd_rel->relkind == RELKIND_VIEW &&
-		!view_has_instead_trigger(target_relation, CMD_INSERT))
+	switch ((RelKind) target_relation->rd_rel->relkind)
 	{
-		List	   *locks;
-		bool		hasUpdate;
-		bool		found;
-		ListCell   *l;
+		case RELKIND_VIEW:
+			if (!force_nulls && !view_has_instead_trigger(target_relation, CMD_INSERT))
+			{
+				List	   *locks;
+				bool		hasUpdate;
+				bool		found;
+				ListCell   *l;
 
-		/* Look for an unconditional DO INSTEAD rule */
-		locks = matchLocks(CMD_INSERT, target_relation->rd_rules,
-						   parsetree->resultRelation, parsetree, &hasUpdate);
+				/* Look for an unconditional DO INSTEAD rule */
+				locks = matchLocks(CMD_INSERT, target_relation->rd_rules,
+								   parsetree->resultRelation, parsetree, &hasUpdate);
 
-		found = false;
-		foreach(l, locks)
-		{
-			RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
+				found = false;
+				foreach(l, locks)
+				{
+					RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
 
-			if (rule_lock->isInstead &&
-				rule_lock->qual == NULL)
-			{
-				found = true;
-				break;
-			}
-		}
+					if (rule_lock->isInstead &&
+						rule_lock->qual == NULL)
+					{
+						found = true;
+						break;
+					}
+				}
 
-		/*
-		 * If we didn't find an unconditional DO INSTEAD rule, assume that the
-		 * view is auto-updatable.  If it isn't, rewriteTargetView() will
-		 * throw an error.
-		 */
-		if (!found)
-			isAutoUpdatableView = true;
+				/*
+				 * If we didn't find an unconditional DO INSTEAD rule, assume
+				 * that the view is auto-updatable.  If it isn't,
+				 * rewriteTargetView() will throw an error.
+				 */
+				if (!found)
+					isAutoUpdatableView = true;
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	newValues = NIL;
@@ -1450,55 +1482,72 @@ rewriteTargetListUD(Query *parsetree, RangeTblEntry *target_rte,
 	const char *attrname;
 	TargetEntry *tle;
 
-	if (target_relation->rd_rel->relkind == RELKIND_RELATION ||
-		target_relation->rd_rel->relkind == RELKIND_MATVIEW ||
-		target_relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-	{
-		/*
-		 * Emit CTID so that executor can find the row to update or delete.
-		 */
-		var = makeVar(parsetree->resultRelation,
-					  SelfItemPointerAttributeNumber,
-					  TIDOID,
-					  -1,
-					  InvalidOid,
-					  0);
-
-		attrname = "ctid";
-	}
-	else if (target_relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+	switch ((RelKind) target_relation->rd_rel->relkind)
 	{
-		/*
-		 * Let the foreign table's FDW add whatever junk TLEs it wants.
-		 */
-		FdwRoutine *fdwroutine;
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+			{
+				/*
+				 * Emit CTID so that executor can find the row to update or
+				 * delete.
+				 */
+				var = makeVar(parsetree->resultRelation,
+							  SelfItemPointerAttributeNumber,
+							  TIDOID,
+							  -1,
+							  InvalidOid,
+							  0);
+
+				attrname = "ctid";
+			}
+			break;
+		case RELKIND_FOREIGN_TABLE:
+			{
+				/*
+				 * Let the foreign table's FDW add whatever junk TLEs it
+				 * wants.
+				 */
+				FdwRoutine *fdwroutine;
 
-		fdwroutine = GetFdwRoutineForRelation(target_relation, false);
+				fdwroutine = GetFdwRoutineForRelation(target_relation, false);
 
-		if (fdwroutine->AddForeignUpdateTargets != NULL)
-			fdwroutine->AddForeignUpdateTargets(parsetree, target_rte,
-												target_relation);
+				if (fdwroutine->AddForeignUpdateTargets != NULL)
+					fdwroutine->AddForeignUpdateTargets(parsetree, target_rte,
+														target_relation);
 
-		/*
-		 * If we have a row-level trigger corresponding to the operation, emit
-		 * a whole-row Var so that executor will have the "old" row to pass to
-		 * the trigger.  Alas, this misses system columns.
-		 */
-		if (target_relation->trigdesc &&
-			((parsetree->commandType == CMD_UPDATE &&
-			  (target_relation->trigdesc->trig_update_after_row ||
-			   target_relation->trigdesc->trig_update_before_row)) ||
-			 (parsetree->commandType == CMD_DELETE &&
-			  (target_relation->trigdesc->trig_delete_after_row ||
-			   target_relation->trigdesc->trig_delete_before_row))))
-		{
-			var = makeWholeRowVar(target_rte,
-								  parsetree->resultRelation,
-								  0,
-								  false);
+				/*
+				 * If we have a row-level trigger corresponding to the
+				 * operation, emit a whole-row Var so that executor will have
+				 * the "old" row to pass to the trigger.  Alas, this misses
+				 * system columns.
+				 */
+				if (target_relation->trigdesc &&
+					((parsetree->commandType == CMD_UPDATE &&
+					  (target_relation->trigdesc->trig_update_after_row ||
+					   target_relation->trigdesc->trig_update_before_row)) ||
+					 (parsetree->commandType == CMD_DELETE &&
+					  (target_relation->trigdesc->trig_delete_after_row ||
+					   target_relation->trigdesc->trig_delete_before_row))))
+				{
+					var = makeWholeRowVar(target_rte,
+										  parsetree->resultRelation,
+										  0,
+										  false);
 
-			attrname = "wholerow";
-		}
+					attrname = "wholerow";
+				}
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	if (var != NULL)
@@ -1909,8 +1958,23 @@ fireRIRrules(Query *parsetree, List *activeRIRs)
 		 * In that case this test would need to be postponed till after we've
 		 * opened the rel, so that we could check its state.
 		 */
-		if (rte->relkind == RELKIND_MATVIEW)
-			continue;
+		switch ((RelKind) rte->relkind)
+		{
+			case RELKIND_MATVIEW:
+				continue;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				break;
+		}
 
 		/*
 		 * In INSERT ... ON CONFLICT, ignore the EXCLUDED pseudo-relation;
@@ -2032,10 +2096,25 @@ fireRIRrules(Query *parsetree, List *activeRIRs)
 		++rt_index;
 
 		/* Only normal relations can have RLS policies */
-		if (rte->rtekind != RTE_RELATION ||
-			(rte->relkind != RELKIND_RELATION &&
-			 rte->relkind != RELKIND_PARTITIONED_TABLE))
+		if (rte->rtekind != RTE_RELATION)
 			continue;
+		switch ((RelKind) rte->relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_PARTITIONED_TABLE:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				continue;
+		}
 
 		rel = table_open(rte->relid, NoLock);
 
@@ -2498,12 +2577,25 @@ view_query_is_auto_updatable(Query *viewquery, bool check_cols)
 		return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
 
 	base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
-	if (base_rte->rtekind != RTE_RELATION ||
-		(base_rte->relkind != RELKIND_RELATION &&
-		 base_rte->relkind != RELKIND_FOREIGN_TABLE &&
-		 base_rte->relkind != RELKIND_VIEW &&
-		 base_rte->relkind != RELKIND_PARTITIONED_TABLE))
-		return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
+	switch ((RelKind) base_rte->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_PARTITIONED_TABLE:
+			if (base_rte->rtekind == RTE_RELATION)
+				break;
+			/* fallthrough */
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
+	}
 
 	if (base_rte->tablesample)
 		return gettext_noop("Views containing TABLESAMPLE are not automatically updatable.");
@@ -2677,11 +2769,23 @@ relation_is_updatable(Oid reloid,
 	}
 
 	/* If the relation is a table, it is always updatable */
-	if (rel->rd_rel->relkind == RELKIND_RELATION ||
-		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		relation_close(rel, AccessShareLock);
-		return ALL_EVENTS;
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			relation_close(rel, AccessShareLock);
+			return ALL_EVENTS;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	/* Look for unconditional DO INSTEAD rules, and note supported events */
@@ -2730,84 +2834,103 @@ relation_is_updatable(Oid reloid,
 		}
 	}
 
-	/* If this is a foreign table, check which update events it supports */
-	if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		FdwRoutine *fdwroutine = GetFdwRoutineForRelation(rel, false);
-
-		if (fdwroutine->IsForeignRelUpdatable != NULL)
-			events |= fdwroutine->IsForeignRelUpdatable(rel);
-		else
-		{
-			/* Assume presence of executor functions is sufficient */
-			if (fdwroutine->ExecForeignInsert != NULL)
-				events |= (1 << CMD_INSERT);
-			if (fdwroutine->ExecForeignUpdate != NULL)
-				events |= (1 << CMD_UPDATE);
-			if (fdwroutine->ExecForeignDelete != NULL)
-				events |= (1 << CMD_DELETE);
-		}
+			/*
+			 * If this is a foreign table, check which update events it
+			 * supports
+			 */
+		case RELKIND_FOREIGN_TABLE:
+			{
+				FdwRoutine *fdwroutine = GetFdwRoutineForRelation(rel, false);
 
-		relation_close(rel, AccessShareLock);
-		return events;
-	}
+				if (fdwroutine->IsForeignRelUpdatable != NULL)
+					events |= fdwroutine->IsForeignRelUpdatable(rel);
+				else
+				{
+					/* Assume presence of executor functions is sufficient */
+					if (fdwroutine->ExecForeignInsert != NULL)
+						events |= (1 << CMD_INSERT);
+					if (fdwroutine->ExecForeignUpdate != NULL)
+						events |= (1 << CMD_UPDATE);
+					if (fdwroutine->ExecForeignDelete != NULL)
+						events |= (1 << CMD_DELETE);
+				}
 
-	/* Check if this is an automatically updatable view */
-	if (rel->rd_rel->relkind == RELKIND_VIEW)
-	{
-		Query	   *viewquery = get_view_query(rel);
+				relation_close(rel, AccessShareLock);
+				return events;
+			}
+			break;
+			/* Check if this is an automatically updatable view */
+		case RELKIND_VIEW:
+			{
+				Query	   *viewquery = get_view_query(rel);
 
-		if (view_query_is_auto_updatable(viewquery, false) == NULL)
-		{
-			Bitmapset  *updatable_cols;
-			int			auto_events;
-			RangeTblRef *rtr;
-			RangeTblEntry *base_rte;
-			Oid			baseoid;
+				if (view_query_is_auto_updatable(viewquery, false) == NULL)
+				{
+					Bitmapset  *updatable_cols;
+					int			auto_events;
+					RangeTblRef *rtr;
+					RangeTblEntry *base_rte;
+					Oid			baseoid;
 
-			/*
-			 * Determine which of the view's columns are updatable. If there
-			 * are none within the set of columns we are looking at, then the
-			 * view doesn't support INSERT/UPDATE, but it may still support
-			 * DELETE.
-			 */
-			view_cols_are_auto_updatable(viewquery, NULL,
-										 &updatable_cols, NULL);
+					/*
+					 * Determine which of the view's columns are updatable. If
+					 * there are none within the set of columns we are looking
+					 * at, then the view doesn't support INSERT/UPDATE, but it
+					 * may still support DELETE.
+					 */
+					view_cols_are_auto_updatable(viewquery, NULL,
+												 &updatable_cols, NULL);
 
-			if (include_cols != NULL)
-				updatable_cols = bms_int_members(updatable_cols, include_cols);
+					if (include_cols != NULL)
+						updatable_cols = bms_int_members(updatable_cols, include_cols);
 
-			if (bms_is_empty(updatable_cols))
-				auto_events = (1 << CMD_DELETE);	/* May support DELETE */
-			else
-				auto_events = ALL_EVENTS;	/* May support all events */
+					if (bms_is_empty(updatable_cols))
+						auto_events = (1 << CMD_DELETE);	/* May support DELETE */
+					else
+						auto_events = ALL_EVENTS;	/* May support all events */
 
-			/*
-			 * The base relation must also support these update commands.
-			 * Tables are always updatable, but for any other kind of base
-			 * relation we must do a recursive check limited to the columns
-			 * referenced by the locally updatable columns in this view.
-			 */
-			rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
-			base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
-			Assert(base_rte->rtekind == RTE_RELATION);
+					/*
+					 * The base relation must also support these update
+					 * commands. Tables are always updatable, but for any
+					 * other kind of base relation we must do a recursive
+					 * check limited to the columns referenced by the locally
+					 * updatable columns in this view.
+					 */
+					rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
+					base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
+					Assert(base_rte->rtekind == RTE_RELATION);
 
-			if (base_rte->relkind != RELKIND_RELATION &&
-				base_rte->relkind != RELKIND_PARTITIONED_TABLE)
-			{
-				baseoid = base_rte->relid;
-				outer_reloids = lappend_oid(outer_reloids,
-											RelationGetRelid(rel));
-				include_cols = adjust_view_column_set(updatable_cols,
-													  viewquery->targetList);
-				auto_events &= relation_is_updatable(baseoid,
-													 outer_reloids,
-													 include_triggers,
-													 include_cols);
-				outer_reloids = list_delete_last(outer_reloids);
+					if (base_rte->relkind != RELKIND_RELATION &&
+						base_rte->relkind != RELKIND_PARTITIONED_TABLE)
+					{
+						baseoid = base_rte->relid;
+						outer_reloids = lappend_oid(outer_reloids,
+													RelationGetRelid(rel));
+						include_cols = adjust_view_column_set(updatable_cols,
+															  viewquery->targetList);
+						auto_events &= relation_is_updatable(baseoid,
+															 outer_reloids,
+															 include_triggers,
+															 include_cols);
+						outer_reloids = list_delete_last(outer_reloids);
+					}
+					events |= auto_events;
+				}
 			}
-			events |= auto_events;
-		}
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	/* If we reach here, the relation may support some update commands */
diff --git a/src/backend/rewrite/rowsecurity.c b/src/backend/rewrite/rowsecurity.c
index 0fe2f9ca83..2002cf9a20 100644
--- a/src/backend/rewrite/rowsecurity.c
+++ b/src/backend/rewrite/rowsecurity.c
@@ -123,9 +123,23 @@ get_row_security_policies(Query *root, RangeTblEntry *rte, int rt_index,
 	*hasSubLinks = false;
 
 	/* If this is not a normal relation, just return immediately */
-	if (rte->relkind != RELKIND_RELATION &&
-		rte->relkind != RELKIND_PARTITIONED_TABLE)
-		return;
+	switch ((RelKind) rte->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			return;
+	}
 
 	/* Switch to checkAsUser if it's set */
 	user_id = rte->checkAsUser ? rte->checkAsUser : GetUserId();
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 29c920800a..6eb28a2210 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -2819,7 +2819,7 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln)
 BlockNumber
 RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum)
 {
-	switch (relation->rd_rel->relkind)
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
 		case RELKIND_SEQUENCE:
 		case RELKIND_INDEX:
@@ -2846,12 +2846,17 @@ RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum)
 				return (szbytes + (BLCKSZ - 1)) / BLCKSZ;
 			}
 		case RELKIND_VIEW:
+			elog(FATAL, "RELKIND_VIEW in RelationGetNumberOfBlocksInFork");
 		case RELKIND_COMPOSITE_TYPE:
+			elog(FATAL, "RELKIND_COMPOSITE_TYPE in RelationGetNumberOfBlocksInFork");
 		case RELKIND_FOREIGN_TABLE:
+			elog(FATAL, "RELKIND_FOREIGN_TABLE in RelationGetNumberOfBlocksInFork");
 		case RELKIND_PARTITIONED_TABLE:
+			elog(FATAL, "RELKIND_PARTITIONED_TABLE in RelationGetNumberOfBlocksInFork");
+		case RELKIND_NULL:
 		default:
-			Assert(false);
-			break;
+			elog(FATAL, "Unexpected relkind %d in RelationGetNumberOfBlocksInFork",
+				 (int) relation->rd_rel->relkind);
 	}
 
 	return 0;					/* keep compiler quiet */
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index e57fcd2538..615670ff41 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -1236,8 +1236,8 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
 	/*
 	 * Set timer so we can wake up after awhile and check for a deadlock. If a
 	 * deadlock is detected, the handler sets MyProc->waitStatus =
-	 * PROC_WAIT_STATUS_ERROR, allowing us to know that we must report failure rather
-	 * than success.
+	 * PROC_WAIT_STATUS_ERROR, allowing us to know that we must report failure
+	 * rather than success.
 	 *
 	 * By delaying the check until we've waited for a bit, we can avoid
 	 * running the rather expensive deadlock-check code in most cases.
@@ -1302,9 +1302,9 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
 		}
 
 		/*
-		 * waitStatus could change from PROC_WAIT_STATUS_WAITING to something else
-		 * asynchronously.  Read it just once per loop to prevent surprising
-		 * behavior (such as missing log messages).
+		 * waitStatus could change from PROC_WAIT_STATUS_WAITING to something
+		 * else asynchronously.  Read it just once per loop to prevent
+		 * surprising behavior (such as missing log messages).
 		 */
 		myWaitStatus = *((volatile ProcWaitStatus *) &MyProc->waitStatus);
 
@@ -1504,11 +1504,12 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
 
 				/*
 				 * Currently, the deadlock checker always kicks its own
-				 * process, which means that we'll only see PROC_WAIT_STATUS_ERROR when
-				 * deadlock_state == DS_HARD_DEADLOCK, and there's no need to
-				 * print redundant messages.  But for completeness and
-				 * future-proofing, print a message if it looks like someone
-				 * else kicked us off the lock.
+				 * process, which means that we'll only see
+				 * PROC_WAIT_STATUS_ERROR when deadlock_state ==
+				 * DS_HARD_DEADLOCK, and there's no need to print redundant
+				 * messages.  But for completeness and future-proofing, print
+				 * a message if it looks like someone else kicked us off the
+				 * lock.
 				 */
 				if (deadlock_state != DS_HARD_DEADLOCK)
 					ereport(LOG,
@@ -1737,9 +1738,9 @@ CheckDeadLock(void)
 		 * preserve the flexibility to kill some other transaction than the
 		 * one detecting the deadlock.)
 		 *
-		 * RemoveFromWaitQueue sets MyProc->waitStatus to PROC_WAIT_STATUS_ERROR, so
-		 * ProcSleep will report an error after we return from the signal
-		 * handler.
+		 * RemoveFromWaitQueue sets MyProc->waitStatus to
+		 * PROC_WAIT_STATUS_ERROR, so ProcSleep will report an error after we
+		 * return from the signal handler.
 		 */
 		Assert(MyProc->waitLock != NULL);
 		RemoveFromWaitQueue(MyProc, LockTagHashCode(&(MyProc->waitLock->tag)));
diff --git a/src/backend/storage/lmgr/spin.c b/src/backend/storage/lmgr/spin.c
index 9f7eae9339..6d76b95c27 100644
--- a/src/backend/storage/lmgr/spin.c
+++ b/src/backend/storage/lmgr/spin.c
@@ -37,7 +37,7 @@
 #define NUM_EMULATION_SEMAPHORES (NUM_SPINLOCK_SEMAPHORES + NUM_ATOMICS_SEMAPHORES)
 #else
 #define NUM_EMULATION_SEMAPHORES (NUM_SPINLOCK_SEMAPHORES)
-#endif /* DISABLE_ATOMICS */
+#endif							/* DISABLE_ATOMICS */
 
 PGSemaphore *SpinlockSemaArray;
 
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 9b0c376c8c..538d237258 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1436,34 +1436,62 @@ ProcessUtilitySlow(ParseState *pstate,
 					 * partitions are something we can put an index on, to
 					 * avoid building some indexes only to fail later.
 					 */
-					if (stmt->relation->inh &&
-						get_rel_relkind(relid) == RELKIND_PARTITIONED_TABLE)
+					switch ((RelKind) get_rel_relkind(relid))
 					{
-						ListCell   *lc;
-						List	   *inheritors = NIL;
-
-						inheritors = find_all_inheritors(relid, lockmode, NULL);
-						foreach(lc, inheritors)
-						{
-							char		relkind = get_rel_relkind(lfirst_oid(lc));
-
-							if (relkind != RELKIND_RELATION &&
-								relkind != RELKIND_MATVIEW &&
-								relkind != RELKIND_PARTITIONED_TABLE &&
-								relkind != RELKIND_FOREIGN_TABLE)
-								elog(ERROR, "unexpected relkind \"%c\" on partition \"%s\"",
-									 relkind, stmt->relation->relname);
-
-							if (relkind == RELKIND_FOREIGN_TABLE &&
-								(stmt->unique || stmt->primary))
-								ereport(ERROR,
-										(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-										 errmsg("cannot create unique index on partitioned table \"%s\"",
-												stmt->relation->relname),
-										 errdetail("Table \"%s\" contains partitions that are foreign tables.",
-												   stmt->relation->relname)));
-						}
-						list_free(inheritors);
+						case RELKIND_PARTITIONED_TABLE:
+							if (stmt->relation->inh)
+							{
+								ListCell   *lc;
+								List	   *inheritors = NIL;
+
+								inheritors = find_all_inheritors(relid, lockmode, NULL);
+								foreach(lc, inheritors)
+								{
+									char		relkind = get_rel_relkind(lfirst_oid(lc));
+
+									switch ((RelKind) relkind)
+									{
+										case RELKIND_RELATION:
+										case RELKIND_MATVIEW:
+										case RELKIND_PARTITIONED_TABLE:
+											break;
+										case RELKIND_FOREIGN_TABLE:
+											if (stmt->unique || stmt->primary)
+												ereport(ERROR,
+														(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+														 errmsg("cannot create unique index on partitioned table \"%s\"",
+																stmt->relation->relname),
+														 errdetail("Table \"%s\" contains partitions that are foreign tables.",
+																   stmt->relation->relname)));
+											break;
+										case RELKIND_NULL:
+										case RELKIND_PARTITIONED_INDEX:
+										case RELKIND_SEQUENCE:
+										case RELKIND_COMPOSITE_TYPE:
+										case RELKIND_INDEX:
+										case RELKIND_TOASTVALUE:
+										case RELKIND_VIEW:
+											elog(ERROR, "unexpected relkind \"%c\" on partition \"%s\"",
+												 relkind, stmt->relation->relname);
+											break;
+									}
+
+								}
+								list_free(inheritors);
+							}
+							break;
+						case RELKIND_PARTITIONED_INDEX:
+						case RELKIND_SEQUENCE:
+						case RELKIND_COMPOSITE_TYPE:
+						case RELKIND_FOREIGN_TABLE:
+						case RELKIND_INDEX:
+						case RELKIND_MATVIEW:
+						case RELKIND_RELATION:
+						case RELKIND_TOASTVALUE:
+						case RELKIND_VIEW:
+						case RELKIND_NULL:
+						default:
+							break;
 					}
 
 					/* Run parse analysis ... */
diff --git a/src/backend/utils/adt/amutils.c b/src/backend/utils/adt/amutils.c
index 220cd8fc52..92fd125649 100644
--- a/src/backend/utils/adt/amutils.c
+++ b/src/backend/utils/adt/amutils.c
@@ -175,11 +175,24 @@ indexam_property(FunctionCallInfo fcinfo,
 		if (!HeapTupleIsValid(tuple))
 			PG_RETURN_NULL();
 		rd_rel = (Form_pg_class) GETSTRUCT(tuple);
-		if (rd_rel->relkind != RELKIND_INDEX &&
-			rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
+		switch ((RelKind) rd_rel->relkind)
 		{
-			ReleaseSysCache(tuple);
-			PG_RETURN_NULL();
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+				break;
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				ReleaseSysCache(tuple);
+				PG_RETURN_NULL();
+				break;
 		}
 		amoid = rd_rel->relam;
 		natts = rd_rel->relnatts;
diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c
index 2320c06a9b..9fe10a2f22 100644
--- a/src/backend/utils/adt/dbsize.c
+++ b/src/backend/utils/adt/dbsize.c
@@ -878,7 +878,7 @@ pg_relation_filenode(PG_FUNCTION_ARGS)
 	{
 		if (relform->relfilenode)
 			result = relform->relfilenode;
-		else				/* Consult the relation mapper */
+		else					/* Consult the relation mapper */
 			result = RelationMapOidToFilenode(relid,
 											  relform->relisshared);
 	}
@@ -957,17 +957,17 @@ pg_relation_filepath(PG_FUNCTION_ARGS)
 			rnode.dbNode = MyDatabaseId;
 		if (relform->relfilenode)
 			rnode.relNode = relform->relfilenode;
-		else				/* Consult the relation mapper */
+		else					/* Consult the relation mapper */
 			rnode.relNode = RelationMapOidToFilenode(relid,
 													 relform->relisshared);
 	}
 	else
 	{
-			/* no storage, return NULL */
-			rnode.relNode = InvalidOid;
-			/* some compilers generate warnings without these next two lines */
-			rnode.dbNode = InvalidOid;
-			rnode.spcNode = InvalidOid;
+		/* no storage, return NULL */
+		rnode.relNode = InvalidOid;
+		/* some compilers generate warnings without these next two lines */
+		rnode.dbNode = InvalidOid;
+		rnode.spcNode = InvalidOid;
 	}
 
 	if (!OidIsValid(rnode.relNode))
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index c1120403fd..549bd64f6b 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -45,10 +45,25 @@ check_rel_can_be_partition(Oid relid)
 	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)
-		return false;
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_PARTITIONED_INDEX:
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			if (!relispartition)
+				return false;
+			break;
+	}
 
 	return true;
 }
@@ -143,8 +158,25 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 			nulls[1] = true;
 
 		/* isleaf */
-		values[2] = BoolGetDatum(relkind != RELKIND_PARTITIONED_TABLE &&
-								 relkind != RELKIND_PARTITIONED_INDEX);
+		switch ((RelKind) relkind)
+		{
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_PARTITIONED_INDEX:
+				values[2] = BoolGetDatum(false);
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				values[2] = BoolGetDatum(true);
+				break;
+		}
 
 		/* level */
 		if (relid != rootrelid)
diff --git a/src/backend/utils/adt/tid.c b/src/backend/utils/adt/tid.c
index 509a0fdffc..821f91eb07 100644
--- a/src/backend/utils/adt/tid.c
+++ b/src/backend/utils/adt/tid.c
@@ -381,8 +381,23 @@ currtid_byreloid(PG_FUNCTION_ARGS)
 		aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
 					   RelationGetRelationName(rel));
 
-	if (rel->rd_rel->relkind == RELKIND_VIEW)
-		return currtid_for_view(rel, tid);
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_VIEW:
+			return currtid_for_view(rel, tid);
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
 		elog(ERROR, "cannot look at latest visible tid for relation \"%s.%s\"",
@@ -423,8 +438,23 @@ currtid_byrelname(PG_FUNCTION_ARGS)
 		aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
 					   RelationGetRelationName(rel));
 
-	if (rel->rd_rel->relkind == RELKIND_VIEW)
-		return currtid_for_view(rel, tid);
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_VIEW:
+			return currtid_for_view(rel, tid);
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
 		elog(ERROR, "cannot look at latest visible tid for relation \"%s.%s\"",
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index 4c299057a6..c2711075ef 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -2475,9 +2475,9 @@ schema_get_xml_visible_tables(Oid nspid)
 	initStringInfo(&query);
 	appendStringInfo(&query, "SELECT oid FROM pg_catalog.pg_class"
 					 " WHERE relnamespace = %u AND relkind IN ("
-					 CppAsString2(RELKIND_RELATION) ","
-					 CppAsString2(RELKIND_MATVIEW) ","
-					 CppAsString2(RELKIND_VIEW) ")"
+					 RelKindAsString(RELKIND_RELATION) ","
+					 RelKindAsString(RELKIND_MATVIEW) ","
+					 RelKindAsString(RELKIND_VIEW) ")"
 					 " AND pg_catalog.has_table_privilege (oid, 'SELECT')"
 					 " ORDER BY relname;", nspid);
 
@@ -2507,9 +2507,9 @@ database_get_xml_visible_tables(void)
 	/* At the moment there is no order required here. */
 	return query_to_oid_list("SELECT oid FROM pg_catalog.pg_class"
 							 " WHERE relkind IN ("
-							 CppAsString2(RELKIND_RELATION) ","
-							 CppAsString2(RELKIND_MATVIEW) ","
-							 CppAsString2(RELKIND_VIEW) ")"
+							 RelKindAsString(RELKIND_RELATION) ","
+							 RelKindAsString(RELKIND_MATVIEW) ","
+							 RelKindAsString(RELKIND_VIEW) ")"
 							 " AND pg_catalog.has_table_privilege(pg_class.oid, 'SELECT')"
 							 " AND relnamespace IN (" XML_VISIBLE_SCHEMAS ");");
 }
diff --git a/src/backend/utils/cache/partcache.c b/src/backend/utils/cache/partcache.c
index acf8a44f30..a5eef66f4e 100644
--- a/src/backend/utils/cache/partcache.c
+++ b/src/backend/utils/cache/partcache.c
@@ -53,8 +53,23 @@ static List *generate_partition_qual(Relation rel);
 PartitionKey
 RelationGetPartitionKey(Relation rel)
 {
-	if (rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		return NULL;
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			return NULL;
+	}
 
 	if (unlikely(rel->rd_partkey == NULL))
 		RelationBuildPartitionKey(rel);
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 0b9eb00d2d..aa8f69224d 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -448,7 +448,7 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple)
 	 * Look up any AM-specific parse function; fall out if relkind should not
 	 * have options.
 	 */
-	switch (relation->rd_rel->relkind)
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_TOASTVALUE:
@@ -461,6 +461,10 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple)
 		case RELKIND_PARTITIONED_INDEX:
 			amoptsfn = relation->rd_indam->amoptions;
 			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_NULL:
 		default:
 			return;
 	}
@@ -1181,7 +1185,7 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
 	/*
 	 * initialize access method information
 	 */
-	switch (relation->rd_rel->relkind)
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
 		case RELKIND_INDEX:
 		case RELKIND_PARTITIONED_INDEX:
@@ -1202,6 +1206,8 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
 		case RELKIND_COMPOSITE_TYPE:
 		case RELKIND_FOREIGN_TABLE:
 		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_NULL:
+		default:
 			Assert(relation->rd_rel->relam == InvalidOid);
 			break;
 	}
@@ -1746,38 +1752,53 @@ RelationInitTableAccessMethod(Relation relation)
 	HeapTuple	tuple;
 	Form_pg_am	aform;
 
-	if (relation->rd_rel->relkind == RELKIND_SEQUENCE)
-	{
-		/*
-		 * Sequences are currently accessed like heap tables, but it doesn't
-		 * seem prudent to show that in the catalog. So just overwrite it
-		 * here.
-		 */
-		relation->rd_amhandler = HEAP_TABLE_AM_HANDLER_OID;
-	}
-	else if (IsCatalogRelation(relation))
-	{
-		/*
-		 * Avoid doing a syscache lookup for catalog tables.
-		 */
-		Assert(relation->rd_rel->relam == HEAP_TABLE_AM_OID);
-		relation->rd_amhandler = HEAP_TABLE_AM_HANDLER_OID;
-	}
-	else
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
-		/*
-		 * Look up the table access method, save the OID of its handler
-		 * function.
-		 */
-		Assert(relation->rd_rel->relam != InvalidOid);
-		tuple = SearchSysCache1(AMOID,
-								ObjectIdGetDatum(relation->rd_rel->relam));
-		if (!HeapTupleIsValid(tuple))
-			elog(ERROR, "cache lookup failed for access method %u",
-				 relation->rd_rel->relam);
-		aform = (Form_pg_am) GETSTRUCT(tuple);
-		relation->rd_amhandler = aform->amhandler;
-		ReleaseSysCache(tuple);
+		case RELKIND_SEQUENCE:
+
+			/*
+			 * Sequences are currently accessed like heap tables, but it
+			 * doesn't seem prudent to show that in the catalog. So just
+			 * overwrite it here.
+			 */
+			relation->rd_amhandler = HEAP_TABLE_AM_HANDLER_OID;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			if (IsCatalogRelation(relation))
+			{
+				/*
+				 * Avoid doing a syscache lookup for catalog tables.
+				 */
+				Assert(relation->rd_rel->relam == HEAP_TABLE_AM_OID);
+				relation->rd_amhandler = HEAP_TABLE_AM_HANDLER_OID;
+			}
+			else
+			{
+				/*
+				 * Look up the table access method, save the OID of its
+				 * handler function.
+				 */
+				Assert(relation->rd_rel->relam != InvalidOid);
+				tuple = SearchSysCache1(AMOID,
+										ObjectIdGetDatum(relation->rd_rel->relam));
+				if (!HeapTupleIsValid(tuple))
+					elog(ERROR, "cache lookup failed for access method %u",
+						 relation->rd_rel->relam);
+				aform = (Form_pg_am) GETSTRUCT(tuple);
+				relation->rd_amhandler = aform->amhandler;
+				ReleaseSysCache(tuple);
+			}
+			break;
 	}
 
 	/*
@@ -2023,11 +2044,25 @@ RelationIdGetRelation(Oid relationId)
 			 * and we don't want to use the full-blown procedure because it's
 			 * a headache for indexes that reload itself depends on.
 			 */
-			if (rd->rd_rel->relkind == RELKIND_INDEX ||
-				rd->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
-				RelationReloadIndexInfo(rd);
-			else
-				RelationClearRelation(rd, true);
+			switch ((RelKind) rd->rd_rel->relkind)
+			{
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+					RelationReloadIndexInfo(rd);
+					break;
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+				case RELKIND_NULL:
+				default:
+					RelationClearRelation(rd, true);
+					break;
+			}
 
 			/*
 			 * Normally entries need to be valid here, but before the relcache
@@ -2284,46 +2319,60 @@ RelationReloadNailed(Relation relation)
 	if (!IsTransactionState() || relation->rd_refcnt <= 1)
 		return;
 
-	if (relation->rd_rel->relkind == RELKIND_INDEX)
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
-		/*
-		 * If it's a nailed-but-not-mapped index, then we need to re-read the
-		 * pg_class row to see if its relfilenode changed.
-		 */
-		RelationReloadIndexInfo(relation);
-	}
-	else
-	{
-		/*
-		 * Reload a non-index entry.  We can't easily do so if relcaches
-		 * aren't yet built, but that's fine because at that stage the
-		 * attributes that need to be current (like relfrozenxid) aren't yet
-		 * accessed.  To ensure the entry will later be revalidated, we leave
-		 * it in invalid state, but allow use (cf. RelationIdGetRelation()).
-		 */
-		if (criticalRelcachesBuilt)
-		{
-			HeapTuple	pg_class_tuple;
-			Form_pg_class relp;
+		case RELKIND_INDEX:
 
 			/*
-			 * NB: Mark the entry as valid before starting to scan, to avoid
-			 * self-recursion when re-building pg_class.
+			 * If it's a nailed-but-not-mapped index, then we need to re-read
+			 * the pg_class row to see if its relfilenode changed.
 			 */
-			relation->rd_isvalid = true;
-
-			pg_class_tuple = ScanPgRelation(RelationGetRelid(relation),
-											true, false);
-			relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
-			memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE);
-			heap_freetuple(pg_class_tuple);
+			RelationReloadIndexInfo(relation);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
 
 			/*
-			 * Again mark as valid, to protect against concurrently arriving
-			 * invalidations.
+			 * Reload a non-index entry.  We can't easily do so if relcaches
+			 * aren't yet built, but that's fine because at that stage the
+			 * attributes that need to be current (like relfrozenxid) aren't
+			 * yet accessed.  To ensure the entry will later be revalidated,
+			 * we leave it in invalid state, but allow use (cf.
+			 * RelationIdGetRelation()).
 			 */
-			relation->rd_isvalid = true;
-		}
+			if (criticalRelcachesBuilt)
+			{
+				HeapTuple	pg_class_tuple;
+				Form_pg_class relp;
+
+				/*
+				 * NB: Mark the entry as valid before starting to scan, to
+				 * avoid self-recursion when re-building pg_class.
+				 */
+				relation->rd_isvalid = true;
+
+				pg_class_tuple = ScanPgRelation(RelationGetRelid(relation),
+												true, false);
+				relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
+				memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE);
+				heap_freetuple(pg_class_tuple);
+
+				/*
+				 * Again mark as valid, to protect against concurrently
+				 * arriving invalidations.
+				 */
+				relation->rd_isvalid = true;
+			}
+			break;
 	}
 }
 
@@ -2470,14 +2519,28 @@ RelationClearRelation(Relation relation, bool rebuild)
 	 * re-read the pg_class row to handle possible physical relocation of the
 	 * index, and we check for pg_index updates too.
 	 */
-	if ((relation->rd_rel->relkind == RELKIND_INDEX ||
-		 relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) &&
-		relation->rd_refcnt > 0 &&
-		relation->rd_indexcxt != NULL)
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
-		if (IsTransactionState())
-			RelationReloadIndexInfo(relation);
-		return;
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			if (relation->rd_refcnt > 0 && relation->rd_indexcxt != NULL)
+			{
+				if (IsTransactionState())
+					RelationReloadIndexInfo(relation);
+				return;
+			}
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	/*
@@ -3478,10 +3541,25 @@ RelationBuildLocalRelation(const char *relname,
 	}
 
 	/* if it's a materialized view, it's not populated initially */
-	if (relkind == RELKIND_MATVIEW)
-		rel->rd_rel->relispopulated = false;
-	else
-		rel->rd_rel->relispopulated = true;
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_MATVIEW:
+			rel->rd_rel->relispopulated = false;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			rel->rd_rel->relispopulated = true;
+			break;
+	}
 
 	/* set replica identity -- system catalogs and non-tables don't have one */
 	if (!IsCatalogNamespace(relnamespace) &&
@@ -3521,11 +3599,23 @@ RelationBuildLocalRelation(const char *relname,
 
 	rel->rd_rel->relam = accessmtd;
 
-	if (relkind == RELKIND_RELATION ||
-		relkind == RELKIND_SEQUENCE ||
-		relkind == RELKIND_TOASTVALUE ||
-		relkind == RELKIND_MATVIEW)
-		RelationInitTableAccessMethod(rel);
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_MATVIEW:
+			RelationInitTableAccessMethod(rel);
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	/*
 	 * Okay to insert into the relcache hash table.
@@ -3618,7 +3708,7 @@ RelationSetNewRelfilenode(Relation relation, char persistence)
 	newrnode = relation->rd_node;
 	newrnode.relNode = newrelfilenode;
 
-	switch (relation->rd_rel->relkind)
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
 		case RELKIND_INDEX:
 		case RELKIND_SEQUENCE:
@@ -3630,7 +3720,6 @@ RelationSetNewRelfilenode(Relation relation, char persistence)
 				smgrclose(srel);
 			}
 			break;
-
 		case RELKIND_RELATION:
 		case RELKIND_TOASTVALUE:
 		case RELKIND_MATVIEW:
@@ -3638,7 +3727,12 @@ RelationSetNewRelfilenode(Relation relation, char persistence)
 											persistence,
 											&freezeXid, &minmulti);
 			break;
-
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
 		default:
 			/* we shouldn't be called for anything else */
 			elog(ERROR, "relation \"%s\" does not have storage",
@@ -3688,11 +3782,25 @@ RelationSetNewRelfilenode(Relation relation, char persistence)
 		classform->relfilenode = newrelfilenode;
 
 		/* relpages etc. never change for sequences */
-		if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
+		switch ((RelKind) relation->rd_rel->relkind)
 		{
-			classform->relpages = 0;	/* it's empty until further notice */
-			classform->reltuples = 0;
-			classform->relallvisible = 0;
+			case RELKIND_SEQUENCE:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				classform->relpages = 0;	/* it's empty until further notice */
+				classform->reltuples = 0;
+				classform->relallvisible = 0;
+				break;
 		}
 		classform->relfrozenxid = freezeXid;
 		classform->relminmxid = minmulti;
@@ -4085,16 +4193,29 @@ RelationCacheInitializePhase3(void)
 		}
 
 		/* 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))
+		switch ((RelKind) relation->rd_rel->relkind)
 		{
-			RelationInitTableAccessMethod(relation);
-			Assert(relation->rd_tableam != NULL);
+			case RELKIND_RELATION:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_MATVIEW:
+				if (relation->rd_tableam == NULL)
+				{
+					RelationInitTableAccessMethod(relation);
+					Assert(relation->rd_tableam != NULL);
 
-			restart = true;
+					restart = true;
+				}
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				break;
 		}
 
 		/* Release hold on the relation */
@@ -5863,11 +5984,24 @@ load_relcache_init_file(bool shared)
 				nailed_rels++;
 
 			/* Load table AM data */
-			if (rel->rd_rel->relkind == RELKIND_RELATION ||
-				rel->rd_rel->relkind == RELKIND_SEQUENCE ||
-				rel->rd_rel->relkind == RELKIND_TOASTVALUE ||
-				rel->rd_rel->relkind == RELKIND_MATVIEW)
-				RelationInitTableAccessMethod(rel);
+			switch ((RelKind) rel->rd_rel->relkind)
+			{
+				case RELKIND_RELATION:
+				case RELKIND_SEQUENCE:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_MATVIEW:
+					RelationInitTableAccessMethod(rel);
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_VIEW:
+				case RELKIND_NULL:
+				default:
+					break;
+			}
 
 			Assert(rel->rd_index == NULL);
 			Assert(rel->rd_indextuple == NULL);
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 786672b1b6..3b0cf8a234 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -1743,12 +1743,12 @@ setup_privileges(FILE *cmdfd)
 		"  SET relacl = (SELECT array_agg(a.acl) FROM "
 		" (SELECT E'=r/\"$POSTGRES_SUPERUSERNAME\"' as acl "
 		"  UNION SELECT unnest(pg_catalog.acldefault("
-		"    CASE WHEN relkind = " CppAsString2(RELKIND_SEQUENCE) " THEN 's' "
+		"    CASE WHEN relkind = " RelKindAsString(RELKIND_SEQUENCE) " THEN 's' "
 		"         ELSE 'r' END::\"char\"," CppAsString2(BOOTSTRAP_SUPERUSERID) "::oid))"
 		" ) as a) "
-		"  WHERE relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-		CppAsString2(RELKIND_VIEW) ", " CppAsString2(RELKIND_MATVIEW) ", "
-		CppAsString2(RELKIND_SEQUENCE) ")"
+		"  WHERE relkind IN (" RelKindAsString(RELKIND_RELATION) ", "
+		RelKindAsString(RELKIND_VIEW) ", " RelKindAsString(RELKIND_MATVIEW) ", "
+		RelKindAsString(RELKIND_SEQUENCE) ")"
 		"  AND relacl IS NULL;\n\n",
 		"GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n\n",
 		"GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n\n",
@@ -1765,9 +1765,9 @@ setup_privileges(FILE *cmdfd)
 		"        pg_class"
 		"    WHERE"
 		"        relacl IS NOT NULL"
-		"        AND relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-		CppAsString2(RELKIND_VIEW) ", " CppAsString2(RELKIND_MATVIEW) ", "
-		CppAsString2(RELKIND_SEQUENCE) ");\n\n",
+		"        AND relkind IN (" RelKindAsString(RELKIND_RELATION) ", "
+		RelKindAsString(RELKIND_VIEW) ", " RelKindAsString(RELKIND_MATVIEW) ", "
+		RelKindAsString(RELKIND_SEQUENCE) ");\n\n",
 		"INSERT INTO pg_init_privs "
 		"  (objoid, classoid, objsubid, initprivs, privtype)"
 		"    SELECT"
@@ -1781,9 +1781,9 @@ setup_privileges(FILE *cmdfd)
 		"        JOIN pg_attribute ON (pg_class.oid = pg_attribute.attrelid)"
 		"    WHERE"
 		"        pg_attribute.attacl IS NOT NULL"
-		"        AND pg_class.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-		CppAsString2(RELKIND_VIEW) ", " CppAsString2(RELKIND_MATVIEW) ", "
-		CppAsString2(RELKIND_SEQUENCE) ");\n\n",
+		"        AND pg_class.relkind IN (" RelKindAsString(RELKIND_RELATION) ", "
+		RelKindAsString(RELKIND_VIEW) ", " RelKindAsString(RELKIND_MATVIEW) ", "
+		RelKindAsString(RELKIND_SEQUENCE) ");\n\n",
 		"INSERT INTO pg_init_privs "
 		"  (objoid, classoid, objsubid, initprivs, privtype)"
 		"    SELECT"
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index 4ea59f5494..cc85c9ef15 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -283,10 +283,23 @@ flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
 		bool		mark_parents = true;
 
 		/* Some kinds never have parents */
-		if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
-			tblinfo[i].relkind == RELKIND_VIEW ||
-			tblinfo[i].relkind == RELKIND_MATVIEW)
-			continue;
+		switch ((RelKind) tblinfo[i].relkind)
+		{
+			case RELKIND_SEQUENCE:
+			case RELKIND_VIEW:
+			case RELKIND_MATVIEW:
+				continue;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				break;
+		}
 
 		/*
 		 * Normally, we don't bother computing anything for non-target tables,
@@ -449,10 +462,23 @@ flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables)
 		TableInfo **parents;
 
 		/* Some kinds never have parents */
-		if (tbinfo->relkind == RELKIND_SEQUENCE ||
-			tbinfo->relkind == RELKIND_VIEW ||
-			tbinfo->relkind == RELKIND_MATVIEW)
-			continue;
+		switch ((RelKind) tbinfo->relkind)
+		{
+			case RELKIND_SEQUENCE:
+			case RELKIND_VIEW:
+			case RELKIND_MATVIEW:
+				continue;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				break;
+		}
 
 		/* Don't bother computing anything for non-target tables, either */
 		if (!tbinfo->dobj.dump)
diff --git a/src/bin/pg_dump/pg_backup_tar.c b/src/bin/pg_dump/pg_backup_tar.c
index b4f5942959..0b04578b9a 100644
--- a/src/bin/pg_dump/pg_backup_tar.c
+++ b/src/bin/pg_dump/pg_backup_tar.c
@@ -1191,7 +1191,7 @@ _tarPositionTo(ArchiveHandle *AH, const char *filename)
 		/* Header doesn't match, so read to next header */
 		len = th->fileLen;
 		len += tarPaddingBytesRequired(th->fileLen);
-		blks = len / TAR_BLOCK_SIZE;		/* # of tar blocks */
+		blks = len / TAR_BLOCK_SIZE;	/* # of tar blocks */
 
 		for (i = 0; i < blks; i++)
 			_tarReadRaw(AH, &header[0], TAR_BLOCK_SIZE, NULL, ctx->tarFH);
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index a41a3db876..9fcdf0ddbc 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -2399,17 +2399,35 @@ makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
 		return;
 
 	/* Skip VIEWs (no data to dump) */
-	if (tbinfo->relkind == RELKIND_VIEW)
-		return;
-	/* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
-	if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
-		(foreign_servers_include_oids.head == NULL ||
-		 !simple_oid_list_member(&foreign_servers_include_oids,
-								 tbinfo->foreign_server)))
-		return;
-	/* Skip partitioned tables (data in partitions) */
-	if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
-		return;
+	switch ((RelKind) tbinfo->relkind)
+	{
+		case RELKIND_VIEW:
+			return;
+
+			/*
+			 * Skip FOREIGN TABLEs (no data to dump) unless requested
+			 * explicitly
+			 */
+		case RELKIND_FOREIGN_TABLE:
+			if (foreign_servers_include_oids.head == NULL ||
+				!simple_oid_list_member(&foreign_servers_include_oids,
+										tbinfo->foreign_server))
+				return;
+			break;
+			/* Skip partitioned tables (data in partitions) */
+		case RELKIND_PARTITIONED_TABLE:
+			return;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
+	}
 
 	/* Don't dump data in unlogged tables, if so requested */
 	if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
@@ -2424,12 +2442,27 @@ makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
 	/* OK, let's dump it */
 	tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
 
-	if (tbinfo->relkind == RELKIND_MATVIEW)
-		tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
-	else if (tbinfo->relkind == RELKIND_SEQUENCE)
-		tdinfo->dobj.objType = DO_SEQUENCE_SET;
-	else
-		tdinfo->dobj.objType = DO_TABLE_DATA;
+	switch ((RelKind) tbinfo->relkind)
+	{
+		case RELKIND_MATVIEW:
+			tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
+			break;
+		case RELKIND_SEQUENCE:
+			tdinfo->dobj.objType = DO_SEQUENCE_SET;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			tdinfo->dobj.objType = DO_TABLE_DATA;
+			break;
+	}
 
 	/*
 	 * Note: use tableoid 0 so that this object won't be mistaken for
@@ -2476,14 +2509,14 @@ buildMatViewRefreshDependencies(Archive *fout)
 						 "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
 						 "FROM pg_depend d1 "
 						 "JOIN pg_class c1 ON c1.oid = d1.objid "
-						 "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
+						 "AND c1.relkind = " RelKindAsString(RELKIND_MATVIEW)
 						 " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
 						 "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
 						 "AND d2.objid = r1.oid "
 						 "AND d2.refobjid <> d1.objid "
 						 "JOIN pg_class c2 ON c2.oid = d2.refobjid "
-						 "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
-						 CppAsString2(RELKIND_VIEW) ") "
+						 "AND c2.relkind IN (" RelKindAsString(RELKIND_MATVIEW) ","
+						 RelKindAsString(RELKIND_VIEW) ") "
 						 "WHERE d1.classid = 'pg_class'::regclass "
 						 "UNION "
 						 "SELECT w.objid, d3.refobjid, c3.relkind "
@@ -2493,12 +2526,12 @@ buildMatViewRefreshDependencies(Archive *fout)
 						 "AND d3.objid = r3.oid "
 						 "AND d3.refobjid <> w.refobjid "
 						 "JOIN pg_class c3 ON c3.oid = d3.refobjid "
-						 "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
-						 CppAsString2(RELKIND_VIEW) ") "
+						 "AND c3.relkind IN (" RelKindAsString(RELKIND_MATVIEW) ","
+						 RelKindAsString(RELKIND_VIEW) ") "
 						 ") "
 						 "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
 						 "FROM w "
-						 "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
+						 "WHERE refrelkind = " RelKindAsString(RELKIND_MATVIEW));
 
 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
@@ -2637,9 +2670,23 @@ guessConstraintInheritance(TableInfo *tblinfo, int numTables)
 		TableInfo  *parent;
 
 		/* Sequences and views never have parents */
-		if (tbinfo->relkind == RELKIND_SEQUENCE ||
-			tbinfo->relkind == RELKIND_VIEW)
-			continue;
+		switch ((RelKind) tbinfo->relkind)
+		{
+			case RELKIND_SEQUENCE:
+			case RELKIND_VIEW:
+				continue;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				break;
+		}
 
 		/* Don't bother computing anything for non-target tables, either */
 		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
@@ -4068,9 +4115,23 @@ getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
 		/*
 		 * Only regular and partitioned tables can be added to publications.
 		 */
-		if (tbinfo->relkind != RELKIND_RELATION &&
-			tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
-			continue;
+		switch ((RelKind) tbinfo->relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_PARTITIONED_TABLE:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				continue;
+		}
 
 		/*
 		 * Ignore publication membership of tables whose definitions are not
@@ -6157,7 +6218,7 @@ getTables(Archive *fout, int *numTables)
 
 		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
 						initracl_subquery, "c.relacl", "c.relowner",
-						"CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
+						"CASE WHEN c.relkind = " RelKindAsString(RELKIND_SEQUENCE)
 						" THEN 's' ELSE 'r' END::\"char\"",
 						dopt->binary_upgrade);
 
@@ -6786,10 +6847,25 @@ getTables(Archive *fout, int *numTables)
 		/*
 		 * Decide whether we want to dump this table.
 		 */
-		if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
-			tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
-		else
-			selectDumpableTable(&tblinfo[i], fout);
+		switch ((RelKind) tblinfo[i].relkind)
+		{
+			case RELKIND_COMPOSITE_TYPE:
+				tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				selectDumpableTable(&tblinfo[i], fout);
+				break;
+		}
 
 		/*
 		 * If the table-level and all column-level ACLs for this table are
@@ -6836,16 +6912,31 @@ getTables(Archive *fout, int *numTables)
 		 * We only need to lock the table for certain components; see
 		 * pg_dump.h
 		 */
-		if (tblinfo[i].dobj.dump &&
-			(tblinfo[i].relkind == RELKIND_RELATION ||
-			 tblinfo->relkind == RELKIND_PARTITIONED_TABLE) &&
-			(tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
+		switch ((RelKind) tblinfo[i].relkind)
 		{
-			resetPQExpBuffer(query);
-			appendPQExpBuffer(query,
-							  "LOCK TABLE %s IN ACCESS SHARE MODE",
-							  fmtQualifiedDumpable(&tblinfo[i]));
-			ExecuteSqlStatement(fout, query->data);
+			case RELKIND_RELATION:
+			case RELKIND_PARTITIONED_TABLE:
+				if (tblinfo[i].dobj.dump &&
+					(tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
+				{
+					resetPQExpBuffer(query);
+					appendPQExpBuffer(query,
+									  "LOCK TABLE %s IN ACCESS SHARE MODE",
+									  fmtQualifiedDumpable(&tblinfo[i]));
+					ExecuteSqlStatement(fout, query->data);
+				}
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				break;
 		}
 
 		/* Emit notice if join for owner failed */
@@ -15749,7 +15840,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 		char	   *srvname = NULL;
 		char	   *foreign = "";
 
-		switch (tbinfo->relkind)
+		switch ((RelKind) tbinfo->relkind)
 		{
 			case RELKIND_FOREIGN_TABLE:
 				{
@@ -15788,8 +15879,21 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 			case RELKIND_MATVIEW:
 				reltypename = "MATERIALIZED VIEW";
 				break;
-			default:
+			case RELKIND_RELATION:
+			case RELKIND_PARTITIONED_TABLE:
 				reltypename = "TABLE";
+				break;
+			case RELKIND_SEQUENCE:
+			case RELKIND_VIEW:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				Assert(false);
+				reltypename = "XXX";
+				break;
 		}
 
 		numParents = tbinfo->numParents;
diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c
index 654e2ec514..1e1da953c8 100644
--- a/src/bin/pg_dump/pg_dump_sort.c
+++ b/src/bin/pg_dump/pg_dump_sort.c
@@ -801,8 +801,24 @@ repairMatViewBoundaryMultiLoop(DumpableObject *boundaryobj,
 	{
 		TableInfo  *nextinfo = (TableInfo *) nextobj;
 
-		if (nextinfo->relkind == RELKIND_MATVIEW)
-			nextinfo->postponed_def = true;
+		switch ((RelKind) nextinfo->relkind)
+		{
+			case RELKIND_MATVIEW:
+				nextinfo->postponed_def = true;
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				break;
+		}
 	}
 }
 
@@ -928,30 +944,61 @@ repairDependencyLoop(DumpableObject **loop,
 		return;
 	}
 
-	/* View (including matview) and its ON SELECT rule */
-	if (nLoop == 2 &&
-		loop[0]->objType == DO_TABLE &&
-		loop[1]->objType == DO_RULE &&
-		(((TableInfo *) loop[0])->relkind == RELKIND_VIEW ||
-		 ((TableInfo *) loop[0])->relkind == RELKIND_MATVIEW) &&
-		((RuleInfo *) loop[1])->ev_type == '1' &&
-		((RuleInfo *) loop[1])->is_instead &&
-		((RuleInfo *) loop[1])->ruletable == (TableInfo *) loop[0])
+	switch ((RelKind) ((TableInfo *) loop[0])->relkind)
 	{
-		repairViewRuleLoop(loop[0], loop[1]);
-		return;
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+			/* View (including matview) and its ON SELECT rule */
+			if (nLoop == 2 &&
+				loop[0]->objType == DO_TABLE &&
+				loop[1]->objType == DO_RULE &&
+				((RuleInfo *) loop[1])->ev_type == '1' &&
+				((RuleInfo *) loop[1])->is_instead &&
+				((RuleInfo *) loop[1])->ruletable == (TableInfo *) loop[0])
+			{
+				repairViewRuleLoop(loop[0], loop[1]);
+				return;
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
-	if (nLoop == 2 &&
-		loop[1]->objType == DO_TABLE &&
-		loop[0]->objType == DO_RULE &&
-		(((TableInfo *) loop[1])->relkind == RELKIND_VIEW ||
-		 ((TableInfo *) loop[1])->relkind == RELKIND_MATVIEW) &&
-		((RuleInfo *) loop[0])->ev_type == '1' &&
-		((RuleInfo *) loop[0])->is_instead &&
-		((RuleInfo *) loop[0])->ruletable == (TableInfo *) loop[1])
+
+	switch ((RelKind) ((TableInfo *) loop[1])->relkind)
 	{
-		repairViewRuleLoop(loop[1], loop[0]);
-		return;
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+			if (nLoop == 2 &&
+				loop[1]->objType == DO_TABLE &&
+				loop[0]->objType == DO_RULE &&
+				((RuleInfo *) loop[0])->ev_type == '1' &&
+				((RuleInfo *) loop[0])->is_instead &&
+				((RuleInfo *) loop[0])->ruletable == (TableInfo *) loop[1])
+			{
+				repairViewRuleLoop(loop[1], loop[0]);
+				return;
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	/* Indirect loop involving view (but not matview) and ON SELECT rule */
@@ -959,20 +1006,36 @@ repairDependencyLoop(DumpableObject **loop,
 	{
 		for (i = 0; i < nLoop; i++)
 		{
-			if (loop[i]->objType == DO_TABLE &&
-				((TableInfo *) loop[i])->relkind == RELKIND_VIEW)
+			switch ((RelKind) ((TableInfo *) loop[i])->relkind)
 			{
-				for (j = 0; j < nLoop; j++)
-				{
-					if (loop[j]->objType == DO_RULE &&
-						((RuleInfo *) loop[j])->ev_type == '1' &&
-						((RuleInfo *) loop[j])->is_instead &&
-						((RuleInfo *) loop[j])->ruletable == (TableInfo *) loop[i])
+				case RELKIND_VIEW:
+					if (loop[i]->objType == DO_TABLE)
 					{
-						repairViewRuleMultiLoop(loop[i], loop[j]);
-						return;
+						for (j = 0; j < nLoop; j++)
+						{
+							if (loop[j]->objType == DO_RULE &&
+								((RuleInfo *) loop[j])->ev_type == '1' &&
+								((RuleInfo *) loop[j])->is_instead &&
+								((RuleInfo *) loop[j])->ruletable == (TableInfo *) loop[i])
+							{
+								repairViewRuleMultiLoop(loop[i], loop[j]);
+								return;
+							}
+						}
 					}
-				}
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_NULL:
+				default:
+					break;
 			}
 		}
 	}
@@ -982,20 +1045,36 @@ repairDependencyLoop(DumpableObject **loop,
 	{
 		for (i = 0; i < nLoop; i++)
 		{
-			if (loop[i]->objType == DO_TABLE &&
-				((TableInfo *) loop[i])->relkind == RELKIND_MATVIEW)
+			switch ((RelKind) ((TableInfo *) loop[i])->relkind)
 			{
-				for (j = 0; j < nLoop; j++)
-				{
-					if (loop[j]->objType == DO_PRE_DATA_BOUNDARY)
+				case RELKIND_MATVIEW:
+					if (loop[i]->objType == DO_TABLE)
 					{
-						DumpableObject *nextobj;
-
-						nextobj = (j < nLoop - 1) ? loop[j + 1] : loop[0];
-						repairMatViewBoundaryMultiLoop(loop[j], nextobj);
-						return;
+						for (j = 0; j < nLoop; j++)
+						{
+							if (loop[j]->objType == DO_PRE_DATA_BOUNDARY)
+							{
+								DumpableObject *nextobj;
+
+								nextobj = (j < nLoop - 1) ? loop[j + 1] : loop[0];
+								repairMatViewBoundaryMultiLoop(loop[j], nextobj);
+								return;
+							}
+						}
 					}
-				}
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+				case RELKIND_NULL:
+				default:
+					break;
 			}
 		}
 	}
diff --git a/src/bin/pg_upgrade/info.c b/src/bin/pg_upgrade/info.c
index 7e524ea192..d67da370c5 100644
--- a/src/bin/pg_upgrade/info.c
+++ b/src/bin/pg_upgrade/info.c
@@ -446,8 +446,8 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
 			 "  SELECT c.oid, 0::oid, 0::oid "
 			 "  FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n "
 			 "         ON c.relnamespace = n.oid "
-			 "  WHERE relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-			 CppAsString2(RELKIND_MATVIEW) ") AND "
+			 "  WHERE relkind IN (" RelKindAsString(RELKIND_RELATION) ", "
+			 RelKindAsString(RELKIND_MATVIEW) ") AND "
 	/* exclude possible orphaned temp tables */
 			 "    ((n.nspname !~ '^pg_temp_' AND "
 			 "      n.nspname !~ '^pg_toast_temp_' AND "
diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c
index 70194eb096..996bf8bf70 100644
--- a/src/bin/pg_upgrade/pg_upgrade.c
+++ b/src/bin/pg_upgrade/pg_upgrade.c
@@ -643,9 +643,9 @@ set_frozenxids(bool minmxid_only)
 									  "SET	relfrozenxid = '%u' "
 			/* only heap, materialized view, and TOAST are vacuumed */
 									  "WHERE	relkind IN ("
-									  CppAsString2(RELKIND_RELATION) ", "
-									  CppAsString2(RELKIND_MATVIEW) ", "
-									  CppAsString2(RELKIND_TOASTVALUE) ")",
+									  RelKindAsString(RELKIND_RELATION) ", "
+									  RelKindAsString(RELKIND_MATVIEW) ", "
+									  RelKindAsString(RELKIND_TOASTVALUE) ")",
 									  old_cluster.controldata.chkpnt_nxtxid));
 
 		/* set pg_class.relminmxid */
@@ -654,9 +654,9 @@ set_frozenxids(bool minmxid_only)
 								  "SET	relminmxid = '%u' "
 		/* only heap, materialized view, and TOAST are vacuumed */
 								  "WHERE	relkind IN ("
-								  CppAsString2(RELKIND_RELATION) ", "
-								  CppAsString2(RELKIND_MATVIEW) ", "
-								  CppAsString2(RELKIND_TOASTVALUE) ")",
+								  RelKindAsString(RELKIND_RELATION) ", "
+								  RelKindAsString(RELKIND_MATVIEW) ", "
+								  RelKindAsString(RELKIND_TOASTVALUE) ")",
 								  old_cluster.controldata.chkpnt_nxtmulti));
 		PQfinish(conn);
 
diff --git a/src/bin/pg_upgrade/version.c b/src/bin/pg_upgrade/version.c
index 4e5d27f76e..5fb158c093 100644
--- a/src/bin/pg_upgrade/version.c
+++ b/src/bin/pg_upgrade/version.c
@@ -176,9 +176,9 @@ check_for_data_type_usage(ClusterInfo *cluster, const char *typename,
 						  "		NOT a.attisdropped AND "
 						  "		a.atttypid IN (SELECT oid FROM oids) AND "
 						  "		c.relkind IN ("
-						  CppAsString2(RELKIND_RELATION) ", "
-						  CppAsString2(RELKIND_MATVIEW) ", "
-						  CppAsString2(RELKIND_INDEX) ") AND "
+						  RelKindAsString(RELKIND_RELATION) ", "
+						  RelKindAsString(RELKIND_MATVIEW) ", "
+						  RelKindAsString(RELKIND_INDEX) ") AND "
 						  "		c.relnamespace = n.oid AND "
 		/* exclude possible orphaned temp tables */
 						  "		n.nspname !~ '^pg_temp_' AND "
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 560eacc7f0..5e0f7f92c6 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -4942,16 +4942,25 @@ get_create_object_cmd(EditableObjectType obj_type, Oid oid,
 					 * does not, so editing a matview definition in this way
 					 * is impossible.
 					 */
-					switch (relkind[0])
+					switch ((RelKind) relkind[0])
 					{
-#ifdef NOT_USED
+						case RELKIND_VIEW:
+							appendPQExpBufferStr(buf, "CREATE OR REPLACE VIEW ");
+							break;
 						case RELKIND_MATVIEW:
+#ifdef NOT_USED
 							appendPQExpBufferStr(buf, "CREATE OR REPLACE MATERIALIZED VIEW ");
 							break;
 #endif
-						case RELKIND_VIEW:
-							appendPQExpBufferStr(buf, "CREATE OR REPLACE VIEW ");
-							break;
+						case RELKIND_PARTITIONED_INDEX:
+						case RELKIND_SEQUENCE:
+						case RELKIND_COMPOSITE_TYPE:
+						case RELKIND_FOREIGN_TABLE:
+						case RELKIND_INDEX:
+						case RELKIND_PARTITIONED_TABLE:
+						case RELKIND_RELATION:
+						case RELKIND_TOASTVALUE:
+						case RELKIND_NULL:
 						default:
 							pg_log_error("\"%s.%s\" is not a view",
 										 nspname, relname);
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index cd39b913cd..67675cc0c3 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -734,7 +734,7 @@ describeTypes(const char *pattern, bool verbose, bool showSystem)
 	 * composite types
 	 */
 	appendPQExpBufferStr(&buf, "WHERE (t.typrelid = 0 ");
-	appendPQExpBufferStr(&buf, "OR (SELECT c.relkind = " CppAsString2(RELKIND_COMPOSITE_TYPE)
+	appendPQExpBufferStr(&buf, "OR (SELECT c.relkind = " RelKindAsString(RELKIND_COMPOSITE_TYPE)
 						 " FROM pg_catalog.pg_class c "
 						 "WHERE c.oid = t.typrelid))\n");
 
@@ -943,12 +943,12 @@ permissionsList(const char *pattern)
 					  "SELECT n.nspname as \"%s\",\n"
 					  "  c.relname as \"%s\",\n"
 					  "  CASE c.relkind"
-					  " WHEN " CppAsString2(RELKIND_RELATION) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_VIEW) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_MATVIEW) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_SEQUENCE) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_RELATION) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_VIEW) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_MATVIEW) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_SEQUENCE) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_FOREIGN_TABLE) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
 					  " END as \"%s\",\n"
 					  "  ",
 					  gettext_noop("Schema"),
@@ -1040,12 +1040,12 @@ permissionsList(const char *pattern)
 	appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_class c\n"
 						 "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
 						 "WHERE c.relkind IN ("
-						 CppAsString2(RELKIND_RELATION) ","
-						 CppAsString2(RELKIND_VIEW) ","
-						 CppAsString2(RELKIND_MATVIEW) ","
-						 CppAsString2(RELKIND_SEQUENCE) ","
-						 CppAsString2(RELKIND_FOREIGN_TABLE) ","
-						 CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
+						 RelKindAsString(RELKIND_RELATION) ","
+						 RelKindAsString(RELKIND_VIEW) ","
+						 RelKindAsString(RELKIND_MATVIEW) ","
+						 RelKindAsString(RELKIND_SEQUENCE) ","
+						 RelKindAsString(RELKIND_FOREIGN_TABLE) ","
+						 RelKindAsString(RELKIND_PARTITIONED_TABLE) ")\n");
 
 	/*
 	 * Unless a schema pattern is specified, we suppress system and temp
@@ -1692,134 +1692,148 @@ describeOneTableDetails(const char *schemaname,
 	/*
 	 * If it's a sequence, deal with it here separately.
 	 */
-	if (tableinfo.relkind == RELKIND_SEQUENCE)
+	switch ((RelKind) tableinfo.relkind)
 	{
-		PGresult   *result = NULL;
-		printQueryOpt myopt = pset.popt;
-		char	   *footers[2] = {NULL, NULL};
-
-		if (pset.sversion >= 100000)
-		{
-			printfPQExpBuffer(&buf,
-							  "SELECT pg_catalog.format_type(seqtypid, NULL) AS \"%s\",\n"
-							  "       seqstart AS \"%s\",\n"
-							  "       seqmin AS \"%s\",\n"
-							  "       seqmax AS \"%s\",\n"
-							  "       seqincrement AS \"%s\",\n"
-							  "       CASE WHEN seqcycle THEN '%s' ELSE '%s' END AS \"%s\",\n"
-							  "       seqcache AS \"%s\"\n",
-							  gettext_noop("Type"),
-							  gettext_noop("Start"),
-							  gettext_noop("Minimum"),
-							  gettext_noop("Maximum"),
-							  gettext_noop("Increment"),
-							  gettext_noop("yes"),
-							  gettext_noop("no"),
-							  gettext_noop("Cycles?"),
-							  gettext_noop("Cache"));
-			appendPQExpBuffer(&buf,
-							  "FROM pg_catalog.pg_sequence\n"
-							  "WHERE seqrelid = '%s';",
-							  oid);
-		}
-		else
-		{
-			printfPQExpBuffer(&buf,
-							  "SELECT 'bigint' AS \"%s\",\n"
-							  "       start_value AS \"%s\",\n"
-							  "       min_value AS \"%s\",\n"
-							  "       max_value AS \"%s\",\n"
-							  "       increment_by AS \"%s\",\n"
-							  "       CASE WHEN is_cycled THEN '%s' ELSE '%s' END AS \"%s\",\n"
-							  "       cache_value AS \"%s\"\n",
-							  gettext_noop("Type"),
-							  gettext_noop("Start"),
-							  gettext_noop("Minimum"),
-							  gettext_noop("Maximum"),
-							  gettext_noop("Increment"),
-							  gettext_noop("yes"),
-							  gettext_noop("no"),
-							  gettext_noop("Cycles?"),
-							  gettext_noop("Cache"));
-			appendPQExpBuffer(&buf, "FROM %s", fmtId(schemaname));
-			/* must be separate because fmtId isn't reentrant */
-			appendPQExpBuffer(&buf, ".%s;", fmtId(relationname));
-		}
+		case RELKIND_SEQUENCE:
+			{
+				PGresult   *result = NULL;
+				printQueryOpt myopt = pset.popt;
+				char	   *footers[2] = {NULL, NULL};
 
-		res = PSQLexec(buf.data);
-		if (!res)
-			goto error_return;
+				if (pset.sversion >= 100000)
+				{
+					printfPQExpBuffer(&buf,
+									  "SELECT pg_catalog.format_type(seqtypid, NULL) AS \"%s\",\n"
+									  "       seqstart AS \"%s\",\n"
+									  "       seqmin AS \"%s\",\n"
+									  "       seqmax AS \"%s\",\n"
+									  "       seqincrement AS \"%s\",\n"
+									  "       CASE WHEN seqcycle THEN '%s' ELSE '%s' END AS \"%s\",\n"
+									  "       seqcache AS \"%s\"\n",
+									  gettext_noop("Type"),
+									  gettext_noop("Start"),
+									  gettext_noop("Minimum"),
+									  gettext_noop("Maximum"),
+									  gettext_noop("Increment"),
+									  gettext_noop("yes"),
+									  gettext_noop("no"),
+									  gettext_noop("Cycles?"),
+									  gettext_noop("Cache"));
+					appendPQExpBuffer(&buf,
+									  "FROM pg_catalog.pg_sequence\n"
+									  "WHERE seqrelid = '%s';",
+									  oid);
+				}
+				else
+				{
+					printfPQExpBuffer(&buf,
+									  "SELECT 'bigint' AS \"%s\",\n"
+									  "       start_value AS \"%s\",\n"
+									  "       min_value AS \"%s\",\n"
+									  "       max_value AS \"%s\",\n"
+									  "       increment_by AS \"%s\",\n"
+									  "       CASE WHEN is_cycled THEN '%s' ELSE '%s' END AS \"%s\",\n"
+									  "       cache_value AS \"%s\"\n",
+									  gettext_noop("Type"),
+									  gettext_noop("Start"),
+									  gettext_noop("Minimum"),
+									  gettext_noop("Maximum"),
+									  gettext_noop("Increment"),
+									  gettext_noop("yes"),
+									  gettext_noop("no"),
+									  gettext_noop("Cycles?"),
+									  gettext_noop("Cache"));
+					appendPQExpBuffer(&buf, "FROM %s", fmtId(schemaname));
+					/* must be separate because fmtId isn't reentrant */
+					appendPQExpBuffer(&buf, ".%s;", fmtId(relationname));
+				}
 
-		/* Footer information about a sequence */
+				res = PSQLexec(buf.data);
+				if (!res)
+					goto error_return;
+
+				/* Footer information about a sequence */
+
+				/* Get the column that owns this sequence */
+				printfPQExpBuffer(&buf, "SELECT pg_catalog.quote_ident(nspname) || '.' ||"
+								  "\n   pg_catalog.quote_ident(relname) || '.' ||"
+								  "\n   pg_catalog.quote_ident(attname),"
+								  "\n   d.deptype"
+								  "\nFROM pg_catalog.pg_class c"
+								  "\nINNER JOIN pg_catalog.pg_depend d ON c.oid=d.refobjid"
+								  "\nINNER JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace"
+								  "\nINNER JOIN pg_catalog.pg_attribute a ON ("
+								  "\n a.attrelid=c.oid AND"
+								  "\n a.attnum=d.refobjsubid)"
+								  "\nWHERE d.classid='pg_catalog.pg_class'::pg_catalog.regclass"
+								  "\n AND d.refclassid='pg_catalog.pg_class'::pg_catalog.regclass"
+								  "\n AND d.objid='%s'"
+								  "\n AND d.deptype IN ('a', 'i')",
+								  oid);
 
-		/* Get the column that owns this sequence */
-		printfPQExpBuffer(&buf, "SELECT pg_catalog.quote_ident(nspname) || '.' ||"
-						  "\n   pg_catalog.quote_ident(relname) || '.' ||"
-						  "\n   pg_catalog.quote_ident(attname),"
-						  "\n   d.deptype"
-						  "\nFROM pg_catalog.pg_class c"
-						  "\nINNER JOIN pg_catalog.pg_depend d ON c.oid=d.refobjid"
-						  "\nINNER JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace"
-						  "\nINNER JOIN pg_catalog.pg_attribute a ON ("
-						  "\n a.attrelid=c.oid AND"
-						  "\n a.attnum=d.refobjsubid)"
-						  "\nWHERE d.classid='pg_catalog.pg_class'::pg_catalog.regclass"
-						  "\n AND d.refclassid='pg_catalog.pg_class'::pg_catalog.regclass"
-						  "\n AND d.objid='%s'"
-						  "\n AND d.deptype IN ('a', 'i')",
-						  oid);
+				result = PSQLexec(buf.data);
 
-		result = PSQLexec(buf.data);
+				/*
+				 * If we get no rows back, don't show anything (obviously). We
+				 * should never get more than one row back, but if we do, just
+				 * ignore it and don't print anything.
+				 */
+				if (!result)
+					goto error_return;
+				else if (PQntuples(result) == 1)
+				{
+					switch (PQgetvalue(result, 0, 1)[0])
+					{
+						case 'a':
+							footers[0] = psprintf(_("Owned by: %s"),
+												  PQgetvalue(result, 0, 0));
+							break;
+						case 'i':
+							footers[0] = psprintf(_("Sequence for identity column: %s"),
+												  PQgetvalue(result, 0, 0));
+							break;
+					}
+				}
+				PQclear(result);
 
-		/*
-		 * If we get no rows back, don't show anything (obviously). We should
-		 * never get more than one row back, but if we do, just ignore it and
-		 * don't print anything.
-		 */
-		if (!result)
-			goto error_return;
-		else if (PQntuples(result) == 1)
-		{
-			switch (PQgetvalue(result, 0, 1)[0])
-			{
-				case 'a':
-					footers[0] = psprintf(_("Owned by: %s"),
-										  PQgetvalue(result, 0, 0));
-					break;
-				case 'i':
-					footers[0] = psprintf(_("Sequence for identity column: %s"),
-										  PQgetvalue(result, 0, 0));
-					break;
-			}
-		}
-		PQclear(result);
+				printfPQExpBuffer(&title, _("Sequence \"%s.%s\""),
+								  schemaname, relationname);
 
-		printfPQExpBuffer(&title, _("Sequence \"%s.%s\""),
-						  schemaname, relationname);
+				myopt.footers = footers;
+				myopt.topt.default_footer = false;
+				myopt.title = title.data;
+				myopt.translate_header = true;
 
-		myopt.footers = footers;
-		myopt.topt.default_footer = false;
-		myopt.title = title.data;
-		myopt.translate_header = true;
+				printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
-		printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+				if (footers[0])
+					free(footers[0]);
 
-		if (footers[0])
-			free(footers[0]);
+				retval = true;
+				goto error_return;	/* not an error, just return early */
+			}
+			break;
 
-		retval = true;
-		goto error_return;		/* not an error, just return early */
+			/*
+			 * Identify whether we should print collation, nullable, default
+			 * vals
+			 */
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_PARTITIONED_TABLE:
+			show_column_details = true;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_INDEX:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
-	/* Identify whether we should print collation, nullable, default vals */
-	if (tableinfo.relkind == RELKIND_RELATION ||
-		tableinfo.relkind == RELKIND_VIEW ||
-		tableinfo.relkind == RELKIND_MATVIEW ||
-		tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
-		tableinfo.relkind == RELKIND_COMPOSITE_TYPE ||
-		tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
-		show_column_details = true;
-
 	/*
 	 * Get per-column info
 	 *
@@ -1861,58 +1875,91 @@ describeOneTableDetails(const char *schemaname,
 			appendPQExpBufferStr(&buf, ",\n  ''::pg_catalog.char AS attgenerated");
 		attgenerated_col = cols++;
 	}
-	if (tableinfo.relkind == RELKIND_INDEX ||
-		tableinfo.relkind == RELKIND_PARTITIONED_INDEX)
-	{
-		if (pset.sversion >= 110000)
-		{
-			appendPQExpBuffer(&buf, ",\n  CASE WHEN a.attnum <= (SELECT i.indnkeyatts FROM pg_catalog.pg_index i WHERE i.indexrelid = '%s') THEN '%s' ELSE '%s' END AS is_key",
-							  oid,
-							  gettext_noop("yes"),
-							  gettext_noop("no"));
-			isindexkey_col = cols++;
-		}
-		appendPQExpBufferStr(&buf, ",\n  pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE) AS indexdef");
-		indexdef_col = cols++;
-	}
-	/* FDW options for foreign table column, only for 9.2 or later */
-	if (tableinfo.relkind == RELKIND_FOREIGN_TABLE && pset.sversion >= 90200)
+	switch ((RelKind) tableinfo.relkind)
 	{
-		appendPQExpBufferStr(&buf, ",\n  CASE WHEN attfdwoptions IS NULL THEN '' ELSE "
-							 "  '(' || pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value)  FROM "
-							 "  pg_catalog.pg_options_to_table(attfdwoptions)), ', ') || ')' END AS attfdwoptions");
-		fdwopts_col = cols++;
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			if (pset.sversion >= 110000)
+			{
+				appendPQExpBuffer(&buf, ",\n  CASE WHEN a.attnum <= (SELECT i.indnkeyatts FROM pg_catalog.pg_index i WHERE i.indexrelid = '%s') THEN '%s' ELSE '%s' END AS is_key",
+								  oid,
+								  gettext_noop("yes"),
+								  gettext_noop("no"));
+				isindexkey_col = cols++;
+			}
+			appendPQExpBufferStr(&buf, ",\n  pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE) AS indexdef");
+			indexdef_col = cols++;
+			break;
+		case RELKIND_FOREIGN_TABLE:
+			/* FDW options for foreign table column, only for 9.2 or later */
+			if (pset.sversion >= 90200)
+			{
+				appendPQExpBufferStr(&buf, ",\n  CASE WHEN attfdwoptions IS NULL THEN '' ELSE "
+									 "  '(' || pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value)  FROM "
+									 "  pg_catalog.pg_options_to_table(attfdwoptions)), ', ') || ')' END AS attfdwoptions");
+				fdwopts_col = cols++;
+			}
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
+
 	if (verbose)
 	{
 		appendPQExpBufferStr(&buf, ",\n  a.attstorage");
 		attstorage_col = cols++;
 
 		/* stats target, if relevant to relkind */
-		if (tableinfo.relkind == RELKIND_RELATION ||
-			tableinfo.relkind == RELKIND_INDEX ||
-			tableinfo.relkind == RELKIND_PARTITIONED_INDEX ||
-			tableinfo.relkind == RELKIND_MATVIEW ||
-			tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
-			tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
+		switch ((RelKind) tableinfo.relkind)
 		{
-			appendPQExpBufferStr(&buf, ",\n  CASE WHEN a.attstattarget=-1 THEN NULL ELSE a.attstattarget END AS attstattarget");
-			attstattarget_col = cols++;
+			case RELKIND_RELATION:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_TABLE:
+				appendPQExpBufferStr(&buf, ",\n  CASE WHEN a.attstattarget=-1 THEN NULL ELSE a.attstattarget END AS attstattarget");
+				attstattarget_col = cols++;
+				break;
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+			case RELKIND_NULL:
+			default:
+				break;
 		}
 
 		/*
 		 * In 9.0+, we have column comments for: relations, views, composite
 		 * types, and foreign tables (cf. CommentObject() in comment.c).
 		 */
-		if (tableinfo.relkind == RELKIND_RELATION ||
-			tableinfo.relkind == RELKIND_VIEW ||
-			tableinfo.relkind == RELKIND_MATVIEW ||
-			tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
-			tableinfo.relkind == RELKIND_COMPOSITE_TYPE ||
-			tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
+		switch ((RelKind) tableinfo.relkind)
 		{
-			appendPQExpBufferStr(&buf, ",\n  pg_catalog.col_description(a.attrelid, a.attnum)");
-			attdescr_col = cols++;
+			case RELKIND_RELATION:
+			case RELKIND_VIEW:
+			case RELKIND_MATVIEW:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_PARTITIONED_TABLE:
+				appendPQExpBufferStr(&buf, ",\n  pg_catalog.col_description(a.attrelid, a.attnum)");
+				attdescr_col = cols++;
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_INDEX:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_NULL:
+			default:
+				break;
 		}
 	}
 
@@ -1926,7 +1973,7 @@ describeOneTableDetails(const char *schemaname,
 	numrows = PQntuples(res);
 
 	/* Make title */
-	switch (tableinfo.relkind)
+	switch ((RelKind) tableinfo.relkind)
 	{
 		case RELKIND_RELATION:
 			if (tableinfo.relpersistence == 'u')
@@ -1964,11 +2011,6 @@ describeOneTableDetails(const char *schemaname,
 				printfPQExpBuffer(&title, _("Partitioned index \"%s.%s\""),
 								  schemaname, relationname);
 			break;
-		case 's':
-			/* not used as of 8.2, but keep it for backwards compatibility */
-			printfPQExpBuffer(&title, _("Special relation \"%s.%s\""),
-							  schemaname, relationname);
-			break;
 		case RELKIND_TOASTVALUE:
 			printfPQExpBuffer(&title, _("TOAST table \"%s.%s\""),
 							  schemaname, relationname);
@@ -1989,10 +2031,23 @@ describeOneTableDetails(const char *schemaname,
 				printfPQExpBuffer(&title, _("Partitioned table \"%s.%s\""),
 								  schemaname, relationname);
 			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_NULL:
 		default:
-			/* untranslated unknown relkind */
-			printfPQExpBuffer(&title, "?%c? \"%s.%s\"",
-							  tableinfo.relkind, schemaname, relationname);
+
+			/*
+			 * 's' is not used as of 8.2, but we keep it for backwards
+			 * compatibility. We cannot handle 's' as a case value without
+			 * adding it to enum RelKind, but that would trigger warnings and
+			 * errors elsewhere.  Handle it here, instead.
+			 */
+			if ((RelKind) tableinfo.relkind == 's')
+				printfPQExpBuffer(&title, _("Special relation \"%s.%s\""),
+								  schemaname, relationname);
+			else
+				/* untranslated unknown relkind */
+				printfPQExpBuffer(&title, "?%c? \"%s.%s\"",
+								  tableinfo.relkind, schemaname, relationname);
 			break;
 	}
 
@@ -2150,742 +2205,806 @@ describeOneTableDetails(const char *schemaname,
 		PQclear(result);
 	}
 
-	if (tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
+	switch ((RelKind) tableinfo.relkind)
 	{
-		/* Footer information for a partitioned table (partitioning parent) */
-		PGresult   *result;
-
-		printfPQExpBuffer(&buf,
-						  "SELECT pg_catalog.pg_get_partkeydef('%s'::pg_catalog.oid);",
-						  oid);
-		result = PSQLexec(buf.data);
-		if (!result)
-			goto error_return;
+		case RELKIND_PARTITIONED_TABLE:
+			{
+				/*
+				 * Footer information for a partitioned table (partitioning
+				 * parent)
+				 */
+				PGresult   *result;
 
-		if (PQntuples(result) == 1)
-		{
-			char	   *partkeydef = PQgetvalue(result, 0, 0);
+				printfPQExpBuffer(&buf,
+								  "SELECT pg_catalog.pg_get_partkeydef('%s'::pg_catalog.oid);",
+								  oid);
+				result = PSQLexec(buf.data);
+				if (!result)
+					goto error_return;
 
-			printfPQExpBuffer(&tmpbuf, _("Partition key: %s"), partkeydef);
-			printTableAddFooter(&cont, tmpbuf.data);
-		}
-		PQclear(result);
-	}
+				if (PQntuples(result) == 1)
+				{
+					char	   *partkeydef = PQgetvalue(result, 0, 0);
 
-	if (tableinfo.relkind == RELKIND_TOASTVALUE)
-	{
-		/* For a TOAST table, print name of owning table */
-		PGresult   *result;
+					printfPQExpBuffer(&tmpbuf, _("Partition key: %s"), partkeydef);
+					printTableAddFooter(&cont, tmpbuf.data);
+				}
+				PQclear(result);
+			}
+			break;
 
-		printfPQExpBuffer(&buf,
-						  "SELECT n.nspname, c.relname\n"
-						  "FROM pg_catalog.pg_class c"
-						  " JOIN pg_catalog.pg_namespace n"
-						  " ON n.oid = c.relnamespace\n"
-						  "WHERE reltoastrelid = '%s';", oid);
-		result = PSQLexec(buf.data);
-		if (!result)
-			goto error_return;
+		case RELKIND_TOASTVALUE:
+			{
+				/* For a TOAST table, print name of owning table */
+				PGresult   *result;
 
-		if (PQntuples(result) == 1)
-		{
-			char	   *schemaname = PQgetvalue(result, 0, 0);
-			char	   *relname = PQgetvalue(result, 0, 1);
+				printfPQExpBuffer(&buf,
+								  "SELECT n.nspname, c.relname\n"
+								  "FROM pg_catalog.pg_class c"
+								  " JOIN pg_catalog.pg_namespace n"
+								  " ON n.oid = c.relnamespace\n"
+								  "WHERE reltoastrelid = '%s';", oid);
+				result = PSQLexec(buf.data);
+				if (!result)
+					goto error_return;
+
+				if (PQntuples(result) == 1)
+				{
+					char	   *schemaname = PQgetvalue(result, 0, 0);
+					char	   *relname = PQgetvalue(result, 0, 1);
 
-			printfPQExpBuffer(&tmpbuf, _("Owning table: \"%s.%s\""),
-							  schemaname, relname);
-			printTableAddFooter(&cont, tmpbuf.data);
-		}
-		PQclear(result);
+					printfPQExpBuffer(&tmpbuf, _("Owning table: \"%s.%s\""),
+									  schemaname, relname);
+					printTableAddFooter(&cont, tmpbuf.data);
+				}
+				PQclear(result);
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
-	if (tableinfo.relkind == RELKIND_INDEX ||
-		tableinfo.relkind == RELKIND_PARTITIONED_INDEX)
+	switch ((RelKind) tableinfo.relkind)
 	{
-		/* Footer information about an index */
-		PGresult   *result;
-
-		printfPQExpBuffer(&buf,
-						  "SELECT i.indisunique, i.indisprimary, i.indisclustered, ");
-		if (pset.sversion >= 80200)
-			appendPQExpBufferStr(&buf, "i.indisvalid,\n");
-		else
-			appendPQExpBufferStr(&buf, "true AS indisvalid,\n");
-		if (pset.sversion >= 90000)
-			appendPQExpBufferStr(&buf,
-								 "  (NOT i.indimmediate) AND "
-								 "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
-								 "WHERE conrelid = i.indrelid AND "
-								 "conindid = i.indexrelid AND "
-								 "contype IN ('p','u','x') AND "
-								 "condeferrable) AS condeferrable,\n"
-								 "  (NOT i.indimmediate) AND "
-								 "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
-								 "WHERE conrelid = i.indrelid AND "
-								 "conindid = i.indexrelid AND "
-								 "contype IN ('p','u','x') AND "
-								 "condeferred) AS condeferred,\n");
-		else
-			appendPQExpBufferStr(&buf,
-								 "  false AS condeferrable, false AS condeferred,\n");
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			{
+				/* Footer information about an index */
+				PGresult   *result;
 
-		if (pset.sversion >= 90400)
-			appendPQExpBufferStr(&buf, "i.indisreplident,\n");
-		else
-			appendPQExpBufferStr(&buf, "false AS indisreplident,\n");
+				printfPQExpBuffer(&buf,
+								  "SELECT i.indisunique, i.indisprimary, i.indisclustered, ");
+				if (pset.sversion >= 80200)
+					appendPQExpBufferStr(&buf, "i.indisvalid,\n");
+				else
+					appendPQExpBufferStr(&buf, "true AS indisvalid,\n");
+				if (pset.sversion >= 90000)
+					appendPQExpBufferStr(&buf,
+										 "  (NOT i.indimmediate) AND "
+										 "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
+										 "WHERE conrelid = i.indrelid AND "
+										 "conindid = i.indexrelid AND "
+										 "contype IN ('p','u','x') AND "
+										 "condeferrable) AS condeferrable,\n"
+										 "  (NOT i.indimmediate) AND "
+										 "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
+										 "WHERE conrelid = i.indrelid AND "
+										 "conindid = i.indexrelid AND "
+										 "contype IN ('p','u','x') AND "
+										 "condeferred) AS condeferred,\n");
+				else
+					appendPQExpBufferStr(&buf,
+										 "  false AS condeferrable, false AS condeferred,\n");
 
-		appendPQExpBuffer(&buf, "  a.amname, c2.relname, "
-						  "pg_catalog.pg_get_expr(i.indpred, i.indrelid, true)\n"
-						  "FROM pg_catalog.pg_index i, pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_am a\n"
-						  "WHERE i.indexrelid = c.oid AND c.oid = '%s' AND c.relam = a.oid\n"
-						  "AND i.indrelid = c2.oid;",
-						  oid);
+				if (pset.sversion >= 90400)
+					appendPQExpBufferStr(&buf, "i.indisreplident,\n");
+				else
+					appendPQExpBufferStr(&buf, "false AS indisreplident,\n");
 
-		result = PSQLexec(buf.data);
-		if (!result)
-			goto error_return;
-		else if (PQntuples(result) != 1)
-		{
-			PQclear(result);
-			goto error_return;
-		}
-		else
-		{
-			char	   *indisunique = PQgetvalue(result, 0, 0);
-			char	   *indisprimary = PQgetvalue(result, 0, 1);
-			char	   *indisclustered = PQgetvalue(result, 0, 2);
-			char	   *indisvalid = PQgetvalue(result, 0, 3);
-			char	   *deferrable = PQgetvalue(result, 0, 4);
-			char	   *deferred = PQgetvalue(result, 0, 5);
-			char	   *indisreplident = PQgetvalue(result, 0, 6);
-			char	   *indamname = PQgetvalue(result, 0, 7);
-			char	   *indtable = PQgetvalue(result, 0, 8);
-			char	   *indpred = PQgetvalue(result, 0, 9);
-
-			if (strcmp(indisprimary, "t") == 0)
-				printfPQExpBuffer(&tmpbuf, _("primary key, "));
-			else if (strcmp(indisunique, "t") == 0)
-				printfPQExpBuffer(&tmpbuf, _("unique, "));
-			else
-				resetPQExpBuffer(&tmpbuf);
-			appendPQExpBuffer(&tmpbuf, "%s, ", indamname);
+				appendPQExpBuffer(&buf, "  a.amname, c2.relname, "
+								  "pg_catalog.pg_get_expr(i.indpred, i.indrelid, true)\n"
+								  "FROM pg_catalog.pg_index i, pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_am a\n"
+								  "WHERE i.indexrelid = c.oid AND c.oid = '%s' AND c.relam = a.oid\n"
+								  "AND i.indrelid = c2.oid;",
+								  oid);
 
-			/* we assume here that index and table are in same schema */
-			appendPQExpBuffer(&tmpbuf, _("for table \"%s.%s\""),
-							  schemaname, indtable);
+				result = PSQLexec(buf.data);
+				if (!result)
+					goto error_return;
+				else if (PQntuples(result) != 1)
+				{
+					PQclear(result);
+					goto error_return;
+				}
+				else
+				{
+					char	   *indisunique = PQgetvalue(result, 0, 0);
+					char	   *indisprimary = PQgetvalue(result, 0, 1);
+					char	   *indisclustered = PQgetvalue(result, 0, 2);
+					char	   *indisvalid = PQgetvalue(result, 0, 3);
+					char	   *deferrable = PQgetvalue(result, 0, 4);
+					char	   *deferred = PQgetvalue(result, 0, 5);
+					char	   *indisreplident = PQgetvalue(result, 0, 6);
+					char	   *indamname = PQgetvalue(result, 0, 7);
+					char	   *indtable = PQgetvalue(result, 0, 8);
+					char	   *indpred = PQgetvalue(result, 0, 9);
+
+					if (strcmp(indisprimary, "t") == 0)
+						printfPQExpBuffer(&tmpbuf, _("primary key, "));
+					else if (strcmp(indisunique, "t") == 0)
+						printfPQExpBuffer(&tmpbuf, _("unique, "));
+					else
+						resetPQExpBuffer(&tmpbuf);
+					appendPQExpBuffer(&tmpbuf, "%s, ", indamname);
 
-			if (strlen(indpred))
-				appendPQExpBuffer(&tmpbuf, _(", predicate (%s)"), indpred);
+					/* we assume here that index and table are in same schema */
+					appendPQExpBuffer(&tmpbuf, _("for table \"%s.%s\""),
+									  schemaname, indtable);
 
-			if (strcmp(indisclustered, "t") == 0)
-				appendPQExpBufferStr(&tmpbuf, _(", clustered"));
+					if (strlen(indpred))
+						appendPQExpBuffer(&tmpbuf, _(", predicate (%s)"), indpred);
 
-			if (strcmp(indisvalid, "t") != 0)
-				appendPQExpBufferStr(&tmpbuf, _(", invalid"));
+					if (strcmp(indisclustered, "t") == 0)
+						appendPQExpBufferStr(&tmpbuf, _(", clustered"));
 
-			if (strcmp(deferrable, "t") == 0)
-				appendPQExpBufferStr(&tmpbuf, _(", deferrable"));
+					if (strcmp(indisvalid, "t") != 0)
+						appendPQExpBufferStr(&tmpbuf, _(", invalid"));
 
-			if (strcmp(deferred, "t") == 0)
-				appendPQExpBufferStr(&tmpbuf, _(", initially deferred"));
+					if (strcmp(deferrable, "t") == 0)
+						appendPQExpBufferStr(&tmpbuf, _(", deferrable"));
 
-			if (strcmp(indisreplident, "t") == 0)
-				appendPQExpBufferStr(&tmpbuf, _(", replica identity"));
+					if (strcmp(deferred, "t") == 0)
+						appendPQExpBufferStr(&tmpbuf, _(", initially deferred"));
 
-			printTableAddFooter(&cont, tmpbuf.data);
+					if (strcmp(indisreplident, "t") == 0)
+						appendPQExpBufferStr(&tmpbuf, _(", replica identity"));
 
-			/*
-			 * If it's a partitioned index, we'll print the tablespace below
-			 */
-			if (tableinfo.relkind == RELKIND_INDEX)
-				add_tablespace_footer(&cont, tableinfo.relkind,
-									  tableinfo.tablespace, true);
-		}
+					printTableAddFooter(&cont, tmpbuf.data);
 
-		PQclear(result);
-	}
-	/* If you add relkinds here, see also "Finish printing..." stanza below */
-	else if (tableinfo.relkind == RELKIND_RELATION ||
-			 tableinfo.relkind == RELKIND_MATVIEW ||
-			 tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
-			 tableinfo.relkind == RELKIND_PARTITIONED_TABLE ||
-			 tableinfo.relkind == RELKIND_PARTITIONED_INDEX ||
-			 tableinfo.relkind == RELKIND_TOASTVALUE)
-	{
-		/* Footer information about a table */
-		PGresult   *result = NULL;
-		int			tuples = 0;
+					/*
+					 * If it's a partitioned index, we'll print the tablespace
+					 * below
+					 */
+					if (tableinfo.relkind == RELKIND_INDEX)
+						add_tablespace_footer(&cont, tableinfo.relkind,
+											  tableinfo.tablespace, true);
+				}
 
-		/* print indexes */
-		if (tableinfo.hasindex)
-		{
-			printfPQExpBuffer(&buf,
-							  "SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, ");
-			if (pset.sversion >= 80200)
-				appendPQExpBufferStr(&buf, "i.indisvalid, ");
-			else
-				appendPQExpBufferStr(&buf, "true as indisvalid, ");
-			appendPQExpBufferStr(&buf, "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true),\n  ");
-			if (pset.sversion >= 90000)
-				appendPQExpBufferStr(&buf,
-									 "pg_catalog.pg_get_constraintdef(con.oid, true), "
-									 "contype, condeferrable, condeferred");
-			else
-				appendPQExpBufferStr(&buf,
-									 "null AS constraintdef, null AS contype, "
-									 "false AS condeferrable, false AS condeferred");
-			if (pset.sversion >= 90400)
-				appendPQExpBufferStr(&buf, ", i.indisreplident");
-			else
-				appendPQExpBufferStr(&buf, ", false AS indisreplident");
-			if (pset.sversion >= 80000)
-				appendPQExpBufferStr(&buf, ", c2.reltablespace");
-			appendPQExpBufferStr(&buf,
-								 "\nFROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n");
-			if (pset.sversion >= 90000)
-				appendPQExpBufferStr(&buf,
-									 "  LEFT JOIN pg_catalog.pg_constraint con ON (conrelid = i.indrelid AND conindid = i.indexrelid AND contype IN ('p','u','x'))\n");
-			appendPQExpBuffer(&buf,
-							  "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
-							  "ORDER BY i.indisprimary DESC, c2.relname;",
-							  oid);
-			result = PSQLexec(buf.data);
-			if (!result)
-				goto error_return;
-			else
-				tuples = PQntuples(result);
+				PQclear(result);
+			}
+			break;
 
-			if (tuples > 0)
+			/*
+			 * If you add relkinds here, see also "Finish printing..." stanza
+			 * below
+			 */
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
 			{
-				printTableAddFooter(&cont, _("Indexes:"));
-				for (i = 0; i < tuples; i++)
-				{
-					/* untranslated index name */
-					printfPQExpBuffer(&buf, "    \"%s\"",
-									  PQgetvalue(result, i, 0));
+				/* Footer information about a table */
+				PGresult   *result = NULL;
+				int			tuples = 0;
 
-					/* If exclusion constraint, print the constraintdef */
-					if (strcmp(PQgetvalue(result, i, 7), "x") == 0)
-					{
-						appendPQExpBuffer(&buf, " %s",
-										  PQgetvalue(result, i, 6));
-					}
+				/* print indexes */
+				if (tableinfo.hasindex)
+				{
+					printfPQExpBuffer(&buf,
+									  "SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, ");
+					if (pset.sversion >= 80200)
+						appendPQExpBufferStr(&buf, "i.indisvalid, ");
 					else
-					{
-						const char *indexdef;
-						const char *usingpos;
+						appendPQExpBufferStr(&buf, "true as indisvalid, ");
+					appendPQExpBufferStr(&buf, "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true),\n  ");
+					if (pset.sversion >= 90000)
+						appendPQExpBufferStr(&buf,
+											 "pg_catalog.pg_get_constraintdef(con.oid, true), "
+											 "contype, condeferrable, condeferred");
+					else
+						appendPQExpBufferStr(&buf,
+											 "null AS constraintdef, null AS contype, "
+											 "false AS condeferrable, false AS condeferred");
+					if (pset.sversion >= 90400)
+						appendPQExpBufferStr(&buf, ", i.indisreplident");
+					else
+						appendPQExpBufferStr(&buf, ", false AS indisreplident");
+					if (pset.sversion >= 80000)
+						appendPQExpBufferStr(&buf, ", c2.reltablespace");
+					appendPQExpBufferStr(&buf,
+										 "\nFROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n");
+					if (pset.sversion >= 90000)
+						appendPQExpBufferStr(&buf,
+											 "  LEFT JOIN pg_catalog.pg_constraint con ON (conrelid = i.indrelid AND conindid = i.indexrelid AND contype IN ('p','u','x'))\n");
+					appendPQExpBuffer(&buf,
+									  "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
+									  "ORDER BY i.indisprimary DESC, c2.relname;",
+									  oid);
+					result = PSQLexec(buf.data);
+					if (!result)
+						goto error_return;
+					else
+						tuples = PQntuples(result);
 
-						/* Label as primary key or unique (but not both) */
-						if (strcmp(PQgetvalue(result, i, 1), "t") == 0)
-							appendPQExpBufferStr(&buf, " PRIMARY KEY,");
-						else if (strcmp(PQgetvalue(result, i, 2), "t") == 0)
+					if (tuples > 0)
+					{
+						printTableAddFooter(&cont, _("Indexes:"));
+						for (i = 0; i < tuples; i++)
 						{
-							if (strcmp(PQgetvalue(result, i, 7), "u") == 0)
-								appendPQExpBufferStr(&buf, " UNIQUE CONSTRAINT,");
+							/* untranslated index name */
+							printfPQExpBuffer(&buf, "    \"%s\"",
+											  PQgetvalue(result, i, 0));
+
+							/*
+							 * If exclusion constraint, print the
+							 * constraintdef
+							 */
+							if (strcmp(PQgetvalue(result, i, 7), "x") == 0)
+							{
+								appendPQExpBuffer(&buf, " %s",
+												  PQgetvalue(result, i, 6));
+							}
 							else
-								appendPQExpBufferStr(&buf, " UNIQUE,");
-						}
+							{
+								const char *indexdef;
+								const char *usingpos;
+
+								/*
+								 * Label as primary key or unique (but not
+								 * both)
+								 */
+								if (strcmp(PQgetvalue(result, i, 1), "t") == 0)
+									appendPQExpBufferStr(&buf, " PRIMARY KEY,");
+								else if (strcmp(PQgetvalue(result, i, 2), "t") == 0)
+								{
+									if (strcmp(PQgetvalue(result, i, 7), "u") == 0)
+										appendPQExpBufferStr(&buf, " UNIQUE CONSTRAINT,");
+									else
+										appendPQExpBufferStr(&buf, " UNIQUE,");
+								}
+
+								/* Everything after "USING" is echoed verbatim */
+								indexdef = PQgetvalue(result, i, 5);
+								usingpos = strstr(indexdef, " USING ");
+								if (usingpos)
+									indexdef = usingpos + 7;
+								appendPQExpBuffer(&buf, " %s", indexdef);
+
+								/* Need these for deferrable PK/UNIQUE indexes */
+								if (strcmp(PQgetvalue(result, i, 8), "t") == 0)
+									appendPQExpBufferStr(&buf, " DEFERRABLE");
+
+								if (strcmp(PQgetvalue(result, i, 9), "t") == 0)
+									appendPQExpBufferStr(&buf, " INITIALLY DEFERRED");
+							}
 
-						/* Everything after "USING" is echoed verbatim */
-						indexdef = PQgetvalue(result, i, 5);
-						usingpos = strstr(indexdef, " USING ");
-						if (usingpos)
-							indexdef = usingpos + 7;
-						appendPQExpBuffer(&buf, " %s", indexdef);
+							/* Add these for all cases */
+							if (strcmp(PQgetvalue(result, i, 3), "t") == 0)
+								appendPQExpBufferStr(&buf, " CLUSTER");
 
-						/* Need these for deferrable PK/UNIQUE indexes */
-						if (strcmp(PQgetvalue(result, i, 8), "t") == 0)
-							appendPQExpBufferStr(&buf, " DEFERRABLE");
+							if (strcmp(PQgetvalue(result, i, 4), "t") != 0)
+								appendPQExpBufferStr(&buf, " INVALID");
 
-						if (strcmp(PQgetvalue(result, i, 9), "t") == 0)
-							appendPQExpBufferStr(&buf, " INITIALLY DEFERRED");
-					}
+							if (strcmp(PQgetvalue(result, i, 10), "t") == 0)
+								appendPQExpBufferStr(&buf, " REPLICA IDENTITY");
 
-					/* Add these for all cases */
-					if (strcmp(PQgetvalue(result, i, 3), "t") == 0)
-						appendPQExpBufferStr(&buf, " CLUSTER");
+							printTableAddFooter(&cont, buf.data);
 
-					if (strcmp(PQgetvalue(result, i, 4), "t") != 0)
-						appendPQExpBufferStr(&buf, " INVALID");
+							/* Print tablespace of the index on the same line */
+							if (pset.sversion >= 80000)
+								add_tablespace_footer(&cont, RELKIND_INDEX,
+													  atooid(PQgetvalue(result, i, 11)),
+													  false);
+						}
+					}
+					PQclear(result);
+				}
 
-					if (strcmp(PQgetvalue(result, i, 10), "t") == 0)
-						appendPQExpBufferStr(&buf, " REPLICA IDENTITY");
+				/* print table (and column) check constraints */
+				if (tableinfo.checks)
+				{
+					printfPQExpBuffer(&buf,
+									  "SELECT r.conname, "
+									  "pg_catalog.pg_get_constraintdef(r.oid, true)\n"
+									  "FROM pg_catalog.pg_constraint r\n"
+									  "WHERE r.conrelid = '%s' AND r.contype = 'c'\n"
+									  "ORDER BY 1;",
+									  oid);
+					result = PSQLexec(buf.data);
+					if (!result)
+						goto error_return;
+					else
+						tuples = PQntuples(result);
 
-					printTableAddFooter(&cont, buf.data);
+					if (tuples > 0)
+					{
+						printTableAddFooter(&cont, _("Check constraints:"));
+						for (i = 0; i < tuples; i++)
+						{
+							/* untranslated constraint name and def */
+							printfPQExpBuffer(&buf, "    \"%s\" %s",
+											  PQgetvalue(result, i, 0),
+											  PQgetvalue(result, i, 1));
 
-					/* Print tablespace of the index on the same line */
-					if (pset.sversion >= 80000)
-						add_tablespace_footer(&cont, RELKIND_INDEX,
-											  atooid(PQgetvalue(result, i, 11)),
-											  false);
+							printTableAddFooter(&cont, buf.data);
+						}
+					}
+					PQclear(result);
 				}
-			}
-			PQclear(result);
-		}
-
-		/* print table (and column) check constraints */
-		if (tableinfo.checks)
-		{
-			printfPQExpBuffer(&buf,
-							  "SELECT r.conname, "
-							  "pg_catalog.pg_get_constraintdef(r.oid, true)\n"
-							  "FROM pg_catalog.pg_constraint r\n"
-							  "WHERE r.conrelid = '%s' AND r.contype = 'c'\n"
-							  "ORDER BY 1;",
-							  oid);
-			result = PSQLexec(buf.data);
-			if (!result)
-				goto error_return;
-			else
-				tuples = PQntuples(result);
 
-			if (tuples > 0)
-			{
-				printTableAddFooter(&cont, _("Check constraints:"));
-				for (i = 0; i < tuples; i++)
+				/*
+				 * Print foreign-key constraints (there are none if no
+				 * triggers, except if the table is partitioned, in which case
+				 * the triggers appear in the partitions)
+				 */
+				if (tableinfo.hastriggers ||
+					tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
 				{
-					/* untranslated constraint name and def */
-					printfPQExpBuffer(&buf, "    \"%s\" %s",
-									  PQgetvalue(result, i, 0),
-									  PQgetvalue(result, i, 1));
-
-					printTableAddFooter(&cont, buf.data);
-				}
-			}
-			PQclear(result);
-		}
+					if (pset.sversion >= 120000 &&
+						(tableinfo.ispartition || tableinfo.relkind == RELKIND_PARTITIONED_TABLE))
+					{
+						/*
+						 * Put the constraints defined in this table first,
+						 * followed by the constraints defined in ancestor
+						 * partitioned tables.
+						 */
+						printfPQExpBuffer(&buf,
+										  "SELECT conrelid = '%s'::pg_catalog.regclass AS sametable,\n"
+										  "       conname,\n"
+										  "       pg_catalog.pg_get_constraintdef(oid, true) AS condef,\n"
+										  "       conrelid::pg_catalog.regclass AS ontable\n"
+										  "  FROM pg_catalog.pg_constraint,\n"
+										  "       pg_catalog.pg_partition_ancestors('%s')\n"
+										  " WHERE conrelid = relid AND contype = 'f' AND conparentid = 0\n"
+										  "ORDER BY sametable DESC, conname;",
+										  oid, oid);
+					}
+					else
+					{
+						printfPQExpBuffer(&buf,
+										  "SELECT true as sametable, conname,\n"
+										  "  pg_catalog.pg_get_constraintdef(r.oid, true) as condef,\n"
+										  "  conrelid::pg_catalog.regclass AS ontable\n"
+										  "FROM pg_catalog.pg_constraint r\n"
+										  "WHERE r.conrelid = '%s' AND r.contype = 'f'\n",
+										  oid);
+
+						if (pset.sversion >= 120000)
+							appendPQExpBufferStr(&buf, "     AND conparentid = 0\n");
+						appendPQExpBufferStr(&buf, "ORDER BY conname");
+					}
 
-		/*
-		 * Print foreign-key constraints (there are none if no triggers,
-		 * except if the table is partitioned, in which case the triggers
-		 * appear in the partitions)
-		 */
-		if (tableinfo.hastriggers ||
-			tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
-		{
-			if (pset.sversion >= 120000 &&
-				(tableinfo.ispartition || tableinfo.relkind == RELKIND_PARTITIONED_TABLE))
-			{
-				/*
-				 * Put the constraints defined in this table first, followed
-				 * by the constraints defined in ancestor partitioned tables.
-				 */
-				printfPQExpBuffer(&buf,
-								  "SELECT conrelid = '%s'::pg_catalog.regclass AS sametable,\n"
-								  "       conname,\n"
-								  "       pg_catalog.pg_get_constraintdef(oid, true) AS condef,\n"
-								  "       conrelid::pg_catalog.regclass AS ontable\n"
-								  "  FROM pg_catalog.pg_constraint,\n"
-								  "       pg_catalog.pg_partition_ancestors('%s')\n"
-								  " WHERE conrelid = relid AND contype = 'f' AND conparentid = 0\n"
-								  "ORDER BY sametable DESC, conname;",
-								  oid, oid);
-			}
-			else
-			{
-				printfPQExpBuffer(&buf,
-								  "SELECT true as sametable, conname,\n"
-								  "  pg_catalog.pg_get_constraintdef(r.oid, true) as condef,\n"
-								  "  conrelid::pg_catalog.regclass AS ontable\n"
-								  "FROM pg_catalog.pg_constraint r\n"
-								  "WHERE r.conrelid = '%s' AND r.contype = 'f'\n",
-								  oid);
+					result = PSQLexec(buf.data);
+					if (!result)
+						goto error_return;
+					else
+						tuples = PQntuples(result);
 
-				if (pset.sversion >= 120000)
-					appendPQExpBufferStr(&buf, "     AND conparentid = 0\n");
-				appendPQExpBufferStr(&buf, "ORDER BY conname");
-			}
+					if (tuples > 0)
+					{
+						int			i_sametable = PQfnumber(result, "sametable"),
+									i_conname = PQfnumber(result, "conname"),
+									i_condef = PQfnumber(result, "condef"),
+									i_ontable = PQfnumber(result, "ontable");
 
-			result = PSQLexec(buf.data);
-			if (!result)
-				goto error_return;
-			else
-				tuples = PQntuples(result);
+						printTableAddFooter(&cont, _("Foreign-key constraints:"));
+						for (i = 0; i < tuples; i++)
+						{
+							/*
+							 * Print untranslated constraint name and
+							 * definition. Use a "TABLE tab" prefix when the
+							 * constraint is defined in a parent partitioned
+							 * table.
+							 */
+							if (strcmp(PQgetvalue(result, i, i_sametable), "f") == 0)
+								printfPQExpBuffer(&buf, "    TABLE \"%s\" CONSTRAINT \"%s\" %s",
+												  PQgetvalue(result, i, i_ontable),
+												  PQgetvalue(result, i, i_conname),
+												  PQgetvalue(result, i, i_condef));
+							else
+								printfPQExpBuffer(&buf, "    \"%s\" %s",
+												  PQgetvalue(result, i, i_conname),
+												  PQgetvalue(result, i, i_condef));
 
-			if (tuples > 0)
-			{
-				int			i_sametable = PQfnumber(result, "sametable"),
-							i_conname = PQfnumber(result, "conname"),
-							i_condef = PQfnumber(result, "condef"),
-							i_ontable = PQfnumber(result, "ontable");
+							printTableAddFooter(&cont, buf.data);
+						}
+					}
+					PQclear(result);
+				}
 
-				printTableAddFooter(&cont, _("Foreign-key constraints:"));
-				for (i = 0; i < tuples; i++)
+				/* print incoming foreign-key references */
+				if (tableinfo.hastriggers ||
+					tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
 				{
-					/*
-					 * Print untranslated constraint name and definition. Use
-					 * a "TABLE tab" prefix when the constraint is defined in
-					 * a parent partitioned table.
-					 */
-					if (strcmp(PQgetvalue(result, i, i_sametable), "f") == 0)
-						printfPQExpBuffer(&buf, "    TABLE \"%s\" CONSTRAINT \"%s\" %s",
-										  PQgetvalue(result, i, i_ontable),
-										  PQgetvalue(result, i, i_conname),
-										  PQgetvalue(result, i, i_condef));
+					if (pset.sversion >= 120000)
+					{
+						printfPQExpBuffer(&buf,
+										  "SELECT conname, conrelid::pg_catalog.regclass AS ontable,\n"
+										  "       pg_catalog.pg_get_constraintdef(oid, true) AS condef\n"
+										  "  FROM pg_catalog.pg_constraint c\n"
+										  " WHERE confrelid IN (SELECT pg_catalog.pg_partition_ancestors('%s')\n"
+										  "                     UNION ALL VALUES ('%s'::pg_catalog.regclass))\n"
+										  "       AND contype = 'f' AND conparentid = 0\n"
+										  "ORDER BY conname;",
+										  oid, oid);
+					}
 					else
-						printfPQExpBuffer(&buf, "    \"%s\" %s",
-										  PQgetvalue(result, i, i_conname),
-										  PQgetvalue(result, i, i_condef));
+					{
+						printfPQExpBuffer(&buf,
+										  "SELECT conname, conrelid::pg_catalog.regclass AS ontable,\n"
+										  "       pg_catalog.pg_get_constraintdef(oid, true) AS condef\n"
+										  "  FROM pg_catalog.pg_constraint\n"
+										  " WHERE confrelid = %s AND contype = 'f'\n"
+										  "ORDER BY conname;",
+										  oid);
+					}
 
-					printTableAddFooter(&cont, buf.data);
-				}
-			}
-			PQclear(result);
-		}
+					result = PSQLexec(buf.data);
+					if (!result)
+						goto error_return;
+					else
+						tuples = PQntuples(result);
 
-		/* print incoming foreign-key references */
-		if (tableinfo.hastriggers ||
-			tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
-		{
-			if (pset.sversion >= 120000)
-			{
-				printfPQExpBuffer(&buf,
-								  "SELECT conname, conrelid::pg_catalog.regclass AS ontable,\n"
-								  "       pg_catalog.pg_get_constraintdef(oid, true) AS condef\n"
-								  "  FROM pg_catalog.pg_constraint c\n"
-								  " WHERE confrelid IN (SELECT pg_catalog.pg_partition_ancestors('%s')\n"
-								  "                     UNION ALL VALUES ('%s'::pg_catalog.regclass))\n"
-								  "       AND contype = 'f' AND conparentid = 0\n"
-								  "ORDER BY conname;",
-								  oid, oid);
-			}
-			else
-			{
-				printfPQExpBuffer(&buf,
-								  "SELECT conname, conrelid::pg_catalog.regclass AS ontable,\n"
-								  "       pg_catalog.pg_get_constraintdef(oid, true) AS condef\n"
-								  "  FROM pg_catalog.pg_constraint\n"
-								  " WHERE confrelid = %s AND contype = 'f'\n"
-								  "ORDER BY conname;",
-								  oid);
-			}
+					if (tuples > 0)
+					{
+						int			i_conname = PQfnumber(result, "conname"),
+									i_ontable = PQfnumber(result, "ontable"),
+									i_condef = PQfnumber(result, "condef");
 
-			result = PSQLexec(buf.data);
-			if (!result)
-				goto error_return;
-			else
-				tuples = PQntuples(result);
+						printTableAddFooter(&cont, _("Referenced by:"));
+						for (i = 0; i < tuples; i++)
+						{
+							printfPQExpBuffer(&buf, "    TABLE \"%s\" CONSTRAINT \"%s\" %s",
+											  PQgetvalue(result, i, i_ontable),
+											  PQgetvalue(result, i, i_conname),
+											  PQgetvalue(result, i, i_condef));
 
-			if (tuples > 0)
-			{
-				int			i_conname = PQfnumber(result, "conname"),
-							i_ontable = PQfnumber(result, "ontable"),
-							i_condef = PQfnumber(result, "condef");
+							printTableAddFooter(&cont, buf.data);
+						}
+					}
+					PQclear(result);
+				}
 
-				printTableAddFooter(&cont, _("Referenced by:"));
-				for (i = 0; i < tuples; i++)
+				/* print any row-level policies */
+				if (pset.sversion >= 90500)
 				{
-					printfPQExpBuffer(&buf, "    TABLE \"%s\" CONSTRAINT \"%s\" %s",
-									  PQgetvalue(result, i, i_ontable),
-									  PQgetvalue(result, i, i_conname),
-									  PQgetvalue(result, i, i_condef));
+					printfPQExpBuffer(&buf, "SELECT pol.polname,");
+					if (pset.sversion >= 100000)
+						appendPQExpBufferStr(&buf,
+											 " pol.polpermissive,\n");
+					else
+						appendPQExpBufferStr(&buf,
+											 " 't' as polpermissive,\n");
+					appendPQExpBuffer(&buf,
+									  "  CASE WHEN pol.polroles = '{0}' THEN NULL ELSE pg_catalog.array_to_string(array(select rolname from pg_catalog.pg_roles where oid = any (pol.polroles) order by 1),',') END,\n"
+									  "  pg_catalog.pg_get_expr(pol.polqual, pol.polrelid),\n"
+									  "  pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid),\n"
+									  "  CASE pol.polcmd\n"
+									  "    WHEN 'r' THEN 'SELECT'\n"
+									  "    WHEN 'a' THEN 'INSERT'\n"
+									  "    WHEN 'w' THEN 'UPDATE'\n"
+									  "    WHEN 'd' THEN 'DELETE'\n"
+									  "    END AS cmd\n"
+									  "FROM pg_catalog.pg_policy pol\n"
+									  "WHERE pol.polrelid = '%s' ORDER BY 1;",
+									  oid);
+
+					result = PSQLexec(buf.data);
+					if (!result)
+						goto error_return;
+					else
+						tuples = PQntuples(result);
 
-					printTableAddFooter(&cont, buf.data);
-				}
-			}
-			PQclear(result);
-		}
+					/*
+					 * Handle cases where RLS is enabled and there are
+					 * policies, or there aren't policies, or RLS isn't
+					 * enabled but there are policies
+					 */
+					if (tableinfo.rowsecurity && !tableinfo.forcerowsecurity && tuples > 0)
+						printTableAddFooter(&cont, _("Policies:"));
 
-		/* print any row-level policies */
-		if (pset.sversion >= 90500)
-		{
-			printfPQExpBuffer(&buf, "SELECT pol.polname,");
-			if (pset.sversion >= 100000)
-				appendPQExpBufferStr(&buf,
-									 " pol.polpermissive,\n");
-			else
-				appendPQExpBufferStr(&buf,
-									 " 't' as polpermissive,\n");
-			appendPQExpBuffer(&buf,
-							  "  CASE WHEN pol.polroles = '{0}' THEN NULL ELSE pg_catalog.array_to_string(array(select rolname from pg_catalog.pg_roles where oid = any (pol.polroles) order by 1),',') END,\n"
-							  "  pg_catalog.pg_get_expr(pol.polqual, pol.polrelid),\n"
-							  "  pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid),\n"
-							  "  CASE pol.polcmd\n"
-							  "    WHEN 'r' THEN 'SELECT'\n"
-							  "    WHEN 'a' THEN 'INSERT'\n"
-							  "    WHEN 'w' THEN 'UPDATE'\n"
-							  "    WHEN 'd' THEN 'DELETE'\n"
-							  "    END AS cmd\n"
-							  "FROM pg_catalog.pg_policy pol\n"
-							  "WHERE pol.polrelid = '%s' ORDER BY 1;",
-							  oid);
+					if (tableinfo.rowsecurity && tableinfo.forcerowsecurity && tuples > 0)
+						printTableAddFooter(&cont, _("Policies (forced row security enabled):"));
 
-			result = PSQLexec(buf.data);
-			if (!result)
-				goto error_return;
-			else
-				tuples = PQntuples(result);
+					if (tableinfo.rowsecurity && !tableinfo.forcerowsecurity && tuples == 0)
+						printTableAddFooter(&cont, _("Policies (row security enabled): (none)"));
 
-			/*
-			 * Handle cases where RLS is enabled and there are policies, or
-			 * there aren't policies, or RLS isn't enabled but there are
-			 * policies
-			 */
-			if (tableinfo.rowsecurity && !tableinfo.forcerowsecurity && tuples > 0)
-				printTableAddFooter(&cont, _("Policies:"));
+					if (tableinfo.rowsecurity && tableinfo.forcerowsecurity && tuples == 0)
+						printTableAddFooter(&cont, _("Policies (forced row security enabled): (none)"));
 
-			if (tableinfo.rowsecurity && tableinfo.forcerowsecurity && tuples > 0)
-				printTableAddFooter(&cont, _("Policies (forced row security enabled):"));
+					if (!tableinfo.rowsecurity && tuples > 0)
+						printTableAddFooter(&cont, _("Policies (row security disabled):"));
 
-			if (tableinfo.rowsecurity && !tableinfo.forcerowsecurity && tuples == 0)
-				printTableAddFooter(&cont, _("Policies (row security enabled): (none)"));
+					/* Might be an empty set - that's ok */
+					for (i = 0; i < tuples; i++)
+					{
+						printfPQExpBuffer(&buf, "    POLICY \"%s\"",
+										  PQgetvalue(result, i, 0));
 
-			if (tableinfo.rowsecurity && tableinfo.forcerowsecurity && tuples == 0)
-				printTableAddFooter(&cont, _("Policies (forced row security enabled): (none)"));
+						if (*(PQgetvalue(result, i, 1)) == 'f')
+							appendPQExpBufferStr(&buf, " AS RESTRICTIVE");
 
-			if (!tableinfo.rowsecurity && tuples > 0)
-				printTableAddFooter(&cont, _("Policies (row security disabled):"));
+						if (!PQgetisnull(result, i, 5))
+							appendPQExpBuffer(&buf, " FOR %s",
+											  PQgetvalue(result, i, 5));
 
-			/* Might be an empty set - that's ok */
-			for (i = 0; i < tuples; i++)
-			{
-				printfPQExpBuffer(&buf, "    POLICY \"%s\"",
-								  PQgetvalue(result, i, 0));
+						if (!PQgetisnull(result, i, 2))
+						{
+							appendPQExpBuffer(&buf, "\n      TO %s",
+											  PQgetvalue(result, i, 2));
+						}
 
-				if (*(PQgetvalue(result, i, 1)) == 'f')
-					appendPQExpBufferStr(&buf, " AS RESTRICTIVE");
+						if (!PQgetisnull(result, i, 3))
+							appendPQExpBuffer(&buf, "\n      USING (%s)",
+											  PQgetvalue(result, i, 3));
 
-				if (!PQgetisnull(result, i, 5))
-					appendPQExpBuffer(&buf, " FOR %s",
-									  PQgetvalue(result, i, 5));
+						if (!PQgetisnull(result, i, 4))
+							appendPQExpBuffer(&buf, "\n      WITH CHECK (%s)",
+											  PQgetvalue(result, i, 4));
 
-				if (!PQgetisnull(result, i, 2))
-				{
-					appendPQExpBuffer(&buf, "\n      TO %s",
-									  PQgetvalue(result, i, 2));
-				}
+						printTableAddFooter(&cont, buf.data);
 
-				if (!PQgetisnull(result, i, 3))
-					appendPQExpBuffer(&buf, "\n      USING (%s)",
-									  PQgetvalue(result, i, 3));
+					}
+					PQclear(result);
+				}
 
-				if (!PQgetisnull(result, i, 4))
-					appendPQExpBuffer(&buf, "\n      WITH CHECK (%s)",
-									  PQgetvalue(result, i, 4));
+				/* print any extended statistics */
+				if (pset.sversion >= 100000)
+				{
+					printfPQExpBuffer(&buf,
+									  "SELECT oid, "
+									  "stxrelid::pg_catalog.regclass, "
+									  "stxnamespace::pg_catalog.regnamespace AS nsp, "
+									  "stxname,\n"
+									  "  (SELECT pg_catalog.string_agg(pg_catalog.quote_ident(attname),', ')\n"
+									  "   FROM pg_catalog.unnest(stxkeys) s(attnum)\n"
+									  "   JOIN pg_catalog.pg_attribute a ON (stxrelid = a.attrelid AND\n"
+									  "        a.attnum = s.attnum AND NOT attisdropped)) AS columns,\n"
+									  "  'd' = any(stxkind) AS ndist_enabled,\n"
+									  "  'f' = any(stxkind) AS deps_enabled,\n"
+									  "  'm' = any(stxkind) AS mcv_enabled\n"
+									  "FROM pg_catalog.pg_statistic_ext stat "
+									  "WHERE stxrelid = '%s'\n"
+									  "ORDER BY 1;",
+									  oid);
+
+					result = PSQLexec(buf.data);
+					if (!result)
+						goto error_return;
+					else
+						tuples = PQntuples(result);
 
-				printTableAddFooter(&cont, buf.data);
+					if (tuples > 0)
+					{
+						printTableAddFooter(&cont, _("Statistics objects:"));
 
-			}
-			PQclear(result);
-		}
+						for (i = 0; i < tuples; i++)
+						{
+							bool		gotone = false;
 
-		/* print any extended statistics */
-		if (pset.sversion >= 100000)
-		{
-			printfPQExpBuffer(&buf,
-							  "SELECT oid, "
-							  "stxrelid::pg_catalog.regclass, "
-							  "stxnamespace::pg_catalog.regnamespace AS nsp, "
-							  "stxname,\n"
-							  "  (SELECT pg_catalog.string_agg(pg_catalog.quote_ident(attname),', ')\n"
-							  "   FROM pg_catalog.unnest(stxkeys) s(attnum)\n"
-							  "   JOIN pg_catalog.pg_attribute a ON (stxrelid = a.attrelid AND\n"
-							  "        a.attnum = s.attnum AND NOT attisdropped)) AS columns,\n"
-							  "  'd' = any(stxkind) AS ndist_enabled,\n"
-							  "  'f' = any(stxkind) AS deps_enabled,\n"
-							  "  'm' = any(stxkind) AS mcv_enabled\n"
-							  "FROM pg_catalog.pg_statistic_ext stat "
-							  "WHERE stxrelid = '%s'\n"
-							  "ORDER BY 1;",
-							  oid);
+							printfPQExpBuffer(&buf, "    ");
 
-			result = PSQLexec(buf.data);
-			if (!result)
-				goto error_return;
-			else
-				tuples = PQntuples(result);
+							/*
+							 * statistics object name (qualified with
+							 * namespace)
+							 */
+							appendPQExpBuffer(&buf, "\"%s\".\"%s\" (",
+											  PQgetvalue(result, i, 2),
+											  PQgetvalue(result, i, 3));
 
-			if (tuples > 0)
-			{
-				printTableAddFooter(&cont, _("Statistics objects:"));
+							/* options */
+							if (strcmp(PQgetvalue(result, i, 5), "t") == 0)
+							{
+								appendPQExpBufferStr(&buf, "ndistinct");
+								gotone = true;
+							}
 
-				for (i = 0; i < tuples; i++)
-				{
-					bool		gotone = false;
+							if (strcmp(PQgetvalue(result, i, 6), "t") == 0)
+							{
+								appendPQExpBuffer(&buf, "%sdependencies", gotone ? ", " : "");
+								gotone = true;
+							}
 
-					printfPQExpBuffer(&buf, "    ");
+							if (strcmp(PQgetvalue(result, i, 7), "t") == 0)
+							{
+								appendPQExpBuffer(&buf, "%smcv", gotone ? ", " : "");
+							}
 
-					/* statistics object name (qualified with namespace) */
-					appendPQExpBuffer(&buf, "\"%s\".\"%s\" (",
-									  PQgetvalue(result, i, 2),
-									  PQgetvalue(result, i, 3));
+							appendPQExpBuffer(&buf, ") ON %s FROM %s",
+											  PQgetvalue(result, i, 4),
+											  PQgetvalue(result, i, 1));
 
-					/* options */
-					if (strcmp(PQgetvalue(result, i, 5), "t") == 0)
-					{
-						appendPQExpBufferStr(&buf, "ndistinct");
-						gotone = true;
+							printTableAddFooter(&cont, buf.data);
+						}
 					}
+					PQclear(result);
+				}
 
-					if (strcmp(PQgetvalue(result, i, 6), "t") == 0)
+				/* print rules */
+				if (tableinfo.hasrules && tableinfo.relkind != RELKIND_MATVIEW)
+				{
+					if (pset.sversion >= 80300)
 					{
-						appendPQExpBuffer(&buf, "%sdependencies", gotone ? ", " : "");
-						gotone = true;
+						printfPQExpBuffer(&buf,
+										  "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
+										  "ev_enabled\n"
+										  "FROM pg_catalog.pg_rewrite r\n"
+										  "WHERE r.ev_class = '%s' ORDER BY 1;",
+										  oid);
 					}
-
-					if (strcmp(PQgetvalue(result, i, 7), "t") == 0)
+					else
 					{
-						appendPQExpBuffer(&buf, "%smcv", gotone ? ", " : "");
+						printfPQExpBuffer(&buf,
+										  "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
+										  "'O' AS ev_enabled\n"
+										  "FROM pg_catalog.pg_rewrite r\n"
+										  "WHERE r.ev_class = '%s' ORDER BY 1;",
+										  oid);
 					}
+					result = PSQLexec(buf.data);
+					if (!result)
+						goto error_return;
+					else
+						tuples = PQntuples(result);
 
-					appendPQExpBuffer(&buf, ") ON %s FROM %s",
-									  PQgetvalue(result, i, 4),
-									  PQgetvalue(result, i, 1));
-
-					printTableAddFooter(&cont, buf.data);
-				}
-			}
-			PQclear(result);
-		}
-
-		/* print rules */
-		if (tableinfo.hasrules && tableinfo.relkind != RELKIND_MATVIEW)
-		{
-			if (pset.sversion >= 80300)
-			{
-				printfPQExpBuffer(&buf,
-								  "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
-								  "ev_enabled\n"
-								  "FROM pg_catalog.pg_rewrite r\n"
-								  "WHERE r.ev_class = '%s' ORDER BY 1;",
-								  oid);
-			}
-			else
-			{
-				printfPQExpBuffer(&buf,
-								  "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
-								  "'O' AS ev_enabled\n"
-								  "FROM pg_catalog.pg_rewrite r\n"
-								  "WHERE r.ev_class = '%s' ORDER BY 1;",
-								  oid);
-			}
-			result = PSQLexec(buf.data);
-			if (!result)
-				goto error_return;
-			else
-				tuples = PQntuples(result);
-
-			if (tuples > 0)
-			{
-				bool		have_heading;
-				int			category;
-
-				for (category = 0; category < 4; category++)
-				{
-					have_heading = false;
-
-					for (i = 0; i < tuples; i++)
+					if (tuples > 0)
 					{
-						const char *ruledef;
-						bool		list_rule = false;
+						bool		have_heading;
+						int			category;
 
-						switch (category)
+						for (category = 0; category < 4; category++)
 						{
-							case 0:
-								if (*PQgetvalue(result, i, 2) == 'O')
-									list_rule = true;
-								break;
-							case 1:
-								if (*PQgetvalue(result, i, 2) == 'D')
-									list_rule = true;
-								break;
-							case 2:
-								if (*PQgetvalue(result, i, 2) == 'A')
-									list_rule = true;
-								break;
-							case 3:
-								if (*PQgetvalue(result, i, 2) == 'R')
-									list_rule = true;
-								break;
-						}
-						if (!list_rule)
-							continue;
+							have_heading = false;
 
-						if (!have_heading)
-						{
-							switch (category)
+							for (i = 0; i < tuples; i++)
 							{
-								case 0:
-									printfPQExpBuffer(&buf, _("Rules:"));
-									break;
-								case 1:
-									printfPQExpBuffer(&buf, _("Disabled rules:"));
-									break;
-								case 2:
-									printfPQExpBuffer(&buf, _("Rules firing always:"));
-									break;
-								case 3:
-									printfPQExpBuffer(&buf, _("Rules firing on replica only:"));
-									break;
+								const char *ruledef;
+								bool		list_rule = false;
+
+								switch (category)
+								{
+									case 0:
+										if (*PQgetvalue(result, i, 2) == 'O')
+											list_rule = true;
+										break;
+									case 1:
+										if (*PQgetvalue(result, i, 2) == 'D')
+											list_rule = true;
+										break;
+									case 2:
+										if (*PQgetvalue(result, i, 2) == 'A')
+											list_rule = true;
+										break;
+									case 3:
+										if (*PQgetvalue(result, i, 2) == 'R')
+											list_rule = true;
+										break;
+								}
+								if (!list_rule)
+									continue;
+
+								if (!have_heading)
+								{
+									switch (category)
+									{
+										case 0:
+											printfPQExpBuffer(&buf, _("Rules:"));
+											break;
+										case 1:
+											printfPQExpBuffer(&buf, _("Disabled rules:"));
+											break;
+										case 2:
+											printfPQExpBuffer(&buf, _("Rules firing always:"));
+											break;
+										case 3:
+											printfPQExpBuffer(&buf, _("Rules firing on replica only:"));
+											break;
+									}
+									printTableAddFooter(&cont, buf.data);
+									have_heading = true;
+								}
+
+								/*
+								 * Everything after "CREATE RULE" is echoed
+								 * verbatim
+								 */
+								ruledef = PQgetvalue(result, i, 1);
+								ruledef += 12;
+								printfPQExpBuffer(&buf, "    %s", ruledef);
+								printTableAddFooter(&cont, buf.data);
 							}
-							printTableAddFooter(&cont, buf.data);
-							have_heading = true;
 						}
-
-						/* Everything after "CREATE RULE" is echoed verbatim */
-						ruledef = PQgetvalue(result, i, 1);
-						ruledef += 12;
-						printfPQExpBuffer(&buf, "    %s", ruledef);
-						printTableAddFooter(&cont, buf.data);
 					}
+					PQclear(result);
 				}
-			}
-			PQclear(result);
-		}
 
-		/* print any publications */
-		if (pset.sversion >= 100000)
-		{
-			printfPQExpBuffer(&buf,
-							  "SELECT pubname\n"
-							  "FROM pg_catalog.pg_publication p\n"
-							  "JOIN pg_catalog.pg_publication_rel pr ON p.oid = pr.prpubid\n"
-							  "WHERE pr.prrelid = '%s'\n"
-							  "UNION ALL\n"
-							  "SELECT pubname\n"
-							  "FROM pg_catalog.pg_publication p\n"
-							  "WHERE p.puballtables AND pg_catalog.pg_relation_is_publishable('%s')\n"
-							  "ORDER BY 1;",
-							  oid, oid);
-
-			result = PSQLexec(buf.data);
-			if (!result)
-				goto error_return;
-			else
-				tuples = PQntuples(result);
+				/* print any publications */
+				if (pset.sversion >= 100000)
+				{
+					printfPQExpBuffer(&buf,
+									  "SELECT pubname\n"
+									  "FROM pg_catalog.pg_publication p\n"
+									  "JOIN pg_catalog.pg_publication_rel pr ON p.oid = pr.prpubid\n"
+									  "WHERE pr.prrelid = '%s'\n"
+									  "UNION ALL\n"
+									  "SELECT pubname\n"
+									  "FROM pg_catalog.pg_publication p\n"
+									  "WHERE p.puballtables AND pg_catalog.pg_relation_is_publishable('%s')\n"
+									  "ORDER BY 1;",
+									  oid, oid);
+
+					result = PSQLexec(buf.data);
+					if (!result)
+						goto error_return;
+					else
+						tuples = PQntuples(result);
 
-			if (tuples > 0)
-				printTableAddFooter(&cont, _("Publications:"));
+					if (tuples > 0)
+						printTableAddFooter(&cont, _("Publications:"));
 
-			/* Might be an empty set - that's ok */
-			for (i = 0; i < tuples; i++)
-			{
-				printfPQExpBuffer(&buf, "    \"%s\"",
-								  PQgetvalue(result, i, 0));
+					/* Might be an empty set - that's ok */
+					for (i = 0; i < tuples; i++)
+					{
+						printfPQExpBuffer(&buf, "    \"%s\"",
+										  PQgetvalue(result, i, 0));
 
-				printTableAddFooter(&cont, buf.data);
+						printTableAddFooter(&cont, buf.data);
+					}
+					PQclear(result);
+				}
 			}
-			PQclear(result);
-		}
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	/* Get view_def if table is a view or materialized view */
-	if ((tableinfo.relkind == RELKIND_VIEW ||
-		 tableinfo.relkind == RELKIND_MATVIEW) && verbose)
+	switch ((RelKind) tableinfo.relkind)
 	{
-		PGresult   *result;
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+			if (verbose)
+			{
+				PGresult   *result;
 
-		printfPQExpBuffer(&buf,
-						  "SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true);",
-						  oid);
-		result = PSQLexec(buf.data);
-		if (!result)
-			goto error_return;
+				printfPQExpBuffer(&buf,
+								  "SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true);",
+								  oid);
+				result = PSQLexec(buf.data);
+				if (!result)
+					goto error_return;
 
-		if (PQntuples(result) > 0)
-			view_def = pg_strdup(PQgetvalue(result, 0, 0));
+				if (PQntuples(result) > 0)
+					view_def = pg_strdup(PQgetvalue(result, 0, 0));
 
-		PQclear(result);
+				PQclear(result);
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	if (view_def)
@@ -3086,224 +3205,235 @@ describeOneTableDetails(const char *schemaname,
 	/*
 	 * Finish printing the footer information about a table.
 	 */
-	if (tableinfo.relkind == RELKIND_RELATION ||
-		tableinfo.relkind == RELKIND_MATVIEW ||
-		tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
-		tableinfo.relkind == RELKIND_PARTITIONED_TABLE ||
-		tableinfo.relkind == RELKIND_PARTITIONED_INDEX ||
-		tableinfo.relkind == RELKIND_TOASTVALUE)
+	switch ((RelKind) tableinfo.relkind)
 	{
-		bool		is_partitioned;
-		PGresult   *result;
-		int			tuples;
-
-		/* simplify some repeated tests below */
-		is_partitioned = (tableinfo.relkind == RELKIND_PARTITIONED_TABLE ||
-						  tableinfo.relkind == RELKIND_PARTITIONED_INDEX);
-
-		/* print foreign server name */
-		if (tableinfo.relkind == RELKIND_FOREIGN_TABLE)
-		{
-			char	   *ftoptions;
-
-			/* Footer information about foreign table */
-			printfPQExpBuffer(&buf,
-							  "SELECT s.srvname,\n"
-							  "  pg_catalog.array_to_string(ARRAY(\n"
-							  "    SELECT pg_catalog.quote_ident(option_name)"
-							  " || ' ' || pg_catalog.quote_literal(option_value)\n"
-							  "    FROM pg_catalog.pg_options_to_table(ftoptions)),  ', ')\n"
-							  "FROM pg_catalog.pg_foreign_table f,\n"
-							  "     pg_catalog.pg_foreign_server s\n"
-							  "WHERE f.ftrelid = '%s' AND s.oid = f.ftserver;",
-							  oid);
-			result = PSQLexec(buf.data);
-			if (!result)
-				goto error_return;
-			else if (PQntuples(result) != 1)
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_TOASTVALUE:
 			{
-				PQclear(result);
-				goto error_return;
-			}
+				bool		is_partitioned;
+				PGresult   *result;
+				int			tuples;
 
-			/* Print server name */
-			printfPQExpBuffer(&buf, _("Server: %s"),
-							  PQgetvalue(result, 0, 0));
-			printTableAddFooter(&cont, buf.data);
+				/* simplify some repeated tests below */
+				is_partitioned = (tableinfo.relkind == RELKIND_PARTITIONED_TABLE ||
+								  tableinfo.relkind == RELKIND_PARTITIONED_INDEX);
 
-			/* Print per-table FDW options, if any */
-			ftoptions = PQgetvalue(result, 0, 1);
-			if (ftoptions && ftoptions[0] != '\0')
-			{
-				printfPQExpBuffer(&buf, _("FDW options: (%s)"), ftoptions);
-				printTableAddFooter(&cont, buf.data);
-			}
-			PQclear(result);
-		}
+				/* print foreign server name */
+				if (tableinfo.relkind == RELKIND_FOREIGN_TABLE)
+				{
+					char	   *ftoptions;
+
+					/* Footer information about foreign table */
+					printfPQExpBuffer(&buf,
+									  "SELECT s.srvname,\n"
+									  "  pg_catalog.array_to_string(ARRAY(\n"
+									  "    SELECT pg_catalog.quote_ident(option_name)"
+									  " || ' ' || pg_catalog.quote_literal(option_value)\n"
+									  "    FROM pg_catalog.pg_options_to_table(ftoptions)),  ', ')\n"
+									  "FROM pg_catalog.pg_foreign_table f,\n"
+									  "     pg_catalog.pg_foreign_server s\n"
+									  "WHERE f.ftrelid = '%s' AND s.oid = f.ftserver;",
+									  oid);
+					result = PSQLexec(buf.data);
+					if (!result)
+						goto error_return;
+					else if (PQntuples(result) != 1)
+					{
+						PQclear(result);
+						goto error_return;
+					}
 
-		/* print tables inherited from (exclude partitioned parents) */
-		printfPQExpBuffer(&buf,
-						  "SELECT c.oid::pg_catalog.regclass\n"
-						  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
-						  "WHERE c.oid = i.inhparent AND i.inhrelid = '%s'\n"
-						  "  AND c.relkind != " CppAsString2(RELKIND_PARTITIONED_TABLE)
-						  " AND c.relkind != " CppAsString2(RELKIND_PARTITIONED_INDEX)
-						  "\nORDER BY inhseqno;",
-						  oid);
+					/* Print server name */
+					printfPQExpBuffer(&buf, _("Server: %s"),
+									  PQgetvalue(result, 0, 0));
+					printTableAddFooter(&cont, buf.data);
 
-		result = PSQLexec(buf.data);
-		if (!result)
-			goto error_return;
-		else
-		{
-			const char *s = _("Inherits");
-			int			sw = pg_wcswidth(s, strlen(s), pset.encoding);
+					/* Print per-table FDW options, if any */
+					ftoptions = PQgetvalue(result, 0, 1);
+					if (ftoptions && ftoptions[0] != '\0')
+					{
+						printfPQExpBuffer(&buf, _("FDW options: (%s)"), ftoptions);
+						printTableAddFooter(&cont, buf.data);
+					}
+					PQclear(result);
+				}
 
-			tuples = PQntuples(result);
+				/* print tables inherited from (exclude partitioned parents) */
+				printfPQExpBuffer(&buf,
+								  "SELECT c.oid::pg_catalog.regclass\n"
+								  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
+								  "WHERE c.oid = i.inhparent AND i.inhrelid = '%s'\n"
+								  "  AND c.relkind != " RelKindAsString(RELKIND_PARTITIONED_TABLE)
+								  " AND c.relkind != " RelKindAsString(RELKIND_PARTITIONED_INDEX)
+								  "\nORDER BY inhseqno;",
+								  oid);
 
-			for (i = 0; i < tuples; i++)
-			{
-				if (i == 0)
-					printfPQExpBuffer(&buf, "%s: %s",
-									  s, PQgetvalue(result, i, 0));
+				result = PSQLexec(buf.data);
+				if (!result)
+					goto error_return;
 				else
-					printfPQExpBuffer(&buf, "%*s  %s",
-									  sw, "", PQgetvalue(result, i, 0));
-				if (i < tuples - 1)
-					appendPQExpBufferChar(&buf, ',');
+				{
+					const char *s = _("Inherits");
+					int			sw = pg_wcswidth(s, strlen(s), pset.encoding);
 
-				printTableAddFooter(&cont, buf.data);
-			}
+					tuples = PQntuples(result);
 
-			PQclear(result);
-		}
+					for (i = 0; i < tuples; i++)
+					{
+						if (i == 0)
+							printfPQExpBuffer(&buf, "%s: %s",
+											  s, PQgetvalue(result, i, 0));
+						else
+							printfPQExpBuffer(&buf, "%*s  %s",
+											  sw, "", PQgetvalue(result, i, 0));
+						if (i < tuples - 1)
+							appendPQExpBufferChar(&buf, ',');
 
-		/* print child tables (with additional info if partitions) */
-		if (pset.sversion >= 100000)
-			printfPQExpBuffer(&buf,
-							  "SELECT c.oid::pg_catalog.regclass, c.relkind,"
-							  " pg_catalog.pg_get_expr(c.relpartbound, c.oid)\n"
-							  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
-							  "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
-							  "ORDER BY pg_catalog.pg_get_expr(c.relpartbound, c.oid) = 'DEFAULT',"
-							  " c.oid::pg_catalog.regclass::pg_catalog.text;",
-							  oid);
-		else if (pset.sversion >= 80300)
-			printfPQExpBuffer(&buf,
-							  "SELECT c.oid::pg_catalog.regclass, c.relkind, NULL\n"
-							  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
-							  "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
-							  "ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;",
-							  oid);
-		else
-			printfPQExpBuffer(&buf,
-							  "SELECT c.oid::pg_catalog.regclass, c.relkind, NULL\n"
-							  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
-							  "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
-							  "ORDER BY c.relname;",
-							  oid);
+						printTableAddFooter(&cont, buf.data);
+					}
 
-		result = PSQLexec(buf.data);
-		if (!result)
-			goto error_return;
-		tuples = PQntuples(result);
+					PQclear(result);
+				}
 
-		/*
-		 * For a partitioned table with no partitions, always print the number
-		 * of partitions as zero, even when verbose output is expected.
-		 * Otherwise, we will not print "Partitions" section for a partitioned
-		 * table without any partitions.
-		 */
-		if (is_partitioned && tuples == 0)
-		{
-			printfPQExpBuffer(&buf, _("Number of partitions: %d"), tuples);
-			printTableAddFooter(&cont, buf.data);
-		}
-		else if (!verbose)
-		{
-			/* print the number of child tables, if any */
-			if (tuples > 0)
-			{
-				if (is_partitioned)
-					printfPQExpBuffer(&buf, _("Number of partitions: %d (Use \\d+ to list them.)"), tuples);
+				/* print child tables (with additional info if partitions) */
+				if (pset.sversion >= 100000)
+					printfPQExpBuffer(&buf,
+									  "SELECT c.oid::pg_catalog.regclass, c.relkind,"
+									  " pg_catalog.pg_get_expr(c.relpartbound, c.oid)\n"
+									  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
+									  "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
+									  "ORDER BY pg_catalog.pg_get_expr(c.relpartbound, c.oid) = 'DEFAULT',"
+									  " c.oid::pg_catalog.regclass::pg_catalog.text;",
+									  oid);
+				else if (pset.sversion >= 80300)
+					printfPQExpBuffer(&buf,
+									  "SELECT c.oid::pg_catalog.regclass, c.relkind, NULL\n"
+									  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
+									  "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
+									  "ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;",
+									  oid);
 				else
-					printfPQExpBuffer(&buf, _("Number of child tables: %d (Use \\d+ to list them.)"), tuples);
-				printTableAddFooter(&cont, buf.data);
-			}
-		}
-		else
-		{
-			/* display the list of child tables */
-			const char *ct = is_partitioned ? _("Partitions") : _("Child tables");
-			int			ctw = pg_wcswidth(ct, strlen(ct), pset.encoding);
-
-			for (i = 0; i < tuples; i++)
-			{
-				char		child_relkind = *PQgetvalue(result, i, 1);
+					printfPQExpBuffer(&buf,
+									  "SELECT c.oid::pg_catalog.regclass, c.relkind, NULL\n"
+									  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
+									  "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
+									  "ORDER BY c.relname;",
+									  oid);
+
+				result = PSQLexec(buf.data);
+				if (!result)
+					goto error_return;
+				tuples = PQntuples(result);
 
-				if (i == 0)
-					printfPQExpBuffer(&buf, "%s: %s",
-									  ct, PQgetvalue(result, i, 0));
+				/*
+				 * For a partitioned table with no partitions, always print
+				 * the number of partitions as zero, even when verbose output
+				 * is expected. Otherwise, we will not print "Partitions"
+				 * section for a partitioned table without any partitions.
+				 */
+				if (is_partitioned && tuples == 0)
+				{
+					printfPQExpBuffer(&buf, _("Number of partitions: %d"), tuples);
+					printTableAddFooter(&cont, buf.data);
+				}
+				else if (!verbose)
+				{
+					/* print the number of child tables, if any */
+					if (tuples > 0)
+					{
+						if (is_partitioned)
+							printfPQExpBuffer(&buf, _("Number of partitions: %d (Use \\d+ to list them.)"), tuples);
+						else
+							printfPQExpBuffer(&buf, _("Number of child tables: %d (Use \\d+ to list them.)"), tuples);
+						printTableAddFooter(&cont, buf.data);
+					}
+				}
 				else
-					printfPQExpBuffer(&buf, "%*s  %s",
-									  ctw, "", PQgetvalue(result, i, 0));
-				if (!PQgetisnull(result, i, 2))
-					appendPQExpBuffer(&buf, " %s", PQgetvalue(result, i, 2));
-				if (child_relkind == RELKIND_PARTITIONED_TABLE ||
-					child_relkind == RELKIND_PARTITIONED_INDEX)
-					appendPQExpBufferStr(&buf, ", PARTITIONED");
-				if (i < tuples - 1)
-					appendPQExpBufferChar(&buf, ',');
+				{
+					/* display the list of child tables */
+					const char *ct = is_partitioned ? _("Partitions") : _("Child tables");
+					int			ctw = pg_wcswidth(ct, strlen(ct), pset.encoding);
 
-				printTableAddFooter(&cont, buf.data);
-			}
-		}
-		PQclear(result);
+					for (i = 0; i < tuples; i++)
+					{
+						char		child_relkind = *PQgetvalue(result, i, 1);
+
+						if (i == 0)
+							printfPQExpBuffer(&buf, "%s: %s",
+											  ct, PQgetvalue(result, i, 0));
+						else
+							printfPQExpBuffer(&buf, "%*s  %s",
+											  ctw, "", PQgetvalue(result, i, 0));
+						if (!PQgetisnull(result, i, 2))
+							appendPQExpBuffer(&buf, " %s", PQgetvalue(result, i, 2));
+						if (child_relkind == RELKIND_PARTITIONED_TABLE ||
+							child_relkind == RELKIND_PARTITIONED_INDEX)
+							appendPQExpBufferStr(&buf, ", PARTITIONED");
+						if (i < tuples - 1)
+							appendPQExpBufferChar(&buf, ',');
 
-		/* Table type */
-		if (tableinfo.reloftype)
-		{
-			printfPQExpBuffer(&buf, _("Typed table of type: %s"), tableinfo.reloftype);
-			printTableAddFooter(&cont, buf.data);
-		}
+						printTableAddFooter(&cont, buf.data);
+					}
+				}
+				PQclear(result);
 
-		if (verbose &&
-			(tableinfo.relkind == RELKIND_RELATION ||
-			 tableinfo.relkind == RELKIND_MATVIEW) &&
+				/* Table type */
+				if (tableinfo.reloftype)
+				{
+					printfPQExpBuffer(&buf, _("Typed table of type: %s"), tableinfo.reloftype);
+					printTableAddFooter(&cont, buf.data);
+				}
 
-		/*
-		 * No need to display default values; we already display a REPLICA
-		 * IDENTITY marker on indexes.
-		 */
-			tableinfo.relreplident != 'i' &&
-			((strcmp(schemaname, "pg_catalog") != 0 && tableinfo.relreplident != 'd') ||
-			 (strcmp(schemaname, "pg_catalog") == 0 && tableinfo.relreplident != 'n')))
-		{
-			const char *s = _("Replica Identity");
+				if (verbose &&
+					(tableinfo.relkind == RELKIND_RELATION ||
+					 tableinfo.relkind == RELKIND_MATVIEW) &&
 
-			printfPQExpBuffer(&buf, "%s: %s",
-							  s,
-							  tableinfo.relreplident == 'f' ? "FULL" :
-							  tableinfo.relreplident == 'n' ? "NOTHING" :
-							  "???");
+				/*
+				 * No need to display default values; we already display a
+				 * REPLICA IDENTITY marker on indexes.
+				 */
+					tableinfo.relreplident != 'i' &&
+					((strcmp(schemaname, "pg_catalog") != 0 && tableinfo.relreplident != 'd') ||
+					 (strcmp(schemaname, "pg_catalog") == 0 && tableinfo.relreplident != 'n')))
+				{
+					const char *s = _("Replica Identity");
 
-			printTableAddFooter(&cont, buf.data);
-		}
+					printfPQExpBuffer(&buf, "%s: %s",
+									  s,
+									  tableinfo.relreplident == 'f' ? "FULL" :
+									  tableinfo.relreplident == 'n' ? "NOTHING" :
+									  "???");
 
-		/* OIDs, if verbose and not a materialized view */
-		if (verbose && tableinfo.relkind != RELKIND_MATVIEW && tableinfo.hasoids)
-			printTableAddFooter(&cont, _("Has OIDs: yes"));
+					printTableAddFooter(&cont, buf.data);
+				}
 
-		/* Tablespace info */
-		add_tablespace_footer(&cont, tableinfo.relkind, tableinfo.tablespace,
-							  true);
+				/* OIDs, if verbose and not a materialized view */
+				if (verbose && tableinfo.relkind != RELKIND_MATVIEW && tableinfo.hasoids)
+					printTableAddFooter(&cont, _("Has OIDs: yes"));
 
-		/* Access method info */
-		if (verbose && tableinfo.relam != NULL && !pset.hide_tableam)
-		{
-			printfPQExpBuffer(&buf, _("Access method: %s"), tableinfo.relam);
-			printTableAddFooter(&cont, buf.data);
-		}
+				/* Tablespace info */
+				add_tablespace_footer(&cont, tableinfo.relkind, tableinfo.tablespace,
+									  true);
+
+				/* Access method info */
+				if (verbose && tableinfo.relam != NULL && !pset.hide_tableam)
+				{
+					printfPQExpBuffer(&buf, _("Access method: %s"), tableinfo.relam);
+					printTableAddFooter(&cont, buf.data);
+				}
+			}
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 
 	/* reloptions, if verbose */
@@ -3348,59 +3478,71 @@ add_tablespace_footer(printTableContent *const cont, char relkind,
 					  Oid tablespace, const bool newline)
 {
 	/* relkinds for which we support tablespaces */
-	if (relkind == RELKIND_RELATION ||
-		relkind == RELKIND_MATVIEW ||
-		relkind == RELKIND_INDEX ||
-		relkind == RELKIND_PARTITIONED_TABLE ||
-		relkind == RELKIND_PARTITIONED_INDEX ||
-		relkind == RELKIND_TOASTVALUE)
+	switch ((RelKind) relkind)
 	{
-		/*
-		 * We ignore the database default tablespace so that users not using
-		 * tablespaces don't need to know about them.  This case also covers
-		 * pre-8.0 servers, for which tablespace will always be 0.
-		 */
-		if (tablespace != 0)
-		{
-			PGresult   *result = NULL;
-			PQExpBufferData buf;
-
-			initPQExpBuffer(&buf);
-			printfPQExpBuffer(&buf,
-							  "SELECT spcname FROM pg_catalog.pg_tablespace\n"
-							  "WHERE oid = '%u';", tablespace);
-			result = PSQLexec(buf.data);
-			if (!result)
-			{
-				termPQExpBuffer(&buf);
-				return;
-			}
-			/* Should always be the case, but.... */
-			if (PQntuples(result) > 0)
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_TOASTVALUE:
 			{
-				if (newline)
-				{
-					/* Add the tablespace as a new footer */
-					printfPQExpBuffer(&buf, _("Tablespace: \"%s\""),
-									  PQgetvalue(result, 0, 0));
-					printTableAddFooter(cont, buf.data);
-				}
-				else
+				/*
+				 * We ignore the database default tablespace so that users not
+				 * using tablespaces don't need to know about them.  This case
+				 * also covers pre-8.0 servers, for which tablespace will
+				 * always be 0.
+				 */
+				if (tablespace != 0)
 				{
-					/* Append the tablespace to the latest footer */
-					printfPQExpBuffer(&buf, "%s", cont->footer->data);
-
-					/*-------
-					   translator: before this string there's an index description like
-					   '"foo_pkey" PRIMARY KEY, btree (a)' */
-					appendPQExpBuffer(&buf, _(", tablespace \"%s\""),
-									  PQgetvalue(result, 0, 0));
-					printTableSetFooter(cont, buf.data);
+					PGresult   *result = NULL;
+					PQExpBufferData buf;
+
+					initPQExpBuffer(&buf);
+					printfPQExpBuffer(&buf,
+									  "SELECT spcname FROM pg_catalog.pg_tablespace\n"
+									  "WHERE oid = '%u';", tablespace);
+					result = PSQLexec(buf.data);
+					if (!result)
+					{
+						termPQExpBuffer(&buf);
+						return;
+					}
+					/* Should always be the case, but.... */
+					if (PQntuples(result) > 0)
+					{
+						if (newline)
+						{
+							/* Add the tablespace as a new footer */
+							printfPQExpBuffer(&buf, _("Tablespace: \"%s\""),
+											  PQgetvalue(result, 0, 0));
+							printTableAddFooter(cont, buf.data);
+						}
+						else
+						{
+							/* Append the tablespace to the latest footer */
+							printfPQExpBuffer(&buf, "%s", cont->footer->data);
+
+							/*-------
+							   translator: before this string there's an index description like
+							   '"foo_pkey" PRIMARY KEY, btree (a)' */
+							appendPQExpBuffer(&buf, _(", tablespace \"%s\""),
+											  PQgetvalue(result, 0, 0));
+							printTableSetFooter(cont, buf.data);
+						}
+					}
+					PQclear(result);
+					termPQExpBuffer(&buf);
 				}
 			}
-			PQclear(result);
-			termPQExpBuffer(&buf);
-		}
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_NULL:
+		default:
+			break;
 	}
 }
 
@@ -3694,15 +3836,15 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
 					  "SELECT n.nspname as \"%s\",\n"
 					  "  c.relname as \"%s\",\n"
 					  "  CASE c.relkind"
-					  " WHEN " CppAsString2(RELKIND_RELATION) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_VIEW) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_MATVIEW) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_INDEX) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_SEQUENCE) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_RELATION) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_VIEW) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_MATVIEW) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_INDEX) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_SEQUENCE) " THEN '%s'"
 					  " WHEN 's' THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_PARTITIONED_INDEX) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_FOREIGN_TABLE) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_PARTITIONED_INDEX) " THEN '%s'"
 					  " END as \"%s\",\n"
 					  "  pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
 					  gettext_noop("Schema"),
@@ -3779,21 +3921,21 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
 
 	appendPQExpBufferStr(&buf, "\nWHERE c.relkind IN (");
 	if (showTables)
-		appendPQExpBufferStr(&buf, CppAsString2(RELKIND_RELATION) ","
-							 CppAsString2(RELKIND_PARTITIONED_TABLE) ",");
+		appendPQExpBufferStr(&buf, RelKindAsString(RELKIND_RELATION) ","
+							 RelKindAsString(RELKIND_PARTITIONED_TABLE) ",");
 	if (showViews)
-		appendPQExpBufferStr(&buf, CppAsString2(RELKIND_VIEW) ",");
+		appendPQExpBufferStr(&buf, RelKindAsString(RELKIND_VIEW) ",");
 	if (showMatViews)
-		appendPQExpBufferStr(&buf, CppAsString2(RELKIND_MATVIEW) ",");
+		appendPQExpBufferStr(&buf, RelKindAsString(RELKIND_MATVIEW) ",");
 	if (showIndexes)
-		appendPQExpBufferStr(&buf, CppAsString2(RELKIND_INDEX) ","
-							 CppAsString2(RELKIND_PARTITIONED_INDEX) ",");
+		appendPQExpBufferStr(&buf, RelKindAsString(RELKIND_INDEX) ","
+							 RelKindAsString(RELKIND_PARTITIONED_INDEX) ",");
 	if (showSeq)
-		appendPQExpBufferStr(&buf, CppAsString2(RELKIND_SEQUENCE) ",");
+		appendPQExpBufferStr(&buf, RelKindAsString(RELKIND_SEQUENCE) ",");
 	if (showSystem || pattern)
 		appendPQExpBufferStr(&buf, "'s',"); /* was RELKIND_SPECIAL */
 	if (showForeign)
-		appendPQExpBufferStr(&buf, CppAsString2(RELKIND_FOREIGN_TABLE) ",");
+		appendPQExpBufferStr(&buf, RelKindAsString(RELKIND_FOREIGN_TABLE) ",");
 
 	appendPQExpBufferStr(&buf, "''");	/* dummy */
 	appendPQExpBufferStr(&buf, ")\n");
@@ -3921,8 +4063,8 @@ listPartitionedTables(const char *reltypes, const char *pattern, bool verbose)
 	{
 		appendPQExpBuffer(&buf,
 						  ",\n  CASE c.relkind"
-						  " WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
-						  " WHEN " CppAsString2(RELKIND_PARTITIONED_INDEX) " THEN '%s'"
+						  " WHEN " RelKindAsString(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
+						  " WHEN " RelKindAsString(RELKIND_PARTITIONED_INDEX) " THEN '%s'"
 						  " END as \"%s\"",
 						  gettext_noop("partitioned table"),
 						  gettext_noop("partitioned index"),
@@ -4012,9 +4154,9 @@ listPartitionedTables(const char *reltypes, const char *pattern, bool verbose)
 
 	appendPQExpBufferStr(&buf, "\nWHERE c.relkind IN (");
 	if (showTables)
-		appendPQExpBufferStr(&buf, CppAsString2(RELKIND_PARTITIONED_TABLE) ",");
+		appendPQExpBufferStr(&buf, RelKindAsString(RELKIND_PARTITIONED_TABLE) ",");
 	if (showIndexes)
-		appendPQExpBufferStr(&buf, CppAsString2(RELKIND_PARTITIONED_INDEX) ",");
+		appendPQExpBufferStr(&buf, RelKindAsString(RELKIND_PARTITIONED_INDEX) ",");
 	appendPQExpBufferStr(&buf, "''");	/* dummy */
 	appendPQExpBufferStr(&buf, ")\n");
 
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index eb018854a5..c56beb579b 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -354,7 +354,7 @@ static const SchemaQuery Query_for_list_of_datatypes = {
 	.catname = "pg_catalog.pg_type t",
 	/* selcondition --- ignore table rowtypes and array types */
 	.selcondition = "(t.typrelid = 0 "
-	" OR (SELECT c.relkind = " CppAsString2(RELKIND_COMPOSITE_TYPE)
+	" OR (SELECT c.relkind = " RelKindAsString(RELKIND_COMPOSITE_TYPE)
 	"     FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "
 	"AND t.typname !~ '^_'",
 	.viscondition = "pg_catalog.pg_type_is_visible(t.oid)",
@@ -366,7 +366,7 @@ static const SchemaQuery Query_for_list_of_datatypes = {
 static const SchemaQuery Query_for_list_of_composite_datatypes = {
 	.catname = "pg_catalog.pg_type t",
 	/* selcondition --- only get composite types */
-	.selcondition = "(SELECT c.relkind = " CppAsString2(RELKIND_COMPOSITE_TYPE)
+	.selcondition = "(SELECT c.relkind = " RelKindAsString(RELKIND_COMPOSITE_TYPE)
 	" FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid) "
 	"AND t.typname !~ '^_'",
 	.viscondition = "pg_catalog.pg_type_is_visible(t.oid)",
@@ -425,7 +425,7 @@ static const SchemaQuery Query_for_list_of_routines = {
 
 static const SchemaQuery Query_for_list_of_sequences = {
 	.catname = "pg_catalog.pg_class c",
-	.selcondition = "c.relkind IN (" CppAsString2(RELKIND_SEQUENCE) ")",
+	.selcondition = "c.relkind IN (" RelKindAsString(RELKIND_SEQUENCE) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -433,7 +433,7 @@ static const SchemaQuery Query_for_list_of_sequences = {
 
 static const SchemaQuery Query_for_list_of_foreign_tables = {
 	.catname = "pg_catalog.pg_class c",
-	.selcondition = "c.relkind IN (" CppAsString2(RELKIND_FOREIGN_TABLE) ")",
+	.selcondition = "c.relkind IN (" RelKindAsString(RELKIND_FOREIGN_TABLE) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -442,8 +442,8 @@ static const SchemaQuery Query_for_list_of_foreign_tables = {
 static const SchemaQuery Query_for_list_of_tables = {
 	.catname = "pg_catalog.pg_class c",
 	.selcondition =
-	"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-	CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
+	"c.relkind IN (" RelKindAsString(RELKIND_RELATION) ", "
+	RelKindAsString(RELKIND_PARTITIONED_TABLE) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -451,7 +451,7 @@ static const SchemaQuery Query_for_list_of_tables = {
 
 static const SchemaQuery Query_for_list_of_partitioned_tables = {
 	.catname = "pg_catalog.pg_class c",
-	.selcondition = "c.relkind IN (" CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
+	.selcondition = "c.relkind IN (" RelKindAsString(RELKIND_PARTITIONED_TABLE) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -459,7 +459,7 @@ static const SchemaQuery Query_for_list_of_partitioned_tables = {
 
 static const SchemaQuery Query_for_list_of_views = {
 	.catname = "pg_catalog.pg_class c",
-	.selcondition = "c.relkind IN (" CppAsString2(RELKIND_VIEW) ")",
+	.selcondition = "c.relkind IN (" RelKindAsString(RELKIND_VIEW) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -467,7 +467,7 @@ static const SchemaQuery Query_for_list_of_views = {
 
 static const SchemaQuery Query_for_list_of_matviews = {
 	.catname = "pg_catalog.pg_class c",
-	.selcondition = "c.relkind IN (" CppAsString2(RELKIND_MATVIEW) ")",
+	.selcondition = "c.relkind IN (" RelKindAsString(RELKIND_MATVIEW) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -476,8 +476,8 @@ static const SchemaQuery Query_for_list_of_matviews = {
 static const SchemaQuery Query_for_list_of_indexes = {
 	.catname = "pg_catalog.pg_class c",
 	.selcondition =
-	"c.relkind IN (" CppAsString2(RELKIND_INDEX) ", "
-	CppAsString2(RELKIND_PARTITIONED_INDEX) ")",
+	"c.relkind IN (" RelKindAsString(RELKIND_INDEX) ", "
+	RelKindAsString(RELKIND_PARTITIONED_INDEX) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -485,7 +485,7 @@ static const SchemaQuery Query_for_list_of_indexes = {
 
 static const SchemaQuery Query_for_list_of_partitioned_indexes = {
 	.catname = "pg_catalog.pg_class c",
-	.selcondition = "c.relkind = " CppAsString2(RELKIND_PARTITIONED_INDEX),
+	.selcondition = "c.relkind = " RelKindAsString(RELKIND_PARTITIONED_INDEX),
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -503,8 +503,8 @@ static const SchemaQuery Query_for_list_of_relations = {
 /* partitioned relations */
 static const SchemaQuery Query_for_list_of_partitioned_relations = {
 	.catname = "pg_catalog.pg_class c",
-	.selcondition = "c.relkind IN (" CppAsString2(RELKIND_PARTITIONED_TABLE)
-	", " CppAsString2(RELKIND_PARTITIONED_INDEX) ")",
+	.selcondition = "c.relkind IN (" RelKindAsString(RELKIND_PARTITIONED_TABLE)
+	", " RelKindAsString(RELKIND_PARTITIONED_INDEX) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -521,10 +521,10 @@ static const SchemaQuery Query_for_list_of_operator_families = {
 static const SchemaQuery Query_for_list_of_updatables = {
 	.catname = "pg_catalog.pg_class c",
 	.selcondition =
-	"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-	CppAsString2(RELKIND_FOREIGN_TABLE) ", "
-	CppAsString2(RELKIND_VIEW) ", "
-	CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
+	"c.relkind IN (" RelKindAsString(RELKIND_RELATION) ", "
+	RelKindAsString(RELKIND_FOREIGN_TABLE) ", "
+	RelKindAsString(RELKIND_VIEW) ", "
+	RelKindAsString(RELKIND_PARTITIONED_TABLE) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -534,12 +534,12 @@ static const SchemaQuery Query_for_list_of_updatables = {
 static const SchemaQuery Query_for_list_of_selectables = {
 	.catname = "pg_catalog.pg_class c",
 	.selcondition =
-	"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-	CppAsString2(RELKIND_SEQUENCE) ", "
-	CppAsString2(RELKIND_VIEW) ", "
-	CppAsString2(RELKIND_MATVIEW) ", "
-	CppAsString2(RELKIND_FOREIGN_TABLE) ", "
-	CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
+	"c.relkind IN (" RelKindAsString(RELKIND_RELATION) ", "
+	RelKindAsString(RELKIND_SEQUENCE) ", "
+	RelKindAsString(RELKIND_VIEW) ", "
+	RelKindAsString(RELKIND_MATVIEW) ", "
+	RelKindAsString(RELKIND_FOREIGN_TABLE) ", "
+	RelKindAsString(RELKIND_PARTITIONED_TABLE) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -552,10 +552,10 @@ static const SchemaQuery Query_for_list_of_selectables = {
 static const SchemaQuery Query_for_list_of_analyzables = {
 	.catname = "pg_catalog.pg_class c",
 	.selcondition =
-	"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-	CppAsString2(RELKIND_PARTITIONED_TABLE) ", "
-	CppAsString2(RELKIND_MATVIEW) ", "
-	CppAsString2(RELKIND_FOREIGN_TABLE) ")",
+	"c.relkind IN (" RelKindAsString(RELKIND_RELATION) ", "
+	RelKindAsString(RELKIND_PARTITIONED_TABLE) ", "
+	RelKindAsString(RELKIND_MATVIEW) ", "
+	RelKindAsString(RELKIND_FOREIGN_TABLE) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -565,9 +565,9 @@ static const SchemaQuery Query_for_list_of_analyzables = {
 static const SchemaQuery Query_for_list_of_indexables = {
 	.catname = "pg_catalog.pg_class c",
 	.selcondition =
-	"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-	CppAsString2(RELKIND_PARTITIONED_TABLE) ", "
-	CppAsString2(RELKIND_MATVIEW) ")",
+	"c.relkind IN (" RelKindAsString(RELKIND_RELATION) ", "
+	RelKindAsString(RELKIND_PARTITIONED_TABLE) ", "
+	RelKindAsString(RELKIND_MATVIEW) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -577,8 +577,8 @@ static const SchemaQuery Query_for_list_of_indexables = {
 static const SchemaQuery Query_for_list_of_vacuumables = {
 	.catname = "pg_catalog.pg_class c",
 	.selcondition =
-	"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-	CppAsString2(RELKIND_MATVIEW) ")",
+	"c.relkind IN (" RelKindAsString(RELKIND_RELATION) ", "
+	RelKindAsString(RELKIND_MATVIEW) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
diff --git a/src/bin/scripts/reindexdb.c b/src/bin/scripts/reindexdb.c
index b7b19ccc1c..1b921a1483 100644
--- a/src/bin/scripts/reindexdb.c
+++ b/src/bin/scripts/reindexdb.c
@@ -621,8 +621,8 @@ get_parallel_object_list(PGconn *conn, ReindexType type,
 							  " ON c.relnamespace = ns.oid\n"
 							  " WHERE ns.nspname != 'pg_catalog'\n"
 							  "   AND c.relkind IN ("
-							  CppAsString2(RELKIND_RELATION) ", "
-							  CppAsString2(RELKIND_MATVIEW) ")\n"
+							  RelKindAsString(RELKIND_RELATION) ", "
+							  RelKindAsString(RELKIND_MATVIEW) ")\n"
 							  " ORDER BY c.relpages DESC;");
 			break;
 
@@ -643,8 +643,8 @@ get_parallel_object_list(PGconn *conn, ReindexType type,
 								  " JOIN pg_catalog.pg_namespace ns"
 								  " ON c.relnamespace = ns.oid\n"
 								  " WHERE c.relkind IN ("
-								  CppAsString2(RELKIND_RELATION) ", "
-								  CppAsString2(RELKIND_MATVIEW) ")\n"
+								  RelKindAsString(RELKIND_RELATION) ", "
+								  RelKindAsString(RELKIND_MATVIEW) ")\n"
 								  " AND ns.nspname IN (");
 
 				for (cell = user_list->head; cell; cell = cell->next)
diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c
index 6a3c941158..9a90e820f4 100644
--- a/src/bin/scripts/vacuumdb.c
+++ b/src/bin/scripts/vacuumdb.c
@@ -573,8 +573,8 @@ vacuum_one_database(const char *dbname, vacuumingOptions *vacopts,
 	if (!tables_listed)
 	{
 		appendPQExpBufferStr(&catalog_query, " WHERE c.relkind OPERATOR(pg_catalog.=) ANY (array["
-							 CppAsString2(RELKIND_RELATION) ", "
-							 CppAsString2(RELKIND_MATVIEW) "])\n");
+							 RelKindAsString(RELKIND_RELATION) ", "
+							 RelKindAsString(RELKIND_MATVIEW) "])\n");
 		has_where = true;
 	}
 
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index 78b33b2a7f..6e9955fe6a 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -154,16 +154,34 @@ typedef FormData_pg_class *Form_pg_class;
 
 #ifdef EXPOSE_TO_CLIENT_CODE
 
-#define		  RELKIND_RELATION		  'r'	/* ordinary table */
-#define		  RELKIND_INDEX			  'i'	/* secondary index */
-#define		  RELKIND_SEQUENCE		  'S'	/* sequence object */
-#define		  RELKIND_TOASTVALUE	  't'	/* for out-of-line values */
-#define		  RELKIND_VIEW			  'v'	/* view */
-#define		  RELKIND_MATVIEW		  'm'	/* materialized view */
-#define		  RELKIND_COMPOSITE_TYPE  'c'	/* composite type */
-#define		  RELKIND_FOREIGN_TABLE   'f'	/* foreign table */
-#define		  RELKIND_PARTITIONED_TABLE 'p' /* partitioned table */
-#define		  RELKIND_PARTITIONED_INDEX 'I' /* partitioned index */
+typedef enum RelKind
+{
+	RELKIND_RELATION = 'r',		/* ordinary table */
+	RELKIND_INDEX = 'i',		/* secondary index */
+	RELKIND_SEQUENCE = 'S',		/* sequence object */
+	RELKIND_TOASTVALUE = 't',	/* for out-of-line values */
+	RELKIND_VIEW = 'v',			/* view */
+	RELKIND_MATVIEW = 'm',		/* materialized view */
+	RELKIND_COMPOSITE_TYPE = 'c',	/* composite type */
+	RELKIND_FOREIGN_TABLE = 'f',	/* foreign table */
+	RELKIND_PARTITIONED_TABLE = 'p',	/* partitioned table */
+	RELKIND_PARTITIONED_INDEX = 'I',	/* partitioned index */
+	RELKIND_NULL = '\0'			/* unset */
+} RelKind;
+
+#define chr_RELKIND_RELATION			'r'
+#define chr_RELKIND_INDEX				'i'
+#define chr_RELKIND_SEQUENCE			'S'
+#define chr_RELKIND_TOASTVALUE			't'
+#define chr_RELKIND_VIEW				'v'
+#define chr_RELKIND_MATVIEW				'm'
+#define chr_RELKIND_COMPOSITE_TYPE		'c'
+#define chr_RELKIND_FOREIGN_TABLE		'f'
+#define chr_RELKIND_PARTITIONED_TABLE	'p'
+#define chr_RELKIND_PARTITIONED_INDEX	'I'
+#define chr_RELKIND_NULL				'\0'
+
+#define RelKindAsString(x) CppAsString2(chr_##x)
 
 #define		  RELPERSISTENCE_PERMANENT	'p' /* regular table */
 #define		  RELPERSISTENCE_UNLOGGED	'u' /* unlogged permanent table */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index f5dfa32d55..a9a2bf1fb6 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -2110,7 +2110,7 @@ typedef struct AggregateInstrumentation
 	Size		hash_mem_peak;	/* peak hash table memory usage */
 	uint64		hash_disk_used; /* kB of disk space used */
 	int			hash_batches_used;	/* batches used during entire execution */
-} AggregateInstrumentation;
+}			AggregateInstrumentation;
 
 /* ----------------
  *	 Shared memory container for per-worker aggregate information
@@ -2120,7 +2120,7 @@ typedef struct SharedAggInfo
 {
 	int			num_workers;
 	AggregateInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER];
-} SharedAggInfo;
+}			SharedAggInfo;
 
 /* ---------------------
  *	AggState information
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index b20e2ad4f6..65602a8763 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -81,7 +81,7 @@ typedef enum
 	PROC_WAIT_STATUS_OK,
 	PROC_WAIT_STATUS_WAITING,
 	PROC_WAIT_STATUS_ERROR,
-} ProcWaitStatus;
+}			ProcWaitStatus;
 
 /*
  * Each backend has a PGPROC struct in shared memory.  There is also a list of
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index f8595642da..e92617111d 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -47,11 +47,11 @@ extern int	namestrcmp(Name name, const char *str);
 extern int32 pg_atoi(const char *s, int size, int c);
 extern int16 pg_strtoint16(const char *s);
 extern int32 pg_strtoint32(const char *s);
-extern int pg_itoa(int16 i, char *a);
-extern int pg_ultoa_n(uint32 l, char *a);
-extern int pg_ulltoa_n(uint64 l, char *a);
-extern int pg_ltoa(int32 l, char *a);
-extern int pg_lltoa(int64 ll, char *a);
+extern int	pg_itoa(int16 i, char *a);
+extern int	pg_ultoa_n(uint32 l, char *a);
+extern int	pg_ulltoa_n(uint64 l, char *a);
+extern int	pg_ltoa(int32 l, char *a);
+extern int	pg_lltoa(int64 ll, char *a);
 extern char *pg_ultostr_zeropad(char *str, uint32 value, int32 minwidth);
 extern char *pg_ultostr(char *str, uint32 value);
 extern uint64 pg_strtouint64(const char *str, char **endptr, int base);
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 828ff5a288..6a13603bb5 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -1723,14 +1723,23 @@ plpgsql_parse_cwordtype(List *idents)
 	 * It must be a relation, sequence, view, materialized view, composite
 	 * type, or foreign table
 	 */
-	if (classStruct->relkind != RELKIND_RELATION &&
-		classStruct->relkind != RELKIND_SEQUENCE &&
-		classStruct->relkind != RELKIND_VIEW &&
-		classStruct->relkind != RELKIND_MATVIEW &&
-		classStruct->relkind != RELKIND_COMPOSITE_TYPE &&
-		classStruct->relkind != RELKIND_FOREIGN_TABLE &&
-		classStruct->relkind != RELKIND_PARTITIONED_TABLE)
-		goto done;
+	switch ((RelKind) classStruct->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_SEQUENCE:
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_INDEX:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_NULL:
+		default:
+			goto done;
+	}
 
 	/*
 	 * Fetch the named table field and its type
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index 02397f2eb1..87453751b0 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -816,7 +816,7 @@ test_spinlock(void)
 			char		data_before[4];
 			slock_t		lock;
 			char		data_after[4];
-		} struct_w_lock;
+		}			struct_w_lock;
 
 		memcpy(struct_w_lock.data_before, "abcd", 4);
 		memcpy(struct_w_lock.data_after, "ef12", 4);
@@ -864,28 +864,28 @@ test_spinlock(void)
 	}
 
 	/*
-	 * Ensure that allocating more than INT32_MAX emulated spinlocks
-	 * works. That's interesting because the spinlock emulation uses a 32bit
-	 * integer to map spinlocks onto semaphores. There've been bugs...
+	 * Ensure that allocating more than INT32_MAX emulated spinlocks works.
+	 * That's interesting because the spinlock emulation uses a 32bit integer
+	 * to map spinlocks onto semaphores. There've been bugs...
 	 */
 #ifndef HAVE_SPINLOCKS
 	{
 		/*
-		 * Initialize enough spinlocks to advance counter close to
-		 * wraparound. It's too expensive to perform acquire/release for each,
-		 * as those may be syscalls when the spinlock emulation is used (and
-		 * even just atomic TAS would be expensive).
+		 * Initialize enough spinlocks to advance counter close to wraparound.
+		 * It's too expensive to perform acquire/release for each, as those
+		 * may be syscalls when the spinlock emulation is used (and even just
+		 * atomic TAS would be expensive).
 		 */
 		for (uint32 i = 0; i < INT32_MAX - 100000; i++)
 		{
-			slock_t lock;
+			slock_t		lock;
 
 			SpinLockInit(&lock);
 		}
 
 		for (uint32 i = 0; i < 200000; i++)
 		{
-			slock_t lock;
+			slock_t		lock;
 
 			SpinLockInit(&lock);
 
@@ -915,7 +915,7 @@ test_spinlock(void)
 static void
 test_atomic_spin_nest(void)
 {
-	slock_t lock;
+	slock_t		lock;
 #define NUM_TEST_ATOMICS (NUM_SPINLOCK_SEMAPHORES + NUM_ATOMICS_SEMAPHORES + 27)
 	pg_atomic_uint32 atomics32[NUM_TEST_ATOMICS];
 	pg_atomic_uint64 atomics64[NUM_TEST_ATOMICS];
diff --git a/src/tools/findoidjoins/findoidjoins.c b/src/tools/findoidjoins/findoidjoins.c
index 5239332ea7..3961804b10 100644
--- a/src/tools/findoidjoins/findoidjoins.c
+++ b/src/tools/findoidjoins/findoidjoins.c
@@ -62,7 +62,7 @@ main(int argc, char **argv)
 					  "SELECT c.relname, (SELECT nspname FROM "
 					  "pg_catalog.pg_namespace n WHERE n.oid = c.relnamespace) AS nspname "
 					  "FROM pg_catalog.pg_class c "
-					  "WHERE c.relkind = " CppAsString2(RELKIND_RELATION)
+					  "WHERE c.relkind = " RelKindAsString(RELKIND_RELATION)
 					  " AND c.oid < '%u'"
 					  " AND EXISTS(SELECT * FROM pg_attribute a"
 					  "            WHERE a.attrelid = c.oid AND a.attname = 'oid' "
@@ -88,7 +88,7 @@ main(int argc, char **argv)
 					  "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
 					  "WHERE a.attnum > 0"
 					  " AND a.attname != 'oid'"
-					  " AND c.relkind = " CppAsString2(RELKIND_RELATION)
+					  " AND c.relkind = " RelKindAsString(RELKIND_RELATION)
 					  " AND c.oid < '%u'"
 					  " AND a.attrelid = c.oid"
 					  " AND a.atttypid IN ('pg_catalog.oid'::regtype, "
@@ -166,7 +166,7 @@ main(int argc, char **argv)
 					  "a.attname "
 					  "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
 					  "WHERE a.attnum > 0"
-					  " AND c.relkind = " CppAsString2(RELKIND_RELATION)
+					  " AND c.relkind = " RelKindAsString(RELKIND_RELATION)
 					  " AND a.attrelid = c.oid"
 					  " AND a.atttypid IN ('pg_catalog.oid[]'::regtype, "
 					  " 'pg_catalog.oidvector'::regtype, "
-- 
2.21.1 (Apple Git-122.3)

#6Michael Paquier
michael@paquier.xyz
In reply to: Mark Dilger (#4)
Re: Towards easier AMs: Cleaning up inappropriate use of name "relkind"

On Wed, Jul 01, 2020 at 09:46:34AM -0700, Mark Dilger wrote:

Rebased patch attached. Thanks for mentioning it!

There are two patches on this thread v2-0001 being much smaller than
v2-0002. I have looked at 0001 for now, and, like Alvaro, this
renaming makes sense to me. Those commands work on objects that are
relkinds, except for one OBJECT_TYPE. So, let's get 0001 patch
merged. Any objections from others?
--
Michael

#7Michael Paquier
michael@paquier.xyz
In reply to: Michael Paquier (#6)
Re: Towards easier AMs: Cleaning up inappropriate use of name "relkind"

On Wed, Jul 08, 2020 at 10:00:47PM +0900, Michael Paquier wrote:

There are two patches on this thread v2-0001 being much smaller than
v2-0002. I have looked at 0001 for now, and, like Alvaro, this
renaming makes sense to me. Those commands work on objects that are
relkinds, except for one OBJECT_TYPE. So, let's get 0001 patch
merged. Any objections from others?

I have been through this one again and applied it as cc35d89.
--
Michael

#8Michael Paquier
michael@paquier.xyz
In reply to: Mark Dilger (#5)
Re: Towards easier AMs: Cleaning up inappropriate use of name "relkind"

On Wed, Jul 01, 2020 at 05:04:19PM -0700, Mark Dilger wrote:

Most of the work in this patch is mechanical replacement of if/else
if/else statements which hinge on relkind to switch statements on
relkind. The patch is not philosophically very interesting, but it
is fairly long. Reviewers might start by scrolling down the patch
to the changes in src/include/catalog/pg_class.h

There are no intentional behavioral changes in this patch.

Please note that 0002 does not apply anymore, there are conflicts in
heap.c and tablecmds.c, and that there are noise diffs, likely because
you ran pgindent and included places unrelated to this patch. Anyway,
I am not really a fan of this patch. I could see a benefit in
switching to an enum so as for places where we use a switch/case
without a default we would be warned if a new relkind gets added or if
a value is not covered, but then we should not really need
RELKIND_NULL, no?
--
Michael

#9Mark Dilger
mark.dilger@enterprisedb.com
In reply to: Michael Paquier (#7)
Re: Towards easier AMs: Cleaning up inappropriate use of name "relkind"

On Jul 10, 2020, at 9:44 PM, Michael Paquier <michael@paquier.xyz> wrote:

On Wed, Jul 08, 2020 at 10:00:47PM +0900, Michael Paquier wrote:

There are two patches on this thread v2-0001 being much smaller than
v2-0002. I have looked at 0001 for now, and, like Alvaro, this
renaming makes sense to me. Those commands work on objects that are
relkinds, except for one OBJECT_TYPE. So, let's get 0001 patch
merged. Any objections from others?

I have been through this one again and applied it as cc35d89.
--
Michael

Thanks for committing!


Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#10Mark Dilger
mark.dilger@enterprisedb.com
In reply to: Michael Paquier (#8)
Re: Towards easier AMs: Cleaning up inappropriate use of name "relkind"

On Jul 10, 2020, at 11:00 PM, Michael Paquier <michael@paquier.xyz> wrote:

On Wed, Jul 01, 2020 at 05:04:19PM -0700, Mark Dilger wrote:

Most of the work in this patch is mechanical replacement of if/else
if/else statements which hinge on relkind to switch statements on
relkind. The patch is not philosophically very interesting, but it
is fairly long. Reviewers might start by scrolling down the patch
to the changes in src/include/catalog/pg_class.h

There are no intentional behavioral changes in this patch.

Please note that 0002 does not apply anymore, there are conflicts in
heap.c and tablecmds.c, and that there are noise diffs, likely because
you ran pgindent and included places unrelated to this patch.

I can resubmit, but should like to address your second point before bothering...

Anyway,
I am not really a fan of this patch. I could see a benefit in
switching to an enum so as for places where we use a switch/case
without a default we would be warned if a new relkind gets added or if
a value is not covered, but then we should not really need
RELKIND_NULL, no?

There are code paths where relkind is sometimes '\0' under normal, non-exceptional conditions. This happens in

allpaths.c: set_append_rel_size
rewriteHandler.c: view_query_is_auto_updatable
lockcmds.c: LockViewRecurse_walker
pg_depend.c: getOwnedSequences_internal

Doesn't this justify having RELKIND_NULL in the enum?

It is not the purpose of this patch to change the behavior of the code. This is just a structural patch, using an enum and switches rather than char and if/else if/else blocks.

Subsequent patches could build on this work, such as changing the behavior when code encounters a relkind value outside the code's expected set of relkind values. Whether those patches would add Assert()s, elog()s, or ereport()s is not something I'd like to have to debate as part of this patch submission. Assert()s have the advantage of costing nothing in production builds, but elog()s have the advantage of protecting against corrupt relkind values at runtime in production.

Getting the compiler to warn when a new relkind is added to the enumeration but not handled in a switch is difficult. One strategy is to add -Wswitch-enum, but that would require refactoring switches over all enums, not just over the RelKind enum, and for some enums, that would require a large number of extra lines to be added to the code. Another strategy is to remove the default label from switches over RelKind, but that removes protections against invalid relkinds being encountered.

Do you have a preference about which directions I should pursue? Or do you think the patch idea itself is dead?


Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#11Tom Lane
tgl@sss.pgh.pa.us
In reply to: Mark Dilger (#10)
Re: Towards easier AMs: Cleaning up inappropriate use of name "relkind"

Mark Dilger <mark.dilger@enterprisedb.com> writes:

On Jul 10, 2020, at 11:00 PM, Michael Paquier <michael@paquier.xyz> wrote:

I am not really a fan of this patch. I could see a benefit in
switching to an enum so as for places where we use a switch/case
without a default we would be warned if a new relkind gets added or if
a value is not covered, but then we should not really need
RELKIND_NULL, no?

There are code paths where relkind is sometimes '\0' under normal, non-exceptional conditions. This happens in

allpaths.c: set_append_rel_size
rewriteHandler.c: view_query_is_auto_updatable
lockcmds.c: LockViewRecurse_walker
pg_depend.c: getOwnedSequences_internal

Doesn't this justify having RELKIND_NULL in the enum?

I'd say no. I think including an intentionally invalid value in such
an enum is horrid, mainly because it will force a lot of places to cover
that value when they shouldn't (or else draw "enum value not handled in
switch" warnings). The confusion factor about whether it maybe *is*
a valid value is not to be discounted, either.

If we can't readily get rid of the use of '\0' in these code paths,
maybe trying to convert to an enum isn't going to be a win after all.

Getting the compiler to warn when a new relkind is added to the
enumeration but not handled in a switch is difficult.

We already have a project policy about how to do that.

regards, tom lane

#12Michael Paquier
michael@paquier.xyz
In reply to: Tom Lane (#11)
Re: Towards easier AMs: Cleaning up inappropriate use of name "relkind"

On Sat, Jul 11, 2020 at 03:32:55PM -0400, Tom Lane wrote:

Mark Dilger <mark.dilger@enterprisedb.com> writes:

There are code paths where relkind is sometimes '\0' under normal,
non-exceptional conditions. This happens in

allpaths.c: set_append_rel_size
rewriteHandler.c: view_query_is_auto_updatable
lockcmds.c: LockViewRecurse_walker
pg_depend.c: getOwnedSequences_internal

There are more code paths than what's mentioned upthread when it comes
to relkinds and \0. For example, I can quickly grep for acl.c that
relies on get_rel_relkind() returning \0 when the relkind cannot be
found. And we do that for get_typtype() as well in the syscache.

Doesn't this justify having RELKIND_NULL in the enum?

I'd say no. I think including an intentionally invalid value in such
an enum is horrid, mainly because it will force a lot of places to cover
that value when they shouldn't (or else draw "enum value not handled in
switch" warnings). The confusion factor about whether it maybe *is*
a valid value is not to be discounted, either.

I agree here that the situation could be improved because we never
store this value in the catalogs. Perhaps there would be a benefit in
switching to an enum in the long run, I am not sure. But if we do so,
RELKIND_NULL should not be around.
--
Michael

#13Mark Dilger
mark.dilger@enterprisedb.com
In reply to: Michael Paquier (#12)
1 attachment(s)
Re: Towards easier AMs: Cleaning up inappropriate use of name "relkind"

On Jul 12, 2020, at 4:59 AM, Michael Paquier <michael@paquier.xyz> wrote:

On Sat, Jul 11, 2020 at 03:32:55PM -0400, Tom Lane wrote:

Mark Dilger <mark.dilger@enterprisedb.com> writes:

There are code paths where relkind is sometimes '\0' under normal,
non-exceptional conditions. This happens in

allpaths.c: set_append_rel_size
rewriteHandler.c: view_query_is_auto_updatable
lockcmds.c: LockViewRecurse_walker
pg_depend.c: getOwnedSequences_internal

There are more code paths than what's mentioned upthread when it comes
to relkinds and \0. For example, I can quickly grep for acl.c that
relies on get_rel_relkind() returning \0 when the relkind cannot be
found. And we do that for get_typtype() as well in the syscache.

I was thinking about places in the code that test a relkind variable against a list of values, rather than places that return a relkind to callers, though certainly those two things are related. It's possible that I've missed some places in the code where \0 might be encountered, but I've added Asserts against unexpected values in v3.

I left get_rel_relkind() as is. There does not seem to be anything wrong with it returning \0 as long as all callers are prepared to deal with that result.

Doesn't this justify having RELKIND_NULL in the enum?

I'd say no. I think including an intentionally invalid value in such
an enum is horrid, mainly because it will force a lot of places to cover
that value when they shouldn't (or else draw "enum value not handled in
switch" warnings). The confusion factor about whether it maybe *is*
a valid value is not to be discounted, either.

I agree here that the situation could be improved because we never
store this value in the catalogs. Perhaps there would be a benefit in
switching to an enum in the long run, I am not sure. But if we do so,
RELKIND_NULL should not be around.

In the v3 patch, I have removed RELKIND_NULL from the enum, and also removed default: labels from switches over RelKind. The patch is also rebased.

Attachments:

v3-0001-Refactoring-relkind-handling.patchapplication/octet-stream; name=v3-0001-Refactoring-relkind-handling.patch; x-unix-mode=0644Download
From f11201365006ced5d7708429fec91b5fbb1ca24f Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Tue, 14 Jul 2020 15:13:01 -0700
Subject: [PATCH v3] Refactoring relkind handling

Cleaning up the #define RELKIND_XXX stuff using a new RelKind enum
and special macros while keeping the relkind fields as type 'char'.
---
 contrib/oid2name/oid2name.c                   |   18 +-
 contrib/pageinspect/rawpage.c                 |   65 +-
 contrib/pg_visibility/pg_visibility.c         |   26 +-
 contrib/pgrowlocks/pgrowlocks.c               |   36 +-
 contrib/pgstattuple/pgstatapprox.c            |   26 +-
 contrib/pgstattuple/pgstatindex.c             |   28 +-
 contrib/pgstattuple/pgstattuple.c             |    8 +-
 contrib/postgres_fdw/postgres_fdw.c           |   10 +-
 contrib/sepgsql/dml.c                         |   52 +-
 contrib/sepgsql/label.c                       |   49 +-
 contrib/sepgsql/relation.c                    |  380 ++-
 contrib/vacuumlo/vacuumlo.c                   |    2 +-
 src/backend/access/common/reloptions.c        |   20 +-
 src/backend/access/heap/heapam.c              |   82 +-
 src/backend/access/heap/heapam_handler.c      |   26 +-
 src/backend/access/heap/heaptoast.c           |   38 +-
 src/backend/access/index/indexam.c            |   25 +-
 src/backend/access/table/table.c              |  108 +-
 src/backend/access/table/tableam.c            |   53 +-
 src/backend/catalog/aclchk.c                  |  403 ++-
 src/backend/catalog/dependency.c              |   44 +-
 src/backend/catalog/heap.c                    |  513 ++--
 src/backend/catalog/index.c                   |  103 +-
 src/backend/catalog/objectaddress.c           |  182 +-
 src/backend/catalog/partition.c               |   20 +-
 src/backend/catalog/pg_depend.c               |   53 +-
 src/backend/catalog/pg_publication.c          |   51 +-
 src/backend/catalog/pg_type.c                 |   21 +-
 src/backend/catalog/toasting.c                |   43 +-
 src/backend/commands/analyze.c                |  212 +-
 src/backend/commands/cluster.c                |  148 +-
 src/backend/commands/comment.c                |   30 +-
 src/backend/commands/copy.c                   |  203 +-
 src/backend/commands/extension.c              |    4 +-
 src/backend/commands/indexcmds.c              |  188 +-
 src/backend/commands/lockcmds.c               |   95 +-
 src/backend/commands/policy.c                 |   72 +-
 src/backend/commands/publicationcmds.c        |   67 +-
 src/backend/commands/seclabel.c               |   29 +-
 src/backend/commands/sequence.c               |   27 +-
 src/backend/commands/statscmds.c              |   27 +-
 src/backend/commands/tablecmds.c              | 2483 +++++++++++------
 src/backend/commands/trigger.c                |  435 ++-
 src/backend/commands/typecmds.c               |   19 +-
 src/backend/commands/vacuum.c                 |   97 +-
 src/backend/executor/execMain.c               |  117 +-
 src/backend/executor/execReplication.c        |   43 +-
 src/backend/executor/nodeModifyTable.c        |  156 +-
 src/backend/optimizer/path/allpaths.c         |  169 +-
 src/backend/optimizer/plan/planner.c          |  138 +-
 src/backend/optimizer/util/inherit.c          |  243 +-
 src/backend/optimizer/util/plancat.c          |   72 +-
 src/backend/parser/parse_utilcmd.c            |  178 +-
 src/backend/partitioning/partbounds.c         |   47 +-
 src/backend/postmaster/autovacuum.c           |   88 +-
 src/backend/replication/basebackup.c          |    6 +-
 .../replication/logical/reorderbuffer.c       |   18 +-
 src/backend/replication/logical/tablesync.c   |   45 +-
 src/backend/replication/logical/worker.c      |  158 +-
 src/backend/replication/slot.c                |   52 +-
 src/backend/rewrite/rewriteDefine.c           |  179 +-
 src/backend/rewrite/rewriteHandler.c          |  462 +--
 src/backend/rewrite/rowsecurity.c             |   19 +-
 src/backend/storage/buffer/bufmgr.c           |   12 +-
 src/backend/storage/lmgr/proc.c               |   27 +-
 src/backend/storage/lmgr/spin.c               |    2 +-
 src/backend/tcop/utility.c                    |   85 +-
 src/backend/utils/adt/amutils.c               |   19 +-
 src/backend/utils/adt/dbsize.c                |   14 +-
 src/backend/utils/adt/partitionfuncs.c        |   40 +-
 src/backend/utils/adt/tid.c                   |   36 +-
 src/backend/utils/adt/xml.c                   |   12 +-
 src/backend/utils/cache/partcache.c           |   18 +-
 src/backend/utils/cache/relcache.c            |  338 ++-
 src/bin/initdb/initdb.c                       |   20 +-
 src/bin/pg_dump/common.c                      |   40 +-
 src/bin/pg_dump/pg_backup_tar.c               |    2 +-
 src/bin/pg_dump/pg_dump.c                     |  184 +-
 src/bin/pg_dump/pg_dump_sort.c                |  180 +-
 src/bin/pg_upgrade/info.c                     |    4 +-
 src/bin/pg_upgrade/pg_upgrade.c               |   12 +-
 src/bin/pg_upgrade/version.c                  |    6 +-
 src/bin/psql/command.c                        |   21 +-
 src/bin/psql/describe.c                       | 2266 ++++++++-------
 src/bin/psql/tab-complete.c                   |   66 +-
 src/bin/scripts/reindexdb.c                   |    8 +-
 src/bin/scripts/vacuumdb.c                    |    4 +-
 src/include/catalog/pg_class.h                |   48 +-
 src/include/nodes/execnodes.h                 |    4 +-
 src/include/storage/proc.h                    |    2 +-
 src/include/utils/builtins.h                  |   10 +-
 src/pl/plpgsql/src/pl_comp.c                  |   24 +-
 src/test/regress/regress.c                    |   22 +-
 src/tools/findoidjoins/findoidjoins.c         |    6 +-
 94 files changed, 8020 insertions(+), 4323 deletions(-)

diff --git a/contrib/oid2name/oid2name.c b/contrib/oid2name/oid2name.c
index c7d0f9025a..cff14f7c47 100644
--- a/contrib/oid2name/oid2name.c
+++ b/contrib/oid2name/oid2name.c
@@ -481,8 +481,8 @@ sql_exec_dumpalltables(PGconn *conn, struct options *opts)
 			 "	LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace "
 			 "	LEFT JOIN pg_catalog.pg_database d ON d.datname = pg_catalog.current_database(),"
 			 "	pg_catalog.pg_tablespace t "
-			 "WHERE relkind IN (" CppAsString2(RELKIND_RELATION) ","
-			 CppAsString2(RELKIND_MATVIEW) "%s%s) AND "
+			 "WHERE relkind IN (" RelKindAsString(RELKIND_RELATION) ","
+			 RelKindAsString(RELKIND_MATVIEW) "%s%s) AND "
 			 "	%s"
 			 "		t.oid = CASE"
 			 "			WHEN reltablespace <> 0 THEN reltablespace"
@@ -490,8 +490,8 @@ sql_exec_dumpalltables(PGconn *conn, struct options *opts)
 			 "		END "
 			 "ORDER BY relname",
 			 opts->extended ? addfields : "",
-			 opts->indexes ? "," CppAsString2(RELKIND_INDEX) "," CppAsString2(RELKIND_SEQUENCE) : "",
-			 opts->systables ? "," CppAsString2(RELKIND_TOASTVALUE) : "",
+			 opts->indexes ? "," RelKindAsString(RELKIND_INDEX) "," RelKindAsString(RELKIND_SEQUENCE) : "",
+			 opts->systables ? "," RelKindAsString(RELKIND_TOASTVALUE) : "",
 			 opts->systables ? "" : "n.nspname NOT IN ('pg_catalog', 'information_schema') AND n.nspname !~ '^pg_toast' AND");
 
 	sql_exec(conn, todo, opts->quiet);
@@ -551,11 +551,11 @@ sql_exec_searchtables(PGconn *conn, struct options *opts)
 					"	LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
 					"	LEFT JOIN pg_catalog.pg_database d ON d.datname = pg_catalog.current_database(),\n"
 					"	pg_catalog.pg_tablespace t\n"
-					"WHERE relkind IN (" CppAsString2(RELKIND_RELATION) ","
-					CppAsString2(RELKIND_MATVIEW) ","
-					CppAsString2(RELKIND_INDEX) ","
-					CppAsString2(RELKIND_SEQUENCE) ","
-					CppAsString2(RELKIND_TOASTVALUE) ") AND\n"
+					"WHERE relkind IN (" RelKindAsString(RELKIND_RELATION) ","
+					RelKindAsString(RELKIND_MATVIEW) ","
+					RelKindAsString(RELKIND_INDEX) ","
+					RelKindAsString(RELKIND_SEQUENCE) ","
+					RelKindAsString(RELKIND_TOASTVALUE) ") AND\n"
 					"		t.oid = CASE\n"
 					"			WHEN reltablespace <> 0 THEN reltablespace\n"
 					"			ELSE dattablespace\n"
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index c0181506a5..b455f95e1a 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -108,31 +108,46 @@ get_raw_page_internal(text *relname, ForkNumber forknum, BlockNumber blkno)
 	rel = relation_openrv(relrv, AccessShareLock);
 
 	/* Check that this relation has storage */
-	if (rel->rd_rel->relkind == RELKIND_VIEW)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot get raw page from view \"%s\"",
-						RelationGetRelationName(rel))));
-	if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot get raw page from composite type \"%s\"",
-						RelationGetRelationName(rel))));
-	if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot get raw page from foreign table \"%s\"",
-						RelationGetRelationName(rel))));
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot get raw page from partitioned table \"%s\"",
-						RelationGetRelationName(rel))));
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot get raw page from partitioned index \"%s\"",
-						RelationGetRelationName(rel))));
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_VIEW:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot get raw page from view \"%s\"",
+							RelationGetRelationName(rel))));
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot get raw page from composite type \"%s\"",
+							RelationGetRelationName(rel))));
+			break;
+		case RELKIND_FOREIGN_TABLE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot get raw page from foreign table \"%s\"",
+							RelationGetRelationName(rel))));
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot get raw page from partitioned table \"%s\"",
+							RelationGetRelationName(rel))));
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot get raw page from partitioned index \"%s\"",
+							RelationGetRelationName(rel))));
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+			break;
+	}
 
 	/*
 	 * Reject attempts to read non-local temporary relations; we would be
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index 68d580ed1e..eb722801bb 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -778,11 +778,23 @@ tuple_all_visible(HeapTuple tup, TransactionId OldestXmin, Buffer buffer)
 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)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table, materialized view, or TOAST table",
-						RelationGetRelationName(rel))));
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_VIEW:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table, materialized view, or TOAST table",
+							RelationGetRelationName(rel))));
+	}
 }
diff --git a/contrib/pgrowlocks/pgrowlocks.c b/contrib/pgrowlocks/pgrowlocks.c
index 714398831b..11a386f8ef 100644
--- a/contrib/pgrowlocks/pgrowlocks.c
+++ b/contrib/pgrowlocks/pgrowlocks.c
@@ -111,17 +111,31 @@ pgrowlocks(PG_FUNCTION_ARGS)
 		ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 						errmsg("only heap AM is supported")));
 
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is a partitioned table",
-						RelationGetRelationName(rel)),
-				 errdetail("Partitioned tables do not contain rows.")));
-	else if (rel->rd_rel->relkind != RELKIND_RELATION)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table",
-						RelationGetRelationName(rel))));
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is a partitioned table",
+							RelationGetRelationName(rel)),
+					 errdetail("Partitioned tables do not contain rows.")));
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table",
+							RelationGetRelationName(rel))));
+	}
 
 	/*
 	 * check permissions: must have SELECT on table or be in
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index dbc0fa11f6..c4e5de69b5 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -281,13 +281,25 @@ pgstattuple_approx_internal(Oid relid, FunctionCallInfo fcinfo)
 	 * We support only relation kinds with a visibility map and a free space
 	 * map.
 	 */
-	if (!(rel->rd_rel->relkind == RELKIND_RELATION ||
-		  rel->rd_rel->relkind == RELKIND_MATVIEW ||
-		  rel->rd_rel->relkind == RELKIND_TOASTVALUE))
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("\"%s\" is not a table, materialized view, or TOAST table",
-						RelationGetRelationName(rel))));
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_VIEW:
+			ereport(ERROR,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("\"%s\" is not a table, materialized view, or TOAST table",
+							RelationGetRelationName(rel))));
+	}
 
 	if (rel->rd_rel->relam != HEAP_TABLE_AM_OID)
 		ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index b1ce0d77d7..f2f3531c82 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -758,13 +758,23 @@ GetHashPageStats(Page page, HashIndexStat *stats)
 static void
 check_relation_relkind(Relation rel)
 {
-	if (rel->rd_rel->relkind != RELKIND_RELATION &&
-		rel->rd_rel->relkind != RELKIND_INDEX &&
-		rel->rd_rel->relkind != RELKIND_MATVIEW &&
-		rel->rd_rel->relkind != RELKIND_SEQUENCE &&
-		rel->rd_rel->relkind != RELKIND_TOASTVALUE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table, index, materialized view, sequence, or TOAST table",
-						RelationGetRelationName(rel))));
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_VIEW:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table, index, materialized view, sequence, or TOAST table",
+							RelationGetRelationName(rel))));
+	}
 }
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 69179d4104..576a3aaf4e 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -252,7 +252,8 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo)
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("cannot access temporary tables of other sessions")));
 
-	switch (rel->rd_rel->relkind)
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_MATVIEW:
@@ -282,7 +283,6 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo)
 					break;
 				default:
 					err = "unknown index";
-					break;
 			}
 			break;
 		case RELKIND_VIEW:
@@ -299,10 +299,6 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo)
 			break;
 		case RELKIND_PARTITIONED_INDEX:
 			err = "partitioned index";
-			break;
-		default:
-			err = "unknown";
-			break;
 	}
 
 	ereport(ERROR,
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 9fc53cad68..77e28757ef 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -4842,11 +4842,11 @@ postgresImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
 
 		appendStringInfoString(&buf,
 							   "WHERE c.relkind IN ("
-							   CppAsString2(RELKIND_RELATION) ","
-							   CppAsString2(RELKIND_VIEW) ","
-							   CppAsString2(RELKIND_FOREIGN_TABLE) ","
-							   CppAsString2(RELKIND_MATVIEW) ","
-							   CppAsString2(RELKIND_PARTITIONED_TABLE) ") "
+							   RelKindAsString(RELKIND_RELATION) ","
+							   RelKindAsString(RELKIND_VIEW) ","
+							   RelKindAsString(RELKIND_FOREIGN_TABLE) ","
+							   RelKindAsString(RELKIND_MATVIEW) ","
+							   RelKindAsString(RELKIND_PARTITIONED_TABLE) ") "
 							   "  AND n.nspname = ");
 		deparseStringLiteral(&buf, stmt->remote_schema);
 
diff --git a/contrib/sepgsql/dml.c b/contrib/sepgsql/dml.c
index 53f6f41c5c..bf5de226e7 100644
--- a/contrib/sepgsql/dml.c
+++ b/contrib/sepgsql/dml.c
@@ -167,10 +167,26 @@ check_relation_privileges(Oid relOid,
 					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 					 errmsg("SELinux: hardwired security policy violation")));
 
-		if (relkind == RELKIND_TOASTVALUE)
-			ereport(ERROR,
-					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-					 errmsg("SELinux: hardwired security policy violation")));
+		Assert(RELKIND_IS_VALID((RelKind) relkind));
+		switch ((RelKind) relkind)
+		{
+			case RELKIND_TOASTVALUE:
+				ereport(ERROR,
+						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+						 errmsg("SELinux: hardwired security policy violation")));
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_VIEW:
+				break;
+		}
+
 	}
 
 	/*
@@ -180,7 +196,8 @@ check_relation_privileges(Oid relOid,
 	object.objectId = relOid;
 	object.objectSubId = 0;
 	audit_name = getObjectIdentity(&object);
-	switch (relkind)
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
@@ -210,7 +227,12 @@ check_relation_privileges(Oid relOid,
 											 abort_on_violation);
 			break;
 
-		default:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
 			/* nothing to be checked */
 			break;
 	}
@@ -219,8 +241,22 @@ check_relation_privileges(Oid relOid,
 	/*
 	 * Only columns owned by relations shall be checked
 	 */
-	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
-		return true;
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			return true;
+	}
 
 	/*
 	 * Check permissions on the columns
diff --git a/contrib/sepgsql/label.c b/contrib/sepgsql/label.c
index 147ab67f32..f272662ddf 100644
--- a/contrib/sepgsql/label.c
+++ b/contrib/sepgsql/label.c
@@ -763,15 +763,27 @@ exec_object_restorecon(struct selabel_handle *sehnd, Oid catalogId)
 			case RelationRelationId:
 				relForm = (Form_pg_class) GETSTRUCT(tuple);
 
-				if (relForm->relkind == RELKIND_RELATION ||
-					relForm->relkind == RELKIND_PARTITIONED_TABLE)
-					objtype = SELABEL_DB_TABLE;
-				else if (relForm->relkind == RELKIND_SEQUENCE)
-					objtype = SELABEL_DB_SEQUENCE;
-				else if (relForm->relkind == RELKIND_VIEW)
-					objtype = SELABEL_DB_VIEW;
-				else
-					continue;	/* no need to assign security label */
+				Assert(RELKIND_IS_VALID((RelKind) relForm->relkind));
+				switch ((RelKind) relForm->relkind)
+				{
+					case RELKIND_RELATION:
+					case RELKIND_PARTITIONED_TABLE:
+						objtype = SELABEL_DB_TABLE;
+						break;
+					case RELKIND_SEQUENCE:
+						objtype = SELABEL_DB_SEQUENCE;
+						break;
+					case RELKIND_VIEW:
+						objtype = SELABEL_DB_VIEW;
+						break;
+					case RELKIND_PARTITIONED_INDEX:
+					case RELKIND_COMPOSITE_TYPE:
+					case RELKIND_FOREIGN_TABLE:
+					case RELKIND_INDEX:
+					case RELKIND_MATVIEW:
+					case RELKIND_TOASTVALUE:
+						continue;	/* no need to assign security label */
+				}
 
 				namespace_name = get_namespace_name(relForm->relnamespace);
 				objname = quote_object_name(database_name,
@@ -788,9 +800,22 @@ exec_object_restorecon(struct selabel_handle *sehnd, Oid catalogId)
 			case AttributeRelationId:
 				attForm = (Form_pg_attribute) GETSTRUCT(tuple);
 
-				if (get_rel_relkind(attForm->attrelid) != RELKIND_RELATION &&
-					get_rel_relkind(attForm->attrelid) != RELKIND_PARTITIONED_TABLE)
-					continue;	/* no need to assign security label */
+				Assert(RELKIND_IS_VALID((RelKind) get_rel_relkind(attForm->attrelid)));
+				switch ((RelKind) get_rel_relkind(attForm->attrelid))
+				{
+					case RELKIND_RELATION:
+					case RELKIND_PARTITIONED_TABLE:
+						break;
+					case RELKIND_PARTITIONED_INDEX:
+					case RELKIND_SEQUENCE:
+					case RELKIND_COMPOSITE_TYPE:
+					case RELKIND_FOREIGN_TABLE:
+					case RELKIND_INDEX:
+					case RELKIND_MATVIEW:
+					case RELKIND_TOASTVALUE:
+					case RELKIND_VIEW:
+						continue;	/* no need to assign security label */
+				}
 
 				objtype = SELABEL_DB_COLUMN;
 
diff --git a/contrib/sepgsql/relation.c b/contrib/sepgsql/relation.c
index 380bc6094d..b3fc647ce2 100644
--- a/contrib/sepgsql/relation.c
+++ b/contrib/sepgsql/relation.c
@@ -59,8 +59,22 @@ sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum)
 	 * Only attributes within regular relations or partition relations have
 	 * individual security labels.
 	 */
-	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
-		return;
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			return;
+	}
 
 	/*
 	 * Compute a default security label of the new column underlying the
@@ -137,8 +151,22 @@ sepgsql_attribute_drop(Oid relOid, AttrNumber attnum)
 	char	   *audit_name;
 	char		relkind = get_rel_relkind(relOid);
 
-	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
-		return;
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			return;
+	}
 
 	/*
 	 * check db_column:{drop} permission
@@ -170,10 +198,24 @@ sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
 	char	   *audit_name;
 	char		relkind = get_rel_relkind(relOid);
 
-	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot set security label on non-regular columns")));
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot set security label on non-regular columns")));
+	}
 
 	object.classId = RelationRelationId;
 	object.objectId = relOid;
@@ -213,8 +255,24 @@ sepgsql_attribute_setattr(Oid relOid, AttrNumber attnum)
 	char	   *audit_name;
 	char		relkind = get_rel_relkind(relOid);
 
-	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
-		return;
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			return;
+	}
 
 	/*
 	 * check db_column:{setattr} permission
@@ -275,9 +333,25 @@ sepgsql_relation_post_create(Oid relOid)
 	classForm = (Form_pg_class) GETSTRUCT(tuple);
 
 	/* ignore indexes on toast tables */
-	if (classForm->relkind == RELKIND_INDEX &&
-		classForm->relnamespace == PG_TOAST_NAMESPACE)
-		goto out;
+	Assert(RELKIND_IS_VALID((RelKind) classForm->relkind));
+	switch ((RelKind) classForm->relkind)
+	{
+		case RELKIND_INDEX:
+			if (classForm->relnamespace == PG_TOAST_NAMESPACE)
+				goto out;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
+	}
+
 
 	/*
 	 * check db_schema:{add_name} permission of the namespace
@@ -291,7 +365,8 @@ sepgsql_relation_post_create(Oid relOid)
 							getObjectIdentity(&object),
 							true);
 
-	switch (classForm->relkind)
+	Assert(RELKIND_IS_VALID((RelKind) classForm->relkind));
+	switch ((RelKind) classForm->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
@@ -307,7 +382,11 @@ sepgsql_relation_post_create(Oid relOid)
 			/* deal with indexes specially; no need for tclass */
 			sepgsql_index_modify(relOid);
 			goto out;
-		default:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
 			/* ignore other relkinds */
 			goto out;
 	}
@@ -348,59 +427,74 @@ sepgsql_relation_post_create(Oid relOid)
 	/*
 	 * We also assign a default security label on columns of a new table.
 	 */
-	if (classForm->relkind == RELKIND_RELATION ||
-		classForm->relkind == RELKIND_PARTITIONED_TABLE)
+	Assert(RELKIND_IS_VALID((RelKind) classForm->relkind));
+	switch ((RelKind) classForm->relkind)
 	{
-		Relation	arel;
-		ScanKeyData akey;
-		SysScanDesc ascan;
-		HeapTuple	atup;
-		Form_pg_attribute attForm;
-
-		arel = table_open(AttributeRelationId, AccessShareLock);
-
-		ScanKeyInit(&akey,
-					Anum_pg_attribute_attrelid,
-					BTEqualStrategyNumber, F_OIDEQ,
-					ObjectIdGetDatum(relOid));
-
-		ascan = systable_beginscan(arel, AttributeRelidNumIndexId, true,
-								   SnapshotSelf, 1, &akey);
-
-		while (HeapTupleIsValid(atup = systable_getnext(ascan)))
-		{
-			attForm = (Form_pg_attribute) GETSTRUCT(atup);
-
-			resetStringInfo(&audit_name);
-			appendStringInfo(&audit_name, "%s.%s.%s",
-							 quote_identifier(nsp_name),
-							 quote_identifier(NameStr(classForm->relname)),
-							 quote_identifier(NameStr(attForm->attname)));
-
-			ccontext = sepgsql_compute_create(scontext,
-											  rcontext,
-											  SEPG_CLASS_DB_COLUMN,
-											  NameStr(attForm->attname));
-
-			/*
-			 * check db_column:{create} permission
-			 */
-			sepgsql_avc_check_perms_label(ccontext,
-										  SEPG_CLASS_DB_COLUMN,
-										  SEPG_DB_COLUMN__CREATE,
-										  audit_name.data,
-										  true);
-
-			object.classId = RelationRelationId;
-			object.objectId = relOid;
-			object.objectSubId = attForm->attnum;
-			SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ccontext);
-
-			pfree(ccontext);
-		}
-		systable_endscan(ascan);
-		table_close(arel, AccessShareLock);
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			{
+				Relation	arel;
+				ScanKeyData akey;
+				SysScanDesc ascan;
+				HeapTuple	atup;
+				Form_pg_attribute attForm;
+
+				arel = table_open(AttributeRelationId, AccessShareLock);
+
+				ScanKeyInit(&akey,
+							Anum_pg_attribute_attrelid,
+							BTEqualStrategyNumber, F_OIDEQ,
+							ObjectIdGetDatum(relOid));
+
+				ascan = systable_beginscan(arel, AttributeRelidNumIndexId, true,
+										   SnapshotSelf, 1, &akey);
+
+				while (HeapTupleIsValid(atup = systable_getnext(ascan)))
+				{
+					attForm = (Form_pg_attribute) GETSTRUCT(atup);
+
+					resetStringInfo(&audit_name);
+					appendStringInfo(&audit_name, "%s.%s.%s",
+									 quote_identifier(nsp_name),
+									 quote_identifier(NameStr(classForm->relname)),
+									 quote_identifier(NameStr(attForm->attname)));
+
+					ccontext = sepgsql_compute_create(scontext,
+													  rcontext,
+													  SEPG_CLASS_DB_COLUMN,
+													  NameStr(attForm->attname));
+
+					/*
+					 * check db_column:{create} permission
+					 */
+					sepgsql_avc_check_perms_label(ccontext,
+												  SEPG_CLASS_DB_COLUMN,
+												  SEPG_DB_COLUMN__CREATE,
+												  audit_name.data,
+												  true);
+
+					object.classId = RelationRelationId;
+					object.objectId = relOid;
+					object.objectSubId = attForm->attnum;
+					SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ccontext);
+
+					pfree(ccontext);
+				}
+				systable_endscan(ascan);
+				table_close(arel, AccessShareLock);
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
 	}
+
 	pfree(rcontext);
 
 out:
@@ -421,7 +515,8 @@ sepgsql_relation_drop(Oid relOid)
 	uint16_t	tclass = 0;
 	char		relkind = get_rel_relkind(relOid);
 
-	switch (relkind)
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
@@ -439,7 +534,11 @@ sepgsql_relation_drop(Oid relOid)
 				return;
 			/* other indexes are handled specially below; no need for tclass */
 			break;
-		default:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
 			/* ignore other relkinds */
 			return;
 	}
@@ -460,10 +559,22 @@ sepgsql_relation_drop(Oid relOid)
 	pfree(audit_name);
 
 	/* deal with indexes specially */
-	if (relkind == RELKIND_INDEX)
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
 	{
-		sepgsql_index_modify(relOid);
-		return;
+		case RELKIND_INDEX:
+			sepgsql_index_modify(relOid);
+			return;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
 	}
 
 	/*
@@ -484,35 +595,50 @@ sepgsql_relation_drop(Oid relOid)
 	/*
 	 * check db_column:{drop} permission
 	 */
-	if (relkind == RELKIND_RELATION || relkind == RELKIND_PARTITIONED_TABLE)
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
 	{
-		Form_pg_attribute attForm;
-		CatCList   *attrList;
-		HeapTuple	atttup;
-		int			i;
-
-		attrList = SearchSysCacheList1(ATTNUM, ObjectIdGetDatum(relOid));
-		for (i = 0; i < attrList->n_members; i++)
-		{
-			atttup = &attrList->members[i]->tuple;
-			attForm = (Form_pg_attribute) GETSTRUCT(atttup);
-
-			if (attForm->attisdropped)
-				continue;
-
-			object.classId = RelationRelationId;
-			object.objectId = relOid;
-			object.objectSubId = attForm->attnum;
-			audit_name = getObjectIdentity(&object);
-
-			sepgsql_avc_check_perms(&object,
-									SEPG_CLASS_DB_COLUMN,
-									SEPG_DB_COLUMN__DROP,
-									audit_name,
-									true);
-			pfree(audit_name);
-		}
-		ReleaseCatCacheList(attrList);
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			{
+				Form_pg_attribute attForm;
+				CatCList   *attrList;
+				HeapTuple	atttup;
+				int			i;
+
+				attrList = SearchSysCacheList1(ATTNUM, ObjectIdGetDatum(relOid));
+				for (i = 0; i < attrList->n_members; i++)
+				{
+					atttup = &attrList->members[i]->tuple;
+					attForm = (Form_pg_attribute) GETSTRUCT(atttup);
+
+					if (attForm->attisdropped)
+						continue;
+
+					object.classId = RelationRelationId;
+					object.objectId = relOid;
+					object.objectSubId = attForm->attnum;
+					audit_name = getObjectIdentity(&object);
+
+					sepgsql_avc_check_perms(&object,
+											SEPG_CLASS_DB_COLUMN,
+											SEPG_DB_COLUMN__DROP,
+											audit_name,
+											true);
+					pfree(audit_name);
+				}
+				ReleaseCatCacheList(attrList);
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
 	}
 }
 
@@ -529,13 +655,21 @@ sepgsql_relation_truncate(Oid relOid)
 	uint16_t	tclass = 0;
 	char		relkind = get_rel_relkind(relOid);
 
-	switch (relkind)
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
 			tclass = SEPG_CLASS_DB_TABLE;
 			break;
-		default:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
 			/* ignore other relkinds */
 			return;
 	}
@@ -569,17 +703,30 @@ sepgsql_relation_relabel(Oid relOid, const char *seclabel)
 	char		relkind = get_rel_relkind(relOid);
 	uint16_t	tclass = 0;
 
-	if (relkind == RELKIND_RELATION || relkind == RELKIND_PARTITIONED_TABLE)
-		tclass = SEPG_CLASS_DB_TABLE;
-	else if (relkind == RELKIND_SEQUENCE)
-		tclass = SEPG_CLASS_DB_SEQUENCE;
-	else if (relkind == RELKIND_VIEW)
-		tclass = SEPG_CLASS_DB_VIEW;
-	else
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot set security labels on relations except "
-						"for tables, sequences or views")));
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			tclass = SEPG_CLASS_DB_TABLE;
+			break;
+		case RELKIND_SEQUENCE:
+			tclass = SEPG_CLASS_DB_SEQUENCE;
+			break;
+		case RELKIND_VIEW:
+			tclass = SEPG_CLASS_DB_VIEW;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot set security labels on relations except "
+							"for tables, sequences or views")));
+	}
 
 	object.classId = RelationRelationId;
 	object.objectId = relOid;
@@ -626,7 +773,8 @@ sepgsql_relation_setattr(Oid relOid)
 	char	   *audit_name;
 	uint16_t	tclass;
 
-	switch (get_rel_relkind(relOid))
+	Assert(RELKIND_IS_VALID((RelKind) get_rel_relkind(relOid)));
+	switch ((RelKind) get_rel_relkind(relOid))
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
@@ -642,7 +790,11 @@ sepgsql_relation_setattr(Oid relOid)
 			/* deal with indexes specially */
 			sepgsql_index_modify(relOid);
 			return;
-		default:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
 			/* other relkinds don't need additional work */
 			return;
 	}
diff --git a/contrib/vacuumlo/vacuumlo.c b/contrib/vacuumlo/vacuumlo.c
index 92bdf71356..e07f8be8e3 100644
--- a/contrib/vacuumlo/vacuumlo.c
+++ b/contrib/vacuumlo/vacuumlo.c
@@ -203,7 +203,7 @@ vacuumlo(const char *database, const struct _param *param)
 	strcat(buf, "      AND a.atttypid = t.oid ");
 	strcat(buf, "      AND c.relnamespace = s.oid ");
 	strcat(buf, "      AND t.typname in ('oid', 'lo') ");
-	strcat(buf, "      AND c.relkind in (" CppAsString2(RELKIND_RELATION) ", " CppAsString2(RELKIND_MATVIEW) ")");
+	strcat(buf, "      AND c.relkind in (" RelKindAsString(RELKIND_RELATION) ", " RelKindAsString(RELKIND_MATVIEW) ")");
 	strcat(buf, "      AND s.nspname !~ '^pg_'");
 	res = PQexec(conn, buf);
 	if (PQresultStatus(res) != PGRES_TUPLES_OK)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 8ccc228a8c..979a8f5a04 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -1372,7 +1372,8 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
 	classForm = (Form_pg_class) GETSTRUCT(tuple);
 
 	/* Parse into appropriate format; don't error out here */
-	switch (classForm->relkind)
+	Assert(RELKIND_IS_VALID((RelKind) classForm->relkind));
+	switch ((RelKind) classForm->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_TOASTVALUE:
@@ -1392,10 +1393,10 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
 		case RELKIND_FOREIGN_TABLE:
 			options = NULL;
 			break;
-		default:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
 			Assert(false);		/* can't get here */
 			options = NULL;		/* keep compiler quiet */
-			break;
 	}
 
 	return options;
@@ -1997,7 +1998,8 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
 {
 	StdRdOptions *rdopts;
 
-	switch (relkind)
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
 	{
 		case RELKIND_TOASTVALUE:
 			rdopts = (StdRdOptions *)
@@ -2013,13 +2015,19 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
 		case RELKIND_RELATION:
 		case RELKIND_MATVIEW:
 			return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
-		default:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_VIEW:
 			/* other relkinds are not supported */
 			return NULL;
 	}
+	return NULL;				/* keep compiler happy */
 }
 
-
 /*
  * Parse options for indexes.
  *
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index d881f4cd46..ed5355ada3 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2040,17 +2040,27 @@ heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 	 * If the new tuple is too big for storage or contains already toasted
 	 * out-of-line attributes from some other relation, invoke the toaster.
 	 */
-	if (relation->rd_rel->relkind != RELKIND_RELATION &&
-		relation->rd_rel->relkind != RELKIND_MATVIEW)
+	Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
-		/* toast table entries should never be recursively toasted */
-		Assert(!HeapTupleHasExternal(tup));
-		return tup;
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+			if (HeapTupleHasExternal(tup) || tup->t_len > TOAST_TUPLE_THRESHOLD)
+				return heap_toast_insert_or_update(relation, tup, NULL, options);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			/* toast table entries should never be recursively toasted */
+			Assert(!HeapTupleHasExternal(tup));
+			break;
 	}
-	else if (HeapTupleHasExternal(tup) || tup->t_len > TOAST_TUPLE_THRESHOLD)
-		return heap_toast_insert_or_update(relation, tup, NULL, options);
-	else
-		return tup;
+	return tup;
 }
 
 /*
@@ -2773,14 +2783,26 @@ l1:
 	 * because we need to look at the contents of the tuple, but it's OK to
 	 * release the content lock on the buffer first.
 	 */
-	if (relation->rd_rel->relkind != RELKIND_RELATION &&
-		relation->rd_rel->relkind != RELKIND_MATVIEW)
+	Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
-		/* toast table entries should never be recursively toasted */
-		Assert(!HeapTupleHasExternal(&tp));
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+			if (HeapTupleHasExternal(&tp))
+				heap_toast_delete(relation, &tp, false);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			/* toast table entries should never be recursively toasted */
+			Assert(!HeapTupleHasExternal(&tp));
+			break;
 	}
-	else if (HeapTupleHasExternal(&tp))
-		heap_toast_delete(relation, &tp, false);
 
 	/*
 	 * Mark tuple for invalidation from system caches at next command
@@ -3362,18 +3384,28 @@ l2:
 	 * We need to invoke the toaster if there are already any out-of-line
 	 * toasted values present, or if the new tuple is over-threshold.
 	 */
-	if (relation->rd_rel->relkind != RELKIND_RELATION &&
-		relation->rd_rel->relkind != RELKIND_MATVIEW)
+	Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
-		/* toast table entries should never be recursively toasted */
-		Assert(!HeapTupleHasExternal(&oldtup));
-		Assert(!HeapTupleHasExternal(newtup));
-		need_toast = false;
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+			need_toast = (HeapTupleHasExternal(&oldtup) ||
+						  HeapTupleHasExternal(newtup) ||
+						  newtup->t_len > TOAST_TUPLE_THRESHOLD);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			/* toast table entries should never be recursively toasted */
+			Assert(!HeapTupleHasExternal(&oldtup));
+			Assert(!HeapTupleHasExternal(newtup));
+			need_toast = false;
 	}
-	else
-		need_toast = (HeapTupleHasExternal(&oldtup) ||
-					  HeapTupleHasExternal(newtup) ||
-					  newtup->t_len > TOAST_TUPLE_THRESHOLD);
 
 	pagefree = PageGetHeapFreeSpace(page);
 
diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index 56b35622f1..bb8f6197c8 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -600,12 +600,26 @@ heapam_relation_set_new_filenode(Relation rel,
 	 */
 	if (persistence == RELPERSISTENCE_UNLOGGED)
 	{
-		Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
-			   rel->rd_rel->relkind == RELKIND_MATVIEW ||
-			   rel->rd_rel->relkind == RELKIND_TOASTVALUE);
-		smgrcreate(srel, INIT_FORKNUM, false);
-		log_smgrcreate(newrnode, INIT_FORKNUM);
-		smgrimmedsync(srel, INIT_FORKNUM);
+		Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+		switch ((RelKind) rel->rd_rel->relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_MATVIEW:
+			case RELKIND_TOASTVALUE:
+				smgrcreate(srel, INIT_FORKNUM, false);
+				log_smgrcreate(newrnode, INIT_FORKNUM);
+				smgrimmedsync(srel, INIT_FORKNUM);
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_VIEW:
+				Assert(false);
+				break;
+		}
 	}
 
 	smgrclose(srel);
diff --git a/src/backend/access/heap/heaptoast.c b/src/backend/access/heap/heaptoast.c
index 584f101dd9..764f6a41d7 100644
--- a/src/backend/access/heap/heaptoast.c
+++ b/src/backend/access/heap/heaptoast.c
@@ -50,8 +50,23 @@ heap_toast_delete(Relation rel, HeapTuple oldtup, bool is_speculative)
 	 * We should only ever be called for tuples of plain relations or
 	 * materialized views --- recursing on a toast rel is bad news.
 	 */
-	Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
-		   rel->rd_rel->relkind == RELKIND_MATVIEW);
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			Assert(false);
+			break;
+	}
 
 	/*
 	 * Get the tuple descriptor and break down the tuple into fields.
@@ -122,8 +137,23 @@ heap_toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
 	 * We should only ever be called for tuples of plain relations or
 	 * materialized views --- recursing on a toast rel is bad news.
 	 */
-	Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
-		   rel->rd_rel->relkind == RELKIND_MATVIEW);
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			Assert(false);
+			break;
+	}
 
 	/*
 	 * Get the tuple descriptor and break down the tuple(s) into fields.
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index 6b9750c244..644dc17045 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -135,12 +135,25 @@ index_open(Oid relationId, LOCKMODE lockmode)
 
 	r = relation_open(relationId, lockmode);
 
-	if (r->rd_rel->relkind != RELKIND_INDEX &&
-		r->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not an index",
-						RelationGetRelationName(r))));
+	Assert(RELKIND_IS_VALID((RelKind) r->rd_rel->relkind));
+	switch ((RelKind) r->rd_rel->relkind)
+	{
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not an index",
+							RelationGetRelationName(r))));
+	}
 
 	return r;
 }
diff --git a/src/backend/access/table/table.c b/src/backend/access/table/table.c
index 1aa01a54b3..623d451ee1 100644
--- a/src/backend/access/table/table.c
+++ b/src/backend/access/table/table.c
@@ -42,17 +42,31 @@ table_open(Oid relationId, LOCKMODE lockmode)
 
 	r = relation_open(relationId, lockmode);
 
-	if (r->rd_rel->relkind == RELKIND_INDEX ||
-		r->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is an index",
-						RelationGetRelationName(r))));
-	else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is a composite type",
-						RelationGetRelationName(r))));
+	Assert(RELKIND_IS_VALID((RelKind) r->rd_rel->relkind));
+	switch ((RelKind) r->rd_rel->relkind)
+	{
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is an index",
+							RelationGetRelationName(r))));
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is a composite type",
+							RelationGetRelationName(r))));
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
+	}
 
 	return r;
 }
@@ -71,17 +85,31 @@ table_openrv(const RangeVar *relation, LOCKMODE lockmode)
 
 	r = relation_openrv(relation, lockmode);
 
-	if (r->rd_rel->relkind == RELKIND_INDEX ||
-		r->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is an index",
-						RelationGetRelationName(r))));
-	else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is a composite type",
-						RelationGetRelationName(r))));
+	Assert(RELKIND_IS_VALID((RelKind) r->rd_rel->relkind));
+	switch ((RelKind) r->rd_rel->relkind)
+	{
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is an index",
+							RelationGetRelationName(r))));
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is a composite type",
+							RelationGetRelationName(r))));
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
+	}
 
 	return r;
 }
@@ -104,17 +132,31 @@ table_openrv_extended(const RangeVar *relation, LOCKMODE lockmode,
 
 	if (r)
 	{
-		if (r->rd_rel->relkind == RELKIND_INDEX ||
-			r->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is an index",
-							RelationGetRelationName(r))));
-		else if (r->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is a composite type",
-							RelationGetRelationName(r))));
+		Assert(RELKIND_IS_VALID((RelKind) r->rd_rel->relkind));
+		switch ((RelKind) r->rd_rel->relkind)
+		{
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("\"%s\" is an index",
+								RelationGetRelationName(r))));
+				break;
+			case RELKIND_COMPOSITE_TYPE:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("\"%s\" is a composite type",
+								RelationGetRelationName(r))));
+				break;
+			case RELKIND_SEQUENCE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				break;
+		}
 	}
 
 	return r;
diff --git a/src/backend/access/table/tableam.c b/src/backend/access/table/tableam.c
index 4b2bb29559..1ea399ba8f 100644
--- a/src/backend/access/table/tableam.c
+++ b/src/backend/access/table/tableam.c
@@ -47,27 +47,42 @@ table_slot_callbacks(Relation relation)
 
 	if (relation->rd_tableam)
 		tts_cb = relation->rd_tableam->slot_callbacks(relation);
-	else if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-	{
-		/*
-		 * Historically FDWs expect to store heap tuples in slots. Continue
-		 * handing them one, to make it less painful to adapt FDWs to new
-		 * versions. The cost of a heap slot over a virtual slot is pretty
-		 * small.
-		 */
-		tts_cb = &TTSOpsHeapTuple;
-	}
 	else
 	{
-		/*
-		 * These need to be supported, as some parts of the code (like COPY)
-		 * need to create slots for such relations too. It seems better to
-		 * centralize the knowledge that a heap slot is the right thing in
-		 * that case here.
-		 */
-		Assert(relation->rd_rel->relkind == RELKIND_VIEW ||
-			   relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-		tts_cb = &TTSOpsVirtual;
+		Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+		switch ((RelKind) relation->rd_rel->relkind)
+		{
+			case RELKIND_FOREIGN_TABLE:
+
+				/*
+				 * Historically FDWs expect to store heap tuples in slots.
+				 * Continue handing them one, to make it less painful to adapt
+				 * FDWs to new versions. The cost of a heap slot over a
+				 * virtual slot is pretty small.
+				 */
+				tts_cb = &TTSOpsHeapTuple;
+				break;
+			case RELKIND_VIEW:
+			case RELKIND_PARTITIONED_TABLE:
+
+				/*
+				 * These need to be supported, as some parts of the code (like
+				 * COPY) need to create slots for such relations too. It seems
+				 * better to centralize the knowledge that a heap slot is the
+				 * right thing in that case here.
+				 */
+				tts_cb = &TTSOpsVirtual;
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+				Assert(false);
+				break;
+		}
 	}
 
 	return tts_cb;
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index c626161408..ac08a4924a 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -1765,36 +1765,61 @@ ExecGrant_Relation(InternalGrant *istmt)
 			elog(ERROR, "cache lookup failed for relation %u", relOid);
 		pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
 
-		/* Not sensible to grant on an index */
-		if (pg_class_tuple->relkind == RELKIND_INDEX ||
-			pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is an index",
-							NameStr(pg_class_tuple->relname))));
+		Assert(RELKIND_IS_VALID((RelKind) pg_class_tuple->relkind));
+		switch ((RelKind) pg_class_tuple->relkind)
+		{
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+				/* Not sensible to grant on an index */
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("\"%s\" is an index",
+								NameStr(pg_class_tuple->relname))));
 
-		/* Composite types aren't tables either */
-		if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is a composite type",
-							NameStr(pg_class_tuple->relname))));
+			case RELKIND_COMPOSITE_TYPE:
+				/* Composite types aren't tables either */
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("\"%s\" is a composite type",
+								NameStr(pg_class_tuple->relname))));
+
+			case RELKIND_SEQUENCE:
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				/* Used GRANT SEQUENCE on a non-sequence? */
+				if (istmt->objtype == OBJECT_SEQUENCE)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is not a sequence",
+									NameStr(pg_class_tuple->relname))));
+		}
 
-		/* Used GRANT SEQUENCE on a non-sequence? */
-		if (istmt->objtype == OBJECT_SEQUENCE &&
-			pg_class_tuple->relkind != RELKIND_SEQUENCE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is not a sequence",
-							NameStr(pg_class_tuple->relname))));
 
 		/* Adjust the default permissions based on object type */
 		if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
 		{
-			if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
-				this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
-			else
-				this_privileges = ACL_ALL_RIGHTS_RELATION;
+			Assert(RELKIND_IS_VALID((RelKind) pg_class_tuple->relkind));
+			switch ((RelKind) pg_class_tuple->relkind)
+			{
+				case RELKIND_SEQUENCE:
+					this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
+					break;
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+					this_privileges = ACL_ALL_RIGHTS_RELATION;
+			}
 		}
 		else
 			this_privileges = istmt->privileges;
@@ -1807,42 +1832,52 @@ ExecGrant_Relation(InternalGrant *istmt)
 		 */
 		if (istmt->objtype == OBJECT_TABLE)
 		{
-			if (pg_class_tuple->relkind == RELKIND_SEQUENCE)
+			Assert(RELKIND_IS_VALID((RelKind) pg_class_tuple->relkind));
+			switch ((RelKind) pg_class_tuple->relkind)
 			{
-				/*
-				 * For backward compatibility, just throw a warning for
-				 * invalid sequence permissions when using the non-sequence
-				 * GRANT syntax.
-				 */
-				if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
-				{
-					/*
-					 * Mention the object name because the user needs to know
-					 * which operations succeeded.  This is required because
-					 * WARNING allows the command to continue.
-					 */
-					ereport(WARNING,
-							(errcode(ERRCODE_INVALID_GRANT_OPERATION),
-							 errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
-									NameStr(pg_class_tuple->relname))));
-					this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
-				}
-			}
-			else
-			{
-				if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
-				{
+				case RELKIND_SEQUENCE:
+
 					/*
-					 * USAGE is the only permission supported by sequences but
-					 * not by non-sequences.  Don't mention the object name
-					 * because we didn't in the combined TABLE | SEQUENCE
-					 * check.
+					 * For backward compatibility, just throw a warning for
+					 * invalid sequence permissions when using the
+					 * non-sequence GRANT syntax.
 					 */
-					ereport(ERROR,
-							(errcode(ERRCODE_INVALID_GRANT_OPERATION),
-							 errmsg("invalid privilege type %s for table",
-									"USAGE")));
-				}
+					if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE))
+					{
+						/*
+						 * Mention the object name because the user needs to
+						 * know which operations succeeded.  This is required
+						 * because WARNING allows the command to continue.
+						 */
+						ereport(WARNING,
+								(errcode(ERRCODE_INVALID_GRANT_OPERATION),
+								 errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges",
+										NameStr(pg_class_tuple->relname))));
+						this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE;
+					}
+					break;
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+					if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
+					{
+						/*
+						 * USAGE is the only permission supported by sequences
+						 * but not by non-sequences.  Don't mention the object
+						 * name because we didn't in the combined TABLE |
+						 * SEQUENCE check.
+						 */
+						ereport(ERROR,
+								(errcode(ERRCODE_INVALID_GRANT_OPERATION),
+								 errmsg("invalid privilege type %s for table",
+										"USAGE")));
+					}
 			}
 		}
 
@@ -1881,14 +1916,22 @@ ExecGrant_Relation(InternalGrant *istmt)
 								   &isNull);
 		if (isNull)
 		{
-			switch (pg_class_tuple->relkind)
+			Assert(RELKIND_IS_VALID((RelKind) pg_class_tuple->relkind));
+			switch ((RelKind) pg_class_tuple->relkind)
 			{
 				case RELKIND_SEQUENCE:
 					old_acl = acldefault(OBJECT_SEQUENCE, ownerId);
 					break;
-				default:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
 					old_acl = acldefault(OBJECT_TABLE, ownerId);
-					break;
 			}
 			/* There are no old member roles according to the catalogs */
 			noldmembers = 0;
@@ -1925,14 +1968,22 @@ ExecGrant_Relation(InternalGrant *istmt)
 								old_acl, ownerId,
 								&grantorId, &avail_goptions);
 
-			switch (pg_class_tuple->relkind)
+			Assert(RELKIND_IS_VALID((RelKind) pg_class_tuple->relkind));
+			switch ((RelKind) pg_class_tuple->relkind)
 			{
 				case RELKIND_SEQUENCE:
 					objtype = OBJECT_SEQUENCE;
 					break;
-				default:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
 					objtype = OBJECT_TABLE;
-					break;
 			}
 
 			/*
@@ -2009,20 +2060,35 @@ ExecGrant_Relation(InternalGrant *istmt)
 						 errmsg("invalid privilege type %s for column",
 								privilege_to_string(this_privileges))));
 
-			if (pg_class_tuple->relkind == RELKIND_SEQUENCE &&
-				this_privileges & ~((AclMode) ACL_SELECT))
+			Assert(RELKIND_IS_VALID((RelKind) pg_class_tuple->relkind));
+			switch ((RelKind) pg_class_tuple->relkind)
 			{
-				/*
-				 * The only column privilege allowed on sequences is SELECT.
-				 * This is a warning not error because we do it that way for
-				 * relation-level privileges.
-				 */
-				ereport(WARNING,
-						(errcode(ERRCODE_INVALID_GRANT_OPERATION),
-						 errmsg("sequence \"%s\" only supports SELECT column privileges",
-								NameStr(pg_class_tuple->relname))));
+				case RELKIND_SEQUENCE:
+					if (this_privileges & ~((AclMode) ACL_SELECT))
+					{
+						/*
+						 * The only column privilege allowed on sequences is
+						 * SELECT. This is a warning not error because we do
+						 * it that way for relation-level privileges.
+						 */
+						ereport(WARNING,
+								(errcode(ERRCODE_INVALID_GRANT_OPERATION),
+								 errmsg("sequence \"%s\" only supports SELECT column privileges",
+										NameStr(pg_class_tuple->relname))));
 
-				this_privileges &= (AclMode) ACL_SELECT;
+						this_privileges &= (AclMode) ACL_SELECT;
+					}
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+					break;
 			}
 
 			expand_col_privileges(col_privs->cols, relOid,
@@ -3824,14 +3890,22 @@ pg_class_aclmask(Oid table_oid, Oid roleid,
 	if (isNull)
 	{
 		/* No ACL, so build default ACL */
-		switch (classForm->relkind)
+		Assert(RELKIND_IS_VALID((RelKind) classForm->relkind));
+		switch ((RelKind) classForm->relkind)
 		{
 			case RELKIND_SEQUENCE:
 				acl = acldefault(OBJECT_SEQUENCE, ownerId);
 				break;
-			default:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
 				acl = acldefault(OBJECT_TABLE, ownerId);
-				break;
 		}
 		aclDatum = (Datum) 0;
 	}
@@ -5519,58 +5593,82 @@ recordExtObjInitPriv(Oid objoid, Oid classoid)
 		 * composite types.  (These cases are unreachable given the
 		 * restrictions in ALTER EXTENSION ADD, but let's check anyway.)
 		 */
-		if (pg_class_tuple->relkind == RELKIND_INDEX ||
-			pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
-			pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
+		Assert(RELKIND_IS_VALID((RelKind) pg_class_tuple->relkind));
+		switch ((RelKind) pg_class_tuple->relkind)
 		{
-			ReleaseSysCache(tuple);
-			return;
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+				ReleaseSysCache(tuple);
+				return;
+			case RELKIND_SEQUENCE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				break;
 		}
 
 		/*
 		 * If this isn't a sequence then it's possibly going to have
 		 * column-level ACLs associated with it.
 		 */
-		if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
+		Assert(RELKIND_IS_VALID((RelKind) pg_class_tuple->relkind));
+		switch ((RelKind) pg_class_tuple->relkind)
 		{
-			AttrNumber	curr_att;
-			AttrNumber	nattrs = pg_class_tuple->relnatts;
-
-			for (curr_att = 1; curr_att <= nattrs; curr_att++)
-			{
-				HeapTuple	attTuple;
-				Datum		attaclDatum;
-
-				attTuple = SearchSysCache2(ATTNUM,
-										   ObjectIdGetDatum(objoid),
-										   Int16GetDatum(curr_att));
-
-				if (!HeapTupleIsValid(attTuple))
-					continue;
-
-				/* ignore dropped columns */
-				if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
+			case RELKIND_SEQUENCE:
+				break;
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
 				{
-					ReleaseSysCache(attTuple);
-					continue;
-				}
-
-				attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
-											  Anum_pg_attribute_attacl,
-											  &isNull);
+					AttrNumber	curr_att;
+					AttrNumber	nattrs = pg_class_tuple->relnatts;
 
-				/* no need to do anything for a NULL ACL */
-				if (isNull)
-				{
-					ReleaseSysCache(attTuple);
-					continue;
+					for (curr_att = 1; curr_att <= nattrs; curr_att++)
+					{
+						HeapTuple	attTuple;
+						Datum		attaclDatum;
+
+						attTuple = SearchSysCache2(ATTNUM,
+												   ObjectIdGetDatum(objoid),
+												   Int16GetDatum(curr_att));
+
+						if (!HeapTupleIsValid(attTuple))
+							continue;
+
+						/* ignore dropped columns */
+						if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
+						{
+							ReleaseSysCache(attTuple);
+							continue;
+						}
+
+						attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
+													  Anum_pg_attribute_attacl,
+													  &isNull);
+
+						/* no need to do anything for a NULL ACL */
+						if (isNull)
+						{
+							ReleaseSysCache(attTuple);
+							continue;
+						}
+
+						recordExtensionInitPrivWorker(objoid, classoid, curr_att,
+													  DatumGetAclP(attaclDatum));
+
+						ReleaseSysCache(attTuple);
+					}
 				}
-
-				recordExtensionInitPrivWorker(objoid, classoid, curr_att,
-											  DatumGetAclP(attaclDatum));
-
-				ReleaseSysCache(attTuple);
-			}
 		}
 
 		aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
@@ -5813,40 +5911,67 @@ removeExtObjInitPriv(Oid objoid, Oid classoid)
 		 * composite types.  (These cases are unreachable given the
 		 * restrictions in ALTER EXTENSION DROP, but let's check anyway.)
 		 */
-		if (pg_class_tuple->relkind == RELKIND_INDEX ||
-			pg_class_tuple->relkind == RELKIND_PARTITIONED_INDEX ||
-			pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
+		Assert(RELKIND_IS_VALID((RelKind) pg_class_tuple->relkind));
+		switch ((RelKind) pg_class_tuple->relkind)
 		{
-			ReleaseSysCache(tuple);
-			return;
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+				ReleaseSysCache(tuple);
+				return;
+			case RELKIND_SEQUENCE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				break;
 		}
 
 		/*
 		 * If this isn't a sequence then it's possibly going to have
 		 * column-level ACLs associated with it.
 		 */
-		if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
+		Assert(RELKIND_IS_VALID((RelKind) pg_class_tuple->relkind));
+		switch ((RelKind) pg_class_tuple->relkind)
 		{
-			AttrNumber	curr_att;
-			AttrNumber	nattrs = pg_class_tuple->relnatts;
+			case RELKIND_SEQUENCE:
+				break;
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				{
+					AttrNumber	curr_att;
+					AttrNumber	nattrs = pg_class_tuple->relnatts;
 
-			for (curr_att = 1; curr_att <= nattrs; curr_att++)
-			{
-				HeapTuple	attTuple;
+					for (curr_att = 1; curr_att <= nattrs; curr_att++)
+					{
+						HeapTuple	attTuple;
 
-				attTuple = SearchSysCache2(ATTNUM,
-										   ObjectIdGetDatum(objoid),
-										   Int16GetDatum(curr_att));
+						attTuple = SearchSysCache2(ATTNUM,
+												   ObjectIdGetDatum(objoid),
+												   Int16GetDatum(curr_att));
 
-				if (!HeapTupleIsValid(attTuple))
-					continue;
+						if (!HeapTupleIsValid(attTuple))
+							continue;
 
-				/* when removing, remove all entries, even dropped columns */
+						/*
+						 * when removing, remove all entries, even dropped
+						 * columns
+						 */
 
-				recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
+						recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
 
-				ReleaseSysCache(attTuple);
-			}
+						ReleaseSysCache(attTuple);
+					}
+				}
 		}
 
 		ReleaseSysCache(tuple);
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index b33a2f94af..31c575bf50 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -1395,22 +1395,34 @@ doDeletion(const ObjectAddress *object, int flags)
 			{
 				char		relKind = get_rel_relkind(object->objectId);
 
-				if (relKind == RELKIND_INDEX ||
-					relKind == RELKIND_PARTITIONED_INDEX)
+				Assert(RELKIND_IS_VALID((RelKind) relKind));
+				switch ((RelKind) relKind)
 				{
-					bool		concurrent = ((flags & PERFORM_DELETION_CONCURRENTLY) != 0);
-					bool		concurrent_lock_mode = ((flags & PERFORM_DELETION_CONCURRENT_LOCK) != 0);
-
-					Assert(object->objectSubId == 0);
-					index_drop(object->objectId, concurrent, concurrent_lock_mode);
-				}
-				else
-				{
-					if (object->objectSubId != 0)
-						RemoveAttributeById(object->objectId,
-											object->objectSubId);
-					else
-						heap_drop_with_catalog(object->objectId);
+					case RELKIND_INDEX:
+					case RELKIND_PARTITIONED_INDEX:
+						{
+							bool		concurrent = ((flags & PERFORM_DELETION_CONCURRENTLY) != 0);
+							bool		concurrent_lock_mode = ((flags & PERFORM_DELETION_CONCURRENT_LOCK) != 0);
+
+							Assert(object->objectSubId == 0);
+							index_drop(object->objectId, concurrent, concurrent_lock_mode);
+						}
+						break;
+					case RELKIND_SEQUENCE:
+					case RELKIND_COMPOSITE_TYPE:
+					case RELKIND_FOREIGN_TABLE:
+					case RELKIND_MATVIEW:
+					case RELKIND_PARTITIONED_TABLE:
+					case RELKIND_RELATION:
+					case RELKIND_TOASTVALUE:
+					case RELKIND_VIEW:
+						{
+							if (object->objectSubId != 0)
+								RemoveAttributeById(object->objectId,
+													object->objectSubId);
+							else
+								heap_drop_with_catalog(object->objectId);
+						}
 				}
 
 				/*
@@ -1419,8 +1431,8 @@ doDeletion(const ObjectAddress *object, int flags)
 				 */
 				if (relKind == RELKIND_SEQUENCE)
 					DeleteSequenceTuple(object->objectId);
-				break;
 			}
+			break;
 
 		case OCLASS_PROC:
 			RemoveFunctionById(object->objectId);
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 3985326df6..b7b6c0e4e8 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -335,7 +335,8 @@ heap_create(const char *relname,
 	*relminmxid = InvalidMultiXactId;
 
 	/* Handle reltablespace for specific relkinds. */
-	switch (relkind)
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
 	{
 		case RELKIND_VIEW:
 		case RELKIND_COMPOSITE_TYPE:
@@ -360,7 +361,13 @@ heap_create(const char *relname,
 			 */
 			reltablespace = InvalidOid;
 			break;
-		default:
+
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
 			break;
 	}
 
@@ -415,21 +422,13 @@ heap_create(const char *relname,
 	{
 		RelationOpenSmgr(rel);
 
-		switch (rel->rd_rel->relkind)
+		Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+		switch ((RelKind) 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:
@@ -437,6 +436,13 @@ heap_create(const char *relname,
 												relpersistence,
 												relfrozenxid, relminmxid);
 				break;
+			case RELKIND_VIEW:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_PARTITIONED_INDEX:
+				Assert(false);
+				break;
 		}
 	}
 
@@ -506,18 +512,30 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
 	 * Skip this for a view or type relation, since those don't have system
 	 * attributes.
 	 */
-	if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
 	{
-		for (i = 0; i < natts; i++)
-		{
-			Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
+		case RELKIND_VIEW:
+		case RELKIND_COMPOSITE_TYPE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+			for (i = 0; i < natts; i++)
+			{
+				Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
 
-			if (SystemAttributeByName(NameStr(attr->attname)) != NULL)
-				ereport(ERROR,
-						(errcode(ERRCODE_DUPLICATE_COLUMN),
-						 errmsg("column name \"%s\" conflicts with a system column name",
-								NameStr(attr->attname))));
-		}
+				if (SystemAttributeByName(NameStr(attr->attname)) != NULL)
+					ereport(ERROR,
+							(errcode(ERRCODE_DUPLICATE_COLUMN),
+							 errmsg("column name \"%s\" conflicts with a system column name",
+									NameStr(attr->attname))));
+			}
 	}
 
 	/*
@@ -836,19 +854,31 @@ AddNewAttributeTuples(Oid new_rel_oid,
 	 * all for a view or type relation.  We don't bother with making datatype
 	 * dependencies here, since presumably all these types are pinned.
 	 */
-	if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE)
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
 	{
-		for (i = 0; i < (int) lengthof(SysAtt); i++)
-		{
-			FormData_pg_attribute attStruct;
+		case RELKIND_VIEW:
+		case RELKIND_COMPOSITE_TYPE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+			for (i = 0; i < (int) lengthof(SysAtt); i++)
+			{
+				FormData_pg_attribute attStruct;
 
-			memcpy(&attStruct, SysAtt[i], sizeof(FormData_pg_attribute));
+				memcpy(&attStruct, SysAtt[i], sizeof(FormData_pg_attribute));
 
-			/* Fill in the correct relation OID in the copied tuple */
-			attStruct.attrelid = new_rel_oid;
+				/* Fill in the correct relation OID in the copied tuple */
+				attStruct.attrelid = new_rel_oid;
 
-			InsertPgAttributeTuple(rel, &attStruct, (Datum) 0, indstate);
-		}
+				InsertPgAttributeTuple(rel, &attStruct, (Datum) 0, indstate);
+			}
 	}
 
 	/*
@@ -966,7 +996,8 @@ AddNewRelationTuple(Relation pg_class_desc,
 	 */
 	new_rel_reltup = new_rel_desc->rd_rel;
 
-	switch (relkind)
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_MATVIEW:
@@ -983,12 +1014,15 @@ AddNewRelationTuple(Relation pg_class_desc,
 			new_rel_reltup->reltuples = 1;
 			new_rel_reltup->relallvisible = 0;
 			break;
-		default:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_VIEW:
 			/* Views, etc, have no disk storage */
 			new_rel_reltup->relpages = 0;
 			new_rel_reltup->reltuples = 0;
 			new_rel_reltup->relallvisible = 0;
-			break;
 	}
 
 	new_rel_reltup->relfrozenxid = relfrozenxid;
@@ -1184,29 +1218,41 @@ heap_create_with_catalog(const char *relname,
 	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 (!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;
-		}
-		/* 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)
+		bool	handled = false;
+		switch (relkind)
 		{
-			relid = binary_upgrade_next_toast_pg_class_oid;
-			binary_upgrade_next_toast_pg_class_oid = InvalidOid;
+			case RELKIND_RELATION:
+			case RELKIND_SEQUENCE:
+			case RELKIND_VIEW:
+			case RELKIND_MATVIEW:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case 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")));
+		
+					relid = binary_upgrade_next_heap_pg_class_oid;
+					binary_upgrade_next_heap_pg_class_oid = InvalidOid;
+					handled = true;
+				}
+				break;
+			case RELKIND_TOASTVALUE:
+				if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_toast_pg_class_oid))
+				{
+					relid = binary_upgrade_next_toast_pg_class_oid;
+					binary_upgrade_next_toast_pg_class_oid = InvalidOid;
+					handled = true;
+				}
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_INDEX:
+				break;
 		}
-		else
+		if (!handled)
 			relid = GetNewRelFileNode(reltablespace, pg_class_desc,
 									  relpersistence);
 	}
@@ -1216,7 +1262,8 @@ heap_create_with_catalog(const char *relname,
 	 */
 	if (use_user_acl)
 	{
-		switch (relkind)
+		Assert(RELKIND_IS_VALID((RelKind) relkind));
+		switch ((RelKind) relkind)
 		{
 			case RELKIND_RELATION:
 			case RELKIND_VIEW:
@@ -1230,9 +1277,11 @@ heap_create_with_catalog(const char *relname,
 				relacl = get_user_default_acl(OBJECT_SEQUENCE, ownerid,
 											  relnamespace);
 				break;
-			default:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_TOASTVALUE:
 				relacl = NULL;
-				break;
 		}
 	}
 	else
@@ -1267,85 +1316,93 @@ heap_create_with_catalog(const char *relname,
 	 * These types are made except where the use of a relation as such is an
 	 * implementation detail: toast tables, sequences and indexes.
 	 */
-	if (!(relkind == RELKIND_SEQUENCE ||
-		  relkind == RELKIND_TOASTVALUE ||
-		  relkind == RELKIND_INDEX ||
-		  relkind == RELKIND_PARTITIONED_INDEX))
-	{
-		Oid			new_array_oid;
-		ObjectAddress new_type_addr;
-		char	   *relarrayname;
-
-		/*
-		 * We'll make an array over the composite type, too.  For largely
-		 * historical reasons, the array type's OID is assigned first.
-		 */
-		new_array_oid = AssignTypeArrayOid();
-
-		/*
-		 * Make the pg_type entry for the composite type.  The OID of the
-		 * composite type can be preselected by the caller, but if reltypeid
-		 * is InvalidOid, we'll generate a new OID for it.
-		 *
-		 * NOTE: we could get a unique-index failure here, in case someone
-		 * else is creating the same type name in parallel but hadn't
-		 * committed yet when we checked for a duplicate name above.
-		 */
-		new_type_addr = AddNewRelationType(relname,
-										   relnamespace,
-										   relid,
-										   relkind,
-										   ownerid,
-										   reltypeid,
-										   new_array_oid);
-		new_type_oid = new_type_addr.objectId;
-		if (typaddress)
-			*typaddress = new_type_addr;
-
-		/* Now create the array type. */
-		relarrayname = makeArrayTypeName(relname, relnamespace);
-
-		TypeCreate(new_array_oid,	/* force the type's OID to this */
-				   relarrayname,	/* Array type name */
-				   relnamespace,	/* Same namespace as parent */
-				   InvalidOid,	/* Not composite, no relationOid */
-				   0,			/* relkind, also N/A here */
-				   ownerid,		/* owner's ID */
-				   -1,			/* Internal size (varlena) */
-				   TYPTYPE_BASE,	/* Not composite - typelem is */
-				   TYPCATEGORY_ARRAY,	/* type-category (array) */
-				   false,		/* array types are never preferred */
-				   DEFAULT_TYPDELIM,	/* default array delimiter */
-				   F_ARRAY_IN,	/* array input proc */
-				   F_ARRAY_OUT, /* array output proc */
-				   F_ARRAY_RECV,	/* array recv (bin) proc */
-				   F_ARRAY_SEND,	/* array send (bin) proc */
-				   InvalidOid,	/* typmodin procedure - none */
-				   InvalidOid,	/* typmodout procedure - none */
-				   F_ARRAY_TYPANALYZE,	/* array analyze procedure */
-				   new_type_oid,	/* array element type - the rowtype */
-				   true,		/* yes, this is an array type */
-				   InvalidOid,	/* this has no array type */
-				   InvalidOid,	/* domain base type - irrelevant */
-				   NULL,		/* default value - none */
-				   NULL,		/* default binary representation */
-				   false,		/* passed by reference */
-				   TYPALIGN_DOUBLE, /* alignment - must be the largest! */
-				   TYPSTORAGE_EXTENDED, /* fully TOASTable */
-				   -1,			/* typmod */
-				   0,			/* array dimensions for typBaseType */
-				   false,		/* Type NOT NULL */
-				   InvalidOid); /* rowtypes never have a collation */
-
-		pfree(relarrayname);
-	}
-	else
+	switch (relkind)
 	{
-		/* Caller should not be expecting a type to be created. */
-		Assert(reltypeid == InvalidOid);
-		Assert(typaddress == NULL);
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			/* Caller should not be expecting a type to be created. */
+			Assert(reltypeid == InvalidOid);
+			Assert(typaddress == NULL);
 
-		new_type_oid = InvalidOid;
+			new_type_oid = InvalidOid;
+			break;
+		case RELKIND_VIEW:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+			{
+				Oid			new_array_oid;
+				ObjectAddress new_type_addr;
+				char	   *relarrayname;
+
+				/*
+				 * We'll make an array over the composite type, too.  For largely
+				 * historical reasons, the array type's OID is assigned first.
+				 */
+				new_array_oid = AssignTypeArrayOid();
+
+				/*
+				 * Make the pg_type entry for the composite type.  The OID of the
+				 * composite type can be preselected by the caller, but if reltypeid
+				 * is InvalidOid, we'll generate a new OID for it.
+				 *
+				 * NOTE: we could get a unique-index failure here, in case someone
+				 * else is creating the same type name in parallel but hadn't
+				 * committed yet when we checked for a duplicate name above.
+				 */
+				new_type_addr = AddNewRelationType(relname,
+												   relnamespace,
+												   relid,
+												   relkind,
+												   ownerid,
+												   reltypeid,
+												   new_array_oid);
+				new_type_oid = new_type_addr.objectId;
+				if (typaddress)
+					*typaddress = new_type_addr;
+
+				/* Now create the array type. */
+				relarrayname = makeArrayTypeName(relname, relnamespace);
+
+				TypeCreate(new_array_oid,	/* force the type's OID to this */
+						   relarrayname,	/* Array type name */
+						   relnamespace,	/* Same namespace as parent */
+						   InvalidOid,	/* Not composite, no relationOid */
+						   0,			/* relkind, also N/A here */
+						   ownerid,		/* owner's ID */
+						   -1,			/* Internal size (varlena) */
+						   TYPTYPE_BASE,	/* Not composite - typelem is */
+						   TYPCATEGORY_ARRAY,	/* type-category (array) */
+						   false,		/* array types are never preferred */
+						   DEFAULT_TYPDELIM,	/* default array delimiter */
+						   F_ARRAY_IN,	/* array input proc */
+						   F_ARRAY_OUT, /* array output proc */
+						   F_ARRAY_RECV,	/* array recv (bin) proc */
+						   F_ARRAY_SEND,	/* array send (bin) proc */
+						   InvalidOid,	/* typmodin procedure - none */
+						   InvalidOid,	/* typmodout procedure - none */
+						   F_ARRAY_TYPANALYZE,	/* array analyze procedure */
+						   new_type_oid,	/* array element type - the rowtype */
+						   true,		/* yes, this is an array type */
+						   InvalidOid,	/* this has no array type */
+						   InvalidOid,	/* domain base type - irrelevant */
+						   NULL,		/* default value - none */
+						   NULL,		/* default binary representation */
+						   false,		/* passed by reference */
+						   TYPALIGN_DOUBLE, /* alignment - must be the largest! */
+						   TYPSTORAGE_EXTENDED, /* fully TOASTable */
+						   -1,			/* typmod */
+						   0,			/* array dimensions for typBaseType */
+						   false,		/* Type NOT NULL */
+						   InvalidOid); /* rowtypes never have a collation */
+
+				pfree(relarrayname);
+			}
+			break;
 	}
 
 	/*
@@ -1387,51 +1444,65 @@ heap_create_with_catalog(const char *relname,
 	 * Also, skip this in bootstrap mode, since we don't make dependencies
 	 * while bootstrapping.
 	 */
-	if (relkind != RELKIND_COMPOSITE_TYPE &&
-		relkind != RELKIND_TOASTVALUE &&
-		!IsBootstrapProcessingMode())
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
 	{
-		ObjectAddress myself,
-					referenced;
-
-		myself.classId = RelationRelationId;
-		myself.objectId = relid;
-		myself.objectSubId = 0;
-
-		referenced.classId = NamespaceRelationId;
-		referenced.objectId = relnamespace;
-		referenced.objectSubId = 0;
-		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
-
-		recordDependencyOnOwner(RelationRelationId, relid, ownerid);
-
-		recordDependencyOnNewAcl(RelationRelationId, relid, 0, ownerid, relacl);
-
-		recordDependencyOnCurrentExtension(&myself, false);
-
-		if (reloftypeid)
-		{
-			referenced.classId = TypeRelationId;
-			referenced.objectId = reloftypeid;
-			referenced.objectSubId = 0;
-			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
-		}
-
-		/*
-		 * Make a dependency link to force the relation to be deleted if its
-		 * access method is. Do this only for relation and materialized views.
-		 *
-		 * 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)
-		{
-			referenced.classId = AccessMethodRelationId;
-			referenced.objectId = accessmtd;
-			referenced.objectSubId = 0;
-			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
-		}
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_TOASTVALUE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+			if (!IsBootstrapProcessingMode())
+			{
+				ObjectAddress myself,
+							referenced;
+
+				myself.classId = RelationRelationId;
+				myself.objectId = relid;
+				myself.objectSubId = 0;
+
+				referenced.classId = NamespaceRelationId;
+				referenced.objectId = relnamespace;
+				referenced.objectSubId = 0;
+				recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+				recordDependencyOnOwner(RelationRelationId, relid, ownerid);
+
+				recordDependencyOnNewAcl(RelationRelationId, relid, 0, ownerid, relacl);
+
+				recordDependencyOnCurrentExtension(&myself, false);
+
+				if (reloftypeid)
+				{
+					referenced.classId = TypeRelationId;
+					referenced.objectId = reloftypeid;
+					referenced.objectSubId = 0;
+					recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+				}
+
+				/*
+				 * Make a dependency link to force the relation to be deleted
+				 * if its access method is. Do this only for relation and
+				 * materialized views.
+				 *
+				 * 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)
+				{
+					referenced.classId = AccessMethodRelationId;
+					referenced.objectId = accessmtd;
+					referenced.objectSubId = 0;
+					recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+				}
+			}
 	}
 
 	/* Post creation hook for new relation */
@@ -2390,12 +2461,27 @@ StoreRelCheck(Relation rel, const char *ccname, Node *expr,
 	 * Partitioned tables do not contain any rows themselves, so a NO INHERIT
 	 * constraint makes no sense.
 	 */
-	if (is_no_inherit &&
-		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-				 errmsg("cannot add NO INHERIT constraint to partitioned table \"%s\"",
-						RelationGetRelationName(rel))));
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			if (is_no_inherit)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+						 errmsg("cannot add NO INHERIT constraint to partitioned table \"%s\"",
+								RelationGetRelationName(rel))));
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
+	}
 
 	/*
 	 * Create the Check Constraint
@@ -3261,8 +3347,22 @@ heap_truncate_one_rel(Relation rel)
 	 * Truncate the relation.  Partitioned tables have no storage, so there is
 	 * nothing to do for them here.
 	 */
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		return;
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			return;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
+	}
 
 	/* Truncate the underlying relation */
 	table_relation_nontransactional_truncate(rel);
@@ -3315,9 +3415,24 @@ heap_truncate_check_FKs(List *relations, bool tempTables)
 	{
 		Relation	rel = lfirst(cell);
 
-		if (rel->rd_rel->relhastriggers ||
-			rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-			oids = lappend_oid(oids, RelationGetRelid(rel));
+		Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+		switch ((RelKind) rel->rd_rel->relkind)
+		{
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				if (!rel->rd_rel->relhastriggers)
+					break;
+				/* fallthrough */
+			case RELKIND_PARTITIONED_TABLE:
+				oids = lappend_oid(oids, RelationGetRelid(rel));
+		}
 	}
 
 	/*
@@ -3540,7 +3655,23 @@ StorePartitionKey(Relation rel,
 	ObjectAddress myself;
 	ObjectAddress referenced;
 
-	Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			Assert(false);
+			break;
+	}
 
 	/* Copy the partition attribute numbers, opclass OIDs into arrays */
 	partattrs_vec = buildint2vector(partattrs, partnatts);
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 8ec2864c76..0fedf58617 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -2203,8 +2203,22 @@ index_drop(Oid indexId, bool concurrent, bool concurrent_lock_mode)
 	/*
 	 * Schedule physical removal of the files (if any)
 	 */
-	if (userIndexRelation->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
-		RelationDropStorage(userIndexRelation);
+	Assert(RELKIND_IS_VALID((RelKind) userIndexRelation->rd_rel->relkind));
+	switch ((RelKind) userIndexRelation->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_INDEX:
+			break;
+		case RELKIND_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			RelationDropStorage(userIndexRelation);
+	}
 
 	/*
 	 * Close and flush the index's relcache entry, to ensure relcache doesn't
@@ -2731,7 +2745,22 @@ index_update_stats(Relation rel,
 	rd_rel = (Form_pg_class) GETSTRUCT(tuple);
 
 	/* Should this be a more comprehensive test? */
-	Assert(rd_rel->relkind != RELKIND_PARTITIONED_INDEX);
+	Assert(RELKIND_IS_VALID((RelKind) rd_rel->relkind));
+	switch ((RelKind) rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_INDEX:
+			Assert(false);
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+		case RELKIND_INDEX:
+			break;
+	}
 
 	/* Apply required updates, if any, to copied tuple */
 
@@ -2747,10 +2776,23 @@ index_update_stats(Relation rel,
 		BlockNumber relpages = RelationGetNumberOfBlocks(rel);
 		BlockNumber relallvisible;
 
-		if (rd_rel->relkind != RELKIND_INDEX)
-			visibilitymap_count(rel, &relallvisible, NULL);
-		else					/* don't bother for indexes */
-			relallvisible = 0;
+		Assert(RELKIND_IS_VALID((RelKind) rd_rel->relkind));
+		switch ((RelKind) rd_rel->relkind)
+		{
+			case RELKIND_INDEX:
+				relallvisible = 0;
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				visibilitymap_count(rel, &relallvisible, NULL);
+		}
 
 		if (rd_rel->relpages != (int32) relpages)
 		{
@@ -3461,9 +3503,24 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 	 * The case of reindexing partitioned tables and indexes is handled
 	 * differently by upper layers, so this case shouldn't arise.
 	 */
-	if (iRel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
-		elog(ERROR, "unsupported relation kind for index \"%s\"",
-			 RelationGetRelationName(iRel));
+	Assert(RELKIND_IS_VALID((RelKind) iRel->rd_rel->relkind));
+	switch ((RelKind) iRel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_INDEX:
+			elog(ERROR, "unsupported relation kind for index \"%s\"",
+				 RelationGetRelationName(iRel));
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
+	}
 
 	/*
 	 * Don't allow reindex on temp tables of other backends ... their local
@@ -3677,14 +3734,26 @@ reindex_relation(Oid relid, int flags, int options)
 	 * (REINDEX SCHEMA) and happen to come across a partitioned table.  The
 	 * partitions may be reindexed on their own anyway.
 	 */
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		ereport(WARNING,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("REINDEX of partitioned tables is not yet implemented, skipping \"%s\"",
-						RelationGetRelationName(rel))));
-		table_close(rel, ShareLock);
-		return false;
+		case RELKIND_PARTITIONED_TABLE:
+			ereport(WARNING,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("REINDEX of partitioned tables is not yet implemented, skipping \"%s\"",
+							RelationGetRelationName(rel))));
+			table_close(rel, ShareLock);
+			return false;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
 	}
 
 	toast_relid = rel->rd_rel->reltoastrelid;
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 534df8e802..1c82310c24 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -97,7 +97,8 @@
  */
 typedef struct
 {
-	const char *class_descr;	/* string describing the catalog, for internal error messages */
+	const char *class_descr;	/* string describing the catalog, for internal
+								 * error messages */
 	Oid			class_oid;		/* oid of catalog */
 	Oid			oid_index_oid;	/* oid of index on system oid column */
 	int			oid_catcache_id;	/* id of catcache on system oid column	*/
@@ -1342,48 +1343,130 @@ get_relation_by_qualified_name(ObjectType objtype, List *object,
 	switch (objtype)
 	{
 		case OBJECT_INDEX:
-			if (relation->rd_rel->relkind != RELKIND_INDEX &&
-				relation->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is not an index",
-								RelationGetRelationName(relation))));
+			Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+			switch ((RelKind) relation->rd_rel->relkind)
+			{
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+					break;
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is not an index",
+									RelationGetRelationName(relation))));
+			}
 			break;
 		case OBJECT_SEQUENCE:
-			if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is not a sequence",
-								RelationGetRelationName(relation))));
+			Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+			switch ((RelKind) relation->rd_rel->relkind)
+			{
+				case RELKIND_SEQUENCE:
+					break;
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is not a sequence",
+									RelationGetRelationName(relation))));
+			}
 			break;
 		case OBJECT_TABLE:
-			if (relation->rd_rel->relkind != RELKIND_RELATION &&
-				relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is not a table",
-								RelationGetRelationName(relation))));
+			Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+			switch ((RelKind) relation->rd_rel->relkind)
+			{
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+					break;
+				case RELKIND_SEQUENCE:
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_MATVIEW:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is not a table",
+									RelationGetRelationName(relation))));
+			}
 			break;
 		case OBJECT_VIEW:
-			if (relation->rd_rel->relkind != RELKIND_VIEW)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is not a view",
-								RelationGetRelationName(relation))));
+			Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+			switch ((RelKind) relation->rd_rel->relkind)
+			{
+				case RELKIND_VIEW:
+					break;
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_SEQUENCE:
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_MATVIEW:
+				case RELKIND_TOASTVALUE:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is not a view",
+									RelationGetRelationName(relation))));
+			}
 			break;
 		case OBJECT_MATVIEW:
-			if (relation->rd_rel->relkind != RELKIND_MATVIEW)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is not a materialized view",
-								RelationGetRelationName(relation))));
+			Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+			switch ((RelKind) relation->rd_rel->relkind)
+			{
+				case RELKIND_MATVIEW:
+					break;
+				case RELKIND_VIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_SEQUENCE:
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_TOASTVALUE:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is not a materialized view",
+									RelationGetRelationName(relation))));
+			}
 			break;
 		case OBJECT_FOREIGN_TABLE:
-			if (relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is not a foreign table",
-								RelationGetRelationName(relation))));
+			Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+			switch ((RelKind) relation->rd_rel->relkind)
+			{
+				case RELKIND_FOREIGN_TABLE:
+					break;
+				case RELKIND_MATVIEW:
+				case RELKIND_VIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_SEQUENCE:
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_TOASTVALUE:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is not a foreign table",
+									RelationGetRelationName(relation))));
+			}
 			break;
 		default:
 			elog(ERROR, "unrecognized objtype: %d", (int) objtype);
@@ -3795,7 +3878,8 @@ getRelationDescription(StringInfo buffer, Oid relid)
 
 	relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
 
-	switch (relForm->relkind)
+	Assert(RELKIND_IS_VALID((RelKind) relForm->relkind));
+	switch ((RelKind) relForm->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
@@ -3830,12 +3914,6 @@ getRelationDescription(StringInfo buffer, Oid relid)
 		case RELKIND_FOREIGN_TABLE:
 			appendStringInfo(buffer, _("foreign table %s"),
 							 relname);
-			break;
-		default:
-			/* shouldn't get here */
-			appendStringInfo(buffer, _("relation %s"),
-							 relname);
-			break;
 	}
 
 	ReleaseSysCache(relTup);
@@ -4276,7 +4354,8 @@ getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId)
 		elog(ERROR, "cache lookup failed for relation %u", relid);
 	relForm = (Form_pg_class) GETSTRUCT(relTup);
 
-	switch (relForm->relkind)
+	Assert(RELKIND_IS_VALID((RelKind) relForm->relkind));
+	switch ((RelKind) relForm->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
@@ -4303,11 +4382,6 @@ getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId)
 			break;
 		case RELKIND_FOREIGN_TABLE:
 			appendStringInfoString(buffer, "foreign table");
-			break;
-		default:
-			/* shouldn't get here */
-			appendStringInfoString(buffer, "relation");
-			break;
 	}
 
 	if (objectSubId != 0)
@@ -5451,11 +5525,9 @@ strlist_to_textarray(List *list)
 ObjectType
 get_relkind_objtype(char relkind)
 {
-	switch (relkind)
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
 	{
-		case RELKIND_RELATION:
-		case RELKIND_PARTITIONED_TABLE:
-			return OBJECT_TABLE;
 		case RELKIND_INDEX:
 		case RELKIND_PARTITIONED_INDEX:
 			return OBJECT_INDEX;
@@ -5467,10 +5539,12 @@ get_relkind_objtype(char relkind)
 			return OBJECT_MATVIEW;
 		case RELKIND_FOREIGN_TABLE:
 			return OBJECT_FOREIGN_TABLE;
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
 		case RELKIND_TOASTVALUE:
-			return OBJECT_TABLE;
-		default:
-			/* Per above, don't raise an error */
-			return OBJECT_TABLE;
+		/* Per above, don't raise an error */
+		case RELKIND_COMPOSITE_TYPE:
+			break;
 	}
+	return OBJECT_TABLE;
 }
diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 239ac017fa..973bddf544 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -235,8 +235,24 @@ has_partition_attrs(Relation rel, Bitmapset *attnums, bool *used_in_expr)
 	ListCell   *partexprs_item;
 	int			i;
 
-	if (attnums == NULL || rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		return false;
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			if (attnums == NULL)
+				return false;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			return false;
+	}
 
 	key = RelationGetPartitionKey(rel);
 	partnatts = get_partition_natts(key);
diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c
index 21cfdcace9..4df83df10d 100644
--- a/src/backend/catalog/pg_depend.c
+++ b/src/backend/catalog/pg_depend.c
@@ -836,15 +836,35 @@ getOwnedSequences_internal(Oid relid, AttrNumber attnum, char deptype)
 		 * We assume any auto or internal dependency of a sequence on a column
 		 * must be what we are looking for.  (We need the relkind test because
 		 * indexes can also have auto dependencies on columns.)
+		 *
+		 * Beware that relkind here may be NULL, which is not a valid member
+		 * of enum RelKind.
 		 */
-		if (deprec->classid == RelationRelationId &&
-			deprec->objsubid == 0 &&
-			deprec->refobjsubid != 0 &&
-			(deprec->deptype == DEPENDENCY_AUTO || deprec->deptype == DEPENDENCY_INTERNAL) &&
-			get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
+		Assert(get_rel_relkind(deprec->objid) == '\0' ||
+			   RELKIND_IS_VALID((RelKind) get_rel_relkind(deprec->objid)));
+		switch ((RelKind) get_rel_relkind(deprec->objid))
 		{
-			if (!deptype || deprec->deptype == deptype)
-				result = lappend_oid(result, deprec->objid);
+			case RELKIND_SEQUENCE:
+				if (deprec->classid == RelationRelationId &&
+					deprec->objsubid == 0 &&
+					deprec->refobjsubid != 0 &&
+					(deprec->deptype == DEPENDENCY_AUTO ||
+					 deprec->deptype == DEPENDENCY_INTERNAL) &&
+					(!deptype || deprec->deptype == deptype))
+				{
+					result = lappend_oid(result, deprec->objid);
+				}
+				break;
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				break;
 		}
 	}
 
@@ -940,9 +960,22 @@ get_constraint_index(Oid constraintId)
 			 * This is pure paranoia; there shouldn't be any other relkinds
 			 * dependent on a constraint.
 			 */
-			if (relkind != RELKIND_INDEX &&
-				relkind != RELKIND_PARTITIONED_INDEX)
-				continue;
+			Assert(RELKIND_IS_VALID((RelKind) relkind));
+			switch ((RelKind) relkind)
+			{
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+					break;
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+					continue;
+			}
 
 			indexId = deprec->objid;
 			break;
diff --git a/src/backend/catalog/pg_publication.c b/src/backend/catalog/pg_publication.c
index 09946be788..b34a97a6fa 100644
--- a/src/backend/catalog/pg_publication.c
+++ b/src/backend/catalog/pg_publication.c
@@ -50,13 +50,26 @@ static void
 check_publication_add_relation(Relation targetrel)
 {
 	/* Must be a regular or partitioned table */
-	if (RelationGetForm(targetrel)->relkind != RELKIND_RELATION &&
-		RelationGetForm(targetrel)->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("\"%s\" is not a table",
-						RelationGetRelationName(targetrel)),
-				 errdetail("Only tables can be added to publications.")));
+	Assert(RELKIND_IS_VALID((RelKind) RelationGetForm(targetrel)->relkind));
+	switch ((RelKind) RelationGetForm(targetrel)->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("\"%s\" is not a table",
+							RelationGetRelationName(targetrel)),
+					 errdetail("Only tables can be added to publications.")));
+	}
 
 	/* Can't be system table */
 	if (IsCatalogRelation(targetrel))
@@ -97,11 +110,25 @@ check_publication_add_relation(Relation targetrel)
 static bool
 is_publishable_class(Oid relid, Form_pg_class reltuple)
 {
-	return (reltuple->relkind == RELKIND_RELATION ||
-			reltuple->relkind == RELKIND_PARTITIONED_TABLE) &&
-		!IsCatalogRelationOid(relid) &&
-		reltuple->relpersistence == RELPERSISTENCE_PERMANENT &&
-		relid >= FirstNormalObjectId;
+	Assert(RELKIND_IS_VALID((RelKind) reltuple->relkind));
+	switch ((RelKind) reltuple->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			return (!IsCatalogRelationOid(relid) &&
+					reltuple->relpersistence == RELPERSISTENCE_PERMANENT &&
+					relid >= FirstNormalObjectId);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			return false;
+	}
 }
 
 /*
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 79ffe317dd..d846e27667 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -658,10 +658,23 @@ GenerateTypeDependencies(HeapTuple typeTuple,
 	{
 		ObjectAddressSet(referenced, RelationRelationId, typeForm->typrelid);
 
-		if (relationKind != RELKIND_COMPOSITE_TYPE)
-			recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
-		else
-			recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
+		Assert(RELKIND_IS_VALID((RelKind) relationKind));
+		switch ((RelKind) relationKind)
+		{
+			case RELKIND_COMPOSITE_TYPE:
+				recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
+		}
 	}
 
 	/*
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index c40d25b301..b25de92a17 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -96,12 +96,25 @@ BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid)
 
 	rel = table_openrv(makeRangeVar(NULL, relName, -1), AccessExclusiveLock);
 
-	if (rel->rd_rel->relkind != RELKIND_RELATION &&
-		rel->rd_rel->relkind != RELKIND_MATVIEW)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table or materialized view",
-						relName)));
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table or materialized view",
+							relName)));
+	}
 
 	/* create_toast_table does all the work */
 	if (!create_toast_table(rel, toastOid, toastIndexOid, (Datum) 0,
@@ -378,8 +391,22 @@ needs_toast_table(Relation rel)
 	/*
 	 * No need to create a TOAST table for partitioned tables.
 	 */
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		return false;
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			return false;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
+	}
 
 	/*
 	 * We cannot allow toasting a shared relation after initdb (because
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 924ef37c81..ac36d93aa7 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -196,54 +196,67 @@ analyze_rel(Oid relid, RangeVar *relation,
 	/*
 	 * Check that it's of an analyzable relkind, and set up appropriately.
 	 */
-	if (onerel->rd_rel->relkind == RELKIND_RELATION ||
-		onerel->rd_rel->relkind == RELKIND_MATVIEW)
+	Assert(RELKIND_IS_VALID((RelKind) onerel->rd_rel->relkind));
+	switch ((RelKind) onerel->rd_rel->relkind)
 	{
-		/* Regular table, so we'll use the regular row acquisition function */
-		acquirefunc = acquire_sample_rows;
-		/* Also get regular table's size */
-		relpages = RelationGetNumberOfBlocks(onerel);
-	}
-	else if (onerel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-	{
-		/*
-		 * For a foreign table, call the FDW's hook function to see whether it
-		 * supports analysis.
-		 */
-		FdwRoutine *fdwroutine;
-		bool		ok = false;
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+			/*
+			 * Regular table, so we'll use the regular row acquisition
+			 * function
+			 */
+			acquirefunc = acquire_sample_rows;
+			/* Also get regular table's size */
+			relpages = RelationGetNumberOfBlocks(onerel);
+			break;
+		case RELKIND_FOREIGN_TABLE:
+			{
+				/*
+				 * For a foreign table, call the FDW's hook function to see
+				 * whether it supports analysis.
+				 */
+				FdwRoutine *fdwroutine;
+				bool		ok = false;
 
-		fdwroutine = GetFdwRoutineForRelation(onerel, false);
+				fdwroutine = GetFdwRoutineForRelation(onerel, false);
 
-		if (fdwroutine->AnalyzeForeignTable != NULL)
-			ok = fdwroutine->AnalyzeForeignTable(onerel,
-												 &acquirefunc,
-												 &relpages);
+				if (fdwroutine->AnalyzeForeignTable != NULL)
+					ok = fdwroutine->AnalyzeForeignTable(onerel,
+														 &acquirefunc,
+														 &relpages);
 
-		if (!ok)
-		{
-			ereport(WARNING,
-					(errmsg("skipping \"%s\" --- cannot analyze this foreign table",
-							RelationGetRelationName(onerel))));
+				if (!ok)
+				{
+					ereport(WARNING,
+							(errmsg("skipping \"%s\" --- cannot analyze this foreign table",
+									RelationGetRelationName(onerel))));
+					relation_close(onerel, ShareUpdateExclusiveLock);
+					return;
+				}
+			}
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+			/*
+			 * For partitioned tables, we want to do the recursive ANALYZE
+			 * below.
+			 */
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			/*
+			 * No need for a WARNING if we already complained during
+			 * VACUUM
+			 */
+			if (!(params->options & VACOPT_VACUUM))
+				ereport(WARNING,
+						(errmsg("skipping \"%s\" --- cannot analyze non-tables or special system tables",
+								RelationGetRelationName(onerel))));
 			relation_close(onerel, ShareUpdateExclusiveLock);
 			return;
-		}
-	}
-	else if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-	{
-		/*
-		 * For partitioned tables, we want to do the recursive ANALYZE below.
-		 */
-	}
-	else
-	{
-		/* No need for a WARNING if we already complained during VACUUM */
-		if (!(params->options & VACOPT_VACUUM))
-			ereport(WARNING,
-					(errmsg("skipping \"%s\" --- cannot analyze non-tables or special system tables",
-							RelationGetRelationName(onerel))));
-		relation_close(onerel, ShareUpdateExclusiveLock);
-		return;
 	}
 
 	/*
@@ -259,9 +272,23 @@ analyze_rel(Oid relid, RangeVar *relation,
 	 * Do the normal non-recursive ANALYZE.  We can skip this for partitioned
 	 * tables, which don't contain any rows.
 	 */
-	if (onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		do_analyze_rel(onerel, params, va_cols, acquirefunc,
-					   relpages, false, in_outer_xact, elevel);
+	Assert(RELKIND_IS_VALID((RelKind) onerel->rd_rel->relkind));
+	switch ((RelKind) onerel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			do_analyze_rel(onerel, params, va_cols, acquirefunc,
+						   relpages, false, in_outer_xact, elevel);
+	}
 
 	/*
 	 * If there are child tables, do recursive ANALYZE.
@@ -1283,49 +1310,66 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
 		}
 
 		/* Check table type (MATVIEW can't happen, but might as well allow) */
-		if (childrel->rd_rel->relkind == RELKIND_RELATION ||
-			childrel->rd_rel->relkind == RELKIND_MATVIEW)
+		Assert(RELKIND_IS_VALID((RelKind) childrel->rd_rel->relkind));
+		switch ((RelKind) childrel->rd_rel->relkind)
 		{
-			/* Regular table, so use the regular row acquisition function */
-			acquirefunc = acquire_sample_rows;
-			relpages = RelationGetNumberOfBlocks(childrel);
-		}
-		else if (childrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-		{
-			/*
-			 * For a foreign table, call the FDW's hook function to see
-			 * whether it supports analysis.
-			 */
-			FdwRoutine *fdwroutine;
-			bool		ok = false;
+			case RELKIND_RELATION:
+			case RELKIND_MATVIEW:
+				{
+					/*
+					 * Regular table, so use the regular row acquisition
+					 * function
+					 */
+					acquirefunc = acquire_sample_rows;
+					relpages = RelationGetNumberOfBlocks(childrel);
+				}
+				break;
+			case RELKIND_FOREIGN_TABLE:
+				{
+					/*
+					 * For a foreign table, call the FDW's hook function to
+					 * see whether it supports analysis.
+					 */
+					FdwRoutine *fdwroutine;
+					bool		ok = false;
 
-			fdwroutine = GetFdwRoutineForRelation(childrel, false);
+					fdwroutine = GetFdwRoutineForRelation(childrel, false);
 
-			if (fdwroutine->AnalyzeForeignTable != NULL)
-				ok = fdwroutine->AnalyzeForeignTable(childrel,
-													 &acquirefunc,
-													 &relpages);
+					if (fdwroutine->AnalyzeForeignTable != NULL)
+						ok = fdwroutine->AnalyzeForeignTable(childrel,
+															 &acquirefunc,
+															 &relpages);
 
-			if (!ok)
-			{
-				/* ignore, but release the lock on it */
-				Assert(childrel != onerel);
-				table_close(childrel, AccessShareLock);
-				continue;
-			}
-		}
-		else
-		{
-			/*
-			 * ignore, but release the lock on it.  don't try to unlock the
-			 * passed-in relation
-			 */
-			Assert(childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
-			if (childrel != onerel)
-				table_close(childrel, AccessShareLock);
-			else
-				table_close(childrel, NoLock);
-			continue;
+					if (!ok)
+					{
+						/* ignore, but release the lock on it */
+						Assert(childrel != onerel);
+						table_close(childrel, AccessShareLock);
+						continue;
+					}
+				}
+				break;
+			case RELKIND_PARTITIONED_TABLE:
+				{
+					/*
+					 * ignore, but release the lock on it.  don't try to
+					 * unlock the passed-in relation
+					 */
+					if (childrel != onerel)
+						table_close(childrel, AccessShareLock);
+					else
+						table_close(childrel, NoLock);
+					continue;
+				}
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				Assert(false);
+				break;
 		}
 
 		/* OK, we'll process this child */
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 04d12a7ece..9d228407c6 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -127,10 +127,25 @@ cluster(ClusterStmt *stmt, bool isTopLevel)
 		/*
 		 * Reject clustering a partitioned table.
 		 */
-		if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-			ereport(ERROR,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("cannot cluster a partitioned table")));
+		Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+		switch ((RelKind) rel->rd_rel->relkind)
+		{
+			case RELKIND_PARTITIONED_TABLE:
+				ereport(ERROR,
+						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+						 errmsg("cannot cluster a partitioned table")));
+				break;
+			case RELKIND_RELATION:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				break;
+		}
 
 		if (stmt->indexname == NULL)
 		{
@@ -383,12 +398,27 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
 	 * multi-relation request -- for example, CLUSTER was run on the entire
 	 * database.
 	 */
-	if (OldHeap->rd_rel->relkind == RELKIND_MATVIEW &&
-		!RelationIsPopulated(OldHeap))
+	Assert(RELKIND_IS_VALID((RelKind) OldHeap->rd_rel->relkind));
+	switch ((RelKind) OldHeap->rd_rel->relkind)
 	{
-		relation_close(OldHeap, AccessExclusiveLock);
-		pgstat_progress_end_command();
-		return;
+		case RELKIND_MATVIEW:
+			if (!RelationIsPopulated(OldHeap))
+			{
+				relation_close(OldHeap, AccessExclusiveLock);
+				pgstat_progress_end_command();
+				return;
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
 	}
 
 	/*
@@ -484,10 +514,25 @@ mark_index_clustered(Relation rel, Oid indexOid, bool is_internal)
 	ListCell   *index;
 
 	/* Disallow applying to a partitioned table */
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("cannot mark index clustered in partitioned table")));
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			ereport(ERROR,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("cannot mark index clustered in partitioned table")));
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
+	}
 
 	/*
 	 * If the index is already marked clustered, no need to do anything.
@@ -1103,12 +1148,24 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 	 */
 
 	/* set rel1's frozen Xid and minimum MultiXid */
-	if (relform1->relkind != RELKIND_INDEX)
+	Assert(RELKIND_IS_VALID((RelKind) relform1->relkind));
+	switch ((RelKind) relform1->relkind)
 	{
-		Assert(!TransactionIdIsValid(frozenXid) ||
-			   TransactionIdIsNormal(frozenXid));
-		relform1->relfrozenxid = frozenXid;
-		relform1->relminmxid = cutoffMulti;
+		case RELKIND_INDEX:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			Assert(!TransactionIdIsValid(frozenXid) ||
+				   TransactionIdIsNormal(frozenXid));
+			relform1->relfrozenxid = frozenXid;
+			relform1->relminmxid = cutoffMulti;
 	}
 
 	/* swap size statistics too, since new rel has freshly-updated stats */
@@ -1267,27 +1324,42 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 	 * valid index. The swap can actually be safely done only if the relations
 	 * have indexes.
 	 */
-	if (swap_toast_by_content &&
-		relform1->relkind == RELKIND_TOASTVALUE &&
-		relform2->relkind == RELKIND_TOASTVALUE)
+	Assert(RELKIND_IS_VALID((RelKind) relform1->relkind));
+	switch ((RelKind) relform1->relkind)
 	{
-		Oid			toastIndex1,
-					toastIndex2;
-
-		/* Get valid index for each relation */
-		toastIndex1 = toast_get_valid_index(r1,
-											AccessExclusiveLock);
-		toastIndex2 = toast_get_valid_index(r2,
-											AccessExclusiveLock);
-
-		swap_relation_files(toastIndex1,
-							toastIndex2,
-							target_is_pg_class,
-							swap_toast_by_content,
-							is_internal,
-							InvalidTransactionId,
-							InvalidMultiXactId,
-							mapped_tables);
+		case RELKIND_TOASTVALUE:
+			if (swap_toast_by_content &&
+				relform2->relkind == RELKIND_TOASTVALUE)
+			{
+				Oid			toastIndex1,
+							toastIndex2;
+
+				/* Get valid index for each relation */
+				toastIndex1 = toast_get_valid_index(r1,
+													AccessExclusiveLock);
+				toastIndex2 = toast_get_valid_index(r2,
+													AccessExclusiveLock);
+
+				swap_relation_files(toastIndex1,
+									toastIndex2,
+									target_is_pg_class,
+									swap_toast_by_content,
+									is_internal,
+									InvalidTransactionId,
+									InvalidMultiXactId,
+									mapped_tables);
+			}
+			break;
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+			break;
 	}
 
 	/* Clean up. */
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index 0ff9ca9f2c..3213bee3ce 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -90,16 +90,26 @@ CommentObject(CommentStmt *stmt)
 			 * versions, so dumping per-column comments could create reload
 			 * failures.
 			 */
-			if (relation->rd_rel->relkind != RELKIND_RELATION &&
-				relation->rd_rel->relkind != RELKIND_VIEW &&
-				relation->rd_rel->relkind != RELKIND_MATVIEW &&
-				relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
-				relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
-				relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
-								RelationGetRelationName(relation))));
+			Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+			switch ((RelKind) relation->rd_rel->relkind)
+			{
+				case RELKIND_RELATION:
+				case RELKIND_VIEW:
+				case RELKIND_MATVIEW:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_PARTITIONED_TABLE:
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_SEQUENCE:
+				case RELKIND_INDEX:
+				case RELKIND_TOASTVALUE:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
+									RelationGetRelationName(relation))));
+					break;
+			}
 			break;
 		default:
 			break;
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 44da71c4cb..19d5f7757a 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -1834,42 +1834,56 @@ BeginCopyTo(ParseState *pstate,
 	bool		pipe = (filename == NULL);
 	MemoryContext oldcontext;
 
-	if (rel != NULL && rel->rd_rel->relkind != RELKIND_RELATION)
+	if (rel != NULL)
 	{
-		if (rel->rd_rel->relkind == RELKIND_VIEW)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot copy from view \"%s\"",
-							RelationGetRelationName(rel)),
-					 errhint("Try the COPY (SELECT ...) TO variant.")));
-		else if (rel->rd_rel->relkind == RELKIND_MATVIEW)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot copy from materialized view \"%s\"",
-							RelationGetRelationName(rel)),
-					 errhint("Try the COPY (SELECT ...) TO variant.")));
-		else if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot copy from foreign table \"%s\"",
-							RelationGetRelationName(rel)),
-					 errhint("Try the COPY (SELECT ...) TO variant.")));
-		else if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot copy from sequence \"%s\"",
-							RelationGetRelationName(rel))));
-		else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot copy from partitioned table \"%s\"",
-							RelationGetRelationName(rel)),
-					 errhint("Try the COPY (SELECT ...) TO variant.")));
-		else
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot copy from non-table relation \"%s\"",
-							RelationGetRelationName(rel))));
+		Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+		switch ((RelKind) rel->rd_rel->relkind)
+		{
+			case RELKIND_RELATION:
+				break;
+			case RELKIND_SEQUENCE:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot copy from sequence \"%s\"",
+								RelationGetRelationName(rel))));
+				break;
+			case RELKIND_FOREIGN_TABLE:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot copy from foreign table \"%s\"",
+								RelationGetRelationName(rel)),
+						 errhint("Try the COPY (SELECT ...) TO variant.")));
+				break;
+			case RELKIND_MATVIEW:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot copy from materialized view \"%s\"",
+								RelationGetRelationName(rel)),
+						 errhint("Try the COPY (SELECT ...) TO variant.")));
+				break;
+			case RELKIND_PARTITIONED_TABLE:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot copy from partitioned table \"%s\"",
+								RelationGetRelationName(rel)),
+						 errhint("Try the COPY (SELECT ...) TO variant.")));
+				break;
+			case RELKIND_VIEW:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot copy from view \"%s\"",
+								RelationGetRelationName(rel)),
+						 errhint("Try the COPY (SELECT ...) TO variant.")));
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_TOASTVALUE:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot copy from non-table relation \"%s\"",
+								RelationGetRelationName(rel))));
+		}
 	}
 
 	cstate = BeginCopy(pstate, false, rel, query, queryRelId, attnamelist,
@@ -2393,8 +2407,22 @@ CopyMultiInsertInfoInit(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 	 * Buffers for partitioned tables will just be setup when we need to send
 	 * tuples their way for the first time.
 	 */
-	if (rri->ri_RelationDesc->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		CopyMultiInsertInfoSetupBuffer(miinfo, rri);
+	Assert(RELKIND_IS_VALID((RelKind) rri->ri_RelationDesc->rd_rel->relkind));
+	switch ((RelKind) rri->ri_RelationDesc->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			CopyMultiInsertInfoSetupBuffer(miinfo, rri);
+	}
 }
 
 /*
@@ -2681,33 +2709,44 @@ CopyFrom(CopyState cstate)
 	 * an INSTEAD OF INSERT row trigger.  (Currently, such triggers are only
 	 * allowed on views, so we only hint about them in the view case.)
 	 */
-	if (cstate->rel->rd_rel->relkind != RELKIND_RELATION &&
-		cstate->rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
-		cstate->rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE &&
-		!(cstate->rel->trigdesc &&
+	if (!(cstate->rel->trigdesc &&
 		  cstate->rel->trigdesc->trig_insert_instead_row))
 	{
-		if (cstate->rel->rd_rel->relkind == RELKIND_VIEW)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot copy to view \"%s\"",
-							RelationGetRelationName(cstate->rel)),
-					 errhint("To enable copying to a view, provide an INSTEAD OF INSERT trigger.")));
-		else if (cstate->rel->rd_rel->relkind == RELKIND_MATVIEW)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot copy to materialized view \"%s\"",
-							RelationGetRelationName(cstate->rel))));
-		else if (cstate->rel->rd_rel->relkind == RELKIND_SEQUENCE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot copy to sequence \"%s\"",
-							RelationGetRelationName(cstate->rel))));
-		else
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot copy to non-table relation \"%s\"",
-							RelationGetRelationName(cstate->rel))));
+		Assert(RELKIND_IS_VALID((RelKind) cstate->rel->rd_rel->relkind));
+		switch ((RelKind) cstate->rel->rd_rel->relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_TABLE:
+				break;
+			case RELKIND_VIEW:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot copy to view \"%s\"",
+								RelationGetRelationName(cstate->rel)),
+						 errhint("To enable copying to a view, provide an INSTEAD OF INSERT trigger.")));
+				break;
+			case RELKIND_MATVIEW:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot copy to materialized view \"%s\"",
+								RelationGetRelationName(cstate->rel))));
+				break;
+			case RELKIND_SEQUENCE:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot copy to sequence \"%s\"",
+								RelationGetRelationName(cstate->rel))));
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_TOASTVALUE:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot copy to non-table relation \"%s\"",
+								RelationGetRelationName(cstate->rel))));
+		}
 	}
 
 	/*
@@ -2742,11 +2781,24 @@ CopyFrom(CopyState cstate)
 		 * tuples to a small number of partitions.  It seems better just to
 		 * raise an ERROR for partitioned tables.
 		 */
-		if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		Assert(RELKIND_IS_VALID((RelKind) cstate->rel->rd_rel->relkind));
+		switch ((RelKind) cstate->rel->rd_rel->relkind)
 		{
-			ereport(ERROR,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("cannot perform COPY FREEZE on a partitioned table")));
+			case RELKIND_PARTITIONED_TABLE:
+				ereport(ERROR,
+						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+						 errmsg("cannot perform COPY FREEZE on a partitioned table")));
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				break;
 		}
 
 		/*
@@ -2831,8 +2883,23 @@ CopyFrom(CopyState cstate)
 	 * If the named relation is a partitioned table, initialize state for
 	 * CopyFrom tuple routing.
 	 */
-	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		proute = ExecSetupPartitionTupleRouting(estate, NULL, cstate->rel);
+	Assert(RELKIND_IS_VALID((RelKind) cstate->rel->rd_rel->relkind));
+	switch ((RelKind) cstate->rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			proute = ExecSetupPartitionTupleRouting(estate, NULL, cstate->rel);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
+	}
 
 	if (cstate->whereClause)
 		cstate->qualexpr = ExecInitQual(castNode(List, cstate->whereClause),
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 3b69ab7ed5..5979f8224c 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -3280,8 +3280,8 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt,
 		case OBJECT_SUBSCRIPTION:
 		case OBJECT_TABLESPACE:
 			ereport(ERROR,
-				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-				 errmsg("cannot add an object of this type to an extension")));
+					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+					 errmsg("cannot add an object of this type to an extension")));
 			break;
 		default:
 			/* OK */
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 2baca12c5f..273d00bdb9 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -615,7 +615,8 @@ DefineIndex(Oid relationId,
 	namespaceId = RelationGetNamespace(rel);
 
 	/* Ensure that it makes sense to index this kind of relation */
-	switch (rel->rd_rel->relkind)
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_MATVIEW:
@@ -633,12 +634,16 @@ DefineIndex(Oid relationId,
 					 errmsg("cannot create index on foreign table \"%s\"",
 							RelationGetRelationName(rel))));
 			break;
-		default:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("\"%s\" is not a table or materialized view",
 							RelationGetRelationName(rel))));
-			break;
 	}
 
 	/*
@@ -1190,18 +1195,33 @@ DefineIndex(Oid relationId,
 				 * those if a regular index, or fail if trying to create a
 				 * constraint index.
 				 */
-				if (childrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+				Assert(RELKIND_IS_VALID((RelKind) childrel->rd_rel->relkind));
+				switch ((RelKind) childrel->rd_rel->relkind)
 				{
-					if (stmt->unique || stmt->primary)
-						ereport(ERROR,
-								(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-								 errmsg("cannot create unique index on partitioned table \"%s\"",
-										RelationGetRelationName(rel)),
-								 errdetail("Table \"%s\" contains partitions that are foreign tables.",
-										   RelationGetRelationName(rel))));
-
-					table_close(childrel, lockmode);
-					continue;
+					case RELKIND_FOREIGN_TABLE:
+						{
+							if (stmt->unique || stmt->primary)
+								ereport(ERROR,
+										(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+										 errmsg("cannot create unique index on partitioned table \"%s\"",
+												RelationGetRelationName(rel)),
+										 errdetail("Table \"%s\" contains partitions that are foreign tables.",
+												   RelationGetRelationName(rel))));
+
+							table_close(childrel, lockmode);
+							continue;
+						}
+						break;
+					case RELKIND_SEQUENCE:
+					case RELKIND_COMPOSITE_TYPE:
+					case RELKIND_INDEX:
+					case RELKIND_MATVIEW:
+					case RELKIND_PARTITIONED_TABLE:
+					case RELKIND_RELATION:
+					case RELKIND_TOASTVALUE:
+					case RELKIND_PARTITIONED_INDEX:
+					case RELKIND_VIEW:
+						break;
 				}
 
 				childidxs = RelationGetIndexList(childrel);
@@ -2451,10 +2471,22 @@ ReindexIndex(RangeVar *indexRelation, int options, bool concurrent)
 	 */
 	irel = index_open(indOid, NoLock);
 
-	if (irel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
+	Assert(RELKIND_IS_VALID((RelKind) irel->rd_rel->relkind));
+	switch ((RelKind) irel->rd_rel->relkind)
 	{
-		ReindexPartitionedIndex(irel);
-		return;
+		case RELKIND_PARTITIONED_INDEX:
+			ReindexPartitionedIndex(irel);
+			return;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
 	}
 
 	persistence = irel->rd_rel->relpersistence;
@@ -2510,11 +2542,24 @@ RangeVarCallbackForReindexIndex(const RangeVar *relation,
 	relkind = get_rel_relkind(relId);
 	if (!relkind)
 		return;
-	if (relkind != RELKIND_INDEX &&
-		relkind != RELKIND_PARTITIONED_INDEX)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not an index", relation->relname)));
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not an index", relation->relname)));
+	}
 
 	/* Check permissions */
 	if (!pg_class_ownercheck(relId, GetUserId()))
@@ -2694,9 +2739,22 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
 		 * partitioned tables, and expand that afterwards into relids,
 		 * ignoring any duplicates.
 		 */
-		if (classtuple->relkind != RELKIND_RELATION &&
-			classtuple->relkind != RELKIND_MATVIEW)
-			continue;
+		Assert(RELKIND_IS_VALID((RelKind) classtuple->relkind));
+		switch ((RelKind) classtuple->relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_MATVIEW:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				continue;
+		}
 
 		/* Skip temp tables of other backends; we can't reindex them at all */
 		if (classtuple->relpersistence == RELPERSISTENCE_TEMP &&
@@ -2867,7 +2925,8 @@ ReindexRelationConcurrently(Oid relationOid, int options)
 	 * Extract the list of indexes that are going to be rebuilt based on the
 	 * relation Oid given by caller.
 	 */
-	switch (relkind)
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_MATVIEW:
@@ -3017,12 +3076,15 @@ ReindexRelationConcurrently(Oid relationOid, int options)
 					 errmsg("REINDEX of partitioned tables is not yet implemented, skipping \"%s\"",
 							get_rel_name(relationOid))));
 			return false;
-		default:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
 			/* Return error if type of relation is not supported */
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("cannot reindex this type of relation concurrently")));
-			break;
 	}
 
 	/* Definitely no indexes, so leave */
@@ -3443,30 +3505,41 @@ ReindexRelationConcurrently(Oid relationOid, int options)
 	/* Log what we did */
 	if (options & REINDEXOPT_VERBOSE)
 	{
-		if (relkind == RELKIND_INDEX)
-			ereport(INFO,
-					(errmsg("index \"%s.%s\" was reindexed",
-							relationNamespace, relationName),
-					 errdetail("%s.",
-							   pg_rusage_show(&ru0))));
-		else
+		Assert(RELKIND_IS_VALID((RelKind) relkind));
+		switch ((RelKind) relkind)
 		{
-			foreach(lc, newIndexIds)
-			{
-				Oid			indOid = lfirst_oid(lc);
-
+			case RELKIND_INDEX:
 				ereport(INFO,
 						(errmsg("index \"%s.%s\" was reindexed",
-								get_namespace_name(get_rel_namespace(indOid)),
-								get_rel_name(indOid))));
-				/* Don't show rusage here, since it's not per index. */
-			}
+								relationNamespace, relationName),
+						 errdetail("%s.",
+								   pg_rusage_show(&ru0))));
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				foreach(lc, newIndexIds)
+				{
+					Oid			indOid = lfirst_oid(lc);
 
-			ereport(INFO,
-					(errmsg("table \"%s.%s\" was reindexed",
-							relationNamespace, relationName),
-					 errdetail("%s.",
-							   pg_rusage_show(&ru0))));
+					ereport(INFO,
+							(errmsg("index \"%s.%s\" was reindexed",
+									get_namespace_name(get_rel_namespace(indOid)),
+									get_rel_name(indOid))));
+					/* Don't show rusage here, since it's not per index. */
+				}
+
+				ereport(INFO,
+						(errmsg("table \"%s.%s\" was reindexed",
+								relationNamespace, relationName),
+						 errdetail("%s.",
+								   pg_rusage_show(&ru0))));
 		}
 	}
 
@@ -3508,8 +3581,23 @@ IndexSetParentIndex(Relation partitionIdx, Oid parentOid)
 	bool		fix_dependencies;
 
 	/* Make sure this is an index */
-	Assert(partitionIdx->rd_rel->relkind == RELKIND_INDEX ||
-		   partitionIdx->rd_rel->relkind == RELKIND_PARTITIONED_INDEX);
+	Assert(RELKIND_IS_VALID((RelKind) partitionIdx->rd_rel->relkind));
+	switch ((RelKind) partitionIdx->rd_rel->relkind)
+	{
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			break;				/* ok */
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			Assert(false);
+			break;
+	}
 
 	/*
 	 * Scan pg_inherits for rows linking our index to some parent.
diff --git a/src/backend/commands/lockcmds.c b/src/backend/commands/lockcmds.c
index d8cafc42bb..56c6b2973c 100644
--- a/src/backend/commands/lockcmds.c
+++ b/src/backend/commands/lockcmds.c
@@ -56,10 +56,24 @@ LockTableCommand(LockStmt *lockstmt)
 										  RangeVarCallbackForLockTable,
 										  (void *) &lockstmt->mode);
 
-		if (get_rel_relkind(reloid) == RELKIND_VIEW)
-			LockViewRecurse(reloid, lockstmt->mode, lockstmt->nowait, NIL);
-		else if (recurse)
-			LockTableRecurse(reloid, lockstmt->mode, lockstmt->nowait);
+		Assert(RELKIND_IS_VALID((RelKind) get_rel_relkind(reloid)));
+		switch ((RelKind) get_rel_relkind(reloid))
+		{
+			case RELKIND_VIEW:
+				LockViewRecurse(reloid, lockstmt->mode, lockstmt->nowait, NIL);
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+				if (recurse)
+					LockTableRecurse(reloid, lockstmt->mode, lockstmt->nowait);
+		}
 	}
 }
 
@@ -84,12 +98,25 @@ RangeVarCallbackForLockTable(const RangeVar *rv, Oid relid, Oid oldrelid,
 								 * check */
 
 	/* Currently, we only allow plain tables or views to be locked */
-	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE &&
-		relkind != RELKIND_VIEW)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table or view",
-						rv->relname)));
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_VIEW:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table or view",
+							rv->relname)));
+	}
 
 	/*
 	 * Make note if a temporary relation has been accessed in this
@@ -201,11 +228,30 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context)
 				 strcmp(rte->eref->aliasname, "new") == 0))
 				continue;
 
-			/* Currently, we only allow plain tables or views to be locked. */
-			if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE &&
-				relkind != RELKIND_VIEW)
+			if (relkind == '\0')
 				continue;
 
+			Assert(RELKIND_IS_VALID((RelKind) relkind));
+			switch ((RelKind) relkind)
+			{
+				/*
+				 * Currently, we only allow plain tables or views to be
+				 * locked.
+				 */
+				case RELKIND_RELATION:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_VIEW:
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_TOASTVALUE:
+					continue;
+			}
+
 			/* Check infinite recursion in the view definition. */
 			if (list_member_oid(context->ancestor_views, relid))
 				ereport(ERROR,
@@ -227,10 +273,25 @@ LockViewRecurse_walker(Node *node, LockViewRecurse_context *context)
 						 errmsg("could not obtain lock on relation \"%s\"",
 								relname)));
 
-			if (relkind == RELKIND_VIEW)
-				LockViewRecurse(relid, context->lockmode, context->nowait, context->ancestor_views);
-			else if (rte->inh)
-				LockTableRecurse(relid, context->lockmode, context->nowait);
+			/* We already checked for relkind == '\0', above */
+			Assert(RELKIND_IS_VALID((RelKind) relkind));
+			switch ((RelKind) relkind)
+			{
+				case RELKIND_VIEW:
+					LockViewRecurse(relid, context->lockmode, context->nowait, context->ancestor_views);
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+					if (rte->inh)
+						LockTableRecurse(relid, context->lockmode, context->nowait);
+			}
 		}
 
 		return query_tree_walker(query,
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index 4b4e469493..ff8affa074 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -89,10 +89,24 @@ RangeVarCallbackForPolicy(const RangeVar *rv, Oid relid, Oid oldrelid,
 						rv->relname)));
 
 	/* Relation type MUST be a table. */
-	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table", rv->relname)));
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table", rv->relname)));
+	}
 
 	ReleaseSysCache(tuple);
 }
@@ -388,12 +402,25 @@ RemovePolicyById(Oid policy_id)
 	relid = ((Form_pg_policy) GETSTRUCT(tuple))->polrelid;
 
 	rel = table_open(relid, AccessExclusiveLock);
-	if (rel->rd_rel->relkind != RELKIND_RELATION &&
-		rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table",
-						RelationGetRelationName(rel))));
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table",
+							RelationGetRelationName(rel))));
+	}
 
 	if (!allowSystemTableMods && IsSystemRelation(rel))
 		ereport(ERROR,
@@ -478,12 +505,25 @@ RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
 
 	rel = relation_open(relid, AccessExclusiveLock);
 
-	if (rel->rd_rel->relkind != RELKIND_RELATION &&
-		rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table",
-						RelationGetRelationName(rel))));
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table",
+							RelationGetRelationName(rel))));
+	}
 
 	if (!allowSystemTableMods && IsSystemRelation(rel))
 		ereport(ERROR,
diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c
index eabbc7473b..dbc5624285 100644
--- a/src/backend/commands/publicationcmds.c
+++ b/src/backend/commands/publicationcmds.c
@@ -548,33 +548,48 @@ OpenTableList(List *tables)
 		 * children other than its partitions, which need not be explicitly
 		 * added to the publication.
 		 */
-		if (recurse && rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
+		Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+		switch ((RelKind) rel->rd_rel->relkind)
 		{
-			List	   *children;
-			ListCell   *child;
-
-			children = find_all_inheritors(myrelid, ShareUpdateExclusiveLock,
-										   NULL);
-
-			foreach(child, children)
-			{
-				Oid			childrelid = lfirst_oid(child);
-
-				/* Allow query cancel in case this takes a long time */
-				CHECK_FOR_INTERRUPTS();
-
-				/*
-				 * Skip duplicates if user specified both parent and child
-				 * tables.
-				 */
-				if (list_member_oid(relids, childrelid))
-					continue;
-
-				/* find_all_inheritors already got lock */
-				rel = table_open(childrelid, NoLock);
-				rels = lappend(rels, rel);
-				relids = lappend_oid(relids, childrelid);
-			}
+			case RELKIND_PARTITIONED_TABLE:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				if (recurse)
+				{
+					List	   *children;
+					ListCell   *child;
+
+					children = find_all_inheritors(myrelid, ShareUpdateExclusiveLock,
+												   NULL);
+
+					foreach(child, children)
+					{
+						Oid			childrelid = lfirst_oid(child);
+
+						/* Allow query cancel in case this takes a long time */
+						CHECK_FOR_INTERRUPTS();
+
+						/*
+						 * Skip duplicates if user specified both parent and
+						 * child tables.
+						 */
+						if (list_member_oid(relids, childrelid))
+							continue;
+
+						/* find_all_inheritors already got lock */
+						rel = table_open(childrelid, NoLock);
+						rels = lappend(rels, rel);
+						relids = lappend_oid(relids, childrelid);
+					}
+				}
 		}
 	}
 
diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c
index ee036e9087..4ddf7616de 100644
--- a/src/backend/commands/seclabel.c
+++ b/src/backend/commands/seclabel.c
@@ -180,16 +180,25 @@ ExecSecLabelStmt(SecLabelStmt *stmt)
 			 * materialized views, composite types, and foreign tables (which
 			 * are the only relkinds for which pg_dump will dump labels).
 			 */
-			if (relation->rd_rel->relkind != RELKIND_RELATION &&
-				relation->rd_rel->relkind != RELKIND_VIEW &&
-				relation->rd_rel->relkind != RELKIND_MATVIEW &&
-				relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
-				relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
-				relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
-								RelationGetRelationName(relation))));
+			Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+			switch ((RelKind) relation->rd_rel->relkind)
+			{
+				case RELKIND_RELATION:
+				case RELKIND_VIEW:
+				case RELKIND_MATVIEW:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_PARTITIONED_TABLE:
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_SEQUENCE:
+				case RELKIND_INDEX:
+				case RELKIND_TOASTVALUE:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
+									RelationGetRelationName(relation))));
+			}
 			break;
 		default:
 			break;
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 6aab73bfd4..803eb6bc8a 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1675,14 +1675,25 @@ process_owned_by(Relation seqrel, List *owned_by, bool for_identity)
 		tablerel = relation_openrv(rel, AccessShareLock);
 
 		/* Must be a regular or foreign table */
-		if (!(tablerel->rd_rel->relkind == RELKIND_RELATION ||
-			  tablerel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
-			  tablerel->rd_rel->relkind == RELKIND_VIEW ||
-			  tablerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("referenced relation \"%s\" is not a table or foreign table",
-							RelationGetRelationName(tablerel))));
+		Assert(RELKIND_IS_VALID((RelKind) tablerel->rd_rel->relkind));
+		switch ((RelKind) tablerel->rd_rel->relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_VIEW:
+			case RELKIND_PARTITIONED_TABLE:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_TOASTVALUE:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("referenced relation \"%s\" is not a table or foreign table",
+								RelationGetRelationName(tablerel))));
+		}
 
 		/* We insist on same owner and schema */
 		if (seqrel->rd_rel->relowner != tablerel->rd_rel->relowner)
diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c
index 974828545c..1cec7552d4 100644
--- a/src/backend/commands/statscmds.c
+++ b/src/backend/commands/statscmds.c
@@ -122,14 +122,25 @@ CreateStatistics(CreateStatsStmt *stmt)
 		rel = relation_openrv((RangeVar *) rln, ShareUpdateExclusiveLock);
 
 		/* Restrict to allowed relation types */
-		if (rel->rd_rel->relkind != RELKIND_RELATION &&
-			rel->rd_rel->relkind != RELKIND_MATVIEW &&
-			rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
-			rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("relation \"%s\" is not a table, foreign table, or materialized view",
-							RelationGetRelationName(rel))));
+		Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+		switch ((RelKind) rel->rd_rel->relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_MATVIEW:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_TABLE:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("relation \"%s\" is not a table, foreign table, or materialized view",
+								RelationGetRelationName(rel))));
+		}
 
 		/* You must own the relation to create stats on it */
 		if (!pg_class_ownercheck(RelationGetRelid(rel), stxowner))
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 20049f2c55..7eba9cc4dc 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -619,8 +619,22 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 
 	if (stmt->partspec != NULL)
 	{
-		if (relkind != RELKIND_RELATION)
-			elog(ERROR, "unexpected relkind: %d", (int) relkind);
+		Assert(RELKIND_IS_VALID((RelKind) relkind));
+		switch ((RelKind) relkind)
+		{
+			case RELKIND_RELATION:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				elog(ERROR, "unexpected relkind: %d", (int) relkind);
+		}
 
 		relkind = RELKIND_PARTITIONED_TABLE;
 		partitioned = true;
@@ -746,7 +760,8 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 	reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
 									 true, false);
 
-	switch (relkind)
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
 	{
 		case RELKIND_VIEW:
 			(void) view_reloptions(reloptions, true);
@@ -754,7 +769,14 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 		case RELKIND_PARTITIONED_TABLE:
 			(void) partitioned_table_reloptions(reloptions, true);
 			break;
-		default:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
 			(void) heap_reloptions(relkind, reloptions, true);
 	}
 
@@ -866,10 +888,26 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 					 errmsg("specifying a table access method is not supported on a partitioned table")));
 
 	}
-	else if (relkind == RELKIND_RELATION ||
-			 relkind == RELKIND_TOASTVALUE ||
-			 relkind == RELKIND_MATVIEW)
-		accessMethod = default_table_access_method;
+	else
+	{
+		Assert(RELKIND_IS_VALID((RelKind) relkind));
+		switch ((RelKind) relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_MATVIEW:
+				accessMethod = default_table_access_method;
+				break;
+			case RELKIND_VIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_INDEX:
+				break;
+		}
+	}
 
 	/* look up the access method, verify it is for a table */
 	if (accessMethod != NULL)
@@ -956,11 +994,25 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 		 * We are going to try to validate the partition bound specification
 		 * against the partition key of parentRel, so it better have one.
 		 */
-		if (parent->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-					 errmsg("\"%s\" is not partitioned",
-							RelationGetRelationName(parent))));
+		Assert(RELKIND_IS_VALID((RelKind) parent->rd_rel->relkind));
+		switch ((RelKind) parent->rd_rel->relkind)
+		{
+			case RELKIND_PARTITIONED_TABLE:
+				break;
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_INDEX:
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+						 errmsg("\"%s\" is not partitioned",
+								RelationGetRelationName(parent))));
+		}
 
 		/*
 		 * The partition constraint of the default partition depends on the
@@ -1104,20 +1156,33 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 			IndexStmt  *idxstmt;
 			Oid			constraintOid;
 
-			if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+			Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+			switch ((RelKind) rel->rd_rel->relkind)
 			{
-				if (idxRel->rd_index->indisunique)
-					ereport(ERROR,
-							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-							 errmsg("cannot create foreign partition of partitioned table \"%s\"",
-									RelationGetRelationName(parent)),
-							 errdetail("Table \"%s\" contains indexes that are unique.",
-									   RelationGetRelationName(parent))));
-				else
-				{
-					index_close(idxRel, AccessShareLock);
-					continue;
-				}
+				case RELKIND_FOREIGN_TABLE:
+					if (idxRel->rd_index->indisunique)
+						ereport(ERROR,
+								(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+								 errmsg("cannot create foreign partition of partitioned table \"%s\"",
+										RelationGetRelationName(parent)),
+								 errdetail("Table \"%s\" contains indexes that are unique.",
+										   RelationGetRelationName(parent))));
+					else
+					{
+						index_close(idxRel, AccessShareLock);
+						continue;
+					}
+					break;
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_MATVIEW:
+				case RELKIND_VIEW:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_SEQUENCE:
+				case RELKIND_INDEX:
+					break;
 			}
 
 			attmap = build_attrmap_by_name(RelationGetDescr(rel),
@@ -1448,12 +1513,25 @@ RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
 	 * the relation is RELKIND_PARTITIONED_TABLE.  An equivalent problem
 	 * exists with indexes.
 	 */
-	if (classform->relkind == RELKIND_PARTITIONED_TABLE)
-		expected_relkind = RELKIND_RELATION;
-	else if (classform->relkind == RELKIND_PARTITIONED_INDEX)
-		expected_relkind = RELKIND_INDEX;
-	else
-		expected_relkind = classform->relkind;
+	Assert(RELKIND_IS_VALID((RelKind) classform->relkind));
+	switch ((RelKind) classform->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			expected_relkind = RELKIND_RELATION;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+			expected_relkind = RELKIND_INDEX;
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_SEQUENCE:
+		case RELKIND_INDEX:
+			expected_relkind = classform->relkind;
+	}
 
 	if (relkind != expected_relkind)
 		DropErrorMsgWrongType(rel->relname, classform->relkind, relkind);
@@ -1470,26 +1548,42 @@ RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
 	 * only concerns indexes of toast relations that became invalid during a
 	 * REINDEX CONCURRENTLY process.
 	 */
-	if (IsSystemClass(relOid, classform) && relkind == RELKIND_INDEX)
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
 	{
-		HeapTuple	locTuple;
-		Form_pg_index indexform;
-		bool		indisvalid;
+		case RELKIND_INDEX:
+			if (IsSystemClass(relOid, classform))
+			{
+				HeapTuple	locTuple;
+				Form_pg_index indexform;
+				bool		indisvalid;
 
-		locTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(relOid));
-		if (!HeapTupleIsValid(locTuple))
-		{
-			ReleaseSysCache(tuple);
-			return;
-		}
+				locTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(relOid));
+				if (!HeapTupleIsValid(locTuple))
+				{
+					ReleaseSysCache(tuple);
+					return;
+				}
 
-		indexform = (Form_pg_index) GETSTRUCT(locTuple);
-		indisvalid = indexform->indisvalid;
-		ReleaseSysCache(locTuple);
+				indexform = (Form_pg_index) GETSTRUCT(locTuple);
+				indisvalid = indexform->indisvalid;
+				ReleaseSysCache(locTuple);
 
-		/* Mark object as being an invalid index of system catalogs */
-		if (!indisvalid)
-			invalid_system_index = true;
+				/* Mark object as being an invalid index of system catalogs */
+				if (!indisvalid)
+					invalid_system_index = true;
+			}
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_SEQUENCE:
+			break;
 	}
 
 	/* In the case of an invalid index, it is fine to bypass this check */
@@ -1508,12 +1602,27 @@ RangeVarCallbackForDropRelation(const RangeVar *rel, Oid relOid, Oid oldRelOid,
 	 * we do it the other way around.  No error if we don't find a pg_index
 	 * entry, though --- the relation may have been dropped.
 	 */
-	if ((relkind == RELKIND_INDEX || relkind == RELKIND_PARTITIONED_INDEX) &&
-		relOid != oldRelOid)
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
 	{
-		state->heapOid = IndexGetRelation(relOid, true);
-		if (OidIsValid(state->heapOid))
-			LockRelationOid(state->heapOid, heap_lockmode);
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			if (relOid != oldRelOid)
+			{
+				state->heapOid = IndexGetRelation(relOid, true);
+				if (OidIsValid(state->heapOid))
+					LockRelationOid(state->heapOid, heap_lockmode);
+			}
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_SEQUENCE:
+			break;
 	}
 
 	/*
@@ -1635,11 +1744,29 @@ ExecuteTruncate(TruncateStmt *stmt)
 					relids_logged = lappend_oid(relids_logged, childrelid);
 			}
 		}
-		else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot truncate only a partitioned table"),
-					 errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
+		else
+		{
+			Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+			switch ((RelKind) rel->rd_rel->relkind)
+			{
+				case RELKIND_PARTITIONED_TABLE:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("cannot truncate only a partitioned table"),
+							 errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
+					break;
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_MATVIEW:
+				case RELKIND_VIEW:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_SEQUENCE:
+					break;
+			}
+		}
 	}
 
 	ExecuteTruncateGuts(rels, relids, relids_logged,
@@ -1815,9 +1942,23 @@ ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged,
 	{
 		Relation	rel = (Relation) lfirst(cell);
 
-		/* Skip partitioned tables as there is nothing to do */
-		if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-			continue;
+		Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+		switch ((RelKind) rel->rd_rel->relkind)
+		{
+				/* Skip partitioned tables as there is nothing to do */
+			case RELKIND_PARTITIONED_TABLE:
+				continue;
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_SEQUENCE:
+				break;
+		}
 
 		/*
 		 * Normally, we need a transaction-safe truncation here.  However, if
@@ -1969,11 +2110,24 @@ truncate_check_rel(Oid relid, Form_pg_class reltuple)
 	 * the latter are only being included here for the following checks; no
 	 * physical truncation will occur in their case.)
 	 */
-	if (reltuple->relkind != RELKIND_RELATION &&
-		reltuple->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table", relname)));
+	Assert(RELKIND_IS_VALID((RelKind) reltuple->relkind));
+	switch ((RelKind) reltuple->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_SEQUENCE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table", relname)));
+	}
 
 	if (!allowSystemTableMods && IsSystemClass(relid, reltuple))
 		ereport(ERROR,
@@ -2235,26 +2389,38 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
 		 * We do not allow partitioned tables and partitions to participate in
 		 * regular inheritance.
 		 */
-		if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
-			!is_partition)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot inherit from partitioned table \"%s\"",
-							RelationGetRelationName(relation))));
+		Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+		switch ((RelKind) relation->rd_rel->relkind)
+		{
+			case RELKIND_PARTITIONED_TABLE:
+				if (!is_partition)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("cannot inherit from partitioned table \"%s\"",
+									RelationGetRelationName(relation))));
+				break;
+			case RELKIND_RELATION:
+			case RELKIND_FOREIGN_TABLE:
+				break;
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_SEQUENCE:
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("inherited relation \"%s\" is not a table or foreign table",
+								RelationGetRelationName(relation))));
+		}
+
 		if (relation->rd_rel->relispartition && !is_partition)
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("cannot inherit from partition \"%s\"",
 							RelationGetRelationName(relation))));
 
-		if (relation->rd_rel->relkind != RELKIND_RELATION &&
-			relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
-			relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("inherited relation \"%s\" is not a table or foreign table",
-							RelationGetRelationName(relation))));
-
 		/*
 		 * If the parent is permanent, so must be all of its partitions.  Note
 		 * that inheritance allows that case.
@@ -2996,18 +3162,25 @@ renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing)
 	 * change names that are hardcoded into the system, hence the following
 	 * restriction.
 	 */
-	if (relkind != RELKIND_RELATION &&
-		relkind != RELKIND_VIEW &&
-		relkind != RELKIND_MATVIEW &&
-		relkind != RELKIND_COMPOSITE_TYPE &&
-		relkind != RELKIND_INDEX &&
-		relkind != RELKIND_PARTITIONED_INDEX &&
-		relkind != RELKIND_FOREIGN_TABLE &&
-		relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table, view, materialized view, composite type, index, or foreign table",
-						NameStr(classform->relname))));
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_TOASTVALUE:
+		case RELKIND_SEQUENCE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table, view, materialized view, composite type, index, or foreign table",
+							NameStr(classform->relname))));
+	}
 
 	/*
 	 * permissions checking.  only the owner of a class can change its schema.
@@ -3105,17 +3278,32 @@ renameatt_internal(Oid myrelid,
 	}
 
 	/* rename attributes in typed tables of composite type */
-	if (targetrelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
+	Assert(RELKIND_IS_VALID((RelKind) targetrelation->rd_rel->relkind));
+	switch ((RelKind) targetrelation->rd_rel->relkind)
 	{
-		List	   *child_oids;
-		ListCell   *lo;
+		case RELKIND_COMPOSITE_TYPE:
+			{
+				List	   *child_oids;
+				ListCell   *lo;
 
-		child_oids = find_typed_table_dependencies(targetrelation->rd_rel->reltype,
-												   RelationGetRelationName(targetrelation),
-												   behavior);
+				child_oids = find_typed_table_dependencies(targetrelation->rd_rel->reltype,
+														   RelationGetRelationName(targetrelation),
+														   behavior);
 
-		foreach(lo, child_oids)
-			renameatt_internal(lfirst_oid(lo), oldattname, newattname, true, true, 0, behavior);
+				foreach(lo, child_oids)
+					renameatt_internal(lfirst_oid(lo), oldattname, newattname, true, true, 0, behavior);
+			}
+			break;
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_SEQUENCE:
+			break;
 	}
 
 	attrelation = table_open(AttributeRelationId, RowExclusiveLock);
@@ -3489,13 +3677,27 @@ RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bo
 	/*
 	 * Also rename the associated constraint, if any.
 	 */
-	if (targetrelation->rd_rel->relkind == RELKIND_INDEX ||
-		targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
+	Assert(RELKIND_IS_VALID((RelKind) targetrelation->rd_rel->relkind));
+	switch ((RelKind) targetrelation->rd_rel->relkind)
 	{
-		Oid			constraintId = get_index_constraint(myrelid);
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			{
+				Oid			constraintId = get_index_constraint(myrelid);
 
-		if (OidIsValid(constraintId))
-			RenameConstraintById(constraintId, newrelname);
+				if (OidIsValid(constraintId))
+					RenameConstraintById(constraintId, newrelname);
+			}
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_SEQUENCE:
+			break;
 	}
 
 	/*
@@ -3542,14 +3744,27 @@ CheckTableNotInUse(Relation rel, const char *stmt)
 				 errmsg("cannot %s \"%s\" because it is being used by active queries in this session",
 						stmt, RelationGetRelationName(rel))));
 
-	if (rel->rd_rel->relkind != RELKIND_INDEX &&
-		rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
-		AfterTriggerPendingOnRel(RelationGetRelid(rel)))
-		ereport(ERROR,
-				(errcode(ERRCODE_OBJECT_IN_USE),
-		/* translator: first %s is a SQL command, eg ALTER TABLE */
-				 errmsg("cannot %s \"%s\" because it has pending trigger events",
-						stmt, RelationGetRelationName(rel))));
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_SEQUENCE:
+			if (AfterTriggerPendingOnRel(RelationGetRelid(rel)))
+				ereport(ERROR,
+						(errcode(ERRCODE_OBJECT_IN_USE),
+				/* translator: first %s is a SQL command, eg ALTER TABLE */
+						 errmsg("cannot %s \"%s\" because it has pending trigger events",
+								stmt, RelationGetRelationName(rel))));
+	}
 }
 
 /*
@@ -4364,11 +4579,26 @@ ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode,
 		 * not modify anything about it that will change its toasting
 		 * requirement, so no need to check.
 		 */
-		if (((tab->relkind == RELKIND_RELATION ||
-			  tab->relkind == RELKIND_PARTITIONED_TABLE) &&
-			 tab->partition_constraint == NULL) ||
-			tab->relkind == RELKIND_MATVIEW)
-			AlterTableCreateToastTable(tab->relid, (Datum) 0, lockmode);
+		Assert(RELKIND_IS_VALID((RelKind) tab->relkind));
+		switch ((RelKind) tab->relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_PARTITIONED_TABLE:
+				if (tab->partition_constraint != NULL)
+					break;
+				/* fallthrough */
+			case RELKIND_MATVIEW:
+				AlterTableCreateToastTable(tab->relid, (Datum) 0, lockmode);
+				break;
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_VIEW:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_SEQUENCE:
+				break;
+		}
 	}
 }
 
@@ -4546,15 +4776,28 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
 			break;
 		case AT_SetTableSpace:	/* SET TABLESPACE */
 
-			/*
-			 * Only do this for partitioned tables and indexes, for which this
-			 * is just a catalog change.  Other relation types which have
-			 * storage are handled by Phase 3.
-			 */
-			if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
-				rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
-				ATExecSetTableSpaceNoStorage(rel, tab->newTableSpace);
-
+			Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+			switch ((RelKind) rel->rd_rel->relkind)
+			{
+					/*
+					 * Only do this for partitioned tables and indexes, for
+					 * which this is just a catalog change.  Other relation
+					 * types which have storage are handled by Phase 3.
+					 */
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_PARTITIONED_INDEX:
+					ATExecSetTableSpaceNoStorage(rel, tab->newTableSpace);
+					break;
+				case RELKIND_RELATION:
+				case RELKIND_MATVIEW:
+				case RELKIND_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_VIEW:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_SEQUENCE:
+					break;
+			}
 			break;
 		case AT_SetRelOptions:	/* SET (...) */
 		case AT_ResetRelOptions:	/* RESET (...) */
@@ -4645,11 +4888,24 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
 			cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
 									  cur_pass, context);
 			Assert(cmd != NULL);
-			if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-				ATExecAttachPartition(wqueue, rel, (PartitionCmd *) cmd->def);
-			else
-				ATExecAttachPartitionIdx(wqueue, rel,
-										 ((PartitionCmd *) cmd->def)->name);
+			Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+			switch ((RelKind) rel->rd_rel->relkind)
+			{
+				case RELKIND_PARTITIONED_TABLE:
+					ATExecAttachPartition(wqueue, rel, (PartitionCmd *) cmd->def);
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_RELATION:
+				case RELKIND_MATVIEW:
+				case RELKIND_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_VIEW:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_SEQUENCE:
+					ATExecAttachPartitionIdx(wqueue, rel,
+											 ((PartitionCmd *) cmd->def)->name);
+			}
 			break;
 		case AT_DetachPartition:
 			cmd = ATParseTransformCmd(wqueue, tab, rel, cmd, false, lockmode,
@@ -5477,7 +5733,8 @@ ATSimplePermissions(Relation rel, int allowed_targets)
 {
 	int			actual_target;
 
-	switch (rel->rd_rel->relkind)
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
@@ -5501,9 +5758,9 @@ ATSimplePermissions(Relation rel, int allowed_targets)
 		case RELKIND_FOREIGN_TABLE:
 			actual_target = ATT_FOREIGN_TABLE;
 			break;
-		default:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
 			actual_target = 0;
-			break;
 	}
 
 	/* Wrong target type? */
@@ -5600,40 +5857,53 @@ ATSimpleRecursion(List **wqueue, Relation rel,
 	 * and partitioned tables have children, so no need to search for other
 	 * relkinds.
 	 */
-	if (recurse &&
-		(rel->rd_rel->relkind == RELKIND_RELATION ||
-		 rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
-		 rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		Oid			relid = RelationGetRelid(rel);
-		ListCell   *child;
-		List	   *children;
-
-		children = find_all_inheritors(relid, lockmode, NULL);
+		case RELKIND_RELATION:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+			if (recurse)
+			{
+				Oid			relid = RelationGetRelid(rel);
+				ListCell   *child;
+				List	   *children;
 
-		/*
-		 * find_all_inheritors does the recursive search of the inheritance
-		 * hierarchy, so all we have to do is process all of the relids in the
-		 * list that it returns.
-		 */
-		foreach(child, children)
-		{
-			Oid			childrelid = lfirst_oid(child);
-			Relation	childrel;
+				children = find_all_inheritors(relid, lockmode, NULL);
 
-			if (childrelid == relid)
-				continue;
-			/* find_all_inheritors already got lock */
-			childrel = relation_open(childrelid, NoLock);
-			CheckTableNotInUse(childrel, "ALTER TABLE");
-			ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
-			relation_close(childrel, NoLock);
-		}
-	}
-}
+				/*
+				 * find_all_inheritors does the recursive search of the
+				 * inheritance hierarchy, so all we have to do is process all
+				 * of the relids in the list that it returns.
+				 */
+				foreach(child, children)
+				{
+					Oid			childrelid = lfirst_oid(child);
+					Relation	childrel;
 
-/*
- * Obtain list of partitions of the given table, locking them all at the given
+					if (childrelid == relid)
+						continue;
+					/* find_all_inheritors already got lock */
+					childrel = relation_open(childrelid, NoLock);
+					CheckTableNotInUse(childrel, "ALTER TABLE");
+					ATPrepCmd(wqueue, childrel, cmd, false, true, lockmode, context);
+					relation_close(childrel, NoLock);
+				}
+			}
+			break;
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
+	}
+}
+
+/*
+ * Obtain list of partitions of the given table, locking them all at the given
  * lockmode and ensuring that they all pass CheckTableNotInUse.
  *
  * This function is a no-op if the given relation is not a partitioned table;
@@ -5773,47 +6043,60 @@ find_composite_type_dependencies(Oid typeOid, Relation origRelation,
 		rel = relation_open(pg_depend->objid, AccessShareLock);
 		att = TupleDescAttr(rel->rd_att, pg_depend->objsubid - 1);
 
-		if (rel->rd_rel->relkind == RELKIND_RELATION ||
-			rel->rd_rel->relkind == RELKIND_MATVIEW ||
-			rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		{
-			if (origTypeName)
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
-								origTypeName,
-								RelationGetRelationName(rel),
-								NameStr(att->attname))));
-			else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
-								RelationGetRelationName(origRelation),
-								RelationGetRelationName(rel),
-								NameStr(att->attname))));
-			else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
-								RelationGetRelationName(origRelation),
-								RelationGetRelationName(rel),
-								NameStr(att->attname))));
-			else
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
-								RelationGetRelationName(origRelation),
-								RelationGetRelationName(rel),
-								NameStr(att->attname))));
-		}
-		else if (OidIsValid(rel->rd_rel->reltype))
+		Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+		switch ((RelKind) rel->rd_rel->relkind)
 		{
-			/*
-			 * A view or composite type itself isn't a problem, but we must
-			 * recursively check for indirect dependencies via its rowtype.
-			 */
-			find_composite_type_dependencies(rel->rd_rel->reltype,
-											 origRelation, origTypeName);
+			case RELKIND_RELATION:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+				{
+					if (origTypeName)
+						ereport(ERROR,
+								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+								 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
+										origTypeName,
+										RelationGetRelationName(rel),
+										NameStr(att->attname))));
+					else if (origRelation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
+						ereport(ERROR,
+								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+								 errmsg("cannot alter type \"%s\" because column \"%s.%s\" uses it",
+										RelationGetRelationName(origRelation),
+										RelationGetRelationName(rel),
+										NameStr(att->attname))));
+					else if (origRelation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+						ereport(ERROR,
+								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+								 errmsg("cannot alter foreign table \"%s\" because column \"%s.%s\" uses its row type",
+										RelationGetRelationName(origRelation),
+										RelationGetRelationName(rel),
+										NameStr(att->attname))));
+					else
+						ereport(ERROR,
+								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+								 errmsg("cannot alter table \"%s\" because column \"%s.%s\" uses its row type",
+										RelationGetRelationName(origRelation),
+										RelationGetRelationName(rel),
+										NameStr(att->attname))));
+				}
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_VIEW:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+				if (OidIsValid(rel->rd_rel->reltype))
+				{
+					/*
+					 * A view or composite type itself isn't a problem, but we
+					 * must recursively check for indirect dependencies via
+					 * its rowtype.
+					 */
+					find_composite_type_dependencies(rel->rd_rel->reltype,
+													 origRelation, origTypeName);
+				}
 		}
 
 		relation_close(rel, AccessShareLock);
@@ -5934,8 +6217,23 @@ ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot add column to typed table")));
 
-	if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-		ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_COMPOSITE_TYPE:
+			ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
+			break;
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
+	}
 
 	if (recurse && !is_view)
 		cmd->subtype = AT_AddColumnRecurse;
@@ -6455,16 +6753,31 @@ ATPrepDropNotNull(Relation rel, bool recurse, bool recursing)
 	 * If the parent is a partitioned table, like check constraints, we do not
 	 * support removing the NOT NULL while partitions exist.
 	 */
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		PartitionDesc partdesc = RelationGetPartitionDesc(rel);
+		case RELKIND_PARTITIONED_TABLE:
+			{
+				PartitionDesc partdesc = RelationGetPartitionDesc(rel);
 
-		Assert(partdesc != NULL);
-		if (partdesc->nparts > 0 && !recurse && !recursing)
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-					 errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
-					 errhint("Do not specify the ONLY keyword.")));
+				Assert(partdesc != NULL);
+				if (partdesc->nparts > 0 && !recurse && !recursing)
+					ereport(ERROR,
+							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+							 errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
+							 errhint("Do not specify the ONLY keyword.")));
+			}
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
 	}
 }
 
@@ -6614,17 +6927,31 @@ ATPrepSetNotNull(List **wqueue, Relation rel,
 	 * apply ALTER TABLE ... CHECK NOT NULL to every child.  Otherwise, use
 	 * normal recursion logic.
 	 */
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
-		!recurse)
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		AlterTableCmd *newcmd = makeNode(AlterTableCmd);
+		case RELKIND_PARTITIONED_TABLE:
+			if (!recurse)
+			{
+				AlterTableCmd *newcmd = makeNode(AlterTableCmd);
 
-		newcmd->subtype = AT_CheckNotNull;
-		newcmd->name = pstrdup(cmd->name);
-		ATSimpleRecursion(wqueue, rel, newcmd, true, lockmode, context);
+				newcmd->subtype = AT_CheckNotNull;
+				newcmd->name = pstrdup(cmd->name);
+				ATSimpleRecursion(wqueue, rel, newcmd, true, lockmode, context);
+				break;
+			}
+			/* fallthrough */
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
 	}
-	else
-		ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
 }
 
 /*
@@ -7249,12 +7576,25 @@ ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newVa
 	 * We allow referencing columns by numbers only for indexes, since table
 	 * column numbers could contain gaps if columns are later dropped.
 	 */
-	if (rel->rd_rel->relkind != RELKIND_INDEX &&
-		rel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX &&
-		!colName)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("cannot refer to non-index column by number")));
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			if (!colName)
+				ereport(ERROR,
+						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+						 errmsg("cannot refer to non-index column by number")));
+	}
 
 	Assert(IsA(newValue, Integer));
 	newtarget = intVal(newValue);
@@ -7310,20 +7650,34 @@ ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newVa
 				 errmsg("cannot alter system column \"%s\"",
 						colName)));
 
-	if (rel->rd_rel->relkind == RELKIND_INDEX ||
-		rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		if (attnum > rel->rd_index->indnkeyatts)
-			ereport(ERROR,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("cannot alter statistics on included column \"%s\" of index \"%s\"",
-							NameStr(attrtuple->attname), RelationGetRelationName(rel))));
-		else if (rel->rd_index->indkey.values[attnum - 1] != 0)
-			ereport(ERROR,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("cannot alter statistics on non-expression column \"%s\" of index \"%s\"",
-							NameStr(attrtuple->attname), RelationGetRelationName(rel)),
-					 errhint("Alter statistics on table column instead.")));
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			{
+				if (attnum > rel->rd_index->indnkeyatts)
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("cannot alter statistics on included column \"%s\" of index \"%s\"",
+									NameStr(attrtuple->attname), RelationGetRelationName(rel))));
+				else if (rel->rd_index->indkey.values[attnum - 1] != 0)
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("cannot alter statistics on non-expression column \"%s\" of index \"%s\"",
+									NameStr(attrtuple->attname), RelationGetRelationName(rel)),
+							 errhint("Alter statistics on table column instead.")));
+			}
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
 	}
 
 	attrtuple->attstattarget = newtarget;
@@ -7566,8 +7920,23 @@ ATPrepDropColumn(List **wqueue, Relation rel, bool recurse, bool recursing,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot drop column from typed table")));
 
-	if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-		ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_COMPOSITE_TYPE:
+			ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
+			break;
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
+	}
 
 	if (recurse)
 		cmd->subtype = AT_DropColumnRecurse;
@@ -7676,15 +8045,31 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName,
 		Relation	attr_rel;
 		ListCell   *child;
 
-		/*
-		 * In case of a partitioned table, the column must be dropped from the
-		 * partitions as well.
-		 */
-		if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && !recurse)
-			ereport(ERROR,
-					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-					 errmsg("cannot drop column from only the partitioned table when partitions exist"),
-					 errhint("Do not specify the ONLY keyword.")));
+		Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+		switch ((RelKind) rel->rd_rel->relkind)
+		{
+				/*
+				 * In case of a partitioned table, the column must be dropped
+				 * from the partitions as well.
+				 */
+			case RELKIND_PARTITIONED_TABLE:
+				if (!recurse)
+					ereport(ERROR,
+							(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+							 errmsg("cannot drop column from only the partitioned table when partitions exist"),
+							 errhint("Do not specify the ONLY keyword.")));
+				break;
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_RELATION:
+			case RELKIND_MATVIEW:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+				break;
+		}
 
 		attr_rel = table_open(AttributeRelationId, RowExclusiveLock);
 		foreach(child, children)
@@ -7861,10 +8246,25 @@ ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
 	 * Doing this on partitioned tables is not a simple feature to implement,
 	 * so let's punt for now.
 	 */
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			ereport(ERROR,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX is not supported on partitioned tables")));
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
+	}
 
 	indexRel = index_open(index_oid, AccessShareLock);
 
@@ -8218,30 +8618,42 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
 	 * Validity checks (permission checks wait till we have the column
 	 * numbers)
 	 */
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		if (!recurse)
+		case RELKIND_PARTITIONED_TABLE:
+			{
+				if (!recurse)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
+									RelationGetRelationName(rel),
+									RelationGetRelationName(pkrel))));
+				if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
+									RelationGetRelationName(rel),
+									RelationGetRelationName(pkrel)),
+							 errdetail("This feature is not yet supported on partitioned tables.")));
+			}
+			break;
+		case RELKIND_RELATION:
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot use ONLY for foreign key on partitioned table \"%s\" referencing relation \"%s\"",
-							RelationGetRelationName(rel),
+					 errmsg("referenced relation \"%s\" is not a table",
 							RelationGetRelationName(pkrel))));
-		if (fkconstraint->skip_validation && !fkconstraint->initially_valid)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("cannot add NOT VALID foreign key on partitioned table \"%s\" referencing relation \"%s\"",
-							RelationGetRelationName(rel),
-							RelationGetRelationName(pkrel)),
-					 errdetail("This feature is not yet supported on partitioned tables.")));
 	}
 
-	if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
-		pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("referenced relation \"%s\" is not a table",
-						RelationGetRelationName(pkrel))));
-
 	if (!allowSystemTableMods && IsSystemRelation(pkrel))
 		ereport(ERROR,
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
@@ -8640,12 +9052,25 @@ addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel,
 	 * Verify relkind for each referenced partition.  At the top level, this
 	 * is redundant with a previous check, but we need it when recursing.
 	 */
-	if (pkrel->rd_rel->relkind != RELKIND_RELATION &&
-		pkrel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("referenced relation \"%s\" is not a table",
-						RelationGetRelationName(pkrel))));
+	Assert(RELKIND_IS_VALID((RelKind) pkrel->rd_rel->relkind));
+	switch ((RelKind) pkrel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("referenced relation \"%s\" is not a table",
+							RelationGetRelationName(pkrel))));
+	}
 
 	/*
 	 * Caller supplies us with a constraint name; however, it may be used in
@@ -8675,7 +9100,22 @@ addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel,
 		/*
 		 * always inherit for partitioned tables, never for legacy inheritance
 		 */
-		connoinherit = rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE;
+		Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+		switch ((RelKind) rel->rd_rel->relkind)
+		{
+			case RELKIND_PARTITIONED_TABLE:
+				connoinherit = false;
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+				connoinherit = true;
+		}
 	}
 
 	/*
@@ -8730,69 +9170,83 @@ addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel,
 	/* make new constraint visible, in case we add more */
 	CommandCounterIncrement();
 
-	/*
-	 * If the referenced table is a plain relation, create the action triggers
-	 * that enforce the constraint.
-	 */
-	if (pkrel->rd_rel->relkind == RELKIND_RELATION)
+	Assert(RELKIND_IS_VALID((RelKind) pkrel->rd_rel->relkind));
+	switch ((RelKind) pkrel->rd_rel->relkind)
 	{
-		createForeignKeyActionTriggers(rel, RelationGetRelid(pkrel),
-									   fkconstraint,
-									   constrOid, indexOid);
-	}
-
-	/*
-	 * If the referenced table is partitioned, recurse on ourselves to handle
-	 * each partition.  We need one pg_constraint row created for each
-	 * partition in addition to the pg_constraint row for the parent table.
-	 */
-	if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-	{
-		PartitionDesc pd = RelationGetPartitionDesc(pkrel);
-
-		for (int i = 0; i < pd->nparts; i++)
-		{
-			Relation	partRel;
-			AttrMap    *map;
-			AttrNumber *mapped_pkattnum;
-			Oid			partIndexId;
-
-			partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
+			/*
+			 * If the referenced table is a plain relation, create the action
+			 * triggers that enforce the constraint.
+			 */
+		case RELKIND_RELATION:
+			createForeignKeyActionTriggers(rel, RelationGetRelid(pkrel),
+										   fkconstraint,
+										   constrOid, indexOid);
+			break;
 
 			/*
-			 * Map the attribute numbers in the referenced side of the FK
-			 * definition to match the partition's column layout.
+			 * If the referenced table is partitioned, recurse on ourselves to
+			 * handle each partition.  We need one pg_constraint row created
+			 * for each partition in addition to the pg_constraint row for the
+			 * parent table.
 			 */
-			map = build_attrmap_by_name_if_req(RelationGetDescr(partRel),
-											   RelationGetDescr(pkrel));
-			if (map)
-			{
-				mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
-				for (int j = 0; j < numfks; j++)
-					mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
-			}
-			else
-				mapped_pkattnum = pkattnum;
-
-			/* do the deed */
-			partIndexId = index_get_partition(partRel, indexOid);
-			if (!OidIsValid(partIndexId))
-				elog(ERROR, "index for %u not found in partition %s",
-					 indexOid, RelationGetRelationName(partRel));
-			addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
-								   partIndexId, constrOid, numfks,
-								   mapped_pkattnum, fkattnum,
-								   pfeqoperators, ppeqoperators, ffeqoperators,
-								   old_check_ok);
-
-			/* Done -- clean up (but keep the lock) */
-			table_close(partRel, NoLock);
-			if (map)
+		case RELKIND_PARTITIONED_TABLE:
 			{
-				pfree(mapped_pkattnum);
-				free_attrmap(map);
+				PartitionDesc pd = RelationGetPartitionDesc(pkrel);
+
+				for (int i = 0; i < pd->nparts; i++)
+				{
+					Relation	partRel;
+					AttrMap    *map;
+					AttrNumber *mapped_pkattnum;
+					Oid			partIndexId;
+
+					partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
+
+					/*
+					 * Map the attribute numbers in the referenced side of the
+					 * FK definition to match the partition's column layout.
+					 */
+					map = build_attrmap_by_name_if_req(RelationGetDescr(partRel),
+													   RelationGetDescr(pkrel));
+					if (map)
+					{
+						mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
+						for (int j = 0; j < numfks; j++)
+							mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
+					}
+					else
+						mapped_pkattnum = pkattnum;
+
+					/* do the deed */
+					partIndexId = index_get_partition(partRel, indexOid);
+					if (!OidIsValid(partIndexId))
+						elog(ERROR, "index for %u not found in partition %s",
+							 indexOid, RelationGetRelationName(partRel));
+					addFkRecurseReferenced(wqueue, fkconstraint, rel, partRel,
+										   partIndexId, constrOid, numfks,
+										   mapped_pkattnum, fkattnum,
+										   pfeqoperators, ppeqoperators, ffeqoperators,
+										   old_check_ok);
+
+					/* Done -- clean up (but keep the lock) */
+					table_close(partRel, NoLock);
+					if (map)
+					{
+						pfree(mapped_pkattnum);
+						free_attrmap(map);
+					}
+				}
 			}
-		}
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
 	}
 
 	return address;
@@ -8836,177 +9290,195 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
 {
 	AssertArg(OidIsValid(parentConstr));
 
-	if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("foreign key constraints are not supported on foreign tables")));
-
-	/*
-	 * If the referencing relation is a plain table, add the check triggers to
-	 * it and, if necessary, schedule it to be checked in Phase 3.
-	 *
-	 * If the relation is partitioned, drill down to do it to its partitions.
-	 */
-	if (rel->rd_rel->relkind == RELKIND_RELATION)
-	{
-		createForeignKeyCheckTriggers(RelationGetRelid(rel),
-									  RelationGetRelid(pkrel),
-									  fkconstraint,
-									  parentConstr,
-									  indexOid);
-
-		/*
-		 * Tell Phase 3 to check that the constraint is satisfied by existing
-		 * rows. We can skip this during table creation, when requested
-		 * explicitly by specifying NOT VALID in an ADD FOREIGN KEY command,
-		 * and when we're recreating a constraint following a SET DATA TYPE
-		 * operation that did not impugn its validity.
-		 */
-		if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
-		{
-			NewConstraint *newcon;
-			AlteredTableInfo *tab;
-
-			tab = ATGetQueueEntry(wqueue, rel);
-
-			newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
-			newcon->name = get_constraint_name(parentConstr);
-			newcon->contype = CONSTR_FOREIGN;
-			newcon->refrelid = RelationGetRelid(pkrel);
-			newcon->refindid = indexOid;
-			newcon->conid = parentConstr;
-			newcon->qual = (Node *) fkconstraint;
-
-			tab->constraints = lappend(tab->constraints, newcon);
-		}
-	}
-	else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		PartitionDesc pd = RelationGetPartitionDesc(rel);
-
-		/*
-		 * Recurse to take appropriate action on each partition; either we
-		 * find an existing constraint to reparent to ours, or we create a new
-		 * one.
-		 */
-		for (int i = 0; i < pd->nparts; i++)
-		{
-			Oid			partitionId = pd->oids[i];
-			Relation	partition = table_open(partitionId, lockmode);
-			List	   *partFKs;
-			AttrMap    *attmap;
-			AttrNumber	mapped_fkattnum[INDEX_MAX_KEYS];
-			bool		attached;
-			char	   *conname;
-			Oid			constrOid;
-			ObjectAddress address,
-						referenced;
-			ListCell   *cell;
-
-			CheckTableNotInUse(partition, "ALTER TABLE");
-
-			attmap = build_attrmap_by_name(RelationGetDescr(partition),
-										   RelationGetDescr(rel));
-			for (int j = 0; j < numfks; j++)
-				mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
-
-			/* Check whether an existing constraint can be repurposed */
-			partFKs = copyObject(RelationGetFKeyList(partition));
-			attached = false;
-			foreach(cell, partFKs)
-			{
-				ForeignKeyCacheInfo *fk;
-
-				fk = lfirst_node(ForeignKeyCacheInfo, cell);
-				if (tryAttachPartitionForeignKey(fk,
-												 partitionId,
-												 parentConstr,
-												 numfks,
-												 mapped_fkattnum,
-												 pkattnum,
-												 pfeqoperators))
-				{
-					attached = true;
-					break;
-				}
-			}
-			if (attached)
-			{
-				table_close(partition, NoLock);
-				continue;
-			}
-
 			/*
-			 * No luck finding a good constraint to reuse; create our own.
+			 * If the referencing relation is a plain table, add the check
+			 * triggers to it and, if necessary, schedule it to be checked in
+			 * Phase 3.
+			 *
+			 * If the relation is partitioned, drill down to do it to its
+			 * partitions.
 			 */
-			if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
-									 RelationGetRelid(partition),
-									 fkconstraint->conname))
-				conname = ChooseConstraintName(RelationGetRelationName(partition),
-											   ChooseForeignKeyConstraintNameAddition(fkconstraint->fk_attrs),
-											   "fkey",
-											   RelationGetNamespace(partition), NIL);
-			else
-				conname = fkconstraint->conname;
-			constrOid =
-				CreateConstraintEntry(conname,
-									  RelationGetNamespace(partition),
-									  CONSTRAINT_FOREIGN,
-									  fkconstraint->deferrable,
-									  fkconstraint->initdeferred,
-									  fkconstraint->initially_valid,
-									  parentConstr,
-									  partitionId,
-									  mapped_fkattnum,
-									  numfks,
-									  numfks,
-									  InvalidOid,
-									  indexOid,
-									  RelationGetRelid(pkrel),
-									  pkattnum,
-									  pfeqoperators,
-									  ppeqoperators,
-									  ffeqoperators,
-									  numfks,
-									  fkconstraint->fk_upd_action,
-									  fkconstraint->fk_del_action,
-									  fkconstraint->fk_matchtype,
-									  NULL,
-									  NULL,
-									  NULL,
-									  false,
-									  1,
-									  false,
-									  false);
+		case RELKIND_RELATION:
+			{
+				createForeignKeyCheckTriggers(RelationGetRelid(rel),
+											  RelationGetRelid(pkrel),
+											  fkconstraint,
+											  parentConstr,
+											  indexOid);
 
-			/*
-			 * Give this constraint partition-type dependencies on the parent
-			 * constraint as well as the table.
-			 */
-			ObjectAddressSet(address, ConstraintRelationId, constrOid);
-			ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
-			recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
-			ObjectAddressSet(referenced, RelationRelationId, partitionId);
-			recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
+				/*
+				 * Tell Phase 3 to check that the constraint is satisfied by
+				 * existing rows. We can skip this during table creation, when
+				 * requested explicitly by specifying NOT VALID in an ADD
+				 * FOREIGN KEY command, and when we're recreating a constraint
+				 * following a SET DATA TYPE operation that did not impugn its
+				 * validity.
+				 */
+				if (wqueue && !old_check_ok && !fkconstraint->skip_validation)
+				{
+					NewConstraint *newcon;
+					AlteredTableInfo *tab;
 
-			/* Make all this visible before recursing */
-			CommandCounterIncrement();
+					tab = ATGetQueueEntry(wqueue, rel);
 
-			/* call ourselves to finalize the creation and we're done */
-			addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
-									indexOid,
-									constrOid,
-									numfks,
-									pkattnum,
-									mapped_fkattnum,
-									pfeqoperators,
-									ppeqoperators,
-									ffeqoperators,
-									old_check_ok,
-									lockmode);
-
-			table_close(partition, NoLock);
-		}
+					newcon = (NewConstraint *) palloc0(sizeof(NewConstraint));
+					newcon->name = get_constraint_name(parentConstr);
+					newcon->contype = CONSTR_FOREIGN;
+					newcon->refrelid = RelationGetRelid(pkrel);
+					newcon->refindid = indexOid;
+					newcon->conid = parentConstr;
+					newcon->qual = (Node *) fkconstraint;
+
+					tab->constraints = lappend(tab->constraints, newcon);
+				}
+			}
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+			{
+				PartitionDesc pd = RelationGetPartitionDesc(rel);
+
+				/*
+				 * Recurse to take appropriate action on each partition;
+				 * either we find an existing constraint to reparent to ours,
+				 * or we create a new one.
+				 */
+				for (int i = 0; i < pd->nparts; i++)
+				{
+					Oid			partitionId = pd->oids[i];
+					Relation	partition = table_open(partitionId, lockmode);
+					List	   *partFKs;
+					AttrMap    *attmap;
+					AttrNumber	mapped_fkattnum[INDEX_MAX_KEYS];
+					bool		attached;
+					char	   *conname;
+					Oid			constrOid;
+					ObjectAddress address,
+								referenced;
+					ListCell   *cell;
+
+					CheckTableNotInUse(partition, "ALTER TABLE");
+
+					attmap = build_attrmap_by_name(RelationGetDescr(partition),
+												   RelationGetDescr(rel));
+					for (int j = 0; j < numfks; j++)
+						mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
+
+					/* Check whether an existing constraint can be repurposed */
+					partFKs = copyObject(RelationGetFKeyList(partition));
+					attached = false;
+					foreach(cell, partFKs)
+					{
+						ForeignKeyCacheInfo *fk;
+
+						fk = lfirst_node(ForeignKeyCacheInfo, cell);
+						if (tryAttachPartitionForeignKey(fk,
+														 partitionId,
+														 parentConstr,
+														 numfks,
+														 mapped_fkattnum,
+														 pkattnum,
+														 pfeqoperators))
+						{
+							attached = true;
+							break;
+						}
+					}
+					if (attached)
+					{
+						table_close(partition, NoLock);
+						continue;
+					}
+
+					/*
+					 * No luck finding a good constraint to reuse; create our
+					 * own.
+					 */
+					if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
+											 RelationGetRelid(partition),
+											 fkconstraint->conname))
+						conname = ChooseConstraintName(RelationGetRelationName(partition),
+													   ChooseForeignKeyConstraintNameAddition(fkconstraint->fk_attrs),
+													   "fkey",
+													   RelationGetNamespace(partition), NIL);
+					else
+						conname = fkconstraint->conname;
+					constrOid =
+						CreateConstraintEntry(conname,
+											  RelationGetNamespace(partition),
+											  CONSTRAINT_FOREIGN,
+											  fkconstraint->deferrable,
+											  fkconstraint->initdeferred,
+											  fkconstraint->initially_valid,
+											  parentConstr,
+											  partitionId,
+											  mapped_fkattnum,
+											  numfks,
+											  numfks,
+											  InvalidOid,
+											  indexOid,
+											  RelationGetRelid(pkrel),
+											  pkattnum,
+											  pfeqoperators,
+											  ppeqoperators,
+											  ffeqoperators,
+											  numfks,
+											  fkconstraint->fk_upd_action,
+											  fkconstraint->fk_del_action,
+											  fkconstraint->fk_matchtype,
+											  NULL,
+											  NULL,
+											  NULL,
+											  false,
+											  1,
+											  false,
+											  false);
+
+					/*
+					 * Give this constraint partition-type dependencies on the
+					 * parent constraint as well as the table.
+					 */
+					ObjectAddressSet(address, ConstraintRelationId, constrOid);
+					ObjectAddressSet(referenced, ConstraintRelationId, parentConstr);
+					recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_PRI);
+					ObjectAddressSet(referenced, RelationRelationId, partitionId);
+					recordDependencyOn(&address, &referenced, DEPENDENCY_PARTITION_SEC);
+
+					/* Make all this visible before recursing */
+					CommandCounterIncrement();
+
+					/* call ourselves to finalize the creation and we're done */
+					addFkRecurseReferencing(wqueue, fkconstraint, partition, pkrel,
+											indexOid,
+											constrOid,
+											numfks,
+											pkattnum,
+											mapped_fkattnum,
+											pfeqoperators,
+											ppeqoperators,
+											ffeqoperators,
+											old_check_ok,
+											lockmode);
+
+					table_close(partition, NoLock);
+				}
+			}
+			break;
+		case RELKIND_FOREIGN_TABLE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("foreign key constraints are not supported on foreign tables")));
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
 	}
 }
 
@@ -9229,10 +9701,25 @@ CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
 	if (clone == NIL)
 		return;
 
-	if (partRel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("foreign key constraints are not supported on foreign tables")));
+	Assert(RELKIND_IS_VALID((RelKind) partRel->rd_rel->relkind));
+	switch ((RelKind) partRel->rd_rel->relkind)
+	{
+		case RELKIND_FOREIGN_TABLE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("foreign key constraints are not supported on foreign tables")));
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
+	}
 
 	/*
 	 * The constraint key may differ, if the columns in the partition are
@@ -9282,9 +9769,24 @@ CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
 		 * relation, that means to lock all partitions.
 		 */
 		pkrel = table_open(constrForm->confrelid, ShareRowExclusiveLock);
-		if (pkrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-			(void) find_all_inheritors(RelationGetRelid(pkrel),
-									   ShareRowExclusiveLock, NULL);
+		Assert(RELKIND_IS_VALID((RelKind) pkrel->rd_rel->relkind));
+		switch ((RelKind) pkrel->rd_rel->relkind)
+		{
+			case RELKIND_PARTITIONED_TABLE:
+				(void) find_all_inheritors(RelationGetRelid(pkrel),
+										   ShareRowExclusiveLock, NULL);
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+				break;
+		}
 
 		DeconstructFkConstraintRow(tuple, &numfks, conkey, confkey,
 								   conpfeqop, conppeqop, conffeqop);
@@ -10650,11 +11152,26 @@ ATExecDropConstraint(Relation rel, const char *constrName,
 	 * For partitioned tables, non-CHECK inherited constraints are dropped via
 	 * the dependency mechanism, so we're done here.
 	 */
-	if (contype != CONSTRAINT_CHECK &&
-		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		table_close(conrel, RowExclusiveLock);
-		return;
+		case RELKIND_PARTITIONED_TABLE:
+			if (contype != CONSTRAINT_CHECK)
+			{
+				table_close(conrel, RowExclusiveLock);
+				return;
+			}
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
 	}
 
 	/*
@@ -10672,12 +11189,27 @@ ATExecDropConstraint(Relation rel, const char *constrName,
 	 * recurse, it's a user error.  It doesn't make sense to have a constraint
 	 * be defined only on the parent, especially if it's a partitioned table.
 	 */
-	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
-		children != NIL && !recurse)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-				 errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
-				 errhint("Do not specify the ONLY keyword.")));
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			if (children != NIL && !recurse)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+						 errmsg("cannot remove constraint from only the partitioned table when partitions exist"),
+						 errhint("Do not specify the ONLY keyword.")));
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
+	}
 
 	foreach(child, children)
 	{
@@ -10869,87 +11401,97 @@ ATPrepAlterColumnType(List **wqueue,
 					   list_make1_oid(rel->rd_rel->reltype),
 					   0);
 
-	if (tab->relkind == RELKIND_RELATION ||
-		tab->relkind == RELKIND_PARTITIONED_TABLE)
+	switch (tab->relkind)
 	{
-		/*
-		 * Set up an expression to transform the old data value to the new
-		 * type. If a USING option was given, use the expression as
-		 * transformed by transformAlterTableStmt, else just take the old
-		 * value and try to coerce it.  We do this first so that type
-		 * incompatibility can be detected before we waste effort, and because
-		 * we need the expression to be parsed against the original table row
-		 * type.
-		 */
-		if (!transform)
-		{
-			transform = (Node *) makeVar(1, attnum,
-										 attTup->atttypid, attTup->atttypmod,
-										 attTup->attcollation,
-										 0);
-		}
-
-		transform = coerce_to_target_type(pstate,
-										  transform, exprType(transform),
-										  targettype, targettypmod,
-										  COERCION_ASSIGNMENT,
-										  COERCE_IMPLICIT_CAST,
-										  -1);
-		if (transform == NULL)
-		{
-			/* error text depends on whether USING was specified or not */
-			if (def->cooked_default != NULL)
-				ereport(ERROR,
-						(errcode(ERRCODE_DATATYPE_MISMATCH),
-						 errmsg("result of USING clause for column \"%s\""
-								" cannot be cast automatically to type %s",
-								colName, format_type_be(targettype)),
-						 errhint("You might need to add an explicit cast.")));
-			else
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			/*
+			 * Set up an expression to transform the old data value to the new
+			 * type. If a USING option was given, use the expression as
+			 * transformed by transformAlterTableStmt, else just take the old
+			 * value and try to coerce it.  We do this first so that type
+			 * incompatibility can be detected before we waste effort, and because
+			 * we need the expression to be parsed against the original table row
+			 * type.
+			 */
+			if (!transform)
+			{
+				transform = (Node *) makeVar(1, attnum,
+											 attTup->atttypid, attTup->atttypmod,
+											 attTup->attcollation,
+											 0);
+			}
+	
+			transform = coerce_to_target_type(pstate,
+											  transform, exprType(transform),
+											  targettype, targettypmod,
+											  COERCION_ASSIGNMENT,
+											  COERCE_IMPLICIT_CAST,
+											  -1);
+			if (transform == NULL)
+			{
+				/* error text depends on whether USING was specified or not */
+				if (def->cooked_default != NULL)
+					ereport(ERROR,
+							(errcode(ERRCODE_DATATYPE_MISMATCH),
+							 errmsg("result of USING clause for column \"%s\""
+									" cannot be cast automatically to type %s",
+									colName, format_type_be(targettype)),
+							 errhint("You might need to add an explicit cast.")));
+				else
+					ereport(ERROR,
+							(errcode(ERRCODE_DATATYPE_MISMATCH),
+							 errmsg("column \"%s\" cannot be cast automatically to type %s",
+									colName, format_type_be(targettype)),
+					/* translator: USING is SQL, don't translate it */
+							 errhint("You might need to specify \"USING %s::%s\".",
+									 quote_identifier(colName),
+									 format_type_with_typemod(targettype,
+															  targettypmod))));
+			}
+	
+			/* Fix collations after all else */
+			assign_expr_collations(pstate, transform);
+	
+			/* Plan the expr now so we can accurately assess the need to rewrite. */
+			transform = (Node *) expression_planner((Expr *) transform);
+	
+			/*
+			 * Add a work queue item to make ATRewriteTable update the column
+			 * contents.
+			 */
+			newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
+			newval->attnum = attnum;
+			newval->expr = (Expr *) transform;
+			newval->is_generated = false;
+	
+			tab->newvals = lappend(tab->newvals, newval);
+			if (ATColumnChangeRequiresRewrite(transform, attnum))
+				tab->rewrite |= AT_REWRITE_COLUMN_REWRITE;
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+			if (!transform)
+			{
+				/*
+				 * For composite types and foreign tables, do this check now.  Regular
+				 * tables will check it later when the table is being rewritten.
+				 */
+				find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
+				break;
+			}
+			/* fallthrough */
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+			if (transform)
 				ereport(ERROR,
-						(errcode(ERRCODE_DATATYPE_MISMATCH),
-						 errmsg("column \"%s\" cannot be cast automatically to type %s",
-								colName, format_type_be(targettype)),
-				/* translator: USING is SQL, don't translate it */
-						 errhint("You might need to specify \"USING %s::%s\".",
-								 quote_identifier(colName),
-								 format_type_with_typemod(targettype,
-														  targettypmod))));
-		}
-
-		/* Fix collations after all else */
-		assign_expr_collations(pstate, transform);
-
-		/* Plan the expr now so we can accurately assess the need to rewrite. */
-		transform = (Node *) expression_planner((Expr *) transform);
-
-		/*
-		 * Add a work queue item to make ATRewriteTable update the column
-		 * contents.
-		 */
-		newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
-		newval->attnum = attnum;
-		newval->expr = (Expr *) transform;
-		newval->is_generated = false;
-
-		tab->newvals = lappend(tab->newvals, newval);
-		if (ATColumnChangeRequiresRewrite(transform, attnum))
-			tab->rewrite |= AT_REWRITE_COLUMN_REWRITE;
-	}
-	else if (transform)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table",
-						RelationGetRelationName(rel))));
-
-	if (tab->relkind == RELKIND_COMPOSITE_TYPE ||
-		tab->relkind == RELKIND_FOREIGN_TABLE)
-	{
-		/*
-		 * For composite types and foreign tables, do this check now.  Regular
-		 * tables will check it later when the table is being rewritten.
-		 */
-		find_composite_type_dependencies(rel->rd_rel->reltype, rel, NULL);
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("\"%s\" is not a table",
+								RelationGetRelationName(rel))));
 	}
 
 	ReleaseSysCache(tuple);
@@ -11053,8 +11595,23 @@ ATPrepAlterColumnType(List **wqueue,
 				 errmsg("type of inherited column \"%s\" must be changed in child tables too",
 						colName)));
 
-	if (tab->relkind == RELKIND_COMPOSITE_TYPE)
-		ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
+	Assert(RELKIND_IS_VALID((RelKind) tab->relkind));
+	switch ((RelKind) tab->relkind)
+	{
+		case RELKIND_COMPOSITE_TYPE:
+			ATTypedTableRecursion(wqueue, rel, cmd, lockmode, context);
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
+	}
 }
 
 /*
@@ -11271,44 +11828,51 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 				{
 					char		relKind = get_rel_relkind(foundObject.objectId);
 
-					if (relKind == RELKIND_INDEX ||
-						relKind == RELKIND_PARTITIONED_INDEX)
+					Assert(RELKIND_IS_VALID((RelKind) relKind));
+					switch ((RelKind) relKind)
 					{
-						Assert(foundObject.objectSubId == 0);
-						RememberIndexForRebuilding(foundObject.objectId, tab);
-					}
-					else if (relKind == RELKIND_SEQUENCE)
-					{
-						/*
-						 * This must be a SERIAL column's sequence.  We need
-						 * not do anything to it.
-						 */
-						Assert(foundObject.objectSubId == 0);
-					}
-					else if (relKind == RELKIND_RELATION &&
-							 foundObject.objectSubId != 0 &&
-							 get_attgenerated(foundObject.objectId, foundObject.objectSubId))
-					{
-						/*
-						 * Changing the type of a column that is used by a
-						 * generated column is not allowed by SQL standard. It
-						 * might be doable with some thinking and effort.
-						 */
-						ereport(ERROR,
-								(errcode(ERRCODE_SYNTAX_ERROR),
-								 errmsg("cannot alter type of a column used by a generated column"),
-								 errdetail("Column \"%s\" is used by generated column \"%s\".",
-										   colName, get_attname(foundObject.objectId, foundObject.objectSubId, false))));
-					}
-					else
-					{
-						/* Not expecting any other direct dependencies... */
-						elog(ERROR, "unexpected object depending on column: %s",
-							 getObjectDescription(&foundObject));
+						case RELKIND_INDEX:
+						case RELKIND_PARTITIONED_INDEX:
+							Assert(foundObject.objectSubId == 0);
+							RememberIndexForRebuilding(foundObject.objectId, tab);
+							break;
+						case RELKIND_SEQUENCE:
+
+							/*
+							 * This must be a SERIAL column's sequence.  We
+							 * need not do anything to it.
+							 */
+							Assert(foundObject.objectSubId == 0);
+							break;
+						case RELKIND_RELATION:
+							if (foundObject.objectSubId != 0 &&
+								get_attgenerated(foundObject.objectId, foundObject.objectSubId))
+							{
+								/*
+								 * Changing the type of a column that is used
+								 * by a generated column is not allowed by SQL
+								 * standard. It might be doable with some
+								 * thinking and effort.
+								 */
+								ereport(ERROR,
+										(errcode(ERRCODE_SYNTAX_ERROR),
+										 errmsg("cannot alter type of a column used by a generated column"),
+										 errdetail("Column \"%s\" is used by generated column \"%s\".",
+												   colName, get_attname(foundObject.objectId, foundObject.objectSubId, false))));
+							}
+							break;
+						case RELKIND_FOREIGN_TABLE:
+						case RELKIND_PARTITIONED_TABLE:
+						case RELKIND_COMPOSITE_TYPE:
+						case RELKIND_MATVIEW:
+						case RELKIND_VIEW:
+						case RELKIND_TOASTVALUE:
+							/* Not expecting any other direct dependencies... */
+							elog(ERROR, "unexpected object depending on column: %s",
+								 getObjectDescription(&foundObject));
 					}
-					break;
 				}
-
+				break;
 			case OCLASS_CONSTRAINT:
 				Assert(foundObject.objectSubId == 0);
 				RememberConstraintForRebuilding(foundObject.objectId, tab);
@@ -12141,13 +12705,26 @@ TryReuseIndex(Oid oldId, IndexStmt *stmt)
 	{
 		Relation	irel = index_open(oldId, NoLock);
 
-		/* If it's a partitioned index, there is no storage to share. */
-		if (irel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
+		Assert(RELKIND_IS_VALID((RelKind) irel->rd_rel->relkind));
+		switch ((RelKind) irel->rd_rel->relkind)
 		{
-			stmt->oldNode = irel->rd_node.relNode;
-			stmt->oldCreateSubid = irel->rd_createSubid;
-			stmt->oldFirstRelfilenodeSubid = irel->rd_firstRelfilenodeSubid;
+			case RELKIND_PARTITIONED_INDEX:
+				/* If it's a partitioned index, there is no storage to share. */
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+				stmt->oldNode = irel->rd_node.relNode;
+				stmt->oldCreateSubid = irel->rd_createSubid;
+				stmt->oldFirstRelfilenodeSubid = irel->rd_firstRelfilenodeSubid;
 		}
+
 		index_close(irel, NoLock);
 	}
 }
@@ -12342,7 +12919,8 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock
 	tuple_class = (Form_pg_class) GETSTRUCT(tuple);
 
 	/* Can we change the ownership of this tuple? */
-	switch (tuple_class->relkind)
+	Assert(RELKIND_IS_VALID((RelKind) tuple_class->relkind));
+	switch ((RelKind) tuple_class->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_VIEW:
@@ -12411,8 +12989,6 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock
 		case RELKIND_TOASTVALUE:
 			if (recursing)
 				break;
-			/* FALL THRU */
-		default:
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("\"%s\" is not a table, view, sequence, or foreign table",
@@ -12517,22 +13093,33 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock
 		 * the ownership of any indexes and sequences that belong to the
 		 * relation, as well as its toast table (if it has one).
 		 */
-		if (tuple_class->relkind == RELKIND_RELATION ||
-			tuple_class->relkind == RELKIND_PARTITIONED_TABLE ||
-			tuple_class->relkind == RELKIND_MATVIEW ||
-			tuple_class->relkind == RELKIND_TOASTVALUE)
+		switch (tuple_class->relkind)
 		{
-			List	   *index_oid_list;
-			ListCell   *i;
+			case RELKIND_RELATION:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_MATVIEW:
+			case RELKIND_TOASTVALUE:
+				{
+					List	   *index_oid_list;
+					ListCell   *i;
 
-			/* Find all the indexes belonging to this relation */
-			index_oid_list = RelationGetIndexList(target_rel);
+					/* Find all the indexes belonging to this relation */
+					index_oid_list = RelationGetIndexList(target_rel);
 
-			/* For each index, recursively change its ownership */
-			foreach(i, index_oid_list)
-				ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
+					/* For each index, recursively change its ownership */
+					foreach(i, index_oid_list)
+						ATExecChangeOwner(lfirst_oid(i), newOwnerId, true, lockmode);
 
-			list_free(index_oid_list);
+					list_free(index_oid_list);
+				}
+				break;
+			case RELKIND_VIEW:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_SEQUENCE:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_INDEX:
+				break;
 		}
 
 		/* If it has a toast table, recurse to change its ownership */
@@ -12665,11 +13252,23 @@ change_owner_recurse_to_sequences(Oid relationOid, Oid newOwnerId, LOCKMODE lock
 		seqRel = relation_open(depForm->objid, lockmode);
 
 		/* skip non-sequence relations */
-		if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
+		Assert(RELKIND_IS_VALID((RelKind) RelationGetForm(seqRel)->relkind));
+		switch ((RelKind) RelationGetForm(seqRel)->relkind)
 		{
-			/* No need to keep the lock */
-			relation_close(seqRel, lockmode);
-			continue;
+			case RELKIND_SEQUENCE:
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_TOASTVALUE:
+				/* No need to keep the lock */
+				relation_close(seqRel, lockmode);
+				continue;
 		}
 
 		/* We don't need to close the sequence while we alter it. */
@@ -12811,7 +13410,8 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 									 operation == AT_ResetRelOptions);
 
 	/* Validate */
-	switch (rel->rd_rel->relkind)
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_TOASTVALUE:
@@ -12823,50 +13423,50 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 			break;
 		case RELKIND_VIEW:
 			(void) view_reloptions(newOptions, true);
+
+			/* Special-case validation of view options */
+			{
+				Query	   *view_query = get_view_query(rel);
+				List	   *view_options = untransformRelOptions(newOptions);
+				ListCell   *cell;
+				bool		check_option = false;
+
+				foreach(cell, view_options)
+				{
+					DefElem    *defel = (DefElem *) lfirst(cell);
+
+					if (strcmp(defel->defname, "check_option") == 0)
+						check_option = true;
+				}
+
+				/*
+				 * If the check option is specified, look to see if the view
+				 * is actually auto-updatable or not.
+				 */
+				if (check_option)
+				{
+					const char *view_updatable_error =
+					view_query_is_auto_updatable(view_query, true);
+
+					if (view_updatable_error)
+						ereport(ERROR,
+								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+								 errmsg("WITH CHECK OPTION is supported only on automatically updatable views"),
+								 errhint("%s", _(view_updatable_error))));
+				}
+			}
 			break;
 		case RELKIND_INDEX:
 		case RELKIND_PARTITIONED_INDEX:
 			(void) index_reloptions(rel->rd_indam->amoptions, newOptions, true);
 			break;
-		default:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_SEQUENCE:
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("\"%s\" is not a table, view, materialized view, index, or TOAST table",
 							RelationGetRelationName(rel))));
-			break;
-	}
-
-	/* Special-case validation of view options */
-	if (rel->rd_rel->relkind == RELKIND_VIEW)
-	{
-		Query	   *view_query = get_view_query(rel);
-		List	   *view_options = untransformRelOptions(newOptions);
-		ListCell   *cell;
-		bool		check_option = false;
-
-		foreach(cell, view_options)
-		{
-			DefElem    *defel = (DefElem *) lfirst(cell);
-
-			if (strcmp(defel->defname, "check_option") == 0)
-				check_option = true;
-		}
-
-		/*
-		 * If the check option is specified, look to see if the view is
-		 * actually auto-updatable or not.
-		 */
-		if (check_option)
-		{
-			const char *view_updatable_error =
-			view_query_is_auto_updatable(view_query, true);
-
-			if (view_updatable_error)
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("WITH CHECK OPTION is supported only on automatically updatable views"),
-						 errhint("%s", _(view_updatable_error))));
-		}
 	}
 
 	/*
@@ -13053,16 +13653,25 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
 	newrnode.spcNode = newTableSpace;
 
 	/* hand off to AM to actually create the new filenode and copy the data */
-	if (rel->rd_rel->relkind == RELKIND_INDEX)
-	{
-		index_copy_data(rel, newrnode);
-	}
-	else
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
-			   rel->rd_rel->relkind == RELKIND_MATVIEW ||
-			   rel->rd_rel->relkind == RELKIND_TOASTVALUE);
-		table_relation_copy_data(rel, &newrnode);
+		case RELKIND_INDEX:
+			index_copy_data(rel, newrnode);
+			break;
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+			table_relation_copy_data(rel, &newrnode);
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+			Assert(false);
+			break;
 	}
 
 	/*
@@ -13433,10 +14042,25 @@ ATPrepAddInherit(Relation child_rel)
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("cannot change inheritance of a partition")));
 
-	if (child_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot change inheritance of partitioned table")));
+	Assert(RELKIND_IS_VALID((RelKind) child_rel->rd_rel->relkind));
+	switch ((RelKind) child_rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot change inheritance of partitioned table")));
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
+	}
 }
 
 /*
@@ -13485,11 +14109,26 @@ ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
 				 errmsg("cannot inherit to temporary relation of another session")));
 
 	/* Prevent partitioned tables from becoming inheritance parents */
-	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot inherit from partitioned table \"%s\"",
-						parent->relname)));
+	Assert(RELKIND_IS_VALID((RelKind) parent_rel->rd_rel->relkind));
+	switch ((RelKind) parent_rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot inherit from partitioned table \"%s\"",
+							parent->relname)));
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
+	}
 
 	/* Likewise for partitions */
 	if (parent_rel->rd_rel->relispartition)
@@ -13693,8 +14332,23 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
 	parent_natts = tupleDesc->natts;
 
 	/* If parent_rel is a partitioned table, child_rel must be a partition */
-	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		child_is_partition = true;
+	Assert(RELKIND_IS_VALID((RelKind) parent_rel->rd_rel->relkind));
+	switch ((RelKind) parent_rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			child_is_partition = true;
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
+	}
 
 	for (parent_attno = 1; parent_attno <= parent_natts; parent_attno++)
 	{
@@ -13802,8 +14456,23 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
 	tuple_desc = RelationGetDescr(catalog_relation);
 
 	/* If parent_rel is a partitioned table, child_rel must be a partition */
-	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		child_is_partition = true;
+	Assert(RELKIND_IS_VALID((RelKind) parent_rel->rd_rel->relkind));
+	switch ((RelKind) parent_rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			child_is_partition = true;
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
+	}
 
 	/* Outer loop scans through the parent's constraint definitions */
 	ScanKeyInit(&parent_key,
@@ -13984,8 +14653,23 @@ RemoveInheritance(Relation child_rel, Relation parent_rel)
 	bool		child_is_partition = false;
 
 	/* If parent_rel is a partitioned table, child_rel must be a partition */
-	if (parent_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		child_is_partition = true;
+	Assert(RELKIND_IS_VALID((RelKind) parent_rel->rd_rel->relkind));
+	switch ((RelKind) parent_rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			child_is_partition = true;
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
+	}
 
 	found = DeleteInheritsTuple(RelationGetRelid(child_rel),
 								RelationGetRelid(parent_rel));
@@ -14896,20 +15580,35 @@ AlterTableNamespace(AlterObjectSchemaStmt *stmt, Oid *oldschema)
 
 	oldNspOid = RelationGetNamespace(rel);
 
-	/* If it's an owned sequence, disallow moving it by itself. */
-	if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		Oid			tableId;
-		int32		colId;
+			/* If it's an owned sequence, disallow moving it by itself. */
+		case RELKIND_SEQUENCE:
+			{
+				Oid			tableId;
+				int32		colId;
 
-		if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
-			sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
-			ereport(ERROR,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("cannot move an owned sequence into another schema"),
-					 errdetail("Sequence \"%s\" is linked to table \"%s\".",
-							   RelationGetRelationName(rel),
-							   get_rel_name(tableId))));
+				if (sequenceIsOwned(relid, DEPENDENCY_AUTO, &tableId, &colId) ||
+					sequenceIsOwned(relid, DEPENDENCY_INTERNAL, &tableId, &colId))
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("cannot move an owned sequence into another schema"),
+							 errdetail("Sequence \"%s\" is linked to table \"%s\".",
+									   RelationGetRelationName(rel),
+									   get_rel_name(tableId))));
+			}
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_TOASTVALUE:
+			break;
 	}
 
 	/* Get and lock schema OID and check its permissions. */
@@ -14959,15 +15658,26 @@ AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, Oid nspOid,
 								   nspOid, false, false, objsMoved);
 
 	/* Fix other dependent stuff */
-	if (rel->rd_rel->relkind == RELKIND_RELATION ||
-		rel->rd_rel->relkind == RELKIND_MATVIEW ||
-		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
-		AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
-						   objsMoved, AccessExclusiveLock);
-		AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
-								  false, objsMoved);
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+			AlterIndexNamespaces(classRel, rel, oldNspOid, nspOid, objsMoved);
+			AlterSeqNamespaces(classRel, rel, oldNspOid, nspOid,
+							   objsMoved, AccessExclusiveLock);
+			AlterConstraintNamespaces(RelationGetRelid(rel), oldNspOid, nspOid,
+									  false, objsMoved);
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
 	}
 
 	table_close(classRel, RowExclusiveLock);
@@ -15138,11 +15848,23 @@ AlterSeqNamespaces(Relation classRel, Relation rel,
 		seqRel = relation_open(depForm->objid, lockmode);
 
 		/* skip non-sequence relations */
-		if (RelationGetForm(seqRel)->relkind != RELKIND_SEQUENCE)
+		Assert(RELKIND_IS_VALID((RelKind) RelationGetForm(seqRel)->relkind));
+		switch ((RelKind) RelationGetForm(seqRel)->relkind)
 		{
-			/* No need to keep the lock */
-			relation_close(seqRel, lockmode);
-			continue;
+			case RELKIND_SEQUENCE:
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_TOASTVALUE:
+				/* No need to keep the lock */
+				relation_close(seqRel, lockmode);
+				continue;
 		}
 
 		/* Fix the pg_class and pg_depend entries */
@@ -15422,11 +16144,24 @@ RangeVarCallbackOwnsTable(const RangeVar *relation,
 	relkind = get_rel_relkind(relId);
 	if (!relkind)
 		return;
-	if (relkind != RELKIND_RELATION && relkind != RELKIND_TOASTVALUE &&
-		relkind != RELKIND_MATVIEW && relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table or materialized view", relation->relname)));
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table or materialized view", relation->relname)));
+	}
 
 	/* Check permissions */
 	if (!pg_class_ownercheck(relId, GetUserId()))
@@ -15585,31 +16320,40 @@ RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid, Oid oldrelid,
 				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 				 errmsg("\"%s\" is not an index", rv->relname)));
 
-	/*
-	 * Don't allow ALTER TABLE on composite types. We want people to use ALTER
-	 * TYPE for that.
-	 */
-	if (reltype != OBJECT_TYPE && relkind == RELKIND_COMPOSITE_TYPE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is a composite type", rv->relname),
-				 errhint("Use ALTER TYPE instead.")));
-
 	/*
 	 * Don't allow ALTER TABLE .. SET SCHEMA on relations that can't be moved
 	 * to a different schema, such as indexes and TOAST tables.
 	 */
-	if (IsA(stmt, AlterObjectSchemaStmt) &&
-		relkind != RELKIND_RELATION &&
-		relkind != RELKIND_VIEW &&
-		relkind != RELKIND_MATVIEW &&
-		relkind != RELKIND_SEQUENCE &&
-		relkind != RELKIND_FOREIGN_TABLE &&
-		relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table, view, materialized view, sequence, or foreign table",
-						rv->relname)));
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+			/*
+			 * Don't allow ALTER TABLE on composite types. We want people to use ALTER
+			 * TYPE for that.
+			 */
+			if (reltype != OBJECT_TYPE)
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("\"%s\" is a composite type", rv->relname),
+						 errhint("Use ALTER TYPE instead.")));
+			/* fallthrough */
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_TOASTVALUE:
+			if (IsA(stmt, AlterObjectSchemaStmt))
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("\"%s\" is not a table, view, materialized view, sequence, or foreign table",
+								rv->relname)));
+	}
 
 	ReleaseSysCache(tuple);
 }
@@ -16084,44 +16828,59 @@ QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
 	 * validation item now; for partitioned tables, recurse to process each
 	 * partition.
 	 */
-	if (scanrel->rd_rel->relkind == RELKIND_RELATION)
+	Assert(RELKIND_IS_VALID((RelKind) scanrel->rd_rel->relkind));
+	switch ((RelKind) scanrel->rd_rel->relkind)
 	{
-		AlteredTableInfo *tab;
+		case RELKIND_RELATION:
+			{
+				AlteredTableInfo *tab;
 
-		/* Grab a work queue entry. */
-		tab = ATGetQueueEntry(wqueue, scanrel);
-		Assert(tab->partition_constraint == NULL);
-		tab->partition_constraint = (Expr *) linitial(partConstraint);
-		tab->validate_default = validate_default;
-	}
-	else if (scanrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-	{
-		PartitionDesc partdesc = RelationGetPartitionDesc(scanrel);
-		int			i;
+				/* Grab a work queue entry. */
+				tab = ATGetQueueEntry(wqueue, scanrel);
+				Assert(tab->partition_constraint == NULL);
+				tab->partition_constraint = (Expr *) linitial(partConstraint);
+				tab->validate_default = validate_default;
+			}
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+			{
+				PartitionDesc partdesc = RelationGetPartitionDesc(scanrel);
+				int			i;
 
-		for (i = 0; i < partdesc->nparts; i++)
-		{
-			Relation	part_rel;
-			List	   *thisPartConstraint;
+				for (i = 0; i < partdesc->nparts; i++)
+				{
+					Relation	part_rel;
+					List	   *thisPartConstraint;
 
-			/*
-			 * This is the minimum lock we need to prevent deadlocks.
-			 */
-			part_rel = table_open(partdesc->oids[i], AccessExclusiveLock);
+					/*
+					 * This is the minimum lock we need to prevent deadlocks.
+					 */
+					part_rel = table_open(partdesc->oids[i], AccessExclusiveLock);
 
-			/*
-			 * Adjust the constraint for scanrel so that it matches this
-			 * partition's attribute numbers.
-			 */
-			thisPartConstraint =
-				map_partition_varattnos(partConstraint, 1,
-										part_rel, scanrel);
-
-			QueuePartitionConstraintValidation(wqueue, part_rel,
-											   thisPartConstraint,
-											   validate_default);
-			table_close(part_rel, NoLock);	/* keep lock till commit */
-		}
+					/*
+					 * Adjust the constraint for scanrel so that it matches
+					 * this partition's attribute numbers.
+					 */
+					thisPartConstraint =
+						map_partition_varattnos(partConstraint, 1,
+												part_rel, scanrel);
+
+					QueuePartitionConstraintValidation(wqueue, part_rel,
+													   thisPartConstraint,
+													   validate_default);
+					table_close(part_rel, NoLock);	/* keep lock till commit */
+				}
+			}
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
 	}
 }
 
@@ -16205,11 +16964,28 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
 				ObjectIdGetDatum(RelationGetRelid(attachrel)));
 	scan = systable_beginscan(catalog, InheritsParentIndexId, true, NULL,
 							  1, &skey);
-	if (HeapTupleIsValid(systable_getnext(scan)) &&
-		attachrel->rd_rel->relkind == RELKIND_RELATION)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot attach inheritance parent as partition")));
+
+	Assert(RELKIND_IS_VALID((RelKind) attachrel->rd_rel->relkind));
+	switch ((RelKind) attachrel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+			if (HeapTupleIsValid(systable_getnext(scan)))
+				ereport(ERROR,
+						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+						 errmsg("cannot attach inheritance parent as partition")));
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
+	}
+
 	systable_endscan(scan);
 	table_close(catalog, AccessShareLock);
 
@@ -16455,26 +17231,37 @@ AttachPartitionEnsureIndexes(Relation rel, Relation attachrel)
 	 * before starting work, to avoid wasting the effort of building a few
 	 * non-unique indexes before coming across a unique one.
 	 */
-	if (attachrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+	Assert(RELKIND_IS_VALID((RelKind) attachrel->rd_rel->relkind));
+	switch ((RelKind) attachrel->rd_rel->relkind)
 	{
-		foreach(cell, idxes)
-		{
-			Oid			idx = lfirst_oid(cell);
-			Relation	idxRel = index_open(idx, AccessShareLock);
-
-			if (idxRel->rd_index->indisunique ||
-				idxRel->rd_index->indisprimary)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("cannot attach foreign table \"%s\" as partition of partitioned table \"%s\"",
-								RelationGetRelationName(attachrel),
-								RelationGetRelationName(rel)),
-						 errdetail("Table \"%s\" contains unique indexes.",
-								   RelationGetRelationName(rel))));
-			index_close(idxRel, AccessShareLock);
-		}
+		case RELKIND_FOREIGN_TABLE:
+			foreach(cell, idxes)
+			{
+				Oid			idx = lfirst_oid(cell);
+				Relation	idxRel = index_open(idx, AccessShareLock);
 
-		goto out;
+				if (idxRel->rd_index->indisunique ||
+					idxRel->rd_index->indisprimary)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("cannot attach foreign table \"%s\" as partition of partitioned table \"%s\"",
+									RelationGetRelationName(attachrel),
+									RelationGetRelationName(rel)),
+							 errdetail("Table \"%s\" contains unique indexes.",
+									   RelationGetRelationName(rel))));
+				index_close(idxRel, AccessShareLock);
+			}
+			goto out;
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
 	}
 
 	/*
@@ -16494,10 +17281,22 @@ AttachPartitionEnsureIndexes(Relation rel, Relation attachrel)
 		 * Ignore indexes in the partitioned table other than partitioned
 		 * indexes.
 		 */
-		if (idxRel->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
+		Assert(RELKIND_IS_VALID((RelKind) idxRel->rd_rel->relkind));
+		switch ((RelKind) idxRel->rd_rel->relkind)
 		{
-			index_close(idxRel, AccessShareLock);
-			continue;
+			case RELKIND_PARTITIONED_INDEX:
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+				index_close(idxRel, AccessShareLock);
+				continue;
 		}
 
 		/* construct an indexinfo to compare existing indexes against */
@@ -17034,11 +17833,25 @@ RangeVarCallbackForAttachIndex(const RangeVar *rv, Oid relOid, Oid oldRelOid,
 	if (!HeapTupleIsValid(tuple))
 		return;					/* concurrently dropped, so nothing to do */
 	classform = (Form_pg_class) GETSTRUCT(tuple);
-	if (classform->relkind != RELKIND_PARTITIONED_INDEX &&
-		classform->relkind != RELKIND_INDEX)
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
-				 errmsg("\"%s\" is not an index", rv->relname)));
+
+	Assert(RELKIND_IS_VALID((RelKind) classform->relkind));
+	switch ((RelKind) classform->relkind)
+	{
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+					 errmsg("\"%s\" is not an index", rv->relname)));
+	}
 	ReleaseSysCache(tuple);
 
 	/*
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 672fccff5b..b59c636fda 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -194,106 +194,120 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 	 * Triggers must be on tables or views, and there are additional
 	 * relation-type-specific restrictions.
 	 */
-	if (rel->rd_rel->relkind == RELKIND_RELATION)
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		/* Tables can't have INSTEAD OF triggers */
-		if (stmt->timing != TRIGGER_TYPE_BEFORE &&
-			stmt->timing != TRIGGER_TYPE_AFTER)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is a table",
-							RelationGetRelationName(rel)),
-					 errdetail("Tables cannot have INSTEAD OF triggers.")));
-	}
-	else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-	{
-		/* Partitioned tables can't have INSTEAD OF triggers */
-		if (stmt->timing != TRIGGER_TYPE_BEFORE &&
-			stmt->timing != TRIGGER_TYPE_AFTER)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is a table",
-							RelationGetRelationName(rel)),
-					 errdetail("Tables cannot have INSTEAD OF triggers.")));
+		case RELKIND_RELATION:
+			{
+				/* Tables can't have INSTEAD OF triggers */
+				if (stmt->timing != TRIGGER_TYPE_BEFORE &&
+					stmt->timing != TRIGGER_TYPE_AFTER)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is a table",
+									RelationGetRelationName(rel)),
+							 errdetail("Tables cannot have INSTEAD OF triggers.")));
+			}
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+			{
+				/* Partitioned tables can't have INSTEAD OF triggers */
+				if (stmt->timing != TRIGGER_TYPE_BEFORE &&
+					stmt->timing != TRIGGER_TYPE_AFTER)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is a table",
+									RelationGetRelationName(rel)),
+							 errdetail("Tables cannot have INSTEAD OF triggers.")));
 
-		/*
-		 * FOR EACH ROW triggers have further restrictions
-		 */
-		if (stmt->row)
-		{
-			/*
-			 * Disallow use of transition tables.
-			 *
-			 * Note that we have another restriction about transition tables
-			 * in partitions; search for 'has_superclass' below for an
-			 * explanation.  The check here is just to protect from the fact
-			 * that if we allowed it here, the creation would succeed for a
-			 * partitioned table with no partitions, but would be blocked by
-			 * the other restriction when the first partition was created,
-			 * which is very unfriendly behavior.
-			 */
-			if (stmt->transitionRels != NIL)
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("\"%s\" is a partitioned table",
-								RelationGetRelationName(rel)),
-						 errdetail("Triggers on partitioned tables cannot have transition tables.")));
-		}
-	}
-	else if (rel->rd_rel->relkind == RELKIND_VIEW)
-	{
-		/*
-		 * Views can have INSTEAD OF triggers (which we check below are
-		 * row-level), or statement-level BEFORE/AFTER triggers.
-		 */
-		if (stmt->timing != TRIGGER_TYPE_INSTEAD && stmt->row)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is a view",
-							RelationGetRelationName(rel)),
-					 errdetail("Views cannot have row-level BEFORE or AFTER triggers.")));
-		/* Disallow TRUNCATE triggers on VIEWs */
-		if (TRIGGER_FOR_TRUNCATE(stmt->events))
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is a view",
-							RelationGetRelationName(rel)),
-					 errdetail("Views cannot have TRUNCATE triggers.")));
-	}
-	else if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-	{
-		if (stmt->timing != TRIGGER_TYPE_BEFORE &&
-			stmt->timing != TRIGGER_TYPE_AFTER)
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is a foreign table",
-							RelationGetRelationName(rel)),
-					 errdetail("Foreign tables cannot have INSTEAD OF triggers.")));
+				/*
+				 * FOR EACH ROW triggers have further restrictions
+				 */
+				if (stmt->row)
+				{
+					/*
+					 * Disallow use of transition tables.
+					 *
+					 * Note that we have another restriction about transition
+					 * tables in partitions; search for 'has_superclass' below
+					 * for an explanation.  The check here is just to protect
+					 * from the fact that if we allowed it here, the creation
+					 * would succeed for a partitioned table with no
+					 * partitions, but would be blocked by the other
+					 * restriction when the first partition was created, which
+					 * is very unfriendly behavior.
+					 */
+					if (stmt->transitionRels != NIL)
+						ereport(ERROR,
+								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+								 errmsg("\"%s\" is a partitioned table",
+										RelationGetRelationName(rel)),
+								 errdetail("Triggers on partitioned tables cannot have transition tables.")));
+				}
+			}
+			break;
+		case RELKIND_VIEW:
+			{
+				/*
+				 * Views can have INSTEAD OF triggers (which we check below
+				 * are row-level), or statement-level BEFORE/AFTER triggers.
+				 */
+				if (stmt->timing != TRIGGER_TYPE_INSTEAD && stmt->row)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is a view",
+									RelationGetRelationName(rel)),
+							 errdetail("Views cannot have row-level BEFORE or AFTER triggers.")));
+				/* Disallow TRUNCATE triggers on VIEWs */
+				if (TRIGGER_FOR_TRUNCATE(stmt->events))
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is a view",
+									RelationGetRelationName(rel)),
+							 errdetail("Views cannot have TRUNCATE triggers.")));
+			}
+			break;
+		case RELKIND_FOREIGN_TABLE:
+			{
+				if (stmt->timing != TRIGGER_TYPE_BEFORE &&
+					stmt->timing != TRIGGER_TYPE_AFTER)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is a foreign table",
+									RelationGetRelationName(rel)),
+							 errdetail("Foreign tables cannot have INSTEAD OF triggers.")));
 
-		if (TRIGGER_FOR_TRUNCATE(stmt->events))
-			ereport(ERROR,
-					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is a foreign table",
-							RelationGetRelationName(rel)),
-					 errdetail("Foreign tables cannot have TRUNCATE triggers.")));
+				if (TRIGGER_FOR_TRUNCATE(stmt->events))
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is a foreign table",
+									RelationGetRelationName(rel)),
+							 errdetail("Foreign tables cannot have TRUNCATE triggers.")));
 
-		/*
-		 * We disallow constraint triggers to protect the assumption that
-		 * triggers on FKs can't be deferred.  See notes with AfterTriggers
-		 * data structures, below.
-		 */
-		if (stmt->isconstraint)
+				/*
+				 * We disallow constraint triggers to protect the assumption
+				 * that triggers on FKs can't be deferred.  See notes with
+				 * AfterTriggers data structures, below.
+				 */
+				if (stmt->isconstraint)
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is a foreign table",
+									RelationGetRelationName(rel)),
+							 errdetail("Foreign tables cannot have constraint triggers.")));
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is a foreign table",
-							RelationGetRelationName(rel)),
-					 errdetail("Foreign tables cannot have constraint triggers.")));
+					 errmsg("\"%s\" is not a table or view",
+							RelationGetRelationName(rel))));
 	}
-	else
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table or view",
-						RelationGetRelationName(rel))));
 
 	if (!allowSystemTableMods && IsSystemRelation(rel))
 		ereport(ERROR,
@@ -345,8 +359,24 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 	 *
 	 * For that, we'd better hold lock on all of them ahead of time.
 	 */
-	partition_recurse = !isInternal && stmt->row &&
-		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE;
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			partition_recurse = !isInternal && stmt->row;
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			partition_recurse = false;
+	}
+
 	if (partition_recurse)
 		list_free(find_all_inheritors(RelationGetRelid(rel),
 									  ShareRowExclusiveLock, NULL));
@@ -416,19 +446,33 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 			 * adjustments will be needed below.
 			 */
 
-			if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is a foreign table",
-								RelationGetRelationName(rel)),
-						 errdetail("Triggers on foreign tables cannot have transition tables.")));
-
-			if (rel->rd_rel->relkind == RELKIND_VIEW)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("\"%s\" is a view",
-								RelationGetRelationName(rel)),
-						 errdetail("Triggers on views cannot have transition tables.")));
+			Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+			switch ((RelKind) rel->rd_rel->relkind)
+			{
+				case RELKIND_FOREIGN_TABLE:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is a foreign table",
+									RelationGetRelationName(rel)),
+							 errdetail("Triggers on foreign tables cannot have transition tables.")));
+					break;
+				case RELKIND_VIEW:
+					ereport(ERROR,
+							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+							 errmsg("\"%s\" is a view",
+									RelationGetRelationName(rel)),
+							 errdetail("Triggers on views cannot have transition tables.")));
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+					break;
+			}
 
 			/*
 			 * We currently don't allow row-level triggers with transition
@@ -1191,14 +1235,25 @@ RemoveTriggerById(Oid trigOid)
 
 	rel = table_open(relid, AccessExclusiveLock);
 
-	if (rel->rd_rel->relkind != RELKIND_RELATION &&
-		rel->rd_rel->relkind != RELKIND_VIEW &&
-		rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
-		rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table, view, or foreign table",
-						RelationGetRelationName(rel))));
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table, view, or foreign table",
+							RelationGetRelationName(rel))));
+	}
 
 	if (!allowSystemTableMods && IsSystemRelation(rel))
 		ereport(ERROR,
@@ -1298,13 +1353,25 @@ RangeVarCallbackForRenameTrigger(const RangeVar *rv, Oid relid, Oid oldrelid,
 	form = (Form_pg_class) GETSTRUCT(tuple);
 
 	/* only tables and views can have triggers */
-	if (form->relkind != RELKIND_RELATION && form->relkind != RELKIND_VIEW &&
-		form->relkind != RELKIND_FOREIGN_TABLE &&
-		form->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table, view, or foreign table",
-						rv->relname)));
+	Assert(RELKIND_IS_VALID((RelKind) form->relkind));
+	switch ((RelKind) form->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table, view, or foreign table",
+							rv->relname)));
+	}
 
 	/* you must own the table to rename one of its triggers */
 	if (!pg_class_ownercheck(relid, GetUserId()))
@@ -1534,21 +1601,36 @@ EnableDisableTrigger(Relation rel, const char *tgname,
 			 * When altering FOR EACH ROW triggers on a partitioned table, do
 			 * the same on the partitions as well.
 			 */
-			if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
-				(TRIGGER_FOR_ROW(oldtrig->tgtype)))
+			Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+			switch ((RelKind) rel->rd_rel->relkind)
 			{
-				PartitionDesc partdesc = RelationGetPartitionDesc(rel);
-				int			i;
-
-				for (i = 0; i < partdesc->nparts; i++)
-				{
-					Relation	part;
-
-					part = relation_open(partdesc->oids[i], lockmode);
-					EnableDisableTrigger(part, NameStr(oldtrig->tgname),
-										 fires_when, skip_system, lockmode);
-					table_close(part, NoLock);	/* keep lock till commit */
-				}
+				case RELKIND_PARTITIONED_TABLE:
+					if (TRIGGER_FOR_ROW(oldtrig->tgtype))
+					{
+						PartitionDesc partdesc = RelationGetPartitionDesc(rel);
+						int			i;
+
+						for (i = 0; i < partdesc->nparts; i++)
+						{
+							Relation	part;
+
+							part = relation_open(partdesc->oids[i], lockmode);
+							EnableDisableTrigger(part, NameStr(oldtrig->tgname),
+												 fires_when, skip_system, lockmode);
+							table_close(part, NoLock);	/* keep lock till commit */
+						}
+					}
+					break;
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_VIEW:
+				case RELKIND_SEQUENCE:
+				case RELKIND_TOASTVALUE:
+					break;
 			}
 
 			changed = true;
@@ -4167,12 +4249,25 @@ afterTriggerInvokeEvents(AfterTriggerEventList *events,
 						ExecDropSingleTupleTableSlot(slot2);
 						slot1 = slot2 = NULL;
 					}
-					if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+					Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+					switch ((RelKind) rel->rd_rel->relkind)
 					{
-						slot1 = MakeSingleTupleTableSlot(rel->rd_att,
-														 &TTSOpsMinimalTuple);
-						slot2 = MakeSingleTupleTableSlot(rel->rd_att,
-														 &TTSOpsMinimalTuple);
+						case RELKIND_FOREIGN_TABLE:
+							slot1 = MakeSingleTupleTableSlot(rel->rd_att,
+															 &TTSOpsMinimalTuple);
+							slot2 = MakeSingleTupleTableSlot(rel->rd_att,
+															 &TTSOpsMinimalTuple);
+							break;
+						case RELKIND_PARTITIONED_TABLE:
+						case RELKIND_RELATION:
+						case RELKIND_COMPOSITE_TYPE:
+						case RELKIND_INDEX:
+						case RELKIND_PARTITIONED_INDEX:
+						case RELKIND_MATVIEW:
+						case RELKIND_VIEW:
+						case RELKIND_SEQUENCE:
+						case RELKIND_TOASTVALUE:
+							break;
 					}
 					if (trigdesc == NULL)	/* should not happen */
 						elog(ERROR, "relation %u has no triggers",
@@ -5566,9 +5661,25 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
 			break;
 	}
 
-	if (!(relkind == RELKIND_FOREIGN_TABLE && row_trigger))
-		new_event.ate_flags = (row_trigger && event == TRIGGER_EVENT_UPDATE) ?
-			AFTER_TRIGGER_2CTID : AFTER_TRIGGER_1CTID;
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_FOREIGN_TABLE:
+			if (row_trigger)
+				break;
+			/* fallthrough */
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			new_event.ate_flags = (row_trigger && event == TRIGGER_EVENT_UPDATE) ?
+				AFTER_TRIGGER_2CTID : AFTER_TRIGGER_1CTID;
+	}
 	/* else, we'll initialize ate_flags for each trigger */
 
 	tgtype_level = (row_trigger ? TRIGGER_TYPE_ROW : TRIGGER_TYPE_STATEMENT);
@@ -5586,16 +5697,32 @@ AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo,
 							modifiedCols, oldslot, newslot))
 			continue;
 
-		if (relkind == RELKIND_FOREIGN_TABLE && row_trigger)
+		Assert(RELKIND_IS_VALID((RelKind) relkind));
+		switch ((RelKind) relkind)
 		{
-			if (fdw_tuplestore == NULL)
-			{
-				fdw_tuplestore = GetCurrentFDWTuplestore();
-				new_event.ate_flags = AFTER_TRIGGER_FDW_FETCH;
-			}
-			else
-				/* subsequent event for the same tuple */
-				new_event.ate_flags = AFTER_TRIGGER_FDW_REUSE;
+			case RELKIND_FOREIGN_TABLE:
+				if (row_trigger)
+				{
+					if (fdw_tuplestore == NULL)
+					{
+						fdw_tuplestore = GetCurrentFDWTuplestore();
+						new_event.ate_flags = AFTER_TRIGGER_FDW_FETCH;
+					}
+					else
+						/* subsequent event for the same tuple */
+						new_event.ate_flags = AFTER_TRIGGER_FDW_REUSE;
+				}
+				break;
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+				break;
 		}
 
 		/*
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 9e5938b10e..7b2f05acf4 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -2918,11 +2918,22 @@ get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
 			 * a suitable expression index, this should also check expression
 			 * index columns.
 			 */
-			if (rel->rd_rel->relkind != RELKIND_RELATION &&
-				rel->rd_rel->relkind != RELKIND_MATVIEW)
+			Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+			switch ((RelKind) rel->rd_rel->relkind)
 			{
-				relation_close(rel, lockmode);
-				continue;
+				case RELKIND_RELATION:
+				case RELKIND_MATVIEW:
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+					relation_close(rel, lockmode);
+					continue;
 			}
 
 			/* Build the RelToCheck entry with enough space for all atts */
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 576c7e63e9..5bcf3fe03f 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -881,10 +881,22 @@ get_all_vacuum_rels(int options)
 		 * to be performed, caller will decide whether to process or ignore
 		 * them.
 		 */
-		if (classForm->relkind != RELKIND_RELATION &&
-			classForm->relkind != RELKIND_MATVIEW &&
-			classForm->relkind != RELKIND_PARTITIONED_TABLE)
-			continue;
+		Assert(RELKIND_IS_VALID((RelKind) classForm->relkind));
+		switch ((RelKind) classForm->relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				continue;
+		}
 
 		/*
 		 * Build VacuumRelation(s) specifying the table OIDs to be processed.
@@ -1383,13 +1395,23 @@ vac_update_datfrozenxid(void)
 		 * Only consider relations able to hold unfrozen XIDs (anything else
 		 * should have InvalidTransactionId in relfrozenxid anyway).
 		 */
-		if (classForm->relkind != RELKIND_RELATION &&
-			classForm->relkind != RELKIND_MATVIEW &&
-			classForm->relkind != RELKIND_TOASTVALUE)
+		Assert(RELKIND_IS_VALID((RelKind) classForm->relkind));
+		switch ((RelKind) classForm->relkind)
 		{
-			Assert(!TransactionIdIsValid(classForm->relfrozenxid));
-			Assert(!MultiXactIdIsValid(classForm->relminmxid));
-			continue;
+			case RELKIND_RELATION:
+			case RELKIND_MATVIEW:
+			case RELKIND_TOASTVALUE:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_VIEW:
+				Assert(!TransactionIdIsValid(classForm->relfrozenxid));
+				Assert(!MultiXactIdIsValid(classForm->relminmxid));
+				continue;
 		}
 
 		/*
@@ -1762,18 +1784,27 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
 	/*
 	 * Check that it's of a vacuumable relkind.
 	 */
-	if (onerel->rd_rel->relkind != RELKIND_RELATION &&
-		onerel->rd_rel->relkind != RELKIND_MATVIEW &&
-		onerel->rd_rel->relkind != RELKIND_TOASTVALUE &&
-		onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
+	Assert(RELKIND_IS_VALID((RelKind) onerel->rd_rel->relkind));
+	switch ((RelKind) onerel->rd_rel->relkind)
 	{
-		ereport(WARNING,
-				(errmsg("skipping \"%s\" --- cannot vacuum non-tables or special system tables",
-						RelationGetRelationName(onerel))));
-		relation_close(onerel, lmode);
-		PopActiveSnapshot();
-		CommitTransactionCommand();
-		return false;
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_VIEW:
+			ereport(WARNING,
+					(errmsg("skipping \"%s\" --- cannot vacuum non-tables or special system tables",
+							RelationGetRelationName(onerel))));
+			relation_close(onerel, lmode);
+			PopActiveSnapshot();
+			CommitTransactionCommand();
+			return false;
 	}
 
 	/*
@@ -1796,13 +1827,25 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
 	 * useful work is on their child partitions, which have been queued up for
 	 * us separately.
 	 */
-	if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	Assert(RELKIND_IS_VALID((RelKind) onerel->rd_rel->relkind));
+	switch ((RelKind) onerel->rd_rel->relkind)
 	{
-		relation_close(onerel, lmode);
-		PopActiveSnapshot();
-		CommitTransactionCommand();
-		/* It's OK to proceed with ANALYZE on this table */
-		return true;
+		case RELKIND_PARTITIONED_TABLE:
+			relation_close(onerel, lmode);
+			PopActiveSnapshot();
+			CommitTransactionCommand();
+			/* It's OK to proceed with ANALYZE on this table */
+			return true;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
 	}
 
 	/*
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 4fdffad6f3..f170d8f570 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -1079,7 +1079,8 @@ CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
 	TriggerDesc *trigDesc = resultRel->trigdesc;
 	FdwRoutine *fdwroutine;
 
-	switch (resultRel->rd_rel->relkind)
+	Assert(RELKIND_IS_VALID((RelKind) resultRel->rd_rel->relkind));
+	switch ((RelKind) resultRel->rd_rel->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
@@ -1193,12 +1194,13 @@ CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation)
 					break;
 			}
 			break;
-		default:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("cannot change relation \"%s\"",
 							RelationGetRelationName(resultRel))));
-			break;
 	}
 }
 
@@ -1213,7 +1215,8 @@ CheckValidRowMarkRel(Relation rel, RowMarkType markType)
 {
 	FdwRoutine *fdwroutine;
 
-	switch (rel->rd_rel->relkind)
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_PARTITIONED_TABLE:
@@ -1257,12 +1260,13 @@ CheckValidRowMarkRel(Relation rel, RowMarkType markType)
 						 errmsg("cannot lock rows in foreign table \"%s\"",
 								RelationGetRelationName(rel))));
 			break;
-		default:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 					 errmsg("cannot lock rows in relation \"%s\"",
 							RelationGetRelationName(rel))));
-			break;
 	}
 }
 
@@ -1308,10 +1312,24 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
 		resultRelInfo->ri_TrigWhenExprs = NULL;
 		resultRelInfo->ri_TrigInstrument = NULL;
 	}
-	if (resultRelationDesc->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
-		resultRelInfo->ri_FdwRoutine = GetFdwRoutineForRelation(resultRelationDesc, true);
-	else
-		resultRelInfo->ri_FdwRoutine = NULL;
+
+	Assert(RELKIND_IS_VALID((RelKind) resultRelationDesc->rd_rel->relkind));
+	switch ((RelKind) resultRelationDesc->rd_rel->relkind)
+	{
+		case RELKIND_FOREIGN_TABLE:
+			resultRelInfo->ri_FdwRoutine = GetFdwRoutineForRelation(resultRelationDesc, true);
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			resultRelInfo->ri_FdwRoutine = NULL;
+	}
 
 	/* The following fields are set later if needed */
 	resultRelInfo->ri_FdwState = NULL;
@@ -2614,42 +2632,57 @@ EvalPlanQualFetchRowMark(EPQState *epqstate, Index rti, TupleTableSlot *slot)
 			return false;
 
 		/* fetch requests on foreign tables must be passed to their FDW */
-		if (erm->relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		Assert(RELKIND_IS_VALID((RelKind) erm->relation->rd_rel->relkind));
+		switch ((RelKind) erm->relation->rd_rel->relkind)
 		{
-			FdwRoutine *fdwroutine;
-			bool		updated = false;
+			case RELKIND_FOREIGN_TABLE:
+				{
+					FdwRoutine *fdwroutine;
+					bool		updated = false;
 
-			fdwroutine = GetFdwRoutineForRelation(erm->relation, false);
-			/* this should have been checked already, but let's be safe */
-			if (fdwroutine->RefetchForeignRow == NULL)
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("cannot lock rows in foreign table \"%s\"",
-								RelationGetRelationName(erm->relation))));
+					fdwroutine = GetFdwRoutineForRelation(erm->relation, false);
 
-			fdwroutine->RefetchForeignRow(epqstate->recheckestate,
-										  erm,
-										  datum,
-										  slot,
-										  &updated);
-			if (TupIsNull(slot))
-				elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
+					/*
+					 * this should have been checked already, but let's be
+					 * safe
+					 */
+					if (fdwroutine->RefetchForeignRow == NULL)
+						ereport(ERROR,
+								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+								 errmsg("cannot lock rows in foreign table \"%s\"",
+										RelationGetRelationName(erm->relation))));
 
-			/*
-			 * Ideally we'd insist on updated == false here, but that assumes
-			 * that FDWs can track that exactly, which they might not be able
-			 * to.  So just ignore the flag.
-			 */
-			return true;
-		}
-		else
-		{
-			/* ordinary table, fetch the tuple */
-			if (!table_tuple_fetch_row_version(erm->relation,
-											   (ItemPointer) DatumGetPointer(datum),
-											   SnapshotAny, slot))
-				elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
-			return true;
+					fdwroutine->RefetchForeignRow(epqstate->recheckestate,
+												  erm,
+												  datum,
+												  slot,
+												  &updated);
+					if (TupIsNull(slot))
+						elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
+
+					/*
+					 * Ideally we'd insist on updated == false here, but that
+					 * assumes that FDWs can track that exactly, which they
+					 * might not be able to.  So just ignore the flag.
+					 */
+					return true;
+				}
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				/* ordinary table, fetch the tuple */
+				if (!table_tuple_fetch_row_version(erm->relation,
+												   (ItemPointer) DatumGetPointer(datum),
+												   SnapshotAny, slot))
+					elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
+				return true;
 		}
 	}
 	else
diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c
index 8f474faed0..391ccf7564 100644
--- a/src/backend/executor/execReplication.c
+++ b/src/backend/executor/execReplication.c
@@ -607,19 +607,32 @@ CheckSubscriptionRelkind(char relkind, const char *nspname,
 	/*
 	 * Give a more specific error for foreign tables.
 	 */
-	if (relkind == RELKIND_FOREIGN_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot use relation \"%s.%s\" as logical replication target",
-						nspname, relname),
-				 errdetail("\"%s.%s\" is a foreign table.",
-						   nspname, relname)));
-
-	if (relkind != RELKIND_RELATION && relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("cannot use relation \"%s.%s\" as logical replication target",
-						nspname, relname),
-				 errdetail("\"%s.%s\" is not a table.",
-						   nspname, relname)));
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_FOREIGN_TABLE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot use relation \"%s.%s\" as logical replication target",
+							nspname, relname),
+					 errdetail("\"%s.%s\" is a foreign table.",
+							   nspname, relname)));
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("cannot use relation \"%s.%s\" as logical replication target",
+							nspname, relname),
+					 errdetail("\"%s.%s\" is not a table.",
+							   nspname, relname)));
+	}
 }
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 20a4c474cc..275fc8fa8b 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -2177,56 +2177,73 @@ ExecModifyTable(PlanState *pstate)
 				bool		isNull;
 
 				relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
-				if (relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW)
+				Assert(RELKIND_IS_VALID((RelKind) relkind));
+				switch ((RelKind) relkind)
 				{
-					datum = ExecGetJunkAttribute(slot,
-												 junkfilter->jf_junkAttNo,
-												 &isNull);
-					/* shouldn't ever get a null result... */
-					if (isNull)
-						elog(ERROR, "ctid is NULL");
-
-					tupleid = (ItemPointer) DatumGetPointer(datum);
-					tuple_ctid = *tupleid;	/* be sure we don't free ctid!! */
-					tupleid = &tuple_ctid;
-				}
+					case RELKIND_RELATION:
+					case RELKIND_MATVIEW:
+						datum = ExecGetJunkAttribute(slot,
+													 junkfilter->jf_junkAttNo,
+													 &isNull);
+						/* shouldn't ever get a null result... */
+						if (isNull)
+							elog(ERROR, "ctid is NULL");
+
+						tupleid = (ItemPointer) DatumGetPointer(datum);
+						tuple_ctid = *tupleid;	/* be sure we don't free
+												 * ctid!! */
+						tupleid = &tuple_ctid;
+						break;
+					case RELKIND_PARTITIONED_INDEX:
+					case RELKIND_SEQUENCE:
+					case RELKIND_COMPOSITE_TYPE:
+					case RELKIND_FOREIGN_TABLE:
+					case RELKIND_INDEX:
+					case RELKIND_PARTITIONED_TABLE:
+					case RELKIND_TOASTVALUE:
+					case RELKIND_VIEW:
+						/*
+						 * Use the wholerow attribute, when available, to
+						 * reconstruct the old relation tuple.
+						 *
+						 * Foreign table updates have a wholerow attribute
+						 * when the relation has a row-level trigger.  Note
+						 * that the wholerow attribute does not carry system
+						 * columns.  Foreign table triggers miss seeing those,
+						 * except that we know enough here to set t_tableOid.
+						 * Quite separately from this, the FDW may fetch its
+						 * own junk attrs to identify the row.
+						 *
+						 * Other relevant relkinds, currently limited to
+						 * views, always have a wholerow attribute.
+						 */
+						if (AttributeNumberIsValid(junkfilter->jf_junkAttNo))
+						{
+							datum = ExecGetJunkAttribute(slot,
+														 junkfilter->jf_junkAttNo,
+														 &isNull);
+							/* shouldn't ever get a null result... */
+							if (isNull)
+								elog(ERROR, "wholerow is NULL");
+
+							oldtupdata.t_data = DatumGetHeapTupleHeader(datum);
+							oldtupdata.t_len =
+								HeapTupleHeaderGetDatumLength(oldtupdata.t_data);
+							ItemPointerSetInvalid(&(oldtupdata.t_self));
 
-				/*
-				 * Use the wholerow attribute, when available, to reconstruct
-				 * the old relation tuple.
-				 *
-				 * Foreign table updates have a wholerow attribute when the
-				 * relation has a row-level trigger.  Note that the wholerow
-				 * attribute does not carry system columns.  Foreign table
-				 * triggers miss seeing those, except that we know enough here
-				 * to set t_tableOid.  Quite separately from this, the FDW may
-				 * fetch its own junk attrs to identify the row.
-				 *
-				 * Other relevant relkinds, currently limited to views, always
-				 * have a wholerow attribute.
-				 */
-				else if (AttributeNumberIsValid(junkfilter->jf_junkAttNo))
-				{
-					datum = ExecGetJunkAttribute(slot,
-												 junkfilter->jf_junkAttNo,
-												 &isNull);
-					/* shouldn't ever get a null result... */
-					if (isNull)
-						elog(ERROR, "wholerow is NULL");
-
-					oldtupdata.t_data = DatumGetHeapTupleHeader(datum);
-					oldtupdata.t_len =
-						HeapTupleHeaderGetDatumLength(oldtupdata.t_data);
-					ItemPointerSetInvalid(&(oldtupdata.t_self));
-					/* Historically, view triggers see invalid t_tableOid. */
-					oldtupdata.t_tableOid =
-						(relkind == RELKIND_VIEW) ? InvalidOid :
-						RelationGetRelid(resultRelInfo->ri_RelationDesc);
-
-					oldtuple = &oldtupdata;
+							/*
+							 * Historically, view triggers see invalid
+							 * t_tableOid.
+							 */
+							oldtupdata.t_tableOid =
+								(relkind == RELKIND_VIEW) ? InvalidOid :
+								RelationGetRelid(resultRelInfo->ri_RelationDesc);
+
+							oldtuple = &oldtupdata;
+						}
+						else
+							Assert(relkind == RELKIND_FOREIGN_TABLE);
 				}
-				else
-					Assert(relkind == RELKIND_FOREIGN_TABLE);
 			}
 
 			/*
@@ -2697,27 +2714,32 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
 					char		relkind;
 
 					relkind = resultRelInfo->ri_RelationDesc->rd_rel->relkind;
-					if (relkind == RELKIND_RELATION ||
-						relkind == RELKIND_MATVIEW ||
-						relkind == RELKIND_PARTITIONED_TABLE)
-					{
-						j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
-						if (!AttributeNumberIsValid(j->jf_junkAttNo))
-							elog(ERROR, "could not find junk ctid column");
-					}
-					else if (relkind == RELKIND_FOREIGN_TABLE)
-					{
-						/*
-						 * When there is a row-level trigger, there should be
-						 * a wholerow attribute.
-						 */
-						j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
-					}
-					else
+					Assert(RELKIND_IS_VALID((RelKind) relkind));
+					switch ((RelKind) relkind)
 					{
-						j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
-						if (!AttributeNumberIsValid(j->jf_junkAttNo))
-							elog(ERROR, "could not find junk wholerow column");
+						case RELKIND_RELATION:
+						case RELKIND_MATVIEW:
+						case RELKIND_PARTITIONED_TABLE:
+							j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
+							if (!AttributeNumberIsValid(j->jf_junkAttNo))
+								elog(ERROR, "could not find junk ctid column");
+							break;
+						case RELKIND_FOREIGN_TABLE:
+							/*
+							 * When there is a row-level trigger, there
+							 * should be a wholerow attribute.
+							 */
+							j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
+							break;
+						case RELKIND_PARTITIONED_INDEX:
+						case RELKIND_SEQUENCE:
+						case RELKIND_COMPOSITE_TYPE:
+						case RELKIND_INDEX:
+						case RELKIND_TOASTVALUE:
+						case RELKIND_VIEW:
+							j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
+							if (!AttributeNumberIsValid(j->jf_junkAttNo))
+								elog(ERROR, "could not find junk wholerow column");
 					}
 				}
 
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6da0dcd61c..c328bdbc10 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -387,29 +387,40 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
 		switch (rel->rtekind)
 		{
 			case RTE_RELATION:
-				if (rte->relkind == RELKIND_FOREIGN_TABLE)
+				Assert(RELKIND_IS_VALID((RelKind) rte->relkind));
+				switch ((RelKind) rte->relkind)
 				{
-					/* Foreign table */
-					set_foreign_size(root, rel, rte);
-				}
-				else if (rte->relkind == RELKIND_PARTITIONED_TABLE)
-				{
-					/*
-					 * We could get here if asked to scan a partitioned table
-					 * with ONLY.  In that case we shouldn't scan any of the
-					 * partitions, so mark it as a dummy rel.
-					 */
-					set_dummy_rel_pathlist(rel);
-				}
-				else if (rte->tablesample != NULL)
-				{
-					/* Sampled relation */
-					set_tablesample_rel_size(root, rel, rte);
-				}
-				else
-				{
-					/* Plain relation */
-					set_plain_rel_size(root, rel, rte);
+					case RELKIND_FOREIGN_TABLE:
+						/* Foreign table */
+						set_foreign_size(root, rel, rte);
+						break;
+					case RELKIND_PARTITIONED_TABLE:
+
+						/*
+						 * We could get here if asked to scan a partitioned
+						 * table with ONLY.  In that case we shouldn't scan
+						 * any of the partitions, so mark it as a dummy rel.
+						 */
+						set_dummy_rel_pathlist(rel);
+						break;
+					case RELKIND_PARTITIONED_INDEX:
+					case RELKIND_SEQUENCE:
+					case RELKIND_COMPOSITE_TYPE:
+					case RELKIND_INDEX:
+					case RELKIND_MATVIEW:
+					case RELKIND_RELATION:
+					case RELKIND_TOASTVALUE:
+					case RELKIND_VIEW:
+						if (rte->tablesample != NULL)
+						{
+							/* Sampled relation */
+							set_tablesample_rel_size(root, rel, rte);
+						}
+						else
+						{
+							/* Plain relation */
+							set_plain_rel_size(root, rel, rte);
+						}
 				}
 				break;
 			case RTE_SUBQUERY:
@@ -484,20 +495,32 @@ set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 		switch (rel->rtekind)
 		{
 			case RTE_RELATION:
-				if (rte->relkind == RELKIND_FOREIGN_TABLE)
-				{
-					/* Foreign table */
-					set_foreign_pathlist(root, rel, rte);
-				}
-				else if (rte->tablesample != NULL)
+				Assert(RELKIND_IS_VALID((RelKind) rte->relkind));
+				switch ((RelKind) rte->relkind)
 				{
-					/* Sampled relation */
-					set_tablesample_rel_pathlist(root, rel, rte);
-				}
-				else
-				{
-					/* Plain relation */
-					set_plain_rel_pathlist(root, rel, rte);
+					case RELKIND_FOREIGN_TABLE:
+						/* Foreign table */
+						set_foreign_pathlist(root, rel, rte);
+						break;
+					case RELKIND_PARTITIONED_INDEX:
+					case RELKIND_SEQUENCE:
+					case RELKIND_COMPOSITE_TYPE:
+					case RELKIND_INDEX:
+					case RELKIND_MATVIEW:
+					case RELKIND_PARTITIONED_TABLE:
+					case RELKIND_RELATION:
+					case RELKIND_TOASTVALUE:
+					case RELKIND_VIEW:
+						if (rte->tablesample != NULL)
+						{
+							/* Sampled relation */
+							set_tablesample_rel_pathlist(root, rel, rte);
+						}
+						else
+						{
+							/* Plain relation */
+							set_plain_rel_pathlist(root, rel, rte);
+						}
 				}
 				break;
 			case RTE_SUBQUERY:
@@ -643,13 +666,26 @@ set_rel_consider_parallel(PlannerInfo *root, RelOptInfo *rel,
 			 * up with a separate connection, and these connections might not
 			 * be appropriately coordinated between workers and the leader.
 			 */
-			if (rte->relkind == RELKIND_FOREIGN_TABLE)
+			Assert(RELKIND_IS_VALID((RelKind) rte->relkind));
+			switch ((RelKind) rte->relkind)
 			{
-				Assert(rel->fdwroutine);
-				if (!rel->fdwroutine->IsForeignScanParallelSafe)
-					return;
-				if (!rel->fdwroutine->IsForeignScanParallelSafe(root, rel, rte))
-					return;
+				case RELKIND_FOREIGN_TABLE:
+					Assert(rel->fdwroutine);
+					if (!rel->fdwroutine->IsForeignScanParallelSafe)
+						return;
+					if (!rel->fdwroutine->IsForeignScanParallelSafe(root, rel, rte))
+						return;
+					break;
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_VIEW:
+				case RELKIND_SEQUENCE:
+				case RELKIND_TOASTVALUE:
+					break;
 			}
 
 			/*
@@ -962,20 +998,57 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
 	 * the indexes of partitioned relations that appear down in the tree, so
 	 * that when we've created Paths for all the children, the root
 	 * partitioned table's list will contain all such indexes.
+	 *
+	 * Beware that rte->relkind here may be NULL, which is not a valid member
+	 * of enum RelKind.
 	 */
-	if (rte->relkind == RELKIND_PARTITIONED_TABLE)
-		rel->partitioned_child_rels = list_make1_int(rti);
+	Assert(rte->relkind == '\0' || RELKIND_IS_VALID((RelKind) rte->relkind));
+	switch ((RelKind) rte->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			rel->partitioned_child_rels = list_make1_int(rti);
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
+	}
 
 	/*
 	 * If this is a partitioned baserel, set the consider_partitionwise_join
 	 * flag; currently, we only consider partitionwise joins with the baserel
 	 * if its targetlist doesn't contain a whole-row Var.
+	 *
+	 * Beware that rte->relkind here may be NULL, which is not a valid member
+	 * of enum RelKind.
 	 */
-	if (enable_partitionwise_join &&
-		rel->reloptkind == RELOPT_BASEREL &&
-		rte->relkind == RELKIND_PARTITIONED_TABLE &&
-		rel->attr_needed[InvalidAttrNumber - rel->min_attr] == NULL)
-		rel->consider_partitionwise_join = true;
+	Assert(rte->relkind == '\0' || RELKIND_IS_VALID((RelKind) rte->relkind));
+	switch ((RelKind) rte->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			if (enable_partitionwise_join &&
+				rel->reloptkind == RELOPT_BASEREL &&
+				rte->relkind == RELKIND_PARTITIONED_TABLE &&
+				rel->attr_needed[InvalidAttrNumber - rel->min_attr] == NULL)
+				rel->consider_partitionwise_join = true;
+			break;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
+	}
 
 	/*
 	 * Initialize to compute size estimates for whole append relation.
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index b406d41e91..e23edcc739 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -1280,10 +1280,23 @@ inheritance_planner(PlannerInfo *root)
 	 */
 	parent_rte = rt_fetch(top_parentRTindex, parse->rtable);
 	Assert(parent_rte->inh);
-	if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+	Assert(RELKIND_IS_VALID((RelKind) parent_rte->relkind));
+	switch ((RelKind) parent_rte->relkind)
 	{
-		nominalRelation = top_parentRTindex;
-		rootRelation = top_parentRTindex;
+		case RELKIND_PARTITIONED_TABLE:
+			nominalRelation = top_parentRTindex;
+			rootRelation = top_parentRTindex;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
 	}
 
 	/*
@@ -2338,11 +2351,23 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
 			 * If target is a partition root table, we need to mark the
 			 * ModifyTable node appropriately for that.
 			 */
-			if (rt_fetch(parse->resultRelation, parse->rtable)->relkind ==
-				RELKIND_PARTITIONED_TABLE)
-				rootRelation = parse->resultRelation;
-			else
-				rootRelation = 0;
+			Assert(RELKIND_IS_VALID((RelKind) rt_fetch(parse->resultRelation, parse->rtable)->relkind));
+			switch ((RelKind) rt_fetch(parse->resultRelation, parse->rtable)->relkind)
+			{
+				case RELKIND_PARTITIONED_TABLE:
+					rootRelation = parse->resultRelation;
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+					rootRelation = 0;
+			}
 
 			/*
 			 * Set up the WITH CHECK OPTION and RETURNING lists-of-lists, if
@@ -2765,44 +2790,58 @@ select_rowmark_type(RangeTblEntry *rte, LockClauseStrength strength)
 		/* If it's not a table at all, use ROW_MARK_COPY */
 		return ROW_MARK_COPY;
 	}
-	else if (rte->relkind == RELKIND_FOREIGN_TABLE)
-	{
-		/* Let the FDW select the rowmark type, if it wants to */
-		FdwRoutine *fdwroutine = GetFdwRoutineByRelId(rte->relid);
-
-		if (fdwroutine->GetForeignRowMarkType != NULL)
-			return fdwroutine->GetForeignRowMarkType(rte, strength);
-		/* Otherwise, use ROW_MARK_COPY by default */
-		return ROW_MARK_COPY;
-	}
 	else
 	{
-		/* Regular table, apply the appropriate lock type */
-		switch (strength)
+		Assert(RELKIND_IS_VALID((RelKind) rte->relkind));
+		switch ((RelKind) rte->relkind)
 		{
-			case LCS_NONE:
+			case RELKIND_FOREIGN_TABLE:
+				{
+					/* Let the FDW select the rowmark type, if it wants to */
+					FdwRoutine *fdwroutine = GetFdwRoutineByRelId(rte->relid);
 
-				/*
-				 * We don't need a tuple lock, only the ability to re-fetch
-				 * the row.
-				 */
-				return ROW_MARK_REFERENCE;
-				break;
-			case LCS_FORKEYSHARE:
-				return ROW_MARK_KEYSHARE;
-				break;
-			case LCS_FORSHARE:
-				return ROW_MARK_SHARE;
-				break;
-			case LCS_FORNOKEYUPDATE:
-				return ROW_MARK_NOKEYEXCLUSIVE;
-				break;
-			case LCS_FORUPDATE:
-				return ROW_MARK_EXCLUSIVE;
+					if (fdwroutine->GetForeignRowMarkType != NULL)
+						return fdwroutine->GetForeignRowMarkType(rte, strength);
+					/* Otherwise, use ROW_MARK_COPY by default */
+					return ROW_MARK_COPY;
+				}
 				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				/* Regular table, apply the appropriate lock type */
+				switch (strength)
+				{
+					case LCS_NONE:
+
+						/*
+						 * We don't need a tuple lock, only the ability to
+						 * re-fetch the row.
+						 */
+						return ROW_MARK_REFERENCE;
+						break;
+					case LCS_FORKEYSHARE:
+						return ROW_MARK_KEYSHARE;
+						break;
+					case LCS_FORSHARE:
+						return ROW_MARK_SHARE;
+						break;
+					case LCS_FORNOKEYUPDATE:
+						return ROW_MARK_NOKEYEXCLUSIVE;
+						break;
+					case LCS_FORUPDATE:
+						return ROW_MARK_EXCLUSIVE;
+						break;
+				}
+				elog(ERROR, "unrecognized LockClauseStrength %d", (int) strength);
+				return ROW_MARK_EXCLUSIVE;	/* keep compiler quiet */
 		}
-		elog(ERROR, "unrecognized LockClauseStrength %d", (int) strength);
-		return ROW_MARK_EXCLUSIVE;	/* keep compiler quiet */
 	}
 }
 
@@ -3142,8 +3181,23 @@ remove_useless_groupby_columns(PlannerInfo *root)
 		 * may cause duplicate rows.  This cannot happen with partitioned
 		 * tables, however.
 		 */
-		if (rte->inh && rte->relkind != RELKIND_PARTITIONED_TABLE)
-			continue;
+		Assert(RELKIND_IS_VALID((RelKind) rte->relkind));
+		switch ((RelKind) rte->relkind)
+		{
+			case RELKIND_PARTITIONED_TABLE:
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+				if (rte->inh)
+					continue;
+		}
 
 		/* Nothing to do unless this rel has multiple Vars in GROUP BY */
 		relattnos = groupbyattnos[relid];
diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c
index 3132fd35a5..5045927bec 100644
--- a/src/backend/optimizer/util/inherit.c
+++ b/src/backend/optimizer/util/inherit.c
@@ -129,88 +129,111 @@ expand_inherited_rtentry(PlannerInfo *root, RelOptInfo *rel,
 	}
 
 	/* Scan the inheritance set and expand it */
-	if (oldrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	Assert(RELKIND_IS_VALID((RelKind) oldrelation->rd_rel->relkind));
+	switch ((RelKind) oldrelation->rd_rel->relkind)
 	{
-		/*
-		 * Partitioned table, so set up for partitioning.
-		 */
-		Assert(rte->relkind == RELKIND_PARTITIONED_TABLE);
-
-		/*
-		 * Recursively expand and lock the partitions.  While at it, also
-		 * extract the partition key columns of all the partitioned tables.
-		 */
-		expand_partitioned_rtentry(root, rel, rte, rti,
-								   oldrelation, oldrc, lockmode);
-	}
-	else
-	{
-		/*
-		 * Ordinary table, so process traditional-inheritance children.  (Note
-		 * that partitioned tables are not allowed to have inheritance
-		 * children, so it's not possible for both cases to apply.)
-		 */
-		List	   *inhOIDs;
-		ListCell   *l;
-
-		/* Scan for all members of inheritance set, acquire needed locks */
-		inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
-
-		/*
-		 * We used to special-case the situation where the table no longer has
-		 * any children, by clearing rte->inh and exiting.  That no longer
-		 * works, because this function doesn't get run until after decisions
-		 * have been made that depend on rte->inh.  We have to treat such
-		 * situations as normal inheritance.  The table itself should always
-		 * have been found, though.
-		 */
-		Assert(inhOIDs != NIL);
-		Assert(linitial_oid(inhOIDs) == parentOID);
-
-		/* Expand simple_rel_array and friends to hold child objects. */
-		expand_planner_arrays(root, list_length(inhOIDs));
-
-		/*
-		 * Expand inheritance children in the order the OIDs were returned by
-		 * find_all_inheritors.
-		 */
-		foreach(l, inhOIDs)
-		{
-			Oid			childOID = lfirst_oid(l);
-			Relation	newrelation;
-			RangeTblEntry *childrte;
-			Index		childRTindex;
-
-			/* Open rel if needed; we already have required locks */
-			if (childOID != parentOID)
-				newrelation = table_open(childOID, NoLock);
-			else
-				newrelation = oldrelation;
-
-			/*
-			 * It is possible that the parent table has children that are temp
-			 * tables of other backends.  We cannot safely access such tables
-			 * (because of buffering issues), and the best thing to do seems
-			 * to be to silently ignore them.
-			 */
-			if (childOID != parentOID && RELATION_IS_OTHER_TEMP(newrelation))
+		case RELKIND_PARTITIONED_TABLE:
 			{
-				table_close(newrelation, lockmode);
-				continue;
+				/*
+				 * Partitioned table, so set up for partitioning.
+				 */
+				Assert(rte->relkind == RELKIND_PARTITIONED_TABLE);
+
+				/*
+				 * Recursively expand and lock the partitions.  While at it,
+				 * also extract the partition key columns of all the
+				 * partitioned tables.
+				 */
+				expand_partitioned_rtentry(root, rel, rte, rti,
+										   oldrelation, oldrc, lockmode);
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			{
+				/*
+				 * Ordinary table, so process traditional-inheritance
+				 * children.  (Note that partitioned tables are not allowed to
+				 * have inheritance children, so it's not possible for both
+				 * cases to apply.)
+				 */
+				List	   *inhOIDs;
+				ListCell   *l;
+
+				/*
+				 * Scan for all members of inheritance set, acquire needed
+				 * locks
+				 */
+				inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
+
+				/*
+				 * We used to special-case the situation where the table no
+				 * longer has any children, by clearing rte->inh and exiting.
+				 * That no longer works, because this function doesn't get run
+				 * until after decisions have been made that depend on
+				 * rte->inh.  We have to treat such situations as normal
+				 * inheritance.  The table itself should always have been
+				 * found, though.
+				 */
+				Assert(inhOIDs != NIL);
+				Assert(linitial_oid(inhOIDs) == parentOID);
+
+				/* Expand simple_rel_array and friends to hold child objects. */
+				expand_planner_arrays(root, list_length(inhOIDs));
+
+				/*
+				 * Expand inheritance children in the order the OIDs were
+				 * returned by find_all_inheritors.
+				 */
+				foreach(l, inhOIDs)
+				{
+					Oid			childOID = lfirst_oid(l);
+					Relation	newrelation;
+					RangeTblEntry *childrte;
+					Index		childRTindex;
+
+					/* Open rel if needed; we already have required locks */
+					if (childOID != parentOID)
+						newrelation = table_open(childOID, NoLock);
+					else
+						newrelation = oldrelation;
+
+					/*
+					 * It is possible that the parent table has children that
+					 * are temp tables of other backends.  We cannot safely
+					 * access such tables (because of buffering issues), and
+					 * the best thing to do seems to be to silently ignore
+					 * them.
+					 */
+					if (childOID != parentOID && RELATION_IS_OTHER_TEMP(newrelation))
+					{
+						table_close(newrelation, lockmode);
+						continue;
+					}
+
+					/*
+					 * Create RTE and AppendRelInfo, plus PlanRowMark if
+					 * needed.
+					 */
+					expand_single_inheritance_child(root, rte, rti, oldrelation,
+													oldrc, newrelation,
+													&childrte, &childRTindex);
+
+					/* Create the otherrel RelOptInfo too. */
+					(void) build_simple_rel(root, childRTindex, rel);
+
+					/* Close child relations, but keep locks */
+					if (childOID != parentOID)
+						table_close(newrelation, NoLock);
+				}
 			}
-
-			/* Create RTE and AppendRelInfo, plus PlanRowMark if needed. */
-			expand_single_inheritance_child(root, rte, rti, oldrelation,
-											oldrc, newrelation,
-											&childrte, &childRTindex);
-
-			/* Create the otherrel RelOptInfo too. */
-			(void) build_simple_rel(root, childRTindex, rel);
-
-			/* Close child relations, but keep locks */
-			if (childOID != parentOID)
-				table_close(newrelation, NoLock);
-		}
 	}
 
 	/*
@@ -380,10 +403,25 @@ expand_partitioned_rtentry(PlannerInfo *root, RelOptInfo *relinfo,
 												childrelinfo->relids);
 
 		/* If this child is itself partitioned, recurse */
-		if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-			expand_partitioned_rtentry(root, childrelinfo,
-									   childrte, childRTindex,
-									   childrel, top_parentrc, lockmode);
+		Assert(RELKIND_IS_VALID((RelKind) childrel->rd_rel->relkind));
+		switch ((RelKind) childrel->rd_rel->relkind)
+		{
+			case RELKIND_PARTITIONED_TABLE:
+				expand_partitioned_rtentry(root, childrelinfo,
+										   childrte, childRTindex,
+										   childrel, top_parentrc, lockmode);
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				break;
+		}
 
 		/* Close child relation, but keep locks */
 		table_close(childrel, NoLock);
@@ -448,13 +486,24 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
 	childrte->relid = childOID;
 	childrte->relkind = childrel->rd_rel->relkind;
 	/* A partitioned child will need to be expanded further. */
-	if (childrte->relkind == RELKIND_PARTITIONED_TABLE)
+	Assert(RELKIND_IS_VALID((RelKind) childrte->relkind));
+	switch ((RelKind) childrte->relkind)
 	{
-		Assert(childOID != parentOID);
-		childrte->inh = true;
+		case RELKIND_PARTITIONED_TABLE:
+			Assert(childOID != parentOID);
+			childrte->inh = true;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			childrte->inh = false;
 	}
-	else
-		childrte->inh = false;
 	childrte->requiredPerms = 0;
 	childrte->securityQuals = NIL;
 
@@ -578,7 +627,23 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
 		 * that the executor ignores them (except their existence means that
 		 * the child tables will be locked using the appropriate mode).
 		 */
-		childrc->isParent = (childrte->relkind == RELKIND_PARTITIONED_TABLE);
+		Assert(RELKIND_IS_VALID((RelKind) childrte->relkind));
+		switch ((RelKind) childrte->relkind)
+		{
+			case RELKIND_PARTITIONED_TABLE:
+				childrc->isParent = true;
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+				childrc->isParent = false;
+		}
 
 		/* Include child's rowmark type in top parent's allMarkTypes */
 		top_parentrc->allMarkTypes |= childrc->allMarkTypes;
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..92a3361401 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -215,10 +215,22 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 			 * Ignore partitioned indexes, since they are not usable for
 			 * queries.
 			 */
-			if (indexRelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
+			Assert(RELKIND_IS_VALID((RelKind) indexRelation->rd_rel->relkind));
+			switch ((RelKind) indexRelation->rd_rel->relkind)
 			{
-				index_close(indexRelation, NoLock);
-				continue;
+				case RELKIND_PARTITIONED_INDEX:
+					index_close(indexRelation, NoLock);
+					continue;
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+					break;
 			}
 
 			/*
@@ -442,15 +454,24 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 	rel->statlist = get_relation_statistics(rel, relation);
 
 	/* Grab foreign-table info using the relcache, while we have it */
-	if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+	Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
-		rel->serverid = GetForeignServerIdByRelId(RelationGetRelid(relation));
-		rel->fdwroutine = GetFdwRoutineForRelation(relation, true);
-	}
-	else
-	{
-		rel->serverid = InvalidOid;
-		rel->fdwroutine = NULL;
+		case RELKIND_FOREIGN_TABLE:
+			rel->serverid = GetForeignServerIdByRelId(RelationGetRelid(relation));
+			rel->fdwroutine = GetFdwRoutineForRelation(relation, true);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			rel->serverid = InvalidOid;
+			rel->fdwroutine = NULL;
 	}
 
 	/* Collect info about relation's foreign keys, if relevant */
@@ -460,8 +481,24 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 	 * Collect info about relation's partitioning scheme, if any. Only
 	 * inheritance parents may be partitioned.
 	 */
-	if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		set_relation_partition_info(root, rel, relation);
+	Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+	switch ((RelKind) relation->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			if (inhparent)
+				set_relation_partition_info(root, rel, relation);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
+	}
 
 	table_close(relation, NoLock);
 
@@ -955,7 +992,8 @@ estimate_rel_size(Relation rel, int32 *attr_widths,
 	BlockNumber relallvisible;
 	double		density;
 
-	switch (rel->rd_rel->relkind)
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_MATVIEW:
@@ -1063,12 +1101,14 @@ estimate_rel_size(Relation rel, int32 *attr_widths,
 			*tuples = rel->rd_rel->reltuples;
 			*allvisfrac = 0;
 			break;
-		default:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_VIEW:
 			/* else it has no disk storage; probably shouldn't get here? */
 			*pages = 0;
 			*tuples = 0;
 			*allvisfrac = 0;
-			break;
 	}
 }
 
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 25abc544fc..9119d71ca0 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -944,37 +944,55 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
 
 	relation = relation_openrv(table_like_clause->relation, AccessShareLock);
 
-	if (relation->rd_rel->relkind != RELKIND_RELATION &&
-		relation->rd_rel->relkind != RELKIND_VIEW &&
-		relation->rd_rel->relkind != RELKIND_MATVIEW &&
-		relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
-		relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
-		relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
-						RelationGetRelationName(relation))));
+	Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+	switch ((RelKind) relation->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_INDEX:
+		case RELKIND_TOASTVALUE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
+							RelationGetRelationName(relation))));
+	}
 
 	cancel_parser_errposition_callback(&pcbstate);
 
 	/*
 	 * Check for privileges
 	 */
-	if (relation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
-	{
-		aclresult = pg_type_aclcheck(relation->rd_rel->reltype, GetUserId(),
-									 ACL_USAGE);
-		if (aclresult != ACLCHECK_OK)
-			aclcheck_error(aclresult, OBJECT_TYPE,
-						   RelationGetRelationName(relation));
-	}
-	else
+	Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
-		aclresult = pg_class_aclcheck(RelationGetRelid(relation), GetUserId(),
-									  ACL_SELECT);
-		if (aclresult != ACLCHECK_OK)
-			aclcheck_error(aclresult, get_relkind_objtype(relation->rd_rel->relkind),
-						   RelationGetRelationName(relation));
+		case RELKIND_COMPOSITE_TYPE:
+			aclresult = pg_type_aclcheck(relation->rd_rel->reltype, GetUserId(),
+										 ACL_USAGE);
+			if (aclresult != ACLCHECK_OK)
+				aclcheck_error(aclresult, OBJECT_TYPE,
+							   RelationGetRelationName(relation));
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			aclresult = pg_class_aclcheck(RelationGetRelid(relation), GetUserId(),
+										  ACL_SELECT);
+			if (aclresult != ACLCHECK_OK)
+				aclcheck_error(aclresult, get_relkind_objtype(relation->rd_rel->relkind),
+							   RelationGetRelationName(relation));
 	}
 
 	tupleDesc = RelationGetDescr(relation);
@@ -2306,13 +2324,25 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
 
 					rel = table_openrv(inh, AccessShareLock);
 					/* check user requested inheritance from valid relkind */
-					if (rel->rd_rel->relkind != RELKIND_RELATION &&
-						rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
-						rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-						ereport(ERROR,
-								(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-								 errmsg("inherited relation \"%s\" is not a table or foreign table",
-										inh->relname)));
+					Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+					switch ((RelKind) rel->rd_rel->relkind)
+					{
+						case RELKIND_RELATION:
+						case RELKIND_FOREIGN_TABLE:
+						case RELKIND_PARTITIONED_TABLE:
+							break;
+						case RELKIND_PARTITIONED_INDEX:
+						case RELKIND_SEQUENCE:
+						case RELKIND_COMPOSITE_TYPE:
+						case RELKIND_INDEX:
+						case RELKIND_MATVIEW:
+						case RELKIND_TOASTVALUE:
+						case RELKIND_VIEW:
+							ereport(ERROR,
+									(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+									 errmsg("inherited relation \"%s\" is not a table or foreign table",
+											inh->relname)));
+					}
 					for (count = 0; count < rel->rd_att->natts; count++)
 					{
 						Form_pg_attribute inhattr = TupleDescAttr(rel->rd_att,
@@ -2448,13 +2478,25 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
 
 					rel = table_openrv(inh, AccessShareLock);
 					/* check user requested inheritance from valid relkind */
-					if (rel->rd_rel->relkind != RELKIND_RELATION &&
-						rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
-						rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-						ereport(ERROR,
-								(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-								 errmsg("inherited relation \"%s\" is not a table or foreign table",
-										inh->relname)));
+					Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+					switch ((RelKind) rel->rd_rel->relkind)
+					{
+						case RELKIND_RELATION:
+						case RELKIND_FOREIGN_TABLE:
+						case RELKIND_PARTITIONED_TABLE:
+							break;
+						case RELKIND_PARTITIONED_INDEX:
+						case RELKIND_SEQUENCE:
+						case RELKIND_COMPOSITE_TYPE:
+						case RELKIND_INDEX:
+						case RELKIND_MATVIEW:
+						case RELKIND_TOASTVALUE:
+						case RELKIND_VIEW:
+							ereport(ERROR,
+									(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+									 errmsg("inherited relation \"%s\" is not a table or foreign table",
+											inh->relname)));
+					}
 					for (count = 0; count < rel->rd_att->natts; count++)
 					{
 						Form_pg_attribute inhattr = TupleDescAttr(rel->rd_att,
@@ -2763,10 +2805,26 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
 	 */
 	rel = table_openrv(stmt->relation, AccessExclusiveLock);
 
-	if (rel->rd_rel->relkind == RELKIND_MATVIEW)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("rules on materialized views are not supported")));
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_MATVIEW:
+			ereport(ERROR,
+					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+					 errmsg("rules on materialized views are not supported")));
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
+	}
+
 
 	/* Set up pstate */
 	pstate = make_parsestate(NULL);
@@ -3097,15 +3155,24 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
 
 	/* Set up CreateStmtContext */
 	cxt.pstate = pstate;
-	if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		cxt.stmtType = "ALTER FOREIGN TABLE";
-		cxt.isforeign = true;
-	}
-	else
-	{
-		cxt.stmtType = "ALTER TABLE";
-		cxt.isforeign = false;
+		case RELKIND_FOREIGN_TABLE:
+			cxt.stmtType = "ALTER FOREIGN TABLE";
+			cxt.isforeign = true;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			cxt.stmtType = "ALTER TABLE";
+			cxt.isforeign = false;
 	}
 	cxt.relation = stmt->relation;
 	cxt.rel = rel;
@@ -3722,7 +3789,8 @@ transformPartitionCmd(CreateStmtContext *cxt, PartitionCmd *cmd)
 {
 	Relation	parentRel = cxt->rel;
 
-	switch (parentRel->rd_rel->relkind)
+	Assert(RELKIND_IS_VALID((RelKind) parentRel->rd_rel->relkind));
+	switch ((RelKind) parentRel->rd_rel->relkind)
 	{
 		case RELKIND_PARTITIONED_TABLE:
 			/* transform the partition bound, if any */
@@ -3757,11 +3825,15 @@ transformPartitionCmd(CreateStmtContext *cxt, PartitionCmd *cmd)
 					 errmsg("index \"%s\" is not partitioned",
 							RelationGetRelationName(parentRel))));
 			break;
-		default:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
 			/* parser shouldn't let this case through */
 			elog(ERROR, "\"%s\" is not a partitioned table or index",
 				 RelationGetRelationName(parentRel));
-			break;
 	}
 }
 
diff --git a/src/backend/partitioning/partbounds.c b/src/backend/partitioning/partbounds.c
index 7553d55987..f6bc2066e3 100644
--- a/src/backend/partitioning/partbounds.c
+++ b/src/backend/partitioning/partbounds.c
@@ -3137,11 +3137,24 @@ check_default_partition_contents(Relation parent, Relation default_rel,
 	 * Scan the default partition and its subpartitions, and check for rows
 	 * that do not satisfy the revised partition constraints.
 	 */
-	if (default_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		all_parts = find_all_inheritors(RelationGetRelid(default_rel),
-										AccessExclusiveLock, NULL);
-	else
-		all_parts = list_make1_oid(RelationGetRelid(default_rel));
+	Assert(RELKIND_IS_VALID((RelKind) default_rel->rd_rel->relkind));
+	switch ((RelKind) default_rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			all_parts = find_all_inheritors(RelationGetRelid(default_rel),
+											AccessExclusiveLock, NULL);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			all_parts = list_make1_oid(RelationGetRelid(default_rel));
+	}
 
 	foreach(lc, all_parts)
 	{
@@ -3196,19 +3209,29 @@ check_default_partition_contents(Relation parent, Relation default_rel,
 		 * Only RELKIND_RELATION relations (i.e. leaf partitions) need to be
 		 * scanned.
 		 */
-		if (part_rel->rd_rel->relkind != RELKIND_RELATION)
+		Assert(RELKIND_IS_VALID((RelKind) part_rel->rd_rel->relkind));
+		switch ((RelKind) part_rel->rd_rel->relkind)
 		{
-			if (part_rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+			case RELKIND_RELATION:
+				break;
+			case RELKIND_FOREIGN_TABLE:
 				ereport(WARNING,
 						(errcode(ERRCODE_CHECK_VIOLATION),
 						 errmsg("skipped scanning foreign table \"%s\" which is a partition of default partition \"%s\"",
 								RelationGetRelationName(part_rel),
 								RelationGetRelationName(default_rel))));
-
-			if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
-				table_close(part_rel, NoLock);
-
-			continue;
+				/* fallthrough */
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				if (RelationGetRelid(default_rel) != RelationGetRelid(part_rel))
+					table_close(part_rel, NoLock);
+				continue;
 		}
 
 		estate = CreateExecutorState();
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 9c7d4b0c60..4fc26fec7f 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -2058,9 +2058,22 @@ do_autovacuum(void)
 		bool		doanalyze;
 		bool		wraparound;
 
-		if (classForm->relkind != RELKIND_RELATION &&
-			classForm->relkind != RELKIND_MATVIEW)
-			continue;
+		Assert(RELKIND_IS_VALID((RelKind) classForm->relkind));
+		switch ((RelKind) classForm->relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_MATVIEW:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				continue;
+		}
 
 		relid = classForm->oid;
 
@@ -2720,9 +2733,23 @@ extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
 	bytea	   *relopts;
 	AutoVacOpts *av;
 
-	Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
-		   ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
-		   ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
+	Assert(RELKIND_IS_VALID((RelKind) ((Form_pg_class) GETSTRUCT(tup))->relkind));
+	switch ((RelKind) ((Form_pg_class) GETSTRUCT(tup))->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_VIEW:
+			Assert(false);
+			break;
+	}
 
 	relopts = extractRelOptions(tup, pg_class_desc, NULL);
 	if (relopts == NULL)
@@ -2800,17 +2827,33 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
 	 * main table reloptions if the toast table itself doesn't have.
 	 */
 	avopts = extract_autovac_opts(classTup, pg_class_desc);
-	if (classForm->relkind == RELKIND_TOASTVALUE &&
-		avopts == NULL && table_toast_map != NULL)
+	Assert(RELKIND_IS_VALID((RelKind) classForm->relkind));
+	switch ((RelKind) classForm->relkind)
 	{
-		av_relation *hentry;
-		bool		found;
+		case RELKIND_TOASTVALUE:
+			if (avopts == NULL && table_toast_map != NULL)
+			{
+				av_relation *hentry;
+				bool		found;
 
-		hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
-		if (found && hentry->ar_hasrelopts)
-			avopts = &hentry->ar_reloptions;
+				hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
+				if (found && hentry->ar_hasrelopts)
+					avopts = &hentry->ar_reloptions;
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+			break;
 	}
 
+
 	/* fetch the pgstat table entry */
 	tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
 										 shared, dbentry);
@@ -2820,8 +2863,23 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
 							  &dovacuum, &doanalyze, &wraparound);
 
 	/* ignore ANALYZE for toast tables */
-	if (classForm->relkind == RELKIND_TOASTVALUE)
-		doanalyze = false;
+	Assert(RELKIND_IS_VALID((RelKind) classForm->relkind));
+	switch ((RelKind) classForm->relkind)
+	{
+		case RELKIND_TOASTVALUE:
+			doanalyze = false;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+			break;
+	}
 
 	/* OK, it needs something done */
 	if (doanalyze || dovacuum)
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 6064384e32..91459a7327 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -414,7 +414,7 @@ perform_base_backup(basebackup_options *opt)
 			if (ti->path == NULL)
 			{
 				struct stat statbuf;
-				bool	sendtblspclinks = true;
+				bool		sendtblspclinks = true;
 
 				/* In the main tar, include the backup_label first... */
 				sendFileWithContent(BACKUP_LABEL_FILE, labelfile->data,
@@ -1777,8 +1777,8 @@ sendFile(const char *readfilename, const char *tarfilename,
 	}
 
 	/*
-	 * Pad to a block boundary, per tar format requirements. (This small
-	 * piece of data is probably not worth throttling, and is not checksummed
+	 * Pad to a block boundary, per tar format requirements. (This small piece
+	 * of data is probably not worth throttling, and is not checksummed
 	 * because it's not actually part of the file.)
 	 */
 	pad = tarPaddingBytesRequired(len);
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index 5251932669..11aed95301 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -1639,8 +1639,22 @@ ReorderBufferCommit(ReorderBuffer *rb, TransactionId xid,
 					 * understand, so it doesn't make sense to handle the few
 					 * cases we do.
 					 */
-					if (relation->rd_rel->relkind == RELKIND_SEQUENCE)
-						goto change_done;
+					Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+					switch ((RelKind) relation->rd_rel->relkind)
+					{
+						case RELKIND_SEQUENCE:
+							goto change_done;
+						case RELKIND_PARTITIONED_INDEX:
+						case RELKIND_COMPOSITE_TYPE:
+						case RELKIND_FOREIGN_TABLE:
+						case RELKIND_INDEX:
+						case RELKIND_MATVIEW:
+						case RELKIND_PARTITIONED_TABLE:
+						case RELKIND_RELATION:
+						case RELKIND_TOASTVALUE:
+						case RELKIND_VIEW:
+							break;
+					}
 
 					/* user-triggered change */
 					if (!IsToastRelation(relation))
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index c27d970589..b6a154270b 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -765,24 +765,35 @@ copy_table(Relation rel)
 
 	/* Start copy on the publisher. */
 	initStringInfo(&cmd);
-	if (lrel.relkind == RELKIND_RELATION)
-		appendStringInfo(&cmd, "COPY %s TO STDOUT",
-						 quote_qualified_identifier(lrel.nspname, lrel.relname));
-	else
+	Assert(RELKIND_IS_VALID((RelKind) lrel.relkind));
+	switch ((RelKind) lrel.relkind)
 	{
-		/*
-		 * For non-tables, we need to do COPY (SELECT ...), but we can't just
-		 * do SELECT * because we need to not copy generated columns.
-		 */
-		appendStringInfo(&cmd, "COPY (SELECT ");
-		for (int i = 0; i < lrel.natts; i++)
-		{
-			appendStringInfoString(&cmd, quote_identifier(lrel.attnames[i]));
-			if (i < lrel.natts - 1)
-				appendStringInfoString(&cmd, ", ");
-		}
-		appendStringInfo(&cmd, " FROM %s) TO STDOUT",
-						 quote_qualified_identifier(lrel.nspname, lrel.relname));
+		case RELKIND_RELATION:
+			appendStringInfo(&cmd, "COPY %s TO STDOUT",
+							 quote_qualified_identifier(lrel.nspname, lrel.relname));
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			/*
+			 * For non-tables, we need to do COPY (SELECT ...), but we can't
+			 * just do SELECT * because we need to not copy generated columns.
+			 */
+			appendStringInfo(&cmd, "COPY (SELECT ");
+			for (int i = 0; i < lrel.natts; i++)
+			{
+				appendStringInfoString(&cmd, quote_identifier(lrel.attnames[i]));
+				if (i < lrel.natts - 1)
+					appendStringInfoString(&cmd, ", ");
+			}
+			appendStringInfo(&cmd, " FROM %s) TO STDOUT",
+							 quote_qualified_identifier(lrel.nspname, lrel.relname));
 	}
 	res = walrcv_exec(wrconn, cmd.data, 0, NULL);
 	pfree(cmd.data);
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index f90a896fc3..ba159a5bde 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -646,12 +646,25 @@ apply_handle_insert(StringInfo s)
 	MemoryContextSwitchTo(oldctx);
 
 	/* For a partitioned table, insert the tuple into a partition. */
-	if (rel->localrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		apply_handle_tuple_routing(estate->es_result_relation_info, estate,
-								   remoteslot, NULL, rel, CMD_INSERT);
-	else
-		apply_handle_insert_internal(estate->es_result_relation_info, estate,
-									 remoteslot);
+	Assert(RELKIND_IS_VALID((RelKind) rel->localrel->rd_rel->relkind));
+	switch ((RelKind) rel->localrel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			apply_handle_tuple_routing(estate->es_result_relation_info, estate,
+									   remoteslot, NULL, rel, CMD_INSERT);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			apply_handle_insert_internal(estate->es_result_relation_info, estate,
+										 remoteslot);
+	}
 
 	PopActiveSnapshot();
 
@@ -781,12 +794,25 @@ apply_handle_update(StringInfo s)
 	MemoryContextSwitchTo(oldctx);
 
 	/* For a partitioned table, apply update to correct partition. */
-	if (rel->localrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		apply_handle_tuple_routing(estate->es_result_relation_info, estate,
-								   remoteslot, &newtup, rel, CMD_UPDATE);
-	else
-		apply_handle_update_internal(estate->es_result_relation_info, estate,
-									 remoteslot, &newtup, rel);
+	Assert(RELKIND_IS_VALID((RelKind) rel->localrel->rd_rel->relkind));
+	switch ((RelKind) rel->localrel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			apply_handle_tuple_routing(estate->es_result_relation_info, estate,
+									   remoteslot, &newtup, rel, CMD_UPDATE);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			apply_handle_update_internal(estate->es_result_relation_info, estate,
+										 remoteslot, &newtup, rel);
+	}
 
 	PopActiveSnapshot();
 
@@ -904,12 +930,25 @@ apply_handle_delete(StringInfo s)
 	MemoryContextSwitchTo(oldctx);
 
 	/* For a partitioned table, apply delete to correct partition. */
-	if (rel->localrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-		apply_handle_tuple_routing(estate->es_result_relation_info, estate,
-								   remoteslot, NULL, rel, CMD_DELETE);
-	else
-		apply_handle_delete_internal(estate->es_result_relation_info, estate,
-									 remoteslot, &rel->remoterel);
+	Assert(RELKIND_IS_VALID((RelKind) rel->localrel->rd_rel->relkind));
+	switch ((RelKind) rel->localrel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			apply_handle_tuple_routing(estate->es_result_relation_info, estate,
+									   remoteslot, NULL, rel, CMD_DELETE);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			apply_handle_delete_internal(estate->es_result_relation_info, estate,
+										 remoteslot, &rel->remoterel);
+	}
 
 	PopActiveSnapshot();
 
@@ -1273,41 +1312,60 @@ apply_handle_truncate(StringInfo s)
 		 * Truncate partitions if we got a message to truncate a partitioned
 		 * table.
 		 */
-		if (rel->localrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		Assert(RELKIND_IS_VALID((RelKind) rel->localrel->rd_rel->relkind));
+		switch ((RelKind) rel->localrel->rd_rel->relkind)
 		{
-			ListCell   *child;
-			List	   *children = find_all_inheritors(rel->localreloid,
-													   RowExclusiveLock,
-													   NULL);
-
-			foreach(child, children)
-			{
-				Oid			childrelid = lfirst_oid(child);
-				Relation	childrel;
-
-				if (list_member_oid(relids, childrelid))
-					continue;
-
-				/* find_all_inheritors already got lock */
-				childrel = table_open(childrelid, NoLock);
-
-				/*
-				 * Ignore temp tables of other backends.  See similar code in
-				 * ExecuteTruncate().
-				 */
-				if (RELATION_IS_OTHER_TEMP(childrel))
+			case RELKIND_PARTITIONED_TABLE:
 				{
-					table_close(childrel, RowExclusiveLock);
-					continue;
-				}
+					ListCell   *child;
+					List	   *children = find_all_inheritors(rel->localreloid,
+															   RowExclusiveLock,
+															   NULL);
 
-				rels = lappend(rels, childrel);
-				part_rels = lappend(part_rels, childrel);
-				relids = lappend_oid(relids, childrelid);
-				/* Log this relation only if needed for logical decoding */
-				if (RelationIsLogicallyLogged(childrel))
-					relids_logged = lappend_oid(relids_logged, childrelid);
-			}
+					foreach(child, children)
+					{
+						Oid			childrelid = lfirst_oid(child);
+						Relation	childrel;
+
+						if (list_member_oid(relids, childrelid))
+							continue;
+
+						/* find_all_inheritors already got lock */
+						childrel = table_open(childrelid, NoLock);
+
+						/*
+						 * Ignore temp tables of other backends.  See similar
+						 * code in ExecuteTruncate().
+						 */
+						if (RELATION_IS_OTHER_TEMP(childrel))
+						{
+							table_close(childrel, RowExclusiveLock);
+							continue;
+						}
+
+						rels = lappend(rels, childrel);
+						part_rels = lappend(part_rels, childrel);
+						relids = lappend_oid(relids, childrelid);
+
+						/*
+						 * Log this relation only if needed for logical
+						 * decoding
+						 */
+						if (RelationIsLogicallyLogged(childrel))
+							relids_logged = lappend_oid(relids_logged, childrelid);
+					}
+				}
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				break;
 		}
 	}
 
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 57bbb6288c..54ae4af52b 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -100,8 +100,8 @@ int			max_replication_slots = 0;	/* the maximum number of replication
 										 * slots */
 
 static ReplicationSlot *SearchNamedReplicationSlot(const char *name);
-static int ReplicationSlotAcquireInternal(ReplicationSlot *slot,
-										  const char *name, SlotAcquireBehavior behavior);
+static int	ReplicationSlotAcquireInternal(ReplicationSlot *slot,
+										   const char *name, SlotAcquireBehavior behavior);
 static void ReplicationSlotDropAcquired(void);
 static void ReplicationSlotDropPtr(ReplicationSlot *slot);
 
@@ -335,7 +335,7 @@ static ReplicationSlot *
 SearchNamedReplicationSlot(const char *name)
 {
 	int			i;
-	ReplicationSlot	*slot = NULL;
+	ReplicationSlot *slot = NULL;
 
 	Assert(LWLockHeldByMeInMode(ReplicationSlotControlLock,
 								LW_SHARED));
@@ -434,8 +434,8 @@ retry:
 
 	/*
 	 * If we found the slot but it's already active in another process, we
-	 * either error out, return the PID of the owning process, or retry
-	 * after a short wait, as caller specified.
+	 * either error out, return the PID of the owning process, or retry after
+	 * a short wait, as caller specified.
 	 */
 	if (active_pid != MyProcPid)
 	{
@@ -454,7 +454,7 @@ retry:
 		goto retry;
 	}
 	else if (behavior == SAB_Block)
-		ConditionVariableCancelSleep();	/* no sleep needed after all */
+		ConditionVariableCancelSleep(); /* no sleep needed after all */
 
 	/* Let everybody know we've modified this slot */
 	ConditionVariableBroadcast(&s->active_cv);
@@ -1143,8 +1143,8 @@ restart:
 		ReplicationSlot *s = &ReplicationSlotCtl->replication_slots[i];
 		XLogRecPtr	restart_lsn = InvalidXLogRecPtr;
 		NameData	slotname;
-		int		wspid;
-		int		last_signaled_pid = 0;
+		int			wspid;
+		int			last_signaled_pid = 0;
 
 		if (!s->in_use)
 			continue;
@@ -1167,20 +1167,20 @@ restart:
 			/*
 			 * Try to mark this slot as used by this process.
 			 *
-			 * Note that ReplicationSlotAcquireInternal(SAB_Inquire)
-			 * should not cancel the prepared condition variable
-			 * if this slot is active in other process. Because in this case
-			 * we have to wait on that CV for the process owning
-			 * the slot to be terminated, later.
+			 * Note that ReplicationSlotAcquireInternal(SAB_Inquire) should
+			 * not cancel the prepared condition variable if this slot is
+			 * active in other process. Because in this case we have to wait
+			 * on that CV for the process owning the slot to be terminated,
+			 * later.
 			 */
 			wspid = ReplicationSlotAcquireInternal(s, NULL, SAB_Inquire);
 
 			/*
-			 * Exit the loop if we successfully acquired the slot or
-			 * the slot was dropped during waiting for the owning process
-			 * to be terminated. For example, the latter case is likely to
-			 * happen when the slot is temporary because it's automatically
-			 * dropped by the termination of the owning process.
+			 * Exit the loop if we successfully acquired the slot or the slot
+			 * was dropped during waiting for the owning process to be
+			 * terminated. For example, the latter case is likely to happen
+			 * when the slot is temporary because it's automatically dropped
+			 * by the termination of the owning process.
 			 */
 			if (wspid <= 0)
 				break;
@@ -1188,13 +1188,13 @@ restart:
 			/*
 			 * Signal to terminate the process that owns the slot.
 			 *
-			 * There is the race condition where other process may own
-			 * the slot after the process using it was terminated and before
-			 * this process owns it. To handle this case, we signal again
-			 * if the PID of the owning process is changed than the last.
+			 * There is the race condition where other process may own the
+			 * slot after the process using it was terminated and before this
+			 * process owns it. To handle this case, we signal again if the
+			 * PID of the owning process is changed than the last.
 			 *
-			 * XXX This logic assumes that the same PID is not reused
-			 * very quickly.
+			 * XXX This logic assumes that the same PID is not reused very
+			 * quickly.
 			 */
 			if (last_signaled_pid != wspid)
 			{
@@ -1211,8 +1211,8 @@ restart:
 		ConditionVariableCancelSleep();
 
 		/*
-		 * Do nothing here and start from scratch if the slot has
-		 * already been dropped.
+		 * Do nothing here and start from scratch if the slot has already been
+		 * dropped.
 		 */
 		if (wspid == -1)
 			goto restart;
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 9989df1107..8de3d902df 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -262,14 +262,25 @@ DefineQueryRewrite(const char *rulename,
 	 * Internal callers can target materialized views, but transformRuleStmt()
 	 * blocks them for users.  Don't mention them in the error message.
 	 */
-	if (event_relation->rd_rel->relkind != RELKIND_RELATION &&
-		event_relation->rd_rel->relkind != RELKIND_MATVIEW &&
-		event_relation->rd_rel->relkind != RELKIND_VIEW &&
-		event_relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table or view",
-						RelationGetRelationName(event_relation))));
+	Assert(RELKIND_IS_VALID((RelKind) event_relation->rd_rel->relkind));
+	switch ((RelKind) event_relation->rd_rel->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_TOASTVALUE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table or view",
+							RelationGetRelationName(event_relation))));
+	}
 
 	if (!allowSystemTableMods && IsSystemRelation(event_relation))
 		ereport(ERROR,
@@ -421,69 +432,81 @@ DefineQueryRewrite(const char *rulename,
 		 * views is just a kluge to allow dump/reload of views that
 		 * participate in circular dependencies.)
 		 */
-		if (event_relation->rd_rel->relkind != RELKIND_VIEW &&
-			event_relation->rd_rel->relkind != RELKIND_MATVIEW)
+		Assert(RELKIND_IS_VALID((RelKind) event_relation->rd_rel->relkind));
+		switch ((RelKind) event_relation->rd_rel->relkind)
 		{
-			TableScanDesc scanDesc;
-			Snapshot	snapshot;
-			TupleTableSlot *slot;
-
-			if (event_relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+			case RELKIND_VIEW:
+			case RELKIND_MATVIEW:
+				break;
+			case RELKIND_PARTITIONED_TABLE:
 				ereport(ERROR,
 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 						 errmsg("cannot convert partitioned table \"%s\" to a view",
 								RelationGetRelationName(event_relation))));
-
-			if (event_relation->rd_rel->relispartition)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("cannot convert partition \"%s\" to a view",
-								RelationGetRelationName(event_relation))));
-
-			snapshot = RegisterSnapshot(GetLatestSnapshot());
-			scanDesc = table_beginscan(event_relation, snapshot, 0, NULL);
-			slot = table_slot_create(event_relation, NULL);
-			if (table_scan_getnextslot(scanDesc, ForwardScanDirection, slot))
-				ereport(ERROR,
-						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-						 errmsg("could not convert table \"%s\" to a view because it is not empty",
-								RelationGetRelationName(event_relation))));
-			ExecDropSingleTupleTableSlot(slot);
-			table_endscan(scanDesc);
-			UnregisterSnapshot(snapshot);
-
-			if (event_relation->rd_rel->relhastriggers)
-				ereport(ERROR,
-						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-						 errmsg("could not convert table \"%s\" to a view because it has triggers",
-								RelationGetRelationName(event_relation)),
-						 errhint("In particular, the table cannot be involved in any foreign key relationships.")));
-
-			if (event_relation->rd_rel->relhasindex)
-				ereport(ERROR,
-						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-						 errmsg("could not convert table \"%s\" to a view because it has indexes",
-								RelationGetRelationName(event_relation))));
-
-			if (event_relation->rd_rel->relhassubclass)
-				ereport(ERROR,
-						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-						 errmsg("could not convert table \"%s\" to a view because it has child tables",
-								RelationGetRelationName(event_relation))));
-
-			if (event_relation->rd_rel->relrowsecurity)
-				ereport(ERROR,
-						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-						 errmsg("could not convert table \"%s\" to a view because it has row security enabled",
-								RelationGetRelationName(event_relation))));
-
-			if (relation_has_policies(event_relation))
-				ereport(ERROR,
-						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-						 errmsg("could not convert table \"%s\" to a view because it has row security policies",
-								RelationGetRelationName(event_relation))));
-
-			RelisBecomingView = true;
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+				{
+					TableScanDesc scanDesc;
+					Snapshot	snapshot;
+					TupleTableSlot *slot;
+
+					if (event_relation->rd_rel->relispartition)
+						ereport(ERROR,
+								(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+								 errmsg("cannot convert partition \"%s\" to a view",
+										RelationGetRelationName(event_relation))));
+
+					snapshot = RegisterSnapshot(GetLatestSnapshot());
+					scanDesc = table_beginscan(event_relation, snapshot, 0, NULL);
+					slot = table_slot_create(event_relation, NULL);
+					if (table_scan_getnextslot(scanDesc, ForwardScanDirection, slot))
+						ereport(ERROR,
+								(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+								 errmsg("could not convert table \"%s\" to a view because it is not empty",
+										RelationGetRelationName(event_relation))));
+					ExecDropSingleTupleTableSlot(slot);
+					table_endscan(scanDesc);
+					UnregisterSnapshot(snapshot);
+
+					if (event_relation->rd_rel->relhastriggers)
+						ereport(ERROR,
+								(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+								 errmsg("could not convert table \"%s\" to a view because it has triggers",
+										RelationGetRelationName(event_relation)),
+								 errhint("In particular, the table cannot be involved in any foreign key relationships.")));
+
+					if (event_relation->rd_rel->relhasindex)
+						ereport(ERROR,
+								(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+								 errmsg("could not convert table \"%s\" to a view because it has indexes",
+										RelationGetRelationName(event_relation))));
+
+					if (event_relation->rd_rel->relhassubclass)
+						ereport(ERROR,
+								(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+								 errmsg("could not convert table \"%s\" to a view because it has child tables",
+										RelationGetRelationName(event_relation))));
+
+					if (event_relation->rd_rel->relrowsecurity)
+						ereport(ERROR,
+								(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+								 errmsg("could not convert table \"%s\" to a view because it has row security enabled",
+										RelationGetRelationName(event_relation))));
+
+					if (relation_has_policies(event_relation))
+						ereport(ERROR,
+								(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+								 errmsg("could not convert table \"%s\" to a view because it has row security policies",
+										RelationGetRelationName(event_relation))));
+
+					RelisBecomingView = true;
+				}
 		}
 	}
 	else
@@ -920,12 +943,24 @@ RangeVarCallbackForRenameRule(const RangeVar *rv, Oid relid, Oid oldrelid,
 	form = (Form_pg_class) GETSTRUCT(tuple);
 
 	/* only tables and views can have rules */
-	if (form->relkind != RELKIND_RELATION &&
-		form->relkind != RELKIND_VIEW &&
-		form->relkind != RELKIND_PARTITIONED_TABLE)
-		ereport(ERROR,
-				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-				 errmsg("\"%s\" is not a table or view", rv->relname)));
+	Assert(RELKIND_IS_VALID((RelKind) form->relkind));
+	switch ((RelKind) form->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+			ereport(ERROR,
+					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+					 errmsg("\"%s\" is not a table or view", rv->relname)));
+	}
 
 	if (!allowSystemTableMods && IsSystemClass(relid, form))
 		ereport(ERROR,
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index fe777c3103..11053907be 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -902,25 +902,41 @@ rewriteTargetListIU(List *targetList,
 		 * For an UPDATE on a trigger-updatable view, provide a dummy entry
 		 * whenever there is no explicit assignment.
 		 */
-		if (new_tle == NULL && commandType == CMD_UPDATE &&
-			target_relation->rd_rel->relkind == RELKIND_VIEW &&
-			view_has_instead_trigger(target_relation, CMD_UPDATE))
+		Assert(RELKIND_IS_VALID((RelKind) target_relation->rd_rel->relkind));
+		switch ((RelKind) target_relation->rd_rel->relkind)
 		{
-			Node	   *new_expr;
-
-			new_expr = (Node *) makeVar(result_rti,
-										attrno,
-										att_tup->atttypid,
-										att_tup->atttypmod,
-										att_tup->attcollation,
-										0);
+			case RELKIND_VIEW:
+				if (new_tle == NULL && commandType == CMD_UPDATE &&
+					view_has_instead_trigger(target_relation, CMD_UPDATE))
+				{
+					Node	   *new_expr;
 
-			new_tle = makeTargetEntry((Expr *) new_expr,
-									  attrno,
-									  pstrdup(NameStr(att_tup->attname)),
-									  false);
+					new_expr = (Node *) makeVar(result_rti,
+												attrno,
+												att_tup->atttypid,
+												att_tup->atttypmod,
+												att_tup->attcollation,
+												0);
+
+					new_tle = makeTargetEntry((Expr *) new_expr,
+											  attrno,
+											  pstrdup(NameStr(att_tup->attname)),
+											  false);
+				}
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+				break;
 		}
 
+
 		if (new_tle)
 			new_tlist = lappend(new_tlist, new_tle);
 	}
@@ -1316,39 +1332,53 @@ rewriteValuesRTE(Query *parsetree, RangeTblEntry *rte, int rti,
 	 * skip this check in that case --- it isn't an auto-updatable view.
 	 */
 	isAutoUpdatableView = false;
-	if (!force_nulls &&
-		target_relation->rd_rel->relkind == RELKIND_VIEW &&
-		!view_has_instead_trigger(target_relation, CMD_INSERT))
+	Assert(RELKIND_IS_VALID((RelKind) target_relation->rd_rel->relkind));
+	switch ((RelKind) target_relation->rd_rel->relkind)
 	{
-		List	   *locks;
-		bool		hasUpdate;
-		bool		found;
-		ListCell   *l;
+		case RELKIND_VIEW:
+			if (!force_nulls && !view_has_instead_trigger(target_relation, CMD_INSERT))
+			{
+				List	   *locks;
+				bool		hasUpdate;
+				bool		found;
+				ListCell   *l;
 
-		/* Look for an unconditional DO INSTEAD rule */
-		locks = matchLocks(CMD_INSERT, target_relation->rd_rules,
-						   parsetree->resultRelation, parsetree, &hasUpdate);
+				/* Look for an unconditional DO INSTEAD rule */
+				locks = matchLocks(CMD_INSERT, target_relation->rd_rules,
+								   parsetree->resultRelation, parsetree, &hasUpdate);
 
-		found = false;
-		foreach(l, locks)
-		{
-			RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
+				found = false;
+				foreach(l, locks)
+				{
+					RewriteRule *rule_lock = (RewriteRule *) lfirst(l);
 
-			if (rule_lock->isInstead &&
-				rule_lock->qual == NULL)
-			{
-				found = true;
-				break;
-			}
-		}
+					if (rule_lock->isInstead &&
+						rule_lock->qual == NULL)
+					{
+						found = true;
+						break;
+					}
+				}
 
-		/*
-		 * If we didn't find an unconditional DO INSTEAD rule, assume that the
-		 * view is auto-updatable.  If it isn't, rewriteTargetView() will
-		 * throw an error.
-		 */
-		if (!found)
-			isAutoUpdatableView = true;
+				/*
+				 * If we didn't find an unconditional DO INSTEAD rule, assume
+				 * that the view is auto-updatable.  If it isn't,
+				 * rewriteTargetView() will throw an error.
+				 */
+				if (!found)
+					isAutoUpdatableView = true;
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+			break;
 	}
 
 	newValues = NIL;
@@ -1450,55 +1480,71 @@ rewriteTargetListUD(Query *parsetree, RangeTblEntry *target_rte,
 	const char *attrname;
 	TargetEntry *tle;
 
-	if (target_relation->rd_rel->relkind == RELKIND_RELATION ||
-		target_relation->rd_rel->relkind == RELKIND_MATVIEW ||
-		target_relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-	{
-		/*
-		 * Emit CTID so that executor can find the row to update or delete.
-		 */
-		var = makeVar(parsetree->resultRelation,
-					  SelfItemPointerAttributeNumber,
-					  TIDOID,
-					  -1,
-					  InvalidOid,
-					  0);
-
-		attrname = "ctid";
-	}
-	else if (target_relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+	Assert(RELKIND_IS_VALID((RelKind) target_relation->rd_rel->relkind));
+	switch ((RelKind) target_relation->rd_rel->relkind)
 	{
-		/*
-		 * Let the foreign table's FDW add whatever junk TLEs it wants.
-		 */
-		FdwRoutine *fdwroutine;
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+			{
+				/*
+				 * Emit CTID so that executor can find the row to update or
+				 * delete.
+				 */
+				var = makeVar(parsetree->resultRelation,
+							  SelfItemPointerAttributeNumber,
+							  TIDOID,
+							  -1,
+							  InvalidOid,
+							  0);
+
+				attrname = "ctid";
+			}
+			break;
+		case RELKIND_FOREIGN_TABLE:
+			{
+				/*
+				 * Let the foreign table's FDW add whatever junk TLEs it
+				 * wants.
+				 */
+				FdwRoutine *fdwroutine;
 
-		fdwroutine = GetFdwRoutineForRelation(target_relation, false);
+				fdwroutine = GetFdwRoutineForRelation(target_relation, false);
 
-		if (fdwroutine->AddForeignUpdateTargets != NULL)
-			fdwroutine->AddForeignUpdateTargets(parsetree, target_rte,
-												target_relation);
+				if (fdwroutine->AddForeignUpdateTargets != NULL)
+					fdwroutine->AddForeignUpdateTargets(parsetree, target_rte,
+														target_relation);
 
-		/*
-		 * If we have a row-level trigger corresponding to the operation, emit
-		 * a whole-row Var so that executor will have the "old" row to pass to
-		 * the trigger.  Alas, this misses system columns.
-		 */
-		if (target_relation->trigdesc &&
-			((parsetree->commandType == CMD_UPDATE &&
-			  (target_relation->trigdesc->trig_update_after_row ||
-			   target_relation->trigdesc->trig_update_before_row)) ||
-			 (parsetree->commandType == CMD_DELETE &&
-			  (target_relation->trigdesc->trig_delete_after_row ||
-			   target_relation->trigdesc->trig_delete_before_row))))
-		{
-			var = makeWholeRowVar(target_rte,
-								  parsetree->resultRelation,
-								  0,
-								  false);
+				/*
+				 * If we have a row-level trigger corresponding to the
+				 * operation, emit a whole-row Var so that executor will have
+				 * the "old" row to pass to the trigger.  Alas, this misses
+				 * system columns.
+				 */
+				if (target_relation->trigdesc &&
+					((parsetree->commandType == CMD_UPDATE &&
+					  (target_relation->trigdesc->trig_update_after_row ||
+					   target_relation->trigdesc->trig_update_before_row)) ||
+					 (parsetree->commandType == CMD_DELETE &&
+					  (target_relation->trigdesc->trig_delete_after_row ||
+					   target_relation->trigdesc->trig_delete_before_row))))
+				{
+					var = makeWholeRowVar(target_rte,
+										  parsetree->resultRelation,
+										  0,
+										  false);
 
-			attrname = "wholerow";
-		}
+					attrname = "wholerow";
+				}
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
 	}
 
 	if (var != NULL)
@@ -1909,8 +1955,22 @@ fireRIRrules(Query *parsetree, List *activeRIRs)
 		 * In that case this test would need to be postponed till after we've
 		 * opened the rel, so that we could check its state.
 		 */
-		if (rte->relkind == RELKIND_MATVIEW)
-			continue;
+		Assert(RELKIND_IS_VALID((RelKind) rte->relkind));
+		switch ((RelKind) rte->relkind)
+		{
+			case RELKIND_MATVIEW:
+				continue;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				break;
+		}
 
 		/*
 		 * In INSERT ... ON CONFLICT, ignore the EXCLUDED pseudo-relation;
@@ -2032,10 +2092,24 @@ fireRIRrules(Query *parsetree, List *activeRIRs)
 		++rt_index;
 
 		/* Only normal relations can have RLS policies */
-		if (rte->rtekind != RTE_RELATION ||
-			(rte->relkind != RELKIND_RELATION &&
-			 rte->relkind != RELKIND_PARTITIONED_TABLE))
+		if (rte->rtekind != RTE_RELATION)
 			continue;
+		Assert(RELKIND_IS_VALID((RelKind) rte->relkind));
+		switch ((RelKind) rte->relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_PARTITIONED_TABLE:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				continue;
+		}
 
 		rel = table_open(rte->relid, NoLock);
 
@@ -2417,6 +2491,7 @@ view_query_is_auto_updatable(Query *viewquery, bool check_cols)
 {
 	RangeTblRef *rtr;
 	RangeTblEntry *base_rte;
+	bool		updatable;
 
 	/*----------
 	 * Check if the view is simply updatable.  According to SQL-92 this means:
@@ -2498,11 +2573,31 @@ view_query_is_auto_updatable(Query *viewquery, bool check_cols)
 		return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
 
 	base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
-	if (base_rte->rtekind != RTE_RELATION ||
-		(base_rte->relkind != RELKIND_RELATION &&
-		 base_rte->relkind != RELKIND_FOREIGN_TABLE &&
-		 base_rte->relkind != RELKIND_VIEW &&
-		 base_rte->relkind != RELKIND_PARTITIONED_TABLE))
+
+	/*
+	 * Beware that base_rte->relkind here may be NULL, which is not a valid member
+	 * of enum RelKind.
+	 */
+	updatable = false;
+	Assert(base_rte->relkind == '\0' || RELKIND_IS_VALID((RelKind) base_rte->relkind));
+	switch ((RelKind) base_rte->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+		case RELKIND_PARTITIONED_TABLE:
+			if (base_rte->rtekind == RTE_RELATION)
+				updatable = true;
+			/* fallthrough */
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+			break;
+	}
+	if (!updatable)
 		return gettext_noop("Views that do not select from a single table or view are not automatically updatable.");
 
 	if (base_rte->tablesample)
@@ -2677,11 +2772,22 @@ relation_is_updatable(Oid reloid,
 	}
 
 	/* If the relation is a table, it is always updatable */
-	if (rel->rd_rel->relkind == RELKIND_RELATION ||
-		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		relation_close(rel, AccessShareLock);
-		return ALL_EVENTS;
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			relation_close(rel, AccessShareLock);
+			return ALL_EVENTS;
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_VIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
 	}
 
 	/* Look for unconditional DO INSTEAD rules, and note supported events */
@@ -2730,84 +2836,102 @@ relation_is_updatable(Oid reloid,
 		}
 	}
 
-	/* If this is a foreign table, check which update events it supports */
-	if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
 	{
-		FdwRoutine *fdwroutine = GetFdwRoutineForRelation(rel, false);
-
-		if (fdwroutine->IsForeignRelUpdatable != NULL)
-			events |= fdwroutine->IsForeignRelUpdatable(rel);
-		else
-		{
-			/* Assume presence of executor functions is sufficient */
-			if (fdwroutine->ExecForeignInsert != NULL)
-				events |= (1 << CMD_INSERT);
-			if (fdwroutine->ExecForeignUpdate != NULL)
-				events |= (1 << CMD_UPDATE);
-			if (fdwroutine->ExecForeignDelete != NULL)
-				events |= (1 << CMD_DELETE);
-		}
+			/*
+			 * If this is a foreign table, check which update events it
+			 * supports
+			 */
+		case RELKIND_FOREIGN_TABLE:
+			{
+				FdwRoutine *fdwroutine = GetFdwRoutineForRelation(rel, false);
 
-		relation_close(rel, AccessShareLock);
-		return events;
-	}
+				if (fdwroutine->IsForeignRelUpdatable != NULL)
+					events |= fdwroutine->IsForeignRelUpdatable(rel);
+				else
+				{
+					/* Assume presence of executor functions is sufficient */
+					if (fdwroutine->ExecForeignInsert != NULL)
+						events |= (1 << CMD_INSERT);
+					if (fdwroutine->ExecForeignUpdate != NULL)
+						events |= (1 << CMD_UPDATE);
+					if (fdwroutine->ExecForeignDelete != NULL)
+						events |= (1 << CMD_DELETE);
+				}
 
-	/* Check if this is an automatically updatable view */
-	if (rel->rd_rel->relkind == RELKIND_VIEW)
-	{
-		Query	   *viewquery = get_view_query(rel);
+				relation_close(rel, AccessShareLock);
+				return events;
+			}
+			break;
+			/* Check if this is an automatically updatable view */
+		case RELKIND_VIEW:
+			{
+				Query	   *viewquery = get_view_query(rel);
 
-		if (view_query_is_auto_updatable(viewquery, false) == NULL)
-		{
-			Bitmapset  *updatable_cols;
-			int			auto_events;
-			RangeTblRef *rtr;
-			RangeTblEntry *base_rte;
-			Oid			baseoid;
+				if (view_query_is_auto_updatable(viewquery, false) == NULL)
+				{
+					Bitmapset  *updatable_cols;
+					int			auto_events;
+					RangeTblRef *rtr;
+					RangeTblEntry *base_rte;
+					Oid			baseoid;
 
-			/*
-			 * Determine which of the view's columns are updatable. If there
-			 * are none within the set of columns we are looking at, then the
-			 * view doesn't support INSERT/UPDATE, but it may still support
-			 * DELETE.
-			 */
-			view_cols_are_auto_updatable(viewquery, NULL,
-										 &updatable_cols, NULL);
+					/*
+					 * Determine which of the view's columns are updatable. If
+					 * there are none within the set of columns we are looking
+					 * at, then the view doesn't support INSERT/UPDATE, but it
+					 * may still support DELETE.
+					 */
+					view_cols_are_auto_updatable(viewquery, NULL,
+												 &updatable_cols, NULL);
 
-			if (include_cols != NULL)
-				updatable_cols = bms_int_members(updatable_cols, include_cols);
+					if (include_cols != NULL)
+						updatable_cols = bms_int_members(updatable_cols, include_cols);
 
-			if (bms_is_empty(updatable_cols))
-				auto_events = (1 << CMD_DELETE);	/* May support DELETE */
-			else
-				auto_events = ALL_EVENTS;	/* May support all events */
+					if (bms_is_empty(updatable_cols))
+						auto_events = (1 << CMD_DELETE);	/* May support DELETE */
+					else
+						auto_events = ALL_EVENTS;	/* May support all events */
 
-			/*
-			 * The base relation must also support these update commands.
-			 * Tables are always updatable, but for any other kind of base
-			 * relation we must do a recursive check limited to the columns
-			 * referenced by the locally updatable columns in this view.
-			 */
-			rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
-			base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
-			Assert(base_rte->rtekind == RTE_RELATION);
+					/*
+					 * The base relation must also support these update
+					 * commands. Tables are always updatable, but for any
+					 * other kind of base relation we must do a recursive
+					 * check limited to the columns referenced by the locally
+					 * updatable columns in this view.
+					 */
+					rtr = (RangeTblRef *) linitial(viewquery->jointree->fromlist);
+					base_rte = rt_fetch(rtr->rtindex, viewquery->rtable);
+					Assert(base_rte->rtekind == RTE_RELATION);
 
-			if (base_rte->relkind != RELKIND_RELATION &&
-				base_rte->relkind != RELKIND_PARTITIONED_TABLE)
-			{
-				baseoid = base_rte->relid;
-				outer_reloids = lappend_oid(outer_reloids,
-											RelationGetRelid(rel));
-				include_cols = adjust_view_column_set(updatable_cols,
-													  viewquery->targetList);
-				auto_events &= relation_is_updatable(baseoid,
-													 outer_reloids,
-													 include_triggers,
-													 include_cols);
-				outer_reloids = list_delete_last(outer_reloids);
+					if (base_rte->relkind != RELKIND_RELATION &&
+						base_rte->relkind != RELKIND_PARTITIONED_TABLE)
+					{
+						baseoid = base_rte->relid;
+						outer_reloids = lappend_oid(outer_reloids,
+													RelationGetRelid(rel));
+						include_cols = adjust_view_column_set(updatable_cols,
+															  viewquery->targetList);
+						auto_events &= relation_is_updatable(baseoid,
+															 outer_reloids,
+															 include_triggers,
+															 include_cols);
+						outer_reloids = list_delete_last(outer_reloids);
+					}
+					events |= auto_events;
+				}
 			}
-			events |= auto_events;
-		}
+			break;
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+			break;
 	}
 
 	/* If we reach here, the relation may support some update commands */
diff --git a/src/backend/rewrite/rowsecurity.c b/src/backend/rewrite/rowsecurity.c
index 0fe2f9ca83..34e439cd83 100644
--- a/src/backend/rewrite/rowsecurity.c
+++ b/src/backend/rewrite/rowsecurity.c
@@ -123,9 +123,22 @@ get_row_security_policies(Query *root, RangeTblEntry *rte, int rt_index,
 	*hasSubLinks = false;
 
 	/* If this is not a normal relation, just return immediately */
-	if (rte->relkind != RELKIND_RELATION &&
-		rte->relkind != RELKIND_PARTITIONED_TABLE)
-		return;
+	Assert(RELKIND_IS_VALID((RelKind) rte->relkind));
+	switch ((RelKind) rte->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			return;
+	}
 
 	/* Switch to checkAsUser if it's set */
 	user_id = rte->checkAsUser ? rte->checkAsUser : GetUserId();
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 29c920800a..2f3053389e 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -2819,7 +2819,8 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln)
 BlockNumber
 RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum)
 {
-	switch (relation->rd_rel->relkind)
+	Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
 		case RELKIND_SEQUENCE:
 		case RELKIND_INDEX:
@@ -2846,13 +2847,16 @@ RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum)
 				return (szbytes + (BLCKSZ - 1)) / BLCKSZ;
 			}
 		case RELKIND_VIEW:
+			elog(FATAL, "RELKIND_VIEW in RelationGetNumberOfBlocksInFork");
 		case RELKIND_COMPOSITE_TYPE:
+			elog(FATAL, "RELKIND_COMPOSITE_TYPE in RelationGetNumberOfBlocksInFork");
 		case RELKIND_FOREIGN_TABLE:
+			elog(FATAL, "RELKIND_FOREIGN_TABLE in RelationGetNumberOfBlocksInFork");
 		case RELKIND_PARTITIONED_TABLE:
-		default:
-			Assert(false);
-			break;
+			elog(FATAL, "RELKIND_PARTITIONED_TABLE in RelationGetNumberOfBlocksInFork");
 	}
+	elog(FATAL, "Unexpected relkind %d in RelationGetNumberOfBlocksInFork",
+		 (int) relation->rd_rel->relkind);
 
 	return 0;					/* keep compiler quiet */
 }
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index e57fcd2538..615670ff41 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -1236,8 +1236,8 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
 	/*
 	 * Set timer so we can wake up after awhile and check for a deadlock. If a
 	 * deadlock is detected, the handler sets MyProc->waitStatus =
-	 * PROC_WAIT_STATUS_ERROR, allowing us to know that we must report failure rather
-	 * than success.
+	 * PROC_WAIT_STATUS_ERROR, allowing us to know that we must report failure
+	 * rather than success.
 	 *
 	 * By delaying the check until we've waited for a bit, we can avoid
 	 * running the rather expensive deadlock-check code in most cases.
@@ -1302,9 +1302,9 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
 		}
 
 		/*
-		 * waitStatus could change from PROC_WAIT_STATUS_WAITING to something else
-		 * asynchronously.  Read it just once per loop to prevent surprising
-		 * behavior (such as missing log messages).
+		 * waitStatus could change from PROC_WAIT_STATUS_WAITING to something
+		 * else asynchronously.  Read it just once per loop to prevent
+		 * surprising behavior (such as missing log messages).
 		 */
 		myWaitStatus = *((volatile ProcWaitStatus *) &MyProc->waitStatus);
 
@@ -1504,11 +1504,12 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
 
 				/*
 				 * Currently, the deadlock checker always kicks its own
-				 * process, which means that we'll only see PROC_WAIT_STATUS_ERROR when
-				 * deadlock_state == DS_HARD_DEADLOCK, and there's no need to
-				 * print redundant messages.  But for completeness and
-				 * future-proofing, print a message if it looks like someone
-				 * else kicked us off the lock.
+				 * process, which means that we'll only see
+				 * PROC_WAIT_STATUS_ERROR when deadlock_state ==
+				 * DS_HARD_DEADLOCK, and there's no need to print redundant
+				 * messages.  But for completeness and future-proofing, print
+				 * a message if it looks like someone else kicked us off the
+				 * lock.
 				 */
 				if (deadlock_state != DS_HARD_DEADLOCK)
 					ereport(LOG,
@@ -1737,9 +1738,9 @@ CheckDeadLock(void)
 		 * preserve the flexibility to kill some other transaction than the
 		 * one detecting the deadlock.)
 		 *
-		 * RemoveFromWaitQueue sets MyProc->waitStatus to PROC_WAIT_STATUS_ERROR, so
-		 * ProcSleep will report an error after we return from the signal
-		 * handler.
+		 * RemoveFromWaitQueue sets MyProc->waitStatus to
+		 * PROC_WAIT_STATUS_ERROR, so ProcSleep will report an error after we
+		 * return from the signal handler.
 		 */
 		Assert(MyProc->waitLock != NULL);
 		RemoveFromWaitQueue(MyProc, LockTagHashCode(&(MyProc->waitLock->tag)));
diff --git a/src/backend/storage/lmgr/spin.c b/src/backend/storage/lmgr/spin.c
index 9f7eae9339..6d76b95c27 100644
--- a/src/backend/storage/lmgr/spin.c
+++ b/src/backend/storage/lmgr/spin.c
@@ -37,7 +37,7 @@
 #define NUM_EMULATION_SEMAPHORES (NUM_SPINLOCK_SEMAPHORES + NUM_ATOMICS_SEMAPHORES)
 #else
 #define NUM_EMULATION_SEMAPHORES (NUM_SPINLOCK_SEMAPHORES)
-#endif /* DISABLE_ATOMICS */
+#endif							/* DISABLE_ATOMICS */
 
 PGSemaphore *SpinlockSemaArray;
 
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 9b0c376c8c..d7e93cbacc 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1436,34 +1436,65 @@ ProcessUtilitySlow(ParseState *pstate,
 					 * partitions are something we can put an index on, to
 					 * avoid building some indexes only to fail later.
 					 */
-					if (stmt->relation->inh &&
-						get_rel_relkind(relid) == RELKIND_PARTITIONED_TABLE)
+					Assert(RELKIND_IS_VALID((RelKind) get_rel_relkind(relid)));
+					switch ((RelKind) get_rel_relkind(relid))
 					{
-						ListCell   *lc;
-						List	   *inheritors = NIL;
-
-						inheritors = find_all_inheritors(relid, lockmode, NULL);
-						foreach(lc, inheritors)
-						{
-							char		relkind = get_rel_relkind(lfirst_oid(lc));
-
-							if (relkind != RELKIND_RELATION &&
-								relkind != RELKIND_MATVIEW &&
-								relkind != RELKIND_PARTITIONED_TABLE &&
-								relkind != RELKIND_FOREIGN_TABLE)
-								elog(ERROR, "unexpected relkind \"%c\" on partition \"%s\"",
-									 relkind, stmt->relation->relname);
-
-							if (relkind == RELKIND_FOREIGN_TABLE &&
-								(stmt->unique || stmt->primary))
-								ereport(ERROR,
-										(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-										 errmsg("cannot create unique index on partitioned table \"%s\"",
-												stmt->relation->relname),
-										 errdetail("Table \"%s\" contains partitions that are foreign tables.",
-												   stmt->relation->relname)));
-						}
-						list_free(inheritors);
+						case RELKIND_PARTITIONED_TABLE:
+							if (stmt->relation->inh)
+							{
+								ListCell   *lc;
+								List	   *inheritors = NIL;
+
+								inheritors = find_all_inheritors(relid, lockmode, NULL);
+								foreach(lc, inheritors)
+								{
+									char		relkind = get_rel_relkind(lfirst_oid(lc));
+
+									/*
+									 * Beware that relkind here may be NULL, which is not
+									 * a valid member of enum RelKind.
+									 */
+									Assert(relkind == '\0' ||
+										   RELKIND_IS_VALID((RelKind) relkind));
+									switch ((RelKind) relkind)
+									{
+										case RELKIND_RELATION:
+										case RELKIND_MATVIEW:
+										case RELKIND_PARTITIONED_TABLE:
+											continue;
+										case RELKIND_FOREIGN_TABLE:
+											if (stmt->unique || stmt->primary)
+												ereport(ERROR,
+														(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+														 errmsg("cannot create unique index on partitioned table \"%s\"",
+																stmt->relation->relname),
+														 errdetail("Table \"%s\" contains partitions that are foreign tables.",
+																   stmt->relation->relname)));
+											continue;
+										case RELKIND_PARTITIONED_INDEX:
+										case RELKIND_SEQUENCE:
+										case RELKIND_COMPOSITE_TYPE:
+										case RELKIND_INDEX:
+										case RELKIND_TOASTVALUE:
+										case RELKIND_VIEW:
+											break;
+									}
+									elog(ERROR, "unexpected relkind \"%c\" on partition \"%s\"",
+										 relkind, stmt->relation->relname);
+								}
+								list_free(inheritors);
+							}
+							break;
+						case RELKIND_PARTITIONED_INDEX:
+						case RELKIND_SEQUENCE:
+						case RELKIND_COMPOSITE_TYPE:
+						case RELKIND_FOREIGN_TABLE:
+						case RELKIND_INDEX:
+						case RELKIND_MATVIEW:
+						case RELKIND_RELATION:
+						case RELKIND_TOASTVALUE:
+						case RELKIND_VIEW:
+							break;
 					}
 
 					/* Run parse analysis ... */
diff --git a/src/backend/utils/adt/amutils.c b/src/backend/utils/adt/amutils.c
index 220cd8fc52..50af704c8e 100644
--- a/src/backend/utils/adt/amutils.c
+++ b/src/backend/utils/adt/amutils.c
@@ -175,11 +175,22 @@ indexam_property(FunctionCallInfo fcinfo,
 		if (!HeapTupleIsValid(tuple))
 			PG_RETURN_NULL();
 		rd_rel = (Form_pg_class) GETSTRUCT(tuple);
-		if (rd_rel->relkind != RELKIND_INDEX &&
-			rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
+		Assert(RELKIND_IS_VALID((RelKind) rd_rel->relkind));
+		switch ((RelKind) rd_rel->relkind)
 		{
-			ReleaseSysCache(tuple);
-			PG_RETURN_NULL();
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+				break;
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				ReleaseSysCache(tuple);
+				PG_RETURN_NULL();
 		}
 		amoid = rd_rel->relam;
 		natts = rd_rel->relnatts;
diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c
index 2320c06a9b..9fe10a2f22 100644
--- a/src/backend/utils/adt/dbsize.c
+++ b/src/backend/utils/adt/dbsize.c
@@ -878,7 +878,7 @@ pg_relation_filenode(PG_FUNCTION_ARGS)
 	{
 		if (relform->relfilenode)
 			result = relform->relfilenode;
-		else				/* Consult the relation mapper */
+		else					/* Consult the relation mapper */
 			result = RelationMapOidToFilenode(relid,
 											  relform->relisshared);
 	}
@@ -957,17 +957,17 @@ pg_relation_filepath(PG_FUNCTION_ARGS)
 			rnode.dbNode = MyDatabaseId;
 		if (relform->relfilenode)
 			rnode.relNode = relform->relfilenode;
-		else				/* Consult the relation mapper */
+		else					/* Consult the relation mapper */
 			rnode.relNode = RelationMapOidToFilenode(relid,
 													 relform->relisshared);
 	}
 	else
 	{
-			/* no storage, return NULL */
-			rnode.relNode = InvalidOid;
-			/* some compilers generate warnings without these next two lines */
-			rnode.dbNode = InvalidOid;
-			rnode.spcNode = InvalidOid;
+		/* no storage, return NULL */
+		rnode.relNode = InvalidOid;
+		/* some compilers generate warnings without these next two lines */
+		rnode.dbNode = InvalidOid;
+		rnode.spcNode = InvalidOid;
 	}
 
 	if (!OidIsValid(rnode.relNode))
diff --git a/src/backend/utils/adt/partitionfuncs.c b/src/backend/utils/adt/partitionfuncs.c
index c1120403fd..88432a68df 100644
--- a/src/backend/utils/adt/partitionfuncs.c
+++ b/src/backend/utils/adt/partitionfuncs.c
@@ -45,10 +45,23 @@ check_rel_can_be_partition(Oid relid)
 	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)
-		return false;
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_PARTITIONED_INDEX:
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			if (!relispartition)
+				return false;
+	}
 
 	return true;
 }
@@ -143,8 +156,23 @@ pg_partition_tree(PG_FUNCTION_ARGS)
 			nulls[1] = true;
 
 		/* isleaf */
-		values[2] = BoolGetDatum(relkind != RELKIND_PARTITIONED_TABLE &&
-								 relkind != RELKIND_PARTITIONED_INDEX);
+		Assert(RELKIND_IS_VALID((RelKind) relkind));
+		switch ((RelKind) relkind)
+		{
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_PARTITIONED_INDEX:
+				values[2] = BoolGetDatum(false);
+				break;
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_VIEW:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+				values[2] = BoolGetDatum(true);
+		}
 
 		/* level */
 		if (relid != rootrelid)
diff --git a/src/backend/utils/adt/tid.c b/src/backend/utils/adt/tid.c
index 509a0fdffc..134b2ac817 100644
--- a/src/backend/utils/adt/tid.c
+++ b/src/backend/utils/adt/tid.c
@@ -381,8 +381,22 @@ currtid_byreloid(PG_FUNCTION_ARGS)
 		aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
 					   RelationGetRelationName(rel));
 
-	if (rel->rd_rel->relkind == RELKIND_VIEW)
-		return currtid_for_view(rel, tid);
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_VIEW:
+			return currtid_for_view(rel, tid);
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+			break;
+	}
 
 	if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
 		elog(ERROR, "cannot look at latest visible tid for relation \"%s.%s\"",
@@ -423,8 +437,22 @@ currtid_byrelname(PG_FUNCTION_ARGS)
 		aclcheck_error(aclresult, get_relkind_objtype(rel->rd_rel->relkind),
 					   RelationGetRelationName(rel));
 
-	if (rel->rd_rel->relkind == RELKIND_VIEW)
-		return currtid_for_view(rel, tid);
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_VIEW:
+			return currtid_for_view(rel, tid);
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+			break;
+	}
 
 	if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
 		elog(ERROR, "cannot look at latest visible tid for relation \"%s.%s\"",
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index 4c299057a6..c2711075ef 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -2475,9 +2475,9 @@ schema_get_xml_visible_tables(Oid nspid)
 	initStringInfo(&query);
 	appendStringInfo(&query, "SELECT oid FROM pg_catalog.pg_class"
 					 " WHERE relnamespace = %u AND relkind IN ("
-					 CppAsString2(RELKIND_RELATION) ","
-					 CppAsString2(RELKIND_MATVIEW) ","
-					 CppAsString2(RELKIND_VIEW) ")"
+					 RelKindAsString(RELKIND_RELATION) ","
+					 RelKindAsString(RELKIND_MATVIEW) ","
+					 RelKindAsString(RELKIND_VIEW) ")"
 					 " AND pg_catalog.has_table_privilege (oid, 'SELECT')"
 					 " ORDER BY relname;", nspid);
 
@@ -2507,9 +2507,9 @@ database_get_xml_visible_tables(void)
 	/* At the moment there is no order required here. */
 	return query_to_oid_list("SELECT oid FROM pg_catalog.pg_class"
 							 " WHERE relkind IN ("
-							 CppAsString2(RELKIND_RELATION) ","
-							 CppAsString2(RELKIND_MATVIEW) ","
-							 CppAsString2(RELKIND_VIEW) ")"
+							 RelKindAsString(RELKIND_RELATION) ","
+							 RelKindAsString(RELKIND_MATVIEW) ","
+							 RelKindAsString(RELKIND_VIEW) ")"
 							 " AND pg_catalog.has_table_privilege(pg_class.oid, 'SELECT')"
 							 " AND relnamespace IN (" XML_VISIBLE_SCHEMAS ");");
 }
diff --git a/src/backend/utils/cache/partcache.c b/src/backend/utils/cache/partcache.c
index acf8a44f30..2deeb14a6a 100644
--- a/src/backend/utils/cache/partcache.c
+++ b/src/backend/utils/cache/partcache.c
@@ -53,8 +53,22 @@ static List *generate_partition_qual(Relation rel);
 PartitionKey
 RelationGetPartitionKey(Relation rel)
 {
-	if (rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
-		return NULL;
+	Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+	switch ((RelKind) rel->rd_rel->relkind)
+	{
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			return NULL;
+	}
 
 	if (unlikely(rel->rd_partkey == NULL))
 		RelationBuildPartitionKey(rel);
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index a2453cf1f4..b4515a1a51 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -448,7 +448,8 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple)
 	 * Look up any AM-specific parse function; fall out if relkind should not
 	 * have options.
 	 */
-	switch (relation->rd_rel->relkind)
+	Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_TOASTVALUE:
@@ -461,7 +462,9 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple)
 		case RELKIND_PARTITIONED_INDEX:
 			amoptsfn = relation->rd_indam->amoptions;
 			break;
-		default:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
 			return;
 	}
 
@@ -1182,7 +1185,8 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
 	/*
 	 * initialize access method information
 	 */
-	switch (relation->rd_rel->relkind)
+	Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
 		case RELKIND_INDEX:
 		case RELKIND_PARTITIONED_INDEX:
@@ -1747,38 +1751,51 @@ RelationInitTableAccessMethod(Relation relation)
 	HeapTuple	tuple;
 	Form_pg_am	aform;
 
-	if (relation->rd_rel->relkind == RELKIND_SEQUENCE)
+	Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
-		/*
-		 * Sequences are currently accessed like heap tables, but it doesn't
-		 * seem prudent to show that in the catalog. So just overwrite it
-		 * here.
-		 */
-		relation->rd_amhandler = HEAP_TABLE_AM_HANDLER_OID;
-	}
-	else if (IsCatalogRelation(relation))
-	{
-		/*
-		 * Avoid doing a syscache lookup for catalog tables.
-		 */
-		Assert(relation->rd_rel->relam == HEAP_TABLE_AM_OID);
-		relation->rd_amhandler = HEAP_TABLE_AM_HANDLER_OID;
-	}
-	else
-	{
-		/*
-		 * Look up the table access method, save the OID of its handler
-		 * function.
-		 */
-		Assert(relation->rd_rel->relam != InvalidOid);
-		tuple = SearchSysCache1(AMOID,
-								ObjectIdGetDatum(relation->rd_rel->relam));
-		if (!HeapTupleIsValid(tuple))
-			elog(ERROR, "cache lookup failed for access method %u",
-				 relation->rd_rel->relam);
-		aform = (Form_pg_am) GETSTRUCT(tuple);
-		relation->rd_amhandler = aform->amhandler;
-		ReleaseSysCache(tuple);
+		case RELKIND_SEQUENCE:
+
+			/*
+			 * Sequences are currently accessed like heap tables, but it
+			 * doesn't seem prudent to show that in the catalog. So just
+			 * overwrite it here.
+			 */
+			relation->rd_amhandler = HEAP_TABLE_AM_HANDLER_OID;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			if (IsCatalogRelation(relation))
+			{
+				/*
+				 * Avoid doing a syscache lookup for catalog tables.
+				 */
+				Assert(relation->rd_rel->relam == HEAP_TABLE_AM_OID);
+				relation->rd_amhandler = HEAP_TABLE_AM_HANDLER_OID;
+			}
+			else
+			{
+				/*
+				 * Look up the table access method, save the OID of its
+				 * handler function.
+				 */
+				Assert(relation->rd_rel->relam != InvalidOid);
+				tuple = SearchSysCache1(AMOID,
+										ObjectIdGetDatum(relation->rd_rel->relam));
+				if (!HeapTupleIsValid(tuple))
+					elog(ERROR, "cache lookup failed for access method %u",
+						 relation->rd_rel->relam);
+				aform = (Form_pg_am) GETSTRUCT(tuple);
+				relation->rd_amhandler = aform->amhandler;
+				ReleaseSysCache(tuple);
+			}
 	}
 
 	/*
@@ -2024,11 +2041,23 @@ RelationIdGetRelation(Oid relationId)
 			 * and we don't want to use the full-blown procedure because it's
 			 * a headache for indexes that reload itself depends on.
 			 */
-			if (rd->rd_rel->relkind == RELKIND_INDEX ||
-				rd->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
-				RelationReloadIndexInfo(rd);
-			else
-				RelationClearRelation(rd, true);
+			Assert(RELKIND_IS_VALID((RelKind) rd->rd_rel->relkind));
+			switch ((RelKind) rd->rd_rel->relkind)
+			{
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_INDEX:
+					RelationReloadIndexInfo(rd);
+					break;
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+					RelationClearRelation(rd, true);
+			}
 
 			/*
 			 * Normally entries need to be valid here, but before the relcache
@@ -2285,46 +2314,57 @@ RelationReloadNailed(Relation relation)
 	if (!IsTransactionState() || relation->rd_refcnt <= 1)
 		return;
 
-	if (relation->rd_rel->relkind == RELKIND_INDEX)
+	Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
-		/*
-		 * If it's a nailed-but-not-mapped index, then we need to re-read the
-		 * pg_class row to see if its relfilenode changed.
-		 */
-		RelationReloadIndexInfo(relation);
-	}
-	else
-	{
-		/*
-		 * Reload a non-index entry.  We can't easily do so if relcaches
-		 * aren't yet built, but that's fine because at that stage the
-		 * attributes that need to be current (like relfrozenxid) aren't yet
-		 * accessed.  To ensure the entry will later be revalidated, we leave
-		 * it in invalid state, but allow use (cf. RelationIdGetRelation()).
-		 */
-		if (criticalRelcachesBuilt)
-		{
-			HeapTuple	pg_class_tuple;
-			Form_pg_class relp;
+		case RELKIND_INDEX:
 
 			/*
-			 * NB: Mark the entry as valid before starting to scan, to avoid
-			 * self-recursion when re-building pg_class.
+			 * If it's a nailed-but-not-mapped index, then we need to re-read
+			 * the pg_class row to see if its relfilenode changed.
 			 */
-			relation->rd_isvalid = true;
-
-			pg_class_tuple = ScanPgRelation(RelationGetRelid(relation),
-											true, false);
-			relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
-			memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE);
-			heap_freetuple(pg_class_tuple);
-
+			RelationReloadIndexInfo(relation);
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
 			/*
-			 * Again mark as valid, to protect against concurrently arriving
-			 * invalidations.
+			 * Reload a non-index entry.  We can't easily do so if relcaches
+			 * aren't yet built, but that's fine because at that stage the
+			 * attributes that need to be current (like relfrozenxid) aren't
+			 * yet accessed.  To ensure the entry will later be revalidated,
+			 * we leave it in invalid state, but allow use (cf.
+			 * RelationIdGetRelation()).
 			 */
-			relation->rd_isvalid = true;
-		}
+			if (criticalRelcachesBuilt)
+			{
+				HeapTuple	pg_class_tuple;
+				Form_pg_class relp;
+
+				/*
+				 * NB: Mark the entry as valid before starting to scan, to
+				 * avoid self-recursion when re-building pg_class.
+				 */
+				relation->rd_isvalid = true;
+
+				pg_class_tuple = ScanPgRelation(RelationGetRelid(relation),
+												true, false);
+				relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
+				memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE);
+				heap_freetuple(pg_class_tuple);
+
+				/*
+				 * Again mark as valid, to protect against concurrently
+				 * arriving invalidations.
+				 */
+				relation->rd_isvalid = true;
+			}
 	}
 }
 
@@ -2471,14 +2511,27 @@ RelationClearRelation(Relation relation, bool rebuild)
 	 * re-read the pg_class row to handle possible physical relocation of the
 	 * index, and we check for pg_index updates too.
 	 */
-	if ((relation->rd_rel->relkind == RELKIND_INDEX ||
-		 relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) &&
-		relation->rd_refcnt > 0 &&
-		relation->rd_indexcxt != NULL)
+	Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
-		if (IsTransactionState())
-			RelationReloadIndexInfo(relation);
-		return;
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			if (relation->rd_refcnt > 0 && relation->rd_indexcxt != NULL)
+			{
+				if (IsTransactionState())
+					RelationReloadIndexInfo(relation);
+				return;
+			}
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
 	}
 
 	/*
@@ -3479,10 +3532,23 @@ RelationBuildLocalRelation(const char *relname,
 	}
 
 	/* if it's a materialized view, it's not populated initially */
-	if (relkind == RELKIND_MATVIEW)
-		rel->rd_rel->relispopulated = false;
-	else
-		rel->rd_rel->relispopulated = true;
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_MATVIEW:
+			rel->rd_rel->relispopulated = false;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			rel->rd_rel->relispopulated = true;
+	}
 
 	/* set replica identity -- system catalogs and non-tables don't have one */
 	if (!IsCatalogNamespace(relnamespace) &&
@@ -3522,11 +3588,23 @@ RelationBuildLocalRelation(const char *relname,
 
 	rel->rd_rel->relam = accessmtd;
 
-	if (relkind == RELKIND_RELATION ||
-		relkind == RELKIND_SEQUENCE ||
-		relkind == RELKIND_TOASTVALUE ||
-		relkind == RELKIND_MATVIEW)
-		RelationInitTableAccessMethod(rel);
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_SEQUENCE:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_MATVIEW:
+			RelationInitTableAccessMethod(rel);
+			break;
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_VIEW:
+			break;
+	}
 
 	/*
 	 * Okay to insert into the relcache hash table.
@@ -3619,7 +3697,8 @@ RelationSetNewRelfilenode(Relation relation, char persistence)
 	newrnode = relation->rd_node;
 	newrnode.relNode = newrelfilenode;
 
-	switch (relation->rd_rel->relkind)
+	Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+	switch ((RelKind) relation->rd_rel->relkind)
 	{
 		case RELKIND_INDEX:
 		case RELKIND_SEQUENCE:
@@ -3631,7 +3710,6 @@ RelationSetNewRelfilenode(Relation relation, char persistence)
 				smgrclose(srel);
 			}
 			break;
-
 		case RELKIND_RELATION:
 		case RELKIND_TOASTVALUE:
 		case RELKIND_MATVIEW:
@@ -3639,12 +3717,14 @@ RelationSetNewRelfilenode(Relation relation, char persistence)
 											persistence,
 											&freezeXid, &minmulti);
 			break;
-
-		default:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_VIEW:
 			/* we shouldn't be called for anything else */
 			elog(ERROR, "relation \"%s\" does not have storage",
 				 RelationGetRelationName(relation));
-			break;
 	}
 
 	/*
@@ -3689,11 +3769,23 @@ RelationSetNewRelfilenode(Relation relation, char persistence)
 		classform->relfilenode = newrelfilenode;
 
 		/* relpages etc. never change for sequences */
-		if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
+		Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+		switch ((RelKind) relation->rd_rel->relkind)
 		{
-			classform->relpages = 0;	/* it's empty until further notice */
-			classform->reltuples = 0;
-			classform->relallvisible = 0;
+			case RELKIND_SEQUENCE:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				classform->relpages = 0;	/* it's empty until further notice */
+				classform->reltuples = 0;
+				classform->relallvisible = 0;
 		}
 		classform->relfrozenxid = freezeXid;
 		classform->relminmxid = minmulti;
@@ -4086,16 +4178,28 @@ RelationCacheInitializePhase3(void)
 		}
 
 		/* 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))
+		Assert(RELKIND_IS_VALID((RelKind) relation->rd_rel->relkind));
+		switch ((RelKind) relation->rd_rel->relkind)
 		{
-			RelationInitTableAccessMethod(relation);
-			Assert(relation->rd_tableam != NULL);
+			case RELKIND_RELATION:
+			case RELKIND_SEQUENCE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_MATVIEW:
+				if (relation->rd_tableam == NULL)
+				{
+					RelationInitTableAccessMethod(relation);
+					Assert(relation->rd_tableam != NULL);
 
-			restart = true;
+					restart = true;
+				}
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_VIEW:
+				break;
 		}
 
 		/* Release hold on the relation */
@@ -5864,11 +5968,23 @@ load_relcache_init_file(bool shared)
 				nailed_rels++;
 
 			/* Load table AM data */
-			if (rel->rd_rel->relkind == RELKIND_RELATION ||
-				rel->rd_rel->relkind == RELKIND_SEQUENCE ||
-				rel->rd_rel->relkind == RELKIND_TOASTVALUE ||
-				rel->rd_rel->relkind == RELKIND_MATVIEW)
-				RelationInitTableAccessMethod(rel);
+			Assert(RELKIND_IS_VALID((RelKind) rel->rd_rel->relkind));
+			switch ((RelKind) rel->rd_rel->relkind)
+			{
+				case RELKIND_RELATION:
+				case RELKIND_SEQUENCE:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_MATVIEW:
+					RelationInitTableAccessMethod(rel);
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_VIEW:
+					break;
+			}
 
 			Assert(rel->rd_index == NULL);
 			Assert(rel->rd_indextuple == NULL);
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 786672b1b6..3b0cf8a234 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -1743,12 +1743,12 @@ setup_privileges(FILE *cmdfd)
 		"  SET relacl = (SELECT array_agg(a.acl) FROM "
 		" (SELECT E'=r/\"$POSTGRES_SUPERUSERNAME\"' as acl "
 		"  UNION SELECT unnest(pg_catalog.acldefault("
-		"    CASE WHEN relkind = " CppAsString2(RELKIND_SEQUENCE) " THEN 's' "
+		"    CASE WHEN relkind = " RelKindAsString(RELKIND_SEQUENCE) " THEN 's' "
 		"         ELSE 'r' END::\"char\"," CppAsString2(BOOTSTRAP_SUPERUSERID) "::oid))"
 		" ) as a) "
-		"  WHERE relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-		CppAsString2(RELKIND_VIEW) ", " CppAsString2(RELKIND_MATVIEW) ", "
-		CppAsString2(RELKIND_SEQUENCE) ")"
+		"  WHERE relkind IN (" RelKindAsString(RELKIND_RELATION) ", "
+		RelKindAsString(RELKIND_VIEW) ", " RelKindAsString(RELKIND_MATVIEW) ", "
+		RelKindAsString(RELKIND_SEQUENCE) ")"
 		"  AND relacl IS NULL;\n\n",
 		"GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n\n",
 		"GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n\n",
@@ -1765,9 +1765,9 @@ setup_privileges(FILE *cmdfd)
 		"        pg_class"
 		"    WHERE"
 		"        relacl IS NOT NULL"
-		"        AND relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-		CppAsString2(RELKIND_VIEW) ", " CppAsString2(RELKIND_MATVIEW) ", "
-		CppAsString2(RELKIND_SEQUENCE) ");\n\n",
+		"        AND relkind IN (" RelKindAsString(RELKIND_RELATION) ", "
+		RelKindAsString(RELKIND_VIEW) ", " RelKindAsString(RELKIND_MATVIEW) ", "
+		RelKindAsString(RELKIND_SEQUENCE) ");\n\n",
 		"INSERT INTO pg_init_privs "
 		"  (objoid, classoid, objsubid, initprivs, privtype)"
 		"    SELECT"
@@ -1781,9 +1781,9 @@ setup_privileges(FILE *cmdfd)
 		"        JOIN pg_attribute ON (pg_class.oid = pg_attribute.attrelid)"
 		"    WHERE"
 		"        pg_attribute.attacl IS NOT NULL"
-		"        AND pg_class.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-		CppAsString2(RELKIND_VIEW) ", " CppAsString2(RELKIND_MATVIEW) ", "
-		CppAsString2(RELKIND_SEQUENCE) ");\n\n",
+		"        AND pg_class.relkind IN (" RelKindAsString(RELKIND_RELATION) ", "
+		RelKindAsString(RELKIND_VIEW) ", " RelKindAsString(RELKIND_MATVIEW) ", "
+		RelKindAsString(RELKIND_SEQUENCE) ");\n\n",
 		"INSERT INTO pg_init_privs "
 		"  (objoid, classoid, objsubid, initprivs, privtype)"
 		"    SELECT"
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index 08239dde4f..4aeefcf1a7 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -283,10 +283,22 @@ flagInhTables(Archive *fout, TableInfo *tblinfo, int numTables,
 		bool		mark_parents = true;
 
 		/* Some kinds never have parents */
-		if (tblinfo[i].relkind == RELKIND_SEQUENCE ||
-			tblinfo[i].relkind == RELKIND_VIEW ||
-			tblinfo[i].relkind == RELKIND_MATVIEW)
-			continue;
+		Assert(RELKIND_IS_VALID((RelKind) tblinfo[i].relkind));
+		switch ((RelKind) tblinfo[i].relkind)
+		{
+			case RELKIND_SEQUENCE:
+			case RELKIND_VIEW:
+			case RELKIND_MATVIEW:
+				continue;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+				break;
+		}
 
 		/*
 		 * Normally, we don't bother computing anything for non-target tables,
@@ -449,10 +461,22 @@ flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables)
 		TableInfo **parents;
 
 		/* Some kinds never have parents */
-		if (tbinfo->relkind == RELKIND_SEQUENCE ||
-			tbinfo->relkind == RELKIND_VIEW ||
-			tbinfo->relkind == RELKIND_MATVIEW)
-			continue;
+		Assert(RELKIND_IS_VALID((RelKind) tbinfo->relkind));
+		switch ((RelKind) tbinfo->relkind)
+		{
+			case RELKIND_SEQUENCE:
+			case RELKIND_VIEW:
+			case RELKIND_MATVIEW:
+				continue;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+				break;
+		}
 
 		/* Don't bother computing anything for non-target tables, either */
 		if (!tbinfo->dobj.dump)
diff --git a/src/bin/pg_dump/pg_backup_tar.c b/src/bin/pg_dump/pg_backup_tar.c
index b4f5942959..0b04578b9a 100644
--- a/src/bin/pg_dump/pg_backup_tar.c
+++ b/src/bin/pg_dump/pg_backup_tar.c
@@ -1191,7 +1191,7 @@ _tarPositionTo(ArchiveHandle *AH, const char *filename)
 		/* Header doesn't match, so read to next header */
 		len = th->fileLen;
 		len += tarPaddingBytesRequired(th->fileLen);
-		blks = len / TAR_BLOCK_SIZE;		/* # of tar blocks */
+		blks = len / TAR_BLOCK_SIZE;	/* # of tar blocks */
 
 		for (i = 0; i < blks; i++)
 			_tarReadRaw(AH, &header[0], TAR_BLOCK_SIZE, NULL, ctx->tarFH);
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index e758b5c50a..24011d6e7e 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -2399,17 +2399,34 @@ makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
 		return;
 
 	/* Skip VIEWs (no data to dump) */
-	if (tbinfo->relkind == RELKIND_VIEW)
-		return;
-	/* Skip FOREIGN TABLEs (no data to dump) unless requested explicitly */
-	if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
-		(foreign_servers_include_oids.head == NULL ||
-		 !simple_oid_list_member(&foreign_servers_include_oids,
-								 tbinfo->foreign_server)))
-		return;
-	/* Skip partitioned tables (data in partitions) */
-	if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
-		return;
+	Assert(RELKIND_IS_VALID((RelKind) tbinfo->relkind));
+	switch ((RelKind) tbinfo->relkind)
+	{
+		case RELKIND_VIEW:
+			return;
+
+			/*
+			 * Skip FOREIGN TABLEs (no data to dump) unless requested
+			 * explicitly
+			 */
+		case RELKIND_FOREIGN_TABLE:
+			if (foreign_servers_include_oids.head == NULL ||
+				!simple_oid_list_member(&foreign_servers_include_oids,
+										tbinfo->foreign_server))
+				return;
+			break;
+			/* Skip partitioned tables (data in partitions) */
+		case RELKIND_PARTITIONED_TABLE:
+			return;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+			break;
+	}
 
 	/* Don't dump data in unlogged tables, if so requested */
 	if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
@@ -2424,12 +2441,25 @@ makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo)
 	/* OK, let's dump it */
 	tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
 
-	if (tbinfo->relkind == RELKIND_MATVIEW)
-		tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
-	else if (tbinfo->relkind == RELKIND_SEQUENCE)
-		tdinfo->dobj.objType = DO_SEQUENCE_SET;
-	else
-		tdinfo->dobj.objType = DO_TABLE_DATA;
+	Assert(RELKIND_IS_VALID((RelKind) tbinfo->relkind));
+	switch ((RelKind) tbinfo->relkind)
+	{
+		case RELKIND_MATVIEW:
+			tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
+			break;
+		case RELKIND_SEQUENCE:
+			tdinfo->dobj.objType = DO_SEQUENCE_SET;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			tdinfo->dobj.objType = DO_TABLE_DATA;
+	}
 
 	/*
 	 * Note: use tableoid 0 so that this object won't be mistaken for
@@ -2476,14 +2506,14 @@ buildMatViewRefreshDependencies(Archive *fout)
 						 "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
 						 "FROM pg_depend d1 "
 						 "JOIN pg_class c1 ON c1.oid = d1.objid "
-						 "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
+						 "AND c1.relkind = " RelKindAsString(RELKIND_MATVIEW)
 						 " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
 						 "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
 						 "AND d2.objid = r1.oid "
 						 "AND d2.refobjid <> d1.objid "
 						 "JOIN pg_class c2 ON c2.oid = d2.refobjid "
-						 "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
-						 CppAsString2(RELKIND_VIEW) ") "
+						 "AND c2.relkind IN (" RelKindAsString(RELKIND_MATVIEW) ","
+						 RelKindAsString(RELKIND_VIEW) ") "
 						 "WHERE d1.classid = 'pg_class'::regclass "
 						 "UNION "
 						 "SELECT w.objid, d3.refobjid, c3.relkind "
@@ -2493,12 +2523,12 @@ buildMatViewRefreshDependencies(Archive *fout)
 						 "AND d3.objid = r3.oid "
 						 "AND d3.refobjid <> w.refobjid "
 						 "JOIN pg_class c3 ON c3.oid = d3.refobjid "
-						 "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
-						 CppAsString2(RELKIND_VIEW) ") "
+						 "AND c3.relkind IN (" RelKindAsString(RELKIND_MATVIEW) ","
+						 RelKindAsString(RELKIND_VIEW) ") "
 						 ") "
 						 "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
 						 "FROM w "
-						 "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
+						 "WHERE refrelkind = " RelKindAsString(RELKIND_MATVIEW));
 
 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
@@ -2637,9 +2667,22 @@ guessConstraintInheritance(TableInfo *tblinfo, int numTables)
 		TableInfo  *parent;
 
 		/* Sequences and views never have parents */
-		if (tbinfo->relkind == RELKIND_SEQUENCE ||
-			tbinfo->relkind == RELKIND_VIEW)
-			continue;
+		Assert(RELKIND_IS_VALID((RelKind) tbinfo->relkind));
+		switch ((RelKind) tbinfo->relkind)
+		{
+			case RELKIND_SEQUENCE:
+			case RELKIND_VIEW:
+				continue;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+				break;
+		}
 
 		/* Don't bother computing anything for non-target tables, either */
 		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
@@ -4068,9 +4111,22 @@ getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
 		/*
 		 * Only regular and partitioned tables can be added to publications.
 		 */
-		if (tbinfo->relkind != RELKIND_RELATION &&
-			tbinfo->relkind != RELKIND_PARTITIONED_TABLE)
-			continue;
+		Assert(RELKIND_IS_VALID((RelKind) tbinfo->relkind));
+		switch ((RelKind) tbinfo->relkind)
+		{
+			case RELKIND_RELATION:
+			case RELKIND_PARTITIONED_TABLE:
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				continue;
+		}
 
 		/*
 		 * Ignore publication membership of tables whose definitions are not
@@ -6145,7 +6201,7 @@ getTables(Archive *fout, int *numTables)
 
 		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
 						initracl_subquery, "c.relacl", "c.relowner",
-						"CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
+						"CASE WHEN c.relkind = " RelKindAsString(RELKIND_SEQUENCE)
 						" THEN 's' ELSE 'r' END::\"char\"",
 						dopt->binary_upgrade);
 
@@ -6774,10 +6830,23 @@ getTables(Archive *fout, int *numTables)
 		/*
 		 * Decide whether we want to dump this table.
 		 */
-		if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
-			tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
-		else
-			selectDumpableTable(&tblinfo[i], fout);
+		Assert(RELKIND_IS_VALID((RelKind) tblinfo[i].relkind));
+		switch ((RelKind) tblinfo[i].relkind)
+		{
+			case RELKIND_COMPOSITE_TYPE:
+				tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				selectDumpableTable(&tblinfo[i], fout);
+		}
 
 		/*
 		 * If the table-level and all column-level ACLs for this table are
@@ -6824,16 +6893,30 @@ getTables(Archive *fout, int *numTables)
 		 * We only need to lock the table for certain components; see
 		 * pg_dump.h
 		 */
-		if (tblinfo[i].dobj.dump &&
-			(tblinfo[i].relkind == RELKIND_RELATION ||
-			 tblinfo->relkind == RELKIND_PARTITIONED_TABLE) &&
-			(tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
+		Assert(RELKIND_IS_VALID((RelKind) tblinfo[i].relkind));
+		switch ((RelKind) tblinfo[i].relkind)
 		{
-			resetPQExpBuffer(query);
-			appendPQExpBuffer(query,
-							  "LOCK TABLE %s IN ACCESS SHARE MODE",
-							  fmtQualifiedDumpable(&tblinfo[i]));
-			ExecuteSqlStatement(fout, query->data);
+			case RELKIND_RELATION:
+			case RELKIND_PARTITIONED_TABLE:
+				if (tblinfo[i].dobj.dump &&
+					(tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
+				{
+					resetPQExpBuffer(query);
+					appendPQExpBuffer(query,
+									  "LOCK TABLE %s IN ACCESS SHARE MODE",
+									  fmtQualifiedDumpable(&tblinfo[i]));
+					ExecuteSqlStatement(fout, query->data);
+				}
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				break;
 		}
 
 		/* Emit notice if join for owner failed */
@@ -15719,7 +15802,8 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 		char	   *srvname = NULL;
 		char	   *foreign = "";
 
-		switch (tbinfo->relkind)
+		Assert(RELKIND_IS_VALID((RelKind) tbinfo->relkind));
+		switch ((RelKind) tbinfo->relkind)
 		{
 			case RELKIND_FOREIGN_TABLE:
 				{
@@ -15758,8 +15842,18 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
 			case RELKIND_MATVIEW:
 				reltypename = "MATERIALIZED VIEW";
 				break;
-			default:
+			case RELKIND_RELATION:
+			case RELKIND_PARTITIONED_TABLE:
 				reltypename = "TABLE";
+				break;
+			case RELKIND_SEQUENCE:
+			case RELKIND_VIEW:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_INDEX:
+			case RELKIND_TOASTVALUE:
+				Assert(false);
+				reltypename = "XXX";
 		}
 
 		numParents = tbinfo->numParents;
diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c
index 654e2ec514..d528dba474 100644
--- a/src/bin/pg_dump/pg_dump_sort.c
+++ b/src/bin/pg_dump/pg_dump_sort.c
@@ -801,8 +801,28 @@ repairMatViewBoundaryMultiLoop(DumpableObject *boundaryobj,
 	{
 		TableInfo  *nextinfo = (TableInfo *) nextobj;
 
-		if (nextinfo->relkind == RELKIND_MATVIEW)
-			nextinfo->postponed_def = true;
+		/*
+		 * Beware that relkind here may be NULL, which is not a valid member
+		 * of enum RelKind.
+		 */
+		Assert(nextinfo->relkind == '\0' ||
+			   RELKIND_IS_VALID((RelKind) nextinfo->relkind));
+		switch ((RelKind) nextinfo->relkind)
+		{
+			case RELKIND_MATVIEW:
+				nextinfo->postponed_def = true;
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_TABLE:
+			case RELKIND_RELATION:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				break;
+		}
 	}
 }
 
@@ -928,30 +948,64 @@ repairDependencyLoop(DumpableObject **loop,
 		return;
 	}
 
-	/* View (including matview) and its ON SELECT rule */
-	if (nLoop == 2 &&
-		loop[0]->objType == DO_TABLE &&
-		loop[1]->objType == DO_RULE &&
-		(((TableInfo *) loop[0])->relkind == RELKIND_VIEW ||
-		 ((TableInfo *) loop[0])->relkind == RELKIND_MATVIEW) &&
-		((RuleInfo *) loop[1])->ev_type == '1' &&
-		((RuleInfo *) loop[1])->is_instead &&
-		((RuleInfo *) loop[1])->ruletable == (TableInfo *) loop[0])
+	/*
+	 * Beware that relkind here is not guaranteed to be a valid member
+	 * of enum RelKind.
+	 */
+	switch ((RelKind) ((TableInfo *) loop[0])->relkind)
 	{
-		repairViewRuleLoop(loop[0], loop[1]);
-		return;
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+			/* View (including matview) and its ON SELECT rule */
+			if (nLoop == 2 &&
+				loop[0]->objType == DO_TABLE &&
+				loop[1]->objType == DO_RULE &&
+				((RuleInfo *) loop[1])->ev_type == '1' &&
+				((RuleInfo *) loop[1])->is_instead &&
+				((RuleInfo *) loop[1])->ruletable == (TableInfo *) loop[0])
+			{
+				repairViewRuleLoop(loop[0], loop[1]);
+				return;
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+			break;
 	}
-	if (nLoop == 2 &&
-		loop[1]->objType == DO_TABLE &&
-		loop[0]->objType == DO_RULE &&
-		(((TableInfo *) loop[1])->relkind == RELKIND_VIEW ||
-		 ((TableInfo *) loop[1])->relkind == RELKIND_MATVIEW) &&
-		((RuleInfo *) loop[0])->ev_type == '1' &&
-		((RuleInfo *) loop[0])->is_instead &&
-		((RuleInfo *) loop[0])->ruletable == (TableInfo *) loop[1])
+	/*
+	 * Beware that relkind here is not guaranteed to be a valid member
+	 * of enum RelKind.
+	 */
+	switch ((RelKind) ((TableInfo *) loop[1])->relkind)
 	{
-		repairViewRuleLoop(loop[1], loop[0]);
-		return;
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+			if (nLoop == 2 &&
+				loop[1]->objType == DO_TABLE &&
+				loop[0]->objType == DO_RULE &&
+				((RuleInfo *) loop[0])->ev_type == '1' &&
+				((RuleInfo *) loop[0])->is_instead &&
+				((RuleInfo *) loop[0])->ruletable == (TableInfo *) loop[1])
+			{
+				repairViewRuleLoop(loop[1], loop[0]);
+				return;
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+			break;
 	}
 
 	/* Indirect loop involving view (but not matview) and ON SELECT rule */
@@ -959,20 +1013,38 @@ repairDependencyLoop(DumpableObject **loop,
 	{
 		for (i = 0; i < nLoop; i++)
 		{
-			if (loop[i]->objType == DO_TABLE &&
-				((TableInfo *) loop[i])->relkind == RELKIND_VIEW)
+			/*
+			 * Beware that relkind here is not guaranteed to be a valid member
+			 * of enum RelKind.
+			 */
+			switch ((RelKind) ((TableInfo *) loop[i])->relkind)
 			{
-				for (j = 0; j < nLoop; j++)
-				{
-					if (loop[j]->objType == DO_RULE &&
-						((RuleInfo *) loop[j])->ev_type == '1' &&
-						((RuleInfo *) loop[j])->is_instead &&
-						((RuleInfo *) loop[j])->ruletable == (TableInfo *) loop[i])
+				case RELKIND_VIEW:
+					if (loop[i]->objType == DO_TABLE)
 					{
-						repairViewRuleMultiLoop(loop[i], loop[j]);
-						return;
+						for (j = 0; j < nLoop; j++)
+						{
+							if (loop[j]->objType == DO_RULE &&
+								((RuleInfo *) loop[j])->ev_type == '1' &&
+								((RuleInfo *) loop[j])->is_instead &&
+								((RuleInfo *) loop[j])->ruletable == (TableInfo *) loop[i])
+							{
+								repairViewRuleMultiLoop(loop[i], loop[j]);
+								return;
+							}
+						}
 					}
-				}
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_MATVIEW:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+					break;
 			}
 		}
 	}
@@ -982,20 +1054,38 @@ repairDependencyLoop(DumpableObject **loop,
 	{
 		for (i = 0; i < nLoop; i++)
 		{
-			if (loop[i]->objType == DO_TABLE &&
-				((TableInfo *) loop[i])->relkind == RELKIND_MATVIEW)
+			/*
+			 * Beware that relkind here is not guaranteed to be a valid member
+			 * of enum RelKind.
+			 */
+			switch ((RelKind) ((TableInfo *) loop[i])->relkind)
 			{
-				for (j = 0; j < nLoop; j++)
-				{
-					if (loop[j]->objType == DO_PRE_DATA_BOUNDARY)
+				case RELKIND_MATVIEW:
+					if (loop[i]->objType == DO_TABLE)
 					{
-						DumpableObject *nextobj;
-
-						nextobj = (j < nLoop - 1) ? loop[j + 1] : loop[0];
-						repairMatViewBoundaryMultiLoop(loop[j], nextobj);
-						return;
+						for (j = 0; j < nLoop; j++)
+						{
+							if (loop[j]->objType == DO_PRE_DATA_BOUNDARY)
+							{
+								DumpableObject *nextobj;
+
+								nextobj = (j < nLoop - 1) ? loop[j + 1] : loop[0];
+								repairMatViewBoundaryMultiLoop(loop[j], nextobj);
+								return;
+							}
+						}
 					}
-				}
+					break;
+				case RELKIND_PARTITIONED_INDEX:
+				case RELKIND_SEQUENCE:
+				case RELKIND_COMPOSITE_TYPE:
+				case RELKIND_FOREIGN_TABLE:
+				case RELKIND_INDEX:
+				case RELKIND_PARTITIONED_TABLE:
+				case RELKIND_RELATION:
+				case RELKIND_TOASTVALUE:
+				case RELKIND_VIEW:
+					break;
 			}
 		}
 	}
diff --git a/src/bin/pg_upgrade/info.c b/src/bin/pg_upgrade/info.c
index 7e524ea192..d67da370c5 100644
--- a/src/bin/pg_upgrade/info.c
+++ b/src/bin/pg_upgrade/info.c
@@ -446,8 +446,8 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
 			 "  SELECT c.oid, 0::oid, 0::oid "
 			 "  FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n "
 			 "         ON c.relnamespace = n.oid "
-			 "  WHERE relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-			 CppAsString2(RELKIND_MATVIEW) ") AND "
+			 "  WHERE relkind IN (" RelKindAsString(RELKIND_RELATION) ", "
+			 RelKindAsString(RELKIND_MATVIEW) ") AND "
 	/* exclude possible orphaned temp tables */
 			 "    ((n.nspname !~ '^pg_temp_' AND "
 			 "      n.nspname !~ '^pg_toast_temp_' AND "
diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c
index 70194eb096..996bf8bf70 100644
--- a/src/bin/pg_upgrade/pg_upgrade.c
+++ b/src/bin/pg_upgrade/pg_upgrade.c
@@ -643,9 +643,9 @@ set_frozenxids(bool minmxid_only)
 									  "SET	relfrozenxid = '%u' "
 			/* only heap, materialized view, and TOAST are vacuumed */
 									  "WHERE	relkind IN ("
-									  CppAsString2(RELKIND_RELATION) ", "
-									  CppAsString2(RELKIND_MATVIEW) ", "
-									  CppAsString2(RELKIND_TOASTVALUE) ")",
+									  RelKindAsString(RELKIND_RELATION) ", "
+									  RelKindAsString(RELKIND_MATVIEW) ", "
+									  RelKindAsString(RELKIND_TOASTVALUE) ")",
 									  old_cluster.controldata.chkpnt_nxtxid));
 
 		/* set pg_class.relminmxid */
@@ -654,9 +654,9 @@ set_frozenxids(bool minmxid_only)
 								  "SET	relminmxid = '%u' "
 		/* only heap, materialized view, and TOAST are vacuumed */
 								  "WHERE	relkind IN ("
-								  CppAsString2(RELKIND_RELATION) ", "
-								  CppAsString2(RELKIND_MATVIEW) ", "
-								  CppAsString2(RELKIND_TOASTVALUE) ")",
+								  RelKindAsString(RELKIND_RELATION) ", "
+								  RelKindAsString(RELKIND_MATVIEW) ", "
+								  RelKindAsString(RELKIND_TOASTVALUE) ")",
 								  old_cluster.controldata.chkpnt_nxtmulti));
 		PQfinish(conn);
 
diff --git a/src/bin/pg_upgrade/version.c b/src/bin/pg_upgrade/version.c
index 4e5d27f76e..5fb158c093 100644
--- a/src/bin/pg_upgrade/version.c
+++ b/src/bin/pg_upgrade/version.c
@@ -176,9 +176,9 @@ check_for_data_type_usage(ClusterInfo *cluster, const char *typename,
 						  "		NOT a.attisdropped AND "
 						  "		a.atttypid IN (SELECT oid FROM oids) AND "
 						  "		c.relkind IN ("
-						  CppAsString2(RELKIND_RELATION) ", "
-						  CppAsString2(RELKIND_MATVIEW) ", "
-						  CppAsString2(RELKIND_INDEX) ") AND "
+						  RelKindAsString(RELKIND_RELATION) ", "
+						  RelKindAsString(RELKIND_MATVIEW) ", "
+						  RelKindAsString(RELKIND_INDEX) ") AND "
 						  "		c.relnamespace = n.oid AND "
 		/* exclude possible orphaned temp tables */
 						  "		n.nspname !~ '^pg_temp_' AND "
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 9902a4a2ba..e1d3bca4a0 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -4942,21 +4942,28 @@ get_create_object_cmd(EditableObjectType obj_type, Oid oid,
 					 * does not, so editing a matview definition in this way
 					 * is impossible.
 					 */
-					switch (relkind[0])
+					Assert(RELKIND_IS_VALID((RelKind) relkind[0]));
+					switch ((RelKind) relkind[0])
 					{
-#ifdef NOT_USED
+						case RELKIND_VIEW:
+							appendPQExpBufferStr(buf, "CREATE OR REPLACE VIEW ");
+							break;
 						case RELKIND_MATVIEW:
+#ifdef NOT_USED
 							appendPQExpBufferStr(buf, "CREATE OR REPLACE MATERIALIZED VIEW ");
 							break;
 #endif
-						case RELKIND_VIEW:
-							appendPQExpBufferStr(buf, "CREATE OR REPLACE VIEW ");
-							break;
-						default:
+						case RELKIND_PARTITIONED_INDEX:
+						case RELKIND_SEQUENCE:
+						case RELKIND_COMPOSITE_TYPE:
+						case RELKIND_FOREIGN_TABLE:
+						case RELKIND_INDEX:
+						case RELKIND_PARTITIONED_TABLE:
+						case RELKIND_RELATION:
+						case RELKIND_TOASTVALUE:
 							pg_log_error("\"%s.%s\" is not a view",
 										 nspname, relname);
 							result = false;
-							break;
 					}
 					appendPQExpBuffer(buf, "%s.", fmtId(nspname));
 					appendPQExpBufferStr(buf, fmtId(relname));
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 3b870c3b17..28fcd388f6 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -734,7 +734,7 @@ describeTypes(const char *pattern, bool verbose, bool showSystem)
 	 * composite types
 	 */
 	appendPQExpBufferStr(&buf, "WHERE (t.typrelid = 0 ");
-	appendPQExpBufferStr(&buf, "OR (SELECT c.relkind = " CppAsString2(RELKIND_COMPOSITE_TYPE)
+	appendPQExpBufferStr(&buf, "OR (SELECT c.relkind = " RelKindAsString(RELKIND_COMPOSITE_TYPE)
 						 " FROM pg_catalog.pg_class c "
 						 "WHERE c.oid = t.typrelid))\n");
 
@@ -943,12 +943,12 @@ permissionsList(const char *pattern)
 					  "SELECT n.nspname as \"%s\",\n"
 					  "  c.relname as \"%s\",\n"
 					  "  CASE c.relkind"
-					  " WHEN " CppAsString2(RELKIND_RELATION) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_VIEW) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_MATVIEW) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_SEQUENCE) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_RELATION) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_VIEW) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_MATVIEW) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_SEQUENCE) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_FOREIGN_TABLE) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
 					  " END as \"%s\",\n"
 					  "  ",
 					  gettext_noop("Schema"),
@@ -1040,12 +1040,12 @@ permissionsList(const char *pattern)
 	appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_class c\n"
 						 "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
 						 "WHERE c.relkind IN ("
-						 CppAsString2(RELKIND_RELATION) ","
-						 CppAsString2(RELKIND_VIEW) ","
-						 CppAsString2(RELKIND_MATVIEW) ","
-						 CppAsString2(RELKIND_SEQUENCE) ","
-						 CppAsString2(RELKIND_FOREIGN_TABLE) ","
-						 CppAsString2(RELKIND_PARTITIONED_TABLE) ")\n");
+						 RelKindAsString(RELKIND_RELATION) ","
+						 RelKindAsString(RELKIND_VIEW) ","
+						 RelKindAsString(RELKIND_MATVIEW) ","
+						 RelKindAsString(RELKIND_SEQUENCE) ","
+						 RelKindAsString(RELKIND_FOREIGN_TABLE) ","
+						 RelKindAsString(RELKIND_PARTITIONED_TABLE) ")\n");
 
 	/*
 	 * Unless a schema pattern is specified, we suppress system and temp
@@ -1692,134 +1692,147 @@ describeOneTableDetails(const char *schemaname,
 	/*
 	 * If it's a sequence, deal with it here separately.
 	 */
-	if (tableinfo.relkind == RELKIND_SEQUENCE)
+	Assert(RELKIND_IS_VALID((RelKind) tableinfo.relkind));
+	switch ((RelKind) tableinfo.relkind)
 	{
-		PGresult   *result = NULL;
-		printQueryOpt myopt = pset.popt;
-		char	   *footers[2] = {NULL, NULL};
-
-		if (pset.sversion >= 100000)
-		{
-			printfPQExpBuffer(&buf,
-							  "SELECT pg_catalog.format_type(seqtypid, NULL) AS \"%s\",\n"
-							  "       seqstart AS \"%s\",\n"
-							  "       seqmin AS \"%s\",\n"
-							  "       seqmax AS \"%s\",\n"
-							  "       seqincrement AS \"%s\",\n"
-							  "       CASE WHEN seqcycle THEN '%s' ELSE '%s' END AS \"%s\",\n"
-							  "       seqcache AS \"%s\"\n",
-							  gettext_noop("Type"),
-							  gettext_noop("Start"),
-							  gettext_noop("Minimum"),
-							  gettext_noop("Maximum"),
-							  gettext_noop("Increment"),
-							  gettext_noop("yes"),
-							  gettext_noop("no"),
-							  gettext_noop("Cycles?"),
-							  gettext_noop("Cache"));
-			appendPQExpBuffer(&buf,
-							  "FROM pg_catalog.pg_sequence\n"
-							  "WHERE seqrelid = '%s';",
-							  oid);
-		}
-		else
-		{
-			printfPQExpBuffer(&buf,
-							  "SELECT 'bigint' AS \"%s\",\n"
-							  "       start_value AS \"%s\",\n"
-							  "       min_value AS \"%s\",\n"
-							  "       max_value AS \"%s\",\n"
-							  "       increment_by AS \"%s\",\n"
-							  "       CASE WHEN is_cycled THEN '%s' ELSE '%s' END AS \"%s\",\n"
-							  "       cache_value AS \"%s\"\n",
-							  gettext_noop("Type"),
-							  gettext_noop("Start"),
-							  gettext_noop("Minimum"),
-							  gettext_noop("Maximum"),
-							  gettext_noop("Increment"),
-							  gettext_noop("yes"),
-							  gettext_noop("no"),
-							  gettext_noop("Cycles?"),
-							  gettext_noop("Cache"));
-			appendPQExpBuffer(&buf, "FROM %s", fmtId(schemaname));
-			/* must be separate because fmtId isn't reentrant */
-			appendPQExpBuffer(&buf, ".%s;", fmtId(relationname));
-		}
+		case RELKIND_SEQUENCE:
+			{
+				PGresult   *result = NULL;
+				printQueryOpt myopt = pset.popt;
+				char	   *footers[2] = {NULL, NULL};
 
-		res = PSQLexec(buf.data);
-		if (!res)
-			goto error_return;
+				if (pset.sversion >= 100000)
+				{
+					printfPQExpBuffer(&buf,
+									  "SELECT pg_catalog.format_type(seqtypid, NULL) AS \"%s\",\n"
+									  "       seqstart AS \"%s\",\n"
+									  "       seqmin AS \"%s\",\n"
+									  "       seqmax AS \"%s\",\n"
+									  "       seqincrement AS \"%s\",\n"
+									  "       CASE WHEN seqcycle THEN '%s' ELSE '%s' END AS \"%s\",\n"
+									  "       seqcache AS \"%s\"\n",
+									  gettext_noop("Type"),
+									  gettext_noop("Start"),
+									  gettext_noop("Minimum"),
+									  gettext_noop("Maximum"),
+									  gettext_noop("Increment"),
+									  gettext_noop("yes"),
+									  gettext_noop("no"),
+									  gettext_noop("Cycles?"),
+									  gettext_noop("Cache"));
+					appendPQExpBuffer(&buf,
+									  "FROM pg_catalog.pg_sequence\n"
+									  "WHERE seqrelid = '%s';",
+									  oid);
+				}
+				else
+				{
+					printfPQExpBuffer(&buf,
+									  "SELECT 'bigint' AS \"%s\",\n"
+									  "       start_value AS \"%s\",\n"
+									  "       min_value AS \"%s\",\n"
+									  "       max_value AS \"%s\",\n"
+									  "       increment_by AS \"%s\",\n"
+									  "       CASE WHEN is_cycled THEN '%s' ELSE '%s' END AS \"%s\",\n"
+									  "       cache_value AS \"%s\"\n",
+									  gettext_noop("Type"),
+									  gettext_noop("Start"),
+									  gettext_noop("Minimum"),
+									  gettext_noop("Maximum"),
+									  gettext_noop("Increment"),
+									  gettext_noop("yes"),
+									  gettext_noop("no"),
+									  gettext_noop("Cycles?"),
+									  gettext_noop("Cache"));
+					appendPQExpBuffer(&buf, "FROM %s", fmtId(schemaname));
+					/* must be separate because fmtId isn't reentrant */
+					appendPQExpBuffer(&buf, ".%s;", fmtId(relationname));
+				}
 
-		/* Footer information about a sequence */
+				res = PSQLexec(buf.data);
+				if (!res)
+					goto error_return;
+
+				/* Footer information about a sequence */
+
+				/* Get the column that owns this sequence */
+				printfPQExpBuffer(&buf, "SELECT pg_catalog.quote_ident(nspname) || '.' ||"
+								  "\n   pg_catalog.quote_ident(relname) || '.' ||"
+								  "\n   pg_catalog.quote_ident(attname),"
+								  "\n   d.deptype"
+								  "\nFROM pg_catalog.pg_class c"
+								  "\nINNER JOIN pg_catalog.pg_depend d ON c.oid=d.refobjid"
+								  "\nINNER JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace"
+								  "\nINNER JOIN pg_catalog.pg_attribute a ON ("
+								  "\n a.attrelid=c.oid AND"
+								  "\n a.attnum=d.refobjsubid)"
+								  "\nWHERE d.classid='pg_catalog.pg_class'::pg_catalog.regclass"
+								  "\n AND d.refclassid='pg_catalog.pg_class'::pg_catalog.regclass"
+								  "\n AND d.objid='%s'"
+								  "\n AND d.deptype IN ('a', 'i')",
+								  oid);
 
-		/* Get the column that owns this sequence */
-		printfPQExpBuffer(&buf, "SELECT pg_catalog.quote_ident(nspname) || '.' ||"
-						  "\n   pg_catalog.quote_ident(relname) || '.' ||"
-						  "\n   pg_catalog.quote_ident(attname),"
-						  "\n   d.deptype"
-						  "\nFROM pg_catalog.pg_class c"
-						  "\nINNER JOIN pg_catalog.pg_depend d ON c.oid=d.refobjid"
-						  "\nINNER JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace"
-						  "\nINNER JOIN pg_catalog.pg_attribute a ON ("
-						  "\n a.attrelid=c.oid AND"
-						  "\n a.attnum=d.refobjsubid)"
-						  "\nWHERE d.classid='pg_catalog.pg_class'::pg_catalog.regclass"
-						  "\n AND d.refclassid='pg_catalog.pg_class'::pg_catalog.regclass"
-						  "\n AND d.objid='%s'"
-						  "\n AND d.deptype IN ('a', 'i')",
-						  oid);
+				result = PSQLexec(buf.data);
 
-		result = PSQLexec(buf.data);
+				/*
+				 * If we get no rows back, don't show anything (obviously). We
+				 * should never get more than one row back, but if we do, just
+				 * ignore it and don't print anything.
+				 */
+				if (!result)
+					goto error_return;
+				else if (PQntuples(result) == 1)
+				{
+					switch (PQgetvalue(result, 0, 1)[0])
+					{
+						case 'a':
+							footers[0] = psprintf(_("Owned by: %s"),
+												  PQgetvalue(result, 0, 0));
+							break;
+						case 'i':
+							footers[0] = psprintf(_("Sequence for identity column: %s"),
+												  PQgetvalue(result, 0, 0));
+							break;
+					}
+				}
+				PQclear(result);
 
-		/*
-		 * If we get no rows back, don't show anything (obviously). We should
-		 * never get more than one row back, but if we do, just ignore it and
-		 * don't print anything.
-		 */
-		if (!result)
-			goto error_return;
-		else if (PQntuples(result) == 1)
-		{
-			switch (PQgetvalue(result, 0, 1)[0])
-			{
-				case 'a':
-					footers[0] = psprintf(_("Owned by: %s"),
-										  PQgetvalue(result, 0, 0));
-					break;
-				case 'i':
-					footers[0] = psprintf(_("Sequence for identity column: %s"),
-										  PQgetvalue(result, 0, 0));
-					break;
-			}
-		}
-		PQclear(result);
+				printfPQExpBuffer(&title, _("Sequence \"%s.%s\""),
+								  schemaname, relationname);
 
-		printfPQExpBuffer(&title, _("Sequence \"%s.%s\""),
-						  schemaname, relationname);
+				myopt.footers = footers;
+				myopt.topt.default_footer = false;
+				myopt.title = title.data;
+				myopt.translate_header = true;
 
-		myopt.footers = footers;
-		myopt.topt.default_footer = false;
-		myopt.title = title.data;
-		myopt.translate_header = true;
+				printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
 
-		printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+				if (footers[0])
+					free(footers[0]);
 
-		if (footers[0])
-			free(footers[0]);
+				retval = true;
+				goto error_return;	/* not an error, just return early */
+			}
+			break;
 
-		retval = true;
-		goto error_return;		/* not an error, just return early */
+			/*
+			 * Identify whether we should print collation, nullable, default
+			 * vals
+			 */
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_PARTITIONED_TABLE:
+			show_column_details = true;
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_INDEX:
+		case RELKIND_TOASTVALUE:
+			break;
 	}
 
-	/* Identify whether we should print collation, nullable, default vals */
-	if (tableinfo.relkind == RELKIND_RELATION ||
-		tableinfo.relkind == RELKIND_VIEW ||
-		tableinfo.relkind == RELKIND_MATVIEW ||
-		tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
-		tableinfo.relkind == RELKIND_COMPOSITE_TYPE ||
-		tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
-		show_column_details = true;
-
 	/*
 	 * Get per-column info
 	 *
@@ -1861,58 +1874,88 @@ describeOneTableDetails(const char *schemaname,
 			appendPQExpBufferStr(&buf, ",\n  ''::pg_catalog.char AS attgenerated");
 		attgenerated_col = cols++;
 	}
-	if (tableinfo.relkind == RELKIND_INDEX ||
-		tableinfo.relkind == RELKIND_PARTITIONED_INDEX)
-	{
-		if (pset.sversion >= 110000)
-		{
-			appendPQExpBuffer(&buf, ",\n  CASE WHEN a.attnum <= (SELECT i.indnkeyatts FROM pg_catalog.pg_index i WHERE i.indexrelid = '%s') THEN '%s' ELSE '%s' END AS is_key",
-							  oid,
-							  gettext_noop("yes"),
-							  gettext_noop("no"));
-			isindexkey_col = cols++;
-		}
-		appendPQExpBufferStr(&buf, ",\n  pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE) AS indexdef");
-		indexdef_col = cols++;
-	}
-	/* FDW options for foreign table column, only for 9.2 or later */
-	if (tableinfo.relkind == RELKIND_FOREIGN_TABLE && pset.sversion >= 90200)
+	Assert(RELKIND_IS_VALID((RelKind) tableinfo.relkind));
+	switch ((RelKind) tableinfo.relkind)
 	{
-		appendPQExpBufferStr(&buf, ",\n  CASE WHEN attfdwoptions IS NULL THEN '' ELSE "
-							 "  '(' || pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value)  FROM "
-							 "  pg_catalog.pg_options_to_table(attfdwoptions)), ', ') || ')' END AS attfdwoptions");
-		fdwopts_col = cols++;
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			if (pset.sversion >= 110000)
+			{
+				appendPQExpBuffer(&buf, ",\n  CASE WHEN a.attnum <= (SELECT i.indnkeyatts FROM pg_catalog.pg_index i WHERE i.indexrelid = '%s') THEN '%s' ELSE '%s' END AS is_key",
+								  oid,
+								  gettext_noop("yes"),
+								  gettext_noop("no"));
+				isindexkey_col = cols++;
+			}
+			appendPQExpBufferStr(&buf, ",\n  pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE) AS indexdef");
+			indexdef_col = cols++;
+			break;
+		case RELKIND_FOREIGN_TABLE:
+			/* FDW options for foreign table column, only for 9.2 or later */
+			if (pset.sversion >= 90200)
+			{
+				appendPQExpBufferStr(&buf, ",\n  CASE WHEN attfdwoptions IS NULL THEN '' ELSE "
+									 "  '(' || pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value)  FROM "
+									 "  pg_catalog.pg_options_to_table(attfdwoptions)), ', ') || ')' END AS attfdwoptions");
+				fdwopts_col = cols++;
+			}
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_MATVIEW:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+		case RELKIND_VIEW:
+			break;
 	}
+
 	if (verbose)
 	{
 		appendPQExpBufferStr(&buf, ",\n  a.attstorage");
 		attstorage_col = cols++;
 
 		/* stats target, if relevant to relkind */
-		if (tableinfo.relkind == RELKIND_RELATION ||
-			tableinfo.relkind == RELKIND_INDEX ||
-			tableinfo.relkind == RELKIND_PARTITIONED_INDEX ||
-			tableinfo.relkind == RELKIND_MATVIEW ||
-			tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
-			tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
+		Assert(RELKIND_IS_VALID((RelKind) tableinfo.relkind));
+		switch ((RelKind) tableinfo.relkind)
 		{
-			appendPQExpBufferStr(&buf, ",\n  CASE WHEN a.attstattarget=-1 THEN NULL ELSE a.attstattarget END AS attstattarget");
-			attstattarget_col = cols++;
+			case RELKIND_RELATION:
+			case RELKIND_INDEX:
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_MATVIEW:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_PARTITIONED_TABLE:
+				appendPQExpBufferStr(&buf, ",\n  CASE WHEN a.attstattarget=-1 THEN NULL ELSE a.attstattarget END AS attstattarget");
+				attstattarget_col = cols++;
+				break;
+			case RELKIND_SEQUENCE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_TOASTVALUE:
+			case RELKIND_VIEW:
+				break;
 		}
 
 		/*
 		 * In 9.0+, we have column comments for: relations, views, composite
 		 * types, and foreign tables (cf. CommentObject() in comment.c).
 		 */
-		if (tableinfo.relkind == RELKIND_RELATION ||
-			tableinfo.relkind == RELKIND_VIEW ||
-			tableinfo.relkind == RELKIND_MATVIEW ||
-			tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
-			tableinfo.relkind == RELKIND_COMPOSITE_TYPE ||
-			tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
+		Assert(RELKIND_IS_VALID((RelKind) tableinfo.relkind));
+		switch ((RelKind) tableinfo.relkind)
 		{
-			appendPQExpBufferStr(&buf, ",\n  pg_catalog.col_description(a.attrelid, a.attnum)");
-			attdescr_col = cols++;
+			case RELKIND_RELATION:
+			case RELKIND_VIEW:
+			case RELKIND_MATVIEW:
+			case RELKIND_FOREIGN_TABLE:
+			case RELKIND_COMPOSITE_TYPE:
+			case RELKIND_PARTITIONED_TABLE:
+				appendPQExpBufferStr(&buf, ",\n  pg_catalog.col_description(a.attrelid, a.attnum)");
+				attdescr_col = cols++;
+				break;
+			case RELKIND_PARTITIONED_INDEX:
+			case RELKIND_SEQUENCE:
+			case RELKIND_INDEX:
+			case RELKIND_TOASTVALUE:
+				break;
 		}
 	}
 
@@ -1926,7 +1969,8 @@ describeOneTableDetails(const char *schemaname,
 	numrows = PQntuples(res);
 
 	/* Make title */
-	switch (tableinfo.relkind)
+	Assert(RELKIND_IS_VALID((RelKind) tableinfo.relkind));
+	switch ((RelKind) tableinfo.relkind)
 	{
 		case RELKIND_RELATION:
 			if (tableinfo.relpersistence == 'u')
@@ -1964,11 +2008,6 @@ describeOneTableDetails(const char *schemaname,
 				printfPQExpBuffer(&title, _("Partitioned index \"%s.%s\""),
 								  schemaname, relationname);
 			break;
-		case 's':
-			/* not used as of 8.2, but keep it for backwards compatibility */
-			printfPQExpBuffer(&title, _("Special relation \"%s.%s\""),
-							  schemaname, relationname);
-			break;
 		case RELKIND_TOASTVALUE:
 			printfPQExpBuffer(&title, _("TOAST table \"%s.%s\""),
 							  schemaname, relationname);
@@ -1989,11 +2028,20 @@ describeOneTableDetails(const char *schemaname,
 				printfPQExpBuffer(&title, _("Partitioned table \"%s.%s\""),
 								  schemaname, relationname);
 			break;
-		default:
-			/* untranslated unknown relkind */
-			printfPQExpBuffer(&title, "?%c? \"%s.%s\"",
-							  tableinfo.relkind, schemaname, relationname);
-			break;
+		case RELKIND_SEQUENCE:
+			/*
+			 * 's' is not used as of 8.2, but we keep it for backwards
+			 * compatibility. We cannot handle 's' as a case value without
+			 * adding it to enum RelKind, but that would trigger warnings and
+			 * errors elsewhere.  Handle it here, instead.
+			 */
+			if ((RelKind) tableinfo.relkind == 's')
+				printfPQExpBuffer(&title, _("Special relation \"%s.%s\""),
+								  schemaname, relationname);
+			else
+				/* untranslated unknown relkind */
+				printfPQExpBuffer(&title, "?%c? \"%s.%s\"",
+								  tableinfo.relkind, schemaname, relationname);
 	}
 
 	/* Fill headers[] with the names of the columns we will output */
@@ -2150,742 +2198,803 @@ describeOneTableDetails(const char *schemaname,
 		PQclear(result);
 	}
 
-	if (tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
+	Assert(RELKIND_IS_VALID((RelKind) tableinfo.relkind));
+	switch ((RelKind) tableinfo.relkind)
 	{
-		/* Footer information for a partitioned table (partitioning parent) */
-		PGresult   *result;
-
-		printfPQExpBuffer(&buf,
-						  "SELECT pg_catalog.pg_get_partkeydef('%s'::pg_catalog.oid);",
-						  oid);
-		result = PSQLexec(buf.data);
-		if (!result)
-			goto error_return;
+		case RELKIND_PARTITIONED_TABLE:
+			{
+				/*
+				 * Footer information for a partitioned table (partitioning
+				 * parent)
+				 */
+				PGresult   *result;
 
-		if (PQntuples(result) == 1)
-		{
-			char	   *partkeydef = PQgetvalue(result, 0, 0);
+				printfPQExpBuffer(&buf,
+								  "SELECT pg_catalog.pg_get_partkeydef('%s'::pg_catalog.oid);",
+								  oid);
+				result = PSQLexec(buf.data);
+				if (!result)
+					goto error_return;
 
-			printfPQExpBuffer(&tmpbuf, _("Partition key: %s"), partkeydef);
-			printTableAddFooter(&cont, tmpbuf.data);
-		}
-		PQclear(result);
-	}
+				if (PQntuples(result) == 1)
+				{
+					char	   *partkeydef = PQgetvalue(result, 0, 0);
 
-	if (tableinfo.relkind == RELKIND_TOASTVALUE)
-	{
-		/* For a TOAST table, print name of owning table */
-		PGresult   *result;
+					printfPQExpBuffer(&tmpbuf, _("Partition key: %s"), partkeydef);
+					printTableAddFooter(&cont, tmpbuf.data);
+				}
+				PQclear(result);
+			}
+			break;
 
-		printfPQExpBuffer(&buf,
-						  "SELECT n.nspname, c.relname\n"
-						  "FROM pg_catalog.pg_class c"
-						  " JOIN pg_catalog.pg_namespace n"
-						  " ON n.oid = c.relnamespace\n"
-						  "WHERE reltoastrelid = '%s';", oid);
-		result = PSQLexec(buf.data);
-		if (!result)
-			goto error_return;
+		case RELKIND_TOASTVALUE:
+			{
+				/* For a TOAST table, print name of owning table */
+				PGresult   *result;
 
-		if (PQntuples(result) == 1)
-		{
-			char	   *schemaname = PQgetvalue(result, 0, 0);
-			char	   *relname = PQgetvalue(result, 0, 1);
+				printfPQExpBuffer(&buf,
+								  "SELECT n.nspname, c.relname\n"
+								  "FROM pg_catalog.pg_class c"
+								  " JOIN pg_catalog.pg_namespace n"
+								  " ON n.oid = c.relnamespace\n"
+								  "WHERE reltoastrelid = '%s';", oid);
+				result = PSQLexec(buf.data);
+				if (!result)
+					goto error_return;
+
+				if (PQntuples(result) == 1)
+				{
+					char	   *schemaname = PQgetvalue(result, 0, 0);
+					char	   *relname = PQgetvalue(result, 0, 1);
 
-			printfPQExpBuffer(&tmpbuf, _("Owning table: \"%s.%s\""),
-							  schemaname, relname);
-			printTableAddFooter(&cont, tmpbuf.data);
-		}
-		PQclear(result);
+					printfPQExpBuffer(&tmpbuf, _("Owning table: \"%s.%s\""),
+									  schemaname, relname);
+					printTableAddFooter(&cont, tmpbuf.data);
+				}
+				PQclear(result);
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_MATVIEW:
+		case RELKIND_RELATION:
+		case RELKIND_VIEW:
+			break;
 	}
 
-	if (tableinfo.relkind == RELKIND_INDEX ||
-		tableinfo.relkind == RELKIND_PARTITIONED_INDEX)
+	Assert(RELKIND_IS_VALID((RelKind) tableinfo.relkind));
+	switch ((RelKind) tableinfo.relkind)
 	{
-		/* Footer information about an index */
-		PGresult   *result;
-
-		printfPQExpBuffer(&buf,
-						  "SELECT i.indisunique, i.indisprimary, i.indisclustered, ");
-		if (pset.sversion >= 80200)
-			appendPQExpBufferStr(&buf, "i.indisvalid,\n");
-		else
-			appendPQExpBufferStr(&buf, "true AS indisvalid,\n");
-		if (pset.sversion >= 90000)
-			appendPQExpBufferStr(&buf,
-								 "  (NOT i.indimmediate) AND "
-								 "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
-								 "WHERE conrelid = i.indrelid AND "
-								 "conindid = i.indexrelid AND "
-								 "contype IN ('p','u','x') AND "
-								 "condeferrable) AS condeferrable,\n"
-								 "  (NOT i.indimmediate) AND "
-								 "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
-								 "WHERE conrelid = i.indrelid AND "
-								 "conindid = i.indexrelid AND "
-								 "contype IN ('p','u','x') AND "
-								 "condeferred) AS condeferred,\n");
-		else
-			appendPQExpBufferStr(&buf,
-								 "  false AS condeferrable, false AS condeferred,\n");
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			{
+				/* Footer information about an index */
+				PGresult   *result;
 
-		if (pset.sversion >= 90400)
-			appendPQExpBufferStr(&buf, "i.indisreplident,\n");
-		else
-			appendPQExpBufferStr(&buf, "false AS indisreplident,\n");
+				printfPQExpBuffer(&buf,
+								  "SELECT i.indisunique, i.indisprimary, i.indisclustered, ");
+				if (pset.sversion >= 80200)
+					appendPQExpBufferStr(&buf, "i.indisvalid,\n");
+				else
+					appendPQExpBufferStr(&buf, "true AS indisvalid,\n");
+				if (pset.sversion >= 90000)
+					appendPQExpBufferStr(&buf,
+										 "  (NOT i.indimmediate) AND "
+										 "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
+										 "WHERE conrelid = i.indrelid AND "
+										 "conindid = i.indexrelid AND "
+										 "contype IN ('p','u','x') AND "
+										 "condeferrable) AS condeferrable,\n"
+										 "  (NOT i.indimmediate) AND "
+										 "EXISTS (SELECT 1 FROM pg_catalog.pg_constraint "
+										 "WHERE conrelid = i.indrelid AND "
+										 "conindid = i.indexrelid AND "
+										 "contype IN ('p','u','x') AND "
+										 "condeferred) AS condeferred,\n");
+				else
+					appendPQExpBufferStr(&buf,
+										 "  false AS condeferrable, false AS condeferred,\n");
 
-		appendPQExpBuffer(&buf, "  a.amname, c2.relname, "
-						  "pg_catalog.pg_get_expr(i.indpred, i.indrelid, true)\n"
-						  "FROM pg_catalog.pg_index i, pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_am a\n"
-						  "WHERE i.indexrelid = c.oid AND c.oid = '%s' AND c.relam = a.oid\n"
-						  "AND i.indrelid = c2.oid;",
-						  oid);
+				if (pset.sversion >= 90400)
+					appendPQExpBufferStr(&buf, "i.indisreplident,\n");
+				else
+					appendPQExpBufferStr(&buf, "false AS indisreplident,\n");
 
-		result = PSQLexec(buf.data);
-		if (!result)
-			goto error_return;
-		else if (PQntuples(result) != 1)
-		{
-			PQclear(result);
-			goto error_return;
-		}
-		else
-		{
-			char	   *indisunique = PQgetvalue(result, 0, 0);
-			char	   *indisprimary = PQgetvalue(result, 0, 1);
-			char	   *indisclustered = PQgetvalue(result, 0, 2);
-			char	   *indisvalid = PQgetvalue(result, 0, 3);
-			char	   *deferrable = PQgetvalue(result, 0, 4);
-			char	   *deferred = PQgetvalue(result, 0, 5);
-			char	   *indisreplident = PQgetvalue(result, 0, 6);
-			char	   *indamname = PQgetvalue(result, 0, 7);
-			char	   *indtable = PQgetvalue(result, 0, 8);
-			char	   *indpred = PQgetvalue(result, 0, 9);
-
-			if (strcmp(indisprimary, "t") == 0)
-				printfPQExpBuffer(&tmpbuf, _("primary key, "));
-			else if (strcmp(indisunique, "t") == 0)
-				printfPQExpBuffer(&tmpbuf, _("unique, "));
-			else
-				resetPQExpBuffer(&tmpbuf);
-			appendPQExpBuffer(&tmpbuf, "%s, ", indamname);
+				appendPQExpBuffer(&buf, "  a.amname, c2.relname, "
+								  "pg_catalog.pg_get_expr(i.indpred, i.indrelid, true)\n"
+								  "FROM pg_catalog.pg_index i, pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_am a\n"
+								  "WHERE i.indexrelid = c.oid AND c.oid = '%s' AND c.relam = a.oid\n"
+								  "AND i.indrelid = c2.oid;",
+								  oid);
 
-			/* we assume here that index and table are in same schema */
-			appendPQExpBuffer(&tmpbuf, _("for table \"%s.%s\""),
-							  schemaname, indtable);
+				result = PSQLexec(buf.data);
+				if (!result)
+					goto error_return;
+				else if (PQntuples(result) != 1)
+				{
+					PQclear(result);
+					goto error_return;
+				}
+				else
+				{
+					char	   *indisunique = PQgetvalue(result, 0, 0);
+					char	   *indisprimary = PQgetvalue(result, 0, 1);
+					char	   *indisclustered = PQgetvalue(result, 0, 2);
+					char	   *indisvalid = PQgetvalue(result, 0, 3);
+					char	   *deferrable = PQgetvalue(result, 0, 4);
+					char	   *deferred = PQgetvalue(result, 0, 5);
+					char	   *indisreplident = PQgetvalue(result, 0, 6);
+					char	   *indamname = PQgetvalue(result, 0, 7);
+					char	   *indtable = PQgetvalue(result, 0, 8);
+					char	   *indpred = PQgetvalue(result, 0, 9);
+
+					if (strcmp(indisprimary, "t") == 0)
+						printfPQExpBuffer(&tmpbuf, _("primary key, "));
+					else if (strcmp(indisunique, "t") == 0)
+						printfPQExpBuffer(&tmpbuf, _("unique, "));
+					else
+						resetPQExpBuffer(&tmpbuf);
+					appendPQExpBuffer(&tmpbuf, "%s, ", indamname);
 
-			if (strlen(indpred))
-				appendPQExpBuffer(&tmpbuf, _(", predicate (%s)"), indpred);
+					/* we assume here that index and table are in same schema */
+					appendPQExpBuffer(&tmpbuf, _("for table \"%s.%s\""),
+									  schemaname, indtable);
 
-			if (strcmp(indisclustered, "t") == 0)
-				appendPQExpBufferStr(&tmpbuf, _(", clustered"));
+					if (strlen(indpred))
+						appendPQExpBuffer(&tmpbuf, _(", predicate (%s)"), indpred);
 
-			if (strcmp(indisvalid, "t") != 0)
-				appendPQExpBufferStr(&tmpbuf, _(", invalid"));
+					if (strcmp(indisclustered, "t") == 0)
+						appendPQExpBufferStr(&tmpbuf, _(", clustered"));
 
-			if (strcmp(deferrable, "t") == 0)
-				appendPQExpBufferStr(&tmpbuf, _(", deferrable"));
+					if (strcmp(indisvalid, "t") != 0)
+						appendPQExpBufferStr(&tmpbuf, _(", invalid"));
 
-			if (strcmp(deferred, "t") == 0)
-				appendPQExpBufferStr(&tmpbuf, _(", initially deferred"));
+					if (strcmp(deferrable, "t") == 0)
+						appendPQExpBufferStr(&tmpbuf, _(", deferrable"));
 
-			if (strcmp(indisreplident, "t") == 0)
-				appendPQExpBufferStr(&tmpbuf, _(", replica identity"));
+					if (strcmp(deferred, "t") == 0)
+						appendPQExpBufferStr(&tmpbuf, _(", initially deferred"));
 
-			printTableAddFooter(&cont, tmpbuf.data);
+					if (strcmp(indisreplident, "t") == 0)
+						appendPQExpBufferStr(&tmpbuf, _(", replica identity"));
 
-			/*
-			 * If it's a partitioned index, we'll print the tablespace below
-			 */
-			if (tableinfo.relkind == RELKIND_INDEX)
-				add_tablespace_footer(&cont, tableinfo.relkind,
-									  tableinfo.tablespace, true);
-		}
+					printTableAddFooter(&cont, tmpbuf.data);
 
-		PQclear(result);
-	}
-	/* If you add relkinds here, see also "Finish printing..." stanza below */
-	else if (tableinfo.relkind == RELKIND_RELATION ||
-			 tableinfo.relkind == RELKIND_MATVIEW ||
-			 tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
-			 tableinfo.relkind == RELKIND_PARTITIONED_TABLE ||
-			 tableinfo.relkind == RELKIND_PARTITIONED_INDEX ||
-			 tableinfo.relkind == RELKIND_TOASTVALUE)
-	{
-		/* Footer information about a table */
-		PGresult   *result = NULL;
-		int			tuples = 0;
+					/*
+					 * If it's a partitioned index, we'll print the tablespace
+					 * below
+					 */
+					if (tableinfo.relkind == RELKIND_INDEX)
+						add_tablespace_footer(&cont, tableinfo.relkind,
+											  tableinfo.tablespace, true);
+				}
 
-		/* print indexes */
-		if (tableinfo.hasindex)
-		{
-			printfPQExpBuffer(&buf,
-							  "SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, ");
-			if (pset.sversion >= 80200)
-				appendPQExpBufferStr(&buf, "i.indisvalid, ");
-			else
-				appendPQExpBufferStr(&buf, "true as indisvalid, ");
-			appendPQExpBufferStr(&buf, "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true),\n  ");
-			if (pset.sversion >= 90000)
-				appendPQExpBufferStr(&buf,
-									 "pg_catalog.pg_get_constraintdef(con.oid, true), "
-									 "contype, condeferrable, condeferred");
-			else
-				appendPQExpBufferStr(&buf,
-									 "null AS constraintdef, null AS contype, "
-									 "false AS condeferrable, false AS condeferred");
-			if (pset.sversion >= 90400)
-				appendPQExpBufferStr(&buf, ", i.indisreplident");
-			else
-				appendPQExpBufferStr(&buf, ", false AS indisreplident");
-			if (pset.sversion >= 80000)
-				appendPQExpBufferStr(&buf, ", c2.reltablespace");
-			appendPQExpBufferStr(&buf,
-								 "\nFROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n");
-			if (pset.sversion >= 90000)
-				appendPQExpBufferStr(&buf,
-									 "  LEFT JOIN pg_catalog.pg_constraint con ON (conrelid = i.indrelid AND conindid = i.indexrelid AND contype IN ('p','u','x'))\n");
-			appendPQExpBuffer(&buf,
-							  "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
-							  "ORDER BY i.indisprimary DESC, c2.relname;",
-							  oid);
-			result = PSQLexec(buf.data);
-			if (!result)
-				goto error_return;
-			else
-				tuples = PQntuples(result);
+				PQclear(result);
+			}
+			break;
 
-			if (tuples > 0)
+			/*
+			 * If you add relkinds here, see also "Finish printing..." stanza
+			 * below
+			 */
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_TOASTVALUE:
 			{
-				printTableAddFooter(&cont, _("Indexes:"));
-				for (i = 0; i < tuples; i++)
-				{
-					/* untranslated index name */
-					printfPQExpBuffer(&buf, "    \"%s\"",
-									  PQgetvalue(result, i, 0));
+				/* Footer information about a table */
+				PGresult   *result = NULL;
+				int			tuples = 0;
 
-					/* If exclusion constraint, print the constraintdef */
-					if (strcmp(PQgetvalue(result, i, 7), "x") == 0)
-					{
-						appendPQExpBuffer(&buf, " %s",
-										  PQgetvalue(result, i, 6));
-					}
+				/* print indexes */
+				if (tableinfo.hasindex)
+				{
+					printfPQExpBuffer(&buf,
+									  "SELECT c2.relname, i.indisprimary, i.indisunique, i.indisclustered, ");
+					if (pset.sversion >= 80200)
+						appendPQExpBufferStr(&buf, "i.indisvalid, ");
 					else
-					{
-						const char *indexdef;
-						const char *usingpos;
+						appendPQExpBufferStr(&buf, "true as indisvalid, ");
+					appendPQExpBufferStr(&buf, "pg_catalog.pg_get_indexdef(i.indexrelid, 0, true),\n  ");
+					if (pset.sversion >= 90000)
+						appendPQExpBufferStr(&buf,
+											 "pg_catalog.pg_get_constraintdef(con.oid, true), "
+											 "contype, condeferrable, condeferred");
+					else
+						appendPQExpBufferStr(&buf,
+											 "null AS constraintdef, null AS contype, "
+											 "false AS condeferrable, false AS condeferred");
+					if (pset.sversion >= 90400)
+						appendPQExpBufferStr(&buf, ", i.indisreplident");
+					else
+						appendPQExpBufferStr(&buf, ", false AS indisreplident");
+					if (pset.sversion >= 80000)
+						appendPQExpBufferStr(&buf, ", c2.reltablespace");
+					appendPQExpBufferStr(&buf,
+										 "\nFROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i\n");
+					if (pset.sversion >= 90000)
+						appendPQExpBufferStr(&buf,
+											 "  LEFT JOIN pg_catalog.pg_constraint con ON (conrelid = i.indrelid AND conindid = i.indexrelid AND contype IN ('p','u','x'))\n");
+					appendPQExpBuffer(&buf,
+									  "WHERE c.oid = '%s' AND c.oid = i.indrelid AND i.indexrelid = c2.oid\n"
+									  "ORDER BY i.indisprimary DESC, c2.relname;",
+									  oid);
+					result = PSQLexec(buf.data);
+					if (!result)
+						goto error_return;
+					else
+						tuples = PQntuples(result);
 
-						/* Label as primary key or unique (but not both) */
-						if (strcmp(PQgetvalue(result, i, 1), "t") == 0)
-							appendPQExpBufferStr(&buf, " PRIMARY KEY,");
-						else if (strcmp(PQgetvalue(result, i, 2), "t") == 0)
+					if (tuples > 0)
+					{
+						printTableAddFooter(&cont, _("Indexes:"));
+						for (i = 0; i < tuples; i++)
 						{
-							if (strcmp(PQgetvalue(result, i, 7), "u") == 0)
-								appendPQExpBufferStr(&buf, " UNIQUE CONSTRAINT,");
+							/* untranslated index name */
+							printfPQExpBuffer(&buf, "    \"%s\"",
+											  PQgetvalue(result, i, 0));
+
+							/*
+							 * If exclusion constraint, print the
+							 * constraintdef
+							 */
+							if (strcmp(PQgetvalue(result, i, 7), "x") == 0)
+							{
+								appendPQExpBuffer(&buf, " %s",
+												  PQgetvalue(result, i, 6));
+							}
 							else
-								appendPQExpBufferStr(&buf, " UNIQUE,");
+							{
+								const char *indexdef;
+								const char *usingpos;
+
+								/*
+								 * Label as primary key or unique (but not
+								 * both)
+								 */
+								if (strcmp(PQgetvalue(result, i, 1), "t") == 0)
+									appendPQExpBufferStr(&buf, " PRIMARY KEY,");
+								else if (strcmp(PQgetvalue(result, i, 2), "t") == 0)
+								{
+									if (strcmp(PQgetvalue(result, i, 7), "u") == 0)
+										appendPQExpBufferStr(&buf, " UNIQUE CONSTRAINT,");
+									else
+										appendPQExpBufferStr(&buf, " UNIQUE,");
+								}
+
+								/* Everything after "USING" is echoed verbatim */
+								indexdef = PQgetvalue(result, i, 5);
+								usingpos = strstr(indexdef, " USING ");
+								if (usingpos)
+									indexdef = usingpos + 7;
+								appendPQExpBuffer(&buf, " %s", indexdef);
+
+								/* Need these for deferrable PK/UNIQUE indexes */
+								if (strcmp(PQgetvalue(result, i, 8), "t") == 0)
+									appendPQExpBufferStr(&buf, " DEFERRABLE");
+
+								if (strcmp(PQgetvalue(result, i, 9), "t") == 0)
+									appendPQExpBufferStr(&buf, " INITIALLY DEFERRED");
+							}
+
+							/* Add these for all cases */
+							if (strcmp(PQgetvalue(result, i, 3), "t") == 0)
+								appendPQExpBufferStr(&buf, " CLUSTER");
+
+							if (strcmp(PQgetvalue(result, i, 4), "t") != 0)
+								appendPQExpBufferStr(&buf, " INVALID");
+
+							if (strcmp(PQgetvalue(result, i, 10), "t") == 0)
+								appendPQExpBufferStr(&buf, " REPLICA IDENTITY");
+
+							printTableAddFooter(&cont, buf.data);
+
+							/* Print tablespace of the index on the same line */
+							if (pset.sversion >= 80000)
+								add_tablespace_footer(&cont, RELKIND_INDEX,
+													  atooid(PQgetvalue(result, i, 11)),
+													  false);
 						}
+					}
+					PQclear(result);
+				}
 
-						/* Everything after "USING" is echoed verbatim */
-						indexdef = PQgetvalue(result, i, 5);
-						usingpos = strstr(indexdef, " USING ");
-						if (usingpos)
-							indexdef = usingpos + 7;
-						appendPQExpBuffer(&buf, " %s", indexdef);
+				/* print table (and column) check constraints */
+				if (tableinfo.checks)
+				{
+					printfPQExpBuffer(&buf,
+									  "SELECT r.conname, "
+									  "pg_catalog.pg_get_constraintdef(r.oid, true)\n"
+									  "FROM pg_catalog.pg_constraint r\n"
+									  "WHERE r.conrelid = '%s' AND r.contype = 'c'\n"
+									  "ORDER BY 1;",
+									  oid);
+					result = PSQLexec(buf.data);
+					if (!result)
+						goto error_return;
+					else
+						tuples = PQntuples(result);
 
-						/* Need these for deferrable PK/UNIQUE indexes */
-						if (strcmp(PQgetvalue(result, i, 8), "t") == 0)
-							appendPQExpBufferStr(&buf, " DEFERRABLE");
+					if (tuples > 0)
+					{
+						printTableAddFooter(&cont, _("Check constraints:"));
+						for (i = 0; i < tuples; i++)
+						{
+							/* untranslated constraint name and def */
+							printfPQExpBuffer(&buf, "    \"%s\" %s",
+											  PQgetvalue(result, i, 0),
+											  PQgetvalue(result, i, 1));
 
-						if (strcmp(PQgetvalue(result, i, 9), "t") == 0)
-							appendPQExpBufferStr(&buf, " INITIALLY DEFERRED");
+							printTableAddFooter(&cont, buf.data);
+						}
 					}
+					PQclear(result);
+				}
 
-					/* Add these for all cases */
-					if (strcmp(PQgetvalue(result, i, 3), "t") == 0)
-						appendPQExpBufferStr(&buf, " CLUSTER");
+				/*
+				 * Print foreign-key constraints (there are none if no
+				 * triggers, except if the table is partitioned, in which case
+				 * the triggers appear in the partitions)
+				 */
+				if (tableinfo.hastriggers ||
+					tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
+				{
+					if (pset.sversion >= 120000 &&
+						(tableinfo.ispartition || tableinfo.relkind == RELKIND_PARTITIONED_TABLE))
+					{
+						/*
+						 * Put the constraints defined in this table first,
+						 * followed by the constraints defined in ancestor
+						 * partitioned tables.
+						 */
+						printfPQExpBuffer(&buf,
+										  "SELECT conrelid = '%s'::pg_catalog.regclass AS sametable,\n"
+										  "       conname,\n"
+										  "       pg_catalog.pg_get_constraintdef(oid, true) AS condef,\n"
+										  "       conrelid::pg_catalog.regclass AS ontable\n"
+										  "  FROM pg_catalog.pg_constraint,\n"
+										  "       pg_catalog.pg_partition_ancestors('%s')\n"
+										  " WHERE conrelid = relid AND contype = 'f' AND conparentid = 0\n"
+										  "ORDER BY sametable DESC, conname;",
+										  oid, oid);
+					}
+					else
+					{
+						printfPQExpBuffer(&buf,
+										  "SELECT true as sametable, conname,\n"
+										  "  pg_catalog.pg_get_constraintdef(r.oid, true) as condef,\n"
+										  "  conrelid::pg_catalog.regclass AS ontable\n"
+										  "FROM pg_catalog.pg_constraint r\n"
+										  "WHERE r.conrelid = '%s' AND r.contype = 'f'\n",
+										  oid);
+
+						if (pset.sversion >= 120000)
+							appendPQExpBufferStr(&buf, "     AND conparentid = 0\n");
+						appendPQExpBufferStr(&buf, "ORDER BY conname");
+					}
 
-					if (strcmp(PQgetvalue(result, i, 4), "t") != 0)
-						appendPQExpBufferStr(&buf, " INVALID");
+					result = PSQLexec(buf.data);
+					if (!result)
+						goto error_return;
+					else
+						tuples = PQntuples(result);
 
-					if (strcmp(PQgetvalue(result, i, 10), "t") == 0)
-						appendPQExpBufferStr(&buf, " REPLICA IDENTITY");
+					if (tuples > 0)
+					{
+						int			i_sametable = PQfnumber(result, "sametable"),
+									i_conname = PQfnumber(result, "conname"),
+									i_condef = PQfnumber(result, "condef"),
+									i_ontable = PQfnumber(result, "ontable");
 
-					printTableAddFooter(&cont, buf.data);
+						printTableAddFooter(&cont, _("Foreign-key constraints:"));
+						for (i = 0; i < tuples; i++)
+						{
+							/*
+							 * Print untranslated constraint name and
+							 * definition. Use a "TABLE tab" prefix when the
+							 * constraint is defined in a parent partitioned
+							 * table.
+							 */
+							if (strcmp(PQgetvalue(result, i, i_sametable), "f") == 0)
+								printfPQExpBuffer(&buf, "    TABLE \"%s\" CONSTRAINT \"%s\" %s",
+												  PQgetvalue(result, i, i_ontable),
+												  PQgetvalue(result, i, i_conname),
+												  PQgetvalue(result, i, i_condef));
+							else
+								printfPQExpBuffer(&buf, "    \"%s\" %s",
+												  PQgetvalue(result, i, i_conname),
+												  PQgetvalue(result, i, i_condef));
 
-					/* Print tablespace of the index on the same line */
-					if (pset.sversion >= 80000)
-						add_tablespace_footer(&cont, RELKIND_INDEX,
-											  atooid(PQgetvalue(result, i, 11)),
-											  false);
+							printTableAddFooter(&cont, buf.data);
+						}
+					}
+					PQclear(result);
 				}
-			}
-			PQclear(result);
-		}
 
-		/* print table (and column) check constraints */
-		if (tableinfo.checks)
-		{
-			printfPQExpBuffer(&buf,
-							  "SELECT r.conname, "
-							  "pg_catalog.pg_get_constraintdef(r.oid, true)\n"
-							  "FROM pg_catalog.pg_constraint r\n"
-							  "WHERE r.conrelid = '%s' AND r.contype = 'c'\n"
-							  "ORDER BY 1;",
-							  oid);
-			result = PSQLexec(buf.data);
-			if (!result)
-				goto error_return;
-			else
-				tuples = PQntuples(result);
-
-			if (tuples > 0)
-			{
-				printTableAddFooter(&cont, _("Check constraints:"));
-				for (i = 0; i < tuples; i++)
+				/* print incoming foreign-key references */
+				if (tableinfo.hastriggers ||
+					tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
 				{
-					/* untranslated constraint name and def */
-					printfPQExpBuffer(&buf, "    \"%s\" %s",
-									  PQgetvalue(result, i, 0),
-									  PQgetvalue(result, i, 1));
-
-					printTableAddFooter(&cont, buf.data);
-				}
-			}
-			PQclear(result);
-		}
+					if (pset.sversion >= 120000)
+					{
+						printfPQExpBuffer(&buf,
+										  "SELECT conname, conrelid::pg_catalog.regclass AS ontable,\n"
+										  "       pg_catalog.pg_get_constraintdef(oid, true) AS condef\n"
+										  "  FROM pg_catalog.pg_constraint c\n"
+										  " WHERE confrelid IN (SELECT pg_catalog.pg_partition_ancestors('%s')\n"
+										  "                     UNION ALL VALUES ('%s'::pg_catalog.regclass))\n"
+										  "       AND contype = 'f' AND conparentid = 0\n"
+										  "ORDER BY conname;",
+										  oid, oid);
+					}
+					else
+					{
+						printfPQExpBuffer(&buf,
+										  "SELECT conname, conrelid::pg_catalog.regclass AS ontable,\n"
+										  "       pg_catalog.pg_get_constraintdef(oid, true) AS condef\n"
+										  "  FROM pg_catalog.pg_constraint\n"
+										  " WHERE confrelid = %s AND contype = 'f'\n"
+										  "ORDER BY conname;",
+										  oid);
+					}
 
-		/*
-		 * Print foreign-key constraints (there are none if no triggers,
-		 * except if the table is partitioned, in which case the triggers
-		 * appear in the partitions)
-		 */
-		if (tableinfo.hastriggers ||
-			tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
-		{
-			if (pset.sversion >= 120000 &&
-				(tableinfo.ispartition || tableinfo.relkind == RELKIND_PARTITIONED_TABLE))
-			{
-				/*
-				 * Put the constraints defined in this table first, followed
-				 * by the constraints defined in ancestor partitioned tables.
-				 */
-				printfPQExpBuffer(&buf,
-								  "SELECT conrelid = '%s'::pg_catalog.regclass AS sametable,\n"
-								  "       conname,\n"
-								  "       pg_catalog.pg_get_constraintdef(oid, true) AS condef,\n"
-								  "       conrelid::pg_catalog.regclass AS ontable\n"
-								  "  FROM pg_catalog.pg_constraint,\n"
-								  "       pg_catalog.pg_partition_ancestors('%s')\n"
-								  " WHERE conrelid = relid AND contype = 'f' AND conparentid = 0\n"
-								  "ORDER BY sametable DESC, conname;",
-								  oid, oid);
-			}
-			else
-			{
-				printfPQExpBuffer(&buf,
-								  "SELECT true as sametable, conname,\n"
-								  "  pg_catalog.pg_get_constraintdef(r.oid, true) as condef,\n"
-								  "  conrelid::pg_catalog.regclass AS ontable\n"
-								  "FROM pg_catalog.pg_constraint r\n"
-								  "WHERE r.conrelid = '%s' AND r.contype = 'f'\n",
-								  oid);
+					result = PSQLexec(buf.data);
+					if (!result)
+						goto error_return;
+					else
+						tuples = PQntuples(result);
 
-				if (pset.sversion >= 120000)
-					appendPQExpBufferStr(&buf, "     AND conparentid = 0\n");
-				appendPQExpBufferStr(&buf, "ORDER BY conname");
-			}
+					if (tuples > 0)
+					{
+						int			i_conname = PQfnumber(result, "conname"),
+									i_ontable = PQfnumber(result, "ontable"),
+									i_condef = PQfnumber(result, "condef");
 
-			result = PSQLexec(buf.data);
-			if (!result)
-				goto error_return;
-			else
-				tuples = PQntuples(result);
+						printTableAddFooter(&cont, _("Referenced by:"));
+						for (i = 0; i < tuples; i++)
+						{
+							printfPQExpBuffer(&buf, "    TABLE \"%s\" CONSTRAINT \"%s\" %s",
+											  PQgetvalue(result, i, i_ontable),
+											  PQgetvalue(result, i, i_conname),
+											  PQgetvalue(result, i, i_condef));
 
-			if (tuples > 0)
-			{
-				int			i_sametable = PQfnumber(result, "sametable"),
-							i_conname = PQfnumber(result, "conname"),
-							i_condef = PQfnumber(result, "condef"),
-							i_ontable = PQfnumber(result, "ontable");
+							printTableAddFooter(&cont, buf.data);
+						}
+					}
+					PQclear(result);
+				}
 
-				printTableAddFooter(&cont, _("Foreign-key constraints:"));
-				for (i = 0; i < tuples; i++)
+				/* print any row-level policies */
+				if (pset.sversion >= 90500)
 				{
-					/*
-					 * Print untranslated constraint name and definition. Use
-					 * a "TABLE tab" prefix when the constraint is defined in
-					 * a parent partitioned table.
-					 */
-					if (strcmp(PQgetvalue(result, i, i_sametable), "f") == 0)
-						printfPQExpBuffer(&buf, "    TABLE \"%s\" CONSTRAINT \"%s\" %s",
-										  PQgetvalue(result, i, i_ontable),
-										  PQgetvalue(result, i, i_conname),
-										  PQgetvalue(result, i, i_condef));
+					printfPQExpBuffer(&buf, "SELECT pol.polname,");
+					if (pset.sversion >= 100000)
+						appendPQExpBufferStr(&buf,
+											 " pol.polpermissive,\n");
 					else
-						printfPQExpBuffer(&buf, "    \"%s\" %s",
-										  PQgetvalue(result, i, i_conname),
-										  PQgetvalue(result, i, i_condef));
-
-					printTableAddFooter(&cont, buf.data);
-				}
-			}
-			PQclear(result);
-		}
-
-		/* print incoming foreign-key references */
-		if (tableinfo.hastriggers ||
-			tableinfo.relkind == RELKIND_PARTITIONED_TABLE)
-		{
-			if (pset.sversion >= 120000)
-			{
-				printfPQExpBuffer(&buf,
-								  "SELECT conname, conrelid::pg_catalog.regclass AS ontable,\n"
-								  "       pg_catalog.pg_get_constraintdef(oid, true) AS condef\n"
-								  "  FROM pg_catalog.pg_constraint c\n"
-								  " WHERE confrelid IN (SELECT pg_catalog.pg_partition_ancestors('%s')\n"
-								  "                     UNION ALL VALUES ('%s'::pg_catalog.regclass))\n"
-								  "       AND contype = 'f' AND conparentid = 0\n"
-								  "ORDER BY conname;",
-								  oid, oid);
-			}
-			else
-			{
-				printfPQExpBuffer(&buf,
-								  "SELECT conname, conrelid::pg_catalog.regclass AS ontable,\n"
-								  "       pg_catalog.pg_get_constraintdef(oid, true) AS condef\n"
-								  "  FROM pg_catalog.pg_constraint\n"
-								  " WHERE confrelid = %s AND contype = 'f'\n"
-								  "ORDER BY conname;",
-								  oid);
-			}
-
-			result = PSQLexec(buf.data);
-			if (!result)
-				goto error_return;
-			else
-				tuples = PQntuples(result);
-
-			if (tuples > 0)
-			{
-				int			i_conname = PQfnumber(result, "conname"),
-							i_ontable = PQfnumber(result, "ontable"),
-							i_condef = PQfnumber(result, "condef");
+						appendPQExpBufferStr(&buf,
+											 " 't' as polpermissive,\n");
+					appendPQExpBuffer(&buf,
+									  "  CASE WHEN pol.polroles = '{0}' THEN NULL ELSE pg_catalog.array_to_string(array(select rolname from pg_catalog.pg_roles where oid = any (pol.polroles) order by 1),',') END,\n"
+									  "  pg_catalog.pg_get_expr(pol.polqual, pol.polrelid),\n"
+									  "  pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid),\n"
+									  "  CASE pol.polcmd\n"
+									  "    WHEN 'r' THEN 'SELECT'\n"
+									  "    WHEN 'a' THEN 'INSERT'\n"
+									  "    WHEN 'w' THEN 'UPDATE'\n"
+									  "    WHEN 'd' THEN 'DELETE'\n"
+									  "    END AS cmd\n"
+									  "FROM pg_catalog.pg_policy pol\n"
+									  "WHERE pol.polrelid = '%s' ORDER BY 1;",
+									  oid);
+
+					result = PSQLexec(buf.data);
+					if (!result)
+						goto error_return;
+					else
+						tuples = PQntuples(result);
 
-				printTableAddFooter(&cont, _("Referenced by:"));
-				for (i = 0; i < tuples; i++)
-				{
-					printfPQExpBuffer(&buf, "    TABLE \"%s\" CONSTRAINT \"%s\" %s",
-									  PQgetvalue(result, i, i_ontable),
-									  PQgetvalue(result, i, i_conname),
-									  PQgetvalue(result, i, i_condef));
+					/*
+					 * Handle cases where RLS is enabled and there are
+					 * policies, or there aren't policies, or RLS isn't
+					 * enabled but there are policies
+					 */
+					if (tableinfo.rowsecurity && !tableinfo.forcerowsecurity && tuples > 0)
+						printTableAddFooter(&cont, _("Policies:"));
 
-					printTableAddFooter(&cont, buf.data);
-				}
-			}
-			PQclear(result);
-		}
+					if (tableinfo.rowsecurity && tableinfo.forcerowsecurity && tuples > 0)
+						printTableAddFooter(&cont, _("Policies (forced row security enabled):"));
 
-		/* print any row-level policies */
-		if (pset.sversion >= 90500)
-		{
-			printfPQExpBuffer(&buf, "SELECT pol.polname,");
-			if (pset.sversion >= 100000)
-				appendPQExpBufferStr(&buf,
-									 " pol.polpermissive,\n");
-			else
-				appendPQExpBufferStr(&buf,
-									 " 't' as polpermissive,\n");
-			appendPQExpBuffer(&buf,
-							  "  CASE WHEN pol.polroles = '{0}' THEN NULL ELSE pg_catalog.array_to_string(array(select rolname from pg_catalog.pg_roles where oid = any (pol.polroles) order by 1),',') END,\n"
-							  "  pg_catalog.pg_get_expr(pol.polqual, pol.polrelid),\n"
-							  "  pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid),\n"
-							  "  CASE pol.polcmd\n"
-							  "    WHEN 'r' THEN 'SELECT'\n"
-							  "    WHEN 'a' THEN 'INSERT'\n"
-							  "    WHEN 'w' THEN 'UPDATE'\n"
-							  "    WHEN 'd' THEN 'DELETE'\n"
-							  "    END AS cmd\n"
-							  "FROM pg_catalog.pg_policy pol\n"
-							  "WHERE pol.polrelid = '%s' ORDER BY 1;",
-							  oid);
+					if (tableinfo.rowsecurity && !tableinfo.forcerowsecurity && tuples == 0)
+						printTableAddFooter(&cont, _("Policies (row security enabled): (none)"));
 
-			result = PSQLexec(buf.data);
-			if (!result)
-				goto error_return;
-			else
-				tuples = PQntuples(result);
+					if (tableinfo.rowsecurity && tableinfo.forcerowsecurity && tuples == 0)
+						printTableAddFooter(&cont, _("Policies (forced row security enabled): (none)"));
 
-			/*
-			 * Handle cases where RLS is enabled and there are policies, or
-			 * there aren't policies, or RLS isn't enabled but there are
-			 * policies
-			 */
-			if (tableinfo.rowsecurity && !tableinfo.forcerowsecurity && tuples > 0)
-				printTableAddFooter(&cont, _("Policies:"));
+					if (!tableinfo.rowsecurity && tuples > 0)
+						printTableAddFooter(&cont, _("Policies (row security disabled):"));
 
-			if (tableinfo.rowsecurity && tableinfo.forcerowsecurity && tuples > 0)
-				printTableAddFooter(&cont, _("Policies (forced row security enabled):"));
+					/* Might be an empty set - that's ok */
+					for (i = 0; i < tuples; i++)
+					{
+						printfPQExpBuffer(&buf, "    POLICY \"%s\"",
+										  PQgetvalue(result, i, 0));
 
-			if (tableinfo.rowsecurity && !tableinfo.forcerowsecurity && tuples == 0)
-				printTableAddFooter(&cont, _("Policies (row security enabled): (none)"));
+						if (*(PQgetvalue(result, i, 1)) == 'f')
+							appendPQExpBufferStr(&buf, " AS RESTRICTIVE");
 
-			if (tableinfo.rowsecurity && tableinfo.forcerowsecurity && tuples == 0)
-				printTableAddFooter(&cont, _("Policies (forced row security enabled): (none)"));
+						if (!PQgetisnull(result, i, 5))
+							appendPQExpBuffer(&buf, " FOR %s",
+											  PQgetvalue(result, i, 5));
 
-			if (!tableinfo.rowsecurity && tuples > 0)
-				printTableAddFooter(&cont, _("Policies (row security disabled):"));
+						if (!PQgetisnull(result, i, 2))
+						{
+							appendPQExpBuffer(&buf, "\n      TO %s",
+											  PQgetvalue(result, i, 2));
+						}
 
-			/* Might be an empty set - that's ok */
-			for (i = 0; i < tuples; i++)
-			{
-				printfPQExpBuffer(&buf, "    POLICY \"%s\"",
-								  PQgetvalue(result, i, 0));
+						if (!PQgetisnull(result, i, 3))
+							appendPQExpBuffer(&buf, "\n      USING (%s)",
+											  PQgetvalue(result, i, 3));
 
-				if (*(PQgetvalue(result, i, 1)) == 'f')
-					appendPQExpBufferStr(&buf, " AS RESTRICTIVE");
+						if (!PQgetisnull(result, i, 4))
+							appendPQExpBuffer(&buf, "\n      WITH CHECK (%s)",
+											  PQgetvalue(result, i, 4));
 
-				if (!PQgetisnull(result, i, 5))
-					appendPQExpBuffer(&buf, " FOR %s",
-									  PQgetvalue(result, i, 5));
+						printTableAddFooter(&cont, buf.data);
 
-				if (!PQgetisnull(result, i, 2))
-				{
-					appendPQExpBuffer(&buf, "\n      TO %s",
-									  PQgetvalue(result, i, 2));
+					}
+					PQclear(result);
 				}
 
-				if (!PQgetisnull(result, i, 3))
-					appendPQExpBuffer(&buf, "\n      USING (%s)",
-									  PQgetvalue(result, i, 3));
-
-				if (!PQgetisnull(result, i, 4))
-					appendPQExpBuffer(&buf, "\n      WITH CHECK (%s)",
-									  PQgetvalue(result, i, 4));
+				/* print any extended statistics */
+				if (pset.sversion >= 100000)
+				{
+					printfPQExpBuffer(&buf,
+									  "SELECT oid, "
+									  "stxrelid::pg_catalog.regclass, "
+									  "stxnamespace::pg_catalog.regnamespace AS nsp, "
+									  "stxname,\n"
+									  "  (SELECT pg_catalog.string_agg(pg_catalog.quote_ident(attname),', ')\n"
+									  "   FROM pg_catalog.unnest(stxkeys) s(attnum)\n"
+									  "   JOIN pg_catalog.pg_attribute a ON (stxrelid = a.attrelid AND\n"
+									  "        a.attnum = s.attnum AND NOT attisdropped)) AS columns,\n"
+									  "  'd' = any(stxkind) AS ndist_enabled,\n"
+									  "  'f' = any(stxkind) AS deps_enabled,\n"
+									  "  'm' = any(stxkind) AS mcv_enabled\n"
+									  "FROM pg_catalog.pg_statistic_ext stat "
+									  "WHERE stxrelid = '%s'\n"
+									  "ORDER BY 1;",
+									  oid);
+
+					result = PSQLexec(buf.data);
+					if (!result)
+						goto error_return;
+					else
+						tuples = PQntuples(result);
 
-				printTableAddFooter(&cont, buf.data);
+					if (tuples > 0)
+					{
+						printTableAddFooter(&cont, _("Statistics objects:"));
 
-			}
-			PQclear(result);
-		}
+						for (i = 0; i < tuples; i++)
+						{
+							bool		gotone = false;
 
-		/* print any extended statistics */
-		if (pset.sversion >= 100000)
-		{
-			printfPQExpBuffer(&buf,
-							  "SELECT oid, "
-							  "stxrelid::pg_catalog.regclass, "
-							  "stxnamespace::pg_catalog.regnamespace AS nsp, "
-							  "stxname,\n"
-							  "  (SELECT pg_catalog.string_agg(pg_catalog.quote_ident(attname),', ')\n"
-							  "   FROM pg_catalog.unnest(stxkeys) s(attnum)\n"
-							  "   JOIN pg_catalog.pg_attribute a ON (stxrelid = a.attrelid AND\n"
-							  "        a.attnum = s.attnum AND NOT attisdropped)) AS columns,\n"
-							  "  'd' = any(stxkind) AS ndist_enabled,\n"
-							  "  'f' = any(stxkind) AS deps_enabled,\n"
-							  "  'm' = any(stxkind) AS mcv_enabled\n"
-							  "FROM pg_catalog.pg_statistic_ext stat "
-							  "WHERE stxrelid = '%s'\n"
-							  "ORDER BY 1;",
-							  oid);
+							printfPQExpBuffer(&buf, "    ");
 
-			result = PSQLexec(buf.data);
-			if (!result)
-				goto error_return;
-			else
-				tuples = PQntuples(result);
+							/*
+							 * statistics object name (qualified with
+							 * namespace)
+							 */
+							appendPQExpBuffer(&buf, "\"%s\".\"%s\" (",
+											  PQgetvalue(result, i, 2),
+											  PQgetvalue(result, i, 3));
 
-			if (tuples > 0)
-			{
-				printTableAddFooter(&cont, _("Statistics objects:"));
+							/* options */
+							if (strcmp(PQgetvalue(result, i, 5), "t") == 0)
+							{
+								appendPQExpBufferStr(&buf, "ndistinct");
+								gotone = true;
+							}
 
-				for (i = 0; i < tuples; i++)
-				{
-					bool		gotone = false;
+							if (strcmp(PQgetvalue(result, i, 6), "t") == 0)
+							{
+								appendPQExpBuffer(&buf, "%sdependencies", gotone ? ", " : "");
+								gotone = true;
+							}
 
-					printfPQExpBuffer(&buf, "    ");
+							if (strcmp(PQgetvalue(result, i, 7), "t") == 0)
+							{
+								appendPQExpBuffer(&buf, "%smcv", gotone ? ", " : "");
+							}
 
-					/* statistics object name (qualified with namespace) */
-					appendPQExpBuffer(&buf, "\"%s\".\"%s\" (",
-									  PQgetvalue(result, i, 2),
-									  PQgetvalue(result, i, 3));
+							appendPQExpBuffer(&buf, ") ON %s FROM %s",
+											  PQgetvalue(result, i, 4),
+											  PQgetvalue(result, i, 1));
 
-					/* options */
-					if (strcmp(PQgetvalue(result, i, 5), "t") == 0)
-					{
-						appendPQExpBufferStr(&buf, "ndistinct");
-						gotone = true;
+							printTableAddFooter(&cont, buf.data);
+						}
 					}
+					PQclear(result);
+				}
 
-					if (strcmp(PQgetvalue(result, i, 6), "t") == 0)
+				/* print rules */
+				if (tableinfo.hasrules && tableinfo.relkind != RELKIND_MATVIEW)
+				{
+					if (pset.sversion >= 80300)
 					{
-						appendPQExpBuffer(&buf, "%sdependencies", gotone ? ", " : "");
-						gotone = true;
+						printfPQExpBuffer(&buf,
+										  "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
+										  "ev_enabled\n"
+										  "FROM pg_catalog.pg_rewrite r\n"
+										  "WHERE r.ev_class = '%s' ORDER BY 1;",
+										  oid);
 					}
-
-					if (strcmp(PQgetvalue(result, i, 7), "t") == 0)
+					else
 					{
-						appendPQExpBuffer(&buf, "%smcv", gotone ? ", " : "");
+						printfPQExpBuffer(&buf,
+										  "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
+										  "'O' AS ev_enabled\n"
+										  "FROM pg_catalog.pg_rewrite r\n"
+										  "WHERE r.ev_class = '%s' ORDER BY 1;",
+										  oid);
 					}
+					result = PSQLexec(buf.data);
+					if (!result)
+						goto error_return;
+					else
+						tuples = PQntuples(result);
 
-					appendPQExpBuffer(&buf, ") ON %s FROM %s",
-									  PQgetvalue(result, i, 4),
-									  PQgetvalue(result, i, 1));
-
-					printTableAddFooter(&cont, buf.data);
-				}
-			}
-			PQclear(result);
-		}
-
-		/* print rules */
-		if (tableinfo.hasrules && tableinfo.relkind != RELKIND_MATVIEW)
-		{
-			if (pset.sversion >= 80300)
-			{
-				printfPQExpBuffer(&buf,
-								  "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
-								  "ev_enabled\n"
-								  "FROM pg_catalog.pg_rewrite r\n"
-								  "WHERE r.ev_class = '%s' ORDER BY 1;",
-								  oid);
-			}
-			else
-			{
-				printfPQExpBuffer(&buf,
-								  "SELECT r.rulename, trim(trailing ';' from pg_catalog.pg_get_ruledef(r.oid, true)), "
-								  "'O' AS ev_enabled\n"
-								  "FROM pg_catalog.pg_rewrite r\n"
-								  "WHERE r.ev_class = '%s' ORDER BY 1;",
-								  oid);
-			}
-			result = PSQLexec(buf.data);
-			if (!result)
-				goto error_return;
-			else
-				tuples = PQntuples(result);
-
-			if (tuples > 0)
-			{
-				bool		have_heading;
-				int			category;
-
-				for (category = 0; category < 4; category++)
-				{
-					have_heading = false;
-
-					for (i = 0; i < tuples; i++)
+					if (tuples > 0)
 					{
-						const char *ruledef;
-						bool		list_rule = false;
+						bool		have_heading;
+						int			category;
 
-						switch (category)
+						for (category = 0; category < 4; category++)
 						{
-							case 0:
-								if (*PQgetvalue(result, i, 2) == 'O')
-									list_rule = true;
-								break;
-							case 1:
-								if (*PQgetvalue(result, i, 2) == 'D')
-									list_rule = true;
-								break;
-							case 2:
-								if (*PQgetvalue(result, i, 2) == 'A')
-									list_rule = true;
-								break;
-							case 3:
-								if (*PQgetvalue(result, i, 2) == 'R')
-									list_rule = true;
-								break;
-						}
-						if (!list_rule)
-							continue;
+							have_heading = false;
 
-						if (!have_heading)
-						{
-							switch (category)
+							for (i = 0; i < tuples; i++)
 							{
-								case 0:
-									printfPQExpBuffer(&buf, _("Rules:"));
-									break;
-								case 1:
-									printfPQExpBuffer(&buf, _("Disabled rules:"));
-									break;
-								case 2:
-									printfPQExpBuffer(&buf, _("Rules firing always:"));
-									break;
-								case 3:
-									printfPQExpBuffer(&buf, _("Rules firing on replica only:"));
-									break;
+								const char *ruledef;
+								bool		list_rule = false;
+
+								switch (category)
+								{
+									case 0:
+										if (*PQgetvalue(result, i, 2) == 'O')
+											list_rule = true;
+										break;
+									case 1:
+										if (*PQgetvalue(result, i, 2) == 'D')
+											list_rule = true;
+										break;
+									case 2:
+										if (*PQgetvalue(result, i, 2) == 'A')
+											list_rule = true;
+										break;
+									case 3:
+										if (*PQgetvalue(result, i, 2) == 'R')
+											list_rule = true;
+										break;
+								}
+								if (!list_rule)
+									continue;
+
+								if (!have_heading)
+								{
+									switch (category)
+									{
+										case 0:
+											printfPQExpBuffer(&buf, _("Rules:"));
+											break;
+										case 1:
+											printfPQExpBuffer(&buf, _("Disabled rules:"));
+											break;
+										case 2:
+											printfPQExpBuffer(&buf, _("Rules firing always:"));
+											break;
+										case 3:
+											printfPQExpBuffer(&buf, _("Rules firing on replica only:"));
+											break;
+									}
+									printTableAddFooter(&cont, buf.data);
+									have_heading = true;
+								}
+
+								/*
+								 * Everything after "CREATE RULE" is echoed
+								 * verbatim
+								 */
+								ruledef = PQgetvalue(result, i, 1);
+								ruledef += 12;
+								printfPQExpBuffer(&buf, "    %s", ruledef);
+								printTableAddFooter(&cont, buf.data);
 							}
-							printTableAddFooter(&cont, buf.data);
-							have_heading = true;
 						}
-
-						/* Everything after "CREATE RULE" is echoed verbatim */
-						ruledef = PQgetvalue(result, i, 1);
-						ruledef += 12;
-						printfPQExpBuffer(&buf, "    %s", ruledef);
-						printTableAddFooter(&cont, buf.data);
 					}
+					PQclear(result);
 				}
-			}
-			PQclear(result);
-		}
-
-		/* print any publications */
-		if (pset.sversion >= 100000)
-		{
-			printfPQExpBuffer(&buf,
-							  "SELECT pubname\n"
-							  "FROM pg_catalog.pg_publication p\n"
-							  "JOIN pg_catalog.pg_publication_rel pr ON p.oid = pr.prpubid\n"
-							  "WHERE pr.prrelid = '%s'\n"
-							  "UNION ALL\n"
-							  "SELECT pubname\n"
-							  "FROM pg_catalog.pg_publication p\n"
-							  "WHERE p.puballtables AND pg_catalog.pg_relation_is_publishable('%s')\n"
-							  "ORDER BY 1;",
-							  oid, oid);
 
-			result = PSQLexec(buf.data);
-			if (!result)
-				goto error_return;
-			else
-				tuples = PQntuples(result);
+				/* print any publications */
+				if (pset.sversion >= 100000)
+				{
+					printfPQExpBuffer(&buf,
+									  "SELECT pubname\n"
+									  "FROM pg_catalog.pg_publication p\n"
+									  "JOIN pg_catalog.pg_publication_rel pr ON p.oid = pr.prpubid\n"
+									  "WHERE pr.prrelid = '%s'\n"
+									  "UNION ALL\n"
+									  "SELECT pubname\n"
+									  "FROM pg_catalog.pg_publication p\n"
+									  "WHERE p.puballtables AND pg_catalog.pg_relation_is_publishable('%s')\n"
+									  "ORDER BY 1;",
+									  oid, oid);
+
+					result = PSQLexec(buf.data);
+					if (!result)
+						goto error_return;
+					else
+						tuples = PQntuples(result);
 
-			if (tuples > 0)
-				printTableAddFooter(&cont, _("Publications:"));
+					if (tuples > 0)
+						printTableAddFooter(&cont, _("Publications:"));
 
-			/* Might be an empty set - that's ok */
-			for (i = 0; i < tuples; i++)
-			{
-				printfPQExpBuffer(&buf, "    \"%s\"",
-								  PQgetvalue(result, i, 0));
+					/* Might be an empty set - that's ok */
+					for (i = 0; i < tuples; i++)
+					{
+						printfPQExpBuffer(&buf, "    \"%s\"",
+										  PQgetvalue(result, i, 0));
 
-				printTableAddFooter(&cont, buf.data);
+						printTableAddFooter(&cont, buf.data);
+					}
+					PQclear(result);
+				}
 			}
-			PQclear(result);
-		}
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_VIEW:
+			break;
 	}
 
 	/* Get view_def if table is a view or materialized view */
-	if ((tableinfo.relkind == RELKIND_VIEW ||
-		 tableinfo.relkind == RELKIND_MATVIEW) && verbose)
+	Assert(RELKIND_IS_VALID((RelKind) tableinfo.relkind));
+	switch ((RelKind) tableinfo.relkind)
 	{
-		PGresult   *result;
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+			if (verbose)
+			{
+				PGresult   *result;
 
-		printfPQExpBuffer(&buf,
-						  "SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true);",
-						  oid);
-		result = PSQLexec(buf.data);
-		if (!result)
-			goto error_return;
+				printfPQExpBuffer(&buf,
+								  "SELECT pg_catalog.pg_get_viewdef('%s'::pg_catalog.oid, true);",
+								  oid);
+				result = PSQLexec(buf.data);
+				if (!result)
+					goto error_return;
 
-		if (PQntuples(result) > 0)
-			view_def = pg_strdup(PQgetvalue(result, 0, 0));
+				if (PQntuples(result) > 0)
+					view_def = pg_strdup(PQgetvalue(result, 0, 0));
 
-		PQclear(result);
+				PQclear(result);
+			}
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_RELATION:
+		case RELKIND_TOASTVALUE:
+			break;
 	}
 
 	if (view_def)
@@ -3086,224 +3195,234 @@ describeOneTableDetails(const char *schemaname,
 	/*
 	 * Finish printing the footer information about a table.
 	 */
-	if (tableinfo.relkind == RELKIND_RELATION ||
-		tableinfo.relkind == RELKIND_MATVIEW ||
-		tableinfo.relkind == RELKIND_FOREIGN_TABLE ||
-		tableinfo.relkind == RELKIND_PARTITIONED_TABLE ||
-		tableinfo.relkind == RELKIND_PARTITIONED_INDEX ||
-		tableinfo.relkind == RELKIND_TOASTVALUE)
+	Assert(RELKIND_IS_VALID((RelKind) tableinfo.relkind));
+	switch ((RelKind) tableinfo.relkind)
 	{
-		bool		is_partitioned;
-		PGresult   *result;
-		int			tuples;
-
-		/* simplify some repeated tests below */
-		is_partitioned = (tableinfo.relkind == RELKIND_PARTITIONED_TABLE ||
-						  tableinfo.relkind == RELKIND_PARTITIONED_INDEX);
-
-		/* print foreign server name */
-		if (tableinfo.relkind == RELKIND_FOREIGN_TABLE)
-		{
-			char	   *ftoptions;
-
-			/* Footer information about foreign table */
-			printfPQExpBuffer(&buf,
-							  "SELECT s.srvname,\n"
-							  "  pg_catalog.array_to_string(ARRAY(\n"
-							  "    SELECT pg_catalog.quote_ident(option_name)"
-							  " || ' ' || pg_catalog.quote_literal(option_value)\n"
-							  "    FROM pg_catalog.pg_options_to_table(ftoptions)),  ', ')\n"
-							  "FROM pg_catalog.pg_foreign_table f,\n"
-							  "     pg_catalog.pg_foreign_server s\n"
-							  "WHERE f.ftrelid = '%s' AND s.oid = f.ftserver;",
-							  oid);
-			result = PSQLexec(buf.data);
-			if (!result)
-				goto error_return;
-			else if (PQntuples(result) != 1)
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_TOASTVALUE:
 			{
-				PQclear(result);
-				goto error_return;
-			}
+				bool		is_partitioned;
+				PGresult   *result;
+				int			tuples;
 
-			/* Print server name */
-			printfPQExpBuffer(&buf, _("Server: %s"),
-							  PQgetvalue(result, 0, 0));
-			printTableAddFooter(&cont, buf.data);
+				/* simplify some repeated tests below */
+				is_partitioned = (tableinfo.relkind == RELKIND_PARTITIONED_TABLE ||
+								  tableinfo.relkind == RELKIND_PARTITIONED_INDEX);
 
-			/* Print per-table FDW options, if any */
-			ftoptions = PQgetvalue(result, 0, 1);
-			if (ftoptions && ftoptions[0] != '\0')
-			{
-				printfPQExpBuffer(&buf, _("FDW options: (%s)"), ftoptions);
-				printTableAddFooter(&cont, buf.data);
-			}
-			PQclear(result);
-		}
+				/* print foreign server name */
+				if (tableinfo.relkind == RELKIND_FOREIGN_TABLE)
+				{
+					char	   *ftoptions;
+
+					/* Footer information about foreign table */
+					printfPQExpBuffer(&buf,
+									  "SELECT s.srvname,\n"
+									  "  pg_catalog.array_to_string(ARRAY(\n"
+									  "    SELECT pg_catalog.quote_ident(option_name)"
+									  " || ' ' || pg_catalog.quote_literal(option_value)\n"
+									  "    FROM pg_catalog.pg_options_to_table(ftoptions)),  ', ')\n"
+									  "FROM pg_catalog.pg_foreign_table f,\n"
+									  "     pg_catalog.pg_foreign_server s\n"
+									  "WHERE f.ftrelid = '%s' AND s.oid = f.ftserver;",
+									  oid);
+					result = PSQLexec(buf.data);
+					if (!result)
+						goto error_return;
+					else if (PQntuples(result) != 1)
+					{
+						PQclear(result);
+						goto error_return;
+					}
 
-		/* print tables inherited from (exclude partitioned parents) */
-		printfPQExpBuffer(&buf,
-						  "SELECT c.oid::pg_catalog.regclass\n"
-						  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
-						  "WHERE c.oid = i.inhparent AND i.inhrelid = '%s'\n"
-						  "  AND c.relkind != " CppAsString2(RELKIND_PARTITIONED_TABLE)
-						  " AND c.relkind != " CppAsString2(RELKIND_PARTITIONED_INDEX)
-						  "\nORDER BY inhseqno;",
-						  oid);
+					/* Print server name */
+					printfPQExpBuffer(&buf, _("Server: %s"),
+									  PQgetvalue(result, 0, 0));
+					printTableAddFooter(&cont, buf.data);
 
-		result = PSQLexec(buf.data);
-		if (!result)
-			goto error_return;
-		else
-		{
-			const char *s = _("Inherits");
-			int			sw = pg_wcswidth(s, strlen(s), pset.encoding);
+					/* Print per-table FDW options, if any */
+					ftoptions = PQgetvalue(result, 0, 1);
+					if (ftoptions && ftoptions[0] != '\0')
+					{
+						printfPQExpBuffer(&buf, _("FDW options: (%s)"), ftoptions);
+						printTableAddFooter(&cont, buf.data);
+					}
+					PQclear(result);
+				}
 
-			tuples = PQntuples(result);
+				/* print tables inherited from (exclude partitioned parents) */
+				printfPQExpBuffer(&buf,
+								  "SELECT c.oid::pg_catalog.regclass\n"
+								  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
+								  "WHERE c.oid = i.inhparent AND i.inhrelid = '%s'\n"
+								  "  AND c.relkind != " RelKindAsString(RELKIND_PARTITIONED_TABLE)
+								  " AND c.relkind != " RelKindAsString(RELKIND_PARTITIONED_INDEX)
+								  "\nORDER BY inhseqno;",
+								  oid);
 
-			for (i = 0; i < tuples; i++)
-			{
-				if (i == 0)
-					printfPQExpBuffer(&buf, "%s: %s",
-									  s, PQgetvalue(result, i, 0));
+				result = PSQLexec(buf.data);
+				if (!result)
+					goto error_return;
 				else
-					printfPQExpBuffer(&buf, "%*s  %s",
-									  sw, "", PQgetvalue(result, i, 0));
-				if (i < tuples - 1)
-					appendPQExpBufferChar(&buf, ',');
+				{
+					const char *s = _("Inherits");
+					int			sw = pg_wcswidth(s, strlen(s), pset.encoding);
 
-				printTableAddFooter(&cont, buf.data);
-			}
+					tuples = PQntuples(result);
 
-			PQclear(result);
-		}
+					for (i = 0; i < tuples; i++)
+					{
+						if (i == 0)
+							printfPQExpBuffer(&buf, "%s: %s",
+											  s, PQgetvalue(result, i, 0));
+						else
+							printfPQExpBuffer(&buf, "%*s  %s",
+											  sw, "", PQgetvalue(result, i, 0));
+						if (i < tuples - 1)
+							appendPQExpBufferChar(&buf, ',');
 
-		/* print child tables (with additional info if partitions) */
-		if (pset.sversion >= 100000)
-			printfPQExpBuffer(&buf,
-							  "SELECT c.oid::pg_catalog.regclass, c.relkind,"
-							  " pg_catalog.pg_get_expr(c.relpartbound, c.oid)\n"
-							  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
-							  "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
-							  "ORDER BY pg_catalog.pg_get_expr(c.relpartbound, c.oid) = 'DEFAULT',"
-							  " c.oid::pg_catalog.regclass::pg_catalog.text;",
-							  oid);
-		else if (pset.sversion >= 80300)
-			printfPQExpBuffer(&buf,
-							  "SELECT c.oid::pg_catalog.regclass, c.relkind, NULL\n"
-							  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
-							  "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
-							  "ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;",
-							  oid);
-		else
-			printfPQExpBuffer(&buf,
-							  "SELECT c.oid::pg_catalog.regclass, c.relkind, NULL\n"
-							  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
-							  "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
-							  "ORDER BY c.relname;",
-							  oid);
+						printTableAddFooter(&cont, buf.data);
+					}
 
-		result = PSQLexec(buf.data);
-		if (!result)
-			goto error_return;
-		tuples = PQntuples(result);
+					PQclear(result);
+				}
 
-		/*
-		 * For a partitioned table with no partitions, always print the number
-		 * of partitions as zero, even when verbose output is expected.
-		 * Otherwise, we will not print "Partitions" section for a partitioned
-		 * table without any partitions.
-		 */
-		if (is_partitioned && tuples == 0)
-		{
-			printfPQExpBuffer(&buf, _("Number of partitions: %d"), tuples);
-			printTableAddFooter(&cont, buf.data);
-		}
-		else if (!verbose)
-		{
-			/* print the number of child tables, if any */
-			if (tuples > 0)
-			{
-				if (is_partitioned)
-					printfPQExpBuffer(&buf, _("Number of partitions: %d (Use \\d+ to list them.)"), tuples);
+				/* print child tables (with additional info if partitions) */
+				if (pset.sversion >= 100000)
+					printfPQExpBuffer(&buf,
+									  "SELECT c.oid::pg_catalog.regclass, c.relkind,"
+									  " pg_catalog.pg_get_expr(c.relpartbound, c.oid)\n"
+									  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
+									  "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
+									  "ORDER BY pg_catalog.pg_get_expr(c.relpartbound, c.oid) = 'DEFAULT',"
+									  " c.oid::pg_catalog.regclass::pg_catalog.text;",
+									  oid);
+				else if (pset.sversion >= 80300)
+					printfPQExpBuffer(&buf,
+									  "SELECT c.oid::pg_catalog.regclass, c.relkind, NULL\n"
+									  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
+									  "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
+									  "ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;",
+									  oid);
 				else
-					printfPQExpBuffer(&buf, _("Number of child tables: %d (Use \\d+ to list them.)"), tuples);
-				printTableAddFooter(&cont, buf.data);
-			}
-		}
-		else
-		{
-			/* display the list of child tables */
-			const char *ct = is_partitioned ? _("Partitions") : _("Child tables");
-			int			ctw = pg_wcswidth(ct, strlen(ct), pset.encoding);
-
-			for (i = 0; i < tuples; i++)
-			{
-				char		child_relkind = *PQgetvalue(result, i, 1);
+					printfPQExpBuffer(&buf,
+									  "SELECT c.oid::pg_catalog.regclass, c.relkind, NULL\n"
+									  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
+									  "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
+									  "ORDER BY c.relname;",
+									  oid);
+
+				result = PSQLexec(buf.data);
+				if (!result)
+					goto error_return;
+				tuples = PQntuples(result);
 
-				if (i == 0)
-					printfPQExpBuffer(&buf, "%s: %s",
-									  ct, PQgetvalue(result, i, 0));
+				/*
+				 * For a partitioned table with no partitions, always print
+				 * the number of partitions as zero, even when verbose output
+				 * is expected. Otherwise, we will not print "Partitions"
+				 * section for a partitioned table without any partitions.
+				 */
+				if (is_partitioned && tuples == 0)
+				{
+					printfPQExpBuffer(&buf, _("Number of partitions: %d"), tuples);
+					printTableAddFooter(&cont, buf.data);
+				}
+				else if (!verbose)
+				{
+					/* print the number of child tables, if any */
+					if (tuples > 0)
+					{
+						if (is_partitioned)
+							printfPQExpBuffer(&buf, _("Number of partitions: %d (Use \\d+ to list them.)"), tuples);
+						else
+							printfPQExpBuffer(&buf, _("Number of child tables: %d (Use \\d+ to list them.)"), tuples);
+						printTableAddFooter(&cont, buf.data);
+					}
+				}
 				else
-					printfPQExpBuffer(&buf, "%*s  %s",
-									  ctw, "", PQgetvalue(result, i, 0));
-				if (!PQgetisnull(result, i, 2))
-					appendPQExpBuffer(&buf, " %s", PQgetvalue(result, i, 2));
-				if (child_relkind == RELKIND_PARTITIONED_TABLE ||
-					child_relkind == RELKIND_PARTITIONED_INDEX)
-					appendPQExpBufferStr(&buf, ", PARTITIONED");
-				if (i < tuples - 1)
-					appendPQExpBufferChar(&buf, ',');
+				{
+					/* display the list of child tables */
+					const char *ct = is_partitioned ? _("Partitions") : _("Child tables");
+					int			ctw = pg_wcswidth(ct, strlen(ct), pset.encoding);
 
-				printTableAddFooter(&cont, buf.data);
-			}
-		}
-		PQclear(result);
+					for (i = 0; i < tuples; i++)
+					{
+						char		child_relkind = *PQgetvalue(result, i, 1);
+
+						if (i == 0)
+							printfPQExpBuffer(&buf, "%s: %s",
+											  ct, PQgetvalue(result, i, 0));
+						else
+							printfPQExpBuffer(&buf, "%*s  %s",
+											  ctw, "", PQgetvalue(result, i, 0));
+						if (!PQgetisnull(result, i, 2))
+							appendPQExpBuffer(&buf, " %s", PQgetvalue(result, i, 2));
+						if (child_relkind == RELKIND_PARTITIONED_TABLE ||
+							child_relkind == RELKIND_PARTITIONED_INDEX)
+							appendPQExpBufferStr(&buf, ", PARTITIONED");
+						if (i < tuples - 1)
+							appendPQExpBufferChar(&buf, ',');
 
-		/* Table type */
-		if (tableinfo.reloftype)
-		{
-			printfPQExpBuffer(&buf, _("Typed table of type: %s"), tableinfo.reloftype);
-			printTableAddFooter(&cont, buf.data);
-		}
+						printTableAddFooter(&cont, buf.data);
+					}
+				}
+				PQclear(result);
 
-		if (verbose &&
-			(tableinfo.relkind == RELKIND_RELATION ||
-			 tableinfo.relkind == RELKIND_MATVIEW) &&
+				/* Table type */
+				if (tableinfo.reloftype)
+				{
+					printfPQExpBuffer(&buf, _("Typed table of type: %s"), tableinfo.reloftype);
+					printTableAddFooter(&cont, buf.data);
+				}
 
-		/*
-		 * No need to display default values; we already display a REPLICA
-		 * IDENTITY marker on indexes.
-		 */
-			tableinfo.relreplident != 'i' &&
-			((strcmp(schemaname, "pg_catalog") != 0 && tableinfo.relreplident != 'd') ||
-			 (strcmp(schemaname, "pg_catalog") == 0 && tableinfo.relreplident != 'n')))
-		{
-			const char *s = _("Replica Identity");
+				if (verbose &&
+					(tableinfo.relkind == RELKIND_RELATION ||
+					 tableinfo.relkind == RELKIND_MATVIEW) &&
 
-			printfPQExpBuffer(&buf, "%s: %s",
-							  s,
-							  tableinfo.relreplident == 'f' ? "FULL" :
-							  tableinfo.relreplident == 'n' ? "NOTHING" :
-							  "???");
+				/*
+				 * No need to display default values; we already display a
+				 * REPLICA IDENTITY marker on indexes.
+				 */
+					tableinfo.relreplident != 'i' &&
+					((strcmp(schemaname, "pg_catalog") != 0 && tableinfo.relreplident != 'd') ||
+					 (strcmp(schemaname, "pg_catalog") == 0 && tableinfo.relreplident != 'n')))
+				{
+					const char *s = _("Replica Identity");
 
-			printTableAddFooter(&cont, buf.data);
-		}
+					printfPQExpBuffer(&buf, "%s: %s",
+									  s,
+									  tableinfo.relreplident == 'f' ? "FULL" :
+									  tableinfo.relreplident == 'n' ? "NOTHING" :
+									  "???");
 
-		/* OIDs, if verbose and not a materialized view */
-		if (verbose && tableinfo.relkind != RELKIND_MATVIEW && tableinfo.hasoids)
-			printTableAddFooter(&cont, _("Has OIDs: yes"));
+					printTableAddFooter(&cont, buf.data);
+				}
 
-		/* Tablespace info */
-		add_tablespace_footer(&cont, tableinfo.relkind, tableinfo.tablespace,
-							  true);
+				/* OIDs, if verbose and not a materialized view */
+				if (verbose && tableinfo.relkind != RELKIND_MATVIEW && tableinfo.hasoids)
+					printTableAddFooter(&cont, _("Has OIDs: yes"));
 
-		/* Access method info */
-		if (verbose && tableinfo.relam != NULL && !pset.hide_tableam)
-		{
-			printfPQExpBuffer(&buf, _("Access method: %s"), tableinfo.relam);
-			printTableAddFooter(&cont, buf.data);
-		}
+				/* Tablespace info */
+				add_tablespace_footer(&cont, tableinfo.relkind, tableinfo.tablespace,
+									  true);
+
+				/* Access method info */
+				if (verbose && tableinfo.relam != NULL && !pset.hide_tableam)
+				{
+					printfPQExpBuffer(&buf, _("Access method: %s"), tableinfo.relam);
+					printTableAddFooter(&cont, buf.data);
+				}
+			}
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_INDEX:
+		case RELKIND_VIEW:
+			break;
 	}
 
 	/* reloptions, if verbose */
@@ -3348,59 +3467,70 @@ add_tablespace_footer(printTableContent *const cont, char relkind,
 					  Oid tablespace, const bool newline)
 {
 	/* relkinds for which we support tablespaces */
-	if (relkind == RELKIND_RELATION ||
-		relkind == RELKIND_MATVIEW ||
-		relkind == RELKIND_INDEX ||
-		relkind == RELKIND_PARTITIONED_TABLE ||
-		relkind == RELKIND_PARTITIONED_INDEX ||
-		relkind == RELKIND_TOASTVALUE)
+	Assert(RELKIND_IS_VALID((RelKind) relkind));
+	switch ((RelKind) relkind)
 	{
-		/*
-		 * We ignore the database default tablespace so that users not using
-		 * tablespaces don't need to know about them.  This case also covers
-		 * pre-8.0 servers, for which tablespace will always be 0.
-		 */
-		if (tablespace != 0)
-		{
-			PGresult   *result = NULL;
-			PQExpBufferData buf;
-
-			initPQExpBuffer(&buf);
-			printfPQExpBuffer(&buf,
-							  "SELECT spcname FROM pg_catalog.pg_tablespace\n"
-							  "WHERE oid = '%u';", tablespace);
-			result = PSQLexec(buf.data);
-			if (!result)
-			{
-				termPQExpBuffer(&buf);
-				return;
-			}
-			/* Should always be the case, but.... */
-			if (PQntuples(result) > 0)
+		case RELKIND_RELATION:
+		case RELKIND_MATVIEW:
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_TABLE:
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_TOASTVALUE:
 			{
-				if (newline)
-				{
-					/* Add the tablespace as a new footer */
-					printfPQExpBuffer(&buf, _("Tablespace: \"%s\""),
-									  PQgetvalue(result, 0, 0));
-					printTableAddFooter(cont, buf.data);
-				}
-				else
+				/*
+				 * We ignore the database default tablespace so that users not
+				 * using tablespaces don't need to know about them.  This case
+				 * also covers pre-8.0 servers, for which tablespace will
+				 * always be 0.
+				 */
+				if (tablespace != 0)
 				{
-					/* Append the tablespace to the latest footer */
-					printfPQExpBuffer(&buf, "%s", cont->footer->data);
-
-					/*-------
-					   translator: before this string there's an index description like
-					   '"foo_pkey" PRIMARY KEY, btree (a)' */
-					appendPQExpBuffer(&buf, _(", tablespace \"%s\""),
-									  PQgetvalue(result, 0, 0));
-					printTableSetFooter(cont, buf.data);
+					PGresult   *result = NULL;
+					PQExpBufferData buf;
+
+					initPQExpBuffer(&buf);
+					printfPQExpBuffer(&buf,
+									  "SELECT spcname FROM pg_catalog.pg_tablespace\n"
+									  "WHERE oid = '%u';", tablespace);
+					result = PSQLexec(buf.data);
+					if (!result)
+					{
+						termPQExpBuffer(&buf);
+						return;
+					}
+					/* Should always be the case, but.... */
+					if (PQntuples(result) > 0)
+					{
+						if (newline)
+						{
+							/* Add the tablespace as a new footer */
+							printfPQExpBuffer(&buf, _("Tablespace: \"%s\""),
+											  PQgetvalue(result, 0, 0));
+							printTableAddFooter(cont, buf.data);
+						}
+						else
+						{
+							/* Append the tablespace to the latest footer */
+							printfPQExpBuffer(&buf, "%s", cont->footer->data);
+
+							/*-------
+							   translator: before this string there's an index description like
+							   '"foo_pkey" PRIMARY KEY, btree (a)' */
+							appendPQExpBuffer(&buf, _(", tablespace \"%s\""),
+											  PQgetvalue(result, 0, 0));
+							printTableSetFooter(cont, buf.data);
+						}
+					}
+					PQclear(result);
+					termPQExpBuffer(&buf);
 				}
 			}
-			PQclear(result);
-			termPQExpBuffer(&buf);
-		}
+			break;
+		case RELKIND_SEQUENCE:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_VIEW:
+			break;
 	}
 }
 
@@ -3694,15 +3824,15 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
 					  "SELECT n.nspname as \"%s\",\n"
 					  "  c.relname as \"%s\",\n"
 					  "  CASE c.relkind"
-					  " WHEN " CppAsString2(RELKIND_RELATION) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_VIEW) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_MATVIEW) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_INDEX) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_SEQUENCE) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_RELATION) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_VIEW) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_MATVIEW) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_INDEX) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_SEQUENCE) " THEN '%s'"
 					  " WHEN 's' THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_FOREIGN_TABLE) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
-					  " WHEN " CppAsString2(RELKIND_PARTITIONED_INDEX) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_FOREIGN_TABLE) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
+					  " WHEN " RelKindAsString(RELKIND_PARTITIONED_INDEX) " THEN '%s'"
 					  " END as \"%s\",\n"
 					  "  pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
 					  gettext_noop("Schema"),
@@ -3779,21 +3909,21 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
 
 	appendPQExpBufferStr(&buf, "\nWHERE c.relkind IN (");
 	if (showTables)
-		appendPQExpBufferStr(&buf, CppAsString2(RELKIND_RELATION) ","
-							 CppAsString2(RELKIND_PARTITIONED_TABLE) ",");
+		appendPQExpBufferStr(&buf, RelKindAsString(RELKIND_RELATION) ","
+							 RelKindAsString(RELKIND_PARTITIONED_TABLE) ",");
 	if (showViews)
-		appendPQExpBufferStr(&buf, CppAsString2(RELKIND_VIEW) ",");
+		appendPQExpBufferStr(&buf, RelKindAsString(RELKIND_VIEW) ",");
 	if (showMatViews)
-		appendPQExpBufferStr(&buf, CppAsString2(RELKIND_MATVIEW) ",");
+		appendPQExpBufferStr(&buf, RelKindAsString(RELKIND_MATVIEW) ",");
 	if (showIndexes)
-		appendPQExpBufferStr(&buf, CppAsString2(RELKIND_INDEX) ","
-							 CppAsString2(RELKIND_PARTITIONED_INDEX) ",");
+		appendPQExpBufferStr(&buf, RelKindAsString(RELKIND_INDEX) ","
+							 RelKindAsString(RELKIND_PARTITIONED_INDEX) ",");
 	if (showSeq)
-		appendPQExpBufferStr(&buf, CppAsString2(RELKIND_SEQUENCE) ",");
+		appendPQExpBufferStr(&buf, RelKindAsString(RELKIND_SEQUENCE) ",");
 	if (showSystem || pattern)
 		appendPQExpBufferStr(&buf, "'s',"); /* was RELKIND_SPECIAL */
 	if (showForeign)
-		appendPQExpBufferStr(&buf, CppAsString2(RELKIND_FOREIGN_TABLE) ",");
+		appendPQExpBufferStr(&buf, RelKindAsString(RELKIND_FOREIGN_TABLE) ",");
 
 	appendPQExpBufferStr(&buf, "''");	/* dummy */
 	appendPQExpBufferStr(&buf, ")\n");
@@ -3921,8 +4051,8 @@ listPartitionedTables(const char *reltypes, const char *pattern, bool verbose)
 	{
 		appendPQExpBuffer(&buf,
 						  ",\n  CASE c.relkind"
-						  " WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
-						  " WHEN " CppAsString2(RELKIND_PARTITIONED_INDEX) " THEN '%s'"
+						  " WHEN " RelKindAsString(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
+						  " WHEN " RelKindAsString(RELKIND_PARTITIONED_INDEX) " THEN '%s'"
 						  " END as \"%s\"",
 						  gettext_noop("partitioned table"),
 						  gettext_noop("partitioned index"),
@@ -4012,9 +4142,9 @@ listPartitionedTables(const char *reltypes, const char *pattern, bool verbose)
 
 	appendPQExpBufferStr(&buf, "\nWHERE c.relkind IN (");
 	if (showTables)
-		appendPQExpBufferStr(&buf, CppAsString2(RELKIND_PARTITIONED_TABLE) ",");
+		appendPQExpBufferStr(&buf, RelKindAsString(RELKIND_PARTITIONED_TABLE) ",");
 	if (showIndexes)
-		appendPQExpBufferStr(&buf, CppAsString2(RELKIND_PARTITIONED_INDEX) ",");
+		appendPQExpBufferStr(&buf, RelKindAsString(RELKIND_PARTITIONED_INDEX) ",");
 	appendPQExpBufferStr(&buf, "''");	/* dummy */
 	appendPQExpBufferStr(&buf, ")\n");
 
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index eb018854a5..c56beb579b 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -354,7 +354,7 @@ static const SchemaQuery Query_for_list_of_datatypes = {
 	.catname = "pg_catalog.pg_type t",
 	/* selcondition --- ignore table rowtypes and array types */
 	.selcondition = "(t.typrelid = 0 "
-	" OR (SELECT c.relkind = " CppAsString2(RELKIND_COMPOSITE_TYPE)
+	" OR (SELECT c.relkind = " RelKindAsString(RELKIND_COMPOSITE_TYPE)
 	"     FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "
 	"AND t.typname !~ '^_'",
 	.viscondition = "pg_catalog.pg_type_is_visible(t.oid)",
@@ -366,7 +366,7 @@ static const SchemaQuery Query_for_list_of_datatypes = {
 static const SchemaQuery Query_for_list_of_composite_datatypes = {
 	.catname = "pg_catalog.pg_type t",
 	/* selcondition --- only get composite types */
-	.selcondition = "(SELECT c.relkind = " CppAsString2(RELKIND_COMPOSITE_TYPE)
+	.selcondition = "(SELECT c.relkind = " RelKindAsString(RELKIND_COMPOSITE_TYPE)
 	" FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid) "
 	"AND t.typname !~ '^_'",
 	.viscondition = "pg_catalog.pg_type_is_visible(t.oid)",
@@ -425,7 +425,7 @@ static const SchemaQuery Query_for_list_of_routines = {
 
 static const SchemaQuery Query_for_list_of_sequences = {
 	.catname = "pg_catalog.pg_class c",
-	.selcondition = "c.relkind IN (" CppAsString2(RELKIND_SEQUENCE) ")",
+	.selcondition = "c.relkind IN (" RelKindAsString(RELKIND_SEQUENCE) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -433,7 +433,7 @@ static const SchemaQuery Query_for_list_of_sequences = {
 
 static const SchemaQuery Query_for_list_of_foreign_tables = {
 	.catname = "pg_catalog.pg_class c",
-	.selcondition = "c.relkind IN (" CppAsString2(RELKIND_FOREIGN_TABLE) ")",
+	.selcondition = "c.relkind IN (" RelKindAsString(RELKIND_FOREIGN_TABLE) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -442,8 +442,8 @@ static const SchemaQuery Query_for_list_of_foreign_tables = {
 static const SchemaQuery Query_for_list_of_tables = {
 	.catname = "pg_catalog.pg_class c",
 	.selcondition =
-	"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-	CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
+	"c.relkind IN (" RelKindAsString(RELKIND_RELATION) ", "
+	RelKindAsString(RELKIND_PARTITIONED_TABLE) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -451,7 +451,7 @@ static const SchemaQuery Query_for_list_of_tables = {
 
 static const SchemaQuery Query_for_list_of_partitioned_tables = {
 	.catname = "pg_catalog.pg_class c",
-	.selcondition = "c.relkind IN (" CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
+	.selcondition = "c.relkind IN (" RelKindAsString(RELKIND_PARTITIONED_TABLE) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -459,7 +459,7 @@ static const SchemaQuery Query_for_list_of_partitioned_tables = {
 
 static const SchemaQuery Query_for_list_of_views = {
 	.catname = "pg_catalog.pg_class c",
-	.selcondition = "c.relkind IN (" CppAsString2(RELKIND_VIEW) ")",
+	.selcondition = "c.relkind IN (" RelKindAsString(RELKIND_VIEW) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -467,7 +467,7 @@ static const SchemaQuery Query_for_list_of_views = {
 
 static const SchemaQuery Query_for_list_of_matviews = {
 	.catname = "pg_catalog.pg_class c",
-	.selcondition = "c.relkind IN (" CppAsString2(RELKIND_MATVIEW) ")",
+	.selcondition = "c.relkind IN (" RelKindAsString(RELKIND_MATVIEW) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -476,8 +476,8 @@ static const SchemaQuery Query_for_list_of_matviews = {
 static const SchemaQuery Query_for_list_of_indexes = {
 	.catname = "pg_catalog.pg_class c",
 	.selcondition =
-	"c.relkind IN (" CppAsString2(RELKIND_INDEX) ", "
-	CppAsString2(RELKIND_PARTITIONED_INDEX) ")",
+	"c.relkind IN (" RelKindAsString(RELKIND_INDEX) ", "
+	RelKindAsString(RELKIND_PARTITIONED_INDEX) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -485,7 +485,7 @@ static const SchemaQuery Query_for_list_of_indexes = {
 
 static const SchemaQuery Query_for_list_of_partitioned_indexes = {
 	.catname = "pg_catalog.pg_class c",
-	.selcondition = "c.relkind = " CppAsString2(RELKIND_PARTITIONED_INDEX),
+	.selcondition = "c.relkind = " RelKindAsString(RELKIND_PARTITIONED_INDEX),
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -503,8 +503,8 @@ static const SchemaQuery Query_for_list_of_relations = {
 /* partitioned relations */
 static const SchemaQuery Query_for_list_of_partitioned_relations = {
 	.catname = "pg_catalog.pg_class c",
-	.selcondition = "c.relkind IN (" CppAsString2(RELKIND_PARTITIONED_TABLE)
-	", " CppAsString2(RELKIND_PARTITIONED_INDEX) ")",
+	.selcondition = "c.relkind IN (" RelKindAsString(RELKIND_PARTITIONED_TABLE)
+	", " RelKindAsString(RELKIND_PARTITIONED_INDEX) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -521,10 +521,10 @@ static const SchemaQuery Query_for_list_of_operator_families = {
 static const SchemaQuery Query_for_list_of_updatables = {
 	.catname = "pg_catalog.pg_class c",
 	.selcondition =
-	"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-	CppAsString2(RELKIND_FOREIGN_TABLE) ", "
-	CppAsString2(RELKIND_VIEW) ", "
-	CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
+	"c.relkind IN (" RelKindAsString(RELKIND_RELATION) ", "
+	RelKindAsString(RELKIND_FOREIGN_TABLE) ", "
+	RelKindAsString(RELKIND_VIEW) ", "
+	RelKindAsString(RELKIND_PARTITIONED_TABLE) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -534,12 +534,12 @@ static const SchemaQuery Query_for_list_of_updatables = {
 static const SchemaQuery Query_for_list_of_selectables = {
 	.catname = "pg_catalog.pg_class c",
 	.selcondition =
-	"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-	CppAsString2(RELKIND_SEQUENCE) ", "
-	CppAsString2(RELKIND_VIEW) ", "
-	CppAsString2(RELKIND_MATVIEW) ", "
-	CppAsString2(RELKIND_FOREIGN_TABLE) ", "
-	CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
+	"c.relkind IN (" RelKindAsString(RELKIND_RELATION) ", "
+	RelKindAsString(RELKIND_SEQUENCE) ", "
+	RelKindAsString(RELKIND_VIEW) ", "
+	RelKindAsString(RELKIND_MATVIEW) ", "
+	RelKindAsString(RELKIND_FOREIGN_TABLE) ", "
+	RelKindAsString(RELKIND_PARTITIONED_TABLE) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -552,10 +552,10 @@ static const SchemaQuery Query_for_list_of_selectables = {
 static const SchemaQuery Query_for_list_of_analyzables = {
 	.catname = "pg_catalog.pg_class c",
 	.selcondition =
-	"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-	CppAsString2(RELKIND_PARTITIONED_TABLE) ", "
-	CppAsString2(RELKIND_MATVIEW) ", "
-	CppAsString2(RELKIND_FOREIGN_TABLE) ")",
+	"c.relkind IN (" RelKindAsString(RELKIND_RELATION) ", "
+	RelKindAsString(RELKIND_PARTITIONED_TABLE) ", "
+	RelKindAsString(RELKIND_MATVIEW) ", "
+	RelKindAsString(RELKIND_FOREIGN_TABLE) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -565,9 +565,9 @@ static const SchemaQuery Query_for_list_of_analyzables = {
 static const SchemaQuery Query_for_list_of_indexables = {
 	.catname = "pg_catalog.pg_class c",
 	.selcondition =
-	"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-	CppAsString2(RELKIND_PARTITIONED_TABLE) ", "
-	CppAsString2(RELKIND_MATVIEW) ")",
+	"c.relkind IN (" RelKindAsString(RELKIND_RELATION) ", "
+	RelKindAsString(RELKIND_PARTITIONED_TABLE) ", "
+	RelKindAsString(RELKIND_MATVIEW) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
@@ -577,8 +577,8 @@ static const SchemaQuery Query_for_list_of_indexables = {
 static const SchemaQuery Query_for_list_of_vacuumables = {
 	.catname = "pg_catalog.pg_class c",
 	.selcondition =
-	"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
-	CppAsString2(RELKIND_MATVIEW) ")",
+	"c.relkind IN (" RelKindAsString(RELKIND_RELATION) ", "
+	RelKindAsString(RELKIND_MATVIEW) ")",
 	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
 	.namespace = "c.relnamespace",
 	.result = "pg_catalog.quote_ident(c.relname)",
diff --git a/src/bin/scripts/reindexdb.c b/src/bin/scripts/reindexdb.c
index b7b19ccc1c..1b921a1483 100644
--- a/src/bin/scripts/reindexdb.c
+++ b/src/bin/scripts/reindexdb.c
@@ -621,8 +621,8 @@ get_parallel_object_list(PGconn *conn, ReindexType type,
 							  " ON c.relnamespace = ns.oid\n"
 							  " WHERE ns.nspname != 'pg_catalog'\n"
 							  "   AND c.relkind IN ("
-							  CppAsString2(RELKIND_RELATION) ", "
-							  CppAsString2(RELKIND_MATVIEW) ")\n"
+							  RelKindAsString(RELKIND_RELATION) ", "
+							  RelKindAsString(RELKIND_MATVIEW) ")\n"
 							  " ORDER BY c.relpages DESC;");
 			break;
 
@@ -643,8 +643,8 @@ get_parallel_object_list(PGconn *conn, ReindexType type,
 								  " JOIN pg_catalog.pg_namespace ns"
 								  " ON c.relnamespace = ns.oid\n"
 								  " WHERE c.relkind IN ("
-								  CppAsString2(RELKIND_RELATION) ", "
-								  CppAsString2(RELKIND_MATVIEW) ")\n"
+								  RelKindAsString(RELKIND_RELATION) ", "
+								  RelKindAsString(RELKIND_MATVIEW) ")\n"
 								  " AND ns.nspname IN (");
 
 				for (cell = user_list->head; cell; cell = cell->next)
diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c
index 6a3c941158..9a90e820f4 100644
--- a/src/bin/scripts/vacuumdb.c
+++ b/src/bin/scripts/vacuumdb.c
@@ -573,8 +573,8 @@ vacuum_one_database(const char *dbname, vacuumingOptions *vacopts,
 	if (!tables_listed)
 	{
 		appendPQExpBufferStr(&catalog_query, " WHERE c.relkind OPERATOR(pg_catalog.=) ANY (array["
-							 CppAsString2(RELKIND_RELATION) ", "
-							 CppAsString2(RELKIND_MATVIEW) "])\n");
+							 RelKindAsString(RELKIND_RELATION) ", "
+							 RelKindAsString(RELKIND_MATVIEW) "])\n");
 		has_where = true;
 	}
 
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index 78b33b2a7f..4bd86703af 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -154,16 +154,44 @@ typedef FormData_pg_class *Form_pg_class;
 
 #ifdef EXPOSE_TO_CLIENT_CODE
 
-#define		  RELKIND_RELATION		  'r'	/* ordinary table */
-#define		  RELKIND_INDEX			  'i'	/* secondary index */
-#define		  RELKIND_SEQUENCE		  'S'	/* sequence object */
-#define		  RELKIND_TOASTVALUE	  't'	/* for out-of-line values */
-#define		  RELKIND_VIEW			  'v'	/* view */
-#define		  RELKIND_MATVIEW		  'm'	/* materialized view */
-#define		  RELKIND_COMPOSITE_TYPE  'c'	/* composite type */
-#define		  RELKIND_FOREIGN_TABLE   'f'	/* foreign table */
-#define		  RELKIND_PARTITIONED_TABLE 'p' /* partitioned table */
-#define		  RELKIND_PARTITIONED_INDEX 'I' /* partitioned index */
+typedef enum RelKind
+{
+	RELKIND_RELATION = 'r',				/* ordinary table */
+	RELKIND_INDEX = 'i',				/* secondary index */
+	RELKIND_SEQUENCE = 'S',				/* sequence object */
+	RELKIND_TOASTVALUE = 't',			/* for out-of-line values */
+	RELKIND_VIEW = 'v',					/* view */
+	RELKIND_MATVIEW = 'm',				/* materialized view */
+	RELKIND_COMPOSITE_TYPE = 'c',		/* composite type */
+	RELKIND_FOREIGN_TABLE = 'f',		/* foreign table */
+	RELKIND_PARTITIONED_TABLE = 'p',	/* partitioned table */
+	RELKIND_PARTITIONED_INDEX = 'I'		/* partitioned index */
+} RelKind;
+
+#define chr_RELKIND_RELATION			'r'
+#define chr_RELKIND_INDEX				'i'
+#define chr_RELKIND_SEQUENCE			'S'
+#define chr_RELKIND_TOASTVALUE			't'
+#define chr_RELKIND_VIEW				'v'
+#define chr_RELKIND_MATVIEW				'm'
+#define chr_RELKIND_COMPOSITE_TYPE		'c'
+#define chr_RELKIND_FOREIGN_TABLE		'f'
+#define chr_RELKIND_PARTITIONED_TABLE	'p'
+#define chr_RELKIND_PARTITIONED_INDEX	'I'
+
+#define RELKIND_IS_VALID(x) ( \
+	(x) == chr_RELKIND_RELATION				|| \
+	(x) == chr_RELKIND_INDEX				|| \
+	(x) == chr_RELKIND_SEQUENCE				|| \
+	(x) == chr_RELKIND_TOASTVALUE			|| \
+	(x) == chr_RELKIND_VIEW					|| \
+	(x) == chr_RELKIND_MATVIEW				|| \
+	(x) == chr_RELKIND_COMPOSITE_TYPE		|| \
+	(x) == chr_RELKIND_FOREIGN_TABLE		|| \
+	(x) == chr_RELKIND_PARTITIONED_TABLE	|| \
+	(x) == chr_RELKIND_PARTITIONED_INDEX )
+
+#define RelKindAsString(x) CppAsString2(chr_##x)
 
 #define		  RELPERSISTENCE_PERMANENT	'p' /* regular table */
 #define		  RELPERSISTENCE_UNLOGGED	'u' /* unlogged permanent table */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 6f96b31fb4..f72a241b7c 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -2110,7 +2110,7 @@ typedef struct AggregateInstrumentation
 	Size		hash_mem_peak;	/* peak hash table memory usage */
 	uint64		hash_disk_used; /* kB of disk space used */
 	int			hash_batches_used;	/* batches used during entire execution */
-} AggregateInstrumentation;
+}			AggregateInstrumentation;
 
 /* ----------------
  *	 Shared memory container for per-worker aggregate information
@@ -2120,7 +2120,7 @@ typedef struct SharedAggInfo
 {
 	int			num_workers;
 	AggregateInstrumentation sinstrument[FLEXIBLE_ARRAY_MEMBER];
-} SharedAggInfo;
+}			SharedAggInfo;
 
 /* ---------------------
  *	AggState information
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index b20e2ad4f6..65602a8763 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -81,7 +81,7 @@ typedef enum
 	PROC_WAIT_STATUS_OK,
 	PROC_WAIT_STATUS_WAITING,
 	PROC_WAIT_STATUS_ERROR,
-} ProcWaitStatus;
+}			ProcWaitStatus;
 
 /*
  * Each backend has a PGPROC struct in shared memory.  There is also a list of
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 3ca5e938f8..e5afbeddae 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -47,11 +47,11 @@ extern int	namestrcmp(Name name, const char *str);
 extern int32 pg_atoi(const char *s, int size, int c);
 extern int16 pg_strtoint16(const char *s);
 extern int32 pg_strtoint32(const char *s);
-extern int pg_itoa(int16 i, char *a);
-extern int pg_ultoa_n(uint32 l, char *a);
-extern int pg_ulltoa_n(uint64 l, char *a);
-extern int pg_ltoa(int32 l, char *a);
-extern int pg_lltoa(int64 ll, char *a);
+extern int	pg_itoa(int16 i, char *a);
+extern int	pg_ultoa_n(uint32 l, char *a);
+extern int	pg_ulltoa_n(uint64 l, char *a);
+extern int	pg_ltoa(int32 l, char *a);
+extern int	pg_lltoa(int64 ll, char *a);
 extern char *pg_ultostr_zeropad(char *str, uint32 value, int32 minwidth);
 extern char *pg_ultostr(char *str, uint32 value);
 extern uint64 pg_strtouint64(const char *str, char **endptr, int base);
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index e7f4a5f291..cefe979988 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -1723,14 +1723,22 @@ plpgsql_parse_cwordtype(List *idents)
 	 * It must be a relation, sequence, view, materialized view, composite
 	 * type, or foreign table
 	 */
-	if (classStruct->relkind != RELKIND_RELATION &&
-		classStruct->relkind != RELKIND_SEQUENCE &&
-		classStruct->relkind != RELKIND_VIEW &&
-		classStruct->relkind != RELKIND_MATVIEW &&
-		classStruct->relkind != RELKIND_COMPOSITE_TYPE &&
-		classStruct->relkind != RELKIND_FOREIGN_TABLE &&
-		classStruct->relkind != RELKIND_PARTITIONED_TABLE)
-		goto done;
+	Assert(RELKIND_IS_VALID((RelKind) classStruct->relkind));
+	switch ((RelKind) classStruct->relkind)
+	{
+		case RELKIND_RELATION:
+		case RELKIND_SEQUENCE:
+		case RELKIND_VIEW:
+		case RELKIND_MATVIEW:
+		case RELKIND_COMPOSITE_TYPE:
+		case RELKIND_FOREIGN_TABLE:
+		case RELKIND_PARTITIONED_TABLE:
+			break;
+		case RELKIND_PARTITIONED_INDEX:
+		case RELKIND_INDEX:
+		case RELKIND_TOASTVALUE:
+			goto done;
+	}
 
 	/*
 	 * Fetch the named table field and its type
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index 02397f2eb1..87453751b0 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -816,7 +816,7 @@ test_spinlock(void)
 			char		data_before[4];
 			slock_t		lock;
 			char		data_after[4];
-		} struct_w_lock;
+		}			struct_w_lock;
 
 		memcpy(struct_w_lock.data_before, "abcd", 4);
 		memcpy(struct_w_lock.data_after, "ef12", 4);
@@ -864,28 +864,28 @@ test_spinlock(void)
 	}
 
 	/*
-	 * Ensure that allocating more than INT32_MAX emulated spinlocks
-	 * works. That's interesting because the spinlock emulation uses a 32bit
-	 * integer to map spinlocks onto semaphores. There've been bugs...
+	 * Ensure that allocating more than INT32_MAX emulated spinlocks works.
+	 * That's interesting because the spinlock emulation uses a 32bit integer
+	 * to map spinlocks onto semaphores. There've been bugs...
 	 */
 #ifndef HAVE_SPINLOCKS
 	{
 		/*
-		 * Initialize enough spinlocks to advance counter close to
-		 * wraparound. It's too expensive to perform acquire/release for each,
-		 * as those may be syscalls when the spinlock emulation is used (and
-		 * even just atomic TAS would be expensive).
+		 * Initialize enough spinlocks to advance counter close to wraparound.
+		 * It's too expensive to perform acquire/release for each, as those
+		 * may be syscalls when the spinlock emulation is used (and even just
+		 * atomic TAS would be expensive).
 		 */
 		for (uint32 i = 0; i < INT32_MAX - 100000; i++)
 		{
-			slock_t lock;
+			slock_t		lock;
 
 			SpinLockInit(&lock);
 		}
 
 		for (uint32 i = 0; i < 200000; i++)
 		{
-			slock_t lock;
+			slock_t		lock;
 
 			SpinLockInit(&lock);
 
@@ -915,7 +915,7 @@ test_spinlock(void)
 static void
 test_atomic_spin_nest(void)
 {
-	slock_t lock;
+	slock_t		lock;
 #define NUM_TEST_ATOMICS (NUM_SPINLOCK_SEMAPHORES + NUM_ATOMICS_SEMAPHORES + 27)
 	pg_atomic_uint32 atomics32[NUM_TEST_ATOMICS];
 	pg_atomic_uint64 atomics64[NUM_TEST_ATOMICS];
diff --git a/src/tools/findoidjoins/findoidjoins.c b/src/tools/findoidjoins/findoidjoins.c
index 5239332ea7..3961804b10 100644
--- a/src/tools/findoidjoins/findoidjoins.c
+++ b/src/tools/findoidjoins/findoidjoins.c
@@ -62,7 +62,7 @@ main(int argc, char **argv)
 					  "SELECT c.relname, (SELECT nspname FROM "
 					  "pg_catalog.pg_namespace n WHERE n.oid = c.relnamespace) AS nspname "
 					  "FROM pg_catalog.pg_class c "
-					  "WHERE c.relkind = " CppAsString2(RELKIND_RELATION)
+					  "WHERE c.relkind = " RelKindAsString(RELKIND_RELATION)
 					  " AND c.oid < '%u'"
 					  " AND EXISTS(SELECT * FROM pg_attribute a"
 					  "            WHERE a.attrelid = c.oid AND a.attname = 'oid' "
@@ -88,7 +88,7 @@ main(int argc, char **argv)
 					  "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
 					  "WHERE a.attnum > 0"
 					  " AND a.attname != 'oid'"
-					  " AND c.relkind = " CppAsString2(RELKIND_RELATION)
+					  " AND c.relkind = " RelKindAsString(RELKIND_RELATION)
 					  " AND c.oid < '%u'"
 					  " AND a.attrelid = c.oid"
 					  " AND a.atttypid IN ('pg_catalog.oid'::regtype, "
@@ -166,7 +166,7 @@ main(int argc, char **argv)
 					  "a.attname "
 					  "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
 					  "WHERE a.attnum > 0"
-					  " AND c.relkind = " CppAsString2(RELKIND_RELATION)
+					  " AND c.relkind = " RelKindAsString(RELKIND_RELATION)
 					  " AND a.attrelid = c.oid"
 					  " AND a.atttypid IN ('pg_catalog.oid[]'::regtype, "
 					  " 'pg_catalog.oidvector'::regtype, "
-- 
2.21.1 (Apple Git-122.3)

#14Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Mark Dilger (#13)
Re: Towards easier AMs: Cleaning up inappropriate use of name "relkind"

This patch is way too large. Probably in part explained by the fact
that you seem to have run pgindent and absorbed a lot of unrelated
changes. This makes the patch essentially unreviewable.

I think you should define a RelationGetRelkind() static function that
returns the appropriate datatype without requiring a cast and assert in
every single place that processes a relation's relkind. Similarly
you've chosen to leave get_rel_relkind untouched, but that seems unwise.

I think the chr_ macros are pointless.

Reading back the thread, it seems that the whole point of your patch was
to change the tests that currently use 'if' tests to switch blocks. I
cannot understand what's the motivation for that, but it appears to me
that the approach is backwards: I'd counsel to *first* change the APIs
(get_rel_relkind and defining an enum, plus adding RelationGetRelkind)
so that everything is more sensible and safe, including appropriate
answers for the places where an "invalid" relkind is returned; and once
that's in place, replace if tests with switch blocks where it makes
sense to do so.

Also, I suggest that this thread is not a good one for this patch.
Subject is entirely not appropriate. Open a new thread perhaps?

--
�lvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#15Mark Dilger
mark.dilger@enterprisedb.com
In reply to: Alvaro Herrera (#14)
Refactoring relkind as an enum

On Jul 14, 2020, at 4:12 PM, Alvaro Herrera <alvherre@2ndquadrant.com> wrote:

This patch is way too large. Probably in part explained by the fact
that you seem to have run pgindent and absorbed a lot of unrelated
changes. This makes the patch essentially unreviewable.

I did not run pgindent, but when changing

if (relkind == RELKIND_INDEX)
{
/* foo */
}

to

switch (relkind)
{
case RELKIND_INDEX:
/* foo */
}

the indentation of /* foo */ changes. For large foo, that results in a lot of lines. There are also cases in the code where comparisons of multiple variables are mixed together. To split those out into switch/case statements I had to rearrange some of the code blocks.

I think you should define a RelationGetRelkind() static function that
returns the appropriate datatype without requiring a cast and assert in
every single place that processes a relation's relkind. Similarly
you've chosen to leave get_rel_relkind untouched, but that seems unwise.

I was well aware of how large the patch had gotten, and didn't want to add more....

I think the chr_ macros are pointless.

Look more closely at the #define RelKindAsString(x) CppAsString2(chr_##x)

Reading back the thread, it seems that the whole point of your patch was
to change the tests that currently use 'if' tests to switch blocks. I
cannot understand what's the motivation for that,

There might not be sufficient motivation to make the patch worth doing. The motivation was to leverage the project's recent addition of -Wswitch to make it easier to know which code needs updating when you add a new relkind. That doesn't happen very often, but I was working towards that kind of thing, and thought this might be a good prerequisite patch for that work. Stylistically, I also prefer

+       switch ((RelKind) rel->rd_rel->relkind)
+       {
+               case RELKIND_RELATION:
+               case RELKIND_MATVIEW:
+               case RELKIND_TOASTVALUE:

over

- if (rel->rd_rel->relkind == RELKIND_RELATION ||
- rel->rd_rel->relkind == RELKIND_MATVIEW ||
- rel->rd_rel->relkind == RELKIND_TOASTVALUE)

which is a somewhat common pattern in the code. It takes less mental effort to see that only one variable is being compared against those three enum values. In some cases, though not necessarily this exact example, it also *might* save duplicated work computing the variable, depending on the situation and what the compiler can optimize away.

but it appears to me
that the approach is backwards: I'd counsel to *first* change the APIs
(get_rel_relkind and defining an enum, plus adding RelationGetRelkind)
so that everything is more sensible and safe, including appropriate
answers for the places where an "invalid" relkind is returned;

Ok.

and once
that's in place, replace if tests with switch blocks where it makes
sense to do so.

Ok.

Also, I suggest that this thread is not a good one for this patch.
Subject is entirely not appropriate. Open a new thread perhaps?

I've changed the subject line.


Mark Dilger
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company