internal override SqlExpression VisitAliasRef(SqlAliasRef aref)
		{
			if(this.ingoreExternalRefs && !this.nodeMap.ContainsKey(aref.Alias))
			{
				return aref;
			}
			return new SqlAliasRef((SqlAlias)this.Visit(aref.Alias));
		}
		internal override SqlExpression VisitAliasRef(SqlAliasRef aref)
		{
			SqlAlias alias = aref.Alias;
			SqlAlias value;
			if(_removedMap.TryGetValue(alias, out value))
			{
				throw Error.InvalidReferenceToRemovedAliasDuringDeflation();
			}
			return aref;
		}
		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;
		}
示例#4
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);
        }
		internal override SqlExpression VisitAliasRef(SqlAliasRef aref)
		{
			SqlNode node = aref.Alias.Node;
			if(node is SqlTable || node is SqlTableValuedFunctionCall)
			{
				return aref;
			}
			SqlUnion union = node as SqlUnion;
			if(union != null)
			{
				return this.ExpandUnion(union);
			}
			SqlSelect ss = node as SqlSelect;
			if(ss != null)
			{
				return this.VisitExpression(ss.Selection);
			}
			SqlExpression exp = node as SqlExpression;
			if(exp != null)
				return this.VisitExpression(exp);
			throw Error.CouldNotHandleAliasRef(node.NodeType);
		}
示例#6
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);
			}
		}
示例#7
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);
		}
示例#8
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;
		}
示例#9
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;
		}
示例#10
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);
		}
		/// <summary>
		/// Given a ClientCase and a list of sequence (one for each case), construct a structure
		/// that is equivalent to a CASE of SELECTs. To accomplish this we use UNION ALL and attach
		/// a WHERE clause which will pick the SELECT that matches the discriminator in the Client Case.
		/// </summary>
		private SqlSelect SimulateCaseOfSequences(SqlClientCase clientCase, List<SqlNode> sequences) {
			/*
                   * There are two situations we may be in:
                   * (1) There is exactly one case alternative. 
                   *     Here, no where clause is needed.
                   * (2) There is more than case alternative.
                   *     Here, each WHERE clause needs to be ANDed with [Disc]=D where D
                   *     is the literal discriminanator value.
                   */
			if (sequences.Count == 1) {
				return (SqlSelect)sequences[0];
			}
			else {
				SqlNode union = null;
				SqlSelect sel = null;
				int elseIndex = clientCase.Whens.Count - 1;
				int elseCount = clientCase.Whens[elseIndex].Match == null ? 1 : 0;
				SqlExpression elseFilter = null;
				for (int i = 0; i < sequences.Count - elseCount; ++i) {
					sel = (SqlSelect)sequences[i];
					SqlExpression discriminatorPredicate = sql.Binary(SqlNodeType.EQ, clientCase.Expression, clientCase.Whens[i].Match);
					sel.Where = sql.AndAccumulate(sel.Where, discriminatorPredicate);
					elseFilter = sql.AndAccumulate(elseFilter, sql.Binary(SqlNodeType.NE, clientCase.Expression, clientCase.Whens[i].Match));

					if (union == null) {
						union = sel;
					}
					else {
						union = new SqlUnion(sel, union, true /* Union All */);
					}
				}
				// Handle 'else' if present.
				if (elseCount == 1) {
					sel = (SqlSelect)sequences[elseIndex];
					sel.Where = sql.AndAccumulate(sel.Where, elseFilter);

					if (union == null) {
						union = sel;
					}
					else {
						union = new SqlUnion(sel, union, true /* Union All */);
					}

				}
				SqlAlias alias = new SqlAlias(union);
				SqlAliasRef aref = new SqlAliasRef(alias);
				return new SqlSelect(aref, alias, union.SourceExpression);
			}
		}
示例#12
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();
				}
			}
		}
		internal override SqlExpression VisitAliasRef(SqlAliasRef aref) {
			return this.ExpandExpression(aref);
		}
示例#14
0
 internal override SqlExpression VisitAliasRef(SqlAliasRef aref) {
     if (this.UnwrapSequences != null && this.UnwrapSequences.Unwrap) {
         this.UnwrapSequences = new UnwrapStack(this.UnwrapSequences, false);
         this.VisitAlias(aref.Alias);
         this.UnwrapSequences = this.UnwrapSequences.Last;
     } else {
         this.VisitAlias(aref.Alias);
     }
     return aref;
 }
