Skip to content

Commit

Permalink
Query: Remove TpcTablesExpression once pruning is done (#28142)
Browse files Browse the repository at this point in the history
- Apply pruning on subqueries in set operation when not distinct
- Avoid table aliases which would be pruned in TPC later
- Avoid push down when left-joining with TPC select expression

Resolves npgsql/efcore.pg#2387
Resolves #28009
  • Loading branch information
smitpatel authored Jun 2, 2022
1 parent 7433fe6 commit f43f454
Show file tree
Hide file tree
Showing 22 changed files with 1,917 additions and 1,946 deletions.
2 changes: 1 addition & 1 deletion src/EFCore.Relational/Query/EntityProjectionExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public virtual EntityProjectionExpression UpdateEntityType(IEntityType derivedTy
var discriminatorExpression = DiscriminatorExpression;
if (DiscriminatorExpression is CaseExpression caseExpression)
{
var entityTypesToSelect = derivedType.GetConcreteDerivedTypesInclusive().Select(e => e.GetDiscriminatorValue()).ToList();
var entityTypesToSelect = derivedType.GetConcreteDerivedTypesInclusive().Select(e => (string)e.GetDiscriminatorValue()!).ToList();
var whenClauses = caseExpression.WhenClauses
.Where(wc => entityTypesToSelect.Contains((string)((SqlConstantExpression)wc.Result).Value!))
.ToList();
Expand Down
150 changes: 0 additions & 150 deletions src/EFCore.Relational/Query/Internal/TpcTablesExpression.cs

This file was deleted.

149 changes: 42 additions & 107 deletions src/EFCore.Relational/Query/QuerySqlGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.EntityFrameworkCore.Query.Internal;
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
using Microsoft.EntityFrameworkCore.Storage.Internal;

Expand Down Expand Up @@ -148,141 +147,77 @@ private static bool IsNonComposedSetOperation(SelectExpression selectExpression)
column.Name, setOperation.Source1.Projection[index].Alias, StringComparison.Ordinal))
.All(e => e);

private static bool IsNonComposedTpc(SelectExpression selectExpression)
=> selectExpression.Offset == null
&& selectExpression.Limit == null
&& !selectExpression.IsDistinct
&& selectExpression.Predicate == null
&& selectExpression.Having == null
&& selectExpression.Orderings.Count == 0
&& selectExpression.GroupBy.Count == 0
&& selectExpression.Tables.Count == 1
&& selectExpression.Tables[0] is TpcTablesExpression tpcTablesExpression
&& selectExpression.Projection.Count == tpcTablesExpression.SelectExpressions[0].Projection.Count
&& selectExpression.Projection.Select(
(pe, index) => pe.Expression is ColumnExpression column
&& string.Equals(column.TableAlias, tpcTablesExpression.Alias, StringComparison.Ordinal)
&& string.Equals(
column.Name, tpcTablesExpression.SelectExpressions[0].Projection[index].Alias, StringComparison.Ordinal))
.All(e => e);

/// <inheritdoc />
protected override Expression VisitExtension(Expression extensionExpression)
protected override Expression VisitSelect(SelectExpression selectExpression)
{
if (extensionExpression is TpcTablesExpression tpcTablesExpression)
IDisposable? subQueryIndent = null;
if (selectExpression.Alias != null)
{
_relationalCommandBuilder.AppendLine("(");
using (_relationalCommandBuilder.Indent())
{
GenerateList(tpcTablesExpression.SelectExpressions, e => Visit(e), e => e.AppendLine().AppendLine("UNION ALL"));
}
_relationalCommandBuilder.AppendLine()
.Append(")")
.Append(AliasSeparator)
.Append(_sqlGenerationHelper.DelimitIdentifier(tpcTablesExpression.Alias));

return tpcTablesExpression;
subQueryIndent = _relationalCommandBuilder.Indent();
}

return base.VisitExtension(extensionExpression);
}

/// <inheritdoc />
protected override Expression VisitSelect(SelectExpression selectExpression)
{
if (IsNonComposedSetOperation(selectExpression))
{
// Naked set operation
GenerateSetOperation((SetOperationBase)selectExpression.Tables[0]);

return selectExpression;
}

IDisposable? subQueryIndent = null;

if (IsNonComposedTpc(selectExpression))
else
{
var tpcTablesExpression = (TpcTablesExpression)selectExpression.Tables[0];
if (selectExpression.Alias != null)
_relationalCommandBuilder.Append("SELECT ");

if (selectExpression.IsDistinct)
{
_relationalCommandBuilder.AppendLine("(");
subQueryIndent = _relationalCommandBuilder.Indent();
_relationalCommandBuilder.Append("DISTINCT ");
}

GenerateList(tpcTablesExpression.SelectExpressions, e => Visit(e), e => e.AppendLine().AppendLine("UNION ALL"));
GenerateTop(selectExpression);

if (selectExpression.Alias != null)
if (selectExpression.Projection.Any())
{
subQueryIndent!.Dispose();

_relationalCommandBuilder.AppendLine()
.Append(")")
.Append(AliasSeparator)
.Append(_sqlGenerationHelper.DelimitIdentifier(selectExpression.Alias));
GenerateList(selectExpression.Projection, e => Visit(e));
}
else
{
_relationalCommandBuilder.Append("1");
}

return selectExpression;
}

if (selectExpression.Alias != null)
{
_relationalCommandBuilder.AppendLine("(");
subQueryIndent = _relationalCommandBuilder.Indent();
}

_relationalCommandBuilder.Append("SELECT ");

if (selectExpression.IsDistinct)
{
_relationalCommandBuilder.Append("DISTINCT ");
}

GenerateTop(selectExpression);

if (selectExpression.Projection.Any())
{
GenerateList(selectExpression.Projection, e => Visit(e));
}
else
{
_relationalCommandBuilder.Append("1");
}
if (selectExpression.Tables.Any())
{
_relationalCommandBuilder.AppendLine().Append("FROM ");

if (selectExpression.Tables.Any())
{
_relationalCommandBuilder.AppendLine().Append("FROM ");
GenerateList(selectExpression.Tables, e => Visit(e), sql => sql.AppendLine());
}
else
{
GeneratePseudoFromClause();
}

GenerateList(selectExpression.Tables, e => Visit(e), sql => sql.AppendLine());
}
else
{
GeneratePseudoFromClause();
}
if (selectExpression.Predicate != null)
{
_relationalCommandBuilder.AppendLine().Append("WHERE ");

if (selectExpression.Predicate != null)
{
_relationalCommandBuilder.AppendLine().Append("WHERE ");
Visit(selectExpression.Predicate);
}

Visit(selectExpression.Predicate);
}
if (selectExpression.GroupBy.Count > 0)
{
_relationalCommandBuilder.AppendLine().Append("GROUP BY ");

if (selectExpression.GroupBy.Count > 0)
{
_relationalCommandBuilder.AppendLine().Append("GROUP BY ");
GenerateList(selectExpression.GroupBy, e => Visit(e));
}

GenerateList(selectExpression.GroupBy, e => Visit(e));
}
if (selectExpression.Having != null)
{
_relationalCommandBuilder.AppendLine().Append("HAVING ");

if (selectExpression.Having != null)
{
_relationalCommandBuilder.AppendLine().Append("HAVING ");
Visit(selectExpression.Having);
}

Visit(selectExpression.Having);
GenerateOrderings(selectExpression);
GenerateLimitOffset(selectExpression);
}

GenerateOrderings(selectExpression);
GenerateLimitOffset(selectExpression);

if (selectExpression.Alias != null)
{
subQueryIndent!.Dispose();
Expand Down
Loading

0 comments on commit f43f454

Please sign in to comment.