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;
}
}
}
}
|