Source code for sqlalchemy_jdbcapi.dialects.db2

"""
IBM DB2 JDBC dialect for SQLAlchemy.

Provides support for IBM DB2 for Linux, Unix, Windows, and z/OS.
"""

from __future__ import annotations

import logging
import re
from typing import Any

from sqlalchemy import exc, sql
from sqlalchemy.engine import Connection, Dialect

from .base import BaseJDBCDialect, JDBCDriverConfig

logger = logging.getLogger(__name__)

# Try to import DB2 dialect if available
try:
    from sqlalchemy.dialects.db2.base import DB2Dialect as BaseDB2Dialect

    HAS_DB2_DIALECT = True
except ImportError:
    # Fallback to generic dialect
    BaseDB2Dialect = Dialect  # type: ignore
    HAS_DB2_DIALECT = False
    logger.debug("IBM DB2 dialect not available, using generic implementation")


[docs] class DB2Dialect(BaseJDBCDialect, BaseDB2Dialect): # type: ignore """ IBM DB2 dialect using JDBC driver. Supports DB2-specific features including: - Sequences - Identity columns - Generated columns - Temporal tables (DB2 10+) - JSON support (DB2 11+) Connection URL format: jdbcapi+db2://user:password@host:50000/database """ name = "db2" driver = "jdbcapi" # DB2 capabilities supports_native_boolean = False # DB2 < 11.1 doesn't support BOOLEAN supports_sequences = True supports_identity_columns = True supports_native_enum = False
[docs] @classmethod def get_driver_config(cls) -> JDBCDriverConfig: """Get DB2 JDBC driver configuration.""" return JDBCDriverConfig( driver_class="com.ibm.db2.jcc.DB2Driver", jdbc_url_template="jdbc:db2://{host}:{port}/{database}", default_port=50000, supports_transactions=True, supports_schemas=True, supports_sequences=True, )
[docs] def initialize(self, connection: Connection) -> None: """Initialize DB2 connection.""" if HAS_DB2_DIALECT: super().initialize(connection) # Basic initialization elif not hasattr(self, "_server_version_info"): self._server_version_info = self._get_server_version_info(connection) logger.debug("Initialized DB2 JDBC dialect")
def _get_server_version_info(self, connection: Connection) -> tuple[int, ...]: """ Get DB2 server version. Returns: Tuple of version numbers (e.g., (11, 5, 8)) """ try: # Try DB2-specific version query result = connection.execute( sql.text("SELECT SERVICE_LEVEL FROM SYSIBMADM.ENV_INST_INFO") ).scalar() if result: # Parse version from string like: # "DB2 v11.5.8.0" match = re.search(r"v(\d+)\.(\d+)\.(\d+)", result) if match: major = int(match.group(1)) minor = int(match.group(2)) patch = int(match.group(3)) return (major, minor, patch) except exc.DBAPIError as e: logger.warning(f"Failed to get DB2 server version: {e}") # Fallback: try alternative query try: result = connection.execute( sql.text("VALUES (SYSPROC.VERSION())") ).scalar() if result: match = re.search(r"(\d+)\.(\d+)\.(\d+)", result) if match: return tuple(int(match.group(i)) for i in range(1, 4)) except exc.DBAPIError: pass # Default fallback return (11, 1, 0)
[docs] def do_ping(self, dbapi_connection: Any) -> bool: """Check if DB2 connection is alive.""" try: cursor = dbapi_connection.cursor() cursor.execute("SELECT 1 FROM SYSIBM.SYSDUMMY1") cursor.close() return True except Exception as e: logger.debug(f"DB2 ping failed: {e}") return False
# Export the dialect dialect = DB2Dialect