diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2003-02-10 17:08:50 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2003-02-10 17:08:50 +0000 |
commit | 8a4fdce9f277fe1f02654091e89e96180af9c4cb (patch) | |
tree | d55143b4f8782ad8f710573191ce50a688d1e1bd /src/backend | |
parent | ec8f0e82ef63927e48615b2684258eb8ce84c599 (diff) | |
download | postgresql-8a4fdce9f277fe1f02654091e89e96180af9c4cb.tar.gz postgresql-8a4fdce9f277fe1f02654091e89e96180af9c4cb.zip |
Fix thinko in new logic about pushing down non-nullability constraints:
constraints appearing in outer-join qualification clauses are restricted
as to when and where they can be pushed down. Add regression test
to catch future errors in this area.
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/optimizer/prep/prepjointree.c | 38 |
1 files changed, 30 insertions, 8 deletions
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index 54fd393df59..207a813e8e0 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -16,7 +16,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.5 2003/02/09 23:57:19 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.6 2003/02/10 17:08:50 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -694,23 +694,45 @@ reduce_outer_joins_pass2(Node *jtnode, /* Only recurse if there's more to do below here */ if (left_state->contains_outer || right_state->contains_outer) { + Relids local_nonnullable; Relids pass_nonnullable; /* - * Scan join quals to see if we can add any nonnullability - * constraints. (Okay to do this even if join is still outer.) + * If this join is (now) inner, we can add any nonnullability + * constraints its quals provide to those we got from above. + * But if it is outer, we can only pass down the local constraints + * into the nullable side, because an outer join never eliminates + * any rows from its non-nullable side. If it's a FULL join then + * it doesn't eliminate anything from either side. */ - pass_nonnullable = find_nonnullable_rels(j->quals, true); - pass_nonnullable = bms_add_members(pass_nonnullable, - nonnullable_rels); - /* And recurse as needed */ + if (jointype != JOIN_FULL) + { + local_nonnullable = find_nonnullable_rels(j->quals, true); + local_nonnullable = bms_add_members(local_nonnullable, + nonnullable_rels); + } + else + local_nonnullable = NULL; /* no use in calculating it */ + if (left_state->contains_outer) + { + if (jointype == JOIN_INNER || jointype == JOIN_RIGHT) + pass_nonnullable = local_nonnullable; + else + pass_nonnullable = nonnullable_rels; reduce_outer_joins_pass2(j->larg, left_state, parse, pass_nonnullable); + } if (right_state->contains_outer) + { + if (jointype == JOIN_INNER || jointype == JOIN_LEFT) + pass_nonnullable = local_nonnullable; + else + pass_nonnullable = nonnullable_rels; reduce_outer_joins_pass2(j->rarg, right_state, parse, pass_nonnullable); - bms_free(pass_nonnullable); + } + bms_free(local_nonnullable); } } else |