ArrowTTC — Data types
How Oracle types map to Apache Arrow on the fetch (read) path, and how Arrow types map back to Oracle on the ingest/bind (write) path.
The non-obvious cases — unconstrained NUMBER has no exact Arrow type, DATE
carries a time component (so it is a timestamp, not date32), TIMESTAMP WITH TIME ZONE collapses to a UTC instant — are called out below.
Read path: Oracle → Arrow
Numeric
| Oracle type | Arrow type | Notes |
|---|---|---|
NUMBER(p,0), p ≤ 18 | int64 | Max 999,999,999,999,999,999 < 263; better for every consumer than a zero-scale decimal |
NUMBER(p,0), p 19–38 | decimal128(p,0) | Can exceed int64 |
NUMBER(p,s), s > 0 | decimal128(p,s) | Exact; Oracle's max precision is 38, so decimal256 is never needed |
NUMBER (unconstrained) | utf8 (default) / float64 / decimal128(P,S) | Governed by number_mapping |
BINARY_INTEGER | as NUMBER above | Same policy path |
BINARY_FLOAT | float32 | |
BINARY_DOUBLE | float64 |
Character & binary
| Oracle type | Arrow type | Notes |
|---|---|---|
VARCHAR2 / CHAR / LONG | utf8 | AL32UTF8 passes through unchanged |
NVARCHAR2 / NCHAR | utf8 | National charset (AL16UTF16) transcoded UTF-16 → UTF-8; distinguished from VARCHAR2 only by the character-set form (csfrm) |
RAW / LONG RAW | binary | |
ROWID / UROWID | utf8 | rendered as text |
CLOB | utf8 | fetched via a LOB locator round-trip after the row |
NCLOB | utf8 | national CLOB, UTF-16 → UTF-8 |
BLOB | binary | LOB locator round-trip |
Temporal
| Oracle type | Arrow type | Notes |
|---|---|---|
DATE | timestamp[s] | Not date32 — Oracle DATE always carries a time component |
TIMESTAMP(n) | timestamp[s|ms|us|ns] | unit follows the column's fractional-seconds precision |
TIMESTAMP(n) WITH TIME ZONE | timestamp[…, tz=UTC] | offset applied → UTC instant |
TIMESTAMP(n) WITH LOCAL TIME ZONE | timestamp[…, tz=UTC] | wire value is UTC (DBTIMEZONE assumed UTC) |
INTERVAL YEAR TO MONTH | interval (month_day_nano) | |
INTERVAL DAY TO SECOND | interval (month_day_nano) |
Fractional-seconds precision → unit (for TIMESTAMP and its TZ variants):
| Column precision | Arrow unit |
|---|---|
| 0 | seconds |
| 1–3 | milliseconds |
| 4–6 | microseconds |
| 7–9 | nanoseconds |
Oracle allows up to 9 fractional digits, so the precision is rounded up to the next representable Arrow unit and no precision is lost.
Oracle 23ai native types
Since ArrowTTC v0.2.10, decoded natively on Oracle 23ai / 26ai.
| Oracle type | Arrow type | Notes |
|---|---|---|
BOOLEAN | bool | 23ai native boolean (Oracle type 252), packed one bit per value |
JSON | utf8 | 23ai native binary JSON (OSON, type 119) decoded to JSON text |
VECTOR | list<float32 | float64 | int8> | 23ai vectors (type 127); the element type follows the column's VECTOR format |
On the wire, JSON and VECTOR are LOB-backed, so their images are prefetched
inline in the row and decoded there rather than through a second LOB round trip.
Spatial
Since ArrowTTC v0.3.1, on Oracle with the Spatial option.
| Oracle type | Arrow type | Notes |
|---|---|---|
MDSYS.SDO_GEOMETRY | binary + geoarrow.wkb extension | Decoded to little-endian ISO WKB, tagged ARROW:extension:name = geoarrow.wkb so consumers such as GeoPandas or DuckDB spatial treat it as geometry. The stored SDO_SRID is surfaced as the geoarrow CRS metadata ({"crs_type":"srid","crs":N}), or forced with the arrowttc.sdo.srid statement option. On read, 2D POINT, LINESTRING, and single-exterior-ring POLYGON are decoded (any size); interior rings, multi-part geometries, 3D/LRS, and collections are out of scope and rejected. The write path below is broader. |
Not yet mapped
BFILE— a pointer to a server-filesystem file through aDIRECTORYobject; a different permission model, not a different encoding, so it is surfaced as unsupported rather than half-decoded.- Region-id
TIMESTAMP WITH TIME ZONE(a named zone rather than a fixed offset) fails loudly rather than resolving the zone through DST rules; fixed-offset TSTZ and TSLTZ decode normally. JSON/BOOLEANon Oracle 19c–21c — these are not native column types before 23ai (JSONis stored in a LOB/VARCHAR2with anIS JSONcheck), so such a column decodes as its underlying text/LOB type. Oracle 23ai's nativeJSONandBOOLEANtypes are decoded directly — see Oracle 23ai native types above.- Unknown Oracle types are surfaced as opaque
binaryrather than guessed at.
Number Mapping
Oracle's unconstrained NUMBER (no declared precision or scale — describe reports
scale −127) is Oracle's default numeric type and has no exact Arrow equivalent.
A fixed decimal128(p,s) cannot be chosen safely (it would truncate high-scale
values and overflow large ones), and an Arrow schema is fixed before the first
batch, so the scale cannot be inferred by looking ahead in the stream. The
adbc.arrowttc.number_mapping database
option chooses:
| Value | Output | Notes |
|---|---|---|
auto (default) | utf8 | Lossless. The deliberate default — a lossy default would silently lose precision on Oracle's most common numeric column |
double | float64 | Fast, lossy — 15–17 significant digits against Oracle's 38 |
decimal:P,S | decimal128(P,S) | For callers who know their data; 1 ≤ P ≤ 38, 0 ≤ S ≤ P |
Constrained columns are unaffected by this option — only unconstrained NUMBER
is routed through it. The lossless default is not theoretical: the type-matrix
fixture's unconstrained column round-trips 21 significant digits, well beyond
float64.
Write path: Arrow → Oracle (ingest & bind)
On adbc_ingest and prepared-statement bind, Arrow arrays drive positional
binds — one Arrow row is one execution. Ingest issues an array-bound INSERT
with a SQL-injection-safe identifier and literal escaper, in create / append
/ replace / create_append modes, with optional target_db_schema and a
GLOBAL TEMPORARY target (adbc.ingest.temporary). See
CONNECTION.md for the ingest options.
A geoarrow.wkb Arrow column is ingested as a real MDSYS.SDO_GEOMETRY column —
the inverse of the spatial read path (since v0.3.1). The create-table DDL emits
the SDO_GEOMETRY type, each row's WKB is converted to Oracle's packed object
image and bound as an OBJECT, a geoarrow CRS on the field maps to SDO_SRID,
and — when the ingest itself creates the table — USER_SDO_GEOM_METADATA and a
spatial index are registered. The write path is broader than read: in
addition to points, lines, and single-ring polygons, it supports POLYGON with
interior rings and the MULTIPOINT / MULTILINESTRING / MULTIPOLYGON kinds.
3D geometries, geometry collections, and malformed WKB are rejected.
See also
CONNECTION.md— thenumber_mappingoptionCOMPATIBILITY.md— validated Oracle versionsEXAMPLES.md— reading and ingesting typed data