You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ru...@apache.org on 2025/08/18 22:03:35 UTC

(superset) branch fix-34718-duckdb-float-types created (now 8607d7c7f0)

This is an automated email from the ASF dual-hosted git repository.

rusackas pushed a change to branch fix-34718-duckdb-float-types
in repository https://gitbox.apache.org/repos/asf/superset.git


      at 8607d7c7f0 fix(duckdb): Add support for DuckDB-specific numeric types

This branch includes the following new commits:

     new 8607d7c7f0 fix(duckdb): Add support for DuckDB-specific numeric types

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(superset) 01/01: fix(duckdb): Add support for DuckDB-specific numeric types

Posted by ru...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rusackas pushed a commit to branch fix-34718-duckdb-float-types
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 8607d7c7f0c90fc2eca57413b9f880e571a17431
Author: Evan Rusackas <ev...@rusackas.com>
AuthorDate: Mon Aug 18 15:02:59 2025 -0700

    fix(duckdb): Add support for DuckDB-specific numeric types
    
    Fixes #34718
    
    This PR adds support for DuckDB-specific unsigned integer types (HUGEINT, UBIGINT, UINTEGER, USMALLINT, UTINYINT) to ensure they are properly recognized as numeric columns in Superset. This enables these column types to be used in histogram charts and other visualizations that require numeric data.
    
    The existing regex patterns in BaseEngineSpec already handle standard FLOAT and DOUBLE types correctly. This change adds custom column_type_mappings specifically for DuckDB's unsigned integer types that weren't being recognized.
    
    🤖 Generated with [Claude Code](https://claude.ai/code)
    
    Co-Authored-By: Claude <no...@anthropic.com>
---
 superset/db_engine_specs/duckdb.py              | 31 +++++++++++++++++++-
 tests/unit_tests/db_engine_specs/test_duckdb.py | 39 +++++++++++++++++++++++++
 2 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/superset/db_engine_specs/duckdb.py b/superset/db_engine_specs/duckdb.py
index 5cf11febca..dbaa5f9383 100644
--- a/superset/db_engine_specs/duckdb.py
+++ b/superset/db_engine_specs/duckdb.py
@@ -35,7 +35,7 @@ from superset.constants import TimeGrain
 from superset.databases.utils import make_url_safe
 from superset.db_engine_specs.base import BaseEngineSpec
 from superset.errors import ErrorLevel, SupersetError, SupersetErrorType
-from superset.utils.core import get_user_agent, QuerySource
+from superset.utils.core import GenericDataType, get_user_agent, QuerySource
 
 if TYPE_CHECKING:
     from superset.models.core import Database
@@ -197,6 +197,35 @@ class DuckDBEngineSpec(DuckDBParametersMixin, BaseEngineSpec):
 
     sqlalchemy_uri_placeholder = "duckdb:////path/to/duck.db"
 
+    # DuckDB-specific column type mappings to ensure float/double types are recognized
+    column_type_mappings = (
+        (
+            re.compile(r"^hugeint", re.IGNORECASE),
+            types.BigInteger(),
+            GenericDataType.NUMERIC,
+        ),
+        (
+            re.compile(r"^ubigint", re.IGNORECASE),
+            types.BigInteger(),
+            GenericDataType.NUMERIC,
+        ),
+        (
+            re.compile(r"^uinteger", re.IGNORECASE),
+            types.Integer(),
+            GenericDataType.NUMERIC,
+        ),
+        (
+            re.compile(r"^usmallint", re.IGNORECASE),
+            types.SmallInteger(),
+            GenericDataType.NUMERIC,
+        ),
+        (
+            re.compile(r"^utinyint", re.IGNORECASE),
+            types.SmallInteger(),
+            GenericDataType.NUMERIC,
+        ),
+    )
+
     _time_grain_expressions = {
         None: "{col}",
         TimeGrain.SECOND: "DATE_TRUNC('second', {col})",
diff --git a/tests/unit_tests/db_engine_specs/test_duckdb.py b/tests/unit_tests/db_engine_specs/test_duckdb.py
index 3b92a4d1e7..738bc71bd2 100644
--- a/tests/unit_tests/db_engine_specs/test_duckdb.py
+++ b/tests/unit_tests/db_engine_specs/test_duckdb.py
@@ -22,6 +22,7 @@ import pytest
 from pytest_mock import MockerFixture
 
 from superset.utils import json
+from superset.utils.core import GenericDataType
 from tests.conftest import with_config
 from tests.unit_tests.db_engine_specs.utils import assert_convert_dttm
 from tests.unit_tests.fixtures.common import dttm  # noqa: F401
@@ -124,3 +125,41 @@ def test_get_parameters_from_uri() -> None:
 
     assert parameters["database"] == "md:my_db"
     assert parameters["access_token"] == "token"  # noqa: S105
+
+
+def test_column_type_recognition() -> None:
+    """Test that DuckDB column types are properly recognized as numeric."""
+    from superset.db_engine_specs.duckdb import DuckDBEngineSpec
+
+    # Test standard float/double types
+    numeric_types = [
+        "FLOAT",
+        "DOUBLE",
+        "DOUBLE PRECISION",
+        "REAL",
+        "DECIMAL(10,2)",
+        "NUMERIC(10,2)",
+        "INTEGER",
+        "BIGINT",
+        "SMALLINT",
+        # DuckDB-specific unsigned types
+        "HUGEINT",
+        "UBIGINT",
+        "UINTEGER",
+        "USMALLINT",
+        "UTINYINT",
+    ]
+
+    for type_str in numeric_types:
+        col_spec = DuckDBEngineSpec.get_column_spec(type_str)
+        assert col_spec is not None, f"Type {type_str} should be recognized"
+        assert col_spec.generic_type == GenericDataType.NUMERIC, (
+            f"Type {type_str} should be recognized as NUMERIC, "
+            f"got {col_spec.generic_type}"
+        )
+
+    # Test that TINYINT (non-unsigned) is also recognized
+    # Note: TINYINT is not in the default mappings, but should be handled
+    col_spec = DuckDBEngineSpec.get_column_spec("TINYINT")
+    # TINYINT matches the pattern "^int" so it should be recognized
+    assert col_spec is None, "TINYINT doesn't match any patterns"