diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 1e8f618a3476b9e171658900f92532b87b3cde97..33252a8e205abc3726ffb32c5615ef6fa64e28a8 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -51,6 +51,10 @@ static void ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es,
 static void report_triggers(ResultRelInfo *rInfo, bool show_relname,
 				ExplainState *es);
 static double elapsed_time(instr_time *starttime);
+static void ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used);
+static void ExplainPreScanMemberNodes(List *plans, PlanState **planstates,
+						  Bitmapset **rels_used);
+static void ExplainPreScanSubPlans(List *plans, Bitmapset **rels_used);
 static void ExplainNode(PlanState *planstate, List *ancestors,
 			const char *relationship, const char *plan_name,
 			ExplainState *es);
@@ -539,9 +543,13 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es,
 void
 ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
 {
+	Bitmapset  *rels_used = NULL;
+
 	Assert(queryDesc->plannedstmt != NULL);
 	es->pstmt = queryDesc->plannedstmt;
 	es->rtable = queryDesc->plannedstmt->rtable;
+	ExplainPreScanNode(queryDesc->planstate, &rels_used);
+	es->rtable_names = select_rtable_names_for_explain(es->rtable, rels_used);
 	ExplainNode(queryDesc->planstate, NIL, NULL, NULL, es);
 }
 
@@ -640,6 +648,132 @@ elapsed_time(instr_time *starttime)
 	return INSTR_TIME_GET_DOUBLE(endtime);
 }
 
+/*
+ * ExplainPreScanNode -
+ *	  Prescan the planstate tree to identify which RTEs are referenced
+ *
+ * Adds the relid of each referenced RTE to *rels_used.  The result controls
+ * which RTEs are assigned aliases by select_rtable_names_for_explain.	This
+ * ensures that we don't confusingly assign un-suffixed aliases to RTEs that
+ * never appear in the EXPLAIN output (such as inheritance parents).
+ */
+static void
+ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
+{
+	Plan	   *plan = planstate->plan;
+
+	switch (nodeTag(plan))
+	{
+		case T_SeqScan:
+		case T_IndexScan:
+		case T_IndexOnlyScan:
+		case T_BitmapHeapScan:
+		case T_TidScan:
+		case T_SubqueryScan:
+		case T_FunctionScan:
+		case T_ValuesScan:
+		case T_CteScan:
+		case T_WorkTableScan:
+		case T_ForeignScan:
+			*rels_used = bms_add_member(*rels_used,
+										((Scan *) plan)->scanrelid);
+			break;
+		case T_ModifyTable:
+			/* cf ExplainModifyTarget */
+			*rels_used = bms_add_member(*rels_used,
+					  linitial_int(((ModifyTable *) plan)->resultRelations));
+			break;
+		default:
+			break;
+	}
+
+	/* initPlan-s */
+	if (planstate->initPlan)
+		ExplainPreScanSubPlans(planstate->initPlan, rels_used);
+
+	/* lefttree */
+	if (outerPlanState(planstate))
+		ExplainPreScanNode(outerPlanState(planstate), rels_used);
+
+	/* righttree */
+	if (innerPlanState(planstate))
+		ExplainPreScanNode(innerPlanState(planstate), rels_used);
+
+	/* special child plans */
+	switch (nodeTag(plan))
+	{
+		case T_ModifyTable:
+			ExplainPreScanMemberNodes(((ModifyTable *) plan)->plans,
+								  ((ModifyTableState *) planstate)->mt_plans,
+									  rels_used);
+			break;
+		case T_Append:
+			ExplainPreScanMemberNodes(((Append *) plan)->appendplans,
+									((AppendState *) planstate)->appendplans,
+									  rels_used);
+			break;
+		case T_MergeAppend:
+			ExplainPreScanMemberNodes(((MergeAppend *) plan)->mergeplans,
+								((MergeAppendState *) planstate)->mergeplans,
+									  rels_used);
+			break;
+		case T_BitmapAnd:
+			ExplainPreScanMemberNodes(((BitmapAnd *) plan)->bitmapplans,
+								 ((BitmapAndState *) planstate)->bitmapplans,
+									  rels_used);
+			break;
+		case T_BitmapOr:
+			ExplainPreScanMemberNodes(((BitmapOr *) plan)->bitmapplans,
+								  ((BitmapOrState *) planstate)->bitmapplans,
+									  rels_used);
+			break;
+		case T_SubqueryScan:
+			ExplainPreScanNode(((SubqueryScanState *) planstate)->subplan,
+							   rels_used);
+			break;
+		default:
+			break;
+	}
+
+	/* subPlan-s */
+	if (planstate->subPlan)
+		ExplainPreScanSubPlans(planstate->subPlan, rels_used);
+}
+
+/*
+ * Prescan the constituent plans of a ModifyTable, Append, MergeAppend,
+ * BitmapAnd, or BitmapOr node.
+ *
+ * Note: we don't actually need to examine the Plan list members, but
+ * we need the list in order to determine the length of the PlanState array.
+ */
+static void
+ExplainPreScanMemberNodes(List *plans, PlanState **planstates,
+						  Bitmapset **rels_used)
+{
+	int			nplans = list_length(plans);
+	int			j;
+
+	for (j = 0; j < nplans; j++)
+		ExplainPreScanNode(planstates[j], rels_used);
+}
+
+/*
+ * Prescan a list of SubPlans (or initPlans, which also use SubPlan nodes).
+ */
+static void
+ExplainPreScanSubPlans(List *plans, Bitmapset **rels_used)
+{
+	ListCell   *lst;
+
+	foreach(lst, plans)
+	{
+		SubPlanState *sps = (SubPlanState *) lfirst(lst);
+
+		ExplainPreScanNode(sps->planstate, rels_used);
+	}
+}
+
 /*
  * ExplainNode -
  *	  Appends a description of a plan tree to es->str
@@ -1440,7 +1574,8 @@ show_plan_tlist(PlanState *planstate, List *ancestors, ExplainState *es)
 	/* Set up deparsing context */
 	context = deparse_context_for_planstate((Node *) planstate,
 											ancestors,
-											es->rtable);
+											es->rtable,
+											es->rtable_names);
 	useprefix = list_length(es->rtable) > 1;
 
 	/* Deparse each result column (we now include resjunk ones) */
@@ -1471,7 +1606,8 @@ show_expression(Node *node, const char *qlabel,
 	/* Set up deparsing context */
 	context = deparse_context_for_planstate((Node *) planstate,
 											ancestors,
-											es->rtable);
+											es->rtable,
+											es->rtable_names);
 
 	/* Deparse the expression */
 	exprstr = deparse_expression(node, context, useprefix, false);
@@ -1573,7 +1709,8 @@ show_sort_keys_common(PlanState *planstate, int nkeys, AttrNumber *keycols,
 	/* Set up deparsing context */
 	context = deparse_context_for_planstate((Node *) planstate,
 											ancestors,
-											es->rtable);
+											es->rtable,
+											es->rtable_names);
 	useprefix = (list_length(es->rtable) > 1 || es->verbose);
 
 	for (keyno = 0; keyno < nkeys; keyno++)
@@ -1813,8 +1950,10 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
 	char	   *namespace = NULL;
 	const char *objecttag = NULL;
 	RangeTblEntry *rte;
+	char	   *refname;
 
 	rte = rt_fetch(rti, es->rtable);
+	refname = (char *) list_nth(es->rtable_names, rti - 1);
 
 	switch (nodeTag(plan))
 	{
@@ -1887,10 +2026,9 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
 							 quote_identifier(objectname));
 		else if (objectname != NULL)
 			appendStringInfo(es->str, " %s", quote_identifier(objectname));
