예제 #1
0
 internal ProjectionExpression(SelectExpression source, Expression projector, LambdaExpression aggregator)
     : base(PigExpressionType.Projection, aggregator != null ? aggregator.Body.Type : typeof(IEnumerable<>).MakeGenericType(projector.Type))
 {
     Source = source;
     Projector = projector;
     Aggregator = aggregator;
 }
예제 #2
0
        protected override Expression VisitSelect(SelectExpression node)
        {
            // visit column projection first
            ReadOnlyCollection<ColumnDeclaration> columns = node.Columns;

            List<ColumnDeclaration> alternate = null;
            for (Int32 i = 0, n = node.Columns.Count; i < n; i++)
            {
                ColumnDeclaration decl = node.Columns[i];
                if (IsColumnUsed(node.Alias, decl.Name))
                {
                    Expression expr = Visit(decl.Expression);
                    if (expr != decl.Expression)
                    {
                        decl = new ColumnDeclaration(decl.Name, expr);
                    }
                }
                else
                {
                    decl = null; // null means it gets omitted
                }
                if (decl != node.Columns[i] && alternate == null)
                {
                    alternate = new List<ColumnDeclaration>();
                    for (Int32 j = 0; j < i; j++)
                    {
                        alternate.Add(node.Columns[j]);
                    }
                }
                if (decl != null && alternate != null)
                {
                    alternate.Add(decl);
                }
            }
            if (alternate != null)
            {
                columns = alternate.AsReadOnly();
            }

            Expression take = Visit(node.Take);
            ReadOnlyCollection<Expression> groupbys = VisitExpressionList(node.GroupBy);
            ReadOnlyCollection<OrderByExpression> orderbys = VisitOrderBy(node.OrderBy);
            Expression where = Visit(node.Where);
            Expression from = Visit(node.From);

            ClearColumnsUsed(node.Alias);

            if (columns != node.Columns
                || take != node.Take
                || orderbys != node.OrderBy
                || groupbys != node.GroupBy
                || where != node.Where
                || from != node.From)
            {
                node = new SelectExpression(node.Alias, columns, from, where, orderbys, groupbys, take);
            }

            return node;
        }
예제 #3
0
 protected override Expression VisitSelect(SelectExpression node)
 {
     if (_selectsToRemove.Contains(node))
     {
         return Visit(node.From);
     }
     return base.VisitSelect(node);
 }
예제 #4
0
 private static Boolean ProjectionIsNameMapOnly(SelectExpression select)
 {
     var fromSelect = select.From as SelectExpression;
     if (fromSelect == null || select.Columns.Count != fromSelect.Columns.Count)
         return false;
     // test that all _columns in 'select' are refering to _columns in the same position
     // in 'fromSelect'.
     for (Int32 i = 0, n = select.Columns.Count; i < n; i++)
     {
         var col = select.Columns[i].Expression as ColumnExpression;
         if (col == null || !(col.Name == fromSelect.Columns[i].Name))
             return false;
     }
     return true;
 }
예제 #5
0
 // protected override methods
 protected override Expression VisitSelect(SelectExpression node)
 {
     node = (SelectExpression) base.VisitSelect(node);
     if (_lookup.Contains(node.Alias))
     {
         var aggColumns = new List<ColumnDeclaration>(node.Columns);
         foreach (AggregateSubqueryExpression ae in _lookup[node.Alias])
         {
             String name = "agg" + aggColumns.Count;
             var cd = new ColumnDeclaration(name, ae.AggregateInGroupSelect);
             _map.Add(ae, new ColumnExpression(ae.Type, ae.GroupByAlias, name));
             aggColumns.Add(cd);
         }
         return new SelectExpression(node.Alias, aggColumns, node.From, node.Where, node.OrderBy, node.GroupBy,
                                     node.Take);
     }
     return node;
 }
예제 #6
0
        // protected override methods
        protected override Expression VisitSelect(SelectExpression node)
        {
            node = (SelectExpression) base.VisitSelect(node);

            // first remove all purely redundant subqueries
            List<SelectExpression> redundant = RedundantSubqueryGatherer.Gather(node.From);
            if (redundant != null)
            {
                node = SubqueryRemover.Remove(node, redundant);
            }

            // next attempt to merge subqueries that would have been removed by the above
            // logic except for the existence of a where clause
            //while (CanMergeWithFrom(node))
            //{
            // SelectExpression fromSelect = (SelectExpression)node.From;

            // // remove the redundant subquery
            // node = SubqueryRemover.Remove(node, fromSelect);

            // // merge where expressions
            // Expression where = node.Where;
            // if (fromSelect.Where != null)
            // {
            // if (where != null)
            // {
            // where = Expression.And(fromSelect.Where, where);
            // }
            // else
            // {
            // where = fromSelect.Where;
            // }
            // }
            // if (where != node.Where)
            // {
            // node = new SelectExpression(node.Type, node.Alias, node.Columns, node.From, where, node.OrderBy, node.GroupBy);
            // }
            //}
            return node;
        }
