mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-22 07:31:57 +00:00
work in progress
This commit is contained in:
parent
899bf99d44
commit
7fec55eea4
@ -640,6 +640,12 @@
|
||||
executed by any user. You can change this behaviour by setting this to true.
|
||||
If it's set to true then this query requires "GRANT SELECT ON information_schema.<table>" just like as for ordinary tables. -->
|
||||
<select_from_information_schema_requires_grant>false</select_from_information_schema_requires_grant>
|
||||
|
||||
<!-- By default, for backward compatibility a settings profile constraint for a specific setting inherit every not set field from
|
||||
previous profile. You can change this behaviour by setting this to true.
|
||||
If it's set to true then if settings profile has a constraint for a specific setting, then this constraint completely cancels all
|
||||
actions of previous constraint (defined in other profiles) for the same specific setting, including fields that are not set by new constraint. -->
|
||||
<settings_constraints_replace_previous>false</settings_constraints_replace_previous>
|
||||
</access_control_improvements>
|
||||
|
||||
<!-- Default profile of settings. -->
|
||||
|
@ -171,6 +171,7 @@ void AccessControl::setUpFromMainConfig(const Poco::Util::AbstractConfiguration
|
||||
setOnClusterQueriesRequireClusterGrant(config_.getBool("access_control_improvements.on_cluster_queries_require_cluster_grant", false));
|
||||
setSelectFromSystemDatabaseRequiresGrant(config_.getBool("access_control_improvements.select_from_system_db_requires_grant", false));
|
||||
setSelectFromInformationSchemaRequiresGrant(config_.getBool("access_control_improvements.select_from_information_schema_requires_grant", false));
|
||||
setSettingsConstraintsReplacePrevious(config_.getBool("access_control_improvements.settings_constraints_replace_previous", false));
|
||||
|
||||
addStoragesFromMainConfig(config_, config_path_, get_zookeeper_function_);
|
||||
}
|
||||
|
@ -158,6 +158,9 @@ public:
|
||||
void setSelectFromInformationSchemaRequiresGrant(bool enable) { select_from_information_schema_requires_grant = enable; }
|
||||
bool doesSelectFromInformationSchemaRequireGrant() const { return select_from_information_schema_requires_grant; }
|
||||
|
||||
void setSettingsConstraintsReplacePrevious(bool enable) { settings_constraints_replace_previous = enable; }
|
||||
bool doesSettingsConstraintsReplacePrevious() const { return settings_constraints_replace_previous; }
|
||||
|
||||
std::shared_ptr<const ContextAccess> getContextAccess(
|
||||
const UUID & user_id,
|
||||
const std::vector<UUID> & current_roles,
|
||||
@ -223,6 +226,7 @@ private:
|
||||
std::atomic_bool on_cluster_queries_require_cluster_grant = false;
|
||||
std::atomic_bool select_from_system_db_requires_grant = false;
|
||||
std::atomic_bool select_from_information_schema_requires_grant = false;
|
||||
std::atomic_bool settings_constraints_replace_previous = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -36,45 +36,42 @@ void SettingsConstraints::clear()
|
||||
}
|
||||
|
||||
|
||||
void SettingsConstraints::constrainMinValue(const String & setting_name, const Field & min_value)
|
||||
void SettingsConstraints::setMinValue(const String & setting_name, const Field & min_value)
|
||||
{
|
||||
constraints[setting_name].min_value = Settings::castValueUtil(setting_name, min_value);
|
||||
}
|
||||
|
||||
void SettingsConstraints::constrainMaxValue(const String & setting_name, const Field & max_value)
|
||||
void SettingsConstraints::setMaxValue(const String & setting_name, const Field & max_value)
|
||||
{
|
||||
constraints[setting_name].max_value = Settings::castValueUtil(setting_name, max_value);
|
||||
}
|
||||
|
||||
void SettingsConstraints::constrainReadOnly(const String & setting_name, bool read_only)
|
||||
void SettingsConstraints::setIsConst(const String & setting_name, bool is_const)
|
||||
{
|
||||
constraints[setting_name].read_only = read_only;
|
||||
constraints[setting_name].is_const = is_const;
|
||||
}
|
||||
|
||||
void SettingsConstraints::allowMinValue(const String & setting_name, const Field & min_value)
|
||||
void SettingsConstraints::setChangableInReadonly(const String & setting_name, bool changeable_in_readonly)
|
||||
{
|
||||
allowances[setting_name].min_value = Settings::castValueUtil(setting_name, min_value);
|
||||
constraints[setting_name].changeable_in_readonly = changeable_in_readonly;
|
||||
}
|
||||
|
||||
void SettingsConstraints::allowMaxValue(const String & setting_name, const Field & max_value)
|
||||
{
|
||||
allowances[setting_name].max_value = Settings::castValueUtil(setting_name, max_value);
|
||||
}
|
||||
|
||||
void SettingsConstraints::allowReadOnly(const String & setting_name, bool read_only)
|
||||
{
|
||||
allowances[setting_name].read_only = read_only;
|
||||
}
|
||||
|
||||
void SettingsConstraints::get(const Settings & current_settings, std::string_view setting_name, Field & min_value, Field & max_value, bool & read_only) const
|
||||
void SettingsConstraints::get(const Settings & current_settings, std::string_view setting_name, Field & min_value, Field & max_value, bool & is_const) const
|
||||
{
|
||||
auto range = getRange(current_settings, setting_name);
|
||||
min_value = range.min_value;
|
||||
max_value = range.max_value;
|
||||
read_only = range.read_only;
|
||||
is_const = range.is_const;
|
||||
}
|
||||
|
||||
void SettingsConstraints::merge(const SettingsConstraints & other)
|
||||
{
|
||||
if (access_control.doesSettingsConstraintsReplacePrevious())
|
||||
{
|
||||
for (const auto & [other_name, other_constraint] : other.constraints)
|
||||
constraints[other_name] = other_constraint;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto & [other_name, other_constraint] : other.constraints)
|
||||
{
|
||||
@ -83,18 +80,9 @@ void SettingsConstraints::merge(const SettingsConstraints & other)
|
||||
constraint.min_value = other_constraint.min_value;
|
||||
if (!other_constraint.max_value.isNull())
|
||||
constraint.max_value = other_constraint.max_value;
|
||||
if (other_constraint.read_only)
|
||||
constraint.read_only = true;
|
||||
if (other_constraint.is_const)
|
||||
constraint.is_const = true; // NOTE: In this mode <readonly/> flag cannot be overriden to be false
|
||||
}
|
||||
for (const auto & [other_name, other_allowance] : other.allowances)
|
||||
{
|
||||
auto & allowance = allowances[other_name];
|
||||
if (!other_allowance.min_value.isNull())
|
||||
allowance.min_value = other_allowance.min_value;
|
||||
if (!other_allowance.max_value.isNull())
|
||||
allowance.max_value = other_allowance.max_value;
|
||||
if (other_allowance.read_only)
|
||||
allowance.read_only = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,7 +217,7 @@ bool SettingsConstraints::Range::check(SettingChange & change, const Field & new
|
||||
return false;
|
||||
}
|
||||
|
||||
if (read_only)
|
||||
if (is_const)
|
||||
{
|
||||
if (reaction == THROW_ON_VIOLATION)
|
||||
throw Exception("Setting " + setting_name + " should not be changed", ErrorCodes::SETTING_CONSTRAINT_VIOLATION);
|
||||
@ -279,36 +267,34 @@ SettingsConstraints::Range SettingsConstraints::getRange(const Settings & curren
|
||||
|
||||
/** The `readonly` value is understood as follows:
|
||||
* 0 - no read-only restrictions.
|
||||
* 1 - only read requests, as well as changing explicitly allowed settings.
|
||||
* 1 - only read requests, as well as changing settings with `changable_in_readonly` flag.
|
||||
* 2 - only read requests, as well as changing settings, except for the `readonly` setting.
|
||||
*/
|
||||
|
||||
if (current_settings.readonly > 1 && setting_name == "readonly")
|
||||
return Range::forbidden("Cannot modify 'readonly' setting in readonly mode", ErrorCodes::READONLY);
|
||||
|
||||
auto it = constraints.find(setting_name);
|
||||
if (current_settings.readonly == 1)
|
||||
{
|
||||
auto it = allowances.find(setting_name);
|
||||
if (it == allowances.end())
|
||||
if (it == constraints.end() || !it->second.changeable_in_readonly)
|
||||
return Range::forbidden("Cannot modify '" + String(setting_name) + "' setting in readonly mode", ErrorCodes::READONLY);
|
||||
return it->second;
|
||||
}
|
||||
else // For both readonly=0 and readonly=2
|
||||
{
|
||||
auto it = constraints.find(setting_name);
|
||||
if (it == constraints.end())
|
||||
return Range::allowed();
|
||||
return it->second;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
bool SettingsConstraints::Range::operator==(const Range & other) const
|
||||
{
|
||||
return read_only == other.read_only && min_value == other.min_value && max_value == other.max_value;
|
||||
return is_const == other.is_const && changeable_in_readonly == other.changeable_in_readonly && min_value == other.min_value && max_value == other.max_value;
|
||||
}
|
||||
|
||||
bool operator ==(const SettingsConstraints & left, const SettingsConstraints & right)
|
||||
{
|
||||
return left.constraints == right.constraints && left.allowances == right.allowances;
|
||||
return left.constraints == right.constraints;
|
||||
}
|
||||
}
|
||||
|
@ -35,15 +35,12 @@ class AccessControl;
|
||||
* <max>20000000000</max>
|
||||
* </max_memory_usage>
|
||||
* <force_index_by_date>
|
||||
* <readonly/>
|
||||
* <const/>
|
||||
* </force_index_by_date>
|
||||
* <max_threads>
|
||||
* <changable_in_readonly/>
|
||||
* </max_threads>
|
||||
* </constraints>
|
||||
* <allow>
|
||||
* <max_memory_usage>
|
||||
* <min>200000</min>
|
||||
* <max>10000000000</max>
|
||||
* <max_memory_usage>
|
||||
* </allow>
|
||||
* </user_profile>
|
||||
* </profiles>
|
||||
*
|
||||
@ -51,7 +48,7 @@ class AccessControl;
|
||||
* If a setting cannot be change due to the read-only mode this class throws an exception.
|
||||
* The value of `readonly` is understood as follows:
|
||||
* 0 - not read-only mode, no additional checks.
|
||||
* 1 - only read queries, as well as changing explicitly allowed settings.
|
||||
* 1 - only read queries, as well as changing settings with <changable_in_readonly/> flag.
|
||||
* 2 - only read queries and you can change the settings, except for the `readonly` setting.
|
||||
*
|
||||
*/
|
||||
@ -68,14 +65,12 @@ public:
|
||||
void clear();
|
||||
bool empty() const { return constraints.empty(); }
|
||||
|
||||
void constrainMinValue(const String & setting_name, const Field & min_value);
|
||||
void constrainMaxValue(const String & setting_name, const Field & max_value);
|
||||
void constrainReadOnly(const String & setting_name, bool read_only);
|
||||
void allowMinValue(const String & setting_name, const Field & min_value);
|
||||
void allowMaxValue(const String & setting_name, const Field & max_value);
|
||||
void allowReadOnly(const String & setting_name, bool read_only);
|
||||
void setMinValue(const String & setting_name, const Field & min_value);
|
||||
void setMaxValue(const String & setting_name, const Field & max_value);
|
||||
void setIsConst(const String & setting_name, bool is_const);
|
||||
void setChangableInReadonly(const String & setting_name, bool is_const);
|
||||
|
||||
void get(const Settings & current_settings, std::string_view setting_name, Field & min_value, Field & max_value, bool & read_only) const;
|
||||
void get(const Settings & current_settings, std::string_view setting_name, Field & min_value, Field & max_value, bool & is_const) const;
|
||||
|
||||
void merge(const SettingsConstraints & other);
|
||||
|
||||
@ -99,7 +94,8 @@ private:
|
||||
|
||||
struct Range
|
||||
{
|
||||
bool read_only = false;
|
||||
bool is_const = false;
|
||||
bool changeable_in_readonly = false;
|
||||
Field min_value;
|
||||
Field max_value;
|
||||
|
||||
@ -119,7 +115,7 @@ private:
|
||||
|
||||
static Range forbidden(const String & explain, int code)
|
||||
{
|
||||
return Range{.read_only = true, .explain = explain, .code = code};
|
||||
return Range{.is_const = true, .explain = explain, .code = code};
|
||||
}
|
||||
};
|
||||
|
||||
@ -143,7 +139,6 @@ private:
|
||||
// Special container for heterogeneous lookups: to avoid `String` construction during `find(std::string_view)`
|
||||
using RangeMap = std::unordered_map<String, Range, StringHash, std::equal_to<>>;
|
||||
RangeMap constraints;
|
||||
RangeMap allowances;
|
||||
|
||||
const AccessControl * access_control = nullptr;
|
||||
};
|
||||
|
@ -56,7 +56,23 @@ void SettingsProfileElement::init(const ASTSettingsProfileElement & ast, const A
|
||||
value = ast.value;
|
||||
min_value = ast.min_value;
|
||||
max_value = ast.max_value;
|
||||
readonly = ast.readonly;
|
||||
changeable_in_readonly = false;
|
||||
switch (ast.type)
|
||||
{
|
||||
case ASTSettingsProfileElement::ConstraintType::NONE:
|
||||
is_const.reset();
|
||||
break;
|
||||
case ASTSettingsProfileElement::ConstraintType::WRITABLE:
|
||||
is_const.emplace(false);
|
||||
break;
|
||||
case ASTSettingsProfileElement::ConstraintType::CONST:
|
||||
is_const.emplace(true);
|
||||
break;
|
||||
case ASTSettingsProfileElement::ConstraintType::CHANGEABLE_IN_READONLY:
|
||||
is_const.reset();
|
||||
changeable_in_readonly = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!value.isNull())
|
||||
value = Settings::castValueUtil(setting_name, value);
|
||||
@ -208,25 +224,14 @@ SettingsConstraints SettingsProfileElements::toSettingsConstraints(const AccessC
|
||||
{
|
||||
if (!elem.setting_name.empty() && (elem.setting_name != ALLOW_BACKUP_SETTING_NAME))
|
||||
{
|
||||
switch (elem.kind)
|
||||
{
|
||||
case SettingsProfileElement::RangeKind::Constrain:
|
||||
if (!elem.min_value.isNull())
|
||||
res.constrainMinValue(elem.setting_name, elem.min_value);
|
||||
res.setMinValue(elem.setting_name, elem.min_value);
|
||||
if (!elem.max_value.isNull())
|
||||
res.constrainMaxValue(elem.setting_name, elem.max_value);
|
||||
if (elem.readonly)
|
||||
res.constrainReadOnly(elem.setting_name, *elem.readonly);
|
||||
break;
|
||||
case SettingsProfileElement::RangeKind::Allow:
|
||||
if (!elem.min_value.isNull())
|
||||
res.allowMinValue(elem.setting_name, elem.min_value);
|
||||
if (!elem.max_value.isNull())
|
||||
res.allowMaxValue(elem.setting_name, elem.max_value);
|
||||
if (elem.readonly)
|
||||
res.allowReadOnly(elem.setting_name, *elem.readonly);
|
||||
break;
|
||||
}
|
||||
res.setMaxValue(elem.setting_name, elem.max_value);
|
||||
if (elem.is_const)
|
||||
res.setIsConst(elem.setting_name, *elem.is_const);
|
||||
if (elem.changeable_in_readonly)
|
||||
res.setChangableInReadonly(elem.setting_name, true);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
@ -21,20 +21,14 @@ struct SettingsProfileElement
|
||||
{
|
||||
std::optional<UUID> parent_profile;
|
||||
|
||||
enum class RangeKind
|
||||
{
|
||||
Constrain = 0,
|
||||
Allow
|
||||
};
|
||||
|
||||
String setting_name;
|
||||
Field value;
|
||||
RangeKind kind = RangeKind::Constrain;
|
||||
Field min_value;
|
||||
Field max_value;
|
||||
std::optional<bool> readonly;
|
||||
std::optional<bool> is_const;
|
||||
bool changeable_in_readonly;
|
||||
|
||||
auto toTuple() const { return std::tie(parent_profile, setting_name, value, kind, min_value, max_value, readonly); }
|
||||
auto toTuple() const { return std::tie(parent_profile, setting_name, value, min_value, max_value, is_const, changeable_in_readonly); }
|
||||
friend bool operator==(const SettingsProfileElement & lhs, const SettingsProfileElement & rhs) { return lhs.toTuple() == rhs.toTuple(); }
|
||||
friend bool operator!=(const SettingsProfileElement & lhs, const SettingsProfileElement & rhs) { return !(lhs == rhs); }
|
||||
friend bool operator <(const SettingsProfileElement & lhs, const SettingsProfileElement & rhs) { return lhs.toTuple() < rhs.toTuple(); }
|
||||
|
@ -52,10 +52,22 @@ void ASTSettingsProfileElement::formatImpl(const FormatSettings & settings, Form
|
||||
<< applyVisitor(FieldVisitorToString{}, max_value);
|
||||
}
|
||||
|
||||
if (readonly)
|
||||
switch (type)
|
||||
{
|
||||
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << (*readonly ? " READONLY" : " WRITABLE")
|
||||
case ConstraintType::NONE:
|
||||
break;
|
||||
case ConstraintType::WRITABLE:
|
||||
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " WRITABLE"
|
||||
<< (settings.hilite ? IAST::hilite_none : "");
|
||||
break;
|
||||
case ConstraintType::CONST:
|
||||
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " READONLY"
|
||||
<< (settings.hilite ? IAST::hilite_none : "");
|
||||
break;
|
||||
case ConstraintType::CHANGEABLE_IN_READONLY:
|
||||
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " CHANGEABLE_IN_READONLY"
|
||||
<< (settings.hilite ? IAST::hilite_none : "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
namespace DB
|
||||
{
|
||||
/** Represents a settings profile's element like the following
|
||||
* {variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE]} | PROFILE 'profile_name'
|
||||
* {variable [= value] [MIN [=] min_value] [MAX [=] max_value] [CONST|READONLY|WRITABLE|CHANGEABLE_IN_READONLY]} | PROFILE 'profile_name'
|
||||
*/
|
||||
class ASTSettingsProfileElement : public IAST
|
||||
{
|
||||
@ -17,7 +17,13 @@ public:
|
||||
Field value;
|
||||
Field min_value;
|
||||
Field max_value;
|
||||
std::optional<bool> readonly;
|
||||
enum class ConstraintType {
|
||||
NONE, // default
|
||||
WRITABLE,
|
||||
CONST, // equals READONLY
|
||||
CHANGEABLE_IN_READONLY,
|
||||
};
|
||||
ConstraintType type;
|
||||
bool id_mode = false; /// If true then `parent_profile` keeps UUID, not a name.
|
||||
bool use_inherit_keyword = false; /// If true then this element is a part of ASTCreateSettingsProfileQuery.
|
||||
|
||||
@ -30,7 +36,7 @@ public:
|
||||
|
||||
|
||||
/** Represents settings profile's elements like the following
|
||||
* {{variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE]} | PROFILE 'profile_name'} [,...]
|
||||
* {{variable [= value] [MIN [=] min_value] [MAX [=] max_value] [CONST|READONLY|WRITABLE|CHANGEABLE_IN_READONLY]} | PROFILE 'profile_name'} [,...]
|
||||
*/
|
||||
class ASTSettingsProfileElements : public IAST
|
||||
{
|
||||
|
@ -40,8 +40,9 @@ void StorageSystemSettings::fillData(MutableColumns & res_columns, ContextPtr co
|
||||
res_columns[3]->insert(setting.getDescription());
|
||||
|
||||
Field min, max;
|
||||
bool read_only = false;
|
||||
constraints.get(settings, setting_name, min, max, read_only);
|
||||
bool is_const = false;
|
||||
bool changeable_in_readonly = false;
|
||||
constraints.get(settings, setting_name, min, max, is_const, changeable_in_readonly);
|
||||
|
||||
/// These two columns can accept strings only.
|
||||
if (!min.isNull())
|
||||
|
@ -29,7 +29,7 @@ NamesAndTypesList StorageSystemSettingsProfileElements::getNamesAndTypes()
|
||||
{"min", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeString>())},
|
||||
{"max", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeString>())},
|
||||
{"readonly", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeUInt8>())},
|
||||
{"allowance", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeUInt8>())},
|
||||
{"changeable_in_readonly", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeUInt8>())},
|
||||
{"inherit_profile", std::make_shared<DataTypeNullable>(std::make_shared<DataTypeString>())},
|
||||
};
|
||||
return names_and_types;
|
||||
@ -65,8 +65,8 @@ void StorageSystemSettingsProfileElements::fillData(MutableColumns & res_columns
|
||||
auto & column_max_null_map = assert_cast<ColumnNullable &>(*res_columns[i++]).getNullMapData();
|
||||
auto & column_readonly = assert_cast<ColumnUInt8 &>(assert_cast<ColumnNullable &>(*res_columns[i]).getNestedColumn()).getData();
|
||||
auto & column_readonly_null_map = assert_cast<ColumnNullable &>(*res_columns[i++]).getNullMapData();
|
||||
auto & column_allowance = assert_cast<ColumnUInt8 &>(assert_cast<ColumnNullable &>(*res_columns[i]).getNestedColumn()).getData();
|
||||
auto & column_allowance_null_map = assert_cast<ColumnNullable &>(*res_columns[i++]).getNullMapData();
|
||||
auto & column_changeable_in_readonly = assert_cast<ColumnUInt8 &>(assert_cast<ColumnNullable &>(*res_columns[i]).getNestedColumn()).getData();
|
||||
auto & column_changeable_in_readonly_null_map = assert_cast<ColumnNullable &>(*res_columns[i++]).getNullMapData();
|
||||
auto & column_inherit_profile = assert_cast<ColumnString &>(assert_cast<ColumnNullable &>(*res_columns[i]).getNestedColumn());
|
||||
auto & column_inherit_profile_null_map = assert_cast<ColumnNullable &>(*res_columns[i++]).getNullMapData();
|
||||
|
||||
@ -104,23 +104,23 @@ void StorageSystemSettingsProfileElements::fillData(MutableColumns & res_columns
|
||||
}
|
||||
|
||||
bool inserted_readonly = false;
|
||||
if (element.readonly && !element.setting_name.empty())
|
||||
if (element.is_const && !element.setting_name.empty())
|
||||
{
|
||||
column_readonly.push_back(*element.readonly);
|
||||
column_readonly_null_map.push_back(false);
|
||||
inserted_readonly = true;
|
||||
}
|
||||
|
||||
bool inserted_allowance = false;
|
||||
if (element.kind == SettingsProfileElement::RangeKind::Allow && !element.setting_name.empty())
|
||||
bool inserted_changeable_in_readonly = false;
|
||||
if (element.changeable_in_readonly && !element.setting_name.empty())
|
||||
{
|
||||
column_allowance.push_back(true);
|
||||
column_allowance_null_map.push_back(false);
|
||||
inserted_allowance = true;
|
||||
column_changeable_in_readonly.push_back(true);
|
||||
column_changeable_in_readonly_null_map.push_back(false);
|
||||
inserted_changeable_in_readonly = true;
|
||||
}
|
||||
|
||||
bool inserted_setting_name = false;
|
||||
if (inserted_value || inserted_min || inserted_max || inserted_readonly || inserted_allowance)
|
||||
if (inserted_value || inserted_min || inserted_max || inserted_readonly || inserted_changeable_in_readonly)
|
||||
{
|
||||
const auto & setting_name = element.setting_name;
|
||||
column_setting_name.insertData(setting_name.data(), setting_name.size());
|
||||
|
@ -4,5 +4,6 @@
|
||||
<on_cluster_queries_require_cluster_grant>true</on_cluster_queries_require_cluster_grant>
|
||||
<select_from_system_db_requires_grant>true</select_from_system_db_requires_grant>
|
||||
<select_from_information_schema_requires_grant>true</select_from_information_schema_requires_grant>
|
||||
<settings_constraints_replace_previous>true</settings_constraints_replace_previous>
|
||||
</access_control_improvements>
|
||||
</clickhouse>
|
||||
|
@ -24,5 +24,6 @@
|
||||
<on_cluster_queries_require_cluster_grant>true</on_cluster_queries_require_cluster_grant>
|
||||
<select_from_system_db_requires_grant>true</select_from_system_db_requires_grant>
|
||||
<select_from_information_schema_requires_grant>true</select_from_information_schema_requires_grant>
|
||||
<settings_constraints_replace_previous>true</settings_constraints_replace_previous>
|
||||
</access_control_improvements>
|
||||
</clickhouse>
|
||||
|
@ -3,5 +3,6 @@
|
||||
<users_without_row_policies_can_read_rows remove="remove"/>
|
||||
<select_from_system_db_requires_grant remove="remove"/>
|
||||
<select_from_information_schema_requires_grant remove="remove"/>
|
||||
<settings_constraints_replace_previous remove="remove"/>
|
||||
</access_control_improvements>
|
||||
</clickhouse>
|
||||
|
Loading…
Reference in New Issue
Block a user