/// <summary>
        /// Gets the list of key properties for an entity
        /// </summary>
        /// <param name="entityType"></param>
        /// <returns></returns>
        private static PropertyRefList GetKeyProperties(md.EntityType entityType)
        {
            PropertyRefList desiredProperties = new PropertyRefList();

            foreach (md.EdmMember p in entityType.KeyMembers)
            {
                md.EdmProperty edmP = p as md.EdmProperty;
                PlanCompiler.Assert(edmP != null, "EntityType had non-EdmProperty key member?");
                SimplePropertyRef pRef = new SimplePropertyRef(edmP);
                desiredProperties.Add(pRef);
            }
            return(desiredProperties);
        }
        /// <summary>
        /// Creates a var info for var variables of primitive or enum type.
        /// </summary>
        /// <param name="v">Current variable of primitive or enum type.</param>
        /// <param name="newVar">The new variable replacing <paramref name="v"/>.</param>
        /// <returns><see cref="PrimitiveTypeVarInfo"/> for <paramref name="v"/>.</returns>
        internal VarInfo CreatePrimitiveTypeVarInfo(Var v, Var newVar)
        {
            System.Diagnostics.Debug.Assert(v != null, "v != null");
            System.Diagnostics.Debug.Assert(newVar != null, "newVar != null");

            PlanCompiler.Assert(md.TypeSemantics.IsScalarType(v.Type), "The current variable should be of primitive or enum type.");
            PlanCompiler.Assert(md.TypeSemantics.IsScalarType(newVar.Type), "The new variable should be of primitive or enum type.");

            VarInfo varInfo = new PrimitiveTypeVarInfo(newVar);

            m_map.Add(v, varInfo);
            return(varInfo);
        }
        /// <summary>
        /// ScanViewOp
        ///
        /// ask for all properties from the view definition
        /// that have currently been requested from the view itself
        /// </summary>
        /// <param name="op">current ScanViewOp</param>
        /// <param name="n">current node</param>
        public override void Visit(ScanViewOp op, Node n)
        {
            PlanCompiler.Assert(op.Table.Columns.Count == 1, "ScanViewOp with multiple columns?");
            Var             columnVar   = op.Table.Columns[0];
            PropertyRefList columnProps = GetPropertyRefList(columnVar);

            Var inputVar = NominalTypeEliminator.GetSingletonVar(n.Child0);

            PlanCompiler.Assert(inputVar != null, "cannot determine single Var from ScanViewOp's input");

            AddPropertyRefs(inputVar, columnProps.Clone());

            VisitChildren(n);
        }
Beispiel #4
0
        /// <summary>
        /// Find the TypeInfo entry for a type. For non-structured types, we always
        /// return null. For structured types, we return the entry in the typeInfoMap.
        /// If we don't find one, and the typeInfoMap has already been populated, then we
        /// assert
        /// </summary>
        /// <param name="type">the type to look up</param>
        /// <returns>the typeinfo for the type (null if we couldn't find one)</returns>
        internal TypeInfo GetTypeInfo(md.TypeUsage type)
        {
            if (!TypeUtils.IsStructuredType(type))
            {
                return(null);
            }
            TypeInfo typeInfo = null;

            if (!m_typeInfoMap.TryGetValue(type, out typeInfo))
            {
                PlanCompiler.Assert(!TypeUtils.IsStructuredType(type) || !m_typeInfoMapPopulated,
                                    "cannot find typeInfo for type " + type);
            }
            return(typeInfo);
        }
        /// <summary>
        /// GetEntityRefOp handling
        ///
        /// Ask for the "identity" properties from the input entity, and push that
        /// down to my child
        /// </summary>
        /// <param name="op"></param>
        /// <param name="n"></param>
        public override void Visit(GetEntityRefOp op, Node n)
        {
            ScalarOp childOp = n.Child0.Op as ScalarOp;

            PlanCompiler.Assert(childOp != null, "input to GetEntityRefOp is not a ScalarOp?");

            //
            md.EntityType entityType = TypeHelpers.GetEdmType <md.EntityType>(childOp.Type);

            PropertyRefList desiredProperties = GetIdentityProperties(entityType);

            AddPropertyRefs(n.Child0, desiredProperties);

            VisitNode(n.Child0);
        }
Beispiel #6
0
        /// <summary>
        /// Determines the offset for structured types in Flattened type. For instance, if the original type is of the form:
        ///
        ///     { int X, ComplexType Y }
        ///
        /// and the flattened type is of the form:
        ///
        ///     { int X, Y_ComplexType_Prop1, Y_ComplexType_Prop2 }
        ///
        /// GetNestedStructureOffset(Y) returns 1
        /// </summary>
        /// <param name="property">Complex property.</param>
        /// <returns>Offset.</returns>
        internal int GetNestedStructureOffset(PropertyRef property)
        {
            // m_propertyRefList contains every element of the flattened type
            for (int i = 0; i < m_propertyRefList.Count; i++)
            {
                NestedPropertyRef nestedPropertyRef = m_propertyRefList[i] as NestedPropertyRef;

                // match offset of the first element of the complex type property
                if (null != nestedPropertyRef && nestedPropertyRef.InnerProperty.Equals(property))
                {
                    return(i);
                }
            }
            PlanCompiler.Assert(false, "no complex structure " + property + " found in TypeInfo");
            // return something so that the compiler doesn't complain
            return(default(int));
        }
