internal override SqlExpression VisitMultiset(SqlSubSelect sms)
		{
			// allow one big-join per query?
			if((this.options & SqlMultiplexerOptionType.EnableBigJoin) != 0 &&
			   !this.hasBigJoin && this.canJoin && this.isTopLevel && this.outerSelect != null
			   && !MultisetChecker.HasMultiset(sms.Select.Selection)
			   && BigJoinChecker.CanBigJoin(sms.Select))
			{

				sms.Select = this.VisitSelect(sms.Select);

				SqlAlias alias = new SqlAlias(sms.Select);
				SqlJoin join = new SqlJoin(SqlJoinType.OuterApply, this.outerSelect.From, alias, null, sms.SourceExpression);
				this.outerSelect.From = @join;
				this.outerSelect.OrderingType = SqlOrderingType.Always;

				// make joined expression
				SqlExpression expr = (SqlExpression)SqlDuplicator.Copy(sms.Select.Selection);

				// make count expression
				SqlSelect copySelect = (SqlSelect)SqlDuplicator.Copy(sms.Select);
				SqlAlias copyAlias = new SqlAlias(copySelect);
				SqlSelect countSelect = new SqlSelect(sql.Unary(SqlNodeType.Count, null, sms.SourceExpression), copyAlias, sms.SourceExpression);
				countSelect.OrderingType = SqlOrderingType.Never;
				SqlExpression count = sql.SubSelect(SqlNodeType.ScalarSubSelect, countSelect);

				// make joined collection
				SqlJoinedCollection jc = new SqlJoinedCollection(sms.ClrType, sms.SqlType, expr, count, sms.SourceExpression);
				this.hasBigJoin = true;
				return jc;
			}
			return QueryExtractor.Extract(sms, this.parentParameters);
		}
示例#2
0
 internal override SqlAlias VisitAlias(SqlAlias sqlAlias) {
     SqlAlias save = this.alias;
     this.alias = sqlAlias;
     sqlAlias.Node = this.Visit(sqlAlias.Node);
     this.alias = save;
     return sqlAlias;
 }
示例#3
0
		internal override SqlAlias VisitAlias(SqlAlias a)
		{
			SqlAlias save = _currentAlias;
			_currentAlias = a;
			base.VisitAlias(a);
			_currentAlias = save;
			return a;
		}
		internal override SqlAlias VisitAlias(SqlAlias a)
		{
			SqlAlias n = new SqlAlias(a.Node);
			this.nodeMap[a] = n;
			n.Node = this.Visit(a.Node);
			n.Name = a.Name;
			return n;
		}
示例#5
0
 internal SqlAliasRef(SqlAlias alias)
     : base(SqlNodeType.AliasRef, GetClrType(alias.Node), alias.SourceExpression)
 {
     if (alias == null)
     {
         throw Error.ArgumentNull("alias");
     }
     this.alias = alias;
 }
		internal override SqlExpression VisitAliasRef(SqlAliasRef aref) {
			SqlExpression result = base.VisitAliasRef(aref);
			if (result != null && result == aref) {
				// reference to outer scope, don't propogate references to expressions or aliases
				SqlAlias alias = aref.Alias;
				SqlAlias newalias = new SqlAlias(new SqlNop(aref.ClrType, aref.SqlType, null));
				return new SqlAliasRef(newalias);
			}
			return result;
		}
		internal override SqlExpression VisitScalarSubSelect(SqlSubSelect ss)
		{
			SqlSelect innerSelect = this.VisitSelect(ss.Select);
			if(!this.aggregateChecker.HasAggregates(innerSelect))
			{
				innerSelect.Top = this.sql.ValueFromObject(1, ss.SourceExpression);
			}
			innerSelect.OrderingType = SqlOrderingType.Blocked;
			SqlAlias alias = new SqlAlias(innerSelect);
			this.currentSelect.From = new SqlJoin(SqlJoinType.OuterApply, this.currentSelect.From, alias, null, ss.SourceExpression);
			return new SqlColumnRef(innerSelect.Row.Columns[0]);
		}
示例#8
0
        internal SqlSelect BuildDefaultQuery(MetaType rowType, bool allowDeferred, SqlLink link, Expression source) {
            System.Diagnostics.Debug.Assert(rowType != null && rowType.Table != null);
            if (rowType.HasInheritance && rowType.InheritanceRoot != rowType) {
                // RowType is expected to be an inheritance root.
                throw Error.ArgumentWrongValue("rowType");
            }
            SqlTable table = sql.Table(rowType.Table, rowType, source);
            SqlAlias tableAlias = new SqlAlias(table);
            SqlAliasRef tableAliasRef = new SqlAliasRef(tableAlias);

            SqlExpression projection = this.BuildProjection(tableAliasRef, table.RowType, allowDeferred, link, source);
            return new SqlSelect(projection, tableAlias, source);
        }
示例#9
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 SqlAlias VisitAliasConsumed(SqlAlias a) {
                if (a == null)
                    return a;

                bool match = false;
                foreach (SqlAlias alias in aliases)
                    if (alias == a) {
                        match = true;
                        break;
                    }

                if (match) {
                    this.referencesAnyMatchingAliases = true;
                }

                return a;
            }
示例#11
0
		private SqlSelect VisitJoin(Expression outerSequence, Expression innerSequence, LambdaExpression outerKeySelector, LambdaExpression innerKeySelector, LambdaExpression resultSelector)
		{
			SqlSelect outerSelect = this.VisitSequence(outerSequence);
			SqlSelect innerSelect = this.VisitSequence(innerSequence);

			SqlAlias outerAlias = new SqlAlias(outerSelect);
			SqlAliasRef outerRef = new SqlAliasRef(outerAlias);
			SqlAlias innerAlias = new SqlAlias(innerSelect);
			SqlAliasRef innerRef = new SqlAliasRef(innerAlias);

			_parameterExpressionToSqlExpression[outerKeySelector.Parameters[0]] = outerRef;
			SqlExpression outerKey = this.VisitExpression(outerKeySelector.Body);

			_parameterExpressionToSqlExpression[innerKeySelector.Parameters[0]] = innerRef;
			SqlExpression innerKey = this.VisitExpression(innerKeySelector.Body);

			_parameterExpressionToSqlExpression[resultSelector.Parameters[0]] = outerRef;
			_parameterExpressionToSqlExpression[resultSelector.Parameters[1]] = innerRef;
			SqlExpression result = this.VisitExpression(resultSelector.Body);

			SqlExpression condition = _nodeFactory.Binary(SqlNodeType.EQ, outerKey, innerKey);
			SqlSelect select = null;
			if((_converterStrategy & ConverterStrategy.CanUseJoinOn) != 0)
			{
				SqlJoin join = new SqlJoin(SqlJoinType.Inner, outerAlias, innerAlias, condition, _dominatingExpression);
				select = new SqlSelect(result, join, _dominatingExpression);
			}
			else
			{
				SqlJoin join = new SqlJoin(SqlJoinType.Cross, outerAlias, innerAlias, null, _dominatingExpression);
				select = new SqlSelect(result, join, _dominatingExpression);
				select.Where = condition;
			}
			return select;
		}
示例#12
0
		private SqlSelect VisitSelectMany(Expression sequence, LambdaExpression colSelector, LambdaExpression resultSelector)
		{
			SqlSelect seqSelect = this.VisitSequence(sequence);
			SqlAlias seqAlias = new SqlAlias(seqSelect);
			SqlAliasRef seqRef = new SqlAliasRef(seqAlias);

			_parameterExpressionToSqlExpression[colSelector.Parameters[0]] = seqRef;

			SqlNode colSelectorNode = this.VisitSequence(colSelector.Body);
			SqlAlias selAlias = new SqlAlias(colSelectorNode);
			SqlAliasRef selRef = new SqlAliasRef(selAlias);
			SqlJoin join = new SqlJoin(SqlJoinType.CrossApply, seqAlias, selAlias, null, _dominatingExpression);

			SqlExpression projection = selRef;

			if(resultSelector != null)
			{
				_parameterExpressionToSqlExpression[resultSelector.Parameters[0]] = seqRef;
				_parameterExpressionToSqlExpression[resultSelector.Parameters[1]] = selRef;
				projection = this.VisitExpression(resultSelector.Body);
			}

			return new SqlSelect(projection, join, _dominatingExpression);
		}
