Removed SET GLOBAL query. [#MTRSADMIN-3068]

It even was not supported properly in console client.
This commit is contained in:
Vitaliy Lyudvichenko 2017-06-07 15:54:35 +03:00 committed by alexey-milovidov
parent 353dba545d
commit 2167e4efdd
11 changed files with 122 additions and 56 deletions

View File

@ -128,6 +128,7 @@ struct ContextShared
std::unique_ptr<MergeTreeSettings> merge_tree_settings; /// Settings of MergeTree* engines.
size_t max_table_size_to_drop = 50000000000lu; /// Protects MergeTree tables from accidental DROP (50GB by default)
/// Named sessions. The user could specify session identifier to reuse settings and temporary tables in subsequent requests.
class SessionKeyHash
@ -498,30 +499,42 @@ ConfigurationPtr Context::getUsersConfig()
}
void Context::calculateUserSettings()
{
auto lock = getLock();
String profile = shared->users.get(client_info.current_user).profile;
/// 1) Set default settings (hardcoded values)
/// NOTE: we ignore global_context settings (from which it is usually copied)
/// NOTE: global_context settings are immutable and not auto updated
settings = Settings();
/// 2) Apply settings from default profile
auto default_profile_name = getDefaultProfileName();
if (profile != default_profile_name)
settings.setProfile(default_profile_name, *shared->users_config);
/// 3) Apply settings from current user
settings.setProfile(profile, *shared->users_config);
}
void Context::setUser(const String & name, const String & password, const Poco::Net::SocketAddress & address, const String & quota_key)
{
auto lock = getLock();
const User & user_props = shared->users.get(name, password, address.host());
/// 1) Set default (hardcoded) settings values, ignoring global_context settings from which it was copied
settings = Settings();
/// 2) Apply settings from default profile
auto default_profile_name = getDefaultProfileName();
if (user_props.profile != default_profile_name)
settings.setProfile(default_profile_name, *shared->users_config);
/// 3) Apply settings from current user
settings.setProfile(user_props.profile, *shared->users_config);
setQuota(user_props.quota, quota_key, name, address.host());
client_info.current_user = name;
client_info.current_address = address;
if (!quota_key.empty())
client_info.quota_key = quota_key;
calculateUserSettings();
setQuota(user_props.quota, quota_key, name, address.host());
}

View File

@ -138,6 +138,8 @@ public:
/// Must be called before getClientInfo.
void setUser(const String & name, const String & password, const Poco::Net::SocketAddress & address, const String & quota_key);
/// Compute and set actual user settings, client_info.current_user should be set
void calculateUserSettings();
ClientInfo & getClientInfo() { return client_info; };
const ClientInfo & getClientInfo() const { return client_info; };

View File

