Beispiel #1
0
 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());
     }
 }
Beispiel #2
0
        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));
            }
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        // 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);
        }
Beispiel #5
0
        // 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);
        }