Skip to content

Commit d0b86c0

Browse files
committed
Merge branch 'release/2.1.4' into master-2.1
2 parents 3cdf4c9 + 80b3430 commit d0b86c0

File tree

10 files changed

+80
-34
lines changed

10 files changed

+80
-34
lines changed

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[submodule "cpyint"]
22
path = cpyint
33
url = ../connector-python-internal.git
4-
branch = master
4+
branch = master-2.1

CHANGES.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ Full release notes:
1111
v2.1.4
1212
======
1313

14+
- BUG#22873551: Fix cleartext authentication issue
1415
- BUG#22545879: Fix usage of --ssl-cipher option
16+
- BUG#22529828: Fix potencial SQL injection
1517
- BUG#21881038: Fix duplicate entry in CHANGES.txt
1618
- BUG#21879914: Fix using SSL without key or certificate using C/Ext
1719
- BUG#21879859: Fix consuming results after calling procedure
1820
- BUG#21498719: Fix conversion of Python bytearray
1921
- BUG#21449996: Fix LOAD DATA with compression turned on
20-
- BUG#21449207: Fix fetching compressed data bigger than 16M
2122
- BUG#20834643: Attribute Error while promoting servers using MySQL Fabric
2223
- BUG#20811802: Fix buffered named tuple cursor with CExtension
2324
- BUG#20217174: Fix install command honouring --install-lib when given

README.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ doubt, this particular copy of the software is released
2828
under the version 2 of the GNU General Public License.
2929
MySQL Connector/Python is brought to you by Oracle.
3030

31-
Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
31+
Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
3232

3333
License information can be found in the LICENSE.txt file.
3434

cpyint

lib/mysql/connector/cursor.py

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# MySQL Connector/Python - MySQL driver written in Python.
2-
# Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
2+
# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
33

