summaryrefslogtreecommitdiffstats
path: root/Modules/_sqlite/cursor.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_sqlite/cursor.c')
-rw-r--r--Modules/_sqlite/cursor.c128
1 files changed, 64 insertions, 64 deletions
diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c
index 7ce6cc5..5431112 100644
--- a/Modules/_sqlite/cursor.c
+++ b/Modules/_sqlite/cursor.c
@@ -1,6 +1,6 @@
/* cursor.c - the cursor type
*
- * Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
+ * Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de>
*
* This file is part of pysqlite.
*
@@ -36,6 +36,8 @@
PyObject* pysqlite_cursor_iternext(pysqlite_Cursor* self);
+static char* errmsg_fetch_across_rollback = "Cursor needed to be reset because of commit/rollback and can no longer be fetched from.";
+
static pysqlite_StatementKind detect_statement_type(const char* statement)
{
char buf[20];
@@ -74,7 +76,7 @@ static pysqlite_StatementKind detect_statement_type(const char* statement)
}
}
-int pysqlite_cursor_init(pysqlite_Cursor* self, PyObject* args, PyObject* kwargs)
+static int pysqlite_cursor_init(pysqlite_Cursor* self, PyObject* args, PyObject* kwargs)
{
pysqlite_Connection* connection;
@@ -87,6 +89,7 @@ int pysqlite_cursor_init(pysqlite_Cursor* self, PyObject* args, PyObject* kwargs
self->connection = connection;
self->statement = NULL;
self->next_row = NULL;
+ self->in_weakreflist = NULL;
self->row_cast_map = PyList_New(0);
if (!self->row_cast_map) {
@@ -100,6 +103,8 @@ int pysqlite_cursor_init(pysqlite_Cursor* self, PyObject* args, PyObject* kwargs
self->lastrowid= Py_None;
self->arraysize = 1;
+ self->closed = 0;
+ self->reset = 0;
self->rowcount = -1L;
@@ -110,10 +115,16 @@ int pysqlite_cursor_init(pysqlite_Cursor* self, PyObject* args, PyObject* kwargs
return -1;
}
+ if (!pysqlite_connection_register_cursor(connection, (PyObject*)self)) {
+ return -1;
+ }
+
+ self->initialized = 1;
+
return 0;
}
-void pysqlite_cursor_dealloc(pysqlite_Cursor* self)
+static void pysqlite_cursor_dealloc(pysqlite_Cursor* self)
{
int rc;
@@ -130,6 +141,10 @@ void pysqlite_cursor_dealloc(pysqlite_Cursor* self)
Py_XDECREF(self->row_factory);
Py_XDECREF(self->next_row);
+ if (self->in_weakreflist != NULL) {
+ PyObject_ClearWeakRefs((PyObject*)self);
+ }
+
Py_TYPE(self)->tp_free((PyObject*)self);
}
@@ -281,6 +296,11 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self)
PyObject* buf_bytes;
PyObject* error_obj;
+ if (self->reset) {
+ PyErr_SetString(pysqlite_InterfaceError, errmsg_fetch_across_rollback);
+ return NULL;
+ }
+
Py_BEGIN_ALLOW_THREADS
numcols = sqlite3_data_count(self->statement->st);
Py_END_ALLOW_THREADS
@@ -397,6 +417,26 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self)
return row;
}
+/*
+ * Checks if a cursor object is usable.
+ *
+ * 0 => error; 1 => ok
+ */
+static int check_cursor(pysqlite_Cursor* cur)
+{
+ if (!cur->initialized) {
+ PyErr_SetString(pysqlite_ProgrammingError, "Base Cursor.__init__ not called.");
+ return 0;
+ }
+
+ if (cur->closed) {
+ PyErr_SetString(pysqlite_ProgrammingError, "Cannot operate on a closed cursor.");
+ return 0;
+ } else {
+ return pysqlite_check_thread(cur->connection) && pysqlite_check_connection(cur->connection);
+ }
+}
+
PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args)
{
PyObject* operation;
@@ -416,13 +456,15 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
PyObject* second_argument = NULL;
int allow_8bit_chars;
- if (!pysqlite_check_thread(self->connection) || !pysqlite_check_connection(self->connection)) {
+ if (!check_cursor(self)) {
return NULL;
}
+ self->reset = 0;
+
/* Make shooting yourself in the foot with not utf-8 decodable 8-bit-strings harder */
allow_8bit_chars = ((self->connection->text_factory != (PyObject*)&PyUnicode_Type) &&
- (self->connection->text_factory != (PyObject*)&PyUnicode_Type && pysqlite_OptimizedUnicode));
+ (self->connection->text_factory != pysqlite_OptimizedUnicode));
Py_XDECREF(self->next_row);
self->next_row = NULL;
@@ -573,42 +615,6 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
}
}
- func_args = PyTuple_New(1);
- if (!func_args) {
- goto error;
- }
- Py_INCREF(operation);
- if (PyTuple_SetItem(func_args, 0, operation) != 0) {
- goto error;
- }
-
- if (self->statement) {
- (void)pysqlite_statement_reset(self->statement);
- Py_DECREF(self->statement);
- }
-
- self->statement = (pysqlite_Statement*)pysqlite_cache_get(self->connection->statement_cache, func_args);
- Py_DECREF(func_args);
-
- if (!self->statement) {
- goto error;
- }
-
- if (self->statement->in_use) {
- Py_DECREF(self->statement);
- self->statement = PyObject_New(pysqlite_Statement, &pysqlite_StatementType);
- if (!self->statement) {
- goto error;
- }
- rc = pysqlite_statement_create(self->statement, self->connection, operation);
- if (rc != SQLITE_OK) {
- Py_CLEAR(self->statement);
- goto error;
- }
- }
-
- pysqlite_statement_reset(self->statement);
- pysqlite_statement_mark_dirty(self->statement);
while (1) {
parameters = PyIter_Next(parameters_iter);
@@ -623,11 +629,6 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
goto error;
}
- if (pysqlite_build_row_cast_map(self) != 0) {
- PyErr_SetString(pysqlite_OperationalError, "Error while building row_cast_map");
- goto error;
- }
-
/* Keep trying the SQL statement until the schema stops changing. */
while (1) {
/* Actually execute the SQL statement. */
@@ -671,10 +672,6 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
}
if (rc == SQLITE_ROW || (rc == SQLITE_DONE && statement_type == STATEMENT_SELECT)) {
- Py_BEGIN_ALLOW_THREADS
- numcols = sqlite3_column_count(self->statement->st);
- Py_END_ALLOW_THREADS
-
if (self->description == Py_None) {
Py_BEGIN_ALLOW_THREADS
numcols = sqlite3_column_count(self->statement->st);
@@ -782,16 +779,17 @@ PyObject* pysqlite_cursor_executescript(pysqlite_Cursor* self, PyObject* args)
sqlite3_stmt* statement;
int rc;
PyObject* result;
- int statement_completed = 0;
if (!PyArg_ParseTuple(args, "O", &script_obj)) {
return NULL;
}
- if (!pysqlite_check_thread(self->connection) || !pysqlite_check_connection(self->connection)) {
+ if (!check_cursor(self)) {
return NULL;
}
+ self->reset = 0;
+
if (PyUnicode_Check(script_obj)) {
script_cstr = _PyUnicode_AsString(script_obj);
if (!script_cstr) {
@@ -810,11 +808,6 @@ PyObject* pysqlite_cursor_executescript(pysqlite_Cursor* self, PyObject* args)
Py_DECREF(result);
while (1) {
- if (!sqlite3_complete(script_cstr)) {
- break;
- }
- statement_completed = 1;
-
Py_BEGIN_ALLOW_THREADS
rc = sqlite3_prepare(self->connection->db,
script_cstr,
@@ -845,15 +838,15 @@ PyObject* pysqlite_cursor_executescript(pysqlite_Cursor* self, PyObject* args)
_pysqlite_seterror(self->connection->db, NULL);
goto error;
}
+
+ if (*script_cstr == (char)0) {
+ break;
+ }
}
error:
Py_XDECREF(script_str);
- if (!statement_completed) {
- PyErr_SetString(pysqlite_ProgrammingError, "you did not provide a complete SQL statement");
- }
-
if (PyErr_Occurred()) {
return NULL;
} else {
@@ -874,7 +867,12 @@ PyObject* pysqlite_cursor_iternext(pysqlite_Cursor *self)
PyObject* next_row;
int rc;
- if (!pysqlite_check_thread(self->connection) || !pysqlite_check_connection(self->connection)) {
+ if (!check_cursor(self)) {
+ return NULL;
+ }
+
+ if (self->reset) {
+ PyErr_SetString(pysqlite_InterfaceError, errmsg_fetch_across_rollback);
return NULL;
}
@@ -1017,6 +1015,8 @@ PyObject* pysqlite_cursor_close(pysqlite_Cursor* self, PyObject* args)
Py_CLEAR(self->statement);
}
+ self->closed = 1;
+
Py_INCREF(Py_None);
return Py_None;
}
@@ -1077,12 +1077,12 @@ PyTypeObject pysqlite_CursorType = {
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
cursor_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
+ offsetof(pysqlite_Cursor, in_weakreflist), /* tp_weaklistoffset */
(getiterfunc)pysqlite_cursor_getiter, /* tp_iter */
(iternextfunc)pysqlite_cursor_iternext, /* tp_iternext */
cursor_methods, /* tp_methods */