You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

398 lines
14 KiB

6 years ago
  1. """
  2. This module implements connections for MySQLdb. Presently there is
  3. only one class: Connection. Others are unlikely. However, you might
  4. want to make your own subclasses. In most cases, you will probably
  5. override Connection.default_cursor with a non-standard Cursor class.
  6. """
  7. import re
  8. import sys
  9. from MySQLdb import cursors
  10. from MySQLdb.compat import unicode, PY2
  11. from _mysql_exceptions import (
  12. Warning, Error, InterfaceError, DataError,
  13. DatabaseError, OperationalError, IntegrityError, InternalError,
  14. NotSupportedError, ProgrammingError,
  15. )
  16. import _mysql
  17. if not PY2:
  18. if sys.version_info[:2] < (3, 6):
  19. # See http://bugs.python.org/issue24870
  20. _surrogateescape_table = [chr(i) if i < 0x80 else chr(i + 0xdc00) for i in range(256)]
  21. def _fast_surrogateescape(s):
  22. return s.decode('latin1').translate(_surrogateescape_table)
  23. else:
  24. def _fast_surrogateescape(s):
  25. return s.decode('ascii', 'surrogateescape')
  26. def defaulterrorhandler(connection, cursor, errorclass, errorvalue):
  27. """
  28. If cursor is not None, (errorclass, errorvalue) is appended to
  29. cursor.messages; otherwise it is appended to
  30. connection.messages. Then errorclass is raised with errorvalue as
  31. the value.
  32. You can override this with your own error handler by assigning it
  33. to the instance.
  34. """
  35. error = errorclass, errorvalue
  36. if cursor:
  37. cursor.messages.append(error)
  38. else:
  39. connection.messages.append(error)
  40. del cursor
  41. del connection
  42. if isinstance(errorvalue, BaseException):
  43. raise errorvalue
  44. if errorclass is not None:
  45. raise errorclass(errorvalue)
  46. else:
  47. raise Exception(errorvalue)
  48. re_numeric_part = re.compile(r"^(\d+)")
  49. def numeric_part(s):
  50. """Returns the leading numeric part of a string.
  51. >>> numeric_part("20-alpha")
  52. 20
  53. >>> numeric_part("foo")
  54. >>> numeric_part("16b")
  55. 16
  56. """
  57. m = re_numeric_part.match(s)
  58. if m:
  59. return int(m.group(1))
  60. return None
  61. class Connection(_mysql.connection):
  62. """MySQL Database Connection Object"""
  63. default_cursor = cursors.Cursor
  64. waiter = None
  65. def __init__(self, *args, **kwargs):
  66. """
  67. Create a connection to the database. It is strongly recommended
  68. that you only use keyword parameters. Consult the MySQL C API
  69. documentation for more information.
  70. :param str host: host to connect
  71. :param str user: user to connect as
  72. :param str password: password to use
  73. :param str passwd: alias of password, for backward compatibility
  74. :param str database: database to use
  75. :param str db: alias of database, for backward compatibility
  76. :param int port: TCP/IP port to connect to
  77. :param str unix_socket: location of unix_socket to use
  78. :param dict conv: conversion dictionary, see MySQLdb.converters
  79. :param int connect_timeout:
  80. number of seconds to wait before the connection attempt fails.
  81. :param bool compress: if set, compression is enabled
  82. :param str named_pipe: if set, a named pipe is used to connect (Windows only)
  83. :param str init_command:
  84. command which is run once the connection is created
  85. :param str read_default_file:
  86. file from which default client values are read
  87. :param str read_default_group:
  88. configuration group to use from the default file
  89. :param type cursorclass:
  90. class object, used to create cursors (keyword only)
  91. :param bool use_unicode:
  92. If True, text-like columns are returned as unicode objects
  93. using the connection's character set. Otherwise, text-like
  94. columns are returned as strings. columns are returned as
  95. normal strings. Unicode objects will always be encoded to
  96. the connection's character set regardless of this setting.
  97. Default to False on Python 2 and True on Python 3.
  98. :param str charset:
  99. If supplied, the connection character set will be changed
  100. to this character set (MySQL-4.1 and newer). This implies
  101. use_unicode=True.
  102. :param str sql_mode:
  103. If supplied, the session SQL mode will be changed to this
  104. setting (MySQL-4.1 and newer). For more details and legal
  105. values, see the MySQL documentation.
  106. :param int client_flag:
  107. flags to use or 0 (see MySQL docs or constants/CLIENTS.py)
  108. :param dict ssl:
  109. dictionary or mapping contains SSL connection parameters;
  110. see the MySQL documentation for more details
  111. (mysql_ssl_set()). If this is set, and the client does not
  112. support SSL, NotSupportedError will be raised.
  113. :param bool local_infile:
  114. enables LOAD LOCAL INFILE; zero disables
  115. :param bool autocommit:
  116. If False (default), autocommit is disabled.
  117. If True, autocommit is enabled.
  118. If None, autocommit isn't set and server default is used.
  119. :param bool binary_prefix:
  120. If set, the '_binary' prefix will be used for raw byte query
  121. arguments (e.g. Binary). This is disabled by default.
  122. There are a number of undocumented, non-standard methods. See the
  123. documentation for the MySQL C API for some hints on what they do.
  124. """
  125. from MySQLdb.constants import CLIENT, FIELD_TYPE
  126. from MySQLdb.converters import conversions
  127. from weakref import proxy
  128. kwargs2 = kwargs.copy()
  129. if 'database' in kwargs2:
  130. kwargs2['db'] = kwargs2.pop('database')
  131. if 'password' in kwargs2:
  132. kwargs2['passwd'] = kwargs2.pop('password')
  133. if 'conv' in kwargs:
  134. conv = kwargs['conv']
  135. else:
  136. conv = conversions
  137. conv2 = {}
  138. for k, v in conv.items():
  139. if isinstance(k, int) and isinstance(v, list):
  140. conv2[k] = v[:]
  141. else:
  142. conv2[k] = v
  143. kwargs2['conv'] = conv2
  144. cursorclass = kwargs2.pop('cursorclass', self.default_cursor)
  145. charset = kwargs2.pop('charset', '')
  146. if charset or not PY2:
  147. use_unicode = True
  148. else:
  149. use_unicode = False
  150. use_unicode = kwargs2.pop('use_unicode', use_unicode)
  151. sql_mode = kwargs2.pop('sql_mode', '')
  152. self._binary_prefix = kwargs2.pop('binary_prefix', False)
  153. client_flag = kwargs.get('client_flag', 0)
  154. client_version = tuple([ numeric_part(n) for n in _mysql.get_client_info().split('.')[:2] ])
  155. if client_version >= (4, 1):
  156. client_flag |= CLIENT.MULTI_STATEMENTS
  157. if client_version >= (5, 0):
  158. client_flag |= CLIENT.MULTI_RESULTS
  159. kwargs2['client_flag'] = client_flag
  160. # PEP-249 requires autocommit to be initially off
  161. autocommit = kwargs2.pop('autocommit', False)
  162. self.waiter = kwargs2.pop('waiter', None)
  163. super(Connection, self).__init__(*args, **kwargs2)
  164. self.cursorclass = cursorclass
  165. self.encoders = dict([ (k, v) for k, v in conv.items()
  166. if type(k) is not int ])
  167. self._server_version = tuple([ numeric_part(n) for n in self.get_server_info().split('.')[:2] ])
  168. self.encoding = 'ascii' # overridden in set_character_set()
  169. db = proxy(self)
  170. # Note: string_literal() is called for bytes object on Python 3 (via bytes_literal)
  171. def string_literal(obj, dummy=None):
  172. return db.string_literal(obj)
  173. if PY2:
  174. # unicode_literal is called for only unicode object.
  175. def unicode_literal(u, dummy=None):
  176. return db.string_literal(u.encode(db.encoding))
  177. else:
  178. # unicode_literal() is called for arbitrary object.
  179. def unicode_literal(u, dummy=None):
  180. return db.string_literal(str(u).encode(db.encoding))
  181. def bytes_literal(obj, dummy=None):
  182. return b'_binary' + db.string_literal(obj)
  183. def string_decoder(s):
  184. return s.decode(db.encoding)
  185. if not charset:
  186. charset = self.character_set_name()
  187. self.set_character_set(charset)
  188. if sql_mode:
  189. self.set_sql_mode(sql_mode)
  190. if use_unicode:
  191. for t in (FIELD_TYPE.STRING, FIELD_TYPE.VAR_STRING, FIELD_TYPE.VARCHAR, FIELD_TYPE.TINY_BLOB,
  192. FIELD_TYPE.MEDIUM_BLOB, FIELD_TYPE.LONG_BLOB, FIELD_TYPE.BLOB):
  193. self.converter[t].append((None, string_decoder))
  194. self.encoders[bytes] = string_literal
  195. self.encoders[unicode] = unicode_literal
  196. self._transactional = self.server_capabilities & CLIENT.TRANSACTIONS
  197. if self._transactional:
  198. if autocommit is not None:
  199. self.autocommit(autocommit)
  200. self.messages = []
  201. def autocommit(self, on):
  202. on = bool(on)
  203. if self.get_autocommit() != on:
  204. _mysql.connection.autocommit(self, on)
  205. def cursor(self, cursorclass=None):
  206. """
  207. Create a cursor on which queries may be performed. The
  208. optional cursorclass parameter is used to create the
  209. Cursor. By default, self.cursorclass=cursors.Cursor is
  210. used.
  211. """
  212. return (cursorclass or self.cursorclass)(self)
  213. def query(self, query):
  214. # Since _mysql releases GIL while querying, we need immutable buffer.
  215. if isinstance(query, bytearray):
  216. query = bytes(query)
  217. if self.waiter is not None:
  218. self.send_query(query)
  219. self.waiter(self.fileno())
  220. self.read_query_result()
  221. else:
  222. _mysql.connection.query(self, query)
  223. def __enter__(self):
  224. from warnings import warn
  225. warn("context interface will be changed. Use explicit conn.commit() or conn.rollback().",
  226. DeprecationWarning, 2)
  227. if self.get_autocommit():
  228. self.query("BEGIN")
  229. return self.cursor()
  230. def __exit__(self, exc, value, tb):
  231. if exc:
  232. self.rollback()
  233. else:
  234. self.commit()
  235. def _bytes_literal(self, bs):
  236. assert isinstance(bs, (bytes, bytearray))
  237. x = self.string_literal(bs) # x is escaped and quoted bytes
  238. if self._binary_prefix:
  239. return b'_binary' + x
  240. return x
  241. def _tuple_literal(self, t):
  242. return "(%s)" % (','.join(map(self.literal, t)))
  243. def literal(self, o):
  244. """If o is a single object, returns an SQL literal as a string.
  245. If o is a non-string sequence, the items of the sequence are
  246. converted and returned as a sequence.
  247. Non-standard. For internal use; do not use this in your
  248. applications.
  249. """
  250. if isinstance(o, bytearray):
  251. s = self._bytes_literal(o)
  252. elif not PY2 and isinstance(o, bytes):
  253. s = self._bytes_literal(o)
  254. elif isinstance(o, (tuple, list)):
  255. s = self._tuple_literal(o)
  256. else:
  257. s = self.escape(o, self.encoders)
  258. # Python 3(~3.4) doesn't support % operation for bytes object.
  259. # We should decode it before using %.
  260. # Decoding with ascii and surrogateescape allows convert arbitrary
  261. # bytes to unicode and back again.
  262. # See http://python.org/dev/peps/pep-0383/
  263. if not PY2 and isinstance(s, (bytes, bytearray)):
  264. return _fast_surrogateescape(s)
  265. return s
  266. def begin(self):
  267. """Explicitly begin a connection. Non-standard.
  268. DEPRECATED: Will be removed in 1.3.
  269. Use an SQL BEGIN statement instead."""
  270. from warnings import warn
  271. warn("begin() is non-standard and will be removed in 1.4",
  272. DeprecationWarning, 2)
  273. self.query("BEGIN")
  274. if not hasattr(_mysql.connection, 'warning_count'):
  275. def warning_count(self):
  276. """Return the number of warnings generated from the
  277. last query. This is derived from the info() method."""
  278. info = self.info()
  279. if info:
  280. return int(info.split()[-1])
  281. else:
  282. return 0
  283. def set_character_set(self, charset):
  284. """Set the connection character set to charset. The character
  285. set can only be changed in MySQL-4.1 and newer. If you try
  286. to change the character set from the current value in an
  287. older version, NotSupportedError will be raised."""
  288. if charset == "utf8mb4":
  289. py_charset = "utf8"
  290. else:
  291. py_charset = charset
  292. if self.character_set_name() != charset:
  293. try:
  294. super(Connection, self).set_character_set(charset)
  295. except AttributeError:
  296. if self._server_version < (4, 1):
  297. raise NotSupportedError("server is too old to set charset")
  298. self.query('SET NAMES %s' % charset)
  299. self.store_result()
  300. self.encoding = py_charset
  301. def set_sql_mode(self, sql_mode):
  302. """Set the connection sql_mode. See MySQL documentation for
  303. legal values."""
  304. if self._server_version < (4, 1):
  305. raise NotSupportedError("server is too old to set sql_mode")
  306. self.query("SET SESSION sql_mode='%s'" % sql_mode)
  307. self.store_result()
  308. def show_warnings(self):
  309. """Return detailed information about warnings as a
  310. sequence of tuples of (Level, Code, Message). This
  311. is only supported in MySQL-4.1 and up. If your server
  312. is an earlier version, an empty sequence is returned."""
  313. if self._server_version < (4,1): return ()
  314. self.query("SHOW WARNINGS")
  315. r = self.store_result()
  316. warnings = r.fetch_row(0)
  317. return warnings
  318. Warning = Warning
  319. Error = Error
  320. InterfaceError = InterfaceError
  321. DatabaseError = DatabaseError
  322. DataError = DataError
  323. OperationalError = OperationalError
  324. IntegrityError = IntegrityError
  325. InternalError = InternalError
  326. ProgrammingError = ProgrammingError
  327. NotSupportedError = NotSupportedError
  328. errorhandler = defaulterrorhandler
  329. # vim: colorcolumn=100

Powered by TurnKey Linux.