Пример #1
0
		private SqlNode ConvertDateToDateTime2(SqlExpression expr)
		{
			SqlExpression datetime2 = new SqlVariable(expr.ClrType, expr.SqlType, "DATETIME2", expr.SourceExpression);
			return _nodeFactory.FunctionCall(typeof(DateTime), "CONVERT", new SqlExpression[2] { datetime2, expr }, expr.SourceExpression);
		}
Пример #2
0
 internal virtual SqlExpression VisitVariable(SqlVariable v) {
     return v;
 }
Пример #3
0
		internal override SqlExpression VisitVariable(SqlVariable v)
		{
			return v;
		}
Пример #4
0
		internal override SqlExpression VisitVariable(SqlVariable v)
		{
			_commandStringBuilder.Append(v.Name);
			return v;
		}
			private SqlExpression TranslateNewDateTimeOffset(SqlNew sox)
			{
				Expression source = sox.SourceExpression;
				if(sox.ClrType == typeof(DateTimeOffset))
				{
					// DateTimeOffset(DateTime dateTime)
					// --> CONVERT(DATETIMEOFFSET, @dateTime)
					if(sox.Args.Count == 1 && sox.Args[0].ClrType == typeof(DateTime))
					{
						return sql.FunctionCall(typeof(DateTimeOffset), "TODATETIMEOFFSET",
												new SqlExpression[2] { sox.Args[0], sql.ValueFromObject(0, false, source) },
												source);
					}
					// DateTimeOffset(DateTime dateTime, TimeSpan timeSpan)
					// --> DATEADD(DATETIMEOFFSET, @dateTimePart)
					if(sox.Args.Count == 2 && sox.Args[0].ClrType == typeof(DateTime) && sox.Args[1].ClrType == typeof(TimeSpan))
					{
						return sql.FunctionCall(typeof(DateTimeOffset), "TODATETIMEOFFSET",
												new SqlExpression[2] 
                                                { 
                                                    sox.Args[0], 
                                                    sql.ConvertToInt(sql.ConvertToBigint(sql.Divide(sql.ConvertTimeToDouble(sox.Args[1]), TimeSpan.TicksPerMinute)))
                                                },
												source);
					}
					// DateTimeOffset(year, month, day, hour, minute, second, [millisecond,] timeSpan) 
					//
					if(sox.Args.Count >= 7 &&
						sox.Args[0].ClrType == typeof(int) && sox.Args[1].ClrType == typeof(int) && sox.Args[2].ClrType == typeof(int) &&
						sox.Args[3].ClrType == typeof(int) && sox.Args[4].ClrType == typeof(int) && sox.Args[5].ClrType == typeof(int))
					{

						SqlExpression char2 = sql.FunctionCall(typeof(void), "NCHAR", new SqlExpression[1] { sql.ValueFromObject(2, false, source) }, source);
						SqlExpression char4 = sql.FunctionCall(typeof(void), "NCHAR", new SqlExpression[1] { sql.ValueFromObject(4, false, source) }, source);
						SqlExpression char5 = sql.FunctionCall(typeof(void), "NCHAR", new SqlExpression[1] { sql.ValueFromObject(5, false, source) }, source);

						// add leading zeros to year by RIGHT(CONVERT(NCHAR(5),10000+@ms),4) 
						SqlExpression yyRaw = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] {char5,
                                       sql.Add(sql.ValueFromObject(10000, false, source),sox.Args[0])}, source);
						SqlExpression year = sql.FunctionCall(typeof(string), "RIGHT", new SqlExpression[2] { yyRaw, sql.ValueFromObject(4, false, source) }, source);

						SqlExpression month = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char2, sox.Args[1] }, source);
						SqlExpression day = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char2, sox.Args[2] }, source);

						SqlExpression hour = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char2, sox.Args[3] }, source);
						SqlExpression minute = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char2, sox.Args[4] }, source);
						SqlExpression second = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char2, sox.Args[5] }, source);
						SqlExpression date = sql.Concat(year, sql.ValueFromObject("-", false, source), month, sql.ValueFromObject("-", false, source), day);
						SqlExpression time = sql.Concat(hour, sql.ValueFromObject(":", false, source), minute, sql.ValueFromObject(":", false, source), second);

						SqlExpression datetimeoffset = new SqlVariable(typeof(void), null, "DATETIMEOFFSET", source);
						SqlExpression result, dateAndTime;
						int timeSpanIndex;

						if(sox.Args.Count == 7 && sox.Args[6].ClrType == typeof(TimeSpan))
						{
							timeSpanIndex = 6;
							dateAndTime = sql.Concat(date, sql.ValueFromObject(' ', false, source), time);
							result = sql.FunctionCall(typeof(DateTimeOffset), "CONVERT", new SqlExpression[3] { datetimeoffset, dateAndTime, sql.ValueFromObject(120, false, source) }, source);
						}
						else if(sox.Args.Count == 8 && sox.Args[6].ClrType == typeof(int) && sox.Args[7].ClrType == typeof(TimeSpan))
						{
							timeSpanIndex = 7;
							// add leading zeros to milliseconds by RIGHT(CONVERT(NCHAR(4),1000+@ms),3) 
							SqlExpression msRaw = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] {char4,
                                       sql.Add(sql.ValueFromObject(1000, false, source),sox.Args[6])}, source);
							SqlExpression ms = sql.FunctionCall(typeof(string), "RIGHT", new SqlExpression[2] { msRaw, sql.ValueFromObject(3, false, source) }, source);
							dateAndTime = sql.Concat(date, sql.ValueFromObject(' ', false, source), time, sql.ValueFromObject('.', false, source), ms);
							result = sql.FunctionCall(typeof(DateTimeOffset), "CONVERT", new SqlExpression[3] { datetimeoffset, dateAndTime, sql.ValueFromObject(121, false, source) }, source);
						}
						else
						{
							throw Error.UnsupportedDateTimeOffsetConstructorForm();
						}

						return sql.FunctionCall(typeof(DateTimeOffset), "TODATETIMEOFFSET",
												new SqlExpression[2] 
                                                { 
                                                    result, 
                                                    sql.ConvertToInt(sql.ConvertToBigint(sql.Divide(sql.ConvertTimeToDouble(sox.Args[timeSpanIndex]), TimeSpan.TicksPerMinute)))
                                                },
												source);
					}
				}
				throw Error.UnsupportedDateTimeOffsetConstructorForm();
			}
			private SqlExpression TranslateNewDateTime(SqlNew sox)
			{
				Expression source = sox.SourceExpression;

				// DateTime(int year, int month, int day) 
				// --> CONVERT(DATETIME, CONVERT(nchar(2),@month) + '/' + CONVERT(nchar(2),@day) + '/' + CONVERT(nchar(4),@year),101)
				if(sox.ClrType == typeof(DateTime) && sox.Args.Count >= 3 &&
					sox.Args[0].ClrType == typeof(int) && sox.Args[1].ClrType == typeof(int) && sox.Args[2].ClrType == typeof(int))
				{
					SqlExpression char2 = sql.FunctionCall(typeof(void), "NCHAR", new SqlExpression[1] { sql.ValueFromObject(2, false, source) }, source);
					SqlExpression char4 = sql.FunctionCall(typeof(void), "NCHAR", new SqlExpression[1] { sql.ValueFromObject(4, false, source) }, source);
					SqlExpression year = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char4, sox.Args[0] }, source);
					SqlExpression month = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char2, sox.Args[1] }, source);
					SqlExpression day = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char2, sox.Args[2] }, source);
					SqlExpression datetime = new SqlVariable(typeof(void), null, "DATETIME", source);
					if(sox.Args.Count == 3)
					{
						SqlExpression date = sql.Concat(month, sql.ValueFromObject("/", false, source), day, sql.ValueFromObject("/", false, source), year);
						return sql.FunctionCall(typeof(DateTime), "CONVERT", new SqlExpression[3] { datetime, date, sql.ValueFromObject(101, false, source) }, source);
					}
					if(sox.Args.Count >= 6 &&
						sox.Args[3].ClrType == typeof(int) && sox.Args[4].ClrType == typeof(int) && sox.Args[5].ClrType == typeof(int))
					{
						// DateTime(year, month, day, hour, minute, second ) 
						// --> CONVERT(DATETIME, CONVERT(nchar(2),@month) + '-' + CONVERT(nchar(2),@day) + '-' + CONVERT(nchar(4),@year) +
						//                 ' ' + CONVERT(nchar(2),@hour) + ':' + CONVERT(nchar(2),@minute) + ':' + CONVERT(nchar(2),@second)  ,120)
						SqlExpression hour = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char2, sox.Args[3] }, source);
						SqlExpression minute = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char2, sox.Args[4] }, source);
						SqlExpression second = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] { char2, sox.Args[5] }, source);
						SqlExpression date = sql.Concat(year, sql.ValueFromObject("-", false, source), month, sql.ValueFromObject("-", false, source), day);
						SqlExpression time = sql.Concat(hour, sql.ValueFromObject(":", false, source), minute, sql.ValueFromObject(":", false, source), second);
						SqlExpression dateAndTime = sql.Concat(date, sql.ValueFromObject(' ', false, source), time);
						if(sox.Args.Count == 6)
						{
							return sql.FunctionCall(typeof(DateTime), "CONVERT", new SqlExpression[3] { datetime, dateAndTime, sql.ValueFromObject(120, false, source) }, source);
						}
						if((sox.Args.Count == 7) && (sox.Args[6].ClrType == typeof(int)))
						{
							// DateTime(year, month, day, hour, minute, second, millisecond ) 
							// add leading zeros to milliseconds by RIGHT(CONVERT(NCHAR(4),1000+@ms),3) 
							SqlExpression msRaw = sql.FunctionCall(typeof(string), "CONVERT", new SqlExpression[2] {char4,
                                       sql.Add(sql.ValueFromObject(1000, false, source),sox.Args[6])}, source);
							SqlExpression ms;
							if(this.providerMode == SqlServerProviderMode.SqlCE)
							{
								//SqlCE doesn't have "RIGHT", so need to use "SUBSTRING"
								SqlExpression len = sql.FunctionCall(typeof(int), "LEN", new SqlExpression[1] { msRaw }, source);
								SqlExpression startIndex = sql.Binary(SqlNodeType.Sub, len, sql.ValueFromObject(2, false, source));
								ms = sql.FunctionCall(typeof(string), "SUBSTRING", new SqlExpression[3] { msRaw, startIndex, sql.ValueFromObject(3, false, source) }, source);
							}
							else
							{
								ms = sql.FunctionCall(typeof(string), "RIGHT", new SqlExpression[2] { msRaw, sql.ValueFromObject(3, false, source) }, source);
							}
							dateAndTime = sql.Concat(dateAndTime, sql.ValueFromObject('.', false, source), ms);
							return sql.FunctionCall(typeof(DateTime), "CONVERT", new SqlExpression[3] { datetime, dateAndTime, sql.ValueFromObject(121, false, source) }, source);
						}
					}
				}
				throw Error.UnsupportedDateTimeConstructorForm();
			}
			internal override SqlNode VisitMember(SqlMember m)
			{
				SqlExpression exp = this.VisitExpression(m.Expression);
				MemberInfo member = m.Member;
				Expression source = m.SourceExpression;

				Type baseClrTypeOfExpr = TypeSystem.GetNonNullableType(exp.ClrType);
				if(baseClrTypeOfExpr == typeof(string) && member.Name == "Length")
				{
					// This gives a different result than .Net would if the string ends in spaces.
					// We decided not to fix this up (e.g. LEN(@s+'#') - 1) since it would incur a performance hit and 
					// people may actually expect that it translates to the SQL LEN function.
					return sql.FunctionCallStringLength(exp);
				}
				else if(baseClrTypeOfExpr == typeof(Binary) && member.Name == "Length")
				{
					return sql.FunctionCallDataLength(exp);
				}
				else if(baseClrTypeOfExpr == typeof(DateTime) || baseClrTypeOfExpr == typeof(DateTimeOffset))
				{
					string datePart = GetDatePart(member.Name);
					if(datePart != null)
					{
						return sql.FunctionCallDatePart(datePart, exp);
					}
					else if(member.Name == "Date")
					{
						if(this.providerMode == SqlServerProviderMode.Sql2008)
						{
							SqlExpression date = new SqlVariable(typeof(void), null, "DATE", source);
							return sql.FunctionCall(typeof(DateTime), "CONVERT", new SqlExpression[2] { date, exp }, source);
						}
						// date --> dateadd(hh, -(datepart(hh, @date)), 
						//          dateadd(mi, -(datepart(mi, @date)), 
						//          dateadd(ss, -(datepart(ss, @date)), 
						//          dateadd(ms, -(datepart(ms, @date)), 
						//          @date))))

						SqlExpression ms = sql.FunctionCallDatePart("MILLISECOND", exp);
						SqlExpression ss = sql.FunctionCallDatePart("SECOND", exp);
						SqlExpression mi = sql.FunctionCallDatePart("MINUTE", exp);
						SqlExpression hh = sql.FunctionCallDatePart("HOUR", exp);

						SqlExpression result = exp;

						result = sql.FunctionCallDateAdd("MILLISECOND", sql.Unary(SqlNodeType.Negate, ms), result);
						result = sql.FunctionCallDateAdd("SECOND", sql.Unary(SqlNodeType.Negate, ss), result);
						result = sql.FunctionCallDateAdd("MINUTE", sql.Unary(SqlNodeType.Negate, mi), result);
						result = sql.FunctionCallDateAdd("HOUR", sql.Unary(SqlNodeType.Negate, hh), result);

						return result;
					}
					else if(member.Name == "DateTime")
					{
						Debug.Assert(baseClrTypeOfExpr == typeof(DateTimeOffset), "'DateTime' property supported only for instances of DateTimeOffset.");
						SqlExpression datetime = new SqlVariable(typeof(void), null, "DATETIME", source);
						return sql.FunctionCall(typeof(DateTime), "CONVERT", new SqlExpression[2] { datetime, exp }, source);
					}
					else if(member.Name == "TimeOfDay")
					{
						SqlExpression hours = sql.FunctionCallDatePart("HOUR", exp);
						SqlExpression minutes = sql.FunctionCallDatePart("MINUTE", exp);
						SqlExpression seconds = sql.FunctionCallDatePart("SECOND", exp);
						SqlExpression milliseconds = sql.FunctionCallDatePart("MILLISECOND", exp);

						SqlExpression ticksFromHour = sql.Multiply(sql.ConvertToBigint(hours), TimeSpan.TicksPerHour);
						SqlExpression ticksFromMinutes = sql.Multiply(sql.ConvertToBigint(minutes), TimeSpan.TicksPerMinute);
						SqlExpression ticksFromSeconds = sql.Multiply(sql.ConvertToBigint(seconds), TimeSpan.TicksPerSecond);
						SqlExpression ticksFromMs = sql.Multiply(sql.ConvertToBigint(milliseconds), TimeSpan.TicksPerMillisecond);
						return sql.ConvertTo(typeof(TimeSpan), sql.Add(ticksFromHour, ticksFromMinutes, ticksFromSeconds, ticksFromMs));
					}
					else if(member.Name == "DayOfWeek")
					{
						//(DATEPART(dw,@date) + @@Datefirst + 6) % 7 to make it independent from SQL settings
						SqlExpression sqlDay = sql.FunctionCallDatePart("dw", exp);

						// 
						// .DayOfWeek returns a System.DayOfWeek, so ConvertTo that enum.
						return sql.ConvertTo(typeof(DayOfWeek),
								sql.Mod(
								  sql.Add(sqlDay,
									 sql.Add(new SqlVariable(typeof(int), sql.Default(typeof(int)), "@@DATEFIRST", source), 6)
								  )
								, 7));
					}
				}
				else if(baseClrTypeOfExpr == typeof(System.TimeSpan))
				{
					switch(member.Name)
					{
						case "Ticks":
							if(sql.IsTimeType(exp))
							{
								return this.sql.Divide(
											sql.ConvertToBigint(
												sql.Add(
													this.sql.Multiply(sql.ConvertToBigint(sql.FunctionCallDatePart("HOUR", exp)), 3600000000000),
													this.sql.Multiply(sql.ConvertToBigint(sql.FunctionCallDatePart("MINUTE", exp)), 60000000000),
													this.sql.Multiply(sql.ConvertToBigint(sql.FunctionCallDatePart("SECOND", exp)), 1000000000),
													sql.FunctionCallDatePart("NANOSECOND", exp))
												),
											100
									);
							}
							return sql.ConvertToBigint(exp);
						case "TotalMilliseconds":
							if(sql.IsTimeType(exp))
							{
								return this.sql.Add(
											this.sql.Multiply(sql.FunctionCallDatePart("HOUR", exp), 3600000),
											this.sql.Multiply(sql.FunctionCallDatePart("MINUTE", exp), 60000),
											this.sql.Multiply(sql.FunctionCallDatePart("SECOND", exp), 1000),
											this.sql.Divide(sql.ConvertToDouble(sql.ConvertToBigint(sql.FunctionCallDatePart("NANOSECOND", exp))), 1000000)
										);
							}
							return sql.Divide(sql.ConvertToDouble(exp), TimeSpan.TicksPerMillisecond);
						case "TotalSeconds":
							if(sql.IsTimeType(exp))
							{
								return this.sql.Add(
											this.sql.Multiply(sql.FunctionCallDatePart("HOUR", exp), 3600),
											this.sql.Multiply(sql.FunctionCallDatePart("MINUTE", exp), 60),
											this.sql.FunctionCallDatePart("SECOND", exp),
											this.sql.Divide(sql.ConvertToDouble(sql.ConvertToBigint(sql.FunctionCallDatePart("NANOSECOND", exp))), 1000000000)
										);
							}
							return sql.Divide(sql.ConvertToDouble(exp), TimeSpan.TicksPerSecond);
						case "TotalMinutes":
							if(sql.IsTimeType(exp))
							{
								return this.sql.Add(
											this.sql.Multiply(sql.FunctionCallDatePart("HOUR", exp), 60),
											this.sql.FunctionCallDatePart("MINUTE", exp),
											this.sql.Divide(sql.ConvertToDouble(sql.FunctionCallDatePart("SECOND", exp)), 60),
											this.sql.Divide(sql.ConvertToDouble(sql.ConvertToBigint(sql.FunctionCallDatePart("NANOSECOND", exp))), 60000000000)
										);
							}
							return sql.Divide(sql.ConvertToDouble(exp), TimeSpan.TicksPerMinute);
						case "TotalHours":
							if(sql.IsTimeType(exp))
							{
								return this.sql.Add(
											this.sql.FunctionCallDatePart("HOUR", exp),
											this.sql.Divide(sql.ConvertToDouble(sql.FunctionCallDatePart("MINUTE", exp)), 60),
											this.sql.Divide(sql.ConvertToDouble(sql.FunctionCallDatePart("SECOND", exp)), 3600),
											this.sql.Divide(sql.ConvertToDouble(sql.ConvertToBigint(sql.FunctionCallDatePart("NANOSECOND", exp))), 3600000000000)
										);
							}
							return sql.Divide(sql.ConvertToDouble(exp), TimeSpan.TicksPerHour);
						case "TotalDays":
							if(sql.IsTimeType(exp))
							{
								return this.sql.Divide(
											this.sql.Add(
												this.sql.FunctionCallDatePart("HOUR", exp),
												this.sql.Divide(sql.ConvertToDouble(sql.FunctionCallDatePart("MINUTE", exp)), 60),
												this.sql.Divide(sql.ConvertToDouble(sql.FunctionCallDatePart("SECOND", exp)), 3600),
												this.sql.Divide(sql.ConvertToDouble(sql.ConvertToBigint(sql.FunctionCallDatePart("NANOSECOND", exp))), 3600000000000)),
											24
										);
							}
							return sql.Divide(sql.ConvertToDouble(exp), TimeSpan.TicksPerDay);
						case "Milliseconds":
							if(sql.IsTimeType(exp))
							{
								return this.sql.FunctionCallDatePart("MILLISECOND", exp);
							}
							return sql.ConvertToInt(sql.Mod(sql.ConvertToBigint(sql.Divide(exp, TimeSpan.TicksPerMillisecond)), 1000));
						case "Seconds":
							if(sql.IsTimeType(exp))
							{
								return this.sql.FunctionCallDatePart("SECOND", exp);
							}
							return sql.ConvertToInt(sql.Mod(sql.ConvertToBigint(sql.Divide(exp, TimeSpan.TicksPerSecond)), 60));
						case "Minutes":
							if(sql.IsTimeType(exp))
							{
								return this.sql.FunctionCallDatePart("MINUTE", exp);
							}
							return sql.ConvertToInt(sql.Mod(sql.ConvertToBigint(sql.Divide(exp, TimeSpan.TicksPerMinute)), 60));
						case "Hours":
							if(sql.IsTimeType(exp))
							{
								return this.sql.FunctionCallDatePart("HOUR", exp);
							}
							return sql.ConvertToInt(sql.Mod(sql.ConvertToBigint(sql.Divide(exp, TimeSpan.TicksPerHour)), 24));
						case "Days":
							if(sql.IsTimeType(exp))
							{
								return this.sql.ValueFromObject(0, false, exp.SourceExpression);
							}
							return sql.ConvertToInt(sql.Divide(exp, TimeSpan.TicksPerDay));
						default:
							throw Error.MemberCannotBeTranslated(member.DeclaringType, member.Name);
					}
				}
				throw Error.MemberCannotBeTranslated(member.DeclaringType, member.Name);
			}
			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;
			}
			private SqlExpression TranslateSqlMethodsMethod(SqlMethodCall mc)
			{
				Expression source = mc.SourceExpression;
				SqlExpression returnValue = null;
				string name = mc.Method.Name;
				if(name.StartsWith("DateDiff", StringComparison.Ordinal) && mc.Arguments.Count == 2)
				{
					foreach(string datePart in dateParts)
					{
						if(mc.Method.Name == "DateDiff" + datePart)
						{
							SqlExpression start = mc.Arguments[0];
							SqlExpression end = mc.Arguments[1];
							SqlExpression unit = new SqlVariable(typeof(void), null, datePart, source);
							return sql.FunctionCall(typeof(int), "DATEDIFF",
													new SqlExpression[] { unit, start, end }, source);
						}
					}
				}
				else if(name == "Like")
				{
					if(mc.Arguments.Count == 2)
					{
						return sql.Like(mc.Arguments[0], mc.Arguments[1], null, source);
					}
					else if(mc.Arguments.Count == 3)
					{
						return sql.Like(mc.Arguments[0], mc.Arguments[1], sql.ConvertTo(typeof(string), mc.Arguments[2]), source);
					}
				}
				else if(name == "RawLength")
				{
					SqlExpression length = sql.FunctionCallDataLength(mc.Arguments[0]);
					return length;
				}

				return returnValue;
			}