Query - entry.hpp renamed to interpreter.hpp, Engine renamed to Interpreter
Summary: Query - interpreter console hack Reviewers: buda, teon.banek, mislav.bradac Reviewed By: buda Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D157
This commit is contained in:
parent
8da6ce67c0
commit
b236694fd2
@ -351,7 +351,6 @@ set(memgraph_src_files
|
||||
${src_dir}/database/graph_db_accessor.cpp
|
||||
${src_dir}/query/stripper.cpp
|
||||
${src_dir}/query/frontend/ast/cypher_main_visitor.cpp
|
||||
${src_dir}/query/context.cpp
|
||||
${src_dir}/query/backend/cpp/typed_value.cpp
|
||||
${src_dir}/query/frontend/logical/planner.cpp
|
||||
)
|
||||
|
@ -26,6 +26,7 @@ constexpr const char *SNAPSHOTS_PATH = "snapshots_path";
|
||||
constexpr const char *CLEANING_CYCLE_SEC = "cleaning_cycle_sec";
|
||||
constexpr const char *SNAPSHOT_CYCLE_SEC = "snapshot_cycle_sec";
|
||||
constexpr const char *MAX_RETAINED_SNAPSHOTS = "max_retained_snapshots";
|
||||
constexpr const char *INTERPRET = "interpret";
|
||||
// -- all possible Memgraph's keys --
|
||||
|
||||
inline size_t to_int(std::string &&s) { return stoull(s); }
|
||||
|
@ -1,12 +0,0 @@
|
||||
#include "query/context.hpp"
|
||||
#include "query/frontend/ast/cypher_main_visitor.hpp"
|
||||
|
||||
namespace query {
|
||||
|
||||
Query *HighLevelAstConversion::Apply(Context &ctx,
|
||||
antlr4::tree::ParseTree *tree) {
|
||||
query::frontend::CypherMainVisitor visitor(ctx);
|
||||
visitor.visit(tree);
|
||||
return visitor.query();
|
||||
}
|
||||
}
|
@ -30,22 +30,4 @@ public:
|
||||
Config config_;
|
||||
GraphDbAccessor &db_accessor_;
|
||||
};
|
||||
|
||||
class LogicalPlanner {
|
||||
public:
|
||||
LogicalPlanner(Context ctx) : ctx_(ctx) {}
|
||||
|
||||
LogicalPlan Apply(TypedcheckedTree typedchecked_tree) {
|
||||
return ctx_.config_.logical_plan_generator.Generate(typedchecked_tree,
|
||||
ctx_)[0];
|
||||
}
|
||||
|
||||
private:
|
||||
Context ctx_;
|
||||
};
|
||||
|
||||
class HighLevelAstConversion {
|
||||
public:
|
||||
Query *Apply(Context &ctx, antlr4::tree::ParseTree *tree);
|
||||
};
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ namespace fs = std::experimental::filesystem;
|
||||
#include "query/plan_compiler.hpp"
|
||||
#include "query/plan_interface.hpp"
|
||||
#include "query/preprocessor.hpp"
|
||||
#include "query/interpreter.hpp"
|
||||
#include "utils/dynamic_lib.hpp"
|
||||
|
||||
/**
|
||||
@ -62,6 +63,12 @@ public:
|
||||
*/
|
||||
auto Run(const std::string &query, GraphDbAccessor &db_accessor,
|
||||
Stream &stream) {
|
||||
|
||||
if (CONFIG[config::INTERPRET]) {
|
||||
query::Interpret(query, db_accessor, stream);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto preprocessed = preprocessor.preprocess(query);
|
||||
auto plan = LoadCypher(preprocessed);
|
||||
auto result = plan->run(db_accessor, preprocessed.arguments, stream);
|
||||
|
@ -1,97 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
#include "query/context.hpp"
|
||||
#include "query/context.hpp"
|
||||
#include "query/frontend/interpret/interpret.hpp"
|
||||
#include "query/frontend/logical/planner.hpp"
|
||||
#include "query/frontend/opencypher/parser.hpp"
|
||||
#include "query/frontend/semantic/symbol_generator.hpp"
|
||||
|
||||
namespace query {
|
||||
|
||||
/**
|
||||
* A Stream implementation that writes out to the
|
||||
* console (for testing and debugging only).
|
||||
*/
|
||||
// TODO move somewhere to /test/manual or so
|
||||
class ConsoleResultStream : public Loggable {
|
||||
public:
|
||||
ConsoleResultStream() : Loggable("ConsoleResultStream") {}
|
||||
|
||||
void Header(const std::vector<std::string> &) { logger.info("header"); }
|
||||
|
||||
void Result(std::vector<TypedValue> &values) {
|
||||
for (auto value : values) {
|
||||
auto va = value.Value<VertexAccessor>();
|
||||
logger.info(" {}", va.labels().size());
|
||||
}
|
||||
}
|
||||
|
||||
void Summary(const std::map<std::string, TypedValue> &) {
|
||||
logger.info("summary");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Stream>
|
||||
class Engine {
|
||||
public:
|
||||
Engine() {}
|
||||
auto Execute(const std::string &query, GraphDbAccessor &db_accessor,
|
||||
Stream &stream) {
|
||||
Config config;
|
||||
Context ctx(config, db_accessor);
|
||||
|
||||
// query -> AST
|
||||
::frontend::opencypher::Parser parser(query);
|
||||
auto low_level_tree = parser.tree();
|
||||
|
||||
// AST -> high level tree
|
||||
HighLevelAstConversion low2high_tree;
|
||||
auto high_level_tree = low2high_tree.Apply(ctx, low_level_tree);
|
||||
Execute(*high_level_tree, db_accessor, stream);
|
||||
}
|
||||
|
||||
auto Execute(Query &query, GraphDbAccessor &db_accessor, Stream stream) {
|
||||
// symbol table fill
|
||||
SymbolTable symbol_table;
|
||||
SymbolGenerator symbol_generator(symbol_table);
|
||||
query.Accept(symbol_generator);
|
||||
|
||||
// high level tree -> logical plan
|
||||
auto logical_plan = MakeLogicalPlan(query, symbol_table);
|
||||
|
||||
// generate frame based on symbol table max_position
|
||||
Frame frame(symbol_table.max_position());
|
||||
|
||||
auto *produce = dynamic_cast<Produce *>(logical_plan.get());
|
||||
|
||||
if (produce) {
|
||||
// top level node in the operator tree is a produce (return)
|
||||
// so stream out results
|
||||
|
||||
// generate header
|
||||
std::vector<std::string> header;
|
||||
for (auto named_expression : produce->named_expressions())
|
||||
header.push_back(named_expression->name_);
|
||||
stream.Header(header);
|
||||
|
||||
// collect the symbols from the return clause
|
||||
std::vector<Symbol> symbols;
|
||||
for (auto named_expression : produce->named_expressions())
|
||||
symbols.emplace_back(symbol_table[*named_expression]);
|
||||
|
||||
// stream out results
|
||||
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]);
|
||||
stream.Result(values);
|
||||
}
|
||||
|
||||
stream.Summary({{std::string("type"), TypedValue("r")}});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
87
src/query/interpreter.hpp
Normal file
87
src/query/interpreter.hpp
Normal file
@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#include "database/graph_db_accessor.hpp"
|
||||
#include "query/context.hpp"
|
||||
#include "query/frontend/ast/cypher_main_visitor.hpp"
|
||||
#include "query/frontend/interpret/interpret.hpp"
|
||||
#include "query/frontend/logical/planner.hpp"
|
||||
#include "query/frontend/opencypher/parser.hpp"
|
||||
#include "query/frontend/semantic/symbol_generator.hpp"
|
||||
|
||||
namespace query {
|
||||
|
||||
template <typename Stream>
|
||||
void Interpret(const std::string &query, GraphDbAccessor &db_accessor,
|
||||
Stream &stream) {
|
||||
|
||||
clock_t start_time = clock();
|
||||
|
||||
Config config;
|
||||
Context ctx(config, db_accessor);
|
||||
std::map<std::string, TypedValue> summary;
|
||||
|
||||
// query -> AST
|
||||
::frontend::opencypher::Parser parser(query);
|
||||
auto low_level_tree = parser.tree();
|
||||
|
||||
// AST -> high level tree
|
||||
query::frontend::CypherMainVisitor visitor(ctx);
|
||||
visitor.visit(low_level_tree);
|
||||
auto high_level_tree = visitor.query();
|
||||
|
||||
// symbol table fill
|
||||
SymbolTable symbol_table;
|
||||
SymbolGenerator symbol_generator(symbol_table);
|
||||
high_level_tree->Accept(symbol_generator);
|
||||
|
||||
// high level tree -> logical plan
|
||||
auto logical_plan = MakeLogicalPlan(*high_level_tree, symbol_table);
|
||||
|
||||
// generate frame based on symbol table max_position
|
||||
Frame frame(symbol_table.max_position());
|
||||
|
||||
if (auto produce = dynamic_cast<Produce *>(logical_plan.get())) {
|
||||
// top level node in the operator tree is a produce (return)
|
||||
// so stream out results
|
||||
|
||||
// generate header
|
||||
std::vector<std::string> header;
|
||||
for (auto named_expression : produce->named_expressions())
|
||||
header.push_back(named_expression->name_);
|
||||
stream.Header(header);
|
||||
|
||||
// collect the symbols from the return clause
|
||||
std::vector<Symbol> symbols;
|
||||
for (auto named_expression : produce->named_expressions())
|
||||
symbols.emplace_back(symbol_table[*named_expression]);
|
||||
|
||||
// stream out results
|
||||
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]);
|
||||
stream.Result(values);
|
||||
}
|
||||
|
||||
summary["type"] = "r";
|
||||
} else if (auto create = dynamic_cast<CreateOp *>(logical_plan.get())) {
|
||||
auto cursor = create->MakeCursor(db_accessor);
|
||||
while (cursor->Pull(frame, symbol_table)) {
|
||||
continue;
|
||||
}
|
||||
} else if (auto create = dynamic_cast<CreateExpand *>(logical_plan.get())) {
|
||||
auto cursor = create->MakeCursor(db_accessor);
|
||||
while (cursor->Pull(frame, symbol_table)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
clock_t end_time = clock();
|
||||
double time_second = double(end_time - start_time) / CLOCKS_PER_SEC;
|
||||
summary["query_time_sec"] = TypedValue(time_second);
|
||||
stream.Summary(summary);
|
||||
|
||||
}
|
||||
}
|
@ -5,9 +5,9 @@
|
||||
#include "query/backend/cpp/typed_value.hpp"
|
||||
#include "storage/property_value_store.hpp"
|
||||
|
||||
#include "parameters.hpp"
|
||||
#include "utils/assert.hpp"
|
||||
#include "utils/hashing/fnv.hpp"
|
||||
#include "parameters.hpp"
|
||||
|
||||
/*
|
||||
* StrippedQuery contains:
|
||||
@ -16,10 +16,12 @@
|
||||
* * hash of stripped query
|
||||
*/
|
||||
struct StrippedQuery {
|
||||
StrippedQuery(const std::string &&query,
|
||||
const Parameters &arguments,
|
||||
HashType hash)
|
||||
: query(query), arguments(arguments), hash(hash) {}
|
||||
StrippedQuery(const std::string &unstripped_query, const std::string &&query,
|
||||
const Parameters &arguments, HashType hash)
|
||||
: unstripped_query(unstripped_query),
|
||||
query(query),
|
||||
arguments(arguments),
|
||||
hash(hash) {}
|
||||
|
||||
/**
|
||||
* Copy constructor is deleted because we don't want to make unnecessary
|
||||
@ -35,18 +37,15 @@ struct StrippedQuery {
|
||||
StrippedQuery(StrippedQuery &&other) = default;
|
||||
StrippedQuery &operator=(StrippedQuery &&other) = default;
|
||||
|
||||
/**
|
||||
* Stripped query
|
||||
*/
|
||||
// original, unstripped query
|
||||
const std::string unstripped_query;
|
||||
|
||||
// stripped query
|
||||
const std::string query;
|
||||
|
||||
/**
|
||||
* Stripped arguments
|
||||
*/
|
||||
// striped arguments
|
||||
const Parameters arguments;
|
||||
|
||||
/**
|
||||
* Hash based on stripped query.
|
||||
*/
|
||||
// hash based on the stripped query
|
||||
const HashType hash;
|
||||
};
|
||||
|
@ -214,7 +214,8 @@ StrippedQuery Strip(const std::string &query) {
|
||||
}
|
||||
|
||||
// return stripped query, stripped arguments and stripped query hash
|
||||
return StrippedQuery(std::move(stripped_query),
|
||||
return StrippedQuery(query,
|
||||
std::move(stripped_query),
|
||||
std::move(stripped_arguments),
|
||||
fnv(stripped_query));
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "dbms/dbms.hpp"
|
||||
#include "logging/default.hpp"
|
||||
#include "logging/streams/stdout.cpp"
|
||||
#include "query/entry.hpp"
|
||||
#include "query/interpreter.hpp"
|
||||
#include "query/backend/cpp/typed_value.hpp"
|
||||
#include "query/frontend/logical/operator.hpp"
|
||||
|
||||
@ -11,6 +12,77 @@ using std::cout;
|
||||
using std::cin;
|
||||
using std::endl;
|
||||
|
||||
/**
|
||||
* A Stream implementation that writes out to the
|
||||
* console (for testing and debugging only).
|
||||
*/
|
||||
// TODO move somewhere to /test/manual or so
|
||||
class ConsoleResultStream : public Loggable {
|
||||
public:
|
||||
ConsoleResultStream() : Loggable("ConsoleResultStream") {}
|
||||
|
||||
void Header(const std::vector<std::string> &) { logger.info("header"); }
|
||||
|
||||
void Result(std::vector<TypedValue> &values) {
|
||||
std::stringstream ss;
|
||||
bool first = true;
|
||||
for (auto value : values) {
|
||||
if (first) {
|
||||
ss << "\t";
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
ss << " | ";
|
||||
switch (value.type()) {
|
||||
case TypedValue::Type::Vertex: {
|
||||
auto va = value.Value<VertexAccessor>();
|
||||
ss << "Vertex(";
|
||||
for (auto label : va.labels())
|
||||
ss << ":" << va.db_accessor().label_name(label) << " ";
|
||||
ss << "{";
|
||||
for (auto kv : va.Properties()) {
|
||||
ss << va.db_accessor().property_name(kv.first) << ": ";
|
||||
ss << kv.second << ", ";
|
||||
}
|
||||
ss << "}";
|
||||
ss << ")";
|
||||
break;
|
||||
}
|
||||
case TypedValue::Type::Edge: {
|
||||
auto ea = value.Value<EdgeAccessor>();
|
||||
ss << "Edge[" << ea.db_accessor().edge_type_name(ea.edge_type()) << "}";
|
||||
ss << "{";
|
||||
for (auto kv : ea.Properties()) {
|
||||
ss << ea.db_accessor().property_name(kv.first) << ": ";
|
||||
ss << kv.second << ", ";
|
||||
}
|
||||
ss << "}";
|
||||
ss << "]";
|
||||
break;
|
||||
}
|
||||
|
||||
case TypedValue::Type::List:break;
|
||||
case TypedValue::Type::Map:break;
|
||||
case TypedValue::Type::Path:break;
|
||||
default:
|
||||
ss << value;
|
||||
}
|
||||
}
|
||||
logger.info("{}", ss.str());
|
||||
}
|
||||
|
||||
void Summary(const std::map<std::string, TypedValue> &summary) {
|
||||
std::stringstream ss;
|
||||
ss << "Summary {";
|
||||
bool first = true;
|
||||
for (auto kv : summary)
|
||||
ss << kv.first << " : " << kv.second << ", ";
|
||||
ss << "}";
|
||||
logger.info("{}", ss.str());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// init arguments
|
||||
REGISTER_ARGS(argc, argv);
|
||||
@ -21,8 +93,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
// init db context
|
||||
Dbms dbms;
|
||||
query::ConsoleResultStream stream;
|
||||
query::Engine<query::ConsoleResultStream> query_engine;
|
||||
ConsoleResultStream stream;
|
||||
|
||||
// initialize the database
|
||||
auto dba = dbms.active();
|
||||
@ -42,20 +113,20 @@ int main(int argc, char* argv[]) {
|
||||
memgraph.PropsSet(name, "Memgraph");
|
||||
memgraph.add_label(company);
|
||||
auto teon = dba->insert_vertex();
|
||||
memgraph.PropsSet(name, "Teon");
|
||||
memgraph.PropsSet(age, 26);
|
||||
teon.PropsSet(name, "Teon");
|
||||
teon.PropsSet(age, 26);
|
||||
teon.add_label(person);
|
||||
auto mislav = dba->insert_vertex();
|
||||
memgraph.PropsSet(name, "Mislav");
|
||||
memgraph.PropsSet(age, 22);
|
||||
mislav.PropsSet(name, "Mislav");
|
||||
mislav.PropsSet(age, 22);
|
||||
mislav.add_label(person);
|
||||
auto florijan = dba->insert_vertex();
|
||||
memgraph.PropsSet(name, "Florijan");
|
||||
memgraph.PropsSet(age, 31);
|
||||
florijan.PropsSet(name, "Florijan");
|
||||
florijan.PropsSet(age, 31);
|
||||
florijan.add_label(person);
|
||||
auto xps_15 = dba->insert_vertex();
|
||||
memgraph.PropsSet(type, "PC");
|
||||
memgraph.PropsSet(name, "Dell XPS 15");
|
||||
xps_15.PropsSet(type, "PC");
|
||||
xps_15.PropsSet(name, "Dell XPS 15");
|
||||
xps_15.add_label(device);
|
||||
|
||||
// edges
|
||||
@ -76,11 +147,12 @@ int main(int argc, char* argv[]) {
|
||||
dba->insert_edge(mislav, xps_15, dba->edge_type("USES"));
|
||||
dba->insert_edge(florijan, xps_15, dba->edge_type("USES"));
|
||||
|
||||
dba->advance_command();
|
||||
dba->commit();
|
||||
|
||||
cout << "-- Memgraph Query Engine --" << endl;
|
||||
|
||||
while (true) {
|
||||
auto inner_dba = dbms.active();
|
||||
// read command
|
||||
cout << "> ";
|
||||
std::string command;
|
||||
@ -89,7 +161,8 @@ int main(int argc, char* argv[]) {
|
||||
// execute command / query
|
||||
// try {
|
||||
// auto db_accessor = dbms.active();
|
||||
query_engine.Execute(command, *dba, stream);
|
||||
query::Interpret(command, *inner_dba, stream);
|
||||
inner_dba->commit();
|
||||
// } catch (const std::exception& e) {
|
||||
// cout << e.what() << endl;
|
||||
// } catch (...) {
|
||||
|
@ -12,7 +12,11 @@
|
||||
|
||||
#include "communication/result_stream_faker.hpp"
|
||||
#include "dbms/dbms.hpp"
|
||||
#include "query/entry.hpp"
|
||||
#include "query/context.hpp"
|
||||
#include "query/frontend/interpret/interpret.hpp"
|
||||
#include "query/frontend/logical/planner.hpp"
|
||||
#include "query/frontend/opencypher/parser.hpp"
|
||||
#include "query/frontend/semantic/symbol_generator.hpp"
|
||||
|
||||
using namespace query;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user