File: SqlLiftWhereClauses.cs

package info (click to toggle)
mono 6.12.0.199%2Bdfsg-6
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 1,296,836 kB
  • sloc: cs: 11,181,803; xml: 2,850,076; ansic: 699,709; cpp: 123,344; perl: 59,361; javascript: 30,841; asm: 21,853; makefile: 20,405; sh: 15,009; python: 4,839; pascal: 925; sql: 859; sed: 16; php: 1
file content (116 lines) | stat: -rw-r--r-- 4,709 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.Linq.Mapping;
using System.Data.Linq.Provider;

namespace System.Data.Linq.SqlClient {

    /// <summary>
    /// Hoist WHERE clauses as close to the root as possible.
    /// </summary>
    class SqlLiftWhereClauses {
        internal static SqlNode Lift(SqlNode node, TypeSystemProvider typeProvider, MetaModel model) {
            return new Lifter(typeProvider, model).Visit(node);
        }

        class Lifter : SqlVisitor {
            private class Scope {
                internal Scope Parent;
                internal SqlExpression Where;
                internal Scope(SqlExpression where, Scope parent) {
                    this.Where = where;
                    this.Parent = parent;
                }
            };

            Scope current;
            SqlFactory sql;
            SqlAggregateChecker aggregateChecker;
            SqlRowNumberChecker rowNumberChecker;

            internal Lifter(TypeSystemProvider typeProvider, MetaModel model) {
                this.sql = new SqlFactory(typeProvider, model);
                this.aggregateChecker = new SqlAggregateChecker();
                this.rowNumberChecker = new SqlRowNumberChecker();
            }

            internal override SqlSelect VisitSelect(SqlSelect select) {
                Scope save = this.current;
                this.current = new Scope(select.Where, this.current);

                SqlSelect result = base.VisitSelect(select);

                bool stopHoisting =
                    select.IsDistinct ||
                    select.GroupBy.Count > 0 ||
                    this.aggregateChecker.HasAggregates(select) ||
                    select.Top != null ||
                    this.rowNumberChecker.HasRowNumber(select);

                // Shift as much of the current WHERE to the parent as possible.
                if (this.current != null) {
                    if (this.current.Parent != null && !stopHoisting) {
                        this.current.Parent.Where = sql.AndAccumulate(this.current.Parent.Where, this.current.Where);
                        this.current.Where = null;
                    }
                    select.Where = this.current.Where;
                }

                this.current = save;
                return result;
            }

            internal override SqlNode VisitUnion(SqlUnion su) {
                Scope save = this.current;
                this.current = null;
                SqlNode result = base.VisitUnion(su);
                this.current = save;
                return result;
            }
            internal override SqlSource VisitJoin(SqlJoin join) {
                // block where clauses from being lifted out of the cardinality-dependent 
                // side of an outer join.
                Scope save = this.current;
                try {
                    switch (join.JoinType) {
                        case SqlJoinType.Cross:
                        case SqlJoinType.CrossApply:
                        case SqlJoinType.Inner:
                            return base.VisitJoin(join);
                        case SqlJoinType.LeftOuter:
                        case SqlJoinType.OuterApply: {
                                join.Left = this.VisitSource(join.Left);
                                this.current = null;
                                join.Right = this.VisitSource(join.Right);
                                join.Condition = this.VisitExpression(join.Condition);
                                return join;
                            }
                        default:
                            this.current = null;
                            return base.VisitJoin(join);
                    }
                }
                finally {
                    this.current = save;
                }
            }
            internal override SqlExpression VisitSubSelect(SqlSubSelect ss) {
                // block where clauses from being lifted out of a sub-query
                Scope save = this.current;
                this.current = null;
                SqlExpression result = base.VisitSubSelect(ss);
                this.current = save;
                return result;
            }
            internal override SqlExpression VisitClientQuery(SqlClientQuery cq) {
                // block where clauses from being lifted out of a client-materialized sub-query
                Scope save = this.current;
                this.current = null;
                SqlExpression result = base.VisitClientQuery(cq);
                this.current = save;
                return result;
            }
        }
    }
}