diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 1679776f019faf1a4ced3f9d809f5373c79481cb..bce0e076837f57857c8c19d82b08f5cb51b1f766 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -1284,6 +1284,7 @@ recordDependencyOnSingleRelExpr(const ObjectAddress *depender,
 	rte.type = T_RangeTblEntry;
 	rte.rtekind = RTE_RELATION;
 	rte.relid = relId;
+	rte.relkind = RELKIND_RELATION;		/* no need for exactness here */
 
 	context.rtables = list_make1(list_make1(&rte));
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 44f568f396414f69485ab0538b0086741e5068c9..3c504e96be2d3f426269bdbd61ef4632c6ceb75f 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -763,6 +763,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString)
 		rte = makeNode(RangeTblEntry);
 		rte->rtekind = RTE_RELATION;
 		rte->relid = RelationGetRelid(rel);
+		rte->relkind = rel->rd_rel->relkind;
 		rte->requiredPerms = required_access;
 
 		tupDesc = RelationGetDescr(rel);
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 1ba746bb4d893c0145e8376553c468d5b086fe1c..04763d44ebb6e38342d2c4d483e780e6b3360a4f 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -1927,6 +1927,7 @@ _copyRangeTblEntry(RangeTblEntry *from)
 
 	COPY_SCALAR_FIELD(rtekind);
 	COPY_SCALAR_FIELD(relid);
