From 372e59e53a1f61b018010d3ec0d93371052a9927 Mon Sep 17 00:00:00 2001 From: vimiix Date: Tue, 29 Aug 2023 11:34:52 +0800 Subject: [PATCH] fix(extra):object type error, change to only support string or str-able params --- lib/extras.py | 29 ++++++++++++++++++++--------- psycopg/cursor_type.c | 26 ++++++++++++++------------ 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/lib/extras.py b/lib/extras.py index 332b08f..9f3644d 100644 --- a/lib/extras.py +++ b/lib/extras.py @@ -1142,7 +1142,7 @@ def register_composite(name, conn_or_curs, globally=False, factory=None): return caster -def _paginate(seq, page_size): +def _paginate(seq, page_size, to_byte=False): """Consume an iterable and return it in chunks. Every chunk is at most `page_size`. Never return an empty chunk. @@ -1152,7 +1152,16 @@ def _paginate(seq, page_size): while True: try: for i in range(page_size): - page.append(next(it)) + if not to_byte: + page.append(next(it)) + continue + vs = next(it) + if isinstance(vs, (list, tuple)): + # Ignore None object + # Serialized params to bytes + page.append(list(map(lambda v: v if v is None else str(v).encode('utf-8'), vs))) + else: + page.append(vs) yield page page = [] except StopIteration: @@ -1308,16 +1317,17 @@ def execute_prepared_batch(cur, prepared_statement_name, args_list, page_size=10 r""" [openGauss libpq only] - Execute prepared statement with api `PQexecPreparedBatch` (new api in openGauss) + Execute prepared statement with api `PQexecPreparedBatch` (new api in openGauss's libpq.so) - Param: - argslist: 2d list, do nothing if empty + Arguments: + argslist: Two-dimensional list, if empty, return directly + Each parameter in the argument list must be a string or be string-able(should implements `__str__` magic method) """ if len(args_list) == 0: return nparams = len(args_list[0]) - for page in _paginate(args_list, page_size=page_size): + for page in _paginate(args_list, page_size=page_size, to_byte=True): cur.execute_prepared_batch(prepared_statement_name, nparams, len(page), page) @@ -1325,14 +1335,15 @@ def execute_params_batch(cur, sql_format, args_list, page_size=100): r""" [openGauss libpq only] - Execute sql with api `PQexecParamsBatch` (new api in openGauss) + Execute sql with api `PQexecParamsBatch` (new api in openGauss's libpq.so) Arguments: - argslist: 2d list, do nothing if empty + argslist: Two-dimensional list, if empty, return directly + Each parameter in the argument list must be a string or be string-able(should implements `__str__` magic method) """ if len(args_list) == 0: return nparams = len(args_list[0]) - for page in _paginate(args_list, page_size=page_size): + for page in _paginate(args_list, page_size=page_size, to_byte=True): cur.execute_params_batch(sql_format, nparams, len(page), page) diff --git a/psycopg/cursor_type.c b/psycopg/cursor_type.c index 17ad401..62a5d55 100644 --- a/psycopg/cursor_type.c +++ b/psycopg/cursor_type.c @@ -628,7 +628,7 @@ curs_execute_prepared_batch(cursorObject *self, PyObject *args) int nParams = 0, nBatch = 0; PyObject *argsList = NULL; - Py_ssize_t rowIdx, colIdx, total; + int rowIdx, colIdx, total; char **paramValues = NULL; PGresult *res = NULL; @@ -642,7 +642,7 @@ curs_execute_prepared_batch(cursorObject *self, PyObject *args) } Dprintf("execute_prepared_batch parsed statement_name: %s, nParams: %d, nBatch: %d", stmtName, nParams, nBatch); - total = nBatch*nParams; + total = nBatch * nParams; EXC_IF_CURS_CLOSED(self); EXC_IF_CURS_ASYNC(self, execute_prepared_batch); @@ -679,11 +679,12 @@ curs_execute_prepared_batch(cursorObject *self, PyObject *args) PyObject *argItem = PySequence_GetItem(rowArgs, colIdx); if (argItem == Py_None) { - paramValues[rowIdx*nParams+colIdx] = "NULL"; + paramValues[rowIdx * nParams + colIdx] = NULL; } else { - PyObject *t = microprotocol_getquoted(argItem, self->conn); - paramValues[rowIdx*nParams+colIdx] = strdup(Bytes_AsString(t)); - Py_XDECREF(t); + if (!(argItem = psyco_ensure_bytes(argItem))) { + goto exit; + } + paramValues[rowIdx * nParams + colIdx] = Bytes_AsString(argItem); } Py_XDECREF(argItem); } @@ -715,7 +716,7 @@ curs_execute_params_batch(cursorObject *self, PyObject *args) int nParams = 0, nBatch = 0; PyObject *argsList = NULL; - Py_ssize_t rowIdx, colIdx, total; + int rowIdx, colIdx, total; char **paramValues = NULL; PGresult *res = NULL; @@ -729,7 +730,7 @@ curs_execute_params_batch(cursorObject *self, PyObject *args) Dprintf("execute_params_batch parsed sql: %s, nParams: %d, nBatch: %d", sql, nParams, nBatch); - total = nBatch*nParams; + total = nBatch * nParams; EXC_IF_CURS_CLOSED(self); EXC_IF_CURS_ASYNC(self, execute_params_batch); @@ -765,11 +766,12 @@ curs_execute_params_batch(cursorObject *self, PyObject *args) PyObject *argItem = PySequence_GetItem(rowArgs, colIdx); if (argItem == Py_None) { - paramValues[rowIdx*nParams+colIdx] = "NULL"; + paramValues[rowIdx * nParams + colIdx] = NULL; } else { - PyObject *t = microprotocol_getquoted(argItem, self->conn); - paramValues[rowIdx*nParams+colIdx] = strdup(Bytes_AsString(t)); - Py_XDECREF(t); + if (!(argItem = psyco_ensure_bytes(argItem))) { + goto exit; + } + paramValues[rowIdx * nParams + colIdx] = Bytes_AsString(argItem); } Py_XDECREF(argItem); } -- Gitee