8000 bpo-40956: Convert sqlite3.connect and sqlite3.Connection.__init__ to… · python/cpython@185ecdc · GitHub
[go: up one dir, main page]

Skip to content

Commit 185ecdc

Browse files
author
Erlend Egeberg Aasland
authored
bpo-40956: Convert sqlite3.connect and sqlite3.Connection.__init__ to AC (GH-24421)
1 parent 09eb817 commit 185ecdc

File tree

6 files changed

+298
-71
lines changed

6 files changed

+298
-71
lines changed

Lib/sqlite3/test/dbapi.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import unittest
2828

2929
from test.support.os_helper import TESTFN, unlink
30+
from test.support import threading_helper
3031

3132

3233
# Helper for tests using TESTFN
@@ -224,6 +225,10 @@ def test_open_uri(self):
224225
with managed_connect(f"file:{TESTFN}?mode=ro", uri=True) as cx:
225226
cx.execute(self._sql)
226227

228+
def test_database_keyword(self):
229+
with sqlite.connect(database=":memory:") as cx:
230+
self.assertEqual(type(cx), sqlite.Connection)
231+
227232

228233
class CursorTests(unittest.TestCase):
229234
def setUp(self):
@@ -724,6 +729,22 @@ def run(cur, errors):
724729
if len(errors) > 0:
725730
self.fail("\n".join(errors))
726731

732+
@threading_helper.reap_threads
733+
def test_dont_check_same_thread(self):
734+
def run(con, err):
735+
try:
736+
con.execute("select 1")
737+
except sqlite.Error:
738+
err.append("multi-threading not allowed")
739+
740+
con = sqlite.connect(":memory:", check_same_thread=False)
741+
err = []
742+
t = threading.Thread(target=run, kwargs={"con": con, "err": err})
743+
t.start()
744+
t.join()
745+
self.assertEqual(len(err), 0, "\n".join(err))
746+
747+
727748
class ConstructorTests(unittest.TestCase):
728749
def test_date(self):
729750
d = sqlite.Date(2004, 10, 28)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Use Argument Clinic in :mod:`sqlite3`. Patches by Erlend E. Aasland.

Modules/_sqlite/clinic/connection.c.h

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,107 @@
22
preserve
33
[clinic start generated code]*/
44

