Actian Ingres into Apache Arrow with ADBC
Actian Ingres 10.1 (open-source edition), read and written through adbcBridge — the ADBC driver that loads the database's ODBC driver — verified on Linux. Everything below is the compatibility matrix's record for this row.
Status
PASS
driver unavailable: Actian Client for macOS is x86_64 only, no arm64 build
FAIL (astral check): Actian Client 1.5.0 for Windows (CAIIOD35.DLL 3.50.1211, registered as Ingres, from esd.actian.com behind a login, setup.exe with a response file — a bare msi installs no driver) negotiates the server's ISO88591 with Ingres 10.1 — declaring UTF8 is refused, E_GC2462 — and substitutes U+1F680 with ? on every route, literal, wide or narrow parameter, pyodbc identical; the Linux driver passes the UTF-8 bytes through, this one honours the negotiated set. On this tree the failure surfaces earlier as a session abort on the two-row array INSERT (08S01 … The connection to the server has been aborted, server E_CLFE07_BS_READ_ERR), because the bridge's iiodbcdriver key does not match the Windows driver name and the Windows tail leaves the wide path on: extending the key to caiiod35 and exempting it from that tail turns the abort into the honest AssertionError: héllo ? — a proposed one-line fix, not in this tree. Client setup a Windows host needs before any of that: a vnode (netutil) with encryption_mode off (the 1.5 client defaults Net encryption on, the 10.1 server has no mechanism, E_GC1004), character_set ISO88591, and II_TIMEZONE_NAME=GMT in the environment (the installer writes America-New_York, which its own config.dat cannot map)
Driver and connection string
- ODBC driver
- Ingres ODBC (
libiiodbcdriver.1.so, ships with the installation) - Wire
- native ODBC
- adbcBridge
- 0.1.1 (release)
The connection string the matrix used, as the connection strings reference records it (Databases with their own native protocol and ODBC driver); {drv} is the driver library or its name from odbcinst.ini, and the host, port and credentials are the test server's.
Driver={drv};Server=adbcing;Database=adbc;UID=ingres;PWD=adbc;ServerType=INGRES;
Python
import adbcbridge
# {drv}: the ODBC driver library (path), or its name from odbcinst.ini
conn = adbcbridge.connect(uri="Driver={drv};Server=adbcing;Database=adbc;UID=ingres;PWD=adbc;ServerType=INGRES;")
with conn.cursor() as cur:
cur.execute("SELECT * FROM my_table")
table = cur.fetch_arrow_table() # pyarrow.Table
Polars and pandas
import polars as pl, pandas as pd
df = pl.read_database("SELECT * FROM my_table", connection=conn) # Polars, Arrow-native
pdf = pd.read_sql("SELECT * FROM my_table", conn) # pandas 2.2+, ADBC connection
pip install adbcbridge brings the driver library; the Actian Ingres ODBC driver is installed the way its vendor documents, then named in Driver=. Rust, Go, C# and Java use the same connection string through their ADBC driver managers — see the docs.
What the matrix recorded
Ingres' own driver over Ingres/Net on 21064. It cannot be used through unixODBC as it stands: its wide entry points take a four-byte SQLWCHAR (the platform wchar_t) while unixODBC's is two, and unixODBC picks a driver's Unicode path purely by finding SQLConnectW in it, so the connection string arrives as its first character and the connect fails 08004 / 786744 E_GC0138_GCN_NO_SERVER — an empty vnode and database, leaving just the /INGRES server class.
What this stack needed
- The same call with a UTF-32 string connects, which is the proof of the width.
- Its *narrow* entry points are correct and complete, so the entry loads it behind a generated ANSI-only forwarding library (
fixtures/ingres_ansi_shim.c, 72 one-jump stubs) and unixODBC does the UCS-2 conversion itself. - A second driver bug sets the shape of the connection string:
Driver=isstrcpy'd into a 32-byte buffer, so any real path aborts the process outright (* buffer overflow detected *,__strcpy_chkunderConDriverInfo) — the entry registers the shim inodbcinst.iniand names itDriver=Ingres. - Two bridge quirks then carry it: 32-bit
SQLLEN(as for the Db2 clidriver — a NULL column otherwise reads back as the row before it, a NULLFLOAT8as1e-323), and no usableSQL_C_WCHARparameters (each 16-bit unit is treated as a code point, so a surrogate pair is rejected:5000B, *Unicode code point 0000D83D cannot be mapped to local character set* — UTF-8 narrow path instead, as for Firebird, Virtuoso and Informix). - Server side:
createdb -n(a Unicode-enabled database, without which aVARCHARcannot hold the emoji andNVARCHARcannot be created at all),date_alias = ansidatebefore the DBMS starts (on the default,ANSIDATEis created as Ingres' own date-*and-time*INGRESDATE, whose NULL comes back as the year-0 empty date), and an Ingres user for the local account the client runs as — the vnode login authenticates the connection while the session still runs as the caller's OS user (E_US18FF). - Ingres SQL has no multi-row
VALUESat all (Syntax error on ','), so bulk ingest falls back to parameter arrays on its own. - Actian's own
actian/ingres:ii12.1.0image refuses to start without a commerciallicense.xml, so the server is the GPLingres-10.1.0-00-NPTLbuild baked into the community imageiidbdb/ingres; ingest 1.1k rows/s (1.3k array), fetch 393k rows/s