internal override SqlSelect VisitSelect(SqlSelect select) {
                bool saveTop = this.topSelect;
                bool savePK = this.addPrimaryKeys;

                SqlSelect saveSelect = this.currentSelect;
                this.currentSelect = select;

                if (select.OrderingType == SqlOrderingType.Always) {
                    this.addPrimaryKeys = true;
                }

                this.topSelect = false;

                // can't forward ordering information through a group-by
                if (select.GroupBy.Count > 0) {
                    this.Visit(select.From);
                    this.orders = null;
                }
                else {
                    this.Visit(select.From);
                }

                if (select.OrderBy.Count > 0) {
                    this.PrependOrderExpressions(select.OrderBy);
                }

                List<SqlOrderExpression> save = this.orders;
                this.orders = null;
                this.rowNumberOrders = save; // lest orders be null when we need info

                /* do all the lower level stuff */
                select.Where = this.VisitExpression(select.Where);
                for (int i = 0, n = select.GroupBy.Count; i < n; i++) {
                    select.GroupBy[i] = this.VisitExpression(select.GroupBy[i]);
                }
                select.Having = this.VisitExpression(select.Having);
                for (int i = 0, n = select.OrderBy.Count; i < n; i++) {
                    select.OrderBy[i].Expression = this.VisitExpression(select.OrderBy[i].Expression);
                }
                select.Top = this.VisitExpression(select.Top);
                select.Selection = this.VisitExpression(select.Selection);
                select.Row = (SqlRow)this.Visit(select.Row);

                this.topSelect = saveTop;
                this.addPrimaryKeys = savePK;

                this.orders = save;

                // all ordering is blocked for this layer and above
                if (select.OrderingType == SqlOrderingType.Blocked) {
                    this.orders = null;
                }

                // rebuild orderby expressions, provided this select doesn't contain a SqlRowNumber
                // otherwise, replace the orderby with a reference to that column
                select.OrderBy.Clear();
                var rowNumberChecker = new SqlRowNumberChecker();

                if (rowNumberChecker.HasRowNumber(select) && rowNumberChecker.RowNumberColumn != null) {
                    select.Row.Columns.Remove(rowNumberChecker.RowNumberColumn);
                    this.PushDown(rowNumberChecker.RowNumberColumn);
                    this.Orders.Add(new SqlOrderExpression(SqlOrderType.Ascending, new SqlColumnRef(rowNumberChecker.RowNumberColumn)));
                } 
                if ((this.topSelect || select.Top != null) && select.OrderingType != SqlOrderingType.Never && this.orders != null) {
                    this.orders = new HashSet<SqlOrderExpression>(this.orders).ToList();
                    SqlDuplicator dup = new SqlDuplicator(true);
                    foreach (SqlOrderExpression sox in this.orders) {
                        select.OrderBy.Add(new SqlOrderExpression(sox.OrderType, (SqlExpression)dup.Duplicate(sox.Expression)));
                    }
                }
                this.currentSelect = saveSelect;

                return select;
            }
            internal override SqlRowNumber VisitRowNumber(SqlRowNumber rowNumber) {
                if (rowNumber.OrderBy.Count > 0) return rowNumber;

                SqlDuplicator dup = new SqlDuplicator(true);
                List<SqlOrderExpression> orderBy = new List<SqlOrderExpression>();
                List<SqlOrderExpression> existingOrders = new List<SqlOrderExpression>();

                if (this.rowNumberOrders != null && this.rowNumberOrders.Count != 0) {
                    existingOrders = new List<SqlOrderExpression>(this.rowNumberOrders);
                }
                else if (this.orders != null) {
                    existingOrders = new List<SqlOrderExpression>(this.orders);
                }

                foreach (SqlOrderExpression expr in existingOrders) {
                    if (!expr.Expression.IsConstantColumn) {
                        orderBy.Add(expr);
                        if (this.rowNumberOrders != null) {
                            this.rowNumberOrders.Remove(expr);
                        }
                        if (this.orders != null) {
                            this.orders.Remove(expr);
                        }
                    }
                }

                rowNumber.OrderBy.Clear();

                if (orderBy.Count == 0) {
                    List<SqlColumn> columns = SqlGatherColumnsProduced.GatherColumns(this.currentSelect.From);

                    foreach (SqlColumn col in columns) {
                        if (col.Expression.SqlType.IsOrderable) {
                            orderBy.Add(new SqlOrderExpression(SqlOrderType.Ascending, new SqlColumnRef(col)));
                        }
                    }

                    if (orderBy.Count == 0) {
                        // insert simple column
                        SqlColumn col =
                            new SqlColumn(
                                "rowNumberOrder",
                                sql.Value(typeof(int), this.typeProvider.From(typeof(int)), 1, false, rowNumber.SourceExpression)
                            );
                        this.PushDown(col);
                        orderBy.Add(new SqlOrderExpression(SqlOrderType.Ascending, new SqlColumnRef(col)));
                    }
                }

                foreach (SqlOrderExpression sox in orderBy) {
                    rowNumber.OrderBy.Add(new SqlOrderExpression(sox.OrderType, (SqlExpression)dup.Duplicate(sox.Expression)));
                }

                return rowNumber;
            }
        private SqlNode VisitGroupBy(Expression sequence, LambdaExpression keyLambda, LambdaExpression elemLambda, LambdaExpression resultSelector) {
            // Convert seq.Group(elem, key) into
            //
            // SELECT s.key, MULTISET(select s2.elem from seq AS s2 where s.key == s2.key)
            // FROM seq AS s
            //
            // where key and elem can be either simple scalars or object constructions
            //
            SqlSelect seq = this.VisitSequence(sequence);
            seq = this.LockSelect(seq);
            SqlAlias seqAlias = new SqlAlias(seq);
            SqlAliasRef seqAliasRef = new SqlAliasRef(seqAlias);

            // evaluate the key expression relative to original sequence
            this.map[keyLambda.Parameters[0]] = seqAliasRef;
            SqlExpression keyExpr = this.VisitExpression(keyLambda.Body);

            // make a duplicate of the original sequence to use as a foundation of our group multiset
            SqlDuplicator sd = new SqlDuplicator();
            SqlSelect selDup = (SqlSelect)sd.Duplicate(seq);

            // rebind key in relative to the duplicate sequence
            SqlAlias selDupAlias = new SqlAlias(selDup);
            SqlAliasRef selDupRef = new SqlAliasRef(selDupAlias);
            this.map[keyLambda.Parameters[0]] = selDupRef;
            SqlExpression keyDup = this.VisitExpression(keyLambda.Body);

            SqlExpression elemExpr = null;
            SqlExpression elemOnGroupSource = null;
            if (elemLambda != null) {
                // evaluate element expression relative to the duplicate sequence
                this.map[elemLambda.Parameters[0]] = selDupRef;
                elemExpr = this.VisitExpression(elemLambda.Body);

                // evaluate element expression relative to original sequence
                this.map[elemLambda.Parameters[0]] = seqAliasRef;
                elemOnGroupSource = this.VisitExpression(elemLambda.Body);
            }
            else {
                // no elem expression supplied, so just use an alias ref to the duplicate sequence.
                // this will resolve to whatever was being produced by the sequence
                elemExpr = selDupRef;
                elemOnGroupSource = seqAliasRef;
            }

            // Make a sub expression out of the key.  This will allow a single definition of the 
            // expression to be shared at multiple points in the tree (via SqlSharedExpressionRef's)
            SqlSharedExpression keySubExpr = new SqlSharedExpression(keyExpr);
            keyExpr = new SqlSharedExpressionRef(keySubExpr);

            // construct the select clause that picks out the elements (this may be redundant...)
            SqlSelect selElem = new SqlSelect(elemExpr, selDupAlias, this.dominatingExpression);
            selElem.Where = sql.Binary(SqlNodeType.EQ2V, keyExpr, keyDup);

            // Finally, make the MULTISET node. this will be used as part of the final select
            SqlSubSelect ss = sql.SubSelect(SqlNodeType.Multiset, selElem);

            // add a layer to the original sequence before applying the actual group-by clause
            SqlSelect gsel = new SqlSelect(new SqlSharedExpressionRef(keySubExpr), seqAlias, this.dominatingExpression);
            gsel.GroupBy.Add(keySubExpr);
            SqlAlias gselAlias = new SqlAlias(gsel);

            SqlSelect result = null;
            if (resultSelector != null) {
                // Create final select to include construction of group multiset
                // select new Grouping { Key = key, Group = Multiset(select elem from seq where match) } from ...
                Type elementType = typeof(IGrouping<,>).MakeGenericType(keyExpr.ClrType, elemExpr.ClrType);

                SqlExpression keyGroup = new SqlGrouping(elementType, this.typeProvider.From(elementType), keyExpr, ss, this.dominatingExpression);
                SqlSelect keyGroupSel = new SqlSelect(keyGroup, gselAlias, this.dominatingExpression);
                SqlAlias kgAlias = new SqlAlias(keyGroupSel);
                SqlAliasRef kgAliasRef = new SqlAliasRef(kgAlias);

                this.map[resultSelector.Parameters[0]] = sql.Member(kgAliasRef, elementType.GetProperty("Key"));
                this.map[resultSelector.Parameters[1]] = kgAliasRef;

                // remember the select that has the actual group (for optimizing aggregates later)
                this.gmap[kgAliasRef] = new GroupInfo { SelectWithGroup = gsel, ElementOnGroupSource = elemOnGroupSource };

                SqlExpression resultExpr = this.VisitExpression(resultSelector.Body);
                result = new SqlSelect(resultExpr, kgAlias, this.dominatingExpression);

                // remember the select that has the actual group (for optimizing aggregates later)
                this.gmap[resultExpr] = new GroupInfo { SelectWithGroup = gsel, ElementOnGroupSource = elemOnGroupSource };
            }
            else {
                // Create final select to include construction of group multiset
                // select new Grouping { Key = key, Group = Multiset(select elem from seq where match) } from ...
                Type elementType = typeof(IGrouping<,>).MakeGenericType(keyExpr.ClrType, elemExpr.ClrType);

                SqlExpression resultExpr = new SqlGrouping(elementType, this.typeProvider.From(elementType), keyExpr, ss, this.dominatingExpression);
                result = new SqlSelect(resultExpr, gselAlias, this.dominatingExpression);

                // remember the select that has the actual group (for optimizing aggregates later)
                this.gmap[resultExpr] = new GroupInfo { SelectWithGroup = gsel, ElementOnGroupSource = elemOnGroupSource };
            }

            return result;
        }
 private SqlExpression MakeCoalesce(SqlExpression left, SqlExpression right, Type resultType) {
     CompensateForLowerPrecedenceOfDateType(ref left, ref right);    // DevDiv 176874
     if (TypeSystem.IsSimpleType(resultType)) {
         return sql.Binary(SqlNodeType.Coalesce, left, right, resultType);
     }
     else {
         List<SqlWhen> whens = new List<SqlWhen>(1);
         whens.Add(new SqlWhen(sql.Unary(SqlNodeType.IsNull, left, left.SourceExpression), right));
         SqlDuplicator dup = new SqlDuplicator(true);
         return sql.SearchedCase(whens.ToArray(), (SqlExpression)dup.Duplicate(left), this.dominatingExpression);
     }
 }
 private SqlNode VisitParameter(ParameterExpression p) {
     SqlExpression sqlExpr;
     if (this.map.TryGetValue(p, out sqlExpr))
         return sqlExpr;
     Expression expr;
     if (this.exprMap.TryGetValue(p, out expr))
         return this.Visit(expr);
     SqlNode nodeToDup;
     if (this.dupMap.TryGetValue(p, out nodeToDup)) {
         SqlDuplicator duplicator = new SqlDuplicator(true);
         return duplicator.Duplicate(nodeToDup);
     }
     throw Error.ParameterNotInScope(p.Name);
 }
