From b10bb48ce4d33c653ec19b9d13960c4215c4668d Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:32:29 +0100 Subject: [PATCH 01/26] Init --- src/Analyzer/QueryTreeBuilder.cpp | 51 ++++++++++++++----- src/Interpreters/InterpreterCreateQuery.cpp | 39 ++++++++++++++ src/Parsers/ASTCreateQuery.cpp | 2 + src/Parsers/ASTCreateQuery.h | 3 ++ src/Parsers/ASTSelectQuery.h | 5 ++ src/Parsers/ExpressionListParsers.cpp | 6 +++ src/Parsers/ExpressionListParsers.h | 7 +++ src/Parsers/ParserCreateQuery.cpp | 29 +++++++++-- src/Parsers/ParserSelectQuery.cpp | 12 +++++ .../03280_aliases_override_logic.reference | 6 +++ .../03280_aliases_override_logic.sql | 27 ++++++++++ 11 files changed, 170 insertions(+), 17 deletions(-) create mode 100644 tests/queries/0_stateless/03280_aliases_override_logic.reference create mode 100644 tests/queries/0_stateless/03280_aliases_override_logic.sql diff --git a/src/Analyzer/QueryTreeBuilder.cpp b/src/Analyzer/QueryTreeBuilder.cpp index d3c88d39213e..18d7639066f1 100644 --- a/src/Analyzer/QueryTreeBuilder.cpp +++ b/src/Analyzer/QueryTreeBuilder.cpp @@ -89,12 +89,14 @@ class QueryTreeBuilder QueryTreeNodePtr buildSelectOrUnionExpression(const ASTPtr & select_or_union_query, bool is_subquery, const std::string & cte_name, - const ContextPtr & context) const; + const ContextPtr & context, + const ASTPtr & aliases_to_override = nullptr) const; QueryTreeNodePtr buildSelectWithUnionExpression(const ASTPtr & select_with_union_query, bool is_subquery, const std::string & cte_name, - const ContextPtr & context) const; + const ContextPtr & context, + const ASTPtr & aliases_to_override = nullptr) const; QueryTreeNodePtr buildSelectIntersectExceptQuery(const ASTPtr & select_intersect_except_query, bool is_subquery, @@ -104,7 +106,8 @@ class QueryTreeBuilder QueryTreeNodePtr buildSelectExpression(const ASTPtr & select_query, bool is_subquery, const std::string & cte_name, - const ContextPtr & context) const; + const ContextPtr & context, + const ASTPtr & aliases_to_override = nullptr) const; QueryTreeNodePtr buildSortList(const ASTPtr & order_by_expression_list, const ContextPtr & context) const; @@ -118,7 +121,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; @@ -142,7 +145,8 @@ QueryTreeBuilder::QueryTreeBuilder(ASTPtr query_, ContextPtr context_) QueryTreeNodePtr QueryTreeBuilder::buildSelectOrUnionExpression(const ASTPtr & select_or_union_query, bool is_subquery, const std::string & cte_name, - const ContextPtr & context) const + const ContextPtr & context, + const ASTPtr & aliases_to_override) const { QueryTreeNodePtr query_node; @@ -151,7 +155,7 @@ QueryTreeNodePtr QueryTreeBuilder::buildSelectOrUnionExpression(const ASTPtr & s else if (select_or_union_query->as()) query_node = buildSelectIntersectExceptQuery(select_or_union_query, is_subquery /*is_subquery*/, cte_name /*cte_name*/, context); else if (select_or_union_query->as()) - 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*/, context, aliases_to_override); else throw Exception(ErrorCodes::UNSUPPORTED_METHOD, "SELECT or UNION query {} is not supported", select_or_union_query->formatForErrorMessage()); @@ -162,13 +166,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 ContextPtr & context) const + const ContextPtr & context, + const ASTPtr & aliases_to_override) const { auto & select_with_union_query_typed = select_with_union_query->as(); auto & select_lists = select_with_union_query_typed.list_of_selects->as(); 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, context, aliases_to_override); auto union_node = std::make_shared(Context::createCopy(context), select_with_union_query_typed.union_mode); union_node->setIsSubquery(is_subquery); @@ -181,7 +186,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*/, context, aliases_to_override); union_node->getQueries().getNodes().push_back(std::move(query_node)); } @@ -232,7 +237,8 @@ QueryTreeNodePtr QueryTreeBuilder::buildSelectIntersectExceptQuery(const ASTPtr QueryTreeNodePtr QueryTreeBuilder::buildSelectExpression(const ASTPtr & select_query, bool is_subquery, const std::string & cte_name, - const ContextPtr & context) const + const ContextPtr & context, + const ASTPtr & aliases_to_override) const { const auto & select_query_typed = select_query->as(); @@ -302,7 +308,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) @@ -326,6 +332,24 @@ 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_to_override) + { + auto & projection_nodes = current_query_tree->getProjection().getNodes(); + auto & override_aliases_children = aliases_to_override->as().children; + + if (projection_nodes.size() != override_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 < projection_nodes.size(); ++i) + { + const auto & alias_ast = override_aliases_children[i]->as(); + projection_nodes[i]->setAlias(alias_ast.name()); + } + } + auto prewhere_expression = select_query_typed.prewhere(); if (prewhere_expression) current_query_tree->getPrewhere() = buildExpression(prewhere_expression, current_context); @@ -785,8 +809,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. @@ -851,7 +876,7 @@ QueryTreeNodePtr QueryTreeBuilder::buildJoinTree(const ASTPtr & tables_in_select auto & subquery_expression = table_expression.subquery->as(); 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*/, context, select_query.aliasesOverride()); node->setAlias(subquery_expression.tryGetAlias()); node->setOriginalAST(select_with_union_query); diff --git a/src/Interpreters/InterpreterCreateQuery.cpp b/src/Interpreters/InterpreterCreateQuery.cpp index b1a15d101efc..6ac54c1bfbab 100644 --- a/src/Interpreters/InterpreterCreateQuery.cpp +++ b/src/Interpreters/InterpreterCreateQuery.cpp @@ -934,6 +934,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(); + + 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_query_ptr : selects) + { + const auto * select_query = select_query_ptr->as(); + + 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(); + expr->setAlias(alias_ast.name()); + } + } + } + Block as_select_sample; if (getContext()->getSettingsRef()[Setting::allow_experimental_analyzer]) diff --git a/src/Parsers/ASTCreateQuery.cpp b/src/Parsers/ASTCreateQuery.cpp index 974b56e8ef6b..5c98d8e4f25b 100644 --- a/src/Parsers/ASTCreateQuery.cpp +++ b/src/Parsers/ASTCreateQuery.cpp @@ -240,6 +240,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) diff --git a/src/Parsers/ASTCreateQuery.h b/src/Parsers/ASTCreateQuery.h index 3621eae1f745..a54d1e1f3f82 100644 --- a/src/Parsers/ASTCreateQuery.h +++ b/src/Parsers/ASTCreateQuery.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -105,6 +106,7 @@ class ASTCreateQuery : public ASTQueryWithTableAndOutput, public ASTQueryWithOnC bool has_uuid{false}; // CREATE TABLE x UUID '...' ASTColumns * columns_list = nullptr; + ASTExpressionList * aliases_list = nullptr; // Explicit aliases for syntax like CREATE VIEW my_view (a, b) AS SELECT 1, 2 ASTStorage * storage = nullptr; ASTPtr watermark_function; @@ -184,6 +186,7 @@ class ASTCreateQuery : public ASTQueryWithTableAndOutput, public ASTQueryWithOnC void forEachPointerToChild(std::function f) override { f(reinterpret_cast(&columns_list)); + f(reinterpret_cast(&aliases_list)); f(reinterpret_cast(&storage)); f(reinterpret_cast(&targets)); f(reinterpret_cast(&as_table_function)); diff --git a/src/Parsers/ASTSelectQuery.h b/src/Parsers/ASTSelectQuery.h index a2a6791442ab..29767d06179f 100644 --- a/src/Parsers/ASTSelectQuery.h +++ b/src/Parsers/ASTSelectQuery.h @@ -20,6 +20,7 @@ class ASTSelectQuery : public IAST WITH, SELECT, TABLES, + ALIASES_OVERRIDE, PREWHERE, WHERE, GROUP_BY, @@ -46,6 +47,8 @@ class ASTSelectQuery : public IAST return "SELECT"; case Expression::TABLES: return "TABLES"; + case Expression::ALIASES_OVERRIDE: + return "ALIASES_OVERRIDE"; case Expression::PREWHERE: return "PREWHERE"; case Expression::WHERE: @@ -96,6 +99,7 @@ class ASTSelectQuery : public IAST ASTPtr & refSelect() { return getExpression(Expression::SELECT); } ASTPtr & refTables() { return getExpression(Expression::TABLES); } + ASTPtr & refAliasesOverride() { return getExpression(Expression::ALIASES_OVERRIDE); } ASTPtr & refPrewhere() { return getExpression(Expression::PREWHERE); } ASTPtr & refWhere() { return getExpression(Expression::WHERE); } ASTPtr & refHaving() { return getExpression(Expression::HAVING); } @@ -104,6 +108,7 @@ class ASTSelectQuery : public IAST ASTPtr with() const { return getExpression(Expression::WITH); } ASTPtr select() const { return getExpression(Expression::SELECT); } ASTPtr tables() const { return getExpression(Expression::TABLES); } + ASTPtr aliasesOverride()const { return getExpression(Expression::ALIASES_OVERRIDE); } ASTPtr prewhere() const { return getExpression(Expression::PREWHERE); } ASTPtr where() const { return getExpression(Expression::WHERE); } ASTPtr groupBy() const { return getExpression(Expression::GROUP_BY); } diff --git a/src/Parsers/ExpressionListParsers.cpp b/src/Parsers/ExpressionListParsers.cpp index 6d4a2e57d103..3247274b9c73 100644 --- a/src/Parsers/ExpressionListParsers.cpp +++ b/src/Parsers/ExpressionListParsers.cpp @@ -331,6 +331,12 @@ bool ParserOrderByExpressionList::parseImpl(Pos & pos, ASTPtr & node, Expected & .parse(pos, node, expected); } +bool ParserAliasesExpressionList::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) +{ + return ParserList(std::make_unique(), std::make_unique(TokenType::Comma), false) + .parse(pos, node, expected); +} + bool ParserGroupingSetsExpressionListElements::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) { auto command_list = std::make_shared(); diff --git a/src/Parsers/ExpressionListParsers.h b/src/Parsers/ExpressionListParsers.h index 6ab38416f322..739a3d95fc80 100644 --- a/src/Parsers/ExpressionListParsers.h +++ b/src/Parsers/ExpressionListParsers.h @@ -257,6 +257,13 @@ class ParserOrderByExpressionList : public IParserBase bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override; }; +class ParserAliasesExpressionList : public IParserBase +{ +protected: + const char * getName() const override { return "list of aliases expressions"; } + bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override; +}; + class ParserGroupingSetsExpressionList : public IParserBase { protected: diff --git a/src/Parsers/ParserCreateQuery.cpp b/src/Parsers/ParserCreateQuery.cpp index cc2ccf2645ce..d7b7a9cf0af7 100644 --- a/src/Parsers/ParserCreateQuery.cpp +++ b/src/Parsers/ParserCreateQuery.cpp @@ -1477,6 +1477,7 @@ bool ParserCreateViewQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec ParserStorage storage_p{ParserStorage::TABLE_ENGINE}; ParserIdentifier name_p; ParserTablePropertiesDeclarationList table_properties_p; + ParserAliasesExpressionList expr_list_aliases; ParserSelectWithUnionQuery select_p; ParserNameList names_p; ParserSQLSecurity sql_security_p; @@ -1485,6 +1486,7 @@ bool ParserCreateViewQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec ASTPtr to_table; ASTPtr to_inner_uuid; ASTPtr columns_list; + ASTPtr aliases_list; ASTPtr storage; ASTPtr as_database; ASTPtr as_table; @@ -1560,15 +1562,33 @@ bool ParserCreateViewQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec if (!table_name_p.parse(pos, to_table, expected)) return false; } + bool aliases_override = false; /// Optional - a list of columns can be specified. It must fully comply with SELECT. - if (s_lparen.ignore(pos, expected)) + if (s_lparen.ignore(pos, expected)) // Parsing cases like CREATE VIEW (a Int64, b Int64) (a, b) SELECT ... { if (!table_properties_p.parse(pos, columns_list, expected)) - return false; + { + if (!expr_list_aliases.parse(pos, aliases_list, expected)) + return false; + else + aliases_override = true; + } + else + { + if (!s_rparen.ignore(pos, expected)) + return false; + if (s_lparen.ignore(pos, expected)) + { + aliases_override = true; + if (!expr_list_aliases.parse(pos, aliases_list, expected)) + return false; + } + } - if (!s_rparen.ignore(pos, expected)) - return false; + if (aliases_override) + if (!s_rparen.ignore(pos, expected)) + return false; } if (is_materialized_view) @@ -1644,6 +1664,7 @@ bool ParserCreateViewQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec query->children.push_back(query->table); query->set(query->columns_list, columns_list); + query->set(query->aliases_list, aliases_list); if (refresh_strategy) query->set(query->refresh_strategy, refresh_strategy); diff --git a/src/Parsers/ParserSelectQuery.cpp b/src/Parsers/ParserSelectQuery.cpp index 067a3c5b67bf..da5eb388d73a 100644 --- a/src/Parsers/ParserSelectQuery.cpp +++ b/src/Parsers/ParserSelectQuery.cpp @@ -72,6 +72,7 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) ParserNotEmptyExpressionList exp_list(false); ParserNotEmptyExpressionList exp_list_for_with_clause(false); ParserNotEmptyExpressionList exp_list_for_select_clause(/*allow_alias_without_as_keyword*/ true, /*allow_trailing_commas*/ true); + ParserAliasesExpressionList exp_list_after_from; ParserExpressionWithOptionalAlias exp_elem(false); ParserOrderByExpressionList order_list; ParserGroupingSetsExpressionList grouping_sets_list; @@ -83,6 +84,7 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) ASTPtr with_expression_list; ASTPtr select_expression_list; ASTPtr tables; + ASTPtr expression_list_after_from; ASTPtr prewhere_expression; ASTPtr where_expression; ASTPtr group_expression_list; @@ -189,6 +191,15 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) return false; } + if (open_bracket.ignore(pos, expected)) + { + if (!exp_list_after_from.parse(pos, expression_list_after_from, expected)) + return false; + + if (!close_bracket.ignore(pos, expected)) + return false; + } + /// PREWHERE expr if (s_prewhere.ignore(pos, expected)) { @@ -500,6 +511,7 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) select_query->setExpression(ASTSelectQuery::Expression::WITH, std::move(with_expression_list)); select_query->setExpression(ASTSelectQuery::Expression::SELECT, std::move(select_expression_list)); select_query->setExpression(ASTSelectQuery::Expression::TABLES, std::move(tables)); + select_query->setExpression(ASTSelectQuery::Expression::ALIASES_OVERRIDE, std::move(expression_list_after_from)); select_query->setExpression(ASTSelectQuery::Expression::PREWHERE, std::move(prewhere_expression)); select_query->setExpression(ASTSelectQuery::Expression::WHERE, std::move(where_expression)); select_query->setExpression(ASTSelectQuery::Expression::GROUP_BY, std::move(group_expression_list)); diff --git a/tests/queries/0_stateless/03280_aliases_override_logic.reference b/tests/queries/0_stateless/03280_aliases_override_logic.reference new file mode 100644 index 000000000000..369dbdb26b44 --- /dev/null +++ b/tests/queries/0_stateless/03280_aliases_override_logic.reference @@ -0,0 +1,6 @@ +0 +2 +0 +1 +1 +2 diff --git a/tests/queries/0_stateless/03280_aliases_override_logic.sql b/tests/queries/0_stateless/03280_aliases_override_logic.sql new file mode 100644 index 000000000000..92dc6bc63a82 --- /dev/null +++ b/tests/queries/0_stateless/03280_aliases_override_logic.sql @@ -0,0 +1,27 @@ +SELECT b FROM +( + SELECT number, number*2 + FROM numbers(2) (a, b) +) as x; + +SELECT a FROM +( + SELECT number, number*2 + FROM numbers(2) (a, b) +) as x; + +SELECT a FROM +( +SELECT number, number*2 +FROM numbers(10) +) as x (a); -- { serverError BAD_ARGUMENTS } + +CREATE VIEW IF NOT EXISTS test_view_03280 (a,b) AS SELECT 1, 2; + +SELECT a FROM test_view_03280; + +SELECT b FROM test_view_03280; + +DROP VIEW IF EXISTS test_view_03280; + +CREATE VIEW test_view_1_03280 (a) AS SELECT 1, 2; -- { serverError BAD_ARGUMENTS } From 2f6936bf2afeccce5ef3bbcaf8da5f4db167b5e2 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:50:50 +0100 Subject: [PATCH 02/26] Update 03280_aliases_override_logic.sql --- .../queries/0_stateless/03280_aliases_override_logic.sql | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/queries/0_stateless/03280_aliases_override_logic.sql b/tests/queries/0_stateless/03280_aliases_override_logic.sql index 92dc6bc63a82..9884013182a8 100644 --- a/tests/queries/0_stateless/03280_aliases_override_logic.sql +++ b/tests/queries/0_stateless/03280_aliases_override_logic.sql @@ -1,14 +1,14 @@ SELECT b FROM ( SELECT number, number*2 - FROM numbers(2) (a, b) -) as x; + FROM numbers(2) +) as x (a, b); SELECT a FROM ( SELECT number, number*2 - FROM numbers(2) (a, b) -) as x; + FROM numbers(2) +) as x (a, b); SELECT a FROM ( From 732cfd718abda970edd08119418061c3c91184b4 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Tue, 26 Nov 2024 17:27:26 +0100 Subject: [PATCH 03/26] Enhance docs. --- docs/en/sql-reference/statements/create/view.md | 2 +- docs/en/sql-reference/statements/select/index.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/en/sql-reference/statements/create/view.md b/docs/en/sql-reference/statements/create/view.md index c770348bce07..b2e62bbfdea5 100644 --- a/docs/en/sql-reference/statements/create/view.md +++ b/docs/en/sql-reference/statements/create/view.md @@ -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 [(column1_name [, column2_name ...])] [ON CLUSTER cluster_name] [DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | INVOKER | NONE }] AS SELECT ... [COMMENT 'comment'] diff --git a/docs/en/sql-reference/statements/select/index.md b/docs/en/sql-reference/statements/select/index.md index 1fea29aa40e3..8e7256de5837 100644 --- a/docs/en/sql-reference/statements/select/index.md +++ b/docs/en/sql-reference/statements/select/index.md @@ -17,6 +17,7 @@ SELECT [DISTINCT [ON (column1, column2, ...)]] expr_list [SAMPLE sample_coeff] [ARRAY JOIN ...] [GLOBAL] [ANY|ALL|ASOF] [INNER|LEFT|RIGHT|FULL|CROSS] [OUTER|SEMI|ANTI] JOIN (subquery)|table (ON )|(USING ) +[(column1_name [, column2_name ...])] [PREWHERE expr] [WHERE expr] [GROUP BY expr_list] [WITH ROLLUP|WITH CUBE] [WITH TOTALS] From cb09777630fd3620de5cd256f3386a26cbfb5362 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Tue, 26 Nov 2024 17:56:32 +0100 Subject: [PATCH 04/26] Fixes for review. --- .../getting-started/example-datasets/tpch.md | 20 -------- .../sql-reference/statements/create/view.md | 2 +- .../sql-reference/statements/select/index.md | 2 +- src/Analyzer/QueryTreeBuilder.cpp | 48 +++++++++---------- src/Parsers/ASTSelectQuery.h | 10 ++-- src/Parsers/ParserSelectQuery.cpp | 2 +- ...0_aliases_for_selects_and_views.reference} | 0 .../03280_aliases_for_selects_and_views.sql | 41 ++++++++++++++++ .../03280_aliases_override_logic.sql | 27 ----------- 9 files changed, 73 insertions(+), 79 deletions(-) rename tests/queries/0_stateless/{03280_aliases_override_logic.reference => 03280_aliases_for_selects_and_views.reference} (100%) create mode 100644 tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql delete mode 100644 tests/queries/0_stateless/03280_aliases_override_logic.sql diff --git a/docs/en/getting-started/example-datasets/tpch.md b/docs/en/getting-started/example-datasets/tpch.md index 3ea4bffec385..ffe69724fd2b 100644 --- a/docs/en/getting-started/example-datasets/tpch.md +++ b/docs/en/getting-started/example-datasets/tpch.md @@ -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 diff --git a/docs/en/sql-reference/statements/create/view.md b/docs/en/sql-reference/statements/create/view.md index b2e62bbfdea5..c04ac94a9a75 100644 --- a/docs/en/sql-reference/statements/create/view.md +++ b/docs/en/sql-reference/statements/create/view.md @@ -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 [(column1_name [, column2_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'] diff --git a/docs/en/sql-reference/statements/select/index.md b/docs/en/sql-reference/statements/select/index.md index 8e7256de5837..78d853be4b32 100644 --- a/docs/en/sql-reference/statements/select/index.md +++ b/docs/en/sql-reference/statements/select/index.md @@ -17,7 +17,7 @@ SELECT [DISTINCT [ON (column1, column2, ...)]] expr_list [SAMPLE sample_coeff] [ARRAY JOIN ...] [GLOBAL] [ANY|ALL|ASOF] [INNER|LEFT|RIGHT|FULL|CROSS] [OUTER|SEMI|ANTI] JOIN (subquery)|table (ON )|(USING ) -[(column1_name [, column2_name ...])] +[(alias1 [, alias2 ...])] [PREWHERE expr] [WHERE expr] [GROUP BY expr_list] [WITH ROLLUP|WITH CUBE] [WITH TOTALS] diff --git a/src/Analyzer/QueryTreeBuilder.cpp b/src/Analyzer/QueryTreeBuilder.cpp index 18d7639066f1..9d352a0beb94 100644 --- a/src/Analyzer/QueryTreeBuilder.cpp +++ b/src/Analyzer/QueryTreeBuilder.cpp @@ -89,14 +89,14 @@ class QueryTreeBuilder QueryTreeNodePtr buildSelectOrUnionExpression(const ASTPtr & select_or_union_query, bool is_subquery, const std::string & cte_name, - const ContextPtr & context, - const ASTPtr & aliases_to_override = nullptr) const; + const ASTPtr & aliases_to_override, + const ContextPtr & context) const; QueryTreeNodePtr buildSelectWithUnionExpression(const ASTPtr & select_with_union_query, bool is_subquery, const std::string & cte_name, - const ContextPtr & context, - const ASTPtr & aliases_to_override = nullptr) const; + const ASTPtr & aliases_to_override, + const ContextPtr & context) const; QueryTreeNodePtr buildSelectIntersectExceptQuery(const ASTPtr & select_intersect_except_query, bool is_subquery, @@ -106,8 +106,8 @@ class QueryTreeBuilder QueryTreeNodePtr buildSelectExpression(const ASTPtr & select_query, bool is_subquery, const std::string & cte_name, - const ContextPtr & context, - const ASTPtr & aliases_to_override = nullptr) const; + const ASTPtr & aliases_to_override, + const ContextPtr & context) const; QueryTreeNodePtr buildSortList(const ASTPtr & order_by_expression_list, const ContextPtr & context) const; @@ -135,7 +135,7 @@ QueryTreeBuilder::QueryTreeBuilder(ASTPtr query_, ContextPtr context_) if (query->as() || query->as() || query->as()) - query_tree_node = buildSelectOrUnionExpression(query, false /*is_subquery*/, {} /*cte_name*/, context_); + query_tree_node = buildSelectOrUnionExpression(query, false /*is_subquery*/, {} /*cte_name*/, nullptr, context_); else if (query->as()) query_tree_node = buildExpressionList(query, context_); else @@ -145,17 +145,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 ContextPtr & context, - const ASTPtr & aliases_to_override) const + const ASTPtr & aliases_to_override, + const ContextPtr & context) const { QueryTreeNodePtr query_node; if (select_or_union_query->as()) - 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_to_override*/, context); else if (select_or_union_query->as()) query_node = buildSelectIntersectExceptQuery(select_or_union_query, is_subquery /*is_subquery*/, cte_name /*cte_name*/, context); else if (select_or_union_query->as()) - query_node = buildSelectExpression(select_or_union_query, is_subquery /*is_subquery*/, cte_name /*cte_name*/, context, aliases_to_override); + query_node = buildSelectExpression(select_or_union_query, is_subquery /*is_subquery*/, cte_name /*cte_name*/, aliases_to_override, context); else throw Exception(ErrorCodes::UNSUPPORTED_METHOD, "SELECT or UNION query {} is not supported", select_or_union_query->formatForErrorMessage()); @@ -166,14 +166,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 ContextPtr & context, - const ASTPtr & aliases_to_override) const + const ASTPtr & aliases_to_override, + const ContextPtr & context) const { auto & select_with_union_query_typed = select_with_union_query->as(); auto & select_lists = select_with_union_query_typed.list_of_selects->as(); if (select_lists.children.size() == 1) - return buildSelectOrUnionExpression(select_lists.children[0], is_subquery, cte_name, context, aliases_to_override); + return buildSelectOrUnionExpression(select_lists.children[0], is_subquery, cte_name, aliases_to_override, context); auto union_node = std::make_shared(Context::createCopy(context), select_with_union_query_typed.union_mode); union_node->setIsSubquery(is_subquery); @@ -186,7 +186,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, aliases_to_override); + QueryTreeNodePtr query_node = buildSelectOrUnionExpression(select_list_node, false /*is_subquery*/, {} /*cte_name*/, aliases_to_override, context); union_node->getQueries().getNodes().push_back(std::move(query_node)); } @@ -202,7 +202,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_to_override*/, context); SelectUnionMode union_mode; if (select_intersect_except_query_typed.final_operator == ASTSelectIntersectExceptQuery::Operator::INTERSECT_ALL) @@ -227,7 +227,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_to_override*/, context); union_node->getQueries().getNodes().push_back(std::move(query_node)); } @@ -237,8 +237,8 @@ QueryTreeNodePtr QueryTreeBuilder::buildSelectIntersectExceptQuery(const ASTPtr QueryTreeNodePtr QueryTreeBuilder::buildSelectExpression(const ASTPtr & select_query, bool is_subquery, const std::string & cte_name, - const ContextPtr & context, - const ASTPtr & aliases_to_override) const + const ASTPtr & aliases_to_override, + const ContextPtr & context) const { const auto & select_query_typed = select_query->as(); @@ -698,19 +698,19 @@ QueryTreeNodePtr QueryTreeBuilder::buildExpression(const ASTPtr & expression, co else if (const auto * subquery = expression->as()) { 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_to_override*/, context); result = std::move(query_node); } else if (const auto * /*select_with_union_query*/ _ = expression->as()) { - auto query_node = buildSelectWithUnionExpression(expression, false /*is_subquery*/, {} /*cte_name*/, context); + auto query_node = buildSelectWithUnionExpression(expression, false /*is_subquery*/, {} /*cte_name*/, nullptr /*aliases_to_override*/, context); result = std::move(query_node); } else if (const auto * with_element = expression->as()) { auto with_element_subquery = with_element->subquery->as().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*/, nullptr /*aliases_to_override*/, context); result = std::move(query_node); } @@ -876,7 +876,7 @@ QueryTreeNodePtr QueryTreeBuilder::buildJoinTree(const ASTSelectQuery & select_q auto & subquery_expression = table_expression.subquery->as(); const auto & select_with_union_query = subquery_expression.children[0]; - auto node = buildSelectWithUnionExpression(select_with_union_query, true /*is_subquery*/, {} /*cte_name*/, context, select_query.aliasesOverride()); + auto node = buildSelectWithUnionExpression(select_with_union_query, true /*is_subquery*/, {} /*cte_name*/, select_query.aliasesOverride(), context); node->setAlias(subquery_expression.tryGetAlias()); node->setOriginalAST(select_with_union_query); @@ -906,7 +906,7 @@ QueryTreeNodePtr QueryTreeBuilder::buildJoinTree(const ASTSelectQuery & select_q table_function_expression.formatForErrorMessage()); if (argument->as() || argument->as() || argument->as()) - 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_to_override*/, context)); else if (const auto * ast_set = argument->as()) node->setSettingsChanges(ast_set->changes); else diff --git a/src/Parsers/ASTSelectQuery.h b/src/Parsers/ASTSelectQuery.h index 29767d06179f..245e8a4f3fa6 100644 --- a/src/Parsers/ASTSelectQuery.h +++ b/src/Parsers/ASTSelectQuery.h @@ -20,7 +20,7 @@ class ASTSelectQuery : public IAST WITH, SELECT, TABLES, - ALIASES_OVERRIDE, + ALIAS, PREWHERE, WHERE, GROUP_BY, @@ -47,8 +47,8 @@ class ASTSelectQuery : public IAST return "SELECT"; case Expression::TABLES: return "TABLES"; - case Expression::ALIASES_OVERRIDE: - return "ALIASES_OVERRIDE"; + case Expression::ALIAS: + return "ALIAS"; case Expression::PREWHERE: return "PREWHERE"; case Expression::WHERE: @@ -99,7 +99,7 @@ class ASTSelectQuery : public IAST ASTPtr & refSelect() { return getExpression(Expression::SELECT); } ASTPtr & refTables() { return getExpression(Expression::TABLES); } - ASTPtr & refAliasesOverride() { return getExpression(Expression::ALIASES_OVERRIDE); } + ASTPtr & refAliasesOverride() { return getExpression(Expression::ALIAS); } ASTPtr & refPrewhere() { return getExpression(Expression::PREWHERE); } ASTPtr & refWhere() { return getExpression(Expression::WHERE); } ASTPtr & refHaving() { return getExpression(Expression::HAVING); } @@ -108,7 +108,7 @@ class ASTSelectQuery : public IAST ASTPtr with() const { return getExpression(Expression::WITH); } ASTPtr select() const { return getExpression(Expression::SELECT); } ASTPtr tables() const { return getExpression(Expression::TABLES); } - ASTPtr aliasesOverride()const { return getExpression(Expression::ALIASES_OVERRIDE); } + ASTPtr aliasesOverride()const { return getExpression(Expression::ALIAS); } ASTPtr prewhere() const { return getExpression(Expression::PREWHERE); } ASTPtr where() const { return getExpression(Expression::WHERE); } ASTPtr groupBy() const { return getExpression(Expression::GROUP_BY); } diff --git a/src/Parsers/ParserSelectQuery.cpp b/src/Parsers/ParserSelectQuery.cpp index da5eb388d73a..ddb7b2bf2ec5 100644 --- a/src/Parsers/ParserSelectQuery.cpp +++ b/src/Parsers/ParserSelectQuery.cpp @@ -511,7 +511,7 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) select_query->setExpression(ASTSelectQuery::Expression::WITH, std::move(with_expression_list)); select_query->setExpression(ASTSelectQuery::Expression::SELECT, std::move(select_expression_list)); select_query->setExpression(ASTSelectQuery::Expression::TABLES, std::move(tables)); - select_query->setExpression(ASTSelectQuery::Expression::ALIASES_OVERRIDE, std::move(expression_list_after_from)); + select_query->setExpression(ASTSelectQuery::Expression::ALIAS, std::move(expression_list_after_from)); select_query->setExpression(ASTSelectQuery::Expression::PREWHERE, std::move(prewhere_expression)); select_query->setExpression(ASTSelectQuery::Expression::WHERE, std::move(where_expression)); select_query->setExpression(ASTSelectQuery::Expression::GROUP_BY, std::move(group_expression_list)); diff --git a/tests/queries/0_stateless/03280_aliases_override_logic.reference b/tests/queries/0_stateless/03280_aliases_for_selects_and_views.reference similarity index 100% rename from tests/queries/0_stateless/03280_aliases_override_logic.reference rename to tests/queries/0_stateless/03280_aliases_for_selects_and_views.reference diff --git a/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql b/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql new file mode 100644 index 000000000000..42a52adae6d3 --- /dev/null +++ b/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql @@ -0,0 +1,41 @@ +SELECT b FROM +( + SELECT number, number*2 + FROM numbers(2) +) AS x (a, b); + +SELECT a FROM +( + SELECT number, number*2 + FROM numbers(2) +) AS x (a, b); + +SELECT a FROM +( + SELECT number, number*2 + FROM numbers(2) +) AS x (a); -- { serverError BAD_ARGUMENTS } + +SELECT c FROM +( + SELECT number, number*2 + FROM numbers(2) +) as x (a, b); -- { serverError UNKNOWN_IDENTIFIER } + +DROP VIEW IF EXISTS test_view_03280; + +CREATE VIEW test_view_03280 (a,b) AS SELECT 1, 2; + +SELECT a FROM test_view_03280; + +SELECT b FROM test_view_03280; + +DROP VIEW IF EXISTS test_view_03280; + +SELECT c FROM test_view_03280; -- { serverError UNKNOWN_IDENTIFIER } + +CREATE VIEW test_view_1_03280 (a) AS SELECT 1, 2; -- { serverError BAD_ARGUMENTS } + +CREATE VIEW test_view_1_03280 (a, b] AS SELECT 1, 2; -- { clientError SYNTAX_ERROR } + +CREATE VIEW test_view_1_03280 ((a, b)) AS SELECT 1, 2; -- { clientError SYNTAX_ERROR } diff --git a/tests/queries/0_stateless/03280_aliases_override_logic.sql b/tests/queries/0_stateless/03280_aliases_override_logic.sql deleted file mode 100644 index 9884013182a8..000000000000 --- a/tests/queries/0_stateless/03280_aliases_override_logic.sql +++ /dev/null @@ -1,27 +0,0 @@ -SELECT b FROM -( - SELECT number, number*2 - FROM numbers(2) -) as x (a, b); - -SELECT a FROM -( - SELECT number, number*2 - FROM numbers(2) -) as x (a, b); - -SELECT a FROM -( -SELECT number, number*2 -FROM numbers(10) -) as x (a); -- { serverError BAD_ARGUMENTS } - -CREATE VIEW IF NOT EXISTS test_view_03280 (a,b) AS SELECT 1, 2; - -SELECT a FROM test_view_03280; - -SELECT b FROM test_view_03280; - -DROP VIEW IF EXISTS test_view_03280; - -CREATE VIEW test_view_1_03280 (a) AS SELECT 1, 2; -- { serverError BAD_ARGUMENTS } From b2e12e5d36f3d572e0c4cea0789beeefb13a4f1c Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Tue, 26 Nov 2024 18:47:37 +0100 Subject: [PATCH 05/26] Fix tests. --- src/Parsers/ParserSelectQuery.cpp | 2 +- .../0_stateless/03280_aliases_for_selects_and_views.sql | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Parsers/ParserSelectQuery.cpp b/src/Parsers/ParserSelectQuery.cpp index ddb7b2bf2ec5..6356fce5c761 100644 --- a/src/Parsers/ParserSelectQuery.cpp +++ b/src/Parsers/ParserSelectQuery.cpp @@ -191,7 +191,7 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) return false; } - if (open_bracket.ignore(pos, expected)) + if (tables && open_bracket.ignore(pos, expected)) { if (!exp_list_after_from.parse(pos, expression_list_after_from, expected)) return false; diff --git a/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql b/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql index 42a52adae6d3..ca579b0cc10f 100644 --- a/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql +++ b/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql @@ -36,6 +36,6 @@ SELECT c FROM test_view_03280; -- { serverError UNKNOWN_IDENTIFIER } CREATE VIEW test_view_1_03280 (a) AS SELECT 1, 2; -- { serverError BAD_ARGUMENTS } -CREATE VIEW test_view_1_03280 (a, b] AS SELECT 1, 2; -- { clientError SYNTAX_ERROR } +EXPLAIN AST CREATE VIEW test_view_1_03280 (a, b] AS SELECT 1, 2; -- { clientError SYNTAX_ERROR } -CREATE VIEW test_view_1_03280 ((a, b)) AS SELECT 1, 2; -- { clientError SYNTAX_ERROR } +EXPLAIN AST CREATE VIEW test_view_1_03280 ((a, b)) AS SELECT 1, 2; -- { clientError SYNTAX_ERROR } From 850eccc740f0e60db414e41bd0de766e1c88cac3 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Tue, 26 Nov 2024 19:06:22 +0100 Subject: [PATCH 06/26] Move syntaxError tests to the top. --- .../03280_aliases_for_selects_and_views.sql | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql b/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql index ca579b0cc10f..6d3e22a3d07e 100644 --- a/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql +++ b/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql @@ -1,3 +1,7 @@ +EXPLAIN AST CREATE VIEW test_view_1_03280 (a, b] AS SELECT 1, 2; -- { clientError SYNTAX_ERROR } + +EXPLAIN AST CREATE VIEW test_view_1_03280 ((a, b)) AS SELECT 1, 2; -- { clientError SYNTAX_ERROR } + SELECT b FROM ( SELECT number, number*2 @@ -30,12 +34,8 @@ SELECT a FROM test_view_03280; SELECT b FROM test_view_03280; -DROP VIEW IF EXISTS test_view_03280; - SELECT c FROM test_view_03280; -- { serverError UNKNOWN_IDENTIFIER } -CREATE VIEW test_view_1_03280 (a) AS SELECT 1, 2; -- { serverError BAD_ARGUMENTS } - -EXPLAIN AST CREATE VIEW test_view_1_03280 (a, b] AS SELECT 1, 2; -- { clientError SYNTAX_ERROR } +DROP VIEW IF EXISTS test_view_03280; -EXPLAIN AST CREATE VIEW test_view_1_03280 ((a, b)) AS SELECT 1, 2; -- { clientError SYNTAX_ERROR } +CREATE VIEW test_view_1_03280 (a) AS SELECT 1, 2; -- { serverError BAD_ARGUMENTS } From e4b1a92b8dc828e15d9a987f9b67ef878b3c59f3 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Wed, 27 Nov 2024 21:24:14 +0100 Subject: [PATCH 07/26] Fixes after review. --- src/Analyzer/QueryTreeBuilder.cpp | 38 ++++++++++----------- src/Interpreters/InterpreterCreateQuery.cpp | 4 +-- src/Parsers/ASTCreateQuery.cpp | 10 ++++++ src/Parsers/ASTCreateQuery.h | 3 +- src/Parsers/ASTSelectQuery.cpp | 12 +++++++ src/Parsers/ASTSelectQuery.h | 10 +++--- src/Parsers/ParserCreateQuery.cpp | 8 ++--- src/Parsers/ParserSelectQuery.cpp | 8 ++--- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/src/Analyzer/QueryTreeBuilder.cpp b/src/Analyzer/QueryTreeBuilder.cpp index 9d352a0beb94..f66d7887552e 100644 --- a/src/Analyzer/QueryTreeBuilder.cpp +++ b/src/Analyzer/QueryTreeBuilder.cpp @@ -89,13 +89,13 @@ class QueryTreeBuilder QueryTreeNodePtr buildSelectOrUnionExpression(const ASTPtr & select_or_union_query, bool is_subquery, const std::string & cte_name, - const ASTPtr & aliases_to_override, + 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_to_override, + const ASTPtr & aliases, const ContextPtr & context) const; QueryTreeNodePtr buildSelectIntersectExceptQuery(const ASTPtr & select_intersect_except_query, @@ -106,7 +106,7 @@ class QueryTreeBuilder QueryTreeNodePtr buildSelectExpression(const ASTPtr & select_query, bool is_subquery, const std::string & cte_name, - const ASTPtr & aliases_to_override, + const ASTPtr & aliases const ContextPtr & context) const; QueryTreeNodePtr buildSortList(const ASTPtr & order_by_expression_list, const ContextPtr & context) const; @@ -145,17 +145,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_to_override, + const ASTPtr & aliases, const ContextPtr & context) const { QueryTreeNodePtr query_node; if (select_or_union_query->as()) - query_node = buildSelectWithUnionExpression(select_or_union_query, is_subquery /*is_subquery*/, cte_name /*cte_name*/, nullptr /*aliases_to_override*/, 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()) query_node = buildSelectIntersectExceptQuery(select_or_union_query, is_subquery /*is_subquery*/, cte_name /*cte_name*/, context); else if (select_or_union_query->as()) - query_node = buildSelectExpression(select_or_union_query, is_subquery /*is_subquery*/, cte_name /*cte_name*/, aliases_to_override, 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()); @@ -166,14 +166,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_to_override, + const ASTPtr & aliases, const ContextPtr & context) const { auto & select_with_union_query_typed = select_with_union_query->as(); auto & select_lists = select_with_union_query_typed.list_of_selects->as(); if (select_lists.children.size() == 1) - return buildSelectOrUnionExpression(select_lists.children[0], is_subquery, cte_name, aliases_to_override, context); + return buildSelectOrUnionExpression(select_lists.children[0], is_subquery, cte_name, aliases, context); auto union_node = std::make_shared(Context::createCopy(context), select_with_union_query_typed.union_mode); union_node->setIsSubquery(is_subquery); @@ -186,7 +186,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*/, aliases_to_override, 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)); } @@ -202,7 +202,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, nullptr /*aliases_to_override*/, 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) @@ -227,7 +227,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*/, nullptr /*aliases_to_override*/, 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)); } @@ -237,7 +237,7 @@ QueryTreeNodePtr QueryTreeBuilder::buildSelectIntersectExceptQuery(const ASTPtr QueryTreeNodePtr QueryTreeBuilder::buildSelectExpression(const ASTPtr & select_query, bool is_subquery, const std::string & cte_name, - const ASTPtr & aliases_to_override, + const ASTPtr & aliases, const ContextPtr & context) const { const auto & select_query_typed = select_query->as(); @@ -333,10 +333,10 @@ QueryTreeNodePtr QueryTreeBuilder::buildSelectExpression(const ASTPtr & select_q current_query_tree->getProjectionNode() = buildExpressionList(select_expression_list, current_context); // Apply the override aliases to the projection nodes - if (aliases_to_override) + if (aliases) { auto & projection_nodes = current_query_tree->getProjection().getNodes(); - auto & override_aliases_children = aliases_to_override->as().children; + auto & override_aliases_children = aliases->as().children; if (projection_nodes.size() != override_aliases_children.size()) { @@ -698,19 +698,19 @@ QueryTreeNodePtr QueryTreeBuilder::buildExpression(const ASTPtr & expression, co else if (const auto * subquery = expression->as()) { auto subquery_query = subquery->children[0]; - auto query_node = buildSelectWithUnionExpression(subquery_query, true /*is_subquery*/, {} /*cte_name*/, nullptr /*aliases_to_override*/, 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()) { - auto query_node = buildSelectWithUnionExpression(expression, false /*is_subquery*/, {} /*cte_name*/, nullptr /*aliases_to_override*/, 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()) { auto with_element_subquery = with_element->subquery->as().children.at(0); - auto query_node = buildSelectWithUnionExpression(with_element_subquery, true /*is_subquery*/, with_element->name /*cte_name*/, nullptr /*aliases_to_override*/, context); + auto query_node = buildSelectWithUnionExpression(with_element_subquery, true /*is_subquery*/, with_element->name /*cte_name*/, nullptr /*aliases*/, context); result = std::move(query_node); } @@ -876,7 +876,7 @@ QueryTreeNodePtr QueryTreeBuilder::buildJoinTree(const ASTSelectQuery & select_q auto & subquery_expression = table_expression.subquery->as(); const auto & select_with_union_query = subquery_expression.children[0]; - auto node = buildSelectWithUnionExpression(select_with_union_query, true /*is_subquery*/, {} /*cte_name*/, select_query.aliasesOverride(), 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); @@ -906,7 +906,7 @@ QueryTreeNodePtr QueryTreeBuilder::buildJoinTree(const ASTSelectQuery & select_q table_function_expression.formatForErrorMessage()); if (argument->as() || argument->as() || argument->as()) - node->getArguments().getNodes().push_back(buildSelectOrUnionExpression(argument, false /*is_subquery*/, {} /*cte_name*/, nullptr /*aliases_to_override*/, context)); + node->getArguments().getNodes().push_back(buildSelectOrUnionExpression(argument, false /*is_subquery*/, {} /*cte_name*/, nullptr /*aliases*/, context)); else if (const auto * ast_set = argument->as()) node->setSettingsChanges(ast_set->changes); else diff --git a/src/Interpreters/InterpreterCreateQuery.cpp b/src/Interpreters/InterpreterCreateQuery.cpp index 6ac54c1bfbab..e06b1394b18e 100644 --- a/src/Interpreters/InterpreterCreateQuery.cpp +++ b/src/Interpreters/InterpreterCreateQuery.cpp @@ -944,9 +944,9 @@ InterpreterCreateQuery::TableProperties InterpreterCreateQuery::getTableProperti const auto & selects = select_with_union_query->list_of_selects->children; - for (const auto & select_query_ptr : selects) + for (const auto & select : selects) { - const auto * select_query = select_query_ptr->as(); + const auto * select_query = select->as(); if (!select_query) throw Exception(ErrorCodes::LOGICAL_ERROR, "Expected ASTSelectQuery inside ASTSelectWithUnionQuery"); diff --git a/src/Parsers/ASTCreateQuery.cpp b/src/Parsers/ASTCreateQuery.cpp index 5c98d8e4f25b..1ff4cc25bbe4 100644 --- a/src/Parsers/ASTCreateQuery.cpp +++ b/src/Parsers/ASTCreateQuery.cpp @@ -481,6 +481,16 @@ void ASTCreateQuery::formatQueryImpl(const FormatSettings & settings, FormatStat settings.ostr << (settings.one_line ? ")" : "\n)"); } + frame.expression_list_always_start_on_new_line = true; + + if (is_ordinary_view && aliases_list && !as_table_function) + { + settings.ostr << (settings.one_line ? " (" : "\n("); + FormatStateStacked frame_nested = frame; + aliases_list->formatImpl(settings, state, frame_nested); + settings.ostr << (settings.one_line ? ")" : "\n)"); + } + if (dictionary_attributes_list) { settings.ostr << (settings.one_line ? " (" : "\n("); diff --git a/src/Parsers/ASTCreateQuery.h b/src/Parsers/ASTCreateQuery.h index a54d1e1f3f82..69cc9aaaad70 100644 --- a/src/Parsers/ASTCreateQuery.h +++ b/src/Parsers/ASTCreateQuery.h @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -106,7 +105,7 @@ class ASTCreateQuery : public ASTQueryWithTableAndOutput, public ASTQueryWithOnC bool has_uuid{false}; // CREATE TABLE x UUID '...' ASTColumns * columns_list = nullptr; - ASTExpressionList * aliases_list = nullptr; // Explicit aliases for syntax like CREATE VIEW my_view (a, b) AS SELECT 1, 2 + ASTExpressionList * aliases_list = nullptr; /// Aliases such as "(a, b)" in "CREATE VIEW my_view (a, b) AS SELECT 1, 2" ASTStorage * storage = nullptr; ASTPtr watermark_function; diff --git a/src/Parsers/ASTSelectQuery.cpp b/src/Parsers/ASTSelectQuery.cpp index 8b1f82e9ee85..f10cd8efef2b 100644 --- a/src/Parsers/ASTSelectQuery.cpp +++ b/src/Parsers/ASTSelectQuery.cpp @@ -87,6 +87,18 @@ void ASTSelectQuery::formatImpl(const FormatSettings & s, FormatState & state, F tables()->formatImpl(s, state, frame); } + if (aliases()) + { + const bool prep_whitespace = frame.expression_list_prepend_whitespace; + frame.expression_list_prepend_whitespace = false; + + s.ostr << (s.hilite ? hilite_none : "") << indent_str << " ("; + aliases()->formatImpl(s, state, frame); + s.ostr << (s.hilite ? hilite_none : "") << indent_str << ")"; + + frame.expression_list_prepend_whitespace = prep_whitespace; + } + if (prewhere()) { s.ostr << (s.hilite ? hilite_keyword : "") << s.nl_or_ws << indent_str << "PREWHERE " << (s.hilite ? hilite_none : ""); diff --git a/src/Parsers/ASTSelectQuery.h b/src/Parsers/ASTSelectQuery.h index 245e8a4f3fa6..37eb2d45be82 100644 --- a/src/Parsers/ASTSelectQuery.h +++ b/src/Parsers/ASTSelectQuery.h @@ -20,7 +20,7 @@ class ASTSelectQuery : public IAST WITH, SELECT, TABLES, - ALIAS, + ALIASES, PREWHERE, WHERE, GROUP_BY, @@ -47,8 +47,8 @@ class ASTSelectQuery : public IAST return "SELECT"; case Expression::TABLES: return "TABLES"; - case Expression::ALIAS: - return "ALIAS"; + case Expression::ALIASES: + return "ALIASES"; case Expression::PREWHERE: return "PREWHERE"; case Expression::WHERE: @@ -99,7 +99,7 @@ class ASTSelectQuery : public IAST ASTPtr & refSelect() { return getExpression(Expression::SELECT); } ASTPtr & refTables() { return getExpression(Expression::TABLES); } - ASTPtr & refAliasesOverride() { return getExpression(Expression::ALIAS); } + ASTPtr & refAliases() { return getExpression(Expression::ALIASES); } ASTPtr & refPrewhere() { return getExpression(Expression::PREWHERE); } ASTPtr & refWhere() { return getExpression(Expression::WHERE); } ASTPtr & refHaving() { return getExpression(Expression::HAVING); } @@ -108,7 +108,7 @@ class ASTSelectQuery : public IAST ASTPtr with() const { return getExpression(Expression::WITH); } ASTPtr select() const { return getExpression(Expression::SELECT); } ASTPtr tables() const { return getExpression(Expression::TABLES); } - ASTPtr aliasesOverride()const { return getExpression(Expression::ALIAS); } + ASTPtr aliases() const { return getExpression(Expression::ALIASES); } ASTPtr prewhere() const { return getExpression(Expression::PREWHERE); } ASTPtr where() const { return getExpression(Expression::WHERE); } ASTPtr groupBy() const { return getExpression(Expression::GROUP_BY); } diff --git a/src/Parsers/ParserCreateQuery.cpp b/src/Parsers/ParserCreateQuery.cpp index d7b7a9cf0af7..4e576b6c947e 100644 --- a/src/Parsers/ParserCreateQuery.cpp +++ b/src/Parsers/ParserCreateQuery.cpp @@ -1562,17 +1562,17 @@ bool ParserCreateViewQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec if (!table_name_p.parse(pos, to_table, expected)) return false; } - bool aliases_override = false; /// Optional - a list of columns can be specified. It must fully comply with SELECT. if (s_lparen.ignore(pos, expected)) // Parsing cases like CREATE VIEW (a Int64, b Int64) (a, b) SELECT ... { + bool has_aliases = false; if (!table_properties_p.parse(pos, columns_list, expected)) { if (!expr_list_aliases.parse(pos, aliases_list, expected)) return false; else - aliases_override = true; + has_aliases = true; } else { @@ -1580,13 +1580,13 @@ bool ParserCreateViewQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expec return false; if (s_lparen.ignore(pos, expected)) { - aliases_override = true; + has_aliases = true; if (!expr_list_aliases.parse(pos, aliases_list, expected)) return false; } } - if (aliases_override) + if (has_aliases) if (!s_rparen.ignore(pos, expected)) return false; } diff --git a/src/Parsers/ParserSelectQuery.cpp b/src/Parsers/ParserSelectQuery.cpp index 6356fce5c761..39b76d23bfe5 100644 --- a/src/Parsers/ParserSelectQuery.cpp +++ b/src/Parsers/ParserSelectQuery.cpp @@ -72,7 +72,7 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) ParserNotEmptyExpressionList exp_list(false); ParserNotEmptyExpressionList exp_list_for_with_clause(false); ParserNotEmptyExpressionList exp_list_for_select_clause(/*allow_alias_without_as_keyword*/ true, /*allow_trailing_commas*/ true); - ParserAliasesExpressionList exp_list_after_from; + ParserAliasesExpressionList exp_list_for_aliases; ParserExpressionWithOptionalAlias exp_elem(false); ParserOrderByExpressionList order_list; ParserGroupingSetsExpressionList grouping_sets_list; @@ -84,7 +84,7 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) ASTPtr with_expression_list; ASTPtr select_expression_list; ASTPtr tables; - ASTPtr expression_list_after_from; + ASTPtr expression_list_for_aliases; ASTPtr prewhere_expression; ASTPtr where_expression; ASTPtr group_expression_list; @@ -193,7 +193,7 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) if (tables && open_bracket.ignore(pos, expected)) { - if (!exp_list_after_from.parse(pos, expression_list_after_from, expected)) + if (!exp_list_for_aliases.parse(pos, expression_list_for_aliases, expected)) return false; if (!close_bracket.ignore(pos, expected)) @@ -511,7 +511,7 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) select_query->setExpression(ASTSelectQuery::Expression::WITH, std::move(with_expression_list)); select_query->setExpression(ASTSelectQuery::Expression::SELECT, std::move(select_expression_list)); select_query->setExpression(ASTSelectQuery::Expression::TABLES, std::move(tables)); - select_query->setExpression(ASTSelectQuery::Expression::ALIAS, std::move(expression_list_after_from)); + select_query->setExpression(ASTSelectQuery::Expression::ALIASES, std::move(expression_list_for_aliases)); select_query->setExpression(ASTSelectQuery::Expression::PREWHERE, std::move(prewhere_expression)); select_query->setExpression(ASTSelectQuery::Expression::WHERE, std::move(where_expression)); select_query->setExpression(ASTSelectQuery::Expression::GROUP_BY, std::move(group_expression_list)); From bf20fef8139a2177fbd04ac4e90acf7da8481f8b Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Wed, 27 Nov 2024 21:43:25 +0100 Subject: [PATCH 08/26] Fix build --- src/Analyzer/QueryTreeBuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Analyzer/QueryTreeBuilder.cpp b/src/Analyzer/QueryTreeBuilder.cpp index f66d7887552e..023cabb82f90 100644 --- a/src/Analyzer/QueryTreeBuilder.cpp +++ b/src/Analyzer/QueryTreeBuilder.cpp @@ -106,7 +106,7 @@ class QueryTreeBuilder QueryTreeNodePtr buildSelectExpression(const ASTPtr & select_query, bool is_subquery, const std::string & cte_name, - const ASTPtr & aliases + const ASTPtr & aliases, const ContextPtr & context) const; QueryTreeNodePtr buildSortList(const ASTPtr & order_by_expression_list, const ContextPtr & context) const; From 1be8d9cbbf314cd0ad7d74fcedc960d9c816f6a9 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Thu, 28 Nov 2024 21:30:45 +0100 Subject: [PATCH 09/26] Add the CTE logic. --- src/Analyzer/QueryTreeBuilder.cpp | 2 +- src/Parsers/ASTSelectQuery.h | 5 +++ src/Parsers/ASTWithElement.cpp | 13 +++++++ src/Parsers/ASTWithElement.h | 1 + src/Parsers/ParserSelectQuery.cpp | 9 +++++ src/Parsers/ParserWithElement.cpp | 39 +++++++++++++------ ...80_aliases_for_selects_and_views.reference | 2 + .../03280_aliases_for_selects_and_views.sql | 26 +++++++++++++ 8 files changed, 84 insertions(+), 13 deletions(-) diff --git a/src/Analyzer/QueryTreeBuilder.cpp b/src/Analyzer/QueryTreeBuilder.cpp index 023cabb82f90..4c199fe87293 100644 --- a/src/Analyzer/QueryTreeBuilder.cpp +++ b/src/Analyzer/QueryTreeBuilder.cpp @@ -710,7 +710,7 @@ QueryTreeNodePtr QueryTreeBuilder::buildExpression(const ASTPtr & expression, co else if (const auto * with_element = expression->as()) { auto with_element_subquery = with_element->subquery->as().children.at(0); - auto query_node = buildSelectWithUnionExpression(with_element_subquery, true /*is_subquery*/, with_element->name /*cte_name*/, nullptr /*aliases*/, 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); } diff --git a/src/Parsers/ASTSelectQuery.h b/src/Parsers/ASTSelectQuery.h index 37eb2d45be82..5fe74fba29da 100644 --- a/src/Parsers/ASTSelectQuery.h +++ b/src/Parsers/ASTSelectQuery.h @@ -21,6 +21,7 @@ class ASTSelectQuery : public IAST SELECT, TABLES, ALIASES, + CTE_ALIASES, PREWHERE, WHERE, GROUP_BY, @@ -49,6 +50,8 @@ class ASTSelectQuery : public IAST return "TABLES"; case Expression::ALIASES: return "ALIASES"; + case Expression::CTE_ALIASES: + return "CTE_ALIASES"; case Expression::PREWHERE: return "PREWHERE"; case Expression::WHERE: @@ -100,6 +103,7 @@ class ASTSelectQuery : public IAST ASTPtr & refSelect() { return getExpression(Expression::SELECT); } ASTPtr & refTables() { return getExpression(Expression::TABLES); } ASTPtr & refAliases() { return getExpression(Expression::ALIASES); } + ASTPtr & refCteAliases() { return getExpression(Expression::CTE_ALIASES); } ASTPtr & refPrewhere() { return getExpression(Expression::PREWHERE); } ASTPtr & refWhere() { return getExpression(Expression::WHERE); } ASTPtr & refHaving() { return getExpression(Expression::HAVING); } @@ -109,6 +113,7 @@ class ASTSelectQuery : public IAST ASTPtr select() const { return getExpression(Expression::SELECT); } ASTPtr tables() const { return getExpression(Expression::TABLES); } ASTPtr aliases() const { return getExpression(Expression::ALIASES); } + ASTPtr cteAliases() const { return getExpression(Expression::CTE_ALIASES); } ASTPtr prewhere() const { return getExpression(Expression::PREWHERE); } ASTPtr where() const { return getExpression(Expression::WHERE); } ASTPtr groupBy() const { return getExpression(Expression::GROUP_BY); } diff --git a/src/Parsers/ASTWithElement.cpp b/src/Parsers/ASTWithElement.cpp index a94b0a7062d7..b23b2b45d3de 100644 --- a/src/Parsers/ASTWithElement.cpp +++ b/src/Parsers/ASTWithElement.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -10,6 +11,7 @@ ASTPtr ASTWithElement::clone() const const auto res = std::make_shared(*this); res->children.clear(); res->subquery = subquery->clone(); + res->aliases = aliases->clone(); res->children.emplace_back(res->subquery); return res; } @@ -21,6 +23,17 @@ void ASTWithElement::formatImpl(const FormatSettings & settings, FormatState & s settings.ostr << (settings.hilite ? hilite_alias : ""); settings.writeIdentifier(name, /*ambiguous=*/false); settings.ostr << (settings.hilite ? hilite_none : ""); + if (aliases) + { + const bool prep_whitespace = frame.expression_list_prepend_whitespace; + frame.expression_list_prepend_whitespace = false; + + settings.ostr << " ("; + aliases->formatImpl(settings, state, frame); + settings.ostr << ")"; + + frame.expression_list_prepend_whitespace = prep_whitespace; + } settings.ostr << (settings.hilite ? hilite_keyword : "") << " AS" << (settings.hilite ? hilite_none : ""); settings.ostr << settings.nl_or_ws << indent_str; dynamic_cast(*subquery).formatImplWithoutAlias(settings, state, frame); diff --git a/src/Parsers/ASTWithElement.h b/src/Parsers/ASTWithElement.h index 97c68579fa11..10156b455021 100644 --- a/src/Parsers/ASTWithElement.h +++ b/src/Parsers/ASTWithElement.h @@ -12,6 +12,7 @@ class ASTWithElement : public IAST public: String name; ASTPtr subquery; + ASTPtr aliases; /** Get the text that identifies this element. */ String getID(char) const override { return "WithElement"; } diff --git a/src/Parsers/ParserSelectQuery.cpp b/src/Parsers/ParserSelectQuery.cpp index 39b76d23bfe5..c2e666125117 100644 --- a/src/Parsers/ParserSelectQuery.cpp +++ b/src/Parsers/ParserSelectQuery.cpp @@ -85,6 +85,7 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) ASTPtr select_expression_list; ASTPtr tables; ASTPtr expression_list_for_aliases; + ASTPtr expression_list_for_cte_aliases; ASTPtr prewhere_expression; ASTPtr where_expression; ASTPtr group_expression_list; @@ -113,6 +114,13 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) return false; if (with_expression_list->children.empty()) return false; + + for (const auto & child : with_expression_list->children) /// For cases: WITH _ (a, b) AS ... <- (a, b) are aliases + { + if (auto * with_element = child->as()) + if (with_element->aliases) + expression_list_for_cte_aliases = with_element->aliases; + } } } @@ -512,6 +520,7 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) select_query->setExpression(ASTSelectQuery::Expression::SELECT, std::move(select_expression_list)); select_query->setExpression(ASTSelectQuery::Expression::TABLES, std::move(tables)); select_query->setExpression(ASTSelectQuery::Expression::ALIASES, std::move(expression_list_for_aliases)); + select_query->setExpression(ASTSelectQuery::Expression::CTE_ALIASES, std::move(expression_list_for_cte_aliases)); select_query->setExpression(ASTSelectQuery::Expression::PREWHERE, std::move(prewhere_expression)); select_query->setExpression(ASTSelectQuery::Expression::WHERE, std::move(where_expression)); select_query->setExpression(ASTSelectQuery::Expression::GROUP_BY, std::move(group_expression_list)); diff --git a/src/Parsers/ParserWithElement.cpp b/src/Parsers/ParserWithElement.cpp index 5b31c9296858..61baff3009fb 100644 --- a/src/Parsers/ParserWithElement.cpp +++ b/src/Parsers/ParserWithElement.cpp @@ -15,24 +15,39 @@ bool ParserWithElement::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) ParserIdentifier s_ident; ParserKeyword s_as(Keyword::AS); ParserSubquery s_subquery; + ParserAliasesExpressionList exp_list_for_aliases; + ParserToken open_bracket(TokenType::OpeningRoundBracket); + ParserToken close_bracket(TokenType::ClosingRoundBracket); auto old_pos = pos; if (ASTPtr name, subquery; - s_ident.parse(pos, name, expected) && s_as.ignore(pos, expected) && s_subquery.parse(pos, subquery, expected)) + s_ident.parse(pos, name, expected)) { auto with_element = std::make_shared(); - tryGetIdentifierNameInto(name, with_element->name); - with_element->subquery = subquery; - with_element->children.push_back(with_element->subquery); - node = with_element; - } - else - { - pos = old_pos; - ParserExpressionWithOptionalAlias s_expr(false); - if (!s_expr.parse(pos, node, expected)) - return false; + if (open_bracket.ignore(pos, expected)) + { + if (ASTPtr expression_list_for_aliases; exp_list_for_aliases.parse(pos, expression_list_for_aliases, expected)) + with_element->aliases = expression_list_for_aliases; + + if (!close_bracket.ignore(pos, expected)) + return false; + } + + if (s_as.ignore(pos, expected) && s_subquery.parse(pos, subquery, expected)) + { + tryGetIdentifierNameInto(name, with_element->name); + with_element->subquery = subquery; + with_element->children.push_back(with_element->subquery); + node = with_element; + return true; + } } + + pos = old_pos; + ParserExpressionWithOptionalAlias s_expr(false); + if (!s_expr.parse(pos, node, expected)) + return false; + return true; } diff --git a/tests/queries/0_stateless/03280_aliases_for_selects_and_views.reference b/tests/queries/0_stateless/03280_aliases_for_selects_and_views.reference index 369dbdb26b44..313ca2cf9b1a 100644 --- a/tests/queries/0_stateless/03280_aliases_for_selects_and_views.reference +++ b/tests/queries/0_stateless/03280_aliases_for_selects_and_views.reference @@ -4,3 +4,5 @@ 1 1 2 +1 +2 diff --git a/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql b/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql index 6d3e22a3d07e..cb56a2abec35 100644 --- a/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql +++ b/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql @@ -1,3 +1,5 @@ +SET enable_analyzer = 1; + EXPLAIN AST CREATE VIEW test_view_1_03280 (a, b] AS SELECT 1, 2; -- { clientError SYNTAX_ERROR } EXPLAIN AST CREATE VIEW test_view_1_03280 ((a, b)) AS SELECT 1, 2; -- { clientError SYNTAX_ERROR } @@ -39,3 +41,27 @@ SELECT c FROM test_view_03280; -- { serverError UNKNOWN_IDENTIFIER } DROP VIEW IF EXISTS test_view_03280; CREATE VIEW test_view_1_03280 (a) AS SELECT 1, 2; -- { serverError BAD_ARGUMENTS } + +WITH t (a, b) AS ( + SELECT 1, 2 +) +SELECT a +FROM t; + +WITH t (a, b) AS ( + SELECT 1, 2 +) +SELECT b +FROM t; + +WITH t (a) AS ( + SELECT 1, 2 +) +SELECT b +FROM t; -- { serverError BAD_ARGUMENTS } + +WITH t (a, b) AS ( + SELECT 1, 2 +) +SELECT c +FROM t; -- { serverError UNKNOWN_IDENTIFIER } From 62298b1364f3c9032fa1b2bc13fd7a591d9ae787 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Fri, 29 Nov 2024 00:23:41 +0100 Subject: [PATCH 10/26] Style fix. --- src/Parsers/ParserWithElement.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Parsers/ParserWithElement.cpp b/src/Parsers/ParserWithElement.cpp index 61baff3009fb..8e76d4c0d35a 100644 --- a/src/Parsers/ParserWithElement.cpp +++ b/src/Parsers/ParserWithElement.cpp @@ -42,7 +42,7 @@ bool ParserWithElement::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) return true; } } - + pos = old_pos; ParserExpressionWithOptionalAlias s_expr(false); if (!s_expr.parse(pos, node, expected)) From e5ca3f55562a6fa89d8ee2f911d7f8e204a2736b Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Fri, 29 Nov 2024 01:01:04 +0100 Subject: [PATCH 11/26] Update ParserSelectQuery.cpp --- src/Parsers/ParserSelectQuery.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Parsers/ParserSelectQuery.cpp b/src/Parsers/ParserSelectQuery.cpp index c2e666125117..2ad204356d27 100644 --- a/src/Parsers/ParserSelectQuery.cpp +++ b/src/Parsers/ParserSelectQuery.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include From 5146505b40aeb873e8143a87b05286a559705198 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Fri, 29 Nov 2024 01:02:08 +0100 Subject: [PATCH 12/26] Update index.md --- docs/en/sql-reference/statements/select/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/sql-reference/statements/select/index.md b/docs/en/sql-reference/statements/select/index.md index 78d853be4b32..93aa0ff7ab27 100644 --- a/docs/en/sql-reference/statements/select/index.md +++ b/docs/en/sql-reference/statements/select/index.md @@ -11,7 +11,7 @@ sidebar_label: SELECT ## Syntax ``` sql -[WITH expr_list|(subquery)] +[WITH expr_list [(alias1 [, alias2 ...])] | (subquery)] SELECT [DISTINCT [ON (column1, column2, ...)]] expr_list [FROM [db.]table | (subquery) | table_function] [FINAL] [SAMPLE sample_coeff] From b6b62e3a486918d3997c81e671c7313eb1a5ede3 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Fri, 29 Nov 2024 13:11:52 +0100 Subject: [PATCH 13/26] Fix crashes. --- src/Parsers/ASTWithElement.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Parsers/ASTWithElement.cpp b/src/Parsers/ASTWithElement.cpp index b23b2b45d3de..36770b462e24 100644 --- a/src/Parsers/ASTWithElement.cpp +++ b/src/Parsers/ASTWithElement.cpp @@ -11,7 +11,8 @@ ASTPtr ASTWithElement::clone() const const auto res = std::make_shared(*this); res->children.clear(); res->subquery = subquery->clone(); - res->aliases = aliases->clone(); + if (aliases) + res->aliases = aliases->clone(); res->children.emplace_back(res->subquery); return res; } From 152e100933e466bdfe18c08e5996a7a84ae67b56 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Fri, 29 Nov 2024 17:41:43 +0100 Subject: [PATCH 14/26] Try to fix WITH parsing algorithm --- src/Parsers/ParserWithElement.cpp | 65 +++++++++++++++++++------------ 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/src/Parsers/ParserWithElement.cpp b/src/Parsers/ParserWithElement.cpp index 8e76d4c0d35a..41b9c2c0c738 100644 --- a/src/Parsers/ParserWithElement.cpp +++ b/src/Parsers/ParserWithElement.cpp @@ -20,34 +20,49 @@ bool ParserWithElement::parseImpl(Pos & pos, ASTPtr & node, Expected & expected) ParserToken close_bracket(TokenType::ClosingRoundBracket); auto old_pos = pos; - if (ASTPtr name, subquery; - s_ident.parse(pos, name, expected)) + auto with_element = std::make_shared(); + + // Trying to parse structure: identifier [(alias1, alias2, ...)] AS (subquery) + if (ASTPtr name_or_expr; + (s_ident.parse(pos, name_or_expr, expected) || ParserExpressionWithOptionalAlias(false).parse(pos, name_or_expr, expected)) && + ( + [&]() -> bool { + auto saved_pos = pos; + if (open_bracket.ignore(pos, expected)) + { + if (ASTPtr expression_list_for_aliases; exp_list_for_aliases.parse(pos, expression_list_for_aliases, expected)) + { + with_element->aliases = expression_list_for_aliases; + if (!close_bracket.ignore(pos, expected)) + return false; + return true; + } + else + { + pos = saved_pos; + return false; + } + } + return true; + }() + ) && + s_as.ignore(pos, expected) && + s_subquery.parse(pos, with_element->subquery, expected)) { - auto with_element = std::make_shared(); - if (open_bracket.ignore(pos, expected)) - { - if (ASTPtr expression_list_for_aliases; exp_list_for_aliases.parse(pos, expression_list_for_aliases, expected)) - with_element->aliases = expression_list_for_aliases; - - if (!close_bracket.ignore(pos, expected)) - return false; - } - - if (s_as.ignore(pos, expected) && s_subquery.parse(pos, subquery, expected)) - { - tryGetIdentifierNameInto(name, with_element->name); - with_element->subquery = subquery; - with_element->children.push_back(with_element->subquery); - node = with_element; - return true; - } - } + if (name_or_expr) + tryGetIdentifierNameInto(name_or_expr, with_element->name); - pos = old_pos; - ParserExpressionWithOptionalAlias s_expr(false); - if (!s_expr.parse(pos, node, expected)) - return false; + with_element->children.push_back(with_element->subquery); + node = with_element; + } + else + { + pos = old_pos; + ParserExpressionWithOptionalAlias s_expr(false); + if (!s_expr.parse(pos, node, expected)) + return false; + } return true; } From fdcb993374e6ffc17389275016fdc893b3a0d0c6 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Fri, 29 Nov 2024 18:20:38 +0100 Subject: [PATCH 15/26] Move SET statement after SYNTAX_ERROR checks --- .../0_stateless/03280_aliases_for_selects_and_views.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql b/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql index cb56a2abec35..b372a3a0eab4 100644 --- a/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql +++ b/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql @@ -1,9 +1,9 @@ -SET enable_analyzer = 1; - EXPLAIN AST CREATE VIEW test_view_1_03280 (a, b] AS SELECT 1, 2; -- { clientError SYNTAX_ERROR } EXPLAIN AST CREATE VIEW test_view_1_03280 ((a, b)) AS SELECT 1, 2; -- { clientError SYNTAX_ERROR } +SET enable_analyzer = 1; + SELECT b FROM ( SELECT number, number*2 From d078f84d5f0f40b2dc78e2287f23bbae314e841e Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Wed, 4 Dec 2024 16:35:30 +0100 Subject: [PATCH 16/26] Fixes after conflicts. --- src/Parsers/ASTCreateQuery.cpp | 6 +++--- src/Parsers/ASTSelectQuery.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Parsers/ASTCreateQuery.cpp b/src/Parsers/ASTCreateQuery.cpp index 0f50198eb51e..cda5d17b7644 100644 --- a/src/Parsers/ASTCreateQuery.cpp +++ b/src/Parsers/ASTCreateQuery.cpp @@ -485,10 +485,10 @@ void ASTCreateQuery::formatQueryImpl(WriteBuffer & ostr, const FormatSettings & if (is_ordinary_view && aliases_list && !as_table_function) { - settings.ostr << (settings.one_line ? " (" : "\n("); + ostr << (settings.one_line ? " (" : "\n("); FormatStateStacked frame_nested = frame; - aliases_list->formatImpl(settings, state, frame_nested); - settings.ostr << (settings.one_line ? ")" : "\n)"); + aliases_list->formatImpl(ostr, settings, state, frame_nested); + ostr << (settings.one_line ? ")" : "\n)"); } if (dictionary_attributes_list) diff --git a/src/Parsers/ASTSelectQuery.cpp b/src/Parsers/ASTSelectQuery.cpp index 6916da352d32..2857d428ff92 100644 --- a/src/Parsers/ASTSelectQuery.cpp +++ b/src/Parsers/ASTSelectQuery.cpp @@ -92,9 +92,9 @@ void ASTSelectQuery::formatImpl(WriteBuffer & ostr, const FormatSettings & s, Fo const bool prep_whitespace = frame.expression_list_prepend_whitespace; frame.expression_list_prepend_whitespace = false; - s.ostr << (s.hilite ? hilite_none : "") << indent_str << " ("; - aliases()->formatImpl(s, state, frame); - s.ostr << (s.hilite ? hilite_none : "") << indent_str << ")"; + ostr << (s.hilite ? hilite_none : "") << indent_str << " ("; + aliases()->formatImpl(ostr, s, state, frame); + ostr << (s.hilite ? hilite_none : "") << indent_str << ")"; frame.expression_list_prepend_whitespace = prep_whitespace; } From 72d80ea697100ca940b75c568b0ab39b07cb9658 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Wed, 4 Dec 2024 16:51:04 +0100 Subject: [PATCH 17/26] Fixes after conflict: 2 --- src/Parsers/ASTWithElement.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Parsers/ASTWithElement.cpp b/src/Parsers/ASTWithElement.cpp index f7d7f94390c6..0af9a43cb45e 100644 --- a/src/Parsers/ASTWithElement.cpp +++ b/src/Parsers/ASTWithElement.cpp @@ -30,7 +30,7 @@ void ASTWithElement::formatImpl(WriteBuffer & ostr, const FormatSettings & setti frame.expression_list_prepend_whitespace = false; ostr << " ("; - aliases->formatImpl(settings, state, frame); + aliases->formatImpl(ostr, settings, state, frame); ostr << ")"; frame.expression_list_prepend_whitespace = prep_whitespace; From 6e8a0d209c04a017ca459ca57d08d0340b99b531 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Wed, 4 Dec 2024 17:05:07 +0100 Subject: [PATCH 18/26] Fixes after conflict: 3 --- src/Parsers/ASTWithElement.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Parsers/ASTWithElement.cpp b/src/Parsers/ASTWithElement.cpp index 0af9a43cb45e..81c1a1e5f75f 100644 --- a/src/Parsers/ASTWithElement.cpp +++ b/src/Parsers/ASTWithElement.cpp @@ -37,7 +37,7 @@ void ASTWithElement::formatImpl(WriteBuffer & ostr, const FormatSettings & setti } ostr << (settings.hilite ? hilite_keyword : "") << " AS" << (settings.hilite ? hilite_none : ""); ostr << settings.nl_or_ws << indent_str; - dynamic_cast(*subquery).formatImplWithoutAlias(settings, state, frame); + dynamic_cast(*subquery).formatImplWithoutAlias(ostr, settings, state, frame); } } From fd06f812ca50ee583694517eba7bf4fec7199734 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Sat, 14 Dec 2024 10:45:04 +0100 Subject: [PATCH 19/26] review PR, need to fix --- .../sql-reference/statements/select/index.md | 5 ++--- src/Analyzer/QueryNode.cpp | 18 ++++++++++++++++-- src/Analyzer/QueryNode.h | 16 ++++++++++++++++ src/Analyzer/QueryTreeBuilder.cpp | 17 ++++++++--------- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/docs/en/sql-reference/statements/select/index.md b/docs/en/sql-reference/statements/select/index.md index fd3c7a94c7b3..6e6d6b2a78f5 100644 --- a/docs/en/sql-reference/statements/select/index.md +++ b/docs/en/sql-reference/statements/select/index.md @@ -11,13 +11,12 @@ sidebar_label: SELECT ## Syntax ``` sql -[WITH expr_list [(alias1 [, alias2 ...])] | (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 )|(USING ) -[(alias1 [, alias2 ...])] +[GLOBAL] [ANY|ALL|ASOF] [INNER|LEFT|RIGHT|FULL|CROSS] [OUTER|SEMI|ANTI] JOIN (subquery)|table [(alias1 [, alias2 ...])] (ON )|(USING ) [PREWHERE expr] [WHERE expr] [GROUP BY expr_list] [WITH ROLLUP|WITH CUBE] [WITH TOTALS] diff --git a/src/Analyzer/QueryNode.cpp b/src/Analyzer/QueryNode.cpp index 8499c431b846..02a6a77ab27c 100644 --- a/src/Analyzer/QueryNode.cpp +++ b/src/Analyzer/QueryNode.cpp @@ -50,9 +50,23 @@ 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"); + if (!projection_aliases_to_override.empty()) + { + if (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(), + projection_aliases_to_override.size()); + } + // Apply the aliases + for (size_t i = 0; i < projection_columns_value.size(); ++i) + { + projection_columns_value[i].name = projection_aliases_to_override[i]; + } + } projection_columns = std::move(projection_columns_value); } diff --git a/src/Analyzer/QueryNode.h b/src/Analyzer/QueryNode.h index 2333fc56218d..4e107e23d38a 100644 --- a/src/Analyzer/QueryNode.h +++ b/src/Analyzer/QueryNode.h @@ -630,6 +630,21 @@ class QueryNode final : public IQueryTreeNode void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override; + bool hasProjectionAliasesToOverride() + { + return !projection_aliases_to_override.empty(); + } + + Names getProjectionAliasesToOverride() + { + return projection_aliases_to_override; + } + + void setProjectionAliasesToOverride(Names && pr_aliases) + { + projection_aliases_to_override = pr_aliases; + } + protected: bool isEqualImpl(const IQueryTreeNode & rhs, CompareOptions) const override; @@ -654,6 +669,7 @@ class QueryNode final : public IQueryTreeNode std::string cte_name; NamesAndTypes projection_columns; + Names projection_aliases_to_override; ContextMutablePtr context; SettingsChanges settings_changes; diff --git a/src/Analyzer/QueryTreeBuilder.cpp b/src/Analyzer/QueryTreeBuilder.cpp index 4c199fe87293..5cb7f4bd2fbf 100644 --- a/src/Analyzer/QueryTreeBuilder.cpp +++ b/src/Analyzer/QueryTreeBuilder.cpp @@ -135,7 +135,7 @@ QueryTreeBuilder::QueryTreeBuilder(ASTPtr query_, ContextPtr context_) if (query->as() || query->as() || query->as()) - query_tree_node = buildSelectOrUnionExpression(query, false /*is_subquery*/, {} /*cte_name*/, nullptr, context_); + query_tree_node = buildSelectOrUnionExpression(query, false /*is_subquery*/, {} /*cte_name*/, nullptr /*aliases*/, context_); else if (query->as()) query_tree_node = buildExpressionList(query, context_); else @@ -335,19 +335,18 @@ QueryTreeNodePtr QueryTreeBuilder::buildSelectExpression(const ASTPtr & select_q // Apply the override aliases to the projection nodes if (aliases) { - auto & projection_nodes = current_query_tree->getProjection().getNodes(); + // Collect the aliases into a vector of strings + Names collected_aliases; auto & override_aliases_children = aliases->as().children; + collected_aliases.reserve(override_aliases_children.size()); - if (projection_nodes.size() != override_aliases_children.size()) + for (const auto & child : override_aliases_children) { - throw Exception(ErrorCodes::BAD_ARGUMENTS, "Number of aliases does not match number of expressions in SELECT list"); + const auto & alias_ast = child->as(); + collected_aliases.push_back(alias_ast.name()); } - for (size_t i = 0; i < projection_nodes.size(); ++i) - { - const auto & alias_ast = override_aliases_children[i]->as(); - projection_nodes[i]->setAlias(alias_ast.name()); - } + current_query_tree->setProjectionAliasesToOverride(std::move(collected_aliases)); } auto prewhere_expression = select_query_typed.prewhere(); From 69b468165d7766e7a19969898d321afbd0828d38 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Sat, 14 Dec 2024 10:52:18 +0100 Subject: [PATCH 20/26] fix style --- src/Analyzer/QueryNode.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Analyzer/QueryNode.cpp b/src/Analyzer/QueryNode.cpp index 02a6a77ab27c..eb5f7ad02f33 100644 --- a/src/Analyzer/QueryNode.cpp +++ b/src/Analyzer/QueryNode.cpp @@ -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_) From 3f3115e387f33ff16c647341f9e63240e6fc42ef Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Sat, 14 Dec 2024 11:42:08 +0100 Subject: [PATCH 21/26] fix build --- src/Parsers/ASTWithElement.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Parsers/ASTWithElement.h b/src/Parsers/ASTWithElement.h index 5d14312f29bc..9020503c7214 100644 --- a/src/Parsers/ASTWithElement.h +++ b/src/Parsers/ASTWithElement.h @@ -19,7 +19,6 @@ class ASTWithElement : public IAST ASTPtr clone() const override; -protected: void formatImpl(WriteBuffer & ostr, const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override; }; From 4c32736052acbb593b5ed4d13b742035faac0164 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Sat, 14 Dec 2024 12:22:07 +0100 Subject: [PATCH 22/26] fix build --- src/Parsers/ASTSelectQuery.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Parsers/ASTSelectQuery.h b/src/Parsers/ASTSelectQuery.h index 42082b10d860..1d66d75f175d 100644 --- a/src/Parsers/ASTSelectQuery.h +++ b/src/Parsers/ASTSelectQuery.h @@ -161,7 +161,6 @@ class ASTSelectQuery : public IAST QueryKind getQueryKind() const override { return QueryKind::Select; } bool hasQueryParameters() const; -protected: void formatImpl(WriteBuffer & ostr, const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override; private: From 048ca6749096bca2158c4fdc3b8cff7a6da09481 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Mon, 16 Dec 2024 12:39:57 +0100 Subject: [PATCH 23/26] Try to fix build --- src/Parsers/ASTCreateQuery.cpp | 2 +- src/Parsers/ASTSelectQuery.cpp | 2 +- src/Parsers/ASTWithElement.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Parsers/ASTCreateQuery.cpp b/src/Parsers/ASTCreateQuery.cpp index 1258f3321ce7..6894f21b1a78 100644 --- a/src/Parsers/ASTCreateQuery.cpp +++ b/src/Parsers/ASTCreateQuery.cpp @@ -488,7 +488,7 @@ void ASTCreateQuery::formatQueryImpl(WriteBuffer & ostr, const FormatSettings & { ostr << (settings.one_line ? " (" : "\n("); FormatStateStacked frame_nested = frame; - aliases_list->formatImpl(ostr, settings, state, frame_nested); + aliases_list->format(ostr, settings, state, frame_nested); ostr << (settings.one_line ? ")" : "\n)"); } diff --git a/src/Parsers/ASTSelectQuery.cpp b/src/Parsers/ASTSelectQuery.cpp index 14a53b52614e..d0601bf8bd0c 100644 --- a/src/Parsers/ASTSelectQuery.cpp +++ b/src/Parsers/ASTSelectQuery.cpp @@ -94,7 +94,7 @@ void ASTSelectQuery::formatImpl(WriteBuffer & ostr, const FormatSettings & s, Fo frame.expression_list_prepend_whitespace = false; ostr << (s.hilite ? hilite_none : "") << indent_str << " ("; - aliases()->formatImpl(ostr, s, state, frame); + aliases()->format(ostr, s, state, frame); ostr << (s.hilite ? hilite_none : "") << indent_str << ")"; frame.expression_list_prepend_whitespace = prep_whitespace; diff --git a/src/Parsers/ASTWithElement.cpp b/src/Parsers/ASTWithElement.cpp index 81c1a1e5f75f..f8f4fcfe9a65 100644 --- a/src/Parsers/ASTWithElement.cpp +++ b/src/Parsers/ASTWithElement.cpp @@ -30,7 +30,7 @@ void ASTWithElement::formatImpl(WriteBuffer & ostr, const FormatSettings & setti frame.expression_list_prepend_whitespace = false; ostr << " ("; - aliases->formatImpl(ostr, settings, state, frame); + aliases->format(ostr, settings, state, frame); ostr << ")"; frame.expression_list_prepend_whitespace = prep_whitespace; From d1a2f54743b7f4b59b90275cc865788cb0801210 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Mon, 16 Dec 2024 16:27:45 +0100 Subject: [PATCH 24/26] Fix + tests --- src/Analyzer/QueryNode.cpp | 22 +++++++++++-------- ...80_aliases_for_selects_and_views.reference | 20 +++++++++++++++++ .../03280_aliases_for_selects_and_views.sql | 8 +++++++ 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/src/Analyzer/QueryNode.cpp b/src/Analyzer/QueryNode.cpp index eb5f7ad02f33..26665754a167 100644 --- a/src/Analyzer/QueryNode.cpp +++ b/src/Analyzer/QueryNode.cpp @@ -51,22 +51,19 @@ QueryNode::QueryNode(ContextMutablePtr context_) void QueryNode::resolveProjectionColumns(NamesAndTypes projection_columns_value) { - if (!projection_aliases_to_override.empty()) + + // Ensure the number of aliases matches the number of projection columns + if (!this->projection_aliases_to_override.empty()) { - if (projection_aliases_to_override.size() != projection_columns_value.size()) - { + 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(), - projection_aliases_to_override.size()); - } + this->projection_aliases_to_override.size()); - // Apply the aliases for (size_t i = 0; i < projection_columns_value.size(); ++i) - { - projection_columns_value[i].name = projection_aliases_to_override[i]; - } + projection_columns_value[i].name = this->projection_aliases_to_override[i]; } projection_columns = std::move(projection_columns_value); } @@ -312,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); @@ -353,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; } diff --git a/tests/queries/0_stateless/03280_aliases_for_selects_and_views.reference b/tests/queries/0_stateless/03280_aliases_for_selects_and_views.reference index 313ca2cf9b1a..58a2ddec41b1 100644 --- a/tests/queries/0_stateless/03280_aliases_for_selects_and_views.reference +++ b/tests/queries/0_stateless/03280_aliases_for_selects_and_views.reference @@ -6,3 +6,23 @@ 2 1 2 +0 +QUERY id: 0 + PROJECTION COLUMNS + b UInt8 + PROJECTION + LIST id: 1, nodes: 1 + COLUMN id: 2, column_name: b, result_type: UInt8, source_id: 3 + JOIN TREE + QUERY id: 3, alias: __table1, is_subquery: 1, is_cte: 1, cte_name: t + PROJECTION COLUMNS + b UInt8 + PROJECTION + LIST id: 4, nodes: 1 + CONSTANT id: 5, constant_value: UInt64_2, constant_value_type: UInt8 + JOIN TREE + TABLE id: 6, alias: __table2, table_name: system.one + + SELECT __table1.b AS b + FROM + t AS __table1 diff --git a/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql b/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql index b372a3a0eab4..bccc89e7836b 100644 --- a/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql +++ b/tests/queries/0_stateless/03280_aliases_for_selects_and_views.sql @@ -54,6 +54,14 @@ WITH t (a, b) AS ( SELECT b FROM t; +WITH t (a) AS ( + SELECT * FROM numbers(1) +) +SELECT a +FROM t; + +explain query tree dump_ast = 1 WITH t (a, b) AS (SELECT 1, 2) SELECT b FROM t; + WITH t (a) AS ( SELECT 1, 2 ) From 0c62b561403a6a98965fcec9c60a262faebace84 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Mon, 16 Dec 2024 16:57:16 +0100 Subject: [PATCH 25/26] fix test output --- ...80_aliases_for_selects_and_views.reference | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/queries/0_stateless/03280_aliases_for_selects_and_views.reference b/tests/queries/0_stateless/03280_aliases_for_selects_and_views.reference index 58a2ddec41b1..53f647a551cd 100644 --- a/tests/queries/0_stateless/03280_aliases_for_selects_and_views.reference +++ b/tests/queries/0_stateless/03280_aliases_for_selects_and_views.reference @@ -8,21 +8,21 @@ 2 0 QUERY id: 0 - PROJECTION COLUMNS - b UInt8 - PROJECTION - LIST id: 1, nodes: 1 - COLUMN id: 2, column_name: b, result_type: UInt8, source_id: 3 - JOIN TREE - QUERY id: 3, alias: __table1, is_subquery: 1, is_cte: 1, cte_name: t - PROJECTION COLUMNS - b UInt8 - PROJECTION - LIST id: 4, nodes: 1 - CONSTANT id: 5, constant_value: UInt64_2, constant_value_type: UInt8 - JOIN TREE - TABLE id: 6, alias: __table2, table_name: system.one + PROJECTION COLUMNS + b UInt8 + PROJECTION + LIST id: 1, nodes: 1 + COLUMN id: 2, column_name: b, result_type: UInt8, source_id: 3 + JOIN TREE + QUERY id: 3, alias: __table1, is_subquery: 1, is_cte: 1, cte_name: t + PROJECTION COLUMNS + b UInt8 + PROJECTION + LIST id: 4, nodes: 1 + CONSTANT id: 5, constant_value: UInt64_2, constant_value_type: UInt8 + JOIN TREE + TABLE id: 6, alias: __table2, table_name: system.one - SELECT __table1.b AS b - FROM - t AS __table1 +SELECT __table1.b AS b +FROM +t AS __table1 From abdda03dada0bc1f09b418d8404f862ee098e970 Mon Sep 17 00:00:00 2001 From: Yarik Briukhovetskyi <114298166+yariks5s@users.noreply.github.com> Date: Mon, 16 Dec 2024 17:19:00 +0100 Subject: [PATCH 26/26] Minor improvements --- src/Analyzer/QueryNode.h | 14 ++------------ src/Analyzer/QueryTreeBuilder.cpp | 2 +- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/Analyzer/QueryNode.h b/src/Analyzer/QueryNode.h index 4e107e23d38a..f4b5754be49c 100644 --- a/src/Analyzer/QueryNode.h +++ b/src/Analyzer/QueryNode.h @@ -630,19 +630,9 @@ class QueryNode final : public IQueryTreeNode void dumpTreeImpl(WriteBuffer & buffer, FormatState & format_state, size_t indent) const override; - bool hasProjectionAliasesToOverride() + void setProjectionAliasesToOverride(Names pr_aliases) { - return !projection_aliases_to_override.empty(); - } - - Names getProjectionAliasesToOverride() - { - return projection_aliases_to_override; - } - - void setProjectionAliasesToOverride(Names && pr_aliases) - { - projection_aliases_to_override = pr_aliases; + projection_aliases_to_override = std::move(pr_aliases); } protected: diff --git a/src/Analyzer/QueryTreeBuilder.cpp b/src/Analyzer/QueryTreeBuilder.cpp index 52a52ac4460c..c091399a4be1 100644 --- a/src/Analyzer/QueryTreeBuilder.cpp +++ b/src/Analyzer/QueryTreeBuilder.cpp @@ -352,7 +352,7 @@ QueryTreeNodePtr QueryTreeBuilder::buildSelectExpression(const ASTPtr & select_q collected_aliases.push_back(alias_ast.name()); } - current_query_tree->setProjectionAliasesToOverride(std::move(collected_aliases)); + current_query_tree->setProjectionAliasesToOverride(collected_aliases); } auto prewhere_expression = select_query_typed.prewhere();