Skip to content

Commit 1a74a1f

Browse files
committed
BUG#34499578: MySQLCursor.executemany() fails to correctly identify BULK data loading ops
The MySQLCursor.executemany() method fails to batch insert data since the regular expression (RE) sentinel used does not detect batch cases correctly resulting in using the one-on-one insert, hence an overall performance issue. With this patch the RE sentinel is fixed, hence restoring back the batch insert mechanism. Also, this patch fixes BUG#34555367 and is the product of a contribution from Alex Cazacu. Thank you for the contribution. Change-Id: I784ea8c44d5f1f6dcd2d6d9448e173393689242d
1 parent 6594d25 commit 1a74a1f

File tree

3 files changed

+65
-1
lines changed

3 files changed

+65
-1
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ v8.0.32
1515
- WL#15036: Support for type hints
1616
- BUG#34689812: Fix datetime conversion when using prepared cursors
1717
- BUG#34556157: Kerberos authorization fails when using SSPI as security interface
18+
- BUG#34499578: MySQLCursor.executemany() fails to correctly identify BULK data loading ops
1819
- BUG#30089671: Fix decoding VARBINARY columns when using a prepared cursor
1920

2021
v8.0.31

lib/mysql/connector/cursor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@
8585
RE_SQL_INSERT_STMT = re.compile(
8686
rf"({SQL_COMMENT}|\s)*INSERT({SQL_COMMENT}|\s)"
8787
r"*INTO\s+[`'\"]?.+[`'\"]?(?:\.[`'\"]?.+[`'\"]?)"
88-
r"{{0,2}}\s+VALUES\s*\(.+(?:\s*,.+)*\)",
88+
r"{0,2}\s+VALUES\s*\(.+(?:\s*,.+)*\)",
8989
re.I | re.M | re.S,
9090
)
9191
RE_SQL_INSERT_VALUES = re.compile(r".*VALUES\s*(\(.*\)).*", re.I | re.M | re.S)

tests/test_bugs.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7185,3 +7185,66 @@ def test_datetime_with_prepared_cursor(self):
71857185
)
71867186
res = cur.fetchall()
71877187
self.assertEqual(res[0], self.data)
7188+
7189+
7190+
class BugOra34499578(tests.MySQLConnectorTests):
7191+
"""BUG#34499578: MySQLCursor.executemany() fails to correctly identify BULK data loading ops.
7192+
7193+
The MySQLCursor.executemany() method fails to batch insert data since
7194+
the regular expression (RE) sentinel used does not detect batch cases
7195+
correctly resulting in using the one-on-one insert, hence an overall
7196+
performance issue.
7197+
"""
7198+
7199+
table_name = "BugOra34499578"
7200+
field1, field2 = "color", "country"
7201+
7202+
def setUp(self):
7203+
config = tests.get_mysql_config()
7204+
with mysql.connector.connect(**config) as cnx:
7205+
with cnx.cursor() as cur:
7206+
cur.execute(f"DROP TABLE IF EXISTS {self.table_name}")
7207+
cur.execute(
7208+
f"""
7209+
CREATE TABLE {self.table_name}(
7210+
{self.field1} char(32),
7211+
{self.field2} char(32)
7212+
)
7213+
"""
7214+
)
7215+
cnx.commit()
7216+
7217+
def tearDown(self):
7218+
config = tests.get_mysql_config()
7219+
with mysql.connector.connect(**config) as cnx:
7220+
cnx.cmd_query(f"DROP TABLE IF EXISTS {self.table_name}")
7221+
7222+
@foreach_cnx()
7223+
def test_batch_insert_happens_in_executemany(self):
7224+
seq_params = [["red", "portugal"], ["green", "mexico"], ["blue", "argentina"]]
7225+
with self.cnx.cursor() as cur:
7226+
cur.executemany(
7227+
f"""
7228+
INSERT INTO {self.table_name} (
7229+
{self.field1},
7230+
{self.field2})
7231+
VALUES(
7232+
%s,
7233+
%s
7234+
)
7235+
""",
7236+
seq_params,
7237+
)
7238+
# if batch insert happens, it means all parameters must be
7239+
# somewhere in the executed statement, else just a parameters
7240+
# subset is in, particularly the last parameter.
7241+
self.assertTrue(
7242+
all(
7243+
[
7244+
param.encode("utf8", errors="ignore") in cur._executed
7245+
for params in seq_params
7246+
for param in params
7247+
]
7248+
),
7249+
"Batch insert failed!",
7250+
)

0 commit comments

Comments
 (0)