work in progress query_engine
This commit is contained in:
parent
396f0d9c31
commit
b1459a891b
@ -2,28 +2,41 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "exceptions/query_engine_exception.hpp"
|
||||
#include "utils/string/join.hpp"
|
||||
|
||||
// TODO: all libraries have to be compiled in the server compile time
|
||||
// TODO: generate copile command
|
||||
// TODO:
|
||||
// * all libraries have to be compiled in the server compile time
|
||||
// * compile command has to be generated
|
||||
#include <iostream>
|
||||
|
||||
class CodeCompiler
|
||||
{
|
||||
public:
|
||||
void compile(const std::string &in_file, const std::string &out_file)
|
||||
{
|
||||
// generate compile command
|
||||
auto compile_command =
|
||||
utils::prints("clang++",
|
||||
// "-std=c++1y -O2 -DNDEBUG", // compile flags
|
||||
"-std=c++1y -DDEBUG", // compile flags
|
||||
in_file, // input file
|
||||
"-o", out_file, // ouput file
|
||||
"-I./include", // include paths (TODO: parameter)
|
||||
"-I./src",
|
||||
"-I../../libs/fmt",
|
||||
"-std=c++1y -DDEBUG", // compile flags
|
||||
in_file, // input file
|
||||
"-o", out_file, // ouput file
|
||||
"-I./include", // include paths (TODO: parameter)
|
||||
"-I./src", "-I../../libs/fmt",
|
||||
"-shared -fPIC" // shared library flags
|
||||
);
|
||||
|
||||
// synchronous call
|
||||
system(compile_command.c_str());
|
||||
auto compile_status = system(compile_command.c_str());
|
||||
|
||||
// if compilation has failed throw exception
|
||||
if (compile_status == -1) {
|
||||
throw QueryEngineException("Code compilation error");
|
||||
}
|
||||
|
||||
// TODO: use logger
|
||||
std::cout << fmt::format("SUCCESS: Query Code Compilation: {} -> {}",
|
||||
in_file, out_file) << std::endl;
|
||||
}
|
||||
};
|
||||
|
@ -6,6 +6,11 @@
|
||||
#include "template_engine/engine.hpp"
|
||||
#include "traverser/code_traverser.hpp"
|
||||
#include "utils/string/file.hpp"
|
||||
#include "query_engine/exceptions/query_engine_exception.hpp"
|
||||
|
||||
// TODO:
|
||||
// * logger
|
||||
#include <iostream>
|
||||
|
||||
using std::string;
|
||||
|
||||
@ -19,10 +24,23 @@ public:
|
||||
string template_path = CONFIG(config::TEMPLATE_CPU_CPP_PATH);
|
||||
string template_file = utils::read_file(template_path.c_str());
|
||||
|
||||
// traversing
|
||||
auto tree = compiler.syntax_tree(query);
|
||||
// syntax tree generation
|
||||
try {
|
||||
tree = compiler.syntax_tree(query);
|
||||
} catch (const std::exception &e) {
|
||||
// TODO: extract more information
|
||||
throw QueryEngineException("Syntax tree generation error");
|
||||
}
|
||||
|
||||
code_traverser.reset();
|
||||
tree.root->accept(code_traverser);
|
||||
|
||||
// code generation
|
||||
try {
|
||||
tree.root->accept(code_traverser);
|
||||
} catch (const std::exception &e) {
|
||||
// TODO: extract more information
|
||||
throw QueryEngineException("Code generation error");
|
||||
}
|
||||
|
||||
// save the code
|
||||
string generated = template_engine.render(
|
||||
@ -30,7 +48,8 @@ public:
|
||||
{"stripped_hash", std::to_string(stripped_hash)},
|
||||
{"query", query},
|
||||
{"code", code_traverser.code}});
|
||||
// TODO: ifndef
|
||||
|
||||
// TODO: use logger, ifndef
|
||||
std::cout << generated << std::endl;
|
||||
|
||||
utils::write_file(generated, path);
|
||||
|
@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "storage/model/properties/properties.hpp"
|
||||
#include "storage/model/properties/traversers/jsonwriter.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
void print_props(const Properties &properties)
|
||||
{
|
||||
StringBuffer buffer;
|
||||
JsonWriter<StringBuffer> writer(buffer);
|
||||
properties.accept(writer);
|
||||
cout << buffer.str() << endl;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
#define PRINT_PROPS(_PROPS_) print_props(_PROPS_);
|
||||
#else
|
||||
#define PRINT_PROPS(_)
|
||||
#endif
|
8
src/query_engine/exceptions/query_engine_exception.hpp
Normal file
8
src/query_engine/exceptions/query_engine_exception.hpp
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/exceptions/basic_exception.hpp"
|
||||
|
||||
class QueryEngineException : public BasicException
|
||||
{
|
||||
using BasicException::BasicException;
|
||||
};
|
@ -1,118 +0,0 @@
|
||||
#include "database/db.hpp"
|
||||
#include "query_engine/query_stripper.hpp"
|
||||
#include "utils/hashing/fnv.hpp"
|
||||
#include "storage/model/properties/all.hpp"
|
||||
#include "query_engine/query_result.hpp"
|
||||
#define DEBUG
|
||||
#include "query_engine/debug.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
int main()
|
||||
{
|
||||
Db db;
|
||||
|
||||
std::vector<std::string> queries = {{
|
||||
std::string("CREATE (n{id:3}) RETURN n"),
|
||||
std::string("MATCH (n{id:3}) RETURN n"),
|
||||
std::string("MATCH (n{id:3}) SET n.prop = \"\" RETURN n"),
|
||||
std::string("MATCH (n{id:3}) DELETE n"),
|
||||
std::string("MATCH (n{id:3}),(m{id:2}) CREATE (n)-[r:test]->(m) RETURN r"),
|
||||
std::string("MATCH (n{id:3})-[r]->(m) RETURN count(r)")
|
||||
}};
|
||||
|
||||
auto stripper = make_query_stripper(TK_INT, TK_FLOAT, TK_STR, TK_BOOL);
|
||||
|
||||
for(auto query : queries) {
|
||||
auto strip = stripper.strip(query).query;
|
||||
auto hash = std::to_string(fnv(strip));
|
||||
cout << "QUERY: " << query <<
|
||||
" STRIP: " << strip <<
|
||||
" HASH: " << hash << endl;
|
||||
}
|
||||
|
||||
auto create_node = [&db](uint64_t id) {
|
||||
auto& t = db.tx_engine.begin();
|
||||
auto vertex_accessor = db.graph.vertices.insert(t);
|
||||
vertex_accessor.property<Int64>(
|
||||
"id", Int64(id)
|
||||
);
|
||||
t.commit();
|
||||
return vertex_accessor;
|
||||
};
|
||||
|
||||
auto find_node = [&db](uint64_t id) {
|
||||
auto& t = db.tx_engine.begin();
|
||||
auto vertex_accessor = db.graph.vertices.find(t, id);
|
||||
t.commit();
|
||||
return vertex_accessor;
|
||||
};
|
||||
|
||||
auto edit_node = [&db](uint64_t id, std::string prop) {
|
||||
auto& t = db.tx_engine.begin();
|
||||
auto vertex_accessor = db.graph.vertices.find(t, id);
|
||||
if (!vertex_accessor) {
|
||||
t.commit();
|
||||
return vertex_accessor;
|
||||
}
|
||||
vertex_accessor.property<String>(
|
||||
"prop", String(prop)
|
||||
);
|
||||
t.commit();
|
||||
return vertex_accessor;
|
||||
};
|
||||
|
||||
auto delete_node = [&db](uint64_t id) {
|
||||
auto& t = db.tx_engine.begin();
|
||||
auto vertex_accessor = db.graph.vertices.find(t, id);
|
||||
if (!vertex_accessor)
|
||||
return vertex_accessor;
|
||||
vertex_accessor.remove(t);
|
||||
t.commit();
|
||||
return vertex_accessor;
|
||||
};
|
||||
|
||||
auto create_edge = [&db](uint64_t id1, uint64_t id2, std::string type) {
|
||||
auto& t = db.tx_engine.begin();
|
||||
auto v1 = db.graph.vertices.find(t, id1);
|
||||
if (!v1)
|
||||
return Edge::Accessor();
|
||||
auto v2 = db.graph.vertices.find(t, id2);
|
||||
if (!v2)
|
||||
return Edge::Accessor();
|
||||
auto edge_accessor = db.graph.edges.insert(t);
|
||||
v1.vlist->access(t).update()->data.out.add(edge_accessor.vlist);
|
||||
v2.vlist->access(t).update()->data.in.add(edge_accessor.vlist);
|
||||
edge_accessor.from(v1.vlist);
|
||||
edge_accessor.to(v2.vlist);
|
||||
edge_accessor.edge_type(EdgeType(type));
|
||||
t.commit();
|
||||
return edge_accessor;
|
||||
};
|
||||
|
||||
auto vertex_out_degree = [&db](uint64_t id) {
|
||||
auto& t = db.tx_engine.begin();
|
||||
auto v = db.graph.vertices.find(t, id);
|
||||
t.commit();
|
||||
return v.out_degree();
|
||||
};
|
||||
|
||||
auto created_node1 = create_node(100);
|
||||
PRINT_PROPS(created_node1.properties());
|
||||
auto created_node2 = create_node(200);
|
||||
PRINT_PROPS(created_node2.properties());
|
||||
auto found_node = find_node(0);
|
||||
PRINT_PROPS(found_node.properties());
|
||||
auto edited_node = edit_node(0, "test");
|
||||
PRINT_PROPS(edited_node.properties());
|
||||
// delete_node(0);
|
||||
if (!find_node(0))
|
||||
cout << "node doesn't exist" << endl;
|
||||
auto edge_accessor = create_edge(0, 1, "test");
|
||||
if (edge_accessor)
|
||||
cout << edge_accessor.record->data.edge_type << endl;
|
||||
cout << vertex_out_degree(0) << endl;
|
||||
|
||||
return 0;
|
||||
}
|
@ -3,9 +3,10 @@
|
||||
#include <string>
|
||||
|
||||
#include "database/db.hpp"
|
||||
#include "query_engine/debug.hpp"
|
||||
#include "query_engine/util.hpp"
|
||||
#include "query_program.hpp"
|
||||
#include "utils/log/logger.hpp"
|
||||
#include "query_engine/exceptions/query_engine_exception.hpp"
|
||||
|
||||
// preparations before execution
|
||||
// execution
|
||||
@ -16,9 +17,17 @@ class ProgramExecutor
|
||||
public:
|
||||
auto execute(QueryProgram &program)
|
||||
{
|
||||
return program.code->run(db, program.stripped.arguments);
|
||||
try {
|
||||
// TODO: return result of query/code exection
|
||||
return program.code->run(db, program.stripped.arguments);
|
||||
} catch (...) {
|
||||
// TODO: return more information about the error
|
||||
throw QueryEngineException("code execution error");
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// TODO: here shoud be one database from DBMS, not local instance of
|
||||
// DB
|
||||
Db db;
|
||||
};
|
||||
|
@ -32,10 +32,10 @@ public:
|
||||
auto load(const string &query)
|
||||
{
|
||||
auto stripped = stripper.strip(query);
|
||||
LOG_INFO("stripped_query=" + stripped.query);
|
||||
LOG_INFO("stripped_query = " + stripped.query);
|
||||
|
||||
auto hash_string = std::to_string(stripped.hash);
|
||||
LOG_INFO("query_hash=" + hash_string);
|
||||
LOG_INFO("query_hash = " + hash_string);
|
||||
|
||||
auto code_lib_iter = code_libs.find(stripped.hash);
|
||||
|
||||
@ -52,7 +52,6 @@ public:
|
||||
auto path_cpp = base_path + hash_string + ".cpp";
|
||||
code_generator.generate_cpp(query, stripped.hash, path_cpp);
|
||||
|
||||
// TODO compile generated code
|
||||
auto path_so = base_path + hash_string + ".so";
|
||||
code_compiler.compile(path_cpp, path_so);
|
||||
|
||||
@ -60,14 +59,14 @@ public:
|
||||
auto code_lib = load_code_lib(path_so);
|
||||
code_libs.insert({{stripped.hash, code_lib}});
|
||||
|
||||
// return instance of runnable code (ICodeCPU)
|
||||
LOG_INFO("new code compiled and placed into cache");
|
||||
// return an instance of runnable code (ICodeCPU)
|
||||
return QueryProgram(code_lib->instance(), std::move(stripped));
|
||||
}
|
||||
|
||||
private:
|
||||
// TODO somehow remove int.. from here
|
||||
QueryStripper<int, int, int, int> stripper;
|
||||
|
||||
// TODO ifdef MEMGRAPH64 problem, how to use this kind
|
||||
// of ifdef functions?
|
||||
// uint64_t depends on fnv function
|
||||
|
@ -14,6 +14,7 @@ class QueryEngine
|
||||
public:
|
||||
auto execute(const std::string &query)
|
||||
{
|
||||
// TODO: error handling
|
||||
auto program = program_loader.load(query);
|
||||
auto result = program_executor.execute(program);
|
||||
return result;
|
||||
|
@ -9,10 +9,14 @@
|
||||
#include "read_traverser.hpp"
|
||||
#include "update_traverser.hpp"
|
||||
#include "delete_traverser.hpp"
|
||||
#include "read_write_traverser.hpp"
|
||||
|
||||
class CodeTraverser : public Traverser, public Code
|
||||
{
|
||||
public:
|
||||
|
||||
// TODO: remove code duplication
|
||||
|
||||
void visit(ast::WriteQuery& write_query) override
|
||||
{
|
||||
auto write_traverser = WriteTraverser();
|
||||
@ -40,4 +44,11 @@ public:
|
||||
delete_query.accept(delete_traverser);
|
||||
code = delete_traverser.code;
|
||||
}
|
||||
|
||||
void visit(ast::ReadWriteQuery& read_write_query) override
|
||||
{
|
||||
auto read_write_traverser = ReadWriteTraverser();
|
||||
read_write_query.accept(read_write_traverser);
|
||||
code = read_write_traverser.code;
|
||||
}
|
||||
};
|
||||
|
@ -5,4 +5,14 @@
|
||||
|
||||
class DeleteTraverser : public Traverser, public Code
|
||||
{
|
||||
void visit(ast::Match& match) override
|
||||
{
|
||||
code += LINE(fmt::format(code::todo, "MATCH"));
|
||||
}
|
||||
|
||||
void visit(ast::Delete& delete_clause) override
|
||||
{
|
||||
code += LINE(fmt::format(code::todo, "DELETE"));
|
||||
code += LINE(code::return_empty_result);
|
||||
}
|
||||
};
|
||||
|
@ -23,11 +23,9 @@ private:
|
||||
std::map<std::string, uint32_t> property_indices;
|
||||
|
||||
public:
|
||||
std::string code;
|
||||
|
||||
void update_entities(const std::string &name)
|
||||
{
|
||||
std::cout << name << std::endl;
|
||||
std::cout << name << std::endl;
|
||||
if (entities.find(name) == entities.end()) {
|
||||
csm.init_cost(name);
|
||||
property_indices[name] = index++;
|
||||
@ -49,7 +47,7 @@ public:
|
||||
auto name = identifier->name;
|
||||
update_entities(name);
|
||||
|
||||
if (node.labels != nullptr && node.labels->value != nullptr)
|
||||
if (node.labels != nullptr && node.labels->value != nullptr)
|
||||
csm.search_cost(name, search_label_index, label_cost);
|
||||
}
|
||||
|
||||
|
31
src/query_engine/traverser/read_write_traverser.hpp
Normal file
31
src/query_engine/traverser/read_write_traverser.hpp
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "code.hpp"
|
||||
#include "cypher/visitor/traverser.hpp"
|
||||
|
||||
class ReadWriteTraverser : public Traverser, public Code
|
||||
{
|
||||
void visit(ast::Match& match) override
|
||||
{
|
||||
code += LINE(fmt::format(code::todo, "MATCH"));
|
||||
Traverser::visit(match);
|
||||
}
|
||||
|
||||
void visit(ast::Where& where) override
|
||||
{
|
||||
code += LINE(fmt::format(code::todo, "WHERE"));
|
||||
Traverser::visit(where);
|
||||
}
|
||||
|
||||
void visit(ast::Create& create) override
|
||||
{
|
||||
code += LINE(fmt::format(code::todo, "CREATE"));
|
||||
Traverser::visit(create);
|
||||
}
|
||||
|
||||
void visit(ast::Return& ast_return) override
|
||||
{
|
||||
code += LINE(fmt::format(code::todo, "RETURN"));
|
||||
code += LINE(code::return_empty_result);
|
||||
}
|
||||
};
|
@ -7,13 +7,17 @@ class UpdateTraverser : public Traverser, public Code
|
||||
{
|
||||
void visit(ast::Match& match) override
|
||||
{
|
||||
code += LINE(fmt::format(code::todo, "MATCH"));
|
||||
}
|
||||
|
||||
void visit(ast::Set& set) override
|
||||
{
|
||||
code += LINE(fmt::format(code::todo, "SET"));
|
||||
}
|
||||
|
||||
void visit(ast::Return& ret) override
|
||||
{
|
||||
code += LINE(fmt::format(code::todo, "RETURN"));
|
||||
code += LINE(code::return_empty_result);
|
||||
}
|
||||
};
|
||||
|
@ -1,5 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "storage/model/properties/properties.hpp"
|
||||
#include "storage/model/properties/traversers/jsonwriter.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
std::string LINE(std::string line) { return "\t" + line + "\n"; }
|
||||
|
||||
void print_props(const Properties &properties)
|
||||
{
|
||||
StringBuffer buffer;
|
||||
JsonWriter<StringBuffer> writer(buffer);
|
||||
properties.accept(writer);
|
||||
cout << buffer.str() << endl;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
#define PRINT_PROPS(_PROPS_) print_props(_PROPS_);
|
||||
#else
|
||||
#define PRINT_PROPS(_)
|
||||
#endif
|
||||
|
@ -11,34 +11,22 @@
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
// * INPUT ARGUMENTS *
|
||||
// -q -> query
|
||||
// -v -> visitor
|
||||
// -f -> file
|
||||
//
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
std::set_terminate(&terminate_handler);
|
||||
|
||||
// arguments parsing
|
||||
// // arguments parsing
|
||||
auto arguments = all_arguments(argc, argv);
|
||||
|
||||
// query extraction
|
||||
// // query extraction
|
||||
auto cypher_query = extract_query(arguments);
|
||||
cout << "QUERY: " << cypher_query << endl;
|
||||
|
||||
// traversers
|
||||
auto traverser = get_argument(arguments, "-t", "code");
|
||||
auto print_traverser = Traverser::sptr(new PrintVisitor(cout));
|
||||
std::map<std::string, Traverser::sptr> traversers = {
|
||||
{"print", print_traverser}
|
||||
};
|
||||
|
||||
auto print_visitor = new PrintVisitor(cout);
|
||||
cypher::Compiler compiler;
|
||||
auto tree = compiler.syntax_tree(cypher_query);
|
||||
|
||||
auto t = traversers[traverser];
|
||||
tree.root->accept(*t);
|
||||
tree.root->accept(*print_visitor);
|
||||
cout << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "cypher/common.hpp"
|
||||
#include "query_engine/query_engine.hpp"
|
||||
#include "utils/time/timer.hpp"
|
||||
#include "utils/terminate_handler.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
@ -13,15 +14,29 @@ using std::cin;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
std::set_terminate(&terminate_handler);
|
||||
|
||||
QueryEngine engine;
|
||||
|
||||
std::string command;
|
||||
cout << "-- Memgraph query engine --" << endl;
|
||||
do {
|
||||
|
||||
while (true) {
|
||||
// read command
|
||||
cout << "> ";
|
||||
std::string command;
|
||||
std::getline(cin, command);
|
||||
engine.execute(command);
|
||||
} while (command != "quit");
|
||||
if (command == "quit")
|
||||
break;
|
||||
|
||||
// execute command
|
||||
try {
|
||||
engine.execute(command);
|
||||
} catch (const std::exception& e) {
|
||||
cout << e.what() << endl;
|
||||
} catch (const QueryEngineException& e) {
|
||||
cout << e.what() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user