Beispiel #1
0
		internal SqlColumn BubbleUp(SqlColumn col, SqlNode source)
		{
			this.match = this.GetOriginatingColumn(col);
			this.found = null;
			this.Visit(source);
			return this.found;
		}
			internal override SqlExpression VisitColumn(SqlColumn col)
			{
				if(col.Expression != null)
				{
					this.Visit(col.Expression);
				}
				return col;
			}
Beispiel #3
0
		private static string GetColumnName(SqlColumn c)
		{
#if DEBUG
			return c.Text;
#else
            return c.Name;
#endif
		}
Beispiel #4
0
		internal SqlColumn GetOriginatingColumn(SqlColumn col)
		{
			SqlColumnRef cref = col.Expression as SqlColumnRef;
			if(cref != null)
			{
				return this.GetOriginatingColumn(cref.Column);
			}
			return col;
		}
		internal override SqlExpression VisitColumn(SqlColumn col)
		{
			if(!String.IsNullOrEmpty(col.Name))
			{
				this.Names.Add(col.Name);
			}

			return base.VisitColumn(col);
		}
		private SqlColumnRef MakeFlattenedColumn(SqlExpression expr, string name)
		{
			SqlColumn c = (!this.isInput) ? this.FindColumnWithExpression(this.row.Columns, expr) : null;
			if(c == null)
			{
				c = new SqlColumn(expr.ClrType, expr.SqlType, name, null, expr, expr.SourceExpression);
				this.row.Columns.Add(c);
			}
			return new SqlColumnRef(c);
		}
		internal override SqlExpression VisitColumnRef(SqlColumnRef cref) {
			SqlExpression result = base.VisitColumnRef(cref);
			if (result != null && result == cref) {
				// reference to outer scope, don't propogate references to expressions or aliases
				SqlColumn col = cref.Column;
				SqlColumn newcol = new SqlColumn(col.ClrType, col.SqlType, col.Name, col.MetaMember, null, col.SourceExpression);
				newcol.Ordinal = col.Ordinal;
				result = new SqlColumnRef(newcol);
				newcol.ClearSourceExpression();
			}
			return result;
		}
			internal override SqlRow VisitRow(SqlRow row)
			{
				for(int i = 0, n = row.Columns.Count; i < n; i++)
				{
					row.Columns[i].Expression = this.VisitExpression(row.Columns[i].Expression);
					if(this.hasRowNumber)
					{
						this.CurrentColumn = row.Columns[i];
						break;
					}
				}
				return row;
			}
Beispiel #9
0
		internal override SqlTable VisitTable(SqlTable tab)
		{
			foreach(SqlColumn c in tab.Columns)
			{
				if(c == this.match)
				{
					if(this.found != null)
						throw Error.ColumnIsDefinedInMultiplePlaces(GetColumnName(this.match));
					this.found = c;
					break;
				}
			}
			return tab;
		}
Beispiel #10
0
		internal override SqlRow VisitRow(SqlRow row)
		{
			foreach(SqlColumn c in row.Columns)
			{
				if(this.RefersToColumn(c, this.match))
				{
					if(this.found != null)
					{
						throw Error.ColumnIsDefinedInMultiplePlaces(GetColumnName(this.match));
					}
					this.found = c;
					break;
				}
			}
			return row;
		}
		internal override SqlExpression VisitColumn(SqlColumn col)
		{
			SqlColumn c = this.FindColumn(this.row.Columns, col);
			if(c == null && col.Expression != null && !this.isInput && (!this.isNew || (this.isNew && !col.Expression.IsConstantColumn)))
			{
				c = this.FindColumnWithExpression(this.row.Columns, col.Expression);
			}
			if(c == null)
			{
				this.row.Columns.Add(col);
				c = col;
			}
			else if(c != col)
			{
				// preserve expr-sets when folding expressions together
				if(col.Expression.NodeType == SqlNodeType.ExprSet && c.Expression.NodeType != SqlNodeType.ExprSet)
				{
					c.Expression = col.Expression;
				}
				this.map[col] = c;
			}
			return new SqlColumnRef(c);
		}
