Environment: CUBRIDdb 11.3.0.51 (tag v11.3.0.51, client_version() reports 11.3.0.0001), Python 3.10 and 3.12, CUBRID 11.4.6 and 10.2.18.
Reproduce
import CUBRIDdb
conn = CUBRIDdb.connect("CUBRID:localhost:33000:testdb:::", "dba", ""); conn.set_autocommit(False)
cur = conn.cursor()
cur.execute("CREATE TABLE em (id INT, v VARCHAR(20), n INT)")
cur.executemany("INSERT INTO em VALUES (?, ?, ?)", [(1,"a",10),(2,None,None),(3,"c",30),(4,None,None)])
conn.commit(); cur.execute("SELECT * FROM em ORDER BY id"); print(cur.fetchall())
# actual: [(1,'a',10),(2,'a',10),(3,'c',30),(4,'c',30)]
# expected: [(1,'a',10),(2,None,None),(3,'c',30),(4,None,None)]
Separately, an UPDATE executemany that matches 3 rows leaves cursor.rowcount == 1. PEP 249 expects the total number of affected rows.
Cause
CUBRIDdb/cursors.py _bind_params does if arg is None: continue, so NULL is never bound. Since #44 (APIS-1701), executemany prepares once and re-executes, so the previous binding stays in effect for that parameter. _cubrid.cursor.bind_param(i, None) currently fails with SystemError: <method 'bind_param'> returned NULL without setting an exception, so callers can't work around it. rowcount is set only after the last execute().
Suggested fix
- Bind SQL NULL explicitly for
None, e.g. cci_bind_param(..., CCI_A_TYPE_STR, NULL, CCI_U_TYPE_NULL, 0), and make bind_param(i, None) supported.
- Accumulate
rowcount across executions in executemany.
- Add tests for
None following a non-None value in executemany.
Environment: CUBRIDdb 11.3.0.51 (tag v11.3.0.51,
client_version()reports 11.3.0.0001), Python 3.10 and 3.12, CUBRID 11.4.6 and 10.2.18.Reproduce
Separately, an UPDATE
executemanythat matches 3 rows leavescursor.rowcount == 1. PEP 249 expects the total number of affected rows.Cause
CUBRIDdb/cursors.py_bind_paramsdoesif arg is None: continue, so NULL is never bound. Since #44 (APIS-1701),executemanyprepares once and re-executes, so the previous binding stays in effect for that parameter._cubrid.cursor.bind_param(i, None)currently fails withSystemError: <method 'bind_param'> returned NULL without setting an exception, so callers can't work around it.rowcountis set only after the lastexecute().Suggested fix
None, e.g.cci_bind_param(..., CCI_A_TYPE_STR, NULL, CCI_U_TYPE_NULL, 0), and makebind_param(i, None)supported.rowcountacross executions inexecutemany.Nonefollowing a non-Nonevalue inexecutemany.