Skip to content

Commit d542742

Browse files
author
Erlend Egeberg Aasland
authored
bpo-42064: Optimise sqlite3 state access, part 1 (GH-27273)
Prepare for module state: - Add "get state by defining class" and "get state by module def" stubs - Add AC defining class when needed - Add state pointer to connection context - Pass state as argument to utility functions Automerge-Triggered-By: GH:encukou
1 parent 47fd472 commit d542742

File tree

13 files changed

+103
-66
lines changed

13 files changed

+103
-66
lines changed

Modules/_sqlite/clinic/cursor.c.h

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -249,14 +249,25 @@ PyDoc_STRVAR(pysqlite_cursor_close__doc__,
249249
"Closes the cursor.");
250250

251251
#define PYSQLITE_CURSOR_CLOSE_METHODDEF \
252-
{"close", (PyCFunction)pysqlite_cursor_close, METH_NOARGS, pysqlite_cursor_close__doc__},
252+
{"close", (PyCFunction)(void(*)(void))pysqlite_cursor_close, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pysqlite_cursor_close__doc__},
253253

254254
static PyObject *
255-
pysqlite_cursor_close_impl(pysqlite_Cursor *self);
255+
pysqlite_cursor_close_impl(pysqlite_Cursor *self, PyTypeObject *cls);
256256

257257
static PyObject *
258-
pysqlite_cursor_close(pysqlite_Cursor *self, PyObject *Py_UNUSED(ignored))
258+
pysqlite_cursor_close(pysqlite_Cursor *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
259259
{
260-
return pysqlite_cursor_close_impl(self);
260+
PyObject *return_value = NULL;
261+
static const char * const _keywords[] = { NULL};
262+
static _PyArg_Parser _parser = {":close", _keywords, 0};
263+
264+
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser
265+
)) {
266+
goto exit;
267+
}
268+
return_value = pysqlite_cursor_close_impl(self, cls);
269+
270+
exit:
271+
return return_value;
261272
}
262-
/*[clinic end generated code: output=8f70eac5f8aa8d97 input=a9049054013a1b77]*/
273+
/*[clinic end generated code: output=7b216aba2439f5cf input=a9049054013a1b77]*/

