예제 #1
0
파일: RulesTrans.cs 프로젝트: bigwa/qpmodel
        // Extract filter matching ABC's tablerefs
        // ABC=[a,b]
        //  a.i=b.i AND a.j=b.j AND a.k+b.k=c.k => a.i=b.i AND a.j=b.j
        // ABC=[a,b,c]
        //   a.i=b.i AND a.j=b.j AND a.k+b.k=c.k => a.k+b.k=c.k
        Expr exactFilter(Expr fullfilter, List <LogicNode> ABC)
        {
            Expr ret = null;

            if (fullfilter is null)
            {
                return(null);
            }

            List <TableRef> ABCtabrefs = new List <TableRef>();

            foreach (var m in ABC)
            {
                ABCtabrefs.AddRange(m.InclusiveTableRefs());
            }

            var andlist = fullfilter.FilterToAndList();

            foreach (var v in andlist)
            {
                var predicate     = v as BinExpr;
                var predicateRefs = predicate.tableRefs_;
                if (ABCtabrefs.ListAEqualsB(predicateRefs))
                {
                    ret = ret.AddAndFilter(predicate);
                }
            }

            return(ret);
        }
예제 #2
0
파일: RulesTrans.cs 프로젝트: bigwa/qpmodel
        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_));
        }
예제 #3
0
        LogicNode inToMarkJoin(LogicNode planWithSubExpr, InSubqueryExpr inExpr)
        {
            LogicNode nodeA = planWithSubExpr;

            // nodeB contains the join filter
            var nodeB       = inExpr.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(nodeBFilter.tableRefs_, inExpr.subqueryid_), 0);
            var nodeAFilter  = extractCurINExprFromNodeAFilter(nodeA, inExpr, markerFilter);

            // consider SQL ...a1 in select b1 from...
            // a1 is outerExpr and b1 is selectExpr
            Expr outerExpr = inExpr.child_();

            Debug.Assert(inExpr.query_.selection_.Count == 1);
            Expr    selectExpr = inExpr.query_.selection_[0];
            BinExpr inToEqual  = BinExpr.MakeBooleanExpr(outerExpr, selectExpr, "=", true);

            // make a mark join
            LogicMarkJoin markjoin;

            if (inExpr.hasNot_)
            {
                markjoin = new LogicMarkAntiSemiJoin(nodeA, nodeB, inExpr.subqueryid_);
            }
            else
            {
                markjoin = new LogicMarkSemiJoin(nodeA, nodeB, inExpr.subqueryid_);
            }

            // make a filter on top of the mark join collecting all filters
            Expr topfilter = nodeAFilter.SearchAndReplace(inExpr, markerFilter);

            nodeBFilter.DeParameter(nodeA.InclusiveTableRefs());
            topfilter = topfilter.AddAndFilter(nodeBFilter);
            // TODO mutiple nested insubquery subquery
            // seperate the overlapping code with existsToSubquery to a new method
            // when the PR in #support nestted exist subquery pass
            LogicFilter Filter = new LogicFilter(markjoin, topfilter);

            Filter = new LogicFilter(Filter, inToEqual);
            return(Filter);
        }
예제 #4
0
        // from clause -
        //  pair each from item with cross join, their join conditions will be handled
        //  with where clause processing.
        //
        LogicNode transformFromClause()
        {
            LogicNode transformOneFrom(TableRef tab)
            {
                LogicNode from;

                switch (tab)
                {
                case BaseTableRef bref:
                    if (bref.Table().source_ == TableDef.TableSource.Table)
                    {
                        from = new LogicScanTable(bref);
                    }
                    else
                    {
                        from = new LogicScanStream(bref);
                    }
                    if (bref.tableSample_ != null)
                    {
                        from = new LogicSampleScan(from, bref.tableSample_);
                    }
                    break;

                case ExternalTableRef eref:
                    from = new LogicScanFile(eref);
                    break;

                case QueryRef qref:
                    var plan = qref.query_.CreatePlan();
                    if (qref is FromQueryRef && queryOpt_.optimize_.remove_from_)
                    {
                        from = plan;
                    }
                    else
                    {
                        string alias = null;
                        if (qref is CTEQueryRef cq)
                        {
                            alias = cq.alias_;
                        }
                        else if (qref is FromQueryRef fq)
                        {
                            alias = fq.alias_;
                        }
                        var key = new NamedQuery(qref.query_, alias);
                        from = new LogicFromQuery(qref, plan);
                        subQueries_.Add(key);

                        // if from CTE, then it could be duplicates
                        if (!fromQueries_.ContainsKey(key))
                        {
                            fromQueries_.Add(key, from as LogicFromQuery);
                        }
                    }
                    break;

                case JoinQueryRef jref:
                    // We will form join group on all tables and put a filter on top
                    // of the joins as a normalized form for later processing.
                    //
                    //      from a join b on a1=b1 or a3=b3 join c on a2=c2;
                    //   => from a , b, c where  (a1=b1 or a3=b3) and a2=c2;
                    //
                    LogicJoin subjoin    = new LogicJoin(null, null);
                    Expr      filterexpr = null;
                    for (int i = 0; i < jref.tables_.Count; i++)
                    {
                        LogicNode t        = transformOneFrom(jref.tables_[i]);
                        var       children = subjoin.children_;
                        if (children[0] is null)
                        {
                            children[0] = t;
                        }
                        else
                        {
                            if (children[1] is null)
                            {
                                children[1] = t;
                            }
                            else
                            {
                                subjoin = new LogicJoin(t, subjoin);
                            }
                            subjoin.type_ = jref.joinops_[i - 1];
                            filterexpr    = filterexpr.AddAndFilter(jref.constraints_[i - 1]);
                        }
                    }
                    Debug.Assert(filterexpr != null);
                    from = new LogicFilter(subjoin, filterexpr);
                    break;

                default:
                    throw new InvalidProgramException();
                }

                return(from);
            }

            LogicNode root;

            if (from_.Count >= 2)
            {
                var join     = new LogicJoin(null, null);
                var children = join.children_;
                from_.ForEach(x =>
                {
                    LogicNode from = transformOneFrom(x);
                    if (children[0] is null)
                    {
                        children[0] = from;
                    }
                    else
                    {
                        children[1] = (children[1] is null) ? from :
                                      new LogicJoin(from, children[1]);
                    }
                });
                root = join;
            }
            else if (from_.Count == 1)
            {
                root = transformOneFrom(from_[0]);
            }
            else
            {
                root = new LogicResult(selection_);
            }

            // distributed plan is required if any table is distributed, subquery
            // referenced tables are not counted here. So we may have the query
            // shape with main queyr not distributed but subquery is.
            //
            bool hasdtable      = false;
            bool onlyreplicated = true;

            from_.ForEach(x => checkifHasdtableAndifOnlyReplicated(x, ref hasdtable, ref onlyreplicated));
            if (hasdtable)
            {
                Debug.Assert(!distributed_);
                distributed_ = true;

                // distributed table query can also use memo
                // remote exchange is considered in memo optimization
                queryOpt_.optimize_.memo_use_remoteexchange_ = true;

                if (onlyreplicated)
                {
                    root = new LogicGather(root, new List <int> {
                        0
                    });
                }
                else
                {
                    root = new LogicGather(root);
                }
            }

            return(root);
        }
