public static HashSet <ColumnExpression> Gather(HashSet <TableAlias> aliases, SelectExpression select) { var gatherer = new JoinColumnGatherer(aliases); gatherer.Gather(select.Where); return(gatherer.columns); }
protected override Expression VisitProjection(ProjectionExpression proj) { SelectExpression save = this.currentSelect; this.currentSelect = proj.Select; try { if (!this.isTopLevel) { if (this.CanJoinOnClient(this.currentSelect)) { // make a query that combines all the constraints from the outer queries into a single select SelectExpression newOuterSelect = (SelectExpression)QueryDuplicator.Duplicate(save); // remap any references to the outer select to the new alias; SelectExpression newInnerSelect = (SelectExpression)ColumnMapper.Map(proj.Select, newOuterSelect.Alias, save.Alias); // add outer-join test ProjectionExpression newInnerProjection = this.language.AddOuterJoinTest(new ProjectionExpression(newInnerSelect, proj.Projector)); newInnerSelect = newInnerProjection.Select; Expression newProjector = newInnerProjection.Projector; TableAlias newAlias = new TableAlias(); var pc = ColumnProjector.ProjectColumns(this.language, newProjector, null, newAlias, newOuterSelect.Alias, newInnerSelect.Alias); JoinExpression join = new JoinExpression(JoinType.OuterApply, newOuterSelect, newInnerSelect, null); SelectExpression joinedSelect = new SelectExpression(newAlias, pc.Columns, join, null, null, null, proj.IsSingleton, null, null, false); // apply client-join treatment recursively this.currentSelect = joinedSelect; newProjector = this.Visit(pc.Projector); // compute keys (this only works if join condition was a single column comparison) List <Expression> outerKeys = new List <Expression>(); List <Expression> innerKeys = new List <Expression>(); if (this.GetEquiJoinKeyExpressions(newInnerSelect.Where, newOuterSelect.Alias, outerKeys, innerKeys)) { // outerKey needs to refer to the outer-scope's alias var outerKey = outerKeys.Select(k => ColumnMapper.Map(k, save.Alias, newOuterSelect.Alias)); // innerKey needs to refer to the new alias for the select with the new join var innerKey = innerKeys.Select(k => ColumnMapper.Map(k, joinedSelect.Alias, ((ColumnExpression)k).Alias)); ProjectionExpression newProjection = new ProjectionExpression(joinedSelect, newProjector, proj.Aggregator); return(new ClientJoinExpression(newProjection, outerKey, innerKey)); } } else { bool saveJoin = this.canJoinOnClient; this.canJoinOnClient = false; var result = base.VisitProjection(proj); this.canJoinOnClient = saveJoin; return(result); } } else { this.isTopLevel = false; } return(base.VisitProjection(proj)); } finally { this.currentSelect = save; } }
protected override Expression VisitSelect(SelectExpression select) { bool saveIsOuterMostSelect = this.isOuterMostSelect; try { this.isOuterMostSelect = false; select = (SelectExpression)base.VisitSelect(select); bool hasOrderBy = select.OrderBy != null && select.OrderBy.Count > 0; bool hasGroupBy = select.GroupBy != null && select.GroupBy.Count > 0; bool canHaveOrderBy = saveIsOuterMostSelect || select.Take != null || select.Skip != null; bool canReceiveOrderings = canHaveOrderBy && !hasGroupBy && !select.IsDistinct && !AggregateChecker.HasAggregates(select); if (hasOrderBy) { this.PrependOrderings(select.OrderBy); } if (select.IsReverse) { this.ReverseOrderings(); } IEnumerable <OrderExpression> orderings = null; if (canReceiveOrderings) { orderings = this.gatheredOrderings; } else if (canHaveOrderBy) { orderings = select.OrderBy; } bool canPassOnOrderings = !saveIsOuterMostSelect && !hasGroupBy && !select.IsDistinct; ReadOnlyCollection <ColumnDeclaration> columns = select.Columns; if (this.gatheredOrderings != null) { if (canPassOnOrderings) { var producedAliases = DeclaredAliasGatherer.Gather(select.From); // reproject order expressions using this select's alias so the outer select will have properly formed expressions BindResult project = this.RebindOrderings(this.gatheredOrderings, select.Alias, producedAliases, select.Columns); this.gatheredOrderings = null; this.PrependOrderings(project.Orderings); columns = project.Columns; } else { this.gatheredOrderings = null; } } if (orderings != select.OrderBy || columns != select.Columns || select.IsReverse) { select = new SelectExpression(select.Alias, columns, select.From, select.Where, orderings, select.GroupBy, select.IsDistinct, select.Skip, select.Take, false); } return(select); } finally { this.isOuterMostSelect = saveIsOuterMostSelect; } }
public static SelectExpression SetColumns(this SelectExpression select, IEnumerable <ColumnDeclaration> columns) { return(new SelectExpression(select.Alias, columns.OrderBy(c => c.Name), select.From, select.Where, select.OrderBy, select.GroupBy, select.IsDistinct, select.Skip, select.Take, select.IsReverse)); }
public static SelectExpression SetGroupBy(this SelectExpression select, IEnumerable <Expression> groupBy) { return(new SelectExpression(select.Alias, select.Columns, select.From, select.Where, select.OrderBy, groupBy, select.IsDistinct, select.Skip, select.Take, select.IsReverse)); }
protected override Expression VisitProjection(ProjectionExpression proj) { SelectExpression select = (SelectExpression)this.Visit(proj.Select); return(this.UpdateProjection(proj, select, proj.Projector, proj.Aggregator)); }