Beispiel #7
0
        /// <summary>
        /// Fills the StructuredTypeInfo instance from the itree provided.
        /// </summary>
        /// <param name="itree"></param>
        /// <param name="referencedTypes">referenced structured types</param>
        /// <param name="referencedEntitySets">referenced entitysets</param>
        /// <param name="freeFloatingEntityConstructorTypes">free-floating entityConstructor types</param>
        /// <param name="discriminatorMaps">discriminator information for entity sets mapped using TPH pattern</param>
        /// <param name="relPropertyHelper">helper for rel properties</param>
        private void Process(Command itree,
                             HashSet <md.TypeUsage> referencedTypes,
                             HashSet <md.EntitySet> referencedEntitySets,
                             HashSet <md.EntityType> freeFloatingEntityConstructorTypes,
                             Dictionary <md.EntitySetBase, DiscriminatorMapInfo> discriminatorMaps,
                             RelPropertyHelper relPropertyHelper)
        {
            PlanCompiler.Assert(null != itree, "null itree?");

            m_stringType        = itree.StringType;
            m_intType           = itree.IntegerType;
            m_relPropertyHelper = relPropertyHelper;

            ProcessEntitySets(referencedEntitySets, freeFloatingEntityConstructorTypes);
            ProcessDiscriminatorMaps(discriminatorMaps);
            ProcessTypes(referencedTypes);
        }
Beispiel #8
0
 /// <summary>
 /// Build out an EntityIdentity structure - for use by EntityColumnMap and RefColumnMap
 /// </summary>
 /// <param name="entityType">the entity type in question</param>
 /// <param name="entitySetIdColumnMap">column map for the entitysetid column</param>
 /// <param name="keyColumnMaps">column maps for the keys</param>
 /// <returns></returns>
 private EntityIdentity CreateEntityIdentity(md.EntityType entityType,
                                             SimpleColumnMap entitySetIdColumnMap,
                                             SimpleColumnMap[] keyColumnMaps)
 {
     //
     // If we have an entitysetid (and therefore, a column map for the entitysetid),
     // then use a discriminated entity identity; otherwise, we use a simpleentityidentity
     // instead
     //
     if (entitySetIdColumnMap != null)
     {
         return(new DiscriminatedEntityIdentity(entitySetIdColumnMap, m_typeInfo.EntitySetIdToEntitySetMap, keyColumnMaps));
     }
     else
     {
         md.EntitySet entitySet = m_typeInfo.GetEntitySet(entityType);
         PlanCompiler.Assert(entitySet != null, "Expected non-null entityset when no entitysetid is required. Entity type = " + entityType);
         return(new SimpleEntityIdentity(entitySet, keyColumnMaps));
     }
 }
        /// <summary>
        /// If the op is a collection aggregate function it checks whether its arguement can be translated over
        /// a single group aggregate var. If so, it is tracked as a candidate to be pushed into that
        /// group by into node.
        /// </summary>
        /// <param name="op"></param>
        /// <param name="n"></param>
        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");

            Node 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));
            }
        }
Beispiel #10
0
        /// <summary>
        /// Create a column map for a record type. Simply iterates through the
        /// list of fields, and produces a column map for each field
        /// </summary>
        /// <param name="typeInfo">Type information for the record type</param>
        /// <param name="name">column name</param>
        /// <returns></returns>
        private RecordColumnMap CreateRecordColumnMap(TypeInfo typeInfo, string name)
        {
            PlanCompiler.Assert(typeInfo.Type.EdmType is md.RowType, "not RowType");
            SimpleColumnMap nullSentinelColumnMap = null;

            if (typeInfo.HasNullSentinelProperty)
            {
                nullSentinelColumnMap = CreateSimpleColumnMap(md.Helper.GetModelTypeUsage(typeInfo.NullSentinelProperty), c_NullSentinelColumnName);
            }

            md.ReadOnlyMetadataCollection <md.EdmProperty> properties = TypeHelpers.GetProperties(typeInfo.Type);
            ColumnMap[] propertyColumnMapList = new ColumnMap[properties.Count];
            for (int i = 0; i < propertyColumnMapList.Length; ++i)
            {
                md.EdmMember property = properties[i];
                propertyColumnMapList[i] = CreateColumnMap(md.Helper.GetModelTypeUsage(property), property.Name);
            }

            RecordColumnMap result = new RecordColumnMap(typeInfo.Type, name, propertyColumnMapList, nullSentinelColumnMap);

            return(result);
        }
