Add AstTreeStorage

Reviewers: teon.banek

Reviewed By: teon.banek

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D134
This commit is contained in:
Mislav Bradac 2017-03-16 15:00:34 +01:00
parent baa644e9b7
commit 0db7883670
10 changed files with 226 additions and 185 deletions

View File

@ -3,8 +3,8 @@
namespace query {
std::shared_ptr<Query> HighLevelAstConversion::Apply(Context &ctx,
antlr4::tree::ParseTree *tree) {
Query *HighLevelAstConversion::Apply(Context &ctx,
antlr4::tree::ParseTree *tree) {
query::frontend::CypherMainVisitor visitor(ctx);
visitor.visit(tree);
return visitor.query();

View File

@ -27,11 +27,8 @@ class Context {
public:
Context(Config config, GraphDbAccessor &db_accessor)
: config_(config), db_accessor_(db_accessor) {}
int next_uid() { return uid_counter_++; }
Config config_;
GraphDbAccessor &db_accessor_;
int uid_counter_ = 0;
};
class LogicalPlanner {
@ -49,6 +46,6 @@ private:
class HighLevelAstConversion {
public:
std::shared_ptr<Query> Apply(Context &ctx, antlr4::tree::ParseTree *tree);
Query *Apply(Context &ctx, antlr4::tree::ParseTree *tree);
};
}

View File

@ -9,43 +9,45 @@
namespace query {
class AstTreeStorage;
class Tree : public ::utils::Visitable<TreeVisitorBase> {
public:
Tree(int uid) : uid_(uid) {}
friend class AstTreeStorage;
public:
int uid() const { return uid_; }
protected:
Tree(int uid) : uid_(uid) {}
private:
const int uid_;
};
class Expression : public Tree {
public:
protected:
Expression(int uid) : Tree(uid) {}
};
class Identifier : public Expression {
friend class AstTreeStorage;
public:
Identifier(int uid, const std::string &name) : Expression(uid), name_(name) {}
DEFVISITABLE(TreeVisitorBase)
DEFVISITABLE(TreeVisitorBase);
std::string name_;
protected:
Identifier(int uid, const std::string &name) : Expression(uid), name_(name) {}
};
class PropertyLookup : public Expression {
friend class AstTreeStorage;
public:
PropertyLookup(int uid, std::shared_ptr<Expression> expression,
GraphDb::Property property)
: Expression(uid), expression_(expression), property_(property) {}
void Accept(TreeVisitorBase &visitor) override {
visitor.Visit(*this);
expression_->Accept(visitor);
visitor.PostVisit(*this);
}
std::shared_ptr<Expression>
expression_; // vertex or edge, what if map literal???
Expression *expression_;
GraphDb::Property property_;
// TODO potential problem: property lookups are allowed on both map literals
// and records, but map literals have strings as keys and records have
@ -53,11 +55,16 @@ class PropertyLookup : public Expression {
//
// possible solution: store both string and GraphDb::Property here and choose
// between the two depending on Expression result
protected:
PropertyLookup(int uid, Expression* expression,
GraphDb::Property property)
: Expression(uid), expression_(expression), property_(property) {}
};
class NamedExpression : public Tree {
friend class AstTreeStorage;
public:
NamedExpression(int uid) : Tree(uid) {}
void Accept(TreeVisitorBase &visitor) override {
visitor.Visit(*this);
expression_->Accept(visitor);
@ -65,33 +72,45 @@ class NamedExpression : public Tree {
}
std::string name_;
std::shared_ptr<Expression> expression_;
Expression* expression_;
protected:
NamedExpression(int uid) : Tree(uid) {}
NamedExpression(int uid, std::string name, Expression *expression) :
Tree(uid), name_(name), expression_(expression) {}
};
class PatternAtom : public Tree {
public:
friend class AstTreeStorage;
protected:
PatternAtom(int uid) : Tree(uid) {}
};
class NodeAtom : public PatternAtom {
friend class AstTreeStorage;
public:
NodeAtom(int uid) : PatternAtom(uid) {}
void Accept(TreeVisitorBase &visitor) override {
visitor.Visit(*this);
identifier_->Accept(visitor);
visitor.PostVisit(*this);
}
std::shared_ptr<Identifier> identifier_;
Identifier* identifier_;
std::vector<GraphDb::Label> labels_;
std::map<GraphDb::Property, std::shared_ptr<Expression>> properties_;
std::map<GraphDb::Property, Expression*> properties_;
protected:
NodeAtom(int uid) : PatternAtom(uid) {}
NodeAtom(int uid, Identifier *identifier) :
PatternAtom(uid), identifier_(identifier) {}
};
class EdgeAtom : public PatternAtom {
friend class AstTreeStorage;
public:
enum class Direction { LEFT, RIGHT, BOTH };
EdgeAtom(int uid) : PatternAtom(uid) {}
void Accept(TreeVisitorBase &visitor) override {
visitor.Visit(*this);
identifier_->Accept(visitor);
@ -99,17 +118,21 @@ class EdgeAtom : public PatternAtom {
}
Direction direction = Direction::BOTH;
std::shared_ptr<Identifier> identifier_;
Identifier* identifier_;
protected:
EdgeAtom(int uid) : PatternAtom(uid) {}
};
class Clause : public Tree {
friend class AstTreeStorage;
public:
Clause(int uid) : Tree(uid) {}
};
class Pattern : public Tree {
friend class AstTreeStorage;
public:
Pattern(int uid) : Tree(uid) {}
void Accept(TreeVisitorBase &visitor) override {
visitor.Visit(*this);
for (auto &part : atoms_) {
@ -117,13 +140,16 @@ class Pattern : public Tree {
}
visitor.PostVisit(*this);
}
std::shared_ptr<Identifier> identifier_;
std::vector<std::shared_ptr<PatternAtom>> atoms_;
Identifier* identifier_;
std::vector<PatternAtom*> atoms_;
protected:
Pattern(int uid) : Tree(uid) {}
};
class Query : public Tree {
friend class AstTreeStorage;
public:
Query(int uid) : Tree(uid) {}
void Accept(TreeVisitorBase &visitor) override {
visitor.Visit(*this);
for (auto &clause : clauses_) {
@ -131,7 +157,10 @@ class Query : public Tree {
}
visitor.PostVisit(*this);
}
std::vector<std::shared_ptr<Clause>> clauses_;
std::vector<Clause*> clauses_;
protected:
Query(int uid) : Tree(uid) {}
};
class Create : public Clause {
@ -148,9 +177,9 @@ class Create : public Clause {
};
class Match : public Clause {
friend class AstTreeStorage;
public:
Match(int uid) : Clause(uid) {}
std::vector<std::shared_ptr<Pattern>> patterns_;
std::vector<Pattern*> patterns_;
void Accept(TreeVisitorBase &visitor) override {
visitor.Visit(*this);
for (auto &pattern : patterns_) {
@ -158,11 +187,14 @@ class Match : public Clause {
}
visitor.PostVisit(*this);
}
protected:
Match(int uid) : Clause(uid) {}
};
class Return : public Clause {
friend class AstTreeStorage;
public:
Return(int uid) : Clause(uid) {}
void Accept(TreeVisitorBase &visitor) override {
visitor.Visit(*this);
for (auto &expr : named_expressions_) {
@ -170,6 +202,39 @@ class Return : public Clause {
}
visitor.PostVisit(*this);
}
std::vector<std::shared_ptr<NamedExpression>> named_expressions_;
std::vector<NamedExpression*> named_expressions_;
protected:
Return(int uid) : Clause(uid) {}
};
// It would be better to call this AstTree, but we already have a class Tree,
// which could be renamed to Node or AstTreeNode, but we also have a class
// called NodeAtom...
class AstTreeStorage {
friend class AstTreeStorage;
public:
AstTreeStorage() {
storage_.emplace_back(new Query(next_uid_++));
}
AstTreeStorage(const AstTreeStorage &) = delete;
AstTreeStorage &operator=(const AstTreeStorage &) = delete;
template<typename T, typename... Args>
T *Create(Args&&... args) {
// Never call create for a Query. Call query() instead.
static_assert(!std::is_same<T, Query>::value, "Call query() instead");
// TODO: use std::forward here
T *p = new T(next_uid_++, args...);
storage_.emplace_back(p);
return p;
}
Query *query() { return dynamic_cast<Query*>(storage_[0].get()); }
private:
int next_uid_ = 0;
std::vector<std::unique_ptr<Tree>> storage_;
};
}

View File

@ -41,10 +41,9 @@ namespace {
antlrcpp::Any
CypherMainVisitor::visitSingleQuery(CypherParser::SingleQueryContext *ctx) {
query_ = std::make_shared<Query>(ctx_.next_uid());
query_ = storage_.query();
for (auto *child : ctx->clause()) {
query_->clauses_.push_back(
child->accept(this).as<std::shared_ptr<Clause>>());
query_->clauses_.push_back(child->accept(this));
}
return query_;
}
@ -52,18 +51,17 @@ antlrcpp::Any CypherMainVisitor::visitClause(CypherParser::ClauseContext *ctx) {
if (!ctx->cypherReturn() && !ctx->cypherMatch()) {
throw std::exception();
}
return 0;
return visitChildren(ctx);
}
antlrcpp::Any
CypherMainVisitor::visitCypherMatch(CypherParser::CypherMatchContext *ctx) {
auto match = std::make_shared<Match>(ctx_.next_uid());
auto *match = storage_.Create<Match>();
if (ctx->OPTIONAL() || ctx->where()) {
throw std::exception();
}
match->patterns_ =
ctx->pattern()->accept(this).as<std::vector<std::shared_ptr<Pattern>>>();
return std::shared_ptr<Clause>(match);
match->patterns_ = ctx->pattern()->accept(this).as<std::vector<Pattern *>>();
return match;
}
antlrcpp::Any
@ -84,22 +82,22 @@ CypherMainVisitor::visitReturnBody(CypherParser::ReturnBodyContext *ctx) {
antlrcpp::Any
CypherMainVisitor::visitReturnItems(CypherParser::ReturnItemsContext *ctx) {
auto return_clause = std::make_shared<Return>(ctx_.next_uid());
auto *return_clause = storage_.Create<Return>();
if (ctx->getTokens(kReturnAllTokenId).size()) {
throw std::exception();
}
for (auto *item : ctx->returnItem()) {
return_clause->named_expressions_.push_back(item->accept(this));
}
return std::shared_ptr<Clause>(return_clause);
return return_clause;
}
antlrcpp::Any
CypherMainVisitor::visitReturnItem(CypherParser::ReturnItemContext *ctx) {
auto named_expr = std::make_shared<NamedExpression>(ctx_.next_uid());
auto *named_expr = storage_.Create<NamedExpression>();
if (ctx->variable()) {
named_expr->name_ =
std::string(ctx_.next_uid(), ctx->variable()->accept(this));
std::string(ctx->variable()->accept(this).as<std::string>());
} else {
// TODO: Should we get this by text or some escaping is needed?
named_expr->name_ = std::string(ctx->getText());
@ -110,16 +108,16 @@ CypherMainVisitor::visitReturnItem(CypherParser::ReturnItemContext *ctx) {
antlrcpp::Any
CypherMainVisitor::visitNodePattern(CypherParser::NodePatternContext *ctx) {
auto node = std::make_shared<NodeAtom>(ctx_.next_uid());
auto *node = storage_.Create<NodeAtom>();
if (ctx->variable()) {
// TODO: user's identifiers should be unchanged, but we must be sure that
// ours identifier is not in a clash with user's.
std::string variable = ctx->variable()->accept(this);
node->identifier_ = std::make_shared<Identifier>(
ctx_.next_uid(), kUserIdentPrefix + variable);
node->identifier_ =
storage_.Create<Identifier>(kUserIdentPrefix + variable);
} else {
node->identifier_ = std::make_shared<Identifier>(
ctx_.next_uid(), kAnonIdentPrefix + std::to_string(next_ident_id_++));
node->identifier_ = storage_.Create<Identifier>(
kAnonIdentPrefix + std::to_string(next_ident_id_++));
}
if (ctx->nodeLabels()) {
std::vector<std::string> labels = ctx->nodeLabels()->accept(this);
@ -135,7 +133,7 @@ CypherMainVisitor::visitNodePattern(CypherParser::NodePatternContext *ctx) {
// .as<std::unordered_map<std::string,
// std::string>>();
}
return std::shared_ptr<PatternAtom>(node);
return node;
}
antlrcpp::Any
@ -184,7 +182,7 @@ CypherMainVisitor::visitSymbolicName(CypherParser::SymbolicNameContext *ctx) {
antlrcpp::Any
CypherMainVisitor::visitPattern(CypherParser::PatternContext *ctx) {
std::vector<std::shared_ptr<Pattern>> patterns;
std::vector<Pattern *> patterns;
for (auto *pattern_part : ctx->patternPart()) {
patterns.push_back(pattern_part->accept(this));
}
@ -193,15 +191,15 @@ CypherMainVisitor::visitPattern(CypherParser::PatternContext *ctx) {
antlrcpp::Any
CypherMainVisitor::visitPatternPart(CypherParser::PatternPartContext *ctx) {
std::shared_ptr<Pattern> pattern = ctx->anonymousPatternPart()->accept(this);
Pattern *pattern = ctx->anonymousPatternPart()->accept(this);
if (ctx->variable()) {
// TODO: don't change user's identifier name.
std::string variable = ctx->variable()->accept(this);
pattern->identifier_ = std::make_shared<Identifier>(
ctx_.next_uid(), kUserIdentPrefix + variable);
pattern->identifier_ =
storage_.Create<Identifier>(kUserIdentPrefix + variable);
} else {
pattern->identifier_ = std::make_shared<Identifier>(
ctx_.next_uid(), kAnonIdentPrefix + std::to_string(next_ident_id_++));
pattern->identifier_ = storage_.Create<Identifier>(
kAnonIdentPrefix + std::to_string(next_ident_id_++));
}
return pattern;
}
@ -211,11 +209,11 @@ antlrcpp::Any CypherMainVisitor::visitPatternElement(
if (ctx->patternElement()) {
return ctx->patternElement()->accept(this);
}
auto pattern = std::make_shared<Pattern>(ctx_.next_uid());
auto pattern = storage_.Create<Pattern>();
pattern->atoms_.push_back(ctx->nodePattern()->accept(this));
for (auto *pattern_element_chain : ctx->patternElementChain()) {
std::pair<std::shared_ptr<PatternAtom>, std::shared_ptr<PatternAtom>>
element = pattern_element_chain->accept(this);
std::pair<PatternAtom *, PatternAtom *> element =
pattern_element_chain->accept(this);
pattern->atoms_.push_back(element.first);
pattern->atoms_.push_back(element.second);
}
@ -224,23 +222,21 @@ antlrcpp::Any CypherMainVisitor::visitPatternElement(
antlrcpp::Any CypherMainVisitor::visitPatternElementChain(
CypherParser::PatternElementChainContext *ctx) {
return std::pair<std::shared_ptr<PatternAtom>, std::shared_ptr<PatternAtom>>(
ctx->relationshipPattern()
->accept(this)
.as<std::shared_ptr<PatternAtom>>(),
ctx->nodePattern()->accept(this).as<std::shared_ptr<PatternAtom>>());
return std::pair<PatternAtom *, PatternAtom *>(
ctx->relationshipPattern()->accept(this),
ctx->nodePattern()->accept(this));
}
antlrcpp::Any CypherMainVisitor::visitRelationshipPattern(
CypherParser::RelationshipPatternContext *ctx) {
auto edge = std::make_shared<EdgeAtom>(ctx_.next_uid());
auto *edge = storage_.Create<EdgeAtom>();
if (ctx->relationshipDetail()) {
if (ctx->relationshipDetail()->variable()) {
std::string variable =
ctx->relationshipDetail()->variable()->accept(this);
// TODO: Don't change user's identifier name.
edge->identifier_ = std::make_shared<Identifier>(
ctx_.next_uid(), kUserIdentPrefix + variable);
edge->identifier_ =
storage_.Create<Identifier>(kUserIdentPrefix + variable);
}
if (ctx->relationshipDetail()->relationshipTypes()) {
throw std::exception();
@ -260,8 +256,8 @@ antlrcpp::Any CypherMainVisitor::visitRelationshipPattern(
// relationship.lower_bound = range.first;
// relationship.upper_bound = range.second;
if (!edge->identifier_) {
edge->identifier_ = std::make_shared<Identifier>(
ctx_.next_uid(), kAnonIdentPrefix + std::to_string(next_ident_id_++));
edge->identifier_ = storage_.Create<Identifier>(
kAnonIdentPrefix + std::to_string(next_ident_id_++));
}
if (ctx->leftArrowHead() && !ctx->rightArrowHead()) {
@ -273,7 +269,7 @@ antlrcpp::Any CypherMainVisitor::visitRelationshipPattern(
// grammar.
edge->direction = EdgeAtom::Direction::BOTH;
}
return std::shared_ptr<PatternAtom>(edge);
return edge;
}
antlrcpp::Any CypherMainVisitor::visitRelationshipDetail(
@ -550,8 +546,7 @@ antlrcpp::Any CypherMainVisitor::visitAtom(CypherParser::AtomContext *ctx) {
return ctx->parenthesizedExpression()->accept(this);
} else if (ctx->variable()) {
std::string variable = ctx->variable()->accept(this);
return std::shared_ptr<Expression>(std::make_shared<Identifier>(
ctx_.next_uid(), kUserIdentPrefix + variable));
return storage_.Create<Identifier>(kUserIdentPrefix + variable);
}
// TODO: Implement this. We don't support comprehensions, functions,
// filtering... at the moment.

View File

@ -289,14 +289,15 @@ private:
visitIntegerLiteral(CypherParser::IntegerLiteralContext *ctx) override;
public:
std::shared_ptr<Query> query() { return query_; }
Query *query() { return query_; }
private:
Context &ctx_;
int next_ident_id_;
const std::string kUserIdentPrefix = "u_";
const std::string kAnonIdentPrefix = "a_";
std::shared_ptr<Query> query_;
AstTreeStorage storage_;
Query *query_;
};
}
}

View File

@ -29,7 +29,7 @@ class LogicalOperator {
class CreateOp : public LogicalOperator {
public:
CreateOp(std::shared_ptr<NodeAtom> node_atom) : node_atom_(node_atom) {}
CreateOp(NodeAtom* node_atom) : node_atom_(node_atom) {}
private:
class CreateOpCursor : public Cursor {
@ -66,12 +66,12 @@ public:
}
private:
std::shared_ptr<NodeAtom> node_atom_;
NodeAtom* node_atom_;
};
class ScanAll : public LogicalOperator {
public:
ScanAll(std::shared_ptr<NodeAtom> node_atom) : node_atom_(node_atom) {}
ScanAll(NodeAtom *node_atom) : node_atom_(node_atom) {}
private:
class ScanAllCursor : public Cursor {
@ -99,7 +99,7 @@ class ScanAll : public LogicalOperator {
}
private:
std::shared_ptr<NodeAtom> node_atom_;
NodeAtom *node_atom_;
};
class NodeFilter : public LogicalOperator {
@ -107,7 +107,7 @@ class NodeFilter : public LogicalOperator {
NodeFilter(
std::shared_ptr<LogicalOperator> input, Symbol input_symbol,
std::vector<GraphDb::Label> labels,
std::map<GraphDb::Property, std::shared_ptr<Expression>> properties)
std::map<GraphDb::Property, Expression*> properties)
: input_(input),
input_symbol_(input_symbol),
labels_(labels),
@ -158,13 +158,13 @@ class NodeFilter : public LogicalOperator {
std::shared_ptr<LogicalOperator> input_;
const Symbol input_symbol_;
std::vector<GraphDb::Label> labels_;
std::map<GraphDb::Property, std::shared_ptr<Expression>> properties_;
std::map<GraphDb::Property, Expression*> properties_;
};
class Produce : public LogicalOperator {
public:
Produce(std::shared_ptr<LogicalOperator> input,
std::vector<std::shared_ptr<NamedExpression>> named_expressions)
std::vector<NamedExpression*> named_expressions)
: input_(input), named_expressions_(named_expressions) {
children_.emplace_back(input);
}
@ -198,6 +198,6 @@ class Produce : public LogicalOperator {
private:
std::shared_ptr<LogicalOperator> input_;
std::vector<std::shared_ptr<NamedExpression>> named_expressions_;
std::vector<NamedExpression*> named_expressions_;
};
}

View File

@ -5,6 +5,8 @@
namespace query {
namespace {
static LogicalOperator *GenCreate(
Create& create, std::shared_ptr<LogicalOperator> input_op)
{
@ -18,11 +20,11 @@ static LogicalOperator *GenCreate(
if (pattern->atoms_.size() != 1) {
throw NotYetImplemented();
}
auto node_atom = std::dynamic_pointer_cast<NodeAtom>(pattern->atoms_[0]);
auto *node_atom = dynamic_cast<NodeAtom*>(pattern->atoms_[0]);
return new CreateOp(node_atom);
}
static LogicalOperator *GenMatch(
LogicalOperator *GenMatch(
Match& match,
std::shared_ptr<LogicalOperator> input_op,
const SymbolTable &symbol_table)
@ -37,7 +39,7 @@ static LogicalOperator *GenMatch(
if (pattern->atoms_.size() != 1) {
throw NotYetImplemented();
}
auto node_atom = std::dynamic_pointer_cast<NodeAtom>(pattern->atoms_[0]);
auto *node_atom = dynamic_cast<NodeAtom*>(pattern->atoms_[0]);
auto *scan_all = new ScanAll(node_atom);
if (!node_atom->labels_.empty() || !node_atom->properties_.empty()) {
auto &input_symbol = symbol_table.at(*node_atom->identifier_);
@ -47,20 +49,21 @@ static LogicalOperator *GenMatch(
return scan_all;
}
static Produce *GenReturn(Return& ret, std::shared_ptr<LogicalOperator> input_op)
Produce *GenReturn(Return& ret, std::shared_ptr<LogicalOperator> input_op)
{
if (!input_op) {
throw NotYetImplemented();
}
return new Produce(input_op, ret.named_expressions_);
}
}
std::unique_ptr<LogicalOperator> MakeLogicalPlan(
Query& query, const SymbolTable &symbol_table)
{
LogicalOperator *input_op = nullptr;
for (auto &clause : query.clauses_) {
auto *clause_ptr = clause.get();
auto *clause_ptr = clause;
if (auto *match = dynamic_cast<Match*>(clause_ptr)) {
input_op = GenMatch(*match, std::shared_ptr<LogicalOperator>(input_op),
symbol_table);

View File

@ -12,7 +12,6 @@ class SymbolTable;
// Returns the root of LogicalOperator tree. The tree is constructed by
// traversing the given AST Query node. SymbolTable is used to determine inputs
// and outputs of certain operators.
std::unique_ptr<LogicalOperator> MakeLogicalPlan(
Query& query, const SymbolTable &symbol_table);
std::unique_ptr<LogicalOperator>
MakeLogicalPlan(Query &query, const SymbolTable &symbol_table);
}

View File

@ -46,7 +46,8 @@ auto CollectProduce(std::shared_ptr<Produce> produce, SymbolTable &symbol_table,
auto cursor = produce->MakeCursor(db_accessor);
while (cursor->Pull(frame, symbol_table)) {
std::vector<TypedValue> values;
for (auto &symbol : symbols) values.emplace_back(frame[symbol]);
for (auto &symbol : symbols)
values.emplace_back(frame[symbol]);
stream.Result(values);
}
@ -59,34 +60,12 @@ void ExecuteCreate(std::shared_ptr<CreateOp> create, GraphDbAccessor &db) {
SymbolTable symbol_table;
Frame frame(symbol_table.max_position());
auto cursor = create->MakeCursor(db);
while (cursor->Pull(frame, symbol_table))
;
while (cursor->Pull(frame, symbol_table)) {
continue;
}
}
/*
* Following are helper functions that create high level AST
* and logical operator objects.
*/
auto MakeNamedExpression(Context &ctx, const std::string name,
std::shared_ptr<Expression> expression) {
auto named_expression = std::make_shared<NamedExpression>(ctx.next_uid());
named_expression->name_ = name;
named_expression->expression_ = expression;
return named_expression;
}
auto MakeIdentifier(Context &ctx, const std::string name) {
return std::make_shared<Identifier>(ctx.next_uid(), name);
}
auto MakeNode(Context &ctx, std::shared_ptr<Identifier> identifier) {
auto node = std::make_shared<NodeAtom>(ctx.next_uid());
node->identifier_ = identifier;
return node;
}
auto MakeScanAll(std::shared_ptr<NodeAtom> node_atom) {
auto MakeScanAll(NodeAtom *node_atom) {
return std::make_shared<ScanAll>(node_atom);
}
@ -94,8 +73,7 @@ template <typename... TNamedExpressions>
auto MakeProduce(std::shared_ptr<LogicalOperator> input,
TNamedExpressions... named_expressions) {
return std::make_shared<Produce>(
input,
std::vector<std::shared_ptr<NamedExpression>>{named_expressions...});
input, std::vector<NamedExpression *>{named_expressions...});
}
/*
@ -110,15 +88,15 @@ TEST(Interpreter, MatchReturn) {
dba->insert_vertex();
dba->insert_vertex();
Config config;
Context ctx(config, *dba);
AstTreeStorage storage;
// make a scan all
auto node = MakeNode(ctx, MakeIdentifier(ctx, "n"));
auto node = storage.Create<NodeAtom>(storage.Create<Identifier>("n"));
auto scan_all = MakeScanAll(node);
// make a named expression and a produce
auto output = MakeNamedExpression(ctx, "n", MakeIdentifier(ctx, "n"));
auto output =
storage.Create<NamedExpression>("n", storage.Create<Identifier>("n"));
auto produce = MakeProduce(scan_all, output);
// fill up the symbol table
@ -156,11 +134,10 @@ TEST(Interpreter, NodeFilterLabelsAndProperties) {
v4.PropsSet(property, 42);
v5.PropsSet(property, 1);
Config config;
Context ctx(config, *dba);
AstTreeStorage storage;
// make a scan all
auto node = MakeNode(ctx, MakeIdentifier(ctx, "n"));
auto node = storage.Create<NodeAtom>(storage.Create<Identifier>("n"));
auto scan_all = MakeScanAll(node);
// node filtering
@ -169,10 +146,11 @@ TEST(Interpreter, NodeFilterLabelsAndProperties) {
// TODO implement the test once int-literal expressions are available
auto node_filter = std::make_shared<NodeFilter>(
scan_all, n_symbol, std::vector<GraphDb::Label>{label},
std::map<GraphDb::Property, std::shared_ptr<Expression>>());
std::map<GraphDb::Property, Expression*>{});
// make a named expression and a produce
auto output = MakeNamedExpression(ctx, "n", MakeIdentifier(ctx, "n"));
auto output =
storage.Create<NamedExpression>("x", storage.Create<Identifier>("n"));
auto produce = MakeProduce(node_filter, output);
// fill up the symbol table
@ -193,26 +171,25 @@ TEST(Interpreter, NodeFilterMultipleLabels) {
GraphDb::Label label2 = dba->label("label2");
GraphDb::Label label3 = dba->label("label3");
// the test will look for nodes that have label1 and label2
dba->insert_vertex(); // NOT accepted
dba->insert_vertex().add_label(label1); // NOT accepted
dba->insert_vertex().add_label(label2); // NOT accepted
dba->insert_vertex().add_label(label3); // NOT accepted
auto v1 = dba->insert_vertex(); // YES accepted
dba->insert_vertex(); // NOT accepted
dba->insert_vertex().add_label(label1); // NOT accepted
dba->insert_vertex().add_label(label2); // NOT accepted
dba->insert_vertex().add_label(label3); // NOT accepted
auto v1 = dba->insert_vertex(); // YES accepted
v1.add_label(label1);
v1.add_label(label2);
auto v2 = dba->insert_vertex(); // NOT accepted
auto v2 = dba->insert_vertex(); // NOT accepted
v2.add_label(label1);
v2.add_label(label3);
auto v3 = dba->insert_vertex(); // YES accepted
auto v3 = dba->insert_vertex(); // YES accepted
v3.add_label(label1);
v3.add_label(label2);
v3.add_label(label3);
Config config;
Context ctx(config, *dba);
AstTreeStorage storage;
// make a scan all
auto node = MakeNode(ctx, MakeIdentifier(ctx, "n"));
auto node = storage.Create<NodeAtom>(storage.Create<Identifier>("n"));
auto scan_all = MakeScanAll(node);
// node filtering
@ -221,10 +198,11 @@ TEST(Interpreter, NodeFilterMultipleLabels) {
// TODO implement the test once int-literal expressions are available
auto node_filter = std::make_shared<NodeFilter>(
scan_all, n_symbol, std::vector<GraphDb::Label>{label1, label2},
std::map<GraphDb::Property, std::shared_ptr<Expression>>());
std::map<GraphDb::Property, Expression *>());
// make a named expression and a produce
auto output = MakeNamedExpression(ctx, "n", MakeIdentifier(ctx, "n"));
auto output =
storage.Create<NamedExpression>("n", storage.Create<Identifier>("n"));
auto produce = MakeProduce(node_filter, output);
// fill up the symbol table
@ -239,13 +217,13 @@ TEST(Interpreter, NodeFilterMultipleLabels) {
TEST(Interpreter, CreateNodeWithAttributes) {
Dbms dbms;
auto dba = dbms.active();
Config config;
Context ctx(config, *dba);
GraphDb::Label label = dba->label("Person");
GraphDb::Property property = dba->label("age");
auto node = MakeNode(ctx, MakeIdentifier(ctx, "n"));
AstTreeStorage storage;
auto node = storage.Create<NodeAtom>(storage.Create<Identifier>("n"));
node->labels_.emplace_back(label);
// TODO make a property here with an int literal expression
// node->properties_[property] = TypedValue(42);

View File

@ -9,23 +9,24 @@
using namespace query;
namespace {
// Build a simple AST which describes:
// MATCH (node_atom_1) RETURN node_atom_1 AS node_atom_1
static std::unique_ptr<Query> MatchNodeReturn() {
int uid = 0;
auto node_atom = std::make_shared<NodeAtom>(uid++);
node_atom->identifier_ = std::make_shared<Identifier>(uid++, "node_atom_1");
auto pattern = std::make_shared<Pattern>(uid++);
Query *MatchNodeReturn(AstTreeStorage &storage) {
auto node_atom = storage.Create<NodeAtom>();
node_atom->identifier_ = storage.Create<Identifier>("node_atom_1");
auto pattern = storage.Create<Pattern>();
pattern->atoms_.emplace_back(node_atom);
auto match = std::make_shared<Match>(uid++);
auto match = storage.Create<Match>();
match->patterns_.emplace_back(pattern);
auto query = std::make_unique<Query>(uid++);
auto query = storage.query();
query->clauses_.emplace_back(match);
auto named_expr = std::make_shared<NamedExpression>(uid++);
auto named_expr = storage.Create<NamedExpression>();
named_expr->name_ = "node_atom_1";
named_expr->expression_ = std::make_shared<Identifier>(uid++, "node_atom_1");
auto ret = std::make_shared<Return>(uid++);
named_expr->expression_ = storage.Create<Identifier>("node_atom_1");
auto ret = storage.Create<Return>();
ret->named_expressions_.emplace_back(named_expr);
query->clauses_.emplace_back(ret);
return query;
@ -34,24 +35,23 @@ static std::unique_ptr<Query> MatchNodeReturn() {
// AST using variable in return bound by naming the previous return expression.
// This is treated as an unbound variable.
// MATCH (node_atom_1) RETURN node_atom_1 AS n, n AS n
static std::unique_ptr<Query> MatchUnboundMultiReturn() {
int uid = 0;
auto node_atom = std::make_shared<NodeAtom>(uid++);
node_atom->identifier_ = std::make_shared<Identifier>(uid++, "node_atom_1");
auto pattern = std::make_shared<Pattern>(uid++);
Query *MatchUnboundMultiReturn(AstTreeStorage &storage) {
auto node_atom = storage.Create<NodeAtom>();
node_atom->identifier_ = storage.Create<Identifier>("node_atom_1");
auto pattern = storage.Create<Pattern>();
pattern->atoms_.emplace_back(node_atom);
auto match = std::make_shared<Match>(uid++);
auto match = storage.Create<Match>();
match->patterns_.emplace_back(pattern);
auto query = std::make_unique<Query>(uid++);
auto query = storage.query();
query->clauses_.emplace_back(match);
auto named_expr_1 = std::make_shared<NamedExpression>(uid++);
auto named_expr_1 = storage.Create<NamedExpression>();
named_expr_1->name_ = "n";
named_expr_1->expression_ = std::make_shared<Identifier>(uid++, "node_atom_1");
auto named_expr_2 = std::make_shared<NamedExpression>(uid++);
named_expr_1->expression_ = storage.Create<Identifier>("node_atom_1");
auto named_expr_2 = storage.Create<NamedExpression>();
named_expr_2->name_ = "n";
named_expr_2->expression_ = std::make_shared<Identifier>(uid++, "n");
auto ret = std::make_shared<Return>(uid++);
named_expr_2->expression_ = storage.Create<Identifier>("n");
auto ret = storage.Create<Return>();
ret->named_expressions_.emplace_back(named_expr_1);
ret->named_expressions_.emplace_back(named_expr_2);
query->clauses_.emplace_back(ret);
@ -59,21 +59,20 @@ static std::unique_ptr<Query> MatchUnboundMultiReturn() {
}
// AST with unbound variable in return: MATCH (n) RETURN x AS x
static std::unique_ptr<Query> MatchNodeUnboundReturn() {
int uid = 0;
auto node_atom = std::make_shared<NodeAtom>(uid++);
node_atom->identifier_ = std::make_shared<Identifier>(uid++, "n");
auto pattern = std::make_shared<Pattern>(uid++);
Query *MatchNodeUnboundReturn(AstTreeStorage &storage) {
auto node_atom = storage.Create<NodeAtom>();
node_atom->identifier_ = storage.Create<Identifier>("n");
auto pattern = storage.Create<Pattern>();
pattern->atoms_.emplace_back(node_atom);
auto match = std::make_shared<Match>(uid++);
auto match = storage.Create<Match>();
match->patterns_.emplace_back(pattern);
auto query = std::make_unique<Query>(uid++);
auto query = storage.query();
query->clauses_.emplace_back(match);
auto named_expr = std::make_shared<NamedExpression>(uid++);
auto named_expr = storage.Create<NamedExpression>();
named_expr->name_ = "x";
named_expr->expression_ = std::make_shared<Identifier>(uid++, "x");
auto ret = std::make_shared<Return>(uid++);
named_expr->expression_ = storage.Create<Identifier>("x");
auto ret = storage.Create<Return>();
ret->named_expressions_.emplace_back(named_expr);
query->clauses_.emplace_back(ret);
return query;
@ -81,16 +80,17 @@ static std::unique_ptr<Query> MatchNodeUnboundReturn() {
TEST(TestSymbolGenerator, MatchNodeReturn) {
SymbolTable symbol_table;
auto query_ast = MatchNodeReturn();
AstTreeStorage storage;
auto query_ast = MatchNodeReturn(storage);
SymbolGenerator symbol_generator(symbol_table);
query_ast->Accept(symbol_generator);
EXPECT_EQ(symbol_table.max_position(), 2);
auto match = std::dynamic_pointer_cast<Match>(query_ast->clauses_[0]);
auto match = dynamic_cast<Match*>(query_ast->clauses_[0]);
auto pattern = match->patterns_[0];
auto node_atom = std::dynamic_pointer_cast<NodeAtom>(pattern->atoms_[0]);
auto node_atom = dynamic_cast<NodeAtom*>(pattern->atoms_[0]);
auto node_sym = symbol_table[*node_atom->identifier_];
EXPECT_EQ(node_sym.name_, "node_atom_1");
auto ret = std::dynamic_pointer_cast<Return>(query_ast->clauses_[1]);
auto ret = dynamic_cast<Return*>(query_ast->clauses_[1]);
auto named_expr = ret->named_expressions_[0];
auto column_sym = symbol_table[*named_expr];
EXPECT_EQ(node_sym.name_, column_sym.name_);
@ -101,14 +101,17 @@ TEST(TestSymbolGenerator, MatchNodeReturn) {
TEST(TestSymbolGenerator, MatchUnboundMultiReturn) {
SymbolTable symbol_table;
auto query_ast = MatchUnboundMultiReturn();
AstTreeStorage storage;
auto query_ast = MatchUnboundMultiReturn(storage);
SymbolGenerator symbol_generator(symbol_table);
EXPECT_THROW(query_ast->Accept(symbol_generator), SemanticException);
}
TEST(TestSymbolGenerator, MatchNodeUnboundReturn) {
SymbolTable symbol_table;
auto query_ast = MatchNodeUnboundReturn();
AstTreeStorage storage;
auto query_ast = MatchNodeUnboundReturn(storage);
SymbolGenerator symbol_generator(symbol_table);
EXPECT_THROW(query_ast->Accept(symbol_generator), SemanticException);
}
}