diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index e0b78a30b0d..9f49ec096bc 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -83,6 +83,7 @@ namespace ErrorCodes extern const int ILLEGAL_AGGREGATION; extern const int SUPPORT_IS_DISABLED; extern const int TOO_DEEP_AST; + extern const int TOO_BIG_AST; extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; } @@ -932,6 +933,16 @@ void ExpressionAnalyzer::normalizeTree() SetOfASTs tmp_set; MapOfASTs tmp_map; normalizeTreeImpl(ast, tmp_map, tmp_set, "", 0); + + try + { + ast->checkSize(settings.limits.max_expanded_ast_elements); + } + catch (Exception & e) + { + e.addMessage("(after expansion of aliases)"); + throw; + } } @@ -942,7 +953,8 @@ void ExpressionAnalyzer::normalizeTreeImpl( ASTPtr & ast, MapOfASTs & finished_asts, SetOfASTs & current_asts, std::string current_alias, size_t level) { if (level > settings.limits.max_ast_depth) - throw Exception("Normalized AST is too deep. Maximum: " + settings.limits.max_ast_depth.toString(), ErrorCodes::TOO_DEEP_AST); + throw Exception("Normalized AST is too deep. Maximum: " + + settings.limits.max_ast_depth.toString(), ErrorCodes::TOO_DEEP_AST); if (finished_asts.count(ast)) { diff --git a/dbms/src/Interpreters/Limits.h b/dbms/src/Interpreters/Limits.h index cd6fc409508..4b6942cf2f3 100644 --- a/dbms/src/Interpreters/Limits.h +++ b/dbms/src/Interpreters/Limits.h @@ -63,6 +63,7 @@ struct Limits M(SettingUInt64, max_pipeline_depth, 1000, "") \ M(SettingUInt64, max_ast_depth, 1000, "") /** Checked not during parsing, */ \ M(SettingUInt64, max_ast_elements, 50000, "") /** but after parsing the request. */ \ + M(SettingUInt64, max_expanded_ast_elements, 500000, "Limit after expansion of aliases.") \ \ /** 0 - everything is allowed. 1 - only read requests. 2 - only read requests, as well as changing settings, except for the readonly setting. */ \ M(SettingUInt64, readonly, 0, "") \ diff --git a/dbms/src/Storages/StorageView.cpp b/dbms/src/Storages/StorageView.cpp index 9351873c752..76cd481a855 100644 --- a/dbms/src/Storages/StorageView.cpp +++ b/dbms/src/Storages/StorageView.cpp @@ -38,7 +38,7 @@ BlockInputStreams StorageView::read( const unsigned /*num_streams*/) { processed_stage = QueryProcessingStage::FetchColumns; - BlockInputStreams res = InterpreterSelectWithUnionQuery(inner_query->clone(), context, column_names).executeWithMultipleStreams(); + BlockInputStreams res = InterpreterSelectWithUnionQuery(inner_query, context, column_names).executeWithMultipleStreams(); /// It's expected that the columns read from storage are not constant. /// Because method 'getSampleBlockForColumns' is used to obtain a structure of result in InterpreterSelectQuery. diff --git a/dbms/tests/queries/0_stateless/00596_limit_on_expanded_ast.reference b/dbms/tests/queries/0_stateless/00596_limit_on_expanded_ast.reference new file mode 100644 index 00000000000..d00491fd7e5 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00596_limit_on_expanded_ast.reference @@ -0,0 +1 @@ +1 diff --git a/dbms/tests/queries/0_stateless/00596_limit_on_expanded_ast.sh b/dbms/tests/queries/0_stateless/00596_limit_on_expanded_ast.sh new file mode 100755 index 00000000000..85d13cbdb47 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00596_limit_on_expanded_ast.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +. $CURDIR/../shell_config.sh + +exception_pattern="too big" + +${CLICKHOUSE_CLIENT} --max_expanded_ast_elements=500000 --query=" + select 1 as a, a+a as b, b+b as c, c+c as d, d+d as e, e+e as f, f+f as g, g+g as h, h+h as i, i+i as j, j+j as k, k+k as l, l+l as m, m+m as n, n+n as o, o+o as p, p+p as q, q+q as r, r+r as s, s+s as t, t+t as u, u+u as v, v+v as w, w+w as x, x+x as y, y+y as z +" 2>&1 | grep -c "$exception_pattern"