From 5d8c27109691794c741a427f1618446d643c53e7 Mon Sep 17 00:00:00 2001 From: Steve Teahan <75569952+steveteahan@users.noreply.github.com> Date: Sat, 16 Jan 2021 13:04:22 -0500 Subject: [PATCH 1/3] Added mogrify support to Cursor (#476) --- MySQLdb/cursors.py | 40 +++++++++++++++++++++++++++++++++++++--- tests/test_cursor.py | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/MySQLdb/cursors.py b/MySQLdb/cursors.py index 451dab5f..883d1be8 100644 --- a/MySQLdb/cursors.py +++ b/MySQLdb/cursors.py @@ -182,6 +182,27 @@ def execute(self, query, args=None): """ while self.nextset(): pass + + mogrified_query = self._mogrify(query, args) + + assert isinstance(mogrified_query, (bytes, bytearray)) + res = self._query(mogrified_query) + return res + + def _mogrify(self, query, args=None): + """Generates the query to be sent to the server with argument + interpolation and proper encoding. This is for internal use, see + mogrify() for the external API that returns a string. + + query -- string, query to execute on server + args -- optional sequence or mapping, parameters to use with query. + + Note: If args is a sequence, then %s must be used as the + parameter placeholder in the query. If a mapping is used, + %(key)s must be used as the placeholder. + + Returns bytes or bytearray representing the query + """ db = self._get_db() if isinstance(query, str): @@ -202,9 +223,22 @@ def execute(self, query, args=None): except TypeError as m: raise ProgrammingError(str(m)) - assert isinstance(query, (bytes, bytearray)) - res = self._query(query) - return res + return query + + def mogrify(self, query, args=None): + """Get the query exactly as it would be sent to the database running the + execute() method. + + query -- string, query to execute on server + args -- optional sequence or mapping, parameters to use with query. + + Note: If args is a sequence, then %s must be used as the + parameter placeholder in the query. If a mapping is used, + %(key)s must be used as the placeholder. + + Returns string representing query that would be executed by the server + """ + return self._mogrify(query, args).decode() def executemany(self, query, args): # type: (str, list) -> int diff --git a/tests/test_cursor.py b/tests/test_cursor.py index 91f0323e..f24abd74 100644 --- a/tests/test_cursor.py +++ b/tests/test_cursor.py @@ -150,3 +150,39 @@ def test_dictcursor(): names2 = sorted(rows[1]) for a, b in zip(names1, names2): assert a is b + + +def test_mogrify_without_args(): + conn = connect() + cursor = conn.cursor() + + query = "SELECT VERSION()" + mogrified_query = cursor.mogrify(query) + cursor.execute(query) + + assert mogrified_query == query + assert mogrified_query == cursor._executed.decode() + + +def test_mogrify_with_tuple_args(): + conn = connect() + cursor = conn.cursor() + + query_with_args = "SELECT %s, %s", (1, 2) + mogrified_query = cursor.mogrify(*query_with_args) + cursor.execute(*query_with_args) + + assert mogrified_query == "SELECT 1, 2" + assert mogrified_query == cursor._executed.decode() + + +def test_mogrify_with_dict_args(): + conn = connect() + cursor = conn.cursor() + + query_with_args = "SELECT %(a)s, %(b)s", {"a": 1, "b": 2} + mogrified_query = cursor.mogrify(*query_with_args) + cursor.execute(*query_with_args) + + assert mogrified_query == "SELECT 1, 2" + assert mogrified_query == cursor._executed.decode() From 2412be77a6e2bd4755b89a5643ee0d72e702cf84 Mon Sep 17 00:00:00 2001 From: Steve Teahan <75569952+steveteahan@users.noreply.github.com> Date: Tue, 19 Jan 2021 06:32:41 -0500 Subject: [PATCH 2/3] Fixed docstrings and decoding in mogrify() --- MySQLdb/cursors.py | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/MySQLdb/cursors.py b/MySQLdb/cursors.py index 883d1be8..dc656b32 100644 --- a/MySQLdb/cursors.py +++ b/MySQLdb/cursors.py @@ -190,19 +190,8 @@ def execute(self, query, args=None): return res def _mogrify(self, query, args=None): - """Generates the query to be sent to the server with argument - interpolation and proper encoding. This is for internal use, see - mogrify() for the external API that returns a string. - - query -- string, query to execute on server - args -- optional sequence or mapping, parameters to use with query. - - Note: If args is a sequence, then %s must be used as the - parameter placeholder in the query. If a mapping is used, - %(key)s must be used as the placeholder. - - Returns bytes or bytearray representing the query - """ + """Returns bytes or bytearray representing the query. See mogrify() for the + external API that returns a string.""" db = self._get_db() if isinstance(query, str): @@ -229,7 +218,7 @@ def mogrify(self, query, args=None): """Get the query exactly as it would be sent to the database running the execute() method. - query -- string, query to execute on server + query -- string, query to mogrify args -- optional sequence or mapping, parameters to use with query. Note: If args is a sequence, then %s must be used as the @@ -238,7 +227,7 @@ def mogrify(self, query, args=None): Returns string representing query that would be executed by the server """ - return self._mogrify(query, args).decode() + return self._mogrify(query, args).decode(self._get_db().encoding) def executemany(self, query, args): # type: (str, list) -> int From 92d7ec0435ffa26a5b8f3c24a10df93cc885e5fc Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Mon, 15 May 2023 13:55:22 +0900 Subject: [PATCH 3/3] Update docstring --- MySQLdb/cursors.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/MySQLdb/cursors.py b/MySQLdb/cursors.py index dc656b32..80b72ef5 100644 --- a/MySQLdb/cursors.py +++ b/MySQLdb/cursors.py @@ -190,8 +190,7 @@ def execute(self, query, args=None): return res def _mogrify(self, query, args=None): - """Returns bytes or bytearray representing the query. See mogrify() for the - external API that returns a string.""" + """Return query after binding args.""" db = self._get_db() if isinstance(query, str): @@ -215,8 +214,7 @@ def _mogrify(self, query, args=None): return query def mogrify(self, query, args=None): - """Get the query exactly as it would be sent to the database running the - execute() method. + """Return query after binding args. query -- string, query to mogrify args -- optional sequence or mapping, parameters to use with query.