示例#13
0
		private SqlSelect VisitSelect(Expression sequence, LambdaExpression selector)
		{
			SqlSelect source = this.VisitSequence(sequence);
			SqlAlias alias = new SqlAlias(source);
			SqlAliasRef aref = new SqlAliasRef(alias);

			_parameterExpressionToSqlExpression[selector.Parameters[0]] = aref;
			SqlNode project = this.Visit(selector.Body);

			SqlSelect pselect = project as SqlSelect;
			if(pselect != null)
			{
				return new SqlSelect(_nodeFactory.SubSelect(SqlNodeType.Multiset, pselect, selector.Body.Type), alias, _dominatingExpression);
			}
			else if((project.NodeType == SqlNodeType.Element || project.NodeType == SqlNodeType.ScalarSubSelect) &&
					 (_converterStrategy & ConverterStrategy.CanUseOuterApply) != 0)
			{
				SqlSubSelect sub = (SqlSubSelect)project;
				SqlSelect inner = sub.Select;
				SqlAlias innerAlias = new SqlAlias(inner);
				SqlAliasRef innerRef = new SqlAliasRef(innerAlias);
				if(project.NodeType == SqlNodeType.Element)
				{
					inner.Selection = new SqlOptionalValue(
						new SqlColumn(
							"test",
							_nodeFactory.Unary(
								SqlNodeType.OuterJoinedValue,
								_nodeFactory.Value(typeof(int?), _typeProvider.From(typeof(int)), 1, false, _dominatingExpression)
								)
							),
							_nodeFactory.Unary(SqlNodeType.OuterJoinedValue, inner.Selection)
						);
				}
				else
				{
					inner.Selection = _nodeFactory.Unary(SqlNodeType.OuterJoinedValue, inner.Selection);
				}
				SqlJoin join = new SqlJoin(SqlJoinType.OuterApply, alias, innerAlias, null, _dominatingExpression);
				return new SqlSelect(innerRef, join, _dominatingExpression);
			}
			else
			{
				SqlExpression expr = project as SqlExpression;
				if(expr != null)
				{
					return new SqlSelect(expr, alias, _dominatingExpression);
				}
				else
				{
					throw Error.BadProjectionInSelect();
				}
			}
		}
示例#14
0
		private SqlSelect CoerceToSequence(SqlNode node)
		{
			SqlSelect select = node as SqlSelect;
			if(select == null)
			{
				if(node.NodeType == SqlNodeType.Value)
				{
					SqlValue sv = (SqlValue)node;
					// Check for ITables.
					ITable t = sv.Value as ITable;
					if(t != null)
					{
						return this.CoerceToSequence(this.TranslateConstantTable(t, null));
					}
					// Check for IQueryable.
					IQueryable query = sv.Value as IQueryable;
					if(query != null)
					{
						Expression fex = Funcletizer.Funcletize(query.Expression);
						// IQueryables that return self-referencing Constant expressions cause infinite recursion
						if(fex.NodeType != ExpressionType.Constant ||
							((ConstantExpression)fex).Value != query)
						{
							return this.VisitSequence(fex);
						}
						throw Error.IQueryableCannotReturnSelfReferencingConstantExpression();
					}
					throw Error.CapturedValuesCannotBeSequences();
				}
				else if(node.NodeType == SqlNodeType.Multiset || node.NodeType == SqlNodeType.Element)
				{
					return ((SqlSubSelect)node).Select;
				}
				else if(node.NodeType == SqlNodeType.ClientArray)
				{
					throw Error.ConstructedArraysNotSupported();
				}
				else if(node.NodeType == SqlNodeType.ClientParameter)
				{
					throw Error.ParametersCannotBeSequences();
				}
				// this needs to be a sequence expression!
				SqlExpression sqlExpr = (SqlExpression)node;
				SqlAlias sa = new SqlAlias(sqlExpr);
				SqlAliasRef aref = new SqlAliasRef(sa);
				return new SqlSelect(aref, sa, _dominatingExpression);
			}
			return select;
		}
