dbms: added optional section SETTINGS to SELECT query [#METR-16354].

This commit is contained in:
Alexey Milovidov 2015-06-06 00:28:04 +03:00
parent cac3ce7e27
commit 854a2f4cc8
9 changed files with 114 additions and 22 deletions

View File

@ -130,6 +130,18 @@ private:
void ignoreWithTotals();
/** Если в запросе SELECT есть секция SETTINGS, то применить настройки из неё и удалить секцию SETTINGS.
* Затем достать настройки из context и поместить их в settings.
*
* Секция SETTINGS - настройки для конкретного запроса.
* Обычно настройки могут быть переданы другими способами, не внутри запроса.
* Но использование такой секции оправдано, если нужно задать настройки для одного подзапроса.
*
* При распределённой обработке запроса, секция SETTINGS не будет передана внутри запроса,
* а настройки будут переданы отдельно, при отправке запроса.
*/
void initSettings();
ASTPtr query_ptr;
ASTSelectQuery & query;
Context context;

View File

@ -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;
};

View File

@ -51,6 +51,7 @@ public:
ASTPtr order_expression_list;
ASTPtr limit_offset;
ASTPtr limit_length;
ASTPtr settings;
ASTPtr next_union_all; /// Следующий запрос SELECT в цепочке UNION ALL, если такой есть
};

View File

@ -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;
};
}

View File

@ -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();
}
}

View File

@ -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)

View File

@ -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)

View File

@ -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;

View File

@ -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 : "");