diff --git a/src/graph/validator/MatchValidator.cpp b/src/graph/validator/MatchValidator.cpp index eb5d998a374..8a359b7f2f1 100644 --- a/src/graph/validator/MatchValidator.cpp +++ b/src/graph/validator/MatchValidator.cpp @@ -379,7 +379,7 @@ Status MatchValidator::buildColumnsForAllNamedAliases(const std::vectorkind) { case CypherClauseKind::kUnwind: { auto unwindCtx = static_cast(boundary.get()); - columns->addColumn(makeColumn(unwindCtx->alias)); + columns->addColumn(makeColumn(unwindCtx->alias), true); break; } case CypherClauseKind::kWith: { @@ -390,7 +390,7 @@ Status MatchValidator::buildColumnsForAllNamedAliases(const std::vectorcolumns()) { if (!col->alias().empty()) { - columns->addColumn(makeColumn(col->alias())); + columns->addColumn(makeColumn(col->alias()), true); } } break; @@ -584,7 +584,10 @@ Status MatchValidator::validateWith(const WithClause *with, auto found = withClauseCtx.yield->aliasesAvailable.find(label); DCHECK(found != withClauseCtx.yield->aliasesAvailable.end()); if (!withClauseCtx.aliasesGenerated.emplace(col->alias(), found->second).second) { - return Status::SemanticError("`%s': Redefined alias", col->alias().c_str()); + auto columnFound = withClauseCtx.yield->yieldColumns->find(col->alias()); + if (!(columnFound != nullptr && columnFound->isMatched())) { + return Status::SemanticError("`%s': Redefined alias", col->alias().c_str()); + } } } else { if (!withClauseCtx.aliasesGenerated.emplace(col->alias(), aliasType).second) { diff --git a/src/parser/Clauses.h b/src/parser/Clauses.h index fd62eb20418..0d275996028 100644 --- a/src/parser/Clauses.h +++ b/src/parser/Clauses.h @@ -257,6 +257,7 @@ class YieldColumn final { explicit YieldColumn(Expression *expr, const std::string &alias = "") { expr_ = expr; alias_ = alias; + isMatched_ = false; } std::unique_ptr clone() const { @@ -285,9 +286,18 @@ class YieldColumn final { std::string toString() const; + void setMatched(bool isMatched) { + isMatched_ = isMatched; + } + + bool isMatched() const { + return isMatched_; + } + private: Expression *expr_{nullptr}; std::string alias_; + bool isMatched_; }; bool operator==(const YieldColumn &l, const YieldColumn &r); @@ -297,8 +307,9 @@ inline bool operator!=(const YieldColumn &l, const YieldColumn &r) { class YieldColumns final { public: - void addColumn(YieldColumn *field) { + void addColumn(YieldColumn *field, bool isMatched = false) { columns_.emplace_back(field); + field->setMatched(isMatched); } std::vector columns() const { @@ -346,6 +357,15 @@ class YieldColumns final { bool hasAgg() const; + YieldColumn *find(const std::string &name) const { + for (auto &col : columns_) { + if (name.compare(col->name()) == 0) { + return col.get(); + } + } + return nullptr; + } + private: std::vector> columns_; }; diff --git a/tests/tck/features/match/With.feature b/tests/tck/features/match/With.feature index 895853de8ba..c3905e8e5b5 100644 --- a/tests/tck/features/match/With.feature +++ b/tests/tck/features/match/With.feature @@ -387,3 +387,16 @@ Feature: With clause | [:teammate "Tim Duncan"->"Tony Parker" @0 {end_year: 2016, start_year: 2001}] | | [:like "Tim Duncan"->"Tony Parker" @0 {likeness: 95}] | | [:teammate "Tim Duncan"->"Danny Green" @0 {end_year: 2016, start_year: 2010}] | + + Scenario: with wildcard after multiple matches + When executing query: + """ + match (v0:player)--(v1:team) where v1.team.name == "Spurs" and v0.player.name == "Tim Duncan" + match (v:player) where v.player.name != "Tim Duncan" with v0 where v0.player.age > 0 + match (v0:player) + with * + return count(v0) + """ + Then the result should be, in order: + | count(v0) | + | 51 |