Skip to content

Commit

Permalink
Generate Unique alias for table names
Browse files Browse the repository at this point in the history
  • Loading branch information
smitpatel committed Feb 17, 2016
1 parent 36f39a6 commit ef15f26
Show file tree
Hide file tree
Showing 24 changed files with 1,069 additions and 926 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ var targetTableExpression

var targetEntityType = navigation.GetTargetType();
var targetTableName = _relationalAnnotationProvider.For(targetEntityType).TableName;
var targetTableAlias = targetTableName[0].ToString().ToLower();
var targetTableAlias = _queryCompilationContext.CreateUniqueTableAlias(targetTableName[0].ToString().ToLower());

if (!navigation.IsCollection())
{
Expand Down Expand Up @@ -179,7 +179,7 @@ var materializer

selectExpression.Predicate = oldPredicate;
selectExpression.RemoveTable(joinExpression);
selectExpression.AddTable(newJoinExpression);
selectExpression.AddTable(newJoinExpression, createUniqueAlias: false);
joinExpression = newJoinExpression;
}

Expand Down Expand Up @@ -223,7 +223,7 @@ var principalTable
OrderingDirection.Asc);
}

var targetSelectExpression = _selectExpressionFactory.Create();
var targetSelectExpression = _selectExpressionFactory.Create(_queryCompilationContext);

targetTableExpression
= new TableExpression(
Expand All @@ -232,7 +232,7 @@ var principalTable
targetTableAlias,
querySource);

targetSelectExpression.AddTable(targetTableExpression);
targetSelectExpression.AddTable(targetTableExpression, createUniqueAlias: false);

var materializer
= _materializerFactory
Expand Down Expand Up @@ -290,8 +290,9 @@ var innerJoinSelectExpression
private JoinExpressionBase AdjustJoinExpression(
SelectExpression selectExpression, JoinExpressionBase joinExpression)
{
var subquery = new SelectExpression(_querySqlGeneratorFactory, joinExpression.Alias);
subquery.AddTable(joinExpression.TableExpression);
var subquery = new SelectExpression(_querySqlGeneratorFactory, _queryCompilationContext) { Alias = joinExpression.Alias };
// Don't create new alias when adding tables to subquery
subquery.AddTable(joinExpression.TableExpression, createUniqueAlias: false);
subquery.IsProjectStar = true;
subquery.Predicate = selectExpression.Predicate;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ protected override Expression VisitEntityQueryable(Type elementType)
var relationalQueryCompilationContext = QueryModelVisitor.QueryCompilationContext;
var entityType = _model.FindEntityType(elementType);

var selectExpression = _selectExpressionFactory.Create();
var selectExpression = _selectExpressionFactory.Create(relationalQueryCompilationContext);

QueryModelVisitor.AddQuery(_querySource, selectExpression);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ namespace Microsoft.EntityFrameworkCore.Query.Expressions
{
public interface ISelectExpressionFactory
{
SelectExpression Create();
SelectExpression Create([NotNull]RelationalQueryCompilationContext queryCompilationContext);

SelectExpression Create([NotNull] string alias);
SelectExpression Create([NotNull]RelationalQueryCompilationContext queryCompilationContext, [NotNull] string alias);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class SelectExpression : TableExpressionBase
#endif

private readonly IQuerySqlGeneratorFactory _querySqlGeneratorFactory;
private readonly RelationalQueryCompilationContext _queryCompilationContext;
private readonly List<Expression> _projection = new List<Expression>();
private readonly List<TableExpressionBase> _tables = new List<TableExpressionBase>();
private readonly List<Ordering> _orderBy = new List<Ordering>();
Expand All @@ -35,22 +36,27 @@ public class SelectExpression : TableExpressionBase

public virtual Expression Predicate { get; [param: CanBeNull] set; }

public SelectExpression([NotNull] IQuerySqlGeneratorFactory querySqlGeneratorFactory)
public SelectExpression([NotNull] IQuerySqlGeneratorFactory querySqlGeneratorFactory,
[NotNull] RelationalQueryCompilationContext queryCompilationContext)
: base(null, null)
{
Check.NotNull(querySqlGeneratorFactory, nameof(querySqlGeneratorFactory));
Check.NotNull(queryCompilationContext, nameof(queryCompilationContext));

_querySqlGeneratorFactory = querySqlGeneratorFactory;
_queryCompilationContext = queryCompilationContext;
}

public SelectExpression(
[NotNull] IQuerySqlGeneratorFactory querySqlGeneratorFactory,
[NotNull] RelationalQueryCompilationContext queryCompilationContext,
[NotNull] string alias)
: base(null, Check.NotNull(alias, nameof(alias)))
: this(querySqlGeneratorFactory, queryCompilationContext)
{
Check.NotNull(querySqlGeneratorFactory, nameof(querySqlGeneratorFactory));
Check.NotNull(alias, nameof(alias));

_querySqlGeneratorFactory = querySqlGeneratorFactory;
// When assigning alias to select expression make it unique
Alias = queryCompilationContext.CreateUniqueTableAlias(alias);
}

public override Type Type => _projection.Count == 1
Expand All @@ -62,7 +68,7 @@ public virtual SelectExpression Clone([NotNull] string alias)
Check.NotNull(alias, nameof(alias));

var selectExpression
= new SelectExpression(_querySqlGeneratorFactory, alias)
= new SelectExpression(_querySqlGeneratorFactory, _queryCompilationContext, alias)
{
_limit = _limit,
_offset = _offset,
Expand All @@ -84,13 +90,32 @@ var selectExpression

public virtual bool IsProjectStar { get; set; }

public virtual void AddTable([NotNull] TableExpressionBase tableExpression)
=> _tables.Add(Check.NotNull(tableExpression, nameof(tableExpression)));
public virtual void AddTable([NotNull] TableExpressionBase tableExpression, bool createUniqueAlias = true)
{
Check.NotNull(tableExpression, nameof(tableExpression));

if (createUniqueAlias)
{
tableExpression.Alias = _queryCompilationContext.CreateUniqueTableAlias(tableExpression.Alias);
}
_tables.Add(tableExpression);
}

public virtual void AddTables([NotNull] IEnumerable<TableExpressionBase> tableExpressions)
=> _tables.AddRange(Check.NotNull(tableExpressions, nameof(tableExpressions)));
{
Check.NotNull(tableExpressions, nameof(tableExpressions));

public virtual void ClearTables() => _tables.Clear();
// Multiple tables are added while moving current select expression inside subquery hence it does not need to generate unique alias
foreach (var tableExpression in tableExpressions.ToList())
{
AddTable(tableExpression, createUniqueAlias: false);
}
}

public virtual void ClearTables()
{
_tables.Clear();
}

public virtual bool IsCorrelated() => new CorrelationFindingExpressionVisitor().IsCorrelated(this);

Expand Down Expand Up @@ -229,7 +254,7 @@ public virtual SelectExpression PushDownSubquery()
{
_subqueryDepth++;

var subquery = new SelectExpression(_querySqlGeneratorFactory, SystemAliasPrefix + _subqueryDepth);
var subquery = new SelectExpression(_querySqlGeneratorFactory, _queryCompilationContext, SystemAliasPrefix);

var columnAliasCounter = 0;

Expand Down Expand Up @@ -277,7 +302,7 @@ public virtual SelectExpression PushDownSubquery()
ClearProjection();
ClearOrderBy();

AddTable(subquery);
AddTable(subquery, createUniqueAlias: false);

return subquery;
}
Expand Down Expand Up @@ -382,7 +407,7 @@ var projectionIndex

if (alias != null)
{
foreach (var orderByAliasExpression
foreach (var orderByAliasExpression
in _orderBy.Select(o => o.Expression).OfType<AliasExpression>())
{
if (orderByAliasExpression.TryGetColumnExpression() == null)
Expand Down Expand Up @@ -625,8 +650,6 @@ public virtual void AddCrossJoin(
Check.NotNull(tableExpression, nameof(tableExpression));
Check.NotNull(projection, nameof(projection));

tableExpression.Alias = CreateUniqueTableAlias(tableExpression.Alias);

_tables.Add(new CrossJoinExpression(tableExpression));
_projection.AddRange(projection);
}
Expand All @@ -638,8 +661,6 @@ public virtual void AddLateralJoin(
Check.NotNull(tableExpression, nameof(tableExpression));
Check.NotNull(projection, nameof(projection));

tableExpression.Alias = CreateUniqueTableAlias(tableExpression.Alias);

_tables.Add(new LateralJoinExpression(tableExpression));
_projection.AddRange(projection);
}
Expand All @@ -658,8 +679,6 @@ public virtual JoinExpressionBase AddInnerJoin(
Check.NotNull(tableExpression, nameof(tableExpression));
Check.NotNull(projection, nameof(projection));

tableExpression.Alias = CreateUniqueTableAlias(tableExpression.Alias);

var innerJoinExpression = new InnerJoinExpression(tableExpression);

_tables.Add(innerJoinExpression);
Expand All @@ -682,8 +701,6 @@ public virtual JoinExpressionBase AddOuterJoin(
Check.NotNull(tableExpression, nameof(tableExpression));
Check.NotNull(projection, nameof(projection));

tableExpression.Alias = CreateUniqueTableAlias(tableExpression.Alias);

var outerJoinExpression = new LeftOuterJoinExpression(tableExpression);

_tables.Add(outerJoinExpression);
Expand All @@ -692,31 +709,6 @@ public virtual JoinExpressionBase AddOuterJoin(
return outerJoinExpression;
}

public virtual string CreateUniqueTableAlias()
=> CreateUniqueTableAlias(SystemAliasPrefix);

private string CreateUniqueTableAlias(string currentAlias)
{
Debug.Assert(currentAlias != null);

var uniqueAlias = currentAlias;
var counter = 0;

int _;
if (currentAlias.StartsWith(SystemAliasPrefix, StringComparison.Ordinal)
&& int.TryParse(currentAlias.Substring(1), out _))
{
currentAlias = SystemAliasPrefix;
}

while (_tables.Any(t => string.Equals(t.Alias, uniqueAlias, StringComparison.OrdinalIgnoreCase)))
{
uniqueAlias = currentAlias + counter++;
}

return uniqueAlias;
}

private string CreateUniqueProjectionAlias(string currentAlias)
{
var uniqueAlias = currentAlias ?? "A";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ public SelectExpressionFactory([NotNull] IQuerySqlGeneratorFactory querySqlGener
_querySqlGeneratorFactory = querySqlGeneratorFactory;
}

public virtual SelectExpression Create()
=> new SelectExpression(_querySqlGeneratorFactory);
public virtual SelectExpression Create(RelationalQueryCompilationContext queryCompilationContext)
=> new SelectExpression(_querySqlGeneratorFactory, queryCompilationContext);

public virtual SelectExpression Create(string alias)
public virtual SelectExpression Create(RelationalQueryCompilationContext queryCompilationContext, string alias)
=> new SelectExpression(
_querySqlGeneratorFactory,
queryCompilationContext,
Check.NotEmpty(alias, nameof(alias)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ var predicate

if (predicate != null)
{
var innerSelectExpression = handlerContext.SelectExpressionFactory.Create();
var innerSelectExpression
= handlerContext.SelectExpressionFactory.Create(handlerContext.QueryModelVisitor.QueryCompilationContext);

innerSelectExpression.AddTables(handlerContext.SelectExpression.Tables);
innerSelectExpression.Predicate = Expression.Not(predicate);
Expand Down Expand Up @@ -194,7 +195,7 @@ var predicate

private static Expression HandleAny(HandlerContext handlerContext)
{
var innerSelectExpression = handlerContext.SelectExpressionFactory.Create();
var innerSelectExpression = handlerContext.SelectExpressionFactory.Create(handlerContext.QueryModelVisitor.QueryCompilationContext);

innerSelectExpression.AddTables(handlerContext.SelectExpression.Tables);
innerSelectExpression.Predicate = handlerContext.SelectExpression.Predicate;
Expand Down Expand Up @@ -235,14 +236,14 @@ var filteringVisitor

if (entityType != null)
{
var outterSelectExpression = handlerContext.SelectExpressionFactory.Create();
var outterSelectExpression = handlerContext.SelectExpressionFactory.Create(handlerContext.QueryModelVisitor.QueryCompilationContext);
outterSelectExpression.SetProjectionExpression(Expression.Constant(1));

var collectionSelectExpression
= handlerContext.SelectExpression.Clone(outterSelectExpression.CreateUniqueTableAlias());
= handlerContext.SelectExpression.Clone(handlerContext.QueryModelVisitor.QueryCompilationContext.CreateUniqueTableAlias());
outterSelectExpression.AddTable(collectionSelectExpression);

itemSelectExpression.Alias = outterSelectExpression.CreateUniqueTableAlias();
itemSelectExpression.Alias = handlerContext.QueryModelVisitor.QueryCompilationContext.CreateUniqueTableAlias();
var joinExpression = outterSelectExpression.AddInnerJoin(itemSelectExpression);

foreach (var property in entityType.FindPrimaryKey().Properties)
Expand Down Expand Up @@ -333,7 +334,7 @@ private static Expression HandleDefaultIfEmpty(HandlerContext handlerContext)

selectExpression.ClearTables();

var emptySelectExpression = handlerContext.SelectExpressionFactory.Create("empty");
var emptySelectExpression = handlerContext.SelectExpressionFactory.Create(handlerContext.QueryModelVisitor.QueryCompilationContext, "empty");
emptySelectExpression.AddToProjection(new AliasExpression("empty", Expression.Constant(null)));

selectExpression.AddTable(emptySelectExpression);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
Expand All @@ -20,6 +22,10 @@ public class RelationalQueryCompilationContext : QueryCompilationContext
private readonly List<RelationalQueryModelVisitor> _relationalQueryModelVisitors
= new List<RelationalQueryModelVisitor>();

private const string SystemAliasPrefix = "t";
private readonly IDictionary<string, int> _tableAliasCounterMap = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
private readonly ISet<string> _tableAliasSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

public RelationalQueryCompilationContext(
[NotNull] IModel model,
[NotNull] ISensitiveDataLogger logger,
Expand Down Expand Up @@ -78,5 +84,36 @@ public virtual SelectExpression FindSelectExpression([NotNull] IQuerySource quer
select selectExpression)
.First();
}

public virtual string CreateUniqueTableAlias()
=> CreateUniqueTableAlias(SystemAliasPrefix);

public virtual string CreateUniqueTableAlias([NotNull] string currentAlias)
{
Check.NotNull(currentAlias, nameof(currentAlias));

if (currentAlias.Length == 0)
{
return currentAlias;
}

var counter = 0;
var uniqueAlias = currentAlias;

if (_tableAliasCounterMap.ContainsKey(currentAlias))
{
counter = _tableAliasCounterMap[currentAlias];
uniqueAlias += counter;
}

while (_tableAliasSet.Contains(uniqueAlias))
{
uniqueAlias = currentAlias + counter++;
}
_tableAliasCounterMap[currentAlias] = counter;

_tableAliasSet.Add(uniqueAlias);
return uniqueAlias;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ private Expression CreateSubqueryForNavigations(

var mainFromClause
= new MainFromClause(
_queryModel.GetNewName("subQuery"),
"subQuery",
targetEntityType.ClrType, CreateEntityQueryable(targetEntityType));

var querySourceReference = new QuerySourceReferenceExpression(mainFromClause);
Expand Down
Loading

0 comments on commit ef15f26

Please sign in to comment.