Skip to main content

pycubrid icon (CUBRID Lab brand repository)

pycubrid

Pure Python DB-API 2.0 driver for the CUBRID database — no C extensions, no compilation, implements the PEP 249 (DB-API 2.0) interface.

🇰🇷 한국어 · 🇺🇸 English · 🇨🇳 中文 · 🇮🇳 हिन्दी · 🇩🇪 Deutsch · 🇷🇺 Русский

PyPI version python version ci workflow integration-full workflow coverage license GitHub stars docs


Status: Stable (1.x). The public API follows semantic versioning; names first released in 1.9.0 or later in the opt-in pycubrid.compat namespaces are provisional. See RELEASE_POLICY.md for the full contract.

Start here

pycubrid lets a Python program talk to a CUBRID database. CUBRID itself is a separate database server that must already be running; installing pycubrid does not install CUBRID or create a database. New to CUBRID? Follow Your First CUBRID Connection: it shows what to prepare when you already have a database, how to start a disposable local one with Docker, and walks you to a first query and a first saved row.

Requirements

  • Python 3.11 or later
  • CUBRID database server 10.2+ (CI validates 10.2, 11.0, 11.2, 11.4)

Installation

pip install pycubrid

Your first query

With a database to connect to, save this as first_query.py and run python first_query.py:

import pycubrid

conn = pycubrid.connect(host="localhost", port=33000, database="testdb", user="dba", password="")
cur = conn.cursor()
cur.execute("SELECT 1 + 1")
print(cur.fetchone())  # (2,)
cur.close()
conn.close()

The connection values are those of the local Docker lab; use your own for any other database. If the connection fails, see If the first connection fails.

pycubrid in action

Usage

Task-oriented examples, once your first connection works.

Quick Start

Basic Connection

import pycubrid

conn = pycubrid.connect(
    host="localhost",
    port=33000,
    database="testdb",
    user="dba",
    password="",
)

cur = conn.cursor()
cur.execute("SELECT 1 + 1")
print(cur.fetchone())  # (2,)

cur.close()
conn.close()

Context Manager

import pycubrid

with pycubrid.connect(host="localhost", port=33000, database="testdb", user="dba") as conn:
    with conn.cursor() as cur:
        cur.execute("CREATE TABLE IF NOT EXISTS users (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100))")
        cur.execute("INSERT INTO users (name) VALUES (?)", ("Alice",))
        conn.commit()

        cur.execute("SELECT * FROM users")
        for row in cur:
            print(row)

Async

import asyncio
import pycubrid.aio

async def main():
    conn = await pycubrid.aio.connect(
        host="localhost", port=33000, database="testdb", user="dba"
    )
    cur = conn.cursor()
    await cur.execute("SELECT 1 + 1")
    print(await cur.fetchone())  # (2,)
    await cur.close()
    await conn.close()

asyncio.run(main())

Practical Examples

Run the setup, the three examples and cleanup in order in the same Python session against a scratch database. Adjust the connection settings for your server. The dedicated table must not already exist: setup deliberately fails rather than reusing or deleting an existing table. Manual commit mode and the initial DDL commit keep rollback focused on the DML below.

Setup
import pycubrid

conn = pycubrid.connect(host="localhost", port=33000, database="testdb", user="dba")
conn.autocommit = False
cur = conn.cursor()
cur.execute("CREATE TABLE pycubrid_quickstart_327 (id INT PRIMARY KEY, name VARCHAR(100))")
conn.commit()
Basic CRUD
cur.execute("INSERT INTO pycubrid_quickstart_327 (id, name) VALUES (?, ?)", (1, "Alice"))
cur.execute("SELECT name FROM pycubrid_quickstart_327 WHERE id = ?", (1,))
print(cur.fetchone())  # ('Alice',)
cur.execute("UPDATE pycubrid_quickstart_327 SET name = ? WHERE id = ?", ("Alicia", 1))
cur.execute("SELECT name FROM pycubrid_quickstart_327 WHERE id = ?", (1,))
print(cur.fetchone())  # ('Alicia',)
cur.execute("DELETE FROM pycubrid_quickstart_327 WHERE id = ?", (1,))
conn.commit()
Transactions: commit and rollback
cur.execute("INSERT INTO pycubrid_quickstart_327 (id, name) VALUES (?, ?)", (2, "Bob"))
conn.commit()
cur.execute("UPDATE pycubrid_quickstart_327 SET name = ? WHERE id = ?", ("Temporary", 2))
conn.rollback()
cur.execute("SELECT name FROM pycubrid_quickstart_327 WHERE id = ?", (2,))
print(cur.fetchone())  # ('Bob',)
conn.rollback()
Error handling
from pycubrid.exceptions import ProgrammingError

