@@ -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