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(); } }
public override Type EvaluateType() { var innerType = InnerExpression.EvaluateType(); var canBeNull = TypeHelper.CanAssignNullToType(innerType); switch (Function.FunctionName) { case Common.Function.ToFloat: return(canBeNull ? typeof(float?) : typeof(float)); case Common.Function.ToString: return(typeof(string)); case Common.Function.ToBoolean: return(canBeNull ? typeof(bool?) : typeof(bool)); case Common.Function.ToInteger: return(canBeNull ? typeof(int?) : typeof(int)); case Common.Function.ToDouble: return(canBeNull ? typeof(long?) : typeof(long)); case Common.Function.ToLong: return(canBeNull ? typeof(double?) : typeof(double)); case Common.Function.Not: return(canBeNull ? typeof(bool?) : typeof(bool)); case Common.Function.StringContains: case Common.Function.StringStartsWith: case Common.Function.StringEndsWith: case Common.Function.IsNull: case Common.Function.IsNotNull: return(typeof(bool)); case Common.Function.StringSize: return(typeof(int)); default: // treat all the rest as type preserving, e.g. // trim, ltrim .... return(InnerExpression.EvaluateType()); } }