This is an automated email from the ASF dual-hosted git repository.

BiteTheDDDDt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 85767429400 [Chore](be) Reject right anti hash mark join plans (#63482)
85767429400 is described below

commit 8576742940065ccc8e979159bccb2be822efbde4
Author: Pxl <[email protected]>
AuthorDate: Fri May 22 15:20:13 2026 +0800

    [Chore](be) Reject right anti hash mark join plans (#63482)
    
    Problem Summary: Hash mark join currently supports left semi/anti,
    null-aware left semi/anti, and right semi plans. Current FE rules do not
    generate right anti mark hash join from SQL, but a malformed or future
    plan could still reach BE hash join operators. The right anti mark path
    is not a supported hash mark join shape, so reject it during hash join
    build/probe operator initialization instead of allowing the unsupported
    plan to proceed.
---
 be/src/exec/operator/hashjoin_build_sink.cpp       |  5 +++++
 be/src/exec/operator/join_build_sink_operator.cpp  |  6 +++---
 be/test/exec/operator/hashjoin_build_sink_test.cpp | 21 +++++++++++++++++++++
 3 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/be/src/exec/operator/hashjoin_build_sink.cpp 
b/be/src/exec/operator/hashjoin_build_sink.cpp
index 1d5d4e84261..4c5815c71ab 100644
--- a/be/src/exec/operator/hashjoin_build_sink.cpp
+++ b/be/src/exec/operator/hashjoin_build_sink.cpp
@@ -700,6 +700,11 @@ 
HashJoinBuildSinkOperatorX::HashJoinBuildSinkOperatorX(ObjectPool* pool, int ope
 Status HashJoinBuildSinkOperatorX::init(const TPlanNode& tnode, RuntimeState* 
state) {
     RETURN_IF_ERROR(JoinBuildSinkOperatorX::init(tnode, state));
     DCHECK(tnode.__isset.hash_join_node);
+    if (_is_mark_join && _join_op == TJoinOp::RIGHT_ANTI_JOIN) {
+        return Status::InternalError(
+                "Hash join does not support right anti mark join, query={}, 
node={}, join_op={}",
+                print_id(state->query_id()), node_id(), to_string(_join_op));
+    }
 
     if (tnode.hash_join_node.__isset.hash_output_slot_ids) {
         _hash_output_slot_ids = tnode.hash_join_node.hash_output_slot_ids;
diff --git a/be/src/exec/operator/join_build_sink_operator.cpp 
b/be/src/exec/operator/join_build_sink_operator.cpp
index 01b61ae1e81..719b33fab2e 100644
--- a/be/src/exec/operator/join_build_sink_operator.cpp
+++ b/be/src/exec/operator/join_build_sink_operator.cpp
@@ -77,9 +77,9 @@ 
JoinBuildSinkOperatorX<LocalStateType>::JoinBuildSinkOperatorX(ObjectPool* pool,
         DCHECK(_join_op == TJoinOp::LEFT_ANTI_JOIN || _join_op == 
TJoinOp::LEFT_SEMI_JOIN ||
                _join_op == TJoinOp::CROSS_JOIN || _join_op == 
TJoinOp::NULL_AWARE_LEFT_ANTI_JOIN ||
                _join_op == TJoinOp::NULL_AWARE_LEFT_SEMI_JOIN ||
-               _join_op == TJoinOp::RIGHT_SEMI_JOIN)
-                << "Mark join is only supported for null aware left semi/anti 
join and right semi "
-                   "join and cross join "
+               _join_op == TJoinOp::RIGHT_SEMI_JOIN || _join_op == 
TJoinOp::RIGHT_ANTI_JOIN)
+                << "Mark join is only supported for null aware left semi/anti 
join, right "
+                   "semi/anti join and cross join "
                    "but this is "
                 << _join_op;
     }
diff --git a/be/test/exec/operator/hashjoin_build_sink_test.cpp 
b/be/test/exec/operator/hashjoin_build_sink_test.cpp
index 20b66132949..26dcbcc65e4 100644
--- a/be/test/exec/operator/hashjoin_build_sink_test.cpp
+++ b/be/test/exec/operator/hashjoin_build_sink_test.cpp
@@ -208,6 +208,27 @@ TEST_F(HashJoinBuildSinkTest, 
RejectBroadcastJoinThatRequiresBuildSideFinalize)
     }
 }
 
+TEST_F(HashJoinBuildSinkTest, RightAntiMarkJoinRejected) {
+    auto tnode = _helper.create_test_plan_node(TJoinOp::RIGHT_ANTI_JOIN,
+                                               {TPrimitiveType::INT, 
TPrimitiveType::STRING},
+                                               {false, false}, {false, false}, 
true, 1);
+    auto [probe_operator, sink_operator] = _helper.create_operators(tnode);
+    ASSERT_TRUE(probe_operator);
+    ASSERT_TRUE(sink_operator);
+
+    auto runtime_state = std::make_unique<MockRuntimeState>();
+    runtime_state->_query_ctx = _helper.query_ctx.get();
+    runtime_state->_query_id = _helper.query_ctx->query_id();
+    runtime_state->resize_op_id_to_local_state(-100);
+    runtime_state->set_max_operator_id(-100);
+    runtime_state->set_desc_tbl(_helper.desc_tbl);
+
+    auto st = sink_operator->init(tnode, runtime_state.get());
+    ASSERT_FALSE(st.ok());
+    EXPECT_THAT(st.to_string(), testing::HasSubstr("right anti mark join"));
+    EXPECT_THAT(st.to_string(), testing::HasSubstr("node=0"));
+}
+
 TEST_F(HashJoinBuildSinkTest, Sink) {
     auto test_block = [&](TJoinOp::type op_type, const 
std::vector<TPrimitiveType::type>& key_types,
                           const std::vector<bool>& left_nullables,


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

Reply via email to