try:
    cur.execute("SELECT missing_column FROM pycubrid_quickstart_327 WHERE id = ?", (2,))
except ProgrammingError as exc:
    conn.rollback()
    print(f"Query failed: {exc}")
Cleanup

After setup succeeds, run this cleanup even if an example fails; it removes only the table created above. For more examples, see EXAMPLES.md.

conn.rollback()
cur.execute("DROP TABLE pycubrid_quickstart_327")
conn.commit()
cur.close()
conn.close()

SQLAlchemy Integration

pycubrid works as a driver for sqlalchemy-cubrid — the SQLAlchemy 2.0 dialect for CUBRID:

pip install "sqlalchemy-cubrid[pycubrid]"
from sqlalchemy import create_engine, text

engine = create_engine("cubrid+pycubrid://dba@localhost:33000/testdb")

with engine.connect() as conn:
    result = conn.execute(text("SELECT 1"))
    print(result.scalar())

SQLAlchemy features (ORM, Core, Alembic migrations, schema reflection) are accessible through the pycubrid driver when used with sqlalchemy-cubrid.

Reference

What pycubrid implements and supports, in detail.

Why pycubrid?

CUBRID is a high-performance open-source relational database, widely adopted in Korean public-sector and enterprise applications. The existing C-extension driver (CUBRIDdb) had build dependencies and platform compatibility issues.

pycubrid solves these problems:

  • Pure Python implementation — no C build dependencies, install with pip install only
  • Implements PEP 249 (DB-API 2.0) — standard exception hierarchy, type objects, cursor interface
  • Offline regression suite with a 95% coverage floor on full coverage runs — see measured coverage and the CI execution policy; routine PR smoke does not measure coverage
  • TLS/SSL for sync and async connections — opt-in ssl=True (verified context, TLS 1.2 minimum) or custom ssl.SSLContext on connect() and pycubrid.aio.connect().
  • Native asyncio support — async/await API via pycubrid.aio for high-concurrency applications
  • PEP 561 typed package — py.typed marker for modern IDE and static analysis support
  • Direct CUBRID CAS protocol implementation — no additional middleware required
  • LOB (CLOB/BLOB) support — handle large text and binary data

PEP 249 Compliance

Attribute Value
apilevel "2.0"
threadsafety 1 (connections cannot be shared between threads)
paramstyle "qmark" (positional parameters ?)
  • Full standard exception hierarchy: Warning, Error, InterfaceError, DatabaseError, DataError, OperationalError, IntegrityError, InternalError, ProgrammingError, NotSupportedError — also exposed as attributes on Connection/AsyncConnection (PEP 249 optional extension), e.g. conn.IntegrityError is pycubrid.IntegrityError
  • Standard type objects: STRING, BINARY, NUMBER, DATETIME, ROWID
  • Standard constructors: Date(), Time(), Timestamp(), Binary(), DateFromTicks(), TimeFromTicks(), TimestampFromTicks()
  • nextset() raises NotSupportedError (CUBRID does not support multiple result sets)

Features

  • Pure Python — no C extensions, no compilation, works everywhere Python runs
  • Complete DB-API 2.0 — connect(), Cursor, fetchone/many/all, executemany, callproc
  • Parameterized queries — cursor.execute(sql, params) with driver-side parameter binding (? placeholders escaped and interpolated locally)
  • Batch operations — executemany() and executemany_batch() for bulk inserts
  • LOB support — create_lob(), read/write CLOB and BLOB columns
  • Owned schema introspection — get_schema_info() plus eager fetch_schema_info() or explicit close_schema_info(); the #457 live matrix verifies CLASS/VCLASS/ATTRIBUTE/CONSTRAINT/PRIMARY_KEY/IMPORTED_KEYS/EXPORTED_KEYS on CUBRID 10.2/11.4, not all schema codes or native-driver parity
  • Auto-commit control — connection.autocommit property for transaction management
  • Server version detection — connection.get_server_version() returns version string (e.g., "11.2.0.0378")
  • Iterator protocol — iterate over cursor results with for row in cursor
  • Context managers — with statements for both connections and cursors
  • Async support — pycubrid.aio.connect() with AsyncConnection and AsyncCursor for asyncio event loops
  • Per-cursor fetch size — cursor.fetch_size property to tune server-side fetch batch size per cursor