+	COPY_SCALAR_FIELD(relkind);
 	COPY_NODE_FIELD(subquery);
 	COPY_SCALAR_FIELD(jointype);
 	COPY_NODE_FIELD(joinaliasvars);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index dd332f19f00d91baec544229a6b98772028a9f5b..c896f49ff6f3a7d809063f13a2defc63f5c90e79 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -2286,6 +2286,7 @@ _equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b)
 {
 	COMPARE_SCALAR_FIELD(rtekind);
 	COMPARE_SCALAR_FIELD(relid);
+	COMPARE_SCALAR_FIELD(relkind);
 	COMPARE_NODE_FIELD(subquery);
 	COMPARE_SCALAR_FIELD(jointype);
 	COMPARE_NODE_FIELD(joinaliasvars);
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 8a23047d382e9474aa3eea0bffa89ac2259a3a81..d4b9242917197263578fd949c6c29b06a1b99a03 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -1671,7 +1671,6 @@ range_table_walker(List *rtable,
 		switch (rte->rtekind)
 		{
 			case RTE_RELATION:
-			case RTE_SPECIAL:
 			case RTE_CTE:
 				/* nothing to do */
 				break;
@@ -2374,7 +2373,6 @@ range_table_mutator(List *rtable,
 		switch (rte->rtekind)
 		{
 			case RTE_RELATION:
-			case RTE_SPECIAL:
 			case RTE_CTE:
 				/* we don't bother to copy eref, aliases, etc; OK? */
 				break;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 10f630e27f5b14f695540984feee31c096655ce2..706b2425cf2b1516b47128824083af1e0b127dad 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2275,8 +2275,8 @@ _outRangeTblEntry(StringInfo str, RangeTblEntry *node)
 	switch (node->rtekind)
 	{
 		case RTE_RELATION:
-		case RTE_SPECIAL:
 			WRITE_OID_FIELD(relid);
+			WRITE_CHAR_FIELD(relkind);
 			break;
 		case RTE_SUBQUERY:
 			WRITE_NODE_FIELD(subquery);
diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c
index 14487f25a1044cfa240f3cdc1ad4bfb0d41551f1..cd119dbabb8c78a72af30a0902397680328c26db 100644
--- a/src/backend/nodes/print.c
+++ b/src/backend/nodes/print.c
@@ -265,8 +265,8 @@ print_rt(List *rtable)
 		switch (rte->rtekind)
 		{
 			case RTE_RELATION:
-				printf("%d\t%s\t%u",
-					   i, rte->eref->aliasname, rte->relid);
+				printf("%d\t%s\t%u\t%c",
+					   i, rte->eref->aliasname, rte->relid, rte->relkind);
 				break;
 			case RTE_SUBQUERY:
 				printf("%d\t%s\t[subquery]",
@@ -276,10 +276,6 @@ print_rt(List *rtable)
 				printf("%d\t%s\t[join]",
 					   i, rte->eref->aliasname);
 				break;
-			case RTE_SPECIAL:
-				printf("%d\t%s\t[special]",
-					   i, rte->eref->aliasname);
-				break;
 			case RTE_FUNCTION:
 				printf("%d\t%s\t[rangefunction]",
 					   i, rte->eref->aliasname);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index b007caeee3e1ecb4238632e53c7de6c2b3328c8e..c76884e991f4b2eeca8a38b4ef32ae24017b86f8 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1171,8 +1171,8 @@ _readRangeTblEntry(void)
 	switch (local_node->rtekind)
 	{
 		case RTE_RELATION:
-		case RTE_SPECIAL:
 			READ_OID_FIELD(relid);
+			READ_CHAR_FIELD(relkind);
 			break;
 		case RTE_SUBQUERY:
 			READ_NODE_FIELD(subquery);
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index c835a954ed97b29e87adb933af5078f27fc9971b..dc2a23bb2737313b43e1e6d7b272119863693cbc 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -176,41 +176,44 @@ set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
 		/* It's an "append relation", process accordingly */
 		set_append_rel_pathlist(root, rel, rti, rte);
 	}
-	else if (rel->rtekind == RTE_SUBQUERY)
-	{
-		/* Subquery --- generate a separate plan for it */
-		set_subquery_pathlist(root, rel, rti, rte);
-	}
-	else if (rel->rtekind == RTE_FUNCTION)
-	{
-		/* RangeFunction --- generate a suitable path for it */
-		set_function_pathlist(root, rel, rte);
-	}
-	else if (rel->rtekind == RTE_VALUES)
-	{
-		/* Values list --- generate a suitable path for it */
-		set_values_pathlist(root, rel, rte);
-	}
-	else if (rel->rtekind == RTE_CTE)
-	{
-		/* CTE reference --- generate a suitable path for it */
-		if (rte->self_reference)
-			set_worktable_pathlist(root, rel, rte);
-		else
-			set_cte_pathlist(root, rel, rte);
-	}
 	else
 	{
-		Assert(rel->rtekind == RTE_RELATION);
-		if (get_rel_relkind(rte->relid) == RELKIND_FOREIGN_TABLE)
-		{
-			/* Foreign table */
-			set_foreign_pathlist(root, rel, rte);
-		}
-		else
+		switch (rel->rtekind)
 		{
-			/* Plain relation */
-			set_plain_rel_pathlist(root, rel, rte);
+			case RTE_RELATION:
+				if (rte->relkind == RELKIND_FOREIGN_TABLE)
+				{
+					/* Foreign table */
+					set_foreign_pathlist(root, rel, rte);
+				}
+				else
+				{
+					/* Plain relation */
+					set_plain_rel_pathlist(root, rel, rte);
+				}
+				break;
+			case RTE_SUBQUERY:
+				/* Subquery --- generate a separate plan for it */
+				set_subquery_pathlist(root, rel, rti, rte);
+				break;
+			case RTE_FUNCTION:
+				/* RangeFunction --- generate a suitable path for it */
+				set_function_pathlist(root, rel, rte);
+				break;
+			case RTE_VALUES:
+				/* Values list --- generate a suitable path for it */
+				set_values_pathlist(root, rel, rte);
+				break;
+			case RTE_CTE:
+				/* CTE reference --- generate a suitable path for it */
+				if (rte->self_reference)
+					set_worktable_pathlist(root, rel, rte);
+				else
+					set_cte_pathlist(root, rel, rte);
+				break;
+			default:
+				elog(ERROR, "unexpected rtekind: %d", (int) rel->rtekind);
+				break;
 		}
 	}
 
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index b73b872b3128f40b9a4bcfff01fd2e1aac20f62c..ee09673051ff0e03f61622d5fee7c8d151886b87 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -1915,7 +1915,7 @@ preprocess_rowmarks(PlannerInfo *root)
 		newrc->rowmarkId = ++(root->glob->lastRowMarkId);
 		/* real tables support REFERENCE, anything else needs COPY */
 		if (rte->rtekind == RTE_RELATION &&
-			get_rel_relkind(rte->relid) != RELKIND_FOREIGN_TABLE)
+			rte->relkind != RELKIND_FOREIGN_TABLE)
 			newrc->markType = ROW_MARK_REFERENCE;
 		else
 			newrc->markType = ROW_MARK_COPY;
@@ -3078,6 +3078,7 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
 	rte = makeNode(RangeTblEntry);
 	rte->rtekind = RTE_RELATION;
 	rte->relid = tableOid;
+	rte->relkind = RELKIND_RELATION;
 	rte->inh = false;
 	rte->inFromCl = true;
 	query->rtable = list_make1(rte);
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index c7a7a230767889d332c037d866d42160e8e8f7f9..7f28d9df4f5ea701d21162a00da96e1bf3c5af1c 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -40,7 +40,6 @@
 #include "parser/parse_target.h"
 #include "parser/parsetree.h"
 #include "rewrite/rewriteManip.h"
-#include "utils/lsyscache.h"
 #include "utils/rel.h"
 
 
@@ -2178,13 +2177,11 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
 			{
 				case RTE_RELATION:
 					/* ignore foreign tables */
-					if (get_rel_relkind(rte->relid) != RELKIND_FOREIGN_TABLE)
-					{
-						applyLockingClause(qry, i,
-										   lc->forUpdate, lc->noWait,
-										   pushedDown);
-						rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;
-					}
+					if (rte->relkind == RELKIND_FOREIGN_TABLE)
+						break;
+					applyLockingClause(qry, i,
+									   lc->forUpdate, lc->noWait, pushedDown);
+					rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;
 					break;
 				case RTE_SUBQUERY:
 					applyLockingClause(qry, i,
@@ -2231,11 +2228,11 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
 					switch (rte->rtekind)
 					{
 						case RTE_RELATION:
-							if (get_rel_relkind(rte->relid) == RELKIND_FOREIGN_TABLE)
+							if (rte->relkind == RELKIND_FOREIGN_TABLE)
 								ereport(ERROR,
 										(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 										 errmsg("SELECT FOR UPDATE/SHARE cannot be used with foreign table \"%s\"",
-												get_rel_name(rte->relid)),
+												rte->eref->aliasname),
 										 parser_errposition(pstate, thisrel->location)));
 							applyLockingClause(qry, i,
 											   lc->forUpdate, lc->noWait,
@@ -2256,12 +2253,6 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
 									 errmsg("SELECT FOR UPDATE/SHARE cannot be applied to a join"),
 							 parser_errposition(pstate, thisrel->location)));
 							break;
-						case RTE_SPECIAL:
-							ereport(ERROR,
-									(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-									 errmsg("SELECT FOR UPDATE/SHARE cannot be applied to NEW or OLD"),
-							 parser_errposition(pstate, thisrel->location)));
-							break;
 						case RTE_FUNCTION:
 							ereport(ERROR,
 									(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 497c726f31455fc6f24a0533bc3c411ce545e87b..033ed411fde92d7bd60c9889d6e0872be73e9a7f 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -894,6 +894,7 @@ addRangeTableEntry(ParseState *pstate,
 	lockmode = isLockedRefname(pstate, refname) ? RowShareLock : AccessShareLock;
 	rel = parserOpenTable(pstate, relation, lockmode);
 	rte->relid = RelationGetRelid(rel);
+	rte->relkind = rel->rd_rel->relkind;
 
 	/*
 	 * Build the list of effective column names using user-supplied aliases
@@ -956,6 +957,7 @@ addRangeTableEntryForRelation(ParseState *pstate,
 	rte->rtekind = RTE_RELATION;
 	rte->alias = alias;
 	rte->relid = RelationGetRelid(rel);
+	rte->relkind = rel->rd_rel->relkind;
 
 	/*
 	 * Build the list of effective column names using user-supplied aliases
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index a0761da875be78c7387bc0053e6b68f2852eab9b..e9ace37e2d803fd47b132ca228f16465dce5851f 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -305,7 +305,6 @@ markTargetListOrigin(ParseState *pstate, TargetEntry *tle,
 				markTargetListOrigin(pstate, tle, aliasvar, netlevelsup);
 			}
 			break;
-		case RTE_SPECIAL:
 		case RTE_FUNCTION:
 		case RTE_VALUES:
 			/* not a simple relation, leave it unmarked */
@@ -1357,7 +1356,6 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
 	switch (rte->rtekind)
 	{
 		case RTE_RELATION:
-		case RTE_SPECIAL:
 		case RTE_VALUES:
 
 			/*
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 3a50642fce8008d6b99b816515022cd10773d232..c0d25b15c60c3e20e887fa976cb3641b7352c6fd 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -144,6 +144,13 @@ AcquireRewriteLocks(Query *parsetree, bool forUpdatePushedDown)
 					lockmode = AccessShareLock;
 
 				rel = heap_open(rte->relid, lockmode);
+
+				/*
+				 * While we have the relation open, update the RTE's relkind,
+				 * just in case it changed since this rule was made.
+				 */
+				rte->relkind = rel->rd_rel->relkind;
+
 				heap_close(rel, NoLock);
 				break;
 
@@ -1393,7 +1400,7 @@ markQueryForLocking(Query *qry, Node *jtnode,
 		if (rte->rtekind == RTE_RELATION)
 		{
 			/* ignore foreign tables */
-			if (get_rel_relkind(rte->relid) != RELKIND_FOREIGN_TABLE)
+			if (rte->relkind != RELKIND_FOREIGN_TABLE)
 			{
 				applyLockingClause(qry, rti, forUpdate, noWait, pushedDown);
 				rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;
diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c
index 5ef1563d1c95a47b823b5032d11351d81204ad8a..591d2eb16b00e643107f53a75ae6157df4cc6f83 100644
--- a/src/backend/utils/adt/ri_triggers.c
+++ b/src/backend/utils/adt/ri_triggers.c
@@ -2651,11 +2651,13 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
 	pkrte = makeNode(RangeTblEntry);
 	pkrte->rtekind = RTE_RELATION;
 	pkrte->relid = RelationGetRelid(pk_rel);
+	pkrte->relkind = pk_rel->rd_rel->relkind;
 	pkrte->requiredPerms = ACL_SELECT;
 
 	fkrte = makeNode(RangeTblEntry);
 	fkrte->rtekind = RTE_RELATION;
 	fkrte->relid = RelationGetRelid(fk_rel);
+	fkrte->relkind = fk_rel->rd_rel->relkind;
 	fkrte->requiredPerms = ACL_SELECT;
 
 	for (i = 0; i < riinfo.nkeys; i++)
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index cd64235438e9f3b89a5e7eb40f08be09c4889a91..d9b359465a2fc96a10ee5b04ce3025da04473002 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -628,6 +628,7 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
 	if (!isnull)
 	{
 		Node	   *qual;
+		char		relkind;
 		deparse_context context;
 		deparse_namespace dpns;
 		RangeTblEntry *oldrte;
@@ -637,10 +638,13 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
 
 		qual = stringToNode(TextDatumGetCString(value));
 
+		relkind = get_rel_relkind(trigrec->tgrelid);
+
 		/* Build minimal OLD and NEW RTEs for the rel */
 		oldrte = makeNode(RangeTblEntry);
 		oldrte->rtekind = RTE_RELATION;
 		oldrte->relid = trigrec->tgrelid;
+		oldrte->relkind = relkind;
 		oldrte->eref = makeAlias("old", NIL);
 		oldrte->inh = false;
 		oldrte->inFromCl = true;
@@ -648,6 +652,7 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
 		newrte = makeNode(RangeTblEntry);
 		newrte->rtekind = RTE_RELATION;
 		newrte->relid = trigrec->tgrelid;
+		newrte->relkind = relkind;
 		newrte->eref = makeAlias("new", NIL);
 		newrte->inh = false;
 		newrte->inFromCl = true;
@@ -2125,6 +2130,7 @@ deparse_context_for(const char *aliasname, Oid relid)
 	rte = makeNode(RangeTblEntry);
 	rte->rtekind = RTE_RELATION;
 	rte->relid = relid;
+	rte->relkind = RELKIND_RELATION;	/* no need for exactness here */
 	rte->eref = makeAlias(aliasname, NIL);
 	rte->inh = false;
 	rte->inFromCl = true;
@@ -4004,7 +4010,6 @@ get_name_for_var_field(Var *var, int fieldno,
 	switch (rte->rtekind)
 	{
 		case RTE_RELATION:
-		case RTE_SPECIAL:
 		case RTE_VALUES:
 
 			/*
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 70106414cfe2b4e643a188de021657933cd12066..0a0544bc38aba4a930e33ef84e9e3e7ab23f3a5d 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	201102221
+#define CATALOG_VERSION_NO	201102222
 
 #endif
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index 42bc8635a249558b4d70222ee70f6fa342a90fb1..e103530a3f24c582fd6643761e2cccdcffad3119 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -49,7 +49,7 @@ CATALOG(pg_class,1259) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83) BKI_SCHEMA_MACRO
 	Oid			reltoastidxid;	/* if toast table, OID of chunk_id index */
 	bool		relhasindex;	/* T if has (or has had) any indexes */
 	bool		relisshared;	/* T if shared across databases */
-	char		relpersistence;	/* see RELPERSISTENCE_xxx constants */
+	char		relpersistence;	/* see RELPERSISTENCE_xxx constants below */
 	char		relkind;		/* see RELKIND_xxx constants below */
 	int2		relnatts;		/* number of user attributes */
 
@@ -139,17 +139,18 @@ DESCR("");
 DATA(insert OID = 1259 (  pg_class		PGNSP 83 0 PGUID 0 0 0 0 0 0 0 f f p r 26 0 t f f f f 3 _null_ _null_ ));
 DESCR("");
 
+
+#define		  RELKIND_RELATION		  'r'		/* ordinary table */
 #define		  RELKIND_INDEX			  'i'		/* secondary index */
-#define		  RELKIND_RELATION		  'r'		/* ordinary cataloged heap */
-#define		  RELKIND_SEQUENCE		  'S'		/* SEQUENCE relation */
-#define		  RELKIND_UNCATALOGED	  'u'		/* temporary heap */
-#define		  RELKIND_TOASTVALUE	  't'		/* moved off huge values */
+#define		  RELKIND_SEQUENCE		  'S'		/* sequence object */
+#define		  RELKIND_TOASTVALUE	  't'		/* for out-of-line values */
 #define		  RELKIND_VIEW			  'v'		/* view */
 #define		  RELKIND_COMPOSITE_TYPE  'c'		/* composite type */
 #define		  RELKIND_FOREIGN_TABLE	  'f'		/* foreign table */
+#define		  RELKIND_UNCATALOGED	  'u'		/* not yet cataloged */
 
-#define		  RELPERSISTENCE_PERMANENT	'p'
-#define		  RELPERSISTENCE_UNLOGGED	'u'
-#define		  RELPERSISTENCE_TEMP		't'
+#define		  RELPERSISTENCE_PERMANENT	'p'		/* regular table */
+#define		  RELPERSISTENCE_UNLOGGED	'u'		/* unlogged permanent table */
+#define		  RELPERSISTENCE_TEMP		't'		/* temporary table */
 
 #endif   /* PG_CLASS_H */
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 63a61e3da248b2a1677d35eb56ff2b82b9c53b64..536c03245e3335da7b1d49e8cbb70d607fdbb387 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -597,6 +597,9 @@ typedef struct XmlSerialize
  *	  like outer joins and join-output-column aliasing.)  Other special
  *	  RTE types also exist, as indicated by RTEKind.
  *
+ *	  Note that we consider RTE_RELATION to cover anything that has a pg_class
+ *	  entry.  relkind distinguishes the sub-cases.
+ *
  *	  alias is an Alias node representing the AS alias-clause attached to the
  *	  FROM expression, or NULL if no clause.
  *
@@ -643,7 +646,7 @@ typedef struct XmlSerialize
  *	  indicates no permissions checking).  If checkAsUser is not zero,
  *	  then do the permissions checks using the access rights of that user,
  *	  not the current effective user ID.  (This allows rules to act as
- *	  setuid gateways.)
+ *	  setuid gateways.)  Permissions checks only apply to RELATION RTEs.
  *
  *	  For SELECT/INSERT/UPDATE permissions, if the user doesn't have
  *	  table-wide permissions then it is sufficient to have the permissions
@@ -660,7 +663,6 @@ typedef enum RTEKind
 	RTE_RELATION,				/* ordinary relation reference */
 	RTE_SUBQUERY,				/* subquery in FROM */
 	RTE_JOIN,					/* join */
-	RTE_SPECIAL,				/* special rule relation (NEW or OLD) */
 	RTE_FUNCTION,				/* function in FROM */
 	RTE_VALUES,					/* VALUES (<exprlist>), (<exprlist>), ... */
 	RTE_CTE						/* common table expr (WITH list element) */
@@ -682,6 +684,7 @@ typedef struct RangeTblEntry
 	 * Fields valid for a plain relation RTE (else zero):
 	 */
 	Oid			relid;			/* OID of the relation */
+	char		relkind;		/* relation kind (see pg_class.relkind) */
 
 	/*
 	 * Fields valid for a subquery RTE (else NULL):