public override void Visit(FunctionOp op, Node n)
        {
            VisitDefault(n);
            if (!PlanCompilerUtil.IsCollectionAggregateFunction(op, n))
            {
                return;
            }

            if (n.Children.Count > 1)
            {
                return;
            }

            GroupAggregateVarInfo referencedGroupAggregateVarInfo;
            Node templateNode;
            bool isUnnested;

            if (GroupAggregateVarComputationTranslator.TryTranslateOverGroupAggregateVar(
                    n.Child0, false, _command, _groupAggregateVarInfoManager, out referencedGroupAggregateVarInfo, out templateNode,
                    out isUnnested)
                &&
                (isUnnested || AggregatePushdownUtil.IsVarRefOverGivenVar(templateNode, referencedGroupAggregateVarInfo.GroupAggregateVar)))
            {
                referencedGroupAggregateVarInfo.CandidateAggregateNodes.Add(new KeyValuePair <Node, List <Node> >(n, new List <Node> {
                    templateNode
                }));
            }
        }
示例#2
0
        private Node VisitCollectionAggregateFunction(FunctionOp op, Node n)
        {
            TypeUsage type   = (TypeUsage)null;
            Node      child0 = n.Child0;

            if (OpType.SoftCast == child0.Op.OpType)
            {
                type   = TypeHelpers.GetEdmType <CollectionType>(child0.Op.Type).TypeUsage;
                child0 = child0.Child0;
                while (OpType.SoftCast == child0.Op.OpType)
                {
                    child0 = child0.Child0;
                }
            }
            Node        node1       = this.BuildUnnest(child0);
            Var         column      = (node1.Op as UnnestOp).Table.Columns[0];
            AggregateOp aggregateOp = this.m_command.CreateAggregateOp(op.Function, false);
            Node        node2       = this.m_command.CreateNode((Op)this.m_command.CreateVarRefOp(column));

            if (type != null)
            {
                node2 = this.m_command.CreateNode((Op)this.m_command.CreateSoftCastOp(type), node2);
            }
            Node   node3   = this.m_command.CreateNode((Op)aggregateOp, node2);
            VarVec varVec1 = this.m_command.CreateVarVec();
            Node   node4   = this.m_command.CreateNode((Op)this.m_command.CreateVarDefListOp());
            VarVec varVec2 = this.m_command.CreateVarVec();
            Var    computedVar;
            Node   varDefListNode = this.m_command.CreateVarDefListNode(node3, out computedVar);

            varVec2.Set(computedVar);
            Node node5 = this.m_command.CreateNode((Op)this.m_command.CreateGroupByOp(varVec1, varVec2), node1, node4, varDefListNode);

            return(this.AddSubqueryToParentRelOp(computedVar, node5));
        }
示例#3
0
 internal static bool IsCollectionAggregateFunction(FunctionOp op, System.Data.Entity.Core.Query.InternalTrees.Node n)
 {
     if (n.Children.Count == 1 && TypeSemantics.IsCollectionType(n.Child0.Op.Type))
     {
         return(TypeSemantics.IsAggregateFunction(op.Function));
     }
     return(false);
 }
示例#4
0
        private Node VisitCollectionFunction(FunctionOp op, Node n)
        {
            System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(TypeSemantics.IsCollectionType(op.Type), "non-TVF function?");
            Node node1 = this.BuildUnnest(n);
            Node node2 = this.m_command.CreateNode((Op)this.m_command.CreatePhysicalProjectOp((node1.Op as UnnestOp).Table.Columns[0]), node1);

            return(this.m_command.CreateNode((Op)this.m_command.CreateCollectOp(n.Op.Type), node2));
        }
示例#5
0
        public override Node Visit(FunctionOp op, Node n)
        {
            this.VisitScalarOpDefault((ScalarOp)op, n);
            Node node = !TypeSemantics.IsCollectionType(op.Type) ? (!PlanCompilerUtil.IsCollectionAggregateFunction(op, n) ? n : this.VisitCollectionAggregateFunction(op, n)) : this.VisitCollectionFunction(op, n);

            System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(node != null, "failure to construct a functionOp?");
            return(node);
        }
