Compare commits

...

1 Commits

Author SHA1 Message Date
Andreja Tonev
1c30643b06 Split SHOW DATABASES in two 2024-01-04 15:50:06 +01:00
8 changed files with 63 additions and 41 deletions

View File

@@ -3553,7 +3553,7 @@ class MultiDatabaseQuery : public memgraph::query::Query {
DEFVISITABLE(QueryVisitor<void>);
enum class Action { CREATE, USE, DROP };
enum class Action { CREATE, USE, DROP, SHOW };
memgraph::query::MultiDatabaseQuery::Action action_;
std::string db_name_;

View File

@@ -2853,6 +2853,14 @@ antlrcpp::Any CypherMainVisitor::visitDropDatabase(MemgraphCypher::DropDatabaseC
return mdb_query;
}
antlrcpp::Any CypherMainVisitor::visitShowDatabase(MemgraphCypher::ShowDatabaseContext * /*ctx*/) {
auto *mdb_query = storage_->Create<MultiDatabaseQuery>();
mdb_query->db_name_ = "";
mdb_query->action_ = MultiDatabaseQuery::Action::SHOW;
query_ = mdb_query;
return mdb_query;
}
antlrcpp::Any CypherMainVisitor::visitShowDatabases(MemgraphCypher::ShowDatabasesContext * /*ctx*/) {
query_ = storage_->Create<ShowDatabasesQuery>();
return query_;

View File

@@ -985,6 +985,11 @@ class CypherMainVisitor : public antlropencypher::MemgraphCypherBaseVisitor {
*/
antlrcpp::Any visitDropDatabase(MemgraphCypher::DropDatabaseContext *ctx) override;
/**
* @return MultiDatabaseQuery*
*/
antlrcpp::Any visitShowDatabase(MemgraphCypher::ShowDatabaseContext *ctx) override;
/**
* @return ShowDatabasesQuery*
*/

View File

@@ -480,6 +480,7 @@ transactionId : literal ;
multiDatabaseQuery : createDatabase
| useDatabase
| dropDatabase
| showDatabase
;
createDatabase : CREATE DATABASE databaseName ;
@@ -488,6 +489,8 @@ useDatabase : USE DATABASE databaseName ;
dropDatabase : DROP DATABASE databaseName ;
showDatabase : SHOW DATABASE ;
showDatabases : SHOW DATABASES ;
edgeImportModeQuery : EDGE IMPORT MODE ( ACTIVE | INACTIVE ) ;

View File

@@ -106,6 +106,7 @@ class PrivilegeExtractor : public QueryVisitor<void>, public HierarchicalTreeVis
AddPrivilege(AuthQuery::Privilege::MULTI_DATABASE_EDIT);
break;
case MultiDatabaseQuery::Action::USE:
case MultiDatabaseQuery::Action::SHOW:
AddPrivilege(AuthQuery::Privilege::MULTI_DATABASE_USE);
break;
}

View File

@@ -3522,48 +3522,54 @@ PreparedQuery PrepareMultiDatabaseQuery(ParsedQuery parsed_query, CurrentDB &cur
},
RWType::W,
query->db_name_};
}
case MultiDatabaseQuery::Action::SHOW:
return PreparedQuery{
{"Current"},
std::move(parsed_query.required_privileges),
[storage = current_db.db_acc_->get()->storage(), pull_plan = std::shared_ptr<PullPlanVector>(nullptr)](
AnyStream *stream, std::optional<int> n) mutable -> std::optional<QueryHandlerResult> {
if (!pull_plan) {
std::vector<std::vector<TypedValue>> results;
results.push_back({TypedValue(storage->id())});
pull_plan = std::make_shared<PullPlanVector>(std::move(results));
}
if (pull_plan->Pull(stream, n)) {
return QueryHandlerResult::NOTHING;
}
return std::nullopt;
},
RWType::NONE,
"" // No target DB
};
};
#else
throw QueryException("Query not supported.");
#endif
}
PreparedQuery PrepareShowDatabasesQuery(ParsedQuery parsed_query, CurrentDB &current_db,
InterpreterContext *interpreter_context,
PreparedQuery PrepareShowDatabasesQuery(ParsedQuery parsed_query, InterpreterContext *interpreter_context,
const std::optional<std::string> &username) {
#ifdef MG_ENTERPRISE
// TODO: split query into two, Databases (no need for current_db), & Current database (uses current_db)
MG_ASSERT(current_db.db_acc_, "Show Database Level query expects a current DB");
storage::Storage *storage = current_db.db_acc_->get()->storage();
if (!license::global_license_checker.IsEnterpriseValidFast()) {
throw QueryException("Trying to use enterprise feature without a valid license.");
}
// TODO pick directly from ic
auto *db_handler = interpreter_context->dbms_handler;
AuthQueryHandler *auth = interpreter_context->auth;
Callback callback;
callback.header = {"Name", "Current"};
callback.fn = [auth, storage, db_handler, username]() mutable -> std::vector<std::vector<TypedValue>> {
callback.header = {"Name"};
callback.fn = [auth, db_handler, username]() mutable -> std::vector<std::vector<TypedValue>> {
std::vector<std::vector<TypedValue>> status;
const auto &in_use = storage->id();
bool found_current = false;
auto gen_status = [&]<typename T, typename K>(T all, K denied) {
Sort(all);
Sort(denied);
status.reserve(all.size());
for (const auto &name : all) {
TypedValue use("");
if (!found_current && Same(name, in_use)) {
use = TypedValue("*");
found_current = true;
}
status.push_back({TypedValue(name), std::move(use)});
status.push_back({TypedValue(name)});
}
// No denied databases (no need to filter them out)
@@ -3593,7 +3599,6 @@ PreparedQuery PrepareShowDatabasesQuery(ParsedQuery parsed_query, CurrentDB &cur
}
}
if (!found_current) throw QueryRuntimeException("Missing current database!");
return status;
};
@@ -3847,9 +3852,7 @@ Interpreter::PrepareResult Interpreter::Prepare(const std::string &query_string,
prepared_query =
PrepareMultiDatabaseQuery(std::move(parsed_query), current_db_, interpreter_context_, on_change_);
} else if (utils::Downcast<ShowDatabasesQuery>(parsed_query.query)) {
/// SYSTEM PURE ("SHOW DATABASES")
/// INTERPRETER (TODO: "SHOW DATABASE")
prepared_query = PrepareShowDatabasesQuery(std::move(parsed_query), current_db_, interpreter_context_, username_);
prepared_query = PrepareShowDatabasesQuery(std::move(parsed_query), interpreter_context_, username_);
} else if (utils::Downcast<EdgeImportModeQuery>(parsed_query.query)) {
if (in_explicit_transaction_) {
throw EdgeImportModeModificationInMulticommandTxException();

View File

@@ -23,13 +23,20 @@ def test_show_databases_w_user():
user3_connection = common.connect(username="user3", password="test")
assert common.execute_and_fetch_all(admin_connection.cursor(), "SHOW DATABASES") == [
("db1", ""),
("db2", ""),
("memgraph", "*"),
("db1",),
("db2",),
("memgraph",),
]
assert common.execute_and_fetch_all(user_connection.cursor(), "SHOW DATABASES") == [("db1", ""), ("memgraph", "*")]
assert common.execute_and_fetch_all(user2_connection.cursor(), "SHOW DATABASES") == [("db2", "*")]
assert common.execute_and_fetch_all(user3_connection.cursor(), "SHOW DATABASES") == [("db1", "*"), ("db2", "")]
assert common.execute_and_fetch_all(admin_connection.cursor(), "SHOW DATABASE") == [("memgraph",)]
assert common.execute_and_fetch_all(user_connection.cursor(), "SHOW DATABASES") == [("db1",), ("memgraph",)]
assert common.execute_and_fetch_all(user_connection.cursor(), "SHOW DATABASE") == [("memgraph",)]
assert common.execute_and_fetch_all(user2_connection.cursor(), "SHOW DATABASES") == [("db2",)]
assert common.execute_and_fetch_all(user2_connection.cursor(), "SHOW DATABASE") == [("db2",)]
assert common.execute_and_fetch_all(user3_connection.cursor(), "SHOW DATABASES") == [("db1",), ("db2",)]
assert common.execute_and_fetch_all(user3_connection.cursor(), "SHOW DATABASE") == [("db1",)]
if __name__ == "__main__":

View File

@@ -87,18 +87,13 @@ void SwitchToDB(const std::string &name, std::unique_ptr<mg::Client> &client) {
void SwitchToCleanDB(std::unique_ptr<mg::Client> &client) { SwitchToDB("clean", client); }
void SwitchToSameDB(std::unique_ptr<mg::Client> &main, std::unique_ptr<mg::Client> &client) {
MG_ASSERT(main->Execute("SHOW DATABASES;"));
MG_ASSERT(main->Execute("SHOW DATABASE;"));
auto dbs = main->FetchAll();
MG_ASSERT(dbs, "Failed to show databases");
for (const auto &elem : *dbs) {
MG_ASSERT(!elem.empty(), "Show databases wrong output");
const auto &active = elem[1].ValueString();
if (active == "*") {
const auto &name = elem[0].ValueString();
SwitchToDB(std::string(name), client);
break;
}
}
MG_ASSERT(!dbs->empty(), "Show databases wrong output");
MG_ASSERT(!(*dbs)[0].empty(), "Show databases wrong output");
const auto &name = (*dbs)[0][0].ValueString();
SwitchToDB(std::string(name), client);
}
void TestSnapshotIsolation(std::unique_ptr<mg::Client> &client) {