From 27ab6bd85eebe636d1f96e10c7ca1cc7f2fcff0e Mon Sep 17 00:00:00 2001 From: shuke <37901441+shuke987@users.noreply.github.com> Date: Mon, 13 Jul 2026 17:58:30 +0800 Subject: [PATCH] [fix](fe) Revert semi join constraint matching fix ### What problem does this PR solve? Issue Number: N/A Related PR: #65205 Problem Summary: PR #65205 introduced a correctness issue in leading hint planning. Revert its semi/anti join constraint matching change and the unit tests added with it to restore the previous planner behavior while a correct fix is prepared. ### Release note None ### Check List (For Author) - Test: No need to test - Exact revert verified against the parent of #65205; targeted FE UT was stopped to publish the revert immediately. - Behavior changed: Yes. Restore the leading hint behavior before #65205. - Does this need documentation: No --- .../doris/nereids/hint/LeadingHint.java | 17 +- .../doris/nereids/hint/LeadingHintTest.java | 219 ------------------ 2 files changed, 5 insertions(+), 231 deletions(-) delete mode 100644 fe/fe-core/src/test/java/org/apache/doris/nereids/hint/LeadingHintTest.java diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/hint/LeadingHint.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/hint/LeadingHint.java index 45df90d3d1d091..7f67311204d349 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/hint/LeadingHint.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/hint/LeadingHint.java @@ -416,20 +416,13 @@ public Pair getJoinConstraint(Long joinTableBitmap, Lon continue; } - if (joinConstraint.getJoinType().isSemiOrAntiJoin()) { - if (!LongBitmap.isSubset(joinConstraint.getMinLeftHand(), joinTableBitmap) - || !LongBitmap.isSubset(joinConstraint.getMinRightHand(), joinTableBitmap)) { + if (joinConstraint.getJoinType().isSemiJoin()) { + if (LongBitmap.isSubset(joinConstraint.getRightHand(), leftTableBitmap) + && !LongBitmap.isSubset(joinConstraint.getRightHand(), leftTableBitmap)) { continue; } - - Long constrainedSide = joinConstraint.getJoinType().isRightSemiOrAntiJoin() - ? joinConstraint.getLeftHand() : joinConstraint.getRightHand(); - if (LongBitmap.isOverlap(constrainedSide, leftTableBitmap) - && !constrainedSide.equals(leftTableBitmap)) { - continue; - } - if (LongBitmap.isOverlap(constrainedSide, rightTableBitmap) - && !constrainedSide.equals(rightTableBitmap)) { + if (LongBitmap.isSubset(joinConstraint.getRightHand(), rightTableBitmap) + && !joinConstraint.getRightHand().equals(rightTableBitmap)) { continue; } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/hint/LeadingHintTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/hint/LeadingHintTest.java deleted file mode 100644 index 00f0c45437f091..00000000000000 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/hint/LeadingHintTest.java +++ /dev/null @@ -1,219 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package org.apache.doris.nereids.hint; - -import org.apache.doris.common.Pair; -import org.apache.doris.nereids.jobs.joinorder.hypergraph.bitmap.LongBitmap; -import org.apache.doris.nereids.trees.plans.JoinType; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class LeadingHintTest { - - @Test - public void testLeftSemiJoinConstrainedSideMatchesExactly() { - LeadingHint leading = new LeadingHint("Leading"); - long leftHand = LongBitmap.newBitmap(0); - long rightHand = LongBitmap.newBitmap(1); - long extraTable = LongBitmap.newBitmap(2); - JoinConstraint semiJoinConstraint = addJoinConstraint(leading, leftHand, rightHand, - JoinType.LEFT_SEMI_JOIN); - - Pair exactReversed = leading.getJoinConstraint( - LongBitmap.newBitmapUnion(leftHand, rightHand), rightHand, leftHand); - assertMatchedJoinConstraint(semiJoinConstraint, exactReversed, true); - - Pair withoutRetainedSide = leading.getJoinConstraint( - LongBitmap.newBitmapUnion(rightHand, extraTable), rightHand, extraTable); - assertNoMatchedJoinConstraint(withoutRetainedSide); - - Pair withExtraTable = leading.getJoinConstraint( - LongBitmap.newBitmapUnion(leftHand, rightHand, extraTable), - LongBitmap.newBitmapUnion(rightHand, extraTable), - leftHand); - assertNoMatchedJoinConstraint(withExtraTable); - } - - @Test - public void testLeftAntiJoinConstrainedSideMatchesExactly() { - LeadingHint leading = new LeadingHint("Leading"); - long leftHand = LongBitmap.newBitmap(0); - long rightHand = LongBitmap.newBitmap(1); - long extraTable = LongBitmap.newBitmap(2); - JoinConstraint antiJoinConstraint = addJoinConstraint(leading, leftHand, rightHand, - JoinType.LEFT_ANTI_JOIN); - - Pair exactReversed = leading.getJoinConstraint( - LongBitmap.newBitmapUnion(leftHand, rightHand), rightHand, leftHand); - assertMatchedJoinConstraint(antiJoinConstraint, exactReversed, true); - - Pair withExtraTable = leading.getJoinConstraint( - LongBitmap.newBitmapUnion(leftHand, rightHand, extraTable), - LongBitmap.newBitmapUnion(rightHand, extraTable), - leftHand); - assertNoMatchedJoinConstraint(withExtraTable); - } - - @Test - public void testRightSemiJoinConstrainedSideMatchesExactly() { - LeadingHint leading = new LeadingHint("Leading"); - long leftHand = LongBitmap.newBitmap(0); - long rightHand = LongBitmap.newBitmap(1); - long extraTable = LongBitmap.newBitmap(2); - JoinConstraint semiJoinConstraint = addJoinConstraint(leading, leftHand, rightHand, - JoinType.RIGHT_SEMI_JOIN); - - Pair exact = leading.getJoinConstraint( - LongBitmap.newBitmapUnion(leftHand, rightHand), leftHand, rightHand); - assertMatchedJoinConstraint(semiJoinConstraint, exact, false); - - Pair withoutConstrainedSide = leading.getJoinConstraint( - LongBitmap.newBitmapUnion(rightHand, extraTable), rightHand, extraTable); - assertNoMatchedJoinConstraint(withoutConstrainedSide); - - Pair withExtraTable = leading.getJoinConstraint( - LongBitmap.newBitmapUnion(leftHand, rightHand, extraTable), - LongBitmap.newBitmapUnion(leftHand, extraTable), - rightHand); - assertNoMatchedJoinConstraint(withExtraTable); - } - - @Test - public void testRightAntiJoinConstrainedSideMatchesExactly() { - LeadingHint leading = new LeadingHint("Leading"); - long leftHand = LongBitmap.newBitmap(0); - long rightHand = LongBitmap.newBitmap(1); - long extraTable = LongBitmap.newBitmap(2); - JoinConstraint antiJoinConstraint = addJoinConstraint(leading, leftHand, rightHand, - JoinType.RIGHT_ANTI_JOIN); - - Pair exact = leading.getJoinConstraint( - LongBitmap.newBitmapUnion(leftHand, rightHand), leftHand, rightHand); - assertMatchedJoinConstraint(antiJoinConstraint, exact, false); - - Pair withExtraTable = leading.getJoinConstraint( - LongBitmap.newBitmapUnion(leftHand, rightHand, extraTable), - LongBitmap.newBitmapUnion(leftHand, extraTable), - rightHand); - assertNoMatchedJoinConstraint(withExtraTable); - } - - @Test - public void testCompositeLeftSemiAndAntiJoinConstrainedSideCanNotBeSplit() { - assertCompositeConstrainedSideCanNotBeSplit(JoinType.LEFT_SEMI_JOIN); - assertCompositeConstrainedSideCanNotBeSplit(JoinType.LEFT_ANTI_JOIN); - } - - @Test - public void testCompositeRightSemiAndAntiJoinConstrainedSideCanNotBeSplit() { - assertCompositeConstrainedSideCanNotBeSplit(JoinType.RIGHT_SEMI_JOIN); - assertCompositeConstrainedSideCanNotBeSplit(JoinType.RIGHT_ANTI_JOIN); - } - - @Test - public void testCompositeLeftSemiAndAntiJoinRetainedSideCanUseMinHand() { - assertCompositeRetainedSideCanUseMinHand(JoinType.LEFT_SEMI_JOIN); - assertCompositeRetainedSideCanUseMinHand(JoinType.LEFT_ANTI_JOIN); - } - - @Test - public void testCompositeRightSemiAndAntiJoinRetainedSideCanUseMinHand() { - assertCompositeRetainedSideCanUseMinHand(JoinType.RIGHT_SEMI_JOIN); - assertCompositeRetainedSideCanUseMinHand(JoinType.RIGHT_ANTI_JOIN); - } - - private JoinConstraint addJoinConstraint(LeadingHint leading, long leftHand, long rightHand, - JoinType joinType) { - JoinConstraint joinConstraint = new JoinConstraint(leftHand, rightHand, leftHand, rightHand, joinType, true); - leading.getJoinConstraintList().add(joinConstraint); - return joinConstraint; - } - - private JoinConstraint addJoinConstraint(LeadingHint leading, long minLeftHand, long minRightHand, - long leftHand, long rightHand, JoinType joinType) { - JoinConstraint joinConstraint = new JoinConstraint(minLeftHand, minRightHand, leftHand, rightHand, - joinType, true); - leading.getJoinConstraintList().add(joinConstraint); - return joinConstraint; - } - - private void assertCompositeConstrainedSideCanNotBeSplit(JoinType joinType) { - LeadingHint leading = new LeadingHint("Leading"); - long leftHand = LongBitmap.newBitmap(0); - long rightHand = LongBitmap.newBitmap(1); - long extraTable = LongBitmap.newBitmap(2); - long joinTable = LongBitmap.newBitmapUnion(leftHand, rightHand, extraTable); - - if (joinType.isRightSemiOrAntiJoin()) { - JoinConstraint joinConstraint = addJoinConstraint(leading, leftHand, rightHand, - LongBitmap.newBitmapUnion(leftHand, extraTable), rightHand, joinType); - - Pair exact = leading.getJoinConstraint( - joinTable, LongBitmap.newBitmapUnion(leftHand, extraTable), rightHand); - assertMatchedJoinConstraint(joinConstraint, exact, false); - - Pair splitConstrainedSide = leading.getJoinConstraint( - joinTable, leftHand, LongBitmap.newBitmapUnion(rightHand, extraTable)); - assertNoMatchedJoinConstraint(splitConstrainedSide); - } else { - JoinConstraint joinConstraint = addJoinConstraint(leading, leftHand, rightHand, - leftHand, LongBitmap.newBitmapUnion(rightHand, extraTable), joinType); - - Pair exact = leading.getJoinConstraint( - joinTable, leftHand, LongBitmap.newBitmapUnion(rightHand, extraTable)); - assertMatchedJoinConstraint(joinConstraint, exact, false); - - Pair splitConstrainedSide = leading.getJoinConstraint( - joinTable, LongBitmap.newBitmapUnion(leftHand, extraTable), rightHand); - assertNoMatchedJoinConstraint(splitConstrainedSide); - } - } - - private void assertCompositeRetainedSideCanUseMinHand(JoinType joinType) { - LeadingHint leading = new LeadingHint("Leading"); - long leftHand = LongBitmap.newBitmap(0); - long rightHand = LongBitmap.newBitmap(1); - long extraTable = LongBitmap.newBitmap(2); - - JoinConstraint joinConstraint; - if (joinType.isRightSemiOrAntiJoin()) { - joinConstraint = addJoinConstraint(leading, leftHand, rightHand, - leftHand, LongBitmap.newBitmapUnion(rightHand, extraTable), joinType); - } else { - joinConstraint = addJoinConstraint(leading, leftHand, rightHand, - LongBitmap.newBitmapUnion(leftHand, extraTable), rightHand, joinType); - } - - Pair minRetainedSide = leading.getJoinConstraint( - LongBitmap.newBitmapUnion(leftHand, rightHand), leftHand, rightHand); - assertMatchedJoinConstraint(joinConstraint, minRetainedSide, false); - } - - private void assertMatchedJoinConstraint(JoinConstraint expected, Pair actual, - boolean reversed) { - Assertions.assertSame(expected, actual.first); - Assertions.assertTrue(actual.second); - Assertions.assertEquals(reversed, actual.first.isReversed()); - } - - private void assertNoMatchedJoinConstraint(Pair actual) { - Assertions.assertNull(actual.first); - Assertions.assertTrue(actual.second); - } -}