Beispiel #11
0
        /// <summary>
        /// Default processing for RelOps.
        /// - First, we mark the current node as its own ancestor (so that any
        ///   subqueries that we detect internally will be added to this node's list)
        /// - then, visit each child
        /// - finally, accumulate all nested subqueries.
        /// - if the current RelOp has only one input, then add the nested subqueries via
        ///   Outer apply nodes to this input.
        ///
        /// The interesting RelOps are
        ///   Project, Filter, GroupBy, Sort,
        /// Should we break this out into separate functions instead?
        /// </summary>
        /// <param name="op">Current RelOp</param>
        /// <param name="n">Node to process</param>
        /// <returns>Current subtree</returns>
        protected override Node VisitRelOpDefault(RelOp op, Node n)
        {
            VisitChildren(n); // visit all my children first

            // Then identify all the subqueries that have shown up as part of my node
            // Create Apply Nodes for each of these.
            List <Node> nestedSubqueries;

            if (m_nodeSubqueries.TryGetValue(n, out nestedSubqueries) && nestedSubqueries.Count > 0)
            {
                // Validate - this must only apply to the following nodes
                PlanCompiler.Assert(
                    n.Op.OpType == OpType.Project || n.Op.OpType == OpType.Filter ||
                    n.Op.OpType == OpType.GroupBy || n.Op.OpType == OpType.GroupByInto,
                    "VisitRelOpDefault: Unexpected op?" + n.Op.OpType);

                Node newInputNode = AugmentWithSubqueries(n.Child0, nestedSubqueries, true);
                // Now make this the new input child
                n.Child0 = newInputNode;
            }

            return(n);
        }
Beispiel #12
0
        /// <summary>
        /// Build up an equivalence map of primary keys and foreign keys (ie) for each
        /// foreign key column, identify the corresponding primary key property
        /// </summary>
        private void BuildKeyMap()
        {
            if (m_keyMap != null)
            {
                return;
            }

            m_keyMap = new Dictionary <string, string>();
            IEnumerator <md.EdmProperty> parentProps = m_constraint.FromProperties.GetEnumerator();
            IEnumerator <md.EdmProperty> childProps  = m_constraint.ToProperties.GetEnumerator();

            while (true)
            {
                bool parentOver = !parentProps.MoveNext();
                bool childOver  = !childProps.MoveNext();
                PlanCompiler.Assert(parentOver == childOver, "key count mismatch");
                if (parentOver)
                {
                    break;
                }
                m_keyMap[childProps.Current.Name] = parentProps.Current.Name;
            }
        }
Beispiel #13
0
        /// <summary>
        /// Get the list of "key" properties (in the flattened type)
        /// </summary>
        /// <returns>the key property equivalents in the flattened type</returns>
        internal IEnumerable <PropertyRef> GetKeyPropertyRefs()
        {
            md.EntityTypeBase entityType = null;
            md.RefType        refType    = null;
            if (TypeHelpers.TryGetEdmType <md.RefType>(m_type, out refType))
            {
                entityType = refType.ElementType;
            }
            else
            {
                entityType = TypeHelpers.GetEdmType <md.EntityTypeBase>(m_type);
            }

            // Walk through the list of keys of the entity type, and find their analogs in the
            // "flattened" type
            foreach (md.EdmMember p in entityType.KeyMembers)
            {
                // Eventually this could be RelationshipEndMember, but currently only properties are suppported as key members
                PlanCompiler.Assert(p is md.EdmProperty, "Non-EdmProperty key members are not supported");
                SimplePropertyRef spr = new SimplePropertyRef(p);
                yield return(spr);
            }
        }
Beispiel #14
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);
        }
Beispiel #15
0
        /// <summary>
        /// Creates a ProviderCommandInfo for the given node.
        /// This method should be called when the keys, foreign keys and sort keys are known ahead of time.
        /// Typically it is used when the original command is factored into multiple commands.
        /// </summary>
        /// <param name="command">The owning command, used for creating VarVecs, etc</param>
        /// <param name="node">The root of the sub-command for which a ProviderCommandInfo should be generated</param>
        /// <param name="children">A list of ProviderCommandInfos that were created for the child sub-commands.</param>
        /// <returns>The resulting ProviderCommandInfo</returns>
        internal static ProviderCommandInfo Create(
            Command command,
            Node node,
            List <ProviderCommandInfo> children)
        {
            PhysicalProjectOp projectOp = node.Op as PhysicalProjectOp;

            PlanCompiler.Assert(projectOp != null, "Expected root Op to be a physical Project");

            // build up the CQT
            DbCommandTree      ctree  = CTreeGenerator.Generate(command, node);
            DbQueryCommandTree cqtree = ctree as DbQueryCommandTree;

            PlanCompiler.Assert(cqtree != null, "null query command tree");

            // Get the rowtype for the result cqt
            md.CollectionType collType = TypeHelpers.GetEdmType <md.CollectionType>(cqtree.Query.ResultType);
            PlanCompiler.Assert(md.TypeSemantics.IsRowType(collType.TypeUsage), "command rowtype is not a record");

            // Build up a mapping from Vars to the corresponding output property/column
            Dictionary <Var, md.EdmProperty> outputVarMap = BuildOutputVarMap(projectOp, collType.TypeUsage);

            return(new ProviderCommandInfo(ctree, children));
        }
 /// <summary>
 /// ScanTableOp handler
 /// </summary>
 /// <param name="op"></param>
 /// <param name="n"></param>
 public override void Visit(ScanTableOp op, Node n)
 {
     PlanCompiler.Assert(!n.HasChild0, "scanTableOp with an input?");
 }