Beispiel #12
0
		internal override SqlAlias VisitAlias(SqlAlias a)
		{

			SqlTable tab = a.Node as SqlTable;
			SqlTableValuedFunctionCall tvf = a.Node as SqlTableValuedFunctionCall;

			if(this.addPrimaryKeys && (tab != null || tvf != null))
			{
				List<SqlOrderExpression> list = new List<SqlOrderExpression>();

				bool isTable = tab != null;
				MetaType rowType = isTable ? tab.RowType : tvf.RowType;
				foreach(MetaDataMember mm in rowType.IdentityMembers)
				{
					string name = mm.MappedName;
					SqlColumn col;
					Expression sourceExpression;
					List<SqlColumn> columns;

					if(isTable)
					{
						col = tab.Find(name);
						sourceExpression = tab.SourceExpression;
						columns = tab.Columns;
					}
					else
					{
						col = tvf.Find(name);
						sourceExpression = tvf.SourceExpression;
						columns = tvf.Columns;
					}

					if(col == null)
					{
						col = new SqlColumn(mm.MemberAccessor.Type, typeProvider.From(mm.MemberAccessor.Type), name, mm, null, sourceExpression);
						col.Alias = a;
						columns.Add(col);
					}
					list.Add(new SqlOrderExpression(SqlOrderType.Ascending, new SqlColumnRef(col)));
				}

				this.PrependOrderExpressions(list);

				return a;
			}
			else
			{
				return base.VisitAlias(a);
			}
		}
		internal override SqlExpression VisitColumn(SqlColumn col)
		{
			VisitAliasConsumed(col.Alias);
			VisitExpression(col.Expression);
			return col;
		}
Beispiel #14
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;
		}
