diff --git a/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlArrayMethodTranslator.cs b/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlArrayMethodTranslator.cs index e128dacea9..847da4c171 100644 --- a/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlArrayMethodTranslator.cs +++ b/src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlArrayMethodTranslator.cs @@ -141,7 +141,10 @@ static bool IsMappedToNonArray(SqlExpression arrayOrList) "array_position", [array, item], nullable: true, - TrueArrays[2], + // array_position can return NULL even if both its arguments are non-nullable; + // this is currently the way to express that (see + // https://github.com/dotnet/efcore/pull/33814#issuecomment-2687857927). + FalseArrays[2], arrayOrList.Type), _sqlExpressionFactory.Constant(1)), _sqlExpressionFactory.Constant(-1)); @@ -161,7 +164,10 @@ static bool IsMappedToNonArray(SqlExpression arrayOrList) "array_position", [array, item, startIndex], nullable: true, - TrueArrays[3], + // array_position can return NULL even if both its arguments are non-nullable; + // this is currently the way to express that (see + // https://github.com/dotnet/efcore/pull/33814#issuecomment-2687857927). + FalseArrays[3], arrayOrList.Type), _sqlExpressionFactory.Constant(1)), _sqlExpressionFactory.Constant(-1)); diff --git a/src/EFCore.PG/Utilities/Util.cs b/src/EFCore.PG/Utilities/Util.cs index bdbceb2829..97bca187c1 100644 --- a/src/EFCore.PG/Utilities/Util.cs +++ b/src/EFCore.PG/Utilities/Util.cs @@ -15,5 +15,10 @@ internal static class Statics [true, true, true, true, true, true, true, true] ]; - internal static readonly bool[][] FalseArrays = [[], [false], [false, false]]; + internal static readonly bool[][] FalseArrays = [ + [], + [false], + [false, false], + [false, false, false] + ]; } diff --git a/test/EFCore.PG.FunctionalTests/Query/ArrayArrayQueryTest.cs b/test/EFCore.PG.FunctionalTests/Query/ArrayArrayQueryTest.cs index 2b481dfcd5..cbe860667c 100644 --- a/test/EFCore.PG.FunctionalTests/Query/ArrayArrayQueryTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/ArrayArrayQueryTest.cs @@ -835,7 +835,7 @@ await AssertQuery( """ SELECT s."Id", s."ArrayContainerEntityId", s."ArrayOfStringConvertedToDelimitedString", s."Byte", s."ByteArray", s."Bytea", s."EnumConvertedToInt", s."EnumConvertedToString", s."IList", s."IntArray", s."IntList", s."ListOfStringConvertedToDelimitedString", s."NonNullableText", s."NullableEnumConvertedToString", s."NullableEnumConvertedToStringWithNonNullableLambda", s."NullableIntArray", s."NullableIntList", s."NullableStringArray", s."NullableStringList", s."NullableText", s."StringArray", s."StringList", s."ValueConvertedArrayOfEnum", s."ValueConvertedListOfEnum", s."Varchar10", s."Varchar15" FROM "SomeEntities" AS s -WHERE array_position(s."IntArray", 6) - 1 = 1 +WHERE COALESCE(array_position(s."IntArray", 6) - 1, -1) = 1 """); } @@ -849,7 +849,7 @@ await AssertQuery( """ SELECT s."Id", s."ArrayContainerEntityId", s."ArrayOfStringConvertedToDelimitedString", s."Byte", s."ByteArray", s."Bytea", s."EnumConvertedToInt", s."EnumConvertedToString", s."IList", s."IntArray", s."IntList", s."ListOfStringConvertedToDelimitedString", s."NonNullableText", s."NullableEnumConvertedToString", s."NullableEnumConvertedToStringWithNonNullableLambda", s."NullableIntArray", s."NullableIntList", s."NullableStringArray", s."NullableStringList", s."NullableText", s."StringArray", s."StringList", s."ValueConvertedArrayOfEnum", s."ValueConvertedListOfEnum", s."Varchar10", s."Varchar15" FROM "SomeEntities" AS s -WHERE array_position(s."IntArray", 6, 2) - 1 = 1 +WHERE COALESCE(array_position(s."IntArray", 6, 2) - 1, -1) = 1 """); } diff --git a/test/EFCore.PG.FunctionalTests/Query/ArrayListQueryTest.cs b/test/EFCore.PG.FunctionalTests/Query/ArrayListQueryTest.cs index cfe968bb5d..02ef5d2a75 100644 --- a/test/EFCore.PG.FunctionalTests/Query/ArrayListQueryTest.cs +++ b/test/EFCore.PG.FunctionalTests/Query/ArrayListQueryTest.cs @@ -856,7 +856,7 @@ await AssertQuery( """ SELECT s."Id", s."ArrayContainerEntityId", s."ArrayOfStringConvertedToDelimitedString", s."Byte", s."ByteArray", s."Bytea", s."EnumConvertedToInt", s."EnumConvertedToString", s."IList", s."IntArray", s."IntList", s."ListOfStringConvertedToDelimitedString", s."NonNullableText", s."NullableEnumConvertedToString", s."NullableEnumConvertedToStringWithNonNullableLambda", s."NullableIntArray", s."NullableIntList", s."NullableStringArray", s."NullableStringList", s."NullableText", s."StringArray", s."StringList", s."ValueConvertedArrayOfEnum", s."ValueConvertedListOfEnum", s."Varchar10", s."Varchar15" FROM "SomeEntities" AS s -WHERE array_position(s."IntList", 6) - 1 = 1 +WHERE COALESCE(array_position(s."IntList", 6) - 1, -1) = 1 """); } @@ -872,7 +872,7 @@ await AssertQuery( """ SELECT s."Id", s."ArrayContainerEntityId", s."ArrayOfStringConvertedToDelimitedString", s."Byte", s."ByteArray", s."Bytea", s."EnumConvertedToInt", s."EnumConvertedToString", s."IList", s."IntArray", s."IntList", s."ListOfStringConvertedToDelimitedString", s."NonNullableText", s."NullableEnumConvertedToString", s."NullableEnumConvertedToStringWithNonNullableLambda", s."NullableIntArray", s."NullableIntList", s."NullableStringArray", s."NullableStringList", s."NullableText", s."StringArray", s."StringList", s."ValueConvertedArrayOfEnum", s."ValueConvertedListOfEnum", s."Varchar10", s."Varchar15" FROM "SomeEntities" AS s -WHERE array_position(s."IntList", 6, 2) - 1 = 1 +WHERE COALESCE(array_position(s."IntList", 6, 2) - 1, -1) = 1 """); }