Skip to content

fix: prefer codec over driver.Valuer for typed-nil in array/composite encoding - #2621

Open
waterWang wants to merge 1 commit into
jackc:masterfrom
waterWang:fix/array-composite-nil-valuer-codec
Open

fix: prefer codec over driver.Valuer for typed-nil in array/composite encoding#2621
waterWang wants to merge 1 commit into
jackc:masterfrom
waterWang:fix/array-composite-nil-valuer-codec

Conversation

@waterWang

Copy link
Copy Markdown
Contributor

Description

When a typed-nil value in an array or composite field implements driver.Valuer, the array and composite codecs bypass the element type's registered Codec and directly call encodePlanDriverValuer. This is incorrect when the type has a registered Codec that should handle nil values (typically encoding as SQL NULL).

This was introduced in #2567.

Fix

Replace the encodePlanDriverValuer shortcut with PlanEncode, which naturally gives precedence to the Codec's PlanEncode before falling back to driver.Valuer encoding. This ensures that types with both a Codec and driver.Valuer use the Codec's nil handling.

Changes

  • pgtype/array_codec.go (text + binary encode paths): Replaced direct encodePlanDriverValuer call with PlanEncode + caching by elemType (same pattern as the non-nil path)
  • **pgtype/composite.go\** (text + binary builder): Replaced direct encodePlanDriverValuerwithPlanEncode(with fallback toencodePlanDriverValuer` if nil)

Fixes #2611

… encoding

When a typed-nil value in an array or composite field implements
driver.Valuer, the array and composite codecs bypass the element
type's registered Codec and directly call encodePlanDriverValuer.
This is incorrect when the type has a registered Codec that should
handle nil values (typically encoding as SQL NULL).

Fix: replace the encodePlanDriverValuer shortcut with PlanEncode,
which naturally gives precedence to the Codec's PlanEncode before
falling back to driver.Valuer encoding. This ensures that types
with both a Codec and driver.Valuer use the Codec's nil handling.

Fixes jackc#2611
@jackc

jackc commented Aug 15, 2026

Copy link
Copy Markdown
Owner

Is this just reversing #2567?

When a typed-nil value in an array or composite field implements driver.Valuer, the array and composite codecs bypass the element type's registered Codec and directly call encodePlanDriverValuer. This is incorrect when the type has a registered Codec that should handle nil values (typically encoding as SQL NULL).

As was mentioned in the issue, that is incorrect.

pgx/pgtype/doc.go

Lines 145 to 153 in 6e4e3e7

Encoding Typed Nils
pgtype encodes untyped and typed nils (e.g. nil and []byte(nil)) to the SQL NULL value without going through the [Codec]
system. This means that [Codec]s and other encoding logic do not have to handle nil or *T(nil).
However, [database/sql] compatibility requires Value to be called on T(nil) when T implements [database/sql/driver.Valuer]. Therefore,
[database/sql/driver.Valuer] values are only considered NULL when *T(nil) where [database/sql/driver.Valuer] is implemented on T not on *T. See
https://github.com/golang/go/issues/8415 and
https://github.com/golang/go/commit/0ce1d79a6a771f7449ec493b993ed2a720917870.

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.

driver.Valuer existence takes precedence over codec for nil values

2 participants