Skip to content

Type System

Complete reference for pycubrid's PEP 249 type objects, constructors, and CUBRID CCI data type codes.


Table of Contents


Declared SQL Types vs Fetch/Description Types

This guide separates two different views of type information:

  • Declared SQL types are the column types you define in DDL and bind in SQL, such as VARCHAR, JSON, SET, BLOB, or TIMESTAMPTZ.
  • Fetch/description types are the CUBRIDDataType integer codes exposed through cursor.description[n][1] and the Python objects pycubrid returns after decoding wire data.

The PEP 249 type-object sections below group declared SQL types into the standard DB-API families. Later sections list the raw CUBRIDDataType codes and the exact Python values returned on fetch.


Overview

pycubrid implements the DB-API 2.0 (PEP 249) type system with:

  • 5 type objectsSTRING, BINARY, NUMBER, DATETIME, ROWID
  • 7 constructorsDate, Time, Timestamp, DateFromTicks, TimeFromTicks, TimestampFromTicks, Binary
  • 27+ CCI data type codes — mapping CUBRID wire types to Python types, including JSON and collection support

Type objects enable comparison with cursor.description type codes:

import pycubrid

conn = pycubrid.connect(host="localhost", port=33000, database="testdb")
cur = conn.cursor()
cur.execute("SELECT name, age, created_at FROM cookbook_users")

for col in cur.description:
    col_name = col[0]
    col_type = col[1]

    if col_type == pycubrid.STRING:
        print(f"{col_name} is a string column")
    elif col_type == pycubrid.NUMBER:
        print(f"{col_name} is a numeric column")
    elif col_type == pycubrid.DATETIME:
        print(f"{col_name} is a date/time column")

DBAPIType Class

The DBAPIType class implements the PEP 249 type comparison protocol. Each instance wraps a frozenset of integer type codes and compares equal to any code in that set.

from pycubrid.types import DBAPIType

# Create a custom type object
MY_TYPE = DBAPIType("MY_TYPE", frozenset({1, 2, 3}))

# Comparison with integer type codes
assert MY_TYPE == 1      # True — 1 is in the set
assert MY_TYPE == 4      # False — 4 is not in the set
assert MY_TYPE != 4      # True

# Comparison with other DBAPIType instances
OTHER = DBAPIType("OTHER", frozenset({1, 2, 3}))
assert MY_TYPE == OTHER  # True — same value sets

Methods

Method Description
__eq__(other) Returns True if other (int) is in values, or if other (DBAPIType) has the same values set
__ne__(other) Negation of __eq__
__hash__() Hash based on the frozen set of values
__repr__() Returns DBAPIType('name')

PEP 249 Type Objects

STRING

Describes string-based columns.

from pycubrid import STRING
Member Type CCI Code CUBRID SQL Type
CHAR 1 CHAR(n)
STRING (VARCHAR) 2 VARCHAR(n)
NCHAR 3 NCHAR(n)
VARNCHAR 4 NCHAR VARYING(n)
ENUM 25 ENUM
CLOB 24 CLOB
JSON 34 JSON

BINARY

Describes binary data columns.

from pycubrid import BINARY
Member Type CCI Code CUBRID SQL Type
BIT 5 BIT(n)
VARBIT 6 BIT VARYING(n)
BLOB 23 BLOB

NUMBER

Describes numeric columns.

from pycubrid import NUMBER
Member Type CCI Code CUBRID SQL Type Python Type
SHORT 9 SMALLINT int
INT 8 INTEGER int
BIGINT 21 BIGINT int
FLOAT 11 FLOAT float
DOUBLE 12 DOUBLE float
NUMERIC 7 NUMERIC(p, s) Decimal
MONETARY 10 MONETARY float

DATETIME

Describes date and time columns.

from pycubrid import DATETIME
Member Type CCI Code CUBRID SQL Type Python Type
DATE 13 DATE datetime.date
TIME 14 TIME datetime.time
TIMESTAMP 15 TIMESTAMP datetime.datetime
DATETIME 22 DATETIME datetime.datetime
TIMESTAMPTZ 29 TIMESTAMPTZ datetime.datetime
TIMESTAMPLTZ 30 TIMESTAMPLTZ datetime.datetime
DATETIMETZ 31 DATETIMETZ datetime.datetime
DATETIMELTZ 32 DATETIMELTZ datetime.datetime

ROWID

Describes row identifier columns.

from pycubrid import ROWID
Member Type CCI Code CUBRID SQL Type Python Type
OBJECT 19 OBJECT (OID) str ("OID:@page|slot|volume")

PEP 249 Constructors

These functions create Python objects suitable for use as query parameters.

