private SqlSelect ProcessApplyViaSubqueries(ApplyProvider provider, SqlProvider left, SqlProvider right, bool shouldUseQueryReference) { var rightQuery = right.Request.Statement; SqlSelect query; if (shouldUseQueryReference) { var leftTable = left.PermanentReference; query = SqlDml.Select(leftTable); query.Columns.AddRange(leftTable.Columns.Cast <SqlColumn>()); } else { query = left.Request.Statement.ShallowClone(); } var isApplyExistence = provider.Right.Type == ProviderType.Existence || provider.Right.Type == ProviderType.Select && provider.Right.Sources[0].Type == ProviderType.Existence; if (isApplyExistence) { for (int i = 0; i < rightQuery.Columns.Count; i++) { var column = rightQuery.Columns[i]; if (provider.IsInlined) { var columnStub = SqlDml.ColumnStub(column); var userColumn = ExtractUserColumn(column); stubColumnMap.Add(columnStub, userColumn.Expression); column = columnStub; } query.Columns.Add(column); } } else { if (provider.IsInlined) { for (int i = 0; i < rightQuery.Columns.Count; i++) { var subquery = rightQuery.ShallowClone(); var sqlColumn = subquery.Columns[i]; if (IsColumnStub(sqlColumn)) { var columnStub = ExtractColumnStub(sqlColumn); subquery.Columns.Clear(); subquery.Columns.Add(columnStub.Column); query.Columns.Add(subquery, sqlColumn.Name); } else { var columnRef = (SqlColumnRef)sqlColumn; var column = columnRef.SqlColumn; subquery.Columns.Clear(); subquery.Columns.Add(column); var columnName = ProcessAliasedName(provider.Right.Header.Columns[i].Name); var userColumnRef = SqlDml.ColumnRef(SqlDml.Column(subquery), columnName); var columnStub = SqlDml.ColumnStub(userColumnRef); stubColumnMap.Add(columnStub, subquery); query.Columns.Add(columnStub); } } } else { for (int i = 0; i < rightQuery.Columns.Count; i++) { var subquery = rightQuery.ShallowClone(); var column = subquery.Columns[i]; if (IsColumnStub(column)) { var columnStub = ExtractColumnStub(column); subquery.Columns.Clear(); subquery.Columns.Add(columnStub.Column); query.Columns.Add(subquery, column.Name); } else { var columnRef = (SqlColumnRef)column; var sqlColumn = columnRef.SqlColumn; subquery.Columns.Clear(); subquery.Columns.Add(sqlColumn); query.Columns.Add(subquery, columnRef.Name); } } } } return(query); }
private static bool ShouldUseQueryReference(CompilableProvider origin, SqlProvider compiledSource) { var sourceSelect = compiledSource.Request.Statement; if (sourceSelect.From == null) { return(false); } var calculatedColumnIndexes = sourceSelect.Columns .Select((c, i) => IsCalculatedColumn(c) ? i : -1) .Where(i => i >= 0) .ToList(); var containsCalculatedColumns = calculatedColumnIndexes.Count > 0; var rowNumberIsUsed = calculatedColumnIndexes.Count > 0 && sourceSelect.Columns .Select((c, i) => new { c, i }) .Any(a => calculatedColumnIndexes.Contains(a.i) && ExtractUserColumn(a.c).Expression is SqlRowNumber); var pagingIsUsed = !sourceSelect.Limit.IsNullReference() || !sourceSelect.Offset.IsNullReference() || rowNumberIsUsed; var groupByIsUsed = sourceSelect.GroupBy.Count > 0; var distinctIsUsed = sourceSelect.Distinct; var filterIsUsed = !sourceSelect.Where.IsNullReference(); if (origin.Type == ProviderType.Filter) { var filterProvider = (FilterProvider)origin; var usedColumnIndexes = new TupleAccessGatherer().Gather(filterProvider.Predicate.Body); return(pagingIsUsed || usedColumnIndexes.Any(calculatedColumnIndexes.Contains)); } if (origin.Type == ProviderType.Select) { return(distinctIsUsed); } if (origin.Type == ProviderType.RowNumber) { var usedColumnIndexes = origin.Header.Order.Select(o => o.Key); return(pagingIsUsed || groupByIsUsed || distinctIsUsed || usedColumnIndexes.Any(calculatedColumnIndexes.Contains)); } if (origin.Type == ProviderType.Calculate) { var calculateProvider = (CalculateProvider)origin; var columnGatherer = new TupleAccessGatherer(); var usedColumnIndexes = new List <int>(); foreach (var column in calculateProvider.CalculatedColumns) { usedColumnIndexes.AddRange( columnGatherer.Gather(column.Expression.Body, column.Expression.Parameters[0])); } return(usedColumnIndexes.Any(calculatedColumnIndexes.Contains)); } if (origin.Type == ProviderType.Aggregate) { var aggregateProvider = (AggregateProvider)origin; var columnGatherer = new TupleAccessGatherer(); var usedColumnIndexes = (aggregateProvider.AggregateColumns ?? Enumerable.Empty <AggregateColumn>()) .Select(ac => ac.SourceIndex) .Concat(aggregateProvider.GroupColumnIndexes) .ToList(); return(usedColumnIndexes.Any(calculatedColumnIndexes.Contains) || pagingIsUsed || distinctIsUsed || groupByIsUsed); } if (origin.Type.In(ProviderType.Take, ProviderType.Skip, ProviderType.Paging)) { var sortProvider = origin.Sources[0] as SortProvider; var orderingOverCalculatedColumn = sortProvider != null && sortProvider.Header.Order .Select(order => order.Key) .Any(calculatedColumnIndexes.Contains); return(distinctIsUsed || pagingIsUsed || groupByIsUsed || orderingOverCalculatedColumn); } if (origin.Type == ProviderType.Apply) { return(containsCalculatedColumns || distinctIsUsed || pagingIsUsed || groupByIsUsed); } if (origin.Type == ProviderType.Join) { var shouldUseQueryReference = distinctIsUsed || pagingIsUsed || groupByIsUsed; if (shouldUseQueryReference) { return(true); } var joinProvider = (JoinProvider)origin; var isRight = joinProvider.Right == compiledSource.Origin; var indexes = joinProvider.EqualIndexes.Select(p => isRight ? p.Second : p.First); return((joinProvider.JoinType == JoinType.LeftOuter && filterIsUsed && isRight) || (containsCalculatedColumns && indexes.Any(calculatedColumnIndexes.Contains))); } if (origin.Type == ProviderType.PredicateJoin) { var shouldUseQueryReference = distinctIsUsed || pagingIsUsed || groupByIsUsed; if (shouldUseQueryReference) { return(true); } var joinProvider = (PredicateJoinProvider)origin; var isRight = joinProvider.Right == compiledSource.Origin; var indexes = new TupleAccessGatherer().Gather(joinProvider.Predicate.Body, joinProvider.Predicate.Parameters[isRight ? 1 : 0]); return((joinProvider.JoinType == JoinType.LeftOuter && filterIsUsed && isRight) || (containsCalculatedColumns && indexes.Any(calculatedColumnIndexes.Contains))); } if (origin.Type == ProviderType.Sort) { if (distinctIsUsed) { return(true); } var orderingOverCalculatedColumn = origin.Header.Order .Select(order => order.Key) .Any(calculatedColumnIndexes.Contains); return(orderingOverCalculatedColumn); } return(containsCalculatedColumns || distinctIsUsed || pagingIsUsed || groupByIsUsed); }
private SqlSelect ProcessApplyViaCrossApply(ApplyProvider provider, SqlProvider left, SqlProvider right) { var leftShouldUseReference = ShouldUseQueryReference(provider, left); var leftTable = leftShouldUseReference ? left.PermanentReference : left.Request.Statement.From; var leftColumns = leftShouldUseReference ? leftTable.Columns.Cast <SqlColumn>() : left.Request.Statement.Columns; var rightShouldUseReference = ShouldUseQueryReference(provider, right); var rightTable = rightShouldUseReference ? right.PermanentReference : right.Request.Statement.From; var rightColumns = rightShouldUseReference ? rightTable.Columns.Cast <SqlColumn>() : right.Request.Statement.Columns; var joinType = provider.ApplyType == JoinType.LeftOuter ? SqlJoinType.LeftOuterApply : SqlJoinType.CrossApply; var joinedTable = SqlDml.Join( joinType, leftTable, rightTable, leftColumns.ToList(), rightColumns.ToList()); var query = SqlDml.Select(joinedTable); if (!leftShouldUseReference) { query.Where &= left.Request.Statement.Where; } if (!rightShouldUseReference) { query.Where &= right.Request.Statement.Where; } query.Columns.AddRange(joinedTable.AliasedColumns); return(query); }