Beispiel #15
0
		private void PushDown(SqlColumn column)
		{
			SqlSelect select = new SqlSelect(new SqlNop(column.ClrType, column.SqlType, column.SourceExpression), this.currentSelect.From, this.currentSelect.SourceExpression);
			this.currentSelect.From = new SqlAlias(select);
			select.Row.Columns.Add(column);
		}
		internal override SqlExpression VisitColumn(SqlColumn col)
		{
			throw Error.UnexpectedFloatingColumn();
		}
		private SqlNode VisitAggregate(Expression sequence, LambdaExpression lambda, SqlNodeType aggType, Type returnType)
		{
			// Convert seq.Agg(exp) into 
			//
			// 1) SELECT Agg(exp) FROM seq
			// 2) SELECT Agg1 FROM (SELECT Agg(exp) as Agg1 FROM group-seq GROUP BY ...)
			// 3) SCALAR(SELECT Agg(exp) FROM seq)
			//
			bool isCount = aggType == SqlNodeType.Count || aggType == SqlNodeType.LongCount;

			SqlNode source = this.Visit(sequence);
			SqlSelect select = this.CoerceToSequence(source);
			SqlAlias alias = new SqlAlias(select);
			SqlAliasRef aref = new SqlAliasRef(alias);

			// If the sequence is of the form x.Select(expr).Agg() and the lambda for the aggregate is null,
			// or is a no-op parameter expression (like u=>u), clone the group by selection lambda 
			// expression, and use for the aggregate.
			// Final form should be x.Agg(expr)
			MethodCallExpression mce = sequence as MethodCallExpression;
			if(!_outerNode && !isCount && (lambda == null || (lambda.Parameters.Count == 1 && lambda.Parameters[0] == lambda.Body)) &&
				(mce != null) && IsSequenceOperatorCall(mce, "Select") && select.From is SqlAlias)
			{
				LambdaExpression selectionLambda = GetLambda(mce.Arguments[1]);

				lambda = Expression.Lambda(selectionLambda.Type, selectionLambda.Body, selectionLambda.Parameters);

				alias = (SqlAlias)select.From;
				aref = new SqlAliasRef(alias);
			}

			if(lambda != null && !TypeSystem.IsSimpleType(lambda.Body.Type))
			{
				throw Error.CannotAggregateType(lambda.Body.Type);
			}

			//Empty parameter aggregates are not allowed on anonymous types
			//i.e. db.Customers.Select(c=>new{c.Age}).Max() instead it should be
			//     db.Customers.Select(c=>new{c.Age}).Max(c=>c.Age)
			if(select.Selection.SqlType.IsRuntimeOnlyType && !IsGrouping(sequence.Type) && !isCount && lambda == null)
			{
				throw Error.NonCountAggregateFunctionsAreNotValidOnProjections(aggType);
			}
			if(lambda != null)
				_parameterExpressionToSqlExpression[lambda.Parameters[0]] = aref;

			if(_outerNode)
			{
				// If this aggregate is basically the last/outer-most operator of the query
				// 
				// produce SELECT Agg(exp) FROM seq
				//
				SqlExpression exp = (lambda != null) ? this.VisitExpression(lambda.Body) : null;
				SqlExpression where = null;
				if(isCount && exp != null)
				{
					where = exp;
					exp = null;
				}
				else if(exp == null && !isCount)
				{
					exp = aref;
				}
				if(exp != null)
				{
					// in case this contains another aggregate
					exp = new SqlSimpleExpression(exp);
				}
				SqlSelect sel = new SqlSelect(
					this.GetAggregate(aggType, returnType, exp),
					alias,
					_dominatingExpression
					);
				sel.Where = where;
				sel.OrderingType = SqlOrderingType.Never;
				return sel;
			}
			else if(!isCount || lambda == null)
			{
				// Look to optimize aggregate by pushing its evaluation down to the select node that has the
				// actual group-by operator.
				//
				// Produce:  SELECT Agg1 FROM (SELECT Agg(exp) as Agg1 FROM seq GROUP BY ...)
				//
				GroupInfo info = this.FindGroupInfo(source);
				if(info != null)
				{
					SqlExpression exp = null;
					if(lambda != null)
					{
						// evaluate expression relative to the group-by select node
						_parameterExpressionToSqlExpression[lambda.Parameters[0]] = (SqlExpression)SqlDuplicator.Copy(info.ElementOnGroupSource);
						exp = this.VisitExpression(lambda.Body);
					}
					else if(!isCount)
					{
						// support aggregates w/o an explicit selector specified
						exp = info.ElementOnGroupSource;
					}
					if(exp != null)
					{
						// in case this contains another aggregate
						exp = new SqlSimpleExpression(exp);
					}
					SqlExpression agg = this.GetAggregate(aggType, returnType, exp);
					SqlColumn c = new SqlColumn(agg.ClrType, agg.SqlType, null, null, agg, _dominatingExpression);
					info.SelectWithGroup.Row.Columns.Add(c);
					return new SqlColumnRef(c);
				}
			}
			// Otherwise, if we cannot optimize then fall back to generating a nested aggregate in a correlated sub query
			//
			// SCALAR(SELECT Agg(exp) FROM seq)
			{
				SqlExpression exp = (lambda != null) ? this.VisitExpression(lambda.Body) : null;
				if(exp != null)
				{
					// in case this contains another aggregate
					exp = new SqlSimpleExpression(exp);
				}
				SqlSelect sel = new SqlSelect(
					this.GetAggregate(aggType, returnType, isCount ? null : (lambda == null) ? aref : exp),
					alias,
					_dominatingExpression
					);
				sel.Where = isCount ? exp : null;
				return _nodeFactory.SubSelect(SqlNodeType.ScalarSubSelect, sel);
			}
		}
Beispiel #18
0
		internal SqlColumnRef(SqlColumn col)
			: base(SqlNodeType.ColumnRef, col.ClrType, col.SourceExpression) {
			this.column = col;
			}
Beispiel #19
0
		private void ForceLocal(SqlRow row, string name)
		{
			bool isLocal = false;
			// check to see if it already exists locally
			foreach(SqlColumn c in row.Columns)
			{
				if(this.RefersToColumn(c, this.found))
				{
					this.found = c;
					isLocal = true;
					break;
				}
			}
			if(!isLocal)
			{
				// need to put this in the local projection list to bubble it up
				SqlColumn c = new SqlColumn(found.ClrType, found.SqlType, name, this.found.MetaMember, new SqlColumnRef(this.found), row.SourceExpression);
				row.Columns.Add(c);
				this.found = c;
			}
		}
