mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-20 16:50:48 +00:00
Merge pull request #46241 from kssenii/named-collections-granular-access
Allow separate grants for every named collection
This commit is contained in:
commit
a9bcd022d5
@ -61,14 +61,25 @@ namespace
|
||||
res.any_database = true;
|
||||
res.any_table = true;
|
||||
res.any_column = true;
|
||||
res.any_parameter = true;
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
res.any_database = false;
|
||||
res.database = full_name[0];
|
||||
res.any_table = true;
|
||||
res.any_column = true;
|
||||
if (access_flags.isGlobalWithParameter())
|
||||
{
|
||||
res.parameter = full_name[0];
|
||||
res.any_parameter = false;
|
||||
res.any_database = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
res.database = full_name[0];
|
||||
res.any_database = false;
|
||||
res.any_parameter = false;
|
||||
res.any_table = true;
|
||||
res.any_column = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
@ -110,10 +121,35 @@ namespace
|
||||
size_t count_elements_with_diff_columns = sorted.countElementsWithDifferenceInColumnOnly(i);
|
||||
if (count_elements_with_diff_columns == 1)
|
||||
{
|
||||
/// Easy case: one Element is converted to one AccessRightsElement.
|
||||
const auto & element = sorted[i];
|
||||
if (element.access_flags)
|
||||
res.emplace_back(element.getResult());
|
||||
{
|
||||
const bool all_granted = sorted.size() == 1 && element.access_flags.contains(AccessFlags::allFlags());
|
||||
if (all_granted)
|
||||
{
|
||||
/// Easy case: one Element is converted to one AccessRightsElement.
|
||||
res.emplace_back(element.getResult());
|
||||
}
|
||||
else
|
||||
{
|
||||
auto per_parameter = element.access_flags.splitIntoParameterTypes();
|
||||
if (per_parameter.size() == 1)
|
||||
{
|
||||
/// Easy case: one Element is converted to one AccessRightsElement.
|
||||
res.emplace_back(element.getResult());
|
||||
}
|
||||
else
|
||||
{
|
||||
/// Difficult case: one element is converted into multiple AccessRightsElements.
|
||||
for (const auto & [_, parameter_flags] : per_parameter)
|
||||
{
|
||||
auto current_element{element};
|
||||
current_element.access_flags = parameter_flags;
|
||||
res.emplace_back(current_element.getResult());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
else
|
||||
@ -137,6 +173,8 @@ namespace
|
||||
{
|
||||
return (element.full_name.size() != 3) || (element.full_name[0] != start_element.full_name[0])
|
||||
|| (element.full_name[1] != start_element.full_name[1]) || (element.grant_option != start_element.grant_option)
|
||||
|| (element.access_flags.isGlobalWithParameter() != start_element.access_flags.isGlobalWithParameter())
|
||||
|| (element.access_flags.getParameterType() != start_element.access_flags.getParameterType())
|
||||
|| (element.is_partial_revoke != start_element.is_partial_revoke);
|
||||
});
|
||||
|
||||
@ -191,11 +229,19 @@ namespace
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Levels:
|
||||
* 1. GLOBAL
|
||||
* 2. DATABASE_LEVEL 2. GLOBAL_WITH_PARAMETER (parameter example: named collection)
|
||||
* 3. TABLE_LEVEL
|
||||
* 4. COLUMN_LEVEL
|
||||
*/
|
||||
|
||||
enum Level
|
||||
{
|
||||
GLOBAL_LEVEL,
|
||||
DATABASE_LEVEL,
|
||||
GLOBAL_WITH_PARAMETER = DATABASE_LEVEL,
|
||||
TABLE_LEVEL,
|
||||
COLUMN_LEVEL,
|
||||
};
|
||||
@ -205,7 +251,7 @@ namespace
|
||||
switch (level)
|
||||
{
|
||||
case GLOBAL_LEVEL: return AccessFlags::allFlagsGrantableOnGlobalLevel();
|
||||
case DATABASE_LEVEL: return AccessFlags::allFlagsGrantableOnDatabaseLevel();
|
||||
case DATABASE_LEVEL: return AccessFlags::allFlagsGrantableOnDatabaseLevel() | AccessFlags::allFlagsGrantableOnGlobalWithParameterLevel();
|
||||
case TABLE_LEVEL: return AccessFlags::allFlagsGrantableOnTableLevel();
|
||||
case COLUMN_LEVEL: return AccessFlags::allFlagsGrantableOnColumnLevel();
|
||||
}
|
||||
@ -783,7 +829,14 @@ void AccessRights::grantImplHelper(const AccessRightsElement & element)
|
||||
{
|
||||
assert(!element.is_partial_revoke);
|
||||
assert(!element.grant_option || with_grant_option);
|
||||
if (element.any_database)
|
||||
if (element.isGlobalWithParameter())
|
||||
{
|
||||
if (element.any_parameter)
|
||||
grantImpl<with_grant_option>(element.access_flags);
|
||||
else
|
||||
grantImpl<with_grant_option>(element.access_flags, element.parameter);
|
||||
}
|
||||
else if (element.any_database)
|
||||
grantImpl<with_grant_option>(element.access_flags);
|
||||
else if (element.any_table)
|
||||
grantImpl<with_grant_option>(element.access_flags, element.database);
|
||||
@ -858,7 +911,14 @@ template <bool grant_option>
|
||||
void AccessRights::revokeImplHelper(const AccessRightsElement & element)
|
||||
{
|
||||
assert(!element.grant_option || grant_option);
|
||||
if (element.any_database)
|
||||
if (element.isGlobalWithParameter())
|
||||
{
|
||||
if (element.any_parameter)
|
||||
revokeImpl<grant_option>(element.access_flags);
|
||||
else
|
||||
revokeImpl<grant_option>(element.access_flags, element.parameter);
|
||||
}
|
||||
else if (element.any_database)
|
||||
revokeImpl<grant_option>(element.access_flags);
|
||||
else if (element.any_table)
|
||||
revokeImpl<grant_option>(element.access_flags, element.database);
|
||||
@ -948,7 +1008,14 @@ template <bool grant_option>
|
||||
bool AccessRights::isGrantedImplHelper(const AccessRightsElement & element) const
|
||||
{
|
||||
assert(!element.grant_option || grant_option);
|
||||
if (element.any_database)
|
||||
if (element.isGlobalWithParameter())
|
||||
{
|
||||
if (element.any_parameter)
|
||||
return isGrantedImpl<grant_option>(element.access_flags);
|
||||
else
|
||||
return isGrantedImpl<grant_option>(element.access_flags, element.parameter);
|
||||
}
|
||||
else if (element.any_database)
|
||||
return isGrantedImpl<grant_option>(element.access_flags);
|
||||
else if (element.any_table)
|
||||
return isGrantedImpl<grant_option>(element.access_flags, element.database);
|
||||
|
@ -15,6 +15,7 @@ namespace ErrorCodes
|
||||
{
|
||||
extern const int UNKNOWN_ACCESS_TYPE;
|
||||
extern const int LOGICAL_ERROR;
|
||||
extern const int MIXED_ACCESS_PARAMETER_TYPES;
|
||||
}
|
||||
|
||||
namespace
|
||||
@ -96,11 +97,14 @@ namespace
|
||||
|
||||
const Flags & getAllFlags() const { return all_flags; }
|
||||
const Flags & getGlobalFlags() const { return all_flags_for_target[GLOBAL]; }
|
||||
const Flags & getGlobalWithParameterFlags() const { return all_flags_grantable_on_global_with_parameter_level; }
|
||||
const Flags & getDatabaseFlags() const { return all_flags_for_target[DATABASE]; }
|
||||
const Flags & getTableFlags() const { return all_flags_for_target[TABLE]; }
|
||||
const Flags & getColumnFlags() const { return all_flags_for_target[COLUMN]; }
|
||||
const Flags & getDictionaryFlags() const { return all_flags_for_target[DICTIONARY]; }
|
||||
const Flags & getNamedCollectionFlags() const { return all_flags_for_target[NAMED_COLLECTION]; }
|
||||
const Flags & getAllFlagsGrantableOnGlobalLevel() const { return getAllFlags(); }
|
||||
const Flags & getAllFlagsGrantableOnGlobalWithParameterLevel() const { return getGlobalWithParameterFlags(); }
|
||||
const Flags & getAllFlagsGrantableOnDatabaseLevel() const { return all_flags_grantable_on_database_level; }
|
||||
const Flags & getAllFlagsGrantableOnTableLevel() const { return all_flags_grantable_on_table_level; }
|
||||
const Flags & getAllFlagsGrantableOnColumnLevel() const { return getColumnFlags(); }
|
||||
@ -116,6 +120,7 @@ namespace
|
||||
VIEW = TABLE,
|
||||
COLUMN,
|
||||
DICTIONARY,
|
||||
NAMED_COLLECTION,
|
||||
};
|
||||
|
||||
struct Node;
|
||||
@ -295,6 +300,7 @@ namespace
|
||||
collectAllFlags(child.get());
|
||||
|
||||
all_flags_grantable_on_table_level = all_flags_for_target[TABLE] | all_flags_for_target[DICTIONARY] | all_flags_for_target[COLUMN];
|
||||
all_flags_grantable_on_global_with_parameter_level = all_flags_for_target[NAMED_COLLECTION];
|
||||
all_flags_grantable_on_database_level = all_flags_for_target[DATABASE] | all_flags_grantable_on_table_level;
|
||||
}
|
||||
|
||||
@ -345,12 +351,44 @@ namespace
|
||||
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[static_cast<size_t>(DICTIONARY) + 1];
|
||||
Flags all_flags_for_target[static_cast<size_t>(NAMED_COLLECTION) + 1];
|
||||
Flags all_flags_grantable_on_database_level;
|
||||
Flags all_flags_grantable_on_table_level;
|
||||
Flags all_flags_grantable_on_global_with_parameter_level;
|
||||
};
|
||||
}
|
||||
|
||||
bool AccessFlags::isGlobalWithParameter() const
|
||||
{
|
||||
return getParameterType() != AccessFlags::NONE;
|
||||
}
|
||||
|
||||
std::unordered_map<AccessFlags::ParameterType, AccessFlags> AccessFlags::splitIntoParameterTypes() const
|
||||
{
|
||||
std::unordered_map<ParameterType, AccessFlags> result;
|
||||
|
||||
auto named_collection_flags = AccessFlags::allNamedCollectionFlags() & *this;
|
||||
if (named_collection_flags)
|
||||
result.emplace(ParameterType::NAMED_COLLECTION, named_collection_flags);
|
||||
|
||||
auto other_flags = (~AccessFlags::allNamedCollectionFlags()) & *this;
|
||||
if (other_flags)
|
||||
result.emplace(ParameterType::NONE, other_flags);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
AccessFlags::ParameterType AccessFlags::getParameterType() const
|
||||
{
|
||||
if (isEmpty() || !AccessFlags::allGlobalWithParameterFlags().contains(*this))
|
||||
return AccessFlags::NONE;
|
||||
|
||||
/// All flags refer to NAMED COLLECTION access type.
|
||||
if (AccessFlags::allNamedCollectionFlags().contains(*this))
|
||||
return AccessFlags::NAMED_COLLECTION;
|
||||
|
||||
throw Exception(ErrorCodes::MIXED_ACCESS_PARAMETER_TYPES, "Having mixed parameter types: {}", toString());
|
||||
}
|
||||
|
||||
AccessFlags::AccessFlags(AccessType type) : flags(Helper::instance().accessTypeToFlags(type)) {}
|
||||
AccessFlags::AccessFlags(std::string_view keyword) : flags(Helper::instance().keywordToFlags(keyword)) {}
|
||||
@ -361,11 +399,14 @@ std::vector<AccessType> AccessFlags::toAccessTypes() const { return Helper::inst
|
||||
std::vector<std::string_view> AccessFlags::toKeywords() const { return Helper::instance().flagsToKeywords(flags); }
|
||||
AccessFlags AccessFlags::allFlags() { return Helper::instance().getAllFlags(); }
|
||||
AccessFlags AccessFlags::allGlobalFlags() { return Helper::instance().getGlobalFlags(); }
|
||||
AccessFlags AccessFlags::allGlobalWithParameterFlags() { return Helper::instance().getGlobalWithParameterFlags(); }
|
||||
AccessFlags AccessFlags::allDatabaseFlags() { return Helper::instance().getDatabaseFlags(); }
|
||||
AccessFlags AccessFlags::allTableFlags() { return Helper::instance().getTableFlags(); }
|
||||
AccessFlags AccessFlags::allColumnFlags() { return Helper::instance().getColumnFlags(); }
|
||||
AccessFlags AccessFlags::allDictionaryFlags() { return Helper::instance().getDictionaryFlags(); }
|
||||
AccessFlags AccessFlags::allNamedCollectionFlags() { return Helper::instance().getNamedCollectionFlags(); }
|
||||
AccessFlags AccessFlags::allFlagsGrantableOnGlobalLevel() { return Helper::instance().getAllFlagsGrantableOnGlobalLevel(); }
|
||||
AccessFlags AccessFlags::allFlagsGrantableOnGlobalWithParameterLevel() { return Helper::instance().getAllFlagsGrantableOnGlobalWithParameterLevel(); }
|
||||
AccessFlags AccessFlags::allFlagsGrantableOnDatabaseLevel() { return Helper::instance().getAllFlagsGrantableOnDatabaseLevel(); }
|
||||
AccessFlags AccessFlags::allFlagsGrantableOnTableLevel() { return Helper::instance().getAllFlagsGrantableOnTableLevel(); }
|
||||
AccessFlags AccessFlags::allFlagsGrantableOnColumnLevel() { return Helper::instance().getAllFlagsGrantableOnColumnLevel(); }
|
||||
|
@ -48,8 +48,17 @@ public:
|
||||
AccessFlags operator ~() const { AccessFlags res; res.flags = ~flags; return res; }
|
||||
|
||||
bool isEmpty() const { return flags.none(); }
|
||||
bool isAll() const { return flags.all(); }
|
||||
explicit operator bool() const { return !isEmpty(); }
|
||||
bool contains(const AccessFlags & other) const { return (flags & other.flags) == other.flags; }
|
||||
bool isGlobalWithParameter() const;
|
||||
enum ParameterType
|
||||
{
|
||||
NONE,
|
||||
NAMED_COLLECTION,
|
||||
};
|
||||
ParameterType getParameterType() const;
|
||||
std::unordered_map<ParameterType, AccessFlags> splitIntoParameterTypes() const;
|
||||
|
||||
friend bool operator ==(const AccessFlags & left, const AccessFlags & right) { return left.flags == right.flags; }
|
||||
friend bool operator !=(const AccessFlags & left, const AccessFlags & right) { return !(left == right); }
|
||||
@ -76,6 +85,8 @@ public:
|
||||
/// Returns all the global flags.
|
||||
static AccessFlags allGlobalFlags();
|
||||
|
||||
static AccessFlags allGlobalWithParameterFlags();
|
||||
|
||||
/// Returns all the flags related to a database.
|
||||
static AccessFlags allDatabaseFlags();
|
||||
|
||||
@ -88,10 +99,16 @@ public:
|
||||
/// Returns all the flags related to a dictionary.
|
||||
static AccessFlags allDictionaryFlags();
|
||||
|
||||
/// Returns all the flags related to a named collection.
|
||||
static AccessFlags allNamedCollectionFlags();
|
||||
|
||||
/// Returns all the flags which could be granted on the global level.
|
||||
/// The same as allFlags().
|
||||
static AccessFlags allFlagsGrantableOnGlobalLevel();
|
||||
|
||||
/// Returns all the flags which could be granted on the global with parameter level.
|
||||
static AccessFlags allFlagsGrantableOnGlobalWithParameterLevel();
|
||||
|
||||
/// Returns all the flags which could be granted on the database level.
|
||||
/// Returns allDatabaseFlags() | allTableFlags() | allDictionaryFlags() | allColumnFlags().
|
||||
static AccessFlags allFlagsGrantableOnDatabaseLevel();
|
||||
|
@ -21,24 +21,31 @@ namespace
|
||||
result += ")";
|
||||
}
|
||||
|
||||
void formatONClause(const String & database, bool any_database, const String & table, bool any_table, String & result)
|
||||
void formatONClause(const AccessRightsElement & element, String & result)
|
||||
{
|
||||
result += "ON ";
|
||||
if (any_database)
|
||||
if (element.isGlobalWithParameter())
|
||||
{
|
||||
if (element.any_parameter)
|
||||
result += "*";
|
||||
else
|
||||
result += backQuoteIfNeed(element.parameter);
|
||||
}
|
||||
else if (element.any_database)
|
||||
{
|
||||
result += "*.*";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!database.empty())
|
||||
if (!element.database.empty())
|
||||
{
|
||||
result += backQuoteIfNeed(database);
|
||||
result += backQuoteIfNeed(element.database);
|
||||
result += ".";
|
||||
}
|
||||
if (any_table)
|
||||
if (element.any_table)
|
||||
result += "*";
|
||||
else
|
||||
result += backQuoteIfNeed(table);
|
||||
result += backQuoteIfNeed(element.table);
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,7 +103,7 @@ namespace
|
||||
String result;
|
||||
formatAccessFlagsWithColumns(element.access_flags, element.columns, element.any_column, result);
|
||||
result += " ";
|
||||
formatONClause(element.database, element.any_database, element.table, element.any_table, result);
|
||||
formatONClause(element, result);
|
||||
if (with_options)
|
||||
formatOptions(element.grant_option, element.is_partial_revoke, result);
|
||||
return result;
|
||||
@ -122,14 +129,16 @@ namespace
|
||||
if (i != elements.size() - 1)
|
||||
{
|
||||
const auto & next_element = elements[i + 1];
|
||||
if (element.sameDatabaseAndTable(next_element) && element.sameOptions(next_element))
|
||||
if (element.sameDatabaseAndTableAndParameter(next_element) && element.sameOptions(next_element))
|
||||
{
|
||||
next_element_uses_same_table_and_options = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!next_element_uses_same_table_and_options)
|
||||
{
|
||||
part += " ";
|
||||
formatONClause(element.database, element.any_database, element.table, element.any_table, part);
|
||||
formatONClause(element, part);
|
||||
if (with_options)
|
||||
formatOptions(element.grant_option, element.is_partial_revoke, part);
|
||||
if (result.empty())
|
||||
@ -164,6 +173,7 @@ AccessRightsElement::AccessRightsElement(
|
||||
, any_database(false)
|
||||
, any_table(false)
|
||||
, any_column(false)
|
||||
, any_parameter(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -188,12 +198,15 @@ AccessRightsElement::AccessRightsElement(
|
||||
, any_database(false)
|
||||
, any_table(false)
|
||||
, any_column(false)
|
||||
, any_parameter(false)
|
||||
{
|
||||
}
|
||||
|
||||
void AccessRightsElement::eraseNonGrantable()
|
||||
{
|
||||
if (!any_column)
|
||||
if (isGlobalWithParameter() && !any_parameter)
|
||||
access_flags &= AccessFlags::allFlagsGrantableOnGlobalWithParameterLevel();
|
||||
else if (!any_column)
|
||||
access_flags &= AccessFlags::allFlagsGrantableOnColumnLevel();
|
||||
else if (!any_table)
|
||||
access_flags &= AccessFlags::allFlagsGrantableOnTableLevel();
|
||||
@ -215,6 +228,11 @@ String AccessRightsElement::toStringWithoutOptions() const { return toStringImpl
|
||||
|
||||
bool AccessRightsElements::empty() const { return std::all_of(begin(), end(), [](const AccessRightsElement & e) { return e.empty(); }); }
|
||||
|
||||
bool AccessRightsElements::sameDatabaseAndTableAndParameter() const
|
||||
{
|
||||
return (size() < 2) || std::all_of(std::next(begin()), end(), [this](const AccessRightsElement & e) { return e.sameDatabaseAndTableAndParameter(front()); });
|
||||
}
|
||||
|
||||
bool AccessRightsElements::sameDatabaseAndTable() const
|
||||
{
|
||||
return (size() < 2) || std::all_of(std::next(begin()), end(), [this](const AccessRightsElement & e) { return e.sameDatabaseAndTable(front()); });
|
||||
|
@ -11,12 +11,17 @@ namespace DB
|
||||
struct AccessRightsElement
|
||||
{
|
||||
AccessFlags access_flags;
|
||||
|
||||
String database;
|
||||
String table;
|
||||
Strings columns;
|
||||
String parameter;
|
||||
|
||||
bool any_database = true;
|
||||
bool any_table = true;
|
||||
bool any_column = true;
|
||||
bool any_parameter = false;
|
||||
|
||||
bool grant_option = false;
|
||||
bool is_partial_revoke = false;
|
||||
|
||||
@ -44,14 +49,26 @@ struct AccessRightsElement
|
||||
|
||||
bool empty() const { return !access_flags || (!any_column && columns.empty()); }
|
||||
|
||||
auto toTuple() const { return std::tie(access_flags, any_database, database, any_table, table, any_column, columns, grant_option, is_partial_revoke); }
|
||||
auto toTuple() const { return std::tie(access_flags, any_database, database, any_table, table, any_column, columns, any_parameter, parameter, grant_option, is_partial_revoke); }
|
||||
friend bool operator==(const AccessRightsElement & left, const AccessRightsElement & right) { return left.toTuple() == right.toTuple(); }
|
||||
friend bool operator!=(const AccessRightsElement & left, const AccessRightsElement & right) { return !(left == right); }
|
||||
|
||||
bool sameDatabaseAndTableAndParameter(const AccessRightsElement & other) const
|
||||
{
|
||||
return sameDatabaseAndTable(other) && sameParameter(other);
|
||||
}
|
||||
|
||||
bool sameParameter(const AccessRightsElement & other) const
|
||||
{
|
||||
return (parameter == other.parameter) && (any_parameter == other.any_parameter)
|
||||
&& (access_flags.getParameterType() == other.access_flags.getParameterType())
|
||||
&& (isGlobalWithParameter() == other.isGlobalWithParameter());
|
||||
}
|
||||
|
||||
bool sameDatabaseAndTable(const AccessRightsElement & other) const
|
||||
{
|
||||
return (database == other.database) && (any_database == other.any_database) && (table == other.table)
|
||||
&& (any_table == other.any_table);
|
||||
return (database == other.database) && (any_database == other.any_database)
|
||||
&& (table == other.table) && (any_table == other.any_table);
|
||||
}
|
||||
|
||||
bool sameOptions(const AccessRightsElement & other) const
|
||||
@ -67,6 +84,8 @@ struct AccessRightsElement
|
||||
/// If the database is empty, replaces it with `current_database`. Otherwise does nothing.
|
||||
void replaceEmptyDatabase(const String & current_database);
|
||||
|
||||
bool isGlobalWithParameter() const { return access_flags.isGlobalWithParameter(); }
|
||||
|
||||
/// Returns a human-readable representation like "GRANT SELECT, UPDATE(x, y) ON db.table".
|
||||
String toString() const;
|
||||
String toStringWithoutOptions() const;
|
||||
@ -81,6 +100,7 @@ public:
|
||||
using Base::Base;
|
||||
|
||||
bool empty() const;
|
||||
bool sameDatabaseAndTableAndParameter() const;
|
||||
bool sameDatabaseAndTable() const;
|
||||
bool sameOptions() const;
|
||||
|
||||
|
@ -12,7 +12,7 @@ enum class AccessType
|
||||
/// 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),
|
||||
/// node_type either specifies access type's level (GLOBAL/NAMED_COLLECTION/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).
|
||||
/// NOTE A parent group must be declared AFTER all its children.
|
||||
@ -70,7 +70,7 @@ enum class AccessType
|
||||
M(ALTER_FREEZE_PARTITION, "FREEZE PARTITION, UNFREEZE", TABLE, ALTER_TABLE) \
|
||||
\
|
||||
M(ALTER_DATABASE_SETTINGS, "ALTER DATABASE SETTING, ALTER MODIFY DATABASE SETTING, MODIFY DATABASE SETTING", DATABASE, ALTER_DATABASE) /* allows to execute ALTER MODIFY SETTING */\
|
||||
M(ALTER_NAMED_COLLECTION, "", GROUP, ALTER) /* allows to execute ALTER NAMED COLLECTION */\
|
||||
M(ALTER_NAMED_COLLECTION, "", NAMED_COLLECTION, NAMED_COLLECTION_CONTROL) /* allows to execute ALTER NAMED COLLECTION */\
|
||||
\
|
||||
M(ALTER_TABLE, "", GROUP, ALTER) \
|
||||
M(ALTER_DATABASE, "", GROUP, ALTER) \
|
||||
@ -92,7 +92,7 @@ enum class AccessType
|
||||
M(CREATE_ARBITRARY_TEMPORARY_TABLE, "", GLOBAL, CREATE) /* allows to create and manipulate temporary tables
|
||||
with arbitrary table engine */\
|
||||
M(CREATE_FUNCTION, "", GLOBAL, CREATE) /* allows to execute CREATE FUNCTION */ \
|
||||
M(CREATE_NAMED_COLLECTION, "", GLOBAL, CREATE) /* allows to execute CREATE NAMED COLLECTION */ \
|
||||
M(CREATE_NAMED_COLLECTION, "", NAMED_COLLECTION, NAMED_COLLECTION_CONTROL) /* allows to execute CREATE NAMED COLLECTION */ \
|
||||
M(CREATE, "", GROUP, ALL) /* allows to execute {CREATE|ATTACH} */ \
|
||||
\
|
||||
M(DROP_DATABASE, "", DATABASE, DROP) /* allows to execute {DROP|DETACH} DATABASE */\
|
||||
@ -101,7 +101,7 @@ enum class AccessType
|
||||
implicitly enabled by the grant DROP_TABLE */\
|
||||
M(DROP_DICTIONARY, "", DICTIONARY, DROP) /* allows to execute {DROP|DETACH} DICTIONARY */\
|
||||
M(DROP_FUNCTION, "", GLOBAL, DROP) /* allows to execute DROP FUNCTION */\
|
||||
M(DROP_NAMED_COLLECTION, "", GLOBAL, DROP) /* allows to execute DROP NAMED COLLECTION */\
|
||||
M(DROP_NAMED_COLLECTION, "", NAMED_COLLECTION, NAMED_COLLECTION_CONTROL) /* allows to execute DROP NAMED COLLECTION */\
|
||||
M(DROP, "", GROUP, ALL) /* allows to execute {DROP|DETACH} */\
|
||||
\
|
||||
M(TRUNCATE, "TRUNCATE TABLE", TABLE, ALL) \
|
||||
@ -137,9 +137,10 @@ enum class AccessType
|
||||
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(SHOW_NAMED_COLLECTIONS, "SHOW NAMED COLLECTIONS", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(SHOW_NAMED_COLLECTIONS_SECRETS, "SHOW NAMED COLLECTIONS SECRETS", GLOBAL, ACCESS_MANAGEMENT) \
|
||||
M(ACCESS_MANAGEMENT, "", GROUP, ALL) \
|
||||
M(SHOW_NAMED_COLLECTIONS, "SHOW NAMED COLLECTIONS", NAMED_COLLECTION, NAMED_COLLECTION_CONTROL) \
|
||||
M(SHOW_NAMED_COLLECTIONS_SECRETS, "SHOW NAMED COLLECTIONS SECRETS", NAMED_COLLECTION, NAMED_COLLECTION_CONTROL) \
|
||||
M(NAMED_COLLECTION_CONTROL, "", NAMED_COLLECTION, 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) \
|
||||
|
@ -507,13 +507,17 @@ bool ContextAccess::checkAccessImplHelper(AccessFlags flags, const Args &... arg
|
||||
if (!flags)
|
||||
return true;
|
||||
|
||||
/// Access to temporary tables is controlled in an unusual way, not like normal tables.
|
||||
/// Creating of temporary tables is controlled by AccessType::CREATE_TEMPORARY_TABLES grant,
|
||||
/// and other grants are considered as always given.
|
||||
/// The DatabaseCatalog class won't resolve StorageID for temporary tables
|
||||
/// which shouldn't be accessed.
|
||||
if (getDatabase(args...) == DatabaseCatalog::TEMPORARY_DATABASE)
|
||||
return access_granted();
|
||||
const auto parameter_type = flags.getParameterType();
|
||||
if (parameter_type == AccessFlags::NONE)
|
||||
{
|
||||
/// Access to temporary tables is controlled in an unusual way, not like normal tables.
|
||||
/// Creating of temporary tables is controlled by AccessType::CREATE_TEMPORARY_TABLES grant,
|
||||
/// and other grants are considered as always given.
|
||||
/// The DatabaseCatalog class won't resolve StorageID for temporary tables
|
||||
/// which shouldn't be accessed.
|
||||
if (getDatabase(args...) == DatabaseCatalog::TEMPORARY_DATABASE)
|
||||
return access_granted();
|
||||
}
|
||||
|
||||
auto acs = getAccessRightsWithImplicit();
|
||||
bool granted;
|
||||
@ -611,7 +615,14 @@ template <bool throw_if_denied, bool grant_option>
|
||||
bool ContextAccess::checkAccessImplHelper(const AccessRightsElement & element) const
|
||||
{
|
||||
assert(!element.grant_option || grant_option);
|
||||
if (element.any_database)
|
||||
if (element.isGlobalWithParameter())
|
||||
{
|
||||
if (element.any_parameter)
|
||||
return checkAccessImpl<throw_if_denied, grant_option>(element.access_flags);
|
||||
else
|
||||
return checkAccessImpl<throw_if_denied, grant_option>(element.access_flags, element.parameter);
|
||||
}
|
||||
else if (element.any_database)
|
||||
return checkAccessImpl<throw_if_denied, grant_option>(element.access_flags);
|
||||
else if (element.any_table)
|
||||
return checkAccessImpl<throw_if_denied, grant_option>(element.access_flags, element.database);
|
||||
|
@ -233,10 +233,10 @@ namespace
|
||||
user->access.revokeGrantOption(AccessType::ALL);
|
||||
}
|
||||
|
||||
bool show_named_collections = config.getBool(user_config + ".show_named_collections", false);
|
||||
if (!show_named_collections)
|
||||
bool named_collection_control = config.getBool(user_config + ".named_collection_control", false);
|
||||
if (!named_collection_control)
|
||||
{
|
||||
user->access.revoke(AccessType::SHOW_NAMED_COLLECTIONS);
|
||||
user->access.revoke(AccessType::NAMED_COLLECTION_CONTROL);
|
||||
}
|
||||
|
||||
bool show_named_collections_secrets = config.getBool(user_config + ".show_named_collections_secrets", false);
|
||||
|
@ -53,7 +53,7 @@ TEST(AccessRights, Union)
|
||||
"SHOW ROW POLICIES, SYSTEM MERGES, SYSTEM TTL MERGES, SYSTEM FETCHES, "
|
||||
"SYSTEM MOVES, SYSTEM SENDS, SYSTEM REPLICATION QUEUES, "
|
||||
"SYSTEM DROP REPLICA, SYSTEM SYNC REPLICA, SYSTEM RESTART REPLICA, "
|
||||
"SYSTEM RESTORE REPLICA, SYSTEM WAIT LOADING PARTS, SYSTEM SYNC DATABASE REPLICA, SYSTEM FLUSH DISTRIBUTED, dictGet ON db1.*");
|
||||
"SYSTEM RESTORE REPLICA, SYSTEM WAIT LOADING PARTS, SYSTEM SYNC DATABASE REPLICA, SYSTEM FLUSH DISTRIBUTED, dictGet ON db1.*, GRANT NAMED COLLECTION CONTROL ON db1");
|
||||
}
|
||||
|
||||
|
||||
|
@ -648,6 +648,7 @@
|
||||
M(677, THREAD_WAS_CANCELED) \
|
||||
M(678, IO_URING_INIT_FAILED) \
|
||||
M(679, IO_URING_SUBMIT_ERROR) \
|
||||
M(690, MIXED_ACCESS_PARAMETER_TYPES) \
|
||||
\
|
||||
M(999, KEEPER_EXCEPTION) \
|
||||
M(1000, POCO_EXCEPTION) \
|
||||
|
@ -48,7 +48,7 @@ namespace
|
||||
if (current_query)
|
||||
{
|
||||
const auto & prev_element = current_query->access_rights_elements.back();
|
||||
bool continue_with_current_query = element.sameDatabaseAndTable(prev_element) && element.sameOptions(prev_element);
|
||||
bool continue_with_current_query = element.sameDatabaseAndTableAndParameter(prev_element) && element.sameOptions(prev_element);
|
||||
if (!continue_with_current_query)
|
||||
current_query = nullptr;
|
||||
}
|
||||
|
@ -12,9 +12,10 @@ namespace DB
|
||||
BlockIO InterpreterAlterNamedCollectionQuery::execute()
|
||||
{
|
||||
auto current_context = getContext();
|
||||
current_context->checkAccess(AccessType::ALTER_NAMED_COLLECTION);
|
||||
|
||||
const auto & query = query_ptr->as<const ASTAlterNamedCollectionQuery &>();
|
||||
|
||||
current_context->checkAccess(AccessType::ALTER_NAMED_COLLECTION, query.collection_name);
|
||||
|
||||
if (!query.cluster.empty())
|
||||
{
|
||||
DDLQueryOnClusterParams params;
|
||||
|
@ -13,10 +13,10 @@ namespace DB
|
||||
BlockIO InterpreterCreateNamedCollectionQuery::execute()
|
||||
{
|
||||
auto current_context = getContext();
|
||||
current_context->checkAccess(AccessType::CREATE_NAMED_COLLECTION);
|
||||
|
||||
const auto & query = query_ptr->as<const ASTCreateNamedCollectionQuery &>();
|
||||
|
||||
current_context->checkAccess(AccessType::CREATE_NAMED_COLLECTION, query.collection_name);
|
||||
|
||||
if (!query.cluster.empty())
|
||||
{
|
||||
DDLQueryOnClusterParams params;
|
||||
|
@ -12,9 +12,10 @@ namespace DB
|
||||
BlockIO InterpreterDropNamedCollectionQuery::execute()
|
||||
{
|
||||
auto current_context = getContext();
|
||||
current_context->checkAccess(AccessType::DROP_NAMED_COLLECTION);
|
||||
|
||||
const auto & query = query_ptr->as<const ASTDropNamedCollectionQuery &>();
|
||||
|
||||
current_context->checkAccess(AccessType::DROP_NAMED_COLLECTION, query.collection_name);
|
||||
|
||||
if (!query.cluster.empty())
|
||||
{
|
||||
DDLQueryOnClusterParams params;
|
||||
|
@ -27,21 +27,28 @@ namespace
|
||||
}
|
||||
|
||||
|
||||
void formatONClause(const String & database, bool any_database, const String & table, bool any_table, const IAST::FormatSettings & settings)
|
||||
void formatONClause(const AccessRightsElement & element, const IAST::FormatSettings & settings)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << "ON " << (settings.hilite ? IAST::hilite_none : "");
|
||||
if (any_database)
|
||||
if (element.isGlobalWithParameter())
|
||||
{
|
||||
if (element.any_parameter)
|
||||
settings.ostr << "*";
|
||||
else
|
||||
settings.ostr << backQuoteIfNeed(element.parameter);
|
||||
}
|
||||
else if (element.any_database)
|
||||
{
|
||||
settings.ostr << "*.*";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!database.empty())
|
||||
settings.ostr << backQuoteIfNeed(database) << ".";
|
||||
if (any_table)
|
||||
if (!element.database.empty())
|
||||
settings.ostr << backQuoteIfNeed(element.database) << ".";
|
||||
if (element.any_table)
|
||||
settings.ostr << "*";
|
||||
else
|
||||
settings.ostr << backQuoteIfNeed(table);
|
||||
settings.ostr << backQuoteIfNeed(element.table);
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,15 +77,16 @@ namespace
|
||||
if (i != elements.size() - 1)
|
||||
{
|
||||
const auto & next_element = elements[i + 1];
|
||||
if ((element.database == next_element.database) && (element.any_database == next_element.any_database)
|
||||
&& (element.table == next_element.table) && (element.any_table == next_element.any_table))
|
||||
if (element.sameDatabaseAndTableAndParameter(next_element))
|
||||
{
|
||||
next_element_on_same_db_and_table = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!next_element_on_same_db_and_table)
|
||||
{
|
||||
settings.ostr << " ";
|
||||
formatONClause(element.database, element.any_database, element.table, element.any_table, settings);
|
||||
formatONClause(element, settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,13 +123,40 @@ namespace
|
||||
if (!parseAccessFlagsWithColumns(pos, expected, access_and_columns))
|
||||
return false;
|
||||
|
||||
String database_name, table_name, parameter;
|
||||
bool any_database = false, any_table = false, any_parameter = false;
|
||||
|
||||
size_t is_global_with_parameter = 0;
|
||||
for (const auto & elem : access_and_columns)
|
||||
{
|
||||
if (elem.first.isGlobalWithParameter())
|
||||
++is_global_with_parameter;
|
||||
}
|
||||
|
||||
if (!ParserKeyword{"ON"}.ignore(pos, expected))
|
||||
return false;
|
||||
|
||||
String database_name, table_name;
|
||||
bool any_database = false, any_table = false;
|
||||
if (!parseDatabaseAndTableNameOrAsterisks(pos, expected, database_name, any_database, table_name, any_table))
|
||||
if (is_global_with_parameter && is_global_with_parameter == access_and_columns.size())
|
||||
{
|
||||
ASTPtr parameter_ast;
|
||||
if (ParserToken{TokenType::Asterisk}.ignore(pos, expected))
|
||||
{
|
||||
any_parameter = true;
|
||||
}
|
||||
else if (ParserIdentifier{}.parse(pos, parameter_ast, expected))
|
||||
{
|
||||
any_parameter = false;
|
||||
parameter = getIdentifierName(parameter_ast);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
any_database = any_table = true;
|
||||
}
|
||||
else if (!parseDatabaseAndTableNameOrAsterisks(pos, expected, database_name, any_database, table_name, any_table))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto & [access_flags, columns] : access_and_columns)
|
||||
{
|
||||
@ -140,7 +167,9 @@ namespace
|
||||
element.any_database = any_database;
|
||||
element.database = database_name;
|
||||
element.any_table = any_table;
|
||||
element.any_parameter = any_parameter;
|
||||
element.table = table_name;
|
||||
element.parameter = parameter;
|
||||
res_elements.emplace_back(std::move(element));
|
||||
}
|
||||
|
||||
@ -173,6 +202,8 @@ namespace
|
||||
throw Exception(ErrorCodes::INVALID_GRANT, "{} cannot be granted on the table level", old_flags.toString());
|
||||
else if (!element.any_database)
|
||||
throw Exception(ErrorCodes::INVALID_GRANT, "{} cannot be granted on the database level", old_flags.toString());
|
||||
else if (!element.any_parameter)
|
||||
throw Exception(ErrorCodes::INVALID_GRANT, "{} cannot be granted on the global with parameter level", old_flags.toString());
|
||||
else
|
||||
throw Exception(ErrorCodes::INVALID_GRANT, "{} cannot be granted", old_flags.toString());
|
||||
});
|
||||
|
@ -7,9 +7,9 @@
|
||||
#include <Interpreters/ProfileEventsExt.h>
|
||||
#include <Access/Common/AccessType.h>
|
||||
#include <Access/Common/AccessFlags.h>
|
||||
#include <Access/ContextAccess.h>
|
||||
#include <Columns/ColumnMap.h>
|
||||
#include <Common/NamedCollections/NamedCollections.h>
|
||||
#include <Access/ContextAccess.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
@ -30,7 +30,6 @@ StorageSystemNamedCollections::StorageSystemNamedCollections(const StorageID & t
|
||||
|
||||
void StorageSystemNamedCollections::fillData(MutableColumns & res_columns, ContextPtr context, const SelectQueryInfo &) const
|
||||
{
|
||||
context->checkAccess(AccessType::SHOW_NAMED_COLLECTIONS);
|
||||
const auto & access = context->getAccess();
|
||||
|
||||
NamedCollectionUtils::loadIfNot();
|
||||
@ -38,6 +37,9 @@ void StorageSystemNamedCollections::fillData(MutableColumns & res_columns, Conte
|
||||
auto collections = NamedCollectionFactory::instance().getAll();
|
||||
for (const auto & [name, collection] : collections)
|
||||
{
|
||||
if (!access->isGranted(AccessType::SHOW_NAMED_COLLECTIONS, name))
|
||||
continue;
|
||||
|
||||
res_columns[0]->insert(name);
|
||||
|
||||
auto * column_map = typeid_cast<ColumnMap *>(res_columns[1].get());
|
||||
|
@ -28,6 +28,7 @@ namespace
|
||||
DICTIONARY,
|
||||
VIEW,
|
||||
COLUMN,
|
||||
NAMED_COLLECTION,
|
||||
};
|
||||
|
||||
DataTypeEnum8::Values getLevelEnumValues()
|
||||
@ -39,6 +40,7 @@ namespace
|
||||
enum_values.emplace_back("DICTIONARY", static_cast<Int8>(DICTIONARY));
|
||||
enum_values.emplace_back("VIEW", static_cast<Int8>(VIEW));
|
||||
enum_values.emplace_back("COLUMN", static_cast<Int8>(COLUMN));
|
||||
enum_values.emplace_back("NAMED_COLLECTION", static_cast<Int8>(NAMED_COLLECTION));
|
||||
return enum_values;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<users>
|
||||
<default>
|
||||
<access_management>1</access_management>
|
||||
<show_named_collections>1</show_named_collections>
|
||||
<named_collection_control>1</named_collection_control>
|
||||
<show_named_collections_secrets>1</show_named_collections_secrets>
|
||||
</default>
|
||||
</users>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<password></password>
|
||||
<profile>default</profile>
|
||||
<quota>default</quota>
|
||||
<show_named_collections>1</show_named_collections>
|
||||
<named_collection_control>1</named_collection_control>
|
||||
<show_named_collections_secrets>1</show_named_collections_secrets>
|
||||
</default>
|
||||
</users>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<password></password>
|
||||
<profile>default</profile>
|
||||
<quota>default</quota>
|
||||
<show_named_collections>1</show_named_collections>
|
||||
<named_collection_control>1</named_collection_control>
|
||||
<show_named_collections_secrets>1</show_named_collections_secrets>
|
||||
</default>
|
||||
</users>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<password></password>
|
||||
<profile>default</profile>
|
||||
<quota>default</quota>
|
||||
<show_named_collections>1</show_named_collections>
|
||||
<named_collection_control>1</named_collection_control>
|
||||
<show_named_collections_secrets>1</show_named_collections_secrets>
|
||||
</default>
|
||||
</users>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<password></password>
|
||||
<profile>default</profile>
|
||||
<quota>default</quota>
|
||||
<show_named_collections>1</show_named_collections>
|
||||
<named_collection_control>1</named_collection_control>
|
||||
<show_named_collections_secrets>1</show_named_collections_secrets>
|
||||
</default>
|
||||
</users>
|
||||
|
@ -402,6 +402,9 @@ def test_introspection():
|
||||
assert instance.query("SHOW GRANTS FOR B") == TSV(
|
||||
["GRANT CREATE ON *.* TO B WITH GRANT OPTION"]
|
||||
)
|
||||
assert instance.query("SHOW GRANTS FOR default") == TSV(
|
||||
["GRANT ALL ON *.* TO default WITH GRANT OPTION"]
|
||||
)
|
||||
assert instance.query("SHOW GRANTS FOR A,B") == TSV(
|
||||
[
|
||||
"GRANT SELECT ON test.table TO A",
|
||||
|
@ -4,6 +4,7 @@
|
||||
<password></password>
|
||||
<profile>default</profile>
|
||||
<quota>default</quota>
|
||||
<named_collection_control>1</named_collection_control>
|
||||
<show_named_collections>1</show_named_collections>
|
||||
<show_named_collections_secrets>1</show_named_collections_secrets>
|
||||
</default>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<password></password>
|
||||
<profile>default</profile>
|
||||
<quota>default</quota>
|
||||
<access_management>1</access_management>
|
||||
<named_collection_control>1</named_collection_control>
|
||||
</default>
|
||||
</users>
|
||||
</clickhouse>
|
@ -24,6 +24,16 @@ def cluster():
|
||||
],
|
||||
stay_alive=True,
|
||||
)
|
||||
cluster.add_instance(
|
||||
"node_only_named_collection_control",
|
||||
main_configs=[
|
||||
"configs/config.d/named_collections.xml",
|
||||
],
|
||||
user_configs=[
|
||||
"configs/users.d/users_only_named_collection_control.xml",
|
||||
],
|
||||
stay_alive=True,
|
||||
)
|
||||
cluster.add_instance(
|
||||
"node_no_default_access",
|
||||
main_configs=[
|
||||
@ -34,16 +44,6 @@ def cluster():
|
||||
],
|
||||
stay_alive=True,
|
||||
)
|
||||
cluster.add_instance(
|
||||
"node_no_default_access_but_with_access_management",
|
||||
main_configs=[
|
||||
"configs/config.d/named_collections.xml",
|
||||
],
|
||||
user_configs=[
|
||||
"configs/users.d/users_no_default_access_with_access_management.xml",
|
||||
],
|
||||
stay_alive=True,
|
||||
)
|
||||
|
||||
logging.info("Starting cluster...")
|
||||
cluster.start()
|
||||
@ -70,40 +70,39 @@ def replace_in_users_config(node, old, new):
|
||||
)
|
||||
|
||||
|
||||
def test_access(cluster):
|
||||
def test_default_access(cluster):
|
||||
node = cluster.instances["node_no_default_access"]
|
||||
assert 0 == int(node.query("select count() from system.named_collections"))
|
||||
node = cluster.instances["node_only_named_collection_control"]
|
||||
assert 1 == int(node.query("select count() from system.named_collections"))
|
||||
assert (
|
||||
"DB::Exception: default: Not enough privileges. To execute this query it's necessary to have grant SHOW NAMED COLLECTIONS ON *.*"
|
||||
in node.query_and_get_error("select count() from system.named_collections")
|
||||
)
|
||||
node = cluster.instances["node_no_default_access_but_with_access_management"]
|
||||
assert (
|
||||
"DB::Exception: default: Not enough privileges. To execute this query it's necessary to have grant SHOW NAMED COLLECTIONS ON *.*"
|
||||
in node.query_and_get_error("select count() from system.named_collections")
|
||||
node.query("select collection['key1'] from system.named_collections").strip()
|
||||
== "[HIDDEN]"
|
||||
)
|
||||
|
||||
node = cluster.instances["node"]
|
||||
assert int(node.query("select count() from system.named_collections")) > 0
|
||||
|
||||
replace_in_users_config(
|
||||
node, "show_named_collections>1", "show_named_collections>0"
|
||||
node, "named_collection_control>1", "named_collection_control>0"
|
||||
)
|
||||
assert "show_named_collections>0" in node.exec_in_container(
|
||||
assert "named_collection_control>0" in node.exec_in_container(
|
||||
["bash", "-c", f"cat /etc/clickhouse-server/users.d/users.xml"]
|
||||
)
|
||||
node.restart_clickhouse()
|
||||
assert 0 == int(node.query("select count() from system.named_collections"))
|
||||
|
||||
replace_in_users_config(
|
||||
node, "named_collection_control>0", "named_collection_control>1"
|
||||
)
|
||||
assert "named_collection_control>1" in node.exec_in_container(
|
||||
["bash", "-c", f"cat /etc/clickhouse-server/users.d/users.xml"]
|
||||
)
|
||||
node.restart_clickhouse()
|
||||
assert (
|
||||
"DB::Exception: default: Not enough privileges. To execute this query it's necessary to have grant SHOW NAMED COLLECTIONS ON *.*"
|
||||
in node.query_and_get_error("select count() from system.named_collections")
|
||||
)
|
||||
replace_in_users_config(
|
||||
node, "show_named_collections>0", "show_named_collections>1"
|
||||
)
|
||||
assert "show_named_collections>1" in node.exec_in_container(
|
||||
["bash", "-c", f"cat /etc/clickhouse-server/users.d/users.xml"]
|
||||
)
|
||||
node.restart_clickhouse()
|
||||
assert (
|
||||
node.query("select collection['key1'] from system.named_collections").strip()
|
||||
node.query(
|
||||
"select collection['key1'] from system.named_collections where name = 'collection1'"
|
||||
).strip()
|
||||
== "value1"
|
||||
)
|
||||
replace_in_users_config(
|
||||
@ -114,7 +113,9 @@ def test_access(cluster):
|
||||
)
|
||||
node.restart_clickhouse()
|
||||
assert (
|
||||
node.query("select collection['key1'] from system.named_collections").strip()
|
||||
node.query(
|
||||
"select collection['key1'] from system.named_collections where name = 'collection1'"
|
||||
).strip()
|
||||
== "[HIDDEN]"
|
||||
)
|
||||
replace_in_users_config(
|
||||
@ -125,11 +126,282 @@ def test_access(cluster):
|
||||
)
|
||||
node.restart_clickhouse()
|
||||
assert (
|
||||
node.query("select collection['key1'] from system.named_collections").strip()
|
||||
node.query(
|
||||
"select collection['key1'] from system.named_collections where name = 'collection1'"
|
||||
).strip()
|
||||
== "value1"
|
||||
)
|
||||
|
||||
|
||||
def test_granular_access_show_query(cluster):
|
||||
node = cluster.instances["node"]
|
||||
assert (
|
||||
"GRANT ALL ON *.* TO default WITH GRANT OPTION"
|
||||
== node.query("SHOW GRANTS FOR default").strip()
|
||||
) # includes named collections control
|
||||
assert 1 == int(node.query("SELECT count() FROM system.named_collections"))
|
||||
assert (
|
||||
"collection1" == node.query("SELECT name FROM system.named_collections").strip()
|
||||
)
|
||||
|
||||
node.query("DROP USER IF EXISTS kek")
|
||||
node.query("CREATE USER kek")
|
||||
node.query("GRANT select ON *.* TO kek")
|
||||
assert 0 == int(
|
||||
node.query("SELECT count() FROM system.named_collections", user="kek")
|
||||
)
|
||||
|
||||
node.query("GRANT show named collections ON collection1 TO kek")
|
||||
assert 1 == int(
|
||||
node.query("SELECT count() FROM system.named_collections", user="kek")
|
||||
)
|
||||
assert (
|
||||
"collection1"
|
||||
== node.query("SELECT name FROM system.named_collections", user="kek").strip()
|
||||
)
|
||||
|
||||
node.query("CREATE NAMED COLLECTION collection2 AS key1=1, key2='value2'")
|
||||
assert 2 == int(node.query("SELECT count() FROM system.named_collections"))
|
||||
assert (
|
||||
"collection1\ncollection2"
|
||||
== node.query("select name from system.named_collections").strip()
|
||||
)
|
||||
|
||||
assert 1 == int(
|
||||
node.query("SELECT count() FROM system.named_collections", user="kek")
|
||||
)
|
||||
assert (
|
||||
"collection1"
|
||||
== node.query("select name from system.named_collections", user="kek").strip()
|
||||
)
|
||||
|
||||
node.query("GRANT show named collections ON collection2 TO kek")
|
||||
assert 2 == int(
|
||||
node.query("SELECT count() FROM system.named_collections", user="kek")
|
||||
)
|
||||
assert (
|
||||
"collection1\ncollection2"
|
||||
== node.query("select name from system.named_collections", user="kek").strip()
|
||||
)
|
||||
node.restart_clickhouse()
|
||||
assert (
|
||||
"collection1\ncollection2"
|
||||
== node.query("select name from system.named_collections", user="kek").strip()
|
||||
)
|
||||
|
||||
# check:
|
||||
# GRANT show named collections ON *
|
||||
# REVOKE show named collections ON collection
|
||||
|
||||
node.query("DROP USER IF EXISTS koko")
|
||||
node.query("CREATE USER koko")
|
||||
node.query("GRANT select ON *.* TO koko")
|
||||
assert 0 == int(
|
||||
node.query("SELECT count() FROM system.named_collections", user="koko")
|
||||
)
|
||||
assert "GRANT SELECT ON *.* TO koko" == node.query("SHOW GRANTS FOR koko;").strip()
|
||||
node.query("GRANT show named collections ON * TO koko")
|
||||
assert (
|
||||
"GRANT SELECT ON *.* TO koko\nGRANT SHOW NAMED COLLECTIONS ON * TO koko"
|
||||
== node.query("SHOW GRANTS FOR koko;").strip()
|
||||
)
|
||||
assert (
|
||||
"collection1\ncollection2"
|
||||
== node.query("select name from system.named_collections", user="koko").strip()
|
||||
)
|
||||
node.restart_clickhouse()
|
||||
assert (
|
||||
"GRANT SELECT ON *.* TO koko\nGRANT SHOW NAMED COLLECTIONS ON * TO koko"
|
||||
== node.query("SHOW GRANTS FOR koko;").strip()
|
||||
)
|
||||
assert (
|
||||
"collection1\ncollection2"
|
||||
== node.query("select name from system.named_collections", user="koko").strip()
|
||||
)
|
||||
|
||||
node.query("REVOKE show named collections ON collection1 FROM koko;")
|
||||
assert (
|
||||
"GRANT SELECT ON *.* TO koko\nGRANT SHOW NAMED COLLECTIONS ON * TO koko\nREVOKE SHOW NAMED COLLECTIONS ON collection1 FROM koko"
|
||||
== node.query("SHOW GRANTS FOR koko;").strip()
|
||||
)
|
||||
assert (
|
||||
"collection2"
|
||||
== node.query("select name from system.named_collections", user="koko").strip()
|
||||
)
|
||||
node.restart_clickhouse()
|
||||
assert (
|
||||
"GRANT SELECT ON *.* TO koko\nGRANT SHOW NAMED COLLECTIONS ON * TO koko\nREVOKE SHOW NAMED COLLECTIONS ON collection1 FROM koko"
|
||||
== node.query("SHOW GRANTS FOR koko;").strip()
|
||||
)
|
||||
assert (
|
||||
"collection2"
|
||||
== node.query("select name from system.named_collections", user="koko").strip()
|
||||
)
|
||||
node.query("REVOKE show named collections ON collection2 FROM koko;")
|
||||
assert (
|
||||
"" == node.query("select * from system.named_collections", user="koko").strip()
|
||||
)
|
||||
assert (
|
||||
"GRANT SELECT ON *.* TO koko\nGRANT SHOW NAMED COLLECTIONS ON * TO koko\nREVOKE SHOW NAMED COLLECTIONS ON collection1 FROM koko\nREVOKE SHOW NAMED COLLECTIONS ON collection2 FROM koko"
|
||||
== node.query("SHOW GRANTS FOR koko;").strip()
|
||||
)
|
||||
|
||||
# check:
|
||||
# GRANT show named collections ON collection
|
||||
# REVOKE show named collections ON *
|
||||
|
||||
node.query("GRANT show named collections ON collection2 TO koko")
|
||||
assert (
|
||||
"GRANT SELECT ON *.* TO koko\nGRANT SHOW NAMED COLLECTIONS ON * TO koko\nREVOKE SHOW NAMED COLLECTIONS ON collection1 FROM koko"
|
||||
== node.query("SHOW GRANTS FOR koko;").strip()
|
||||
)
|
||||
assert (
|
||||
"collection2"
|
||||
== node.query("select name from system.named_collections", user="koko").strip()
|
||||
)
|
||||
node.query("REVOKE show named collections ON * FROM koko;")
|
||||
assert "GRANT SELECT ON *.* TO koko" == node.query("SHOW GRANTS FOR koko;").strip()
|
||||
assert (
|
||||
"" == node.query("select * from system.named_collections", user="koko").strip()
|
||||
)
|
||||
|
||||
node.query("DROP NAMED COLLECTION collection2")
|
||||
|
||||
|
||||
def test_show_grants(cluster):
|
||||
node = cluster.instances["node"]
|
||||
node.query("DROP USER IF EXISTS koko")
|
||||
node.query("CREATE USER koko")
|
||||
node.query("GRANT CREATE NAMED COLLECTION ON name1 TO koko")
|
||||
node.query("GRANT select ON name1.* TO koko")
|
||||
assert (
|
||||
"GRANT SELECT ON name1.* TO koko\nGRANT CREATE NAMED COLLECTION ON name1 TO koko"
|
||||
== node.query("SHOW GRANTS FOR koko;").strip()
|
||||
)
|
||||
|
||||
node.query("DROP USER IF EXISTS koko")
|
||||
node.query("CREATE USER koko")
|
||||
node.query("GRANT CREATE NAMED COLLECTION ON name1 TO koko")
|
||||
node.query("GRANT select ON name1 TO koko")
|
||||
assert (
|
||||
"GRANT SELECT ON default.name1 TO koko\nGRANT CREATE NAMED COLLECTION ON name1 TO koko"
|
||||
== node.query("SHOW GRANTS FOR koko;").strip()
|
||||
)
|
||||
|
||||
node.query("DROP USER IF EXISTS koko")
|
||||
node.query("CREATE USER koko")
|
||||
node.query("GRANT select ON name1 TO koko")
|
||||
node.query("GRANT CREATE NAMED COLLECTION ON name1 TO koko")
|
||||
assert (
|
||||
"GRANT SELECT ON default.name1 TO koko\nGRANT CREATE NAMED COLLECTION ON name1 TO koko"
|
||||
== node.query("SHOW GRANTS FOR koko;").strip()
|
||||
)
|
||||
|
||||
node.query("DROP USER IF EXISTS koko")
|
||||
node.query("CREATE USER koko")
|
||||
node.query("GRANT select ON *.* TO koko")
|
||||
node.query("GRANT CREATE NAMED COLLECTION ON * TO koko")
|
||||
assert (
|
||||
"GRANT SELECT ON *.* TO koko\nGRANT CREATE NAMED COLLECTION ON * TO koko"
|
||||
== node.query("SHOW GRANTS FOR koko;").strip()
|
||||
)
|
||||
|
||||
node.query("DROP USER IF EXISTS koko")
|
||||
node.query("CREATE USER koko")
|
||||
node.query("GRANT CREATE NAMED COLLECTION ON * TO koko")
|
||||
node.query("GRANT select ON *.* TO koko")
|
||||
assert (
|
||||
"GRANT SELECT ON *.* TO koko\nGRANT CREATE NAMED COLLECTION ON * TO koko"
|
||||
== node.query("SHOW GRANTS FOR koko;").strip()
|
||||
)
|
||||
|
||||
node.query("DROP USER IF EXISTS koko")
|
||||
node.query("CREATE USER koko")
|
||||
node.query("GRANT CREATE NAMED COLLECTION ON * TO koko")
|
||||
node.query("GRANT select ON * TO koko")
|
||||
assert (
|
||||
"GRANT CREATE NAMED COLLECTION ON * TO koko\nGRANT SELECT ON default.* TO koko"
|
||||
== node.query("SHOW GRANTS FOR koko;").strip()
|
||||
)
|
||||
|
||||
node.query("DROP USER IF EXISTS koko")
|
||||
node.query("CREATE USER koko")
|
||||
node.query("GRANT select ON * TO koko")
|
||||
node.query("GRANT CREATE NAMED COLLECTION ON * TO koko")
|
||||
assert (
|
||||
"GRANT CREATE NAMED COLLECTION ON * TO koko\nGRANT SELECT ON default.* TO koko"
|
||||
== node.query("SHOW GRANTS FOR koko;").strip()
|
||||
)
|
||||
|
||||
|
||||
def test_granular_access_create_alter_drop_query(cluster):
|
||||
node = cluster.instances["node"]
|
||||
node.query("DROP USER IF EXISTS kek")
|
||||
node.query("CREATE USER kek")
|
||||
node.query("GRANT select ON *.* TO kek")
|
||||
assert 0 == int(
|
||||
node.query("SELECT count() FROM system.named_collections", user="kek")
|
||||
)
|
||||
|
||||
assert (
|
||||
"DB::Exception: kek: Not enough privileges. To execute this query it's necessary to have grant CREATE NAMED COLLECTION"
|
||||
in node.query_and_get_error(
|
||||
"CREATE NAMED COLLECTION collection2 AS key1=1, key2='value2'", user="kek"
|
||||
)
|
||||
)
|
||||
node.query("GRANT create named collection ON collection2 TO kek")
|
||||
node.query(
|
||||
"CREATE NAMED COLLECTION collection2 AS key1=1, key2='value2'", user="kek"
|
||||
)
|
||||
assert 0 == int(
|
||||
node.query("select count() from system.named_collections", user="kek")
|
||||
)
|
||||
|
||||
node.query("GRANT show named collections ON collection2 TO kek")
|
||||
assert (
|
||||
"collection2"
|
||||
== node.query("select name from system.named_collections", user="kek").strip()
|
||||
)
|
||||
assert (
|
||||
"1"
|
||||
== node.query(
|
||||
"select collection['key1'] from system.named_collections where name = 'collection2'"
|
||||
).strip()
|
||||
)
|
||||
|
||||
assert (
|
||||
"DB::Exception: kek: Not enough privileges. To execute this query it's necessary to have grant ALTER NAMED COLLECTION"
|
||||
in node.query_and_get_error(
|
||||
"ALTER NAMED COLLECTION collection2 SET key1=2", user="kek"
|
||||
)
|
||||
)
|
||||
node.query("GRANT alter named collection ON collection2 TO kek")
|
||||
node.query("ALTER NAMED COLLECTION collection2 SET key1=2", user="kek")
|
||||
assert (
|
||||
"2"
|
||||
== node.query(
|
||||
"select collection['key1'] from system.named_collections where name = 'collection2'"
|
||||
).strip()
|
||||
)
|
||||
node.query("REVOKE alter named collection ON collection2 FROM kek")
|
||||
assert (
|
||||
"DB::Exception: kek: Not enough privileges. To execute this query it's necessary to have grant ALTER NAMED COLLECTION"
|
||||
in node.query_and_get_error(
|
||||
"ALTER NAMED COLLECTION collection2 SET key1=3", user="kek"
|
||||
)
|
||||
)
|
||||
|
||||
assert (
|
||||
"DB::Exception: kek: Not enough privileges. To execute this query it's necessary to have grant DROP NAMED COLLECTION"
|
||||
in node.query_and_get_error("DROP NAMED COLLECTION collection2", user="kek")
|
||||
)
|
||||
node.query("GRANT drop named collection ON collection2 TO kek")
|
||||
node.query("DROP NAMED COLLECTION collection2", user="kek")
|
||||
assert 0 == int(
|
||||
node.query("select count() from system.named_collections", user="kek")
|
||||
)
|
||||
|
||||
|
||||
def test_config_reload(cluster):
|
||||
node = cluster.instances["node"]
|
||||
assert (
|
||||
@ -164,6 +436,16 @@ def test_config_reload(cluster):
|
||||
).strip()
|
||||
)
|
||||
|
||||
replace_in_server_config(node, "value2", "value1")
|
||||
node.query("SYSTEM RELOAD CONFIG")
|
||||
|
||||
assert (
|
||||
"value1"
|
||||
== node.query(
|
||||
"select collection['key1'] from system.named_collections where name = 'collection1'"
|
||||
).strip()
|
||||
)
|
||||
|
||||
|
||||
def test_sql_commands(cluster):
|
||||
node = cluster.instances["node"]
|
||||
|
@ -4,7 +4,7 @@
|
||||
<password></password>
|
||||
<profile>default</profile>
|
||||
<quota>default</quota>
|
||||
<show_named_collections>1</show_named_collections>
|
||||
<named_collection_control>1</named_collection_control>
|
||||
<show_named_collections_secrets>1</show_named_collections_secrets>
|
||||
</default>
|
||||
</users>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<password></password>
|
||||
<profile>default</profile>
|
||||
<quota>default</quota>
|
||||
<show_named_collections>1</show_named_collections>
|
||||
<named_collection_control>1</named_collection_control>
|
||||
<show_named_collections_secrets>1</show_named_collections_secrets>
|
||||
</default>
|
||||
</users>
|
||||
|
@ -39,7 +39,7 @@ ALTER MOVE PARTITION ['ALTER MOVE PART','MOVE PARTITION','MOVE PART'] TABLE ALTE
|
||||
ALTER FETCH PARTITION ['ALTER FETCH PART','FETCH PARTITION'] TABLE ALTER TABLE
|
||||
ALTER FREEZE PARTITION ['FREEZE PARTITION','UNFREEZE'] TABLE ALTER TABLE
|
||||
ALTER DATABASE SETTINGS ['ALTER DATABASE SETTING','ALTER MODIFY DATABASE SETTING','MODIFY DATABASE SETTING'] DATABASE ALTER DATABASE
|
||||
ALTER NAMED COLLECTION [] \N ALTER
|
||||
ALTER NAMED COLLECTION [] NAMED_COLLECTION NAMED COLLECTION CONTROL
|
||||
ALTER TABLE [] \N ALTER
|
||||
ALTER DATABASE [] \N ALTER
|
||||
ALTER VIEW REFRESH ['ALTER LIVE VIEW REFRESH','REFRESH VIEW'] VIEW ALTER VIEW
|
||||
@ -53,14 +53,14 @@ CREATE DICTIONARY [] DICTIONARY CREATE
|
||||
CREATE TEMPORARY TABLE [] GLOBAL CREATE ARBITRARY TEMPORARY TABLE
|
||||
CREATE ARBITRARY TEMPORARY TABLE [] GLOBAL CREATE
|
||||
CREATE FUNCTION [] GLOBAL CREATE
|
||||
CREATE NAMED COLLECTION [] GLOBAL CREATE
|
||||
CREATE NAMED COLLECTION [] NAMED_COLLECTION NAMED COLLECTION CONTROL
|
||||
CREATE [] \N ALL
|
||||
DROP DATABASE [] DATABASE DROP
|
||||
DROP TABLE [] TABLE DROP
|
||||
DROP VIEW [] VIEW DROP
|
||||
DROP DICTIONARY [] DICTIONARY DROP
|
||||
DROP FUNCTION [] GLOBAL DROP
|
||||
DROP NAMED COLLECTION [] GLOBAL DROP
|
||||
DROP NAMED COLLECTION [] NAMED_COLLECTION NAMED COLLECTION CONTROL
|
||||
DROP [] \N ALL
|
||||
TRUNCATE ['TRUNCATE TABLE'] TABLE ALL
|
||||
OPTIMIZE ['OPTIMIZE TABLE'] TABLE ALL
|
||||
@ -90,9 +90,10 @@ SHOW ROW POLICIES ['SHOW POLICIES','SHOW CREATE ROW POLICY','SHOW CREATE POLICY'
|
||||
SHOW QUOTAS ['SHOW CREATE QUOTA'] GLOBAL SHOW ACCESS
|
||||
SHOW SETTINGS PROFILES ['SHOW PROFILES','SHOW CREATE SETTINGS PROFILE','SHOW CREATE PROFILE'] GLOBAL SHOW ACCESS
|
||||
SHOW ACCESS [] \N ACCESS MANAGEMENT
|
||||
SHOW NAMED COLLECTIONS ['SHOW NAMED COLLECTIONS'] GLOBAL ACCESS MANAGEMENT
|
||||
SHOW NAMED COLLECTIONS SECRETS ['SHOW NAMED COLLECTIONS SECRETS'] GLOBAL ACCESS MANAGEMENT
|
||||
ACCESS MANAGEMENT [] \N ALL
|
||||
SHOW NAMED COLLECTIONS ['SHOW NAMED COLLECTIONS'] NAMED_COLLECTION NAMED COLLECTION CONTROL
|
||||
SHOW NAMED COLLECTIONS SECRETS ['SHOW NAMED COLLECTIONS SECRETS'] NAMED_COLLECTION NAMED COLLECTION CONTROL
|
||||
NAMED COLLECTION CONTROL [] NAMED_COLLECTION ALL
|
||||
SYSTEM SHUTDOWN ['SYSTEM KILL','SHUTDOWN'] GLOBAL SYSTEM
|
||||
SYSTEM DROP DNS CACHE ['SYSTEM DROP DNS','DROP DNS CACHE','DROP DNS'] GLOBAL SYSTEM DROP CACHE
|
||||
SYSTEM DROP MARK CACHE ['SYSTEM DROP MARK','DROP MARK CACHE','DROP MARKS'] GLOBAL SYSTEM DROP CACHE
|
||||
|
@ -289,7 +289,7 @@ CREATE TABLE system.grants
|
||||
(
|
||||
`user_name` Nullable(String),
|
||||
`role_name` Nullable(String),
|
||||
`access_type` Enum16('SHOW DATABASES' = 0, 'SHOW TABLES' = 1, 'SHOW COLUMNS' = 2, 'SHOW DICTIONARIES' = 3, 'SHOW' = 4, 'SHOW FILESYSTEM CACHES' = 5, 'SELECT' = 6, 'INSERT' = 7, 'ALTER UPDATE' = 8, 'ALTER DELETE' = 9, 'ALTER ADD COLUMN' = 10, 'ALTER MODIFY COLUMN' = 11, 'ALTER DROP COLUMN' = 12, 'ALTER COMMENT COLUMN' = 13, 'ALTER CLEAR COLUMN' = 14, 'ALTER RENAME COLUMN' = 15, 'ALTER MATERIALIZE COLUMN' = 16, 'ALTER COLUMN' = 17, 'ALTER MODIFY COMMENT' = 18, 'ALTER ORDER BY' = 19, 'ALTER SAMPLE BY' = 20, 'ALTER ADD INDEX' = 21, 'ALTER DROP INDEX' = 22, 'ALTER MATERIALIZE INDEX' = 23, 'ALTER CLEAR INDEX' = 24, 'ALTER INDEX' = 25, 'ALTER ADD PROJECTION' = 26, 'ALTER DROP PROJECTION' = 27, 'ALTER MATERIALIZE PROJECTION' = 28, 'ALTER CLEAR PROJECTION' = 29, 'ALTER PROJECTION' = 30, 'ALTER ADD CONSTRAINT' = 31, 'ALTER DROP CONSTRAINT' = 32, 'ALTER CONSTRAINT' = 33, 'ALTER TTL' = 34, 'ALTER MATERIALIZE TTL' = 35, 'ALTER SETTINGS' = 36, 'ALTER MOVE PARTITION' = 37, 'ALTER FETCH PARTITION' = 38, 'ALTER FREEZE PARTITION' = 39, 'ALTER DATABASE SETTINGS' = 40, 'ALTER NAMED COLLECTION' = 41, 'ALTER TABLE' = 42, 'ALTER DATABASE' = 43, 'ALTER VIEW REFRESH' = 44, 'ALTER VIEW MODIFY QUERY' = 45, 'ALTER VIEW' = 46, 'ALTER' = 47, 'CREATE DATABASE' = 48, 'CREATE TABLE' = 49, 'CREATE VIEW' = 50, 'CREATE DICTIONARY' = 51, 'CREATE TEMPORARY TABLE' = 52, 'CREATE ARBITRARY TEMPORARY TABLE' = 53, 'CREATE FUNCTION' = 54, 'CREATE NAMED COLLECTION' = 55, 'CREATE' = 56, 'DROP DATABASE' = 57, 'DROP TABLE' = 58, 'DROP VIEW' = 59, 'DROP DICTIONARY' = 60, 'DROP FUNCTION' = 61, 'DROP NAMED COLLECTION' = 62, 'DROP' = 63, 'TRUNCATE' = 64, 'OPTIMIZE' = 65, 'BACKUP' = 66, 'KILL QUERY' = 67, 'KILL TRANSACTION' = 68, 'MOVE PARTITION BETWEEN SHARDS' = 69, 'CREATE USER' = 70, 'ALTER USER' = 71, 'DROP USER' = 72, 'CREATE ROLE' = 73, 'ALTER ROLE' = 74, 'DROP ROLE' = 75, 'ROLE ADMIN' = 76, 'CREATE ROW POLICY' = 77, 'ALTER ROW POLICY' = 78, 'DROP ROW POLICY' = 79, 'CREATE QUOTA' = 80, 'ALTER QUOTA' = 81, 'DROP QUOTA' = 82, 'CREATE SETTINGS PROFILE' = 83, 'ALTER SETTINGS PROFILE' = 84, 'DROP SETTINGS PROFILE' = 85, 'SHOW USERS' = 86, 'SHOW ROLES' = 87, 'SHOW ROW POLICIES' = 88, 'SHOW QUOTAS' = 89, 'SHOW SETTINGS PROFILES' = 90, 'SHOW ACCESS' = 91, 'SHOW NAMED COLLECTIONS' = 92, 'SHOW NAMED COLLECTIONS SECRETS' = 93, 'ACCESS MANAGEMENT' = 94, 'SYSTEM SHUTDOWN' = 95, 'SYSTEM DROP DNS CACHE' = 96, 'SYSTEM DROP MARK CACHE' = 97, 'SYSTEM DROP UNCOMPRESSED CACHE' = 98, 'SYSTEM DROP MMAP CACHE' = 99, 'SYSTEM DROP QUERY CACHE' = 100, 'SYSTEM DROP COMPILED EXPRESSION CACHE' = 101, 'SYSTEM DROP FILESYSTEM CACHE' = 102, 'SYSTEM DROP SCHEMA CACHE' = 103, 'SYSTEM DROP S3 CLIENT CACHE' = 104, 'SYSTEM DROP CACHE' = 105, 'SYSTEM RELOAD CONFIG' = 106, 'SYSTEM RELOAD USERS' = 107, 'SYSTEM RELOAD SYMBOLS' = 108, 'SYSTEM RELOAD DICTIONARY' = 109, 'SYSTEM RELOAD MODEL' = 110, 'SYSTEM RELOAD FUNCTION' = 111, 'SYSTEM RELOAD EMBEDDED DICTIONARIES' = 112, 'SYSTEM RELOAD' = 113, 'SYSTEM RESTART DISK' = 114, 'SYSTEM MERGES' = 115, 'SYSTEM TTL MERGES' = 116, 'SYSTEM FETCHES' = 117, 'SYSTEM MOVES' = 118, 'SYSTEM DISTRIBUTED SENDS' = 119, 'SYSTEM REPLICATED SENDS' = 120, 'SYSTEM SENDS' = 121, 'SYSTEM REPLICATION QUEUES' = 122, 'SYSTEM DROP REPLICA' = 123, 'SYSTEM SYNC REPLICA' = 124, 'SYSTEM RESTART REPLICA' = 125, 'SYSTEM RESTORE REPLICA' = 126, 'SYSTEM WAIT LOADING PARTS' = 127, 'SYSTEM SYNC DATABASE REPLICA' = 128, 'SYSTEM SYNC TRANSACTION LOG' = 129, 'SYSTEM SYNC FILE CACHE' = 130, 'SYSTEM FLUSH DISTRIBUTED' = 131, 'SYSTEM FLUSH LOGS' = 132, 'SYSTEM FLUSH' = 133, 'SYSTEM THREAD FUZZER' = 134, 'SYSTEM UNFREEZE' = 135, 'SYSTEM' = 136, 'dictGet' = 137, 'addressToLine' = 138, 'addressToLineWithInlines' = 139, 'addressToSymbol' = 140, 'demangle' = 141, 'INTROSPECTION' = 142, 'FILE' = 143, 'URL' = 144, 'REMOTE' = 145, 'MONGO' = 146, 'MEILISEARCH' = 147, 'MYSQL' = 148, 'POSTGRES' = 149, 'SQLITE' = 150, 'ODBC' = 151, 'JDBC' = 152, 'HDFS' = 153, 'S3' = 154, 'HIVE' = 155, 'SOURCES' = 156, 'CLUSTER' = 157, 'ALL' = 158, 'NONE' = 159),
|
||||
`access_type` Enum16('SHOW DATABASES' = 0, 'SHOW TABLES' = 1, 'SHOW COLUMNS' = 2, 'SHOW DICTIONARIES' = 3, 'SHOW' = 4, 'SHOW FILESYSTEM CACHES' = 5, 'SELECT' = 6, 'INSERT' = 7, 'ALTER UPDATE' = 8, 'ALTER DELETE' = 9, 'ALTER ADD COLUMN' = 10, 'ALTER MODIFY COLUMN' = 11, 'ALTER DROP COLUMN' = 12, 'ALTER COMMENT COLUMN' = 13, 'ALTER CLEAR COLUMN' = 14, 'ALTER RENAME COLUMN' = 15, 'ALTER MATERIALIZE COLUMN' = 16, 'ALTER COLUMN' = 17, 'ALTER MODIFY COMMENT' = 18, 'ALTER ORDER BY' = 19, 'ALTER SAMPLE BY' = 20, 'ALTER ADD INDEX' = 21, 'ALTER DROP INDEX' = 22, 'ALTER MATERIALIZE INDEX' = 23, 'ALTER CLEAR INDEX' = 24, 'ALTER INDEX' = 25, 'ALTER ADD PROJECTION' = 26, 'ALTER DROP PROJECTION' = 27, 'ALTER MATERIALIZE PROJECTION' = 28, 'ALTER CLEAR PROJECTION' = 29, 'ALTER PROJECTION' = 30, 'ALTER ADD CONSTRAINT' = 31, 'ALTER DROP CONSTRAINT' = 32, 'ALTER CONSTRAINT' = 33, 'ALTER TTL' = 34, 'ALTER MATERIALIZE TTL' = 35, 'ALTER SETTINGS' = 36, 'ALTER MOVE PARTITION' = 37, 'ALTER FETCH PARTITION' = 38, 'ALTER FREEZE PARTITION' = 39, 'ALTER DATABASE SETTINGS' = 40, 'ALTER NAMED COLLECTION' = 41, 'ALTER TABLE' = 42, 'ALTER DATABASE' = 43, 'ALTER VIEW REFRESH' = 44, 'ALTER VIEW MODIFY QUERY' = 45, 'ALTER VIEW' = 46, 'ALTER' = 47, 'CREATE DATABASE' = 48, 'CREATE TABLE' = 49, 'CREATE VIEW' = 50, 'CREATE DICTIONARY' = 51, 'CREATE TEMPORARY TABLE' = 52, 'CREATE ARBITRARY TEMPORARY TABLE' = 53, 'CREATE FUNCTION' = 54, 'CREATE NAMED COLLECTION' = 55, 'CREATE' = 56, 'DROP DATABASE' = 57, 'DROP TABLE' = 58, 'DROP VIEW' = 59, 'DROP DICTIONARY' = 60, 'DROP FUNCTION' = 61, 'DROP NAMED COLLECTION' = 62, 'DROP' = 63, 'TRUNCATE' = 64, 'OPTIMIZE' = 65, 'BACKUP' = 66, 'KILL QUERY' = 67, 'KILL TRANSACTION' = 68, 'MOVE PARTITION BETWEEN SHARDS' = 69, 'CREATE USER' = 70, 'ALTER USER' = 71, 'DROP USER' = 72, 'CREATE ROLE' = 73, 'ALTER ROLE' = 74, 'DROP ROLE' = 75, 'ROLE ADMIN' = 76, 'CREATE ROW POLICY' = 77, 'ALTER ROW POLICY' = 78, 'DROP ROW POLICY' = 79, 'CREATE QUOTA' = 80, 'ALTER QUOTA' = 81, 'DROP QUOTA' = 82, 'CREATE SETTINGS PROFILE' = 83, 'ALTER SETTINGS PROFILE' = 84, 'DROP SETTINGS PROFILE' = 85, 'SHOW USERS' = 86, 'SHOW ROLES' = 87, 'SHOW ROW POLICIES' = 88, 'SHOW QUOTAS' = 89, 'SHOW SETTINGS PROFILES' = 90, 'SHOW ACCESS' = 91, 'ACCESS MANAGEMENT' = 92, 'SHOW NAMED COLLECTIONS' = 93, 'SHOW NAMED COLLECTIONS SECRETS' = 94, 'NAMED COLLECTION CONTROL' = 95, 'SYSTEM SHUTDOWN' = 96, 'SYSTEM DROP DNS CACHE' = 97, 'SYSTEM DROP MARK CACHE' = 98, 'SYSTEM DROP UNCOMPRESSED CACHE' = 99, 'SYSTEM DROP MMAP CACHE' = 100, 'SYSTEM DROP QUERY CACHE' = 101, 'SYSTEM DROP COMPILED EXPRESSION CACHE' = 102, 'SYSTEM DROP FILESYSTEM CACHE' = 103, 'SYSTEM DROP SCHEMA CACHE' = 104, 'SYSTEM DROP S3 CLIENT CACHE' = 105, 'SYSTEM DROP CACHE' = 106, 'SYSTEM RELOAD CONFIG' = 107, 'SYSTEM RELOAD USERS' = 108, 'SYSTEM RELOAD SYMBOLS' = 109, 'SYSTEM RELOAD DICTIONARY' = 110, 'SYSTEM RELOAD MODEL' = 111, 'SYSTEM RELOAD FUNCTION' = 112, 'SYSTEM RELOAD EMBEDDED DICTIONARIES' = 113, 'SYSTEM RELOAD' = 114, 'SYSTEM RESTART DISK' = 115, 'SYSTEM MERGES' = 116, 'SYSTEM TTL MERGES' = 117, 'SYSTEM FETCHES' = 118, 'SYSTEM MOVES' = 119, 'SYSTEM DISTRIBUTED SENDS' = 120, 'SYSTEM REPLICATED SENDS' = 121, 'SYSTEM SENDS' = 122, 'SYSTEM REPLICATION QUEUES' = 123, 'SYSTEM DROP REPLICA' = 124, 'SYSTEM SYNC REPLICA' = 125, 'SYSTEM RESTART REPLICA' = 126, 'SYSTEM RESTORE REPLICA' = 127, 'SYSTEM WAIT LOADING PARTS' = 128, 'SYSTEM SYNC DATABASE REPLICA' = 129, 'SYSTEM SYNC TRANSACTION LOG' = 130, 'SYSTEM SYNC FILE CACHE' = 131, 'SYSTEM FLUSH DISTRIBUTED' = 132, 'SYSTEM FLUSH LOGS' = 133, 'SYSTEM FLUSH' = 134, 'SYSTEM THREAD FUZZER' = 135, 'SYSTEM UNFREEZE' = 136, 'SYSTEM' = 137, 'dictGet' = 138, 'addressToLine' = 139, 'addressToLineWithInlines' = 140, 'addressToSymbol' = 141, 'demangle' = 142, 'INTROSPECTION' = 143, 'FILE' = 144, 'URL' = 145, 'REMOTE' = 146, 'MONGO' = 147, 'MEILISEARCH' = 148, 'MYSQL' = 149, 'POSTGRES' = 150, 'SQLITE' = 151, 'ODBC' = 152, 'JDBC' = 153, 'HDFS' = 154, 'S3' = 155, 'HIVE' = 156, 'SOURCES' = 157, 'CLUSTER' = 158, 'ALL' = 159, 'NONE' = 160),
|
||||
`database` Nullable(String),
|
||||
`table` Nullable(String),
|
||||
`column` Nullable(String),
|
||||
@ -570,10 +570,10 @@ ENGINE = SystemPartsColumns
|
||||
COMMENT 'SYSTEM TABLE is built on the fly.'
|
||||
CREATE TABLE system.privileges
|
||||
(
|
||||
`privilege` Enum16('SHOW DATABASES' = 0, 'SHOW TABLES' = 1, 'SHOW COLUMNS' = 2, 'SHOW DICTIONARIES' = 3, 'SHOW' = 4, 'SHOW FILESYSTEM CACHES' = 5, 'SELECT' = 6, 'INSERT' = 7, 'ALTER UPDATE' = 8, 'ALTER DELETE' = 9, 'ALTER ADD COLUMN' = 10, 'ALTER MODIFY COLUMN' = 11, 'ALTER DROP COLUMN' = 12, 'ALTER COMMENT COLUMN' = 13, 'ALTER CLEAR COLUMN' = 14, 'ALTER RENAME COLUMN' = 15, 'ALTER MATERIALIZE COLUMN' = 16, 'ALTER COLUMN' = 17, 'ALTER MODIFY COMMENT' = 18, 'ALTER ORDER BY' = 19, 'ALTER SAMPLE BY' = 20, 'ALTER ADD INDEX' = 21, 'ALTER DROP INDEX' = 22, 'ALTER MATERIALIZE INDEX' = 23, 'ALTER CLEAR INDEX' = 24, 'ALTER INDEX' = 25, 'ALTER ADD PROJECTION' = 26, 'ALTER DROP PROJECTION' = 27, 'ALTER MATERIALIZE PROJECTION' = 28, 'ALTER CLEAR PROJECTION' = 29, 'ALTER PROJECTION' = 30, 'ALTER ADD CONSTRAINT' = 31, 'ALTER DROP CONSTRAINT' = 32, 'ALTER CONSTRAINT' = 33, 'ALTER TTL' = 34, 'ALTER MATERIALIZE TTL' = 35, 'ALTER SETTINGS' = 36, 'ALTER MOVE PARTITION' = 37, 'ALTER FETCH PARTITION' = 38, 'ALTER FREEZE PARTITION' = 39, 'ALTER DATABASE SETTINGS' = 40, 'ALTER NAMED COLLECTION' = 41, 'ALTER TABLE' = 42, 'ALTER DATABASE' = 43, 'ALTER VIEW REFRESH' = 44, 'ALTER VIEW MODIFY QUERY' = 45, 'ALTER VIEW' = 46, 'ALTER' = 47, 'CREATE DATABASE' = 48, 'CREATE TABLE' = 49, 'CREATE VIEW' = 50, 'CREATE DICTIONARY' = 51, 'CREATE TEMPORARY TABLE' = 52, 'CREATE ARBITRARY TEMPORARY TABLE' = 53, 'CREATE FUNCTION' = 54, 'CREATE NAMED COLLECTION' = 55, 'CREATE' = 56, 'DROP DATABASE' = 57, 'DROP TABLE' = 58, 'DROP VIEW' = 59, 'DROP DICTIONARY' = 60, 'DROP FUNCTION' = 61, 'DROP NAMED COLLECTION' = 62, 'DROP' = 63, 'TRUNCATE' = 64, 'OPTIMIZE' = 65, 'BACKUP' = 66, 'KILL QUERY' = 67, 'KILL TRANSACTION' = 68, 'MOVE PARTITION BETWEEN SHARDS' = 69, 'CREATE USER' = 70, 'ALTER USER' = 71, 'DROP USER' = 72, 'CREATE ROLE' = 73, 'ALTER ROLE' = 74, 'DROP ROLE' = 75, 'ROLE ADMIN' = 76, 'CREATE ROW POLICY' = 77, 'ALTER ROW POLICY' = 78, 'DROP ROW POLICY' = 79, 'CREATE QUOTA' = 80, 'ALTER QUOTA' = 81, 'DROP QUOTA' = 82, 'CREATE SETTINGS PROFILE' = 83, 'ALTER SETTINGS PROFILE' = 84, 'DROP SETTINGS PROFILE' = 85, 'SHOW USERS' = 86, 'SHOW ROLES' = 87, 'SHOW ROW POLICIES' = 88, 'SHOW QUOTAS' = 89, 'SHOW SETTINGS PROFILES' = 90, 'SHOW ACCESS' = 91, 'SHOW NAMED COLLECTIONS' = 92, 'SHOW NAMED COLLECTIONS SECRETS' = 93, 'ACCESS MANAGEMENT' = 94, 'SYSTEM SHUTDOWN' = 95, 'SYSTEM DROP DNS CACHE' = 96, 'SYSTEM DROP MARK CACHE' = 97, 'SYSTEM DROP UNCOMPRESSED CACHE' = 98, 'SYSTEM DROP MMAP CACHE' = 99, 'SYSTEM DROP QUERY CACHE' = 100, 'SYSTEM DROP COMPILED EXPRESSION CACHE' = 101, 'SYSTEM DROP FILESYSTEM CACHE' = 102, 'SYSTEM DROP SCHEMA CACHE' = 103, 'SYSTEM DROP S3 CLIENT CACHE' = 104, 'SYSTEM DROP CACHE' = 105, 'SYSTEM RELOAD CONFIG' = 106, 'SYSTEM RELOAD USERS' = 107, 'SYSTEM RELOAD SYMBOLS' = 108, 'SYSTEM RELOAD DICTIONARY' = 109, 'SYSTEM RELOAD MODEL' = 110, 'SYSTEM RELOAD FUNCTION' = 111, 'SYSTEM RELOAD EMBEDDED DICTIONARIES' = 112, 'SYSTEM RELOAD' = 113, 'SYSTEM RESTART DISK' = 114, 'SYSTEM MERGES' = 115, 'SYSTEM TTL MERGES' = 116, 'SYSTEM FETCHES' = 117, 'SYSTEM MOVES' = 118, 'SYSTEM DISTRIBUTED SENDS' = 119, 'SYSTEM REPLICATED SENDS' = 120, 'SYSTEM SENDS' = 121, 'SYSTEM REPLICATION QUEUES' = 122, 'SYSTEM DROP REPLICA' = 123, 'SYSTEM SYNC REPLICA' = 124, 'SYSTEM RESTART REPLICA' = 125, 'SYSTEM RESTORE REPLICA' = 126, 'SYSTEM WAIT LOADING PARTS' = 127, 'SYSTEM SYNC DATABASE REPLICA' = 128, 'SYSTEM SYNC TRANSACTION LOG' = 129, 'SYSTEM SYNC FILE CACHE' = 130, 'SYSTEM FLUSH DISTRIBUTED' = 131, 'SYSTEM FLUSH LOGS' = 132, 'SYSTEM FLUSH' = 133, 'SYSTEM THREAD FUZZER' = 134, 'SYSTEM UNFREEZE' = 135, 'SYSTEM' = 136, 'dictGet' = 137, 'addressToLine' = 138, 'addressToLineWithInlines' = 139, 'addressToSymbol' = 140, 'demangle' = 141, 'INTROSPECTION' = 142, 'FILE' = 143, 'URL' = 144, 'REMOTE' = 145, 'MONGO' = 146, 'MEILISEARCH' = 147, 'MYSQL' = 148, 'POSTGRES' = 149, 'SQLITE' = 150, 'ODBC' = 151, 'JDBC' = 152, 'HDFS' = 153, 'S3' = 154, 'HIVE' = 155, 'SOURCES' = 156, 'CLUSTER' = 157, 'ALL' = 158, 'NONE' = 159),
|
||||
`privilege` Enum16('SHOW DATABASES' = 0, 'SHOW TABLES' = 1, 'SHOW COLUMNS' = 2, 'SHOW DICTIONARIES' = 3, 'SHOW' = 4, 'SHOW FILESYSTEM CACHES' = 5, 'SELECT' = 6, 'INSERT' = 7, 'ALTER UPDATE' = 8, 'ALTER DELETE' = 9, 'ALTER ADD COLUMN' = 10, 'ALTER MODIFY COLUMN' = 11, 'ALTER DROP COLUMN' = 12, 'ALTER COMMENT COLUMN' = 13, 'ALTER CLEAR COLUMN' = 14, 'ALTER RENAME COLUMN' = 15, 'ALTER MATERIALIZE COLUMN' = 16, 'ALTER COLUMN' = 17, 'ALTER MODIFY COMMENT' = 18, 'ALTER ORDER BY' = 19, 'ALTER SAMPLE BY' = 20, 'ALTER ADD INDEX' = 21, 'ALTER DROP INDEX' = 22, 'ALTER MATERIALIZE INDEX' = 23, 'ALTER CLEAR INDEX' = 24, 'ALTER INDEX' = 25, 'ALTER ADD PROJECTION' = 26, 'ALTER DROP PROJECTION' = 27, 'ALTER MATERIALIZE PROJECTION' = 28, 'ALTER CLEAR PROJECTION' = 29, 'ALTER PROJECTION' = 30, 'ALTER ADD CONSTRAINT' = 31, 'ALTER DROP CONSTRAINT' = 32, 'ALTER CONSTRAINT' = 33, 'ALTER TTL' = 34, 'ALTER MATERIALIZE TTL' = 35, 'ALTER SETTINGS' = 36, 'ALTER MOVE PARTITION' = 37, 'ALTER FETCH PARTITION' = 38, 'ALTER FREEZE PARTITION' = 39, 'ALTER DATABASE SETTINGS' = 40, 'ALTER NAMED COLLECTION' = 41, 'ALTER TABLE' = 42, 'ALTER DATABASE' = 43, 'ALTER VIEW REFRESH' = 44, 'ALTER VIEW MODIFY QUERY' = 45, 'ALTER VIEW' = 46, 'ALTER' = 47, 'CREATE DATABASE' = 48, 'CREATE TABLE' = 49, 'CREATE VIEW' = 50, 'CREATE DICTIONARY' = 51, 'CREATE TEMPORARY TABLE' = 52, 'CREATE ARBITRARY TEMPORARY TABLE' = 53, 'CREATE FUNCTION' = 54, 'CREATE NAMED COLLECTION' = 55, 'CREATE' = 56, 'DROP DATABASE' = 57, 'DROP TABLE' = 58, 'DROP VIEW' = 59, 'DROP DICTIONARY' = 60, 'DROP FUNCTION' = 61, 'DROP NAMED COLLECTION' = 62, 'DROP' = 63, 'TRUNCATE' = 64, 'OPTIMIZE' = 65, 'BACKUP' = 66, 'KILL QUERY' = 67, 'KILL TRANSACTION' = 68, 'MOVE PARTITION BETWEEN SHARDS' = 69, 'CREATE USER' = 70, 'ALTER USER' = 71, 'DROP USER' = 72, 'CREATE ROLE' = 73, 'ALTER ROLE' = 74, 'DROP ROLE' = 75, 'ROLE ADMIN' = 76, 'CREATE ROW POLICY' = 77, 'ALTER ROW POLICY' = 78, 'DROP ROW POLICY' = 79, 'CREATE QUOTA' = 80, 'ALTER QUOTA' = 81, 'DROP QUOTA' = 82, 'CREATE SETTINGS PROFILE' = 83, 'ALTER SETTINGS PROFILE' = 84, 'DROP SETTINGS PROFILE' = 85, 'SHOW USERS' = 86, 'SHOW ROLES' = 87, 'SHOW ROW POLICIES' = 88, 'SHOW QUOTAS' = 89, 'SHOW SETTINGS PROFILES' = 90, 'SHOW ACCESS' = 91, 'ACCESS MANAGEMENT' = 92, 'SHOW NAMED COLLECTIONS' = 93, 'SHOW NAMED COLLECTIONS SECRETS' = 94, 'NAMED COLLECTION CONTROL' = 95, 'SYSTEM SHUTDOWN' = 96, 'SYSTEM DROP DNS CACHE' = 97, 'SYSTEM DROP MARK CACHE' = 98, 'SYSTEM DROP UNCOMPRESSED CACHE' = 99, 'SYSTEM DROP MMAP CACHE' = 100, 'SYSTEM DROP QUERY CACHE' = 101, 'SYSTEM DROP COMPILED EXPRESSION CACHE' = 102, 'SYSTEM DROP FILESYSTEM CACHE' = 103, 'SYSTEM DROP SCHEMA CACHE' = 104, 'SYSTEM DROP S3 CLIENT CACHE' = 105, 'SYSTEM DROP CACHE' = 106, 'SYSTEM RELOAD CONFIG' = 107, 'SYSTEM RELOAD USERS' = 108, 'SYSTEM RELOAD SYMBOLS' = 109, 'SYSTEM RELOAD DICTIONARY' = 110, 'SYSTEM RELOAD MODEL' = 111, 'SYSTEM RELOAD FUNCTION' = 112, 'SYSTEM RELOAD EMBEDDED DICTIONARIES' = 113, 'SYSTEM RELOAD' = 114, 'SYSTEM RESTART DISK' = 115, 'SYSTEM MERGES' = 116, 'SYSTEM TTL MERGES' = 117, 'SYSTEM FETCHES' = 118, 'SYSTEM MOVES' = 119, 'SYSTEM DISTRIBUTED SENDS' = 120, 'SYSTEM REPLICATED SENDS' = 121, 'SYSTEM SENDS' = 122, 'SYSTEM REPLICATION QUEUES' = 123, 'SYSTEM DROP REPLICA' = 124, 'SYSTEM SYNC REPLICA' = 125, 'SYSTEM RESTART REPLICA' = 126, 'SYSTEM RESTORE REPLICA' = 127, 'SYSTEM WAIT LOADING PARTS' = 128, 'SYSTEM SYNC DATABASE REPLICA' = 129, 'SYSTEM SYNC TRANSACTION LOG' = 130, 'SYSTEM SYNC FILE CACHE' = 131, 'SYSTEM FLUSH DISTRIBUTED' = 132, 'SYSTEM FLUSH LOGS' = 133, 'SYSTEM FLUSH' = 134, 'SYSTEM THREAD FUZZER' = 135, 'SYSTEM UNFREEZE' = 136, 'SYSTEM' = 137, 'dictGet' = 138, 'addressToLine' = 139, 'addressToLineWithInlines' = 140, 'addressToSymbol' = 141, 'demangle' = 142, 'INTROSPECTION' = 143, 'FILE' = 144, 'URL' = 145, 'REMOTE' = 146, 'MONGO' = 147, 'MEILISEARCH' = 148, 'MYSQL' = 149, 'POSTGRES' = 150, 'SQLITE' = 151, 'ODBC' = 152, 'JDBC' = 153, 'HDFS' = 154, 'S3' = 155, 'HIVE' = 156, 'SOURCES' = 157, 'CLUSTER' = 158, 'ALL' = 159, 'NONE' = 160),
|
||||
`aliases` Array(String),
|
||||
`level` Nullable(Enum8('GLOBAL' = 0, 'DATABASE' = 1, 'TABLE' = 2, 'DICTIONARY' = 3, 'VIEW' = 4, 'COLUMN' = 5)),
|
||||
`parent_group` Nullable(Enum16('SHOW DATABASES' = 0, 'SHOW TABLES' = 1, 'SHOW COLUMNS' = 2, 'SHOW DICTIONARIES' = 3, 'SHOW' = 4, 'SHOW FILESYSTEM CACHES' = 5, 'SELECT' = 6, 'INSERT' = 7, 'ALTER UPDATE' = 8, 'ALTER DELETE' = 9, 'ALTER ADD COLUMN' = 10, 'ALTER MODIFY COLUMN' = 11, 'ALTER DROP COLUMN' = 12, 'ALTER COMMENT COLUMN' = 13, 'ALTER CLEAR COLUMN' = 14, 'ALTER RENAME COLUMN' = 15, 'ALTER MATERIALIZE COLUMN' = 16, 'ALTER COLUMN' = 17, 'ALTER MODIFY COMMENT' = 18, 'ALTER ORDER BY' = 19, 'ALTER SAMPLE BY' = 20, 'ALTER ADD INDEX' = 21, 'ALTER DROP INDEX' = 22, 'ALTER MATERIALIZE INDEX' = 23, 'ALTER CLEAR INDEX' = 24, 'ALTER INDEX' = 25, 'ALTER ADD PROJECTION' = 26, 'ALTER DROP PROJECTION' = 27, 'ALTER MATERIALIZE PROJECTION' = 28, 'ALTER CLEAR PROJECTION' = 29, 'ALTER PROJECTION' = 30, 'ALTER ADD CONSTRAINT' = 31, 'ALTER DROP CONSTRAINT' = 32, 'ALTER CONSTRAINT' = 33, 'ALTER TTL' = 34, 'ALTER MATERIALIZE TTL' = 35, 'ALTER SETTINGS' = 36, 'ALTER MOVE PARTITION' = 37, 'ALTER FETCH PARTITION' = 38, 'ALTER FREEZE PARTITION' = 39, 'ALTER DATABASE SETTINGS' = 40, 'ALTER NAMED COLLECTION' = 41, 'ALTER TABLE' = 42, 'ALTER DATABASE' = 43, 'ALTER VIEW REFRESH' = 44, 'ALTER VIEW MODIFY QUERY' = 45, 'ALTER VIEW' = 46, 'ALTER' = 47, 'CREATE DATABASE' = 48, 'CREATE TABLE' = 49, 'CREATE VIEW' = 50, 'CREATE DICTIONARY' = 51, 'CREATE TEMPORARY TABLE' = 52, 'CREATE ARBITRARY TEMPORARY TABLE' = 53, 'CREATE FUNCTION' = 54, 'CREATE NAMED COLLECTION' = 55, 'CREATE' = 56, 'DROP DATABASE' = 57, 'DROP TABLE' = 58, 'DROP VIEW' = 59, 'DROP DICTIONARY' = 60, 'DROP FUNCTION' = 61, 'DROP NAMED COLLECTION' = 62, 'DROP' = 63, 'TRUNCATE' = 64, 'OPTIMIZE' = 65, 'BACKUP' = 66, 'KILL QUERY' = 67, 'KILL TRANSACTION' = 68, 'MOVE PARTITION BETWEEN SHARDS' = 69, 'CREATE USER' = 70, 'ALTER USER' = 71, 'DROP USER' = 72, 'CREATE ROLE' = 73, 'ALTER ROLE' = 74, 'DROP ROLE' = 75, 'ROLE ADMIN' = 76, 'CREATE ROW POLICY' = 77, 'ALTER ROW POLICY' = 78, 'DROP ROW POLICY' = 79, 'CREATE QUOTA' = 80, 'ALTER QUOTA' = 81, 'DROP QUOTA' = 82, 'CREATE SETTINGS PROFILE' = 83, 'ALTER SETTINGS PROFILE' = 84, 'DROP SETTINGS PROFILE' = 85, 'SHOW USERS' = 86, 'SHOW ROLES' = 87, 'SHOW ROW POLICIES' = 88, 'SHOW QUOTAS' = 89, 'SHOW SETTINGS PROFILES' = 90, 'SHOW ACCESS' = 91, 'SHOW NAMED COLLECTIONS' = 92, 'SHOW NAMED COLLECTIONS SECRETS' = 93, 'ACCESS MANAGEMENT' = 94, 'SYSTEM SHUTDOWN' = 95, 'SYSTEM DROP DNS CACHE' = 96, 'SYSTEM DROP MARK CACHE' = 97, 'SYSTEM DROP UNCOMPRESSED CACHE' = 98, 'SYSTEM DROP MMAP CACHE' = 99, 'SYSTEM DROP QUERY CACHE' = 100, 'SYSTEM DROP COMPILED EXPRESSION CACHE' = 101, 'SYSTEM DROP FILESYSTEM CACHE' = 102, 'SYSTEM DROP SCHEMA CACHE' = 103, 'SYSTEM DROP S3 CLIENT CACHE' = 104, 'SYSTEM DROP CACHE' = 105, 'SYSTEM RELOAD CONFIG' = 106, 'SYSTEM RELOAD USERS' = 107, 'SYSTEM RELOAD SYMBOLS' = 108, 'SYSTEM RELOAD DICTIONARY' = 109, 'SYSTEM RELOAD MODEL' = 110, 'SYSTEM RELOAD FUNCTION' = 111, 'SYSTEM RELOAD EMBEDDED DICTIONARIES' = 112, 'SYSTEM RELOAD' = 113, 'SYSTEM RESTART DISK' = 114, 'SYSTEM MERGES' = 115, 'SYSTEM TTL MERGES' = 116, 'SYSTEM FETCHES' = 117, 'SYSTEM MOVES' = 118, 'SYSTEM DISTRIBUTED SENDS' = 119, 'SYSTEM REPLICATED SENDS' = 120, 'SYSTEM SENDS' = 121, 'SYSTEM REPLICATION QUEUES' = 122, 'SYSTEM DROP REPLICA' = 123, 'SYSTEM SYNC REPLICA' = 124, 'SYSTEM RESTART REPLICA' = 125, 'SYSTEM RESTORE REPLICA' = 126, 'SYSTEM WAIT LOADING PARTS' = 127, 'SYSTEM SYNC DATABASE REPLICA' = 128, 'SYSTEM SYNC TRANSACTION LOG' = 129, 'SYSTEM SYNC FILE CACHE' = 130, 'SYSTEM FLUSH DISTRIBUTED' = 131, 'SYSTEM FLUSH LOGS' = 132, 'SYSTEM FLUSH' = 133, 'SYSTEM THREAD FUZZER' = 134, 'SYSTEM UNFREEZE' = 135, 'SYSTEM' = 136, 'dictGet' = 137, 'addressToLine' = 138, 'addressToLineWithInlines' = 139, 'addressToSymbol' = 140, 'demangle' = 141, 'INTROSPECTION' = 142, 'FILE' = 143, 'URL' = 144, 'REMOTE' = 145, 'MONGO' = 146, 'MEILISEARCH' = 147, 'MYSQL' = 148, 'POSTGRES' = 149, 'SQLITE' = 150, 'ODBC' = 151, 'JDBC' = 152, 'HDFS' = 153, 'S3' = 154, 'HIVE' = 155, 'SOURCES' = 156, 'CLUSTER' = 157, 'ALL' = 158, 'NONE' = 159))
|
||||
`level` Nullable(Enum8('GLOBAL' = 0, 'DATABASE' = 1, 'TABLE' = 2, 'DICTIONARY' = 3, 'VIEW' = 4, 'COLUMN' = 5, 'NAMED_COLLECTION' = 6)),
|
||||
`parent_group` Nullable(Enum16('SHOW DATABASES' = 0, 'SHOW TABLES' = 1, 'SHOW COLUMNS' = 2, 'SHOW DICTIONARIES' = 3, 'SHOW' = 4, 'SHOW FILESYSTEM CACHES' = 5, 'SELECT' = 6, 'INSERT' = 7, 'ALTER UPDATE' = 8, 'ALTER DELETE' = 9, 'ALTER ADD COLUMN' = 10, 'ALTER MODIFY COLUMN' = 11, 'ALTER DROP COLUMN' = 12, 'ALTER COMMENT COLUMN' = 13, 'ALTER CLEAR COLUMN' = 14, 'ALTER RENAME COLUMN' = 15, 'ALTER MATERIALIZE COLUMN' = 16, 'ALTER COLUMN' = 17, 'ALTER MODIFY COMMENT' = 18, 'ALTER ORDER BY' = 19, 'ALTER SAMPLE BY' = 20, 'ALTER ADD INDEX' = 21, 'ALTER DROP INDEX' = 22, 'ALTER MATERIALIZE INDEX' = 23, 'ALTER CLEAR INDEX' = 24, 'ALTER INDEX' = 25, 'ALTER ADD PROJECTION' = 26, 'ALTER DROP PROJECTION' = 27, 'ALTER MATERIALIZE PROJECTION' = 28, 'ALTER CLEAR PROJECTION' = 29, 'ALTER PROJECTION' = 30, 'ALTER ADD CONSTRAINT' = 31, 'ALTER DROP CONSTRAINT' = 32, 'ALTER CONSTRAINT' = 33, 'ALTER TTL' = 34, 'ALTER MATERIALIZE TTL' = 35, 'ALTER SETTINGS' = 36, 'ALTER MOVE PARTITION' = 37, 'ALTER FETCH PARTITION' = 38, 'ALTER FREEZE PARTITION' = 39, 'ALTER DATABASE SETTINGS' = 40, 'ALTER NAMED COLLECTION' = 41, 'ALTER TABLE' = 42, 'ALTER DATABASE' = 43, 'ALTER VIEW REFRESH' = 44, 'ALTER VIEW MODIFY QUERY' = 45, 'ALTER VIEW' = 46, 'ALTER' = 47, 'CREATE DATABASE' = 48, 'CREATE TABLE' = 49, 'CREATE VIEW' = 50, 'CREATE DICTIONARY' = 51, 'CREATE TEMPORARY TABLE' = 52, 'CREATE ARBITRARY TEMPORARY TABLE' = 53, 'CREATE FUNCTION' = 54, 'CREATE NAMED COLLECTION' = 55, 'CREATE' = 56, 'DROP DATABASE' = 57, 'DROP TABLE' = 58, 'DROP VIEW' = 59, 'DROP DICTIONARY' = 60, 'DROP FUNCTION' = 61, 'DROP NAMED COLLECTION' = 62, 'DROP' = 63, 'TRUNCATE' = 64, 'OPTIMIZE' = 65, 'BACKUP' = 66, 'KILL QUERY' = 67, 'KILL TRANSACTION' = 68, 'MOVE PARTITION BETWEEN SHARDS' = 69, 'CREATE USER' = 70, 'ALTER USER' = 71, 'DROP USER' = 72, 'CREATE ROLE' = 73, 'ALTER ROLE' = 74, 'DROP ROLE' = 75, 'ROLE ADMIN' = 76, 'CREATE ROW POLICY' = 77, 'ALTER ROW POLICY' = 78, 'DROP ROW POLICY' = 79, 'CREATE QUOTA' = 80, 'ALTER QUOTA' = 81, 'DROP QUOTA' = 82, 'CREATE SETTINGS PROFILE' = 83, 'ALTER SETTINGS PROFILE' = 84, 'DROP SETTINGS PROFILE' = 85, 'SHOW USERS' = 86, 'SHOW ROLES' = 87, 'SHOW ROW POLICIES' = 88, 'SHOW QUOTAS' = 89, 'SHOW SETTINGS PROFILES' = 90, 'SHOW ACCESS' = 91, 'ACCESS MANAGEMENT' = 92, 'SHOW NAMED COLLECTIONS' = 93, 'SHOW NAMED COLLECTIONS SECRETS' = 94, 'NAMED COLLECTION CONTROL' = 95, 'SYSTEM SHUTDOWN' = 96, 'SYSTEM DROP DNS CACHE' = 97, 'SYSTEM DROP MARK CACHE' = 98, 'SYSTEM DROP UNCOMPRESSED CACHE' = 99, 'SYSTEM DROP MMAP CACHE' = 100, 'SYSTEM DROP QUERY CACHE' = 101, 'SYSTEM DROP COMPILED EXPRESSION CACHE' = 102, 'SYSTEM DROP FILESYSTEM CACHE' = 103, 'SYSTEM DROP SCHEMA CACHE' = 104, 'SYSTEM DROP S3 CLIENT CACHE' = 105, 'SYSTEM DROP CACHE' = 106, 'SYSTEM RELOAD CONFIG' = 107, 'SYSTEM RELOAD USERS' = 108, 'SYSTEM RELOAD SYMBOLS' = 109, 'SYSTEM RELOAD DICTIONARY' = 110, 'SYSTEM RELOAD MODEL' = 111, 'SYSTEM RELOAD FUNCTION' = 112, 'SYSTEM RELOAD EMBEDDED DICTIONARIES' = 113, 'SYSTEM RELOAD' = 114, 'SYSTEM RESTART DISK' = 115, 'SYSTEM MERGES' = 116, 'SYSTEM TTL MERGES' = 117, 'SYSTEM FETCHES' = 118, 'SYSTEM MOVES' = 119, 'SYSTEM DISTRIBUTED SENDS' = 120, 'SYSTEM REPLICATED SENDS' = 121, 'SYSTEM SENDS' = 122, 'SYSTEM REPLICATION QUEUES' = 123, 'SYSTEM DROP REPLICA' = 124, 'SYSTEM SYNC REPLICA' = 125, 'SYSTEM RESTART REPLICA' = 126, 'SYSTEM RESTORE REPLICA' = 127, 'SYSTEM WAIT LOADING PARTS' = 128, 'SYSTEM SYNC DATABASE REPLICA' = 129, 'SYSTEM SYNC TRANSACTION LOG' = 130, 'SYSTEM SYNC FILE CACHE' = 131, 'SYSTEM FLUSH DISTRIBUTED' = 132, 'SYSTEM FLUSH LOGS' = 133, 'SYSTEM FLUSH' = 134, 'SYSTEM THREAD FUZZER' = 135, 'SYSTEM UNFREEZE' = 136, 'SYSTEM' = 137, 'dictGet' = 138, 'addressToLine' = 139, 'addressToLineWithInlines' = 140, 'addressToSymbol' = 141, 'demangle' = 142, 'INTROSPECTION' = 143, 'FILE' = 144, 'URL' = 145, 'REMOTE' = 146, 'MONGO' = 147, 'MEILISEARCH' = 148, 'MYSQL' = 149, 'POSTGRES' = 150, 'SQLITE' = 151, 'ODBC' = 152, 'JDBC' = 153, 'HDFS' = 154, 'S3' = 155, 'HIVE' = 156, 'SOURCES' = 157, 'CLUSTER' = 158, 'ALL' = 159, 'NONE' = 160))
|
||||
)
|
||||
ENGINE = SystemPrivileges
|
||||
COMMENT 'SYSTEM TABLE is built on the fly.'
|
||||
|
Loading…
Reference in New Issue
Block a user