示例#6
0
 public override void Visit(FunctionOp op, Node n)
 {
     VisitScalarOpDefault(op, n);
     Assert(op.Function.Parameters.Count == n.Children.Count, "FunctionOp: Argument count ({0}) does not match parameter count ({1})", n.Children.Count, op.Function.Parameters.Count);
     for (int idx = 0; idx < n.Children.Count; idx++)
     {
         AssertEqualTypes(n.Children[idx].Op.Type, op.Function.Parameters[idx].TypeUsage);
     }
 }
示例#7
0
        /// <summary>
        /// Converts the reference to a TVF as following: Collect(PhysicalProject(Unnest(Func)))
        /// </summary>
        /// <param name="op">current function op</param>
        /// <param name="n">current function subtree</param>
        /// <returns>the new expression that corresponds to the TVF</returns>
        private Node VisitCollectionFunction(FunctionOp op, Node n)
        {
            PlanCompiler.Assert(TypeSemantics.IsCollectionType(op.Type), "non-TVF function?");

            Node              unnestNode  = BuildUnnest(n);
            UnnestOp          unnestOp    = unnestNode.Op as UnnestOp;
            PhysicalProjectOp projectOp   = m_command.CreatePhysicalProjectOp(unnestOp.Table.Columns[0]);
            Node              projectNode = m_command.CreateNode(projectOp, unnestNode);
            CollectOp         collectOp   = m_command.CreateCollectOp(n.Op.Type);
            Node              collectNode = m_command.CreateNode(collectOp, projectNode);

            return(collectNode);
        }
示例#8
0
        /// <summary>
        ///     Converts a collection aggregate function count(X), where X is a collection into
        ///     two parts. Part A is a groupby subquery that looks like
        ///     GroupBy(Unnest(X), empty, count(y))
        ///     where "empty" describes the fact that the groupby has no keys, and y is an
        ///     element var of the Unnest
        ///     Part 2 is a VarRef that refers to the aggregate var for count(y) described above.
        ///     Logically, we would replace the entire functionOp by element(GroupBy...). However,
        ///     since we also want to translate element() into single-row-subqueries, we do this
        ///     here as well.
        ///     The function itself is replaced by the VarRef, and the GroupBy is added to the list
        ///     of scalar subqueries for the current relOp node on the stack
        /// </summary>
        /// <param name="op"> the functionOp for the collection agg </param>
        /// <param name="n"> current subtree </param>
        /// <returns> the VarRef node that should replace the function </returns>
        private Node VisitCollectionAggregateFunction(FunctionOp op, Node n)
        {
            TypeUsage softCastType = null;
            var       argNode      = n.Child0;

            if (OpType.SoftCast
                == argNode.Op.OpType)
            {
                softCastType = TypeHelpers.GetEdmType <CollectionType>(argNode.Op.Type).TypeUsage;
                argNode      = argNode.Child0;

                while (OpType.SoftCast
                       == argNode.Op.OpType)
                {
                    argNode = argNode.Child0;
                }
            }

            var unnestNode      = BuildUnnest(argNode);
            var unnestOp        = unnestNode.Op as UnnestOp;
            var unnestOutputVar = unnestOp.Table.Columns[0];

            var aggregateOp      = m_command.CreateAggregateOp(op.Function, false);
            var unnestVarRefOp   = m_command.CreateVarRefOp(unnestOutputVar);
            var unnestVarRefNode = m_command.CreateNode(unnestVarRefOp);

            if (softCastType != null)
            {
                unnestVarRefNode = m_command.CreateNode(m_command.CreateSoftCastOp(softCastType), unnestVarRefNode);
            }
            var aggExprNode = m_command.CreateNode(aggregateOp, unnestVarRefNode);

            var keyVars           = m_command.CreateVarVec(); // empty keys
            var keyVarDefListNode = m_command.CreateNode(m_command.CreateVarDefListOp());

            var gbyOutputVars = m_command.CreateVarVec();
            Var aggVar;
            var aggVarDefListNode = m_command.CreateVarDefListNode(aggExprNode, out aggVar);

            gbyOutputVars.Set(aggVar);
            var gbyOp           = m_command.CreateGroupByOp(keyVars, gbyOutputVars);
            var gbySubqueryNode = m_command.CreateNode(gbyOp, unnestNode, keyVarDefListNode, aggVarDefListNode);

            // "Move" this subquery to my parent relop
            var ret = AddSubqueryToParentRelOp(aggVar, gbySubqueryNode);

            return(ret);
        }
        private void TryProcessCandidate(
            KeyValuePair <System.Data.Entity.Core.Query.InternalTrees.Node, System.Data.Entity.Core.Query.InternalTrees.Node> candidate,
            GroupAggregateVarInfo groupAggregateVarInfo)
        {
            System.Data.Entity.Core.Query.InternalTrees.Node         definingGroupNode = groupAggregateVarInfo.DefiningGroupNode;
            IList <System.Data.Entity.Core.Query.InternalTrees.Node> ancestors1;
            IList <System.Data.Entity.Core.Query.InternalTrees.Node> ancestors2;

            this.FindPathsToLeastCommonAncestor(candidate.Key, definingGroupNode, out ancestors1, out ancestors2);
            if (!AggregatePushdown.AreAllNodesSupportedForPropagation(ancestors2))
            {
                return;
            }
            GroupByIntoOp op1 = (GroupByIntoOp)definingGroupNode.Op;

            System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(op1.Inputs.Count == 1, "There should be one input var to GroupByInto at this stage");
            Var        first = op1.Inputs.First;
            FunctionOp op2   = (FunctionOp)candidate.Key.Op;

            System.Data.Entity.Core.Query.InternalTrees.Node subTree = OpCopier.Copy(this.m_command, candidate.Value);
            new VarRemapper(this.m_command, new Dictionary <Var, Var>(1)
            {
                {
                    groupAggregateVarInfo.GroupAggregateVar,
                    first
                }
            }).RemapSubtree(subTree);
            Var computedVar;

            System.Data.Entity.Core.Query.InternalTrees.Node varDefNode = this.m_command.CreateVarDefNode(this.m_command.CreateNode((Op)this.m_command.CreateAggregateOp(op2.Function, false), subTree), out computedVar);
            definingGroupNode.Child2.Children.Add(varDefNode);
            ((GroupByBaseOp)definingGroupNode.Op).Outputs.Set(computedVar);
            for (int index = 0; index < ancestors2.Count; ++index)
            {
                System.Data.Entity.Core.Query.InternalTrees.Node node = ancestors2[index];
                if (node.Op.OpType == OpType.Project)
                {
                    ((ProjectOp)node.Op).Outputs.Set(computedVar);
                }
            }
            candidate.Key.Op = (Op)this.m_command.CreateVarRefOp(computedVar);
            candidate.Key.Children.Clear();
        }
