SqlReorderer.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DLinq / Dlinq / SqlClient / Query / SqlReorderer.cs / 1305376 / SqlReorderer.cs

                            using System; 
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
 
namespace System.Data.Linq.SqlClient {
    using System.Data.Linq.Mapping; 
    using System.Data.Linq.Provider; 
    using System.Diagnostics.CodeAnalysis;
    using System.Linq.Expressions; 

    // moves order-by clauses from sub-queries to outer-most or top selects
    // removes ordering in correlated sub-queries
    internal class SqlReorderer { 
        TypeSystemProvider typeProvider;
        SqlFactory sql; 
 
        internal SqlReorderer(TypeSystemProvider typeProvider, SqlFactory sqlFactory) {
            this.typeProvider = typeProvider; 
            this.sql = sqlFactory;
        }

        internal SqlNode Reorder(SqlNode node) { 
            return new Visitor(this.typeProvider, this.sql).Visit(node);
        } 
 
        class Visitor : SqlVisitor {
            TypeSystemProvider typeProvider; 
            bool topSelect = true;
            bool addPrimaryKeys;
            List orders;
            List rowNumberOrders; 
            SqlSelect currentSelect;
            SqlFactory sql; 
            SqlAggregateChecker aggregateChecker; 

            internal Visitor(TypeSystemProvider typeProvider, SqlFactory sqlFactory) { 
                this.orders = new List();
                this.typeProvider = typeProvider;
                this.sql = sqlFactory;
                this.aggregateChecker = new SqlAggregateChecker(); 
            }
 
            internal override SqlExpression VisitSubSelect(SqlSubSelect ss) { 
                List save = this.orders;
                this.orders = new List(); 
                base.VisitSubSelect(ss);
                this.orders = save;
                return ss;
            } 

            private void PrependOrderExpressions(IEnumerable exprs) { 
                if (exprs != null) { 
                    this.Orders.InsertRange(0, exprs);
                } 
            }

            private List Orders {
                get { 
                    if (this.orders == null) {
                        this.orders = new List(); 
                    } 
                    return this.orders;
                } 
            }


            internal override SqlSource VisitJoin(SqlJoin join) { 
                this.Visit(join.Left);
                List leftOrders = this.orders; 
                this.orders = null; 
                this.Visit(join.Right);
                this.PrependOrderExpressions(leftOrders); 
                return join;
            }

            internal override SqlNode VisitUnion(SqlUnion su) { 
                // ordering does not carry through a union
                this.orders = null; 
                su.Left = this.Visit(su.Left); 
                this.orders = null;
                su.Right = this.Visit(su.Right); 
                this.orders = null;
                return su;
            }
 
            internal override SqlAlias VisitAlias(SqlAlias a) {
 
                SqlTable tab = a.Node as SqlTable; 
                SqlTableValuedFunctionCall tvf = a.Node as SqlTableValuedFunctionCall;
 
                if (this.addPrimaryKeys && (tab != null || tvf != null)) {
                    List list = new List();

                    bool isTable = tab != null; 
                    MetaType rowType = isTable ? tab.RowType : tvf.RowType;
                    foreach (MetaDataMember mm in rowType.IdentityMembers) { 
                        string name = mm.MappedName; 
                        SqlColumn col;
                        Expression sourceExpression; 
                        List columns;

                        if (isTable) {
                            col = tab.Find(name); 
                            sourceExpression = tab.SourceExpression;
                            columns = tab.Columns; 
                        } 
                        else {
                            col = tvf.Find(name); 
                            sourceExpression = tvf.SourceExpression;
                            columns = tvf.Columns;
                        }
 
                        if (col == null) {
                            col = new SqlColumn(mm.MemberAccessor.Type, typeProvider.From(mm.MemberAccessor.Type), name, mm, null, sourceExpression); 
                            col.Alias = a; 
                            columns.Add(col);
                        } 
                        list.Add(new SqlOrderExpression(SqlOrderType.Ascending, new SqlColumnRef(col)));
                    }

                    this.PrependOrderExpressions(list); 

                    return a; 
                } 
                else {
                    return base.VisitAlias(a); 
                }
            }

