예제 #1
0
 protected internal override Expression VisitSelect(SelectExpression select)
 {
     this.aliases.Add(select.Alias);
     return(base.VisitSelect(select));
 }
예제 #2
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));
        }
예제 #3
0
        private bool IsKey(SelectExpression source, HashSet <ColumnExpression> columns)
        {
            var keys = KeyFinder.Keys(source);

            return(keys.All(k => k != null && columns.Contains(k)));
        }
예제 #4
0
        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();

                    SelectExpression @internal = ExtractOrders(proj.Select, out List <OrderExpression>?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 => MakeEquatable(cd.GetReference(aliasSM))));
                    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 => MakeEquatable(a))), inMList != null, inMList ?? proj.Type, new LookupToken()));
                }
            }
        }
예제 #5
0
 public ScalarExpression(Type type, SelectExpression select)
     : base(DbExpressionType.Scalar, type, select)
 {
 }
예제 #6
0
 public ExistsExpression(SelectExpression select)
     : base(DbExpressionType.Exists, typeof(bool), select)
 {
 }
예제 #7
0
 protected SubqueryExpression(DbExpressionType nodeType, Type type, SelectExpression select)
     : base(nodeType, type)
 {
     System.Diagnostics.Debug.Assert(nodeType == DbExpressionType.Scalar || nodeType == DbExpressionType.Exists || nodeType == DbExpressionType.In);
     this.Select = select;
 }
 static bool HasJoins(SelectExpression s)
 {
     return(s.From is JoinExpression || s.From is SelectExpression s2 && HasJoins(s2));
 }
예제 #9
0
        protected internal override Expression VisitSelect(SelectExpression select)
        {
            bool isFirst = sb.Length == 0;

            if (!isFirst)
            {
                AppendNewLine(Indentation.Inner);
                sb.Append('(');
            }

            sb.Append("SELECT ");
            if (select.IsDistinct)
            {
                sb.Append("DISTINCT ");
            }

            if (select.Top != null && !this.isPostgres)
            {
                sb.Append("TOP (");
                Visit(select.Top);
                sb.Append(") ");
            }

            if (select.Columns.Count == 0)
            {
                sb.Append("0 as Dummy");
            }
            else
            {
                this.AppendNewLine(Indentation.Inner);
                for (int i = 0, n = select.Columns.Count; i < n; i++)
                {
                    ColumnDeclaration column = select.Columns[i];
                    AppendColumn(column);
                    if (i < (n - 1))
                    {
                        sb.Append(", ");
                        this.AppendNewLine(Indentation.Same);
                    }
                    else
                    {
                        this.Indent(Indentation.Outer);
                    }
                }
            }

            if (select.From != null)
            {
                this.AppendNewLine(Indentation.Same);
                sb.Append("FROM ");
                this.VisitSource(select.From);
            }
            if (select.Where != null)
            {
                this.AppendNewLine(Indentation.Same);
                sb.Append("WHERE ");
                this.Visit(select.Where);
            }
            if (select.GroupBy.Count > 0)
            {
                this.AppendNewLine(Indentation.Same);
                sb.Append("GROUP BY ");
                for (int i = 0, n = select.GroupBy.Count; i < n; i++)
                {
                    Expression exp = select.GroupBy[i];
                    if (i > 0)
                    {
                        sb.Append(", ");
                    }
                    this.Visit(exp);
                }
            }
            if (select.OrderBy.Count > 0)
            {
                this.AppendNewLine(Indentation.Same);
                sb.Append("ORDER BY ");
                for (int i = 0, n = select.OrderBy.Count; i < n; i++)
                {
                    OrderExpression exp = select.OrderBy[i];
                    if (i > 0)
                    {
                        sb.Append(", ");
                    }
                    this.Visit(exp.Expression);
                    if (exp.OrderType != OrderType.Ascending)
                    {
                        sb.Append(" DESC");
                    }
                }
            }

            if (select.Top != null && this.isPostgres)
            {
                this.AppendNewLine(Indentation.Same);
                sb.Append("LIMIT ");
                Visit(select.Top);
            }

            if (select.IsForXmlPathEmpty)
            {
                this.AppendNewLine(Indentation.Same);
                sb.Append("FOR XML PATH('')");
            }

            if (!isFirst)
            {
                sb.Append(')');
                AppendNewLine(Indentation.Outer);
            }

            return(select);
        }
 internal static bool IsInitialProjection(SelectExpression select)
 {
     return(select.From is TableExpression);
 }
예제 #11
0
            static bool CanMergeWithFrom(SelectExpression select, bool isTopLevel)
            {
                SelectExpression?fromSelect = GetLeftMostSelect(select.From !);

                if (fromSelect == null)
                {
                    return(false);
                }

                if (!IsColumnProjection(fromSelect))
                {
                    return(false);
                }

                bool selHasOrderBy = select.OrderBy.Count > 0;
                bool selHasGroupBy = select.GroupBy.Count > 0;

                bool frmHasOrderBy = fromSelect.OrderBy.Count > 0;
                bool frmHasGroupBy = fromSelect.GroupBy.Count > 0;

                // both cannot have orderby
                if (selHasOrderBy && frmHasOrderBy)
                {
                    return(false);
                }
                // both cannot have groupby
                if (selHasGroupBy && frmHasGroupBy)
                {
                    return(false);
                }
                // this are distinct operations
                if (select.IsReverse || fromSelect.IsReverse)
                {
                    return(false);
                }

                // cannot move forward order-by if outer has group-by
                if (frmHasOrderBy && (selHasGroupBy || select.IsDistinct || AggregateChecker.HasAggregates(select)))
                {
                    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.Top != null && (select.Top != null || /*select.Skip != null ||*/ select.IsDistinct || selHasGroupBy || HasApplyJoin(select.From !) || select.Where != null))
                {
                    return(false);
                }
                // cannot move forward a skip if outer has skip or distinct
                //if (fromSelect.Skip != null && (select.Skip != null || select.Distinct || selHasAggregates || selHasGroupBy))
                //    return false;
                // cannot move forward a distinct if outer has take, skip, groupby or a different projection
                if (fromSelect.IsDistinct && (select.Top != null || /*select.Skip != null ||*/ !IsNameMapProjection(select) || selHasGroupBy || (selHasOrderBy && !isTopLevel) || AggregateChecker.HasAggregates(select)))
                {
                    return(false);
                }
                return(true);
            }