cymysql.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. # dialects/mysql/cymysql.py
  2. # Copyright (C) 2005-2025 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: https://www.opensource.org/licenses/mit-license.php
  7. r"""
  8. .. dialect:: mysql+cymysql
  9. :name: CyMySQL
  10. :dbapi: cymysql
  11. :connectstring: mysql+cymysql://<username>:<password>@<host>/<dbname>[?<options>]
  12. :url: https://github.com/nakagami/CyMySQL
  13. .. note::
  14. The CyMySQL dialect is **not tested as part of SQLAlchemy's continuous
  15. integration** and may have unresolved issues. The recommended MySQL
  16. dialects are mysqlclient and PyMySQL.
  17. """ # noqa
  18. from __future__ import annotations
  19. from typing import Any
  20. from typing import Iterable
  21. from typing import Optional
  22. from typing import TYPE_CHECKING
  23. from typing import Union
  24. from .base import MySQLDialect
  25. from .mysqldb import MySQLDialect_mysqldb
  26. from .types import BIT
  27. from ... import util
  28. if TYPE_CHECKING:
  29. from ...engine.base import Connection
  30. from ...engine.interfaces import DBAPIConnection
  31. from ...engine.interfaces import DBAPICursor
  32. from ...engine.interfaces import DBAPIModule
  33. from ...engine.interfaces import Dialect
  34. from ...engine.interfaces import PoolProxiedConnection
  35. from ...sql.type_api import _ResultProcessorType
  36. class _cymysqlBIT(BIT):
  37. def result_processor(
  38. self, dialect: Dialect, coltype: object
  39. ) -> Optional[_ResultProcessorType[Any]]:
  40. """Convert MySQL's 64 bit, variable length binary string to a long."""
  41. def process(value: Optional[Iterable[int]]) -> Optional[int]:
  42. if value is not None:
  43. v = 0
  44. for i in iter(value):
  45. v = v << 8 | i
  46. return v
  47. return value
  48. return process
  49. class MySQLDialect_cymysql(MySQLDialect_mysqldb):
  50. driver = "cymysql"
  51. supports_statement_cache = True
  52. description_encoding = None
  53. supports_sane_rowcount = True
  54. supports_sane_multi_rowcount = False
  55. supports_unicode_statements = True
  56. colspecs = util.update_copy(MySQLDialect.colspecs, {BIT: _cymysqlBIT})
  57. @classmethod
  58. def import_dbapi(cls) -> DBAPIModule:
  59. return __import__("cymysql")
  60. def _detect_charset(self, connection: Connection) -> str:
  61. return connection.connection.charset # type: ignore[no-any-return]
  62. def _extract_error_code(self, exception: DBAPIModule.Error) -> int:
  63. return exception.errno # type: ignore[no-any-return]
  64. def is_disconnect(
  65. self,
  66. e: DBAPIModule.Error,
  67. connection: Optional[Union[PoolProxiedConnection, DBAPIConnection]],
  68. cursor: Optional[DBAPICursor],
  69. ) -> bool:
  70. if isinstance(e, self.loaded_dbapi.OperationalError):
  71. return self._extract_error_code(e) in (
  72. 2006,
  73. 2013,
  74. 2014,
  75. 2045,
  76. 2055,
  77. )
  78. elif isinstance(e, self.loaded_dbapi.InterfaceError):
  79. # if underlying connection is closed,
  80. # this is the error you get
  81. return True
  82. else:
  83. return False
  84. dialect = MySQLDialect_cymysql