Constructor Signature Returns Description
Date (year, month, day) datetime.date Calendar date
Time (hour, minute, second) datetime.time Time of day
Timestamp (year, month, day, hour, minute, second) datetime.datetime Date and time
DateFromTicks (ticks) datetime.date Date from Unix timestamp
TimeFromTicks (ticks) datetime.time Time from Unix timestamp
TimestampFromTicks (ticks) datetime.datetime Datetime from Unix timestamp
Binary (value) bytes Binary data from bytes, bytearray, or str (UTF-8)

Usage

import pycubrid

# Date/Time constructors
d = pycubrid.Date(2025, 3, 15)
t = pycubrid.Time(14, 30, 0)
ts = pycubrid.Timestamp(2025, 3, 15, 14, 30, 0)

# From Unix timestamps
d2 = pycubrid.DateFromTicks(1710500000.0)
t2 = pycubrid.TimeFromTicks(1710500000.0)
ts2 = pycubrid.TimestampFromTicks(1710500000.0)

# Binary constructor
b1 = pycubrid.Binary(b"\x00\x01\x02")           # from bytes
b2 = pycubrid.Binary(bytearray([0, 1, 2]))      # from bytearray
b3 = pycubrid.Binary("hello")                    # from str → UTF-8 encoded bytes

CUBRID CCI_U_TYPE Codes

These integer codes are used on the CAS wire protocol and appear in cursor.description[n][1].

Constant Code CUBRID Type Category
UNKNOWN / NULL 0 NULL
CHAR 1 CHAR(n) STRING
STRING 2 VARCHAR(n) STRING
NCHAR 3 NCHAR(n) STRING
VARNCHAR 4 NCHAR VARYING(n) STRING
BIT 5 BIT(n) BINARY
VARBIT 6 BIT VARYING(n) BINARY
NUMERIC 7 NUMERIC(p, s) NUMBER
INT 8 INTEGER NUMBER
SHORT 9 SMALLINT NUMBER
MONETARY 10 MONETARY NUMBER
FLOAT 11 FLOAT NUMBER
DOUBLE 12 DOUBLE NUMBER
DATE 13 DATE DATETIME
TIME 14 TIME DATETIME
TIMESTAMP 15 TIMESTAMP DATETIME
SET 16 SET Collection
MULTISET 17 MULTISET Collection
SEQUENCE 18 SEQUENCE / LIST Collection
OBJECT 19 OBJECT (OID) ROWID
RESULTSET 20 Result set
BIGINT 21 BIGINT NUMBER
DATETIME 22 DATETIME DATETIME
BLOB 23 BLOB BINARY
CLOB 24 CLOB STRING
ENUM 25 ENUM STRING
JSON 34 JSON STRING
TIMESTAMPTZ 29 TIMESTAMPTZ DATETIME
TIMESTAMPLTZ 30 TIMESTAMPLTZ DATETIME
DATETIMETZ 31 DATETIMETZ DATETIME
DATETIMELTZ 32 DATETIMELTZ DATETIME

These codes are available as the CUBRIDDataType enum:

from pycubrid.constants import CUBRIDDataType

print(CUBRIDDataType.INT)       # CUBRIDDataType.INT (8)
print(CUBRIDDataType.VARCHAR)   # AttributeError — use CUBRIDDataType.STRING (2)

Fetch Conversion Table

How pycubrid converts CUBRID wire types to Python objects when fetching results:

CUBRID Type CCI Code Python Type Notes
CHAR, VARCHAR, NCHAR, NCHAR VARYING, ENUM 1–4, 25 str Null-terminated, UTF-8 decoded
SHORT (SMALLINT) 9 int 16-bit signed
INTEGER 8 int 32-bit signed
BIGINT 21 int 64-bit signed
FLOAT 11 float IEEE 754 single
DOUBLE, MONETARY 12, 10 float IEEE 754 double
NUMERIC / DECIMAL 7 Decimal Exact numeric (string-parsed)
DATE 13 datetime.date Calendar date
TIME 14 datetime.time Time of day
TIMESTAMP 15 datetime.datetime Date + time (microsecond = 0)
DATETIME 22 datetime.datetime Date + time + millisecond
TIMESTAMPTZ, TIMESTAMPLTZ 29, 30 datetime.datetime Timezone-aware timestamps
DATETIMETZ, DATETIMELTZ 31, 32 datetime.datetime Timezone-aware datetimes
BIT, BIT VARYING 5, 6 bytes Raw binary data
JSON 34 str or Any Raw JSON string by default; decoded when json_deserializer= is set
SET, MULTISET, SEQUENCE 16, 17, 18 bytes or decoded collection Decoded only when decode_collections=True
OBJECT (OID) 19 str Format: "OID:@page\|slot\|volume"
BLOB 23 dict LOB handle (see below)
CLOB 24 dict LOB handle (see below)
NULL / UNKNOWN 0 None

LOB Type Handling

LOB columns (BLOB and CLOB) are not returned as content. Instead, they return a handle dictionary that can be used with the Lob class to read the actual data.

LOB Handle Structure

When you fetch a BLOB or CLOB column, you receive:

{
    "lob_type": 23,                    # CUBRIDDataType.BLOB (23) or CLOB (24)
    "lob_length": 1024,                # Size of the LOB content in bytes
    "file_locator": "file://.../...",   # Server-side file locator
    "packed_lob_handle": b"...",        # Raw handle bytes for Lob.read()
}

Reading LOB Content

from pycubrid.lob import Lob
from pycubrid.constants import CUBRIDDataType

conn = pycubrid.connect(host="localhost", port=33000, database="testdb")
cur = conn.cursor()

# Insert string data directly into CLOB column
cur.execute("INSERT INTO cookbook_docs (content) VALUES ('Hello, CLOB!')")
conn.commit()

# Fetch returns a LOB handle dict, not the content
cur.execute("SELECT content FROM cookbook_docs WHERE id = 1")
row = cur.fetchone()
lob_handle = row[0]  # dict with lob_type, lob_length, etc.

# To read content, use Lob class with the packed handle
lob = Lob(conn, CUBRIDDataType.CLOB, lob_handle["packed_lob_handle"])
content = lob.read(lob_handle["lob_length"])
print(content)  # b'Hello, CLOB!'

Important: You cannot pass Lob objects as query parameters. Insert strings directly into CLOB columns and bytes directly into BLOB columns.


Collection Types

CUBRID's collection types (SET, MULTISET, SEQUENCE) default to raw bytes for backward compatibility. When decode_collections=True is passed to connect() or pycubrid.aio.connect(), pycubrid decodes supported collection payloads into Python containers.

CUBRID Type CCI Code decode_collections=False decode_collections=True
SET 16 bytes frozenset when hashable, otherwise tuple
MULTISET 17 bytes list
SEQUENCE 18 bytes list

Notes:

  • Nested collection payloads remain raw bytes.
  • Unknown collection element types fall back to raw bytes.
  • SET values are normalized to a frozenset when every decoded element is hashable. If a set contains unhashable elements (for example decoded JSON objects), pycubrid returns a tuple to preserve the contents without raising.

JSON Columns

JSON columns use CUBRID type code 34.

Connection option Fetch result
default (json_deserializer=None) raw JSON str
json_deserializer=json.loads decoded Python object
json_deserializer=custom_callable return value of the callable

This opt-in behavior keeps fetches allocation-light when applications prefer to defer JSON parsing.

decode_collections

decode_collections is a connection-level switch on both pycubrid.connect() and pycubrid.aio.connect().

Setting Result
False (default) Return collection payloads as raw CAS wire bytes
True Decode supported SET, MULTISET, and SEQUENCE payloads into Python containers

Usage Examples

Type Checking with cursor.description

import pycubrid

conn = pycubrid.connect(host="localhost", port=33000, database="testdb")
cur = conn.cursor()
cur.execute("SELECT * FROM cookbook_users LIMIT 1")

for col in cur.description:
    name, type_code, _, _, precision, scale, nullable = col
    if type_code == pycubrid.STRING:
        print(f"  {name}: STRING (precision={precision})")
    elif type_code == pycubrid.NUMBER:
        print(f"  {name}: NUMBER (precision={precision}, scale={scale})")
    elif type_code == pycubrid.DATETIME:
        print(f"  {name}: DATETIME")
    elif type_code == pycubrid.BINARY:
        print(f"  {name}: BINARY")
    elif type_code == pycubrid.ROWID:
        print(f"  {name}: ROWID (OID)")
    else:
        print(f"  {name}: type_code={type_code}")

cur.close()
conn.close()

Parameter Binding with Constructors

import pycubrid

conn = pycubrid.connect(host="localhost", port=33000, database="testdb")
cur = conn.cursor()

# Use PEP 249 constructors for parameter values
cur.execute(
    "INSERT INTO cookbook_events (event_date, event_time, created_at) VALUES (?, ?, ?)",
    [
        pycubrid.Date(2025, 12, 25),
        pycubrid.Time(10, 0, 0),
        pycubrid.Timestamp(2025, 3, 15, 14, 30, 0),
    ],
)
conn.commit()
cur.close()
conn.close()

Using CUBRIDDataType Enum

from pycubrid.constants import CUBRIDDataType

# Check specific type codes
assert CUBRIDDataType.INT == 8
assert CUBRIDDataType.STRING == 2
assert CUBRIDDataType.DATETIME == 22

# Use in type switch logic
def describe_type(code: int) -> str:
    match code:
        case CUBRIDDataType.INT | CUBRIDDataType.BIGINT | CUBRIDDataType.SHORT:
            return "integer"
        case CUBRIDDataType.FLOAT | CUBRIDDataType.DOUBLE:
            return "floating point"
        case CUBRIDDataType.NUMERIC:
            return "exact decimal"
        case CUBRIDDataType.STRING | CUBRIDDataType.CHAR:
            return "text"
        case _:
            return f"other ({code})"

See also: API Reference · Examples · Connection Guide