From 5057eeb7dfb41c6eb0cbb459cb455bda77c5fe66 Mon Sep 17 00:00:00 2001 From: Cheng Xuntao <7731943+xtcyclist@users.noreply.github.com> Date: Thu, 8 Dec 2022 13:31:50 +0800 Subject: [PATCH] Allow usage of aliases defined in previous matches. (#5021) * allow usage of aliases defined in previous matches. * update tck * add a tck * fix tck format --- src/graph/validator/MatchValidator.cpp | 9 ++++++--- src/parser/Clauses.h | 22 +++++++++++++++++++- tests/tck/features/match/With.feature | 28 +++++++++++++++++++++++++- 3 files changed, 54 insertions(+), 5 deletions(-) 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..7637c5b374f 100644 --- a/tests/tck/features/match/With.feature +++ b/tests/tck/features/match/With.feature @@ -378,7 +378,7 @@ Feature: With clause Scenario: with wildcard after unwind When executing query: """ - match p = (v0)-[e0]->(v1) where id(v0) in ["Tim Duncan"] unwind v0 as uv0 with * return e0 limit 5; + match p = (v0)-[e0]->(v1) where id(v0) in ["Tim Duncan"] unwind v0 as uv0 with * return e0; """ Then the result should be, in any order: | e0 | @@ -387,3 +387,29 @@ 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}] | + | [:teammate "Tim Duncan"->"Manu Ginobili" @0 {end_year: 2016, start_year: 2002}] | + | [:like "Tim Duncan"->"Manu Ginobili" @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'