Exemplo n.º 1
0
        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);
        }
Exemplo n.º 2
0
        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));
        }
Exemplo n.º 3
0
        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));
        }
Exemplo n.º 4
0
        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 })));
        }
Exemplo n.º 5
0
        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);
 }
Exemplo n.º 10
0
 internal override SqlNode VisitMember(SqlMember m) {
     return new SqlMember(m.ClrType, m.SqlType, (SqlExpression)this.Visit(m.Expression), m.Member);
 }
Exemplo n.º 11
0
 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);
            }
        }
Exemplo n.º 14
0
 internal override SqlExpression DateTime_Minute(SqlMember m, SqlExpression expr)
 {
     return(FunctionCall(typeof(int), "date_part", new[] { ValueFromObject("minute", false, expr.SourceExpression), expr }, expr.SourceExpression));
 }
Exemplo n.º 15
0
 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;
 }
Exemplo n.º 17
0
 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);
 }
Exemplo n.º 19
0
            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";
 }
Exemplo n.º 21
0
 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);
            }