internal override SqlExpression VisitUnaryOperator(SqlUnary fc) { // process the arguments SqlExpression result = base.VisitUnaryOperator(fc); if(result is SqlUnary) { SqlUnary unary = (SqlUnary)result; switch(unary.NodeType) { case SqlNodeType.ClrLength: SqlExpression expr = unary.Operand; result = sql.FunctionCallDataLength(expr); if(expr.SqlType.IsUnicodeType) { result = sql.Divide(result, sql.ValueFromObject(2, expr.SourceExpression)); } result = sql.ConvertToInt(result); break; default: break; } } return result; }
internal override SqlExpression VisitUnaryOperator(SqlUnary uo) { base.VisitUnaryOperator(uo); if(uo.NodeType != SqlNodeType.Convert && uo.Operand != null && uo.Operand.SqlType != null) { uo.SetSqlType(this.typeProvider.PredictTypeForUnary(uo.NodeType, uo.Operand.SqlType)); } return uo; }
internal override SqlExpression VisitUnaryOperator(SqlUnary uo) { if(uo.NodeType.IsUnaryOperatorExpectingPredicateOperand()) { uo.Operand = this.VisitPredicate(uo.Operand); } else { uo.Operand = this.VisitExpression(uo.Operand); } return uo; }
internal override SqlExpression VisitUnaryOperator(SqlUnary uo) { switch (uo.NodeType) { case SqlNodeType.Min: case SqlNodeType.Max: case SqlNodeType.Avg: case SqlNodeType.Sum: case SqlNodeType.Count: case SqlNodeType.LongCount: this.hasAggregates = true; return uo; default: return base.VisitUnaryOperator(uo); } }
internal virtual SqlExpression VisitUnaryOperator(SqlUnary uo) { uo.Operand = this.VisitExpression(uo.Operand); return uo; }
private Type GenerateValueOf(SqlUnary u) { Diagnostics.Debug.Assert(TypeSystem.IsNullableType(u.Operand.ClrType)); this.GenerateExpressionForType(u.Operand, u.Operand.ClrType); LocalBuilder loc = gen.DeclareLocal(u.Operand.ClrType); gen.Emit(OpCodes.Stloc, loc); gen.Emit(OpCodes.Ldloca, loc); this.GenerateGetValue(u.Operand.ClrType); return u.ClrType; }
internal override SqlExpression VisitUnaryOperator(SqlUnary uo) { switch(uo.NodeType) { case SqlNodeType.Not: case SqlNodeType.Not2V: _commandStringBuilder.Append(GetOperator(uo.NodeType)); _commandStringBuilder.Append(" "); this.VisitWithParens(uo.Operand, uo); break; case SqlNodeType.Negate: case SqlNodeType.BitNot: _commandStringBuilder.Append(GetOperator(uo.NodeType)); this.VisitWithParens(uo.Operand, uo); break; case SqlNodeType.Count: case SqlNodeType.LongCount: case SqlNodeType.Max: case SqlNodeType.Min: case SqlNodeType.Sum: case SqlNodeType.Avg: case SqlNodeType.Stddev: case SqlNodeType.ClrLength: { _commandStringBuilder.Append(GetOperator(uo.NodeType)); _commandStringBuilder.Append("("); if(uo.Operand == null) { _commandStringBuilder.Append("*"); } else { this.Visit(uo.Operand); } _commandStringBuilder.Append(")"); break; } case SqlNodeType.IsNull: case SqlNodeType.IsNotNull: { this.VisitWithParens(uo.Operand, uo); _commandStringBuilder.Append(" "); _commandStringBuilder.Append(GetOperator(uo.NodeType)); break; } case SqlNodeType.Convert: { _commandStringBuilder.Append("CONVERT("); QueryFormatOptions options = QueryFormatOptions.None; if(uo.Operand.SqlType.CanSuppressSizeForConversionToString) { options = QueryFormatOptions.SuppressSize; } _commandStringBuilder.Append(uo.SqlType.ToQueryString(options)); _commandStringBuilder.Append(","); this.Visit(uo.Operand); _commandStringBuilder.Append(")"); break; } case SqlNodeType.ValueOf: case SqlNodeType.OuterJoinedValue: this.Visit(uo.Operand); // no op break; default: throw Error.InvalidFormatNode(uo.NodeType); } return uo; }
internal override SqlExpression VisitTreat(SqlUnary t) { _commandStringBuilder.Append("TREAT("); this.Visit(t.Operand); _commandStringBuilder.Append(" AS "); this.FormatType(t.SqlType); _commandStringBuilder.Append(")"); return t; }
internal override SqlExpression VisitCast(SqlUnary c) { _commandStringBuilder.Append("CAST("); this.Visit(c.Operand); _commandStringBuilder.Append(" AS "); QueryFormatOptions options = QueryFormatOptions.None; if(c.Operand.SqlType.CanSuppressSizeForConversionToString) { options = QueryFormatOptions.SuppressSize; } _commandStringBuilder.Append(c.SqlType.ToQueryString(options)); _commandStringBuilder.Append(")"); return c; }
internal override SqlExpression VisitUnaryOperator(SqlUnary uo) { return new SqlUnary(uo.NodeType, uo.ClrType, uo.SqlType, (SqlExpression)this.Visit(uo.Operand), uo.Method, uo.SourceExpression); }
internal override SqlExpression VisitTreat(SqlUnary t) { return new SqlUnary(SqlNodeType.Treat, t.ClrType, t.SqlType, (SqlExpression)this.Visit(t.Operand), t.SourceExpression); }
private static bool IsSupportedUnary(SqlUnary uo) { return uo.NodeType == SqlNodeType.Convert && uo.ClrType == typeof(char) || uo.Operand.ClrType == typeof(char); }
internal virtual SqlExpression VisitCast(SqlUnary c) { c.Operand = this.VisitExpression(c.Operand); return c; }
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); } if(oldClrType == typeof(bool)) { // use 'true' or 'false' if it was a bool in the CLR expression return ConvertBitToString(uo.Operand, uo.ClrType); } 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; }
internal override SqlExpression VisitUnaryOperator(SqlUnary uo) { uo.Operand = this.VisitExpression(uo.Operand); // ------------------------------------------------------------ // PHASE 1: If possible, evaluate without fetching the operand. // This is preferred because fetching LINKs causes them to not // be deferred. // ------------------------------------------------------------ if (uo.NodeType == SqlNodeType.IsNull || uo.NodeType == SqlNodeType.IsNotNull) { SqlExpression translated = this.translator.TranslateLinkIsNull(uo); if (translated != uo) { return this.VisitExpression(translated); } if (uo.Operand.NodeType==SqlNodeType.OuterJoinedValue) { SqlUnary ojv = uo.Operand as SqlUnary; if (ojv.Operand.NodeType == SqlNodeType.OptionalValue) { SqlOptionalValue ov = (SqlOptionalValue)ojv.Operand; return this.VisitUnaryOperator( new SqlUnary(uo.NodeType, uo.ClrType, uo.SqlType, new SqlUnary(SqlNodeType.OuterJoinedValue, ov.ClrType, ov.SqlType, ov.HasValue, ov.SourceExpression) , uo.SourceExpression) ); } else if (ojv.Operand.NodeType == SqlNodeType.TypeCase) { SqlTypeCase tc = (SqlTypeCase)ojv.Operand; return new SqlUnary(uo.NodeType, uo.ClrType, uo.SqlType, new SqlUnary(SqlNodeType.OuterJoinedValue, tc.Discriminator.ClrType, tc.Discriminator.SqlType, tc.Discriminator, tc.SourceExpression), uo.SourceExpression ); } } } // Fetch the expression. uo.Operand = this.ConvertToFetchedExpression(uo.Operand); // ------------------------------------------------------------ // PHASE 2: Evaluate operator on fetched expression. // ------------------------------------------------------------ if ((uo.NodeType == SqlNodeType.Not || uo.NodeType == SqlNodeType.Not2V) && uo.Operand.NodeType == SqlNodeType.Value) { SqlValue val = (SqlValue)uo.Operand; return sql.Value(typeof(bool), val.SqlType, !(bool)val.Value, val.IsClientSpecified, val.SourceExpression); } else if (uo.NodeType == SqlNodeType.Not2V) { if (SqlExpressionNullability.CanBeNull(uo.Operand) != false) { SqlSearchedCase c = new SqlSearchedCase( typeof(int), new [] { new SqlWhen(uo.Operand, sql.ValueFromObject(1, false, uo.SourceExpression)) }, sql.ValueFromObject(0, false, uo.SourceExpression), uo.SourceExpression ); return sql.Binary(SqlNodeType.EQ, c, sql.ValueFromObject(0, false, uo.SourceExpression)); } else { return sql.Unary(SqlNodeType.Not, uo.Operand); } } // push converts of client-expressions inside the client-expression (to be evaluated client side) else if (uo.NodeType == SqlNodeType.Convert && uo.Operand.NodeType == SqlNodeType.Value) { SqlValue val = (SqlValue)uo.Operand; return sql.Value(uo.ClrType, uo.SqlType, DBConvert.ChangeType(val.Value, uo.ClrType), val.IsClientSpecified, val.SourceExpression); } else if (uo.NodeType == SqlNodeType.IsNull || uo.NodeType == SqlNodeType.IsNotNull) { bool? canBeNull = SqlExpressionNullability.CanBeNull(uo.Operand); if (canBeNull == false) { return sql.ValueFromObject(uo.NodeType == SqlNodeType.IsNotNull, false, uo.SourceExpression); } SqlExpression exp = uo.Operand; switch (exp.NodeType) { case SqlNodeType.Element: exp = sql.SubSelect(SqlNodeType.Exists, ((SqlSubSelect)exp).Select); if (uo.NodeType == SqlNodeType.IsNull) { exp = sql.Unary(SqlNodeType.Not, exp, exp.SourceExpression); } return exp; case SqlNodeType.ClientQuery: { SqlClientQuery cq = (SqlClientQuery)exp; if (cq.Query.NodeType == SqlNodeType.Element) { exp = sql.SubSelect(SqlNodeType.Exists, cq.Query.Select); if (uo.NodeType == SqlNodeType.IsNull) { exp = sql.Unary(SqlNodeType.Not, exp, exp.SourceExpression); } return exp; } return sql.ValueFromObject(uo.NodeType == SqlNodeType.IsNotNull, false, uo.SourceExpression); } case SqlNodeType.OptionalValue: uo.Operand = ((SqlOptionalValue)exp).HasValue; return uo; case SqlNodeType.ClientCase: { // Distribute unary into simple case. SqlClientCase sc = (SqlClientCase)uo.Operand; List<SqlExpression> matches = new List<SqlExpression>(); List<SqlExpression> values = new List<SqlExpression>(); foreach (SqlClientWhen when in sc.Whens) { matches.Add(when.Match); values.Add(VisitUnaryOperator(sql.Unary(uo.NodeType, when.Value, when.Value.SourceExpression))); } return sql.Case(sc.ClrType, sc.Expression, matches, values, sc.SourceExpression); } case SqlNodeType.TypeCase: { // Distribute unary into type case. In the process, convert to simple case. SqlTypeCase tc = (SqlTypeCase)uo.Operand; List<SqlExpression> newMatches = new List<SqlExpression>(); List<SqlExpression> newValues = new List<SqlExpression>(); foreach (SqlTypeCaseWhen when in tc.Whens) { SqlUnary un = new SqlUnary(uo.NodeType, uo.ClrType, uo.SqlType, when.TypeBinding, when.TypeBinding.SourceExpression); SqlExpression expr = VisitUnaryOperator(un); if (expr is SqlNew) { throw Error.DidNotExpectTypeBinding(); } newMatches.Add(when.Match); newValues.Add(expr); } return sql.Case(uo.ClrType, tc.Discriminator, newMatches, newValues, tc.SourceExpression); } case SqlNodeType.Value: { SqlValue val = (SqlValue)uo.Operand; return sql.Value(typeof(bool), this.typeProvider.From(typeof(int)), (val.Value == null) == (uo.NodeType == SqlNodeType.IsNull), val.IsClientSpecified, uo.SourceExpression); } } } else if (uo.NodeType == SqlNodeType.Treat) { return ApplyTreat(VisitExpression(uo.Operand), uo.ClrType); } return uo; }
internal override SqlExpression VisitTreat(SqlUnary a) { return VisitUnaryOperator(a); }
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; } if(treatType.IsAssignableFrom(originalType)) { t.Operand.SetClrType(treatType); return t.Operand; } 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; }
// transform type conversion if necessary internal override SqlExpression VisitUnaryOperator(SqlUnary uo) { if(uo.NodeType == SqlNodeType.Convert) { Type newType = uo.ClrType; SqlExpression expr = uo.Operand; if(newType == typeof(char) || expr.ClrType == typeof(char)) { expr = this.VisitExpression(uo.Operand); uo.Operand = expr; return sql.ConvertTo(newType, uo.SqlType, expr); } } return base.VisitUnaryOperator(uo); }
internal virtual SqlExpression VisitTreat(SqlUnary t) { t.Operand = this.VisitExpression(t.Operand); return t; }
internal SqlExpression TranslateLinkIsNull(SqlUnary expr) { System.Diagnostics.Debug.Assert(expr.NodeType == SqlNodeType.IsNull || expr.NodeType == SqlNodeType.IsNotNull); SqlLink link = expr.Operand as SqlLink; if (!(link != null && link.Member.IsAssociation && link.Member.Association.IsForeignKey)) { return expr; } List<SqlExpression> exprs = link.KeyExpressions; System.Diagnostics.Debug.Assert(exprs.Count > 0); SqlExpression exp = null; SqlNodeType combo = (expr.NodeType == SqlNodeType.IsNull) ? SqlNodeType.Or : SqlNodeType.And; for (int i = 0, n = exprs.Count; i < n; i++) { SqlExpression compare = sql.Unary(expr.NodeType, sql.DoNotVisitExpression(exprs[i]), expr.SourceExpression); if (exp == null) { exp = compare; } else { exp = sql.Binary(combo, exp, compare); } } return exp; }