e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
2282 lines
75 KiB
C#
2282 lines
75 KiB
C#
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; }
|
|
|
|
/// <summary>
|
|
/// Drill down looking for a constant root expression, returning true if found.
|
|
/// </summary>
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A SqlExpression with a simple implementation of ClrType and SqlType.
|
|
/// </summary>
|
|
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; }
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Represents a dynamic CLR type that is chosen based on a discriminator expression.
|
|
/// </summary>
|
|
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<SqlExpression> groupBy;
|
|
private SqlExpression having;
|
|
private List<SqlOrderExpression> 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<SqlExpression>();
|
|
this.orderBy = new List<SqlOrderExpression>();
|
|
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<SqlExpression> 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<SqlOrderExpression> 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<SqlColumn> 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<SqlColumn>();
|
|
}
|
|
|
|
internal MetaTable MetaTable {
|
|
get { return this.table; }
|
|
}
|
|
|
|
internal string Name {
|
|
get { return this.table.TableName; }
|
|
}
|
|
|
|
internal List<SqlColumn> 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<SqlExpression> args;
|
|
private List<SqlUserColumn> columns;
|
|
|
|
internal SqlUserQuery(SqlNodeType nt, SqlExpression projection, IEnumerable<SqlExpression> args, Expression source)
|
|
: base(nt, source) {
|
|
this.Projection = projection;
|
|
this.args = (args != null) ? new List<SqlExpression>(args) : new List<SqlExpression>();
|
|
this.columns = new List<SqlUserColumn>();
|
|
}
|
|
|
|
internal SqlUserQuery(string queryText, SqlExpression projection, IEnumerable<SqlExpression> args, Expression source)
|
|
: base(SqlNodeType.UserQuery, source) {
|
|
this.queryText = queryText;
|
|
this.Projection = projection;
|
|
this.args = (args != null) ? new List<SqlExpression>(args) : new List<SqlExpression>();
|
|
this.columns = new List<SqlUserColumn>();
|
|
}
|
|
|
|
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<SqlExpression> Arguments {
|
|
get { return this.args; }
|
|
}
|
|
|
|
internal List<SqlUserColumn> 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<SqlExpression> 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<SqlOrderExpression> {
|
|
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<SqlOrderExpression> orderBy;
|
|
|
|
internal List<SqlOrderExpression> OrderBy {
|
|
get { return orderBy; }
|
|
}
|
|
|
|
internal SqlRowNumber(Type clrType, ProviderType sqlType, List<SqlOrderExpression> 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<SqlExpression> values;
|
|
|
|
internal SqlIn(Type clrType, ProviderType sqlType, SqlExpression expression, IEnumerable<SqlExpression> values, Expression sourceExpression)
|
|
:base(SqlNodeType.In, clrType, sqlType, sourceExpression) {
|
|
this.expression = expression;
|
|
this.values = values != null ? new List<SqlExpression>(values) : new List<SqlExpression>(0);
|
|
}
|
|
|
|
internal SqlExpression Expression {
|
|
get { return this.expression; }
|
|
set {
|
|
if (value == null) {
|
|
throw Error.ArgumentNull("value");
|
|
}
|
|
this.expression = value;
|
|
}
|
|
}
|
|
internal List<SqlExpression> 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<SqlWhen> whens;
|
|
private SqlExpression @else;
|
|
|
|
internal SqlSearchedCase(Type clrType, IEnumerable<SqlWhen> whens, SqlExpression @else, Expression sourceExpression)
|
|
: base(SqlNodeType.SearchedCase, clrType, sourceExpression) {
|
|
if (whens == null)
|
|
throw Error.ArgumentNull("whens");
|
|
this.whens = new List<SqlWhen>(whens);
|
|
if (this.whens.Count == 0)
|
|
throw Error.ArgumentOutOfRange("whens");
|
|
this.Else = @else;
|
|
}
|
|
|
|
internal List<SqlWhen> 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<SqlWhen> whens = new List<SqlWhen>();
|
|
|
|
internal SqlSimpleCase(Type clrType, SqlExpression expr, IEnumerable<SqlWhen> 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<SqlWhen> Whens {
|
|
get { return this.whens; }
|
|
}
|
|
|
|
internal override ProviderType SqlType {
|
|
get { return this.whens[0].Value.SqlType; }
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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
|
|
/// </summary>
|
|
internal class SqlClientCase : SqlExpression {
|
|
private SqlExpression expression;
|
|
private List<SqlClientWhen> whens = new List<SqlClientWhen>();
|
|
|
|
internal SqlClientCase(Type clrType, SqlExpression expr, IEnumerable<SqlClientWhen> 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<SqlClientWhen> Whens {
|
|
get { return this.whens; }
|
|
}
|
|
|
|
internal override ProviderType SqlType {
|
|
get { return this.whens[0].Value.SqlType; }
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A single WHEN clause for ClientCase.
|
|
/// </summary>
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
internal class SqlTypeCase : SqlExpression {
|
|
private MetaType rowType;
|
|
private SqlExpression discriminator;
|
|
private List<SqlTypeCaseWhen> whens = new List<SqlTypeCaseWhen>();
|
|
ProviderType sqlType;
|
|
|
|
internal SqlTypeCase(Type clrType, ProviderType sqlType, MetaType rowType, SqlExpression discriminator, IEnumerable<SqlTypeCaseWhen> 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<SqlTypeCaseWhen> Whens {
|
|
get { return this.whens; }
|
|
}
|
|
|
|
internal override ProviderType SqlType {
|
|
get { return sqlType; }
|
|
}
|
|
|
|
internal MetaType RowType {
|
|
get { return this.rowType; }
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
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; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the column's Expression. This can change the type of the column.
|
|
/// </summary>
|
|
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<SqlColumn> columns;
|
|
|
|
internal SqlRow(Expression sourceExpression)
|
|
: base(SqlNodeType.Row, sourceExpression) {
|
|
this.columns = new List<SqlColumn>();
|
|
}
|
|
|
|
internal List<SqlColumn> 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<SqlExpression> args;
|
|
private List<MemberInfo> argMembers;
|
|
private List<SqlMemberAssign> members;
|
|
|
|
internal SqlNew(MetaType metaType, ProviderType sqlType, ConstructorInfo cons, IEnumerable<SqlExpression> args, IEnumerable<MemberInfo> argMembers, IEnumerable<SqlMemberAssign> 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<SqlExpression>();
|
|
this.argMembers = new List<MemberInfo>();
|
|
this.members = new List<SqlMemberAssign>();
|
|
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<SqlExpression> Args {
|
|
get { return this.args; }
|
|
}
|
|
|
|
internal List<MemberInfo> ArgMembers {
|
|
get { return this.argMembers; }
|
|
}
|
|
|
|
internal List<SqlMemberAssign> 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<SqlExpression> arguments;
|
|
|
|
internal SqlMethodCall(Type clrType, ProviderType sqlType, MethodInfo method, SqlExpression obj, IEnumerable<SqlExpression> 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<SqlExpression>();
|
|
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<SqlExpression> 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<SqlExpression> expressions;
|
|
|
|
internal SqlClientArray(Type clrType, ProviderType sqlType, SqlExpression[ ] exprs, Expression sourceExpression)
|
|
: base(SqlNodeType.ClientArray, clrType, sqlType, sourceExpression) {
|
|
this.expressions = new List<SqlExpression>();
|
|
if (exprs != null)
|
|
this.Expressions.AddRange(exprs);
|
|
}
|
|
|
|
internal List<SqlExpression> Expressions {
|
|
get { return this.expressions; }
|
|
}
|
|
}
|
|
|
|
internal class SqlLink : SqlSimpleTypeExpression {
|
|
private MetaType rowType;
|
|
private SqlExpression expression;
|
|
private MetaDataMember member;
|
|
private List<SqlExpression> keyExpressions;
|
|
private SqlExpression expansion;
|
|
private object id;
|
|
|
|
internal SqlLink(object id, MetaType rowType, Type clrType, ProviderType sqlType, SqlExpression expression, MetaDataMember member, IEnumerable<SqlExpression> 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<SqlExpression>();
|
|
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<SqlExpression> KeyExpressions {
|
|
get { return this.keyExpressions; }
|
|
}
|
|
|
|
internal object Id {
|
|
get { return this.id; }
|
|
}
|
|
}
|
|
|
|
internal class SqlExprSet : SqlExpression {
|
|
private List<SqlExpression> expressions;
|
|
|
|
internal SqlExprSet(Type clrType, IEnumerable <SqlExpression> exprs, Expression sourceExpression)
|
|
: base(SqlNodeType.ExprSet, clrType, sourceExpression) {
|
|
this.expressions = new List<SqlExpression>(exprs);
|
|
}
|
|
|
|
internal List<SqlExpression> Expressions {
|
|
get { return this.expressions; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the first non-set expression of the set by drilling
|
|
/// down the left expressions.
|
|
/// </summary>
|
|
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<SqlExpression> arguments;
|
|
private List<SqlParameter> parameters;
|
|
int ordinal;
|
|
|
|
internal SqlClientQuery(SqlSubSelect subquery)
|
|
: base(SqlNodeType.ClientQuery, subquery.ClrType, subquery.SqlType, subquery.SourceExpression) {
|
|
this.query = subquery;
|
|
this.arguments = new List<SqlExpression>();
|
|
this.parameters = new List<SqlParameter>();
|
|
}
|
|
|
|
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<SqlExpression> Arguments {
|
|
get { return this.arguments; }
|
|
}
|
|
|
|
internal List<SqlParameter> 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<SqlAssign> assignments;
|
|
|
|
internal SqlUpdate(SqlSelect select, IEnumerable<SqlAssign> assignments, Expression sourceExpression)
|
|
: base(SqlNodeType.Update, sourceExpression) {
|
|
this.Select = select;
|
|
this.assignments = new List<SqlAssign>(assignments);
|
|
}
|
|
|
|
internal SqlSelect Select {
|
|
get { return this.select; }
|
|
set {
|
|
if (value == null)
|
|
throw Error.ArgumentNull("value");
|
|
this.select = value;
|
|
}
|
|
}
|
|
|
|
internal List<SqlAssign> 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<SqlStatement> statements;
|
|
|
|
internal SqlBlock(Expression sourceExpression)
|
|
: base(SqlNodeType.Block, sourceExpression) {
|
|
this.statements = new List<SqlStatement>();
|
|
}
|
|
|
|
internal List<SqlStatement> 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<SqlExpression> arguments;
|
|
|
|
internal SqlFunctionCall(Type clrType, ProviderType sqlType, string name, IEnumerable <SqlExpression > args , Expression source)
|
|
: this(SqlNodeType.FunctionCall, clrType , sqlType, name, args, source) {
|
|
}
|
|
|
|
internal SqlFunctionCall(SqlNodeType nodeType, Type clrType, ProviderType sqlType, string name , IEnumerable <SqlExpression> args , Expression source)
|
|
: base(nodeType, clrType, sqlType, source) {
|
|
this.name = name;
|
|
this.arguments = new List<SqlExpression>(args);
|
|
}
|
|
|
|
internal string Name {
|
|
get { return this.name; }
|
|
}
|
|
|
|
internal List<SqlExpression> Arguments {
|
|
get { return this.arguments; }
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This class is used to represent a table value function. It inherits normal function
|
|
/// call functionality, and adds TVF specific members.
|
|
/// </summary>
|
|
internal class SqlTableValuedFunctionCall : SqlFunctionCall {
|
|
private MetaType rowType;
|
|
private List<SqlColumn> columns;
|
|
|
|
internal SqlTableValuedFunctionCall(MetaType rowType, Type clrType, ProviderType sqlType, string name, IEnumerable <SqlExpression > args , Expression source)
|
|
: base(SqlNodeType.TableValuedFunctionCall, clrType , sqlType, name, args, source) {
|
|
this.rowType = rowType;
|
|
this.columns = new List<SqlColumn>();
|
|
}
|
|
|
|
internal MetaType RowType {
|
|
get { return this.rowType; }
|
|
}
|
|
|
|
internal List<SqlColumn> 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<Func<object[], T>>
|
|
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; }
|
|
}
|
|
}
|
|
}
|