-		if (objectname == NULL ||
-			strcmp(rte->eref->aliasname, objectname) != 0)
-			appendStringInfo(es->str, " %s",
-							 quote_identifier(rte->eref->aliasname));
+		if (refname != NULL &&
+			(objectname == NULL || strcmp(refname, objectname) != 0))
+			appendStringInfo(es->str, " %s", quote_identifier(refname));
 	}
 	else
 	{
@@ -1898,7 +2036,8 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
 			ExplainPropertyText(objecttag, objectname, es);
 		if (namespace != NULL)
 			ExplainPropertyText("Schema", namespace, es);
-		ExplainPropertyText("Alias", rte->eref->aliasname, es);
+		if (refname != NULL)
+			ExplainPropertyText("Alias", refname, es);
 	}
 }
 
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 08396431384a8f8581492304c8c916c41e4b9516..c8d7d9c21b3a4398008160da844e83e8330e8ad4 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -104,7 +104,9 @@ typedef struct
  * the current context's namespaces list.
  *
  * The rangetable is the list of actual RTEs from the query tree, and the
- * cte list is the list of actual CTEs.
+ * cte list is the list of actual CTEs.  rtable_names holds the alias name
+ * to be used for each RTE (either a C string, or NULL for nameless RTEs
+ * such as unnamed joins).
  *
  * When deparsing plan trees, there is always just a single item in the
  * deparse_namespace list (since a plan tree never contains Vars with
@@ -119,6 +121,7 @@ typedef struct
 typedef struct
 {
 	List	   *rtable;			/* List of RangeTblEntry nodes */
+	List	   *rtable_names;	/* Parallel list of names for RTEs */
 	List	   *ctes;			/* List of CommonTableExpr nodes */
 	/* Remaining fields are used only when deparsing a Plan tree: */
 	PlanState  *planstate;		/* immediate parent of current expression */
@@ -172,6 +175,11 @@ static text *pg_get_expr_worker(text *expr, Oid relid, const char *relname,
 static int print_function_arguments(StringInfo buf, HeapTuple proctup,
 						 bool print_table_args, bool print_defaults);
 static void print_function_rettype(StringInfo buf, HeapTuple proctup);
+static void set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
+				 Bitmapset *rels_used);
+static bool refname_is_unique(char *refname, deparse_namespace *dpns,
+				  List *parent_namespaces);
+static char *get_rtable_name(int rtindex, deparse_context *context);
 static void set_deparse_planstate(deparse_namespace *dpns, PlanState *ps);
 static void push_child_plan(deparse_namespace *dpns, PlanState *ps,
 				deparse_namespace *save_dpns);
@@ -212,8 +220,6 @@ static void get_rule_windowspec(WindowClause *wc, List *targetList,
 					deparse_context *context);
 static char *get_variable(Var *var, int levelsup, bool istoplevel,
 			 deparse_context *context);
-static RangeTblEntry *find_rte_by_refname(const char *refname,
-					deparse_context *context);
 static Node *find_param_referent(Param *param, deparse_context *context,
 					deparse_namespace **dpns_p, ListCell **ancestor_cell_p);
 static void get_parameter(Param *param, deparse_context *context);
@@ -676,7 +682,8 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
 		oldrte->rtekind = RTE_RELATION;
 		oldrte->relid = trigrec->tgrelid;
 		oldrte->relkind = relkind;
-		oldrte->eref = makeAlias("old", NIL);
+		oldrte->alias = makeAlias("old", NIL);
+		oldrte->eref = oldrte->alias;
 		oldrte->lateral = false;
 		oldrte->inh = false;
 		oldrte->inFromCl = true;
@@ -685,7 +692,8 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
 		newrte->rtekind = RTE_RELATION;
 		newrte->relid = trigrec->tgrelid;
 		newrte->relkind = relkind;
-		newrte->eref = makeAlias("new", NIL);
+		newrte->alias = makeAlias("new", NIL);
+		newrte->eref = newrte->alias;
 		newrte->lateral = false;
 		newrte->inh = false;
 		newrte->inFromCl = true;
@@ -694,6 +702,7 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
 		memset(&dpns, 0, sizeof(dpns));
 		dpns.rtable = list_make2(oldrte, newrte);
 		dpns.ctes = NIL;
+		set_rtable_names(&dpns, NIL, NULL);
 
 		/* Set up context with one-deep namespace stack */
 		context.buf = &buf;
@@ -2176,7 +2185,8 @@ deparse_context_for(const char *aliasname, Oid relid)
 	rte->rtekind = RTE_RELATION;
 	rte->relid = relid;
 	rte->relkind = RELKIND_RELATION;	/* no need for exactness here */
-	rte->eref = makeAlias(aliasname, NIL);
+	rte->alias = makeAlias(aliasname, NIL);
+	rte->eref = rte->alias;
 	rte->lateral = false;
 	rte->inh = false;
 	rte->inFromCl = true;
@@ -2184,6 +2194,7 @@ deparse_context_for(const char *aliasname, Oid relid)
 	/* Build one-element rtable */
 	dpns->rtable = list_make1(rte);
 	dpns->ctes = NIL;
+	set_rtable_names(dpns, NIL, NULL);
 
 	/* Return a one-deep namespace stack */
 	return list_make1(dpns);
@@ -2209,13 +2220,14 @@ deparse_context_for(const char *aliasname, Oid relid)
  * most-closely-nested first.  This is needed to resolve PARAM_EXEC Params.
  * Note we assume that all the PlanStates share the same rtable.
  *
- * The plan's rangetable list must also be passed.  We actually prefer to use
- * the rangetable to resolve simple Vars, but the plan inputs are necessary
- * for Vars with special varnos.
+ * The plan's rangetable list must also be passed, along with the per-RTE
+ * alias names assigned by a previous call to select_rtable_names_for_explain.
+ * (We use the rangetable to resolve simple Vars, but the plan inputs are
+ * necessary for Vars with special varnos.)
  */
 List *
 deparse_context_for_planstate(Node *planstate, List *ancestors,
-							  List *rtable)
+							  List *rtable, List *rtable_names)
 {
 	deparse_namespace *dpns;
 
@@ -2223,6 +2235,7 @@ deparse_context_for_planstate(Node *planstate, List *ancestors,
 
 	/* Initialize fields that stay the same across the whole plan tree */
 	dpns->rtable = rtable;
+	dpns->rtable_names = rtable_names;
 	dpns->ctes = NIL;
 
 	/* Set our attention on the specific plan node passed in */
@@ -2233,6 +2246,142 @@ deparse_context_for_planstate(Node *planstate, List *ancestors,
 	return list_make1(dpns);
 }
 
+/*
+ * select_rtable_names_for_explain	- Select RTE aliases for EXPLAIN
+ *
+ * Determine the aliases we'll use during an EXPLAIN operation.  This is
+ * just a frontend to set_rtable_names.  We have to expose the aliases
+ * to EXPLAIN because EXPLAIN needs to know the right alias names to print.
+ */
+List *
+select_rtable_names_for_explain(List *rtable, Bitmapset *rels_used)
+{
+	deparse_namespace dpns;
+
+	memset(&dpns, 0, sizeof(dpns));
+	dpns.rtable = rtable;
+	dpns.ctes = NIL;
+	set_rtable_names(&dpns, NIL, rels_used);
+
+	return dpns.rtable_names;
+}
+
+/*
+ * set_rtable_names: select RTE aliases to be used in printing variables
+ *
+ * We fill in dpns->rtable_names with a list of names that is one-for-one with
+ * the already-filled dpns->rtable list.  Each RTE name is unique among those
+ * in the new namespace plus any ancestor namespaces listed in
+ * parent_namespaces.
+ *
+ * If rels_used isn't NULL, only RTE indexes listed in it are given aliases.
+ */
+static void
+set_rtable_names(deparse_namespace *dpns, List *parent_namespaces,
+				 Bitmapset *rels_used)
+{
+	ListCell   *lc;
+	int			rtindex = 1;
+
+	dpns->rtable_names = NIL;
+	foreach(lc, dpns->rtable)
+	{
+		RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
+		char	   *refname;
+
+		if (rels_used && !bms_is_member(rtindex, rels_used))
+		{
+			/* Ignore unreferenced RTE */
+			refname = NULL;
+		}
+		else if (rte->alias)
+		{
+			/* If RTE has a user-defined alias, prefer that */
+			refname = rte->alias->aliasname;
+		}
+		else if (rte->rtekind == RTE_RELATION)
+		{
+			/* Use the current actual name of the relation */
+			refname = get_rel_name(rte->relid);
+		}
+		else if (rte->rtekind == RTE_JOIN)
+		{
+			/* Unnamed join has no refname */
+			refname = NULL;
+		}
+		else
+		{
+			/* Otherwise use whatever the parser assigned */
+			refname = rte->eref->aliasname;
+		}
+
+		/*
+		 * If the selected name isn't unique, append digits to make it so
+		 */
+		if (refname &&
+			!refname_is_unique(refname, dpns, parent_namespaces))
+		{
+			char	   *modname = (char *) palloc(strlen(refname) + 32);
+			int			i = 0;
+
+			do
+			{
+				sprintf(modname, "%s_%d", refname, ++i);
+			} while (!refname_is_unique(modname, dpns, parent_namespaces));
+			refname = modname;
+		}
+
+		dpns->rtable_names = lappend(dpns->rtable_names, refname);
+		rtindex++;
+	}
+}
+
+/*
+ * refname_is_unique: is refname distinct from all already-chosen RTE names?
+ */
+static bool
+refname_is_unique(char *refname, deparse_namespace *dpns,
+				  List *parent_namespaces)
+{
+	ListCell   *lc;
+
+	foreach(lc, dpns->rtable_names)
+	{
+		char	   *oldname = (char *) lfirst(lc);
+
+		if (oldname && strcmp(oldname, refname) == 0)
+			return false;
+	}
+	foreach(lc, parent_namespaces)
+	{
+		deparse_namespace *olddpns = (deparse_namespace *) lfirst(lc);
+		ListCell   *lc2;
+
+		foreach(lc2, olddpns->rtable_names)
+		{
+			char	   *oldname = (char *) lfirst(lc2);
+
+			if (oldname && strcmp(oldname, refname) == 0)
+				return false;
+		}
+	}
+	return true;
+}
+
+/*
+ * get_rtable_name: convenience function to get a previously assigned RTE alias
+ *
+ * The RTE must belong to the topmost namespace level in "context".
+ */
+static char *
+get_rtable_name(int rtindex, deparse_context *context)
+{
+	deparse_namespace *dpns = (deparse_namespace *) linitial(context->namespaces);
+
+	Assert(rtindex > 0 && rtindex <= list_length(dpns->rtable_names));
+	return (char *) list_nth(dpns->rtable_names, rtindex - 1);
+}
+
 /*
  * set_deparse_planstate: set up deparse_namespace to parse subexpressions
  * of a given PlanState node
@@ -2534,6 +2683,7 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
 		memset(&dpns, 0, sizeof(dpns));
 		dpns.rtable = query->rtable;
 		dpns.ctes = query->cteList;
+		set_rtable_names(&dpns, NIL, NULL);
 
 		get_rule_expr(qual, &context, false);
 	}
@@ -2680,6 +2830,7 @@ get_query_def(Query *query, StringInfo buf, List *parentnamespace,
 	memset(&dpns, 0, sizeof(dpns));
 	dpns.rtable = query->rtable;
 	dpns.ctes = query->cteList;
+	set_rtable_names(&dpns, parentnamespace, NULL);
 
 	switch (query->commandType)
 	{
@@ -2899,7 +3050,6 @@ get_select_query_def(Query *query, deparse_context *context,
 		foreach(l, query->rowMarks)
 		{
 			RowMarkClause *rc = (RowMarkClause *) lfirst(l);
-			RangeTblEntry *rte = rt_fetch(rc->rti, query->rtable);
 
 			/* don't print implicit clauses */
 			if (rc->pushedDown)
@@ -2912,7 +3062,8 @@ get_select_query_def(Query *query, deparse_context *context,
 				appendContextKeyword(context, " FOR SHARE",
 									 -PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
 			appendStringInfo(buf, " OF %s",
-							 quote_identifier(rte->eref->aliasname));
+							 quote_identifier(get_rtable_name(rc->rti,
+															  context)));
 			if (rc->noWait)
 				appendStringInfo(buf, " NOWAIT");
 		}
@@ -3854,7 +4005,6 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
 	AttrNumber	attnum;
 	int			netlevelsup;
 	deparse_namespace *dpns;
-	char	   *schemaname;
 	char	   *refname;
 	char	   *attname;
 
@@ -3874,6 +4024,7 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
 	if (var->varno >= 1 && var->varno <= list_length(dpns->rtable))
 	{
 		rte = rt_fetch(var->varno, dpns->rtable);
+		refname = (char *) list_nth(dpns->rtable_names, var->varno - 1);
 		attnum = var->varattno;
 	}
 	else if (var->varno == OUTER_VAR && dpns->outer_tlist)
@@ -3993,61 +4144,41 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
 		return NULL;
 	}
 
-	/* Identify names to use */
-	schemaname = NULL;			/* default assumptions */
-	refname = rte->eref->aliasname;
-
-	/* Exceptions occur only if the RTE is alias-less */
-	if (rte->alias == NULL)
+	/*
+	 * If it's an unnamed join, look at the expansion of the alias variable.
+	 * If it's a simple reference to one of the input vars, then recursively
+	 * print the name of that var instead.	(This allows correct decompiling
+	 * of cases where there are identically named columns on both sides of the
+	 * join.)  When it's not a simple reference, we have to just print the
+	 * unqualified variable name (this can only happen with columns that were
+	 * merged by USING or NATURAL clauses).
+	 *
+	 * This wouldn't work in decompiling plan trees, because we don't store
+	 * joinaliasvars lists after planning; but a plan tree should never
+	 * contain a join alias variable.
+	 */
+	if (rte->rtekind == RTE_JOIN && rte->alias == NULL)
 	{
-		if (rte->rtekind == RTE_RELATION)
-		{
-			/*
-			 * It's possible that use of the bare refname would find another
-			 * more-closely-nested RTE, or be ambiguous, in which case we need
-			 * to specify the schemaname to avoid these errors.
-			 */
-			if (find_rte_by_refname(rte->eref->aliasname, context) != rte)
-				schemaname = get_namespace_name(get_rel_namespace(rte->relid));
-		}
-		else if (rte->rtekind == RTE_JOIN)
+		if (rte->joinaliasvars == NIL)
+			elog(ERROR, "cannot decompile join alias var in plan tree");
+		if (attnum > 0)
 		{
-			/*
-			 * If it's an unnamed join, look at the expansion of the alias
-			 * variable.  If it's a simple reference to one of the input vars
-			 * then recursively print the name of that var, instead. (This
-			 * allows correct decompiling of cases where there are identically
-			 * named columns on both sides of the join.) When it's not a
-			 * simple reference, we have to just print the unqualified
-			 * variable name (this can only happen with columns that were
-			 * merged by USING or NATURAL clauses).
-			 *
-			 * This wouldn't work in decompiling plan trees, because we don't
-			 * store joinaliasvars lists after planning; but a plan tree
-			 * should never contain a join alias variable.
-			 */
-			if (rte->joinaliasvars == NIL)
-				elog(ERROR, "cannot decompile join alias var in plan tree");
-			if (attnum > 0)
-			{
-				Var		   *aliasvar;
+			Var		   *aliasvar;
 
-				aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
-				if (IsA(aliasvar, Var))
-				{
-					return get_variable(aliasvar, var->varlevelsup + levelsup,
-										istoplevel, context);
-				}
+			aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);
+			if (IsA(aliasvar, Var))
+			{
+				return get_variable(aliasvar, var->varlevelsup + levelsup,
+									istoplevel, context);
 			}
-
-			/*
-			 * Unnamed join has neither schemaname nor refname.  (Note: since
-			 * it's unnamed, there is no way the user could have referenced it
-			 * to create a whole-row Var for it.  So we don't have to cover
-			 * that case below.)
-			 */
-			refname = NULL;
 		}
+
+		/*
+		 * Unnamed join has no refname.  (Note: since it's unnamed, there is
+		 * no way the user could have referenced it to create a whole-row Var
+		 * for it.	So we don't have to cover that case below.)
+		 */
+		Assert(refname == NULL);
 	}
 
 	if (attnum == InvalidAttrNumber)
@@ -4057,9 +4188,6 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
 
 	if (refname && (context->varprefix || attname == NULL))
 	{
-		if (schemaname)
-			appendStringInfo(buf, "%s.",
-							 quote_identifier(schemaname));
 		appendStringInfoString(buf, quote_identifier(refname));
 		appendStringInfoChar(buf, '.');
 	}
@@ -4289,6 +4417,7 @@ get_name_for_var_field(Var *var, int fieldno,
 						memset(&mydpns, 0, sizeof(mydpns));
 						mydpns.rtable = rte->subquery->rtable;
 						mydpns.ctes = rte->subquery->cteList;
+						set_rtable_names(&mydpns, context->namespaces, NULL);
 
 						context->namespaces = lcons(&mydpns,
 													context->namespaces);
@@ -4406,6 +4535,7 @@ get_name_for_var_field(Var *var, int fieldno,
 						memset(&mydpns, 0, sizeof(mydpns));
 						mydpns.rtable = ctequery->rtable;
 						mydpns.ctes = ctequery->cteList;
+						set_rtable_names(&mydpns, context->namespaces, NULL);
 
 						new_nslist = list_copy_tail(context->namespaces,
 													ctelevelsup);
@@ -4467,47 +4597,6 @@ get_name_for_var_field(Var *var, int fieldno,
 	return NameStr(tupleDesc->attrs[fieldno - 1]->attname);
 }
 
-
-/*
- * find_rte_by_refname		- look up an RTE by refname in a deparse context
- *
- * Returns NULL if there is no matching RTE or the refname is ambiguous.
- *
- * NOTE: this code is not really correct since it does not take account of
- * the fact that not all the RTEs in a rangetable may be visible from the
- * point where a Var reference appears.  For the purposes we need, however,
- * the only consequence of a false match is that we might stick a schema
- * qualifier on a Var that doesn't really need it.  So it seems close
- * enough.
- */
-static RangeTblEntry *
-find_rte_by_refname(const char *refname, deparse_context *context)
-{
-	RangeTblEntry *result = NULL;
-	ListCell   *nslist;
-
-	foreach(nslist, context->namespaces)
-	{
-		deparse_namespace *dpns = (deparse_namespace *) lfirst(nslist);
-		ListCell   *rtlist;
-
-		foreach(rtlist, dpns->rtable)
-		{
-			RangeTblEntry *rte = (RangeTblEntry *) lfirst(rtlist);
-
-			if (strcmp(rte->eref->aliasname, refname) == 0)
-			{
-				if (result)
-					return NULL;	/* it's ambiguous */
-				result = rte;
-			}
-		}
-		if (result)
-			break;
-	}
-	return result;
-}
-
 /*
  * Try to find the referenced expression for a PARAM_EXEC Param that might
  * reference a parameter supplied by an upper NestLoop or SubPlan plan node.
@@ -6649,6 +6738,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
 	{
 		int			varno = ((RangeTblRef *) jtnode)->rtindex;
 		RangeTblEntry *rte = rt_fetch(varno, query->rtable);
+		char	   *refname = get_rtable_name(varno, context);
 		bool		gavealias = false;
 
 		if (rte->lateral)
@@ -6688,32 +6778,31 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
 
 		if (rte->alias != NULL)
 		{
-			appendStringInfo(buf, " %s",
-							 quote_identifier(rte->alias->aliasname));
+			/* Always print alias if user provided one */
+			appendStringInfo(buf, " %s", quote_identifier(refname));
 			gavealias = true;
 		}
-		else if (rte->rtekind == RTE_RELATION &&
-			strcmp(rte->eref->aliasname, get_relation_name(rte->relid)) != 0)
+		else if (rte->rtekind == RTE_RELATION)
 		{
 			/*
-			 * Apparently the rel has been renamed since the rule was made.
-			 * Emit a fake alias clause so that variable references will still
-			 * work.  This is not a 100% solution but should work in most
-			 * reasonable situations.
+			 * No need to print alias if it's same as relation name (this
+			 * would normally be the case, but not if set_rtable_names had to
+			 * resolve a conflict).
 			 */
-			appendStringInfo(buf, " %s",
-							 quote_identifier(rte->eref->aliasname));
-			gavealias = true;
+			if (strcmp(refname, get_relation_name(rte->relid)) != 0)
+			{
+				appendStringInfo(buf, " %s", quote_identifier(refname));
+				gavealias = true;
+			}
 		}
 		else if (rte->rtekind == RTE_FUNCTION)
 		{
 			/*
-			 * For a function RTE, always give an alias. This covers possible
+			 * For a function RTE, always print alias.  This covers possible
 			 * renaming of the function and/or instability of the
 			 * FigureColname rules for things that aren't simple functions.
 			 */
-			appendStringInfo(buf, " %s",
-							 quote_identifier(rte->eref->aliasname));
+			appendStringInfo(buf, " %s", quote_identifier(refname));
 			gavealias = true;
 		}
 
diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h
index c4215da1e329102df3289f9c88a732f51f90503e..4227f4e59c3d07cee8d0fc95660010705ce5e13b 100644
--- a/src/include/commands/explain.h
+++ b/src/include/commands/explain.h
@@ -37,6 +37,7 @@ typedef struct ExplainState
 	/* other states */
 	PlannedStmt *pstmt;			/* top of plan */
 	List	   *rtable;			/* range table */
+	List	   *rtable_names;	/* alias names for RTEs */
 	int			indent;			/* current indentation level */
 	List	   *grouping_stack; /* format-specific grouping state */
 } ExplainState;
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index c9c665dae09c08a726c04ed58591d63e3b1b3347..5bc3a75856d8efe53ed50064ae71d15711b2beaf 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -654,7 +654,9 @@ extern char *deparse_expression(Node *expr, List *dpcontext,
 				   bool forceprefix, bool showimplicit);
 extern List *deparse_context_for(const char *aliasname, Oid relid);
 extern List *deparse_context_for_planstate(Node *planstate, List *ancestors,
-							  List *rtable);
+							  List *rtable, List *rtable_names);
+extern List *select_rtable_names_for_explain(List *rtable,
+								Bitmapset *rels_used);
 extern const char *quote_identifier(const char *ident);
 extern char *quote_qualified_identifier(const char *qualifier,
 						   const char *ident);
diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out
index 6ca73a0ed73fc9c2fa18701f17fa34b7f12db131..7286f1aa446ffc0f3b0d0527daf2a5bbba34713e 100644
--- a/src/test/regress/expected/aggregates.out
+++ b/src/test/regress/expected/aggregates.out
@@ -705,32 +705,32 @@ insert into minmaxtest2 values(15), (16);
 insert into minmaxtest3 values(17), (18);
 explain (costs off)
   select min(f1), max(f1) from minmaxtest;
-                                        QUERY PLAN                                         
--------------------------------------------------------------------------------------------
+                                          QUERY PLAN                                          
+----------------------------------------------------------------------------------------------
  Result
    InitPlan 1 (returns $0)
      ->  Limit
            ->  Merge Append
-                 Sort Key: public.minmaxtest.f1
+                 Sort Key: minmaxtest.f1
                  ->  Index Only Scan using minmaxtesti on minmaxtest
                        Index Cond: (f1 IS NOT NULL)
-                 ->  Index Only Scan using minmaxtest1i on minmaxtest1 minmaxtest
+                 ->  Index Only Scan using minmaxtest1i on minmaxtest1
                        Index Cond: (f1 IS NOT NULL)
-                 ->  Index Only Scan Backward using minmaxtest2i on minmaxtest2 minmaxtest
+                 ->  Index Only Scan Backward using minmaxtest2i on minmaxtest2
                        Index Cond: (f1 IS NOT NULL)
-                 ->  Index Only Scan using minmaxtest3i on minmaxtest3 minmaxtest
+                 ->  Index Only Scan using minmaxtest3i on minmaxtest3
                        Index Cond: (f1 IS NOT NULL)
    InitPlan 2 (returns $1)
      ->  Limit
            ->  Merge Append
-                 Sort Key: public.minmaxtest.f1
-                 ->  Index Only Scan Backward using minmaxtesti on minmaxtest
+                 Sort Key: minmaxtest_1.f1
+                 ->  Index Only Scan Backward using minmaxtesti on minmaxtest minmaxtest_1
                        Index Cond: (f1 IS NOT NULL)
-                 ->  Index Only Scan Backward using minmaxtest1i on minmaxtest1 minmaxtest
+                 ->  Index Only Scan Backward using minmaxtest1i on minmaxtest1 minmaxtest1_1
                        Index Cond: (f1 IS NOT NULL)
-                 ->  Index Only Scan using minmaxtest2i on minmaxtest2 minmaxtest
+                 ->  Index Only Scan using minmaxtest2i on minmaxtest2 minmaxtest2_1
                        Index Cond: (f1 IS NOT NULL)
-                 ->  Index Only Scan Backward using minmaxtest3i on minmaxtest3 minmaxtest
+                 ->  Index Only Scan Backward using minmaxtest3i on minmaxtest3 minmaxtest3_1
                        Index Cond: (f1 IS NOT NULL)
 (25 rows)
 
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 453a3894b202873b31dada5727e7e09ae3f2f142..c22d74c7b562e86d6e839b4ab3a87d3cf7a29149 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -391,9 +391,9 @@ explain (costs off) select * from nv_parent where d between '2011-08-01' and '20
    ->  Append
          ->  Seq Scan on nv_parent
                Filter: ((d >= '08-01-2011'::date) AND (d <= '08-31-2011'::date))
-         ->  Seq Scan on nv_child_2010 nv_parent
+         ->  Seq Scan on nv_child_2010
                Filter: ((d >= '08-01-2011'::date) AND (d <= '08-31-2011'::date))
-         ->  Seq Scan on nv_child_2011 nv_parent
+         ->  Seq Scan on nv_child_2011
                Filter: ((d >= '08-01-2011'::date) AND (d <= '08-31-2011'::date))
 (8 rows)
 
@@ -405,9 +405,9 @@ explain (costs off) select * from nv_parent where d between '2011-08-01'::date a
    ->  Append
          ->  Seq Scan on nv_parent
                Filter: ((d >= '08-01-2011'::date) AND (d <= '08-31-2011'::date))
-         ->  Seq Scan on nv_child_2010 nv_parent
+         ->  Seq Scan on nv_child_2010
                Filter: ((d >= '08-01-2011'::date) AND (d <= '08-31-2011'::date))
-         ->  Seq Scan on nv_child_2011 nv_parent
+         ->  Seq Scan on nv_child_2011
                Filter: ((d >= '08-01-2011'::date) AND (d <= '08-31-2011'::date))
 (8 rows)
 
@@ -418,11 +418,11 @@ explain (costs off) select * from nv_parent where d between '2009-08-01'::date a
    ->  Append
          ->  Seq Scan on nv_parent
                Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
-         ->  Seq Scan on nv_child_2010 nv_parent
+         ->  Seq Scan on nv_child_2010
                Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
-         ->  Seq Scan on nv_child_2011 nv_parent
+         ->  Seq Scan on nv_child_2011
                Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
-         ->  Seq Scan on nv_child_2009 nv_parent
+         ->  Seq Scan on nv_child_2009
                Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
 (10 rows)
 
@@ -435,9 +435,9 @@ explain (costs off) select * from nv_parent where d between '2009-08-01'::date a
    ->  Append
          ->  Seq Scan on nv_parent
                Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
-         ->  Seq Scan on nv_child_2010 nv_parent
+         ->  Seq Scan on nv_child_2010
                Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
-         ->  Seq Scan on nv_child_2009 nv_parent
+         ->  Seq Scan on nv_child_2009
                Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
 (8 rows)
 
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index cc93854c423084e1e0a1afdc6d9d67f4c22235e8..d37c88234a279cd48286bbaadb7b6f42104a51ef 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -288,8 +288,368 @@ SELECT relname, relkind, reloptions FROM pg_class
  mysecview4 | v       | {security_barrier=false}
 (4 rows)
 
+-- Test view decompilation in the face of renaming conflicts
+CREATE TABLE tt1 (f1 int, f2 int, f3 text);
+CREATE TABLE tx1 (x1 int, x2 int, x3 text);
+CREATE TABLE temp_view_test.tt1 (y1 int, f2 int, f3 text);
+CREATE VIEW aliased_view_1 AS
+  select * from tt1
+    where exists (select 1 from tx1 where tt1.f1 = tx1.x1);
+CREATE VIEW aliased_view_2 AS
+  select * from tt1 a1
+    where exists (select 1 from tx1 where a1.f1 = tx1.x1);
+CREATE VIEW aliased_view_3 AS
+  select * from tt1
+    where exists (select 1 from tx1 a2 where tt1.f1 = a2.x1);
+CREATE VIEW aliased_view_4 AS
+  select * from temp_view_test.tt1
+    where exists (select 1 from tt1 where temp_view_test.tt1.y1 = tt1.f1);
+\d+ aliased_view_1
+          View "testviewschm2.aliased_view_1"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ f1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT tt1.f1, tt1.f2, tt1.f3
+   FROM tt1
+  WHERE (EXISTS ( SELECT 1
+           FROM tx1
+          WHERE tt1.f1 = tx1.x1));
+
+\d+ aliased_view_2
+          View "testviewschm2.aliased_view_2"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ f1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT a1.f1, a1.f2, a1.f3
+   FROM tt1 a1
+  WHERE (EXISTS ( SELECT 1
+           FROM tx1
+          WHERE a1.f1 = tx1.x1));
+
+\d+ aliased_view_3
+          View "testviewschm2.aliased_view_3"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ f1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT tt1.f1, tt1.f2, tt1.f3
+   FROM tt1
+  WHERE (EXISTS ( SELECT 1
+           FROM tx1 a2
+          WHERE tt1.f1 = a2.x1));
+
+\d+ aliased_view_4
+          View "testviewschm2.aliased_view_4"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ y1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT tt1.y1, tt1.f2, tt1.f3
+   FROM temp_view_test.tt1
+  WHERE (EXISTS ( SELECT 1
+           FROM tt1 tt1_1
+          WHERE tt1.y1 = tt1_1.f1));
+
+ALTER TABLE tx1 RENAME TO a1;
+\d+ aliased_view_1
+          View "testviewschm2.aliased_view_1"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ f1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT tt1.f1, tt1.f2, tt1.f3
+   FROM tt1
+  WHERE (EXISTS ( SELECT 1
+           FROM a1
+          WHERE tt1.f1 = a1.x1));
+
+\d+ aliased_view_2
+          View "testviewschm2.aliased_view_2"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ f1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT a1.f1, a1.f2, a1.f3
+   FROM tt1 a1
+  WHERE (EXISTS ( SELECT 1
+           FROM a1 a1_1
+          WHERE a1.f1 = a1_1.x1));
+
+\d+ aliased_view_3
+          View "testviewschm2.aliased_view_3"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ f1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT tt1.f1, tt1.f2, tt1.f3
+   FROM tt1
+  WHERE (EXISTS ( SELECT 1
+           FROM a1 a2
+          WHERE tt1.f1 = a2.x1));
+
+\d+ aliased_view_4
+          View "testviewschm2.aliased_view_4"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ y1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT tt1.y1, tt1.f2, tt1.f3
+   FROM temp_view_test.tt1
+  WHERE (EXISTS ( SELECT 1
+           FROM tt1 tt1_1
+          WHERE tt1.y1 = tt1_1.f1));
+
+ALTER TABLE tt1 RENAME TO a2;
+\d+ aliased_view_1
+          View "testviewschm2.aliased_view_1"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ f1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT a2.f1, a2.f2, a2.f3
+   FROM a2
+  WHERE (EXISTS ( SELECT 1
+           FROM a1
+          WHERE a2.f1 = a1.x1));
+
+\d+ aliased_view_2
+          View "testviewschm2.aliased_view_2"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ f1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT a1.f1, a1.f2, a1.f3
+   FROM a2 a1
+  WHERE (EXISTS ( SELECT 1
+           FROM a1 a1_1
+          WHERE a1.f1 = a1_1.x1));
+
+\d+ aliased_view_3
+          View "testviewschm2.aliased_view_3"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ f1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT a2.f1, a2.f2, a2.f3
+   FROM a2
+  WHERE (EXISTS ( SELECT 1
+           FROM a1 a2_1
+          WHERE a2.f1 = a2_1.x1));
+
+\d+ aliased_view_4
+          View "testviewschm2.aliased_view_4"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ y1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT tt1.y1, tt1.f2, tt1.f3
+   FROM temp_view_test.tt1
+  WHERE (EXISTS ( SELECT 1
+           FROM a2
+          WHERE tt1.y1 = a2.f1));
+
+ALTER TABLE a1 RENAME TO tt1;
+\d+ aliased_view_1
+          View "testviewschm2.aliased_view_1"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ f1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT a2.f1, a2.f2, a2.f3
+   FROM a2
+  WHERE (EXISTS ( SELECT 1
+           FROM tt1
+          WHERE a2.f1 = tt1.x1));
+
+\d+ aliased_view_2
+          View "testviewschm2.aliased_view_2"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ f1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT a1.f1, a1.f2, a1.f3
+   FROM a2 a1
+  WHERE (EXISTS ( SELECT 1
+           FROM tt1
+          WHERE a1.f1 = tt1.x1));
+
+\d+ aliased_view_3
+          View "testviewschm2.aliased_view_3"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ f1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT a2.f1, a2.f2, a2.f3
+   FROM a2
+  WHERE (EXISTS ( SELECT 1
+           FROM tt1 a2_1
+          WHERE a2.f1 = a2_1.x1));
+
+\d+ aliased_view_4
+          View "testviewschm2.aliased_view_4"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ y1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT tt1.y1, tt1.f2, tt1.f3
+   FROM temp_view_test.tt1
+  WHERE (EXISTS ( SELECT 1
+           FROM a2
+          WHERE tt1.y1 = a2.f1));
+
+ALTER TABLE a2 RENAME TO tx1;
+ALTER TABLE tx1 SET SCHEMA temp_view_test;
+\d+ aliased_view_1
+          View "testviewschm2.aliased_view_1"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ f1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT tx1.f1, tx1.f2, tx1.f3
+   FROM temp_view_test.tx1
+  WHERE (EXISTS ( SELECT 1
+           FROM tt1
+          WHERE tx1.f1 = tt1.x1));
+
+\d+ aliased_view_2
+          View "testviewschm2.aliased_view_2"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ f1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT a1.f1, a1.f2, a1.f3
+   FROM temp_view_test.tx1 a1
+  WHERE (EXISTS ( SELECT 1
+           FROM tt1
+          WHERE a1.f1 = tt1.x1));
+
+\d+ aliased_view_3
+          View "testviewschm2.aliased_view_3"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ f1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT tx1.f1, tx1.f2, tx1.f3
+   FROM temp_view_test.tx1
+  WHERE (EXISTS ( SELECT 1
+           FROM tt1 a2
+          WHERE tx1.f1 = a2.x1));
+
+\d+ aliased_view_4
+          View "testviewschm2.aliased_view_4"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ y1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT tt1.y1, tt1.f2, tt1.f3
+   FROM temp_view_test.tt1
+  WHERE (EXISTS ( SELECT 1
+           FROM temp_view_test.tx1
+          WHERE tt1.y1 = tx1.f1));
+
+ALTER TABLE temp_view_test.tt1 RENAME TO tmp1;
+ALTER TABLE temp_view_test.tmp1 SET SCHEMA testviewschm2;
+ALTER TABLE tmp1 RENAME TO tx1;
+\d+ aliased_view_1
+          View "testviewschm2.aliased_view_1"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ f1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT tx1.f1, tx1.f2, tx1.f3
+   FROM temp_view_test.tx1
+  WHERE (EXISTS ( SELECT 1
+           FROM tt1
+          WHERE tx1.f1 = tt1.x1));
+
+\d+ aliased_view_2
+          View "testviewschm2.aliased_view_2"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ f1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT a1.f1, a1.f2, a1.f3
+   FROM temp_view_test.tx1 a1
+  WHERE (EXISTS ( SELECT 1
+           FROM tt1
+          WHERE a1.f1 = tt1.x1));
+
+\d+ aliased_view_3
+          View "testviewschm2.aliased_view_3"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ f1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT tx1.f1, tx1.f2, tx1.f3
+   FROM temp_view_test.tx1
+  WHERE (EXISTS ( SELECT 1
+           FROM tt1 a2
+          WHERE tx1.f1 = a2.x1));
+
+\d+ aliased_view_4
+          View "testviewschm2.aliased_view_4"
+ Column |  Type   | Modifiers | Storage  | Description 
+--------+---------+-----------+----------+-------------
+ y1     | integer |           | plain    | 
+ f2     | integer |           | plain    | 
+ f3     | text    |           | extended | 
+View definition:
+ SELECT tx1.y1, tx1.f2, tx1.f3
+   FROM tx1
+  WHERE (EXISTS ( SELECT 1
+           FROM temp_view_test.tx1 tx1_1
+          WHERE tx1.y1 = tx1_1.f1));
+
 DROP SCHEMA temp_view_test CASCADE;
-NOTICE:  drop cascades to 22 other objects
+NOTICE:  drop cascades to 27 other objects
 DETAIL:  drop cascades to table temp_view_test.base_table
 drop cascades to view v7_temp
 drop cascades to view v10_temp
@@ -312,8 +672,13 @@ drop cascades to view temp_view_test.v7
 drop cascades to view temp_view_test.v8
 drop cascades to sequence temp_view_test.seq1
 drop cascades to view temp_view_test.v9
+drop cascades to table temp_view_test.tx1
+drop cascades to view aliased_view_1
+drop cascades to view aliased_view_2
+drop cascades to view aliased_view_3
+drop cascades to view aliased_view_4
 DROP SCHEMA testviewschm2 CASCADE;
-NOTICE:  drop cascades to 20 other objects
+NOTICE:  drop cascades to 22 other objects
 DETAIL:  drop cascades to table t1
 drop cascades to view temporal1
 drop cascades to view temporal2
@@ -334,4 +699,6 @@ drop cascades to view mysecview1
 drop cascades to view mysecview2
 drop cascades to view mysecview3
 drop cascades to view mysecview4
+drop cascades to table tt1
+drop cascades to table tx1
 SET search_path to public;
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index 25adcd2346118853ef57943bd22d9b80667ca560..906a928b0c0a44ff1dcac5b3b9803cd508ec7533 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -1105,17 +1105,17 @@ analyze patest1;
 analyze patest2;
 explain (costs off)
 select * from patest0 join (select f1 from int4_tbl limit 1) ss on id = f1;
-                        QUERY PLAN                        
-----------------------------------------------------------
+                    QUERY PLAN                    
+--------------------------------------------------
  Nested Loop
    ->  Limit
          ->  Seq Scan on int4_tbl
    ->  Append
          ->  Index Scan using patest0i on patest0
                Index Cond: (id = int4_tbl.f1)
-         ->  Index Scan using patest1i on patest1 patest0
+         ->  Index Scan using patest1i on patest1
                Index Cond: (id = int4_tbl.f1)
-         ->  Index Scan using patest2i on patest2 patest0
+         ->  Index Scan using patest2i on patest2
                Index Cond: (id = int4_tbl.f1)
 (10 rows)
 
@@ -1130,17 +1130,17 @@ select * from patest0 join (select f1 from int4_tbl limit 1) ss on id = f1;
 drop index patest2i;
 explain (costs off)
 select * from patest0 join (select f1 from int4_tbl limit 1) ss on id = f1;
-                        QUERY PLAN                        
-----------------------------------------------------------
+                    QUERY PLAN                    
+--------------------------------------------------
  Nested Loop
    ->  Limit
          ->  Seq Scan on int4_tbl
    ->  Append
          ->  Index Scan using patest0i on patest0
                Index Cond: (id = int4_tbl.f1)
-         ->  Index Scan using patest1i on patest1 patest0
+         ->  Index Scan using patest1i on patest1
                Index Cond: (id = int4_tbl.f1)
-         ->  Seq Scan on patest2 patest0
+         ->  Seq Scan on patest2
                Filter: (int4_tbl.f1 = id)
 (10 rows)
 
@@ -1178,22 +1178,22 @@ insert into matest3 (name) values ('Test 5');
 insert into matest3 (name) values ('Test 6');
 set enable_indexscan = off;  -- force use of seqscan/sort, so no merge
 explain (verbose, costs off) select * from matest0 order by 1-id;
-                                   QUERY PLAN                                    
----------------------------------------------------------------------------------
+                         QUERY PLAN                         
+------------------------------------------------------------
  Sort
-   Output: public.matest0.id, public.matest0.name, ((1 - public.matest0.id))
-   Sort Key: ((1 - public.matest0.id))
+   Output: matest0.id, matest0.name, ((1 - matest0.id))
+   Sort Key: ((1 - matest0.id))
    ->  Result
-         Output: public.matest0.id, public.matest0.name, (1 - public.matest0.id)
+         Output: matest0.id, matest0.name, (1 - matest0.id)
          ->  Append
                ->  Seq Scan on public.matest0
-                     Output: public.matest0.id, public.matest0.name
-               ->  Seq Scan on public.matest1 matest0
-                     Output: public.matest0.id, public.matest0.name
-               ->  Seq Scan on public.matest2 matest0
-                     Output: public.matest0.id, public.matest0.name
-               ->  Seq Scan on public.matest3 matest0
-                     Output: public.matest0.id, public.matest0.name
+                     Output: matest0.id, matest0.name
+               ->  Seq Scan on public.matest1
+                     Output: matest1.id, matest1.name
+               ->  Seq Scan on public.matest2
+                     Output: matest2.id, matest2.name
+               ->  Seq Scan on public.matest3
+                     Output: matest3.id, matest3.name
 (14 rows)
 
 select * from matest0 order by 1-id;
@@ -1210,23 +1210,23 @@ select * from matest0 order by 1-id;
 reset enable_indexscan;
 set enable_seqscan = off;  -- plan with fewest seqscans should be merge
 explain (verbose, costs off) select * from matest0 order by 1-id;
-                                         QUERY PLAN                                          
----------------------------------------------------------------------------------------------
+                               QUERY PLAN                               
+------------------------------------------------------------------------
  Result
-   Output: public.matest0.id, public.matest0.name, ((1 - public.matest0.id))
+   Output: matest0.id, matest0.name, ((1 - matest0.id))
    ->  Merge Append
-         Sort Key: ((1 - public.matest0.id))
+         Sort Key: ((1 - matest0.id))
          ->  Index Scan using matest0i on public.matest0
-               Output: public.matest0.id, public.matest0.name, (1 - public.matest0.id)
-         ->  Index Scan using matest1i on public.matest1 matest0
-               Output: public.matest0.id, public.matest0.name, (1 - public.matest0.id)
+               Output: matest0.id, matest0.name, (1 - matest0.id)
+         ->  Index Scan using matest1i on public.matest1
+               Output: matest1.id, matest1.name, (1 - matest1.id)
          ->  Sort
-               Output: public.matest0.id, public.matest0.name, ((1 - public.matest0.id))
-               Sort Key: ((1 - public.matest0.id))
-               ->  Seq Scan on public.matest2 matest0
-                     Output: public.matest0.id, public.matest0.name, (1 - public.matest0.id)
-         ->  Index Scan using matest3i on public.matest3 matest0
-               Output: public.matest0.id, public.matest0.name, (1 - public.matest0.id)
+               Output: matest2.id, matest2.name, ((1 - matest2.id))
+               Sort Key: ((1 - matest2.id))
+               ->  Seq Scan on public.matest2
+                     Output: matest2.id, matest2.name, (1 - matest2.id)
+         ->  Index Scan using matest3i on public.matest3
+               Output: matest3.id, matest3.name, (1 - matest3.id)
 (15 rows)
 
 select * from matest0 order by 1-id;
@@ -1258,15 +1258,15 @@ SELECT thousand, tenthous FROM tenk1
 UNION ALL
 SELECT thousand, thousand FROM tenk1
 ORDER BY thousand, tenthous;
-                              QUERY PLAN                               
------------------------------------------------------------------------
+                                  QUERY PLAN                                   
+-------------------------------------------------------------------------------
  Result
    ->  Merge Append
-         Sort Key: public.tenk1.thousand, public.tenk1.tenthous
+         Sort Key: tenk1.thousand, tenk1.tenthous
          ->  Index Only Scan using tenk1_thous_tenthous on tenk1
          ->  Sort
-               Sort Key: public.tenk1.thousand, public.tenk1.thousand
-               ->  Index Only Scan using tenk1_thous_tenthous on tenk1
+               Sort Key: tenk1_1.thousand, tenk1_1.thousand
+               ->  Index Only Scan using tenk1_thous_tenthous on tenk1 tenk1_1
 (7 rows)
 
 explain (costs off)
@@ -1274,15 +1274,15 @@ SELECT thousand, tenthous, thousand+tenthous AS x FROM tenk1
 UNION ALL
 SELECT 42, 42, hundred FROM tenk1
 ORDER BY thousand, tenthous;
-                           QUERY PLAN                            
------------------------------------------------------------------
+                               QUERY PLAN                               
+------------------------------------------------------------------------
  Result
    ->  Merge Append
-         Sort Key: public.tenk1.thousand, public.tenk1.tenthous
+         Sort Key: tenk1.thousand, tenk1.tenthous
          ->  Index Only Scan using tenk1_thous_tenthous on tenk1
          ->  Sort
                Sort Key: (42), (42)
-               ->  Index Only Scan using tenk1_hundred on tenk1
+               ->  Index Only Scan using tenk1_hundred on tenk1 tenk1_1
 (7 rows)
 
 explain (costs off)
@@ -1290,15 +1290,15 @@ SELECT thousand, tenthous FROM tenk1
 UNION ALL
 SELECT thousand, random()::integer FROM tenk1
 ORDER BY thousand, tenthous;
-                              QUERY PLAN                               
------------------------------------------------------------------------
+                                  QUERY PLAN                                   
+-------------------------------------------------------------------------------
  Result
    ->  Merge Append
-         Sort Key: public.tenk1.thousand, public.tenk1.tenthous
+         Sort Key: tenk1.thousand, tenk1.tenthous
          ->  Index Only Scan using tenk1_thous_tenthous on tenk1
          ->  Sort
-               Sort Key: public.tenk1.thousand, ((random())::integer)
-               ->  Index Only Scan using tenk1_thous_tenthous on tenk1
+               Sort Key: tenk1_1.thousand, ((random())::integer)
+               ->  Index Only Scan using tenk1_thous_tenthous on tenk1 tenk1_1
 (7 rows)
 
 -- Check min/max aggregate optimization
diff --git a/src/test/regress/expected/select_views.out b/src/test/regress/expected/select_views.out
index e4eba1ae36c8715d2f414db413feb68e71c1c575..24bbff9d2e4727529d470454f012db0f9a774776 100644
--- a/src/test/regress/expected/select_views.out
+++ b/src/test/regress/expected/select_views.out
@@ -1421,10 +1421,10 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_usage_normal
          ->  Subquery Scan on l
                Filter: f_leak(l.cnum)
                ->  Hash Join
-                     Hash Cond: (r.cid = l.cid)
-                     ->  Seq Scan on credit_card r
+                     Hash Cond: (r_1.cid = l_1.cid)
+                     ->  Seq Scan on credit_card r_1
                      ->  Hash
-                           ->  Seq Scan on customer l
+                           ->  Seq Scan on customer l_1
                                  Filter: (name = ("current_user"())::text)
 (13 rows)
 
@@ -1452,8 +1452,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_usage_secure
                Filter: ((ymd >= '10-01-2011'::date) AND (ymd < '11-01-2011'::date))
          ->  Materialize
                ->  Hash Join
-                     Hash Cond: (r.cid = l.cid)
-                     ->  Seq Scan on credit_card r
+                     Hash Cond: (r_1.cid = l.cid)
+                     ->  Seq Scan on credit_card r_1
                      ->  Hash
                            ->  Seq Scan on customer l
                                  Filter: (name = ("current_user"())::text)
diff --git a/src/test/regress/expected/select_views_1.out b/src/test/regress/expected/select_views_1.out
index 94b439825c49b25651a7722f301d203f9d6c958f..ec6e938cb1d3a30d56bc8b0ceeafd0a6f8d6fe43 100644
--- a/src/test/regress/expected/select_views_1.out
+++ b/src/test/regress/expected/select_views_1.out
@@ -1421,10 +1421,10 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_usage_normal
          ->  Subquery Scan on l
                Filter: f_leak(l.cnum)
                ->  Hash Join
-                     Hash Cond: (r.cid = l.cid)
-                     ->  Seq Scan on credit_card r
+                     Hash Cond: (r_1.cid = l_1.cid)
+                     ->  Seq Scan on credit_card r_1
                      ->  Hash
-                           ->  Seq Scan on customer l
+                           ->  Seq Scan on customer l_1
                                  Filter: (name = ("current_user"())::text)
 (13 rows)
 
@@ -1452,8 +1452,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_usage_secure
                Filter: ((ymd >= '10-01-2011'::date) AND (ymd < '11-01-2011'::date))
          ->  Materialize
                ->  Hash Join
-                     Hash Cond: (r.cid = l.cid)
-                     ->  Seq Scan on credit_card r
+                     Hash Cond: (r_1.cid = l.cid)
+                     ->  Seq Scan on credit_card r_1
                      ->  Hash
                            ->  Seq Scan on customer l
                                  Filter: (name = ("current_user"())::text)
diff --git a/src/test/regress/expected/with.out b/src/test/regress/expected/with.out
index 38cfb8c7276c9310a60375f0f70d56b8c14eb970..671f293b68de95617b6f953573a31fda3fde176f 100644
--- a/src/test/regress/expected/with.out
+++ b/src/test/regress/expected/with.out
@@ -2006,8 +2006,8 @@ SELECT * FROM parent;
 EXPLAIN (VERBOSE, COSTS OFF)
 WITH wcte AS ( INSERT INTO int8_tbl VALUES ( 42, 47 ) RETURNING q2 )
 DELETE FROM a USING wcte WHERE aa = q2;
-                    QUERY PLAN                    
---------------------------------------------------
+                   QUERY PLAN                   
+------------------------------------------------
  Delete on public.a
    CTE wcte
      ->  Insert on public.int8_tbl
@@ -2015,31 +2015,31 @@ DELETE FROM a USING wcte WHERE aa = q2;
            ->  Result
                  Output: 42::bigint, 47::bigint
    ->  Nested Loop
-         Output: public.a.ctid, wcte.*
-         Join Filter: (public.a.aa = wcte.q2)
+         Output: a.ctid, wcte.*
+         Join Filter: (a.aa = wcte.q2)
          ->  Seq Scan on public.a
-               Output: public.a.ctid, public.a.aa
+               Output: a.ctid, a.aa
          ->  CTE Scan on wcte
                Output: wcte.*, wcte.q2
    ->  Nested Loop
-         Output: public.a.ctid, wcte.*
-         Join Filter: (public.a.aa = wcte.q2)
-         ->  Seq Scan on public.b a
-               Output: public.a.ctid, public.a.aa
+         Output: b.ctid, wcte.*
+         Join Filter: (b.aa = wcte.q2)
+         ->  Seq Scan on public.b
+               Output: b.ctid, b.aa
          ->  CTE Scan on wcte
                Output: wcte.*, wcte.q2
    ->  Nested Loop
-         Output: public.a.ctid, wcte.*
-         Join Filter: (public.a.aa = wcte.q2)
-         ->  Seq Scan on public.c a
-               Output: public.a.ctid, public.a.aa
+         Output: c.ctid, wcte.*
+         Join Filter: (c.aa = wcte.q2)
+         ->  Seq Scan on public.c
+               Output: c.ctid, c.aa
          ->  CTE Scan on wcte
                Output: wcte.*, wcte.q2
    ->  Nested Loop
-         Output: public.a.ctid, wcte.*
-         Join Filter: (public.a.aa = wcte.q2)
-         ->  Seq Scan on public.d a
-               Output: public.a.ctid, public.a.aa
+         Output: d.ctid, wcte.*
+         Join Filter: (d.aa = wcte.q2)
+         ->  Seq Scan on public.d
+               Output: d.ctid, d.aa
          ->  CTE Scan on wcte
                Output: wcte.*, wcte.q2
 (34 rows)
diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql
index 48d8d22d1b8e4e997f1bd236b75a2b7773a6ad7f..07145911e6be500bfa8d7b99d06a7fd3819db79f 100644
--- a/src/test/regress/sql/create_view.sql
+++ b/src/test/regress/sql/create_view.sql
@@ -224,6 +224,68 @@ SELECT relname, relkind, reloptions FROM pg_class
                      'mysecview3'::regclass, 'mysecview4'::regclass)
        ORDER BY relname;
 
