internal SqlJoin(SqlJoinType type, SqlSource left, SqlSource right, SqlExpression cond, Expression sourceExpression) : base(SqlNodeType.Join, sourceExpression) { this.JoinType = type; this.Left = left; this.Right = right; this.Condition = cond; }
internal static bool CanLift(SqlSource source, HashSet<SqlAlias> aliasesForLifting, HashSet<SqlExpression> liftedExpressions) { Diagnostics.Debug.Assert(source != null); Diagnostics.Debug.Assert(aliasesForLifting != null); PredicateLifter v = new PredicateLifter(false, aliasesForLifting, liftedExpressions); v.VisitSource(source); return v.CanLiftAll; }
internal static SqlExpression Lift(SqlSource source, HashSet<SqlAlias> aliasesForLifting) { Diagnostics.Debug.Assert(source != null); Diagnostics.Debug.Assert(aliasesForLifting != null); PredicateLifter v = new PredicateLifter(true, aliasesForLifting, null); v.VisitSource(source); return v.Lifted; }
internal SqlSelect(SqlExpression selection, SqlSource from, Expression sourceExpression) : base(SqlNodeType.Select, sourceExpression) { this.Row = new SqlRow(sourceExpression); this.Selection = selection; this.From = from; this.groupBy = new List<SqlExpression>(); this.orderBy = new List<SqlOrderExpression>(); this.orderingType = SqlOrderingType.Default; }
internal SqlSelect(SqlExpression selection, SqlSource from, Expression sourceExpression) : base(SqlNodeType.Select, sourceExpression) { this.Row = new SqlRow(sourceExpression); this.Selection = selection; this.From = from; this.groupBy = new List <SqlExpression>(); this.orderBy = new List <SqlOrderExpression>(); this.orderingType = SqlOrderingType.Default; }
private SqlUnion GetUnion(SqlSource source) { SqlAlias alias = source as SqlAlias; if(alias != null) { SqlUnion union = alias.Node as SqlUnion; if(union != null) return union; } return null; }
internal override SqlSource VisitSource(SqlSource node) { node = (SqlSource)this.Visit(node); SqlAlias alias = node as SqlAlias; if(alias != null) { SqlSelect sel = alias.Node as SqlSelect; if(sel != null && this.IsTrivialSelect(sel)) { _removedMap[alias] = alias; node = sel.From; } } return node; }
private bool HasEmptySource(SqlSource node) { SqlAlias alias = node as SqlAlias; if(alias == null) return false; SqlSelect sel = alias.Node as SqlSelect; if(sel == null) return false; return sel.Row.Columns.Count == 0 && sel.From == null && sel.Where == null && sel.GroupBy.Count == 0 && sel.Having == null && sel.OrderBy.Count == 0; }
private bool HasTrivialSource(SqlSource node) { SqlAlias alias = node as SqlAlias; if(alias == null) return false; return alias.Node is SqlSelect; }
internal void VisitJoinSource(SqlSource src) { if(src.NodeType == SqlNodeType.Join) { _depth++; _commandStringBuilder.Append("("); this.Visit(src); _commandStringBuilder.Append(")"); _depth--; } else { this.Visit(src); } }
private bool HasTrivialSource(SqlSource node) { SqlJoin join = node as SqlJoin; if(@join != null) { return this.HasTrivialSource(@join.Left) && this.HasTrivialSource(@join.Right); } return node is SqlAlias; }
static internal List<SqlColumn> GatherColumns(SqlSource source) { List<SqlColumn> columns = new List<SqlColumn>(); new ProducedColumnsGatherer(columns).Visit(source); return columns; }
internal override SqlSource VisitSource(SqlSource source) { return source; }
private SqlSelect GetSourceSelect(SqlSource source) { SqlAlias alias = source as SqlAlias; if (alias == null) { return null; } return alias.Node as SqlSelect; }
internal void BuildEqivalenceMap(SqlSource scope) { this._map = new Dictionary<SqlColumn, SqlColumn>(); this.Visit(scope); }
// insert new join closest to the aliases it depends on private bool IsOuterDependent(bool isOuterDependent, SqlSource location, HashSet<SqlAlias> consumed, out HashSet<SqlAlias> produced) { if (location.NodeType == SqlNodeType.Join) { // walk down join tree looking for best location for join SqlJoin join = (SqlJoin)location; if (this.IsOuterDependent(isOuterDependent, @join.Left, consumed, out produced)) return true; HashSet<SqlAlias> rightProduced; bool rightIsOuterDependent = @join.JoinType == SqlJoinType.LeftOuter || @join.JoinType == SqlJoinType.OuterApply; if (this.IsOuterDependent(rightIsOuterDependent, @join.Right, consumed, out rightProduced)) return true; produced.UnionWith(rightProduced); } else { SqlAlias a = location as SqlAlias; if (a != null) { SqlSelect s = a.Node as SqlSelect; if (s != null && !isOuterDependent && s.From != null) { if (this.IsOuterDependent(false, s.From, consumed, out produced)) return true; } } produced = SqlGatherProducedAliases.Gather(location); } // look to see if this subtree fully satisfies join condition if (consumed.IsSubsetOf(produced)) { return isOuterDependent; } return false; }
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 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 { #warning [FB] REFACTOR: SQL SERVER SPECIFIC: MOVE TO A CTOR PROVIDED SET OF INCOMPATIBLE MODES. this.AnnotateSqlIncompatibility(join, SqlServerProviderMode.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 { #warning [FB] REFACTOR: SQL SERVER SPECIFIC: MOVE TO A CTOR PROVIDED SET OF INCOMPATIBLE MODES. this.AnnotateSqlIncompatibility(join, SqlServerProviderMode.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; }
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; }
private void GetSelectionsBeforeJoin(SqlSource source, List<List<SqlColumn>> 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); } } }
internal static List<List<SqlColumn>> Lift(SqlSource source, HashSet<SqlAlias> aliasesForLifting, HashSet<SqlExpression> liftedExpressions) { SelectionLifter v = new SelectionLifter(true, aliasesForLifting, liftedExpressions); v.VisitSource(source); return v.Lifted; }
// insert new join in an appropriate location within an existing join tree private bool IsOuterDependent(SqlSource location, SqlAlias alias, SqlExpression where) { HashSet<SqlAlias> consumed = SqlGatherConsumedAliases.Gather(@where); consumed.ExceptWith(SqlGatherProducedAliases.Gather(alias)); HashSet<SqlAlias> produced; if (this.IsOuterDependent(false, location, consumed, out produced)) return true; return false; }
internal virtual SqlSource VisitSource(SqlSource source) { return (SqlSource) this.Visit(source); }
internal static bool CanLift(SqlSource source, HashSet<SqlAlias> aliasesForLifting, HashSet<SqlExpression> liftedExpressions) { SelectionLifter v = new SelectionLifter(false, aliasesForLifting, liftedExpressions); v.VisitSource(source); return v.CanLiftAll; }
private SqlSource PushSourceDown(SqlSource sqlSource, List<SqlColumn> 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); }
internal SqlJoin MakeJoin(SqlJoinType joinType, SqlSource location, SqlAlias alias, SqlExpression condition, Expression source) { // if the new item is on the right side of some outer join then fixup the projection to reflect that it can possibly be null if(joinType == SqlJoinType.LeftOuter) { SqlSelect sel = alias.Node as SqlSelect; if(sel != null && sel.Selection != null && sel.Selection.NodeType != SqlNodeType.OptionalValue) { // replace selection w/ optional + outer-joined-value sel.Selection = new SqlOptionalValue( new SqlColumn( "test", this.Unary(SqlNodeType.OuterJoinedValue, this.Value(typeof(int?), this.typeProvider.From(typeof(int)), 1, false, source)) ), sel.Selection ); } } return new SqlJoin(joinType, location, alias, condition, source); }