public ICloneableElement Clone(Dictionary <ICloneableElement, ICloneableElement> objectTree, Predicate <ICloneableElement> doClone) { if (!doClone(this)) { return(this); } if (!objectTree.TryGetValue(this, out var clone)) { objectTree.Add(this, clone = new SqlBinaryExpression( SystemType, (ISqlExpression)Expr1.Clone(objectTree, doClone), Operation, (ISqlExpression)Expr2.Clone(objectTree, doClone), Precedence)); } return(clone); }
IQueryElement?ConvertInternal(IQueryElement?element) { if (element == null) { return(null); } // if element manually added outside to VisistedElements as null, it will be processed continuously. // Useful when we have to duplicate such items, especially parameters var newElement = GetCurrentReplaced(element); if (newElement != null) { return(newElement); } Stack.Add(element); try { switch (element.ElementType) { case QueryElementType.SqlFunction: { var func = (SqlFunction)element; var parms = Convert(func.Parameters); if (parms != null && !ReferenceEquals(parms, func.Parameters)) { newElement = new SqlFunction(func.SystemType, func.Name, func.IsAggregate, func.Precedence, parms); } break; } case QueryElementType.SqlExpression: { var expr = (SqlExpression)element; var parameter = Convert(expr.Parameters); 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); var expr2 = (ISqlExpression?)ConvertInternal(bexpr.Expr2); 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 newTable = (SqlTable)_convert(this, table); if (ReferenceEquals(newTable, table)) { var targs = table.TableArguments == null || table.TableArguments.Length == 0 ? null : Convert(table.TableArguments); if (targs != null && !ReferenceEquals(table.TableArguments, targs)) { var newFields = table.Fields.Values.Select(f => new SqlField(f)); newTable = new SqlTable(table, newFields, targs); } } if (!ReferenceEquals(table, newTable)) { AddVisited(table.All, newTable.All); foreach (var prevField in table.Fields.Values) { if (newTable.Fields.TryGetValue(prevField.Name, out var newField)) { AddVisited(prevField, newField); } } } newElement = newTable; break; } case QueryElementType.SqlCteTable: { var table = (SqlCteTable)element; var newTable = (SqlCteTable)_convert(this, table); if (ReferenceEquals(newTable, table)) { var cte = (CteClause?)ConvertInternal(table.Cte); var ce = cte != null && !ReferenceEquals(table.Cte, cte); if (ce) { var newFields = table.Fields.Values.Select(f => new SqlField(f)); newTable = new SqlCteTable(table, newFields, cte !); } } if (!ReferenceEquals(table, newTable)) { AddVisited(table.All, newTable.All); foreach (var prevField in table.Fields.Values) { if (newTable.Fields.TryGetValue(prevField.Name, out var newField)) { AddVisited(prevField, newField); } } } newElement = newTable; break; } case QueryElementType.Column: { var col = (SqlColumn)element; var expr = (ISqlExpression?)ConvertInternal(col.Expression); if (expr != null && !ReferenceEquals(expr, col.Expression)) { newElement = new SqlColumn(col.Parent, expr, col.RawAlias); } break; } case QueryElementType.TableSource: { var table = (SqlTableSource)element; var source = (ISqlTableSource?)ConvertInternal(table.Source); var joins = Convert(table.Joins); List <ISqlExpression[]>?uk = null; if (table.HasUniqueKeys) { uk = ConvertListArray(table.UniqueKeys, null); } if (source != null && !ReferenceEquals(source, table.Source) || joins != null && !ReferenceEquals(table.Joins, joins)) { newElement = new SqlTableSource( source ?? table.Source, table._alias, joins ?? table.Joins, uk ?? (table.HasUniqueKeys ? table.UniqueKeys : null)); } break; } case QueryElementType.JoinedTable: { var join = (SqlJoinedTable)element; var table = (SqlTableSource?)ConvertInternal(join.Table); var cond = (SqlSearchCondition?)ConvertInternal(join.Condition); if (table != null && !ReferenceEquals(table, join.Table) || cond != null && !ReferenceEquals(cond, join.Condition)) { newElement = new SqlJoinedTable(join.JoinType, table ?? join.Table, join.IsWeak, cond ?? join.Condition); } break; } case QueryElementType.SearchCondition: { var sc = (SqlSearchCondition)element; var conds = Convert(sc.Conditions); if (conds != null && !ReferenceEquals(sc.Conditions, conds)) { newElement = new SqlSearchCondition(conds); } break; } case QueryElementType.Condition: { var c = (SqlCondition)element; var p = (ISqlPredicate?)ConvertInternal(c.Predicate); if (p != null && !ReferenceEquals(c.Predicate, p)) { newElement = new SqlCondition(c.IsNot, p, c.IsOr); } break; } case QueryElementType.ExprPredicate: { var p = (SqlPredicate.Expr)element; var e = (ISqlExpression?)ConvertInternal(p.Expr1); if (e != null && !ReferenceEquals(p.Expr1, e)) { newElement = new SqlPredicate.Expr(e, p.Precedence); } break; } case QueryElementType.NotExprPredicate: { var p = (SqlPredicate.NotExpr)element; var e = (ISqlExpression?)ConvertInternal(p.Expr1); if (e != null && !ReferenceEquals(p.Expr1, e)) { newElement = new SqlPredicate.NotExpr(e, p.IsNot, p.Precedence); } break; } case QueryElementType.ExprExprPredicate: { var p = (SqlPredicate.ExprExpr)element; var e1 = (ISqlExpression?)ConvertInternal(p.Expr1); var e2 = (ISqlExpression?)ConvertInternal(p.Expr2); if (e1 != null && !ReferenceEquals(p.Expr1, e1) || e2 != null && !ReferenceEquals(p.Expr2, e2)) { newElement = new SqlPredicate.ExprExpr(e1 ?? p.Expr1, p.Operator, e2 ?? p.Expr2); } break; } case QueryElementType.LikePredicate: { var p = (SqlPredicate.Like)element; var e1 = (ISqlExpression?)ConvertInternal(p.Expr1); var e2 = (ISqlExpression?)ConvertInternal(p.Expr2); var es = (ISqlExpression?)ConvertInternal(p.Escape); if (e1 != null && !ReferenceEquals(p.Expr1, e1) || e2 != null && !ReferenceEquals(p.Expr2, e2) || es != null && !ReferenceEquals(p.Escape, es)) { newElement = new SqlPredicate.Like(e1 ?? p.Expr1, p.IsNot, e2 ?? p.Expr2, es ?? p.Escape, p.IsSqlLike); } break; } case QueryElementType.BetweenPredicate: { var p = (SqlPredicate.Between)element; var e1 = (ISqlExpression?)ConvertInternal(p.Expr1); var e2 = (ISqlExpression?)ConvertInternal(p.Expr2); var e3 = (ISqlExpression?)ConvertInternal(p.Expr3); if (e1 != null && !ReferenceEquals(p.Expr1, e1) || e2 != null && !ReferenceEquals(p.Expr2, e2) || e3 != null && !ReferenceEquals(p.Expr3, e3)) { newElement = new SqlPredicate.Between(e1 ?? p.Expr1, p.IsNot, e2 ?? p.Expr2, e3 ?? p.Expr3); } break; } case QueryElementType.IsNullPredicate: { var p = (SqlPredicate.IsNull)element; var e = (ISqlExpression?)ConvertInternal(p.Expr1); if (e != null && !ReferenceEquals(p.Expr1, e)) { newElement = new SqlPredicate.IsNull(e, p.IsNot); } break; } case QueryElementType.InSubQueryPredicate: { var p = (SqlPredicate.InSubQuery)element; var e = (ISqlExpression?)ConvertInternal(p.Expr1); var q = (SelectQuery?)ConvertInternal(p.SubQuery); if (e != null && !ReferenceEquals(p.Expr1, e) || q != null && !ReferenceEquals(p.SubQuery, q)) { newElement = new SqlPredicate.InSubQuery(e ?? p.Expr1, p.IsNot, q ?? p.SubQuery); } break; } case QueryElementType.InListPredicate: { var p = (SqlPredicate.InList)element; var e = (ISqlExpression?)ConvertInternal(p.Expr1); var v = Convert(p.Values); if (e != null && !ReferenceEquals(p.Expr1, e) || v != null && !ReferenceEquals(p.Values, v)) { newElement = new SqlPredicate.InList(e ?? p.Expr1, p.IsNot, v ?? p.Values); } break; } case QueryElementType.FuncLikePredicate: { var p = (SqlPredicate.FuncLike)element; var f = (SqlFunction?)ConvertInternal(p.Function); if (f != null && !ReferenceEquals(p.Function, f)) { newElement = new SqlPredicate.FuncLike(f); } break; } case QueryElementType.SetExpression: { var s = (SqlSetExpression)element; var c = (ISqlExpression?)ConvertInternal(s.Column); var e = (ISqlExpression?)ConvertInternal(s.Expression); if (c != null && !ReferenceEquals(s.Column, c) || e != null && !ReferenceEquals(s.Expression, e)) { newElement = new SqlSetExpression(c ?? s.Column, e ?? s.Expression !); } break; } case QueryElementType.InsertClause: { var s = (SqlInsertClause)element; var t = s.Into != null ? (SqlTable?)ConvertInternal(s.Into) : null; var i = Convert(s.Items); if (t != null && !ReferenceEquals(s.Into, t) || i != null && !ReferenceEquals(s.Items, i)) { var sc = new SqlInsertClause { Into = t ?? s.Into }; sc.Items.AddRange(i ?? s.Items); sc.WithIdentity = s.WithIdentity; newElement = sc; } break; } case QueryElementType.UpdateClause: { var s = (SqlUpdateClause)element; var t = s.Table != null ? (SqlTable?)ConvertInternal(s.Table) : null; var i = Convert(s.Items); var k = Convert(s.Keys); if (t != null && !ReferenceEquals(s.Table, t) || i != null && !ReferenceEquals(s.Items, i) || k != null && !ReferenceEquals(s.Keys, k)) { var sc = new SqlUpdateClause { Table = t ?? s.Table }; sc.Items.AddRange(i ?? s.Items); sc.Keys.AddRange(k ?? s.Keys); newElement = sc; } break; } case QueryElementType.SelectStatement: { var s = (SqlSelectStatement)element; var selectQuery = (SelectQuery?)ConvertInternal(s.SelectQuery); var with = s.With != null ? (SqlWithClause?)ConvertInternal(s.With) : null; var ps = ConvertSafe(s.Parameters); if (ps != null && !ReferenceEquals(s.Parameters, ps) || selectQuery != null && !ReferenceEquals(s.SelectQuery, selectQuery) || with != null && !ReferenceEquals(s.With, with)) { newElement = new SqlSelectStatement(selectQuery ?? s.SelectQuery); ((SqlSelectStatement)newElement).Parameters.AddRange(ps ?? s.Parameters); ((SqlSelectStatement)newElement).With = with ?? s.With; CorrectQueryHierarchy(((SqlSelectStatement)newElement).SelectQuery); } break; } case QueryElementType.InsertStatement: { var s = (SqlInsertStatement)element; var selectQuery = (SelectQuery? )ConvertInternal(s.SelectQuery); var insert = (SqlInsertClause?)ConvertInternal(s.Insert); var with = s.With != null ? (SqlWithClause?)ConvertInternal(s.With) : null; var ps = ConvertSafe(s.Parameters); if (insert != null && !ReferenceEquals(s.Insert, insert) || ps != null && !ReferenceEquals(s.Parameters, ps) || selectQuery != null && !ReferenceEquals(s.SelectQuery, selectQuery) || with != null && !ReferenceEquals(s.With, with)) { newElement = new SqlInsertStatement(selectQuery ?? s.SelectQuery) { Insert = insert ?? s.Insert }; ((SqlInsertStatement)newElement).Parameters.AddRange(ps ?? s.Parameters); ((SqlInsertStatement)newElement).With = with ?? s.With; CorrectQueryHierarchy(((SqlInsertStatement)newElement).SelectQuery); } break; } case QueryElementType.UpdateStatement: { var s = (SqlUpdateStatement)element; var selectQuery = (SelectQuery? )ConvertInternal(s.SelectQuery); var update = (SqlUpdateClause?)ConvertInternal(s.Update); var with = s.With != null ? (SqlWithClause?)ConvertInternal(s.With) : null; var ps = ConvertSafe(s.Parameters); if (update != null && !ReferenceEquals(s.Update, update) || ps != null && !ReferenceEquals(s.Parameters, ps) || selectQuery != null && !ReferenceEquals(s.SelectQuery, selectQuery) || with != null && !ReferenceEquals(s.With, with)) { newElement = new SqlUpdateStatement(selectQuery ?? s.SelectQuery) { Update = update ?? s.Update }; ((SqlUpdateStatement)newElement).Parameters.AddRange(ps ?? s.Parameters); ((SqlUpdateStatement)newElement).With = with ?? s.With; CorrectQueryHierarchy(((SqlUpdateStatement)newElement).SelectQuery); } break; } case QueryElementType.InsertOrUpdateStatement: { var s = (SqlInsertOrUpdateStatement)element; var selectQuery = (SelectQuery? )ConvertInternal(s.SelectQuery); var insert = (SqlInsertClause?)ConvertInternal(s.Insert); var update = (SqlUpdateClause?)ConvertInternal(s.Update); var with = s.With != null ? (SqlWithClause?)ConvertInternal(s.With) : null; var ps = ConvertSafe(s.Parameters); if (insert != null && !ReferenceEquals(s.Insert, insert) || update != null && !ReferenceEquals(s.Update, update) || ps != null && !ReferenceEquals(s.Parameters, ps) || selectQuery != null && !ReferenceEquals(s.SelectQuery, selectQuery) || with != null && !ReferenceEquals(s.With, with)) { newElement = new SqlInsertOrUpdateStatement(selectQuery ?? s.SelectQuery) { Insert = insert ?? s.Insert, Update = update ?? s.Update }; ((SqlInsertOrUpdateStatement)newElement).Parameters.AddRange(ps ?? s.Parameters); ((SqlInsertOrUpdateStatement)newElement).With = with ?? s.With; CorrectQueryHierarchy(((SqlInsertOrUpdateStatement)newElement).SelectQuery); } break; } case QueryElementType.DeleteStatement: { var s = (SqlDeleteStatement)element; var selectQuery = s.SelectQuery != null ? (SelectQuery?)ConvertInternal(s.SelectQuery) : null; var table = s.Table != null ? (SqlTable?)ConvertInternal(s.Table) : null; var top = s.Top != null ? (ISqlExpression?)ConvertInternal(s.Top) : null; var with = s.With != null ? (SqlWithClause?)ConvertInternal(s.With) : null; var ps = ConvertSafe(s.Parameters); if (table != null && !ReferenceEquals(s.Table, table) || top != null && !ReferenceEquals(s.Top, top) || ps != null && !ReferenceEquals(s.Parameters, ps) || selectQuery != null && !ReferenceEquals(s.SelectQuery, selectQuery) || with != null && !ReferenceEquals(s.With, with)) { newElement = new SqlDeleteStatement { Table = table ?? s.Table, SelectQuery = selectQuery ?? s.SelectQuery, Top = top ?? s.Top !, IsParameterDependent = s.IsParameterDependent }; ((SqlDeleteStatement)newElement).Parameters.AddRange(ps ?? s.Parameters); ((SqlDeleteStatement)newElement).With = with ?? s.With; CorrectQueryHierarchy(((SqlDeleteStatement)newElement).SelectQuery); } break; } case QueryElementType.CreateTableStatement: { var s = (SqlCreateTableStatement)element; var t = s.Table != null ? (SqlTable?)ConvertInternal(s.Table) : null; var ps = ConvertSafe(s.Parameters); if (t != null && !ReferenceEquals(s.Table, t) || ps != null && !ReferenceEquals(s.Parameters, ps)) { newElement = new SqlCreateTableStatement { Table = t ?? s.Table }; if (ps != null) { ((SqlCreateTableStatement)newElement).Parameters.AddRange(ps); } else { ((SqlCreateTableStatement)newElement).Parameters.AddRange(s.Parameters); } } break; } case QueryElementType.DropTableStatement: { var s = (SqlDropTableStatement)element; var t = s.Table != null ? (SqlTable?)ConvertInternal(s.Table) : null; var ps = ConvertSafe(s.Parameters); if (t != null && !ReferenceEquals(s.Table, t) || ps != null && !ReferenceEquals(s.Parameters, ps)) { newElement = new SqlDropTableStatement(s.IfExists) { Table = t ?? s.Table }; if (ps != null) { ((SqlDropTableStatement)newElement).Parameters.AddRange(ps); } else { ((SqlDropTableStatement)newElement).Parameters.AddRange(s.Parameters); } } break; } case QueryElementType.SelectClause: { var sc = (SqlSelectClause)element; var cols = Convert(sc.Columns, CloneColumn); var take = (ISqlExpression?)ConvertInternal(sc.TakeValue); var skip = (ISqlExpression?)ConvertInternal(sc.SkipValue); if ( cols != null && !ReferenceEquals(sc.Columns, cols) || take != null && !ReferenceEquals(sc.TakeValue, take) || skip != null && !ReferenceEquals(sc.SkipValue, skip)) { newElement = new SqlSelectClause(sc.IsDistinct, take ?? sc.TakeValue, sc.TakeHints, skip ?? sc.SkipValue, cols ?? sc.Columns); ((SqlSelectClause)newElement).SetSqlQuery(sc.SelectQuery); }