connections.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  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. from MySQLdb import cursors
  8. from _mysql_exceptions import Warning, Error, InterfaceError, DataError, \
  9. DatabaseError, OperationalError, IntegrityError, InternalError, \
  10. NotSupportedError, ProgrammingError
  11. import types, _mysql
  12. import re
  13. def defaulterrorhandler(connection, cursor, errorclass, errorvalue):
  14. """
  15. If cursor is not None, (errorclass, errorvalue) is appended to
  16. cursor.messages; otherwise it is appended to
  17. connection.messages. Then errorclass is raised with errorvalue as
  18. the value.
  19. You can override this with your own error handler by assigning it
  20. to the instance.
  21. """
  22. error = errorclass, errorvalue
  23. if cursor:
  24. cursor.messages.append(error)
  25. else:
  26. connection.messages.append(error)
  27. del cursor
  28. del connection
  29. raise errorclass, errorvalue
  30. re_numeric_part = re.compile(r"^(\d+)")
  31. def numeric_part(s):
  32. """Returns the leading numeric part of a string.
  33. >>> numeric_part("20-alpha")
  34. 20
  35. >>> numeric_part("foo")
  36. >>> numeric_part("16b")
  37. 16
  38. """
  39. m = re_numeric_part.match(s)
  40. if m:
  41. return int(m.group(1))
  42. return None
  43. class Connection(_mysql.connection):
  44. """MySQL Database Connection Object"""
  45. default_cursor = cursors.Cursor
  46. def __init__(self, *args, **kwargs):
  47. """
  48. Create a connection to the database. It is strongly recommended
  49. that you only use keyword parameters. Consult the MySQL C API
  50. documentation for more information.
  51. host
  52. string, host to connect
  53. user
  54. string, user to connect as
  55. passwd
  56. string, password to use
  57. db
  58. string, database to use
  59. port
  60. integer, TCP/IP port to connect to
  61. unix_socket
  62. string, location of unix_socket to use
  63. conv
  64. conversion dictionary, see MySQLdb.converters
  65. connect_timeout
  66. number of seconds to wait before the connection attempt
  67. fails.
  68. compress
  69. if set, compression is enabled
  70. named_pipe
  71. if set, a named pipe is used to connect (Windows only)
  72. init_command
  73. command which is run once the connection is created
  74. read_default_file
  75. file from which default client values are read
  76. read_default_group
  77. configuration group to use from the default file
  78. cursorclass
  79. class object, used to create cursors (keyword only)
  80. use_unicode
  81. If True, text-like columns are returned as unicode objects
  82. using the connection's character set. Otherwise, text-like
  83. columns are returned as strings. columns are returned as
  84. normal strings. Unicode objects will always be encoded to
  85. the connection's character set regardless of this setting.
  86. charset
  87. If supplied, the connection character set will be changed
  88. to this character set (MySQL-4.1 and newer). This implies
  89. use_unicode=True.
  90. sql_mode
  91. If supplied, the session SQL mode will be changed to this
  92. setting (MySQL-4.1 and newer). For more details and legal
  93. values, see the MySQL documentation.
  94. client_flag
  95. integer, flags to use or 0
  96. (see MySQL docs or constants/CLIENTS.py)
  97. ssl
  98. dictionary or mapping, contains SSL connection parameters;
  99. see the MySQL documentation for more details
  100. (mysql_ssl_set()). If this is set, and the client does not
  101. support SSL, NotSupportedError will be raised.
  102. local_infile
  103. integer, non-zero enables LOAD LOCAL INFILE; zero disables
  104. autocommit
  105. If False (default), autocommit is disabled.
  106. If True, autocommit is enabled.
  107. If None, autocommit isn't set and server default is used.
  108. There are a number of undocumented, non-standard methods. See the
  109. documentation for the MySQL C API for some hints on what they do.
  110. """
  111. from MySQLdb.constants import CLIENT, FIELD_TYPE
  112. from MySQLdb.converters import conversions
  113. from weakref import proxy
  114. kwargs2 = kwargs.copy()
  115. if 'conv' in kwargs:
  116. conv = kwargs['conv']
  117. else:
  118. conv = conversions
  119. conv2 = {}
  120. for k, v in conv.items():
  121. if isinstance(k, int) and isinstance(v, list):
  122. conv2[k] = v[:]
  123. else:
  124. conv2[k] = v
  125. kwargs2['conv'] = conv2
  126. cursorclass = kwargs2.pop('cursorclass', self.default_cursor)
  127. charset = kwargs2.pop('charset', '')
  128. if charset:
  129. use_unicode = True
  130. else:
  131. use_unicode = False
  132. use_unicode = kwargs2.pop('use_unicode', use_unicode)
  133. sql_mode = kwargs2.pop('sql_mode', '')
  134. client_flag = kwargs.get('client_flag', 0)
  135. client_version = tuple([ numeric_part(n) for n in _mysql.get_client_info().split('.')[:2] ])
  136. if client_version >= (4, 1):
  137. client_flag |= CLIENT.MULTI_STATEMENTS
  138. if client_version >= (5, 0):
  139. client_flag |= CLIENT.MULTI_RESULTS
  140. kwargs2['client_flag'] = client_flag
  141. # PEP-249 requires autocommit to be initially off
  142. autocommit = kwargs2.pop('autocommit', False)
  143. super(Connection, self).__init__(*args, **kwargs2)
  144. self.cursorclass = cursorclass
  145. self.encoders = dict([ (k, v) for k, v in conv.items()
  146. if type(k) is not int ])
  147. self._server_version = tuple([ numeric_part(n) for n in self.get_server_info().split('.')[:2] ])
  148. db = proxy(self)
  149. def _get_string_literal():
  150. def string_literal(obj, dummy=None):
  151. return db.string_literal(obj)
  152. return string_literal
  153. def _get_unicode_literal():
  154. def unicode_literal(u, dummy=None):
  155. return db.literal(u.encode(unicode_literal.charset))
  156. return unicode_literal
  157. def _get_string_decoder():
  158. def string_decoder(s):
  159. return s.decode(string_decoder.charset)
  160. return string_decoder
  161. string_literal = _get_string_literal()
  162. self.unicode_literal = unicode_literal = _get_unicode_literal()
  163. self.string_decoder = string_decoder = _get_string_decoder()
  164. if not charset:
  165. charset = self.character_set_name()
  166. self.set_character_set(charset)
  167. if sql_mode:
  168. self.set_sql_mode(sql_mode)
  169. if use_unicode:
  170. self.converter[FIELD_TYPE.STRING].append((None, string_decoder))
  171. self.converter[FIELD_TYPE.VAR_STRING].append((None, string_decoder))
  172. self.converter[FIELD_TYPE.VARCHAR].append((None, string_decoder))
  173. self.converter[FIELD_TYPE.BLOB].append((None, string_decoder))
  174. self.encoders[types.StringType] = string_literal
  175. self.encoders[types.UnicodeType] = unicode_literal
  176. self._transactional = self.server_capabilities & CLIENT.TRANSACTIONS
  177. if self._transactional:
  178. if autocommit is not None:
  179. self.autocommit(autocommit)
  180. self.messages = []
  181. def autocommit(self, on):
  182. on = bool(on)
  183. if self.get_autocommit() != on:
  184. _mysql.connection.autocommit(self, on)
  185. def cursor(self, cursorclass=None):
  186. """
  187. Create a cursor on which queries may be performed. The
  188. optional cursorclass parameter is used to create the
  189. Cursor. By default, self.cursorclass=cursors.Cursor is
  190. used.
  191. """
  192. return (cursorclass or self.cursorclass)(self)
  193. def __enter__(self):
  194. if self.get_autocommit():
  195. self.query("BEGIN")
  196. return self.cursor()
  197. def __exit__(self, exc, value, tb):
  198. if exc:
  199. self.rollback()
  200. else:
  201. self.commit()
  202. def literal(self, o):
  203. """
  204. If o is a single object, returns an SQL literal as a string.
  205. If o is a non-string sequence, the items of the sequence are
  206. converted and returned as a sequence.
  207. Non-standard. For internal use; do not use this in your
  208. applications.
  209. """
  210. return self.escape(o, self.encoders)
  211. def begin(self):
  212. """Explicitly begin a connection. Non-standard.
  213. DEPRECATED: Will be removed in 1.3.
  214. Use an SQL BEGIN statement instead."""
  215. from warnings import warn
  216. warn("begin() is non-standard and will be removed in 1.3",
  217. DeprecationWarning, 2)
  218. self.query("BEGIN")
  219. if not hasattr(_mysql.connection, 'warning_count'):
  220. def warning_count(self):
  221. """Return the number of warnings generated from the
  222. last query. This is derived from the info() method."""
  223. from string import atoi
  224. info = self.info()
  225. if info:
  226. return atoi(info.split()[-1])
  227. else:
  228. return 0
  229. def set_character_set(self, charset):
  230. """Set the connection character set to charset. The character
  231. set can only be changed in MySQL-4.1 and newer. If you try
  232. to change the character set from the current value in an
  233. older version, NotSupportedError will be raised."""
  234. if charset == "utf8mb4":
  235. py_charset = "utf8"
  236. else:
  237. py_charset = charset
  238. if self.character_set_name() != charset:
  239. try:
  240. super(Connection, self).set_character_set(charset)
  241. except AttributeError:
  242. if self._server_version < (4, 1):
  243. raise NotSupportedError("server is too old to set charset")
  244. self.query('SET NAMES %s' % charset)
  245. self.store_result()
  246. self.string_decoder.charset = py_charset
  247. self.unicode_literal.charset = py_charset
  248. def set_sql_mode(self, sql_mode):
  249. """Set the connection sql_mode. See MySQL documentation for
  250. legal values."""
  251. if self._server_version < (4, 1):
  252. raise NotSupportedError("server is too old to set sql_mode")
  253. self.query("SET SESSION sql_mode='%s'" % sql_mode)
  254. self.store_result()
  255. def show_warnings(self):
  256. """Return detailed information about warnings as a
  257. sequence of tuples of (Level, Code, Message). This
  258. is only supported in MySQL-4.1 and up. If your server
  259. is an earlier version, an empty sequence is returned."""
  260. if self._server_version < (4,1): return ()
  261. self.query("SHOW WARNINGS")
  262. r = self.store_result()
  263. warnings = r.fetch_row(0)
  264. return warnings
  265. Warning = Warning
  266. Error = Error
  267. InterfaceError = InterfaceError
  268. DatabaseError = DatabaseError
  269. DataError = DataError
  270. OperationalError = OperationalError
  271. IntegrityError = IntegrityError
  272. InternalError = InternalError
  273. ProgrammingError = ProgrammingError
  274. NotSupportedError = NotSupportedError
  275. errorhandler = defaulterrorhandler