@ -15,20 +15,21 @@ namespace ErrorCodes
BlockIO InterpreterSetQuery::execute()
{
const ASTSetQuery & ast = typeid_cast<const ASTSetQuery &>(*query_ptr);
Context & target = ast.global ? context.getGlobalContext() : context.getSessionContext();
executeImpl(ast, target);
checkAccess(ast);
if (ast.global)
throw Exception("SET GLOBAL command is depricated", ErrorCodes::NOT_IMPLEMENTED);
Context & target = context.getSessionContext();
for (const auto & change : ast.changes)
target.setSetting(change.name, change.value);
return {};
}
void InterpreterSetQuery::executeForCurrentContext()
{
const ASTSetQuery & ast = typeid_cast<const ASTSetQuery &>(*query_ptr);
executeImpl(ast, context);
}
void InterpreterSetQuery::executeImpl(const ASTSetQuery & ast, Context & target)
void InterpreterSetQuery::checkAccess(const ASTSetQuery & ast)
{
/** The `readonly` value is understood as follows:
* 0 - everything allowed.
@ -40,12 +41,24 @@ void InterpreterSetQuery::executeImpl(const ASTSetQuery & ast, Context & target)
throw Exception("Cannot execute SET query in readonly mode", ErrorCodes::READONLY);
if (context.getSettingsRef().limits.readonly > 1)
for (ASTSetQuery::Changes::const_iterator it = ast.changes.begin(); it != ast.changes.end(); ++it)
if (it->name == "readonly")
{
for (const auto & change : ast.changes)
{
if (change.name == "readonly")
throw Exception("Cannot modify 'readonly' setting in readonly mode", ErrorCodes::READONLY);
}
}
}
for (ASTSetQuery::Changes::const_iterator it = ast.changes.begin(); it != ast.changes.end(); ++it)
target.setSetting(it->name, it->value);
void InterpreterSetQuery::executeForCurrentContext()
{
const ASTSetQuery & ast = typeid_cast<const ASTSetQuery &>(*query_ptr);
checkAccess(ast);
for (const auto & change : ast.changes)
context.setSetting(change.name, change.value);
}

View File

@ -24,6 +24,8 @@ public:
*/
BlockIO execute() override;
void checkAccess(const ASTSetQuery & ast);
/** Set setting for current context (query context).
* It is used for interpretation of SETTINGS clause in SELECT query.
*/

View File

@ -317,22 +317,22 @@ void Users::loadFromConfig(Poco::Util::AbstractConfiguration & config)
cont[key] = User(key, "users." + key, config);
}
const User & Users::get(const String & name, const String & password, const Poco::Net::IPAddress & address) const
const User & Users::get(const String & user_name, const String & password, const Poco::Net::IPAddress & address) const
{
Container::const_iterator it = cont.find(name);
auto it = cont.find(user_name);
if (cont.end() == it)
throw Exception("Unknown user " + name, ErrorCodes::UNKNOWN_USER);
throw Exception("Unknown user " + user_name, ErrorCodes::UNKNOWN_USER);
if (!it->second.addresses.contains(address))
throw Exception("User " + name + " is not allowed to connect from address " + address.toString(), ErrorCodes::IP_ADDRESS_NOT_ALLOWED);
throw Exception("User " + user_name + " is not allowed to connect from address " + address.toString(), ErrorCodes::IP_ADDRESS_NOT_ALLOWED);
auto on_wrong_password = [&]()
{
if (password.empty())
throw Exception("Password required for user " + name, ErrorCodes::REQUIRED_PASSWORD);
throw Exception("Password required for user " + user_name, ErrorCodes::REQUIRED_PASSWORD);
else
throw Exception("Wrong password for user " + name, ErrorCodes::WRONG_PASSWORD);
throw Exception("Wrong password for user " + user_name, ErrorCodes::WRONG_PASSWORD);
};
if (!it->second.password_sha256_hex.empty())
@ -364,6 +364,18 @@ const User & Users::get(const String & name, const String & password, const Poco
return it->second;
}
const User & Users::get(const String & user_name)
{
auto it = cont.find(user_name);
if (cont.end() == it)
throw Exception("Unknown user " + user_name, ErrorCodes::UNKNOWN_USER);
return it->second;
}
bool Users::isAllowedDatabase(const std::string & user_name, const std::string & database_name) const
{
auto it = cont.find(user_name);

View File

@ -83,10 +83,14 @@ private:
public:
void loadFromConfig(Poco::Util::AbstractConfiguration & config);
const User & get(const String & name, const String & password, const Poco::Net::IPAddress & address) const;
/// Find user and make authorize checks
const User & get(const String & user_name, const String & password, const Poco::Net::IPAddress & address) const;
/// Just find user
const User & get(const String & user_name);
/// Check if the user has access to the database.
bool isAllowedDatabase(const std::string & user_name, const std::string & database_name) const;
bool isAllowedDatabase(const String & user_name, const String & database_name) const;
};

View File

@ -642,12 +642,12 @@ private:
if (set_query)
{
/// Save all changes in settings to avoid losing them if the connection is lost.
for (ASTSetQuery::Changes::const_iterator it = set_query->changes.begin(); it != set_query->changes.end(); ++it)
for (const auto & change : set_query->changes)
{
if (it->name == "profile")
current_profile = it->value.safeGet<String>();
if (change.name == "profile")
current_profile = change.value.safeGet<String>();
else
context.setSetting(it->name, it->value);
context.setSetting(change.name, change.value);
}
}

View File

@ -1,7 +1,27 @@
Settings
========
In this section, we review settings that you can make using a SET query or in a config file. Remember that these settings can be set for a session or globally. Settings that can only be made in the server config file are not covered here.
In this section, we review settings that you can make using a SET query or in a config file.
Remember that these settings can be set for a session or globally.
Settings that can only be made in the server config file are not covered here.
There are three ways to setup settings (sorted by priority):
* Settings in server configuration files.
They are set in user profiles.
* Session-level settings.
Use ``SET setting=value`` command in ClickHouse console client running in interactive mode.
Also sessions are supported in HTTP interface (you need to pass ``session_id`` HTTP parameter)
* Query-level settings.
Use ``--setting=value`` command line parameters in non-iteractive mode of ClickHouse console client.
Use HTTP parameters (``URL?setting_1=value&setting_2=value...``) with HTTP ClickHouse interface.
.. toctree::
:glob:

View File

@ -518,10 +518,8 @@ SET
Lets you set the 'param' setting to 'value'. You can also make all the settings from the specified settings profile in a single query. To do this, specify 'profile' as the setting name. For more information, see the section "Settings". The setting is made for the session, or for the server (globally) if GLOBAL is specified.
When making a global setting, the setting is not applied to sessions already running, including the current session. It will only be used for new sessions.
Settings made using SET GLOBAL have a lower priority compared with settings made in the config file in the user profile. In other words, user settings can't be overridden by SET GLOBAL.
When the server is restarted, global settings made using SET GLOBAL are lost.
To make settings that persist after a server restart, you can only use the server's config file. (This can't be done using a SET query.)
When the server is restarted, settings made using SET are lost.
To make settings that persist after a server restart, you can only use the server's config file.
OPTIMIZE
~~~~~~~~

