Repository: apache/airflow
File: providers/oracle/src/airflow/providers/oracle/hooks/oracle.py (Python)

Code before:
def _safe_read(val):
    if val is not None and callable(getattr(val, "read", None)):
        return val.read()
    return val


def _safe_read_row(row):
    if row is not None:
        return tuple([_safe_read(value) for value in row])
    return row


def fetch_all_handler(cursor) -> list[tuple] | None:
    """Return results for DbApiHook.run()."""
    if not hasattr(cursor, "description"):
        raise RuntimeError(
            "The database we interact with does not support DBAPI 2.0. Use operator and "
            "handlers that are specifically designed for your database."
        )
    if cursor.description is not None:
        results = [_safe_read_row(row) for row in cursor.fetchall()]
        return results
    return None


def fetch_one_handler(cursor) -> list[tuple] | None:
    """Return first result for DbApiHook.run()."""
    if not hasattr(cursor, "description"):
        raise RuntimeError(
            "The database we interact with does not support DBAPI 2.0. Use operator and "
            "handlers that are specifically designed for your database."
        )
    if cursor.description is not None:
        return _safe_read_row(cursor.fetchone())
    return None


class OracleHook(DbApiHook):
    """
    Interact with Oracle SQL.

    :param oracle_conn_id: The :ref:`Oracle connection id <howto/connection:oracle>`
        used for Oracle credentials.
    :param thick_mode: Specify whether to use python-oracledb in thick mode. Defaults to False.
        If set to True, you must have the Oracle Client libraries installed.
        See `oracledb docs<https://python-oracledb.readthedocs.io/en/latest/user_guide/initialization.html>`
        for more info.
    :param thick_mode_lib_dir: Path to use to find the Oracle Client libraries when using thick mode.
        If not specified, defaults to the standard way of locating the Oracle Client library on the OS.
        See `oracledb docs
        <https://python-oracledb.readthedocs.io/en/latest/user_guide/initialization.html#setting-the-oracle-client-library-directory>`

Review comment (suggestion):
```suggestion
def fetch_one_handler(cursor) -> tuple | None:
```

Code after:

class OracleHook(DbApiHook):
    """
    Interact with Oracle SQL.

    :param oracle_conn_id: The :ref:`Oracle connection id <howto/connection:oracle>`
        used for Oracle credentials.
    :param thick_mode: Specify whether to use python-oracledb in thick mode. Defaults to False.
        If set to True, you must have the Oracle Client libraries installed.
        See `oracledb docs<https://python-oracledb.readthedocs.io/en/latest/user_guide/initialization.html>`
        for more info.
    :param thick_mode_lib_dir: Path to use to find the Oracle Client libraries when using thick mode.
        If not specified, defaults to the standard way of locating the Oracle Client library on the OS.
        See `oracledb docs
        <https://python-oracledb.readthedocs.io/en/latest/user_guide/initialization.html#setting-the-oracle-client-library-directory>`
        for more info.
    :param thick_mode_config_dir: Path to use to find the Oracle Client library
        configuration files when using thick mode.
        If not specified, defaults to the standard way of locating the Oracle Client
        library configuration files on the OS.
        See `oracledb docs
        <https://python-oracledb.readthedocs.io/en/latest/user_guide/initialization.html#optional-oracle-net-configuration-files>`
        for more info.
    :param fetch_decimals: Specify whether numbers should be fetched as ``decimal.Decimal`` values.
        See `defaults.fetch_decimals
        <https://python-oracledb.readthedocs.io/en/latest/api_manual/defaults.html#defaults.fetch_decimals>`
        for more info.
    :param fetch_lobs: Specify whether to fetch strings/bytes for CLOBs or BLOBs instead of locators.
        See `defaults.fetch_lobs
        <https://python-oracledb.readthedocs.io/en/latest/api_manual/defaults.html#defaults.fetch_decimals>`
        for more info.
    """

    conn_name_attr = "oracle_conn_id"
    default_conn_name = "oracle_default"
    conn_type = "oracle"
    hook_name = "Oracle"

    _test_connection_sql = "select 1 from dual"
    supports_autocommit = True

    def __init__(
        self,
        *args,
        thick_mode: bool | None = None,
        thick_mode_lib_dir: str | None = None,
        thick_mode_config_dir: str | None = None,
        fetch_decimals: bool | None = None,
        fetch_lobs: bool | None = None,
        **kwargs,
    ) -> None: