From ebd71f226cbc52340e712b07bbaebc6656aa7e4b Mon Sep 17 00:00:00 2001 From: vdimir Date: Mon, 13 Mar 2023 11:41:00 +0000 Subject: [PATCH] Support SETTINGS argument of table functions --- src/Analyzer/QueryTreeBuilder.cpp | 6 +++++ src/Analyzer/TableFunctionNode.cpp | 27 +++++++++++++++++++ src/Analyzer/TableFunctionNode.h | 15 +++++++++++ .../02479_mysql_connect_to_self.reference | 21 +++++++++++++++ .../02479_mysql_connect_to_self.sql | 10 +++++++ 5 files changed, 79 insertions(+) diff --git a/src/Analyzer/QueryTreeBuilder.cpp b/src/Analyzer/QueryTreeBuilder.cpp index 7dd988619ac..4887cfcd6ea 100644 --- a/src/Analyzer/QueryTreeBuilder.cpp +++ b/src/Analyzer/QueryTreeBuilder.cpp @@ -838,8 +838,14 @@ QueryTreeNodePtr QueryTreeBuilder::buildJoinTree(const ASTPtr & tables_in_select const auto & function_arguments_list = table_function_expression.arguments->as().children; for (const auto & argument : function_arguments_list) { + if (!node->getSettingsChanges().empty()) + throw Exception(ErrorCodes::LOGICAL_ERROR, "Table function '{}' has arguments after SETTINGS", + table_function_expression.formatForErrorMessage()); + if (argument->as() || argument->as() || argument->as()) node->getArguments().getNodes().push_back(buildSelectOrUnionExpression(argument, false /*is_subquery*/, {} /*cte_name*/, context)); + else if (const auto * ast_set = argument->as()) + node->setSettingsChanges(ast_set->changes); else node->getArguments().getNodes().push_back(buildExpression(argument, context)); } diff --git a/src/Analyzer/TableFunctionNode.cpp b/src/Analyzer/TableFunctionNode.cpp index 89e2cdc3ec8..41eb1d151c7 100644 --- a/src/Analyzer/TableFunctionNode.cpp +++ b/src/Analyzer/TableFunctionNode.cpp @@ -7,6 +7,7 @@ #include #include +#include #include @@ -71,6 +72,13 @@ void TableFunctionNode::dumpTreeImpl(WriteBuffer & buffer, FormatState & format_ buffer << '\n' << std::string(indent + 2, ' ') << "ARGUMENTS\n"; arguments.dumpTreeImpl(buffer, format_state, indent + 4); } + + if (!settings_changes.empty()) + { + buffer << '\n' << std::string(indent + 6, ' ') << "SETTINGS"; + for (const auto & change : settings_changes) + buffer << fmt::format(" {}={}", change.name, toString(change.value)); + } } bool TableFunctionNode::isEqualImpl(const IQueryTreeNode & rhs) const @@ -99,6 +107,16 @@ void TableFunctionNode::updateTreeHashImpl(HashState & state) const if (table_expression_modifiers) table_expression_modifiers->updateTreeHash(state); + + for (const auto & change : settings_changes) + { + state.update(change.name.size()); + state.update(change.name); + + const auto & value_dump = change.value.dump(); + state.update(value_dump.size()); + state.update(value_dump); + } } QueryTreeNodePtr TableFunctionNode::cloneImpl() const @@ -109,6 +127,7 @@ QueryTreeNodePtr TableFunctionNode::cloneImpl() const result->storage_id = storage_id; result->storage_snapshot = storage_snapshot; result->table_expression_modifiers = table_expression_modifiers; + result->settings_changes = settings_changes; return result; } @@ -123,6 +142,14 @@ ASTPtr TableFunctionNode::toASTImpl(ConvertToASTOptions options) const table_function_ast->children.push_back(arguments.toAST(options)); table_function_ast->arguments = table_function_ast->children.back(); + if (!settings_changes.empty()) + { + auto settings_ast = std::make_shared(); + settings_ast->changes = settings_changes; + settings_ast->is_standalone = false; + table_function_ast->arguments->children.push_back(std::move(settings_ast)); + } + return table_function_ast; } diff --git a/src/Analyzer/TableFunctionNode.h b/src/Analyzer/TableFunctionNode.h index 7e5f180bdcb..cf2830f2ecb 100644 --- a/src/Analyzer/TableFunctionNode.h +++ b/src/Analyzer/TableFunctionNode.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include @@ -122,6 +124,18 @@ public: return table_expression_modifiers; } + /// Get settings changes passed to table function + const SettingsChanges & getSettingsChanges() const + { + return settings_changes; + } + + /// Set settings changes passed as last argument to table function + void setSettingsChanges(SettingsChanges settings_changes_) + { + settings_changes = std::move(settings_changes_); + } + /// Set table expression modifiers void setTableExpressionModifiers(TableExpressionModifiers table_expression_modifiers_value) { @@ -151,6 +165,7 @@ private: StorageID storage_id; StorageSnapshotPtr storage_snapshot; std::optional table_expression_modifiers; + SettingsChanges settings_changes; static constexpr size_t arguments_child_index = 0; static constexpr size_t children_size = arguments_child_index + 1; diff --git a/tests/queries/0_stateless/02479_mysql_connect_to_self.reference b/tests/queries/0_stateless/02479_mysql_connect_to_self.reference index 07cd8dea949..2b9215a3517 100644 --- a/tests/queries/0_stateless/02479_mysql_connect_to_self.reference +++ b/tests/queries/0_stateless/02479_mysql_connect_to_self.reference @@ -37,3 +37,24 @@ -5 --- 4 +QUERY id: 0 + PROJECTION COLUMNS + key String + PROJECTION + LIST id: 1, nodes: 1 + COLUMN id: 2, column_name: key, result_type: String, source_id: 3 + JOIN TREE + TABLE_FUNCTION id: 3, table_function_name: mysql + ARGUMENTS + LIST id: 4, nodes: 5 + CONSTANT id: 5, constant_value: \'127.0.0.1:9004\', constant_value_type: String + CONSTANT id: 6, constant_value: \'default\', constant_value_type: String + CONSTANT id: 7, constant_value: \'foo\', constant_value_type: String + CONSTANT id: 8, constant_value: \'default\', constant_value_type: String + CONSTANT id: 9, constant_value: \'\', constant_value_type: String + SETTINGS connection_wait_timeout=123 connect_timeout=40123002 read_write_timeout=40123001 connection_pool_size=3 + +SELECT key AS key +FROM mysql(\'127.0.0.1:9004\', \'default\', \'foo\', \'default\', \'\', SETTINGS connection_wait_timeout = 123, connect_timeout = 40123002, read_write_timeout = 40123001, connection_pool_size = 3) +--- +5 diff --git a/tests/queries/0_stateless/02479_mysql_connect_to_self.sql b/tests/queries/0_stateless/02479_mysql_connect_to_self.sql index 832d4a6347d..3da2a1dd2b9 100644 --- a/tests/queries/0_stateless/02479_mysql_connect_to_self.sql +++ b/tests/queries/0_stateless/02479_mysql_connect_to_self.sql @@ -30,3 +30,13 @@ SELECT b FROM mysql('127.0.0.1:9004', currentDatabase(), foo, 'default', '') WHE SELECT '---'; SELECT count() FROM mysql('127.0.0.1:9004', currentDatabase(), foo, 'default', '') WHERE c != 'twee'; + +EXPLAIN QUERY TREE dump_ast = 1 +SELECT * FROM mysql( + '127.0.0.1:9004', 'default', 'foo', 'default', '', + SETTINGS connection_wait_timeout = 123, connect_timeout = 40123002, read_write_timeout = 40123001, connection_pool_size = 3 +); + +SELECT '---'; +SELECT count() FROM mysql('127.0.0.1:9004', currentDatabase(), foo, 'default', '', SETTINGS connection_pool_size = 1); +SELECT count() FROM mysql('127.0.0.1:9004', currentDatabase(), foo, 'default', '', SETTINGS connection_pool_size = 0); -- { serverError BAD_ARGUMENTS }