Skip to content

postgres: infer RETURNING OLD/NEW columns as nullable - #4360

Open
DoTuanAnh2k1 wants to merge 1 commit into
transact-rs:mainfrom
DoTuanAnh2k1:fix/pg-returning-old-new-nullable
Open

postgres: infer RETURNING OLD/NEW columns as nullable#4360
DoTuanAnh2k1 wants to merge 1 commit into
transact-rs:mainfrom
DoTuanAnh2k1:fix/pg-returning-old-new-nullable

Conversation

@DoTuanAnh2k1

Copy link
Copy Markdown

Why

sqlx::query! infers a non-nullable column for a RETURNING old.<col> clause even when the value is null at runtime, producing an unexpected-null error.

A RETURNING clause can reference the OLD/NEW transition relations (Postgres 18+). Those columns are nullable regardless of the underlying column's NOT NULL constraint:

  • OLD is null for a row added by INSERT (including ON CONFLICT DO NOTHING),
  • NEW is null for a row removed by DELETE.

The EXPLAIN-based nullability inference only marked outer-join columns as nullable, so RETURNING old.hash on a NOT NULL PRIMARY KEY was reported as non-nullable (see #4332).

What changed

visit_plan now marks any ModifyTable output referencing an old./new. transition relation as nullable, mirroring the existing over-approximation used for outer joins (a false positive here is safe; a false negative causes the runtime error). This required parsing the Node Type field from the EXPLAIN plan.

Testing

Added a unit test built from the exact EXPLAIN (VERBOSE, FORMAT JSON) output in #4332; it fails on the current code ([None]) and passes with the fix ([Some(true)]). cargo test -p sqlx-postgres, cargo fmt --check and cargo clippy -p sqlx-postgres are clean.

Fixes #4332.


Disclosure: prepared with AI assistance.

A `RETURNING` clause can reference the OLD/NEW transition relations
(Postgres 18+). Those columns are nullable even when the underlying
column is NOT NULL: OLD is null for a row added by INSERT (including
`ON CONFLICT DO NOTHING`) and NEW is null for one removed by DELETE.

The EXPLAIN-based nullability inference didn't account for this and
reported such columns as non-nullable, causing an unexpected-null error
at runtime with the query macros.

Fixes transact-rs#4332.
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.

Postgres: nullability false-negative in INSERT ... DO NOTHING ... RETURNING ...

1 participant