diff --git a/src/Storages/IndicesDescription.cpp b/src/Storages/IndicesDescription.cpp index 06518a52c61..c723fa4225c 100644 --- a/src/Storages/IndicesDescription.cpp +++ b/src/Storages/IndicesDescription.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include #include "Common/Exception.h" @@ -22,6 +24,11 @@ namespace ErrorCodes extern const int LOGICAL_ERROR; } +namespace +{ +using ReplaceAliasToExprVisitor = InDepthNodeVisitor; +} + IndexDescription::IndexDescription(const IndexDescription & other) : definition_ast(other.definition_ast ? other.definition_ast->clone() : nullptr) , expression_list_ast(other.expression_list_ast ? other.expression_list_ast->clone() : nullptr) @@ -94,6 +101,10 @@ IndexDescription IndexDescription::getIndexFromAST(const ASTPtr & definition_ast if (index_definition->expr) { expr_list = extractKeyExpressionList(index_definition->expr->clone()); + + ReplaceAliasToExprVisitor::Data data{columns}; + ReplaceAliasToExprVisitor{data}.visit(expr_list); + result.expression_list_ast = expr_list->clone(); } else diff --git a/src/Storages/ReplaceAliasByExpressionVisitor.cpp b/src/Storages/ReplaceAliasByExpressionVisitor.cpp new file mode 100644 index 00000000000..b7836cfa9c4 --- /dev/null +++ b/src/Storages/ReplaceAliasByExpressionVisitor.cpp @@ -0,0 +1,32 @@ +#include + +#include +#include +#include +#include + +namespace DB +{ + +void ReplaceAliasByExpressionMatcher::visit(ASTPtr & ast, Data & data) +{ + if (auto * identifier = ast->as()) + { + visit(*identifier, ast, data); + } +} + +void ReplaceAliasByExpressionMatcher::visit(const ASTIdentifier & column, ASTPtr & ast, Data & data) +{ + const auto & column_name = column.name(); + if (data.columns.hasAlias(column_name)) + { + /// Alias expr is saved in default expr. + if (auto col_default = data.columns.getDefault(column_name)) + { + ast = col_default->expression->clone(); + } + } +} + +} diff --git a/src/Storages/ReplaceAliasByExpressionVisitor.h b/src/Storages/ReplaceAliasByExpressionVisitor.h new file mode 100644 index 00000000000..4acc1fd4be7 --- /dev/null +++ b/src/Storages/ReplaceAliasByExpressionVisitor.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +namespace DB +{ + +class ASTFunction; +class ColumnsDescription; +class ASTIdentifier; + + +/* The Visitor is used to replace ALIAS by EXPRESSION when we refer to ALIAS + * column in index definition. + * + * For example, if we have following create statement: + * CREATE TABLE t + * ( + * col UInt8, + * col_alias ALIAS col + 1 + * INDEX idx (col_alias) TYPE minmax + * ) ENGINE = MergeTree ORDER BY col; + * we need call the visitor to replace `col_alias` by `col` + 1 when get index + * description from index definition AST. +*/ +class ReplaceAliasByExpressionMatcher +{ +public: + struct Data + { + const ColumnsDescription & columns; + }; + + static void visit(ASTPtr & ast, Data &); + static void visit(const ASTIdentifier &, ASTPtr & ast, Data &); + static bool needChildVisit(const ASTPtr &, const ASTPtr &) { return true; } +}; + +} diff --git a/tests/queries/0_stateless/02911_support_alias_column_in_indices.reference b/tests/queries/0_stateless/02911_support_alias_column_in_indices.reference new file mode 100644 index 00000000000..883966ce6b5 --- /dev/null +++ b/tests/queries/0_stateless/02911_support_alias_column_in_indices.reference @@ -0,0 +1,55 @@ +Expression ((Projection + Before ORDER BY)) + Filter (WHERE) + ReadFromMergeTree (02911_support_alias_column_in_indices.test1) + Indexes: + PrimaryKey + Keys: + c + Condition: (plus(c, 1) in [11, +Inf)) + Parts: 1/2 + Granules: 1/2 + Skip + Name: i + Description: minmax GRANULARITY 1 + Parts: 1/1 + Granules: 1/1 +Expression ((Project names + Projection)) + Filter ((WHERE + Change column names to column identifiers)) + ReadFromMergeTree (02911_support_alias_column_in_indices.test1) + Indexes: + PrimaryKey + Keys: + c + Condition: (_CAST(plus(c, \'UInt64\'), 1) in [11, +Inf)) + Parts: 1/2 + Granules: 1/2 + Skip + Name: i + Description: minmax GRANULARITY 1 + Parts: 1/1 + Granules: 1/1 +Expression ((Projection + Before ORDER BY)) + Filter (WHERE) + ReadFromMergeTree (02911_support_alias_column_in_indices.test2) + Indexes: + PrimaryKey + Keys: + c + Condition: (plus(plus(c, 1), 1) in [16, +Inf)) + Parts: 1/2 + Granules: 1/2 + Skip + Name: i + Description: minmax GRANULARITY 1 + Parts: 1/1 + Granules: 1/1 +Expression ((Project names + Projection)) + Filter ((WHERE + Change column names to column identifiers)) + ReadFromMergeTree (02911_support_alias_column_in_indices.test2) + Indexes: + PrimaryKey + Keys: + c + Condition: (_CAST(plus(_CAST(plus(c, \'UInt64\'), 1), \'UInt64\'), 1) in [16, +Inf)) + Parts: 1/2 + Granules: 1/2 diff --git a/tests/queries/0_stateless/02911_support_alias_column_in_indices.sql b/tests/queries/0_stateless/02911_support_alias_column_in_indices.sql new file mode 100644 index 00000000000..93d9a1670db --- /dev/null +++ b/tests/queries/0_stateless/02911_support_alias_column_in_indices.sql @@ -0,0 +1,34 @@ +-- Tags: no-parallel + +drop database if exists 02911_support_alias_column_in_indices; +create database 02911_support_alias_column_in_indices; +use 02911_support_alias_column_in_indices; + +create table test1 +( + c UInt32, + a alias c + 1, + index i (a) type minmax +) engine = MergeTree order by c; + +insert into test1 select * from numbers(10); +insert into test1 select * from numbers(11, 20); + +explain indexes = 1 select * from test1 where a > 10 settings allow_experimental_analyzer = 0; +explain indexes = 1 select * from test1 where a > 10 settings allow_experimental_analyzer = 1; + +create table test2 +( + c UInt32, + a1 alias c + 1, + a2 alias a1 + 1, + index i (a2) type minmax +) engine = MergeTree order by c; + +insert into test2 select * from numbers(10); +insert into test2 select * from numbers(11, 20); + +explain indexes = 1 select * from test2 where a2 > 15 settings allow_experimental_analyzer = 0; +explain indexes = 1 select * from test2 where a2 > 15 settings allow_experimental_analyzer = 1; -- buggy, analyzer does not pick up index i + +drop database 02911_support_alias_column_in_indices;