From 6d8dc7b23c97e9cae3a641c5990a1ea78f58cf60 Mon Sep 17 00:00:00 2001 From: singhpratech <42719720+singhpratech@users.noreply.github.com> Date: Tue, 22 Sep 2026 12:36:53 -0400 Subject: [PATCH] docs: ArcadeDB #8090 fixed in #8096, verified on the 26.10.1 snapshot Luca Garulli merged the fix at 04:07 UTC on 2026-09-22, closing the issue with "Fixed in 26.10.1". Retested here the same day on the 26.10.1-SNAPSHOT image (build 382ae09d, sixty commits past the merge commit): the space-and-fraction literal and the bound timestamp parameter both round-trip to the microsecond, an unreadable value now fails the write with SQLSTATE 22023 instead of storing NULL, and the column reaches Arrow as timestamp[us] rather than a string. A second machine ran psycopg over libpq 18 in both parameter formats plus psqlodbc 18 and agreed on every case. The compatibility notes now scope the T-literal requirement to the released 26.9.1 and record one shape still refused after a space separator, a trailing offset given to the second. The tracker row says "fixed" and waits on the 26.10.1 release for the shipped-in line. --- docs/COMPATIBILITY.md | 2 +- docs/UPSTREAM.md | 2 +- tests/compat/README.md | 19 ++++++++++++++----- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/docs/COMPATIBILITY.md b/docs/COMPATIBILITY.md index 1d734e9..5e626fd 100644 --- a/docs/COMPATIBILITY.md +++ b/docs/COMPATIBILITY.md @@ -110,7 +110,7 @@ table with neither gets one partition. The numbers are in | InfluxDB 3 Core (InfluxDB IOx 2.0, Arrow Flight SQL) | Flight SQL ODBC 0.9.7 (Dremio, open source) | PASS (read) | a second Flight SQL server behind the same driver, and it needed no new driver quirk (the `SQLColumns` one is shared with sqlflite — here it crashes only for tables whose Flight SQL schema carries no per-field metadata, InfluxDB's `system` and `information_schema` tables, while the entry's own `iox` tables fetch cleanly); the entry is read-only twice over (InfluxDB 3's SQL is query-only — DDL answers `DDL not supported: `, DML `DML not supported: `, and tables come into existence when line protocol is written to them over the HTTP API — and the driver has no `SQLBindParameter`); server side: a table is tags, fields and a nanosecond `time` column that is always spelled `time`, with no `DATE`, `DECIMAL` or binary type, so the entry reads `time` as `ts` and casts the date back in its own `SELECT`; fetch 1.03M rows/s | | Dremio 26.0.5 (OSS, Arrow Flight SQL) | Flight SQL ODBC 0.9.7 (Dremio, open source) | PASS (read) | the engine that publishes this driver, and it needed no new driver quirk — `no_sql_columns` is keyed on the driver name, so Dremio takes the path shared with sqlflite and InfluxDB, though against Dremio 26 `SQLColumns` does not in fact crash (it describes its 18 result columns and fetches every row), so here the quirk costs a describe rather than avoiding a segfault; read-only because of the driver alone -- Dremio writes fine (`$scratch`, the writable source a stock dremio-oss ships, takes CTAS, and a table created there with a column list is Iceberg and takes `INSERT`), but `SQLBindParameter` is `HYC00 Unsupported function` even after a `SQLPrepare` that succeeds, and `SQLNumParams` reports 0, so no parameter can reach the server and `setup` builds both tables with literal `CREATE TABLE IF NOT EXISTS ... AS SELECT`; unlike sqlflite the driver reports a `DECIMAL`'s declared scale — described as (19, *s*), precision still always 19 — so decimals arrive exact in a wider decimal128 rather than as text; a string literal holding any character outside ISO-8859-1 (a BMP `漢` as much as an emoji) needs the `_UTF8'…'` prefix or Dremio's parser encodes it as ISO-8859-1 and fails planning; server side, the first admin user has to be created over the REST API before any login works, and the query context comes from a `schema` connection property the driver forwards as a gRPC header; fetch 1.1M rows/s | | Microsoft Access `.mdb`/`.accdb` | MDB Tools 1.0 (`odbc-mdbtools`) | PASS (read) | the driver executes no DDL/DML and has no `SQLBindParameter`; 32-bit `SQLLEN`, as Db2 | -| ArcadeDB 26.9 (PostgreSQL wire) | psqlodbc 16 (PG wire) | PASS (read) | multi-model engine behind the PG wire: no `CREATE TABLE` at all (a table is a document type plus one `CREATE PROPERTY` per column), so `adbc_ingest`'s generated DDL has nowhere to go and the entry runs the read side — queries, parameters and the catalog all work; driver quirks handled: psqlodbc's `SQLColumns` and `SQLTables(SQL_ALL_TABLE_TYPES)` are queries its parser will not run -- `SQLColumns` answers `SQL_SUCCESS` with zero rows, `SQLTables(SQL_ALL_TABLE_TYPES)` answers `SQL_ERROR` -- so `GetObjects` describes a zero-row SELECT and `GetTableTypes` falls back to the types the server's own tables have; `BoolsAsChar=0`, ISO-8601 `T` timestamp literals, `@rid`/`@type`/`@cat` in every `SELECT *`; also traverses a small graph (vertices, edges, `expand(out())`); fetch 332k rows/s. ArcadeDB published an account of this integration and the four protocol findings behind it on 2026-09-21: . Native-driver status, for comparison: the Apache Arrow PostgreSQL ADBC driver (1.12.0) could not connect at all until ArcadeDB fixed its `pg_type` bootstrap ([#7178](https://github.com/ArcadeData/arcadedb/issues/7178), opened and merged by the maintainer within a day of the [probe note](https://adbcbridge.org/notes/native-adbc-drivers-on-wire-compatible-databases/), 2026-09-06; ships in 26.10.1, in `26.10.1-SNAPSHOT` now); on the merged build it connects and lists types, stops at `COPY … TO STDOUT (FORMAT binary)` with its defaults, and with `adbc.postgresql.use_copy=false` reads the fixture end to end; `GetTableSchema`'s `::regclass` lookup, the last catalog gap, is fixed in [#7187](https://github.com/ArcadeData/arcadedb/pull/7187) (merged 2026-09-06, also in 26.10.1); binary `COPY` itself, [#7188](https://github.com/ArcadeData/arcadedb/issues/7188), was implemented in [#7398](https://github.com/ArcadeData/arcadedb/pull/7398) and its framing matched to PostgreSQL's in [#7607](https://github.com/ArcadeData/arcadedb/pull/7607) (2026-09-15), so on `26.10.1-SNAPSHOT` the native driver passes the whole probe with its defaults; on the released 26.9.1 the ODBC route above is the one that works | +| ArcadeDB 26.9 (PostgreSQL wire) | psqlodbc 16 (PG wire) | PASS (read) | multi-model engine behind the PG wire: no `CREATE TABLE` at all (a table is a document type plus one `CREATE PROPERTY` per column), so `adbc_ingest`'s generated DDL has nowhere to go and the entry runs the read side — queries, parameters and the catalog all work; driver quirks handled: psqlodbc's `SQLColumns` and `SQLTables(SQL_ALL_TABLE_TYPES)` are queries its parser will not run -- `SQLColumns` answers `SQL_SUCCESS` with zero rows, `SQLTables(SQL_ALL_TABLE_TYPES)` answers `SQL_ERROR` -- so `GetObjects` describes a zero-row SELECT and `GetTableTypes` falls back to the types the server's own tables have; `BoolsAsChar=0`, ISO-8601 `T` timestamp literals, `@rid`/`@type`/`@cat` in every `SELECT *`; also traverses a small graph (vertices, edges, `expand(out())`); fetch 332k rows/s. ArcadeDB published an account of this integration and the four protocol findings behind it on 2026-09-21: . The `T`-literal requirement is a 26.9.1 trait only: the silent `NULL` behind it, [#8090](https://github.com/ArcadeData/arcadedb/issues/8090), is fixed in [#8096](https://github.com/ArcadeData/arcadedb/pull/8096) (merged 2026-09-22, ships in 26.10.1), and on `26.10.1-SNAPSHOT` the space-and-fraction literal and a bound timestamp parameter both round-trip, verified here 2026-09-22. Native-driver status, for comparison: the Apache Arrow PostgreSQL ADBC driver (1.12.0) could not connect at all until ArcadeDB fixed its `pg_type` bootstrap ([#7178](https://github.com/ArcadeData/arcadedb/issues/7178), opened and merged by the maintainer within a day of the [probe note](https://adbcbridge.org/notes/native-adbc-drivers-on-wire-compatible-databases/), 2026-09-06; ships in 26.10.1, in `26.10.1-SNAPSHOT` now); on the merged build it connects and lists types, stops at `COPY … TO STDOUT (FORMAT binary)` with its defaults, and with `adbc.postgresql.use_copy=false` reads the fixture end to end; `GetTableSchema`'s `::regclass` lookup, the last catalog gap, is fixed in [#7187](https://github.com/ArcadeData/arcadedb/pull/7187) (merged 2026-09-06, also in 26.10.1); binary `COPY` itself, [#7188](https://github.com/ArcadeData/arcadedb/issues/7188), was implemented in [#7398](https://github.com/ArcadeData/arcadedb/pull/7398) and its framing matched to PostgreSQL's in [#7607](https://github.com/ArcadeData/arcadedb/pull/7607) (2026-09-15), so on `26.10.1-SNAPSHOT` the native driver passes the whole probe with its defaults; on the released 26.9.1 the ODBC route above is the one that works | | Materialize 26.38 | psqlodbc 16 (PG wire) | PASS | streaming warehouse; PostgreSQL SQL layer, so no driver quirks -- but no `SAVEPOINT`, so the entry sets psqlodbc's `Protocol=7.4-0` to stop the driver wrapping the second batch of a large ingest in one (with that setting, a prepared statement freed before a manual commit also lost the transaction's rows through a psqlodbc/Materialize pair of defects: fixed in psqlodbc 18.00.0003 and in Materialize [#38606](https://github.com/MaterializeInc/materialize/pull/38606), merged 2026-09-14, verified on its main image, not yet in a Materialize release); its single 39-digit `NUMERIC` is wider than an Arrow decimal128, so decimals read back as exact strings; also ingests into and reads back an incrementally maintained `MATERIALIZED VIEW`; ingest 23.6k rows/s (23.7k with array binding), fetch 322k rows/s | | Apache Ignite 2.17 | Ignite ODBC (built from the sources in the image) | PASS | in-memory key-value grid with a SQL engine: no prebuilt Linux driver exists, so `platforms/cpp` is built root-free (`-DWITH_ODBC=ON -DWITH_CORE=OFF`, no JVM); driver quirks handled: no wide SQL type at all (`SQL_WVARCHAR` refused outright by `SQLBindParameter`, `SQL_C_WCHAR` sized in `wchar_t`) so the UTF-8 narrow path, as for Firebird, and column-wise parameter arrays that test the NULL indicator of row 0 for every row — a NULL below the first row is dropped rather than sent: a character column stores an empty string, and a `BINARY` column segfaults the client inside `SQLExecute` (`WriteInt8Array` is handed the -1 indicator as its length), so arrays are off (row-wise binding is refused outright). `SQL_DRIVER_VER` and `SQL_DBMS_VER` are both the hardcoded `02.04.0000`, neither the server's 2.17.0 nor the negotiated protocol 2.13.0. Server side: every table is a cache and must declare a `PRIMARY KEY`, which generated ingest DDL cannot, so `mode="create"` is impossible (`ingest_create=False`) and the entry ingests by appending into a keyed table; identifiers fold to upper case and the driver reports no quote character. Fetch 930k rows/s; append into a keyed table ~95k rows/s | | Google Cloud Spanner (emulator + PGAdapter 0.55) | psqlodbc 16 (PG wire) | PASS | two driver quirks, both keyed on a PGAdapter-only setting because `version()` just says PostgreSQL 14.1: psqlodbc inlines a parameter array's timestamps as `'...'::timestamp`, a type Spanner does not have, so a batch binding a timestamp goes row-at-a-time (`no_timestamp_param_arrays`); and every Spanner table needs a PRIMARY KEY, so generated ingest DDL adds a surrogate `GENERATED BY DEFAULT AS IDENTITY` column (`ingest_key_column`). Server side: no 32-bit integer, no `TIMESTAMP WITHOUT TIME ZONE` (so `ts` reads back zone-aware), no modifier on `NUMERIC`, no DDL inside a transaction; also ingests into and reads back an `INTERLEAVE IN PARENT` child table. A third quirk on the same key is Spanner's ceiling of **950 parameters per statement** (`max_statement_params`): PGAdapter prepares a multi-row INSERT that carries more without complaint and then closes the connection at `SQLExecute` (`08S01`), leaving the batching's halving search no connection to halve on -- measured exactly, 948 parameters go through and 952 drop the connection -- so it is declared rather than probed, and ingest runs at 237 four-column rows per INSERT. ingest 7.3k rows/s (7.4k with array binding), fetch 95.8k rows/s at `--rows 300 --fetch-rows 2000`, which is the size this entry is benchmarked at | diff --git a/docs/UPSTREAM.md b/docs/UPSTREAM.md index 5573333..52c3892 100644 --- a/docs/UPSTREAM.md +++ b/docs/UPSTREAM.md @@ -48,7 +48,7 @@ before it is filed. | 2026-09-05 | ArcadeDB | [ArcadeData/arcadedb#7178](https://github.com/ArcadeData/arcadedb/issues/7178) (opened by the maintainer from the [discussion follow-up](https://github.com/ArcadeData/arcadedb/discussions/6888#discussioncomment-18309009)) | The Arrow native PostgreSQL ADBC driver cannot connect to ArcadeDB's PostgreSQL-protocol plugin: its type-resolver bootstrap `SELECT oid, typname, typreceive, typbasetype, typrelid, typarray FROM pg_catalog.pg_type WHERE …` is answered with zero columns (`Expected 5 or 6 columns from type resolver pg_type query but got 0`), because the emulated `pg_type` knows neither `typreceive` nor `typsend` and its WHERE parser accepts only a single equality. Found by the 2026-09-05 native-driver probe; the maintainer's own diagnosis is in the issue. | **fixed on main**: [ArcadeData/arcadedb#7179](https://github.com/ArcadeData/arcadedb/pull/7179), opened by the maintainer the same day and merged 2026-09-06 (558e6042); ships in ArcadeDB 26.10.1 (October 2026, per the maintainer) and is in `26.10.1-SNAPSHOT` now. Verified on the PR's CI build with the fixture types present: the native driver connects and `GetObjects` lists the types; with the driver's defaults it then stops at the first result set because ArcadeDB has no `COPY (…) TO STDOUT (FORMAT binary)` (the CockroachDB, CrateDB and YDB stop); with `adbc.postgresql.use_copy=false` reads work end to end and only `GetTableSchema` (its `$1::regclass::oid` lookup) returns an empty schema. Follow-up issue [#7180](https://github.com/ArcadeData/arcadedb/issues/7180) carried the driver's exact statements; its `GetTableSchema` item (the `::regclass` cast) is **fixed in [#7187](https://github.com/ArcadeData/arcadedb/pull/7187)**, merged 2026-09-06 (ec871770), verified on its CI build: five and eight fields with the right Arrow types. Binary `COPY` was tracked as [#7188](https://github.com/ArcadeData/arcadedb/issues/7188), implemented in [#7398](https://github.com/ArcadeData/arcadedb/pull/7398) on 2026-09-10 and framed like PostgreSQL's in [#7607](https://github.com/ArcadeData/arcadedb/pull/7607) on 2026-09-15; with all three, the native driver passes the whole probe with its defaults on `26.10.1-SNAPSHOT`. | | 2026-09-06 | ArcadeDB | [ArcadeData/arcadedb#7188](https://github.com/ArcadeData/arcadedb/issues/7188) (opened by the maintainer from the probe follow-up) | `COPY () TO STDOUT`, text and binary, is not supported by the PostgreSQL-protocol plugin; the Arrow native PostgreSQL ADBC driver reads every result through binary `COPY` by default, so with defaults it stops at the first result set. The driver's `adbc.postgresql.use_copy=false` statement option reads through ordinary binary-format results and works end to end on ArcadeDB, which the issue records. | **fixed on main**: [ArcadeData/arcadedb#7398](https://github.com/ArcadeData/arcadedb/pull/7398) (merged 2026-09-10) implemented `COPY () TO STDOUT` in text, csv and binary on both protocol paths; the one framing detail left between it and the Arrow driver's default path (the binary header sent as its own `CopyData` message, [reported](https://github.com/ArcadeData/arcadedb/issues/7188#issuecomment-5647328956) with both servers' chunk dumps on 2026-09-12) was fixed by the maintainer in [ArcadeData/arcadedb#7607](https://github.com/ArcadeData/arcadedb/pull/7607), merged 2026-09-15 (3bdb3451b). Verified the same morning on `26.10.1-SNAPSHOT` build 99f4cb48: the Arrow PostgreSQL ADBC driver 1.12.0 with its defaults passes all seven probe steps and decodes real rows (int64, string, double, date32, bool) through binary COPY, no `use_copy=false` needed. The maintainer closed the issue on 2026-09-15; re-verified the same day past the probe — 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, non-BMP text, `GetTableSchema` and `GetObjects` — all correct with the driver's defaults. Ships in ArcadeDB 26.10.1 | | 2026-09-04 | SingleStore Connector/ODBC | [memsql/singlestore-odbc-connector#46](https://github.com/memsql/singlestore-odbc-connector/issues/46) | `SQLColumns` with a NULL `CatalogName` segfaults the client on a connection opened without `Database=`: `TABLE_CAT` falls back to the client library's current-database field, which stays NULL after `USE`, and `strdup(NULL)` is called (`ma_statement.c`). Zero matching rows, an explicit catalog, or `Database=` in the connection string avoid it. | open — **fix PR [#47](https://github.com/memsql/singlestore-odbc-connector/pull/47) (ours)**, opened 2026-09-17: `TABLE_CAT` NULL instead of `strdup(NULL)` in `SQLColumns` and `SQLPrimaryKeys`, with a test; verified against SingleStore 9.1.1 | -| 2026-09-21 | ArcadeDB | [ArcadeData/arcadedb#8090](https://github.com/ArcadeData/arcadedb/issues/8090) | A `DATETIME_MICROS` (also `DATETIME_NANOS`, `DATETIME`) value written as a string with a space separator **and** a fractional second — `'2024-02-29 13:45:10.123456'`, exactly the form psqlodbc renders a bound timestamp in — is stored as `NULL` while the `INSERT` reports success. Either half alone is fine: the `T` separator round-trips, and the space form without a fraction round-trips. Carried into the project's own tracker by a maintainer after we documented it in the compatibility notes, with the root cause named: a blanket catch in `Type.convert()` logs at `FINE` and returns `null`. Every PostgreSQL-wire client that binds a timestamp against a sub-second property is affected, not only this driver | **open**, filed 2026-09-21 by the project (Luca Garulli) and labelled `severity:critical`, crediting the report; a reproducer and the root cause are in the issue. ArcadeDB published an account of this and the three earlier findings on 2026-09-21: [arcadedb.com](https://arcadedb.com/blog/arcadedb-apache-arrow-adbc-postgresql-wire/) | +| 2026-09-21 | ArcadeDB | [ArcadeData/arcadedb#8090](https://github.com/ArcadeData/arcadedb/issues/8090) | A `DATETIME_MICROS` (also `DATETIME_NANOS`, `DATETIME`) value written as a string with a space separator **and** a fractional second — `'2024-02-29 13:45:10.123456'`, exactly the form psqlodbc renders a bound timestamp in — is stored as `NULL` while the `INSERT` reports success. Either half alone is fine: the `T` separator round-trips, and the space form without a fraction round-trips. Carried into the project's own tracker by a maintainer after we documented it in the compatibility notes, with the root cause named: a blanket catch in `Type.convert()` logs at `FINE` and returns `null`. Every PostgreSQL-wire client that binds a timestamp against a sub-second property is affected, not only this driver | **fixed** in [#8096](https://github.com/ArcadeData/arcadedb/pull/8096), merged 2026-09-22 by the project (Luca Garulli), who had filed the issue on 2026-09-21 as `severity:critical`, crediting the report and naming the root cause. The space-and-fraction form is now accepted, and a value no parser can read fails the write with an error naming it instead of storing `NULL`; reads stay lenient and return `NULL`. Verified here on `26.10.1-SNAPSHOT` (build `382ae09d`, 60 commits past the merge) on 2026-09-22: the literal and the bound parameter both round-trip to the microsecond, an unreadable value raises SQLSTATE 22023 through psqlodbc, and the column now reaches Arrow as `timestamp[us]` rather than a string. Awaiting the 26.10.1 release. ArcadeDB published an account of this and the three earlier findings on 2026-09-21: [arcadedb.com](https://arcadedb.com/blog/arcadedb-apache-arrow-adbc-postgresql-wire/) | ## Documented here, not yet reported diff --git a/tests/compat/README.md b/tests/compat/README.md index f198836..7f05aaa 100644 --- a/tests/compat/README.md +++ b/tests/compat/README.md @@ -3516,13 +3516,22 @@ that path, since every other driver answers the enumeration. * **`decimal_type="decimal128(28, 3)"`.** ArcadeDB reports no declared precision for a `DECIMAL` property, so psqlodbc falls back to its own maximum (28) with the scale of the values in the result set — as it does for RisingWave's unqualified `NUMERIC`. -* **Timestamp literals need the ISO-8601 `T`.** Reported upstream on 2026-09-21 as +* **Timestamp literals need the ISO-8601 `T`** on the released 26.9.1, and no longer on + 26.10.1. Reported upstream on 2026-09-21 as [ArcadeData/arcadedb#8090](https://github.com/ArcadeData/arcadedb/issues/8090), - `severity:critical`. `'2024-02-29 13:45:10.123456'` into a - `DATETIME_MICROS` property is stored as `NULL`, silently; - `'2024-02-29T13:45:10.123456'` round-trips to the microsecond. (A bound + `severity:critical`, and fixed in + [#8096](https://github.com/ArcadeData/arcadedb/pull/8096), merged 2026-09-22. On 26.9.1, + `'2024-02-29 13:45:10.123456'` into a `DATETIME_MICROS` property is stored as `NULL`, + silently, while `'2024-02-29T13:45:10.123456'` round-trips to the microsecond; a bound `SQL_TYPE_TIMESTAMP` parameter goes as the space form, so it hits the same silent NULL — - a reason to write timestamps as ISO text against this server.) + a reason to write timestamps as ISO text against that release. Retested on + `26.10.1-SNAPSHOT` (build `382ae09d`) on 2026-09-22: both the literal and the bound + parameter round-trip, a value no parser can read fails the write (SQLSTATE 22023 through + psqlodbc) rather than storing `NULL`, and the column reaches Arrow as `timestamp[us]` + instead of a string. The ISO form works on both, so writing ISO text stays the portable + choice. One narrower shape is still refused after a space separator, a trailing offset + given to the second (`+05:30:00`); it is accepted after a `T`, and `+05`, `+05:30` and + `Z` are accepted after either. * **No binary transport.** A bound `bytea` parameter is refused by the protocol layer outright (`Error on parsing bind message: Type with code 0 not supported for deserializing`), and a `BINARY` property fed a string hands the string straight back.