Environment: CUBRIDdb 11.3.0.51, Python 3.10 and 3.12, CUBRID 11.4.6 and 10.2.18.
Reproduce
cur.execute("CREATE TABLE lob_t (id INT, b BLOB, c CLOB)")
cur.execute("INSERT INTO lob_t VALUES (?, ?, ?)", (1, b"\x00\x01binary", "hello clob")); conn.commit()
cur.execute("SELECT id, b, c FROM lob_t"); print(cur.fetchone())
# (1, 'file:ces_706/dba.lob_t.00001790519511835570_0028', 'file:ces_509/...') <- str locators, not bytes/str
SELECT BLOB_TO_BIT(b), CLOB_TO_CHAR(c) returns the correct values.
Problems in the low-level API
cursor.fetch_lob(col, lob) decides between BLOB and CLOB from the type of column 1 (python_cubrid.c, CCI_GET_RESULT_INFO_TYPE (self->col_info, 1)), not from col. A BLOB in column 2 is read as a CLOB, and lob.read() raises UnicodeDecodeError on non-UTF-8 bytes.
- Every call advances the cursor (
cci_cursor(…, 1, CCI_CURSOR_CURRENT) + cursor_pos += 1). When reading two LOB columns from one row, the second column comes from the next row, and later rows fail with -30018 LOB not exist.
Cause
_cubrid_CursorObject_dbval_to_pyvalue has no CCI_U_TYPE_BLOB / CCI_U_TYPE_CLOB case, so it falls through to the CCI_A_TYPE_STR default.
Suggested fix
- Return BLOB as
bytes and CLOB as str in fetch_row (via cci_blob_read / cci_clob_read), or return a documented Lob object. Put this behind an option if compatibility matters.
- Make
fetch_lob use the type of col itself, and stop it from advancing the cursor.
Environment: CUBRIDdb 11.3.0.51, Python 3.10 and 3.12, CUBRID 11.4.6 and 10.2.18.
Reproduce
SELECT BLOB_TO_BIT(b), CLOB_TO_CHAR(c)returns the correct values.Problems in the low-level API
cursor.fetch_lob(col, lob)decides between BLOB and CLOB from the type of column 1 (python_cubrid.c,CCI_GET_RESULT_INFO_TYPE (self->col_info, 1)), not fromcol. A BLOB in column 2 is read as a CLOB, andlob.read()raisesUnicodeDecodeErroron non-UTF-8 bytes.cci_cursor(…, 1, CCI_CURSOR_CURRENT)+cursor_pos += 1). When reading two LOB columns from one row, the second column comes from the next row, and later rows fail with-30018 LOB not exist.Cause
_cubrid_CursorObject_dbval_to_pyvaluehas noCCI_U_TYPE_BLOB/CCI_U_TYPE_CLOBcase, so it falls through to theCCI_A_TYPE_STRdefault.Suggested fix
bytesand CLOB asstrinfetch_row(viacci_blob_read/cci_clob_read), or return a documented Lob object. Put this behind an option if compatibility matters.fetch_lobuse the type ofcolitself, and stop it from advancing the cursor.