Skip to main content

ArrowTTC — Examples & recipes

Copy-paste snippets for the common tasks. All assume the driver is installed and loadable by name (driver="arrowttc") — see Install. For the full option reference behind each db_kwargs, see CONNECTION.md.


Connect and query to Arrow

The same recipe in every ADBC client — the driver is loaded by name (arrowttc) from the installed ADBC manifest, so only the language changes:

import adbc_driver_manager.dbapi as dbapi

with dbapi.connect(
driver="arrowttc",
db_kwargs={"uri": "oracle://scott:tiger@localhost:1521/orclpdb1"},
) as conn, conn.cursor() as cur:
cur.execute("SELECT * FROM lineitem WHERE ROWNUM <= 10")
table = cur.fetch_arrow_table() # pyarrow.Table
print(table.schema)

Connect with discrete options

Discrete options keep secrets out of a single string and override any uri. Set them where the uri went — the rest of each program is identical to the recipe above:

conn = dbapi.connect(driver="arrowttc", db_kwargs={
"adbc.arrowttc.server": "localhost",
"adbc.arrowttc.port": "1521",
"adbc.arrowttc.service_name": "orclpdb1",
"adbc.arrowttc.username": "scott",
"adbc.arrowttc.password": "tiger",
})

Or the DB-API shortcut from the Python package:

Python
import arrowttc_adbc
conn = arrowttc_adbc.connect(server="localhost", service_name="orclpdb1",
username="scott", password="tiger")

Straight to pandas / Polars / DuckDB

Because results are already Arrow, there is no row-by-row marshalling. These handoffs are Python-ecosystem specific:

Python
with conn.cursor() as cur:
cur.execute("SELECT * FROM orders WHERE o_orderdate >= DATE '1996-01-01'")

df = cur.fetch_arrow_table().to_pandas() # pandas
# or, without materialising twice:
import polars as pl
pf = pl.from_arrow(cur.fetch_arrow_table()) # Polars
import duckdb
tbl = conn.cursor().execute("SELECT * FROM lineitem").fetch_arrow_table()
duckdb.sql("SELECT l_returnflag, count(*) FROM tbl GROUP BY 1").show()

Prepared statements & parameter binding

Oracle uses positional :1, :2 bind placeholders. In the compiled clients you bind an Arrow batch of parameters to the statement before executing:

with conn.cursor() as cur:
cur.execute("SELECT * FROM orders WHERE o_orderkey = :1", parameters=[42])
row = cur.fetch_arrow_table()

Array binding — bind a whole Arrow batch of parameters in one call (Python's executemany):

Python
with conn.cursor() as cur:
cur.executemany(
"INSERT INTO t(a, b) VALUES (:1, :2)",
seq_of_parameters=[(1, "x"), (2, "y"), (3, "z")],
)
conn.commit()

Bulk ingest an Arrow table

adbc_ingest pipes an Arrow table straight in via an array-bound INSERT:

import pyarrow as pa

table = pa.table({
"id": pa.array([1, 2, 3], pa.int32()),
"name": pa.array(["a", "b", "c"], pa.string()),
})

with conn.cursor() as cur:
cur.adbc_ingest("my_table", table, mode="create") # create | append | replace | create_append
conn.commit()
note

Rust & C++ have no one-call adbc_ingest helper: set the standard statement options adbc.ingest.target_table / adbc.ingest.mode, Bind the Arrow batch, then execute_update (Rust) / AdbcStatementExecuteQuery (C++).

Ingest into a specific schema or a GLOBAL TEMPORARY table via the statement options adbc.ingest.target_db_schema / adbc.ingest.temporary (see CONNECTION.md).

Export a query to Parquet

Python
import pyarrow.parquet as pq

with conn.cursor() as cur:
cur.execute("SELECT * FROM lineitem")
reader = cur.fetch_record_batch() # streaming RecordBatchReader
with pq.ParquetWriter("lineitem.parquet", reader.schema) as w:
for batch in reader:
w.write_batch(batch)

Streaming keeps memory flat regardless of result size; batch size is a memory knob (see the README ### Batch Size).

Native Network Encryption

Encrypt the whole session without TCPS — the way to connect a server configured SQLNET.ENCRYPTION_SERVER=REQUIRED:

Python
conn = dbapi.connect(driver="arrowttc", db_kwargs={
"adbc.arrowttc.server": "dbhost",
"adbc.arrowttc.service_name": "orclpdb1",
"adbc.arrowttc.username": "scott",
"adbc.arrowttc.password": "tiger",
"adbc.arrowttc.encryption": "required", # AES-256 payloads
"adbc.arrowttc.data_integrity": "required", # SHA-256 checksum
})

TLS / Oracle Cloud ADB with a wallet

Point wallet_location at an unzipped ADB wallet (mutual TLS):

Python
conn = dbapi.connect(driver="arrowttc", db_kwargs={
"adbc.arrowttc.server": "adb.<region>.oraclecloud.com",
"adbc.arrowttc.port": "1522",
"adbc.arrowttc.service_name": "<svc>_low.adb.oraclecloud.com",
"adbc.arrowttc.username": "scott",
"adbc.arrowttc.password": "tiger",
"adbc.arrowttc.ssl_mode": "verify-full",
"adbc.arrowttc.wallet_location": "/home/you/wallet",
"adbc.arrowttc.wallet_password": "<wallet-pw>",
})

Kerberos auth

No Oracle password — a Kerberos ticket (Linux / MIT krb5 only):

Python
conn = dbapi.connect(driver="arrowttc", db_kwargs={
"adbc.arrowttc.server": "db.corp.example.com",
"adbc.arrowttc.service_name": "orclpdb1",
"adbc.arrowttc.auth_method": "kerberos",
"adbc.arrowttc.krb5_spn": "oracle/db.corp.example.com",
# "adbc.arrowttc.krb5_cred_mode": "ccache", # or keytab / password
})

See AUTHENTICATION.md for SPN and credential details.

OCI IAM & OAuth2 / Entra ID token auth

OCI IAM database token (oci iam db-token get writes the token directory); pair with the ADB wallet for mutual TLS:

Python
db_kwargs = {
"adbc.arrowttc.server": "adb.<region>.oraclecloud.com",
"adbc.arrowttc.port": "1522",
"adbc.arrowttc.service_name": "<svc>_low.adb.oraclecloud.com",
"adbc.arrowttc.auth_method": "token",
"adbc.arrowttc.token_location": "/home/you/.oci/db-token",
"adbc.arrowttc.ssl_mode": "verify-full",
"adbc.arrowttc.wallet_location": "/home/you/wallet",
"adbc.arrowttc.wallet_password": "<wallet-pw>",
}

OAuth2 / Microsoft Entra ID bearer token — setting the token auto-selects the method (no username; Oracle maps the token's upn claim to a global user):

Python
db_kwargs = {
"adbc.arrowttc.server": "adb.<region>.oraclecloud.com",
"adbc.arrowttc.port": "1522",
"adbc.arrowttc.service_name": "<svc>_low.adb.oraclecloud.com",
"adbc.arrowttc.access_token": "<entra-jwt>", # or token_file=<path>
# wallet options as above for ADB mutual TLS
}

See AUTHENTICATION.md.

Loading by explicit path

Load-by-name (above) uses the ADBC manifest the installer registers. When the driver is not installed system-wide, point the driver manager at the shared library instead — e.g. in C# via CAdbcDriverImporter.Load("libarrowttc_adbc_driver.so", "AdbcDriverInit"), or by setting ARROWTTC/ADBC_DRIVER_PATH for the name-based loaders. Everything after loading is identical.

See also