Exemple #6
0
            internal override SqlRowNumber VisitRowNumber(SqlRowNumber rowNumber)
            {
                if (rowNumber.OrderBy.Count > 0)
                {
                    return(rowNumber);
                }

                SqlDuplicator             dup            = new SqlDuplicator(true);
                List <SqlOrderExpression> orderBy        = new List <SqlOrderExpression>();
                List <SqlOrderExpression> existingOrders = new List <SqlOrderExpression>();

                if (this.rowNumberOrders != null && this.rowNumberOrders.Count != 0)
                {
                    existingOrders = new List <SqlOrderExpression>(this.rowNumberOrders);
                }
                else if (this.orders != null)
                {
                    existingOrders = new List <SqlOrderExpression>(this.orders);
                }

                foreach (SqlOrderExpression expr in existingOrders)
                {
                    if (!expr.Expression.IsConstantColumn)
                    {
                        orderBy.Add(expr);
                        if (this.rowNumberOrders != null)
                        {
                            this.rowNumberOrders.Remove(expr);
                        }
                        if (this.orders != null)
                        {
                            this.orders.Remove(expr);
                        }
                    }
                }

                rowNumber.OrderBy.Clear();

                if (orderBy.Count == 0)
                {
                    List <SqlColumn> columns = SqlGatherColumnsProduced.GatherColumns(this.currentSelect.From);

                    foreach (SqlColumn col in columns)
                    {
                        if (col.Expression.SqlType.IsOrderable)
                        {
                            orderBy.Add(new SqlOrderExpression(SqlOrderType.Ascending, new SqlColumnRef(col)));
                        }
                    }

                    if (orderBy.Count == 0)
                    {
                        // insert simple column
                        SqlColumn col =
                            new SqlColumn(
                                "rowNumberOrder",
                                sql.Value(typeof(int), this.typeProvider.From(typeof(int)), 1, false, rowNumber.SourceExpression)
                                );
                        this.PushDown(col);
                        orderBy.Add(new SqlOrderExpression(SqlOrderType.Ascending, new SqlColumnRef(col)));
                    }
                }

                foreach (SqlOrderExpression sox in orderBy)
                {
                    rowNumber.OrderBy.Add(new SqlOrderExpression(sox.OrderType, (SqlExpression)dup.Duplicate(sox.Expression)));
                }

                return(rowNumber);
            }
