scenario 000001 pass, dressipi scenario 1 - 3 more queries have to be implemented
This commit is contained in:
parent
7d85bc2bc0
commit
d45121a1a2
@ -3,7 +3,7 @@ Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlinesLeft: false
|
||||
AlignOperands: true
|
||||
@ -22,15 +22,15 @@ BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: true
|
||||
AfterControlStatement: false
|
||||
AfterControlStatement: true
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
IndentBraces: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
@ -84,6 +84,6 @@ SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: "C++11"
|
||||
TabWidth: 8
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
...
|
||||
|
@ -99,7 +99,7 @@ set(catch_source_dir "${libs_dir}/Catch")
|
||||
|
||||
# build memgraph's cypher grammar
|
||||
# copy grammar file to the build directory
|
||||
FILE(COPY ${src_dir}/cypher/cypher.y DESTINATION ${CMAKE_BINARY_DIR})
|
||||
FILE(COPY ${include_dir}/query/language/cypher/cypher.y DESTINATION ${CMAKE_BINARY_DIR})
|
||||
# build cypher parser (only c file - cypher.c)
|
||||
EXECUTE_PROCESS(
|
||||
COMMAND ${lemon_dir}/lemon ${CMAKE_BINARY_DIR}/cypher.y -s
|
||||
@ -164,10 +164,9 @@ FILE(COPY ${include_dir}/storage/label/label_store.hpp DESTINATION ${build_inclu
|
||||
FILE(COPY ${include_dir}/storage/model/edge_map.hpp DESTINATION ${build_include_dir}/storage/model)
|
||||
FILE(COPY ${include_dir}/storage/model/properties/flags.hpp DESTINATION ${build_include_dir}/storage/model/properties)
|
||||
|
||||
FILE(COPY ${include_dir}/query_engine/util.hpp DESTINATION ${build_include_dir}/query_engine)
|
||||
FILE(COPY ${include_dir}/query_engine/i_code_cpu.hpp DESTINATION ${build_include_dir}/query_engine)
|
||||
FILE(COPY ${include_dir}/query_engine/query_result.hpp DESTINATION ${build_include_dir}/query_engine)
|
||||
FILE(COPY ${include_dir}/query_engine/query_stripped.hpp DESTINATION ${build_include_dir}/query_engine)
|
||||
FILE(COPY ${include_dir}/query/util.hpp DESTINATION ${build_include_dir}/query)
|
||||
FILE(COPY ${include_dir}/query/i_plan_cpu.hpp DESTINATION ${build_include_dir}/query)
|
||||
FILE(COPY ${include_dir}/query/strip/stripped.hpp DESTINATION ${build_include_dir}/query/strip)
|
||||
|
||||
FILE(COPY ${include_dir}/data_structures/concurrent/concurrent_map.hpp DESTINATION ${build_include_dir}/data_structures/concurrent)
|
||||
FILE(COPY ${include_dir}/data_structures/concurrent/concurrent_set.hpp DESTINATION ${build_include_dir}/data_structures/concurrent)
|
||||
|
@ -43,6 +43,15 @@ public:
|
||||
bolt_encoder.message_ignored();
|
||||
}
|
||||
|
||||
void write_empty_fields()
|
||||
{
|
||||
bolt_encoder.message_success();
|
||||
bolt_encoder.write_map_header(1);
|
||||
bolt_encoder.write_string("fields");
|
||||
write_list_header(0);
|
||||
chunk();
|
||||
}
|
||||
|
||||
void write_fields(const std::vector<std::string> &fields)
|
||||
{
|
||||
// TODO: that should be one level below?
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include "communication/bolt/v1/states/state.hpp"
|
||||
#include "communication/bolt/v1/session.hpp"
|
||||
#include "query_engine/query_engine.hpp"
|
||||
#include "query/engine.hpp"
|
||||
|
||||
namespace bolt
|
||||
{
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "communication/bolt/v1/packing/codes.hpp"
|
||||
#include "query_engine/exceptions/exceptions.hpp"
|
||||
#include "query/exception/decoder_exception.hpp"
|
||||
#include "utils/bswap.hpp"
|
||||
#include "utils/types/byte.hpp"
|
||||
|
||||
|
14
include/logging/loggable.hpp
Normal file
14
include/logging/loggable.hpp
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "logging/default.hpp"
|
||||
|
||||
class Loggable
|
||||
{
|
||||
public:
|
||||
Loggable(const std::string& name) : logger(logging::log->logger(name)) {}
|
||||
|
||||
virtual ~Loggable() {}
|
||||
|
||||
protected:
|
||||
Logger logger;
|
||||
};
|
10
include/query/backend/backend.hpp
Normal file
10
include/query/backend/backend.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "query/ir/tree/node.hpp"
|
||||
|
||||
class Backend
|
||||
{
|
||||
public:
|
||||
virtual void process(ir::Node *node) = 0;
|
||||
virtual ~Backend() {}
|
||||
};
|
40
include/query/backend/code_generator.hpp
Normal file
40
include/query/backend/code_generator.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "query/backend/backend.hpp"
|
||||
|
||||
class CodeGenerator : public Backend
|
||||
{
|
||||
private:
|
||||
struct Code
|
||||
{
|
||||
public:
|
||||
void println(const std::string &line)
|
||||
{
|
||||
code.append(line + "\n");
|
||||
line_no++;
|
||||
}
|
||||
|
||||
void save(const std::string &)
|
||||
{
|
||||
throw std::runtime_error("TODO: implementation");
|
||||
}
|
||||
|
||||
void reset() { code = ""; }
|
||||
|
||||
std::string code;
|
||||
uint64_t line_no;
|
||||
};
|
||||
|
||||
protected:
|
||||
Code code;
|
||||
|
||||
public:
|
||||
void emit(const std::string &line) { code.println(line); }
|
||||
|
||||
void save(const std::string &path) { code.save(path); }
|
||||
|
||||
void reset() { code.reset(); }
|
||||
};
|
22
include/query/backend/cpp/code_generator.hpp
Normal file
22
include/query/backend/cpp/code_generator.hpp
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "query/backend/code_generator.hpp"
|
||||
|
||||
/*
|
||||
* Traverses the intermediate representation tree and generates
|
||||
* C++ code.
|
||||
*/
|
||||
class CppCodeGenerator : public CodeGenerator
|
||||
{
|
||||
public:
|
||||
CppCodeGenerator()
|
||||
{
|
||||
throw std::runtime_error("TODO: implementation");
|
||||
}
|
||||
|
||||
void process(ir::Node *) override
|
||||
{
|
||||
throw std::runtime_error("TODO: implementation");
|
||||
|
||||
}
|
||||
};
|
@ -1,11 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
// !! DEPRICATED !!
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "query_engine/util.hpp"
|
||||
#include "query/util.hpp"
|
||||
|
||||
struct Code
|
||||
class Code
|
||||
{
|
||||
public:
|
||||
std::string code;
|
||||
|
||||
void reset() { code = ""; }
|
||||
@ -152,6 +155,12 @@ const std::string print_property =
|
||||
}
|
||||
|
||||
// DELETE
|
||||
const std::string detach_delete_all_nodes =
|
||||
"t.vertex_access().fill().isolated().for_all("
|
||||
" [&](auto a) {{ a.remove(); }});";
|
||||
const std::string delete_all_detached_nodes =
|
||||
"t.vertex_access().fill().isolated().for_all(\n"
|
||||
" [&](auto a) {{ a.remove(); }});\n"
|
||||
" stream.write_empty_fields();\n"
|
||||
" stream.write_meta(\"w\");\n";
|
||||
const std::string delete_whole_graph =
|
||||
"t.edge_access().fill().for_all(\n"
|
||||
" [&](auto e) { e.remove(); }\n"
|
||||
");\n" + delete_all_detached_nodes;
|
@ -2,10 +2,10 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "query_engine/code_generator/cypher_state.hpp"
|
||||
#include "query_engine/code_generator/handlers/all.hpp"
|
||||
#include "query_engine/code_generator/query_action.hpp"
|
||||
#include "query_engine/exceptions/exceptions.hpp"
|
||||
#include "query/backend/cpp_old/cypher_state.hpp"
|
||||
#include "query/backend/cpp_old/handlers/all.hpp"
|
||||
#include "query/backend/cpp_old/query_action.hpp"
|
||||
#include "query/exception/cpp_code_generator.hpp"
|
||||
|
||||
class CppGenerator
|
||||
{
|
||||
@ -24,11 +24,12 @@ public:
|
||||
{
|
||||
std::string code = "";
|
||||
|
||||
for (uint64_t i = processed_index; i < unprocessed_index; ++i) {
|
||||
for (uint64_t i = processed_index; i < unprocessed_index; ++i)
|
||||
{
|
||||
auto &action = actions.at(i);
|
||||
auto query_action = action.first;
|
||||
if (action_functions.find(query_action) == action_functions.end())
|
||||
throw CppGeneratorException(
|
||||
throw CppCodeGeneratorException(
|
||||
"Query Action Function is not defined");
|
||||
auto &action_data = action.second;
|
||||
code += action_functions[query_action](_cypher_data, action_data);
|
65
include/query/backend/cpp_old/cypher.hpp
Normal file
65
include/query/backend/cpp_old/cypher.hpp
Normal file
@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
// DEPRICATED!
|
||||
#include "config/config.hpp"
|
||||
#include "query/frontend/cypher/traverser.hpp"
|
||||
#include "query/language/cypher/errors.hpp"
|
||||
#include "template_engine/engine.hpp"
|
||||
#include "utils/string/file.hpp"
|
||||
#include "utils/type_discovery.hpp"
|
||||
|
||||
template <typename Stream>
|
||||
class CypherBackend
|
||||
{
|
||||
public:
|
||||
CypherBackend() : logger(logging::log->logger("CypherBackend"))
|
||||
{
|
||||
// load template file
|
||||
#ifdef BARRIER
|
||||
std::string template_path =
|
||||
CONFIG(config::BARRIER_TEMPLATE_CPU_CPP_PATH);
|
||||
#else
|
||||
std::string template_path = CONFIG(config::TEMPLATE_CPU_CPP_PATH);
|
||||
#endif
|
||||
template_file = utils::read_file(template_path.c_str());
|
||||
}
|
||||
|
||||
template <typename Tree>
|
||||
void generate_code(const Tree &tree, const std::string &query,
|
||||
const uint64_t stripped_hash, const std::string &path)
|
||||
{
|
||||
CppTraverser cpp_traverser;
|
||||
cpp_traverser.reset();
|
||||
|
||||
try {
|
||||
tree.root->accept(cpp_traverser);
|
||||
} catch (const CypherSemanticError &e) {
|
||||
throw e;
|
||||
} catch (const std::exception &e) {
|
||||
logger.error("AST traversal error: {}", std::string(e.what()));
|
||||
throw e;
|
||||
}
|
||||
|
||||
// save the code
|
||||
std::string generated = template_engine::render(
|
||||
template_file, {{"class_name", "CodeCPU"},
|
||||
{"stripped_hash", std::to_string(stripped_hash)},
|
||||
{"query", query},
|
||||
#ifdef BARRIER
|
||||
{"stream", "RecordStream<::io::Socket>"},
|
||||
#else
|
||||
{"stream", type_name<Stream>().to_string()},
|
||||
#endif
|
||||
{"code", cpp_traverser.code}});
|
||||
|
||||
logger.trace("generated code: {}", generated);
|
||||
|
||||
utils::write_file(generated, path);
|
||||
}
|
||||
|
||||
protected:
|
||||
Logger logger;
|
||||
|
||||
private:
|
||||
std::string template_file;
|
||||
};
|
@ -5,8 +5,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "query_engine/code_generator/namer.hpp"
|
||||
#include "query_engine/exceptions/exceptions.hpp"
|
||||
#include "query/backend/cpp_old/namer.hpp"
|
||||
#include "query/exception/cpp_code_generator.hpp"
|
||||
#include "storage/model/properties/flags.hpp"
|
||||
|
||||
// main states that are used while ast is traversed
|
||||
@ -50,7 +50,7 @@ enum class EntitySource : uint8_t
|
||||
class CypherStateData
|
||||
{
|
||||
public:
|
||||
using tags_type = std::vector<std::string>;
|
||||
using tags_type = std::vector<std::string>;
|
||||
using properties_type = std::map<std::string, int64_t>;
|
||||
|
||||
private:
|
||||
@ -96,25 +96,25 @@ public:
|
||||
|
||||
void node_matched(const std::string &name)
|
||||
{
|
||||
entity_type[name] = EntityType::Node;
|
||||
entity_type[name] = EntityType::Node;
|
||||
entity_status[name] = EntityStatus::Matched;
|
||||
}
|
||||
|
||||
void node_created(const std::string &name)
|
||||
{
|
||||
entity_type[name] = EntityType::Node;
|
||||
entity_type[name] = EntityType::Node;
|
||||
entity_status[name] = EntityStatus::Created;
|
||||
}
|
||||
|
||||
void relationship_matched(const std::string &name)
|
||||
{
|
||||
entity_type[name] = EntityType::Relationship;
|
||||
entity_type[name] = EntityType::Relationship;
|
||||
entity_status[name] = EntityStatus::Matched;
|
||||
}
|
||||
|
||||
void relationship_created(const std::string &name)
|
||||
{
|
||||
entity_type[name] = EntityType::Relationship;
|
||||
entity_type[name] = EntityType::Relationship;
|
||||
entity_status[name] = EntityStatus::Created;
|
||||
}
|
||||
|
||||
@ -127,7 +127,7 @@ public:
|
||||
auto tags(const std::string &name) const
|
||||
{
|
||||
if (entity_tags.find(name) == entity_tags.end())
|
||||
throw CppGeneratorException("No tags for specified entity");
|
||||
throw CppCodeGeneratorException("No tags for specified entity");
|
||||
return entity_tags.at(name);
|
||||
}
|
||||
|
||||
@ -138,17 +138,24 @@ public:
|
||||
|
||||
void tag(const std::string &name, const std::string &new_tag)
|
||||
{
|
||||
if (entity_tags.find(name) == entity_tags.end()) {
|
||||
if (entity_tags.find(name) == entity_tags.end())
|
||||
{
|
||||
entity_tags[name] = std::vector<std::string>{};
|
||||
}
|
||||
entity_tags[name].emplace_back(new_tag);
|
||||
}
|
||||
|
||||
auto has_properties(const std::string& name)
|
||||
{
|
||||
return entity_properties.find(name) != entity_properties.end();
|
||||
}
|
||||
|
||||
// entity properties
|
||||
auto properties(const std::string &name) const
|
||||
{
|
||||
if (entity_properties.find(name) == entity_properties.end())
|
||||
throw CppGeneratorException("No properties for specified entity");
|
||||
throw CppCodeGeneratorException(
|
||||
"No properties for specified entity: " + name);
|
||||
return entity_properties.at(name);
|
||||
}
|
||||
|
||||
@ -160,7 +167,8 @@ public:
|
||||
void index(const std::string &entity, const std::string &property,
|
||||
int64_t index)
|
||||
{
|
||||
if (entity_properties.find(entity) == entity_properties.end()) {
|
||||
if (entity_properties.find(entity) == entity_properties.end())
|
||||
{
|
||||
entity_properties[entity] = properties_type{};
|
||||
}
|
||||
entity_properties[entity][property] = index;
|
||||
@ -169,12 +177,13 @@ public:
|
||||
auto index(const std::string &entity, const std::string &property_name)
|
||||
{
|
||||
if (entity_properties.find(entity) == entity_properties.end())
|
||||
throw CppGeneratorException("No properties for specified entity");
|
||||
throw CppCodeGeneratorException(
|
||||
"No properties for specified entity");
|
||||
|
||||
auto properties = entity_properties.at(entity);
|
||||
|
||||
if (properties.find(property_name) == properties.end())
|
||||
throw CppGeneratorException(
|
||||
throw CppCodeGeneratorException(
|
||||
"No property for specified property name");
|
||||
|
||||
return properties[property_name];
|
||||
@ -186,19 +195,21 @@ public:
|
||||
{
|
||||
// TODO: find out smarter way it's not hard
|
||||
std::string print =
|
||||
"std::map<std::string, int64_t> " + variable_name + " = ";
|
||||
print += "{";
|
||||
"std::map<std::string, int64_t> " + variable_name + " = {";
|
||||
|
||||
auto indices = entity_properties.at(name);
|
||||
size_t i = 0;
|
||||
iter_t it = indices.begin();
|
||||
size_t i = 0;
|
||||
iter_t it = indices.begin();
|
||||
|
||||
for (; it != indices.end(); ++it, ++i)
|
||||
{
|
||||
print +=
|
||||
"{\"" + it->first + "\"," + std::to_string(it->second) + "}";
|
||||
if (i < indices.size() - 1)
|
||||
print += ",";
|
||||
if (i < indices.size() - 1) print += ",";
|
||||
}
|
||||
|
||||
print += "};";
|
||||
|
||||
return print;
|
||||
}
|
||||
};
|
11
include/query/backend/cpp_old/handlers/all.hpp
Normal file
11
include/query/backend/cpp_old/handlers/all.hpp
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
// TODO: refactor build state machine instead of ifs
|
||||
|
||||
#include "query/backend/cpp_old/handlers/create.hpp"
|
||||
#include "query/backend/cpp_old/handlers/delete.hpp"
|
||||
#include "query/backend/cpp_old/handlers/match.hpp"
|
||||
#include "query/backend/cpp_old/handlers/return.hpp"
|
||||
#include "query/backend/cpp_old/handlers/set.hpp"
|
||||
#include "query/backend/cpp_old/handlers/transaction_begin.hpp"
|
||||
#include "query/backend/cpp_old/handlers/transaction_commit.hpp"
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "query_engine/code_generator/handlers/includes.hpp"
|
||||
#include "includes.hpp"
|
||||
|
||||
auto create_query_action =
|
||||
[](CypherStateData &cypher_data,
|
||||
@ -35,7 +35,8 @@ auto create_query_action =
|
||||
// find start and end node
|
||||
auto &relationships_data = action_data.relationship_data;
|
||||
if (relationships_data.find(name) == relationships_data.end())
|
||||
throw CodeGenerationError("Unable to find data for: " + name);
|
||||
throw CppCodeGeneratorException("Unable to find data for: " +
|
||||
name);
|
||||
auto &relationship_data = relationships_data.at(name);
|
||||
auto left_node = relationship_data.nodes.first;
|
||||
auto right_node = relationship_data.nodes.second;
|
||||
@ -43,12 +44,12 @@ auto create_query_action =
|
||||
// TODO: If node isn't already matched or created it has to be
|
||||
// created here. It is not possible for now.
|
||||
if (cypher_data.status(left_node) != EntityStatus::Matched) {
|
||||
throw SemanticError("Create Relationship: node " + left_node +
|
||||
" can't be found");
|
||||
throw CypherSemanticError("Create Relationship: node " +
|
||||
left_node + " can't be found");
|
||||
}
|
||||
if (cypher_data.status(right_node) != EntityStatus::Matched) {
|
||||
throw SemanticError("Create Relationship: node " + right_node +
|
||||
" can't be found");
|
||||
throw CypherSemanticError("Create Relationship: node " +
|
||||
right_node + " can't be found");
|
||||
}
|
||||
|
||||
// create relationship
|
||||
@ -64,19 +65,6 @@ auto create_query_action =
|
||||
code += code_line(code::set_type, name, tag);
|
||||
}
|
||||
|
||||
// define direction
|
||||
// if (relationship_data.direction == Direction::Right) {
|
||||
// code += code_line(code::node_out, left_node, name);
|
||||
// code += code_line(code::node_in, right_node, name);
|
||||
// code += code_line(code::edge_from, name, left_node);
|
||||
// code += code_line(code::edge_to, name, right_node);
|
||||
// } else if (relationship_data.direction == Direction::Left) {
|
||||
// code += code_line(code::node_out, right_node, name);
|
||||
// code += code_line(code::node_in, left_node, name);
|
||||
// code += code_line(code::edge_from, name, right_node);
|
||||
// code += code_line(code::edge_to, name, left_node);
|
||||
// }
|
||||
|
||||
// mark relationship as created
|
||||
cypher_data.relationship_created(name);
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "query_engine/code_generator/handlers/includes.hpp"
|
||||
#include "includes.hpp"
|
||||
|
||||
auto delete_query_action =
|
||||
[](CypherStateData &cypher_data,
|
||||
@ -10,8 +10,11 @@ auto delete_query_action =
|
||||
|
||||
for (auto const &kv : action_data.actions) {
|
||||
auto entity = kv.first;
|
||||
if (kv.second == ClauseAction::DeleteNode) {
|
||||
code += code_line(detach_delete_all_nodes);
|
||||
if (kv.second == ClauseAction::DeleteNode && action_data.is_detach) {
|
||||
code += code_line(delete_whole_graph);
|
||||
}
|
||||
if (kv.second == ClauseAction::DeleteNode && !action_data.is_detach) {
|
||||
code += code_line(delete_all_detached_nodes);
|
||||
}
|
||||
if (kv.second == ClauseAction::DeleteRelationship) {
|
||||
code += code_line("// DELETE Relationship({})", entity);
|
@ -6,12 +6,13 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "query_engine/code_generator/cypher_state.hpp"
|
||||
#include "query_engine/code_generator/namer.hpp"
|
||||
#include "query_engine/code_generator/query_action_data.hpp"
|
||||
#include "query_engine/exceptions/errors.hpp"
|
||||
#include "query_engine/traverser/code.hpp"
|
||||
#include "query_engine/util.hpp"
|
||||
#include "query/backend/cpp_old/cypher_state.hpp"
|
||||
#include "query/backend/cpp_old/namer.hpp"
|
||||
#include "query/backend/cpp_old/query_action_data.hpp"
|
||||
#include "query/backend/cpp_old/code.hpp"
|
||||
#include "query/util.hpp"
|
||||
#include "query/exception/cpp_code_generator.hpp"
|
||||
#include "query/language/cypher/errors.hpp"
|
||||
|
||||
using ParameterIndexKey::Type::InternalId;
|
||||
using Direction = RelationshipData::Direction;
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "query_engine/code_generator/handlers/includes.hpp"
|
||||
#include "includes.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -49,7 +49,7 @@ auto match_query_action =
|
||||
}
|
||||
if (place == entity_search::search_label_index) {
|
||||
if (action_data.entity_data.at(name).tags.size() > 1) {
|
||||
throw SemanticError("Multiple label match (currently NOT supported)");
|
||||
throw CypherSemanticError("Multiple label match (currently NOT supported)");
|
||||
}
|
||||
cypher_data.source(name, EntitySource::LabelIndex);
|
||||
cypher_data.tags(name, action_data.entity_data.at(name).tags);
|
||||
@ -72,7 +72,7 @@ auto match_query_action =
|
||||
}
|
||||
if (place == entity_search::search_type_index) {
|
||||
if (action_data.entity_data.at(name).tags.size() > 1) {
|
||||
throw SemanticError("Multiple type match (currently NOT supported)");
|
||||
throw CypherSemanticError("Multiple type match (currently NOT supported)");
|
||||
}
|
||||
cypher_data.source(name, EntitySource::TypeIndex);
|
||||
cypher_data.tags(name, action_data.entity_data.at(name).tags);
|
@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "query_engine/code_generator/handlers/includes.hpp"
|
||||
#include "includes.hpp"
|
||||
|
||||
// TODO: total fuck up; replace this with IR + Backend
|
||||
|
||||
auto return_query_action =
|
||||
[](CypherStateData &cypher_data,
|
||||
@ -15,8 +17,8 @@ auto return_query_action =
|
||||
{
|
||||
auto &entity = element.entity;
|
||||
|
||||
if (!cypher_data.exist(entity))
|
||||
throw SemanticError(
|
||||
if (!cypher_data.exist(entity))
|
||||
throw CypherSemanticError(
|
||||
fmt::format("{} couldn't be found (RETURN clause).", entity));
|
||||
|
||||
if (element.is_entity_only())
|
||||
@ -36,42 +38,49 @@ auto return_query_action =
|
||||
code += code_line(code::write_all_vertices, entity);
|
||||
else if (cypher_data.type(entity) == EntityType::Relationship)
|
||||
code += code_line(code::write_all_edges, entity);
|
||||
|
||||
}
|
||||
// the client will receive entities from label index
|
||||
if (cypher_data.source(entity) == EntitySource::LabelIndex)
|
||||
if (cypher_data.status(entity) != EntityStatus::Created &&
|
||||
cypher_data.source(entity) == EntitySource::LabelIndex)
|
||||
{
|
||||
if (cypher_data.tags(entity).size() == 0)
|
||||
throw CppGeneratorException("node has no labels");
|
||||
throw CppCodeGeneratorException("node has no labels");
|
||||
|
||||
// node and no other property
|
||||
if (cypher_data.type(entity) == EntityType::Node) {
|
||||
auto label = cypher_data.tags(entity).at(0);
|
||||
if (cypher_data.properties(entity).size() > 0)
|
||||
if (cypher_data.type(entity) == EntityType::Node)
|
||||
{
|
||||
auto label = cypher_data.tags(entity).at(0);
|
||||
if (cypher_data.has_properties(entity))
|
||||
{
|
||||
code += code_line(code::find_and_write_vertices_by_label_and_properties,
|
||||
cypher_data.print_indices(entity), label, entity);
|
||||
code += code_line(
|
||||
code::
|
||||
find_and_write_vertices_by_label_and_properties,
|
||||
cypher_data.print_indices(entity), label, entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
code += code_line(code::find_and_write_vertices_by_label,
|
||||
entity, label);
|
||||
code +=
|
||||
code_line(code::find_and_write_vertices_by_label,
|
||||
entity, label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (cypher_data.source(entity) == EntitySource::TypeIndex)
|
||||
{
|
||||
if (cypher_data.type(entity) == EntityType::Relationship) {
|
||||
if (cypher_data.type(entity) == EntityType::Relationship)
|
||||
{
|
||||
if (cypher_data.tags(entity).size() == 0)
|
||||
throw CppGeneratorException("edge has no tag");
|
||||
auto type = cypher_data.tags(entity).at(0);
|
||||
throw CppCodeGeneratorException("edge has no tag");
|
||||
auto type = cypher_data.tags(entity).at(0);
|
||||
code += code_line(code::find_and_write_edges_by_type,
|
||||
entity, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (element.is_projection())
|
||||
}
|
||||
else if (element.is_projection())
|
||||
{
|
||||
code += code_line("// TODO: implement projection");
|
||||
// auto &property = element.property;
|
||||
@ -94,10 +103,11 @@ auto return_query_action =
|
||||
if (cypher_data.source(name) == EntitySource::LabelIndex)
|
||||
{
|
||||
auto tags = cypher_data.tags(name);
|
||||
if (tags.size() == 1) {
|
||||
if (tags.size() == 1)
|
||||
{
|
||||
auto label = tags.at(0);
|
||||
code += code_line(code::count_vertices_for_one_label,
|
||||
name, label);
|
||||
code += code_line(code::count_vertices_for_one_label, name,
|
||||
label);
|
||||
}
|
||||
// TODO: do for more, isn't easy because of
|
||||
// multiple iterators, but we have iterator infrastructure
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "query_engine/code_generator/handlers/includes.hpp"
|
||||
#include "includes.hpp"
|
||||
|
||||
auto set_query_action = [](CypherStateData &cypher_data,
|
||||
const QueryActionData &action_data) -> std::string {
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "query_engine/code_generator/handlers/includes.hpp"
|
||||
#include "includes.hpp"
|
||||
|
||||
auto transaction_begin_action = [](CypherStateData &,
|
||||
const QueryActionData &) -> std::string {
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "query_engine/code_generator/handlers/includes.hpp"
|
||||
#include "includes.hpp"
|
||||
|
||||
auto transaction_commit_action = [](CypherStateData &,
|
||||
const QueryActionData &) -> std::string {
|
@ -4,9 +4,9 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "query_engine/code_generator/clause_action.hpp"
|
||||
#include "query_engine/code_generator/entity_search.hpp"
|
||||
#include "query_engine/exceptions/exceptions.hpp"
|
||||
#include "query/backend/cpp_old/clause_action.hpp"
|
||||
#include "query/backend/cpp_old/entity_search.hpp"
|
||||
#include "query/exception/cpp_code_generator.hpp"
|
||||
#include "storage/model/properties/all.hpp"
|
||||
#include "utils/assert.hpp"
|
||||
#include "utils/underlying_cast.hpp"
|
||||
@ -118,6 +118,7 @@ struct QueryActionData
|
||||
std::map<std::string, EntityData> entity_data;
|
||||
std::map<std::string, RelationshipData> relationship_data;
|
||||
std::vector<ReturnElement> return_elements;
|
||||
bool is_detach;
|
||||
CypherStateMachine csm;
|
||||
|
||||
QueryActionData() = default;
|
||||
@ -146,7 +147,7 @@ struct QueryActionData
|
||||
auto get_entity_property(const std::string &entity) const
|
||||
{
|
||||
if (entity_data.find(entity) == entity_data.end())
|
||||
throw CppGeneratorException("Entity " + entity + " doesn't exist");
|
||||
throw CppCodeGeneratorException("Entity " + entity + " doesn't exist");
|
||||
|
||||
return entity_data.at(entity);
|
||||
}
|
||||
@ -154,7 +155,7 @@ struct QueryActionData
|
||||
auto get_tags(const std::string& entity) const
|
||||
{
|
||||
if (entity_data.find(entity) == entity_data.end())
|
||||
throw CppGeneratorException("Entity " + entity + "doesn't exist");
|
||||
throw CppCodeGeneratorException("Entity " + entity + "doesn't exist");
|
||||
|
||||
return entity_data.at(entity).tags;
|
||||
}
|
3
include/query/backend/llvm/code_generator.hpp
Normal file
3
include/query/backend/llvm/code_generator.hpp
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
// TODO: implementation
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "query_engine/i_code_cpu.hpp"
|
||||
#include "query/i_plan_cpu.hpp"
|
||||
#include "dc/dynamic_lib.hpp"
|
||||
|
||||
namespace
|
||||
@ -12,7 +12,7 @@ class MemgraphDynamicLib
|
||||
public:
|
||||
using produce = produce_t<Stream>;
|
||||
using destruct = destruct_t<Stream>;
|
||||
using lib_object = ICodeCPU<Stream>;
|
||||
using lib_object = IPlanCPU<Stream>;
|
||||
};
|
||||
|
||||
template <typename Stream>
|
@ -2,9 +2,10 @@
|
||||
|
||||
#include "database/db.hpp"
|
||||
#include "logging/default.hpp"
|
||||
#include "program_executor.hpp"
|
||||
#include "program_loader.hpp"
|
||||
#include "query_result.hpp"
|
||||
#include "query/exception/query_engine.hpp"
|
||||
#include "query/plan/program.hpp"
|
||||
#include "query/plan/program_loader.hpp"
|
||||
#include "query/plan/program_executor.hpp"
|
||||
|
||||
/*
|
||||
* Current arhitecture:
|
||||
@ -20,8 +21,7 @@ class QueryEngine
|
||||
public:
|
||||
QueryEngine() : logger(logging::log->logger("QueryEngine")) {}
|
||||
|
||||
auto execute(const std::string &query, Db &db,
|
||||
Stream &stream)
|
||||
auto execute(const std::string &query, Db &db, Stream &stream)
|
||||
{
|
||||
try {
|
||||
auto program = program_loader.load(query);
|
||||
@ -38,6 +38,8 @@ public:
|
||||
logger.error("QueryEngineException: {}", std::string(e.what()));
|
||||
// return false;
|
||||
throw e;
|
||||
} catch (std::exception &e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
9
include/query/exception/cpp_code_generator.hpp
Normal file
9
include/query/exception/cpp_code_generator.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/exceptions/basic_exception.hpp"
|
||||
|
||||
class CppCodeGeneratorException : public BasicException
|
||||
{
|
||||
public:
|
||||
using BasicException::BasicException;
|
||||
};
|
9
include/query/exception/decoder_exception.hpp
Normal file
9
include/query/exception/decoder_exception.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/exceptions/basic_exception.hpp"
|
||||
|
||||
class DecoderException : public BasicException
|
||||
{
|
||||
public:
|
||||
using BasicException::BasicException;
|
||||
};
|
9
include/query/exception/out_of_memory.hpp
Normal file
9
include/query/exception/out_of_memory.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/exceptions/basic_exception.hpp"
|
||||
|
||||
class OutOfMemory : public BasicException
|
||||
{
|
||||
public:
|
||||
using BasicException::BasicException;
|
||||
};
|
9
include/query/exception/plan_compilation.hpp
Normal file
9
include/query/exception/plan_compilation.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/exceptions/basic_exception.hpp"
|
||||
|
||||
class PlanCompilationException : public BasicException
|
||||
{
|
||||
public:
|
||||
using BasicException::BasicException;
|
||||
};
|
9
include/query/exception/plan_execution.hpp
Normal file
9
include/query/exception/plan_execution.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/exceptions/basic_exception.hpp"
|
||||
|
||||
class PlanExecutionException : public BasicException
|
||||
{
|
||||
public:
|
||||
using BasicException::BasicException;
|
||||
};
|
9
include/query/exception/query_engine.hpp
Normal file
9
include/query/exception/query_engine.hpp
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/exceptions/basic_exception.hpp"
|
||||
|
||||
class QueryEngineException : public BasicException
|
||||
{
|
||||
public:
|
||||
using BasicException::BasicException;
|
||||
};
|
33
include/query/frontend/cypher.hpp
Normal file
33
include/query/frontend/cypher.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "logging/loggable.hpp"
|
||||
#include "query/language/cypher/compiler.hpp"
|
||||
|
||||
// DEPRICATED
|
||||
|
||||
namespace cypher
|
||||
{
|
||||
|
||||
class Frontend
|
||||
{
|
||||
public:
|
||||
Frontend() {}
|
||||
|
||||
auto generate_ir(const std::string& query)
|
||||
{
|
||||
try {
|
||||
return compiler.syntax_tree(query);
|
||||
} catch (const BasicException &e) {
|
||||
// logger.error("Parsing error while processing query: {}", query);
|
||||
// logger.error(std::string(e.what()));
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
cypher::Compiler compiler;
|
||||
};
|
||||
|
||||
}
|
@ -2,13 +2,13 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "cypher/visitor/traverser.hpp"
|
||||
#include "query_engine/code_generator/cpp_generator.hpp"
|
||||
#include "query_engine/code_generator/entity_search.hpp"
|
||||
#include "query_engine/code_generator/structures.hpp"
|
||||
#include "query_engine/exceptions/exceptions.hpp"
|
||||
#include "query_engine/traverser/code.hpp"
|
||||
#include "logging/default.hpp"
|
||||
#include "query/backend/cpp_old/code.hpp"
|
||||
#include "query/backend/cpp_old/cpp_generator.hpp"
|
||||
#include "query/backend/cpp_old/entity_search.hpp"
|
||||
#include "query/backend/cpp_old/structures.hpp"
|
||||
#include "query/language/cypher/errors.hpp"
|
||||
#include "query/language/cypher/visitor/traverser.hpp"
|
||||
|
||||
struct SetElementState
|
||||
{
|
||||
@ -107,9 +107,10 @@ public:
|
||||
void semantic_check() const
|
||||
{
|
||||
if (!has_return)
|
||||
throw SemanticError("The query doesn't have RETURN clause. Next "
|
||||
"releases will support query without RETURN "
|
||||
"clause");
|
||||
throw CypherSemanticError(
|
||||
"The query doesn't have RETURN clause. Next "
|
||||
"releases will support query without RETURN "
|
||||
"clause");
|
||||
}
|
||||
|
||||
void visit(ast::WriteQuery &write_query) override
|
||||
@ -258,11 +259,8 @@ public:
|
||||
|
||||
Traverser::visit(ast_node);
|
||||
|
||||
// this is here because of RETURN clause
|
||||
// CREATE (n {...}) RETURN n
|
||||
if (cypher_data.status(name) != EntityStatus::Matched &&
|
||||
state == CypherState::Create)
|
||||
{
|
||||
state == CypherState::Create) {
|
||||
cypher_data.node_created(name);
|
||||
}
|
||||
}
|
||||
@ -300,8 +298,7 @@ public:
|
||||
auto &cypher_data = generator.cypher_data();
|
||||
auto &action_data = generator.action_data();
|
||||
|
||||
if (!ast_relationship.has_name())
|
||||
return;
|
||||
if (!ast_relationship.has_name()) return;
|
||||
entity = ast_relationship.name();
|
||||
|
||||
using ast_direction = ast::Relationship::Direction;
|
||||
@ -362,9 +359,9 @@ public:
|
||||
if (ast_relationship_type_list.has_value()) {
|
||||
auto type = ast_relationship_type_list.value->name;
|
||||
action_data.add_entity_tag(entity, type);
|
||||
action_data.csm.search_cost(
|
||||
entity, entity_search::search_type_index,
|
||||
entity_search::type_cost);
|
||||
action_data.csm.search_cost(entity,
|
||||
entity_search::search_type_index,
|
||||
entity_search::type_cost);
|
||||
}
|
||||
|
||||
Traverser::visit(ast_relationship_type_list);
|
||||
@ -411,7 +408,8 @@ public:
|
||||
|
||||
// update action data
|
||||
auto &action_data = generator.action_data();
|
||||
action_data.parameter_index.emplace(ParameterIndexKey(entity, prop), index);
|
||||
action_data.parameter_index.emplace(ParameterIndexKey(entity, prop),
|
||||
index);
|
||||
action_data.add_entitiy_property(entity, prop);
|
||||
|
||||
// update cypher data
|
||||
@ -469,7 +467,7 @@ public:
|
||||
auto entity_type = cypher_data.type(entity);
|
||||
|
||||
if (entity_type == EntityType::None)
|
||||
throw SemanticError("Entity (" + entity + ") doesn't exist");
|
||||
throw CypherSemanticError("Entity (" + entity + ") doesn't exist");
|
||||
|
||||
auto &action_data = generator.action_data();
|
||||
|
||||
@ -515,27 +513,27 @@ public:
|
||||
Traverser::visit(ast_set_value);
|
||||
}
|
||||
|
||||
void visit(ast::Delete& ast_delete) override
|
||||
void visit(ast::Delete &ast_delete) override
|
||||
{
|
||||
code += generator.generate();
|
||||
|
||||
state = CypherState::Delete;
|
||||
|
||||
generator.add_action(QueryAction::Delete);
|
||||
auto &action_data = generator.add_action(QueryAction::Delete);
|
||||
|
||||
Traverser::visit(ast_delete);
|
||||
|
||||
code += generator.generate();
|
||||
}
|
||||
|
||||
void visit(ast::CountFunction& ast_count) override
|
||||
void visit(ast::CountFunction &ast_count) override
|
||||
{
|
||||
auto &action_data = generator.action_data();
|
||||
auto &cypher_data = generator.cypher_data();
|
||||
|
||||
// if (state == CypherState::Return)
|
||||
// {
|
||||
action_data.actions[ast_count.argument] = ClauseAction::ReturnCount;
|
||||
action_data.actions[ast_count.argument] = ClauseAction::ReturnCount;
|
||||
// }
|
||||
}
|
||||
};
|
10
include/query/frontend/opencypher.hpp
Normal file
10
include/query/frontend/opencypher.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
namespace opencypher
|
||||
{
|
||||
|
||||
class Fronted
|
||||
{
|
||||
};
|
||||
|
||||
}
|
3
include/query/frontend/opencypher/traverser.hpp
Normal file
3
include/query/frontend/opencypher/traverser.hpp
Normal file
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
// TODO: implementation
|
@ -18,6 +18,7 @@ namespace barrier
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "communication/bolt/v1/serialization/bolt_serializer.hpp"
|
||||
#include "communication/bolt/v1/serialization/record_stream.hpp"
|
||||
#include "database/db.hpp"
|
||||
@ -37,7 +38,7 @@ namespace barrier
|
||||
#include "utils/iterator/iterator.hpp"
|
||||
#include "utils/option_ptr.hpp"
|
||||
#include "utils/reference_wrapper.hpp"
|
||||
#include "query_engine/util.hpp"
|
||||
#include "query/util.hpp"
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "query_engine/query_stripped.hpp"
|
||||
#include "query/strip/stripped.hpp"
|
||||
|
||||
#ifdef BARRIER
|
||||
#include "barrier/barrier.hpp"
|
||||
@ -12,19 +12,19 @@
|
||||
#endif
|
||||
|
||||
template <typename Stream>
|
||||
class ICodeCPU
|
||||
class IPlanCPU
|
||||
{
|
||||
public:
|
||||
#ifdef BARRIER
|
||||
virtual bool run(barrier::Db &db, code_args_t &args, Stream &stream) = 0;
|
||||
virtual bool run(barrier::Db &db, plan_args_t &args, Stream &stream) = 0;
|
||||
#else
|
||||
virtual bool run(Db &db, code_args_t &args, Stream &stream) = 0;
|
||||
virtual bool run(Db &db, plan_args_t &args, Stream &stream) = 0;
|
||||
#endif
|
||||
virtual ~ICodeCPU() {}
|
||||
virtual ~IPlanCPU() {}
|
||||
};
|
||||
|
||||
template <typename Stream>
|
||||
using produce_t = ICodeCPU<Stream> *(*)();
|
||||
using produce_t = IPlanCPU<Stream> *(*)();
|
||||
|
||||
template <typename Stream>
|
||||
using destruct_t = void (*)(ICodeCPU<Stream> *);
|
||||
using destruct_t = void (*)(IPlanCPU<Stream> *);
|
0
include/query/ir/tree/delete.hpp
Normal file
0
include/query/ir/tree/delete.hpp
Normal file
0
include/query/ir/tree/edge.hpp
Normal file
0
include/query/ir/tree/edge.hpp
Normal file
27
include/query/ir/tree/node.hpp
Normal file
27
include/query/ir/tree/node.hpp
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "query/backend/backend.hpp"
|
||||
|
||||
namespace ir
|
||||
{
|
||||
|
||||
class Node
|
||||
{
|
||||
public:
|
||||
virtual ~Node() {}
|
||||
|
||||
virtual void accept(Backend* visitor)
|
||||
{
|
||||
for (auto &child : childs)
|
||||
{
|
||||
visitor->process(child.get());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<Node>> childs;
|
||||
Node *parent;
|
||||
};
|
||||
}
|
5
include/query/ir/tree/query.hpp
Normal file
5
include/query/ir/tree/query.hpp
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
class Query : public Node
|
||||
{
|
||||
};
|
0
include/query/ir/tree/read.hpp
Normal file
0
include/query/ir/tree/read.hpp
Normal file
0
include/query/ir/tree/tree.hpp
Normal file
0
include/query/ir/tree/tree.hpp
Normal file
0
include/query/ir/tree/update.hpp
Normal file
0
include/query/ir/tree/update.hpp
Normal file
0
include/query/ir/tree/vertex.hpp
Normal file
0
include/query/ir/tree/vertex.hpp
Normal file
@ -8,10 +8,11 @@ namespace ast
|
||||
|
||||
struct Delete : public AstNode<Delete>
|
||||
{
|
||||
Delete(Identifier* identifier)
|
||||
: identifier(identifier) {}
|
||||
|
||||
Delete(Identifier* identifier, bool is_detached = false)
|
||||
: identifier(identifier), is_detached(is_detached) {}
|
||||
|
||||
Identifier* identifier;
|
||||
bool is_detached;
|
||||
};
|
||||
|
||||
}
|
@ -21,13 +21,13 @@
|
||||
printf("possible token: %s\n", yyTokenName[i]);
|
||||
}
|
||||
}
|
||||
throw SyntaxError(TOKEN->value);
|
||||
throw CypherSyntaxError(TOKEN->value);
|
||||
#endif
|
||||
}
|
||||
|
||||
%stack_overflow
|
||||
{
|
||||
throw ParserError("Parser stack overflow");
|
||||
throw CypherParsingError("Parser stack overflow");
|
||||
}
|
||||
|
||||
%name cypher_parser
|
||||
@ -38,10 +38,10 @@
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "cypher/token.hpp"
|
||||
#include "cypher/errors.hpp"
|
||||
#include "cypher/ast/ast.hpp"
|
||||
#include "cypher/ast/tree.hpp"
|
||||
#include "query/language/cypher/token.hpp"
|
||||
#include "query/language/cypher/errors.hpp"
|
||||
#include "query/language/cypher/ast/ast.hpp"
|
||||
#include "query/language/cypher/ast/tree.hpp"
|
||||
|
||||
#define DEBUG(X) std::cout << "PARSER: " << X << std::endl
|
||||
}
|
||||
@ -198,9 +198,15 @@ match_clause(M) ::= MATCH pattern_list(P) where_clause(W). {
|
||||
}
|
||||
|
||||
%type delete_clause {ast::Delete*}
|
||||
// TODO: add DETACH DELETE
|
||||
|
||||
// TODO: expression list support
|
||||
|
||||
delete_clause(D) ::= DELETE idn(I). {
|
||||
D = ast->create<ast::Delete>(I);
|
||||
D = ast->create<ast::Delete>(I, false);
|
||||
}
|
||||
|
||||
delete_clause(D) ::= DETACH DELETE idn(I). {
|
||||
D = ast->create<ast::Delete>(I, true);
|
||||
}
|
||||
|
||||
// ---- pattern list
|
@ -3,7 +3,7 @@
|
||||
#include <iostream>
|
||||
#include <stack>
|
||||
|
||||
#include "cypher/visitor/traverser.hpp"
|
||||
#include "query/language/cypher/visitor/traverser.hpp"
|
||||
|
||||
class PrintVisitor : public Traverser
|
||||
{
|
||||
@ -13,52 +13,48 @@ public:
|
||||
public:
|
||||
friend class Entry;
|
||||
|
||||
Printer(std::ostream& stream, const std::string& header)
|
||||
Printer(std::ostream &stream, const std::string &header)
|
||||
: stream(stream)
|
||||
{
|
||||
// stream << header;
|
||||
}
|
||||
|
||||
~Printer()
|
||||
{
|
||||
stream << std::endl;
|
||||
}
|
||||
~Printer() { stream << std::endl; }
|
||||
|
||||
class Entry
|
||||
{
|
||||
public:
|
||||
Entry(Printer& printer) : printer(printer), valid(true)
|
||||
Entry(Printer &printer) : printer(printer), valid(true)
|
||||
{
|
||||
printer.level++;
|
||||
|
||||
for(size_t i = 1; i < printer.level; ++i)
|
||||
for (size_t i = 1; i < printer.level; ++i)
|
||||
printer.stream << "| ";
|
||||
|
||||
printer.stream << "+--";
|
||||
}
|
||||
|
||||
Entry(const Entry&) = delete;
|
||||
Entry(const Entry &) = delete;
|
||||
|
||||
Entry(Entry&& other) : printer(other.printer), valid(true)
|
||||
Entry(Entry &&other) : printer(other.printer), valid(true)
|
||||
{
|
||||
other.valid = false;
|
||||
}
|
||||
|
||||
~Entry()
|
||||
{
|
||||
if(valid)
|
||||
printer.level--;
|
||||
if (valid) printer.level--;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Entry& operator<<(const T& item)
|
||||
Entry &operator<<(const T &item)
|
||||
{
|
||||
printer.stream << item;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
Printer& printer;
|
||||
Printer &printer;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
@ -68,7 +64,7 @@ public:
|
||||
return std::move(Entry(*this));
|
||||
}
|
||||
|
||||
Entry advance(const std::string& text)
|
||||
Entry advance(const std::string &text)
|
||||
{
|
||||
stream << std::endl;
|
||||
auto entry = Entry(*this);
|
||||
@ -77,116 +73,115 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
std::ostream& stream;
|
||||
std::ostream &stream;
|
||||
size_t level = 0;
|
||||
};
|
||||
|
||||
PrintVisitor(std::ostream& stream)
|
||||
: printer(stream, "Printing AST") {}
|
||||
PrintVisitor(std::ostream &stream) : printer(stream, "Printing AST") {}
|
||||
|
||||
void visit(ast::Start& start) override
|
||||
void visit(ast::Start &start) override
|
||||
{
|
||||
auto entry = printer.advance("Start");
|
||||
Traverser::visit(start);
|
||||
}
|
||||
|
||||
void visit(ast::ReadQuery& read_query) override
|
||||
void visit(ast::ReadQuery &read_query) override
|
||||
{
|
||||
auto entry = printer.advance("Read Query");
|
||||
Traverser::visit(read_query);
|
||||
}
|
||||
|
||||
void visit(ast::ReadWriteQuery& query) override
|
||||
void visit(ast::ReadWriteQuery &query) override
|
||||
{
|
||||
auto entry = printer.advance("Read Write Query");
|
||||
Traverser::visit(query);
|
||||
}
|
||||
|
||||
void visit(ast::Match& match) override
|
||||
void visit(ast::Match &match) override
|
||||
{
|
||||
auto entry = printer.advance("Match");
|
||||
Traverser::visit(match);
|
||||
}
|
||||
|
||||
void visit(ast::Pattern& pattern) override
|
||||
void visit(ast::Pattern &pattern) override
|
||||
{
|
||||
auto entry = printer.advance("Pattern");
|
||||
Traverser::visit(pattern);
|
||||
}
|
||||
|
||||
void visit(ast::PatternExpr& pattern_expr) override
|
||||
void visit(ast::PatternExpr &pattern_expr) override
|
||||
{
|
||||
auto entry = printer.advance("Pattern Expression");
|
||||
Traverser::visit(pattern_expr);
|
||||
}
|
||||
|
||||
void visit(ast::PatternList& pattern_list) override
|
||||
void visit(ast::PatternList &pattern_list) override
|
||||
{
|
||||
auto entry = printer.advance("Pattern List");
|
||||
Traverser::visit(pattern_list);
|
||||
}
|
||||
|
||||
void visit(ast::Node& node) override
|
||||
void visit(ast::Node &node) override
|
||||
{
|
||||
auto entry = printer.advance("Node");
|
||||
Traverser::visit(node);
|
||||
}
|
||||
|
||||
void visit(ast::Alias& alias) override
|
||||
void visit(ast::Alias &alias) override
|
||||
{
|
||||
auto entry = printer.advance();
|
||||
entry << "Alias: '" << alias.name << "' AS '" << alias.alias << "'";
|
||||
}
|
||||
|
||||
void visit(ast::Identifier& idn) override
|
||||
void visit(ast::Identifier &idn) override
|
||||
{
|
||||
auto entry = printer.advance();
|
||||
entry << "Identifier '" << idn.name << "'";
|
||||
}
|
||||
|
||||
void visit(ast::IdentifierList& list) override
|
||||
void visit(ast::IdentifierList &list) override
|
||||
{
|
||||
auto entry = printer.advance("Identifier List");
|
||||
Traverser::visit(list);
|
||||
}
|
||||
|
||||
void visit(ast::Return& return_clause) override
|
||||
void visit(ast::Return &return_clause) override
|
||||
{
|
||||
auto entry = printer.advance("Return");
|
||||
Traverser::visit(return_clause);
|
||||
}
|
||||
|
||||
void visit(ast::Distinct& distinct) override
|
||||
void visit(ast::Distinct &distinct) override
|
||||
{
|
||||
auto entry = printer.advance("Distinct");
|
||||
Traverser::visit(distinct);
|
||||
}
|
||||
|
||||
void visit(ast::Accessor& accessor) override
|
||||
void visit(ast::Accessor &accessor) override
|
||||
{
|
||||
auto entry = printer.advance("Accessor");
|
||||
Traverser::visit(accessor);
|
||||
}
|
||||
|
||||
void visit(ast::Boolean& boolean) override
|
||||
void visit(ast::Boolean &boolean) override
|
||||
{
|
||||
auto entry = printer.advance();
|
||||
entry << "Boolean " << boolean.value;
|
||||
}
|
||||
|
||||
void visit(ast::Float& floating) override
|
||||
void visit(ast::Float &floating) override
|
||||
{
|
||||
auto entry = printer.advance();
|
||||
entry << "Float " << floating.value;
|
||||
}
|
||||
|
||||
void visit(ast::Integer& integer) override
|
||||
void visit(ast::Integer &integer) override
|
||||
{
|
||||
auto entry = printer.advance();
|
||||
entry << "Integer " << integer.value;
|
||||
}
|
||||
|
||||
void visit(ast::Long& ast_long) override
|
||||
void visit(ast::Long &ast_long) override
|
||||
{
|
||||
auto entry = printer.advance();
|
||||
entry << "Long " << ast_long.value;
|
||||
@ -198,224 +193,227 @@ public:
|
||||
// entry << "ULong " << ulong.value;
|
||||
// }
|
||||
|
||||
void visit(ast::String& string) override
|
||||
void visit(ast::String &string) override
|
||||
{
|
||||
auto entry = printer.advance();
|
||||
entry << "String " << string.value;
|
||||
}
|
||||
|
||||
void visit(ast::InternalIdExpr& internal_id) override
|
||||
void visit(ast::InternalIdExpr &internal_id) override
|
||||
{
|
||||
auto entry = printer.advance("InternalId");
|
||||
Traverser::visit(internal_id);
|
||||
}
|
||||
|
||||
void visit(ast::Property& property) override
|
||||
void visit(ast::Property &property) override
|
||||
{
|
||||
auto entry = printer.advance("Property");
|
||||
Traverser::visit(property);
|
||||
}
|
||||
|
||||
void visit(ast::And& and_expr) override
|
||||
void visit(ast::And &and_expr) override
|
||||
{
|
||||
auto entry = printer.advance("And");
|
||||
Traverser::visit(and_expr);
|
||||
}
|
||||
|
||||
void visit(ast::Or& or_expr) override
|
||||
void visit(ast::Or &or_expr) override
|
||||
{
|
||||
auto entry = printer.advance("Or");
|
||||
Traverser::visit(or_expr);
|
||||
}
|
||||
|
||||
void visit(ast::Lt& lt_expr) override
|
||||
void visit(ast::Lt <_expr) override
|
||||
{
|
||||
auto entry = printer.advance("Less Than");
|
||||
Traverser::visit(lt_expr);
|
||||
}
|
||||
|
||||
void visit(ast::Gt& gt_expr) override
|
||||
void visit(ast::Gt >_expr) override
|
||||
{
|
||||
auto entry = printer.advance("Greater Than");
|
||||
Traverser::visit(gt_expr);
|
||||
}
|
||||
|
||||
void visit(ast::Ge& ge_expr) override
|
||||
void visit(ast::Ge &ge_expr) override
|
||||
{
|
||||
auto entry = printer.advance("Greater od Equal");
|
||||
Traverser::visit(ge_expr);
|
||||
}
|
||||
|
||||
void visit(ast::Le& le_expr) override
|
||||
void visit(ast::Le &le_expr) override
|
||||
{
|
||||
auto entry = printer.advance("Less or Equal");
|
||||
Traverser::visit(le_expr);
|
||||
}
|
||||
|
||||
void visit(ast::Eq& eq_expr) override
|
||||
void visit(ast::Eq &eq_expr) override
|
||||
{
|
||||
auto entry = printer.advance("Equal");
|
||||
Traverser::visit(eq_expr);
|
||||
}
|
||||
|
||||
void visit(ast::Ne& ne_expr) override
|
||||
void visit(ast::Ne &ne_expr) override
|
||||
{
|
||||
auto entry = printer.advance("Not Equal");
|
||||
Traverser::visit(ne_expr);
|
||||
}
|
||||
|
||||
void visit(ast::Plus& plus) override
|
||||
void visit(ast::Plus &plus) override
|
||||
{
|
||||
auto entry = printer.advance("Plus");
|
||||
Traverser::visit(plus);
|
||||
}
|
||||
|
||||
void visit(ast::Minus& minus) override
|
||||
void visit(ast::Minus &minus) override
|
||||
{
|
||||
auto entry = printer.advance("Minus");
|
||||
Traverser::visit(minus);
|
||||
}
|
||||
|
||||
void visit(ast::Star& star) override
|
||||
void visit(ast::Star &star) override
|
||||
{
|
||||
auto entry = printer.advance("Star");
|
||||
Traverser::visit(star);
|
||||
}
|
||||
|
||||
void visit(ast::Slash& slash) override
|
||||
void visit(ast::Slash &slash) override
|
||||
{
|
||||
auto entry = printer.advance("Slash");
|
||||
Traverser::visit(slash);
|
||||
}
|
||||
|
||||
void visit(ast::Rem& rem) override
|
||||
void visit(ast::Rem &rem) override
|
||||
{
|
||||
auto entry = printer.advance("Rem (%)");
|
||||
Traverser::visit(rem);
|
||||
}
|
||||
|
||||
void visit(ast::CountFunction& count) override
|
||||
void visit(ast::CountFunction &count) override
|
||||
{
|
||||
auto entry = printer.advance("Count ");
|
||||
entry << count.name << "(" << count.argument << ")";
|
||||
}
|
||||
|
||||
void visit(ast::LabelsFunction& labels) override
|
||||
void visit(ast::LabelsFunction &labels) override
|
||||
{
|
||||
auto entry = printer.advance("Labels ");
|
||||
entry << labels.name << "(" << labels.argument << ")";
|
||||
}
|
||||
|
||||
void visit(ast::PropertyList& prop_list) override
|
||||
void visit(ast::PropertyList &prop_list) override
|
||||
{
|
||||
auto entry = printer.advance("Property List");
|
||||
Traverser::visit(prop_list);
|
||||
}
|
||||
|
||||
void visit(ast::RelationshipTypeList& rel_list) override
|
||||
void visit(ast::RelationshipTypeList &rel_list) override
|
||||
{
|
||||
auto entry = printer.advance("Relationship Type List");
|
||||
Traverser::visit(rel_list);
|
||||
}
|
||||
|
||||
void visit(ast::Relationship& rel) override
|
||||
void visit(ast::Relationship &rel) override
|
||||
{
|
||||
auto entry = printer.advance("Relationship");
|
||||
entry << " direction: " << rel.direction;
|
||||
Traverser::visit(rel);
|
||||
}
|
||||
|
||||
void visit(ast::RelationshipSpecs& rel_specs) override
|
||||
void visit(ast::RelationshipSpecs &rel_specs) override
|
||||
{
|
||||
auto entry = printer.advance("Relationship Specs");
|
||||
Traverser::visit(rel_specs);
|
||||
}
|
||||
|
||||
void visit(ast::LabelList& labels) override
|
||||
void visit(ast::LabelList &labels) override
|
||||
{
|
||||
auto entry = printer.advance("Label List");
|
||||
Traverser::visit(labels);
|
||||
}
|
||||
|
||||
void visit(ast::ReturnList& return_list) override
|
||||
void visit(ast::ReturnList &return_list) override
|
||||
{
|
||||
auto entry = printer.advance("Return List");
|
||||
Traverser::visit(return_list);
|
||||
}
|
||||
|
||||
void visit(ast::Where& where) override
|
||||
void visit(ast::Where &where) override
|
||||
{
|
||||
auto entry = printer.advance("Where");
|
||||
Traverser::visit(where);
|
||||
}
|
||||
|
||||
void visit(ast::WriteQuery& write_query) override
|
||||
void visit(ast::WriteQuery &write_query) override
|
||||
{
|
||||
auto entry = printer.advance("Write Query");
|
||||
Traverser::visit(write_query);
|
||||
}
|
||||
|
||||
void visit(ast::DeleteQuery& delete_query) override
|
||||
void visit(ast::DeleteQuery &delete_query) override
|
||||
{
|
||||
auto entry = printer.advance("Delete Query");
|
||||
Traverser::visit(delete_query);
|
||||
}
|
||||
|
||||
void visit(ast::Delete& delete_clause) override
|
||||
void visit(ast::Delete &delete_clause) override
|
||||
{
|
||||
auto entry = printer.advance("Delete");
|
||||
auto is_detached = delete_clause.is_detached ? "yes" : "no";
|
||||
auto text_entry =
|
||||
std::string("Delete - DETACH: ") + std::string(is_detached);
|
||||
auto entry = printer.advance(text_entry);
|
||||
Traverser::visit(delete_clause);
|
||||
}
|
||||
|
||||
void visit(ast::Create& create) override
|
||||
void visit(ast::Create &create) override
|
||||
{
|
||||
auto entry = printer.advance("Create");
|
||||
Traverser::visit(create);
|
||||
}
|
||||
|
||||
void visit(ast::UpdateQuery& update_query) override
|
||||
void visit(ast::UpdateQuery &update_query) override
|
||||
{
|
||||
auto entry = printer.advance("Update Query");
|
||||
Traverser::visit(update_query);
|
||||
}
|
||||
|
||||
void visit(ast::Set& set_clause) override
|
||||
void visit(ast::Set &set_clause) override
|
||||
{
|
||||
auto entry = printer.advance("Set");
|
||||
Traverser::visit(set_clause);
|
||||
}
|
||||
|
||||
void visit(ast::SetValue& set_value) override
|
||||
void visit(ast::SetValue &set_value) override
|
||||
{
|
||||
auto entry = printer.advance("Set Value");
|
||||
Traverser::visit(set_value);
|
||||
}
|
||||
|
||||
void visit(ast::SetElement& set_element) override
|
||||
void visit(ast::SetElement &set_element) override
|
||||
{
|
||||
auto entry = printer.advance("Set Element");
|
||||
Traverser::visit(set_element);
|
||||
}
|
||||
|
||||
void visit(ast::SetList& set_list) override
|
||||
void visit(ast::SetList &set_list) override
|
||||
{
|
||||
auto entry = printer.advance("Set List");
|
||||
Traverser::visit(set_list);
|
||||
}
|
||||
|
||||
void visit(ast::WithClause& with_clause) override
|
||||
void visit(ast::WithClause &with_clause) override
|
||||
{
|
||||
auto entry = printer.advance("With Clause");
|
||||
Traverser::visit(with_clause);
|
||||
}
|
||||
|
||||
void visit(ast::WithList& with_list) override
|
||||
void visit(ast::WithList &with_list) override
|
||||
{
|
||||
auto entry = printer.advance("With List");
|
||||
Traverser::visit(with_list);
|
||||
}
|
||||
|
||||
void visit(ast::WithQuery& with_query) override
|
||||
void visit(ast::WithQuery &with_query) override
|
||||
{
|
||||
auto entry = printer.advance("With Query");
|
||||
Traverser::visit(with_query);
|
43
include/query/language/cypher/errors.hpp
Normal file
43
include/query/language/cypher/errors.hpp
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "token.hpp"
|
||||
#include "utils/exceptions/basic_exception.hpp"
|
||||
|
||||
class CypherParsingError : public BasicException
|
||||
{
|
||||
public:
|
||||
CypherParsingError(const std::string &what)
|
||||
: BasicException("Cypher Parsing Error: " + what)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class CypherLexicalError : public BasicException
|
||||
{
|
||||
public:
|
||||
CypherLexicalError(const Token &token)
|
||||
: BasicException("Cypher Lexical Error: unrecognized token '" +
|
||||
token.value + "'.")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class CypherSyntaxError : public BasicException
|
||||
{
|
||||
public:
|
||||
CypherSyntaxError(const std::string &near)
|
||||
: BasicException("Cypher Syntax Error: near '" + near + "'.")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class CypherSemanticError : public BasicException
|
||||
{
|
||||
public:
|
||||
CypherSemanticError(const std::string &what)
|
||||
: BasicException("Cypher Semanic Error: " + what)
|
||||
{
|
||||
}
|
||||
};
|
@ -48,6 +48,7 @@ public:
|
||||
rule("(?i:SET)", TK_SET);
|
||||
rule("(?i:RETURN)", TK_RETURN);
|
||||
rule("(?i:DISTINCT)", TK_DISTINCT);
|
||||
rule("(?i:DETACH)", TK_DETACH);
|
||||
rule("(?i:DELETE)", TK_DELETE);
|
||||
rule("(?i:WITH)", TK_WITH);
|
||||
// TODO: here should be better regex
|
@ -12,8 +12,8 @@
|
||||
#include "lexertl/lookup.hpp"
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#include "cypher/errors.hpp"
|
||||
#include "cypher/token.hpp"
|
||||
#include "query/language/cypher/errors.hpp"
|
||||
#include "query/language/cypher/token.hpp"
|
||||
|
||||
class Lexer
|
||||
{
|
||||
@ -56,7 +56,7 @@ public:
|
||||
auto token = Token {results.id, results.str()};
|
||||
|
||||
if(results.id == static_cast<decltype(results.id)>(-1))
|
||||
throw LexicalError(token);
|
||||
throw CypherLexicalError(token);
|
||||
|
||||
return token;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "cypher/ast/ast.hpp"
|
||||
#include "cypher/ast/ast_visitor.hpp"
|
||||
#include "query/language/cypher/ast/ast.hpp"
|
||||
#include "query/language/cypher/ast/ast_visitor.hpp"
|
||||
|
||||
class Traverser : public ast::AstVisitor
|
||||
{
|
@ -2,24 +2,24 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "exceptions/exceptions.hpp"
|
||||
#include "logging/default.hpp"
|
||||
#include "query/exception/plan_compilation.hpp"
|
||||
#include "utils/string/join.hpp"
|
||||
|
||||
// TODO:
|
||||
// * all libraries have to be compiled in the server compile time
|
||||
// * compile command has to be generated
|
||||
|
||||
class CodeCompiler
|
||||
class PlanCompiler
|
||||
{
|
||||
public:
|
||||
CodeCompiler() : logger(logging::log->logger("CodeCompiler")) {}
|
||||
PlanCompiler() : logger(logging::log->logger("PlanCompiler")) {}
|
||||
|
||||
void compile(const std::string &in_file, const std::string &out_file)
|
||||
{
|
||||
std::string flags;
|
||||
|
||||
// TODO: sync this with cmake configuration
|
||||
// TODO: sync this with cmake configuration
|
||||
#ifdef BARRIER
|
||||
flags += " -DBARRIER";
|
||||
#endif
|
||||
@ -46,14 +46,13 @@ public:
|
||||
auto compile_command = utils::prints(
|
||||
"clang++" + flags,
|
||||
// "-std=c++1y -O2 -DNDEBUG", // compile flags
|
||||
"-std=c++1y", // compile flags // TODO: load from config file
|
||||
in_file, // input file
|
||||
"-o", out_file, // ouput file
|
||||
"-I./include", // include paths (TODO: parameter)
|
||||
"-std=c++1y", // compile flags // TODO: load from config file
|
||||
in_file, // input file
|
||||
"-o", out_file, // ouput file
|
||||
"-I./include", // include paths (TODO: parameter)
|
||||
"-I../include",
|
||||
"-I../libs/fmt", // TODO: load from config
|
||||
"-I../../libs/fmt",
|
||||
"-L./ -L../",
|
||||
"-I../../libs/fmt", "-L./ -L../",
|
||||
#ifdef BARRIER
|
||||
"-lbarrier_pic",
|
||||
#endif
|
||||
@ -68,9 +67,9 @@ public:
|
||||
|
||||
// if compilation has failed throw exception
|
||||
if (compile_status == -1) {
|
||||
throw QueryEngineException("Code compilation error. Generated code "
|
||||
"is not compilable or compilation "
|
||||
"settings are wrong");
|
||||
throw PlanCompilationException(
|
||||
"Code compilation error. Generated code is not compilable or "
|
||||
"compilation settings are wrong");
|
||||
}
|
||||
|
||||
logger.debug("SUCCESS: Query Code Compilation: {} -> {}", in_file,
|
29
include/query/plan/generator.hpp
Normal file
29
include/query/plan/generator.hpp
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "config/config.hpp"
|
||||
#include "query/language/cypher/ast/ast.hpp"
|
||||
#include "query/language/cypher/compiler.hpp"
|
||||
#include "logging/loggable.hpp"
|
||||
#include "template_engine/engine.hpp"
|
||||
#include "utils/string/file.hpp"
|
||||
#include "utils/type_discovery.hpp"
|
||||
|
||||
template <typename Frontend, typename Backend>
|
||||
class PlanGenerator : public Loggable
|
||||
{
|
||||
public:
|
||||
PlanGenerator() : Loggable("PlanGenerator") {}
|
||||
|
||||
void generate_plan(const std::string &query, const uint64_t stripped_hash,
|
||||
const std::string &path)
|
||||
{
|
||||
// TODO: multithread environment TEST
|
||||
// multiple connections for the same query at the beginning
|
||||
auto ir = frontend.generate_ir(query);
|
||||
backend.generate_code(ir, query, stripped_hash, path);
|
||||
}
|
||||
|
||||
private:
|
||||
Frontend frontend;
|
||||
Backend backend;
|
||||
};
|
26
include/query/plan/program.hpp
Normal file
26
include/query/plan/program.hpp
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "query/i_plan_cpu.hpp"
|
||||
#include "query/strip/stripped.hpp"
|
||||
|
||||
/*
|
||||
* Query Program Contains:
|
||||
* * Query Plan
|
||||
* * Query Arguments (Stripped)
|
||||
*/
|
||||
template <typename Stream>
|
||||
struct QueryProgram
|
||||
{
|
||||
using plan_t = IPlanCPU<Stream>;
|
||||
|
||||
QueryProgram(plan_t *plan, QueryStripped &&stripped)
|
||||
: plan(plan), stripped(std::forward<QueryStripped>(stripped))
|
||||
{
|
||||
}
|
||||
|
||||
QueryProgram(QueryProgram &other) = delete;
|
||||
QueryProgram(QueryProgram &&other) = default;
|
||||
|
||||
plan_t *plan;
|
||||
QueryStripped stripped;
|
||||
};
|
@ -3,9 +3,10 @@
|
||||
#include <string>
|
||||
|
||||
#include "database/db.hpp"
|
||||
#include "query_engine/exceptions/exceptions.hpp"
|
||||
#include "query_engine/util.hpp"
|
||||
#include "query_program.hpp"
|
||||
#include "query/exception/query_engine.hpp"
|
||||
#include "query/exception/plan_execution.hpp"
|
||||
#include "query/plan/program.hpp"
|
||||
#include "query/util.hpp"
|
||||
|
||||
// preparations before execution
|
||||
// execution
|
||||
@ -28,16 +29,16 @@ public:
|
||||
auto execute(QueryProgram<Stream> &program, Db &db, Stream &stream)
|
||||
{
|
||||
try {
|
||||
// TODO: return result of query/code exection
|
||||
// TODO: return result of query/code exection
|
||||
#ifdef BARRIER
|
||||
return program.code->run(barrier::trans(db),
|
||||
return program.plan->run(barrier::trans(db),
|
||||
program.stripped.arguments, stream);
|
||||
#else
|
||||
return program.code->run(db, program.stripped.arguments, stream);
|
||||
return program.plan->run(db, program.stripped.arguments, stream);
|
||||
#endif
|
||||
// TODO: catch more exceptions
|
||||
} catch (...) {
|
||||
// TODO: return more information about the error
|
||||
throw QueryEngineException("code execution error");
|
||||
throw PlanExecutionException("");
|
||||
}
|
||||
}
|
||||
};
|
@ -5,16 +5,16 @@
|
||||
#include <unordered_map>
|
||||
|
||||
#include "config/config.hpp"
|
||||
#include "query_engine/code_compiler.hpp"
|
||||
#include "query_engine/code_generator.hpp"
|
||||
#include "query_engine/memgraph_dynamic_lib.hpp"
|
||||
#include "query_engine/query_program.hpp"
|
||||
#include "query_engine/query_stripper.hpp"
|
||||
#include "utils/hashing/fnv.hpp"
|
||||
#include "logging/default.hpp"
|
||||
#include "query/backend/cpp_old/cypher.hpp"
|
||||
#include "query/dynamic_lib.hpp"
|
||||
#include "query/frontend/cypher.hpp"
|
||||
#include "query/plan/compiler.hpp"
|
||||
#include "query/plan/generator.hpp"
|
||||
#include "query/plan/program.hpp"
|
||||
#include "query/preprocesor.hpp"
|
||||
#include "utils/file.hpp"
|
||||
|
||||
using std::string;
|
||||
#include "utils/hashing/fnv.hpp"
|
||||
|
||||
template <typename Stream>
|
||||
class ProgramLoader
|
||||
@ -24,40 +24,34 @@ public:
|
||||
using sptr_code_lib = std::shared_ptr<code_lib_t>;
|
||||
using query_program_t = QueryProgram<Stream>;
|
||||
|
||||
ProgramLoader() :
|
||||
logger(logging::log->logger("ProgramLoader")),
|
||||
stripper(make_query_stripper(TK_LONG, TK_FLOAT, TK_STR, TK_BOOL))
|
||||
ProgramLoader() : logger(logging::log->logger("PlanLoader")) {}
|
||||
|
||||
auto load(const std::string &query)
|
||||
{
|
||||
}
|
||||
auto preprocessed = preprocessor.preprocess(query);
|
||||
logger.debug("stripped_query = {}", preprocessed.query);
|
||||
logger.debug("query_hash = {}", std::to_string(preprocessed.hash));
|
||||
|
||||
auto load(const string &query)
|
||||
{
|
||||
auto stripped = stripper.strip(query);
|
||||
logger.debug("stripped_query = {}", stripped.query);
|
||||
|
||||
auto hash_string = std::to_string(stripped.hash);
|
||||
logger.debug("query_hash = {}", hash_string);
|
||||
|
||||
auto code_lib_iter = code_libs.find(stripped.hash);
|
||||
auto code_lib_iter = code_libs.find(preprocessed.hash);
|
||||
|
||||
// code is already compiled and loaded, just return runnable
|
||||
// instance
|
||||
if (code_lib_iter != code_libs.end()) {
|
||||
auto code = code_lib_iter->second->instance();
|
||||
return query_program_t(code, std::move(stripped));
|
||||
return query_program_t(code, std::move(preprocessed));
|
||||
}
|
||||
|
||||
auto base_path = CONFIG(config::COMPILE_CPU_PATH);
|
||||
auto hash_string = std::to_string(preprocessed.hash);
|
||||
auto path_cpp = base_path + hash_string + ".cpp";
|
||||
auto hard_code_cpp = base_path + "hardcode/" + hash_string + ".cpp";
|
||||
auto stripped_space = stripper.strip_space(query);
|
||||
auto stripped_space = preprocessor.strip_space(query);
|
||||
|
||||
// cpp files in the hardcode folder have bigger priority then
|
||||
// other cpp files
|
||||
if (!utils::fexists(hard_code_cpp))
|
||||
{
|
||||
code_generator.generate_cpp(stripped_space.query, stripped.hash,
|
||||
path_cpp);
|
||||
if (!utils::fexists(hard_code_cpp)) {
|
||||
plan_generator.generate_plan(stripped_space.query,
|
||||
preprocessed.hash, path_cpp);
|
||||
}
|
||||
|
||||
// compile the code
|
||||
@ -65,39 +59,39 @@ public:
|
||||
|
||||
// hardcoded queries are compiled to the same folder as generated
|
||||
// queries (all .so files are in the same folder)
|
||||
if (utils::fexists(hard_code_cpp))
|
||||
{
|
||||
code_compiler.compile(hard_code_cpp, path_so);
|
||||
}
|
||||
else
|
||||
{
|
||||
code_compiler.compile(path_cpp, path_so);
|
||||
if (utils::fexists(hard_code_cpp)) {
|
||||
plan_compiler.compile(hard_code_cpp, path_so);
|
||||
} else {
|
||||
plan_compiler.compile(path_cpp, path_so);
|
||||
}
|
||||
|
||||
// loads dynamic lib and store it
|
||||
auto code_lib = load_code_lib(path_so);
|
||||
code_libs.insert({{stripped.hash, code_lib}});
|
||||
code_libs.insert({{preprocessed.hash, code_lib}});
|
||||
|
||||
// return an instance of runnable code (ICodeCPU)
|
||||
return query_program_t(code_lib->instance(), std::move(stripped));
|
||||
return query_program_t(code_lib->instance(), std::move(preprocessed));
|
||||
}
|
||||
|
||||
protected:
|
||||
Logger logger;
|
||||
|
||||
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
|
||||
std::unordered_map<uint64_t, sptr_code_lib> code_libs;
|
||||
|
||||
CodeGenerator<Stream> code_generator;
|
||||
CodeCompiler code_compiler;
|
||||
QueryPreprocessor preprocessor;
|
||||
|
||||
sptr_code_lib load_code_lib(const string &path)
|
||||
// TODO: compile time switch between frontends and backends
|
||||
using frontend_t = cypher::Frontend;
|
||||
using backend_t = CypherBackend<Stream>;
|
||||
PlanGenerator<frontend_t, backend_t> plan_generator;
|
||||
|
||||
PlanCompiler plan_compiler;
|
||||
|
||||
sptr_code_lib load_code_lib(const std::string &path)
|
||||
{
|
||||
sptr_code_lib code_lib = std::make_shared<CodeLib<Stream>>(path);
|
||||
code_lib->load();
|
31
include/query/preprocesor.hpp
Normal file
31
include/query/preprocesor.hpp
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "query/strip/stripper.hpp"
|
||||
|
||||
/*
|
||||
* Query preprocessing contains:
|
||||
* * query stripping
|
||||
*
|
||||
* The preprocessing results are:
|
||||
* * stripped query |
|
||||
* * stripped arguments |-> QueryStripped
|
||||
* * stripped query hash |
|
||||
*/
|
||||
class QueryPreprocessor
|
||||
{
|
||||
public:
|
||||
QueryPreprocessor()
|
||||
: stripper(make_query_stripper(TK_LONG, TK_FLOAT, TK_STR, TK_BOOL))
|
||||
{
|
||||
}
|
||||
|
||||
auto strip_space(const std::string& query)
|
||||
{
|
||||
return stripper.strip_space(query);
|
||||
}
|
||||
|
||||
auto preprocess(const std::string &query) { return stripper.strip(query); }
|
||||
|
||||
private:
|
||||
QueryStripper<int, int, int, int> stripper;
|
||||
};
|
32
include/query/strip/stripped.hpp
Normal file
32
include/query/strip/stripped.hpp
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "storage/model/properties/property.hpp"
|
||||
|
||||
/*
|
||||
* Query Plan Arguments Type
|
||||
*/
|
||||
using plan_args_t = std::vector<Property>;
|
||||
|
||||
/*
|
||||
* QueryStripped contains:
|
||||
* * stripped query
|
||||
* * plan arguments stripped from query
|
||||
* * hash of stripped query
|
||||
*/
|
||||
struct QueryStripped
|
||||
{
|
||||
QueryStripped(const std::string &&query, plan_args_t &&arguments,
|
||||
uint64_t hash)
|
||||
: query(std::forward<const std::string>(query)),
|
||||
arguments(std::forward<plan_args_t>(arguments)), hash(hash)
|
||||
{
|
||||
}
|
||||
QueryStripped(QueryStripped &other) = delete;
|
||||
QueryStripped(QueryStripped &&other) = default;
|
||||
|
||||
std::string query;
|
||||
plan_args_t arguments;
|
||||
uint64_t hash;
|
||||
};
|
@ -7,9 +7,9 @@
|
||||
#include <utility>
|
||||
|
||||
#include "cypher/cypher.h"
|
||||
#include "cypher/tokenizer/cypher_lexer.hpp"
|
||||
#include "logging/default.hpp"
|
||||
#include "query_stripped.hpp"
|
||||
#include "logging/loggable.hpp"
|
||||
#include "query/language/cypher/tokenizer/cypher_lexer.hpp"
|
||||
#include "query/strip/stripped.hpp"
|
||||
#include "storage/model/properties/all.hpp"
|
||||
#include "utils/hashing/fnv.hpp"
|
||||
#include "utils/string/transform.hpp"
|
||||
@ -17,17 +17,16 @@
|
||||
|
||||
// TODO: Maybe std::move(v) is faster, but it must be cheked for validity.
|
||||
template <class T, class V>
|
||||
void store_query_param(code_args_t &arguments, V &&v)
|
||||
void store_query_param(plan_args_t &arguments, V &&v)
|
||||
{
|
||||
arguments.emplace_back(Property(T(std::move(v)), T::type));
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
class QueryStripper
|
||||
class QueryStripper : public Loggable
|
||||
{
|
||||
public:
|
||||
QueryStripper(Ts &&... strip_types)
|
||||
: logger(logging::log->logger("QueryStripper")),
|
||||
QueryStripper(Ts &&... strip_types) : Loggable("QueryStripper"),
|
||||
strip_types(std::make_tuple(std::forward<Ts>(strip_types)...)),
|
||||
lexer(std::make_unique<CypherLexer>())
|
||||
{
|
||||
@ -35,17 +34,15 @@ public:
|
||||
|
||||
QueryStripper(QueryStripper &other) = delete;
|
||||
|
||||
QueryStripper(QueryStripper &&other)
|
||||
: strip_types(std::move(other.strip_types)),
|
||||
QueryStripper(QueryStripper &&other) : Loggable("QueryStripper"),
|
||||
strip_types(std::move(other.strip_types)),
|
||||
lexer(std::move(other.lexer))
|
||||
{
|
||||
}
|
||||
|
||||
auto strip_space(const std::string &query)
|
||||
{
|
||||
auto stripped = strip(query, " ");
|
||||
return QueryStripped(std::move(stripped.query), stripped.hash,
|
||||
std::move(stripped.arguments));
|
||||
return strip(query, " ");
|
||||
}
|
||||
|
||||
auto strip(const std::string &query, const std::string &separator = "")
|
||||
@ -60,13 +57,14 @@ public:
|
||||
constexpr auto size = std::tuple_size<decltype(strip_types)>::value;
|
||||
|
||||
int counter = 0;
|
||||
code_args_t stripped_arguments;
|
||||
plan_args_t stripped_arguments;
|
||||
std::string stripped_query;
|
||||
stripped_query.reserve(query.size());
|
||||
|
||||
while (auto token = tokenizer.lookup()) {
|
||||
// TODO: better implementation
|
||||
if (_or(token.id, strip_types, std::make_index_sequence<size>{})) {
|
||||
while (auto token = tokenizer.lookup())
|
||||
{
|
||||
if (_or(token.id, strip_types, std::make_index_sequence<size>{}))
|
||||
{
|
||||
auto index = counter++;
|
||||
switch (token.id) {
|
||||
case TK_LONG:
|
||||
@ -90,7 +88,7 @@ public:
|
||||
std::stof(token.value));
|
||||
break;
|
||||
default:
|
||||
// TODO: other propertys
|
||||
// TODO: other properties
|
||||
assert(false);
|
||||
}
|
||||
stripped_query += std::to_string(index) + separator;
|
||||
@ -100,12 +98,13 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
return QueryStripped(std::move(stripped_query), fnv(stripped_query),
|
||||
std::move(stripped_arguments));
|
||||
auto hash = fnv(stripped_query);
|
||||
return QueryStripped(std::move(stripped_query),
|
||||
std::move(stripped_arguments),
|
||||
hash);
|
||||
}
|
||||
|
||||
private:
|
||||
Logger logger;
|
||||
std::tuple<Ts...> strip_types;
|
||||
CypherLexer::uptr lexer;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user