kerwin-zk opened a new pull request, #9155:
URL: https://github.com/apache/paimon/pull/9155

   ### Purpose
   
   `MergeIntoPaimonTable` extracts the target-only conjuncts of the merge 
condition and uses them to prune the target table before the full outer join 
(`targetOnlyCondition` / `filteredTargetPlan`, 
`MergeIntoPaimonTable.scala:63-69`).
   
   That pruning is sound for `WHEN MATCHED` and `WHEN NOT MATCHED`: a target 
row that fails a target-only conjunct can never satisfy the whole merge 
condition, so it can never be matched, and dropping it cannot change the 
outcome of those actions.
   
   It is **not** sound for `WHEN NOT MATCHED BY SOURCE`. The pruned-away rows 
are exactly the population that clause is defined over, so their actions are 
silently skipped — no error, no warning, just fewer rows changed.
   
   Repro on a partitioned table holding `pt = 'p1'` and `pt = 'p2'` rows, with 
a source that only contains `a = 1`:
   
   ```sql
   MERGE INTO target t
   USING source s
   ON t.a = s.a AND t.pt = 'p1'
   WHEN MATCHED THEN UPDATE SET t.b = s.b
   WHEN NOT MATCHED BY SOURCE THEN UPDATE SET t.c = 'stale'
   ```
   
   Every `pt = 'p2'` row should be updated to `stale` (no source row can ever 
match it), but none of them is:
   
   ```
   Expected                Actual
    [1,100,c1,p1]          [1,100,c1,p1]
    [2,20,stale,p1]        [2,20,stale,p1]
   ![3,30,stale,p2]        [3,30,c3,p2]
   ![4,40,stale,p2]        [4,40,c4,p2]
   ```
   
   The pruning was introduced together with MERGE INTO itself in #2331 
(2023-11-17), one month before `WHEN NOT MATCHED BY SOURCE` was added in #2517 
(2023-12-22), and its safety argument was never revisited.
   
   Note the V2 row-level paths (`ReplaceData` / `WriteDelta`) are rewritten by 
Spark and are **not** affected, so today the same statement produces different 
results depending on whether the table qualifies for 
`SparkTable.supportsV2RowLevelOps`. Primary key tables never qualify, so they 
always take the affected V1 path.
   
   **Fix:** disable the pruning when the merge has any `WHEN NOT MATCHED BY 
SOURCE` action. Setting `targetOnlyCondition` to `None` covers all three places 
it feeds — `filteredTargetPlan`, `findCandidateDataSplits` and 
`targetDSWithFilePathCol` — so there is no path left that can drop those rows.
   
   A follow-up can restore part of the pruning by handling the excluded rows as 
a separate not-matched-by-source-only stream: they are all 
not-matched-by-source by definition, so they never need to be joined against 
the source, only read and rewritten.
   
   ### Tests
   
   Added `Paimon MergeInto: not matched by source is not narrowed by 
target-only condition` to the `MergeIntoNotMatchedBySourceTest` trait, which is 
mixed into all eight MERGE INTO test classes (V1/V2 x primary key/append x 
bucketed/non-bucketed).
   
   Verified both directions on `paimon-spark-3.5`:
   
   | | with fix | without fix |
   | --- | --- | --- |
   | total | `succeeded 476, failed 0` | `succeeded 470, failed 6` |
   | failures | none | the 6 V1 classes, all on the new test |
   
   Without the fix, the split is exactly along the V1/V2 line, which also pins 
down that primary key tables always take the V1 path:
   
   ```
   FAILED   MergeIntoPrimaryKeyBucketedTableTest
   FAILED   MergeIntoPrimaryKeyNonBucketTableTest
   FAILED   MergeIntoAppendBucketedTableTest
   FAILED   MergeIntoAppendNonBucketedTableTest
   FAILED   V2MergeIntoPrimaryKeyBucketedTableTest
   FAILED   V2MergeIntoPrimaryKeyNonBucketTableTest
   passed   V2MergeIntoAppendBucketedTableTest
   passed   V2MergeIntoAppendNonBucketedTableTest
   ```
   
   ### API and Format
   
   No API or format change.
   
   ### Documentation
   
   No documentation change; this restores the documented SQL semantics of `WHEN 
NOT MATCHED BY SOURCE`.
   


-- 
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]

Reply via email to