Skip to content

Commit

Permalink
Merge pull request ClickHouse#72480 from yariks5s/new_aliases_overrid…
Browse files Browse the repository at this point in the history
…e_logic

Adding a new aliases defining logic for `SELECT` and `CREATE VIEW`
  • Loading branch information
alexey-milovidov authored Dec 19, 2024
2 parents 8a04621 + abdda03 commit 6529c0b
Show file tree
Hide file tree
Showing 20 changed files with 357 additions and 51 deletions.
20 changes: 0 additions & 20 deletions docs/en/getting-started/example-datasets/tpch.md
Original file line number Diff line number Diff line change
Expand Up @@ -812,26 +812,6 @@ ORDER BY
DROP VIEW revenue0;
```

::::note
As of October 2024, the view definition does not work out-of-the box. Corresponding issue: https://github.com/ClickHouse/ClickHouse/issues/70139

This alternative view definition does work:

```sql
CREATE VIEW revenue0 AS
SELECT
l_suppkey AS supplier_no,
sum(l_extendedprice * (1 - l_discount)) AS total_revenue
FROM
lineitem
WHERE
l_shipdate >= DATE '1996-01-01'
AND l_shipdate < DATE '1996-01-01' + INTERVAL '3' MONTH
GROUP BY
l_suppkey;
```
::::

**Q16**

```sql
Expand Down
2 changes: 1 addition & 1 deletion docs/en/sql-reference/statements/create/view.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Creates a new view. Views can be [normal](#normal-view), [materialized](#materia
Syntax:

``` sql
CREATE [OR REPLACE] VIEW [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster_name]
CREATE [OR REPLACE] VIEW [IF NOT EXISTS] [db.]table_name [(alias1 [, alias2 ...])] [ON CLUSTER cluster_name]
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | INVOKER | NONE }]
AS SELECT ...
[COMMENT 'comment']
Expand Down
4 changes: 2 additions & 2 deletions docs/en/sql-reference/statements/select/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ sidebar_label: SELECT
## Syntax

``` sql
[WITH expr_list|(subquery)]
[WITH expr_list(subquery)]
SELECT [DISTINCT [ON (column1, column2, ...)]] expr_list
[FROM [db.]table | (subquery) | table_function] [FINAL]
[SAMPLE sample_coeff]
[ARRAY JOIN ...]
[GLOBAL] [ANY|ALL|ASOF] [INNER|LEFT|RIGHT|FULL|CROSS] [OUTER|SEMI|ANTI] JOIN (subquery)|table (ON <expr_list>)|(USING <column_list>)
[GLOBAL] [ANY|ALL|ASOF] [INNER|LEFT|RIGHT|FULL|CROSS] [OUTER|SEMI|ANTI] JOIN (subquery)|table [(alias1 [, alias2 ...])] (ON <expr_list>)|(USING <column_list>)
[PREWHERE expr]
[WHERE expr]
[GROUP BY expr_list] [WITH ROLLUP|WITH CUBE] [WITH TOTALS]
Expand Down
23 changes: 21 additions & 2 deletions src/Analyzer/QueryNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ namespace DB
namespace ErrorCodes
{
extern const int LOGICAL_ERROR;
extern const int BAD_ARGUMENTS;
}

QueryNode::QueryNode(ContextMutablePtr context_, SettingsChanges settings_changes_)
Expand All @@ -50,9 +51,20 @@ QueryNode::QueryNode(ContextMutablePtr context_)

void QueryNode::resolveProjectionColumns(NamesAndTypes projection_columns_value)
{
if (projection_columns_value.size() != getProjection().getNodes().size())
throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected projection columns size to match projection nodes size");

// Ensure the number of aliases matches the number of projection columns
if (!this->projection_aliases_to_override.empty())
{
if (this->projection_aliases_to_override.size() != projection_columns_value.size())
throw Exception(ErrorCodes::BAD_ARGUMENTS,
"Number of aliases does not match number of projection columns. "
"Expected {}, got {}",
projection_columns_value.size(),
this->projection_aliases_to_override.size());

for (size_t i = 0; i < projection_columns_value.size(); ++i)
projection_columns_value[i].name = this->projection_aliases_to_override[i];
}
projection_columns = std::move(projection_columns_value);
}

Expand Down Expand Up @@ -297,6 +309,12 @@ void QueryNode::updateTreeHashImpl(HashState & state, CompareOptions) const
state.update(projection_column_type_name);
}

