Skip to content

Commit 2c01872

Browse files
committed
ProviderVisitors track applyparameter changes during expression tree traversal
1 parent 48efdbd commit 2c01872

8 files changed

Lines changed: 109 additions & 61 deletions

File tree

Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.Apply.cs

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2009-2021 Xtensive LLC.
1+
// Copyright (C) 2009-2024 Xtensive LLC.
22
// This code is distributed under MIT license terms.
33
// See the License.txt file in the project root for more information.
44
// Created by: Denis Krjuchkov
@@ -24,24 +24,24 @@ protected override SqlProvider VisitApply(ApplyProvider provider)
2424
{
2525
bool processViaCrossApply;
2626
switch (provider.SequenceType) {
27-
case ApplySequenceType.All:
28-
// apply is required
29-
if (!providerInfo.Supports(ProviderFeatures.Apply))
30-
throw new NotSupportedException();
31-
processViaCrossApply = true;
32-
break;
33-
case ApplySequenceType.First:
34-
case ApplySequenceType.FirstOrDefault:
35-
// apply is prefered but is not required
36-
processViaCrossApply = providerInfo.Supports(ProviderFeatures.Apply);
37-
break;
38-
case ApplySequenceType.Single:
39-
case ApplySequenceType.SingleOrDefault:
40-
// apply is not allowed
41-
processViaCrossApply = false;
42-
break;
43-
default:
44-
throw new ArgumentOutOfRangeException();
27+
case ApplySequenceType.All:
28+
// apply is required
29+
if (!providerInfo.Supports(ProviderFeatures.Apply))
30+
throw new NotSupportedException();
31+
processViaCrossApply = true;
32+
break;
33+
case ApplySequenceType.First:
34+
case ApplySequenceType.FirstOrDefault:
35+
// apply is prefered but is not required
36+
processViaCrossApply = providerInfo.Supports(ProviderFeatures.Apply);
37+
break;
38+
case ApplySequenceType.Single:
39+
case ApplySequenceType.SingleOrDefault:
40+
// apply is not allowed
41+
processViaCrossApply = false;
42+
break;
43+
default:
44+
throw new ArgumentOutOfRangeException();
4545
}
4646

4747
var left = Compile(provider.Left);
@@ -64,24 +64,29 @@ protected override SqlProvider VisitApply(ApplyProvider provider)
6464
return mc;
6565
});
6666
var providerVisitor = new CompilableProviderVisitor((p, e) => visitor.Visit(e));
67-
providerVisitor.VisitCompilable(provider.Right);
67+
_ = providerVisitor.VisitCompilable(provider.Right);
6868
shouldUseQueryReference = usedOuterColumns.Any(calculatedColumnIndexes.Contains)
6969
|| groupByIsUsed
7070
|| provider.Left.Type.In(ProviderType.Store, ProviderType.Include)
7171
|| left.Header.Columns.Count!=left.Request.Statement.Columns.Count;
7272
}
7373

74-
var binding = OuterReferences.Add(
75-
provider.ApplyParameter, new Pair<SqlProvider, bool>(left, shouldUseQueryReference));
74+
var outerReference = new Pair<SqlProvider, bool>(left, shouldUseQueryReference);
75+
var binding = OuterReferences.Add(provider.ApplyParameter, outerReference);
7676