示例#10
0
        public override void Visit(FunctionOp op, System.Data.Entity.Core.Query.InternalTrees.Node n)
        {
            this.VisitDefault(n);
            if (!PlanCompilerUtil.IsCollectionAggregateFunction(op, n))
            {
                return;
            }
            System.Data.Entity.Core.Query.PlanCompiler.PlanCompiler.Assert(n.Children.Count == 1, "Aggregate Function must have one argument");
            System.Data.Entity.Core.Query.InternalTrees.Node child0 = n.Child0;
            GroupAggregateVarInfo groupAggregateVarInfo;

            System.Data.Entity.Core.Query.InternalTrees.Node templateNode;
            bool isUnnested;

            if (!GroupAggregateVarComputationTranslator.TryTranslateOverGroupAggregateVar(n.Child0, false, this._command, this._groupAggregateVarInfoManager, out groupAggregateVarInfo, out templateNode, out isUnnested) || !isUnnested && !AggregatePushdownUtil.IsVarRefOverGivenVar(templateNode, groupAggregateVarInfo.GroupAggregateVar))
            {
                return;
            }
            groupAggregateVarInfo.CandidateAggregateNodes.Add(new KeyValuePair <System.Data.Entity.Core.Query.InternalTrees.Node, System.Data.Entity.Core.Query.InternalTrees.Node>(n, templateNode));
        }
