ArpeTeradata
v0.3.5Linux · Windows (x64)On-premise
A native ADBC driver for Teradata, written in C, returning Apache Arrow
RecordBatches end to end. It speaks the Teradata request/response parcel
protocol directly, so you don't need ODBC or teradatasql. On a server with
TLS, the driver does the whole logon itself and no Teradata software is
needed on the client. On a server without TLS, it logs on through the
Teradata Tools and Utilities (TTU) client library you have installed, then
takes the session over. The released binaries are self-contained: OpenSSL is
linked in, and nothing beyond the operating system's C library is needed at
runtime. It is validated on Teradata 20.00. It also covers Teradata cloud
environments: see Teradata cloud environments.
Reading these docs. The badge above is the version this documentation describes. Options and features added recently are flagged inline with a Since vX.Y.Z note; the What's new page is the release-by-release view. See Versioning.
Highlights
- Logon over TLS without TTU. On servers with TLS (Teradata 16.20.53.30 or later with a gateway certificate), the driver connects to the HTTPS port and performs the TD2, JWT or Kerberos logon itself. Every request and result then travels over TLS 1.2 / 1.3.
- Legacy port through TTU. For servers without TLS, the driver loads the CLIv2 library of your TTU install in process, logs on through it, and runs its own protocol on the authenticated socket. TTU is never involved in a query.
- TD2, LDAP, JWT and Kerberos. Choose the logon mechanism with
adbc.arpeteradata.logmech. JWT and Kerberos (KRB5,TDNEGO) also work over TLS without TTU; LDAP needs the legacy port. - Arrow-native extract. Result rows are decoded straight into Arrow column
buffers, 32000 rows per batch by default.
DECIMALup to 38 digits becomesdecimal128(p,s), and large results stream with bounded memory. - Bulk ingest.
adbc_ingestloads an Arrow table through packed, parameterisedINSERTrequests, increate,append,replaceandcreate_appendmodes, into permanent or volatile tables. - Full Teradata type coverage. Numerics,
NUMBER, character,BYTE/VARBYTE, dates, times and timestamps (with and without time zone),INTERVAL,PERIOD,ARRAY,VECTOR, user-defined types,CLOB,BLOB,JSON,XML,DATASETandST_Geometry. Every column also carries its Teradata type name in the Arrow field metadata. - Load name
arpeteradata. Options live underadbc.arpeteradata.*.
Connect in seconds
Load the driver by name (arpeteradata) from any ADBC client, with discrete
options as below, an ADO.NET connection string, or a teradata:// URI (see
Three ways to connect).
- Python
- C / C++
- C#
- Go
- Java
- R
- Rust
import adbc_driver_manager.dbapi as dbapi
with dbapi.connect(driver="arpeteradata", db_kwargs={
"adbc.arpeteradata.server": "td.example.com",
"adbc.arpeteradata.username": "alice",
"adbc.arpeteradata.password": "<pw>",
}, autocommit=True) as conn:
cur = conn.cursor()
cur.execute("SELECT TOP 10 * FROM SALES.ORDERS")
table = cur.fetch_arrow_table()
#include <arrow-adbc/adbc.h>
// (error checks elided for brevity)
AdbcError e = {}; AdbcDatabase db = {}; AdbcConnection conn = {}; AdbcStatement st = {};
AdbcDatabaseNew(&db, &e);
AdbcDatabaseSetOption(&db, "driver", "arpeteradata", &e);
AdbcDatabaseSetOption(&db, "adbc.arpeteradata.server", "td.example.com", &e);
AdbcDatabaseSetOption(&db, "adbc.arpeteradata.username", "alice", &e);
AdbcDatabaseSetOption(&db, "adbc.arpeteradata.password", "<pw>", &e);
AdbcDatabaseInit(&db, &e);
AdbcConnectionNew(&conn, &e); AdbcConnectionInit(&conn, &db, &e);
AdbcStatementNew(&conn, &st, &e);
AdbcStatementSetSqlQuery(&st, "SELECT TOP 10 * FROM SALES.ORDERS", &e);
ArrowArrayStream stream = {}; int64_t n = -1;
AdbcStatementExecuteQuery(&st, &stream, &n, &e); // consume `stream`
using Apache.Arrow.Adbc;
using Apache.Arrow.Adbc.DriverManager;
using var driver = AdbcDriverManager.FindLoadDriver("arpeteradata", loadOptions: AdbcLoadFlags.Default);
using var database = driver.Open(new Dictionary<string, string> {
["adbc.arpeteradata.server"] = "td.example.com",
["adbc.arpeteradata.username"] = "alice",
["adbc.arpeteradata.password"] = "<pw>" });
using var connection = database.Connect(null);
using var statement = connection.CreateStatement();
statement.SqlQuery = "SELECT TOP 10 * FROM SALES.ORDERS";
using var stream = statement.ExecuteQuery().Stream!; // IArrowArrayStream
var drv drivermgr.Driver
db, _ := drv.NewDatabase(map[string]string{
"driver": "arpeteradata",
"adbc.arpeteradata.server": "td.example.com",
"adbc.arpeteradata.username": "alice",
"adbc.arpeteradata.password": "<pw>",
})
conn, _ := db.Open(ctx)
stmt, _ := conn.NewStatement()
_ = stmt.SetSqlQuery("SELECT TOP 10 * FROM SALES.ORDERS")
reader, _, _ := stmt.ExecuteQuery(ctx) // array.RecordReader
defer reader.Release()
Map<String, Object> params = new HashMap<>();
JniDriver.PARAM_DRIVER.set(params, "arpeteradata");
params.put("adbc.arpeteradata.server", "td.example.com");
params.put("adbc.arpeteradata.username", "alice");
params.put("adbc.arpeteradata.password", "<pw>");
try (BufferAllocator a = new RootAllocator();
AdbcDatabase db = new JniDriver(a).open(params);
AdbcConnection conn = db.connect();
AdbcStatement st = conn.createStatement()) {
st.setSqlQuery("SELECT TOP 10 * FROM SALES.ORDERS");
try (AdbcStatement.QueryResult r = st.executeQuery()) {
ArrowReader reader = r.getReader();
}
}
library(adbcdrivermanager)
db <- adbc_database_init(adbc_driver("arpeteradata"),
adbc.arpeteradata.server = "td.example.com",
adbc.arpeteradata.username = "alice",
adbc.arpeteradata.password = "<pw>")
con <- adbc_connection_init(db)
table <- read_adbc(con, "SELECT TOP 10 * FROM SALES.ORDERS") |> arrow::as_arrow_table()
use adbc_core::{Connection, Database, Driver, Statement, LOAD_FLAG_DEFAULT};
use adbc_core::options::{AdbcVersion, OptionDatabase, OptionValue};
use adbc_driver_manager::ManagedDriver;
let mut driver = ManagedDriver::load_from_name("arpeteradata", None, AdbcVersion::default(), LOAD_FLAG_DEFAULT, None)?;
let mut db = driver.new_database_with_opts([
(OptionDatabase::Other("adbc.arpeteradata.server".into()), OptionValue::String("td.example.com".into())),
(OptionDatabase::Other("adbc.arpeteradata.username".into()), OptionValue::String("alice".into())),
(OptionDatabase::Other("adbc.arpeteradata.password".into()), OptionValue::String("<pw>".into())),
])?;
let mut conn = db.new_connection()?;
let mut stmt = conn.new_statement()?;
stmt.set_sql_query("SELECT TOP 10 * FROM SALES.ORDERS")?;
let reader = stmt.execute()?; // impl RecordBatchReader
With the default sslmode=prefer, the driver tries TLS first and falls back to
the legacy port (which needs TTU) when the server has no TLS. prefer does not
check the server certificate, so after a TLS logon the driver prints this line
once on standard error:
WARNING: ArpeTeradata: TLS logon without server certificate verification (sslmode=prefer); use sslmode=verify-ca or verify-full to protect the password.
The session is encrypted, but the password could reach a server that only
pretends to be yours. To make sure it only ever reaches the real server, set
adbc.arpeteradata.sslmode to verify-full, plus adbc.arpeteradata.sslca if
the server's CA is not in the system store: see
TLS. On a test server, set
ARPETERADATA_NO_TLS_WARNING=1 to silence the warning.
New here? Install ArpeTeradata first, then see the Connection guide.