for (const auto & projection_alias : projection_aliases_to_override)
{
state.update(projection_alias.size());
state.update(projection_alias);
}

state.update(is_recursive_with);
state.update(is_distinct);
state.update(is_limit_with_ties);
Expand Down Expand Up @@ -338,6 +356,7 @@ QueryTreeNodePtr QueryNode::cloneImpl() const
result_query_node->cte_name = cte_name;
result_query_node->projection_columns = projection_columns;
result_query_node->settings_changes = settings_changes;
result_query_node->projection_aliases_to_override = projection_aliases_to_override;

return result_query_node;
}
Expand Down
6 changes: 6 additions & 0 deletions src/Analyzer/QueryNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,11 @@ class QueryNode final : public IQueryTreeNode

void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override;

void setProjectionAliasesToOverride(Names pr_aliases)
{
projection_aliases_to_override = std::move(pr_aliases);
}

protected:
bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const override;

Expand All @@ -654,6 +659,7 @@ class QueryNode final : public IQueryTreeNode

std::string cte_name;
NamesAndTypes projection_columns;
Names projection_aliases_to_override;
ContextMutablePtr context;
SettingsChanges settings_changes;

Expand Down
54 changes: 39 additions & 15 deletions src/Analyzer/QueryTreeBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,13 @@ class QueryTreeBuilder
QueryTreeNodePtr buildSelectOrUnionExpression(const ASTPtr & select_or_union_query,
bool is_subquery,
const std::string & cte_name,
const ASTPtr & aliases,
const ContextPtr & context) const;

QueryTreeNodePtr buildSelectWithUnionExpression(const ASTPtr & select_with_union_query,
bool is_subquery,
const std::string & cte_name,
const ASTPtr & aliases,
const ContextPtr & context) const;

