Prevent same names in named expressions
Reviewers: florijan, mislav.bradac Reviewed By: florijan Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D291
This commit is contained in:
parent
c1d0090fe1
commit
c429923b31
@ -4,6 +4,8 @@
|
||||
|
||||
#include "query/frontend/semantic/symbol_generator.hpp"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
namespace query {
|
||||
|
||||
auto SymbolGenerator::CreateSymbol(const std::string &name, Symbol::Type type) {
|
||||
@ -28,21 +30,30 @@ auto SymbolGenerator::GetOrCreateSymbol(const std::string &name,
|
||||
return CreateSymbol(name, type);
|
||||
}
|
||||
|
||||
void SymbolGenerator::BindNamedExpressionSymbols(
|
||||
const std::vector<NamedExpression *> &named_expressions) {
|
||||
std::unordered_set<std::string> seen_names;
|
||||
for (auto &named_expr : named_expressions) {
|
||||
// Improvement would be to infer the type of the expression.
|
||||
const auto &name = named_expr->name_;
|
||||
if (!seen_names.insert(name).second) {
|
||||
throw SemanticException(
|
||||
"Multiple results with the same name '{}' are not allowed.", name);
|
||||
}
|
||||
symbol_table_[*named_expr] = CreateSymbol(name);
|
||||
}
|
||||
}
|
||||
|
||||
// Clauses
|
||||
|
||||
void SymbolGenerator::Visit(Create &create) { scope_.in_create = true; }
|
||||
void SymbolGenerator::PostVisit(Create &create) { scope_.in_create = false; }
|
||||
|
||||
void SymbolGenerator::Visit(Return &ret) {
|
||||
scope_.in_return = true;
|
||||
}
|
||||
void SymbolGenerator::Visit(Return &ret) { scope_.in_return = true; }
|
||||
void SymbolGenerator::PostVisit(Return &ret) {
|
||||
for (auto &named_expr : ret.named_expressions_) {
|
||||
// Named expressions establish bindings for expressions which come after
|
||||
// return, but not for the expressions contained inside.
|
||||
symbol_table_[*named_expr] = CreateSymbol(named_expr->name_);
|
||||
// Improvement to type checking system would be to infer the type of the expression.
|
||||
}
|
||||
// Named expressions establish bindings for expressions which come after
|
||||
// return, but not for the expressions contained inside.
|
||||
BindNamedExpressionSymbols(ret.named_expressions_);
|
||||
scope_.in_return = false;
|
||||
}
|
||||
|
||||
@ -56,10 +67,7 @@ bool SymbolGenerator::PreVisit(With &with) {
|
||||
// only those established through named expressions. New declarations must not
|
||||
// be visible inside named expressions themselves.
|
||||
scope_.symbols.clear();
|
||||
for (auto &named_expr : with.named_expressions_) {
|
||||
// Improvement would be to infer the type of the expression.
|
||||
symbol_table_[*named_expr] = CreateSymbol(named_expr->name_);
|
||||
}
|
||||
BindNamedExpressionSymbols(with.named_expressions_);
|
||||
if (with.where_) with.where_->Accept(*this);
|
||||
return false; // We handled the traversal ourselves.
|
||||
}
|
||||
|
@ -76,6 +76,9 @@ class SymbolGenerator : public TreeVisitorBase {
|
||||
auto GetOrCreateSymbol(const std::string &name,
|
||||
Symbol::Type type = Symbol::Type::Any);
|
||||
|
||||
void BindNamedExpressionSymbols(
|
||||
const std::vector<NamedExpression *> &named_expressions);
|
||||
|
||||
SymbolTable &symbol_table_;
|
||||
Scope scope_;
|
||||
};
|
||||
|
@ -534,4 +534,25 @@ TEST(TestSymbolGenerator, MatchWithCreate) {
|
||||
EXPECT_EQ(m, symbol_table.at(*node_3->identifier_));
|
||||
}
|
||||
|
||||
TEST(TestSymbolGenerator, SameResults) {
|
||||
// Test MATCH (n) WITH n AS m, n AS m
|
||||
{
|
||||
AstTreeStorage storage;
|
||||
auto query = QUERY(MATCH(PATTERN(NODE("n"))),
|
||||
WITH(IDENT("n"), AS("m"), IDENT("n"), AS("m")));
|
||||
SymbolTable symbol_table;
|
||||
SymbolGenerator symbol_generator(symbol_table);
|
||||
EXPECT_THROW(query->Accept(symbol_generator), SemanticException);
|
||||
}
|
||||
// Test MATCH (n) RETURN n, n
|
||||
{
|
||||
AstTreeStorage storage;
|
||||
auto query = QUERY(MATCH(PATTERN(NODE("n"))),
|
||||
RETURN(IDENT("n"), AS("n"), IDENT("n"), AS("n")));
|
||||
SymbolTable symbol_table;
|
||||
SymbolGenerator symbol_generator(symbol_table);
|
||||
EXPECT_THROW(query->Accept(symbol_generator), SemanticException);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user