Skip to content

Commit 9dae337

Browse files
committed
[GLUTEN-12597][CORE] Migrate nested loop joins from CrossRel to NestedLoopJoinRel (Substrait 0.98)
Substrait 0.98 splits Gluten's overloaded CrossRel (which carried both `expression` and `type`) into a pure-cartesian CrossRel plus a new NestedLoopJoinRel (expression=4, type=5) with a paired JoinType enum. This increment of the proto rebase adopts that split across the vendored proto, the JVM producer, and both native consumers in lockstep. The NestedLoopJoinRel.JoinType enum reorders the anti/semi/single values relative to the old CrossRel.JoinType fork, but Gluten only ever emits and consumes INNER/OUTER/LEFT/LEFT_SEMI, whose proto numbers (1/2/3/5) are identical in both, so the split is semantically neutral for Gluten's code paths. The new rel is parked at a temporary Rel-oneof field number; the final oneof reconciliation increment relocates it to the official nested_loop_join = 18. Field numbers are codegen-transparent for Gluten's coupled build (single proto source, transient plans, producer + both consumers regenerate and ship together). Part of #12597. Generated-by: Claude Code (Claude Opus 4.8)
1 parent 9b15c7d commit 9dae337

19 files changed

Lines changed: 200 additions & 105 deletions

File tree

backends-clickhouse/src/main/java/org/apache/gluten/vectorized/StorageJoinBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public static long build(
8383
joinType =
8484
JoinTypeTransform.toSubstraitJoinType(broadcastContext.joinType(), buildRight).ordinal();
8585
} else {
86-
joinType = SubstraitUtil.toCrossRelSubstrait(broadcastContext.joinType()).ordinal();
86+
joinType = SubstraitUtil.toNestedLoopJoinSubstrait(broadcastContext.joinType()).ordinal();
8787
}
8888

8989
return nativeBuild(

backends-velox/src/main/scala/org/apache/gluten/metrics/MetricsUtil.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,8 @@ object MetricsUtil extends Logging {
382382
}
383383
smj.updateJoinMetrics(operatorMetrics, singleMetrics, joinParams)
384384
case ju: JoinMetricsUpdaterBase =>
385-
// JoinRel and CrossRel output two suites of metrics respectively for build and probe.
385+
// JoinRel and NestedLoopJoinRel output two suites of metrics respectively for build and
386+
// probe.
386387
// Therefore, fetch one more suite of metrics here.
387388
operatorMetrics.add(nativeMetrics.get(curMetricsIdx))
388389
curMetricsIdx -= 1

cpp-ch/local-engine/Common/CHUtil.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,15 +1118,15 @@ JoinUtil::getJoinKindAndStrictness(substrait::JoinRel_JoinType join_type, bool i
11181118
}
11191119
}
11201120

1121-
std::pair<DB::JoinKind, DB::JoinStrictness> JoinUtil::getCrossJoinKindAndStrictness(substrait::CrossRel_JoinType join_type)
1121+
std::pair<DB::JoinKind, DB::JoinStrictness> JoinUtil::getCrossJoinKindAndStrictness(substrait::NestedLoopJoinRel_JoinType join_type)
11221122
{
11231123
switch (join_type)
11241124
{
1125-
case substrait::CrossRel_JoinType_JOIN_TYPE_INNER:
1125+
case substrait::NestedLoopJoinRel_JoinType_JOIN_TYPE_INNER:
11261126
return {DB::JoinKind::Cross, DB::JoinStrictness::All};
1127-
case substrait::CrossRel_JoinType_JOIN_TYPE_LEFT:
1127+
case substrait::NestedLoopJoinRel_JoinType_JOIN_TYPE_LEFT:
11281128
return {DB::JoinKind::Left, DB::JoinStrictness::All};
1129-
case substrait::CrossRel_JoinType_JOIN_TYPE_OUTER:
1129+
case substrait::NestedLoopJoinRel_JoinType_JOIN_TYPE_OUTER:
11301130
return {DB::JoinKind::Full, DB::JoinStrictness::All};
11311131
default:
11321132
throw Exception(ErrorCodes::UNKNOWN_TYPE, "unsupported join type {}.", magic_enum::enum_name(join_type));

cpp-ch/local-engine/Common/CHUtil.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ class JoinUtil
258258
static void adjustJoinOutput(DB::QueryPlan & plan, DB::Names cols);
259259
static std::pair<DB::JoinKind, DB::JoinStrictness>
260260
getJoinKindAndStrictness(substrait::JoinRel_JoinType join_type, bool is_existence_join);
261-
static std::pair<DB::JoinKind, DB::JoinStrictness> getCrossJoinKindAndStrictness(substrait::CrossRel_JoinType join_type);
261+
static std::pair<DB::JoinKind, DB::JoinStrictness> getCrossJoinKindAndStrictness(substrait::NestedLoopJoinRel_JoinType join_type);
262262
};
263263

264264
}

