Skip to content

Commit d27cde7

Browse files
committed
bpo-45512: Simplify manage isolation level
1 parent da20d74 commit d27cde7

File tree

3 files changed

+33
-41
lines changed

3 files changed

+33
-41
lines changed

Modules/_sqlite/connection.c

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,6 @@ class _sqlite3.Connection "pysqlite_Connection *" "clinic_state()->ConnectionTyp
7171

7272
_Py_IDENTIFIER(cursor);
7373

74-
static const char * const begin_statements[] = {
75-
"BEGIN ",
76-
"BEGIN DEFERRED",
77-
"BEGIN IMMEDIATE",
78-
"BEGIN EXCLUSIVE",
79-
NULL
80-
};
81-
8274
static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self);
8375
static void free_callback_context(callback_context *ctx);
8476
static void set_callback_context(callback_context **ctx_pp,
@@ -108,25 +100,21 @@ new_statement_cache(pysqlite_Connection *self, pysqlite_state *state,
108100
return res;
109101
}
110102

111-
static inline const char *
112-
begin_stmt_to_isolation_level(const char *begin_stmt)
113-
{
114-
assert(begin_stmt != NULL);
115-
116-
// All begin statements start with "BEGIN "; add strlen("BEGIN ") to get
117-
// the isolation level.
118-
return begin_stmt + 6;
119-
}
120-
121103
static const char *
122-
get_begin_statement(const char *level)
104+
get_isolation_level(const char *level)
123105
{
124106
assert(level != NULL);
125-
for (int i = 0; begin_statements[i] != NULL; i++) {
126-
const char *stmt = begin_statements[i];
127-
const char *candidate = begin_stmt_to_isolation_level(stmt);
107+
static const char *const allowed_levels[] = {
108+
"",
109+
"DEFERRED",
110+
"IMMEDIATE",
111+
"EXCLUSIVE",
112+
NULL
113+
};
114+
for (int i = 0; allowed_levels[i] != NULL; i++) {
115+
const char *candidate = allowed_levels[i];
128116
if (sqlite3_stricmp(level, candidate) == 0) {
129-
return begin_statements[i];
117+
return candidate;
130118
}
131119
}
132120
PyErr_SetString(PyExc_ValueError,
@@ -202,10 +190,10 @@ pysqlite_connection_init_impl(pysqlite_Connection *self,
202190
}
203191

204192
// Convert isolation level to begin statement.
205-
const char *begin_statement = NULL;
193+
const char *level = NULL;
206194
if (isolation_level != NULL) {
207-
begin_statement = get_begin_statement(isolation_level);
208-
if (begin_statement == NULL) {
195+
level = get_isolation_level(isolation_level);
196+
if (level == NULL) {
209197
return -1;
210198
}
211199
}
@@ -227,7 +215,7 @@ pysqlite_connection_init_impl(pysqlite_Connection *self,
227215
self->db = db;
228216
self->state = state;
229217
self->detect_types = detect_types;
230-
self->begin_statement = begin_statement;
218+
self->isolation_level = level;
231219
self->check_same_thread = check_same_thread;
232220
self->thread_ident = PyThread_get_thread_ident();
233221
self->statement_cache = statement_cache;
@@ -1345,10 +1333,8 @@ static PyObject* pysqlite_connection_get_isolation_level(pysqlite_Connection* se
13451333
if (!pysqlite_check_connection(self)) {
13461334
return NULL;
13471335
}
1348-
if (self->begin_statement != NULL) {
1349-
const char *stmt = self->begin_statement;
1350-
const char *iso_level = begin_stmt_to_isolation_level(stmt);
1351-
return PyUnicode_FromString(iso_level);
1336+
if (self->isolation_level != NULL) {
1337+
return PyUnicode_FromString(self->isolation_level);
13521338
}
13531339
Py_RETURN_NONE;
13541340
}
@@ -1381,7 +1367,7 @@ pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* iso
13811367
return -1;
13821368
}
13831369
if (Py_IsNone(isolation_level)) {
1384-
self->begin_statement = NULL;
1370+
self->isolation_level = NULL;
13851371

13861372
// Execute a COMMIT to re-enable autocommit mode
13871373
PyObject *res = pysqlite_connection_commit_impl(self);
@@ -1400,11 +1386,11 @@ pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* iso
14001386
PyErr_SetString(PyExc_ValueError, "embedded null character");
14011387
return -1;
14021388
}
1403-
const char *stmt = get_begin_statement(cstr_level);
1404-
if (stmt == NULL) {
1389+
const char *level = get_isolation_level(cstr_level);
1390+
if (level == NULL) {
14051391
return -1;
14061392
}
1407-
self->begin_statement = stmt;
1393+
self->isolation_level = level;
14081394
}
14091395
else {
14101396
PyErr_SetString(PyExc_TypeError,

Modules/_sqlite/connection.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,15 @@ typedef struct _callback_context
4242
typedef struct
4343
{
4444
PyObject_HEAD
45-
sqlite3* db;
45+
sqlite3 *db;
4646
pysqlite_state *state;
4747

4848
/* the type detection mode. Only 0, PARSE_DECLTYPES, PARSE_COLNAMES or a
4949
* bitwise combination thereof makes sense */
5050
int detect_types;
5151

52-
/* NULL for autocommit, otherwise a string with the BEGIN statement */
53-
const char* begin_statement;
52+
/* NULL for autocommit, otherwise a string with the isolation level */
53+
const char *isolation_level;
5454

5555
/* 1 if a check should be performed for each API call if the connection is
5656
* used from the same thread it was created in */

Modules/_sqlite/cursor.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -430,12 +430,18 @@ static int check_cursor(pysqlite_Cursor* cur)
430430
static int
431431
begin_transaction(pysqlite_Connection *self)
432432
{
433+
assert(self->isolation_level != NULL);
433434
int rc;
434435

435436
Py_BEGIN_ALLOW_THREADS
436437
sqlite3_stmt *statement;
437-
rc = sqlite3_prepare_v2(self->db, self->begin_statement, -1, &statement,
438-
NULL);
438+
char begin_stmt[16] = "BEGIN ";
439+
#ifdef Py_DEBUG
440+
size_t len = strlen(self->isolation_level);
441+
assert(len <= 9);
442+
#endif
443+
(void)strcat(begin_stmt, self->isolation_level);
444+
rc = sqlite3_prepare_v2(self->db, begin_stmt, -1, &statement, NULL);
439445
if (rc == SQLITE_OK) {
440446
(void)sqlite3_step(statement);
441447
rc = sqlite3_finalize(statement);
@@ -555,7 +561,7 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
555561

556562
/* We start a transaction implicitly before a DML statement.
557563
SELECT is the only exception. See #9924. */
558-
if (self->connection->begin_statement
564+
if (self->connection->isolation_level
559565
&& self->statement->is_dml
560566
&& sqlite3_get_autocommit(self->connection->db))
561567
{

0 commit comments

Comments
 (0)