Beispiel #17
0
        /// <summary>
        /// Create a column map for an entitytype column.
        /// Currently, the key columns are not duplicated (ie) they point into the
        /// same locations as in the properties list.
        /// Note: we also don't handle keys that are properties of nested fields
        /// </summary>
        /// <param name="typeInfo">Type information for the type</param>
        /// <param name="name">column name</param>
        /// <param name="superTypeColumnMap">supertype information if any</param>
        /// <param name="discriminatorMap">Dictionary of typeid->column map information</param>
        /// <param name="allMaps">List of all column maps (including those without typeid)</param>
        /// <param name="handleRelProperties">should we handle rel-properties?</param>
        /// <returns></returns>
        private EntityColumnMap CreateEntityColumnMap(TypeInfo typeInfo, string name, EntityColumnMap superTypeColumnMap,
                                                      Dictionary <object, TypedColumnMap> discriminatorMap, List <TypedColumnMap> allMaps, bool handleRelProperties)
        {
            EntityColumnMap  columnMap             = null;
            List <ColumnMap> propertyColumnMapList = new List <ColumnMap>();

            // Copy over information from my supertype if it already exists
            if (superTypeColumnMap != null)
            {
                // get supertype properties
                foreach (ColumnMap c in superTypeColumnMap.Properties)
                {
                    propertyColumnMapList.Add(c);
                }
                // Now add on all of my "specific" properties
                foreach (md.EdmMember property in TypeHelpers.GetDeclaredStructuralMembers(typeInfo.Type))
                {
                    ColumnMap propertyColumnMap = CreateColumnMap(md.Helper.GetModelTypeUsage(property), property.Name);
                    propertyColumnMapList.Add(propertyColumnMap);
                }
                // create the entity column map w/ information from my supertype
                columnMap = new EntityColumnMap(typeInfo.Type, name, propertyColumnMapList.ToArray(), superTypeColumnMap.EntityIdentity);
            }
            else
            {
                SimpleColumnMap entitySetIdColumnMap = null;
                if (typeInfo.HasEntitySetIdProperty)
                {
                    entitySetIdColumnMap = CreateEntitySetIdColumnMap(typeInfo.EntitySetIdProperty);
                }

                // build up a list of key columns
                List <SimpleColumnMap> keyColumnMapList = new List <SimpleColumnMap>();
                // Create a dictionary to look up the key properties
                Dictionary <md.EdmProperty, ColumnMap> keyPropertyMap = new Dictionary <md.EdmProperty, ColumnMap>();

                foreach (md.EdmMember property in TypeHelpers.GetDeclaredStructuralMembers(typeInfo.Type))
                {
                    ColumnMap propertyColumnMap = CreateColumnMap(md.Helper.GetModelTypeUsage(property), property.Name);
                    propertyColumnMapList.Add(propertyColumnMap);
                    // add property to keymap, if this property is part of the key
                    if (md.TypeSemantics.IsPartOfKey(property))
                    {
                        md.EdmProperty edmProperty = property as md.EdmProperty;
                        PlanCompiler.Assert(edmProperty != null, "EntityType key member is not property?");
                        keyPropertyMap[edmProperty] = propertyColumnMap;
                    }
                }

                // Build up the key list if required
                foreach (md.EdmMember keyProperty in TypeHelpers.GetEdmType <md.EntityType>(typeInfo.Type).KeyMembers)
                {
                    md.EdmProperty edmKeyProperty = keyProperty as md.EdmProperty;
                    PlanCompiler.Assert(edmKeyProperty != null, "EntityType key member is not property?");
                    SimpleColumnMap keyColumnMap = keyPropertyMap[edmKeyProperty] as SimpleColumnMap;
                    PlanCompiler.Assert(keyColumnMap != null, "keyColumnMap is null");
                    keyColumnMapList.Add(keyColumnMap);
                }

                //
                // Create the entity identity.
                //
                EntityIdentity identity = CreateEntityIdentity((md.EntityType)typeInfo.Type.EdmType, entitySetIdColumnMap, keyColumnMapList.ToArray());

                // finally create the entity column map
                columnMap = new EntityColumnMap(typeInfo.Type, name, propertyColumnMapList.ToArray(), identity);
            }

            // if a dictionary is supplied, add myself to the dictionary (abstract types need not be added)
            if (discriminatorMap != null)
            {
                // where DiscriminatedNewInstanceOp is used, there will not be an explicit type id for an abstract type
                // or types that do not appear in the QueryView
                // (the mapping will not include such information)
                if (null != typeInfo.TypeId)
                {
                    discriminatorMap[typeInfo.TypeId] = columnMap;
                }
            }
            if (allMaps != null)
            {
                allMaps.Add(columnMap);
            }
            // Finally walk through my subtypes
            foreach (TypeInfo subTypeInfo in typeInfo.ImmediateSubTypes)
            {
                CreateEntityColumnMap(subTypeInfo, name, columnMap, discriminatorMap, allMaps, false);
            }

            //
            // Build up the list of rel property column maps
            //
            if (handleRelProperties)
            {
                BuildRelPropertyColumnMaps(typeInfo, true);
            }
            return(columnMap);
        }
 /// <summary>
 /// Create a predicate from a node tree
 /// </summary>
 /// <param name="command">current iqt command</param>
 /// <param name="andTree">the node tree</param>
 internal Predicate(Command command, Node andTree)
     : this(command)
 {
     PlanCompiler.Assert(andTree != null, "null node passed to Predicate() constructor");
     InitFromAndTree(andTree);
 }
