File: SqlMethodTransformer.cs

package info (click to toggle)
mono 6.12.0.199%2Bdfsg-6
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 1,296,836 kB
  • sloc: cs: 11,181,803; xml: 2,850,076; ansic: 699,709; cpp: 123,344; perl: 59,361; javascript: 30,841; asm: 21,853; makefile: 20,405; sh: 15,009; python: 4,839; pascal: 925; sql: 859; sed: 16; php: 1
file content (88 lines) | stat: -rw-r--r-- 3,599 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.Linq;

namespace System.Data.Linq.SqlClient {

    /// <summary>
    /// After retyping and conversions take place, some functions need to be changed into more suitable calls.
    /// Example: LEN -> DATALENGTH for long text types.
    /// </summary>
    internal class SqlMethodTransformer : SqlVisitor {
        protected SqlFactory sql;

        internal SqlMethodTransformer(SqlFactory sql) {
            this.sql = sql;
        }

        internal override SqlExpression VisitFunctionCall(SqlFunctionCall fc) {
            // process the arguments
            SqlExpression result = base.VisitFunctionCall(fc);
            if (result is SqlFunctionCall) {
                SqlFunctionCall resultFunctionCall = (SqlFunctionCall)result;

                if (resultFunctionCall.Name == "LEN") {
                    SqlExpression expr = resultFunctionCall.Arguments[0];

                    if (expr.SqlType.IsLargeType && !expr.SqlType.SupportsLength) {
                        result = sql.DATALENGTH(expr);
                        
                        if (expr.SqlType.IsUnicodeType) {
                            result = sql.ConvertToInt(sql.Divide(result, sql.ValueFromObject(2, expr.SourceExpression)));
                        }
                    }
                }

                // If the return type of the sql function is not compatible with
                // the expected CLR type of the function, inject a conversion. This
                // step must be performed AFTER SqlRetyper has run.
                Type clrType = resultFunctionCall.SqlType.GetClosestRuntimeType();
                bool skipConversion = SqlMethodTransformer.SkipConversionForDateAdd(resultFunctionCall.Name,
                                                                                    resultFunctionCall.ClrType,
                                                                                    clrType);
                if ((resultFunctionCall.ClrType != clrType) && !skipConversion) {
                    result = sql.ConvertTo(resultFunctionCall.ClrType, resultFunctionCall);
                }
            }

            return result;
        }

        internal override SqlExpression VisitUnaryOperator(SqlUnary fc) {
            // process the arguments
            SqlExpression result = base.VisitUnaryOperator(fc);
            if (result is SqlUnary) {
                SqlUnary unary = (SqlUnary)result;

                switch (unary.NodeType) {
                    case SqlNodeType.ClrLength:
                        SqlExpression expr = unary.Operand;

                        result = sql.DATALENGTH(expr);

                        if (expr.SqlType.IsUnicodeType) {
                            result = sql.Divide(result, sql.ValueFromObject(2, expr.SourceExpression));
                        }

                        result = sql.ConvertToInt(result);
                        break;
                    default:
                        break;
                }
            }

            return result;
        }

        // We don't inject a conversion for DATEADD if doing so will downgrade the result to
        // a less precise type.
        //
        private static bool SkipConversionForDateAdd(string functionName, Type expected, Type actual) {
            if (string.Compare(functionName, "DATEADD", StringComparison.OrdinalIgnoreCase) != 0)
                return false;

            return (expected == typeof(DateTime) && actual == typeof(DateTimeOffset));
        }
    }
}