Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DLinq / Dlinq / SqlClient / Query / SqlOuterApplyReducer.cs / 1 / SqlOuterApplyReducer.cs
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Data.Linq; using System.Diagnostics.CodeAnalysis; namespace System.Data.Linq.SqlClient { ////// internal class SqlOuterApplyReducer { internal static SqlNode Reduce(SqlNode node, SqlFactory factory, SqlNodeAnnotations annotations) { Visitor r = new Visitor(factory, annotations); return r.Visit(node); } class Visitor : SqlVisitor { SqlFactory factory; SqlNodeAnnotations annotations; internal Visitor(SqlFactory factory, SqlNodeAnnotations annotations) { this.factory = factory; this.annotations = annotations; } internal override SqlSource VisitSource(SqlSource source) { source = base.VisitSource(source); SqlJoin join = source as SqlJoin; if (join != null) { if (join.JoinType == SqlJoinType.OuterApply) { // Reduce outer-apply into left-outer-join HashSetleftProducedAliases = SqlGatherProducedAliases.Gather(join.Left); HashSet liftedExpressions = new HashSet (); if (SqlPredicateLifter.CanLift(join.Right, leftProducedAliases, liftedExpressions) && SqlSelectionLifter.CanLift(join.Right, leftProducedAliases, liftedExpressions) && !SqlAliasDependencyChecker.IsDependent(join.Right, leftProducedAliases, liftedExpressions) ) { SqlExpression liftedPredicate = SqlPredicateLifter.Lift(join.Right, leftProducedAliases); List > liftedSelections = SqlSelectionLifter.Lift(join.Right, leftProducedAliases, liftedExpressions); join.JoinType = SqlJoinType.LeftOuter; join.Condition = liftedPredicate; if (liftedSelections != null) { foreach(List
selection in liftedSelections) { source = this.PushSourceDown(source, selection); } } } else { this.AnnotateSqlIncompatibility(join, SqlProvider.ProviderMode.Sql2000); } } else if (join.JoinType == SqlJoinType.CrossApply) { // reduce cross apply with special nested left-outer-join's into a single left-outer-join // // SELECT x.*, y.* // FROM X // CROSS APPLY ( // SELECT y.* // FROM ( // SELECT ? // ) // LEFT OUTER JOIN ( // SELECT y.* FROM Y // ) AS y // // ==> // // SELECT x.*, y.* // FROM X // LEFT OUTER JOIN ( // SELECT y.* FROM Y // ) SqlJoin leftOuter = this.GetLeftOuterWithUnreferencedSingletonOnLeft(join.Right); if (leftOuter != null) { HashSet leftProducedAliases = SqlGatherProducedAliases.Gather(join.Left); HashSet liftedExpressions = new HashSet (); if (SqlPredicateLifter.CanLift(leftOuter.Right, leftProducedAliases, liftedExpressions) && SqlSelectionLifter.CanLift(leftOuter.Right, leftProducedAliases, liftedExpressions) && !SqlAliasDependencyChecker.IsDependent(leftOuter.Right, leftProducedAliases, liftedExpressions) ) { SqlExpression liftedPredicate = SqlPredicateLifter.Lift(leftOuter.Right, leftProducedAliases); List > liftedSelections = SqlSelectionLifter.Lift(leftOuter.Right, leftProducedAliases, liftedExpressions); // add intermediate selections this.GetSelectionsBeforeJoin(join.Right, liftedSelections); // push down all selections foreach(List
selection in liftedSelections.Where(s => s.Count > 0)) { source = this.PushSourceDown(source, selection); } join.JoinType = SqlJoinType.LeftOuter; join.Condition = this.factory.AndAccumulate(leftOuter.Condition, liftedPredicate); join.Right = leftOuter.Right; } else { this.AnnotateSqlIncompatibility(join, SqlProvider.ProviderMode.Sql2000); } } } // re-balance join tree of left-outer-joins to expose LOJ w/ leftside unreferenced while (join.JoinType == SqlJoinType.LeftOuter) { // look for buried left-outer-joined-with-unreferenced singleton SqlJoin leftLeftOuter = this.GetLeftOuterWithUnreferencedSingletonOnLeft(join.Left); if (leftLeftOuter == null) break; List > liftedSelections = new List
>(); // add intermediate selections this.GetSelectionsBeforeJoin(join.Left, liftedSelections); // push down all selections foreach(List
selection in liftedSelections) { source = this.PushSourceDown(source, selection); } // bubble this one up on-top of this 'join'. SqlSource jRight = join.Right; SqlExpression jCondition = join.Condition; join.Left = leftLeftOuter.Left; join.Right = leftLeftOuter; join.Condition = leftLeftOuter.Condition; leftLeftOuter.Left = leftLeftOuter.Right; leftLeftOuter.Right = jRight; leftLeftOuter.Condition = jCondition; } } return source; } private void AnnotateSqlIncompatibility(SqlNode node, params SqlProvider.ProviderMode[] providers) { this.annotations.Add(node, new SqlServerCompatibilityAnnotation(Strings.SourceExpressionAnnotation(node.SourceExpression), providers)); } [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")] private SqlSource PushSourceDown(SqlSource sqlSource, List cols) { SqlSelect ns = new SqlSelect(new SqlNop(cols[0].ClrType, cols[0].SqlType, sqlSource.SourceExpression), sqlSource, sqlSource.SourceExpression); ns.Row.Columns.AddRange(cols); return new SqlAlias(ns); } private SqlJoin GetLeftOuterWithUnreferencedSingletonOnLeft(SqlSource source) { SqlAlias alias = source as SqlAlias; if (alias != null) { SqlSelect select = alias.Node as SqlSelect; if (select != null && select.Where == null && select.Top == null && select.GroupBy.Count == 0 && select.OrderBy.Count == 0) { return this.GetLeftOuterWithUnreferencedSingletonOnLeft(select.From); } } SqlJoin join = source as SqlJoin; if (join == null || join.JoinType != SqlJoinType.LeftOuter) return null; if (!this.IsSingletonSelect(join.Left)) return null; HashSet p = SqlGatherProducedAliases.Gather(join.Left); HashSet c = SqlGatherConsumedAliases.Gather(join.Right); if (p.Overlaps(c)) { return null; } return join; } private void GetSelectionsBeforeJoin(SqlSource source, List > selections) { SqlJoin join = source as SqlJoin; if (join != null) return; SqlAlias alias = source as SqlAlias; if (alias != null) { SqlSelect select = alias.Node as SqlSelect; if (select != null) { this.GetSelectionsBeforeJoin(select.From, selections); selections.Add(select.Row.Columns); } } } [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")] private bool IsSingletonSelect(SqlSource source) { SqlAlias alias = source as SqlAlias; if (alias == null) return false; SqlSelect select = alias.Node as SqlSelect; if (select == null) return false; if (select.From != null) return false; return true; } } class SqlGatherReferencedColumns { private SqlGatherReferencedColumns() { } internal static HashSet
Gather(SqlNode node, HashSet columns) { Visitor v = new Visitor(columns); v.Visit(node); return columns; } class Visitor : SqlVisitor { HashSet columns; internal Visitor(HashSet columns) { this.columns = columns; } internal override SqlExpression VisitColumnRef(SqlColumnRef cref) { if (!this.columns.Contains(cref.Column)) { this.columns.Add(cref.Column); if (cref.Column.Expression != null) { this.Visit(cref.Column.Expression); } } return cref; } } } class SqlAliasesReferenced { HashSet aliases; bool referencesAny; Visitor visitor; internal SqlAliasesReferenced(HashSet aliases) { this.aliases = aliases; this.visitor = new Visitor(this); } internal bool ReferencesAny(SqlExpression expression) { this.referencesAny = false; this.visitor.Visit(expression); return this.referencesAny; } class Visitor: SqlVisitor { SqlAliasesReferenced parent; internal Visitor(SqlAliasesReferenced parent) { this.parent = parent; } internal override SqlExpression VisitColumnRef(SqlColumnRef cref) { if (this.parent.aliases.Contains(cref.Column.Alias)) { this.parent.referencesAny = true; } else if (cref.Column.Expression != null) { this.Visit(cref.Column.Expression); } return cref; } internal override SqlExpression VisitColumn(SqlColumn col) { if (col.Expression != null) { this.Visit(col.Expression); } return col; } } } static class SqlAliasDependencyChecker { internal static bool IsDependent(SqlNode node, HashSet aliasesToCheck, HashSet ignoreExpressions) { Visitor v = new Visitor(aliasesToCheck, ignoreExpressions); v.Visit(node); return v.hasDependency; } class Visitor : SqlVisitor { HashSet aliasesToCheck; HashSet ignoreExpressions; internal bool hasDependency; internal Visitor(HashSet aliasesToCheck, HashSet ignoreExpressions) { this.aliasesToCheck = aliasesToCheck; this.ignoreExpressions = ignoreExpressions; } internal override SqlNode Visit(SqlNode node) { SqlExpression e = node as SqlExpression; if (this.hasDependency) return node; if (e != null && this.ignoreExpressions.Contains(e)) { return node; } return base.Visit(node); } internal override SqlExpression VisitColumnRef(SqlColumnRef cref) { if (this.aliasesToCheck.Contains(cref.Column.Alias)) { this.hasDependency = true; } else if (cref.Column.Expression != null) { this.Visit(cref.Column.Expression); } return cref; } internal override SqlExpression VisitColumn(SqlColumn col) { if (col.Expression != null) { this.Visit(col.Expression); } return col; } } } static class SqlPredicateLifter { internal static bool CanLift(SqlSource source, HashSet aliasesForLifting, HashSet liftedExpressions) { System.Diagnostics.Debug.Assert(source != null); System.Diagnostics.Debug.Assert(aliasesForLifting != null); Visitor v = new Visitor(false, aliasesForLifting, liftedExpressions); v.VisitSource(source); return v.canLiftAll; } internal static SqlExpression Lift(SqlSource source, HashSet aliasesForLifting) { System.Diagnostics.Debug.Assert(source != null); System.Diagnostics.Debug.Assert(aliasesForLifting != null); Visitor v = new Visitor(true, aliasesForLifting, null); v.VisitSource(source); return v.lifted; } class Visitor : SqlVisitor { SqlAliasesReferenced aliases; HashSet liftedExpressions; bool doLifting; internal bool canLiftAll; internal SqlExpression lifted; SqlAggregateChecker aggregateChecker; internal Visitor(bool doLifting, HashSet aliasesForLifting, HashSet liftedExpressions) { this.doLifting = doLifting; this.aliases = new SqlAliasesReferenced(aliasesForLifting); this.liftedExpressions = liftedExpressions; this.canLiftAll = true; this.aggregateChecker = new SqlAggregateChecker(); } internal override SqlSelect VisitSelect(SqlSelect select) { // check subqueries first this.VisitSource(select.From); // don't allow lifting through these operations if (select.Top != null || select.GroupBy.Count > 0 || this.aggregateChecker.HasAggregates(select) || select.IsDistinct) { this.canLiftAll = false; } // only lift predicates that actually reference the aliases if (this.canLiftAll && select.Where != null) { bool referencesAliases = this.aliases.ReferencesAny(select.Where); if (referencesAliases) { if (this.liftedExpressions != null) { this.liftedExpressions.Add(select.Where); } if (this.doLifting) { if (this.lifted != null) this.lifted = new SqlBinary(SqlNodeType.And, this.lifted.ClrType, this.lifted.SqlType, this.lifted, select.Where); else this.lifted = select.Where; select.Where = null; } } } return select; } } } static class SqlSelectionLifter { internal static bool CanLift(SqlSource source, HashSet aliasesForLifting, HashSet liftedExpressions) { Visitor v = new Visitor(false, aliasesForLifting, liftedExpressions); v.VisitSource(source); return v.canLiftAll; } internal static List > Lift(SqlSource source, HashSet
aliasesForLifting, HashSet liftedExpressions) { Visitor v = new Visitor(true, aliasesForLifting, liftedExpressions); v.VisitSource(source); return v.lifted; } class Visitor : SqlVisitor { SqlAliasesReferenced aliases; HashSet referencedColumns; HashSet liftedExpressions; internal List > lifted; internal bool canLiftAll; bool hasLifted; bool doLifting; SqlAggregateChecker aggregateChecker; internal Visitor(bool doLifting, HashSet
aliasesForLifting, HashSet liftedExpressions) { this.doLifting = doLifting; this.aliases = new SqlAliasesReferenced(aliasesForLifting); this.referencedColumns = new HashSet (); this.liftedExpressions = liftedExpressions; this.canLiftAll = true; if (doLifting) this.lifted = new List >(); this.aggregateChecker = new SqlAggregateChecker(); } internal override SqlSource VisitJoin(SqlJoin join) { this.ReferenceColumns(join.Condition); return base.VisitJoin(join); } internal override SqlSelect VisitSelect(SqlSelect select) { // reference all columns this.ReferenceColumns(select.Where); foreach(SqlOrderExpression oe in select.OrderBy) { // this.ReferenceColumns(oe.Expression); } foreach(SqlExpression e in select.GroupBy) { // this.ReferenceColumns(e); } this.ReferenceColumns(select.Having); // determine what if anything should be lifted from this select List
lift = null; List keep = null; foreach (SqlColumn sc in select.Row.Columns) { bool referencesAliasesForLifting = this.aliases.ReferencesAny(sc.Expression); bool isLockedExpression = this.referencedColumns.Contains(sc); if (referencesAliasesForLifting) { // if (isLockedExpression) { this.canLiftAll = false; this.ReferenceColumns(sc); } else { this.hasLifted = true; if (this.doLifting) { if (lift == null) lift = new List (); lift.Add(sc); } } } else { if (this.doLifting) { if (keep == null) keep = new List (); keep.Add(sc); } this.ReferenceColumns(sc); } } // check subqueries too if (this.canLiftAll) { this.VisitSource(select.From); } // don't allow lifting through these operations if (select.Top != null || select.GroupBy.Count > 0 || this.aggregateChecker.HasAggregates(select) || select.IsDistinct) { if (this.hasLifted) { // this.canLiftAll = false; } } // do the actual lifting for this select if (this.doLifting && this.canLiftAll) { select.Row.Columns.Clear(); if (keep != null) select.Row.Columns.AddRange(keep); if (lift != null) { // this.lifted.Add(lift); } } return select; } private void ReferenceColumns(SqlExpression expression) { if (expression != null) { if (this.liftedExpressions == null || !this.liftedExpressions.Contains(expression)) { SqlGatherReferencedColumns.Gather(expression, this.referencedColumns); } } } } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Data.Linq; using System.Diagnostics.CodeAnalysis; namespace System.Data.Linq.SqlClient { /// /// internal class SqlOuterApplyReducer { internal static SqlNode Reduce(SqlNode node, SqlFactory factory, SqlNodeAnnotations annotations) { Visitor r = new Visitor(factory, annotations); return r.Visit(node); } class Visitor : SqlVisitor { SqlFactory factory; SqlNodeAnnotations annotations; internal Visitor(SqlFactory factory, SqlNodeAnnotations annotations) { this.factory = factory; this.annotations = annotations; } internal override SqlSource VisitSource(SqlSource source) { source = base.VisitSource(source); SqlJoin join = source as SqlJoin; if (join != null) { if (join.JoinType == SqlJoinType.OuterApply) { // Reduce outer-apply into left-outer-join HashSetleftProducedAliases = SqlGatherProducedAliases.Gather(join.Left); HashSet liftedExpressions = new HashSet (); if (SqlPredicateLifter.CanLift(join.Right, leftProducedAliases, liftedExpressions) && SqlSelectionLifter.CanLift(join.Right, leftProducedAliases, liftedExpressions) && !SqlAliasDependencyChecker.IsDependent(join.Right, leftProducedAliases, liftedExpressions) ) { SqlExpression liftedPredicate = SqlPredicateLifter.Lift(join.Right, leftProducedAliases); List > liftedSelections = SqlSelectionLifter.Lift(join.Right, leftProducedAliases, liftedExpressions); join.JoinType = SqlJoinType.LeftOuter; join.Condition = liftedPredicate; if (liftedSelections != null) { foreach(List
selection in liftedSelections) { source = this.PushSourceDown(source, selection); } } } else { this.AnnotateSqlIncompatibility(join, SqlProvider.ProviderMode.Sql2000); } } else if (join.JoinType == SqlJoinType.CrossApply) { // reduce cross apply with special nested left-outer-join's into a single left-outer-join // // SELECT x.*, y.* // FROM X // CROSS APPLY ( // SELECT y.* // FROM ( // SELECT ? // ) // LEFT OUTER JOIN ( // SELECT y.* FROM Y // ) AS y // // ==> // // SELECT x.*, y.* // FROM X // LEFT OUTER JOIN ( // SELECT y.* FROM Y // ) SqlJoin leftOuter = this.GetLeftOuterWithUnreferencedSingletonOnLeft(join.Right); if (leftOuter != null) { HashSet leftProducedAliases = SqlGatherProducedAliases.Gather(join.Left); HashSet liftedExpressions = new HashSet (); if (SqlPredicateLifter.CanLift(leftOuter.Right, leftProducedAliases, liftedExpressions) && SqlSelectionLifter.CanLift(leftOuter.Right, leftProducedAliases, liftedExpressions) && !SqlAliasDependencyChecker.IsDependent(leftOuter.Right, leftProducedAliases, liftedExpressions) ) { SqlExpression liftedPredicate = SqlPredicateLifter.Lift(leftOuter.Right, leftProducedAliases); List > liftedSelections = SqlSelectionLifter.Lift(leftOuter.Right, leftProducedAliases, liftedExpressions); // add intermediate selections this.GetSelectionsBeforeJoin(join.Right, liftedSelections); // push down all selections foreach(List
selection in liftedSelections.Where(s => s.Count > 0)) { source = this.PushSourceDown(source, selection); } join.JoinType = SqlJoinType.LeftOuter; join.Condition = this.factory.AndAccumulate(leftOuter.Condition, liftedPredicate); join.Right = leftOuter.Right; } else { this.AnnotateSqlIncompatibility(join, SqlProvider.ProviderMode.Sql2000); } } } // re-balance join tree of left-outer-joins to expose LOJ w/ leftside unreferenced while (join.JoinType == SqlJoinType.LeftOuter) { // look for buried left-outer-joined-with-unreferenced singleton SqlJoin leftLeftOuter = this.GetLeftOuterWithUnreferencedSingletonOnLeft(join.Left); if (leftLeftOuter == null) break; List > liftedSelections = new List
>(); // add intermediate selections this.GetSelectionsBeforeJoin(join.Left, liftedSelections); // push down all selections foreach(List
selection in liftedSelections) { source = this.PushSourceDown(source, selection); } // bubble this one up on-top of this 'join'. SqlSource jRight = join.Right; SqlExpression jCondition = join.Condition; join.Left = leftLeftOuter.Left; join.Right = leftLeftOuter; join.Condition = leftLeftOuter.Condition; leftLeftOuter.Left = leftLeftOuter.Right; leftLeftOuter.Right = jRight; leftLeftOuter.Condition = jCondition; } } return source; } private void AnnotateSqlIncompatibility(SqlNode node, params SqlProvider.ProviderMode[] providers) { this.annotations.Add(node, new SqlServerCompatibilityAnnotation(Strings.SourceExpressionAnnotation(node.SourceExpression), providers)); } [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")] private SqlSource PushSourceDown(SqlSource sqlSource, List cols) { SqlSelect ns = new SqlSelect(new SqlNop(cols[0].ClrType, cols[0].SqlType, sqlSource.SourceExpression), sqlSource, sqlSource.SourceExpression); ns.Row.Columns.AddRange(cols); return new SqlAlias(ns); } private SqlJoin GetLeftOuterWithUnreferencedSingletonOnLeft(SqlSource source) { SqlAlias alias = source as SqlAlias; if (alias != null) { SqlSelect select = alias.Node as SqlSelect; if (select != null && select.Where == null && select.Top == null && select.GroupBy.Count == 0 && select.OrderBy.Count == 0) { return this.GetLeftOuterWithUnreferencedSingletonOnLeft(select.From); } } SqlJoin join = source as SqlJoin; if (join == null || join.JoinType != SqlJoinType.LeftOuter) return null; if (!this.IsSingletonSelect(join.Left)) return null; HashSet p = SqlGatherProducedAliases.Gather(join.Left); HashSet c = SqlGatherConsumedAliases.Gather(join.Right); if (p.Overlaps(c)) { return null; } return join; } private void GetSelectionsBeforeJoin(SqlSource source, List > selections) { SqlJoin join = source as SqlJoin; if (join != null) return; SqlAlias alias = source as SqlAlias; if (alias != null) { SqlSelect select = alias.Node as SqlSelect; if (select != null) { this.GetSelectionsBeforeJoin(select.From, selections); selections.Add(select.Row.Columns); } } } [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification="Unknown reason.")] private bool IsSingletonSelect(SqlSource source) { SqlAlias alias = source as SqlAlias; if (alias == null) return false; SqlSelect select = alias.Node as SqlSelect; if (select == null) return false; if (select.From != null) return false; return true; } } class SqlGatherReferencedColumns { private SqlGatherReferencedColumns() { } internal static HashSet
Gather(SqlNode node, HashSet columns) { Visitor v = new Visitor(columns); v.Visit(node); return columns; } class Visitor : SqlVisitor { HashSet columns; internal Visitor(HashSet columns) { this.columns = columns; } internal override SqlExpression VisitColumnRef(SqlColumnRef cref) { if (!this.columns.Contains(cref.Column)) { this.columns.Add(cref.Column); if (cref.Column.Expression != null) { this.Visit(cref.Column.Expression); } } return cref; } } } class SqlAliasesReferenced { HashSet aliases; bool referencesAny; Visitor visitor; internal SqlAliasesReferenced(HashSet aliases) { this.aliases = aliases; this.visitor = new Visitor(this); } internal bool ReferencesAny(SqlExpression expression) { this.referencesAny = false; this.visitor.Visit(expression); return this.referencesAny; } class Visitor: SqlVisitor { SqlAliasesReferenced parent; internal Visitor(SqlAliasesReferenced parent) { this.parent = parent; } internal override SqlExpression VisitColumnRef(SqlColumnRef cref) { if (this.parent.aliases.Contains(cref.Column.Alias)) { this.parent.referencesAny = true; } else if (cref.Column.Expression != null) { this.Visit(cref.Column.Expression); } return cref; } internal override SqlExpression VisitColumn(SqlColumn col) { if (col.Expression != null) { this.Visit(col.Expression); } return col; } } } static class SqlAliasDependencyChecker { internal static bool IsDependent(SqlNode node, HashSet aliasesToCheck, HashSet ignoreExpressions) { Visitor v = new Visitor(aliasesToCheck, ignoreExpressions); v.Visit(node); return v.hasDependency; } class Visitor : SqlVisitor { HashSet aliasesToCheck; HashSet ignoreExpressions; internal bool hasDependency; internal Visitor(HashSet aliasesToCheck, HashSet ignoreExpressions) { this.aliasesToCheck = aliasesToCheck; this.ignoreExpressions = ignoreExpressions; } internal override SqlNode Visit(SqlNode node) { SqlExpression e = node as SqlExpression; if (this.hasDependency) return node; if (e != null && this.ignoreExpressions.Contains(e)) { return node; } return base.Visit(node); } internal override SqlExpression VisitColumnRef(SqlColumnRef cref) { if (this.aliasesToCheck.Contains(cref.Column.Alias)) { this.hasDependency = true; } else if (cref.Column.Expression != null) { this.Visit(cref.Column.Expression); } return cref; } internal override SqlExpression VisitColumn(SqlColumn col) { if (col.Expression != null) { this.Visit(col.Expression); } return col; } } } static class SqlPredicateLifter { internal static bool CanLift(SqlSource source, HashSet aliasesForLifting, HashSet liftedExpressions) { System.Diagnostics.Debug.Assert(source != null); System.Diagnostics.Debug.Assert(aliasesForLifting != null); Visitor v = new Visitor(false, aliasesForLifting, liftedExpressions); v.VisitSource(source); return v.canLiftAll; } internal static SqlExpression Lift(SqlSource source, HashSet aliasesForLifting) { System.Diagnostics.Debug.Assert(source != null); System.Diagnostics.Debug.Assert(aliasesForLifting != null); Visitor v = new Visitor(true, aliasesForLifting, null); v.VisitSource(source); return v.lifted; } class Visitor : SqlVisitor { SqlAliasesReferenced aliases; HashSet liftedExpressions; bool doLifting; internal bool canLiftAll; internal SqlExpression lifted; SqlAggregateChecker aggregateChecker; internal Visitor(bool doLifting, HashSet aliasesForLifting, HashSet liftedExpressions) { this.doLifting = doLifting; this.aliases = new SqlAliasesReferenced(aliasesForLifting); this.liftedExpressions = liftedExpressions; this.canLiftAll = true; this.aggregateChecker = new SqlAggregateChecker(); } internal override SqlSelect VisitSelect(SqlSelect select) { // check subqueries first this.VisitSource(select.From); // don't allow lifting through these operations if (select.Top != null || select.GroupBy.Count > 0 || this.aggregateChecker.HasAggregates(select) || select.IsDistinct) { this.canLiftAll = false; } // only lift predicates that actually reference the aliases if (this.canLiftAll && select.Where != null) { bool referencesAliases = this.aliases.ReferencesAny(select.Where); if (referencesAliases) { if (this.liftedExpressions != null) { this.liftedExpressions.Add(select.Where); } if (this.doLifting) { if (this.lifted != null) this.lifted = new SqlBinary(SqlNodeType.And, this.lifted.ClrType, this.lifted.SqlType, this.lifted, select.Where); else this.lifted = select.Where; select.Where = null; } } } return select; } } } static class SqlSelectionLifter { internal static bool CanLift(SqlSource source, HashSet aliasesForLifting, HashSet liftedExpressions) { Visitor v = new Visitor(false, aliasesForLifting, liftedExpressions); v.VisitSource(source); return v.canLiftAll; } internal static List > Lift(SqlSource source, HashSet
aliasesForLifting, HashSet liftedExpressions) { Visitor v = new Visitor(true, aliasesForLifting, liftedExpressions); v.VisitSource(source); return v.lifted; } class Visitor : SqlVisitor { SqlAliasesReferenced aliases; HashSet referencedColumns; HashSet liftedExpressions; internal List > lifted; internal bool canLiftAll; bool hasLifted; bool doLifting; SqlAggregateChecker aggregateChecker; internal Visitor(bool doLifting, HashSet
aliasesForLifting, HashSet liftedExpressions) { this.doLifting = doLifting; this.aliases = new SqlAliasesReferenced(aliasesForLifting); this.referencedColumns = new HashSet (); this.liftedExpressions = liftedExpressions; this.canLiftAll = true; if (doLifting) this.lifted = new List >(); this.aggregateChecker = new SqlAggregateChecker(); } internal override SqlSource VisitJoin(SqlJoin join) { this.ReferenceColumns(join.Condition); return base.VisitJoin(join); } internal override SqlSelect VisitSelect(SqlSelect select) { // reference all columns this.ReferenceColumns(select.Where); foreach(SqlOrderExpression oe in select.OrderBy) { // this.ReferenceColumns(oe.Expression); } foreach(SqlExpression e in select.GroupBy) { // this.ReferenceColumns(e); } this.ReferenceColumns(select.Having); // determine what if anything should be lifted from this select List
lift = null; List keep = null; foreach (SqlColumn sc in select.Row.Columns) { bool referencesAliasesForLifting = this.aliases.ReferencesAny(sc.Expression); bool isLockedExpression = this.referencedColumns.Contains(sc); if (referencesAliasesForLifting) { // if (isLockedExpression) { this.canLiftAll = false; this.ReferenceColumns(sc); } else { this.hasLifted = true; if (this.doLifting) { if (lift == null) lift = new List (); lift.Add(sc); } } } else { if (this.doLifting) { if (keep == null) keep = new List (); keep.Add(sc); } this.ReferenceColumns(sc); } } // check subqueries too if (this.canLiftAll) { this.VisitSource(select.From); } // don't allow lifting through these operations if (select.Top != null || select.GroupBy.Count > 0 || this.aggregateChecker.HasAggregates(select) || select.IsDistinct) { if (this.hasLifted) { // this.canLiftAll = false; } } // do the actual lifting for this select if (this.doLifting && this.canLiftAll) { select.Row.Columns.Clear(); if (keep != null) select.Row.Columns.AddRange(keep); if (lift != null) { // this.lifted.Add(lift); } } return select; } private void ReferenceColumns(SqlExpression expression) { if (expression != null) { if (this.liftedExpressions == null || !this.liftedExpressions.Contains(expression)) { SqlGatherReferencedColumns.Gather(expression, this.referencedColumns); } } } } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- MessageBox.cs
- EntityObject.cs
- ThreadInterruptedException.cs
- ObjectDataSourceMethodEventArgs.cs
- ChtmlTextBoxAdapter.cs
- HtmlTextArea.cs
- CustomAttributeBuilder.cs
- DoubleLinkListEnumerator.cs
- NamedObject.cs
- ObjectParameter.cs
- DataServiceHost.cs
- GroupDescription.cs
- GraphicsContext.cs
- LineMetrics.cs
- TextAction.cs
- ProfileWorkflowElement.cs
- CommandBinding.cs
- AsymmetricKeyExchangeDeformatter.cs
- Internal.cs
- MatrixTransform3D.cs
- PersonalizationProviderCollection.cs
- VariantWrapper.cs
- DataGridViewColumnCollectionEditor.cs
- TextTreeRootTextBlock.cs
- XmlEnumAttribute.cs
- ClassDataContract.cs
- Int32KeyFrameCollection.cs
- BasicAsyncResult.cs
- DaylightTime.cs
- Transform.cs
- SingleTagSectionHandler.cs
- PenContext.cs
- Help.cs
- VerificationException.cs
- TextRangeProviderWrapper.cs
- GroupBoxAutomationPeer.cs
- SqlTriggerAttribute.cs
- Internal.cs
- DrawingCollection.cs
- ProcessHost.cs
- RemoteHelper.cs
- ControlValuePropertyAttribute.cs
- Atom10FormatterFactory.cs
- Transform.cs
- RichTextBox.cs
- OracleTimeSpan.cs
- Claim.cs
- TiffBitmapDecoder.cs
- CharacterMetricsDictionary.cs
- ImageMetadata.cs
- SafeEventLogReadHandle.cs
- BaseValidator.cs
- AuthenticationService.cs
- CompoundFileStorageReference.cs
- DependencyObjectProvider.cs
- CellPartitioner.cs
- DataGridTable.cs
- Vector3DCollectionValueSerializer.cs
- StaticTextPointer.cs
- Span.cs
- MultiPropertyDescriptorGridEntry.cs
- AssemblyName.cs
- ValueSerializerAttribute.cs
- ProcessModelSection.cs
- SqlParameterizer.cs
- WindowsListViewScroll.cs
- FlowDecisionDesigner.xaml.cs
- PersonalizableAttribute.cs
- SerialPinChanges.cs
- OutputCacheSettings.cs
- TTSVoice.cs
- MobileListItem.cs
- SymbolEqualComparer.cs
- SspiHelper.cs
- ExtentJoinTreeNode.cs
- DependencyPropertyKey.cs
- StaticExtensionConverter.cs
- XPathNodeInfoAtom.cs
- CompressEmulationStream.cs
- IssuedTokenParametersEndpointAddressElement.cs
- LinkAreaEditor.cs
- List.cs
- DbException.cs
- AsymmetricSecurityProtocol.cs
- DLinqTableProvider.cs
- OutputCacheModule.cs
- DBConnectionString.cs
- _CommandStream.cs
- Int64AnimationBase.cs
- ImageClickEventArgs.cs
- Zone.cs
- ManipulationDelta.cs
- RegistrationServices.cs
- ToolStripDropDownClosedEventArgs.cs
- ClientSponsor.cs
- Crc32.cs
- PriorityBinding.cs
- Events.cs
- XmlBoundElement.cs
- TextViewBase.cs