Beispiel #19
0
        /// <summary>
        /// Comments from Murali:
        ///
        ///   There are several cases to consider here.
        ///
        ///   Case 0:
        ///     Let’s assume that K1 is the set of keys ({k1, k2, ..., kn}) for the
        ///     first input, and K2 ({l1, l2, …}) is the set of keys for the second
        ///     input.
        ///
        ///     The best case is when both K1 and K2 have the same cardinality (hopefully
        ///     greater than 0), and the keys are in the same locations (ie) the corresponding
        ///     positions in the select-list.  Even in this case, its not enough to take
        ///     the keys, and treat them as the keys of the union-all. What we’ll need to
        ///     do is to add a “branch” discriminator constant for each branch of the
        ///     union-all, and use this as the prefix for the keys.
        ///
        ///     For example, if I had:
        ///
        ///         Select c1, c2, c3... from ...
        ///         Union all
        ///         Select d1, d2, d3... from ...
        ///
        ///     And for the sake of argument, lets say that {c2} and {d2} are the keys of
        ///     each of the branches. What you’ll need to do is to translate this into
        ///
        ///         Select 0 as bd, c1, c2, c3... from ...
        ///         Union all
        ///         Select 1 as bd, d1, d2, d3... from ...
        ///
        ///     And then treat {bd, c2/d2} as the key of the union-all
        ///
        ///   Case 1:  (actually, a subcase of Case 0):
        ///     Now, if the keys don’t align, then we can simply take the union of the
        ///     corresponding positions, and make them all the keys (we would still need
        ///     the branch discriminator)
        ///
        ///   Case 2:
        ///     Finally, if you need to “pull” up keys from either of the branches, it is
        ///     possible that the branches get out of whack.  We will then need to push up
        ///     the keys (with nulls if the other branch doesn’t have the corresponding key)
        ///     into the union-all. (We still need the branch discriminator).
        ///
        /// Now, unfortunately, whenever we've got polymorphic entity types, we'll end up
        /// in case 2 way more often than we really want to, because when we're pulling up
        /// keys, we don't want to reason about a caseop (which is how polymorphic types
        /// wrap their key value).
        ///
        /// To simplify all of this, we:
        ///
        /// (1) Pulling up the keys for both branches of the UnionAll, and computing which
        ///     keys are in the outputs and which are missing from the outputs.
        ///
        /// (2) Accumulate all the missing keys.
        ///
        /// (3) Slap a projectOp around each branch, adding a branch discriminator
        ///     var and all the missing keys.  When keys are missing from a different
        ///     branch, we'll construct null ops for them on the other branches.  If
        ///     a branch already has a branch descriminator, we'll re-use it instead
        ///     of constructing a new one.  (Of course, if there aren't any keys to
        ///     add and it's already including the branch discriminator we won't
        ///     need the projectOp)
        ///
        /// </summary>
        /// <param name="op">the UnionAllOp</param>
        /// <param name="n">current subtree</param>
        public override void Visit(UnionAllOp op, Node n)
        {
#if DEBUG
            string input = Dump.ToXml(m_command, n);
#endif //DEBUG

            // Ensure we have keys pulled up on each branch of the union all.
            VisitChildren(n);

            // Create the setOp var we'll use to output the branch discriminator value; if
            // any of the branches are already surfacing a branchDiscriminator var to the
            // output of this operation then we won't need to use this but we construct it
            // early to simplify logic.
            Var outputBranchDiscriminatorVar = m_command.CreateSetOpVar(m_command.IntegerType);

            // Now ensure that we're outputting the key vars from this op as well.
            VarList  allKeyVarsMissingFromOutput = Command.CreateVarList();
            VarVec[] keyVarsMissingFromOutput    = new VarVec[n.Children.Count];

            for (int i = 0; i < n.Children.Count; i++)
            {
                Node             branchNode     = n.Children[i];
                ExtendedNodeInfo branchNodeInfo = m_command.GetExtendedNodeInfo(branchNode);

                // Identify keys that aren't in the output list of this operation. We
                // determine these by remapping the keys that are found through the node's
                // VarMap, which gives us the keys in the same "varspace" as the outputs
                // of the UnionAll, then we subtract out the outputs of this UnionAll op,
                // leaving things that are not in the output vars.  Of course, if they're
                // not in the output vars, then we didn't really remap.
                VarVec existingKeyVars = branchNodeInfo.Keys.KeyVars.Remap(op.VarMap[i]);

                keyVarsMissingFromOutput[i] = m_command.CreateVarVec(existingKeyVars);
                keyVarsMissingFromOutput[i].Minus(op.Outputs);

                // Special Case: if the branch is a UnionAll, it will already have it's
                // branch discriminator var added in the keys; we don't want to add that
                // a second time...
                if (OpType.UnionAll == branchNode.Op.OpType)
                {
                    UnionAllOp branchUnionAllOp = (UnionAllOp)branchNode.Op;

                    keyVarsMissingFromOutput[i].Clear(branchUnionAllOp.BranchDiscriminator);
                }

                allKeyVarsMissingFromOutput.AddRange(keyVarsMissingFromOutput[i]);
            }

            // Construct the setOp vars we're going to map to output.
            VarList allKeyVarsToAddToOutput = Command.CreateVarList();

            foreach (Var v in allKeyVarsMissingFromOutput)
            {
                Var newKeyVar = m_command.CreateSetOpVar(v.Type);
                allKeyVarsToAddToOutput.Add(newKeyVar);
            }

            // Now that we've identified all the keys we need to add, ensure that each branch
            // has both the branch discrimination var and the all the keys in them, even when
            // the keys are just going to null (which we construct, as needed)
            for (int i = 0; i < n.Children.Count; i++)
            {
                Node             branchNode     = n.Children[i];
                ExtendedNodeInfo branchNodeInfo = m_command.GetExtendedNodeInfo(branchNode);

                VarVec      branchOutputVars = m_command.CreateVarVec();
                List <Node> varDefNodes      = new List <Node>();

                // If the branch is a UnionAllOp that has a branch discriminator var then we can
                // use it, otherwise we'll construct a new integer constant with the next value
                // of the branch discriminator value from the command object.
                Var branchDiscriminatorVar;

                if (OpType.UnionAll == branchNode.Op.OpType && null != ((UnionAllOp)branchNode.Op).BranchDiscriminator)
                {
                    branchDiscriminatorVar = ((UnionAllOp)branchNode.Op).BranchDiscriminator;

                    // If the branch has a discriminator var, but we haven't added it to the
                    // varmap yet, then we do so now.
                    if (!op.VarMap[i].ContainsValue(branchDiscriminatorVar))
                    {
                        op.VarMap[i].Add(outputBranchDiscriminatorVar, branchDiscriminatorVar);
                        // We don't need to add this to the branch outputs, because it's already there,
                        // otherwise we wouln't have gotten here, yes?
                    }
                    else
                    {
                        // In this case, we're already outputting the branch discriminator var -- we'll
                        // just use it for both sides.  We should never have a case where only one of the
                        // two branches are outputting the branch discriminator var, because it can only
                        // be constructed in this method, and we wouldn't need it for any other purpose.
                        PlanCompiler.Assert(0 == i, "right branch has a discriminator var that the left branch doesn't have?");
                        VarMap reverseVarMap = op.VarMap[i].GetReverseMap();
                        outputBranchDiscriminatorVar = reverseVarMap[branchDiscriminatorVar];
                    }
                }
                else
                {
                    // Not a unionAll -- we have to add a BranchDiscriminator var.
                    varDefNodes.Add(
                        m_command.CreateVarDefNode(
                            m_command.CreateNode(
                                m_command.CreateConstantOp(m_command.IntegerType, m_command.NextBranchDiscriminatorValue)), out branchDiscriminatorVar));

                    branchOutputVars.Set(branchDiscriminatorVar);
                    op.VarMap[i].Add(outputBranchDiscriminatorVar, branchDiscriminatorVar);
                }

                // Append all the missing keys to the branch outputs.  If the missing key
                // is not from this branch then create a null.
                for (int j = 0; j < allKeyVarsMissingFromOutput.Count; j++)
                {
                    Var keyVar = allKeyVarsMissingFromOutput[j];

                    if (!keyVarsMissingFromOutput[i].IsSet(keyVar))
                    {
                        varDefNodes.Add(
                            m_command.CreateVarDefNode(
                                m_command.CreateNode(
                                    m_command.CreateNullOp(keyVar.Type)), out keyVar));

                        branchOutputVars.Set(keyVar);
                    }

                    // In all cases, we're adding a key to the output so we need to update the
                    // varmap.
                    op.VarMap[i].Add(allKeyVarsToAddToOutput[j], keyVar);
                }

                // If we got this far and didn't add anything to the branch, then we're done.
                // Otherwise we'll have to construct the new projectOp around the input branch
                // to add the stuff we've added.
                if (branchOutputVars.IsEmpty)
                {
                    // Actually, we're not quite done -- we need to update the key vars for the
                    // branch to include the branch discriminator var we
                    branchNodeInfo.Keys.KeyVars.Set(branchDiscriminatorVar);
                }
                else
                {
                    PlanCompiler.Assert(varDefNodes.Count != 0, "no new nodes?");

                    // Start by ensuring all the existing outputs from the branch are in the list.
                    foreach (Var v in op.VarMap[i].Values)
                    {
                        branchOutputVars.Set(v);
                    }

                    // Now construct a project op to project out everything we've added, and
                    // replace the branchNode with it in the flattened ladder.
                    n.Children[i] = m_command.CreateNode(m_command.CreateProjectOp(branchOutputVars),
                                                         branchNode,
                                                         m_command.CreateNode(m_command.CreateVarDefListOp(), varDefNodes));

                    // Finally, ensure that we update the Key info for the projectOp to include
                    // the original branch's keys, along with the branch discriminator var.
                    m_command.RecomputeNodeInfo(n.Children[i]);
                    ExtendedNodeInfo projectNodeInfo = m_command.GetExtendedNodeInfo(n.Children[i]);
                    projectNodeInfo.Keys.KeyVars.InitFrom(branchNodeInfo.Keys.KeyVars);
                    projectNodeInfo.Keys.KeyVars.Set(branchDiscriminatorVar);
                }
            }

            // All done with the branches, now it's time to update the UnionAll op to indicate
            // that we've got a branch discriminator var.
            n.Op = m_command.CreateUnionAllOp(op.VarMap[0], op.VarMap[1], outputBranchDiscriminatorVar);

            // Finally, the thing we've all been waiting for -- computing the keys.  We cheat here and let
            // nodeInfo do it so we don't have to duplicate the logic...
            m_command.RecomputeNodeInfo(n);

#if DEBUG
            input = input.Trim();
            string output = Dump.ToXml(m_command, n);
#endif //DEBUG
        }
