Commit 11e13185 authored by Tom Lane's avatar Tom Lane

Improve ruleutils.c's heuristics for dealing with rangetable aliases.

The previous scheme had bugs in some corner cases involving tables that had
been renamed since a view was made.  This could result in dumped views that
failed to reload or reloaded incorrectly, as seen in bug #7553 from Lloyd
Albin, as well as in some pgsql-hackers discussion back in January.  Also,
its behavior for printing EXPLAIN plans was sometimes confusing because of
willingness to use the same alias for multiple RTEs (it was Ashutosh
Bapat's complaint about that aspect that started the January thread).

To fix, ensure that each RTE in the query has a unique unqualified alias,
by modifying the alias if necessary (we add "_" and digits as needed to
create a non-conflicting name).  Then we can just print its variables with
that alias, avoiding the confusing and bug-prone scheme of sometimes
schema-qualifying variable names.  In EXPLAIN, it proves to be expedient to
take the further step of only assigning such aliases to RTEs that are
actually referenced in the query, since the planner has a habit of
generating extra RTEs with the same alias in situations such as
inheritance-tree expansion.

Although this fixes a bug of very long standing, I'm hesitant to back-patch
such a noticeable behavioral change.  My experiments while creating a
regression test convinced me that actually incorrect output (as opposed to
confusing output) occurs only in very narrow cases, which is backed up by
the lack of previous complaints from the field.  So we may be better off
living with it in released branches; and in any case it'd be smart to let
this ripen awhile in HEAD before we consider back-patching it.
parent 7c45e3a3
...@@ -51,6 +51,10 @@ static void ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es, ...@@ -51,6 +51,10 @@ static void ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es,
static void report_triggers(ResultRelInfo *rInfo, bool show_relname, static void report_triggers(ResultRelInfo *rInfo, bool show_relname,
ExplainState *es); ExplainState *es);
static double elapsed_time(instr_time *starttime); 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, static void ExplainNode(PlanState *planstate, List *ancestors,
const char *relationship, const char *plan_name, const char *relationship, const char *plan_name,
ExplainState *es); ExplainState *es);
...@@ -539,9 +543,13 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, ...@@ -539,9 +543,13 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es,
void void
ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc) ExplainPrintPlan(ExplainState *es, QueryDesc *queryDesc)
{ {
Bitmapset *rels_used = NULL;
Assert(queryDesc->plannedstmt != NULL); Assert(queryDesc->plannedstmt != NULL);
es->pstmt = queryDesc->plannedstmt; es->pstmt = queryDesc->plannedstmt;
es->rtable = queryDesc->plannedstmt->rtable; 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); ExplainNode(queryDesc->planstate, NIL, NULL, NULL, es);
} }
...@@ -640,6 +648,132 @@ elapsed_time(instr_time *starttime) ...@@ -640,6 +648,132 @@ elapsed_time(instr_time *starttime)
return INSTR_TIME_GET_DOUBLE(endtime); 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 - * ExplainNode -
* Appends a description of a plan tree to es->str * Appends a description of a plan tree to es->str
...@@ -1440,7 +1574,8 @@ show_plan_tlist(PlanState *planstate, List *ancestors, ExplainState *es) ...@@ -1440,7 +1574,8 @@ show_plan_tlist(PlanState *planstate, List *ancestors, ExplainState *es)
/* Set up deparsing context */ /* Set up deparsing context */
context = deparse_context_for_planstate((Node *) planstate, context = deparse_context_for_planstate((Node *) planstate,
ancestors, ancestors,
es->rtable); es->rtable,
es->rtable_names);
useprefix = list_length(es->rtable) > 1; useprefix = list_length(es->rtable) > 1;
/* Deparse each result column (we now include resjunk ones) */ /* Deparse each result column (we now include resjunk ones) */
...@@ -1471,7 +1606,8 @@ show_expression(Node *node, const char *qlabel, ...@@ -1471,7 +1606,8 @@ show_expression(Node *node, const char *qlabel,
/* Set up deparsing context */ /* Set up deparsing context */
context = deparse_context_for_planstate((Node *) planstate, context = deparse_context_for_planstate((Node *) planstate,
ancestors, ancestors,
es->rtable); es->rtable,
es->rtable_names);
/* Deparse the expression */ /* Deparse the expression */
exprstr = deparse_expression(node, context, useprefix, false); exprstr = deparse_expression(node, context, useprefix, false);
...@@ -1573,7 +1709,8 @@ show_sort_keys_common(PlanState *planstate, int nkeys, AttrNumber *keycols, ...@@ -1573,7 +1709,8 @@ show_sort_keys_common(PlanState *planstate, int nkeys, AttrNumber *keycols,
/* Set up deparsing context */ /* Set up deparsing context */
context = deparse_context_for_planstate((Node *) planstate, context = deparse_context_for_planstate((Node *) planstate,
ancestors, ancestors,
es->rtable); es->rtable,
es->rtable_names);
useprefix = (list_length(es->rtable) > 1 || es->verbose); useprefix = (list_length(es->rtable) > 1 || es->verbose);
for (keyno = 0; keyno < nkeys; keyno++) for (keyno = 0; keyno < nkeys; keyno++)
...@@ -1813,8 +1950,10 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es) ...@@ -1813,8 +1950,10 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
char *namespace = NULL; char *namespace = NULL;
const char *objecttag = NULL; const char *objecttag = NULL;
RangeTblEntry *rte; RangeTblEntry *rte;
char *refname;
rte = rt_fetch(rti, es->rtable); rte = rt_fetch(rti, es->rtable);
refname = (char *) list_nth(es->rtable_names, rti - 1);
switch (nodeTag(plan)) switch (nodeTag(plan))
{ {
...@@ -1887,10 +2026,9 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es) ...@@ -1887,10 +2026,9 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
quote_identifier(objectname)); quote_identifier(objectname));
else if (objectname != NULL) else if (objectname != NULL)
appendStringInfo(es->str, " %s", quote_identifier(objectname)); appendStringInfo(es->str, " %s", quote_identifier(objectname));
if (objectname == NULL || if (refname != NULL &&
strcmp(rte->eref->aliasname, objectname) != 0) (objectname == NULL || strcmp(refname, objectname) != 0))
appendStringInfo(es->str, " %s", appendStringInfo(es->str, " %s", quote_identifier(refname));
quote_identifier(rte->eref->aliasname));
} }
else else
{ {
...@@ -1898,7 +2036,8 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es) ...@@ -1898,7 +2036,8 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
ExplainPropertyText(objecttag, objectname, es); ExplainPropertyText(objecttag, objectname, es);
if (namespace != NULL) if (namespace != NULL)
ExplainPropertyText("Schema", namespace, es); ExplainPropertyText("Schema", namespace, es);
ExplainPropertyText("Alias", rte->eref->aliasname, es); if (refname != NULL)
ExplainPropertyText("Alias", refname, es);
} }
} }
......
This diff is collapsed.
...@@ -37,6 +37,7 @@ typedef struct ExplainState ...@@ -37,6 +37,7 @@ typedef struct ExplainState
/* other states */ /* other states */
PlannedStmt *pstmt; /* top of plan */ PlannedStmt *pstmt; /* top of plan */
List *rtable; /* range table */ List *rtable; /* range table */
List *rtable_names; /* alias names for RTEs */
int indent; /* current indentation level */ int indent; /* current indentation level */
List *grouping_stack; /* format-specific grouping state */ List *grouping_stack; /* format-specific grouping state */
} ExplainState; } ExplainState;
......
...@@ -654,7 +654,9 @@ extern char *deparse_expression(Node *expr, List *dpcontext, ...@@ -654,7 +654,9 @@ extern char *deparse_expression(Node *expr, List *dpcontext,
bool forceprefix, bool showimplicit); bool forceprefix, bool showimplicit);
extern List *deparse_context_for(const char *aliasname, Oid relid); extern List *deparse_context_for(const char *aliasname, Oid relid);
extern List *deparse_context_for_planstate(Node *planstate, List *ancestors, 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 const char *quote_identifier(const char *ident);
extern char *quote_qualified_identifier(const char *qualifier, extern char *quote_qualified_identifier(const char *qualifier,
const char *ident); const char *ident);
......
...@@ -705,32 +705,32 @@ insert into minmaxtest2 values(15), (16); ...@@ -705,32 +705,32 @@ insert into minmaxtest2 values(15), (16);
insert into minmaxtest3 values(17), (18); insert into minmaxtest3 values(17), (18);
explain (costs off) explain (costs off)
select min(f1), max(f1) from minmaxtest; select min(f1), max(f1) from minmaxtest;
QUERY PLAN QUERY PLAN
------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------
Result Result
InitPlan 1 (returns $0) InitPlan 1 (returns $0)
-> Limit -> Limit
-> Merge Append -> Merge Append
Sort Key: public.minmaxtest.f1 Sort Key: minmaxtest.f1
-> Index Only Scan using minmaxtesti on minmaxtest -> Index Only Scan using minmaxtesti on minmaxtest
Index Cond: (f1 IS NOT NULL) 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 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 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) Index Cond: (f1 IS NOT NULL)
InitPlan 2 (returns $1) InitPlan 2 (returns $1)
-> Limit -> Limit
-> Merge Append -> Merge Append
Sort Key: public.minmaxtest.f1 Sort Key: minmaxtest_1.f1
-> Index Only Scan Backward using minmaxtesti on minmaxtest -> Index Only Scan Backward using minmaxtesti on minmaxtest minmaxtest_1
Index Cond: (f1 IS NOT NULL) 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 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 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) Index Cond: (f1 IS NOT NULL)
(25 rows) (25 rows)
......
...@@ -391,9 +391,9 @@ explain (costs off) select * from nv_parent where d between '2011-08-01' and '20 ...@@ -391,9 +391,9 @@ explain (costs off) select * from nv_parent where d between '2011-08-01' and '20
-> Append -> Append
-> Seq Scan on nv_parent -> Seq Scan on nv_parent
Filter: ((d >= '08-01-2011'::date) AND (d <= '08-31-2011'::date)) 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)) 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)) Filter: ((d >= '08-01-2011'::date) AND (d <= '08-31-2011'::date))
(8 rows) (8 rows)
...@@ -405,9 +405,9 @@ explain (costs off) select * from nv_parent where d between '2011-08-01'::date a ...@@ -405,9 +405,9 @@ explain (costs off) select * from nv_parent where d between '2011-08-01'::date a
-> Append -> Append
-> Seq Scan on nv_parent -> Seq Scan on nv_parent
Filter: ((d >= '08-01-2011'::date) AND (d <= '08-31-2011'::date)) 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)) 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)) Filter: ((d >= '08-01-2011'::date) AND (d <= '08-31-2011'::date))
(8 rows) (8 rows)
...@@ -418,11 +418,11 @@ explain (costs off) select * from nv_parent where d between '2009-08-01'::date a ...@@ -418,11 +418,11 @@ explain (costs off) select * from nv_parent where d between '2009-08-01'::date a
-> Append -> Append
-> Seq Scan on nv_parent -> Seq Scan on nv_parent
Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date)) 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)) 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)) 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)) Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
(10 rows) (10 rows)
...@@ -435,9 +435,9 @@ explain (costs off) select * from nv_parent where d between '2009-08-01'::date a ...@@ -435,9 +435,9 @@ explain (costs off) select * from nv_parent where d between '2009-08-01'::date a
-> Append -> Append
-> Seq Scan on nv_parent -> Seq Scan on nv_parent
Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date)) 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)) 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)) Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
(8 rows) (8 rows)
......
This diff is collapsed.
...@@ -1105,17 +1105,17 @@ analyze patest1; ...@@ -1105,17 +1105,17 @@ analyze patest1;
analyze patest2; analyze patest2;
explain (costs off) explain (costs off)
select * from patest0 join (select f1 from int4_tbl limit 1) ss on id = f1; select * from patest0 join (select f1 from int4_tbl limit 1) ss on id = f1;
QUERY PLAN QUERY PLAN
---------------------------------------------------------- --------------------------------------------------
Nested Loop Nested Loop
-> Limit -> Limit
-> Seq Scan on int4_tbl -> Seq Scan on int4_tbl
-> Append -> Append
-> Index Scan using patest0i on patest0 -> Index Scan using patest0i on patest0
Index Cond: (id = int4_tbl.f1) 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 Cond: (id = int4_tbl.f1)
-> Index Scan using patest2i on patest2 patest0 -> Index Scan using patest2i on patest2
Index Cond: (id = int4_tbl.f1) Index Cond: (id = int4_tbl.f1)
(10 rows) (10 rows)
...@@ -1130,17 +1130,17 @@ select * from patest0 join (select f1 from int4_tbl limit 1) ss on id = f1; ...@@ -1130,17 +1130,17 @@ select * from patest0 join (select f1 from int4_tbl limit 1) ss on id = f1;
drop index patest2i; drop index patest2i;
explain (costs off) explain (costs off)
select * from patest0 join (select f1 from int4_tbl limit 1) ss on id = f1; select * from patest0 join (select f1 from int4_tbl limit 1) ss on id = f1;
QUERY PLAN QUERY PLAN
---------------------------------------------------------- --------------------------------------------------
Nested Loop Nested Loop
-> Limit -> Limit
-> Seq Scan on int4_tbl -> Seq Scan on int4_tbl
-> Append -> Append
-> Index Scan using patest0i on patest0 -> Index Scan using patest0i on patest0
Index Cond: (id = int4_tbl.f1) 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 Cond: (id = int4_tbl.f1)
-> Seq Scan on patest2 patest0 -> Seq Scan on patest2
Filter: (int4_tbl.f1 = id) Filter: (int4_tbl.f1 = id)
(10 rows) (10 rows)
...@@ -1178,22 +1178,22 @@ insert into matest3 (name) values ('Test 5'); ...@@ -1178,22 +1178,22 @@ insert into matest3 (name) values ('Test 5');
insert into matest3 (name) values ('Test 6'); insert into matest3 (name) values ('Test 6');
set enable_indexscan = off; -- force use of seqscan/sort, so no merge set enable_indexscan = off; -- force use of seqscan/sort, so no merge
explain (verbose, costs off) select * from matest0 order by 1-id; explain (verbose, costs off) select * from matest0 order by 1-id;
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------------------- ------------------------------------------------------------
Sort Sort
Output: public.matest0.id, public.matest0.name, ((1 - public.matest0.id)) Output: matest0.id, matest0.name, ((1 - matest0.id))
Sort Key: ((1 - public.matest0.id)) Sort Key: ((1 - matest0.id))
-> Result -> Result
Output: public.matest0.id, public.matest0.name, (1 - public.matest0.id) Output: matest0.id, matest0.name, (1 - matest0.id)
-> Append -> Append
-> Seq Scan on public.matest0 -> Seq Scan on public.matest0
Output: public.matest0.id, public.matest0.name Output: matest0.id, matest0.name
-> Seq Scan on public.matest1 matest0 -> Seq Scan on public.matest1
Output: public.matest0.id, public.matest0.name Output: matest1.id, matest1.name
-> Seq Scan on public.matest2 matest0 -> Seq Scan on public.matest2
Output: public.matest0.id, public.matest0.name Output: matest2.id, matest2.name
-> Seq Scan on public.matest3 matest0 -> Seq Scan on public.matest3
Output: public.matest0.id, public.matest0.name Output: matest3.id, matest3.name
(14 rows) (14 rows)
select * from matest0 order by 1-id; select * from matest0 order by 1-id;
...@@ -1210,23 +1210,23 @@ select * from matest0 order by 1-id; ...@@ -1210,23 +1210,23 @@ select * from matest0 order by 1-id;
reset enable_indexscan; reset enable_indexscan;
set enable_seqscan = off; -- plan with fewest seqscans should be merge set enable_seqscan = off; -- plan with fewest seqscans should be merge
explain (verbose, costs off) select * from matest0 order by 1-id; explain (verbose, costs off) select * from matest0 order by 1-id;
QUERY PLAN QUERY PLAN
--------------------------------------------------------------------------------------------- ------------------------------------------------------------------------
Result Result
Output: public.matest0.id, public.matest0.name, ((1 - public.matest0.id)) Output: matest0.id, matest0.name, ((1 - matest0.id))
-> Merge Append -> Merge Append
Sort Key: ((1 - public.matest0.id)) Sort Key: ((1 - matest0.id))
-> Index Scan using matest0i on public.matest0 -> Index Scan using matest0i on public.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 matest0 -> Index Scan using matest1i on public.matest1
Output: public.matest0.id, public.matest0.name, (1 - public.matest0.id) Output: matest1.id, matest1.name, (1 - matest1.id)
-> Sort -> Sort
Output: public.matest0.id, public.matest0.name, ((1 - public.matest0.id)) Output: matest2.id, matest2.name, ((1 - matest2.id))
Sort Key: ((1 - public.matest0.id)) Sort Key: ((1 - matest2.id))
-> Seq Scan on public.matest2 matest0 -> Seq Scan on public.matest2
Output: public.matest0.id, public.matest0.name, (1 - public.matest0.id) Output: matest2.id, matest2.name, (1 - matest2.id)
-> Index Scan using matest3i on public.matest3 matest0 -> Index Scan using matest3i on public.matest3
Output: public.matest0.id, public.matest0.name, (1 - public.matest0.id) Output: matest3.id, matest3.name, (1 - matest3.id)
(15 rows) (15 rows)
select * from matest0 order by 1-id; select * from matest0 order by 1-id;
...@@ -1258,15 +1258,15 @@ SELECT thousand, tenthous FROM tenk1 ...@@ -1258,15 +1258,15 @@ SELECT thousand, tenthous FROM tenk1
UNION ALL UNION ALL
SELECT thousand, thousand FROM tenk1 SELECT thousand, thousand FROM tenk1
ORDER BY thousand, tenthous; ORDER BY thousand, tenthous;
QUERY PLAN QUERY PLAN
----------------------------------------------------------------------- -------------------------------------------------------------------------------
Result Result
-> Merge Append -> 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 -> Index Only Scan using tenk1_thous_tenthous on tenk1
-> Sort -> Sort
Sort Key: public.tenk1.thousand, public.tenk1.thousand Sort Key: tenk1_1.thousand, tenk1_1.thousand
-> Index Only Scan using tenk1_thous_tenthous on tenk1 -> Index Only Scan using tenk1_thous_tenthous on tenk1 tenk1_1
(7 rows) (7 rows)
explain (costs off) explain (costs off)
...@@ -1274,15 +1274,15 @@ SELECT thousand, tenthous, thousand+tenthous AS x FROM tenk1 ...@@ -1274,15 +1274,15 @@ SELECT thousand, tenthous, thousand+tenthous AS x FROM tenk1
UNION ALL UNION ALL
SELECT 42, 42, hundred FROM tenk1 SELECT 42, 42, hundred FROM tenk1
ORDER BY thousand, tenthous; ORDER BY thousand, tenthous;
QUERY PLAN QUERY PLAN
----------------------------------------------------------------- ------------------------------------------------------------------------
Result Result
-> Merge Append -> 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 -> Index Only Scan using tenk1_thous_tenthous on tenk1
-> Sort -> Sort
Sort Key: (42), (42) Sort Key: (42), (42)
-> Index Only Scan using tenk1_hundred on tenk1 -> Index Only Scan using tenk1_hundred on tenk1 tenk1_1
(7 rows) (7 rows)
explain (costs off) explain (costs off)
...@@ -1290,15 +1290,15 @@ SELECT thousand, tenthous FROM tenk1 ...@@ -1290,15 +1290,15 @@ SELECT thousand, tenthous FROM tenk1
UNION ALL UNION ALL
SELECT thousand, random()::integer FROM tenk1 SELECT thousand, random()::integer FROM tenk1
ORDER BY thousand, tenthous; ORDER BY thousand, tenthous;
QUERY PLAN QUERY PLAN
----------------------------------------------------------------------- -------------------------------------------------------------------------------
Result Result
-> Merge Append -> 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 -> Index Only Scan using tenk1_thous_tenthous on tenk1
-> Sort -> Sort
Sort Key: public.tenk1.thousand, ((random())::integer) Sort Key: tenk1_1.thousand, ((random())::integer)
-> Index Only Scan using tenk1_thous_tenthous on tenk1 -> Index Only Scan using tenk1_thous_tenthous on tenk1 tenk1_1
(7 rows) (7 rows)
-- Check min/max aggregate optimization -- Check min/max aggregate optimization
......
...@@ -1421,10 +1421,10 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_usage_normal ...@@ -1421,10 +1421,10 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_usage_normal
-> Subquery Scan on l -> Subquery Scan on l
Filter: f_leak(l.cnum) Filter: f_leak(l.cnum)
-> Hash Join -> Hash Join
Hash Cond: (r.cid = l.cid) Hash Cond: (r_1.cid = l_1.cid)
-> Seq Scan on credit_card r -> Seq Scan on credit_card r_1
-> Hash -> Hash
-> Seq Scan on customer l -> Seq Scan on customer l_1
Filter: (name = ("current_user"())::text) Filter: (name = ("current_user"())::text)
(13 rows) (13 rows)
...@@ -1452,8 +1452,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_usage_secure ...@@ -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)) Filter: ((ymd >= '10-01-2011'::date) AND (ymd < '11-01-2011'::date))
-> Materialize -> Materialize
-> Hash Join -> Hash Join
Hash Cond: (r.cid = l.cid) Hash Cond: (r_1.cid = l.cid)
-> Seq Scan on credit_card r -> Seq Scan on credit_card r_1
-> Hash -> Hash
-> Seq Scan on customer l -> Seq Scan on customer l
Filter: (name = ("current_user"())::text) Filter: (name = ("current_user"())::text)
......
...@@ -1421,10 +1421,10 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_usage_normal ...@@ -1421,10 +1421,10 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_usage_normal
-> Subquery Scan on l -> Subquery Scan on l
Filter: f_leak(l.cnum) Filter: f_leak(l.cnum)
-> Hash Join -> Hash Join
Hash Cond: (r.cid = l.cid) Hash Cond: (r_1.cid = l_1.cid)
-> Seq Scan on credit_card r -> Seq Scan on credit_card r_1
-> Hash -> Hash
-> Seq Scan on customer l -> Seq Scan on customer l_1
Filter: (name = ("current_user"())::text) Filter: (name = ("current_user"())::text)
(13 rows) (13 rows)
...@@ -1452,8 +1452,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM my_credit_card_usage_secure ...@@ -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)) Filter: ((ymd >= '10-01-2011'::date) AND (ymd < '11-01-2011'::date))
-> Materialize -> Materialize
-> Hash Join -> Hash Join
Hash Cond: (r.cid = l.cid) Hash Cond: (r_1.cid = l.cid)
-> Seq Scan on credit_card r -> Seq Scan on credit_card r_1
-> Hash -> Hash
-> Seq Scan on customer l -> Seq Scan on customer l
Filter: (name = ("current_user"())::text) Filter: (name = ("current_user"())::text)
......
...@@ -2006,8 +2006,8 @@ SELECT * FROM parent; ...@@ -2006,8 +2006,8 @@ SELECT * FROM parent;
EXPLAIN (VERBOSE, COSTS OFF) EXPLAIN (VERBOSE, COSTS OFF)
WITH wcte AS ( INSERT INTO int8_tbl VALUES ( 42, 47 ) RETURNING q2 ) WITH wcte AS ( INSERT INTO int8_tbl VALUES ( 42, 47 ) RETURNING q2 )
DELETE FROM a USING wcte WHERE aa = q2; DELETE FROM a USING wcte WHERE aa = q2;
QUERY PLAN QUERY PLAN
-------------------------------------------------- ------------------------------------------------
Delete on public.a Delete on public.a
CTE wcte CTE wcte
-> Insert on public.int8_tbl -> Insert on public.int8_tbl
...@@ -2015,31 +2015,31 @@ DELETE FROM a USING wcte WHERE aa = q2; ...@@ -2015,31 +2015,31 @@ DELETE FROM a USING wcte WHERE aa = q2;
-> Result -> Result
Output: 42::bigint, 47::bigint Output: 42::bigint, 47::bigint
-> Nested Loop -> Nested Loop
Output: public.a.ctid, wcte.* Output: a.ctid, wcte.*
Join Filter: (public.a.aa = wcte.q2) Join Filter: (a.aa = wcte.q2)
-> Seq Scan on public.a -> Seq Scan on public.a
Output: public.a.ctid, public.a.aa Output: a.ctid, a.aa
-> CTE Scan on wcte -> CTE Scan on wcte
Output: wcte.*, wcte.q2 Output: wcte.*, wcte.q2
-> Nested Loop -> Nested Loop
Output: public.a.ctid, wcte.* Output: b.ctid, wcte.*
Join Filter: (public.a.aa = wcte.q2) Join Filter: (b.aa = wcte.q2)
-> Seq Scan on public.b a -> Seq Scan on public.b
Output: public.a.ctid, public.a.aa Output: b.ctid, b.aa
-> CTE Scan on wcte -> CTE Scan on wcte
Output: wcte.*, wcte.q2 Output: wcte.*, wcte.q2
-> Nested Loop -> Nested Loop
Output: public.a.ctid, wcte.* Output: c.ctid, wcte.*
Join Filter: (public.a.aa = wcte.q2) Join Filter: (c.aa = wcte.q2)
-> Seq Scan on public.c a -> Seq Scan on public.c
Output: public.a.ctid, public.a.aa Output: c.ctid, c.aa
-> CTE Scan on wcte -> CTE Scan on wcte
Output: wcte.*, wcte.q2 Output: wcte.*, wcte.q2
-> Nested Loop -> Nested Loop
Output: public.a.ctid, wcte.* Output: d.ctid, wcte.*
Join Filter: (public.a.aa = wcte.q2) Join Filter: (d.aa = wcte.q2)
-> Seq Scan on public.d a -> Seq Scan on public.d
Output: public.a.ctid, public.a.aa Output: d.ctid, d.aa
-> CTE Scan on wcte -> CTE Scan on wcte
Output: wcte.*, wcte.q2 Output: wcte.*, wcte.q2
(34 rows) (34 rows)
......
...@@ -224,6 +224,68 @@ SELECT relname, relkind, reloptions FROM pg_class ...@@ -224,6 +224,68 @@ SELECT relname, relkind, reloptions FROM pg_class
'mysecview3'::regclass, 'mysecview4'::regclass) 'mysecview3'::regclass, 'mysecview4'::regclass)
ORDER BY relname; 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 temp_view_test CASCADE;
DROP SCHEMA testviewschm2 CASCADE; DROP SCHEMA testviewschm2 CASCADE;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment