Decouple interactive planning manual test (#585)

This commit is contained in:
Marko Budiselić 2022-10-21 13:34:13 +02:00 committed by GitHub
parent e5437080c5
commit 1c3bb969e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 547 additions and 289 deletions

View File

@ -35,12 +35,18 @@ target_link_libraries(${test_prefix}kvstore_console mg-kvstore gflags mg-utils)
add_manual_test(query_hash.cpp)
target_link_libraries(${test_prefix}query_hash mg-query)
add_manual_test(query_planner.cpp interactive_planning.cpp)
add_manual_test(query_planner.cpp interactive/planning.cpp)
target_link_libraries(${test_prefix}query_planner mg-query)
if (READLINE_FOUND)
target_link_libraries(${test_prefix}query_planner readline)
endif()
add_manual_test(query_execution_dummy.cpp)
target_link_libraries(${test_prefix}query_execution_dummy mg-query)
if (READLINE_FOUND)
target_link_libraries(${test_prefix}query_execution_dummy readline)
endif()
add_manual_test(expression_pretty_printer.cpp)
target_link_libraries(${test_prefix}expression_pretty_printer mg-query)

View File

@ -9,82 +9,13 @@
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#include "interactive_planning.hpp"
#pragma once
#include <chrono>
#include <cstdlib>
#include <optional>
#include <string>
#include <gflags/gflags.h>
#include "query/context.hpp"
#include "query/db_accessor.hpp"
#include "query/frontend/ast/cypher_main_visitor.hpp"
#include "query/frontend/opencypher/parser.hpp"
#include "query/frontend/semantic/symbol_generator.hpp"
#include "query/plan/operator.hpp"
#include "query/plan/planner.hpp"
#include "query/plan/pretty_print.hpp"
#include "query/typed_value.hpp"
#include "storage/v2/property_value.hpp"
#include "utils/string.hpp"
#include "readline.hpp"
#include "timer.hpp"
DEFINE_string(save_mock_db_file, "", "File where the mock database should be saved (on exit)");
DEFINE_string(load_mock_db_file, "", "File from which the mock database should be loaded");
#ifdef HAS_READLINE
// TODO: This should probably be moved to some utils file.
#include "readline/history.h"
#include "readline/readline.h"
/**
* Helper function that reads a line from the
* standard input using the 'readline' lib.
* Adds support for history and reverse-search.
*
* @param prompt The prompt to display.
* @return A single command the user entered, or nullopt on EOF.
*/
std::optional<std::string> ReadLine(const std::string &prompt) {
char *line = readline(prompt.c_str());
if (!line) return std::nullopt;
if (*line) add_history(line);
std::string r_val(line);
free(line);
return r_val;
}
#else
std::optional<std::string> ReadLine(const std::string &prompt) {
std::cout << prompt;
std::string line;
std::getline(std::cin, line);
if (std::cin.eof()) return std::nullopt;
return line;
}
#endif // HAS_READLINE
// Repeats the prompt untile the user inputs an integer.
int64_t ReadInt(const std::string &prompt) {
int64_t val = 0;
std::stringstream ss;
do {
auto line = ReadLine(prompt);
if (!line) continue;
ss.str(*line);
ss.clear();
ss >> val;
} while (ss.fail() || !ss.eof());
return val;
}
bool AskYesNo(const std::string &prompt) {
inline bool AskYesNo(const std::string &prompt) {
while (auto line = ReadLine(prompt + " (y/n) ")) {
if (*line == "y" || *line == "Y") return true;
if (*line == "n" || *line == "N") return false;
@ -92,48 +23,6 @@ bool AskYesNo(const std::string &prompt) {
return false;
}
class Timer {
public:
void Start() {
duration_ = duration_.zero();
start_time_ = std::chrono::steady_clock::now();
}
void Pause() {
if (pause_ == 0) {
duration_ += std::chrono::steady_clock::now() - start_time_;
}
++pause_;
}
void Resume() {
if (pause_ == 1) {
start_time_ = std::chrono::steady_clock::now();
}
pause_ = std::max(0, pause_ - 1);
}
template <class TFun>
auto WithPause(const TFun &fun) {
Pause();
auto ret = fun();
Resume();
return std::move(ret);
}
std::chrono::duration<double> Elapsed() {
if (pause_ == 0) {
return duration_ + (std::chrono::steady_clock::now() - start_time_);
}
return duration_;
}
private:
std::chrono::duration<double> duration_;
std::chrono::time_point<std::chrono::steady_clock> start_time_;
int pause_ = 0;
};
// Dummy DbAccessor which forwards user input for various vertex counts.
class InteractiveDbAccessor {
public:
@ -343,164 +232,3 @@ class InteractiveDbAccessor {
return memgraph::storage::PropertyValue(val);
}
};
DEFCOMMAND(Top) {
int64_t n_plans = 0;
std::stringstream ss(args[0]);
ss >> n_plans;
if (ss.fail() || !ss.eof()) return;
n_plans = std::min(static_cast<int64_t>(plans.size()), n_plans);
for (int64_t i = 0; i < n_plans; ++i) {
std::cout << "---- Plan #" << i << " ---- " << std::endl;
std::cout << "cost: " << plans[i].cost << std::endl;
memgraph::query::plan::PrettyPrint(dba, plans[i].final_plan.get());
std::cout << std::endl;
}
}
DEFCOMMAND(Show) {
int64_t plan_ix = 0;
std::stringstream ss(args[0]);
ss >> plan_ix;
if (ss.fail() || !ss.eof() || plan_ix >= plans.size()) return;
const auto &plan = plans[plan_ix].final_plan;
auto cost = plans[plan_ix].cost;
std::cout << "Plan cost: " << cost << std::endl;
memgraph::query::plan::PrettyPrint(dba, plan.get());
}
DEFCOMMAND(ShowUnoptimized) {
int64_t plan_ix = 0;
std::stringstream ss(args[0]);
ss >> plan_ix;
if (ss.fail() || !ss.eof() || plan_ix >= plans.size()) return;
const auto &plan = plans[plan_ix].unoptimized_plan;
memgraph::query::plan::PrettyPrint(dba, plan.get());
}
DEFCOMMAND(Help);
std::map<std::string, Command> commands = {
{"top", {TopCommand, 1, "Show top N plans"}},
{"show", {ShowCommand, 1, "Show the Nth plan"}},
{"show-unoptimized", {ShowUnoptimizedCommand, 1, "Show the Nth plan in its original, unoptimized form"}},
{"help", {HelpCommand, 0, "Show available commands"}},
};
void AddCommand(const std::string &name, const Command &command) { commands[name] = command; }
DEFCOMMAND(Help) {
std::cout << "Available commands:" << std::endl;
for (const auto &command : commands) {
std::cout << command.first;
for (int i = 1; i <= command.second.arg_count; ++i) {
std::cout << " arg" << i;
}
std::cout << " -- " << command.second.documentation << std::endl;
}
}
void ExaminePlans(memgraph::query::DbAccessor *dba, const memgraph::query::SymbolTable &symbol_table,
std::vector<InteractivePlan> &plans, const memgraph::query::AstStorage &ast) {
while (true) {
auto line = ReadLine("plan? ");
if (!line || *line == "quit") break;
auto words = memgraph::utils::Split(memgraph::utils::ToLowerCase(*line));
if (words.empty()) continue;
auto command_name = words[0];
std::vector<std::string> args(words.begin() + 1, words.end());
auto command_it = commands.find(command_name);
if (command_it == commands.end()) {
std::cout << "Undefined command: '" << command_name << "'. Try 'help'." << std::endl;
continue;
}
const auto &command = command_it->second;
if (args.size() < command.arg_count) {
std::cout << command_name << " expects " << command.arg_count << " arguments" << std::endl;
continue;
}
command.function(*dba, symbol_table, plans, args, ast);
}
}
memgraph::query::Query *MakeAst(const std::string &query, memgraph::query::AstStorage *storage) {
memgraph::query::frontend::ParsingContext parsing_context;
parsing_context.is_query_cached = false;
// query -> AST
auto parser = std::make_unique<memgraph::query::frontend::opencypher::Parser>(query);
// AST -> high level tree
memgraph::query::frontend::CypherMainVisitor visitor(parsing_context, storage);
visitor.visit(parser->tree());
return visitor.query();
}
// Returns a list of InteractivePlan instances, sorted in the ascending order by
// cost.
auto MakeLogicalPlans(memgraph::query::CypherQuery *query, memgraph::query::AstStorage &ast,
memgraph::query::SymbolTable &symbol_table, InteractiveDbAccessor *dba) {
auto query_parts = memgraph::query::plan::CollectQueryParts(symbol_table, ast, query);
std::vector<InteractivePlan> interactive_plans;
auto ctx = memgraph::query::plan::MakePlanningContext(&ast, &symbol_table, query, dba);
if (query_parts.query_parts.size() <= 0) {
std::cerr << "Failed to extract query parts" << std::endl;
std::exit(EXIT_FAILURE);
}
memgraph::query::Parameters parameters;
memgraph::query::plan::PostProcessor post_process(parameters);
auto plans = memgraph::query::plan::MakeLogicalPlanForSingleQuery<memgraph::query::plan::VariableStartPlanner>(
query_parts.query_parts.at(0).single_query_parts, &ctx);
for (auto plan : plans) {
memgraph::query::AstStorage ast_copy;
auto unoptimized_plan = plan->Clone(&ast_copy);
auto rewritten_plan = post_process.Rewrite(std::move(plan), &ctx);
double cost = post_process.EstimatePlanCost(rewritten_plan, dba);
interactive_plans.push_back(
InteractivePlan{std::move(unoptimized_plan), std::move(ast_copy), std::move(rewritten_plan), cost});
}
std::stable_sort(interactive_plans.begin(), interactive_plans.end(),
[](const auto &a, const auto &b) { return a.cost < b.cost; });
return interactive_plans;
}
void RunInteractivePlanning(memgraph::query::DbAccessor *dba) {
std::string in_db_filename(memgraph::utils::Trim(FLAGS_load_mock_db_file));
if (!in_db_filename.empty() && !std::filesystem::exists(in_db_filename)) {
std::cerr << "File '" << in_db_filename << "' does not exist!" << std::endl;
std::exit(EXIT_FAILURE);
}
Timer planning_timer;
InteractiveDbAccessor interactive_db(dba, in_db_filename.empty() ? ReadInt("Vertices in DB: ") : 0, planning_timer);
if (!in_db_filename.empty()) {
std::ifstream db_file(in_db_filename);
interactive_db.Load(db_file);
}
while (true) {
auto line = ReadLine("query? ");
if (!line || *line == "quit") break;
if (line->empty()) continue;
try {
memgraph::query::AstStorage ast;
auto *query = dynamic_cast<memgraph::query::CypherQuery *>(MakeAst(*line, &ast));
if (!query) {
throw memgraph::utils::BasicException(
"Interactive planning is only avaialable for regular openCypher "
"queries.");
}
auto symbol_table = memgraph::query::MakeSymbolTable(query);
planning_timer.Start();
auto plans = MakeLogicalPlans(query, ast, symbol_table, &interactive_db);
auto planning_time = planning_timer.Elapsed();
std::cout << "Planning took " << std::chrono::duration<double, std::milli>(planning_time).count() << "ms"
<< std::endl;
std::cout << "Generated " << plans.size() << " plans" << std::endl;
ExaminePlans(dba, symbol_table, plans, ast);
} catch (const memgraph::utils::BasicException &e) {
std::cout << "Error: " << e.what() << std::endl;
}
}
std::string db_filename(memgraph::utils::Trim(FLAGS_save_mock_db_file));
if (!db_filename.empty()) {
std::ofstream db_file(db_filename);
interactive_db.Save(db_file);
}
}

View File

@ -0,0 +1,70 @@
// Copyright 2022 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#pragma once
#include <string>
#include "query/frontend/ast/cypher_main_visitor.hpp"
#include "query/frontend/opencypher/parser.hpp"
#include "query/plan/planner.hpp"
#include "db_accessor.hpp"
struct InteractivePlan {
// Original plan after going only through the RuleBasedPlanner.
std::unique_ptr<memgraph::query::plan::LogicalOperator> unoptimized_plan;
// Storage for the AST used in unoptimized_plan
memgraph::query::AstStorage ast_storage;
// Final plan after being rewritten and optimized.
std::unique_ptr<memgraph::query::plan::LogicalOperator> final_plan;
// Cost of the final plan.
double cost;
};
inline memgraph::query::Query *MakeAst(const std::string &query, memgraph::query::AstStorage *storage) {
memgraph::query::frontend::ParsingContext parsing_context;
parsing_context.is_query_cached = false;
// query -> AST
auto parser = std::make_unique<memgraph::query::frontend::opencypher::Parser>(query);
// AST -> high level tree
memgraph::query::frontend::CypherMainVisitor visitor(parsing_context, storage);
visitor.visit(parser->tree());
return visitor.query();
}
// Returns a list of InteractivePlan instances, sorted in the ascending order by
// cost.
inline auto MakeLogicalPlans(memgraph::query::CypherQuery *query, memgraph::query::AstStorage &ast,
memgraph::query::SymbolTable &symbol_table, InteractiveDbAccessor *dba) {
auto query_parts = memgraph::query::plan::CollectQueryParts(symbol_table, ast, query);
std::vector<InteractivePlan> interactive_plans;
auto ctx = memgraph::query::plan::MakePlanningContext(&ast, &symbol_table, query, dba);
if (query_parts.query_parts.size() <= 0) {
std::cerr << "Failed to extract query parts" << std::endl;
std::exit(EXIT_FAILURE);
}
memgraph::query::Parameters parameters;
memgraph::query::plan::PostProcessor post_process(parameters);
auto plans = memgraph::query::plan::MakeLogicalPlanForSingleQuery<memgraph::query::plan::VariableStartPlanner>(
query_parts.query_parts.at(0).single_query_parts, &ctx);
for (auto plan : plans) {
memgraph::query::AstStorage ast_copy;
auto unoptimized_plan = plan->Clone(&ast_copy);
auto rewritten_plan = post_process.Rewrite(std::move(plan), &ctx);
double cost = post_process.EstimatePlanCost(rewritten_plan, dba);
interactive_plans.push_back(
InteractivePlan{std::move(unoptimized_plan), std::move(ast_copy), std::move(rewritten_plan), cost});
}
std::stable_sort(interactive_plans.begin(), interactive_plans.end(),
[](const auto &a, const auto &b) { return a.cost < b.cost; });
return interactive_plans;
}

View File

@ -0,0 +1,158 @@
// Copyright 2022 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#include "planning.hpp"
#include <chrono>
#include <cstdlib>
#include <optional>
#include <string>
#include <gflags/gflags.h>
#include "db_accessor.hpp"
#include "plan.hpp"
#include "query/context.hpp"
#include "query/db_accessor.hpp"
#include "query/frontend/ast/cypher_main_visitor.hpp"
#include "query/frontend/opencypher/parser.hpp"
#include "query/frontend/semantic/symbol_generator.hpp"
#include "query/plan/operator.hpp"
#include "query/plan/planner.hpp"
#include "query/plan/pretty_print.hpp"
#include "query/typed_value.hpp"
#include "storage/v2/property_value.hpp"
#include "utils/string.hpp"
DEFINE_string(save_mock_db_file, "", "File where the mock database should be saved (on exit)");
DEFINE_string(load_mock_db_file, "", "File from which the mock database should be loaded");
DEFCOMMAND(Top) {
int64_t n_plans = 0;
std::stringstream ss(args[0]);
ss >> n_plans;
if (ss.fail() || !ss.eof()) return;
n_plans = std::min(static_cast<int64_t>(plans.size()), n_plans);
for (int64_t i = 0; i < n_plans; ++i) {
std::cout << "---- Plan #" << i << " ---- " << std::endl;
std::cout << "cost: " << plans[i].cost << std::endl;
memgraph::query::plan::PrettyPrint(dba, plans[i].final_plan.get());
std::cout << std::endl;
}
}
DEFCOMMAND(Show) {
int64_t plan_ix = 0;
std::stringstream ss(args[0]);
ss >> plan_ix;
if (ss.fail() || !ss.eof() || plan_ix >= plans.size()) return;
const auto &plan = plans[plan_ix].final_plan;
auto cost = plans[plan_ix].cost;
std::cout << "Plan cost: " << cost << std::endl;
memgraph::query::plan::PrettyPrint(dba, plan.get());
}
DEFCOMMAND(ShowUnoptimized) {
int64_t plan_ix = 0;
std::stringstream ss(args[0]);
ss >> plan_ix;
if (ss.fail() || !ss.eof() || plan_ix >= plans.size()) return;
const auto &plan = plans[plan_ix].unoptimized_plan;
memgraph::query::plan::PrettyPrint(dba, plan.get());
}
DEFCOMMAND(Help);
std::map<std::string, Command> commands = {
{"top", {TopCommand, 1, "Show top N plans"}},
{"show", {ShowCommand, 1, "Show the Nth plan"}},
{"show-unoptimized", {ShowUnoptimizedCommand, 1, "Show the Nth plan in its original, unoptimized form"}},
{"help", {HelpCommand, 0, "Show available commands"}},
};
void AddCommand(const std::string &name, const Command &command) { commands[name] = command; }
DEFCOMMAND(Help) {
std::cout << "Available commands:" << std::endl;
for (const auto &command : commands) {
std::cout << command.first;
for (int i = 1; i <= command.second.arg_count; ++i) {
std::cout << " arg" << i;
}
std::cout << " -- " << command.second.documentation << std::endl;
}
}
void ExaminePlans(memgraph::query::DbAccessor *dba, const memgraph::query::SymbolTable &symbol_table,
std::vector<InteractivePlan> &plans, const memgraph::query::AstStorage &ast) {
while (true) {
auto line = ReadLine("plan? ");
if (!line || *line == "quit") break;
auto words = memgraph::utils::Split(memgraph::utils::ToLowerCase(*line));
if (words.empty()) continue;
auto command_name = words[0];
std::vector<std::string> args(words.begin() + 1, words.end());
auto command_it = commands.find(command_name);
if (command_it == commands.end()) {
std::cout << "Undefined command: '" << command_name << "'. Try 'help'." << std::endl;
continue;
}
const auto &command = command_it->second;
if (args.size() < command.arg_count) {
std::cout << command_name << " expects " << command.arg_count << " arguments" << std::endl;
continue;
}
command.function(*dba, symbol_table, plans, args, ast);
}
}
void RunInteractivePlanning(memgraph::query::DbAccessor *dba) {
std::string in_db_filename(memgraph::utils::Trim(FLAGS_load_mock_db_file));
if (!in_db_filename.empty() && !std::filesystem::exists(in_db_filename)) {
std::cerr << "File '" << in_db_filename << "' does not exist!" << std::endl;
std::exit(EXIT_FAILURE);
}
Timer planning_timer;
InteractiveDbAccessor interactive_db(dba, in_db_filename.empty() ? ReadInt("Vertices in DB: ") : 0, planning_timer);
if (!in_db_filename.empty()) {
std::ifstream db_file(in_db_filename);
interactive_db.Load(db_file);
}
while (true) {
auto line = ReadLine("query? ");
if (!line || *line == "quit") break;
if (line->empty()) continue;
try {
memgraph::query::AstStorage ast;
auto *query = dynamic_cast<memgraph::query::CypherQuery *>(MakeAst(*line, &ast));
if (!query) {
throw memgraph::utils::BasicException(
"Interactive planning is only avaialable for regular openCypher "
"queries.");
}
auto symbol_table = memgraph::query::MakeSymbolTable(query);
planning_timer.Start();
auto plans = MakeLogicalPlans(query, ast, symbol_table, &interactive_db);
auto planning_time = planning_timer.Elapsed();
std::cout << "Planning took " << std::chrono::duration<double, std::milli>(planning_time).count() << "ms"
<< std::endl;
std::cout << "Generated " << plans.size() << " plans" << std::endl;
ExaminePlans(dba, symbol_table, plans, ast);
} catch (const memgraph::utils::BasicException &e) {
std::cout << "Error: " << e.what() << std::endl;
}
}
std::string db_filename(memgraph::utils::Trim(FLAGS_save_mock_db_file));
if (!db_filename.empty()) {
std::ofstream db_file(db_filename);
interactive_db.Save(db_file);
}
}

View File

@ -21,21 +21,12 @@
#include "query/frontend/semantic/symbol_table.hpp"
#include "query/plan/operator.hpp"
#include "plan.hpp"
namespace database {
class GraphDbAccessor;
}
struct InteractivePlan {
// Original plan after going only through the RuleBasedPlanner.
std::unique_ptr<memgraph::query::plan::LogicalOperator> unoptimized_plan;
// Storage for the AST used in unoptimized_plan
memgraph::query::AstStorage ast_storage;
// Final plan after being rewritten and optimized.
std::unique_ptr<memgraph::query::plan::LogicalOperator> final_plan;
// Cost of the final plan.
double cost;
};
typedef std::vector<InteractivePlan> PlansWithCost;
// Encapsulates a consoles command function.

View File

@ -0,0 +1,65 @@
// Copyright 2022 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#pragma once
#include <optional>
#include <string>
#ifdef HAS_READLINE
// TODO: This should probably be moved to some utils file.
#include "readline/history.h"
#include "readline/readline.h"
/**
* Helper function that reads a line from the
* standard input using the 'readline' lib.
* Adds support for history and reverse-search.
*
* @param prompt The prompt to display.
* @return A single command the user entered, or nullopt on EOF.
*/
inline std::optional<std::string> ReadLine(const std::string &prompt) {
char *line = readline(prompt.c_str());
if (!line) return std::nullopt;
if (*line) add_history(line);
std::string r_val(line);
free(line);
return r_val;
}
#else
inline std::optional<std::string> ReadLine(const std::string &prompt) {
std::cout << prompt;
std::string line;
std::getline(std::cin, line);
if (std::cin.eof()) return std::nullopt;
return line;
}
#endif // HAS_READLINE
// Repeats the prompt untile the user inputs an integer.
inline int64_t ReadInt(const std::string &prompt) {
int64_t val = 0;
std::stringstream ss;
do {
auto line = ReadLine(prompt);
if (!line) continue;
ss.str(*line);
ss.clear();
ss >> val;
} while (ss.fail() || !ss.eof());
return val;
}

View File

@ -0,0 +1,57 @@
// Copyright 2022 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#pragma once
#include <algorithm>
#include <chrono>
class Timer {
public:
void Start() {
duration_ = duration_.zero();
start_time_ = std::chrono::steady_clock::now();
}
void Pause() {
if (pause_ == 0) {
duration_ += std::chrono::steady_clock::now() - start_time_;
}
++pause_;
}
void Resume() {
if (pause_ == 1) {
start_time_ = std::chrono::steady_clock::now();
}
pause_ = std::max(0, pause_ - 1);
}
template <class TFun>
auto WithPause(const TFun &fun) {
Pause();
auto ret = fun();
Resume();
return std::move(ret);
}
std::chrono::duration<double> Elapsed() {
if (pause_ == 0) {
return duration_ + (std::chrono::steady_clock::now() - start_time_);
}
return duration_;
}
private:
std::chrono::duration<double> duration_;
std::chrono::time_point<std::chrono::steady_clock> start_time_;
int pause_ = 0;
};

View File

@ -0,0 +1,183 @@
// Copyright 2022 Memgraph Ltd.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
// License, and you may not use this file except in compliance with the Business Source License.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#include "interactive/planning.hpp"
#include <chrono>
#include <thread>
#include <gflags/gflags.h>
#include "interactive/db_accessor.hpp"
#include "interactive/plan.hpp"
#include "query/frontend/semantic/symbol_generator.hpp"
#include "storage/v2/storage.hpp"
#include "utils/string.hpp"
namespace memgraph::query::plan {
class TestLogicalOperatorVisitor final : public HierarchicalLogicalOperatorVisitor {
public:
TestLogicalOperatorVisitor() {}
using HierarchicalLogicalOperatorVisitor::PostVisit;
using HierarchicalLogicalOperatorVisitor::PreVisit;
using HierarchicalLogicalOperatorVisitor::Visit;
void Start() {}
bool IsDone() { return true; }
bool Visit(Once &) override {
std::cout << "Visit Once" << std::endl;
return true;
}
bool PreVisit(Filter &op) override { return true; }
bool PostVisit(Filter &op) override { return true; }
bool PreVisit(ScanAll &op) override {
std::cout << "PreVisit ScanAll, output " << op.output_symbol_.name_ << std::endl;
return true;
}
bool PostVisit(ScanAll &scan) override { return true; }
bool PreVisit(Expand &op) override { return true; }
bool PostVisit(Expand &expand) override { return true; }
bool PreVisit(ExpandVariable &op) override { return true; }
bool PostVisit(ExpandVariable &expand) override { return true; }
bool PreVisit(Merge &op) override { return false; }
bool PostVisit(Merge &) override { return true; }
bool PreVisit(Optional &op) override { return false; }
bool PostVisit(Optional &) override { return true; }
bool PreVisit(Cartesian &op) override { return true; }
bool PostVisit(Cartesian &) override { return true; }
bool PreVisit(Union &op) override { return false; }
bool PostVisit(Union &) override { return true; }
bool PreVisit(CreateNode &op) override { return true; }
bool PostVisit(CreateNode &) override { return true; }
bool PreVisit(CreateExpand &op) override { return true; }
bool PostVisit(CreateExpand &) override { return true; }
bool PreVisit(ScanAllByLabel &op) override { return true; }
bool PostVisit(ScanAllByLabel &) override { return true; }
bool PreVisit(ScanAllByLabelPropertyRange &op) override { return true; }
bool PostVisit(ScanAllByLabelPropertyRange &) override { return true; }
bool PreVisit(ScanAllByLabelPropertyValue &op) override { return true; }
bool PostVisit(ScanAllByLabelPropertyValue &) override { return true; }
bool PreVisit(ScanAllByLabelProperty &op) override { return true; }
bool PostVisit(ScanAllByLabelProperty &) override { return true; }
bool PreVisit(ScanAllById &op) override { return true; }
bool PostVisit(ScanAllById &) override { return true; }
bool PreVisit(ConstructNamedPath &op) override { return true; }
bool PostVisit(ConstructNamedPath &) override { return true; }
bool PreVisit(Produce &op) override {
std::cout << "PreVisit Produce, named expressions: ";
for (const auto &name_expr : op.named_expressions_) {
std::cout << name_expr->name_ << " ";
}
std::cout << std::endl;
return true;
}
bool PostVisit(Produce &) override { return true; }
bool PreVisit(Delete &op) override { return true; }
bool PostVisit(Delete &) override { return true; }
bool PreVisit(SetProperty &op) override { return true; }
bool PostVisit(SetProperty &) override { return true; }
bool PreVisit(SetProperties &op) override { return true; }
bool PostVisit(SetProperties &) override { return true; }
bool PreVisit(SetLabels &op) override { return true; }
bool PostVisit(SetLabels &) override { return true; }
bool PreVisit(RemoveProperty &op) override { return true; }
bool PostVisit(RemoveProperty &) override { return true; }
bool PreVisit(RemoveLabels &op) override { return true; }
bool PostVisit(RemoveLabels &) override { return true; }
bool PreVisit(EdgeUniquenessFilter &op) override { return true; }
bool PostVisit(EdgeUniquenessFilter &) override { return true; }
bool PreVisit(Accumulate &op) override { return true; }
bool PostVisit(Accumulate &) override { return true; }
bool PreVisit(Aggregate &op) override { return true; }
bool PostVisit(Aggregate &) override { return true; }
bool PreVisit(Skip &op) override { return true; }
bool PostVisit(Skip &) override { return true; }
bool PreVisit(Limit &op) override { return true; }
bool PostVisit(Limit &) override { return true; }
bool PreVisit(OrderBy &op) override { return true; }
bool PostVisit(OrderBy &) override { return true; }
bool PreVisit(Unwind &op) override { return true; }
bool PostVisit(Unwind &) override { return true; }
bool PreVisit(Distinct &op) override { return true; }
bool PostVisit(Distinct &) override { return true; }
bool PreVisit(CallProcedure &op) override { return true; }
bool PostVisit(CallProcedure &) override { return true; }
};
} // namespace memgraph::query::plan
int main(int argc, char *argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
spdlog::set_level(spdlog::level::info);
memgraph::storage::Storage db;
auto storage_dba = db.Access();
memgraph::query::DbAccessor dba(&storage_dba);
Timer planning_timer;
InteractiveDbAccessor interactive_db(&dba, 10, planning_timer);
std::string input_query = "MATCH (n) RETURN n;";
memgraph::query::AstStorage ast;
auto *query = dynamic_cast<memgraph::query::CypherQuery *>(MakeAst(input_query, &ast));
if (!query) {
throw memgraph::utils::BasicException("Create CypherQuery failed");
}
auto symbol_table = memgraph::query::MakeSymbolTable(query);
planning_timer.Start();
auto plans = MakeLogicalPlans(query, ast, symbol_table, &interactive_db);
if (plans.size() == 0) {
throw memgraph::utils::BasicException("No plans");
}
memgraph::query::plan::TestLogicalOperatorVisitor executor;
plans[0].unoptimized_plan->Accept(executor);
executor.Start();
while (!executor.IsDone()) {
std::cout << "Executor NOT done yet" << std::endl;
}
std::cout << "Executor done" << std::endl;
return 0;
}

View File

@ -9,7 +9,7 @@
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
#include "interactive_planning.hpp"
#include "interactive/planning.hpp"
#include <gflags/gflags.h>