1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 
5 namespace System.Data.Linq.SqlClient {
6 
7     /// <summary>
8     /// Validates the integrity of super-SQL trees.
9     /// </summary>
10     internal class SqlSupersetValidator {
11 
12         List<SqlVisitor> validators = new List<SqlVisitor>();
13 
14         /// <summary>
15         /// Add a validator to the collection of validators to run.
16         /// </summary>
AddValidator(SqlVisitor validator)17         internal void AddValidator(SqlVisitor validator) {
18             this.validators.Add(validator);
19         }
20 
21         /// <summary>
22         /// Execute each current validator.
23         /// </summary>
Validate(SqlNode node)24         internal void Validate(SqlNode node) {
25             foreach (SqlVisitor validator in this.validators) {
26                 validator.Visit(node);
27             }
28         }
29     }
30 
31     /// <summary>
32     /// Column ClrType must agree with the expression that it points to.
33     /// </summary>
34     internal class ColumnTypeValidator : SqlVisitor {
35 
VisitRow(SqlRow row)36         internal override SqlRow VisitRow(SqlRow row) {
37             for (int i = 0, n = row.Columns.Count; i < n; i++) {
38                 SqlColumn col = row.Columns[i];
39                 SqlExpression expr = this.VisitExpression(col.Expression);
40                 if (expr != null) {
41                     if (TypeSystem.GetNonNullableType(col.ClrType) != TypeSystem.GetNonNullableType(expr.ClrType)) {
42                         throw Error.ColumnClrTypeDoesNotAgreeWithExpressionsClrType();
43                     }
44                 }
45             }
46             return row;
47         }
48     }
49 
50     /// <summary>
51     /// A validator that ensures literal values are reasonable.
52     /// </summary>
53     internal class LiteralValidator : SqlVisitor {
54 
VisitValue(SqlValue value)55         internal override SqlExpression VisitValue(SqlValue value) {
56             if (!value.IsClientSpecified
57                 && value.ClrType.IsClass
58                 && value.ClrType != typeof(string)
59                 && value.ClrType != typeof(Type)
60                 && value.Value != null) {
61                 throw Error.ClassLiteralsNotAllowed(value.ClrType);
62             }
63             return value;
64         }
65 
VisitBinaryOperator(SqlBinary bo)66         internal override SqlExpression VisitBinaryOperator(SqlBinary bo) {
67             bo.Left = this.VisitExpression(bo.Left);
68             return bo;
69         }
70     }
71 
72     /// <summary>
73     /// A validator which enforces rationalized boolean expressions.
74     /// </summary>
75     internal class ExpectRationalizedBooleans : SqlBooleanMismatchVisitor {
76 
ExpectRationalizedBooleans()77         internal ExpectRationalizedBooleans() {
78         }
79 
ConvertValueToPredicate(SqlExpression bitExpression)80         internal override SqlExpression ConvertValueToPredicate(SqlExpression bitExpression) {
81             throw Error.ExpectedPredicateFoundBit();
82         }
83 
ConvertPredicateToValue(SqlExpression predicateExpression)84         internal override SqlExpression ConvertPredicateToValue(SqlExpression predicateExpression) {
85             throw Error.ExpectedBitFoundPredicate();
86         }
87     }
88 
89     /// <summary>
90     /// A validator which enforces that no more SqlMethodCall nodes exist in the tree.
91     /// </summary>
92     internal class ExpectNoMethodCalls : SqlVisitor {
93 
VisitMethodCall(SqlMethodCall mc)94         internal override SqlExpression VisitMethodCall(SqlMethodCall mc) {
95             // eventually we may support this type of stuff given the SQL CLR, but for now it is illegal
96             throw Error.MethodHasNoSupportConversionToSql(mc.Method.Name);
97         }
98 
99         // check everything except selection expressions (which will be client or ignored)
VisitSelect(SqlSelect select)100         internal override SqlSelect VisitSelect(SqlSelect select) {
101             return this.VisitSelectCore(select);
102         }
103     }
104 
105     internal class ExpectNoFloatingColumns : SqlVisitor {
VisitRow(SqlRow row)106         internal override SqlRow VisitRow(SqlRow row) {
107             foreach (SqlColumn c in row.Columns) {
108                 this.Visit(c.Expression);
109             }
110             return row;
111         }
VisitTable(SqlTable tab)112         internal override SqlTable VisitTable(SqlTable tab) {
113             foreach (SqlColumn c in tab.Columns) {
114                 this.Visit(c.Expression);
115             }
116             return tab;
117         }
VisitColumn(SqlColumn col)118         internal override SqlExpression VisitColumn(SqlColumn col) {
119             throw Error.UnexpectedFloatingColumn();
120         }
121     }
122 
123     internal class ExpectNoAliasRefs : SqlVisitor {
VisitAliasRef(SqlAliasRef aref)124         internal override SqlExpression VisitAliasRef(SqlAliasRef aref) {
125             throw Error.UnexpectedNode(aref.NodeType);
126         }
127     }
128 
129     internal class ExpectNoSharedExpressions : SqlVisitor {
VisitSharedExpression(SqlSharedExpression shared)130         internal override SqlExpression VisitSharedExpression(SqlSharedExpression shared) {
131             throw Error.UnexpectedSharedExpression();
132         }
VisitSharedExpressionRef(SqlSharedExpressionRef sref)133         internal override SqlExpression VisitSharedExpressionRef(SqlSharedExpressionRef sref) {
134             throw Error.UnexpectedSharedExpressionReference();
135         }
136     }
137 
138     /// <summary>
139     /// Determines if there is a boolean NText/Text/Image comparison and if so throws an exception
140     /// because this is not valid in SQLServer.
141     /// </summary>
142     internal class ValidateNoInvalidComparison : SqlVisitor {
143 
VisitBinaryOperator(SqlBinary bo)144         internal override SqlExpression VisitBinaryOperator(SqlBinary bo) {
145             if (bo.NodeType == SqlNodeType.EQ || bo.NodeType == SqlNodeType.NE ||
146                 bo.NodeType == SqlNodeType.EQ2V || bo.NodeType == SqlNodeType.NE2V ||
147                 bo.NodeType == SqlNodeType.GT || bo.NodeType == SqlNodeType.GE ||
148                 bo.NodeType == SqlNodeType.LT || bo.NodeType == SqlNodeType.LE ) {
149                 if (!bo.Left.SqlType.SupportsComparison ||
150                     !bo.Right.SqlType.SupportsComparison){
151                     throw Error.UnhandledStringTypeComparison();
152                 }
153             }
154             bo.Left = this.VisitExpression(bo.Left);
155             bo.Right = this.VisitExpression(bo.Right);
156             return bo;
157         }
158 
159     }
160 }
161