@@ -267,14 +267,15 @@ protected override Expression ApplyInferredTypeMappings(
267267 {
268268 if ( source . QueryExpression is SelectExpression
269269 {
270- Tables : [ ( PgUnnestExpression or ValuesExpression { ColumnNames : [ "_ord" , "Value" ] } ) and var sourceTable ] ,
270+ Tables : [ var sourceTable ] ,
271271 Predicate : null ,
272272 GroupBy : [ ] ,
273273 Having : null ,
274274 IsDistinct : false ,
275275 Limit : null ,
276276 Offset : null
277277 }
278+ && TryGetArray ( sourceTable , out var array )
278279 && TranslateLambdaExpression ( source , predicate ) is { } translatedPredicate )
279280 {
280281 switch ( translatedPredicate )
@@ -291,7 +292,7 @@ protected override Expression ApplyInferredTypeMappings(
291292 {
292293 return BuildSimplifiedShapedQuery (
293294 source ,
294- _sqlExpressionFactory . All ( match , GetArray ( sourceTable ) , PgAllOperatorType . Like ) ) ;
295+ _sqlExpressionFactory . All ( match , array , PgAllOperatorType . Like ) ) ;
295296 }
296297
297298 // Pattern match for: new[] { "a", "b", "c" }.All(p => EF.Functions.Like(e.SomeText, p)),
@@ -306,7 +307,7 @@ protected override Expression ApplyInferredTypeMappings(
306307 {
307308 return BuildSimplifiedShapedQuery (
308309 source ,
309- _sqlExpressionFactory . All ( match , GetArray ( sourceTable ) , PgAllOperatorType . ILike ) ) ;
310+ _sqlExpressionFactory . All ( match , array , PgAllOperatorType . ILike ) ) ;
310311 }
311312
312313 // Pattern match for: e.SomeArray.All(p => ints.Contains(p)) over non-column,
@@ -318,7 +319,7 @@ protected override Expression ApplyInferredTypeMappings(
318319 }
319320 when sourceColumn . Table == sourceTable :
320321 {
321- return BuildSimplifiedShapedQuery ( source , _sqlExpressionFactory . ContainedBy ( GetArray ( sourceTable ) , otherArray ) ) ;
322+ return BuildSimplifiedShapedQuery ( source , _sqlExpressionFactory . ContainedBy ( array , otherArray ) ) ;
322323 }
323324
324325 // Pattern match for: new[] { 4, 5 }.All(p => e.SomeArray.Contains(p)) over column,
@@ -331,7 +332,7 @@ protected override Expression ApplyInferredTypeMappings(
331332 }
332333 when sourceColumn . Table == sourceTable :
333334 {
334- return BuildSimplifiedShapedQuery ( source , _sqlExpressionFactory . ContainedBy ( GetArray ( sourceTable ) , otherArray ) ) ;
335+ return BuildSimplifiedShapedQuery ( source , _sqlExpressionFactory . ContainedBy ( array , otherArray ) ) ;
335336 }
336337 }
337338 }
@@ -349,14 +350,15 @@ protected override Expression ApplyInferredTypeMappings(
349350 {
350351 if ( source . QueryExpression is SelectExpression
351352 {
352- Tables : [ ( PgUnnestExpression or ValuesExpression { ColumnNames : [ "_ord" , "Value" ] } ) and var sourceTable ] ,
353+ Tables : [ var sourceTable ] ,
353354 Predicate : null ,
354355 GroupBy : [ ] ,
355356 Having : null ,
356357 IsDistinct : false ,
357358 Limit : null ,
358359 Offset : null
359- } )
360+ }
361+ && TryGetArray ( sourceTable , out var array ) )
360362 {
361363 // Pattern match: x.Array.Any()
362364 // Translation: cardinality(x.array) > 0 instead of EXISTS (SELECT 1 FROM FROM unnest(x.Array))
@@ -367,7 +369,7 @@ protected override Expression ApplyInferredTypeMappings(
367369 _sqlExpressionFactory . GreaterThan (
368370 _sqlExpressionFactory . Function (
369371 "cardinality" ,
370- new [ ] { GetArray ( sourceTable ) } ,
372+ new [ ] { array } ,
371373 nullable : true ,
372374 argumentsPropagateNullability : TrueArrays [ 1 ] ,
373375 typeof ( int ) ) ,
@@ -392,7 +394,7 @@ protected override Expression ApplyInferredTypeMappings(
392394 when pattern . Table == sourceTable :
393395 {
394396 return BuildSimplifiedShapedQuery (
395- source , _sqlExpressionFactory . Any ( match , GetArray ( sourceTable ) , PgAnyOperatorType . Like ) ) ;
397+ source , _sqlExpressionFactory . Any ( match , array , PgAnyOperatorType . Like ) ) ;
396398 }
397399
398400 // Pattern match: new[] { "a", "b", "c" }.Any(p => EF.Functions.Like(e.SomeText, p))
@@ -406,7 +408,7 @@ protected override Expression ApplyInferredTypeMappings(
406408 when pattern . Table == sourceTable :
407409 {
408410 return BuildSimplifiedShapedQuery (
409- source , _sqlExpressionFactory . Any ( match , GetArray ( sourceTable ) , PgAnyOperatorType . ILike ) ) ;
411+ source , _sqlExpressionFactory . Any ( match , array , PgAnyOperatorType . ILike ) ) ;
410412 }
411413
412414 // Array overlap over non-column
@@ -419,7 +421,7 @@ protected override Expression ApplyInferredTypeMappings(
419421 }
420422 when sourceColumn . Table == sourceTable :
421423 {
422- return BuildSimplifiedShapedQuery ( source , _sqlExpressionFactory . Overlaps ( GetArray ( sourceTable ) , otherArray ) ) ;
424+ return BuildSimplifiedShapedQuery ( source , _sqlExpressionFactory . Overlaps ( array , otherArray ) ) ;
423425 }
424426
425427 // Array overlap over column
@@ -433,7 +435,7 @@ protected override Expression ApplyInferredTypeMappings(
433435 }
434436 when sourceColumn . Table == sourceTable :
435437 {
436- return BuildSimplifiedShapedQuery ( source , _sqlExpressionFactory . Overlaps ( GetArray ( sourceTable ) , otherArray ) ) ;
438+ return BuildSimplifiedShapedQuery ( source , _sqlExpressionFactory . Overlaps ( array , otherArray ) ) ;
437439 }
438440
439441 #region LTree translations
@@ -453,7 +455,7 @@ protected override Expression ApplyInferredTypeMappings(
453455 new PgBinaryExpression (
454456 PgExpressionType . LTreeMatchesAny ,
455457 ltree ,
456- _sqlExpressionFactory . ApplyTypeMapping ( GetArray ( sourceTable ) , _typeMappingSource . FindMapping ( "lquery[]" ) ) ,
458+ _sqlExpressionFactory . ApplyTypeMapping ( array , _typeMappingSource . FindMapping ( "lquery[]" ) ) ,
457459 typeof ( bool ) ,
458460 typeMapping : _typeMappingSource . FindMapping ( typeof ( bool ) ) ) ) ;
459461 }
@@ -475,7 +477,7 @@ protected override Expression ApplyInferredTypeMappings(
475477 source ,
476478 new PgBinaryExpression (
477479 operatorType ,
478- _sqlExpressionFactory . ApplyDefaultTypeMapping ( GetArray ( sourceTable ) ) ,
480+ _sqlExpressionFactory . ApplyDefaultTypeMapping ( array ) ,
479481 ltree ,
480482 typeof ( bool ) ,
481483 typeMapping : _typeMappingSource . FindMapping ( typeof ( bool ) ) ) ) ;
@@ -497,7 +499,7 @@ protected override Expression ApplyInferredTypeMappings(
497499 source ,
498500 new PgBinaryExpression (
499501 PgExpressionType . LTreeMatches ,
500- _sqlExpressionFactory . ApplyDefaultTypeMapping ( GetArray ( sourceTable ) ) ,
502+ _sqlExpressionFactory . ApplyDefaultTypeMapping ( array ) ,
501503 lquery ,
502504 typeof ( bool ) ,
503505 typeMapping : _typeMappingSource . FindMapping ( typeof ( bool ) ) ) ) ;
@@ -518,7 +520,7 @@ protected override Expression ApplyInferredTypeMappings(
518520 source ,
519521 new PgBinaryExpression (
520522 PgExpressionType . LTreeMatchesAny ,
521- _sqlExpressionFactory . ApplyDefaultTypeMapping ( GetArray ( sourceTable ) ) ,
523+ _sqlExpressionFactory . ApplyDefaultTypeMapping ( array ) ,
522524 lqueries ,
523525 typeof ( bool ) ,
524526 typeMapping : _typeMappingSource . FindMapping ( typeof ( bool ) ) ) ) ;
@@ -578,26 +580,20 @@ protected override Expression ApplyInferredTypeMappings(
578580 /// </summary>
579581 protected override ShapedQueryExpression ? TranslateContains ( ShapedQueryExpression source , Expression item )
580582 {
583+ // Note that most other simplifications convert ValuesExpression to unnest over array constructor, but we avoid doing that
584+ // here for Contains, since the relational translation for ValuesExpression is better.
581585 if ( source . QueryExpression is SelectExpression
582586 {
583- Tables : [ ( PgUnnestExpression or ValuesExpression { ColumnNames : [ "_ord" , "Value" ] } ) and var sourceTable ] ,
587+ Tables : [ PgUnnestExpression { Array : var array } ] ,
584588 Predicate : null ,
585589 GroupBy : [ ] ,
586590 Having : null ,
587591 IsDistinct : false ,
588592 Limit : null ,
589593 Offset : null
590- } )
591- {
592- if ( TranslateExpression ( item , applyDefaultTypeMapping : false ) is not SqlExpression translatedItem )
593- {
594- return null ;
595594 }
596-
597- // Note that most other simplifications here convert ValuesExpression to unnest over array constructor, but we avoid doing that
598- // here, since the relational translation for ValuesExpression is better.
599- var array = GetArray ( sourceTable ) ;
600-
595+ && TranslateExpression ( item , applyDefaultTypeMapping : false ) is SqlExpression translatedItem )
596+ {
601597 ( translatedItem , array ) = _sqlExpressionFactory . ApplyTypeMappingsOnItemAndArray ( translatedItem , array ) ;
602598
603599 // When the array is a column, we translate Contains to array @> ARRAY[item]. GIN indexes on array are used, but null
@@ -823,7 +819,7 @@ protected override ShapedQueryExpression TranslateConcat(ShapedQueryExpression s
823819 // select expression should already contain our predicate.
824820 if ( source . QueryExpression is SelectExpression
825821 {
826- Tables : [ ( PgUnnestExpression or ValuesExpression { ColumnNames : [ "_ord" , "Value" ] } ) and var sourceTable ] ,
822+ Tables : [ var sourceTable ] ,
827823 Predicate : var translatedPredicate ,
828824 GroupBy : [ ] ,
829825 Having : null ,
@@ -832,6 +828,7 @@ protected override ShapedQueryExpression TranslateConcat(ShapedQueryExpression s
832828 Offset : null ,
833829 Orderings : [ ]
834830 }
831+ && TryGetArray ( sourceTable , out var array )
835832 && translatedPredicate is null ^ predicate is null )
836833 {
837834 if ( translatedPredicate is null )
@@ -864,7 +861,7 @@ protected override ShapedQueryExpression TranslateConcat(ShapedQueryExpression s
864861 operatorType == PgExpressionType . Contains
865862 ? PgExpressionType . LTreeFirstAncestor
866863 : PgExpressionType . LTreeFirstDescendent ,
867- _sqlExpressionFactory . ApplyDefaultTypeMapping ( GetArray ( sourceTable ) ) ,
864+ _sqlExpressionFactory . ApplyDefaultTypeMapping ( array ) ,
868865 ltree ,
869866 typeof ( LTree ) ,
870867 _typeMappingSource . FindMapping ( typeof ( LTree ) ) ) ) ;
@@ -886,7 +883,7 @@ protected override ShapedQueryExpression TranslateConcat(ShapedQueryExpression s
886883 source ,
887884 new PgBinaryExpression (
888885 PgExpressionType . LTreeFirstMatches ,
889- _sqlExpressionFactory . ApplyDefaultTypeMapping ( GetArray ( sourceTable ) ) ,
886+ _sqlExpressionFactory . ApplyDefaultTypeMapping ( array ) ,
890887 lquery ,
891888 typeof ( LTree ) ,
892889 _typeMappingSource . FindMapping ( typeof ( LTree ) ) ) ) ;
@@ -1226,18 +1223,17 @@ private ShapedQueryExpression BuildSimplifiedShapedQuery(ShapedQueryExpression s
12261223 /// Extracts the <see cref="PgUnnestExpression.Array" /> out of <see cref="PgUnnestExpression" />.
12271224 /// If a <see cref="ValuesExpression" /> is given, converts its literal values into a <see cref="PgNewArrayExpression" />.
12281225 /// </summary>
1229- private SqlExpression GetArray ( TableExpressionBase tableExpression )
1226+ private bool TryGetArray ( TableExpressionBase tableExpression , [ NotNullWhen ( true ) ] out SqlExpression ? array )
12301227 {
1231- Check . DebugAssert (
1232- tableExpression is PgUnnestExpression or ValuesExpression { ColumnNames : [ "_ord" , "Value" ] } ,
1233- "Bad tableExpression" ) ;
1234-
12351228 switch ( tableExpression )
12361229 {
12371230 case PgUnnestExpression unnest :
1238- return unnest . Array ;
1231+ array = unnest . Array ;
1232+ return true ;
12391233
1240- case ValuesExpression valuesExpression :
1234+ // TODO: We currently don't have information type information on empty ValuesExpression, so we can't transform that into an
1235+ // array.
1236+ case ValuesExpression { ColumnNames : [ "_ord" , "Value" ] , RowValues . Count : > 0 } valuesExpression :
12411237 {
12421238 // The source table was a constant collection, so translated by default to ValuesExpression. Convert it to an unnest over
12431239 // an array constructor.
@@ -1249,12 +1245,14 @@ private SqlExpression GetArray(TableExpressionBase tableExpression)
12491245 elements [ i ] = valuesExpression . RowValues [ i ] . Values [ 1 ] ;
12501246 }
12511247
1252- return new PgNewArrayExpression (
1248+ array = new PgNewArrayExpression (
12531249 elements , valuesExpression . RowValues [ 0 ] . Values [ 1 ] . Type . MakeArrayType ( ) , typeMapping : null ) ;
1250+ return true ;
12541251 }
12551252
12561253 default :
1257- throw new ArgumentException ( nameof ( tableExpression ) ) ;
1254+ array = null ;
1255+ return false ;
12581256 }
12591257 }
12601258
0 commit comments