Skip to content

Commit 40ddac4

Browse files
committed
ExpressionProcessor class improvements
- save some memory on booleans by using flags - fields region structure is more clear - ctor structure improved
1 parent 01615de commit 40ddac4

2 files changed

Lines changed: 69 additions & 47 deletions

File tree

Orm/Xtensive.Orm/Orm/Providers/Expressions/ExpressionProcessor.Helpers.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
namespace Xtensive.Orm.Providers
1717
{
18-
partial class ExpressionProcessor
18+
internal partial class ExpressionProcessor
1919
{
2020
private readonly static Type ObjectType = typeof(object);
2121
private readonly static Type BooleanType = typeof(bool);
@@ -157,7 +157,7 @@ private SqlExpression TryTranslateBinaryExpressionSpecialCases(Expression expres
157157

158158
private SqlExpression TryTranslateEqualitySpecialCases(SqlExpression left, SqlExpression right)
159159
{
160-
if (right.NodeType==SqlNodeType.Null || emptyStringIsNull && IsEmptyStringLiteral(right))
160+
if (right.NodeType==SqlNodeType.Null || EmptyStringIsNull && IsEmptyStringLiteral(right))
161161
return SqlDml.IsNull(left);
162162

163163
object id = null;
@@ -173,7 +173,7 @@ private SqlExpression TryTranslateEqualitySpecialCases(SqlExpression left, SqlEx
173173

174174
private SqlExpression TryTranslateInequalitySpecialCases(SqlExpression left, SqlExpression right)
175175
{
176-
if (right.NodeType==SqlNodeType.Null || emptyStringIsNull && IsEmptyStringLiteral(right))
176+
if (right.NodeType==SqlNodeType.Null || EmptyStringIsNull && IsEmptyStringLiteral(right))
177177
return SqlDml.IsNotNull(left);
178178

179179
object id = null;

Orm/Xtensive.Orm/Orm/Providers/Expressions/ExpressionProcessor.cs

Lines changed: 66 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -22,35 +22,51 @@ namespace Xtensive.Orm.Providers
2222
{
2323
internal sealed partial class ExpressionProcessor : ExpressionVisitor<SqlExpression>
2424
{
25+
[Flags]
26+
private enum ProcessorOptions
27+
{
28+
None = 0,
29+
FixBooleanExpressions = 1 << 0,
30+
PreferCaseOverVariant = 1 << 1,
31+
EmptyStringIsNull = 1 << 2,
32+
DateTimeEmulation = 1 << 3,
33+
DateTimeOffsetEmulation = 1 << 4,
34+
SpecialByteArrayComparison = 1 << 5
35+
}
36+
2537
private static readonly SqlExpression SqlFalse = SqlDml.Literal(false);
2638
private static readonly SqlExpression SqlTrue = SqlDml.Literal(true);
2739

40+
private readonly SqlCompiler compiler;
41+
private readonly LambdaExpression lambda;
2842
private readonly StorageDriver driver;
2943
private readonly BooleanExpressionConverter booleanExpressionConverter;
3044
private readonly IMemberCompilerProvider<SqlExpression> memberCompilerProvider;
3145
private readonly IReadOnlyList<SqlExpression>[] sourceColumns;
3246
private readonly ExpressionEvaluator evaluator;
3347
private readonly ParameterExtractor parameterExtractor;
34-
private readonly LambdaExpression lambda;
35-
private readonly HashSet<QueryParameterBinding> bindings;
36-
private readonly List<ParameterExpression> activeParameters;
37-
private readonly Dictionary<ParameterExpression, IReadOnlyList<SqlExpression>> sourceMapping;
38-
private readonly SqlCompiler compiler;
48+
private readonly ProviderInfo providerInfo;
49+
private readonly ProcessorOptions options;
3950

51+
private readonly List<ParameterExpression> activeParameters
52+
= new List<ParameterExpression>();
53+
private readonly Dictionary<ParameterExpression, IReadOnlyList<SqlExpression>> sourceMapping
54+
= new Dictionary<ParameterExpression, IReadOnlyList<SqlExpression>>();
4055
private readonly Dictionary<QueryParameterIdentity, QueryParameterBinding> bindingsWithIdentity
4156
= new Dictionary<QueryParameterIdentity, QueryParameterBinding>();
42-
private readonly List<QueryParameterBinding> otherBindings = new List<QueryParameterBinding>();
43-
44-
private readonly bool fixBooleanExpressions;
45-
private readonly bool preferCaseOverVariant;
46-
private readonly bool emptyStringIsNull;
47-
private readonly bool dateTimeEmulation;
48-
private readonly bool dateTimeOffsetEmulation;
49-
private readonly bool specialByteArrayComparison;
50-
private readonly ProviderInfo providerInfo;
57+
private readonly List<QueryParameterBinding> otherBindings
58+
= new List<QueryParameterBinding>();
5159

5260
private bool executed;
5361

62+
private bool FixBooleanExpressions => (options & ProcessorOptions.FixBooleanExpressions) !=0;
63+
private bool PreferCaseOverVariant => options.HasFlag(ProcessorOptions.PreferCaseOverVariant);
64+
private bool EmptyStringIsNull => (options & ProcessorOptions.EmptyStringIsNull) != 0;
65+
private bool DateTimeEmulation => (options & ProcessorOptions.DateTimeEmulation) != 0;
66+
private bool DateTimeOffsetEmulation => (options & ProcessorOptions.DateTimeOffsetEmulation) != 0;
67+
private bool SpecialByteArrayComparison => (options & ProcessorOptions.SpecialByteArrayComparison) != 0;
68+
69+
5470
public SqlExpression Translate()
5571
{
5672
if (executed)
@@ -102,12 +118,12 @@ private SqlExpression VisitParameterAccess(Expression e, bool smartNull)
102118
SqlExpression result;
103119
if (optimizeBooleanParameter) {
104120
result = SqlDml.Variant(binding, SqlFalse, SqlTrue);
105-
if (fixBooleanExpressions)
121+
if (FixBooleanExpressions)
106122
result = booleanExpressionConverter.IntToBoolean(result);
107123
}
108124
else {
109125
result = binding.ParameterReference;
110-
if (type==typeof(bool) && fixBooleanExpressions)
126+
if (type == typeof(bool) && FixBooleanExpressions)
111127
result = booleanExpressionConverter.IntToBoolean(result);
112128
else if (typeMapping.ParameterCastRequired)
113129
result = SqlDml.Cast(result, typeMapping.MapType());
@@ -152,9 +168,9 @@ private SqlExpression VisitCast(UnaryExpression cast, SqlExpression operand)
152168
if (IsEnumUnderlyingType(sourceType, targetType) || IsEnumUnderlyingType(targetType, sourceType))
153169
return operand;
154170
// Special case for boolean cast
155-
if (fixBooleanExpressions && IsBooleanExpression(cast.Operand)) {
171+
if (FixBooleanExpressions && IsBooleanExpression(cast.Operand)) {
156172
var result = SqlDml.Case();
157-
result.Add(operand, 1);
173+
_ = result.Add(operand, 1);
158174
result.Else = 0;
159175
operand = result;
160176
}
@@ -178,7 +194,7 @@ protected override SqlExpression VisitBinary(BinaryExpression expression)
178194
expression.NodeType == ExpressionType.Equal
179195
|| expression.NodeType == ExpressionType.NotEqual;
180196

181-
var isBooleanFixRequired = fixBooleanExpressions
197+
var isBooleanFixRequired = FixBooleanExpressions
182198
&& (isEqualityCheck || expression.NodeType == ExpressionType.Coalesce)
183199
&& (IsBooleanExpression(expression.Left) || IsBooleanExpression(expression.Right));
184200

@@ -215,7 +231,7 @@ protected override SqlExpression VisitBinary(BinaryExpression expression)
215231
}
216232

217233
//handle SQLite DateTime comparsion
218-
if (dateTimeEmulation
234+
if (DateTimeEmulation
219235
&& left.NodeType != SqlNodeType.Null
220236
&& right.NodeType != SqlNodeType.Null
221237
&& IsComparisonExpression(expression)
@@ -225,7 +241,7 @@ protected override SqlExpression VisitBinary(BinaryExpression expression)
225241
}
226242

227243
//handle SQLite DateTimeOffset comparsion
228-
if (dateTimeOffsetEmulation
244+
if (DateTimeOffsetEmulation
229245
&& left.NodeType != SqlNodeType.Null
230246
&& right.NodeType != SqlNodeType.Null
231247
&& IsComparisonExpression(expression)
@@ -235,7 +251,7 @@ protected override SqlExpression VisitBinary(BinaryExpression expression)
235251
}
236252

237253
//handle Oracle special syntax of BLOB comparison
238-
if (specialByteArrayComparison
254+
if (SpecialByteArrayComparison
239255
&& (IsExpressionOf(expression.Left, typeof(byte[])) || IsExpressionOf(expression.Left, typeof(byte[])))) {
240256
var comparison = BuildByteArraySyntaxComparison(left, right);
241257
left = comparison.left;
@@ -330,14 +346,16 @@ protected override SqlExpression VisitConditional(ConditionalExpression expressi
330346
if (ifFalse is SqlContainer ifFalseContainer)
331347
ifFalse = TryUnwrapEnum(ifFalseContainer);
332348

333-
var boolCheck = fixBooleanExpressions
349+
var fixExpressions = FixBooleanExpressions;
350+
351+
var boolCheck = fixExpressions
334352
? booleanExpressionConverter.BooleanToInt(check)
335353
: check;
336354
var varCheck = boolCheck as SqlVariant;
337-
if (!preferCaseOverVariant && !varCheck.IsNullReference())
355+
if (!PreferCaseOverVariant && !varCheck.IsNullReference())
338356
return SqlDml.Variant(varCheck.Id, ifFalse, ifTrue);
339357
var @case = SqlDml.Case();
340-
if (fixBooleanExpressions && IsBooleanExpression(expression)) {
358+
if (fixExpressions && IsBooleanExpression(expression)) {
341359
@case[check] = booleanExpressionConverter.BooleanToInt(ifTrue);
342360
@case.Else = booleanExpressionConverter.BooleanToInt(ifFalse);
343361
return booleanExpressionConverter.IntToBoolean(@case);
@@ -352,14 +370,14 @@ protected override SqlExpression VisitConditional(ConditionalExpression expressi
352370
protected override SqlExpression VisitConstant(ConstantExpression expression)
353371
{
354372
if (expression.Value==null)
355-
return fixBooleanExpressions && expression.Type==typeof (bool?)
373+
return FixBooleanExpressions && expression.Type==typeof (bool?)
356374
? booleanExpressionConverter.IntToBoolean(SqlDml.Null)
357375
: SqlDml.Null;
358376
var type = expression.Type;
359377
if (type==typeof (object))
360378
type = expression.Value.GetType();
361379
type = type.StripNullable();
362-
if (fixBooleanExpressions && type==typeof (bool)) {
380+
if (FixBooleanExpressions && type == typeof(bool)) {
363381
var literal = SqlDml.Literal((bool) expression.Value);
364382
return booleanExpressionConverter.IntToBoolean(literal);
365383
}
@@ -404,7 +422,7 @@ private SqlExpression VisitTupleAccess(MethodCallExpression tupleAccess)
404422
var queryRef = sourceMapping[(ParameterExpression) tupleAccess.Object];
405423
result = queryRef[columnIndex];
406424
}
407-
if (fixBooleanExpressions && IsBooleanExpression(tupleAccess))
425+
if (FixBooleanExpressions && IsBooleanExpression(tupleAccess))
408426
result = booleanExpressionConverter.IntToBoolean(result);
409427
return result;
410428
}
@@ -465,39 +483,43 @@ private SqlExpression TryUnwrapEnum(SqlContainer container)
465483
// Constructors
466484

467485
public ExpressionProcessor(
468-
LambdaExpression lambda, HandlerAccessor handlers, SqlCompiler compiler, bool preferCaseOverVariant, params IReadOnlyList<SqlExpression>[] sourceColumns)
486+
LambdaExpression lambda, HandlerAccessor handlers, SqlCompiler compiler, in bool preferCaseOverVariant, params IReadOnlyList<SqlExpression>[] sourceColumns)
469487
{
470488
ArgumentValidator.EnsureArgumentNotNull(lambda, "lambda");
471489
ArgumentValidator.EnsureArgumentNotNull(handlers, "handlers");
472490
ArgumentValidator.EnsureArgumentNotNull(sourceColumns, "sourceColumns");
473491

492+
if (lambda.Parameters.Count != sourceColumns.Length)
493+
throw Exceptions.InternalError(Strings.ExParametersCountIsNotSameAsSourceColumnListsCount, OrmLog.Instance);
494+
if (sourceColumns.Any(list => list.Any(c => c.IsNullReference())))
495+
throw Exceptions.InternalError(Strings.ExSourceColumnListContainsNullValues, OrmLog.Instance);
496+
474497
this.compiler = compiler; // This might be null, check before use!
475498
this.lambda = lambda;
476499
this.sourceColumns = sourceColumns;
477-
this.preferCaseOverVariant = preferCaseOverVariant;
478500

479501
providerInfo = handlers.ProviderInfo;
480502
driver = handlers.StorageDriver;
481-
482-
fixBooleanExpressions = !providerInfo.Supports(ProviderFeatures.FullFeaturedBooleanExpressions);
483-
emptyStringIsNull = providerInfo.Supports(ProviderFeatures.TreatEmptyStringAsNull);
484-
dateTimeEmulation = providerInfo.Supports(ProviderFeatures.DateTimeEmulation);
485-
dateTimeOffsetEmulation = providerInfo.Supports(ProviderFeatures.DateTimeOffsetEmulation);
486503
memberCompilerProvider = handlers.DomainHandler.GetMemberCompilerProvider<SqlExpression>();
487-
specialByteArrayComparison = providerInfo.ProviderName.Equals(WellKnown.Provider.Oracle);
488504

489-
bindings = new HashSet<QueryParameterBinding>();
490-
activeParameters = new List<ParameterExpression>();
491505
evaluator = new ExpressionEvaluator(lambda);
492506
parameterExtractor = new ParameterExtractor(evaluator);
493507

494-
if (fixBooleanExpressions)
508+
options = ProcessorOptions.None;
509+
if (!providerInfo.Supports(ProviderFeatures.FullFeaturedBooleanExpressions)) {
510+
options |= ProcessorOptions.FixBooleanExpressions;
495511
booleanExpressionConverter = new BooleanExpressionConverter(driver);
496-
if (lambda.Parameters.Count!=sourceColumns.Length)
497-
throw Exceptions.InternalError(Strings.ExParametersCountIsNotSameAsSourceColumnListsCount, OrmLog.Instance);
498-
if (sourceColumns.Any(list => list.Any(c => c.IsNullReference())))
499-
throw Exceptions.InternalError(Strings.ExSourceColumnListContainsNullValues, OrmLog.Instance);
500-
sourceMapping = new Dictionary<ParameterExpression, IReadOnlyList<SqlExpression>>();
512+
}
513+
if (providerInfo.Supports(ProviderFeatures.TreatEmptyStringAsNull))
514+
options |= ProcessorOptions.EmptyStringIsNull;
515+
if (providerInfo.Supports(ProviderFeatures.DateTimeEmulation))
516+
options |= ProcessorOptions.DateTimeEmulation;
517+
if (providerInfo.Supports(ProviderFeatures.DateTimeOffsetEmulation))
518+
options |= ProcessorOptions.DateTimeOffsetEmulation;
519+
if (providerInfo.ProviderName.Equals(WellKnown.Provider.Oracle))
520+
options |= ProcessorOptions.SpecialByteArrayComparison;
521+
if (preferCaseOverVariant)
522+
options |= ProcessorOptions.PreferCaseOverVariant;
501523
}
502524
}
503525
}

0 commit comments

Comments
 (0)