示例#11
0
        /// <summary>
        /// Pre-processing for a function. Does the default scalar op processing.
        /// If the function returns a collection (TVF), the method converts this expression into
        ///    Collect(PhysicalProject(Unnest(Func))).
        /// If the function is a collection aggregate, converts it into the corresponding group aggregate.
        /// </summary>
        /// <param name="op"></param>
        /// <param name="n"></param>
        /// <returns></returns>
        public override Node Visit(FunctionOp op, Node n)
        {
            VisitScalarOpDefault(op, n);
            Node newNode = null;

            // Is this a TVF?
            if (TypeSemantics.IsCollectionType(op.Type))
            {
                newNode = VisitCollectionFunction(op, n);
            }
            // Is this a collection-aggregate function?
            else if (PlanCompilerUtil.IsCollectionAggregateFunction(op, n))
            {
                newNode = VisitCollectionAggregateFunction(op, n);
            }
            else
            {
                newNode = n;
            }

            PlanCompiler.Assert(newNode != null, "failure to construct a functionOp?");
            return(newNode);
        }
示例#12
0
        public override void Visit(FunctionOp op, Node n)
        {
            VisitDefault(n);
            if (!PlanCompilerUtil.IsCollectionAggregateFunction(op, n))
            {
                return;
            }
            PlanCompiler.Assert(n.Children.Count == 1, "Aggregate Function must have one argument");

            var argumentNode = n.Child0;

            GroupAggregateVarInfo referencedGroupAggregateVarInfo;
            Node templateNode;
            bool isUnnested;

            if (GroupAggregateVarComputationTranslator.TryTranslateOverGroupAggregateVar(
                    n.Child0, false, _command, _groupAggregateVarInfoManager, out referencedGroupAggregateVarInfo, out templateNode,
                    out isUnnested)
                &&
                (isUnnested || AggregatePushdownUtil.IsVarRefOverGivenVar(templateNode, referencedGroupAggregateVarInfo.GroupAggregateVar)))
            {
                referencedGroupAggregateVarInfo.CandidateAggregateNodes.Add(new KeyValuePair <Node, Node>(n, templateNode));
            }
        }
示例#13
0
        private Node VisitCollectionFunction(FunctionOp op, Node n)
        {
            PlanCompiler.Assert(TypeSemantics.IsCollectionType(op.Type), "non-TVF function?");

            var unnestNode = BuildUnnest(n);
            var unnestOp = unnestNode.Op as UnnestOp;
            var projectOp = m_command.CreatePhysicalProjectOp(unnestOp.Table.Columns[0]);
            var projectNode = m_command.CreateNode(projectOp, unnestNode);
            var collectOp = m_command.CreateCollectOp(n.Op.Type);
            var collectNode = m_command.CreateNode(collectOp, projectNode);

            return collectNode;
        }
 public override void Visit(FunctionOp op, Node n)
 {
     VisitScalarOpDefault(op, n);
     Assert(
         op.Function.Parameters.Count == n.Children.Count, "FunctionOp: Argument count ({0}) does not match parameter count ({1})",
         n.Children.Count, op.Function.Parameters.Count);
     for (var idx = 0; idx < n.Children.Count; idx++)
     {
         AssertEqualTypes(n.Children[idx].Op.Type, op.Function.Parameters[idx].TypeUsage);
     }
 }
