diff --git a/src/graph/validator/MatchValidator.cpp b/src/graph/validator/MatchValidator.cpp index f77394a24cd..c1b93044cf2 100644 --- a/src/graph/validator/MatchValidator.cpp +++ b/src/graph/validator/MatchValidator.cpp @@ -399,7 +399,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: { @@ -410,7 +410,7 @@ Status MatchValidator::buildColumnsForAllNamedAliases(const std::vectorcolumns()) { if (!col->alias().empty()) { - columns->addColumn(makeColumn(col->alias())); + columns->addColumn(makeColumn(col->alias()), true); } } break; @@ -621,7 +621,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 4e7a76b4bd2..baa89bcc8a2 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 49900ce9d9c..fd54d6716a9 100644 --- a/tests/tck/features/match/With.feature +++ b/tests/tck/features/match/With.feature @@ -389,3 +389,27 @@ Feature: With clause | [:serve "Tim Duncan"->"Spurs" @0 {end_year: 2016, start_year: 1997}] | | [:like "Tim Duncan"->"Manu Ginobili" @0 {likeness: 95}] | | [:like "Tim Duncan"->"Tony Parker" @0 {likeness: 95}] | + + 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 | + When executing query: + """ + match (v:player) + with v AS p + match (p) + with p AS v + match (v) + with * + return count (p) + """ + Then a SemanticError should be raised at runtime: Alias used but not defined: `p'