Skip to content
This repository was archived by the owner on Oct 10, 2025. It is now read-only.

Commit d471344

Browse files
author
wyj
committed
path semantic use isDistinct function in binder
1 parent dfabf90 commit d471344

File tree

7 files changed

+374
-3
lines changed

7 files changed

+374
-3
lines changed

src/binder/bind/bind_graph_pattern.cpp

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "binder/expression/literal_expression.h"
44
#include "binder/expression/path_expression.h"
55
#include "binder/expression/property_expression.h"
6+
#include "binder/expression/scalar_function_expression.h"
67
#include "binder/expression_visitor.h"
78
#include "catalog/catalog.h"
89
#include "catalog/catalog_entry/node_table_catalog_entry.h"
@@ -11,8 +12,10 @@
1112
#include "common/exception/binder.h"
1213
#include "common/string_format.h"
1314
#include "common/utils.h"
15+
#include "function/built_in_function_utils.h"
1416
#include "function/cast/functions/cast_from_string_functions.h"
1517
#include "function/rewrite_function.h"
18+
#include "function/scalar_function.h"
1619
#include "function/schema/vector_node_rel_functions.h"
1720
#include "main/client_context.h"
1821

@@ -56,6 +59,106 @@ QueryGraph Binder::bindPatternElement(const PatternElement& patternElement) {
5659
nodeAndRels.push_back(rightNode);
5760
leftNode = rightNode;
5861
}
62+
if (clientContext->getClientConfig()->recursivePatternSemantic != common::PathSemantic::WALK) {
63+
if (queryGraph.hasRecursiveRel()) {
64+
// The only one recursive rel doesn't need to be handled because RecursiveJoin
65+
// already implements path semantics. Like (a)-[b*2]-(c)
66+
// What needs to be handled is the recursive
67+
// rels with other nodes/rels. Like (a)-[b*2]-(c)-[d*2]-(e) or (a)-[b*2]-(c)-[d]-(e)
68+
auto rels = queryGraph.getQueryRels();
69+
if (rels.size() > 1) {
70+
std::vector<LogicalType> childrenTypes;
71+
binder::expression_vector childrenExpressions;
72+
std::string funcName;
73+
if (clientContext->getClientConfig()->recursivePatternSemantic ==
74+
common::PathSemantic::ACYCLIC) {
75+
auto nodes = queryGraph.getQueryNodes();
76+
for (uint32_t j = 0; j < nodes.size(); ++j) {
77+
childrenTypes.push_back(nodes[j]->getInternalID()->dataType.copy());
78+
childrenExpressions.push_back(nodes[j]->getInternalID());
79+
}
80+
for (uint32_t j = 0; j < rels.size(); ++j) {
81+
if (rels[j]->isRecursive()) {
82+
childrenTypes.push_back(rels[j]->dataType.copy());
83+
childrenExpressions.push_back(rels[j]);
84+
}
85+
}
86+
funcName = function::IsNodeDistinctFunction::name;
87+
} else {
88+
for (uint32_t j = 0; j < rels.size(); ++j) {
89+
if (rels[j]->isRecursive()) {
90+
childrenTypes.push_back(rels[j]->dataType.copy());
91+
childrenExpressions.push_back(rels[j]);
92+
} else {
93+
childrenTypes.push_back(
94+
rels[j]->getInternalIDProperty()->dataType.copy());
95+
childrenExpressions.push_back(rels[j]->getInternalIDProperty());
96+
}
97+
}
98+
funcName = function::IsRelDistinctFunction::name;
99+
}
100+
auto catalog = clientContext->getCatalog();
101+
auto transaction = clientContext->getTransaction();
102+
auto functionEntry = catalog->getFunctionEntry(transaction, funcName);
103+
auto function = function::BuiltInFunctionsUtils::matchFunction(funcName,
104+
childrenTypes, functionEntry->ptrCast<FunctionCatalogEntry>())
105+
->ptrCast<function::ScalarFunction>()
106+
->copy();
107+
std::unique_ptr<function::FunctionBindData> bindData =
108+
std::make_unique<function::FunctionBindData>(
109+
LogicalType(function->returnTypeID));
110+
auto uniqueExpressionName = binder::ScalarFunctionExpression::getUniqueName(
111+
function->name, childrenExpressions);
112+
auto functionExpression = std::make_shared<binder::ScalarFunctionExpression>(
113+
ExpressionType::FUNCTION, std::move(function), std::move(bindData),
114+
childrenExpressions, uniqueExpressionName);
115+
queryGraph.addSemanticExpression(functionExpression);
116+
}
117+
} else {
118+
// not have recursive rel. Like: (a)-[b]-(c)-[d]-(e)
119+
std::vector<LogicalType> childrenTypes;
120+
binder::expression_vector childrenExpressions;
121+
if (clientContext->getClientConfig()->recursivePatternSemantic ==
122+
common::PathSemantic::ACYCLIC) {
123+
auto nodes = queryGraph.getQueryNodes();
124+
for (uint32_t j = 0; j < nodes.size(); ++j) {
125+
childrenTypes.push_back(nodes[j]->getInternalID()->dataType.copy());
126+
childrenExpressions.push_back(nodes[j]->getInternalID());
127+
}
128+
} else {
129+
auto rels = queryGraph.getQueryRels();
130+
for (uint32_t j = 0; j < rels.size(); ++j) {
131+
childrenTypes.push_back(rels[j]->getInternalIDProperty()->dataType.copy());
132+
childrenExpressions.push_back(rels[j]->getInternalIDProperty());
133+
}
134+
}
135+
if (childrenExpressions.size() > 2) {
136+
auto catalog = clientContext->getCatalog();
137+
auto transaction = clientContext->getTransaction();
138+
auto functionEntry =
139+
catalog->getFunctionEntry(transaction, function::IsIDDistinctFunction::name);
140+
auto function = function::BuiltInFunctionsUtils::matchFunction(
141+
function::IsIDDistinctFunction::name, childrenTypes,
142+
functionEntry->ptrCast<FunctionCatalogEntry>())
143+
->ptrCast<function::ScalarFunction>()
144+
->copy();
145+
std::unique_ptr<function::FunctionBindData> bindData =
146+
std::make_unique<function::FunctionBindData>(
147+
LogicalType(function->returnTypeID));
148+
auto uniqueExpressionName = binder::ScalarFunctionExpression::getUniqueName(
149+
function->name, childrenExpressions);
150+
auto functionExpression = std::make_shared<binder::ScalarFunctionExpression>(
151+
ExpressionType::FUNCTION, std::move(function), std::move(bindData),
152+
childrenExpressions, uniqueExpressionName);
153+
queryGraph.addSemanticExpression(functionExpression);
154+
} else if (childrenExpressions.size() == 2) {
155+
// when only two children use no_equal
156+
auto noEquals = expressionBinder.bindComparisonExpression(
157+
kuzu::common::ExpressionType::NOT_EQUALS, childrenExpressions);
158+
queryGraph.addSemanticExpression(noEquals);
159+
}
160+
}
161+
}
59162
if (patternElement.hasPathName()) {
60163
auto pathName = patternElement.getPathName();
61164
auto pathExpression = createPath(pathName, nodeAndRels);

src/binder/bind/read/bind_match.cpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
#include "binder/binder.h"
2+
#include "binder/expression/scalar_function_expression.h"
23
#include "binder/query/reading_clause/bound_match_clause.h"
4+
#include "catalog/catalog.h"
35
#include "common/exception/binder.h"
6+
#include "function/built_in_function_utils.h"
7+
#include "function/scalar_function.h"
8+
#include "function/schema/vector_node_rel_functions.h"
9+
#include "main/client_context.h"
410
#include "parser/query/reading_clause/match_clause.h"
5-
611
using namespace kuzu::common;
712
using namespace kuzu::parser;
813

@@ -37,8 +42,27 @@ static void validateHintCompleteness(const BoundJoinHintNode& root, const QueryG
3742
std::unique_ptr<BoundReadingClause> Binder::bindMatchClause(const ReadingClause& readingClause) {
3843
auto& matchClause = readingClause.constCast<MatchClause>();
3944
auto boundGraphPattern = bindGraphPattern(matchClause.getPatternElementsRef());
40-
if (matchClause.hasWherePredicate()) {
45+
std::shared_ptr<Expression> semanticExpression;
46+
auto queryGraphsNum = boundGraphPattern.queryGraphCollection.getNumQueryGraphs();
47+
for (uint32_t i = 0; i < queryGraphsNum; ++i){
48+
for(auto & expr: boundGraphPattern.queryGraphCollection.getQueryGraph(i)->getSemanticExpressions()) {
49+
if(!semanticExpression){
50+
semanticExpression = expr;
51+
} else {
52+
semanticExpression = expressionBinder.bindBooleanExpression(kuzu::common::ExpressionType::AND,
53+
binder::expression_vector{semanticExpression, expr});
54+
}
55+
}
56+
}
57+
if (matchClause.hasWherePredicate() && semanticExpression) {
58+
boundGraphPattern.where =
59+
expressionBinder.bindBooleanExpression(kuzu::common::ExpressionType::AND,
60+
binder::expression_vector{semanticExpression,
61+
bindWhereExpression(*matchClause.getWherePredicate())});
62+
} else if (matchClause.hasWherePredicate()) {
4163
boundGraphPattern.where = bindWhereExpression(*matchClause.getWherePredicate());
64+
} else if (semanticExpression) {
65+
boundGraphPattern.where = semanticExpression;
4266
}
4367
rewriteMatchPattern(boundGraphPattern);
4468
auto boundMatch = std::make_unique<BoundMatchClause>(

src/binder/query/query_graph.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,9 @@ void QueryGraph::merge(const QueryGraph& other) {
213213
for (auto& otherRel : other.queryRels) {
214214
addQueryRel(otherRel);
215215
}
216+
for (auto& otherSemantic : other.semanticExpressions) {
217+
semanticExpressions.push_back(otherSemantic);
218+
}
216219
}
217220

218221
bool QueryGraph::canProjectExpression(const std::shared_ptr<Expression>& expression) const {
@@ -235,6 +238,15 @@ bool QueryGraph::isConnected(const QueryGraph& other) const {
235238
return false;
236239
}
237240

241+
bool QueryGraph::hasRecursiveRel() {
242+
for (auto& rel : queryRels) {
243+
if (rel->isRecursive()) {
244+
return true;
245+
}
246+
}
247+
return false;
248+
}
249+
238250
void QueryGraphCollection::addAndMergeQueryGraphIfConnected(QueryGraph queryGraphToAdd) {
239251
auto newQueryGraphSet = std::vector<QueryGraph>();
240252
for (auto i = 0u; i < queryGraphs.size(); i++) {

src/function/function_collection.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,8 @@ FunctionCollection* FunctionCollection::getFunctions() {
188188
SCALAR_FUNCTION(OffsetFunction), REWRITE_FUNCTION(IDFunction),
189189
REWRITE_FUNCTION(StartNodeFunction), REWRITE_FUNCTION(EndNodeFunction),
190190
REWRITE_FUNCTION(LabelFunction),
191+
SCALAR_FUNCTION(IsIDDistinctFunction),SCALAR_FUNCTION(IsNodeDistinctFunction),
192+
SCALAR_FUNCTION(IsRelDistinctFunction),
191193

192194
// Path functions
193195
SCALAR_FUNCTION(NodesFunction), SCALAR_FUNCTION(RelsFunction),

0 commit comments

Comments
 (0)