internal override SqlSource VisitJoin(SqlJoin join) { if (join.JoinType == SqlJoinType.CrossApply) { // Visit the left side as usual. join.Left = this.VisitSource(join.Left); // Visit the condition as usual. join.Condition = this.VisitExpression(join.Condition); // Visit the right, with the expressionSink set. SelectScope s = expressionSink; expressionSink = new SelectScope(); expressionSink.LeftProduction = SqlGatherProducedAliases.Gather(join.Left); join.Right = this.VisitSource(join.Right); // Were liftable expressions found? SqlSource newSource = join; foreach (List <SqlColumn> cols in expressionSink.Lifted) { newSource = PushSourceDown(newSource, cols); } expressionSink = s; return(newSource); } return(base.VisitJoin(join)); }
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 <SqlAlias> p = SqlGatherProducedAliases.Gather(join.Left); HashSet <SqlAlias> c = SqlGatherConsumedAliases.Gather(join.Right); if (p.Overlaps(c)) { return(null); } return(join); }
internal override SqlSource VisitJoin(SqlJoin join) { if (join.JoinType == SqlJoinType.CrossApply) { // Look down the left side to see what table aliases are produced. HashSet <SqlAlias> p = SqlGatherProducedAliases.Gather(join.Left); // Look down the right side to see what table aliases are consumed. HashSet <SqlAlias> c = SqlGatherConsumedAliases.Gather(join.Right); // Look at each consumed alias and see if they are mentioned in produced. if (p.Overlaps(c)) { Annotations.Add(join, new SqlServerCompatibilityAnnotation(Strings.SourceExpressionAnnotation(join.SourceExpression), SqlProvider.ProviderMode.Sql2000)); // Can't reduce because this consumed alias is produced on the left. return(base.VisitJoin(join)); } // Can turn this into a CROSS JOIN join.JoinType = SqlJoinType.Cross; return(VisitJoin(join)); } return(base.VisitJoin(join)); }
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 HashSet <SqlAlias> leftProducedAliases = SqlGatherProducedAliases.Gather(join.Left); HashSet <SqlExpression> liftedExpressions = new HashSet <SqlExpression>(); 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 <List <SqlColumn> > liftedSelections = SqlSelectionLifter.Lift(join.Right, leftProducedAliases, liftedExpressions); join.JoinType = SqlJoinType.LeftOuter; join.Condition = liftedPredicate; if (liftedSelections != null) { foreach (List <SqlColumn> 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 <SqlAlias> leftProducedAliases = SqlGatherProducedAliases.Gather(join.Left); HashSet <SqlExpression> liftedExpressions = new HashSet <SqlExpression>(); 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 <List <SqlColumn> > liftedSelections = SqlSelectionLifter.Lift(leftOuter.Right, leftProducedAliases, liftedExpressions); // add intermediate selections this.GetSelectionsBeforeJoin(join.Right, liftedSelections); // push down all selections foreach (List <SqlColumn> 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 <List <SqlColumn> > liftedSelections = new List <List <SqlColumn> >(); // add intermediate selections this.GetSelectionsBeforeJoin(join.Left, liftedSelections); // push down all selections foreach (List <SqlColumn> 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); }