Пример #1
0
 /// <summary>
 /// Get a list of "desired" properties for each operationKind (specified by the opKind
 /// parameter). The OpKinds we support are 
 /// 
 ///  * GetKeys
 ///    Applies only to entity and ref types - gets the key properties (more specifically
 ///      the flattened equivalents)
 ///  * GetIdentity
 ///    Applies only to entity and ref types - gets the entityset id property first, and then the
 ///      the Key properties
 ///  * All
 ///    Gets all properties of the flattened type
 /// 
 ///  * Equality
 ///    Scalar types - the entire instance
 ///    Entity - the identity properties
 ///    Ref - all properties (= identity properties)
 ///    Complex/Collection - Not supported
 ///    Record - recurse over each property
 /// 
 ///  * IsNull
 ///    Scalar types - entire instance
 ///    Entity - typeid property, if it exists; otherwise, the key properties
 ///    ComplexType - typeid property
 ///    Ref - all properties
 ///    Collection - not supported
 ///    Record - recurse over each property
 /// </summary>
 /// <param name="typeInfo">Type information for the current op</param>
 /// <param name="opKind">Current operation kind</param>
 /// <returns>List of desired properties</returns>
 private IEnumerable<md.EdmProperty> GetProperties(TypeInfo typeInfo, OperationKind opKind)
 {
     if (opKind == OperationKind.All)
     {
         foreach (md.EdmProperty p in typeInfo.GetAllProperties())
         {
             yield return p;
         }
     }
     else
     {
         foreach (PropertyRef p in GetPropertyRefs(typeInfo, opKind))
         {
             yield return typeInfo.GetNewProperty(p);
         }
     }
 }
Пример #2
0
        /// <summary>
        /// Project properties of <paramref name="unnestOpTableTypeInfo"/> that represents the flattened type of the <paramref name="unnestNode"/>.
        /// The <paramref name="unnestNode"/> contains a TVF call. 
        /// Return new node with ProjectOp and <paramref name="newVars"/> representing the projection outputs.
        /// </summary>
        private Node CreateTVFProjection(Node unnestNode, List<Var> unnestOpTableColumns, TypeInfo unnestOpTableTypeInfo, out List<Var> newVars)
        {
            md.RowType originalRowType = unnestOpTableTypeInfo.Type.EdmType as md.RowType;
            PlanCompiler.Assert(originalRowType != null, "Unexpected TVF return type (must be row): " + unnestOpTableTypeInfo.Type.ToString());

            List<Var> convertToFlattenedTypeVars = new List<Var>();
            List<Node> convertToFlattenedTypeVarDefs = new List<Node>();
            PropertyRef[] propRefs = unnestOpTableTypeInfo.PropertyRefList.ToArray();

            Dictionary<md.EdmProperty, PropertyRef> flattenedTypePropertyToPropertyRef = new Dictionary<md.EdmProperty, PropertyRef>();
            foreach (var propRef in propRefs)
            {
                flattenedTypePropertyToPropertyRef.Add(unnestOpTableTypeInfo.GetNewProperty(propRef), propRef);
            }

            foreach (var flattenedTypeProperty in unnestOpTableTypeInfo.FlattenedType.Properties)
            {
                var propRef = flattenedTypePropertyToPropertyRef[flattenedTypeProperty];

                Var var = null;
                SimplePropertyRef simplePropRef = propRef as SimplePropertyRef;
                if (simplePropRef != null)
                {
                    // Find the corresponding column in the TVF output and build a var ref to it.
                    int columnIndex = originalRowType.Members.IndexOf(simplePropRef.Property);
                    PlanCompiler.Assert(columnIndex >= 0, "Can't find a column in the TVF result type");
                    convertToFlattenedTypeVarDefs.Add(m_command.CreateVarDefNode(m_command.CreateNode(m_command.CreateVarRefOp(unnestOpTableColumns[columnIndex])), out var));
                }
                else
                {
                    NullSentinelPropertyRef nullSentinelPropRef = propRef as NullSentinelPropertyRef;
                    if (nullSentinelPropRef != null)
                    {
                        // Null sentinel does not exist in the TVF output, so build a new null sentinel expression.
                        convertToFlattenedTypeVarDefs.Add(m_command.CreateVarDefNode(CreateNullSentinelConstant(), out var));
                    }
                }
                PlanCompiler.Assert(var != null, "TVFs returning a collection of rows with non-primitive properties are not supported");

                convertToFlattenedTypeVars.Add(var);
            }

            // Make sure unnestTableColumnVar is mapped to the ProjectOp outputs.
            newVars = convertToFlattenedTypeVars;

            // Create Project(Unnest(Func()))
            return m_command.CreateNode(m_command.CreateProjectOp(m_command.CreateVarVec(convertToFlattenedTypeVars)),
                                        unnestNode,
                                        m_command.CreateNode(m_command.CreateVarDefListOp(), convertToFlattenedTypeVarDefs));
        }
Пример #3
0
        /// <summary>
        /// Flattens a CaseOp - Specifically, if the CaseOp returns a structuredtype,
        /// then the CaseOp is broken up so that we build up a "flat" record constructor
        /// for that structured type, with each argument to the record constructor being 
        /// a (scalar) CaseOp.  For example:
        /// 
        ///     Case when b1 then e1 else e2 end
        /// 
        /// gets translated into:
        /// 
        ///     RecordOp(case when b1 then e1.a else e2.a end,
        ///              case when b1 then e1.b else e2.b end,
        ///              ...)
        /// 
        /// The property extraction is optimized by producing only those properties 
        /// that have actually been requested.
        /// </summary>
        /// <param name="op">the CaseOp</param>
        /// <param name="n">Node corresponding to the CaseOp</param>
        /// <param name="typeInfo">Information about the type</param>
        /// <param name="desiredProperties">Set of properties desired</param>
        /// <returns></returns>
        private Node FlattenCaseOp(CaseOp op, Node n, TypeInfo typeInfo, PropertyRefList desiredProperties)
        {
            // Build up a type constructor - with only as many fields filled in 
            // as are desired. 
            List<md.EdmProperty> fieldTypes = new List<md.EdmProperty>();
            List<Node> fieldValues = new List<Node>();

            foreach (PropertyRef pref in typeInfo.PropertyRefList)
            {
                // Is this property desired later?
                if (!desiredProperties.Contains(pref))
                {
                    continue;
                }
                md.EdmProperty property = typeInfo.GetNewProperty(pref);

                // Build up an accessor for this property across each when/then clause
                List<Node> caseChildren = new List<Node>();
                for (int i = 0; i < n.Children.Count - 1; )
                {
                    Node whenNode = Copy(n.Children[i]);
                    caseChildren.Add(whenNode);
                    i++;

                    Node propNode = BuildAccessorWithNulls(n.Children[i], property);
                    caseChildren.Add(propNode);
                    i++;
                }
                Node elseNode = BuildAccessorWithNulls(n.Children[n.Children.Count - 1], property);
                caseChildren.Add(elseNode);

                Node caseNode = m_command.CreateNode(m_command.CreateCaseOp(md.Helper.GetModelTypeUsage(property)), caseChildren);

                fieldTypes.Add(property);
                fieldValues.Add(caseNode);
            }

            NewRecordOp newRec = m_command.CreateNewRecordOp(typeInfo.FlattenedTypeUsage, fieldTypes);
            return m_command.CreateNode(newRec, fieldValues);
        }