arrow-odbc#
Sync Arrow-over-ODBC adapter built on arrow-odbc.
Streams pyarrow.RecordBatchReader results from any ODBC-compliant driver,
making it a good fit for read-heavy analytical transfer between SQL Server,
PostgreSQL, MySQL, or other ODBC sources and the Arrow ecosystem.
SQL Server coverage is exercised in CI against SQL Server 2022 through
pytest-databases and Microsoft ODBC Driver 18. The shared contract matrix
verifies native Arrow reads, Arrow reader/batch output, and Arrow bulk ingest
for this adapter. Use load_from_arrow() or bulk_insert_arrow() for
native Arrow bulk writes, or execute_many() for row-oriented batches.
The adapter exports a table-backed events queue store, a Litestar session store, and Google ADK session/event and memory stores. They support SQL Server connections through Microsoft ODBC Driver 18 and IBM Db2 LUW connections through the IBM CLI/ODBC driver (see IBM Db2).
IBM Db2#
arrow-odbc reads Db2 LUW 11.5 and later through the IBM CLI/ODBC driver. Db2 for z/OS and Db2 for IBM i are not supported. For row-oriented work, pooling, and async access use the Db2 adapter.
Dialect detection. The adapter picks the SQL dialect from the ODBC driver
name only: the Driver value of the connection string, or its DSN value
when there is no Driver. Names containing db2, IBM Data Server Driver,
clidriver, or libdb2o select db2. Database, host, and user names are
never used. When the driver is reached through a DSN whose name does not say
Db2, set driver_features={"dbms_name": "DB2"}.
Connection keywords. For Db2, host (or server) and port render as
the IBM CLI keywords Hostname and Port, and Protocol=TCPIP is added
when a host is set. SQL Server options such as encrypt,
trust_server_certificate, and trusted_connection raise
ImproperConfigurationError.
The ibm_db package (installed by sqlspec[db2]) bundles the CLI driver, so
no separate ODBC driver installation is needed; unixODBC must be present on Linux.
Point Driver at the bundled libdb2o.so:
from pathlib import Path
import ibm_db
from arrow_odbc import TextEncoding
from sqlspec.adapters.arrow_odbc import ArrowOdbcConfig
package_dir = Path(ibm_db.__file__).resolve().parent
driver = next(package_dir.rglob("clidriver/lib/libdb2o.so"), package_dir / "clidriver/lib/libdb2o.so")
config = ArrowOdbcConfig(
connection_config={
"connection_string": f"Driver={driver};LongDataCompat=1;",
"host": "db2.example.com",
"port": 50000,
"database": "SAMPLE",
"uid": "db2inst1",
"pwd": "secret",
"autocommit": False,
},
driver_features={"payload_text_encoding": TextEncoding.UTF16},
)
print(config.statement_config.dialect)
# db2
Transactions. Db2 has no BEGIN statement. begin() and
transaction() require a connection opened with autocommit off, so set
connection_config={"autocommit": False} for transactional work; on an
autocommit connection they raise ImproperConfigurationError. Savepoints use
Db2 syntax.
Large objects. Add LongDataCompat=1 to the connection string so BLOB
columns arrive as binary rather than hexadecimal text and CLOB columns as
text.
Text encoding. For non-ASCII text, either set the DB2CODEPAGE=1208
environment variable before connecting or set
driver_features={"payload_text_encoding": TextEncoding.UTF16} (TextEncoding
comes from the arrow_odbc package). Text parameters are
always bound as text.
Results. Implicitly uppercase column names are lowercased (disable with
driver_features={"enable_lowercase_column_names": False}); quoted mixed-case
names are kept. Timezone-aware datetime parameters are bound as UTC. Db2
TIMESTAMP(12) values are truncated to nanoseconds, and DECFLOAT, XML,
and BOOLEAN columns arrive as UTF-8 text.
Configuration#
- class sqlspec.adapters.arrow_odbc.ArrowOdbcConfig[source]#
Bases:
NoPoolSyncConfig[Connection,ArrowOdbcDriver]Configuration for synchronous arrow-odbc connections.
- driver_type#
alias of
ArrowOdbcDriver
- __init__(*, connection_config=None, connection_instance=None, migration_config=None, statement_config=None, driver_features=None, bind_key=None, extension_config=None, observability_config=None, **kwargs)[source]#
Initialize arrow-odbc configuration.
- provide_connection(*args, **kwargs)[source]#
Provide a connection context manager.
- Return type:
ArrowOdbcConnectionContext
- provide_session(*_args, statement_config=None, **_kwargs)[source]#
Provide a driver session context manager.
- Return type:
ArrowOdbcSessionContext
Connection Parameters#
Driver Features#
- class sqlspec.adapters.arrow_odbc.ArrowOdbcDriverFeatures[source]#
Bases:
TypedDictarrow-odbc driver feature flags.
connection_autocommitis the autocommit mode of connections created by the config; the config sets it fromconnection_config["autocommit"].enable_lowercase_column_nameslowercases result column names the database folded to uppercase (quoted mixed-case names are kept); it defaults to on for Db2 and off for every other dialect.
Driver#
- class sqlspec.adapters.arrow_odbc.ArrowOdbcDriver[source]#
Bases:
SyncDriverAdapterBaseSync driver for generic ODBC connections with Arrow-native transfer.
- __init__(connection, statement_config=None, driver_features=None)[source]#
Initialize driver adapter with connection and configuration.
- Parameters:
connection¶ (
Connection) -- Database connection instancestatement_config¶ (
StatementConfig|None) -- Statement configuration for the driverdriver_features¶ (
dict[str, typing.Any] |None) -- Driver-specific features like extensions, secrets, and connection callbacksobservability¶ -- Optional runtime handling lifecycle hooks, observers, and spans
- property data_dictionary: ArrowOdbcDataDictionary#
Get the data dictionary for this driver.
- Returns:
Data dictionary instance for metadata queries
- dispatch_execute(cursor, statement)[source]#
Execute a single SQL statement.
Must be implemented by each driver for database-specific execution logic.
- Parameters:
- Return type:
- Returns:
ExecutionResult with execution data
- dispatch_execute_many(cursor, statement)[source]#
Execute SQL with multiple parameter sets (executemany).
Must be implemented by each driver for database-specific executemany logic.
- Parameters:
- Return type:
- Returns:
ExecutionResult with execution data for the many operation
- dispatch_execute_script(cursor, statement)[source]#
Execute a SQL script containing multiple statements.
Default implementation splits the script and executes statements individually. Drivers can override for database-specific script execution methods.
- Parameters:
- Return type:
- Returns:
ExecutionResult with script execution data including statement counts
- dispatch_select_stream(statement, chunk_size)[source]#
Return a native Arrow ODBC row stream backed by record batches.
- Return type:
Optional[SyncRowStream[dict[str, typing.Any]]]
- collect_rows(cursor, fetched)[source]#
Collect rows from cursor after fetchall for the direct execution path.
Adapters should override this method to provide optimized row collection that bypasses full dispatch_execute overhead.
- Parameters:
- Return type:
- Returns:
Tuple of (data, column_names, row_count).
- Raises:
NotImplementedError -- If the adapter does not implement this method.
- resolve_rowcount(cursor)[source]#
Resolve the number of affected rows from cursor for the direct execution path.
Adapters should override this method to provide optimized rowcount resolution that bypasses full dispatch_execute overhead.
- Parameters:
cursor¶ (
Connection) -- Database cursor with rowcount metadata.- Return type:
- Returns:
Number of affected rows, or 0 when unknown.
- Raises:
NotImplementedError -- If the adapter does not implement this method.
- begin()[source]#
Begin an explicit transaction.
SQL Server starts one with
BEGIN TRANSACTION. Db2 has no begin statement: a connection opened with autocommit off is always inside a unit of work, so only the boundary is recorded, and an autocommit connection is refused because each statement would commit on its own.- Raises:
ImproperConfigurationError -- If the Db2 connection was opened with autocommit on.
SQLSpecError -- If the begin statement fails.
- Return type:
- with_cursor(connection)[source]#
Create and return a context manager for cursor acquisition and cleanup.
Returns a context manager that yields a cursor for database operations. Concrete implementations handle database-specific cursor creation and cleanup.
- Return type:
ArrowOdbcCursor
- handle_database_exceptions()[source]#
Handle database-specific exceptions and wrap them appropriately.
- Return type:
ArrowOdbcExceptionHandler- Returns:
Exception handler with deferred exception pattern for mypyc compatibility. The handler stores mapped exceptions in pending_exception rather than raising from __exit__ to avoid ABI boundary violations.
- rollback_to_savepoint(name)[source]#
Roll back the current transaction to a previously created savepoint.
- Return type:
- select_to_arrow(statement, /, *parameters, statement_config=None, return_format='table', native_only=False, batch_size=None, arrow_schema=None, **kwargs)[source]#
Execute a query and return native Arrow results.
- bulk_insert_arrow(target_table, source, *, chunk_size=None)[source]#
Insert an Arrow table or reader into a database table.
- Return type:
- load_from_arrow(table, source, *, partitioner=None, overwrite=False, telemetry=None)[source]#
Load Arrow data into a table via arrow-odbc bulk insert.
- Return type:
Data Dictionary#
- class sqlspec.adapters.arrow_odbc.data_dictionary.ArrowOdbcDataDictionary[source]#
Bases:
SyncDataDictionaryBaseRuntime-dialect data dictionary for generic ODBC connections.
- dialect: ClassVar[str] = 'sqlite'#
Dialect identifier. Must be defined by subclasses as a class attribute.
- get_dialect_config()[source]#
Return the runtime dialect configuration for this data dictionary.
- Return type:
DialectConfig
- get_query(domain, operation, *, mode=None)[source]#
Return an exact domain query for the runtime dialect.
- Return type:
- get_query_text(domain, operation, *, mode=None)[source]#
Return raw SQL text for an exact runtime dialect query.
- Return type:
- get_metadata_capabilities(driver, domains=None)[source]#
Report Arrow ODBC metadata capabilities without claiming raw catalog support.
- Return type:
- resolve_identifier(identifier)[source]#
Return a runtime-dialect-normalized identifier.
- Return type:
- get_version(driver)[source]#
Get database version information when the runtime dialect provides a query.
- Return type:
- get_feature_flag(driver, feature)[source]#
Check whether the runtime dialect supports a feature.
- Return type:
- get_optimal_type(driver, type_category)[source]#
Get the optimal runtime dialect type for a category.
- Return type:
- get_tables(driver, schema=None)[source]#
Get table metadata for dialects with bundled catalog queries.
- Return type:
- get_columns(driver, table=None, schema=None)[source]#
Get column metadata for dialects with bundled catalog queries.
- Return type:
- get_indexes(driver, table=None, schema=None)[source]#
Get index metadata for dialects with bundled catalog queries.
- Return type:
Extensions#
- class sqlspec.adapters.arrow_odbc.events.ArrowOdbcEventQueueStore[source]#
Bases:
BaseEventQueueStore[ArrowOdbcConfig]Event queue DDL for arrow-odbc configs.
SQL Server DDL with
OBJECT_IDguards is used by default. A config whose dialect resolves todb2gets plain Db2CREATE TABLE/CREATE INDEXstatements; the events migration checks the catalog for the table and the index before running them.
- class sqlspec.adapters.arrow_odbc.litestar.ArrowOdbcStore[source]#
Bases:
BaseSQLSpecStore[ArrowOdbcConfig]Session store using arrow-odbc sessions.
SQL Server statements are used by default; a config whose dialect resolves to
db2uses Db2 statements with bound UTC times and catalog-probed DDL.- __init__(config)[source]#
Initialize the session store.
- Parameters:
config¶ (
ArrowOdbcConfig) -- SQLSpec database configuration.
- class sqlspec.adapters.arrow_odbc.adk.ArrowOdbcADKStore[source]#
Bases:
BaseSyncADKStore[ArrowOdbcConfig]Synchronous ADK session/event store using arrow-odbc.
SQL Server statements are used by default; a config whose dialect resolves to
db2uses Db2 statements with bound UTC times and catalog-probed DDL.- __init__(config)[source]#
Initialize the ADK store.
- Parameters:
config¶ (
ArrowOdbcConfig) -- SQLSpec database configuration.
Notes
Reads configuration from config.extension_config["adk"]: - session_table: Sessions table name (default: "adk_session") - events_table: Events table name (default: "adk_event") - app_state_table: App-scoped state table name (default: "adk_app_state") - user_state_table: User-scoped state table name (default: "adk_user_state") - metadata_table: Internal metadata table name (default: "adk_internal_metadata") - owner_id_column: Optional owner FK column DDL (default: None)
- create_tables()[source]#
Create the ADK tables and indexes the catalog reports as missing.
- Return type:
- create_session(session_id, app_name, user_id, state, owner_id=None)[source]#
Create a new ADK session.
- Return type:
- get_session(app_name, user_id, session_id, *, renew_for=None)[source]#
Return a scoped session or
Noneif absent.- Return type:
- update_session_state(app_name, user_id, session_id, state)[source]#
Replace a session's durable state.
- Return type:
- list_sessions(app_name, user_id=None, *, order_by='update_time', descending=True, limit=None, offset=None)[source]#
List ADK sessions for an application, optionally scoped to a user.
- Return type:
- delete_session(app_name, user_id, session_id)[source]#
Delete a session. Event rows cascade through the FK.
- Return type:
- append_event_and_update_state(event_record, app_name, user_id, session_id, state, *, app_state=None, user_state=None)[source]#
Atomically append an event and update durable session/scoped state.
- Return type:
- get_events(app_name, user_id, session_id, after_timestamp=None, limit=None)[source]#
Return events for a scoped session ordered by event timestamp.
- Return type:
- delete_idle_sessions(updated_before, app_name=None)[source]#
Delete sessions whose update_time is older than
updated_before.- Return type:
- delete_idle_user_states(updated_before, app_name=None)[source]#
Delete user state rows whose update_time is older than
updated_before.- Return type:
- class sqlspec.adapters.arrow_odbc.adk.ArrowOdbcADKMemoryStore[source]#
Bases:
BaseSyncADKMemoryStore[ArrowOdbcConfig]ADK memory store using arrow-odbc.
SQL Server statements are used by default; a config whose dialect resolves to
db2uses Db2 statements with bound UTC times and catalog-probed DDL.- __init__(config)[source]#
Initialize the ADK memory store.
- Parameters:
config¶ (
ArrowOdbcConfig) -- SQLSpec database configuration.
- create_tables()[source]#
Create the memory table and indexes the catalog reports as missing.
- Return type:
- insert_memory_entries(entries, owner_id=None)[source]#
Insert memory entries, skipping duplicates by event_id.
- Return type:
- search_entries(query, app_name, user_id, limit=None, scope_filter='all', embedding=None)[source]#
Search memory entries with SQL Server LIKE matching.
- Return type:
Schema Discovery#
ArrowOdbcDataDictionary.get_columns first uses bundled dialect catalog
queries. When no query exists for the detected dialect (or it returns no
rows) and a table name is given, the driver issues a zero-row probe
(SELECT * FROM "schema"."table" WHERE 1=0) and derives column names,
ordering, nullability, and SQL type names from the Arrow reader schema.
Arrow-derived type names are approximations (for example VARCHAR for any
string column); mssql_python and other ODBC adapters without native
metadata APIs remain SQL-only.
Extension Settings#
Use these types inside extension_config["adk"].
- class sqlspec.adapters.arrow_odbc.adk.ArrowOdbcADKConfig[source]#
Bases:
ADKConfigarrow-odbc ADK extension settings.
- native_json: NotRequired[bool]#
Accepted for parity with SQL Server adapters; arrow-odbc uses NVARCHAR(MAX).
Row-oriented batch execution#
execute_many() executes each parameter set through the native execute API
without rewriting SQL. Nonempty batches report an unknown affected-row count
(-1); empty batches report zero. Use bulk_insert_arrow() for native
Arrow bulk ingestion.