using System; using System.Collections.Generic; using System.Reflection; using System.Text; using System.Linq.Expressions; using System.Diagnostics; using System.Data; namespace System.Data.Linq.SqlClient { using System.Data.Linq.Mapping; using System.Data.Linq.Provider; using System.Diagnostics.CodeAnalysis; internal enum SqlNodeType { Add, Alias, AliasRef, And, Assign, Avg, Between, BitAnd, BitNot, BitOr, BitXor, Block, ClientArray, ClientCase, ClientParameter, ClientQuery, ClrLength, Coalesce, Column, ColumnRef, Concat, Convert, Count, Delete, DiscriminatedType, DiscriminatorOf, Div, DoNotVisit, Element, ExprSet, EQ, EQ2V, Exists, FunctionCall, In, IncludeScope, IsNotNull, IsNull, LE, Lift, Link, Like, LongCount, LT, GE, Grouping, GT, Insert, Join, JoinedCollection, Max, MethodCall, Member, MemberAssign, Min, Mod, Mul, Multiset, NE, NE2V, Negate, New, Not, Not2V, Nop, Or, OptionalValue, OuterJoinedValue, Parameter, Property, Row, RowNumber, ScalarSubSelect, SearchedCase, Select, SharedExpression, SharedExpressionRef, SimpleCase, SimpleExpression, Stddev, StoredProcedureCall, Sub, Sum, Table, TableValuedFunctionCall, Treat, TypeCase, Union, Update, UserColumn, UserQuery, UserRow, Variable, Value, ValueOf } [System.Diagnostics.DebuggerDisplay("text = {Text}, \r\nsource = {SourceExpression}")] internal abstract class SqlNode { private SqlNodeType nodeType; private Expression sourceExpression; internal SqlNode(SqlNodeType nodeType, Expression sourceExpression) { this.nodeType = nodeType; this.sourceExpression = sourceExpression; } internal Expression SourceExpression { get { return this.sourceExpression; } } internal void ClearSourceExpression() { this.sourceExpression = null; } internal SqlNodeType NodeType { get { return this.nodeType; } } #if DEBUG private static DbFormatter formatter; internal static DbFormatter Formatter { get { return formatter; } set { formatter = value; } } internal string Text { get { if (Formatter == null) return "SqlNode.Formatter is not assigned"; return SqlNode.Formatter.Format(this, true); } } #endif } internal abstract class SqlExpression : SqlNode { private Type clrType; internal SqlExpression(SqlNodeType nodeType, Type clrType, Expression sourceExpression) : base(nodeType, sourceExpression) { this.clrType = clrType; } internal Type ClrType { get { return this.clrType; } } // note: changing the CLR type of a node is potentially dangerous internal void SetClrType(Type type) { this.clrType = type; } internal abstract ProviderType SqlType { get; } /// /// Drill down looking for a constant root expression, returning true if found. /// internal bool IsConstantColumn { get { if (this.NodeType == SqlNodeType.Column) { SqlColumn col = (SqlColumn)this; if (col.Expression != null) { return col.Expression.IsConstantColumn; } } else if (this.NodeType == SqlNodeType.ColumnRef) { return ((SqlColumnRef)this).Column.IsConstantColumn; } else if (this.NodeType == SqlNodeType.OptionalValue) { return ((SqlOptionalValue)this).Value.IsConstantColumn; } else if (this.NodeType == SqlNodeType.Value || this.NodeType == SqlNodeType.Parameter) { return true; } return false; } } } /// /// A SqlExpression with a simple implementation of ClrType and SqlType. /// internal abstract class SqlSimpleTypeExpression : SqlExpression { private ProviderType sqlType; internal SqlSimpleTypeExpression(SqlNodeType nodeType, Type clrType, ProviderType sqlType, Expression sourceExpression) : base(nodeType, clrType, sourceExpression) { this.sqlType = sqlType; } internal override ProviderType SqlType { get { return this.sqlType; } } internal void SetSqlType(ProviderType type) { this.sqlType = type; } } internal class SqlDiscriminatorOf : SqlSimpleTypeExpression { SqlExpression obj; internal SqlDiscriminatorOf(SqlExpression obj, Type clrType, ProviderType sqlType, Expression sourceExpression) : base(SqlNodeType.DiscriminatorOf, clrType, sqlType, sourceExpression) { this.obj = obj; } internal SqlExpression Object { get { return this.obj; } set { this.obj = value; } } } /// /// Represents a dynamic CLR type that is chosen based on a discriminator expression. /// internal class SqlDiscriminatedType : SqlExpression { private ProviderType sqlType; private SqlExpression discriminator; private MetaType targetType; internal SqlDiscriminatedType(ProviderType sqlType, SqlExpression discriminator, MetaType targetType, Expression sourceExpression) : base(SqlNodeType.DiscriminatedType, typeof(Type), sourceExpression) { if (discriminator == null) throw Error.ArgumentNull("discriminator"); this.discriminator = discriminator; this.targetType = targetType; this.sqlType = sqlType; } internal override ProviderType SqlType { get { return this.sqlType; } } internal SqlExpression Discriminator { get { return this.discriminator; } set { this.discriminator = value; } } internal MetaType TargetType { get { return this.targetType; } } } internal abstract class SqlStatement : SqlNode { internal SqlStatement(SqlNodeType nodeType, Expression sourceExpression) : base(nodeType, sourceExpression) { } } internal abstract class SqlSource : SqlNode { internal SqlSource(SqlNodeType nt, Expression sourceExpression) : base(nt, sourceExpression) { } } internal class SqlSelect : SqlStatement { private SqlExpression top; private bool isPercent; private bool isDistinct; private SqlExpression selection; private SqlRow row; private SqlSource from; private SqlExpression where; private List groupBy; private SqlExpression having; private List orderBy; private SqlOrderingType orderingType; private bool squelch; internal SqlSelect(SqlExpression selection, SqlSource from, Expression sourceExpression) : base(SqlNodeType.Select, sourceExpression) { this.Row = new SqlRow(sourceExpression); this.Selection = selection; this.From = from; this.groupBy = new List(); this.orderBy = new List(); this.orderingType = SqlOrderingType.Default; } internal SqlExpression Top { get { return this.top; } set { this.top = value; } } internal bool IsPercent { get { return this.isPercent; } set { this.isPercent = value; } } internal bool IsDistinct { get { return this.isDistinct; } set { this.isDistinct = value; } } internal SqlExpression Selection { get { return this.selection; } set { if (value == null) throw Error.ArgumentNull("value"); this.selection = value; } } internal SqlRow Row { get { return this.row; } set { if (value == null) throw Error.ArgumentNull("value"); this.row = value; } } internal SqlSource From { get { return this.from; } set { this.from = value; } } internal SqlExpression Where { get { return this.where; } set { if (value != null && TypeSystem.GetNonNullableType(value.ClrType) != typeof(bool)) { throw Error.ArgumentWrongType("value", "bool", value.ClrType); } this.where = value; } } internal List GroupBy { get { return this.groupBy; } } internal SqlExpression Having { get { return this.having; } set { if (value != null && TypeSystem.GetNonNullableType(value.ClrType) != typeof(bool)) { throw Error.ArgumentWrongType("value", "bool", value.ClrType); } this.having = value; } } internal List OrderBy { get { return this.orderBy; } } internal SqlOrderingType OrderingType { get { return this.orderingType; } set { this.orderingType = value; } } internal bool DoNotOutput { get { return this.squelch; } set { this.squelch = value; } } } internal enum SqlOrderingType { Default, Never, Blocked, Always } internal class SqlTable : SqlNode { private MetaTable table; private MetaType rowType; private ProviderType sqlRowType; private List columns; internal SqlTable(MetaTable table, MetaType rowType, ProviderType sqlRowType, Expression sourceExpression) : base(SqlNodeType.Table, sourceExpression) { this.table = table; this.rowType = rowType; this.sqlRowType = sqlRowType; this.columns = new List(); } internal MetaTable MetaTable { get { return this.table; } } internal string Name { get { return this.table.TableName; } } internal List Columns { get { return this.columns; } } internal MetaType RowType { get { return this.rowType; } } internal ProviderType SqlRowType { get { return this.sqlRowType; } } internal SqlColumn Find(string columnName) { foreach (SqlColumn c in this.Columns) { if (c.Name == columnName) return c; } return null; } } internal class SqlUserQuery : SqlNode { private string queryText; private SqlExpression projection; private List args; private List columns; internal SqlUserQuery(SqlNodeType nt, SqlExpression projection, IEnumerable args, Expression source) : base(nt, source) { this.Projection = projection; this.args = (args != null) ? new List(args) : new List(); this.columns = new List(); } internal SqlUserQuery(string queryText, SqlExpression projection, IEnumerable args, Expression source) : base(SqlNodeType.UserQuery, source) { this.queryText = queryText; this.Projection = projection; this.args = (args != null) ? new List(args) : new List(); this.columns = new List(); } internal string QueryText { get { return this.queryText; } } internal SqlExpression Projection { get { return this.projection; } set { if (this.projection != null && this.projection.ClrType != value.ClrType) throw Error.ArgumentWrongType("value", this.projection.ClrType, value.ClrType); this.projection = value; } } internal List Arguments { get { return this.args; } } internal List Columns { get { return this.columns; } } internal SqlUserColumn Find(string name) { foreach (SqlUserColumn c in this.Columns) { if (c.Name == name) return c; } return null; } } internal class SqlStoredProcedureCall : SqlUserQuery { private MetaFunction function; internal SqlStoredProcedureCall(MetaFunction function, SqlExpression projection, IEnumerable args, Expression source) : base(SqlNodeType.StoredProcedureCall, projection, args, source) { if (function == null) throw Error.ArgumentNull("function"); this.function = function; } internal MetaFunction Function { get { return this.function; } } } internal class SqlUserRow : SqlSimpleTypeExpression { private SqlUserQuery query; private MetaType rowType; internal SqlUserRow(MetaType rowType, ProviderType sqlType, SqlUserQuery query, Expression source) : base(SqlNodeType.UserRow, rowType.Type, sqlType, source) { this.Query = query; this.rowType = rowType; } internal MetaType RowType { get { return this.rowType; } } internal SqlUserQuery Query { get { return this.query; } set { if (value == null) throw Error.ArgumentNull("value"); if (value.Projection != null && value.Projection.ClrType != this.ClrType) throw Error.ArgumentWrongType("value", this.ClrType, value.Projection.ClrType); this.query = value; } } } internal class SqlUserColumn : SqlSimpleTypeExpression { private SqlUserQuery query; private string name; private bool isRequired; internal SqlUserColumn(Type clrType, ProviderType sqlType, SqlUserQuery query, string name, bool isRequired, Expression source) : base(SqlNodeType.UserColumn, clrType, sqlType, source) { this.Query = query; this.name = name; this.isRequired = isRequired; } internal SqlUserQuery Query { get { return this.query; } set { if (value == null) throw Error.ArgumentNull("value"); if (this.query != null && this.query != value) throw Error.ArgumentWrongValue("value"); this.query = value; } } internal string Name { get { return this.name; } } internal bool IsRequired { get { return this.isRequired; } } } internal class SqlAlias : SqlSource { private string name; private SqlNode node; internal SqlAlias(SqlNode node) : base(SqlNodeType.Alias, node.SourceExpression) { this.Node = node; } internal string Name { get { return this.name; } set { this.name = value; } } internal SqlNode Node { get { return this.node; } set { if (value == null) throw Error.ArgumentNull("value"); if (!(value is SqlExpression || value is SqlSelect || value is SqlTable || value is SqlUnion)) throw Error.UnexpectedNode(value.NodeType); this.node = value; } } } internal class SqlAliasRef : SqlExpression { private SqlAlias alias; internal SqlAliasRef(SqlAlias alias) : base(SqlNodeType.AliasRef, GetClrType(alias.Node), alias.SourceExpression) { if (alias == null) throw Error.ArgumentNull("alias"); this.alias = alias; } internal SqlAlias Alias { get { return this.alias; } } internal override ProviderType SqlType { get { return GetSqlType(this.alias.Node); } } private static Type GetClrType(SqlNode node) { SqlTableValuedFunctionCall tvf = node as SqlTableValuedFunctionCall; if (tvf != null) return tvf.RowType.Type; SqlExpression exp = node as SqlExpression; if (exp != null) { if (TypeSystem.IsSequenceType(exp.ClrType)) return TypeSystem.GetElementType(exp.ClrType); return exp.ClrType; } SqlSelect sel = node as SqlSelect; if (sel != null) return sel.Selection.ClrType; SqlTable tab = node as SqlTable; if (tab != null) return tab.RowType.Type; SqlUnion su = node as SqlUnion; if (su != null) return su.GetClrType(); throw Error.UnexpectedNode(node.NodeType); } private static ProviderType GetSqlType(SqlNode node) { SqlExpression exp = node as SqlExpression; if (exp != null) return exp.SqlType; SqlSelect sel = node as SqlSelect; if (sel != null) return sel.Selection.SqlType; SqlTable tab = node as SqlTable; if (tab != null) return tab.SqlRowType; SqlUnion su = node as SqlUnion; if (su != null) return su.GetSqlType(); throw Error.UnexpectedNode(node.NodeType); } } internal class SqlJoin : SqlSource { private SqlJoinType joinType; private SqlSource left; private SqlSource right; private SqlExpression condition; internal SqlJoin(SqlJoinType type, SqlSource left, SqlSource right, SqlExpression cond, Expression sourceExpression) : base(SqlNodeType.Join, sourceExpression) { this.JoinType = type; this.Left = left; this.Right = right; this.Condition = cond; } internal SqlJoinType JoinType { get { return this.joinType; } set { this.joinType = value; } } internal SqlSource Left { get { return this.left; } set { if (value == null) throw Error.ArgumentNull("value"); this.left = value; } } internal SqlSource Right { get { return this.right; } set { if (value == null) throw Error.ArgumentNull("value"); this.right = value; } } internal SqlExpression Condition { get { return this.condition; } set { this.condition = value; } } } internal enum SqlJoinType { Cross, Inner, LeftOuter, CrossApply, OuterApply } internal class SqlUnion : SqlNode { private SqlNode left; private SqlNode right; private bool all; internal SqlUnion(SqlNode left, SqlNode right, bool all) : base(SqlNodeType.Union, right.SourceExpression) { this.Left = left; this.Right = right; this.All = all; } internal SqlNode Left { get { return this.left; } set { Validate(value); this.left = value; } } internal SqlNode Right { get { return this.right; } set { Validate(value); this.right = value; } } internal bool All { get { return this.all; } set { this.all = value; } } [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")] private void Validate(SqlNode node) { if (node == null) throw Error.ArgumentNull("node"); if (!(node is SqlExpression || node is SqlSelect || node is SqlUnion)) throw Error.UnexpectedNode(node.NodeType); } internal Type GetClrType() { SqlExpression exp = this.Left as SqlExpression; if (exp != null) return exp.ClrType; SqlSelect sel = this.Left as SqlSelect; if (sel != null) return sel.Selection.ClrType; throw Error.CouldNotGetClrType(); } internal ProviderType GetSqlType() { SqlExpression exp = this.Left as SqlExpression; if (exp != null) return exp.SqlType; SqlSelect sel = this.Left as SqlSelect; if (sel != null) return sel.Selection.SqlType; throw Error.CouldNotGetSqlType(); } } internal class SqlNop : SqlSimpleTypeExpression { internal SqlNop(Type clrType, ProviderType sqlType, Expression sourceExpression) : base(SqlNodeType.Nop, clrType, sqlType, sourceExpression) { } } internal class SqlLift : SqlExpression { internal SqlExpression liftedExpression; internal SqlLift(Type type, SqlExpression liftedExpression, Expression sourceExpression) : base(SqlNodeType.Lift, type, sourceExpression) { if (liftedExpression == null) throw Error.ArgumentNull("liftedExpression"); this.liftedExpression = liftedExpression; } internal SqlExpression Expression { get { return this.liftedExpression; } set { if (value == null) throw Error.ArgumentNull("value"); this.liftedExpression = value; } } internal override ProviderType SqlType { get { return this.liftedExpression.SqlType; } } } internal enum SqlOrderType { Ascending, Descending } internal class SqlOrderExpression : IEquatable { private SqlOrderType orderType; private SqlExpression expression; internal SqlOrderExpression(SqlOrderType type, SqlExpression expr) { this.OrderType = type; this.Expression = expr; } internal SqlOrderType OrderType { get { return this.orderType; } set { this.orderType = value; } } internal SqlExpression Expression { get { return this.expression; } set { if (value == null) throw Error.ArgumentNull("value"); if (this.expression != null && !this.expression.ClrType.IsAssignableFrom(value.ClrType)) throw Error.ArgumentWrongType("value", this.expression.ClrType, value.ClrType); this.expression = value; } } public override bool Equals(object obj) { if (this.EqualsTo(obj as SqlOrderExpression)) return true; return base.Equals(obj); } public bool Equals(SqlOrderExpression other) { if (this.EqualsTo(other)) return true; return base.Equals(other); } private bool EqualsTo(SqlOrderExpression other) { if (other == null) return false; if (object.ReferenceEquals(this, other)) return true; if (this.OrderType != other.OrderType) return false; if (!this.Expression.SqlType.Equals(other.Expression.SqlType)) return false; SqlColumn col1 = SqlOrderExpression.UnwrapColumn(this.Expression); SqlColumn col2 = SqlOrderExpression.UnwrapColumn(other.Expression); if (col1 == null || col2 == null) return false; return col1 == col2; } public override int GetHashCode() { SqlColumn col = SqlOrderExpression.UnwrapColumn(this.Expression); if (col != null) return col.GetHashCode(); return base.GetHashCode(); } private static SqlColumn UnwrapColumn(SqlExpression expr) { System.Diagnostics.Debug.Assert(expr != null); SqlUnary exprAsUnary = expr as SqlUnary; if (exprAsUnary != null) { expr = exprAsUnary.Operand; } SqlColumn exprAsColumn = expr as SqlColumn; if (exprAsColumn != null) { return exprAsColumn; } SqlColumnRef exprAsColumnRef = expr as SqlColumnRef; if (exprAsColumnRef != null) { return exprAsColumnRef.GetRootColumn(); } // // For all other types return null to revert to default behavior for Equals() // and GetHashCode() // return null; } } internal class SqlRowNumber : SqlSimpleTypeExpression { private List orderBy; internal List OrderBy { get { return orderBy; } } internal SqlRowNumber(Type clrType, ProviderType sqlType, List orderByList, Expression sourceExpression) : base(SqlNodeType.RowNumber, clrType, sqlType, sourceExpression) { if (orderByList == null) { throw Error.ArgumentNull("orderByList"); } this.orderBy = orderByList; } } internal class SqlUnary : SqlSimpleTypeExpression { private SqlExpression operand; private MethodInfo method; [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.")] internal SqlUnary(SqlNodeType nt, Type clrType, ProviderType sqlType, SqlExpression expr, Expression sourceExpression) : this(nt, clrType, sqlType, expr, null, sourceExpression) { } internal SqlUnary(SqlNodeType nt, Type clrType, ProviderType sqlType, SqlExpression expr, MethodInfo method, Expression sourceExpression) : base(nt, clrType, sqlType, sourceExpression) { switch (nt) { case SqlNodeType.Not: case SqlNodeType.Not2V: case SqlNodeType.Negate: case SqlNodeType.BitNot: case SqlNodeType.IsNull: case SqlNodeType.IsNotNull: case SqlNodeType.Count: case SqlNodeType.LongCount: case SqlNodeType.Max: case SqlNodeType.Min: case SqlNodeType.Sum: case SqlNodeType.Avg: case SqlNodeType.Stddev: case SqlNodeType.Convert: case SqlNodeType.ValueOf: case SqlNodeType.Treat: case SqlNodeType.OuterJoinedValue: case SqlNodeType.ClrLength: break; default: throw Error.UnexpectedNode(nt); } this.Operand = expr; this.method = method; } internal SqlExpression Operand { get { return this.operand; } set { if (value == null && (this.NodeType != SqlNodeType.Count && this.NodeType != SqlNodeType.LongCount)) throw Error.ArgumentNull("value"); this.operand = value; } } internal MethodInfo Method { get { return this.method; } } } internal class SqlBinary : SqlSimpleTypeExpression { private SqlExpression left; private SqlExpression right; private MethodInfo method; [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.")] internal SqlBinary(SqlNodeType nt, Type clrType, ProviderType sqlType, SqlExpression left, SqlExpression right) : this(nt, clrType, sqlType, left, right, null) { } internal SqlBinary(SqlNodeType nt, Type clrType, ProviderType sqlType, SqlExpression left, SqlExpression right, MethodInfo method) : base(nt, clrType, sqlType, right.SourceExpression) { switch (nt) { case SqlNodeType.Add: case SqlNodeType.Sub: case SqlNodeType.Mul: case SqlNodeType.Div: case SqlNodeType.Mod: case SqlNodeType.BitAnd: case SqlNodeType.BitOr: case SqlNodeType.BitXor: case SqlNodeType.And: case SqlNodeType.Or: case SqlNodeType.GE: case SqlNodeType.GT: case SqlNodeType.LE: case SqlNodeType.LT: case SqlNodeType.EQ: case SqlNodeType.NE: case SqlNodeType.EQ2V: case SqlNodeType.NE2V: case SqlNodeType.Concat: case SqlNodeType.Coalesce: break; default: throw Error.UnexpectedNode(nt); } this.Left = left; this.Right = right; this.method = method; } internal SqlExpression Left { get { return this.left; } set { if (value == null) throw Error.ArgumentNull("value"); this.left = value; } } internal SqlExpression Right { get { return this.right; } set { if (value == null) throw Error.ArgumentNull("value"); this.right = value; } } internal MethodInfo Method { get { return this.method; } } } internal class SqlBetween : SqlSimpleTypeExpression { SqlExpression expression; SqlExpression start; SqlExpression end; internal SqlBetween(Type clrType, ProviderType sqlType, SqlExpression expr, SqlExpression start, SqlExpression end, Expression source) : base(SqlNodeType.Between, clrType, sqlType, source) { this.expression = expr; this.start = start; this.end = end; } internal SqlExpression Expression { get { return this.expression; } set { this.expression = value; } } internal SqlExpression Start { get { return this.start; } set { this.start = value; } } internal SqlExpression End { get { return this.end; } set { this.end = value; } } } internal class SqlIn : SqlSimpleTypeExpression { private SqlExpression expression; private List values; internal SqlIn(Type clrType, ProviderType sqlType, SqlExpression expression, IEnumerable values, Expression sourceExpression) :base(SqlNodeType.In, clrType, sqlType, sourceExpression) { this.expression = expression; this.values = values != null ? new List(values) : new List(0); } internal SqlExpression Expression { get { return this.expression; } set { if (value == null) { throw Error.ArgumentNull("value"); } this.expression = value; } } internal List Values { get { return this.values; } } } internal class SqlLike : SqlSimpleTypeExpression { private SqlExpression expression; private SqlExpression pattern; private SqlExpression escape; internal SqlLike(Type clrType, ProviderType sqlType, SqlExpression expr, SqlExpression pattern, SqlExpression escape, Expression source) : base(SqlNodeType.Like, clrType, sqlType, source) { if (expr == null) throw Error.ArgumentNull("expr"); if (pattern == null) throw Error.ArgumentNull("pattern"); this.Expression = expr; this.Pattern = pattern; this.Escape = escape; } internal SqlExpression Expression { get { return this.expression; } set { if (value == null) throw Error.ArgumentNull("value"); if (value.ClrType != typeof(string)) throw Error.ArgumentWrongType("value", "string", value.ClrType); this.expression = value; } } internal SqlExpression Pattern { get { return this.pattern; } set { if (value == null) throw Error.ArgumentNull("value"); if (value.ClrType != typeof(string)) throw Error.ArgumentWrongType("value", "string", value.ClrType); this.pattern = value; } } internal SqlExpression Escape { get { return this.escape; } set { if (value != null && value.ClrType != typeof(string)) throw Error.ArgumentWrongType("value", "string", value.ClrType); this.escape = value; } } } internal class SqlWhen { private SqlExpression matchExpression; private SqlExpression valueExpression; internal SqlWhen(SqlExpression match, SqlExpression value) { // 'match' may be null when this when represents the ELSE condition. if (value == null) throw Error.ArgumentNull("value"); this.Match = match; this.Value = value; } internal SqlExpression Match { get { return this.matchExpression; } set { if (this.matchExpression != null && value != null && this.matchExpression.ClrType != value.ClrType // Exception: bool types, because predicates can have type bool or bool? && !TypeSystem.GetNonNullableType(this.matchExpression.ClrType).Equals(typeof(bool)) && !TypeSystem.GetNonNullableType(value.ClrType).Equals(typeof(bool))) throw Error.ArgumentWrongType("value", this.matchExpression.ClrType, value.ClrType); this.matchExpression = value; } } internal SqlExpression Value { get { return this.valueExpression; } set { if (value == null) throw Error.ArgumentNull("value"); if (this.valueExpression != null && !this.valueExpression.ClrType.IsAssignableFrom(value.ClrType)) throw Error.ArgumentWrongType("value", this.valueExpression.ClrType, value.ClrType); this.valueExpression = value; } } } /* * Searched CASE function: * CASE * WHEN BooleanExpression THEN resultExpression * [ ...n ] * [ * ELSE elseResultExpression * ] * END */ internal class SqlSearchedCase : SqlExpression { private List whens; private SqlExpression @else; internal SqlSearchedCase(Type clrType, IEnumerable whens, SqlExpression @else, Expression sourceExpression) : base(SqlNodeType.SearchedCase, clrType, sourceExpression) { if (whens == null) throw Error.ArgumentNull("whens"); this.whens = new List(whens); if (this.whens.Count == 0) throw Error.ArgumentOutOfRange("whens"); this.Else = @else; } internal List Whens { get { return this.whens; } } internal SqlExpression Else { get { return this.@else; } set { if (value == null) throw Error.ArgumentNull("value"); if (this.@else != null && !this.@else.ClrType.IsAssignableFrom(value.ClrType)) throw Error.ArgumentWrongType("value", this.@else.ClrType, value.ClrType); this.@else = value; } } internal override ProviderType SqlType { get { return this.whens[0].Value.SqlType; } } } /* * Simple CASE function: * CASE inputExpression * WHEN whenExpression THEN resultExpression * [ ...n ] * [ * ELSE elseResultExpression * ] * END */ internal class SqlSimpleCase : SqlExpression { private SqlExpression expression; private List whens = new List(); internal SqlSimpleCase(Type clrType, SqlExpression expr, IEnumerable whens, Expression sourceExpression) : base(SqlNodeType.SimpleCase, clrType, sourceExpression) { this.Expression = expr; if (whens == null) throw Error.ArgumentNull("whens"); this.whens.AddRange(whens); if (this.whens.Count == 0) throw Error.ArgumentOutOfRange("whens"); } internal SqlExpression Expression { get { return this.expression; } set { if (value == null) throw Error.ArgumentNull("value"); if (this.expression != null && this.expression.ClrType != value.ClrType) throw Error.ArgumentWrongType("value", this.expression.ClrType, value.ClrType); this.expression = value; } } internal List Whens { get { return this.whens; } } internal override ProviderType SqlType { get { return this.whens[0].Value.SqlType; } } } /// /// A case statement that must be evaluated on the client. For example, a case statement /// that contains values of LINK, Element, or Multi-set are not directly handleable by /// SQL. /// /// CASE inputExpression /// WHEN whenExpression THEN resultExpression /// [ ...n ] /// END /// internal class SqlClientCase : SqlExpression { private SqlExpression expression; private List whens = new List(); internal SqlClientCase(Type clrType, SqlExpression expr, IEnumerable whens, Expression sourceExpression) : base(SqlNodeType.ClientCase, clrType, sourceExpression) { this.Expression = expr; if (whens == null) throw Error.ArgumentNull("whens"); this.whens.AddRange(whens); if (this.whens.Count == 0) throw Error.ArgumentOutOfRange("whens"); } internal SqlExpression Expression { get { return this.expression; } set { if (value == null) throw Error.ArgumentNull("value"); if (this.expression != null && this.expression.ClrType != value.ClrType) throw Error.ArgumentWrongType("value", this.expression.ClrType, value.ClrType); this.expression = value; } } internal List Whens { get { return this.whens; } } internal override ProviderType SqlType { get { return this.whens[0].Value.SqlType; } } } /// /// A single WHEN clause for ClientCase. /// internal class SqlClientWhen { private SqlExpression matchExpression; private SqlExpression matchValue; internal SqlClientWhen(SqlExpression match, SqlExpression value) { // 'match' may be null when this when represents the ELSE condition. if (value == null) throw Error.ArgumentNull("value"); this.Match = match; this.Value = value; } internal SqlExpression Match { get { return this.matchExpression; } set { if (this.matchExpression != null && value != null && this.matchExpression.ClrType != value.ClrType) throw Error.ArgumentWrongType("value", this.matchExpression.ClrType, value.ClrType); this.matchExpression = value; } } internal SqlExpression Value { get { return this.matchValue; } set { if (value == null) throw Error.ArgumentNull("value"); if (this.matchValue != null && this.matchValue.ClrType != value.ClrType) throw Error.ArgumentWrongType("value", this.matchValue.ClrType, value.ClrType); this.matchValue = value; } } } /// /// Represents the construction of an object in abstract 'super sql'. /// The type may be polymorphic. A discriminator field is used to determine /// which type in a hierarchy should be instantiated. /// In the common degenerate case where the inheritance hierarchy is 1-deep /// the discriminator will be a constant SqlValue and there will be one /// type-case-when corresponding to that type. /// internal class SqlTypeCase : SqlExpression { private MetaType rowType; private SqlExpression discriminator; private List whens = new List(); ProviderType sqlType; internal SqlTypeCase(Type clrType, ProviderType sqlType, MetaType rowType, SqlExpression discriminator, IEnumerable whens, Expression sourceExpression) : base(SqlNodeType.TypeCase, clrType, sourceExpression) { this.Discriminator = discriminator; if (whens == null) throw Error.ArgumentNull("whens"); this.whens.AddRange(whens); if (this.whens.Count == 0) throw Error.ArgumentOutOfRange("whens"); this.sqlType = sqlType; this.rowType = rowType; } internal SqlExpression Discriminator { get { return this.discriminator; } set { if (value == null) throw Error.ArgumentNull("value"); if (this.discriminator != null && this.discriminator.ClrType != value.ClrType) throw Error.ArgumentWrongType("value", this.discriminator.ClrType, value.ClrType); this.discriminator = value; } } internal List Whens { get { return this.whens; } } internal override ProviderType SqlType { get { return sqlType; } } internal MetaType RowType { get { return this.rowType; } } } /// /// Represents one choice of object instantiation type in a type case. /// When 'match' is the same as type case Discriminator then the corresponding /// type binding is the one used for instantiation. /// internal class SqlTypeCaseWhen { private SqlExpression match; private SqlExpression @new; internal SqlTypeCaseWhen(SqlExpression match, SqlExpression typeBinding) { this.Match = match; this.TypeBinding = typeBinding; } internal SqlExpression Match { get { return this.match; } set { if (this.match != null && value != null && this.match.ClrType != value.ClrType) throw Error.ArgumentWrongType("value", this.match.ClrType, value.ClrType); this.match = value; } } internal SqlExpression TypeBinding { get { return this.@new; } set { this.@new = value; } } } internal class SqlValue : SqlSimpleTypeExpression { private object value; private bool isClient; internal SqlValue(Type clrType, ProviderType sqlType, object value, bool isClientSpecified, Expression sourceExpression) : base(SqlNodeType.Value, clrType, sqlType, sourceExpression) { this.value = value; this.isClient = isClientSpecified; } internal object Value { get { return this.value; } } internal bool IsClientSpecified { get { return this.isClient; } } } internal class SqlParameter : SqlSimpleTypeExpression { private string name; private System.Data.ParameterDirection direction; internal SqlParameter(Type clrType, ProviderType sqlType, string name, Expression sourceExpression) : base(SqlNodeType.Parameter, clrType, sqlType, sourceExpression) { if (name == null) throw Error.ArgumentNull("name"); if (typeof(Type).IsAssignableFrom(clrType)) throw Error.ArgumentWrongValue("clrType"); this.name = name; this.direction = System.Data.ParameterDirection.Input; } internal string Name { get { return this.name; } } internal System.Data.ParameterDirection Direction { get { return this.direction; } set { this.direction = value; } } } internal class SqlVariable : SqlSimpleTypeExpression { private string name; internal SqlVariable(Type clrType, ProviderType sqlType, string name, Expression sourceExpression) : base(SqlNodeType.Variable, clrType, sqlType, sourceExpression) { if (name == null) throw Error.ArgumentNull("name"); this.name = name; } internal string Name { get { return this.name; } } } internal class SqlMember : SqlSimpleTypeExpression { private SqlExpression expression; private MemberInfo member; internal SqlMember(Type clrType, ProviderType sqlType, SqlExpression expr, MemberInfo member) : base(SqlNodeType.Member, clrType, sqlType, expr.SourceExpression) { this.member = member; this.Expression = expr; } internal MemberInfo Member { get { return this.member; } } internal SqlExpression Expression { get { return this.expression; } set { if (value == null) throw Error.ArgumentNull("value"); if (!this.member.ReflectedType.IsAssignableFrom(value.ClrType) && !value.ClrType.IsAssignableFrom(this.member.ReflectedType)) throw Error.MemberAccessIllegal(this.member, this.member.ReflectedType, value.ClrType); this.expression = value; } } } internal class SqlColumn : SqlExpression { private SqlAlias alias; private string name; private int ordinal; private MetaDataMember member; private SqlExpression expression; private ProviderType sqlType; internal SqlColumn(Type clrType, ProviderType sqlType, string name, MetaDataMember member, SqlExpression expr, Expression sourceExpression) : base(SqlNodeType.Column, clrType, sourceExpression) { if (typeof(Type).IsAssignableFrom(clrType)) throw Error.ArgumentWrongValue("clrType"); this.Name = name; this.member = member; this.Expression = expr; this.Ordinal = -1; if (sqlType == null) throw Error.ArgumentNull("sqlType"); this.sqlType = sqlType; System.Diagnostics.Debug.Assert(sqlType.CanBeColumn); } internal SqlColumn(string name, SqlExpression expr) : this(expr.ClrType, expr.SqlType, name, null, expr, expr.SourceExpression) { System.Diagnostics.Debug.Assert(expr != null); } internal SqlAlias Alias { get { return this.alias; } set { this.alias = value; } } internal string Name { get { return this.name; } set { this.name = value; } } internal int Ordinal { get { return this.ordinal; } set { this.ordinal = value; } } internal MetaDataMember MetaMember { get { return this.member; } } /// /// Set the column's Expression. This can change the type of the column. /// internal SqlExpression Expression { get { return this.expression; } set { if (value != null) { if (!this.ClrType.IsAssignableFrom(value.ClrType)) throw Error.ArgumentWrongType("value", this.ClrType, value.ClrType); SqlColumnRef cref = value as SqlColumnRef; if (cref != null && cref.Column == this) throw Error.ColumnCannotReferToItself(); } this.expression = value; } } internal override ProviderType SqlType { get { if (this.expression != null) return this.expression.SqlType; return this.sqlType; } } } internal class SqlColumnRef : SqlExpression { private SqlColumn column; internal SqlColumnRef(SqlColumn col) : base(SqlNodeType.ColumnRef, col.ClrType, col.SourceExpression) { this.column = col; } internal SqlColumn Column { get { return this.column; } } internal override ProviderType SqlType { get { return this.column.SqlType; } } public override bool Equals(object obj) { SqlColumnRef cref = obj as SqlColumnRef; return cref != null && cref.Column == this.column; } public override int GetHashCode() { return this.column.GetHashCode(); } internal SqlColumn GetRootColumn() { SqlColumn c = this.column; while (c.Expression != null && c.Expression.NodeType == SqlNodeType.ColumnRef) { c = ((SqlColumnRef)c.Expression).Column; } return c; } } internal class SqlRow : SqlNode { private List columns; internal SqlRow(Expression sourceExpression) : base(SqlNodeType.Row, sourceExpression) { this.columns = new List(); } internal List Columns { get { return this.columns; } } internal SqlColumn Find(string name) { foreach (SqlColumn c in this.columns) { if (name == c.Name) return c; } return null; } } internal class SqlMemberAssign : SqlNode { private MemberInfo member; private SqlExpression expression; internal SqlMemberAssign(MemberInfo member, SqlExpression expr) : base(SqlNodeType.MemberAssign, expr.SourceExpression) { if (member == null) throw Error.ArgumentNull("member"); this.member = member; this.Expression = expr; } internal MemberInfo Member { get { return this.member; } } internal SqlExpression Expression { get { return this.expression; } set { if (value == null) throw Error.ArgumentNull("value"); this.expression = value; } } } internal class SqlGrouping : SqlSimpleTypeExpression { private SqlExpression key; private SqlExpression group; internal SqlGrouping(Type clrType, ProviderType sqlType, SqlExpression key, SqlExpression group, Expression sourceExpression) : base(SqlNodeType.Grouping, clrType, sqlType, sourceExpression) { if (key == null) throw Error.ArgumentNull("key"); if (group == null) throw Error.ArgumentNull("group"); this.key = key; this.group = group; } internal SqlExpression Key { get { return this.key; } set { if (value == null) throw Error.ArgumentNull("value"); if (!this.key.ClrType.IsAssignableFrom(value.ClrType) && !value.ClrType.IsAssignableFrom(this.key.ClrType)) throw Error.ArgumentWrongType("value", this.key.ClrType, value.ClrType); this.key = value; } } internal SqlExpression Group { get { return this.group; } set { if (value == null) throw Error.ArgumentNull("value"); if (value.ClrType != this.group.ClrType) throw Error.ArgumentWrongType("value", this.group.ClrType, value.ClrType); this.group = value; } } } internal class SqlNew : SqlSimpleTypeExpression { private MetaType metaType; private ConstructorInfo constructor; private List args; private List argMembers; private List members; internal SqlNew(MetaType metaType, ProviderType sqlType, ConstructorInfo cons, IEnumerable args, IEnumerable argMembers, IEnumerable members, Expression sourceExpression) : base(SqlNodeType.New, metaType.Type, sqlType, sourceExpression) { this.metaType = metaType; if (cons == null && metaType.Type.IsClass) { // structs do not need to have a constructor throw Error.ArgumentNull("cons"); } this.constructor = cons; this.args = new List(); this.argMembers = new List(); this.members = new List(); if (args != null) { this.args.AddRange(args); } if (argMembers != null) { this.argMembers.AddRange(argMembers); } if (members != null) { this.members.AddRange(members); } } internal MetaType MetaType { get { return this.metaType; } } internal ConstructorInfo Constructor { get { return this.constructor; } } internal List Args { get { return this.args; } } internal List ArgMembers { get { return this.argMembers; } } internal List Members { get { return this.members; } } internal SqlExpression Find(MemberInfo mi) { for (int i = 0, n = this.argMembers.Count; i < n; i++) { MemberInfo argmi = this.argMembers[i]; if (argmi.Name == mi.Name) { return this.args[i]; } } foreach (SqlMemberAssign ma in this.Members) { if (ma.Member.Name == mi.Name) { return ma.Expression; } } return null; } } internal class SqlMethodCall : SqlSimpleTypeExpression { private MethodInfo method; private SqlExpression obj; private List arguments; internal SqlMethodCall(Type clrType, ProviderType sqlType, MethodInfo method, SqlExpression obj, IEnumerable args, Expression sourceExpression) : base(SqlNodeType.MethodCall, clrType, sqlType, sourceExpression) { if (method == null) throw Error.ArgumentNull("method"); this.method = method; this.Object = obj; this.arguments = new List(); if (args != null) this.arguments.AddRange(args); } internal MethodInfo Method { get { return this.method; } } internal SqlExpression Object { get { return this.obj; } set { if (value == null && !this.method.IsStatic) throw Error.ArgumentNull("value"); if (value != null && !this.method.DeclaringType.IsAssignableFrom(value.ClrType)) throw Error.ArgumentWrongType("value", this.method.DeclaringType, value.ClrType); this.obj = value; } } internal List Arguments { get { return this.arguments; } } } internal class SqlIncludeScope : SqlNode { SqlNode child; internal SqlIncludeScope(SqlNode child, Expression sourceExpression) : base(SqlNodeType.IncludeScope, sourceExpression) { this.child = child; } internal SqlNode Child { get {return this.child;} set {this.child = value;} } } internal class SqlClientArray : SqlSimpleTypeExpression { private List expressions; internal SqlClientArray(Type clrType, ProviderType sqlType, SqlExpression[ ] exprs, Expression sourceExpression) : base(SqlNodeType.ClientArray, clrType, sqlType, sourceExpression) { this.expressions = new List(); if (exprs != null) this.Expressions.AddRange(exprs); } internal List Expressions { get { return this.expressions; } } } internal class SqlLink : SqlSimpleTypeExpression { private MetaType rowType; private SqlExpression expression; private MetaDataMember member; private List keyExpressions; private SqlExpression expansion; private object id; internal SqlLink(object id, MetaType rowType, Type clrType, ProviderType sqlType, SqlExpression expression, MetaDataMember member, IEnumerable keyExpressions, SqlExpression expansion, Expression sourceExpression) : base(SqlNodeType.Link, clrType, sqlType, sourceExpression) { this.id = id; this.rowType = rowType; this.expansion = expansion; this.expression = expression; this.member = member; this.keyExpressions = new List(); if (keyExpressions != null) this.keyExpressions.AddRange(keyExpressions); } internal MetaType RowType { get { return this.rowType; } } internal SqlExpression Expansion { get { return this.expansion; } set { this.expansion = value; } } internal SqlExpression Expression { get { return this.expression; } set { this.expression = value; } } internal MetaDataMember Member { get { return this.member; } } internal List KeyExpressions { get { return this.keyExpressions; } } internal object Id { get { return this.id; } } } internal class SqlExprSet : SqlExpression { private List expressions; internal SqlExprSet(Type clrType, IEnumerable exprs, Expression sourceExpression) : base(SqlNodeType.ExprSet, clrType, sourceExpression) { this.expressions = new List(exprs); } internal List Expressions { get { return this.expressions; } } /// /// Get the first non-set expression of the set by drilling /// down the left expressions. /// internal SqlExpression GetFirstExpression() { SqlExpression expr = expressions[0]; while (expr is SqlExprSet) { expr = ((SqlExprSet)expr).Expressions[0]; } return expr; } internal override ProviderType SqlType { get { return this.expressions[0].SqlType; } } } internal class SqlSubSelect : SqlSimpleTypeExpression { private SqlSelect select; internal SqlSubSelect(SqlNodeType nt , Type clrType, ProviderType sqlType , SqlSelect select) : base(nt, clrType, sqlType, select.SourceExpression) { switch (nt) { case SqlNodeType.Multiset: case SqlNodeType.ScalarSubSelect: case SqlNodeType.Element: case SqlNodeType.Exists: break; default: throw Error.UnexpectedNode(nt); } this.Select = select; } internal SqlSelect Select { get { return this.select; } set { if (value == null) throw Error.ArgumentNull("value"); this.select = value; } } } internal class SqlClientQuery : SqlSimpleTypeExpression { private SqlSubSelect query; private List arguments; private List parameters; int ordinal; internal SqlClientQuery(SqlSubSelect subquery) : base(SqlNodeType.ClientQuery, subquery.ClrType, subquery.SqlType, subquery.SourceExpression) { this.query = subquery; this.arguments = new List(); this.parameters = new List(); } internal SqlSubSelect Query { get { return this.query; } set { if (value == null || (this.query != null && this.query.ClrType != value.ClrType)) throw Error.ArgumentWrongType(value, this.query.ClrType, value.ClrType); this.query = value; } } internal List Arguments { get { return this.arguments; } } internal List Parameters { get { return this.parameters; } } internal int Ordinal { get { return this.ordinal; } set { this.ordinal = value; } } } internal class SqlJoinedCollection : SqlSimpleTypeExpression { private SqlExpression expression; private SqlExpression count; internal SqlJoinedCollection(Type clrType, ProviderType sqlType, SqlExpression expression, SqlExpression count, Expression sourceExpression) : base(SqlNodeType.JoinedCollection, clrType, sqlType, sourceExpression) { this.expression = expression; this.count = count; } internal SqlExpression Expression { get { return this.expression; } set { if (value == null || this.expression != null && this.expression.ClrType != value.ClrType) throw Error.ArgumentWrongType(value, this.expression.ClrType, value.ClrType); this.expression = value; } } internal SqlExpression Count { get { return this.count; } set { if (value == null) throw Error.ArgumentNull("value"); if (value.ClrType != typeof(int)) throw Error.ArgumentWrongType(value, typeof(int), value.ClrType); this.count = value; } } } internal class SqlUpdate : SqlStatement { private SqlSelect select; private List assignments; internal SqlUpdate(SqlSelect select, IEnumerable assignments, Expression sourceExpression) : base(SqlNodeType.Update, sourceExpression) { this.Select = select; this.assignments = new List(assignments); } internal SqlSelect Select { get { return this.select; } set { if (value == null) throw Error.ArgumentNull("value"); this.select = value; } } internal List Assignments { get { return this.assignments; } } } internal class SqlInsert : SqlStatement { private SqlTable table; private SqlRow row; private SqlExpression expression; private SqlColumn outputKey; private bool outputToLocal; internal SqlInsert(SqlTable table, SqlExpression expr, Expression sourceExpression) : base(SqlNodeType.Insert, sourceExpression) { this.Table = table; this.Expression = expr; this.Row = new SqlRow(sourceExpression); } internal SqlTable Table { get { return this.table; } set { if (value == null) throw Error.ArgumentNull("null"); this.table = value; } } internal SqlRow Row { get { return this.row; } set { this.row = value; } } internal SqlExpression Expression { get { return this.expression; } set { if (value == null) throw Error.ArgumentNull("null"); if (!this.table.RowType.Type.IsAssignableFrom(value.ClrType)) throw Error.ArgumentWrongType("value", this.table.RowType, value.ClrType); this.expression = value; } } internal SqlColumn OutputKey { get { return this.outputKey; } set { this.outputKey = value; } } internal bool OutputToLocal { get { return this.outputToLocal; } set { this.outputToLocal = value; } } } internal class SqlDelete : SqlStatement { private SqlSelect select; internal SqlDelete(SqlSelect select, Expression sourceExpression) : base(SqlNodeType.Delete, sourceExpression) { this.Select = select; } internal SqlSelect Select { get { return this.select; } set { if (value == null) throw Error.ArgumentNull("value"); this.select = value; } } } internal class SqlBlock : SqlStatement { private List statements; internal SqlBlock(Expression sourceExpression) : base(SqlNodeType.Block, sourceExpression) { this.statements = new List(); } internal List Statements { get { return this.statements; } } } internal class SqlAssign : SqlStatement { private SqlExpression leftValue; private SqlExpression rightValue; internal SqlAssign(SqlExpression lValue, SqlExpression rValue, Expression sourceExpression) : base(SqlNodeType.Assign, sourceExpression) { this.LValue = lValue; this.RValue = rValue; } internal SqlExpression LValue { get { return this.leftValue; } set { if (value == null) throw Error.ArgumentNull("value"); if (this.rightValue != null && !value.ClrType.IsAssignableFrom(this.rightValue.ClrType)) throw Error.ArgumentWrongType("value", this.rightValue.ClrType, value.ClrType); this.leftValue = value; } } internal SqlExpression RValue { get { return this.rightValue; } set { if (value == null) throw Error.ArgumentNull("value"); if (this.leftValue != null && !this.leftValue.ClrType.IsAssignableFrom(value.ClrType)) throw Error.ArgumentWrongType("value", this.leftValue.ClrType, value.ClrType); this.rightValue = value; } } } internal class SqlDoNotVisitExpression : SqlExpression { private SqlExpression expression; internal SqlDoNotVisitExpression(SqlExpression expr) : base(SqlNodeType.DoNotVisit, expr.ClrType, expr.SourceExpression) { if (expr == null) throw Error.ArgumentNull("expr"); this.expression = expr; } internal SqlExpression Expression { get { return this.expression; } } internal override ProviderType SqlType { get { return this.expression.SqlType; } } } internal class SqlOptionalValue : SqlSimpleTypeExpression { private SqlExpression hasValue; private SqlExpression expressionValue; internal SqlOptionalValue( SqlExpression hasValue, SqlExpression value) : base(SqlNodeType.OptionalValue, value.ClrType, value.SqlType, value.SourceExpression) { this.HasValue = hasValue; this.Value = value; } internal SqlExpression HasValue { get { return this.hasValue; } set { if (value == null) throw Error.ArgumentNull("value"); this.hasValue = value; } } internal SqlExpression Value { get { return this.expressionValue; } set { if (value == null) throw Error.ArgumentNull("value"); if (value.ClrType != this.ClrType) throw Error.ArgumentWrongType("value", this.ClrType, value.ClrType); this.expressionValue = value; } } } internal class SqlFunctionCall : SqlSimpleTypeExpression { private string name; private List arguments; internal SqlFunctionCall(Type clrType, ProviderType sqlType, string name, IEnumerable args , Expression source) : this(SqlNodeType.FunctionCall, clrType , sqlType, name, args, source) { } internal SqlFunctionCall(SqlNodeType nodeType, Type clrType, ProviderType sqlType, string name , IEnumerable args , Expression source) : base(nodeType, clrType, sqlType, source) { this.name = name; this.arguments = new List(args); } internal string Name { get { return this.name; } } internal List Arguments { get { return this.arguments; } } } /// /// This class is used to represent a table value function. It inherits normal function /// call functionality, and adds TVF specific members. /// internal class SqlTableValuedFunctionCall : SqlFunctionCall { private MetaType rowType; private List columns; internal SqlTableValuedFunctionCall(MetaType rowType, Type clrType, ProviderType sqlType, string name, IEnumerable args , Expression source) : base(SqlNodeType.TableValuedFunctionCall, clrType , sqlType, name, args, source) { this.rowType = rowType; this.columns = new List(); } internal MetaType RowType { get { return this.rowType; } } internal List Columns { get { return this.columns; } } internal SqlColumn Find(string name) { foreach (SqlColumn c in this.Columns) { if (c.Name == name) return c; } return null; } } internal class SqlSharedExpression : SqlExpression { private SqlExpression expr; internal SqlSharedExpression(SqlExpression expr) : base(SqlNodeType.SharedExpression, expr.ClrType, expr.SourceExpression) { this.expr = expr; } internal SqlExpression Expression { get { return this.expr; } set { if (value == null) throw Error.ArgumentNull("value"); if (!this.ClrType.IsAssignableFrom(value.ClrType) && !value.ClrType.IsAssignableFrom(this.ClrType)) throw Error.ArgumentWrongType("value", this.ClrType, value.ClrType); this.expr = value; } } internal override ProviderType SqlType { get { return this.expr.SqlType; } } } internal class SqlSharedExpressionRef : SqlExpression { private SqlSharedExpression expr; internal SqlSharedExpressionRef(SqlSharedExpression expr) : base(SqlNodeType.SharedExpressionRef, expr.ClrType, expr.SourceExpression) { this.expr = expr; } internal SqlSharedExpression SharedExpression { get { return this.expr; } } internal override ProviderType SqlType { get { return this.expr.SqlType; } } } internal class SqlSimpleExpression : SqlExpression { private SqlExpression expr; internal SqlSimpleExpression(SqlExpression expr) : base(SqlNodeType.SimpleExpression, expr.ClrType, expr.SourceExpression) { this.expr = expr; } internal SqlExpression Expression { get { return this.expr; } set { if (value == null) throw Error.ArgumentNull("value"); if (!TypeSystem.GetNonNullableType(this.ClrType).IsAssignableFrom(TypeSystem.GetNonNullableType(value.ClrType))) throw Error.ArgumentWrongType("value", this.ClrType, value.ClrType); this.expr = value; } } internal override ProviderType SqlType { get { return this.expr.SqlType; } } } internal class SqlClientParameter : SqlSimpleTypeExpression { // Expression> LambdaExpression accessor; internal SqlClientParameter(Type clrType, ProviderType sqlType, LambdaExpression accessor, Expression sourceExpression): base(SqlNodeType.ClientParameter, clrType, sqlType, sourceExpression) { this.accessor = accessor; } internal LambdaExpression Accessor { get { return this.accessor; } } } }