Modules/_sqlite/connection.c

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ new_statement_cache(pysqlite_Connection *self, int maxsize)
6666
if (args[0] == NULL) {
6767
return NULL;
6868
}
69-
pysqlite_state *state = pysqlite_get_state(NULL);
70-
PyObject *inner = PyObject_Vectorcall(state->lru_cache, args, 1, NULL);
69+
PyObject *lru_cache = self->state->lru_cache;
70+
PyObject *inner = PyObject_Vectorcall(lru_cache, args, 1, NULL);
7171
Py_DECREF(args[0]);
7272
if (inner == NULL) {
7373
return NULL;
@@ -106,6 +106,9 @@ pysqlite_connection_init_impl(pysqlite_Connection *self,
106106
return -1;
107107
}
108108

109+
pysqlite_state *state = pysqlite_get_state_by_type(Py_TYPE(self));
110+
self->state = state;
111+
109112
const char *database = PyBytes_AsString(database_obj);
110113

111114
self->initialized = 1;
@@ -131,7 +134,7 @@ pysqlite_connection_init_impl(pysqlite_Connection *self,
131134
Py_DECREF(database_obj); // needed bco. the AC FSConverter
132135

133136
if (rc != SQLITE_OK) {
134-
_pysqlite_seterror(self->db);
137+
_pysqlite_seterror(state, self->db);
135138
return -1;
136139
}
137140

@@ -177,7 +180,6 @@ pysqlite_connection_init_impl(pysqlite_Connection *self,
177180
self->function_pinboard_progress_handler = NULL;
178181
self->function_pinboard_authorizer_cb = NULL;
179182

180-
pysqlite_state *state = pysqlite_get_state(NULL);
181183
self->Warning = state->Warning;
182184
self->Error = state->Error;
183185
self->InterfaceError = state->InterfaceError;
@@ -330,15 +332,14 @@ pysqlite_connection_cursor_impl(pysqlite_Connection *self, PyObject *factory)
330332
return NULL;
331333
}
332334

333-
pysqlite_state *state = pysqlite_get_state(NULL);
334335
if (factory == NULL) {
335-
factory = (PyObject *)state->CursorType;
336+
factory = (PyObject *)self->state->CursorType;
336337
}
337338

338339
cursor = PyObject_CallOneArg(factory, (PyObject *)self);
339340
if (cursor == NULL)
340341
return NULL;
341-
if (!PyObject_TypeCheck(cursor, state->CursorType)) {
342+
if (!PyObject_TypeCheck(cursor, self->state->CursorType)) {
342343
PyErr_Format(PyExc_TypeError,
343344
"factory must return a cursor, not %.100s",
344345
Py_TYPE(cursor)->tp_name);
@@ -383,15 +384,15 @@ pysqlite_connection_close_impl(pysqlite_Connection *self)
383384
*/
384385
int pysqlite_check_connection(pysqlite_Connection* con)
385386
{
386-
pysqlite_state *state = pysqlite_get_state(NULL);
387387
if (!con->initialized) {
388+
pysqlite_state *state = pysqlite_get_state_by_type(Py_TYPE(con));
388389
PyErr_SetString(state->ProgrammingError,
389390
"Base Connection.__init__ not called.");
390391
return 0;
391392
}
392393

393394
if (!con->db) {
394-
PyErr_SetString(state->ProgrammingError,
395+
PyErr_SetString(con->state->ProgrammingError,
395396
"Cannot operate on a closed database.");
396397
return 0;
397398
} else {
@@ -422,20 +423,20 @@ pysqlite_connection_commit_impl(pysqlite_Connection *self)
422423
rc = sqlite3_prepare_v2(self->db, "COMMIT", 7, &statement, NULL);
423424
Py_END_ALLOW_THREADS
424425
if (rc != SQLITE_OK) {
425-
_pysqlite_seterror(self->db);
426+
_pysqlite_seterror(self->state, self->db);
426427
goto error;
427428
}
428429

429430
rc = pysqlite_step(statement);
430431
if (rc != SQLITE_DONE) {
431-
_pysqlite_seterror(self->db);
432+
_pysqlite_seterror(self->state, self->db);
432433
}
433434

434435
Py_BEGIN_ALLOW_THREADS
435436
rc = sqlite3_finalize(statement);
436437
Py_END_ALLOW_THREADS
437438
if (rc != SQLITE_OK && !PyErr_Occurred()) {
438-
_pysqlite_seterror(self->db);
439+
_pysqlite_seterror(self->state, self->db);
439440
}
440441

441442
}
@@ -472,20 +473,20 @@ pysqlite_connection_rollback_impl(pysqlite_Connection *self)
472473
rc = sqlite3_prepare_v2(self->db, "ROLLBACK", 9, &statement, NULL);
473474
Py_END_ALLOW_THREADS
474475
if (rc != SQLITE_OK) {
475-
_pysqlite_seterror(self->db);
476+
_pysqlite_seterror(self->state, self->db);
476477
goto error;
477478
}
478479

479480
rc = pysqlite_step(statement);
480481
if (rc != SQLITE_DONE) {
481-
_pysqlite_seterror(self->db);
482+
_pysqlite_seterror(self->state, self->db);
482483
}
483484

484485
Py_BEGIN_ALLOW_THREADS
485486
rc = sqlite3_finalize(statement);
486487
Py_END_ALLOW_THREADS
487488
if (rc != SQLITE_OK && !PyErr_Occurred()) {
488-
_pysqlite_seterror(self->db);
489+
_pysqlite_seterror(self->state, self->db);
489490
}
490491

491492
}
@@ -1672,7 +1673,7 @@ pysqlite_connection_backup_impl(pysqlite_Connection *self,
16721673
Py_END_ALLOW_THREADS
16731674

16741675
if (bck_handle == NULL) {
1675-
_pysqlite_seterror(bck_conn);
1676+
_pysqlite_seterror(self->state, bck_conn);
16761677
return NULL;
16771678
}
16781679

@@ -1710,7 +1711,7 @@ pysqlite_connection_backup_impl(pysqlite_Connection *self,
17101711
Py_END_ALLOW_THREADS
17111712

17121713
if (rc != SQLITE_OK) {
1713-
_pysqlite_seterror(bck_conn);
1714+
_pysqlite_seterror(self->state, bck_conn);
17141715
return NULL;
17151716
}
17161717

@@ -1762,7 +1763,7 @@ pysqlite_connection_create_collation_impl(pysqlite_Connection *self,
17621763
if (callable != Py_None) {
17631764
Py_DECREF(callable);
17641765
}
1765-
_pysqlite_seterror(self->db);
1766+
_pysqlite_seterror(self->state, self->db);
17661767
return NULL;
17671768
}
17681769

Modules/_sqlite/connection.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ typedef struct
3636
{
3737
PyObject_HEAD
3838
sqlite3* db;
39+
pysqlite_state *state;
3940

4041
/* the type detection mode. Only 0, PARSE_DECLTYPES, PARSE_COLNAMES or a
4142
* bitwise combination thereof makes sense */

Modules/_sqlite/cursor.c

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,8 @@ cursor_dealloc(pysqlite_Cursor *self)
130130
}
131131

132132
static PyObject *
133-
_pysqlite_get_converter(const char *keystr, Py_ssize_t keylen)
133+
_pysqlite_get_converter(pysqlite_state *state, const char *keystr,
134+
Py_ssize_t keylen)
134135
{
135136
PyObject *key;
136137
PyObject *upcase_key;
@@ -147,7 +148,6 @@ _pysqlite_get_converter(const char *keystr, Py_ssize_t keylen)
147148
return NULL;
148149
}
149150

150-
pysqlite_state *state = pysqlite_get_state(NULL);
151151
retval = PyDict_GetItemWithError(state->converters, upcase_key);
152152
Py_DECREF(upcase_key);
153153

@@ -187,7 +187,9 @@ pysqlite_build_row_cast_map(pysqlite_Cursor* self)
187187
type_start = pos + 1;
188188
}
189189
else if (*pos == ']' && type_start != NULL) {
190-
converter = _pysqlite_get_converter(type_start, pos - type_start);
190+
pysqlite_state *state = self->connection->state;
191+
converter = _pysqlite_get_converter(state, type_start,
192+
pos - type_start);
191193
if (!converter && PyErr_Occurred()) {
192194
Py_CLEAR(self->row_cast_map);
193195
return -1;
@@ -206,7 +208,9 @@ pysqlite_build_row_cast_map(pysqlite_Cursor* self)
206208
* 'NUMBER(10)' to be treated as 'NUMBER', for example.
207209
* In other words, it will work as people expect it to work.*/
208210
if (*pos == ' ' || *pos == '(' || *pos == 0) {
209-
converter = _pysqlite_get_converter(decltype, pos - decltype);
211+
pysqlite_state *state = self->connection->state;
212+
converter = _pysqlite_get_converter(state, decltype,
213+
pos - decltype);
210214
if (!converter && PyErr_Occurred()) {
211215
Py_CLEAR(self->row_cast_map);
212216
return -1;
@@ -404,22 +408,21 @@ _pysqlite_fetch_one_row(pysqlite_Cursor* self)
404408
*/
405409
static int check_cursor(pysqlite_Cursor* cur)
406410
{
407-
pysqlite_state *state = pysqlite_get_state(NULL);
408-
409411
if (!cur->initialized) {
412+
pysqlite_state *state = pysqlite_get_state_by_type(Py_TYPE(cur));
410413
PyErr_SetString(state->ProgrammingError,
411414
"Base Cursor.__init__ not called.");
412415
return 0;
413416
}
414417

415418
if (cur->closed) {
416-
PyErr_SetString(state->ProgrammingError,
419+
PyErr_SetString(cur->connection->state->ProgrammingError,
417420
"Cannot operate on a closed cursor.");
418421
return 0;
419422
}
420423

421424
if (cur->locked) {
422-
PyErr_SetString(state->ProgrammingError,
425+
PyErr_SetString(cur->connection->state->ProgrammingError,
423426
"Recursive use of cursors not allowed.");
424427
return 0;
425428
}
@@ -439,7 +442,7 @@ begin_transaction(pysqlite_Connection *self)
439442
Py_END_ALLOW_THREADS
440443

441444
if (rc != SQLITE_OK) {
442-
_pysqlite_seterror(self->db);
445+
_pysqlite_seterror(self->state, self->db);
443446
goto error;
444447
}
445448

@@ -449,7 +452,7 @@ begin_transaction(pysqlite_Connection *self)
449452
Py_END_ALLOW_THREADS
450453

451454
if (rc != SQLITE_OK && !PyErr_Occurred()) {
452-
_pysqlite_seterror(self->db);
455+
_pysqlite_seterror(self->state, self->db);
453456
}
454457

455458
error:
@@ -470,7 +473,6 @@ get_statement_from_cache(pysqlite_Cursor *self, PyObject *operation)
470473
static PyObject *
471474
_pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation, PyObject* second_argument)
472475
{
473-
pysqlite_state *state = pysqlite_get_state(NULL);
474476
PyObject* parameters_list = NULL;
475477
PyObject* parameters_iter = NULL;
476478
PyObject* parameters = NULL;
@@ -568,6 +570,7 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
568570
}
569571
}
570572

573+
pysqlite_state *state = self->connection->state;
571574
while (1) {
572575
parameters = PyIter_Next(parameters_iter);
573576
if (!parameters) {
@@ -576,7 +579,7 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
576579

577580
pysqlite_statement_mark_dirty(self->statement);
578581

579-
pysqlite_statement_bind_parameters(self->statement, parameters);
582+
pysqlite_statement_bind_parameters(state, self->statement, parameters);
580583
if (PyErr_Occurred()) {
581584
goto error;
582585
}
@@ -592,12 +595,12 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
592595
}
593596
}
594597
(void)pysqlite_statement_reset(self->statement);
595-
_pysqlite_seterror(self->connection->db);
598+
_pysqlite_seterror(state, self->connection->db);
596599
goto error;
597600
}
598601

599602
if (pysqlite_build_row_cast_map(self) != 0) {
600-
_PyErr_FormatFromCause(self->connection->OperationalError,
603+
_PyErr_FormatFromCause(state->OperationalError,
601604
"Error while building row_cast_map");
602605
goto error;
603606
}
@@ -651,7 +654,7 @@ _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* operation
651654

652655
if (rc == SQLITE_ROW) {
653656
if (multiple) {
654-
PyErr_SetString(self->connection->ProgrammingError,
657+
PyErr_SetString(state->ProgrammingError,
655658
"executemany() can only execute DML "
656659
"statements.");
657660
goto error;
@@ -773,6 +776,7 @@ pysqlite_cursor_executescript(pysqlite_Cursor *self, PyObject *script_obj)
773776
}
774777
Py_DECREF(result);
775778

779+
pysqlite_state *state = self->connection->state;
776780
while (1) {
777781
const char *tail;
778782

@@ -784,7 +788,7 @@ pysqlite_cursor_executescript(pysqlite_Cursor *self, PyObject *script_obj)
784788
&tail);
785789
Py_END_ALLOW_THREADS
786790
if (rc != SQLITE_OK) {
787-
_pysqlite_seterror(self->connection->db);
791+
_pysqlite_seterror(state, self->connection->db);
788792
goto error;
789793
}
790794

@@ -799,13 +803,13 @@ pysqlite_cursor_executescript(pysqlite_Cursor *self, PyObject *script_obj)
799803

800804
if (rc != SQLITE_DONE) {
801805
(void)sqlite3_finalize(statement);
802-
_pysqlite_seterror(self->connection->db);
806+
_pysqlite_seterror(state, self->connection->db);
803807
goto error;
804808
}
805809

806810
rc = sqlite3_finalize(statement);
807811
if (rc != SQLITE_OK) {
808-
_pysqlite_seterror(self->connection->db);
812+
_pysqlite_seterror(state, self->connection->db);
809813
goto error;
810814
}
811815

@@ -874,7 +878,7 @@ pysqlite_cursor_iternext(pysqlite_Cursor *self)
874878
if (rc != SQLITE_DONE && rc != SQLITE_ROW) {
875879
(void)pysqlite_statement_reset(self->statement);
876880
Py_DECREF(next_row);
877-
_pysqlite_seterror(self->connection->db);
881+
_pysqlite_seterror(self->connection->state, self->connection->db);
878882
return NULL;
879883
}
880884

@@ -1023,15 +1027,17 @@ pysqlite_cursor_setoutputsize_impl(pysqlite_Cursor *self, PyObject *size,
10231027
/*[clinic input]
10241028
_sqlite3.Cursor.close as pysqlite_cursor_close
10251029
1030+
cls: defining_class
1031+
10261032
Closes the cursor.
10271033
[clinic start generated code]*/
10281034

10291035
static PyObject *
1030-
pysqlite_cursor_close_impl(pysqlite_Cursor *self)
1031-
/*[clinic end generated code: output=b6055e4ec6fe63b6 input=08b36552dbb9a986]*/
1036+
pysqlite_cursor_close_impl(pysqlite_Cursor *self, PyTypeObject *cls)
1037+
/*[clinic end generated code: output=a08ab3d772f45438 input=28ba9b532ab46ba0]*/
10321038
{
10331039
if (!self->connection) {
1034-
pysqlite_state *state = pysqlite_get_state(NULL);
1040+
pysqlite_state *state = pysqlite_get_state_by_cls(cls);
10351041
PyErr_SetString(state->ProgrammingError,
10361042
"Base Cursor.__init__ not called.");
10371043
return NULL;

0 commit comments

Comments
 (0)