88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.130 2007/02/13 02:31:03 tgl Exp $
11+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.131 2007/02/16 20:57:19 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -43,7 +43,6 @@ static OuterJoinInfo *make_outerjoininfo(PlannerInfo *root,
4343Relids left_rels ,Relids right_rels ,
4444bool is_full_join ,Node * clause );
4545static void distribute_qual_to_rels (PlannerInfo * root ,Node * clause ,
46- bool is_pushed_down ,
4746bool is_deduced ,
4847bool below_outer_join ,
4948Relids qualscope ,
@@ -283,12 +282,11 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
283282}
284283
285284/*
286- * Now process the top-level quals. These are always marked as
287- * "pushed down", since they clearly didn't come from a JOIN expr.
285+ * Now process the top-level quals.
288286 */
289287foreach (l , (List * )f -> quals )
290288distribute_qual_to_rels (root , (Node * )lfirst (l ),
291- true, false,below_outer_join ,
289+ false,below_outer_join ,
292290* qualscope ,NULL ,NULL );
293291}
294292else if (IsA (jtnode ,JoinExpr ))
@@ -389,7 +387,7 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
389387/* Process the qual clauses */
390388foreach (qual , (List * )j -> quals )
391389distribute_qual_to_rels (root , (Node * )lfirst (qual ),
392- false,false, below_outer_join ,
390+ false,below_outer_join ,
393391* qualscope ,ojscope ,nonnullable_rels );
394392
395393/* Now we can add the OuterJoinInfo to oj_info_list */
@@ -600,8 +598,6 @@ make_outerjoininfo(PlannerInfo *root,
600598 * EquivalenceClasses.
601599 *
602600 * 'clause': the qual clause to be distributed
603- * 'is_pushed_down': if TRUE, force the clause to be marked 'is_pushed_down'
604- *(this indicates the clause came from a FromExpr, not a JoinExpr)
605601 * 'is_deduced': TRUE if the qual came from implied-equality deduction
606602 * 'below_outer_join': TRUE if the qual is from a JOIN/ON that is below the
607603 *nullable side of a higher-level outer join
@@ -619,14 +615,14 @@ make_outerjoininfo(PlannerInfo *root,
619615 */
620616static void
621617distribute_qual_to_rels (PlannerInfo * root ,Node * clause ,
622- bool is_pushed_down ,
623618bool is_deduced ,
624619bool below_outer_join ,
625620Relids qualscope ,
626621Relids ojscope ,
627622Relids outerjoin_nonnullable )
628623{
629624Relids relids ;
625+ bool is_pushed_down ;
630626bool outerjoin_delayed ;
631627bool pseudoconstant = false;
632628bool maybe_equivalence ;
@@ -692,17 +688,37 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
692688root -> hasPseudoConstantQuals = true;
693689/* if not below outer join, push it to top of tree */
694690if (!below_outer_join )
695- {
696691relids = get_relids_in_jointree ((Node * )root -> parse -> jointree );
697- is_pushed_down = true;
698- }
699692}
700693}
701694}
702695
703- /*
696+ /*----------
704697 * Check to see if clause application must be delayed by outer-join
705698 * considerations.
699+ *
700+ * A word about is_pushed_down: we mark the qual as "pushed down" if
701+ * it is (potentially) applicable at a level different from its original
702+ * syntactic level. This flag is used to distinguish OUTER JOIN ON quals
703+ * from other quals pushed down to the same joinrel. The rules are:
704+ *WHERE quals and INNER JOIN quals: is_pushed_down = true.
705+ *Non-degenerate OUTER JOIN quals: is_pushed_down = false.
706+ *Degenerate OUTER JOIN quals: is_pushed_down = true.
707+ * A "degenerate" OUTER JOIN qual is one that doesn't mention the
708+ * non-nullable side, and hence can be pushed down into the nullable side
709+ * without changing the join result. It is correct to treat it as a
710+ * regular filter condition at the level where it is evaluated.
711+ *
712+ * Note: it is not immediately obvious that a simple boolean is enough
713+ * for this: if for some reason we were to attach a degenerate qual to
714+ * its original join level, it would need to be treated as an outer join
715+ * qual there. However, this cannot happen, because all the rels the
716+ * clause mentions must be in the outer join's min_righthand, therefore
717+ * the join it needs must be formed before the outer join; and we always
718+ * attach quals to the lowest level where they can be evaluated. But
719+ * if we were ever to re-introduce a mechanism for delaying evaluation
720+ * of "expensive" quals, this area would need work.
721+ *----------
706722 */
707723if (is_deduced )
708724{
@@ -713,6 +729,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
713729 * where the qual belongs.
714730 */
715731Assert (!ojscope );
732+ is_pushed_down = true;
716733outerjoin_delayed = false;
717734/* Don't feed it back for more deductions */
718735maybe_equivalence = false;
@@ -722,12 +739,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
722739{
723740/*
724741 * The qual is attached to an outer join and mentions (some of the)
725- * rels on the nonnullable side.
726- *
727- * Note: an outer-join qual that mentions only nullable-side rels can
728- * be pushed down into the nullable side without changing the join
729- * result, so we treat it almost the same as an ordinary inner-join
730- * qual (see below).
742+ * rels on the nonnullable side, so it's not degenerate.
731743 *
732744 * We can't use such a clause to deduce equivalence (the left and right
733745 * sides might be unequal above the join because one of them has gone
@@ -751,12 +763,19 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
751763 */
752764Assert (ojscope );
753765relids = ojscope ;
766+ is_pushed_down = false;
754767outerjoin_delayed = true;
755768Assert (!pseudoconstant );
756769}
757770else
758771{
759- /* Normal qual clause; check to see if must be delayed by outer join */
772+ /*
773+ * Normal qual clause or degenerate outer-join clause. Either way,
774+ * we can mark it as pushed-down.
775+ */
776+ is_pushed_down = true;
777+
778+ /* Check to see if must be delayed by outer join */
760779outerjoin_delayed = check_outerjoin_delay (root ,& relids );
761780
762781if (outerjoin_delayed )
@@ -791,17 +810,6 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
791810maybe_outer_join = false;
792811}
793812
794- /*
795- * Mark the qual as "pushed down" if it can be applied at a level below
796- * its original syntactic level. This allows us to distinguish original
797- * JOIN/ON quals from higher-level quals pushed down to the same joinrel.
798- * A qual originating from WHERE is always considered "pushed down". Note
799- * that for an outer-join qual, we have to compare to ojscope not
800- * qualscope.
801- */
802- if (!is_pushed_down )
803- is_pushed_down = !bms_equal (relids ,ojscope ?ojscope :qualscope );
804-
805813/*
806814 * Build the RestrictInfo node itself.
807815 */
@@ -915,7 +923,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
915923 * If so, add relids to *relids_p to reflect the lowest safe level for
916924 * evaluating the qual, and return TRUE.
917925 *
918- * Fora non-outer-join qual, we can evaluate the qual as soon as (1) we have
926+ * Foran is_pushed_down qual, we can evaluate the qual as soon as (1) we have
919927 * all the rels it mentions, and (2) we are at or above any outer joins that
920928 * can null any of these rels and are below the syntactic location of the
921929 * given qual. We must enforce (2) because pushing down such a clause below
@@ -935,7 +943,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
935943 * B/C join is done first then the join to A can null C, so a qual actually
936944 * mentioning only C cannot be applied below the join to A.
937945 *
938- * Foran outer-join qual, this isn't going to determine where we place the
946+ * Fora non-pushed-down qual, this isn't going to determine where we place the
939947 * qual, but we need to determine outerjoin_delayed anyway so we can decide
940948 * whether the qual is potentially useful for equivalence deductions.
941949 */
@@ -1101,12 +1109,9 @@ process_implied_equality(PlannerInfo *root,
11011109
11021110/*
11031111 * Push the new clause into all the appropriate restrictinfo lists.
1104- *
1105- * Note: we mark the qual "pushed down" to ensure that it can never be
1106- * taken for an original JOIN/ON clause.
11071112 */
11081113distribute_qual_to_rels (root , (Node * )clause ,
1109- true,true, below_outer_join ,
1114+ true,below_outer_join ,
11101115qualscope ,NULL ,NULL );
11111116}
11121117