Merge pull request #9811 from vitlibar/RBAC-8

RBAC-8
This commit is contained in:
alexey-milovidov 2020-04-08 05:47:55 +03:00 committed by GitHub
commit 6d80ab1eed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
123 changed files with 1021 additions and 910 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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;
}

View File

@ -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];
};

View File

@ -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;

View File

@ -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;
};
}

View File

@ -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);

View File

@ -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)

View File

@ -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, &current_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, &current_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;

View File

@ -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 = {});
};
}

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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)

View File

@ -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;
}

View File

@ -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();

View File

@ -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, {});
}
}

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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()};

View File

@ -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};

View File

@ -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)

View File

@ -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};

View File

@ -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};

View File

@ -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;

View File

@ -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);
}

View File

@ -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();

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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()); }
};
}

View File

@ -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);

View File

@ -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()); }
};
}

View File

@ -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);
}
}

View File

@ -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()); }
};
}

View File

@ -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);
}
}

View File

@ -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()); }
};
}

View File

@ -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);

View File

@ -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()); }
};
}

View File

@ -75,5 +75,7 @@ void ASTDropAccessEntityQuery::formatImpl(const FormatSettings & settings, Forma
settings.ostr << ' ' << backQuoteIfNeed(name);
}
}
formatOnCluster(settings);
}
}

View File

@ -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()); }
};
}

View File

@ -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;
}
}
}

View File

@ -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); }

View File

@ -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);
}
}

View File

@ -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()); }
};
}

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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).

View File

@ -810,6 +810,9 @@ void registerStorageDistributed(StorageFactory & factory)
storage_policy,
args.relative_data_path,
args.attach);
},
{
.source_access_type = AccessType::REMOTE,
});
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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,
});
}
}

View 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,
});
}

View File

@ -248,6 +248,9 @@ void registerStorageMySQL(StorageFactory & factory)
args.columns,
args.constraints,
args.context);
},
{
.source_access_type = AccessType::MYSQL,
});
}

View File

@ -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,
});
}

View File

@ -252,6 +252,9 @@ void registerStorageURL(StorageFactory & factory)
format_name,
args.columns, args.constraints, args.context,
compression_method);
},
{
.source_access_type = AccessType::URL,
});
}
}

View File

@ -134,6 +134,9 @@ namespace
args.context,
bridge_helper);
},
{
.source_access_type = BridgeHelperMixin::getSourceAccessType(),
});
}
}

View File

@ -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)

View File

@ -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++];

View File

@ -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>();

View File

@ -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);
}

View File

@ -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>;

View File

@ -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);

View File

@ -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;
};
}

View File

@ -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);

View File

@ -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"; }
};
}

View File

@ -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>();

View File

@ -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"; }
};}

View 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"; }
};

View File

@ -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)

View File

@ -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"; }
};
}

View File

@ -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);

View File

@ -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"; }
};
}

View File

@ -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)},

View File

@ -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"; }
};

View File

@ -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)

View File

@ -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"; }
};
}

View File

@ -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;

View File

@ -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;
};

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -38,6 +38,8 @@ private:
Context & global_context,
const std::string & table_name,
const String & compression_method);
const char * getStorageTypeName() const override { return "S3"; }
};
}

View File

@ -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>();

View File

@ -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"; }
};
}

View File

@ -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>();

View File

@ -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"; }
};

View File

@ -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;

View File

@ -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;
};

View File

@ -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