예제 #7
0
 protected virtual Expression VisitSelect(SelectExpression node)
 {
     Expression from = VisitSource(node.From);
     Expression where = Visit(node.Where);
     ReadOnlyCollection<ColumnDeclaration> columns = VisitColumnDeclarations(node.Columns);
     ReadOnlyCollection<OrderByExpression> orderBy = VisitOrderBy(node.OrderBy);
     ReadOnlyCollection<Expression> groupBy = VisitExpressionList(node.GroupBy);
     Expression take = Visit(node.Take);
     if (from != node.From
         || where != node.Where
         || columns != node.Columns
         || orderBy != node.OrderBy
         || groupBy != node.GroupBy
         || take != node.Take)
     {
         return new SelectExpression(node.Alias, columns, from, where, orderBy, groupBy, take);
     }
     return node;
 }
예제 #8
0
 // private static methods
 private static Boolean IsRedudantSubquery(SelectExpression select)
 {
     return (select.From is SelectExpression || select.From is SourceExpression)
            && (ProjectionIsSimple(select) || ProjectionIsNameMapOnly(select))
            && (select.Where == null)
            && (select.Take == null)
            && (select.OrderBy == null || select.OrderBy.Count == 0)
            && (select.GroupBy == null || select.GroupBy.Count == 0);
 }
예제 #9
0
 // protected override methods
 protected override Expression VisitSelect(SelectExpression select)
 {
     if (IsRedudantSubquery(select))
     {
         if (_redundant == null)
         {
             _redundant = new List<SelectExpression>();
         }
         _redundant.Add(select);
     }
     return select;
 }
예제 #10
0
 internal ScalarExpression(Type type, SelectExpression select)
     : base(PigExpressionType.Scalar, type, select)
 {
 }
예제 #11
0
 // constructors
 internal SubqueryExpression(PigExpressionType eType, Type type, SelectExpression select)
     : base(eType, type)
 {
     Select = select;
 }
예제 #12
0
        // private methods
        private Expression BindAggregate(Expression source, String aggName, MethodInfo method, LambdaExpression argument,
                                         Boolean isRoot)
        {
            Type returnType = method.ReturnType;
            Boolean hasPredicateArg = HasPredicateArg(aggName);
            Boolean isDistinct = false;
            Boolean argumentWasPredicate = false;

            // check for distinct
            var mcs = source as MethodCallExpression;
            if (mcs != null && !hasPredicateArg && argument == null)
            {
                if (mcs.Method.Name == "Distinct" && mcs.Arguments.Count == 1 &&
                    (mcs.Method.DeclaringType == typeof (Queryable) || mcs.Method.DeclaringType == typeof (Enumerable)))
                {
                    source = mcs.Arguments[0];
                    isDistinct = true;
                }
            }

            if (argument != null && hasPredicateArg)
            {
                // convert query.Count(predicate) into query.Where(predicate).Count()
                source = Expression.Call(typeof (Queryable), "Where", method.GetGenericArguments(), source, argument);
                argument = null;
                argumentWasPredicate = true;
            }

            ProjectionExpression projection = VisitSequence(source);

            Expression argExpr = null;
            if (argument != null)
            {
                _map[argument.Parameters[0]] = projection.Projector;
                argExpr = Visit(argument.Body);
            }
            else if (!hasPredicateArg)
            {
                argExpr = projection.Projector;
            }

            SourceAlias alias = GetNextAlias();
            Expression aggExpr = new AggregateExpression(returnType, aggName, argExpr, isDistinct);
            var select = new SelectExpression(alias, new[] {new ColumnDeclaration("", aggExpr)}, projection.Source, null);

            if (isRoot)
            {
                ParameterExpression p = Expression.Parameter(typeof (IEnumerable<>).MakeGenericType(aggExpr.Type),
                                                             "node");
                LambdaExpression gator =
                    Expression.Lambda(Expression.Call(typeof (Enumerable), "Single", new[] {returnType}, p), p);
                return new ProjectionExpression(select, new ColumnExpression(returnType, alias, ""), gator);
            }

            var subquery = new ScalarExpression(returnType, select);

            // if we can find the corresponding group-info we can build a special AggregateSubquery node that will enable us to
            // optimize the node expression later using AggregateRewriter
            GroupByInfo info;
            if (!argumentWasPredicate && _groupByMap.TryGetValue(projection, out info))
            {
                // use the element expression from the group-by info to rebind the argument so the resulting expression is one that
                // would be legal to add to the _columns in the select expression that has the corresponding group-by clause.
                if (argument != null)
                {
                    _map[argument.Parameters[0]] = info.Element;
                    argExpr = Visit(argument.Body);
                }
                else if (!hasPredicateArg)
                {
                    argExpr = info.Element;
                }
                aggExpr = new AggregateExpression(returnType, aggName, argExpr, isDistinct);

                // check for easy to optimize case. If the projection that our node is based on is really the 'group' argument from
                // the query.GroupBy(xxx, (key, group) => yyy) method then whatever expression we return here will automatically
                // become part of the select expression that has the group-by clause, so just return the simple node expression.
                if (projection == _currentGroupElement)
                {
                    return aggExpr;
                }
                return new AggregateSubqueryExpression(info.Alias, aggExpr, subquery);
            }
            return subquery;
        }
