From df81bd7f41fa2d5b5a492ee29d943db4f7482218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20M=C3=BCller?= Date: Sat, 4 Jun 2022 15:43:36 +0200 Subject: [PATCH 1/5] Add BASE_TYPE_ADAPTION optimization. --HG-- branch : sqlite-need-adapt-optimization --- lib_pypy/_sqlite3.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py index 48dba7bb0a..790ca669a8 100644 --- a/lib_pypy/_sqlite3.py +++ b/lib_pypy/_sqlite3.py @@ -107,6 +107,9 @@ _STMT_TYPE_OTHER = 4 _STMT_TYPE_SELECT = 5 _STMT_TYPE_INVALID = 6 +# flag that signals if base types need adaption +BASE_TYPE_ADAPTED = False + class Error(StandardError): pass @@ -1110,10 +1113,11 @@ class Statement(object): "just switch your application to Unicode strings.") def __set_param(self, idx, param): - try: - param = adapt(param) - except: - pass # And use previous value + if BASE_TYPE_ADAPTED: + try: + param = adapt(param) + except: + pass # And use previous value if param is None: rc = _lib.sqlite3_bind_null(self._statement, idx) @@ -1342,6 +1346,8 @@ class PrepareProtocol(object): def register_adapter(typ, callable): + global BASE_TYPE_ADAPTED + BASE_TYPE_ADAPTED = True adapters[typ, PrepareProtocol] = callable -- GitLab From d83e05e1d5caf7d1881579a182d38b204d5bd135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20M=C3=BCller?= Date: Sat, 4 Jun 2022 16:46:35 +0200 Subject: [PATCH 2/5] Add type checking, draft a test case --HG-- branch : sqlite-need-adapt-optimization --- extra_tests/test_sqlite3.py | 26 ++++++++++++++++++++++++++ lib_pypy/_sqlite3.py | 4 +++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/extra_tests/test_sqlite3.py b/extra_tests/test_sqlite3.py index 2fd46ce09f..c05ed28af7 100644 --- a/extra_tests/test_sqlite3.py +++ b/extra_tests/test_sqlite3.py @@ -4,6 +4,7 @@ from __future__ import absolute_import import pytest import sys +from unittest import mock _sqlite3 = pytest.importorskip('_sqlite3') @@ -330,3 +331,28 @@ def test_empty_statement(): r = cur.execute(sql) assert r.description is None assert cur.fetchall() == [] + + +need_adapt_test_cases = ( + (bytearray([1, 2, 3]), False), + (3.14, False), + (42, False), + ("pypy", False), + (None, False), +) + +@pytest.mark.parametrize("param,is_called", need_adapt_test_cases) +def test_need_adapt_flag(param, is_called): + adapters = dict(_sqlite3.adapters) + flag = bool(_sqlite3.BASE_TYPE_ADAPTED) + + _sqlite3.register_adapter(type(param), lambda x: pass) + + with mock.patch("_sqlite3.adapt") as mock_adapt: + # TODO: What do I have to call here? + mock_adapt.assert_not_called() + + _sqlite3.adapters = adapters + _sqlite3.BASE_TYPE_ADAPTED = flag + + diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py index 790ca669a8..85771ef3f0 100644 --- a/lib_pypy/_sqlite3.py +++ b/lib_pypy/_sqlite3.py @@ -1347,7 +1347,9 @@ class PrepareProtocol(object): def register_adapter(typ, callable): global BASE_TYPE_ADAPTED - BASE_TYPE_ADAPTED = True + # only set flag if typ is not a base type supported by SQLite3 + if type(typ) not in {bytearray, float, int, str, NoneType}: + BASE_TYPE_ADAPTED = True adapters[typ, PrepareProtocol] = callable -- GitLab From 8566de6ac497117b29c008b6c56e0fab9441d5c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20M=C3=BCller?= Date: Sat, 4 Jun 2022 16:48:14 +0200 Subject: [PATCH 3/5] Remove wrong type call --HG-- branch : sqlite-need-adapt-optimization --- lib_pypy/_sqlite3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py index 85771ef3f0..c619692834 100644 --- a/lib_pypy/_sqlite3.py +++ b/lib_pypy/_sqlite3.py @@ -1348,7 +1348,7 @@ class PrepareProtocol(object): def register_adapter(typ, callable): global BASE_TYPE_ADAPTED # only set flag if typ is not a base type supported by SQLite3 - if type(typ) not in {bytearray, float, int, str, NoneType}: + if typ not in {bytearray, float, int, str, NoneType}: BASE_TYPE_ADAPTED = True adapters[typ, PrepareProtocol] = callable -- GitLab From 10390e6af7ba1fbad6b8e8541fb673ec8807052d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20M=C3=BCller?= Date: Sat, 4 Jun 2022 17:18:44 +0200 Subject: [PATCH 4/5] Add additional test case, fix call assertion conditional. --HG-- branch : sqlite-need-adapt-optimization --- extra_tests/test_sqlite3.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/extra_tests/test_sqlite3.py b/extra_tests/test_sqlite3.py index c05ed28af7..bac84f9176 100644 --- a/extra_tests/test_sqlite3.py +++ b/extra_tests/test_sqlite3.py @@ -339,6 +339,7 @@ need_adapt_test_cases = ( (42, False), ("pypy", False), (None, False), + ([1, 2, 3], True), ) @pytest.mark.parametrize("param,is_called", need_adapt_test_cases) @@ -350,7 +351,10 @@ def test_need_adapt_flag(param, is_called): with mock.patch("_sqlite3.adapt") as mock_adapt: # TODO: What do I have to call here? - mock_adapt.assert_not_called() + if not is_called: + mock_adapt.assert_not_called() + else: + mock_adapt.assert_called() _sqlite3.adapters = adapters _sqlite3.BASE_TYPE_ADAPTED = flag -- GitLab From 96db1d4c1048be66ae69fae0ceda76b4c13d3226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20M=C3=BCller?= Date: Sat, 4 Jun 2022 22:24:08 +0200 Subject: [PATCH 5/5] Expand test case --HG-- branch : sqlite-need-adapt-optimization --- extra_tests/test_sqlite3.py | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/extra_tests/test_sqlite3.py b/extra_tests/test_sqlite3.py index bac84f9176..a70c1a6ebb 100644 --- a/extra_tests/test_sqlite3.py +++ b/extra_tests/test_sqlite3.py @@ -333,28 +333,29 @@ def test_empty_statement(): assert cur.fetchall() == [] -need_adapt_test_cases = ( - (bytearray([1, 2, 3]), False), - (3.14, False), - (42, False), - ("pypy", False), - (None, False), - ([1, 2, 3], True), +NEED_ADAPT_TESTCASES = ( + (bytearray([1, 2, 3]), 0), + (3.14, 0), + (42, 0), + ("pypy", 0), + (None, 0), ) -@pytest.mark.parametrize("param,is_called", need_adapt_test_cases) -def test_need_adapt_flag(param, is_called): +@pytest.mark.parametrize("param,call_count", NEED_ADAPT_TESTCASES) +def test_need_adapt_flag(con, param, call_count): adapters = dict(_sqlite3.adapters) flag = bool(_sqlite3.BASE_TYPE_ADAPTED) - _sqlite3.register_adapter(type(param), lambda x: pass) + def noop(): + pass + + _sqlite3.register_adapter(type(param), noop) with mock.patch("_sqlite3.adapt") as mock_adapt: - # TODO: What do I have to call here? - if not is_called: - mock_adapt.assert_not_called() - else: - mock_adapt.assert_called() + cur = con.cursor() + cur.execute("select ?", (param,)) + + assert mock_adapt.call_count == call_count _sqlite3.adapters = adapters _sqlite3.BASE_TYPE_ADAPTED = flag -- GitLab