Connection & Driver Setup¶
This guide covers how to install the CUBRID Python driver, configure SQLAlchemy connection strings, and understand the connection lifecycle.
Table of Contents¶
- Prerequisites
- Installing the CUBRID Python Driver
- Connection String Format
- Entry Points
- How the Dialect Translates URLs
- Connection Options
- Autocommit Behavior
- Server Version Detection
- Troubleshooting
Prerequisites¶
| Requirement | Version |
|---|---|
| Python | 3.10+ |
| SQLAlchemy | 2.0 – 2.1 |
| CUBRID Server | 10.2 – 11.4 |
| CUBRID Python Driver | Latest |
Installing the CUBRID Python Driver¶
The dialect requires the CUBRID-Python driver:
Or install both the dialect and driver together:
Note:
CUBRID-Pythonis a C-extension driver. On some platforms you may need the CUBRID CCI library installed. See the CUBRID Python driver documentation for platform-specific instructions.
Alternative: Pure Python Driver (pycubrid)¶
If you prefer a pure Python driver with no C build dependencies:
Or install separately:
Then use the cubrid+pycubrid:// URL scheme:
Tip:
pycubridis a pure Python implementation — it works anywhere Python runs, with no native library dependencies. See pycubrid on GitHub.
Connection String Format¶
SQLAlchemy uses standard URL-style connection strings:
Examples¶
from sqlalchemy import create_engine
# Basic connection
engine = create_engine("cubrid://dba:password@localhost:33000/demodb")
# Without password (CUBRID allows passwordless dba access by default)
engine = create_engine("cubrid://dba@localhost:33000/testdb")
# With explicit driver name (C-extension)
engine = create_engine("cubrid+cubrid://dba:password@localhost:33000/demodb")
# Using pycubrid pure Python driver
engine = create_engine("cubrid+pycubrid://dba:password@localhost:33000/demodb")
URL Components¶
| Component | Default | Description |
|---|---|---|
user |
(required) | Database username (typically dba) |
password |
(empty) | Database password |
host |
localhost |
CUBRID server hostname or IP |
port |
33000 |
CUBRID broker port |
database |
(required) | Database name |
Entry Points¶
The dialect registers three SQLAlchemy entry points:
| URL Scheme | Driver | Description |
|---|---|---|
cubrid:// |
CUBRIDdb | Default C-extension driver |
cubrid+cubrid:// |
CUBRIDdb | Explicit C-extension driver |
cubrid+pycubrid:// |
pycubrid | Pure Python driver (no C build) |
Use cubrid:// for the C-extension driver (best performance), or cubrid+pycubrid:// for the pure Python driver (easiest installation, no native build step).¶
How the Dialect Translates URLs¶
Internally, the dialect converts SQLAlchemy URLs to the CUBRID native connection format:
SQLAlchemy URL: cubrid://dba:password@myhost:33000/mydb
↓
CUBRID native: CUBRID:myhost:33000:mydb:::
The create_connect_args() method returns (connect_url, username, password) as positional arguments to the CUBRID Python driver's connect() function.
Translation Details¶
# CUBRIDdb (C-extension driver):
connect_url = f"CUBRID:{host}:{port}:{database}:::"
args = (connect_url, username, password)
# → CUBRIDdb.connect("CUBRID:myhost:33000:mydb:::", "dba", "password")
The trailing ::: in the CUBRID connection string represents three empty optional parameters (reserved for future use by CUBRID).
pycubrid Translation¶
The pycubrid dialect passes keyword arguments directly:
# pycubrid (pure Python driver):
kwargs = {"host": host, "port": port, "database": database, "user": user, "password": password}
# → pycubrid.connect(host="myhost", port=33000, database="mydb", user="dba", password="password")
Connection Options¶
Engine-Level Options¶
engine = create_engine(
"cubrid://dba@localhost:33000/testdb",
# Set default isolation level for all connections
isolation_level="REPEATABLE READ",
# SQLAlchemy 2.0 connection pool settings
pool_size=5,
max_overflow=10,
pool_timeout=30,
# Enable SQL logging
echo=True,
)
Per-Connection Isolation Level¶
with engine.connect().execution_options(
isolation_level="SERIALIZABLE"
) as conn:
# This connection uses SERIALIZABLE isolation
result = conn.execute(text("SELECT * FROM accounts"))
See Isolation Levels for all supported levels.
Autocommit Behavior¶
Driver Default vs. Dialect Override¶
Both CUBRID Python drivers default to autocommit=True. The dialect overrides this on every new connection so that SQLAlchemy can manage transactions properly. CUBRIDdb uses conn.set_autocommit(False); pycubrid uses the property setter conn.autocommit = False.
DDL Autocommit Detection¶
CUBRID implicitly commits DDL statements. The dialect detects DDL patterns and enables autocommit for:
CREATE,ALTER,DROPGRANT,REVOKETRUNCATEMERGE
This is handled by the CubridExecutionContext.should_autocommit_text() method using a regex pattern.
Server Version Detection¶
The dialect queries the server version on initialization:
The result (e.g., 11.2.0.0374) is parsed into a tuple (11, 2, 0, 374) for internal version checks.
Troubleshooting¶
Common Connection Errors¶
ImportError: No module named 'CUBRIDdb'¶
The CUBRID Python driver is not installed:
Connection refused on port 33000¶
-
Verify the CUBRID broker is running:
-
Check the broker port in
cubrid_broker.conf— default is33000. -
If using Docker:
Authentication failed¶
CUBRID's default dba user has no password. If you set one, ensure it matches your connection string:
# If dba has no password
engine = create_engine("cubrid://dba@localhost:33000/testdb")
# If dba has a password
engine = create_engine("cubrid://dba:mypassword@localhost:33000/testdb")
Docker Quick Start¶
For local development, use the provided docker-compose.yml:
# Start CUBRID 11.2 (default)
docker compose up -d
# Start a specific version
CUBRID_VERSION=11.4 docker compose up -d
# Verify it's running
docker compose ps
# Connect
python -c "
from sqlalchemy import create_engine, text
engine = create_engine('cubrid://dba@localhost:33000/testdb')
with engine.connect() as conn:
print(conn.execute(text('SELECT VERSION()')).scalar())
"
Connection Pool Tuning¶
SQLAlchemy manages a connection pool by default. Understanding how CUBRID interacts with the pool is important for production deployments.
Key Pool Parameters¶
from sqlalchemy import create_engine
engine = create_engine(
"cubrid://dba@localhost:33000/testdb",
# Pool size: number of persistent connections to keep
pool_size=5, # Default: 5
# Overflow: additional connections allowed beyond pool_size
max_overflow=10, # Default: 10
# Timeout: seconds to wait for a connection from the pool
pool_timeout=30, # Default: 30
# Recycle: seconds before a connection is replaced
# Set this LOWER than CUBRID broker's SESSION_TIMEOUT
pool_recycle=1800, # Recommended: 1800 (30 minutes)
# Pre-ping: test connection liveness before checkout
pool_pre_ping=True, # Recommended: True for production
)
pool_pre_ping (Recommended)¶
When pool_pre_ping=True, SQLAlchemy calls do_ping() on each connection before handing it to your application. The CUBRIDdb dialect uses the native connection.ping() method from the CUBRID Python driver. The pycubrid dialect executes SELECT 1 since pycubrid has no native ping() method. Both approaches prevent "stale connection" errors.
This prevents "stale connection" errors that occur when:
- The CUBRID broker restarts
- Network interruptions occur
- The broker's SESSION_TIMEOUT expires
# Production-recommended configuration
engine = create_engine(
"cubrid://dba@localhost:33000/mydb",
pool_pre_ping=True,
pool_recycle=1800,
)
pool_recycle and CUBRID Broker Timeout¶
CUBRID's broker has a SESSION_TIMEOUT setting (default varies by version, typically 300 seconds). If a pooled connection sits idle longer than this timeout, the broker will close it server-side.
Always set pool_recycle lower than SESSION_TIMEOUT to avoid stale connections:
# If CUBRID broker SESSION_TIMEOUT is 300 (5 minutes)
engine = create_engine(
"cubrid://dba@localhost:33000/mydb",
pool_recycle=240, # Recycle before broker timeout
)
Disconnect Detection¶
The dialect implements is_disconnect() which detects connection failures by:
- Message matching — checks error messages for known disconnect patterns (e.g., "connection is closed", "broker is not available", "connection reset")
- Error code matching — checks for CUBRID CCI error codes like
CAS_ER_COMMUNICATION(-21003)
When a disconnect is detected, SQLAlchemy automatically invalidates the connection and creates a new one from the pool.
Error Code Mapping¶
CUBRID driver exceptions are mapped to appropriate SQLAlchemy exception types. The driver exposes a limited exception hierarchy:
| CUBRID Driver Exception | SA Exception Mapping |
|---|---|
Error (base) |
DBAPIError |
InterfaceError |
InterfaceError |
DatabaseError |
DatabaseError |
NotSupportedError |
NotSupportedError |
Note: CUBRIDdb does not provide
OperationalError,ProgrammingError,InternalError, orDataError. All database-level errors are raised asDatabaseError.
Pool Configuration Recommendations¶
| Scenario | pool_size |
pool_recycle |
pool_pre_ping |
|---|---|---|---|
| Development | 2 | -1 (disabled) | False |
| Web application | 5–10 | 1800 | True |
| High-concurrency | 10–20 | 900 | True |
| Background workers | 2–5 | 600 | True |
NullPool for Short-Lived Scripts¶
For scripts or one-off tasks, disable pooling entirely:
from sqlalchemy.pool import NullPool
engine = create_engine(
"cubrid://dba@localhost:33000/testdb",
poolclass=NullPool,
)
Connection URL Parsing Flow¶
flowchart TD
input[SQLAlchemy URL string] --> parse[SQLAlchemy URL parser]
parse --> check{Driver name}
check -->|cubrid or cubrid+cubrid| cext[Build CUBRID native DSN]
check -->|cubrid+pycubrid| pykw[Build pycubrid kwargs]
cext --> connect1[CUBRIDdb.connect(url, user, password)]
pykw --> connect2[pycubrid.connect(host, port, database, user, password)]
connect1 --> session[Dialect on_connect sets autocommit=False]
connect2 --> session
Use the correct dialect prefix
pycubrid://... is not a valid SQLAlchemy URL scheme.
Always use cubrid+pycubrid://....
Do not pass broker port as query string
Use ...@host:33000/dbname, not ...?port=33000.
Prefer pool_pre_ping=True in production
This prevents stale connection failures after broker restarts or idle timeout expiration.
See also: Isolation Levels · Type Mapping · Feature Support