示例#15
0
		private SqlSelect LockSelect(SqlSelect sel)
		{
			if(sel.Selection.NodeType != SqlNodeType.AliasRef ||
				sel.Where != null ||
				sel.OrderBy.Count > 0 ||
				sel.GroupBy.Count > 0 ||
				sel.Having != null ||
				sel.Top != null ||
				sel.OrderingType != SqlOrderingType.Default ||
				sel.IsDistinct)
			{
				SqlAlias alias = new SqlAlias(sel);
				SqlAliasRef aref = new SqlAliasRef(alias);
				return new SqlSelect(aref, alias, _dominatingExpression);
			}
			return sel;
		}
示例#16
0
		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;
			}
		}
示例#17
0
		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);
			}
		}
示例#18
0
		private SqlNode VisitQuantifier(SqlSelect select, LambdaExpression lambda, bool isAny)
		{
			SqlAlias alias = new SqlAlias(select);
			SqlAliasRef aref = new SqlAliasRef(alias);
			if(lambda != null)
			{
				_parameterExpressionToSqlExpression[lambda.Parameters[0]] = aref;
			}
			SqlExpression cond = lambda != null ? this.VisitExpression(lambda.Body) : null;
			return this.GenerateQuantifier(alias, cond, isAny);
		}
		internal void VisitAliasConsumed(SqlAlias a)
		{
			_consumed.Add(a);
		}
		private void WriteAliasName(SqlAlias alias)
		{
			string aliasName = null;
			if(alias.Name == null)
			{
				if(!_names.TryGetValue(alias, out aliasName))
				{
					aliasName = "A" + _names.Count;
					_names[alias] = aliasName;
				}
			}
			else
			{
				aliasName = alias.Name;
			}
			this.WriteName(aliasName);
		}
示例#21
0
		private SqlNode VisitExcept(Expression source1, Expression source2)
		{
			Type type = TypeSystem.GetElementType(source1.Type);
			if(IsGrouping(type))
			{
				throw Error.ExceptNotSupportedForHierarchicalTypes();
			}

			SqlSelect select1 = this.LockSelect(this.VisitSequence(source1));
			SqlSelect select2 = this.VisitSequence(source2);

			SqlAlias alias1 = new SqlAlias(select1);
			SqlAliasRef aref1 = new SqlAliasRef(alias1);

			SqlAlias alias2 = new SqlAlias(select2);
			SqlAliasRef aref2 = new SqlAliasRef(alias2);

			SqlExpression any = this.GenerateQuantifier(alias2, _nodeFactory.Binary(SqlNodeType.EQ2V, aref1, aref2), true);

			SqlSelect result = new SqlSelect(aref1, alias1, select1.SourceExpression);
			result.Where = _nodeFactory.Unary(SqlNodeType.Not, any);
			result.IsDistinct = true;
			result.OrderingType = SqlOrderingType.Blocked;
			return result;
		}
示例#22
0
		private SqlNode VisitUnion(Expression source1, Expression source2)
		{
			SqlSelect left = this.VisitSequence(source1);
			SqlSelect right = this.VisitSequence(source2);
			SqlUnion union = new SqlUnion(left, right, false);
			SqlAlias alias = new SqlAlias(union);
			SqlAliasRef aref = new SqlAliasRef(alias);
			SqlSelect result = new SqlSelect(aref, alias, _dominatingExpression);
			result.OrderingType = SqlOrderingType.Blocked;
			return result;
		}
