internal override SqlExpression VisitTreat(SqlUnary t) { t.Operand = this.VisitExpression(t.Operand); Type treatType = t.ClrType; Type originalType = model.GetMetaType(t.Operand.ClrType).InheritanceRoot.Type; // .NET nullability rules are that typeof(int)==typeof(int?). Let's be consistent with that: treatType = TypeSystem.GetNonNullableType(treatType); originalType = TypeSystem.GetNonNullableType(originalType); if (treatType == originalType) { return(t.Operand); } else if (treatType.IsAssignableFrom(originalType)) { t.Operand.SetClrType(treatType); return(t.Operand); } else if (!treatType.IsAssignableFrom(originalType) && !originalType.IsAssignableFrom(treatType)) { if (!treatType.IsInterface && !originalType.IsInterface) // You can't tell when there's an interface involved. // We statically know the TREAT will result in NULL. { return(sql.TypedLiteralNull(treatType, t.SourceExpression)); } } //return base.VisitTreat(t); return(t); }
/// <summary> /// Get a MetaType that represents the dynamic type of the given node. /// </summary> internal static MetaType GetSourceMetaType(SqlNode node, MetaModel model) { Visitor v = new Visitor(); v.Visit(node); Type type = v.sourceType; type = TypeSystem.GetNonNullableType(type); // Emulate CLR's behavior: strip nullability from type. return(model.GetMetaType(type)); }
internal override SqlRow VisitRow(SqlRow row) { for (int i = 0, n = row.Columns.Count; i < n; i++) { SqlColumn col = row.Columns[i]; SqlExpression expr = this.VisitExpression(col.Expression); if (expr != null) { if (TypeSystem.GetNonNullableType(col.ClrType) != TypeSystem.GetNonNullableType(expr.ClrType)) { throw Error.ColumnClrTypeDoesNotAgreeWithExpressionsClrType(); } } } return(row); }
internal SqlUnary UnaryValueOf(SqlExpression expression, Expression sourceExpression) { Type valueType = TypeSystem.GetNonNullableType(expression.ClrType); return(new SqlUnary(SqlNodeType.ValueOf, valueType, expression.SqlType, expression, null, sourceExpression)); }
internal override SqlNode Visit(SqlNode node) { if (node == null) { return(null); } sourceExpression = node as SqlExpression; if (sourceExpression != null) { Type type = sourceExpression.ClrType; UnwrapStack unwrap = this.UnwrapSequences; while (unwrap != null) { if (unwrap.Unwrap) { type = TypeSystem.GetElementType(type); } unwrap = unwrap.Last; } sourceType = type; } if (sourceType != null && TypeSystem.GetNonNullableType(sourceType).IsValueType) { return(node); // Value types can't also have a dynamic type. } if (sourceType != null && TypeSystem.HasIEnumerable(sourceType)) { return(node); // Sequences can't be polymorphic. } switch (node.NodeType) { case SqlNodeType.ScalarSubSelect: case SqlNodeType.Multiset: case SqlNodeType.Element: case SqlNodeType.SearchedCase: case SqlNodeType.ClientCase: case SqlNodeType.SimpleCase: case SqlNodeType.Member: case SqlNodeType.DiscriminatedType: case SqlNodeType.New: case SqlNodeType.FunctionCall: case SqlNodeType.MethodCall: case SqlNodeType.Convert: // Object identity does not survive convert. It does survive Cast. // Dig no further. return(node); case SqlNodeType.TypeCase: sourceType = ((SqlTypeCase)node).RowType.Type; return(node); case SqlNodeType.Link: sourceType = ((SqlLink)node).RowType.Type; return(node); case SqlNodeType.Table: sourceType = ((SqlTable)node).RowType.Type; return(node); case SqlNodeType.Value: SqlValue val = (SqlValue)node; if (val.Value != null) { // In some cases the ClrType of a Value node may // differ from the actual runtime type of the value. // Therefore, we ensure here that the correct type is set. sourceType = val.Value.GetType(); } return(node); } return(base.Visit(node)); }
internal override SqlExpression VisitUnaryOperator(SqlUnary uo) { uo.Operand = this.VisitExpression(uo.Operand); if (uo.NodeType != SqlNodeType.Convert) { return(uo); } ProviderType oldSqlType = uo.Operand.SqlType; ProviderType newSqlType = uo.SqlType; Type oldClrType = TypeSystem.GetNonNullableType(uo.Operand.ClrType); Type newClrType = TypeSystem.GetNonNullableType(uo.ClrType); if (newClrType == typeof(char)) { if (oldClrType == typeof(bool)) { throw Error.ConvertToCharFromBoolNotSupported(); } if (oldSqlType.IsNumeric) { // numeric --> char return(sql.FunctionCall(uo.ClrType, "NCHAR", new SqlExpression[] { uo.Operand }, uo.SourceExpression)); } if (StringConversionIsSafe(oldSqlType, newSqlType)) { if (StringConversionIsNeeded(oldSqlType, newSqlType)) { // set the new size to the (potentially smaller) oldSqlType.Size uo.SetSqlType(sql.TypeProvider.From(uo.ClrType, oldSqlType.HasSizeOrIsLarge ? oldSqlType.Size : (int?)null)); } } else { throw Error.UnsafeStringConversion(oldSqlType.ToQueryString(), newSqlType.ToQueryString()); } } else if (oldClrType == typeof(char) && (oldSqlType.IsChar || oldSqlType.IsString) && newSqlType.IsNumeric) { // char --> int return(sql.FunctionCall(newClrType, sql.TypeProvider.From(typeof(int)), "UNICODE", new SqlExpression[] { uo.Operand }, uo.SourceExpression)); } else if (newClrType == typeof(string)) { if (oldClrType == typeof(double)) { // use longer format if it was a double in the CLR expression return(ConvertDoubleToString(uo.Operand, uo.ClrType)); } else if (oldClrType == typeof(bool)) { // use 'true' or 'false' if it was a bool in the CLR expression return(ConvertBitToString(uo.Operand, uo.ClrType)); } else if (StringConversionIsSafe(oldSqlType, newSqlType)) { if (StringConversionIsNeeded(oldSqlType, newSqlType)) { // set the new size to the (potentially smaller) oldSqlType.Size uo.SetSqlType(sql.TypeProvider.From(uo.ClrType, oldSqlType.HasSizeOrIsLarge ? oldSqlType.Size : (int?)null)); } } else { throw Error.UnsafeStringConversion(oldSqlType.ToQueryString(), newSqlType.ToQueryString()); } } return(uo); }