diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index b7aff37..795739f 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -2071,14 +2071,15 @@ generate_implied_equalities_for_column(PlannerInfo *root, { List *result = NIL; bool is_child_rel = (rel->reloptkind == RELOPT_OTHER_MEMBER_REL); - Index parent_relid; + Index top_parent_relid; ListCell *lc1; - /* If it's a child rel, we'll need to know what its parent is */ + /* If it's a child rel, we'll need to know what its top parent is */ if (is_child_rel) - parent_relid = find_childrel_appendrelinfo(root, rel)->parent_relid; + top_parent_relid = + find_childrel_appendrelinfo(root, rel)->top_parent_relid; else - parent_relid = 0; /* not used, but keep compiler quiet */ + top_parent_relid = 0; /* not used, but keep compiler quiet */ foreach(lc1, root->eq_classes) { @@ -2151,7 +2152,7 @@ generate_implied_equalities_for_column(PlannerInfo *root, * to its parent rel. */ if (is_child_rel && - bms_is_member(parent_relid, other_em->em_relids)) + bms_is_member(top_parent_relid, other_em->em_relids)) continue; eq_op = select_equality_operator(cur_ec, diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index 9cb1378..3bdfbec 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -1196,6 +1196,7 @@ pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex, make_setop_translation_list(setOpQuery, childRTindex, &appinfo->translated_vars); appinfo->parent_reloid = InvalidOid; + adjust_appendrel_top_parent(root, appinfo); root->append_rel_list = lappend(root->append_rel_list, appinfo); /* diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 0410fdd..93ae3af 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -112,6 +112,8 @@ static Node *adjust_appendrel_attrs_mutator(Node *node, static Relids adjust_relid_set(Relids relids, Index oldrelid, Index newrelid); static List *adjust_inherited_tlist(List *tlist, AppendRelInfo *context); +static Index adjust_appendrel_top_parent_worker(PlannerInfo *root, + AppendRelInfo *context); /* @@ -1359,6 +1361,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti) make_inh_translation_list(oldrelation, newrelation, childRTindex, &appinfo->translated_vars); appinfo->parent_reloid = parentOID; + adjust_appendrel_top_parent(root, appinfo); appinfos = lappend(appinfos, appinfo); /* @@ -1884,6 +1887,48 @@ adjust_relid_set(Relids relids, Index oldrelid, Index newrelid) } /* + * Recursive wrapper for adjust_appendrel_top_parent + */ +static Index +adjust_appendrel_top_parent_worker(PlannerInfo *root, + AppendRelInfo *context) +{ + Index top_parent_relid = context->parent_relid; + ListCell *l; + + /* Scan direct parent and return its index */ + foreach(l, root->append_rel_list) + { + AppendRelInfo *appinfo = lfirst(l); + + /* + * Check if this appendrel is the direct parent of the one + * saved in context. + */ + if (context->parent_relid == appinfo->child_relid) + { + top_parent_relid = adjust_appendrel_top_parent_worker(root, appinfo); + break; + } + } + + return top_parent_relid; +} + +/* + * Scan the list of AppendRelInfo in this plan root and find + * the top-level parent for the given relation. + */ +void +adjust_appendrel_top_parent(PlannerInfo *root, + AppendRelInfo *appinfo) +{ + /* Set result value */ + appinfo->top_parent_relid = + adjust_appendrel_top_parent_worker(root, appinfo); +} + +/* * Adjust the targetlist entries of an inherited UPDATE operation * * The expressions have already been fixed, but we have to make sure that diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index f1a0504..c921cdd 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -1441,8 +1441,15 @@ typedef struct AppendRelInfo * parent_relid, but never more than one per child_relid, since a given * RTE cannot be a child of more than one append parent. */ - Index parent_relid; /* RT index of append parent rel */ - Index child_relid; /* RT index of append child rel */ + Index parent_relid; /* RT index of append parent rel */ + Index child_relid; /* RT index of append child rel */ + + /* + * Identify the top level parent. If this AppendRelInfo does not have + * more than one generation of parent top_parent_relid has the same + * value as parent_relid. + */ + Index top_parent_relid; /* RT index of append top parent rel */ /* * For an inheritance appendrel, the parent and child are both regular diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h index f5fc7e8..54b195e 100644 --- a/src/include/optimizer/prep.h +++ b/src/include/optimizer/prep.h @@ -57,5 +57,7 @@ extern void expand_inherited_tables(PlannerInfo *root); extern Node *adjust_appendrel_attrs(PlannerInfo *root, Node *node, AppendRelInfo *appinfo); +extern void adjust_appendrel_top_parent(PlannerInfo *root, + AppendRelInfo *appinfo); #endif /* PREP_H */ diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out index 2501184..101186c 100644 --- a/src/test/regress/expected/join.out +++ b/src/test/regress/expected/join.out @@ -4339,3 +4339,34 @@ ERROR: invalid reference to FROM-clause entry for table "xx1" LINE 1: ...xx1 using lateral (select * from int4_tbl where f1 = x1) ss; ^ HINT: There is an entry for table "xx1", but it cannot be referenced from this part of the query. +-- Test two-level of relation dependencies joined +CREATE TABLE tab_child (id int primary key); +CREATE TABLE tab_parent (id int primary key references tab_child); +CREATE TABLE tab_grandparent (id int primary key references tab_parent); +EXPLAIN (VERBOSE, COSTS off) SELECT union2.id + FROM (SELECT union1.id + FROM (SELECT tab_child.id FROM tab_child + UNION ALL + SELECT tab_parent.id FROM tab_parent) AS union1 + UNION ALL + SELECT tab_grandparent.id FROM tab_grandparent) AS union2 +INNER JOIN tab_child ON union2.id = tab_child.id; + QUERY PLAN +------------------------------------------------------ + Hash Join + Output: tab_child_1.id + Hash Cond: (tab_child_1.id = tab_child.id) + -> Append + -> Seq Scan on public.tab_child tab_child_1 + Output: tab_child_1.id + -> Seq Scan on public.tab_parent + Output: tab_parent.id + -> Seq Scan on public.tab_grandparent + Output: tab_grandparent.id + -> Hash + Output: tab_child.id + -> Seq Scan on public.tab_child + Output: tab_child.id +(14 rows) + +DROP TABLE tab_child, tab_parent, tab_grandparent; diff --git a/src/test/regress/sql/join.sql b/src/test/regress/sql/join.sql index 718e1d9..d5f27cb 100644 --- a/src/test/regress/sql/join.sql +++ b/src/test/regress/sql/join.sql @@ -1267,3 +1267,17 @@ update xx1 set x2 = f1 from xx1, lateral (select * from int4_tbl where f1 = x1) delete from xx1 using (select * from int4_tbl where f1 = x1) ss; delete from xx1 using (select * from int4_tbl where f1 = xx1.x1) ss; delete from xx1 using lateral (select * from int4_tbl where f1 = x1) ss; + +-- Test two-level of relation dependencies joined +CREATE TABLE tab_child (id int primary key); +CREATE TABLE tab_parent (id int primary key references tab_child); +CREATE TABLE tab_grandparent (id int primary key references tab_parent); +EXPLAIN (VERBOSE, COSTS off) SELECT union2.id + FROM (SELECT union1.id + FROM (SELECT tab_child.id FROM tab_child + UNION ALL + SELECT tab_parent.id FROM tab_parent) AS union1 + UNION ALL + SELECT tab_grandparent.id FROM tab_grandparent) AS union2 +INNER JOIN tab_child ON union2.id = tab_child.id; +DROP TABLE tab_child, tab_parent, tab_grandparent;