Beispiel #20
0
        /// <summary>
        /// Create the flattened record type for the type.
        /// Walk through the list of property refs, and creates a new field
        /// (which we name as "F1", "F2" etc.) with the required property type.
        ///
        /// We then produce a mapping from the original property (propertyRef really)
        /// to the new property for use in later modules.
        ///
        /// Finally, we identify the TypeId and EntitySetId property if they exist
        /// </summary>
        /// <param name="type"></param>
        private void CreateFlattenedRecordType(RootTypeInfo type)
        {
            //
            // If this type corresponds to an entity type, and that entity type
            // has no subtypes, and that that entity type has no complex properties
            // then simply use the name from that property
            //
            bool usePropertyNamesFromUnderlyingType;

            if (md.TypeSemantics.IsEntityType(type.Type) &&
                type.ImmediateSubTypes.Count == 0)
            {
                usePropertyNamesFromUnderlyingType = true;
            }
            else
            {
                usePropertyNamesFromUnderlyingType = false;
            }


            // Build the record type
            List <KeyValuePair <string, md.TypeUsage> > fieldList = new List <KeyValuePair <string, md.TypeUsage> >();
            HashSet <string> fieldNames = new HashSet <string>();
            int nextFieldId             = 0;

            foreach (PropertyRef p in type.PropertyRefList)
            {
                string fieldName = null;
                if (usePropertyNamesFromUnderlyingType)
                {
                    SimplePropertyRef simpleP = p as SimplePropertyRef;
                    if (simpleP != null)
                    {
                        fieldName = simpleP.Property.Name;
                    }
                }

                if (fieldName == null)
                {
                    fieldName = "F" + nextFieldId.ToString(CultureInfo.InvariantCulture);
                    nextFieldId++;
                }

                // Deal with collisions
                while (fieldNames.Contains(fieldName))
                {
                    fieldName = "F" + nextFieldId.ToString(CultureInfo.InvariantCulture);
                    nextFieldId++;
                }

                md.TypeUsage propertyType = GetPropertyType(type, p);
                fieldList.Add(new KeyValuePair <string, md.TypeUsage>(fieldName, propertyType));
                fieldNames.Add(fieldName);
            }

            type.FlattenedType = TypeHelpers.CreateRowType(fieldList);

            // Now build up the property map
            IEnumerator <PropertyRef> origProps = type.PropertyRefList.GetEnumerator();

            foreach (md.EdmProperty p in type.FlattenedType.Properties)
            {
                if (!origProps.MoveNext())
                {
                    PlanCompiler.Assert(false, "property refs count and flattened type member count mismatch?");
                }
                type.AddPropertyMapping(origProps.Current, p);
            }
        }
