pysybase.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. # sybase/pysybase.py
  2. # Copyright (C) 2010-2022 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. """
  8. .. dialect:: sybase+pysybase
  9. :name: Python-Sybase
  10. :dbapi: Sybase
  11. :connectstring: sybase+pysybase://<username>:<password>@<dsn>/[database name]
  12. :url: https://python-sybase.sourceforge.net/
  13. Unicode Support
  14. ---------------
  15. The python-sybase driver does not appear to support non-ASCII strings of any
  16. kind at this time.
  17. """ # noqa
  18. from sqlalchemy import processors
  19. from sqlalchemy import types as sqltypes
  20. from sqlalchemy.dialects.sybase.base import SybaseDialect
  21. from sqlalchemy.dialects.sybase.base import SybaseExecutionContext
  22. from sqlalchemy.dialects.sybase.base import SybaseSQLCompiler
  23. class _SybNumeric(sqltypes.Numeric):
  24. def result_processor(self, dialect, type_):
  25. if not self.asdecimal:
  26. return processors.to_float
  27. else:
  28. return sqltypes.Numeric.result_processor(self, dialect, type_)
  29. class SybaseExecutionContext_pysybase(SybaseExecutionContext):
  30. def set_ddl_autocommit(self, dbapi_connection, value):
  31. if value:
  32. # call commit() on the Sybase connection directly,
  33. # to avoid any side effects of calling a Connection
  34. # transactional method inside of pre_exec()
  35. dbapi_connection.commit()
  36. def pre_exec(self):
  37. SybaseExecutionContext.pre_exec(self)
  38. for param in self.parameters:
  39. for key in list(param):
  40. param["@" + key] = param[key]
  41. del param[key]
  42. class SybaseSQLCompiler_pysybase(SybaseSQLCompiler):
  43. def bindparam_string(self, name, **kw):
  44. return "@" + name
  45. class SybaseDialect_pysybase(SybaseDialect):
  46. driver = "pysybase"
  47. execution_ctx_cls = SybaseExecutionContext_pysybase
  48. statement_compiler = SybaseSQLCompiler_pysybase
  49. supports_statement_cache = True
  50. colspecs = {sqltypes.Numeric: _SybNumeric, sqltypes.Float: sqltypes.Float}
  51. @classmethod
  52. def dbapi(cls):
  53. import Sybase
  54. return Sybase
  55. def create_connect_args(self, url):
  56. opts = url.translate_connect_args(username="user", password="passwd")
  57. return ([opts.pop("host")], opts)
  58. def do_executemany(self, cursor, statement, parameters, context=None):
  59. # calling python-sybase executemany yields:
  60. # TypeError: string too long for buffer
  61. for param in parameters:
  62. cursor.execute(statement, param)
  63. def _get_server_version_info(self, connection):
  64. vers = connection.exec_driver_sql("select @@version_number").scalar()
  65. # i.e. 15500, 15000, 12500 == (15, 5, 0, 0), (15, 0, 0, 0),
  66. # (12, 5, 0, 0)
  67. return (vers / 1000, vers % 1000 / 100, vers % 100 / 10, vers % 10)
  68. def is_disconnect(self, e, connection, cursor):
  69. if isinstance(
  70. e, (self.dbapi.OperationalError, self.dbapi.ProgrammingError)
  71. ):
  72. msg = str(e)
  73. return (
  74. "Unable to complete network request to host" in msg
  75. or "Invalid connection state" in msg
  76. or "Invalid cursor state" in msg
  77. )
  78. else:
  79. return False
  80. dialect = SybaseDialect_pysybase