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

beto pushed a commit to branch pinot-dialect-timestamp
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 88657c3cfd569eea440306c337dcd4cea3505aeb
Author: Beto Dealmeida <[email protected]>
AuthorDate: Wed Oct 1 11:55:23 2025 -0400

    fix: Pinot dialect date truncation
---
 superset/sql/dialects/pinot.py               | 11 ++++
 tests/unit_tests/sql/dialects/pinot_tests.py | 77 ++++++++++++++++++++++++++++
 2 files changed, 88 insertions(+)

diff --git a/superset/sql/dialects/pinot.py b/superset/sql/dialects/pinot.py
index 05d32f004b..f667b9bdab 100644
--- a/superset/sql/dialects/pinot.py
+++ b/superset/sql/dialects/pinot.py
@@ -78,6 +78,12 @@ class Pinot(MySQL):
             exp.DataType.Type.UBIGINT: "UNSIGNED",
         }
 
+        TRANSFORMS = {
+            **MySQL.Generator.TRANSFORMS,
+        }
+        # Remove DATE_TRUNC transformation - Pinot supports standard SQL 
DATE_TRUNC
+        TRANSFORMS.pop(exp.DateTrunc, None)
+
         def datatype_sql(self, expression: exp.DataType) -> str:
             # Don't use MySQL's VARCHAR size requirement logic
             # Just use TYPE_MAPPING for all types
@@ -95,3 +101,8 @@ class Pinot(MySQL):
                 return f"{type_sql} UNSIGNED{nested}"
 
             return f"{type_sql}{nested}"
+
+        def cast_sql(self, expression: exp.Cast, safe_prefix: str | None = 
None) -> str:
+            # Pinot doesn't support MySQL's TIMESTAMP() function
+            # Use standard CAST syntax instead
+            return super(MySQL.Generator, self).cast_sql(expression, 
safe_prefix)
diff --git a/tests/unit_tests/sql/dialects/pinot_tests.py 
b/tests/unit_tests/sql/dialects/pinot_tests.py
index f1a6cfb729..afbd01e88a 100644
--- a/tests/unit_tests/sql/dialects/pinot_tests.py
+++ b/tests/unit_tests/sql/dialects/pinot_tests.py
@@ -421,3 +421,80 @@ def test_unsigned_type() -> None:
 
     assert "UNSIGNED" in result
     assert "BIGINT" in result
+
+
+def test_date_trunc_preserved() -> None:
+    """
+    Test that DATE_TRUNC is preserved and not converted to MySQL's DATE() 
function.
+    """
+    sql = "SELECT DATE_TRUNC('day', dt_column) FROM table"
+    result = sqlglot.parse_one(sql, Pinot).sql(Pinot)
+
+    assert "DATE_TRUNC" in result
+    assert "DATE_TRUNC('day'" in result or "DATE_TRUNC('DAY'" in result
+    # Should not be converted to MySQL's DATE() function
+    assert result != "SELECT DATE(dt_column) FROM table"
+
+
+def test_cast_timestamp_preserved() -> None:
+    """
+    Test that CAST AS TIMESTAMP is preserved and not converted to TIMESTAMP() 
function.
+    """
+    sql = "SELECT CAST(dt_column AS TIMESTAMP) FROM table"
+    result = sqlglot.parse_one(sql, Pinot).sql(Pinot)
+
+    assert "CAST" in result
+    assert "AS TIMESTAMP" in result
+    # Should not be converted to MySQL's TIMESTAMP() function
+    assert "TIMESTAMP(dt_column)" not in result
+
+
+def test_date_trunc_with_cast_timestamp() -> None:
+    """
+    Test the original complex query with DATE_TRUNC and CAST AS TIMESTAMP.
+    Verifies that both are preserved in parse/generate round-trip.
+    """
+    sql = """
+SELECT
+  CAST(
+    DATE_TRUNC(
+      'day',
+      CAST(
+        DATETIMECONVERT(
+          dt_epoch_ms, '1:MILLISECONDS:EPOCH',
+          '1:MILLISECONDS:EPOCH', '1:MILLISECONDS'
+        ) AS TIMESTAMP
+      )
+    ) AS TIMESTAMP
+  ),
+  SUM(a) + SUM(b)
+FROM
+  "default".c
+WHERE
+  dt_epoch_ms >= 1735690800000
+  AND dt_epoch_ms < 1759328588000
+  AND locality != 'US'
+GROUP BY
+  CAST(
+    DATE_TRUNC(
+      'day',
+      CAST(
+        DATETIMECONVERT(
+          dt_epoch_ms, '1:MILLISECONDS:EPOCH',
+          '1:MILLISECONDS:EPOCH', '1:MILLISECONDS'
+        ) AS TIMESTAMP
+      )
+    ) AS TIMESTAMP
+  )
+LIMIT
+  10000
+    """
+    result = sqlglot.parse_one(sql, Pinot).sql(Pinot)
+
+    # Verify DATE_TRUNC and CAST are preserved
+    assert "DATE_TRUNC" in result
+    assert "CAST" in result
+
+    # Verify these are NOT converted to MySQL functions
+    assert "TIMESTAMP(DATETIMECONVERT" not in result
+    assert result.count("DATE_TRUNC") == 2  # Should appear twice (SELECT and 
GROUP BY)

Reply via email to