Commit 55a1954d authored by Tom Lane's avatar Tom Lane

Fix EXPLAIN's column alias output for mismatched child tables.

If an inheritance/partitioning parent table is assigned some column
alias names in the query, EXPLAIN mapped those aliases onto the
child tables' columns by physical position, resulting in bogus output
if a child table's columns aren't one-for-one with the parent's.

To fix, make expand_single_inheritance_child() generate a correctly
re-mapped column alias list, rather than just copying the parent
RTE's alias node.  (We have to fill the alias field, not just
adjust the eref field, because ruleutils.c will ignore eref in
favor of looking at the real column names.)

This means that child tables will now always have alias fields in
plan rtables, where before they might not have.  That results in
a rather substantial set of regression test output changes:
EXPLAIN will now always show child tables with aliases that match
the parent table (usually with "_N" appended for uniqueness).
But that seems like a net positive for understandability, since
the parent alias corresponds to something that actually appeared
in the original query, while the child table names didn't.
(Note that this does not change anything for cases where an explicit
table alias was written in the query for the parent table; it
just makes cases without such aliases behave similarly to that.)
Hence, while we could avoid these subsidiary changes if we made
inherit.c more complicated, we choose not to.

Discussion: https://postgr.es/m/12424.1575168015@sss.pgh.pa.us
parent ce76c0ba
......@@ -421,10 +421,13 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
RangeTblEntry *childrte;
Index childRTindex;
AppendRelInfo *appinfo;
TupleDesc child_tupdesc;
List *parent_colnames;
List *child_colnames;
/*
* Build an RTE for the child, and attach to query's rangetable list. We
* copy most fields of the parent's RTE, but replace relation OID,
* copy most scalar fields of the parent's RTE, but replace relation OID,
* relkind, and inh for the child. Also, set requiredPerms to zero since
* all required permissions checks are done on the original RTE. Likewise,
* set the child's securityQuals to empty, because we only want to apply
......@@ -432,10 +435,14 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
* individual children may have. (This is an intentional choice to make
* inherited RLS work like regular permissions checks.) The parent
* securityQuals will be propagated to children along with other base
* restriction clauses, so we don't need to do it here.
* restriction clauses, so we don't need to do it here. Other
* infrastructure of the parent RTE has to be translated to match the
* child table's column ordering, which we do below, so a "flat" copy is
* sufficient to start with.
*/
childrte = copyObject(parentrte);
*childrte_p = childrte;
childrte = makeNode(RangeTblEntry);
memcpy(childrte, parentrte, sizeof(RangeTblEntry));
Assert(parentrte->rtekind == RTE_RELATION); /* else this is dubious */
childrte->relid = childOID;
childrte->relkind = childrel->rd_rel->relkind;
/* A partitioned child will need to be expanded further. */
......@@ -448,8 +455,11 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
childrte->inh = false;
childrte->requiredPerms = 0;
childrte->securityQuals = NIL;
/* Link not-yet-fully-filled child RTE into data structures */
parse->rtable = lappend(parse->rtable, childrte);
childRTindex = list_length(parse->rtable);
*childrte_p = childrte;
*childRTindex_p = childRTindex;
/*
......@@ -459,10 +469,57 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
parentRTindex, childRTindex);
root->append_rel_list = lappend(root->append_rel_list, appinfo);
/* tablesample is probably null, but copy it */
childrte->tablesample = copyObject(parentrte->tablesample);
/*
* Construct an alias clause for the child, which we can also use as eref.
* This is important so that EXPLAIN will print the right column aliases
* for child-table columns. (Since ruleutils.c doesn't have any easy way
* to reassociate parent and child columns, we must get the child column
* aliases right to start with. Note that setting childrte->alias forces
* ruleutils.c to use these column names, which it otherwise would not.)
*/
child_tupdesc = RelationGetDescr(childrel);
parent_colnames = parentrte->eref->colnames;
child_colnames = NIL;
for (int cattno = 0; cattno < child_tupdesc->natts; cattno++)
{
Form_pg_attribute att = TupleDescAttr(child_tupdesc, cattno);
const char *attname;
if (att->attisdropped)
{
/* Always insert an empty string for a dropped column */
attname = "";
}
else if (appinfo->parent_colnos[cattno] > 0 &&
appinfo->parent_colnos[cattno] <= list_length(parent_colnames))
{
/* Duplicate the query-assigned name for the parent column */
attname = strVal(list_nth(parent_colnames,
appinfo->parent_colnos[cattno] - 1));
}
else
{
/* New column, just use its real name */
attname = NameStr(att->attname);
}
child_colnames = lappend(child_colnames, makeString(pstrdup(attname)));
}
/*
* We just duplicate the parent's table alias name for each child. If the
* plan gets printed, ruleutils.c has to sort out unique table aliases to
* use, which it can handle.
*/
childrte->alias = childrte->eref = makeAlias(parentrte->eref->aliasname,
child_colnames);
/*
* Translate the column permissions bitmaps to the child's attnums (we
* have to build the translated_vars list before we can do this). But if
* this is the parent table, we can leave copyObject's result alone.
* this is the parent table, we can just duplicate the parent's bitmaps.
*
* Note: we need to do this even though the executor won't run any
* permissions checks on the child RTE. The insertedCols/updatedCols
......@@ -479,6 +536,13 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
childrte->extraUpdatedCols = translate_col_privs(parentrte->extraUpdatedCols,
appinfo->translated_vars);
}
else
{
childrte->selectedCols = bms_copy(parentrte->selectedCols);
childrte->insertedCols = bms_copy(parentrte->insertedCols);
childrte->updatedCols = bms_copy(parentrte->updatedCols);
childrte->extraUpdatedCols = bms_copy(parentrte->extraUpdatedCols);
}
/*
* Store the RTE and appinfo in the respective PlannerInfo arrays, which
......
......@@ -998,8 +998,8 @@ 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
......@@ -1007,22 +1007,22 @@ explain (costs off)
Sort Key: minmaxtest.f1
-> Index Only Scan using minmaxtesti on minmaxtest
Index Cond: (f1 IS NOT NULL)
-> Index Only Scan using minmaxtest1i on minmaxtest1
-> Index Only Scan using minmaxtest1i on minmaxtest1 minmaxtest_1
Index Cond: (f1 IS NOT NULL)
-> Index Only Scan Backward using minmaxtest2i on minmaxtest2
-> Index Only Scan Backward using minmaxtest2i on minmaxtest2 minmaxtest_2
Index Cond: (f1 IS NOT NULL)
-> Index Only Scan using minmaxtest3i on minmaxtest3
-> Index Only Scan using minmaxtest3i on minmaxtest3 minmaxtest_3
InitPlan 2 (returns $1)
-> Limit
-> Merge Append
Sort Key: minmaxtest_1.f1 DESC
-> Index Only Scan Backward using minmaxtesti on minmaxtest minmaxtest_1
Sort Key: minmaxtest_4.f1 DESC
-> Index Only Scan Backward using minmaxtesti on minmaxtest minmaxtest_4
Index Cond: (f1 IS NOT NULL)
-> Index Only Scan Backward using minmaxtest1i on minmaxtest1 minmaxtest1_1
-> Index Only Scan Backward using minmaxtest1i on minmaxtest1 minmaxtest_5
Index Cond: (f1 IS NOT NULL)
-> Index Only Scan using minmaxtest2i on minmaxtest2 minmaxtest2_1
-> Index Only Scan using minmaxtest2i on minmaxtest2 minmaxtest_6
Index Cond: (f1 IS NOT NULL)
-> Index Only Scan Backward using minmaxtest3i on minmaxtest3 minmaxtest3_1
-> Index Only Scan Backward using minmaxtest3i on minmaxtest3 minmaxtest_7
(23 rows)
select min(f1), max(f1) from minmaxtest;
......@@ -1034,8 +1034,8 @@ select min(f1), max(f1) from minmaxtest;
-- DISTINCT doesn't do anything useful here, but it shouldn't fail
explain (costs off)
select distinct min(f1), max(f1) from minmaxtest;
QUERY PLAN
----------------------------------------------------------------------------------------------
QUERY PLAN
---------------------------------------------------------------------------------------------
Unique
InitPlan 1 (returns $0)
-> Limit
......@@ -1043,22 +1043,22 @@ explain (costs off)
Sort Key: minmaxtest.f1
-> Index Only Scan using minmaxtesti on minmaxtest
Index Cond: (f1 IS NOT NULL)
-> Index Only Scan using minmaxtest1i on minmaxtest1
-> Index Only Scan using minmaxtest1i on minmaxtest1 minmaxtest_1
Index Cond: (f1 IS NOT NULL)
-> Index Only Scan Backward using minmaxtest2i on minmaxtest2
-> Index Only Scan Backward using minmaxtest2i on minmaxtest2 minmaxtest_2
Index Cond: (f1 IS NOT NULL)
-> Index Only Scan using minmaxtest3i on minmaxtest3
-> Index Only Scan using minmaxtest3i on minmaxtest3 minmaxtest_3
InitPlan 2 (returns $1)
-> Limit
-> Merge Append
Sort Key: minmaxtest_1.f1 DESC
-> Index Only Scan Backward using minmaxtesti on minmaxtest minmaxtest_1
Sort Key: minmaxtest_4.f1 DESC
-> Index Only Scan Backward using minmaxtesti on minmaxtest minmaxtest_4
Index Cond: (f1 IS NOT NULL)
-> Index Only Scan Backward using minmaxtest1i on minmaxtest1 minmaxtest1_1
-> Index Only Scan Backward using minmaxtest1i on minmaxtest1 minmaxtest_5
Index Cond: (f1 IS NOT NULL)
-> Index Only Scan using minmaxtest2i on minmaxtest2 minmaxtest2_1
-> Index Only Scan using minmaxtest2i on minmaxtest2 minmaxtest_6
Index Cond: (f1 IS NOT NULL)
-> Index Only Scan Backward using minmaxtest3i on minmaxtest3 minmaxtest3_1
-> Index Only Scan Backward using minmaxtest3i on minmaxtest3 minmaxtest_7
-> Sort
Sort Key: ($0), ($1)
-> Result
......@@ -1156,7 +1156,7 @@ explain (costs off) select * from t1 group by a,b,c,d;
Group Key: t1.a, t1.b, t1.c, t1.d
-> Append
-> Seq Scan on t1
-> Seq Scan on t1c
-> Seq Scan on t1c t1_1
(5 rows)
-- Okay to remove columns if we're only querying the parent.
......@@ -1179,13 +1179,13 @@ create temp table p_t1_1 partition of p_t1 for values in(1);
create temp table p_t1_2 partition of p_t1 for values in(2);
-- Ensure we can remove non-PK columns for partitioned tables.
explain (costs off) select * from p_t1 group by a,b,c,d;
QUERY PLAN
---------------------------------
QUERY PLAN
---------------------------------------
HashAggregate
Group Key: p_t1_1.a, p_t1_1.b
Group Key: p_t1.a, p_t1.b
-> Append
-> Seq Scan on p_t1_1
-> Seq Scan on p_t1_2
-> Seq Scan on p_t1_1 p_t1
-> Seq Scan on p_t1_2 p_t1_1
(5 rows)
drop table t1 cascade;
......
......@@ -542,9 +542,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
-> Seq Scan on nv_child_2010 nv_parent_1
Filter: ((d >= '08-01-2011'::date) AND (d <= '08-31-2011'::date))
-> Seq Scan on nv_child_2011
-> Seq Scan on nv_child_2011 nv_parent_2
Filter: ((d >= '08-01-2011'::date) AND (d <= '08-31-2011'::date))
(7 rows)
......@@ -555,9 +555,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
-> Seq Scan on nv_child_2010 nv_parent_1
Filter: ((d >= '08-01-2011'::date) AND (d <= '08-31-2011'::date))
-> Seq Scan on nv_child_2011
-> Seq Scan on nv_child_2011 nv_parent_2
Filter: ((d >= '08-01-2011'::date) AND (d <= '08-31-2011'::date))
(7 rows)
......@@ -567,11 +567,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
-> Seq Scan on nv_child_2010 nv_parent_1
Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
-> Seq Scan on nv_child_2011
-> Seq Scan on nv_child_2011 nv_parent_2
Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
-> Seq Scan on nv_child_2009
-> Seq Scan on nv_child_2009 nv_parent_3
Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
(9 rows)
......@@ -583,9 +583,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
-> Seq Scan on nv_child_2010 nv_parent_1
Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
-> Seq Scan on nv_child_2009
-> Seq Scan on nv_child_2009 nv_parent_2
Filter: ((d >= '08-01-2009'::date) AND (d <= '08-31-2009'::date))
(7 rows)
......
This diff is collapsed.
This diff is collapsed.
......@@ -14,18 +14,18 @@ set max_parallel_workers_per_gather=4;
-- Parallel Append with partial-subplans
explain (costs off)
select round(avg(aa)), sum(aa) from a_star;
QUERY PLAN
-----------------------------------------------------
QUERY PLAN
--------------------------------------------------------------
Finalize Aggregate
-> Gather
Workers Planned: 3
-> Partial Aggregate
-> Parallel Append
-> Parallel Seq Scan on d_star
-> Parallel Seq Scan on f_star
-> Parallel Seq Scan on e_star
-> Parallel Seq Scan on b_star
-> Parallel Seq Scan on c_star
-> Parallel Seq Scan on d_star a_star_3
-> Parallel Seq Scan on f_star a_star_5
-> Parallel Seq Scan on e_star a_star_4
-> Parallel Seq Scan on b_star a_star_1
-> Parallel Seq Scan on c_star a_star_2
-> Parallel Seq Scan on a_star
(11 rows)
......@@ -40,18 +40,18 @@ alter table c_star set (parallel_workers = 0);
alter table d_star set (parallel_workers = 0);
explain (costs off)
select round(avg(aa)), sum(aa) from a_star;
QUERY PLAN
-----------------------------------------------------
QUERY PLAN
--------------------------------------------------------------
Finalize Aggregate
-> Gather
Workers Planned: 3
-> Partial Aggregate
-> Parallel Append
-> Seq Scan on d_star
-> Seq Scan on c_star
-> Parallel Seq Scan on f_star
-> Parallel Seq Scan on e_star
-> Parallel Seq Scan on b_star
-> Seq Scan on d_star a_star_3
-> Seq Scan on c_star a_star_2
-> Parallel Seq Scan on f_star a_star_5
-> Parallel Seq Scan on e_star a_star_4
-> Parallel Seq Scan on b_star a_star_1
-> Parallel Seq Scan on a_star
(11 rows)
......@@ -68,18 +68,18 @@ alter table e_star set (parallel_workers = 0);
alter table f_star set (parallel_workers = 0);
explain (costs off)
select round(avg(aa)), sum(aa) from a_star;
QUERY PLAN
--------------------------------------------
QUERY PLAN
-----------------------------------------------------
Finalize Aggregate
-> Gather
Workers Planned: 3
-> Partial Aggregate
-> Parallel Append
-> Seq Scan on d_star
-> Seq Scan on f_star
-> Seq Scan on e_star
-> Seq Scan on b_star
-> Seq Scan on c_star
-> Seq Scan on d_star a_star_3
-> Seq Scan on f_star a_star_5
-> Seq Scan on e_star a_star_4
-> Seq Scan on b_star a_star_1
-> Seq Scan on c_star a_star_2
-> Seq Scan on a_star
(11 rows)
......@@ -99,19 +99,19 @@ alter table f_star reset (parallel_workers);
set enable_parallel_append to off;
explain (costs off)
select round(avg(aa)), sum(aa) from a_star;
QUERY PLAN
-----------------------------------------------------
QUERY PLAN
--------------------------------------------------------------
Finalize Aggregate
-> Gather
Workers Planned: 1
-> Partial Aggregate
-> Append
-> Parallel Seq Scan on a_star
-> Parallel Seq Scan on b_star
-> Parallel Seq Scan on c_star
-> Parallel Seq Scan on d_star
-> Parallel Seq Scan on e_star
-> Parallel Seq Scan on f_star
-> Parallel Seq Scan on b_star a_star_1
-> Parallel Seq Scan on c_star a_star_2
-> Parallel Seq Scan on d_star a_star_3
-> Parallel Seq Scan on e_star a_star_4
-> Parallel Seq Scan on f_star a_star_5
(11 rows)
select round(avg(aa)), sum(aa) from a_star a4;
......
......@@ -200,11 +200,11 @@ explain (costs off)
-> Append
-> Sample Scan on person
Sampling: bernoulli ('100'::real)
-> Sample Scan on emp
-> Sample Scan on emp person_1
Sampling: bernoulli ('100'::real)
-> Sample Scan on student
-> Sample Scan on student person_2
Sampling: bernoulli ('100'::real)
-> Sample Scan on stud_emp
-> Sample Scan on stud_emp person_3
Sampling: bernoulli ('100'::real)
(10 rows)
......@@ -319,12 +319,12 @@ create table parted_sample_1 partition of parted_sample for values in (1);
create table parted_sample_2 partition of parted_sample for values in (2);
explain (costs off)
select * from parted_sample tablesample bernoulli (100);
QUERY PLAN
-------------------------------------------
QUERY PLAN
------------------------------------------------------
Append
-> Sample Scan on parted_sample_1
-> Sample Scan on parted_sample_1 parted_sample
Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_2
-> Sample Scan on parted_sample_2 parted_sample_1
Sampling: bernoulli ('100'::real)
(5 rows)
......
......@@ -751,15 +751,15 @@ explain (costs off)
UNION ALL
SELECT ab FROM t2) t
ORDER BY 1 LIMIT 8;
QUERY PLAN
------------------------------------------------
QUERY PLAN
-----------------------------------------------------
Limit
-> Merge Append
Sort Key: ((t1.a || t1.b))
-> Index Scan using t1_ab_idx on t1
-> Index Scan using t1c_ab_idx on t1c
-> Index Scan using t1c_ab_idx on t1c t1_1
-> Index Scan using t2_pkey on t2
-> Index Scan using t2c_pkey on t2c
-> Index Scan using t2c_pkey on t2c t2_1
(7 rows)
SELECT * FROM
......@@ -798,8 +798,8 @@ select event_id
Sort Key: events.event_id
-> Index Scan using events_pkey on events
-> Sort
Sort Key: events_child.event_id
-> Seq Scan on events_child
Sort Key: events_1.event_id
-> Seq Scan on events_child events_1
-> Index Scan using other_events_pkey on other_events
(7 rows)
......
......@@ -1548,28 +1548,28 @@ INSERT INTO other_tbl_parent VALUES (7),(200);
INSERT INTO other_tbl_child VALUES (8),(100);
EXPLAIN (costs off)
UPDATE rw_view1 SET a = a + 1000 FROM other_tbl_parent WHERE a = id;
QUERY PLAN
--------------------------------------------------------------
QUERY PLAN
------------------------------------------------------------------------
Update on base_tbl_parent
Update on base_tbl_parent
Update on base_tbl_child
Update on base_tbl_child base_tbl_parent_1
-> Hash Join
Hash Cond: (other_tbl_parent.id = base_tbl_parent.a)
-> Append
-> Seq Scan on other_tbl_parent
-> Seq Scan on other_tbl_child
-> Seq Scan on other_tbl_child other_tbl_parent_1
-> Hash
-> Seq Scan on base_tbl_parent
-> Merge Join
Merge Cond: (base_tbl_child.a = other_tbl_parent.id)
Merge Cond: (base_tbl_parent_1.a = other_tbl_parent.id)
-> Sort
Sort Key: base_tbl_child.a
-> Seq Scan on base_tbl_child
Sort Key: base_tbl_parent_1.a
-> Seq Scan on base_tbl_child base_tbl_parent_1
-> Sort
Sort Key: other_tbl_parent.id
-> Append
-> Seq Scan on other_tbl_parent
-> Seq Scan on other_tbl_child
-> Seq Scan on other_tbl_child other_tbl_parent_1
(20 rows)
UPDATE rw_view1 SET a = a + 1000 FROM other_tbl_parent WHERE a = id;
......@@ -2284,37 +2284,37 @@ UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a < 7 AND a != 6;
---------------------------------------------------------------------------------------------------------------------------
Update on public.t1
Update on public.t1
Update on public.t11
Update on public.t12
Update on public.t111
Update on public.t11 t1_1
Update on public.t12 t1_2
Update on public.t111 t1_3
-> Index Scan using t1_a_idx on public.t1
Output: 100, t1.b, t1.c, t1.ctid
Index Cond: ((t1.a > 5) AND (t1.a < 7))
Filter: ((t1.a <> 6) AND (alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t1.a) AND leakproof(t1.a))
SubPlan 1
-> Append
-> Seq Scan on public.t12 t12_1
-> Seq Scan on public.t12
Filter: (t12.a = t1.a)
-> Seq Scan on public.t111 t12_1
Filter: (t12_1.a = t1.a)
-> Seq Scan on public.t111 t111_1
Filter: (t111_1.a = t1.a)
SubPlan 2
-> Append
-> Seq Scan on public.t12 t12_2
Output: t12_2.a
-> Seq Scan on public.t111 t111_2
Output: t111_2.a
-> Index Scan using t11_a_idx on public.t11
Output: 100, t11.b, t11.c, t11.d, t11.ctid
Index Cond: ((t11.a > 5) AND (t11.a < 7))
Filter: ((t11.a <> 6) AND (alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t11.a) AND leakproof(t11.a))
-> Index Scan using t12_a_idx on public.t12
Output: 100, t12.b, t12.c, t12.e, t12.ctid
Index Cond: ((t12.a > 5) AND (t12.a < 7))
Filter: ((t12.a <> 6) AND (alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t12.a) AND leakproof(t12.a))
-> Index Scan using t111_a_idx on public.t111
Output: 100, t111.b, t111.c, t111.d, t111.e, t111.ctid
Index Cond: ((t111.a > 5) AND (t111.a < 7))
Filter: ((t111.a <> 6) AND (alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t111.a) AND leakproof(t111.a))
-> Seq Scan on public.t111 t12_3
Output: t12_3.a
-> Index Scan using t11_a_idx on public.t11 t1_1
Output: 100, t1_1.b, t1_1.c, t1_1.d, t1_1.ctid
Index Cond: ((t1_1.a > 5) AND (t1_1.a < 7))
Filter: ((t1_1.a <> 6) AND (alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t1_1.a) AND leakproof(t1_1.a))
-> Index Scan using t12_a_idx on public.t12 t1_2
Output: 100, t1_2.b, t1_2.c, t1_2.e, t1_2.ctid
Index Cond: ((t1_2.a > 5) AND (t1_2.a < 7))
Filter: ((t1_2.a <> 6) AND (alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t1_2.a) AND leakproof(t1_2.a))
-> Index Scan using t111_a_idx on public.t111 t1_3
Output: 100, t1_3.b, t1_3.c, t1_3.d, t1_3.e, t1_3.ctid
Index Cond: ((t1_3.a > 5) AND (t1_3.a < 7))
Filter: ((t1_3.a <> 6) AND (alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t1_3.a) AND leakproof(t1_3.a))
(33 rows)
UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a < 7 AND a != 6;
......@@ -2334,37 +2334,37 @@ UPDATE v1 SET a=a+1 WHERE snoop(a) AND leakproof(a) AND a = 8;
---------------------------------------------------------------------------------------------------------
Update on public.t1
Update on public.t1
Update on public.t11
Update on public.t12
Update on public.t111
Update on public.t11 t1_1
Update on public.t12 t1_2
Update on public.t111 t1_3
-> Index Scan using t1_a_idx on public.t1
Output: (t1.a + 1), t1.b, t1.c, t1.ctid
Index Cond: ((t1.a > 5) AND (t1.a = 8))
Filter: ((alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t1.a) AND leakproof(t1.a))
SubPlan 1
-> Append
-> Seq Scan on public.t12 t12_1
-> Seq Scan on public.t12
Filter: (t12.a = t1.a)
-> Seq Scan on public.t111 t12_1
Filter: (t12_1.a = t1.a)
-> Seq Scan on public.t111 t111_1
Filter: (t111_1.a = t1.a)
SubPlan 2
-> Append
-> Seq Scan on public.t12 t12_2
Output: t12_2.a
-> Seq Scan on public.t111 t111_2
Output: t111_2.a
-> Index Scan using t11_a_idx on public.t11
Output: (t11.a + 1), t11.b, t11.c, t11.d, t11.ctid
Index Cond: ((t11.a > 5) AND (t11.a = 8))
Filter: ((alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t11.a) AND leakproof(t11.a))
-> Index Scan using t12_a_idx on public.t12
Output: (t12.a + 1), t12.b, t12.c, t12.e, t12.ctid
Index Cond: ((t12.a > 5) AND (t12.a = 8))
Filter: ((alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t12.a) AND leakproof(t12.a))
-> Index Scan using t111_a_idx on public.t111
Output: (t111.a + 1), t111.b, t111.c, t111.d, t111.e, t111.ctid
Index Cond: ((t111.a > 5) AND (t111.a = 8))
Filter: ((alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t111.a) AND leakproof(t111.a))
-> Seq Scan on public.t111 t12_3
Output: t12_3.a
-> Index Scan using t11_a_idx on public.t11 t1_1
Output: (t1_1.a + 1), t1_1.b, t1_1.c, t1_1.d, t1_1.ctid
Index Cond: ((t1_1.a > 5) AND (t1_1.a = 8))
Filter: ((alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t1_1.a) AND leakproof(t1_1.a))
-> Index Scan using t12_a_idx on public.t12 t1_2
Output: (t1_2.a + 1), t1_2.b, t1_2.c, t1_2.e, t1_2.ctid
Index Cond: ((t1_2.a > 5) AND (t1_2.a = 8))
Filter: ((alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t1_2.a) AND leakproof(t1_2.a))
-> Index Scan using t111_a_idx on public.t111 t1_3
Output: (t1_3.a + 1), t1_3.b, t1_3.c, t1_3.d, t1_3.e, t1_3.ctid
Index Cond: ((t1_3.a > 5) AND (t1_3.a = 8))
Filter: ((alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t1_3.a) AND leakproof(t1_3.a))
(33 rows)
UPDATE v1 SET a=a+1 WHERE snoop(a) AND leakproof(a) AND a = 8;
......
......@@ -310,29 +310,29 @@ ALTER TABLE part_b_10_b_20 ATTACH PARTITION part_c_1_100 FOR VALUES FROM (1) TO
-- The order of subplans should be in bound order
EXPLAIN (costs off) UPDATE range_parted set c = c - 50 WHERE c > 97;
QUERY PLAN
-------------------------------------
QUERY PLAN
-------------------------------------------------
Update on range_parted
Update on part_a_1_a_10
Update on part_a_10_a_20
Update on part_b_1_b_10
Update on part_c_1_100
Update on part_d_1_15
Update on part_d_15_20
Update on part_b_20_b_30
-> Seq Scan on part_a_1_a_10
Update on part_a_1_a_10 range_parted_1
Update on part_a_10_a_20 range_parted_2
Update on part_b_1_b_10 range_parted_3
Update on part_c_1_100 range_parted_4
Update on part_d_1_15 range_parted_5
Update on part_d_15_20 range_parted_6
Update on part_b_20_b_30 range_parted_7
-> Seq Scan on part_a_1_a_10 range_parted_1
Filter: (c > '97'::numeric)
-> Seq Scan on part_a_10_a_20
-> Seq Scan on part_a_10_a_20 range_parted_2
Filter: (c > '97'::numeric)
-> Seq Scan on part_b_1_b_10
-> Seq Scan on part_b_1_b_10 range_parted_3
Filter: (c > '97'::numeric)
-> Seq Scan on part_c_1_100
-> Seq Scan on part_c_1_100 range_parted_4
Filter: (c > '97'::numeric)
-> Seq Scan on part_d_1_15
-> Seq Scan on part_d_1_15 range_parted_5
Filter: (c > '97'::numeric)
-> Seq Scan on part_d_15_20
-> Seq Scan on part_d_15_20 range_parted_6
Filter: (c > '97'::numeric)
-> Seq Scan on part_b_20_b_30
-> Seq Scan on part_b_20_b_30 range_parted_7
Filter: (c > '97'::numeric)
(22 rows)
......
......@@ -2185,9 +2185,9 @@ DELETE FROM a USING wcte WHERE aa = q2;
----------------------------------------------------
Delete on public.a
Delete on public.a
Delete on public.b
Delete on public.c
Delete on public.d
Delete on public.b a_1
Delete on public.c a_2
Delete on public.d a_3
CTE wcte
-> Insert on public.int8_tbl
Output: int8_tbl.q2
......@@ -2201,24 +2201,24 @@ DELETE FROM a USING wcte WHERE aa = q2;
-> CTE Scan on wcte
Output: wcte.*, wcte.q2
-> Nested Loop
Output: b.ctid, wcte.*
Join Filter: (b.aa = wcte.q2)
-> Seq Scan on public.b
Output: b.ctid, b.aa
Output: a_1.ctid, wcte.*
Join Filter: (a_1.aa = wcte.q2)
-> Seq Scan on public.b a_1
Output: a_1.ctid, a_1.aa
-> CTE Scan on wcte
Output: wcte.*, wcte.q2
-> Nested Loop
Output: c.ctid, wcte.*
Join Filter: (c.aa = wcte.q2)
-> Seq Scan on public.c
Output: c.ctid, c.aa
Output: a_2.ctid, wcte.*
Join Filter: (a_2.aa = wcte.q2)
-> Seq Scan on public.c a_2
Output: a_2.ctid, a_2.aa
-> CTE Scan on wcte
Output: wcte.*, wcte.q2
-> Nested Loop
Output: d.ctid, wcte.*
Join Filter: (d.aa = wcte.q2)
-> Seq Scan on public.d
Output: d.ctid, d.aa
Output: a_3.ctid, wcte.*
Join Filter: (a_3.aa = wcte.q2)
-> Seq Scan on public.d a_3
Output: a_3.ctid, a_3.aa
-> CTE Scan on wcte
Output: wcte.*, wcte.q2
(38 rows)
......
......@@ -202,8 +202,13 @@ CREATE TABLE part (a INT, b INT) PARTITION BY LIST (a);
CREATE TABLE part_p1 PARTITION OF part FOR VALUES IN (-2,-1,0,1,2);
CREATE TABLE part_p2 PARTITION OF part DEFAULT PARTITION BY RANGE(a);
CREATE TABLE part_p2_p1 PARTITION OF part_p2 DEFAULT;
CREATE TABLE part_rev (b INT, c INT, a INT);
ALTER TABLE part ATTACH PARTITION part_rev FOR VALUES IN (3); -- fail
ALTER TABLE part_rev DROP COLUMN c;
ALTER TABLE part ATTACH PARTITION part_rev FOR VALUES IN (3); -- now it's ok
INSERT INTO part VALUES (-1,-1), (1,1), (2,NULL), (NULL,-2),(NULL,NULL);
EXPLAIN (COSTS OFF) SELECT tableoid::regclass as part, a, b FROM part WHERE a IS NULL ORDER BY 1, 2, 3;
EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM part p(x) ORDER BY x;
--
-- some more cases
......
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