mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-20 00:30:49 +00:00
fix build, fix docs, fix comments, logical fixes, test are still to be fixed and new test are to be added
This commit is contained in:
parent
7fec55eea4
commit
014d109175
@ -26,15 +26,33 @@ The constraints are defined as the following:
|
||||
<setting_name_4>
|
||||
<readonly/>
|
||||
</setting_name_4>
|
||||
<setting_name_5>
|
||||
<min>lower_boundary</min>
|
||||
<max>upper_boundary</max>
|
||||
<changeable_in_readonly/>
|
||||
</setting_name_5>
|
||||
</constraints>
|
||||
</user_name>
|
||||
</profiles>
|
||||
```
|
||||
|
||||
If the user tries to violate the constraints an exception is thrown and the setting isn’t changed.
|
||||
There are supported three types of constraints: `min`, `max`, `readonly`. The `min` and `max` constraints specify upper and lower boundaries for a numeric setting and can be used in combination. The `readonly` constraint specifies that the user cannot change the corresponding setting at all.
|
||||
There are supported few types of constraints: `min`, `max`, `readonly` (with alias `const`) and `changeable_in_readonly`. The `min` and `max` constraints specify upper and lower boundaries for a numeric setting and can be used in combination. The `readonly` or `const` constraint specifies that the user cannot change the corresponding setting at all. The `changeable_in_readonly` constraint type allows user to change the setting within `min`/`max` range even if `readonly` setting is set to 1, otherwise settings are not allow to be changed in `readonly=1` mode. Note that `changeable_in_readonly` is supported only if `settings_constraints_replace_previous` is enabled:
|
||||
``` xml
|
||||
<access_control_improvements>
|
||||
<settings_constraints_replace_previous>true<settings_constraints_replace_previous>
|
||||
</access_control_improvements>
|
||||
```
|
||||
|
||||
If there are multiple profiles active for a user, then constraints are merged. Merge process depends on `settings_constraints_replace_previous`:
|
||||
- **true** (recommended): constraints for the same setting are replaced during merge, such that the last constraint is used and all previous are ignored including fields that are not set in new constraint.
|
||||
- **false** (default): constraints for the same setting are merged in a way that every not set type of constraint is taken from previous profile and every set type of constraint is replaced by value from new profile.
|
||||
|
||||
Read-only mode is enabled by `readonly` setting (not to confuse with `readonly` constraint type):
|
||||
- `readonly=0`: No read-only restrictions.
|
||||
- `readonly=1`: Only read queries are allowed and settings cannot be changes unless `changeable_in_readonly` is set.
|
||||
- `readonly=2`: Only read queries are allowed, but settings can be changed, except for `readonly` setting itself.
|
||||
|
||||
If there are multiple profiles active for a user, then constraints are merged. Constraints for the same setting are replaced during merge, such that the last constraint is used and all previous are ignored.
|
||||
|
||||
**Example:** Let `users.xml` includes lines:
|
||||
|
||||
@ -71,38 +89,6 @@ Code: 452, e.displayText() = DB::Exception: Setting max_memory_usage should not
|
||||
Code: 452, e.displayText() = DB::Exception: Setting force_index_by_date should not be changed.
|
||||
```
|
||||
|
||||
## Allowances in read-only mode {#settings-readonly-allowance}
|
||||
Read-only mode is enabled by `readonly` setting:
|
||||
- `readonly=0`: No read-only restrictions.
|
||||
- `readonly=1`: Only read queries are allowed and settings cannot be changes unless explicitly allowed.
|
||||
- `readonly=2`: Only read queries are allowed, but settings can be changed, except for `readonly` setting itself.
|
||||
|
||||
In `readonly=0` and `readonly=2` modes settings constraints are applied as usual. But in `readonly=1` by default all settings changes are forbidden and constraints are ignored. But special allowances can be set in the following way:
|
||||
``` xml
|
||||
<profiles>
|
||||
<user_name>
|
||||
<allow>
|
||||
<setting_name_1>
|
||||
<min>lower_boundary</min>
|
||||
</setting_name_1>
|
||||
<setting_name_2>
|
||||
<max>upper_boundary</max>
|
||||
</setting_name_2>
|
||||
<setting_name_3>
|
||||
<min>lower_boundary</min>
|
||||
<max>upper_boundary</max>
|
||||
</setting_name_3>
|
||||
<setting_name_4>
|
||||
<readonly/>
|
||||
</setting_name_4>
|
||||
<setting_name_5/><!-- allow any value -->
|
||||
</allow>
|
||||
</user_name>
|
||||
</profiles>
|
||||
```
|
||||
|
||||
Constraints and allowances are merged from multiple profiles independently. Previous constraint is not canceled by new allowance, as well as previous allowance is not canceled by new constraint. Instead profile can have one allowance and one constraint for every setting. Allowances are used in `readonly=1` mode, otherwise constraints are used.
|
||||
|
||||
**Note:** the `default` profile has special handling: all the constraints defined for the `default` profile become the default constraints, so they restrict all the users until they’re overridden explicitly for these users.
|
||||
|
||||
[Original article](https://clickhouse.com/docs/en/operations/settings/constraints_on_settings/) <!--hide-->
|
||||
|
@ -644,7 +644,8 @@
|
||||
<!-- 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. -->
|
||||
actions of previous constraint (defined in other profiles) for the same specific setting, including fields that are not set by new constraint.
|
||||
Also it enables 'changeable_in_readonly' constraint type -->
|
||||
<settings_constraints_replace_previous>false</settings_constraints_replace_previous>
|
||||
</access_control_improvements>
|
||||
|
||||
|
@ -66,7 +66,7 @@ void SettingsConstraints::get(const Settings & current_settings, std::string_vie
|
||||
|
||||
void SettingsConstraints::merge(const SettingsConstraints & other)
|
||||
{
|
||||
if (access_control.doesSettingsConstraintsReplacePrevious())
|
||||
if (access_control->doesSettingsConstraintsReplacePrevious())
|
||||
{
|
||||
for (const auto & [other_name, other_constraint] : other.constraints)
|
||||
constraints[other_name] = other_constraint;
|
||||
|
@ -140,7 +140,7 @@ private:
|
||||
using RangeMap = std::unordered_map<String, Range, StringHash, std::equal_to<>>;
|
||||
RangeMap constraints;
|
||||
|
||||
const AccessControl * access_control = nullptr;
|
||||
const AccessControl * access_control;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -69,6 +69,8 @@ void SettingsProfileElement::init(const ASTSettingsProfileElement & ast, const A
|
||||
is_const.emplace(true);
|
||||
break;
|
||||
case ASTSettingsProfileElement::ConstraintType::CHANGEABLE_IN_READONLY:
|
||||
if (!access_control->doesSettingsConstraintsReplacePrevious())
|
||||
throw Exception("CHANGEABLE_IN_READONLY for " + setting_name + " is not allowed unless settings_constraints_replace_previous is enabled", ErrorCodes::NOT_IMPLEMENTED);
|
||||
is_const.reset();
|
||||
changeable_in_readonly = true;
|
||||
break;
|
||||
@ -96,7 +98,12 @@ std::shared_ptr<ASTSettingsProfileElement> SettingsProfileElement::toAST() const
|
||||
ast->value = value;
|
||||
ast->min_value = min_value;
|
||||
ast->max_value = max_value;
|
||||
ast->readonly = readonly;
|
||||
if (changeable_in_readonly)
|
||||
ast->type = ASTSettingsProfileElement::ConstraintType::CHANGEABLE_IN_READONLY;
|
||||
if (is_const.has_value())
|
||||
ast->type = *is_const ? ASTSettingsProfileElement::ConstraintType::CONST : ASTSettingsProfileElement::ConstraintType::WRITABLE;
|
||||
else
|
||||
ast->type = ASTSettingsProfileElement::ConstraintType::NONE;
|
||||
|
||||
return ast;
|
||||
}
|
||||
@ -117,7 +124,12 @@ std::shared_ptr<ASTSettingsProfileElement> SettingsProfileElement::toASTWithName
|
||||
ast->value = value;
|
||||
ast->min_value = min_value;
|
||||
ast->max_value = max_value;
|
||||
ast->readonly = readonly;
|
||||
if (changeable_in_readonly)
|
||||
ast->type = ASTSettingsProfileElement::ConstraintType::CHANGEABLE_IN_READONLY;
|
||||
if (is_const.has_value())
|
||||
ast->type = *is_const ? ASTSettingsProfileElement::ConstraintType::CONST : ASTSettingsProfileElement::ConstraintType::WRITABLE;
|
||||
else
|
||||
ast->type = ASTSettingsProfileElement::ConstraintType::NONE;
|
||||
|
||||
return ast;
|
||||
}
|
||||
|
@ -425,8 +425,7 @@ namespace
|
||||
|
||||
SettingsProfileElements parseSettingsConstraints(const Poco::Util::AbstractConfiguration & config,
|
||||
const String & path_to_constraints,
|
||||
const AccessControl & access_control,
|
||||
SettingsProfileElement::RangeKind kind)
|
||||
const AccessControl & access_control)
|
||||
{
|
||||
SettingsProfileElements profile_elements;
|
||||
Poco::Util::AbstractConfiguration::Keys keys;
|
||||
@ -438,7 +437,6 @@ namespace
|
||||
|
||||
SettingsProfileElement profile_element;
|
||||
profile_element.setting_name = setting_name;
|
||||
profile_element.kind = kind;
|
||||
Poco::Util::AbstractConfiguration::Keys constraint_types;
|
||||
String path_to_name = path_to_constraints + "." + setting_name;
|
||||
config.keys(path_to_name, constraint_types);
|
||||
@ -449,11 +447,21 @@ namespace
|
||||
profile_element.min_value = Settings::stringToValueUtil(setting_name, config.getString(path_to_name + "." + constraint_type));
|
||||
else if (constraint_type == "max")
|
||||
profile_element.max_value = Settings::stringToValueUtil(setting_name, config.getString(path_to_name + "." + constraint_type));
|
||||
else if (constraint_type == "readonly")
|
||||
profile_element.readonly = true;
|
||||
else if (constraint_type == "readonly" || constraint_type == "const")
|
||||
profile_element.is_const = true;
|
||||
else if (constraint_type == "changeable_in_readonly")
|
||||
{
|
||||
if (access_control.doesSettingsConstraintsReplacePrevious())
|
||||
profile_element.changeable_in_readonly = true;
|
||||
else
|
||||
throw Exception("Setting changeable_in_readonly for " + setting_name + " is not allowed unless settings_constraints_replace_previous is enabled", ErrorCodes::NOT_IMPLEMENTED);
|
||||
}
|
||||
else
|
||||
throw Exception("Setting " + constraint_type + " value for " + setting_name + " isn't supported", ErrorCodes::NOT_IMPLEMENTED);
|
||||
}
|
||||
if (profile_element.is_const && profile_element.changeable_in_readonly)
|
||||
throw Exception("Both settings changeable_in_readonly and const/readonly cannot be used for " + setting_name, ErrorCodes::NOT_IMPLEMENTED);
|
||||
|
||||
profile_elements.push_back(std::move(profile_element));
|
||||
}
|
||||
|
||||
@ -489,13 +497,7 @@ namespace
|
||||
|
||||
if (key == "constraints" || key.starts_with("constraints["))
|
||||
{
|
||||
profile->elements.merge(parseSettingsConstraints(config, profile_config + "." + key, access_control, SettingsProfileElement::RangeKind::Constrain));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key == "allow" || key.starts_with("allow["))
|
||||
{
|
||||
profile->elements.merge(parseSettingsConstraints(config, profile_config + "." + key, access_control, SettingsProfileElement::RangeKind::Allow));
|
||||
profile->elements.merge(parseSettingsConstraints(config, profile_config + "." + key, access_control));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -95,18 +95,23 @@ namespace
|
||||
}
|
||||
|
||||
|
||||
bool parseReadonlyOrWritableKeyword(IParserBase::Pos & pos, Expected & expected, std::optional<bool> & readonly)
|
||||
bool parseConstraintTypeKeyword(IParserBase::Pos & pos, Expected & expected, ASTSettingsProfileElement::ConstraintType & type)
|
||||
{
|
||||
return IParserBase::wrapParseImpl(pos, [&]
|
||||
{
|
||||
if (ParserKeyword{"READONLY"}.ignore(pos, expected))
|
||||
if (ParserKeyword{"READONLY"}.ignore(pos, expected) || ParserKeyword{"CONST"}.ignore(pos, expected))
|
||||
{
|
||||
readonly = true;
|
||||
type = ASTSettingsProfileElement::ConstraintType::CONST;
|
||||
return true;
|
||||
}
|
||||
else if (ParserKeyword{"WRITABLE"}.ignore(pos, expected))
|
||||
{
|
||||
readonly = false;
|
||||
type = ASTSettingsProfileElement::ConstraintType::WRITABLE;
|
||||
return true;
|
||||
}
|
||||
else if (ParserKeyword{"CHANGEABLE_IN_READONLY"}.ignore(pos, expected))
|
||||
{
|
||||
type = ASTSettingsProfileElement::ConstraintType::CHANGEABLE_IN_READONLY;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -122,7 +127,7 @@ namespace
|
||||
Field & value,
|
||||
Field & min_value,
|
||||
Field & max_value,
|
||||
std::optional<bool> & readonly)
|
||||
ASTSettingsProfileElement::ConstraintType & type)
|
||||
{
|
||||
return IParserBase::wrapParseImpl(pos, [&]
|
||||
{
|
||||
@ -134,11 +139,11 @@ namespace
|
||||
Field res_value;
|
||||
Field res_min_value;
|
||||
Field res_max_value;
|
||||
std::optional<bool> res_readonly;
|
||||
ASTSettingsProfileElement::ConstraintType res_type;
|
||||
|
||||
bool has_value_or_constraint = false;
|
||||
while (parseValue(pos, expected, res_value) || parseMinMaxValue(pos, expected, res_min_value, res_max_value)
|
||||
|| parseReadonlyOrWritableKeyword(pos, expected, res_readonly))
|
||||
|| parseConstraintTypeKeyword(pos, expected, res_type))
|
||||
{
|
||||
has_value_or_constraint = true;
|
||||
}
|
||||
@ -147,7 +152,7 @@ namespace
|
||||
return false;
|
||||
|
||||
if (boost::iequals(res_setting_name, "PROFILE") && res_value.isNull() && res_min_value.isNull() && res_max_value.isNull()
|
||||
&& res_readonly)
|
||||
&& res_type == ASTSettingsProfileElement::ConstraintType::CONST)
|
||||
{
|
||||
/// Ambiguity: "profile readonly" can be treated either as a profile named "readonly" or
|
||||
/// as a setting named 'profile' with the readonly constraint.
|
||||
@ -159,7 +164,7 @@ namespace
|
||||
value = std::move(res_value);
|
||||
min_value = std::move(res_min_value);
|
||||
max_value = std::move(res_max_value);
|
||||
readonly = res_readonly;
|
||||
type = res_type;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@ -179,9 +184,9 @@ namespace
|
||||
Field value;
|
||||
Field min_value;
|
||||
Field max_value;
|
||||
std::optional<bool> readonly;
|
||||
ASTSettingsProfileElement::ConstraintType type;
|
||||
|
||||
bool ok = parseSettingNameWithValueOrConstraints(pos, expected, setting_name, value, min_value, max_value, readonly);
|
||||
bool ok = parseSettingNameWithValueOrConstraints(pos, expected, setting_name, value, min_value, max_value, type);
|
||||
|
||||
if (!ok && (parseProfileKeyword(pos, expected, use_inherit_keyword) || previous_element_was_parent_profile))
|
||||
ok = parseProfileNameOrID(pos, expected, id_mode, parent_profile);
|
||||
@ -195,7 +200,7 @@ namespace
|
||||
result->value = std::move(value);
|
||||
result->min_value = std::move(min_value);
|
||||
result->max_value = std::move(max_value);
|
||||
result->readonly = readonly;
|
||||
result->type = type;
|
||||
result->id_mode = id_mode;
|
||||
result->use_inherit_keyword = use_inherit_keyword;
|
||||
return true;
|
||||
|
@ -41,8 +41,7 @@ void StorageSystemSettings::fillData(MutableColumns & res_columns, ContextPtr co
|
||||
|
||||
Field min, max;
|
||||
bool is_const = false;
|
||||
bool changeable_in_readonly = false;
|
||||
constraints.get(settings, setting_name, min, max, is_const, changeable_in_readonly);
|
||||
constraints.get(settings, setting_name, min, max, is_const);
|
||||
|
||||
/// These two columns can accept strings only.
|
||||
if (!min.isNull())
|
||||
@ -52,7 +51,7 @@ void StorageSystemSettings::fillData(MutableColumns & res_columns, ContextPtr co
|
||||
|
||||
res_columns[4]->insert(min);
|
||||
res_columns[5]->insert(max);
|
||||
res_columns[6]->insert(read_only);
|
||||
res_columns[6]->insert(is_const);
|
||||
res_columns[7]->insert(setting.getTypeName());
|
||||
}
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ void StorageSystemSettingsProfileElements::fillData(MutableColumns & res_columns
|
||||
bool inserted_readonly = false;
|
||||
if (element.is_const && !element.setting_name.empty())
|
||||
{
|
||||
column_readonly.push_back(*element.readonly);
|
||||
column_readonly.push_back(*element.is_const);
|
||||
column_readonly_null_map.push_back(false);
|
||||
inserted_readonly = true;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user