From 7920ed389cb361e8580e379e60c094f376ec9672 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 20 Feb 2009 00:01:03 +0000 Subject: [PATCH] Simplify overcomplicated (and overly restrictive) test to see whether an IS NULL condition is rendered redundant by detection of an antijoin. If we know that a join is an antijoin, then *any* Var coming out of its righthand side must be NULL, not only the joining column(s). Also, it's still gonna be null after being passed up through higher joins, whether they're outer joins or not. I was misled by a faulty analogy to reduce_outer_joins() in the original coding. But consider select * from a left join b on a.x = b.y where b.y is null and b.z is null; The first IS NULL condition justifies deciding that the join is an antijoin (if the = is strict) and then the second one is just plain redundant. --- src/backend/optimizer/plan/initsplan.c | 42 +++++--------------------- 1 file changed, 8 insertions(+), 34 deletions(-) diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index d8639a67e4..1b3296f971 100644 --- a/src/backend/optimizer/plan/initsplan.c +++ b/src/backend/optimizer/plan/initsplan.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.146 2009/01/01 17:23:44 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.147 2009/02/20 00:01:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -725,6 +725,9 @@ make_outerjoininfo(PlannerInfo *root, * 'qualscope' identifies what level of JOIN the qual came from syntactically. * 'ojscope' is needed if we decide to force the qual up to the outer-join * level, which will be ojscope not necessarily qualscope. + * + * At the time this is called, root->join_info_list must contain entries for + * all and only those special joins that are syntactically below this qual. */ static void distribute_qual_to_rels(PlannerInfo *root, Node *clause, @@ -1209,7 +1212,6 @@ check_redundant_nullability_qual(PlannerInfo *root, Node *clause) { Var *forced_null_var; Index forced_null_rel; - SpecialJoinInfo *match_sjinfo = NULL; ListCell *lc; /* Check for IS NULL, and identify the Var forced to NULL */ @@ -1219,47 +1221,19 @@ check_redundant_nullability_qual(PlannerInfo *root, Node *clause) forced_null_rel = forced_null_var->varno; /* - * Search to see if there's a matching antijoin that is not masked by - * a higher outer join. Because we have to scan the join info bottom-up, - * we have to continue looking after finding a match to check for masking - * joins. This logic should agree with reduce_outer_joins's code - * to detect antijoins on the basis of IS NULL clauses. (It's tempting - * to consider adding some data structures to avoid redundant work, - * but in practice this code shouldn't get executed often enough to - * make it worth the trouble.) + * If the Var comes from the nullable side of a lower antijoin, the + * IS NULL condition is necessarily true. */ foreach(lc, root->join_info_list) { SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(lc); - /* Check for match ... */ if (sjinfo->jointype == JOIN_ANTI && bms_is_member(forced_null_rel, sjinfo->syn_righthand)) - { - List *nonnullable_vars; - - nonnullable_vars = find_nonnullable_vars((Node *) sjinfo->join_quals); - if (list_member(nonnullable_vars, forced_null_var)) - { - match_sjinfo = sjinfo; - continue; - } - } - /* - * Else, if we had a lower match, check to see if the target var is - * from the nullable side of this OJ. If so, this OJ masks the - * lower one and we can no longer consider the IS NULL as redundant - * with the lower antijoin. - */ - if (!match_sjinfo) - continue; - if (bms_is_member(forced_null_rel, sjinfo->syn_righthand) || - (sjinfo->jointype == JOIN_FULL && - bms_is_member(forced_null_rel, sjinfo->syn_lefthand))) - match_sjinfo = NULL; + return true; } - return (match_sjinfo != NULL); + return false; } /*