Skip to content

Translate bytea.Any() as octet_length > 0#3817

Open
georg-jung wants to merge 3 commits intonpgsql:hotfix/10.0.2from
georg-jung:hotfix/issue-3816
Open

Translate bytea.Any() as octet_length > 0#3817
georg-jung wants to merge 3 commits intonpgsql:hotfix/10.0.2from
georg-jung:hotfix/issue-3816

Conversation

@georg-jung
Copy link
Copy Markdown
Contributor

@georg-jung georg-jung commented Apr 24, 2026

My naive attempt to fix #3816

I opted for octet_length here because it communicates clearly that it is about byte length, not text length.

Let me know if this goes in the right direction and/or if I should change something.

Have a nice weekend!

(Note that I chose hotfix/10.0.2 as target branch; mostly because executing the test suite with an unreleased preview sdk was somewhat hard to setup)

Copilot AI review requested due to automatic review settings April 24, 2026 16:36
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds translation support for predicate-less Any() on byte[] columns mapped to PostgreSQL bytea, addressing EF Core 9/10’s rewrite of byte[].Length > 0 into Any() which previously failed translation.

Changes:

  • Translate Enumerable.Any() (no predicate) over bytea to a SQL length check (octet_length(...) > 0).
  • Expose EnumerableMethods.AnyWithoutPredicate for method matching.
  • Add a functional test asserting SQL generation for bytea non-emptiness checks.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
test/EFCore.PG.FunctionalTests/Query/ArrayArrayQueryTest.cs Adds coverage asserting SQL for querying non-empty bytea.
src/EFCore.PG/Query/ExpressionTranslators/Internal/NpgsqlByteArrayMethodTranslator.cs Implements translation of bytea.Any() to a SQL length comparison.
src/EFCore.PG/Internal/EnumerableMethods.cs Adds AnyWithoutPredicate MethodInfo for identifying predicate-less Any().

Comment on lines +49 to +58
if (method.GetGenericMethodDefinition().Equals(EnumerableMethods.AnyWithoutPredicate))
{
return _sqlExpressionFactory.GreaterThan(
_sqlExpressionFactory.Function(
"octet_length",
[arguments[0]],
nullable: true,
argumentsPropagateNullability: TrueArrays[1],
typeof(int)),
_sqlExpressionFactory.Constant(0));
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using octet_length here is semantically fine for bytea, but the provider already translates byte[].Length on bytea via length(...) (see src/EFCore.PG/Query/Internal/NpgsqlSqlTranslatingExpressionVisitor.cs:155-165). To keep SQL generation consistent (and match pre-EF9 behavior referenced in #3816), consider using length(arguments[0]) > 0 instead of octet_length(...) > 0.

Copilot uses AI. Check for mistakes.
Comment on lines +682 to +693
[ConditionalFact]
public virtual async Task Bytea_Length_greater_than_zero()
{
await AssertQuery(ss => ss.Set<ArrayEntity>().Where(e => e.Bytea.Length > 0));

AssertSql(
"""
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 octet_length(s."Bytea") > 0
""");
}
Copy link

Copilot AI Apr 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test queries e.Bytea.Length > 0 but asserts SQL for octet_length(...) > 0, which depends on EF Core rewriting Length > 0 into Any() and on the provider translating that. That makes the test name/placement (under Length/Count) a bit misleading and potentially brittle if EF changes its rewrite rules. Consider expressing the intent more directly (e.g., query e.Bytea.Any() and/or rename/move the test under the Any/All region).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants