Altibase ODBC stores astral characters as CESU-8 on its wide path
Altibase's first-party ODBC driver (libaltibase_odbc-64bit-ul64.so, Altibase ODBC 7.3)
round-trips text correctly only when both ends of a value take the same path: it does not
encode the same string the same way on each. Against a UTF8 database opened
NLS_USE=UTF8, writing hรฉllo ๐:
| written as | stored | LENGTH/LENGTHB |
read SQL_C_CHAR |
read SQL_C_WCHAR |
|---|---|---|---|---|
SQL_C_WCHAR |
CESU-8 (the surrogate pair as two 3-byte sequences) | 8 / 13 | 68 c3a9 6c6c6f 20 eda0bd edba80 โ not valid UTF-8 |
correct |
SQL_C_CHAR (UTF-8) |
the bytes, passed through | 10 / 11 | correct, byte for byte | four U+FFFD |
Write wide and read narrow and you get bytes no UTF-8 decoder will take:
'utf-8' codec can't decode byte 0xed in position 7
Only the narrow pair yields bytes a UTF-8 consumer accepts, so the rule is to keep both
ends narrow. It holds for NVARCHAR as well as VARCHAR.
A bare VARCHAR is VARCHAR(1), and the type table is what leads you there
Altibase has no SQL_LONGVARCHAR and no SQL_WLONGVARCHAR at all โ its large-object
character type, CLOB, is numbered 40 โ so anything generating DDL from the driver's type
table falls through to SQL_VARCHAR. There the CREATE_PARAMS column reads precision,
not the length every other driver in this matrix reports for a character type. Nothing then supplies a
length, the column is created bare, and a bare VARCHAR in Altibase is VARCHAR(1):
22026 Invalid data type length : B. (135273)
on the first string longer than one byte. Naming the type outright is the way out;
VARCHAR(32000) is the widest the server takes (VARCHAR(32001) is refused). The length
is in bytes โ three Greek letters do not fit a VARCHAR(4).
Byte types carry vendor numbers, and come back as hex
SQLGetTypeInfo reports SQL_DATA_TYPE values outside the ODBC range: BYTE 20001,
NIBBLE 20002, VARBYTE 20003, GEOMETRY 10003, BLOB 30, CLOB 40, VARBIT -100.
Left unrecognised they fall through a generic reader's text default, where the driver hands the
value back hex-encoded โ b"\x01\x02" arrives as the four characters 0102. Reading
BYTE, VARBYTE and BLOB as SQL_C_BINARY gives the value's own bytes. NIBBLE and
VARBIT do not: read that way they carry Altibase's internal framing rather than the
value (NIBBLE'01' comes back b"\x02\x01", a length byte first), so for those the hex
text is the more faithful answer.
Writing into a byte column is a different matter. BYTE, VARBYTE, NIBBLE, BIT and
VARBIT all refuse a bound SQL_C_BINARY parameter before the value is looked at โ
22018 Conversion not applicable. (135180)
โ so nothing can be written into one through ODBC parameters at all; only a literal
(VARBYTE'0001FF') gets data in. BLOB takes the same parameter without complaint,
which settles which type to use.
Types that are not there, and one that does double duty
CREATE TABLE t (x BOOLEAN) fails HY004, "Unable to create a column with the specified
data type. (200744)"; SMALLINT is how a boolean is spelled, and it reads back as
int16. DOUBLE PRECISION in two words is a parse error โ the type is DOUBLE.
There is no VARBINARY (Data type module (Name="VARBINARY") not found), and BINARY,
which SQLGetTypeInfo does list at SQL_BINARY, is not creatable either. And DATE
is the timestamp: it holds a time down to the microsecond, the driver describes it
SQL_TYPE_TIMESTAMP (93), and there is no date-only type โ one column type carries both
dates and timestamps.
One thing it is good at: its parameter arrays are a single round trip and beat a
multi-row INSERT by 26ร. Twenty-thousand-row loads run at 30,016โ30,265 rows/s
multi-row against 778,486โ815,625 rows/s as an array.
Getting a server, and the platforms you cannot
altibase/altibase, the image the vendor's Docker Hub description points at, does not run
without a licence: it ships a one-byte conf/license and the boot stops at Check License
with Corrupted license string! / No valid license present! / ERR-42000(errno=2). The
same vendor publishes altibase/a_plus_edition, the free full-featured build, which needs
none. It wants MODE=foreground โ the default MODE=init starts a shell and exits,
creating no database โ and DB_CHARSET=UTF8, baked in at CREATE DATABASE time and
unchangeable afterwards (the default is KO16KSC5601).
There is no client to download separately: the driver is inside the server image, and its
-ul64 suffix is the 8-byte SQLLEN build unixODBC wants on 64-bit Linux. There is no
macOS client at all โ the vendor's supported-platform list is Linux, AIX, HP-UX and
Windows โ and its Windows ODBC client "is provided only up to Altibase version 6.5.1, and
not provided to Altibase version 7 or later", so nothing drives a 7.x server from Windows.
Status
Found on 2026-09-03. Recorded in docs/UPSTREAM.md under "Documented here, not yet reported"; the vendor's GitHub has carried no source since the 2023 withdrawal of the open-source edition and there is a support channel only, so there is no issue link and no fix version to name.
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/#altibase, and the finding is on file with its reproduction in docs/UPSTREAM.md of the repository.