mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-03 13:02:00 +00:00
commit
6d80ab1eed
@ -128,6 +128,9 @@
|
||||
<!-- Directory with user provided files that are accessible by 'file' table function. -->
|
||||
<user_files_path>/var/lib/clickhouse/user_files/</user_files_path>
|
||||
|
||||
<!-- Path to folder where users and roles created by SQL commands are stored. -->
|
||||
<access_control_path>/var/lib/clickhouse/access/</access_control_path>
|
||||
|
||||
<!-- Path to configuration file with users, access rights, profiles of settings, quotas. -->
|
||||
<users_config>users.xml</users_config>
|
||||
|
||||
|
@ -83,6 +83,9 @@
|
||||
|
||||
<!-- Quota for user. -->
|
||||
<quota>default</quota>
|
||||
|
||||
<!-- User can create other users and grant rights to them. -->
|
||||
<!-- <access_management>1</access_management> -->
|
||||
</default>
|
||||
</users>
|
||||
|
||||
|
@ -23,7 +23,10 @@ namespace
|
||||
std::vector<std::unique_ptr<IAccessStorage>> list;
|
||||
list.emplace_back(std::make_unique<DiskAccessStorage>());
|
||||
list.emplace_back(std::make_unique<UsersConfigAccessStorage>());
|
||||
|
||||
#if 0 /// Memory access storage is disabled.
|
||||
list.emplace_back(std::make_unique<MemoryAccessStorage>());
|
||||
#endif
|
||||
return list;
|
||||
}
|
||||
|
||||
|
@ -5,12 +5,19 @@
|
||||
#include <Common/Exception.h>
|
||||
#include <ext/range.h>
|
||||
#include <ext/push_back.h>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <bitset>
|
||||
#include <unordered_map>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int LOGICAL_ERROR;
|
||||
}
|
||||
|
||||
/// Represents a combination of access types which can be granted globally, on databases, tables, columns, etc.
|
||||
/// For example "SELECT, CREATE USER" is an access type.
|
||||
class AccessFlags
|
||||
@ -175,9 +182,10 @@ public:
|
||||
const Flags & getDictionaryFlags() const { return all_flags_for_target[DICTIONARY]; }
|
||||
|
||||
private:
|
||||
enum Target
|
||||
enum NodeType
|
||||
{
|
||||
UNKNOWN_TARGET,
|
||||
UNKNOWN = -2,
|
||||
GROUP = -1,
|
||||
GLOBAL,
|
||||
DATABASE,
|
||||
TABLE,
|
||||
@ -186,46 +194,190 @@ private:
|
||||
DICTIONARY,
|
||||
};
|
||||
|
||||
static constexpr size_t NUM_TARGETS = static_cast<size_t>(DICTIONARY) + 1;
|
||||
|
||||
struct Node;
|
||||
using NodePtr = std::unique_ptr<Node>;
|
||||
using Nodes = std::vector<NodePtr>;
|
||||
|
||||
template <typename... Args>
|
||||
static Nodes nodes(Args&& ... args)
|
||||
{
|
||||
Nodes res;
|
||||
ext::push_back(res, std::move(args)...);
|
||||
return res;
|
||||
}
|
||||
|
||||
struct Node
|
||||
{
|
||||
std::string_view keyword;
|
||||
std::vector<String> aliases;
|
||||
const String keyword;
|
||||
NodeType node_type;
|
||||
AccessType type = AccessType::NONE;
|
||||
Strings aliases;
|
||||
Flags flags;
|
||||
Target target = UNKNOWN_TARGET;
|
||||
Nodes children;
|
||||
std::vector<NodePtr> children;
|
||||
|
||||
Node(std::string_view keyword_, size_t flag_, Target target_)
|
||||
: keyword(keyword_), target(target_)
|
||||
Node(String keyword_, NodeType node_type_ = UNKNOWN) : keyword(std::move(keyword_)), node_type(node_type_) {}
|
||||
|
||||
void setFlag(size_t flag) { flags.set(flag); }
|
||||
|
||||
void addChild(NodePtr child)
|
||||
{
|
||||
flags.set(flag_);
|
||||
flags |= child->flags;
|
||||
children.push_back(std::move(child));
|
||||
}
|
||||
|
||||
Node(std::string_view keyword_, Nodes children_)
|
||||
: keyword(keyword_), children(std::move(children_))
|
||||
{
|
||||
for (const auto & child : children)
|
||||
flags |= child->flags;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
Node(std::string_view keyword_, NodePtr first_child, Args &&... other_children)
|
||||
: Node(keyword_, nodes(std::move(first_child), std::move(other_children)...)) {}
|
||||
};
|
||||
|
||||
static String replaceUnderscoreWithSpace(const std::string_view & str)
|
||||
{
|
||||
String res{str};
|
||||
boost::replace_all(res, "_", " ");
|
||||
return res;
|
||||
}
|
||||
|
||||
static Strings splitAliases(const std::string_view & str)
|
||||
{
|
||||
Strings aliases;
|
||||
boost::split(aliases, str, boost::is_any_of(","));
|
||||
for (auto & alias : aliases)
|
||||
boost::trim(alias);
|
||||
return aliases;
|
||||
}
|
||||
|
||||
static void makeFlagsToKeywordTreeNode(
|
||||
AccessType type,
|
||||
const std::string_view & name,
|
||||
const std::string_view & aliases,
|
||||
NodeType node_type,
|
||||
const std::string_view & parent_group_name,
|
||||
std::unordered_map<std::string_view, Node *> & nodes,
|
||||
std::unordered_map<std::string_view, NodePtr> & owned_nodes,
|
||||
size_t & next_flag)
|
||||
{
|
||||
NodePtr node;
|
||||
auto keyword = replaceUnderscoreWithSpace(name);
|
||||
auto it = owned_nodes.find(keyword);
|
||||
if (it != owned_nodes.end())
|
||||
{
|
||||
node = std::move(it->second);
|
||||
owned_nodes.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nodes.contains(keyword))
|
||||
throw Exception(keyword + " declared twice", ErrorCodes::LOGICAL_ERROR);
|
||||
node = std::make_unique<Node>(keyword, node_type);
|
||||
nodes[node->keyword] = node.get();
|
||||
}
|
||||
|
||||
node->type = type;
|
||||
node->node_type = node_type;
|
||||
node->aliases = splitAliases(aliases);
|
||||
if (node_type != GROUP)
|
||||
node->setFlag(next_flag++);
|
||||
|
||||
bool has_parent_group = (parent_group_name != "NONE");
|
||||
if (!has_parent_group)
|
||||
{
|
||||
std::string_view keyword_as_string_view = node->keyword;
|
||||
owned_nodes[keyword_as_string_view] = std::move(node);
|
||||
return;
|
||||
}
|
||||
|
||||
auto parent_keyword = replaceUnderscoreWithSpace(parent_group_name);
|
||||
auto it_parent = nodes.find(parent_keyword);
|
||||
if (it_parent == nodes.end())
|
||||
{
|
||||
auto parent_node = std::make_unique<Node>(parent_keyword);
|
||||
it_parent = nodes.emplace(parent_node->keyword, parent_node.get()).first;
|
||||
assert(!owned_nodes.contains(parent_node->keyword));
|
||||
std::string_view parent_keyword_as_string_view = parent_node->keyword;
|
||||
owned_nodes[parent_keyword_as_string_view] = std::move(parent_node);
|
||||
}
|
||||
it_parent->second->addChild(std::move(node));
|
||||
}
|
||||
|
||||
void makeFlagsToKeywordTree()
|
||||
{
|
||||
std::unordered_map<std::string_view, NodePtr> owned_nodes;
|
||||
std::unordered_map<std::string_view, Node *> nodes;
|
||||
size_t next_flag = 0;
|
||||
|
||||
#define MAKE_ACCESS_FLAGS_TO_KEYWORD_TREE_NODE(name, aliases, node_type, parent_group_name) \
|
||||
makeFlagsToKeywordTreeNode(AccessType::name, #name, aliases, node_type, #parent_group_name, nodes, owned_nodes, next_flag);
|
||||
|
||||
APPLY_FOR_ACCESS_TYPES(MAKE_ACCESS_FLAGS_TO_KEYWORD_TREE_NODE)
|
||||
|
||||
#undef MAKE_ACCESS_FLAGS_TO_KEYWORD_TREE_NODE
|
||||
|
||||
if (!owned_nodes.contains("NONE"))
|
||||
throw Exception("'NONE' not declared", ErrorCodes::LOGICAL_ERROR);
|
||||
if (!owned_nodes.contains("ALL"))
|
||||
throw Exception("'ALL' not declared", ErrorCodes::LOGICAL_ERROR);
|
||||
|
||||
flags_to_keyword_tree = std::move(owned_nodes["ALL"]);
|
||||
none_node = std::move(owned_nodes["NONE"]);
|
||||
owned_nodes.erase("ALL");
|
||||
owned_nodes.erase("NONE");
|
||||
|
||||
if (!owned_nodes.empty())
|
||||
{
|
||||
const auto & unused_node = *(owned_nodes.begin()->second);
|
||||
if (unused_node.node_type == UNKNOWN)
|
||||
throw Exception("Parent group '" + unused_node.keyword + "' not found", ErrorCodes::LOGICAL_ERROR);
|
||||
else
|
||||
throw Exception("Access type '" + unused_node.keyword + "' should have parent group", ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
void makeKeywordToFlagsMap(Node * start_node = nullptr)
|
||||
{
|
||||
if (!start_node)
|
||||
{
|
||||
makeKeywordToFlagsMap(none_node.get());
|
||||
start_node = flags_to_keyword_tree.get();
|
||||
}
|
||||
|
||||
start_node->aliases.emplace_back(start_node->keyword);
|
||||
for (auto & alias : start_node->aliases)
|
||||
{
|
||||
boost::to_upper(alias);
|
||||
keyword_to_flags_map[alias] = start_node->flags;
|
||||
}
|
||||
|
||||
for (auto & child : start_node->children)
|
||||
makeKeywordToFlagsMap(child.get());
|
||||
}
|
||||
|
||||
void makeAccessTypeToFlagsMapping(Node * start_node = nullptr)
|
||||
{
|
||||
if (!start_node)
|
||||
{
|
||||
makeAccessTypeToFlagsMapping(none_node.get());
|
||||
start_node = flags_to_keyword_tree.get();
|
||||
}
|
||||
|
||||
size_t index = static_cast<size_t>(start_node->type);
|
||||
access_type_to_flags_mapping.resize(std::max(index + 1, access_type_to_flags_mapping.size()));
|
||||
access_type_to_flags_mapping[index] = start_node->flags;
|
||||
|
||||
for (auto & child : start_node->children)
|
||||
makeAccessTypeToFlagsMapping(child.get());
|
||||
}
|
||||
|
||||
void collectAllFlags(const Node * start_node = nullptr)
|
||||
{
|
||||
if (!start_node)
|
||||
{
|
||||
start_node = flags_to_keyword_tree.get();
|
||||
all_flags = start_node->flags;
|
||||
}
|
||||
if (start_node->node_type != GROUP)
|
||||
{
|
||||
assert(static_cast<size_t>(start_node->node_type) < std::size(all_flags_for_target));
|
||||
all_flags_for_target[start_node->node_type] |= start_node->flags;
|
||||
}
|
||||
for (const auto & child : start_node->children)
|
||||
collectAllFlags(child.get());
|
||||
}
|
||||
|
||||
Impl()
|
||||
{
|
||||
makeFlagsToKeywordTree();
|
||||
makeKeywordToFlagsMap();
|
||||
makeAccessTypeToFlagsMapping();
|
||||
collectAllFlags();
|
||||
}
|
||||
|
||||
static void flagsToKeywordsRec(const Flags & flags_, std::vector<std::string_view> & keywords, const Node & start_node)
|
||||
{
|
||||
Flags matching_flags = (flags_ & start_node.flags);
|
||||
@ -243,275 +395,12 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
static NodePtr makeFlagsToKeywordTree()
|
||||
{
|
||||
size_t next_flag = 0;
|
||||
Nodes all;
|
||||
|
||||
auto show_databases = std::make_unique<Node>("SHOW DATABASES", next_flag++, DATABASE);
|
||||
auto show_tables = std::make_unique<Node>("SHOW TABLES", next_flag++, TABLE);
|
||||
auto show_columns = std::make_unique<Node>("SHOW COLUMNS", next_flag++, COLUMN);
|
||||
auto show_dictionaries = std::make_unique<Node>("SHOW DICTIONARIES", next_flag++, DICTIONARY);
|
||||
auto show = std::make_unique<Node>("SHOW", std::move(show_databases), std::move(show_tables), std::move(show_columns), std::move(show_dictionaries));
|
||||
ext::push_back(all, std::move(show));
|
||||
|
||||
auto select = std::make_unique<Node>("SELECT", next_flag++, COLUMN);
|
||||
auto insert = std::make_unique<Node>("INSERT", next_flag++, COLUMN);
|
||||
ext::push_back(all, std::move(select), std::move(insert));
|
||||
|
||||
auto update = std::make_unique<Node>("UPDATE", next_flag++, COLUMN);
|
||||
ext::push_back(update->aliases, "ALTER UPDATE");
|
||||
auto delet = std::make_unique<Node>("DELETE", next_flag++, TABLE);
|
||||
ext::push_back(delet->aliases, "ALTER DELETE");
|
||||
|
||||
auto add_column = std::make_unique<Node>("ADD COLUMN", next_flag++, COLUMN);
|
||||
add_column->aliases.push_back("ALTER ADD COLUMN");
|
||||
auto modify_column = std::make_unique<Node>("MODIFY COLUMN", next_flag++, COLUMN);
|
||||
modify_column->aliases.push_back("ALTER MODIFY COLUMN");
|
||||
auto drop_column = std::make_unique<Node>("DROP COLUMN", next_flag++, COLUMN);
|
||||
drop_column->aliases.push_back("ALTER DROP COLUMN");
|
||||
auto comment_column = std::make_unique<Node>("COMMENT COLUMN", next_flag++, COLUMN);
|
||||
comment_column->aliases.push_back("ALTER COMMENT COLUMN");
|
||||
auto clear_column = std::make_unique<Node>("CLEAR COLUMN", next_flag++, COLUMN);
|
||||
clear_column->aliases.push_back("ALTER CLEAR COLUMN");
|
||||
auto rename_column = std::make_unique<Node>("RENAME COLUMN", next_flag++, COLUMN);
|
||||
rename_column->aliases.push_back("ALTER RENAME COLUMN");
|
||||
|
||||
auto alter_column = std::make_unique<Node>(
|
||||
"ALTER COLUMN",
|
||||
std::move(add_column),
|
||||
std::move(modify_column),
|
||||
std::move(drop_column),
|
||||
std::move(comment_column),
|
||||
std::move(clear_column),
|
||||
std::move(rename_column));
|
||||
|
||||
auto alter_order_by = std::make_unique<Node>("ALTER ORDER BY", next_flag++, TABLE);
|
||||
alter_order_by->aliases.push_back("MODIFY ORDER BY");
|
||||
alter_order_by->aliases.push_back("ALTER MODIFY ORDER BY");
|
||||
auto add_index = std::make_unique<Node>("ADD INDEX", next_flag++, TABLE);
|
||||
add_index->aliases.push_back("ALTER ADD INDEX");
|
||||
auto drop_index = std::make_unique<Node>("DROP INDEX", next_flag++, TABLE);
|
||||
drop_index->aliases.push_back("ALTER DROP INDEX");
|
||||
auto materialize_index = std::make_unique<Node>("MATERIALIZE INDEX", next_flag++, TABLE);
|
||||
materialize_index->aliases.push_back("ALTER MATERIALIZE INDEX");
|
||||
auto clear_index = std::make_unique<Node>("CLEAR INDEX", next_flag++, TABLE);
|
||||
clear_index->aliases.push_back("ALTER CLEAR INDEX");
|
||||
auto index = std::make_unique<Node>("INDEX", std::move(alter_order_by), std::move(add_index), std::move(drop_index), std::move(materialize_index), std::move(clear_index));
|
||||
index->aliases.push_back("ALTER INDEX");
|
||||
|
||||
auto add_constraint = std::make_unique<Node>("ADD CONSTRAINT", next_flag++, TABLE);
|
||||
add_constraint->aliases.push_back("ALTER ADD CONSTRAINT");
|
||||
auto drop_constraint = std::make_unique<Node>("DROP CONSTRAINT", next_flag++, TABLE);
|
||||
drop_constraint->aliases.push_back("ALTER DROP CONSTRAINT");
|
||||
auto alter_constraint = std::make_unique<Node>("CONSTRAINT", std::move(add_constraint), std::move(drop_constraint));
|
||||
alter_constraint->aliases.push_back("ALTER CONSTRAINT");
|
||||
|
||||
auto modify_ttl = std::make_unique<Node>("MODIFY TTL", next_flag++, TABLE);
|
||||
modify_ttl->aliases.push_back("ALTER MODIFY TTL");
|
||||
auto materialize_ttl = std::make_unique<Node>("MATERIALIZE TTL", next_flag++, TABLE);
|
||||
materialize_ttl->aliases.push_back("ALTER MATERIALIZE TTL");
|
||||
|
||||
auto modify_setting = std::make_unique<Node>("MODIFY SETTING", next_flag++, TABLE);
|
||||
modify_setting->aliases.push_back("ALTER MODIFY SETTING");
|
||||
|
||||
auto move_partition = std::make_unique<Node>("MOVE PARTITION", next_flag++, TABLE);
|
||||
ext::push_back(move_partition->aliases, "ALTER MOVE PARTITION", "MOVE PART", "ALTER MOVE PART");
|
||||
auto fetch_partition = std::make_unique<Node>("FETCH PARTITION", next_flag++, TABLE);
|
||||
ext::push_back(fetch_partition->aliases, "ALTER FETCH PARTITION");
|
||||
auto freeze_partition = std::make_unique<Node>("FREEZE PARTITION", next_flag++, TABLE);
|
||||
ext::push_back(freeze_partition->aliases, "ALTER FREEZE PARTITION");
|
||||
|
||||
auto alter_table = std::make_unique<Node>("ALTER TABLE", std::move(update), std::move(delet), std::move(alter_column), std::move(index), std::move(alter_constraint), std::move(modify_ttl), std::move(materialize_ttl), std::move(modify_setting), std::move(move_partition), std::move(fetch_partition), std::move(freeze_partition));
|
||||
|
||||
auto refresh_view = std::make_unique<Node>("REFRESH VIEW", next_flag++, VIEW);
|
||||
ext::push_back(refresh_view->aliases, "ALTER LIVE VIEW REFRESH");
|
||||
auto modify_view_query = std::make_unique<Node>("MODIFY VIEW QUERY", next_flag++, VIEW);
|
||||
auto alter_view = std::make_unique<Node>("ALTER VIEW", std::move(refresh_view), std::move(modify_view_query));
|
||||
|
||||
auto alter = std::make_unique<Node>("ALTER", std::move(alter_table), std::move(alter_view));
|
||||
ext::push_back(all, std::move(alter));
|
||||
|
||||
auto create_database = std::make_unique<Node>("CREATE DATABASE", next_flag++, DATABASE);
|
||||
auto create_table = std::make_unique<Node>("CREATE TABLE", next_flag++, TABLE);
|
||||
auto create_view = std::make_unique<Node>("CREATE VIEW", next_flag++, VIEW);
|
||||
auto create_dictionary = std::make_unique<Node>("CREATE DICTIONARY", next_flag++, DICTIONARY);
|
||||
auto create = std::make_unique<Node>("CREATE", std::move(create_database), std::move(create_table), std::move(create_view), std::move(create_dictionary));
|
||||
ext::push_back(all, std::move(create));
|
||||
|
||||
auto create_temporary_table = std::make_unique<Node>("CREATE TEMPORARY TABLE", next_flag++, GLOBAL);
|
||||
ext::push_back(all, std::move(create_temporary_table));
|
||||
|
||||
auto drop_database = std::make_unique<Node>("DROP DATABASE", next_flag++, DATABASE);
|
||||
auto drop_table = std::make_unique<Node>("DROP TABLE", next_flag++, TABLE);
|
||||
auto drop_view = std::make_unique<Node>("DROP VIEW", next_flag++, VIEW);
|
||||
auto drop_dictionary = std::make_unique<Node>("DROP DICTIONARY", next_flag++, DICTIONARY);
|
||||
auto drop = std::make_unique<Node>("DROP", std::move(drop_database), std::move(drop_table), std::move(drop_view), std::move(drop_dictionary));
|
||||
ext::push_back(all, std::move(drop));
|
||||
|
||||
auto truncate_table = std::make_unique<Node>("TRUNCATE TABLE", next_flag++, TABLE);
|
||||
auto truncate_view = std::make_unique<Node>("TRUNCATE VIEW", next_flag++, VIEW);
|
||||
auto truncate = std::make_unique<Node>("TRUNCATE", std::move(truncate_table), std::move(truncate_view));
|
||||
ext::push_back(all, std::move(truncate));
|
||||
|
||||
auto optimize = std::make_unique<Node>("OPTIMIZE", next_flag++, TABLE);
|
||||
optimize->aliases.push_back("OPTIMIZE TABLE");
|
||||
ext::push_back(all, std::move(optimize));
|
||||
|
||||
auto kill_query = std::make_unique<Node>("KILL QUERY", next_flag++, GLOBAL);
|
||||
ext::push_back(all, std::move(kill_query));
|
||||
|
||||
auto create_user = std::make_unique<Node>("CREATE USER", next_flag++, GLOBAL);
|
||||
auto alter_user = std::make_unique<Node>("ALTER USER", next_flag++, GLOBAL);
|
||||
auto drop_user = std::make_unique<Node>("DROP USER", next_flag++, GLOBAL);
|
||||
auto create_role = std::make_unique<Node>("CREATE ROLE", next_flag++, GLOBAL);
|
||||
auto alter_role = std::make_unique<Node>("ALTER ROLE", next_flag++, GLOBAL);
|
||||
auto drop_role = std::make_unique<Node>("DROP ROLE", next_flag++, GLOBAL);
|
||||
auto create_policy = std::make_unique<Node>("CREATE POLICY", next_flag++, GLOBAL);
|
||||
auto alter_policy = std::make_unique<Node>("ALTER POLICY", next_flag++, GLOBAL);
|
||||
auto drop_policy = std::make_unique<Node>("DROP POLICY", next_flag++, GLOBAL);
|
||||
auto create_quota = std::make_unique<Node>("CREATE QUOTA", next_flag++, GLOBAL);
|
||||
auto alter_quota = std::make_unique<Node>("ALTER QUOTA", next_flag++, GLOBAL);
|
||||
auto drop_quota = std::make_unique<Node>("DROP QUOTA", next_flag++, GLOBAL);
|
||||
auto create_profile = std::make_unique<Node>("CREATE SETTINGS PROFILE", next_flag++, GLOBAL);
|
||||
ext::push_back(create_profile->aliases, "CREATE PROFILE");
|
||||
auto alter_profile = std::make_unique<Node>("ALTER SETTINGS PROFILE", next_flag++, GLOBAL);
|
||||
ext::push_back(alter_profile->aliases, "ALTER PROFILE");
|
||||
auto drop_profile = std::make_unique<Node>("DROP SETTINGS PROFILE", next_flag++, GLOBAL);
|
||||
ext::push_back(drop_profile->aliases, "DROP PROFILE");
|
||||
auto role_admin = std::make_unique<Node>("ROLE ADMIN", next_flag++, GLOBAL);
|
||||
ext::push_back(all, std::move(create_user), std::move(alter_user), std::move(drop_user), std::move(create_role), std::move(alter_role), std::move(drop_role), std::move(create_policy), std::move(alter_policy), std::move(drop_policy), std::move(create_quota), std::move(alter_quota), std::move(drop_quota), std::move(create_profile), std::move(alter_profile), std::move(drop_profile), std::move(role_admin));
|
||||
|
||||
auto shutdown = std::make_unique<Node>("SHUTDOWN", next_flag++, GLOBAL);
|
||||
ext::push_back(shutdown->aliases, "SYSTEM SHUTDOWN", "SYSTEM KILL");
|
||||
auto drop_cache = std::make_unique<Node>("DROP CACHE", next_flag++, GLOBAL);
|
||||
ext::push_back(drop_cache->aliases, "SYSTEM DROP CACHE", "DROP DNS CACHE", "SYSTEM DROP DNS CACHE", "DROP MARK CACHE", "SYSTEM DROP MARK CACHE", "DROP UNCOMPRESSED CACHE", "SYSTEM DROP UNCOMPRESSED CACHE", "DROP COMPILED EXPRESSION CACHE", "SYSTEM DROP COMPILED EXPRESSION CACHE");
|
||||
auto reload_config = std::make_unique<Node>("RELOAD CONFIG", next_flag++, GLOBAL);
|
||||
ext::push_back(reload_config->aliases, "SYSTEM RELOAD CONFIG");
|
||||
auto reload_dictionary = std::make_unique<Node>("RELOAD DICTIONARY", next_flag++, GLOBAL);
|
||||
ext::push_back(reload_dictionary->aliases, "SYSTEM RELOAD DICTIONARY", "RELOAD DICTIONARIES", "SYSTEM RELOAD DICTIONARIES", "RELOAD EMBEDDED DICTIONARIES", "SYSTEM RELOAD EMBEDDED DICTIONARIES");
|
||||
auto stop_merges = std::make_unique<Node>("STOP MERGES", next_flag++, TABLE);
|
||||
ext::push_back(stop_merges->aliases, "SYSTEM STOP MERGES", "START MERGES", "SYSTEM START MERGES");
|
||||
auto stop_ttl_merges = std::make_unique<Node>("STOP TTL MERGES", next_flag++, TABLE);
|
||||
ext::push_back(stop_ttl_merges->aliases, "SYSTEM STOP TTL MERGES", "START TTL MERGES", "SYSTEM START TTL MERGES");
|
||||
auto stop_fetches = std::make_unique<Node>("STOP FETCHES", next_flag++, TABLE);
|
||||
ext::push_back(stop_fetches->aliases, "SYSTEM STOP FETCHES", "START FETCHES", "SYSTEM START FETCHES");
|
||||
auto stop_moves = std::make_unique<Node>("STOP MOVES", next_flag++, TABLE);
|
||||
ext::push_back(stop_moves->aliases, "SYSTEM STOP MOVES", "START MOVES", "SYSTEM START MOVES");
|
||||
auto stop_distributed_sends = std::make_unique<Node>("STOP DISTRIBUTED SENDS", next_flag++, TABLE);
|
||||
ext::push_back(stop_distributed_sends->aliases, "SYSTEM STOP DISTRIBUTED SENDS", "START DISTRIBUTED SENDS", "SYSTEM START DISTRIBUTED SENDS");
|
||||
auto stop_replicated_sends = std::make_unique<Node>("STOP REPLICATED SENDS", next_flag++, TABLE);
|
||||
ext::push_back(stop_replicated_sends->aliases, "SYSTEM STOP REPLICATED SENDS", "START REPLICATED SENDS", "SYSTEM START REPLICATED SENDS");
|
||||
auto stop_replication_queues = std::make_unique<Node>("STOP REPLICATION QUEUES", next_flag++, TABLE);
|
||||
ext::push_back(stop_replication_queues->aliases, "SYSTEM STOP REPLICATION QUEUES", "START REPLICATION QUEUES", "SYSTEM START REPLICATION QUEUES");
|
||||
auto sync_replica = std::make_unique<Node>("SYNC REPLICA", next_flag++, TABLE);
|
||||
ext::push_back(sync_replica->aliases, "SYSTEM SYNC REPLICA");
|
||||
auto restart_replica = std::make_unique<Node>("RESTART REPLICA", next_flag++, TABLE);
|
||||
ext::push_back(restart_replica->aliases, "SYSTEM RESTART REPLICA");
|
||||
auto flush_distributed = std::make_unique<Node>("FLUSH DISTRIBUTED", next_flag++, TABLE);
|
||||
ext::push_back(flush_distributed->aliases, "SYSTEM FLUSH DISTRIBUTED");
|
||||
auto flush_logs = std::make_unique<Node>("FLUSH LOGS", next_flag++, GLOBAL);
|
||||
ext::push_back(flush_logs->aliases, "SYSTEM FLUSH LOGS");
|
||||
auto system = std::make_unique<Node>("SYSTEM", std::move(shutdown), std::move(drop_cache), std::move(reload_config), std::move(reload_dictionary), std::move(stop_merges), std::move(stop_ttl_merges), std::move(stop_fetches), std::move(stop_moves), std::move(stop_distributed_sends), std::move(stop_replicated_sends), std::move(stop_replication_queues), std::move(sync_replica), std::move(restart_replica), std::move(flush_distributed), std::move(flush_logs));
|
||||
ext::push_back(all, std::move(system));
|
||||
|
||||
auto dict_get = std::make_unique<Node>("dictGet()", next_flag++, DICTIONARY);
|
||||
dict_get->aliases.push_back("dictHas()");
|
||||
dict_get->aliases.push_back("dictGetHierarchy()");
|
||||
dict_get->aliases.push_back("dictIsIn()");
|
||||
ext::push_back(all, std::move(dict_get));
|
||||
|
||||
auto address_to_line = std::make_unique<Node>("addressToLine()", next_flag++, GLOBAL);
|
||||
auto address_to_symbol = std::make_unique<Node>("addressToSymbol()", next_flag++, GLOBAL);
|
||||
auto demangle = std::make_unique<Node>("demangle()", next_flag++, GLOBAL);
|
||||
auto introspection = std::make_unique<Node>("INTROSPECTION", std::move(address_to_line), std::move(address_to_symbol), std::move(demangle));
|
||||
ext::push_back(introspection->aliases, "INTROSPECTION FUNCTIONS");
|
||||
ext::push_back(all, std::move(introspection));
|
||||
|
||||
auto file = std::make_unique<Node>("file()", next_flag++, GLOBAL);
|
||||
auto url = std::make_unique<Node>("url()", next_flag++, GLOBAL);
|
||||
auto input = std::make_unique<Node>("input()", next_flag++, GLOBAL);
|
||||
auto values = std::make_unique<Node>("values()", next_flag++, GLOBAL);
|
||||
auto numbers = std::make_unique<Node>("numbers()", next_flag++, GLOBAL);
|
||||
auto zeros = std::make_unique<Node>("zeros()", next_flag++, GLOBAL);
|
||||
auto merge = std::make_unique<Node>("merge()", next_flag++, DATABASE);
|
||||
auto remote = std::make_unique<Node>("remote()", next_flag++, GLOBAL);
|
||||
ext::push_back(remote->aliases, "remoteSecure()", "cluster()");
|
||||
auto mysql = std::make_unique<Node>("mysql()", next_flag++, GLOBAL);
|
||||
auto odbc = std::make_unique<Node>("odbc()", next_flag++, GLOBAL);
|
||||
auto jdbc = std::make_unique<Node>("jdbc()", next_flag++, GLOBAL);
|
||||
auto hdfs = std::make_unique<Node>("hdfs()", next_flag++, GLOBAL);
|
||||
auto s3 = std::make_unique<Node>("s3()", next_flag++, GLOBAL);
|
||||
auto table_functions = std::make_unique<Node>("TABLE FUNCTIONS", std::move(file), std::move(url), std::move(input), std::move(values), std::move(numbers), std::move(zeros), std::move(merge), std::move(remote), std::move(mysql), std::move(odbc), std::move(jdbc), std::move(hdfs), std::move(s3));
|
||||
ext::push_back(all, std::move(table_functions));
|
||||
|
||||
auto node_all = std::make_unique<Node>("ALL", std::move(all));
|
||||
node_all->aliases.push_back("ALL PRIVILEGES");
|
||||
return node_all;
|
||||
}
|
||||
|
||||
void makeKeywordToFlagsMap(Node * start_node = nullptr)
|
||||
{
|
||||
if (!start_node)
|
||||
{
|
||||
start_node = flags_to_keyword_tree.get();
|
||||
keyword_to_flags_map["USAGE"] = {};
|
||||
keyword_to_flags_map["NONE"] = {};
|
||||
keyword_to_flags_map["NO PRIVILEGES"] = {};
|
||||
}
|
||||
start_node->aliases.emplace_back(start_node->keyword);
|
||||
for (auto & alias : start_node->aliases)
|
||||
{
|
||||
boost::to_upper(alias);
|
||||
keyword_to_flags_map[alias] = start_node->flags;
|
||||
}
|
||||
for (auto & child : start_node->children)
|
||||
makeKeywordToFlagsMap(child.get());
|
||||
}
|
||||
|
||||
void makeAccessTypeToFlagsMapping()
|
||||
{
|
||||
access_type_to_flags_mapping.resize(MAX_ACCESS_TYPE);
|
||||
for (auto access_type : ext::range_with_static_cast<AccessType>(0, MAX_ACCESS_TYPE))
|
||||
{
|
||||
auto str = toKeyword(access_type);
|
||||
auto it = keyword_to_flags_map.find(str);
|
||||
if (it == keyword_to_flags_map.end())
|
||||
{
|
||||
String uppercased{str};
|
||||
boost::to_upper(uppercased);
|
||||
it = keyword_to_flags_map.find(uppercased);
|
||||
}
|
||||
access_type_to_flags_mapping[static_cast<size_t>(access_type)] = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
void collectAllFlags(const Node * start_node = nullptr)
|
||||
{
|
||||
if (!start_node)
|
||||
{
|
||||
start_node = flags_to_keyword_tree.get();
|
||||
all_flags = start_node->flags;
|
||||
}
|
||||
if (start_node->target != UNKNOWN_TARGET)
|
||||
all_flags_for_target[start_node->target] |= start_node->flags;
|
||||
for (const auto & child : start_node->children)
|
||||
collectAllFlags(child.get());
|
||||
}
|
||||
|
||||
Impl()
|
||||
{
|
||||
flags_to_keyword_tree = makeFlagsToKeywordTree();
|
||||
makeKeywordToFlagsMap();
|
||||
makeAccessTypeToFlagsMapping();
|
||||
collectAllFlags();
|
||||
}
|
||||
|
||||
std::unique_ptr<Node> flags_to_keyword_tree;
|
||||
NodePtr flags_to_keyword_tree;
|
||||
NodePtr none_node;
|
||||
std::unordered_map<std::string_view, Flags> keyword_to_flags_map;
|
||||
std::vector<Flags> access_type_to_flags_mapping;
|
||||
Flags all_flags;
|
||||
Flags all_flags_for_target[NUM_TARGETS];
|
||||
Flags all_flags_for_target[static_cast<size_t>(DICTIONARY) + 1];
|
||||
};
|
||||
|
||||
|
||||
|
@ -49,10 +49,13 @@ namespace
|
||||
const AccessFlags create_temporary_table_flag = AccessType::CREATE_TEMPORARY_TABLE;
|
||||
const AccessFlags alter_table_flag = AccessType::ALTER_TABLE;
|
||||
const AccessFlags alter_view_flag = AccessType::ALTER_VIEW;
|
||||
const AccessFlags truncate_table_flag = AccessType::TRUNCATE_TABLE;
|
||||
const AccessFlags truncate_view_flag = AccessType::TRUNCATE_VIEW;
|
||||
const AccessFlags truncate_flag = AccessType::TRUNCATE;
|
||||
const AccessFlags drop_table_flag = AccessType::DROP_TABLE;
|
||||
const AccessFlags drop_view_flag = AccessType::DROP_VIEW;
|
||||
const AccessFlags alter_ttl_flag = AccessType::ALTER_TTL;
|
||||
const AccessFlags alter_materialize_ttl_flag = AccessType::ALTER_MATERIALIZE_TTL;
|
||||
const AccessFlags system_reload_dictionary = AccessType::SYSTEM_RELOAD_DICTIONARY;
|
||||
const AccessFlags system_reload_embedded_dictionaries = AccessType::SYSTEM_RELOAD_EMBEDDED_DICTIONARIES;
|
||||
};
|
||||
|
||||
std::string_view checkCurrentDatabase(const std::string_view & current_database)
|
||||
@ -413,8 +416,14 @@ private:
|
||||
implicit_access |= helper.show_tables_flag;
|
||||
}
|
||||
|
||||
if ((level == GLOBAL_LEVEL) && ((access | max_access_among_children) & helper.create_table_flag))
|
||||
implicit_access |= helper.create_temporary_table_flag;
|
||||
if (level == GLOBAL_LEVEL)
|
||||
{
|
||||
if ((access | max_access_among_children) & helper.create_table_flag)
|
||||
implicit_access |= helper.create_temporary_table_flag;
|
||||
|
||||
if (access & helper.system_reload_dictionary)
|
||||
implicit_access |= helper.system_reload_embedded_dictionaries;
|
||||
}
|
||||
|
||||
if (level <= TABLE_LEVEL)
|
||||
{
|
||||
@ -427,8 +436,8 @@ private:
|
||||
if (access & helper.alter_table_flag)
|
||||
implicit_access |= helper.alter_view_flag;
|
||||
|
||||
if (access & helper.truncate_table_flag)
|
||||
implicit_access |= helper.truncate_view_flag;
|
||||
if (access & helper.alter_ttl_flag)
|
||||
implicit_access |= helper.alter_materialize_ttl_flag;
|
||||
}
|
||||
|
||||
final_access = access | implicit_access;
|
||||
|
@ -11,139 +11,162 @@ namespace DB
|
||||
/// Represents an access type which can be granted on databases, tables, columns, etc.
|
||||
enum class AccessType
|
||||
{
|
||||
NONE, /// no access
|
||||
ALL, /// full access
|
||||
/// Macro M should be defined as M(name, aliases, node_type, parent_group_name)
|
||||
/// where name is identifier with underscores (instead of spaces);
|
||||
/// aliases is a string containing comma-separated list;
|
||||
/// node_type either specifies access type's level (GLOBAL/DATABASE/TABLE/DICTIONARY/VIEW/COLUMNS),
|
||||
/// or specifies that the access type is a GROUP of other access types;
|
||||
/// parent_group_name is the name of the group containing this access type (or NONE if there is no such group).
|
||||
#define APPLY_FOR_ACCESS_TYPES(M) \
|
||||
M(SHOW_DATABASES, "", DATABASE, SHOW) /* allows to execute SHOW DATABASES, SHOW CREATE DATABASE, USE <database>;
|
||||
implicitly enabled by any grant on the database */\
|
||||
M(SHOW_TABLES, "", TABLE, SHOW) /* allows to execute SHOW TABLES, EXISTS <table>, CHECK <table>;
|
||||
implicitly enabled by any grant on the table */\
|
||||
M(SHOW_COLUMNS, "", COLUMN, SHOW) /* allows to execute SHOW CREATE TABLE, DESCRIBE;
|
||||
implicitly enabled with any grant on the column */\
|
||||
M(SHOW_DICTIONARIES, "", DICTIONARY, SHOW) /* allows to execute SHOW DICTIONARIES, SHOW CREATE DICTIONARY, EXISTS <dictionary>;
|
||||
implicitly enabled by any grant on the dictionary */\
|
||||
M(SHOW, "", GROUP, ALL) /* allows to execute SHOW, USE, EXISTS, CHECK, DESCRIBE */\
|
||||
\
|
||||
M(SELECT, "", COLUMN, ALL) \
|
||||
M(INSERT, "", COLUMN, ALL) \
|
||||
M(ALTER_UPDATE, "UPDATE", COLUMN, ALTER_TABLE) /* allows to execute ALTER UPDATE */\
|
||||
M(ALTER_DELETE, "DELETE", COLUMN, ALTER_TABLE) /* allows to execute ALTER DELETE */\
|
||||
\
|
||||
M(ALTER_ADD_COLUMN, "ADD COLUMN", COLUMN, ALTER_COLUMN) \
|
||||
M(ALTER_MODIFY_COLUMN, "MODIFY COLUMN", COLUMN, ALTER_COLUMN) \
|
||||
M(ALTER_DROP_COLUMN, "DROP COLUMN", COLUMN, ALTER_COLUMN) \
|
||||
M(ALTER_COMMENT_COLUMN, "COMMENT COLUMN", COLUMN, ALTER_COLUMN) \
|
||||
M(ALTER_CLEAR_COLUMN, "CLEAR COLUMN", COLUMN, ALTER_COLUMN) \
|
||||
M(ALTER_RENAME_COLUMN, "RENAME COLUMN", COLUMN, ALTER_COLUMN) \
|
||||
M(ALTER_COLUMN, "", GROUP, ALTER_TABLE) /* allow to execute ALTER {ADD|DROP|MODIFY...} COLUMN */\
|
||||
\
|
||||
M(ALTER_ORDER_BY, "ALTER MODIFY ORDER BY, MODIFY ORDER BY", TABLE, ALTER_INDEX) \
|
||||
M(ALTER_ADD_INDEX, "ADD INDEX", TABLE, ALTER_INDEX) \
|
||||
M(ALTER_DROP_INDEX, "DROP INDEX", TABLE, ALTER_INDEX) \
|
||||
M(ALTER_MATERIALIZE_INDEX, "MATERIALIZE INDEX", TABLE, ALTER_INDEX) \
|
||||
M(ALTER_CLEAR_INDEX, "CLEAR INDEX", TABLE, ALTER_INDEX) \
|
||||
M(ALTER_INDEX, "INDEX", GROUP, ALTER_TABLE) /* allows to execute ALTER ORDER BY or ALTER {ADD|DROP...} INDEX */\
|
||||
\
|
||||
M(ALTER_ADD_CONSTRAINT, "ADD CONSTRAINT", TABLE, ALTER_CONSTRAINT) \
|
||||
M(ALTER_DROP_CONSTRAINT, "DROP CONSTRAINT", TABLE, ALTER_CONSTRAINT) \
|
||||
M(ALTER_CONSTRAINT, "CONSTRAINT", GROUP, ALTER_TABLE) /* allows to execute ALTER {ADD|DROP} CONSTRAINT */\
|
||||
\
|
||||
M(ALTER_TTL, "ALTER MODIFY TTL, MODIFY TTL", TABLE, ALTER_TABLE) /* allows to execute ALTER MODIFY TTL */\
|
||||
M(ALTER_MATERIALIZE_TTL, "MATERIALIZE TTL", TABLE, ALTER_TABLE) /* allows to execute ALTER MATERIALIZE TTL;
|
||||
enabled implicitly by the grant ALTER_TABLE */\
|
||||
M(ALTER_SETTINGS, "ALTER SETTING, ALTER MODIFY SETTING, MODIFY SETTING", TABLE, ALTER_TABLE) /* allows to execute ALTER MODIFY SETTING */\
|
||||
M(ALTER_MOVE_PARTITION, "ALTER MOVE PART, MOVE PARTITION, MOVE PART", TABLE, ALTER_TABLE) \
|
||||
M(ALTER_FETCH_PARTITION, "FETCH PARTITION", TABLE, ALTER_TABLE) \
|
||||
M(ALTER_FREEZE_PARTITION, "FREEZE PARTITION", TABLE, ALTER_TABLE) \
|
||||
\
|
||||
M(ALTER_TABLE, "", GROUP, ALTER) \
|
||||
\
|
||||
M(ALTER_VIEW_REFRESH, "ALTER LIVE VIEW REFRESH, REFRESH VIEW", VIEW, ALTER_VIEW) \
|
||||
M(ALTER_VIEW_MODIFY_QUERY, "ALTER TABLE MODIFY QUERY", VIEW, ALTER_VIEW) \
|
||||
M(ALTER_VIEW, "", GROUP, ALTER) /* allows to execute ALTER VIEW REFRESH, ALTER VIEW MODIFY QUERY;
|
||||
implicitly enabled by the grant ALTER_TABLE */\
|
||||
\
|
||||
M(ALTER, "", GROUP, ALL) /* allows to execute ALTER {TABLE|LIVE VIEW} */\
|
||||
\
|
||||
M(CREATE_DATABASE, "", DATABASE, CREATE) /* allows to execute {CREATE|ATTACH} DATABASE */\
|
||||
M(CREATE_TABLE, "", TABLE, CREATE) /* allows to execute {CREATE|ATTACH} {TABLE|VIEW} */\
|
||||
M(CREATE_VIEW, "", VIEW, CREATE) /* allows to execute {CREATE|ATTACH} VIEW;
|
||||
implicitly enabled by the grant CREATE_TABLE */\
|
||||
M(CREATE_DICTIONARY, "", DICTIONARY, CREATE) /* allows to execute {CREATE|ATTACH} DICTIONARY */\
|
||||
M(CREATE_TEMPORARY_TABLE, "", GLOBAL, CREATE) /* allows to create and manipulate temporary tables;
|
||||
implicitly enabled by the grant CREATE_TABLE on any table */ \
|
||||
M(CREATE, "", GROUP, ALL) /* allows to execute {CREATE|ATTACH} */ \
|
||||
\
|
||||
M(DROP_DATABASE, "", DATABASE, DROP) /* allows to execute {DROP|DETACH} DATABASE */\
|
||||
M(DROP_TABLE, "", TABLE, DROP) /* allows to execute {DROP|DETACH} TABLE */\
|
||||
M(DROP_VIEW, "", VIEW, DROP) /* allows to execute {DROP|DETACH} TABLE for views;
|
||||
implicitly enabled by the grant DROP_TABLE */\
|
||||
M(DROP_DICTIONARY, "", DICTIONARY, DROP) /* allows to execute {DROP|DETACH} DICTIONARY */\
|
||||
M(DROP, "", GROUP, ALL) /* allows to execute {DROP|DETACH} */\
|
||||
\
|
||||
M(TRUNCATE, "TRUNCATE TABLE", TABLE, ALL) \
|
||||
M(OPTIMIZE, "OPTIMIZE TABLE", TABLE, ALL) \
|
||||
\
|
||||
M(KILL_QUERY, "", GLOBAL, ALL) /* allows to kill a query started by another user
|
||||
(anyone can kill his own queries) */\
|
||||
\
|
||||
M(CREATE_USER, "", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(ALTER_USER, "", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(DROP_USER, "", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(CREATE_ROLE, "", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(ALTER_ROLE, "", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(DROP_ROLE, "", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(ROLE_ADMIN, "", GLOBAL, ACCESS_MANAGEMENT) /* allows to grant and revoke the roles which are not granted to the current user with admin option */\
|
||||
M(CREATE_ROW_POLICY, "CREATE POLICY", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(ALTER_ROW_POLICY, "ALTER POLICY", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(DROP_ROW_POLICY, "DROP POLICY", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(CREATE_QUOTA, "", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(ALTER_QUOTA, "", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(DROP_QUOTA, "", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(CREATE_SETTINGS_PROFILE, "CREATE PROFILE", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(ALTER_SETTINGS_PROFILE, "ALTER PROFILE", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(DROP_SETTINGS_PROFILE, "DROP PROFILE", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(SHOW_USERS, "SHOW CREATE USER", GLOBAL, SHOW_ACCESS) \
|
||||
M(SHOW_ROLES, "SHOW CREATE ROLE", GLOBAL, SHOW_ACCESS) \
|
||||
M(SHOW_ROW_POLICIES, "SHOW POLICIES, SHOW CREATE ROW POLICY, SHOW CREATE POLICY", GLOBAL, SHOW_ACCESS) \
|
||||
M(SHOW_QUOTAS, "SHOW CREATE QUOTA", GLOBAL, SHOW_ACCESS) \
|
||||
M(SHOW_SETTINGS_PROFILES, "SHOW PROFILES, SHOW CREATE SETTINGS PROFILE, SHOW CREATE PROFILE", GLOBAL, SHOW_ACCESS) \
|
||||
M(SHOW_ACCESS, "", GROUP, ACCESS_MANAGEMENT) \
|
||||
M(ACCESS_MANAGEMENT, "", GROUP, ALL) \
|
||||
\
|
||||
M(SYSTEM_SHUTDOWN, "SYSTEM KILL, SHUTDOWN", GLOBAL, SYSTEM) \
|
||||
M(SYSTEM_DROP_DNS_CACHE, "SYSTEM DROP DNS, DROP DNS CACHE, DROP DNS", GLOBAL, SYSTEM_DROP_CACHE) \
|
||||
M(SYSTEM_DROP_MARK_CACHE, "SYSTEM DROP MARK, DROP MARK CACHE, DROP MARKS", GLOBAL, SYSTEM_DROP_CACHE) \
|
||||
M(SYSTEM_DROP_UNCOMPRESSED_CACHE, "SYSTEM DROP UNCOMPRESSED, DROP UNCOMPRESSED CACHE, DROP UNCOMPRESSED", GLOBAL, SYSTEM_DROP_CACHE) \
|
||||
M(SYSTEM_DROP_COMPILED_EXPRESSION_CACHE, "SYSTEM DROP COMPILED EXPRESSION, DROP COMPILED EXPRESSION CACHE, DROP COMPILED EXPRESSIONS", GLOBAL, SYSTEM_DROP_CACHE) \
|
||||
M(SYSTEM_DROP_CACHE, "DROP CACHE", GROUP, SYSTEM) \
|
||||
M(SYSTEM_RELOAD_CONFIG, "RELOAD CONFIG", GLOBAL, SYSTEM_RELOAD) \
|
||||
M(SYSTEM_RELOAD_DICTIONARY, "SYSTEM RELOAD DICTIONARIES, RELOAD DICTIONARY, RELOAD DICTIONARIES", GLOBAL, SYSTEM_RELOAD) \
|
||||
M(SYSTEM_RELOAD_EMBEDDED_DICTIONARIES, "RELOAD EMBEDDED DICTIONARIES", GLOBAL, SYSTEM_RELOAD) /* implicitly enabled by the grant SYSTEM_RELOAD_DICTIONARY ON *.* */\
|
||||
M(SYSTEM_RELOAD, "", GROUP, SYSTEM) \
|
||||
M(SYSTEM_MERGES, "SYSTEM STOP MERGES, SYSTEM START MERGES, STOP_MERGES, START MERGES", TABLE, SYSTEM) \
|
||||
M(SYSTEM_TTL_MERGES, "SYSTEM STOP TTL MERGES, SYSTEM START TTL MERGES, STOP TTL MERGES, START TTL MERGES", TABLE, SYSTEM) \
|
||||
M(SYSTEM_FETCHES, "SYSTEM STOP FETCHES, SYSTEM START FETCHES, STOP FETCHES, START FETCHES", TABLE, SYSTEM) \
|
||||
M(SYSTEM_MOVES, "SYSTEM STOP MOVES, SYSTEM START MOVES, STOP MOVES, START MOVES", TABLE, SYSTEM) \
|
||||
M(SYSTEM_DISTRIBUTED_SENDS, "SYSTEM STOP DISTRIBUTED SENDS, SYSTEM START DISTRIBUTED SENDS, STOP DISTRIBUTED SENDS, START DISTRIBUTED SENDS", TABLE, SYSTEM_SENDS) \
|
||||
M(SYSTEM_REPLICATED_SENDS, "SYSTEM STOP REPLICATED SENDS, SYSTEM START REPLICATED SENDS, STOP_REPLICATED_SENDS, START REPLICATED SENDS", TABLE, SYSTEM_SENDS) \
|
||||
M(SYSTEM_SENDS, "SYSTEM STOP SENDS, SYSTEM START SENDS, STOP SENDS, START SENDS", GROUP, SYSTEM) \
|
||||
M(SYSTEM_REPLICATION_QUEUES, "SYSTEM STOP REPLICATION QUEUES, SYSTEM START REPLICATION QUEUES, STOP_REPLICATION_QUEUES, START REPLICATION QUEUES", TABLE, SYSTEM) \
|
||||
M(SYSTEM_SYNC_REPLICA, "SYNC REPLICA", TABLE, SYSTEM) \
|
||||
M(SYSTEM_RESTART_REPLICA, "RESTART REPLICA", TABLE, SYSTEM) \
|
||||
M(SYSTEM_FLUSH_DISTRIBUTED, "FLUSH DISTRIBUTED", TABLE, SYSTEM_FLUSH) \
|
||||
M(SYSTEM_FLUSH_LOGS, "FLUSH LOGS", GLOBAL, SYSTEM_FLUSH) \
|
||||
M(SYSTEM_FLUSH, "", GROUP, SYSTEM) \
|
||||
M(SYSTEM, "", GROUP, ALL) /* allows to execute SYSTEM {SHUTDOWN|RELOAD CONFIG|...} */ \
|
||||
\
|
||||
M(dictGet, "dictHas, dictGetHierarchy, dictIsIn", DICTIONARY, ALL) /* allows to execute functions dictGet(), dictHas(), dictGetHierarchy(), dictIsIn() */\
|
||||
\
|
||||
M(addressToLine, "", GLOBAL, INTROSPECTION) /* allows to execute function addressToLine() */\
|
||||
M(addressToSymbol, "", GLOBAL, INTROSPECTION) /* allows to execute function addressToSymbol() */\
|
||||
M(demangle, "", GLOBAL, INTROSPECTION) /* allows to execute function demangle() */\
|
||||
M(INTROSPECTION, "INTROSPECTION FUNCTIONS", GROUP, ALL) /* allows to execute functions addressToLine(), addressToSymbol(), demangle()*/\
|
||||
\
|
||||
M(FILE, "", GLOBAL, SOURCES) \
|
||||
M(URL, "", GLOBAL, SOURCES) \
|
||||
M(REMOTE, "", GLOBAL, SOURCES) \
|
||||
M(MYSQL, "", GLOBAL, SOURCES) \
|
||||
M(ODBC, "", GLOBAL, SOURCES) \
|
||||
M(JDBC, "", GLOBAL, SOURCES) \
|
||||
M(HDFS, "", GLOBAL, SOURCES) \
|
||||
M(S3, "", GLOBAL, SOURCES) \
|
||||
M(SOURCES, "", GROUP, ALL) \
|
||||
\
|
||||
M(ALL, "ALL PRIVILEGES", GROUP, NONE) /* full access */ \
|
||||
M(NONE, "USAGE, NO PRIVILEGES", GROUP, NONE) /* no access */
|
||||
|
||||
SHOW_DATABASES, /// allows to execute SHOW DATABASES, SHOW CREATE DATABASE, USE <database>
|
||||
SHOW_TABLES, /// allows to execute SHOW TABLES, EXISTS <table>, CHECK <table>
|
||||
SHOW_COLUMNS, /// allows to execute SHOW CREATE TABLE, DESCRIBE
|
||||
SHOW_DICTIONARIES, /// allows to execute SHOW DICTIONARIES, SHOW CREATE DICTIONARY, EXISTS <dictionary>
|
||||
SHOW, /// allows to execute SHOW, USE, EXISTS, CHECK, DESCRIBE
|
||||
#define DECLARE_ACCESS_TYPE_ENUM_CONST(name, aliases, node_type, parent_group_name) \
|
||||
name,
|
||||
|
||||
SELECT,
|
||||
INSERT,
|
||||
UPDATE, /// allows to execute ALTER UPDATE
|
||||
DELETE, /// allows to execute ALTER DELETE
|
||||
|
||||
ADD_COLUMN,
|
||||
DROP_COLUMN,
|
||||
MODIFY_COLUMN,
|
||||
COMMENT_COLUMN,
|
||||
CLEAR_COLUMN,
|
||||
RENAME_COLUMN,
|
||||
ALTER_COLUMN, /// allow to execute ALTER {ADD|DROP|MODIFY...} COLUMN
|
||||
|
||||
ALTER_ORDER_BY,
|
||||
ADD_INDEX,
|
||||
DROP_INDEX,
|
||||
MATERIALIZE_INDEX,
|
||||
CLEAR_INDEX,
|
||||
INDEX, /// allows to execute ALTER ORDER BY or ALTER {ADD|DROP...} INDEX
|
||||
|
||||
ADD_CONSTRAINT,
|
||||
DROP_CONSTRAINT,
|
||||
ALTER_CONSTRAINT, /// allows to execute ALTER {ADD|DROP} CONSTRAINT
|
||||
|
||||
MODIFY_TTL, /// allows to execute ALTER MODIFY TTL
|
||||
MATERIALIZE_TTL, /// allows to execute ALTER MATERIALIZE TTL
|
||||
MODIFY_SETTING, /// allows to execute ALTER MODIFY SETTING
|
||||
|
||||
MOVE_PARTITION,
|
||||
FETCH_PARTITION,
|
||||
FREEZE_PARTITION,
|
||||
|
||||
ALTER_TABLE, /// allows to execute ALTER TABLE ...
|
||||
|
||||
REFRESH_VIEW, /// allows to execute ALTER LIVE VIEW REFRESH
|
||||
MODIFY_VIEW_QUERY, /// allows to execute ALTER TABLE MODIFY QUERY
|
||||
ALTER_VIEW, /// allows to execute ALTER LIVE VIEW REFRESH, ALTER TABLE MODIFY QUERY
|
||||
|
||||
ALTER, /// allows to execute ALTER {TABLE|LIVE VIEW} ...
|
||||
|
||||
CREATE_DATABASE, /// allows to execute {CREATE|ATTACH} DATABASE
|
||||
CREATE_TABLE, /// allows to execute {CREATE|ATTACH} TABLE
|
||||
CREATE_VIEW, /// allows to execute {CREATE|ATTACH} VIEW
|
||||
CREATE_DICTIONARY, /// allows to execute {CREATE|ATTACH} DICTIONARY
|
||||
CREATE_TEMPORARY_TABLE, /// allows to create and manipulate temporary tables and views.
|
||||
CREATE, /// allows to execute {CREATE|ATTACH} [TEMPORARY] {DATABASE|TABLE|VIEW|DICTIONARY}
|
||||
|
||||
DROP_DATABASE,
|
||||
DROP_TABLE,
|
||||
DROP_VIEW,
|
||||
DROP_DICTIONARY,
|
||||
DROP, /// allows to execute DROP {DATABASE|TABLE|VIEW|DICTIONARY}
|
||||
|
||||
TRUNCATE_TABLE,
|
||||
TRUNCATE_VIEW,
|
||||
TRUNCATE, /// allows to execute TRUNCATE {TABLE|VIEW}
|
||||
|
||||
OPTIMIZE, /// allows to execute OPTIMIZE TABLE
|
||||
|
||||
KILL_QUERY, /// allows to kill a query started by another user (anyone can kill his own queries)
|
||||
|
||||
CREATE_USER,
|
||||
ALTER_USER,
|
||||
DROP_USER,
|
||||
CREATE_ROLE,
|
||||
ALTER_ROLE,
|
||||
DROP_ROLE,
|
||||
CREATE_POLICY,
|
||||
ALTER_POLICY,
|
||||
DROP_POLICY,
|
||||
CREATE_QUOTA,
|
||||
ALTER_QUOTA,
|
||||
DROP_QUOTA,
|
||||
CREATE_SETTINGS_PROFILE,
|
||||
ALTER_SETTINGS_PROFILE,
|
||||
DROP_SETTINGS_PROFILE,
|
||||
|
||||
ROLE_ADMIN, /// allows to grant and revoke any roles.
|
||||
|
||||
SHUTDOWN,
|
||||
DROP_CACHE,
|
||||
RELOAD_CONFIG,
|
||||
RELOAD_DICTIONARY,
|
||||
STOP_MERGES,
|
||||
STOP_TTL_MERGES,
|
||||
STOP_FETCHES,
|
||||
STOP_MOVES,
|
||||
STOP_DISTRIBUTED_SENDS,
|
||||
STOP_REPLICATED_SENDS,
|
||||
STOP_REPLICATION_QUEUES,
|
||||
SYNC_REPLICA,
|
||||
RESTART_REPLICA,
|
||||
FLUSH_DISTRIBUTED,
|
||||
FLUSH_LOGS,
|
||||
SYSTEM, /// allows to execute SYSTEM {SHUTDOWN|RELOAD CONFIG|...}
|
||||
|
||||
dictGet, /// allows to execute functions dictGet, dictHas, dictGetHierarchy, dictIsIn
|
||||
dictHas, /// allows to execute functions dictGet, dictHas, dictGetHierarchy, dictIsIn
|
||||
dictGetHierarchy, /// allows to execute functions dictGet, dictHas, dictGetHierarchy, dictIsIn
|
||||
dictIsIn, /// allows to execute functions dictGet, dictHas, dictGetHierarchy, dictIsIn
|
||||
|
||||
addressToLine, /// allows to execute function addressToLine
|
||||
addressToSymbol, /// allows to execute function addressToSymbol
|
||||
demangle, /// allows to execute function demangle
|
||||
INTROSPECTION, /// allows to execute functions addressToLine, addressToSymbol, demangle
|
||||
|
||||
file,
|
||||
url,
|
||||
input,
|
||||
values,
|
||||
numbers,
|
||||
zeros,
|
||||
merge,
|
||||
remote,
|
||||
mysql,
|
||||
odbc,
|
||||
jdbc,
|
||||
hdfs,
|
||||
s3,
|
||||
TABLE_FUNCTIONS, /// allows to execute any table function
|
||||
APPLY_FOR_ACCESS_TYPES(DECLARE_ACCESS_TYPE_ENUM_CONST)
|
||||
#undef DECLARE_ACCESS_TYPE_ENUM_CONST
|
||||
};
|
||||
|
||||
constexpr size_t MAX_ACCESS_TYPE = static_cast<size_t>(AccessType::TABLE_FUNCTIONS) + 1;
|
||||
|
||||
std::string_view toString(AccessType type);
|
||||
|
||||
|
||||
@ -165,153 +188,26 @@ namespace impl
|
||||
}
|
||||
|
||||
private:
|
||||
void addToMapping(AccessType type, const std::string_view & str)
|
||||
AccessTypeToKeywordConverter()
|
||||
{
|
||||
#define INSERT_ACCESS_TYPE_KEYWORD_PAIR_TO_MAPPING(name, aliases, node_type, parent_group_name) \
|
||||
insertToMapping(AccessType::name, #name);
|
||||
|
||||
APPLY_FOR_ACCESS_TYPES(INSERT_ACCESS_TYPE_KEYWORD_PAIR_TO_MAPPING)
|
||||
|
||||
#undef INSERT_ACCESS_TYPE_KEYWORD_PAIR_TO_MAPPING
|
||||
}
|
||||
|
||||
void insertToMapping(AccessType type, const std::string_view & str)
|
||||
{
|
||||
String str2{str};
|
||||
boost::replace_all(str2, "_", " ");
|
||||
if (islower(str2[0]))
|
||||
str2 += "()";
|
||||
access_type_to_keyword_mapping[static_cast<size_t>(type)] = str2;
|
||||
size_t index = static_cast<size_t>(type);
|
||||
access_type_to_keyword_mapping.resize(std::max(index + 1, access_type_to_keyword_mapping.size()));
|
||||
access_type_to_keyword_mapping[index] = str2;
|
||||
}
|
||||
|
||||
AccessTypeToKeywordConverter()
|
||||
{
|
||||
#define ACCESS_TYPE_TO_KEYWORD_CASE(type) \
|
||||
addToMapping(AccessType::type, #type)
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(NONE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALL);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(SHOW_DATABASES);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(SHOW_TABLES);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(SHOW_COLUMNS);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(SHOW_DICTIONARIES);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(SHOW);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(SELECT);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(INSERT);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(UPDATE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DELETE);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ADD_COLUMN);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_COLUMN);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(MODIFY_COLUMN);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(COMMENT_COLUMN);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CLEAR_COLUMN);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(RENAME_COLUMN);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_COLUMN);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_ORDER_BY);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ADD_INDEX);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_INDEX);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(MATERIALIZE_INDEX);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CLEAR_INDEX);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(INDEX);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ADD_CONSTRAINT);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_CONSTRAINT);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_CONSTRAINT);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(MODIFY_TTL);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(MATERIALIZE_TTL);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(MODIFY_SETTING);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(MOVE_PARTITION);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(FETCH_PARTITION);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(FREEZE_PARTITION);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_TABLE);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(REFRESH_VIEW);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(MODIFY_VIEW_QUERY);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_VIEW);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_DATABASE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_TABLE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_VIEW);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_DICTIONARY);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_TEMPORARY_TABLE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_DATABASE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_TABLE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_VIEW);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_DICTIONARY);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(TRUNCATE_TABLE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(TRUNCATE_VIEW);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(TRUNCATE);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(OPTIMIZE);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(KILL_QUERY);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_USER);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_USER);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_USER);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_ROLE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_ROLE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_ROLE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_POLICY);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_POLICY);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_POLICY);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_QUOTA);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_QUOTA);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_QUOTA);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(CREATE_SETTINGS_PROFILE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ALTER_SETTINGS_PROFILE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_SETTINGS_PROFILE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(ROLE_ADMIN);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(SHUTDOWN);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(DROP_CACHE);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(RELOAD_CONFIG);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(RELOAD_DICTIONARY);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(STOP_MERGES);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(STOP_TTL_MERGES);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(STOP_FETCHES);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(STOP_MOVES);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(STOP_DISTRIBUTED_SENDS);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(STOP_REPLICATED_SENDS);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(STOP_REPLICATION_QUEUES);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(SYNC_REPLICA);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(RESTART_REPLICA);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(FLUSH_DISTRIBUTED);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(FLUSH_LOGS);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(SYSTEM);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(dictGet);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(dictHas);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(dictGetHierarchy);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(dictIsIn);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(addressToLine);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(addressToSymbol);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(demangle);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(INTROSPECTION);
|
||||
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(file);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(url);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(input);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(values);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(numbers);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(zeros);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(merge);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(remote);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(mysql);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(odbc);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(jdbc);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(hdfs);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(s3);
|
||||
ACCESS_TYPE_TO_KEYWORD_CASE(TABLE_FUNCTIONS);
|
||||
|
||||
#undef ACCESS_TYPE_TO_KEYWORD_CASE
|
||||
}
|
||||
|
||||
std::array<String, MAX_ACCESS_TYPE> access_type_to_keyword_mapping;
|
||||
Strings access_type_to_keyword_mapping;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ public:
|
||||
|
||||
/// Allows IP addresses or host names using LIKE pattern.
|
||||
/// This pattern can contain % and _ wildcard characters.
|
||||
/// For example, addLikePattern("@") will allow all addresses.
|
||||
/// For example, addLikePattern("%") will allow all addresses.
|
||||
void addLikePattern(const String & pattern);
|
||||
void removeLikePattern(const String & like_pattern);
|
||||
const std::vector<String> & getLikePatterns() const { return like_patterns; }
|
||||
@ -298,7 +298,7 @@ inline void AllowedClientHosts::addLikePattern(const String & pattern)
|
||||
{
|
||||
if (boost::iequals(pattern, "localhost") || (pattern == "127.0.0.1") || (pattern == "::1"))
|
||||
local_host = true;
|
||||
else if ((pattern == "@") || (pattern == "0.0.0.0/0") || (pattern == "::/0"))
|
||||
else if ((pattern == "%") || (pattern == "0.0.0.0/0") || (pattern == "::/0"))
|
||||
any_host = true;
|
||||
else if (boost::range::find(like_patterns, pattern) == name_regexps.end())
|
||||
like_patterns.push_back(pattern);
|
||||
@ -308,7 +308,7 @@ inline void AllowedClientHosts::removeLikePattern(const String & pattern)
|
||||
{
|
||||
if (boost::iequals(pattern, "localhost") || (pattern == "127.0.0.1") || (pattern == "::1"))
|
||||
local_host = false;
|
||||
else if ((pattern == "@") || (pattern == "0.0.0.0/0") || (pattern == "::/0"))
|
||||
else if ((pattern == "%") || (pattern == "0.0.0.0/0") || (pattern == "::/0"))
|
||||
any_host = false;
|
||||
else
|
||||
boost::range::remove_erase(like_patterns, pattern);
|
||||
|
@ -404,23 +404,19 @@ boost::shared_ptr<const AccessRights> ContextAccess::calculateResultAccess(bool
|
||||
static const AccessFlags table_ddl = AccessType::CREATE_DATABASE | AccessType::CREATE_TABLE | AccessType::CREATE_VIEW
|
||||
| AccessType::ALTER_TABLE | AccessType::ALTER_VIEW | AccessType::DROP_DATABASE | AccessType::DROP_TABLE | AccessType::DROP_VIEW
|
||||
| AccessType::TRUNCATE;
|
||||
|
||||
static const AccessFlags dictionary_ddl = AccessType::CREATE_DICTIONARY | AccessType::DROP_DICTIONARY;
|
||||
static const AccessFlags table_and_dictionary_ddl = table_ddl | dictionary_ddl;
|
||||
static const AccessFlags write_table_access = AccessType::INSERT | AccessType::OPTIMIZE;
|
||||
static const AccessFlags all_dcl = AccessType::CREATE_USER | AccessType::CREATE_ROLE | AccessType::CREATE_POLICY
|
||||
| AccessType::CREATE_QUOTA | AccessType::CREATE_SETTINGS_PROFILE | AccessType::ALTER_USER | AccessType::ALTER_ROLE
|
||||
| AccessType::ALTER_POLICY | AccessType::ALTER_QUOTA | AccessType::ALTER_SETTINGS_PROFILE | AccessType::DROP_USER
|
||||
| AccessType::DROP_ROLE | AccessType::DROP_POLICY | AccessType::DROP_QUOTA | AccessType::DROP_SETTINGS_PROFILE
|
||||
| AccessType::ROLE_ADMIN;
|
||||
|
||||
if (readonly_)
|
||||
merged_access->revoke(write_table_access | all_dcl | table_and_dictionary_ddl | AccessType::SYSTEM | AccessType::KILL_QUERY);
|
||||
merged_access->revoke(write_table_access | table_and_dictionary_ddl | AccessType::SYSTEM | AccessType::KILL_QUERY | AccessType::ACCESS_MANAGEMENT);
|
||||
|
||||
if (readonly_ == 1)
|
||||
{
|
||||
/// Table functions are forbidden in readonly mode.
|
||||
/// For example, for readonly = 2 - allowed.
|
||||
merged_access->revoke(AccessType::CREATE_TEMPORARY_TABLE | AccessType::TABLE_FUNCTIONS);
|
||||
merged_access->revoke(AccessType::CREATE_TEMPORARY_TABLE);
|
||||
}
|
||||
|
||||
if (!allow_ddl_ && !grant_option)
|
||||
|
@ -51,25 +51,25 @@ ExtendedRoleSet::ExtendedRoleSet(const boost::container::flat_set<UUID> & ids_)
|
||||
|
||||
ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast)
|
||||
{
|
||||
init(ast, nullptr, nullptr);
|
||||
init(ast, nullptr);
|
||||
}
|
||||
|
||||
ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast, const UUID & current_user_id)
|
||||
ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast, const std::optional<UUID> & current_user_id)
|
||||
{
|
||||
init(ast, nullptr, ¤t_user_id);
|
||||
init(ast, nullptr, current_user_id);
|
||||
}
|
||||
|
||||
ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager)
|
||||
{
|
||||
init(ast, &manager, nullptr);
|
||||
init(ast, &manager);
|
||||
}
|
||||
|
||||
ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager, const UUID & current_user_id)
|
||||
ExtendedRoleSet::ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager, const std::optional<UUID> & current_user_id)
|
||||
{
|
||||
init(ast, &manager, ¤t_user_id);
|
||||
init(ast, &manager, current_user_id);
|
||||
}
|
||||
|
||||
void ExtendedRoleSet::init(const ASTExtendedRoleSet & ast, const AccessControlManager * manager, const UUID * current_user_id)
|
||||
void ExtendedRoleSet::init(const ASTExtendedRoleSet & ast, const AccessControlManager * manager, const std::optional<UUID> & current_user_id)
|
||||
{
|
||||
all = ast.all;
|
||||
|
||||
|
@ -32,9 +32,9 @@ struct ExtendedRoleSet
|
||||
|
||||
/// The constructor from AST requires the AccessControlManager if `ast.id_mode == false`.
|
||||
ExtendedRoleSet(const ASTExtendedRoleSet & ast);
|
||||
ExtendedRoleSet(const ASTExtendedRoleSet & ast, const UUID & current_user_id);
|
||||
ExtendedRoleSet(const ASTExtendedRoleSet & ast, const std::optional<UUID> & current_user_id);
|
||||
ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager);
|
||||
ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager, const UUID & current_user_id);
|
||||
ExtendedRoleSet(const ASTExtendedRoleSet & ast, const AccessControlManager & manager, const std::optional<UUID> & current_user_id);
|
||||
|
||||
std::shared_ptr<ASTExtendedRoleSet> toAST() const;
|
||||
String toString() const;
|
||||
@ -69,7 +69,7 @@ struct ExtendedRoleSet
|
||||
boost::container::flat_set<UUID> except_ids;
|
||||
|
||||
private:
|
||||
void init(const ASTExtendedRoleSet & ast, const AccessControlManager * manager = nullptr, const UUID * current_user_id = nullptr);
|
||||
void init(const ASTExtendedRoleSet & ast, const AccessControlManager * manager = nullptr, const std::optional<UUID> & current_user_id = {});
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -168,7 +168,14 @@ namespace
|
||||
user->access.grant(AccessFlags::allDictionaryFlags(), IDictionary::NO_DATABASE_TAG, dictionary);
|
||||
}
|
||||
|
||||
user->access_with_grant_option = user->access;
|
||||
user->access_with_grant_option = user->access; /// By default the user can grant everything he has.
|
||||
|
||||
bool access_management = config.getBool(user_config + ".access_management", false);
|
||||
if (!access_management)
|
||||
{
|
||||
user->access.revoke(AccessType::ACCESS_MANAGEMENT);
|
||||
user->access_with_grant_option.clear();
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <IO/ReadHelpers.h>
|
||||
#include <IO/ReadWriteBufferFromHTTP.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Access/AccessType.h>
|
||||
#include <Parsers/IdentifierQuotingStyle.h>
|
||||
#include <Poco/File.h>
|
||||
#include <Poco/Logger.h>
|
||||
@ -230,6 +231,10 @@ struct JDBCBridgeMixin
|
||||
{
|
||||
return "JDBC";
|
||||
}
|
||||
static AccessType getSourceAccessType()
|
||||
{
|
||||
return AccessType::JDBC;
|
||||
}
|
||||
|
||||
static std::unique_ptr<ShellCommand> startBridge(const Poco::Util::AbstractConfiguration &, const Poco::Logger *, const Poco::Timespan &)
|
||||
{
|
||||
@ -253,6 +258,10 @@ struct ODBCBridgeMixin
|
||||
{
|
||||
return "ODBC";
|
||||
}
|
||||
static AccessType getSourceAccessType()
|
||||
{
|
||||
return AccessType::ODBC;
|
||||
}
|
||||
|
||||
static std::unique_ptr<ShellCommand> startBridge(const Poco::Util::AbstractConfiguration & config, Poco::Logger * log, const Poco::Timespan & http_timeout)
|
||||
{
|
||||
|
@ -128,7 +128,7 @@ private:
|
||||
|
||||
auto dict = dictionaries_loader.getDictionary(dict_name_col->getValue<String>());
|
||||
const auto dict_ptr = dict.get();
|
||||
context.checkAccess(AccessType::dictHas, dict_ptr->getDatabaseOrNoDatabaseTag(), dict_ptr->getName());
|
||||
context.checkAccess(AccessType::dictGet, dict_ptr->getDatabaseOrNoDatabaseTag(), dict_ptr->getName());
|
||||
|
||||
if (!executeDispatchSimple<FlatDictionary>(block, arguments, result, dict_ptr) &&
|
||||
!executeDispatchSimple<HashedDictionary>(block, arguments, result, dict_ptr) &&
|
||||
@ -1652,7 +1652,7 @@ private:
|
||||
|
||||
auto dict = dictionaries_loader.getDictionary(dict_name_col->getValue<String>());
|
||||
const auto dict_ptr = dict.get();
|
||||
context.checkAccess(AccessType::dictGetHierarchy, dict_ptr->getDatabaseOrNoDatabaseTag(), dict_ptr->getName());
|
||||
context.checkAccess(AccessType::dictGet, dict_ptr->getDatabaseOrNoDatabaseTag(), dict_ptr->getName());
|
||||
|
||||
if (!executeDispatch<FlatDictionary>(block, arguments, result, dict_ptr) &&
|
||||
!executeDispatch<HashedDictionary>(block, arguments, result, dict_ptr) &&
|
||||
@ -1816,7 +1816,7 @@ private:
|
||||
|
||||
auto dict = dictionaries_loader.getDictionary(dict_name_col->getValue<String>());
|
||||
const auto dict_ptr = dict.get();
|
||||
context.checkAccess(AccessType::dictIsIn, dict_ptr->getDatabaseOrNoDatabaseTag(), dict_ptr->getName());
|
||||
context.checkAccess(AccessType::dictGet, dict_ptr->getDatabaseOrNoDatabaseTag(), dict_ptr->getName());
|
||||
|
||||
if (!executeDispatch<FlatDictionary>(block, arguments, result, dict_ptr)
|
||||
&& !executeDispatch<HashedDictionary>(block, arguments, result, dict_ptr)
|
||||
|
@ -665,12 +665,10 @@ String Context::getUserName() const
|
||||
return access->getUserName();
|
||||
}
|
||||
|
||||
UUID Context::getUserID() const
|
||||
std::optional<UUID> Context::getUserID() const
|
||||
{
|
||||
auto lock = getLock();
|
||||
if (!user_id)
|
||||
throw Exception("No current user", ErrorCodes::LOGICAL_ERROR);
|
||||
return *user_id;
|
||||
return user_id;
|
||||
}
|
||||
|
||||
|
||||
|
@ -233,7 +233,7 @@ public:
|
||||
|
||||
UserPtr getUser() const;
|
||||
String getUserName() const;
|
||||
UUID getUserID() const;
|
||||
std::optional<UUID> getUserID() const;
|
||||
|
||||
void setCurrentRoles(const std::vector<UUID> & current_roles_);
|
||||
void setCurrentRolesDefault();
|
||||
|
@ -1377,4 +1377,9 @@ BlockIO executeDDLQueryOnCluster(const ASTPtr & query_ptr_, const Context & cont
|
||||
}
|
||||
|
||||
|
||||
BlockIO executeDDLQueryOnCluster(const ASTPtr & query_ptr_, const Context & context)
|
||||
{
|
||||
return executeDDLQueryOnCluster(query_ptr_, context, {});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ struct DDLTask;
|
||||
|
||||
/// Pushes distributed DDL query to the queue
|
||||
BlockIO executeDDLQueryOnCluster(const ASTPtr & query_ptr, const Context & context, AccessRightsElements && query_required_access);
|
||||
BlockIO executeDDLQueryOnCluster(const ASTPtr & query_ptr, const Context & context);
|
||||
|
||||
|
||||
class DDLWorker
|
||||
|
@ -149,35 +149,35 @@ AccessRightsElements InterpreterAlterQuery::getRequiredAccessForCommand(const AS
|
||||
{
|
||||
case ASTAlterCommand::UPDATE:
|
||||
{
|
||||
required_access.emplace_back(AccessType::UPDATE, database, table, column_names_from_update_assignments());
|
||||
required_access.emplace_back(AccessType::ALTER_UPDATE, database, table, column_names_from_update_assignments());
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::DELETE:
|
||||
{
|
||||
required_access.emplace_back(AccessType::DELETE, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_DELETE, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::ADD_COLUMN:
|
||||
{
|
||||
required_access.emplace_back(AccessType::ADD_COLUMN, database, table, column_name_from_col_decl());
|
||||
required_access.emplace_back(AccessType::ALTER_ADD_COLUMN, database, table, column_name_from_col_decl());
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::DROP_COLUMN:
|
||||
{
|
||||
if (command.clear_column)
|
||||
required_access.emplace_back(AccessType::CLEAR_COLUMN, database, table, column_name());
|
||||
required_access.emplace_back(AccessType::ALTER_CLEAR_COLUMN, database, table, column_name());
|
||||
else
|
||||
required_access.emplace_back(AccessType::DROP_COLUMN, database, table, column_name());
|
||||
required_access.emplace_back(AccessType::ALTER_DROP_COLUMN, database, table, column_name());
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::MODIFY_COLUMN:
|
||||
{
|
||||
required_access.emplace_back(AccessType::MODIFY_COLUMN, database, table, column_name_from_col_decl());
|
||||
required_access.emplace_back(AccessType::ALTER_MODIFY_COLUMN, database, table, column_name_from_col_decl());
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::COMMENT_COLUMN:
|
||||
{
|
||||
required_access.emplace_back(AccessType::COMMENT_COLUMN, database, table, column_name());
|
||||
required_access.emplace_back(AccessType::ALTER_COMMENT_COLUMN, database, table, column_name());
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::MODIFY_ORDER_BY:
|
||||
@ -187,45 +187,45 @@ AccessRightsElements InterpreterAlterQuery::getRequiredAccessForCommand(const AS
|
||||
}
|
||||
case ASTAlterCommand::ADD_INDEX:
|
||||
{
|
||||
required_access.emplace_back(AccessType::ADD_INDEX, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_ADD_INDEX, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::DROP_INDEX:
|
||||
{
|
||||
if (command.clear_index)
|
||||
required_access.emplace_back(AccessType::CLEAR_INDEX, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_CLEAR_INDEX, database, table);
|
||||
else
|
||||
required_access.emplace_back(AccessType::DROP_INDEX, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_DROP_INDEX, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::MATERIALIZE_INDEX:
|
||||
{
|
||||
required_access.emplace_back(AccessType::MATERIALIZE_INDEX, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_MATERIALIZE_INDEX, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::ADD_CONSTRAINT:
|
||||
{
|
||||
required_access.emplace_back(AccessType::ADD_CONSTRAINT, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_ADD_CONSTRAINT, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::DROP_CONSTRAINT:
|
||||
{
|
||||
required_access.emplace_back(AccessType::DROP_CONSTRAINT, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_DROP_CONSTRAINT, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::MODIFY_TTL:
|
||||
{
|
||||
required_access.emplace_back(AccessType::MODIFY_TTL, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_TTL, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::MATERIALIZE_TTL:
|
||||
{
|
||||
required_access.emplace_back(AccessType::MATERIALIZE_TTL, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_MATERIALIZE_TTL, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::MODIFY_SETTING:
|
||||
{
|
||||
required_access.emplace_back(AccessType::MODIFY_SETTING, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_SETTINGS, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::ATTACH_PARTITION:
|
||||
@ -236,7 +236,7 @@ AccessRightsElements InterpreterAlterQuery::getRequiredAccessForCommand(const AS
|
||||
case ASTAlterCommand::DROP_PARTITION: [[fallthrough]];
|
||||
case ASTAlterCommand::DROP_DETACHED_PARTITION:
|
||||
{
|
||||
required_access.emplace_back(AccessType::DELETE, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_DELETE, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::MOVE_PARTITION:
|
||||
@ -244,11 +244,11 @@ AccessRightsElements InterpreterAlterQuery::getRequiredAccessForCommand(const AS
|
||||
if ((command.move_destination_type == PartDestinationType::DISK)
|
||||
|| (command.move_destination_type == PartDestinationType::VOLUME))
|
||||
{
|
||||
required_access.emplace_back(AccessType::MOVE_PARTITION, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_MOVE_PARTITION, database, table);
|
||||
}
|
||||
else if (command.move_destination_type == PartDestinationType::TABLE)
|
||||
{
|
||||
required_access.emplace_back(AccessType::SELECT | AccessType::DELETE, database, table);
|
||||
required_access.emplace_back(AccessType::SELECT | AccessType::ALTER_DELETE, database, table);
|
||||
required_access.emplace_back(AccessType::INSERT, command.to_database, command.to_table);
|
||||
}
|
||||
break;
|
||||
@ -256,33 +256,33 @@ AccessRightsElements InterpreterAlterQuery::getRequiredAccessForCommand(const AS
|
||||
case ASTAlterCommand::REPLACE_PARTITION:
|
||||
{
|
||||
required_access.emplace_back(AccessType::SELECT, command.from_database, command.from_table);
|
||||
required_access.emplace_back(AccessType::DELETE | AccessType::INSERT, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_DELETE | AccessType::INSERT, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::FETCH_PARTITION:
|
||||
{
|
||||
required_access.emplace_back(AccessType::FETCH_PARTITION, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_FETCH_PARTITION, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::FREEZE_PARTITION: [[fallthrough]];
|
||||
case ASTAlterCommand::FREEZE_ALL:
|
||||
{
|
||||
required_access.emplace_back(AccessType::FREEZE_PARTITION, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_FREEZE_PARTITION, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::MODIFY_QUERY:
|
||||
{
|
||||
required_access.emplace_back(AccessType::MODIFY_VIEW_QUERY, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_VIEW_MODIFY_QUERY, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::LIVE_VIEW_REFRESH:
|
||||
{
|
||||
required_access.emplace_back(AccessType::REFRESH_VIEW, database, table);
|
||||
required_access.emplace_back(AccessType::ALTER_VIEW_REFRESH, database, table);
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::RENAME_COLUMN:
|
||||
{
|
||||
required_access.emplace_back(AccessType::RENAME_COLUMN, database, table, column_name());
|
||||
required_access.emplace_back(AccessType::ALTER_RENAME_COLUMN, database, table, column_name());
|
||||
break;
|
||||
}
|
||||
case ASTAlterCommand::NO_TYPE: break;
|
||||
|
@ -765,7 +765,14 @@ AccessRightsElements InterpreterCreateQuery::getRequiredAccess() const
|
||||
}
|
||||
|
||||
if (!create.to_table.empty())
|
||||
required_access.emplace_back(AccessType::INSERT, create.to_database, create.to_table);
|
||||
required_access.emplace_back(AccessType::SELECT | AccessType::INSERT, create.to_database, create.to_table);
|
||||
|
||||
if (create.storage && create.storage->engine)
|
||||
{
|
||||
auto source_access_type = StorageFactory::instance().getSourceAccessType(create.storage->engine->name);
|
||||
if (source_access_type != AccessType::NONE)
|
||||
required_access.emplace_back(source_access_type);
|
||||
}
|
||||
|
||||
return required_access;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <Parsers/ASTCreateQuotaQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/DDLWorker.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <ext/range.h>
|
||||
@ -76,10 +77,16 @@ void updateQuotaFromQueryImpl(Quota & quota, const ASTCreateQuotaQuery & query,
|
||||
|
||||
BlockIO InterpreterCreateQuotaQuery::execute()
|
||||
{
|
||||
const auto & query = query_ptr->as<const ASTCreateQuotaQuery &>();
|
||||
auto & query = query_ptr->as<ASTCreateQuotaQuery &>();
|
||||
auto & access_control = context.getAccessControlManager();
|
||||
context.checkAccess(query.alter ? AccessType::ALTER_QUOTA : AccessType::CREATE_QUOTA);
|
||||
|
||||
if (!query.cluster.empty())
|
||||
{
|
||||
query.replaceCurrentUserTagWithName(context.getUserName());
|
||||
return executeDDLQueryOnCluster(query_ptr, context);
|
||||
}
|
||||
|
||||
std::optional<ExtendedRoleSet> roles_from_query;
|
||||
if (query.roles)
|
||||
roles_from_query = ExtendedRoleSet{*query.roles, access_control, context.getUserID()};
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <Interpreters/InterpreterCreateRoleQuery.h>
|
||||
#include <Parsers/ASTCreateRoleQuery.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/DDLWorker.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/Role.h>
|
||||
|
||||
@ -44,6 +45,9 @@ BlockIO InterpreterCreateRoleQuery::execute()
|
||||
else
|
||||
context.checkAccess(AccessType::CREATE_ROLE);
|
||||
|
||||
if (!query.cluster.empty())
|
||||
return executeDDLQueryOnCluster(query_ptr, context);
|
||||
|
||||
std::optional<SettingsProfileElements> settings_from_query;
|
||||
if (query.settings)
|
||||
settings_from_query = SettingsProfileElements{*query.settings, access_control};
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Parsers/formatAST.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/DDLWorker.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <boost/range/algorithm/sort.hpp>
|
||||
@ -63,9 +64,15 @@ namespace
|
||||
|
||||
BlockIO InterpreterCreateRowPolicyQuery::execute()
|
||||
{
|
||||
const auto & query = query_ptr->as<const ASTCreateRowPolicyQuery &>();
|
||||
auto & query = query_ptr->as<ASTCreateRowPolicyQuery &>();
|
||||
auto & access_control = context.getAccessControlManager();
|
||||
context.checkAccess(query.alter ? AccessType::ALTER_POLICY : AccessType::CREATE_POLICY);
|
||||
context.checkAccess(query.alter ? AccessType::ALTER_ROW_POLICY : AccessType::CREATE_ROW_POLICY);
|
||||
|
||||
if (!query.cluster.empty())
|
||||
{
|
||||
query.replaceCurrentUserTagWithName(context.getUserName());
|
||||
return executeDDLQueryOnCluster(query_ptr, context);
|
||||
}
|
||||
|
||||
std::optional<ExtendedRoleSet> roles_from_query;
|
||||
if (query.roles)
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include <Interpreters/InterpreterCreateSettingsProfileQuery.h>
|
||||
#include <Parsers/ASTCreateSettingsProfileQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/DDLWorker.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/SettingsProfile.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
@ -49,13 +51,19 @@ namespace
|
||||
|
||||
BlockIO InterpreterCreateSettingsProfileQuery::execute()
|
||||
{
|
||||
const auto & query = query_ptr->as<const ASTCreateSettingsProfileQuery &>();
|
||||
auto & query = query_ptr->as<ASTCreateSettingsProfileQuery &>();
|
||||
auto & access_control = context.getAccessControlManager();
|
||||
if (query.alter)
|
||||
context.checkAccess(AccessType::ALTER_SETTINGS_PROFILE);
|
||||
else
|
||||
context.checkAccess(AccessType::CREATE_SETTINGS_PROFILE);
|
||||
|
||||
if (!query.cluster.empty())
|
||||
{
|
||||
query.replaceCurrentUserTagWithName(context.getUserName());
|
||||
return executeDDLQueryOnCluster(query_ptr, context);
|
||||
}
|
||||
|
||||
std::optional<SettingsProfileElements> settings_from_query;
|
||||
if (query.settings)
|
||||
settings_from_query = SettingsProfileElements{*query.settings, access_control};
|
||||
|
@ -1,10 +1,11 @@
|
||||
#include <Interpreters/InterpreterCreateUserQuery.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/InterpreterSetRoleQuery.h>
|
||||
#include <Interpreters/DDLWorker.h>
|
||||
#include <Parsers/ASTCreateUserQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/User.h>
|
||||
#include <Access/ExtendedRoleSet.h>
|
||||
#include <Access/ContextAccess.h>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
|
||||
@ -67,7 +68,7 @@ namespace
|
||||
|
||||
BlockIO InterpreterCreateUserQuery::execute()
|
||||
{
|
||||
const auto & query = query_ptr->as<const ASTCreateUserQuery &>();
|
||||
auto & query = query_ptr->as<const ASTCreateUserQuery &>();
|
||||
auto & access_control = context.getAccessControlManager();
|
||||
auto access = context.getAccess();
|
||||
access->checkAccess(query.alter ? AccessType::ALTER_USER : AccessType::CREATE_USER);
|
||||
@ -83,6 +84,9 @@ BlockIO InterpreterCreateUserQuery::execute()
|
||||
}
|
||||
}
|
||||
|
||||
if (!query.cluster.empty())
|
||||
return executeDDLQueryOnCluster(query_ptr, context);
|
||||
|
||||
std::optional<SettingsProfileElements> settings_from_query;
|
||||
if (query.settings)
|
||||
settings_from_query = SettingsProfileElements{*query.settings, access_control};
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <Interpreters/InterpreterDropAccessEntityQuery.h>
|
||||
#include <Parsers/ASTDropAccessEntityQuery.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/DDLWorker.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <Access/User.h>
|
||||
@ -37,7 +38,7 @@ namespace
|
||||
case Kind::USER: return AccessType::DROP_USER;
|
||||
case Kind::ROLE: return AccessType::DROP_ROLE;
|
||||
case Kind::QUOTA: return AccessType::DROP_QUOTA;
|
||||
case Kind::ROW_POLICY: return AccessType::DROP_POLICY;
|
||||
case Kind::ROW_POLICY: return AccessType::DROP_ROW_POLICY;
|
||||
case Kind::SETTINGS_PROFILE: return AccessType::DROP_SETTINGS_PROFILE;
|
||||
}
|
||||
__builtin_unreachable();
|
||||
@ -52,6 +53,9 @@ BlockIO InterpreterDropAccessEntityQuery::execute()
|
||||
std::type_index type = getType(query.kind);
|
||||
context.checkAccess(getRequiredAccessType(query.kind));
|
||||
|
||||
if (!query.cluster.empty())
|
||||
return executeDDLQueryOnCluster(query_ptr, context);
|
||||
|
||||
if (query.kind == Kind::ROW_POLICY)
|
||||
{
|
||||
Strings full_names;
|
||||
|
@ -99,7 +99,7 @@ BlockIO InterpreterDropQuery::executeToTable(
|
||||
}
|
||||
else if (kind == ASTDropQuery::Kind::Truncate)
|
||||
{
|
||||
context.checkAccess(table->isView() ? AccessType::TRUNCATE_VIEW : AccessType::TRUNCATE_TABLE, table_id);
|
||||
context.checkAccess(AccessType::TRUNCATE, table_id);
|
||||
table->checkTableCanBeDropped();
|
||||
|
||||
/// If table was already dropped by anyone, an exception will be thrown
|
||||
@ -316,7 +316,7 @@ AccessRightsElements InterpreterDropQuery::getRequiredAccessForDDLOnCluster() co
|
||||
if (drop.kind == ASTDropQuery::Kind::Drop)
|
||||
required_access.emplace_back(AccessType::DROP_TABLE | AccessType::DROP_VIEW, drop.database, drop.table);
|
||||
else if (drop.kind == ASTDropQuery::Kind::Truncate)
|
||||
required_access.emplace_back(AccessType::TRUNCATE_TABLE | AccessType::TRUNCATE_VIEW, drop.database, drop.table);
|
||||
required_access.emplace_back(AccessType::TRUNCATE, drop.database, drop.table);
|
||||
else if (drop.kind == ASTDropQuery::Kind::Detach)
|
||||
required_access.emplace_back(AccessType::DROP_TABLE | AccessType::DROP_VIEW, drop.database, drop.table);
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include <Interpreters/InterpreterGrantQuery.h>
|
||||
#include <Parsers/ASTGrantQuery.h>
|
||||
#include <Parsers/ASTExtendedRoleSet.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/DDLWorker.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/ContextAccess.h>
|
||||
#include <Access/ExtendedRoleSet.h>
|
||||
@ -59,7 +61,7 @@ namespace
|
||||
|
||||
BlockIO InterpreterGrantQuery::execute()
|
||||
{
|
||||
const auto & query = query_ptr->as<const ASTGrantQuery &>();
|
||||
auto & query = query_ptr->as<ASTGrantQuery &>();
|
||||
auto & access_control = context.getAccessControlManager();
|
||||
auto access = context.getAccess();
|
||||
access->checkGrantOption(query.access_rights_elements);
|
||||
@ -72,6 +74,12 @@ BlockIO InterpreterGrantQuery::execute()
|
||||
access->checkAdminOption(role_from_query);
|
||||
}
|
||||
|
||||
if (!query.cluster.empty())
|
||||
{
|
||||
query.replaceCurrentUserTagWithName(context.getUserName());
|
||||
return executeDDLQueryOnCluster(query_ptr, context);
|
||||
}
|
||||
|
||||
std::vector<UUID> to_roles = ExtendedRoleSet{*query.to_roles, access_control, context.getUserID()}.getMatchingIDs(access_control);
|
||||
String current_database = context.getCurrentDatabase();
|
||||
|
||||
|
@ -319,7 +319,7 @@ AccessRightsElements InterpreterKillQueryQuery::getRequiredAccessForDDLOnCluster
|
||||
if (query.type == ASTKillQueryQuery::Type::Query)
|
||||
required_access.emplace_back(AccessType::KILL_QUERY);
|
||||
else if (query.type == ASTKillQueryQuery::Type::Mutation)
|
||||
required_access.emplace_back(AccessType::UPDATE | AccessType::DELETE | AccessType::MATERIALIZE_INDEX | AccessType::MATERIALIZE_TTL);
|
||||
required_access.emplace_back(AccessType::ALTER_UPDATE | AccessType::ALTER_DELETE | AccessType::ALTER_MATERIALIZE_INDEX | AccessType::ALTER_MATERIALIZE_TTL);
|
||||
return required_access;
|
||||
}
|
||||
|
||||
|
@ -256,6 +256,7 @@ BlockInputStreamPtr InterpreterShowCreateAccessEntityQuery::executeImpl()
|
||||
ASTPtr InterpreterShowCreateAccessEntityQuery::getCreateQuery(const ASTShowCreateAccessEntityQuery & show_query) const
|
||||
{
|
||||
const auto & access_control = context.getAccessControlManager();
|
||||
context.checkAccess(getRequiredAccess());
|
||||
|
||||
if (show_query.current_user)
|
||||
{
|
||||
@ -281,6 +282,22 @@ ASTPtr InterpreterShowCreateAccessEntityQuery::getCreateQuery(const ASTShowCreat
|
||||
}
|
||||
|
||||
|
||||
AccessRightsElements InterpreterShowCreateAccessEntityQuery::getRequiredAccess() const
|
||||
{
|
||||
const auto & show_query = query_ptr->as<ASTShowCreateAccessEntityQuery &>();
|
||||
AccessRightsElements res;
|
||||
switch (show_query.kind)
|
||||
{
|
||||
case Kind::USER: res.emplace_back(AccessType::SHOW_USERS); break;
|
||||
case Kind::ROLE: res.emplace_back(AccessType::SHOW_ROLES); break;
|
||||
case Kind::ROW_POLICY: res.emplace_back(AccessType::SHOW_ROW_POLICIES); break;
|
||||
case Kind::SETTINGS_PROFILE: res.emplace_back(AccessType::SHOW_SETTINGS_PROFILES); break;
|
||||
case Kind::QUOTA: res.emplace_back(AccessType::SHOW_QUOTAS); break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
ASTPtr InterpreterShowCreateAccessEntityQuery::getAttachQuery(const IAccessEntity & entity)
|
||||
{
|
||||
return getCreateQueryImpl(entity, nullptr, true);
|
||||
|
@ -9,6 +9,7 @@ namespace DB
|
||||
{
|
||||
class Context;
|
||||
class ASTShowCreateAccessEntityQuery;
|
||||
class AccessRightsElements;
|
||||
struct IAccessEntity;
|
||||
|
||||
|
||||
@ -30,6 +31,7 @@ public:
|
||||
private:
|
||||
BlockInputStreamPtr executeImpl();
|
||||
ASTPtr getCreateQuery(const ASTShowCreateAccessEntityQuery & show_query) const;
|
||||
AccessRightsElements getRequiredAccess() const;
|
||||
|
||||
ASTPtr query_ptr;
|
||||
const Context & context;
|
||||
|
@ -102,19 +102,19 @@ void executeCommandsAndThrowIfError(Callables && ... commands)
|
||||
AccessType getRequiredAccessType(StorageActionBlockType action_type)
|
||||
{
|
||||
if (action_type == ActionLocks::PartsMerge)
|
||||
return AccessType::STOP_MERGES;
|
||||
return AccessType::SYSTEM_MERGES;
|
||||
else if (action_type == ActionLocks::PartsFetch)
|
||||
return AccessType::STOP_FETCHES;
|
||||
return AccessType::SYSTEM_FETCHES;
|
||||
else if (action_type == ActionLocks::PartsSend)
|
||||
return AccessType::STOP_REPLICATED_SENDS;
|
||||
return AccessType::SYSTEM_REPLICATED_SENDS;
|
||||
else if (action_type == ActionLocks::ReplicationQueue)
|
||||
return AccessType::STOP_REPLICATION_QUEUES;
|
||||
return AccessType::SYSTEM_REPLICATION_QUEUES;
|
||||
else if (action_type == ActionLocks::DistributedSend)
|
||||
return AccessType::STOP_DISTRIBUTED_SENDS;
|
||||
return AccessType::SYSTEM_DISTRIBUTED_SENDS;
|
||||
else if (action_type == ActionLocks::PartsTTLMerge)
|
||||
return AccessType::STOP_TTL_MERGES;
|
||||
return AccessType::SYSTEM_TTL_MERGES;
|
||||
else if (action_type == ActionLocks::PartsMove)
|
||||
return AccessType::STOP_MOVES;
|
||||
return AccessType::SYSTEM_MOVES;
|
||||
else
|
||||
throw Exception("Unknown action type: " + std::to_string(action_type), ErrorCodes::LOGICAL_ERROR);
|
||||
}
|
||||
@ -183,42 +183,42 @@ BlockIO InterpreterSystemQuery::execute()
|
||||
switch (query.type)
|
||||
{
|
||||
case Type::SHUTDOWN:
|
||||
context.checkAccess(AccessType::SHUTDOWN);
|
||||
context.checkAccess(AccessType::SYSTEM_SHUTDOWN);
|
||||
if (kill(0, SIGTERM))
|
||||
throwFromErrno("System call kill(0, SIGTERM) failed", ErrorCodes::CANNOT_KILL);
|
||||
break;
|
||||
case Type::KILL:
|
||||
context.checkAccess(AccessType::SHUTDOWN);
|
||||
context.checkAccess(AccessType::SYSTEM_SHUTDOWN);
|
||||
if (kill(0, SIGKILL))
|
||||
throwFromErrno("System call kill(0, SIGKILL) failed", ErrorCodes::CANNOT_KILL);
|
||||
break;
|
||||
case Type::DROP_DNS_CACHE:
|
||||
context.checkAccess(AccessType::DROP_CACHE);
|
||||
context.checkAccess(AccessType::SYSTEM_DROP_DNS_CACHE);
|
||||
DNSResolver::instance().dropCache();
|
||||
/// Reinitialize clusters to update their resolved_addresses
|
||||
system_context.reloadClusterConfig();
|
||||
break;
|
||||
case Type::DROP_MARK_CACHE:
|
||||
context.checkAccess(AccessType::DROP_CACHE);
|
||||
context.checkAccess(AccessType::SYSTEM_DROP_MARK_CACHE);
|
||||
system_context.dropMarkCache();
|
||||
break;
|
||||
case Type::DROP_UNCOMPRESSED_CACHE:
|
||||
context.checkAccess(AccessType::DROP_CACHE);
|
||||
context.checkAccess(AccessType::SYSTEM_DROP_UNCOMPRESSED_CACHE);
|
||||
system_context.dropUncompressedCache();
|
||||
break;
|
||||
#if USE_EMBEDDED_COMPILER
|
||||
case Type::DROP_COMPILED_EXPRESSION_CACHE:
|
||||
context.checkAccess(AccessType::DROP_CACHE);
|
||||
context.checkAccess(AccessType::SYSTEM_DROP_COMPILED_EXPRESSION_CACHE);
|
||||
system_context.dropCompiledExpressionCache();
|
||||
break;
|
||||
#endif
|
||||
case Type::RELOAD_DICTIONARY:
|
||||
context.checkAccess(AccessType::RELOAD_DICTIONARY);
|
||||
context.checkAccess(AccessType::SYSTEM_RELOAD_DICTIONARY);
|
||||
system_context.getExternalDictionariesLoader().loadOrReload(query.target_dictionary);
|
||||
ExternalDictionariesLoader::resetAll();
|
||||
break;
|
||||
case Type::RELOAD_DICTIONARIES:
|
||||
context.checkAccess(AccessType::RELOAD_DICTIONARY);
|
||||
context.checkAccess(AccessType::SYSTEM_RELOAD_DICTIONARY);
|
||||
executeCommandsAndThrowIfError(
|
||||
[&] () { system_context.getExternalDictionariesLoader().reloadAllTriedToLoad(); },
|
||||
[&] () { system_context.getEmbeddedDictionaries().reload(); }
|
||||
@ -226,11 +226,11 @@ BlockIO InterpreterSystemQuery::execute()
|
||||
ExternalDictionariesLoader::resetAll();
|
||||
break;
|
||||
case Type::RELOAD_EMBEDDED_DICTIONARIES:
|
||||
context.checkAccess(AccessType::RELOAD_DICTIONARY);
|
||||
context.checkAccess(AccessType::SYSTEM_RELOAD_EMBEDDED_DICTIONARIES);
|
||||
system_context.getEmbeddedDictionaries().reload();
|
||||
break;
|
||||
case Type::RELOAD_CONFIG:
|
||||
context.checkAccess(AccessType::RELOAD_CONFIG);
|
||||
context.checkAccess(AccessType::SYSTEM_RELOAD_CONFIG);
|
||||
system_context.reloadConfig();
|
||||
break;
|
||||
case Type::STOP_MERGES:
|
||||
@ -290,7 +290,7 @@ BlockIO InterpreterSystemQuery::execute()
|
||||
ErrorCodes::BAD_ARGUMENTS);
|
||||
break;
|
||||
case Type::FLUSH_LOGS:
|
||||
context.checkAccess(AccessType::FLUSH_LOGS);
|
||||
context.checkAccess(AccessType::SYSTEM_FLUSH_LOGS);
|
||||
executeCommandsAndThrowIfError(
|
||||
[&] () { if (auto query_log = context.getQueryLog()) query_log->flush(); },
|
||||
[&] () { if (auto part_log = context.getPartLog("")) part_log->flush(); },
|
||||
@ -313,7 +313,7 @@ BlockIO InterpreterSystemQuery::execute()
|
||||
|
||||
StoragePtr InterpreterSystemQuery::tryRestartReplica(const StorageID & replica, Context & system_context, bool need_ddl_guard)
|
||||
{
|
||||
context.checkAccess(AccessType::RESTART_REPLICA, replica);
|
||||
context.checkAccess(AccessType::SYSTEM_RESTART_REPLICA, replica);
|
||||
|
||||
auto table_ddl_guard = need_ddl_guard ? DatabaseCatalog::instance().getDDLGuard(replica.getDatabaseName(), replica.getTableName()) : nullptr;
|
||||
auto [database, table] = DatabaseCatalog::instance().tryGetDatabaseAndTable(replica);
|
||||
@ -387,7 +387,7 @@ void InterpreterSystemQuery::restartReplicas(Context & system_context)
|
||||
|
||||
void InterpreterSystemQuery::syncReplica(ASTSystemQuery &)
|
||||
{
|
||||
context.checkAccess(AccessType::SYNC_REPLICA, table_id);
|
||||
context.checkAccess(AccessType::SYSTEM_SYNC_REPLICA, table_id);
|
||||
StoragePtr table = DatabaseCatalog::instance().getTable(table_id);
|
||||
|
||||
if (auto storage_replicated = dynamic_cast<StorageReplicatedMergeTree *>(table.get()))
|
||||
@ -408,7 +408,7 @@ void InterpreterSystemQuery::syncReplica(ASTSystemQuery &)
|
||||
|
||||
void InterpreterSystemQuery::flushDistributed(ASTSystemQuery &)
|
||||
{
|
||||
context.checkAccess(AccessType::FLUSH_DISTRIBUTED, table_id);
|
||||
context.checkAccess(AccessType::SYSTEM_FLUSH_DISTRIBUTED, table_id);
|
||||
|
||||
if (auto storage_distributed = dynamic_cast<StorageDistributed *>(DatabaseCatalog::instance().getTable(table_id).get()))
|
||||
storage_distributed->flushClusterNodesAllData();
|
||||
@ -427,7 +427,7 @@ AccessRightsElements InterpreterSystemQuery::getRequiredAccessForDDLOnCluster()
|
||||
case Type::SHUTDOWN: [[fallthrough]];
|
||||
case Type::KILL:
|
||||
{
|
||||
required_access.emplace_back(AccessType::SHUTDOWN);
|
||||
required_access.emplace_back(AccessType::SYSTEM_SHUTDOWN);
|
||||
break;
|
||||
}
|
||||
case Type::DROP_DNS_CACHE: [[fallthrough]];
|
||||
@ -437,107 +437,107 @@ AccessRightsElements InterpreterSystemQuery::getRequiredAccessForDDLOnCluster()
|
||||
#endif
|
||||
case Type::DROP_UNCOMPRESSED_CACHE:
|
||||
{
|
||||
required_access.emplace_back(AccessType::DROP_CACHE);
|
||||
required_access.emplace_back(AccessType::SYSTEM_DROP_CACHE);
|
||||
break;
|
||||
}
|
||||
case Type::RELOAD_DICTIONARY: [[fallthrough]];
|
||||
case Type::RELOAD_DICTIONARIES: [[fallthrough]];
|
||||
case Type::RELOAD_EMBEDDED_DICTIONARIES:
|
||||
{
|
||||
required_access.emplace_back(AccessType::RELOAD_DICTIONARY);
|
||||
required_access.emplace_back(AccessType::SYSTEM_RELOAD_DICTIONARY);
|
||||
break;
|
||||
}
|
||||
case Type::RELOAD_CONFIG:
|
||||
{
|
||||
required_access.emplace_back(AccessType::RELOAD_CONFIG);
|
||||
required_access.emplace_back(AccessType::SYSTEM_RELOAD_CONFIG);
|
||||
break;
|
||||
}
|
||||
case Type::STOP_MERGES: [[fallthrough]];
|
||||
case Type::START_MERGES:
|
||||
{
|
||||
if (query.table.empty())
|
||||
required_access.emplace_back(AccessType::STOP_MERGES);
|
||||
required_access.emplace_back(AccessType::SYSTEM_MERGES);
|
||||
else
|
||||
required_access.emplace_back(AccessType::STOP_MERGES, query.database, query.table);
|
||||
required_access.emplace_back(AccessType::SYSTEM_MERGES, query.database, query.table);
|
||||
break;
|
||||
}
|
||||
case Type::STOP_TTL_MERGES: [[fallthrough]];
|
||||
case Type::START_TTL_MERGES:
|
||||
{
|
||||
if (query.table.empty())
|
||||
required_access.emplace_back(AccessType::STOP_TTL_MERGES);
|
||||
required_access.emplace_back(AccessType::SYSTEM_TTL_MERGES);
|
||||
else
|
||||
required_access.emplace_back(AccessType::STOP_TTL_MERGES, query.database, query.table);
|
||||
required_access.emplace_back(AccessType::SYSTEM_TTL_MERGES, query.database, query.table);
|
||||
break;
|
||||
}
|
||||
case Type::STOP_MOVES: [[fallthrough]];
|
||||
case Type::START_MOVES:
|
||||
{
|
||||
if (query.table.empty())
|
||||
required_access.emplace_back(AccessType::STOP_MOVES);
|
||||
required_access.emplace_back(AccessType::SYSTEM_MOVES);
|
||||
else
|
||||
required_access.emplace_back(AccessType::STOP_MOVES, query.database, query.table);
|
||||
required_access.emplace_back(AccessType::SYSTEM_MOVES, query.database, query.table);
|
||||
break;
|
||||
}
|
||||
case Type::STOP_FETCHES: [[fallthrough]];
|
||||
case Type::START_FETCHES:
|
||||
{
|
||||
if (query.table.empty())
|
||||
required_access.emplace_back(AccessType::STOP_FETCHES);
|
||||
required_access.emplace_back(AccessType::SYSTEM_FETCHES);
|
||||
else
|
||||
required_access.emplace_back(AccessType::STOP_FETCHES, query.database, query.table);
|
||||
required_access.emplace_back(AccessType::SYSTEM_FETCHES, query.database, query.table);
|
||||
break;
|
||||
}
|
||||
case Type::STOP_DISTRIBUTED_SENDS: [[fallthrough]];
|
||||
case Type::START_DISTRIBUTED_SENDS:
|
||||
{
|
||||
if (query.table.empty())
|
||||
required_access.emplace_back(AccessType::STOP_DISTRIBUTED_SENDS);
|
||||
required_access.emplace_back(AccessType::SYSTEM_DISTRIBUTED_SENDS);
|
||||
else
|
||||
required_access.emplace_back(AccessType::STOP_DISTRIBUTED_SENDS, query.database, query.table);
|
||||
required_access.emplace_back(AccessType::SYSTEM_DISTRIBUTED_SENDS, query.database, query.table);
|
||||
break;
|
||||
}
|
||||
case Type::STOP_REPLICATED_SENDS: [[fallthrough]];
|
||||
case Type::START_REPLICATED_SENDS:
|
||||
{
|
||||
if (query.table.empty())
|
||||
required_access.emplace_back(AccessType::STOP_REPLICATED_SENDS);
|
||||
required_access.emplace_back(AccessType::SYSTEM_REPLICATED_SENDS);
|
||||
else
|
||||
required_access.emplace_back(AccessType::STOP_REPLICATED_SENDS, query.database, query.table);
|
||||
required_access.emplace_back(AccessType::SYSTEM_REPLICATED_SENDS, query.database, query.table);
|
||||
break;
|
||||
}
|
||||
case Type::STOP_REPLICATION_QUEUES: [[fallthrough]];
|
||||
case Type::START_REPLICATION_QUEUES:
|
||||
{
|
||||
if (query.table.empty())
|
||||
required_access.emplace_back(AccessType::STOP_REPLICATION_QUEUES);
|
||||
required_access.emplace_back(AccessType::SYSTEM_REPLICATION_QUEUES);
|
||||
else
|
||||
required_access.emplace_back(AccessType::STOP_REPLICATION_QUEUES, query.database, query.table);
|
||||
required_access.emplace_back(AccessType::SYSTEM_REPLICATION_QUEUES, query.database, query.table);
|
||||
break;
|
||||
}
|
||||
case Type::SYNC_REPLICA:
|
||||
{
|
||||
required_access.emplace_back(AccessType::SYNC_REPLICA, query.database, query.table);
|
||||
required_access.emplace_back(AccessType::SYSTEM_SYNC_REPLICA, query.database, query.table);
|
||||
break;
|
||||
}
|
||||
case Type::RESTART_REPLICA:
|
||||
{
|
||||
required_access.emplace_back(AccessType::RESTART_REPLICA, query.database, query.table);
|
||||
required_access.emplace_back(AccessType::SYSTEM_RESTART_REPLICA, query.database, query.table);
|
||||
break;
|
||||
}
|
||||
case Type::RESTART_REPLICAS:
|
||||
{
|
||||
required_access.emplace_back(AccessType::RESTART_REPLICA);
|
||||
required_access.emplace_back(AccessType::SYSTEM_RESTART_REPLICA);
|
||||
break;
|
||||
}
|
||||
case Type::FLUSH_DISTRIBUTED:
|
||||
{
|
||||
required_access.emplace_back(AccessType::FLUSH_DISTRIBUTED, query.database, query.table);
|
||||
required_access.emplace_back(AccessType::SYSTEM_FLUSH_DISTRIBUTED, query.database, query.table);
|
||||
break;
|
||||
}
|
||||
case Type::FLUSH_LOGS:
|
||||
{
|
||||
required_access.emplace_back(AccessType::FLUSH_LOGS);
|
||||
required_access.emplace_back(AccessType::SYSTEM_FLUSH_LOGS);
|
||||
break;
|
||||
}
|
||||
case Type::STOP_LISTEN_QUERIES: break;
|
||||
|
@ -135,6 +135,8 @@ void ASTCreateQuotaQuery::formatImpl(const FormatSettings & settings, FormatStat
|
||||
|
||||
settings.ostr << " " << backQuoteIfNeed(name);
|
||||
|
||||
formatOnCluster(settings);
|
||||
|
||||
if (!new_name.empty())
|
||||
formatRenameTo(new_name, settings);
|
||||
|
||||
@ -146,4 +148,12 @@ void ASTCreateQuotaQuery::formatImpl(const FormatSettings & settings, FormatStat
|
||||
if (roles && (!roles->empty() || alter))
|
||||
formatToRoles(*roles, settings);
|
||||
}
|
||||
|
||||
|
||||
void ASTCreateQuotaQuery::replaceCurrentUserTagWithName(const String & current_user_name)
|
||||
{
|
||||
if (roles)
|
||||
roles->replaceCurrentUserTagWithName(current_user_name);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/IAST.h>
|
||||
#include <Parsers/ASTQueryWithOnCluster.h>
|
||||
#include <Access/Quota.h>
|
||||
|
||||
|
||||
@ -25,7 +26,7 @@ class ASTExtendedRoleSet;
|
||||
* UNSET TRACKING} [,...]]
|
||||
* [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
|
||||
*/
|
||||
class ASTCreateQuotaQuery : public IAST
|
||||
class ASTCreateQuotaQuery : public IAST, public ASTQueryWithOnCluster
|
||||
{
|
||||
public:
|
||||
bool alter = false;
|
||||
@ -58,5 +59,7 @@ public:
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
|
||||
void replaceCurrentUserTagWithName(const String & current_user_name);
|
||||
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTCreateQuotaQuery>(clone()); }
|
||||
};
|
||||
}
|
||||
|
@ -54,6 +54,8 @@ void ASTCreateRoleQuery::formatImpl(const FormatSettings & format, FormatState &
|
||||
|
||||
format.ostr << " " << backQuoteIfNeed(name);
|
||||
|
||||
formatOnCluster(format);
|
||||
|
||||
if (!new_name.empty())
|
||||
formatRenameTo(new_name, format);
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/IAST.h>
|
||||
#include <Parsers/ASTQueryWithOnCluster.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -15,7 +16,7 @@ class ASTSettingsProfileElements;
|
||||
* [RENAME TO new_name]
|
||||
* [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]
|
||||
*/
|
||||
class ASTCreateRoleQuery : public IAST
|
||||
class ASTCreateRoleQuery : public IAST, public ASTQueryWithOnCluster
|
||||
{
|
||||
public:
|
||||
bool alter = false;
|
||||
@ -33,5 +34,6 @@ public:
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
void formatImpl(const FormatSettings & format, FormatState &, FormatStateStacked) const override;
|
||||
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTCreateRoleQuery>(clone()); }
|
||||
};
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ namespace
|
||||
|
||||
String ASTCreateRowPolicyQuery::getID(char) const
|
||||
{
|
||||
return "CREATE POLICY or ALTER POLICY query";
|
||||
return "CREATE ROW POLICY or ALTER ROW POLICY query";
|
||||
}
|
||||
|
||||
|
||||
@ -136,11 +136,11 @@ void ASTCreateRowPolicyQuery::formatImpl(const FormatSettings & settings, Format
|
||||
{
|
||||
if (attach)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << "ATTACH POLICY";
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << "ATTACH ROW POLICY";
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << (alter ? "ALTER POLICY" : "CREATE POLICY")
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << (alter ? "ALTER ROW POLICY" : "CREATE ROW POLICY")
|
||||
<< (settings.hilite ? hilite_none : "");
|
||||
}
|
||||
|
||||
@ -157,6 +157,8 @@ void ASTCreateRowPolicyQuery::formatImpl(const FormatSettings & settings, Format
|
||||
settings.ostr << " " << backQuoteIfNeed(policy_name) << (settings.hilite ? hilite_keyword : "") << " ON "
|
||||
<< (settings.hilite ? hilite_none : "") << (database.empty() ? String{} : backQuoteIfNeed(database) + ".") << table_name;
|
||||
|
||||
formatOnCluster(settings);
|
||||
|
||||
if (!new_policy_name.empty())
|
||||
formatRenameTo(new_policy_name, settings);
|
||||
|
||||
@ -168,4 +170,11 @@ void ASTCreateRowPolicyQuery::formatImpl(const FormatSettings & settings, Format
|
||||
if (roles && (!roles->empty() || alter))
|
||||
formatToRoles(*roles, settings);
|
||||
}
|
||||
|
||||
|
||||
void ASTCreateRowPolicyQuery::replaceCurrentUserTagWithName(const String & current_user_name)
|
||||
{
|
||||
if (roles)
|
||||
roles->replaceCurrentUserTagWithName(current_user_name);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/IAST.h>
|
||||
#include <Parsers/ASTQueryWithOnCluster.h>
|
||||
#include <Access/RowPolicy.h>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@ -25,7 +26,7 @@ class ASTExtendedRoleSet;
|
||||
* [WITH CHECK {condition | NONE}] [,...]
|
||||
* [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
|
||||
*/
|
||||
class ASTCreateRowPolicyQuery : public IAST
|
||||
class ASTCreateRowPolicyQuery : public IAST, public ASTQueryWithOnCluster
|
||||
{
|
||||
public:
|
||||
bool alter = false;
|
||||
@ -47,5 +48,7 @@ public:
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
|
||||
void replaceCurrentUserTagWithName(const String & current_user_name);
|
||||
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTCreateRowPolicyQuery>(clone()); }
|
||||
};
|
||||
}
|
||||
|
@ -61,6 +61,8 @@ void ASTCreateSettingsProfileQuery::formatImpl(const FormatSettings & format, Fo
|
||||
|
||||
format.ostr << " " << backQuoteIfNeed(name);
|
||||
|
||||
formatOnCluster(format);
|
||||
|
||||
if (!new_name.empty())
|
||||
formatRenameTo(new_name, format);
|
||||
|
||||
@ -71,4 +73,10 @@ void ASTCreateSettingsProfileQuery::formatImpl(const FormatSettings & format, Fo
|
||||
formatToRoles(*to_roles, format);
|
||||
}
|
||||
|
||||
|
||||
void ASTCreateSettingsProfileQuery::replaceCurrentUserTagWithName(const String & current_user_name)
|
||||
{
|
||||
if (to_roles)
|
||||
to_roles->replaceCurrentUserTagWithName(current_user_name);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/IAST.h>
|
||||
#include <Parsers/ASTQueryWithOnCluster.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -16,7 +17,7 @@ class ASTExtendedRoleSet;
|
||||
* [RENAME TO new_name]
|
||||
* [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]
|
||||
*/
|
||||
class ASTCreateSettingsProfileQuery : public IAST
|
||||
class ASTCreateSettingsProfileQuery : public IAST, public ASTQueryWithOnCluster
|
||||
{
|
||||
public:
|
||||
bool alter = false;
|
||||
@ -36,5 +37,7 @@ public:
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
void formatImpl(const FormatSettings & format, FormatState &, FormatStateStacked) const override;
|
||||
void replaceCurrentUserTagWithName(const String & current_user_name);
|
||||
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTCreateSettingsProfileQuery>(clone()); }
|
||||
};
|
||||
}
|
||||
|
@ -184,6 +184,8 @@ void ASTCreateUserQuery::formatImpl(const FormatSettings & format, FormatState &
|
||||
|
||||
format.ostr << " " << backQuoteIfNeed(name);
|
||||
|
||||
formatOnCluster(format);
|
||||
|
||||
if (!new_name.empty())
|
||||
formatRenameTo(new_name, format);
|
||||
|
||||
@ -195,7 +197,7 @@ void ASTCreateUserQuery::formatImpl(const FormatSettings & format, FormatState &
|
||||
if (add_hosts)
|
||||
formatHosts("ADD", *add_hosts, format);
|
||||
if (remove_hosts)
|
||||
formatHosts("REMOVE", *remove_hosts, format);
|
||||
formatHosts("DROP", *remove_hosts, format);
|
||||
|
||||
if (default_roles)
|
||||
formatDefaultRoles(*default_roles, format);
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Parsers/IAST.h>
|
||||
#include <Parsers/ASTQueryWithOnCluster.h>
|
||||
#include <Access/Authentication.h>
|
||||
#include <Access/AllowedClientHosts.h>
|
||||
|
||||
@ -19,11 +20,11 @@ class ASTSettingsProfileElements;
|
||||
* ALTER USER [IF EXISTS] name
|
||||
* [RENAME TO new_name]
|
||||
* [IDENTIFIED [WITH {PLAINTEXT_PASSWORD|SHA256_PASSWORD|DOUBLE_SHA1_PASSWORD}] BY {'password'|'hash'}]
|
||||
* [[ADD|REMOVE] HOST {LOCAL | NAME 'name' | NAME REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE]
|
||||
* [[ADD|DROP] HOST {LOCAL | NAME 'name' | NAME REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE]
|
||||
* [DEFAULT ROLE role [,...] | ALL | ALL EXCEPT role [,...] ]
|
||||
* [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]
|
||||
*/
|
||||
class ASTCreateUserQuery : public IAST
|
||||
class ASTCreateUserQuery : public IAST, public ASTQueryWithOnCluster
|
||||
{
|
||||
public:
|
||||
bool alter = false;
|
||||
@ -49,5 +50,6 @@ public:
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
void formatImpl(const FormatSettings & format, FormatState &, FormatStateStacked) const override;
|
||||
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTCreateUserQuery>(clone()); }
|
||||
};
|
||||
}
|
||||
|
@ -75,5 +75,7 @@ void ASTDropAccessEntityQuery::formatImpl(const FormatSettings & settings, Forma
|
||||
settings.ostr << ' ' << backQuoteIfNeed(name);
|
||||
}
|
||||
}
|
||||
|
||||
formatOnCluster(settings);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <Parsers/IAST.h>
|
||||
#include <Access/RowPolicy.h>
|
||||
#include <Parsers/ASTQueryWithOnCluster.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -13,7 +14,7 @@ namespace DB
|
||||
* DROP [ROW] POLICY [IF EXISTS] name [,...] ON [database.]table [,...]
|
||||
* DROP [SETTINGS] PROFILE [IF EXISTS] name [,...]
|
||||
*/
|
||||
class ASTDropAccessEntityQuery : public IAST
|
||||
class ASTDropAccessEntityQuery : public IAST, public ASTQueryWithOnCluster
|
||||
{
|
||||
public:
|
||||
enum class Kind
|
||||
@ -34,5 +35,6 @@ public:
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
|
||||
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTDropAccessEntityQuery>(clone()); }
|
||||
};
|
||||
}
|
||||
|
@ -72,4 +72,21 @@ void ASTExtendedRoleSet::formatImpl(const FormatSettings & settings, FormatState
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ASTExtendedRoleSet::replaceCurrentUserTagWithName(const String & current_user_name)
|
||||
{
|
||||
if (current_user)
|
||||
{
|
||||
names.push_back(current_user_name);
|
||||
current_user = false;
|
||||
}
|
||||
|
||||
if (except_current_user)
|
||||
{
|
||||
except_names.push_back(current_user_name);
|
||||
except_current_user = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ public:
|
||||
bool id_mode = false; /// If true then `names` and `except_names` keeps UUIDs, not names.
|
||||
|
||||
bool empty() const { return names.empty() && !current_user && !all; }
|
||||
void replaceCurrentUserTagWithName(const String & current_user_name);
|
||||
|
||||
String getID(char) const override { return "ExtendedRoleSet"; }
|
||||
ASTPtr clone() const override { return std::make_shared<ASTExtendedRoleSet>(*this); }
|
||||
|
@ -122,19 +122,22 @@ ASTPtr ASTGrantQuery::clone() const
|
||||
void ASTGrantQuery::formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const
|
||||
{
|
||||
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << (attach ? "ATTACH " : "") << ((kind == Kind::GRANT) ? "GRANT" : "REVOKE")
|
||||
<< (settings.hilite ? IAST::hilite_none : "") << " ";
|
||||
<< (settings.hilite ? IAST::hilite_none : "");
|
||||
|
||||
formatOnCluster(settings);
|
||||
|
||||
if (kind == Kind::REVOKE)
|
||||
{
|
||||
if (grant_option)
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << "GRANT OPTION FOR " << (settings.hilite ? hilite_none : "");
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " GRANT OPTION FOR" << (settings.hilite ? hilite_none : "");
|
||||
else if (admin_option)
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << "ADMIN OPTION FOR " << (settings.hilite ? hilite_none : "");
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " ADMIN OPTION FOR" << (settings.hilite ? hilite_none : "");
|
||||
}
|
||||
|
||||
if ((!!roles + !access_rights_elements.empty()) != 1)
|
||||
throw Exception("Either roles or access rights elements should be set", ErrorCodes::LOGICAL_ERROR);
|
||||
|
||||
settings.ostr << " ";
|
||||
if (roles)
|
||||
roles->format(settings);
|
||||
else
|
||||
@ -150,4 +153,11 @@ void ASTGrantQuery::formatImpl(const FormatSettings & settings, FormatState &, F
|
||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " WITH ADMIN OPTION" << (settings.hilite ? hilite_none : "");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ASTGrantQuery::replaceCurrentUserTagWithName(const String & current_user_name)
|
||||
{
|
||||
if (to_roles)
|
||||
to_roles->replaceCurrentUserTagWithName(current_user_name);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <Parsers/IAST.h>
|
||||
#include <Access/AccessRightsElement.h>
|
||||
#include <Parsers/ASTQueryWithOnCluster.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -15,7 +16,7 @@ class ASTExtendedRoleSet;
|
||||
* GRANT role [,...] TO {user_name | role_name | CURRENT_USER} [,...] [WITH ADMIN OPTION]
|
||||
* REVOKE [ADMIN OPTION FOR] role [,...] FROM {user_name | role_name | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user_name | role_name | CURRENT_USER} [,...]
|
||||
*/
|
||||
class ASTGrantQuery : public IAST
|
||||
class ASTGrantQuery : public IAST, public ASTQueryWithOnCluster
|
||||
{
|
||||
public:
|
||||
enum class Kind
|
||||
@ -34,5 +35,7 @@ public:
|
||||
String getID(char) const override;
|
||||
ASTPtr clone() const override;
|
||||
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
|
||||
void replaceCurrentUserTagWithName(const String & current_user_name);
|
||||
ASTPtr getRewrittenASTWithoutOnCluster(const std::string &) const override { return removeOnCluster<ASTGrantQuery>(clone()); }
|
||||
};
|
||||
}
|
||||
|
@ -238,6 +238,13 @@ bool ParserCreateQuotaQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expe
|
||||
if (!parseIdentifierOrStringLiteral(pos, expected, name))
|
||||
return false;
|
||||
|
||||
String cluster;
|
||||
if (ParserKeyword{"ON"}.ignore(pos, expected))
|
||||
{
|
||||
if (!ASTQueryWithOnCluster::parse(pos, cluster, expected))
|
||||
return false;
|
||||
}
|
||||
|
||||
String new_name;
|
||||
std::optional<KeyType> key_type;
|
||||
std::vector<ASTCreateQuotaQuery::Limits> all_limits;
|
||||
@ -266,6 +273,7 @@ bool ParserCreateQuotaQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expe
|
||||
query->if_exists = if_exists;
|
||||
query->if_not_exists = if_not_exists;
|
||||
query->or_replace = or_replace;
|
||||
query->cluster = std::move(cluster);
|
||||
query->name = std::move(name);
|
||||
query->new_name = std::move(new_name);
|
||||
query->key_type = key_type;
|
||||
|
@ -80,6 +80,13 @@ bool ParserCreateRoleQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
if (!parseRoleName(pos, expected, name))
|
||||
return false;
|
||||
|
||||
String cluster;
|
||||
if (ParserKeyword{"ON"}.ignore(pos, expected))
|
||||
{
|
||||
if (!ASTQueryWithOnCluster::parse(pos, cluster, expected))
|
||||
return false;
|
||||
}
|
||||
|
||||
String new_name;
|
||||
std::shared_ptr<ASTSettingsProfileElements> settings;
|
||||
while (true)
|
||||
@ -101,6 +108,7 @@ bool ParserCreateRoleQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
query->if_exists = if_exists;
|
||||
query->if_not_exists = if_not_exists;
|
||||
query->or_replace = or_replace;
|
||||
query->cluster = std::move(cluster);
|
||||
query->name = std::move(name);
|
||||
query->new_name = std::move(new_name);
|
||||
query->settings = std::move(settings);
|
||||
|
@ -243,6 +243,13 @@ bool ParserCreateRowPolicyQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
|
||||
|| !parseDatabaseAndTableName(pos, expected, database, table_name))
|
||||
return false;
|
||||
|
||||
String cluster;
|
||||
if (ParserKeyword{"ON"}.ignore(pos, expected))
|
||||
{
|
||||
if (!ASTQueryWithOnCluster::parse(pos, cluster, expected))
|
||||
return false;
|
||||
}
|
||||
|
||||
String new_policy_name;
|
||||
std::optional<bool> is_restrictive;
|
||||
std::vector<std::pair<ConditionType, ASTPtr>> conditions;
|
||||
@ -272,6 +279,7 @@ bool ParserCreateRowPolicyQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
|
||||
query->if_exists = if_exists;
|
||||
query->if_not_exists = if_not_exists;
|
||||
query->or_replace = or_replace;
|
||||
query->cluster = std::move(cluster);
|
||||
query->name_parts = std::move(name_parts);
|
||||
query->new_policy_name = std::move(new_policy_name);
|
||||
query->is_restrictive = is_restrictive;
|
||||
|
@ -96,6 +96,13 @@ bool ParserCreateSettingsProfileQuery::parseImpl(Pos & pos, ASTPtr & node, Expec
|
||||
if (!parseIdentifierOrStringLiteral(pos, expected, name))
|
||||
return false;
|
||||
|
||||
String cluster;
|
||||
if (ParserKeyword{"ON"}.ignore(pos, expected))
|
||||
{
|
||||
if (!ASTQueryWithOnCluster::parse(pos, cluster, expected))
|
||||
return false;
|
||||
}
|
||||
|
||||
String new_name;
|
||||
std::shared_ptr<ASTSettingsProfileElements> settings;
|
||||
while (true)
|
||||
@ -120,6 +127,7 @@ bool ParserCreateSettingsProfileQuery::parseImpl(Pos & pos, ASTPtr & node, Expec
|
||||
query->if_exists = if_exists;
|
||||
query->if_not_exists = if_not_exists;
|
||||
query->or_replace = or_replace;
|
||||
query->cluster = std::move(cluster);
|
||||
query->name = std::move(name);
|
||||
query->new_name = std::move(new_name);
|
||||
query->settings = std::move(settings);
|
||||
|
@ -23,7 +23,7 @@ namespace ErrorCodes
|
||||
|
||||
namespace
|
||||
{
|
||||
bool parseRenameTo(IParserBase::Pos & pos, Expected & expected, String & new_name, String & new_host_pattern)
|
||||
bool parseRenameTo(IParserBase::Pos & pos, Expected & expected, String & new_name, std::optional<String> & new_host_pattern)
|
||||
{
|
||||
return IParserBase::wrapParseImpl(pos, [&]
|
||||
{
|
||||
@ -286,12 +286,19 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
}
|
||||
|
||||
String name;
|
||||
String host_pattern;
|
||||
std::optional<String> host_pattern;
|
||||
if (!parseUserName(pos, expected, name, host_pattern))
|
||||
return false;
|
||||
|
||||
String cluster;
|
||||
if (ParserKeyword{"ON"}.ignore(pos, expected))
|
||||
{
|
||||
if (!ASTQueryWithOnCluster::parse(pos, cluster, expected))
|
||||
return false;
|
||||
}
|
||||
|
||||
String new_name;
|
||||
String new_host_pattern;
|
||||
std::optional<String> new_host_pattern;
|
||||
std::optional<Authentication> authentication;
|
||||
std::optional<AllowedClientHosts> hosts;
|
||||
std::optional<AllowedClientHosts> add_hosts;
|
||||
@ -318,7 +325,7 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
if (new_name.empty() && parseRenameTo(pos, expected, new_name, new_host_pattern))
|
||||
continue;
|
||||
|
||||
if (parseHosts(pos, expected, "ADD", add_hosts) || parseHosts(pos, expected, "REMOVE", remove_hosts))
|
||||
if (parseHosts(pos, expected, "ADD", add_hosts) || parseHosts(pos, expected, "DROP", remove_hosts))
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -327,10 +334,10 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
|
||||
if (!hosts)
|
||||
{
|
||||
if (!alter)
|
||||
hosts.emplace().addLikePattern(host_pattern);
|
||||
else if (alter && !new_name.empty())
|
||||
hosts.emplace().addLikePattern(new_host_pattern);
|
||||
if (!alter && host_pattern)
|
||||
hosts.emplace().addLikePattern(*host_pattern);
|
||||
else if (alter && new_host_pattern)
|
||||
hosts.emplace().addLikePattern(*new_host_pattern);
|
||||
}
|
||||
|
||||
auto query = std::make_shared<ASTCreateUserQuery>();
|
||||
@ -341,6 +348,7 @@ bool ParserCreateUserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
||||
query->if_exists = if_exists;
|
||||
query->if_not_exists = if_not_exists;
|
||||
query->or_replace = or_replace;
|
||||
query->cluster = std::move(cluster);
|
||||
query->name = std::move(name);
|
||||
query->new_name = std::move(new_name);
|
||||
query->authentication = std::move(authentication);
|
||||
|
@ -14,7 +14,7 @@ namespace DB
|
||||
* ALTER USER [IF EXISTS] name
|
||||
* [RENAME TO new_name]
|
||||
* [IDENTIFIED [WITH {PLAINTEXT_PASSWORD|SHA256_PASSWORD|DOUBLE_SHA1_PASSWORD}] BY {'password'|'hash'}]
|
||||
* [[ADD|REMOVE] HOST {LOCAL | NAME 'name' | NAME REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE]
|
||||
* [[ADD|DROP] HOST {LOCAL | NAME 'name' | NAME REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE]
|
||||
* [SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]
|
||||
*/
|
||||
class ParserCreateUserQuery : public IParserBase
|
||||
|
@ -117,10 +117,18 @@ bool ParserDropAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
|
||||
return false;
|
||||
}
|
||||
|
||||
String cluster;
|
||||
if (ParserKeyword{"ON"}.ignore(pos, expected))
|
||||
{
|
||||
if (!ASTQueryWithOnCluster::parse(pos, cluster, expected))
|
||||
return false;
|
||||
}
|
||||
|
||||
auto query = std::make_shared<ASTDropAccessEntityQuery>(kind);
|
||||
node = query;
|
||||
|
||||
query->if_exists = if_exists;
|
||||
query->cluster = std::move(cluster);
|
||||
query->names = std::move(names);
|
||||
query->row_policies_names = std::move(row_policies_names);
|
||||
|
||||
|
@ -17,15 +17,6 @@ namespace ErrorCodes
|
||||
|
||||
namespace
|
||||
{
|
||||
bool parseRoundBrackets(IParser::Pos & pos, Expected & expected)
|
||||
{
|
||||
return IParserBase::wrapParseImpl(pos, [&]
|
||||
{
|
||||
return ParserToken{TokenType::OpeningRoundBracket}.ignore(pos, expected)
|
||||
&& ParserToken{TokenType::ClosingRoundBracket}.ignore(pos, expected);
|
||||
});
|
||||
}
|
||||
|
||||
bool parseAccessFlags(IParser::Pos & pos, Expected & expected, AccessFlags & access_flags)
|
||||
{
|
||||
static constexpr auto is_one_of_access_type_words = [](IParser::Pos & pos_)
|
||||
@ -63,7 +54,6 @@ namespace
|
||||
return false;
|
||||
}
|
||||
|
||||
parseRoundBrackets(pos, expected);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -269,6 +259,13 @@ bool ParserGrantQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
else
|
||||
return false;
|
||||
|
||||
String cluster;
|
||||
if (ParserKeyword{"ON"}.ignore(pos, expected))
|
||||
{
|
||||
if (!ASTQueryWithOnCluster::parse(pos, cluster, expected))
|
||||
return false;
|
||||
}
|
||||
|
||||
bool grant_option = false;
|
||||
bool admin_option = false;
|
||||
if (kind == Kind::REVOKE)
|
||||
@ -306,6 +303,7 @@ bool ParserGrantQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||
|
||||
query->kind = kind;
|
||||
query->attach = attach;
|
||||
query->cluster = std::move(cluster);
|
||||
query->access_rights_elements = std::move(elements);
|
||||
query->roles = std::move(roles);
|
||||
query->to_roles = std::move(to_roles);
|
||||
|
@ -3,48 +3,39 @@
|
||||
#include <Parsers/CommonParsers.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
namespace
|
||||
bool parseUserName(IParser::Pos & pos, Expected & expected, String & user_name, std::optional<String> & host_like_pattern)
|
||||
{
|
||||
bool parseUserNameImpl(IParser::Pos & pos, Expected & expected, String & user_name, String * host_like_pattern)
|
||||
String name;
|
||||
if (!parseIdentifierOrStringLiteral(pos, expected, name))
|
||||
return false;
|
||||
|
||||
boost::algorithm::trim(name);
|
||||
|
||||
std::optional<String> pattern;
|
||||
if (ParserToken{TokenType::At}.ignore(pos, expected))
|
||||
{
|
||||
String name;
|
||||
if (!parseIdentifierOrStringLiteral(pos, expected, name))
|
||||
if (!parseIdentifierOrStringLiteral(pos, expected, pattern.emplace()))
|
||||
return false;
|
||||
|
||||
boost::algorithm::trim(name);
|
||||
|
||||
String pattern = "@";
|
||||
|
||||
if (ParserToken{TokenType::At}.ignore(pos, expected))
|
||||
{
|
||||
if (!parseIdentifierOrStringLiteral(pos, expected, pattern))
|
||||
return false;
|
||||
|
||||
boost::algorithm::trim(pattern);
|
||||
}
|
||||
|
||||
if (pattern != "@")
|
||||
name += '@' + pattern;
|
||||
|
||||
user_name = std::move(name);
|
||||
if (host_like_pattern)
|
||||
*host_like_pattern = std::move(pattern);
|
||||
return true;
|
||||
boost::algorithm::trim(*pattern);
|
||||
}
|
||||
|
||||
if (pattern && (pattern != "%"))
|
||||
name += '@' + *pattern;
|
||||
|
||||
user_name = std::move(name);
|
||||
host_like_pattern = std::move(pattern);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool parseUserName(IParser::Pos & pos, Expected & expected, String & user_name)
|
||||
{
|
||||
return parseUserNameImpl(pos, expected, user_name, nullptr);
|
||||
}
|
||||
|
||||
|
||||
bool parseUserName(IParser::Pos & pos, Expected & expected, String & user_name, String & host_like_pattern)
|
||||
{
|
||||
return parseUserNameImpl(pos, expected, user_name, &host_like_pattern);
|
||||
std::optional<String> unused_pattern;
|
||||
return parseUserName(pos, expected, user_name, unused_pattern);
|
||||
}
|
||||
|
||||
|
||||
|
@ -10,7 +10,7 @@ namespace DB
|
||||
/// The `host` can be an ip address, ip subnet, or a host name.
|
||||
/// The % and _ wildcard characters are permitted in `host`.
|
||||
/// These have the same meaning as for pattern-matching operations performed with the LIKE operator.
|
||||
bool parseUserName(IParser::Pos & pos, Expected & expected, String & user_name, String & host_like_pattern);
|
||||
bool parseUserName(IParser::Pos & pos, Expected & expected, String & user_name, std::optional<String> & host_like_pattern);
|
||||
bool parseUserName(IParser::Pos & pos, Expected & expected, String & user_name);
|
||||
|
||||
/// Parses either a user name or the 'CURRENT_USER' keyword (or some of the aliases).
|
||||
|
@ -810,6 +810,9 @@ void registerStorageDistributed(StorageFactory & factory)
|
||||
storage_policy,
|
||||
args.relative_data_path,
|
||||
args.attach);
|
||||
},
|
||||
{
|
||||
.source_access_type = AccessType::REMOTE,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -189,4 +189,13 @@ StorageFactory & StorageFactory::instance()
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
AccessType StorageFactory::getSourceAccessType(const String & table_engine) const
|
||||
{
|
||||
auto it = storages.find(table_engine);
|
||||
if (it == storages.end())
|
||||
return AccessType::NONE;
|
||||
return it->second.features.source_access_type;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <Storages/ConstraintsDescription.h>
|
||||
#include <Storages/IStorage_fwd.h>
|
||||
#include <Storages/registerStorages.h>
|
||||
#include <Access/AccessType.h>
|
||||
#include <unordered_map>
|
||||
|
||||
|
||||
@ -54,6 +55,7 @@ public:
|
||||
bool supports_ttl = false;
|
||||
bool supports_replication = false;
|
||||
bool supports_deduplication = false;
|
||||
AccessType source_access_type = AccessType::NONE;
|
||||
};
|
||||
|
||||
using CreatorFn = std::function<StoragePtr(const Arguments & arguments)>;
|
||||
@ -83,6 +85,7 @@ public:
|
||||
.supports_ttl = false,
|
||||
.supports_replication = false,
|
||||
.supports_deduplication = false,
|
||||
.source_access_type = AccessType::NONE,
|
||||
});
|
||||
|
||||
const Storages & getAllStorages() const
|
||||
@ -108,6 +111,7 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
AccessType getSourceAccessType(const String & table_engine) const;
|
||||
|
||||
private:
|
||||
Storages storages;
|
||||
|
@ -541,67 +541,71 @@ void StorageFile::truncate(const ASTPtr & /*query*/, const Context & /* context
|
||||
|
||||
void registerStorageFile(StorageFactory & factory)
|
||||
{
|
||||
factory.registerStorage("File", [](const StorageFactory::Arguments & args)
|
||||
{
|
||||
ASTs & engine_args = args.engine_args;
|
||||
|
||||
if (!(engine_args.size() >= 1 && engine_args.size() <= 3)) // NOLINT
|
||||
throw Exception(
|
||||
"Storage File requires from 1 to 3 arguments: name of used format, source and compression_method.",
|
||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||
|
||||
engine_args[0] = evaluateConstantExpressionOrIdentifierAsLiteral(engine_args[0], args.local_context);
|
||||
String format_name = engine_args[0]->as<ASTLiteral &>().value.safeGet<String>();
|
||||
|
||||
String compression_method;
|
||||
StorageFile::CommonArguments common_args{args.table_id, format_name, compression_method,
|
||||
args.columns, args.constraints, args.context};
|
||||
|
||||
if (engine_args.size() == 1) /// Table in database
|
||||
return StorageFile::create(args.relative_data_path, common_args);
|
||||
|
||||
/// Will use FD if engine_args[1] is int literal or identifier with std* name
|
||||
int source_fd = -1;
|
||||
String source_path;
|
||||
|
||||
if (auto opt_name = tryGetIdentifierName(engine_args[1]))
|
||||
factory.registerStorage(
|
||||
"File",
|
||||
[](const StorageFactory::Arguments & args)
|
||||
{
|
||||
if (*opt_name == "stdin")
|
||||
source_fd = STDIN_FILENO;
|
||||
else if (*opt_name == "stdout")
|
||||
source_fd = STDOUT_FILENO;
|
||||
else if (*opt_name == "stderr")
|
||||
source_fd = STDERR_FILENO;
|
||||
ASTs & engine_args = args.engine_args;
|
||||
|
||||
if (!(engine_args.size() >= 1 && engine_args.size() <= 3)) // NOLINT
|
||||
throw Exception(
|
||||
"Storage File requires from 1 to 3 arguments: name of used format, source and compression_method.",
|
||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||
|
||||
engine_args[0] = evaluateConstantExpressionOrIdentifierAsLiteral(engine_args[0], args.local_context);
|
||||
String format_name = engine_args[0]->as<ASTLiteral &>().value.safeGet<String>();
|
||||
|
||||
String compression_method;
|
||||
StorageFile::CommonArguments common_args{
|
||||
args.table_id, format_name, compression_method, args.columns, args.constraints, args.context};
|
||||
|
||||
if (engine_args.size() == 1) /// Table in database
|
||||
return StorageFile::create(args.relative_data_path, common_args);
|
||||
|
||||
/// Will use FD if engine_args[1] is int literal or identifier with std* name
|
||||
int source_fd = -1;
|
||||
String source_path;
|
||||
|
||||
if (auto opt_name = tryGetIdentifierName(engine_args[1]))
|
||||
{
|
||||
if (*opt_name == "stdin")
|
||||
source_fd = STDIN_FILENO;
|
||||
else if (*opt_name == "stdout")
|
||||
source_fd = STDOUT_FILENO;
|
||||
else if (*opt_name == "stderr")
|
||||
source_fd = STDERR_FILENO;
|
||||
else
|
||||
throw Exception(
|
||||
"Unknown identifier '" + *opt_name + "' in second arg of File storage constructor", ErrorCodes::UNKNOWN_IDENTIFIER);
|
||||
}
|
||||
else if (const auto * literal = engine_args[1]->as<ASTLiteral>())
|
||||
{
|
||||
auto type = literal->value.getType();
|
||||
if (type == Field::Types::Int64)
|
||||
source_fd = static_cast<int>(literal->value.get<Int64>());
|
||||
else if (type == Field::Types::UInt64)
|
||||
source_fd = static_cast<int>(literal->value.get<UInt64>());
|
||||
else if (type == Field::Types::String)
|
||||
source_path = literal->value.get<String>();
|
||||
else
|
||||
throw Exception("Second argument must be path or file descriptor", ErrorCodes::BAD_ARGUMENTS);
|
||||
}
|
||||
|
||||
if (engine_args.size() == 3)
|
||||
{
|
||||
engine_args[2] = evaluateConstantExpressionOrIdentifierAsLiteral(engine_args[2], args.local_context);
|
||||
compression_method = engine_args[2]->as<ASTLiteral &>().value.safeGet<String>();
|
||||
}
|
||||
else
|
||||
throw Exception("Unknown identifier '" + *opt_name + "' in second arg of File storage constructor",
|
||||
ErrorCodes::UNKNOWN_IDENTIFIER);
|
||||
}
|
||||
else if (const auto * literal = engine_args[1]->as<ASTLiteral>())
|
||||
compression_method = "auto";
|
||||
|
||||
if (0 <= source_fd) /// File descriptor
|
||||
return StorageFile::create(source_fd, common_args);
|
||||
else /// User's file
|
||||
return StorageFile::create(source_path, args.context.getUserFilesPath(), common_args);
|
||||
},
|
||||
{
|
||||
auto type = literal->value.getType();
|
||||
if (type == Field::Types::Int64)
|
||||
source_fd = static_cast<int>(literal->value.get<Int64>());
|
||||
else if (type == Field::Types::UInt64)
|
||||
source_fd = static_cast<int>(literal->value.get<UInt64>());
|
||||
else if (type == Field::Types::String)
|
||||
source_path = literal->value.get<String>();
|
||||
else
|
||||
throw Exception("Second argument must be path or file descriptor", ErrorCodes::BAD_ARGUMENTS);
|
||||
}
|
||||
|
||||
if (engine_args.size() == 3)
|
||||
{
|
||||
engine_args[2] = evaluateConstantExpressionOrIdentifierAsLiteral(engine_args[2], args.local_context);
|
||||
compression_method = engine_args[2]->as<ASTLiteral &>().value.safeGet<String>();
|
||||
}
|
||||
else
|
||||
compression_method = "auto";
|
||||
|
||||
if (0 <= source_fd) /// File descriptor
|
||||
return StorageFile::create(source_fd, common_args);
|
||||
else /// User's file
|
||||
return StorageFile::create(source_path, args.context.getUserFilesPath(), common_args);
|
||||
});
|
||||
.source_access_type = AccessType::FILE,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -339,6 +339,9 @@ void registerStorageHDFS(StorageFactory & factory)
|
||||
} else compression_method = "auto";
|
||||
|
||||
return StorageHDFS::create(url, args.table_id, format_name, args.columns, args.constraints, args.context, compression_method);
|
||||
},
|
||||
{
|
||||
.source_access_type = AccessType::HDFS,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -248,6 +248,9 @@ void registerStorageMySQL(StorageFactory & factory)
|
||||
args.columns,
|
||||
args.constraints,
|
||||
args.context);
|
||||
},
|
||||
{
|
||||
.source_access_type = AccessType::MYSQL,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -348,6 +348,9 @@ void registerStorageS3(StorageFactory & factory)
|
||||
compression_method = "auto";
|
||||
|
||||
return StorageS3::create(s3_uri, access_key_id, secret_access_key, args.table_id, format_name, min_upload_part_size, args.columns, args.constraints, args.context);
|
||||
},
|
||||
{
|
||||
.source_access_type = AccessType::S3,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -252,6 +252,9 @@ void registerStorageURL(StorageFactory & factory)
|
||||
format_name,
|
||||
args.columns, args.constraints, args.context,
|
||||
compression_method);
|
||||
},
|
||||
{
|
||||
.source_access_type = AccessType::URL,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -134,6 +134,9 @@ namespace
|
||||
args.context,
|
||||
bridge_helper);
|
||||
|
||||
},
|
||||
{
|
||||
.source_access_type = BridgeHelperMixin::getSourceAccessType(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/EnabledQuota.h>
|
||||
#include <Access/QuotaUsageInfo.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <ext/range.h>
|
||||
|
||||
|
||||
@ -40,7 +41,9 @@ NamesAndTypesList StorageSystemQuotaUsage::getNamesAndTypes()
|
||||
|
||||
void StorageSystemQuotaUsage::fillData(MutableColumns & res_columns, const Context & context, const SelectQueryInfo &) const
|
||||
{
|
||||
context.checkAccess(AccessType::SHOW_QUOTAS);
|
||||
const auto & access_control = context.getAccessControlManager();
|
||||
|
||||
for (const auto & info : access_control.getQuotaUsageInfo())
|
||||
{
|
||||
for (const auto & interval : info.intervals)
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/Quota.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <ext/range.h>
|
||||
|
||||
|
||||
@ -54,6 +55,8 @@ NamesAndTypesList StorageSystemQuotas::getNamesAndTypes()
|
||||
|
||||
void StorageSystemQuotas::fillData(MutableColumns & res_columns, const Context & context, const SelectQueryInfo &) const
|
||||
{
|
||||
context.checkAccess(AccessType::SHOW_QUOTAS);
|
||||
|
||||
size_t i = 0;
|
||||
auto & name_column = *res_columns[i++];
|
||||
auto & id_column = *res_columns[i++];
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Access/AccessControlManager.h>
|
||||
#include <Access/RowPolicy.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <ext/range.h>
|
||||
|
||||
|
||||
@ -33,6 +34,7 @@ NamesAndTypesList StorageSystemRowPolicies::getNamesAndTypes()
|
||||
|
||||
void StorageSystemRowPolicies::fillData(MutableColumns & res_columns, const Context & context, const SelectQueryInfo &) const
|
||||
{
|
||||
context.checkAccess(AccessType::SHOW_ROW_POLICIES);
|
||||
const auto & access_control = context.getAccessControlManager();
|
||||
std::vector<UUID> ids = access_control.findAll<RowPolicy>();
|
||||
|
||||
|
@ -1,4 +1,7 @@
|
||||
#include <TableFunctions/ITableFunction.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Storages/StorageFactory.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <Common/ProfileEvents.h>
|
||||
|
||||
|
||||
@ -13,6 +16,7 @@ namespace DB
|
||||
StoragePtr ITableFunction::execute(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const
|
||||
{
|
||||
ProfileEvents::increment(ProfileEvents::TableFunctionExecute);
|
||||
context.checkAccess(AccessType::CREATE_TEMPORARY_TABLE | StorageFactory::instance().getSourceAccessType(getStorageTypeName()));
|
||||
return executeImpl(ast_function, context, table_name);
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,7 @@ public:
|
||||
|
||||
private:
|
||||
virtual StoragePtr executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const = 0;
|
||||
virtual const char * getStorageTypeName() const = 0;
|
||||
};
|
||||
|
||||
using TableFunctionPtr = std::shared_ptr<ITableFunction>;
|
||||
|
@ -10,8 +10,6 @@
|
||||
|
||||
#include <Storages/StorageFile.h>
|
||||
|
||||
#include <Access/AccessFlags.h>
|
||||
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/evaluateConstantExpression.h>
|
||||
|
||||
@ -65,8 +63,6 @@ StoragePtr ITableFunctionFileLike::executeImpl(const ASTPtr & ast_function, cons
|
||||
if (args.size() == 4)
|
||||
compression_method = args[3]->as<ASTLiteral &>().value.safeGet<String>();
|
||||
|
||||
context.checkAccess(getRequiredAccessType());
|
||||
|
||||
/// Create table
|
||||
StoragePtr storage = getStorage(filename, format, columns, const_cast<Context &>(context), table_name, compression_method);
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
namespace DB
|
||||
{
|
||||
enum class AccessType;
|
||||
class ColumnsDescription;
|
||||
|
||||
/*
|
||||
@ -17,6 +16,5 @@ private:
|
||||
StoragePtr executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const override;
|
||||
virtual StoragePtr getStorage(
|
||||
const String & source, const String & format, const ColumnsDescription & columns, Context & global_context, const std::string & table_name, const String & compression_method) const = 0;
|
||||
virtual AccessType getRequiredAccessType() const = 0;
|
||||
};
|
||||
}
|
||||
|
@ -60,8 +60,6 @@ StoragePtr ITableFunctionXDBC::executeImpl(const ASTPtr & ast_function, const Co
|
||||
remote_table_name = args[1]->as<ASTLiteral &>().value.safeGet<String>();
|
||||
}
|
||||
|
||||
context.checkAccess(getRequiredAccessType());
|
||||
|
||||
/* Infer external table structure */
|
||||
/// Have to const_cast, because bridges store their commands inside context
|
||||
BridgeHelperPtr helper = createBridgeHelper(const_cast<Context &>(context), context.getSettingsRef().http_receive_timeout.value, connection_string);
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include <Storages/StorageXDBC.h>
|
||||
#include <TableFunctions/ITableFunction.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <Poco/Util/AbstractConfiguration.h>
|
||||
#include <Common/XDBCBridgeHelper.h>
|
||||
#include <Common/config.h>
|
||||
@ -22,8 +21,6 @@ private:
|
||||
virtual BridgeHelperPtr createBridgeHelper(Context & context,
|
||||
const Poco::Timespan & http_timeout_,
|
||||
const std::string & connection_string_) const = 0;
|
||||
|
||||
virtual AccessType getRequiredAccessType() const = 0;
|
||||
};
|
||||
|
||||
class TableFunctionJDBC : public ITableFunctionXDBC
|
||||
@ -43,7 +40,7 @@ private:
|
||||
return std::make_shared<XDBCBridgeHelper<JDBCBridgeMixin>>(context, http_timeout_, connection_string_);
|
||||
}
|
||||
|
||||
AccessType getRequiredAccessType() const override { return AccessType::jdbc; }
|
||||
const char * getStorageTypeName() const override { return "JDBC"; }
|
||||
};
|
||||
|
||||
class TableFunctionODBC : public ITableFunctionXDBC
|
||||
@ -63,6 +60,6 @@ private:
|
||||
return std::make_shared<XDBCBridgeHelper<ODBCBridgeMixin>>(context, http_timeout_, connection_string_);
|
||||
}
|
||||
|
||||
AccessType getRequiredAccessType() const override { return AccessType::odbc; }
|
||||
const char * getStorageTypeName() const override { return "ODBC"; }
|
||||
};
|
||||
}
|
||||
|
@ -15,11 +15,6 @@ StoragePtr TableFunctionFile::getStorage(
|
||||
return StorageFile::create(source, global_context.getUserFilesPath(), args);
|
||||
}
|
||||
|
||||
AccessType TableFunctionFile::getRequiredAccessType() const
|
||||
{
|
||||
return AccessType::file;
|
||||
}
|
||||
|
||||
void registerTableFunctionFile(TableFunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<TableFunctionFile>();
|
||||
|
@ -24,6 +24,5 @@ public:
|
||||
private:
|
||||
StoragePtr getStorage(
|
||||
const String & source, const String & format, const ColumnsDescription & columns, Context & global_context, const std::string & table_name, const std::string & compression_method) const override;
|
||||
AccessType getRequiredAccessType() const override;
|
||||
};
|
||||
}
|
||||
const char * getStorageTypeName() const override { return "File"; }
|
||||
};}
|
||||
|
@ -15,6 +15,7 @@ public:
|
||||
std::string getName() const override { return name; }
|
||||
private:
|
||||
StoragePtr executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const override;
|
||||
const char * getStorageTypeName() const override { return "GenerateRandom"; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
#if USE_HDFS
|
||||
#include <Storages/StorageHDFS.h>
|
||||
#include <Storages/ColumnsDescription.h>
|
||||
#include <Access/AccessType.h>
|
||||
#include <TableFunctions/TableFunctionFactory.h>
|
||||
#include <TableFunctions/TableFunctionHDFS.h>
|
||||
|
||||
@ -22,10 +21,6 @@ StoragePtr TableFunctionHDFS::getStorage(
|
||||
compression_method);
|
||||
}
|
||||
|
||||
AccessType TableFunctionHDFS::getRequiredAccessType() const
|
||||
{
|
||||
return AccessType::hdfs;
|
||||
}
|
||||
|
||||
#if USE_HDFS
|
||||
void registerTableFunctionHDFS(TableFunctionFactory & factory)
|
||||
|
@ -25,7 +25,7 @@ public:
|
||||
private:
|
||||
StoragePtr getStorage(
|
||||
const String & source, const String & format, const ColumnsDescription & columns, Context & global_context, const std::string & table_name, const String & compression_method) const override;
|
||||
AccessType getRequiredAccessType() const override;
|
||||
const char * getStorageTypeName() const override { return "HDFS"; }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <DataTypes/DataTypeFactory.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Interpreters/evaluateConstantExpression.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include "registerTableFunctions.h"
|
||||
|
||||
@ -37,8 +36,6 @@ StoragePtr TableFunctionInput::executeImpl(const ASTPtr & ast_function, const Co
|
||||
throw Exception("Table function '" + getName() + "' requires exactly 1 argument: structure",
|
||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||
|
||||
context.checkAccess(AccessType::input);
|
||||
|
||||
String structure = evaluateConstantExpressionOrIdentifierAsLiteral(args[0], context)->as<ASTLiteral &>().value.safeGet<String>();
|
||||
auto columns = parseColumnsListFromString(structure, context);
|
||||
StoragePtr storage = StorageInput::create(StorageID(getDatabaseName(), table_name), columns);
|
||||
|
@ -16,5 +16,6 @@ public:
|
||||
|
||||
private:
|
||||
StoragePtr executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const override;
|
||||
const char * getStorageTypeName() const override { return "Input"; }
|
||||
};
|
||||
}
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include <TableFunctions/ITableFunction.h>
|
||||
#include <Interpreters/evaluateConstantExpression.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <TableFunctions/TableFunctionMerge.h>
|
||||
#include <TableFunctions/TableFunctionFactory.h>
|
||||
#include <TableFunctions/registerTableFunctions.h>
|
||||
@ -68,8 +67,6 @@ StoragePtr TableFunctionMerge::executeImpl(const ASTPtr & ast_function, const Co
|
||||
String source_database = args[0]->as<ASTLiteral &>().value.safeGet<String>();
|
||||
String table_name_regexp = args[1]->as<ASTLiteral &>().value.safeGet<String>();
|
||||
|
||||
context.checkAccess(AccessType::merge, source_database);
|
||||
|
||||
auto res = StorageMerge::create(
|
||||
StorageID(getDatabaseName(), table_name),
|
||||
ColumnsDescription{chooseColumns(source_database, table_name_regexp, context)},
|
||||
|
@ -17,6 +17,7 @@ public:
|
||||
std::string getName() const override { return name; }
|
||||
private:
|
||||
StoragePtr executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const override;
|
||||
const char * getStorageTypeName() const override { return "Merge"; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include <DataTypes/DataTypesNumber.h>
|
||||
#include <DataTypes/DataTypeString.h>
|
||||
#include <Formats/MySQLBlockInputStream.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <Interpreters/evaluateConstantExpression.h>
|
||||
#include <Parsers/ASTFunction.h>
|
||||
#include <Parsers/ASTLiteral.h>
|
||||
@ -57,8 +56,6 @@ StoragePtr TableFunctionMySQL::executeImpl(const ASTPtr & ast_function, const Co
|
||||
std::string user_name = args[3]->as<ASTLiteral &>().value.safeGet<String>();
|
||||
std::string password = args[4]->as<ASTLiteral &>().value.safeGet<String>();
|
||||
|
||||
context.checkAccess(AccessType::mysql);
|
||||
|
||||
bool replace_query = false;
|
||||
std::string on_duplicate_clause;
|
||||
if (args.size() >= 6)
|
||||
|
@ -20,6 +20,7 @@ public:
|
||||
}
|
||||
private:
|
||||
StoragePtr executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const override;
|
||||
const char * getStorageTypeName() const override { return "MySQL"; }
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <Parsers/ASTLiteral.h>
|
||||
#include <Common/typeid_cast.h>
|
||||
#include <Storages/System/StorageSystemNumbers.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <Interpreters/evaluateConstantExpression.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include "registerTableFunctions.h"
|
||||
@ -33,8 +32,6 @@ StoragePtr TableFunctionNumbers<multithreaded>::executeImpl(const ASTPtr & ast_f
|
||||
UInt64 offset = arguments.size() == 2 ? evaluateArgument(context, arguments[0]) : 0;
|
||||
UInt64 length = arguments.size() == 2 ? evaluateArgument(context, arguments[1]) : evaluateArgument(context, arguments[0]);
|
||||
|
||||
context.checkAccess(AccessType::numbers);
|
||||
|
||||
auto res = StorageSystemNumbers::create(StorageID(getDatabaseName(), table_name), multithreaded, length, offset, false);
|
||||
res->startup();
|
||||
return res;
|
||||
|
@ -19,6 +19,7 @@ public:
|
||||
std::string getName() const override { return name; }
|
||||
private:
|
||||
StoragePtr executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const override;
|
||||
const char * getStorageTypeName() const override { return "SystemNumbers"; }
|
||||
|
||||
UInt64 evaluateArgument(const Context & context, ASTPtr & argument) const;
|
||||
};
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include <Parsers/ASTLiteral.h>
|
||||
#include <Parsers/ASTFunction.h>
|
||||
#include <Parsers/ASTExpressionList.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <Interpreters/evaluateConstantExpression.h>
|
||||
#include <Interpreters/Cluster.h>
|
||||
#include <Interpreters/Context.h>
|
||||
@ -132,8 +131,6 @@ StoragePtr TableFunctionRemote::executeImpl(const ASTPtr & ast_function, const C
|
||||
if (arg_num < args.size())
|
||||
throw Exception(help_message, ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||
|
||||
context.checkAccess(AccessType::remote);
|
||||
|
||||
/// ExpressionAnalyzer will be created in InterpreterSelectQuery that will meet these `Identifier` when processing the request.
|
||||
/// We need to mark them as the name of the database or table, because the default value is column.
|
||||
for (auto ast : args)
|
||||
|
@ -22,6 +22,7 @@ public:
|
||||
|
||||
private:
|
||||
StoragePtr executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const override;
|
||||
const char * getStorageTypeName() const override { return "Distributed"; }
|
||||
|
||||
std::string name;
|
||||
bool is_cluster_function;
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
#include <IO/S3Common.h>
|
||||
#include <Storages/StorageS3.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <Interpreters/evaluateConstantExpression.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include <TableFunctions/TableFunctionFactory.h>
|
||||
@ -64,8 +63,6 @@ StoragePtr TableFunctionS3::executeImpl(const ASTPtr & ast_function, const Conte
|
||||
else
|
||||
compression_method = "auto";
|
||||
|
||||
context.checkAccess(AccessType::s3);
|
||||
|
||||
ColumnsDescription columns = parseColumnsListFromString(structure, context);
|
||||
|
||||
/// Create table
|
||||
|
@ -38,6 +38,8 @@ private:
|
||||
Context & global_context,
|
||||
const std::string & table_name,
|
||||
const String & compression_method);
|
||||
|
||||
const char * getStorageTypeName() const override { return "S3"; }
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -16,11 +16,6 @@ StoragePtr TableFunctionURL::getStorage(
|
||||
return StorageURL::create(uri, StorageID(getDatabaseName(), table_name), format, columns, ConstraintsDescription{}, global_context, compression_method);
|
||||
}
|
||||
|
||||
AccessType TableFunctionURL::getRequiredAccessType() const
|
||||
{
|
||||
return AccessType::url;
|
||||
}
|
||||
|
||||
void registerTableFunctionURL(TableFunctionFactory & factory)
|
||||
{
|
||||
factory.registerFunction<TableFunctionURL>();
|
||||
|
@ -20,6 +20,6 @@ public:
|
||||
private:
|
||||
StoragePtr getStorage(
|
||||
const String & source, const String & format, const ColumnsDescription & columns, Context & global_context, const std::string & table_name, const String & compression_method) const override;
|
||||
AccessType getRequiredAccessType() const override;
|
||||
const char * getStorageTypeName() const override { return "URL"; }
|
||||
};
|
||||
}
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include <TableFunctions/TableFunctionFactory.h>
|
||||
#include <TableFunctions/parseColumnsListForTableFunction.h>
|
||||
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <Interpreters/convertFieldToType.h>
|
||||
#include <Interpreters/evaluateConstantExpression.h>
|
||||
#include <Interpreters/Context.h>
|
||||
@ -75,8 +74,6 @@ StoragePtr TableFunctionValues::executeImpl(const ASTPtr & ast_function, const C
|
||||
throw Exception("Table function '" + getName() + "' requires 2 or more arguments: structure and values.",
|
||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||
|
||||
context.checkAccess(AccessType::values);
|
||||
|
||||
/// Parsing first argument as table structure and creating a sample block
|
||||
std::string structure = args[0]->as<ASTLiteral &>().value.safeGet<String>();
|
||||
|
||||
|
@ -14,6 +14,7 @@ public:
|
||||
std::string getName() const override { return name; }
|
||||
private:
|
||||
StoragePtr executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const override;
|
||||
const char * getStorageTypeName() const override { return "Values"; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <Parsers/ASTLiteral.h>
|
||||
#include <Common/typeid_cast.h>
|
||||
#include <Storages/System/StorageSystemZeros.h>
|
||||
#include <Access/AccessFlags.h>
|
||||
#include <Interpreters/evaluateConstantExpression.h>
|
||||
#include <Interpreters/Context.h>
|
||||
#include "registerTableFunctions.h"
|
||||
@ -32,8 +31,6 @@ StoragePtr TableFunctionZeros<multithreaded>::executeImpl(const ASTPtr & ast_fun
|
||||
|
||||
UInt64 length = evaluateArgument(context, arguments[0]);
|
||||
|
||||
context.checkAccess(AccessType::zeros);
|
||||
|
||||
auto res = StorageSystemZeros::create(StorageID(getDatabaseName(), table_name), multithreaded, length);
|
||||
res->startup();
|
||||
return res;
|
||||
|
@ -19,6 +19,7 @@ public:
|
||||
std::string getName() const override { return name; }
|
||||
private:
|
||||
StoragePtr executeImpl(const ASTPtr & ast_function, const Context & context, const std::string & table_name) const override;
|
||||
const char * getStorageTypeName() const override { return "SystemZeros"; }
|
||||
|
||||
UInt64 evaluateArgument(const Context & context, ASTPtr & argument) const;
|
||||
};
|
||||
|
@ -0,0 +1,22 @@
|
||||
<yandex>
|
||||
<remote_servers>
|
||||
<cluster>
|
||||
<shard>
|
||||
<replica>
|
||||
<host>ch1</host>
|
||||
<port>9000</port>
|
||||
</replica>
|
||||
<replica>
|
||||
<host>ch2</host>
|
||||
<port>9000</port>
|
||||
</replica>
|
||||
</shard>
|
||||
<shard>
|
||||
<replica>
|
||||
<host>ch3</host>
|
||||
<port>9000</port>
|
||||
</replica>
|
||||
</shard>
|
||||
</cluster>
|
||||
</remote_servers>
|
||||
</yandex>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user