Source code for sqlalchemy_jdbcapi.dialects.sqlite

"""
SQLite JDBC dialect for SQLAlchemy.

Provides SQLite support through JDBC (mainly for testing or Java interop).
"""

from __future__ import annotations

import logging
from typing import Any

from sqlalchemy import exc, sql
from sqlalchemy.dialects.sqlite.base import SQLiteDialect as BaseSQLiteDialect
from sqlalchemy.engine import Connection

from .base import BaseJDBCDialect, JDBCDriverConfig

logger = logging.getLogger(__name__)


[docs] class SQLiteDialect(BaseJDBCDialect, BaseSQLiteDialect): """ SQLite dialect using JDBC driver. Note: For production use, the native sqlite3 dialect is recommended. This JDBC dialect is primarily useful for: - Testing JDBC infrastructure - Java application integration - Environments where native sqlite3 is not available Connection URL format: jdbcapi+sqlite:///path/to/database.db jdbcapi+sqlite:///:memory: # In-memory database """ name = "sqlite" driver = "jdbcapi" # SQLite capabilities supports_native_boolean = False supports_sequences = False supports_native_enum = False supports_native_decimal = False
[docs] @classmethod def import_dbapi(cls) -> Any: """ Import JDBC module. SQLAlchemy's SQLite dialect expects sqlite_version_info attribute, so we add it as a wrapper. """ from sqlalchemy_jdbcapi import jdbc # Add sqlite_version_info if not present (required by SQLAlchemy's SQLite dialect) if not hasattr(jdbc, "sqlite_version_info"): # Use a reasonable default version jdbc.sqlite_version_info = (3, 40, 0) return jdbc
[docs] @classmethod def get_driver_config(cls) -> JDBCDriverConfig: """Get SQLite JDBC driver configuration.""" return JDBCDriverConfig( driver_class="org.sqlite.JDBC", jdbc_url_template="jdbc:sqlite:{database}", default_port=0, # Not applicable for SQLite supports_transactions=True, supports_schemas=False, # SQLite has limited schema support supports_sequences=False, )
[docs] def create_connect_args(self, url: Any) -> tuple[list[Any], dict[str, Any]]: """ Create connection arguments for SQLite. Handles file paths and in-memory databases. """ config = self.get_driver_config() # Build JDBC URL if url.database: if url.database == ":memory:": jdbc_url = "jdbc:sqlite::memory:" else: jdbc_url = f"jdbc:sqlite:{url.database}" else: # Default to in-memory jdbc_url = "jdbc:sqlite::memory:" logger.debug(f"Creating SQLite connection to: {jdbc_url}") kwargs = { "jclassname": config.driver_class, "url": jdbc_url, "driver_args": None, } return ([], kwargs)
[docs] def initialize(self, connection: Connection) -> None: """Initialize SQLite connection.""" super().initialize(connection) logger.debug("Initialized SQLite JDBC dialect")
def _get_server_version_info(self, connection: Connection) -> tuple[int, ...]: """ Get SQLite version. Returns: Tuple of version numbers (e.g., (3, 40, 1)) """ try: result = connection.execute(sql.text("SELECT sqlite_version()")).scalar() if result: # Parse version from string like: "3.40.1" parts = result.split(".") return tuple(int(p) for p in parts[:3]) except exc.DBAPIError as e: logger.warning(f"Failed to get SQLite version: {e}") # Default fallback return (3, 30, 0)
[docs] def do_ping(self, dbapi_connection: Any) -> bool: """Check if SQLite connection is alive.""" try: cursor = dbapi_connection.cursor() cursor.execute("SELECT 1") cursor.close() return True except Exception as e: logger.debug(f"SQLite ping failed: {e}") return False
# Export the dialect dialect = SQLiteDialect