private SelectExpression ExtractOrders(SelectExpression sel, out List <OrderExpression> innerOrders) { if (sel.Top != null || (sel.OrderBy.Count == 0)) { innerOrders = null; return(sel); } else { ColumnGenerator cg = new ColumnGenerator(sel.Columns); Dictionary <OrderExpression, ColumnDeclaration> newColumns = sel.OrderBy.ToDictionary(o => o, o => cg.NewColumn(o.Expression)); innerOrders = newColumns.Select(kvp => new OrderExpression(kvp.Key.OrderType, kvp.Value.GetReference(sel.Alias))).ToList(); return(new SelectExpression(sel.Alias, sel.IsDistinct, sel.Top, sel.Columns.Concat(newColumns.Values), sel.From, sel.Where, null, sel.GroupBy, sel.SelectOptions)); } }
private ReadOnlyCollection <ColumnDeclaration> AnswerAndExpand(ReadOnlyCollection <ColumnDeclaration> columns, Alias currentAlias, Dictionary <ColumnExpression, Expression> askedColumns) { ColumnGenerator cg = new ColumnGenerator(columns); foreach (var col in askedColumns.Keys.ToArray()) { if (col.Alias == currentAlias) { Expression expr = columns.SingleEx(cd => (cd.Name ?? "-") == col.Name).Expression; askedColumns[col] = expr is SqlConstantExpression? expr: col; } else { Expression expr = CurrentScope[col]; ColumnExpression colExp = expr as ColumnExpression; if (colExp != null) { ColumnDeclaration cd = cg.Columns.FirstOrDefault(c => c.Expression.Equals(colExp)); if (cd == null) { cd = cg.MapColumn(colExp); } askedColumns[col] = new ColumnExpression(col.Type, currentAlias, cd.Name); } else { askedColumns[col] = expr; } } } if (columns.Count != cg.Columns.Count()) { return(cg.Columns.ToReadOnly()); } return(columns); }
private ReadOnlyCollection<ColumnDeclaration> AnswerAndExpand(ReadOnlyCollection<ColumnDeclaration> columns, Alias currentAlias, Dictionary<ColumnExpression, Expression> askedColumns) { ColumnGenerator cg = new ColumnGenerator(columns); foreach (var col in askedColumns.Keys.ToArray()) { if (col.Alias == currentAlias) { Expression expr = columns.SingleEx(cd => (cd.Name ?? "-") == col.Name).Expression; askedColumns[col] = expr.NodeType == (ExpressionType)DbExpressionType.SqlConstant? expr: col; } else { Expression expr = CurrentScope[col]; ColumnExpression colExp = expr as ColumnExpression; if (colExp != null) { ColumnDeclaration cd = cg.Columns.FirstOrDefault(c => c.Expression.Equals(colExp)); if (cd == null) { cd = cg.MapColumn(colExp); } askedColumns[col] = new ColumnExpression(col.Type, currentAlias, cd.Name); } else { askedColumns[col] = expr; } } } if (columns.Count != cg.Columns.Count()) return cg.Columns.ToReadOnly(); return columns; }
protected override Expression VisitProjection(ProjectionExpression proj) { if (currentSource == null) { currentSource = WithoutOrder(proj.Select); Expression projector = this.Visit(proj.Projector); if (projector != proj.Projector) proj = new ProjectionExpression(proj.Select, projector, proj.UniqueFunction, proj.Type); currentSource = null; return proj; } else { HashSet<ColumnExpression> columns = ExternalColumnGatherer.Gatherer(proj, currentSource.Alias); if (columns.Count == 0) { Expression projector = Visit(proj.Projector); ConstantExpression key = Expression.Constant(0); Type kvpType = typeof(KeyValuePair<,>).MakeGenericType(key.Type, projector.Type); ConstructorInfo ciKVP = kvpType.GetConstructor(new[] { key.Type, projector.Type }); Type projType = proj.UniqueFunction == null ? typeof(IEnumerable<>).MakeGenericType(kvpType) : kvpType; var childProj = new ProjectionExpression(proj.Select, Expression.New(ciKVP, key, projector), proj.UniqueFunction, projType); return new ChildProjectionExpression(childProj, Expression.Constant(0), inMList, proj.Type, new LookupToken()); } else { SelectExpression external; IEnumerable<ColumnExpression> externalColumns; if (!IsKey(currentSource, columns)) { Alias aliasDistinct = aliasGenerator.GetUniqueAlias(currentSource.Alias.Name + "D"); ColumnGenerator generatorDistinct = new ColumnGenerator(); List<ColumnDeclaration> columnDistinct = columns.Select(ce => generatorDistinct.MapColumn(ce)).ToList(); external = new SelectExpression(aliasDistinct, true, null, columnDistinct, currentSource, null, null, null, 0); Dictionary<ColumnExpression, ColumnExpression> distinctReplacements = columnDistinct.ToDictionary( cd => (ColumnExpression)cd.Expression, cd => cd.GetReference(aliasDistinct)); proj = (ProjectionExpression)ColumnReplacer.Replace(proj, distinctReplacements); externalColumns = distinctReplacements.Values.ToHashSet(); } else { external = currentSource; externalColumns = columns; } ColumnGenerator generatorSM = new ColumnGenerator(); List<ColumnDeclaration> columnsSMExternal = externalColumns.Select(ce => generatorSM.MapColumn(ce)).ToList(); List<ColumnDeclaration> columnsSMInternal = proj.Select.Columns.Select(cd => generatorSM.MapColumn(cd.GetReference(proj.Select.Alias))).ToList(); List<OrderExpression> innerOrders; SelectExpression @internal = ExtractOrders(proj.Select, out innerOrders); Alias aliasSM = aliasGenerator.GetUniqueAlias(@internal.Alias.Name + "SM"); SelectExpression selectMany = new SelectExpression(aliasSM, false, null, columnsSMExternal.Concat(columnsSMInternal), new JoinExpression(JoinType.CrossApply, external, @internal, null), null, innerOrders, null, 0); SelectExpression old = currentSource; currentSource = WithoutOrder(selectMany); var selectManyReplacements = selectMany.Columns.ToDictionary( cd => (ColumnExpression)cd.Expression, cd => cd.GetReference(aliasSM)); Expression projector = ColumnReplacer.Replace(proj.Projector, selectManyReplacements); projector = Visit(projector); currentSource = old; Expression key = TupleReflection.TupleChainConstructor(columnsSMExternal.Select(cd => cd.GetReference(aliasSM).Nullify())); Type kvpType = typeof(KeyValuePair<,>).MakeGenericType(key.Type, projector.Type); ConstructorInfo ciKVP = kvpType.GetConstructor(new[] { key.Type, projector.Type }); Type projType = proj.UniqueFunction == null ? typeof(IEnumerable<>).MakeGenericType(kvpType) : kvpType; var childProj = new ProjectionExpression(selectMany, Expression.New(ciKVP, key, projector), proj.UniqueFunction, projType); return new ChildProjectionExpression(childProj, TupleReflection.TupleChainConstructor(columns.Select(a => a.Nullify())), inMList, proj.Type, new LookupToken()); } } }
private SelectExpression ExtractOrders(SelectExpression sel, out List<OrderExpression> innerOrders) { if (sel.Top != null || (sel.OrderBy == null || sel.OrderBy.Count == 0)) { innerOrders = null; return sel; } else { ColumnGenerator cg = new ColumnGenerator(sel.Columns); Dictionary<OrderExpression, ColumnDeclaration> newColumns = sel.OrderBy.ToDictionary(o => o, o => cg.NewColumn(o.Expression)); innerOrders = newColumns.Select(kvp => new OrderExpression(kvp.Key.OrderType, kvp.Value.GetReference(sel.Alias))).ToList(); return new SelectExpression(sel.Alias, sel.IsDistinct, sel.Top, sel.Columns.Concat(newColumns.Values), sel.From, sel.Where, null, sel.GroupBy, sel.SelectOptions); } }
protected internal override Expression VisitProjection(ProjectionExpression proj) { if (currentSource == null) { currentSource = WithoutOrder(proj.Select); Expression projector = this.Visit(proj.Projector); if (projector != proj.Projector) { proj = new ProjectionExpression(proj.Select, projector, proj.UniqueFunction, proj.Type); } currentSource = null; return(proj); } else { HashSet <ColumnExpression> columns = ExternalColumnGatherer.Gatherer(proj, currentSource.Alias); if (columns.Count == 0) { Expression projector = Visit(proj.Projector); ConstantExpression key = Expression.Constant(0); Type kvpType = typeof(KeyValuePair <,>).MakeGenericType(key.Type, projector.Type); ConstructorInfo ciKVP = kvpType.GetConstructor(new[] { key.Type, projector.Type }); Type projType = proj.UniqueFunction == null ? typeof(IEnumerable <>).MakeGenericType(kvpType) : kvpType; var childProj = new ProjectionExpression(proj.Select, Expression.New(ciKVP, key, projector), proj.UniqueFunction, projType); return(new ChildProjectionExpression(childProj, Expression.Constant(0), inMList != null, inMList ?? proj.Type, new LookupToken())); } else { SelectExpression external; IEnumerable <ColumnExpression> externalColumns; if (!IsKey(currentSource, columns)) { Alias aliasDistinct = aliasGenerator.GetUniqueAlias(currentSource.Alias.Name + "D"); ColumnGenerator generatorDistinct = new ColumnGenerator(); List <ColumnDeclaration> columnDistinct = columns.Select(ce => generatorDistinct.MapColumn(ce)).ToList(); external = new SelectExpression(aliasDistinct, true, null, columnDistinct, currentSource, null, null, null, 0); Dictionary <ColumnExpression, ColumnExpression> distinctReplacements = columnDistinct.ToDictionary( cd => (ColumnExpression)cd.Expression, cd => cd.GetReference(aliasDistinct)); proj = (ProjectionExpression)ColumnReplacer.Replace(proj, distinctReplacements); externalColumns = distinctReplacements.Values.ToHashSet(); } else { external = currentSource; externalColumns = columns; } ColumnGenerator generatorSM = new ColumnGenerator(); List <ColumnDeclaration> columnsSMExternal = externalColumns.Select(ce => generatorSM.MapColumn(ce)).ToList(); List <ColumnDeclaration> columnsSMInternal = proj.Select.Columns.Select(cd => generatorSM.MapColumn(cd.GetReference(proj.Select.Alias))).ToList(); List <OrderExpression> innerOrders; SelectExpression @internal = ExtractOrders(proj.Select, out innerOrders); Alias aliasSM = aliasGenerator.GetUniqueAlias(@internal.Alias.Name + "SM"); SelectExpression selectMany = new SelectExpression(aliasSM, false, null, columnsSMExternal.Concat(columnsSMInternal), new JoinExpression(JoinType.CrossApply, external, @internal, null), null, innerOrders, null, 0); SelectExpression old = currentSource; currentSource = WithoutOrder(selectMany); var selectManyReplacements = selectMany.Columns.ToDictionary( cd => (ColumnExpression)cd.Expression, cd => cd.GetReference(aliasSM)); Expression projector = ColumnReplacer.Replace(proj.Projector, selectManyReplacements); projector = Visit(projector); currentSource = old; Expression key = TupleReflection.TupleChainConstructor(columnsSMExternal.Select(cd => cd.GetReference(aliasSM).Nullify())); Type kvpType = typeof(KeyValuePair <,>).MakeGenericType(key.Type, projector.Type); ConstructorInfo ciKVP = kvpType.GetConstructor(new[] { key.Type, projector.Type }); Type projType = proj.UniqueFunction == null ? typeof(IEnumerable <>).MakeGenericType(kvpType) : kvpType; var childProj = new ProjectionExpression(selectMany, Expression.New(ciKVP, key, projector), proj.UniqueFunction, projType); return(new ChildProjectionExpression(childProj, TupleReflection.TupleChainConstructor(columns.Select(a => a.Nullify())), inMList != null, inMList ?? proj.Type, new LookupToken())); } } }
protected internal override Expression VisitSelect(SelectExpression select) { bool isOuterMost = select == outerMostSelect; if (select.IsOrderAlsoByKeys || select.HasIndex || select.Top != null && hasProjectionInProjector) { if (gatheredKeys == null) { gatheredKeys = new List <ColumnExpression>(); } } List <ColumnExpression>?savedKeys = null; if (gatheredKeys != null && (select.IsDistinct || select.GroupBy.HasItems() || select.IsAllAggregates)) { savedKeys = gatheredKeys.ToList(); } if ((AggregateFinder.GetAggregates(select.Columns)?.Any(a => a.AggregateFunction.OrderMatters()) ?? false) && select.From is SelectExpression from) { var oldOuterMostSelect = outerMostSelect; outerMostSelect = from; select = (SelectExpression)base.VisitSelect(select); outerMostSelect = oldOuterMostSelect; } else { select = (SelectExpression)base.VisitSelect(select); } if (savedKeys != null) { gatheredKeys = savedKeys; } List <ColumnDeclaration>?newColumns = null; if (select.GroupBy.HasItems()) { gatheredOrderings = null; if (gatheredKeys != null) { ColumnGenerator cg = new ColumnGenerator(select.Columns); var newKeys = new List <ColumnDeclaration>(); foreach (var ge in select.GroupBy) { var cd = cg.Columns.NotNull().FirstOrDefault(a => DbExpressionComparer.AreEqual(a.Expression, ge)); if (cd != null) { newKeys.Add(cd); } else { newKeys.Add(cg.NewColumn(ge)); } } if (cg.Columns.Count() != select.Columns.Count) { newColumns = cg.Columns.NotNull().ToList(); } gatheredKeys.AddRange(newKeys.Select(cd => new ColumnExpression(cd.Expression.Type, select.Alias, cd.Name))); } } if (select.IsAllAggregates) { if (gatheredKeys != null) { gatheredKeys.AddRange(select.Columns.Select(cd => new ColumnExpression(cd.Expression.Type, select.Alias, cd.Name))); } } if (select.IsDistinct) { gatheredOrderings = null; if (gatheredKeys != null) { gatheredKeys.AddRange(select.Columns.Select(cd => cd.GetReference(select.Alias))); } } if (select.IsReverse && !gatheredOrderings.IsNullOrEmpty()) { gatheredOrderings = gatheredOrderings.Select(o => new OrderExpression( o.OrderType == OrderType.Ascending ? OrderType.Descending : OrderType.Ascending, o.Expression)).ToReadOnly(); } if (select.OrderBy.Count > 0) { this.PrependOrderings(select.OrderBy); } ReadOnlyCollection <OrderExpression>?orderings = null; if (isOuterMost && !IsCountSumOrAvg(select) || select.Top != null) { AppendKeys(); orderings = gatheredOrderings; gatheredOrderings = null; } if (AreEqual(select.OrderBy, orderings) && !select.IsReverse && newColumns == null) { return(select); } return(new SelectExpression(select.Alias, select.IsDistinct, select.Top, (IEnumerable <ColumnDeclaration>?)newColumns ?? select.Columns, select.From, select.Where, orderings, select.GroupBy, select.SelectOptions & ~SelectOptions.Reverse)); }
protected override Expression VisitSelect(SelectExpression select) { bool isOuterMost = select == outerMostSelect; if (select.IsOrderAlsoByKeys || select.HasIndex || select.Top != null && hasProjectionInProjector) { if (gatheredKeys == null) gatheredKeys = new List<ColumnExpression>(); } List<ColumnExpression> saveKeys = null; if (gatheredKeys != null && (select.IsDistinct || select.GroupBy.HasItems())) saveKeys = gatheredKeys.ToList(); select = (SelectExpression)base.VisitSelect(select); if (saveKeys != null) gatheredKeys = saveKeys; List<ColumnDeclaration> newColumns = null; if (select.GroupBy.HasItems()) { gatheredOrderings = null; if (gatheredKeys != null) { ColumnGenerator cg = new ColumnGenerator(select.Columns); var newKeys = new List<ColumnDeclaration>(); foreach (var ge in select.GroupBy) { var cd = cg.Columns.FirstOrDefault(a => DbExpressionComparer.AreEqual(a.Expression, ge)); if (cd != null) newKeys.Add(cd); else newKeys.Add(cg.NewColumn(ge)); } if (cg.Columns.Count() != select.Columns.Count) newColumns = cg.Columns.ToList(); gatheredKeys.AddRange(newKeys.Select(cd => new ColumnExpression(cd.Expression.Type, select.Alias, cd.Name))); } } if (select.IsDistinct) { gatheredOrderings = null; if (gatheredKeys != null) { gatheredKeys.AddRange(select.Columns.Select(cd => cd.GetReference(select.Alias))); } } if (select.IsReverse && !gatheredOrderings.IsNullOrEmpty()) gatheredOrderings = gatheredOrderings.Select(o => new OrderExpression( o.OrderType == OrderType.Ascending ? OrderType.Descending : OrderType.Ascending, o.Expression)).ToReadOnly(); if (select.OrderBy != null && select.OrderBy.Count > 0) this.PrependOrderings(select.OrderBy); ReadOnlyCollection<OrderExpression> orderings = null; if (isOuterMost && !IsCountSumOrAvg(select) || select.Top != null) { AppendKeys(); orderings = gatheredOrderings; gatheredOrderings = null; } if (AreEqual(select.OrderBy, orderings) && !select.IsReverse && newColumns == null) return select; return new SelectExpression(select.Alias, select.IsDistinct, select.Top, (IEnumerable<ColumnDeclaration>)newColumns ?? select.Columns, select.From, select.Where, orderings, select.GroupBy, select.SelectOptions & ~SelectOptions.Reverse); }