protected override void BuildSql(StringBuilder sb) { if (NeedSkip) { AlternativeBuildSql2(sb, base.BuildSql); return; } if (SqlQuery.From.Tables.Count == 0 && SqlQuery.Select.Columns.Count == 1 && SqlQuery.Select.Columns[0].Expression is SqlFunction) { SqlFunction func = (SqlFunction)SqlQuery.Select.Columns[0].Expression; if (func.Name == "Iif" && func.Parameters.Length == 3 && func.Parameters[0] is SqlQuery.SearchCondition) { SqlQuery.SearchCondition sc = (SqlQuery.SearchCondition)func.Parameters[0]; if (sc.Conditions.Count == 1 && sc.Conditions[0].Predicate is SqlQuery.Predicate.FuncLike) { SqlQuery.Predicate.FuncLike p = (SqlQuery.Predicate.FuncLike)sc.Conditions[0].Predicate; if (p.Function.Name == "EXISTS") { BuildAnyAsCount(sb); return; } } } } base.BuildSql(sb); }
protected override void BuildFunction(StringBuilder sb, SqlFunction func) { func = ConvertFunctionParameters(func); switch (func.Name) { case "CASE": func = ConvertCase(func.SystemType, func.Parameters, 0); break; case "Coalesce": if (func.Parameters.Length > 2) { var parms = new ISqlExpression[func.Parameters.Length - 1]; Array.Copy(func.Parameters, 1, parms, 0, parms.Length); BuildFunction(sb, new SqlFunction(func.SystemType, func.Name, func.Parameters[0], new SqlFunction(func.SystemType, func.Name, parms))); return; } var sc = new SqlQuery.SearchCondition(); sc.Conditions.Add(new SqlQuery.Condition(false, new SqlQuery.Predicate.IsNull(func.Parameters[0], false))); func = new SqlFunction(func.SystemType, "IIF", sc, func.Parameters[1], func.Parameters[0]); break; } base.BuildFunction(sb, func); }
protected override void BuildFunction(StringBuilder sb, SqlFunction func) { func = ConvertFunctionParameters(func); switch (func.Name) { case "CASE" : func = ConvertCase(func.SystemType, func.Parameters, 0); break; case "Coalesce" : if (func.Parameters.Length > 2) { var parms = new ISqlExpression[func.Parameters.Length - 1]; Array.Copy(func.Parameters, 1, parms, 0, parms.Length); BuildFunction(sb, new SqlFunction(func.SystemType, func.Name, func.Parameters[0], new SqlFunction(func.SystemType, func.Name, parms))); return; } var sc = new SqlQuery.SearchCondition(); sc.Conditions.Add(new SqlQuery.Condition(false, new SqlQuery.Predicate.IsNull(func.Parameters[0], false))); func = new SqlFunction(func.SystemType, "IIF", sc, func.Parameters[1], func.Parameters[0]); break; } base.BuildFunction(sb, func); }
void BuildAnyAsCount(StringBuilder sb) { SqlFunction func = (SqlFunction)SqlQuery.Select.Columns[0].Expression; SqlQuery.SearchCondition cond = (SqlQuery.SearchCondition)func.Parameters[0]; SqlFunction exist = ((SqlQuery.Predicate.FuncLike)cond.Conditions[0].Predicate).Function; SqlQuery query = (SqlQuery)exist.Parameters[0]; _selectColumn = new SqlQuery.Column(SqlQuery, new SqlExpression(cond.Conditions[0].IsNot ? "Count(*) = 0" : "Count(*) > 0"), SqlQuery.Select.Columns[0].Alias); BuildSql(0, query, sb, 0, 0, false); _selectColumn = null; }
protected override IParseContext ParseMethodCall(ExpressionParser parser, IParseContext parent, MethodCallExpression methodCall, SqlQuery sqlQuery) { var sequence = parser.ParseSequence(parent, methodCall.Arguments[0], sqlQuery); if (sequence.SqlQuery.Select.TakeValue != null || sequence.SqlQuery.Select.SkipValue != null) { sequence = new SubQueryContext(sequence); } var lambda = (LambdaExpression)methodCall.Arguments[1].Unwrap(); var order = new PathThroughContext(sequence, lambda); var body = lambda.Body.Unwrap(); var sql = parser.ParseExpressions(order, body, ConvertFlags.Key); if (!methodCall.Method.Name.StartsWith("Then")) { sequence.SqlQuery.OrderBy.Items.Clear(); } foreach (var expr in sql) { var e = expr.Sql; if (e is SqlQuery.SearchCondition) { if (e.CanBeNull()) { var notExpr = new SqlQuery.SearchCondition { Conditions = { new SqlQuery.Condition(true, new SqlQuery.Predicate.Expr(e, e.Precedence)) } }; e = parser.Convert(sequence, new SqlFunction(e.SystemType, "CASE", e, new SqlValue(1), notExpr, new SqlValue(0), new SqlValue(null))); } else { e = parser.Convert(sequence, new SqlFunction(e.SystemType, "CASE", e, new SqlValue(1), new SqlValue(0))); } } sequence.SqlQuery.OrderBy.Expr(e, methodCall.Method.Name.EndsWith("Descending")); } return(sequence); }
protected override IParseContext ParseMethodCall(ExpressionParser parser, IParseContext parent, MethodCallExpression methodCall, SqlQuery sqlQuery) { var sequence = parser.ParseSequence(parent, methodCall.Arguments[0], sqlQuery); if (sequence.SqlQuery.Select.TakeValue != null || sequence.SqlQuery.Select.SkipValue != null) sequence = new SubQueryContext(sequence); var lambda = (LambdaExpression)methodCall.Arguments[1].Unwrap(); var order = new PathThroughContext(sequence, lambda); var body = lambda.Body.Unwrap(); var sql = parser.ParseExpressions(order, body, ConvertFlags.Key); if (!methodCall.Method.Name.StartsWith("Then")) sequence.SqlQuery.OrderBy.Items.Clear(); foreach (var expr in sql) { var e = expr.Sql; if (e is SqlQuery.SearchCondition) { if (e.CanBeNull()) { var notExpr = new SqlQuery.SearchCondition { Conditions = { new SqlQuery.Condition(true, new SqlQuery.Predicate.Expr(e, e.Precedence)) } }; e = parser.Convert(sequence, new SqlFunction(e.SystemType, "CASE", e, new SqlValue(1), notExpr, new SqlValue(0), new SqlValue(null))); } else e = parser.Convert(sequence, new SqlFunction(e.SystemType, "CASE", e, new SqlValue(1), new SqlValue(0))); } sequence.SqlQuery.OrderBy.Expr(e, methodCall.Method.Name.EndsWith("Descending")); } return sequence; }
static SqlFunction ConvertCase(Type systemType, ISqlExpression[] parameters, int start) { var len = parameters.Length - start; var name = start == 0 ? "IIF" : "CASE"; var cond = parameters[start]; if (start == 0 && SqlExpression.NeedsEqual(cond)) { cond = new SqlQuery.SearchCondition( new SqlQuery.Condition( false, new SqlQuery.Predicate.ExprExpr(cond, SqlQuery.Predicate.Operator.Equal, new SqlValue(1)))); } if (len == 3) return new SqlFunction(systemType, name, cond, parameters[start + 1], parameters[start + 2]); return new SqlFunction(systemType, name, cond, parameters[start + 1], ConvertCase(systemType, parameters, start + 2)); }
protected override void BuildWhereSearchCondition(StringBuilder sb, SqlQuery.SearchCondition condition) { if (NeedTake && !NeedSkip && SqlQuery.OrderBy.IsEmpty && SqlQuery.Having.IsEmpty) { BuildPredicate( sb, Precedence.LogicalConjunction, new SqlQuery.Predicate.ExprExpr( new SqlExpression(null, "ROWNUM", Precedence.Primary), SqlQuery.Predicate.Operator.LessOrEqual, SqlQuery.Select.TakeValue)); if (base.BuildWhere()) { sb.Append(" AND "); BuildSearchCondition(sb, Precedence.LogicalConjunction, condition); } } else { BuildSearchCondition(sb, Precedence.Unknown, condition); } }
static SqlFunction ConvertCase(Type systemType, ISqlExpression[] parameters, int start) { var len = parameters.Length - start; var name = start == 0 ? "IIF" : "CASE"; var cond = parameters[start]; if (start == 0 && SqlExpression.NeedsEqual(cond)) { cond = new SqlQuery.SearchCondition( new SqlQuery.Condition( false, new SqlQuery.Predicate.ExprExpr(cond, SqlQuery.Predicate.Operator.Equal, new SqlValue(1)))); } if (len == 3) { return(new SqlFunction(systemType, name, cond, parameters[start + 1], parameters[start + 2])); } return(new SqlFunction(systemType, name, cond, parameters[start + 1], ConvertCase(systemType, parameters, start + 2))); }
public override ISqlExpression ConvertExpression(ISqlExpression expr) { expr = base.ConvertExpression(expr); if (expr is SqlBinaryExpression) { var be = (SqlBinaryExpression)expr; switch (be.Operation[0]) { case '%': return(new SqlBinaryExpression(be.SystemType, be.Expr1, "MOD", be.Expr2, Precedence.Additive - 1)); case '&': case '|': case '^': throw new SqlException("Operator '{0}' is not supported by the {1}.", be.Operation, GetType().Name); } } else if (expr is SqlFunction) { var func = (SqlFunction)expr; switch (func.Name) { case "Coalesce": if (func.Parameters.Length > 2) { var parms = new ISqlExpression[func.Parameters.Length - 1]; Array.Copy(func.Parameters, 1, parms, 0, parms.Length); return(new SqlFunction(func.SystemType, func.Name, func.Parameters[0], new SqlFunction(func.SystemType, func.Name, parms))); } var sc = new SqlQuery.SearchCondition(); sc.Conditions.Add(new SqlQuery.Condition(false, new SqlQuery.Predicate.IsNull(func.Parameters[0], false))); return(new SqlFunction(func.SystemType, "Iif", sc, func.Parameters[1], func.Parameters[0])); case "CASE": return(ConvertCase(func.SystemType, func.Parameters, 0)); case "CharIndex": return(func.Parameters.Length == 2? new SqlFunction(func.SystemType, "InStr", new SqlValue(1), func.Parameters[1], func.Parameters[0], new SqlValue(1)): new SqlFunction(func.SystemType, "InStr", func.Parameters[2], func.Parameters[1], func.Parameters[0], new SqlValue(1))); case "Convert": { switch (Type.GetTypeCode(TypeHelper.GetUnderlyingType(func.SystemType))) { case TypeCode.String: return(new SqlFunction(func.SystemType, "CStr", func.Parameters[1])); case TypeCode.DateTime: if (IsDateDataType(func.Parameters[0], "Date")) { return(new SqlFunction(func.SystemType, "DateValue", func.Parameters[1])); } if (IsTimeDataType(func.Parameters[0])) { return(new SqlFunction(func.SystemType, "TimeValue", func.Parameters[1])); } return(new SqlFunction(func.SystemType, "CDate", func.Parameters[1])); default: if (func.SystemType == typeof(DateTime)) { goto case TypeCode.DateTime; } break; } return(func.Parameters[1]); } /* * case "Convert" : * { * string name = null; * * switch (((SqlDataType)func.Parameters[0]).DbType) * { * case SqlDbType.BigInt : name = "CLng"; break; * case SqlDbType.TinyInt : name = "CByte"; break; * case SqlDbType.Int : * case SqlDbType.SmallInt : name = "CInt"; break; * case SqlDbType.Bit : name = "CBool"; break; * case SqlDbType.Char : * case SqlDbType.Text : * case SqlDbType.VarChar : * case SqlDbType.NChar : * case SqlDbType.NText : * case SqlDbType.NVarChar : name = "CStr"; break; * case SqlDbType.DateTime : * case SqlDbType.Date : * case SqlDbType.Time : * case SqlDbType.DateTime2 : * case SqlDbType.SmallDateTime : * case SqlDbType.DateTimeOffset : name = "CDate"; break; * case SqlDbType.Decimal : name = "CDec"; break; * case SqlDbType.Float : name = "CDbl"; break; * case SqlDbType.Money : * case SqlDbType.SmallMoney : name = "CCur"; break; * case SqlDbType.Real : name = "CSng"; break; * case SqlDbType.Image : * case SqlDbType.Binary : * case SqlDbType.UniqueIdentifier : * case SqlDbType.Timestamp : * case SqlDbType.VarBinary : * case SqlDbType.Variant : * case SqlDbType.Xml : * case SqlDbType.Udt : * case SqlDbType.Structured : name = "CVar"; break; * } * * return new SqlFunction(name, func.Parameters[1]); * } */ } } return(expr); }
public override ISqlExpression ConvertExpression(ISqlExpression expr) { expr = base.ConvertExpression(expr); if (expr is SqlBinaryExpression) { var be = (SqlBinaryExpression)expr; switch (be.Operation[0]) { case '%': return new SqlBinaryExpression(be.SystemType, be.Expr1, "MOD", be.Expr2, Precedence.Additive - 1); case '&': case '|': case '^': throw new SqlException("Operator '{0}' is not supported by the {1}.", be.Operation, GetType().Name); } } else if (expr is SqlFunction) { var func = (SqlFunction) expr; switch (func.Name) { case "Coalesce": if (func.Parameters.Length > 2) { var parms = new ISqlExpression[func.Parameters.Length - 1]; Array.Copy(func.Parameters, 1, parms, 0, parms.Length); return new SqlFunction(func.SystemType, func.Name, func.Parameters[0], new SqlFunction(func.SystemType, func.Name, parms)); } var sc = new SqlQuery.SearchCondition(); sc.Conditions.Add(new SqlQuery.Condition(false, new SqlQuery.Predicate.IsNull(func.Parameters[0], false))); return new SqlFunction(func.SystemType, "Iif", sc, func.Parameters[1], func.Parameters[0]); case "CASE" : return ConvertCase(func.SystemType, func.Parameters, 0); case "CharIndex" : return func.Parameters.Length == 2? new SqlFunction(func.SystemType, "InStr", new SqlValue(1), func.Parameters[1], func.Parameters[0], new SqlValue(1)): new SqlFunction(func.SystemType, "InStr", func.Parameters[2], func.Parameters[1], func.Parameters[0], new SqlValue(1)); case "Convert" : { switch (Type.GetTypeCode(TypeHelper.GetUnderlyingType(func.SystemType))) { case TypeCode.String : return new SqlFunction(func.SystemType, "CStr", func.Parameters[1]); case TypeCode.DateTime : if (IsDateDataType(func.Parameters[0], "Date")) return new SqlFunction(func.SystemType, "DateValue", func.Parameters[1]); if (IsTimeDataType(func.Parameters[0])) return new SqlFunction(func.SystemType, "TimeValue", func.Parameters[1]); return new SqlFunction(func.SystemType, "CDate", func.Parameters[1]); default: if (func.SystemType == typeof(DateTime)) goto case TypeCode.DateTime; break; } return func.Parameters[1]; } /* case "Convert" : { string name = null; switch (((SqlDataType)func.Parameters[0]).DbType) { case SqlDbType.BigInt : name = "CLng"; break; case SqlDbType.TinyInt : name = "CByte"; break; case SqlDbType.Int : case SqlDbType.SmallInt : name = "CInt"; break; case SqlDbType.Bit : name = "CBool"; break; case SqlDbType.Char : case SqlDbType.Text : case SqlDbType.VarChar : case SqlDbType.NChar : case SqlDbType.NText : case SqlDbType.NVarChar : name = "CStr"; break; case SqlDbType.DateTime : case SqlDbType.Date : case SqlDbType.Time : case SqlDbType.DateTime2 : case SqlDbType.SmallDateTime : case SqlDbType.DateTimeOffset : name = "CDate"; break; case SqlDbType.Decimal : name = "CDec"; break; case SqlDbType.Float : name = "CDbl"; break; case SqlDbType.Money : case SqlDbType.SmallMoney : name = "CCur"; break; case SqlDbType.Real : name = "CSng"; break; case SqlDbType.Image : case SqlDbType.Binary : case SqlDbType.UniqueIdentifier : case SqlDbType.Timestamp : case SqlDbType.VarBinary : case SqlDbType.Variant : case SqlDbType.Xml : case SqlDbType.Udt : case SqlDbType.Structured : name = "CVar"; break; } return new SqlFunction(name, func.Parameters[1]); } */ } } return expr; }
IQueryElement ConvertInternal(IQueryElement element, ConvertFunc action) { if (element == null) { return(null); } IQueryElement newElement; if (_visitedElements.TryGetValue(element, out newElement)) { return(newElement); } switch (element.ElementType) { case QueryElementType.SqlFunction: { var func = (SqlFunction)element; var parms = Convert(func.Parameters, action); if (parms != null && !ReferenceEquals(parms, func.Parameters)) { newElement = new SqlFunction(func.SystemType, func.Name, func.Precedence, parms); } break; } case QueryElementType.SqlExpression: { var expr = (SqlExpression)element; var parameter = Convert(expr.Parameters, action); if (parameter != null && !ReferenceEquals(parameter, expr.Parameters)) { newElement = new SqlExpression(expr.SystemType, expr.Expr, expr.Precedence, parameter); } break; } case QueryElementType.SqlBinaryExpression: { var bexpr = (SqlBinaryExpression)element; var expr1 = (ISqlExpression)ConvertInternal(bexpr.Expr1, action); var expr2 = (ISqlExpression)ConvertInternal(bexpr.Expr2, action); if (expr1 != null && !ReferenceEquals(expr1, bexpr.Expr1) || expr2 != null && !ReferenceEquals(expr2, bexpr.Expr2)) { newElement = new SqlBinaryExpression(bexpr.SystemType, expr1 ?? bexpr.Expr1, bexpr.Operation, expr2 ?? bexpr.Expr2, bexpr.Precedence); } break; } case QueryElementType.SqlTable: { var table = (SqlTable)element; var fields1 = ToArray(table.Fields); var fields2 = Convert(fields1, action, f => new SqlField(f)); var joins = Convert(table.Joins, action, j => j.Clone()); var targs = table.TableArguments == null ? null : Convert(table.TableArguments, action); var fe = fields2 == null || ReferenceEquals(fields1, fields2); var je = joins == null || ReferenceEquals(table.Joins, joins); var ta = ReferenceEquals(table.TableArguments, targs); if (!fe || !je || !ta) { if (fe) { fields2 = fields1; for (var i = 0; i < fields2.Length; i++) { var field = fields2[i]; fields2[i] = new SqlField(field); _visitedElements[field] = fields2[i]; } } newElement = new SqlTable(table, fields2, joins ?? table.Joins, targs ?? table.TableArguments); _visitedElements[((SqlTable)newElement).All] = table.All; } break; } case QueryElementType.Join: { var join = (Join)element; var ons = Convert(join.JoinOns, action); if (ons != null && !ReferenceEquals(join.JoinOns, ons)) { newElement = new Join(join.TableName, join.Alias, ons); } break; } case QueryElementType.Column: { var col = (SqlQuery.Column)element; var expr = (ISqlExpression)ConvertInternal(col.Expression, action); IQueryElement parent; _visitedElements.TryGetValue(col.Parent, out parent); if (parent != null || expr != null && !ReferenceEquals(expr, col.Expression)) { newElement = new SqlQuery.Column(parent == null ? col.Parent : (SqlQuery)parent, expr ?? col.Expression, col._alias); } break; } case QueryElementType.TableSource: { var table = (SqlQuery.TableSource)element; var source = (ISqlTableSource)ConvertInternal(table.Source, action); var joins = Convert(table.Joins, action); if (source != null && !ReferenceEquals(source, table.Source) || joins != null && !ReferenceEquals(table.Joins, joins)) { newElement = new SqlQuery.TableSource(source ?? table.Source, table._alias, joins ?? table.Joins); } break; } case QueryElementType.JoinedTable: { var join = (SqlQuery.JoinedTable)element; var table = (SqlQuery.TableSource)ConvertInternal(join.Table, action); var cond = (SqlQuery.SearchCondition)ConvertInternal(join.Condition, action); if (table != null && !ReferenceEquals(table, join.Table) || cond != null && !ReferenceEquals(cond, join.Condition)) { newElement = new SqlQuery.JoinedTable(join.JoinType, table ?? join.Table, join.IsWeak, cond ?? join.Condition); } break; } case QueryElementType.SearchCondition: { var sc = (SqlQuery.SearchCondition)element; var conds = Convert(sc.Conditions, action); if (conds != null && !ReferenceEquals(sc.Conditions, conds)) { newElement = new SqlQuery.SearchCondition(conds); } break; } case QueryElementType.Condition: { var c = (SqlQuery.Condition)element; var p = (ISqlPredicate)ConvertInternal(c.Predicate, action); if (p != null && !ReferenceEquals(c.Predicate, p)) { newElement = new SqlQuery.Condition(c.IsNot, p, c.IsOr); } break; } case QueryElementType.ExprPredicate: { var p = (SqlQuery.Predicate.Expr)element; var e = (ISqlExpression)ConvertInternal(p.Expr1, action); if (e != null && !ReferenceEquals(p.Expr1, e)) { newElement = new SqlQuery.Predicate.Expr(e, p.Precedence); } break; } case QueryElementType.NotExprPredicate: { var p = (SqlQuery.Predicate.NotExpr)element; var e = (ISqlExpression)ConvertInternal(p.Expr1, action); if (e != null && !ReferenceEquals(p.Expr1, e)) { newElement = new SqlQuery.Predicate.NotExpr(e, p.IsNot, p.Precedence); } break; } case QueryElementType.ExprExprPredicate: { var p = (SqlQuery.Predicate.ExprExpr)element; var e1 = (ISqlExpression)ConvertInternal(p.Expr1, action); var e2 = (ISqlExpression)ConvertInternal(p.Expr2, action); if (e1 != null && !ReferenceEquals(p.Expr1, e1) || e2 != null && !ReferenceEquals(p.Expr2, e2)) { newElement = new SqlQuery.Predicate.ExprExpr(e1 ?? p.Expr1, p.Operator, e2 ?? p.Expr2); } break; } case QueryElementType.LikePredicate: { var p = (SqlQuery.Predicate.Like)element; var e1 = (ISqlExpression)ConvertInternal(p.Expr1, action); var e2 = (ISqlExpression)ConvertInternal(p.Expr2, action); var es = (ISqlExpression)ConvertInternal(p.Escape, action); if (e1 != null && !ReferenceEquals(p.Expr1, e1) || e2 != null && !ReferenceEquals(p.Expr2, e2) || es != null && !ReferenceEquals(p.Escape, es)) { newElement = new SqlQuery.Predicate.Like(e1 ?? p.Expr1, p.IsNot, e2 ?? p.Expr2, es ?? p.Escape); } break; } case QueryElementType.BetweenPredicate: { var p = (SqlQuery.Predicate.Between)element; var e1 = (ISqlExpression)ConvertInternal(p.Expr1, action); var e2 = (ISqlExpression)ConvertInternal(p.Expr2, action); var e3 = (ISqlExpression)ConvertInternal(p.Expr3, action); if (e1 != null && !ReferenceEquals(p.Expr1, e1) || e2 != null && !ReferenceEquals(p.Expr2, e2) || e3 != null && !ReferenceEquals(p.Expr3, e3)) { newElement = new SqlQuery.Predicate.Between(e1 ?? p.Expr1, p.IsNot, e2 ?? p.Expr2, e3 ?? p.Expr3); } break; } case QueryElementType.IsNullPredicate: { var p = (SqlQuery.Predicate.IsNull)element; var e = (ISqlExpression)ConvertInternal(p.Expr1, action); if (e != null && !ReferenceEquals(p.Expr1, e)) { newElement = new SqlQuery.Predicate.IsNull(e, p.IsNot); } break; } case QueryElementType.InSubQueryPredicate: { var p = (SqlQuery.Predicate.InSubQuery)element; var e = (ISqlExpression)ConvertInternal(p.Expr1, action); var q = (SqlQuery)ConvertInternal(p.SubQuery, action); if (e != null && !ReferenceEquals(p.Expr1, e) || q != null && !ReferenceEquals(p.SubQuery, q)) { newElement = new SqlQuery.Predicate.InSubQuery(e ?? p.Expr1, p.IsNot, q ?? p.SubQuery); } break; } case QueryElementType.InListPredicate: { var p = (SqlQuery.Predicate.InList)element; var e = (ISqlExpression)ConvertInternal(p.Expr1, action); var v = Convert(p.Values, action); if (e != null && !ReferenceEquals(p.Expr1, e) || v != null && !ReferenceEquals(p.Values, v)) { newElement = new SqlQuery.Predicate.InList(e ?? p.Expr1, p.IsNot, v ?? p.Values); } break; } case QueryElementType.FuncLikePredicate: { var p = (SqlQuery.Predicate.FuncLike)element; var f = (SqlFunction)ConvertInternal(p.Function, action); if (f != null && !ReferenceEquals(p.Function, f)) { newElement = new SqlQuery.Predicate.FuncLike(f); } break; } case QueryElementType.SetExpression: { var s = (SqlQuery.SetExpression)element; var c = (ISqlExpression)ConvertInternal(s.Column, action); var e = (ISqlExpression)ConvertInternal(s.Expression, action); if (c != null && !ReferenceEquals(s.Column, c) || e != null && !ReferenceEquals(s.Expression, e)) { newElement = new SqlQuery.SetExpression(c ?? s.Column, e ?? s.Expression); } break; } case QueryElementType.SetClause: { var s = (SqlQuery.SetClause)element; var t = s.Into != null ? (SqlTable)ConvertInternal(s.Into, action) : null; var i = Convert(s.Items, action); if (t != null && !ReferenceEquals(s.Into, t) || i != null && !ReferenceEquals(s.Items, i)) { var sc = new SqlQuery.SetClause(); sc.Into = t ?? sc.Into; sc.Items.AddRange(i ?? s.Items); sc.WithIdentity = s.WithIdentity; newElement = sc; } break; } case QueryElementType.SelectClause: { var sc = (SqlQuery.SelectClause)element; var cols = Convert(sc.Columns, action); var take = (ISqlExpression)ConvertInternal(sc.TakeValue, action); var skip = (ISqlExpression)ConvertInternal(sc.SkipValue, action); IQueryElement parent; _visitedElements.TryGetValue(sc.SqlQuery, out parent); if (parent != null || cols != null && !ReferenceEquals(sc.Columns, cols) || take != null && !ReferenceEquals(sc.TakeValue, take) || skip != null && !ReferenceEquals(sc.SkipValue, skip)) { newElement = new SqlQuery.SelectClause(sc.IsDistinct, take ?? sc.TakeValue, skip ?? sc.SkipValue, cols ?? sc.Columns); ((SqlQuery.SelectClause)newElement).SetSqlQuery((SqlQuery)parent); } break; } case QueryElementType.FromClause: { var fc = (SqlQuery.FromClause)element; var ts = Convert(fc.Tables, action); IQueryElement parent; _visitedElements.TryGetValue(fc.SqlQuery, out parent); if (parent != null || ts != null && !ReferenceEquals(fc.Tables, ts)) { newElement = new SqlQuery.FromClause(ts ?? fc.Tables); ((SqlQuery.FromClause)newElement).SetSqlQuery((SqlQuery)parent); } break; } case QueryElementType.WhereClause: { var wc = (SqlQuery.WhereClause)element; var cond = (SqlQuery.SearchCondition)ConvertInternal(wc.SearchCondition, action); IQueryElement parent; _visitedElements.TryGetValue(wc.SqlQuery, out parent); if (parent != null || cond != null && !ReferenceEquals(wc.SearchCondition, cond)) { newElement = new SqlQuery.WhereClause(cond ?? wc.SearchCondition); ((SqlQuery.WhereClause)newElement).SetSqlQuery((SqlQuery)parent); } break; } case QueryElementType.GroupByClause: { var gc = (SqlQuery.GroupByClause)element; var es = Convert(gc.Items, action); IQueryElement parent; _visitedElements.TryGetValue(gc.SqlQuery, out parent); if (parent != null || es != null && !ReferenceEquals(gc.Items, es)) { newElement = new SqlQuery.GroupByClause(es ?? gc.Items); ((SqlQuery.GroupByClause)newElement).SetSqlQuery((SqlQuery)parent); } break; } case QueryElementType.OrderByClause: { var oc = (SqlQuery.OrderByClause)element; var es = Convert(oc.Items, action); IQueryElement parent; _visitedElements.TryGetValue(oc.SqlQuery, out parent); if (parent != null || es != null && !ReferenceEquals(oc.Items, es)) { newElement = new SqlQuery.OrderByClause(es ?? oc.Items); ((SqlQuery.OrderByClause)newElement).SetSqlQuery((SqlQuery)parent); } break; } case QueryElementType.OrderByItem: { var i = (SqlQuery.OrderByItem)element; var e = (ISqlExpression)ConvertInternal(i.Expression, action); if (e != null && !ReferenceEquals(i.Expression, e)) { newElement = new SqlQuery.OrderByItem(e, i.IsDescending); } break; } case QueryElementType.Union: { var u = (SqlQuery.Union)element; var q = (SqlQuery)ConvertInternal(u.SqlQuery, action); if (q != null && !ReferenceEquals(u.SqlQuery, q)) { newElement = new SqlQuery.Union(q, u.IsAll); } break; } case QueryElementType.SqlQuery: { var q = (SqlQuery)element; IQueryElement parent = null; var doConvert = q.ParentSql != null && !_visitedElements.TryGetValue(q.ParentSql, out parent); if (!doConvert) { doConvert = null != Find(q, e => { var ret = action(e); if (ret != null && !ReferenceEquals(e, ret)) { _visitedElements.Add(e, ret); return(true); } return(false); }); } if (!doConvert) { break; } var nq = new SqlQuery { QueryType = q.QueryType }; _visitedElements.Add(q, nq); var fc = (SqlQuery.FromClause)ConvertInternal(q.From, action) ?? q.From; var sc = (SqlQuery.SelectClause)ConvertInternal(q.Select, action) ?? q.Select; var tc = q.QueryType == QueryType.Update || q.QueryType == QueryType.Insert ? ((SqlQuery.SetClause)ConvertInternal(q.Set, action) ?? q.Set) : null; var wc = (SqlQuery.WhereClause)ConvertInternal(q.Where, action) ?? q.Where; var gc = (SqlQuery.GroupByClause)ConvertInternal(q.GroupBy, action) ?? q.GroupBy; var hc = (SqlQuery.WhereClause)ConvertInternal(q.Having, action) ?? q.Having; var oc = (SqlQuery.OrderByClause)ConvertInternal(q.OrderBy, action) ?? q.OrderBy; var us = q.HasUnion ? Convert(q.Unions, action) : q.Unions; var ps = new List <SqlParameter>(q.Parameters.Count); foreach (var p in q.Parameters) { IQueryElement e; if (_visitedElements.TryGetValue(p, out e)) { if (e == null) { ps.Add(p); } else if (e is SqlParameter) { ps.Add((SqlParameter)e); } } } nq.Init(tc, sc, fc, wc, gc, hc, oc, us, (SqlQuery)parent, q.ParameterDependent, ps); _visitedElements[q] = action(nq) ?? nq; return(nq); } } newElement = newElement == null?action(element) : (action(newElement) ?? newElement); _visitedElements.Add(element, newElement); return(newElement); }
public ISqlExpression ParseExpression(IParseContext context, Expression expression) { /* var qlen = queries.Length; if (expression.NodeType == ExpressionType.Parameter && qlen == 1 && queries[0] is QuerySource.Scalar) { var ma = (QuerySource.Scalar)queries[0]; return ParseExpression(ma.Lambda, ma.Lambda.Body, ma.Sources); } */ if (CanBeConstant(expression)) return BuildConstant(expression); if (CanBeCompiled(expression)) return BuildParameter(expression).SqlParameter; if (IsSubQuery(context, expression)) return ParseSubQuery(context, expression); switch (expression.NodeType) { case ExpressionType.AndAlso: case ExpressionType.OrElse: case ExpressionType.Not: case ExpressionType.Equal: case ExpressionType.NotEqual: case ExpressionType.GreaterThan: case ExpressionType.GreaterThanOrEqual: case ExpressionType.LessThan: case ExpressionType.LessThanOrEqual: { var condition = new SqlQuery.SearchCondition(); ParseSearchCondition(context, expression, condition.Conditions); return condition; } case ExpressionType.Add: case ExpressionType.AddChecked: case ExpressionType.And: case ExpressionType.Divide: case ExpressionType.ExclusiveOr: case ExpressionType.Modulo: case ExpressionType.Multiply: case ExpressionType.MultiplyChecked: case ExpressionType.Or: case ExpressionType.Power: case ExpressionType.Subtract: case ExpressionType.SubtractChecked: case ExpressionType.Coalesce: { var e = (BinaryExpression)expression; var l = ParseExpression(context, e.Left); var r = ParseExpression(context, e.Right); var t = e.Type; switch (expression.NodeType) { case ExpressionType.Add : case ExpressionType.AddChecked : return Convert(context, new SqlBinaryExpression(t, l, "+", r, Precedence.Additive)); case ExpressionType.And : return Convert(context, new SqlBinaryExpression(t, l, "&", r, Precedence.Bitwise)); case ExpressionType.Divide : return Convert(context, new SqlBinaryExpression(t, l, "/", r, Precedence.Multiplicative)); case ExpressionType.ExclusiveOr : return Convert(context, new SqlBinaryExpression(t, l, "^", r, Precedence.Bitwise)); case ExpressionType.Modulo : return Convert(context, new SqlBinaryExpression(t, l, "%", r, Precedence.Multiplicative)); case ExpressionType.Multiply: case ExpressionType.MultiplyChecked : return Convert(context, new SqlBinaryExpression(t, l, "*", r, Precedence.Multiplicative)); case ExpressionType.Or : return Convert(context, new SqlBinaryExpression(t, l, "|", r, Precedence.Bitwise)); case ExpressionType.Power : return Convert(context, new SqlFunction(t, "Power", l, r)); case ExpressionType.Subtract : case ExpressionType.SubtractChecked : return Convert(context, new SqlBinaryExpression(t, l, "-", r, Precedence.Subtraction)); case ExpressionType.Coalesce : { if (r is SqlFunction) { var c = (SqlFunction)r; if (c.Name == "Coalesce") { var parms = new ISqlExpression[c.Parameters.Length + 1]; parms[0] = l; c.Parameters.CopyTo(parms, 1); return Convert(context, new SqlFunction(t, "Coalesce", parms)); } } return Convert(context, new SqlFunction(t, "Coalesce", l, r)); } } break; } case ExpressionType.UnaryPlus: case ExpressionType.Negate: case ExpressionType.NegateChecked: { var e = (UnaryExpression)expression; var o = ParseExpression(context, e.Operand); var t = e.Type; switch (expression.NodeType) { case ExpressionType.UnaryPlus : return o; case ExpressionType.Negate : case ExpressionType.NegateChecked : return Convert(context, new SqlBinaryExpression(t, new SqlValue(-1), "*", o, Precedence.Multiplicative)); } break; } case ExpressionType.Convert : case ExpressionType.ConvertChecked : { var e = (UnaryExpression)expression; var o = ParseExpression(context, e.Operand); if (e.Method == null && e.IsLifted) return o; if (e.Operand.Type.IsEnum && Enum.GetUnderlyingType(e.Operand.Type) == e.Type) return o; return Convert( context, new SqlFunction(e.Type, "$Convert$", SqlDataType.GetDataType(e.Type), SqlDataType.GetDataType(e.Operand.Type), o)); } case ExpressionType.Conditional : { var e = (ConditionalExpression)expression; var s = ParseExpression(context, e.Test); var t = ParseExpression(context, e.IfTrue); var f = ParseExpression(context, e.IfFalse); if (f is SqlFunction) { var c = (SqlFunction)f; if (c.Name == "CASE") { var parms = new ISqlExpression[c.Parameters.Length + 2]; parms[0] = s; parms[1] = t; c.Parameters.CopyTo(parms, 2); return Convert(context, new SqlFunction(e.Type, "CASE", parms)); } } return Convert(context, new SqlFunction(e.Type, "CASE", s, t, f)); } case ExpressionType.MemberAccess: { var ma = (MemberExpression)expression; var l = ConvertMember(ma.Member); if (l != null) { var ef = l.Body.Unwrap(); var pie = ef.Convert(wpi => wpi.NodeType == ExpressionType.Parameter ? ma.Expression : wpi); return ParseExpression(context, pie); } var attr = GetFunctionAttribute(ma.Member); if (attr != null) return Convert(context, attr.GetExpression(ma.Member)); if (TypeHelper.IsNullableValueMember(ma.Member)) return ParseExpression(context, ma.Expression); var de = ParseTimeSpanMember(context, ma); if (de != null) return de; var ctx = GetContext(context, expression); if (ctx != null) { var sql = ctx.ConvertToSql(expression, 0, ConvertFlags.Field); switch (sql.Length) { case 0 : break; case 1 : return sql[0].Sql; default : throw new InvalidOperationException(); } } break; } case ExpressionType.Parameter: { var ctx = GetContext(context, expression); if (ctx != null) { var sql = ctx.ConvertToSql(expression, 0, ConvertFlags.Field); switch (sql.Length) { case 0 : break; case 1 : return sql[0].Sql; default : throw new InvalidOperationException(); } } break; /* var sql = context.ConvertToSql(expression, 0, ConvertFlags.None).ToList(); if (sql.Count != 0) { if (sql.Count == 1) return sql[0]; throw new InvalidOperationException(); } break; */ } case ExpressionType.Call: { var e = (MethodCallExpression)expression; if (e.Method.DeclaringType == typeof(Enumerable)) { var ctx = GetContext(context, expression); if (ctx != null) { var sql = ctx.ConvertToSql(expression, 0, ConvertFlags.Field); if (sql.Length != 1) throw new InvalidOperationException(); return sql[0].Sql; } return ParseEnumerable(context, e); } var cm = ConvertMethod(e); if (cm != null) return ParseExpression(context, cm); var attr = GetFunctionAttribute(e.Method); if (attr != null) { var parms = new List<ISqlExpression>(); if (e.Object != null) parms.Add(ParseExpression(context, e.Object)); parms.AddRange(e.Arguments.Select(t => ParseExpression(context, t))); return Convert(context, attr.GetExpression(e.Method, parms.ToArray())); } break; } case ExpressionType.New: { var pie = ConvertNew((NewExpression)expression); if (pie != null) return ParseExpression(context, pie); break; } case ExpressionType.Invoke: { var pi = (InvocationExpression)expression; var ex = pi.Expression; if (ex.NodeType == ExpressionType.Quote) ex = ((UnaryExpression)ex).Operand; //if (ex.NodeType == ExpressionType.MemberAccess) // return ParseExpression(lambda, ex, queries); if (ex.NodeType == ExpressionType.Lambda) { var l = (LambdaExpression)ex; var dic = new Dictionary<Expression,Expression>(); for (var i = 0; i < l.Parameters.Count; i++) dic.Add(l.Parameters[i], pi.Arguments[i]); var pie = l.Body.Convert(wpi => { Expression ppi; return dic.TryGetValue(wpi, out ppi) ? ppi : wpi; }); return ParseExpression(context, pie); } break; } } throw new LinqException("'{0}' cannot be converted to SQL.", expression); }
void ParseSearchCondition(IParseContext context, Expression expression, List<SqlQuery.Condition> conditions) { if (IsSubQuery(context, expression)) { var cond = ParseConditionSubQuery(context, expression); if (cond != null) { conditions.Add(cond); return; } } switch (expression.NodeType) { case ExpressionType.AndAlso: { var e = (BinaryExpression)expression; ParseSearchCondition(context, e.Left, conditions); ParseSearchCondition(context, e.Right, conditions); break; } case ExpressionType.OrElse: { var e = (BinaryExpression)expression; var orCondition = new SqlQuery.SearchCondition(); ParseSearchCondition(context, e.Left, orCondition.Conditions); orCondition.Conditions[orCondition.Conditions.Count - 1].IsOr = true; ParseSearchCondition(context, e.Right, orCondition.Conditions); conditions.Add(new SqlQuery.Condition(false, orCondition)); break; } case ExpressionType.Not: { var e = expression as UnaryExpression; var notCondition = new SqlQuery.SearchCondition(); ParseSearchCondition(context, e.Operand, notCondition.Conditions); if (notCondition.Conditions.Count == 1 && notCondition.Conditions[0].Predicate is SqlQuery.Predicate.NotExpr) { var p = notCondition.Conditions[0].Predicate as SqlQuery.Predicate.NotExpr; p.IsNot = !p.IsNot; conditions.Add(notCondition.Conditions[0]); } else conditions.Add(new SqlQuery.Condition(true, notCondition)); break; } default: var predicate = ParsePredicate(context, expression); if (predicate is SqlQuery.Predicate.Expr) { var expr = ((SqlQuery.Predicate.Expr)predicate).Expr1; if (expr.ElementType == QueryElementType.SearchCondition) { var sc = (SqlQuery.SearchCondition)expr; if (sc.Conditions.Count == 1) { conditions.Add(sc.Conditions[0]); break; } } } conditions.Add(new SqlQuery.Condition(false, predicate)); break; } }
ISqlPredicate MakeIsPredicate(IParseContext context, QuerySource.Table table, Type typeOperand) { if (typeOperand == table.ObjectType && table.InheritanceMapping.Count(m => m.Type == typeOperand) == 0) return Convert(context, new SqlQuery.Predicate.Expr(new SqlValue(true))); var mapping = table.InheritanceMapping.Select((m,i) => new { m, i }).Where(m => m.m.Type == typeOperand && !m.m.IsDefault).ToList(); switch (mapping.Count) { case 0: { var cond = new SqlQuery.SearchCondition(); foreach (var m in table.InheritanceMapping.Select((m,i) => new { m, i }).Where(m => !m.m.IsDefault)) { cond.Conditions.Add( new SqlQuery.Condition( false, Convert(context, new SqlQuery.Predicate.ExprExpr( table.Columns[table.InheritanceDiscriminators[m.i]].Field, SqlQuery.Predicate.Operator.NotEqual, new SqlValue(m.m.Code))))); } return cond; } case 1: return Convert(context, new SqlQuery.Predicate.ExprExpr( table.Columns[table.InheritanceDiscriminators[mapping[0].i]].Field, SqlQuery.Predicate.Operator.Equal, new SqlValue(mapping[0].m.Code))); default: { var cond = new SqlQuery.SearchCondition(); foreach (var m in mapping) { cond.Conditions.Add( new SqlQuery.Condition( false, Convert(context, new SqlQuery.Predicate.ExprExpr( table.Columns[table.InheritanceDiscriminators[m.i]].Field, SqlQuery.Predicate.Operator.Equal, new SqlValue(m.m.Code))), true)); } return cond; } } }
ISqlPredicate ParseNewObjectComparison(IParseContext context, ExpressionType nodeType, Expression left, Expression right) { left = FindExpression(left); right = FindExpression(right); var condition = new SqlQuery.SearchCondition(); if (left.NodeType != ExpressionType.New) { var temp = left; left = right; right = temp; } var newRight = right as NewExpression; var newExpr = (NewExpression)left; for (var i = 0; i < newExpr.Arguments.Count; i++) { var lex = ParseExpression(context, newExpr.Arguments[i]); var rex = newRight != null ? ParseExpression(context, newRight.Arguments[i]) : GetParameter(right, newExpr.Members[i]); var predicate = Convert(context, new SqlQuery.Predicate.ExprExpr( lex, nodeType == ExpressionType.Equal ? SqlQuery.Predicate.Operator.Equal : SqlQuery.Predicate.Operator.NotEqual, rex)); condition.Conditions.Add(new SqlQuery.Condition(false, predicate)); } if (nodeType == ExpressionType.NotEqual) foreach (var c in condition.Conditions) c.IsOr = true; return condition; }
public ISqlPredicate ParseObjectComparison( ExpressionType nodeType, IParseContext leftContext, Expression left, IParseContext rightContext, Expression right) { var qsl = GetContext(leftContext, left); var qsr = GetContext(rightContext, right); var sl = qsl != null && qsl.IsExpression(left, 0, RequestFor.Object); var sr = qsr != null && qsr.IsExpression(right, 0, RequestFor.Object); if (sl == false && sr == false) return null; if (sl == false) { var r = right; right = left; left = r; var c = rightContext; rightContext = leftContext; leftContext = c; var q = qsr; //qsr = qsl; qsl = q; //sl = true; sr = false; } var isNull = right is ConstantExpression && ((ConstantExpression)right).Value == null; var lcols = qsl.ConvertToSql(left, 0, ConvertFlags.Key); if (lcols.Length == 0) return null; var condition = new SqlQuery.SearchCondition(); foreach (var lcol in lcols) { if (lcol.Member == null) throw new InvalidOperationException(); ISqlExpression rcol = null; if (sr) rcol = rightContext.ConvertToSql(Expression.MakeMemberAccess(right, lcol.Member), 0, ConvertFlags.Field).Single().Sql; var rex = isNull ? new SqlValue(right.Type, null) : sr ? rcol : GetParameter(right, lcol.Member); var predicate = Convert(leftContext, new SqlQuery.Predicate.ExprExpr( lcol.Sql, nodeType == ExpressionType.Equal ? SqlQuery.Predicate.Operator.Equal : SqlQuery.Predicate.Operator.NotEqual, rex)); condition.Conditions.Add(new SqlQuery.Condition(false, predicate)); } if (nodeType == ExpressionType.NotEqual) foreach (var c in condition.Conditions) c.IsOr = true; return condition; }
protected override void BuildFunction(StringBuilder sb, SqlFunction func) { switch (func.Name) { case "Coalesce" : if (func.Parameters.Length > 2) { var parms = new ISqlExpression[func.Parameters.Length - 1]; Array.Copy(func.Parameters, 1, parms, 0, parms.Length); BuildFunction(sb, new SqlFunction(func.SystemType, func.Name, func.Parameters[0], new SqlFunction(func.SystemType, func.Name, parms))); return; } var sc = new SqlQuery.SearchCondition(); sc.Conditions.Add(new SqlQuery.Condition(false, new SqlQuery.Predicate.IsNull(func.Parameters[0], false))); func = new SqlFunction(func.SystemType, "Iif", sc, func.Parameters[1], func.Parameters[0]); break; case "CASE" : func = ConvertCase(func.SystemType, func.Parameters, 0); break; case "CharIndex" : func = func.Parameters.Length == 2? new SqlFunction(func.SystemType, "InStr", new SqlValue(1), func.Parameters[1], func.Parameters[0], new SqlValue(1)): new SqlFunction(func.SystemType, "InStr", func.Parameters[2], func.Parameters[1], func.Parameters[0], new SqlValue(1)); break; case "Convert" : switch (Type.GetTypeCode(func.SystemType.ToUnderlying())) { case TypeCode.String : func = new SqlFunction(func.SystemType, "CStr", func.Parameters[1]); break; case TypeCode.DateTime : if (IsDateDataType(func.Parameters[0], "Date")) func = new SqlFunction(func.SystemType, "DateValue", func.Parameters[1]); else if (IsTimeDataType(func.Parameters[0])) func = new SqlFunction(func.SystemType, "TimeValue", func.Parameters[1]); else func = new SqlFunction(func.SystemType, "CDate", func.Parameters[1]); break; default: if (func.SystemType == typeof(DateTime)) goto case TypeCode.DateTime; BuildExpression(sb, func.Parameters[1]); return; } break; } base.BuildFunction(sb, func); }
protected override void BuildFunction(StringBuilder sb, SqlFunction func) { switch (func.Name) { case "Coalesce": if (func.Parameters.Length > 2) { var parms = new ISqlExpression[func.Parameters.Length - 1]; Array.Copy(func.Parameters, 1, parms, 0, parms.Length); BuildFunction(sb, new SqlFunction(func.SystemType, func.Name, func.Parameters[0], new SqlFunction(func.SystemType, func.Name, parms))); return; } var sc = new SqlQuery.SearchCondition(); sc.Conditions.Add(new SqlQuery.Condition(false, new SqlQuery.Predicate.IsNull(func.Parameters[0], false))); func = new SqlFunction(func.SystemType, "Iif", sc, func.Parameters[1], func.Parameters[0]); break; case "CASE": func = ConvertCase(func.SystemType, func.Parameters, 0); break; case "CharIndex": func = func.Parameters.Length == 2? new SqlFunction(func.SystemType, "InStr", new SqlValue(1), func.Parameters[1], func.Parameters[0], new SqlValue(1)): new SqlFunction(func.SystemType, "InStr", func.Parameters[2], func.Parameters[1], func.Parameters[0], new SqlValue(1)); break; case "Convert": switch (Type.GetTypeCode(func.SystemType.ToUnderlying())) { case TypeCode.String: func = new SqlFunction(func.SystemType, "CStr", func.Parameters[1]); break; case TypeCode.DateTime: if (IsDateDataType(func.Parameters[0], "Date")) { func = new SqlFunction(func.SystemType, "DateValue", func.Parameters[1]); } else if (IsTimeDataType(func.Parameters[0])) { func = new SqlFunction(func.SystemType, "TimeValue", func.Parameters[1]); } else { func = new SqlFunction(func.SystemType, "CDate", func.Parameters[1]); } break; default: if (func.SystemType == typeof(DateTime)) { goto case TypeCode.DateTime; } BuildExpression(sb, func.Parameters[1]); return; } break; } base.BuildFunction(sb, func); }