diff --git a/dbms/include/DB/Interpreters/ExpressionAnalyzer.h b/dbms/include/DB/Interpreters/ExpressionAnalyzer.h index 5d2c326566a..7bb679b57bf 100644 --- a/dbms/include/DB/Interpreters/ExpressionAnalyzer.h +++ b/dbms/include/DB/Interpreters/ExpressionAnalyzer.h @@ -232,7 +232,7 @@ private: /// remove Function_if AST if condition is constant void optimizeIfWithConstantCondition(); - void optimizeIfWithConstantConditionImpl(ASTPtr & current_ast) const; + void optimizeIfWithConstantConditionImpl(ASTPtr & current_ast, Aliases & aliases) const; bool tryExtractConstValueFromCondition(const ASTPtr & condition, bool & value) const; /// Превратить перечисление значений или подзапрос в ASTSet. node - функция in или notIn. diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index f10352fcfca..042ff4cd0bb 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -200,7 +200,7 @@ void ExpressionAnalyzer::init() void ExpressionAnalyzer::optimizeIfWithConstantCondition() { - optimizeIfWithConstantConditionImpl(ast); + optimizeIfWithConstantConditionImpl(ast, aliases); } bool ExpressionAnalyzer::tryExtractConstValueFromCondition(const ASTPtr & condition, bool & value) const @@ -237,7 +237,7 @@ bool ExpressionAnalyzer::tryExtractConstValueFromCondition(const ASTPtr & condit return false; } -void ExpressionAnalyzer::optimizeIfWithConstantConditionImpl(ASTPtr & current_ast) const +void ExpressionAnalyzer::optimizeIfWithConstantConditionImpl(ASTPtr & current_ast, ExpressionAnalyzer::Aliases & aliases) const { if (!current_ast) return; @@ -247,11 +247,11 @@ void ExpressionAnalyzer::optimizeIfWithConstantConditionImpl(ASTPtr & current_as ASTFunction * function_node = typeid_cast(child.get()); if (!function_node || function_node->name != FunctionIf::name) { - optimizeIfWithConstantConditionImpl(child); + optimizeIfWithConstantConditionImpl(child, aliases); continue; } - optimizeIfWithConstantConditionImpl(function_node->arguments); + optimizeIfWithConstantConditionImpl(function_node->arguments, aliases); ASTExpressionList * args = typeid_cast(function_node->arguments.get()); ASTPtr condition_expr = args->children.at(0); @@ -262,10 +262,24 @@ void ExpressionAnalyzer::optimizeIfWithConstantConditionImpl(ASTPtr & current_as bool condition; if (tryExtractConstValueFromCondition(condition_expr, condition)) { - if (condition) - child = then_expr; + ASTPtr replace_ast = condition ? then_expr : else_expr; + String replace_alias = replace_ast->tryGetAlias(); + String if_alias = child->tryGetAlias(); + + if (replace_alias.empty()) + { + replace_ast->setAlias(if_alias); + child = replace_ast; + } else - child = else_expr; + { + /// Only copy of one node is required here. + /// But IAST has only method for deep copy of subtree. + /// This can be a reason of performance degradation in case of deep queries. + ASTPtr replace_ast_deep_copy = replace_ast->clone(); + replace_ast_deep_copy->setAlias(if_alias); + child = replace_ast_deep_copy; + } } } } diff --git a/dbms/tests/queries/0_stateless/00393_if_with_constant_condition.reference b/dbms/tests/queries/0_stateless/00393_if_with_constant_condition.reference index 019389c1815..69685047337 100644 --- a/dbms/tests/queries/0_stateless/00393_if_with_constant_condition.reference +++ b/dbms/tests/queries/0_stateless/00393_if_with_constant_condition.reference @@ -1,7 +1,8 @@ 1 1 2 -42 -1 0 -0 5 -1 2 3 +1 +d=2 a=1 b=2 c=3 d=2 +d=3 a=0 b=2 c=3 d=3 +d=2 a=1 b=2 c=3 d=2 +not_existing=42 diff --git a/dbms/tests/queries/0_stateless/00393_if_with_constant_condition.sql b/dbms/tests/queries/0_stateless/00393_if_with_constant_condition.sql index af4051f34a4..c35e4ff24e3 100644 --- a/dbms/tests/queries/0_stateless/00393_if_with_constant_condition.sql +++ b/dbms/tests/queries/0_stateless/00393_if_with_constant_condition.sql @@ -1,10 +1,15 @@ SELECT 1 ? 1 : 0; SELECT 0 ? not_existing_column : 1 FROM system.numbers LIMIT 1; -SELECT if(1, if(0, not_existing_column, 2), 0) FROM system.numbers LIMIT 1; +SELECT 1 ? (0 ? not_existing_column : 2) : 0 FROM system.numbers LIMIT 1; -SELECT (SELECT hasColumnInTable('system', 'numbers', 'not_existing')) ? not_existing : 42 FROM system.numbers LIMIT 1; +/* scalar subquery optimization */ +SELECT (SELECT toUInt8(number + 1) FROM system.numbers LIMIT 1) ? 1 : 2 FROM system.numbers LIMIT 1; /* alias test */ -SELECT 1 ? 1 : (0 as n), n FROM system.numbers LIMIT 1; -SELECT 0 ? (number + 5 as n) : 0, n FROM system.numbers LIMIT 1; -SELECT (2 as n) ? 1 : (number + 3 as nn), n, nn FROM system.numbers LIMIT 1; \ No newline at end of file +SELECT (1 as a) ? (2 as b) : (3 as c) as d, a, b, c, d FORMAT TSKV; +SELECT (0 as a) ? (2 as b) : (3 as c) as d, a, b, c, d FORMAT TSKV; + +SELECT (1 as a) ? (number + 2 as b) : (number + 3 as c) as d, a, b, c, d FROM system.numbers LIMIT 1 FORMAT TSKV; + +/* intergration test */ +SELECT (SELECT hasColumnInTable('system', 'numbers', 'not_existing')) ? not_existing : 42 as not_existing FROM system.numbers LIMIT 1 FORMAT TSKV; \ No newline at end of file