Пример #1
0
        internal override void PropagateDataTypesForOutSchema()
        {
            // Output for JOIN depends on type of the join
            // For LEFT join, attributes becomes non-nullable
            // For CROSS join or INNER join, attributes type remains unchanged after join
            if (Type == JoinType.Left)
            {
                var prevLeftSchema  = InOperatorLeft.OutputSchema;
                var prevRightSchema = InOperatorRight.OutputSchema;

                var fieldMapping = new Dictionary <Field, Field>();
                foreach (var outField in OutputSchema)
                {
                    var inFieldMatches = InputSchema.Where(f => f.FieldAlias == outField.FieldAlias);
                    Debug.Assert(InputSchema.Where(f => f.FieldAlias == outField.FieldAlias).Count() == 1); // must have match in IN for any OUT field
                    var inField = inFieldMatches.First();
                    // we made it that left schema LEFT OUTTER JOIN with right schema always
                    var isFromRight = !prevLeftSchema.Any(f => f.FieldAlias == inField.FieldAlias);

                    // copy over the schema first
                    outField.Copy(inField);

                    // make adjustment for outter join
                    if (inField is ValueField)
                    {
                        Debug.Assert(outField.GetType() == inField.GetType()); // join doesn't alter field types
                        var outFieldSingleField = outField as ValueField;

                        if (isFromRight && !TypeHelper.CanAssignNullToType(outFieldSingleField.FieldType))
                        {
                            // make it nullable variant of the original type
                            outFieldSingleField.FieldType = TypeHelper.GetNullableTypeForType(outFieldSingleField.FieldType);
                        }
                    }
                    else
                    {
                        Debug.Assert(outField is EntityField);
                        var outEntCapFields = (outField as EntityField).EncapsulatedFields;

                        if (isFromRight)
                        {
                            foreach (var outEntCapField in outEntCapFields)
                            {
                                if (!TypeHelper.CanAssignNullToType(outEntCapField.FieldType))
                                {
                                    // make it nullable variant of the original type
                                    outEntCapField.FieldType = TypeHelper.GetNullableTypeForType(outEntCapField.FieldType);
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                base.PropagateDataTypesForOutSchema();
            }
        }
Пример #2
0
            /// <summary>
            /// Given a set of columns, return the input columns that are needed to generate those output columns.
            /// </summary>
            IEnumerable <DataViewSchema.Column> ISchemaBoundRowMapper.GetDependenciesForNewColumns(IEnumerable <DataViewSchema.Column> dependingColumns)
            {
                if (dependingColumns.Count() == 0)
                {
                    return(Enumerable.Empty <DataViewSchema.Column>());
                }

                return(InputSchema.Where(col => _inputColIndices.Contains(col.Index)));
            }
        /// <summary>
        /// Used by logic planner to update the list of ReferencedFields
        /// </summary>
        internal virtual void PropagateReferencedPropertiesForEntityFields()
        {
            // lift the referenced fields from the next layer of operators back to this one's output entity fields
            var referredFieldsInDownstreamOps = OutOperators.SelectMany(op => op.InputSchema)
                                                .Where(f => f is EntityField)
                                                .Cast <EntityField>()
                                                .GroupBy(f => f.FieldAlias)
                                                .ToDictionary(kv => kv.Key, kv => kv.SelectMany(fn => fn.ReferencedFieldAliases).Distinct().ToList());

            foreach (var field in OutputSchema.Where(f => f is EntityField).Cast <EntityField>())
            {
                Debug.Assert(referredFieldsInDownstreamOps.ContainsKey(field.FieldAlias));
                field.AddReferenceFieldNames(referredFieldsInDownstreamOps[field.FieldAlias]);
            }

            // lift the referenced fields in the entity fields from output to input schema of this operator, if
            // applicable
            if ((InputSchema?.Count ?? 0) > 0)
            {
                // handle entity name renamed cases by creating a map from field alias before projection to after
                // projection
                var aliasMap = new Dictionary <String, String>();

                if (this is ProjectionOperator)
                {
                    var aliasMap1 = (this as ProjectionOperator).ProjectionMap
                                    .Where(u => OutputSchema.Where(n => n is EntityField).Any(k => k.FieldAlias == u.Key));
                    aliasMap = aliasMap1?.ToDictionary(n => n.Value.GetChildrenQueryExpressionType <QueryExpressionProperty>().First().VariableName, n => n.Key);
                }
                else
                {
                    // create a dummy alias map ( A -> A, B -> B; not alias name modified) for non-projection operator
                    aliasMap = OutputSchema.Where(n => n is EntityField).ToDictionary(n => n.FieldAlias, n => n.FieldAlias);
                }

                foreach (var field in InputSchema.Where(f => f is EntityField).Cast <EntityField>())
                {
                    var mappedAlias = (aliasMap.ContainsKey(field.FieldAlias) ?aliasMap[field.FieldAlias]:null);

                    if (mappedAlias != null && referredFieldsInDownstreamOps.ContainsKey(mappedAlias))
                    {
                        field.AddReferenceFieldNames(referredFieldsInDownstreamOps[mappedAlias]);
                    }
                }

                var referredFieldsForUpstream = InputSchema
                                                .Where(f => f is EntityField).Cast <EntityField>()
                                                .ToDictionary(kv => kv.FieldAlias, kv => kv);

                // Some operators has additional fields may get referenced even they are not in output schema
                // Such as in WHERE or ORDER BY
                // Child logical operator class implement this and does the appending
                AppendReferencedProperties(referredFieldsForUpstream);
            }
        }
Пример #4
0
 /// <summary>
 /// For adding to the maintained list of what entities are joint together by this operator
 /// </summary>
 /// <param name="entityAlias1">the alias on the left side of the join</param>
 /// <param name="entityAlias2">the alias on the right side of the join</param>
 internal void AddJoinPair(JoinKeyPair joinKeyPair)
 {
     Debug.Assert(InputSchema.Where(f => f is EntityField && f.FieldAlias == joinKeyPair.NodeAlias).Count() == 1);
     Debug.Assert(InputSchema.Where(f => f is EntityField && f.FieldAlias == joinKeyPair.RelationshipOrNodeAlias).Count() == 1);
     _joinPairs.Add(joinKeyPair);
 }