示例#15
0
        public override Node Visit(FunctionOp op, Node n)
        {
            if (op.Function.IsFunctionImport)
            {
                PlanCompiler.Assert(
                    op.Function.IsComposableAttribute, "Cannot process a non-composable function inside query tree composition.");

                FunctionImportMapping functionImportMapping = null;
                if (!m_command.MetadataWorkspace.TryGetFunctionImportMapping(op.Function, out functionImportMapping))
                {
                    throw new MetadataException(Strings.EntityClient_UnmappedFunctionImport(op.Function.FullName));
                }
                PlanCompiler.Assert(
                    functionImportMapping is FunctionImportMappingComposable, "Composable function import must have corresponding mapping.");
                var functionImportMappingComposable = (FunctionImportMappingComposable)functionImportMapping;

                // Visit children (function call arguments) before processing the function view.
                // Visiting argument trees before the view tree is required because we want to process them first
                // outside of the context of the view. For example if an argument tree contains a free-floating entity-type constructor
                // and the function mapping scopes the function results to a particular entity set, we don't want 
                // the free-floating constructor to be auto-scoped to this set. So we process the argument first, it will
                // scope the constructor to the null scope and which guarantees that this constructor will not be rescoped after the argument
                // tree is embedded into the function view inside the functionMapping.GetInternalTree(...) call.
                VisitChildren(n);

                // Get the mapping view of the function.
                var ret = functionImportMappingComposable.GetInternalTree(m_command, n.Children);

                // Push the entity type scope, if any, before processing the view.
                if (op.Function.EntitySet != null)
                {
                    m_entityTypeScopes.Push(op.Function.EntitySet);
                    AddEntitySetReference(op.Function.EntitySet);
                    PlanCompiler.Assert(
                        functionImportMappingComposable.TvfKeys != null && functionImportMappingComposable.TvfKeys.Length > 0,
                        "Function imports returning entities must have inferred keys.");
                    if (!m_tvfResultKeys.ContainsKey(functionImportMappingComposable.TargetFunction))
                    {
                        m_tvfResultKeys.Add(functionImportMappingComposable.TargetFunction, functionImportMappingComposable.TvfKeys);
                    }
                }

                // Rerun the processor over the resulting subtree.
                ret = VisitNode(ret);

                // Remove the entity type scope, if any.
                if (op.Function.EntitySet != null)
                {
                    var scope = m_entityTypeScopes.Pop();
                    PlanCompiler.Assert(scope == op.Function.EntitySet, "m_entityTypeScopes stack is broken");
                }

                return ret;
            }
            else
            {
                PlanCompiler.Assert(op.Function.EntitySet == null, "Entity type scope is not supported on functions that aren't mapped.");

                // If this is TVF or a collection aggregate, function NestPullUp and Normalization are needed.
                if (TypeSemantics.IsCollectionType(op.Type)
                    || PlanCompilerUtil.IsCollectionAggregateFunction(op, n))
                {
                    m_compilerState.MarkPhaseAsNeeded(PlanCompilerPhase.NestPullup);
                    m_compilerState.MarkPhaseAsNeeded(PlanCompilerPhase.Normalization);
                }
                return base.Visit(op, n);
            }
        }
示例#16
0
 /// <summary>
 ///     Is this function a collection aggregate function. It is, if
 ///     - it has exactly one child
 ///     - that child is a collection type
 ///     - and the function has been marked with the aggregate attribute
 /// </summary>
 /// <param name="op"> the function op </param>
 /// <param name="n"> the current subtree </param>
 /// <returns> true, if this was a collection aggregate function </returns>
 internal static bool IsCollectionAggregateFunction(FunctionOp op, Node n)
 {
     return((n.Children.Count == 1) &&
            TypeSemantics.IsCollectionType(n.Child0.Op.Type) &&
            TypeSemantics.IsAggregateFunction(op.Function));
 }
 /// <summary>
 /// Is this function a collection aggregate function. It is, if
 ///   - it has exactly one child
 ///   - that child is a collection type
 ///   - and the function has been marked with the aggregate attribute
 /// </summary>
 /// <param name="op">the function op</param>
 /// <param name="n">the current subtree</param>
 /// <returns>true, if this was a collection aggregate function</returns>
 internal static bool IsCollectionAggregateFunction(FunctionOp op, Node n)
 {
     return ((n.Children.Count == 1) &&
             TypeSemantics.IsCollectionType(n.Child0.Op.Type) &&
             TypeSemantics.IsAggregateFunction(op.Function));
 }
        public override void Visit(FunctionOp op, Node n)
        {
            VisitDefault(n);
            if (!PlanCompilerUtil.IsCollectionAggregateFunction(op, n))
            {
                return;
            }
            PlanCompiler.Assert(n.Children.Count == 1, "Aggregate Function must have one argument");

            var argumentNode = n.Child0;

            GroupAggregateVarInfo referencedGroupAggregateVarInfo;
            Node templateNode;
            bool isUnnested;
            if (GroupAggregateVarComputationTranslator.TryTranslateOverGroupAggregateVar(
                n.Child0, false, _command, _groupAggregateVarInfoManager, out referencedGroupAggregateVarInfo, out templateNode,
                out isUnnested)
                &&
                (isUnnested || AggregatePushdownUtil.IsVarRefOverGivenVar(templateNode, referencedGroupAggregateVarInfo.GroupAggregateVar)))
            {
                referencedGroupAggregateVarInfo.CandidateAggregateNodes.Add(new KeyValuePair<Node, Node>(n, templateNode));
            }
        }
