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;
		}
示例#5
0
		/// <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);
		}
示例#7
0
		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;
		}
示例#9
0
 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;
		}
示例#16
0
 internal virtual SqlExpression VisitBinaryOperator(SqlBinary bo) {
     bo.Left = this.VisitExpression(bo.Left);
     bo.Right = this.VisitExpression(bo.Right);
     return bo;
 }
示例#17
0
        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;
        }