示例#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;
		}
		private SqlNode AccessMember(SqlMember m, SqlExpression expo) {
			SqlExpression exp = expo;

			switch (exp.NodeType) {
				case SqlNodeType.ClientCase: {
					// Distribute into each case.
					SqlClientCase sc = (SqlClientCase)exp;
					Type newClrType = null;
					List<SqlExpression> matches = new List<SqlExpression>();
					List<SqlExpression> values = new List<SqlExpression>();
					foreach (SqlClientWhen when in sc.Whens) {
						SqlExpression newValue = (SqlExpression)AccessMember(m, when.Value);
						if (newClrType == null) {
							newClrType = newValue.ClrType;
						}
						else if (newClrType != newValue.ClrType) {
							throw Error.ExpectedClrTypesToAgree(newClrType, newValue.ClrType);
						}
						matches.Add(when.Match);
						values.Add(newValue);
					}

					SqlExpression result = sql.Case(newClrType, sc.Expression, matches, values, sc.SourceExpression);
					return result;
				}
				case SqlNodeType.SimpleCase: {
					// Distribute into each case.
					SqlSimpleCase sc = (SqlSimpleCase)exp;
					Type newClrType = null;
					List<SqlExpression> newMatches = new List<SqlExpression>();
					List<SqlExpression> newValues = new List<SqlExpression>();
					foreach (SqlWhen when in sc.Whens) {
						SqlExpression newValue = (SqlExpression)AccessMember(m, when.Value);
						if (newClrType == null) {
							newClrType = newValue.ClrType;
						}
						else if (newClrType != newValue.ClrType) {
							throw Error.ExpectedClrTypesToAgree(newClrType, newValue.ClrType);
						}
						newMatches.Add(when.Match);
						newValues.Add(newValue);
					}
					SqlExpression result = sql.Case(newClrType, sc.Expression, newMatches, newValues, sc.SourceExpression);
					return result;
				}
				case SqlNodeType.SearchedCase: {
					// Distribute into each case.
					SqlSearchedCase sc = (SqlSearchedCase)exp;
					List<SqlWhen> whens = new List<SqlWhen>(sc.Whens.Count);
					foreach (SqlWhen when in sc.Whens) {
						SqlExpression value = (SqlExpression)AccessMember(m, when.Value);
						whens.Add(new SqlWhen(when.Match, value));
					}
					SqlExpression @else = (SqlExpression)AccessMember(m, sc.Else);
					return sql.SearchedCase(whens.ToArray(), @else, sc.SourceExpression);
				}
				case SqlNodeType.TypeCase: {
					// We don't allow derived types to map members to different database fields.
					// Therefore, just pick the best SqlNew to call AccessMember on.
					SqlTypeCase tc = (SqlTypeCase)exp;

					// Find the best type binding for this member.
					SqlNew tb = tc.Whens[0].TypeBinding as SqlNew;
					foreach (SqlTypeCaseWhen when in tc.Whens) {
						if (when.TypeBinding.NodeType == SqlNodeType.New) {
							SqlNew sn = (SqlNew)when.TypeBinding;
							if (m.Member.DeclaringType.IsAssignableFrom(sn.ClrType)) {
								tb = sn;
								break;
							}
						}
					}
					return AccessMember(m, tb);
				}
				case SqlNodeType.AliasRef: {
					// convert alias.Member => column
					SqlAliasRef aref = (SqlAliasRef)exp;
					// if its a table, find the matching column
					SqlTable tab = aref.Alias.Node as SqlTable;
					if (tab != null) {
						MetaDataMember mm = GetRequiredInheritanceDataMember(tab.RowType, m.Member);
						Diagnostics.Debug.Assert(mm != null);
						string name = mm.MappedName;
						SqlColumn c = tab.Find(name);
						if (c == null) {
							ProviderType sqlType = sql.Default(mm);
							c = new SqlColumn(m.ClrType, sqlType, name, mm, null, m.SourceExpression);
							c.Alias = aref.Alias;
							tab.Columns.Add(c);
						}
						return new SqlColumnRef(c);
					}
					// if it is a table valued function, find the matching result column                                
					SqlTableValuedFunctionCall fc = aref.Alias.Node as SqlTableValuedFunctionCall;
					if (fc != null) {
						MetaDataMember mm = GetRequiredInheritanceDataMember(fc.RowType, m.Member);
						Diagnostics.Debug.Assert(mm != null);
						string name = mm.MappedName;
						SqlColumn c = fc.Find(name);
						if (c == null) {
							ProviderType sqlType = sql.Default(mm);
							c = new SqlColumn(m.ClrType, sqlType, name, mm, null, m.SourceExpression);
							c.Alias = aref.Alias;
							fc.Columns.Add(c);
						}
						return new SqlColumnRef(c);
					}
					break;
				}
				case SqlNodeType.OptionalValue:
					// convert option(exp).Member => exp.Member
					return this.AccessMember(m, ((SqlOptionalValue)exp).Value);

				case SqlNodeType.OuterJoinedValue: {
					SqlNode n = this.AccessMember(m, ((SqlUnary)exp).Operand);
					SqlExpression e = n as SqlExpression;
					if (e != null) return sql.Unary(SqlNodeType.OuterJoinedValue, e);
					return n;
				}

				case SqlNodeType.Lift:
					return this.AccessMember(m, ((SqlLift)exp).Expression);

				case SqlNodeType.UserRow: {
					// convert UserRow.Member => UserColumn
					SqlUserRow row = (SqlUserRow)exp;
					SqlUserQuery suq = row.Query;
					MetaDataMember mm = GetRequiredInheritanceDataMember(row.RowType, m.Member);
					Diagnostics.Debug.Assert(mm != null);
					string name = mm.MappedName;
					SqlUserColumn c = suq.Find(name);
					if (c == null) {
						ProviderType sqlType = sql.Default(mm);
						c = new SqlUserColumn(m.ClrType, sqlType, suq, name, mm.IsPrimaryKey, m.SourceExpression);
						suq.Columns.Add(c);
					}
					return c;
				}
				case SqlNodeType.New: {
					// convert (new {Member = expr}).Member => expr
					SqlNew sn = (SqlNew)exp;
					SqlExpression e = sn.Find(m.Member);
					if (e != null) {
						return e;
					}
					MetaDataMember mm = sn.MetaType.PersistentDataMembers.FirstOrDefault(p => p.Member == m.Member);
					if (!sn.SqlType.CanBeColumn && mm != null) {
						throw Error.MemberNotPartOfProjection(m.Member.DeclaringType, m.Member.Name);
					}
					break;
				}
				case SqlNodeType.Element:
				case SqlNodeType.ScalarSubSelect: {
					// convert Scalar/Element(select exp).Member => Scalar/Element(select exp.Member) / select exp.Member
					SqlSubSelect sub = (SqlSubSelect)exp;
					SqlAlias alias = new SqlAlias(sub.Select);
					SqlAliasRef aref = new SqlAliasRef(alias);

					SqlSelect saveSelect = this.currentSelect;
					try {
						SqlSelect newSelect = new SqlSelect(aref, alias, sub.SourceExpression);
						this.currentSelect = newSelect;
						SqlNode result = this.Visit(sql.Member(aref, m.Member));

						SqlExpression rexp = result as SqlExpression;
						if (rexp != null) {

							// If the expression is still a Member after being visited, but it cannot be a column, then it cannot be collapsed
							// into the SubSelect because we need to keep track of the fact that this member has to be accessed on the client.
							// This must be done after the expression has been Visited above, because otherwise we don't have
							// enough context to know if the member can be a column or not.
							if (rexp.NodeType == SqlNodeType.Member && !SqlColumnizer.CanBeColumn(rexp)) {
								// If the original member expression is an Element, optimize it by converting to an OuterApply if possible.
								// We have to do this here because we are creating a new member expression based on it, and there are no
								// subsequent visitors that will do this optimization.
								if (this.canUseOuterApply && exp.NodeType == SqlNodeType.Element && this.currentSelect != null) {
									// Reset the currentSelect since we are not going to use the previous SqlSelect that was created
									this.currentSelect = saveSelect;                                            
									this.currentSelect.From = sql.MakeJoin(SqlJoinType.OuterApply, this.currentSelect.From, alias, null, sub.SourceExpression);
									exp = this.VisitExpression(aref);
								}                                        
								return sql.Member(exp, m.Member);
							}

							// Since we are going to make a SubSelect out of this member expression, we need to make
							// sure it gets columnized before it gets to the PostBindDotNetConverter, otherwise only the
							// entire SubSelect will be columnized as a whole. Subsequent columnization does not know how to handle
							// any function calls that may be produced by the PostBindDotNetConverter, but we know how to handle it here.
							newSelect.Selection = rexp;
							newSelect.Selection = this.columnizer.ColumnizeSelection(newSelect.Selection);
							newSelect.Selection = this.ConvertLinks(newSelect.Selection);
							SqlNodeType subType = (rexp is SqlTypeCase || !rexp.SqlType.CanBeColumn) ? SqlNodeType.Element : SqlNodeType.ScalarSubSelect;
							SqlSubSelect subSel = sql.SubSelect(subType, newSelect);
							return this.FoldSubquery(subSel);
						}

						SqlSelect rselect = result as SqlSelect;
						if (rselect != null) {
							SqlAlias ralias = new SqlAlias(rselect);
							SqlAliasRef rref = new SqlAliasRef(ralias);
							newSelect.Selection = this.ConvertLinks(this.VisitExpression(rref));
							newSelect.From = new SqlJoin(SqlJoinType.CrossApply, alias, ralias, null, m.SourceExpression);
							return newSelect;
						}
						throw Error.UnexpectedNode(result.NodeType);
					}
					finally {
						this.currentSelect = saveSelect;
					}
				}
				case SqlNodeType.Value: {
					SqlValue val = (SqlValue)exp;
					if (val.Value == null) {
						return sql.Value(m.ClrType, m.SqlType, null, val.IsClientSpecified, m.SourceExpression);
					}
					else if (m.Member is PropertyInfo) {
						PropertyInfo p = (PropertyInfo)m.Member;
						return sql.Value(m.ClrType, m.SqlType, p.GetValue(val.Value, null), val.IsClientSpecified, m.SourceExpression);
					}
					else {
						FieldInfo f = (FieldInfo)m.Member;
						return sql.Value(m.ClrType, m.SqlType, f.GetValue(val.Value), val.IsClientSpecified, m.SourceExpression);
					}
				}
				case SqlNodeType.Grouping: {
					SqlGrouping g = ((SqlGrouping)exp);
					if (m.Member.Name == "Key") {
						return g.Key;
					}
					break;
				}
				case SqlNodeType.ClientParameter: {
					SqlClientParameter cp = (SqlClientParameter)exp;
					// create new accessor including this member access
					LambdaExpression accessor =
						Expression.Lambda(
										  typeof(Func<,>).MakeGenericType(typeof(object[]), m.ClrType),
							Expression.MakeMemberAccess(cp.Accessor.Body, m.Member),
							cp.Accessor.Parameters
							);
					return new SqlClientParameter(m.ClrType, m.SqlType, accessor, cp.SourceExpression);
				}
				default:
					break;  
			}
			if (m.Expression == exp) {
				return m;
			}
			else {
				return sql.Member(exp, m.Member);
			}
		}
		private SqlExpression FoldSubquery(SqlSubSelect ss) {
			// convert ELEMENT(SELECT MULTISET(SELECT xxx FROM t1 WHERE p1) FROM t2 WHERE p2)
			// into MULTISET(SELECT xxx FROM t2 CA (SELECT xxx FROM t1 WHERE p1) WHERE p2))
			while (true) {
				if (ss.NodeType == SqlNodeType.Element && ss.Select.Selection.NodeType == SqlNodeType.Multiset) {
					SqlSubSelect msub = (SqlSubSelect)ss.Select.Selection;
					SqlAlias alias = new SqlAlias(msub.Select);
					SqlAliasRef aref = new SqlAliasRef(alias);
					SqlSelect sel = ss.Select;
					sel.Selection = this.ConvertLinks(this.VisitExpression(aref));
					sel.From = new SqlJoin(SqlJoinType.CrossApply, sel.From, alias, null, ss.SourceExpression);
					SqlSubSelect newss = sql.SubSelect(SqlNodeType.Multiset, sel, ss.ClrType);
					ss = newss;
				}
				else if (ss.NodeType == SqlNodeType.Element && ss.Select.Selection.NodeType == SqlNodeType.Element) {
					SqlSubSelect msub = (SqlSubSelect)ss.Select.Selection;
					SqlAlias alias = new SqlAlias(msub.Select);
					SqlAliasRef aref = new SqlAliasRef(alias);
					SqlSelect sel = ss.Select;
					sel.Selection = this.ConvertLinks(this.VisitExpression(aref));
					sel.From = new SqlJoin(SqlJoinType.CrossApply, sel.From, alias, null, ss.SourceExpression);
					SqlSubSelect newss = sql.SubSelect(SqlNodeType.Element, sel);
					ss = newss;
				}
				else {
					break;
				}
			}
			return ss;
		}
		internal override SqlExpression VisitAliasRef(SqlAliasRef aref)
		{
			_commandStringBuilder.Append("AREF(");
			this.WriteAliasName(aref.Alias);
			_commandStringBuilder.Append(")");
			return aref;
		}
示例#19
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);
			}
		}
示例#20
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;
		}
示例#21
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;
			}
		}
示例#22
0
		internal override SqlExpression VisitAliasRef(SqlAliasRef aref)
		{
			throw Error.UnexpectedNode(aref.NodeType);
		}
示例#23
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;
		}
示例#24
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;
			}
		}
示例#25
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);
		}
示例#26
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;
		}
示例#27
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);
		}
示例#28
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;
		}
示例#29
0
 internal virtual SqlExpression VisitAliasRef(SqlAliasRef aref) {
     return aref;
 }
示例#30
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;
		}