Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -79,21 +79,28 @@ public NpgsqlArrayMethodTranslator(NpgsqlSqlExpressionFactory sqlExpressionFacto
// During preprocessing, ArrayIndex and List[] get normalized to ElementAt; so we handle indexing into array/list here
if (method.IsClosedFormOf(Enumerable_ElementAt))
{
// Indexing over bytea is special, we have to use function rather than subscript
if (arguments[0].TypeMapping is NpgsqlByteArrayTypeMapping)
return arguments[0].TypeMapping switch
{
return _sqlExpressionFactory.Function(
"get_byte",
[arguments[0], arguments[1]],
nullable: true,
argumentsPropagateNullability: TrueArrays[2],
typeof(byte));
}

// Try translating indexing inside JSON column
// Note that Length over PG arrays (not within JSON) gets translated by QueryableMethodTranslatingEV, since arrays are primitive
// collections
return _jsonPocoTranslator.TranslateMemberAccess(arguments[0], arguments[1], method.ReturnType);
// Indexing over bytea is special, we have to use function rather than subscript
NpgsqlByteArrayTypeMapping
=> _sqlExpressionFactory.Function(
"get_byte",
[arguments[0], arguments[1]],
nullable: true,
argumentsPropagateNullability: TrueArrays[2],
typeof(byte)),

NpgsqlArrayTypeMapping typeMapping
=> _sqlExpressionFactory.ArrayIndex(
arguments[0],
_sqlExpressionFactory.GenerateOneBasedIndexExpression(arguments[1]),
nullable: true),

// Try translating indexing inside JSON column
// Note that Length over PG arrays (not within JSON) gets translated by QueryableMethodTranslatingEV, since arrays are primitive
// collections
_ => _jsonPocoTranslator.TranslateMemberAccess(arguments[0], arguments[1], method.ReturnType)
};
}

if (method.IsClosedFormOf(Enumerable_SequenceEqual)
Expand Down
3 changes: 3 additions & 0 deletions src/EFCore.PG/Query/Internal/NpgsqlQuerySqlGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1485,6 +1485,9 @@ protected override bool RequiresParentheses(SqlExpression outerExpression, SqlEx
return true;
}

// PG requires function calls to be wrapped in parentheses before indexing on the returned array:
// (string_to_array(c."ContactName", ' '))[1]
case SqlFunctionExpression when outerExpression is PgArrayIndexExpression:
case PgUnknownBinaryExpression:
return true;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,28 @@ WHERE string_to_array(c."ContactName", ' ', 'Maria') = ARRAY[NULL,'Anders']::tex
""");
}

[Fact]
public void StringToArray_with_index()
{
using var context = CreateContext();
var count = context.Customers
.Select(c => EF.Functions.StringToArray(c.ContactName, " ")[0])
.Distinct()
.Count(c => c == "Maria");

Assert.Equal(1, count);

AssertSql(
"""
SELECT count(*)::int
FROM (
SELECT DISTINCT (string_to_array(c."ContactName", ' '))[1] AS c
FROM "Customers" AS c
WHERE (string_to_array(c."ContactName", ' '))[1] = 'Maria'
) AS c0
""");
}

[Fact]
public void ToDate()
{
Expand Down