Пример #1
0
        // We assume plan is with normalized shape:
        //    LogicFilter
        //        LogicJoin
        //               ...
        // There shall be only 1 join filter on top.
        // Subqueries is not considered here.
        //
        internal static JoinGraph ExtractJoinGraph(LogicNode plan,
                                                   out LogicNode filterNodeParent, out int index, out LogicFilter filterNode)
        {
            // find the join filter
            var parents = new List <LogicNode>();
            var indexes = new List <int>();
            var filters = new List <LogicFilter>();

            plan.FindNodeTypeMatch <LogicFilter>(parents, indexes, filters);
            var joinfilters = filters.Where(x => x.child_() is LogicJoin).ToList();

            Debug.Assert(joinfilters.Count <= 1);
            if (joinfilters.Count == 1)
            {
                JoinGraph graph      = null;
                var       joinfilter = joinfilters[0];
                var       topjoin    = joinfilter.child_() as LogicJoin;

                // vertices are non-join nodes. We don't do any cross boundary optimization
                // (say pull aggregation up thus we have bigger join space etc), which is
                // the job of upper layer.
                //
                var vertices = new List <LogicNode>();
                topjoin.VisitEach(x =>
                {
                    if (!(x is LogicJoin))
                    {
                        vertices.Add(x as LogicNode);
                    }
                });

                graph            = new JoinGraph(vertices, joinfilters[0].filter_.FilterToAndList());
                index            = indexes[0];
                filterNodeParent = parents[0];
                filterNode       = joinfilter;
                Debug.Assert(filterNodeParent is null || filterNodeParent.children_[index] == filterNode);
                return(graph);
            }

            // there is no join or we can't handle this query
            filterNodeParent = null;
            index            = -1;
            filterNode       = null;
            return(null);
        }
Пример #2
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);
        }