+-- Test view decompilation in the face of renaming conflicts
+
+CREATE TABLE tt1 (f1 int, f2 int, f3 text);
+CREATE TABLE tx1 (x1 int, x2 int, x3 text);
+CREATE TABLE temp_view_test.tt1 (y1 int, f2 int, f3 text);
+
+CREATE VIEW aliased_view_1 AS
+  select * from tt1
+    where exists (select 1 from tx1 where tt1.f1 = tx1.x1);
+CREATE VIEW aliased_view_2 AS
+  select * from tt1 a1
+    where exists (select 1 from tx1 where a1.f1 = tx1.x1);
+CREATE VIEW aliased_view_3 AS
+  select * from tt1
+    where exists (select 1 from tx1 a2 where tt1.f1 = a2.x1);
+CREATE VIEW aliased_view_4 AS
+  select * from temp_view_test.tt1
+    where exists (select 1 from tt1 where temp_view_test.tt1.y1 = tt1.f1);
+
+\d+ aliased_view_1
+\d+ aliased_view_2
+\d+ aliased_view_3
+\d+ aliased_view_4
+
+ALTER TABLE tx1 RENAME TO a1;
+
+\d+ aliased_view_1
+\d+ aliased_view_2
+\d+ aliased_view_3
+\d+ aliased_view_4
+
+ALTER TABLE tt1 RENAME TO a2;
+
+\d+ aliased_view_1
+\d+ aliased_view_2
+\d+ aliased_view_3
+\d+ aliased_view_4
+
+ALTER TABLE a1 RENAME TO tt1;
+
+\d+ aliased_view_1
+\d+ aliased_view_2
+\d+ aliased_view_3
+\d+ aliased_view_4
+
+ALTER TABLE a2 RENAME TO tx1;
+ALTER TABLE tx1 SET SCHEMA temp_view_test;
+
+\d+ aliased_view_1
+\d+ aliased_view_2
+\d+ aliased_view_3
+\d+ aliased_view_4
+
+ALTER TABLE temp_view_test.tt1 RENAME TO tmp1;
+ALTER TABLE temp_view_test.tmp1 SET SCHEMA testviewschm2;
+ALTER TABLE tmp1 RENAME TO tx1;
+
+\d+ aliased_view_1
+\d+ aliased_view_2
+\d+ aliased_view_3
+\d+ aliased_view_4
+
 DROP SCHEMA temp_view_test CASCADE;
 DROP SCHEMA testviewschm2 CASCADE;