Beispiel #20
0
 internal virtual SqlExpression VisitColumn(SqlColumn col) {
     col.Expression = this.VisitExpression(col.Expression);
     return col;
 }
Beispiel #21
0
		private bool IsUniqueName(List<SqlColumn> columns, ICollection<string> reservedNames, SqlColumn c, string name)
		{
			foreach(SqlColumn sc in columns)
			{
				if(sc != c && String.Compare(sc.Name, name, StringComparison.OrdinalIgnoreCase) == 0)
					return false;
			}

			if(!IsSimpleColumn(c, name))
			{
				return !reservedNames.Contains(name);
			}

			return true;
		}
		internal override SqlExpression VisitColumn(SqlColumn c)
		{
			if(!_isDebugMode)
			{
				throw Error.InvalidFormatNode("Column");
			}
			_commandStringBuilder.Append("COLUMN(");
			if(c.Expression != null)
			{
				this.Visit(c.Expression);
			}
			else
			{
				string aliasName = null;
				if(c.Alias != null)
				{
					if(c.Alias.Name == null)
					{
						if(!_names.TryGetValue(c.Alias, out aliasName))
						{
							aliasName = "A" + _names.Count;
							_names[c.Alias] = aliasName;
						}
					}
					else
					{
						aliasName = c.Alias.Name;
					}
				}
				_commandStringBuilder.Append(aliasName);
				_commandStringBuilder.Append(".");
				_commandStringBuilder.Append(c.Name);
			}
			_commandStringBuilder.Append(")");
			return c;
		}
		internal override SqlExpression VisitColumn(SqlColumn col)
		{
			SqlColumn n = new SqlColumn(col.ClrType, col.SqlType, col.Name, col.MetaMember, null, col.SourceExpression);
			this.nodeMap[col] = n;
			n.Expression = this.VisitExpression(col.Expression);
			n.Alias = (SqlAlias)this.Visit(col.Alias);
			return n;
		}
Beispiel #24
0
		/// <summary>
		/// An expression is a simple reprojection if it's a column node whose expression is null, or 
		/// whose expression is a column whose name matches the name of the given name or where
		/// where the given name is null or empty.
		/// </summary>
		/// <param name="c"></param>
		/// <returns></returns>
		private static bool IsSimpleColumn(SqlColumn c, string name)
		{
			if(c.Expression != null)
			{
				switch(c.Expression.NodeType)
				{
					case SqlNodeType.ColumnRef:
						var colRef = c.Expression as SqlColumnRef;
						return String.IsNullOrEmpty(name) || String.Compare(name, colRef.Column.Name, StringComparison.OrdinalIgnoreCase) == 0;
					default:
						return false;
				}
			}
			return true;
		}
Beispiel #25
0
        internal bool RefersToColumn(SqlExpression exp, SqlColumn col) {
#if DEBUG
            try {
                refersDepth++;
                System.Diagnostics.Debug.Assert(refersDepth < 20);
#endif
                if (exp != null) {
                    switch (exp.NodeType) {
                        case SqlNodeType.Column:
                            return exp == col || this.RefersToColumn(((SqlColumn)exp).Expression, col);
                        case SqlNodeType.ColumnRef:
                            SqlColumnRef cref = (SqlColumnRef)exp;
                            return cref.Column == col || this.RefersToColumn(cref.Column.Expression, col);
                        case SqlNodeType.ExprSet:
                            SqlExprSet set = (SqlExprSet)exp;
                            for (int i = 0, n = set.Expressions.Count; i < n; i++) {
                                if (this.RefersToColumn(set.Expressions[i], col)) {
                                    return true;
                                }
                            }
                            break;
                        case SqlNodeType.OuterJoinedValue:
                            return this.RefersToColumn(((SqlUnary)exp).Operand, col);
                    }
                }

                return false;
#if DEBUG
            }
            finally {
                refersDepth--;
            }
#endif
        }
