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