Skip to content

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

Merged
roji merged 7 commits intonpgsql:hotfix/10.0.2from
georg-jung:hotfix/issue-3816
Apr 26, 2026
Merged

Translate bytea.Any() as length > 0#3817
roji merged 7 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

Fixes #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 thread test/EFCore.PG.FunctionalTests/Query/ArrayArrayQueryTest.cs Outdated
Copy link
Copy Markdown
Member

@roji roji left a comment

Choose a reason for hiding this comment

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

Thanks @georg-jung, see some notes.

Can you also please retarget this PR against main, as I don't think we should patch 10.0.x with it?

Ah, I see this is a regression from 8, in that case we should indeed patch 10.0.x.

[ConditionalFact]
public virtual async Task Bytea_Length_greater_than_zero()
{
await AssertQuery(ss => ss.Set<ArrayEntity>().Where(e => e.Bytea.Length > 0));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this test for Any(), rather than for Length > 0?

Also, can you please move this test to ByteArrayTranslationsNpgsqlTest? The latter is then newer place for this kind of test (ArrayArrayQueryTest should eventually disappear).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Actually I'm slightly confused, as #3816 talks about Length > 0 not working, but this PR implements support for Any() - are both broken, or just one of them? I'm noting that ByteArrayTranslationsNpgsqlTest does have test coverage for Length, so I assume it's working and the problem is only with Any?

Copy link
Copy Markdown
Contributor Author

@georg-jung georg-jung Apr 26, 2026

Choose a reason for hiding this comment

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

What caused the regression is that .Length > 0 was translated similar to .Length == 7 until incl. EF8, but as far as I understand it, EF started to rewrite .Length > 0 to .Any internally from EF 9. Thus, to effectively fix .Length > 0, this PR implements .Any.

Options include:

  • test .Length > 0 (what we currently have); goes through the .Any path internally but the expression and the sql both use Length
  • also test .Any in the expression, same translation, two tests
  • only test .Any, also same translation

Copy link
Copy Markdown
Contributor Author

@georg-jung georg-jung Apr 26, 2026

Choose a reason for hiding this comment

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

I went for

also test .Any in the expression, same translation, two tests

in 05db0b8 now.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Probably dotnet/efcore#33644 introduced this

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

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

@georg-jung georg-jung changed the title Translate bytea.Any() as octet_length > 0 Translate bytea.Any() as length > 0 Apr 26, 2026
Copy link
Copy Markdown
Member

@roji roji left a comment

Choose a reason for hiding this comment

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

OK, all good - looks almost ready to merge.

}

[ConditionalFact]
public virtual async Task Length_greater_than_zero()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do you think this test is necessary, given that we already have coverage for Length and Any? This tests a composite tree pattern (so both ByteArray.Length and greater-than-zero), but we usually do that only when there's a special casing - here it seems like it's just the regular translation for Length, and then the regular translation for greater-than-zero.

Another way to think about it, is that AFAICT this doesn't add any more coverage than Length_greater_than_one, Length_greater_than_two would (and obviously we wouldn't do them).

(I understand that we now normalize Length > 0 to Any() - which is slightly "special" - but we already have the direct Any() test below to cover that)

So unless you think there's a specific reason for this test, we can consider removing it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I saw #3817 (comment) - I'm still not sure that test really adds anything, but I'm also OK with leaving it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Makes sense. I agree that one of them is sufficient to cover the relevant code paths, so I removed the Length > 0 test in e2ad4b0

@georg-jung
Copy link
Copy Markdown
Contributor Author

georg-jung commented Apr 26, 2026

(I'm not a user of EF 9, just wanted to note that we could consider cherry picking this in https://github.com/npgsql/efcore.pg/tree/hotfix/9.0.5 once merged, given the regression was introduced in EF9)

Copy link
Copy Markdown
Member

@roji roji left a comment

Choose a reason for hiding this comment

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

Thanks @georg-jung!

}

[ConditionalFact]
public virtual async Task Any()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

BTW I'll "promote" this test to the EF test suite later as it's not very PG-specific.

@roji roji merged commit 7ce26dd into npgsql:hotfix/10.0.2 Apr 26, 2026
10 checks passed
roji pushed a commit that referenced this pull request Apr 26, 2026
Fixes #3816

(cherry picked from commit 7ce26dd)
roji pushed a commit that referenced this pull request Apr 26, 2026
Fixes #3816

(cherry picked from commit 7ce26dd)
@roji
Copy link
Copy Markdown
Member

roji commented Apr 26, 2026

Forwarded-ported to main (11) via a964a63
Backported to 9.0.5 via 15982e5

@roji
Copy link
Copy Markdown
Member

roji commented Apr 26, 2026

Thanks @georg-jung!

@georg-jung
Copy link
Copy Markdown
Contributor Author

Thank you for the quick and insightful reviews, as always 🚀

@georg-jung georg-jung deleted the hotfix/issue-3816 branch April 26, 2026 11:21
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.

3 participants