Beispiel #1
0
		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;
			}
Beispiel #2
0
 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;
		}
Beispiel #5
0
		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;
			}
Beispiel #6
0
 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;
		}
Beispiel #24
0
 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;
		}
Beispiel #26
0
		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);
		}
Beispiel #27
0
		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);
		}