mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
dbms: added optional section SETTINGS to SELECT query [#METR-16354].
This commit is contained in:
parent
cac3ce7e27
commit
854a2f4cc8
@ -130,6 +130,18 @@ private:
|
||||
|
||||
void ignoreWithTotals();
|
||||
|
||||
/** Если в запросе SELECT есть секция SETTINGS, то применить настройки из неё и удалить секцию SETTINGS.
|
||||
* Затем достать настройки из context и поместить их в settings.
|
||||
*
|
||||
* Секция SETTINGS - настройки для конкретного запроса.
|
||||
* Обычно настройки могут быть переданы другими способами, не внутри запроса.
|
||||
* Но использование такой секции оправдано, если нужно задать настройки для одного подзапроса.
|
||||
*
|
||||
* При распределённой обработке запроса, секция SETTINGS не будет передана внутри запроса,
|
||||
* а настройки будут переданы отдельно, при отправке запроса.
|
||||
*/
|
||||
void initSettings();
|
||||
|
||||
ASTPtr query_ptr;
|
||||
ASTSelectQuery & query;
|
||||
Context context;
|
||||
|
@ -8,7 +8,7 @@ namespace DB
|
||||
{
|
||||
|
||||
|
||||
/** Установить один или несколько параметров, для сессии или глобально.
|
||||
/** Установить один или несколько параметров, для сессии или глобально... или для текущего запроса.
|
||||
*/
|
||||
class InterpreterSetQuery
|
||||
{
|
||||
@ -16,17 +16,36 @@ public:
|
||||
InterpreterSetQuery(ASTPtr query_ptr_, Context & context_)
|
||||
: query_ptr(query_ptr_), context(context_) {}
|
||||
|
||||
|
||||
/** Обычный запрос SET. Задать настройку на сессию или глобальную (если указано GLOBAL).
|
||||
*/
|
||||
void execute()
|
||||
{
|
||||
ASTSetQuery & ast = typeid_cast<ASTSetQuery &>(*query_ptr);
|
||||
|
||||
Context & target = ast.global ? context.getGlobalContext() : context.getSessionContext();
|
||||
executeImpl(ast, target);
|
||||
}
|
||||
|
||||
/** Задать настроку для текущего контекста (контекста запроса).
|
||||
* Используется для интерпретации секции SETTINGS в запросе SELECT.
|
||||
*/
|
||||
void executeForCurrentContext()
|
||||
{
|
||||
ASTSetQuery & ast = typeid_cast<ASTSetQuery &>(*query_ptr);
|
||||
executeImpl(ast, context);
|
||||
}
|
||||
|
||||
private:
|
||||
ASTPtr query_ptr;
|
||||
Context & context;
|
||||
|
||||
void executeImpl(ASTSetQuery & ast, Context & target)
|
||||
{
|
||||
/** Значение readonly понимается следующим образом:
|
||||
* 0 - можно всё.
|
||||
* 1 - можно делать только запросы на чтение; в том числе, нельзя менять настройки.
|
||||
* 2 - можно делать только запросы на чтение и можно менять настройки, кроме настройки readonly.
|
||||
*/
|
||||
* 0 - можно всё.
|
||||
* 1 - можно делать только запросы на чтение; в том числе, нельзя менять настройки.
|
||||
* 2 - можно делать только запросы на чтение и можно менять настройки, кроме настройки readonly.
|
||||
*/
|
||||
|
||||
if (context.getSettingsRef().limits.readonly == 1)
|
||||
throw Exception("Cannot execute SET query in readonly mode", ErrorCodes::READONLY);
|
||||
@ -39,10 +58,6 @@ public:
|
||||
for (ASTSetQuery::Changes::const_iterator it = ast.changes.begin(); it != ast.changes.end(); ++it)
|
||||
target.setSetting(it->name, it->value);
|
||||
}
|
||||
|
||||
private:
|
||||
ASTPtr query_ptr;
|
||||
Context & context;
|
||||
};
|
||||
|
||||
|
||||
|
@ -51,6 +51,7 @@ public:
|
||||
ASTPtr order_expression_list;
|
||||
ASTPtr limit_offset;
|
||||
ASTPtr limit_length;
|
||||
ASTPtr settings;
|
||||
ASTPtr next_union_all; /// Следующий запрос SELECT в цепочке UNION ALL, если такой есть
|
||||
};
|
||||
|
||||
|
@ -12,9 +12,15 @@ namespace DB
|
||||
*/
|
||||
class ParserSetQuery : public IParserBase
|
||||
{
|
||||
public:
|
||||
ParserSetQuery(bool parse_only_internals_ = false) : parse_only_internals(parse_only_internals_) {}
|
||||
|
||||
protected:
|
||||
const char * getName() const { return "SET query"; }
|
||||
bool parseImpl(Pos & pos, Pos end, ASTPtr & node, Pos & max_parsed_pos, Expected & expected);
|
||||
|
||||
/// Парсить список name = value пар, без SET [GLOBAL].
|
||||
bool parse_only_internals;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <DB/Parsers/ASTOrderByElement.h>
|
||||
|
||||
#include <DB/Interpreters/InterpreterSelectQuery.h>
|
||||
#include <DB/Interpreters/InterpreterSetQuery.h>
|
||||
#include <DB/Interpreters/ExpressionAnalyzer.h>
|
||||
#include <DB/Storages/StorageView.h>
|
||||
#include <DB/TableFunctions/ITableFunction.h>
|
||||
@ -39,10 +40,12 @@ InterpreterSelectQuery::~InterpreterSelectQuery() = default;
|
||||
|
||||
void InterpreterSelectQuery::init(BlockInputStreamPtr input, const Names & required_column_names, const NamesAndTypesList & table_column_names)
|
||||
{
|
||||
original_max_threads = settings.max_threads;
|
||||
|
||||
ProfileEvents::increment(ProfileEvents::SelectQuery);
|
||||
|
||||
initSettings();
|
||||
|
||||
original_max_threads = settings.max_threads;
|
||||
|
||||
if (settings.limits.max_subquery_depth && subquery_depth > settings.limits.max_subquery_depth)
|
||||
throw Exception("Too deep subqueries. Maximum: " + toString(settings.limits.max_subquery_depth),
|
||||
ErrorCodes::TOO_DEEP_SUBQUERIES);
|
||||
@ -174,7 +177,7 @@ void InterpreterSelectQuery::initQueryAnalyzer()
|
||||
InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context & context_, QueryProcessingStage::Enum to_stage_,
|
||||
size_t subquery_depth_, BlockInputStreamPtr input_, bool is_union_all_head_)
|
||||
: query_ptr(query_ptr_), query(typeid_cast<ASTSelectQuery &>(*query_ptr)),
|
||||
context(context_), settings(context.getSettings()), to_stage(to_stage_), subquery_depth(subquery_depth_),
|
||||
context(context_), to_stage(to_stage_), subquery_depth(subquery_depth_),
|
||||
is_first_select_inside_union_all(is_union_all_head_ && !query.next_union_all.isNull()),
|
||||
log(&Logger::get("InterpreterSelectQuery"))
|
||||
{
|
||||
@ -185,7 +188,7 @@ InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context
|
||||
const Names & required_column_names_,
|
||||
QueryProcessingStage::Enum to_stage_, size_t subquery_depth_, BlockInputStreamPtr input_)
|
||||
: query_ptr(query_ptr_), query(typeid_cast<ASTSelectQuery &>(*query_ptr)),
|
||||
context(context_), settings(context.getSettings()), to_stage(to_stage_), subquery_depth(subquery_depth_),
|
||||
context(context_), to_stage(to_stage_), subquery_depth(subquery_depth_),
|
||||
is_first_select_inside_union_all(!query.next_union_all.isNull()),
|
||||
log(&Logger::get("InterpreterSelectQuery"))
|
||||
{
|
||||
@ -196,7 +199,7 @@ InterpreterSelectQuery::InterpreterSelectQuery(ASTPtr query_ptr_, const Context
|
||||
const Names & required_column_names_,
|
||||
const NamesAndTypesList & table_column_names, QueryProcessingStage::Enum to_stage_, size_t subquery_depth_, BlockInputStreamPtr input_)
|
||||
: query_ptr(query_ptr_), query(typeid_cast<ASTSelectQuery &>(*query_ptr)),
|
||||
context(context_), settings(context.getSettings()), to_stage(to_stage_), subquery_depth(subquery_depth_),
|
||||
context(context_), to_stage(to_stage_), subquery_depth(subquery_depth_),
|
||||
is_first_select_inside_union_all(!query.next_union_all.isNull()),
|
||||
log(&Logger::get("InterpreterSelectQuery"))
|
||||
{
|
||||
@ -1028,4 +1031,21 @@ void InterpreterSelectQuery::ignoreWithTotals()
|
||||
}
|
||||
|
||||
|
||||
void InterpreterSelectQuery::initSettings()
|
||||
{
|
||||
if (query.settings)
|
||||
{
|
||||
InterpreterSetQuery(query.settings, context).executeForCurrentContext();
|
||||
|
||||
auto it = std::find(query.children.begin(), query.children.end(), query.settings);
|
||||
if (query.children.end() == it)
|
||||
throw Exception("Logical error: cannot find query.settings element in query.children", ErrorCodes::LOGICAL_ERROR);
|
||||
|
||||
query.children.erase(it);
|
||||
query.settings = nullptr;
|
||||
}
|
||||
|
||||
settings = context.getSettings();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -164,6 +164,7 @@ ASTPtr ASTSelectQuery::clone() const
|
||||
CLONE(order_expression_list)
|
||||
CLONE(limit_offset)
|
||||
CLONE(limit_length)
|
||||
CLONE(settings)
|
||||
CLONE(format)
|
||||
CLONE(next_union_all)
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <DB/Parsers/ExpressionElementParsers.h>
|
||||
#include <DB/Parsers/ExpressionListParsers.h>
|
||||
#include <DB/Parsers/ParserJoin.h>
|
||||
#include <DB/Parsers/ParserSetQuery.h>
|
||||
#include <DB/Parsers/ParserSelectQuery.h>
|
||||
|
||||
|
||||
@ -37,6 +38,7 @@ bool ParserSelectQuery::parseImpl(Pos & pos, Pos end, ASTPtr & node, Pos & max_p
|
||||
ParserString s_having("HAVING", true, true);
|
||||
ParserString s_order("ORDER", true, true);
|
||||
ParserString s_limit("LIMIT", true, true);
|
||||
ParserString s_settings("SETTINGS", true, true);
|
||||
ParserString s_format("FORMAT", true, true);
|
||||
ParserString s_union("UNION", true, true);
|
||||
ParserString s_all("ALL", true, true);
|
||||
@ -281,6 +283,19 @@ bool ParserSelectQuery::parseImpl(Pos & pos, Pos end, ASTPtr & node, Pos & max_p
|
||||
}
|
||||
}
|
||||
|
||||
/// SETTINGS key1 = value1, key2 = value2, ...
|
||||
if (s_settings.ignore(pos, end, max_parsed_pos, expected))
|
||||
{
|
||||
ws.ignore(pos, end);
|
||||
|
||||
ParserSetQuery parser_settings(true);
|
||||
|
||||
if (!parser_settings.parse(pos, end, select_query->settings, max_parsed_pos, expected))
|
||||
return false;
|
||||
|
||||
ws.ignore(pos, end);
|
||||
}
|
||||
|
||||
/// FORMAT format_name
|
||||
if (s_format.ignore(pos, end, max_parsed_pos, expected))
|
||||
{
|
||||
@ -339,6 +354,8 @@ bool ParserSelectQuery::parseImpl(Pos & pos, Pos end, ASTPtr & node, Pos & max_p
|
||||
select_query->children.push_back(select_query->limit_offset);
|
||||
if (select_query->limit_length)
|
||||
select_query->children.push_back(select_query->limit_length);
|
||||
if (select_query->settings)
|
||||
select_query->children.push_back(select_query->settings);
|
||||
if (select_query->format)
|
||||
select_query->children.push_back(select_query->format);
|
||||
if (select_query->next_union_all)
|
||||
|
@ -50,18 +50,24 @@ bool ParserSetQuery::parseImpl(Pos & pos, Pos end, ASTPtr & node, Pos & max_pars
|
||||
Pos begin = pos;
|
||||
|
||||
ParserWhiteSpaceOrComments ws;
|
||||
ParserString s_set("SET", true, true);
|
||||
ParserString s_global("GLOBAL", true, true);
|
||||
ParserString s_comma(",");
|
||||
|
||||
ws.ignore(pos, end);
|
||||
bool global = false;
|
||||
|
||||
if (!s_set.ignore(pos, end, max_parsed_pos, expected))
|
||||
return false;
|
||||
if (!parse_only_internals)
|
||||
{
|
||||
ParserString s_set("SET", true, true);
|
||||
ParserString s_global("GLOBAL", true, true);
|
||||
|
||||
ws.ignore(pos, end);
|
||||
ws.ignore(pos, end);
|
||||
|
||||
bool global = s_global.ignore(pos, end, max_parsed_pos, expected);
|
||||
if (!s_set.ignore(pos, end, max_parsed_pos, expected))
|
||||
return false;
|
||||
|
||||
ws.ignore(pos, end);
|
||||
|
||||
global = s_global.ignore(pos, end, max_parsed_pos, expected);
|
||||
}
|
||||
|
||||
ASTSetQuery::Changes changes;
|
||||
|
||||
|
@ -211,6 +211,20 @@ void formatAST(const ASTSelectQuery & ast, std::ostream & s, size_t indent, bo
|
||||
formatAST(*ast.limit_length, s, indent, hilite, one_line);
|
||||
}
|
||||
|
||||
if (ast.settings)
|
||||
{
|
||||
s << (hilite ? hilite_keyword : "") << nl_or_ws << indent_str << "SETTINGS " << (hilite ? hilite_none : "");
|
||||
|
||||
const ASTSetQuery & ast_set = typeid_cast<const ASTSetQuery &>(*ast.settings);
|
||||
for (ASTSetQuery::Changes::const_iterator it = ast_set.changes.begin(); it != ast_set.changes.end(); ++it)
|
||||
{
|
||||
if (it != ast_set.changes.begin())
|
||||
s << ", ";
|
||||
|
||||
s << it->name << " = " << apply_visitor(FieldVisitorToString(), it->value);
|
||||
}
|
||||
}
|
||||
|
||||
if (ast.format)
|
||||
{
|
||||
s << (hilite ? hilite_keyword : "") << nl_or_ws << indent_str << "FORMAT " << (hilite ? hilite_none : "");
|
||||
|
Loading…
Reference in New Issue
Block a user