public override CGroupMember Apply(CGroupMember expr) { LogicJoin a_bc = expr.logic_ as LogicJoin; LogicNode a = (a_bc.l_() as LogicMemoRef).Deref <LogicNode>(); LogicJoin bc = (a_bc.r_() as LogicMemoRef).Deref <LogicJoin>(); Expr bcfilter = bc.filter_; var ab = new LogicJoin(a_bc.l_(), bc.l_()); var c = bc.r_(); var ab_c = new LogicJoin(ab, c); Debug.Assert(!a.LeftReferencesRight(bc)); if (ab.LeftReferencesRight(c)) { return(expr); } // pull up all join filters and re-push them back Expr allfilters = bcfilter; if (a_bc.filter_ != null) { allfilters = allfilters.AddAndFilter(a_bc.filter_); } if (allfilters != null) { var andlist = allfilters.FilterToAndList(); andlist.RemoveAll(e => ab_c.PushJoinFilter(e)); if (andlist.Count > 0) { ab_c.filter_ = andlist.AndListToExpr(); } } // Ideally if there is no cross join in the given plan but cross join // in the new plan, we shall return the original plan. However, stop // exploration now will prevent generating other promising plans. So // we have to return the new plan. // if (expr.QueryOption().optimize_.memo_disable_crossjoin_) { if (a_bc.filter_ != null && bcfilter != null) { if (ab_c.filter_ is null || ab.filter_ is null) { return(expr); } } } return(new CGroupMember(ab_c, expr.group_)); }