Skip to content

Commit 5843251

Browse files
committed
consolidate sqlite3_finalize and sqlite3_reset usages
1 parent c7b11b7 commit 5843251

File tree

4 files changed

+106
-17
lines changed

4 files changed

+106
-17
lines changed

Modules/_sqlite/cursor.c

Lines changed: 88 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,41 @@ check_cursor_locked(pysqlite_Cursor *cur)
5858
return 1;
5959
}
6060

61+
static pysqlite_state *
62+
get_module_state_by_cursor(pysqlite_Cursor *cursor)
63+
{
64+
if (cursor->connection != NULL && cursor->connection->state != NULL) {
65+
return cursor->connection->state;
66+
}
67+
return pysqlite_get_state_by_type(Py_TYPE(cursor));
68+
}
69+
70+
static void
71+
cursor_sqlite3_internal_error(pysqlite_Cursor *cursor,
72+
const char *error_message,
73+
int chain_exceptions)
74+
{
75+
pysqlite_state *state = get_module_state_by_cursor(cursor);
76+
if (chain_exceptions) {
77+
assert(PyErr_Occurred());
78+
PyObject *exc = PyErr_GetRaisedException();
79+
PyErr_SetString(state->InternalError, error_message);
80+
_PyErr_ChainExceptions1(exc);
81+
}
82+
else {
83+
// assert(!PyErr_Occurred());
84+
PyErr_SetString(state->InternalError, error_message);
85+
}
86+
}
87+
88+
static void
89+
cursor_cannot_reset_stmt_error(pysqlite_Cursor *cursor, int chain_exceptions)
90+
{
91+
cursor_sqlite3_internal_error(cursor,
92+
"cannot reset statement",
93+
chain_exceptions);
94+
}
95+
6196
/*[clinic input]
6297
module _sqlite3
6398
class _sqlite3.Cursor "pysqlite_Cursor *" "clinic_state()->CursorType"
@@ -173,8 +208,12 @@ cursor_clear(PyObject *op)
173208
Py_CLEAR(self->row_factory);
174209
if (self->statement) {
175210
/* Reset the statement if the user has not closed the cursor */
176-
stmt_reset(self->statement);
211+
int rc = stmt_reset(self->statement);
177212
Py_CLEAR(self->statement);
213+
if (rc != SQLITE_OK) {
214+
cursor_cannot_reset_stmt_error(self, 0);
215+
PyErr_FormatUnraisable("Exception ignored in cursor_clear()");
216+
}
178217
}
179218

180219
return 0;
@@ -834,7 +873,9 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
834873

835874
if (self->statement) {
836875
// Reset pending statements on this cursor.
837-
(void)stmt_reset(self->statement);
876+
if (stmt_reset(self->statement) != SQLITE_OK) {
877+
goto reset_failure;
878+
}
838879
}
839880

840881
PyObject *stmt = get_statement_from_cache(self, operation);
@@ -858,7 +899,9 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
858899
}
859900
}
860901

861-
(void)stmt_reset(self->statement);
902+
if (stmt_reset(self->statement) != SQLITE_OK) {
903+
goto reset_failure;
904+
}
862905
self->rowcount = self->statement->is_dml ? 0L : -1L;
863906

864907
/* We start a transaction implicitly before a DML statement.
@@ -940,7 +983,9 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
940983
if (self->statement->is_dml) {
941984
self->rowcount += (long)sqlite3_changes(self->connection->db);
942985
}
943-
stmt_reset(self->statement);
986+
if (stmt_reset(self->statement) != SQLITE_OK) {
987+
goto reset_failure;
988+
}
944989
}
945990
Py_XDECREF(parameters);
946991
}
@@ -965,8 +1010,15 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
9651010

9661011
if (PyErr_Occurred()) {
9671012
if (self->statement) {
968-
(void)stmt_reset(self->statement);
1013+
sqlite3 *db = sqlite3_db_handle(self->statement->st);
1014+
int prev = sqlite3_errcode(db);
1015+
// stmt_reset() may return the previous error that may be
1016+
// currently set, so we need to avoid a double "raise".
1017+
rc = stmt_reset(self->statement);
9691018
Py_CLEAR(self->statement);
1019+
if (rc != SQLITE_OK && rc != prev) {
1020+
cursor_cannot_reset_stmt_error(self, 1);
1021+
}
9701022
}
9711023
self->rowcount = -1L;
9721024
return NULL;
@@ -975,6 +1027,20 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
9751027
Py_CLEAR(self->statement);
9761028
}
9771029
return Py_NewRef((PyObject *)self);
1030+
1031+
reset_failure:
1032+
/* suite to execute when stmt_reset() failed and no exception is set */
1033+
assert(!PyErr_Occurred());
1034+
1035+
Py_XDECREF(parameters);
1036+
Py_XDECREF(parameters_iter);
1037+
Py_XDECREF(parameters_list);
1038+
1039+
self->locked = 0;
1040+
self->rowcount = -1L;
1041+
Py_CLEAR(self->statement);
1042+
cursor_cannot_reset_stmt_error(self, 0);
1043+
return NULL;
9781044
}
9791045

9801046
/*[clinic input]
@@ -1117,14 +1183,20 @@ pysqlite_cursor_iternext(PyObject *op)
11171183
if (self->statement->is_dml) {
11181184
self->rowcount = (long)sqlite3_changes(self->connection->db);
11191185
}
1120-
(void)stmt_reset(self->statement);
1186+
int rc = stmt_reset(self->statement);
11211187
Py_CLEAR(self->statement);
1188+
if (rc != SQLITE_OK) {
1189+
goto reset_failure;
1190+
}
11221191
}
11231192
else if (rc != SQLITE_ROW) {
1124-
set_error_from_db(self->connection->state, self->connection->db);
1125-
(void)stmt_reset(self->statement);
1193+
rc = set_error_from_db(self->connection->state, self->connection->db);
1194+
int reset_ok = stmt_reset(self->statement);
11261195
Py_CLEAR(self->statement);
11271196
Py_DECREF(row);
1197+
if (rc == SQLITE_OK && reset_ok != SQLITE_OK) {
1198+
goto reset_failure;
1199+
}
11281200
return NULL;
11291201
}
11301202
if (!Py_IsNone(self->row_factory)) {
@@ -1134,6 +1206,10 @@ pysqlite_cursor_iternext(PyObject *op)
11341206
Py_SETREF(row, new_row);
11351207
}
11361208
return row;
1209+
1210+
reset_failure:
1211+
cursor_cannot_reset_stmt_error(self, 0);
1212+
return NULL;
11371213
}
11381214

11391215
/*[clinic input]
@@ -1291,11 +1367,12 @@ pysqlite_cursor_close_impl(pysqlite_Cursor *self)
12911367
return NULL;
12921368
}
12931369

1294-
if (self->statement) {
1295-
(void)stmt_reset(self->statement);
1296-
Py_CLEAR(self->statement);
1370+
if (self->statement && stmt_reset(self->statement) != SQLITE_OK) {
1371+
cursor_cannot_reset_stmt_error(self, 0);
1372+
return NULL;
12971373
}
12981374

1375+
Py_CLEAR(self->statement);
12991376
self->closed = 1;
13001377

13011378
Py_RETURN_NONE;

Modules/_sqlite/statement.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,12 @@ pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
9696
return self;
9797

9898
error:
99-
(void)sqlite3_finalize(stmt);
99+
assert(PyErr_Occurred());
100+
if (sqlite3_finalize(stmt) != SQLITE_OK) {
101+
PyObject *exc = PyErr_GetRaisedException();
102+
PyErr_SetString(connection->InternalError, "cannot finalize statement");
103+
_PyErr_ChainExceptions1(exc);
104+
}
100105
return NULL;
101106
}
102107

@@ -107,10 +112,16 @@ stmt_dealloc(PyObject *op)
107112
PyTypeObject *tp = Py_TYPE(self);
108113
PyObject_GC_UnTrack(op);
109114
if (self->st) {
115+
int rc;
110116
Py_BEGIN_ALLOW_THREADS
111-
sqlite3_finalize(self->st);
117+
rc = sqlite3_finalize(self->st);
112118
Py_END_ALLOW_THREADS
113-
self->st = 0;
119+
self->st = NULL;
120+
if (rc != SQLITE_OK) {
121+
pysqlite_state *state = PyType_GetModuleState(Py_TYPE(op));
122+
PyErr_SetString(state->InternalError, "cannot finalize statement");
123+
PyErr_FormatUnraisable("Exception ignored in stmt_dealloc()");
124+
}
114125
}
115126
tp->tp_free(self);
116127
Py_DECREF(tp);

Modules/_sqlite/util.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,21 +135,22 @@ set_error_from_code(pysqlite_state *state, int code)
135135
/**
136136
* Checks the SQLite error code and sets the appropriate DB-API exception.
137137
*/
138-
void
138+
int
139139
set_error_from_db(pysqlite_state *state, sqlite3 *db)
140140
{
141141
int errorcode = sqlite3_errcode(db);
142142
PyObject *exc_class = get_exception_class(state, errorcode);
143143
if (exc_class == NULL) {
144144
// No new exception need be raised.
145-
return;
145+
return SQLITE_OK;
146146
}
147147

148148
/* Create and set the exception. */
149149
int extended_errcode = sqlite3_extended_errcode(db);
150150
// sqlite3_errmsg() always returns an UTF-8 encoded message
151151
const char *errmsg = sqlite3_errmsg(db);
152152
raise_exception(exc_class, extended_errcode, errmsg);
153+
return errorcode;
153154
}
154155

155156
#ifdef WORDS_BIGENDIAN

Modules/_sqlite/util.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
/**
3232
* Checks the SQLite error code and sets the appropriate DB-API exception.
3333
*/
34-
void set_error_from_db(pysqlite_state *state, sqlite3 *db);
34+
int set_error_from_db(pysqlite_state *state, sqlite3 *db);
3535
void set_error_from_code(pysqlite_state *state, int code);
3636

3737
sqlite_int64 _pysqlite_long_as_int64(PyObject * value);

0 commit comments

Comments
 (0)