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);
        }
Example #3
0
        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()));
                }
            }
        }
Example #7
0
        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));
        }
Example #8
0
        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);
        }