File: SqlBooleanMismatchVisitor.cs

package info (click to toggle)
mono 6.8.0.105%2Bdfsg-3.3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,284,512 kB
  • sloc: cs: 11,172,132; xml: 2,850,069; ansic: 671,653; cpp: 122,091; perl: 59,366; javascript: 30,841; asm: 22,168; makefile: 20,093; sh: 15,020; python: 4,827; pascal: 925; sql: 859; sed: 16; php: 1
file content (150 lines) | stat: -rw-r--r-- 5,898 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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Data;

namespace System.Data.Linq.SqlClient {
    using System.Data.Linq;
    using System.Diagnostics.CodeAnalysis;

    /// <summary>
    /// This visitor searches for places where 'Predicate' is found but a 'Bit'
    /// was expected or vice versa. In response, it will call VisitBitExpectedPredicate
    /// and VisitPredicateExpectedBit.
    /// </summary>
    internal abstract class SqlBooleanMismatchVisitor : SqlVisitor {

        internal SqlBooleanMismatchVisitor() {
        }

        internal abstract SqlExpression ConvertValueToPredicate(SqlExpression valueExpression);
        internal abstract SqlExpression ConvertPredicateToValue(SqlExpression predicateExpression);

        internal override SqlSelect VisitSelect(SqlSelect select) {
            select.From = this.VisitSource(select.From);
            select.Where = this.VisitPredicate(select.Where);
            for (int i = 0, n = select.GroupBy.Count; i < n; i++) {
                select.GroupBy[i] = this.VisitExpression(select.GroupBy[i]);
            }
            select.Having = this.VisitPredicate(select.Having);
            for (int i = 0, n = select.OrderBy.Count; i < n; i++) {
                select.OrderBy[i].Expression = this.VisitExpression(select.OrderBy[i].Expression);
            }
            select.Top = this.VisitExpression(select.Top);
            select.Row = (SqlRow)this.Visit(select.Row);

            // don't visit selection
            //select.Selection = this.VisitExpression(select.Selection);

            return select;
        }

        internal override SqlSource VisitJoin(SqlJoin join) {
            join.Left = this.VisitSource(join.Left);
            join.Right = this.VisitSource(join.Right);
            join.Condition = this.VisitPredicate(join.Condition);
            return join;
        }

        internal override SqlExpression VisitUnaryOperator(SqlUnary uo) {
            if (uo.NodeType.IsUnaryOperatorExpectingPredicateOperand()) {
                uo.Operand = this.VisitPredicate(uo.Operand);
            } else {
                uo.Operand = this.VisitExpression(uo.Operand);
            }
            return uo;
        }

        internal override SqlExpression VisitBinaryOperator(SqlBinary bo) {
            if (bo.NodeType.IsBinaryOperatorExpectingPredicateOperands()) {
                bo.Left = this.VisitPredicate(bo.Left);
                bo.Right = this.VisitPredicate(bo.Right);
            } else {
                bo.Left = this.VisitExpression(bo.Left);
                bo.Right = this.VisitExpression(bo.Right);
            }

            return bo;
        }

        internal override SqlStatement VisitAssign(SqlAssign sa) {
            // L-Value of assign is never a 'Bit' nor a 'Predicate'.
            sa.LValue = this.VisitExpression(sa.LValue);
            sa.RValue = this.VisitExpression(sa.RValue);
            return sa;
        }

        internal override SqlExpression VisitSearchedCase(SqlSearchedCase c) {
            for (int i = 0, n = c.Whens.Count; i < n; i++) {
                SqlWhen when = c.Whens[i];
                when.Match = this.VisitPredicate(when.Match);
                when.Value = this.VisitExpression(when.Value);
            }
            c.Else = this.VisitExpression(c.Else);
            return c;
        }

        internal override SqlExpression VisitLift(SqlLift lift) {
            lift.Expression = base.VisitExpression(lift.Expression);
            return lift;
        }

        /// <summary>
        /// If an expression is type 'Bit' but a 'Predicate' is expected then 
        /// call 'VisitBitExpectedPredicate'.
        /// </summary>
        internal SqlExpression VisitPredicate(SqlExpression exp) {
            exp = (SqlExpression)base.Visit(exp);
            if (exp != null) {
                if (!IsPredicateExpression(exp)) {
                    exp = ConvertValueToPredicate(exp);
                }
            }
            return exp;
        }

        /// <summary>
        /// Any remaining calls to VisitExpression expect a 'Bit' when there's
        /// a boolean expression.
        /// </summary>
        internal override SqlExpression VisitExpression(SqlExpression exp) {
            exp = (SqlExpression)base.Visit(exp);
            if (exp != null) {
                if (IsPredicateExpression(exp)) {
                    exp = ConvertPredicateToValue(exp);
                }
            }
            return exp;
        }

        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "These issues are related to our use of if-then and case statements for node types, which adds to the complexity count however when reviewed they are easy to navigate and understand.")]
        private static bool IsPredicateExpression(SqlExpression exp) {
            switch (exp.NodeType) {
                case SqlNodeType.And:
                case SqlNodeType.Or:
                case SqlNodeType.Not:
                case SqlNodeType.Not2V:
                case SqlNodeType.EQ:
                case SqlNodeType.EQ2V:
                case SqlNodeType.NE:
                case SqlNodeType.NE2V:
                case SqlNodeType.GE:
                case SqlNodeType.GT:
                case SqlNodeType.LE:
                case SqlNodeType.LT:
                case SqlNodeType.Exists:
                case SqlNodeType.Between:
                case SqlNodeType.In:
                case SqlNodeType.Like:
                case SqlNodeType.IsNotNull:
                case SqlNodeType.IsNull:
                    return true;
                case SqlNodeType.Lift:
                    return IsPredicateExpression(((SqlLift)exp).Expression);
                default:
                    return false;
            }
        }
    }
}