Skip to content

Commit c1089f2

Browse files
committed
BUG21477493: Fix RE_SQL_INSERT_STMT to correctly match Insert Statement
The regex matches the literal "VALUES" in the insert string and assumes that it is a batch insert, which may not be the case if this literal is used as a value itself. The regex is modified to match the complete Insert Statement and made sure it conforms to the format `INSERT INTO [table_name] (col,...) VALUES(a,...)`. Unittests have been added for regression.
1 parent 7a72b0c commit c1089f2

File tree

2 files changed

+57
-1
lines changed

2 files changed

+57
-1
lines changed

lib/mysql/connector/cursor.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@
4040
r'''\s*ON\s+DUPLICATE\s+KEY(?:[^"'`]*["'`][^"'`]*["'`])*[^"'`]*$''',
4141
re.I | re.M | re.S)
4242
RE_SQL_INSERT_STMT = re.compile(
43-
r"({0}|\s)*INSERT({0}|\s)*INTO.+VALUES.*".format(SQL_COMMENT),
43+
r"({0}|\s)*INSERT({0}|\s)*INTO\s+[`'\"]?.+[`'\"]?(?:\.[`'\"]?.+[`'\"]?)"
44+
"{{0,2}}\s+VALUES\s*\(.+(?:\s*,.+)*\)".format(SQL_COMMENT),
4445
re.I | re.M | re.S)
4546
RE_SQL_INSERT_VALUES = re.compile(r'.*VALUES\s*(\(.*\)).*', re.I | re.M | re.S)
4647
RE_PY_PARAM = re.compile(b'(%s)')

tests/test_bugs.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4025,6 +4025,61 @@ def test_bad_set_charset_number(self):
40254025
self.assertEqual(self.cnx._charset_id, old_val)
40264026

40274027

4028+
class BugOra21477493(tests.MySQLConnectorTests):
4029+
"""Bug 21477493 - EXECUTEMANY() API WITH INSERT INTO .. SELECT STATEMENT
4030+
RETURNS INTERFACEERROR
4031+
"""
4032+
def setUp(self):
4033+
config = tests.get_mysql_config()
4034+
self.cnx = connection.MySQLConnection(**config)
4035+
cursor = self.cnx.cursor()
4036+
cursor.execute("DROP TABLE IF EXISTS fun1")
4037+
cursor.execute("CREATE TABLE fun1(a CHAR(50), b INT)")
4038+
data=[('A',1),('B',2)]
4039+
cursor.executemany("INSERT INTO fun1 (a, b) VALUES (%s, %s)",data)
4040+
cursor.close()
4041+
4042+
def tearDown(self):
4043+
cursor = self.cnx.cursor()
4044+
cursor.execute("DROP TABLE IF EXISTS fun1")
4045+
cursor.close()
4046+
4047+
def test_insert_into_select_type1(self):
4048+
data = [('A',1),('B',2)]
4049+
cursor = self.cnx.cursor()
4050+
cursor.executemany("INSERT INTO fun1 SELECT CONCAT('VALUES', %s), "
4051+
"b + %s FROM fun1", data)
4052+
cursor.close()
4053+
4054+
cursor = self.cnx.cursor()
4055+
cursor.execute("SELECT * FROM fun1")
4056+
self.assertEqual(8, len(cursor.fetchall()))
4057+
4058+
def test_insert_into_select_type2(self):
4059+
data = [('A',1),('B',2)]
4060+
cursor = self.cnx.cursor()
4061+
cursor.executemany("INSERT INTO fun1 SELECT CONCAT('VALUES(ab, cd)',"
4062+
"%s), b + %s FROM fun1", data)
4063+
cursor.close()
4064+
4065+
cursor = self.cnx.cursor()
4066+
cursor.execute("SELECT * FROM fun1")
4067+
self.assertEqual(8, len(cursor.fetchall()))
4068+
4069+
def test_insert_into_select_type3(self):
4070+
config = tests.get_mysql_config()
4071+
data = [('A',1),('B',2)]
4072+
cursor = self.cnx.cursor()
4073+
cursor.executemany("INSERT INTO `{0}`.`fun1` SELECT CONCAT('"
4074+
"VALUES(ab, cd)', %s), b + %s FROM fun1"
4075+
"".format(config["database"]), data)
4076+
cursor.close()
4077+
4078+
cursor = self.cnx.cursor()
4079+
cursor.execute("SELECT * FROM fun1")
4080+
self.assertEqual(8, len(cursor.fetchall()))
4081+
4082+
40284083
class BugOra21492815(tests.MySQLConnectorTests):
40294084
"""BUG#21492815: CALLPROC() HANGS WHEN CONSUME_RESULTS=TRUE
40304085
"""

0 commit comments

Comments
 (0)