| 58 | } |
| 59 | |
| 60 | JoinTreeConstructor::IntermediateResult JoinTreeConstructor::constructTreeNode( |
| 61 | std::shared_ptr<BoundJoinHintNode> hintNode) { |
| 62 | // Construct leaf scans. |
| 63 | if (hintNode->isLeaf()) { |
| 64 | if (ExpressionUtil::isNodePattern(*hintNode->nodeOrRel)) { |
| 65 | return constructNodeScan(hintNode->nodeOrRel); |
| 66 | } else { |
| 67 | DASSERT(ExpressionUtil::isRelPattern(*hintNode->nodeOrRel) || |
| 68 | ExpressionUtil::isRecursiveRelPattern(*hintNode->nodeOrRel)); |
| 69 | return constructRelScan(hintNode->nodeOrRel); |
| 70 | } |
| 71 | } |
| 72 | // Construct binary join. |
| 73 | if (hintNode->isBinary()) { |
| 74 | auto left = constructTreeNode(hintNode->children[0]); |
| 75 | auto right = constructTreeNode(hintNode->children[1]); |
| 76 | auto joinNodes = getJoinNodes(left.subqueryGraph, right.subqueryGraph); |
| 77 | if (joinNodes.empty()) { |
| 78 | joinNodes = getJoinNodes(right.subqueryGraph, left.subqueryGraph); |
| 79 | } |
| 80 | if (joinNodes.empty()) { |
| 81 | throw BinderException(std::format("Cannot resolve join condition between {} and {}.", |
| 82 | left.treeNode->toString(), right.treeNode->toString())); |
| 83 | } |
| 84 | auto newSubgraph = left.subqueryGraph; |
| 85 | newSubgraph.addSubqueryGraph(right.subqueryGraph); |
| 86 | auto predicates = Planner::getNewlyMatchedExprs(left.subqueryGraph, right.subqueryGraph, |
| 87 | newSubgraph, queryGraphPredicates); |
| 88 | // First try to construct as index nested loop join. |
| 89 | auto nestedLoopTreeNode = |
| 90 | tryConstructNestedLoopJoin(joinNodes, *left.treeNode, *right.treeNode, predicates); |
| 91 | if (nestedLoopTreeNode != nullptr) { |
| 92 | return {nestedLoopTreeNode, newSubgraph}; |
| 93 | } |
| 94 | // Cannot construct index nested loop join. Fall back to hash join. |
| 95 | auto extraInfo = std::make_unique<ExtraJoinTreeNodeInfo>(joinNodes); |
| 96 | extraInfo->predicates = predicates; |
| 97 | auto treeNode = |
| 98 | std::make_shared<JoinTreeNode>(TreeNodeType::BINARY_JOIN, std::move(extraInfo)); |
| 99 | treeNode->addChild(left.treeNode); |
| 100 | treeNode->addChild(right.treeNode); |
| 101 | return {treeNode, newSubgraph}; |
| 102 | } |
| 103 | // Construct multi-way join |
| 104 | DASSERT(hintNode->isMultiWay()); |
| 105 | auto probe = constructTreeNode(hintNode->children[0]); |
| 106 | auto newSubgraph = probe.subqueryGraph; |
| 107 | std::vector<std::shared_ptr<JoinTreeNode>> childrenNodes; |
| 108 | childrenNodes.push_back(probe.treeNode); |
| 109 | std::vector<SubqueryGraph> buildSubgraphs; |
| 110 | for (auto i = 1u; i < hintNode->children.size(); ++i) { |
| 111 | auto build = constructTreeNode(hintNode->children[i]); |
| 112 | if (build.treeNode->type != TreeNodeType::REL_SCAN) { |
| 113 | throw BinderException(std::format( |
| 114 | "Cannot construct multi-way join because build side is not a relationship table.")); |
| 115 | } |
| 116 | newSubgraph.addSubqueryGraph(build.subqueryGraph); |
| 117 | childrenNodes.push_back(build.treeNode); |
nothing calls this directly
no test coverage detected