cpp-ch/local-engine/Join/BroadcastJoinBuilder.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ std::shared_ptr<StorageJoinFromReadBuffer> buildJoin(
173173
if (is_bhj)
174174
std::tie(kind, strictness) = JoinUtil::getJoinKindAndStrictness(static_cast<substrait::JoinRel_JoinType>(join_type), is_existence_join);
175175
else
176-
std::tie(kind, strictness) = JoinUtil::getCrossJoinKindAndStrictness(static_cast<substrait::CrossRel_JoinType>(join_type));
176+
std::tie(kind, strictness) = JoinUtil::getCrossJoinKindAndStrictness(static_cast<substrait::NestedLoopJoinRel_JoinType>(join_type));
177177

178178
substrait::NamedStruct substrait_struct;
179179
substrait_struct.ParseFromString(named_struct);

cpp-ch/local-engine/Parser/RelParsers/CrossRelParser.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ namespace local_engine
5858
{
5959
using namespace DB;
6060

61-
std::shared_ptr<DB::TableJoin> createCrossTableJoin(substrait::CrossRel_JoinType join_type)
61+
std::shared_ptr<DB::TableJoin> createCrossTableJoin(substrait::NestedLoopJoinRel_JoinType join_type)
6262
{
6363
auto global_context = QueryContext::globalContext();
6464
auto table_join = std::make_shared<TableJoin>(
@@ -82,7 +82,7 @@ CrossRelParser::parse(DB::QueryPlanPtr /*query_plan*/, const substrait::Rel & /*
8282

8383
std::vector<const substrait::Rel *> CrossRelParser::getInputs(const substrait::Rel & rel)
8484
{
85-
const auto & join = rel.cross();
85+
const auto & join = rel.nested_loop_join();
8686
if (!join.has_left() || !join.has_right())
8787
{
8888
throw Exception(ErrorCodes::BAD_ARGUMENTS, "left table or right table is missing.");
@@ -124,7 +124,7 @@ DB::QueryPlanPtr
124124
CrossRelParser::parse(std::vector<DB::QueryPlanPtr> & input_plans_, const substrait::Rel & rel, std::list<const substrait::Rel *> &)
125125
{
126126
assert(input_plans_.size() == 2);
127-
const auto & join = rel.cross();
127+
const auto & join = rel.nested_loop_join();
128128
std::pair<DB::JoinKind, DB::JoinStrictness> kind_and_strictness = JoinUtil::getCrossJoinKindAndStrictness(join.type());
129129
if (kind_and_strictness.first != JoinKind::Cross)
130130
addConstJoinKeys(*input_plans_[0], *input_plans_[1]);
@@ -166,7 +166,7 @@ void CrossRelParser::renamePlanColumns(DB::QueryPlan & left, DB::QueryPlan & rig
166166
left.addStep(std::move(project_step));
167167
}
168168

169-
DB::QueryPlanPtr CrossRelParser::parseJoin(const substrait::CrossRel & join, DB::QueryPlanPtr left, DB::QueryPlanPtr right)
169+
DB::QueryPlanPtr CrossRelParser::parseJoin(const substrait::NestedLoopJoinRel & join, DB::QueryPlanPtr left, DB::QueryPlanPtr right)
170170
{
171171
google::protobuf::StringValue optimization_info;
172172
optimization_info.ParseFromString(firstOptimizationOrDefault(join.advanced_extension()).value());
@@ -247,7 +247,7 @@ DB::QueryPlanPtr CrossRelParser::parseJoin(const substrait::CrossRel & join, DB:
247247
}
248248

249249

250-
void CrossRelParser::addPostFilter(DB::QueryPlan & query_plan, const substrait::CrossRel & join_rel)
250+
void CrossRelParser::addPostFilter(DB::QueryPlan & query_plan, const substrait::NestedLoopJoinRel & join_rel)
251251
{
252252
if (!join_rel.has_expression())
253253
return;
@@ -366,7 +366,7 @@ DB::Names CrossRelParser::collectOutputColumnsName(const DB::QueryPlan & left, c
366366
void registerCrossRelParser(RelParserFactory & factory)
367367
{
368368
auto builder = [](ParserContextPtr parser_context) { return std::make_shared<CrossRelParser>(parser_context); };
369-
factory.registerBuilder(substrait::Rel::RelTypeCase::kCross, builder);
369+
factory.registerBuilder(substrait::Rel::RelTypeCase::kNestedLoopJoin, builder);
370370
}
371371

372372
}

cpp-ch/local-engine/Parser/RelParsers/CrossRelParser.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,13 @@ class CrossRelParser : public RelParser
5555
std::vector<DB::QueryPlanPtr> extra_plan_holder;
5656

5757

58-
DB::QueryPlanPtr parseJoin(const substrait::CrossRel & join, DB::QueryPlanPtr left, DB::QueryPlanPtr right);
58+
DB::QueryPlanPtr parseJoin(const substrait::NestedLoopJoinRel & join, DB::QueryPlanPtr left, DB::QueryPlanPtr right);
5959
void renamePlanColumns(DB::QueryPlan & left, DB::QueryPlan & right, const StorageJoinFromReadBuffer & storage_join);
6060
void addConvertStep(DB::TableJoin & table_join, DB::QueryPlan & left, DB::QueryPlan & right);
61-
void addPostFilter(DB::QueryPlan & query_plan, const substrait::CrossRel & join);
61+
void addPostFilter(DB::QueryPlan & query_plan, const substrait::NestedLoopJoinRel & join);
6262
bool applyJoinFilter(
6363
DB::TableJoin & table_join,
64-
const substrait::CrossRel & join_rel,
64+
const substrait::NestedLoopJoinRel & join_rel,
6565
DB::QueryPlan & left,
6666
DB::QueryPlan & right,
6767
bool allow_mixed_condition);

cpp/velox/substrait/SubstraitToVeloxPlan.cc

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -515,43 +515,44 @@ core::PlanNodePtr SubstraitToVeloxPlanConverter::toVeloxPlan(const ::substrait::
515515
}
516516
}
517517

518-
core::PlanNodePtr SubstraitToVeloxPlanConverter::toVeloxPlan(const ::substrait::CrossRel& crossRel) {
519-
// Support basic cross join without any filters
520-
if (!crossRel.has_left()) {
521-
VELOX_FAIL("Left Rel is expected in CrossRel.");
518+
core::PlanNodePtr SubstraitToVeloxPlanConverter::toVeloxPlan(
519+
const ::substrait::NestedLoopJoinRel& nestedLoopJoinRel) {
520+
// Support basic nested loop join without any filters
521+
if (!nestedLoopJoinRel.has_left()) {
522+
VELOX_FAIL("Left Rel is expected in NestedLoopJoinRel.");
522523
}
523-
if (!crossRel.has_right()) {
524-
VELOX_FAIL("Right Rel is expected in CrossRel.");
524+
if (!nestedLoopJoinRel.has_right()) {
525+
VELOX_FAIL("Right Rel is expected in NestedLoopJoinRel.");
525526
}
526527

527-
auto leftNode = toVeloxPlan(crossRel.left());
528-
auto rightNode = toVeloxPlan(crossRel.right());
528+
auto leftNode = toVeloxPlan(nestedLoopJoinRel.left());
529+
auto rightNode = toVeloxPlan(nestedLoopJoinRel.right());
529530

530531
// Map join type.
531532
core::JoinType joinType;
532-
switch (crossRel.type()) {
533-
case ::substrait::CrossRel_JoinType::CrossRel_JoinType_JOIN_TYPE_INNER:
533+
switch (nestedLoopJoinRel.type()) {
534+
case ::substrait::NestedLoopJoinRel_JoinType::NestedLoopJoinRel_JoinType_JOIN_TYPE_INNER:
534535
joinType = core::JoinType::kInner;
535536
break;
536-
case ::substrait::CrossRel_JoinType::CrossRel_JoinType_JOIN_TYPE_LEFT:
537+
case ::substrait::NestedLoopJoinRel_JoinType::NestedLoopJoinRel_JoinType_JOIN_TYPE_LEFT:
537538
joinType = core::JoinType::kLeft;
538539
break;
539-
case ::substrait::CrossRel_JoinType::CrossRel_JoinType_JOIN_TYPE_LEFT_SEMI:
540-
if (crossRel.has_advanced_extension() &&
541-
SubstraitParser::configSetInOptimization(crossRel.advanced_extension(), "isExistenceJoin=")) {
540+
case ::substrait::NestedLoopJoinRel_JoinType::NestedLoopJoinRel_JoinType_JOIN_TYPE_LEFT_SEMI:
541+
if (nestedLoopJoinRel.has_advanced_extension() &&
542+
SubstraitParser::configSetInOptimization(nestedLoopJoinRel.advanced_extension(), "isExistenceJoin=")) {
542543
joinType = core::JoinType::kLeftSemiProject;
543544
} else {
544-
VELOX_NYI("Unsupported Join type: {}", std::to_string(crossRel.type()));
545+
VELOX_NYI("Unsupported Join type: {}", std::to_string(nestedLoopJoinRel.type()));
545546
}
546547
break;
547548
default:
548-
VELOX_NYI("Unsupported Join type: {}", std::to_string(crossRel.type()));
549+
VELOX_NYI("Unsupported Join type: {}", std::to_string(nestedLoopJoinRel.type()));
549550
}
550551

551552
auto inputRowType = getJoinInputType(leftNode, rightNode);
552553
core::TypedExprPtr joinConditions;
553-
if (crossRel.has_expression()) {
554-
joinConditions = exprConverter_->toVeloxExpr(crossRel.expression(), inputRowType);
554+
if (nestedLoopJoinRel.has_expression()) {
555+
joinConditions = exprConverter_->toVeloxExpr(nestedLoopJoinRel.expression(), inputRowType);
555556
}
556557

557558
return std::make_shared<core::NestedLoopJoinNode>(
@@ -1691,8 +1692,8 @@ core::PlanNodePtr SubstraitToVeloxPlanConverter::toVeloxPlan(const ::substrait::
16911692
return toVeloxPlan(rel.filter());
16921693
} else if (rel.has_join()) {
16931694
return toVeloxPlan(rel.join());
1694-
} else if (rel.has_cross()) {
1695-
return toVeloxPlan(rel.cross());
1695+
} else if (rel.has_nested_loop_join()) {
1696+
return toVeloxPlan(rel.nested_loop_join());
16961697
} else if (rel.has_read()) {
16971698
return toVeloxPlan(rel.read());
16981699
} else if (rel.has_sort()) {

cpp/velox/substrait/SubstraitToVeloxPlan.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ class SubstraitToVeloxPlanConverter {
116116
/// Used to convert Substrait JoinRel into Velox PlanNode.
117117
core::PlanNodePtr toVeloxPlan(const ::substrait::JoinRel& joinRel);
118118

119-
/// Used to convert Substrait CrossRel into Velox PlanNode.
120-
core::PlanNodePtr toVeloxPlan(const ::substrait::CrossRel& crossRel);
119+
/// Used to convert Substrait NestedLoopJoinRel into Velox PlanNode.
120+
core::PlanNodePtr toVeloxPlan(const ::substrait::NestedLoopJoinRel& nestedLoopJoinRel);
121121

122122
/// Used to convert Substrait AggregateRel into Velox PlanNode.
123123
core::PlanNodePtr toVeloxPlan(const ::substrait::AggregateRel& aggRel);

cpp/velox/substrait/SubstraitToVeloxPlanValidator.cc

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,38 +1097,38 @@ bool SubstraitToVeloxPlanValidator::validate(const ::substrait::JoinRel& joinRel
10971097
return true;
10981098
}
10991099

1100-
bool SubstraitToVeloxPlanValidator::validate(const ::substrait::CrossRel& crossRel) {
1101-
if (crossRel.has_left() && !validate(crossRel.left())) {
1102-
logValidateMsg("Native validation failed due to: validation fails for cross join left input. ");
1100+
bool SubstraitToVeloxPlanValidator::validate(const ::substrait::NestedLoopJoinRel& nestedLoopJoinRel) {
1101+
if (nestedLoopJoinRel.has_left() && !validate(nestedLoopJoinRel.left())) {
1102+
logValidateMsg("Native validation failed due to: validation fails for nested loop join left input. ");
11031103
return false;
11041104
}
11051105

1106-
if (crossRel.has_right() && !validate(crossRel.right())) {
1107-
logValidateMsg("Native validation failed due to: validation fails for cross join right input. ");
1106+
if (nestedLoopJoinRel.has_right() && !validate(nestedLoopJoinRel.right())) {
1107+
logValidateMsg("Native validation failed due to: validation fails for nested loop join right input. ");
11081108
return false;
11091109
}
11101110

11111111
// Validate input types.
1112-
if (!crossRel.has_advanced_extension()) {
1113-
logValidateMsg("Native validation failed due to: Input types are expected in CrossRel.");
1112+
if (!nestedLoopJoinRel.has_advanced_extension()) {
1113+
logValidateMsg("Native validation failed due to: Input types are expected in NestedLoopJoinRel.");
11141114
return false;
11151115
}
11161116

1117-
switch (crossRel.type()) {
1118-
case ::substrait::CrossRel_JoinType_JOIN_TYPE_INNER:
1119-
case ::substrait::CrossRel_JoinType_JOIN_TYPE_LEFT:
1120-
case ::substrait::CrossRel_JoinType_JOIN_TYPE_LEFT_SEMI:
1117+
switch (nestedLoopJoinRel.type()) {
1118+
case ::substrait::NestedLoopJoinRel_JoinType_JOIN_TYPE_INNER:
1119+
case ::substrait::NestedLoopJoinRel_JoinType_JOIN_TYPE_LEFT:
1120+
case ::substrait::NestedLoopJoinRel_JoinType_JOIN_TYPE_LEFT_SEMI:
11211121
break;
11221122
default:
1123-
LOG_VALIDATION_MSG("Unsupported Join type in CrossRel");
1123+
LOG_VALIDATION_MSG("Unsupported Join type in NestedLoopJoinRel");
11241124
return false;
11251125
}
11261126

1127-
const auto& extension = crossRel.advanced_extension();
1127+
const auto& extension = nestedLoopJoinRel.advanced_extension();
11281128
TypePtr inputRowType;
11291129
std::vector<TypePtr> types;
11301130
if (!parseVeloxType(extension, inputRowType) || !flattenSingleLevel(inputRowType, types)) {
1131-
logValidateMsg("Native validation failed due to: Validation failed for input types in CrossRel");
1131+
logValidateMsg("Native validation failed due to: Validation failed for input types in NestedLoopJoinRel");
11321132
return false;
11331133
}
11341134

@@ -1140,11 +1140,11 @@ bool SubstraitToVeloxPlanValidator::validate(const ::substrait::CrossRel& crossR
11401140
}
11411141
auto rowType = std::make_shared<RowType>(std::move(names), std::move(types));
11421142

1143-
if (crossRel.has_expression()) {
1144-
if (!validateExpression(crossRel.expression(), rowType)) {
1143+
if (nestedLoopJoinRel.has_expression()) {
1144+
if (!validateExpression(nestedLoopJoinRel.expression(), rowType)) {
11451145
return false;
11461146
}
1147-
auto expression = exprConverter_->toVeloxExpr(crossRel.expression(), rowType);
1147+
auto expression = exprConverter_->toVeloxExpr(nestedLoopJoinRel.expression(), rowType);
11481148
exec::ExprSet exprSet({std::move(expression)}, execCtx_.get());
11491149
}
11501150

@@ -1424,8 +1424,8 @@ bool SubstraitToVeloxPlanValidator::validate(const ::substrait::Rel& rel) {
14241424
if (rel.has_join()) {
14251425
return validate(rel.join());
14261426
}
1427-
if (rel.has_cross()) {
1428-
return validate(rel.cross());
1427+
if (rel.has_nested_loop_join()) {
1428+
return validate(rel.nested_loop_join());
14291429
}
14301430
if (rel.has_read()) {
14311431
return validate(rel.read());

0 commit comments

Comments
 (0)