| 353 | } |
| 354 | |
| 355 | std::shared_ptr<RelExpression> Binder::createRecursiveQueryRel(const parser::RelPattern& relPattern, |
| 356 | const std::vector<TableCatalogEntry*>& entries, std::shared_ptr<NodeExpression> srcNode, |
| 357 | std::shared_ptr<NodeExpression> dstNode, RelDirectionType directionType) { |
| 358 | auto catalog = Catalog::Get(*clientContext); |
| 359 | auto transaction = transaction::Transaction::Get(*clientContext); |
| 360 | table_catalog_entry_set_t nodeEntrySet; |
| 361 | for (auto entry : entries) { |
| 362 | auto& relGroupEntry = entry->constCast<RelGroupCatalogEntry>(); |
| 363 | for (auto id : relGroupEntry.getSrcNodeTableIDSet()) { |
| 364 | nodeEntrySet.insert(catalog->getTableCatalogEntry(transaction, id)); |
| 365 | } |
| 366 | for (auto id : relGroupEntry.getDstNodeTableIDSet()) { |
| 367 | nodeEntrySet.insert(catalog->getTableCatalogEntry(transaction, id)); |
| 368 | } |
| 369 | } |
| 370 | auto nodeEntries = std::vector<TableCatalogEntry*>{nodeEntrySet.begin(), nodeEntrySet.end()}; |
| 371 | auto recursivePatternInfo = relPattern.getRecursiveInfo(); |
| 372 | auto prevScope = saveScope(); |
| 373 | scope.clear(); |
| 374 | // Bind intermediate node. |
| 375 | auto node = createQueryNode(recursivePatternInfo->nodeName, nodeEntries, {}, {}); |
| 376 | addToScope(node->toString(), node); |
| 377 | auto nodeFields = getBaseNodeStructFields(); |
| 378 | auto nodeProjectionList = bindRecursivePatternNodeProjectionList(*recursivePatternInfo, *node); |
| 379 | bindProjectionListAsStructField(nodeProjectionList, nodeFields); |
| 380 | node->setDataType(LogicalType::NODE(std::move(nodeFields))); |
| 381 | auto nodeCopy = createQueryNode(recursivePatternInfo->nodeName, nodeEntries, {}, {}); |
| 382 | // Bind intermediate rel |
| 383 | auto rel = createNonRecursiveQueryRel(recursivePatternInfo->relName, entries, |
| 384 | nullptr /* srcNode */, nullptr /* dstNode */, directionType, {}); |
| 385 | addToScope(rel->toString(), rel); |
| 386 | auto relProjectionList = bindRecursivePatternRelProjectionList(*recursivePatternInfo, *rel); |
| 387 | auto relFields = getBaseRelStructFields(); |
| 388 | relFields.emplace_back(InternalKeyword::ID, LogicalType::INTERNAL_ID()); |
| 389 | bindProjectionListAsStructField(relProjectionList, relFields); |
| 390 | rel->setDataType(LogicalType::REL(std::move(relFields))); |
| 391 | // Bind predicates in {}, e.g. [e* {date=1999-01-01}] |
| 392 | std::shared_ptr<Expression> relPredicate = nullptr; |
| 393 | for (auto& [propertyName, rhs] : relPattern.getPropertyKeyVals()) { |
| 394 | auto boundLhs = expressionBinder.bindNodeOrRelPropertyExpression(*rel, propertyName); |
| 395 | auto boundRhs = expressionBinder.bindExpression(*rhs); |
| 396 | boundRhs = expressionBinder.implicitCastIfNecessary(boundRhs, boundLhs->dataType); |
| 397 | auto predicate = expressionBinder.createEqualityComparisonExpression(boundLhs, boundRhs); |
| 398 | relPredicate = expressionBinder.combineBooleanExpressions(ExpressionType::AND, relPredicate, |
| 399 | predicate); |
| 400 | } |
| 401 | // Bind predicates in (r, n | WHERE ) |
| 402 | bool emptyRecursivePattern = false; |
| 403 | std::shared_ptr<Expression> nodePredicate = nullptr; |
| 404 | if (recursivePatternInfo->whereExpression != nullptr) { |
| 405 | expressionBinder.config.disableLabelFunctionLiteralRewrite = true; |
| 406 | auto wherePredicate = bindWhereExpression(*recursivePatternInfo->whereExpression); |
| 407 | expressionBinder.config.disableLabelFunctionLiteralRewrite = false; |
| 408 | for (auto& predicate : wherePredicate->splitOnAND()) { |
| 409 | auto collector = DependentVarNameCollector(); |
| 410 | collector.visit(predicate); |
| 411 | auto dependentVariableNames = collector.getVarNames(); |
| 412 | auto dependOnNode = dependentVariableNames.contains(node->getUniqueName()); |
nothing calls this directly
no test coverage detected