Supported CUBRID Versions

The project targets CUBRID 10.2+ (protocol-compatible). CI validates against:

  • 10.2
  • 11.0
  • 11.2
  • 11.4

Compatibility

Python 3.10 support retirement: Python 3.10 reached upstream end of life on 2026-10-01 (PEP 619). The 1.8.x and 1.9.x lines support Python 3.10; 1.9.0 carried the advance notice. From 1.10.0 the package requires Python 3.11 or newer, so pip on Python 3.10 keeps installing 1.9.x. Upgrade your interpreter, recreate your virtual environment and validate your application before upgrading.

Supported: Python 3.11–3.15 and CUBRID 10.2, 11.0, 11.2, 11.4. Ordinary PRs use one Ubuntu/Python 3.12 offline smoke lane; high-risk changes add Python 3.14/CUBRID 11.4. Main/changed-weekly validation also runs Python 3.11/CUBRID 10.2 live and the full offline suite on Python 3.11 and 3.15. The full 5 × 4 live matrix runs on explicit dispatch and every release. See CI execution policy and support matrix.

Documentation

Guide Description
Your First CUBRID Connection Start here: prepare a database, first query, first saved row, first-connection problems
Connection Connection strings, URL format, configuration
Type Mapping Full type mapping, CUBRID-specific types, collection types
Parameter Binding Driver-side literal-binding contract: per-type SQL mapping, escaping rules, non-guarantees
API Reference Complete API documentation — modules, classes, functions
Protocol CAS wire protocol reference
CAS Concepts Advanced: Broker, CAS process, CAS wire protocol and CCI, and how DB-API calls map to them
Development Dev setup, testing, Docker, coverage, CI/CD
Examples Practical usage examples with code
Troubleshooting Connection errors, query problems, LOB handling, debugging

Architecture

graph TD
    app[Application]
    pycubrid[pycubrid Connection/Cursor]
    cas[CAS Protocol]
    server[CUBRID Server]

    app --> pycubrid
    pycubrid --> cas
    cas --> server
graph TD
    root[pycubrid/]
    init["__init__.py - Public API connect(), types, exceptions, __version__"]
    connection[connection.py - Connection class connect/commit/rollback/cursor/LOB]
    cursor[cursor.py - Cursor class execute/fetch/executemany/callproc/iterator]
    types[types.py - DB-API 2.0 type objects and constructors]
    exceptions[exceptions.py - PEP 249 exception hierarchy]
    constants[constants.py - CAS function codes, data types, protocol constants]
    protocol["protocol.py - CAS wire protocol packet classes (20 packet types)"]
    packet[packet.py - Low-level packet reader/writer]
    lob[lob.py - LOB support]
    typed[py.typed - PEP 561 marker]

    root --> init
    root --> connection
    root --> cursor
    root --> types
    root --> exceptions
    root --> constants
    root --> protocol
    root --> packet
    root --> lob
    root --> typed
    root --> aio
    aio["aio/ - AsyncConnection, AsyncCursor, async connect()"]

FAQ

How do I connect to CUBRID with Python?

import pycubrid
conn = pycubrid.connect(host="localhost", port=33000, database="testdb", user="dba")

How do I install pycubrid?

pip install pycubrid — no C extensions or build tools required.

What parameter style does pycubrid use?

Question mark (qmark) style: cursor.execute("SELECT * FROM users WHERE id = ?", (1,))

Parameters are bound driver-side — pycubrid escapes and interpolates values into the SQL string locally before sending the final query to the server. This is not server-side prepared statement binding, except for the opt-in executemany(..., prepared=True), which sends typed values with one PREPARE and one EXECUTE_ARRAY request (see docs/API_REFERENCE.md). The escaping logic is type-aware (strings, bytes, dates, decimals, None → NULL) and safe against SQL injection when used correctly via ? placeholders. Never use f-strings or % formatting to inject untrusted parameter values into SQL — always pass them through ? placeholders. Using f-strings to assemble the SQL structure itself from trusted inputs (for example, expanding an IN-clause with ','.join('?' * len(ids))) is fine. See docs/PARAMETER_BINDING.md for the full 1.x contract — per-type mapping, escaping modes, and explicit non-guarantees.

