public ProjectionExpression(SelectExpression source, Expression projector, LambdaExpression aggregator) : base(DbExpressionType.Projection, aggregator != null ? aggregator.Body.Type : typeof(IEnumerable<>).MakeGenericType(projector.Type)) { this.select = source; this.projector = projector; this.aggregator = aggregator; }
protected override Expression VisitSelect(SelectExpression select) { IdentifiableAlias newAlias = new IdentifiableAlias(); this.map[select.Alias] = newAlias; select = (SelectExpression)base.VisitSelect(select); return new SelectExpression(newAlias, select.Fields, select.From, select.Where, select.OrderBy, select.GroupBy, select.IsDistinct, select.Skip, select.Take, select.IsReverse); }
protected override Expression VisitSelect(SelectExpression select) { Expression saveCurrentFrom = this.currentFrom; this.currentFrom = this.VisitSource(select.From); try { Expression where = this.Visit(select.Where); ReadOnlyCollection<OrderExpression> orderBy = this.VisitOrderBy(select.OrderBy); ReadOnlyCollection<Expression> groupBy = this.VisitExpressionList(select.GroupBy); Expression skip = this.Visit(select.Skip); Expression take = this.Visit(select.Take); ReadOnlyCollection<FieldDeclaration> Fields = this.VisitFieldDeclarations(select.Fields); if (this.currentFrom != select.From || where != select.Where || orderBy != select.OrderBy || groupBy != select.GroupBy || take != select.Take || skip != select.Skip || Fields != select.Fields ) { return new SelectExpression(select.Alias, Fields, this.currentFrom, where, orderBy, groupBy, select.IsDistinct, skip, take, select.IsReverse); } return select; } finally { this.currentFrom = saveCurrentFrom; } }
protected DeclarationCommand UpdateDeclaration(DeclarationCommand decl, IEnumerable<VariableDeclaration> variables, SelectExpression source) { if (variables != decl.Variables || source != decl.Source) { return new DeclarationCommand(variables, source); } return decl; }
protected override Expression VisitSelect(SelectExpression select) { // only consider aggregates in these locations this.Visit(select.Where); this.VisitOrderBy(select.OrderBy); this.VisitFieldDeclarations(select.Fields); return select; }
public static SelectExpression AddRedundantSelect(this SelectExpression sel, QueryLanguage language, IdentifiableAlias newAlias) { var newFields = from d in sel.Fields let qt = (d.Expression is FieldExpression) ? ((FieldExpression)d.Expression).QueryType : language.TypeSystem.GetStorageType(d.Expression.Type) select new FieldDeclaration(d.Name, new FieldExpression(d.Expression.Type, qt, newAlias, d.Name), qt); var newFrom = new SelectExpression(newAlias, sel.Fields, sel.From, sel.Where, sel.OrderBy, sel.GroupBy, sel.IsDistinct, sel.Skip, sel.Take, sel.IsReverse); return new SelectExpression(sel.Alias, newFields, newFrom, null, null, null, false, null, null, false); }
protected override Expression VisitSelect(SelectExpression select) { if (this.selectsToRemove.Contains(select)) { return this.Visit(select.From); } else { return base.VisitSelect(select); } }
internal static bool IsSimpleProjection(SelectExpression select) { foreach (FieldDeclaration decl in select.Fields) { FieldExpression col = decl.Expression as FieldExpression; if (col == null || decl.Name != col.Name) { return false; } } return true; }
protected override Expression VisitClientJoin(ClientJoinExpression join) { // treat client joins as new top level var saveTop = this.isTopLevel; var saveSelect = this.currentSelect; this.isTopLevel = true; this.currentSelect = null; Expression result = base.VisitClientJoin(join); this.isTopLevel = saveTop; this.currentSelect = saveSelect; return result; }
protected override Expression VisitSelect(SelectExpression select) { select = (SelectExpression)base.VisitSelect(select); // first remove all purely redundant subqueries List<SelectExpression> redundant = RedundantSubqueryGatherer.Gather(select.From); if (redundant != null) { select = SubqueryRemover.Remove(select, redundant); } return select; }
internal static bool IsNameMapProjection(SelectExpression select) { if (select.From is IdentifiableExpression) return false; SelectExpression fromSelect = select.From as SelectExpression; if (fromSelect == null || select.Fields.Count != fromSelect.Fields.Count) return false; ReadOnlyCollection<FieldDeclaration> fromFields = fromSelect.Fields; // test that all fields in 'select' are refering to fields in the same position // in from. for (int i = 0, n = select.Fields.Count; i < n; i++) { FieldExpression col = select.Fields[i].Expression as FieldExpression; if (col == null || !(col.Name == fromFields[i].Name)) return false; } return true; }
protected override Expression VisitSelect(SelectExpression select) { select = (SelectExpression)base.VisitSelect(select); if (lookup.Contains(select.Alias)) { List<FieldDeclaration> aggFields = new List<FieldDeclaration>(select.Fields); foreach (AggregateSubqueryExpression ae in lookup[select.Alias]) { string name = "agg" + aggFields.Count; var colType = this.language.TypeSystem.GetStorageType(ae.Type); FieldDeclaration cd = new FieldDeclaration(name, ae.AggregateInGroupSelect, colType); this.map.Add(ae, new FieldExpression(ae.Type, colType, ae.GroupByAlias, name)); aggFields.Add(cd); } return new SelectExpression(select.Alias, aggFields, select.From, select.Where, select.OrderBy, select.GroupBy, select.IsDistinct, select.Skip, select.Take, select.IsReverse); } return select; }
protected override Expression VisitSelect(SelectExpression select) { var saveWhere = this.currentWhere; try { this.currentWhere = select.Where; var result = (SelectExpression)base.VisitSelect(select); if (this.currentWhere != result.Where) { return result.SetWhere(this.currentWhere); } return result; } finally { this.currentWhere = saveWhere; } }
protected override Expression VisitSelect(SelectExpression select) { select = (SelectExpression)base.VisitSelect(select); // look for redundant field declarations List<FieldDeclaration> cols = select.Fields.OrderBy(c => c.Name).ToList(); BitArray removed = new BitArray(select.Fields.Count); bool anyRemoved = false; for (int i = 0, n = cols.Count; i < n - 1; i++) { FieldDeclaration ci = cols[i]; FieldExpression cix = ci.Expression as FieldExpression; StorageType qt = cix != null ? cix.QueryType : ci.QueryType; FieldExpression cxi = new FieldExpression(ci.Expression.Type, qt, select.Alias, ci.Name); for (int j = i + 1; j < n; j++) { if (!removed.Get(j)) { FieldDeclaration cj = cols[j]; if (SameExpression(ci.Expression, cj.Expression)) { // any reference to 'j' should now just be a reference to 'i' FieldExpression cxj = new FieldExpression(cj.Expression.Type, qt, select.Alias, cj.Name); this.map.Add(cxj, cxi); removed.Set(j, true); anyRemoved = true; } } } } if (anyRemoved) { List<FieldDeclaration> newDecls = new List<FieldDeclaration>(); for (int i = 0, n = cols.Count; i < n; i++) { if (!removed.Get(i)) { newDecls.Add(cols[i]); } } select = select.SetFields(newDecls); } return select; }
protected override Expression VisitProjection(ProjectionExpression proj) { if (isTopLevel) { isTopLevel = false; this.currentSelect = proj.Select; Expression projector = this.Visit(proj.Projector); if (projector != proj.Projector || this.currentSelect != proj.Select) { return new ProjectionExpression(this.currentSelect, projector, proj.Aggregator); } return proj; } if (proj.IsSingleton && this.CanJoinOnServer(this.currentSelect)) { IdentifiableAlias newAlias = new IdentifiableAlias(); this.currentSelect = this.currentSelect.AddRedundantSelect(this.language, newAlias); // remap any references to the outer select to the new alias; SelectExpression source = (SelectExpression)FieldMapper.Map(proj.Select, newAlias, this.currentSelect.Alias); // add outer-join test ProjectionExpression pex = this.language.AddOuterJoinTest(new ProjectionExpression(source, proj.Projector)); var pc = FieldProjector.ProjectFields(this.language, pex.Projector, this.currentSelect.Fields, this.currentSelect.Alias, newAlias, proj.Select.Alias); JoinExpression join = new JoinExpression(JoinType.OuterApply, this.currentSelect.From, pex.Select, null); this.currentSelect = new SelectExpression(this.currentSelect.Alias, pc.Fields, join, null); return this.Visit(pc.Projector); } var saveTop = this.isTopLevel; var saveSelect = this.currentSelect; this.isTopLevel = true; this.currentSelect = null; Expression result = base.VisitProjection(proj); this.isTopLevel = saveTop; this.currentSelect = saveSelect; return result; }
protected override Expression VisitSelect(SelectExpression select) { var from = this.VisitSource(select.From); var where = this.Visit(select.Where); var orderBy = this.VisitOrderBy(select.OrderBy); var groupBy = this.VisitExpressionList(select.GroupBy); var skip = this.Visit(select.Skip); var take = this.Visit(select.Take); var fields = this.VisitFieldDeclarations(select.Fields); select = this.UpdateSelect(select, from, where, orderBy, groupBy, skip, take, select.IsDistinct, select.IsReverse, fields); // first remove all purely redundant subqueries List<SelectExpression> redundant = ORedundantSubqueryGatherer.Gather(select.From); if (redundant != null) { select = OSubqueryRemover.Remove(select, redundant); } return select; }
protected override Expression VisitSelect(SelectExpression select) { if (!_visited) { _visited = true; if (select.Take == null) { Expression take = Visit(Expression.Constant(Policy.Limit)); select = new SelectExpression( select.Alias, select.Fields, select.From, select.Where, select.OrderBy, select.GroupBy, select.IsDistinct, select.Skip, take, select.IsReverse); } } return select; }
protected InExpression UpdateIn(InExpression @in, Expression expression, SelectExpression select, IEnumerable<Expression> values) { if (expression != @in.Expression || select != @in.Select || values != @in.Values) { if (select != null) { return new InExpression(expression, select); } else { return new InExpression(expression, values); } } return @in; }
protected ExistsExpression UpdateExists(ExistsExpression exists, SelectExpression select) { if (select != exists.Select) { return new ExistsExpression(select); } return exists; }
protected ProjectionExpression UpdateProjection(ProjectionExpression proj, SelectExpression select, Expression projector, LambdaExpression aggregator) { if (select != proj.Select || projector != proj.Projector || aggregator != proj.Aggregator) { return new ProjectionExpression(select, projector, aggregator); } return proj; }
protected SelectExpression UpdateSelect( SelectExpression select, Expression from, Expression where, IEnumerable<OrderExpression> orderBy, IEnumerable<Expression> groupBy, Expression skip, Expression take, bool isDistinct, bool isReverse, IEnumerable<FieldDeclaration> fields ) { if (from != select.From || where != select.Where || orderBy != select.OrderBy || groupBy != select.GroupBy || take != select.Take || skip != select.Skip || isDistinct != select.IsDistinct || fields != select.Fields || isReverse != select.IsReverse ) { return new SelectExpression(select.Alias, fields, from, where, orderBy, groupBy, isDistinct, skip, take, isReverse); } return select; }
internal static bool IsInitialProjection(SelectExpression select) { return select.From is IdentifiableExpression; }
protected ScalarExpression UpdateScalar(ScalarExpression scalar, SelectExpression select) { if (select != scalar.Select) { return new ScalarExpression(scalar.Type, select); } return scalar; }
private static bool IsRedudantSubquery(SelectExpression select) { return (IsSimpleProjection(select) || IsNameMapProjection(select)) && !select.IsDistinct && !select.IsReverse && select.Take == null && select.Skip == null && select.Where == null && (select.OrderBy == null || select.OrderBy.Count == 0) && (select.GroupBy == null || select.GroupBy.Count == 0); }
protected virtual Expression VisitSelect(SelectExpression select) { var from = this.VisitSource(select.From); var where = this.Visit(select.Where); var orderBy = this.VisitOrderBy(select.OrderBy); var groupBy = this.VisitExpressionList(select.GroupBy); var skip = this.Visit(select.Skip); var take = this.Visit(select.Take); var fields = this.VisitFieldDeclarations(select.Fields); return this.UpdateSelect(select, from, where, orderBy, groupBy, skip, take, select.IsDistinct, select.IsReverse, fields); }
protected override Expression VisitSelect(SelectExpression select) { bool wasTopLevel = isTopLevel; isTopLevel = false; select = (SelectExpression)base.VisitSelect(select); // next attempt to merge subqueries that would have been removed by the above // logic except for the existence of a where clause while (CanMergeWithFrom(select, wasTopLevel)) { SelectExpression fromSelect = GetLeftMostSelect(select.From); // remove the redundant subquery select = SubqueryRemover.Remove(select, fromSelect); // merge where expressions Expression where = select.Where; if (fromSelect.Where != null) { if (where != null) { where = fromSelect.Where.And(where); } else { where = fromSelect.Where; } } var orderBy = select.OrderBy != null && select.OrderBy.Count > 0 ? select.OrderBy : fromSelect.OrderBy; var groupBy = select.GroupBy != null && select.GroupBy.Count > 0 ? select.GroupBy : fromSelect.GroupBy; Expression skip = select.Skip != null ? select.Skip : fromSelect.Skip; Expression take = select.Take != null ? select.Take : fromSelect.Take; bool isDistinct = select.IsDistinct | fromSelect.IsDistinct; if (where != select.Where || orderBy != select.OrderBy || groupBy != select.GroupBy || isDistinct != select.IsDistinct || skip != select.Skip || take != select.Take) { select = new SelectExpression(select.Alias, select.Fields, select.From, where, orderBy, groupBy, isDistinct, skip, take, select.IsReverse); } } return select; }
public ScalarExpression(Type type, SelectExpression select) : base(DbExpressionType.Scalar, type, select) { }
private static bool CanMergeWithFrom(SelectExpression select, bool isTopLevel) { SelectExpression fromSelect = GetLeftMostSelect(select.From); if (fromSelect == null) return false; if (!IsFieldProjection(fromSelect)) return false; bool selHasNameMapProjection = IsNameMapProjection(select); bool selHasOrderBy = select.OrderBy != null && select.OrderBy.Count > 0; bool selHasGroupBy = select.GroupBy != null && select.GroupBy.Count > 0; bool selHasAggregates = AggregateChecker.HasAggregates(select); bool selHasJoin = select.From is JoinExpression; bool frmHasOrderBy = fromSelect.OrderBy != null && fromSelect.OrderBy.Count > 0; bool frmHasGroupBy = fromSelect.GroupBy != null && fromSelect.GroupBy.Count > 0; bool frmHasAggregates = AggregateChecker.HasAggregates(fromSelect); // both cannot have orderby if (selHasOrderBy && frmHasOrderBy) return false; // both cannot have groupby if (selHasGroupBy && frmHasGroupBy) return false; // these are distinct operations if (select.IsReverse || fromSelect.IsReverse) return false; // cannot move forward order-by if outer has group-by if (frmHasOrderBy && (selHasGroupBy || selHasAggregates || select.IsDistinct)) return false; // cannot move forward group-by if outer has where clause if (frmHasGroupBy /*&& (select.Where != null)*/) // need to assert projection is the same in order to move group-by forward return false; // cannot move forward a take if outer has take or skip or distinct if (fromSelect.Take != null && (select.Take != null || select.Skip != null || select.IsDistinct || selHasAggregates || selHasGroupBy || selHasJoin)) return false; // cannot move forward a skip if outer has skip or distinct if (fromSelect.Skip != null && (select.Skip != null || select.IsDistinct || selHasAggregates || selHasGroupBy || selHasJoin)) return false; // cannot move forward a distinct if outer has take, skip, groupby or a different projection if (fromSelect.IsDistinct && (select.Take != null || select.Skip != null || !selHasNameMapProjection || selHasGroupBy || selHasAggregates || (selHasOrderBy && !isTopLevel) || selHasJoin)) return false; if (frmHasAggregates && (select.Take != null || select.Skip != null || select.IsDistinct || selHasAggregates || selHasGroupBy || selHasJoin)) return false; return true; }
public ExistsExpression(SelectExpression select) : base(DbExpressionType.Exists, typeof(bool), select) { }
private static bool IsFieldProjection(SelectExpression select) { for (int i = 0, n = select.Fields.Count; i < n; i++) { var cd = select.Fields[i]; if (cd.Expression.NodeType != (ExpressionType)DbExpressionType.Field && cd.Expression.NodeType != ExpressionType.Constant) return false; } return true; }