Repository: ClickHouse/ClickHouse
File: src/Access/SettingsConstraints.cpp (C++)

Code before:
}

void SettingsConstraints::check(const Settings & current_settings, const SettingChange & change, SettingSource source) const
{
    checkImpl(current_settings, const_cast<SettingChange &>(change), THROW_ON_VIOLATION, source);
}

void SettingsConstraints::check(const Settings & current_settings, const SettingsChanges & changes, SettingSource source) const
{
    for (const auto & change : changes)
        check(current_settings, change, source);
}

void SettingsConstraints::check(const Settings & current_settings, SettingsChanges & changes, SettingSource source) const
{
    /// When `compatibility` is present, keep all settings (even if they match current values). This ensures they're applied
    /// and marked as `changed`, preventing `compatibility` from overriding explicit user values with its own defaults.
    bool has_compatibility = false;
    for (const auto & change : changes)
    {
        if (change.name == "compatibility")
        {
            has_compatibility = true;
            break;
        }
    }

    if (has_compatibility)
    {
        for (auto & change : changes)
            checkImpl(current_settings, change, THROW_ON_VIOLATION, source);
    }
    else
    {
        std::erase_if(
            changes,
            [&](SettingChange & change) -> bool
            {
                return !checkImpl(current_settings, change, THROW_ON_VIOLATION, source);
            });
    }
}

void SettingsConstraints::check(const MergeTreeSettings & current_settings, const SettingChange & change) const
{
    checkImpl(current_settings, const_cast<SettingChange &>(change), THROW_ON_VIOLATION);
}

void SettingsConstraints::check(const MergeTreeSettings & current_settings, const SettingsChanges & changes) const
{
    for (const auto & change : changes)

Review comment (bug):
```suggestion
    bool has_compatibility = changes.tryGet("compatibility") != nullptr;
```

Code after:
}

void SettingsConstraints::check(const Settings & current_settings, const SettingChange & change, SettingSource source) const
{
    checkImpl(current_settings, const_cast<SettingChange &>(change), THROW_ON_VIOLATION, source);
}

void SettingsConstraints::check(const Settings & current_settings, const SettingsChanges & changes, SettingSource source) const
{
    for (const auto & change : changes)
        check(current_settings, change, source);
}

void SettingsConstraints::check(const Settings & current_settings, SettingsChanges & changes, SettingSource source) const
{
    /// When `compatibility` is present, keep all settings (even if they match current values). This ensures they're applied
    /// and marked as `changed`, preventing `compatibility` from overriding explicit user values with its own defaults.
    if (changes.tryGet("compatibility") == nullptr)
        std::erase_if(changes, [&](SettingChange & change) { return !checkImpl(current_settings, change, THROW_ON_VIOLATION, source); });
    else
        for (auto & change : changes)
            checkImpl(current_settings, change, THROW_ON_VIOLATION, source);
}

void SettingsConstraints::check(const MergeTreeSettings & current_settings, const SettingChange & change) const
{
    checkImpl(current_settings, const_cast<SettingChange &>(change), THROW_ON_VIOLATION);
}

void SettingsConstraints::check(const MergeTreeSettings & current_settings, const SettingsChanges & changes) const
{
    for (const auto & change : changes)
        check(current_settings, change);
}

void SettingsConstraints::clamp(const Settings & current_settings, SettingsChanges & changes, SettingSource source) const
{
    std::erase_if(
        changes,
        [&](SettingChange & change) -> bool
        {
            return !checkImpl(current_settings, change, CLAMP_ON_VIOLATION, source);
        });
}

template <typename SettingsT>
bool getNewValueToCheck(const SettingsT & current_settings, SettingChange & change, Field & new_value, bool throw_on_failure)
{
    Field current_value;
    bool has_current_value = current_settings.tryGet(change.name, current_value);