示例#23
0
		/// <summary>
		/// Translate a call to a table valued function expression into a sql select.
		/// </summary>             
		private SqlNode TranslateTableValuedFunction(MethodCallExpression mce, MetaFunction function)
		{
			// translate method call into sql function call
			List<SqlExpression> sqlParams = GetFunctionParameters(mce, function);
			SqlTableValuedFunctionCall functionCall = _nodeFactory.TableValuedFunctionCall(function.ResultRowTypes[0].InheritanceRoot, mce.Method.ReturnType, function.MappedName, sqlParams, mce);

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

			// Build default projection           
			SqlExpression projection = _translator.BuildProjection(aref, function.ResultRowTypes[0].InheritanceRoot, _allowDeferred, null, mce);

			SqlSelect select = new SqlSelect(projection, alias, mce);
			return select;
		}
示例#24
0
		private SqlSelect VisitGroupJoin(Expression outerSequence, Expression innerSequence, LambdaExpression outerKeySelector, LambdaExpression innerKeySelector, LambdaExpression resultSelector)
		{
			SqlSelect outerSelect = this.VisitSequence(outerSequence);
			SqlSelect innerSelect = this.VisitSequence(innerSequence);

			SqlAlias outerAlias = new SqlAlias(outerSelect);
			SqlAliasRef outerRef = new SqlAliasRef(outerAlias);
			SqlAlias innerAlias = new SqlAlias(innerSelect);
			SqlAliasRef innerRef = new SqlAliasRef(innerAlias);

			_parameterExpressionToSqlExpression[outerKeySelector.Parameters[0]] = outerRef;
			SqlExpression outerKey = this.VisitExpression(outerKeySelector.Body);

			_parameterExpressionToSqlExpression[innerKeySelector.Parameters[0]] = innerRef;
			SqlExpression innerKey = this.VisitExpression(innerKeySelector.Body);

			// make multiset 
			SqlExpression pred = _nodeFactory.Binary(SqlNodeType.EQ, outerKey, innerKey);
			SqlSelect select = new SqlSelect(innerRef, innerAlias, _dominatingExpression);
			select.Where = pred;
			SqlSubSelect subquery = _nodeFactory.SubSelect(SqlNodeType.Multiset, select);

			// make outer ref & multiset for result-selector params
			_parameterExpressionToSqlExpression[resultSelector.Parameters[0]] = outerRef;
			_parameterExpressionToSqlNode[resultSelector.Parameters[1]] = subquery;
			SqlExpression result = this.VisitExpression(resultSelector.Body);

			return new SqlSelect(result, outerAlias, _dominatingExpression);
		}
示例#25
0
		private SqlExpression GenerateQuantifier(SqlAlias alias, SqlExpression cond, bool isAny)
		{
			SqlAliasRef aref = new SqlAliasRef(alias);
			if(isAny)
			{
				SqlSelect sel = new SqlSelect(aref, alias, _dominatingExpression);
				sel.Where = cond;
				sel.OrderingType = SqlOrderingType.Never;
				SqlSubSelect exists = _nodeFactory.SubSelect(SqlNodeType.Exists, sel);
				return exists;
			}
			else
			{
				SqlSelect sel = new SqlSelect(aref, alias, _dominatingExpression);
				SqlSubSelect ss = _nodeFactory.SubSelect(SqlNodeType.Exists, sel);
				sel.Where = _nodeFactory.Unary(SqlNodeType.Not2V, cond, _dominatingExpression);
				return _nodeFactory.Unary(SqlNodeType.Not, ss, _dominatingExpression);
			}
		}
