internal override SqlExpression DateTime_DayOfYear(SqlMember m, SqlExpression expr) { var args = new[] { VariableFromName("DOY", expr.SourceExpression), VariableFromName("FROM", expr.SourceExpression), expr }; var f = FunctionCall(typeof(int), "EXTRACT", args, expr.SourceExpression); f.Comma = false; return(f); }
internal override SqlExpression DateTime_DayOfWeek(SqlMember m, SqlExpression expr) { var clrType = typeof(DayOfWeek); var sqlType = TypeProvider.From(typeof(int)); var interval = ValueFromObject("w", expr.SourceExpression); var func = FunctionCall(typeof(int), sqlType, "DatePart", new[] { interval, expr }, expr.SourceExpression); return(new SqlBinary(SqlNodeType.Sub, clrType, sqlType, func, ValueFromObject(1, expr.SourceExpression))); //return Add(func, ValueFromObject(1, expr.SourceExpression)); }
internal override SqlExpression DateTime_Date(SqlMember m, SqlExpression expr) { var s = expr.SourceExpression; var func = new SqlFunctionCall(typeof(string), TypeProvider.From(typeof(string)), "TO_CHAR", new[] { expr, ValueFromObject("YYYY-MM-DD", s) }, s); //return func; return(new SqlFunctionCall(typeof(DateTime), TypeProvider.From(typeof(DateTime)), "TO_DATE", new[] { func, ValueFromObject("YYYY-MM-DD", s) }, s)); }
internal override SqlNode DateTime_TimeOfDay(SqlMember member, SqlExpression expr) { var h = DATEPART("HOUR", expr); var m = DATEPART("MINUTE", expr); var s = DATEPART("SECOND", expr); h = Multiply(ConvertToBigint(h), 0x861c46800L); m = Multiply(ConvertToBigint(m), 0x23c34600L); s = Multiply(ConvertToBigint(s), 0x989680L); return(ConvertTo(typeof(TimeSpan), Add(new[] { h, m, s }))); }
internal SqlExpression BuildProjection(SqlExpression item, MetaType rowType, bool allowDeferred, SqlLink link, Expression source) { if (!rowType.HasInheritance) { return(this.BuildProjectionInternal(item, rowType, (rowType.Table != null) ? rowType.PersistentDataMembers : rowType.DataMembers, allowDeferred, link, source)); } else { // Build a type case that represents a switch between the various type. List <MetaType> mappedTypes = new List <MetaType>(rowType.InheritanceTypes); List <SqlTypeCaseWhen> whens = new List <SqlTypeCaseWhen>(); SqlTypeCaseWhen @else = null; MetaType root = rowType.InheritanceRoot; MetaDataMember discriminator = root.Discriminator; Type dt = discriminator.Type; SqlMember dm = sql.Member(item, discriminator.Member); foreach (MetaType type in mappedTypes) { if (type.HasInheritanceCode) { SqlNew defaultProjection = this.BuildProjectionInternal(item, type, type.PersistentDataMembers, allowDeferred, link, source); if (type.IsInheritanceDefault) { @else = new SqlTypeCaseWhen(null, defaultProjection); } // Add an explicit case even for the default. // Redundant results will be optimized out later. object code = InheritanceRules.InheritanceCodeForClientCompare(type.InheritanceCode, dm.SqlType); SqlExpression match = sql.Value(dt, sql.Default(discriminator), code, true, source); whens.Add(new SqlTypeCaseWhen(match, defaultProjection)); } } if (@else == null) { throw Error.EmptyCaseNotSupported(); } whens.Add(@else); // Add the else at the end. return(sql.TypeCase(root.Type, root, dm, whens.ToArray(), source)); } }
// // Identical to IsSupportedDateTimeMember(), except for support for 'DateTime' // private static bool IsSupportedDateTimeOffsetMember(SqlMember m) { if (m.Expression.ClrType == typeof(DateTimeOffset)) { string datePart = GetDatePart(m.Member.Name); if (datePart != null) { return true; } switch (m.Member.Name) { case "Date": case "DateTime": case "TimeOfDay": case "DayOfWeek": return true; } } return false; }
private static bool IsSupportedBinaryMember(SqlMember m) { return m.Expression.ClrType == typeof(Binary) && m.Member.Name == "Length"; }
private static bool IsSupportedStringMember(SqlMember m) { return m.Expression.ClrType == typeof(string) && m.Member.Name == "Length"; }
private static bool IsSupportedMember(SqlMember m) { return IsSupportedStringMember(m) || IsSupportedBinaryMember(m) || IsSupportedDateTimeMember(m) || IsSupportedDateTimeOffsetMember(m) || IsSupportedTimeSpanMember(m); }
internal override SqlNode VisitMember(SqlMember m) { return new SqlMember(m.ClrType, m.SqlType, (SqlExpression)this.Visit(m.Expression), m.Member); }
internal override SqlNode VisitMember(SqlMember m) { return this.AccessMember(m, this.FetchExpression(m.Expression)); }
internal override SqlNode VisitMember(SqlMember m) { m.Expression = this.VisitExpression(m.Expression); if (IsNullableValue(m)) { return sql.UnaryValueOf(m.Expression, m.SourceExpression); } else if (IsNullableHasValue(m)) { return sql.Unary(SqlNodeType.IsNotNull, m.Expression, m.SourceExpression); } return m; }
internal static bool AreSimilar(SqlExpression node1, SqlExpression node2) { if (node1 == node2) { return(true); } if (node1 == null || node2 == null) { return(false); } if (node1.NodeType != node2.NodeType || node1.ClrType != node2.ClrType || node1.SqlType != node2.SqlType) { return(false); } switch (node1.NodeType) { case SqlNodeType.New: { SqlNew new1 = (SqlNew)node1; SqlNew new2 = (SqlNew)node2; if (new1.Args.Count != new2.Args.Count || new1.Members.Count != new2.Members.Count) { return(false); } for (int i = 0, n = new1.Args.Count; i < n; i++) { if (!AreSimilar(new1.Args[i], new2.Args[i])) { return(false); } } for (int i = 0, n = new1.Members.Count; i < n; i++) { if (!MetaPosition.AreSameMember(new1.Members[i].Member, new2.Members[i].Member) || !AreSimilar(new1.Members[i].Expression, new2.Members[i].Expression)) { return(false); } } return(true); } case SqlNodeType.ColumnRef: { SqlColumnRef cref1 = (SqlColumnRef)node1; SqlColumnRef cref2 = (SqlColumnRef)node2; return(cref1.Column.Ordinal == cref2.Column.Ordinal); } case SqlNodeType.Link: { SqlLink l1 = (SqlLink)node1; SqlLink l2 = (SqlLink)node2; if (!MetaPosition.AreSameMember(l1.Member.Member, l2.Member.Member)) { return(false); } if (l1.KeyExpressions.Count != l2.KeyExpressions.Count) { return(false); } for (int i = 0, c = l1.KeyExpressions.Count; i < c; ++i) { if (!AreSimilar(l1.KeyExpressions[i], l2.KeyExpressions[i])) { return(false); } } return(true); } case SqlNodeType.Value: return(Object.Equals(((SqlValue)node1).Value, ((SqlValue)node2).Value)); case SqlNodeType.OptionalValue: { SqlOptionalValue ov1 = (SqlOptionalValue)node1; SqlOptionalValue ov2 = (SqlOptionalValue)node2; return(AreSimilar(ov1.Value, ov2.Value)); } case SqlNodeType.ValueOf: case SqlNodeType.OuterJoinedValue: return(AreSimilar(((SqlUnary)node1).Operand, ((SqlUnary)node2).Operand)); case SqlNodeType.Lift: return(AreSimilar(((SqlLift)node1).Expression, ((SqlLift)node2).Expression)); case SqlNodeType.Grouping: { SqlGrouping g1 = (SqlGrouping)node1; SqlGrouping g2 = (SqlGrouping)node2; return(AreSimilar(g1.Key, g2.Key) && AreSimilar(g1.Group, g2.Group)); } case SqlNodeType.ClientArray: { SqlClientArray a1 = (SqlClientArray)node1; SqlClientArray a2 = (SqlClientArray)node2; if (a1.Expressions.Count != a2.Expressions.Count) { return(false); } for (int i = 0, n = a1.Expressions.Count; i < n; i++) { if (!AreSimilar(a1.Expressions[i], a2.Expressions[i])) { return(false); } } return(true); } case SqlNodeType.UserColumn: return(((SqlUserColumn)node1).Name == ((SqlUserColumn)node2).Name); case SqlNodeType.ClientCase: { SqlClientCase c1 = (SqlClientCase)node1; SqlClientCase c2 = (SqlClientCase)node2; if (c1.Whens.Count != c2.Whens.Count) { return(false); } for (int i = 0, n = c1.Whens.Count; i < n; i++) { if (!AreSimilar(c1.Whens[i].Match, c2.Whens[i].Match) || !AreSimilar(c1.Whens[i].Value, c2.Whens[i].Value)) { return(false); } } return(true); } case SqlNodeType.SearchedCase: { SqlSearchedCase c1 = (SqlSearchedCase)node1; SqlSearchedCase c2 = (SqlSearchedCase)node2; if (c1.Whens.Count != c2.Whens.Count) { return(false); } for (int i = 0, n = c1.Whens.Count; i < n; i++) { if (!AreSimilar(c1.Whens[i].Match, c2.Whens[i].Match) || !AreSimilar(c1.Whens[i].Value, c2.Whens[i].Value)) { return(false); } } return(AreSimilar(c1.Else, c2.Else)); } case SqlNodeType.TypeCase: { SqlTypeCase c1 = (SqlTypeCase)node1; SqlTypeCase c2 = (SqlTypeCase)node2; if (!AreSimilar(c1.Discriminator, c2.Discriminator)) { return(false); } if (c1.Whens.Count != c2.Whens.Count) { return(false); } for (int i = 0, c = c1.Whens.Count; i < c; ++i) { if (!AreSimilar(c1.Whens[i].Match, c2.Whens[i].Match)) { return(false); } if (!AreSimilar(c1.Whens[i].TypeBinding, c2.Whens[i].TypeBinding)) { return(false); } } return(true); } case SqlNodeType.DiscriminatedType: { SqlDiscriminatedType dt1 = (SqlDiscriminatedType)node1; SqlDiscriminatedType dt2 = (SqlDiscriminatedType)node2; return(AreSimilar(dt1.Discriminator, dt2.Discriminator)); } case SqlNodeType.JoinedCollection: { SqlJoinedCollection j1 = (SqlJoinedCollection)node1; SqlJoinedCollection j2 = (SqlJoinedCollection)node2; return(AreSimilar(j1.Count, j2.Count) && AreSimilar(j1.Expression, j2.Expression)); } case SqlNodeType.Member: { SqlMember m1 = (SqlMember)node1; SqlMember m2 = (SqlMember)node2; return(m1.Member == m2.Member && AreSimilar(m1.Expression, m2.Expression)); } case SqlNodeType.ClientQuery: { SqlClientQuery cq1 = (SqlClientQuery)node1; SqlClientQuery cq2 = (SqlClientQuery)node2; if (cq1.Arguments.Count != cq2.Arguments.Count) { return(false); } for (int i = 0, n = cq1.Arguments.Count; i < n; i++) { if (!AreSimilar(cq1.Arguments[i], cq2.Arguments[i])) { return(false); } } return(true); } case SqlNodeType.MethodCall: { SqlMethodCall mc1 = (SqlMethodCall)node1; SqlMethodCall mc2 = (SqlMethodCall)node2; if (mc1.Method != mc2.Method || !AreSimilar(mc1.Object, mc2.Object)) { return(false); } if (mc1.Arguments.Count != mc2.Arguments.Count) { return(false); } for (int i = 0, n = mc1.Arguments.Count; i < n; i++) { if (!AreSimilar(mc1.Arguments[i], mc2.Arguments[i])) { return(false); } } return(true); } case SqlNodeType.ClientParameter: default: return(false); } }
internal override SqlExpression DateTime_Minute(SqlMember m, SqlExpression expr) { return(FunctionCall(typeof(int), "date_part", new[] { ValueFromObject("minute", false, expr.SourceExpression), expr }, expr.SourceExpression)); }
internal override SqlExpression DateTime_Date(SqlMember m, SqlExpression expr) { return(FunctionCall(typeof(DateTime), "date_trunc", new[] { ValueFromObject("day", false, expr.SourceExpression), expr }, expr.SourceExpression)); }
private static bool IsSupportedTimeSpanMember(SqlMember m) { if (m.Expression.ClrType == typeof(TimeSpan)) { switch (m.Member.Name) { case "Ticks": case "TotalMilliseconds": case "TotalSeconds": case "TotalMinutes": case "TotalHours": case "TotalDays": case "Milliseconds": case "Seconds": case "Minutes": case "Hours": case "Days": return true; } } return false; }
internal virtual SqlNode VisitMember(SqlMember m) { m.Expression = this.VisitExpression(m.Expression); return m; }
private static bool IsSupportedMember(SqlMember m) { return IsNullableHasValue(m) || IsNullableHasValue(m); }
private SqlNode AccessMember(SqlMember m, SqlExpression expo) { SqlExpression exp = expo; switch (exp.NodeType) { case SqlNodeType.ClientCase: { // Distribute into each case. SqlClientCase sc = (SqlClientCase)exp; Type newClrType = null; List<SqlExpression> matches = new List<SqlExpression>(); List<SqlExpression> values = new List<SqlExpression>(); foreach (SqlClientWhen when in sc.Whens) { SqlExpression newValue = (SqlExpression)AccessMember(m, when.Value); if (newClrType == null) { newClrType = newValue.ClrType; } else if (newClrType != newValue.ClrType) { throw Error.ExpectedClrTypesToAgree(newClrType, newValue.ClrType); } matches.Add(when.Match); values.Add(newValue); } SqlExpression result = sql.Case(newClrType, sc.Expression, matches, values, sc.SourceExpression); return result; } case SqlNodeType.SimpleCase: { // Distribute into each case. SqlSimpleCase sc = (SqlSimpleCase)exp; Type newClrType = null; List<SqlExpression> newMatches = new List<SqlExpression>(); List<SqlExpression> newValues = new List<SqlExpression>(); foreach (SqlWhen when in sc.Whens) { SqlExpression newValue = (SqlExpression)AccessMember(m, when.Value); if (newClrType == null) { newClrType = newValue.ClrType; } else if (newClrType != newValue.ClrType) { throw Error.ExpectedClrTypesToAgree(newClrType, newValue.ClrType); } newMatches.Add(when.Match); newValues.Add(newValue); } SqlExpression result = sql.Case(newClrType, sc.Expression, newMatches, newValues, sc.SourceExpression); return result; } case SqlNodeType.SearchedCase: { // Distribute into each case. SqlSearchedCase sc = (SqlSearchedCase)exp; List<SqlWhen> whens = new List<SqlWhen>(sc.Whens.Count); foreach (SqlWhen when in sc.Whens) { SqlExpression value = (SqlExpression)AccessMember(m, when.Value); whens.Add(new SqlWhen(when.Match, value)); } SqlExpression @else = (SqlExpression)AccessMember(m, sc.Else); return sql.SearchedCase(whens.ToArray(), @else, sc.SourceExpression); } case SqlNodeType.TypeCase: { // We don't allow derived types to map members to different database fields. // Therefore, just pick the best SqlNew to call AccessMember on. SqlTypeCase tc = (SqlTypeCase)exp; // Find the best type binding for this member. SqlNew tb = tc.Whens[0].TypeBinding as SqlNew; foreach (SqlTypeCaseWhen when in tc.Whens) { if (when.TypeBinding.NodeType == SqlNodeType.New) { SqlNew sn = (SqlNew)when.TypeBinding; if (m.Member.DeclaringType.IsAssignableFrom(sn.ClrType)) { tb = sn; break; } } } return AccessMember(m, tb); } case SqlNodeType.AliasRef: { // convert alias.Member => column SqlAliasRef aref = (SqlAliasRef)exp; // if its a table, find the matching column SqlTable tab = aref.Alias.Node as SqlTable; if (tab != null) { MetaDataMember mm = GetRequiredInheritanceDataMember(tab.RowType, m.Member); System.Diagnostics.Debug.Assert(mm != null); string name = mm.MappedName; SqlColumn c = tab.Find(name); if (c == null) { ProviderType sqlType = sql.Default(mm); c = new SqlColumn(m.ClrType, sqlType, name, mm, null, m.SourceExpression); c.Alias = aref.Alias; tab.Columns.Add(c); } return new SqlColumnRef(c); } // if it is a table valued function, find the matching result column SqlTableValuedFunctionCall fc = aref.Alias.Node as SqlTableValuedFunctionCall; if (fc != null) { MetaDataMember mm = GetRequiredInheritanceDataMember(fc.RowType, m.Member); System.Diagnostics.Debug.Assert(mm != null); string name = mm.MappedName; SqlColumn c = fc.Find(name); if (c == null) { ProviderType sqlType = sql.Default(mm); c = new SqlColumn(m.ClrType, sqlType, name, mm, null, m.SourceExpression); c.Alias = aref.Alias; fc.Columns.Add(c); } return new SqlColumnRef(c); } break; } case SqlNodeType.OptionalValue: // convert option(exp).Member => exp.Member return this.AccessMember(m, ((SqlOptionalValue)exp).Value); case SqlNodeType.OuterJoinedValue: { SqlNode n = this.AccessMember(m, ((SqlUnary)exp).Operand); SqlExpression e = n as SqlExpression; if (e != null) return sql.Unary(SqlNodeType.OuterJoinedValue, e); return n; } case SqlNodeType.Lift: return this.AccessMember(m, ((SqlLift)exp).Expression); case SqlNodeType.UserRow: { // convert UserRow.Member => UserColumn SqlUserRow row = (SqlUserRow)exp; SqlUserQuery suq = row.Query; MetaDataMember mm = GetRequiredInheritanceDataMember(row.RowType, m.Member); System.Diagnostics.Debug.Assert(mm != null); string name = mm.MappedName; SqlUserColumn c = suq.Find(name); if (c == null) { ProviderType sqlType = sql.Default(mm); c = new SqlUserColumn(m.ClrType, sqlType, suq, name, mm.IsPrimaryKey, m.SourceExpression); suq.Columns.Add(c); } return c; } case SqlNodeType.New: { // convert (new {Member = expr}).Member => expr SqlNew sn = (SqlNew)exp; SqlExpression e = sn.Find(m.Member); if (e != null) { return e; } MetaDataMember mm = sn.MetaType.PersistentDataMembers.FirstOrDefault(p => p.Member == m.Member); if (!sn.SqlType.CanBeColumn && mm != null) { throw Error.MemberNotPartOfProjection(m.Member.DeclaringType, m.Member.Name); } break; } case SqlNodeType.Element: case SqlNodeType.ScalarSubSelect: { // convert Scalar/Element(select exp).Member => Scalar/Element(select exp.Member) / select exp.Member SqlSubSelect sub = (SqlSubSelect)exp; SqlAlias alias = new SqlAlias(sub.Select); SqlAliasRef aref = new SqlAliasRef(alias); SqlSelect saveSelect = this.currentSelect; try { SqlSelect newSelect = new SqlSelect(aref, alias, sub.SourceExpression); this.currentSelect = newSelect; SqlNode result = this.Visit(sql.Member(aref, m.Member)); SqlExpression rexp = result as SqlExpression; if (rexp != null) { // If the expression is still a Member after being visited, but it cannot be a column, then it cannot be collapsed // into the SubSelect because we need to keep track of the fact that this member has to be accessed on the client. // This must be done after the expression has been Visited above, because otherwise we don't have // enough context to know if the member can be a column or not. if (rexp.NodeType == SqlNodeType.Member && !SqlColumnizer.CanBeColumn(rexp)) { // If the original member expression is an Element, optimize it by converting to an OuterApply if possible. // We have to do this here because we are creating a new member expression based on it, and there are no // subsequent visitors that will do this optimization. if (this.canUseOuterApply && exp.NodeType == SqlNodeType.Element && this.currentSelect != null) { // Reset the currentSelect since we are not going to use the previous SqlSelect that was created this.currentSelect = saveSelect; this.currentSelect.From = sql.MakeJoin(SqlJoinType.OuterApply, this.currentSelect.From, alias, null, sub.SourceExpression); exp = this.VisitExpression(aref); } return sql.Member(exp, m.Member); } // Since we are going to make a SubSelect out of this member expression, we need to make // sure it gets columnized before it gets to the PostBindDotNetConverter, otherwise only the // entire SubSelect will be columnized as a whole. Subsequent columnization does not know how to handle // any function calls that may be produced by the PostBindDotNetConverter, but we know how to handle it here. newSelect.Selection = rexp; newSelect.Selection = this.columnizer.ColumnizeSelection(newSelect.Selection); newSelect.Selection = this.ConvertLinks(newSelect.Selection); SqlNodeType subType = (rexp is SqlTypeCase || !rexp.SqlType.CanBeColumn) ? SqlNodeType.Element : SqlNodeType.ScalarSubSelect; SqlSubSelect subSel = sql.SubSelect(subType, newSelect); return this.FoldSubquery(subSel); } SqlSelect rselect = result as SqlSelect; if (rselect != null) { SqlAlias ralias = new SqlAlias(rselect); SqlAliasRef rref = new SqlAliasRef(ralias); newSelect.Selection = this.ConvertLinks(this.VisitExpression(rref)); newSelect.From = new SqlJoin(SqlJoinType.CrossApply, alias, ralias, null, m.SourceExpression); return newSelect; } throw Error.UnexpectedNode(result.NodeType); } finally { this.currentSelect = saveSelect; } } case SqlNodeType.Value: { SqlValue val = (SqlValue)exp; if (val.Value == null) { return sql.Value(m.ClrType, m.SqlType, null, val.IsClientSpecified, m.SourceExpression); } else if (m.Member is PropertyInfo) { PropertyInfo p = (PropertyInfo)m.Member; return sql.Value(m.ClrType, m.SqlType, p.GetValue(val.Value, null), val.IsClientSpecified, m.SourceExpression); } else { FieldInfo f = (FieldInfo)m.Member; return sql.Value(m.ClrType, m.SqlType, f.GetValue(val.Value), val.IsClientSpecified, m.SourceExpression); } } case SqlNodeType.Grouping: { SqlGrouping g = ((SqlGrouping)exp); if (m.Member.Name == "Key") { return g.Key; } break; } case SqlNodeType.ClientParameter: { SqlClientParameter cp = (SqlClientParameter)exp; // create new accessor including this member access LambdaExpression accessor = Expression.Lambda( typeof(Func<,>).MakeGenericType(typeof(object[]), m.ClrType), Expression.MakeMemberAccess(cp.Accessor.Body, m.Member), cp.Accessor.Parameters ); return new SqlClientParameter(m.ClrType, m.SqlType, accessor, cp.SourceExpression); } default: break; } if (m.Expression == exp) { return m; } else { return sql.Member(exp, m.Member); } }
private static bool IsNullableHasValue(SqlMember m) { return TypeSystem.IsNullableType(m.Expression.ClrType) && m.Member.Name == "HasValue"; }
internal override SqlNode VisitMember(SqlMember m) { this.Visit(m.Expression); sb.Append("."); sb.Append(m.Member.Name); return m; }
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.LEN(exp); } else if (baseClrTypeOfExpr == typeof(Binary) && member.Name == "Length") { return sql.DATALENGTH(exp); } else if (baseClrTypeOfExpr == typeof(DateTime) || baseClrTypeOfExpr == typeof(DateTimeOffset)) { string datePart = GetDatePart(member.Name); if (datePart != null) { return sql.DATEPART(datePart, exp); } else if (member.Name == "Date") { if (this.providerMode == SqlProvider.ProviderMode.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.DATEPART("MILLISECOND", exp); SqlExpression ss = sql.DATEPART("SECOND", exp); SqlExpression mi = sql.DATEPART("MINUTE", exp); SqlExpression hh = sql.DATEPART("HOUR", exp); SqlExpression result = exp; result = sql.DATEADD("MILLISECOND", sql.Unary(SqlNodeType.Negate, ms), result); result = sql.DATEADD("SECOND", sql.Unary(SqlNodeType.Negate, ss), result); result = sql.DATEADD("MINUTE", sql.Unary(SqlNodeType.Negate, mi), result); result = sql.DATEADD("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.DATEPART("HOUR", exp); SqlExpression minutes = sql.DATEPART("MINUTE", exp); SqlExpression seconds = sql.DATEPART("SECOND", exp); SqlExpression milliseconds = sql.DATEPART("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.DATEPART("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 (SqlFactory.IsSqlTimeType(exp)) { return this.sql.Divide( sql.ConvertToBigint( sql.Add( this.sql.Multiply(sql.ConvertToBigint(sql.DATEPART("HOUR", exp)), 3600000000000), this.sql.Multiply(sql.ConvertToBigint(sql.DATEPART("MINUTE", exp)), 60000000000), this.sql.Multiply(sql.ConvertToBigint(sql.DATEPART("SECOND", exp)), 1000000000), sql.DATEPART("NANOSECOND", exp)) ), 100 ); } return sql.ConvertToBigint(exp); case "TotalMilliseconds": if (SqlFactory.IsSqlTimeType(exp)) { return this.sql.Add( this.sql.Multiply(sql.DATEPART("HOUR", exp), 3600000), this.sql.Multiply(sql.DATEPART("MINUTE", exp), 60000), this.sql.Multiply(sql.DATEPART("SECOND", exp), 1000), this.sql.Divide(sql.ConvertToDouble(sql.ConvertToBigint(sql.DATEPART("NANOSECOND", exp))), 1000000) ); } return sql.Divide(sql.ConvertToDouble(exp), TimeSpan.TicksPerMillisecond); case "TotalSeconds": if (SqlFactory.IsSqlTimeType(exp)) { return this.sql.Add( this.sql.Multiply(sql.DATEPART("HOUR", exp), 3600), this.sql.Multiply(sql.DATEPART("MINUTE", exp), 60), this.sql.DATEPART("SECOND", exp), this.sql.Divide(sql.ConvertToDouble(sql.ConvertToBigint(sql.DATEPART("NANOSECOND", exp))), 1000000000) ); } return sql.Divide(sql.ConvertToDouble(exp), TimeSpan.TicksPerSecond); case "TotalMinutes": if (SqlFactory.IsSqlTimeType(exp)) { return this.sql.Add( this.sql.Multiply(sql.DATEPART("HOUR", exp), 60), this.sql.DATEPART("MINUTE", exp), this.sql.Divide(sql.ConvertToDouble(sql.DATEPART("SECOND", exp)), 60), this.sql.Divide(sql.ConvertToDouble(sql.ConvertToBigint(sql.DATEPART("NANOSECOND", exp))), 60000000000) ); } return sql.Divide(sql.ConvertToDouble(exp), TimeSpan.TicksPerMinute); case "TotalHours": if (SqlFactory.IsSqlTimeType(exp)) { return this.sql.Add( this.sql.DATEPART("HOUR", exp), this.sql.Divide(sql.ConvertToDouble(sql.DATEPART("MINUTE", exp)), 60), this.sql.Divide(sql.ConvertToDouble(sql.DATEPART("SECOND", exp)), 3600), this.sql.Divide(sql.ConvertToDouble(sql.ConvertToBigint(sql.DATEPART("NANOSECOND", exp))), 3600000000000) ); } return sql.Divide(sql.ConvertToDouble(exp), TimeSpan.TicksPerHour); case "TotalDays": if (SqlFactory.IsSqlTimeType(exp)) { return this.sql.Divide( this.sql.Add( this.sql.DATEPART("HOUR", exp), this.sql.Divide(sql.ConvertToDouble(sql.DATEPART("MINUTE", exp)), 60), this.sql.Divide(sql.ConvertToDouble(sql.DATEPART("SECOND", exp)), 3600), this.sql.Divide(sql.ConvertToDouble(sql.ConvertToBigint(sql.DATEPART("NANOSECOND", exp))), 3600000000000)), 24 ); } return sql.Divide(sql.ConvertToDouble(exp), TimeSpan.TicksPerDay); case "Milliseconds": if (SqlFactory.IsSqlTimeType(exp)) { return this.sql.DATEPART("MILLISECOND", exp); } return sql.ConvertToInt(sql.Mod(sql.ConvertToBigint(sql.Divide(exp, TimeSpan.TicksPerMillisecond)), 1000)); case "Seconds": if (SqlFactory.IsSqlTimeType(exp)) { return this.sql.DATEPART("SECOND", exp); } return sql.ConvertToInt(sql.Mod(sql.ConvertToBigint(sql.Divide(exp, TimeSpan.TicksPerSecond)), 60)); case "Minutes": if (SqlFactory.IsSqlTimeType(exp)) { return this.sql.DATEPART("MINUTE", exp); } return sql.ConvertToInt(sql.Mod(sql.ConvertToBigint(sql.Divide(exp, TimeSpan.TicksPerMinute)), 60)); case "Hours": if (SqlFactory.IsSqlTimeType(exp)) { return this.sql.DATEPART("HOUR", exp); } return sql.ConvertToInt(sql.Mod(sql.ConvertToBigint(sql.Divide(exp, TimeSpan.TicksPerHour)), 24)); case "Days": if (SqlFactory.IsSqlTimeType(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); }