Does pycubrid work with SQLAlchemy?

Yes. Install pip install "sqlalchemy-cubrid[pycubrid]" and use the connection URL cubrid+pycubrid://dba@localhost:33000/testdb.

What Python versions are supported?

Python 3.11, 3.12, 3.13, 3.14, and 3.15 (standard GIL builds).

Does pycubrid support LOBs (CLOB/BLOB)?

Yes. Insert strings/bytes directly into CLOB/BLOB columns. For reading, LOB columns return data that can be accessed through the cursor.

Is pycubrid thread-safe?

pycubrid has threadsafety = 1, meaning connections cannot be shared between threads. Create a separate connection per thread.

What CUBRID versions are supported?

CUBRID 10.2, 11.0, 11.2, and 11.4 are tested in CI.

Does pycubrid support async/await?

Yes. Use pycubrid.aio.connect() for native asyncio support. The async surface is similar to the sync API: await conn.ping(reconnect=...) performs the same native CHECK_CAS health check as sync Connection.ping(), create_lob() remains sync-only, and auto-commit changes use await conn.set_autocommit(...) instead of a property setter.

Development

Contributing

See CONTRIBUTING.md for guidelines and docs/DEVELOPMENT.md for development setup.

First contribution

New to CUBRID? Pick the repository that matches what you want to work on:

Most first issues can be developed and tested with the offline checks in CONTRIBUTING.md — no Docker or CUBRID server needed. Live CUBRID verification can be completed by CI and maintainers.

Browse open good first issue tasks.

Roadmap

See ROADMAP.md for this project's direction and next milestones.

For the ecosystem-wide view, see the CUBRID Labs Ecosystem Roadmap.

Security

Report vulnerabilities privately through GitHub's private vulnerability reporting (email is the fallback) — see SECURITY.md. Do not open public issues for security concerns.

Acknowledgments

During pycubrid's initial development, the official CUBRID Node.js driver — node-cubrid (© 2008–2012 Search Solution Corporation, BSD-3-Clause) — was consulted as a reference implementation to understand CUBRID's CAS (Common Application Server) wire protocol: its packet structure and function codes. pycubrid is an independent pure-Python implementation; see NOTICE for details.

We also thank the maintainers and contributors of CUBRID/cubrid-python. Its tests3 suite informed the SQL-feature and type/data regression scenarios added in #409, #410 and #433: INDEX, PARTITION, VIEW, TRIGGER, collections, ENUM and LOB round-trips. These scenarios were adapted to pycubrid's APIs and documented differences, not a claim of full CUBRIDdb API parity. See NOTICE for the source files and third-party notes for provenance and licensing limits.

Disclaimer

This project is part of CUBRID Lab, an independent open-source initiative for CUBRID developer tooling, and is not affiliated with, sponsored by, or endorsed by CUBRID Corporation or the official CUBRID project.

License

MIT — see LICENSE.

Metadata

Release files for pycubrid 1.13.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pycubrid 1.13.4
File Size Uploaded Provenance
pycubrid-1.13.4.tar.gz 789.7 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for pycubrid 1.13.4
File Interpreter ABI Platform
pycubrid-1.13.4-py3-none-any.whl Python 3 none any Details

Total release size: 939.9 kB

Release files / pycubrid-1.13.4.tar.gz

Download URL pycubrid-1.13.4.tar.gz
Size 789.7 kB
Tags Source
SHA-256 checksum
How to use checksums
d34312d821159074a90b3067635a306a84e83e4ed89bfb398c68a4740c243a89
BLAKE2b-256 checksum
How to use checksums
4148367c30e303ecf8a4b54eb5b24d239a1cfe2505efe097489ad9fff0cb3a3c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Release files / pycubrid-1.13.4-py3-none-any.whl

Download URL pycubrid-1.13.4-py3-none-any.whl
Size 150.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
09d5f61be4c6f7a23f4fa3f2374238e9efcd73631cf0570ebd3fc55e9124d629
BLAKE2b-256 checksum
How to use checksums
3bf50a7f3e4541692b83cf73d40865b41436ce1fa757f9480326f9925557ccf8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Security for pycubrid 1.13.4

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for pycubrid-1.13.4.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page