1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00

Fix self-join elimination to avoid inheritance scans.

Self-join elimination failed to check for inheritance cases,
which has two big problems.  First, a unique index on the parent
table isn't sufficient to prove uniqueness across its children too.
Second, since we matched RTEs by OID without considering rte->inh,
we could try to merge "mytable" with "mytable ONLY", which doesn't
even represent the same set of rows.

We can fix both issues by just skipping RTEs that have inh set.
preprocess_relation_rtes already cleared that flag for tables known
not to have inheritance children, so this doesn't break SJE for the
cases where it's valid.

Author: Tender Wang <tndrwang@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAHewXNn4EjCQEvanN_FPKQ3OJWaBXq8Pxcj-DZYbeQ6_4xSFgw@mail.gmail.com
Backpatch-through: 18
This commit is contained in:
Tom Lane
2026-10-14 16:38:15 -04:00
parent 18aca7257e
commit ebf82fae68

View File

@@ -2018,7 +2018,7 @@ remove_self_joins_recurse(PlannerInfo *root, List *joinlist)
int j;
int numRels;
/* Collect indexes of base relations of the join tree */
/* Collect indexes of possibly-mergeable relations from the joinlist */
foreach(jl, joinlist)
{
Node *jlnode = (Node *) lfirst(jl);
@@ -2029,15 +2029,31 @@ remove_self_joins_recurse(PlannerInfo *root, List *joinlist)
RangeTblEntry *rte = root->simple_rte_array[varno];
/*
* We only consider ordinary relations as candidates to be
* removed, and these relations should not have TABLESAMPLE
* clauses specified. Removing a relation with TABLESAMPLE clause
* could potentially change the semantics of the query. Because of
* UPDATE/DELETE EPQ mechanism, currently Query->resultRelation or
* Query->mergeTargetRelation associated rel cannot be eliminated.
* To be considered for self-join removal, the RTE must:
*
* 1. Be an ordinary relation. (Someday we might support SJE on
* partitioned tables, but not yet.)
*
* 2. Not have inh set, ie it has no inheritance children (or the
* user wrote ONLY to ignore them). Under traditional inheritance
* a unique index on a parent table does not establish uniqueness
* across its children. This rule also keeps us from trying to
* merge an inheritance scan with an ONLY scan, which would be
* wrong. (preprocess_relation_rtes already cleared the inh flag
* for tables known not to have inheritance children.)
*
* 3. Not have a TABLESAMPLE clause. Removing a relation with a
* TABLESAMPLE clause would change the semantics of the query,
* even if we merged it with another RTE with an identical
* TABLESAMPLE clause. (Two such RTEs should represent
* independent samplings of the base table.)
*
* 4. Not be the query's result relation or MERGE target. Merging
* would cause misbehavior during EPQ.
*/
if (rte->rtekind == RTE_RELATION &&
rte->relkind == RELKIND_RELATION &&
!rte->inh &&
rte->tablesample == NULL &&
varno != root->parse->resultRelation &&
varno != root->parse->mergeTargetRelation)