Skip to content

Commit 9b86b29

Browse files
committed
BUG#37859771 - mysql/connector python version 9.3.0 has a regression
which cannot persist binary data with percent signs in it Reverted back the changes made to fix BUG#37447394 which introduced an unwanted behavior reducing double percentage sign character "%%s" in query strings passed to MySQLCursor.execute to a single "%s" character. Change-Id: I8fd834e8f165827672a272f30d410191880a6e8a
1 parent 83a5d24 commit 9b86b29

File tree

6 files changed

+338
-66
lines changed

6 files changed

+338
-66
lines changed

CHANGES.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ v9.4.0
1616
- WL#16962: Update the Python Protobuf version
1717
- BUG#37868219: RPM packages have incorrect copyright year in their metadata
1818
- BUG#37820231: Text based django ORM filters doesn't work with Connector/Python
19+
- BUG#37859771: mysql/connector python version 9.3.0 has a regression which cannot persist binary data with percent signs in it
1920
- BUG#37806057: Rename extra option (when installing wheel package) to install webauthn functionality dependencies
2021
- BUG#37642447: The license type is missing from RPM package
2122
- BUG#37627508: mysql/connector python fetchmany() has an off by one bug when argument given as 1
@@ -32,7 +33,6 @@ v9.3.0
3233
- WL#16327: Remove Cursors Prepared Raw and Named Tuple
3334
- BUG#37541353: (Contribution) Fix typing annotation of MySQLConnectionAbstract's close function
3435
- BUG#37453587: Github links in PyPI project's pages do not work
35-
- BUG#37447394: Unable to escape a parameter marker (`%s`) used in a query that should not be treated as a parameter marker
3636
- BUG#37418436: Arbitrary File Read in MySQL Python Client library
3737
- BUG#37410052: Bad formatting of exceptions when connecting with Unix sockets
3838
- BUG#37399636: The C-extension has a memory leak when working with prepared statements

mysql-connector-python/lib/mysql/connector/aio/cursor.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -410,8 +410,6 @@ async def _prepare_statement(
410410
f"Could not process parameters: {type(params).__name__}({params}),"
411411
" it must be of type list, tuple or dict"
412412
)
413-
# final statement with `%%s` should be replaced as `%s`
414-
stmt = stmt.replace(b"%%s", b"%s")
415413

416414
return stmt
417415

