Skip to content

Fix JSON null partial updates#3855

Merged
roji merged 2 commits into
npgsql:mainfrom
roji:roji/triage-json-null
Jun 2, 2026
Merged

Fix JSON null partial updates#3855
roji merged 2 commits into
npgsql:mainfrom
roji:roji/triage-json-null

Conversation

@roji
Copy link
Copy Markdown
Member

@roji roji commented Jun 2, 2026

JSON partial updates currently allow SQL NULL values to flow into PostgreSQL JSON update functions, which can produce SQL NULL for the entire JSON document instead of writing JSON null.

This updates JSON partial update translation to use PostgreSQL 16's jsonb_set_lax for nullable jsonb updates, relying on its default use_json_null behavior. Older/non-lax paths continue to use jsonb_set/json_set with explicit JSON-null fallback. SQL baselines were updated for the affected JSON bulk update and type tests.

Addresses #3850.

Tests:

  • dotnet test --no-restore

Use jsonb_set_lax for JSONB partial updates when targeting PostgreSQL 16 or later so SQL null values are written as JSON null rather than nulling the whole document. Keep older PostgreSQL versions on jsonb_set/json_set with a JSON null fallback for nullable update values.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 2, 2026 13:21
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

This PR fixes JSON/jsonb partial-update translation for ExecuteUpdate(Async) so that CLR null updates write JSON null instead of accidentally flowing SQL NULL into PostgreSQL JSON update functions (which can null out the entire JSON document). For PostgreSQL 16+ (and non-Redshift), it prefers jsonb_set_lax to rely on its default use_json_null behavior; older/non-lax paths keep using explicit JSON-null fallback behavior.

Changes:

  • Update JSON scalar serialization and JSON partial-update setter generation to correctly treat SQL NULL as JSON null and to use jsonb_set_lax when supported.
  • Add helper logic to detect nullable SQL expressions and apply COALESCE(..., 'null'::jsonb/json) when jsonb_set_lax isn’t available.
  • Update functional test SQL baselines for JSON bulk updates and various JSON type tests to reflect the new SQL shape.
Show a summary per file
File Description
src/EFCore.PG/Query/Internal/NpgsqlQueryableMethodTranslatingExpressionVisitor.cs Implements JSON null handling and switches to jsonb_set_lax on PG16+ for nullable JSONB partial updates.
test/EFCore.PG.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonBulkUpdateNpgsqlTest.cs Updates bulk-update SQL baselines to expect jsonb_set_lax where applicable.
test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlTimeSpanTypeTest.cs Updates JSON ExecuteUpdate SQL baselines to jsonb_set_lax.
test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlTimeOnlyTypeTest.cs Updates JSON ExecuteUpdate SQL baselines to jsonb_set_lax.
test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeUtcTypeTest.cs Updates JSON ExecuteUpdate SQL baselines to jsonb_set_lax.
test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeUnspecifiedTypeTest.cs Updates JSON ExecuteUpdate SQL baselines to jsonb_set_lax.
test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateTimeOffsetTypeTest.cs Updates JSON ExecuteUpdate SQL baselines to jsonb_set_lax.
test/EFCore.PG.FunctionalTests/Types/Temporal/NpgsqlDateOnlyTypeTest.cs Updates JSON ExecuteUpdate SQL baselines to jsonb_set_lax.
test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlShortTypeTest.cs Updates JSON ExecuteUpdate SQL baselines to jsonb_set_lax.
test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlLongTypeTest.cs Updates JSON ExecuteUpdate SQL baselines to jsonb_set_lax.
test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlIntTypeTest.cs Updates JSON ExecuteUpdate SQL baselines to jsonb_set_lax.
test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlFloatTypeTest.cs Updates JSON ExecuteUpdate SQL baselines to jsonb_set_lax.
test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlDoubleTypeTest.cs Updates JSON ExecuteUpdate SQL baselines to jsonb_set_lax.
test/EFCore.PG.FunctionalTests/Types/Numeric/NpgsqlDecimalTypeTest.cs Updates JSON ExecuteUpdate SQL baselines to jsonb_set_lax.
test/EFCore.PG.FunctionalTests/Types/Networking/NpgsqlMacaddrTypeTest.cs Updates JSON ExecuteUpdate SQL baselines to jsonb_set_lax.
test/EFCore.PG.FunctionalTests/Types/Networking/NpgsqlInetTypeTest.cs Updates JSON ExecuteUpdate SQL baselines to jsonb_set_lax.
test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlStringTypeTest.cs Updates JSON ExecuteUpdate SQL baselines to jsonb_set_lax.
test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlGuidTypeTest.cs Updates JSON ExecuteUpdate SQL baselines to jsonb_set_lax.
test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlByteArrayTypeTest.cs Updates JSON ExecuteUpdate SQL baselines to jsonb_set_lax.
test/EFCore.PG.FunctionalTests/Types/Miscellaneous/NpgsqlBoolTypeTest.cs Updates JSON ExecuteUpdate SQL baselines to jsonb_set_lax.

Copilot's findings

  • Files reviewed: 20/20 changed files
  • Comments generated: 1

Keep generated JSON null expressions typed with the JSON type mapping CLR type instead of object, so COALESCE and JSON setter expressions stay well-typed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@roji roji merged commit 5f95083 into npgsql:main Jun 2, 2026
10 checks passed
@roji roji deleted the roji/triage-json-null branch June 2, 2026 16:48
roji added a commit that referenced this pull request Jun 2, 2026
Fixes #3850

(cherry picked from commit 5f95083)
@roji
Copy link
Copy Markdown
Member Author

roji commented Jun 2, 2026

Backported to 10.0.3 via 78e671c

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