7777
using (binding) {
78+
outerReferenceStack.Push(outerReference);
79+
7880
var right = Compile(provider.Right);
7981

8082
var query = processViaCrossApply
8183
? ProcessApplyViaCrossApply(provider, left, right)
8284
: ProcessApplyViaSubqueries(provider, left, right, shouldUseQueryReference);
8385

84-
return CreateProvider(query, provider, left, right);
86+
var result = CreateProvider(query, provider, left, right);
87+
88+
_ = outerReferenceStack.Pop();
89+
return result;
8590
}
8691
}
8792

Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.Helpers.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,9 @@ private SqlExpression GetJoinExpression(SqlExpression leftExpression, SqlExpress
345345

346346
public SqlExpression GetOuterExpression(ApplyParameter parameter, int columnIndex)
347347
{
348-
var reference = OuterReferences[parameter];
348+
if (!OuterReferences.TryGetValue(parameter, out var reference)) {
349+
reference = outerReferenceStack.Peek();
350+
}
349351
var sqlProvider = reference.First;
350352
var useQueryReference = reference.Second;
351353
return useQueryReference

Orm/Xtensive.Orm/Orm/Providers/SqlCompiler.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2009-2021 Xtensive LLC.
1+
// Copyright (C) 2009-2024 Xtensive LLC.
22
// This code is distributed under MIT license terms.
33
// See the License.txt file in the project root for more information.
44
// Created by: Vakhtina Elena
@@ -23,6 +23,8 @@ namespace Xtensive.Orm.Providers
2323
{
2424
public partial class SqlCompiler : Compiler<SqlProvider>
2525
{
26+
protected readonly Stack<Pair<SqlProvider, bool>> outerReferenceStack = new Stack<Pair<SqlProvider, bool>>();
27+
2628
private readonly BooleanExpressionConverter booleanExpressionConverter;
2729
private readonly Dictionary<SqlColumnStub, SqlExpression> stubColumnMap;
2830
private readonly ProviderInfo providerInfo;

Orm/Xtensive.Orm/Orm/Rse/Transformation/ColumnMappingInspector.cs

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
// Copyright (C) 2010-2020 Xtensive LLC.
1+
// Copyright (C) 2010-2024 Xtensive LLC.
22
// This code is distributed under MIT license terms.
33
// See the License.txt file in the project root for more information.
44

55
using System;
66
using System.Collections.Generic;
77
using System.Linq;
88
using System.Linq.Expressions;
9+
using System.Runtime.CompilerServices;
910
using Xtensive.Collections;
1011
using Xtensive.Core;
1112
using Xtensive.Orm.Rse.Providers;
@@ -21,6 +22,7 @@ internal abstract class ColumnMappingInspector : CompilableProviderVisitor
2122
private readonly Dictionary<ApplyParameter, List<int>> outerColumnUsages;
2223
private readonly CompilableProviderVisitor outerColumnUsageVisitor;
2324
private readonly CompilableProvider rootProvider;
25+
private readonly Stack<List<int>> outerColumnUsageStack;
2426

2527
private bool hasGrouping;
2628

@@ -195,9 +197,9 @@ protected override Provider VisitApply(ApplyProvider provider)
195197
var applyParameter = provider.ApplyParameter;
196198
var currentOuterUsages = new List<int>();
197199

198-
outerColumnUsages.Add(applyParameter, currentOuterUsages);
199-
_ = outerColumnUsageVisitor.VisitCompilable(provider.Right);
200-
_ = outerColumnUsages.Remove(applyParameter);
200+
using (SetOuterColumnUsage(applyParameter, currentOuterUsages)) {
201+
_ = outerColumnUsageVisitor.VisitCompilable(provider.Right);
202+
}
201203

202204
leftMapping = Merge(leftMapping, currentOuterUsages);
203205

@@ -212,9 +214,10 @@ protected override Provider VisitApply(ApplyProvider provider)
212214
leftMapping = mappings[provider.Left];
213215

214216
_ = ReplaceMappings(provider.Right, rightMapping);
215-
outerColumnUsages.Add(applyParameter, leftMapping);
216-
var newRightProvider = VisitCompilable(provider.Right);
217-
_ = outerColumnUsages.Remove(applyParameter);
217+
CompilableProvider newRightProvider;
218+
using (SetOuterColumnUsage(applyParameter, leftMapping)) {
219+
newRightProvider = VisitCompilable(provider.Right);
220+
}
218221

219222
var pair = OverrideRightApplySource(provider, newRightProvider, rightMapping);
220223
if (pair.First == null) {
@@ -466,7 +469,7 @@ private void RegisterOuterMapping(ApplyParameter parameter, int value)
466469

467470
private int ResolveOuterMapping(ApplyParameter parameter, int value)
468471
{
469-
var result = outerColumnUsages[parameter].IndexOf(value);
472+
var result = GetOuterColumnUsage(parameter).IndexOf(value);
470473
return result < 0 ? value : result;
471474
}
472475

@@ -514,6 +517,21 @@ private Dictionary<Provider, List<int>> ReplaceMappings(Provider firstNewKey, Li
514517

515518
private void RestoreMappings(Dictionary<Provider, List<int>> savedMappings) => mappings = savedMappings;
516519

520+
private IDisposable SetOuterColumnUsage(ApplyParameter parameter, List<int> usages)
521+
{
522+
outerColumnUsages.Add(parameter, usages);
523+
outerColumnUsageStack.Push(usages);
524+
return new Disposable(
525+
x => {
526+
_ = outerColumnUsages.Remove(parameter);
527+
_ = outerColumnUsageStack.Pop();
528+
});
529+
}
530+
531+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
532+
private List<int> GetOuterColumnUsage(ApplyParameter parameter) =>
533+
outerColumnUsages.TryGetValue(parameter, out var result) ? result : outerColumnUsageStack.Peek();
534+
517535
#endregion
518536

519537
// Constructors
@@ -524,6 +542,7 @@ protected ColumnMappingInspector(CompilableProvider originalProvider)
524542

525543
mappings = new Dictionary<Provider, List<int>>();
526544
outerColumnUsages = new Dictionary<ApplyParameter, List<int>>();
545+
outerColumnUsageStack = new Stack<List<int>>();
527546
mappingsGatherer = new TupleAccessGatherer((a, b) => { });
528547

529548
var outerMappingsGatherer = new TupleAccessGatherer(RegisterOuterMapping);

Orm/Xtensive.Orm/Orm/Rse/Transformation/Internals/ApplyPredicateCollector.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// Copyright (C) 2003-2010 Xtensive LLC.
2-
// All rights reserved.
3-
// For conditions of distribution and use, see license.
1+
// Copyright (C) 2009-2024 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
44
// Created by: Alexander Nikolaev
55
// Created: 2009.05.22
66

@@ -26,7 +26,7 @@ public bool TryAdd(FilterProvider filter)
2626
{
2727
var applyParameter = parameterSearcher.Find(filter.Predicate);
2828
if (applyParameter != null) {
29-
if (!owner.State.SelfConvertibleApplyProviders[applyParameter]) {
29+
if (!owner.State.CheckIfApplyParameterSeflConvertible(applyParameter)) {
3030
SaveApplyPredicate(filter, applyParameter);
3131
return true;
3232
}

Orm/Xtensive.Orm/Orm/Rse/Transformation/Internals/ApplyProviderCorrectorRewriter.cs

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// Copyright (C) 2003-2010 Xtensive LLC.
2-
// All rights reserved.
3-
// For conditions of distribution and use, see license.
1+
// Copyright (C) 2009-2024 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
44
// Created by: Alexander Nikolaev
55
// Created: 2009.05.15
66

@@ -21,28 +21,41 @@ internal sealed class ApplyProviderCorrectorRewriter : CompilableProviderVisitor
2121
{
2222
#region Nested types: CorrectorState
2323

24-
public sealed class CorrectorState : IDisposable
24+
internal sealed class CorrectorState : IDisposable
2525
{
2626
private readonly CorrectorState previousState;
2727
private readonly ApplyProviderCorrectorRewriter owner;
28+
private readonly Stack<bool> selfConvertibleApplyProviderStack;
29+
private readonly Dictionary<ApplyParameter, bool> selfConvertibleApplyProviders;
30+
2831
private bool isDisposed;
2932

3033
public
3134
Dictionary<ApplyParameter, List<Pair<Expression<Func<Tuple, bool>>, ColumnCollection>>>
3235
Predicates { get; set; }
3336

34-
public Dictionary<ApplyParameter, bool> SelfConvertibleApplyProviders { get; set; }
37+
public Dictionary<ApplyParameter, List<Pair<CalculateProvider, ColumnCollection>>> CalculateProviders { get; set; }
3538

36-
public Dictionary<ApplyParameter, List<Pair<CalculateProvider, ColumnCollection>>>
37-
CalculateProviders { get; set; }
39+
public Dictionary<CalculateProvider, List<Pair<Expression<Func<Tuple, bool>>, ColumnCollection>>> CalculateFilters { get; set; }
3840

39-
public Dictionary<CalculateProvider, List<Pair<Expression<Func<Tuple, bool>>, ColumnCollection>>>
40-
CalculateFilters { get; set; }
41+
public bool ExistsApplyProviderRequiringConversion => Predicates.Count > 0 || CalculateProviders.Count > 0;
4142

42-
public bool ExistsApplyProviderRequiringConversion {
43-
get { return Predicates.Count > 0 || CalculateProviders.Count > 0;}
43+
public Disposable SetIfApplyParameterConvertible(ApplyParameter parameter, bool isSelfConvertibleApply)
44+
{
45+
selfConvertibleApplyProviders.Add(parameter, isSelfConvertibleApply);
46+
selfConvertibleApplyProviderStack.Push(isSelfConvertibleApply);
47+
return new Disposable(
48+
x => {
49+
_ = selfConvertibleApplyProviders.Remove(parameter);
50+
_ = selfConvertibleApplyProviderStack.Pop();
51+
});
4452
}
4553

54+
public bool CheckIfApplyParameterSeflConvertible(ApplyParameter parameter) =>
55+
selfConvertibleApplyProviders.TryGetValue(parameter, out var result)
56+
? result
57+
: selfConvertibleApplyProviderStack.Peek();
58+
4659

4760
// Constructors
4861

@@ -57,10 +70,12 @@ public CorrectorState(ApplyProviderCorrectorRewriter owner)
5770
new Dictionary<CalculateProvider, List<Pair<Expression<Func<Tuple, bool>>, ColumnCollection>>>();
5871
previousState = owner.State;
5972
if (previousState == null) {
60-
SelfConvertibleApplyProviders = new Dictionary<ApplyParameter, bool>();
73+
selfConvertibleApplyProviders = new Dictionary<ApplyParameter, bool>();
74+
selfConvertibleApplyProviderStack = new Stack<bool>();
6175
}
6276
else {
63-
SelfConvertibleApplyProviders = previousState.SelfConvertibleApplyProviders;
77+
selfConvertibleApplyProviders = previousState.selfConvertibleApplyProviders;
78+
selfConvertibleApplyProviderStack = previousState.selfConvertibleApplyProviderStack;
6479
}
6580
owner.State = this;
6681
}
@@ -149,9 +164,9 @@ protected override Provider VisitApply(ApplyProvider provider)
149164
CompilableProvider left;
150165
CompilableProvider right;
151166
var isSelfConvertibleApply = provider.SequenceType != ApplySequenceType.All;
152-
State.SelfConvertibleApplyProviders.Add(provider.ApplyParameter, isSelfConvertibleApply);
153-
VisitBinaryProvider(provider, out left, out right);
154-
State.SelfConvertibleApplyProviders.Remove(provider.ApplyParameter);
167+
using (State.SetIfApplyParameterConvertible(provider.ApplyParameter, isSelfConvertibleApply)) {
168+
VisitBinaryProvider(provider, out left, out right);
169+
}
155170

156171
if (isSelfConvertibleApply) {
157172
return ProcesSelfConvertibleApply(provider, left, right);

Orm/Xtensive.Orm/Orm/Rse/Transformation/Internals/CalculateProviderCollector.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// Copyright (C) 2003-2010 Xtensive LLC.
2-
// All rights reserved.
3-
// For conditions of distribution and use, see license.
1+
// Copyright (C) 2009-2024 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
44
// Created by: Alexander Nikolaev
55
// Created: 2009.05.22
66

@@ -29,7 +29,7 @@ public bool TryAdd(CalculateProvider provider)
2929
if (applyParameters.Count > 1)
3030
ApplyProviderCorrectorRewriter.ThrowInvalidOperationException();
3131
var applyParameter = applyParameters[0];
32-
if (owner.State.SelfConvertibleApplyProviders[applyParameter])
32+
if (owner.State.CheckIfApplyParameterSeflConvertible(applyParameter))
3333
return false;
3434
var newPair = new Pair<CalculateProvider, ColumnCollection>(provider, provider.Header.Columns);
3535
if (owner.State.CalculateProviders.ContainsKey(applyParameter))

Orm/Xtensive.Orm/Orm/Rse/Transformation/RedundantColumnRemover.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// Copyright (C) 2003-2010 Xtensive LLC.
2-
// All rights reserved.
3-
// For conditions of distribution and use, see license.
1+
// Copyright (C) 2009-2024 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
44
// Created by: Alexey Gamzov
55
// Created: 2009.10.12
66

@@ -23,7 +23,12 @@ protected override Pair<CompilableProvider, List<int>> OverrideRightApplySource(
2323
var currentMapping = mappings[applyProvider.Right];
2424
if (currentMapping.SequenceEqual(requestedMapping))
2525
return base.OverrideRightApplySource(applyProvider, provider, requestedMapping);
26-
var selectProvider = new SelectProvider(provider, requestedMapping.ToArray());
26+
var selectingRequestedMapping = requestedMapping.ToArray();
27+
for (int i = 0, count = requestedMapping.Count; i < count; i++) {
28+
selectingRequestedMapping[i] = currentMapping.IndexOf(selectingRequestedMapping[i]);
29+
}
30+
31+
var selectProvider = new SelectProvider(provider, selectingRequestedMapping);
2732
return new Pair<CompilableProvider, List<int>>(selectProvider, requestedMapping);
2833
}
2934

0 commit comments

Comments
 (0)