Beispiel #21
0
        /// <summary>
        /// Add a new entry to the map. If an entry already exists, then this function
        /// simply returns the existing entry. Otherwise a new entry is created. If
        /// the type has a supertype, then we ensure that the supertype also exists in
        /// the map, and we add our info to the supertype's list of subtypes
        /// </summary>
        /// <param name="type">New type to add</param>
        /// <param name="discriminatorMap">type discriminator map</param>
        /// <returns>The TypeInfo for this type</returns>
        private TypeInfo CreateTypeInfoForStructuredType(md.TypeUsage type, ExplicitDiscriminatorMap discriminatorMap)
        {
            TypeInfo typeInfo;

            PlanCompiler.Assert(TypeUtils.IsStructuredType(type), "expected structured type. Found " + type);

            // Return existing entry, if one is available
            typeInfo = GetTypeInfo(type);
            if (typeInfo != null)
            {
                return(typeInfo);
            }

            // Ensure that my supertype has been added to the map.
            TypeInfo superTypeInfo = null;

            md.RefType refType;
            if (type.EdmType.BaseType != null)
            {
                superTypeInfo = CreateTypeInfoForStructuredType(md.TypeUsage.Create(type.EdmType.BaseType), discriminatorMap);
            }
            //
            // Handle Ref types also in a similar fashion
            //
            else if (TypeHelpers.TryGetEdmType <md.RefType>(type, out refType))
            {
                md.EntityType entityType = refType.ElementType as md.EntityType;
                if (entityType != null && entityType.BaseType != null)
                {
                    md.TypeUsage baseRefType = TypeHelpers.CreateReferenceTypeUsage(entityType.BaseType as md.EntityType);
                    superTypeInfo = CreateTypeInfoForStructuredType(baseRefType, discriminatorMap);
                }
            }

            //
            // Add the types of my properties to the TypeInfo map
            //
            foreach (md.EdmMember m in TypeHelpers.GetDeclaredStructuralMembers(type))
            {
                CreateTypeInfoForType(m.TypeUsage);
            }

            //
            // Get the types of the rel properties also
            //
            {
                md.EntityTypeBase entityType;
                if (TypeHelpers.TryGetEdmType <md.EntityTypeBase>(type, out entityType))
                {
                    foreach (RelProperty p in m_relPropertyHelper.GetDeclaredOnlyRelProperties(entityType))
                    {
                        CreateTypeInfoForType(p.ToEnd.TypeUsage);
                    }
                }
            }


            // Now add myself to the map
            typeInfo = TypeInfo.Create(type, superTypeInfo, discriminatorMap);
            m_typeInfoMap.Add(type, typeInfo);

            return(typeInfo);
        }
        /// <summary>
        /// If the Subtree rooted at the collect is of the following structure:
        ///
        /// PhysicalProject(outputVar)
        /// |
        /// Project(s)
        /// |
        /// Unnest
        ///
        /// where the unnest is over the group aggregate var and the output var
        /// is either a reference to the group aggregate var or to a constant, it returns the
        /// translation of the ouput var.
        /// </summary>
        /// <param name="n"></param>
        /// <returns></returns>
        private Node VisitCollect(Node n)
        {
            //Make sure the only children are projects over unnest
            Node currentNode = n.Child0;
            Dictionary <Var, Node> constantDefinitions = new Dictionary <Var, Node>();

            while (currentNode.Child0.Op.OpType == OpType.Project)
            {
                currentNode = currentNode.Child0;
                //Visit the VarDefListOp child
                if (VisitDefault(currentNode.Child1) == null)
                {
                    return(null);
                }
                foreach (Node definitionNode in currentNode.Child1.Children)
                {
                    if (IsConstant(definitionNode.Child0))
                    {
                        constantDefinitions.Add(((VarDefOp)definitionNode.Op).Var, definitionNode.Child0);
                    }
                }
            }

            if (currentNode.Child0.Op.OpType != OpType.Unnest)
            {
                return(null);
            }

            // Handle the unnest
            UnnestOp unnestOp = (UnnestOp)currentNode.Child0.Op;
            GroupAggregateVarRefInfo groupAggregateVarRefInfo;

            if (_groupAggregateVarInfoManager.TryGetReferencedGroupAggregateVarInfo(unnestOp.Var, out groupAggregateVarRefInfo))
            {
                if (_targetGroupAggregateVarInfo == null)
                {
                    _targetGroupAggregateVarInfo = groupAggregateVarRefInfo.GroupAggregateVarInfo;
                }
                else if (_targetGroupAggregateVarInfo != groupAggregateVarRefInfo.GroupAggregateVarInfo)
                {
                    return(null);
                }
                if (!_isUnnested)
                {
                    return(null);
                }
            }
            else
            {
                return(null);
            }

            PhysicalProjectOp physicalProjectOp = (PhysicalProjectOp)n.Child0.Op;

            PlanCompiler.Assert(physicalProjectOp.Outputs.Count == 1, "PhysicalProject should only have one output at this stage");
            Var outputVar = physicalProjectOp.Outputs[0];

            Node computationTemplate = TranslateOverGroupAggregateVar(outputVar, null);

            if (computationTemplate != null)
            {
                _isUnnested = true;
                return(computationTemplate);
            }

            Node constantDefinitionNode;

            if (constantDefinitions.TryGetValue(outputVar, out constantDefinitionNode))
            {
                _isUnnested = true;
                return(constantDefinitionNode);
            }
            return(null);
        }
        /// <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();
        }
 /// <summary>
 /// Basic constructor.
 /// Represents the access of property "propertyRef" within property "property"
 /// </summary>
 /// <param name="innerProperty">the inner property</param>
 /// <param name="outerProperty">the outer property</param>
 internal NestedPropertyRef(PropertyRef innerProperty, PropertyRef outerProperty)
 {
     PlanCompiler.Assert(!(innerProperty is NestedPropertyRef), "innerProperty cannot be a NestedPropertyRef");
     m_inner = innerProperty;
     m_outer = outerProperty;
 }