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 2026/10/02 20:53:22 UTC
(superset) 01/01: test(cratedb): cover epoch-ms timestamp decoding against a real instance
This is an automated email from the ASF dual-hosted git repository.
rusackas pushed a commit to branch fix/crate-timestamp-testcontainers
in repository https://gitbox.apache.org/repos/asf/superset.git
commit c0d1dc51451ae63d40310e332009aad90c8fd238
Author: Evan Rusackas <ev...@rusackas.com>
AuthorDate: Fri Oct 2 13:52:35 2026 -0700
test(cratedb): cover epoch-ms timestamp decoding against a real instance
#44720 fixed CrateEngineSpec.fetch_data to decode TIMESTAMP columns via
cursor._result["col_types"] (crate-python's DBAPI cursor.description
always reports type_code=None, confirmed by reading
crate.client.cursor.Cursor.description directly), but only unit tests
with a mocked cursor._result ever exercised it. Those would never
notice a future crate-python release renaming or restructuring that
private attribute.
Adds a testcontainers case that creates a real table with both
TIMESTAMP WITHOUT TIME ZONE and TIMESTAMP WITH TIME ZONE columns
(type codes 15 and 11 per crate.client.converter.DataType, confirmed
against the installed driver), inserts epoch-millisecond values, and
runs fetch_data against the real raw DBAPI cursor from a live query.
Co-Authored-By: Evan Rusackas <ev...@preset.io>
Co-Authored-By: Claude Sonnet 5 <no...@anthropic.com>
---
tests/testcontainers/db_engine_specs/test_crate.py | 44 ++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/tests/testcontainers/db_engine_specs/test_crate.py b/tests/testcontainers/db_engine_specs/test_crate.py
index 6ad7fb3cc25..245fb1b5d11 100644
--- a/tests/testcontainers/db_engine_specs/test_crate.py
+++ b/tests/testcontainers/db_engine_specs/test_crate.py
@@ -26,6 +26,7 @@ runs natively on GitHub Actions' x86_64 runners.
"""
from collections.abc import Iterator
+from datetime import datetime
import pytest
from sqlalchemy import (
@@ -101,3 +102,46 @@ def test_get_columns_maps_native_types(engine: Engine) -> None:
for col in by_name.values():
spec = CrateEngineSpec.get_column_spec(str(col["type"]))
assert spec is not None
+
+
+def test_fetch_data_decodes_epoch_ms_timestamps(engine: Engine) -> None:
+ """
+ Regression for apache/superset#44720: crate-python's real DBAPI cursor
+ always reports ``type_code=None`` in ``cursor.description`` (confirmed
+ by reading ``crate.client.cursor.Cursor.description`` directly -- it
+ hardcodes ``None`` for every description slot but the column name), so
+ ``CrateEngineSpec.fetch_data`` has to find TIMESTAMP columns via the
+ driver's private ``cursor._result["col_types"]`` instead. The existing
+ unit tests mock that attribute directly and would never notice if a
+ future crate-python release renamed or restructured it; only a real
+ cursor, from a real query against a real server, exercises the actual
+ attribute this code depends on.
+
+ CrateDB's wire protocol reports both ``TIMESTAMP WITHOUT TIME ZONE`` and
+ ``TIMESTAMP WITH TIME ZONE`` as epoch-millisecond integers (type codes
+ 15 and 11 respectively -- see ``crate.client.converter.DataType``);
+ both must decode to the same real ``datetime``.
+ """
+ with engine.begin() as conn:
+ conn.exec_driver_sql(
+ "CREATE TABLE pilot_timestamps ("
+ "id INTEGER PRIMARY KEY, "
+ "ts_no_tz TIMESTAMP WITHOUT TIME ZONE, "
+ "ts_with_tz TIMESTAMP WITH TIME ZONE"
+ ")"
+ )
+ conn.exec_driver_sql(
+ "INSERT INTO pilot_timestamps (id, ts_no_tz, ts_with_tz) "
+ "VALUES (1, 1704067200000, 1704067200000)"
+ )
+ conn.exec_driver_sql("REFRESH TABLE pilot_timestamps")
+
+ raw_conn = engine.raw_connection()
+ try:
+ cursor = raw_conn.cursor()
+ cursor.execute("SELECT ts_no_tz, ts_with_tz FROM pilot_timestamps WHERE id = 1")
+ rows = CrateEngineSpec.fetch_data(cursor)
+ finally:
+ raw_conn.close()
+
+ assert rows == [(datetime(2024, 1, 1), datetime(2024, 1, 1))]