5+
static int
6+
pysqlite_connection_init_impl(pysqlite_Connection *self,
7+
PyObject *database_obj, double timeout,
8+
int detect_types, PyObject *isolation_level,
9+
int check_same_thread, PyObject *factory,
10+
int cached_statements, int uri);
11+
12+
static int
13+
pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs)
14+
{
15+
int return_value = -1;
16+
static const char * const _keywords[] = {"database", "timeout", "detect_types", "isolation_level", "check_same_thread", "factory", "cached_statements", "uri", NULL};
17+
static _PyArg_Parser _parser = {NULL, _keywords, "Connection", 0};
18+
PyObject *argsbuf[8];
19+
PyObject * const *fastargs;
20+
Py_ssize_t nargs = PyTuple_GET_SIZE(args);
21+
Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1;
22+
PyObject *database_obj;
23+
double timeout = 5.0;
24+
int detect_types = 0;
25+
PyObject *isolation_level = NULL;
26+
int check_same_thread = 1;
27+
PyObject *factory = (PyObject*)clinic_state()->ConnectionType;
28+
int cached_statements = 128;
29+
int uri = 0;
30+
31+
fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 8, 0, argsbuf);
32+
if (!fastargs) {
33+
goto exit;
34+
}
35+
if (!PyUnicode_FSConverter(fastargs[0], &database_obj)) {
36+
goto exit;
37+
}
38+
if (!noptargs) {
39+
goto skip_optional_pos;
< F438 code>40+
}
41+
if (fastargs[1]) {
42+
if (PyFloat_CheckExact(fastargs[1])) {
43+
timeout = PyFloat_AS_DOUBLE(fastargs[1]);
44+
}
45+
else
46+
{
47+
timeout = PyFloat_AsDouble(fastargs[1]);
48+
if (timeout == -1.0 && PyErr_Occurred()) {
49+
goto exit;
50+
}
51+
}
52+
if (!--noptargs) {
53+
goto skip_optional_pos;
54+
}
55+
}
56+
if (fastargs[2]) {
57+
detect_types = _PyLong_AsInt(fastargs[2]);
58+
if (detect_types == -1 && PyErr_Occurred()) {
59+
goto exit;
60+
}
61+
if (!--noptargs) {
62+
goto skip_optional_pos;
63+
}
64+
}
65+
if (fastargs[3]) {
66+
isolation_level = fastargs[3];
67+
if (!--noptargs) {
68+
goto skip_optional_pos;
69+
}
70+
}
71+
if (fastargs[4]) {
72+
check_same_thread = _PyLong_AsInt(fastargs[4]);
73+
if (check_same_thread == -1 && PyErr_Occurred()) {
74+
goto exit;
75+
}
76+
if (!--noptargs) {
77+
goto skip_optional_pos;
78+
}
79+
}
80+
if (fastargs[5]) {
81+
factory = fastargs[5];
82+
if (!--noptargs) {
83+
goto skip_optional_pos;
84+
}
85+
}
86+
if (fastargs[6]) {
87+
cached_statements = _PyLong_AsInt(fastargs[6]);
88+
if (cached_statements == -1 && PyErr_Occurred()) {
89+
goto exit;
90+
}
91+
if (!--noptargs) {
92+
goto skip_optional_pos;
93+
}
94+
}
95+
uri = PyObject_IsTrue(fastargs[7]);
96+
if (uri < 0) {
97+
goto exit;
98+
}
99+
skip_optional_pos:
100+
return_value = pysqlite_connection_init_impl((pysqlite_Connection *)self, database_obj, timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements, uri);
101+
102+
exit:
103+
return return_value;
104+
}
105+
5106
PyDoc_STRVAR(pysqlite_connection_cursor__doc__,
6107
"cursor($self, /, factory=<unrepresentable>)\n"
7108
"--\n"
@@ -710,4 +811,4 @@ pysqlite_connection_exit(pysqlite_Connection *self, PyObject *const *args, Py_ss
710811
#ifndef PYSQLITE_CONNECTION_LOAD_EXTENSION_METHODDEF
711812
#define PYSQLITE_CONNECTION_LOAD_EXTENSION_METHODDEF
712813
#endif /* !defined(PYSQLITE_CONNECTION_LOAD_EXTENSION_METHODDEF) */
713-
/*[clinic end generated code: output=1ee2f6173f4acec3 input=a9049054013a1b77]*/
814+
/*[clinic end generated code: output=c350732a2758c8c1 input=a9049054013a1b77]*/

Modules/_sqlite/clinic/module.c.h

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,118 @@
22
preserve
33
[clinic start generated code]*/
44

5+
PyDoc_STRVAR(pysqlite_connect__doc__,
6+
"connect($module, /, database, timeout=5.0, detect_types=0,\n"
7+
" isolation_level=<unrepresentable>, check_same_thread=True,\n"
8+
" factory=ConnectionType, cached_statements=128, uri=False)\n"
9+
"--\n"
10+
"\n"
11+
"Opens a connection to the SQLite database file database.\n"
12+
"\n"
13+
"You can use \":memory:\" to open a database connection to a database that resides\n"
14+
"in RAM instead of on disk.");
15+
16+
#define PYSQLITE_CONNECT_METHODDEF \
17+
{"connect", (PyCFunction)(void(*)(void))pysqlite_connect, METH_FASTCALL|METH_KEYWORDS, pysqlite_connect__doc__},
18+
19+
static PyObject *
20+
pysqlite_connect_impl(PyObject *module, PyObject *database, double timeout,
21+
int detect_types, PyObject *isolation_level,
22+
int check_same_thread, PyObject *factory,
23+
int cached_statements, int uri);
24+
25+
static PyObject *
26+
pysqlite_connect(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
27+
{
28+
PyObject *return_value = NULL;
29+
static const char * const _keywords[] = {"database", "timeout", "detect_types", "isolation_level", "check_same_thread", "factory", "cached_statements", "uri", NULL};
30+
static _PyArg_Parser _parser = {NULL, _keywords, "connect", 0};
31+
PyObject *argsbuf[8];
32+
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1;
33+
PyObject *database;
34+
double timeout = 5.0;
35+
int detect_types = 0;
36+
PyObject *isolation_level = NULL;
37+
int check_same_thread = 1;
38+
PyObject *factory = (PyObject*)clinic_state()->ConnectionType;
39+
int cached_statements = 128;
40+
int uri = 0;
41+
42+
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 8, 0, argsbuf);
43+
if (!args) {
44+
goto exit;
45+
}
46+
if (!PyUnicode_FSConverter(args[0], &database)) {
47+
goto exit;
48+
}
49+
if (!noptargs) {
50+
goto skip_optional_pos;
51+
}
52+
if (args[1]) {
53+
if (PyFloat_CheckExact(args[1])) {
54+
timeout = PyFloat_AS_DOUBLE(args[1]);
55+
}
56+
else
57+
{
58+
timeout = PyFloat_AsDouble(args[1]);
59+
if (timeout == -1.0 && PyErr_Occurred()) {
60+
goto exit;
61+
}
62+
}
63+
if (!--noptargs) {
64+
goto skip_optional_pos;
65+
}
66+
}
67+
if (args[2]) {
68+
detect_types = _PyLong_AsInt(args[2]);
69+
if (detect_types == -1 && PyErr_Occurred()) {
70+
goto exit;
71+
}
72+
if (!--noptargs) {
73+
goto skip_optional_pos;
74+
}
75+
}
76+
if (args[3]) {
77+
isolation_level = args[3];
78+
if (!--noptargs) {
79+
goto skip_optional_pos;
80+
}
81+
}
82+
if (args[4]) {
83+
check_same_thread = _PyLong_AsInt(args[4]);
84+
if (check_same_thread == -1 && PyErr_Occurred()) {
85+
goto exit;
86+
}
87+
if (!--noptargs) {
88+
goto skip_optional_pos;
89+
}
90+
}
91+
if (args[5]) {
92+
factory = args[5];
93+
if (!--noptargs) {
94+
goto skip_optional_pos;
95+
}
96+
}
97+
if (args[6]) {
98+
cached_statements = _PyLong_AsInt(args[6]);
99+
if (cached_statements == -1 && PyErr_Occurred()) {
100+
goto exit;
101+
}
102+
if (!--noptargs) {
103+
goto skip_optional_pos;
104+
}
105+
}
106+
uri = PyObject_IsTrue(args[7]);
107+
if (uri < 0) {
108+
goto exit;
109+
}
110+
skip_optional_pos:
111+
return_value = pysqlite_connect_impl(module, database, timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements, uri);
112+
113+
exit:
114+
return return_value;
115+
}
116+
5117
PyDoc_STRVAR(pysqlite_complete_statement__doc__,
6118
"complete_statement($module, /, statement)\n"
7119
"--\n"
@@ -219,4 +331,4 @@ pysqlite_adapt(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
219331
exit:
220332
return return_value;
221333
}
222-
/*[clinic end generated code: output=e9c2442673289cab input=a9049054013a1b77]*/
334+
/*[clinic end generated code: output=ef03fdbf018d3391 input=a9049054013a1b77]*/

Modules/_sqlite/connection.c

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -79,40 +79,34 @@ new_statement_cache(pysqlite_Connection *self, int maxsize)
7979
return res;
8080
}
8181

82+
/*[clinic input]
83+
_sqlite3.Connection.__init__ as pysqlite_connection_init
84+
85+
database as database_obj: object(converter='PyUnicode_FSConverter')
86+
timeout: double = 5.0
87+
detect_types: int = 0
88+
isolation_level: object = NULL
89+
check_same_thread: bool(accept={int}) = True
90+
factory: object(c_default='(PyObject*)clinic_state()->ConnectionType') = ConnectionType
91+
cached_statements: int = 128
92+
uri: bool = False
93+
[clinic start generated code]*/
94+
8295
static int
83-
pysqlite_connection_init(pysqlite_Connection *self, PyObject *args,
84-
PyObject *kwargs)
96+
pysqlite_connection_init_impl(pysqlite_Connection *self,
97+
PyObject *database_obj, double timeout,
98+
int detect_types, PyObject *isolation_level,
99+
int check_same_thread, PyObject *factory,
100+
int cached_statements, int uri)
101+
/*[clinic end generated code: output=dc19df1c0e2b7b77 input=aa1f21bf12fe907a]*/
85102
{
86-
static char *kwlist[] = {
87-
"database", "timeout", "detect_types", "isolation_level",
88-
"check_same_thread", "factory", "cached_statements", "uri",
89-
NULL
90-
};
91-
92-
const char* database;
93-
PyObject* database_obj;
94-
int detect_types = 0;
95-
PyObject* isolation_level = NULL;
96-
PyObject* factory = NULL;
97-
int check_same_thread = 1;
98-
int cached_statements = 128;
99-
int uri = 0;
100-
double timeout = 5.0;
101103
int rc;
102104

103-
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|diOiOip", kwlist,
104-
PyUnicode_FSConverter, &database_obj, &timeout, &detect_types,
105-
&isolation_level, &check_same_thread,
106-
&factory, &cached_statements, &uri))
107-
{
108-
return -1;
109-
}
110-
111105
if (PySys_Audit("sqlite3.connect", "O", database_obj) < 0) {
112106
return -1;
113107
}
114108

115-
database = PyBytes_AsString(database_obj);
109+
const char *database = PyBytes_AsString(database_obj);
116110

117111
self->initialized = 1;
118112

@@ -134,7 +128,7 @@ pysqlite_connection_init(pysqlite_Connection *self, PyObject *args,
134128
(uri ? SQLITE_OPEN_URI : 0), NULL);
135129
Py_END_ALLOW_THREADS
136130

137-
Py_DECREF(database_obj);
131+
Py_DECREF(database_obj); // needed bco. the AC FSConverter
138132

139133
if (rc != SQLITE_OK) {
140134
_pysqlite_seterror(self->db);

0 commit comments

Comments
 (0)
0