From dbfbf42fde445b7fc91aa96a7cd5f74e834e7099 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 18 May 2022 17:10:53 +0300 Subject: [PATCH 1/8] gh-91922: Fix sqlite connection on nonstardard locales and paths * Fix function sqlite.connect() and the sqlite.Connection constructor on non-UTF-8 locales. * Fix support of bytes paths non-decodable with the current FS encoding. --- Lib/test/test_sqlite3/test_dbapi.py | 41 +++++++++----- ...2-05-18-17-18-41.gh-issue-91922.DwWIsJ.rst | 3 ++ Modules/_sqlite/clinic/connection.c.h | 17 +++--- Modules/_sqlite/clinic/module.c.h | 6 +-- Modules/_sqlite/connection.c | 54 +++++-------------- Modules/_sqlite/module.c | 8 +-- 6 files changed, 55 insertions(+), 74 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2022-05-18-17-18-41.gh-issue-91922.DwWIsJ.rst diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index 8a218973794db9..5980c24833f68f 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -21,21 +21,18 @@ # 3. This notice may not be removed or altered from any source distribution. import contextlib +import os import sqlite3 as sqlite import subprocess import sys import threading import unittest -from test.support import ( - SHORT_TIMEOUT, - bigmemtest, - check_disallow_instantiation, - threading_helper, -) +from test.support import SHORT_TIMEOUT, bigmemtest, check_disallow_instantiation +from test.support import threading_helper from _testcapi import INT_MAX, ULLONG_MAX from os import SEEK_SET, SEEK_CUR, SEEK_END -from test.support.os_helper import TESTFN, unlink, temp_dir +from test.support.os_helper import TESTFN, TESTFN_UNDECODABLE, unlink, temp_dir, FakePath # Helper for tests using TESTFN @@ -654,20 +651,36 @@ class OpenTests(unittest.TestCase): def test_open_with_path_like_object(self): """ Checks that we can successfully connect to a database using an object that is PathLike, i.e. has __fspath__(). """ - class Path: - def __fspath__(self): - return TESTFN - path = Path() + path = FakePath(TESTFN) with managed_connect(path) as cx: + self.assertTrue(os.path.exists(path)) cx.execute(self._sql) - def test_open_uri(self): - with managed_connect(TESTFN) as cx: + @unittest.skipUnless(TESTFN_UNDECODABLE, "only works if there are undecodable paths") + def test_open_with_undecodable_path(self): + self.addCleanup(unlink, TESTFN_UNDECODABLE) + path = TESTFN_UNDECODABLE + with managed_connect(path) as cx: + self.assertTrue(os.path.exists(path)) cx.execute(self._sql) + + def test_open_uri(self): with managed_connect(f"file:{TESTFN}", uri=True) as cx: + self.assertTrue(os.path.exists(TESTFN)) cx.execute(self._sql) + + def test_open_uri_readonly(self): + self.addCleanup(unlink, TESTFN) + # Cannot create new DB with self.assertRaises(sqlite.OperationalError): - with managed_connect(f"file:{TESTFN}?mode=ro", uri=True) as cx: + with sqlite.connect(f"file:{TESTFN}?mode=ro", uri=True): + pass + self.assertFalse(os.path.exists(TESTFN)) + with sqlite.connect(TESTFN) as cx: + self.assertTrue(os.path.exists(TESTFN)) + # Cannot modify new DB + with sqlite.connect(f"file:{TESTFN}?mode=ro", uri=True) as cx: + with self.assertRaises(sqlite.OperationalError): cx.execute(self._sql) def test_database_keyword(self): diff --git a/Misc/NEWS.d/next/Library/2022-05-18-17-18-41.gh-issue-91922.DwWIsJ.rst b/Misc/NEWS.d/next/Library/2022-05-18-17-18-41.gh-issue-91922.DwWIsJ.rst new file mode 100644 index 00000000000000..30f7bba115606d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-05-18-17-18-41.gh-issue-91922.DwWIsJ.rst @@ -0,0 +1,3 @@ +Fix function :func:`sqlite.connect` and the :class:`sqlite.Connection` +constructor on non-UTF-8 locales. Also, they now support bytes paths +non-decodable with the current FS encoding. diff --git a/Modules/_sqlite/clinic/connection.c.h b/Modules/_sqlite/clinic/connection.c.h index 1e27c5e0afb126..dd86fb5b64f3f0 100644 --- a/Modules/_sqlite/clinic/connection.c.h +++ b/Modules/_sqlite/clinic/connection.c.h @@ -3,9 +3,9 @@ preserve [clinic start generated code]*/ static int -pysqlite_connection_init_impl(pysqlite_Connection *self, - const char *database, double timeout, - int detect_types, const char *isolation_level, +pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database, + double timeout, int detect_types, + const char *isolation_level, int check_same_thread, PyObject *factory, int cache_size, int uri); @@ -19,7 +19,7 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs) PyObject * const *fastargs; Py_ssize_t nargs = PyTuple_GET_SIZE(args); Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 1; - const char *database = NULL; + PyObject *database; double timeout = 5.0; int detect_types = 0; const char *isolation_level = ""; @@ -32,9 +32,7 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs) if (!fastargs) { goto exit; } - if (!clinic_fsconverter(fastargs[0], &database)) { - goto exit; - } + database = fastargs[0]; if (!noptargs) { goto skip_optional_pos; } @@ -102,9 +100,6 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs) return_value = pysqlite_connection_init_impl((pysqlite_Connection *)self, database, timeout, detect_types, isolation_level, check_same_thread, factory, cache_size, uri); exit: - /* Cleanup for database */ - PyMem_Free((void *)database); - return return_value; } @@ -1236,4 +1231,4 @@ getlimit(pysqlite_Connection *self, PyObject *arg) #ifndef DESERIALIZE_METHODDEF #define DESERIALIZE_METHODDEF #endif /* !defined(DESERIALIZE_METHODDEF) */ -/*[clinic end generated code: output=d21767843c480a10 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=fb8908674e9f25ff input=a9049054013a1b77]*/ diff --git a/Modules/_sqlite/clinic/module.c.h b/Modules/_sqlite/clinic/module.c.h index 74a6a362c05aba..d3367cf62bf724 100644 --- a/Modules/_sqlite/clinic/module.c.h +++ b/Modules/_sqlite/clinic/module.c.h @@ -43,9 +43,7 @@ pysqlite_connect(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb if (!args) { goto exit; } - if (!PyUnicode_FSConverter(args[0], &database)) { - goto exit; - } + database = args[0]; if (!noptargs) { goto skip_optional_pos; } @@ -294,4 +292,4 @@ pysqlite_adapt(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=43aa4f4356f9269d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a7cfa6dc9d54273c input=a9049054013a1b77]*/ diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index 333847f0fafb96..ef9641f03b7bb2 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -92,32 +92,6 @@ isolation_level_converter(PyObject *str_or_none, const char **result) return 1; } -static int -clinic_fsconverter(PyObject *pathlike, const char **result) -{ - PyObject *bytes = NULL; - Py_ssize_t len; - char *str; - - if (!PyUnicode_FSConverter(pathlike, &bytes)) { - goto error; - } - if (PyBytes_AsStringAndSize(bytes, &str, &len) < 0) { - goto error; - } - if ((*result = (const char *)PyMem_Malloc(len+1)) == NULL) { - goto error; - } - - memcpy((void *)(*result), str, len+1); - Py_DECREF(bytes); - return 1; - -error: - Py_XDECREF(bytes); - return 0; -} - #define clinic_state() (pysqlite_get_state_by_type(Py_TYPE(self))) #include "clinic/connection.c.h" #undef clinic_state @@ -159,25 +133,17 @@ new_statement_cache(pysqlite_Connection *self, pysqlite_state *state, } /*[python input] -class FSConverter_converter(CConverter): - type = "const char *" - converter = "clinic_fsconverter" - def converter_init(self): - self.c_default = "NULL" - def cleanup(self): - return f"PyMem_Free((void *){self.name});\n" - class IsolationLevel_converter(CConverter): type = "const char *" converter = "isolation_level_converter" [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=be142323885672ab]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=cbcfe85b253061c2]*/ /*[clinic input] _sqlite3.Connection.__init__ as pysqlite_connection_init - database: FSConverter + database: object timeout: double = 5.0 detect_types: int = 0 isolation_level: IsolationLevel = "" @@ -188,17 +154,22 @@ _sqlite3.Connection.__init__ as pysqlite_connection_init [clinic start generated code]*/ static int -pysqlite_connection_init_impl(pysqlite_Connection *self, - const char *database, double timeout, - int detect_types, const char *isolation_level, +pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database, + double timeout, int detect_types, + const char *isolation_level, int check_same_thread, PyObject *factory, int cache_size, int uri) -/*[clinic end generated code: output=7d640ae1d83abfd4 input=342173993434ba1e]*/ +/*[clinic end generated code: output=839eb2fee4293bda input=b8ce63dc6f70a383]*/ { if (PySys_Audit("sqlite3.connect", "s", database) < 0) { return -1; } + PyObject *bytes; + if (!PyUnicode_FSConverter(database, &bytes)) { + return -1; + } + if (self->initialized) { PyTypeObject *tp = Py_TYPE(self); tp->tp_clear((PyObject *)self); @@ -210,7 +181,7 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, sqlite3 *db; int rc; Py_BEGIN_ALLOW_THREADS - rc = sqlite3_open_v2(database, &db, + rc = sqlite3_open_v2(PyBytes_AS_STRING(bytes), &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | (uri ? SQLITE_OPEN_URI : 0), NULL); if (rc == SQLITE_OK) { @@ -218,6 +189,7 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, } Py_END_ALLOW_THREADS + Py_DECREF(bytes); if (db == NULL && rc == SQLITE_NOMEM) { PyErr_NoMemory(); return -1; diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index 78591f85c1f7de..4ab655f64bfa48 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -46,7 +46,7 @@ module _sqlite3 /*[clinic input] _sqlite3.connect as pysqlite_connect - database: object(converter='PyUnicode_FSConverter') + database: object timeout: double = 5.0 detect_types: int = 0 isolation_level: object = NULL @@ -66,7 +66,7 @@ pysqlite_connect_impl(PyObject *module, PyObject *database, double timeout, int detect_types, PyObject *isolation_level, int check_same_thread, PyObject *factory, int cached_statements, int uri) -/*[clinic end generated code: output=450ac9078b4868bb input=ea6355ba55a78e12]*/ +/*[clinic end generated code: output=450ac9078b4868bb input=e16914663ddf93ce]*/ { if (isolation_level == NULL) { isolation_level = PyUnicode_FromString(""); @@ -77,11 +77,11 @@ pysqlite_connect_impl(PyObject *module, PyObject *database, double timeout, else { Py_INCREF(isolation_level); } - PyObject *res = PyObject_CallFunction(factory, "OdiOiOii", database, + PyObject *res = PyObject_CallFunction(factory, "NdiOiOii", + PyOS_FSPath(database), timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements, uri); - Py_DECREF(database); // needed bco. the AC FSConverter Py_DECREF(isolation_level); return res; } From b9be4a2f55d9ea458b960cd44eb0a00ef41ef212 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 18 May 2022 19:39:06 +0300 Subject: [PATCH 2/8] Test with escaped URIs --- Lib/test/test_sqlite3/test_dbapi.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index 5980c24833f68f..f6bd557e6401fb 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -32,6 +32,7 @@ from test.support import threading_helper from _testcapi import INT_MAX, ULLONG_MAX from os import SEEK_SET, SEEK_CUR, SEEK_END +from urllib.request import pathname2url from test.support.os_helper import TESTFN, TESTFN_UNDECODABLE, unlink, temp_dir, FakePath @@ -665,24 +666,34 @@ def test_open_with_undecodable_path(self): cx.execute(self._sql) def test_open_uri(self): - with managed_connect(f"file:{TESTFN}", uri=True) as cx: + uri = "file:" + pathname2url(os.fsencode(TESTFN)) + with managed_connect(uri, uri=True) as cx: self.assertTrue(os.path.exists(TESTFN)) cx.execute(self._sql) def test_open_uri_readonly(self): + uri = "file:" + pathname2url(os.fsencode(TESTFN)) + "?mode=ro" self.addCleanup(unlink, TESTFN) # Cannot create new DB with self.assertRaises(sqlite.OperationalError): - with sqlite.connect(f"file:{TESTFN}?mode=ro", uri=True): + with sqlite.connect(uri, uri=True): pass self.assertFalse(os.path.exists(TESTFN)) with sqlite.connect(TESTFN) as cx: self.assertTrue(os.path.exists(TESTFN)) # Cannot modify new DB - with sqlite.connect(f"file:{TESTFN}?mode=ro", uri=True) as cx: + with sqlite.connect(uri, uri=True) as cx: with self.assertRaises(sqlite.OperationalError): cx.execute(self._sql) + @unittest.skipUnless(TESTFN_UNDECODABLE, "only works if there are undecodable paths") + def test_open_undecodable_uri(self): + uri = "file:" + pathname2url(TESTFN_UNDECODABLE) + self.addCleanup(unlink, TESTFN_UNDECODABLE) + with managed_connect(uri, uri=True) as cx: + self.assertTrue(os.path.exists(TESTFN_UNDECODABLE)) + cx.execute(self._sql) + def test_database_keyword(self): with sqlite.connect(database=":memory:") as cx: self.assertEqual(type(cx), sqlite.Connection) From dcee457fad9677a43b60ede2b29d37f0d1126d67 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 18 May 2022 19:59:41 +0300 Subject: [PATCH 3/8] Skip tests for undecodaple paths on Windows and macOS. --- Lib/test/test_sqlite3/test_dbapi.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index f6bd557e6401fb..fcca0cb7681c0d 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -657,6 +657,8 @@ def test_open_with_path_like_object(self): self.assertTrue(os.path.exists(path)) cx.execute(self._sql) + @unittest.skipIf(sys.platform == "win32", "skipped on Windows") + @unittest.skipIf(sys.platform == "darwin", "skipped on macOS") @unittest.skipUnless(TESTFN_UNDECODABLE, "only works if there are undecodable paths") def test_open_with_undecodable_path(self): self.addCleanup(unlink, TESTFN_UNDECODABLE) @@ -686,6 +688,8 @@ def test_open_uri_readonly(self): with self.assertRaises(sqlite.OperationalError): cx.execute(self._sql) + @unittest.skipIf(sys.platform == "win32", "skipped on Windows") + @unittest.skipIf(sys.platform == "darwin", "skipped on macOS") @unittest.skipUnless(TESTFN_UNDECODABLE, "only works if there are undecodable paths") def test_open_undecodable_uri(self): uri = "file:" + pathname2url(TESTFN_UNDECODABLE) From 5490686a5d71664c3c2e49934c3aac81d254f696 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 18 May 2022 20:40:23 +0300 Subject: [PATCH 4/8] Fix open URI tests on Windows. --- Lib/test/test_sqlite3/test_dbapi.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index fcca0cb7681c0d..6366449406620c 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -27,12 +27,12 @@ import sys import threading import unittest +import urllib.parse from test.support import SHORT_TIMEOUT, bigmemtest, check_disallow_instantiation from test.support import threading_helper from _testcapi import INT_MAX, ULLONG_MAX from os import SEEK_SET, SEEK_CUR, SEEK_END -from urllib.request import pathname2url from test.support.os_helper import TESTFN, TESTFN_UNDECODABLE, unlink, temp_dir, FakePath @@ -668,13 +668,19 @@ def test_open_with_undecodable_path(self): cx.execute(self._sql) def test_open_uri(self): - uri = "file:" + pathname2url(os.fsencode(TESTFN)) + uri = "file:" + urllib.parse.quote(os.fsencode(TESTFN)) + with managed_connect(uri, uri=True) as cx: + self.assertTrue(os.path.exists(TESTFN)) + cx.execute(self._sql) + + def test_open_unquoted_uri(self): + uri = "file:" + TESTFN with managed_connect(uri, uri=True) as cx: self.assertTrue(os.path.exists(TESTFN)) cx.execute(self._sql) def test_open_uri_readonly(self): - uri = "file:" + pathname2url(os.fsencode(TESTFN)) + "?mode=ro" + uri = "file:" + urllib.parse.quote(os.fsencode(TESTFN)) + "?mode=ro" self.addCleanup(unlink, TESTFN) # Cannot create new DB with self.assertRaises(sqlite.OperationalError): @@ -692,7 +698,7 @@ def test_open_uri_readonly(self): @unittest.skipIf(sys.platform == "darwin", "skipped on macOS") @unittest.skipUnless(TESTFN_UNDECODABLE, "only works if there are undecodable paths") def test_open_undecodable_uri(self): - uri = "file:" + pathname2url(TESTFN_UNDECODABLE) + uri = "file:" + urllib.parse.quote(TESTFN_UNDECODABLE) self.addCleanup(unlink, TESTFN_UNDECODABLE) with managed_connect(uri, uri=True) as cx: self.assertTrue(os.path.exists(TESTFN_UNDECODABLE)) From a0e2704d3683a0bab6ebf001fb2727f183d796d3 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 19 May 2022 12:32:04 +0300 Subject: [PATCH 5/8] Temporary revert some URI opening tests --- Lib/test/test_sqlite3/test_dbapi.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index 6366449406620c..6041604c8f3199 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -668,19 +668,13 @@ def test_open_with_undecodable_path(self): cx.execute(self._sql) def test_open_uri(self): - uri = "file:" + urllib.parse.quote(os.fsencode(TESTFN)) - with managed_connect(uri, uri=True) as cx: - self.assertTrue(os.path.exists(TESTFN)) - cx.execute(self._sql) - - def test_open_unquoted_uri(self): uri = "file:" + TESTFN with managed_connect(uri, uri=True) as cx: self.assertTrue(os.path.exists(TESTFN)) cx.execute(self._sql) def test_open_uri_readonly(self): - uri = "file:" + urllib.parse.quote(os.fsencode(TESTFN)) + "?mode=ro" + uri = "file:" + TESTFN + "?mode=ro" self.addCleanup(unlink, TESTFN) # Cannot create new DB with self.assertRaises(sqlite.OperationalError): From 407d9784982d6321413a4cafb721bcb4f63a1f6a Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 19 May 2022 16:34:38 +0300 Subject: [PATCH 6/8] Temporary revert other URI opening tests --- Lib/test/test_sqlite3/test_dbapi.py | 30 ++++------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index 6041604c8f3199..40f91a193b2cdd 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -668,36 +668,14 @@ def test_open_with_undecodable_path(self): cx.execute(self._sql) def test_open_uri(self): - uri = "file:" + TESTFN - with managed_connect(uri, uri=True) as cx: - self.assertTrue(os.path.exists(TESTFN)) + with managed_connect(TESTFN) as cx: + cx.execute(self._sql) + with managed_connect(f"file:{TESTFN}", uri=True) as cx: cx.execute(self._sql) - - def test_open_uri_readonly(self): - uri = "file:" + TESTFN + "?mode=ro" - self.addCleanup(unlink, TESTFN) - # Cannot create new DB with self.assertRaises(sqlite.OperationalError): - with sqlite.connect(uri, uri=True): - pass - self.assertFalse(os.path.exists(TESTFN)) - with sqlite.connect(TESTFN) as cx: - self.assertTrue(os.path.exists(TESTFN)) - # Cannot modify new DB - with sqlite.connect(uri, uri=True) as cx: - with self.assertRaises(sqlite.OperationalError): + with managed_connect(f"file:{TESTFN}?mode=ro", uri=True) as cx: cx.execute(self._sql) - @unittest.skipIf(sys.platform == "win32", "skipped on Windows") - @unittest.skipIf(sys.platform == "darwin", "skipped on macOS") - @unittest.skipUnless(TESTFN_UNDECODABLE, "only works if there are undecodable paths") - def test_open_undecodable_uri(self): - uri = "file:" + urllib.parse.quote(TESTFN_UNDECODABLE) - self.addCleanup(unlink, TESTFN_UNDECODABLE) - with managed_connect(uri, uri=True) as cx: - self.assertTrue(os.path.exists(TESTFN_UNDECODABLE)) - cx.execute(self._sql) - def test_database_keyword(self): with sqlite.connect(database=":memory:") as cx: self.assertEqual(type(cx), sqlite.Connection) From 9ba5bd1a97bb669fb4e4867ca36d90f170602867 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 20 May 2022 07:05:53 +0300 Subject: [PATCH 7/8] Revert changes in Modules/_sqlite/module.c --- Modules/_sqlite/clinic/module.c.h | 6 ++++-- Modules/_sqlite/module.c | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Modules/_sqlite/clinic/module.c.h b/Modules/_sqlite/clinic/module.c.h index d3367cf62bf724..74a6a362c05aba 100644 --- a/Modules/_sqlite/clinic/module.c.h +++ b/Modules/_sqlite/clinic/module.c.h @@ -43,7 +43,9 @@ pysqlite_connect(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb if (!args) { goto exit; } - database = args[0]; + if (!PyUnicode_FSConverter(args[0], &database)) { + goto exit; + } if (!noptargs) { goto skip_optional_pos; } @@ -292,4 +294,4 @@ pysqlite_adapt(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=a7cfa6dc9d54273c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=43aa4f4356f9269d input=a9049054013a1b77]*/ diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index 4ab655f64bfa48..78591f85c1f7de 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -46,7 +46,7 @@ module _sqlite3 /*[clinic input] _sqlite3.connect as pysqlite_connect - database: object + database: object(converter='PyUnicode_FSConverter') timeout: double = 5.0 detect_types: int = 0 isolation_level: object = NULL @@ -66,7 +66,7 @@ pysqlite_connect_impl(PyObject *module, PyObject *database, double timeout, int detect_types, PyObject *isolation_level, int check_same_thread, PyObject *factory, int cached_statements, int uri) -/*[clinic end generated code: output=450ac9078b4868bb input=e16914663ddf93ce]*/ +/*[clinic end generated code: output=450ac9078b4868bb input=ea6355ba55a78e12]*/ { if (isolation_level == NULL) { isolation_level = PyUnicode_FromString(""); @@ -77,11 +77,11 @@ pysqlite_connect_impl(PyObject *module, PyObject *database, double timeout, else { Py_INCREF(isolation_level); } - PyObject *res = PyObject_CallFunction(factory, "NdiOiOii", - PyOS_FSPath(database), + PyObject *res = PyObject_CallFunction(factory, "OdiOiOii", database, timeout, detect_types, isolation_level, check_same_thread, factory, cached_statements, uri); + Py_DECREF(database); // needed bco. the AC FSConverter Py_DECREF(isolation_level); return res; } From 8f58dcf85ab14c00c1d6db555d2fcc62ebd1cc27 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 20 May 2022 07:08:49 +0300 Subject: [PATCH 8/8] Fix the PySys_Audit format. --- Modules/_sqlite/connection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index ef9641f03b7bb2..7f7de8e709228d 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -161,7 +161,7 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database, int cache_size, int uri) /*[clinic end generated code: output=839eb2fee4293bda input=b8ce63dc6f70a383]*/ { - if (PySys_Audit("sqlite3.connect", "s", database) < 0) { + if (PySys_Audit("sqlite3.connect", "O", database) < 0) { return -1; }