pyodbc.py 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. # mysql/pyodbc.py
  2. # Copyright (C) 2005-2017 the SQLAlchemy authors and contributors
  3. # <see AUTHORS file>
  4. #
  5. # This module is part of SQLAlchemy and is released under
  6. # the MIT License: http://www.opensource.org/licenses/mit-license.php
  7. """
  8. .. dialect:: mysql+pyodbc
  9. :name: PyODBC
  10. :dbapi: pyodbc
  11. :connectstring: mysql+pyodbc://<username>:<password>@<dsnname>
  12. :url: http://pypi.python.org/pypi/pyodbc/
  13. .. note:: The PyODBC for MySQL dialect is not well supported, and
  14. is subject to unresolved character encoding issues
  15. which exist within the current ODBC drivers available.
  16. (see http://code.google.com/p/pyodbc/issues/detail?id=25).
  17. Other dialects for MySQL are recommended.
  18. """
  19. from .base import MySQLDialect, MySQLExecutionContext
  20. from ...connectors.pyodbc import PyODBCConnector
  21. from ... import util
  22. import re
  23. class MySQLExecutionContext_pyodbc(MySQLExecutionContext):
  24. def get_lastrowid(self):
  25. cursor = self.create_cursor()
  26. cursor.execute("SELECT LAST_INSERT_ID()")
  27. lastrowid = cursor.fetchone()[0]
  28. cursor.close()
  29. return lastrowid
  30. class MySQLDialect_pyodbc(PyODBCConnector, MySQLDialect):
  31. supports_unicode_statements = False
  32. execution_ctx_cls = MySQLExecutionContext_pyodbc
  33. pyodbc_driver_name = "MySQL"
  34. def __init__(self, **kw):
  35. # deal with http://code.google.com/p/pyodbc/issues/detail?id=25
  36. kw.setdefault('convert_unicode', True)
  37. super(MySQLDialect_pyodbc, self).__init__(**kw)
  38. def _detect_charset(self, connection):
  39. """Sniff out the character set in use for connection results."""
  40. # Prefer 'character_set_results' for the current connection over the
  41. # value in the driver. SET NAMES or individual variable SETs will
  42. # change the charset without updating the driver's view of the world.
  43. #
  44. # If it's decided that issuing that sort of SQL leaves you SOL, then
  45. # this can prefer the driver value.
  46. rs = connection.execute("SHOW VARIABLES LIKE 'character_set%%'")
  47. opts = dict([(row[0], row[1]) for row in self._compat_fetchall(rs)])
  48. for key in ('character_set_connection', 'character_set'):
  49. if opts.get(key, None):
  50. return opts[key]
  51. util.warn("Could not detect the connection character set. "
  52. "Assuming latin1.")
  53. return 'latin1'
  54. def _extract_error_code(self, exception):
  55. m = re.compile(r"\((\d+)\)").search(str(exception.args))
  56. c = m.group(1)
  57. if c:
  58. return int(c)
  59. else:
  60. return None
  61. dialect = MySQLDialect_pyodbc