예제 #5
0
        // D Xs (Filter(T)) => Filter(D Xs T)
        LogicNode djoinOnRightFilter(LogicSingleJoin singleJoinNode, ScalarSubqueryExpr scalarExpr)
        {
            var nodeLeft           = singleJoinNode.lchild_();
            var nodeSubquery       = singleJoinNode.rchild_();
            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  = ConstExpr.MakeConstBool(true);
            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.SearchAndReplace(scalarExpr, singleValueExpr);
                nonMovableFilter = new LogicFilter(singleJoinNode, decExpr)
                {
                    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);
        }
예제 #6
0
파일: Plan.cs 프로젝트: bigwa/qpmodel
        // from clause -
        //  pair each from item with cross join, their join conditions will be handled
        //  with where clauss processing.
        //
        LogicNode transformFromClause()
        {
            LogicNode transformOneFrom(TableRef tab)
            {
                LogicNode from;

                switch (tab)
                {
                case BaseTableRef bref:
                    from = new LogicScanTable(bref);
                    break;

                case ExternalTableRef eref:
                    from = new LogicScanFile(eref);
                    break;

                case QueryRef qref:
                    var plan = qref.query_.CreatePlan();
                    if (qref is FromQueryRef && queryOpt_.optimize_.remove_from_)
                    {
                        from = plan;
                    }
                    else
                    {
                        string alias = null;
                        if (qref is CTEQueryRef cq)
                        {
                            alias = cq.alias_;
                        }
                        else if (qref is FromQueryRef fq)
                        {
                            alias = fq.alias_;
                        }
                        var key = new NamedQuery(qref.query_, alias);
                        from = new LogicFromQuery(qref, plan);
                        subQueries_.Add(key);

                        // if from CTE, then it could be duplicates
                        if (!fromQueries_.ContainsKey(key))
                        {
                            fromQueries_.Add(key, from as LogicFromQuery);
                        }
                    }
                    break;

                case JoinQueryRef jref:
                    // We will form join group on all tables and put a filter on top
                    // of the joins as a normalized form for later processing.
                    //
                    //      from a join b on a1=b1 or a3=b3 join c on a2=c2;
                    //   => from a , b, c where  (a1=b1 or a3=b3) and a2=c2;
                    //
                    LogicJoin subjoin    = new LogicJoin(null, null);
                    Expr      filterexpr = null;
                    for (int i = 0; i < jref.tables_.Count; i++)
                    {
                        LogicNode t        = transformOneFrom(jref.tables_[i]);
                        var       children = subjoin.children_;
                        if (children[0] is null)
                        {
                            children[0] = t;
                        }
                        else
                        {
                            if (children[1] is null)
                            {
                                children[1] = t;
                            }
                            else
                            {
                                subjoin = new LogicJoin(t, subjoin);
                            }
                            subjoin.type_ = jref.joinops_[i - 1];
                            filterexpr    = filterexpr.AddAndFilter(jref.constraints_[i - 1]);
                        }
                    }
                    Debug.Assert(filterexpr != null);
                    from = new LogicFilter(subjoin, filterexpr);
                    break;

                default:
                    throw new Exception();
                }

                return(from);
            }

            LogicNode root;

            if (from_.Count >= 2)
            {
                var join     = new LogicJoin(null, null);
                var children = join.children_;
                from_.ForEach(x =>
                {
                    LogicNode from = transformOneFrom(x);
                    if (children[0] is null)
                    {
                        children[0] = from;
                    }
                    else
                    {
                        children[1] = (children[1] is null) ? from :
                                      new LogicJoin(from, children[1]);
                    }
                });
                root = join;
            }
            else if (from_.Count == 1)
            {
                root = transformOneFrom(from_[0]);
            }
            else
            {
                root = new LogicResult(selection_);
            }

            return(root);
        }