← All notes

Notes · 2026-09-17

Five defects from the sweep, sent upstream as fixes instead of reports

DuckDB ODBC (SQL_DBMS_VER segfault, parameter arrays that store set 0 in every row), ArcadeDB (BEGIN answered with a RowDescription) and SingleStore Connector/ODBC (strdup(NULL) in SQLColumns, SQLGetTypeInfo under ANSI_QUOTES) - what each bug was, how it was pinned down, and the pull request that fixes it.

Until now every finding went upstream as a report with a reproduction. On 2026-09-17 five of them went as pull requests instead: the cause was already known, the fix was small, and a fix with a test is less work for a maintainer than a report. Each section below has the failure as a caller sees it, the cause in the project's own source, and what the pull request changes.

Project What a caller saw Pull request
DuckDB ODBC SQLGetInfo(SQL_DBMS_VER) segfaults under unixODBC; returns an empty string when linked directly duckdb/duckdb-odbc#523
DuckDB ODBC a parameter array stores set 0's value in every row, under SQL_SUCCESS duckdb/duckdb-odbc#524
ArcadeDB [libpq] Failed to begin transaction: from the Arrow PostgreSQL ADBC driver ArcadeData/arcadedb#7815
SingleStore Connector/ODBC SQLColumns with a NULL catalog segfaults memsql/singlestore-odbc-connector#47
SingleStore Connector/ODBC 42S22 Unknown column 'json' from SQLGetTypeInfo under ANSI_QUOTES memsql/singlestore-odbc-connector#48

DuckDB ODBC: SQLGetInfo(SQL_DBMS_VER)

Twelve lines of plain ODBC against the 1.5.5 release:

SQLDriverConnect -> 0
SQL_DBMS_NAME -> 0 "DuckDB"
Segmentation fault

#0  duckdb::FreeHandle(short, void*)                    libduckdb_odbc.so
#1  GetInfoInternal<unsigned char>(void*, unsigned short, void*, short, short*)
#2  ?? ()                                               libodbc.so.2

The driver answers this one info type by running SELECT library_version FROM pragma_version() through the public SQLAllocHandle / SQLExecDirect / SQLFetch / SQLGetData entry points. Two defects share those thirty lines. Under unixODBC the call to SQLAllocHandle inside the driver binds to the driver manager's function of the same name (LD_DEBUG=bindings shows it), which rejects the driver's handle; the statement handle is still uninitialized and the error path frees it. Linked directly, as the driver's own tests are, the call succeeds but the value is read into the caller's buffer and then overwritten from a second, zero-filled one: SQL_SUCCESS, length 6, six NUL bytes. That second form is the Windows entry in the matrix that recorded DuckDB (via ODBC) with nothing after it.

The fix returns DuckDB::LibraryVersion() directly, the same value pragma_version() reports, and the new test compares the two.

DuckDB ODBC: parameter arrays

Four sets of (SQL_C_SLONG, SQL_C_DOUBLE, SQL_C_CHAR), (10, 1.5, "a") to (40, 4.5, "dddd"), on the release and on main:

execute -> 0, processed = 4
  row: i=10 d=1.5 s=a
  row: i=10 d=1.5 s=bb
  row: i=10 d=1.5 s=ccc
  row: i=10 d=1.5 s=dddd

In ParameterDescriptor::SetValue the string and binary branches index the bound buffer by the current set; the fixed-length branches all load from the start of it, and a TODO above them says so. The driver's one parameter-array test binds SQL_C_CHAR only, which is why it never failed. The fix steps each fixed-length load to the current set's element; the new test covers INTEGER, BIGINT, DOUBLE, DATE, TIMESTAMP and VARCHAR with a NULL set in the middle.

ArcadeDB: BEGIN answered with a RowDescription

→ Q "BEGIN"
← T  RowDescription, 0 fields
← C  "BEGIN"
← Z  ReadyForQuery 'T'

PostgreSQL answers a statement that returns no rows with the bare CommandComplete. The zero-field RowDescription in front of it makes libpq report PGRES_TUPLES_OK instead of PGRES_COMMAND_OK. psql shows an empty table after BEGIN; the Arrow PostgreSQL ADBC driver checks the status when it opens a transaction and gives up, and since its Python DB-API starts with autocommit off, adbc_driver_postgresql.dbapi.connect(uri) cannot run one query until autocommit=True is passed. psqlodbc ignores the status, so the ODBC route never noticed. In PostgresNetworkExecutor.queryCommand the transaction-control and savepoint branches now skip the RowDescription; the new test speaks the wire directly and fails on main at BEGIN and at SAVEPOINT.

SingleStore Connector/ODBC: two catalog functions

SQLColumns with a NULL catalog, on a connection opened without DATABASE=:

#1  __GI___strdup (s=0x0)
#2  MADB_StmtColumnsNoInfoSchema (... CatalogName=0x0, NameLength1=0 ...) at ma_statement.c:5063

TABLE_CAT falls back to the client library's current-database field, which only the connect-time database sets; USE does not. The same line exists in SQLPrimaryKeys. Both now leave TABLE_CAT NULL.

SQLGetTypeInfo with ANSI_QUOTES in sql_mode:

[42S22] [ss-1.2.2][9.1.1] Unknown column 'json' in 'field list' (1054) (SQLGetTypeInfo)

The result set is built from a SQL template with double-quoted values, which that mode turns into identifiers. The template now uses single-quoted literals, and because the literal prefix of the character types is itself a single quote, the values go through a helper that doubles it.

How each one was checked

Fix Reproduced on New test on unpatched code With the fix
DuckDB SQL_DBMS_VER 1.5.5 release zip, checksum matched fails, "" == "v2.1.0-alpha…" whole suite passes, 93 test cases; no crash through unixODBC
DuckDB parameter arrays 1.5.5 release and main fails at row two whole suite passes, 93 test cases; rows read 10, 20, 30, 40
ArcadeDB transaction control 26.10.1-SNAPSHOT container, wire capture fails at BEGIN and at SAVEPOINT every integration test of the PostgreSQL module passes, 243
SingleStore SQLColumns SingleStore 9.1.1, build of master segfault catalog tests pass in both prepared-statement modes
SingleStore SQLGetTypeInfo SingleStore 9.1.1, build of master 42S22 info tests pass in both modes; 56 rows with and without ANSI_QUOTES

The reproductions are plain ODBC or plain wire protocol in every case, the failing outputs above are copied from those runs, and the status of each pull request is tracked in the upstream record.