|
1 | 1 | # MySQL Connector/Python - MySQL driver written in Python.
|
2 |
| -# Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. |
| 2 | +# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. |
3 | 3 |
|
4 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2
|
5 | 5 | # <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
|
|
29 | 29 | import weakref
|
30 | 30 |
|
31 | 31 | from . import errors
|
| 32 | +from .catch23 import PY2 |
32 | 33 |
|
33 | 34 | SQL_COMMENT = r"\/\*.*?\*\/"
|
34 | 35 | RE_SQL_COMMENT = re.compile(
|
|
42 | 43 | re.I | re.M | re.S)
|
43 | 44 | RE_SQL_INSERT_VALUES = re.compile(r'.*VALUES\s*(\(.*\)).*', re.I | re.M | re.S)
|
44 | 45 | RE_PY_PARAM = re.compile(b'(%s)')
|
| 46 | +RE_PY_MAPPING_PARAM = re.compile( |
| 47 | + br''' |
| 48 | + % |
| 49 | + \((?P<mapping_key>[^)]+)\) |
| 50 | + (?P<conversion_type>[diouxXeEfFgGcrs%]) |
| 51 | + ''', |
| 52 | + re.X |
| 53 | +) |
45 | 54 | RE_SQL_SPLIT_STMTS = re.compile(
|
46 | 55 | b''';(?=(?:[^"'`]*["'`][^"'`]*["'`])*[^"'`]*$)''')
|
47 | 56 | RE_SQL_FIND_PARAM = re.compile(
|
@@ -73,6 +82,35 @@ def remaining(self):
|
73 | 82 | return len(self.params) - self.index
|
74 | 83 |
|
75 | 84 |
|
| 85 | +def _bytestr_format_dict(bytestr, value_dict): |
| 86 | + """ |
| 87 | + >>> _bytestr_format_dict(b'%(a)s', {b'a': b'foobar'}) |
| 88 | + b'foobar |
| 89 | + >>> _bytestr_format_dict(b'%%(a)s', {b'a': b'foobar'}) |
| 90 | + b'%%(a)s' |
| 91 | + >>> _bytestr_format_dict(b'%%%(a)s', {b'a': b'foobar'}) |
| 92 | + b'%%foobar' |
| 93 | + >>> _bytestr_format_dict(b'%(x)s %(y)s', |
| 94 | + ... {b'x': b'x=%(y)s', b'y': b'y=%(x)s'}) |
| 95 | + b'x=%(y)s y=%(x)s' |
| 96 | + """ |
| 97 | + def replace(matchobj): |
| 98 | + value = None |
| 99 | + groups = matchobj.groupdict() |
| 100 | + if groups["conversion_type"] == b"%": |
| 101 | + value = b"%" |
| 102 | + if groups["conversion_type"] == b"s": |
| 103 | + key = groups["mapping_key"].encode("utf-8") \ |
| 104 | + if PY2 else groups["mapping_key"] |
| 105 | + value = value_dict[key] |
| 106 | + if value is None: |
| 107 | + raise ValueError("Unsupported conversion_type: {0}" |
| 108 | + "".format(groups["conversion_type"])) |
| 109 | + return value.decode("utf-8") if PY2 else value |
| 110 | + return RE_PY_MAPPING_PARAM.sub(replace, bytestr.decode("utf-8") |
| 111 | + if PY2 else bytestr) |
| 112 | + |
| 113 | + |
76 | 114 | class CursorBase(object):
|
77 | 115 | """
|
78 | 116 | Base for defining MySQLCursor. This class is a skeleton and defines
|
@@ -355,7 +393,10 @@ def _process_params_dict(self, params):
|
355 | 393 | conv = to_mysql(conv)
|
356 | 394 | conv = escape(conv)
|
357 | 395 | conv = quote(conv)
|
358 |
| - res["%({0})s".format(key).encode()] = conv |
| 396 | + if PY2: |
| 397 | + res[key] = conv |
| 398 | + else: |
| 399 | + res[key.encode()] = conv |
359 | 400 | except Exception as err:
|
360 | 401 | raise errors.ProgrammingError(
|
361 | 402 | "Failed processing pyformat-parameters; %s" % err)
|
@@ -488,8 +529,8 @@ def execute(self, operation, params=None, multi=False):
|
488 | 529 |
|
489 | 530 | if params is not None:
|
490 | 531 | if isinstance(params, dict):
|
491 |
| - for key, value in self._process_params_dict(params).items(): |
492 |
| - stmt = stmt.replace(key, value) |
| 532 | + stmt = _bytestr_format_dict( |
| 533 | + stmt, self._process_params_dict(params)) |
493 | 534 | elif isinstance(params, (list, tuple)):
|
494 | 535 | psub = _ParamSubstitutor(self._process_params(params))
|
495 | 536 | stmt = RE_PY_PARAM.sub(psub, stmt)
|
@@ -543,8 +584,8 @@ def remove_comments(match):
|
543 | 584 | for params in seq_params:
|
544 | 585 | tmp = fmt
|
545 | 586 | if isinstance(params, dict):
|
546 |
| - for key, value in self._process_params_dict(params).items(): |
547 |
| - tmp = tmp.replace(key, value) |
| 587 | + tmp = _bytestr_format_dict( |
| 588 | + tmp, self._process_params_dict(params)) |
548 | 589 | else:
|
549 | 590 | psub = _ParamSubstitutor(self._process_params(params))
|
550 | 591 | tmp = RE_PY_PARAM.sub(psub, tmp)
|
|
0 commit comments