Exemple #7
0
            internal override SqlSelect VisitSelect(SqlSelect select)
            {
                bool saveTop = this.topSelect;
                bool savePK  = this.addPrimaryKeys;

                SqlSelect saveSelect = this.currentSelect;

                this.currentSelect = select;

                if (select.OrderingType == SqlOrderingType.Always)
                {
                    this.addPrimaryKeys = true;
                }

                this.topSelect = false;

                // can't forward ordering information through a group-by
                if (select.GroupBy.Count > 0)
                {
                    this.Visit(select.From);
                    this.orders = null;
                }
                else
                {
                    this.Visit(select.From);
                }

                if (select.OrderBy.Count > 0)
                {
                    this.PrependOrderExpressions(select.OrderBy);
                }

                List <SqlOrderExpression> save = this.orders;

                this.orders          = null;
                this.rowNumberOrders = save; // lest orders be null when we need info

                /* do all the lower level stuff */
                select.Where = this.VisitExpression(select.Where);
                for (int i = 0, n = select.GroupBy.Count; i < n; i++)
                {
                    select.GroupBy[i] = this.VisitExpression(select.GroupBy[i]);
                }
                select.Having = this.VisitExpression(select.Having);
                for (int i = 0, n = select.OrderBy.Count; i < n; i++)
                {
                    select.OrderBy[i].Expression = this.VisitExpression(select.OrderBy[i].Expression);
                }
                select.Top       = this.VisitExpression(select.Top);
                select.Selection = this.VisitExpression(select.Selection);
                select.Row       = (SqlRow)this.Visit(select.Row);

                this.topSelect      = saveTop;
                this.addPrimaryKeys = savePK;

                this.orders = save;

                // all ordering is blocked for this layer and above
                if (select.OrderingType == SqlOrderingType.Blocked)
                {
                    this.orders = null;
                }

                // rebuild orderby expressions, provided this select doesn't contain a SqlRowNumber
                // otherwise, replace the orderby with a reference to that column
                select.OrderBy.Clear();
                var rowNumberChecker = new SqlRowNumberChecker();

                if (rowNumberChecker.HasRowNumber(select) && rowNumberChecker.RowNumberColumn != null)
                {
                    select.Row.Columns.Remove(rowNumberChecker.RowNumberColumn);
                    this.PushDown(rowNumberChecker.RowNumberColumn);
                    this.Orders.Add(new SqlOrderExpression(SqlOrderType.Ascending, new SqlColumnRef(rowNumberChecker.RowNumberColumn)));
                }
                if ((this.topSelect || select.Top != null) && select.OrderingType != SqlOrderingType.Never && this.orders != null)
                {
                    this.orders = new HashSet <SqlOrderExpression>(this.orders).ToList();
                    SqlDuplicator dup = new SqlDuplicator(true);
                    foreach (SqlOrderExpression sox in this.orders)
                    {
                        select.OrderBy.Add(new SqlOrderExpression(sox.OrderType, (SqlExpression)dup.Duplicate(sox.Expression)));
                    }
                }
                this.currentSelect = saveSelect;

                return(select);
            }