← All notes

Notes · 2026-09-06

ArcadeDB fixed the pg_type bootstrap within a day, verified on the merged build

The native PostgreSQL ADBC driver could not connect to ArcadeDB; a probe comment became a diagnosed issue, a fix and a merge within a day. Verified.

The native-driver probe of 2026-09-05 found that the Apache Arrow PostgreSQL ADBC driver (1.12.0) could not open a connection to ArcadeDB's PostgreSQL-protocol plugin at all. This note records what happened next, because it happened fast, and because the first verification needed a correction.

Timeline

When (UTC) What
2026-09-05 21:19 Follow-up comment on ArcadeDB's discussion thread with the probe result: Expected 5 or 6 columns from type resolver pg_type query but got 0
22:11 ArcadeDB's maintainer opened #7178 with the diagnosis
22:33 Fix PR #7179 opened, with tests
22:44 Verified on the PR's CI image: the driver connects (see the correction below)
22:47 Maintainer filed #7180 for what the driver hits next
2026-09-06 02:48 PR merged; #7178 closed
03:05 Verified again on the merged code, this time with the fixture types present
03:29 Maintainer opened PR #7187 for the ::regclass cast behind GetTableSchema, and #7188 for binary COPY
04:2x Verified #7187 on its CI build: GetTableSchema answers with five and eight fields
06:31 #7187 merged; #7180 closed

What was wrong

The driver bootstraps its type resolver with three queries before it hands back a connection, and it checks the shape of each answer: zero rows are fine, zero columns are fatal. The third query selects oid, typname, typreceive, typbasetype, typrelid, typarray from pg_catalog.pg_type with a WHERE clause of inequalities, a parenthesised OR and a ::TEXT cast. ArcadeDB's emulated pg_type knew neither typreceive nor typsend, and its WHERE parser accepted a single equality only, so the whole projection was declined and the answer had no columns. The fix teaches the emulation those columns, with PostgreSQL's real receive and send function names (the driver selects a column's decoder by that name), and registers pg_type as a query family of its own so the filter is evaluated.

What the merged build does now

Same seven-step probe, native driver, fixture types created first:

Step Driver defaults With adbc.postgresql.use_copy=false
connect passes passes
SELECT 1 stops: COPY (…) TO STDOUT (FORMAT binary) is not ArcadeDB SQL passes
GetTableSchema empty schema, then five fields with #7187 same
GetObjects lists both types lists both types
read the fixture table stops at COPY passes; @rid, @type, @cat as strings, the five properties as int64, string, double, date32 and bool

So the fix does exactly what #7178 says, and with one driver option the native driver now runs the read workload against ArcadeDB end to end apart from the schema lookup. adbcBridge over psqlodbc passes all seven steps before and after, as it did in the original probe.

ArcadeDB published their own account of this fix and the three that followed it on 2026-09-21: ArcadeDB in the Apache Arrow Ecosystem, Through Its PostgreSQL Wire Protocol.

What is left, and where it is tracked

Both items were in #7180 with the driver's exact statements; one is fixed, one is tracked on its own:

  • Binary COPY … TO STDOUT, #7188, implemented in #7398 on 2026-09-10, four days after it was split out: text, csv and binary, both protocol paths, in 26.10.1. Verified on the snapshot the same day: the stream is correct on the wire and the rows match the Describe OIDs byte for byte, but the Arrow driver's default path still stops at the first row, because ArcadeDB sends the 19-byte binary header as its own CopyData message and PostgreSQL sends it inside the first row's message, which is what the driver's reader expects. Fixed on 2026-09-15 in #7607, the morning after the byte-level report: on the 26.10.1-SNAPSHOT build that carries it, the Arrow driver with its defaults passes the whole seven-step probe and decodes real rows through binary COPY. use_copy=false is no longer needed from 26.10.1. The issue was closed on 2026-09-15, and a wider check on the same build passed with the driver's defaults: an empty result set (header and trailer with no rows, the case the fix names), one row, 10,000 rows in one COPY, a NULL in every column, text outside the Basic Multilingual Plane, GetTableSchema and GetObjects.
  • GetTableSchema, now fixed. The driver's statement joins pg_class, pg_attribute and pg_type with cls.oid = $1::regclass::oid; ArcadeDB ignored the regclass cast, so a name was compared with a number and the statement was answered with zero rows. PR #7187 makes ::regclass and ::regtype real lookups; on its build adbc_big describes with its five properties and adbc_t with all eight, and the whole seven-step read probe passes with use_copy=false.

All three fixes ship in ArcadeDB 26.10.1, the October release, and are in the 26.10.1-SNAPSHOT build now. With them the native driver works out of the box; the ArcadeDB row in the probe note and on the ArcadeDB page will say so once 26.10.1 is out.

A correction to the first verification

The first verification, on the PR's CI image, reported two further stops that were not ArcadeDB's: GetObjects returning no tables and SELECT * FROM "adbc_big" failing with "type not found". Both came from the probe's own order of operations. It runs the native driver before the ODBC pass, and the ODBC pass is what creates the fixture types, so on a freshly started image the native run saw a database with nothing in it. With the types present, GetObjects lists everything and quoted identifiers work. The correction was posted on the PR and on #7180 the same evening, and the probe is now run twice on a fresh server so the second pass measures a populated database.

Trying it

docker run -d -p 5432:5432 \
  -e JAVA_OPTS="-Darcadedb.server.rootPassword=… -Darcadedb.server.defaultDatabases=adbc[adbc:adbc] \
     -Darcadedb.server.plugins=Postgres:com.arcadedb.postgres.PostgresProtocolPlugin" \
  arcadedata/arcadedb:latest
import adbc_driver_postgresql.dbapi as pg
from adbc_driver_postgresql import StatementOptions
conn = pg.connect("postgresql://root:…@127.0.0.1:5432/adbc", autocommit=True)
cur = conn.cursor()
cur.adbc_statement.set_options(**{StatementOptions.USE_COPY.value: "false"})
cur.execute("SELECT * FROM adbc_big")
print(cur.fetch_arrow_table())

Until 26.10.1 is out, that needs the 26.10.1-SNAPSHOT build. The ODBC route works on the released 26.9.1 today:

import adbcbridge
conn = adbcbridge.connect(uri="Driver=psqlodbcw.so;Server=127.0.0.1;Port=5432;Database=adbc;Uid=root;Pwd=…;BoolsAsChar=0;")