public static void NullifyFilter(this LogicNode node) { node.filter_ = null; // we have to keep the LogicFilter in various cases for easier handling // and we leave the vacuum job to filter push down // if (node is LogicFilter) { node.filter_ = LiteralExpr.MakeLiteral("true", new BoolType()); } }
public static Expr ConstFolding(this Expr expr) { Debug.Assert(expr.bounded_); bool IsConstFn(Expr e) => !(e is LiteralExpr) && e.IsConst(); Expr EvalConstFn(Expr e) { e.TryEvalConst(out Value val); return(LiteralExpr.MakeLiteral(val, expr.type_)); } if (expr is LiteralExpr) { return(expr); } else { return(expr.SearchReplace <Expr>(IsConstFn, EvalConstFn)); } }
LogicNode FilterPushDown(LogicNode plan, bool pushJoinFilter) { // locate the all filters ingoring any within FromQuery as it will // be optimized by subquery optimization and this will cause double // predicate push down (e.g., a1>1 && a1>1) // var parents = new List <LogicNode>(); var indexes = new List <int>(); var filters = new List <LogicFilter>(); var cntFilter = plan.FindNodeTypeMatch(parents, indexes, filters, skipParentType: typeof(LogicFromQuery)); for (int i = 0; i < cntFilter; i++) { var parent = parents[i]; var filter = filters[i]; var index = indexes[i]; Debug.Assert(!(parent is LogicFromQuery)); if (filter?.filter_ != null && filter?.movable_ is true) { List <Expr> andlist = new List <Expr>(); var filterexpr = filter.filter_; // if it is a constant true filer, remove it. If a false filter, we leave // it there - shall we try hard to stop query early? Nope, it is no deserved // to poke around for this corner case. // var isConst = filterexpr.FilterIsConst(out bool trueOrFalse); if (isConst) { if (!trueOrFalse) { andlist.Add(LiteralExpr.MakeLiteral("false", new BoolType())); } else { Debug.Assert(andlist.Count == 0); } } else { // filter push down andlist = filterexpr.FilterToAndList(); andlist.RemoveAll(e => { var isConst = e.FilterIsConst(out bool trueOrFalse); if (isConst) { Debug.Assert(trueOrFalse); return(true); } return(pushdownFilter(plan, e, pushJoinFilter)); }); } // stich the new plan if (andlist.Count == 0) { if (parent is null) { // take it out from the tree plan = plan.child_(); } else { parent.children_[index] = filter.child_(); } } else { filter.filter_ = andlist.AndListToExpr(); } } } return(plan); }
// expands [NOT] EXISTS filter to mark join // // LogicNode_A // Filter: @1 AND|OR <others1> // <ExistSubqueryExpr> 1 // -> LogicNode_B // Filter: b.b1[0]=?a.a1[0] AND|OR <others2> // => // Filter // Filter: #marker AND|OR <others1> // MarkJoin // Filter: (b.b1[0]=a.a1[0]) AND|OR <others2> as #marker // LogicNode_A // LogicNode_B // // further convert DJoin to semi-join here is by decorrelate process // LogicNode existsToMarkJoin(LogicNode nodeA, ExistSubqueryExpr existExpr) { var nodeAIsOnMarkJoin = nodeA is LogicFilter && (nodeA.child_() is LogicMarkJoin || nodeA.child_() is LogicSingleJoin); // nodeB contains the join filter var nodeB = existExpr.query_.logicPlan_; var nodeBFilter = nodeB.filter_; nodeB.NullifyFilter(); // nullify nodeA's filter: the rest is push to top filter. However, // if nodeA is a Filter|MarkJoin, keep its mark filter. var markerFilter = new ExprRef(new MarkerExpr(), 0); var nodeAFilter = nodeA.filter_; if (nodeAIsOnMarkJoin) { nodeA.filter_ = markerFilter; } else { if (nodeAFilter != null) { // a1 > @1 and a2 > @2 and a3 > 2, scalarExpr = @1 // keeplist: a1 > @1 and a3 > 2 // andlist after removal: a2 > @2 // nodeAFilter = a1 > @1 and a3 > 2 // var andlist = nodeAFilter.FilterToAndList(); var keeplist = andlist.Where(x => x.VisitEachExists(e => e.Equals(existExpr))).ToList(); andlist.RemoveAll(x => x.VisitEachExists(e => e.Equals(existExpr))); if (andlist.Count == 0) { nodeA.NullifyFilter(); } else { nodeA.filter_ = andlist.AndListToExpr(); if (keeplist.Count > 0) { nodeAFilter = keeplist.AndListToExpr(); } else { nodeAFilter = markerFilter; } } } } // make a mark join LogicMarkJoin markjoin; if (existExpr.hasNot_) { markjoin = new LogicMarkAntiSemiJoin(nodeA, nodeB); } else { markjoin = new LogicMarkSemiJoin(nodeA, nodeB); } // make a filter on top of the mark join collecting all filters Expr topfilter; if (nodeAIsOnMarkJoin) { topfilter = nodeAFilter.SearchReplace(existExpr, LiteralExpr.MakeLiteral("true", new BoolType())); } else { topfilter = nodeAFilter.SearchReplace(existExpr, markerFilter); } nodeBFilter.DeParameter(nodeA.InclusiveTableRefs()); topfilter = topfilter.AddAndFilter(nodeBFilter); LogicFilter Filter = new LogicFilter(markjoin, topfilter); return(Filter); }
// D Xs (Filter(T)) => Filter(D Xs T) LogicNode djoinOnRightFilter(LogicSingleJoin singleJoinNode, ScalarSubqueryExpr scalarExpr) { var nodeLeft = singleJoinNode.l_(); var nodeSubquery = singleJoinNode.r_(); var nodeSubqueryFilter = nodeSubquery.filter_; Debug.Assert(scalarExpr.query_.selection_.Count == 1); var singleValueExpr = scalarExpr.query_.selection_[0]; nodeSubquery.NullifyFilter(); // nullify nodeA's filter: the rest is push to top filter. However, // if nodeA is a Filter|MarkJoin, keep its mark filter. var trueCondition = LiteralExpr.MakeLiteral("true", new BoolType()); var nodeLeftFilter = nodeLeft.filter_; if (nodeLeftFilter != null) { // a1 > @1 and a2 > @2 and a3 > 2, scalarExpr = @1 // keeplist: a1 > @1 and a3 > 2 // andlist after removal: a2 > @2 // nodeAFilter = a1 > @1 and a3 > 2 // var andlist = nodeLeftFilter.FilterToAndList(); var keeplist = andlist.Where(x => x.VisitEachExists(e => e.Equals(scalarExpr))).ToList(); andlist.RemoveAll(x => x.VisitEachExists(e => e.Equals(scalarExpr))); if (andlist.Count == 0) { nodeLeft.NullifyFilter(); } else { nodeLeft.filter_ = andlist.AndListToExpr(); if (keeplist.Count > 0) { nodeLeftFilter = keeplist.AndListToExpr(); } else { nodeLeftFilter = trueCondition; } } } // make a non-movable filter on top of the single join to replace a1 > @1 LogicFilter nonMovableFilter = null; if (nodeLeftFilter != null) { // a1 > @1 => a1 > c1 var decExpr = nodeLeftFilter.SearchReplace(scalarExpr, singleValueExpr); nonMovableFilter = new LogicFilter(singleJoinNode, decExpr); nonMovableFilter.movable_ = false; } // b1 = ?outsideRef => b1 = outsideRef nodeSubqueryFilter.DeParameter(nodeLeft.InclusiveTableRefs()); // join filter within sbuquery Expr pullupFilter = nodeSubqueryFilter; if (nodeLeft.filter_ != null && !nodeLeft.filter_.HasSubQuery()) { pullupFilter = pullupFilter.AddAndFilter(nodeLeft.filter_); nodeLeft.NullifyFilter(); } LogicFilter Filter = new LogicFilter(nonMovableFilter != null ? (LogicNode)nonMovableFilter : singleJoinNode, pullupFilter); return(Filter); }