You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by hu...@apache.org on 2026/10/15 17:39:30 UTC
(superset) 04/15: fix(datasets): count an absent key in the echo exemption as unchanged
This is an automated email from the ASF dual-hosted git repository.
hughhhh pushed a commit to branch hughhhh/pfm-6-explore-indicator
in repository https://gitbox.apache.org/repos/asf/superset.git
commit 3ee2fe0c7c3b8a39516116107b47ca0af99bd39b
Author: Hugh A. Miles II <hu...@gmail.com>
AuthorDate: Wed Oct 14 13:30:05 2026 +0000
fix(datasets): count an absent key in the echo exemption as unchanged
`_upsert_columns` writes only the keys a column entry carries, so a payload
echoing the transform without the monotonicity declaration -- or the
declaration without the transform -- is a valid partial update. The
exemption compared the missing key as `None`, read that as a change, and
wrote *both* fields back as null: the same unrecoverable loss the exemption
was added to prevent, reached by the shape it was added for.
Co-Authored-By: Claude Opus 5 (1M context) <no...@anthropic.com>
Signed-off-by: Hugh A. Miles II <hu...@gmail.com>
---
superset/connectors/sqla/partition_mapping.py | 17 ++++++++++--
.../connectors/sqla/partition_mapping_test.py | 32 ++++++++++++++++++++++
2 files changed, 46 insertions(+), 3 deletions(-)
diff --git a/superset/connectors/sqla/partition_mapping.py b/superset/connectors/sqla/partition_mapping.py
index 01c828242b9..a87d2489c67 100644
--- a/superset/connectors/sqla/partition_mapping.py
+++ b/superset/connectors/sqla/partition_mapping.py
@@ -2242,9 +2242,20 @@ def drop_unmapped_value_transforms(
continue
if stored_by_name is not None and name in stored_by_name:
stored_transform, stored_monotonic = stored_by_name[name]
- if transform == stored_transform and bool(is_monotonic) == bool(
- stored_monotonic
- ):
+ # A key the entry does not carry is unchanged, not `False`:
+ # `_upsert_columns` writes only the keys present, so echoing the
+ # transform without the declaration is a valid partial update. Read
+ # as a change, it failed the exemption and wrote both fields back
+ # as null -- the loss the exemption exists to prevent.
+ monotonic_echoes = (
+ "partition_transform_is_monotonic" not in column
+ or bool(is_monotonic) == bool(stored_monotonic)
+ )
+ transform_echoes = (
+ "partition_value_transform" not in column
+ or transform == stored_transform
+ )
+ if transform_echoes and monotonic_echoes:
# An echo, not an introduction. See `stored_by_name`.
continue
column["partition_value_transform"] = None
diff --git a/tests/unit_tests/connectors/sqla/partition_mapping_test.py b/tests/unit_tests/connectors/sqla/partition_mapping_test.py
index d5c2facd943..aca0ee5a28d 100644
--- a/tests/unit_tests/connectors/sqla/partition_mapping_test.py
+++ b/tests/unit_tests/connectors/sqla/partition_mapping_test.py
@@ -3119,6 +3119,38 @@ def test_a_changed_transform_on_an_unmapped_column_is_still_dropped(
assert columns[0]["partition_value_transform"] is None
+@pytest.mark.parametrize(
+ "entry",
+ [
+ # The transform echoed, the declaration simply absent.
+ {"id": 7, "partition_value_transform": "unix_timestamp(:value)"},
+ # And the reverse: the declaration echoed, the transform absent.
+ {"id": 7, "partition_transform_is_monotonic": True},
+ ],
+)
+def test_a_partial_echo_counts_as_unchanged(entry: dict[str, Any]) -> None:
+ """
+ `_upsert_columns` writes only the keys an entry carries, so a payload
+ echoing one of the two fields is a valid partial update. Read as a change,
+ it failed the exemption and both fields were written back as null -- the
+ same unrecoverable loss the exemption exists to prevent.
+ """
+ columns = [dict(entry)]
+
+ assert (
+ drop_unmapped_value_transforms(
+ columns,
+ partition_column="dt_epoch",
+ partition_mapped_column=None,
+ main_dttm_col="event_time2",
+ names_by_id={7: "event_time"},
+ stored_by_name={"event_time": ("unix_timestamp(:value)", True)},
+ )
+ == []
+ )
+ assert columns[0] == entry
+
+
def test_a_caller_that_cannot_see_storage_keeps_the_stricter_behaviour() -> None:
"""
`stored_by_name` is optional, and omitting it drops an unmapped column's