Beispiel #26
0
		internal override SqlExpression VisitColumn(SqlColumn col)
		{
			_aliasMap[col] = _currentAlias;
			this.Visit(col.Expression);
			return col;
		}
		internal override SqlExpression VisitColumn(SqlColumn col)
		{
			return new SqlColumnRef(col);
		}
		private SqlSelect GenerateSkipTake(SqlSelect sequence, SqlExpression skipExp, SqlExpression takeExp)
		{
			SqlSelect select = this.LockSelect(sequence);

			// no skip?
			if(skipExp == null)
			{
				if(takeExp != null)
				{
					select.Top = takeExp;
				}
				return select;
			}

			SqlAlias alias = new SqlAlias(select);
			SqlAliasRef aref = new SqlAliasRef(alias);

			if(this.UseConverterStrategy(ConverterStrategy.SkipWithRowNumber))
			{
				// use ROW_NUMBER() (preferred)
				SqlColumn rowNumber = new SqlColumn("ROW_NUMBER", _nodeFactory.RowNumber(new List<SqlOrderExpression>(), _dominatingExpression));
				SqlColumnRef rowNumberRef = new SqlColumnRef(rowNumber);

				select.Row.Columns.Add(rowNumber);

				SqlSelect final = new SqlSelect(aref, alias, _dominatingExpression);

				if(takeExp != null)
				{
					// use BETWEEN for skip+take combo (much faster)
					final.Where = _nodeFactory.Between(
						rowNumberRef,
						_nodeFactory.Add(skipExp, 1),
						_nodeFactory.Binary(SqlNodeType.Add, (SqlExpression)SqlDuplicator.Copy(skipExp), takeExp),
						_dominatingExpression
						);
				}
				else
				{
					final.Where = _nodeFactory.Binary(SqlNodeType.GT, rowNumberRef, skipExp);
				}

				return final;
			}
			else
			{
				// Ensure that the sequence contains elements that can be skipped
				if(!CanSkipOnSelection(select.Selection))
				{
					throw Error.SkipNotSupportedForSequenceTypes();
				}

				// use NOT EXISTS

				// Supported cases:
				//  - Entities
				//  - Projections that contain all PK columns
				//
				// .. where there sequence can be traced back to a:
				//  - Single-table query
				//  - Distinct
				//  - Except
				//  - Intersect
				//  - Union, where union.All == false

				// Not supported: joins

				// Sequence should also be ordered, but we can't test for it at this 
				// point in processing, and we won't know that we need to test it, later.

				SingleTableQueryVisitor stqv = new SingleTableQueryVisitor();
				stqv.Visit(select);
				if(!stqv.IsValid)
				{
					throw Error.SkipRequiresSingleTableQueryWithPKs();
				}

				SqlSelect dupsel = (SqlSelect)SqlDuplicator.Copy(select);
				dupsel.Top = skipExp;

				SqlAlias dupAlias = new SqlAlias(dupsel);
				SqlAliasRef dupRef = new SqlAliasRef(dupAlias);

				SqlSelect eqsel = new SqlSelect(dupRef, dupAlias, _dominatingExpression);
				eqsel.Where = _nodeFactory.Binary(SqlNodeType.EQ2V, aref, dupRef);
				SqlSubSelect ss = _nodeFactory.SubSelect(SqlNodeType.Exists, eqsel);

				SqlSelect final = new SqlSelect(aref, alias, _dominatingExpression);
				final.Where = _nodeFactory.Unary(SqlNodeType.Not, ss, _dominatingExpression);
				final.Top = takeExp;

				return final;
			}
		}
		private SqlColumn FindColumn(IEnumerable<SqlColumn> columns, SqlColumn col)
		{
			foreach(SqlColumn c in columns)
			{
				if(this.RefersToColumn(c, col))
				{
					return c;
				}
			}
			return null;
		}
Beispiel #30
0
		internal override SqlExpression VisitTableValuedFunctionCall(SqlTableValuedFunctionCall fc)
		{
			foreach(SqlColumn c in fc.Columns)
			{
				if(c == this.match)
				{
					if(this.found != null)
						throw Error.ColumnIsDefinedInMultiplePlaces(GetColumnName(this.match));
					this.found = c;
					break;
				}
			}
			return fc;
		}