hughhhh opened a new pull request, #43758:
URL: https://github.com/apache/superset/pull/43758

   ### SUMMARY
   
   Second of four, stacked on the model/migration PR. Reads the mapping and 
appends an equivalent predicate on the partition column to every query, so 
chart authors change nothing and queries prune.
   
   **Operator safety is the whole of this change.** The PRD says "comparison 
and range operators map directly; `IN` maps element-wise" — that is not sound 
in general, and the unsoundness is silent, showing up as wrong chart numbers 
rather than an error. A mirrored predicate `P2` may only be `AND`-ed onto the 
query when the original `P1` *implies* it:
   
   | Original | Safe when |
   |---|---|
   | `col = v`, `col IN (…)` | **always** — `T` is a function |
   | `col >=`, `>`, `<`, `<=`, `TEMPORAL_RANGE` | **only if `T` is monotonic** |
   | `col != v`, `NOT IN`, `LIKE`, `IS NULL`, … | **never** |
   
   Negations are never safe because `T` need not be injective: `lower(:value)` 
with `country != 'US'` mirrors to `region_key != 'us'`, which excludes rows 
whose `country` is already lowercase `'us'` — rows the original filter *keeps*.
   
   **Monotonicity is declared, not inferred.** An earlier draft inferred it 
from the column type ("a temporal→partition-key transform is monotonic by 
construction"). That's wrong, and it fails on partition schemes people actually 
use: `hour(:value)`, `date_format(:value, 'dd')` and `dayofweek(:value)` are 
all reasonable transforms on a `TIMESTAMP` column and none preserve ordering. 
Since the Explore time range is a *range* operator, this is not an edge case. 
`T(lower) <= T(upper)` is asserted at runtime as a backstop — necessary, not 
sufficient, and free because both bounds are already being resolved.
   
   **Two things worth reviewer attention:**
   
   1. `get_time_filter` applied the dataset timezone and legacy hour offset to 
the bounds *internally*. That adjustment is extracted into `adjust_time_bounds` 
so the mirrored predicate is resolved from the **same instants** the timestamp 
predicate compares against. Probing the raw bounds would be wrong by exactly 
the offset, silently; duplicating the logic would drift.
   2. **`PARTITION_FILTER_MAPPING` must be configured as a static boolean.** 
`FEATURE_FLAGS` also accepts per-request callables, and since the mapping only 
enters the cache key when active, a flag resolving per user would let a 
flag-*off* user read a cache entry written from pruned SQL by a flag-*on* user.
   
   **Safety posture.** Values are bound, never interpolated — they're 
attacker-controlled in the sense that a Gamma user picks filter values. The 
probe query references no tables, so it can't leak data or bypass RLS. Any 
failure at all falls open to no pruning: the query still runs and is still 
correct, it just scans more partitions.
   
   **Deliberate non-coverage,** documented in PR 4: filter-value dropdowns 
(`values_for_column` builds its own `SELECT DISTINCT` and never reaches this 
code path), RLS predicates and `extras.where` (raw SQL appended downstream of 
the structured-filter loop), and columns with an active `advanced_data_type` 
(`translate_filter` builds its own predicate shape from *translated* values, so 
the `(operator, value)` pair this reasoning depends on doesn't exist).
   
   ### BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
   
   The mirrored predicate lands in `where_clause_and` and shows up in **View 
query** as an ordinary `WHERE` clause, by design:
   
   ```sql
   WHERE event_time >= '2026-01-01 00:00:00'
     AND event_time <  '2026-02-01 00:00:00'
     AND dt_epoch   >= 1767225600
     AND dt_epoch   <  1769904000
   ```
   
   ### TESTING INSTRUCTIONS
   
   ```bash
   pytest tests/unit_tests/models/partition_mirroring_test.py \
          tests/unit_tests/connectors/sqla/partition_mapping_test.py
   ```
   
   The mirroring tests stub the engine probe and assert on the generated SQL, 
so they pin down *which* predicates are emitted and with what values — where 
the correctness argument lives. Worth reading as the review surface: nothing 
emitted for `!=`/`NOT IN`/`LIKE`/`IS NULL`; nothing for a range when the 
transform isn't declared monotonic; nothing when `T(lo) > T(hi)`; no duplicate 
when `granularity` and a `TEMPORAL_RANGE` filter hit the same column; and the 
timezone/hour-offset tests, which catch the whole class of off-by-offset bugs.
   
   There is **no UI to configure a mapping yet** — this is exercised through 
the ORM.
   
   ### ADDITIONAL INFORMATION
   - [ ] Has associated issue:
   - [x] Required feature flags: `PARTITION_FILTER_MAPPING` (off by default)
   - [ ] Changes UI
   - [ ] Includes DB Migration (follow approval process in 
[SIP-59](https://github.com/apache/superset/issues/13351))
   - [x] Introduces new feature or API
   - [ ] Removes existing feature or API
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to