1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
|
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Data.Linq;
namespace System.Data.Linq.SqlClient {
// converts correlated scalar subqueries into outer-applies
// must be run after flattener.
internal class SqlRewriteScalarSubqueries {
Visitor visitor;
internal SqlRewriteScalarSubqueries(SqlFactory sqlFactory) {
this.visitor = new Visitor(sqlFactory);
}
internal SqlNode Rewrite(SqlNode node) {
return this.visitor.Visit(node);
}
class Visitor : SqlVisitor {
SqlFactory sql;
SqlSelect currentSelect;
SqlAggregateChecker aggregateChecker;
internal Visitor(SqlFactory sqlFactory) {
this.sql = sqlFactory;
this.aggregateChecker = new SqlAggregateChecker();
}
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]);
}
internal override SqlSelect VisitSelect(SqlSelect select) {
SqlSelect save = this.currentSelect;
try {
this.currentSelect = select;
return base.VisitSelect(select);
}
finally {
this.currentSelect = save;
}
}
}
}
}
|