From e98fc6489e8b071f430da2b314dc2f9481654cf3 Mon Sep 17 00:00:00 2001 From: Gil Forsyth Date: Thu, 18 Jan 2024 16:56:31 -0500 Subject: [PATCH] refactor(oracle): remove cruft --- ibis/backends/oracle/__init__.py | 23 ------ ibis/backends/oracle/datatypes.py | 42 ---------- ibis/backends/oracle/registry.py | 130 ------------------------------ 3 files changed, 195 deletions(-) delete mode 100644 ibis/backends/oracle/datatypes.py delete mode 100644 ibis/backends/oracle/registry.py diff --git a/ibis/backends/oracle/__init__.py b/ibis/backends/oracle/__init__.py index 07c230deea9d6..302733d99e99f 100644 --- a/ibis/backends/oracle/__init__.py +++ b/ibis/backends/oracle/__init__.py @@ -13,14 +13,6 @@ import sqlglot as sg import sqlglot.expressions as sge -# Wow, this is truly horrible -# Get out your clippers, it's time to shave a yak. -# -# 1. oracledb is only supported in sqlalchemy 2.0 -# 2. Ergo, module hacking is required to avoid doing a silly amount of work -# to create multiple lockfiles or port snowflake away from sqlalchemy -# 3. Also the version needs to be spoofed to be >= 7 or else the cx_Oracle -# dialect barfs import ibis import ibis.common.exceptions as exc import ibis.expr.datatypes as dt @@ -487,21 +479,6 @@ def _fetch_from_cursor(self, cursor, schema: sch.Schema) -> pd.DataFrame: df = OraclePandasData.convert_table(df, schema) return df - # def _table_from_schema( - # self, - # name: str, - # schema: sch.Schema, - # temp: bool = False, - # database: str | None = None, - # **kwargs: Any, - # ) -> sa.Table: - # if temp: - # kwargs["oracle_on_commit"] = "PRESERVE ROWS" - # t = super()._table_from_schema(name, schema, temp, database, **kwargs) - # if temp: - # atexit.register(self._clean_up_tmp_table, t) - # return t - def _clean_up_tmp_table(self, name: str) -> None: with self.begin() as bind: # global temporary tables cannot be dropped without first truncating them diff --git a/ibis/backends/oracle/datatypes.py b/ibis/backends/oracle/datatypes.py deleted file mode 100644 index 7ca9c57d49c26..0000000000000 --- a/ibis/backends/oracle/datatypes.py +++ /dev/null @@ -1,42 +0,0 @@ -# from __future__ import annotations - -# import ibis.expr.datatypes as dt -# from ibis.backends.base.sqlglot.datatypes import OracleType as SqlglotOracleType - - -# class OracleType(AlchemyType): -# dialect = "oracle" - -# @classmethod -# def to_ibis(cls, typ, nullable=True): -# if isinstance(typ, oracle.ROWID): -# return dt.String(nullable=nullable) -# elif isinstance(typ, (oracle.RAW, sat.BLOB)): -# return dt.Binary(nullable=nullable) -# elif isinstance(typ, sat.Float): -# return dt.Float64(nullable=nullable) -# elif isinstance(typ, sat.Numeric): -# if typ.scale == 0: -# # kind of a lie, should be int128 because 38 digits -# return dt.Int64(nullable=nullable) -# else: -# return dt.Decimal( -# precision=typ.precision or 38, -# scale=typ.scale or 0, -# nullable=nullable, -# ) -# else: -# return super().to_ibis(typ, nullable=nullable) - -# @classmethod -# def from_ibis(cls, dtype): -# if isinstance(dtype, dt.Float64): -# return sat.Float(precision=53).with_variant(oracle.FLOAT(14), "oracle") -# elif isinstance(dtype, dt.Float32): -# return sat.Float(precision=23).with_variant(oracle.FLOAT(7), "oracle") -# else: -# return super().from_ibis(dtype) - -# @classmethod -# def from_string(cls, type_string, nullable=True): -# return SqlglotOracleType.from_string(type_string, nullable=nullable) diff --git a/ibis/backends/oracle/registry.py b/ibis/backends/oracle/registry.py deleted file mode 100644 index 8c6b074bd21d0..0000000000000 --- a/ibis/backends/oracle/registry.py +++ /dev/null @@ -1,130 +0,0 @@ -from __future__ import annotations - -import sqlalchemy as sa -import toolz -from packaging.version import parse as vparse - -import ibis.expr.operations as ops -from ibis.backends.base.sql.alchemy import ( - fixed_arity, - reduction, - sqlalchemy_operation_registry, - sqlalchemy_window_functions_registry, - unary, -) -from ibis.backends.base.sql.alchemy.registry import ( - _gen_string_find, -) -from ibis.backends.base.sql.alchemy.registry import ( - _literal as _alchemy_literal, -) - -operation_registry = sqlalchemy_operation_registry.copy() - -operation_registry.update(sqlalchemy_window_functions_registry) - - -def _cot(t, op): - arg = t.translate(op.arg) - return 1.0 / sa.func.tan(arg, type_=t.get_sqla_type(op.arg.dtype)) - - -def _cov(t, op): - return t._reduction(getattr(sa.func, f"covar_{op.how[:4]}"), op) - - -def _corr(t, op): - if op.how == "sample": - raise ValueError( - f"{t.__class__.__name__} only implements population correlation " - "coefficient" - ) - return t._reduction(sa.func.corr, op) - - -def _literal(t, op): - dtype = op.dtype - value = op.value - - if value is None: - return sa.null() - elif ( - # handle UUIDs in sqlalchemy < 2 - vparse(sa.__version__) < vparse("2") and dtype.is_uuid() - ): - return sa.literal(str(value), type_=t.get_sqla_type(dtype)) - elif dtype.is_timestamp(): - if dtype.timezone is not None: - return sa.func.to_utc_timestamp_tz(value.isoformat(timespec="microseconds")) - return sa.func.to_timestamp( - # comma for sep here because T is a special character in Oracle - # the FX prefix means "requires an exact match" - value.isoformat(sep=",", timespec="microseconds"), - "FXYYYY-MM-DD,HH24:MI:SS.FF6", - ) - elif dtype.is_date(): - return sa.func.to_date(value.isoformat(), "FXYYYY-MM-DD") - elif dtype.is_time(): - raise NotImplementedError("Time values are not supported in Oracle") - return _alchemy_literal(t, op) - - -def _second(t, op): - # Oracle returns fractional seconds, so `floor` the result to match - # the behavior of other backends - return sa.func.floor(sa.extract("SECOND", t.translate(op.arg))) - - -def _string_join(t, op): - sep = t.translate(op.sep) - values = list(map(t.translate, op.arg)) - return sa.func.concat(*toolz.interpose(sep, values)) - - -def _median(t, op): - arg = op.arg - if (where := op.where) is not None: - arg = ops.IfElse(where, arg, None) - - if arg.dtype.is_numeric(): - return sa.func.median(t.translate(arg)) - return sa.cast( - sa.func.percentile_disc(0.5).within_group(t.translate(arg)), - t.get_sqla_type(op.dtype), - ) - - -operation_registry.update( - { - ops.Log2: unary(lambda arg: sa.func.log(2, arg)), - ops.Log10: unary(lambda arg: sa.func.log(10, arg)), - ops.Log: fixed_arity(lambda arg, base: sa.func.log(base, arg), 2), - ops.Power: fixed_arity(sa.func.power, 2), - ops.Cot: _cot, - ops.Pi: lambda *_: sa.func.ACOS(-1), - ops.RandomScalar: fixed_arity(sa.func.dbms_random.value, 0), - ops.Degrees: lambda t, op: 180 * t.translate(op.arg) / t.translate(ops.Pi()), - ops.Radians: lambda t, op: t.translate(ops.Pi()) * t.translate(op.arg) / 180, - # Aggregate Functions - ops.Covariance: _cov, - ops.Correlation: _corr, - ops.ApproxMedian: reduction(sa.func.approx_median), - ops.Median: _median, - # Temporal - ops.ExtractSecond: _second, - # String - ops.StrRight: fixed_arity(lambda arg, nchars: sa.func.substr(arg, -nchars), 2), - ops.StringJoin: _string_join, - ops.StringFind: _gen_string_find(sa.func.instr), - # Generic - ops.Hash: unary(sa.func.ora_hash), - ops.Literal: _literal, - ops.Levenshtein: fixed_arity(sa.func.utl_match.edit_distance, 2), - } -) - -_invalid_operations = set() - -operation_registry = { - k: v for k, v in operation_registry.items() if k not in _invalid_operations -}