示例#26
0
		private SqlSelect VisitDefaultIfEmpty(Expression sequence)
		{
			SqlSelect select = this.VisitSequence(sequence);
			SqlAlias alias = new SqlAlias(select);
			SqlAliasRef aliasRef = new SqlAliasRef(alias);

			SqlExpression opt = new SqlOptionalValue(
				new SqlColumn(
					"test",
					_nodeFactory.Unary(SqlNodeType.OuterJoinedValue,
						_nodeFactory.Value(typeof(int?), _typeProvider.From(typeof(int)), 1, false, _dominatingExpression)
						)
					),
					_nodeFactory.Unary(SqlNodeType.OuterJoinedValue, aliasRef)
				);
			SqlSelect optSelect = new SqlSelect(opt, alias, _dominatingExpression);

			alias = new SqlAlias(optSelect);
			aliasRef = new SqlAliasRef(alias);

			SqlExpression litNull = _nodeFactory.TypedLiteralNull(typeof(string), _dominatingExpression);
			SqlSelect selNull = new SqlSelect(litNull, null, _dominatingExpression);
			SqlAlias aliasNull = new SqlAlias(selNull);

			SqlJoin join = new SqlJoin(SqlJoinType.OuterApply, aliasNull, alias, null, _dominatingExpression);

			return new SqlSelect(aliasRef, join, _dominatingExpression);
		}
示例#27
0
		private SqlStatement VisitInsert(Expression item, LambdaExpression resultSelector)
		{
			if(item == null)
			{
				throw Error.ArgumentNull("item");
			}
			_dominatingExpression = item;

			MetaTable metaTable = _services.Model.GetTable(item.Type);
			Expression source = _services.Context.GetTable(metaTable.RowType.Type).Expression;

			MetaType itemMetaType = null;
			SqlNew sqlItem = null;

			// construct insert assignments from 'item' info
			ConstantExpression conItem = item as ConstantExpression;
			if(conItem == null)
			{
				throw Error.InsertItemMustBeConstant();
			}
			if(conItem.Value == null)
			{
				throw Error.ArgumentNull("item");
			}
			// construct insert based on constant value
			List<SqlMemberAssign> bindings = new List<SqlMemberAssign>();
			itemMetaType = metaTable.RowType.GetInheritanceType(conItem.Value.GetType());
			SqlExpression sqlExprItem = _nodeFactory.ValueFromObject(conItem.Value, true, source);
			foreach(MetaDataMember mm in itemMetaType.PersistentDataMembers)
			{
				if(!mm.IsAssociation && !mm.IsDbGenerated && !mm.IsVersion)
				{
					bindings.Add(new SqlMemberAssign(mm.Member, _nodeFactory.Member(sqlExprItem, mm.Member)));
				}
			}
			ConstructorInfo cons = itemMetaType.Type.GetConstructor(Type.EmptyTypes);
			System.Diagnostics.Debug.Assert(cons != null);
			sqlItem = _nodeFactory.New(itemMetaType, cons, null, null, bindings, item);

			SqlTable tab = _nodeFactory.Table(metaTable, metaTable.RowType, _dominatingExpression);
			SqlInsert sin = new SqlInsert(tab, sqlItem, item);

			if(resultSelector == null)
			{
				return sin;
			}
			else
			{
				MetaDataMember id = itemMetaType.DBGeneratedIdentityMember;
				bool isDbGenOnly = false;
				if(id != null)
				{
					isDbGenOnly = this.IsDbGeneratedKeyProjectionOnly(resultSelector.Body, id);
					if(id.Type == typeof(Guid) && (_converterStrategy & ConverterStrategy.CanOutputFromInsert) != 0)
					{
						sin.OutputKey = new SqlColumn(id.Type, _nodeFactory.Default(id), id.Name, id, null, _dominatingExpression);
						if(!isDbGenOnly)
						{
							sin.OutputToLocal = true;
						}
					}
				}

				SqlSelect result = null;
				SqlSelect preResult = null;
				SqlAlias tableAlias = new SqlAlias(tab);
				SqlAliasRef tableAliasRef = new SqlAliasRef(tableAlias);
				System.Diagnostics.Debug.Assert(resultSelector.Parameters.Count == 1);
				_parameterExpressionToSqlExpression.Add(resultSelector.Parameters[0], tableAliasRef);
				SqlExpression projection = this.VisitExpression(resultSelector.Body);

				// build select to return result
				SqlExpression pred = null;
				if(id != null)
				{
					pred = _nodeFactory.Binary(
							SqlNodeType.EQ,
							_nodeFactory.Member(tableAliasRef, id.Member),
							this.GetIdentityExpression(id, sin.OutputKey != null)
							);
				}
				else
				{
					SqlExpression itemExpression = this.VisitExpression(item);
					pred = _nodeFactory.Binary(SqlNodeType.EQ2V, tableAliasRef, itemExpression);
				}
				result = new SqlSelect(projection, tableAlias, resultSelector);
				result.Where = pred;

				// Since we're only projecting back a single generated key, we can
				// optimize the query to a simple selection (e.g. SELECT @@IDENTITY)
				// rather than selecting back from the table.
				if(id != null && isDbGenOnly)
				{
					if(sin.OutputKey == null)
					{
						SqlExpression exp = this.GetIdentityExpression(id, false);
						if(exp.ClrType != id.Type)
						{
							ProviderType sqlType = _nodeFactory.Default(id);
							exp = _nodeFactory.ConvertTo(id.Type, sqlType, exp);
						}
						// The result selector passed in was bound to the table -
						// we need to rebind to the single result as an array projection
						ParameterExpression p = Expression.Parameter(id.Type, "p");
						Expression[] init = new Expression[1] { Expression.Convert(p, typeof(object)) };
						NewArrayExpression arrExp = Expression.NewArrayInit(typeof(object), init);
						LambdaExpression rs = Expression.Lambda(arrExp, p);
						_parameterExpressionToSqlExpression.Add(p, exp);
						SqlExpression proj = this.VisitExpression(rs.Body);
						preResult = new SqlSelect(proj, null, rs);
					}
					else
					{
						// case handled in formatter automatically
					}
					result.DoNotOutput = true;
				}

				// combine insert & result into block
				SqlBlock block = new SqlBlock(_dominatingExpression);
				block.Statements.Add(sin);
				if(preResult != null)
				{
					block.Statements.Add(preResult);
				}
				block.Statements.Add(result);
				return block;
			}
		}
示例#28
0
		private SqlSelect VisitOrderBy(Expression sequence, LambdaExpression expression, SqlOrderType orderType)
		{
			if(IsGrouping(expression.Body.Type))
			{
				throw Error.GroupingNotSupportedAsOrderCriterion();
			}
			if(!_typeProvider.From(expression.Body.Type).IsOrderable)
			{
				throw Error.TypeCannotBeOrdered(expression.Body.Type);
			}

			SqlSelect select = this.LockSelect(this.VisitSequence(sequence));

			if(select.Selection.NodeType != SqlNodeType.AliasRef || select.OrderBy.Count > 0)
			{
				SqlAlias alias = new SqlAlias(select);
				SqlAliasRef aref = new SqlAliasRef(alias);
				select = new SqlSelect(aref, alias, _dominatingExpression);
			}

			_parameterExpressionToSqlExpression[expression.Parameters[0]] = (SqlAliasRef)select.Selection;
			SqlExpression expr = this.VisitExpression(expression.Body);

			select.OrderBy.Add(new SqlOrderExpression(orderType, expr));
			return select;
		}
示例#29
0
		internal SqlAliasRef(SqlAlias alias)
			: base(SqlNodeType.AliasRef, GetClrType(alias.Node), alias.SourceExpression) {
			if (alias == null)
				throw Error.ArgumentNull("alias");
			this.alias = alias;
			}
示例#30
0
 internal virtual SqlAlias VisitAlias(SqlAlias a) {
     a.Node = this.Visit(a.Node);
     return a;
 }
示例#31
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;
		}