44
# MySQL Connector/Python is licensed under the terms of the GPLv2
55
# <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -44,6 +44,14 @@
4444
re.I | re.M | re.S)
4545
RE_SQL_INSERT_VALUES = re.compile(r'.*VALUES\s*(\(.*\)).*', re.I | re.M | re.S)
4646
RE_PY_PARAM = re.compile(b'(%s)')
47+
RE_PY_MAPPING_PARAM = re.compile(
48+
br'''
49+
%
50+
\((?P<mapping_key>[^)]+)\)
51+
(?P<conversion_type>[diouxXeEfFgGcrs%])
52+
''',
53+
re.X
54+
)
4755
RE_SQL_SPLIT_STMTS = re.compile(
4856
b''';(?=(?:[^"'`]*["'`][^"'`]*["'`])*[^"'`]*$)''')
4957
RE_SQL_FIND_PARAM = re.compile(
@@ -75,6 +83,34 @@ def remaining(self):
7583
return len(self.params) - self.index
7684

7785

86+
def _bytestr_format_dict(bytestr, value_dict):
87+
"""
88+
>>> _bytestr_format_dict(b'%(a)s', {b'a': b'foobar'})
89+
b'foobar
90+
>>> _bytestr_format_dict(b'%%(a)s', {b'a': b'foobar'})
91+
b'%%(a)s'
92+
>>> _bytestr_format_dict(b'%%%(a)s', {b'a': b'foobar'})
93+
b'%%foobar'
94+
>>> _bytestr_format_dict(b'%(x)s %(y)s',
95+
... {b'x': b'x=%(y)s', b'y': b'y=%(x)s'})
96+
b'x=%(y)s y=%(x)s'
97+
"""
98+
def replace(matchobj):
99+
value = None
100+
groups = matchobj.groupdict()
101+
if groups["conversion_type"] == b"%":
102+
value = b"%"
103+
if groups["conversion_type"] == b"s":
104+
key = groups["mapping_key"].encode("utf-8") \
105+
if PY2 else groups["mapping_key"]
106+
value = value_dict[key]
107+
if value is None:
108+
raise ValueError("Unsupported conversion_type: {0}"
109+
"".format(groups["conversion_type"]))
110+
return value.decode("utf-8") if PY2 else value
111+
return RE_PY_MAPPING_PARAM.sub(replace, bytestr.decode("utf-8")
112+
if PY2 else bytestr)
113+
78114
class CursorBase(MySQLCursorAbstract):
79115
"""
80116
Base for defining MySQLCursor. This class is a skeleton and defines
@@ -360,9 +396,9 @@ def _process_params_dict(self, params):
360396
conv = escape(conv)
361397
conv = quote(conv)
362398
if PY2:
363-
res["%({0})s".format(key)] = conv
399+
res[key] = conv
364400
else:
365-
res["%({0})s".format(key).encode()] = conv
401+
res[key.encode()] = conv
366402
except Exception as err:
367403
raise errors.ProgrammingError(
368404
"Failed processing pyformat-parameters; %s" % err)
@@ -497,8 +533,8 @@ def execute(self, operation, params=None, multi=False):
497533

498534
if params is not None:
499535
if isinstance(params, dict):
500-
for key, value in self._process_params_dict(params).items():
501-
stmt = stmt.replace(key, value)
536+
stmt = _bytestr_format_dict(
537+
stmt, self._process_params_dict(params))
502538
elif isinstance(params, (list, tuple)):
503539
psub = _ParamSubstitutor(self._process_params(params))
504540
stmt = RE_PY_PARAM.sub(psub, stmt)
@@ -551,8 +587,8 @@ def remove_comments(match):
551587
for params in seq_params:
552588
tmp = fmt
553589
if isinstance(params, dict):
554-
for key, value in self._process_params_dict(params).items():
555-
tmp = tmp.replace(key, value)
590+
tmp = _bytestr_format_dict(
591+
tmp, self._process_params_dict(params))
556592
else:
557593
psub = _ParamSubstitutor(self._process_params(params))
558594
tmp = RE_PY_PARAM.sub(psub, tmp)

lib/mysql/connector/protocol.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -718,7 +718,7 @@ def parse_auth_switch_request(self, packet):
718718
"Failed parsing AuthSwitchRequest packet")
719719

720720
(packet, plugin_name) = utils.read_string(packet[5:], end=b'\x00')
721-
if packet[-1] == 0:
721+
if packet and packet[-1] == 0:
722722
packet = packet[:-1]
723723

724724
return plugin_name.decode('utf8'), packet

lib/mysql/connector/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# MySQL Connector/Python - MySQL driver written in Python.
2-
# Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
2+
# Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
33

44
# MySQL Connector/Python is licensed under the terms of the GPLv2
55
# <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most

src/mysql_capi.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,7 +1030,6 @@ MySQL_connect(MySQL *self, PyObject *args, PyObject *kwds)
10301030
char *ssl_ca= NULL, *ssl_cert= NULL, *ssl_key= NULL;
10311031
PyObject *charset_name, *compress, *ssl_verify_cert;
10321032
const char* auth_plugin;
1033-
unsigned long ver;
10341033
unsigned long client_flags= 0;
10351034
unsigned int port= 3306, tmp_uint;
10361035
unsigned int protocol= 0;
@@ -1065,7 +1064,6 @@ MySQL_connect(MySQL *self, PyObject *args, PyObject *kwds)
10651064
}
10661065

10671066
mysql_init(&self->session);
1068-
ver= mysql_get_client_version();
10691067

10701068
#ifdef MS_WINDOWS
10711069
if (NULL == host)

tests/test_abstracts.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from decimal import Decimal
2828
from operator import attrgetter
2929

30+
import unittest
3031
import tests
3132
from tests import PY2, foreach_cnx
3233

@@ -185,6 +186,8 @@ def test_reset_session(self):
185186
row = self.cnx.info_query("SELECT @@session.{0}".format(key))
186187
self.assertEqual(value, row[0])
187188

189+
@unittest.skipIf(tests.MYSQL_VERSION > (5, 7, 10),
190+
"As of MySQL 5.7.11, mysql_refresh() is deprecated")
188191
@foreach_cnx()
189192
def test_cmd_refresh(self):
190193
refresh = RefreshOption.LOG | RefreshOption.THREADS

tests/test_cursor.py

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# -*- coding: utf-8 -*-
2-
# Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
2+
# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
33

44
# MySQL Connector/Python is licensed under the terms of the GPLv2
55
# <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
@@ -361,6 +361,8 @@ def test__process_params(self):
361361
datetime.time(20, 3, 23),
362362
st_now,
363363
datetime.timedelta(hours=40, minutes=30, seconds=12),
364+
'foo %(t)s',
365+
'foo %(s)s',
364366
)
365367
exp = (
366368
b'NULL',
@@ -382,6 +384,8 @@ def test__process_params(self):
382384
b"'" + time.strftime('%Y-%m-%d %H:%M:%S', st_now).encode('ascii')
383385
+ b"'",
384386
b"'40:30:12'",
387+
b"'foo %(t)s'",
388+
b"'foo %(s)s'",
385389
)
386390

387391
self.cnx = connection.MySQLConnection(**tests.get_mysql_config())
@@ -421,28 +425,32 @@ def test__process_params_dict(self):
421425
'p': datetime.time(20, 3, 23),
422426
'q': st_now,
423427
'r': datetime.timedelta(hours=40, minutes=30, seconds=12),
428+
's': 'foo %(t)s',
429+
't': 'foo %(s)s',
424430
}
425431
exp = {
426-
b'%(a)s': b'NULL',
427-
b'%(b)s': b'128',
428-
b'%(c)s': b'1281288',
429-
b'%(d)s': repr(float(3.14)) if PY2 else b'3.14',
430-
b'%(e)s': b"'3.14'",
431-
b'%(f)s': b"'back\\\\slash'",
432-
b'%(g)s': b"'newline\\n'",
433-
b'%(h)s': b"'return\\r'",
434-
b'%(i)s': b"'\\'single\\''",
435-
b'%(j)s': b'\'\\"double\\"\'',
436-
b'%(k)s': b"'windows\\\x1a'",
437-
b'%(l)s': b"'Strings are sexy'",
438-
b'%(m)s': b"'\xe8\x8a\xb1'",
439-
b'%(n)s': b"'2008-05-07 20:01:23'",
440-
b'%(o)s': b"'2008-05-07'",
441-
b'%(p)s': b"'20:03:23'",
442-
b'%(q)s': b"'" +
432+
b'a': b'NULL',
433+
b'b': b'128',
434+
b'c': b'1281288',
435+
b'd': repr(float(3.14)) if PY2 else b'3.14',
436+
b'e': b"'3.14'",
437+
b'f': b"'back\\\\slash'",
438+
b'g': b"'newline\\n'",
439+
b'h': b"'return\\r'",
440+
b'i': b"'\\'single\\''",
441+
b'j': b'\'\\"double\\"\'',
442+
b'k': b"'windows\\\x1a'",
443+
b'l': b"'Strings are sexy'",
444+
b'm': b"'\xe8\x8a\xb1'",
445+
b'n': b"'2008-05-07 20:01:23'",
446+
b'o': b"'2008-05-07'",
447+
b'p': b"'20:03:23'",
448+
b'q': b"'" +
443449
time.strftime('%Y-%m-%d %H:%M:%S', st_now).encode('ascii')
444450
+ b"'",
445-
b'%(r)s': b"'40:30:12'",
451+
b'r': b"'40:30:12'",
452+
b's': b"'foo %(t)s'",
453+
b't': b"'foo %(s)s'",
446454
}
447455

448456
self.cnx = connection.MySQLConnection(**tests.get_mysql_config())

0 commit comments

Comments
 (0)