타입 시스템 (한국어)¶
🌐 TYPES.md의 번역입니다. 영어 원문이 표준이며, CI가 영어 원문과의 구조 일치를 검사합니다.
pycubrid의 PEP 249 타입 객체·생성자·CUBRID CCI 데이터 타입 코드의 완전한 참조.
목차¶
- 개요
- 선언 SQL 타입 vs Fetch/Description 타입
- DBAPIType 클래스
- PEP 249 타입 객체
- STRING
- BINARY
- NUMBER
- DATETIME
- ROWID
- PEP 249 생성자
- CUBRID CCI_U_TYPE 코드
- Fetch 변환 표
- LOB 타입 처리
- 컬렉션 타입
- JSON 컬럼
decode_collections- 컬렉션 바인딩
- 사용 예제
선언 SQL 타입 vs Fetch/Description 타입¶
이 가이드는 타입 정보의 두 가지 관점을 구분합니다:
- 선언 SQL 타입은 DDL에서 정의하고 SQL에서 바인딩하는 컬럼 타입입니다 —
VARCHAR,JSON,SET,BLOB,TIMESTAMPTZ등. - Fetch/description 타입은
cursor.description[n][1]로 노출되는CUBRIDDataType정수 코드와, pycubrid가 와이어 데이터를 디코딩한 후 반환하는 Python 객체입니다.
아래 PEP 249 타입 객체 섹션은 선언 SQL 타입을 표준 DB-API 패밀리로 묶습니다. 이후 섹션은 raw CUBRIDDataType 코드와 fetch 시 반환되는 정확한 Python 값을 나열합니다.
개요¶
pycubrid는 DB-API 2.0 (PEP 249) 타입 시스템을 다음으로 구현합니다:
- 타입 객체 5종 —
STRING,BINARY,NUMBER,DATETIME,ROWID - 생성자 7종 —
Date,Time,Timestamp,DateFromTicks,TimeFromTicks,TimestampFromTicks,Binary - CCI 데이터 타입 코드 27+종 — CUBRID 와이어 타입을 Python 타입으로 매핑 (JSON·컬렉션 지원 포함)
타입 객체는 cursor.description의 타입 코드와 비교할 수 있습니다:
import pycubrid
conn = pycubrid.connect(host="localhost", port=33000, database="testdb")
cur = conn.cursor()
cur.execute("SELECT name, age, created_at FROM 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 클래스¶
DBAPIType 클래스는 PEP 249 타입 비교 프로토콜을 구현합니다. 각 인스턴스는 정수 타입 코드의 frozenset을 감싸며, 그 집합의 모든 코드와 같음 비교됩니다.
from pycubrid.types import DBAPIType
# 커스텀 타입 객체 생성
MY_TYPE = DBAPIType("MY_TYPE", frozenset({1, 2, 3}))
# 정수 타입 코드와 비교
assert MY_TYPE == 1 # True — 1은 집합에 있음
assert MY_TYPE == 4 # False — 4는 집합에 없음
assert MY_TYPE != 4 # True
# 다른 DBAPIType 인스턴스와 비교
OTHER = DBAPIType("OTHER", frozenset({1, 2, 3}))
assert MY_TYPE == OTHER # True — 같은 값 집합
메서드¶
| 메서드 | 설명 |
|---|---|
__eq__(other) |
other(int)가 values에 있거나, other(DBAPIType)가 같은 values 집합을 가지면 True |
__ne__(other) |
__eq__의 부정 |
__hash__() |
값의 frozen 집합 기반 해시 |
__repr__() |
DBAPIType('name') 반환 |
PEP 249 타입 객체¶
STRING¶
문자열 기반 컬럼을 기술합니다.
| 멤버 타입 | CCI 코드 | CUBRID SQL 타입 |
|---|---|---|
| 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¶
바이너리 데이터 컬럼을 기술합니다.
| 멤버 타입 | CCI 코드 | CUBRID SQL 타입 |
|---|---|---|
| BIT | 5 | BIT(n) |
| VARBIT | 6 | BIT VARYING(n) |
| BLOB | 23 | BLOB |
NUMBER¶
숫자 컬럼을 기술합니다.
| 멤버 타입 | CCI 코드 | CUBRID SQL 타입 | Python 타입 |
|---|---|---|---|
| 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¶
날짜와 시간 컬럼을 기술합니다.
| 멤버 타입 | CCI 코드 | CUBRID SQL 타입 | Python 타입 |
|---|---|---|---|
| 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¶
행 식별자 컬럼을 기술합니다.
| 멤버 타입 | CCI 코드 | CUBRID SQL 타입 | Python 타입 |
|---|---|---|---|
| OBJECT | 19 | OBJECT (OID) |
str ("OID:@page\|slot\|volume") |
PEP 249 생성자¶
이 함수들은 쿼리 파라미터로 사용할 수 있는 Python 객체를 만듭니다.
| 생성자 | 시그니처 | 반환 | 설명 |
|---|---|---|---|
Date |
(year, month, day) |
datetime.date |
달력 날짜 |
Time |
(hour, minute, second) |
datetime.time |
시각 |
Timestamp |
(year, month, day, hour, minute, second) |
datetime.datetime |
날짜와 시간 |
DateFromTicks |
(ticks) |
datetime.date |
Unix 타임스탬프로부터 날짜 |
TimeFromTicks |
(ticks) |
datetime.time |
Unix 타임스탬프로부터 시각 |
TimestampFromTicks |
(ticks) |
datetime.datetime |
Unix 타임스탬프로부터 datetime |
Binary |
(value) |
bytes |
bytes, bytearray, 또는 str(UTF-8)로부터 바이너리 데이터 |
사용¶
import pycubrid
# 날짜/시간 생성자
d = pycubrid.Date(2025, 3, 15)
t = pycubrid.Time(14, 30, 0)
ts = pycubrid.Timestamp(2025, 3, 15, 14, 30, 0)
# Unix 타임스탬프로부터
d2 = pycubrid.DateFromTicks(1710500000.0)
t2 = pycubrid.TimeFromTicks(1710500000.0)
ts2 = pycubrid.TimestampFromTicks(1710500000.0)
# 바이너리 생성자
b1 = pycubrid.Binary(b"\x00\x01\x02") # bytes로부터
b2 = pycubrid.Binary(bytearray([0, 1, 2])) # bytearray로부터
b3 = pycubrid.Binary("hello") # str로부터 → UTF-8 인코딩된 bytes
CUBRID CCI_U_TYPE 코드¶
이 정수 코드들은 CAS 와이어 프로토콜에서 사용되며 cursor.description[n][1]에 나타납니다.
CUBRIDDataType.NULL은 CUBRIDDataType.UNKNOWN의 별칭입니다(둘 다 0).
CUBRIDDataType.NULL is CUBRIDDataType.UNKNOWN이 참이고
CUBRIDDataType(0).name은 "UNKNOWN"입니다.
| 상수 | 코드 | CUBRID 타입 | 분류 |
|---|---|---|---|
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 |
컬렉션 |
MULTISET |
17 | MULTISET |
컬렉션 |
SEQUENCE |
18 | SEQUENCE / LIST |
컬렉션 |
OBJECT |
19 | OBJECT (OID) |
ROWID |
RESULTSET |
20 | 결과 집합 | — |
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 |
이 코드들은 CUBRIDDataType enum으로 사용할 수 있습니다:
from pycubrid.constants import CUBRIDDataType
print(CUBRIDDataType.INT) # CUBRIDDataType.INT (8)
print(CUBRIDDataType.VARCHAR) # AttributeError — CUBRIDDataType.STRING (2)을 사용하세요
Fetch 변환 표¶
fetch 시 pycubrid가 CUBRID 와이어 타입을 Python 객체로 변환하는 방식:
| CUBRID 타입 | CCI 코드 | Python 타입 | 비고 |
|---|---|---|---|
CHAR, VARCHAR, NCHAR, NCHAR VARYING, ENUM |
1–4, 25 | str |
Null 종단, 연결 charset(기본 UTF-8)으로 디코딩; 디코딩할 수 없는 바이트는 코덱 이름을 담은 DataError 발생 (연결은 유지). EUC-KR 데이터베이스에서 CHAR(n)은 U+3000으로 채움 |
SHORT (SMALLINT) |
9 | int |
16비트 부호 있는 정수 |
INTEGER |
8 | int |
32비트 부호 있는 정수 |
BIGINT |
21 | int |
64비트 부호 있는 정수 |
FLOAT |
11 | float |
IEEE 754 단정밀도 |
DOUBLE, MONETARY |
12, 10 | float |
IEEE 754 배정밀도 |
NUMERIC / DECIMAL |
7 | Decimal |
정확한 숫자 (문자열 파싱) |
DATE |
13 | datetime.date |
달력 날짜 |
TIME |
14 | datetime.time |
시각 (초 정밀도; 바인딩한 datetime.time의 마이크로초와 tzinfo는 오류 없이 버려집니다. 파라미터 바인딩 참고) |
TIMESTAMP |
15 | datetime.datetime |
날짜 + 시간 (microsecond = 0) |
DATETIME |
22 | datetime.datetime |
날짜 + 시간 + 밀리초 |
TIMESTAMPTZ, TIMESTAMPLTZ |
29, 30 | datetime.datetime |
타임존 포함 타임스탬프 (초 정밀도, microsecond = 0) |
DATETIMETZ, DATETIMELTZ |
31, 32 | datetime.datetime |
타임존 포함 datetime (밀리초 정밀도) |
BIT, BIT VARYING |
5, 6 | bytes |
raw 바이너리 데이터. 빈 BIT/BIT VARYING 값(X'', B'')은 NULL과 구분되는 b"" (#994). JDBC 드라이버를 따른 동작이며, 공식 CUBRIDdb 드라이버는 X''에 None을 돌려줌 |
JSON |
34 | str 또는 Any |
기본은 raw JSON 문자열; json_deserializer= 설정 시 디코딩됨. 연결 charset과 무관하게 항상 UTF-8 |
SET, MULTISET, SEQUENCE |
16, 17, 18 | bytes 또는 디코딩된 컬렉션 |
decode_collections=True일 때만 디코딩 |
OBJECT (OID) |
19 | str |
형식: "OID:@page\|slot\|volume" |
BLOB |
23 | dict |
LOB 핸들 (아래 참고) |
CLOB |
24 | dict |
LOB 핸들 (아래 참고); Lob.read()는 charset으로 디코딩하지 않은 컬럼 문자셋의 바이트 반환 |
NULL / UNKNOWN |
0 | None |
— |
로컬 타임존 타입:
TIMESTAMPLTZ와DATETIMELTZ값은 값을 저장할 때의 타임존이 아니라 세션 타임존 기준의 aware datetime으로 반환됩니다. 세션 타임존은SET TIME ZONE '<zone>'으로 설정합니다. pycubrid 1.8.0부터 CAS 세션이 유지되는 동안에는commit()/rollback()이후에도 타임존이 유지됩니다. 트랜잭션 경계 후 CAS가 소켓을 닫으면(CAS 재시작, CHANGE CLIENT,cubrid broker reset) 드라이버가 재연결하고 새 세션은 서버 기본 타임존을 사용하므로, 다른 SQL 세션 상태와 마찬가지로SET TIME ZONE을 다시 적용해야 합니다(연결 가이드의 "트랜잭션 경계에서 CAS가 재활용되는 경우" 참고). 세션 타임존이 바뀌면 같은 저장 시점(instant)이 다른 UTC 오프셋으로 반환됩니다.TIMESTAMPTZ와DATETIMETZ는 값 자체의 타임존을 가집니다.반복되는 DST 시각(#819): 반복되는 벽시계 시각에 있는, 지역
tzinfo(ZoneInfo)를 가진 awaredatetime을 바인딩하면fold가 유지됩니다.fold=0값은 지역 이름만 있는 리터럴을 유지하며, CUBRID는 이를 첫 번째 발생으로 해석합니다.fold=1이면 pycubrid는 타임존 약어를 덧붙이고 (America/New_York EST), 약어가 숫자이거나 두 발생이 같은 약어를 쓰면 오프셋만 보냅니다. 따라서 두 번째 발생이 더 이상 첫 번째로 저장되지 않습니다. 건너뛴 봄철 시각은 CUBRID가 거부합니다. 파라미터 바인딩을 참고하세요.0 날짜 (#512): CUBRID는
DATE'0000-00-00',DATETIME'0000-00-00 00:00:00'및 0 값의TIMESTAMP,TIMESTAMPTZ,TIMESTAMPLTZ,DATETIMETZ,DATETIMELTZ를 허용하지만 Pythondatetime에는 0년이 없습니다. 이런 값을 가져오면execute()에서든 이후 fetch 페이지에서든 CUBRID 타입과 필드 값을 담은DataError가 발생합니다. 연결은 계속 사용할 수 있으며, 잘못된 UTF-8(#492)과 마찬가지로 커서는 서버 핸들을 유지합니다. 이후 페이지에서 발생한 경우 그 페이지 전에 가져온 행은 그대로 반환되고, 그 뒤의 fetch는 다음execute()전까지 같은DataError를 계속 발생시킵니다(#507). Python이 표현할 수 없는 다른 날짜/시간 필드 값도 같은 방식으로 보고됩니다.None이나 텍스트로 반환하는 옵션은 없으므로 SQL에서 변환하세요. 예:NULLIF(d, DATE'0000-00-00')(0 값은NULL),CASE WHEN d = DATE'0000-00-00' THEN NULL ELSE d END,TO_CHAR(d, 'YYYY-MM-DD')('0000-00-00'반환). 명시적 prepared API(pycubrid.compat.native)는 fail-closed로 동작하여OperationalError를 발생시키고 세션을 폐기합니다. 0 날짜 또는 날짜시간 값을 참고하세요.타임존 디코딩 (#413): CUBRID는 각 값의 타임존을 텍스트로 보냅니다. 오프셋 (
+05:30)이거나, 리전 이름과 그 시점의 약어(Asia/Seoul KST, LTZ 타입은UTC UTC)입니다. pycubrid는 다음과 같이 해석합니다.
- 오프셋은 고정
datetime.timezone으로 변환합니다.- 리전은
zoneinfo.ZoneInfo(region)으로 변환합니다. 서머타임이 끝나 같은 벽시계 시각이 두 번 나타나면 약어로fold를 고릅니다. 따라서 2026-11-01 01:30의America/New_York EST는 UTC-05:00(fold=1),EDT는 UTC-04:00입니다. 약어가 없거나 알 수 없는 경우, 또는 두 시점이 같은 약어를 쓰는 경우 (2014-10-26의Europe/Moscow MSK)에는fold=0을 유지합니다.- 빈 타임존은 naive
datetime으로 반환합니다.클라이언트의 타임존 데이터베이스가 모르는 리전이나, 형식이 잘못되었거나 ±24시간 범위를 벗어난 오프셋은 naive 값을 조용히 반환하지 않고, 해당 타임존을 담은
DataError를 발생시킵니다. 연결은 계속 사용할 수 있습니다. 명시적 prepared API(pycubrid.compat.native)는 잘못된 UTF-8(#492)과 마찬가지로 fail-closed로 동작하여OperationalError를 발생시키고 세션을 폐기합니다.zoneinfo는 시스템 데이터베이스 또는tzdata패키지를 읽습니다. Windows에서는 pycubrid가tzdata를 자동으로 설치하며, 최소 구성 Linux 이미지에서는tzdata를 (pip 또는 OS 패키지로) 설치하세요. TZ 값의 타임존을 해석할 수 없음을 참고하세요.
LOB 타입 처리¶
LOB 컬럼(BLOB과 CLOB)은 내용으로 반환되지 않습니다. 대신, Lob 클래스와 함께 실제 데이터를 읽을 수 있는 핸들 딕셔너리를 반환합니다.
LOB 핸들 구조¶
BLOB 또는 CLOB 컬럼을 fetch하면 다음을 받습니다:
{
"lob_type": 23, # CUBRIDDataType.BLOB (23) 또는 CLOB (24)
"lob_length": 1024, # LOB 내용의 바이트 크기
"file_locator": "file://.../...", # 서버 측 파일 로케이터
"packed_lob_handle": b"...", # Lob.read()용 raw 핸들 바이트
}
LOB 내용 읽기¶
from pycubrid.lob import Lob
from pycubrid.constants import CUBRIDDataType
conn = pycubrid.connect(host="localhost", port=33000, database="testdb")
cur = conn.cursor()
# CLOB 컬럼에 문자열 데이터 직접 삽입
cur.execute("INSERT INTO cookbook_docs (content) VALUES ('Hello, CLOB!')")
conn.commit()
# fetch는 LOB 핸들 dict를 반환, 내용이 아님
cur.execute("SELECT content FROM cookbook_docs WHERE id = 1")
row = cur.fetchone()
lob_handle = row[0] # lob_type, lob_length 등을 담은 dict
# 내용을 읽으려면 packed 핸들로 Lob 클래스 사용
lob = Lob(conn, CUBRIDDataType.CLOB, lob_handle["packed_lob_handle"])
content = lob.read(lob_handle["lob_length"])
print(content) # b'Hello, CLOB!'
중요:
Lob객체를execute()나 기본executemany()의 쿼리 파라미터로 전달할 수 없습니다. CLOB 컬럼에는 문자열을, BLOB 컬럼에는 바이트를 직접 삽입하세요. 예외는 autocommit이 꺼진 동기 커서의executemany(..., prepared=True)로, 같은 연결의Lob을 핸들로 바인딩합니다(API_REFERENCE.md).
컬렉션 타입¶
CUBRID의 컬렉션 타입(SET, MULTISET, SEQUENCE)은 하위 호환을 위해 기본적으로 raw bytes로 반환됩니다. connect() 또는 pycubrid.aio.connect()에 decode_collections=True를 전달하면, pycubrid는 지원되는 컬렉션 페이로드를 Python 컨테이너로 디코딩합니다.
| CUBRID 타입 | CCI 코드 | decode_collections=False |
decode_collections=True |
|---|---|---|---|
SET |
16 | bytes |
해시 가능하면 frozenset, 아니면 tuple |
MULTISET |
17 | bytes |
list |
SEQUENCE |
18 | bytes |
list |
참고:
cursor.description은 요소 타입이 아니라 컬렉션 코드(16, 17, 18)를 반환합니다. 정수 요소는 Pythonint를 유지하며 MULTISET은 중복, SEQUENCE는 순서를 보존합니다. 동기·비동기 fetch에 동일한 디코딩 규칙이 적용됩니다.- description의 마지막
null_ok필드는 PEP 249 의미로 NULL 허용 컬럼이면True, NOT NULL/기본키 컬럼이면False입니다. CAS의 반대 의미 플래그is_non_null을 그대로 노출하지 않습니다. - 모든 요소가 SQL NULL인 비어 있지 않은 컬렉션(예:
{NULL},{NULL, NULL})은MULTISET/SEQUENCE에서[None, ...],SET에서frozenset({None})으로 디코딩됩니다. 빈 컬렉션은[]/frozenset()으로 디코딩됩니다. - 빈
BIT/BIT VARYING요소(X'', 와이어 길이 0)는b"", NULL 요소(길이 -1)는None으로 디코딩되므로SEQUENCE{X'', NULL, X'01'}은[b"", None, b"\x01"]입니다(#998). 다른 타입의 길이 0 요소는None입니다. - 중첩 컬렉션 페이로드는 raw
bytes로 유지됩니다. - 알 수 없는 컬렉션 요소 타입은 raw
bytes로 폴백됩니다. SET값은 모든 디코딩된 요소가 해시 가능하면frozenset으로 정규화됩니다. 집합에 해시 불가능한 요소가 있으면(예: 디코딩된 JSON 객체), 예외 없이 내용을 보존하기 위해tuple을 반환합니다.
JSON 컬럼¶
JSON 컬럼은 CUBRID 타입 코드 34를 사용합니다.
| 연결 옵션 | fetch 결과 |
|---|---|
기본 (json_deserializer=None) |
raw JSON str |
json_deserializer=json.loads |
디코딩된 Python 객체 |
json_deserializer=custom_callable |
콜러블의 반환 값 |
이 옵트인 동작은 애플리케이션이 JSON 파싱을 지연시키는 것을 선호할 때 fetch를 할당-가볍게 유지합니다.
decode_collections¶
decode_collections는 pycubrid.connect()와 pycubrid.aio.connect() 양쪽의 연결 수준 스위치입니다.
| 설정 | 결과 |
|---|---|
False (기본) |
컬렉션 페이로드를 raw CAS 와이어 bytes로 반환 |
True |
지원되는 SET, MULTISET, SEQUENCE 페이로드를 Python 컨테이너로 디코딩 |
컬렉션 바인딩¶
일반 Python set, frozenset, list, tuple 값은 파라미터로 거부됩니다. 컬렉션을 바인딩하려면 원소를 타입 지정 컬렉션 파라미터로 감싸세요(#567):
| 클래스 | 렌더링되는 리터럴 | 서버 의미 |
|---|---|---|
pycubrid.types.Set |
SET{...} |
중복 제거, 순서 유지 안 함 |
pycubrid.types.Multiset |
MULTISET{...} |
중복 유지, 순서 유지 안 함 |
pycubrid.types.Sequence |
SEQUENCE{...} (LIST{...}와 같은 타입) |
중복과 순서 유지 |
from pycubrid.types import Multiset, Sequence, Set
cur.execute("INSERT INTO t VALUES (?, ?, ?)", (Set([1, 2]), Multiset(["a", "a"]), Sequence([3, 1])))
이 클래스들은 최상위 pycubrid 패키지에서도 export됩니다. 각각 불변이고, 원소를 tuple(.elements)로 저장하며, 하위 클래스를 만들 수 없습니다. 원소는 스칼라 파라미터와 같은 타입(None, bool, int, float, Decimal, str, bytes, bytearray, date, time, datetime)을 받으며 같은 보호된 렌더러로 렌더링됩니다. 중첩 컬렉션은 ProgrammingError를 발생시킵니다. 동기와 비동기 일반 커서 모두 지원합니다. 파라미터 바인딩을 참고하세요.
세 클래스 모두 dict를 거부합니다(TypeError) — dict를 순회하면 키만 쓰이고 값은 조용히 버려지기 때문입니다. Sequence는 추가로 set/frozenset을 거부합니다(TypeError): 순회 순서가 보장되지 않아 순서가 있는 컬렉션의 원소 순서가 실행마다 달라질 수 있기 때문입니다. Set과 Multiset은 서버 측 의미가 이미 순서를 버리므로 set/frozenset을 그대로 받습니다. 이 인스턴스들은 copy.copy()(항상 같은 객체를 반환), copy.deepcopy()(모든 원소가 그 자체로 불변이면 같은 객체를 반환하고, bytearray처럼 가변인 원소가 있으면 원소까지 독립적으로 복사한 별개의 객체를 반환해 복사본을 변경해도 원본에 되돌아가 영향을 주지 않음), pickle(동등한 인스턴스로 왕복)에 안전하며, 기존 인스턴스에서 __init__을 다시 호출해도 변경할 수 없습니다.
Set, Multiset, Sequence는 pycubrid.types와 pycubrid의 평범한 이름일 뿐 typing의 별칭이 아니지만, 그중 Sequence는 표준 typing/collections.abc 모듈에도 있는 이름입니다. from pycubrid import *를 쓰면 pycubrid의 Set과 Sequence가 스코프에 들어와 같은 방식으로 import한 typing.Set/typing.Sequence(또는 collections.abc.Sequence)를 가립니다. 같은 모듈에서 둘 다 필요하다면 from pycubrid.types import Sequence as CubridSequence처럼 명시적으로 import하거나(또는 pycubrid를 import해서 pycubrid.Sequence로 사용) 하세요.
디코딩은 바뀌지 않습니다: 조회한 컬렉션은 위 표와 같이(decode_collections=True일 때) 일반 Python 컨테이너이며, 이 파라미터 타입이 아닙니다.
사용 예제¶
cursor.description으로 타입 확인¶
import pycubrid
conn = pycubrid.connect(host="localhost", port=33000, database="testdb")
cur = conn.cursor()
cur.execute("SELECT * FROM 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()
생성자로 파라미터 바인딩¶
import pycubrid
conn = pycubrid.connect(host="localhost", port=33000, database="testdb")
cur = conn.cursor()
# 파라미터 값으로 PEP 249 생성자 사용
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()
Decimal 파라미터¶
Decimal 파라미터는 고정소수점 리터럴(E 표기 사용 안 함)로 전송되므로 CUBRID가
작성된 scale 그대로 NUMERIC으로 유지합니다. Decimal("0.0000001")은 float가
아니라 Decimal로 조회됩니다. 고정소수점 리터럴이 CUBRID NUMERIC 최대
정밀도인 38자리를 넘는 값은 DOUBLE이 되지 않고 DataError를 발생시킵니다.
파라미터 바인딩: Decimal 파라미터를 참고하세요.
from decimal import Decimal
cur.execute("SELECT ?", [Decimal("0.0000001")]) # 0.0000001로 전송
assert cur.fetchone()[0] == Decimal("0.0000001")
assert cur.description[0][1] == pycubrid.constants.CUBRIDDataType.NUMERIC
CUBRIDDataType enum 사용¶
from pycubrid.constants import CUBRIDDataType
# 특정 타입 코드 확인
assert CUBRIDDataType.INT == 8
assert CUBRIDDataType.STRING == 2
assert CUBRIDDataType.DATETIME == 22
# 타입 분기 로직에 사용
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})"