[feature](Nereids) support cross join in Nereids (#11502)

support cross join in Nereids

1. add PhysicalNestedLoopJoin
2. Translate PhysicalNestedLoopJoin to CrossJoinNode in PhysicalPlanTranslator
This commit is contained in:
morrySnow
2022-08-08 22:14:27 +08:00
committed by GitHub
parent 1701ffa7c0
commit 7c950c7cd5
40 changed files with 510 additions and 84 deletions

View File

@ -24,6 +24,7 @@ under the License.
<import-control pkg="org.apache.doris" strategyOnMismatch="allowed">
<disallow pkg="com.clearspring.analytics.util" />
<disallow pkg="com.alibaba.google" />
<subpackage name="nereids">
<allow pkg="org.junit.jupiter"/>
<disallow pkg="org.junit"/>

View File

@ -25,6 +25,7 @@ import org.apache.doris.nereids.trees.plans.physical.PhysicalAggregate;
import org.apache.doris.nereids.trees.plans.physical.PhysicalDistribution;
import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
import org.apache.doris.nereids.trees.plans.physical.PhysicalHeapSort;
import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin;
import org.apache.doris.nereids.trees.plans.physical.PhysicalOlapScan;
import org.apache.doris.nereids.trees.plans.physical.PhysicalProject;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
@ -133,5 +134,32 @@ public class CostCalculator {
0);
}
@Override
public CostEstimate visitPhysicalNestedLoopJoin(PhysicalNestedLoopJoin<Plan, Plan> nestedLoopJoin,
PlanContext context) {
// TODO: copy from physicalHashJoin, should update according to physical nested loop join properties.
Preconditions.checkState(context.getGroupExpression().arity() == 2);
Preconditions.checkState(context.getChildrenStats().size() == 2);
StatsDeriveResult leftStatistics = context.getChildStatistics(0);
StatsDeriveResult rightStatistics = context.getChildStatistics(1);
List<Id> leftIds = context.getChildOutputIds(0);
List<Id> rightIds = context.getChildOutputIds(1);
// TODO: handle some case
// handle cross join, onClause is empty .....
if (nestedLoopJoin.getJoinType().isCrossJoin()) {
return new CostEstimate(
leftStatistics.computeColumnSize(leftIds) + rightStatistics.computeColumnSize(rightIds),
rightStatistics.computeColumnSize(rightIds),
0);
}
// TODO: network 0?
return new CostEstimate(
(leftStatistics.computeColumnSize(leftIds) + rightStatistics.computeColumnSize(rightIds)) / 2,
rightStatistics.computeColumnSize(rightIds),
0);
}
}
}

View File

