Skip to content

Commit 89128c5

Browse files
committed
Merge branch 'WL7937' into develop
2 parents 1b56083 + 0049944 commit 89128c5

File tree

5 files changed

+137
-4
lines changed

5 files changed

+137
-4
lines changed

lib/mysql/connector/connection.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
'dsn': None,
7878
'force_ipv6': False,
7979
'auth_plugin': None,
80+
'allow_local_infile': True,
8081
}
8182

8283

@@ -149,7 +150,9 @@ def _do_handshake(self):
149150
if PY2:
150151
regex_ver = re.compile(r"^(\d{1,2})\.(\d{1,2})\.(\d{1,3})(.*)")
151152
else:
153+
# pylint: disable=W1401
152154
regex_ver = re.compile(br"^(\d{1,2})\.(\d{1,2})\.(\d{1,3})(.*)")
155+
# pylint: enable=W1401
153156
match = regex_ver.match(handshake['server_version_original'])
154157
if not match:
155158
raise errors.InterfaceError("Failed parsing MySQL version")
@@ -267,6 +270,12 @@ def config(self, **kwargs):
267270
except KeyError:
268271
pass # Missing compress argument is OK
269272

273+
try:
274+
if not config['allow_local_infile']:
275+
self.set_client_flags([-ClientFlag.LOCAL_FILES])
276+
except KeyError:
277+
pass # Missing allow_local_infile argument is OK
278+
270279
# Configure character set and collation
271280
if 'charset' in config or 'collation' in config:
272281
try:

lib/mysql/connector/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ class ClientFlag(_Flags):
390390
SECURE_CONNECTION,
391391
MULTI_STATEMENTS,
392392
MULTI_RESULTS,
393+
LOCAL_FILES,
393394
]
394395

395396
@classmethod

tests/test_connection.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ def test_DEFAULT_CONFIGURATION(self):
110110
'dsn': None,
111111
'force_ipv6': False,
112112
'auth_plugin': None,
113+
'allow_local_infile': True,
113114
}
114115
self.assertEqual(exp, connection.DEFAULT_CONFIGURATION)
115116

@@ -1794,3 +1795,49 @@ def test_cmd_reset_connection(self):
17941795
self.assertNotEqual(('2',), self.cnx.get_rows()[0][0])
17951796
else:
17961797
self.assertNotEqual((b'2',), self.cnx.get_rows()[0][0])
1798+
1799+
1800+
class WL7937(tests.MySQLConnectorTests):
1801+
"""Allow 'LOAD DATA LOCAL INFILE' by default
1802+
"""
1803+
def setUp(self):
1804+
config = tests.get_mysql_config()
1805+
self.cnx = connection.MySQLConnection(**config)
1806+
self.cur = self.cnx.cursor()
1807+
1808+
self.data_file = os.path.join('tests', 'data', 'local_data.csv')
1809+
1810+
self.cur.execute("DROP TABLE IF EXISTS local_data")
1811+
self.cur.execute(
1812+
"CREATE TABLE local_data (id int, c1 VARCHAR(6), c2 VARCHAR(6))")
1813+
1814+
def tearDown(self):
1815+
try:
1816+
self.cur.execute("DROP TABLE IF EXISTS local_data")
1817+
self.cur.close()
1818+
self.cnx.close()
1819+
except:
1820+
pass
1821+
1822+
def test_load_local_infile(self):
1823+
sql = ("LOAD DATA LOCAL INFILE '{data_file}' INTO "
1824+
"TABLE local_data".format(data_file=self.data_file))
1825+
self.cur.execute(sql)
1826+
self.cur.execute("SELECT * FROM local_data")
1827+
1828+
exp = [
1829+
(1, 'c1_1', 'c2_1'), (2, 'c1_2', 'c2_2'),
1830+
(3, 'c1_3', 'c2_3'), (4, 'c1_4', 'c2_4'),
1831+
(5, 'c1_5', 'c2_5'), (6, 'c1_6', 'c2_6')]
1832+
self.assertEqual(exp, self.cur.fetchall())
1833+
1834+
def test_without_load_local_infile(self):
1835+
config = tests.get_mysql_config()
1836+
config['allow_local_infile'] = False
1837+
1838+
self.cnx = connection.MySQLConnection(**config)
1839+
self.cur = self.cnx.cursor()
1840+
1841+
sql = ("LOAD DATA LOCAL INFILE '{data_file}' INTO "
1842+
"TABLE local_data".format(data_file=self.data_file))
1843+
self.assertRaises(errors.ProgrammingError, self.cur.execute, sql)

tests/test_constants.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,82 @@ def test_get_bit_info(self):
234234
self.assertEqual(exp, constants.FieldFlag.get_bit_info(data).sort())
235235

236236