示例#19
0
 /// <summary>
 /// Copies a FunctionOp
 /// </summary>
 /// <param name="op">The Op to Copy</param>
 /// <param name="n">The Node that references the Op</param>
 /// <returns>A copy of the original Node that references a copy of the original Op</returns>
 public override Node Visit(FunctionOp op, Node n)
 {
     return(CopyDefault(m_destCmd.CreateFunctionOp(op.Function), n));
 }
 /// <summary>
 ///     Visitor pattern method for FunctionOp
 /// </summary>
 /// <param name="op"> The FunctionOp being visited </param>
 /// <param name="n"> The Node that references the Op </param>
 public virtual void Visit(FunctionOp op, Node n)
 {
     VisitScalarOpDefault(op, n);
 }
示例#21
0
 // <summary>
 // Copies a FunctionOp
 // </summary>
 // <param name="op"> The Op to Copy </param>
 // <param name="n"> The Node that references the Op </param>
 // <returns> A copy of the original Node that references a copy of the original Op </returns>
 public override Node Visit(FunctionOp op, Node n)
 {
     return CopyDefault(m_destCmd.CreateFunctionOp(op.Function), n);
 }
示例#22
0
        /// <summary>
        ///     Converts a collection aggregate function count(X), where X is a collection into
        ///     two parts. Part A is a groupby subquery that looks like
        ///     GroupBy(Unnest(X), empty, count(y))
        ///     where "empty" describes the fact that the groupby has no keys, and y is an
        ///     element var of the Unnest
        ///     Part 2 is a VarRef that refers to the aggregate var for count(y) described above.
        ///     Logically, we would replace the entire functionOp by element(GroupBy...). However,
        ///     since we also want to translate element() into single-row-subqueries, we do this
        ///     here as well.
        ///     The function itself is replaced by the VarRef, and the GroupBy is added to the list
        ///     of scalar subqueries for the current relOp node on the stack
        /// </summary>
        /// <param name="op"> the functionOp for the collection agg </param>
        /// <param name="n"> current subtree </param>
        /// <returns> the VarRef node that should replace the function </returns>
        private Node VisitCollectionAggregateFunction(FunctionOp op, Node n)
        {
            TypeUsage softCastType = null;
            var argNode = n.Child0;
            if (OpType.SoftCast
                == argNode.Op.OpType)
            {
                softCastType = TypeHelpers.GetEdmType<CollectionType>(argNode.Op.Type).TypeUsage;
                argNode = argNode.Child0;

                while (OpType.SoftCast
                       == argNode.Op.OpType)
                {
                    argNode = argNode.Child0;
                }
            }

            var unnestNode = BuildUnnest(argNode);
            var unnestOp = unnestNode.Op as UnnestOp;
            var unnestOutputVar = unnestOp.Table.Columns[0];

            var aggregateOp = m_command.CreateAggregateOp(op.Function, false);
            var unnestVarRefOp = m_command.CreateVarRefOp(unnestOutputVar);
            var unnestVarRefNode = m_command.CreateNode(unnestVarRefOp);
            if (softCastType != null)
            {
                unnestVarRefNode = m_command.CreateNode(m_command.CreateSoftCastOp(softCastType), unnestVarRefNode);
            }
            var aggExprNode = m_command.CreateNode(aggregateOp, unnestVarRefNode);

            var keyVars = m_command.CreateVarVec(); // empty keys
            var keyVarDefListNode = m_command.CreateNode(m_command.CreateVarDefListOp());

            var gbyOutputVars = m_command.CreateVarVec();
            Var aggVar;
            var aggVarDefListNode = m_command.CreateVarDefListNode(aggExprNode, out aggVar);
            gbyOutputVars.Set(aggVar);
            var gbyOp = m_command.CreateGroupByOp(keyVars, gbyOutputVars);
            var gbySubqueryNode = m_command.CreateNode(gbyOp, unnestNode, keyVarDefListNode, aggVarDefListNode);

            // "Move" this subquery to my parent relop
            var ret = AddSubqueryToParentRelOp(aggVar, gbySubqueryNode);

            return ret;
        }