            internal override SqlSelect VisitSelect(SqlSelect select) { 
                bool saveTop = this.topSelect;
                bool savePK = this.addPrimaryKeys; 
 
                SqlSelect saveSelect = this.currentSelect;
                this.currentSelect = select; 

                if (select.OrderingType == SqlOrderingType.Always) {
                    this.addPrimaryKeys = true;
                } 

                this.topSelect = false; 
 
                // can't forward ordering information through a group-by
                if (select.GroupBy.Count > 0) { 
                    this.Visit(select.From);
                    this.orders = null;
                }
                else { 
                    this.Visit(select.From);
                } 
 
                if (select.OrderBy.Count > 0) {
                    this.PrependOrderExpressions(select.OrderBy); 
                }

                List save = this.orders;
                this.orders = null; 
                this.rowNumberOrders = save; // lest orders be null when we need info
 
                /* do all the lower level stuff */ 
                select.Where = this.VisitExpression(select.Where);
                for (int i = 0, n = select.GroupBy.Count; i < n; i++) { 
                    select.GroupBy[i] = this.VisitExpression(select.GroupBy[i]);
                }
                select.Having = this.VisitExpression(select.Having);
                for (int i = 0, n = select.OrderBy.Count; i < n; i++) { 
                    select.OrderBy[i].Expression = this.VisitExpression(select.OrderBy[i].Expression);
                } 
                select.Top = this.VisitExpression(select.Top); 
                select.Selection = this.VisitExpression(select.Selection);
                select.Row = (SqlRow)this.Visit(select.Row); 

                this.topSelect = saveTop;
                this.addPrimaryKeys = savePK;
 
                this.orders = save;
 
                // all ordering is blocked for this layer and above 
                if (select.OrderingType == SqlOrderingType.Blocked) {
                    this.orders = null; 
                }

                // rebuild orderby expressions, provided this select doesn't contain a SqlRowNumber
                // otherwise, replace the orderby with a reference to that column 
                select.OrderBy.Clear();
                var rowNumberChecker = new SqlRowNumberChecker(); 
 
                if (rowNumberChecker.HasRowNumber(select) && rowNumberChecker.RowNumberColumn != null) {
                    select.Row.Columns.Remove(rowNumberChecker.RowNumberColumn); 
                    this.PushDown(rowNumberChecker.RowNumberColumn);
                    this.Orders.Add(new SqlOrderExpression(SqlOrderType.Ascending, new SqlColumnRef(rowNumberChecker.RowNumberColumn)));
                }
                if ((this.topSelect || select.Top != null) && select.OrderingType != SqlOrderingType.Never && this.orders != null) { 
                    this.orders = new HashSet(this.orders).ToList();
                    SqlDuplicator dup = new SqlDuplicator(true); 
                    foreach (SqlOrderExpression sox in this.orders) { 
                        select.OrderBy.Add(new SqlOrderExpression(sox.OrderType, (SqlExpression)dup.Duplicate(sox.Expression)));
                    } 
                }
                this.currentSelect = saveSelect;

                return select; 
            }
 
            internal override SqlRowNumber VisitRowNumber(SqlRowNumber rowNumber) { 
                if (rowNumber.OrderBy.Count > 0) return rowNumber;
 
                SqlDuplicator dup = new SqlDuplicator(true);
                List orderBy = new List();
                List existingOrders = new List();
 
                if (this.rowNumberOrders != null && this.rowNumberOrders.Count != 0) {
                    existingOrders = new List(this.rowNumberOrders); 
                } 
                else if (this.orders != null) {
                    existingOrders = new List(this.orders); 
                }

                foreach (SqlOrderExpression expr in existingOrders) {
                    if (!expr.Expression.IsConstantColumn) { 
                        orderBy.Add(expr);
                        if (this.rowNumberOrders != null) { 
                            this.rowNumberOrders.Remove(expr); 
                        }
                        if (this.orders != null) { 
                            this.orders.Remove(expr);
                        }
                    }
                } 

                rowNumber.OrderBy.Clear(); 
 
                if (orderBy.Count == 0) {
                    List columns = SqlGatherColumnsProduced.GatherColumns(this.currentSelect.From); 

                    foreach (SqlColumn col in columns) {
                        if (col.Expression.SqlType.IsOrderable) {
                            orderBy.Add(new SqlOrderExpression(SqlOrderType.Ascending, new SqlColumnRef(col))); 
                        }
                    } 
 
                    if (orderBy.Count == 0) {
                        // insert simple column 
                        SqlColumn col =
                            new SqlColumn(
                                "rowNumberOrder",
                                sql.Value(typeof(int), this.typeProvider.From(typeof(int)), 1, false, rowNumber.SourceExpression) 
                            );
                        this.PushDown(col); 
                        orderBy.Add(new SqlOrderExpression(SqlOrderType.Ascending, new SqlColumnRef(col))); 
                    }
                } 

                foreach (SqlOrderExpression sox in orderBy) {
                    rowNumber.OrderBy.Add(new SqlOrderExpression(sox.OrderType, (SqlExpression)dup.Duplicate(sox.Expression)));
                } 

                return rowNumber; 
            } 

            private void PushDown(SqlColumn column) { 
                SqlSelect select = new SqlSelect(new SqlNop(column.ClrType, column.SqlType, column.SourceExpression), this.currentSelect.From, this.currentSelect.SourceExpression);
                this.currentSelect.From = new SqlAlias(select);
                select.Row.Columns.Add(column);
            } 
        }
 
        internal class SqlGatherColumnsProduced { 
            static internal List GatherColumns(SqlSource source) {
                List columns = new List(); 
                new Visitor(columns).Visit(source);
                return columns;
            }
            class Visitor : SqlVisitor { 
                List columns;
                internal Visitor(List columns) { 
                    this.columns = columns; 
                }
                internal override SqlSelect VisitSelect(SqlSelect select) { 
                    foreach (SqlColumn c in select.Row.Columns) {
                        this.columns.Add(c);
                    }
                    return select; 
                }
                internal override SqlNode VisitUnion(SqlUnion su) { 
                    return su; 
                }
            } 
        }
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK