Kubling SQLAlchemy Dialect
kubling-sqlalchemy connects SQLAlchemy 2 applications to Kubling through its
native client gRPC API. It includes a synchronous DB-API 2.0 driver and a Kubling
SQL compiler. The published kubling-grpc package supplies the protocol bindings.
The current scope covers SQLAlchemy Core queries, parameter binding, result streaming, basic writes, explicit transactions, autocommit, connection pooling and catalog reflection. Apache Superset integration belongs to its own project.
Version 26.2 replaces the old PostgreSQL/psycopg2 transport. Existing URLs must be
updated with the gRPC endpoint, the VDB version and, for local plaintext servers,
insecure=true.
| Component | Supported version |
|---|---|
| Python | 3.10–3.14 |
| SQLAlchemy | 2.0.36–2.0.x |
kubling-grpc |
1.1.1 |
| Kubling server | Verified with 26.2-RC5 |
| Apache Superset | Verified with the 7.0 development line; 6.1 and older are incompatible |
Installation
Python 3.10 or newer is required.
python -m pip install kubling-sqlalchemy
SQLAlchemy usage
Kubling gRPC uses an explicit endpoint. TLS is enabled by default:
from sqlalchemy import create_engine, text
engine = create_engine(
"kubling://username:password@kubling.example:55051/Analytics"
"?vdb_version=1"
)
with engine.connect() as connection:
rows = connection.execute(
text("SELECT name FROM inventory.products WHERE category = :category"),
{"category": "books"},
)
for row in rows:
print(row.name)
When using SQLAlchemy expression objects, named bindparam() values are compiled
to the driver's positional qmark parameters:
from sqlalchemy import Integer, String, bindparam, column, select, table
products = table(
"products",
column("name", String),
column("category", String),
column("rank", Integer),
schema="inventory",
)
statement = (
select(products.c.name)
.where(products.c.category == bindparam("category"))
.order_by(products.c.rank)
.limit(10)
)
with engine.connect() as connection:
rows = connection.execute(statement, {"category": "books"}).all()
For a local plaintext server, opt in explicitly:
kubling://username:password@127.0.0.1:55051/Analytics?vdb_version=1&insecure=true
kubling+grpc:// is an equivalent, more explicit alias. There is no implicit
port. An endpoint can instead be supplied as a query option, which is useful for
IPv6 or custom gRPC resolvers:
kubling://username:password@/Analytics?endpoint=dns:///kubling.example:443&vdb_version=1
Supported connection options are:
| Option | Meaning | Default |
|---|---|---|
vdb_version |
VDB version sent during login | empty |
insecure |
Disable TLS when true |
false |
ca_file |
PEM root CA file | system roots |
client_cert_file |
PEM client certificate for mTLS | unset |
client_key_file |
PEM client private key for mTLS | unset |
server_name |
TLS server-name override | unset |
connect_timeout |
Channel/login timeout in seconds | 10 |
rpc_timeout |
RPC timeout in seconds | 30 |
wait_for_ready |
Wait for the channel when true |
true |
max_send_message_bytes |
Maximum outbound gRPC message size | 16777216 |
max_receive_message_bytes |
Maximum inbound gRPC message size | 67108864 |
application_name |
Client name sent at login | kubling-sqlalchemy |
property.<name> |
Additional VDB login property | unset |
The client certificate and private key must be configured together. TLS options
cannot be combined with insecure=true. Unknown or repeated URL options fail
early instead of being silently ignored.
Direct DB-API usage
The driver can be used without SQLAlchemy:
from kubling_sqlalchemy import dbapi
connection = dbapi.connect(
endpoint="kubling.example:443",
vdb_name="Analytics",
vdb_version="1",
username="user",
password="...",
)
try:
cursor = connection.cursor()
cursor.execute(
"SELECT marker, seq FROM acceptance.GRPC_B2_TEST WHERE seq = ?",
(1,),
)
print(cursor.fetchall())
connection.commit()
finally:
connection.close()
The driver uses DB-API 2.0 qmark parameters. Transactions begin lazily unless
autocommit=True. A connection permits one unfinished result stream at a time;
closing its cursor cancels that stream and releases the connection.
Types
The driver handles strings, booleans, bytes, integral and floating-point numbers,
Decimal, dates, local times and timestamps, XML, JSON, geometry, geography, arrays
and BLOB/CLOB values. SQLAlchemy reflects those values to its closest standard type;
unknown catalog types become NullType with a warning.
DB-API rows return standard Python time and datetime values when the server value
fits Python's microsecond precision. Values with finer precision retain their
lossless KublingLocalTime or KublingLocalTimestamp wrapper.
Large BLOB and CLOB values can be returned as references. Call
connection.materialize_lob(reference) while the session is active to read and
release one. Array and LOB operations are enabled only when the server advertises
the corresponding capability.
Catalog reflection
The dialect reflects schemas, tables, views, materialized views, columns, comments,
primary keys, unique constraints, foreign keys and catalog indexes through Kubling's
SYS and SYSADMIN relations. Inspector, Table(..., autoload_with=...) and
MetaData.reflect() use the same gRPC connection and parameter binding as normal
queries.
Kubling VDBs do not expose one universal default schema. Pass schema= explicitly
when listing or reflecting objects. With no configured default schema,
Inspector.get_table_names() returns an empty list and table-scoped reflection
raises NoSuchTableError; the dialect never substitutes public implicitly.
Column reflection preserves length, precision, scale, nullability, default,
autoincrement and comments reported by the catalog. Unknown Kubling types produce a
SQLAlchemy NullType warning instead of being assigned an unsafe conversion.
Current limits
- SQLAlchemy 1.4 and the former PostgreSQL transport are no longer supported.
- A connection has one active result stream; server-side cursors are not exposed.
RETURNING, multi-value inserts, sequences and identity columns are disabled.- DDL support depends on the source behind the VDB. The dialect does not emulate it.
- SQLAlchemy ORM has not been validated separately.
- Superset support requires its SQLAlchemy 2 line. Released versions through 6.1 still use SQLAlchemy 1.4 and cannot install this package.
Development
Install the project and its development tools in a Python 3.10+ virtual environment:
python -m pip install -e '.[dev]'
python -m pytest
python -m build
The default test run uses in-process gRPC services and does not contact an
external server. To run the live acceptance tests, configure an isolated Kubling
instance and add --integration:
export KUBLING_GRPC_TARGET=localhost:55051
export KUBLING_GRPC_VDB=GrpcAcceptanceVDB
export KUBLING_GRPC_VDB_VERSION=1
export KUBLING_GRPC_USERNAME=test-user
export KUBLING_GRPC_PASSWORD='...'
export KUBLING_GRPC_TEST_TABLE=acceptance.GRPC_B2_TEST
export KUBLING_GRPC_INSECURE=1
python -m pytest --integration -m integration
For TLS, omit KUBLING_GRPC_INSECURE and optionally set
KUBLING_GRPC_CA_FILE, KUBLING_GRPC_CLIENT_CERT_FILE,
KUBLING_GRPC_CLIENT_KEY_FILE and KUBLING_GRPC_SERVER_NAME.
The live transport and DB-API tests also use
KUBLING_GRPC_LATE_ERROR_SQL for their controlled late-stream error fixture.
Incremental memory behavior can be measured without retaining rows by running
python scripts/profile-stream-memory.py with the same connection variables. The
script reports row and payload sizes, Python peak allocation and process RSS growth;
its SQL, row count, batch size, consumer pause and RSS limit can be overridden with
the KUBLING_GRPC_MEMORY_* variables. Set
KUBLING_GRPC_MEMORY_STRING_BYTES to generate a parameterized result with an exact
ASCII payload size per row; the default parameterized query returns the requested
row count from the system catalog. Set KUBLING_GRPC_MEMORY_MATERIALIZE_LOBS=1
when the query returns LOB references to read, validate and release each payload.
Tests, local connection scripts and internal planning files are excluded from
distribution artifacts. Building the project does not publish it. See
RELEASING.md for the release procedure.
Contributing
Issues and pull requests are welcome. Please include focused tests for behavioral changes and run the local suite before submitting a change.
Release files for kubling-sqlalchemy 26.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| kubling_sqlalchemy-26.2.0.tar.gz | 39.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| kubling_sqlalchemy-26.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 82.5 kB
Release files / kubling_sqlalchemy-26.2.0.tar.gz
| Download URL | kubling_sqlalchemy-26.2.0.tar.gz |
|---|---|
| Size | 39.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6bae879712c0a99c4eb799dddc63ba0c9cb021f7bf1eb200ea471fef4a6b6ede
|
|
BLAKE2b-256 checksum How to use checksums |
345c4e70fd39f7dfdd3358f42566e1fc366a8ba81d994fb58075ab046256bf60
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / kubling_sqlalchemy-26.2.0-py3-none-any.whl
| Download URL | kubling_sqlalchemy-26.2.0-py3-none-any.whl |
|---|---|
| Size | 43.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
95c5e39d96b2e4e50b5ba4bfb530b641bf306c88aa4c9663b4fc44d6b8d5bfd9
|
|
BLAKE2b-256 checksum How to use checksums |
783393ee8d838e0f25228b3087c4c7f531efd8cbed17f05fd0a118c7ef97f3b5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|