SQLColumns segfaults on a NULL NUMERIC_PRECISION from mongosqld
#0 __GI_____strtol_l_internal (nptr=0x0, ...)
#1 get_buffer_length (..., sqltype=3 /* SQL_DECIMAL */, col_size=0) at driver/catalog.cc:626
#2 columns_i_s (..., table="adbc_t", ...) at driver/catalog.cc:962
#3 MySQLColumns (...) / SQLColumnsW (...)
MongoDB has no SQL wire protocol of its own. The BI Connector is MongoDB's own answer to that:
mongosqld sits in front of a MongoDB instance and presents each collection as a SQL table over
the MySQL wire, announcing itself as 5.7.12 mongosqld v2.14.22. So the ODBC route to it is
MySQL Connector/ODBC — and asking that connector for a table's columns kills the process, if the
table has a DECIMAL column in it.
Why it dies
mongosqld's information_schema.columns reports NULL for NUMERIC_PRECISION,
NUMERIC_SCALE and CHARACTER_OCTET_LENGTH on every column. Connector/ODBC 9 builds
SQLColumns entirely from information_schema — the older SHOW-based path is gone, and there
is no NO_I_S option left to switch back to (NO_I_S=1 is accepted and changes nothing). For a
DECIMAL column it calls strtol() on that NULL pointer.
It is a per-column crash, not a per-table one, which makes it worse than it sounds: a table with no decimal column comes back with a clean six-column result and rc 0, and nothing in the return code separates the two cases.
./probe_c "Driver=…libmyodbc9w.so;…;PLUGIN_DIR=…;" columns adbc_big # SQLColumns rc=0, six columns
./probe_c "Driver=…libmyodbc9w.so;…;PLUGIN_DIR=…;" columns adbc_t # Segmentation fault
Both of those are a standalone C program against libmyodbc9w.so with nothing else in the
picture. The workaround is to stop calling SQLColumns here and describe a zero-row
SELECT * FROM <table> WHERE 1=0 instead — which is where a table's columns already come from
on the schema path. It is keyed on SQL_DBMS_VER, the 5.7.12 mongosqld v2.14.22 string out of
the handshake, rather than on SELECT version(), which answers a bare 5.7.12 and names
nothing.
A second segfault, in the handshake
mongosqld offers only mysql_native_password, whose client-side plugin Connector/ODBC 9 no
longer links in — it ships as a loadable .so beside the driver, and the generic tarball's
compiled-in search path is /usr/local/mysql/lib/plugin. Where Dolt reports that as a clean
Authentication plugin ... cannot be loaded, here SQLDriverConnect segfaults. Pointing
PLUGIN_DIR at the tarball's own plugin directory avoids it entirely, so this one costs a
connection property and nothing else.
COM_STMT_PREPARE is a third thing to set: it comes back as error 1295, This command is not
supported in the prepared statement protocol yet. With NO_SSPS=1 the connector substitutes
bound parameters into the SQL text and the parameterised SELECT works.
What the workload could and could not do
With those three settings the whole read side runs: int64, double, string (including
"héllo 🚀" — the emoji survives the round trip), booleans as int8, timestamps, the all-NULL
row, the parameterised SELECT, a 100,000-row batched read, catalog and schema metadata, and
the error text. Because mongosqld translates SQL into MongoDB aggregation pipelines, the entry
also runs a filtered count, a GROUP BY on a boolean field and a COUNT(DISTINCT _id) over the
ObjectId every document carries. Fetch is 128k rows/s over 100,000 documents.
The write side does not exist. CREATE TABLE, INSERT and DROP TABLE answer 1105
… requires --writeMode, UPDATE/DELETE/TRUNCATE are not in the grammar at all, and
--writeMode is refused together with a --schema path — so the collections are loaded with
mongosh and the entry is read-only. Three mapping facts follow from the BI Connector's type
system rather than from the driver: there is no binary type (bson.Binary is rejected as a
DRDL Mongo type and varbinary/binary/bindata as DRDL SQL types; a sampled binData field
maps to varchar and then reads back NULL), so bytes are stored and read as text; every decimal
is described DECIMAL(65,20) whatever is in it, past what a 128-bit decimal holds, so those
columns arrive as their exact text; and _id is an ordinary column, so it appears in every
SELECT *.
One platform caveat. Through MySQL Connector/ODBC 8.4.0 on Windows this entry failed at one
check only: héllo 🚀 stored byte-exact and read back as héllo ??? on every read path,
because 8.4.0 substitutes ? for a non-BMP character before either C type sees it. Connector/ODBC
26.7.1 reads it correctly, and the entry passes.
Where this comes from: the adbcBridge compatibility matrix runs one workload through every database's ODBC driver on Linux, macOS and Windows and records each failure with its first error; the row for this database is at https://adbcbridge.org/matrix/#mongodbbi, and the finding is on file with its reproduction in docs/UPSTREAM.md of the repository.