237+
class ClientFlagTests(tests.MySQLConnectorTests):
238+
239+
desc = {
240+
'LONG_PASSWD': (1 << 0, 'New more secure passwords'),
241+
'FOUND_ROWS': (1 << 1, 'Found instead of affected rows'),
242+
'LONG_FLAG': (1 << 2, 'Get all column flags'),
243+
'CONNECT_WITH_DB': (1 << 3, 'One can specify db on connect'),
244+
'NO_SCHEMA': (1 << 4, "Don't allow database.table.column"),
245+
'COMPRESS': (1 << 5, 'Can use compression protocol'),
246+
'ODBC': (1 << 6, 'ODBC client'),
247+
'LOCAL_FILES': (1 << 7, 'Can use LOAD DATA LOCAL'),
248+
'IGNORE_SPACE': (1 << 8, "Ignore spaces before ''"),
249+
'PROTOCOL_41': (1 << 9, 'New 4.1 protocol'),
250+
'INTERACTIVE': (1 << 10, 'This is an interactive client'),
251+
'SSL': (1 << 11, 'Switch to SSL after handshake'),
252+
'IGNORE_SIGPIPE': (1 << 12, 'IGNORE sigpipes'),
253+
'TRANSACTIONS': (1 << 13, 'Client knows about transactions'),
254+
'RESERVED': (1 << 14, 'Old flag for 4.1 protocol'),
255+
'SECURE_CONNECTION': (1 << 15, 'New 4.1 authentication'),
256+
'MULTI_STATEMENTS': (1 << 16, 'Enable/disable multi-stmt support'),
257+
'MULTI_RESULTS': (1 << 17, 'Enable/disable multi-results'),
258+
'SSL_VERIFY_SERVER_CERT': (1 << 30, ''),
259+
'REMEMBER_OPTIONS': (1 << 31, ''),
260+
}
261+
262+
def test_attributes(self):
263+
"""Check attributes for ClientFlag"""
264+
for key, value in self.desc.items():
265+
self.assertTrue(key in constants.ClientFlag.__dict__,
266+
'{0} is not an attribute of FieldFlag'.format(key))
267+
self.assertEqual(
268+
value[0], constants.ClientFlag.__dict__[key],
269+
'{0} attribute of FieldFlag has wrong value'.format(key))
270+
271+
def test_get_desc(self):
272+
"""Get client flag by name"""
273+
for key, value in self.desc.items():
274+
exp = value[1]
275+
res = constants.ClientFlag.get_desc(key)
276+
self.assertEqual(exp, res)
277+
278+
def test_get_info(self):
279+
"""Get client flag by id"""
280+
for exp, info in self.desc.items():
281+
res = constants.ClientFlag.get_info(info[0])
282+
self.assertEqual(exp, res)
283+
284+
def test_get_bit_info(self):
285+
"""Get names of the set flags"""
286+
data = 0
287+
data |= constants.ClientFlag.LONG_FLAG
288+
data |= constants.ClientFlag.LOCAL_FILES
289+
exp = ['LONG_FLAG', 'LOCAL_FILES'].sort()
290+
self.assertEqual(exp, constants.ClientFlag.get_bit_info(data).sort())
291+
292+
def test_get_default(self):
293+
"""Get client flags which are set by default.
294+
"""
295+
data = [
296+
constants.ClientFlag.LONG_PASSWD,
297+
constants.ClientFlag.LONG_FLAG,
298+
constants.ClientFlag.CONNECT_WITH_DB,
299+
constants.ClientFlag.PROTOCOL_41,
300+
constants.ClientFlag.TRANSACTIONS,
301+
constants.ClientFlag.SECURE_CONNECTION,
302+
constants.ClientFlag.MULTI_STATEMENTS,
303+
constants.ClientFlag.MULTI_RESULTS,
304+
constants.ClientFlag.LOCAL_FILES,
305+
]
306+
exp = 0
307+
for option in data:
308+
exp |= option
309+
310+
self.assertEqual(exp, constants.ClientFlag.get_default())
311+
312+
237313
class CharacterSetTests(tests.MySQLConnectorTests):
238314

239315
"""Tests for constants.CharacterSet"""

tests/test_protocol.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,26 +67,26 @@ def test_make_auth(self):
6767
"""Make a MySQL authentication packet"""
6868
exp = {
6969
'allset': bytearray(
70-
b'\x0d\xa2\x03\x00\x00\x00\x00\x40'
70+
b'\x8d\xa2\x03\x00\x00\x00\x00\x40'
7171
b'\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
7272
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
7373
b'\x68\x61\x6d\x00\x14\x3a\x07\x66\xba\xba\x01\xce'
7474
b'\xbe\x55\xe6\x29\x88\xaa\xae\xdb\x00\xb3\x4d\x91'
7575
b'\x5b\x74\x65\x73\x74\x00'),
7676
'nopass': bytearray(
77-
b'\x0d\xa2\x03\x00\x00\x00\x00\x40'
77+
b'\x8d\xa2\x03\x00\x00\x00\x00\x40'
7878
b'\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
7979
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
8080
b'\x68\x61\x6d\x00\x00\x74\x65\x73\x74\x00'),
8181
'nouser': bytearray(
82-
b'\x0d\xa2\x03\x00\x00\x00\x00\x40'
82+
b'\x8d\xa2\x03\x00\x00\x00\x00\x40'
8383
b'\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
8484
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
8585
b'\x00\x14\x3a\x07\x66\xba\xba\x01\xce'
8686
b'\xbe\x55\xe6\x29\x88\xaa\xae\xdb\x00\xb3\x4d\x91'
8787
b'\x5b\x74\x65\x73\x74\x00'),
8888
'nodb': bytearray(
89-
b'\x0d\xa2\x03\x00\x00\x00\x00\x40'
89+
b'\x8d\xa2\x03\x00\x00\x00\x00\x40'
9090
b'\x21\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
9191
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
9292
b'\x68\x61\x6d\x00\x14\x3a\x07\x66\xba\xba\x01\xce'

0 commit comments

Comments
 (0)