コード例 #1
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;
		}
コード例 #2
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;
		}
コード例 #3
0
		private SqlExpression MakeCoalesce(SqlExpression left, SqlExpression right, Type resultType)
		{
			CompensateForLowerPrecedenceOfDateType(ref left, ref right);    // DevDiv 176874
			if(TypeSystem.IsSimpleType(resultType))
			{
				return _nodeFactory.Binary(SqlNodeType.Coalesce, left, right, resultType);
			}
			else
			{
				List<SqlWhen> whens = new List<SqlWhen>(1);
				whens.Add(new SqlWhen(_nodeFactory.Unary(SqlNodeType.IsNull, left, left.SourceExpression), right));
				SqlDuplicator dup = new SqlDuplicator(true);
				return _nodeFactory.SearchedCase(whens.ToArray(), (SqlExpression)dup.Duplicate(left), _dominatingExpression);
			}
		}
コード例 #4
0
		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
			_parameterExpressionToSqlExpression[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);
			_parameterExpressionToSqlExpression[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
				_parameterExpressionToSqlExpression[elemLambda.Parameters[0]] = selDupRef;
				elemExpr = this.VisitExpression(elemLambda.Body);

				// evaluate element expression relative to original sequence
				_parameterExpressionToSqlExpression[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, _dominatingExpression);
			selElem.Where = _nodeFactory.Binary(SqlNodeType.EQ2V, keyExpr, keyDup);

			// Finally, make the MULTISET node. this will be used as part of the final select
			SqlSubSelect ss = _nodeFactory.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, _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, _typeProvider.From(elementType), keyExpr, ss, _dominatingExpression);
				SqlSelect keyGroupSel = new SqlSelect(keyGroup, gselAlias, _dominatingExpression);
				SqlAlias kgAlias = new SqlAlias(keyGroupSel);
				SqlAliasRef kgAliasRef = new SqlAliasRef(kgAlias);

				_parameterExpressionToSqlExpression[resultSelector.Parameters[0]] = _nodeFactory.Member(kgAliasRef, elementType.GetProperty("Key"));
				_parameterExpressionToSqlExpression[resultSelector.Parameters[1]] = kgAliasRef;

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

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

				// remember the select that has the actual group (for optimizing aggregates later)
				_sqlNodeToGroupInfo[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, _typeProvider.From(elementType), keyExpr, ss, _dominatingExpression);
				result = new SqlSelect(resultExpr, gselAlias, _dominatingExpression);

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

			return result;
		}
コード例 #5
0
		private SqlNode VisitParameter(ParameterExpression p)
		{
			SqlExpression sqlExpr;
			if(_parameterExpressionToSqlExpression.TryGetValue(p, out sqlExpr))
				return sqlExpr;
			Expression expr;
			if(_parameterExpressionToExpression.TryGetValue(p, out expr))
				return this.Visit(expr);
			SqlNode nodeToDup;
			if(_parameterExpressionToSqlNode.TryGetValue(p, out nodeToDup))
			{
				SqlDuplicator duplicator = new SqlDuplicator(true);
				return duplicator.Duplicate(nodeToDup);
			}
			throw Error.ParameterNotInScope(p.Name);
		}