OSDN Git Service

Version 1.3.6
[pghintplan/pg_hint_plan.git] / core.c
diff --git a/core.c b/core.c
index ebed66d..e979fb3 100644 (file)
--- a/core.c
+++ b/core.c
  *     make_rels_by_clauseless_joins()
  *     join_is_legal()
  *     has_join_restriction()
- *     is_dummy_rel()
  *     restriction_is_constant_false()
  *
  *
- * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *-------------------------------------------------------------------------
@@ -860,6 +859,10 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
                                {
                                        SpecialJoinInfo *sjinfo = (SpecialJoinInfo *) lfirst(l);
 
+                                       /* ignore full joins --- their ordering is predetermined */
+                                       if (sjinfo->jointype == JOIN_FULL)
+                                               continue;
+
                                        if (bms_overlap(sjinfo->min_lefthand, join_plus_rhs) &&
                                                !bms_is_subset(sjinfo->min_righthand, join_plus_rhs))
                                        {
@@ -867,15 +870,6 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
                                                                                                                sjinfo->min_righthand);
                                                more = true;
                                        }
-                                       /* full joins constrain both sides symmetrically */
-                                       if (sjinfo->jointype == JOIN_FULL &&
-                                               bms_overlap(sjinfo->min_righthand, join_plus_rhs) &&
-                                               !bms_is_subset(sjinfo->min_lefthand, join_plus_rhs))
-                                       {
-                                               join_plus_rhs = bms_add_members(join_plus_rhs,
-                                                                                                               sjinfo->min_lefthand);
-                                               more = true;
-                                       }
                                }
                        } while (more);
                        if (bms_overlap(join_plus_rhs, join_lateral_rels))
@@ -942,15 +936,6 @@ has_join_restriction(PlannerInfo *root, RelOptInfo *rel)
 
 
 /*
- * is_dummy_rel --- has relation been proven empty?
- */
-static bool
-is_dummy_rel(RelOptInfo *rel)
-{
-       return IS_DUMMY_REL(rel);
-}
-
-/*
  * Mark a relation as proven empty.
  *
  * During GEQO planning, this can get invoked more than once on the same
@@ -985,7 +970,8 @@ mark_dummy_rel(RelOptInfo *rel)
        rel->partial_pathlist = NIL;
 
        /* Set up the dummy path */
-       add_path(rel, (Path *) create_append_path(NULL, rel, NIL, NIL, NULL,
+       add_path(rel, (Path *) create_append_path(NULL, rel, NIL, NIL,
+                                                                                         rel->lateral_relids,
                                                                                          0, false, NIL, -1));
 
        /* Set or update cheapest_total_path and related fields */
@@ -1066,6 +1052,8 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
                                           RelOptInfo *joinrel, SpecialJoinInfo *parent_sjinfo,
                                           List *parent_restrictlist)
 {
+       bool            rel1_is_simple = IS_SIMPLE_REL(rel1);
+       bool            rel2_is_simple = IS_SIMPLE_REL(rel2);
        int                     nparts;
        int                     cnt_parts;
 
@@ -1123,6 +1111,10 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
        {
                RelOptInfo *child_rel1 = rel1->part_rels[cnt_parts];
                RelOptInfo *child_rel2 = rel2->part_rels[cnt_parts];
+               bool            rel1_empty = (child_rel1 == NULL ||
+                                                                 IS_DUMMY_REL(child_rel1));
+               bool            rel2_empty = (child_rel2 == NULL ||
+                                                                 IS_DUMMY_REL(child_rel2));
                SpecialJoinInfo *child_sjinfo;
                List       *child_restrictlist;
                RelOptInfo *child_joinrel;
@@ -1130,6 +1122,72 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
                AppendRelInfo **appinfos;
                int                     nappinfos;
 
+               /*
+                * Check for cases where we can prove that this segment of the join
+                * returns no rows, due to one or both inputs being empty (including
+                * inputs that have been pruned away entirely).  If so just ignore it.
+                * These rules are equivalent to populate_joinrel_with_paths's rules
+                * for dummy input relations.
+                */
+               switch (parent_sjinfo->jointype)
+               {
+                       case JOIN_INNER:
+                       case JOIN_SEMI:
+                               if (rel1_empty || rel2_empty)
+                                       continue;       /* ignore this join segment */
+                               break;
+                       case JOIN_LEFT:
+                       case JOIN_ANTI:
+                               if (rel1_empty)
+                                       continue;       /* ignore this join segment */
+                               break;
+                       case JOIN_FULL:
+                               if (rel1_empty && rel2_empty)
+                                       continue;       /* ignore this join segment */
+                               break;
+                       default:
+                               /* other values not expected here */
+                               elog(ERROR, "unrecognized join type: %d",
+                                        (int) parent_sjinfo->jointype);
+                               break;
+               }
+
+               /*
+                * If a child has been pruned entirely then we can't generate paths
+                * for it, so we have to reject partitionwise joining unless we were
+                * able to eliminate this partition above.
+                */
+               if (child_rel1 == NULL || child_rel2 == NULL)
+               {
+                       /*
+                        * Mark the joinrel as unpartitioned so that later functions treat
+                        * it correctly.
+                        */
+                       joinrel->nparts = 0;
+                       return;
+               }
+
+               /*
+                * If a leaf relation has consider_partitionwise_join=false, it means
+                * that it's a dummy relation for which we skipped setting up tlist
+                * expressions and adding EC members in set_append_rel_size(), so
+                * again we have to fail here.
+                */
+               if (rel1_is_simple && !child_rel1->consider_partitionwise_join)
+               {
+                       Assert(child_rel1->reloptkind == RELOPT_OTHER_MEMBER_REL);
+                       Assert(IS_DUMMY_REL(child_rel1));
+                       joinrel->nparts = 0;
+                       return;
+               }
+               if (rel2_is_simple && !child_rel2->consider_partitionwise_join)
+               {
+                       Assert(child_rel2->reloptkind == RELOPT_OTHER_MEMBER_REL);
+                       Assert(IS_DUMMY_REL(child_rel2));
+                       joinrel->nparts = 0;
+                       return;
+               }
+
                /* We should never try to join two overlapping sets of rels. */
                Assert(!bms_overlap(child_rel1->relids, child_rel2->relids));
                child_joinrelids = bms_union(child_rel1->relids, child_rel2->relids);