예제 #13
0
 // internal static methods
 internal static SelectExpression Remove(SelectExpression outerSelect,
                                         IEnumerable<SelectExpression> selectsToRemove)
 {
     return (SelectExpression) new SubqueryRemover(selectsToRemove).Visit(outerSelect);
 }
예제 #14
0
 // constructors
 internal ProjectionExpression(SelectExpression source, Expression projector)
     : this(source, projector, null)
 {
 }
예제 #15
0
 // protected methods
 protected override Expression VisitSelect(SelectExpression select)
 {
     _aliases.Add(select.Alias);
     return select;
 }
예제 #16
0
        protected override Expression VisitSelect(SelectExpression select)
        {
            Boolean saveIsOuterMostSelect = _isOuterMostSelect;
            try
            {
                _isOuterMostSelect = false;
                select = (SelectExpression) base.VisitSelect(select);

                Boolean hasOrderBy = select.OrderBy != null && select.OrderBy.Count > 0;
                Boolean hasGroupBy = select.GroupBy != null && select.GroupBy.Count > 0;
                Boolean canHaveOrderBy = saveIsOuterMostSelect || select.Take != null;
                Boolean canReceiveOrderings = canHaveOrderBy && !hasGroupBy;

                if (hasOrderBy)
                {
                    PrependOrderings(select.OrderBy);
                }

                IEnumerable<OrderByExpression> orderings = null;
                if (canReceiveOrderings)
                {
                    orderings = _gatheredOrderings;
                }
                else if (canHaveOrderBy)
                {
                    orderings = select.OrderBy;
                }
                Boolean canPassOnOrderings = !saveIsOuterMostSelect && !hasGroupBy;
                ReadOnlyCollection<ColumnDeclaration> columns = select.Columns;
                if (_gatheredOrderings != null)
                {
                    if (canPassOnOrderings)
                    {
                        HashSet<SourceAlias> producedAliases = AliasesProduced.Gather(select.From);
                        // reproject order expressions using this select's alias so the outer select will have properly formed expressions
                        BindResult project = RebindOrderings(_gatheredOrderings, select.Alias, producedAliases,
                                                             select.Columns);
                        _gatheredOrderings = null;
                        PrependOrderings(project.Orderings);
                        columns = project.Columns;
                    }
                    else
                    {
                        _gatheredOrderings = null;
                    }
                }
                if (orderings != select.OrderBy || columns != select.Columns)
                {
                    select = new SelectExpression(select.Alias, columns, select.From, select.Where, orderings,
                                                  select.GroupBy, select.Take);
                }
                return select;
            }
            finally
            {
                _isOuterMostSelect = saveIsOuterMostSelect;
            }
        }
예제 #17
0
 // private static methods
 private static Boolean ProjectionIsSimple(SelectExpression select)
 {
     foreach (ColumnDeclaration decl in select.Columns)
     {
         var col = decl.Expression as ColumnExpression;
         if (col == null || decl.Name != col.Name)
         {
             return false;
         }
     }
     return true;
 }