…ards
The join subsearch maxout setting bounds how many subsearch rows are joined
against, not which ones. LogicalSystemLimit takes its collation from its
input, which is empty for an unsorted subsearch, so the discarded row is
whichever one the scan yields last.
testJoinSubsearchMaxOut asserted an exact count that is only reachable when
the cap happens to discard a row matching the join key. Three of the six
right-side rows match, so a cap of five need not discard a matching row at
all, and the result is 10 or 15 depending on scan order. It passed on one
shard and failed on five with expected:<10> but was:<15>.
The cap is now two, below the three matching rows, so at most two can
survive and the joined result cannot exceed 5 x 2 regardless of which rows
are kept. The original query keeps its exact uncapped assertion and gains
that bound. A companion test filters the subsearch to the join key so every
retained row joins identically, which makes the capped count exact again.
No production behavior is changed.
Signed-off-by: Eric Wei <[email protected]>
Description
CalcitePPLJoinIT.testJoinSubsearchMaxOutpassed on a single shard and failed on five withexpected:<10> but was:<15>.The fix: lower the cap so it actually bounds the result, assert that bound on the original query, and add a companion test that filters the subsearch to the join key so the capped count is exact again. Test-only change, no production behavior is touched.
Why the original assertion could not hold
plugins.ppl.join.subsearch_maxoutbounds how many subsearch rows are joined against, not which ones.LogicalSystemLimittakes its collation from its input, and an unsorted subsearch has none, so the discarded row is whichever one the scan yields last. The user documentation andjoin.mdboth specify only a maximum row count.The fixture makes that decisive. Three of the six
occupationrows matchcountry = 'Canada', and the left side has five matching rows:Both satisfy a cap of five, so the assertion inferred cap enforcement from the identity of an arbitrarily discarded row. A cap of five cannot bound this result at all, since five already exceeds the three matching rows.
What changed
testJoinSubsearchMaxOut<= 10, then exactly15uncappedtestJoinSubsearchMaxOutOnFilteredSubsearch(new)10, then exactly15uncappedWith a cap of two, at most two matching rows can survive, so the join cannot exceed
5 x 2whichever rows are kept. That bound is what the setting actually promises. Filtering the subsearch to the join key makes every retained row join identically, which recovers an exact count without depending on row identity.Scope notes:
15is unchanged in both tests.Validation
Both tests, both pushdown modes, one and five shards: 8 executions, all pass. Shard counts are confirmed from the cluster log rather than assumed, and each result file was attributed to its pushdown mode by inspecting the recorded setting rather than by fork order.
expected:<10> but was:<15>The five-shard failure reproduced locally before the change, and only with pushdown enabled. That the same code passes with pushdown disabled is further evidence that the retained subset varies with execution strategy and was never fixed.
The new bound is not vacuous. Mutating only
testJoinSubsearchMaxOut's cap to0makes it fail in both modes withcan join at most 5 x 2 = 10 rows, but got 15, while the companion test keeps passing. So an unenforced cap is still caught.spotlessJavaCheck,compileTestJavaandgit diff --checkpass.Related Issues
None. The engine behavior is correct and unchanged; only the test oracle assumed more than the setting guarantees.
Check List
--signoffor-s.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.