View File

@ -1,22 +1,25 @@
Настройки
=========
Описанные в разделе настройки могут быть заданы следующими способами:
Все настройки, описанные ниже, могут быть заданы несколькими способами.
Настройки задаются послойно, т.е. каждый следующий слой перезаписывает предыдущие настройки.
* Глобально.
Способы задания настроек, упорядоченные по их приоритету:
В конфигурационных файлах сервера.
* Настройки в конфигурационных файлах сервера.
Задаются через профили пользователей.
* Для сессии.
При запуске консольного клиента ClickHouse в интерактивном режиме отправьте запрос ``SET setting=value``.
Из консольного клиента ClickHouse в интерактивном режиме отправьте запрос ``SET setting=value``.
Аналогично можно использовать ClickHouse-сессии в HTTP-протоколе, для этого необходимо указывать HTTP-праметр ``session_id``.
* Для запроса.
* При запуске консольного клиента ClickHouse в неинтерактивном режиме установите параметр запуска ``--setting=value``.
* При использовании HTTP API передавайте cgi-параметры (``URL?setting_1=value&setting_2=value...``).
Настройки, которые можно задать только в конфигурационном файле сервера, в разделе не рассматриваются.
.. toctree::

View File

@ -524,16 +524,15 @@ SET
.. code-block:: sql
SET [GLOBAL] param = value
SET param = value
Позволяет установить настройку ``param`` в значение ``value``. Также можно одним запросом установить все настройки из заданного профиля настроек - для этого, укажите в качестве имени настройки profile. Подробнее смотри раздел "Настройки".
Настройка устанавливается на сессию, или на сервер (глобально), если указано ``GLOBAL``.
При установке глобальной настройки, настройка на все уже запущенные сессии, включая текущую сессию, не устанавливается, а будет использована только для новых сессий.
Настройки, заданные с помощью ``SET GLOBAL`` имеют меньший приоритет по сравнению с настройками, указанными в профиле пользователя, в конфигурационном файле. То есть, переопределить такие настройки с помощью ``SET GLOBAL`` невозможно.
При перезапуске сервера, теряются глобальные настройки, установленные с помощью ``SET GLOBAL``.
Установить настройки, которые переживут перезапуск сервера, можно только с помощью конфигурационного файла сервера. (Это не может быть сделано с помощью запроса ``SET``.)
При перезапуске сервера, теряются настройки, установленные с помощью ``SET``.
Установить настройки, которые переживут перезапуск сервера, можно только с помощью конфигурационного файла сервера.
OPTIMIZE
~~~~~~~~