Skip to content

Arrays with a NULL element (int4[], text[], etc.) decode to null instead of preserving the null slot #73

Description

@aesslinger

Describe the bug

For the hardcoded array fast-paths in extract.rs (INT2_ARRAY, INT4_ARRAY, INT8_ARRAY, TEXT_ARRAY/VARCHAR_ARRAY, FLOAT4_ARRAY, FLOAT8_ARRAY, BOOL_ARRAY), an array containing even one NULL element decodes to null for the entire column value instead of [value, null].

Root cause: these fast-paths decode via Vec<T>: FromSql (e.g. Vec<i32>), not Vec<Option<T>>. tokio-postgres's Vec<T>::from_sql calls T::from_sql_nullable per element and propagates an error the moment any element is absent, since plain T has no "missing" representation. try_extract's catch-all then turns that error into JsonValue::Null for the whole column.

To Reproduce

SELECT ARRAY[1, NULL];        -- int4[] -> returns null, not [1, null]
SELECT ARRAY['a', NULL];      -- text[] -> returns null, not ["a", null]
SELECT ARRAY[true, NULL];     -- bool[] -> returns null, not [true, null]

Discovered via

Found while regression-testing #71/#72 (hstore and array-of-custom-OID-type fixes). Confirmed via git stash that this behavior is unchanged by those fixes — it exists identically on main. Notably, the new generic array decoder added in #72 (for enum[]/hstore[]/etc.) does not have this bug — it correctly decodes ARRAY['happy'::mood, NULL] as ["happy", null], since it parses each element's length prefix directly (-1 length = null) rather than going through Vec<T>: FromSql.

Suggested fix

Change the hardcoded fast-paths to decode via Vec<Option<T>> instead of Vec<T>, mapping each Option<T> to JsonValue (null-safe) instead of T directly. Matches the builtin driver's extract/array.rs, which fills a Null slot per failed/absent element rather than nulling the whole array (see extract_recursively_or_fill_nulls_into's fill_nulls fallback).

Relevant Log Output

N/A — no error, just silent whole-array null.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions