comparison Source/Data/Sql/SqlQuery.cs @ 0:f990fcb411a9

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:f990fcb411a9
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Diagnostics;
5 using System.IO;
6 using System.Linq;
7 using System.Text;
8 using System.Threading;
9
10 using JetBrains.Annotations;
11
12 namespace BLToolkit.Data.Sql
13 {
14 using Reflection;
15
16 using FJoin = SqlQuery.FromClause.Join;
17
18 [DebuggerDisplay("SQL = {SqlText}")]
19 public class SqlQuery : ISqlTableSource
20 {
21 #region Init
22
23 static readonly Dictionary<string,object> _reservedWords = new Dictionary<string,object>();
24
25 static SqlQuery()
26 {
27 using (var stream = typeof(SqlQuery).Assembly.GetManifestResourceStream(typeof(SqlQuery), "ReservedWords.txt"))
28 using (var reader = new StreamReader(stream))
29 {
30 /*
31 var words = reader.ReadToEnd().Replace(' ', '\n').Replace('\t', '\n').Split('\n');
32 var q = from w in words where w.Length > 0 orderby w select w;
33
34 var text = string.Join("\n", q.Distinct().ToArray());
35 */
36
37 string s;
38 while ((s = reader.ReadLine()) != null)
39 _reservedWords.Add(s, s);
40 }
41 }
42
43 public SqlQuery()
44 {
45 SourceID = Interlocked.Increment(ref SourceIDCounter);
46
47 _select = new SelectClause (this);
48 _from = new FromClause (this);
49 _where = new WhereClause (this);
50 _groupBy = new GroupByClause(this);
51 _having = new WhereClause (this);
52 _orderBy = new OrderByClause(this);
53 }
54
55 internal SqlQuery(int id)
56 {
57 SourceID = id;
58 }
59
60 internal void Init(
61 InsertClause insert,
62 UpdateClause update,
63 DeleteClause delete,
64 SelectClause select,
65 FromClause from,
66 WhereClause where,
67 GroupByClause groupBy,
68 WhereClause having,
69 OrderByClause orderBy,
70 List<Union> unions,
71 SqlQuery parentSql,
72 bool parameterDependent,
73 List<SqlParameter> parameters)
74 {
75 _insert = insert;
76 _update = update;
77 _delete = delete;
78 _select = select;
79 _from = from;
80 _where = where;
81 _groupBy = groupBy;
82 _having = having;
83 _orderBy = orderBy;
84 _unions = unions;
85 ParentSql = parentSql;
86 IsParameterDependent = parameterDependent;
87 _parameters.AddRange(parameters);
88
89 foreach (var col in select.Columns)
90 col.Parent = this;
91
92 _select. SetSqlQuery(this);
93 _from. SetSqlQuery(this);
94 _where. SetSqlQuery(this);
95 _groupBy.SetSqlQuery(this);
96 _having. SetSqlQuery(this);
97 _orderBy.SetSqlQuery(this);
98 }
99
100 readonly List<SqlParameter> _parameters = new List<SqlParameter>();
101 public List<SqlParameter> Parameters
102 {
103 get { return _parameters; }
104 }
105
106 private List<object> _properties;
107 public List<object> Properties
108 {
109 get { return _properties ?? (_properties = new List<object>()); }
110 }
111
112 public bool IsParameterDependent { get; set; }
113 public SqlQuery ParentSql { get; set; }
114
115 public bool IsSimple
116 {
117 get { return !Select.HasModifier && Where.IsEmpty && GroupBy.IsEmpty && Having.IsEmpty && OrderBy.IsEmpty; }
118 }
119
120 private QueryType _queryType = QueryType.Select;
121 public QueryType QueryType
122 {
123 get { return _queryType; }
124 set { _queryType = value; }
125 }
126
127 public bool IsSelect { get { return _queryType == QueryType.Select; } }
128 public bool IsDelete { get { return _queryType == QueryType.Delete; } }
129 public bool IsInsertOrUpdate { get { return _queryType == QueryType.InsertOrUpdate; } }
130 public bool IsInsert { get { return _queryType == QueryType.Insert || _queryType == QueryType.InsertOrUpdate; } }
131 public bool IsUpdate { get { return _queryType == QueryType.Update || _queryType == QueryType.InsertOrUpdate; } }
132
133 #endregion
134
135 #region Column
136
137 public class Column : IEquatable<Column>, ISqlExpression, IChild<SqlQuery>
138 {
139 public Column(SqlQuery parent, ISqlExpression expression, string alias)
140 {
141 if (expression == null) throw new ArgumentNullException("expression");
142
143 Parent = parent;
144 Expression = expression;
145 _alias = alias;
146
147 #if DEBUG
148 _columnNumber = ++_columnCounter;
149 #endif
150 }
151
152 public Column(SqlQuery builder, ISqlExpression expression)
153 : this(builder, expression, null)
154 {
155 }
156
157 #if DEBUG
158 readonly int _columnNumber;
159 static int _columnCounter;
160 #endif
161
162 public ISqlExpression Expression { get; set; }
163
164 internal string _alias;
165 public string Alias
166 {
167 get
168 {
169 if (_alias == null)
170 {
171 if (Expression is SqlField)
172 {
173 var field = (SqlField)Expression;
174 return field.Alias ?? field.PhysicalName;
175 }
176
177 if (Expression is Column)
178 {
179 var col = (Column)Expression;
180 return col.Alias;
181 }
182 }
183
184 return _alias;
185 }
186 set { _alias = value; }
187 }
188
189 public bool Equals(Column other)
190 {
191 return Expression.Equals(other.Expression);
192 }
193
194 #if OVERRIDETOSTRING
195
196 public override string ToString()
197 {
198 return ((IQueryElement)this).ToString(new StringBuilder(), new Dictionary<IQueryElement,IQueryElement>()).ToString();
199 }
200
201 #endif
202
203 #region ISqlExpression Members
204
205 public bool CanBeNull()
206 {
207 return Expression.CanBeNull();
208 }
209
210 public bool Equals(ISqlExpression other, Func<ISqlExpression,ISqlExpression,bool> comparer)
211 {
212 if (this == other)
213 return true;
214
215 return
216 other is Column &&
217 Expression.Equals(((Column)other).Expression, comparer) &&
218 comparer(this, other);
219 }
220
221 public int Precedence
222 {
223 get { return Sql.Precedence.Primary; }
224 }
225
226 public Type SystemType
227 {
228 get { return Expression.SystemType; }
229 }
230
231 public ICloneableElement Clone(Dictionary<ICloneableElement, ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
232 {
233 if (!doClone(this))
234 return this;
235
236 ICloneableElement clone;
237
238 var parent = (SqlQuery)Parent.Clone(objectTree, doClone);
239
240 if (!objectTree.TryGetValue(this, out clone))
241 objectTree.Add(this, clone = new Column(
242 parent,
243 (ISqlExpression)Expression.Clone(objectTree, doClone),
244 _alias));
245
246 return clone;
247 }
248
249 #endregion
250
251 #region IEquatable<ISqlExpression> Members
252
253 bool IEquatable<ISqlExpression>.Equals(ISqlExpression other)
254 {
255 if (this == other)
256 return true;
257
258 return other is Column && Equals((Column)other);
259 }
260
261 #endregion
262
263 #region ISqlExpressionWalkable Members
264
265 [Obsolete]
266 public ISqlExpression Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> func)
267 {
268 if (!(skipColumns && Expression is Column))
269 Expression = Expression.Walk(skipColumns, func);
270
271 return func(this);
272 }
273
274 #endregion
275
276 #region IChild<ISqlTableSource> Members
277
278 string IChild<SqlQuery>.Name
279 {
280 get { return Alias; }
281 }
282
283 public SqlQuery Parent { get; set; }
284
285 #endregion
286
287 #region IQueryElement Members
288
289 public QueryElementType ElementType { get { return QueryElementType.Column; } }
290
291 StringBuilder IQueryElement.ToString(StringBuilder sb, Dictionary<IQueryElement,IQueryElement> dic)
292 {
293 if (dic.ContainsKey(this))
294 return sb.Append("...");
295
296 dic.Add(this, this);
297
298 sb
299 .Append('t')
300 .Append(Parent.SourceID)
301 .Append(".");
302
303 #if DEBUG
304 sb.Append('[').Append(_columnNumber).Append(']');
305 #endif
306
307 if (Expression is SqlQuery)
308 {
309 sb
310 .Append("(\n\t\t");
311 var len = sb.Length;
312 Expression.ToString(sb, dic).Replace("\n", "\n\t\t", len, sb.Length - len);
313 sb.Append("\n\t)");
314 }
315 /*else if (Expression is Column)
316 {
317 var col = (Column)Expression;
318 sb
319 .Append("t")
320 .Append(col.Parent.SourceID)
321 .Append(".")
322 .Append(col.Alias ?? "c" + (col.Parent.Select.Columns.IndexOf(col) + 1));
323 }*/
324 else
325 {
326 Expression.ToString(sb, dic);
327 }
328
329 dic.Remove(this);
330
331 return sb;
332 }
333
334 #endregion
335 }
336
337 #endregion
338
339 #region TableSource
340
341 public class TableSource : ISqlTableSource
342 {
343 public TableSource(ISqlTableSource source, string alias)
344 : this(source, alias, null)
345 {
346 }
347
348 public TableSource(ISqlTableSource source, string alias, params JoinedTable[] joins)
349 {
350 if (source == null) throw new ArgumentNullException("source");
351
352 Source = source;
353 _alias = alias;
354
355 if (joins != null)
356 _joins.AddRange(joins);
357 }
358
359 public TableSource(ISqlTableSource source, string alias, IEnumerable<JoinedTable> joins)
360 {
361 if (source == null) throw new ArgumentNullException("source");
362
363 Source = source;
364 _alias = alias;
365
366 if (joins != null)
367 _joins.AddRange(joins);
368 }
369
370 public ISqlTableSource Source { get; set; }
371 public SqlTableType SqlTableType { get { return Source.SqlTableType; } }
372
373 internal string _alias;
374 public string Alias
375 {
376 get
377 {
378 if (string.IsNullOrEmpty(_alias))
379 {
380 if (Source is TableSource)
381 return (Source as TableSource).Alias;
382
383 if (Source is SqlTable)
384 return ((SqlTable)Source).Alias;
385 }
386
387 return _alias;
388 }
389 set { _alias = value; }
390 }
391
392 public TableSource this[ISqlTableSource table]
393 {
394 get { return this[table, null]; }
395 }
396
397 public TableSource this[ISqlTableSource table, string alias]
398 {
399 get
400 {
401 foreach (var tj in Joins)
402 {
403 var t = CheckTableSource(tj.Table, table, alias);
404
405 if (t != null)
406 return t;
407 }
408
409 return null;
410 }
411 }
412
413 readonly List<JoinedTable> _joins = new List<JoinedTable>();
414 public List<JoinedTable> Joins
415 {
416 get { return _joins; }
417 }
418
419 public void ForEach(Action<TableSource> action, HashSet<SqlQuery> visitedQueries)
420 {
421 action(this);
422 foreach (var join in Joins)
423 join.Table.ForEach(action, visitedQueries);
424
425 if (Source is SqlQuery && visitedQueries.Contains((SqlQuery)Source))
426 ((SqlQuery)Source).ForEachTable(action, visitedQueries);
427 }
428
429 public IEnumerable<ISqlTableSource> GetTables()
430 {
431 yield return Source;
432
433 foreach (var join in Joins)
434 foreach (var table in join.Table.GetTables())
435 yield return table;
436 }
437
438 public int GetJoinNumber()
439 {
440 var n = Joins.Count;
441
442 foreach (var join in Joins)
443 n += join.Table.GetJoinNumber();
444
445 return n;
446 }
447
448 #if OVERRIDETOSTRING
449
450 public override string ToString()
451 {
452 return ((IQueryElement)this).ToString(new StringBuilder(), new Dictionary<IQueryElement,IQueryElement>()).ToString();
453 }
454
455 #endif
456
457 #region IEquatable<ISqlExpression> Members
458
459 bool IEquatable<ISqlExpression>.Equals(ISqlExpression other)
460 {
461 return this == other;
462 }
463
464 #endregion
465
466 #region ISqlExpressionWalkable Members
467
468 [Obsolete]
469 public ISqlExpression Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> func)
470 {
471 Source = (ISqlTableSource)Source.Walk(skipColumns, func);
472
473 foreach (var t in Joins)
474 ((ISqlExpressionWalkable)t).Walk(skipColumns, func);
475
476 return this;
477 }
478
479 #endregion
480
481 #region ISqlTableSource Members
482
483 public int SourceID { get { return Source.SourceID; } }
484 public SqlField All { get { return Source.All; } }
485
486 IList<ISqlExpression> ISqlTableSource.GetKeys(bool allIfEmpty)
487 {
488 return Source.GetKeys(allIfEmpty);
489 }
490
491 #endregion
492
493 #region ICloneableElement Members
494
495 public ICloneableElement Clone(Dictionary<ICloneableElement, ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
496 {
497 if (!doClone(this))
498 return this;
499
500 ICloneableElement clone;
501
502 if (!objectTree.TryGetValue(this, out clone))
503 {
504 var ts = new TableSource((ISqlTableSource)Source.Clone(objectTree, doClone), _alias);
505
506 objectTree.Add(this, clone = ts);
507
508 ts._joins.AddRange(_joins.ConvertAll(jt => (JoinedTable)jt.Clone(objectTree, doClone)));
509 }
510
511 return clone;
512 }
513
514 #endregion
515
516 #region IQueryElement Members
517
518 public QueryElementType ElementType { get { return QueryElementType.TableSource; } }
519
520 StringBuilder IQueryElement.ToString(StringBuilder sb, Dictionary<IQueryElement,IQueryElement> dic)
521 {
522 if (sb.Length > 500)
523 return sb;
524
525 if (dic.ContainsKey(this))
526 return sb.Append("...");
527
528 dic.Add(this, this);
529
530 if (Source is SqlQuery)
531 {
532 sb.Append("(\n\t");
533 var len = sb.Length;
534 Source.ToString(sb, dic).Replace("\n", "\n\t", len, sb.Length - len);
535 sb.Append("\n)");
536 }
537 else
538 Source.ToString(sb, dic);
539
540 sb
541 .Append(" as t")
542 .Append(SourceID);
543
544 foreach (IQueryElement join in Joins)
545 {
546 sb.AppendLine().Append('\t');
547 var len = sb.Length;
548 join.ToString(sb, dic).Replace("\n", "\n\t", len, sb.Length - len);
549 }
550
551 dic.Remove(this);
552
553 return sb;
554 }
555
556 #endregion
557
558 #region ISqlExpression Members
559
560 public bool CanBeNull()
561 {
562 return Source.CanBeNull();
563 }
564
565 public bool Equals(ISqlExpression other, Func<ISqlExpression,ISqlExpression,bool> comparer)
566 {
567 return this == other;
568 }
569
570 public int Precedence { get { return Source.Precedence; } }
571 public Type SystemType { get { return Source.SystemType; } }
572
573 #endregion
574 }
575
576 #endregion
577
578 #region TableJoin
579
580 public enum JoinType
581 {
582 Auto,
583 Inner,
584 Left,
585 CrossApply,
586 OuterApply
587 }
588
589 public class JoinedTable : IQueryElement, ISqlExpressionWalkable, ICloneableElement
590 {
591 public JoinedTable(JoinType joinType, TableSource table, bool isWeak, SearchCondition searchCondition)
592 {
593 JoinType = joinType;
594 Table = table;
595 IsWeak = isWeak;
596 Condition = searchCondition;
597 CanConvertApply = true;
598 }
599
600 public JoinedTable(JoinType joinType, TableSource table, bool isWeak)
601 : this(joinType, table, isWeak, new SearchCondition())
602 {
603 }
604
605 public JoinedTable(JoinType joinType, ISqlTableSource table, string alias, bool isWeak)
606 : this(joinType, new TableSource(table, alias), isWeak)
607 {
608 }
609
610 public JoinType JoinType { get; set; }
611 public TableSource Table { get; set; }
612 public SearchCondition Condition { get; private set; }
613 public bool IsWeak { get; set; }
614 public bool CanConvertApply { get; set; }
615
616 public ICloneableElement Clone(Dictionary<ICloneableElement,ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
617 {
618 if (!doClone(this))
619 return this;
620
621 ICloneableElement clone;
622
623 if (!objectTree.TryGetValue(this, out clone))
624 objectTree.Add(this, clone = new JoinedTable(
625 JoinType,
626 (TableSource)Table.Clone(objectTree, doClone),
627 IsWeak,
628 (SearchCondition)Condition.Clone(objectTree, doClone)));
629
630 return clone;
631 }
632
633 #if OVERRIDETOSTRING
634
635 public override string ToString()
636 {
637 return ((IQueryElement)this).ToString(new StringBuilder(), new Dictionary<IQueryElement,IQueryElement>()).ToString();
638 }
639
640 #endif
641
642 #region ISqlExpressionWalkable Members
643
644 [Obsolete]
645 public ISqlExpression Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> action)
646 {
647 Condition = (SearchCondition)((ISqlExpressionWalkable)Condition).Walk(skipColumns, action);
648
649 #pragma warning disable 0618
650 Table.Walk(skipColumns, action);
651 #pragma warning restore 0618
652
653 return null;
654 }
655
656 #endregion
657
658 #region IQueryElement Members
659
660 public QueryElementType ElementType { get { return QueryElementType.JoinedTable; } }
661
662 StringBuilder IQueryElement.ToString(StringBuilder sb, Dictionary<IQueryElement,IQueryElement> dic)
663 {
664 if (dic.ContainsKey(this))
665 return sb.Append("...");
666
667 dic.Add(this, this);
668
669 switch (JoinType)
670 {
671 case JoinType.Inner : sb.Append("INNER JOIN "); break;
672 case JoinType.Left : sb.Append("LEFT JOIN "); break;
673 case JoinType.CrossApply : sb.Append("CROSS APPLY "); break;
674 case JoinType.OuterApply : sb.Append("OUTER APPLY "); break;
675 default : sb.Append("SOME JOIN "); break;
676 }
677
678 ((IQueryElement)Table).ToString(sb, dic);
679 sb.Append(" ON ");
680 ((IQueryElement)Condition).ToString(sb, dic);
681
682 dic.Remove(this);
683
684 return sb;
685 }
686
687 #endregion
688 }
689
690 #endregion
691
692 #region Predicate
693
694 public abstract class Predicate : ISqlPredicate
695 {
696 public enum Operator
697 {
698 Equal, // = Is the operator used to test the equality between two expressions.
699 NotEqual, // <> != Is the operator used to test the condition of two expressions not being equal to each other.
700 Greater, // > Is the operator used to test the condition of one expression being greater than the other.
701 GreaterOrEqual, // >= Is the operator used to test the condition of one expression being greater than or equal to the other expression.
702 NotGreater, // !> Is the operator used to test the condition of one expression not being greater than the other expression.
703 Less, // < Is the operator used to test the condition of one expression being less than the other.
704 LessOrEqual, // <= Is the operator used to test the condition of one expression being less than or equal to the other expression.
705 NotLess // !< Is the operator used to test the condition of one expression not being less than the other expression.
706 }
707
708 public class Expr : Predicate
709 {
710 public Expr([NotNull] ISqlExpression exp1, int precedence)
711 : base(precedence)
712 {
713 if (exp1 == null) throw new ArgumentNullException("exp1");
714
715 Expr1 = exp1;
716 }
717
718 public Expr([NotNull] ISqlExpression exp1)
719 : base(exp1.Precedence)
720 {
721 if (exp1 == null) throw new ArgumentNullException("exp1");
722
723 Expr1 = exp1;
724 }
725
726 public ISqlExpression Expr1 { get; set; }
727
728 [Obsolete]
729 protected override void Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> func)
730 {
731 Expr1 = Expr1.Walk(skipColumns, func);
732
733 if (Expr1 == null)
734 throw new InvalidOperationException();
735 }
736
737 public override bool CanBeNull()
738 {
739 return Expr1.CanBeNull();
740 }
741
742 protected override ICloneableElement Clone(Dictionary<ICloneableElement,ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
743 {
744 if (!doClone(this))
745 return this;
746
747 ICloneableElement clone;
748
749 if (!objectTree.TryGetValue(this, out clone))
750 objectTree.Add(this, clone = new Expr((ISqlExpression)Expr1.Clone(objectTree, doClone), Precedence));
751
752 return clone;
753 }
754
755 public override QueryElementType ElementType
756 {
757 get { return QueryElementType.ExprPredicate; }
758 }
759
760 protected override void ToString(StringBuilder sb, Dictionary<IQueryElement, IQueryElement> dic)
761 {
762 Expr1.ToString(sb, dic);
763 }
764 }
765
766 public class NotExpr : Expr
767 {
768 public NotExpr(ISqlExpression exp1, bool isNot, int precedence)
769 : base(exp1, precedence)
770 {
771 IsNot = isNot;
772 }
773
774 public bool IsNot { get; set; }
775
776 protected override ICloneableElement Clone(Dictionary<ICloneableElement,ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
777 {
778 if (!doClone(this))
779 return this;
780
781 ICloneableElement clone;
782
783 if (!objectTree.TryGetValue(this, out clone))
784 objectTree.Add(this, clone = new NotExpr((ISqlExpression)Expr1.Clone(objectTree, doClone), IsNot, Precedence));
785
786 return clone;
787 }
788
789 public override QueryElementType ElementType
790 {
791 get { return QueryElementType.NotExprPredicate; }
792 }
793
794 protected override void ToString(StringBuilder sb, Dictionary<IQueryElement, IQueryElement> dic)
795 {
796 if (IsNot) sb.Append("NOT (");
797 base.ToString(sb, dic);
798 if (IsNot) sb.Append(")");
799 }
800 }
801
802 // { expression { = | <> | != | > | >= | ! > | < | <= | !< } expression
803 //
804 public class ExprExpr : Expr
805 {
806 public ExprExpr(ISqlExpression exp1, Operator op, ISqlExpression exp2)
807 : base(exp1, Sql.Precedence.Comparison)
808 {
809 this.Operator = op;
810 Expr2 = exp2;
811 }
812
813 public new Operator Operator { get; private set; }
814 public ISqlExpression Expr2 { get; internal set; }
815
816 [Obsolete]
817 protected override void Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> func)
818 {
819 #pragma warning disable 0618
820 base.Walk(skipColumns, func);
821 #pragma warning restore 0618
822 Expr2 = Expr2.Walk(skipColumns, func);
823 }
824
825 public override bool CanBeNull()
826 {
827 return base.CanBeNull() || Expr2.CanBeNull();
828 }
829
830 protected override ICloneableElement Clone(Dictionary<ICloneableElement,ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
831 {
832 if (!doClone(this))
833 return this;
834
835 ICloneableElement clone;
836
837 if (!objectTree.TryGetValue(this, out clone))
838 objectTree.Add(this, clone = new ExprExpr(
839 (ISqlExpression)Expr1.Clone(objectTree, doClone), this.Operator, (ISqlExpression)Expr2.Clone(objectTree, doClone)));
840
841 return clone;
842 }
843
844 public override QueryElementType ElementType
845 {
846 get { return QueryElementType.ExprExprPredicate; }
847 }
848
849 protected override void ToString(StringBuilder sb, Dictionary<IQueryElement, IQueryElement> dic)
850 {
851 Expr1.ToString(sb, dic);
852
853 string op;
854
855 switch (this.Operator)
856 {
857 case Operator.Equal : op = "="; break;
858 case Operator.NotEqual : op = "<>"; break;
859 case Operator.Greater : op = ">"; break;
860 case Operator.GreaterOrEqual: op = ">="; break;
861 case Operator.NotGreater : op = "!>"; break;
862 case Operator.Less : op = "<"; break;
863 case Operator.LessOrEqual : op = "<="; break;
864 case Operator.NotLess : op = "!<"; break;
865 default: throw new InvalidOperationException();
866 }
867
868 sb.Append(" ").Append(op).Append(" ");
869
870 Expr2.ToString(sb, dic);
871 }
872 }
873
874 // string_expression [ NOT ] LIKE string_expression [ ESCAPE 'escape_character' ]
875 //
876 public class Like : NotExpr
877 {
878 public Like(ISqlExpression exp1, bool isNot, ISqlExpression exp2, ISqlExpression escape)
879 : base(exp1, isNot, Sql.Precedence.Comparison)
880 {
881 Expr2 = exp2;
882 Escape = escape;
883 }
884
885 public ISqlExpression Expr2 { get; internal set; }
886 public ISqlExpression Escape { get; internal set; }
887
888 [Obsolete]
889 protected override void Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> func)
890 {
891 #pragma warning disable 0618
892 base.Walk(skipColumns, func);
893 #pragma warning restore 0618
894 Expr2 = Expr2.Walk(skipColumns, func);
895
896 if (Escape != null)
897 Escape = Escape.Walk(skipColumns, func);
898 }
899
900 protected override ICloneableElement Clone(Dictionary<ICloneableElement,ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
901 {
902 if (!doClone(this))
903 return this;
904
905 ICloneableElement clone;
906
907 if (!objectTree.TryGetValue(this, out clone))
908 objectTree.Add(this, clone = new Like(
909 (ISqlExpression)Expr1.Clone(objectTree, doClone), IsNot, (ISqlExpression)Expr2.Clone(objectTree, doClone), Escape));
910
911 return clone;
912 }
913
914 public override QueryElementType ElementType
915 {
916 get { return QueryElementType.LikePredicate; }
917 }
918
919 protected override void ToString(StringBuilder sb, Dictionary<IQueryElement, IQueryElement> dic)
920 {
921 Expr1.ToString(sb, dic);
922
923 if (IsNot) sb.Append(" NOT");
924 sb.Append(" LIKE ");
925
926 Expr2.ToString(sb, dic);
927
928 if (Escape != null)
929 {
930 sb.Append(" ESCAPE ");
931 Escape.ToString(sb, dic);
932 }
933 }
934 }
935
936 // expression [ NOT ] BETWEEN expression AND expression
937 //
938 public class Between : NotExpr
939 {
940 public Between(ISqlExpression exp1, bool isNot, ISqlExpression exp2, ISqlExpression exp3)
941 : base(exp1, isNot, Sql.Precedence.Comparison)
942 {
943 Expr2 = exp2;
944 Expr3 = exp3;
945 }
946
947 public ISqlExpression Expr2 { get; internal set; }
948 public ISqlExpression Expr3 { get; internal set; }
949
950 [Obsolete]
951 protected override void Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> func)
952 {
953 #pragma warning disable 0618
954 base.Walk(skipColumns, func);
955 #pragma warning restore 0618
956 Expr2 = Expr2.Walk(skipColumns, func);
957 Expr3 = Expr3.Walk(skipColumns, func);
958 }
959
960 protected override ICloneableElement Clone(Dictionary<ICloneableElement,ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
961 {
962 if (!doClone(this))
963 return this;
964
965 ICloneableElement clone;
966
967 if (!objectTree.TryGetValue(this, out clone))
968 objectTree.Add(this, clone = new Between(
969 (ISqlExpression)Expr1.Clone(objectTree, doClone),
970 IsNot,
971 (ISqlExpression)Expr2.Clone(objectTree, doClone),
972 (ISqlExpression)Expr3.Clone(objectTree, doClone)));
973
974 return clone;
975 }
976
977 public override QueryElementType ElementType
978 {
979 get { return QueryElementType.BetweenPredicate; }
980 }
981
982 protected override void ToString(StringBuilder sb, Dictionary<IQueryElement, IQueryElement> dic)
983 {
984 Expr1.ToString(sb, dic);
985
986 if (IsNot) sb.Append(" NOT");
987 sb.Append(" BETWEEN ");
988
989 Expr2.ToString(sb, dic);
990 sb.Append(" AND ");
991 Expr3.ToString(sb, dic);
992 }
993 }
994
995 // expression IS [ NOT ] NULL
996 //
997 public class IsNull : NotExpr
998 {
999 public IsNull(ISqlExpression exp1, bool isNot)
1000 : base(exp1, isNot, Sql.Precedence.Comparison)
1001 {
1002 }
1003
1004 protected override ICloneableElement Clone(Dictionary<ICloneableElement,ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
1005 {
1006 if (!doClone(this))
1007 return this;
1008
1009 ICloneableElement clone;
1010
1011 if (!objectTree.TryGetValue(this, out clone))
1012 objectTree.Add(this, clone = new IsNull((ISqlExpression)Expr1.Clone(objectTree, doClone), IsNot));
1013
1014 return clone;
1015 }
1016
1017 protected override void ToString(StringBuilder sb, Dictionary<IQueryElement, IQueryElement> dic)
1018 {
1019 Expr1.ToString(sb, dic);
1020 sb
1021 .Append(" IS ")
1022 .Append(IsNot ? "NOT " : "")
1023 .Append("NULL");
1024 }
1025
1026 public override QueryElementType ElementType
1027 {
1028 get { return QueryElementType.IsNullPredicate; }
1029 }
1030 }
1031
1032 // expression [ NOT ] IN ( subquery | expression [ ,...n ] )
1033 //
1034 public class InSubQuery : NotExpr
1035 {
1036 public InSubQuery(ISqlExpression exp1, bool isNot, SqlQuery subQuery)
1037 : base(exp1, isNot, Sql.Precedence.Comparison)
1038 {
1039 SubQuery = subQuery;
1040 }
1041
1042 public SqlQuery SubQuery { get; private set; }
1043
1044 [Obsolete]
1045 protected override void Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> func)
1046 {
1047 #pragma warning disable 0618
1048 base.Walk(skipColumns, func);
1049 #pragma warning restore 0618
1050 SubQuery = (SqlQuery)((ISqlExpression)SubQuery).Walk(skipColumns, func);
1051 }
1052
1053 protected override ICloneableElement Clone(Dictionary<ICloneableElement,ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
1054 {
1055 if (!doClone(this))
1056 return this;
1057
1058 ICloneableElement clone;
1059
1060 if (!objectTree.TryGetValue(this, out clone))
1061 objectTree.Add(this, clone = new InSubQuery(
1062 (ISqlExpression)Expr1.Clone(objectTree, doClone),
1063 IsNot,
1064 (SqlQuery)SubQuery.Clone(objectTree, doClone)));
1065
1066 return clone;
1067 }
1068
1069 public override QueryElementType ElementType
1070 {
1071 get { return QueryElementType.InSubQueryPredicate; }
1072 }
1073
1074 protected override void ToString(StringBuilder sb, Dictionary<IQueryElement, IQueryElement> dic)
1075 {
1076 Expr1.ToString(sb, dic);
1077
1078 if (IsNot) sb.Append(" NOT");
1079 sb.Append(" IN (");
1080
1081 ((IQueryElement)SubQuery).ToString(sb, dic);
1082 sb.Append(")");
1083 }
1084 }
1085
1086 public class InList : NotExpr
1087 {
1088 public InList(ISqlExpression exp1, bool isNot, params ISqlExpression[] values)
1089 : base(exp1, isNot, Sql.Precedence.Comparison)
1090 {
1091 if (values != null && values.Length > 0)
1092 _values.AddRange(values);
1093 }
1094
1095 public InList(ISqlExpression exp1, bool isNot, IEnumerable<ISqlExpression> values)
1096 : base(exp1, isNot, Sql.Precedence.Comparison)
1097 {
1098 if (values != null)
1099 _values.AddRange(values);
1100 }
1101
1102 readonly List<ISqlExpression> _values = new List<ISqlExpression>();
1103 public List<ISqlExpression> Values { get { return _values; } }
1104
1105 [Obsolete]
1106 protected override void Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> action)
1107 {
1108 #pragma warning disable 0618
1109 base.Walk(skipColumns, action);
1110 #pragma warning restore 0618
1111 for (var i = 0; i < _values.Count; i++)
1112 _values[i] = _values[i].Walk(skipColumns, action);
1113 }
1114
1115 protected override ICloneableElement Clone(Dictionary<ICloneableElement,ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
1116 {
1117 if (!doClone(this))
1118 return this;
1119
1120 ICloneableElement clone;
1121
1122 if (!objectTree.TryGetValue(this, out clone))
1123 {
1124 objectTree.Add(this, clone = new InList(
1125 (ISqlExpression)Expr1.Clone(objectTree, doClone),
1126 IsNot,
1127 _values.ConvertAll(e => (ISqlExpression)e.Clone(objectTree, doClone)).ToArray()));
1128 }
1129
1130 return clone;
1131 }
1132
1133 public override QueryElementType ElementType
1134 {
1135 get { return QueryElementType.InListPredicate; }
1136 }
1137
1138 protected override void ToString(StringBuilder sb, Dictionary<IQueryElement, IQueryElement> dic)
1139 {
1140 Expr1.ToString(sb, dic);
1141
1142 if (IsNot) sb.Append(" NOT");
1143 sb.Append(" IN (");
1144
1145 foreach (var value in Values)
1146 {
1147 value.ToString(sb, dic);
1148 sb.Append(',');
1149 }
1150
1151 if (Values.Count > 0)
1152 sb.Length--;
1153
1154 sb.Append(")");
1155 }
1156 }
1157
1158 // CONTAINS ( { column | * } , '< contains_search_condition >' )
1159 // FREETEXT ( { column | * } , 'freetext_string' )
1160 // expression { = | <> | != | > | >= | !> | < | <= | !< } { ALL | SOME | ANY } ( subquery )
1161 // EXISTS ( subquery )
1162
1163 public class FuncLike : Predicate
1164 {
1165 public FuncLike(SqlFunction func)
1166 : base(func.Precedence)
1167 {
1168 Function = func;
1169 }
1170
1171 public SqlFunction Function { get; private set; }
1172
1173 [Obsolete]
1174 protected override void Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> func)
1175 {
1176 Function = (SqlFunction)((ISqlExpression)Function).Walk(skipColumns, func);
1177 }
1178
1179 public override bool CanBeNull()
1180 {
1181 return Function.CanBeNull();
1182 }
1183
1184 protected override ICloneableElement Clone(Dictionary<ICloneableElement,ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
1185 {
1186 if (!doClone(this))
1187 return this;
1188
1189 ICloneableElement clone;
1190
1191 if (!objectTree.TryGetValue(this, out clone))
1192 objectTree.Add(this, clone = new FuncLike((SqlFunction)Function.Clone(objectTree, doClone)));
1193
1194 return clone;
1195 }
1196
1197 public override QueryElementType ElementType
1198 {
1199 get { return QueryElementType.FuncLikePredicate; }
1200 }
1201
1202 protected override void ToString(StringBuilder sb, Dictionary<IQueryElement, IQueryElement> dic)
1203 {
1204 ((IQueryElement)Function).ToString(sb, dic);
1205 }
1206 }
1207
1208 #region Overrides
1209
1210 #if OVERRIDETOSTRING
1211
1212 public override string ToString()
1213 {
1214 return ((IQueryElement)this).ToString(new StringBuilder(), new Dictionary<IQueryElement,IQueryElement>()).ToString();
1215 }
1216
1217 #endif
1218
1219 #endregion
1220
1221 protected Predicate(int precedence)
1222 {
1223 Precedence = precedence;
1224 }
1225
1226 #region IPredicate Members
1227
1228 public int Precedence { get; private set; }
1229
1230 public abstract bool CanBeNull();
1231 protected abstract ICloneableElement Clone (Dictionary<ICloneableElement,ICloneableElement> objectTree, Predicate<ICloneableElement> doClone);
1232 [Obsolete]
1233 protected abstract void Walk (bool skipColumns, Func<ISqlExpression,ISqlExpression> action);
1234
1235 [Obsolete]
1236 ISqlExpression ISqlExpressionWalkable.Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> func)
1237 {
1238 Walk(skipColumns, func);
1239 return null;
1240 }
1241
1242 ICloneableElement ICloneableElement.Clone(Dictionary<ICloneableElement, ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
1243 {
1244 if (!doClone(this))
1245 return this;
1246
1247 return Clone(objectTree, doClone);
1248 }
1249
1250 #endregion
1251
1252 #region IQueryElement Members
1253
1254 public abstract QueryElementType ElementType { get; }
1255
1256 protected abstract void ToString(StringBuilder sb, Dictionary<IQueryElement, IQueryElement> dic);
1257
1258 StringBuilder IQueryElement.ToString(StringBuilder sb, Dictionary<IQueryElement,IQueryElement> dic)
1259 {
1260 if (dic.ContainsKey(this))
1261 return sb.Append("...");
1262
1263 dic.Add(this, this);
1264 ToString(sb, dic);
1265 dic.Remove(this);
1266
1267 return sb;
1268 }
1269
1270 #endregion
1271 }
1272
1273 #endregion
1274
1275 #region Condition
1276
1277 public class Condition : IQueryElement, ICloneableElement
1278 {
1279 public Condition(bool isNot, ISqlPredicate predicate)
1280 {
1281 IsNot = isNot;
1282 Predicate = predicate;
1283 }
1284
1285 public Condition(bool isNot, ISqlPredicate predicate, bool isOr)
1286 {
1287 IsNot = isNot;
1288 Predicate = predicate;
1289 IsOr = isOr;
1290 }
1291
1292 public bool IsNot { get; set; }
1293 public ISqlPredicate Predicate { get; set; }
1294 public bool IsOr { get; set; }
1295
1296 public int Precedence
1297 {
1298 get
1299 {
1300 return
1301 IsNot ? Sql.Precedence.LogicalNegation :
1302 IsOr ? Sql.Precedence.LogicalDisjunction :
1303 Sql.Precedence.LogicalConjunction;
1304 }
1305 }
1306
1307 public ICloneableElement Clone(Dictionary<ICloneableElement, ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
1308 {
1309 if (!doClone(this))
1310 return this;
1311
1312 ICloneableElement clone;
1313
1314 if (!objectTree.TryGetValue(this, out clone))
1315 objectTree.Add(this, clone = new Condition(IsNot, (ISqlPredicate)Predicate.Clone(objectTree, doClone), IsOr));
1316
1317 return clone;
1318 }
1319
1320 public bool CanBeNull()
1321 {
1322 return Predicate.CanBeNull();
1323 }
1324
1325 #if OVERRIDETOSTRING
1326
1327 public override string ToString()
1328 {
1329 return ((IQueryElement)this).ToString(new StringBuilder(), new Dictionary<IQueryElement,IQueryElement>()).ToString();
1330 }
1331
1332 #endif
1333
1334 #region IQueryElement Members
1335
1336 public QueryElementType ElementType { get { return QueryElementType.Condition; } }
1337
1338 StringBuilder IQueryElement.ToString(StringBuilder sb, Dictionary<IQueryElement,IQueryElement> dic)
1339 {
1340 if (dic.ContainsKey(this))
1341 return sb.Append("...");
1342
1343 dic.Add(this, this);
1344
1345 sb.Append('(');
1346
1347 if (IsNot) sb.Append("NOT ");
1348
1349 Predicate.ToString(sb, dic);
1350 sb.Append(')').Append(IsOr ? " OR " : " AND ");
1351
1352 dic.Remove(this);
1353
1354 return sb;
1355 }
1356
1357 #endregion
1358 }
1359
1360 #endregion
1361
1362 #region SearchCondition
1363
1364 public class SearchCondition : ConditionBase<SearchCondition, SearchCondition.Next>, ISqlPredicate, ISqlExpression
1365 {
1366 public SearchCondition()
1367 {
1368 }
1369
1370 public SearchCondition(IEnumerable<Condition> list)
1371 {
1372 _conditions.AddRange(list);
1373 }
1374
1375 public SearchCondition(params Condition[] list)
1376 {
1377 _conditions.AddRange(list);
1378 }
1379
1380 public class Next
1381 {
1382 internal Next(SearchCondition parent)
1383 {
1384 _parent = parent;
1385 }
1386
1387 readonly SearchCondition _parent;
1388
1389 public SearchCondition Or { get { return _parent.SetOr(true); } }
1390 public SearchCondition And { get { return _parent.SetOr(false); } }
1391
1392 public ISqlExpression ToExpr() { return _parent; }
1393 }
1394
1395 readonly List<Condition> _conditions = new List<Condition>();
1396 public List<Condition> Conditions
1397 {
1398 get { return _conditions; }
1399 }
1400
1401 protected override SearchCondition Search
1402 {
1403 get { return this; }
1404 }
1405
1406 protected override Next GetNext()
1407 {
1408 return new Next(this);
1409 }
1410
1411 #region Overrides
1412
1413 #if OVERRIDETOSTRING
1414
1415 public override string ToString()
1416 {
1417 return ((IQueryElement)this).ToString(new StringBuilder(), new Dictionary<IQueryElement,IQueryElement>()).ToString();
1418 }
1419
1420 #endif
1421
1422 #endregion
1423
1424 #region IPredicate Members
1425
1426 public int Precedence
1427 {
1428 get
1429 {
1430 if (_conditions.Count == 0) return Sql.Precedence.Unknown;
1431 if (_conditions.Count == 1) return _conditions[0].Precedence;
1432
1433 return _conditions.Select(_ =>
1434 _.IsNot ? Sql.Precedence.LogicalNegation :
1435 _.IsOr ? Sql.Precedence.LogicalDisjunction :
1436 Sql.Precedence.LogicalConjunction).Min();
1437 }
1438 }
1439
1440 public Type SystemType
1441 {
1442 get { return typeof(bool); }
1443 }
1444
1445 [Obsolete]
1446 ISqlExpression ISqlExpressionWalkable.Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> func)
1447 {
1448 foreach (var condition in Conditions)
1449 condition.Predicate.Walk(skipColumns, func);
1450
1451 return func(this);
1452 }
1453
1454 #endregion
1455
1456 #region IEquatable<ISqlExpression> Members
1457
1458 bool IEquatable<ISqlExpression>.Equals(ISqlExpression other)
1459 {
1460 return this == other;
1461 }
1462
1463 #endregion
1464
1465 #region ISqlExpression Members
1466
1467 public bool CanBeNull()
1468 {
1469 foreach (var c in Conditions)
1470 if (c.CanBeNull())
1471 return true;
1472
1473 return false;
1474 }
1475
1476 public bool Equals(ISqlExpression other, Func<ISqlExpression,ISqlExpression,bool> comparer)
1477 {
1478 return this == other;
1479 }
1480
1481 #endregion
1482
1483 #region ICloneableElement Members
1484
1485 public ICloneableElement Clone(Dictionary<ICloneableElement, ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
1486 {
1487 if (!doClone(this))
1488 return this;
1489
1490 ICloneableElement clone;
1491
1492 if (!objectTree.TryGetValue(this, out clone))
1493 {
1494 var sc = new SearchCondition();
1495
1496 objectTree.Add(this, clone = sc);
1497
1498 sc._conditions.AddRange(_conditions.ConvertAll(c => (Condition)c.Clone(objectTree, doClone)));
1499 }
1500
1501 return clone;
1502 }
1503
1504 #endregion
1505
1506 #region IQueryElement Members
1507
1508 public QueryElementType ElementType { get { return QueryElementType.SearchCondition; } }
1509
1510 StringBuilder IQueryElement.ToString(StringBuilder sb, Dictionary<IQueryElement,IQueryElement> dic)
1511 {
1512 if (dic.ContainsKey(this))
1513 return sb.Append("...");
1514
1515 dic.Add(this, this);
1516
1517 foreach (IQueryElement c in Conditions)
1518 c.ToString(sb, dic);
1519
1520 if (Conditions.Count > 0)
1521 sb.Length -= 4;
1522
1523 dic.Remove(this);
1524
1525 return sb;
1526 }
1527
1528 #endregion
1529 }
1530
1531 #endregion
1532
1533 #region ConditionBase
1534
1535 interface IConditionExpr<T>
1536 {
1537 T Expr (ISqlExpression expr);
1538 T Field (SqlField field);
1539 T SubQuery(SqlQuery sqlQuery);
1540 T Value (object value);
1541 }
1542
1543 public abstract class ConditionBase<T1,T2> : IConditionExpr<ConditionBase<T1,T2>.Expr_>
1544 where T1 : ConditionBase<T1,T2>
1545 {
1546 public class Expr_
1547 {
1548 internal Expr_(ConditionBase<T1,T2> condition, bool isNot, ISqlExpression expr)
1549 {
1550 _condition = condition;
1551 _isNot = isNot;
1552 _expr = expr;
1553 }
1554
1555 readonly ConditionBase<T1,T2> _condition;
1556 readonly bool _isNot;
1557 readonly ISqlExpression _expr;
1558
1559 T2 Add(ISqlPredicate predicate)
1560 {
1561 _condition.Search.Conditions.Add(new Condition(_isNot, predicate));
1562 return _condition.GetNext();
1563 }
1564
1565 #region Predicate.ExprExpr
1566
1567 public class Op_ : IConditionExpr<T2>
1568 {
1569 internal Op_(Expr_ expr, Predicate.Operator op)
1570 {
1571 _expr = expr;
1572 _op = op;
1573 }
1574
1575 readonly Expr_ _expr;
1576 readonly Predicate.Operator _op;
1577
1578 public T2 Expr (ISqlExpression expr) { return _expr.Add(new Predicate.ExprExpr(_expr._expr, _op, expr)); }
1579 public T2 Field (SqlField field) { return Expr(field); }
1580 public T2 SubQuery(SqlQuery subQuery) { return Expr(subQuery); }
1581 public T2 Value (object value) { return Expr(new SqlValue(value)); }
1582
1583 public T2 All (SqlQuery subQuery) { return Expr(SqlFunction.CreateAll (subQuery)); }
1584 public T2 Some (SqlQuery subQuery) { return Expr(SqlFunction.CreateSome(subQuery)); }
1585 public T2 Any (SqlQuery subQuery) { return Expr(SqlFunction.CreateAny (subQuery)); }
1586 }
1587
1588 public Op_ Equal { get { return new Op_(this, Predicate.Operator.Equal); } }
1589 public Op_ NotEqual { get { return new Op_(this, Predicate.Operator.NotEqual); } }
1590 public Op_ Greater { get { return new Op_(this, Predicate.Operator.Greater); } }
1591 public Op_ GreaterOrEqual { get { return new Op_(this, Predicate.Operator.GreaterOrEqual); } }
1592 public Op_ NotGreater { get { return new Op_(this, Predicate.Operator.NotGreater); } }
1593 public Op_ Less { get { return new Op_(this, Predicate.Operator.Less); } }
1594 public Op_ LessOrEqual { get { return new Op_(this, Predicate.Operator.LessOrEqual); } }
1595 public Op_ NotLess { get { return new Op_(this, Predicate.Operator.NotLess); } }
1596
1597 #endregion
1598
1599 #region Predicate.Like
1600
1601 public T2 Like(ISqlExpression expression, SqlValue escape) { return Add(new Predicate.Like(_expr, false, expression, escape)); }
1602 public T2 Like(ISqlExpression expression) { return Like(expression, null); }
1603 public T2 Like(string expression, SqlValue escape) { return Like(new SqlValue(expression), escape); }
1604 public T2 Like(string expression) { return Like(new SqlValue(expression), null); }
1605
1606 #endregion
1607
1608 #region Predicate.Between
1609
1610 public T2 Between (ISqlExpression expr1, ISqlExpression expr2) { return Add(new Predicate.Between(_expr, false, expr1, expr2)); }
1611 public T2 NotBetween(ISqlExpression expr1, ISqlExpression expr2) { return Add(new Predicate.Between(_expr, true, expr1, expr2)); }
1612
1613 #endregion
1614
1615 #region Predicate.IsNull
1616
1617 public T2 IsNull { get { return Add(new Predicate.IsNull(_expr, false)); } }
1618 public T2 IsNotNull { get { return Add(new Predicate.IsNull(_expr, true)); } }
1619
1620 #endregion
1621
1622 #region Predicate.In
1623
1624 public T2 In (SqlQuery subQuery) { return Add(new Predicate.InSubQuery(_expr, false, subQuery)); }
1625 public T2 NotIn(SqlQuery subQuery) { return Add(new Predicate.InSubQuery(_expr, true, subQuery)); }
1626
1627 Predicate.InList CreateInList(bool isNot, object[] exprs)
1628 {
1629 var list = new Predicate.InList(_expr, isNot, null);
1630
1631 if (exprs != null && exprs.Length > 0)
1632 {
1633 foreach (var item in exprs)
1634 {
1635 if (item == null || item is SqlValue && ((SqlValue)item).Value == null)
1636 continue;
1637
1638 if (item is ISqlExpression)
1639 list.Values.Add((ISqlExpression)item);
1640 else
1641 list.Values.Add(new SqlValue(item));
1642 }
1643 }
1644
1645 return list;
1646 }
1647
1648 public T2 In (params object[] exprs) { return Add(CreateInList(false, exprs)); }
1649 public T2 NotIn(params object[] exprs) { return Add(CreateInList(true, exprs)); }
1650
1651 #endregion
1652 }
1653
1654 public class Not_ : IConditionExpr<Expr_>
1655 {
1656 internal Not_(ConditionBase<T1,T2> condition)
1657 {
1658 _condition = condition;
1659 }
1660
1661 readonly ConditionBase<T1,T2> _condition;
1662
1663 public Expr_ Expr (ISqlExpression expr) { return new Expr_(_condition, true, expr); }
1664 public Expr_ Field (SqlField field) { return Expr(field); }
1665 public Expr_ SubQuery(SqlQuery subQuery) { return Expr(subQuery); }
1666 public Expr_ Value (object value) { return Expr(new SqlValue(value)); }
1667
1668 public T2 Exists(SqlQuery subQuery)
1669 {
1670 _condition.Search.Conditions.Add(new Condition(true, new Predicate.FuncLike(SqlFunction.CreateExists(subQuery))));
1671 return _condition.GetNext();
1672 }
1673 }
1674
1675 protected abstract SearchCondition Search { get; }
1676 protected abstract T2 GetNext();
1677
1678 protected T1 SetOr(bool value)
1679 {
1680 Search.Conditions[Search.Conditions.Count - 1].IsOr = value;
1681 return (T1)this;
1682 }
1683
1684 public Not_ Not { get { return new Not_(this); } }
1685
1686 public Expr_ Expr (ISqlExpression expr) { return new Expr_(this, false, expr); }
1687 public Expr_ Field (SqlField field) { return Expr(field); }
1688 public Expr_ SubQuery(SqlQuery subQuery) { return Expr(subQuery); }
1689 public Expr_ Value (object value) { return Expr(new SqlValue(value)); }
1690
1691 public T2 Exists(SqlQuery subQuery)
1692 {
1693 Search.Conditions.Add(new Condition(false, new Predicate.FuncLike(SqlFunction.CreateExists(subQuery))));
1694 return GetNext();
1695 }
1696 }
1697
1698 #endregion
1699
1700 #region OrderByItem
1701
1702 public class OrderByItem : IQueryElement, ICloneableElement
1703 {
1704 public OrderByItem(ISqlExpression expression, bool isDescending)
1705 {
1706 Expression = expression;
1707 IsDescending = isDescending;
1708 }
1709
1710 public ISqlExpression Expression { get; internal set; }
1711 public bool IsDescending { get; private set; }
1712
1713 [Obsolete]
1714 internal void Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> func)
1715 {
1716 Expression = Expression.Walk(skipColumns, func);
1717 }
1718
1719 public ICloneableElement Clone(Dictionary<ICloneableElement, ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
1720 {
1721 if (!doClone(this))
1722 return this;
1723
1724 ICloneableElement clone;
1725
1726 if (!objectTree.TryGetValue(this, out clone))
1727 objectTree.Add(this, clone = new OrderByItem((ISqlExpression)Expression.Clone(objectTree, doClone), IsDescending));
1728
1729 return clone;
1730 }
1731
1732 #region Overrides
1733
1734 #if OVERRIDETOSTRING
1735
1736 public override string ToString()
1737 {
1738 return ((IQueryElement)this).ToString(new StringBuilder(), new Dictionary<IQueryElement,IQueryElement>()).ToString();
1739 }
1740
1741 #endif
1742
1743 #endregion
1744
1745 #region IQueryElement Members
1746
1747 public QueryElementType ElementType
1748 {
1749 get { return QueryElementType.OrderByItem; }
1750 }
1751
1752 StringBuilder IQueryElement.ToString(StringBuilder sb, Dictionary<IQueryElement,IQueryElement> dic)
1753 {
1754 Expression.ToString(sb, dic);
1755
1756 if (IsDescending)
1757 sb.Append(" DESC");
1758
1759 return sb;
1760 }
1761
1762 #endregion
1763 }
1764
1765 #endregion
1766
1767 #region ClauseBase
1768
1769 public abstract class ClauseBase
1770 {
1771 protected ClauseBase(SqlQuery sqlQuery)
1772 {
1773 SqlQuery = sqlQuery;
1774 }
1775
1776 public SelectClause Select { get { return SqlQuery.Select; } }
1777 public FromClause From { get { return SqlQuery.From; } }
1778 public WhereClause Where { get { return SqlQuery.Where; } }
1779 public GroupByClause GroupBy { get { return SqlQuery.GroupBy; } }
1780 public WhereClause Having { get { return SqlQuery.Having; } }
1781 public OrderByClause OrderBy { get { return SqlQuery.OrderBy; } }
1782 public SqlQuery End() { return SqlQuery; }
1783
1784 protected internal SqlQuery SqlQuery { get; private set; }
1785
1786 internal void SetSqlQuery(SqlQuery sqlQuery)
1787 {
1788 SqlQuery = sqlQuery;
1789 }
1790 }
1791
1792 public abstract class ClauseBase<T1, T2> : ConditionBase<T1, T2>
1793 where T1 : ClauseBase<T1, T2>
1794 {
1795 protected ClauseBase(SqlQuery sqlQuery)
1796 {
1797 SqlQuery = sqlQuery;
1798 }
1799
1800 public SelectClause Select { get { return SqlQuery.Select; } }
1801 public FromClause From { get { return SqlQuery.From; } }
1802 public GroupByClause GroupBy { get { return SqlQuery.GroupBy; } }
1803 public WhereClause Having { get { return SqlQuery.Having; } }
1804 public OrderByClause OrderBy { get { return SqlQuery.OrderBy; } }
1805 public SqlQuery End() { return SqlQuery; }
1806
1807 protected internal SqlQuery SqlQuery { get; private set; }
1808
1809 internal void SetSqlQuery(SqlQuery sqlQuery)
1810 {
1811 SqlQuery = sqlQuery;
1812 }
1813 }
1814
1815 #endregion
1816
1817 #region SelectClause
1818
1819 public class SelectClause : ClauseBase, IQueryElement, ISqlExpressionWalkable
1820 {
1821 #region Init
1822
1823 internal SelectClause(SqlQuery sqlQuery) : base(sqlQuery)
1824 {
1825 }
1826
1827 internal SelectClause(
1828 SqlQuery sqlQuery,
1829 SelectClause clone,
1830 Dictionary<ICloneableElement,ICloneableElement> objectTree,
1831 Predicate<ICloneableElement> doClone)
1832 : base(sqlQuery)
1833 {
1834 _columns.AddRange(clone._columns.ConvertAll(c => (Column)c.Clone(objectTree, doClone)));
1835
1836 IsDistinct = clone.IsDistinct;
1837 TakeValue = clone.TakeValue == null ? null : (ISqlExpression)clone.TakeValue.Clone(objectTree, doClone);
1838 SkipValue = clone.SkipValue == null ? null : (ISqlExpression)clone.SkipValue.Clone(objectTree, doClone);
1839 }
1840
1841 internal SelectClause(bool isDistinct, ISqlExpression takeValue, ISqlExpression skipValue, IEnumerable<Column> columns)
1842 : base(null)
1843 {
1844 IsDistinct = isDistinct;
1845 TakeValue = takeValue;
1846 SkipValue = skipValue;
1847
1848 _columns.AddRange(columns);
1849 }
1850
1851 #endregion
1852
1853 #region Columns
1854
1855 public SelectClause Field(SqlField field)
1856 {
1857 AddOrGetColumn(new Column(SqlQuery, field));
1858 return this;
1859 }
1860
1861 public SelectClause Field(SqlField field, string alias)
1862 {
1863 AddOrGetColumn(new Column(SqlQuery, field, alias));
1864 return this;
1865 }
1866
1867 public SelectClause SubQuery(SqlQuery subQuery)
1868 {
1869 if (subQuery.ParentSql != null && subQuery.ParentSql != SqlQuery)
1870 throw new ArgumentException("SqlQuery already used as subquery");
1871
1872 subQuery.ParentSql = SqlQuery;
1873
1874 AddOrGetColumn(new Column(SqlQuery, subQuery));
1875 return this;
1876 }
1877
1878 public SelectClause SubQuery(SqlQuery sqlQuery, string alias)
1879 {
1880 if (sqlQuery.ParentSql != null && sqlQuery.ParentSql != SqlQuery)
1881 throw new ArgumentException("SqlQuery already used as subquery");
1882
1883 sqlQuery.ParentSql = SqlQuery;
1884
1885 AddOrGetColumn(new Column(SqlQuery, sqlQuery, alias));
1886 return this;
1887 }
1888
1889 public SelectClause Expr(ISqlExpression expr)
1890 {
1891 AddOrGetColumn(new Column(SqlQuery, expr));
1892 return this;
1893 }
1894
1895 public SelectClause Expr(ISqlExpression expr, string alias)
1896 {
1897 AddOrGetColumn(new Column(SqlQuery, expr, alias));
1898 return this;
1899 }
1900
1901 public SelectClause Expr(string expr, params ISqlExpression[] values)
1902 {
1903 AddOrGetColumn(new Column(SqlQuery, new SqlExpression(null, expr, values)));
1904 return this;
1905 }
1906
1907 public SelectClause Expr(Type systemType, string expr, params ISqlExpression[] values)
1908 {
1909 AddOrGetColumn(new Column(SqlQuery, new SqlExpression(systemType, expr, values)));
1910 return this;
1911 }
1912
1913 public SelectClause Expr(string expr, int priority, params ISqlExpression[] values)
1914 {
1915 AddOrGetColumn(new Column(SqlQuery, new SqlExpression(null, expr, priority, values)));
1916 return this;
1917 }
1918
1919 public SelectClause Expr(Type systemType, string expr, int priority, params ISqlExpression[] values)
1920 {
1921 AddOrGetColumn(new Column(SqlQuery, new SqlExpression(systemType, expr, priority, values)));
1922 return this;
1923 }
1924
1925 public SelectClause Expr(string alias, string expr, int priority, params ISqlExpression[] values)
1926 {
1927 AddOrGetColumn(new Column(SqlQuery, new SqlExpression(null, expr, priority, values)));
1928 return this;
1929 }
1930
1931 public SelectClause Expr(Type systemType, string alias, string expr, int priority, params ISqlExpression[] values)
1932 {
1933 AddOrGetColumn(new Column(SqlQuery, new SqlExpression(systemType, expr, priority, values)));
1934 return this;
1935 }
1936
1937 public SelectClause Expr<T>(ISqlExpression expr1, string operation, ISqlExpression expr2)
1938 {
1939 AddOrGetColumn(new Column(SqlQuery, new SqlBinaryExpression(typeof(T), expr1, operation, expr2)));
1940 return this;
1941 }
1942
1943 public SelectClause Expr<T>(ISqlExpression expr1, string operation, ISqlExpression expr2, int priority)
1944 {
1945 AddOrGetColumn(new Column(SqlQuery, new SqlBinaryExpression(typeof(T), expr1, operation, expr2, priority)));
1946 return this;
1947 }
1948
1949 public SelectClause Expr<T>(string alias, ISqlExpression expr1, string operation, ISqlExpression expr2, int priority)
1950 {
1951 AddOrGetColumn(new Column(SqlQuery, new SqlBinaryExpression(typeof(T), expr1, operation, expr2, priority), alias));
1952 return this;
1953 }
1954
1955 public int Add(ISqlExpression expr)
1956 {
1957 if (expr is Column && ((Column)expr).Parent == SqlQuery)
1958 throw new InvalidOperationException();
1959
1960 return Columns.IndexOf(AddOrGetColumn(new Column(SqlQuery, expr)));
1961 }
1962
1963 public int Add(ISqlExpression expr, string alias)
1964 {
1965 return Columns.IndexOf(AddOrGetColumn(new Column(SqlQuery, expr, alias)));
1966 }
1967
1968 Column AddOrGetColumn(Column col)
1969 {
1970 foreach (var c in Columns)
1971 if (c.Equals(col))
1972 return col;
1973
1974 #if DEBUG
1975
1976 switch (col.Expression.ElementType)
1977 {
1978 case QueryElementType.SqlField :
1979 {
1980 var table = ((SqlField)col.Expression).Table;
1981
1982 //if (SqlQuery.From.GetFromTables().Any(_ => _ == table))
1983 // throw new InvalidOperationException("Wrong field usage.");
1984
1985 break;
1986 }
1987
1988 case QueryElementType.Column :
1989 {
1990 var query = ((Column)col.Expression).Parent;
1991
1992 //if (!SqlQuery.From.GetFromQueries().Any(_ => _ == query))
1993 // throw new InvalidOperationException("Wrong column usage.");
1994
1995 break;
1996 }
1997
1998 case QueryElementType.SqlQuery :
1999 {
2000 if (col.Expression == SqlQuery)
2001 throw new InvalidOperationException("Wrong query usage.");
2002 break;
2003 }
2004 }
2005
2006 #endif
2007
2008 Columns.Add(col);
2009
2010 return col;
2011 }
2012
2013 readonly List<Column> _columns = new List<Column>();
2014 public List<Column> Columns
2015 {
2016 get { return _columns; }
2017 }
2018
2019 #endregion
2020
2021 #region HasModifier
2022
2023 public bool HasModifier
2024 {
2025 get { return IsDistinct || SkipValue != null || TakeValue != null; }
2026 }
2027
2028 #endregion
2029
2030 #region Distinct
2031
2032 public SelectClause Distinct
2033 {
2034 get { IsDistinct = true; return this; }
2035 }
2036
2037 public bool IsDistinct { get; set; }
2038
2039 #endregion
2040
2041 #region Take
2042
2043 public SelectClause Take(int value)
2044 {
2045 TakeValue = new SqlValue(value);
2046 return this;
2047 }
2048
2049 public SelectClause Take(ISqlExpression value)
2050 {
2051 TakeValue = value;
2052 return this;
2053 }
2054
2055 public ISqlExpression TakeValue { get; set; }
2056
2057 #endregion
2058
2059 #region Skip
2060
2061 public SelectClause Skip(int value)
2062 {
2063 SkipValue = new SqlValue(value);
2064 return this;
2065 }
2066
2067 public SelectClause Skip(ISqlExpression value)
2068 {
2069 SkipValue = value;
2070 return this;
2071 }
2072
2073 public ISqlExpression SkipValue { get; set; }
2074
2075 #endregion
2076
2077 #region Overrides
2078
2079 #if OVERRIDETOSTRING
2080
2081 public override string ToString()
2082 {
2083 return ((IQueryElement)this).ToString(new StringBuilder(), new Dictionary<IQueryElement,IQueryElement>()).ToString();
2084 }
2085
2086 #endif
2087
2088 #endregion
2089
2090 #region ISqlExpressionWalkable Members
2091
2092 [Obsolete]
2093 ISqlExpression ISqlExpressionWalkable.Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> func)
2094 {
2095 for (var i = 0; i < Columns.Count; i++)
2096 {
2097 var col = Columns[i];
2098 #pragma warning disable 0618
2099 var expr = col.Walk(skipColumns, func);
2100 #pragma warning restore 0618
2101
2102 if (expr is Column)
2103 Columns[i] = (Column)expr;
2104 else
2105 Columns[i] = new Column(col.Parent, expr, col.Alias);
2106 }
2107
2108 if (TakeValue != null) TakeValue = TakeValue.Walk(skipColumns, func);
2109 if (SkipValue != null) SkipValue = SkipValue.Walk(skipColumns, func);
2110
2111 return null;
2112 }
2113
2114 #endregion
2115
2116 #region IQueryElement Members
2117
2118 public QueryElementType ElementType { get { return QueryElementType.SelectClause; } }
2119
2120 StringBuilder IQueryElement.ToString(StringBuilder sb, Dictionary<IQueryElement,IQueryElement> dic)
2121 {
2122 if (dic.ContainsKey(this))
2123 return sb.Append("...");
2124
2125 dic.Add(this, this);
2126
2127 sb.Append("SELECT ");
2128
2129 if (IsDistinct) sb.Append("DISTINCT ");
2130
2131 if (SkipValue != null)
2132 {
2133 sb.Append("SKIP ");
2134 SkipValue.ToString(sb, dic);
2135 sb.Append(" ");
2136 }
2137
2138 if (TakeValue != null)
2139 {
2140 sb.Append("TAKE ");
2141 TakeValue.ToString(sb, dic);
2142 sb.Append(" ");
2143 }
2144
2145 sb.AppendLine();
2146
2147 if (Columns.Count == 0)
2148 sb.Append("\t*, \n");
2149 else
2150 foreach (var c in Columns)
2151 {
2152 sb.Append("\t");
2153 ((IQueryElement)c).ToString(sb, dic);
2154 sb
2155 .Append(" as ")
2156 .Append(c.Alias ?? "c" + (Columns.IndexOf(c) + 1))
2157 .Append(", \n");
2158 }
2159
2160 sb.Length -= 3;
2161
2162 dic.Remove(this);
2163
2164 return sb;
2165 }
2166
2167 #endregion
2168 }
2169
2170 private SelectClause _select;
2171 public SelectClause Select
2172 {
2173 get { return _select; }
2174 }
2175
2176 #endregion
2177
2178 #region InsertClause
2179
2180 public class SetExpression : IQueryElement, ISqlExpressionWalkable, ICloneableElement
2181 {
2182 public SetExpression(ISqlExpression column, ISqlExpression expression)
2183 {
2184 Column = column;
2185 Expression = expression;
2186
2187 if (expression is SqlParameter)
2188 {
2189 var p = (SqlParameter)expression;
2190
2191 //if (type.IsEnum)
2192 // p.SetEnumConverter(type, mappingSchema);
2193
2194 if (column is SqlField)
2195 {
2196 var field = (SqlField)column;
2197
2198 if (field.MemberMapper != null)
2199 {
2200 if (field.MemberMapper.MapMemberInfo.IsDbTypeSet)
2201 p.DbType = field.MemberMapper.MapMemberInfo.DbType;
2202
2203 if (field.MemberMapper.MapMemberInfo.IsDbSizeSet)
2204 p.DbSize = field.MemberMapper.MapMemberInfo.DbSize;
2205 }
2206 }
2207 }
2208 }
2209
2210 public ISqlExpression Column { get; set; }
2211 public ISqlExpression Expression { get; set; }
2212
2213 #region Overrides
2214
2215 #if OVERRIDETOSTRING
2216
2217 public override string ToString()
2218 {
2219 return ((IQueryElement)this).ToString(new StringBuilder(), new Dictionary<IQueryElement,IQueryElement>()).ToString();
2220 }
2221
2222 #endif
2223
2224 #endregion
2225
2226 #region ICloneableElement Members
2227
2228 public ICloneableElement Clone(Dictionary<ICloneableElement, ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
2229 {
2230 if (!doClone(this))
2231 return this;
2232
2233 ICloneableElement clone;
2234
2235 if (!objectTree.TryGetValue(this, out clone))
2236 {
2237 objectTree.Add(this, clone = new SetExpression(
2238 (ISqlExpression)Column. Clone(objectTree, doClone),
2239 (ISqlExpression)Expression.Clone(objectTree, doClone)));
2240 }
2241
2242 return clone;
2243 }
2244
2245 #endregion
2246
2247 #region ISqlExpressionWalkable Members
2248
2249 [Obsolete]
2250 ISqlExpression ISqlExpressionWalkable.Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> func)
2251 {
2252 Column = Column. Walk(skipColumns, func);
2253 Expression = Expression.Walk(skipColumns, func);
2254 return null;
2255 }
2256
2257 #endregion
2258
2259 #region IQueryElement Members
2260
2261 public QueryElementType ElementType { get { return QueryElementType.SetExpression; } }
2262
2263 StringBuilder IQueryElement.ToString(StringBuilder sb, Dictionary<IQueryElement,IQueryElement> dic)
2264 {
2265 Column.ToString(sb, dic);
2266 sb.Append(" = ");
2267 Expression.ToString(sb, dic);
2268
2269 return sb;
2270 }
2271
2272 #endregion
2273 }
2274
2275 public class InsertClause : IQueryElement, ISqlExpressionWalkable, ICloneableElement
2276 {
2277 public InsertClause()
2278 {
2279 Items = new List<SetExpression>();
2280 }
2281
2282 public List<SetExpression> Items { get; private set; }
2283 public SqlTable Into { get; set; }
2284 public bool WithIdentity { get; set; }
2285
2286 #region Overrides
2287
2288 #if OVERRIDETOSTRING
2289
2290 public override string ToString()
2291 {
2292 return ((IQueryElement)this).ToString(new StringBuilder(), new Dictionary<IQueryElement,IQueryElement>()).ToString();
2293 }
2294
2295 #endif
2296
2297 #endregion
2298
2299 #region ICloneableElement Members
2300
2301 public ICloneableElement Clone(Dictionary<ICloneableElement, ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
2302 {
2303 if (!doClone(this))
2304 return this;
2305
2306 var clone = new InsertClause { WithIdentity = WithIdentity };
2307
2308 if (Into != null)
2309 clone.Into = (SqlTable)Into.Clone(objectTree, doClone);
2310
2311 foreach (var item in Items)
2312 clone.Items.Add((SetExpression)item.Clone(objectTree, doClone));
2313
2314 objectTree.Add(this, clone);
2315
2316 return clone;
2317 }
2318
2319 #endregion
2320
2321 #region ISqlExpressionWalkable Members
2322
2323 [Obsolete]
2324 ISqlExpression ISqlExpressionWalkable.Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> func)
2325 {
2326 if (Into != null)
2327 ((ISqlExpressionWalkable)Into).Walk(skipColumns, func);
2328
2329 foreach (var t in Items)
2330 ((ISqlExpressionWalkable)t).Walk(skipColumns, func);
2331
2332 return null;
2333 }
2334
2335 #endregion
2336
2337 #region IQueryElement Members
2338
2339 public QueryElementType ElementType { get { return QueryElementType.InsertClause; } }
2340
2341 StringBuilder IQueryElement.ToString(StringBuilder sb, Dictionary<IQueryElement,IQueryElement> dic)
2342 {
2343 sb.Append("VALUES ");
2344
2345 if (Into != null)
2346 ((IQueryElement)Into).ToString(sb, dic);
2347
2348 sb.AppendLine();
2349
2350 foreach (var e in Items)
2351 {
2352 sb.Append("\t");
2353 ((IQueryElement)e).ToString(sb, dic);
2354 sb.AppendLine();
2355 }
2356
2357 return sb;
2358 }
2359
2360 #endregion
2361 }
2362
2363 private InsertClause _insert;
2364 public InsertClause Insert
2365 {
2366 get { return _insert ?? (_insert = new InsertClause()); }
2367 }
2368
2369 public void ClearInsert()
2370 {
2371 _insert = null;
2372 }
2373
2374 #endregion
2375
2376 #region UpdateClause
2377
2378 public class UpdateClause : IQueryElement, ISqlExpressionWalkable, ICloneableElement
2379 {
2380 public UpdateClause()
2381 {
2382 Items = new List<SetExpression>();
2383 Keys = new List<SetExpression>();
2384 }
2385
2386 public List<SetExpression> Items { get; private set; }
2387 public List<SetExpression> Keys { get; private set; }
2388 public SqlTable Table { get; set; }
2389
2390 #region Overrides
2391
2392 #if OVERRIDETOSTRING
2393
2394 public override string ToString()
2395 {
2396 return ((IQueryElement)this).ToString(new StringBuilder(), new Dictionary<IQueryElement,IQueryElement>()).ToString();
2397 }
2398
2399 #endif
2400
2401 #endregion
2402
2403 #region ICloneableElement Members
2404
2405 public ICloneableElement Clone(Dictionary<ICloneableElement, ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
2406 {
2407 if (!doClone(this))
2408 return this;
2409
2410 var clone = new UpdateClause();
2411
2412 if (Table != null)
2413 clone.Table = (SqlTable)Table.Clone(objectTree, doClone);
2414
2415 foreach (var item in Items)
2416 clone.Items.Add((SetExpression)item.Clone(objectTree, doClone));
2417
2418 foreach (var item in Keys)
2419 clone.Keys.Add((SetExpression)item.Clone(objectTree, doClone));
2420
2421 objectTree.Add(this, clone);
2422
2423 return clone;
2424 }
2425
2426 #endregion
2427
2428 #region ISqlExpressionWalkable Members
2429
2430 [Obsolete]
2431 ISqlExpression ISqlExpressionWalkable.Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> func)
2432 {
2433 if (Table != null)
2434 ((ISqlExpressionWalkable)Table).Walk(skipColumns, func);
2435
2436 foreach (var t in Items)
2437 ((ISqlExpressionWalkable)t).Walk(skipColumns, func);
2438
2439 foreach (var t in Keys)
2440 ((ISqlExpressionWalkable)t).Walk(skipColumns, func);
2441
2442 return null;
2443 }
2444
2445 #endregion
2446
2447 #region IQueryElement Members
2448
2449 public QueryElementType ElementType { get { return QueryElementType.UpdateClause; } }
2450
2451 StringBuilder IQueryElement.ToString(StringBuilder sb, Dictionary<IQueryElement,IQueryElement> dic)
2452 {
2453 sb.Append("SET ");
2454
2455 if (Table != null)
2456 ((IQueryElement)Table).ToString(sb, dic);
2457
2458 sb.AppendLine();
2459
2460 foreach (var e in Items)
2461 {
2462 sb.Append("\t");
2463 ((IQueryElement)e).ToString(sb, dic);
2464 sb.AppendLine();
2465 }
2466
2467 return sb;
2468 }
2469
2470 #endregion
2471 }
2472
2473 private UpdateClause _update;
2474 public UpdateClause Update
2475 {
2476 get { return _update ?? (_update = new UpdateClause()); }
2477 }
2478
2479 public void ClearUpdate()
2480 {
2481 _update = null;
2482 }
2483
2484 #endregion
2485
2486 #region DeleteClause
2487
2488 public class DeleteClause : IQueryElement, ISqlExpressionWalkable, ICloneableElement
2489 {
2490 public SqlTable Table { get; set; }
2491
2492 #region Overrides
2493
2494 #if OVERRIDETOSTRING
2495
2496 public override string ToString()
2497 {
2498 return ((IQueryElement)this).ToString(new StringBuilder(), new Dictionary<IQueryElement,IQueryElement>()).ToString();
2499 }
2500
2501 #endif
2502
2503 #endregion
2504
2505 #region ICloneableElement Members
2506
2507 public ICloneableElement Clone(Dictionary<ICloneableElement, ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
2508 {
2509 if (!doClone(this))
2510 return this;
2511
2512 var clone = new DeleteClause();
2513
2514 if (Table != null)
2515 clone.Table = (SqlTable)Table.Clone(objectTree, doClone);
2516
2517 objectTree.Add(this, clone);
2518
2519 return clone;
2520 }
2521
2522 #endregion
2523
2524 #region ISqlExpressionWalkable Members
2525
2526 [Obsolete]
2527 ISqlExpression ISqlExpressionWalkable.Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> func)
2528 {
2529 if (Table != null)
2530 ((ISqlExpressionWalkable)Table).Walk(skipColumns, func);
2531
2532 return null;
2533 }
2534
2535 #endregion
2536
2537 #region IQueryElement Members
2538
2539 public QueryElementType ElementType { get { return QueryElementType.DeleteClause; } }
2540
2541 StringBuilder IQueryElement.ToString(StringBuilder sb, Dictionary<IQueryElement,IQueryElement> dic)
2542 {
2543 sb.Append("DELETE FROM ");
2544
2545 if (Table != null)
2546 ((IQueryElement)Table).ToString(sb, dic);
2547
2548 sb.AppendLine();
2549
2550 return sb;
2551 }
2552
2553 #endregion
2554 }
2555
2556 private DeleteClause _delete;
2557 public DeleteClause Delete
2558 {
2559 get { return _delete ?? (_delete = new DeleteClause()); }
2560 }
2561
2562 public void ClearDelete()
2563 {
2564 _delete = null;
2565 }
2566
2567 #endregion
2568
2569 #region FromClause
2570
2571 public class FromClause : ClauseBase, IQueryElement, ISqlExpressionWalkable
2572 {
2573 #region Join
2574
2575 public class Join : ConditionBase<Join,Join.Next>
2576 {
2577 public class Next
2578 {
2579 internal Next(Join parent)
2580 {
2581 _parent = parent;
2582 }
2583
2584 readonly Join _parent;
2585
2586 public Join Or { get { return _parent.SetOr(true); } }
2587 public Join And { get { return _parent.SetOr(false); } }
2588
2589 public static implicit operator Join(Next next)
2590 {
2591 return next._parent;
2592 }
2593 }
2594
2595 protected override SearchCondition Search
2596 {
2597 get { return JoinedTable.Condition; }
2598 }
2599
2600 protected override Next GetNext()
2601 {
2602 return new Next(this);
2603 }
2604
2605 internal Join(JoinType joinType, ISqlTableSource table, string alias, bool isWeak, ICollection<Join> joins)
2606 {
2607 JoinedTable = new JoinedTable(joinType, table, alias, isWeak);
2608
2609 if (joins != null && joins.Count > 0)
2610 foreach (var join in joins)
2611 JoinedTable.Table.Joins.Add(join.JoinedTable);
2612 }
2613
2614 public JoinedTable JoinedTable { get; private set; }
2615 }
2616
2617 #endregion
2618
2619 internal FromClause(SqlQuery sqlQuery) : base(sqlQuery)
2620 {
2621 }
2622
2623 internal FromClause(
2624 SqlQuery sqlQuery,
2625 FromClause clone,
2626 Dictionary<ICloneableElement,ICloneableElement> objectTree,
2627 Predicate<ICloneableElement> doClone)
2628 : base(sqlQuery)
2629 {
2630 _tables.AddRange(clone._tables.ConvertAll(ts => (TableSource)ts.Clone(objectTree, doClone)));
2631 }
2632
2633 internal FromClause(IEnumerable<TableSource> tables)
2634 : base(null)
2635 {
2636 _tables.AddRange(tables);
2637 }
2638
2639 public FromClause Table(ISqlTableSource table, params FJoin[] joins)
2640 {
2641 return Table(table, null, joins);
2642 }
2643
2644 public FromClause Table(ISqlTableSource table, string alias, params FJoin[] joins)
2645 {
2646 var ts = AddOrGetTable(table, alias);
2647
2648 if (joins != null && joins.Length > 0)
2649 foreach (var join in joins)
2650 ts.Joins.Add(join.JoinedTable);
2651
2652 return this;
2653 }
2654
2655 TableSource GetTable(ISqlTableSource table, string alias)
2656 {
2657 foreach (var ts in Tables)
2658 if (ts.Source == table)
2659 if (alias == null || ts.Alias == alias)
2660 return ts;
2661 else
2662 throw new ArgumentException("alias");
2663
2664 return null;
2665 }
2666
2667 TableSource AddOrGetTable(ISqlTableSource table, string alias)
2668 {
2669 var ts = GetTable(table, alias);
2670
2671 if (ts != null)
2672 return ts;
2673
2674 var t = new TableSource(table, alias);
2675
2676 Tables.Add(t);
2677
2678 return t;
2679 }
2680
2681 public TableSource this[ISqlTableSource table]
2682 {
2683 get { return this[table, null]; }
2684 }
2685
2686 public TableSource this[ISqlTableSource table, string alias]
2687 {
2688 get
2689 {
2690 foreach (var ts in Tables)
2691 {
2692 var t = CheckTableSource(ts, table, alias);
2693
2694 if (t != null)
2695 return t;
2696 }
2697
2698 return null;
2699 }
2700 }
2701
2702 public bool IsChild(ISqlTableSource table)
2703 {
2704 foreach (var ts in Tables)
2705 if (ts.Source == table || CheckChild(ts.Joins, table))
2706 return true;
2707 return false;
2708 }
2709
2710 static bool CheckChild(IEnumerable<JoinedTable> joins, ISqlTableSource table)
2711 {
2712 foreach (var j in joins)
2713 if (j.Table.Source == table || CheckChild(j.Table.Joins, table))
2714 return true;
2715 return false;
2716 }
2717
2718 readonly List<TableSource> _tables = new List<TableSource>();
2719 public List<TableSource> Tables
2720 {
2721 get { return _tables; }
2722 }
2723
2724 static IEnumerable<ISqlTableSource> GetJoinTables(TableSource source, QueryElementType elementType)
2725 {
2726 if (source.Source.ElementType == elementType)
2727 yield return source.Source;
2728
2729 foreach (var join in source.Joins)
2730 foreach (var table in GetJoinTables(join.Table, elementType))
2731 yield return table;
2732 }
2733
2734 internal IEnumerable<ISqlTableSource> GetFromTables()
2735 {
2736 return Tables.SelectMany(_ => GetJoinTables(_, QueryElementType.SqlTable));
2737 }
2738
2739 internal IEnumerable<ISqlTableSource> GetFromQueries()
2740 {
2741 return Tables.SelectMany(_ => GetJoinTables(_, QueryElementType.SqlQuery));
2742 }
2743
2744 static TableSource FindTableSource(TableSource source, SqlTable table)
2745 {
2746 if (source.Source == table)
2747 return source;
2748
2749 foreach (var join in source.Joins)
2750 {
2751 var ts = FindTableSource(join.Table, table);
2752 if (ts != null)
2753 return ts;
2754 }
2755
2756 return null;
2757 }
2758
2759 public ISqlTableSource FindTableSource(SqlTable table)
2760 {
2761 foreach (var source in Tables)
2762 {
2763 var ts = FindTableSource(source, table);
2764 if (ts != null)
2765 return ts;
2766 }
2767
2768 return null;
2769 }
2770
2771 #region Overrides
2772
2773 #if OVERRIDETOSTRING
2774
2775 public override string ToString()
2776 {
2777 return ((IQueryElement)this).ToString(new StringBuilder(), new Dictionary<IQueryElement,IQueryElement>()).ToString();
2778 }
2779
2780 #endif
2781
2782 #endregion
2783
2784 #region ISqlExpressionWalkable Members
2785
2786 [Obsolete]
2787 ISqlExpression ISqlExpressionWalkable.Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> func)
2788 {
2789 for (var i = 0; i < Tables.Count; i++)
2790 ((ISqlExpressionWalkable)Tables[i]).Walk(skipColumns, func);
2791
2792 return null;
2793 }
2794
2795 #endregion
2796
2797 #region IQueryElement Members
2798
2799 public QueryElementType ElementType { get { return QueryElementType.FromClause; } }
2800
2801 StringBuilder IQueryElement.ToString(StringBuilder sb, Dictionary<IQueryElement,IQueryElement> dic)
2802 {
2803 sb.Append(" \nFROM \n");
2804
2805 if (Tables.Count > 0)
2806 {
2807 foreach (IQueryElement ts in Tables)
2808 {
2809 sb.Append('\t');
2810 var len = sb.Length;
2811 ts.ToString(sb, dic).Replace("\n", "\n\t", len, sb.Length - len);
2812 sb.Append(", ");
2813 }
2814
2815 sb.Length -= 2;
2816 }
2817
2818 return sb;
2819 }
2820
2821 #endregion
2822 }
2823
2824 public static FJoin InnerJoin (ISqlTableSource table, params FJoin[] joins) { return new FJoin(JoinType.Inner, table, null, false, joins); }
2825 public static FJoin InnerJoin (ISqlTableSource table, string alias, params FJoin[] joins) { return new FJoin(JoinType.Inner, table, alias, false, joins); }
2826 public static FJoin LeftJoin (ISqlTableSource table, params FJoin[] joins) { return new FJoin(JoinType.Left, table, null, false, joins); }
2827 public static FJoin LeftJoin (ISqlTableSource table, string alias, params FJoin[] joins) { return new FJoin(JoinType.Left, table, alias, false, joins); }
2828 public static FJoin Join (ISqlTableSource table, params FJoin[] joins) { return new FJoin(JoinType.Auto, table, null, false, joins); }
2829 public static FJoin Join (ISqlTableSource table, string alias, params FJoin[] joins) { return new FJoin(JoinType.Auto, table, alias, false, joins); }
2830 public static FJoin CrossApply (ISqlTableSource table, params FJoin[] joins) { return new FJoin(JoinType.CrossApply, table, null, false, joins); }
2831 public static FJoin CrossApply (ISqlTableSource table, string alias, params FJoin[] joins) { return new FJoin(JoinType.CrossApply, table, alias, false, joins); }
2832 public static FJoin OuterApply (ISqlTableSource table, params FJoin[] joins) { return new FJoin(JoinType.OuterApply, table, null, false, joins); }
2833 public static FJoin OuterApply (ISqlTableSource table, string alias, params FJoin[] joins) { return new FJoin(JoinType.OuterApply, table, alias, false, joins); }
2834
2835 public static FJoin WeakInnerJoin(ISqlTableSource table, params FJoin[] joins) { return new FJoin(JoinType.Inner, table, null, true, joins); }
2836 public static FJoin WeakInnerJoin(ISqlTableSource table, string alias, params FJoin[] joins) { return new FJoin(JoinType.Inner, table, alias, true, joins); }
2837 public static FJoin WeakLeftJoin (ISqlTableSource table, params FJoin[] joins) { return new FJoin(JoinType.Left, table, null, true, joins); }
2838 public static FJoin WeakLeftJoin (ISqlTableSource table, string alias, params FJoin[] joins) { return new FJoin(JoinType.Left, table, alias, true, joins); }
2839 public static FJoin WeakJoin (ISqlTableSource table, params FJoin[] joins) { return new FJoin(JoinType.Auto, table, null, true, joins); }
2840 public static FJoin WeakJoin (ISqlTableSource table, string alias, params FJoin[] joins) { return new FJoin(JoinType.Auto, table, alias, true, joins); }
2841
2842 private FromClause _from;
2843 public FromClause From
2844 {
2845 get { return _from; }
2846 }
2847
2848 #endregion
2849
2850 #region WhereClause
2851
2852 public class WhereClause : ClauseBase<WhereClause,WhereClause.Next>, IQueryElement, ISqlExpressionWalkable
2853 {
2854 public class Next : ClauseBase
2855 {
2856 internal Next(WhereClause parent) : base(parent.SqlQuery)
2857 {
2858 _parent = parent;
2859 }
2860
2861 readonly WhereClause _parent;
2862
2863 public WhereClause Or { get { return _parent.SetOr(true); } }
2864 public WhereClause And { get { return _parent.SetOr(false); } }
2865 }
2866
2867 internal WhereClause(SqlQuery sqlQuery) : base(sqlQuery)
2868 {
2869 SearchCondition = new SearchCondition();
2870 }
2871
2872 internal WhereClause(
2873 SqlQuery sqlQuery,
2874 WhereClause clone,
2875 Dictionary<ICloneableElement,ICloneableElement> objectTree,
2876 Predicate<ICloneableElement> doClone)
2877 : base(sqlQuery)
2878 {
2879 SearchCondition = (SearchCondition)clone.SearchCondition.Clone(objectTree, doClone);
2880 }
2881
2882 internal WhereClause(SearchCondition searchCondition) : base(null)
2883 {
2884 SearchCondition = searchCondition;
2885 }
2886
2887 public SearchCondition SearchCondition { get; private set; }
2888
2889 public bool IsEmpty
2890 {
2891 get { return SearchCondition.Conditions.Count == 0; }
2892 }
2893
2894 protected override SearchCondition Search
2895 {
2896 get { return SearchCondition; }
2897 }
2898
2899 protected override Next GetNext()
2900 {
2901 return new Next(this);
2902 }
2903
2904 #if OVERRIDETOSTRING
2905
2906 public override string ToString()
2907 {
2908 return ((IQueryElement)this).ToString(new StringBuilder(), new Dictionary<IQueryElement,IQueryElement>()).ToString();
2909 }
2910
2911 #endif
2912
2913 #region ISqlExpressionWalkable Members
2914
2915 [Obsolete]
2916 ISqlExpression ISqlExpressionWalkable.Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> action)
2917 {
2918 SearchCondition = (SearchCondition)((ISqlExpressionWalkable)SearchCondition).Walk(skipColumns, action);
2919 return null;
2920 }
2921
2922 #endregion
2923
2924 #region IQueryElement Members
2925
2926 public QueryElementType ElementType
2927 {
2928 get { return QueryElementType.WhereClause; }
2929 }
2930
2931 StringBuilder IQueryElement.ToString(StringBuilder sb, Dictionary<IQueryElement,IQueryElement> dic)
2932 {
2933 if (Search.Conditions.Count == 0)
2934 return sb;
2935
2936 sb.Append("\nWHERE\n\t");
2937 return ((IQueryElement)Search).ToString(sb, dic);
2938 }
2939
2940 #endregion
2941 }
2942
2943 private WhereClause _where;
2944 public WhereClause Where
2945 {
2946 get { return _where; }
2947 }
2948
2949 #endregion
2950
2951 #region GroupByClause
2952
2953 public class GroupByClause : ClauseBase, IQueryElement, ISqlExpressionWalkable
2954 {
2955 internal GroupByClause(SqlQuery sqlQuery) : base(sqlQuery)
2956 {
2957 }
2958
2959 internal GroupByClause(
2960 SqlQuery sqlQuery,
2961 GroupByClause clone,
2962 Dictionary<ICloneableElement,ICloneableElement> objectTree,
2963 Predicate<ICloneableElement> doClone)
2964 : base(sqlQuery)
2965 {
2966 _items.AddRange(clone._items.ConvertAll(e => (ISqlExpression)e.Clone(objectTree, doClone)));
2967 }
2968
2969 internal GroupByClause(IEnumerable<ISqlExpression> items) : base(null)
2970 {
2971 _items.AddRange(items);
2972 }
2973
2974 public GroupByClause Expr(ISqlExpression expr)
2975 {
2976 Add(expr);
2977 return this;
2978 }
2979
2980 public GroupByClause Field(SqlField field)
2981 {
2982 return Expr(field);
2983 }
2984
2985 void Add(ISqlExpression expr)
2986 {
2987 foreach (var e in Items)
2988 if (e.Equals(expr))
2989 return;
2990
2991 Items.Add(expr);
2992 }
2993
2994 readonly List<ISqlExpression> _items = new List<ISqlExpression>();
2995 public List<ISqlExpression> Items
2996 {
2997 get { return _items; }
2998 }
2999
3000 public bool IsEmpty
3001 {
3002 get { return Items.Count == 0; }
3003 }
3004
3005 #if OVERRIDETOSTRING
3006
3007 public override string ToString()
3008 {
3009 return ((IQueryElement)this).ToString(new StringBuilder(), new Dictionary<IQueryElement,IQueryElement>()).ToString();
3010 }
3011
3012 #endif
3013
3014 #region ISqlExpressionWalkable Members
3015
3016 [Obsolete]
3017 ISqlExpression ISqlExpressionWalkable.Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> func)
3018 {
3019 for (var i = 0; i < Items.Count; i++)
3020 Items[i] = Items[i].Walk(skipColumns, func);
3021
3022 return null;
3023 }
3024
3025 #endregion
3026
3027 #region IQueryElement Members
3028
3029 public QueryElementType ElementType { get { return QueryElementType.GroupByClause; } }
3030
3031 StringBuilder IQueryElement.ToString(StringBuilder sb, Dictionary<IQueryElement,IQueryElement> dic)
3032 {
3033 if (Items.Count == 0)
3034 return sb;
3035
3036 sb.Append(" \nGROUP BY \n");
3037
3038 foreach (var item in Items)
3039 {
3040 sb.Append('\t');
3041 item.ToString(sb, dic);
3042 sb.Append(",");
3043 }
3044
3045 sb.Length--;
3046
3047 return sb;
3048 }
3049
3050 #endregion
3051 }
3052
3053 private GroupByClause _groupBy;
3054 public GroupByClause GroupBy
3055 {
3056 get { return _groupBy; }
3057 }
3058
3059 #endregion
3060
3061 #region HavingClause
3062
3063 private WhereClause _having;
3064 public WhereClause Having
3065 {
3066 get { return _having; }
3067 }
3068
3069 #endregion
3070
3071 #region OrderByClause
3072
3073 public class OrderByClause : ClauseBase, IQueryElement, ISqlExpressionWalkable
3074 {
3075 internal OrderByClause(SqlQuery sqlQuery) : base(sqlQuery)
3076 {
3077 }
3078
3079 internal OrderByClause(
3080 SqlQuery sqlQuery,
3081 OrderByClause clone,
3082 Dictionary<ICloneableElement,ICloneableElement> objectTree,
3083 Predicate<ICloneableElement> doClone)
3084 : base(sqlQuery)
3085 {
3086 _items.AddRange(clone._items.ConvertAll(item => (OrderByItem)item.Clone(objectTree, doClone)));
3087 }
3088
3089 internal OrderByClause(IEnumerable<OrderByItem> items) : base(null)
3090 {
3091 _items.AddRange(items);
3092 }
3093
3094 public OrderByClause Expr(ISqlExpression expr, bool isDescending)
3095 {
3096 Add(expr, isDescending);
3097 return this;
3098 }
3099
3100 public OrderByClause Expr (ISqlExpression expr) { return Expr(expr, false); }
3101 public OrderByClause ExprAsc (ISqlExpression expr) { return Expr(expr, false); }
3102 public OrderByClause ExprDesc (ISqlExpression expr) { return Expr(expr, true); }
3103 public OrderByClause Field (SqlField field, bool isDescending) { return Expr(field, isDescending); }
3104 public OrderByClause Field (SqlField field) { return Expr(field, false); }
3105 public OrderByClause FieldAsc (SqlField field) { return Expr(field, false); }
3106 public OrderByClause FieldDesc(SqlField field) { return Expr(field, true); }
3107
3108 void Add(ISqlExpression expr, bool isDescending)
3109 {
3110 foreach (var item in Items)
3111 if (item.Expression.Equals(expr, (x, y) =>
3112 {
3113 var col = x as Column;
3114 return col == null || !col.Parent.HasUnion || x == y;
3115 }))
3116 return;
3117
3118 Items.Add(new OrderByItem(expr, isDescending));
3119 }
3120
3121 readonly List<OrderByItem> _items = new List<OrderByItem>();
3122 public List<OrderByItem> Items
3123 {
3124 get { return _items; }
3125 }
3126
3127 public bool IsEmpty
3128 {
3129 get { return Items.Count == 0; }
3130 }
3131
3132 #if OVERRIDETOSTRING
3133
3134 public override string ToString()
3135 {
3136 return ((IQueryElement)this).ToString(new StringBuilder(), new Dictionary<IQueryElement,IQueryElement>()).ToString();
3137 }
3138
3139 #endif
3140
3141 #region ISqlExpressionWalkable Members
3142
3143 [Obsolete]
3144 ISqlExpression ISqlExpressionWalkable.Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> func)
3145 {
3146 #pragma warning disable 0618
3147 foreach (var t in Items)
3148 t.Walk(skipColumns, func);
3149 #pragma warning restore 0618
3150 return null;
3151 }
3152
3153 #endregion
3154
3155 #region IQueryElement Members
3156
3157 public QueryElementType ElementType { get { return QueryElementType.OrderByClause; } }
3158
3159 StringBuilder IQueryElement.ToString(StringBuilder sb, Dictionary<IQueryElement,IQueryElement> dic)
3160 {
3161 if (Items.Count == 0)
3162 return sb;
3163
3164 sb.Append(" \nORDER BY \n");
3165
3166 foreach (IQueryElement item in Items)
3167 {
3168 sb.Append('\t');
3169 item.ToString(sb, dic);
3170 sb.Append(", ");
3171 }
3172
3173 sb.Length -= 2;
3174
3175 return sb;
3176 }
3177
3178 #endregion
3179 }
3180
3181 private OrderByClause _orderBy;
3182 public OrderByClause OrderBy
3183 {
3184 get { return _orderBy; }
3185 }
3186
3187 #endregion
3188
3189 #region Union
3190
3191 public class Union : IQueryElement
3192 {
3193 public Union()
3194 {
3195 }
3196
3197 public Union(SqlQuery sqlQuery, bool isAll)
3198 {
3199 SqlQuery = sqlQuery;
3200 IsAll = isAll;
3201 }
3202
3203 public SqlQuery SqlQuery { get; private set; }
3204 public bool IsAll { get; private set; }
3205
3206 public QueryElementType ElementType
3207 {
3208 get { return QueryElementType.Union; }
3209 }
3210
3211 #if OVERRIDETOSTRING
3212
3213 public override string ToString()
3214 {
3215 return ((IQueryElement)this).ToString(new StringBuilder(), new Dictionary<IQueryElement,IQueryElement>()).ToString();
3216 }
3217
3218 #endif
3219
3220 StringBuilder IQueryElement.ToString(StringBuilder sb, Dictionary<IQueryElement,IQueryElement> dic)
3221 {
3222 sb.Append(" \nUNION").Append(IsAll ? " ALL" : "").Append(" \n");
3223 return ((IQueryElement)SqlQuery).ToString(sb, dic);
3224 }
3225 }
3226
3227 private List<Union> _unions;
3228 public List<Union> Unions
3229 {
3230 get { return _unions ?? (_unions = new List<Union>()); }
3231 }
3232
3233 public bool HasUnion { get { return _unions != null && _unions.Count > 0; } }
3234
3235 public void AddUnion(SqlQuery union, bool isAll)
3236 {
3237 Unions.Add(new Union(union, isAll));
3238 }
3239
3240 #endregion
3241
3242 #region FinalizeAndValidate
3243
3244 public void FinalizeAndValidate(bool isApplySupported, bool optimizeColumns)
3245 {
3246 #if DEBUG
3247 var sqlText = SqlText;
3248
3249 var dic = new Dictionary<SqlQuery,SqlQuery>();
3250
3251 new QueryVisitor().VisitAll(this, e =>
3252 {
3253 var sql = e as SqlQuery;
3254
3255 if (sql != null)
3256 {
3257 if (dic.ContainsKey(sql))
3258 throw new InvalidOperationException("SqlQuery circle reference detected.");
3259
3260 dic.Add(sql, sql);
3261 }
3262 });
3263 #endif
3264
3265 OptimizeUnions();
3266 FinalizeAndValidateInternal(isApplySupported, optimizeColumns, true, new List<ISqlTableSource>());
3267 ResolveFields();
3268 SetAliases();
3269
3270 #if DEBUG
3271 sqlText = SqlText;
3272 #endif
3273 }
3274
3275 class QueryData
3276 {
3277 public SqlQuery Query;
3278 public List<ISqlExpression> Fields = new List<ISqlExpression>();
3279 public List<QueryData> Queries = new List<QueryData>();
3280 }
3281
3282 void ResolveFields()
3283 {
3284 var root = GetQueryData();
3285
3286 ResolveFields(root);
3287 }
3288
3289 QueryData GetQueryData()
3290 {
3291 var data = new QueryData { Query = this };
3292
3293 new QueryVisitor().VisitParentFirst(this, e =>
3294 {
3295 switch (e.ElementType)
3296 {
3297 case QueryElementType.SqlField :
3298 {
3299 var field = (SqlField)e;
3300
3301 if (field.Name.Length != 1 || field.Name[0] != '*')
3302 data.Fields.Add(field);
3303
3304 break;
3305 }
3306
3307 case QueryElementType.SqlQuery :
3308 {
3309 if (e != this)
3310 {
3311 data.Queries.Add(((SqlQuery)e).GetQueryData());
3312 return false;
3313 }
3314
3315 break;
3316 }
3317
3318 case QueryElementType.Column :
3319 return ((Column)e).Parent == this;
3320
3321 case QueryElementType.SqlTable :
3322 return false;
3323 }
3324
3325 return true;
3326 });
3327
3328 return data;
3329 }
3330
3331 static TableSource FindField(SqlField field, TableSource table)
3332 {
3333 if (field.Table == table.Source)
3334 return table;
3335
3336 foreach (var @join in table.Joins)
3337 {
3338 var t = FindField(field, @join.Table);
3339
3340 if (t != null)
3341 return @join.Table;
3342 }
3343
3344 return null;
3345 }
3346
3347 static ISqlExpression GetColumn(QueryData data, SqlField field)
3348 {
3349 foreach (var query in data.Queries)
3350 {
3351 var q = query.Query;
3352
3353 foreach (var table in q.From.Tables)
3354 {
3355 var t = FindField(field, table);
3356
3357 if (t != null)
3358 {
3359 var n = q.Select.Columns.Count;
3360 var idx = q.Select.Add(field);
3361
3362 if (n != q.Select.Columns.Count)
3363 if (!q.GroupBy.IsEmpty || q.Select.Columns.Exists(c => IsAggregationFunction(c.Expression)))
3364 q.GroupBy.Items.Add(field);
3365
3366 return q.Select.Columns[idx];
3367 }
3368 }
3369 }
3370
3371 return null;
3372 }
3373
3374 static void ResolveFields(QueryData data)
3375 {
3376 if (data.Queries.Count == 0)
3377 return;
3378
3379 var dic = new Dictionary<ISqlExpression,ISqlExpression>();
3380
3381 foreach (SqlField field in data.Fields)
3382 {
3383 if (dic.ContainsKey(field))
3384 continue;
3385
3386 var found = false;
3387
3388 foreach (var table in data.Query.From.Tables)
3389 {
3390 found = FindField(field, table) != null;
3391
3392 if (found)
3393 break;
3394 }
3395
3396 if (!found)
3397 {
3398 var expr = GetColumn(data, field);
3399
3400 if (expr != null)
3401 dic.Add(field, expr);
3402 }
3403 }
3404
3405 if (dic.Count > 0)
3406 new QueryVisitor().VisitParentFirst(data.Query, e =>
3407 {
3408 ISqlExpression ex;
3409
3410 switch (e.ElementType)
3411 {
3412 case QueryElementType.SqlQuery :
3413 return e == data.Query;
3414
3415 case QueryElementType.SqlFunction :
3416 {
3417 var parms = ((SqlFunction)e).Parameters;
3418
3419 for (var i = 0; i < parms.Length; i++)
3420 if (dic.TryGetValue(parms[i], out ex))
3421 parms[i] = ex;
3422
3423 break;
3424 }
3425
3426 case QueryElementType.SqlExpression :
3427 {
3428 var parms = ((SqlExpression)e).Parameters;
3429
3430 for (var i = 0; i < parms.Length; i++)
3431 if (dic.TryGetValue(parms[i], out ex))
3432 parms[i] = ex;
3433
3434 break;
3435 }
3436
3437 case QueryElementType.SqlBinaryExpression :
3438 {
3439 var expr = (SqlBinaryExpression)e;
3440 if (dic.TryGetValue(expr.Expr1, out ex)) expr.Expr1 = ex;
3441 if (dic.TryGetValue(expr.Expr2, out ex)) expr.Expr2 = ex;
3442 break;
3443 }
3444
3445 case QueryElementType.ExprPredicate :
3446 case QueryElementType.NotExprPredicate :
3447 case QueryElementType.IsNullPredicate :
3448 case QueryElementType.InSubQueryPredicate :
3449 {
3450 var expr = (Predicate.Expr)e;
3451 if (dic.TryGetValue(expr.Expr1, out ex)) expr.Expr1 = ex;
3452 break;
3453 }
3454
3455 case QueryElementType.ExprExprPredicate :
3456 {
3457 var expr = (Predicate.ExprExpr)e;
3458 if (dic.TryGetValue(expr.Expr1, out ex)) expr.Expr1 = ex;
3459 if (dic.TryGetValue(expr.Expr2, out ex)) expr.Expr2 = ex;
3460 break;
3461 }
3462
3463 case QueryElementType.LikePredicate :
3464 {
3465 var expr = (Predicate.Like)e;
3466 if (dic.TryGetValue(expr.Expr1, out ex)) expr.Expr1 = ex;
3467 if (dic.TryGetValue(expr.Expr2, out ex)) expr.Expr2 = ex;
3468 if (dic.TryGetValue(expr.Escape, out ex)) expr.Escape = ex;
3469 break;
3470 }
3471
3472 case QueryElementType.BetweenPredicate :
3473 {
3474 var expr = (Predicate.Between)e;
3475 if (dic.TryGetValue(expr.Expr1, out ex)) expr.Expr1 = ex;
3476 if (dic.TryGetValue(expr.Expr2, out ex)) expr.Expr2 = ex;
3477 if (dic.TryGetValue(expr.Expr3, out ex)) expr.Expr3 = ex;
3478 break;
3479 }
3480
3481 case QueryElementType.InListPredicate :
3482 {
3483 var expr = (Predicate.InList)e;
3484
3485 if (dic.TryGetValue(expr.Expr1, out ex)) expr.Expr1 = ex;
3486
3487 for (var i = 0; i < expr.Values.Count; i++)
3488 if (dic.TryGetValue(expr.Values[i], out ex))
3489 expr.Values[i] = ex;
3490
3491 break;
3492 }
3493
3494 case QueryElementType.Column :
3495 {
3496 var expr = (Column)e;
3497
3498 if (expr.Parent != data.Query)
3499 return false;
3500
3501 if (dic.TryGetValue(expr.Expression, out ex)) expr.Expression = ex;
3502
3503 break;
3504 }
3505
3506 case QueryElementType.SetExpression :
3507 {
3508 var expr = (SetExpression)e;
3509 if (dic.TryGetValue(expr.Expression, out ex)) expr.Expression = ex;
3510 break;
3511 }
3512
3513 case QueryElementType.GroupByClause :
3514 {
3515 var expr = (GroupByClause)e;
3516
3517 for (var i = 0; i < expr.Items.Count; i++)
3518 if (dic.TryGetValue(expr.Items[i], out ex))
3519 expr.Items[i] = ex;
3520
3521 break;
3522 }
3523
3524 case QueryElementType.OrderByItem :
3525 {
3526 var expr = (OrderByItem)e;
3527 if (dic.TryGetValue(expr.Expression, out ex)) expr.Expression = ex;
3528 break;
3529 }
3530 }
3531
3532 return true;
3533 });
3534
3535 foreach (var query in data.Queries)
3536 if (query.Queries.Count > 0)
3537 ResolveFields(query);
3538 }
3539
3540 void OptimizeUnions()
3541 {
3542 var exprs = new Dictionary<ISqlExpression,ISqlExpression>();
3543
3544 new QueryVisitor().Visit(this, e =>
3545 {
3546 var sql = e as SqlQuery;
3547
3548 if (sql == null || sql.From.Tables.Count != 1 || !sql.IsSimple || sql._insert != null || sql._update != null || sql._delete != null)
3549 return;
3550
3551 var table = sql.From.Tables[0];
3552
3553 if (table.Joins.Count != 0 || !(table.Source is SqlQuery))
3554 return;
3555
3556 var union = (SqlQuery)table.Source;
3557
3558 if (!union.HasUnion)
3559 return;
3560
3561 for (var i = 0; i < sql.Select.Columns.Count; i++)
3562 {
3563 var scol = sql. Select.Columns[i];
3564 var ucol = union.Select.Columns[i];
3565
3566 if (scol.Expression != ucol)
3567 return;
3568 }
3569
3570 exprs.Add(union, sql);
3571
3572 for (var i = 0; i < sql.Select.Columns.Count; i++)
3573 {
3574 var scol = sql. Select.Columns[i];
3575 var ucol = union.Select.Columns[i];
3576
3577 scol.Expression = ucol.Expression;
3578 scol._alias = ucol._alias;
3579
3580 exprs.Add(ucol, scol);
3581 }
3582
3583 for (var i = sql.Select.Columns.Count; i < union.Select.Columns.Count; i++)
3584 sql.Select.Expr(union.Select.Columns[i].Expression);
3585
3586 sql.From.Tables.Clear();
3587 sql.From.Tables.AddRange(union.From.Tables);
3588
3589 sql.Where. SearchCondition.Conditions.AddRange(union.Where. SearchCondition.Conditions);
3590 sql.Having. SearchCondition.Conditions.AddRange(union.Having.SearchCondition.Conditions);
3591 sql.GroupBy.Items. AddRange(union.GroupBy.Items);
3592 sql.OrderBy.Items. AddRange(union.OrderBy.Items);
3593 sql.Unions.InsertRange(0, union.Unions);
3594 });
3595
3596 ((ISqlExpressionWalkable)this).Walk(false, expr =>
3597 {
3598 ISqlExpression e;
3599
3600 if (exprs.TryGetValue(expr, out e))
3601 return e;
3602
3603 return expr;
3604 });
3605 }
3606
3607 void FinalizeAndValidateInternal(bool isApplySupported, bool optimizeColumns, bool optimizeSearchCondition, List<ISqlTableSource> tables)
3608 {
3609 OptimizeSearchCondition(Where. SearchCondition);
3610 OptimizeSearchCondition(Having.SearchCondition);
3611
3612 if (optimizeSearchCondition)
3613 {
3614 ForEachTable(table =>
3615 {
3616 foreach (var join in table.Joins)
3617 OptimizeSearchCondition(join.Condition);
3618 }, new HashSet<SqlQuery>());
3619 }
3620
3621 new QueryVisitor().Visit(this, e =>
3622 {
3623 var sql = e as SqlQuery;
3624
3625 if (sql != null && sql != this)
3626 {
3627 sql.ParentSql = this;
3628 sql.FinalizeAndValidateInternal(isApplySupported, optimizeColumns, false, tables);
3629
3630 if (sql.IsParameterDependent)
3631 IsParameterDependent = true;
3632 }
3633 });
3634
3635 ResolveWeakJoins(tables);
3636 OptimizeColumns();
3637 OptimizeApplies (isApplySupported, optimizeColumns);
3638 OptimizeSubQueries(isApplySupported, optimizeColumns);
3639 OptimizeApplies (isApplySupported, optimizeColumns);
3640
3641 new QueryVisitor().Visit(this, e =>
3642 {
3643 var sql = e as SqlQuery;
3644
3645 if (sql != null && sql != this)
3646 sql.RemoveOrderBy();
3647 });
3648 }
3649
3650 internal static void OptimizeSearchCondition(SearchCondition searchCondition)
3651 {
3652 // This 'if' could be replaced by one simple match:
3653 //
3654 // match (searchCondition.Conditions)
3655 // {
3656 // | [SearchCondition(true, _) sc] =>
3657 // searchCondition.Conditions = sc.Conditions;
3658 // OptimizeSearchCondition(searchCodition)
3659 //
3660 // | [SearchCondition(false, [SearchCondition(true, [ExprExpr]) sc])] => ...
3661 //
3662 // | [Expr(true, SqlValue(true))]
3663 // | [Expr(false, SqlValue(false))]
3664 // searchCondition.Conditions = []
3665 // }
3666 //
3667 // One day I am going to rewrite all this crap in Nemerle.
3668 //
3669 if (searchCondition.Conditions.Count == 1)
3670 {
3671 var cond = searchCondition.Conditions[0];
3672
3673 if (cond.Predicate is SearchCondition)
3674 {
3675 var sc = (SearchCondition)cond.Predicate;
3676
3677 if (!cond.IsNot)
3678 {
3679 searchCondition.Conditions.Clear();
3680 searchCondition.Conditions.AddRange(sc.Conditions);
3681
3682 OptimizeSearchCondition(searchCondition);
3683 return;
3684 }
3685
3686 if (sc.Conditions.Count == 1)
3687 {
3688 var c1 = sc.Conditions[0];
3689
3690 if (!c1.IsNot && c1.Predicate is Predicate.ExprExpr)
3691 {
3692 var ee = (Predicate.ExprExpr)c1.Predicate;
3693 Predicate.Operator op;
3694
3695 switch (ee.Operator)
3696 {
3697 case Predicate.Operator.Equal : op = Predicate.Operator.NotEqual; break;
3698 case Predicate.Operator.NotEqual : op = Predicate.Operator.Equal; break;
3699 case Predicate.Operator.Greater : op = Predicate.Operator.LessOrEqual; break;
3700 case Predicate.Operator.NotLess :
3701 case Predicate.Operator.GreaterOrEqual : op = Predicate.Operator.Less; break;
3702 case Predicate.Operator.Less : op = Predicate.Operator.GreaterOrEqual; break;
3703 case Predicate.Operator.NotGreater :
3704 case Predicate.Operator.LessOrEqual : op = Predicate.Operator.Greater; break;
3705 default: throw new InvalidOperationException();
3706 }
3707
3708 c1.Predicate = new Predicate.ExprExpr(ee.Expr1, op, ee.Expr2);
3709
3710 searchCondition.Conditions.Clear();
3711 searchCondition.Conditions.AddRange(sc.Conditions);
3712
3713 OptimizeSearchCondition(searchCondition);
3714 return;
3715 }
3716 }
3717 }
3718
3719 if (cond.Predicate.ElementType == QueryElementType.ExprPredicate)
3720 {
3721 var expr = (Predicate.Expr)cond.Predicate;
3722
3723 if (expr.Expr1 is SqlValue)
3724 {
3725 var value = (SqlValue)expr.Expr1;
3726
3727 if (value.Value is bool)
3728 if (cond.IsNot ? !(bool)value.Value : (bool)value.Value)
3729 searchCondition.Conditions.Clear();
3730 }
3731 }
3732 }
3733
3734 for (var i = 0; i < searchCondition.Conditions.Count; i++)
3735 {
3736 var cond = searchCondition.Conditions[i];
3737
3738 if (cond.Predicate is Predicate.Expr)
3739 {
3740 var expr = (Predicate.Expr)cond.Predicate;
3741
3742 if (expr.Expr1 is SqlValue)
3743 {
3744 var value = (SqlValue)expr.Expr1;
3745
3746 if (value.Value is bool)
3747 {
3748 if (cond.IsNot ? !(bool)value.Value : (bool)value.Value)
3749 {
3750 if (i > 0)
3751 {
3752 if (searchCondition.Conditions[i-1].IsOr)
3753 {
3754 searchCondition.Conditions.RemoveRange(0, i);
3755 OptimizeSearchCondition(searchCondition);
3756
3757 break;
3758 }
3759 }
3760 }
3761 }
3762 }
3763 }
3764 else if (cond.Predicate is SearchCondition)
3765 {
3766 var sc = (SearchCondition)cond.Predicate;
3767 OptimizeSearchCondition(sc);
3768 }
3769 }
3770 }
3771
3772 void ForEachTable(Action<TableSource> action, HashSet<SqlQuery> visitedQueries)
3773 {
3774 if (!visitedQueries.Add(this))
3775 return;
3776
3777 foreach (var table in From.Tables)
3778 table.ForEach(action, visitedQueries);
3779
3780 new QueryVisitor().Visit(this, e =>
3781 {
3782 if (e is SqlQuery && e != this)
3783 ((SqlQuery)e).ForEachTable(action, visitedQueries);
3784 });
3785 }
3786
3787 void RemoveOrderBy()
3788 {
3789 if (OrderBy.Items.Count > 0 && Select.SkipValue == null && Select.TakeValue == null)
3790 OrderBy.Items.Clear();
3791 }
3792
3793 internal void ResolveWeakJoins(List<ISqlTableSource> tables)
3794 {
3795 Func<TableSource,bool> findTable = null; findTable = table =>
3796 {
3797 if (tables.Contains(table.Source))
3798 return true;
3799
3800 foreach (var join in table.Joins)
3801 {
3802 if (findTable(join.Table))
3803 {
3804 join.IsWeak = false;
3805 return true;
3806 }
3807 }
3808
3809 if (table.Source is SqlQuery)
3810 foreach (var t in ((SqlQuery)table.Source).From.Tables)
3811 if (findTable(t))
3812 return true;
3813
3814 return false;
3815 };
3816
3817 var areTablesCollected = false;
3818
3819 ForEachTable(table =>
3820 {
3821 for (var i = 0; i < table.Joins.Count; i++)
3822 {
3823 var join = table.Joins[i];
3824
3825 if (join.IsWeak)
3826 {
3827 if (!areTablesCollected)
3828 {
3829 areTablesCollected = true;
3830
3831 Action<IQueryElement> tableCollector = expr =>
3832 {
3833 var field = expr as SqlField;
3834
3835 if (field != null && !tables.Contains(field.Table))
3836 tables.Add(field.Table);
3837 };
3838
3839 var visitor = new QueryVisitor();
3840
3841 visitor.VisitAll(Select, tableCollector);
3842 visitor.VisitAll(Where, tableCollector);
3843 visitor.VisitAll(GroupBy, tableCollector);
3844 visitor.VisitAll(Having, tableCollector);
3845 visitor.VisitAll(OrderBy, tableCollector);
3846
3847 if (_insert != null)
3848 visitor.VisitAll(Insert, tableCollector);
3849
3850 if (_update != null)
3851 visitor.VisitAll(Update, tableCollector);
3852
3853 if (_delete != null)
3854 visitor.VisitAll(Delete, tableCollector);
3855
3856 visitor.VisitAll(From, expr =>
3857 {
3858 var tbl = expr as SqlTable;
3859
3860 if (tbl != null && tbl.TableArguments != null)
3861 {
3862 var v = new QueryVisitor();
3863
3864 foreach (var arg in tbl.TableArguments)
3865 v.VisitAll(arg, tableCollector);
3866 }
3867 });
3868 }
3869
3870 if (findTable(join.Table))
3871 {
3872 join.IsWeak = false;
3873 }
3874 else
3875 {
3876 table.Joins.RemoveAt(i);
3877 i--;
3878 }
3879 }
3880 }
3881 }, new HashSet<SqlQuery>());
3882 }
3883
3884 TableSource OptimizeSubQuery(
3885 TableSource source,
3886 bool optimizeWhere,
3887 bool allColumns,
3888 bool isApplySupported,
3889 bool optimizeValues,
3890 bool optimizeColumns)
3891 {
3892 foreach (var jt in source.Joins)
3893 {
3894 var table = OptimizeSubQuery(
3895 jt.Table,
3896 jt.JoinType == JoinType.Inner || jt.JoinType == JoinType.CrossApply,
3897 false,
3898 isApplySupported,
3899 jt.JoinType == JoinType.Inner || jt.JoinType == JoinType.CrossApply,
3900 optimizeColumns);
3901
3902 if (table != jt.Table)
3903 {
3904 var sql = jt.Table.Source as SqlQuery;
3905
3906 if (sql != null && sql.OrderBy.Items.Count > 0)
3907 foreach (var item in sql.OrderBy.Items)
3908 OrderBy.Expr(item.Expression, item.IsDescending);
3909
3910 jt.Table = table;
3911 }
3912 }
3913
3914 return source.Source is SqlQuery ?
3915 RemoveSubQuery(source, optimizeWhere, allColumns && !isApplySupported, optimizeValues, optimizeColumns) :
3916 source;
3917 }
3918
3919 static bool CheckColumn(Column column, ISqlExpression expr, SqlQuery query, bool optimizeValues, bool optimizeColumns)
3920 {
3921 if (expr is SqlField || expr is Column)
3922 return false;
3923
3924 if (expr is SqlValue)
3925 return !optimizeValues && 1.Equals(((SqlValue)expr).Value);
3926
3927 if (expr is SqlBinaryExpression)
3928 {
3929 var e = (SqlBinaryExpression)expr;
3930
3931 if (e.Operation == "*" && e.Expr1 is SqlValue)
3932 {
3933 var value = (SqlValue)e.Expr1;
3934
3935 if (value.Value is int && (int)value.Value == -1)
3936 return CheckColumn(column, e.Expr2, query, optimizeValues, optimizeColumns);
3937 }
3938 }
3939
3940 var visitor = new QueryVisitor();
3941
3942 if (optimizeColumns &&
3943 visitor.Find(expr, e => e is SqlQuery || IsAggregationFunction(e)) == null)
3944 {
3945 var n = 0;
3946 var q = query.ParentSql ?? query;
3947
3948 visitor.VisitAll(q, e => { if (e == column) n++; });
3949
3950 return n > 2;
3951 }
3952
3953 return true;
3954 }
3955
3956 TableSource RemoveSubQuery(
3957 TableSource childSource,
3958 bool concatWhere,
3959 bool allColumns,
3960 bool optimizeValues,
3961 bool optimizeColumns)
3962 {
3963 var query = (SqlQuery)childSource.Source;
3964
3965 var isQueryOK = query.From.Tables.Count == 1;
3966
3967 isQueryOK = isQueryOK && (concatWhere || query.Where.IsEmpty && query.Having.IsEmpty);
3968 isQueryOK = isQueryOK && !query.HasUnion && query.GroupBy.IsEmpty && !query.Select.HasModifier;
3969
3970 if (!isQueryOK)
3971 return childSource;
3972
3973 var isColumnsOK =
3974 (allColumns && !query.Select.Columns.Exists(c => IsAggregationFunction(c.Expression))) ||
3975 !query.Select.Columns.Exists(c => CheckColumn(c, c.Expression, query, optimizeValues, optimizeColumns));
3976
3977 if (!isColumnsOK)
3978 return childSource;
3979
3980 var map = new Dictionary<ISqlExpression,ISqlExpression>(query.Select.Columns.Count);
3981
3982 foreach (var c in query.Select.Columns)
3983 map.Add(c, c.Expression);
3984
3985 var top = this;
3986
3987 while (top.ParentSql != null)
3988 top = top.ParentSql;
3989
3990 ((ISqlExpressionWalkable)top).Walk(false, expr =>
3991 {
3992 ISqlExpression fld;
3993 return map.TryGetValue(expr, out fld) ? fld : expr;
3994 });
3995
3996 new QueryVisitor().Visit(top, expr =>
3997 {
3998 if (expr.ElementType == QueryElementType.InListPredicate)
3999 {
4000 var p = (Predicate.InList)expr;
4001
4002 if (p.Expr1 == query)
4003 p.Expr1 = query.From.Tables[0];
4004 }
4005 });
4006
4007 query.From.Tables[0].Joins.AddRange(childSource.Joins);
4008
4009 if (query.From.Tables[0].Alias == null)
4010 query.From.Tables[0].Alias = childSource.Alias;
4011
4012 if (!query.Where. IsEmpty) ConcatSearchCondition(Where, query.Where);
4013 if (!query.Having.IsEmpty) ConcatSearchCondition(Having, query.Having);
4014
4015 ((ISqlExpressionWalkable)top).Walk(false, expr =>
4016 {
4017 if (expr is SqlQuery)
4018 {
4019 var sql = (SqlQuery)expr;
4020
4021 if (sql.ParentSql == query)
4022 sql.ParentSql = query.ParentSql ?? this;
4023 }
4024
4025 return expr;
4026 });
4027
4028 return query.From.Tables[0];
4029 }
4030
4031 static bool IsAggregationFunction(IQueryElement expr)
4032 {
4033 if (expr is SqlFunction)
4034 switch (((SqlFunction)expr).Name)
4035 {
4036 case "Count" :
4037 case "Average" :
4038 case "Min" :
4039 case "Max" :
4040 case "Sum" : return true;
4041 }
4042
4043 return false;
4044 }
4045
4046 void OptimizeApply(TableSource tableSource, JoinedTable joinTable, bool isApplySupported, bool optimizeColumns)
4047 {
4048 var joinSource = joinTable.Table;
4049
4050 foreach (var join in joinSource.Joins)
4051 if (join.JoinType == JoinType.CrossApply || join.JoinType == JoinType.OuterApply)
4052 OptimizeApply(joinSource, join, isApplySupported, optimizeColumns);
4053
4054 if (isApplySupported && !joinTable.CanConvertApply)
4055 return;
4056
4057 if (joinSource.Source.ElementType == QueryElementType.SqlQuery)
4058 {
4059 var sql = (SqlQuery)joinSource.Source;
4060 var isAgg = sql.Select.Columns.Exists(c => IsAggregationFunction(c.Expression));
4061
4062 if (isApplySupported && (isAgg || sql.Select.TakeValue != null || sql.Select.SkipValue != null))
4063 return;
4064
4065 var searchCondition = new List<Condition>(sql.Where.SearchCondition.Conditions);
4066
4067 sql.Where.SearchCondition.Conditions.Clear();
4068
4069 if (!ContainsTable(tableSource.Source, sql))
4070 {
4071 joinTable.JoinType = joinTable.JoinType == JoinType.CrossApply ? JoinType.Inner : JoinType.Left;
4072 joinTable.Condition.Conditions.AddRange(searchCondition);
4073 }
4074 else
4075 {
4076 sql.Where.SearchCondition.Conditions.AddRange(searchCondition);
4077
4078 var table = OptimizeSubQuery(
4079 joinTable.Table,
4080 joinTable.JoinType == JoinType.Inner || joinTable.JoinType == JoinType.CrossApply,
4081 joinTable.JoinType == JoinType.CrossApply,
4082 isApplySupported,
4083 joinTable.JoinType == JoinType.Inner || joinTable.JoinType == JoinType.CrossApply,
4084 optimizeColumns);
4085
4086 if (table != joinTable.Table)
4087 {
4088 var q = joinTable.Table.Source as SqlQuery;
4089
4090 if (q != null && q.OrderBy.Items.Count > 0)
4091 foreach (var item in q.OrderBy.Items)
4092 OrderBy.Expr(item.Expression, item.IsDescending);
4093
4094 joinTable.Table = table;
4095
4096 OptimizeApply(tableSource, joinTable, isApplySupported, optimizeColumns);
4097 }
4098 }
4099 }
4100 else
4101 {
4102 if (!ContainsTable(tableSource.Source, joinSource.Source))
4103 joinTable.JoinType = joinTable.JoinType == JoinType.CrossApply ? JoinType.Inner : JoinType.Left;
4104 }
4105 }
4106
4107 static bool ContainsTable(ISqlTableSource table, IQueryElement sql)
4108 {
4109 return null != new QueryVisitor().Find(sql, e =>
4110 e == table ||
4111 e.ElementType == QueryElementType.SqlField && table == ((SqlField)e).Table ||
4112 e.ElementType == QueryElementType.Column && table == ((Column) e).Parent);
4113 }
4114
4115 static void ConcatSearchCondition(WhereClause where1, WhereClause where2)
4116 {
4117 if (where1.IsEmpty)
4118 {
4119 where1.SearchCondition.Conditions.AddRange(where2.SearchCondition.Conditions);
4120 }
4121 else
4122 {
4123 if (where1.SearchCondition.Precedence < Sql.Precedence.LogicalConjunction)
4124 {
4125 var sc1 = new SearchCondition();
4126
4127 sc1.Conditions.AddRange(where1.SearchCondition.Conditions);
4128
4129 where1.SearchCondition.Conditions.Clear();
4130 where1.SearchCondition.Conditions.Add(new Condition(false, sc1));
4131 }
4132
4133 if (where2.SearchCondition.Precedence < Sql.Precedence.LogicalConjunction)
4134 {
4135 var sc2 = new SearchCondition();
4136
4137 sc2.Conditions.AddRange(where2.SearchCondition.Conditions);
4138
4139 where1.SearchCondition.Conditions.Add(new Condition(false, sc2));
4140 }
4141 else
4142 where1.SearchCondition.Conditions.AddRange(where2.SearchCondition.Conditions);
4143 }
4144 }
4145
4146 void OptimizeSubQueries(bool isApplySupported, bool optimizeColumns)
4147 {
4148 for (var i = 0; i < From.Tables.Count; i++)
4149 {
4150 var table = OptimizeSubQuery(From.Tables[i], true, false, isApplySupported, true, optimizeColumns);
4151
4152 if (table != From.Tables[i])
4153 {
4154 var sql = From.Tables[i].Source as SqlQuery;
4155
4156 if (!Select.Columns.All(c => IsAggregationFunction(c.Expression)))
4157 if (sql != null && sql.OrderBy.Items.Count > 0)
4158 foreach (var item in sql.OrderBy.Items)
4159 OrderBy.Expr(item.Expression, item.IsDescending);
4160
4161 From.Tables[i] = table;
4162 }
4163 }
4164 }
4165
4166 void OptimizeApplies(bool isApplySupported, bool optimizeColumns)
4167 {
4168 foreach (var table in From.Tables)
4169 foreach (var join in table.Joins)
4170 if (join.JoinType == JoinType.CrossApply || join.JoinType == JoinType.OuterApply)
4171 OptimizeApply(table, join, isApplySupported, optimizeColumns);
4172 }
4173
4174 void OptimizeColumns()
4175 {
4176 ((ISqlExpressionWalkable)Select).Walk(false, expr =>
4177 {
4178 var query = expr as SqlQuery;
4179
4180 if (query != null && query.From.Tables.Count == 0 && query.Select.Columns.Count == 1)
4181 {
4182 new QueryVisitor().Visit(query.Select.Columns[0].Expression, e =>
4183 {
4184 if (e.ElementType == QueryElementType.SqlQuery)
4185 {
4186 var q = (SqlQuery)e;
4187
4188 if (q.ParentSql == query)
4189 q.ParentSql = query.ParentSql;
4190 }
4191 });
4192
4193 return query.Select.Columns[0].Expression;
4194 }
4195
4196 return expr;
4197 });
4198 }
4199
4200 IDictionary<string,object> _aliases;
4201
4202 public void RemoveAlias(string alias)
4203 {
4204 if (_aliases != null)
4205 {
4206 alias = alias.ToUpper();
4207 if (_aliases.ContainsKey(alias))
4208 _aliases.Remove(alias);
4209 }
4210 }
4211
4212 public string GetAlias(string desiredAlias, string defaultAlias)
4213 {
4214 if (_aliases == null)
4215 _aliases = new Dictionary<string,object>();
4216
4217 var alias = desiredAlias;
4218
4219 if (string.IsNullOrEmpty(desiredAlias) || desiredAlias.Length > 30)
4220 {
4221 desiredAlias = defaultAlias;
4222 alias = defaultAlias + "1";
4223 }
4224
4225 for (var i = 1; ; i++)
4226 {
4227 var s = alias.ToUpper();
4228
4229 if (!_aliases.ContainsKey(s) && !_reservedWords.ContainsKey(s))
4230 {
4231 _aliases.Add(s, s);
4232 break;
4233 }
4234
4235 alias = desiredAlias + i;
4236 }
4237
4238 return alias;
4239 }
4240
4241 public string[] GetTempAliases(int n, string defaultAlias)
4242 {
4243 var aliases = new string[n];
4244
4245 for (var i = 0; i < aliases.Length; i++)
4246 aliases[i] = GetAlias(defaultAlias, defaultAlias);
4247
4248 foreach (var t in aliases)
4249 RemoveAlias(t);
4250
4251 return aliases;
4252 }
4253
4254 void SetAliases()
4255 {
4256 _aliases = null;
4257
4258 var objs = new Dictionary<object,object>();
4259
4260 Parameters.Clear();
4261
4262 new QueryVisitor().VisitAll(this, expr =>
4263 {
4264 switch (expr.ElementType)
4265 {
4266 case QueryElementType.SqlParameter:
4267 {
4268 var p = (SqlParameter)expr;
4269
4270 if (p.IsQueryParameter)
4271 {
4272 if (!objs.ContainsKey(expr))
4273 {
4274 objs.Add(expr, expr);
4275 p.Name = GetAlias(p.Name, "p");
4276 }
4277
4278 Parameters.Add(p);
4279 }
4280 else
4281 IsParameterDependent = true;
4282 }
4283
4284 break;
4285
4286 case QueryElementType.Column:
4287 {
4288 if (!objs.ContainsKey(expr))
4289 {
4290 objs.Add(expr, expr);
4291
4292 var c = (Column)expr;
4293
4294 if (c.Alias != "*")
4295 c.Alias = GetAlias(c.Alias, "c");
4296 }
4297 }
4298
4299 break;
4300
4301 case QueryElementType.TableSource:
4302 {
4303 var table = (TableSource)expr;
4304
4305 if (!objs.ContainsKey(table))
4306 {
4307 objs.Add(table, table);
4308 table.Alias = GetAlias(table.Alias, "t");
4309 }
4310 }
4311
4312 break;
4313
4314 case QueryElementType.SqlQuery:
4315 {
4316 var sql = (SqlQuery)expr;
4317
4318 if (sql.HasUnion)
4319 {
4320 for (var i = 0; i < sql.Select.Columns.Count; i++)
4321 {
4322 var col = sql.Select.Columns[i];
4323
4324 foreach (var t in sql.Unions)
4325 {
4326 var union = t.SqlQuery.Select;
4327
4328 objs.Remove(union.Columns[i].Alias);
4329
4330 union.Columns[i].Alias = col.Alias;
4331 }
4332 }
4333 }
4334 }
4335
4336 break;
4337 }
4338 });
4339 }
4340
4341 #endregion
4342
4343 #region ProcessParameters
4344
4345 public SqlQuery ProcessParameters()
4346 {
4347 if (IsParameterDependent)
4348 {
4349 var query = new QueryVisitor().Convert(this, e =>
4350 {
4351 switch (e.ElementType)
4352 {
4353 case QueryElementType.SqlParameter :
4354 {
4355 var p = (SqlParameter)e;
4356
4357 if (p.Value == null)
4358 return new SqlValue(null);
4359 }
4360
4361 break;
4362
4363 case QueryElementType.ExprExprPredicate :
4364 {
4365 var ee = (Predicate.ExprExpr)e;
4366
4367 if (ee.Operator == Predicate.Operator.Equal || ee.Operator == Predicate.Operator.NotEqual)
4368 {
4369 object value1;
4370 object value2;
4371
4372 if (ee.Expr1 is SqlValue)
4373 value1 = ((SqlValue)ee.Expr1).Value;
4374 else if (ee.Expr1 is SqlParameter)
4375 value1 = ((SqlParameter)ee.Expr1).Value;
4376 else
4377 break;
4378
4379 if (ee.Expr2 is SqlValue)
4380 value2 = ((SqlValue)ee.Expr2).Value;
4381 else if (ee.Expr2 is SqlParameter)
4382 value2 = ((SqlParameter)ee.Expr2).Value;
4383 else
4384 break;
4385
4386 var value = Equals(value1, value2);
4387
4388 if (ee.Operator == Predicate.Operator.NotEqual)
4389 value = !value;
4390
4391 return new Predicate.Expr(new SqlValue(value), Sql.Precedence.Comparison);
4392 }
4393 }
4394
4395 break;
4396
4397 case QueryElementType.InListPredicate :
4398 return ConvertInListPredicate((Predicate.InList)e);
4399 }
4400
4401 return null;
4402 });
4403
4404 if (query != this)
4405 {
4406 query.Parameters.Clear();
4407
4408 new QueryVisitor().VisitAll(query, expr =>
4409 {
4410 if (expr.ElementType == QueryElementType.SqlParameter)
4411 {
4412 var p = (SqlParameter)expr;
4413 if (p.IsQueryParameter)
4414 query.Parameters.Add(p);
4415 }
4416 });
4417 }
4418
4419 return query;
4420 }
4421
4422 return this;
4423 }
4424
4425 static Predicate ConvertInListPredicate(Predicate.InList p)
4426 {
4427 if (p.Values == null || p.Values.Count == 0)
4428 return new Predicate.Expr(new SqlValue(p.IsNot));
4429
4430 if (p.Values.Count == 1 && p.Values[0] is SqlParameter)
4431 {
4432 var pr = (SqlParameter)p.Values[0];
4433
4434 if (pr.Value == null)
4435 return new Predicate.Expr(new SqlValue(p.IsNot));
4436
4437 if (pr.Value is IEnumerable)
4438 {
4439 if (p.Expr1 is ISqlTableSource)
4440 {
4441 var items = (IEnumerable)pr.Value;
4442 var table = (ISqlTableSource)p.Expr1;
4443 var keys = table.GetKeys(true);
4444
4445 if (keys == null || keys.Count == 0)
4446 throw new SqlException("Cant create IN expression.");
4447
4448 if (keys.Count == 1)
4449 {
4450 var values = new List<ISqlExpression>();
4451 var field = GetUnderlayingField(keys[0]);
4452
4453 foreach (var item in items)
4454 {
4455 var value = field.MemberMapper.GetValue(item);
4456 values.Add(new SqlValue(value));
4457 }
4458
4459 if (values.Count == 0)
4460 return new Predicate.Expr(new SqlValue(p.IsNot));
4461
4462 return new Predicate.InList(keys[0], p.IsNot, values);
4463 }
4464
4465 {
4466 var sc = new SearchCondition();
4467
4468 foreach (var item in items)
4469 {
4470 var itemCond = new SearchCondition();
4471
4472 foreach (var key in keys)
4473 {
4474 var field = GetUnderlayingField(key);
4475 var value = field.MemberMapper.GetValue(item);
4476 var cond = value == null ?
4477 new Condition(false, new Predicate.IsNull (field, false)) :
4478 new Condition(false, new Predicate.ExprExpr(field, Predicate.Operator.Equal, new SqlValue(value)));
4479
4480 itemCond.Conditions.Add(cond);
4481 }
4482
4483 sc.Conditions.Add(new Condition(false, new Predicate.Expr(itemCond), true));
4484 }
4485
4486 if (sc.Conditions.Count == 0)
4487 return new Predicate.Expr(new SqlValue(p.IsNot));
4488
4489 if (p.IsNot)
4490 return new Predicate.NotExpr(sc, true, Sql.Precedence.LogicalNegation);
4491
4492 return new Predicate.Expr(sc, Sql.Precedence.LogicalDisjunction);
4493 }
4494 }
4495
4496 if (p.Expr1 is SqlExpression)
4497 {
4498 var expr = (SqlExpression)p.Expr1;
4499
4500 if (expr.Expr.Length > 1 && expr.Expr[0] == '\x1')
4501 {
4502 var type = TypeHelper.GetListItemType(pr.Value);
4503 var ta = TypeAccessor.GetAccessor(type);
4504 var items = (IEnumerable)pr.Value;
4505 var names = expr.Expr.Substring(1).Split(',');
4506
4507 if (expr.Parameters.Length == 1)
4508 {
4509 var values = new List<ISqlExpression>();
4510
4511 foreach (var item in items)
4512 {
4513 var value = ta[names[0]].GetValue(item);
4514 values.Add(new SqlValue(value));
4515 }
4516
4517 if (values.Count == 0)
4518 return new Predicate.Expr(new SqlValue(p.IsNot));
4519
4520 return new Predicate.InList(expr.Parameters[0], p.IsNot, values);
4521 }
4522
4523 {
4524 var sc = new SearchCondition();
4525
4526 foreach (var item in items)
4527 {
4528 var itemCond = new SearchCondition();
4529
4530 for (var i = 0; i < expr.Parameters.Length; i++)
4531 {
4532 var sql = expr.Parameters[i];
4533 var value = ta[names[i]].GetValue(item);
4534 var cond = value == null ?
4535 new Condition(false, new Predicate.IsNull (sql, false)) :
4536 new Condition(false, new Predicate.ExprExpr(sql, Predicate.Operator.Equal, new SqlValue(value)));
4537
4538 itemCond.Conditions.Add(cond);
4539 }
4540
4541 sc.Conditions.Add(new Condition(false, new Predicate.Expr(itemCond), true));
4542 }
4543
4544 if (sc.Conditions.Count == 0)
4545 return new Predicate.Expr(new SqlValue(p.IsNot));
4546
4547 if (p.IsNot)
4548 return new Predicate.NotExpr(sc, true, Sql.Precedence.LogicalNegation);
4549
4550 return new Predicate.Expr(sc, Sql.Precedence.LogicalDisjunction);
4551 }
4552 }
4553 }
4554
4555 /*
4556 var itemType = items.GetType().GetItemType();
4557
4558 if (itemType == typeof(DateTime) || itemType == typeof(DateTimeOffset) ||
4559 itemType == typeof(DateTime?) || itemType == typeof(DateTimeOffset?))
4560 {
4561 var list = new List<SqlParameter>();
4562
4563 foreach (var item in items)
4564 list.Add(new SqlParameter(itemType, "p", item, (MappingSchema)null));
4565
4566 return new Predicate.InList(p.Expr1, p.IsNot, list);
4567 }
4568 */
4569 }
4570 }
4571
4572 return null;
4573 }
4574
4575 static SqlField GetUnderlayingField(ISqlExpression expr)
4576 {
4577 switch (expr.ElementType)
4578 {
4579 case QueryElementType.SqlField: return (SqlField)expr;
4580 case QueryElementType.Column : return GetUnderlayingField(((Column)expr).Expression);
4581 }
4582
4583 throw new InvalidOperationException();
4584 }
4585
4586 #endregion
4587
4588 #region Clone
4589
4590 SqlQuery(SqlQuery clone, Dictionary<ICloneableElement,ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
4591 {
4592 objectTree.Add(clone, this);
4593 objectTree.Add(clone.All, All);
4594
4595 SourceID = Interlocked.Increment(ref SourceIDCounter);
4596
4597 _queryType = clone._queryType;
4598
4599 if (IsInsert) _insert = (InsertClause)clone._insert.Clone(objectTree, doClone);
4600 if (IsUpdate) _update = (UpdateClause)clone._update.Clone(objectTree, doClone);
4601 if (IsDelete) _delete = (DeleteClause)clone._delete.Clone(objectTree, doClone);
4602
4603 _select = new SelectClause (this, clone._select, objectTree, doClone);
4604 _from = new FromClause (this, clone._from, objectTree, doClone);
4605 _where = new WhereClause (this, clone._where, objectTree, doClone);
4606 _groupBy = new GroupByClause(this, clone._groupBy, objectTree, doClone);
4607 _having = new WhereClause (this, clone._having, objectTree, doClone);
4608 _orderBy = new OrderByClause(this, clone._orderBy, objectTree, doClone);
4609
4610 _parameters.AddRange(clone._parameters.ConvertAll(p => (SqlParameter)p.Clone(objectTree, doClone)));
4611 IsParameterDependent = clone.IsParameterDependent;
4612
4613 new QueryVisitor().Visit(this, expr =>
4614 {
4615 var sb = expr as SqlQuery;
4616
4617 if (sb != null && sb.ParentSql == clone)
4618 sb.ParentSql = this;
4619 });
4620 }
4621
4622 public SqlQuery Clone()
4623 {
4624 return (SqlQuery)Clone(new Dictionary<ICloneableElement,ICloneableElement>(), _ => true);
4625 }
4626
4627 public SqlQuery Clone(Predicate<ICloneableElement> doClone)
4628 {
4629 return (SqlQuery)Clone(new Dictionary<ICloneableElement,ICloneableElement>(), doClone);
4630 }
4631
4632 #endregion
4633
4634 #region Helpers
4635
4636 public TableSource GetTableSource(ISqlTableSource table)
4637 {
4638 var ts = From[table];
4639 return ts == null && ParentSql != null? ParentSql.GetTableSource(table) : ts;
4640 }
4641
4642 static TableSource CheckTableSource(TableSource ts, ISqlTableSource table, string alias)
4643 {
4644 if (ts.Source == table && (alias == null || ts.Alias == alias))
4645 return ts;
4646
4647 var jt = ts[table, alias];
4648
4649 if (jt != null)
4650 return jt;
4651
4652 if (ts.Source is SqlQuery)
4653 {
4654 var s = ((SqlQuery)ts.Source).From[table, alias];
4655
4656 if (s != null)
4657 return s;
4658 }
4659
4660 return null;
4661 }
4662
4663 #endregion
4664
4665 #region Overrides
4666
4667 public string SqlText { get { return ToString(); } }
4668
4669 #if OVERRIDETOSTRING
4670
4671 public override string ToString()
4672 {
4673 return ((IQueryElement)this).ToString(new StringBuilder(), new Dictionary<IQueryElement,IQueryElement>()).ToString();
4674 }
4675
4676 #endif
4677
4678 #endregion
4679
4680 #region ISqlExpression Members
4681
4682 public bool CanBeNull()
4683 {
4684 return true;
4685 }
4686
4687 public bool Equals(ISqlExpression other, Func<ISqlExpression, ISqlExpression, bool> comparer)
4688 {
4689 return this == other;
4690 }
4691
4692 public int Precedence
4693 {
4694 get { return Sql.Precedence.Unknown; }
4695 }
4696
4697 public Type SystemType
4698 {
4699 get
4700 {
4701 if (Select.Columns.Count == 1)
4702 return Select.Columns[0].SystemType;
4703
4704 if (From.Tables.Count == 1 && From.Tables[0].Joins.Count == 0)
4705 return From.Tables[0].SystemType;
4706
4707 return null;
4708 }
4709 }
4710
4711 #endregion
4712
4713 #region ICloneableElement Members
4714
4715 public ICloneableElement Clone(Dictionary<ICloneableElement, ICloneableElement> objectTree, Predicate<ICloneableElement> doClone)
4716 {
4717 if (!doClone(this))
4718 return this;
4719
4720 ICloneableElement clone;
4721
4722 if (!objectTree.TryGetValue(this, out clone))
4723 clone = new SqlQuery(this, objectTree, doClone);
4724
4725 return clone;
4726 }
4727
4728 #endregion
4729
4730 #region ISqlExpressionWalkable Members
4731
4732 [Obsolete]
4733 ISqlExpression ISqlExpressionWalkable.Walk(bool skipColumns, Func<ISqlExpression,ISqlExpression> func)
4734 {
4735 if (_insert != null) ((ISqlExpressionWalkable)_insert).Walk(skipColumns, func);
4736 if (_update != null) ((ISqlExpressionWalkable)_update).Walk(skipColumns, func);
4737 if (_delete != null) ((ISqlExpressionWalkable)_delete).Walk(skipColumns, func);
4738
4739 ((ISqlExpressionWalkable)Select) .Walk(skipColumns, func);
4740 ((ISqlExpressionWalkable)From) .Walk(skipColumns, func);
4741 ((ISqlExpressionWalkable)Where) .Walk(skipColumns, func);
4742 ((ISqlExpressionWalkable)GroupBy).Walk(skipColumns, func);
4743 ((ISqlExpressionWalkable)Having) .Walk(skipColumns, func);
4744 ((ISqlExpressionWalkable)OrderBy).Walk(skipColumns, func);
4745
4746 if (HasUnion)
4747 foreach (var union in Unions)
4748 ((ISqlExpressionWalkable)union.SqlQuery).Walk(skipColumns, func);
4749
4750 return func(this);
4751 }
4752
4753 #endregion
4754
4755 #region IEquatable<ISqlExpression> Members
4756
4757 bool IEquatable<ISqlExpression>.Equals(ISqlExpression other)
4758 {
4759 return this == other;
4760 }
4761
4762 #endregion
4763
4764 #region ISqlTableSource Members
4765
4766 public static int SourceIDCounter;
4767
4768 public int SourceID { get; private set; }
4769 public SqlTableType SqlTableType { get { return SqlTableType.Table; } }
4770
4771 private SqlField _all;
4772 public SqlField All
4773 {
4774 get
4775 {
4776 if (_all == null)
4777 {
4778 _all = new SqlField(null, "*", "*", true, -1, null, null);
4779 ((IChild<ISqlTableSource>)_all).Parent = this;
4780 }
4781
4782 return _all;
4783 }
4784
4785 internal set
4786 {
4787 _all = value;
4788
4789 if (_all != null)
4790 ((IChild<ISqlTableSource>)_all).Parent = this;
4791 }
4792 }
4793
4794 List<ISqlExpression> _keys;
4795
4796 public IList<ISqlExpression> GetKeys(bool allIfEmpty)
4797 {
4798 if (_keys == null && From.Tables.Count == 1 && From.Tables[0].Joins.Count == 0)
4799 {
4800 _keys = new List<ISqlExpression>();
4801
4802 var q =
4803 from key in ((ISqlTableSource)From.Tables[0]).GetKeys(allIfEmpty)
4804 from col in Select.Columns
4805 where col.Expression == key
4806 select col as ISqlExpression;
4807
4808 _keys = q.ToList();
4809 }
4810
4811 return _keys;
4812 }
4813
4814 #endregion
4815
4816 #region IQueryElement Members
4817
4818 public QueryElementType ElementType { get { return QueryElementType.SqlQuery; } }
4819
4820 StringBuilder IQueryElement.ToString(StringBuilder sb, Dictionary<IQueryElement,IQueryElement> dic)
4821 {
4822 if (dic.ContainsKey(this))
4823 return sb.Append("...");
4824
4825 dic.Add(this, this);
4826
4827 sb
4828 .Append("(")
4829 .Append(SourceID)
4830 .Append(") ");
4831
4832 ((IQueryElement)Select). ToString(sb, dic);
4833 ((IQueryElement)From). ToString(sb, dic);
4834 ((IQueryElement)Where). ToString(sb, dic);
4835 ((IQueryElement)GroupBy).ToString(sb, dic);
4836 ((IQueryElement)Having). ToString(sb, dic);
4837 ((IQueryElement)OrderBy).ToString(sb, dic);
4838
4839 if (HasUnion)
4840 foreach (IQueryElement u in Unions)
4841 u.ToString(sb, dic);
4842
4843 dic.Remove(this);
4844
4845 return sb;
4846 }
4847
4848 #endregion
4849 }
4850 }