e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
161 lines
5.6 KiB
C#
161 lines
5.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
|
|
namespace System.Data.Linq.SqlClient {
|
|
|
|
/// <summary>
|
|
/// Validates the integrity of super-SQL trees.
|
|
/// </summary>
|
|
internal class SqlSupersetValidator {
|
|
|
|
List<SqlVisitor> validators = new List<SqlVisitor>();
|
|
|
|
/// <summary>
|
|
/// Add a validator to the collection of validators to run.
|
|
/// </summary>
|
|
internal void AddValidator(SqlVisitor validator) {
|
|
this.validators.Add(validator);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Execute each current validator.
|
|
/// </summary>
|
|
internal void Validate(SqlNode node) {
|
|
foreach (SqlVisitor validator in this.validators) {
|
|
validator.Visit(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Column ClrType must agree with the expression that it points to.
|
|
/// </summary>
|
|
internal class ColumnTypeValidator : SqlVisitor {
|
|
|
|
internal override SqlRow VisitRow(SqlRow row) {
|
|
for (int i = 0, n = row.Columns.Count; i < n; i++) {
|
|
SqlColumn col = row.Columns[i];
|
|
SqlExpression expr = this.VisitExpression(col.Expression);
|
|
if (expr != null) {
|
|
if (TypeSystem.GetNonNullableType(col.ClrType) != TypeSystem.GetNonNullableType(expr.ClrType)) {
|
|
throw Error.ColumnClrTypeDoesNotAgreeWithExpressionsClrType();
|
|
}
|
|
}
|
|
}
|
|
return row;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A validator that ensures literal values are reasonable.
|
|
/// </summary>
|
|
internal class LiteralValidator : SqlVisitor {
|
|
|
|
internal override SqlExpression VisitValue(SqlValue value) {
|
|
if (!value.IsClientSpecified
|
|
&& value.ClrType.IsClass
|
|
&& value.ClrType != typeof(string)
|
|
&& value.ClrType != typeof(Type)
|
|
&& value.Value != null) {
|
|
throw Error.ClassLiteralsNotAllowed(value.ClrType);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
internal override SqlExpression VisitBinaryOperator(SqlBinary bo) {
|
|
bo.Left = this.VisitExpression(bo.Left);
|
|
return bo;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A validator which enforces rationalized boolean expressions.
|
|
/// </summary>
|
|
internal class ExpectRationalizedBooleans : SqlBooleanMismatchVisitor {
|
|
|
|
internal ExpectRationalizedBooleans() {
|
|
}
|
|
|
|
internal override SqlExpression ConvertValueToPredicate(SqlExpression bitExpression) {
|
|
throw Error.ExpectedPredicateFoundBit();
|
|
}
|
|
|
|
internal override SqlExpression ConvertPredicateToValue(SqlExpression predicateExpression) {
|
|
throw Error.ExpectedBitFoundPredicate();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A validator which enforces that no more SqlMethodCall nodes exist in the tree.
|
|
/// </summary>
|
|
internal class ExpectNoMethodCalls : SqlVisitor {
|
|
|
|
internal override SqlExpression VisitMethodCall(SqlMethodCall mc) {
|
|
// eventually we may support this type of stuff given the SQL CLR, but for now it is illegal
|
|
throw Error.MethodHasNoSupportConversionToSql(mc.Method.Name);
|
|
}
|
|
|
|
// check everything except selection expressions (which will be client or ignored)
|
|
internal override SqlSelect VisitSelect(SqlSelect select) {
|
|
return this.VisitSelectCore(select);
|
|
}
|
|
}
|
|
|
|
internal class ExpectNoFloatingColumns : SqlVisitor {
|
|
internal override SqlRow VisitRow(SqlRow row) {
|
|
foreach (SqlColumn c in row.Columns) {
|
|
this.Visit(c.Expression);
|
|
}
|
|
return row;
|
|
}
|
|
internal override SqlTable VisitTable(SqlTable tab) {
|
|
foreach (SqlColumn c in tab.Columns) {
|
|
this.Visit(c.Expression);
|
|
}
|
|
return tab;
|
|
}
|
|
internal override SqlExpression VisitColumn(SqlColumn col) {
|
|
throw Error.UnexpectedFloatingColumn();
|
|
}
|
|
}
|
|
|
|
internal class ExpectNoAliasRefs : SqlVisitor {
|
|
internal override SqlExpression VisitAliasRef(SqlAliasRef aref) {
|
|
throw Error.UnexpectedNode(aref.NodeType);
|
|
}
|
|
}
|
|
|
|
internal class ExpectNoSharedExpressions : SqlVisitor {
|
|
internal override SqlExpression VisitSharedExpression(SqlSharedExpression shared) {
|
|
throw Error.UnexpectedSharedExpression();
|
|
}
|
|
internal override SqlExpression VisitSharedExpressionRef(SqlSharedExpressionRef sref) {
|
|
throw Error.UnexpectedSharedExpressionReference();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines if there is a boolean NText/Text/Image comparison and if so throws an exception
|
|
/// because this is not valid in SQLServer.
|
|
/// </summary>
|
|
internal class ValidateNoInvalidComparison : SqlVisitor {
|
|
|
|
internal override SqlExpression VisitBinaryOperator(SqlBinary bo) {
|
|
if (bo.NodeType == SqlNodeType.EQ || bo.NodeType == SqlNodeType.NE ||
|
|
bo.NodeType == SqlNodeType.EQ2V || bo.NodeType == SqlNodeType.NE2V ||
|
|
bo.NodeType == SqlNodeType.GT || bo.NodeType == SqlNodeType.GE ||
|
|
bo.NodeType == SqlNodeType.LT || bo.NodeType == SqlNodeType.LE ) {
|
|
if (!bo.Left.SqlType.SupportsComparison ||
|
|
!bo.Right.SqlType.SupportsComparison){
|
|
throw Error.UnhandledStringTypeComparison();
|
|
}
|
|
}
|
|
bo.Left = this.VisitExpression(bo.Left);
|
|
bo.Right = this.VisitExpression(bo.Right);
|
|
return bo;
|
|
}
|
|
|
|
}
|
|
}
|