@@ -1209,8 +1207,6 @@ async def execute(
12091207
except UnicodeEncodeError as err:
12101208
raise ProgrammingError(str(err)) from err
12111209

1212-
# final statement with `%%s` should be replaced as `%s`
1213-
operation = operation.replace(b"%%s", b"%s")
12141210
if b"%s" in operation:
12151211
# Convert %s to ? before sending it to MySQL
12161212
operation = re.sub(RE_SQL_FIND_PARAM, b"?", operation)

mysql-connector-python/lib/mysql/connector/cursor.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595
re.I | re.M | re.S,
9696
)
9797
RE_SQL_INSERT_VALUES = re.compile(r".*VALUES\s*(\(.+\)).*", re.I | re.M | re.S)
98-
RE_PY_PARAM = re.compile(b"((?<!%)%s)")
98+
RE_PY_PARAM = re.compile(b"(%s)")
9999
RE_PY_MAPPING_PARAM = re.compile(
100100
rb"""
101101
%
@@ -400,8 +400,6 @@ def execute(
400400
" it must be of type list, tuple or dict"
401401
)
402402

403-
# final statement with `%%s` should be replaced as `%s`
404-
stmt = stmt.replace(b"%%s", b"%s")
405403
self._stmt_partitions = split_multi_statement(
406404
sql_code=stmt, map_results=map_results
407405
)
@@ -1237,8 +1235,6 @@ def execute(
12371235
except UnicodeEncodeError as err:
12381236
raise ProgrammingError(str(err)) from err
12391237

1240-
# final statement with `%%s` should be replaced as `%s`
1241-
operation = operation.replace(b"%%s", b"%s")
12421238
if b"%s" in operation:
12431239
# Convert %s to ? before sending it to MySQL
12441240
operation = re.sub(RE_SQL_FIND_PARAM, b"?", operation)

mysql-connector-python/lib/mysql/connector/cursor_cext.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -336,9 +336,6 @@ def execute(
336336
"Not all parameters were used in the SQL statement"
337337
)
338338

339-
# final statement with `%%s` should be replaced as `%s`
340-
stmt = stmt.replace(b"%%s", b"%s")
341-
342339
self._stmt_partitions = split_multi_statement(
343340
sql_code=stmt, map_results=map_results
344341
)
@@ -1129,8 +1126,6 @@ def execute(
11291126
except UnicodeDecodeError as err:
11301127
raise ProgrammingError(str(err)) from err
11311128

1132-
# final statement with `%%s` should be replaced as `%s`
1133-
operation = operation.replace("%%s", "%s")
11341129
if isinstance(params, dict):
11351130
replacement_keys = re.findall(RE_SQL_PYTHON_CAPTURE_PARAM_NAME, operation)
11361131
try:

mysql-connector-python/tests/test_bugs.py

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -8900,57 +8900,6 @@ def test_connection_timeout(self):
89008900
self.fail(err)
89018901

89028902

8903-
class BugOra37447394(tests.MySQLConnectorTests):
8904-
"""BUG#37447394: Unable to escape a parameter marker (`%s`) used in a query that should not be
8905-
treated as a parameter marker.
8906-
8907-
The `%s` parameter marker is not being escaped by using `%%s` in an SQL statement being passed
8908-
via the cursor's execute() method. This is required while passing a query like:
8909-
`select date_format(%s, "%Y-%m-%d %H:%i:%%s")`. Currently, the `%s` at the end of the query is
8910-
is not being escaped and is being treated like a parameter marker instead.
8911-
8912-
This patch fixes this issue by adding proper regular expression checks to escape the `%s` by
8913-
using `%%s`.
8914-
"""
8915-
8916-
stmt = 'select date_format(%s, "%Y-%m-%d %H:%i:%%s")'
8917-
params = ("2017-06-15 12:20:23",)
8918-
8919-
@foreach_cnx()
8920-
def test_bug37447394(self):
8921-
try:
8922-
with self.cnx.cursor() as cur:
8923-
cur.execute(self.stmt, self.params)
8924-
self.assertEqual(cur.fetchone(), self.params)
8925-
with self.cnx.cursor(prepared=True) as cur:
8926-
cur.execute(self.stmt, self.params)
8927-
self.assertEqual(cur.fetchone(), self.params)
8928-
except Exception as err:
8929-
self.fail(err)
8930-
8931-
8932-
class BugOra37447394_async(tests.MySQLConnectorAioTestCase):
8933-
"""BUG#37447394: Unable to escape a parameter marker (`%s`) used in a query that should not be
8934-
treated as a parameter marker.
8935-
8936-
For more details check `test_bugs.BugOra37447394`.
8937-
"""
8938-
8939-
stmt = 'select date_format(%s, "%Y-%m-%d %H:%i:%%s")'
8940-
params = ("2017-06-15 12:20:23", )
8941-
8942-
@foreach_cnx_aio()
8943-
async def test_bug37447394_async(self):
8944-
try:
8945-
async with await self.cnx.cursor() as cur:
8946-
await cur.execute(self.stmt, self.params)
8947-
self.assertEqual(await cur.fetchone(), self.params)
8948-
async with await self.cnx.cursor(prepared=True) as cur:
8949-
await cur.execute(self.stmt, self.params)
8950-
self.assertEqual(await cur.fetchone(), self.params)
8951-
except Exception as err:
8952-
self.fail(err)
8953-
89548903
class BugOra37275524(tests.MySQLConnectorTests):
89558904
"""BUG#37275524: Exception is not interpreted properly on prepared statements when C extension is in use
89568905

0 commit comments

Comments
 (0)