/// <summary>
        ///     Try to produce an equivalent tree to the input subtree, over a single group aggregate variable.
        ///     Such translation can only be produced if all external references of the input subtree are to a
        ///     single group aggregate var, or to vars that are can be translated over that single group
        ///     aggregate var
        /// </summary>
        /// <param name="subtree"> The input subtree </param>
        /// <param name="isVarDefinition"> </param>
        /// <param name="command"> </param>
        /// <param name="groupAggregateVarInfoManager"> </param>
        /// <param name="groupAggregateVarInfo"> The groupAggregateVarInfo over which the input subtree can be translated </param>
        /// <param name="templateNode"> A tree that is equvalent to the input tree, but over the group aggregate variable represented by the groupAggregetVarInfo </param>
        /// <param name="isUnnested"> </param>
        /// <returns> True, if the translation can be done, false otherwise </returns>
        public static bool TryTranslateOverGroupAggregateVar(
            Node subtree,
            bool isVarDefinition,
            Command command,
            GroupAggregateVarInfoManager groupAggregateVarInfoManager,
            out GroupAggregateVarInfo groupAggregateVarInfo,
            out Node templateNode,
            out bool isUnnested)
        {
            var handler = new GroupAggregateVarComputationTranslator(command, groupAggregateVarInfoManager);

            var inputNode = subtree;
            SoftCastOp softCastOp = null;
            bool isCollect;
            if (inputNode.Op.OpType
                == OpType.SoftCast)
            {
                softCastOp = (SoftCastOp)inputNode.Op;
                inputNode = inputNode.Child0;
            }

            if (inputNode.Op.OpType
                == OpType.Collect)
            {
                templateNode = handler.VisitCollect(inputNode);
                isCollect = true;
            }
            else
            {
                templateNode = handler.VisitNode(inputNode);
                isCollect = false;
            }

            groupAggregateVarInfo = handler._targetGroupAggregateVarInfo;
            isUnnested = handler._isUnnested;

            if (handler._targetGroupAggregateVarInfo == null
                || templateNode == null)
            {
                return false;
            }
            if (softCastOp != null)
            {
                SoftCastOp newSoftCastOp;
                // 
                // The type needs to be fixed only if the unnesting happened during this translation.
                // That can be recognized by these two cases: 
                //      1) if the input node was a collect, or 
                //      2) if the input did not represent a var definition, but a function aggregate argument and 
                //              the template is VarRef of a group aggregate var.
                //
                if (isCollect
                    ||
                    !isVarDefinition
                    && AggregatePushdownUtil.IsVarRefOverGivenVar(templateNode, handler._targetGroupAggregateVarInfo.GroupAggregateVar))
                {
                    newSoftCastOp = command.CreateSoftCastOp(TypeHelpers.GetEdmType<CollectionType>(softCastOp.Type).TypeUsage);
                }
                else
                {
                    newSoftCastOp = softCastOp;
                }
                templateNode = command.CreateNode(newSoftCastOp, templateNode);
            }
            return true;
        }
Exemplo n.º 2
0
 // <summary>
 // Copies a SoftCastOp
 // </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(SoftCastOp op, Node n)
 {
     return(CopyDefault(m_destCmd.CreateSoftCastOp(op.Type), n));
 }
        internal Node GetInternalTree(Command targetIqtCommand, IList<Node> targetIqtArguments)
        {
            if (m_internalTreeNode == null)
            {
                var viewGenErrors = new List<EdmSchemaError>();
                DiscriminatorMap discriminatorMap;
                var tree = GenerateFunctionView(out discriminatorMap);
                if (viewGenErrors.Count > 0)
                {
                    throw new MappingException(Helper.CombineErrorMessage(viewGenErrors));
                }
                Debug.Assert(tree != null, "tree != null");

                // Convert this into an ITree first
                var itree = ITreeGenerator.Generate(tree, discriminatorMap);
                var rootProject = itree.Root; // PhysicalProject(RelInput)
                PlanCompiler.Assert(
                    rootProject.Op.OpType == OpType.PhysicalProject,
                    "Expected a physical projectOp at the root of the tree - found " + rootProject.Op.OpType);
                var rootProjectOp = (PhysicalProjectOp)rootProject.Op;
                Debug.Assert(rootProjectOp.Outputs.Count == 1, "rootProjectOp.Outputs.Count == 1");
                var rootInput = rootProject.Child0; // the RelInput in PhysicalProject(RelInput)

                // #554756: VarVec enumerators are not cached on the shared Command instance.
                itree.DisableVarVecEnumCaching();

                // Function import returns a collection, so convert it to a scalar by wrapping into CollectOp.
                var relNode = rootInput;
                var relVar = rootProjectOp.Outputs[0];
                // ProjectOp does not implement Type property, so get the type from the column map.
                var functionViewType = rootProjectOp.ColumnMap.Type;
                if (!Command.EqualTypes(functionViewType, FunctionImport.ReturnParameter.TypeUsage))
                {
                    Debug.Assert(
                        TypeSemantics.IsPromotableTo(functionViewType, FunctionImport.ReturnParameter.TypeUsage),
                        "Mapping expression result type must be promotable to the c-space function return type.");

                    // Build "relNode = Project(relNode, SoftCast(relVar))"
                    var expectedCollectionType = (CollectionType)FunctionImport.ReturnParameter.TypeUsage.EdmType;
                    var expectedElementType = expectedCollectionType.TypeUsage;

                    var varRefNode = itree.CreateNode(itree.CreateVarRefOp(relVar));
                    var castNode = itree.CreateNode(itree.CreateSoftCastOp(expectedElementType), varRefNode);
                    var varDefListNode = itree.CreateVarDefListNode(castNode, out relVar);

                    var projectOp = itree.CreateProjectOp(relVar);
                    relNode = itree.CreateNode(projectOp, relNode, varDefListNode);
                }

                // Build "Collect(PhysicalProject(relNode))
                m_internalTreeNode = itree.BuildCollect(relNode, relVar);
            }
            Debug.Assert(m_internalTreeNode != null, "m_internalTreeNode != null");

            // Prepare argument replacement dictionary
            Debug.Assert(m_commandParameters.Length == targetIqtArguments.Count, "m_commandParameters.Length == targetIqtArguments.Count");
            var viewArguments = new Dictionary<string, Node>(m_commandParameters.Length);
            for (var i = 0; i < m_commandParameters.Length; ++i)
            {
                var commandParam = m_commandParameters[i];
                var argumentNode = targetIqtArguments[i];

                // If function import parameter is of enum type, the argument value for it will be of enum type. We however have 
                // converted enum types to underlying types for m_commandParameters. So we now need to softcast the argument 
                // expression to the underlying type as well.
                if (TypeSemantics.IsEnumerationType(argumentNode.Op.Type))
                {
                    argumentNode = targetIqtCommand.CreateNode(
                        targetIqtCommand.CreateSoftCastOp(TypeHelpers.CreateEnumUnderlyingTypeUsage(argumentNode.Op.Type)),
                        argumentNode);
                }

                Debug.Assert(
                    TypeSemantics.IsPromotableTo(argumentNode.Op.Type, commandParam.ResultType),
                    "Argument type must be promotable to parameter type.");

                viewArguments.Add(commandParam.ParameterName, argumentNode);
            }

            return FunctionViewOpCopier.Copy(targetIqtCommand, m_internalTreeNode, viewArguments);
        }