From 193643717d1042d3244171c9af3888f6009c9c5e Mon Sep 17 00:00:00 2001 From: Phillip Cloud <417981+cpcloud@users.noreply.github.com> Date: Thu, 5 Sep 2024 11:30:13 -0400 Subject: [PATCH] fix(mssql): ensure that dot-sql can be executed when column names are not provided (#10028) Closes #10025. --- ibis/backends/mssql/__init__.py | 3 +++ ibis/backends/mssql/tests/test_client.py | 24 ++++++++++++++++++++ ibis/backends/tests/test_dot_sql.py | 29 +++++++++++++++++++++++- 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/ibis/backends/mssql/__init__.py b/ibis/backends/mssql/__init__.py index ef59caad3dec..363c86e84e17 100644 --- a/ibis/backends/mssql/__init__.py +++ b/ibis/backends/mssql/__init__.py @@ -307,6 +307,9 @@ def _get_schema_using_query(self, query: str) -> sch.Schema: elif newtyp.is_timestamp(): newtyp = newtyp.copy(scale=scale) + if name is None: + name = util.gen_name("col") + schema[name] = newtyp return sch.Schema(schema) diff --git a/ibis/backends/mssql/tests/test_client.py b/ibis/backends/mssql/tests/test_client.py index ec33cd3c16dc..24a8a2fb1a4d 100644 --- a/ibis/backends/mssql/tests/test_client.py +++ b/ibis/backends/mssql/tests/test_client.py @@ -241,3 +241,27 @@ def test_from_url(): ) result = new_con.sql("SELECT 1 AS [a]").to_pandas().a.iat[0] assert result == 1 + + +def test_dot_sql_with_unnamed_columns(con): + expr = con.sql( + "SELECT CAST('2024-01-01 00:00:00' AS DATETIMEOFFSET), 'a' + 'b', 1 AS [col42]" + ) + + schema = expr.schema() + names = schema.names + + assert len(names) == 3 + + assert names[0].startswith("ibis_col") + assert names[1].startswith("ibis_col") + assert names[2] == "col42" + + assert schema.types == ( + dt.Timestamp(timezone="UTC", scale=7), + dt.String(nullable=False), + dt.Int32(nullable=False), + ) + + df = expr.execute() + assert len(df) == 1 diff --git a/ibis/backends/tests/test_dot_sql.py b/ibis/backends/tests/test_dot_sql.py index aa39e7253e61..66f545f3ded9 100644 --- a/ibis/backends/tests/test_dot_sql.py +++ b/ibis/backends/tests/test_dot_sql.py @@ -13,7 +13,11 @@ from ibis import _ from ibis.backends import _get_backend_names from ibis.backends.tests.base import PYTHON_SHORT_VERSION -from ibis.backends.tests.errors import GoogleBadRequest, OracleDatabaseError +from ibis.backends.tests.errors import ( + ExaQueryError, + GoogleBadRequest, + OracleDatabaseError, +) pd = pytest.importorskip("pandas") tm = pytest.importorskip("pandas.testing") @@ -330,3 +334,26 @@ def test_embedded_cte(alltypes, ftname_raw): expr = alltypes.sql(sql, dialect="duckdb") result = expr.head(1).execute() assert len(result) == 1 + + +@dot_sql_never +@pytest.mark.never(["exasol"], raises=ExaQueryError, reason="backend requires aliasing") +@pytest.mark.never( + ["oracle"], raises=OracleDatabaseError, reason="backend requires aliasing" +) +def test_unnamed_columns(con): + sql = "SELECT 'a', 1 AS col42" + sgexpr = sg.parse_one(sql, read="duckdb") + expr = con.sql(sgexpr.sql(con.dialect)) + + schema = expr.schema() + names = schema.names + types = schema.types + + assert len(names) == 2 + + assert names[0] + assert names[1] == "col42" + + assert types[0].is_string() + assert types[1].is_integer()