Skip to content

Commit

Permalink
refactor(mssql): port to sqlglot
Browse files Browse the repository at this point in the history
  • Loading branch information
cpcloud committed Jan 23, 2024
1 parent 62ab5b1 commit 400c2d2
Show file tree
Hide file tree
Showing 32 changed files with 1,262 additions and 941 deletions.
44 changes: 22 additions & 22 deletions .github/workflows/ibis-backends.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,16 +133,16 @@ jobs:
sys-deps:
- cmake
- ninja-build
# - name: mssql
# title: MS SQL Server
# extras:
# - mssql
# services:
# - mssql
# sys-deps:
# - freetds-dev
# - unixodbc-dev
# - tdsodbc
- name: mssql
title: MS SQL Server
extras:
- mssql
services:
- mssql
sys-deps:
- freetds-dev
- unixodbc-dev
- tdsodbc
- name: trino
title: Trino
extras:
Expand Down Expand Up @@ -237,18 +237,18 @@ jobs:
sys-deps:
- cmake
- ninja-build
# - os: windows-latest
# backend:
# name: mssql
# title: MS SQL Server
# extras:
# - mssql
# services:
# - mssql
# sys-deps:
# - freetds-dev
# - unixodbc-dev
# - tdsodbc
- os: windows-latest
backend:
name: mssql
title: MS SQL Server
extras:
- mssql
services:
- mssql
sys-deps:
- freetds-dev
- unixodbc-dev
- tdsodbc
- os: windows-latest
backend:
name: trino
Expand Down
25 changes: 24 additions & 1 deletion ibis/backends/base/sqlglot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
if TYPE_CHECKING:
from collections.abc import Iterable, Iterator, Mapping

import pandas as pd
import pyarrow as pa

import ibis.expr.datatypes as dt
Expand All @@ -28,14 +29,36 @@ class SQLGlotBackend(BaseBackend):
compiler: ClassVar[SQLGlotCompiler]
name: ClassVar[str]

@property
def _sqlglot_dialect(self) -> str:
return self.compiler.dialect

@classmethod
def has_operation(cls, operation: type[ops.Value]) -> bool:
# singledispatchmethod overrides `__get__` so we can't directly access
# the dispatcher
dispatcher = cls.compiler.visit_node.register.__self__.dispatcher
return dispatcher.dispatch(operation) is not dispatcher.dispatch(object)

# TODO(kszucs): get_schema() is not registered as an abstract method
def _fetch_from_cursor(self, cursor, schema: sch.Schema) -> pd.DataFrame:
import pandas as pd

from ibis.formats.pandas import PandasData

try:
df = pd.DataFrame.from_records(
cursor, columns=schema.names, coerce_float=True
)
except Exception:
# clean up the cursor if we fail to create the DataFrame
#
# in the sqlite case failing to close the cursor results in
# artificially locked tables
cursor.close()
raise
df = PandasData.convert_table(df, schema)
return df

def table(
self, name: str, schema: str | None = None, database: str | None = None
) -> ir.Table:
Expand Down
53 changes: 53 additions & 0 deletions ibis/backends/base/sqlglot/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -837,3 +837,56 @@ def _from_sqlglot_MAP(cls, key: sge.DataType, value: sge.DataType) -> NoReturn:
@classmethod
def _from_sqlglot_STRUCT(cls, *cols: sge.ColumnDef) -> NoReturn:
raise com.UnsupportedBackendType("Structs not supported in Exasol")


class MSSQLType(SqlglotType):
dialect = "tsql"

@classmethod
def _from_sqlglot_BIT(cls):
return dt.Boolean(nullable=cls.default_nullable)

@classmethod
def _from_sqlglot_IMAGE(cls):
return dt.Binary(nullable=cls.default_nullable)

@classmethod
def _from_sqlglot_DATETIME(cls, n=None):
return dt.Timestamp(
scale=n if n is None else int(n.this.this), nullable=cls.default_nullable
)

@classmethod
def _from_sqlglot_TIMESTAMP(cls):
return dt.Binary(nullable=False)

@classmethod
def _from_ibis_String(cls, dtype: dt.String) -> sge.DataType:
return sge.DataType(
this=typecode.VARCHAR,
expressions=[sge.DataTypeParam(this=sge.Var(this="max"))],
)

@classmethod
def _from_ibis_Array(cls, dtype: dt.String) -> sge.DataType:
raise com.UnsupportedBackendType("SQL Server does not support arrays")

@classmethod
def _from_ibis_Map(cls, dtype: dt.String) -> sge.DataType:
raise com.UnsupportedBackendType("SQL Server does not support ")

@classmethod
def _from_ibis_Struct(cls, dtype: dt.String) -> sge.DataType:
raise com.UnsupportedBackendType("SQL Server does not support structs")

@classmethod
def _from_sqlglot_ARRAY(cls) -> sge.DataType:
raise com.UnsupportedBackendType("SQL Server does not support arrays")

@classmethod
def _from_sqlglot_MAP(cls) -> sge.DataType:
raise com.UnsupportedBackendType("SQL Server does not support map")

@classmethod
def _from_sqlglot_STRUCT(cls) -> sge.DataType:
raise com.UnsupportedBackendType("SQL Server does not support structs")
2 changes: 1 addition & 1 deletion ibis/backends/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ def ddl_con(ddl_backend):
return ddl_backend.connection


@pytest.fixture(params=_get_backends_to_test(keep=("mssql", "sqlite")), scope="session")
@pytest.fixture(params=_get_backends_to_test(keep=("sqlite",)), scope="session")
def alchemy_backend(request, data_dir, tmp_path_factory, worker_id):
"""Set up the SQLAlchemy-based backends."""
return _setup_backend(request, data_dir, tmp_path_factory, worker_id)
Expand Down
Loading

0 comments on commit 400c2d2

Please sign in to comment.