internal override SqlExpression VisitBinaryOperator(SqlBinary bo) { if(IsCompareToValue(bo)) { SqlMethodCall call = (SqlMethodCall)bo.Left; if(IsCompareToMethod(call)) { int iValue = System.Convert.ToInt32(this.Eval(bo.Right), Globalization.CultureInfo.InvariantCulture); bo = this.MakeCompareTo(call.Object, call.Arguments[0], bo.NodeType, iValue) ?? bo; } else if(IsCompareMethod(call)) { int iValue = System.Convert.ToInt32(this.Eval(bo.Right), Globalization.CultureInfo.InvariantCulture); bo = this.MakeCompareTo(call.Arguments[0], call.Arguments[1], bo.NodeType, iValue) ?? bo; } } else if(IsVbCompareStringEqualsValue(bo)) { SqlMethodCall call = (SqlMethodCall)bo.Left; int iValue = System.Convert.ToInt32(this.Eval(bo.Right), Globalization.CultureInfo.InvariantCulture); //in VB, comparing a string with Nothing means comparing with "" SqlValue strValue = call.Arguments[1] as SqlValue; if(strValue != null && strValue.Value == null) { SqlValue emptyStr = new SqlValue(strValue.ClrType, strValue.SqlType, String.Empty, strValue.IsClientSpecified, strValue.SourceExpression); bo = this.MakeCompareTo(call.Arguments[0], emptyStr, bo.NodeType, iValue) ?? bo; } else { bo = this.MakeCompareTo(call.Arguments[0], call.Arguments[1], bo.NodeType, iValue) ?? bo; } } return base.VisitBinaryOperator(bo); }
internal override SqlExpression VisitBinaryOperator(SqlBinary bo) { // // Special case to allow DateTime CLR type to be passed as a paramater where // a SQL type TIME is expected. We do this only for the equality/inequality // comparisons. // switch(bo.NodeType) { case SqlNodeType.EQ: case SqlNodeType.EQ2V: case SqlNodeType.NE: case SqlNodeType.NE2V: { SqlDbType leftSqlDbType = ((SqlType)(bo.Left.SqlType)).SqlDbType; SqlDbType rightSqlDbType = ((SqlType)(bo.Right.SqlType)).SqlDbType; if(leftSqlDbType == rightSqlDbType) break; bool isLeftColRef = bo.Left is SqlColumnRef; bool isRightColRef = bo.Right is SqlColumnRef; if(isLeftColRef == isRightColRef) break; if(isLeftColRef && leftSqlDbType == SqlDbType.Time && bo.Right.ClrType == typeof(DateTime)) this.timeProviderType = bo.Left.SqlType; else if(isRightColRef && rightSqlDbType == SqlDbType.Time && bo.Left.ClrType == typeof(DateTime)) this.timeProviderType = bo.Left.SqlType; break; } } base.VisitBinaryOperator(bo); return bo; }
internal override SqlExpression VisitBinaryOperator(SqlBinary bo) { if(bo.NodeType.IsBinaryOperatorExpectingPredicateOperands()) { bo.Left = this.VisitPredicate(bo.Left); bo.Right = this.VisitPredicate(bo.Right); } else { bo.Left = this.VisitExpression(bo.Left); bo.Right = this.VisitExpression(bo.Right); } return bo; }
internal override SqlExpression VisitBinaryOperator(SqlBinary bo) { if(bo.NodeType == SqlNodeType.EQ || bo.NodeType == SqlNodeType.NE || bo.NodeType == SqlNodeType.EQ2V || bo.NodeType == SqlNodeType.NE2V || bo.NodeType == SqlNodeType.GT || bo.NodeType == SqlNodeType.GE || bo.NodeType == SqlNodeType.LT || bo.NodeType == SqlNodeType.LE) { if(!bo.Left.SqlType.SupportsComparison || !bo.Right.SqlType.SupportsComparison) { throw Error.UnhandledStringTypeComparison(); } } bo.Left = this.VisitExpression(bo.Left); bo.Right = this.VisitExpression(bo.Right); return bo; }
/// <summary> /// Replace equals and not equals: /// /// | CASE XXX | CASE XXX CASE XXX /// | WHEN AAA THEN MMMM | != RRRR ===> WHEN AAA THEN (MMMM != RRRR) ==> WHEN AAA THEN true /// | WHEN BBB THEN NNNN | WHEN BBB THEN (NNNN != RRRR) WHEN BBB THEN false /// | etc. | etc. etc. /// | ELSE OOOO | ELSE (OOOO != RRRR) ELSE true /// | END END END /// /// Where MMMM, NNNN and RRRR are constants. /// </summary> internal override SqlExpression VisitBinaryOperator(SqlBinary bo) { switch(bo.NodeType) { case SqlNodeType.EQ: case SqlNodeType.NE: case SqlNodeType.EQ2V: case SqlNodeType.NE2V: if(bo.Left.NodeType == SqlNodeType.SimpleCase && bo.Right.NodeType == SqlNodeType.Value && AreCaseWhenValuesConstant((SqlSimpleCase)bo.Left)) { return this.DistributeOperatorIntoCase(bo.NodeType, (SqlSimpleCase)bo.Left, bo.Right); } else if(bo.Right.NodeType == SqlNodeType.SimpleCase && bo.Left.NodeType == SqlNodeType.Value && AreCaseWhenValuesConstant((SqlSimpleCase)bo.Right)) { return this.DistributeOperatorIntoCase(bo.NodeType, (SqlSimpleCase)bo.Right, bo.Left); } break; } return base.VisitBinaryOperator(bo); }
internal override SqlExpression VisitBinaryOperator(SqlBinary bo) { SqlExpression left = (SqlExpression)this.Visit(bo.Left); SqlExpression right = (SqlExpression)this.Visit(bo.Right); return new SqlBinary(bo.NodeType, bo.ClrType, bo.SqlType, left, right, bo.Method); }
internal override SqlExpression VisitBinaryOperator(SqlBinary bo) { base.VisitBinaryOperator(bo); if(bo.NodeType.IsComparisonOperator() && bo.Left.ClrType != typeof(bool) && bo.Right.ClrType != typeof(bool)) { // Strip unnecessary CONVERT calls. if(bo.Left.NodeType == SqlNodeType.Convert) { var conv = (SqlUnary)bo.Left; if(CanDbConvert(conv.Operand.ClrType, bo.Right.ClrType) && conv.Operand.SqlType.ComparePrecedenceTo(bo.Right.SqlType) != 1) { return VisitBinaryOperator(new SqlBinary(bo.NodeType, bo.ClrType, bo.SqlType, conv.Operand, bo.Right)); } } if(bo.Right.NodeType == SqlNodeType.Convert) { var conv = (SqlUnary)bo.Right; if(CanDbConvert(conv.Operand.ClrType, bo.Left.ClrType) && conv.Operand.SqlType.ComparePrecedenceTo(bo.Left.SqlType) != 1) { return VisitBinaryOperator(new SqlBinary(bo.NodeType, bo.ClrType, bo.SqlType, bo.Left, conv.Operand)); } } } if(bo.Right != null && bo.NodeType != SqlNodeType.Concat) { SqlExpression left = bo.Left; SqlExpression right = bo.Right; this.CoerceBinaryArgs(ref left, ref right); if(bo.Left != left || bo.Right != right) { bo = sql.Binary(bo.NodeType, left, right); } bo.SetSqlType(typeProvider.PredictTypeForBinary(bo.NodeType, left.SqlType, right.SqlType)); } if(bo.NodeType.IsComparisonOperator()) { // When comparing a unicode value against a non-unicode column, // we want retype the parameter as non-unicode. Func<SqlExpression, SqlExpression, bool> needsRetype = (expr, val) => (val.NodeType == SqlNodeType.Value || val.NodeType == SqlNodeType.ClientParameter) && !(expr.NodeType == SqlNodeType.Value || expr.NodeType == SqlNodeType.ClientParameter) && val.SqlType.IsUnicodeType && !expr.SqlType.IsUnicodeType; SqlSimpleTypeExpression valueToRetype = null; if(needsRetype(bo.Left, bo.Right)) { valueToRetype = (SqlSimpleTypeExpression)bo.Right; } else if(needsRetype(bo.Right, bo.Left)) { valueToRetype = (SqlSimpleTypeExpression)bo.Left; } if(valueToRetype != null) { valueToRetype.SetSqlType(valueToRetype.SqlType.GetNonUnicodeEquivalent()); } } return bo; }
internal override SqlExpression VisitBinaryOperator(SqlBinary bo) { bo.Left = this.VisitExpression(bo.Left); return bo; }
internal SqlExpression TranslateLinkEquals(SqlBinary bo) { SqlLink link1 = bo.Left as SqlLink; SqlLink link2 = bo.Right as SqlLink; if ((link1 != null && link1.Member.IsAssociation && link1.Member.Association.IsForeignKey) || (link2 != null && link2.Member.IsAssociation && link2.Member.Association.IsForeignKey)) { return this.TranslateEquals(bo); } return bo; }
private static bool IsVbCompareStringEqualsValue(SqlBinary bo) { return IsComparison(bo.NodeType) && bo.Left.NodeType == SqlNodeType.MethodCall && bo.Right.NodeType == SqlNodeType.Value && IsVbCompareString((SqlMethodCall)bo.Left); }
private static bool IsCompareToValue(SqlBinary bo) { if(IsComparison(bo.NodeType) && bo.Left.NodeType == SqlNodeType.MethodCall && bo.Right.NodeType == SqlNodeType.Value) { SqlMethodCall call = (SqlMethodCall)bo.Left; return IsCompareToMethod(call) || IsCompareMethod(call); } return false; }
internal override SqlExpression VisitBinaryOperator(SqlBinary bo) { bo = (SqlBinary)base.VisitBinaryOperator(bo); Type leftType = TypeSystem.GetNonNullableType(bo.Left.ClrType); if(leftType == typeof(DateTime) || leftType == typeof(DateTimeOffset)) { return this.TranslateDateTimeBinary(bo); } return bo; }
private SqlExpression TranslateDateTimeBinary(SqlBinary bo) { bool resultNullable = TypeSystem.IsNullableType(bo.ClrType); Type rightType = TypeSystem.GetNonNullableType(bo.Right.ClrType); switch(bo.NodeType) { case SqlNodeType.Sub: if(rightType == typeof(DateTime)) { // if either of the arguments is nullable, set result type to nullable. Type resultType = bo.ClrType; SqlExpression end = bo.Left; SqlExpression start = bo.Right; SqlExpression day = new SqlVariable(typeof(void), null, "DAY", bo.SourceExpression); SqlExpression ms = new SqlVariable(typeof(void), null, "MILLISECOND", bo.SourceExpression); // DATEDIFF(MILLISECONDS,...) does not work for more then 24 days, since result has to fit int. // So compute the number of days first, and then find out the number of milliseconds needed in addition to that. SqlExpression intDays = sql.FunctionCall(typeof(int), "DATEDIFF", new SqlExpression[] { day, start, end }, bo.SourceExpression); SqlExpression startPlusDays = sql.FunctionCall( typeof(DateTime), "DATEADD", new SqlExpression[] { day, intDays, start }, bo.SourceExpression); SqlExpression intMSec = sql.FunctionCall(typeof(int), "DATEDIFF", new SqlExpression[] { ms, startPlusDays, end }, bo.SourceExpression); SqlExpression result = sql.Multiply(sql.Add(sql.Multiply(sql.ConvertToBigint(intDays), 86400000), intMSec), 10000); // 1 millisecond = 10000 ticks return sql.ConvertTo(resultType, result); } if(rightType == typeof(DateTimeOffset)) { Debug.Assert(TypeSystem.GetNonNullableType(bo.Left.ClrType) == typeof(DateTimeOffset)); // if either of the arguments is nullable, set result type to nullable. Type resultType = bo.ClrType; SqlExpression end = bo.Left; SqlExpression start = bo.Right; SqlExpression day = new SqlVariable(typeof(void), null, "DAY", bo.SourceExpression); SqlExpression ms = new SqlVariable(typeof(void), null, "MILLISECOND", bo.SourceExpression); SqlExpression us = new SqlVariable(typeof(void), null, "MICROSECOND", bo.SourceExpression); SqlExpression ns = new SqlVariable(typeof(void), null, "NANOSECOND", bo.SourceExpression); // compute the number of days first, and then find out the number of milliseconds needed in addition to that. SqlExpression intDays = sql.FunctionCall(typeof(int), "DATEDIFF", new SqlExpression[] { day, start, end }, bo.SourceExpression); SqlExpression startPlusDays = sql.FunctionCall(typeof(DateTimeOffset), "DATEADD", new SqlExpression[] { day, intDays, start }, bo.SourceExpression); SqlExpression intMSec = sql.FunctionCall(typeof(int), "DATEDIFF", new SqlExpression[] { ms, startPlusDays, end }, bo.SourceExpression); SqlExpression startPlusDaysPlusMsec = sql.FunctionCall(typeof(DateTimeOffset), "DATEADD", new SqlExpression[] { ms, intMSec, startPlusDays }, bo.SourceExpression); SqlExpression intUSec = sql.FunctionCall(typeof(int), "DATEDIFF", new SqlExpression[] { us, startPlusDaysPlusMsec, end }, bo.SourceExpression); SqlExpression startPlusDaysPlusMsecPlusUSec = sql.FunctionCall(typeof(DateTimeOffset), "DATEADD", new SqlExpression[] { us, intUSec, startPlusDaysPlusMsec }, bo.SourceExpression); SqlExpression intNSec = sql.FunctionCall(typeof(int), "DATEDIFF", new SqlExpression[] { ns, startPlusDaysPlusMsecPlusUSec, end }, bo.SourceExpression); SqlExpression startPlusDaysPlusMsecPlusUSecPlusNSec = sql.FunctionCall(typeof(DateTimeOffset), "DATEADD", new SqlExpression[] { ns, intNSec, startPlusDaysPlusMsecPlusUSec }, bo.SourceExpression); SqlExpression result = sql.Add( sql.Divide(intNSec, 100), sql.Multiply(intUSec, 10), sql.Multiply( sql.Add( sql.Multiply(sql.ConvertToBigint(intDays), 86400000), intMSec ), 10000) ); return sql.ConvertTo(resultType, result); } else if(rightType == typeof(TimeSpan)) { SqlExpression right = bo.Right; if(sql.IsTimeType(bo.Right)) { SqlExpression ns = sql.FunctionCallDatePart("NANOSECOND", right); SqlExpression ss = sql.FunctionCallDatePart("SECOND", right); SqlExpression mi = sql.FunctionCallDatePart("MINUTE", right); SqlExpression hh = sql.FunctionCallDatePart("HOUR", right); right = sql.Add( sql.Divide(ns, 100), sql.Multiply( sql.Add( sql.Multiply(sql.ConvertToBigint(hh), 3600000), sql.Multiply(sql.ConvertToBigint(mi), 60000), sql.Multiply(sql.ConvertToBigint(ss), 1000) ), 10000 // 1 millisecond = 10000 ticks ) ); } return TypeSystem.GetNonNullableType(bo.Left.ClrType) == typeof(DateTimeOffset) ? CreateDateTimeOffsetFromDateAndTicks( bo.Left, sql.Unary(SqlNodeType.Negate, right, bo.SourceExpression), bo.SourceExpression, resultNullable ) : CreateDateTimeFromDateAndTicks( bo.Left, sql.Unary(SqlNodeType.Negate, right, bo.SourceExpression), bo.SourceExpression, resultNullable ); } break; case SqlNodeType.Add: if(rightType == typeof(TimeSpan)) { if(sql.IsTimeType(bo.Right)) { return sql.AddTimeSpan(bo.Left, bo.Right, resultNullable); } else if(TypeSystem.GetNonNullableType(bo.Left.ClrType) == typeof(DateTimeOffset)) { return CreateDateTimeOffsetFromDateAndTicks(bo.Left, bo.Right, bo.SourceExpression, resultNullable); } return CreateDateTimeFromDateAndTicks(bo.Left, bo.Right, bo.SourceExpression, resultNullable); } break; } return bo; }
internal override SqlExpression VisitBinaryOperator(SqlBinary bo) { switch(bo.NodeType) { case SqlNodeType.Coalesce: _commandStringBuilder.Append("COALESCE("); this.Visit(bo.Left); _commandStringBuilder.Append(","); this.Visit(bo.Right); _commandStringBuilder.Append(")"); break; default: this.VisitWithParens(bo.Left, bo); _commandStringBuilder.Append(" "); _commandStringBuilder.Append(GetOperator(bo.NodeType)); _commandStringBuilder.Append(" "); this.VisitWithParens(bo.Right, bo); break; } return bo; }
internal override SqlExpression VisitBinaryOperator(SqlBinary bo) { // Below we translate comparisons with constant NULL to either IS NULL or IS NOT NULL. // We only want to do this if the type of the binary expression is not nullable. switch (bo.NodeType) { case SqlNodeType.EQ: case SqlNodeType.EQ2V: if (this.IsConstNull(bo.Left) && !TypeSystem.IsNullableType(bo.ClrType)) { return this.VisitUnaryOperator(this.sql.Unary(SqlNodeType.IsNull, bo.Right, bo.SourceExpression)); } else if (this.IsConstNull(bo.Right) && !TypeSystem.IsNullableType(bo.ClrType)) { return this.VisitUnaryOperator(this.sql.Unary(SqlNodeType.IsNull, bo.Left, bo.SourceExpression)); } break; case SqlNodeType.NE: case SqlNodeType.NE2V: if (this.IsConstNull(bo.Left) && !TypeSystem.IsNullableType(bo.ClrType)) { return this.VisitUnaryOperator(this.sql.Unary(SqlNodeType.IsNotNull, bo.Right, bo.SourceExpression)); } else if (this.IsConstNull(bo.Right) && !TypeSystem.IsNullableType(bo.ClrType)) { return this.VisitUnaryOperator(this.sql.Unary(SqlNodeType.IsNotNull, bo.Left, bo.SourceExpression)); } break; } bo.Left = this.VisitExpression(bo.Left); bo.Right = this.VisitExpression(bo.Right); switch (bo.NodeType) { case SqlNodeType.EQ: case SqlNodeType.EQ2V: case SqlNodeType.NE: case SqlNodeType.NE2V: { SqlValue vLeft = bo.Left as SqlValue; SqlValue vRight = bo.Right as SqlValue; bool leftIsBool = vLeft!=null && vLeft.Value is bool; bool rightIsBool = vRight!=null && vRight.Value is bool; if (leftIsBool || rightIsBool) { bool equal = bo.NodeType != SqlNodeType.NE && bo.NodeType != SqlNodeType.NE2V; bool isTwoValue = bo.NodeType == SqlNodeType.EQ2V || bo.NodeType == SqlNodeType.NE2V; SqlNodeType negator = isTwoValue ? SqlNodeType.Not2V : SqlNodeType.Not; if (leftIsBool && !rightIsBool) { bool value = (bool)vLeft.Value; if (value^equal) { return VisitUnaryOperator(new SqlUnary(negator, bo.ClrType, bo.SqlType, sql.DoNotVisitExpression(bo.Right), bo.SourceExpression)); } if (bo.Right.ClrType==typeof(bool)) { // If the other side is nullable bool then this expression is already a reasonable way to handle three-values return bo.Right; } } else if (!leftIsBool && rightIsBool) { bool value = (bool)vRight.Value; if (value^equal) { return VisitUnaryOperator(new SqlUnary(negator, bo.ClrType, bo.SqlType, sql.DoNotVisitExpression(bo.Left), bo.SourceExpression)); } if (bo.Left.ClrType==typeof(bool)) { // If the other side is nullable bool then this expression is already a reasonable way to handle three-values return bo.Left; } } else if (leftIsBool && rightIsBool) { // Here, both left and right are bools. bool leftValue = (bool)vLeft.Value; bool rightValue = (bool)vRight.Value; if (equal) { return sql.ValueFromObject(leftValue==rightValue, false, bo.SourceExpression); } else { return sql.ValueFromObject(leftValue!=rightValue, false, bo.SourceExpression); } } } break; } } switch (bo.NodeType) { case SqlNodeType.And: { SqlValue vLeft = bo.Left as SqlValue; SqlValue vRight = bo.Right as SqlValue; if (vLeft != null && vRight == null) { if (vLeft.Value != null && (bool)vLeft.Value) { return bo.Right; } return sql.ValueFromObject(false, false, bo.SourceExpression); } else if (vLeft == null && vRight != null) { if (vRight.Value != null && (bool)vRight.Value) { return bo.Left; } return sql.ValueFromObject(false, false, bo.SourceExpression); } else if (vLeft != null && vRight != null) { return sql.ValueFromObject((bool)(vLeft.Value ?? false) && (bool)(vRight.Value ?? false), false, bo.SourceExpression); } break; } case SqlNodeType.Or: { SqlValue vLeft = bo.Left as SqlValue; SqlValue vRight = bo.Right as SqlValue; if (vLeft != null && vRight == null) { if (vLeft.Value != null && !(bool)vLeft.Value) { return bo.Right; } return sql.ValueFromObject(true, false, bo.SourceExpression); } else if (vLeft == null && vRight != null) { if (vRight.Value != null && !(bool)vRight.Value) { return bo.Left; } return sql.ValueFromObject(true, false, bo.SourceExpression); } else if (vLeft != null && vRight != null) { return sql.ValueFromObject((bool)(vLeft.Value ?? false) || (bool)(vRight.Value ?? false), false, bo.SourceExpression); } break; } case SqlNodeType.EQ: case SqlNodeType.NE: case SqlNodeType.EQ2V: case SqlNodeType.NE2V: { SqlExpression translated = this.translator.TranslateLinkEquals(bo); if (translated != bo) { return this.VisitExpression(translated); } break; } } bo.Left = this.ConvertToFetchedExpression(bo.Left); bo.Right = this.ConvertToFetchedExpression(bo.Right); switch (bo.NodeType) { case SqlNodeType.EQ: case SqlNodeType.NE: case SqlNodeType.EQ2V: case SqlNodeType.NE2V: SqlExpression translated = this.translator.TranslateEquals(bo); if (translated != bo) { return this.VisitExpression(translated); } // Special handling for typeof(Type) nodes. Reduce to a static check if possible; // strip SqlDiscriminatedType if possible; if (typeof(Type).IsAssignableFrom(bo.Left.ClrType)) { SqlExpression left = TypeSource.GetTypeSource(bo.Left); SqlExpression right = TypeSource.GetTypeSource(bo.Right); MetaType[] leftPossibleTypes = GetPossibleTypes(left); MetaType[] rightPossibleTypes = GetPossibleTypes(right); bool someMatch = false; for (int i = 0; i < leftPossibleTypes.Length; ++i) { for (int j = 0; j < rightPossibleTypes.Length; ++j) { if (leftPossibleTypes[i] == rightPossibleTypes[j]) { someMatch = true; break; } } } // Is a match possible? if (!someMatch) { // No match is possible return this.VisitExpression(sql.ValueFromObject(bo.NodeType == SqlNodeType.NE, false, bo.SourceExpression)); } // Is the match known statically? if (leftPossibleTypes.Length == 1 && rightPossibleTypes.Length == 1) { // Yes, the match is statically known. return this.VisitExpression(sql.ValueFromObject( (bo.NodeType == SqlNodeType.EQ) == (leftPossibleTypes[0] == rightPossibleTypes[0]), false, bo.SourceExpression)); } // If both sides are discriminated types, then create a comparison of discriminators instead; SqlDiscriminatedType leftDt = bo.Left as SqlDiscriminatedType; SqlDiscriminatedType rightDt = bo.Right as SqlDiscriminatedType; if (leftDt != null && rightDt != null) { return this.VisitExpression(sql.Binary(bo.NodeType, leftDt.Discriminator, rightDt.Discriminator)); } } // can only compare sql scalars if (TypeSystem.IsSequenceType(bo.Left.ClrType)) { throw Error.ComparisonNotSupportedForType(bo.Left.ClrType); } if (TypeSystem.IsSequenceType(bo.Right.ClrType)) { throw Error.ComparisonNotSupportedForType(bo.Right.ClrType); } break; } return bo; }
internal virtual SqlExpression VisitBinaryOperator(SqlBinary bo) { bo.Left = this.VisitExpression(bo.Left); bo.Right = this.VisitExpression(bo.Right); return bo; }
internal SqlExpression TranslateEquals(SqlBinary expr) { System.Diagnostics.Debug.Assert( expr.NodeType == SqlNodeType.EQ || expr.NodeType == SqlNodeType.NE || expr.NodeType == SqlNodeType.EQ2V || expr.NodeType == SqlNodeType.NE2V); SqlExpression eLeft = expr.Left; SqlExpression eRight = expr.Right; if (eRight.NodeType == SqlNodeType.Element) { SqlSubSelect sub = (SqlSubSelect)eRight; SqlAlias alias = new SqlAlias(sub.Select); SqlAliasRef aref = new SqlAliasRef(alias); SqlSelect select = new SqlSelect(aref, alias, expr.SourceExpression); select.Where = sql.Binary(expr.NodeType, sql.DoNotVisitExpression(eLeft), aref); return sql.SubSelect(SqlNodeType.Exists, select); } else if (eLeft.NodeType == SqlNodeType.Element) { SqlSubSelect sub = (SqlSubSelect)eLeft; SqlAlias alias = new SqlAlias(sub.Select); SqlAliasRef aref = new SqlAliasRef(alias); SqlSelect select = new SqlSelect(aref, alias, expr.SourceExpression); select.Where = sql.Binary(expr.NodeType, sql.DoNotVisitExpression(eRight), aref); return sql.SubSelect(SqlNodeType.Exists, select); } MetaType mtLeft = TypeSource.GetSourceMetaType(eLeft, this.services.Model); MetaType mtRight = TypeSource.GetSourceMetaType(eRight, this.services.Model); if (eLeft.NodeType == SqlNodeType.TypeCase) { eLeft = BestIdentityNode((SqlTypeCase)eLeft); } if (eRight.NodeType == SqlNodeType.TypeCase) { eRight = BestIdentityNode((SqlTypeCase)eRight); } if (mtLeft.IsEntity && mtRight.IsEntity && mtLeft.Table != mtRight.Table) { throw Error.CannotCompareItemsAssociatedWithDifferentTable(); } // do simple or no translation for non-structural types if (!mtLeft.IsEntity && !mtRight.IsEntity && (eLeft.NodeType != SqlNodeType.New || eLeft.SqlType.CanBeColumn) && (eRight.NodeType != SqlNodeType.New || eRight.SqlType.CanBeColumn)) { if (expr.NodeType == SqlNodeType.EQ2V || expr.NodeType == SqlNodeType.NE2V) { return this.TranslateEqualsOp(expr.NodeType, sql.DoNotVisitExpression(expr.Left), sql.DoNotVisitExpression(expr.Right), false); } return expr; } // If the two types are not comparable, we return the predicate "1=0". if ((mtLeft != mtRight) && (mtLeft.InheritanceRoot != mtRight.InheritanceRoot)) { return sql.Binary(SqlNodeType.EQ, sql.ValueFromObject(0,expr.SourceExpression), sql.ValueFromObject(1,expr.SourceExpression)); } List<SqlExpression> exprs1; List<SqlExpression> exprs2; SqlLink link1 = eLeft as SqlLink; if (link1 != null && link1.Member.IsAssociation && link1.Member.Association.IsForeignKey) { exprs1 = link1.KeyExpressions; } else { exprs1 = this.GetIdentityExpressions(mtLeft, sql.DoNotVisitExpression(eLeft)); } SqlLink link2 = eRight as SqlLink; if (link2 != null && link2.Member.IsAssociation && link2.Member.Association.IsForeignKey) { exprs2 = link2.KeyExpressions; } else { exprs2 = this.GetIdentityExpressions(mtRight, sql.DoNotVisitExpression(eRight)); } System.Diagnostics.Debug.Assert(exprs1.Count > 0); System.Diagnostics.Debug.Assert(exprs2.Count > 0); System.Diagnostics.Debug.Assert(exprs1.Count == exprs2.Count); SqlExpression exp = null; SqlNodeType eqKind = (expr.NodeType == SqlNodeType.EQ2V || expr.NodeType == SqlNodeType.NE2V) ? SqlNodeType.EQ2V : SqlNodeType.EQ; for (int i = 0, n = exprs1.Count; i < n; i++) { SqlExpression eq = this.TranslateEqualsOp(eqKind, exprs1[i], exprs2[i], !mtLeft.IsEntity); if (exp == null) { exp = eq; } else { exp = sql.Binary(SqlNodeType.And, exp, eq); } } if (expr.NodeType == SqlNodeType.NE || expr.NodeType == SqlNodeType.NE2V) { exp = sql.Unary(SqlNodeType.Not, exp, exp.SourceExpression); } return exp; }