示例#23
0
        public override Node Visit(FunctionOp op, Node n)
        {
            VisitScalarOpDefault(op, n);
            Node newNode = null;

            // Is this a TVF?
            if (TypeSemantics.IsCollectionType(op.Type))
            {
                newNode = VisitCollectionFunction(op, n);
            }
            // Is this a collection-aggregate function?
            else if (PlanCompilerUtil.IsCollectionAggregateFunction(op, n))
            {
                newNode = VisitCollectionAggregateFunction(op, n);
            }
            else
            {
                newNode = n;
            }

            PlanCompiler.Assert(newNode != null, "failure to construct a functionOp?");
            return newNode;
        }
示例#24
0
        /// <summary>
        /// Try to push the given function aggregate candidate to the corresponding group into node.
        /// The candidate can be pushed if all ancestors of the group into node up to the least common
        /// ancestor between the group into node and the function aggregate have one of the following node op types:
        ///     Project
        ///     Filter
        ///     ConstraintSortOp
        /// </summary>
        /// <param name="command"></param>
        /// <param name="candidate"></param>
        /// <param name="groupAggregateVarInfo"></param>
        /// <param name="m_childToParent"></param>
        private void TryProcessCandidate(
            KeyValuePair <Node, Node> candidate,
            GroupAggregateVarInfo groupAggregateVarInfo)
        {
            IList <Node> functionAncestors;
            IList <Node> groupByAncestors;
            Node         definingGroupNode = groupAggregateVarInfo.DefiningGroupNode;

            FindPathsToLeastCommonAncestor(candidate.Key, definingGroupNode, out functionAncestors, out groupByAncestors);

            //Check whether all ancestors of the GroupByInto node are of type that we support propagating through
            if (!AreAllNodesSupportedForPropagation(groupByAncestors))
            {
                return;
            }

            //Add the function to the group by node
            GroupByIntoOp definingGroupOp = (GroupByIntoOp)definingGroupNode.Op;

            PlanCompiler.Assert(definingGroupOp.Inputs.Count == 1, "There should be one input var to GroupByInto at this stage");
            Var        inputVar   = definingGroupOp.Inputs.First;
            FunctionOp functionOp = (FunctionOp)candidate.Key.Op;

            //
            // Remap the template from referencing the groupAggregate var to reference the input to
            // the group by into
            //
            Node argumentNode = OpCopier.Copy(m_command, candidate.Value);
            Dictionary <Var, Var> dictionary = new Dictionary <Var, Var>(1);

            dictionary.Add(groupAggregateVarInfo.GroupAggregateVar, inputVar);
            VarRemapper remapper = new VarRemapper(m_command, dictionary);

            remapper.RemapSubtree(argumentNode);

            Node newFunctionDefiningNode = m_command.CreateNode(
                m_command.CreateAggregateOp(functionOp.Function, false),
                argumentNode);

            Var  newFunctionVar;
            Node varDefNode = m_command.CreateVarDefNode(newFunctionDefiningNode, out newFunctionVar);

            // Add the new aggregate to the list of aggregates
            definingGroupNode.Child2.Children.Add(varDefNode);
            GroupByIntoOp groupByOp = (GroupByIntoOp)definingGroupNode.Op;

            groupByOp.Outputs.Set(newFunctionVar);

            //Propagate the new var throught the ancestors of the GroupByInto
            for (int i = 0; i < groupByAncestors.Count; i++)
            {
                Node groupByAncestor = groupByAncestors[i];
                if (groupByAncestor.Op.OpType == OpType.Project)
                {
                    ProjectOp ancestorProjectOp = (ProjectOp)groupByAncestor.Op;
                    ancestorProjectOp.Outputs.Set(newFunctionVar);
                }
            }

            //Update the functionNode
            candidate.Key.Op = m_command.CreateVarRefOp(newFunctionVar);
            candidate.Key.Children.Clear();
        }