QueryTreeNodePtr buildSelectIntersectExceptQuery(const ASTPtr & select_intersect_except_query,
Expand All @@ -108,6 +110,7 @@ class QueryTreeBuilder
QueryTreeNodePtr buildSelectExpression(const ASTPtr & select_query,
bool is_subquery,
const std::string & cte_name,
const ASTPtr & aliases,
const ContextPtr & context) const;

QueryTreeNodePtr buildSortList(const ASTPtr & order_by_expression_list, const ContextPtr & context) const;
Expand All @@ -122,7 +125,7 @@ class QueryTreeBuilder

QueryTreeNodePtr buildWindow(const ASTPtr & window_definition, const ContextPtr & context) const;

QueryTreeNodePtr buildJoinTree(const ASTPtr & tables_in_select_query, const ContextPtr & context) const;
QueryTreeNodePtr buildJoinTree(const ASTSelectQuery & select_query, const ContextPtr & context) const;

ColumnTransformersNodes buildColumnTransformers(const ASTPtr & matcher_expression, const ContextPtr & context) const;

Expand All @@ -138,7 +141,7 @@ QueryTreeBuilder::QueryTreeBuilder(ASTPtr query_, ContextPtr context_)
if (query->as<ASTSelectWithUnionQuery>() ||
query->as<ASTSelectIntersectExceptQuery>() ||
query->as<ASTSelectQuery>())
query_tree_node = buildSelectOrUnionExpression(query, false /*is_subquery*/, {} /*cte_name*/, context_);
query_tree_node = buildSelectOrUnionExpression(query, false /*is_subquery*/, {} /*cte_name*/, nullptr /*aliases*/, context_);
else if (query->as<ASTExpressionList>())
query_tree_node = buildExpressionList(query, context_);
else
Expand All @@ -148,16 +151,17 @@ QueryTreeBuilder::QueryTreeBuilder(ASTPtr query_, ContextPtr context_)
QueryTreeNodePtr QueryTreeBuilder::buildSelectOrUnionExpression(const ASTPtr & select_or_union_query,
bool is_subquery,
const std::string & cte_name,
const ASTPtr & aliases,
const ContextPtr & context) const
{
QueryTreeNodePtr query_node;

if (select_or_union_query->as<ASTSelectWithUnionQuery>())
query_node = buildSelectWithUnionExpression(select_or_union_query, is_subquery /*is_subquery*/, cte_name /*cte_name*/, context);
query_node = buildSelectWithUnionExpression(select_or_union_query, is_subquery /*is_subquery*/, cte_name /*cte_name*/, nullptr /*aliases*/, context);
else if (select_or_union_query->as<ASTSelectIntersectExceptQuery>())
query_node = buildSelectIntersectExceptQuery(select_or_union_query, is_subquery /*is_subquery*/, cte_name /*cte_name*/, context);
else if (select_or_union_query->as<ASTSelectQuery>())
query_node = buildSelectExpression(select_or_union_query, is_subquery /*is_subquery*/, cte_name /*cte_name*/, context);
query_node = buildSelectExpression(select_or_union_query, is_subquery /*is_subquery*/, cte_name /*cte_name*/, aliases, context);
else
throw Exception(ErrorCodes::UNSUPPORTED_METHOD, "SELECT or UNION query {} is not supported",
select_or_union_query->formatForErrorMessage());
Expand All @@ -168,13 +172,14 @@ QueryTreeNodePtr QueryTreeBuilder::buildSelectOrUnionExpression(const ASTPtr & s
QueryTreeNodePtr QueryTreeBuilder::buildSelectWithUnionExpression(const ASTPtr & select_with_union_query,
bool is_subquery,
const std::string & cte_name,
const ASTPtr & aliases,
const ContextPtr & context) const
{
auto & select_with_union_query_typed = select_with_union_query->as<ASTSelectWithUnionQuery &>();
auto & select_lists = select_with_union_query_typed.list_of_selects->as<ASTExpressionList &>();

if (select_lists.children.size() == 1)
return buildSelectOrUnionExpression(select_lists.children[0], is_subquery, cte_name, context);
return buildSelectOrUnionExpression(select_lists.children[0], is_subquery, cte_name, aliases, context);

auto union_node = std::make_shared<UnionNode>(Context::createCopy(context), select_with_union_query_typed.union_mode);
union_node->setIsSubquery(is_subquery);
Expand All @@ -187,7 +192,7 @@ QueryTreeNodePtr QueryTreeBuilder::buildSelectWithUnionExpression(const ASTPtr &
for (size_t i = 0; i < select_lists_children_size; ++i)
{
auto & select_list_node = select_lists.children[i];
QueryTreeNodePtr query_node = buildSelectOrUnionExpression(select_list_node, false /*is_subquery*/, {} /*cte_name*/, context);
QueryTreeNodePtr query_node = buildSelectOrUnionExpression(select_list_node, false /*is_subquery*/, {} /*cte_name*/, aliases, context);
union_node->getQueries().getNodes().push_back(std::move(query_node));
}

Expand All @@ -203,7 +208,7 @@ QueryTreeNodePtr QueryTreeBuilder::buildSelectIntersectExceptQuery(const ASTPtr
auto select_lists = select_intersect_except_query_typed.getListOfSelects();

if (select_lists.size() == 1)
return buildSelectExpression(select_lists[0], is_subquery, cte_name, context);
return buildSelectExpression(select_lists[0], is_subquery, cte_name, nullptr /*aliases*/, context);

SelectUnionMode union_mode;
if (select_intersect_except_query_typed.final_operator == ASTSelectIntersectExceptQuery::Operator::INTERSECT_ALL)
Expand All @@ -228,7 +233,7 @@ QueryTreeNodePtr QueryTreeBuilder::buildSelectIntersectExceptQuery(const ASTPtr
for (size_t i = 0; i < select_lists_size; ++i)
{
auto & select_list_node = select_lists[i];
QueryTreeNodePtr query_node = buildSelectOrUnionExpression(select_list_node, false /*is_subquery*/, {} /*cte_name*/, context);
QueryTreeNodePtr query_node = buildSelectOrUnionExpression(select_list_node, false /*is_subquery*/, {} /*cte_name*/, nullptr /*aliases*/, context);
union_node->getQueries().getNodes().push_back(std::move(query_node));
}

Expand All @@ -238,6 +243,7 @@ QueryTreeNodePtr QueryTreeBuilder::buildSelectIntersectExceptQuery(const ASTPtr
QueryTreeNodePtr QueryTreeBuilder::buildSelectExpression(const ASTPtr & select_query,
bool is_subquery,
const std::string & cte_name,
const ASTPtr & aliases,
const ContextPtr & context) const
{
const auto & select_query_typed = select_query->as<ASTSelectQuery &>();
Expand Down Expand Up @@ -308,7 +314,7 @@ QueryTreeNodePtr QueryTreeBuilder::buildSelectExpression(const ASTPtr & select_q

auto current_context = current_query_tree->getContext();

current_query_tree->getJoinTree() = buildJoinTree(select_query_typed.tables(), current_context);
current_query_tree->getJoinTree() = buildJoinTree(select_query_typed, current_context);

auto select_with_list = select_query_typed.with();
if (select_with_list)
Expand All @@ -332,6 +338,23 @@ QueryTreeNodePtr QueryTreeBuilder::buildSelectExpression(const ASTPtr & select_q
if (select_expression_list)
current_query_tree->getProjectionNode() = buildExpressionList(select_expression_list, current_context);

// Apply the override aliases to the projection nodes
if (aliases)
{
// Collect the aliases into a vector of strings
Names collected_aliases;
auto & override_aliases_children = aliases->as<ASTExpressionList &>().children;
collected_aliases.reserve(override_aliases_children.size());

for (const auto & child : override_aliases_children)
{
const auto & alias_ast = child->as<ASTIdentifier &>();
collected_aliases.push_back(alias_ast.name());
}

current_query_tree->setProjectionAliasesToOverride(collected_aliases);
}

auto prewhere_expression = select_query_typed.prewhere();
if (prewhere_expression)
current_query_tree->getPrewhere() = buildExpression(prewhere_expression, current_context);
Expand Down Expand Up @@ -691,19 +714,19 @@ QueryTreeNodePtr QueryTreeBuilder::buildExpression(const ASTPtr & expression, co
else if (const auto * subquery = expression->as<ASTSubquery>())
{
auto subquery_query = subquery->children[0];
auto query_node = buildSelectWithUnionExpression(subquery_query, true /*is_subquery*/, {} /*cte_name*/, context);
auto query_node = buildSelectWithUnionExpression(subquery_query, true /*is_subquery*/, {} /*cte_name*/, nullptr /*aliases*/, context);

result = std::move(query_node);
}
else if (const auto * /*select_with_union_query*/ _ = expression->as<ASTSelectWithUnionQuery>())
{
auto query_node = buildSelectWithUnionExpression(expression, false /*is_subquery*/, {} /*cte_name*/, context);
auto query_node = buildSelectWithUnionExpression(expression, false /*is_subquery*/, {} /*cte_name*/, nullptr /*aliases*/, context);
result = std::move(query_node);
}
else if (const auto * with_element = expression->as<ASTWithElement>())
{
auto with_element_subquery = with_element->subquery->as<ASTSubquery &>().children.at(0);
auto query_node = buildSelectWithUnionExpression(with_element_subquery, true /*is_subquery*/, with_element->name /*cte_name*/, context);
auto query_node = buildSelectWithUnionExpression(with_element_subquery, true /*is_subquery*/, with_element->name /*cte_name*/, with_element->aliases /*aliases*/, context);

result = std::move(query_node);
}
Expand Down Expand Up @@ -802,8 +825,9 @@ QueryTreeNodePtr QueryTreeBuilder::buildWindow(const ASTPtr & window_definition,
return window_node;
}

QueryTreeNodePtr QueryTreeBuilder::buildJoinTree(const ASTPtr & tables_in_select_query, const ContextPtr & context) const
QueryTreeNodePtr QueryTreeBuilder::buildJoinTree(const ASTSelectQuery & select_query, const ContextPtr & context) const
{
const auto & tables_in_select_query = select_query.tables();
if (!tables_in_select_query)
{
/** If no table is specified in SELECT query we substitute system.one table.
Expand Down Expand Up @@ -868,7 +892,7 @@ QueryTreeNodePtr QueryTreeBuilder::buildJoinTree(const ASTPtr & tables_in_select
auto & subquery_expression = table_expression.subquery->as<ASTSubquery &>();
const auto & select_with_union_query = subquery_expression.children[0];

auto node = buildSelectWithUnionExpression(select_with_union_query, true /*is_subquery*/, {} /*cte_name*/, context);
auto node = buildSelectWithUnionExpression(select_with_union_query, true /*is_subquery*/, {} /*cte_name*/, select_query.aliases(), context);
node->setAlias(subquery_expression.tryGetAlias());
node->setOriginalAST(select_with_union_query);

Expand Down Expand Up @@ -898,7 +922,7 @@ QueryTreeNodePtr QueryTreeBuilder::buildJoinTree(const ASTPtr & tables_in_select
table_function_expression.formatForErrorMessage());

if (argument->as<ASTSelectQuery>() || argument->as<ASTSelectWithUnionQuery>() || argument->as<ASTSelectIntersectExceptQuery>())
node->getArguments().getNodes().push_back(buildSelectOrUnionExpression(argument, false /*is_subquery*/, {} /*cte_name*/, context));
node->getArguments().getNodes().push_back(buildSelectOrUnionExpression(argument, false /*is_subquery*/, {} /*cte_name*/, nullptr /*aliases*/, context));
else if (const auto * ast_set = argument->as<ASTSetQuery>())
node->setSettingsChanges(ast_set->changes);
else
Expand Down
39 changes: 39 additions & 0 deletions src/Interpreters/InterpreterCreateQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,45 @@ InterpreterCreateQuery::TableProperties InterpreterCreateQuery::getTableProperti
if (create.isParameterizedView())
return properties;

if (create.aliases_list)
{
auto & aliases_children = create.aliases_list->children;
const auto * select_with_union_query = create.select->as<ASTSelectWithUnionQuery>();

if (!select_with_union_query)
throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected ASTSelectWithUnionQuery");

const auto & selects = select_with_union_query->list_of_selects->children;

for (const auto & select : selects)
{
const auto * select_query = select->as<ASTSelectQuery>();

if (!select_query)
throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected ASTSelectQuery inside ASTSelectWithUnionQuery");

auto select_expression_list = select_query->select();

if (!select_expression_list)
throw Exception(ErrorCodes::LOGICAL_ERROR, "No select expressions in SELECT query");

auto & select_expressions = select_expression_list->children;

if (select_expressions.size() != aliases_children.size())
{
throw Exception(ErrorCodes::BAD_ARGUMENTS,
"Number of aliases does not match number of expressions in SELECT list");
}

for (size_t i = 0; i < select_expressions.size(); ++i)
{
auto & expr = select_expressions[i];
const auto & alias_ast = aliases_children[i]->as<ASTIdentifier &>();
expr->setAlias(alias_ast.name());
}
}
}

Block as_select_sample;

if (getContext()->getSettingsRef()[Setting::allow_experimental_analyzer])
Expand Down
12 changes: 12 additions & 0 deletions src/Parsers/ASTCreateQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ ASTPtr ASTCreateQuery::clone() const

if (columns_list)
res->set(res->columns_list, columns_list->clone());
if (aliases_list)
res->set(res->aliases_list, aliases_list->clone());
if (storage)
res->set(res->storage, storage->clone());
if (select)
Expand Down Expand Up @@ -480,6 +482,16 @@ void ASTCreateQuery::formatQueryImpl(WriteBuffer & ostr, const FormatSettings &
ostr << (settings.one_line ? ")" : "\n)");
}

frame.expression_list_always_start_on_new_line = true;

if (is_ordinary_view && aliases_list && !as_table_function)
{
ostr << (settings.one_line ? " (" : "\n(");
FormatStateStacked frame_nested = frame;
aliases_list->format(ostr, settings, state, frame_nested);
ostr << (settings.one_line ? ")" : "\n)");
}

if (dictionary_attributes_list)
{
ostr << (settings.one_line ? " (" : "\n(");
Expand Down
Loading

0 comments on commit 6529c0b

Please sign in to comment.