| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- using System;
- using System.Collections.Generic;
- using System.Linq.Expressions;
- using System.Reflection;
- using System.Data.Linq;
- using System.Data.Linq.Mapping;
- using System.Data.Linq.Provider;
- using System.Linq;
- using System.Data.Linq.SqlClient;
- using System.Diagnostics.CodeAnalysis;
- using System.Diagnostics;
- namespace System.Data.Linq.SqlClient {
- // partions select expressions and common subexpressions into scalar and non-scalar pieces by
- // wrapping scalar pieces floating column nodes.
- internal class SqlColumnizer {
- ColumnNominator nominator;
- ColumnDeclarer declarer;
- internal SqlColumnizer() {
- this.nominator = new ColumnNominator();
- this.declarer = new ColumnDeclarer();
- }
- internal SqlExpression ColumnizeSelection(SqlExpression selection) {
- return this.declarer.Declare(selection, this.nominator.Nominate(selection));
- }
- internal static bool CanBeColumn(SqlExpression expression) {
- return ColumnNominator.CanBeColumn(expression);
- }
- class ColumnDeclarer : SqlVisitor {
- HashSet<SqlExpression> candidates;
- internal ColumnDeclarer() {
- }
- internal SqlExpression Declare(SqlExpression expression, HashSet<SqlExpression> candidates) {
- this.candidates = candidates;
- return (SqlExpression)this.Visit(expression);
- }
- internal override SqlNode Visit(SqlNode node) {
- SqlExpression expr = node as SqlExpression;
- if (expr != null) {
- if (this.candidates.Contains(expr)) {
- if (expr.NodeType == SqlNodeType.Column ||
- expr.NodeType == SqlNodeType.ColumnRef) {
- return expr;
- }
- else {
- return new SqlColumn(expr.ClrType, expr.SqlType, null, null, expr, expr.SourceExpression);
- }
- }
- }
- return base.Visit(node);
- }
- }
- class ColumnNominator : SqlVisitor {
- bool isBlocked;
- HashSet<SqlExpression> candidates;
- internal HashSet<SqlExpression> Nominate(SqlExpression expression) {
- this.candidates = new HashSet<SqlExpression>();
- this.isBlocked = false;
- this.Visit(expression);
- return this.candidates;
- }
- internal override SqlNode Visit(SqlNode node) {
- SqlExpression expression = node as SqlExpression;
- if (expression != null) {
- bool saveIsBlocked = this.isBlocked;
- this.isBlocked = false;
- if (CanRecurseColumnize(expression)) {
- base.Visit(expression);
- }
- if (!this.isBlocked) {
- if (CanBeColumn(expression)) {
- this.candidates.Add(expression);
- }
- else {
- this.isBlocked = true;
- }
- }
- this.isBlocked |= saveIsBlocked;
- }
- return node;
- }
- internal override SqlExpression VisitSimpleCase(SqlSimpleCase c) {
- c.Expression = this.VisitExpression(c.Expression);
- for (int i = 0, n = c.Whens.Count; i < n; i++) {
- // Don't walk down the match side. This can't be a column.
- c.Whens[i].Value = this.VisitExpression(c.Whens[i].Value);
- }
- return c;
- }
- internal override SqlExpression VisitTypeCase(SqlTypeCase tc) {
- tc.Discriminator = this.VisitExpression(tc.Discriminator);
- for (int i = 0, n = tc.Whens.Count; i < n; i++) {
- // Don't walk down the match side. This can't be a column.
- tc.Whens[i].TypeBinding = this.VisitExpression(tc.Whens[i].TypeBinding);
- }
- return tc;
- }
- internal override SqlExpression VisitClientCase(SqlClientCase c) {
- c.Expression = this.VisitExpression(c.Expression);
- for (int i = 0, n = c.Whens.Count; i < n; i++) {
- // Don't walk down the match side. This can't be a column.
- c.Whens[i].Value = this.VisitExpression(c.Whens[i].Value);
- }
- return c;
- }
- private static bool CanRecurseColumnize(SqlExpression expr) {
- switch (expr.NodeType) {
- case SqlNodeType.AliasRef:
- case SqlNodeType.ColumnRef:
- case SqlNodeType.Column:
- case SqlNodeType.Multiset:
- case SqlNodeType.Element:
- case SqlNodeType.ScalarSubSelect:
- case SqlNodeType.Exists:
- case SqlNodeType.ClientQuery:
- case SqlNodeType.SharedExpressionRef:
- case SqlNodeType.Link:
- case SqlNodeType.Nop:
- case SqlNodeType.Value:
- case SqlNodeType.Select:
- return false;
- default:
- return true;
- }
- }
- [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 IsClientOnly(SqlExpression expr) {
- switch (expr.NodeType) {
- case SqlNodeType.ClientCase:
- case SqlNodeType.TypeCase:
- case SqlNodeType.ClientArray:
- case SqlNodeType.Grouping:
- case SqlNodeType.DiscriminatedType:
- case SqlNodeType.SharedExpression:
- case SqlNodeType.SimpleExpression:
- case SqlNodeType.AliasRef:
- case SqlNodeType.Multiset:
- case SqlNodeType.Element:
- case SqlNodeType.ClientQuery:
- case SqlNodeType.SharedExpressionRef:
- case SqlNodeType.Link:
- case SqlNodeType.Nop:
- return true;
- case SqlNodeType.OuterJoinedValue:
- return IsClientOnly(((SqlUnary)expr).Operand);
- default:
- return false;
- }
- }
- internal static bool CanBeColumn(SqlExpression expression) {
- if (!IsClientOnly(expression)
- && expression.NodeType != SqlNodeType.Column
- && expression.SqlType.CanBeColumn) {
- switch (expression.NodeType) {
- case SqlNodeType.MethodCall:
- case SqlNodeType.Member:
- case SqlNodeType.New:
- return PostBindDotNetConverter.CanConvert(expression);
- default:
- return true;
- }
- }
- return false;
- }
- }
- }
- }
|