Skip to content

fix(#654): bind UUID array parameters for PostgreSQL ADBC - #656

Merged
cofin merged 2 commits into
mainfrom
feat/adbc-arrow-types
Jul 25, 2026
Merged

fix(#654): bind UUID array parameters for PostgreSQL ADBC#656
cofin merged 2 commits into
mainfrom
feat/adbc-arrow-types

Conversation

@cofin

@cofin cofin commented Jul 24, 2026

Copy link
Copy Markdown
Member

Binding a list of UUIDs as a single PostgreSQL array parameter through an ADBC driver failed before the query ever reached the database. This makes UUID arrays bind correctly, and along the way fixes a separate case where a UUID that was a statement's only parameter reached PostgreSQL as bytea.

  • UUID arrays now bind as one array parameter. Queries such as WHERE id = ANY(CAST(? AS UUID[])) work, and the cast is added automatically when the query does not already supply one. PyArrow cannot build a nested extension array from Python objects at all, so the values are sent as a string array with an explicit UUID[] cast.
  • A cast you write yourself is now honored. A caller-supplied UUID[] cast used to be treated as a foreign cast, which silently left the values unconverted.
  • Fixed: a lone UUID parameter reached PostgreSQL as bytea. A statement whose only parameter was a UUID skipped UUID binding on every execution after the first, because it took a cached fast path. Statements that bound anything alongside the UUID were unaffected, which is why this went unnoticed.
  • UUID parameters convert about twice as fast. UUID objects are now formatted directly instead of being re-parsed on every execution — measured over 10k rows, conversion drops from 26.5ms to 10.0ms. Bound values are unchanged.
  • Arrays containing None now raise a clear error. The PostgreSQL ADBC driver encodes a null array element as an empty string, which PostgreSQL rejects for UUID[]; previously this surfaced as an opaque invalid input syntax for type uuid failure from the server.

Empty sequences, all-None sequences, and sequences that do not start with a UUID are left untouched, as are non-PostgreSQL ADBC backends.

Fixes #654.

cofin added 2 commits July 24, 2026 21:01
PostgreSQL-family ADBC formatted every UUID parameter as
str(UUID(str(value))), re-parsing values that were already UUID objects
before formatting them a second time. Format UUID objects directly and
reserve parsing for string inputs, which are the only values that need
validating and canonicalizing.

Bound values are unchanged. Measured over 10k single-ordinal rows,
UUID-object conversion drops from 26.5ms to 10.0ms; the string path is
unaffected.

Also pins the conversion contract with tests: bare strings are never
detected as UUIDs on the single-execution path, while every parseable
string form canonicalizes on the batch path once a UUID object
establishes the ordinal.
Binding a list of UUIDs as one PostgreSQL array parameter failed before
reaching the database. PyArrow 25 cannot build a nested extension array
from Python objects at all, so the only workable representation is a
string array plus an explicit UUID[] cast.

Detection now classifies each parameter as a scalar UUID or a UUID array
by peeking at the first non-null element of a sequence, and the SQL
rewrite emits CAST($n AS UUID[]) for array ordinals. A caller-written
UUID[] cast is recognized as satisfying that requirement rather than
treated as a foreign cast, which previously caused the values to be left
unconverted. Both ordinal kinds share the existing memoized rewrite.

Also fixes a related failure where a UUID that is a statement's only
parameter reached PostgreSQL as bytea. UUID types were absent from the
ADBC type coercion map, so a lone UUID argument took the statement cache
fast path and skipped UUID binding entirely on every execution after the
first. Existing coverage missed this because its statements always bound
an integer alongside the UUID, which forced the slower path.

Arrays containing None are rejected with an explicit message: the
PostgreSQL ADBC driver encodes null array elements as empty strings,
which PostgreSQL rejects for UUID[]. Empty, all-null, and non-UUID-headed
sequences are left untouched.

Statement name generation now uses the shared UUID helper, which prefers
the accelerated implementation when it is installed.

Fixes #654.
@codecov-commenter

codecov-commenter commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.62500% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.11%. Comparing base (3759181) to head (deda1eb).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
sqlspec/adapters/adbc/core.py 91.48% 5 Missing and 3 partials ⚠️
sqlspec/core/statement.py 50.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main     #656   +/-   ##
=======================================
  Coverage   77.11%   77.11%           
=======================================
  Files         475      475           
  Lines       67363    67422   +59     
  Branches     9209     9226   +17     
=======================================
+ Hits        51945    51992   +47     
- Misses      12021    12029    +8     
- Partials     3397     3401    +4     
Flag Coverage Δ
integration 60.72% <70.83%> (+0.02%) ⬆️
py3.10 75.41% <90.62%> (+0.01%) ⬆️
py3.11 75.42% <90.62%> (+<0.01%) ⬆️
py3.12 75.42% <90.62%> (+0.01%) ⬆️
py3.13 75.42% <90.62%> (+<0.01%) ⬆️
py3.14 76.31% <90.62%> (-0.01%) ⬇️
unit 64.57% <90.62%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
sqlspec/core/statement.py 85.36% <50.00%> (ø)
sqlspec/adapters/adbc/core.py 82.62% <91.48%> (+0.77%) ⬆️

... and 4 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@cofin
cofin merged commit 6c5c3b4 into main Jul 25, 2026
24 checks passed
@cofin
cofin deleted the feat/adbc-arrow-types branch July 25, 2026 01:56
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.

ADBC (PostgreSQL): support UUID values nested in array parameters

2 participants