diff options
author | Dong-hee Na <donghee.na@python.org> | 2021-11-17 12:47:02 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-17 12:47:02 (GMT) |
commit | e002bbc6cce637171fb2b1391ffeca8643a13843 (patch) | |
tree | 9fa5776ee2ecca75ee4b951b435905df74ed20c7 /Modules | |
parent | 5f9247e36a0213b0dcfd43533db5cf6570895cfd (diff) | |
download | cpython-e002bbc6cce637171fb2b1391ffeca8643a13843.zip cpython-e002bbc6cce637171fb2b1391ffeca8643a13843.tar.gz cpython-e002bbc6cce637171fb2b1391ffeca8643a13843.tar.bz2 |
bpo-45512: Simplify manage isolation level (GH-29562)
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_sqlite/connection.c | 56 | ||||
-rw-r--r-- | Modules/_sqlite/connection.h | 6 | ||||
-rw-r--r-- | Modules/_sqlite/cursor.c | 12 |
3 files changed, 33 insertions, 41 deletions
diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index e794767..f632e33 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -71,14 +71,6 @@ class _sqlite3.Connection "pysqlite_Connection *" "clinic_state()->ConnectionTyp _Py_IDENTIFIER(cursor); -static const char * const begin_statements[] = { - "BEGIN ", - "BEGIN DEFERRED", - "BEGIN IMMEDIATE", - "BEGIN EXCLUSIVE", - NULL -}; - static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self); static void free_callback_context(callback_context *ctx); static void set_callback_context(callback_context **ctx_pp, @@ -108,25 +100,21 @@ new_statement_cache(pysqlite_Connection *self, pysqlite_state *state, return res; } -static inline const char * -begin_stmt_to_isolation_level(const char *begin_stmt) -{ - assert(begin_stmt != NULL); - - // All begin statements start with "BEGIN "; add strlen("BEGIN ") to get - // the isolation level. - return begin_stmt + 6; -} - static const char * -get_begin_statement(const char *level) +get_isolation_level(const char *level) { assert(level != NULL); - for (int i = 0; begin_statements[i] != NULL; i++) { - const char *stmt = begin_statements[i]; - const char *candidate = begin_stmt_to_isolation_level(stmt); + static const char *const allowed_levels[] = { + "", + "DEFERRED", + "IMMEDIATE", + "EXCLUSIVE", + NULL + }; + for (int i = 0; allowed_levels[i] != NULL; i++) { + const char *candidate = allowed_levels[i]; if (sqlite3_stricmp(level, candidate) == 0) { - return begin_statements[i]; + return candidate; } } PyErr_SetString(PyExc_ValueError, @@ -202,10 +190,10 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, } // Convert isolation level to begin statement. - const char *begin_statement = NULL; + const char *level = NULL; if (isolation_level != NULL) { - begin_statement = get_begin_statement(isolation_level); - if (begin_statement == NULL) { + level = get_isolation_level(isolation_level); + if (level == NULL) { return -1; } } @@ -227,7 +215,7 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, self->db = db; self->state = state; self->detect_types = detect_types; - self->begin_statement = begin_statement; + self->isolation_level = level; self->check_same_thread = check_same_thread; self->thread_ident = PyThread_get_thread_ident(); self->statement_cache = statement_cache; @@ -1345,10 +1333,8 @@ static PyObject* pysqlite_connection_get_isolation_level(pysqlite_Connection* se if (!pysqlite_check_connection(self)) { return NULL; } - if (self->begin_statement != NULL) { - const char *stmt = self->begin_statement; - const char *iso_level = begin_stmt_to_isolation_level(stmt); - return PyUnicode_FromString(iso_level); + if (self->isolation_level != NULL) { + return PyUnicode_FromString(self->isolation_level); } Py_RETURN_NONE; } @@ -1381,7 +1367,7 @@ pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* iso return -1; } if (Py_IsNone(isolation_level)) { - self->begin_statement = NULL; + self->isolation_level = NULL; // Execute a COMMIT to re-enable autocommit mode PyObject *res = pysqlite_connection_commit_impl(self); @@ -1400,11 +1386,11 @@ pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* iso PyErr_SetString(PyExc_ValueError, "embedded null character"); return -1; } - const char *stmt = get_begin_statement(cstr_level); - if (stmt == NULL) { + const char *level = get_isolation_level(cstr_level); + if (level == NULL) { return -1; } - self->begin_statement = stmt; + self->isolation_level = level; } else { PyErr_SetString(PyExc_TypeError, diff --git a/Modules/_sqlite/connection.h b/Modules/_sqlite/connection.h index 7baf63f..84f1f09 100644 --- a/Modules/_sqlite/connection.h +++ b/Modules/_sqlite/connection.h @@ -42,15 +42,15 @@ typedef struct _callback_context typedef struct { PyObject_HEAD - sqlite3* db; + sqlite3 *db; pysqlite_state *state; /* the type detection mode. Only 0, PARSE_DECLTYPES, PARSE_COLNAMES or a * bitwise combination thereof makes sense */ int detect_types; - /* NULL for autocommit, otherwise a string with the BEGIN statement */ - const char* begin_statement; + /* NULL for autocommit, otherwise a string with the isolation level */ + const char *isolation_level; /* 1 if a check should be performed for each API call if the connection is * used from the same thread it was created in */ diff --git a/Modules/_sqlite/cursor.c b/Modules/_sqlite/cursor.c index 3ee1c5d..e475d93 100644 --- a/Modules/_sqlite/cursor.c +++ b/Modules/_sqlite/cursor.c @@ -430,12 +430,18 @@ static int check_cursor(pysqlite_Cursor* cur) static int begin_transaction(pysqlite_Connection *self) { + assert(self->isolation_level != NULL); int rc; Py_BEGIN_ALLOW_THREADS sqlite3_stmt *statement; - rc = sqlite3_prepare_v2(self->db, self->begin_statement, -1, &statement, - NULL); + char begin_stmt[16] = "BEGIN "; +#ifdef Py_DEBUG + size_t len = strlen(self->isolation_level); + assert(len <= 9); +#endif + (void)strcat(begin_stmt, self->isolation_level); + rc = sqlite3_prepare_v2(self->db, begin_stmt, -1, &statement, NULL); if (rc == SQLITE_OK) { (void)sqlite3_step(statement); rc = sqlite3_finalize(statement); @@ -555,7 +561,7 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation /* We start a transaction implicitly before a DML statement. SELECT is the only exception. See #9924. */ - if (self->connection->begin_statement + if (self->connection->isolation_level && self->statement->is_dml && sqlite3_get_autocommit(self->connection->db)) { |