ArpeNetezza — Examples & recipes
Copy-paste snippets for the common tasks. All assume the driver is loadable by
name (driver="arpenz"), through an arpenz.toml manifest on the ADBC driver
manager's search path. Otherwise, use
Loading by explicit path. For the full option
reference behind each db_kwargs, see Connection.
- Connect and query to Arrow
- Connect with discrete options
- Straight to pandas / Polars
- Parameter binding
- Bulk ingest an Arrow table
- Export a query to Parquet
- TLS
- Loading by explicit path
Connect and query to Arrow
The same recipe in every ADBC client. The driver is loaded by name
(arpenz), so only the language changes:
- Python
- C / C++
- C#
- Go
- Java
- R
- Rust
import adbc_driver_manager.dbapi as dbapi
with dbapi.connect(
driver="arpenz",
db_kwargs={"uri": "netezza://admin:<pw>@nzhost:5480/SYSTEM"},
) as conn, conn.cursor() as cur:
cur.execute("SELECT * FROM lineitem LIMIT 10")
table = cur.fetch_arrow_table() # pyarrow.Table
print(table.schema)
#include <cstdio>
#include <cstdlib>
#include <arrow-adbc/adbc.h>
#include <arrow-adbc/adbc_driver_manager.h>
#define CHECK(EXPR) \
if (AdbcStatusCode s = (EXPR); s != ADBC_STATUS_OK) { \
std::fprintf(stderr, "%s failed: %s\n", #EXPR, \
error.message ? error.message : "(unknown)"); \
std::exit(1); \
}
int main() {
AdbcError error = {};
AdbcDatabase database = {};
CHECK(AdbcDatabaseNew(&database, &error));
// Load the driver by name from its ADBC manifest.
CHECK(AdbcDatabaseSetOption(&database, "driver", "arpenz", &error));
CHECK(AdbcDatabaseSetOption(
&database, "uri", "netezza://admin:<pw>@nzhost:5480/SYSTEM", &error));
CHECK(AdbcDatabaseInit(&database, &error));
AdbcConnection connection = {};
CHECK(AdbcConnectionNew(&connection, &error));
CHECK(AdbcConnectionInit(&connection, &database, &error));
AdbcStatement statement = {};
CHECK(AdbcStatementNew(&connection, &statement, &error));
CHECK(AdbcStatementSetSqlQuery(&statement, "SELECT * FROM lineitem LIMIT 10", &error));
ArrowArrayStream stream = {}; // Arrow C Data interface
int64_t rows_affected = -1;
CHECK(AdbcStatementExecuteQuery(&statement, &stream, &rows_affected, &error));
// consume `stream` with nanoarrow / Arrow C++, then release:
stream.release(&stream);
AdbcStatementRelease(&statement, &error);
AdbcConnectionRelease(&connection, &error);
AdbcDatabaseRelease(&database, &error);
return 0;
}
using Apache.Arrow.Adbc;
using Apache.Arrow.Adbc.DriverManager;
var parameters = new Dictionary<string, string>
{
["uri"] = "netezza://admin:<pw>@nzhost:5480/SYSTEM",
};
// Load the driver by name from its ADBC manifest.
using AdbcDriver driver = AdbcDriverManager.FindLoadDriver(
"arpenz", loadOptions: AdbcLoadFlags.Default);
using AdbcDatabase database = driver.Open(parameters);
using AdbcConnection connection = database.Connect(null);
using AdbcStatement statement = connection.CreateStatement();
statement.SqlQuery = "SELECT * FROM lineitem LIMIT 10";
QueryResult result = statement.ExecuteQuery();
using var stream = result.Stream!; // IArrowArrayStream of RecordBatches
Console.WriteLine(stream.Schema);
package main
import (
"context"
"fmt"
"github.com/apache/arrow-adbc/go/adbc"
"github.com/apache/arrow-adbc/go/adbc/drivermgr"
)
func main() {
ctx := context.Background()
var drv drivermgr.Driver
// Load the driver by name from its ADBC manifest.
db, err := drv.NewDatabase(map[string]string{
"driver": "arpenz",
adbc.OptionKeyURI: "netezza://admin:<pw>@nzhost:5480/SYSTEM",
})
if err != nil {
panic(err)
}
defer db.Close()
conn, err := db.Open(ctx)
if err != nil {
panic(err)
}
defer conn.Close()
stmt, err := conn.NewStatement()
if err != nil {
panic(err)
}
defer stmt.Close()
if err := stmt.SetSqlQuery("SELECT * FROM lineitem LIMIT 10"); err != nil {
panic(err)
}
reader, _, err := stmt.ExecuteQuery(ctx) // (array.RecordReader, int64, error)
if err != nil {
panic(err)
}
defer reader.Release()
fmt.Println(reader.Schema())
}
import java.util.HashMap;
import java.util.Map;
import org.apache.arrow.adbc.core.AdbcConnection;
import org.apache.arrow.adbc.core.AdbcDatabase;
import org.apache.arrow.adbc.core.AdbcDriver;
import org.apache.arrow.adbc.core.AdbcStatement;
import org.apache.arrow.adbc.driver.jni.JniDriver;
import org.apache.arrow.memory.BufferAllocator;
import org.apache.arrow.memory.RootAllocator;
import org.apache.arrow.vector.ipc.ArrowReader;
public class ConnectAndQuery {
public static void main(String[] args) throws Exception {
Map<String, Object> parameters = new HashMap<>();
// Load the driver by name from its ADBC manifest.
JniDriver.PARAM_DRIVER.set(parameters, "arpenz");
AdbcDriver.PARAM_URI.set(parameters, "netezza://admin:<pw>@nzhost:5480/SYSTEM");
try (BufferAllocator allocator = new RootAllocator();
AdbcDatabase db = new JniDriver(allocator).open(parameters);
AdbcConnection connection = db.connect();
AdbcStatement statement = connection.createStatement()) {
statement.setSqlQuery("SELECT * FROM lineitem LIMIT 10");
try (AdbcStatement.QueryResult result = statement.executeQuery()) {
ArrowReader reader = result.getReader();
System.out.println(reader.getVectorSchemaRoot().getSchema());
}
}
}
}
library(adbcdrivermanager)
library(arrow)
# Load the driver by name from its ADBC manifest.
db <- adbc_database_init(
adbc_driver("arpenz"),
uri = "netezza://admin:<pw>@nzhost:5480/SYSTEM"
)
con <- adbc_connection_init(db)
table <- read_adbc(con, "SELECT * FROM lineitem LIMIT 10") |>
as_arrow_table()
print(table$schema)
use adbc_core::options::{AdbcVersion, OptionDatabase, OptionValue};
use adbc_core::{Connection, Database, Driver, Statement, LOAD_FLAG_DEFAULT};
use adbc_driver_manager::ManagedDriver;
use arrow_array::RecordBatchReader;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load the driver by name from its ADBC manifest.
let mut driver = ManagedDriver::load_from_name(
"arpenz", None, AdbcVersion::default(), LOAD_FLAG_DEFAULT, None,
)?;
let mut database = driver.new_database_with_opts([(
OptionDatabase::Uri,
OptionValue::String("netezza://admin:<pw>@nzhost:5480/SYSTEM".into()),
)])?;
let mut connection = database.new_connection()?;
let mut statement = connection.new_statement()?;
statement.set_sql_query("SELECT * FROM lineitem LIMIT 10")?;
let reader = statement.execute()?; // impl RecordBatchReader
println!("{}", reader.schema());
Ok(())
}
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:
- Python
- C / C++
- C#
- Go
- Java
- R
- Rust
conn = dbapi.connect(driver="arpenz", db_kwargs={
"adbc.arpenz.server": "nzhost",
"adbc.arpenz.port": "5480",
"adbc.arpenz.database": "SYSTEM",
"adbc.arpenz.username": "admin",
"adbc.arpenz.password": "<pw>",
})
CHECK(AdbcDatabaseNew(&database, &error));
CHECK(AdbcDatabaseSetOption(&database, "driver", "arpenz", &error));
CHECK(AdbcDatabaseSetOption(&database, "adbc.arpenz.server", "nzhost", &error));
CHECK(AdbcDatabaseSetOption(&database, "adbc.arpenz.port", "5480", &error));
CHECK(AdbcDatabaseSetOption(&database, "adbc.arpenz.database", "SYSTEM", &error));
CHECK(AdbcDatabaseSetOption(&database, "adbc.arpenz.username", "admin", &error));
CHECK(AdbcDatabaseSetOption(&database, "adbc.arpenz.password", "<pw>", &error));
CHECK(AdbcDatabaseInit(&database, &error));
var parameters = new Dictionary<string, string>
{
["adbc.arpenz.server"] = "nzhost",
["adbc.arpenz.port"] = "5480",
["adbc.arpenz.database"] = "SYSTEM",
["adbc.arpenz.username"] = "admin",
["adbc.arpenz.password"] = "<pw>",
};
using AdbcDriver driver = AdbcDriverManager.FindLoadDriver("arpenz", loadOptions: AdbcLoadFlags.Default);
using AdbcDatabase database = driver.Open(parameters);
db, err := drv.NewDatabase(map[string]string{
"driver": "arpenz",
"adbc.arpenz.server": "nzhost",
"adbc.arpenz.port": "5480",
"adbc.arpenz.database": "SYSTEM",
"adbc.arpenz.username": "admin",
"adbc.arpenz.password": "<pw>",
})
Map<String, Object> parameters = new HashMap<>();
JniDriver.PARAM_DRIVER.set(parameters, "arpenz");
parameters.put("adbc.arpenz.server", "nzhost");
parameters.put("adbc.arpenz.port", "5480");
parameters.put("adbc.arpenz.database", "SYSTEM");
parameters.put("adbc.arpenz.username", "admin");
parameters.put("adbc.arpenz.password", "<pw>");
AdbcDatabase db = new JniDriver(allocator).open(parameters);
db <- adbc_database_init(
adbc_driver("arpenz"),
adbc.arpenz.server = "nzhost",
adbc.arpenz.port = "5480",
adbc.arpenz.database = "SYSTEM",
adbc.arpenz.username = "admin",
adbc.arpenz.password = "<pw>"
)
let mut database = driver.new_database_with_opts([
(OptionDatabase::Other("adbc.arpenz.server".into()), OptionValue::String("nzhost".into())),
(OptionDatabase::Other("adbc.arpenz.port".into()), OptionValue::String("5480".into())),
(OptionDatabase::Other("adbc.arpenz.database".into()), OptionValue::String("SYSTEM".into())),
(OptionDatabase::Other("adbc.arpenz.username".into()), OptionValue::String("admin".into())),
(OptionDatabase::Other("adbc.arpenz.password".into()), OptionValue::String("<pw>".into())),
])?;
Straight to pandas / Polars
The result is already Arrow, so these handoffs need no row-by-row conversion. pandas and Polars read straight from the ADBC connection:
import adbc_driver_manager.dbapi as dbapi
import pandas as pd
import polars as pl
uri = "netezza://admin:<pw>@nzhost:5480/SYSTEM"
with dbapi.connect(driver="arpenz", db_kwargs={"uri": uri}) as conn:
# pandas: Arrow-backed dtypes, no Python-object columns
df = pd.read_sql(
"SELECT * FROM orders WHERE o_orderdate >= DATE '1996-01-01'",
conn, dtype_backend="pyarrow",
)
# Polars: reads the same ADBC result directly
pf = pl.read_database(
"SELECT * FROM orders WHERE o_orderdate >= DATE '1996-01-01'", conn
)
Parameter binding
Use ? placeholders. Netezza has no server-side prepared statements, so the
driver renders each bound value into the SQL text as an escaped literal, and
runs the statement once per parameter row. See
Bound parameters.
- Python
- C / C++
- Go
with conn.cursor() as cur:
cur.execute("SELECT * FROM orders WHERE o_orderkey = ?", parameters=[42])
row = cur.fetch_arrow_table()
// One-row, one-column (int64) parameter batch, built with nanoarrow.
ArrowSchema param_schema = {};
ArrowSchemaInitFromType(¶m_schema, NANOARROW_TYPE_STRUCT);
ArrowSchemaAllocateChildren(¶m_schema, 1);
ArrowSchemaInitFromType(param_schema.children[0], NANOARROW_TYPE_INT64);
ArrowSchemaSetName(param_schema.children[0], "0");
ArrowArray param_array = {};
ArrowArrayInitFromSchema(¶m_array, ¶m_schema, nullptr);
ArrowArrayStartAppending(¶m_array);
ArrowArrayAppendInt(param_array.children[0], 42);
ArrowArrayFinishElement(¶m_array);
ArrowArrayFinishBuildingDefault(¶m_array, nullptr);
CHECK(AdbcStatementSetSqlQuery(&statement, "SELECT * FROM orders WHERE o_orderkey = ?", &error));
CHECK(AdbcStatementBind(&statement, ¶m_array, ¶m_schema, &error));
CHECK(AdbcStatementExecuteQuery(&statement, &stream, &rows_affected, &error));
import (
"github.com/apache/arrow-go/v18/arrow"
"github.com/apache/arrow-go/v18/arrow/array"
"github.com/apache/arrow-go/v18/arrow/memory"
)
schema := arrow.NewSchema([]arrow.Field{
{Name: "0", Type: arrow.PrimitiveTypes.Int64},
}, nil)
bldr := array.NewRecordBuilder(memory.DefaultAllocator, schema)
defer bldr.Release()
bldr.Field(0).(*array.Int64Builder).Append(42)
rec := bldr.NewRecord()
defer rec.Release()
_ = stmt.SetSqlQuery("SELECT * FROM orders WHERE o_orderkey = ?")
if err := stmt.Bind(ctx, rec); err != nil {
panic(err)
}
reader, _, err := stmt.ExecuteQuery(ctx)
if err != nil {
panic(err)
}
defer reader.Release()
Several parameter rows in one call (Python's executemany) run the statement
once per row:
with conn.cursor() as cur:
cur.executemany(
"INSERT INTO t(a, b) VALUES (?, ?)",
seq_of_parameters=[(1, "x"), (2, "y"), (3, "z")],
)
For more than a handful of rows, use bulk ingest instead.
Bulk ingest an Arrow table
adbc_ingest streams an Arrow table into Netezza through the external-table
load, falling back to batched INSERT when needed (see
Data types → Write path).
The data must arrive as a stream (BindStream), and adbc.ingest.mode
must be set:
- Python
- Go
- R
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
import (
"github.com/apache/arrow-adbc/go/adbc"
"github.com/apache/arrow-go/v18/arrow"
"github.com/apache/arrow-go/v18/arrow/array"
"github.com/apache/arrow-go/v18/arrow/memory"
)
schema := arrow.NewSchema([]arrow.Field{
{Name: "id", Type: arrow.PrimitiveTypes.Int32},
{Name: "name", Type: arrow.BinaryTypes.String},
}, nil)
bldr := array.NewRecordBuilder(memory.DefaultAllocator, schema)
defer bldr.Release()
bldr.Field(0).(*array.Int32Builder).AppendValues([]int32{1, 2, 3}, nil)
bldr.Field(1).(*array.StringBuilder).AppendValues([]string{"a", "b", "c"}, nil)
rec := bldr.NewRecord()
defer rec.Release()
rdr, _ := array.NewRecordReader(schema, []arrow.Record{rec})
defer rdr.Release()
_ = stmt.SetOption(adbc.OptionKeyIngestTargetTable, "my_table")
_ = stmt.SetOption(adbc.OptionKeyIngestMode, adbc.OptionValueIngestModeCreate)
if err := stmt.BindStream(ctx, rdr); err != nil { // a stream, not Bind
panic(err)
}
if _, err := stmt.ExecuteUpdate(ctx); err != nil {
panic(err)
}
tbl <- arrow::arrow_table(
id = arrow::Array$create(1:3, type = arrow::int32()),
name = c("a", "b", "c")
)
tbl |> write_adbc(con, "my_table", mode = "create")
With autocommit on (the default), each ingest is one transaction. Choose the
load path with adbc.arpenz.ingest_method (auto, external, insert):
conn = dbapi.connect(driver="arpenz", db_kwargs={
"uri": "netezza://admin:<pw>@nzhost:5480/SYSTEM",
"adbc.arpenz.ingest_method": "external", # fail instead of falling back to INSERT
})
Ingest into a specific schema or a temporary table via the statement options
adbc.ingest.target_db_schema / adbc.ingest.temporary (see
Connection). Table
and column names are used exactly as given (quoted), so my_table above is the
case-sensitive "my_table".
Export a query to Parquet
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; buffer_size sets the
rows per batch (default 32000). INTERVAL columns stay Parquet-writable as
long as interval_type is left at its text default.
TLS
Verify the server (verify-full) against a CA file, which IBM Cloud NPS needs
(see Authentication):
conn = dbapi.connect(driver="arpenz", db_kwargs={
"adbc.arpenz.server": "nz-<instance-guid>.<region>.data-warehouse.cloud.ibm.com",
"adbc.arpenz.database": "SYSTEM",
"adbc.arpenz.username": "admin",
"adbc.arpenz.password": "<pw>",
"adbc.arpenz.sslmode": "verify-full",
"adbc.arpenz.ssl_root_cert": "/path/to/ibm_nps_ca.pem",
})
An NPS 7 server, which only offers TLS 1.0 / 1.1, with encryption required.
This combination is not yet validated against a live NPS 7 (see
Authentication → NPS 7); if the
handshake fails, use sslmode=disable on a trusted network:
conn = dbapi.connect(driver="arpenz", db_kwargs={
"uri": "netezza://admin:<pw>@nz7host:5480/SYSTEM?sslmode=require",
"adbc.arpenz.tls_min_version": "1.0",
})
Loading by explicit path
Load-by-name uses an arpenz.toml ADBC driver manifest on the driver manager's
search path (point ADBC_DRIVER_PATH at its directory if needed). Without one,
pass the shared library's path as the driver:
conn = dbapi.connect(
driver="/opt/arpeio/libarpenz_adbc_driver-linux-x64.so", # Windows: r"C:\arpeio\arpenz_adbc_driver-win-x64.dll"
db_kwargs={"uri": "netezza://admin:<pw>@nzhost:5480/SYSTEM"},
)
In C# use CAdbcDriverImporter.Load("libarpenz_adbc_driver-linux-x64.so", "AdbcDriverInit").
Everything after loading is identical. When loading by path, put the licence
file arpeio_adbc.lic next to the library, or supply the licence another way
(see Licensing).
See also
- Connection: every connection option
- Data types: the Arrow types you get back
- Troubleshooting: when a snippet does not connect