@ -47,14 +47,17 @@ import org.apache.doris.nereids.trees.plans.physical.PhysicalFilter;
import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
import org.apache.doris.nereids.trees.plans.physical.PhysicalHeapSort;
import org.apache.doris.nereids.trees.plans.physical.PhysicalLimit;
import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin;
import org.apache.doris.nereids.trees.plans.physical.PhysicalOlapScan;
import org.apache.doris.nereids.trees.plans.physical.PhysicalPlan;
import org.apache.doris.nereids.trees.plans.physical.PhysicalProject;
import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanVisitor;
import org.apache.doris.nereids.util.ExpressionUtils;
import org.apache.doris.nereids.util.JoinUtils;
import org.apache.doris.nereids.util.SlotExtractor;
import org.apache.doris.nereids.util.Utils;
import org.apache.doris.planner.AggregationNode;
import org.apache.doris.planner.CrossJoinNode;
import org.apache.doris.planner.DataPartition;
import org.apache.doris.planner.ExchangeNode;
import org.apache.doris.planner.HashJoinNode;
@ -338,8 +341,7 @@ public class PhysicalPlanTranslator extends DefaultPlanVisitor<PlanFragment, Pla
PlanNode rightFragmentPlanRoot = rightFragment.getPlanRoot();
JoinType joinType = hashJoin.getJoinType();
if (joinType.equals(JoinType.CROSS_JOIN)
|| (joinType.equals(JoinType.INNER_JOIN) && !hashJoin.getCondition().isPresent())) {
if (JoinUtils.shouldNestedLoopJoin(hashJoin)) {
throw new RuntimeException("Physical hash join could not execute without equal join condition.");
} else {
Expression eqJoinExpression = hashJoin.getCondition().get();
@ -368,6 +370,30 @@ public class PhysicalPlanTranslator extends DefaultPlanVisitor<PlanFragment, Pla
}
}
@Override
public PlanFragment visitPhysicalNestedLoopJoin(PhysicalNestedLoopJoin<Plan, Plan> nestedLoopJoin,
PlanTranslatorContext context) {
// NOTICE: We must visit from right to left, to ensure the last fragment is root fragment
// TODO: we should add a helper method to wrap this logic.
// Maybe something like private List<PlanFragment> postOrderVisitChildren(
// PhysicalPlan plan, PlanVisitor visitor, Context context).
PlanFragment rightFragment = nestedLoopJoin.child(1).accept(this, context);
PlanFragment leftFragment = nestedLoopJoin.child(0).accept(this, context);
PlanNode leftFragmentPlanRoot = leftFragment.getPlanRoot();
PlanNode rightFragmentPlanRoot = rightFragment.getPlanRoot();
if (JoinUtils.shouldNestedLoopJoin(nestedLoopJoin)) {
CrossJoinNode crossJoinNode =
new CrossJoinNode(context.nextPlanNodeId(), leftFragmentPlanRoot, rightFragmentPlanRoot, null);
rightFragment.getPlanRoot().setCompactData(false);
crossJoinNode.setChild(0, leftFragment.getPlanRoot());
connectChildFragment(crossJoinNode, 1, leftFragment, rightFragment, context);
leftFragment.setPlanRoot(crossJoinNode);
return leftFragment;
} else {
throw new RuntimeException("Physical nested loop join could not execute with equal join condition.");
}
}
// TODO: generate expression mapping when be project could do in ExecNode
@Override
public PlanFragment visitPhysicalProject(PhysicalProject<Plan> project, PlanTranslatorContext context) {

View File

@ -48,6 +48,10 @@ public class PatternDescriptor<INPUT_TYPE extends Plan> {
return new PatternDescriptor<>(pattern.withPredicates(predicates), defaultPromise);
}
public PatternDescriptor<INPUT_TYPE> whenNot(Predicate<INPUT_TYPE> predicate) {
return when(predicate.negate());
}
public <OUTPUT_TYPE extends Plan> PatternMatcher<INPUT_TYPE, OUTPUT_TYPE> then(
Function<INPUT_TYPE, OUTPUT_TYPE> matchedAction) {
return new PatternMatcher<>(pattern, defaultPromise, ctx -> matchedAction.apply(ctx.root));

View File

@ -21,6 +21,7 @@ import org.apache.doris.nereids.PlanContext;
import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin;
import org.apache.doris.nereids.trees.plans.physical.PhysicalOlapScan;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
@ -99,6 +100,40 @@ public class ChildOutputPropertyDeriver extends PlanVisitor<PhysicalProperties,
return leftOutputProperty;
}
@Override
public PhysicalProperties visitPhysicalNestedLoopJoin(PhysicalNestedLoopJoin<Plan, Plan> nestedLoopJoin,
PlanContext context) {
// TODO: copy from hash join, should update according to nested loop join properties.
Preconditions.checkState(childrenOutputProperties.size() == 2);
PhysicalProperties leftOutputProperty = childrenOutputProperties.get(0);
PhysicalProperties rightOutputProperty = childrenOutputProperties.get(1);
// broadcast
if (rightOutputProperty.getDistributionSpec() instanceof DistributionSpecReplicated) {
// TODO
return leftOutputProperty;
}
// shuffle
// List<SlotReference> leftSlotRefs = hashJoin.left().getOutput().stream().map(slot -> (SlotReference) slot)
// .collect(Collectors.toList());
// List<SlotReference> rightSlotRefs = hashJoin.right().getOutput().stream().map(slot -> (SlotReference) slot)
// .collect(Collectors.toList());
// List<SlotReference> leftOnSlotRefs;
// List<SlotReference> rightOnSlotRefs;
// Preconditions.checkState(leftOnSlotRefs.size() == rightOnSlotRefs.size());
DistributionSpec leftDistribution = leftOutputProperty.getDistributionSpec();
DistributionSpec rightDistribution = rightOutputProperty.getDistributionSpec();
if (!(leftDistribution instanceof DistributionSpecHash)
|| !(rightDistribution instanceof DistributionSpecHash)) {
Preconditions.checkState(false, "error");
return new PhysicalProperties();
}
return leftOutputProperty;
}
@Override
public PhysicalProperties visitPhysicalOlapScan(PhysicalOlapScan olapScan, PlanContext context) {
return olapScan.getPhysicalProperties();

View File

@ -25,6 +25,7 @@ import org.apache.doris.nereids.properties.DistributionSpecHash.ShuffleType;
import org.apache.doris.nereids.trees.expressions.SlotReference;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
import org.apache.doris.nereids.util.JoinUtils;
import org.apache.doris.nereids.util.Utils;
@ -92,6 +93,31 @@ public class RequestPropertyDeriver extends PlanVisitor<Void, PlanContext> {
return null;
}
@Override
public Void visitPhysicalNestedLoopJoin(PhysicalNestedLoopJoin<Plan, Plan> nestedLoopJoin, PlanContext context) {
// TODO: copy from physicalHashJoin, should update according to physical nested loop join properties.
// for broadcast join
List<PhysicalProperties> propertiesForBroadcast = Lists.newArrayList(
new PhysicalProperties(),
new PhysicalProperties(new DistributionSpecReplicated())
);
// for shuffle join
Pair<List<SlotReference>, List<SlotReference>> onClauseUsedSlots
= JoinUtils.getOnClauseUsedSlots(nestedLoopJoin);
List<PhysicalProperties> propertiesForShuffle = Lists.newArrayList(
new PhysicalProperties(new DistributionSpecHash(onClauseUsedSlots.first, ShuffleType.JOIN)),
new PhysicalProperties(new DistributionSpecHash(onClauseUsedSlots.second, ShuffleType.JOIN)));
if (!JoinUtils.onlyBroadcast(nestedLoopJoin)) {
requestPropertyToChildren.add(propertiesForShuffle);
}
if (!JoinUtils.onlyShuffle(nestedLoopJoin)) {
requestPropertyToChildren.add(propertiesForBroadcast);
}
return null;
}
protected static List<PhysicalProperties> computeShuffleJoinRequiredProperties(
PhysicalProperties requestedProperty, List<SlotReference> leftShuffleColumns,
List<SlotReference> rightShuffleColumns) {

View File

@ -21,6 +21,7 @@ import org.apache.doris.nereids.rules.exploration.join.JoinCommute;
import org.apache.doris.nereids.rules.implementation.LogicalAggToPhysicalHashAgg;
import org.apache.doris.nereids.rules.implementation.LogicalFilterToPhysicalFilter;
import org.apache.doris.nereids.rules.implementation.LogicalJoinToHashJoin;
import org.apache.doris.nereids.rules.implementation.LogicalJoinToNestedLoopJoin;
import org.apache.doris.nereids.rules.implementation.LogicalLimitToPhysicalLimit;
import org.apache.doris.nereids.rules.implementation.LogicalOlapScanToPhysicalOlapScan;
import org.apache.doris.nereids.rules.implementation.LogicalProjectToPhysicalProject;
@ -48,6 +49,7 @@ public class RuleSet {
.add(new LogicalAggToPhysicalHashAgg())
.add(new LogicalFilterToPhysicalFilter())
.add(new LogicalJoinToHashJoin())
.add(new LogicalJoinToNestedLoopJoin())
.add(new LogicalOlapScanToPhysicalOlapScan())
.add(new LogicalProjectToPhysicalProject())
.add(new LogicalLimitToPhysicalLimit())

View File

@ -68,6 +68,7 @@ public enum RuleType {
// implementation rules
LOGICAL_AGG_TO_PHYSICAL_HASH_AGG_RULE(RuleTypeClass.IMPLEMENTATION),
LOGICAL_JOIN_TO_HASH_JOIN_RULE(RuleTypeClass.IMPLEMENTATION),
LOGICAL_JOIN_TO_NESTED_LOOP_JOIN_RULE(RuleTypeClass.IMPLEMENTATION),
LOGICAL_PROJECT_TO_PHYSICAL_PROJECT_RULE(RuleTypeClass.IMPLEMENTATION),
LOGICAL_FILTER_TO_PHYSICAL_FILTER_RULE(RuleTypeClass.IMPLEMENTATION),
LOGICAL_SORT_TO_PHYSICAL_HEAP_SORT_RULE(RuleTypeClass.IMPLEMENTATION),

View File

@ -20,6 +20,7 @@ package org.apache.doris.nereids.rules.implementation;
import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
import org.apache.doris.nereids.util.JoinUtils;
/**
* Implementation rule that convert logical join to physical hash join.
@ -27,7 +28,9 @@ import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
public class LogicalJoinToHashJoin extends OneImplementationRuleFactory {
@Override
public Rule build() {
return logicalJoin().then(join -> new PhysicalHashJoin<>(
return logicalJoin()
.whenNot(JoinUtils::shouldNestedLoopJoin)
.then(join -> new PhysicalHashJoin<>(
join.getJoinType(),
join.getCondition(),
join.getLogicalProperties(),

View File

@ -0,0 +1,41 @@
// 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.rules.implementation;
import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin;
import org.apache.doris.nereids.util.JoinUtils;
/**
* Implementation rule that convert logical join to physical nested loop join.
*/
public class LogicalJoinToNestedLoopJoin extends OneImplementationRuleFactory {
@Override
public Rule build() {
return logicalJoin()
.when(JoinUtils::shouldNestedLoopJoin)
.then(join -> new PhysicalNestedLoopJoin<>(
join.getJoinType(),
join.getCondition(),
join.getLogicalProperties(),
join.left(),
join.right())
).toRule(RuleType.LOGICAL_JOIN_TO_NESTED_LOOP_JOIN_RULE);
}
}

View File

@ -22,14 +22,17 @@ import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.expressions.SlotReference;
import org.apache.doris.nereids.trees.plans.JoinType;
import org.apache.doris.nereids.trees.plans.algebra.Join;
import org.apache.doris.nereids.util.ExpressionUtils;
import org.apache.doris.statistics.ColumnStats;
import org.apache.doris.statistics.StatsDeriveResult;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
* Estimate hash join stats.
@ -40,11 +43,13 @@ public class JoinEstimation {
/**
* Do estimate.
*/
public static StatsDeriveResult estimate(StatsDeriveResult leftStats, StatsDeriveResult rightStats,
Expression eqCondition, JoinType joinType) {
public static StatsDeriveResult estimate(StatsDeriveResult leftStats, StatsDeriveResult rightStats, Join join) {
Optional<Expression> eqCondition = join.getCondition();
JoinType joinType = join.getJoinType();
StatsDeriveResult statsDeriveResult = new StatsDeriveResult(leftStats);
statsDeriveResult.merge(rightStats);
List<Expression> eqConjunctList = ExpressionUtils.extractConjunction(eqCondition);
List<Expression> eqConjunctList = Lists.newArrayList();
eqCondition.ifPresent(e -> eqConjunctList.addAll(ExpressionUtils.extractConjunction(e)));
long rowCount = -1;
if (joinType.isSemiOrAntiJoin()) {
rowCount = getSemiJoinRowCount(leftStats, rightStats, eqConjunctList, joinType);

View File

@ -23,12 +23,12 @@ import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.NamedExpression;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.expressions.SlotReference;
import org.apache.doris.nereids.trees.plans.Aggregate;
import org.apache.doris.nereids.trees.plans.Filter;
import org.apache.doris.nereids.trees.plans.Limit;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.Project;
import org.apache.doris.nereids.trees.plans.Scan;
import org.apache.doris.nereids.trees.plans.algebra.Aggregate;
import org.apache.doris.nereids.trees.plans.algebra.Filter;
import org.apache.doris.nereids.trees.plans.algebra.Limit;
import org.apache.doris.nereids.trees.plans.algebra.Project;
import org.apache.doris.nereids.trees.plans.algebra.Scan;
import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
@ -42,6 +42,7 @@ import org.apache.doris.nereids.trees.plans.physical.PhysicalFilter;
import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
import org.apache.doris.nereids.trees.plans.physical.PhysicalHeapSort;
import org.apache.doris.nereids.trees.plans.physical.PhysicalLimit;
import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin;
import org.apache.doris.nereids.trees.plans.physical.PhysicalOlapScan;
import org.apache.doris.nereids.trees.plans.physical.PhysicalProject;
import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanVisitor;
@ -119,8 +120,7 @@ public class StatsCalculator extends DefaultPlanVisitor<StatsDeriveResult, Void>
@Override
public StatsDeriveResult visitLogicalJoin(LogicalJoin<Plan, Plan> join, Void context) {
return JoinEstimation.estimate(groupExpression.getCopyOfChildStats(0),
groupExpression.getCopyOfChildStats(1),
join.getCondition().get(), join.getJoinType());
groupExpression.getCopyOfChildStats(1), join);
}
@Override
@ -141,8 +141,14 @@ public class StatsCalculator extends DefaultPlanVisitor<StatsDeriveResult, Void>
@Override
public StatsDeriveResult visitPhysicalHashJoin(PhysicalHashJoin<Plan, Plan> hashJoin, Void context) {
return JoinEstimation.estimate(groupExpression.getCopyOfChildStats(0),
groupExpression.getCopyOfChildStats(1),
hashJoin.getCondition().get(), hashJoin.getJoinType());
groupExpression.getCopyOfChildStats(1), hashJoin);
}
@Override
public StatsDeriveResult visitPhysicalNestedLoopJoin(PhysicalNestedLoopJoin<Plan, Plan> nestedLoopJoin,
Void context) {
return JoinEstimation.estimate(groupExpression.getCopyOfChildStats(0),
groupExpression.getCopyOfChildStats(1), nestedLoopJoin);
}
// TODO: We should subtract those pruned column, and consider the expression transformations in the node.

View File

@ -17,7 +17,8 @@
package org.apache.doris.nereids.trees;
import com.alibaba.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.function.Consumer;

View File

@ -47,6 +47,7 @@ public enum PlanType {
PHYSICAL_SORT,
PHYSICAL_LIMIT,
PHYSICAL_HASH_JOIN,
PHYSICAL_NESTED_LOOP_JOIN,
PHYSICAL_EXCHANGE,
PHYSICAL_DISTRIBUTION;
}

View File

@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.nereids.trees.plans;
package org.apache.doris.nereids.trees.plans.algebra;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.NamedExpression;

View File

@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.nereids.trees.plans;
package org.apache.doris.nereids.trees.plans.algebra;
import org.apache.doris.nereids.trees.expressions.Expression;

View File

@ -0,0 +1,32 @@
// 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.trees.plans.algebra;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.plans.JoinType;
import java.util.Optional;
/**
* Common interface for logical/physical join.
*/
public interface Join {
JoinType getJoinType();
Optional<Expression> getCondition();
}

View File

@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.nereids.trees.plans;
package org.apache.doris.nereids.trees.plans.algebra;
/**
* Common interface for logical/physical limit.

View File

@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.nereids.trees.plans;
package org.apache.doris.nereids.trees.plans.algebra;
import org.apache.doris.nereids.trees.expressions.NamedExpression;

View File

@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.nereids.trees.plans;
package org.apache.doris.nereids.trees.plans.algebra;
import org.apache.doris.catalog.Table;
import org.apache.doris.nereids.trees.expressions.Expression;

View File

@ -23,9 +23,9 @@ import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.NamedExpression;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.AggPhase;
import org.apache.doris.nereids.trees.plans.Aggregate;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.PlanType;
import org.apache.doris.nereids.trees.plans.algebra.Aggregate;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
import com.google.common.base.Preconditions;

View File

@ -21,9 +21,9 @@ import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.Filter;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.PlanType;
import org.apache.doris.nereids.trees.plans.algebra.Filter;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
import com.google.common.base.Preconditions;

View File

@ -25,6 +25,7 @@ import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.JoinType;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.PlanType;
import org.apache.doris.nereids.trees.plans.algebra.Join;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
import com.google.common.base.Preconditions;
@ -39,7 +40,7 @@ import java.util.stream.Collectors;
* Logical join plan.
*/
public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends Plan>
extends LogicalBinary<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> {
extends LogicalBinary<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> implements Join {
private final JoinType joinType;
private final Optional<Expression> condition;

View File

@ -22,9 +22,9 @@ import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.IntegerLiteral;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.Limit;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.PlanType;
import org.apache.doris.nereids.trees.plans.algebra.Limit;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
import com.google.common.base.Preconditions;

View File

@ -24,7 +24,7 @@ import org.apache.doris.nereids.trees.expressions.NamedExpression;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.PlanType;
import org.apache.doris.nereids.trees.plans.Project;
import org.apache.doris.nereids.trees.plans.algebra.Project;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
import com.google.common.base.Preconditions;

View File

@ -24,7 +24,7 @@ import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.expressions.SlotReference;
import org.apache.doris.nereids.trees.plans.PlanType;
import org.apache.doris.nereids.trees.plans.Scan;
import org.apache.doris.nereids.trees.plans.algebra.Scan;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
import org.apache.doris.nereids.util.Utils;

View File

@ -22,9 +22,9 @@ import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.NamedExpression;
import org.apache.doris.nereids.trees.plans.AggPhase;
import org.apache.doris.nereids.trees.plans.Aggregate;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.PlanType;
import org.apache.doris.nereids.trees.plans.algebra.Aggregate;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
import com.google.common.base.Preconditions;

View File

@ -20,9 +20,9 @@ package org.apache.doris.nereids.trees.plans.physical;
import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.plans.Filter;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.PlanType;
import org.apache.doris.nereids.trees.plans.algebra.Filter;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
import com.google.common.base.Preconditions;

View File

@ -26,10 +26,8 @@ import org.apache.doris.nereids.trees.plans.PlanType;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
/**
@ -38,12 +36,7 @@ import java.util.Optional;
public class PhysicalHashJoin<
LEFT_CHILD_TYPE extends Plan,
RIGHT_CHILD_TYPE extends Plan>
extends PhysicalBinary<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> {
private final JoinType joinType;
private final Optional<Expression> condition;
extends PhysicalJoin<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> {
public PhysicalHashJoin(JoinType joinType, Optional<Expression> condition, LogicalProperties logicalProperties,
LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) {
@ -59,17 +52,8 @@ public class PhysicalHashJoin<
public PhysicalHashJoin(JoinType joinType, Optional<Expression> condition,
Optional<GroupExpression> groupExpression, LogicalProperties logicalProperties,
LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) {
super(PlanType.PHYSICAL_HASH_JOIN, groupExpression, logicalProperties, leftChild, rightChild);
this.joinType = Objects.requireNonNull(joinType, "joinType can not be null");
this.condition = Objects.requireNonNull(condition, "condition can not be null");
}
public JoinType getJoinType() {
return joinType;
}
public Optional<Expression> getCondition() {
return condition;
super(PlanType.PHYSICAL_HASH_JOIN, joinType, condition,
groupExpression, logicalProperties, leftChild, rightChild);
}
@Override
@ -77,11 +61,6 @@ public class PhysicalHashJoin<
return visitor.visitPhysicalHashJoin((PhysicalHashJoin<Plan, Plan>) this, context);
}
@Override
public List<Expression> getExpressions() {
return condition.<List<Expression>>map(ImmutableList::of).orElseGet(ImmutableList::of);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
@ -93,23 +72,6 @@ public class PhysicalHashJoin<
return sb.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
PhysicalHashJoin that = (PhysicalHashJoin) o;
return joinType == that.joinType && Objects.equals(condition, that.condition);
}
@Override
public int hashCode() {
return Objects.hash(joinType, condition);
}
@Override
public PhysicalBinary<Plan, Plan> withChildren(List<Plan> children) {
Preconditions.checkArgument(children.size() == 2);

View File

@ -0,0 +1,88 @@
// 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.trees.plans.physical;
import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.plans.JoinType;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.PlanType;
import org.apache.doris.nereids.trees.plans.algebra.Join;
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
/**
* Abstract class for all physical join node.
*/
public abstract class PhysicalJoin<
LEFT_CHILD_TYPE extends Plan,
RIGHT_CHILD_TYPE extends Plan>
extends PhysicalBinary<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> implements Join {
protected final JoinType joinType;
protected final Optional<Expression> condition;
/**
* Constructor of PhysicalJoin.
*
* @param joinType Which join type, left semi join, inner join...
* @param condition join condition.
*/
public PhysicalJoin(PlanType type, JoinType joinType, Optional<Expression> condition,
Optional<GroupExpression> groupExpression, LogicalProperties logicalProperties,
LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) {
super(type, groupExpression, logicalProperties, leftChild, rightChild);
this.joinType = Objects.requireNonNull(joinType, "joinType can not be null");
this.condition = Objects.requireNonNull(condition, "condition can not be null");
}
public JoinType getJoinType() {
return joinType;
}
public Optional<Expression> getCondition() {
return condition;
}
@Override
public List<Expression> getExpressions() {
return condition.<List<Expression>>map(ImmutableList::of).orElseGet(ImmutableList::of);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
PhysicalJoin that = (PhysicalJoin) o;
return joinType == that.joinType && Objects.equals(condition, that.condition);
}
@Override
public int hashCode() {
return Objects.hash(joinType, condition);
}
}

View File

@ -21,9 +21,9 @@ import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.IntegerLiteral;
import org.apache.doris.nereids.trees.plans.Limit;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.PlanType;
import org.apache.doris.nereids.trees.plans.algebra.Limit;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
import com.google.common.base.Preconditions;

View File

@ -0,0 +1,92 @@
// 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.trees.plans.physical;
import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.plans.JoinType;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.PlanType;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
import com.google.common.base.Preconditions;
import java.util.List;
import java.util.Optional;
/**
* Use nested loop algorithm to do join.
*/
public class PhysicalNestedLoopJoin<
LEFT_CHILD_TYPE extends Plan,
RIGHT_CHILD_TYPE extends Plan>
extends PhysicalJoin<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> {
public PhysicalNestedLoopJoin(JoinType joinType, Optional<Expression> condition,
LogicalProperties logicalProperties, LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) {
this(joinType, condition, Optional.empty(), logicalProperties, leftChild, rightChild);
}
/**
* Constructor of PhysicalNestedLoopJoin.
*
* @param joinType Which join type, left semi join, inner join...
* @param condition join condition.
*/
public PhysicalNestedLoopJoin(JoinType joinType, Optional<Expression> condition,
Optional<GroupExpression> groupExpression, LogicalProperties logicalProperties,
LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) {
super(PlanType.PHYSICAL_NESTED_LOOP_JOIN, joinType, condition,
groupExpression, logicalProperties, leftChild, rightChild);
}
@Override
public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
return visitor.visitPhysicalNestedLoopJoin((PhysicalNestedLoopJoin<Plan, Plan>) this, context);
}
@Override
public String toString() {
// TODO: Maybe we could pull up this to the abstract class in the future.
StringBuilder sb = new StringBuilder();
sb.append("PhysicalNestedLoopJoin ([").append(joinType).append("]");
condition.ifPresent(
expression -> sb.append(", [").append(expression).append("]")
);
sb.append(")");
return sb.toString();
}
@Override
public PhysicalBinary<Plan, Plan> withChildren(List<Plan> children) {
Preconditions.checkArgument(children.size() == 2);
return new PhysicalNestedLoopJoin<>(joinType, condition, logicalProperties, children.get(0), children.get(1));
}
@Override
public Plan withGroupExpression(Optional<GroupExpression> groupExpression) {
return new PhysicalNestedLoopJoin<>(joinType, condition, groupExpression, logicalProperties, left(), right());
}
@Override
public Plan withLogicalProperties(Optional<LogicalProperties> logicalProperties) {
return new PhysicalNestedLoopJoin<>(joinType, condition, Optional.empty(),
logicalProperties.get(), left(), right());
}
}

View File

@ -23,7 +23,7 @@ import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.NamedExpression;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.PlanType;
import org.apache.doris.nereids.trees.plans.Project;
import org.apache.doris.nereids.trees.plans.algebra.Project;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
import com.google.common.base.Preconditions;

View File

@ -21,7 +21,7 @@ import org.apache.doris.nereids.memo.GroupExpression;
import org.apache.doris.nereids.properties.LogicalProperties;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.plans.PlanType;
import org.apache.doris.nereids.trees.plans.Scan;
import org.apache.doris.nereids.trees.plans.algebra.Scan;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
import com.google.common.collect.ImmutableList;

View File

@ -37,6 +37,7 @@ import org.apache.doris.nereids.trees.plans.physical.PhysicalFilter;
import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
import org.apache.doris.nereids.trees.plans.physical.PhysicalHeapSort;
import org.apache.doris.nereids.trees.plans.physical.PhysicalLimit;
import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin;
import org.apache.doris.nereids.trees.plans.physical.PhysicalOlapScan;
import org.apache.doris.nereids.trees.plans.physical.PhysicalProject;
import org.apache.doris.nereids.trees.plans.physical.PhysicalRelation;
@ -136,6 +137,10 @@ public abstract class PlanVisitor<R, C> {
return visit(hashJoin, context);
}
public R visitPhysicalNestedLoopJoin(PhysicalNestedLoopJoin<Plan, Plan> nestedLoopJoin, C context) {
return visit(nestedLoopJoin, context);
}
public R visitPhysicalProject(PhysicalProject<Plan> project, C context) {
return visit(project, context);
}

View File

@ -21,8 +21,10 @@ import org.apache.doris.common.Pair;
import org.apache.doris.nereids.trees.expressions.EqualTo;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.SlotReference;
import org.apache.doris.nereids.trees.plans.JoinType;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin;
import org.apache.doris.nereids.trees.plans.algebra.Join;
import org.apache.doris.nereids.trees.plans.physical.PhysicalJoin;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
@ -34,19 +36,19 @@ import java.util.List;
* Utils for join
*/
public class JoinUtils {
public static boolean onlyBroadcast(PhysicalHashJoin join) {
public static boolean onlyBroadcast(PhysicalJoin join) {
// Cross-join only can be broadcast join.
return join.getJoinType().isCrossJoin();
}
public static boolean onlyShuffle(PhysicalHashJoin join) {
public static boolean onlyShuffle(PhysicalJoin join) {
return join.getJoinType().isRightJoin() || join.getJoinType().isFullOuterJoin();
}
/**
* Get all equalTo from onClause of join
*/
public static List<EqualTo> getEqualTo(PhysicalHashJoin<Plan, Plan> join) {
public static List<EqualTo> getEqualTo(PhysicalJoin<Plan, Plan> join) {
List<EqualTo> eqConjuncts = Lists.newArrayList();
if (!join.getCondition().isPresent()) {
return eqConjuncts;
@ -86,7 +88,7 @@ public class JoinUtils {
* Return pair of left used slots and right used slots.
*/
public static Pair<List<SlotReference>, List<SlotReference>> getOnClauseUsedSlots(
PhysicalHashJoin<Plan, Plan> join) {
PhysicalJoin<Plan, Plan> join) {
Pair<List<SlotReference>, List<SlotReference>> childSlots =
new Pair<>(Lists.newArrayList(), Lists.newArrayList());
@ -114,4 +116,9 @@ public class JoinUtils {
return childSlots;
}
public static boolean shouldNestedLoopJoin(Join join) {
JoinType joinType = join.getJoinType();
return (joinType.isInnerJoin() && !join.getCondition().isPresent()) || joinType.isCrossJoin();
}
}

View File

@ -32,6 +32,7 @@ import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.expressions.SlotReference;
import org.apache.doris.nereids.trees.expressions.functions.AggregateFunction;
import org.apache.doris.nereids.trees.expressions.functions.Sum;
import org.apache.doris.nereids.trees.plans.FakeJoin;
import org.apache.doris.nereids.trees.plans.GroupPlan;
import org.apache.doris.nereids.trees.plans.JoinType;
import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
@ -190,11 +191,13 @@ public class StatsCalculatorTest {
StatsDeriveResult rightStats = new StatsDeriveResult(rightRowCount, slotColumnStatsMap2);
EqualTo equalTo = new EqualTo(slot1, slot2);
StatsDeriveResult semiJoinStats = JoinEstimation.estimate(leftStats,
rightStats, equalTo, JoinType.LEFT_SEMI_JOIN);
FakeJoin fakeSemiJoin = new FakeJoin(JoinType.LEFT_SEMI_JOIN, Optional.of(equalTo));
FakeJoin fakeInnerJoin = new FakeJoin(JoinType.INNER_JOIN, Optional.of(equalTo));
StatsDeriveResult semiJoinStats = JoinEstimation.estimate(leftStats, rightStats, fakeSemiJoin);
Assertions.assertEquals(leftRowCount, semiJoinStats.getRowCount());
StatsDeriveResult innerJoinStats = JoinEstimation.estimate(leftStats,
rightStats, equalTo, JoinType.INNER_JOIN);
StatsDeriveResult innerJoinStats = JoinEstimation.estimate(leftStats, rightStats, fakeInnerJoin);
Assertions.assertEquals(2500000, innerJoinStats.getRowCount());
}
@ -240,7 +243,6 @@ public class StatsCalculatorTest {
Assertions.assertNotNull(stats.getSlotToColumnStats().get(slot1));
}
@Test
public void testLimit() {
List<String> qualifier = new ArrayList<>();
@ -276,6 +278,5 @@ public class StatsCalculatorTest {
ColumnStats slot1Stats = limitStats.getSlotToColumnStats().get(slot1);
Assertions.assertEquals(1, slot1Stats.getNdv());
Assertions.assertEquals(1, slot1Stats.getNumNulls());
}
}

View File

@ -0,0 +1,43 @@
// 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.trees.plans;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.plans.algebra.Join;
import java.util.Optional;
public class FakeJoin implements Join {
private final JoinType joinType;
private final Optional<Expression> condition;
public FakeJoin(JoinType joinType, Optional<Expression> condition) {
this.joinType = joinType;
this.condition = condition;
}
@Override
public JoinType getJoinType() {
return joinType;
}
@Override
public Optional<Expression> getCondition() {
return condition;
}
}

View File

@ -43,3 +43,14 @@
-- !right_anti_join --
-- !cross_join --
1309892 1 1303 1432 15 19920517 3-MEDIUM 0 24 2959704 5119906 7 2752524 73992 0 19920619 TRUCK 15 Supplier#000000015 DF35PepL5saAK INDIA 0 INDIA ASIA 18-687-542-7601
1309892 1 1303 1432 15 19920517 3-MEDIUM 0 24 2959704 5119906 7 2752524 73992 0 19920619 TRUCK 29 Supplier#000000029 VVSymB3fbwaN ARGENTINA4 ARGENTINA AMERICA 11-773-203-7342
1309892 1 1303 1432 15 19920517 3-MEDIUM 0 24 2959704 5119906 7 2752524 73992 0 19920619 TRUCK 9 Supplier#000000009 ,gJ6K2MKveYxQT IRAN 6 IRAN MIDDLE EAST 20-338-906-3675
1309892 2 1303 1165 9 19920517 3-MEDIUM 0 21 2404899 5119906 8 2212507 68711 7 19920616 RAIL 15 Supplier#000000015 DF35PepL5saAK INDIA 0 INDIA ASIA 18-687-542-7601
1309892 2 1303 1165 9 19920517 3-MEDIUM 0 21 2404899 5119906 8 2212507 68711 7 19920616 RAIL 29 Supplier#000000029 VVSymB3fbwaN ARGENTINA4 ARGENTINA AMERICA 11-773-203-7342
1309892 2 1303 1165 9 19920517 3-MEDIUM 0 21 2404899 5119906 8 2212507 68711 7 19920616 RAIL 9 Supplier#000000009 ,gJ6K2MKveYxQT IRAN 6 IRAN MIDDLE EAST 20-338-906-3675
1310179 6 1312 1455 29 19921110 3-MEDIUM 0 15 1705830 20506457 10 1535247 68233 8 19930114 FOB 15 Supplier#000000015 DF35PepL5saAK INDIA 0 INDIA ASIA 18-687-542-7601
1310179 6 1312 1455 29 19921110 3-MEDIUM 0 15 1705830 20506457 10 1535247 68233 8 19930114 FOB 29 Supplier#000000029 VVSymB3fbwaN ARGENTINA4 ARGENTINA AMERICA 11-773-203-7342
1310179 6 1312 1455 29 19921110 3-MEDIUM 0 15 1705830 20506457 10 1535247 68233 8 19930114 FOB 9 Supplier#000000009 ,gJ6K2MKveYxQT IRAN 6 IRAN MIDDLE EAST 20-338-906-3675

View File

@ -63,5 +63,9 @@ suite("join") {
order_qt_right_anti_join """
SELECT * FROM lineorder RIGHT ANTI JOIN supplier ON lineorder.lo_suppkey = supplier.s_suppkey
"""
order_qt_cross_join """
SELECT * FROM lineorder CROSS JOIN supplier;
"""
}