|
|
|
@ -94,40 +94,47 @@ static void pysqlite_cursor_dealloc(pysqlite_Cursor* self) |
|
|
|
Py_TYPE(self)->tp_free((PyObject*)self); |
|
|
|
} |
|
|
|
|
|
|
|
PyObject* _pysqlite_get_converter(PyObject* key) |
|
|
|
static PyObject * |
|
|
|
_pysqlite_get_converter(const char *keystr, Py_ssize_t keylen) |
|
|
|
{ |
|
|
|
PyObject* upcase_key; |
|
|
|
PyObject* retval; |
|
|
|
PyObject *key; |
|
|
|
PyObject *upcase_key; |
|
|
|
PyObject *retval; |
|
|
|
_Py_IDENTIFIER(upper); |
|
|
|
|
|
|
|
key = PyUnicode_FromStringAndSize(keystr, keylen); |
|
|
|
if (!key) { |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
upcase_key = _PyObject_CallMethodId(key, &PyId_upper, NULL); |
|
|
|
Py_DECREF(key); |
|
|
|
if (!upcase_key) { |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
retval = PyDict_GetItem(_pysqlite_converters, upcase_key); |
|
|
|
retval = PyDict_GetItemWithError(_pysqlite_converters, upcase_key); |
|
|
|
Py_DECREF(upcase_key); |
|
|
|
|
|
|
|
return retval; |
|
|
|
} |
|
|
|
|
|
|
|
int pysqlite_build_row_cast_map(pysqlite_Cursor* self) |
|
|
|
static int |
|
|
|
pysqlite_build_row_cast_map(pysqlite_Cursor* self) |
|
|
|
{ |
|
|
|
int i; |
|
|
|
const char* type_start = (const char*)-1; |
|
|
|
const char* pos; |
|
|
|
|
|
|
|
const char* colname; |
|
|
|
const char* decltype; |
|
|
|
PyObject* py_decltype; |
|
|
|
PyObject* converter; |
|
|
|
PyObject* key; |
|
|
|
|
|
|
|
if (!self->connection->detect_types) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
Py_XSETREF(self->row_cast_map, PyList_New(0)); |
|
|
|
if (!self->row_cast_map) { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
for (i = 0; i < sqlite3_column_count(self->statement->st); i++) { |
|
|
|
converter = NULL; |
|
|
|
@ -135,20 +142,17 @@ int pysqlite_build_row_cast_map(pysqlite_Cursor* self) |
|
|
|
if (self->connection->detect_types & PARSE_COLNAMES) { |
|
|
|
colname = sqlite3_column_name(self->statement->st, i); |
|
|
|
if (colname) { |
|
|
|
const char *type_start = NULL; |
|
|
|
for (pos = colname; *pos != 0; pos++) { |
|
|
|
if (*pos == '[') { |
|
|
|
type_start = pos + 1; |
|
|
|
} else if (*pos == ']' && type_start != (const char*)-1) { |
|
|
|
key = PyUnicode_FromStringAndSize(type_start, pos - type_start); |
|
|
|
if (!key) { |
|
|
|
/* creating a string failed, but it is too complicated |
|
|
|
* to propagate the error here, we just assume there is |
|
|
|
* no converter and proceed */ |
|
|
|
break; |
|
|
|
} |
|
|
|
else if (*pos == ']' && type_start != NULL) { |
|
|
|
converter = _pysqlite_get_converter(type_start, pos - type_start); |
|
|
|
if (!converter && PyErr_Occurred()) { |
|
|
|
Py_CLEAR(self->row_cast_map); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
converter = _pysqlite_get_converter(key); |
|
|
|
Py_DECREF(key); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -164,16 +168,14 @@ int pysqlite_build_row_cast_map(pysqlite_Cursor* self) |
|
|
|
* 'NUMBER(10)' to be treated as 'NUMBER', for example. |
|
|
|
* In other words, it will work as people expect it to work.*/ |
|
|
|
if (*pos == ' ' || *pos == '(' || *pos == 0) { |
|
|
|
py_decltype = PyUnicode_FromStringAndSize(decltype, pos - decltype); |
|
|
|
if (!py_decltype) { |
|
|
|
converter = _pysqlite_get_converter(decltype, pos - decltype); |
|
|
|
if (!converter && PyErr_Occurred()) { |
|
|
|
Py_CLEAR(self->row_cast_map); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
converter = _pysqlite_get_converter(py_decltype); |
|
|
|
Py_DECREF(py_decltype); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -182,11 +184,7 @@ int pysqlite_build_row_cast_map(pysqlite_Cursor* self) |
|
|
|
} |
|
|
|
|
|
|
|
if (PyList_Append(self->row_cast_map, converter) != 0) { |
|
|
|
if (converter != Py_None) { |
|
|
|
Py_DECREF(converter); |
|
|
|
} |
|
|
|
Py_CLEAR(self->row_cast_map); |
|
|
|
|
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -194,7 +192,8 @@ int pysqlite_build_row_cast_map(pysqlite_Cursor* self) |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
PyObject* _pysqlite_build_column_name(const char* colname) |
|
|
|
static PyObject * |
|
|
|
_pysqlite_build_column_name(const char* colname) |
|
|
|
{ |
|
|
|
const char* pos; |
|
|
|
|
|
|
|
@ -218,7 +217,8 @@ PyObject* _pysqlite_build_column_name(const char* colname) |
|
|
|
* Precondidition: |
|
|
|
* - sqlite3_step() has been called before and it returned SQLITE_ROW. |
|
|
|
*/ |
|
|
|
PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self) |
|
|
|
static PyObject * |
|
|
|
_pysqlite_fetch_one_row(pysqlite_Cursor* self) |
|
|
|
{ |
|
|
|
int i, numcols; |
|
|
|
PyObject* row; |
|
|
|
@ -227,12 +227,10 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self) |
|
|
|
PyObject* converter; |
|
|
|
PyObject* converted; |
|
|
|
Py_ssize_t nbytes; |
|
|
|
PyObject* buffer; |
|
|
|
const char* val_str; |
|
|
|
char buf[200]; |
|
|
|
const char* colname; |
|
|
|
PyObject* buf_bytes; |
|
|
|
PyObject* error_obj; |
|
|
|
PyObject* error_msg; |
|
|
|
|
|
|
|
if (self->reset) { |
|
|
|
PyErr_SetString(pysqlite_InterfaceError, errmsg_fetch_across_rollback); |
|
|
|
@ -248,13 +246,13 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self) |
|
|
|
return NULL; |
|
|
|
|
|
|
|
for (i = 0; i < numcols; i++) { |
|
|
|
if (self->connection->detect_types) { |
|
|
|
assert(self->row_cast_map != NULL); |
|
|
|
converter = PyList_GetItem(self->row_cast_map, i); |
|
|
|
if (!converter) { |
|
|
|
converter = Py_None; |
|
|
|
} |
|
|
|
} else { |
|
|
|
if (self->connection->detect_types |
|
|
|
&& self->row_cast_map != NULL |
|
|
|
&& i < PyList_GET_SIZE(self->row_cast_map)) |
|
|
|
{ |
|
|
|
converter = PyList_GET_ITEM(self->row_cast_map, i); |
|
|
|
} |
|
|
|
else { |
|
|
|
converter = Py_None; |
|
|
|
} |
|
|
|
|
|
|
|
@ -270,8 +268,6 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self) |
|
|
|
goto error; |
|
|
|
converted = PyObject_CallFunction(converter, "O", item); |
|
|
|
Py_DECREF(item); |
|
|
|
if (!converted) |
|
|
|
break; |
|
|
|
} |
|
|
|
} else { |
|
|
|
Py_BEGIN_ALLOW_THREADS |
|
|
|
@ -289,7 +285,7 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self) |
|
|
|
nbytes = sqlite3_column_bytes(self->statement->st, i); |
|
|
|
if (self->connection->text_factory == (PyObject*)&PyUnicode_Type) { |
|
|
|
converted = PyUnicode_FromStringAndSize(val_str, nbytes); |
|
|
|
if (!converted) { |
|
|
|
if (!converted && PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) { |
|
|
|
PyErr_Clear(); |
|
|
|
colname = sqlite3_column_name(self->statement->st, i); |
|
|
|
if (!colname) { |
|
|
|
@ -297,18 +293,12 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self) |
|
|
|
} |
|
|
|
PyOS_snprintf(buf, sizeof(buf) - 1, "Could not decode to UTF-8 column '%s' with text '%s'", |
|
|
|
colname , val_str); |
|
|
|
buf_bytes = PyByteArray_FromStringAndSize(buf, strlen(buf)); |
|
|
|
if (!buf_bytes) { |
|
|
|
error_msg = PyUnicode_Decode(buf, strlen(buf), "ascii", "replace"); |
|
|
|
if (!error_msg) { |
|
|
|
PyErr_SetString(pysqlite_OperationalError, "Could not decode to UTF-8"); |
|
|
|
} else { |
|
|
|
error_obj = PyUnicode_FromEncodedObject(buf_bytes, "ascii", "replace"); |
|
|
|
if (!error_obj) { |
|
|
|
PyErr_SetString(pysqlite_OperationalError, "Could not decode to UTF-8"); |
|
|
|
} else { |
|
|
|
PyErr_SetObject(pysqlite_OperationalError, error_obj); |
|
|
|
Py_DECREF(error_obj); |
|
|
|
} |
|
|
|
Py_DECREF(buf_bytes); |
|
|
|
PyErr_SetObject(pysqlite_OperationalError, error_msg); |
|
|
|
Py_DECREF(error_msg); |
|
|
|
} |
|
|
|
} |
|
|
|
} else if (self->connection->text_factory == (PyObject*)&PyBytes_Type) { |
|
|
|
@ -321,20 +311,15 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self) |
|
|
|
} else { |
|
|
|
/* coltype == SQLITE_BLOB */ |
|
|
|
nbytes = sqlite3_column_bytes(self->statement->st, i); |
|
|
|
buffer = PyBytes_FromStringAndSize( |
|
|
|
converted = PyBytes_FromStringAndSize( |
|
|
|
sqlite3_column_blob(self->statement->st, i), nbytes); |
|
|
|
if (!buffer) |
|
|
|
break; |
|
|
|
converted = buffer; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (converted) { |
|
|
|
PyTuple_SetItem(row, i, converted); |
|
|
|
} else { |
|
|
|
Py_INCREF(Py_None); |
|
|
|
PyTuple_SetItem(row, i, Py_None); |
|
|
|
if (!converted) { |
|
|
|
goto error; |
|
|
|
} |
|
|
|
PyTuple_SetItem(row, i, converted); |
|
|
|
} |
|
|
|
|
|
|
|
if (PyErr_Occurred()) |
|
|
|
@ -372,7 +357,8 @@ static int check_cursor(pysqlite_Cursor* cur) |
|
|
|
return pysqlite_check_thread(cur->connection) && pysqlite_check_connection(cur->connection); |
|
|
|
} |
|
|
|
|
|
|
|
PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args) |
|
|
|
static PyObject * |
|
|
|
_pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args) |
|
|
|
{ |
|
|
|
PyObject* operation; |
|
|
|
PyObject* parameters_list = NULL; |
|
|
|
@ -542,7 +528,7 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* |
|
|
|
} |
|
|
|
|
|
|
|
if (pysqlite_build_row_cast_map(self) != 0) { |
|
|
|
PyErr_SetString(pysqlite_OperationalError, "Error while building row_cast_map"); |
|
|
|
_PyErr_FormatFromCause(pysqlite_OperationalError, "Error while building row_cast_map"); |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
@ -631,7 +617,8 @@ PyObject* pysqlite_cursor_executemany(pysqlite_Cursor* self, PyObject* args) |
|
|
|
return _pysqlite_query_execute(self, 1, args); |
|
|
|
} |
|
|
|
|
|
|
|
PyObject* pysqlite_cursor_executescript(pysqlite_Cursor* self, PyObject* args) |
|
|
|
static PyObject * |
|
|
|
pysqlite_cursor_executescript(pysqlite_Cursor* self, PyObject* args) |
|
|
|
{ |
|
|
|
PyObject* script_obj; |
|
|
|
PyObject* script_str = NULL; |
|
|
|
@ -718,12 +705,6 @@ error: |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
PyObject* pysqlite_cursor_getiter(pysqlite_Cursor *self) |
|
|
|
{ |
|
|
|
Py_INCREF(self); |
|
|
|
return (PyObject*)self; |
|
|
|
} |
|
|
|
|
|
|
|
PyObject* pysqlite_cursor_iternext(pysqlite_Cursor *self) |
|
|
|
{ |
|
|
|
PyObject* next_row_tuple; |
|
|
|
@ -961,7 +942,7 @@ PyTypeObject pysqlite_CursorType = { |
|
|
|
0, /* tp_clear */ |
|
|
|
0, /* tp_richcompare */ |
|
|
|
offsetof(pysqlite_Cursor, in_weakreflist), /* tp_weaklistoffset */ |
|
|
|
(getiterfunc)pysqlite_cursor_getiter, /* tp_iter */ |
|
|
|
PyObject_SelfIter, /* tp_iter */ |
|
|
|
(iternextfunc)pysqlite_cursor_iternext, /* tp_iternext */ |
|
|
|
cursor_methods, /* tp_methods */ |
|
|
|
cursor_members, /* tp_members */ |
|
|
|
|