@@ -79,7 +79,6 @@ static const char * const begin_statements[] = {
79
79
NULL
80
80
};
81
81
82
- static int pysqlite_connection_set_isolation_level (pysqlite_Connection * self , PyObject * isolation_level , void * Py_UNUSED (ignored ));
83
82
static void _pysqlite_drop_unused_cursor_references (pysqlite_Connection * self );
84
83
static void free_callback_context (callback_context * ctx );
85
84
static void set_callback_context (callback_context * * ctx_pp ,
@@ -107,6 +106,30 @@ new_statement_cache(pysqlite_Connection *self, int maxsize)
107
106
return res ;
108
107
}
109
108
109
+ static inline const char *
110
+ begin_stmt_to_isolation_level (const char * begin_stmt )
111
+ {
112
+ assert (begin_stmt != NULL );
113
+
114
+ // All begin statements start with "BEGIN "; add strlen("BEGIN ") to get
115
+ // the isolation level.
116
+ return begin_stmt + 6 ;
117
+ }
118
+
119
+ static const char *
120
+ get_begin_statement (const char * level )
121
+ {
122
+ assert (level != NULL );
123
+ for (int i = 0 ; begin_statements [i ] != NULL ; i ++ ) {
124
+ const char * stmt = begin_statements [i ];
125
+ const char * candidate = begin_stmt_to_isolation_level (stmt );
126
+ if (sqlite3_stricmp (level , candidate ) == 0 ) {
127
+ return begin_statements [i ];
128
+ }
129
+ }
130
+ return NULL ;
131
+ }
132
+
110
133
/*[python input]
111
134
class FSConverter_converter(CConverter):
112
135
type = "const char *"
@@ -124,7 +147,7 @@ _sqlite3.Connection.__init__ as pysqlite_connection_init
124
147
database: FSConverter
125
148
timeout: double = 5.0
126
149
detect_types: int = 0
127
- isolation_level: object = NULL
150
+ isolation_level: str(accept={str, NoneType}) = ""
128
151
check_same_thread: bool(accept={int}) = True
129
152
factory: object(c_default='(PyObject*)clinic_state()->ConnectionType') = ConnectionType
130
153
cached_statements: int = 128
@@ -134,10 +157,10 @@ _sqlite3.Connection.__init__ as pysqlite_connection_init
134
157
static int
135
158
pysqlite_connection_init_impl (pysqlite_Connection * self ,
136
159
const char * database , double timeout ,
137
- int detect_types , PyObject * isolation_level ,
160
+ int detect_types , const char * isolation_level ,
138
161
int check_same_thread , PyObject * factory ,
139
162
int cached_statements , int uri )
140
- /*[clinic end generated code: output=bc39e55eb0b68783 input=f8d1f7efc0d84104 ]*/
163
+ /*[clinic end generated code: output=d8c37afc46d318b0 input=adfb29ac461f9e61 ]*/
141
164
{
142
165
int rc ;
143
166
@@ -148,8 +171,6 @@ pysqlite_connection_init_impl(pysqlite_Connection *self,
148
171
pysqlite_state * state = pysqlite_get_state_by_type (Py_TYPE (self ));
149
172
self -> state = state ;
150
173
151
- self -> begin_statement = NULL ;
152
-
153
174
Py_CLEAR (self -> statement_cache );
154
175
Py_CLEAR (self -> cursors );
155
176
@@ -174,20 +195,16 @@ pysqlite_connection_init_impl(pysqlite_Connection *self,
174
195
return -1 ;
175
196
}
176
197
177
- if (! isolation_level ) {
178
- isolation_level = PyUnicode_FromString ( "" );
179
- if (! isolation_level ) {
198
+ if (isolation_level ) {
199
+ const char * stmt = get_begin_statement ( isolation_level );
200
+ if (stmt == NULL ) {
180
201
return -1 ;
181
202
}
182
- } else {
183
- Py_INCREF (isolation_level );
203
+ self -> begin_statement = stmt ;
184
204
}
185
- Py_CLEAR (self -> isolation_level );
186
- if (pysqlite_connection_set_isolation_level (self , isolation_level , NULL ) != 0 ) {
187
- Py_DECREF (isolation_level );
188
- return -1 ;
205
+ else {
206
+ self -> begin_statement = NULL ;
189
207
}
190
- Py_DECREF (isolation_level );
191
208
192
209
self -> statement_cache = new_statement_cache (self , cached_statements );
193
210
if (self -> statement_cache == NULL ) {
@@ -268,7 +285,6 @@ static int
268
285
connection_traverse (pysqlite_Connection * self , visitproc visit , void * arg )
269
286
{
270
287
Py_VISIT (Py_TYPE (self ));
271
- Py_VISIT (self -> isolation_level );
272
288
Py_VISIT (self -> statement_cache );
273
289
Py_VISIT (self -> cursors );
274
290
Py_VISIT (self -> row_factory );
@@ -292,7 +308,6 @@ clear_callback_context(callback_context *ctx)
292
308
static int
293
309
connection_clear (pysqlite_Connection * self )
294
310
{
295
- Py_CLEAR (self -> isolation_level );
296
311
Py_CLEAR (self -> statement_cache );
297
312
Py_CLEAR (self -> cursors );
298
313
Py_CLEAR (self -> row_factory );
@@ -1317,7 +1332,12 @@ static PyObject* pysqlite_connection_get_isolation_level(pysqlite_Connection* se
1317
1332
if (!pysqlite_check_connection (self )) {
1318
1333
return NULL ;
1319
1334
}
1320
- return Py_NewRef (self -> isolation_level );
1335
+ if (self -> begin_statement != NULL ) {
1336
+ const char * stmt = self -> begin_statement ;
1337
+ const char * iso_level = begin_stmt_to_isolation_level (stmt );
1338
+ return PyUnicode_FromString (iso_level );
1339
+ }
1340
+ Py_RETURN_NONE ;
1321
1341
}
1322
1342
1323
1343
static PyObject * pysqlite_connection_get_total_changes (pysqlite_Connection * self , void * unused )
@@ -1347,53 +1367,40 @@ pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* iso
1347
1367
PyErr_SetString (PyExc_AttributeError , "cannot delete attribute" );
1348
1368
return -1 ;
1349
1369
}
1350
- if (isolation_level == Py_None ) {
1351
- /* We might get called during connection init, so we cannot use
1352
- * pysqlite_connection_commit() here. */
1353
- if (self -> db && !sqlite3_get_autocommit (self -> db )) {
1354
- int rc ;
1355
- Py_BEGIN_ALLOW_THREADS
1356
- rc = sqlite3_exec (self -> db , "COMMIT" , NULL , NULL , NULL );
1357
- Py_END_ALLOW_THREADS
1358
- if (rc != SQLITE_OK ) {
1359
- return _pysqlite_seterror (self -> state , self -> db );
1360
- }
1361
- }
1362
-
1370
+ if (Py_IsNone (isolation_level )) {
1363
1371
self -> begin_statement = NULL ;
1364
- } else {
1365
- const char * const * candidate ;
1366
- PyObject * uppercase_level ;
1367
- _Py_IDENTIFIER (upper );
1368
-
1369
- if (!PyUnicode_Check (isolation_level )) {
1370
- PyErr_Format (PyExc_TypeError ,
1371
- "isolation_level must be a string or None, not %.100s" ,
1372
- Py_TYPE (isolation_level )-> tp_name );
1372
+
1373
+ // Execute a COMMIT to re-enable autocommit mode
1374
+ PyObject * res = pysqlite_connection_commit_impl (self );
1375
+ if (res == NULL ) {
1373
1376
return -1 ;
1374
1377
}
1375
-
1376
- uppercase_level = _PyObject_CallMethodIdOneArg (
1377
- (PyObject * )& PyUnicode_Type , & PyId_upper ,
1378
- isolation_level );
1379
- if (!uppercase_level ) {
1378
+ Py_DECREF (res );
1379
+ }
1380
+ else if (PyUnicode_Check (isolation_level )) {
1381
+ Py_ssize_t len ;
1382
+ const char * cstr_level = PyUnicode_AsUTF8AndSize (isolation_level , & len );
1383
+ if (cstr_level == NULL ) {
1380
1384
return -1 ;
1381
1385
}
1382
- for ( candidate = begin_statements ; * candidate ; candidate ++ ) {
1383
- if ( _PyUnicode_EqualToASCIIString ( uppercase_level , * candidate + 6 ))
1384
- break ;
1386
+ if ( strlen ( cstr_level ) != ( size_t ) len ) {
1387
+ PyErr_SetString ( PyExc_ValueError , "embedded null character" );
1388
+ return -1 ;
1385
1389
}
1386
- Py_DECREF ( uppercase_level );
1387
- if (! * candidate ) {
1390
+ const char * stmt = get_begin_statement ( cstr_level );
1391
+ if (stmt == NULL ) {
1388
1392
PyErr_SetString (PyExc_ValueError ,
1389
- "invalid value for isolation_level" );
1393
+ "isolation_level string must be '', 'DEFERRED', "
1394
+ "'IMMEDIATE', or 'EXCLUSIVE'" );
1390
1395
return -1 ;
1391
1396
}
1392
- self -> begin_statement = * candidate ;
1397
+ self -> begin_statement = stmt ;
1398
+ }
1399
+ else {
1400
+ PyErr_SetString (PyExc_TypeError ,
1401
+ "isolation_level must be str or None" );
1402
+ return -1 ;
1393
1403
}
1394
-
1395
- Py_INCREF (isolation_level );
1396
- Py_XSETREF (self -> isolation_level , isolation_level );
1397
1404
return 0 ;
1398
1405
}
1399
1406
0 commit comments