Compare commits
1 Commits
release/2.
...
MG_show_da
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c30643b06 |
@@ -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_;
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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*
|
||||
*/
|
||||
|
||||
@@ -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 ) ;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 ¤t_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();
|
||||
|
||||
@@ -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__":
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user